diff --git a/yunkes/src/views/StaffList.vue b/yunkes/src/views/StaffList.vue index c224268..b2a2fb2 100644 --- a/yunkes/src/views/StaffList.vue +++ b/yunkes/src/views/StaffList.vue @@ -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> => { + // 复用已缓存的 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 }