From 73fd9d0975c2140afd940be690ae3c17238b07d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=85=E5=BF=B5?= Date: Sat, 8 Aug 2026 14:44:58 +0800 Subject: [PATCH] =?UTF-8?q?docs(spec):=20=E4=BF=AE=E6=AD=A3=20today=5Fcoun?= =?UTF-8?q?t=20=E6=97=B6=E5=8C=BA(=E9=92=89=E6=AD=BB=20UTC+8)=20+=20?= =?UTF-8?q?=E6=97=A5=E6=9C=9F=E9=80=89=E6=8B=A9=E5=99=A8=E6=8C=81=E4=B9=85?= =?UTF-8?q?=20ref=20=E6=BE=84=E6=B8=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude --- .../specs/2026-08-08-yunke-chat-sessions-design.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/superpowers/specs/2026-08-08-yunke-chat-sessions-design.md b/docs/superpowers/specs/2026-08-08-yunke-chat-sessions-design.md index 7c69f51..da15f27 100644 --- a/docs/superpowers/specs/2026-08-08-yunke-chat-sessions-design.md +++ b/docs/superpowers/specs/2026-08-08-yunke-chat-sessions-design.md @@ -37,7 +37,7 @@ - **query**:`owner_account_id`(必填)、`channel`(默认 `wechat`)。 - **好友会话**:`message WHERE channel=:ch AND owner_account_id=:owner AND (room_id IS NULL OR room_id='') AND timestamp IS NOT NULL` → `GROUP BY talker_id` → - `last_chat_time = max(timestamp)` - - `today_count = count(timestamp >= :today_start)`(`today_start` = 本地 0 点 ms-epoch) + - `today_count = count(timestamp >= :today_start)`(`today_start` = **Asia/Shanghai (UTC+8) 当日 0 点** ms-epoch —— 对齐云客中国时区;**不依赖服务器本地时区**,保证部署无关 + 测试确定性) - **群会话**:`... AND room_id IS NOT NULL AND room_id != ''` → `GROUP BY room_id` → 同两字段。 - **取昵称/头像**:left-join `customer`(好友:`friend_remark`/`friend_nickname`/`real_name`/`head_image_url`,优先级同 Phase A)+ `group`/`chat_group`(群:`room_name` + 头像 if any)。 - **响应**: @@ -52,7 +52,7 @@ } ``` 按 `last_chat_time` desc(NULL 最后)。 -- **今日边界**:`today_start = int(datetime.now().replace(00:00:00).timestamp()*1000)`(本地 0 点)。测试用 `time.time()` 播「当下」消息断言 `today_count>=1`、播「昨天」断言排除。 +- **今日边界**:`today_start` = Asia/Shanghai(UTC+8) 当日 0 点的 ms-epoch(用 `zoneinfo.ZoneInfo("Asia/Shanghai")` 构造当日 0 点 → timestamp,**不用** `datetime.now()` 的服务器本地时区)。测试用 `time.time()` 播「当下」消息断言 `today_count>=1`、播「昨天(UTC+8)」断言排除——因 today_start 固定 UTC+8,测试确定性。 - schema:`SessionOut`(`type: Literal['friend','group']`、`talker_id|room_id` 二选一可空、`name/avatar` 可空、`today_count: int`、`last_chat_time: int|None`)。 ## 4. 前端 @@ -89,7 +89,7 @@ 2. **后端+UI 一个 plan**(约 4 task)。 3. **架构 = ChatTimeline 双栏 + 新 ChatSidebar 子件**(侧栏常驻,同组件换会话,对齐云客;不做独立 ChatWindow 页以减少重构)。 4. **会话列表全时段**(today_count + last_chat_time,不受日期选择器影响);**日期选择器只过滤消息流**。 -5. **日期选择器默认近 2 周**(对齐云客聊天页默认 ~2 周);stat modal 带 query 入口 → 初值取 query。 +5. **日期选择器 = ChatTimeline 本地 ref(跨会话持久,默认近 2 周对齐云客聊天页)**:会话切换(同组件、路由 param 变)时选择器**不重置**,消息流按持久窗 + 新会话重查;**无需**在点会话时传 query。仅 stat-modal 带 query 入口时,选择器 mount 初值取 query;badge 账号级入口取默认(近 2 周)。 6. **不做未读数/最后消息预览**(云客会话列表无此字段)。 ## 6. 文件清单(预期) @@ -120,7 +120,7 @@ ## 8. 风险 -- **今日计数确定性**:依赖「本地 0 点」+ 服务器时钟;测试用 `time.time()` 播当日 + 昨日消息对比(plan 落实)。 +- **今日计数确定性**:today_start 钉死 Asia/Shanghai(UTC+8) 当日 0 点(不依赖服务器时区);测试用 `time.time()` 播「当下(UTC+8 今日)」+「昨日(UTC+8)」消息对比,确定性。 - **群头像/群名缺失**:smoke.db 群数据稀疏(Plan 3 已知 gap);缺失显 `--`/默认头像,不阻塞。 - **ChatTimeline 重构面**:从「路由驱动单会话」→「双栏 + 本地窗 ref」,需保持向后兼容(深链/stat modal 入口)。plan 分小 task、每步 vue-tsc + 浏览器验。 - **关键词搜索后端能力**:`/api/messages` 是否支持 `q` 待 plan 核实;不支持则前端过滤当前页(声明近似)。