feat(staff): align StaffList columns to 云客 backend
WeChat tab: 6 compound columns mirroring wechatlist (员工信息/数据更新·最新消息时间/好友数/消息数/沟通数/及时回复). WhatsApp tab: 10 columns incl 操作 mirroring waBusiness/userlist. Fixes string-time bug (lastUpdate/uploadTime parsed as number showed --; cellTimeText renders strings). Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+338
-124
@@ -1,21 +1,29 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, reactive, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { getAccounts } from '@/api'
|
||||
import type { Account, Channel } from '@/api/types'
|
||||
import { useChannelStore } from '@/stores/channel'
|
||||
import { channelLabel, formatTime } from '@/utils/format'
|
||||
import { buildAccountSections, formatBytes, readField } from '@/utils/accountFields'
|
||||
|
||||
/**
|
||||
* 员工 list — channel-tabbed account view mirroring the 云客 backend's
|
||||
* 员工微信列表 (WeChat staff accounts) and WhatsApp 员工列表. The earlier sparse
|
||||
* staff-record table is replaced by the underlying messaging accounts, which
|
||||
* carry the verbatim upstream record on `raw_json` (nickName/alias/userName/
|
||||
* sendNum/receiveNum/dbSize/onlineStatus/lastUpdate/talkerCount/...).
|
||||
* 员工微信列表 (WeChat staff accounts) and WhatsApp 员工列表.
|
||||
*
|
||||
* Each tab loads `/api/accounts?channel=<channel>` independently with its own
|
||||
* pagination state. Row click opens the all-fields drawer reused from
|
||||
* AccountList.vue (see accountFields.ts).
|
||||
* Column layout matches 云客 verbatim (captured via Playwright against
|
||||
* crm2.yunkecn.com): the WeChat tab uses 云客's 6 compound columns
|
||||
* (员工信息 / 数据更新时间·最新消息时间 / 好友数 / 消息数 / 沟通数 / 及时回复),
|
||||
* the WhatsApp tab uses 云客's 10 columns ending in an 操作 column with
|
||||
* 好友列表 / 群聊 actions. Each compound cell stacks label+value pairs.
|
||||
*
|
||||
* Fields are read structured-first, raw_json fallback via accountFields.
|
||||
* readField. Time fields upstream are strings ("YYYY-MM-DD HH:mm:ss"), so
|
||||
* cellTimeText renders strings directly and only falls back to formatTime
|
||||
* for numeric epochs.
|
||||
*
|
||||
* Row click opens the all-fields drawer reused from AccountList.vue.
|
||||
*/
|
||||
|
||||
type TabKey = Channel
|
||||
@@ -48,6 +56,9 @@ const tabState = reactive<Record<TabKey, TabState>>({
|
||||
whatsapp: freshTabState(),
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
const channelStore = useChannelStore()
|
||||
|
||||
// All-fields drawer state (shared across tabs).
|
||||
const drawerOpen = ref(false)
|
||||
const drawerAccount = ref<Account | null>(null)
|
||||
@@ -70,8 +81,20 @@ function cellNumber(row: Account, camelKey: string): number | undefined {
|
||||
return typeof v === 'number' && Number.isFinite(v) ? v : undefined
|
||||
}
|
||||
|
||||
function cellTime(row: Account, camelKey: string): number | undefined {
|
||||
return cellNumber(row, camelKey)
|
||||
/** Numeric value with a fallback (defaults to 0) — for stat cells. */
|
||||
function cellNum(row: Account, camelKey: string, fallback = 0): number {
|
||||
return cellNumber(row, camelKey) ?? fallback
|
||||
}
|
||||
|
||||
/**
|
||||
* Time cell: upstream sends strings ("YYYY-MM-DD HH:mm[:ss]"); legacy/numeric
|
||||
* epochs are formatted via formatTime. Returns '--' only when truly empty.
|
||||
*/
|
||||
function cellTimeText(row: Account, camelKey: string): string {
|
||||
const v = cell(row, camelKey)
|
||||
if (typeof v === 'number' && Number.isFinite(v)) return formatTime(v)
|
||||
if (typeof v === 'string' && v.trim()) return v.trim()
|
||||
return '--'
|
||||
}
|
||||
|
||||
function imageCell(row: Account, camelKey: string): string | undefined {
|
||||
@@ -116,25 +139,52 @@ function onJobLabel(v: unknown): string {
|
||||
return '--'
|
||||
}
|
||||
|
||||
// 在线状态: upstream sends "online"/"offline" (sometimes 1/0). Render as a tag
|
||||
// when recognized; pass through other strings so info isn't hidden.
|
||||
function onlineTagType(v: unknown): 'success' | 'info' | '' {
|
||||
if (v === 'online' || v === 1 || v === '1') return 'success'
|
||||
if (v === 'offline' || v === 0 || v === '0') return 'info'
|
||||
/**
|
||||
* 主/副号 tag for the WeChat 员工信息 cell. 云客 marks the primary
|
||||
* dual-open account with 主 and the secondary with 副. Mapped from the
|
||||
* upstream flags: isOpenDuo===1 → 主 (this account hosts a dual-open),
|
||||
* isDuo===1 → 副 (this account is the secondary instance).
|
||||
*
|
||||
* Split into text/type helpers because Vue's template expression parser
|
||||
* rejects TS non-null assertions (duoTag()!.x); two plain functions
|
||||
* sidestep that cleanly.
|
||||
*/
|
||||
function duoTagText(row: Account): string {
|
||||
if (cellNumber(row, 'isDuo') === 1) return '副'
|
||||
if (cellNumber(row, 'isOpenDuo') === 1) return '主'
|
||||
return ''
|
||||
}
|
||||
|
||||
function onlineLabel(v: unknown): string {
|
||||
if (v === 'online' || v === 1 || v === '1') return '在线'
|
||||
if (v === 'offline' || v === 0 || v === '0') return '离线'
|
||||
if (v === null || v === undefined || v === '') return '--'
|
||||
return String(v)
|
||||
function duoTagType(row: Account): 'success' | 'warning' {
|
||||
return cellNumber(row, 'isDuo') === 1 ? 'warning' : 'success'
|
||||
}
|
||||
|
||||
function channelTagType(c: Channel): 'success' | 'warning' {
|
||||
return c === 'wechat' ? 'success' : 'warning'
|
||||
}
|
||||
|
||||
/** WhatsApp row序号: accounts for current page/page-size. */
|
||||
function waSerial(index: number): number {
|
||||
const st = tabState.whatsapp
|
||||
return (st.page - 1) * st.pageSize + index + 1
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Action buttons (WhatsApp 操作 column) — jump to the corresponding list and
|
||||
// preset the global channel filter to WhatsApp. Per-staff filtering is not yet
|
||||
// supported by CustomerList/GroupList, so we land on the channel-wide list.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function viewCustomers(): void {
|
||||
channelStore.setChannel('whatsapp')
|
||||
router.push('/customers')
|
||||
}
|
||||
|
||||
function viewGroups(): void {
|
||||
channelStore.setChannel('whatsapp')
|
||||
router.push('/groups')
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Per-tab loading
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -222,14 +272,15 @@ onMounted(() => {
|
||||
<div>
|
||||
<h2 style="margin: 0 0 4px; font-size: 16px">员工列表</h2>
|
||||
<span class="yk-staff__sub">
|
||||
按渠道展示员工账号(微信号 / WhatsApp 号),点击行查看全部字段。
|
||||
按渠道展示员工账号(微信号 / WhatsApp 号),列布局对齐云客后台,点击行查看全部字段。
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-tabs v-model="activeTab" class="yk-staff__tabs" @tab-change="onTabChange">
|
||||
<!-- ============================================================
|
||||
微信员工 (WeChat staff accounts)
|
||||
微信员工 (WeChat staff accounts) — 6 compound columns mirroring
|
||||
云客 /cms/wechat/wechatlist (员工微信列表).
|
||||
============================================================ -->
|
||||
<el-tab-pane label="微信员工" name="wechat">
|
||||
<el-alert
|
||||
@@ -243,7 +294,6 @@ onMounted(() => {
|
||||
<el-table
|
||||
v-loading="tabState.wechat.loading"
|
||||
:data="tabState.wechat.items"
|
||||
stripe
|
||||
border
|
||||
row-key="account_id"
|
||||
style="width: 100%"
|
||||
@@ -251,82 +301,137 @@ onMounted(() => {
|
||||
empty-text="暂无微信员工账号"
|
||||
@row-click="openDrawer"
|
||||
>
|
||||
<el-table-column label="头像" width="64" align="center">
|
||||
<!-- 员工信息 -->
|
||||
<el-table-column label="员工信息" min-width="300">
|
||||
<template #default="{ row }">
|
||||
<template v-if="avatarUrl(row)">
|
||||
<el-image
|
||||
:src="avatarUrl(row)"
|
||||
fit="cover"
|
||||
class="yk-avatar-round"
|
||||
>
|
||||
<template #error>
|
||||
<div class="yk-avatar-fallback">{{ initials(row) }}</div>
|
||||
</template>
|
||||
</el-image>
|
||||
</template>
|
||||
<el-avatar v-else :size="36" shape="circle">
|
||||
{{ initials(row) }}
|
||||
</el-avatar>
|
||||
<div class="yk-staffinfo">
|
||||
<template v-if="avatarUrl(row)">
|
||||
<el-image
|
||||
:src="avatarUrl(row)"
|
||||
fit="cover"
|
||||
class="yk-avatar-round"
|
||||
>
|
||||
<template #error>
|
||||
<div class="yk-avatar-fallback">{{ initials(row) }}</div>
|
||||
</template>
|
||||
</el-image>
|
||||
</template>
|
||||
<el-avatar v-else :size="40" shape="circle">
|
||||
{{ initials(row) }}
|
||||
</el-avatar>
|
||||
<div class="yk-staffinfo__meta">
|
||||
<div class="yk-staffinfo__line">
|
||||
<el-tag
|
||||
v-if="duoTagText(row)"
|
||||
:type="duoTagType(row)"
|
||||
size="small"
|
||||
effect="dark"
|
||||
class="yk-staffinfo__duo"
|
||||
>{{ duoTagText(row) }}</el-tag>
|
||||
<span class="yk-staffinfo__nick" :title="cellText(row, 'nickName')">
|
||||
{{ cellText(row, 'nickName') }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="yk-staffinfo__pair">
|
||||
<span class="yk-staffinfo__k">员工姓名</span>
|
||||
<span class="yk-staffinfo__v">{{ cellText(row, 'userName') }}</span>
|
||||
</div>
|
||||
<div class="yk-staffinfo__pair">
|
||||
<span class="yk-staffinfo__k">微信手机号</span>
|
||||
<span class="yk-staffinfo__v">{{ cellText(row, 'phone') }}</span>
|
||||
</div>
|
||||
<div class="yk-staffinfo__pair">
|
||||
<span class="yk-staffinfo__k">微信号</span>
|
||||
<span class="yk-staffinfo__v">{{ cellText(row, 'alias') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="微信昵称" min-width="120">
|
||||
<template #default="{ row }">{{ cellText(row, 'nickName') }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="微信号" min-width="120">
|
||||
<template #default="{ row }">{{ cellText(row, 'alias') }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="手机号" min-width="120">
|
||||
<template #default="{ row }">{{ cellText(row, 'phone') }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="员工姓名" min-width="110">
|
||||
<template #default="{ row }">{{ cellText(row, 'userName') }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="好友数" width="90" align="right">
|
||||
|
||||
<!-- 数据更新时间 / 最新消息时间 -->
|
||||
<el-table-column label="数据更新时间/最新消息时间" width="220">
|
||||
<template #default="{ row }">
|
||||
{{ cellNumber(row, 'contactsNum') ?? 0 }}
|
||||
<div class="yk-pair">
|
||||
<span class="yk-pair__k">数据更新</span>
|
||||
<span class="yk-pair__v">{{ cellTimeText(row, 'uploadTime') }}</span>
|
||||
</div>
|
||||
<div class="yk-pair">
|
||||
<span class="yk-pair__k">最新消息</span>
|
||||
<span class="yk-pair__v">{{ cellTimeText(row, 'lastUpdate') }}</span>
|
||||
</div>
|
||||
<div class="yk-pair">
|
||||
<span class="yk-pair__k">数据库大小</span>
|
||||
<span class="yk-pair__v">{{ dbSizeText(row) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="群数" width="80" align="right">
|
||||
|
||||
<!-- 好友数 -->
|
||||
<el-table-column label="好友数" width="130">
|
||||
<template #default="{ row }">
|
||||
{{ cellNumber(row, 'groupNum') ?? 0 }}
|
||||
<div class="yk-pair">
|
||||
<span class="yk-pair__k">好友数</span>
|
||||
<span class="yk-pair__v">{{ cellNum(row, 'contactsNum') }}</span>
|
||||
</div>
|
||||
<div class="yk-pair">
|
||||
<span class="yk-pair__k">微信群数</span>
|
||||
<span class="yk-pair__v">{{ cellNum(row, 'groupNum') }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="发送" width="90" align="right">
|
||||
<template #default="{ row }">{{ cellText(row, 'sendNum') }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="接收" width="90" align="right">
|
||||
<template #default="{ row }">{{ cellText(row, 'receiveNum') }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="数据库大小" width="110" align="right">
|
||||
<template #default="{ row }">{{ dbSizeText(row) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="在职" width="90" align="center">
|
||||
|
||||
<!-- 消息数 -->
|
||||
<el-table-column label="消息数" width="150">
|
||||
<template #default="{ row }">
|
||||
<el-tag
|
||||
:type="onJobTagType(cell(row, 'isOnJob'))"
|
||||
size="small"
|
||||
effect="plain"
|
||||
>
|
||||
{{ onJobLabel(cell(row, 'isOnJob')) }}
|
||||
</el-tag>
|
||||
<div class="yk-pair">
|
||||
<span class="yk-pair__k">发送消息数</span>
|
||||
<span class="yk-pair__v">{{ cellNum(row, 'sendNum') }}</span>
|
||||
</div>
|
||||
<div class="yk-pair">
|
||||
<span class="yk-pair__k">接收消息数</span>
|
||||
<span class="yk-pair__v">{{ cellNum(row, 'receiveNum') }}</span>
|
||||
</div>
|
||||
<div class="yk-pair">
|
||||
<span class="yk-pair__k">撤回消息数</span>
|
||||
<span class="yk-pair__v">{{ cellNum(row, 'withdrawMsgCount') }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="在线状态" width="100" align="center">
|
||||
|
||||
<!-- 沟通数 -->
|
||||
<el-table-column label="沟通数" width="170">
|
||||
<template #default="{ row }">
|
||||
<el-tag
|
||||
v-if="cell(row, 'onlineStatus') !== undefined && cell(row, 'onlineStatus') !== null && cell(row, 'onlineStatus') !== ''"
|
||||
:type="onlineTagType(cell(row, 'onlineStatus'))"
|
||||
size="small"
|
||||
effect="plain"
|
||||
>
|
||||
{{ onlineLabel(cell(row, 'onlineStatus')) }}
|
||||
</el-tag>
|
||||
<span v-else style="color: #c0c4cc">--</span>
|
||||
<div class="yk-pair">
|
||||
<span class="yk-pair__k">沟通人数</span>
|
||||
<span class="yk-pair__v">{{ cellNum(row, 'chatCount') }}</span>
|
||||
</div>
|
||||
<div class="yk-pair">
|
||||
<span class="yk-pair__k">有效沟通数</span>
|
||||
<span class="yk-pair__v">{{ cellNum(row, 'contactCount') }}</span>
|
||||
</div>
|
||||
<div class="yk-pair">
|
||||
<span class="yk-pair__k">跟进客户数</span>
|
||||
<span class="yk-pair__v">{{ cellNum(row, 'followCount') }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="最后更新" width="160">
|
||||
|
||||
<!-- 及时回复 -->
|
||||
<el-table-column label="及时回复" width="200">
|
||||
<template #default="{ row }">
|
||||
{{ formatTime(cellTime(row, 'lastUpdate')) }}
|
||||
<div class="yk-pair">
|
||||
<span class="yk-pair__k">员工最后回复数</span>
|
||||
<span class="yk-pair__v">{{ cellNum(row, 'saleSendLastNum') }}</span>
|
||||
</div>
|
||||
<div class="yk-pair">
|
||||
<span class="yk-pair__k">员工最后回复率</span>
|
||||
<span class="yk-pair__v">{{ cellText(row, 'saleSendLastNumRate') }}</span>
|
||||
</div>
|
||||
<div class="yk-pair">
|
||||
<span class="yk-pair__k">未回复客户数</span>
|
||||
<span class="yk-pair__v">{{ cellNum(row, 'customerSendLastNum') }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -346,7 +451,9 @@ onMounted(() => {
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- ============================================================
|
||||
WhatsApp员工 (WhatsApp staff accounts)
|
||||
WhatsApp员工 (WhatsApp staff accounts) — 10 columns mirroring
|
||||
云客 /cms/wechat/waBusiness/userlist (员工列表), ending in an
|
||||
操作 column with 好友列表 / 群聊.
|
||||
============================================================ -->
|
||||
<el-tab-pane label="WhatsApp员工" name="whatsapp">
|
||||
<el-alert
|
||||
@@ -360,7 +467,6 @@ onMounted(() => {
|
||||
<el-table
|
||||
v-loading="tabState.whatsapp.loading"
|
||||
:data="tabState.whatsapp.items"
|
||||
stripe
|
||||
border
|
||||
row-key="account_id"
|
||||
style="width: 100%"
|
||||
@@ -368,42 +474,38 @@ onMounted(() => {
|
||||
empty-text="暂无 WhatsApp 员工账号"
|
||||
@row-click="openDrawer"
|
||||
>
|
||||
<el-table-column label="头像" width="64" align="center">
|
||||
<!-- 序号 -->
|
||||
<el-table-column label="序号" width="70" align="center">
|
||||
<template #default="{ $index }">{{ waSerial($index) }}</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 员工信息 -->
|
||||
<el-table-column label="员工信息" min-width="150">
|
||||
<template #default="{ row }">
|
||||
<el-avatar :size="36" shape="circle">
|
||||
{{ initials(row) }}
|
||||
</el-avatar>
|
||||
<div class="yk-staffinfo__nick" :title="cellText(row, 'userName')">
|
||||
{{ cellText(row, 'userName') }}
|
||||
</div>
|
||||
<div class="yk-staffinfo__muted">{{ cellText(row, 'salePhone') }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="昵称" min-width="120">
|
||||
<template #default="{ row }">{{ cellText(row, 'nickName') }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="员工姓名" min-width="110">
|
||||
<template #default="{ row }">{{ cellText(row, 'userName') }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="手机" min-width="120">
|
||||
<template #default="{ row }">{{ cellText(row, 'phone') }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="销售手机" min-width="120">
|
||||
<template #default="{ row }">{{ cellText(row, 'salePhone') }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="好友数" width="90" align="right">
|
||||
|
||||
<!-- 员工WhatsApp -->
|
||||
<el-table-column label="员工WhatsApp" min-width="220">
|
||||
<template #default="{ row }">
|
||||
{{ cellNumber(row, 'contactsNum') ?? 0 }}
|
||||
<div class="yk-staffinfo">
|
||||
<el-avatar :size="36" shape="circle">{{ initials(row) }}</el-avatar>
|
||||
<div class="yk-staffinfo__meta">
|
||||
<div class="yk-staffinfo__nick" :title="cellText(row, 'nickName')">
|
||||
{{ cellText(row, 'nickName') }}
|
||||
</div>
|
||||
<div class="yk-staffinfo__muted">{{ cellText(row, 'phone') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="群数" width="80" align="right">
|
||||
<template #default="{ row }">
|
||||
{{ cellNumber(row, 'groupNum') ?? 0 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="联系人数" width="100" align="right">
|
||||
<template #default="{ row }">{{ cellText(row, 'talkerCount') }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="新增好友" width="100" align="right">
|
||||
<template #default="{ row }">{{ cellText(row, 'friendAddNum') }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="在职" width="90" align="center">
|
||||
|
||||
<!-- 是否在职 -->
|
||||
<el-table-column label="是否在职" width="90" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag
|
||||
:type="onJobTagType(cell(row, 'isOnJob'))"
|
||||
@@ -414,9 +516,43 @@ onMounted(() => {
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="最后更新" width="160">
|
||||
|
||||
<!-- 添加人数 -->
|
||||
<el-table-column label="添加人数" width="100" align="right">
|
||||
<template #default="{ row }">{{ cellNum(row, 'friendAddNum') }}</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 沟通人数 -->
|
||||
<el-table-column label="沟通人数" width="100" align="right">
|
||||
<template #default="{ row }">{{ cellNum(row, 'talkerCount') }}</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 好友数 -->
|
||||
<el-table-column label="好友数" width="90" align="right">
|
||||
<template #default="{ row }">{{ cellNum(row, 'contactsNum') }}</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 群数 -->
|
||||
<el-table-column label="群数" width="80" align="right">
|
||||
<template #default="{ row }">{{ cellNum(row, 'groupNum') }}</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 最新消息时间 -->
|
||||
<el-table-column label="最新消息时间" width="170">
|
||||
<template #default="{ row }">
|
||||
{{ formatTime(cellTime(row, 'lastUpdate')) }}
|
||||
{{ cellTimeText(row, 'lastUpdate') }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 操作 -->
|
||||
<el-table-column label="操作" width="150" fixed="right" align="center">
|
||||
<template #default>
|
||||
<el-button link type="primary" size="small" @click.stop="viewCustomers">
|
||||
好友列表
|
||||
</el-button>
|
||||
<el-button link type="primary" size="small" @click.stop="viewGroups">
|
||||
群聊
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -528,28 +664,106 @@ onMounted(() => {
|
||||
color: #c0c4cc;
|
||||
}
|
||||
|
||||
/* Round 36px avatar — el-image renders an <img> inside; size + round it. */
|
||||
/* ---- 员工信息 compound cell (avatar + labelled lines) ---- */
|
||||
.yk-staffinfo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.yk-staffinfo__meta {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.yk-staffinfo__line {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.yk-staffinfo__duo {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.yk-staffinfo__nick {
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
color: #303133;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.yk-staffinfo__muted {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.yk-staffinfo__pair {
|
||||
font-size: 12px;
|
||||
line-height: 1.7;
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.yk-staffinfo__k {
|
||||
color: #909399;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.yk-staffinfo__v {
|
||||
color: #606266;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* ---- label/value pair stack (KPI compound cells) ---- */
|
||||
.yk-pair {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
line-height: 1.8;
|
||||
font-size: 13px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.yk-pair__k {
|
||||
color: #909399;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.yk-pair__v {
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
/* Round 40px avatar — el-image renders an <img> inside; size + round it. */
|
||||
.yk-avatar-round {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #f0f2f5;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.yk-avatar-round :deep(img) {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.yk-avatar-fallback {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
color: #909399;
|
||||
font-size: 14px;
|
||||
|
||||
Reference in New Issue
Block a user