feat(manager): 实现团队管理页面的数据对接和功能优化
- 新增团队异常预警API接口和数据展示 - 完善销售漏斗组件,对接实际数据 - 优化业绩排名组件,支持多种数据源 - 更新成员详情组件,适配新数据结构 - 重构管理页面,整合多个API调用
This commit is contained in:
@@ -1,5 +1,10 @@
|
|||||||
import https from '../utils/https'
|
import https from '../utils/https'
|
||||||
|
|
||||||
|
// 团队异常预警 /api/v1/manager/group_abnormal_response
|
||||||
|
export const getGroupAbnormalResponse = (params) => {
|
||||||
|
return https.post('/api/v1/manager/group_abnormal_response', params)
|
||||||
|
}
|
||||||
|
|
||||||
// 团队总通话 /api/v1/manager/week_total_call
|
// 团队总通话 /api/v1/manager/week_total_call
|
||||||
export const getWeekTotalCall = (params) => {
|
export const getWeekTotalCall = (params) => {
|
||||||
return https.post('/api/v1/manager/week_total_call', params)
|
return https.post('/api/v1/manager/week_total_call', params)
|
||||||
@@ -20,7 +25,10 @@ export const getWeekAddDealTotal = (params) => {
|
|||||||
export const getWeekAddFeeTotal = (params) => {
|
export const getWeekAddFeeTotal = (params) => {
|
||||||
return https.post('/api/v1/manager/week_add_fee_total', params)
|
return https.post('/api/v1/manager/week_add_fee_total', params)
|
||||||
}
|
}
|
||||||
// 定金转化率 /api/v1/manager/week_add_fee_total
|
// 定金转化率 /api/v1/manager/get_pay_deposit_to_money_rate
|
||||||
|
export const getPayDepositToMoneyRate = (params) => {
|
||||||
|
return https.post('/api/v1/manager/get_pay_deposit_to_money_rate', params)
|
||||||
|
}
|
||||||
|
|
||||||
// 团队漏斗 /api/v1/group_funnel/get_group_funnel
|
// 团队漏斗 /api/v1/group_funnel/get_group_funnel
|
||||||
export const getGroupFunnel = (params) => {
|
export const getGroupFunnel = (params) => {
|
||||||
|
|||||||
@@ -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.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"/>
|
||||||
@@ -12,27 +12,27 @@
|
|||||||
<div class="details-grid" v-show="!isDetailsCollapsed" :class="{ 'collapsing': isDetailsCollapsed }">
|
<div class="details-grid" v-show="!isDetailsCollapsed" :class="{ 'collapsing': isDetailsCollapsed }">
|
||||||
<div class="detail-card">
|
<div class="detail-card">
|
||||||
<div class="detail-label">总通话次数</div>
|
<div class="detail-label">总通话次数</div>
|
||||||
<div class="detail-value">{{ selectedMember.calls }} 次</div>
|
<div class="detail-value">{{ selectedMember.calls || 0 }} 次</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-card">
|
<div class="detail-card">
|
||||||
<div class="detail-label">通话时长</div>
|
<div class="detail-label">通话时长</div>
|
||||||
<div class="detail-value">{{ selectedMember.callTime }} 小时</div>
|
<div class="detail-value">{{ selectedMember.callTime || 0 }} 小时</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-card">
|
<div class="detail-card">
|
||||||
<div class="detail-label">新增客户</div>
|
<div class="detail-label">新增客户</div>
|
||||||
<div class="detail-value">{{ selectedMember.newClients }} 人</div>
|
<div class="detail-value">{{ selectedMember.newClients || 0 }} 人</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-card">
|
<div class="detail-card">
|
||||||
<div class="detail-label">成交单数</div>
|
<div class="detail-label">成交单数</div>
|
||||||
<div class="detail-value">{{ selectedMember.deals }} 单</div>
|
<div class="detail-value">{{ selectedMember.deals || 0 }} 单</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-card">
|
<div class="detail-card">
|
||||||
<div class="detail-label">总业绩</div>
|
<div class="detail-label">总业绩</div>
|
||||||
<div class="detail-value">¥{{ selectedMember.performance.toLocaleString() }}</div>
|
<div class="detail-value">¥{{ formatAmount(selectedMember.week_amount || selectedMember.performance) }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-card">
|
<div class="detail-card">
|
||||||
<div class="detail-label">平均单价</div>
|
<div class="detail-label">转化率</div>
|
||||||
<div class="detail-value">¥{{ selectedMember.avgDealValue.toLocaleString() }}</div>
|
<div class="detail-value">{{ selectedMember.conversion_rate || selectedMember.conversion || '0%' }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -66,7 +66,7 @@
|
|||||||
<div class="no-guidance" v-else>
|
<div class="no-guidance" v-else>
|
||||||
<div class="celebration-icon">🎉</div>
|
<div class="celebration-icon">🎉</div>
|
||||||
<h4>表现优秀!</h4>
|
<h4>表现优秀!</h4>
|
||||||
<p>{{ selectedMember.name }} 的各项指标都很不错,继续保持这种状态!</p>
|
<p>{{ selectedMember.user_name || selectedMember.name }} 的各项指标都很不错,继续保持这种状态!</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -104,7 +104,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.name }} 还没有通话录音记录</p>
|
<p>{{ selectedMember.user_name || selectedMember.name }} 还没有通话录音记录</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -146,6 +146,14 @@ const toggleRecordingsCollapse = () => {
|
|||||||
isRecordingsCollapsed.value = !isRecordingsCollapsed.value
|
isRecordingsCollapsed.value = !isRecordingsCollapsed.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 格式化金额
|
||||||
|
const formatAmount = (amount) => {
|
||||||
|
if (typeof amount === 'number') {
|
||||||
|
return amount.toLocaleString()
|
||||||
|
}
|
||||||
|
return amount || '0'
|
||||||
|
}
|
||||||
|
|
||||||
// 获取成员录音列表
|
// 获取成员录音列表
|
||||||
const getRecordingsForMember = (member) => {
|
const getRecordingsForMember = (member) => {
|
||||||
// 模拟录音数据,实际项目中应该从API获取
|
// 模拟录音数据,实际项目中应该从API获取
|
||||||
|
|||||||
@@ -12,18 +12,18 @@
|
|||||||
<span>入群率</span>
|
<span>入群率</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-for="member in teamMembers"
|
v-for="(member, index) in displayMembers"
|
||||||
:key="member.id"
|
:key="member.user_name || member.id"
|
||||||
class="table-row"
|
class="table-row"
|
||||||
:class="{ active: selectedMember.id === member.id }"
|
:class="{ active: selectedMember && (selectedMember.user_name === member.user_name || selectedMember.id === member.id) }"
|
||||||
@click="selectMember(member)"
|
@click="selectMember(member)"
|
||||||
>
|
>
|
||||||
<span class="rank">{{ member.rank }}</span>
|
<span class="rank">{{ index + 1 }}</span>
|
||||||
<span class="name">{{ member.name }}</span>
|
<span class="name">{{ member.user_name || member.name }}</span>
|
||||||
<span class="performance">¥{{ member.performance.toLocaleString() }}</span>
|
<span class="performance">¥{{ formatAmount(member.week_amount || member.performance) }}</span>
|
||||||
<span class="conversion">{{ member.conversion }}%</span>
|
<span class="conversion">{{ member.conversion_rate || member.conversion || '0%' }}</span>
|
||||||
<span class="wechat-rate">{{ member.wechatRate || 0 }}%</span>
|
<span class="wechat-rate">{{ member.plus_v_rate || member.wechatRate || '0%' }}</span>
|
||||||
<span class="group-rate">{{ member.groupRate || 0 }}%</span>
|
<span class="group-rate">{{ member.group_rate || member.groupRate || '0%' }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -31,23 +31,45 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { defineProps, defineEmits } from 'vue'
|
import { defineProps, defineEmits, computed } from 'vue'
|
||||||
|
|
||||||
// 定义props
|
// 定义props
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
teamMembers: {
|
teamMembers: {
|
||||||
type: Array,
|
type: Array,
|
||||||
required: true
|
default: () => []
|
||||||
},
|
},
|
||||||
selectedMember: {
|
selectedMember: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
default: () => null
|
||||||
|
},
|
||||||
|
groupRanking: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 定义emits
|
// 定义emits
|
||||||
const emit = defineEmits(['select-member'])
|
const emit = defineEmits(['select-member'])
|
||||||
|
|
||||||
|
// 计算显示的成员数据
|
||||||
|
const displayMembers = computed(() => {
|
||||||
|
// 如果有groupRanking数据,优先使用
|
||||||
|
if (props.groupRanking && props.groupRanking.team_data && props.groupRanking.team_data.group_list) {
|
||||||
|
return props.groupRanking.team_data.group_list
|
||||||
|
}
|
||||||
|
// 否则使用teamMembers数据
|
||||||
|
return props.teamMembers
|
||||||
|
})
|
||||||
|
|
||||||
|
// 格式化金额
|
||||||
|
const formatAmount = (amount) => {
|
||||||
|
if (typeof amount === 'number') {
|
||||||
|
return amount.toLocaleString()
|
||||||
|
}
|
||||||
|
return amount || '0'
|
||||||
|
}
|
||||||
|
|
||||||
// 选择成员函数
|
// 选择成员函数
|
||||||
const selectMember = (member) => {
|
const selectMember = (member) => {
|
||||||
emit('select-member', member)
|
emit('select-member', member)
|
||||||
|
|||||||
@@ -5,23 +5,23 @@
|
|||||||
<div class="funnel-chart">
|
<div class="funnel-chart">
|
||||||
<div class="funnel-stage" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);">
|
<div class="funnel-stage" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);">
|
||||||
<span class="stage-label">线索总数</span>
|
<span class="stage-label">线索总数</span>
|
||||||
<span class="stage-value">1000</span>
|
<span class="stage-value">{{ funnelData.customers_count?.['线索总数'] || 0 }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="funnel-stage" style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);">
|
<div class="funnel-stage" style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);">
|
||||||
<span class="stage-label">有效沟通</span>
|
<span class="stage-label">有效沟通</span>
|
||||||
<span class="stage-value">450</span>
|
<span class="stage-value">{{ funnelData.customers_count?.['有效沟通'] || 0 }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="funnel-stage" style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);">
|
<div class="funnel-stage" style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);">
|
||||||
<span class="stage-label">到课数据</span>
|
<span class="stage-label">到课数据</span>
|
||||||
<span class="stage-value">180</span>
|
<span class="stage-value">{{ funnelData.customers_count?.['到课数据'] || 0 }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="funnel-stage" style="background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);">
|
<div class="funnel-stage" style="background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);">
|
||||||
<span class="stage-label">预付定金</span>
|
<span class="stage-label">预付定金</span>
|
||||||
<span class="stage-value">50</span>
|
<span class="stage-value">{{ funnelData.customers_count?.['预付定金'] || 0 }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="funnel-stage" style="background: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%);">
|
<div class="funnel-stage" style="background: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%);">
|
||||||
<span class="stage-label">成功签单</span>
|
<span class="stage-label">成功签单</span>
|
||||||
<span class="stage-value">12</span>
|
<span class="stage-value">{{ funnelData.customers_count?.['成功签单'] || 0 }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -29,6 +29,22 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
// 团队销售漏斗组件
|
// 团队销售漏斗组件
|
||||||
|
|
||||||
|
// 定义props
|
||||||
|
const props = defineProps({
|
||||||
|
funnelData: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({
|
||||||
|
customers_count: {
|
||||||
|
'线索总数': 0,
|
||||||
|
'有效沟通': 0,
|
||||||
|
'到课数据': 0,
|
||||||
|
'预付定金': 0,
|
||||||
|
'成功签单': 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@@ -2,24 +2,80 @@
|
|||||||
<div class="team-alerts">
|
<div class="team-alerts">
|
||||||
<h2>团队异常预警</h2>
|
<h2>团队异常预警</h2>
|
||||||
<div class="alert-list">
|
<div class="alert-list">
|
||||||
<div class="alert-item warning">
|
<div
|
||||||
<span class="alert-icon">⚠</span>
|
v-for="alert in aggregatedAlerts"
|
||||||
<span>钱鑫有102人(预计)需今日跟进通话</span>
|
:key="alert.id"
|
||||||
|
class="alert-item"
|
||||||
|
:class="alert.type"
|
||||||
|
>
|
||||||
|
<span class="alert-icon">{{ alert.icon }}</span>
|
||||||
|
<span>{{ alert.message }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="alert-item danger">
|
<div v-if="aggregatedAlerts.length === 0" class="alert-item info">
|
||||||
<span class="alert-icon">🔺</span>
|
|
||||||
<span>李娜今日预计电话工作量达30%</span>
|
|
||||||
</div>
|
|
||||||
<div class="alert-item info">
|
|
||||||
<span class="alert-icon">ℹ</span>
|
<span class="alert-icon">ℹ</span>
|
||||||
<span>高明明客户"王先生"下次未来电话记录</span>
|
<span>暂无异常预警</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
// 团队异常预警组件
|
import { computed } from 'vue'
|
||||||
|
|
||||||
|
// 定义props
|
||||||
|
const props = defineProps({
|
||||||
|
abnormalData: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 聚合异常数据,按人员分组
|
||||||
|
const aggregatedAlerts = computed(() => {
|
||||||
|
const alerts = []
|
||||||
|
const data = props.abnormalData
|
||||||
|
|
||||||
|
if (!data || Object.keys(data).length === 0) {
|
||||||
|
return alerts
|
||||||
|
}
|
||||||
|
|
||||||
|
// 收集所有异常人员
|
||||||
|
const personAbnormalities = new Map()
|
||||||
|
|
||||||
|
// 处理严重超时率异常
|
||||||
|
if (data.erious_timeout_rate_abnorma && Array.isArray(data.erious_timeout_rate_abnorma)) {
|
||||||
|
data.erious_timeout_rate_abnorma.forEach(person => {
|
||||||
|
if (!personAbnormalities.has(person)) {
|
||||||
|
personAbnormalities.set(person, [])
|
||||||
|
}
|
||||||
|
personAbnormalities.get(person).push('严重超时率异常')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理表格填写异常
|
||||||
|
if (data.table_filling_abnormal && Array.isArray(data.table_filling_abnormal)) {
|
||||||
|
data.table_filling_abnormal.forEach(person => {
|
||||||
|
if (!personAbnormalities.has(person)) {
|
||||||
|
personAbnormalities.set(person, [])
|
||||||
|
}
|
||||||
|
personAbnormalities.get(person).push('表格填写异常')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成聚合后的预警信息
|
||||||
|
let alertId = 1
|
||||||
|
personAbnormalities.forEach((abnormalities, person) => {
|
||||||
|
const abnormalityText = abnormalities.join('、')
|
||||||
|
alerts.push({
|
||||||
|
id: alertId++,
|
||||||
|
type: abnormalities.length > 1 ? 'danger' : 'warning',
|
||||||
|
icon: abnormalities.length > 1 ? '🔺' : '⚠',
|
||||||
|
message: `${person}存在${abnormalityText}`
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return alerts
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -43,6 +99,27 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.75rem;
|
gap: 0.75rem;
|
||||||
|
max-height: 300px;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
// 自定义滚动条样式
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-track {
|
||||||
|
background: #f1f5f9;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
background: #cbd5e1;
|
||||||
|
border-radius: 3px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #94a3b8;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.alert-item {
|
.alert-item {
|
||||||
|
|||||||
@@ -32,17 +32,17 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="report-card">
|
<div class="report-card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<span class="card-title">总业绩</span>
|
<span class="card-title">月度总业绩</span>
|
||||||
<span class="card-trend positive">+8% vs 上期</span>
|
<span class="card-trend positive">+8% vs 上月</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-value">{{ formatCurrency(weekTotalData.week_add_fee_total?.total_add_fee || 0) }} 元</div>
|
<div class="card-value">{{ formatCurrency(weekTotalData.week_add_fee_total?.total_add_fee || 0) }} 元</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="report-card">
|
<div class="report-card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<span class="card-title">定金转化率</span>
|
<span class="card-title">定金转化率</span>
|
||||||
<span class="card-trend positive">+9% vs 上期</span>
|
<span class="card-trend positive">{{ weekTotalData.pay_deposit_to_money_rate?.team_data?.week_vs_last_week || '0%' }} vs 上期</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-value">{{ formatCurrency(weekTotalData.week_add_deal_total?.total_add_deal_fee || 0) }} 元</div>
|
<div class="card-value">{{ weekTotalData.pay_deposit_to_money_rate?.team_data?.week_pay_deposit_to_money_rate || '0%' }} </div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -60,6 +60,7 @@ const props = defineProps({
|
|||||||
week_add_customer_total: {},
|
week_add_customer_total: {},
|
||||||
week_add_deal_total: {},
|
week_add_deal_total: {},
|
||||||
week_add_fee_total: {},
|
week_add_fee_total: {},
|
||||||
|
pay_deposit_to_money_rate: {}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -19,13 +19,13 @@
|
|||||||
<!-- Top Section - Team Alerts and Today's Report -->
|
<!-- Top Section - Team Alerts and Today's Report -->
|
||||||
<div class="top-section">
|
<div class="top-section">
|
||||||
<!-- Team Alerts -->
|
<!-- Team Alerts -->
|
||||||
<TeamAlerts />
|
<TeamAlerts :abnormalData="groupAbnormalResponse" />
|
||||||
<!-- Today's Team Report -->
|
<!-- Today's Team Report -->
|
||||||
<TeamReport :weekTotalData="weekTotalData" />
|
<TeamReport :weekTotalData="weekTotalData" />
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!-- Sales Funnel Section -->
|
<!-- Sales Funnel Section -->
|
||||||
<SalesFunnel />
|
<SalesFunnel :funnelData="weekTotalData.group_funnel" />
|
||||||
|
|
||||||
<!-- Bottom Section -->
|
<!-- Bottom Section -->
|
||||||
<div class="bottom-section">
|
<div class="bottom-section">
|
||||||
@@ -34,6 +34,7 @@
|
|||||||
<PerformanceRanking
|
<PerformanceRanking
|
||||||
:team-members="teamMembers"
|
:team-members="teamMembers"
|
||||||
:selected-member="selectedMember"
|
:selected-member="selectedMember"
|
||||||
|
:group-ranking="groupRanking"
|
||||||
@select-member="selectMember"
|
@select-member="selectMember"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -61,9 +62,7 @@ import RawDataCards from "../person/components/RawDataCards.vue";
|
|||||||
import CustomerDetail from "../person/components/CustomerDetail.vue";
|
import CustomerDetail from "../person/components/CustomerDetail.vue";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import { getWeekTotalCall, getWeekAddCustomerTotal, getWeekAddDealTotal, getWeekAddFeeTotal, getGroupFunnel } from "@/api/manager.js";
|
import {getGroupAbnormalResponse, getWeekTotalCall, getWeekAddCustomerTotal, getWeekAddDealTotal, getWeekAddFeeTotal, getGroupFunnel,getPayDepositToMoneyRate,getGroupRanking } from "@/api/manager.js";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 团队成员数据
|
// 团队成员数据
|
||||||
const teamMembers = [
|
const teamMembers = [
|
||||||
@@ -214,8 +213,21 @@ const weekTotalData = ref({
|
|||||||
week_add_customer_total: {},
|
week_add_customer_total: {},
|
||||||
week_add_deal_total: {},
|
week_add_deal_total: {},
|
||||||
week_add_fee_total: {},
|
week_add_fee_total: {},
|
||||||
|
pay_deposit_to_money_rate: {},
|
||||||
|
group_funnel: {},
|
||||||
|
week_add_fee_total: {},
|
||||||
});
|
});
|
||||||
|
// 团队异常预警
|
||||||
|
const groupAbnormalResponse = ref({})
|
||||||
|
async function TeamGetGroupAbnormalResponse() {
|
||||||
|
const params = getRequestParams()
|
||||||
|
const hasParams = params.user_name
|
||||||
|
const res = await getGroupAbnormalResponse(hasParams ? params : undefined)
|
||||||
|
console.log(res)
|
||||||
|
if (res.code === 200) {
|
||||||
|
groupAbnormalResponse.value = res.data
|
||||||
|
}
|
||||||
|
}
|
||||||
// 团队总通话
|
// 团队总通话
|
||||||
async function TeamGetWeekTotalCall() {
|
async function TeamGetWeekTotalCall() {
|
||||||
const params = getRequestParams()
|
const params = getRequestParams()
|
||||||
@@ -246,9 +258,19 @@ async function TeamGetWeekAddDealTotal() {
|
|||||||
weekTotalData.value.week_add_deal_total = res.data
|
weekTotalData.value.week_add_deal_total = res.data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 总业绩
|
// 月度总业绩
|
||||||
|
|
||||||
|
|
||||||
|
// 定金转化
|
||||||
|
async function TeamGetWeekAddFeeTotal() {
|
||||||
|
const params = getRequestParams()
|
||||||
|
const hasParams = params.user_name
|
||||||
|
const res = await getPayDepositToMoneyRate(hasParams ? params : undefined)
|
||||||
|
console.log(res)
|
||||||
|
if (res.code === 200) {
|
||||||
|
weekTotalData.value.pay_deposit_to_money_rate = res.data
|
||||||
|
}
|
||||||
|
}
|
||||||
// 销售漏斗
|
// 销售漏斗
|
||||||
async function TeamGetGroupFunnel() {
|
async function TeamGetGroupFunnel() {
|
||||||
const params = getRequestParams()
|
const params = getRequestParams()
|
||||||
@@ -256,9 +278,74 @@ async function TeamGetGroupFunnel() {
|
|||||||
const res = await getGroupFunnel(hasParams ? params : undefined)
|
const res = await getGroupFunnel(hasParams ? params : undefined)
|
||||||
console.log(res)
|
console.log(res)
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
weekTotalData.value.week_add_fee_total = res.data
|
weekTotalData.value.group_funnel = res.data
|
||||||
|
/**
|
||||||
|
* "data": {
|
||||||
|
"user_name": "马然",
|
||||||
|
"user_level": 2,
|
||||||
|
"customers_count": {
|
||||||
|
"线索总数": 132,
|
||||||
|
"有效沟通": 33,
|
||||||
|
"到课数据": 59,
|
||||||
|
"预付定金": 7,
|
||||||
|
"成功签单": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 团队业绩排名
|
||||||
|
const groupRanking = ref({})
|
||||||
|
|
||||||
|
async function TeamGetGroupRanking() {
|
||||||
|
const params = getRequestParams()
|
||||||
|
const hasParams = params.user_name
|
||||||
|
const res = await getGroupRanking(hasParams ? params : undefined)
|
||||||
|
console.log(res)
|
||||||
|
if (res.code === 200) {
|
||||||
|
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({})
|
||||||
|
|
||||||
|
|
||||||
// 当前选中的成员,默认为第一名
|
// 当前选中的成员,默认为第一名
|
||||||
@@ -269,11 +356,13 @@ const selectMember = (member) => {
|
|||||||
selectedMember.value = member;
|
selectedMember.value = member;
|
||||||
};
|
};
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
await TeamGetGroupAbnormalResponse()
|
||||||
await TeamGetWeekTotalCall()
|
await TeamGetWeekTotalCall()
|
||||||
await TeamGetWeekAddCustomerTotal()
|
await TeamGetWeekAddCustomerTotal()
|
||||||
await TeamGetWeekAddDealTotal()
|
await TeamGetWeekAddDealTotal()
|
||||||
// await TeamGetWeekAddFeeTotal()
|
await TeamGetWeekAddFeeTotal()
|
||||||
await TeamGetGroupFunnel()
|
await TeamGetGroupFunnel()
|
||||||
|
await TeamGetGroupRanking()
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user