feat(团队管理): 实现团队概览和统计指标数据绑定

- 增加团队概览组件数据绑定逻辑
- 实现统计指标组件数据获取与展示
- 更新API接口调用和数据处理逻辑
- 调整超时时间为30秒以适应网络环境
- 添加调试日志用于问题排查
This commit is contained in:
2025-08-12 21:33:02 +08:00
parent d8bfcaab90
commit c48f39fb5e
7 changed files with 277 additions and 42 deletions

View File

@@ -9,8 +9,8 @@ export const getTotalGroupCount = (params) => {
return https.post('/api/v1/level_three/overview/total_group_count', params) return https.post('/api/v1/level_three/overview/total_group_count', params)
} }
// 中心转化率 /api/v1/level_three/overview/center_conversion_rate // 团队转化率 /api/v1/level_three/overview/center_conversion_rate
export const getCenterConversionRate = (params) => { export const getConversionRate = (params) => {
return https.post('/api/v1/level_three/overview/center_conversion_rate', params) return https.post('/api/v1/level_three/overview/center_conversion_rate', params)
} }

View File

@@ -6,7 +6,7 @@ import { useUserStore } from '@/stores/user'
// 创建axios实例 // 创建axios实例
const service = axios.create({ const service = axios.create({
baseURL: 'http://192.168.15.53:8890' || '', // API基础路径支持完整URL baseURL: 'http://192.168.15.53:8890' || '', // API基础路径支持完整URL
timeout: 15000, // 请求超时时间 timeout: 30000, // 请求超时时间
headers: { headers: {
'Content-Type': 'application/json;charset=UTF-8' 'Content-Type': 'application/json;charset=UTF-8'
} }

View File

@@ -179,11 +179,12 @@ const stages = computed(() => [
{ id: 2, name: '待填表单', displayName: '待填表单', count: props.data['待填表单'] || 0, color: '#90caf9' }, { id: 2, name: '待填表单', displayName: '待填表单', count: props.data['待填表单'] || 0, color: '#90caf9' },
{ id: 3, name: '待入群', displayName: '待入群', count: props.data['待入群'] || 0, color: '#bbdefb' }, { id: 3, name: '待入群', displayName: '待入群', count: props.data['待入群'] || 0, color: '#bbdefb' },
{ id: 4, name: '待联系', displayName: '待联系', count: props.data['待联系'] || 0, color: '#bbdefb' }, { id: 4, name: '待联系', displayName: '待联系', count: props.data['待联系'] || 0, color: '#bbdefb' },
{ id: 5, name: '课1-4', displayName: '课1-4', count: props.data['课1-4'] || 0, color: '#64b5f6' }, { id: 5, name: '待到课', displayName: '待到课', count: props.data['待到课'] || 0, color: '#bbdefb' },
{ id: 6, name: '点击未支付', displayName: '点击未支付', count: props.data['点击未支付'] || 0, color: '#42a5f5' }, { id: 6, name: '课1-4', displayName: '课1-4', count: props.data['课1-4'] || 0, color: '#64b5f6' },
{ id: 7, name: '付定金', displayName: '付定金', count: props.data['付定金'] || 0, color: '#2196f3' }, { id: 7, name: '点击未支付', displayName: '点击未支付', count: props.data['点击未支付'] || 0, color: '#42a5f5' },
{ id: 8, name: '定价转化', displayName: '定价转化', count: props.data['定价转化'] || 0, color: '#1e88e5' }, { id: 8, name: '付定金', displayName: '付定金', count: props.data['付定金'] || 0, color: '#2196f3' },
{ id: 9, name: '成交', displayName: '成交', count: props.data['成交'] || 0, color: '#1976d2' } { id: 9, name: '定价转化', displayName: '定价转化', count: props.data['定价转化'] || 0, color: '#1e88e5' },
{ id: 10, name: '成交', displayName: '成交', count: props.data['成交'] || 0, color: '#1976d2' }
]); ]);
// 计算百分比 // 计算百分比

View File

@@ -174,6 +174,7 @@ const MOCK_DATA = reactive({
}); });
// 核心Kpi // 核心Kpi
async function getCoreKpi() { async function getCoreKpi() {
console.log('userStore.userInfo.user_level', userStore.userInfo)
const params = { const params = {
user_level: userStore.userInfo.user_level.toString(), user_level: userStore.userInfo.user_level.toString(),
user_name: userStore.userInfo.username user_name: userStore.userInfo.username

View File

@@ -4,56 +4,56 @@
<div class="overview-grid"> <div class="overview-grid">
<div class="overview-card primary"> <div class="overview-card primary">
<div class="card-header"> <div class="card-header">
<span class="card-title">中心总业绩</span> <span class="card-title">团队总业绩</span>
<span class="card-trend positive">+12% vs 昨日</span> <span class="card-trend positive">{{ totalPerformance.team_current_vs_previous_deals }} vs 上期</span>
</div> </div>
<div class="card-value">552,000 </div> <div class="card-value">{{ totalPerformance.current_team_odd_numbers||0 }}</div>
<div class="card-subtitle">月目标完成率: 56%</div> <div class="card-subtitle">月目标完成率: {{ totalPerformance.team_monthly_performance }}</div>
</div> </div>
<div class="overview-card"> <div class="overview-card">
<div class="card-header"> <div class="card-header">
<span class="card-title">活跃组数</span> <span class="card-title">活跃组数</span>
<span class="card-trend stable">5/5 </span> <span class="card-trend stable">{{ activeGroups.total_group_count }}/{{ activeGroups.total_group_count }} </span>
</div> </div>
<div class="card-value">5 </div> <div class="card-value">{{ activeGroups.total_group_count }} </div>
<div class="card-subtitle">总人数: 40</div> <div class="card-subtitle">总人数: {{ activeGroups.total_user_count }}</div>
</div> </div>
<div class="overview-card"> <div class="overview-card">
<div class="card-header"> <div class="card-header">
<span class="card-title">中心转化率</span> <span class="card-title">团队转化率</span>
<span class="card-trend positive">+0.3% vs 上期</span> <span class="card-trend positive">{{ conversionRate.team_current_vs_previous_deals }} vs 上期</span>
</div> </div>
<div class="card-value">5.2%</div> <div class="card-value">{{ conversionRate.center_conversion_rate }}</div>
<div class="card-subtitle">行业平均: 4.8%</div> <div class="card-subtitle">团队平均转化率: {{ conversionRate.average_conversion_rate }}</div>
</div> </div>
<div class="overview-card"> <div class="overview-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">{{ totalCalls.total_call_count_vs_yesterday }} vs 上期</span>
</div> </div>
<div class="card-value">1,247 </div> <div class="card-value">{{ totalCalls.total_call_count }}</div>
<div class="card-subtitle">有效通话: 892</div> <div class="card-subtitle">有效通话: {{ totalCalls.effective_call_count }}</div>
</div> </div>
<div class="overview-card"> <div class="overview-card">
<div class="card-header"> <div class="card-header">
<span class="card-title">新增客户</span> <span class="card-title">新增客户</span>
<span class="card-trend positive">+15% vs 上期</span> <span class="card-trend positive">{{ newCustomers.new_customer_vs_yesterday }} vs 上期</span>
</div> </div>
<div class="card-value">117 </div> <div class="card-value">{{ newCustomers.new_customer }} </div>
<div class="card-subtitle">意向客户: 89</div> <div class="card-subtitle">意向客户: {{ newCustomers.new_v_customer }}</div>
</div> </div>
<div class="overview-card"> <div class="overview-card">
<div class="card-header"> <div class="card-header">
<span class="card-title">定金转化</span> <span class="card-title">定金转化</span>
<span class="card-trend positive">+18% vs 上期</span> <span class="card-trend positive">{{ depositConversions.deposit_conversion_vs_previous }} vs 上期</span>
</div> </div>
<div class="card-value">40 </div> <div class="card-value">{{ depositConversions.current_deposit_conversion_rate }}</div>
<div class="card-subtitle">本月定金转化率: 10%</div> <div class="card-subtitle">本月定金转化率: {{ depositConversions.monthly_deposit_conversion_rate }}</div>
</div> </div>
</div> </div>
@@ -61,7 +61,48 @@
</template> </template>
<script setup> <script setup>
import { computed } from 'vue'
// 中心整体概览组件 // 中心整体概览组件
const props = defineProps({
overallTeamPerformance: {
type: Object,
default: () => ({
totalPerformance: {},
activeGroups: {},
conversionRate: {},
totalCalls: {},
newCustomers: {},
depositConversions: {}
})
}
})
console.log(99999,props.overallTeamPerformance)
// 计算属性
const totalPerformance = computed(() => {
return props.overallTeamPerformance.totalPerformance
})
const activeGroups = computed(() => {
return props.overallTeamPerformance.activeGroups
})
const conversionRate = computed(() => {
return props.overallTeamPerformance.conversionRate
})
const totalCalls = computed(() => {
return props.overallTeamPerformance.totalCalls
})
const newCustomers = computed(() => {
return props.overallTeamPerformance.newCustomers
})
const depositConversions = computed(() => {
console.log(999991111,props.overallTeamPerformance.depositConversions)
return props.overallTeamPerformance.depositConversions
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -5,35 +5,35 @@
<div class="stat-icon customer-rate"> <div class="stat-icon customer-rate">
<i class="el-icon-chat-dot-round"></i> <i class="el-icon-chat-dot-round"></i>
</div> </div>
<div class="kpi-value">{{ customerCommunicationRate }}%</div> <div class="kpi-value">{{ customerCommunicationRate.active_customer_communication_rate }}</div>
<p>活跃客户沟通率</p> <p>活跃客户沟通率</p>
</div> </div>
<div class="kpi-item stat-item"> <div class="kpi-item stat-item">
<div class="stat-icon response-time"> <div class="stat-icon response-time">
<i class="el-icon-timer"></i> <i class="el-icon-timer"></i>
</div> </div>
<div class="kpi-value">{{ averageResponseTime }}<span class="kpi-unit">分钟</span></div> <div class="kpi-value">{{ averageResponseTime.average_answer_time }}<span class="kpi-unit">分钟</span></div>
<p>平均应答时间</p> <p>平均应答时间</p>
</div> </div>
<div class="kpi-item stat-item"> <div class="kpi-item stat-item">
<div class="stat-icon timeout-rate"> <div class="stat-icon timeout-rate">
<i class="el-icon-warning"></i> <i class="el-icon-warning"></i>
</div> </div>
<div class="kpi-value">{{ timeoutResponseRate }}%</div> <div class="kpi-value">{{ timeoutResponseRate.timeout_rate }}</div>
<p>超时应答率</p> <p>超时应答率</p>
</div> </div>
<div class="kpi-item stat-item"> <div class="kpi-item stat-item">
<div class="stat-icon severe-timeout-rate"> <div class="stat-icon severe-timeout-rate">
<i class="el-icon-warning-outline"></i> <i class="el-icon-warning-outline"></i>
</div> </div>
<div class="kpi-value">{{ severeTimeoutRate }}%</div> <div class="kpi-value">{{ timeoutResponseRate.serious_timeout_rate }}</div>
<p>严重超时应答率</p> <p>严重超时应答率</p>
</div> </div>
<div class="kpi-item stat-item"> <div class="kpi-item stat-item">
<div class="stat-icon form-rate"> <div class="stat-icon form-rate">
<i class="el-icon-document"></i> <i class="el-icon-document"></i>
</div> </div>
<div class="kpi-value">{{ formCompletionRate }}%</div> <div class="kpi-value">{{ formCompletionRate.table_filling_rate }}</div>
<p>表格填写率</p> <p>表格填写率</p>
</div> </div>
</div> </div>

View File

@@ -15,17 +15,20 @@
<!-- Main Content --> <!-- Main Content -->
<main class="dashboard-main"> <main class="dashboard-main">
<div class="top-section"> <div class="top-section">
<CenterOverview style="height: 330px;" /> <CenterOverview
style="height: 330px;"
:overallTeamPerformance="overallTeamPerformance"
/>
<div class="action-items-compact"> <div class="action-items-compact">
<TeamAlerts style="height: 300px;" /> <TeamAlerts style="height: 300px;" />
</div> </div>
</div> </div>
<StatisticalIndicators <StatisticalIndicators
:customerCommunicationRate="customerCommunicationRate" :customerCommunicationRate="statisticalIndicators.customerCommunicationRate"
:averageResponseTime="averageResponseTime" :averageResponseTime="statisticalIndicators.averageResponseTime"
:timeoutResponseRate="timeoutResponseRate" :timeoutResponseRate="statisticalIndicators.timeoutResponseRate"
:severeTimeoutRate="severeTimeoutRate" :severeTimeoutRate="statisticalIndicators.severeTimeoutRate"
:formCompletionRate="formCompletionRate" :formCompletionRate="statisticalIndicators.formCompletionRate"
/> />
<!-- Bottom Section --> <!-- Bottom Section -->
<div class="bottom-section"> <div class="bottom-section">
@@ -133,16 +136,19 @@
</template> </template>
<script setup> <script setup>
import { ref } from 'vue' import { ref, onMounted } from 'vue'
import CenterOverview from './components/CenterOverview.vue' import CenterOverview from './components/CenterOverview.vue'
import GroupComparison from './components/GroupComparison.vue' import GroupComparison from './components/GroupComparison.vue'
import GroupRanking from './components/GroupRanking.vue' import GroupRanking from './components/GroupRanking.vue'
import TeamAlerts from '../maneger/components/TeamAlerts.vue' import TeamAlerts from '../maneger/components/TeamAlerts.vue'
import CustomerDetail from './components/CustomerDetail.vue'
import ProblemRanking from './components/ProblemRanking.vue' import ProblemRanking from './components/ProblemRanking.vue'
import StatisticalIndicators from './components/StatisticalIndicators.vue' import StatisticalIndicators from './components/StatisticalIndicators.vue'
import manager from './components/manager.vue'
import UserDropdown from '@/components/UserDropdown.vue' import UserDropdown from '@/components/UserDropdown.vue'
import { getOverallTeamPerformance,getTotalGroupCount,getConversionRate,getTotalCallCount,getNewCustomer,getDepositConversionRate,getActiveCustomerCommunicationRate,getAverageAnswerTime,getTimeoutRate,getTableFillingRate } from '@/api/senorManger.js'
import { useUserStore } from '@/stores/user.js'
const customerCommunicationRate = ref(85) const customerCommunicationRate = ref(85)
const averageResponseTime = ref(15) const averageResponseTime = ref(15)
@@ -150,6 +156,192 @@ const timeoutResponseRate = ref(5)
const severeTimeoutRate = ref(2) const severeTimeoutRate = ref(2)
const formCompletionRate = ref(90) const formCompletionRate = ref(90)
const userStore = useUserStore()
// 整体概览
const overallTeamPerformance = ref({
totalPerformance: {},
activeGroups: {},
conversionRate: {},
totalCalls: {},
newCustomers: {},
depositConversions: {},
})
// 获取整体概览数据--团队总业绩
async function fetchOverallTeamPerformance() {
const params={
user_name: userStore.userInfo.username,
user_level: userStore.userInfo.user_level.toString()
}
// 团队总业绩
try {
const response = await getOverallTeamPerformance(params)
overallTeamPerformance.value.totalPerformance = response.data
} catch (error) {
console.error('获取整体概览数据失败:', error)
}
}
// 获取整体概览数据--活跃组数
async function fetchActiveGroups() {
const params={
user_name: userStore.userInfo.username,
user_level: userStore.userInfo.user_level.toString()
}
try {
const response = await getTotalGroupCount(params)
overallTeamPerformance.value.activeGroups = response.data
console.log('活跃组数:', response.data)
} catch (error) {
console.error('获取活跃组数失败:', error)
}
}
// 获取整体概览数据--团队转化率
async function fetchConversionRate() {
const params={
user_name: userStore.userInfo.username,
user_level: userStore.userInfo.user_level.toString()
}
try {
const response = await getConversionRate(params)
overallTeamPerformance.value.conversionRate = response.data
} catch (error) {
console.error('获取团队转化率失败:', error)
}
}
// 通话次数
async function fetchTotalCallCount() {
const params={
user_name: userStore.userInfo.username,
user_level: userStore.userInfo.user_level.toString()
}
try {
const response = await getTotalCallCount(params)
overallTeamPerformance.value.totalCalls = response.data
} catch (error) {
console.error('获取通话次数失败:', error)
}
}
// 新增客户
async function fetchNewCustomers() {
const params={
user_name: userStore.userInfo.username,
user_level: userStore.userInfo.user_level.toString()
}
try {
const response = await getNewCustomer(params)
overallTeamPerformance.value.newCustomers = response.data
} catch (error) {
console.error('获取新增客户失败:', error)
}
}
// 定金转化
async function fetchDepositConversions() {
const params={
user_name: userStore.userInfo.username,
user_level: userStore.userInfo.user_level.toString()
}
try {
const response = await getDepositConversionRate(params)
overallTeamPerformance.value.depositConversions = response.data
console.log(99888999,response.data)
} catch (error) {
console.error('获取定金转化失败:', error)
}
}
const statisticalIndicators = ref({
customerCommunicationRate: 0,
averageResponseTime: 0,
timeoutResponseRate: 0,
severeTimeoutRate: 0,
formCompletionRate: 0,
})
// 统计指标--活跃客户沟通率
async function fetchCustomerCommunicationRate() {
const params={
user_name: userStore.userInfo.username,
user_level: userStore.userInfo.user_level.toString()
}
try {
const response = await getActiveCustomerCommunicationRate(params)
statisticalIndicators.value.customerCommunicationRate = response.data
} catch (error) {
console.error('获取活跃客户沟通率失败:', error)
}
}
// 统计指标--平均应答时间
async function fetchAverageResponseTime() {
const params={
user_name: userStore.userInfo.username,
user_level: userStore.userInfo.user_level.toString()
}
try {
const response = await getAverageAnswerTime(params)
statisticalIndicators.value.averageResponseTime = response.data
} catch (error) {
console.error('获取平均应答时间失败:', error)
}
}
// 统计指标--超时应答率、严重超时应答率
async function fetchTimeoutRate() {
const params={
user_name: userStore.userInfo.username,
user_level: userStore.userInfo.user_level.toString()
}
try {
const response = await getTimeoutRate(params)
statisticalIndicators.value.timeoutResponseRate = response.data
} catch (error) {
console.error('获取超时应答率失败:', error)
}
}
// 统计指标--表格填写率
async function fetchTableFillingRate() {
const params={
user_name: userStore.userInfo.username,
user_level: userStore.userInfo.user_level.toString()
}
try {
const response = await getTableFillingRate(params)
statisticalIndicators.value.formCompletionRate = response.data
} catch (error) {
console.error('获取表格填写率失败:', error)
}
}
// 初始化时获取数据
onMounted(async ()=>{
await fetchOverallTeamPerformance()
await fetchActiveGroups()
await fetchConversionRate()
await fetchTotalCallCount()
await fetchNewCustomers()
await fetchDepositConversions()
await fetchCustomerCommunicationRate()
await fetchAverageResponseTime()
await fetchTimeoutRate()
await fetchTableFillingRate()
})
// 组别数据 // 组别数据
const groups = [ const groups = [
{ {