Files
yunke/docs/superpowers/specs/2026-08-08-yunke-export-chat-html-design.md
T

6.2 KiB
Raw Blame History

导出会话聊天为 HTML(③,前端接线)设计

日期:2026-08-08|分支:feat/yunke-data-mirror|路线图 ③ 前置(已就绪):后端 GET /api/export/chat-html(app/api/routers/export.py)已实现、已注册、有测试——按 (channel, owner_account_id, talker_id|room_id, start?, end?) 拉消息 → 渲染自包含 HTML 气泡页(is_send 左右、带时间/文本)→ text/html attachment 下载。 数据/交互:全本地(运行时不碰云客)。云客「导出聊天记录」2026-08-08 真机核实:异步任务 → 下载中心(POST /wechatweb/msg/exportChatData2Html,参数 startdate/enddate/wechatId/friendId)。 用户决策(2026-08-08):按我们的内部逻辑做——不复刻云客的异步下载中心;HTML 渲染沿用已有 export.py(即"我们的逻辑")。

1. 目标与范围

目标:在 3 处加「导出」入口,触发已有的 /api/export/chat-html,让用户把一段会话(员工×客户/群,可带日期窗)下载成 HTML 文件。

在本 plan(纯前端,后端不动):

  1. ChatTimeline 头部「导出」按钮:用当前会话(channel/owner/talkerId 或 roomId)+ 当前 dateRange(start/end)→ 下载该窗内聊天 HTML。仅在 hasActive 时可用。
  2. CustomerList 操作列「导出HTML」(在「查看聊天记录」旁):该 owner×friend_id,全量消息(列表无日期选择器)。
  3. GroupList 操作列「导出HTML」:该 owner×room_id,全量消息。

机制(我们的内部逻辑):直接浏览器下载——构造 /api/export/chat-html?... URL,window.open(url, '_blank') 触发后端返回的 attachment 下载。同步、无下载中心(本地小工具;后端 attachment Content-Disposition 强制下载)。

不在本 plan:

  • 云客的异步任务 / 下载中心(不需要)。
  • 导出多个会话 / 批量导出(云客也是单个会话导出)。
  • HTML 排版改版(沿用 export.py 现有渲染)。
  • 媒体字节内嵌(HTML 里媒体保持链接,不内嵌;export.py 现状)。

2. 后端契约(已就绪,引用)

GET /api/export/chat-html:

  • query:channel(wechat/whatsapp)、owner_account_id(必填)、talker_id?、room_id?(二选一)、start?、end?(ms-epoch,可省=全量)。
  • 返回:text/html; charset=utf-8,Content-Disposition: attachment; filename="chat-...html"。
  • 逻辑:DM 限定 room_id 空;按 timestamp asc;渲染气泡(is_send 右、否则左)。
  • 本 plan 不改后端。

3. 前端

3.1 共用 URL 构造(yunkes/src/api/index.ts)

/** 构造 /api/export/chat-html 下载 URL(浏览器直接下载,不走 getJson)。 */
export function exportChatUrl(params: {
  channel: Channel
  owner_account_id: string
  talker_id?: string
  room_id?: string
  start?: number
  end?: number
}): string {
  const q = clean({
    channel: params.channel,
    owner_account_id: params.owner_account_id,
    talker_id: params.talker_id,
    room_id: params.room_id,
    start: params.start,
    end: params.end,
  })
  const usp = new URLSearchParams(q as Record<string, string>)
  return `/api/export/chat-html?${usp.toString()}`
}

触发下载:window.open(exportChatUrl({...}), '_blank')(attachment 强制下载;本地 viewer 无 api_token,window.open 可达)。

3.2 ChatTimeline.vue

  • 头部 .yk-chat__filters 区(step 5 已建,含日期选择器/搜索)加「导出」el-button:v-if="hasActive",@click → window.open(exportChatUrl({channel: channelTyped, owner_account_id: props.ownerId, talker_id: props.talkerId, room_id: props.roomId, start: winStart, end: winEnd}))。
  • 即「导出当前会话在当前日期窗内的聊天」。

3.3 CustomerList.vue(操作列)

  • 在「查看聊天记录」按钮旁加 <el-button link>导出HTML</el-button>(wechat + WA 两 tab 的操作列)→ window.open(exportChatUrl({channel: row.channel, owner_account_id: row.owner_account_id, talker_id: row.friend_id}))(全量,无 start/end)。
  • plan 核实两 tab 操作列结构(Plan 2 已建「查看聊天记录」→ chat)。

3.4 GroupList.vue(操作列)

  • 在「查看聊天记录」旁加「导出HTML」→ exportChatUrl({channel: row.channel, owner_account_id: row.owner_account_id, room_id: row.room_id})(全量)。

4. 关键决策(已与用户确认 2026-08-08)

  1. 后端已就绪(export.py),③ = 纯前端 3 处按钮接线。
  2. 同步直接下载(window.open + attachment),不做云客异步下载中心。
  3. HTML 渲染沿用 export.py(我们的内部逻辑,不改)。
  4. ChatTimeline 导出带 dateRange;CustomerList/GroupList 导出全量(列表无日期选择器)。
  5. 媒体保持链接(export.py 现状)。

5. 文件清单

  • 改 yunkes/src/api/index.ts(exportChatUrl helper)。
  • 改 yunkes/src/views/ChatTimeline.vue(头部「导出」按钮)。
  • 改 yunkes/src/views/CustomerList.vue(操作列「导出HTML」)。
  • 改 yunkes/src/views/GroupList.vue(操作列「导出HTML」)。
  • 无后端改动;export.py 不动。

6. 验收

  • vue-tsc -b exit 0。
  • 浏览器实测(本地 smoke.db,无云客):
    • ChatTimeline:进一个会话 → 「导出」→ 下载 chat-wechat-{owner}-{talker}.html,打开含该窗内消息气泡(员工右/客户左、时间、文本);改 dateRange 再导出 → 内容随窗变。
    • CustomerList/GroupList:操作列「导出HTML」→ 下载该 owner×friend/room 的全量聊天 HTML。
    • network:仅打 /api/export/chat-html(无云客)。

7. 风险

  • window.open 被拦截:用户手势触发(button click)一般不拦;若拦可降级为隐藏 <a download> + click()。
  • api_token 鉴权:本地 viewer 默认无 token(require_auth no-op)→ window.open 可达;若启用 token 需改 fetch+blob(本 plan 不涉及,记录)。
  • 大对话导出耗时:同步生成;超大对话可能慢,可接受(本地工具);后续必要时再异步。
  • CustomerList/GroupList 操作列结构:plan 核实两 tab(wechat/WA)操作列「查看聊天记录」位置,照旁加按钮。