Commit Graph
204 Commits
Author SHA1 Message Date
key 5027bef32d fix(mobile): support Android system file picker 2026-07-29 23:52:44 +08:00
key 6ba7df863f chore: add UI audits and reconcile release docs 2026-07-29 16:10:46 +08:00
key 70e5516ff3 fix(release): close fixed-code mobile auth gaps 2026-07-29 11:59:30 +08:00
key b9e0878926 fix(android): share public legal URLs with cloud builds 2026-07-29 10:07:22 +08:00
key 7f3357c7a1 fix(android): use login consent instead of native privacy prompt 2026-07-29 09:59:41 +08:00
key dc20b92061 fix(mobile): recover direct channels after network failure 2026-07-29 02:31:19 +08:00
key cb928edafd fix(mobile): handle file picker cancellation 2026-07-29 02:01:45 +08:00
key ba68fc8326 release: harden Android network security 2026-07-29 01:13:18 +08:00
key 9ea5d79a62 release: prepare August 1 Android RC 2026-07-29 00:35:15 +08:00
key 9ae5f750c8 fix: align Windows dev, App compiler, and ASR 2026-07-26 21:27:37 +08:00
admin f57e0a53c6 feat(mobile): expand TTS voices and align App SDK 2026-07-26 17:05:43 +08:00
admin 94ee29f59c fix(speech): write native TTS temp file as binary and clean it up
App-Plus 的 plus.io FileWriter 只接受字符串:write 写文本,writeAsBinary 收
base64。原先传 Blob 会被原生桥接序列化成空内容,落地 0 字节且照样回调
onwriteend,InnerAudioContext 静默播完、不报错,表现为"界面正常但没有声音"。
改用 writeAsBinary 并在 onwriteend 里复核 size > 0,让写盘失败能被暴露。

清理侧同一处存在文件泄漏:播放要 convertLocalFileSystemURL 转出的 file://
绝对路径,而 resolveLocalFileSystemURL 删除只认 `_doc/xxx.mp3` 相对路径。
原先只回传前者,拿它去 resolve 解析不到,remove() 从不执行,且 catch 静默,
临时 mp3 逐句堆积。改为返回 { playbackUrl, plusPath } 两个路径,清理失败加告警。

真机验证(Android 10 / io.dcloud.HBuilder):落盘 80251 字节,ID3+LAME 头,
MPEG layer III 160 kbps 24 kHz 单声道,播完文件自动删除。

顺带把测试里 MP3 头字面量的真实 NUL 字节改为 \x00 转义(运行时字节不变),
此前 git 将该测试文件判为二进制,diff 无法审阅。
2026-07-26 12:10:50 +08:00
adminandClaude Opus 5 d84ad87cb6 fix(sop): restore voice-first replies on App without withholding text
73712994 disabled voice-first on native by gating the TTS preload behind
!isNativeAppRuntime(), which left App users with the degraded text bubble
plus a 播报 button. The voice-line, 转文字 toggle and 收起全文 markup were
still present but unreachable.

Re-enable the preload on every platform and open the transcript when the
message is created, so the answer is readable while synthesis runs.

Collapse the transcript when playback starts rather than when synthesis
finishes: on-device synthesis settles in 2-6s, so collapsing on ready
pulled the answer away mid-sentence. transcriptPinned records a manual
toggle so the automatic collapse never overrides the reader.

Bound the preparing bubble at 20s (the upstream DashScope ceiling) so a
stalled synthesis degrades to the plain text bubble instead of showing an
endless placeholder duration.

Replace the tautological assertion that pinned the previous behaviour by
matching source strings with assertions on the behaviour itself.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 02:36:14 +08:00
adminandClaude Opus 5 7096545e82 fix(mobile): translate microphone errors and pre-request permission
实时陪练失败时,getUserMedia 抛出的 Chromium 英文原文会直接透给用户(真机实测见过
"Could not start audio source"),既不可读也不含任何可执行指引。新增
utils/microphone.ts 把权限、设备占用、无设备、非安全上下文四类底层错误翻译成中文
引导;业务层自己抛的中文文案原样透出,未识别的错误回落到原有通用提示。

同时在建会话之前主动申请 RECORD_AUDIO,并在 manifest 显式声明该权限。

需要说明:此权限预申请是防御性的。真机核查 RECORD_AUDIO 已授予、APK 本就声明该权限、
实时链路可正常跑通,先前那次 "Could not start audio source" 是麦克风被其他应用占用
的瞬时故障,不是权限缺陷。未在"权限未授予"的设备上实测过 WebView 是否会自行弹出
Android 运行时授权框,故此调用在已授权设备上为无害空转;若确实不弹,则它是唯一授权入口。
manifest 声明同样只为防未来模块调整导致权限丢失。

新增 6 项单测覆盖错误映射与授权分支(共 168 项通过)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 00:58:40 +08:00
adminandClaude Opus 5 788a2abbe4 fix(mobile): avoid status bar overlap on custom-nav pages
全局 navigationStyle 为 custom,页面需自行避让状态栏,但四处顶部内容仍被状态栏
压住:练习页标题与对话页标题、我的页顶部卡片、问答页头部。

避让不能走 CSS:env(safe-area-inset-top) 在 Android WebView 恒为 0(该值本是
iOS 刘海概念,Chromium 仅在配置 display-cutout 时才上报),uni-app 注入的
--status-bar-height 实测在 App 端同样取不到,两者都会静默回落成 0,造成"构建产物
里改动存在但运行时无效"。改由 utils/safe-area.ts 读
uni.getSystemInfoSync().statusBarHeight,各页面以内联样式绑定 padding-top。

profile 页同时把 min-height 从 100vh 改为 100%:叠加状态栏内边距后 100vh 会
溢出一屏高度产生多余滚动。

真机(vivo V2443A,720x1600,状态栏 72px)像素验证:修复前状态栏下缘 60-80px 带内
有 872 个文字像素,修复后四处均为 0。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 00:58:18 +08:00
adminandClaude Opus 5 4fc0c1f5f8 chore(mobile): bump App version to 0.1.5 (versionCode 105)
Covers the App-Plus batch in this series: renderjs realtime practice, request
timeout abort, App-Plus date/query API replacements, and on-demand native
voice. Native permissions and plugins are unchanged, so this ships as a normal
cloud rebuild.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 23:59:05 +08:00
adminandClaude Opus 5 73712994c6 fix(mobile): stop preloading answer TTS on native App
On native App the eager TTS request delayed the answer bubble: the message was
created in `preparing` state, so the text stayed behind a voice line that was
still waiting on a round trip.

Skip the preload when `isNativeAppRuntime()`, marking the voice `unavailable`
so the text and citations render immediately. The existing `unavailable`
branch already exposes a play button that calls `toggleAnswerSpeech`, so voice
stays reachable on demand instead of being dropped. H5 keeps preloading.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 23:58:19 +08:00
adminandClaude Opus 5 5cf7ce5847 feat(practice): run realtime practice on App-Plus through renderjs
App-Plus has no WebRTC or getUserMedia in the logic layer, so realtime
practice was H5-only and the native entry had to advertise a record-then-
transcribe downgrade.

Move the media/WebRTC engine into `realtime-browser-engine.js` and drive it
from `RealtimePracticeAppBridge.vue`, whose renderjs script runs inside the
system WebView where those APIs do exist. The logic layer keeps the
authenticated calls: SDP exchange and `search_knowledge` tool invocation stay
server-proxied, so the access token is never handed to the view layer. Both
sides talk over the renderjs bridge only in session payloads the server
already assembled.

Verified against a real App build (`app-renderjs.js` holds RTCPeerConnection
and getUserMedia; `app-service.js` holds the SDP endpoint, renderjs side has
zero hits). Microphone permission, live transcription, remote playback,
foreground/background switching and disconnect fallback still require Android
and iOS device verification.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 23:58:10 +08:00
adminandClaude Opus 5 3055d2bec9 fix(mobile): replace App-Plus unsupported date and query APIs
`URLSearchParams` is absent from the App-Plus JS core, and
`toLocaleDateString('sv-SE', { timeZone: 'Asia/Shanghai' })` depends on full
ICU data that the App runtime does not ship, so the work-result pages built
either a broken query string or the device-local date.

Build query strings with `encodeURIComponent`, and centralise the business day
in `currentShanghaiDate()`, which shifts the epoch by a fixed UTC+8 offset
before slicing the ISO date. Asia/Shanghai has no DST, so the fixed offset is
exact rather than an approximation.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 23:57:06 +08:00
adminandClaude Opus 5 27f4cdac70 fix(mobile): abort uni.request when the platform timeout does not fire
Some uni-app platforms ignore the `timeout` option, leaving the returned
promise pending forever and hanging the calling page with no error path.

Drive the deadline locally: keep a single-shot `finish` guard so success,
failure and timeout can only settle once, and on timeout call `task.abort()`
before rejecting so the in-flight request is released instead of leaking.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 23:56:56 +08:00
adminandClaude Opus 5 a3a5cf944e build(mobile): declare App platform compiler to stop build:app false green
`@dcloudio/uni-app-plus` was never declared, so `uni build -p app` silently
fell back to an H5 shell: exit code 0, `DONE Build complete.`, but the output
was only `index.html` (still carrying the `/h5/assets/...` base path) with no
`app-service.js`, `app-renderjs.js` or `manifest.json`. Because
`docs/MOBILE_APP_PACKAGING.md` lists that command as a local verification
step, App platform code was reported as built without ever reaching the App
compiler.

Declare the compiler at the same version as the other `@dcloudio` packages,
guard the version alignment in `tests/app-packaging.test.mjs`, and document
that success is judged by the emitted artifacts, not by the DONE line.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 23:56:47 +08:00
admin ab3af277c1 fix(speech): convert base64 TTS data URI before playback per platform
后端 TTS 以 data: URI 返回 base64 mp3(生产实证为合法 LAME mp3),但
App-Plus 的 InnerAudioContext 不支持 data: URI,iOS Safari/微信 webview
也常静默失败,统一报"语音播放失败"。播放前按平台转换:H5 转 Blob URL,
App 端经 plus.io 落 _doc/ 临时文件后播放 file:// 路径,播完清理;Blob 不可
用时退回原始 data: URI。竞态守卫与缓存语义保持不变,158 单测全绿。
2026-07-25 20:37:30 +08:00
admin bb8b2dde7e fix(exam): replace unfounded 4-char title rule with explicit validation messages
- 考试名称仅要求非空,移除无依据的至少 4 字限制;保留及格分 1-100、
  至少一题、总分 100、题干/选项/答案完整、至少一名员工的发布校验
- 发布坞展示具体校验失败原因,不再静默禁用按钮
- CHANGELOG/README 同步 2026-07-25 组织姓名定向补齐与生产复核记录
2026-07-25 18:15:32 +08:00
admin acd5fd3a6d fix(practice): generate replies from coach hints 2026-07-25 15:44:45 +08:00
admin 230dfb4dfc feat(broadcast): finish multi-role insight experience 2026-07-25 15:18:58 +08:00
admin 2b3c37677d fix(mobile): prioritize practice actions above guidance 2026-07-25 13:17:32 +08:00
admin fa9d6da975 feat(practice): streamline pilot content operations 2026-07-25 12:51:39 +08:00
admin 35b37b07f7 feat(practice): server-owned realtime personas with knowledge tool calling
- AihrRealtimePersonaRegistry whitelist: owner-calm (default), owner-impatient,
  digital-mentor (search_knowledge); persona binds default voice
- /realtime/session assembles session.update server-side (instructions/tools);
  browser forwards payload verbatim; Redis session record 30min with sliding renewal
- /realtime/tools/invoke validates login identity + Redis session ownership +
  persona tool whitelist, then read-only searchAuthorized; per-account rate limits
- source=realtime skips sop review and knowledge-gap persistence (Beta no-persist)
- frontend: persona cards replace 56-voice picker; serialized tool-call chain with
  soft-landing fallback
2026-07-25 11:13:04 +08:00
admin 3a19b475a8 feat(mobile): add voice-to-text input to direct feedback page
- 反馈内容 label 行新增语音 chip:toggle 录音(启动/录音计时/结束中/转写
  四态),转写结果以换行追加,JS 侧截断至 5000 字上限并提示
- 复用既有 services/speech.ts + /api/ai/asr 链路;表单页文字为主路径,
  录音不可用或权限失败仅提示改文字输入,不做选文件降级
- voiceStopping 状态修复 stop→onCapture 竞态(重复点按不再丢录音)
- onHide/onUnload 统一 teardownVoice:generation++、abort 转写、
  cancel 录音、停计时,切页无迟来写回
- 渠道按钮加图标(vip/wallet/staff/eye/gear),匿名行与空历史态补图标
- 测试改用函数体提取断言,覆盖清理/竞态/截断/模板契约;150/150
  单测、vue-tsc、H5 构建通过,mock API 浏览器验证通过

已经过 Codex 审查
2026-07-25 03:00:30 +08:00
admin f545983de8 fix(knowledge): bind summary cards to cited evidence 2026-07-25 01:45:41 +08:00
admin 4d2b3828c0 feat(brand): rename product to 帮道 2026-07-25 01:09:49 +08:00
admin c9d2012ec1 feat(aihr): finalize practice growth and access boundaries 2026-07-25 00:42:19 +08:00
admin f6ffafda30 fix(mobile): type direct feedback switch event 2026-07-25 00:16:56 +08:00
admin 09278d40c6 merge: integrate broadcast question correction
# Conflicts:
#	docs/BRD_PRODUCTION_MIGRATION_RUNBOOK.md
2026-07-25 00:13:49 +08:00
admin 5f8d8f96f0 fix(agent): preserve broadcast consultation context 2026-07-25 00:12:53 +08:00
admin 342f84a9de feat(aihr): complete company message R1-R3 2026-07-24 23:25:15 +08:00
admin 5b7c5613f5 feat(agent): move mobile ask to unified agent 2026-07-24 22:36:14 +08:00
admin 743d629dc8 fix(knowledge): use native file downloads in app 2026-07-24 14:52:07 +08:00
admin 442ba66848 fix(knowledge): make protected file downloads WebView-safe 2026-07-24 13:31:30 +08:00
admin 474d46e728 feat(speech): add qwen tts voice preferences 2026-07-24 01:54:37 +08:00
admin faa2a77e9a feat(practice): complete five-position training operations 2026-07-24 00:26:27 +08:00
admin 067cc30d80 feat(aihr): complete M3 protected practice replay 2026-07-23 22:21:43 +08:00
admin 83f775faec fix(mobile): stack extra-large schedule actions 2026-07-23 22:18:44 +08:00
admin dfaa198ac8 chore(mobile-app): align native build metadata 2026-07-23 21:18:51 +08:00
admin 927458b9e0 feat(aihr): harden M0-M2 mobile training flows 2026-07-23 21:18:13 +08:00
admin 0f5c2e8667 feat(mobile-app): prepare native app packaging 2026-07-23 14:40:23 +08:00
admin f6609808df feat(aihr): add M1 broadcast targeting and mandatory reads 2026-07-23 12:11:41 +08:00
admin cd94f4fe9f test: add M1 broadcast acceptance reproducers 2026-07-23 11:27:53 +08:00
admin 4b31848e3d fix(aihr): harden broadcast and mobile assistant flows 2026-07-23 03:35:36 +08:00
admin 62c8b41672 feat(mobile-uni): 重构“我”(个人中心)为原生App沉浸式卡片看板,禁用Emoji全面采用uni-icons矢量图标 2026-07-23 02:20:10 +08:00