From 026381f6e6c668adad48ba287a50bdca3150638a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=85=E5=BF=B5?= Date: Tue, 25 Aug 2026 17:42:43 +0800 Subject: [PATCH] =?UTF-8?q?fix(staffchat):=20=E6=90=9C=E7=B4=A2=E8=81=9A?= =?UTF-8?q?=E5=90=88=E5=8F=96=E6=9C=80=E6=96=B0=E5=91=BD=E4=B8=AD(ASC?= =?UTF-8?q?=E9=A1=B51=E9=99=B7=E9=98=B1)+tab=E5=88=87=E6=8D=A2=E4=B8=8D?= =?UTF-8?q?=E6=B8=85=E6=90=9C=E7=B4=A2=E7=BB=93=E6=9E=9C+is=5Fsend?= =?UTF-8?q?=E5=AE=88=E5=8D=AB=E5=85=9C=E5=BA=95=E5=90=8D+=E6=88=AA?= =?UTF-8?q?=E6=96=AD=E6=8F=90=E7=A4=BA+TAB=5FKEYS=E5=8D=95=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude --- .../src/components/staffchat/SessionPane.vue | 51 +++++++++++++++---- .../components/staffchat/StaffChatSide.vue | 2 + yunkes/src/views/StaffChat.vue | 6 +-- 3 files changed, 47 insertions(+), 12 deletions(-) diff --git a/yunkes/src/components/staffchat/SessionPane.vue b/yunkes/src/components/staffchat/SessionPane.vue index 4f4091a..0fb5303 100644 --- a/yunkes/src/components/staffchat/SessionPane.vue +++ b/yunkes/src/components/staffchat/SessionPane.vue @@ -29,11 +29,21 @@ const errorMsg = ref(null) const pinnedOpen = ref(true) /** search 模式聚合结果(q 命中的消息按会话去重,取首条作为该会话快照)。 */ const searchResults = ref([]) +/** 搜索命中总数与截断标记(后端单页上限 100,超出时只聚合已取回条内的会话)。 */ +const searchTotal = ref(0) +const searchTruncated = ref(false) + +/** 清搜索态: 结果与截断提示一起清,不残留上次的统计。 */ +function clearSearch() { + searchResults.value = [] + searchTotal.value = 0 + searchTruncated.value = false +} async function load() { loading.value = true errorMsg.value = null - searchResults.value = [] + clearSearch() try { const res = await getSessions({ owner_account_id: props.ownerId, @@ -48,16 +58,21 @@ async function load() { loading.value = false } } -watch(() => [props.ownerId, props.kind, friendTab.value] as const, load, { immediate: true }) +watch(() => [props.ownerId, props.kind] as const, load, { immediate: true }) +/** 好友/已删 tab 只过滤 list 会话列表(is_del);search 模式的消息搜索与 is_del + 无关——切 tab 不重载、不清关键词/结果(搜索跨 tab 保持有效)。 */ +watch(friendTab, () => { + if (mode.value === 'list') load() +}) /** 切模式清关键词与旧结果,避免 list 过滤词被误当搜索词。 */ watch(mode, () => { keyword.value = '' - searchResults.value = [] + clearSearch() }) /** search 模式清空关键词 → 回到未搜索态(不残留上次聚合结果)。 */ watch(keyword, (k) => { - if (mode.value === 'search' && !k.trim()) searchResults.value = [] + if (mode.value === 'search' && !k.trim()) clearSearch() }) /** 置顶区: 仅 单聊+未删好友+list 模式(后端 pinned 目前只有 filehelper)。 */ @@ -106,7 +121,7 @@ function sessionKey(s: ChatSession): string { async function runSearch() { const k = keyword.value.trim() if (mode.value !== 'search' || !k) { - searchResults.value = [] + clearSearch() return } loading.value = true @@ -119,10 +134,14 @@ async function runSearch() { page: 1, page_size: 100, }) + searchTotal.value = res.total + searchTruncated.value = res.total > res.items.length // 已加载的会话列表提供昵称/头像;未命中(search 只回消息)再以 sender_name/键兜底 const known = new Map(sessions.value.map(s => [sessionKey(s), s])) const seen = new Map() - for (const m of res.items) { + // 陷阱: 后端 /messages 按 timestamp ASC 排序,page 1 取回的是最旧的 100 条命中。 + // 倒序遍历(新→旧)+ 首见即取,保证每个会话的快照时间 = 已取回命中里最新的那条。 + for (const m of [...res.items].reverse()) { const key = m.room_id ?? m.talker_id ?? '' if (!key || seen.has(key)) continue const hit = known.get(key) @@ -131,7 +150,8 @@ async function runSearch() { type: m.room_id ? 'group' : 'friend', talker_id: m.room_id ? undefined : m.talker_id ?? undefined, room_id: m.room_id ?? undefined, - name: hit?.name ?? m.sender_name ?? key, + // is_send=true 时 sender_name 是员工自己,不能当卡片标题 + name: hit?.name ?? (!m.is_send ? m.sender_name : key), avatar: hit?.avatar ?? undefined, today_count: 0, last_chat_time: m.timestamp ?? null, @@ -142,7 +162,7 @@ async function runSearch() { ) } catch (e) { errorMsg.value = (e as Error).message - searchResults.value = [] + clearSearch() } finally { loading.value = false } @@ -212,6 +232,11 @@ async function runSearch() { + +
+ 共 {{ searchTotal }} 条命中,仅聚合最旧 100 条内的会话 +
+
{{ emptyText }}
n.key)