refactor(manager): 优化团队成员详情和预警处理逻辑
- 移除硬编码的团队成员数据,改为从API获取 - 添加可选链操作符处理可能为空的成员数据 - 重构异常预警处理逻辑,动态生成预警消息 - 调整UI组件间距和样式 - 清理无用注释和代码
This commit is contained in:
@@ -10,8 +10,6 @@ export const getWeekTotalCall = (params) => {
|
|||||||
return https.post('/api/v1/manager/week_total_call', params)
|
return https.post('/api/v1/manager/week_total_call', params)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 有效通话时长
|
|
||||||
|
|
||||||
// 新增意向客户 /api/v1/manager/week_add_customer_total
|
// 新增意向客户 /api/v1/manager/week_add_customer_total
|
||||||
export const getWeekAddCustomerTotal = (params) => {
|
export const getWeekAddCustomerTotal = (params) => {
|
||||||
return https.post('/api/v1/manager/week_add_customer_total', params)
|
return https.post('/api/v1/manager/week_add_customer_total', params)
|
||||||
@@ -38,11 +36,12 @@ export const getGroupFunnel = (params) => {
|
|||||||
export const getGroupRanking = (params) => {
|
export const getGroupRanking = (params) => {
|
||||||
return https.post('/api/v1/manager/group_ranking', params)
|
return https.post('/api/v1/manager/group_ranking', params)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 团队成员业绩详情 /api/v1/manager/group_detail
|
// 团队成员业绩详情 /api/v1/manager/group_detail
|
||||||
export const getGroupDetail = (params) => {
|
export const getGroupDetail = (params) => {
|
||||||
return https.post('/api/v1/manager/group_detail', params)
|
return https.post('/api/v1/manager/group_detail', params)
|
||||||
}
|
}
|
||||||
|
// 通话录音 /api/v1/sales/get_call_logs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="member-details">
|
<div class="member-details">
|
||||||
<div class="details-header" @click="toggleDetailsCollapse">
|
<div class="details-header" @click="toggleDetailsCollapse">
|
||||||
<h2>{{ selectedMember.user_name || selectedMember.name }} 的详细数据</h2>
|
<h2>{{ selectedMember?.user_name || selectedMember?.name||'张三' }} 的详细数据</h2>
|
||||||
<div class="collapse-toggle" :class="{ 'collapsed': isDetailsCollapsed }">
|
<div class="collapse-toggle" :class="{ 'collapsed': isDetailsCollapsed }">
|
||||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
|
||||||
<path d="M8 4l4 4H4l4-4z"/>
|
<path d="M8 4l4 4H4l4-4z"/>
|
||||||
@@ -15,35 +15,35 @@
|
|||||||
总通话次数
|
总通话次数
|
||||||
<span class="info-icon" @mouseenter="showTooltip($event, 'totalCalls')" @mouseleave="hideTooltip">ⓘ</span>
|
<span class="info-icon" @mouseenter="showTooltip($event, 'totalCalls')" @mouseleave="hideTooltip">ⓘ</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-value">{{ selectedMember.calls || 0 }} 次</div>
|
<div class="detail-value">{{ selectedMember?.calls || 0 }} 次</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-card">
|
<div class="detail-card">
|
||||||
<div class="detail-label">
|
<div class="detail-label">
|
||||||
通话时长
|
通话时长
|
||||||
<span class="info-icon" @mouseenter="showTooltip($event, 'callTime')" @mouseleave="hideTooltip">ⓘ</span>
|
<span class="info-icon" @mouseenter="showTooltip($event, 'callTime')" @mouseleave="hideTooltip">ⓘ</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-value">{{ selectedMember.callTime || 0 }} 小时</div>
|
<div class="detail-value">{{ selectedMember?.callTime || 0 }} 小时</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-card">
|
<div class="detail-card">
|
||||||
<div class="detail-label">
|
<div class="detail-label">
|
||||||
新增客户
|
新增客户
|
||||||
<span class="info-icon" @mouseenter="showTooltip($event, 'newClients')" @mouseleave="hideTooltip">ⓘ</span>
|
<span class="info-icon" @mouseenter="showTooltip($event, 'newClients')" @mouseleave="hideTooltip">ⓘ</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-value">{{ selectedMember.newClients || 0 }} 人</div>
|
<div class="detail-value">{{ selectedMember?.newClients || 0 }} 人</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-card">
|
<div class="detail-card">
|
||||||
<div class="detail-label">
|
<div class="detail-label">
|
||||||
成交单数
|
成交单数
|
||||||
<span class="info-icon" @mouseenter="showTooltip($event, 'deals')" @mouseleave="hideTooltip">ⓘ</span>
|
<span class="info-icon" @mouseenter="showTooltip($event, 'deals')" @mouseleave="hideTooltip">ⓘ</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-value">{{ selectedMember.deals || 0 }} 单</div>
|
<div class="detail-value">{{ selectedMember?.deals || 0 }} 单</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-card">
|
<div class="detail-card">
|
||||||
<div class="detail-label">
|
<div class="detail-label">
|
||||||
转化率
|
转化率
|
||||||
<span class="info-icon" @mouseenter="showTooltip($event, 'conversionRate')" @mouseleave="hideTooltip">ⓘ</span>
|
<span class="info-icon" @mouseenter="showTooltip($event, 'conversionRate')" @mouseleave="hideTooltip">ⓘ</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-value">{{ selectedMember.conversion_rate || selectedMember.conversion || '0%' }}</div>
|
<div class="detail-value">{{ selectedMember?.conversion_rate || selectedMember?.conversion || '0%' }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -115,7 +115,7 @@
|
|||||||
<div class="no-recordings" v-else>
|
<div class="no-recordings" v-else>
|
||||||
<div class="no-data-icon">📞</div>
|
<div class="no-data-icon">📞</div>
|
||||||
<h4>暂无录音</h4>
|
<h4>暂无录音</h4>
|
||||||
<p>{{ selectedMember.user_name || selectedMember.name }} 还没有通话录音记录</p>
|
<p>{{ selectedMember?.user_name || selectedMember?.name || '张三' }} 还没有通话录音记录</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -259,7 +259,7 @@ const getRecordingsForMember = (member) => {
|
|||||||
]
|
]
|
||||||
|
|
||||||
// 根据成员ID返回对应的录音,这里简化处理
|
// 根据成员ID返回对应的录音,这里简化处理
|
||||||
return recordings.slice(0, Math.min(3, member.calls || 0))
|
return recordings.slice(0, Math.min(3, member?.calls || 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 下载录音文件
|
// 下载录音文件
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ const aggregatedAlerts = computed(() => {
|
|||||||
.alert-list {
|
.alert-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.75rem;
|
|
||||||
max-height: 270px;
|
max-height: 270px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
||||||
@@ -85,12 +84,11 @@ const aggregatedAlerts = computed(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.alert-item {
|
.alert-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.75rem;
|
gap: 0.2rem;
|
||||||
padding: 0.75rem;
|
padding: 0.25rem;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
|
|
||||||
|
|||||||
@@ -95,54 +95,6 @@ const teamMembers = [
|
|||||||
newClients: 12,
|
newClients: 12,
|
||||||
deals: 5,
|
deals: 5,
|
||||||
avgDealValue: 24000,
|
avgDealValue: 24000,
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
name: "张明",
|
|
||||||
rank: 2,
|
|
||||||
performance: 85000,
|
|
||||||
conversion: 5.0,
|
|
||||||
calls: 142,
|
|
||||||
callTime: 6.2,
|
|
||||||
newClients: 8,
|
|
||||||
deals: 3,
|
|
||||||
avgDealValue: 28333,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
name: "王强",
|
|
||||||
rank: 3,
|
|
||||||
performance: 65000,
|
|
||||||
conversion: 4.0,
|
|
||||||
calls: 128,
|
|
||||||
callTime: 5.8,
|
|
||||||
newClients: 6,
|
|
||||||
deals: 2,
|
|
||||||
avgDealValue: 32500,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
name: "赵静",
|
|
||||||
rank: 4,
|
|
||||||
performance: 0,
|
|
||||||
conversion: 0.0,
|
|
||||||
calls: 89,
|
|
||||||
callTime: 3.2,
|
|
||||||
newClients: 2,
|
|
||||||
deals: 0,
|
|
||||||
avgDealValue: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
name: "刘洋",
|
|
||||||
rank: 5,
|
|
||||||
performance: 0,
|
|
||||||
conversion: 0.0,
|
|
||||||
calls: 76,
|
|
||||||
callTime: 2.8,
|
|
||||||
newClients: 1,
|
|
||||||
deals: 0,
|
|
||||||
avgDealValue: 0,
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -199,10 +151,46 @@ const groupAbnormalResponse = ref({})
|
|||||||
async function TeamGetGroupAbnormalResponse() {
|
async function TeamGetGroupAbnormalResponse() {
|
||||||
const params = getRequestParams()
|
const params = getRequestParams()
|
||||||
const hasParams = params.user_name
|
const hasParams = params.user_name
|
||||||
const res = await getGroupAbnormalResponse(hasParams ? params : undefined)
|
try {
|
||||||
console.log(res)
|
const response = await getGroupAbnormalResponse(hasParams ? params : undefined)
|
||||||
if (res.code === 200) {
|
const rawData = response.data
|
||||||
groupAbnormalResponse.value = res.data
|
|
||||||
|
// 转换数据格式,生成预警消息
|
||||||
|
const processedAlerts = []
|
||||||
|
let alertId = 1
|
||||||
|
|
||||||
|
// 处理严重超时异常人员
|
||||||
|
const timeoutPersons = rawData.erious_timeout_rate_abnorma || []
|
||||||
|
// 处理表格填写异常人员
|
||||||
|
const fillingPersons = rawData.table_filling_abnormal || []
|
||||||
|
|
||||||
|
// 为每个异常人员生成独立的预警消息
|
||||||
|
|
||||||
|
// 处理严重超时率异常人员
|
||||||
|
timeoutPersons.forEach(person => {
|
||||||
|
processedAlerts.push({
|
||||||
|
id: `timeout-${alertId++}`,
|
||||||
|
type: 'warning',
|
||||||
|
icon: '⚠',
|
||||||
|
message: `${person}严重超时率过高`
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// 处理表格填写率异常人员
|
||||||
|
fillingPersons.forEach(person => {
|
||||||
|
processedAlerts.push({
|
||||||
|
id: `filling-${alertId++}`,
|
||||||
|
type: 'warning',
|
||||||
|
icon: '⚠',
|
||||||
|
message: `${person}表格填写率过低`
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// 设置处理后的数据
|
||||||
|
groupAbnormalResponse.value = { processedAlerts }
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取团队异常预警失败:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 团队总通话
|
// 团队总通话
|
||||||
@@ -281,57 +269,22 @@ async function TeamGetGroupRanking() {
|
|||||||
console.log(res)
|
console.log(res)
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
groupRanking.value = res.data
|
groupRanking.value = res.data
|
||||||
/**
|
|
||||||
* "data": {
|
|
||||||
"user_name": "马然",
|
|
||||||
"user_level": 2,
|
|
||||||
"team_data": {
|
|
||||||
"group_list": [
|
|
||||||
{
|
|
||||||
"user_name": "马然",
|
|
||||||
"week_amount": 0,
|
|
||||||
"conversion_rate": "0%",
|
|
||||||
"plus_v_rate": "0%",
|
|
||||||
"group_rate": "0%"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"user_name": "程慧仟",
|
|
||||||
"week_amount": 7100.0,
|
|
||||||
"conversion_rate": "0.00%",
|
|
||||||
"plus_v_rate": "0.00%",
|
|
||||||
"group_rate": "0.00%"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"user_name": "常琳",
|
|
||||||
"week_amount": 14500.0,
|
|
||||||
"conversion_rate": "3.51%",
|
|
||||||
"plus_v_rate": "54.39%",
|
|
||||||
"group_rate": "49.12%"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"user_name": "王娟娟",
|
|
||||||
"week_amount": 600.0,
|
|
||||||
"conversion_rate": "0.00%",
|
|
||||||
"plus_v_rate": "3.08%",
|
|
||||||
"group_rate": "0.00%"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 成员详细数据
|
// 成员详细数据
|
||||||
const memberDetails = ref({})
|
const memberDetails = ref({})
|
||||||
|
|
||||||
|
|
||||||
// 当前选中的成员,默认为第一名
|
// 当前选中的成员,默认为空
|
||||||
const selectedMember = ref(teamMembers[0]);
|
const selectedMember = ref(null);
|
||||||
|
|
||||||
// 选择成员函数
|
// 选择成员函数
|
||||||
const selectMember = (member) => {
|
const selectMember = (member) => {
|
||||||
selectedMember.value = member;
|
selectedMember.value = member;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 团队异常预警
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await TeamGetGroupAbnormalResponse()
|
await TeamGetGroupAbnormalResponse()
|
||||||
await TeamGetWeekTotalCall()
|
await TeamGetWeekTotalCall()
|
||||||
@@ -340,7 +293,6 @@ onMounted(async () => {
|
|||||||
await TeamGetWeekAddFeeTotal()
|
await TeamGetWeekAddFeeTotal()
|
||||||
await TeamGetGroupFunnel()
|
await TeamGetGroupFunnel()
|
||||||
await TeamGetGroupRanking()
|
await TeamGetGroupRanking()
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user