feat(aihr): 重构运营后台与租户知识治理

- 重构运营总览、侧栏和内容运营工作台\n- 增加大喇叭、成果审核与运营统计链路\n- 补齐租户、知识空间、分类和知识维护闭环\n- 加固标签页租户上下文、停用租户写保护与迁移预检
This commit is contained in:
2026-07-23 01:24:22 +08:00
parent 333c365c6f
commit 163b08ecfe
94 changed files with 8610 additions and 1114 deletions
+3 -2
View File
@@ -13,9 +13,10 @@
| 对练语音 | `POST /api/ai/asr`(multipart 字段 `file`,≤5MB)、`POST /api/ai/tts`(JSON `{text≤300字, voice?, voiceProfile?:{role,voice?,speed?,emotion?}}`,旧 `voice` 兼容;成功返回 `ossId`,客户端播放地址为受控的内联 `data:audio/*`,不返回原始 OSS URL)、`GET /api/aihr/mobile/oss/{ossId}` | 走 OpenAI-compatible audio 接口;生产 SiliconFlow CosyVoice2 按角色映射老师傅/业主/面试官音色,业主对练再按已有情绪分切换平静/严肃/强烈语气和语速,设备语音降级同步调整语速与音高;模型管理需启用 `category=asr/tts` 配置;移动端优先用浏览器录音,`getUserMedia/MediaRecorder` 不可用或麦克风权限失败时,用 `audio/*` file input 选择/录制音频后继续调同一 ASR 接口;ASR/TTS 未配置或失败返回 fail,前端降级设备语音或文本;训练/每日题录音只通过 `audioOssId` 走受保护下载,历史客户端传入的 HTTP `audioUrl` 不再回显;TTS 成功音频仍写入 `sys_oss` 留痕,同时用内联 data URL 保持旧客户端可播放;音频下载按员工本人或主管项目范围授权,系统管理端保持后台访问 |
| 案例沉淀 `/knowledge/cases` | `GET /api/knowledge/case/capabilities`、`POST /api/knowledge/case/upload`、`/organize`、`/curate`、`GET /records`、`GET /records/{caseId}`、`POST /records/{caseId}/review`、`GET /records/{caseId}/media` | `/capabilities` 返回服务端判定的案例提交/查看能力,移动端不再向普通员工展示无权提交的素材表单;`/upload` 改为 multipart 真实语音上传并走 ASR,服务端只接受 MP3/WAV/M4A/WebM/OGG/AAC/FLAC,成功后原始音频写入 `sys_oss`,案例记录只保存 `mediaOssId` 供受保护媒体接口读取,不向客户端回传原始 `mediaUrl`;`/organize` 用真实转写调 chat 模型整理案例,未配置模型时按真实 transcript 本地结构化,并从背景外的真实摘要项提取学习点;APP 用户的项目范围从 `aihr_org_snapshot` 登录身份解析,上传、整理、入库、列表和详情均按项目范围校验,未完成正式组织映射时安全拒绝,不接受前端伪造项目范围;员工列表/详情只返回 `已入库` 案例,管理端系统用户保留全局运营视图;移动端和管理端案例详情通过受保护媒体接口回放原始音频,主管/项目负责人可提交脱敏点评;预渲染视频样片仍待正式媒体资产接入 |
| 案例媒体安全 | `GET /api/knowledge/case/records/{caseId}/media` | 案例详情只返回 `mediaOssId`,不返回原始 `sys_oss.url`;媒体下载会重复执行登录、后台角色或 APP 项目范围校验,再由服务端流式读取 OSS。管理端与 `mobile-uni` 通过鉴权 blob/temp 文件播放,关闭详情页时释放本地对象 URL |
| 问师傅与 SOP 知识库 `/pages/user/sop/index`、`/knowledge/sop` | `POST /api/knowledge/query`、`POST /api/knowledge/query-media`、`GET /api/knowledge/resources/{attachmentId}/content`、`POST /api/knowledge/answer-feedback`、`GET /api/knowledge/position-sop`、`GET /api/aihr/mobile/onboard/tasks`、`POST /api/aihr/mobile/onboard/tasks/{id}/complete`、`GET /api/aihr/mobile/qualification`、`POST /api/knowledge/doc/upload` | 文字/现场附件查询走统一知识空间授权和 MySQL Fulltext + Qdrant 混合召回;内部登录端可选传 `conversationId/contextVersion`,服务端保留 30 分钟不活跃过期、最近 6 轮脱敏截断上下文,用现有 chat 模型或保守规则输出 `QA/FILE/VIDEO/DATA_TOOL` 和 `rewrittenQuery`,旧版本冲突返回 `409`。原文件/视频仅从当前命中且仍有授权的附件返回,内容接口每次重新计算租户、应用和主体权限;无资源时明确返回空列表,不生成假链接。旧客户端和外部 API 保持单轮无状态。搜索继续返回 `reviewId/promptVersion`,员工反馈保存评审批次;详细边界见 [专项设计](20260718/问师傅多轮会话与原始资料交付设计.md)。员工学习页按当前 APP 身份读取正式岗前/入职任务,资格证据无正式数据时明确返回 `NOT_CONFIGURED` |
| 问师傅与 SOP 知识库 `/pages/user/sop/index`、`/knowledge/sop` | `POST /api/knowledge/query`、`POST /api/knowledge/query-media`、`GET /api/knowledge/resources/{attachmentId}/content`、`POST /api/knowledge/answer-feedback`、`GET /api/knowledge/position-sop`、`GET /api/aihr/mobile/onboard/tasks`、`POST /api/aihr/mobile/onboard/tasks/{id}/complete`、`GET /api/aihr/mobile/qualification`、`POST /api/knowledge/doc/upload` | 文字/现场附件查询走统一知识空间授权和 MySQL Fulltext + Qdrant 混合召回;内部登录端可选传 `conversationId/contextVersion`,服务端保留 30 分钟不活跃过期、最近 6 轮脱敏截断上下文,用现有 chat 模型或保守规则输出 `QA/FILE/VIDEO/DATA_TOOL` 和 `rewrittenQuery`,旧版本冲突返回 `409`。员工从银城大喇叭详情追问时,内部文字查询还可只传 `broadcastMessageId`:服务端每轮按当前 APP 在职员工、当前租户和 `PUBLISHED` 状态重新取消息,响应仅回显 `{messageId,title,publishedAt}`,消息正文不写入客户端存储、会话 JSON 或查询审计;同一会话的消息来源不可改绑,撤回后续问即拒绝。该上下文只说明公司消息,不可据此捏造个人任务;上下文模式拒绝现场媒体和数据工具,外部无状态 API 不接受该参数。原文件/视频仅从当前命中且仍有授权的附件返回,内容接口每次重新计算租户、应用和主体权限;无资源时明确返回空列表,不生成假链接。旧客户端和外部 API 保持单轮无状态。搜索继续返回 `reviewId/promptVersion`,员工反馈保存评审批次;详细边界见 [专项设计](20260718/问师傅多轮会话与原始资料交付设计.md)。员工学习页按当前 APP 身份读取正式岗前/入职任务,资格证据无正式数据时明确返回 `NOT_CONFIGURED` |
| 工作助手确认式统一采集 `/pages/user/sop/index`、`/pages/user/assistant/memories` | 既有 `POST /api/knowledge/query` 和 `POST /api/knowledge/query-media` 可选返回 `memoryCandidate`;`GET /api/aihr/personal-assistant/memory-candidates?status=DRAFT`、`POST /api/aihr/personal-assistant/memory-candidates/{id}/confirm`、`POST .../{id}/dismiss`、`GET /api/aihr/personal-assistant/assistant-captures?limit=50`、`POST /assistant-captures/{id}/status`、`GET /assistant-captures/{id}/status-history`、`GET /assistant-captures/{id}/source`;旧项目记录继续使用 `/api/aihr/service-memories` | 文字、ASR 转写和现场媒体复用同一候选检测。项目工作必须从 `/api/aihr/mobile/me` 返回的项目名称列表选择当前项目,内部 `projectCode` 仍由服务端按当前登录主体授权收窄;个人笔记可以不绑定项目。显式“记一下”生成 `ASSISTANT_CAPTURE/DRAFT`,系统建议 `ATTENDANCE/INSPECTION/SERVICE_LEAD/RESIDENT_PROFILE/CASE/PERSONAL_NOTE/FOLLOW_UP/PROJECT_NOTE`。确认必须带 `expectedVersion + idempotencyKey + saveScope(PRIVATE|COMPANY)`;PRIVATE 仅本人可见,COMPANY 写入 PENDING 待流转。状态更新只允许 `RECORDED/PENDING/IN_PROGRESS/COMPLETED/VOID`,幂等键不得跨记录或目标状态复用。来源文件重新鉴权交付;正式外部接收端未配置前不得显示已送达 |
| 今日工作成果 `/pages/user/work-results/index`、`/pages/supervisor/work-results/index` | 员工 `POST /api/aihr/work-results/mine/generate?projectCode=...&workDate=YYYY-MM-DD`;主管 `GET /api/aihr/work-results/project?projectCode=...&workDate=YYYY-MM-DD` | 按员工 + 项目 + Asia/Shanghai 自然日确定性聚合已确认记录;两页默认当天并可按日期查看历史成果,客户端禁止选择未来日期。内容未变化时重复生成不增加版本,记录或状态变化后版本递增。主管只可查看本人在目标项目具备主管身份的团队结果;APP 登录身份同时兼容组织快照中的外部人员 ID 与手机号,普通员工或跨项目请求返回 403。外部接口未接通时只显示本地状态和 PENDING,不伪造派单或考勤同步成功 |
| 银城大喇叭 | 员工 `GET /api/aihr/broadcast/unread-count`、`GET /api/aihr/broadcast/messages?pageNum=&pageSize=`、`GET /api/aihr/broadcast/messages/{id}`、`POST /api/aihr/broadcast/messages/{id}/read`;员工详情可经统一 `POST /api/knowledge/query` 的 `broadcastMessageId` 发起文字追问;管理 `GET /api/aihr/broadcast/admin/messages?pageNum=&pageSize=&status=PUBLISHED|WITHDRAWN|all`(响应含服务端确认的 `tenantId`)、`POST /api/aihr/broadcast/messages`(`{requestId,title,content,expectedTenantId}`)、`POST /api/aihr/broadcast/messages/{id}/withdraw`(`{reason,expectedTenantId}`) | 员工端只返回当前登录租户的 `PUBLISHED` 公开消息,租户和阅读用户均由服务端登录身份取得;阅读表以 `(tenant_id,message_id,user_id)` 唯一约束保证重复打开幂等。详情“问这条消息”只在本地暂存消息 ID,问模块重新读取并由服务端可信解析消息;撤回、跨租户或非在职员工均不可继续追问。管理读写使用服务端当前有效租户(动态租户优先);`expectedTenantId` 只能回显刚读取的服务端范围,不用于选择租户,若另一标签页已切换范围则返回 `409`,避免旧页面误发或误撤回。发布以 `(tenant_id,published_by,requestId)` 幂等:同键同内容重放原 `{id,version:1}`,同键异内容返回 `409`;一个事务内写主消息和不可变 v1 内容快照。管理列表可按已发布/已撤回筛选并返回正文、发布/撤回审计与固定 `currentVersion=1`。撤回原因必填、去首尾空白且最多 500 字符;首次只允许 `PUBLISHED -> WITHDRAWN`,重复撤回成功但不得覆盖原撤回人、时间或原因。管理端将未知发布请求按“有效租户 + 管理员”的 `v2` 本地记录保存,存储不可用时拒绝发起发布。首版不含修订、定向目标、附件或 AI 摘要;管理接口只允许 `superadmin` 或 `hr_operator`。 |
| 成果投稿(当前页面名“工作上报”)`/pages/user/report/index` | `POST /api/aihr/work-report/organize`、`POST /attachment`、`POST /reports`、`GET /reports/mine`;主管/运营另有列表和审核接口 | 只承载 CASE/VIDEO/SOP/KNOWLEDGE 四类投稿。会话式页面、无状态整理、附件、幂等正式提交和历史状态已部署;审核通过不自动入知识库。当前整理服务不读取图片/视频内容,只把附件名称作为不可信元数据;不得与日常工作记录或“今日工作成果”混用 |
| 资料处理 `/knowledge/processing` | `GET /api/knowledge/processing/overview`、`POST /api/knowledge/doc/upload-async`、`GET /api/knowledge/doc/upload-items`、`POST /api/knowledge/doc/upload-items/{id}/retry` | 已接入解析任务状态聚合;页面只保留“批量导入”,接口暂存+入队即秒回,后台 worker(并发 2)逐条解析/归类/向量化;ZIP 在 worker 内安全解压后把支持的子文件继续入同一批次队列,页面按批次轮询进度、失败可单文件重试;不提供浏览器目录选择或服务端目录导入入口 |
| 组织人员同步 | `POST /api/aihr/org/sync` | 从开放组织同步系统的 `/api/open/v1/sync/snapshot` 拉取 `company/department/employee/employee_project_assignment` 快照,分页参数使用 `limit`;员工手机号只落 `person_phone` 用于移动端身份映射,不在组织列表响应暴露;岗位识别 `position/job_title/post/job_name/role/title` 等字段。`dryRun` 必须显式传入 `true`(预检)或 `false`(写入),省略或传 `null` 直接拒绝,避免空请求意外写库;默认 `replaceExisting=true`,写入前必须先用 `{"dryRun":true}`;dry-run 不访问本地快照表、不执行 DDL/写库,返回 `phoneLinked/maskedPhone/suspectText/warnings` 且 `syncedCount=0`。非 dry-run 覆盖写入遇到员工被跳过、手机号不完整、脱敏手机号或疑似乱码时默认拒绝,只有确认 dry-run 结果后显式传 `allowPartialReplace=true` 才允许覆盖。相同员工可由多条有效项目分配展开为多个项目成员行,唯一约束为 `tenant_id + project_code + ext_party_id`;只拒绝同一项目内的重复成员关系。`replaceExisting=false` 不触发不完整快照覆盖闸门,但仍拒绝同项目重复关系。2026-07-15 线上已用 `/api/open/v1` 前缀完成配置、dry-run 和覆盖同步:开放平台返回公司 17、部门 963、员工 3417;生产 `aihr_org_snapshot` 为 3417 行,`phoneLinked=3392`、`maskedPhone=25`、`suspectText=0`,在职 2943、离职 474。该统计发生在多项目成员迁移前;发布迁移后必须重新 dry-run 并核对展开后的项目成员行数。当前剩余 25 人手机号不可用属于上游数据质量问题 |
@@ -222,7 +223,7 @@ Content-Type: application/json
成功响应包含 `requestId`、`answer`、`citations`、`usedSpaceCodes`、`noEvidence` 和兼容 `legacy` 数据。引用携带 `spaceCode/sourceType/docId/title/snippet/fragmentId`;客户端不得把无引用回答包装成有知识依据的正式答案。
空间、授权和应用管理接口统一位于 `/api/knowledge/admin`:`spaces`、`spaces/{id}/grants`、`spaces/{id}/documents`、`apps`、`apps/{id}/spaces`、`apps/{id}/rotate-token`。`DELETE /spaces/{id}/documents/{attachId}` 只解绑当前空间成员;其他空间仍引用同一 OSS 时原文件不会删除。仅知识平台管理角色可调用,API_TOKEN 创建或轮换后只返回一次明文。完整初始化、令牌保管、legacy 迁移与回滚步骤见 [KNOWLEDGE_PLATFORM_RUNBOOK.md](KNOWLEDGE_PLATFORM_RUNBOOK.md)。
空间、空间内分类、授权和应用管理接口统一位于 `/api/knowledge/admin`:`spaces`、`spaces/{id}/categories`、`spaces/{id}/documents`、`spaces/{id}/documents/{attachId}/category`、`spaces/{id}/grants`、`apps`、`apps/{id}/spaces`、`apps/{id}/rotate-token`。分类仅在当前有效租户和当前知识空间内维护;停用分类不能继续归类,删除前必须先移走其知识,分类不会扩大空间授权或调用应用的检索范围。`DELETE /spaces/{id}/documents/{attachId}` 只解绑当前空间成员;其他空间仍引用同一 OSS 时原文件不会删除。仅知识平台管理角色可调用,API_TOKEN 创建或轮换后只返回一次明文。超级管理员由“租户管理”进入知识维护时,通过 `GET /system/tenant/dynamic/{tenantId}` 设置服务端动态租户,再由 `GET /system/tenant/dynamic` 回读当前上下文;仅正常状态的已存在租户允许切换。动态租户按当前 Sa-Token 与浏览器页面生成的匿名上下文共同隔离,客户端每次请求回传页面上下文及当前展示租户;两者与服务端不一致时服务端返回 `409` 并拒绝读写,避免多标签页误写。知识平台不接受客户端传入的 `tenantId` 来选租户。完整初始化、令牌保管、legacy 迁移与回滚步骤见 [KNOWLEDGE_PLATFORM_RUNBOOK.md](KNOWLEDGE_PLATFORM_RUNBOOK.md)。
## 工作助手确认式统一采集
+22 -6
View File
@@ -51,10 +51,12 @@ mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aih
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260714_daily_drill_score_mode_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260714_sop_requester_identity_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260715_knowledge_feedback_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260715_tenant_collation_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260716_knowledge_space_platform_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260714_org_hire_date_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260715_position_sop_qualification_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260717_practice_assignment_batch_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260717_practice_assignment_contract_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260717_learning_closure_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260717_practice_five_position_catalog_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260717_web_ai_question_reward_mysql8.sql
@@ -67,9 +69,12 @@ mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aih
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260719_work_report_idempotency_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260719_web_ai_database_secret_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260719_web_search_qwen_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260722_knowledge_category_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260722_broadcast_mysql8.sql
mysql --default-character-set=utf8mb4 "$DB_NAME" < backend/script/sql/update/aihr_20260722_broadcast_question_context_mysql8.sql
```
顺序原因:场景补充依赖三张场景/Rubric 基础表;五维迁移依赖场景和 Rubric;岗位/SOP/任务/资格迁移只补正式数据契约,不写业务行,也不代表岗位适用范围、任务规则或资格标准已经获得 HR 确认。住宅 SOP 和 Prompt 迁移只补内置内容,不代表内容已完成业务复核。知识会话迁移只新增短期上下文表,不生成业务对话。排序规则兼容迁移先对齐本批发布表,全量排序规则迁移再统一历史 `aihr_*` 表;两者都读取目标库 `aihr_knowledge_info.tenant_id` 的实际排序规则。服务记忆迁移创建候选、统一采集、兼容项目记录和版本留痕四张表;工作上报幂等迁移随后只补原表列与唯一索引。两者同样对齐目标排序规则,兼容历史生产库与全新 MySQL 8 数据库。
顺序原因:场景补充依赖三张场景/Rubric 基础表;五维迁移依赖场景和 Rubric;岗位/SOP/任务/资格迁移只补正式数据契约,不写业务行,也不代表岗位适用范围、任务规则或资格标准已经获得 HR 确认。住宅 SOP 和 Prompt 迁移只补内置内容,不代表内容已完成业务复核。知识会话迁移只新增短期上下文表,不生成业务对话。排序规则兼容迁移先对齐本批发布表,全量排序规则迁移再统一历史 `aihr_*` 表;两者都读取目标库 `aihr_knowledge_info.tenant_id` 的实际排序规则。服务记忆迁移创建候选、统一采集、兼容项目记录和版本留痕四张表;工作上报幂等迁移随后只补原表列与唯一索引;知识分类迁移新增空间内分类表及附件成员的可空 `category_id`,不迁移、删除或扩大任何空间授权与检索范围;银城大喇叭迁移创建消息、阅读和不可变 v1 快照三表,为已存在消息补一次快照,并补发布请求键/载荷哈希、撤回原因及 `(tenant_id,published_by,publish_request_key)` 唯一约束。随后,消息追问迁移只给短期会话增加可空 `broadcast_message_id`;它不保存消息正文,并用于约束同一会话不能切换公司消息。历史普通会话保持 `NULL`。它们同样对齐目标排序规则,兼容历史生产库与全新 MySQL 8 数据库。
## 迁移后只读核验
@@ -83,7 +88,7 @@ WHERE table_schema = DATABASE()
'aihr_practice_scenario', 'aihr_practice_rubric', 'aihr_practice_rubric_dimension', 'aihr_learning_question',
'aihr_practice_audio', 'aihr_practice_audio_upload', 'aihr_practice_calibration',
'aihr_knowledge_gap', 'aihr_knowledge_answer_feedback',
'aihr_knowledge_space_grant', 'aihr_knowledge_app', 'aihr_knowledge_app_space',
'aihr_knowledge_space_grant', 'aihr_knowledge_app', 'aihr_knowledge_app_space', 'aihr_knowledge_category',
'aihr_knowledge_query_log', 'aihr_knowledge_admin_audit', 'aihr_knowledge_conversation',
'aihr_practice_question_feedback',
'aihr_onboard_exam', 'aihr_onboard_exam_target', 'aihr_onboard_exam_question',
@@ -96,7 +101,7 @@ WHERE table_schema = DATABASE()
'aihr_onboard_task', 'aihr_qualification_gate',
'aihr_memory_candidate', 'aihr_assistant_capture', 'aihr_assistant_capture_status_log',
'aihr_daily_work_result', 'aihr_service_memory', 'aihr_service_memory_version',
'aihr_work_report'
'aihr_work_report', 'aihr_broadcast_message', 'aihr_broadcast_read', 'aihr_broadcast_version'
)
ORDER BY table_name;
@@ -110,6 +115,7 @@ WHERE table_schema = DATABASE()
OR (table_name = 'aihr_practice_assignment' AND column_name IN ('score', 'score_mode', 'due_date', 'request_key', 'content_version', 'question_snapshot', 'reference_answer_snapshot', 'content_hash'))
OR (table_name = 'aihr_sop_answer_review' AND column_name IN ('prompt_version', 'requester_ext_party_id'))
OR (table_name = 'aihr_knowledge_info' AND column_name IN ('code', 'space_type', 'sensitivity_level', 'status'))
OR (table_name = 'aihr_knowledge_attach' AND column_name = 'category_id')
OR (table_name = 'aihr_knowledge_upload_item' AND column_name = 'space_codes_json')
OR (table_name = 'aihr_org_snapshot' AND column_name = 'hire_date')
OR (table_name = 'aihr_candidate_material' AND column_name IN ('reviewer', 'reviewed_time'))
@@ -119,14 +125,23 @@ WHERE table_schema = DATABASE()
OR (table_name = 'aihr_onboard_task' AND column_name IN ('ext_party_id', 'position_code', 'task_type', 'status', 'assign_by'))
OR (table_name = 'aihr_qualification_gate' AND column_name IN ('ext_party_id', 'position_code', 'cert_id', 'passed', 'valid_thru'))
OR (table_name = 'aihr_work_report' AND column_name IN ('request_key', 'request_hash'))
OR (table_name = 'aihr_broadcast_message' AND column_name IN ('publish_request_key', 'publish_request_hash', 'withdraw_reason'))
OR (table_name = 'aihr_memory_candidate' AND column_name IN ('work_date', 'source_snapshot_json'))
OR (table_name = 'aihr_assistant_capture' AND column_name IN ('work_date', 'source_snapshot_json', 'business_status'))
OR (table_name = 'aihr_knowledge_conversation' AND column_name = 'project_code')
OR (table_name = 'aihr_knowledge_conversation' AND column_name IN ('project_code', 'broadcast_message_id'))
OR (table_name = 'aihr_daily_work_result' AND column_name = 'content_hash')
OR (table_name = 'aihr_web_search_provider' AND column_name IN ('agent_id', 'agent_version'))
)
ORDER BY table_name, column_name;
SELECT MIN(non_unique) AS non_unique,
GROUP_CONCAT(column_name ORDER BY seq_in_index) AS indexed_columns,
SUM(sub_part IS NOT NULL) AS prefix_columns
FROM information_schema.statistics
WHERE table_schema = DATABASE()
AND table_name = 'aihr_broadcast_message'
AND index_name = 'uk_aihr_broadcast_message_publish_request';
SELECT COUNT(*) AS built_in_prompt_templates
FROM aihr_prompt_template
WHERE tenant_id = '000000'
@@ -145,7 +160,7 @@ GROUP BY question_type
ORDER BY question_type;
```
预期是三张场景/Rubric 表、岗位题库、训练反馈表、五张考试表、三张全网检索表、问题榜/激励六张表、三张证据表、知识平台治理表、三张候选人/面试表、四张岗位/SOP/任务/资格契约表、四张记忆表、采集状态历史表、每日成果表和原工作上报表均存在;工作上报幂等字段为 `2/2`,工作助手新增字段为 `7/7`,会话证据字段为 `8/8`,专项批量/内容快照字段为 `8/8`,候选资料审核字段为 `2/2`,面试复核字段为 `6/6`,字段查询覆盖所有列,内置 Prompt 数量为 `6`。五个岗位各有 `20` 个场景,`daily/special` 各有 `100` 道题;其中 `14` 个未完成正式审核的高风险场景及其 `28` 道题保持禁用。岗位/SOP/任务/资格表及新记忆表为空是允许的;这只证明 schema/seed 迁移完成,不证明已有员工确认过记忆、完整个人知识库或严格试点完成。
预期是三张场景/Rubric 表、岗位题库、训练反馈表、五张考试表、三张全网检索表、问题榜/激励六张表、三张证据表、知识平台治理表和空间内分类表、三张候选人/面试表、四张岗位/SOP/任务/资格契约表、四张记忆表、采集状态历史表、每日成果表、原工作上报表和三张大喇叭消息/阅读/v1快照表均存在;工作上报幂等字段为 `2/2`,大喇叭发布/撤回审计字段为 `3/3`,其发布幂等索引为 `0 | tenant_id,published_by,publish_request_key | 0`,公司消息追问会话字段为 `1/1`,工作助手新增字段为 `8/8`,会话证据字段为 `8/8`,专项批量/内容快照字段为 `8/8`,候选资料审核字段为 `2/2`,面试复核字段为 `6/6`,字段查询覆盖所有列,内置 Prompt 数量为 `6`。五个岗位各有 `20` 个场景,`daily/special` 各有 `100` 道题;其中 `14` 个未完成正式审核的高风险场景及其 `28` 道题保持禁用。岗位/SOP/任务/资格表及新记忆表为空是允许的;这只证明 schema/seed 迁移完成,不证明已有员工确认过记忆、完整个人知识库或严格试点完成。
## 迁移后应用回归
@@ -155,7 +170,8 @@ ORDER BY question_type;
4. 用正式测试账号在“工作助手”选择当前项目并说“帮我记一下三栋 3203 需要保洁服务”;确认前 `aihr_assistant_capture` 不得新增。分别验证 `PRIVATE` 仅本人可召回、`COMPANY` 只显示 `PENDING` 且没有虚假送达回执;新开对话按房号查询必须只命中对应项目记录,双击确认不得重复写入。测试表达如不需长期保留,应在确认卡选择“暂不保存”,不要直接删除生产审计记录。
5. 在“今日工作成果”按员工 + 项目 + 日期重复生成两次,内容不变时版本哈希必须一致;员工访问团队结果、主管访问非授权项目必须被拒绝。生产无主管正式测试账号时必须明确记录未验收,不以本地 seed 代替。
6. 用员工测试账号进入“成果投稿”,确认其仍只承载优秀案例、操作视频、完整 SOP 和有用知识,不回退为日常事实表单。重复提交同一 `request_key` 只有一条 `PENDING` 记录;普通员工审核仍为 `403`,审核通过不自动写入案例、知识或积分表。
7. 迁移完成后再按同一正式时间窗运行:
7. 用 `superadmin` 或 `hr_operator` 在当前租户发布同一 `requestId` 两次:同内容必须只生成一条消息和一个 v1 快照,改动正文后必须返回 `409`。撤回时提交非空原因,员工端随即不可见;重复撤回不得改写首个撤回人、时间或原因。再确认管理列表不跨租户返回消息。
8. 迁移完成后再按同一正式时间窗运行:
```bash
AIHR_PILOT_TENANT_ID=000000 \
+4 -3
View File
@@ -25,13 +25,14 @@ order by tenant_id;
### 2.2 备份与迁移
先备份数据库,再执行 `backend/script/sql/update/aihr_20260716_knowledge_space_platform_mysql8.sql`。迁移可重复执行,但生产仍应先在结构副本验证。执行后至少核对:
先备份数据库,依次执行 `backend/script/sql/update/aihr_20260716_knowledge_space_platform_mysql8.sql` 与 `backend/script/sql/update/aihr_20260722_knowledge_category_mysql8.sql`。迁移可重复执行,但生产仍应先在结构副本验证。执行后至少核对:
```sql
show tables like 'aihr_knowledge_%';
show create table aihr_knowledge_info;
show create table aihr_knowledge_app;
show create table aihr_knowledge_space_grant;
show create table aihr_knowledge_category;
```
## 3. 幂等初始化
@@ -79,7 +80,7 @@ order by tenant_id, app_code;
## 4. 空间、授权与应用管理
管理端“知识空间”页面提供空间、主体授权和调用应用管理。空间编码创建后不可修改;停用空间会让检索立即失去该空间,但不删除资料。`MANAGE` 授权可以给用户或角色,`READ` 只决定主体能否读;SESSION 应用与主体授权取交集。
超级管理员从“平台设置 → 租户管理”维护租户主体;点击某个租户的“知识维护”会先切换到该租户,再进入知识空间页。管理端“知识空间”页面提供空间、空间内分类与知识、主体授权和调用应用管理。空间和分类编码创建后不可修改;停用空间会让检索立即失去该空间,但不删除资料。分类只组织当前空间内的附件成员关系,不新增授权,也不改变“当前租户 + 调用应用绑定空间 + 用户/角色授权空间”的查询交集。`MANAGE` 授权可以给用户或角色,`READ` 只决定主体能否读;SESSION 应用与主体授权取交集。
外部美途应用的启用顺序固定为:
@@ -96,7 +97,7 @@ order by tenant_id, app_code;
### 5.1 新内容导入
在 SOP 或资料处理页显式选择一个或多个可管理空间。多空间上传只解析一次、复用同一个 OSS 对象,但为每个空间建立独立附件成员关系和检索片段。解绑或停用一个空间不得影响另一个空间的内容。
在 SOP 或资料处理页显式选择一个或多个可管理空间。多空间上传只解析一次、复用同一个 OSS 对象,但为每个空间建立独立附件成员关系和检索片段;上传后可在“分类与知识”页分别为各空间成员归类。解绑或停用一个空间不得影响另一个空间的内容。
导入后核对:
+1
View File
@@ -35,6 +35,7 @@
| [个人AI助理阶段二专项TechSpec.md](个人AI助理阶段二专项TechSpec.md) | 工作助手确认式统一采集的当前契约,以及后续个人知识空间的数据分域、检索、权限、安全和测试规格 |
| [工作助手与今日工作成果迭代计划-20260721.md](工作助手与今日工作成果迭代计划-20260721.md) | 工作助手项目选择、统一采集、来源追溯、今日成果、主管视图、成果投稿和外部流转的分阶段计划;含本地实施状态、390×844 证据和剩余生产边界 |
| [银城帮道产品功能优先级与实施计划-20260721.md](银城帮道产品功能优先级与实施计划-20260721.md) | 对《银城帮道介绍》十项能力进行事实校正,给出 P0-P3、明确不做项、发布批次和本轮实施记录;产品全景施工入口 |
| [银城大喇叭与问模块纠偏增量方案-20260722.md](银城大喇叭与问模块纠偏增量方案-20260722.md) | 银城大喇叭的发布、阅读、消息追问与权限边界,以及“问”模块真实任务问答纠偏的分批实施、验收与回滚方案 |
| [个人AI助理阶段二开发推进计划.md](个人AI助理阶段二开发推进计划.md) | 后续个人资料/网页/PPT 能力的 P0/P1 任务计划;“记一下”当前实现以专项 TechSpec 为准 |
| [prototypes/personal-assistant-work-helper-voice-first-v2.png](prototypes/personal-assistant-work-helper-voice-first-v2.png) | 个人助理并入「问 · 数字师傅」后的语音优先会话、自动内部路由与确认记忆卡实现基准 |
| [prototypes/work-report-voice-conversation-v1.png](prototypes/work-report-voice-conversation-v1.png) | 当前“工作上报”(产品目标名“成果投稿”)会话式页面的视觉回归基准;不代表工作助手日常采集或今日成果页 |
@@ -0,0 +1,352 @@
# “银城大喇叭 + 问模块纠偏”增量方案
> 版本:v1.0
> 日期:2026-07-22
> 状态:A(问模块事实纠偏)与 B(银城大喇叭核心)已本地实现并完成定向验证;尚未部署,C—E 仍待实施。
> 适用范围:银城帮道员工端、管理端与 `ruoyi-aihr` 业务模块
> 关联方案:[产品功能优先级与实施计划](银城帮道产品功能优先级与实施计划-20260721.md)、[员工端 APP 分阶段实施总纲](银城员工端APP分阶段实施总纲.md)、[问师傅多轮会话与原始资料交付设计](20260718/问师傅多轮会话与原始资料交付设计.md)
## 0. 决策摘要
本方案不是新增一个普通公告页,而是把“公司告诉员工什么”和“员工听完后还能问清楚什么”连成一个可信闭环。
1. **银城大喇叭**是员工端的公司信息频道,入口复用首页右上角的喇叭图标;不新增第五个底部 Tab。
2. 已发布的首版消息面向本租户全员可查;按项目、岗位、层级的匹配用于**置顶、提醒和排序**,不应导致员工完全看不到公司公开信息。
3. 员工可在消息详情中点击“就这条消息问数字师傅”,带着受服务端校验的消息上下文进入现有“问”模块。
4. “问”回答“我现在该做什么”时,必须先查该员工当前真实任务;没有任务就明确说明“当前没有查到待办”,只能给非强制建议,不能把通用培训内容伪装为已下发工作。
5. 首版不包含高管直通、匿名建议、企业微信/短信强触达、考勤请假审批、工单派发或自动创建任务。这些能力另立流程和权限,不混入大喇叭 MVP。
这项增量同时服务两个目的:一是让制度、通知、文件不再散落在群聊中;二是让员工在接收信息后能基于原文继续追问,并获得有来源、不过度承诺的回答。
## 1. 背景、问题与目标
### 1.1 当前问题
| 问题 | 对员工的影响 | 根因 | 本方案处理方式 |
|---|---|---|---|
| 现有普通公告不能形成真正的公司消息闭环 | 不知道哪些信息与自己有关,也无法确认是否读过 | `sys_notice` 只有常规公告基础,不具备定向提醒、阅读审计、附件摘要与补推能力 | 建立独立的“大喇叭”领域模型,不把普通公告包装成已完成的公司消息系统 |
| 消息阅读后仍需在群里或重新描述背景提问 | 员工得不到针对该通知、制度或文件的解释 | 消息内容与“问”的会话上下文没有受控连接 | 在消息详情提供“就这条消息问数字师傅”,由服务端传入并校验消息上下文 |
| “问”会把岗位通用培训推荐说成员工当前必须完成的任务 | 员工被误导,主管也无法判断任务是否真实存在 | 回答只检索知识,未以当前员工的真实任务状态作为行动结论依据 | 将“真实待办”设为独立数据工具;无任务时禁止生成“去完成”动作卡 |
| 员工自称其他岗位后,回答可能被错误带向该岗位训练方案 | 角色、任务与权限边界混乱 | 角色描述被当作身份事实 | 服务端当前组织身份优先;其他岗位内容只能作为跨岗位参考明确标注 |
| “问”页面支撑组件占用过多空间 | 对话上下文容易被打断,追问成本高 | 页面没有把连续会话作为核心内容 | 首轮保留引导;会话开始后收起快捷问题、项目和成果组件,突出消息来源与对话 |
### 1.2 增量目标
| 目标 | 可观察结果 |
|---|---|
| 统一公司信息入口 | 员工从首页喇叭进入“银城大喇叭”,可查看全员频道及与自己相关的提醒 |
| 消息可理解 | 每条可带原文、附件、AI 摘要和“与我有关”说明;摘要不能替代原件 |
| 消息可追问 | 员工无需复制粘贴消息,即可围绕该条消息连续追问 |
| 回答不越界 | 涉及真实任务、培训、审批、工单、外部处理结果时,只依据可验证数据回答 |
| 可运营、可追溯 | 发布、版本、命中、阅读、失败补推和问答来源均可审计 |
### 1.3 成功标准
首版上线后,不以“页面存在”或“日活”作为完成证明。以下闭环均有运行证据才可称为可用:
1. 管理人员发布一条面向全员的通知,并按目标人群设置提醒或置顶。
2. 目标员工在首页看到真实未读提示,从列表进入原文和附件。
3. 员工点击“就这条消息问数字师傅”,提问能引用当前消息,且不能越权读取其他消息或附件。
4. 员工追问“我现在要做什么”时,系统根据真实任务数据给出“有任务”“无任务”或“无权确认”的结果。
5. 管理端能查看发布版本、范围、阅读情况和提醒失败记录;不可用时不伪造“已送达”。
## 2. 产品定位与范围边界
### 2.1 模块职责
| 模块 | 要解决的问题 | 首版职责 | 不承担的职责 |
|---|---|---|---|
| 银城大喇叭 | 公司信息如何可靠触达、回看和理解 | 消息发布、频道浏览、定向提醒/置顶、阅读审计、附件与摘要 | 审批流、工单系统、即时聊天、匿名建议箱 |
| 问 · 数字师傅 | 员工如何理解制度、消息和工作知识 | 有来源的消息解读、SOP/知识问答、真实任务状态说明 | 擅自派工、自动创建任务、承诺外部部门已经处理 |
| 学 / 练 | 员工如何获得并完成训练 | 已有学习、陪练、训练任务承接 | 承担公司通知分发 |
| 后续员工直达 | 员工如何向管理层提出敏感意见或求助 | 后续单独设计匿名、实名、收件人、回复 SLA 与审计 | 复用大喇叭消息表“顺手实现” |
| 北森/外部 HR | 请假、考勤、正式人事流程如何办理 | 后续有正式接口合同后承接 | 用问答或大喇叭模拟审批成功 |
### 2.2 本次纳入范围
- 首页喇叭入口、真实未读红点和“大喇叭”消息列表。
- 全员公开频道、按组织身份匹配的提醒/置顶、已读未读和发布时间线。
- 消息详情:原文、附件、发布人、版本、适用提示、AI 摘要、“与我有关”、已读状态。
- 消息详情到“问”的受控上下文跳转,以及在会话中持续显示消息来源。
- “问”对消息类、知识类、真实待办类问题的意图分流与回答纠偏。
- 管理端的发布、撤回/修订、范围配置、阅读审计和失败记录。
### 2.3 明确不纳入首版
- 高管直通、财务/人力/审计直达、匿名建议、投诉受理及其工单分派。
- 企业微信、短信、电话等强触达渠道;H5 的页面内提醒不能被表述为系统级推送。
- 正式请假、考勤、排班、工单、线索、客户画像和北森审批。
- 依据一条消息自动创建训练任务、工作任务、成果记录或 `COMPANY/PENDING` 外部流转。
- 将问师傅改造成长期个人记忆。现有会话仍保持 30 分钟不活跃过期、最近六轮上下文和显式“新对话”。
## 3. 目标体验与信息架构
### 3.1 一条消息的员工闭环
```mermaid
flowchart LR
A[管理端发布公司消息] --> B[服务端生成版本、范围与附件索引]
B --> C[银城大喇叭:全员频道]
B --> D[命中员工:置顶或提醒]
D --> E[首页右上角喇叭红点]
C --> F[消息详情:原文、附件、摘要]
E --> F
F --> G[就这条消息问数字师傅]
G --> H[服务端校验消息、版本与当前身份]
H --> I{问题类型}
I -->|消息解释| J[仅依据消息及获授权附件回答]
I -->|制度/SOP| K[企业知识检索并给出来源]
I -->|我现在做什么| L[查询当前真实任务]
L -->|有任务| M[展示真实任务和可执行入口]
L -->|无任务| N[明确无待办,仅给可选建议]
```
### 3.2 首页与列表
**首页入口**
- 复用“今日”首页右上角现有喇叭图标,名称为“银城大喇叭”。
- 登录后根据服务端返回的未读数展示红点或数字;未登录时不展示假未读,点击后先进入登录。
- 红点只表示当前员工仍有未读的已发布消息;读取成功后应实时消退,不允许前端写死演示状态。
**频道列表**
建议提供三个筛选,不增加复杂频道树:
| 筛选 | 内容 | 排序规则 |
|---|---|---|
| 全部 | 租户内已发布、可公开给员工查看的全部消息 | 发布时间倒序;目标命中置顶优先 |
| 与我有关 | 当前身份被配置为提醒/置顶对象,或 AI 能明确说明相关点的消息 | 提醒优先,再按发布时间 |
| 必读/未读 | 标记为必读且当前员工尚未阅读的消息 | 必读优先,按发布时间 |
“与我有关”是帮助理解和排序的增强能力,不是对公司公开内容的访问过滤。首版发布人只能在大喇叭发布可向全租户员工公开的内容;涉及敏感人员、薪酬、纪律或审批材料,应走专门授权系统,不应通过本频道分发。
### 3.3 消息详情
消息详情是员工理解和追问的起点,固定包含:
- 标题、正文、发布时间、发布人、消息版本、适用提示。
- 附件清单与受保护下载;AI 摘要只用于快速理解,必须可回到原文/原件。
- “与我有关”:说明是因项目、岗位、层级或内容主题而被提醒;匹配不确定时显示“可能与你相关”,不能伪装成确定命中。
- 阅读状态:打开详情即请求记录阅读;阅读记录以服务端成功写入为准。
- 主行动按钮:**“就这条消息问数字师傅”**。
按钮点击后进入既有“问”模块,顶部出现可关闭的上下文条,例如“正在咨询:夏季服务标准通知(v2)”。员工可继续多轮追问;关闭上下文条或点击“新对话”即退出该消息语境。
## 4. 银城大喇叭功能设计
### 4.1 发布与版本
| 能力 | 首版规则 | 审计要求 |
|---|---|---|
| 草稿与发布 | 仅具备发布权限的管理人员可新建、保存草稿、发布 | 记录创建人、发布人、发布时间 |
| 内容 | 通知、制度、新闻、文件、图片等公开公司信息 | 保存正文、附件、来源和内容哈希 |
| 版本修订 | 已发布内容修订后产生新版本;重大变更可重新提醒 | 保留版本链,消息问答引用具体版本 |
| 撤回 | 撤回后频道不可再展示;已读审计保留 | 记录撤回人、时间、原因 |
| 必读 | 标记后进入员工“必读/未读”筛选,可配置提醒 | 不把“已发布”误写为“已送达” |
首版建议控制在“可公开发布的信息”。制度、通知的审批责任仍由线下或既有管理制度承担;大喇叭保存的是发布证据,不取代企业正式发文流程。
### 4.2 目标匹配、提醒与可见性
分发策略采用“**公开可查 + 定向优先**”:
1. **公开可查**:租户内员工可从“全部”频道查阅已发布内容,避免因为组织资料缺失而完全错过信息。
2. **定向优先**:发布人可按项目、岗位、层级配置提醒/置顶对象;命中的员工在列表和未读提示中获得优先呈现。
3. **低置信提示**:组织资料不完整或匹配存在歧义时,降级为“可能与你相关”,同时保留在全员频道,不做静默丢弃。
4. **失败可查**:对需要提醒的对象,生成目标快照和处理状态;匹配失败、用户身份无效或提醒写入失败都应进入运营待处理,而不是显示“已覆盖”。
组织匹配以服务端的租户、当前有效组织身份、项目、岗位、层级为准。客户端不得传入或伪造项目编码、岗位编码来改变自己是否命中。
### 4.3 文件、摘要与“与我有关”
| 能力 | 规则 |
|---|---|
| 原件 | 附件沿用受保护资源交付,员工每次访问仍需重新授权;不能把真实下载地址直接写入消息正文 |
| 摘要 | 发布或解析时生成简短摘要;模型失败时显示“摘要暂不可用”,原件仍可阅读 |
| 与我有关 | 按员工已授权的项目、岗位、层级及消息内容生成简明说明,并标识依据;不能根据未授权个人数据推断 |
| 过期内容 | 若消息有有效期,到期后从默认列表降级或隐藏,但保留审计和管理端查询能力 |
| 版本一致性 | 摘要、相关性说明、附件解析结果都绑定消息版本;版本更新后不得把旧摘要当作新正文解释 |
### 4.4 阅读、补推与运营视图
首版需要的运营数据是“发布是否可追溯”,而非展示未经验证的覆盖率或日活:
- 发布数、已读人数、未读人数、必读未读人数、目标匹配失败数。
- 按消息查看目标快照、首读时间、最后读取版本和提醒状态。
- 对未读对象支持人工再提醒;每次操作记录操作者和时间。
- 员工已读某一版本后,若发布人更新为重大版本,可重新成为未读;是否重新提醒由发布人明确选择。
## 5. “问”模块纠偏设计
### 5.1 回答的三条受控路径
| 员工问题 | 可使用的数据 | 正确回答形态 | 禁止行为 |
|---|---|---|---|
| “这条通知是什么意思?”“我需要注意什么?” | 当前已授权消息、该消息版本及其获授权附件 | 围绕原文解释,注明“依据本条消息”或附件来源 | 把未出现在消息中的要求说成通知结论 |
| “这个流程怎么做?”“请假制度是什么?” | 企业知识库、SOP、制度文件 | 给步骤、适用条件和来源;正式审批入口不存在时明确说明 | 把制度咨询变成已经提交/已经批准的业务结果 |
| “我现在该做什么?”“我有什么培训待完成?” | 当前员工真实任务状态、当前组织身份、被授权的任务/训练数据 | 有任务:给出任务名称、状态、截止信息和真实入口;无任务:明确没有查到待办 | 用通用课程、岗位建议或别人的任务生成强制行动卡 |
优先级是:**真实任务事实 > 当前消息原文 > 授权知识来源 > 非强制建议**。模型只能组织语言,不得替代事实判断。
### 5.2 消息上下文追问
员工从详情页发起追问时,前端只传递 `messageId`(以及会话延续所需的既有上下文标识),**不传递或信任消息正文、附件文本和目标范围**。后端必须:
1. 根据当前登录身份重新校验该消息属于本租户、已发布、未撤回且当前员工可查看。
2. 读取消息的当前或指定版本、已授权附件解析内容和来源标识。
3. 将消息内容作为“可引用资料”而非系统指令,防止正文中的提示语改变模型权限或行为。
4. 在回答中标明来源:例如“根据《夏季服务标准通知》v2……”。消息未说明的内容,要直接说明“本条消息未明确”,再建议查对应制度或咨询负责人。
5. 维持既有短会话规则:30 分钟不活跃过期、最近六轮;不能因为带了消息来源而变成长时记忆。
消息被撤回、版本过期或员工权限变化后,后续提问应返回明确的不可用说明,不得继续以缓存内容作答。
### 5.3 “我现在做什么”的事实规则
为避免把“建议”说成“待办”,需新增一个面向回答引擎的**当前任务状态汇总工具**。它只聚合现有已授权任务来源,例如入职/学习任务、已下发训练、主管正式指派的待办;首版不另建平行任务表。
| 任务状态 | 回答与界面规则 |
|---|---|
| 查到一项或多项真实待办 | 说明任务名称、来源、状态、截止信息(如有)和真实跳转入口;行动卡必须指向真实功能 |
| 当前未查到待办 | 明确回复“当前没有查到分配给你的待办/训练任务”;可提供“查看学习中心”“咨询主管”等可选建议,不能称为必须完成 |
| 任务源暂不可用 | 明确说明当前无法确认,提示稍后再试或联系负责人;不回退成臆造任务 |
| 员工提到其他岗位 | 以服务端当前岗位为准;其他岗位资料只能标记为“跨岗位参考”,不生成该岗位的任务结论 |
示例:当前身份为保洁、没有入职待办的员工询问“生活顾问今天要做什么”。正确答法是说明“你的当前岗位为保洁,暂未查到待办;以下是生活顾问岗位的参考流程”,而不是直接要求其开始“生活顾问 5/30 天训练计划”。
### 5.4 页面交互纠偏
- 对话是“问”页面主体。首轮可展示快捷问题、项目/成果入口和能力说明;一旦开始对话,这些辅助区域收起为轻量入口。
- 消息追问时,顶部固定显示可关闭的来源条;回答卡的来源链接可回到消息详情或制度原文。
- 只有查到真实待办时才展示强行动按钮,如“去训练”“查看任务”。
- 无待办、无权限或数据暂不可用时,使用明确状态卡,不显示伪造的进度、截止日期或完成入口。
- 保留既有文字、语音、单次图片/视频分析能力,但不把附件当作长期记忆,也不把媒体分析结果自动写入大喇叭或任务系统。
## 6. 建议的领域模型与接口契约
以下为实施契约建议,具体字段以现有 TechSpec、数据库迁移评审和权限模型为准。新增业务放入 `ruoyi-aihr`,不改写上游框架的普通公告能力。
### 6.1 数据对象
| 建议对象 | 核心内容 | 说明 |
|---|---|---|
| `aihr_broadcast_message` | 租户、标题、正文、状态、必读、有效期、当前版本、发布/撤回信息 | 大喇叭的主消息,不复用 `sys_notice` 充当定向消息 |
| `aihr_broadcast_version` | 消息版本、内容快照、变更说明、发布版本标记 | 保证阅读、摘要和问答可追溯到具体版本 |
| `aihr_broadcast_attachment` | 消息版本、受保护资源引用、解析/摘要状态 | 不保存公开下载 URL;资源访问继续重新鉴权 |
| `aihr_broadcast_target` | 目标规则快照、命中员工、匹配依据、提醒状态 | 目标用于提醒/置顶与审计,不改变公开频道可见性 |
| `aihr_broadcast_read` | 员工、消息版本、首次/最后阅读时间 | 使用唯一约束保证重复打开幂等 |
| `aihr_broadcast_relevance` | 消息版本、员工、相关性文本、依据、置信标记 | 低置信只显示“可能与你相关”,不作为权限依据 |
禁止把大喇叭发布直接写成工作助手的 `COMPANY/PENDING`,也禁止把阅读事件自动写入“今日工作成果”。它们是不同业务事件。
### 6.2 API 轮廓
| 调用方 | 建议接口 | 关键约束 |
|---|---|---|
| 员工端 | `GET /api/aihr/broadcast/unread-count` | 仅返回当前登录员工真实未读数 |
| 员工端 | `GET /api/aihr/broadcast/messages` | 支持全部、与我有关、必读/未读;服务端按当前身份排序 |
| 员工端 | `GET /api/aihr/broadcast/messages/{id}` | 重新校验租户、发布状态、有效期和资源权限 |
| 员工端 | `POST /api/aihr/broadcast/messages/{id}/read` | 对消息版本幂等记录阅读 |
| 问模块 | 现有 `POST /api/knowledge/query` 增加可选 `messageId` | 只能由后端加载消息上下文;不能接受客户端正文作为可信上下文 |
| 管理端 | `/api/aihr/broadcast/messages/**` | 草稿、发布、修订、撤回、目标规则、审计和人工再提醒;按发布权限控制 |
接口路径是本方案的建议命名,落地前需与既有 `API_INTEGRATION.md`、移动端鉴权和多租户拦截规则统一。所有写操作应包含幂等或版本校验,避免重复点击产生多次阅读、重复提醒或覆盖新版本。
### 6.3 问答所需的任务数据工具
现有知识检索接口继续处理 SOP、制度、文件和媒体问答;另增加服务端内部的“当前任务状态”查询能力,供问答编排调用。该能力的输出至少包含:
- 事实来源类型和记录 ID;例如学习任务、训练任务或主管指派。
- 任务名称、状态、截止时间(如真实存在)、所属项目和合法跳转入口。
- 数据新鲜度及不可用原因。
- 当前组织身份和岗位,以便处理跨岗位问题。
它不接受前端传入的岗位、项目编码或“请给我安排任务”等字段来生成事实。模型只有在该工具返回真实任务后,才可输出强制性待办和跳转动作。
## 7. 权限、安全与数据边界
| 风险点 | 控制要求 |
|---|---|
| 越权查看消息 | 每次列表、详情、问答上下文和附件访问都按当前租户与身份校验;消息 ID 不是授权凭证 |
| 旧版本误答 | 回答、摘要、阅读记录绑定消息版本;撤回/更新后不得继续用失效正文解释 |
| 客户端伪造上下文 | 前端只提交消息 ID;正文、附件文本、目标规则与岗位信息均由服务端加载 |
| 提示词注入 | 消息/附件只作为资料,不可修改系统权限、工具调用或角色判定 |
| 错把建议当任务 | 真实任务工具是唯一强行动事实源;缺失时给“无待办”或“暂无法确认” |
| 外部流转被伪造 | 不因阅读或提问自动派工、发消息、创建工作成果;外部接口仍须显式确认和状态回执 |
| 过度收集 | “与我有关”只使用该员工已授权组织属性,不使用敏感个人画像作为定向依据 |
## 8. 分批实施与依赖关系
大喇叭属于总体计划的 R2 高频协作能力;“问”的事实纠偏是现有能力质量修复,应先于或与 R2 同步完成,不能等到消息页面上线后再处理。
| 批次 | 交付内容 | 前置条件 | 完成证据 |
|---|---|---|---|
| A:问模块事实纠偏 | 任务状态工具、意图分流、跨岗位标注、无待办状态卡、会话页面收纳 | 明确可聚合的现有任务来源和当前身份字段 | 真实账号下有任务/无任务/跨岗位三类 API 与页面验证 |
| B:大喇叭核心 | 消息领域模型、发布/修订/撤回、首页入口、列表、详情、已读未读 | 发布角色、可公开内容范围、组织匹配字段确认 | 发布—阅读—版本—审计闭环;390×844 页面截图与交互记录 |
| C:消息追问融合 | `messageId` 受控上下文、来源条、消息引用、附件再鉴权 | B 已有可审计的消息版本和资源引用 | 员工从详情追问、连续追问、撤回/换版本/越权三类回归 |
| D:运营增强 | AI 摘要、相关性说明、人工补推、失败队列与报表 | 核心阅读与组织匹配运行稳定 | 摘要可回原件、低置信提示、补推审计与失败可见 |
| E:另案能力 | 员工直达/匿名建议、企业微信或短信、北森/审批/工单 | 业务负责人、权限、回执与 SLA 明确 | 独立 BRD、TechSpec、接口和正式环境验收 |
### 8.1 建议实施顺序
1. 先完成 A:解决“问”会误导员工的质量问题,并为消息追问准备可信任务结论。
2. 再完成 B:让消息具有稳定的发布、版本、阅读和权限事实。
3. 完成 C:将“就这条消息问”接入成熟的短会话机制。
4. 最后才做 D 的 AI 摘要和智能相关性。即使 AI 服务不可用,B/C 的原文阅读和人工提问仍应可用。
### 8.2 代码与页面影响面(实施前复核)
| 层级 | 预计责任区域 | 约束 |
|---|---|---|
| 员工端 | `mobile-uni/src/pages/user/today/`、新增大喇叭页面、既有“问”页面 | 保持底栏“今日/练/问/我”;不回到旧 `mobile/` 承载新功能 |
| 管理端 | 现有管理端业务路由及大喇叭发布/审计页面 | 不把页面能力误称为正式全员覆盖 |
| 后端 | `backend/ruoyi-modules/ruoyi-aihr` 的消息、阅读、问答编排和任务状态聚合 | 不把业务代码塞进上游 `ruoyi-demo`;多租户和当前身份由服务端裁决 |
| 数据与迁移 | 新增 `aihr_broadcast_*` 表及必要索引 | 不自动把历史 `sys_notice` 当作已审计大喇叭消息;如需迁移,应经内容和权限人工确认 |
| 测试与证据 | 后端权限/幂等测试、移动端交互测试、真实账号回归 | 区分本地验证、视觉验证、部署和正式试点/生产验证 |
## 9. 验收清单
### 9.1 必须通过的功能与权限场景
| 场景 | 期望结果 |
|---|---|
| 发布全员消息 | 任一员工可从“全部”看到;发布记录、版本和附件可追溯 |
| 发布项目/岗位提醒 | 命中员工看到置顶/未读;未命中员工仍可从全员频道查阅公开消息 |
| 组织信息缺失 | 不丢消息;可见于全员频道,运营端出现匹配异常或低置信记录 |
| 读取消息 | 首次打开记录阅读;重复打开不产生重复记录;新版本按规则重新成为未读 |
| 受保护附件 | 当前有权员工可打开;换用户、换租户或失效后不能凭旧链接下载 |
| 从消息追问 | 回答引用当前消息或附件;消息没有写明的内容明确说明未知 |
| 越权消息 ID | 不能通过构造 `messageId` 读取或提问其他租户/不可用消息 |
| 有真实任务 | “我现在做什么”只展示当前员工确实存在的任务和真实入口 |
| 无真实任务 | 明确“未查到待办”,不生成伪任务、伪截止日或“去完成”按钮 |
| 跨岗位提问 | 服务端真实岗位优先;其他岗位只能作为参考说明 |
| 外部能力未接通 | 不显示“已请假”“已派单”“已送达”等成功结论 |
### 9.2 视觉与交互验收
- 在 390×844 员工端视口检查:首页喇叭、红点、列表筛选、详情、来源条、消息追问、无待办卡、错误态和返回路径。
- 验证会话开始后,快捷问题和支撑卡不会压缩主对话区或遮挡输入框。
- 验证消息摘要、相关性说明、附件、版本和“就这条消息问”层级清楚,原文入口始终可见。
- 实际点击验证,而非仅凭截图:未读变化、阅读写入、来源跳转、关闭上下文、新对话和登录拦截均须可操作。
### 9.3 发布与回滚
- 首次发布前以 feature flag 控制员工端入口与管理端发布权限;先用试点租户和真实组织数据验证。
- 数据库迁移应前向兼容;上线后如需回滚,优先关闭入口和发布能力,不删除已产生的发布、阅读与审计记录。
- 所有结论分别记录“已实现 / 本地验证 / 视觉验证 / 已部署 / 生产验证”,不得把其中任一层级外推为正式试点验收。
## 10. 需要确认的产品决策
以下事项会影响实现,但不影响本方案的核心方向,应在开发前由业务负责人确认:
1. 首版哪些管理角色可以发布、撤回和人工补推;是否需要发布前审核。
2. 哪些内容允许进入“面向全员可查”的大喇叭;涉及敏感信息时采用何种专门系统。
3. “必读”的业务定义:只做未读提醒,还是需要主管跟进;首版不自动产生考核或处罚。
4. AI 摘要与“与我有关”的人工校正机制、内容有效期和历史留存周期。
5. 后续是否接企业微信/短信等强触达渠道;如接入,接收对象、频率、失败回执和退订规则需另立接口与合规设计。
## 11. 结论
“银城大喇叭”应成为银城帮道的**可信公司信息入口**,而不是一个带红点的公告壳;“问”应成为员工**理解消息、理解制度、核验自己真实待办**的助手,而不是把知识库推荐包装成指令。
因此,首版最关键的产品承诺是:**消息有原文、追问有上下文、行动有事实、无事实就明确说无事实。**