feat(团队管理): 实现团队成员双击跳转功能并优化异常数据处理
1. 在PerformanceRanking组件中添加双击事件跳转到销售页面 2. 重构TeamAlerts组件异常数据处理逻辑,使用后端预处理数据 3. 在seniorManager页面添加异常预警API调用和数据处理 4. 优化路由参数处理逻辑,统一使用getRequestParams方法 5. 添加面包屑导航和返回功能,提升用户体验
This commit is contained in:
@@ -20,7 +20,7 @@
|
||||
:overallTeamPerformance="overallTeamPerformance"
|
||||
/>
|
||||
<div class="action-items-compact">
|
||||
<TeamAlerts style="height: 300px;" />
|
||||
<TeamAlerts style="height: 300px;" :abnormalData="teamAlerts" />
|
||||
</div>
|
||||
</div>
|
||||
<StatisticalIndicators
|
||||
@@ -89,6 +89,7 @@
|
||||
v-for="member in teamPerformanceDetail.group_details"
|
||||
:key="member.id"
|
||||
class="member-card"
|
||||
@dblclick="handleMemberDoubleClick(member)"
|
||||
>
|
||||
<div class="member-header">
|
||||
<div class="member-info">
|
||||
@@ -147,6 +148,7 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import CenterOverview from './components/CenterOverview.vue'
|
||||
import GroupComparison from './components/GroupComparison.vue'
|
||||
@@ -158,7 +160,7 @@ import UserDropdown from '@/components/UserDropdown.vue'
|
||||
import Loading from '@/components/Loading.vue'
|
||||
import { getOverallTeamPerformance,getTotalGroupCount,getConversionRate,getTotalCallCount,
|
||||
getNewCustomer,getDepositConversionRate,getActiveCustomerCommunicationRate,getAverageAnswerTime,
|
||||
getTimeoutRate,getTableFillingRate,getUrgentNeedToAddress,getTeamRanking,getTeamRankingInfo } from '@/api/senorManger.js'
|
||||
getTimeoutRate,getTableFillingRate,getUrgentNeedToAddress,getTeamRanking,getTeamRankingInfo,getAbnormalResponseRate } from '@/api/senorManger.js'
|
||||
|
||||
import { useUserStore } from '@/stores/user.js'
|
||||
|
||||
@@ -169,6 +171,8 @@ const severeTimeoutRate = ref(2)
|
||||
const formCompletionRate = ref(90)
|
||||
|
||||
const userStore = useUserStore()
|
||||
// 路由实例
|
||||
const router = useRouter()
|
||||
|
||||
// Loading状态
|
||||
const isLoading = ref(false)
|
||||
@@ -184,16 +188,30 @@ const overallTeamPerformance = ref({
|
||||
newCustomers: {},
|
||||
depositConversions: {},
|
||||
})
|
||||
// 获取通用请求参数的函数
|
||||
const getRequestParams = () => {
|
||||
const params = {}
|
||||
// 只从路由参数获取
|
||||
const routeUserLevel = router.currentRoute.value.query.user_level || router.currentRoute.value.params.user_level
|
||||
const routeUserName = router.currentRoute.value.query.user_name || router.currentRoute.value.params.user_name
|
||||
// 如果路由有参数,使用路由参数
|
||||
if (routeUserLevel) {
|
||||
params.user_level = routeUserLevel.toString()
|
||||
}
|
||||
if (routeUserName) {
|
||||
params.user_name = routeUserName
|
||||
}
|
||||
|
||||
return params
|
||||
}
|
||||
|
||||
// 获取整体概览数据--团队总业绩
|
||||
async function fetchOverallTeamPerformance() {
|
||||
const params={
|
||||
user_name: userStore.userInfo.username,
|
||||
user_level: userStore.userInfo.user_level.toString()
|
||||
}
|
||||
const params = getRequestParams()
|
||||
const hasParams = params.user_name
|
||||
// 团队总业绩
|
||||
try {
|
||||
const response = await getOverallTeamPerformance(params)
|
||||
const response = await getOverallTeamPerformance(hasParams ? params : undefined)
|
||||
overallTeamPerformance.value.totalPerformance = response.data
|
||||
} catch (error) {
|
||||
console.error('获取整体概览数据失败:', error)
|
||||
@@ -201,12 +219,10 @@ async function fetchOverallTeamPerformance() {
|
||||
}
|
||||
// 获取整体概览数据--活跃组数
|
||||
async function fetchActiveGroups() {
|
||||
const params={
|
||||
user_name: userStore.userInfo.username,
|
||||
user_level: userStore.userInfo.user_level.toString()
|
||||
}
|
||||
const params = getRequestParams()
|
||||
const hasParams = params.user_name
|
||||
try {
|
||||
const response = await getTotalGroupCount(params)
|
||||
const response = await getTotalGroupCount(hasParams ? params : undefined)
|
||||
overallTeamPerformance.value.activeGroups = response.data
|
||||
console.log('活跃组数:', response.data)
|
||||
|
||||
@@ -216,12 +232,10 @@ async function fetchActiveGroups() {
|
||||
}
|
||||
// 获取整体概览数据--团队转化率
|
||||
async function fetchConversionRate() {
|
||||
const params={
|
||||
user_name: userStore.userInfo.username,
|
||||
user_level: userStore.userInfo.user_level.toString()
|
||||
}
|
||||
const params = getRequestParams()
|
||||
const hasParams = params.user_name
|
||||
try {
|
||||
const response = await getConversionRate(params)
|
||||
const response = await getConversionRate(hasParams ? params : undefined)
|
||||
overallTeamPerformance.value.conversionRate = response.data
|
||||
} catch (error) {
|
||||
console.error('获取团队转化率失败:', error)
|
||||
@@ -229,12 +243,10 @@ async function fetchConversionRate() {
|
||||
}
|
||||
// 通话次数
|
||||
async function fetchTotalCallCount() {
|
||||
const params={
|
||||
user_name: userStore.userInfo.username,
|
||||
user_level: userStore.userInfo.user_level.toString()
|
||||
}
|
||||
const params = getRequestParams()
|
||||
const hasParams = params.user_name
|
||||
try {
|
||||
const response = await getTotalCallCount(params)
|
||||
const response = await getTotalCallCount(hasParams ? params : undefined)
|
||||
overallTeamPerformance.value.totalCalls = response.data
|
||||
} catch (error) {
|
||||
console.error('获取通话次数失败:', error)
|
||||
@@ -242,12 +254,10 @@ async function fetchTotalCallCount() {
|
||||
}
|
||||
// 新增客户
|
||||
async function fetchNewCustomers() {
|
||||
const params={
|
||||
user_name: userStore.userInfo.username,
|
||||
user_level: userStore.userInfo.user_level.toString()
|
||||
}
|
||||
const params = getRequestParams()
|
||||
const hasParams = params.user_name
|
||||
try {
|
||||
const response = await getNewCustomer(params)
|
||||
const response = await getNewCustomer(hasParams ? params : undefined)
|
||||
overallTeamPerformance.value.newCustomers = response.data
|
||||
} catch (error) {
|
||||
console.error('获取新增客户失败:', error)
|
||||
@@ -255,12 +265,10 @@ async function fetchNewCustomers() {
|
||||
}
|
||||
// 定金转化
|
||||
async function fetchDepositConversions() {
|
||||
const params={
|
||||
user_name: userStore.userInfo.username,
|
||||
user_level: userStore.userInfo.user_level.toString()
|
||||
}
|
||||
const params = getRequestParams()
|
||||
const hasParams = params.user_name
|
||||
try {
|
||||
const response = await getDepositConversionRate(params)
|
||||
const response = await getDepositConversionRate(hasParams ? params : undefined)
|
||||
overallTeamPerformance.value.depositConversions = response.data
|
||||
console.log(99888999,response.data)
|
||||
|
||||
@@ -276,14 +284,77 @@ const statisticalIndicators = ref({
|
||||
severeTimeoutRate: 0,
|
||||
formCompletionRate: 0,
|
||||
})
|
||||
|
||||
// 团队异常
|
||||
const teamAlerts = ref({})
|
||||
// 异常预警
|
||||
async function fetchAbnormalResponseRate() {
|
||||
const params = getRequestParams()
|
||||
const hasParams = params.user_name
|
||||
try {
|
||||
const response = await getAbnormalResponseRate(hasParams ? params : undefined)
|
||||
const rawData = response.data
|
||||
|
||||
// 转换数据格式,按团队分组生成预警消息
|
||||
const processedAlerts = []
|
||||
const teamData = new Map()
|
||||
|
||||
// 收集严重超时异常数据
|
||||
if (rawData.team_serious_timeout_abnormal_counts_by_group) {
|
||||
Object.entries(rawData.team_serious_timeout_abnormal_counts_by_group).forEach(([teamName, data]) => {
|
||||
if (!teamData.has(teamName)) {
|
||||
teamData.set(teamName, { timeoutCount: 0, fillingCount: 0 })
|
||||
}
|
||||
teamData.get(teamName).timeoutCount = data.count
|
||||
})
|
||||
}
|
||||
|
||||
// 收集表格填写异常数据
|
||||
if (rawData.team_table_filling_abnormal_counts_by_group) {
|
||||
Object.entries(rawData.team_table_filling_abnormal_counts_by_group).forEach(([teamName, data]) => {
|
||||
if (!teamData.has(teamName)) {
|
||||
teamData.set(teamName, { timeoutCount: 0, fillingCount: 0 })
|
||||
}
|
||||
teamData.get(teamName).fillingCount = data.count
|
||||
})
|
||||
}
|
||||
|
||||
// 生成按团队分组的预警消息
|
||||
let alertId = 1
|
||||
teamData.forEach((counts, teamName) => {
|
||||
const messages = []
|
||||
if (counts.timeoutCount > 0) {
|
||||
messages.push(`${counts.timeoutCount}人严重超时率过高`)
|
||||
}
|
||||
if (counts.fillingCount > 0) {
|
||||
messages.push(`${counts.fillingCount}人表格填写率过低`)
|
||||
}
|
||||
|
||||
if (messages.length > 0) {
|
||||
processedAlerts.push({
|
||||
id: alertId++,
|
||||
type: messages.length > 1 ? 'danger' : 'warning',
|
||||
icon: messages.length > 1 ? '🔺' : '⚠',
|
||||
message: `${teamName}团队${messages.join(',')}`
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// 设置处理后的数据
|
||||
teamAlerts.value = { processedAlerts }
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取异常预警失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 统计指标--活跃客户沟通率
|
||||
async function fetchCustomerCommunicationRate() {
|
||||
const params={
|
||||
user_name: userStore.userInfo.username,
|
||||
user_level: userStore.userInfo.user_level.toString()
|
||||
}
|
||||
const params = getRequestParams()
|
||||
const hasParams = params.user_name
|
||||
try {
|
||||
const response = await getActiveCustomerCommunicationRate(params)
|
||||
const response = await getActiveCustomerCommunicationRate(hasParams ? params : undefined)
|
||||
statisticalIndicators.value.customerCommunicationRate = response.data
|
||||
} catch (error) {
|
||||
console.error('获取活跃客户沟通率失败:', error)
|
||||
@@ -291,12 +362,10 @@ async function fetchCustomerCommunicationRate() {
|
||||
}
|
||||
// 统计指标--平均应答时间
|
||||
async function fetchAverageResponseTime() {
|
||||
const params={
|
||||
user_name: userStore.userInfo.username,
|
||||
user_level: userStore.userInfo.user_level.toString()
|
||||
}
|
||||
const params = getRequestParams()
|
||||
const hasParams = params.user_name
|
||||
try {
|
||||
const response = await getAverageAnswerTime(params)
|
||||
const response = await getAverageAnswerTime(hasParams ? params : undefined)
|
||||
statisticalIndicators.value.averageResponseTime = response.data
|
||||
} catch (error) {
|
||||
console.error('获取平均应答时间失败:', error)
|
||||
@@ -304,12 +373,10 @@ async function fetchAverageResponseTime() {
|
||||
}
|
||||
// 统计指标--超时应答率、严重超时应答率
|
||||
async function fetchTimeoutRate() {
|
||||
const params={
|
||||
user_name: userStore.userInfo.username,
|
||||
user_level: userStore.userInfo.user_level.toString()
|
||||
}
|
||||
const params = getRequestParams()
|
||||
const hasParams = params.user_name
|
||||
try {
|
||||
const response = await getTimeoutRate(params)
|
||||
const response = await getTimeoutRate(hasParams ? params : undefined)
|
||||
statisticalIndicators.value.timeoutResponseRate = response.data
|
||||
} catch (error) {
|
||||
console.error('获取超时应答率失败:', error)
|
||||
@@ -317,12 +384,10 @@ async function fetchTimeoutRate() {
|
||||
}
|
||||
// 统计指标--表格填写率
|
||||
async function fetchTableFillingRate() {
|
||||
const params={
|
||||
user_name: userStore.userInfo.username,
|
||||
user_level: userStore.userInfo.user_level.toString()
|
||||
}
|
||||
const params = getRequestParams()
|
||||
const hasParams = params.user_name
|
||||
try {
|
||||
const response = await getTableFillingRate(params)
|
||||
const response = await getTableFillingRate(hasParams ? params : undefined)
|
||||
statisticalIndicators.value.formCompletionRate = response.data
|
||||
} catch (error) {
|
||||
console.error('获取表格填写率失败:', error)
|
||||
@@ -332,12 +397,10 @@ const problemRanking = ref({})
|
||||
|
||||
// 客户迫切解决的问题
|
||||
async function fetchUrgentNeedToAddress() {
|
||||
const params={
|
||||
user_name: userStore.userInfo.username,
|
||||
user_level: userStore.userInfo.user_level.toString()
|
||||
}
|
||||
const params = getRequestParams()
|
||||
const hasParams = params.user_name
|
||||
try {
|
||||
const response = await getUrgentNeedToAddress(params)
|
||||
const response = await getUrgentNeedToAddress(hasParams ? params : undefined)
|
||||
problemRanking.value = response.data
|
||||
/**
|
||||
* "data": {
|
||||
@@ -398,12 +461,10 @@ async function fetchUrgentNeedToAddress() {
|
||||
const teamRanking = ref({})
|
||||
|
||||
async function fetchTeamRanking() {
|
||||
const params={
|
||||
user_name: userStore.userInfo.username,
|
||||
user_level: userStore.userInfo.user_level.toString(),
|
||||
}
|
||||
const params = getRequestParams()
|
||||
const hasParams = params.user_name
|
||||
try {
|
||||
const response = await getTeamRanking(params)
|
||||
const response = await getTeamRanking(hasParams ? params : undefined)
|
||||
teamRanking.value = response.data
|
||||
} catch (error) {
|
||||
console.error('获取团队业绩排名失败:', error)
|
||||
@@ -413,14 +474,19 @@ async function fetchTeamRanking() {
|
||||
// 团队业绩详情
|
||||
const teamPerformanceDetail = ref({})
|
||||
async function fetchTeamPerformanceDetail(department) {
|
||||
const params={
|
||||
const params = getRequestParams()
|
||||
const hasParams = params.user_name
|
||||
const requestParams = hasParams ? {
|
||||
...params,
|
||||
department: department
|
||||
} : {
|
||||
user_name: userStore.userInfo.username,
|
||||
user_level: userStore.userInfo.user_level.toString(),
|
||||
department: department
|
||||
}
|
||||
try {
|
||||
teamPerformanceDetail.value = {}
|
||||
const response = await getTeamRankingInfo(params)
|
||||
const response = await getTeamRankingInfo(requestParams)
|
||||
teamPerformanceDetail.value = response.data
|
||||
} catch (error) {
|
||||
console.error('获取团队业绩详情失败:', error)
|
||||
@@ -436,6 +502,7 @@ onMounted(async ()=>{
|
||||
await fetchTotalCallCount()
|
||||
await fetchNewCustomers()
|
||||
await fetchDepositConversions()
|
||||
await fetchAbnormalResponseRate()
|
||||
await fetchCustomerCommunicationRate()
|
||||
await fetchAverageResponseTime()
|
||||
await fetchTimeoutRate()
|
||||
@@ -485,6 +552,24 @@ const selectGroup = async (group) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 处理成员双击事件
|
||||
const handleMemberDoubleClick = (member) => {
|
||||
console.log('双击事件触发,成员数据:', member)
|
||||
|
||||
// 将成员等级写死为1,所有成员都可以跳转
|
||||
const memberLevel = 1
|
||||
console.log('等级设置为1,准备跳转到Sale页面')
|
||||
|
||||
// 跳转到Sale页面,携带成员姓名和等级
|
||||
router.push({
|
||||
name: 'Sale',
|
||||
query: {
|
||||
user_name: member.name,
|
||||
user_level: memberLevel
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 格式化货币
|
||||
const formatCurrency = (value) => {
|
||||
if (value >= 10000) {
|
||||
@@ -749,12 +834,18 @@ const getStatusText = (status) => {
|
||||
padding: 1rem;
|
||||
border: 1px solid #e2e8f0;
|
||||
transition: all 0.2s ease;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
&.status-excellent {
|
||||
border-left: 4px solid #10b981;
|
||||
background: linear-gradient(135deg, #ecfdf5 0%, #f0fdf4 100%);
|
||||
|
||||
Reference in New Issue
Block a user