feat(staff): stat modal 列对齐云客(序号/员工信息/员工微信) + 客户微信可点带窗跳聊天
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user