From d3fd0a54250c669feb315c0097986972cd73784e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=85=E5=BF=B5?= Date: Fri, 7 Aug 2026 15:55:12 +0800 Subject: [PATCH] =?UTF-8?q?docs(spec):=20=E5=BD=95=E9=9F=B3=E6=9C=AC?= =?UTF-8?q?=E5=9C=B0=E5=8C=96=20spec=E2=80=94=E2=80=94drawer=20=E6=92=AD?= =?UTF-8?q?=E6=94=BE=E4=B9=9F=E5=88=87=E6=9C=AC=E5=9C=B0=20+=20media=20URL?= =?UTF-8?q?=20=E7=BA=A6=E5=AE=9A=20+=20sync=20=E5=89=8D=E6=8F=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 用户 review:把详情 drawer 录音播放纳入本地化范围(一致性+全本地); 补 media URL 前缀对齐现有渲染、sync pass 须实跑的运维前提。 Co-Authored-By: Claude --- .../2026-08-07-yunke-recording-localization-design.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/superpowers/specs/2026-08-07-yunke-recording-localization-design.md b/docs/superpowers/specs/2026-08-07-yunke-recording-localization-design.md index 8e94d58..964dbed 100644 --- a/docs/superpowers/specs/2026-08-07-yunke-recording-localization-design.md +++ b/docs/superpowers/specs/2026-08-07-yunke-recording-localization-design.md @@ -23,7 +23,7 @@ - `download_call_recordings`:遍历本地 `record_file` 非空、`record_media_hash` 为空的 phone_call,下载→去重存储→`upsert_media`→回写 hash。幂等 + resilient。 - `sync_call_recordings` + scheduler `ENTITY_FUNCS['call_recordings']` + CLI `sync --entity call_recordings`(独立 sync pass)。 - `PhoneCallOut` / 前端 `PhoneCall` 类型加 `record_media_hash`。 -- CallList `playRecord`:**本地优先(`/api/media/{hash}`),OSS 回退(`record_file`)**。 +- CallList `playRecord` + **详情 drawer 录音**:**本地优先(`/api/media/{record_media_hash}`),OSS 回退(`record_file`)**。 **不在本 plan(后续)**: - 聊天语音消息(message `type=voice`)本地化 —— 复用同机制,另 plan。 @@ -85,7 +85,8 @@ const file = localSrc ?? cell(row,'recordFile')?.toString() ?? row.record_file - **本地优先**:有 `record_media_hash` → `/api/media/{hash}`(本地)。 - **OSS 回退**:否则用 `record_file`(过渡期未下载完仍可播,碰云客 CDN;sync 跑完即全本地)。 - 录音按钮 v-if:`row.record_media_hash || row.record_file || cell(row,'recordFile')`(任一存在即显示,未下载的也能播)。 -- drawer / 其它读 `record_file` 处不变(OSS URL 仍作元数据展示);播放源切本地。 +- **详情 drawer 录音也切本地**:`callFields.ts::toDisplayField`/`buildCallSections` 构建 recordFile 的 audio 字段时,若 `call.record_media_hash` 存在则 value 用 `/api/media/{hash}`,否则原 OSS URL(`readField('recordFile')`/`record_file`);`record_file` 文本字段仍作元数据展示。 +- **media URL 前缀**:`/api/media/{hash}` 必须与现有聊天媒体渲染(MessageBubble 等)的 URL 构造一致(是否带 `VITE_API_BASE` 前缀)——plan 时确认并复用同一 helper,避免本地播放 404。 ## 8. 关键决策(已与用户确认 2026-08-07) @@ -98,6 +99,7 @@ const file = localSrc ?? cell(row,'recordFile')?.toString() ?? row.record_file ## 9. 风险 - **下载量/存储**:~1261+ mp3(voice_call 1159 + wa_voice_call 102,按当前 smoke.db;phone_call 0)。sha256 去重;MEDIA_DIR 可配(.env `MEDIA_DIR`)。GB 级可接受。 +- **全本地依赖 sync 实跑**:本 plan 的「全本地」只有 `call_recordings` sync pass **实际跑完**才达成(否则停留 OSS 回退)。须确保该 pass 可被触发(进默认调度 或 手跑 `sync --entity call_recordings`);批量串行下载 1261 条可能 20-60min,并发下载留后续优化(注意 OSS 限流);磁盘需有 GB 级余量。 - **过渡期 OSS 回退**碰云客 CDN(已知妥协,sync 完成后消失)。 - OSS URL 公开稳定(已实测),不依赖云客登录态 → 不会因 cookie 过期失效。 @@ -114,6 +116,8 @@ const file = localSrc ?? cell(row,'recordFile')?.toString() ?? row.record_file **前端**: - 改 `yunkes/src/api/types.ts`:`PhoneCall.record_media_hash` - 改 `yunkes/src/views/CallList.vue`:`playRecord` 本地优先 + 录音按钮 v-if +- 改 `yunkes/src/utils/callFields.ts`:recordFile audio 字段本地优先(drawer 录音播放切本地) +- (plan 时确认)现有 media URL 构造 helper(MessageBubble 等),复用其前缀 ## 11. 验收