fix: align Windows dev, App compiler, and ASR

This commit is contained in:
key
2026-07-26 21:27:37 +08:00
parent f57e0a53c6
commit 9ae5f750c8
22 changed files with 698 additions and 791 deletions
+1
View File
@@ -1,5 +1,6 @@
.DS_Store .DS_Store
.env.local .env.local
backend/.env
.data/ .data/
.serena/ .serena/
.playwright-cli/ .playwright-cli/
+4 -3
View File
@@ -20,6 +20,7 @@
- Qdrant:REST `127.0.0.1:6333`,默认 collection `aihr_knowledge`;可用 `AIHR_QDRANT_URL`、`AIHR_QDRANT_COLLECTION`、`AIHR_QDRANT_API_KEY` 覆盖。 - Qdrant:REST `127.0.0.1:6333`,默认 collection `aihr_knowledge`;可用 `AIHR_QDRANT_URL`、`AIHR_QDRANT_COLLECTION`、`AIHR_QDRANT_API_KEY` 覆盖。
- 资料导入根目录:默认 `./.data/import`,由 `scripts/dev-backend.sh` 传入 `aihr.import.root`;也可用 `AIHR_IMPORT_ROOT` 覆盖。 - 资料导入根目录:默认 `./.data/import`,由 `scripts/dev-backend.sh` 传入 `aihr.import.root`;也可用 `AIHR_IMPORT_ROOT` 覆盖。
- 本地私密配置:根目录 `.env.local` 已被 `.gitignore` 忽略,`scripts/dev-backend.sh` 会自动加载;阿里云短信密钥只放这里或外部环境变量,不写入 `application-*.yml`。管理端图形验证码本地默认关闭,只有 `AIHR_DEV_CAPTCHA_ENABLED=true` 才开启;该开发开关不进入生产启动。 - 本地私密配置:根目录 `.env.local` 已被 `.gitignore` 忽略,`scripts/dev-backend.sh` 会自动加载;阿里云短信密钥只放这里或外部环境变量,不写入 `application-*.yml`。管理端图形验证码本地默认关闭,只有 `AIHR_DEV_CAPTCHA_ENABLED=true` 才开启;该开发开关不进入生产启动。
- Windows + Docker Desktop 按 `docs/DEV_SETUP.md` 启动:基础设施跑 Docker,应用跑 Windows,`.sh` 仅用 Git Bash。代理/TUN 干扰 `*.localhost` 时,Vite 从 `portless list` 取端口直连 `127.0.0.1`。
- 后端默认通过 portless 启动,入口 `https://wygj-api.localhost/`;使用 `portless run --name wygj-api ./scripts/dev-backend.sh` 或 `./scripts/dev.sh`,`PORTLESS=0` 回退 `8080`。管理端代理目标在 `frontend/.env.development`。 - 后端默认通过 portless 启动,入口 `https://wygj-api.localhost/`;使用 `portless run --name wygj-api ./scripts/dev-backend.sh` 或 `./scripts/dev.sh`,`PORTLESS=0` 回退 `8080`。管理端代理目标在 `frontend/.env.development`。
- 管理端前端:`./scripts/dev-frontend.sh`,默认走 portless,入口 `https://wygj-admin.localhost/`;显式 `PORTLESS=0` 时回退端口 `5173`。 - 管理端前端:`./scripts/dev-frontend.sh`,默认走 portless,入口 `https://wygj-admin.localhost/`;显式 `PORTLESS=0` 时回退端口 `5173`。
- 当前用户侧前端:`portless` 启动 `mobile-uni`,入口 `https://wygj-mobile-uni.localhost/h5/`。 - 当前用户侧前端:`portless` 启动 `mobile-uni`,入口 `https://wygj-mobile-uni.localhost/h5/`。
@@ -52,7 +53,7 @@
- 管理端业务路由集中在 `frontend/src/router/index.ts`,覆盖首页、AI 面试、训练运营、问题榜、案例、知识空间、SOP、资料处理、大喇叭、五渠道直通反馈、系统配置、组织权限和成长激励;侧栏过滤在 `frontend/src/layout/components/Sidebar/index.vue`,不要恢复若依默认全量菜单。 - 管理端业务路由集中在 `frontend/src/router/index.ts`,覆盖首页、AI 面试、训练运营、问题榜、案例、知识空间、SOP、资料处理、大喇叭、五渠道直通反馈、系统配置、组织权限和成长激励;侧栏过滤在 `frontend/src/layout/components/Sidebar/index.vue`,不要恢复若依默认全量菜单。
- 用户侧只改 `mobile-uni/src/pages/*`;员工、候选人、主管首页分别为 `/pages/user/today/index`、`/pages/candidate/index/index`、`/pages/supervisor/index/index`,旧 `/h5/user|candidate|supervisor|employee|admin` 只做兼容重定向,底栏固定「今日/练/问/我」。“问”统一调用 `/api/aihr/agent/messages|messages/media`,服务端规划意图并按固定策略选择既有工具,客户端不得提交 `toolCode`;旧知识查询仅作底层/兼容。登录端短期会话为 30 分钟/最新 6 轮,原文件/视频经 `/api/knowledge/resources/{attachmentId}/content` 重新鉴权。总结卡只接受当前答案中的最多 5 个 `DOCUMENT` 引用 `fragmentIds`,服务端重新鉴权后仅基于这些片段生成固定「问题/建议/标准」结构;不得二次检索,失败不得拿原文冒充结构化步骤。全网外发必须先同意,显式记忆先出确认卡,再通过不透明 `draftId` 按 `PRIVATE/COMPANY` 确认;`COMPANY` 仅为 `PENDING`,不得冒充已派单或送达。`aihr_agent_run` 不保存问题、答案或附件,外部知识 API 保持无状态。 - 用户侧只改 `mobile-uni/src/pages/*`;员工、候选人、主管首页分别为 `/pages/user/today/index`、`/pages/candidate/index/index`、`/pages/supervisor/index/index`,旧 `/h5/user|candidate|supervisor|employee|admin` 只做兼容重定向,底栏固定「今日/练/问/我」。“问”统一调用 `/api/aihr/agent/messages|messages/media`,服务端规划意图并按固定策略选择既有工具,客户端不得提交 `toolCode`;旧知识查询仅作底层/兼容。登录端短期会话为 30 分钟/最新 6 轮,原文件/视频经 `/api/knowledge/resources/{attachmentId}/content` 重新鉴权。总结卡只接受当前答案中的最多 5 个 `DOCUMENT` 引用 `fragmentIds`,服务端重新鉴权后仅基于这些片段生成固定「问题/建议/标准」结构;不得二次检索,失败不得拿原文冒充结构化步骤。全网外发必须先同意,显式记忆先出确认卡,再通过不透明 `draftId` 按 `PRIVATE/COMPANY` 确认;`COMPANY` 仅为 `PENDING`,不得冒充已派单或送达。`aihr_agent_run` 不保存问题、答案或附件,外部知识 API 保持无状态。
- 大喇叭详情追问只让客户端传 `broadcastMessageId`,消息正文、附件文本、租户和身份均由服务端重新校验并加载;撤回、跨租户或非在职员工不得继续使用消息上下文。单条消息最多绑定一个属于当前租户、当前上传人且状态为 `READY` 的公司文件;员工端只返回摘要、受控下载入口和有原文短引用佐证的多岗位解读,不返回提取全文或原始 OSS 地址。默认岗位视角由服务端按认证员工岗位选择,客户端不得提交视角代码;解读处于 `PENDING/PARTIAL/FAILED` 不阻断摘要、原文件、发布或追问。消息/知识回答不得把通用建议包装成当前员工的真实待办,强行动入口只能来自服务端已授权的真实任务数据。 - 大喇叭详情追问只让客户端传 `broadcastMessageId`,消息正文、附件文本、租户和身份均由服务端重新校验并加载;撤回、跨租户或非在职员工不得继续使用消息上下文。单条消息最多绑定一个属于当前租户、当前上传人且状态为 `READY` 的公司文件;员工端只返回摘要、受控下载入口和有原文短引用佐证的多岗位解读,不返回提取全文或原始 OSS 地址。默认岗位视角由服务端按认证员工岗位选择,客户端不得提交视角代码;解读处于 `PENDING/PARTIAL/FAILED` 不阻断摘要、原文件、发布或追问。消息/知识回答不得把通用建议包装成当前员工的真实待办,强行动入口只能来自服务端已授权的真实任务数据。
- 直通车固定为总裁、财务、人力、审计、运营五个渠道;业务匿名只隐藏处理端的提交人展示,服务端仍保留内部提交账号供本人查询、幂等和审计。`direct_president/direct_finance/direct_hr/direct_audit/direct_operations` 只处理各自渠道,`superadmin` 可处理全部;当前产品边界只允许一次正式回复,不扩展为多轮聊天、工单、转派或 SLA。员工提交页支持语音转文字输入(复用 `/api/ai/asr` 与 `services/speech.ts`;文字是主路径,录音不可用或权限失败仅提示改文字,不做选文件降级)。 - 直通车固定为总裁、财务、人力、审计、运营五个渠道;业务匿名只隐藏处理端的提交人展示,服务端仍保留内部提交账号供本人查询、幂等和审计。`direct_president/direct_finance/direct_hr/direct_audit/direct_operations` 只处理各自渠道,`superadmin` 可处理全部;当前产品边界只允许一次正式回复,不扩展为多轮聊天、工单、转派或 SLA。员工提交页支持语音转文字输入(复用 `/api/ai/asr` 与 `services/speech.ts`);该表单页以文字为主,录音不可用或权限失败时只提示改文字,是不提供音频文件降级的明确例外。
- 术语和数据边界:工作助手承载日常事实与确认式记忆;现有 `/pages/user/report/index`、`/api/aihr/work-report/**` 和 `aihr_work_report` 只承载 CASE/VIDEO/SOP/KNOWLEDGE 四类投稿审核,产品名为“成果投稿”;“今日工作成果”按员工 + 项目 + 自然日从已确认记录确定性聚合,员工页为 `/pages/user/work-results/index`,主管页为 `/pages/supervisor/work-results/index`,默认当日但允许查看历史日期且不得选择未来日期。不要把三条链路合表或自动互写。多项目交互只让用户按项目名称选择,内部项目编码必须由服务端按当前身份复核,不让用户输入编码。 - 术语和数据边界:工作助手承载日常事实与确认式记忆;现有 `/pages/user/report/index`、`/api/aihr/work-report/**` 和 `aihr_work_report` 只承载 CASE/VIDEO/SOP/KNOWLEDGE 四类投稿审核,产品名为“成果投稿”;“今日工作成果”按员工 + 项目 + 自然日从已确认记录确定性聚合,员工页为 `/pages/user/work-results/index`,主管页为 `/pages/supervisor/work-results/index`,默认当日但允许查看历史日期且不得选择未来日期。不要把三条链路合表或自动互写。多项目交互只让用户按项目名称选择,内部项目编码必须由服务端按当前身份复核,不让用户输入编码。
- 不要把三端概括成全模态:员工对练/每日题、问师傅和直通车反馈支持文字/语音,问师傅图片/视频只用于本次分析,案例传音频;候选面试支持文字/语音,资料可传文档/图片但图片不参与评分;主管写文字复盘/指派并回听录音。员工对练图像/视频情境、服务录像回放和方言正式验收仍未完成;语音继续复用 `services/speech.ts` 与 `/api/ai/asr`。 - 不要把三端概括成全模态:员工对练/每日题、问师傅和直通车反馈支持文字/语音,问师傅图片/视频只用于本次分析,案例传音频;候选面试支持文字/语音,资料可传文档/图片但图片不参与评分;主管写文字复盘/指派并回听录音。员工对练图像/视频情境、服务录像回放和方言正式验收仍未完成;语音继续复用 `services/speech.ts` 与 `/api/ai/asr`。
- 问题榜奖励只记积分/学习学分,不得擅自增加现金、提现、预算或税务语义;选最佳答案和考试提交必须保持请求幂等。 - 问题榜奖励只记积分/学习学分,不得擅自增加现金、提现、预算或税务语义;选最佳答案和考试提交必须保持请求幂等。
@@ -62,10 +63,10 @@
- 移动端手机号登录和短信参数见 `docs/API_INTEGRATION.md`。密钥只放 `.env.local` 或外部环境;dev 可用固定码,prod 默认关闭,试点期必须同时显式开启固定码和值,停用时两者一并清除。手机号不存在时自动注册 `app_user`。 - 移动端手机号登录和短信参数见 `docs/API_INTEGRATION.md`。密钥只放 `.env.local` 或外部环境;dev 可用固定码,prod 默认关闭,试点期必须同时显式开启固定码和值,停用时两者一并清除。手机号不存在时自动注册 `app_user`。
- 移动端训练必须带 APP 登录态并由服务端强制 `mode=mobile`。APP 身份只按认证手机号精确匹配 `person_phone`,运营/组织身份只按 `ext_party_id`;禁止 `OR` 查询、互相后备或客户端指定身份,碰撞/不唯一一律失败关闭。员工历史、画像、证据、复盘和录音只对验证后的 APP 主体开放;管理端仅允许服务端绑定的 `operator:{userId}`、`mode=preview` 运营预览,且不得进入员工历史或试点统计。主管旧手机号只有与在职外部 ID 双向唯一时才可规范化,团队、详情、复盘和音频授权使用同一规则。 - 移动端训练必须带 APP 登录态并由服务端强制 `mode=mobile`。APP 身份只按认证手机号精确匹配 `person_phone`,运营/组织身份只按 `ext_party_id`;禁止 `OR` 查询、互相后备或客户端指定身份,碰撞/不唯一一律失败关闭。员工历史、画像、证据、复盘和录音只对验证后的 APP 主体开放;管理端仅允许服务端绑定的 `operator:{userId}`、`mode=preview` 运营预览,且不得进入员工历史或试点统计。主管旧手机号只有与在职外部 ID 双向唯一时才可规范化,团队、详情、复盘和音频授权使用同一规则。
- 正式试点 CSV 起止日必填;训练、校准和 SOP 评审按同一窗口、唯一在职身份统计,完训定义为每人至少 10 次。严格预检使用 `AIHR_PILOT_START_DATE`、`AIHR_PILOT_END_DATE` 与 `AIHR_PILOT_STRICT=true ./scripts/demo-check.sh`,不得用 seed、开发身份或四舍五入比率冒充通过。 - 正式试点 CSV 起止日必填;训练、校准和 SOP 评审按同一窗口、唯一在职身份统计,完训定义为每人至少 10 次。严格预检使用 `AIHR_PILOT_START_DATE`、`AIHR_PILOT_END_DATE` 与 `AIHR_PILOT_STRICT=true ./scripts/demo-check.sh`,不得用 seed、开发身份或四舍五入比率冒充通过。
- 生产移动端浏览器验收不等待用户提供手机号:从生产 `aihr_org_snapshot` 只读选择目标岗位下 `employment_status='active'`、11 位 `person_phone` 且手机号与 `ext_party_id` 双向唯一的账号;手机号只在当前自动化进程内使用,不写入命令日志、截图、报告或仓库。固定验证码启用时也必须先请求 `/resource/sms/code`,再用固定码登录;不得因未手工提供手机号或未先请求验证码而把生产验收标为阻塞。 - 生产移动端浏览器验收可从 `aihr_org_snapshot` 只读选择手机号与外部 ID 双向唯一的在职账号;手机号仅在进程内使用,不进日志、截图、报告或仓库。固定码登录仍须先请求 `/resource/sms/code`。
- 候选面试复用 `/api/recruit/interview/**`;补充资料走认证的移动端接口,先写 `sys_oss`/MinIO,再写 `aihr_candidate_material`,状态仅为 `待审核/已通过/已驳回`,由管理端 `/recruit/interview` 审核。上传接口不得放入 class-level `@SaIgnore`。 - 候选面试复用 `/api/recruit/interview/**`;补充资料走认证的移动端接口,先写 `sys_oss`/MinIO,再写 `aihr_candidate_material`,状态仅为 `待审核/已通过/已驳回`,由管理端 `/recruit/interview` 审核。上传接口不得放入 class-level `@SaIgnore`。
- 后端 API 对接先看 `docs/API_INTEGRATION.md`。三角色对练 `/turn`/`/finish` 使用 `AihrPracticeLlmService`,必须保留“未配置/失败回退 seed”的降级链。 - 后端 API 对接先看 `docs/API_INTEGRATION.md`。三角色对练 `/turn`/`/finish` 使用 `AihrPracticeLlmService`,必须保留“未配置/失败回退 seed”的降级链。
- 对练语音复用 `/api/ai/asr` 与 `/api/ai/tts`,TTS 保持旧 `voice` 兼容并支持角色音色。浏览器录音不可用或权限失败时,用 `audio/*` file input 继续走同一 ASR,不退回纯文字;新增 multipart 外发同样清洗 filename/contentType 的 CRLF。 - 会话式语音复用 `/api/ai/asr|tts`;生产 ASR 用 `dashscope/qwen3-asr-flash`,SiliconFlow `/audio/transcriptions` 保留兼容。TTS 兼容旧 `voice` 和角色音色。除直通车表单外,浏览器录音不可用时用 `audio/*` file input 继续走 ASR;multipart 外发须清洗 filename/contentType 的 CRLF。
- 实时对练 Beta(WebRTC)的人设与工具声明只由服务端 `AihrRealtimePersonaRegistry` 白名单组装,客户端原样转发 session.update,不得恢复前端自组 instructions 或音色 picker;工具执行按登录态 + Redis 会话归属 + 人设白名单三重校验,仅只读知识检索且 `source=realtime` 不落 SOP 评审/知识缺口表;实时 Beta 不计分、不持久化,支持 H5 与 App-Plus(App 通过 renderjs WebView 执行媒体/WebRTC,并由逻辑层代理认证 SDP 和工具请求),需 APP 登录态,接口契约见 `docs/API_INTEGRATION.md`。 - 实时对练 Beta(WebRTC)的人设与工具声明只由服务端 `AihrRealtimePersonaRegistry` 白名单组装,客户端原样转发 session.update,不得恢复前端自组 instructions 或音色 picker;工具执行按登录态 + Redis 会话归属 + 人设白名单三重校验,仅只读知识检索且 `source=realtime` 不落 SOP 评审/知识缺口表;实时 Beta 不计分、不持久化,支持 H5 与 App-Plus(App 通过 renderjs WebView 执行媒体/WebRTC,并由逻辑层代理认证 SDP 和工具请求),需 APP 登录态,接口契约见 `docs/API_INTEGRATION.md`。
- 后端业务代码不要塞进上游 `ruoyi-demo`;自有 API 放在 `backend/ruoyi-modules/ruoyi-aihr`,再接入 `ruoyi-admin`。 - 后端业务代码不要塞进上游 `ruoyi-demo`;自有 API 放在 `backend/ruoyi-modules/ruoyi-aihr`,再接入 `ruoyi-admin`。
- AI 面试、三角色对练、案例、SOP 和三端首页保持真实 API/模型优先与既有降级。知识检索以 MySQL 为事实源,Qdrant/vector/rerank 是可选增强;向量维度不一致必须经状态与重建入口处理,不得静默换成本地向量。 - AI 面试、三角色对练、案例、SOP 和三端首页保持真实 API/模型优先与既有降级。知识检索以 MySQL 为事实源,Qdrant/vector/rerank 是可选增强;向量维度不一致必须经状态与重建入口处理,不得静默换成本地向量。
+4
View File
@@ -4,6 +4,10 @@
## Unreleased ## Unreleased
- **2026-07-26,阿里云百炼 ASR 生产热修复**:`POST /api/ai/asr` 新增 `dashscope/qianwen + qwen3-asr-flash` 的 `/compatible-mode/v1/chat/completions` + Base64 `input_audio` 分支,原 SiliconFlow `/audio/transcriptions` multipart 路径继续兼容,ASR 超时放宽至 30 秒。定向 Maven 测试 10 项通过;后端 JAR(SHA-256 `46c99cff75d21f8536a71c3c058b6437e99dbf9ff4bae3542b44471f3f34ad84`)已发布,生产 ASR 已切换至 `dashscope/qwen3-asr-flash`,旧 `siliconflow/TeleAI/TeleSpeechASR` 已停用。生产接口获得正确转写与受控 `ossId`,Android HBuilderX 标准基座“按住说话”请求成功,线上日志无 403/ASR 异常。回滚目录为 `/opt/wygj/backups/asr-hotfix-20260726210122`;本次未发布静态资源、未变更 schema,也不代表完整包一致性或原生 App 全项验收。
- **2026-07-26,移动端编译链升级与 uni-ui 解析修复,未发布**:本机 HBuilderX GUI 已升级为 `5.22.2026071707`,CLI 为 `5.22.2026072503-alpha`;`mobile-uni` 的 App、App-Plus、H5 与 Vite 编译包统一到对应的 `3.0.0-alpha-5020220260725001` 批次,消除 5.15/5.21 混用产生的两套 `uni-cli-shared` 状态隔离,使登录页 `<uni-forms>`、`<uni-easyinput>` 等组件重新由 `pages.json` easycom 规则正常解析。H5 与 App 均以 `Compiler version: 5.22(vue3)` 构建通过;浏览器和 vivo V2443A(Android 15)真机均确认手机号、验证码标签及输入框正常。HBuilder 5.22 标准基座 `versionName=15.22` 已自动更新并成功运行,测试手机号配合固定验证码登录成功,可进入员工首页并切换“问”页,未出现编译器/SDK 版本不匹配弹窗或组件解析告警。升级后仍须重建并安装 5.22 自定义运行基座完成原生权限全清单;`verify:app-release` 当前因缺少含正式法务 HTTPS 链接的 `androidPrivacy.json` 按预期阻断。本项未发布生产 H5,也未云打包 APK/IPA,手机上的 `com.yincheng.wygj` 正式包未被覆盖。
- **2026-07-26,全网 AI 本地库修复,未发布**:补齐 `reset-dev-db.sh` 遗漏的全网 AI 基表、数据库密钥和千问字段三项正式迁移,并增加迁移顺序及幂等回归,避免重置本地库后再次缺失 `aihr_web_search_provider`;当前本地库为 137 张表,管理端代理下的提供方列表接口验证通过。
- **2026-07-26,本地开发工具链,未发布**:补齐 `reset-dev-db.sh` 的 learning-closure 前置迁移,确保 `content_hash` 在训练成长迁移建索引前存在,并增加顺序回归检查;修复管理端 portless 包装在 Windows/Git Bash 下丢失 Vite 参数的问题。Windows 运行手册改为三个应用进程显式启动,两个 Vite 代理从 `portless list` 读取后端动态端口并直连回环地址,以规避 WSL `bash`、portless `0.15.4` 根目录批量启动差异及代理/TUN 对 Node.js `.localhost` DNS 的干扰。已在本地重建 `ry-vue` 为 130 张表,MySQL/Redis/MinIO/Qdrant、三个 portless 路由和管理端/移动端关键公开接口验证通过;未执行生产发布。
- 2026-07-25 23:56–2026-07-26 02:40 的 App-Plus 批次已提交但**尚未发布**:未构建云打包 App、未发布 H5、未发布后端 JAR、未重启服务。见下两节。 - 2026-07-25 23:56–2026-07-26 02:40 的 App-Plus 批次已提交但**尚未发布**:未构建云打包 App、未发布 H5、未发布后端 JAR、未重启服务。见下两节。
## 2026-07-26 16:41–16:57|播报音色扩充、时长恢复与 HBuilderX 5.15 对齐 ## 2026-07-26 16:41–16:57|播报音色扩充、时长恢复与 HBuilderX 5.15 对齐
+8 -4
View File
@@ -11,8 +11,8 @@
- 品牌:管理端与员工端统一显示“帮道”,继续使用现有红色品牌图标。 - 品牌:管理端与员工端统一显示“帮道”,继续使用现有红色品牌图标。
- 基础链路:租户列表、验证码、`000000 / admin / admin123` 加密登录已验证。 - 基础链路:租户列表、验证码、`000000 / admin / admin123` 加密登录已验证。
- 管理端:除 AI 面试、训练、案例、SOP 和资料处理外,已包含大喇叭发布、单文件提炼与多岗位解读、五渠道直通反馈收件箱、内容/任务运营、问题榜运营、知识空间、全网 AI 配置和组织权限;员工个人训练、主管复盘、团队难题、成长证据与训练录音仅在认证 APP 按项目范围访问。 - 管理端:除 AI 面试、训练、案例、SOP 和资料处理外,已包含大喇叭发布、单文件提炼与多岗位解读、五渠道直通反馈收件箱、内容/任务运营、问题榜运营、知识空间、全网 AI 配置和组织权限;员工个人训练、主管复盘、团队难题、成长证据与训练录音仅在认证 APP 按项目范围访问。
- 用户侧:`mobile-uni/` 承载员工、候选人和主管三端;“问”已改为数字师傅 Agent,文字、ASR 转写和图片/视频统一先做意图规划,再按服务端权限调用知识、训练、待办、记忆、媒体或全网工具,寒暄和不完整表达不再机械落入 RAG。现有能力还包括手机号登录、30 分钟短期多轮、原文件/视频受控交付、大喇叭公司文件摘要/下载/多岗位解读/追问、五渠道直通反馈、“记一下”确认卡、三级字号、训练/题目反馈、问题榜与积分、岗位考试、案例、候选面试/资料、主管复盘/派发及学员模式。Agent 代码已随 2026-07-25 完整包部署,但 Agent 专项认证态业务回归和真机验收尚未完成;旧 `mobile/` 只用于历史回溯。 - 用户侧:`mobile-uni/` 承载员工、候选人和主管三端;“问”已改为数字师傅 Agent,文字、ASR 转写和图片/视频统一先做意图规划,再按服务端权限调用知识、训练、待办、记忆、媒体或全网工具,寒暄和不完整表达不再机械落入 RAG。现有能力还包括手机号登录、30 分钟短期多轮、原文件/视频受控交付、大喇叭公司文件摘要/下载/多岗位解读/追问、五渠道直通反馈、“记一下”确认卡、三级字号、训练/题目反馈、问题榜与积分、岗位考试、案例、候选面试/资料、主管复盘/派发及学员模式。Agent 代码已随 2026-07-25 完整包部署;2026-07-26 已完成一台 Android HBuilderX 标准基座的生产 ASR 真机链路,Agent 专项认证态业务回归和自定义基座完整验收仍未完成。旧 `mobile/` 只用于历史回溯。
- 英雄路径:AI 面试(真模型出题/评分)、三角色对练(真 LLM 客户回复+评分,asr/tts 配置后支持语音)、案例沉淀(真实语音上传+ASR 转写+模型整理)均为真模型优先、未配置或失败回退本地兜底;SOP 知识库已接中文关键词 + MySQL Fulltext + Qdrant 混合召回 + rerank 重排,支持 txt/md/PDF/Word/Excel/PPT/图片/视频上传解析入库(图片走 vision OCR,视频走 ffmpeg 抽音轨转写+关键帧描述),资料处理中心支持 ZIP 异步展开后逐文件入队;模型配置页可查看向量库维度/点数并一键重建。 - 英雄路径:AI 面试(真模型出题/评分)、三角色对练(真 LLM 客户回复+评分,ASR/TTS 配置后支持语音)、案例沉淀(真实语音上传+ASR 转写+模型整理)均为真模型优先、未配置或失败回退本地兜底;生产短音频 ASR 当前为阿里云百炼 `qwen3-asr-flash`,SiliconFlow audio 接口保留兼容。SOP 知识库已接中文关键词 + MySQL Fulltext + Qdrant 混合召回 + rerank 重排,支持 txt/md/PDF/Word/Excel/PPT/图片/视频上传解析入库(图片走 vision OCR,视频走 ffmpeg 抽音轨转写+关键帧描述),资料处理中心支持 ZIP 异步展开后逐文件入队;模型配置页可查看向量库维度/点数并一键重建。
- 资料处理:已新增解析任务状态页,按 `aihr_knowledge_attach` 和 `aihr_knowledge_fragment` 展示等待解析、解析中、已完成、失败、片段数和向量化状态;任务列表按当前筛选结果前端分页(10/20/50 条,筛选或刷新回到第一页)。页面只保留“批量导入”,通过异步队列处理多文件或 ZIP,不提供浏览器目录选择和服务端目录导入入口。后端目录导入接口仅保留为运维/调试能力。 - 资料处理:已新增解析任务状态页,按 `aihr_knowledge_attach` 和 `aihr_knowledge_fragment` 展示等待解析、解析中、已完成、失败、片段数和向量化状态;任务列表按当前筛选结果前端分页(10/20/50 条,筛选或刷新回到第一页)。页面只保留“批量导入”,通过异步队列处理多文件或 ZIP,不提供浏览器目录选择和服务端目录导入入口。后端目录导入接口仅保留为运维/调试能力。
- 组织人员:`aihr_org_snapshot` 本地 reset 保留演示 seed;生产通过 `POST /api/aihr/org/sync` 同步外部组织。2026-07-25 记录的生产快照为 3417 人、2938 人在职且均有姓名、3392 个手机号映射、175 名在职主管和 20 名项目经理;姓名通过稳定 `employee_id` 定向补齐,未执行全量覆盖。当前上游 `employee_number` 与既有主体不一致且手机号大量脱敏,修复契约前禁止强制全量同步;人数属于时点事实,发布或验收前应重新查询。 - 组织人员:`aihr_org_snapshot` 本地 reset 保留演示 seed;生产通过 `POST /api/aihr/org/sync` 同步外部组织。2026-07-25 记录的生产快照为 3417 人、2938 人在职且均有姓名、3392 个手机号映射、175 名在职主管和 20 名项目经理;姓名通过稳定 `employee_id` 定向补齐,未执行全量覆盖。当前上游 `employee_number` 与既有主体不一致且手机号大量脱敏,修复契约前禁止强制全量同步;人数属于时点事实,发布或验收前应重新查询。
- 正式试点:服务端提供按起止日期导出的受角色保护 CSV;当前管理端不展示个人训练或试点导出入口,正式试点需在明确独立后台契约后再开放。严格门禁只统计唯一映射到在职组织的训练、校准和 SOP 评审。组织身份同步和至少 20 名手机号映射门槛已具备;下一步仍需选定真实试点窗口,产生员工训练、人工校准和 SOP 评审样本后重跑严格门禁,详见 [演示与试点验收](docs/DEMO_ACCEPTANCE.md)。 - 正式试点:服务端提供按起止日期导出的受角色保护 CSV;当前管理端不展示个人训练或试点导出入口,正式试点需在明确独立后台契约后再开放。严格门禁只统计唯一映射到在职组织的训练、校准和 SOP 评审。组织身份同步和至少 20 名手机号映射门槛已具备;下一步仍需选定真实试点窗口,产生员工训练、人工校准和 SOP 评审样本后重跑严格门禁,详见 [演示与试点验收](docs/DEMO_ACCEPTANCE.md)。
@@ -22,11 +22,15 @@
## 快速启动 ## 快速启动
Linux/macOS:
```bash ```bash
./scripts/dev.sh ./scripts/dev.sh
``` ```
首次启动或需要重建本地 MVP 数据库时执行 `./scripts/dev.sh --reset`。`./scripts/dev.sh` 默认通过 portless 启动后端、管理端和当前 `mobile-uni` 用户侧,对应入口为 `https://wygj-api.localhost/`、`https://wygj-admin.localhost/`、`https://wygj-mobile-uni.localhost/h5/`。只有显式 `PORTLESS=0 ./scripts/dev.sh` 时才回退固定端口和旧移动端兜底。详细端口、默认账号和验证项见 [本地运行手册](docs/DEV_SETUP.md)。 首次启动或需要重建本地 MVP 数据库时执行 `./scripts/dev.sh --reset`。`./scripts/dev.sh` 默认通过 portless 启动后端、管理端和当前 `mobile-uni` 用户侧,对应入口为 `https://wygj-api.localhost/`、`https://wygj-admin.localhost/`、`https://wygj-mobile-uni.localhost/h5/`。只有显式 `PORTLESS=0 ./scripts/dev.sh` 时才回退固定端口和旧移动端兜底。
Windows 10/11 + Docker Desktop 使用 PowerShell 原生 portless,并仅用 Git Bash 执行 `.sh`;不要从 PowerShell 直接把 `./scripts/dev.sh` 交给 WSL。管理端与 `mobile-uni` 分开启动,避免本机 portless 版本和网络代理造成批量启动或 Node.js DNS 假成功。完整首启、日常启动、验证和停止命令见 [本地运行手册的 Windows 章节](docs/DEV_SETUP.md#windows-docker-desktop)。
## 目录 ## 目录
@@ -50,7 +54,7 @@
| [Figma 视觉系统使用规范](docs/FIGMA_DESIGN_SYSTEM_GUIDE.md) | 通用视觉元素、业务元素、状态映射和 LLM 组页规则 | | [Figma 视觉系统使用规范](docs/FIGMA_DESIGN_SYSTEM_GUIDE.md) | 通用视觉元素、业务元素、状态映射和 LLM 组页规则 |
| [Figma 页面实现矩阵](docs/FIGMA_IMPLEMENTATION_MATRIX.md) | 70 张正式画板与代码/线上实现状态、二期边界和剩余动作 | | [Figma 页面实现矩阵](docs/FIGMA_IMPLEMENTATION_MATRIX.md) | 70 张正式画板与代码/线上实现状态、二期边界和剩余动作 |
| [Figma 与线上 H5 差异矩阵](docs/FIGMA_ONLINE_DELTA.md) | 线上真实页面与 Figma 目标的差异、调整顺序和验收口径 | | [Figma 与线上 H5 差异矩阵](docs/FIGMA_ONLINE_DELTA.md) | 线上真实页面与 Figma 目标的差异、调整顺序和验收口径 |
| [本地运行手册](docs/DEV_SETUP.md) | 端口、账号、启动和基础验证 | | [本地运行手册](docs/DEV_SETUP.md) | Linux/macOS 与 Windows + Docker Desktop 的端口、账号、启动和基础验证 |
| [原生 App 打包](docs/MOBILE_APP_PACKAGING.md) | Android/iOS 资源构建、隐私/签名边界和出包前置条件 | | [原生 App 打包](docs/MOBILE_APP_PACKAGING.md) | Android/iOS 资源构建、隐私/签名边界和出包前置条件 |
| [原生 App 真机验收](docs/MOBILE_APP_DEVICE_ACCEPTANCE.md) | Android/iOS 自定义基座或签名包的验收清单 | | [原生 App 真机验收](docs/MOBILE_APP_DEVICE_ACCEPTANCE.md) | Android/iOS 自定义基座或签名包的验收清单 |
| [MVP 演示与验收清单](docs/DEMO_ACCEPTANCE.md) | MVP 演示脚本、录屏兜底和验收口径 | | [MVP 演示与验收清单](docs/DEMO_ACCEPTANCE.md) | MVP 演示脚本、录屏兜底和验收口径 |
@@ -17,6 +17,7 @@ import java.net.http.HttpRequest;
import java.net.http.HttpResponse; import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.time.Duration; import java.time.Duration;
import java.util.Base64;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
@@ -24,7 +25,7 @@ import java.util.UUID;
import java.util.regex.Pattern; import java.util.regex.Pattern;
/** /**
* ASR/TTS 网关:调用 OpenAI 兼容 audio 接口(硅基流动 SenseVoice/CosyVoice2 等)。 * ASR/TTS 网关:兼容 OpenAI audio 接口,并适配阿里云百炼 Qwen ASR/TTS。
* 模型未配置或调用失败返回 empty,由前端降级为纯文本对练。 * 模型未配置或调用失败返回 empty,由前端降级为纯文本对练。
*/ */
@Service @Service
@@ -34,8 +35,10 @@ public class AihrSpeechService {
private static final Duration CONNECT_TIMEOUT = Duration.ofSeconds(15); private static final Duration CONNECT_TIMEOUT = Duration.ofSeconds(15);
private static final Duration REQUEST_TIMEOUT = Duration.ofSeconds(5); private static final Duration REQUEST_TIMEOUT = Duration.ofSeconds(5);
private static final Duration ASR_REQUEST_TIMEOUT = Duration.ofSeconds(30);
private static final Duration DASHSCOPE_TTS_TIMEOUT = Duration.ofSeconds(20); private static final Duration DASHSCOPE_TTS_TIMEOUT = Duration.ofSeconds(20);
private static final String DEFAULT_TTS_VOICE = "anna"; private static final String DEFAULT_TTS_VOICE = "anna";
private static final String QWEN_ASR_MODEL_PREFIX = "qwen3-asr-flash";
private static final String QWEN_TTS_MODEL = "qwen-audio-3.0-tts-flash"; private static final String QWEN_TTS_MODEL = "qwen-audio-3.0-tts-flash";
private static final String QWEN_TTS_DEFAULT_VOICE = "longanhuan_v3.6"; private static final String QWEN_TTS_DEFAULT_VOICE = "longanhuan_v3.6";
private static final Pattern SAFE_VOICE = Pattern.compile("[A-Za-z0-9_./:-]{1,200}"); private static final Pattern SAFE_VOICE = Pattern.compile("[A-Za-z0-9_./:-]{1,200}");
@@ -123,7 +126,7 @@ public class AihrSpeechService {
} }
/** /**
* 语音转写:POST {base}/audio/transcriptions(multipart)。 * 语音转写:OpenAI audio 兼容供应商走 multipart;阿里 Qwen3-ASR 走 chat/completions + input_audio。
*/ */
public Optional<String> transcribe(byte[] audio, String filename, String contentType) { public Optional<String> transcribe(byte[] audio, String filename, String contentType) {
Optional<SpeechModel> model = modelService.speechModel("asr"); Optional<SpeechModel> model = modelService.speechModel("asr");
@@ -131,10 +134,17 @@ public class AihrSpeechService {
return Optional.empty(); return Optional.empty();
} }
SpeechModel runtime = model.get(); SpeechModel runtime = model.get();
if (isDashScopeQwenAsr(runtime)) {
return transcribeDashScopeQwen(runtime, audio, filename, contentType);
}
return transcribeOpenAiAudio(runtime, audio, filename, contentType);
}
private Optional<String> transcribeOpenAiAudio(SpeechModel runtime, byte[] audio, String filename, String contentType) {
try { try {
String boundary = "----aihr-" + UUID.randomUUID(); String boundary = "----aihr-" + UUID.randomUUID();
byte[] body = multipartBody(boundary, runtime.modelName(), audio, filename, contentType); byte[] body = multipartBody(boundary, runtime.modelName(), audio, filename, contentType);
HttpRequest httpRequest = authorized(runtime, "/audio/transcriptions") HttpRequest httpRequest = authorized(runtime, "/audio/transcriptions", ASR_REQUEST_TIMEOUT)
.header("Content-Type", "multipart/form-data; boundary=" + boundary) .header("Content-Type", "multipart/form-data; boundary=" + boundary)
.POST(HttpRequest.BodyPublishers.ofByteArray(body)) .POST(HttpRequest.BodyPublishers.ofByteArray(body))
.build(); .build();
@@ -151,6 +161,91 @@ public class AihrSpeechService {
} }
} }
private Optional<String> transcribeDashScopeQwen(SpeechModel runtime, byte[] audio, String filename, String contentType) {
try {
ObjectNode body = buildDashScopeAsrRequestBody(objectMapper, runtime, audio, filename, contentType);
HttpRequest request = authorized(runtime, "/chat/completions", ASR_REQUEST_TIMEOUT)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(objectMapper.writeValueAsString(body)))
.build();
HttpResponse<String> response = client().send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() < 200 || response.statusCode() >= 300) {
log.warn("dashscope asr http {}(外部响应体已隐藏)", response.statusCode());
return Optional.empty();
}
return dashScopeAsrText(objectMapper, response.body());
} catch (Exception e) {
log.warn("dashscope asr call failed(处理错误已隐藏)");
return Optional.empty();
}
}
static ObjectNode buildDashScopeAsrRequestBody(ObjectMapper objectMapper, SpeechModel runtime, byte[] audio,
String filename, String contentType) {
String mediaType = asrMediaType(filename, contentType);
String dataUri = "data:" + mediaType + ";base64," + Base64.getEncoder().encodeToString(audio);
ObjectNode inputAudio = objectMapper.createObjectNode();
inputAudio.put("data", dataUri);
ObjectNode content = objectMapper.createObjectNode();
content.put("type", "input_audio");
content.set("input_audio", inputAudio);
ObjectNode message = objectMapper.createObjectNode();
message.put("role", "user");
message.putArray("content").add(content);
ObjectNode body = objectMapper.createObjectNode();
body.put("model", runtime.modelName());
body.putArray("messages").add(message);
body.put("stream", false);
body.putObject("asr_options").put("enable_itn", true);
return body;
}
static Optional<String> dashScopeAsrText(ObjectMapper objectMapper, String responseBody) {
try {
var root = objectMapper.readTree(responseBody == null ? "" : responseBody);
String text = root.path("choices").path(0).path("message").path("content").asText("").trim();
return text.isBlank() ? Optional.empty() : Optional.of(text);
} catch (Exception e) {
return Optional.empty();
}
}
static String asrMediaType(String filename, String contentType) {
String supplied = contentType == null ? "" : contentType.split(";", 2)[0].trim().toLowerCase(Locale.ROOT);
if (supplied.startsWith("audio/") && supplied.matches("audio/[a-z0-9.+-]{1,64}")) {
return switch (supplied) {
case "audio/mp3", "audio/x-mp3" -> "audio/mpeg";
case "audio/x-wav", "audio/wave" -> "audio/wav";
default -> supplied;
};
}
String name = filename == null ? "" : filename.trim().toLowerCase(Locale.ROOT);
if (name.endsWith(".wav")) {
return "audio/wav";
}
if (name.endsWith(".m4a") || name.endsWith(".mp4")) {
return "audio/mp4";
}
if (name.endsWith(".webm")) {
return "audio/webm";
}
if (name.endsWith(".ogg") || name.endsWith(".opus")) {
return "audio/ogg";
}
if (name.endsWith(".flac")) {
return "audio/flac";
}
if (name.endsWith(".aac")) {
return "audio/aac";
}
if (name.endsWith(".aiff") || name.endsWith(".aif")) {
return "audio/aiff";
}
return "audio/mpeg";
}
/** /**
* 语音合成:POST {base}/audio/speech,返回 mp3 字节。 * 语音合成:POST {base}/audio/speech,返回 mp3 字节。
*/ */
@@ -402,12 +497,28 @@ public class AihrSpeechService {
&& QWEN_TTS_MODEL.equals(runtime.modelName()); && QWEN_TTS_MODEL.equals(runtime.modelName());
} }
static boolean isDashScopeQwenAsr(SpeechModel runtime) {
if (runtime == null
|| !("dashscope".equalsIgnoreCase(runtime.providerCode()) || "qianwen".equalsIgnoreCase(runtime.providerCode()))
|| runtime.modelName() == null) {
return false;
}
String modelName = runtime.modelName().toLowerCase(Locale.ROOT);
return modelName.startsWith(QWEN_ASR_MODEL_PREFIX)
&& !modelName.contains("-realtime")
&& !modelName.contains("-filetrans");
}
private HttpRequest.Builder authorized(SpeechModel runtime, String path) { private HttpRequest.Builder authorized(SpeechModel runtime, String path) {
return authorized(runtime, path, REQUEST_TIMEOUT);
}
private HttpRequest.Builder authorized(SpeechModel runtime, String path, Duration timeout) {
HttpRequest.Builder builder = HttpRequest.newBuilder() HttpRequest.Builder builder = HttpRequest.newBuilder()
.uri(URI.create(normalizeBaseUrl(runtime.baseUrl()) + path)) .uri(URI.create(normalizeBaseUrl(runtime.baseUrl()) + path))
.timeout(REQUEST_TIMEOUT); .timeout(timeout);
if (runtime.apiKey() != null && !runtime.apiKey().isBlank()) { if (runtime.apiKey() != null && !runtime.apiKey().isBlank()) {
builder.header("Authorization", "Bearer " + runtime.apiKey()); builder.header("Authorization", "Bearer " + runtime.apiKey().trim());
} }
return builder; return builder;
} }
@@ -113,4 +113,50 @@ class AihrSpeechServiceTest {
); );
assertTrue(AihrSpeechService.dashScopeAudioUrl(mapper, "{\"output\":{}}").isEmpty()); assertTrue(AihrSpeechService.dashScopeAudioUrl(mapper, "{\"output\":{}}").isEmpty());
} }
@Test
void buildsAndParsesDashScopeQwenAsrCompatibleRequest() {
ObjectMapper mapper = new ObjectMapper();
SpeechModel runtime = new SpeechModel(
"dashscope",
"qwen3-asr-flash",
"https://ws-example.cn-beijing.maas.aliyuncs.com/compatible-mode/v1",
"test-key"
);
var body = AihrSpeechService.buildDashScopeAsrRequestBody(
mapper, runtime, new byte[]{1, 2, 3}, "recording.mp3", "audio/mp3; charset=binary");
assertTrue(AihrSpeechService.isDashScopeQwenAsr(runtime));
assertEquals("qwen3-asr-flash", body.path("model").asText());
assertFalse(body.path("stream").asBoolean());
assertEquals("user", body.path("messages").path(0).path("role").asText());
assertEquals("input_audio", body.path("messages").path(0).path("content").path(0).path("type").asText());
assertEquals(
"data:audio/mpeg;base64,AQID",
body.path("messages").path(0).path("content").path(0).path("input_audio").path("data").asText()
);
assertTrue(body.path("asr_options").path("enable_itn").asBoolean());
assertEquals(
"欢迎使用阿里云。",
AihrSpeechService.dashScopeAsrText(
mapper,
"{\"choices\":[{\"message\":{\"content\":\" 欢迎使用阿里云。 \"}}]}"
).orElseThrow()
);
}
@Test
void restrictsDashScopeCompatibleAsrToSynchronousQwenFlashModels() {
assertTrue(AihrSpeechService.isDashScopeQwenAsr(new SpeechModel(
"qianwen", "qwen3-asr-flash-2026-02-10", "https://example.com/v1", "key")));
assertFalse(AihrSpeechService.isDashScopeQwenAsr(new SpeechModel(
"dashscope", "qwen3-asr-flash-realtime", "https://example.com/v1", "key")));
assertFalse(AihrSpeechService.isDashScopeQwenAsr(new SpeechModel(
"dashscope", "qwen3-asr-flash-filetrans", "https://example.com/v1", "key")));
assertFalse(AihrSpeechService.isDashScopeQwenAsr(new SpeechModel(
"siliconflow", "qwen3-asr-flash", "https://example.com/v1", "key")));
assertEquals("audio/webm", AihrSpeechService.asrMediaType("recording.webm", ""));
assertEquals("audio/wav", AihrSpeechService.asrMediaType("recording.bin", "audio/x-wav"));
}
} }
@@ -107,7 +107,7 @@ SOP 只解决标准问题,老师傅真正值钱的是案例、策略和火候
## 7. AI 接口和供应商口径 ## 7. AI 接口和供应商口径
核心原则:**系统不绑定单一模型厂商**。后端统一走模型配置表,按能力分成 `chat / vector / rerank / asr / tts / vision` 六类。只要厂商支持 OpenAI-compatible API,就可以接入。 核心原则:**系统不绑定单一模型厂商**。后端统一走模型配置表,按能力分成 `chat / vector / rerank / asr / tts / vision` 六类。通用能力优先复用 OpenAI-compatible API;供应商契约不同的能力由后端按供应商和模型分流,客户端仍使用统一业务接口。
### 7.1 当前系统内置/预留的供应商 ### 7.1 当前系统内置/预留的供应商
@@ -116,9 +116,9 @@ SOP 只解决标准问题,老师傅真正值钱的是案例、策略和火候
| OpenAI 兼容接口 | 通用兜底入口 | 可接企业自有网关或任何兼容服务 | | OpenAI 兼容接口 | 通用兜底入口 | 可接企业自有网关或任何兼容服务 |
| DeepSeek | Chat 大模型候选 | 适合文本生成、问答、总结 | | DeepSeek | Chat 大模型候选 | 适合文本生成、问答、总结 |
| 智谱 AI | Chat / embedding / rerank 候选 | 代码内保留供应商入口 | | 智谱 AI | Chat / embedding / rerank 候选 | 代码内保留供应商入口 |
| 阿里云百炼 / 通义千问 | Chat 大模型候选 | 兼容模式接入 | | 阿里云百炼 / 通义千问 | 生产短音频 ASR/TTS;Chat、实时语音候选 | 短音频 ASR 使用 `qwen3-asr-flash` 兼容模式,密钥只保存在受控配置 |
| Ollama | 本地模型候选 | 可用于内网/离线试验 | | Ollama | 本地模型候选 | 可用于内网/离线试验 |
| 硅基流动 SiliconFlow | 当前重点接入方向 | bge-m3 向量、SenseVoice ASR、CosyVoice2 TTS、部分图像模型 | | 硅基流动 SiliconFlow | 向量、重排及语音兼容供应商 | bge-m3、OpenAI audio 兼容 ASR、CosyVoice2 TTS、部分图像模型 |
### 7.2 各类 AI 能力怎么接 ### 7.2 各类 AI 能力怎么接
@@ -127,8 +127,8 @@ SOP 只解决标准问题,老师傅真正值钱的是案例、策略和火候
| 大模型对话/总结 | `chat` | DeepSeek、通义千问、智谱、硅基流动、企业自有 OpenAI 兼容网关 | 面试出题、评分、案例整理、SOP 总结、资料归类 | | 大模型对话/总结 | `chat` | DeepSeek、通义千问、智谱、硅基流动、企业自有 OpenAI 兼容网关 | 面试出题、评分、案例整理、SOP 总结、资料归类 |
| 向量化 embedding | `vector` | 硅基流动 `BAAI/bge-m3`、智谱 `embedding-3` | SOP/案例/资料切片后做语义检索 | | 向量化 embedding | `vector` | 硅基流动 `BAAI/bge-m3`、智谱 `embedding-3` | SOP/案例/资料切片后做语义检索 |
| 重排序 rerank | `rerank` | bge-reranker 类模型,供应商可走硅基流动或智谱兼容接口 | 多条知识命中后按语义相关度排序 | | 重排序 rerank | `rerank` | bge-reranker 类模型,供应商可走硅基流动或智谱兼容接口 | 多条知识命中后按语义相关度排序 |
| 语音识别 ASR | `asr` | 硅基流动 `FunAudioLLM/SenseVoiceSmall` | 员工语音训练、案例语音上传、视频音轨转写 | | 语音识别 ASR | `asr` | 生产使用阿里云百炼 `qwen3-asr-flash`;SiliconFlow OpenAI audio 接口保留兼容 | 员工语音训练、案例语音上传、视频音轨转写 |
| 语音合成 TTS | `tts` | 硅基流动 `FunAudioLLM/CosyVoice2-0.5B`;二期可评估 MiniMax 语音 | AI 业主播报、SOP 朗读、模拟不同语气声 | | 语音合成 TTS | `tts` | 生产优先阿里云百炼 `qwen-audio-3.0-tts-flash`;SiliconFlow CosyVoice2 保留兼容 | AI 业主播报、SOP 朗读、模拟不同语气声 |
| 图片/视频画面理解 | `vision` | 多模态 Chat 模型;二期可评估火山 Doubao-embedding-vision | 图片 OCR、视频关键帧描述、以图搜图 | | 图片/视频画面理解 | `vision` | 多模态 Chat 模型;二期可评估火山 Doubao-embedding-vision | 图片 OCR、视频关键帧描述、以图搜图 |
| 向量数据库 | Qdrant | 自建 Qdrant 服务 | 只存向量索引和最小 payload,事实源仍是 MySQL/MinIO | | 向量数据库 | Qdrant | 自建 Qdrant 服务 | 只存向量索引和最小 payload,事实源仍是 MySQL/MinIO |
| 原始文件存储 | MinIO / sys_oss | 当前自建 MinIO | 存 SOP、候选资料、语音、图片、视频 | | 原始文件存储 | MinIO / sys_oss | 当前自建 MinIO | 存 SOP、候选资料、语音、图片、视频 |
+1 -1
View File
@@ -12,7 +12,7 @@
| 训练场景运营 `/train/scenarios` | 内容读取 `GET /api/train/practice/scenarios`、`GET /scenarios/{id}`;管理写入 `POST /scenarios`、`PATCH /scenarios/{id}/enabled`、`PATCH /scenarios/{id}/review-status`;目录 `GET /curriculum/capabilities`、`GET /curriculum/matrix` | 读取默认只返回当前租户“已发布且启用”的场景,且不返回审核人、稳定用户 ID 或审核时间;仅 `superadmin/hr_operator` 可请求 `includeDisabled=true`、编辑、启停和推进审核。状态只能按 `草稿 → 待业务审核 → 已发布 → 已下线` 流转;发布时服务端重新读取场景并校验住宅范围、固定五岗位、成长能力项、业务来源/SOP、服务红线、目标、成功标准、至少两轮回合和完整五维 Rubric,不信任客户端传入的发布内容。每次编辑已发布内容会退回待业务审核并刷新内容版本/哈希及审核留痕。运营可以选择风险级别,但服务端会对收费、安全、投诉等受控词及全部回合文本自动升级为“高风险”;待评估内容不可发布。高风险场景先记录第一位审核人的稳定用户 ID 和显示名并保持待业务审核,只有第二位不同的已认证运营人员复核同一内容版本后才发布;迁移重跑不得清空等待复核的首审记录。员工可见和可启动路径始终同时要求 `review_status=已发布 AND enabled=1`。 | | 训练场景运营 `/train/scenarios` | 内容读取 `GET /api/train/practice/scenarios`、`GET /scenarios/{id}`;管理写入 `POST /scenarios`、`PATCH /scenarios/{id}/enabled`、`PATCH /scenarios/{id}/review-status`;目录 `GET /curriculum/capabilities`、`GET /curriculum/matrix` | 读取默认只返回当前租户“已发布且启用”的场景,且不返回审核人、稳定用户 ID 或审核时间;仅 `superadmin/hr_operator` 可请求 `includeDisabled=true`、编辑、启停和推进审核。状态只能按 `草稿 → 待业务审核 → 已发布 → 已下线` 流转;发布时服务端重新读取场景并校验住宅范围、固定五岗位、成长能力项、业务来源/SOP、服务红线、目标、成功标准、至少两轮回合和完整五维 Rubric,不信任客户端传入的发布内容。每次编辑已发布内容会退回待业务审核并刷新内容版本/哈希及审核留痕。运营可以选择风险级别,但服务端会对收费、安全、投诉等受控词及全部回合文本自动升级为“高风险”;待评估内容不可发布。高风险场景先记录第一位审核人的稳定用户 ID 和显示名并保持待业务审核,只有第二位不同的已认证运营人员复核同一内容版本后才发布;迁移重跑不得清空等待复核的首审记录。员工可见和可启动路径始终同时要求 `review_status=已发布 AND enabled=1`。 |
| M2 训练预习与求助 | `GET /api/train/practice/scenarios/{id}/prep-card`、`POST /api/train/practice/sessions/{sessionId}/help` | 均要求已登录;预习卡只使用当前租户已启用的 `prep_card/json_prep` 模板,模型返回必须严格为 3 条要点、3 条红线、2 条话术,否则回退场景卡。求助接口只允许 APP 员工访问其本人、同租户的活动训练会话;客户端可传 `roundIndex` 仅为兼容字段,服务端按会话实际进度落库,返回 `{sessionId,scenarioId,roundIndex,recordedAt}`。迁移表为 `aihr_practice_help_event`,不在请求路径执行 DDL。该表已随 2026-07-24 完整包发布并纳入远端 `62/62` 结构预检;完整训练写入与正式试点仍需另验。 | | M2 训练预习与求助 | `GET /api/train/practice/scenarios/{id}/prep-card`、`POST /api/train/practice/sessions/{sessionId}/help` | 均要求已登录;预习卡只使用当前租户已启用的 `prep_card/json_prep` 模板,模型返回必须严格为 3 条要点、3 条红线、2 条话术,否则回退场景卡。求助接口只允许 APP 员工访问其本人、同租户的活动训练会话;客户端可传 `roundIndex` 仅为兼容字段,服务端按会话实际进度落库,返回 `{sessionId,scenarioId,roundIndex,recordedAt}`。迁移表为 `aihr_practice_help_event`,不在请求路径执行 DDL。该表已随 2026-07-24 完整包发布并纳入远端 `62/62` 结构预检;完整训练写入与正式试点仍需另验。 |
| 正式试点数据导出 | `GET /api/train/practice/export?startDate=YYYY-MM-DD&endDate=YYYY-MM-DD` | 起止日期必填且包含结束日;只统计窗口内能通过唯一手机号或外部 ID 映射到在职组织快照的正式会话,排除重复手机号和身份碰撞。完训定义为每人至少 10 次,校准必须关联同一窗口内正式会话;CSV 同时给出校准命中数、SOP 可用数、满意度响应数/平均分,以及明细级 AI 分、人工校准分、校准人、校准时间、最终采用分、满意度分和意见,避免用四舍五入后的比率反推门禁状态;汇总和明细均携带正式人员及项目口径,不混入历史 seed/开发身份 | | 正式试点数据导出 | `GET /api/train/practice/export?startDate=YYYY-MM-DD&endDate=YYYY-MM-DD` | 起止日期必填且包含结束日;只统计窗口内能通过唯一手机号或外部 ID 映射到在职组织快照的正式会话,排除重复手机号和身份碰撞。完训定义为每人至少 10 次,校准必须关联同一窗口内正式会话;CSV 同时给出校准命中数、SOP 可用数、满意度响应数/平均分,以及明细级 AI 分、人工校准分、校准人、校准时间、最终采用分、满意度分和意见,避免用四舍五入后的比率反推门禁状态;汇总和明细均携带正式人员及项目口径,不混入历史 seed/开发身份 |
| 对练语音 | `POST /api/ai/asr`(multipart 字段 `file`,≤5MB)、`POST /api/ai/tts`(JSON `{text≤300字, voice?, voiceProfile?:{role,voice?,speed?,emotion?,dialect?}, practiceContext?:{sessionId,turnIndex,role:'customer'}}`,`dialect` 仅接受 `mandarin/cantonese/sichuanese`,非法值返回业务码 `400`;旧 `voice` 兼容;成功返回 `ossId`,客户端播放地址为受控的内联 `data:audio/*`,不返回原始 OSS URL)、`GET /api/aihr/mobile/oss/{ossId}` | 走 OpenAI-compatible audio 接口;生产 SiliconFlow CosyVoice2 按角色映射老师傅/业主/面试官音色,业主对练再按已有情绪分切换平静/严肃/强烈语气和语速;dialect 作为语气提示传给支持表现力提示词的 TTS,不含克隆,也不等同于方言正式验收。`practiceContext` 仅允许已认证 APP 员工把本次服务端生成的业主 TTS 绑定到本人当前或刚完成会话的指定原话术回合;服务端重新校验租户、员工身份、回合和文本,不接受员工端传 OSS ID 或任意角色。设备语音降级按方言选择语言:粤语使用 `zh-HK`,四川话无法由设备语音可靠模拟时明确提示用户转用服务端语音或文字,不伪装成普通话。模型管理需启用 `category=asr/tts` 配置;移动端优先用浏览器录音,`getUserMedia/MediaRecorder` 不可用或麦克风权限失败时,用 `audio/*` file input 选择/录制音频后继续调同一 ASR 接口;ASR/TTS 未配置或失败返回 fail,前端降级设备语音或文本;训练/每日题录音只通过 `audioOssId` 走受保护下载,历史客户端传入的 HTTP `audioUrl` 不再回显;TTS 成功音频仍写入 `sys_oss` 留痕,同时用内联 data URL 保持旧客户端可播放;移动端 OSS 下载只允许经本人或主管项目范围验证的 APP 身份,后台账号若需回放必须使用未来独立、受审计的管理端契约。 | | 对练语音 | `POST /api/ai/asr`(multipart 字段 `file`,≤5MB)、`POST /api/ai/tts`(JSON `{text≤300字, voice?, voiceProfile?:{role,voice?,speed?,emotion?,dialect?}, practiceContext?:{sessionId,turnIndex,role:'customer'}}`,`dialect` 仅接受 `mandarin/cantonese/sichuanese`,非法值返回业务码 `400`;旧 `voice` 兼容;成功返回 `ossId`,客户端播放地址为受控的内联 `data:audio/*`,不返回原始 OSS URL)、`GET /api/aihr/mobile/oss/{ossId}` | ASR 按供应商分流:SiliconFlow 等 OpenAI audio 兼容服务继续走 `/audio/transcriptions` multipart;阿里云百炼 `dashscope/qianwen + qwen3-asr-flash` 走工作空间 `/compatible-mode/v1/chat/completions`,将短音频编码为 Base64 `input_audio` 并读取 `choices[0].message.content`,请求上限仍由本接口收窄为 5MB。生产 TTS 优先阿里 `qwen-audio-3.0-tts-flash`,旧 SiliconFlow CosyVoice2 保留兼容;按角色映射老师傅/业主/面试官音色,业主对练再按已有情绪分切换平静/严肃/强烈语气和语速;dialect 作为语气提示传给支持表现力提示词的 TTS,不含克隆,也不等同于方言正式验收。`practiceContext` 仅允许已认证 APP 员工把本次服务端生成的业主 TTS 绑定到本人当前或刚完成会话的指定原话术回合;服务端重新校验租户、员工身份、回合和文本,不接受员工端传 OSS ID 或任意角色。设备语音降级按方言选择语言:粤语使用 `zh-HK`,四川话无法由设备语音可靠模拟时明确提示用户转用服务端语音或文字,不伪装成普通话。模型管理需启用 `category=asr/tts` 配置;移动端优先用浏览器录音,`getUserMedia/MediaRecorder` 不可用或麦克风权限失败时,用 `audio/*` file input 选择/录制音频后继续调同一 ASR 接口;ASR/TTS 未配置或失败返回 fail,前端降级设备语音或文本;训练/每日题录音只通过 `audioOssId` 走受保护下载,历史客户端传入的 HTTP `audioUrl` 不再回显;TTS 成功音频仍写入 `sys_oss` 留痕,同时用内联 data URL 保持旧客户端可播放;移动端 OSS 下载只允许经本人或主管项目范围验证的 APP 身份,后台账号若需回放必须使用未来独立、受审计的管理端契约。 |
| 实时对练 Beta(WebRTC) | `POST /api/train/practice/realtime/sdp`、`GET /realtime/personas`、`POST /realtime/session`、`POST /realtime/tools/invoke` | H5 浏览器及 App-Plus renderjs WebView 内的 WebRTC 直连阿里云(音频不过服务端),后端仅代理 SDP 交换(3 次/分/账号,sessionId 仅作日志关联且限字符)。人设为服务端 `AihrRealtimePersonaRegistry` 白名单:`owner-calm` 业主·常规(默认)、`owner-impatient` 业主·急躁、`digital-mentor` 数字师傅;人设绑定默认音色,客户端只选不编。`session.update`(instructions/音色/turn_detection/tools 声明)由 `/realtime/session` 组装下发,客户端原样转发;personaId 空白回落默认人设;会话记录写 Redis 30min(成功工具调用滑动续期),创建限流 6 次/分/账号。`digital-mentor` 声明 `search_knowledge` 工具:模型 function calling 命中(`response.function_call_arguments.done`)时客户端回传 `/realtime/tools/invoke`,服务端按登录态 + Redis 会话归属 + 人设工具白名单三重校验后走 `searchAuthorized` 浅层检索(不生成 LLM 答案、不落 `aihr_agent_run`;`source=realtime` 跳过 SOP 评审与知识缺口写入),output 拼接 ≤3 条片段并截断 1200 字;工具按账号限流 20 次/分,无授权/无结果/超时一律返回软着陆文案让模型如实作答,不中断语音会话。实时 Beta 不计分、不持久化训练数据;H5 与 App-Plus 均支持,App-Plus 在 renderjs 视图层执行媒体/WebRTC 并通过逻辑层复用受认证 SDP 与工具接口;需 APP 员工登录态,不启用模型 `enable_search`。配置 `AIHR_QWEN_REALTIME_ENDPOINT` / `AIHR_QWEN_REALTIME_API_KEY` / `AIHR_QWEN_REALTIME_MODEL`(模型白名单 `qwen3.5-omni-(flash|plus)-realtime`),密钥只放 `.env.local` 或外部环境变量。 | | 实时对练 Beta(WebRTC) | `POST /api/train/practice/realtime/sdp`、`GET /realtime/personas`、`POST /realtime/session`、`POST /realtime/tools/invoke` | H5 浏览器及 App-Plus renderjs WebView 内的 WebRTC 直连阿里云(音频不过服务端),后端仅代理 SDP 交换(3 次/分/账号,sessionId 仅作日志关联且限字符)。人设为服务端 `AihrRealtimePersonaRegistry` 白名单:`owner-calm` 业主·常规(默认)、`owner-impatient` 业主·急躁、`digital-mentor` 数字师傅;人设绑定默认音色,客户端只选不编。`session.update`(instructions/音色/turn_detection/tools 声明)由 `/realtime/session` 组装下发,客户端原样转发;personaId 空白回落默认人设;会话记录写 Redis 30min(成功工具调用滑动续期),创建限流 6 次/分/账号。`digital-mentor` 声明 `search_knowledge` 工具:模型 function calling 命中(`response.function_call_arguments.done`)时客户端回传 `/realtime/tools/invoke`,服务端按登录态 + Redis 会话归属 + 人设工具白名单三重校验后走 `searchAuthorized` 浅层检索(不生成 LLM 答案、不落 `aihr_agent_run`;`source=realtime` 跳过 SOP 评审与知识缺口写入),output 拼接 ≤3 条片段并截断 1200 字;工具按账号限流 20 次/分,无授权/无结果/超时一律返回软着陆文案让模型如实作答,不中断语音会话。实时 Beta 不计分、不持久化训练数据;H5 与 App-Plus 均支持,App-Plus 在 renderjs 视图层执行媒体/WebRTC 并通过逻辑层复用受认证 SDP 与工具接口;需 APP 员工登录态,不启用模型 `enable_search`。配置 `AIHR_QWEN_REALTIME_ENDPOINT` / `AIHR_QWEN_REALTIME_API_KEY` / `AIHR_QWEN_REALTIME_MODEL`(模型白名单 `qwen3.5-omni-(flash|plus)-realtime`),密钥只放 `.env.local` 或外部环境变量。 |
| 案例沉淀 `/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 用户必须先以认证手机号精确校验在职 `person_phone`,再由可信主体解析 `aihr_org_snapshot` 项目范围;案例 SQL 不得把 `person_phone` 与 `ext_party_id` 作为替代查询键。上传、整理、入库、列表和详情均按该项目范围校验,未完成正式组织映射时安全拒绝,不接受前端伪造项目范围;员工列表/详情只返回 `已入库` 案例,管理端系统用户保留全局运营视图;移动端和管理端案例详情通过受保护媒体接口回放原始音频,主管/项目负责人可提交脱敏点评;预渲染视频样片仍待正式媒体资产接入 | | 案例沉淀 `/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 用户必须先以认证手机号精确校验在职 `person_phone`,再由可信主体解析 `aihr_org_snapshot` 项目范围;案例 SQL 不得把 `person_phone` 与 `ext_party_id` 作为替代查询键。上传、整理、入库、列表和详情均按该项目范围校验,未完成正式组织映射时安全拒绝,不接受前端伪造项目范围;员工列表/详情只返回 `已入库` 案例,管理端系统用户保留全局运营视图;移动端和管理端案例详情通过受保护媒体接口回放原始音频,主管/项目负责人可提交脱敏点评;预渲染视频样片仍待正式媒体资产接入 |
| 案例媒体安全 | `GET /api/knowledge/case/records/{caseId}/media` | 案例详情只返回 `mediaOssId`,不返回原始 `sys_oss.url`;媒体下载会重复执行登录、后台角色或 APP 项目范围校验,再由服务端流式读取 OSS。管理端与 `mobile-uni` 通过鉴权 blob/temp 文件播放,关闭详情页时释放本地对象 URL | | 案例媒体安全 | `GET /api/knowledge/case/records/{caseId}/media` | 案例详情只返回 `mediaOssId`,不返回原始 `sys_oss.url`;媒体下载会重复执行登录、后台角色或 APP 项目范围校验,再由服务端流式读取 OSS。管理端与 `mobile-uni` 通过鉴权 blob/temp 文件播放,关闭详情页时释放本地对象 URL |
+9 -9
View File
@@ -1,8 +1,8 @@
# BRD 功能审查与未完成项记录 # BRD 功能审查与未完成项记录
> 当前基线:2026-07-25。最新完整生产发布源为 `230dfb4d`,包含五岗位训练内容运营、M2—M3 训练闭环、数字师傅 Agent,以及公司消息 R1—R3 和多岗位解读;当前源码 `acd5fd3a` 另含尚未部署的常规陪练“建议回复”。当前真相以本文件、[生产迁移 Runbook](BRD_PRODUCTION_MIGRATION_RUNBOOK.md)、[Changelog](../CHANGELOG.md)和每次发布的只读预检为准。 > 当前基线:2026-07-26。最新完整生产发布源仍为 `230dfb4d`,包含五岗位训练内容运营、M2—M3 训练闭环、数字师傅 Agent,以及公司消息 R1—R3 和多岗位解读;其后仅发布了阿里云百炼 ASR 后端热修复和生产模型配置,未重新发布静态资源或执行 schema 迁移。当前真相以本文件、[生产迁移 Runbook](BRD_PRODUCTION_MIGRATION_RUNBOOK.md)、[Changelog](../CHANGELOG.md)和每次发布的只读预检为准。
> >
> 数字师傅 Agent、`aihr_agent_run` 和对应移动端改造已随 2026-07-25 完整包部署;当前只确认包、schema 和基础运行一致,Agent 专项认证态业务回归及真机验收仍未完成。 > 数字师傅 Agent、`aihr_agent_run` 和对应移动端改造已随 2026-07-25 完整包部署;2026-07-26 已在一台 Android HBuilderX 标准基座跑通生产 ASR 请求,但 Agent 专项认证态业务回归及自定义基座完整真机验收仍未完成。
> >
> 后台已不再暴露个人训练、主管复盘或成长证据入口;这些能力仅留在认证 APP。该收口已随 2026-07-25 完整包部署,但员工训练写入、主管复盘和真机媒体仍需专项生产验收。 > 后台已不再暴露个人训练、主管复盘或成长证据入口;这些能力仅留在认证 APP。该收口已随 2026-07-25 完整包部署,但员工训练写入、主管复盘和真机媒体仍需专项生产验收。
> >
@@ -24,10 +24,10 @@
|---|---|---| |---|---|---|
| 已实现 | 是 | 已有阶段一主功能,公司消息 R1—R3 已实现直通车与公司文件提炼闭环;接口事实见 [API_INTEGRATION.md](API_INTEGRATION.md) | | 已实现 | 是 | 已有阶段一主功能,公司消息 R1—R3 已实现直通车与公司文件提炼闭环;接口事实见 [API_INTEGRATION.md](API_INTEGRATION.md) |
| 本地自动化/API 验证 | 是 | 训练运营定向后端测试 `76` 项;公司消息新增后端 `30` 项、管理端 `2` 项、移动端 `2` 项;管理端/H5 构建通过 | | 本地自动化/API 验证 | 是 | 训练运营定向后端测试 `76` 项;公司消息新增后端 `30` 项、管理端 `2` 项、移动端 `2` 项;管理端/H5 构建通过 |
| 本地浏览器/视觉验证 | 部分 | 已检查管理端目录/任务、两轮动态对练、岗位不匹配拦截、直通处理和文件消息;线上已以认证态员工完成公司消息回归。训练完整写入和真机验收仍未完成 | | 本地浏览器/视觉验证 | 部分 | 已检查管理端目录/任务、两轮动态对练、岗位不匹配拦截、直通处理和文件消息;线上已以认证态员工完成公司消息回归。Android 标准基座生产 ASR 已通过,训练完整写入和原生全项验收仍未完成 |
| 已部署 | 是 | 管理端、H5、后端、公司消息 R1—R3、训练内容运营、M2 求助事件和租户组织治理迁移已发布;线上静态资源及 AIHR 模块与本地构建一致 | | 已部署 | 是 | 管理端、H5、后端、公司消息 R1—R3、训练内容运营、M2 求助事件和租户组织治理迁移已发布;线上静态资源及 AIHR 模块与本地构建一致 |
| 生产基础验证 | 是 | 服务 `active`;根站、H5、租户接口和员工首页 API 正常;远端完整预检为 `64/64`,且管理端/H5 资源、AIHR 模块与本地构建匹配 | | 生产基础验证 | 是 | 服务 `active`;根站、H5、租户接口和员工首页 API 正常;远端完整预检为 `64/64`,且管理端/H5 资源、AIHR 模块与本地构建匹配 |
| 生产完整业务验收 | 部分 | 公司消息已完成认证态全员文件消息和直通车闭环;训练写入、主管复盘、定向人群正反例、正式处理人绑定、真机媒体与严格试点窗口仍未完成 | | 生产完整业务验收 | 部分 | 公司消息已完成认证态全员文件消息和直通车闭环,单台 Android 标准基座已完成生产 ASR;训练写入、主管复盘、定向人群正反例、正式处理人绑定、其他真机媒体与严格试点窗口仍未完成 |
“已部署”不等于“正式试点通过”。当前可以确认生产包和基础运行状态,不能把未执行的正式账号、真机和业务窗口验收写成已完成。 “已部署”不等于“正式试点通过”。当前可以确认生产包和基础运行状态,不能把未执行的正式账号、真机和业务窗口验收写成已完成。
@@ -69,7 +69,7 @@
|---|---|---| |---|---|---|
| 不同角色/岗位内容 | 员工、候选人、主管独立入口;岗位来自组织系统,主管可切换学员模式但不改变组织身份 | 生产包已部署;全岗位内容矩阵和正式权限正反例仍需业务数据 | | 不同角色/岗位内容 | 员工、候选人、主管独立入口;岗位来自组织系统,主管可切换学员模式但不改变组织身份 | 生产包已部署;全岗位内容矩阵和正式权限正反例仍需业务数据 |
| 字号适老化 | 标准/大字/超大字全局持久化,同一页面结构响应式增高 | 本地多视口视觉通过;真实手机触控、键盘和读屏未验收 | | 字号适老化 | 标准/大字/超大字全局持久化,同一页面结构响应式增高 | 本地多视口视觉通过;真实手机触控、键盘和读屏未验收 |
| 问师傅语音与播报 | 录音、选择音频、ASR、TTS/设备语音降级恢复;答案、总结卡、每日题、点评等关键内容可播报 | 生产包已部署;生产 CosyVoice2 已按老师傅/业主/面试官区分音色,业主情绪语气与语速已在生产 H5 验证;真实手机权限、弱网、方言和正式 ASR 仍未验收 | | 问师傅语音与播报 | 录音、选择音频、ASR、TTS/设备语音降级恢复;答案、总结卡、每日题、点评等关键内容可播报 | 生产短音频 ASR 已切换为 `dashscope/qwen3-asr-flash`,并在一台 Android HBuilderX 标准基座完成“按住说话”请求;自定义基座权限、弱网、方言、多机型和完整播报仍未验收 |
| 问师傅连续对话与资料 | 认证用户短期会话保留 30 分钟/最新 6 轮,追问改写并路由 `QA/FILE/VIDEO/DATA_TOOL`;原文件/视频只从当前命中且实时授权的附件交付,无资源不造假链接 | 公司文件消息的认证下载与追问已生产验证;一般知识命中文件/视频的真机下载仍待复验 | | 问师傅连续对话与资料 | 认证用户短期会话保留 30 分钟/最新 6 轮,追问改写并路由 `QA/FILE/VIDEO/DATA_TOOL`;原文件/视频只从当前命中且实时授权的附件交付,无资源不造假链接 | 公司文件消息的认证下载与追问已生产验证;一般知识命中文件/视频的真机下载仍待复验 |
| 问页面有效会话区与消息追问 | 会话开始后收起占位辅助区;大喇叭详情仅以消息 ID 受控进入短会话,消息/知识回答不伪造待办 | 生产认证态发布—阅读—文件追问已验证;390×844 最终截图和真机体验仍待补 | | 问页面有效会话区与消息追问 | 会话开始后收起占位辅助区;大喇叭详情仅以消息 ID 受控进入短会话,消息/知识回答不伪造待办 | 生产认证态发布—阅读—文件追问已验证;390×844 最终截图和真机体验仍待补 |
| 银城大喇叭 | 全员/定向、必读、未读/已读、发布/撤回、单文件异步提炼、摘要、受控下载和文件追问已部署 | 全员文件消息闭环已生产认证验证,测试消息已撤回;仍不含修订、补推和外部强触达,定向正反例待补 | | 银城大喇叭 | 全员/定向、必读、未读/已读、发布/撤回、单文件异步提炼、摘要、受控下载和文件追问已部署 | 全员文件消息闭环已生产认证验证,测试消息已撤回;仍不含修订、补推和外部强触达,定向正反例待补 |
@@ -90,14 +90,14 @@
1. 选定 1–2 个真实项目、正式员工名单和起止日期,固定试点窗口。 1. 选定 1–2 个真实项目、正式员工名单和起止日期,固定试点窗口。
2. 使用已授权的生产登录方式完成员工、主管、候选人和后台角色正反例;当前受控登录方式可用于验收,不再作为“无法验收”的理由。 2. 使用已授权的生产登录方式完成员工、主管、候选人和后台角色正反例;当前受控登录方式可用于验收,不再作为“无法验收”的理由。
3. 在真实手机复验录音/选音频、TTS/设备语音、图片/视频附件、总结卡下载、三级字号、键盘和读屏。 3. 在自定义基座继续复验录音拒绝/选音频、TTS/设备语音、图片/视频附件、总结卡下载、三级字号、键盘和读屏;标准基座的单次 ASR 成功不能替代这些项目。
4. 以同一窗口收集训练、人工校准、SOP 评审、满意度和案例样本,再运行 `AIHR_PILOT_STRICT=true ./scripts/demo-check.sh`。 4. 以同一窗口收集训练、人工校准、SOP 评审、满意度和案例样本,再运行 `AIHR_PILOT_STRICT=true ./scripts/demo-check.sh`。
### P1:业务配置与终态能力 ### P1:业务配置与终态能力
1. 由业务确认五岗位正式场景、题库、SOP、资格规则及当前禁用高风险内容;seed 不能代替内容验收。 1. 由业务确认五岗位正式场景、题库、SOP、资格规则及当前禁用高风险内容;seed 不能代替内容验收。
2. 完成项目权限正例/反例、岗位内容映射、大团队批量派发,以及直通车五类真实处理人员绑定。 2. 完成项目权限正例/反例、岗位内容映射、大团队批量派发,以及直通车五类真实处理人员绑定。
3. 继续用真实手机复验正式 ASR、麦克风权限、弱网、方言与全网 AI 提供方;密钥只从安全环境注入。 3. 继续用真实手机扩展 ASR 多机型样本,并复验麦克风拒绝、弱网、方言与全网 AI 提供方;密钥只从安全环境注入。
4. BRD 终态仍缺员工对练图像/视频情境、服务录像回放、四川话/粤语真实样本和响应时延证据。 4. BRD 终态仍缺员工对练图像/视频情境、服务录像回放、四川话/粤语真实样本和响应时延证据。
5. 多租户知识平台完成正式租户 ID、空间、授权、外部应用、内容迁移和标准题签字后,才可称业务上线。 5. 多租户知识平台完成正式租户 ID、空间、授权、外部应用、内容迁移和标准题签字后,才可称业务上线。
@@ -106,8 +106,8 @@
- 发布源:`230dfb4d feat(broadcast): finish multi-role insight experience`,包含此前训练运营、数字师傅 Agent、公司消息 R1—R3 和多岗位解读;当前源码 `acd5fd3a` 的陪练建议回复未包含在本次生产包。 - 发布源:`230dfb4d feat(broadcast): finish multi-role insight experience`,包含此前训练运营、数字师傅 Agent、公司消息 R1—R3 和多岗位解读;当前源码 `acd5fd3a` 的陪练建议回复未包含在本次生产包。
- 生产地址:`https://peilian.njzhmj.top/`、`https://peilian.njzhmj.top/h5/`;本次完整备份:`/opt/wygj/backups/broadcast-insights-20260725152349`。 - 生产地址:`https://peilian.njzhmj.top/`、`https://peilian.njzhmj.top/h5/`;本次完整备份:`/opt/wygj/backups/broadcast-insights-20260725152349`。
- 数据库:训练、组织、Agent、`aihr_broadcast_attachment`、多岗位解读、`aihr_direct_feedback` 和五类处理角色迁移已执行;远端 `release-preflight` 对结构的只读核验为 `64/64`。 - 数据库:训练、组织、Agent、`aihr_broadcast_attachment`、多岗位解读、`aihr_direct_feedback` 和五类处理角色迁移已执行;远端 `release-preflight` 对结构的只读核验为 `64/64`。
- 产物与服务:管理端/H5 资源、后端 AIHR 模块均与本地构建一致,`wygj-aihr.service` 为 `active`;根站、H5、租户接口和员工首页 API 返回正常业务结果。 - 产物与服务:2026-07-25 完整包曾完成管理端/H5、后端和 schema 三项一致性核验;2026-07-26 后端 ASR 热修复后服务仍为 `active`、新 JAR 哈希匹配且生产 ASR/健康检查通过,但静态资源未重发,因此不得把该单项发布描述为当前工作树的完整包一致。
- 认证态生产已验证员工直通匿名提交、审计角色回复、员工查看回复,以及全员文件消息发布、摘要、多岗位解读、下载、内容追问和撤回。直通测试记录按审计要求保留,公司消息测试记录已撤回;该证据不包含 Agent 专项回归、完整训练写入、主管复盘、定向人群正反例或真机媒体体验验收。 - 认证态生产已验证员工直通匿名提交、审计角色回复、员工查看回复,以及全员文件消息发布、摘要、多岗位解读、下载、内容追问和撤回;2026-07-26 另完成一台 Android 标准基座的生产 ASR。直通测试记录按审计要求保留,公司消息测试记录已撤回;该证据不包含 Agent 专项完整回归、完整训练写入、主管复盘、定向人群正反例或原生全项体验验收。
## 6. 当前事实源 ## 6. 当前事实源
+6
View File
@@ -27,6 +27,12 @@
- 公司文件多岗位解读已完成生产 H5 认证态验证,包含四视角切换、原文依据、下载哈希一致及撤回后拒绝访问; - 公司文件多岗位解读已完成生产 H5 认证态验证,包含四视角切换、原文依据、下载哈希一致及撤回后拒绝访问;
- 主管下一训练层级确认和数字师傅 Agent 仅确认结构/产物已部署,尚未完成各自的生产认证态业务回归;不得由 `64/64` 推断业务验收完成。 - 主管下一训练层级确认和数字师傅 Agent 仅确认结构/产物已部署,尚未完成各自的生产认证态业务回归;不得由 `64/64` 推断业务验收完成。
2026-07-26 已完成后端 ASR 单项热修复:
- 生产 `category=asr` 已切换为 `dashscope/qwen3-asr-flash`,旧 `siliconflow/TeleAI/TeleSpeechASR` 已停用;供应商密钥仍只保存在受控运行配置和模型表,不进入仓库、命令记录或验收材料;
- 生产接口已获得正确转写和受控 `ossId`,Android HBuilderX 标准基座“按住说话”请求成功,服务日志无此前的 403/ASR 异常;
- 回滚目录为 `/opt/wygj/backups/asr-hotfix-20260726210122`,包含原 JAR 与模型配置 SQL。本次未发布管理端/H5/App 静态资源、未变更 schema,不替代完整包预检、自定义基座权限验收、弱网/方言样本或 Agent 专项业务回归。
2026-07-20 增量把“项目服务记忆最小切片”扩展为工作助手确认式统一采集:显式“记一下”生成候选,用户确认后按 `PRIVATE/COMPANY` 写入 `aihr_assistant_capture`;个人记录仅本人可见,公司记录先保持 `PENDING`,正式接收端和回执尚未实现。旧 `aihr_service_memory/version` 继续兼容项目记录;同批会话式“工作上报”继续使用既有 `aihr_work_report`,并补 `request_key/request_hash` 和唯一索引。 2026-07-20 增量把“项目服务记忆最小切片”扩展为工作助手确认式统一采集:显式“记一下”生成候选,用户确认后按 `PRIVATE/COMPANY` 写入 `aihr_assistant_capture`;个人记录仅本人可见,公司记录先保持 `PENDING`,正式接收端和回执尚未实现。旧 `aihr_service_memory/version` 继续兼容项目记录;同批会话式“工作上报”继续使用既有 `aihr_work_report`,并补 `request_key/request_hash` 和唯一索引。
2026-07-21 已在生产发布项目化工作助手与今日工作成果提交 `4536d607`,并发布确认卡首屏修正 `11250811`: 2026-07-21 已在生产发布项目化工作助手与今日工作成果提交 `4536d607`,并发布确认卡首屏修正 `11250811`:
+134 -18
View File
@@ -26,7 +26,7 @@
- 管理端:`https://wygj-admin.localhost/` - 管理端:`https://wygj-admin.localhost/`
- 后端 API:`https://wygj-api.localhost` - 后端 API:`https://wygj-api.localhost`
从根目录一次性启动本地依赖、后端、管理端和 uni-app 用户侧: Linux/macOS 或已完整配置的 Linux shell 可从根目录一次性启动本地依赖、后端、管理端和 uni-app 用户侧:
```bash ```bash
./scripts/dev.sh ./scripts/dev.sh
@@ -38,16 +38,12 @@
portless run --name wygj-api ./scripts/dev-backend.sh portless run --name wygj-api ./scripts/dev-backend.sh
``` ```
Windows 10/11 + Docker Desktop 不要从 PowerShell 直接执行 `./scripts/dev.sh`:Windows 的 `bash` 可能解析到 WSL,而 WSL 的 Node、Docker 集成和检出文件换行符未必满足脚本要求。使用本文件的 [Windows 10/11 + Docker Desktop](#windows-docker-desktop) 流程。
本地启动默认关闭管理端图形验证码;需要专门验证验证码链路时设置 `AIHR_DEV_CAPTCHA_ENABLED=true`。生产启动不使用该开发开关,验证码保持开启。 本地启动默认关闭管理端图形验证码;需要专门验证验证码链路时设置 `AIHR_DEV_CAPTCHA_ENABLED=true`。生产启动不使用该开发开关,验证码保持开启。
重复启动或切换分支时优先使用 `./scripts/dev.sh restart`,停止使用 `./scripts/dev.sh stop`。脚本会递归终止 portless 包装进程及其 Java/Vite 子进程,避免旧后端脱离后继续占用 MySQL 连接池;进程树回归可用 `bash scripts/tests/process-tree.test.sh` 验证。 重复启动或切换分支时优先使用 `./scripts/dev.sh restart`,停止使用 `./scripts/dev.sh stop`。脚本会递归终止 portless 包装进程及其 Java/Vite 子进程,避免旧后端脱离后继续占用 MySQL 连接池;进程树回归可用 `bash scripts/tests/process-tree.test.sh` 验证。
也可以只让 portless 按根目录 `portless.json` 启动前端工程:
```bash
portless
```
旧 `mobile/` 只在显式 `PORTLESS=0 ./scripts/dev.sh` 时作为固定端口兜底启动;后端开发测试优先看 `wygj-api.localhost`,管理端开发测试优先看 `wygj-admin.localhost`,新用户侧开发测试优先看 `wygj-mobile-uni.localhost`。 旧 `mobile/` 只在显式 `PORTLESS=0 ./scripts/dev.sh` 时作为固定端口兜底启动;后端开发测试优先看 `wygj-api.localhost`,管理端开发测试优先看 `wygj-admin.localhost`,新用户侧开发测试优先看 `wygj-mobile-uni.localhost`。
原生 Android/iOS 资源使用 `npm --prefix mobile-uni run build:app` 构建;它不生成签名 APK/IPA,也不适用本文件的 H5 `rsync` 发布流程。自定义基座、协议链接、签名和真机门禁见 [MOBILE_APP_PACKAGING.md](MOBILE_APP_PACKAGING.md)。 原生 Android/iOS 资源使用 `npm --prefix mobile-uni run build:app` 构建;它不生成签名 APK/IPA,也不适用本文件的 H5 `rsync` 发布流程。自定义基座、协议链接、签名和真机门禁见 [MOBILE_APP_PACKAGING.md](MOBILE_APP_PACKAGING.md)。
@@ -91,23 +87,143 @@ AIHR_AI_SPEECH_ENABLED=true
`application-dev.yml` 只保留占位和默认值,不提交真实短信密钥。dev 环境不配阿里云短信也能登录移动端:验证码固定 `123456`。 `application-dev.yml` 只保留占位和默认值,不提交真实短信密钥。dev 环境不配阿里云短信也能登录移动端:验证码固定 `123456`。
## 启动步骤 <a id="windows-docker-desktop"></a>
在项目根目录执行: ## Windows 10/11 + Docker Desktop
```bash Windows 推荐让 Docker Desktop 承载 MySQL、Redis、MinIO 和 Qdrant,Java/Vite/portless 仍作为 Windows 进程运行;无需在 Windows 单独安装数据库或 Redis 服务。基础环境要求:
./scripts/dev.sh
- Docker Desktop 已启动,`docker info` 可连接 daemon
- Git for Windows(使用其 Git Bash 和 OpenSSL)
- JDK 17、Maven
- Node.js 24+、npm、全局 `portless`
- 可选:测试视频解析时另装 `ffmpeg` 和 `ffprobe`
### 1. PowerShell 会话准备
在仓库根目录打开 PowerShell。下面通过 `git.exe` 自动定位 Git for Windows,不依赖仓库或 Git 的固定安装盘符:
```powershell
$gitRoot = Split-Path (Split-Path (Get-Command git).Source -Parent) -Parent
$gitBash = Join-Path $gitRoot 'bin\bash.exe'
$env:Path = "$(Join-Path $gitRoot 'usr\bin');$(Join-Path $gitRoot 'bin');$env:Path"
docker info
docker compose -f docker-compose.dev.yml config --quiet
java -version
mvn -version
node --version
portless --version
portless doctor
``` ```
`./scripts/dev.sh` 默认通过 portless 暴露后端、管理端和当前 `mobile-uni` 用户侧。若要显式使用旧端口调试,可执行 `PORTLESS=0 ./scripts/dev.sh`,后端入口为 `http://127.0.0.1:8080/`,管理端入口为 `http://127.0.0.1:5173/`,旧移动端兜底入口为 `http://127.0.0.1:5174/h5/user`。 若 `portless doctor` 仅提示代理未启动,属于首启正常状态;若提示找不到 OpenSSL,确认本会话已执行上面的 `$env:Path` 设置。首次使用 HTTPS 本地域名时执行一次:
首次启动或需要重建本地 `ry-vue` MVP 数据库时执行: ```powershell
portless trust
```bash
./scripts/dev.sh --reset
``` ```
`--reset` 会删除并重建本地 MVP 数据库,只用于本地开发环境。 公司代理、VPN 或 TUN 软件可能把 `*.localhost` 在 Node.js 中解析到 `198.18.0.0/15`,导致 Vite 页面能打开、`/dev-api` 却返回 `500`。下面的 Windows 流程先让 portless 为后端分配内部端口,再让两个 Vite 代理从 `portless list` 读取该端口并直连 `127.0.0.1`,因此不依赖 Node.js 对 `*.localhost` 的解析,也不要求 `8080` 空闲;浏览器入口仍使用 portless HTTPS 域名。若浏览器本身也无法解析这些域名,可在路由启动后,用**管理员 PowerShell** 执行一次 `portless hosts sync`。
### 2. 首次初始化
首次检出时安装两个当前前端工程的锁定依赖:
```powershell
npm --prefix frontend ci
npm --prefix mobile-uni ci
```
首次创建本地测试库时,通过 Git Bash 执行初始化脚本:
```powershell
& $gitBash ./scripts/reset-dev-db.sh
```
该脚本会在 Docker Desktop 中启动 `wygj-mysql`、`wygj-redis`、`wygj-minio`、`wygj-qdrant`,并**删除后重建**本地 `ry-vue`、导入若依与 AIHR schema/seed。仅首次初始化或明确需要清空本地测试数据时使用。
后续日常启动依赖容器不重建数据:
```powershell
docker compose -f docker-compose.dev.yml up -d mysql redis qdrant minio minio-init
```
基础开发不要求 `.env.local`:dev 短信验证码默认固定为 `123456`,模型调用失败仍保留 seed fallback。真实短信、外部组织同步或外部 AI 模型联调时,再按前文示例创建被 Git 忽略的 `.env.local`。
### 3. 启动后端
新开一个 PowerShell,重复“PowerShell 会话准备”中的 `$gitRoot`、`$gitBash` 和 `$env:Path` 三行,然后执行:
```powershell
portless run --name wygj-api --force bash ./scripts/dev-backend.sh
```
首次启动没有 `backend/ruoyi-admin/target/ruoyi-admin.jar` 时,脚本会先执行 Maven 打包;保持该终端运行。portless 分配的内部端口是动态的,对外入口始终是 `https://wygj-api.localhost/`。
### 4. 启动管理端与 mobile-uni
管理端和 `mobile-uni` 各使用一个 PowerShell,两个终端都先重复“PowerShell 会话准备”中的变量设置。
管理端终端在仓库根目录执行:
```powershell
$apiRoute = (portless list | Select-String 'https://wygj-api\.localhost').Line
$apiPort = [regex]::Match($apiRoute, 'localhost:(\d+)').Groups[1].Value
if (-not $apiPort) { throw 'wygj-api portless route not found' }
$env:VITE_APP_PROXY_TARGET = "http://127.0.0.1:$apiPort"
& $gitBash ./scripts/dev-frontend.sh
```
`mobile-uni` 终端在仓库根目录执行:
```powershell
$apiRoute = (portless list | Select-String 'https://wygj-api\.localhost').Line
$apiPort = [regex]::Match($apiRoute, 'localhost:(\d+)').Groups[1].Value
if (-not $apiPort) { throw 'wygj-api portless route not found' }
Set-Location .\mobile-uni
$env:VITE_PROXY_TARGET = "http://127.0.0.1:$apiPort"
portless run --name wygj-mobile-uni --force npm run dev
```
本机 portless `0.15.4` 在没有根 `package.json` workspace 时不会仅凭 `portless.json` 批量启动两个前端,因此不要用根目录裸命令 `portless` 代替上述两个入口。后端重新启动后内部端口可能变化,此时也要重新启动两个前端以刷新代理目标。保持三个应用终端运行,访问:
- 管理端:`https://wygj-admin.localhost/`
- 用户侧:`https://wygj-mobile-uni.localhost/h5/`
- 后端:`https://wygj-api.localhost/`
### 5. 冒烟与测试
```powershell
$gitBash = Join-Path $gitRoot 'bin\bash.exe'
docker compose -f docker-compose.dev.yml ps
portless list
curl.exe -k -fsS https://wygj-admin.localhost/dev-api/auth/tenant/list
curl.exe -k -fsS https://wygj-admin.localhost/dev-api/auth/code
curl.exe -k -fsS https://wygj-mobile-uni.localhost/dev-api/api/aihr/mobile/home/user
docker exec wygj-mysql mysql -uroot -proot --default-character-set=utf8mb4 -N -B -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='ry-vue';"
docker exec wygj-redis redis-cli -a ruoyi123 ping
curl.exe -fsS http://127.0.0.1:9000/minio/health/live
curl.exe -k -fsS http://127.0.0.1:6333/
npm --prefix mobile-uni run test:unit
npm --prefix mobile-uni run typecheck
npm --prefix frontend run build:dev
mvn -f backend/pom.xml -pl ruoyi-modules/ruoyi-aihr -am -DskipTests=false test
& $gitBash ./scripts/demo-check.sh
```
### 6. 停止
先在后端、管理端和 `mobile-uni` 三个终端按 `Ctrl+C`。需要同时停止代理和依赖容器时执行:
```powershell
portless proxy stop
docker compose -f docker-compose.dev.yml stop
```
日常停止不需要 `docker compose down -v`;当前数据库等数据使用仓库 `.data/` bind mount,只有明确重置时才运行 `reset-dev-db.sh`,不要手工删除 `.data/mysql` 等目录。
## 默认登录 ## 默认登录
@@ -233,7 +349,7 @@ RELEASE_REMOTE_URL=https://peilian.njzhmj.top RELEASE_VERIFY_REMOTE_MATCH=true R
- 移动端登录后若组织快照接口返回 `401/403`,只降级为手动岗位确认,不应清除手机号登录态;岗位确认页仍需允许员工选择“生活顾问”后继续进入业务页。 - 移动端登录后若组织快照接口返回 `401/403`,只降级为手动岗位确认,不应清除手机号登录态;岗位确认页仍需允许员工选择“生活顾问”后继续进入业务页。
- uni-app 主管端:进入 `https://wygj-mobile-uni.localhost/h5/#/pages/supervisor/index/index`,应看到团队概览、团队画像、团队预警、指派专项、待复盘和复盘详情;从团队画像派专项后,最近专项应立即回读新记录。 - uni-app 主管端:进入 `https://wygj-mobile-uni.localhost/h5/#/pages/supervisor/index/index`,应看到团队概览、团队画像、团队预警、指派专项、待复盘和复盘详情;从团队画像派专项后,最近专项应立即回读新记录。
- uni-app 候选人端:进入 `https://wygj-mobile-uni.localhost/h5/#/pages/candidate/index/index`,手机号登录(dev 验证码固定 `123456`)→ “开始面试/面试练习”完成答题评分;“补充资料”选择 PDF/Word/图片后上传,应看到资料状态。Codex 内置浏览器不支持本地文件选择时,用真实 HTTP multipart smoke 代替浏览器文件选择。 - uni-app 候选人端:进入 `https://wygj-mobile-uni.localhost/h5/#/pages/candidate/index/index`,手机号登录(dev 验证码固定 `123456`)→ “开始面试/面试练习”完成答题评分;“补充资料”选择 PDF/Word/图片后上传,应看到资料状态。Codex 内置浏览器不支持本地文件选择时,用真实 HTTP multipart smoke 代替浏览器文件选择。
- 真 LLM 激活:在 `/system/model` 给供应商填 api_host/api_key 并启用 `category=chat` 模型后,三角色对练的客户回复与评分即为真实 LLM 生成;再启用 `category=asr/tts`(如硅基流动 SenseVoice/CosyVoice2)语音路径生效。未配置时全链路自动回退 seed。 - 真 LLM 激活:在 `/system/model` 给供应商填 api_host/api_key 并启用 `category=chat` 模型后,三角色对练的客户回复与评分即为真实 LLM 生成;再启用 `category=asr/tts` 语音路径生效。阿里云短音频 ASR 使用 `provider_code=dashscope`、`model_name=qwen3-asr-flash` 和北京工作空间的 `/compatible-mode/v1` Base URL;现有 `backend/.env` 中同一工作空间的 `AIHR_QWEN_REALTIME_ENDPOINT` / `AIHR_QWEN_REALTIME_API_KEY` 可作为本地模型管理的配置来源,但应用不会自动把私密变量导入模型表。密钥只通过模型管理或本地私密配置提供,不写入文档、SQL 或受版本控制配置。SiliconFlow SenseVoice/CosyVoice2 仍作为兼容供应商。未配置时全链路自动回退 seed。
演示前可先跑最小预检: 演示前可先跑最小预检:
+4
View File
@@ -10,6 +10,10 @@
4. 每台设备保留系统版本、App `versionName/versionCode`、基座/包哈希、录屏或截图和失败日志。 4. 每台设备保留系统版本、App `versionName/versionCode`、基座/包哈希、录屏或截图和失败日志。
5. HBuilderX/CLI 编译链必须与手机调试基座兼容;启动时出现版本不匹配弹窗即视为未通过。当前版本组合和排障命令见 `MOBILE_APP_PACKAGING.md`。 5. HBuilderX/CLI 编译链必须与手机调试基座兼容;启动时出现版本不匹配弹窗即视为未通过。当前版本组合和排障命令见 `MOBILE_APP_PACKAGING.md`。
## 当前证据边界
2026-07-26 已在 vivo V2443A(Android 15)的 HBuilderX 5.22 标准基座完成手机号登录,并通过生产 `dashscope/qwen3-asr-flash` 跑通“按住说话 → ASR → 提交”链路。该证据只证明单台 Android 标准基座和生产短音频识别,不代表自定义基座、原生隐私弹窗、拒绝权限、弱网、方言、iOS 或下列全项已通过,因此清单继续保持未勾选。
## Android(最低 Android 10 + 一台当前主流机型) ## Android(最低 Android 10 + 一台当前主流机型)
- [ ] 首次启动先显示原生隐私弹窗;两个协议链接可打开,拒绝后退出,同意后才进入登录。 - [ ] 首次启动先显示原生隐私弹窗;两个协议链接可打开,拒绝后退出,同意后才进入登录。
+17 -9
View File
@@ -8,8 +8,8 @@
- App 直接请求 `https://peilian.njzhmj.top/dev-api`。不依赖 H5 开发服务器的 `/dev-api` proxy;地址是公开配置,不得在 App 包中放入短信、模型、签名或任何服务端密钥。 - App 直接请求 `https://peilian.njzhmj.top/dev-api`。不依赖 H5 开发服务器的 `/dev-api` proxy;地址是公开配置,不得在 App 包中放入短信、模型、签名或任何服务端密钥。
- `manifest.json` 只保留不含秘密的发布配置。`.keystore`、`.p12`、`.mobileprovision` 与证书密码只能由发布负责人在 HBuilderX 云打包界面或受控 CI 秘密变量中提供,绝不能提交 Git。 - `manifest.json` 只保留不含秘密的发布配置。`.keystore`、`.p12`、`.mobileprovision` 与证书密码只能由发布负责人在 HBuilderX 云打包界面或受控 CI 秘密变量中提供,绝不能提交 Git。
- Android 最低试点设备为 Android 10,iOS 最低试点设备为 iOS 15;每次发版提升 `versionCode`,再更新 `versionName`。 - Android 最低试点设备为 Android 10,iOS 最低试点设备为 iOS 15;每次发版提升 `versionCode`,再更新 `versionName`。
- 当前 App 编译链与本机 HBuilderX `5.15.2026070915` 标准基座对齐:`@dcloudio/uni-app`、`@dcloudio/uni-app-plus`、`@dcloudio/vite-plugin-uni` 固定为 `3.0.0-alpha-5010220260604001`。这是 HBuilderX/uni-app 编译器版本,不是 Android `minSdkVersion`。 - 当前编译链与本机 HBuilderX 5.22 对齐:GUI 产品版本为 `5.22.2026071707`,`D:\HBuilderX\cli.exe version` 返回 `5.22.2026072503-alpha`;`@dcloudio/uni-app`、`@dcloudio/uni-app-plus`、`@dcloudio/uni-h5`、`@dcloudio/vite-plugin-uni` 均固定为 `3.0.0-alpha-5020220260725001`。这是 HBuilderX/uni-app 编译器版本,不是 Android `minSdkVersion`。
- `@dcloudio/uni-h5` 有意保留 `3.0.0-alpha-5020120260710001`;5.15 内置的 H5 包没有导出项目仍在使用的 `Audio` 组件,会使 `build:h5` 失败。不要为了“版本整齐”把 H5 包一并降级。 - 四个 DCloud 编译包必须保持同一批次;否则 npm 版 uni-ui 的 easycom 解析可能落入不同的 `uni-cli-shared` 实例,表现为 `<uni-forms>`、`<uni-easyinput>` 等组件无法解析。
## 本地验证与出包 ## 本地验证与出包
@@ -39,7 +39,7 @@ npm --prefix mobile-uni run build:app
- 现有品牌源图仅为 64×64,因此这里生成的是**可用于自定义基座和测试包的派生资产**。正式提交商店前应替换为品牌方提供的高分辨率母版,再重新执行生成和预检。 - 现有品牌源图仅为 64×64,因此这里生成的是**可用于自定义基座和测试包的派生资产**。正式提交商店前应替换为品牌方提供的高分辨率母版,再重新执行生成和预检。
- `androidPrivacy.json.example` 是**未启用的法务模板**,其中 `__TERMS_URL__` 与 `__PRIVACY_URL__` 必须替换为法务确认的 HTTPS 地址。复制为被 Git 忽略的 `androidPrivacy.json` 后,`npm --prefix mobile-uni run verify:app-release` 才会通过。 - `androidPrivacy.json.example` 是**未启用的法务模板**,其中 `__TERMS_URL__` 与 `__PRIVACY_URL__` 必须替换为法务确认的 HTTPS 地址。复制为被 Git 忽略的 `androidPrivacy.json` 后,`npm --prefix mobile-uni run verify:app-release` 才会通过。
- iOS 已按实际功能填写麦克风和照片库用途说明;不申请相机、定位、通讯录、蓝牙或广告追踪权限。 - iOS 已按实际功能填写麦克风和照片库用途说明;不申请相机、定位、通讯录、蓝牙或广告追踪权限。
- `build:app` 依赖 `@dcloudio/uni-app-plus`,它必须与 `@dcloudio/uni-app`、`@dcloudio/vite-plugin-uni` 同版本;H5 包是上文说明的平台例外。缺少 App 编译器时命令**不报错**,只静默产出带 `/h5/` 基路径的 H5 空壳,产物里没有 `app-service.js` 与 `app-renderjs.js`,App 平台代码等于从未编译。判定 `build:app` 是否真的成功要看产物中是否存在 `app-service.js`、`app-renderjs.js`、`manifest.json`,不能只看 `DONE Build complete.`。 - `build:app` 依赖 `@dcloudio/uni-app-plus`,它必须与 `@dcloudio/uni-app`、`@dcloudio/uni-h5`、`@dcloudio/vite-plugin-uni` 同版本。缺少 App 编译器时命令**不报错**,只静默产出带 `/h5/` 基路径的 H5 空壳,产物里没有 `app-service.js` 与 `app-renderjs.js`,App 平台代码等于从未编译。判定 `build:app` 是否真的成功要看产物中是否存在 `app-service.js`、`app-renderjs.js`、`manifest.json`,不能只看 `DONE Build complete.`。
- App-Plus 实时对练通过 `renderjs` 在系统 WebView 中执行媒体/WebRTC;认证 SDP 与工具请求仍由逻辑层代理。发布前必须在 Android/iOS 真机验证麦克风授权、实时转写、远端语音播放、前后台切换和断线降级。 - App-Plus 实时对练通过 `renderjs` 在系统 WebView 中执行媒体/WebRTC;认证 SDP 与工具请求仍由逻辑层代理。发布前必须在 Android/iOS 真机验证麦克风授权、实时转写、远端语音播放、前后台切换和断线降级。
- 真机步骤和证据口径见 `docs/MOBILE_APP_DEVICE_ACCEPTANCE.md`。资源预检通过不等于 Android/iOS 真机或应用商店验收通过。 - 真机步骤和证据口径见 `docs/MOBILE_APP_DEVICE_ACCEPTANCE.md`。资源预检通过不等于 Android/iOS 真机或应用商店验收通过。
@@ -48,14 +48,22 @@ npm --prefix mobile-uni run build:app
若真机提示“本应用使用 HBuilderX X 或对应 CLI 版本编译,而手机端 SDK 版本是 Y”,先核对编译依赖与基座,不要修改 Android `minSdkVersion`: 若真机提示“本应用使用 HBuilderX X 或对应 CLI 版本编译,而手机端 SDK 版本是 Y”,先核对编译依赖与基座,不要修改 Android `minSdkVersion`:
```bash ```bash
/Applications/HBuilderX.app/Contents/MacOS/cli --version node -e "for (const n of ['@dcloudio/uni-app','@dcloudio/uni-app-plus','@dcloudio/uni-h5','@dcloudio/vite-plugin-uni']) console.log(n, require('./mobile-uni/node_modules/'+n+'/package.json').version)"
node -e "for (const n of ['@dcloudio/uni-app','@dcloudio/uni-app-plus','@dcloudio/vite-plugin-uni']) console.log(n, require('./mobile-uni/node_modules/'+n+'/package.json').version)"
/Applications/HBuilderX.app/Contents/MacOS/cli launch app-android \
--project "$PWD/mobile-uni" --deviceId <adb-serial> \
--playground standard --compile true
``` ```
当前 5.15 内置包在 `build:app` 输出中显示 `Compiler version: 5.12(vue3)`,属于 DCloud 自身的版本映射;依赖、HBuilderX 和手机标准基座按上述固定版本组合后,真机不再弹出 5.21/5.15 不匹配提示。 Windows PowerShell 再核对 HBuilderX CLI 与设备;项目已导入 HBuilderX 且设备在线后,才执行最后一条运行命令:
```powershell
& 'D:\HBuilderX\cli.exe' version
& 'D:\HBuilderX\cli.exe' devices list --platform android
& 'D:\HBuilderX\cli.exe' launch app-android `
--project (Resolve-Path '.\mobile-uni').Path --deviceId <adb-serial> `
--playground standard --native-log true
```
标准基座可先验证编译器/SDK 兼容、启动和页面交互;完整权限验收必须先生成 5.22 自定义基座,再把上面的 `standard` 改为 `custom` 重跑。不要在真机运行命令中加 `--compile true`,该参数表示“只编译代码”,不会安装或启动手机端应用。
当前项目依赖已与 HBuilderX 5.22 统一;升级后必须重新生成并安装 5.22 自定义运行基座,旧的 5.15 基座不能继续用于真机验收。命令行资源构建通过只证明编译链可用,不等同于已完成真机基座验证。
## 更新策略 ## 更新策略
+2 -2
View File
@@ -18,7 +18,7 @@
| 文档 | 用途 | | 文档 | 用途 |
|---|---| |---|---|
| [../CHANGELOG.md](../CHANGELOG.md) | 按明确时间记录源码、生产发布、线上验证和未验收边界 | | [../CHANGELOG.md](../CHANGELOG.md) | 按明确时间记录源码、生产发布、线上验证和未验收边界 |
| [DEV_SETUP.md](DEV_SETUP.md) | 本地端口、账号、启动步骤、基础链路验证、管理端与移动端 H5 静态发布 | | [DEV_SETUP.md](DEV_SETUP.md) | Linux/macOS 与 Windows + Docker Desktop 的本地端口、账号、启动步骤、基础链路验证和静态发布 |
| [MOBILE_APP_PACKAGING.md](MOBILE_APP_PACKAGING.md) | `mobile-uni` Android/iOS 资源构建、隐私/签名边界和出包前置条件 | | [MOBILE_APP_PACKAGING.md](MOBILE_APP_PACKAGING.md) | `mobile-uni` Android/iOS 资源构建、隐私/签名边界和出包前置条件 |
| [MOBILE_APP_DEVICE_ACCEPTANCE.md](MOBILE_APP_DEVICE_ACCEPTANCE.md) | Android/iOS 自定义基座或签名包的真机验收清单 | | [MOBILE_APP_DEVICE_ACCEPTANCE.md](MOBILE_APP_DEVICE_ACCEPTANCE.md) | Android/iOS 自定义基座或签名包的真机验收清单 |
| [FIGMA_DESIGN_INVENTORY.md](FIGMA_DESIGN_INVENTORY.md) | Figma 页面节点索引、设计批次范围、取消项和全文件一致性审计结果 | | [FIGMA_DESIGN_INVENTORY.md](FIGMA_DESIGN_INVENTORY.md) | Figma 页面节点索引、设计批次范围、取消项和全文件一致性审计结果 |
@@ -55,7 +55,7 @@
| [AI陪练二期开发推进计划.md](AI陪练二期开发推进计划.md) | 2026-07-11 历史推进记录;保留 M0-M5 的工程追溯,不再作为当前施工范围 | | [AI陪练二期开发推进计划.md](AI陪练二期开发推进计划.md) | 2026-07-11 历史推进记录;保留 M0-M5 的工程追溯,不再作为当前施工范围 |
| [员工端版本功能对比与功能对齐清单-20260717.md](员工端版本功能对比与功能对齐清单-20260717.md) | 旧版/历史需求/当前实现/生产验收的版本对比,以及 2026-07-17 客户反馈逐项处理结果 | | [员工端版本功能对比与功能对齐清单-20260717.md](员工端版本功能对比与功能对齐清单-20260717.md) | 旧版/历史需求/当前实现/生产验收的版本对比,以及 2026-07-17 客户反馈逐项处理结果 |
| [BRD_IMPLEMENTATION_AUDIT.md](BRD_IMPLEMENTATION_AUDIT.md) | 当前生产基线、三端输入/BRD 匹配、客户反馈完成分层和正式试点剩余硬门槛;旧发布流水从当前真相源移除 | | [BRD_IMPLEMENTATION_AUDIT.md](BRD_IMPLEMENTATION_AUDIT.md) | 当前生产基线、三端输入/BRD 匹配、客户反馈完成分层和正式试点剩余硬门槛;旧发布流水从当前真相源移除 |
| [BRD_PRODUCTION_MIGRATION_RUNBOOK.md](BRD_PRODUCTION_MIGRATION_RUNBOOK.md) | AIHR BRD 生产 schema/内置内容迁移顺序、64 项结构核验、私有个人资料存储配置和发布后回归口径 | | [BRD_PRODUCTION_MIGRATION_RUNBOOK.md](BRD_PRODUCTION_MIGRATION_RUNBOOK.md) | AIHR BRD 生产 schema/内置内容迁移顺序、结构核验、当前运行基线、单项热修复回滚和发布后回归口径 |
| [20260708/uni-app用户侧前端重建计划.md](20260708/uni-app用户侧前端重建计划.md) | `mobile-uni/` 重建阶段留档;当前完成状态以 BRD 审查和版本功能对比为准 | | [20260708/uni-app用户侧前端重建计划.md](20260708/uni-app用户侧前端重建计划.md) | `mobile-uni/` 重建阶段留档;当前完成状态以 BRD 审查和版本功能对比为准 |
| [20260708/数字师傅学练问报整合方案.md](20260708/数字师傅学练问报整合方案.md) | 产品定义(学练问报+问题榜+学分晋升+个人 AI 助理)及 v1.8 “问”模块 Agent 关联与实施边界 | | [20260708/数字师傅学练问报整合方案.md](20260708/数字师傅学练问报整合方案.md) | 产品定义(学练问报+问题榜+学分晋升+个人 AI 助理)及 v1.8 “问”模块 Agent 关联与实施边界 |
| [20260708/发布会演示候选题单.md](20260708/发布会演示候选题单.md) | 2026-07-08 发布会演示候选题单,作为产品讨论留档,不作为阶段一开发入口 | | [20260708/发布会演示候选题单.md](20260708/发布会演示候选题单.md) | 2026-07-08 发布会演示候选题单,作为产品讨论留档,不作为阶段一开发入口 |
+179 -451
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -16,16 +16,16 @@
"typecheck": "vue-tsc --noEmit" "typecheck": "vue-tsc --noEmit"
}, },
"dependencies": { "dependencies": {
"@dcloudio/uni-app": "3.0.0-alpha-5010220260604001", "@dcloudio/uni-app": "3.0.0-alpha-5020220260725001",
"@dcloudio/uni-app-plus": "3.0.0-alpha-5010220260604001", "@dcloudio/uni-app-plus": "3.0.0-alpha-5020220260725001",
"@dcloudio/uni-h5": "3.0.0-alpha-5020120260710001", "@dcloudio/uni-h5": "3.0.0-alpha-5020220260725001",
"@dcloudio/uni-ui": "^1.5.12", "@dcloudio/uni-ui": "^1.5.12",
"lxgw-wenkai-tc-webfont": "^1.0.0", "lxgw-wenkai-tc-webfont": "^1.0.0",
"vue": "3.4.21" "vue": "3.4.21"
}, },
"devDependencies": { "devDependencies": {
"@dcloudio/types": "3.4.31", "@dcloudio/types": "3.4.31",
"@dcloudio/vite-plugin-uni": "3.0.0-alpha-5010220260604001", "@dcloudio/vite-plugin-uni": "3.0.0-alpha-5020220260725001",
"sass": "^1.101.0", "sass": "^1.101.0",
"typescript": "~5.9.3", "typescript": "~5.9.3",
"vite": "5.2.8", "vite": "5.2.8",
+107 -275
View File
@@ -9,14 +9,14 @@ importers:
.: .:
dependencies: dependencies:
'@dcloudio/uni-app': '@dcloudio/uni-app':
specifier: 3.0.0-alpha-5010220260604001 specifier: 3.0.0-alpha-5020220260725001
version: 3.0.0-alpha-5010220260604001(@dcloudio/types@3.4.31)(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3)) version: 3.0.0-alpha-5020220260725001(@dcloudio/types@3.4.31)(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))
'@dcloudio/uni-app-plus': '@dcloudio/uni-app-plus':
specifier: 3.0.0-alpha-5010220260604001 specifier: 3.0.0-alpha-5020220260725001
version: 3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3)) version: 3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))
'@dcloudio/uni-h5': '@dcloudio/uni-h5':
specifier: 3.0.0-alpha-5020120260710001 specifier: 3.0.0-alpha-5020220260725001
version: 3.0.0-alpha-5020120260710001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3)) version: 3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))
'@dcloudio/uni-ui': '@dcloudio/uni-ui':
specifier: ^1.5.12 specifier: ^1.5.12
version: 1.5.12 version: 1.5.12
@@ -31,8 +31,8 @@ importers:
specifier: 3.4.31 specifier: 3.4.31
version: 3.4.31 version: 3.4.31
'@dcloudio/vite-plugin-uni': '@dcloudio/vite-plugin-uni':
specifier: 3.0.0-alpha-5010220260604001 specifier: 3.0.0-alpha-5020220260725001
version: 3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3)) version: 3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))
sass: sass:
specifier: ^1.101.0 specifier: ^1.101.0
version: 1.101.0 version: 1.101.0
@@ -600,87 +600,65 @@ packages:
'@dcloudio/types@3.4.31': '@dcloudio/types@3.4.31':
resolution: {integrity: sha512-YAqOfJpcAwMs4Fagv2oP+iRHSCJOJoN8JUYyoRD6gwfANhsI9QaYj4/j22FzSopfHkqjX50B7YkG/VRAyz9OnA==} resolution: {integrity: sha512-YAqOfJpcAwMs4Fagv2oP+iRHSCJOJoN8JUYyoRD6gwfANhsI9QaYj4/j22FzSopfHkqjX50B7YkG/VRAyz9OnA==}
'@dcloudio/uni-app-plus@3.0.0-alpha-5010220260604001': '@dcloudio/uni-app-plus@3.0.0-alpha-5020220260725001':
resolution: {integrity: sha512-QOYT/U3jXpQ5VAXGcjVHfUMS7uMtzMJeMTmrmVdXT7QUN7Tr//9QJG82z8vMkXD5lvnrDqt80DXixy9kNzz2dg==} resolution: {integrity: sha512-CDUTyRUqAVh6vdVBOhMfeM6QxkLkT9sb/UTMXActr5ZwQuasW6v/IFxLxhmwtkmlmPbs0SgiZ87LiJGWezasnA==}
'@dcloudio/uni-app-uts@3.0.0-alpha-5010220260604001': '@dcloudio/uni-app-uts@3.0.0-alpha-5020220260725001':
resolution: {integrity: sha512-BcdeJlPinUmF2iUX3UFdpzSPMAk5iIlj80H+mqTd23taha7YI6Xh1u/fMYXgKyBDsLi3hNQAY2sRnI0H4dViVQ==} resolution: {integrity: sha512-pF11SxmV3pNnq11C8EhJGNwukmTurAuLBXnuRDT0qJOq8sHIpg2QxgDu7+4t0378y3Q9tGPE2zryPFkLokU4PA==}
'@dcloudio/uni-app-vite@3.0.0-alpha-5010220260604001': '@dcloudio/uni-app-vite@3.0.0-alpha-5020220260725001':
resolution: {integrity: sha512-AnPDZUw8/YAQVOTm54K0g545d+jmKzzsQ/Vd2J+alm3LUyVjsWDJlyKLxsMbzdPClZ9bdfi+F/+lKJB0W0QAGw==} resolution: {integrity: sha512-XKrKkYjchlyCL36S5rhAK23/jLLwY+Xucl/oICFKuqcScBcOTg7POIzdg2PNq5PhuIf1onXks4G71aIwPNX4JA==}
'@dcloudio/uni-app-vue@3.0.0-alpha-5010220260604001': '@dcloudio/uni-app-vue@3.0.0-alpha-5020220260725001':
resolution: {integrity: sha512-5rxJhgRS6ZHWKIoz5uy/VKuk/RSwf2IVH1TzUyr8RyMnF5ACF0xrLxSXbWeNLJwx62WjwJ00J/RMdLo5nSmGOw==} resolution: {integrity: sha512-i54JJO84KZ2EpYK+sWq3h750iATcrvUdfHO33l8pdBwQunqbYMZFW4tJeivCekwL02jOVJWIZXl1I4eOb5qY/Q==}
'@dcloudio/uni-app@3.0.0-alpha-5010220260604001': '@dcloudio/uni-app@3.0.0-alpha-5020220260725001':
resolution: {integrity: sha512-B4OsM0IaQzIBU9IGFJQwKuXnLC8wIUkkVEH4BdEAj6oVdcVpvQs5crNdfdEF2l5BX9tptlVxEdy2ZohIGqytxw==} resolution: {integrity: sha512-jEAbTtfrcAZOfQEJqDEGfM6AVlxRpd4j4kJVHO8+HX3l7NY0vCfgNshM4U8fKB7Ppf27GI7fifoOrN9jJtxscg==}
peerDependencies: peerDependencies:
'@dcloudio/types': 3.4.31 '@dcloudio/types': 3.4.31
'@dcloudio/uni-cli-shared@3.0.0-alpha-5010220260604001': '@dcloudio/uni-cli-shared@3.0.0-alpha-5020220260725001':
resolution: {integrity: sha512-12M5X8/jH/9kYBQQFl0qtniP5GtGxEBO/+h73zN/w8Z0qXfmXgHXxEly8IwDrCqXI4yL008PF+3PMY17krZ7LQ==} resolution: {integrity: sha512-wG93Dva8wjhPPeSDgLXu3+ZV2TiZg3Yk66WDF0E8T3aqLZYnquzGna1SLZXhmPxpqplMEUstO55mHWuNfveEwQ==}
engines: {node: ^14.18.0 || >=16.0.0} engines: {node: ^14.18.0 || >=16.0.0}
'@dcloudio/uni-cli-shared@3.0.0-alpha-5020120260710001': '@dcloudio/uni-cloud@3.0.0-alpha-5020220260725001':
resolution: {integrity: sha512-ZBs1zw83RHh+4Ecsvl/+ML+yGCUVo+oYb9gDaB/Z1leHDQ76kHvNtLNubf/Np9X5pzcXEx/Xe+PhqRvjdeuXbA==} resolution: {integrity: sha512-J3O+IsOk4x/mLu8dObqSGsEGzDhlyYZPEDzDAjwlZvQvzqhw3EUn6vSuzDW2XC5aD+sR52sdJDZleleFsPua2Q==}
engines: {node: ^14.18.0 || >=16.0.0}
'@dcloudio/uni-cloud@3.0.0-alpha-5010220260604001': '@dcloudio/uni-components@3.0.0-alpha-5020220260725001':
resolution: {integrity: sha512-gDldYdV6i1S5aJe+PHp3DQh1YD92GWBhwf9VVG1U0ncpVZ3I84Yd6Q+ndz5tpjGlJ9GQ3xGObaOopgdYSAoEkg==} resolution: {integrity: sha512-en/2zVgx443KM98eH5Lxhikfb8sdp0otq4txrQn9J3BEIvXiTZxvCCdTudB81opIyTol/CcDYv1SkI1crxULfA==}
'@dcloudio/uni-components@3.0.0-alpha-5010220260604001': '@dcloudio/uni-console@3.0.0-alpha-5020220260725001':
resolution: {integrity: sha512-CoE+bAVk8OSt0FoFRsiWm2WflMfYqcsqcJXIak/7rdsS7HJWMuT5NAaHAp7/6G/XMmHfCRAGQNsiiRGcEwTB6Q==} resolution: {integrity: sha512-PEk1+ftfZFc64KjM201gA/6r1ySYiy6kMPP3imqiEDEnmBUGZURPFU/60JcKYPxY4Pw6gauGuyR8Yd9jFi3pBQ==}
'@dcloudio/uni-console@3.0.0-alpha-5010220260604001': '@dcloudio/uni-h5-vite@3.0.0-alpha-5020220260725001':
resolution: {integrity: sha512-EFoWqXSV1sgj66sy4k7R7lbqbXyNx8Bxfy02MRALxDwXoMQf7bKCuH0mMyjvpy6np1o0XoV5WhaAAsH30XisJA==} resolution: {integrity: sha512-OmStZymZbpks0WcbGHZT4ExSu5vBBqx5V62SllZLC8jksfxQpvXuLLdVgqywH2SFdESIxn9B8aNOvI2qdyxIZg==}
'@dcloudio/uni-h5-vite@3.0.0-alpha-5010220260604001': '@dcloudio/uni-h5-vue@3.0.0-alpha-5020220260725001':
resolution: {integrity: sha512-mJOYPZKTsSyVDMpVK0QYiRCCbJvtEwEav9X398gXHL4HoCS7a/Dtjt6PVbQRsMmQ9GoxddtC1RNd7gUpAYZpsg==} resolution: {integrity: sha512-KF/oeQlhoTpxskQlUNHmIUO/XOosTccne8OgGu617Fx1f/lUi00OX7CgyhRAqei5cjOBfi3E9CWJON8Pa3R2bg==}
'@dcloudio/uni-h5-vite@3.0.0-alpha-5020120260710001': '@dcloudio/uni-h5@3.0.0-alpha-5020220260725001':
resolution: {integrity: sha512-NhalG7UZWE3hA8TOUFNSeMW2+t+e1e0gn1lbZGi+BzH//n8dR7xyX15KORhZPqv586ShldmA1BbdmPb46g46Jw==} resolution: {integrity: sha512-BA8LGHfe4nSYNmA9TZEXwxUl0HcJpjcvoPnQG6+4tmp0mtB6i162semklUhYhEeDv0Qn4ayq8g1EugICfL7A5Q==}
'@dcloudio/uni-h5-vue@3.0.0-alpha-5010220260604001': '@dcloudio/uni-i18n@3.0.0-alpha-5020220260725001':
resolution: {integrity: sha512-T+KDmJTRSlhiBAVXFkxwBpUhpYVtimamP9225h+PmkSCCYRePzSSdwUUOgZHObPl/7dNjf3ocGq1EKvv7oatCg==} resolution: {integrity: sha512-if4BmCMIoDLU/OpA2a+xDXVwju9YIWmML3WF0CikGG5Ri532nW+2I7lBU2GuKu/SjSd8G5ITTkA2xCRXs4H6rQ==}
'@dcloudio/uni-h5-vue@3.0.0-alpha-5020120260710001': '@dcloudio/uni-nvue-styler@3.0.0-alpha-5020220260725001':
resolution: {integrity: sha512-Uluox+HR4+Uj9HcXEz8mKZPzLJzrKLVNimGPtSHYAHnTJ0XGLmagn7qyO3OEusvge3yIvefYfIdS++h8dgyF1g==} resolution: {integrity: sha512-DSvhY09poQXiqxX/prWQNjP/EAtgmMOMb+ZbWk7T7ONJtxCsQfB00Vz7VcfHScEGxXSpcVPUrc9XfRI9Etj3Kw==}
'@dcloudio/uni-h5@3.0.0-alpha-5010220260604001': '@dcloudio/uni-push@3.0.0-alpha-5020220260725001':
resolution: {integrity: sha512-pAz7B6zJqSbmuZsnu95+Dkh3N717lo3XBO5qJzp55BrVJiA7ZBTPiqR8G7TU/6IMy6S12kze/liUvkfLtlaA+g==} resolution: {integrity: sha512-cHB2bWgBmjmP0tfaS/MW3mFKThqUfIZufgfbtFxAHeTusm5gtaCvW8wQKdw+oBkRofqi5ctg/KvDQu83wgG08A==}
'@dcloudio/uni-h5@3.0.0-alpha-5020120260710001': '@dcloudio/uni-shared@3.0.0-alpha-5020220260725001':
resolution: {integrity: sha512-wdWVFxWe6mHyaNx7vkU8jkPndETf6EcszWbJlKNS5nnMipsHEDIJTNBVn4Md5ofGejtlo03REjJ2HH37MG/kNw==} resolution: {integrity: sha512-daLwUEBbpX5ynewCk3wy2N36ZFs2IWG2Vd0sjN1+mYWTQrnqh3dACOB+aiN2I+wDau38hIWvpE+FJKx1uPD0pg==}
'@dcloudio/uni-i18n@3.0.0-alpha-5010220260604001': '@dcloudio/uni-stat@3.0.0-alpha-5020220260725001':
resolution: {integrity: sha512-IFIJnf1dpG96RLbDkQd7+2sPpedlIotuBk4Kldl2X0Dogeh2rRe1G3/DBlqVDNo97AvABF4nYChPQj6KFsV40A==} resolution: {integrity: sha512-MxxJDNNZZz6cWi1ZRBqEhfWiGfeybh/mXewRPL9LGyfqd2Cec251tdo1KMKBIsxOUf1JoXZtaIoRTZwpzS896A==}
'@dcloudio/uni-i18n@3.0.0-alpha-5020120260710001':
resolution: {integrity: sha512-B4PFuzRdFi9PIX6rvuJGvAJUlfKZPT9gjGogozWl7eToJbzX+vNjG5kPT0uaSBzI9qlbS6L2ObCkYkudZAPCBQ==}
'@dcloudio/uni-nvue-styler@3.0.0-alpha-5010220260604001':
resolution: {integrity: sha512-u+R+k2MXXPzMSdyoNJ+qwKhuuRfbfH8tGRtAVvbPWLqVUQMGnHBMEeK87zCkXfBQNUYFrs0JtOXtHU8DiG9JFg==}
'@dcloudio/uni-nvue-styler@3.0.0-alpha-5020120260710001':
resolution: {integrity: sha512-ahXTw9RyQb1EmaRYA/PFqyeUBAu41YyC4sdyXscpY5UAQUqC6EGu8IEIdrczj8pxYMitE7tGseGoWQdMEUtDGg==}
'@dcloudio/uni-push@3.0.0-alpha-5010220260604001':
resolution: {integrity: sha512-tuflI92CaC8k4KptGIyxVD+utTtp36bO4myNeZOtYH2pE0jArx0H+CNpuCtMWBhZWtkw2x1pX9/lYONbnH8oSg==}
'@dcloudio/uni-shared@3.0.0-alpha-5010220260604001':
resolution: {integrity: sha512-bzhGjGZZ/H3dvIeoDXAQXw6o0eZYJB5ET0JKQZaV1yw4fAsmB11W/Wt7mizfLe+NYJ/NdjlnLAq4mUskWZrRbg==}
'@dcloudio/uni-shared@3.0.0-alpha-5020120260710001':
resolution: {integrity: sha512-9awppRC9Mj9rpCLVNA5tR5qvyj3cui7CKzMhdn32haDA5MQb3JzWJvoUA1byjvbsaVahDrkCy9+68ltf9QLnyA==}
'@dcloudio/uni-stat@3.0.0-alpha-5010220260604001':
resolution: {integrity: sha512-DrnysOch1gOA8WZYLJA3OXMcdAT+h0vIP9hvWM7k1hjDUngb1DgWNo2N4E/Pc+3FFnQNnfORGTN+M4ti3edDkQ==}
'@dcloudio/uni-ui@1.5.12': '@dcloudio/uni-ui@1.5.12':
resolution: {integrity: sha512-mGDl2OZSz7D8xcUAzJegWDHOqB4MEFBSW9Esb/oJiu2/3Gk9+P/Z4bA4JZ9jv9VWBYbMrYwaTfK1Z728kABdYg==} resolution: {integrity: sha512-mGDl2OZSz7D8xcUAzJegWDHOqB4MEFBSW9Esb/oJiu2/3Gk9+P/Z4bA4JZ9jv9VWBYbMrYwaTfK1Z728kABdYg==}
'@dcloudio/vite-plugin-uni@3.0.0-alpha-5010220260604001': '@dcloudio/vite-plugin-uni@3.0.0-alpha-5020220260725001':
resolution: {integrity: sha512-CTCiWuXID6eRSzX+XHK0ZfsO9XjK9EQRr0tfisbfiPv1+HABZsGaxOaLOKzRxrDhdqBTBr5L8ahEtcPJ2HWdVQ==} resolution: {integrity: sha512-iY5T1CWfEpJBi4B+7fY9oDhGNkWd+vM0KJWS7e5ozbME/EROddVzikRxQ8Ioaj/YmLHGzmR6rA93Z6t90H0Qfw==}
engines: {node: ^14.18.0 || >=16.0.0} engines: {node: ^14.18.0 || >=16.0.0}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
@@ -1050,42 +1028,36 @@ packages:
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm-musl@2.5.6': '@parcel/watcher-linux-arm-musl@2.5.6':
resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==} resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==}
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
libc: [musl]
'@parcel/watcher-linux-arm64-glibc@2.5.6': '@parcel/watcher-linux-arm64-glibc@2.5.6':
resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==} resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==}
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm64-musl@2.5.6': '@parcel/watcher-linux-arm64-musl@2.5.6':
resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==} resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==}
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [musl]
'@parcel/watcher-linux-x64-glibc@2.5.6': '@parcel/watcher-linux-x64-glibc@2.5.6':
resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==} resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==}
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [glibc]
'@parcel/watcher-linux-x64-musl@2.5.6': '@parcel/watcher-linux-x64-musl@2.5.6':
resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==} resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==}
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [musl]
'@parcel/watcher-win32-arm64@2.5.6': '@parcel/watcher-win32-arm64@2.5.6':
resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==} resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==}
@@ -1152,79 +1124,66 @@ packages:
resolution: {integrity: sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==} resolution: {integrity: sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm-musleabihf@4.62.2': '@rollup/rollup-linux-arm-musleabihf@4.62.2':
resolution: {integrity: sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==} resolution: {integrity: sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-linux-arm64-gnu@4.62.2': '@rollup/rollup-linux-arm64-gnu@4.62.2':
resolution: {integrity: sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==} resolution: {integrity: sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm64-musl@4.62.2': '@rollup/rollup-linux-arm64-musl@4.62.2':
resolution: {integrity: sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==} resolution: {integrity: sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-linux-loong64-gnu@4.62.2': '@rollup/rollup-linux-loong64-gnu@4.62.2':
resolution: {integrity: sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==} resolution: {integrity: sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==}
cpu: [loong64] cpu: [loong64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-loong64-musl@4.62.2': '@rollup/rollup-linux-loong64-musl@4.62.2':
resolution: {integrity: sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==} resolution: {integrity: sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==}
cpu: [loong64] cpu: [loong64]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-linux-ppc64-gnu@4.62.2': '@rollup/rollup-linux-ppc64-gnu@4.62.2':
resolution: {integrity: sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==} resolution: {integrity: sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==}
cpu: [ppc64] cpu: [ppc64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-ppc64-musl@4.62.2': '@rollup/rollup-linux-ppc64-musl@4.62.2':
resolution: {integrity: sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==} resolution: {integrity: sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==}
cpu: [ppc64] cpu: [ppc64]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-linux-riscv64-gnu@4.62.2': '@rollup/rollup-linux-riscv64-gnu@4.62.2':
resolution: {integrity: sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==} resolution: {integrity: sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==}
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-musl@4.62.2': '@rollup/rollup-linux-riscv64-musl@4.62.2':
resolution: {integrity: sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==} resolution: {integrity: sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==}
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-linux-s390x-gnu@4.62.2': '@rollup/rollup-linux-s390x-gnu@4.62.2':
resolution: {integrity: sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==} resolution: {integrity: sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==}
cpu: [s390x] cpu: [s390x]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.62.2': '@rollup/rollup-linux-x64-gnu@4.62.2':
resolution: {integrity: sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==} resolution: {integrity: sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-musl@4.62.2': '@rollup/rollup-linux-x64-musl@4.62.2':
resolution: {integrity: sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==} resolution: {integrity: sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-openbsd-x64@4.62.2': '@rollup/rollup-openbsd-x64@4.62.2':
resolution: {integrity: sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==} resolution: {integrity: sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==}
@@ -3206,11 +3165,11 @@ snapshots:
'@dcloudio/types@3.4.31': {} '@dcloudio/types@3.4.31': {}
'@dcloudio/uni-app-plus@3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))': '@dcloudio/uni-app-plus@3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))':
dependencies: dependencies:
'@dcloudio/uni-app-uts': 3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3)) '@dcloudio/uni-app-uts': 3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))
'@dcloudio/uni-app-vite': 3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3)) '@dcloudio/uni-app-vite': 3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))
'@dcloudio/uni-app-vue': 3.0.0-alpha-5010220260604001 '@dcloudio/uni-app-vue': 3.0.0-alpha-5020220260725001
debug: 4.3.7 debug: 4.3.7
fs-extra: 10.1.0 fs-extra: 10.1.0
licia: 1.41.1 licia: 1.41.1
@@ -3225,15 +3184,15 @@ snapshots:
- vite - vite
- vue - vue
'@dcloudio/uni-app-uts@3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))': '@dcloudio/uni-app-uts@3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))':
dependencies: dependencies:
'@babel/parser': 7.25.6 '@babel/parser': 7.25.6
'@babel/types': 7.25.6 '@babel/types': 7.25.6
'@dcloudio/uni-cli-shared': 3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3)) '@dcloudio/uni-cli-shared': 3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))
'@dcloudio/uni-console': 3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3)) '@dcloudio/uni-console': 3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))
'@dcloudio/uni-i18n': 3.0.0-alpha-5010220260604001 '@dcloudio/uni-i18n': 3.0.0-alpha-5020220260725001
'@dcloudio/uni-nvue-styler': 3.0.0-alpha-5010220260604001 '@dcloudio/uni-nvue-styler': 3.0.0-alpha-5020220260725001
'@dcloudio/uni-shared': 3.0.0-alpha-5010220260604001 '@dcloudio/uni-shared': 3.0.0-alpha-5020220260725001
'@jridgewell/gen-mapping': 0.3.12 '@jridgewell/gen-mapping': 0.3.12
'@jridgewell/trace-mapping': 0.3.31 '@jridgewell/trace-mapping': 0.3.31
'@rollup/pluginutils': 5.1.0(rollup@4.62.2) '@rollup/pluginutils': 5.1.0(rollup@4.62.2)
@@ -3260,12 +3219,12 @@ snapshots:
- ts-node - ts-node
- vue - vue
'@dcloudio/uni-app-vite@3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))': '@dcloudio/uni-app-vite@3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))':
dependencies: dependencies:
'@dcloudio/uni-cli-shared': 3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3)) '@dcloudio/uni-cli-shared': 3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))
'@dcloudio/uni-i18n': 3.0.0-alpha-5010220260604001 '@dcloudio/uni-i18n': 3.0.0-alpha-5020220260725001
'@dcloudio/uni-nvue-styler': 3.0.0-alpha-5010220260604001 '@dcloudio/uni-nvue-styler': 3.0.0-alpha-5020220260725001
'@dcloudio/uni-shared': 3.0.0-alpha-5010220260604001 '@dcloudio/uni-shared': 3.0.0-alpha-5020220260725001
'@rollup/pluginutils': 5.1.0(rollup@4.62.2) '@rollup/pluginutils': 5.1.0(rollup@4.62.2)
'@vitejs/plugin-vue': 5.2.4(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3)) '@vitejs/plugin-vue': 5.2.4(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))
'@vue/compiler-dom': 3.4.21 '@vue/compiler-dom': 3.4.21
@@ -3283,18 +3242,18 @@ snapshots:
- vite - vite
- vue - vue
'@dcloudio/uni-app-vue@3.0.0-alpha-5010220260604001': {} '@dcloudio/uni-app-vue@3.0.0-alpha-5020220260725001': {}
'@dcloudio/uni-app@3.0.0-alpha-5010220260604001(@dcloudio/types@3.4.31)(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))': '@dcloudio/uni-app@3.0.0-alpha-5020220260725001(@dcloudio/types@3.4.31)(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))':
dependencies: dependencies:
'@dcloudio/types': 3.4.31 '@dcloudio/types': 3.4.31
'@dcloudio/uni-cloud': 3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3)) '@dcloudio/uni-cloud': 3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))
'@dcloudio/uni-components': 3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3)) '@dcloudio/uni-components': 3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))
'@dcloudio/uni-console': 3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3)) '@dcloudio/uni-console': 3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))
'@dcloudio/uni-i18n': 3.0.0-alpha-5010220260604001 '@dcloudio/uni-i18n': 3.0.0-alpha-5020220260725001
'@dcloudio/uni-push': 3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3)) '@dcloudio/uni-push': 3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))
'@dcloudio/uni-shared': 3.0.0-alpha-5010220260604001 '@dcloudio/uni-shared': 3.0.0-alpha-5020220260725001
'@dcloudio/uni-stat': 3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3)) '@dcloudio/uni-stat': 3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))
'@vue/shared': 3.4.21 '@vue/shared': 3.4.21
transitivePeerDependencies: transitivePeerDependencies:
- '@nuxt/kit' - '@nuxt/kit'
@@ -3306,16 +3265,16 @@ snapshots:
- vite - vite
- vue - vue
'@dcloudio/uni-cli-shared@3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))': '@dcloudio/uni-cli-shared@3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))':
dependencies: dependencies:
'@ampproject/remapping': 2.3.0 '@ampproject/remapping': 2.3.0
'@babel/code-frame': 7.24.7 '@babel/code-frame': 7.24.7
'@babel/core': 7.25.2 '@babel/core': 7.25.2
'@babel/parser': 7.25.6 '@babel/parser': 7.25.6
'@babel/types': 7.25.6 '@babel/types': 7.25.6
'@dcloudio/uni-i18n': 3.0.0-alpha-5010220260604001 '@dcloudio/uni-i18n': 3.0.0-alpha-5020220260725001
'@dcloudio/uni-nvue-styler': 3.0.0-alpha-5010220260604001 '@dcloudio/uni-nvue-styler': 3.0.0-alpha-5020220260725001
'@dcloudio/uni-shared': 3.0.0-alpha-5010220260604001 '@dcloudio/uni-shared': 3.0.0-alpha-5020220260725001
'@intlify/core-base': 9.1.9 '@intlify/core-base': 9.1.9
'@intlify/shared': 9.1.9 '@intlify/shared': 9.1.9
'@intlify/vue-devtools': 9.1.9 '@intlify/vue-devtools': 9.1.9
@@ -3368,73 +3327,11 @@ snapshots:
- ts-node - ts-node
- vue - vue
'@dcloudio/uni-cli-shared@3.0.0-alpha-5020120260710001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))': '@dcloudio/uni-cloud@3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))':
dependencies: dependencies:
'@ampproject/remapping': 2.3.0 '@dcloudio/uni-cli-shared': 3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))
'@babel/code-frame': 7.24.7 '@dcloudio/uni-i18n': 3.0.0-alpha-5020220260725001
'@babel/core': 7.25.2 '@dcloudio/uni-shared': 3.0.0-alpha-5020220260725001
'@babel/parser': 7.25.6
'@babel/types': 7.25.6
'@dcloudio/uni-i18n': 3.0.0-alpha-5020120260710001
'@dcloudio/uni-nvue-styler': 3.0.0-alpha-5020120260710001
'@dcloudio/uni-shared': 3.0.0-alpha-5020120260710001
'@intlify/core-base': 9.1.9
'@intlify/shared': 9.1.9
'@intlify/vue-devtools': 9.1.9
'@rollup/pluginutils': 5.1.0(rollup@4.62.2)
'@vue/compiler-core': 3.4.21
'@vue/compiler-dom': 3.4.21
'@vue/compiler-sfc': 3.4.21
'@vue/compiler-ssr': 3.4.21
'@vue/server-renderer': 3.4.21(vue@3.4.21(typescript@5.9.3))
'@vue/shared': 3.4.21
adm-zip: 0.5.16
autoprefixer: 10.4.20(postcss@8.5.17)
base64url: 3.0.1
chokidar: 3.6.0
compare-versions: 3.6.0
debug: 4.3.7
entities: 7.0.1
es-module-lexer: 1.5.4
esbuild: 0.20.2
estree-walker: 2.0.2
fast-glob: 3.3.3
fs-extra: 10.1.0
hash-sum: 2.0.0
isbinaryfile: 5.0.2
jsonc-parser: 3.3.1
lines-and-columns: 2.0.4
magic-string: 0.30.11
merge: 2.1.1
mime: 3.0.0
module-alias: 2.2.3
os-locale-s-fix: 1.0.8-fix-1
picocolors: 1.1.0
postcss-import: 14.1.0(postcss@8.5.17)
postcss-load-config: 3.1.4(postcss@8.5.17)
postcss-modules: 4.3.0(postcss@8.5.17)
postcss-selector-parser: 6.1.2
resolve: 1.22.8
source-map-js: 1.2.1
tapable: 2.3.3
tinycolor2: 1.6.0
unimport: 4.1.1
unplugin-auto-import: 19.1.0
xregexp: 5.1.2
transitivePeerDependencies:
- '@nuxt/kit'
- '@vueuse/core'
- postcss
- rollup
- supports-color
- ts-node
- vue
'@dcloudio/uni-cloud@3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))':
dependencies:
'@dcloudio/uni-cli-shared': 3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))
'@dcloudio/uni-i18n': 3.0.0-alpha-5010220260604001
'@dcloudio/uni-shared': 3.0.0-alpha-5010220260604001
'@vue/shared': 3.4.21 '@vue/shared': 3.4.21
fast-glob: 3.3.3 fast-glob: 3.3.3
transitivePeerDependencies: transitivePeerDependencies:
@@ -3446,11 +3343,11 @@ snapshots:
- ts-node - ts-node
- vue - vue
'@dcloudio/uni-components@3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))': '@dcloudio/uni-components@3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))':
dependencies: dependencies:
'@dcloudio/uni-cloud': 3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3)) '@dcloudio/uni-cloud': 3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))
'@dcloudio/uni-h5': 3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3)) '@dcloudio/uni-h5': 3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))
'@dcloudio/uni-i18n': 3.0.0-alpha-5010220260604001 '@dcloudio/uni-i18n': 3.0.0-alpha-5020220260725001
transitivePeerDependencies: transitivePeerDependencies:
- '@nuxt/kit' - '@nuxt/kit'
- '@vueuse/core' - '@vueuse/core'
@@ -3461,9 +3358,9 @@ snapshots:
- vite - vite
- vue - vue
'@dcloudio/uni-console@3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))': '@dcloudio/uni-console@3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))':
dependencies: dependencies:
'@dcloudio/uni-cli-shared': 3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3)) '@dcloudio/uni-cli-shared': 3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))
fs-extra: 10.1.0 fs-extra: 10.1.0
transitivePeerDependencies: transitivePeerDependencies:
- '@nuxt/kit' - '@nuxt/kit'
@@ -3474,10 +3371,10 @@ snapshots:
- ts-node - ts-node
- vue - vue
'@dcloudio/uni-h5-vite@3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))': '@dcloudio/uni-h5-vite@3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))':
dependencies: dependencies:
'@dcloudio/uni-cli-shared': 3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3)) '@dcloudio/uni-cli-shared': 3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))
'@dcloudio/uni-shared': 3.0.0-alpha-5010220260604001 '@dcloudio/uni-shared': 3.0.0-alpha-5020220260725001
'@rollup/pluginutils': 5.1.0(rollup@4.62.2) '@rollup/pluginutils': 5.1.0(rollup@4.62.2)
'@vitejs/plugin-basic-ssl': 1.2.0(vite@5.2.8(sass@1.101.0)(terser@5.49.0)) '@vitejs/plugin-basic-ssl': 1.2.0(vite@5.2.8(sass@1.101.0)(terser@5.49.0))
'@vue/compiler-dom': 3.4.21 '@vue/compiler-dom': 3.4.21
@@ -3498,50 +3395,19 @@ snapshots:
- vite - vite
- vue - vue
'@dcloudio/uni-h5-vite@3.0.0-alpha-5020120260710001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))': '@dcloudio/uni-h5-vue@3.0.0-alpha-5020220260725001(vue@3.4.21(typescript@5.9.3))':
dependencies: dependencies:
'@dcloudio/uni-cli-shared': 3.0.0-alpha-5020120260710001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3)) '@dcloudio/uni-shared': 3.0.0-alpha-5020220260725001
'@dcloudio/uni-shared': 3.0.0-alpha-5020120260710001
'@rollup/pluginutils': 5.1.0(rollup@4.62.2)
'@vitejs/plugin-basic-ssl': 1.2.0(vite@5.2.8(sass@1.101.0)(terser@5.49.0))
'@vue/compiler-dom': 3.4.21
'@vue/compiler-sfc': 3.4.21
'@vue/server-renderer': 3.4.21(vue@3.4.21(typescript@5.9.3))
'@vue/shared': 3.4.21
debug: 4.3.7
fs-extra: 10.1.0
mime: 3.0.0
module-alias: 2.2.3
transitivePeerDependencies:
- '@nuxt/kit'
- '@vueuse/core'
- postcss
- rollup
- supports-color
- ts-node
- vite
- vue
'@dcloudio/uni-h5-vue@3.0.0-alpha-5010220260604001(vue@3.4.21(typescript@5.9.3))':
dependencies:
'@dcloudio/uni-shared': 3.0.0-alpha-5010220260604001
'@vue/server-renderer': 3.4.21(vue@3.4.21(typescript@5.9.3)) '@vue/server-renderer': 3.4.21(vue@3.4.21(typescript@5.9.3))
transitivePeerDependencies: transitivePeerDependencies:
- vue - vue
'@dcloudio/uni-h5-vue@3.0.0-alpha-5020120260710001(vue@3.4.21(typescript@5.9.3))': '@dcloudio/uni-h5@3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))':
dependencies: dependencies:
'@dcloudio/uni-shared': 3.0.0-alpha-5020120260710001 '@dcloudio/uni-h5-vite': 3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))
'@vue/server-renderer': 3.4.21(vue@3.4.21(typescript@5.9.3)) '@dcloudio/uni-h5-vue': 3.0.0-alpha-5020220260725001(vue@3.4.21(typescript@5.9.3))
transitivePeerDependencies: '@dcloudio/uni-i18n': 3.0.0-alpha-5020220260725001
- vue '@dcloudio/uni-shared': 3.0.0-alpha-5020220260725001
'@dcloudio/uni-h5@3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))':
dependencies:
'@dcloudio/uni-h5-vite': 3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))
'@dcloudio/uni-h5-vue': 3.0.0-alpha-5010220260604001(vue@3.4.21(typescript@5.9.3))
'@dcloudio/uni-i18n': 3.0.0-alpha-5010220260604001
'@dcloudio/uni-shared': 3.0.0-alpha-5010220260604001
'@vue/server-renderer': 3.4.21(vue@3.4.21(typescript@5.9.3)) '@vue/server-renderer': 3.4.21(vue@3.4.21(typescript@5.9.3))
'@vue/shared': 3.4.21 '@vue/shared': 3.4.21
debug: 4.3.7 debug: 4.3.7
@@ -3560,51 +3426,18 @@ snapshots:
- vite - vite
- vue - vue
'@dcloudio/uni-h5@3.0.0-alpha-5020120260710001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))': '@dcloudio/uni-i18n@3.0.0-alpha-5020220260725001': {}
dependencies:
'@dcloudio/uni-h5-vite': 3.0.0-alpha-5020120260710001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))
'@dcloudio/uni-h5-vue': 3.0.0-alpha-5020120260710001(vue@3.4.21(typescript@5.9.3))
'@dcloudio/uni-i18n': 3.0.0-alpha-5020120260710001
'@dcloudio/uni-shared': 3.0.0-alpha-5020120260710001
'@vue/server-renderer': 3.4.21(vue@3.4.21(typescript@5.9.3))
'@vue/shared': 3.4.21
debug: 4.3.7
localstorage-polyfill: 1.0.1
postcss-selector-parser: 6.1.2
safe-area-insets: 1.4.1
vue-router: 4.4.4(vue@3.4.21(typescript@5.9.3))
xmlhttprequest: 1.8.0
transitivePeerDependencies:
- '@nuxt/kit'
- '@vueuse/core'
- postcss
- rollup
- supports-color
- ts-node
- vite
- vue
'@dcloudio/uni-i18n@3.0.0-alpha-5010220260604001': {} '@dcloudio/uni-nvue-styler@3.0.0-alpha-5020220260725001':
'@dcloudio/uni-i18n@3.0.0-alpha-5020120260710001': {}
'@dcloudio/uni-nvue-styler@3.0.0-alpha-5010220260604001':
dependencies: dependencies:
'@vue/shared': 3.4.21 '@vue/shared': 3.4.21
parse-css-font: 4.0.0 parse-css-font: 4.0.0
postcss: 8.5.6 postcss: 8.5.6
tinycolor2: 1.6.0 tinycolor2: 1.6.0
'@dcloudio/uni-nvue-styler@3.0.0-alpha-5020120260710001': '@dcloudio/uni-push@3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))':
dependencies: dependencies:
'@vue/shared': 3.4.21 '@dcloudio/uni-cli-shared': 3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))
parse-css-font: 4.0.0
postcss: 8.5.6
tinycolor2: 1.6.0
'@dcloudio/uni-push@3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))':
dependencies:
'@dcloudio/uni-cli-shared': 3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))
transitivePeerDependencies: transitivePeerDependencies:
- '@nuxt/kit' - '@nuxt/kit'
- '@vueuse/core' - '@vueuse/core'
@@ -3614,18 +3447,14 @@ snapshots:
- ts-node - ts-node
- vue - vue
'@dcloudio/uni-shared@3.0.0-alpha-5010220260604001': '@dcloudio/uni-shared@3.0.0-alpha-5020220260725001':
dependencies: dependencies:
'@vue/shared': 3.4.21 '@vue/shared': 3.4.21
'@dcloudio/uni-shared@3.0.0-alpha-5020120260710001': '@dcloudio/uni-stat@3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))':
dependencies: dependencies:
'@vue/shared': 3.4.21 '@dcloudio/uni-cli-shared': 3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))
'@dcloudio/uni-shared': 3.0.0-alpha-5020220260725001
'@dcloudio/uni-stat@3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))':
dependencies:
'@dcloudio/uni-cli-shared': 3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))
'@dcloudio/uni-shared': 3.0.0-alpha-5010220260604001
debug: 4.3.7 debug: 4.3.7
transitivePeerDependencies: transitivePeerDependencies:
- '@nuxt/kit' - '@nuxt/kit'
@@ -3638,14 +3467,15 @@ snapshots:
'@dcloudio/uni-ui@1.5.12': {} '@dcloudio/uni-ui@1.5.12': {}
'@dcloudio/vite-plugin-uni@3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))': '@dcloudio/vite-plugin-uni@3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))':
dependencies: dependencies:
'@babel/core': 7.25.2 '@babel/core': 7.25.2
'@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.25.2) '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.25.2)
'@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.25.2) '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.25.2)
'@dcloudio/uni-cli-shared': 3.0.0-alpha-5010220260604001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3)) '@babel/types': 7.25.6
'@dcloudio/uni-nvue-styler': 3.0.0-alpha-5010220260604001 '@dcloudio/uni-cli-shared': 3.0.0-alpha-5020220260725001(postcss@8.5.17)(rollup@4.62.2)(vue@3.4.21(typescript@5.9.3))
'@dcloudio/uni-shared': 3.0.0-alpha-5010220260604001 '@dcloudio/uni-nvue-styler': 3.0.0-alpha-5020220260725001
'@dcloudio/uni-shared': 3.0.0-alpha-5020220260725001
'@rollup/pluginutils': 5.1.0(rollup@4.62.2) '@rollup/pluginutils': 5.1.0(rollup@4.62.2)
'@vitejs/plugin-legacy': 5.3.2(terser@5.49.0)(vite@5.2.8(sass@1.101.0)(terser@5.49.0)) '@vitejs/plugin-legacy': 5.3.2(terser@5.49.0)(vite@5.2.8(sass@1.101.0)(terser@5.49.0))
'@vitejs/plugin-vue': 5.2.4(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3)) '@vitejs/plugin-vue': 5.2.4(vite@5.2.8(sass@1.101.0)(terser@5.49.0))(vue@3.4.21(typescript@5.9.3))
@@ -3656,6 +3486,7 @@ snapshots:
'@vue/shared': 3.4.21 '@vue/shared': 3.4.21
cac: 6.7.9 cac: 6.7.9
debug: 4.3.7 debug: 4.3.7
es-module-lexer: 1.5.4
estree-walker: 2.0.2 estree-walker: 2.0.2
express: 4.20.0 express: 4.20.0
fast-glob: 3.3.3 fast-glob: 3.3.3
@@ -3664,6 +3495,7 @@ snapshots:
jsonc-parser: 3.3.1 jsonc-parser: 3.3.1
magic-string: 0.30.11 magic-string: 0.30.11
picocolors: 1.1.0 picocolors: 1.1.0
source-map-js: 1.2.1
terser: 5.49.0 terser: 5.49.0
unplugin-auto-import: 19.1.0 unplugin-auto-import: 19.1.0
vite: 5.2.8(sass@1.101.0)(terser@5.49.0) vite: 5.2.8(sass@1.101.0)(terser@5.49.0)
+3 -2
View File
@@ -7,7 +7,7 @@ import { dirname, resolve } from 'node:path';
const mobileRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..'); const mobileRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const readJson = async (path) => JSON.parse(await readFile(new URL(path, import.meta.url), 'utf8')); const readJson = async (path) => JSON.parse(await readFile(new URL(path, import.meta.url), 'utf8'));
const hbuilderx515AppCompiler = '3.0.0-alpha-5010220260604001'; const hbuilderx522Compiler = '3.0.0-alpha-5020220260725001';
test('App 图标与启动图映射均可由预检脚本验证', () => { test('App 图标与启动图映射均可由预检脚本验证', () => {
const output = execFileSync(process.execPath, ['scripts/verify-app-assets.mjs'], { const output = execFileSync(process.execPath, ['scripts/verify-app-assets.mjs'], {
@@ -25,7 +25,8 @@ test('App 平台编译器已声明且与其他 uni 包同版本,避免 build:a
const appPlus = pkg.dependencies?.['@dcloudio/uni-app-plus']; const appPlus = pkg.dependencies?.['@dcloudio/uni-app-plus'];
assert.ok(appPlus, '缺少 @dcloudio/uni-app-plus,build:app 会静默产出 H5 空壳'); assert.ok(appPlus, '缺少 @dcloudio/uni-app-plus,build:app 会静默产出 H5 空壳');
assert.equal(appPlus, hbuilderx515AppCompiler, 'App 编译链必须与当前 HBuilderX 5.15 调试基座匹配'); assert.equal(appPlus, hbuilderx522Compiler, '编译链必须与当前 HBuilderX 5.22 调试基座匹配');
assert.equal(appPlus, pkg.dependencies['@dcloudio/uni-app']); assert.equal(appPlus, pkg.dependencies['@dcloudio/uni-app']);
assert.equal(appPlus, pkg.dependencies['@dcloudio/uni-h5']);
assert.equal(appPlus, pkg.devDependencies['@dcloudio/vite-plugin-uni']); assert.equal(appPlus, pkg.devDependencies['@dcloudio/vite-plugin-uni']);
}); });
+5 -1
View File
@@ -9,8 +9,12 @@ if [[ ! -d node_modules ]]; then
npm install --registry=https://registry.npmmirror.com npm install --registry=https://registry.npmmirror.com
fi fi
if [[ -n "${PORTLESS_URL:-}" && -n "${PORT:-}" ]]; then
exec npm run dev -- --host "${HOST:-127.0.0.1}" --port "$PORT" --strictPort
fi
if [[ "${PORTLESS:-1}" != "0" ]] && command -v portless >/dev/null 2>&1; then if [[ "${PORTLESS:-1}" != "0" ]] && command -v portless >/dev/null 2>&1; then
exec portless run --name wygj-admin --force bash -lc 'npm run dev -- --host "${HOST:-127.0.0.1}" --port "$PORT" --strictPort' exec portless run --name wygj-admin --force bash "$ROOT_DIR/scripts/dev-frontend.sh"
fi fi
if [[ "${PORTLESS:-1}" != "0" ]]; then if [[ "${PORTLESS:-1}" != "0" ]]; then
+1 -1
View File
@@ -238,7 +238,7 @@ trap cleanup INT TERM EXIT
if using_portless_backend; then if using_portless_backend; then
portless alias --remove wygj-api >/dev/null 2>&1 || true portless alias --remove wygj-api >/dev/null 2>&1 || true
portless run --name wygj-api --force ./scripts/dev-backend.sh & portless run --name wygj-api --force bash ./scripts/dev-backend.sh &
else else
./scripts/dev-backend.sh & ./scripts/dev-backend.sh &
fi fi
+4
View File
@@ -25,9 +25,13 @@ docker exec -i wygj-mysql mysql -uroot -proot --default-character-set=utf8mb4 ry
docker exec -i wygj-mysql mysql -uroot -proot --default-character-set=utf8mb4 ry-vue < "$ROOT_DIR/backend/script/sql/update/aihr_20260725_deepseek_v4_model_mysql8.sql" docker exec -i wygj-mysql mysql -uroot -proot --default-character-set=utf8mb4 ry-vue < "$ROOT_DIR/backend/script/sql/update/aihr_20260725_deepseek_v4_model_mysql8.sql"
docker exec -i wygj-mysql mysql -uroot -proot --default-character-set=utf8mb4 ry-vue < "$ROOT_DIR/backend/script/sql/aihr_practice_mysql8.sql" docker exec -i wygj-mysql mysql -uroot -proot --default-character-set=utf8mb4 ry-vue < "$ROOT_DIR/backend/script/sql/aihr_practice_mysql8.sql"
docker exec -i wygj-mysql mysql -uroot -proot --default-character-set=utf8mb4 ry-vue < "$ROOT_DIR/backend/script/sql/update/aihr_20260725_sop_answer_partial_evidence_prompt_mysql8.sql" docker exec -i wygj-mysql mysql -uroot -proot --default-character-set=utf8mb4 ry-vue < "$ROOT_DIR/backend/script/sql/update/aihr_20260725_sop_answer_partial_evidence_prompt_mysql8.sql"
docker exec -i wygj-mysql mysql -uroot -proot --default-character-set=utf8mb4 ry-vue < "$ROOT_DIR/backend/script/sql/update/aihr_20260717_learning_closure_mysql8.sql"
docker exec -i wygj-mysql mysql -uroot -proot --default-character-set=utf8mb4 ry-vue < "$ROOT_DIR/backend/script/sql/update/aihr_20260717_practice_five_position_catalog_mysql8.sql" docker exec -i wygj-mysql mysql -uroot -proot --default-character-set=utf8mb4 ry-vue < "$ROOT_DIR/backend/script/sql/update/aihr_20260717_practice_five_position_catalog_mysql8.sql"
docker exec -i wygj-mysql mysql -uroot -proot --default-character-set=utf8mb4 ry-vue < "$ROOT_DIR/backend/script/sql/update/aihr_20260723_practice_content_operations_mysql8.sql" docker exec -i wygj-mysql mysql -uroot -proot --default-character-set=utf8mb4 ry-vue < "$ROOT_DIR/backend/script/sql/update/aihr_20260723_practice_content_operations_mysql8.sql"
docker exec -i wygj-mysql mysql -uroot -proot --default-character-set=utf8mb4 ry-vue < "$ROOT_DIR/backend/script/sql/update/aihr_20260724_practice_growth_curriculum_mysql8.sql" docker exec -i wygj-mysql mysql -uroot -proot --default-character-set=utf8mb4 ry-vue < "$ROOT_DIR/backend/script/sql/update/aihr_20260724_practice_growth_curriculum_mysql8.sql"
docker exec -i wygj-mysql mysql -uroot -proot --default-character-set=utf8mb4 ry-vue < "$ROOT_DIR/backend/script/sql/update/aihr_20260717_web_ai_question_reward_mysql8.sql"
docker exec -i wygj-mysql mysql -uroot -proot --default-character-set=utf8mb4 ry-vue < "$ROOT_DIR/backend/script/sql/update/aihr_20260719_web_ai_database_secret_mysql8.sql"
docker exec -i wygj-mysql mysql -uroot -proot --default-character-set=utf8mb4 ry-vue < "$ROOT_DIR/backend/script/sql/update/aihr_20260719_web_search_qwen_mysql8.sql"
docker exec -i wygj-mysql mysql -uroot -proot --default-character-set=utf8mb4 ry-vue < "$ROOT_DIR/backend/script/sql/aihr_interview_result_mysql8.sql" docker exec -i wygj-mysql mysql -uroot -proot --default-character-set=utf8mb4 ry-vue < "$ROOT_DIR/backend/script/sql/aihr_interview_result_mysql8.sql"
docker exec -i wygj-mysql mysql -uroot -proot --default-character-set=utf8mb4 ry-vue < "$ROOT_DIR/backend/script/sql/aihr_org_snapshot_mysql8.sql" docker exec -i wygj-mysql mysql -uroot -proot --default-character-set=utf8mb4 ry-vue < "$ROOT_DIR/backend/script/sql/aihr_org_snapshot_mysql8.sql"
docker exec -i wygj-mysql mysql -uroot -proot --default-character-set=utf8mb4 ry-vue < "$ROOT_DIR/backend/script/sql/update/aihr_20260721_org_multi_project_membership_mysql8.sql" docker exec -i wygj-mysql mysql -uroot -proot --default-character-set=utf8mb4 ry-vue < "$ROOT_DIR/backend/script/sql/update/aihr_20260721_org_multi_project_membership_mysql8.sql"
+38 -1
View File
@@ -1,12 +1,35 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
RESET_SCRIPT="$ROOT_DIR/scripts/reset-dev-db.sh"
LEARNING_CLOSURE_MIGRATION="backend/script/sql/update/aihr_20260717_learning_closure_mysql8.sql"
PRACTICE_GROWTH_MIGRATION="backend/script/sql/update/aihr_20260724_practice_growth_curriculum_mysql8.sql"
WEB_AI_BASE_MIGRATION="backend/script/sql/update/aihr_20260717_web_ai_question_reward_mysql8.sql"
WEB_AI_SECRET_MIGRATION="backend/script/sql/update/aihr_20260719_web_ai_database_secret_mysql8.sql"
WEB_SEARCH_QWEN_MIGRATION="backend/script/sql/update/aihr_20260719_web_search_qwen_mysql8.sql"
learning_closure_line="$(grep -nF "$LEARNING_CLOSURE_MIGRATION" "$RESET_SCRIPT" | cut -d: -f1 || true)"
practice_growth_line="$(grep -nF "$PRACTICE_GROWTH_MIGRATION" "$RESET_SCRIPT" | cut -d: -f1 || true)"
if [[ -z "$learning_closure_line" || -z "$practice_growth_line" || "$learning_closure_line" -ge "$practice_growth_line" ]]; then
echo "FAIL: reset-dev-db.sh must apply learning closure before practice growth curriculum" >&2
exit 1
fi
web_ai_base_line="$(grep -nF "$WEB_AI_BASE_MIGRATION" "$RESET_SCRIPT" | cut -d: -f1 || true)"
web_ai_secret_line="$(grep -nF "$WEB_AI_SECRET_MIGRATION" "$RESET_SCRIPT" | cut -d: -f1 || true)"
web_search_qwen_line="$(grep -nF "$WEB_SEARCH_QWEN_MIGRATION" "$RESET_SCRIPT" | cut -d: -f1 || true)"
if [[ -z "$web_ai_base_line" || -z "$web_ai_secret_line" || -z "$web_search_qwen_line"
|| "$web_ai_base_line" -ge "$web_ai_secret_line" || "$web_ai_secret_line" -ge "$web_search_qwen_line" ]]; then
echo "FAIL: reset-dev-db.sh must apply the web AI base, secret, and Qwen migrations in order" >&2
exit 1
fi
if ! command -v docker >/dev/null || ! docker ps --format '{{.Names}}' | grep -qx 'wygj-mysql'; then if ! command -v docker >/dev/null || ! docker ps --format '{{.Names}}' | grep -qx 'wygj-mysql'; then
echo "SKIP: AIHR schema migration test requires wygj-mysql" echo "SKIP: AIHR schema migration test requires wygj-mysql"
exit 0 exit 0
fi fi
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
MYSQL_CONTAINER="wygj-mysql" MYSQL_CONTAINER="wygj-mysql"
DB="wygj_aihr_schema_test_$$" DB="wygj_aihr_schema_test_$$"
LEGACY_DB="wygj_aihr_candidate_legacy_test_$$" LEGACY_DB="wygj_aihr_candidate_legacy_test_$$"
@@ -31,6 +54,20 @@ trap cleanup EXIT
mysql -e "CREATE DATABASE \`$DB\` CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;" mysql -e "CREATE DATABASE \`$DB\` CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;"
web_ai_base_migration="$ROOT_DIR/$WEB_AI_BASE_MIGRATION"
web_ai_secret_migration="$ROOT_DIR/$WEB_AI_SECRET_MIGRATION"
web_search_qwen_migration="$ROOT_DIR/$WEB_SEARCH_QWEN_MIGRATION"
mysql "$DB" < "$web_ai_base_migration"
mysql "$DB" < "$web_ai_base_migration"
mysql "$DB" < "$web_ai_secret_migration"
mysql "$DB" < "$web_ai_secret_migration"
mysql "$DB" < "$web_search_qwen_migration"
mysql "$DB" < "$web_search_qwen_migration"
web_search_columns="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(column_name ORDER BY ordinal_position) FROM information_schema.columns WHERE table_schema='$DB' AND table_name='aihr_web_search_provider' AND column_name IN ('api_key','agent_id','agent_version','last_test_ok','last_test_time');")"
test "$web_search_columns" = 'api_key,agent_id,agent_version,last_test_ok,last_test_time'
web_ai_secret_count="$(mysql "$DB" -N -B -e "SELECT COUNT(*) FROM aihr_web_ai_secret WHERE config_key='provider-encryption-v1' AND CHAR_LENGTH(config_value) > 0;")"
test "$web_ai_secret_count" = '1'
mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260714_case_media_mysql8.sql" mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260714_case_media_mysql8.sql"
mysql "$DB" <<'SQL' mysql "$DB" <<'SQL'
CREATE TABLE aihr_case_record ( CREATE TABLE aihr_case_record (