feat(staff): 弹框客户微信/员工微信列改富单元格(头像+昵称+ID+真实姓名,对齐云客)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
浅念
2026-08-25 10:24:07 +08:00
parent 0d19289fba
commit b6eea3070a
5 changed files with 49 additions and 12 deletions
@@ -81,7 +81,7 @@ async def _aggregate(session: AsyncSession, owner: str, start: int, end: int) ->
return agg_rows, last_map
async def _customer_names(session: AsyncSession, owner: str, talker_ids: list[str]) -> dict[str, str]:
async def _customer_names(session: AsyncSession, owner: str, talker_ids: list[str]) -> dict[str, tuple[str, str, str]]:
if not talker_ids:
return {}
stmt = sa.select(
@@ -89,15 +89,16 @@ async def _customer_names(session: AsyncSession, owner: str, talker_ids: list[st
Customer.friend_remark,
Customer.friend_nickname,
Customer.real_name,
Customer.head_image_url,
).where(
Customer.channel == "wechat",
Customer.owner_account_id == owner,
Customer.friend_id.in_(talker_ids),
)
names: dict[str, str] = {}
for fid, remark, nick, real in (await session.execute(stmt)).all():
names[fid] = remark or nick or real or fid
return names
info: dict[str, tuple[str, str, str]] = {}
for fid, remark, nick, real, head in (await session.execute(stmt)).all():
info[fid] = (remark or nick or real or fid, real or "", head or "")
return info
@router.get("/staff-chat-stats")
@@ -124,7 +125,9 @@ async def get_staff_chat_stats(
customers.append(
StaffChatCustomerOut(
talker_id=tid,
friend_name=names.get(tid, tid),
friend_name=(names.get(tid) or (tid, "", ""))[0],
real_name=(names.get(tid) or ("", "", ""))[1] or None,
head_image_url=(names.get(tid) or ("", "", ""))[2] or None,
send_count=int(r.send_count or 0),
receive_count=int(r.receive_count or 0),
interaction_days=int(r.interaction_days or 0),
+2
View File
@@ -366,6 +366,8 @@ class StaffChatCustomerOut(BaseModel):
talker_id: str
friend_name: str # remark > nickname > real_name > talker_id
real_name: str | None = None # 真实姓名(弹框客户微信列显示)
head_image_url: str | None = None # 头像(弹框客户微信列显示)
send_count: int # 员工发出(is_send True)
receive_count: int # 客户发出(is_send False)
interaction_days: int # 窗口内不同日期数
+2
View File
@@ -316,6 +316,8 @@ export interface Message {
export interface StaffChatCustomer {
talker_id: string
friend_name: string
real_name?: string | null
head_image_url?: string | null
send_count: number
receive_count: number
interaction_days: number
+24 -1
View File
@@ -79,7 +79,30 @@ watch(
:formatter="c.formatter"
show-overflow-tooltip
>
<template v-if="c.onClick" #default="{ row }">
<template v-if="c.type === 'person'" #default="{ row }">
<div style="display: flex; align-items: center; gap: 8px; padding: 2px 0">
<el-avatar :size="28" :src="row[c.prop + '_avatar'] || undefined" shape="square" style="flex: none; border-radius: 6px;">
{{ (row[c.prop + '_name'] || '?').slice(0, 1) }}
</el-avatar>
<div style="min-width: 0; flex: 1">
<div v-if="c.onClick" >
<el-button link type="primary" size="small" @click="c.onClick?.(row)">
{{ row[c.prop + '_name'] || row[c.prop] || '--' }}
</el-button>
</div>
<div v-else style="font-size: 13px; color: #2b3240; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
{{ row[c.prop + '_name'] || row[c.prop] || '--' }}
</div>
<div v-if="row[c.prop + '_sub']" style="font-size: 11px; color: #8a94a4; margin-top: 1px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
{{ row[c.prop + '_sub'] }}
</div>
<div v-if="row[c.prop + '_real']" style="font-size: 11px; color: #5a6472; margin-top: 1px;">
{{ row[c.prop + '_real'] }}
</div>
</div>
</div>
</template>
<template v-else-if="c.onClick" #default="{ row }">
<el-button link type="primary" size="small" @click="c.onClick?.(row)">
{{ c.formatter ? c.formatter(row, c, row[c.prop], 0) : row[c.prop] }}
</el-button>
+12 -5
View File
@@ -387,7 +387,8 @@ function commModalColsFor(metric: ChatMetric, row: Account): any[] {
{
prop: 'customer_wx',
label: '客户微信',
minWidth: 180,
minWidth: 200,
type: 'person',
onClick: (c: any) => openCustomerChat(row, c),
},
]
@@ -398,8 +399,7 @@ function commModalColsFor(metric: ChatMetric, row: Account): any[] {
)
}
cols.push(
{ prop: 'staff_info', label: '员工信息', minWidth: 140 },
{ prop: 'staff_wx', label: '员工微信', minWidth: 160 },
{ prop: 'staff_wx', label: '员工微信', minWidth: 200, type: 'person' },
)
return cols
}
@@ -447,9 +447,16 @@ function openWechatCommModal(row: Account, metric: ChatMetric): void {
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,
customer_wx: c.friend_name,
customer_wx_name: c.friend_name,
customer_wx_sub: c.talker_id,
customer_wx_real: c.real_name || '',
customer_wx_avatar: c.head_image_url || '',
staff_wx: staffWx,
staff_wx_name: cellText(row, 'nickName'),
staff_wx_sub: row.account_id,
staff_wx_real: cellText(row, 'userName') || '',
staff_wx_avatar: cellText(row, 'headImg') || (row.raw_json as any)?.headImg || '',
}))
// 汇总说明(对齐云客)
const metricTitle = METRIC_TITLES[metric]