feat(staff): stat modal 列对齐云客(序号/员工信息/员工微信) + 客户微信可点带窗跳聊天

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
浅念
2026-08-08 13:46:59 +08:00
parent abe86489b9
commit 7405ac5fc9
+43 -11
View File
@@ -335,16 +335,44 @@ const METRIC_TITLES: Record<ChatMetric, string> = {
last_reply: '员工最后回复数',
no_reply: '未回复客户数',
}
// 对齐云客 spec §6:所有 modal 显示「客户微信」;仅「有效沟通数」modal 额外显示发送/接收数。
// 序号需改 YkStaffDetailModal(spec §1 不改组件,略);员工信息/员工微信由 modal 标题承载,行内冗余故略。
function commModalColsFor(metric: ChatMetric): any[] {
const cols: any[] = [{ prop: 'friend_name', label: '客户微信', minWidth: 180 }]
/** 拼接非空字段(过滤 '--'),全缺则 '--'。用于 modal 里员工信息/员工微信 单行显示。 */
function joinFields(...vals: (string | undefined | null)[]): string {
const parts = vals.map((v) => (v == null ? '' : String(v).trim())).filter((v) => v && v !== '--')
return parts.length ? parts.join(' ') : '--'
}
/** modal 客户微信 → 该员工×客户聊天(带 StaffList 当前日期窗)。缺失 owner/talker 静默 no-op。 */
function openCustomerChat(row: Account, customer: StaffChatCustomer): void {
if (!row.account_id || !customer.talker_id) return
router.push({
name: 'chat',
params: { channel: 'wechat', ownerId: row.account_id, talkerId: customer.talker_id },
query: { start: String(statsStart.value), end: String(statsEnd.value) },
})
}
// 对齐云客(2026-08-08 真机):序号 / 客户微信(可点→聊天) / [仅有效沟通:发送·接收] / 员工信息 / 员工微信。
// 序号/员工信息/员工微信 靠 fetcher 注入字段实现,不改 YkStaffDetailModal(其 cols 仍 prop 驱动)。
function commModalColsFor(metric: ChatMetric, row: Account): any[] {
const cols: any[] = [
{ prop: '_serial', label: '序号', width: 70, align: 'center' },
{
prop: 'customer_wx',
label: '客户微信',
minWidth: 180,
onClick: (c: any) => openCustomerChat(row, c),
},
]
if (metric === 'effective') {
cols.push(
{ prop: 'send_count', label: '发送消息数', width: 110, align: 'center' },
{ prop: 'receive_count', label: '接收消息数', width: 110, align: 'center' },
)
}
cols.push(
{ prop: 'staff_info', label: '员工信息', minWidth: 140 },
{ prop: 'staff_wx', label: '员工微信', minWidth: 160 },
)
return cols
}
/** 按 metric 过滤客户明细(口径见 spec §4;last_is_send 为 null 时既非最后回复也非未回复)。 */
@@ -366,7 +394,7 @@ function metricFilter(c: StaffChatCustomer, m: ChatMetric): boolean {
/** 微信员工 5 数字 → 明细 modal(数据源:本地 staff-chat-stats,按 metric 过滤 + 合成分页)。 */
function openWechatCommModal(row: Account, metric: ChatMetric): void {
detailTitle.value = `${METRIC_TITLES[metric]} · ${row.user_name ?? row.account_id}`
detailCols.value = commModalColsFor(metric)
detailCols.value = commModalColsFor(metric, row)
detailFetcher.value = async (page: number, page_size: number): Promise<Page<any>> => {
// 复用已缓存的 stats;点击早于列表加载完成则按需补拉。
let stats = staffStats.value[row.account_id]
@@ -386,12 +414,16 @@ function openWechatCommModal(row: Account, metric: ChatMetric): void {
}
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,
}
const staffInfo = joinFields(cellText(row, 'userName'), cellText(row, 'phone'))
const staffWx = joinFields(cellText(row, 'nickName'), row.account_id)
const items = filtered.slice(startIdx, startIdx + page_size).map((c, i) => ({
...c,
_serial: startIdx + i + 1,
customer_wx: joinFields(c.friend_name, c.talker_id),
staff_info: staffInfo,
staff_wx: staffWx,
}))
return { items, total: filtered.length, page, page_size }
}
detailOpen.value = true
}