feat(staff): 微信 5 数字 modal 换本地数据源(metric 过滤 + 合成分页)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
浅念
2026-08-07 18:52:07 +08:00
parent cab8ab95dc
commit f51623d652
+42 -3
View File
@@ -3,7 +3,7 @@ import { computed, onMounted, reactive, ref } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { getAccounts, getCustomers, getMessages, getStaffChatStats } from '@/api'
import type { Account, Channel, StaffChatStats } from '@/api/types'
import type { Account, Channel, Page, StaffChatCustomer, StaffChatStats } from '@/api/types'
import YkStaffDetailModal from '@/components/YkStaffDetailModal.vue'
import { useChannelStore } from '@/stores/channel'
import { channelLabel, formatTime } from '@/utils/format'
@@ -347,11 +347,50 @@ function commModalColsFor(metric: ChatMetric): any[] {
}
return cols
}
/** 按 metric 过滤客户明细(口径见 spec §4;last_is_send 为 null 时既非最后回复也非未回复)。 */
function metricFilter(c: StaffChatCustomer, m: ChatMetric): boolean {
switch (m) {
case 'chat':
return true
case 'effective':
return c.send_count >= 1 && c.receive_count >= 1
case 'follow':
return c.interaction_days >= 2
case 'last_reply':
return c.last_is_send === 1
case 'no_reply':
return c.last_is_send === 0
}
}
/** 微信员工 5 数字 → 明细 modal(数据源:本地 staff-chat-stats,按 metric 过滤 + 合成分页)。 */
function openWechatCommModal(row: Account, metric: ChatMetric): void {
// Task 3 接真实数据 + metric 过滤 + 合成分页。此处先立标题与列骨架。
detailTitle.value = `${METRIC_TITLES[metric]} · ${row.user_name ?? row.account_id}`
detailCols.value = commModalColsFor(metric)
detailFetcher.value = async () => ({ items: [], total: 0, page: 1, page_size: 10 })
detailFetcher.value = async (page: number, page_size: number): Promise<Page<any>> => {
// 复用已缓存的 stats;点击早于列表加载完成则按需补拉。
let stats = staffStats.value[row.account_id]
if (!stats) {
try {
stats = await getStaffChatStats({
owner_account_id: row.account_id,
start: statsStart.value,
end: statsEnd.value,
})
staffStats.value[row.account_id] = stats
} catch {
return { items: [], total: 0, page, page_size }
}
}
const filtered = stats.customers.filter((c) => metricFilter(c, metric))
const startIdx = (page - 1) * page_size
return {
items: filtered.slice(startIdx, startIdx + page_size),
total: filtered.length,
page,
page_size,
}
}
detailOpen.value = true
}