refactor(manager): 优化团队成员详情和预警处理逻辑

- 移除硬编码的团队成员数据,改为从API获取
- 添加可选链操作符处理可能为空的成员数据
- 重构异常预警处理逻辑,动态生成预警消息
- 调整UI组件间距和样式
- 清理无用注释和代码
This commit is contained in:
2025-08-26 14:55:05 +08:00
parent 6779db176c
commit 14ee188856
4 changed files with 57 additions and 108 deletions

View File

@@ -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

View File

@@ -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))
} }
// 下载录音文件 // 下载录音文件

View File

@@ -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;

View File

@@ -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>