feat: add project-scoped work assistant results
This commit is contained in:
+12
-5
@@ -14,12 +14,14 @@
|
||||
| 案例沉淀 `/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` |
|
||||
| 工作助手确认式统一采集 `/pages/user/sop/index`、`/pages/user/assistant/memories` | 既有 `POST /api/knowledge/query` 可选返回 `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`;旧项目记录继续使用 `/api/aihr/service-memories` | 文字或 ASR 转写复用同一候选检测。显式“记一下”生成 `ASSISTANT_CAPTURE/DRAFT`,项目和房屋位置缺失只作可选提示;系统建议 `SERVICE_LEAD/RESIDENT_PROFILE/CASE/PERSONAL_NOTE/FOLLOW_UP/PROJECT_NOTE`。确认必须带 `expectedVersion + idempotencyKey + saveScope(PRIVATE|COMPANY)`;PRIVATE 仅本人可见,COMPANY 写入 PENDING 待流转,正式外部接收端未配置前不得显示已送达。提醒默认关闭且单独确认;音色不在本次范围 |
|
||||
| 工作助手确认式统一采集 `/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 自然日确定性聚合已确认记录;内容未变化时重复生成不增加版本,记录或状态变化后版本递增。主管只可查看本人在目标项目具备主管身份的团队结果,普通员工或跨项目请求返回 403。外部接口未接通时只显示本地状态和 PENDING,不伪造派单或考勤同步成功 |
|
||||
| 成果投稿(当前页面名“工作上报”)`/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` 快照,分页参数使用 `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` 才允许覆盖;重复 `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。当前剩余 25 人手机号不可用属于上游数据质量问题;功能发布不再被组织同步能力阻塞 |
|
||||
| 组织人员同步 | `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 人手机号不可用属于上游数据质量问题 |
|
||||
| 移动端手机号登录 | `GET /resource/sms/code`、`POST /auth/mobile/sms-login` | 已复用 sms4j 阿里云配置 `config1` 和 RuoYi `sms` 授权策略;短信发送成功后才写 Redis 验证码;手机号不存在时自动注册 `app_user`;`aihr.sms.dev-fixed-code` 非空时不真发短信、验证码固定(dev 默认 `123456`)。prod 默认关闭,试点期只有同时设置 `AIHR_SMS_DEV_FIXED_CODE` 与 `AIHR_SMS_PROD_FIXED_CODE_ENABLED=true` 才启用固定码。 |
|
||||
| 用户侧三端首页 `mobile-uni` hash 路由;旧 `/h5/user`、`/h5/candidate`、`/h5/supervisor` 兼容重定向 | `GET /api/aihr/mobile/home/{role}` | 未登录请求只返回不读取租户业务统计的公开首屏 seed;已登录移动端请求自动携带 `Authorization/clientid`,才返回员工/主管真实统计;移动端本地 fallback 保演示 |
|
||||
| 移动端登录后角色识别 | `GET /api/aihr/mobile/me` | 认证后按手机号匹配组织快照;`position_level` 为“主管/项目经理”时进入主管端,否则进入员工端;接口失败回退员工端 |
|
||||
| 移动端登录后角色识别 | `GET /api/aihr/mobile/me` | 认证后按手机号匹配组织快照;`position_level` 为“主管/项目经理”时进入主管端,否则进入员工端。响应返回去重后的 `projects[]` 供页面按项目名称选择,不要求用户输入或记忆编码;同一人员在多个项目的快照行按 `tenant_id + project_code + ext_party_id` 保留。接口失败回退员工端 |
|
||||
| 移动端员工训练与主管复盘闭环 | 员工复用 `POST /api/train/practice/start`、`/turn`、`/finish`,查询 `GET /api/aihr/mobile/practice/history`、`/practice/mistakes`、`/profile`;训练完成后提交 `POST /api/aihr/mobile/practice/satisfaction`;主管查询 `GET /api/aihr/mobile/practice/team`、`/practice/alerts`、`/practice/reviews`、`/practice/reviews/{id}`,标记 `POST /api/aihr/mobile/practice/reviews/{id}/reviewed`,指派 `POST /api/aihr/mobile/practice/assignments` | 员工端登录后带 `Authorization` 与 `clientid` 调用;`mode=mobile` 完成后写入 `aihr_practice_session`。满意度接口只接受本人已完成训练的 1-5 分,意见脱敏后落库,未填写不补默认值。错题本按员工本人聚合低分/红线回合,并关联已有 `retry` assignment,不伪造错题结论。主管 `/practice/team` 在同一项目权限范围内额外返回 `mistakes` 聚合,按场景/归因统计次数、影响人数、平均分和最近发生时间;普通员工返回“无主管权限”。主管接口以后端当前登录手机号映射在职组织快照,仅允许岗位为“主管/项目经理”的账号,并按租户和项目范围返回真实成员、全状态训练记录及非 daily 专项。复盘标记只允许首次 `待复盘 -> 已复盘` 创建后续专项,并发重复提交幂等;可带 `incentivePoint` 写入贡献度。每日三题正式只对 `hire_date` 在当前日期前三个月内的在职员工派发;没有入职日期时不使用训练次数推断,开发 Demo 的旧回退只有在 `dev/local` profile 且由 `aihr.practice.allow-legacy-daily-drill-fallback` 显式开启时生效,生产 profile 强制关闭。 |
|
||||
| 移动端候选人闭环 | 页面拆为 `/pages/candidate/index/index`、`/interview/index`、`/materials/index`、`/progress/index`、`/study/index`;面试复用 `POST /api/recruit/interview/start`、`/answer`、`/finish` 和 `GET /records`;资料 `POST/GET /api/aihr/mobile/candidate/materials`;预习 `POST /api/knowledge/search`;HR 审核 `GET /api/aihr/hr/candidate/materials`、`POST /api/aihr/hr/candidate/materials/{id}/review` | 候选人端登录后带 `Authorization` 与 `clientid` 调用;首页只按当前手机号对应的真实面试记录和最新资料状态分流,不读取公开 home seed。APP 候选人身份以后端登录手机号为准,前端 `candidateId/candidateName` 只作非 APP 场景兼容参数;面试支持文字作答和复用 `/api/ai/asr` 的录音转文字/选音频,`/answer` 可带可选 `answerAudioOssId`,服务端只接受当前候选人名下处于 `staged/bound` 状态的音频并将 `ossId` 写入问题快照,不向客户端暴露原始 OSS URL;`/answer` 与 `/finish` 还会校验当前 APP 手机号与启动会话的候选人 ID 一致,未知或他人会话直接拒绝;面试拉题/评分走真实模型优先;资料写 `sys_oss`/MinIO 和 `aihr_candidate_material`,HR 审核后进度页同步三态;岗前预习查询正式 SOP,不兜前端示例答案 |
|
||||
| 每日题反馈与常见难题 | `POST /api/aihr/mobile/practice/assignments/{id}/feedback`、`GET /api/aihr/mobile/practice/difficulties`、`POST /api/aihr/mobile/practice/difficulties/assign` | 反馈区分题目有用性与答案正确性;主管/管理端按岗位、时间、次数、人数和均分聚合,并可基于难题创建专项;身份和项目范围由服务端解析 |
|
||||
@@ -224,6 +226,8 @@ Content-Type: application/json
|
||||
|
||||
## 工作助手确认式统一采集
|
||||
|
||||
本节记录当前已经部署的接口。当前版本仍允许候选项目为空,也没有当前项目下拉、项目化短会话、原始媒体绑定或今日工作成果接口;这些属于[《工作助手与今日工作成果迭代计划》](工作助手与今日工作成果迭代计划-20260721.md),在代码和接口落地前不得提前写入本指南的可调用接口表。
|
||||
|
||||
该链路复用上面的短会话请求,不新增另一套问答 session。登录员工说“帮我记一下三栋 3203 需要保洁服务”时,`POST /api/knowledge/query` 在正常回答字段之外可返回;缺少单元不会阻断用户保存:
|
||||
|
||||
```json
|
||||
@@ -249,7 +253,7 @@ Content-Type: application/json
|
||||
}
|
||||
```
|
||||
|
||||
确认请求只提交用户在卡片上确认或修改的草稿;`projectCode` 即使传入也不能作为授权依据:
|
||||
确认请求只提交用户在卡片上确认或修改的草稿。`PERSONAL_NOTE` 可以不绑定项目;晨会、巡检、业主服务、画像、线索等项目工作必须先由用户按项目名称选择,草稿携带内部 `projectCode`,但服务端仍以当前登录主体的授权项目集合复核,不能把客户端字段当授权依据:
|
||||
|
||||
```http
|
||||
POST /api/aihr/personal-assistant/memory-candidates/301/confirm
|
||||
@@ -262,15 +266,18 @@ Content-Type: application/json
|
||||
"saveScope": "COMPANY",
|
||||
"enableReminder": false,
|
||||
"draft": {
|
||||
"projectCode": "PRJ-XHW1",
|
||||
"buildingName": "3栋",
|
||||
"unitName": "",
|
||||
"roomNo": "3203",
|
||||
"category": "服务线索",
|
||||
"summary": "需要保洁服务",
|
||||
"occurredAt": "2026-07-19T14:00:00+08:00",
|
||||
"workDate": "2026-07-19",
|
||||
"businessStatus": "PENDING",
|
||||
"followUpAt": null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
服务端在事务中锁定候选,写入 `aihr_assistant_capture` 后才把候选改为 `CONFIRMED`。`PRIVATE` 对应 `deliveryStatus=NOT_REQUIRED`;`COMPANY` 对应 `PENDING`。`DRAFT` 默认 24 小时过期,列表查询强制过滤当前租户与 owner。`GET /api/aihr/personal-assistant/assistant-captures?saveScope=COMPANY&limit=50` 只展示本人的企业流转状态;PENDING 不是已生成工单或已上报成功。后续 `/api/knowledge/query` 可受控召回确认记录,引用域分别为 `PERSONAL / COMPANY / PROJECT_SERVICE`;个人和公司采集按 `tenant_id + owner_user_id` 过滤,旧项目记录继续按项目权限过滤。
|
||||
服务端在事务中锁定候选,写入 `aihr_assistant_capture` 后才把候选改为 `CONFIRMED`。`PRIVATE` 对应 `deliveryStatus=NOT_REQUIRED`;`COMPANY` 对应 `PENDING`。`DRAFT` 默认 24 小时过期,列表查询强制过滤当前租户与 owner。`GET /api/aihr/personal-assistant/assistant-captures?saveScope=COMPANY&limit=50` 只展示本人的企业流转状态;PENDING 不是已生成工单或已上报成功。状态更新带独立 `idempotencyKey`,相同记录和目标状态可安全重试,跨记录或跨目标状态复用返回 409。`/api/knowledge/query` 可受控召回确认记录,引用域分别为 `PERSONAL / COMPANY / PROJECT_SERVICE`;个人和公司采集按 `tenant_id + owner_user_id` 过滤,旧项目记录继续按项目权限过滤。
|
||||
|
||||
Reference in New Issue
Block a user