Files
prop-ai-hr/CHANGELOG.md
T
2026-07-26 02:39:40 +08:00

140 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Changelog
本文件记录源码变更、生产发布与验证结果;每项明确标注完成层级。时间均为中国标准时间(CST,UTC+8)。
## Unreleased
- 2026-07-25 23:56–2026-07-26 02:40 的 App-Plus 批次已提交但**尚未发布**:未构建云打包 App、未发布 H5、未发布后端 JAR、未重启服务。见下两节。
## 2026-07-26 02:35–02:40|恢复 App 端回复语音优先
### 功能与修复
- **2026-07-26 02:38**(`d84ad87c`):恢复 App 端回复的语音优先形态。`73712994` 用 `!isNativeAppRuntime()` 关掉原生端 TTS 预生成后,App 上每条回复都退化成纯文字气泡加 `播报` 按钮;语音条、`转文字`、`收起全文` 的模板与样式一直在包内但无法到达。现预生成在所有平台生效,消息以 `transcriptOpen: true` 建立,合成期间文字即可读,不必等一次 TTS 往返。
### 取舍与偏离
- **2026-07-26 02:38**:收起文字的触发点定为**开始播放**,不是合成完成。真机实测本地合成 2–6 秒即就绪,若按合成完成收起,文字会在读到一半时被抽走、只闪约 3 秒,与「不必等」的意图相反。新增 `transcriptPinned` 记录手动 `转文字`/`收起`/`收起全文`,自动收起不覆盖读者选择;不播放则文字一直可读。
- **2026-07-26 02:38**:`preparing` 语音条加 20 秒上限(对齐后端 DashScope 上游超时),超时按 `unavailable` 退化成纯文字加 `播报`,避免永久停在占位时长。该上限只结束界面等待态,**不中止**已发出的合成请求。
- **2026-07-26 02:38**:语音条显示 `语音` 而非微信式 `12"`。`measureAudioDuration` 依赖全局 `Audio`,App-Plus 逻辑层无该对象直接返回 `null`。属该形态既有缺口,非本次引入;修法需改走 `uni.createInnerAudioContext` 的 `duration`,因该函数被对练与摘要播报共用,**未改**。
- **2026-07-26 02:38**:`tests/agent.test.mjs` 中原断言以 `!isNativeAppRuntime()` 等源码字符串锁住旧行为,属同义反复,已换为行为断言:语音优先不依赖平台、合成完成不得收起文字、播放才收起、超时有兜底。
### 验证与边界
- **2026-07-26 02:40**:`vue-tsc --noEmit` 通过;前端单测 `168/168` 通过。`build:app` 按产物核验含 `app-service.js`、`app-renderjs.js`、`manifest.json`,不以 `DONE Build complete.` 为准。
- **2026-07-26 02:40**:真机取样(包推 `__UNI__B36D8BE` 后重启基座):3 秒为 `…` 合成中加红点、文字可读、`收起全文 ▲`;12 秒语音就绪而文字仍在;点播放后文字收起、红点清除;26 秒回到空闲,未复现挂死。
- **2026-07-26 02:40**:**未验证**音频是否真实出声——状态机走完整链路,但设备音频输出无法取证,需人工试听。
- **2026-07-26 02:40**:本节完成层级为「已实现、已本地验证、已提交」。**未构建云打包 App、未发布 H5、未发布后端 JAR、未重启服务**。
- **2026-07-26 02:40**:排障口径修正。`adb exec-out screencap -p` 的 PNG 直接读取会静默返回空内容,若据此描述界面会得出凭空结论;本批已改为先 `sips` 转换/裁剪再读。据此撤回两条本轮口头结论:「App 端 TTS 挂死」(实测本次 2–6 秒合成成功)与「设备弹出 SDK 版本不匹配窗口并吞掉点击」(界面无该弹窗,点击落空系启动时序)。
## 2026-07-25 23:56–2026-07-26 00:02|App-Plus 实时对练与构建链修复
### 构建链修复(本批最重要)
- **2026-07-25 23:56**(`a3a5cf94`):修复 `npm --prefix mobile-uni run build:app` 长期**假绿**。`@dcloudio/uni-app-plus` 从未被声明为依赖,缺少该编译器时 `uni build -p app` 不报错、退出码 `0`、照样打印 `DONE Build complete.`,但产物只有 `index.html`(仍带 H5 的 `/h5/assets/...` 基路径)、字体和一个 `704` 字节 preload 片段,没有 `app-service.js`、`app-renderjs.js`、`manifest.json`。
- **2026-07-25 23:56**:因 `docs/MOBILE_APP_PACKAGING.md` 把该命令列为本地验证步骤,本批 renderjs 实时对练代码在装上编译器之前**从未经过 App 编译器**,却曾被当作已验证。本次已按同版本 `3.0.0-alpha-5020120260710001` 声明编译器,在 `tests/app-packaging.test.mjs` 加版本对齐闸门,并在打包文档写明:判定 `build:app` 成功只看产物是否含 `app-service.js`、`app-renderjs.js`、`manifest.json`,不看 `DONE Build complete.`。
### 功能与修复
- **2026-07-25 23:58**(`5cf7ce58`):实时对练支持 App-Plus。媒体与 WebRTC 引擎移入 `realtime-browser-engine.js`,由 `components/practice/RealtimePracticeAppBridge.vue` 的 renderjs 脚本在系统 WebView 内执行;认证的 SDP 交换与 `search_knowledge` 工具调用仍留在逻辑层代理,access token 不下放视图层。H5 路径行为不变。
- **2026-07-25 23:56**(`27f4cdac`):部分 uni-app 平台忽略 `uni.request` 的 `timeout`,导致 Promise 永挂、页面无错误出口。改为本地驱动超时,单次 `finish` 守卫保证只 settle 一次,超时先 `task.abort()` 再 reject。
- **2026-07-25 23:57**(`3055d2be`):替换 App-Plus 不支持的两个 API。`URLSearchParams` 在 App-Plus JS core 缺失,`toLocaleDateString('sv-SE', { timeZone: 'Asia/Shanghai' })` 依赖 App 运行时未附带的完整 ICU 数据,二者曾让工作成果页拼出错误查询串或取到设备本地日期。改为 `encodeURIComponent`,业务日统一走 `currentShanghaiDate()` 固定 UTC+8 偏移;Asia/Shanghai 无夏令时,固定偏移是精确值而非近似。
- **2026-07-25 23:58**(`73712994`):原生 App 不再预生成答案 TTS。此前消息以 `preparing` 建立,文字被卡在等待一次 TTS 往返之后;改为原生端标记 `unavailable` 让文字与引用立即渲染,语音由既有 `unavailable` 分支的播放按钮按需触发,不是取消语音。H5 仍保留预生成。
- **2026-07-25 23:58**(`7b014765`):Agent 追问不再答成澄清。规划器在无关键词命中且模型规划不可用/不合法时回落 `CLARIFY`,导致「如果我要报销,一般需要查哪几个文件?」这类已有上下文的追问被要求澄清。现非媒体请求带 `conversationId` 且 `contextVersion > 0` 时改走 `KNOWLEDGE_QA` 接地检索。**取舍**:第二轮起对「你看着办」「帮我处理一下」这类刻意模糊表述的主动澄清也一并被抑制,会改为执行知识检索;空输入仍由 `requireQuestion` 提前拒绝。
- **2026-07-25 23:58**(`c9f5271d`):补记 `30ef6a8f` 已发布的 `/api/aihr/org/sync-changes` 增量同步契约到 `AGENTS.md` 与 `docs/API_INTEGRATION.md`(稳定 `employee.id` 主体键、先 `dryRun=true` 后同起点 `dryRun=false`、全量 `/sync` 对脱敏手机号与重复成员关系 fail-closed)。仅文档,无代码变更。
- **2026-07-25 23:59**(`4fc0c1f5`):App 版本升至 `0.1.5`(`versionCode 105`)。原生权限与插件未变,属常规云打包重建。
### 验证与边界
- **2026-07-26 00:01**:`vue-tsc --noEmit` 通过;前端单测 `162/162`、后端 `694/694` 通过。后端须显式加 `-DskipTests=false`——`backend/pom.xml` 第 60 行把 `skipTests` 默认设为 `true`,不带该参数的 `mvn test` 是空跑且照样输出 `BUILD SUCCESS`,与上面 `build:app` 是同类假绿。
- **2026-07-26 00:01**:`build:app` 在补齐编译器后产出真实 App 包,并按产物核实分层:`RTCPeerConnection` 与 `getUserMedia` 只出现在 `app-renderjs.js`,`realtime/sdp` 端点只出现在 `app-service.js`,renderjs 侧 `0` 命中。
- **2026-07-26 00:02**:以上仅证明 App 平台可正确编译且分层正确。麦克风授权、实时转写、远端语音播放、前后台切换、断线降级只能在真机 WebView 验证,**未验证**;口径已写入 `docs/MOBILE_APP_PACKAGING.md` 与 `docs/MOBILE_APP_DEVICE_ACCEPTANCE.md`。
- **2026-07-26 00:02**:本批完成层级为「已实现、已本地验证、已提交」。**未构建云打包 App、未发布 H5、未发布后端 JAR、未重启服务、未执行 schema 迁移**;`7b014765` 的 Agent 追问修复需后端 JAR 发布后才在生产生效。
## 2026-07-25 15:40–16:15|组织姓名与考试发布修复
### 生产数据修复
- **2026-07-25 15:40**:在 `/opt/wygj/backups/org-name-sync-20260725-1540/org-data.sql` 备份生产组织数据;备份大小 `711248` 字节,SHA-256 为 `9e298bf5e6ac88b6d0e105f510cad3fb9838ed1cf0324a23ee15453a54e3c9dd`。
- **2026-07-25 15:40–15:48**:刷新开放组织目录并将租户 `000000` 绑定到集团根节点 `G:1`。仅按稳定 `employee_id` 精确匹配,补齐 `aihr_org_snapshot.person_name` 共 `3417` 行;未改手机号、项目、岗位和在职状态。
- **2026-07-25 15:48**:生产复核为组织快照 `3417` 行、在职 `2938` 人、在职有姓名 `2938` 人、手机号映射 `3392` 个。使用既有生产主管账号调用团队接口返回 `2316` 名成员,姓名完整 `2316` 名、编号兜底 `0` 名;账号、手机号、验证码和 Token 未写入仓库、截图或本记录。
- **2026-07-25 15:48**:未执行全量组织覆盖。只读预检发现上游 `3424` 名员工中 `3398` 个手机号已脱敏、存在 `1` 条重复项目成员关系,并且当前 `employee_number` 仅能匹配生产既有主体 `7/3417`,稳定 `employee_id` 可匹配 `3417/3417`。在身份字段契约和手机号通道修复前,禁止用 `allowPartialReplace=true` 绕过后执行覆盖同步。
### 考试发布修复
- **2026-07-25 15:55**:移除客户端“考试名称至少 4 个字”的无依据限制,改为仅要求名称非空;同时保留及格分 `1–100`、至少一道题、总分 `100`、题干/选项/答案完整和至少选择一名员工的发布校验。备份当时生产 H5 到 `/opt/wygj/backups/h5-exam-title-20260725-1555/` 后完成首次静态发布。
- **2026-07-25 16:09**:复核发现 `16:01` 的后续 H5 发布重新带入旧 `length>=4` 校验;该次覆盖被识别为生产回退,未将 `15:55` 的短暂上线状态作为最终完成。
- **2026-07-25 16:12**:基于当前主线 `75469b85` 重新构建 H5,保留已发布的陪练“建议回复”功能并叠加考试修复;发布前备份到 `/opt/wygj/backups/h5-exam-restore-20260725-1612/`。生产入口更新为 `/h5/assets/index-QQ2kC1xm.js`,考试页资源为 `/h5/assets/pages-supervisor-exams-edit.B-v9k7L-.js`。
### 验证与边界
- **2026-07-25 16:12**:目标回归 `5/5`、`vue-tsc --noEmit` 和 `npm --prefix mobile-uni run build:h5` 通过;生产考试资源包含“请填写考试名称”和“发布前请至少选择 1 名员工”,不再包含旧 `length>=4` 校验。
- **2026-07-25 16:14**:在生产 H5 `390×844` 视口使用隔离浏览器会话和两名模拟员工完成无写入验收;考试名“测试”可通过名称校验,员工姓名正常显示,“发布给 2 人”按钮启用,未调用保存或发布接口。
- **2026-07-25 16:15**:本次结论为:姓名数据修复已生产验证,考试校验已实现、已本地验证、已重新部署并完成生产 H5 浏览器验证;未执行后端 JAR 发布、服务重启、schema 迁移或全量组织覆盖。对应两处考试源码改动仍在工作区,尚未提交。
## 2026-07-25 15:44–16:05|陪练建议回复
### 功能更新
- **2026-07-25 15:44:45**:完成常规陪练“建议回复”(提交 `acd5fd3a`)。“用这句话回复”改为由 LLM 根据当前会话、回合和老师傅提示生成一条员工可直接回复的新话术,不再复制指导语。
- **2026-07-25 15:44:45**:移动端将 LLM 生成结果只填入输入框,由员工修改后主动发送;生成期间禁用重复点击,接口失败时显示明确错误。
- **2026-07-25 15:44:45**:服务端在既有训练会话归属和身份校验内生成建议回复,不推进训练回合、不改写训练证据;普通训练回合继续保留模型失败时的 seed 降级。
- **2026-07-25 15:44:45**:训练 `/turn` 接口新增 `suggestReply` 请求参数和 `suggestedReply` 响应字段,并保留旧请求、旧响应构造方式兼容。
### 生产发布
- **2026-07-25 15:52:03**:备份生产后端 JAR 与完整移动端 H5,备份目录为 `/opt/wygj/backups/practice-reply-20260725155203-acd5fd3a`。
- **2026-07-25 15:52:45**:将提交 `acd5fd3a` 构建的后端 JAR 原子切换到 `/opt/wygj/app/ruoyi-admin.jar`;本次功能不涉及数据库结构变更。
- **2026-07-25 15:53:16**:重启 `wygj-aihr.service`;Spring Boot 于 `15:53:35` 完成启动。
- **2026-07-25 16:01:13**:将隔离工作树构建的移动端 H5 最终同步到 `/opt/wygj/www/h5`,生产入口固定为 `/h5/assets/index-BDNPeJuO.js`。
- **2026-07-25 16:01–16:02**:完整生产预检通过,确认管理端与移动端静态资源匹配、AIHR 后端模块匹配、schema `64/64`、运行时 schema bootstrap 关闭。
### 线上验证
- **2026-07-25 16:02–16:04**:从生产组织快照只读选择手机号与外部 ID 双向唯一的在职保洁员工,先请求短信验证码再登录;账号值未写入终端输出、截图、报告或仓库。
- **2026-07-25 16:04:03**:在 `390×844` 视口走完场景启动、员工回复、老师傅提示和“用这句话回复”主路径;LLM 生成新的员工话术并填入输入框,没有自动发送,也没有复制老师傅提示,输入框和发送按钮显示完整。
- **2026-07-25 16:04**:发布后复核 `wygj-aihr.service` 为 `active`,自 `15:52:00` 起错误级别日志为 `0`,生产 H5 仍返回 `/h5/assets/index-BDNPeJuO.js`。
### 验收边界
- **2026-07-25 16:04**:本次结论为:**已实现、已部署、已完成生产 H5 浏览器验证**。
- **2026-07-25 16:04**:本次验证不替代 Android/iOS 真机验收,也不代表正式试点窗口、业务内容审核或严格试点指标已经通过。
## 2026-07-25 15:18–15:42|公司文件多岗位解读
### 功能更新
- **2026-07-25 15:18:58**:完成公司文件多岗位解读代码收口(提交 `230dfb4d`)。管理端上传文件并完成正文提炼后,异步生成有原文依据的岗位视角;单个视角包含岗位名称、解读内容、行动建议和原文短引用。
- **2026-07-25 15:18:58**:管理端增加解读状态展示,明确区分“正在生成、已完成、部分完成、生成失败”,并展示已经生成的岗位名称。解读失败不阻断文件摘要、原文件下载、消息发布或消息追问。
- **2026-07-25 15:18:58**:员工端消息详情增加“多岗位解读”。系统优先展示与认证员工岗位匹配的视角;员工可切换查看其他已生成视角,并展开对应的原文依据。
- **2026-07-25 15:18:58**:服务端重新校验租户、登录身份、在职身份、消息状态和附件归属。消息撤回后,员工列表、详情、原文件和后续追问均不再允许访问。
### 数据库更新
- **2026-07-25 15:25–15:26**:生产表 `aihr_broadcast_attachment` 新增 `insight_status`、`insights_json`、`insight_version` 三个字段,并新增 `(insight_status, status, update_time)` 异步队列索引。
- **2026-07-25 15:25–15:26**:迁移仅新增多岗位解读字段和队列索引,不回填历史文件、不修改既有文件 `READY` 状态,也不改变历史消息的发布或撤回状态。
### 生产发布
- **2026-07-25 15:24:06**:完成生产数据库、后端 JAR、管理端和移动端 H5 备份,备份目录为 `/opt/wygj/backups/broadcast-insights-20260725152349`。
- **2026-07-25 15:26:32**:部署新后端 JAR、管理端静态资源和移动端 H5。
- **2026-07-25 15:26:33**:`wygj-aihr.service` 重启并恢复为 `active`。
- **2026-07-25 15:27–15:30**:完整发布预检通过。管理端与移动端静态资源、生产后端 JAR 和 `ruoyi-aihr` 模块哈希均与本地构建一致;生产 schema 为 `64/64`,公司文件附件契约为 `15/15`。
### 线上验证
- **2026-07-25 15:31:52**:管理端上传生产验收 TXT 文件,文件提炼状态进入 `READY`。
- **2026-07-25 15:32:15**:多岗位解读生成完成,共生成“生活顾问/客服、人力、审计/风控、管理层”四个视角,结果状态为 `READY`,规则版本为 `role-perspective-v1`。
- **2026-07-25 15:32:34**:发布全员可见的生产验收消息。
- **2026-07-25 15:38–15:39**:使用生产数据库中的在职员工手机号完成员工端登录验证。在 390×844 视口下验证消息列表、消息详情、四视角切换、行动建议和原文依据展开,未发现横向溢出、内容遮挡或核心入口下沉。
- **2026-07-25 15:39:33**:通过员工端受控入口下载原文件,下载文件 SHA-256 与管理端上传文件完全一致。
- **2026-07-25 15:40:04**:验收完成后撤回测试消息并保留审计原因。
- **2026-07-25 15:40:13–15:40:41**:复核员工端列表不再展示该消息,原详情地址返回“消息不存在或已撤回”。
- **2026-07-25 15:42:11**:更新生产事实文档(提交 `9a34a267`),源码与发布记录已同步至远端 `main`。
### 验收边界
- **2026-07-25 15:42:11**:本次结论为:**已实现、已部署、已完成生产 H5 浏览器验证**。
- **2026-07-25 15:42:11**:本次验证不替代 Android/iOS 真机验收,也不代表正式试点窗口、业务内容审核或严格试点指标已经通过。
- **2026-07-25 15:42:11**:生产验收消息已经撤回;仅保留发布、阅读、下载和撤回审计记录。