Files
admin-vben5/apps/web-antd/src/views/property/customerService/centerConsole/index.vue
FLL 44e2c1fd4a
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
客户服务
2025-07-25 10:03:30 +08:00

349 lines
8.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import { EditOutlined } from '@ant-design/icons-vue';
import {EchartsUI, type EchartsUIType, useEcharts} from "@vben/plugins/echarts";
import {onMounted, ref} from "vue";
import {countsList} from '#/api/property/customerService/centerConsole'
import { useRouter } from 'vue-router'
const router = useRouter()
const board = ref ({})
const getBoard = async () => {
board.value = await countsList();
}
const xAxisData = ref<any[]>([]);
const seriesData = ref<any[]>([]);
// 工单计数
const workOrderCount = ref<EchartsUIType>();
const { renderEcharts: renderWorkOrderCount } = useEcharts(workOrderCount);
async function fetchWorkOrderCount() {
xAxisData.value = board.value.recentWeekWorkOrders.map(item => {
const [year, month, day] = item.date.split('-');
const monthDay = `${month}-${day}`;
return `${monthDay}${item.dayOfWeek}`;
});
seriesData.value = board.value.recentWeekWorkOrders.map(item => {
return `${item.count}`;
});
renderWorkOrderCount({
tooltip: { trigger: 'axis' },
xAxis: {
type: 'category',
boundaryGap: false,
data: xAxisData.value
},
yAxis: {
type: 'value',
name: '近一周工单数',
},
series: [
{
data: seriesData.value,
type: 'line',
areaStyle: {},
smooth: true,
}
]
});
}
// 满意度指数
const satisfactionLevel = ref<EchartsUIType>();
const { renderEcharts: renderSatisfactionLevel } = useEcharts(satisfactionLevel);
async function fetchSatisfactionLevel() {
seriesData.value = board.value.satisfactionRateList.map(item => {
return `${item.value}`;
})
renderSatisfactionLevel({
title: {text: '满意度指数',left: '18px'},
tooltip: { trigger: 'item'},
radar: {
indicator: [
{name: '1星'},
{name: '2星'},
{name: '3星'},
{name: '4星'},
{name: '5星'},
]
},
series: [
{
type: 'radar',
name: '满意度指数',
data: [
{
value: seriesData.value,
}
]
}
]
})
}
// 近半年工单数
const orderNumber = ref<EchartsUIType>();
const { renderEcharts: renderOrderNumber } = useEcharts(orderNumber);
async function fetchOrderNumber() {
seriesData.value = board.value.recentSixMonthWorkOrders.map(item => [
item.month, // 月份(对应目标结构的第一个元素)
item.orderCount // 工单数量(对应目标结构的第二个元素)
])
seriesData.value.unshift(['product','入驻员工'])
renderOrderNumber({
title: {text: '近半年工单数',left: '18px'},
legend: {},
tooltip: { trigger: 'axis' },
dataset: {
source: seriesData.value
},
xAxis: { type: 'category' },
yAxis: {},
series: [{ type: 'bar' }]
})
}
// 工单类型分类占比
const orderTyper = ref<EchartsUIType>();
const { renderEcharts: renderOrderTyper } = useEcharts(orderTyper);
async function fetchOrderTyper() {
seriesData.value = board.value.satisfactionChartList.map(item => {
return {
value: item.quantity,
name: item.type,
};
})
const totalQuantity = board.value.satisfactionChartList.reduce((sum, item) => {
return sum + Number(item.quantity || 0);
}, 0);
console.log(seriesData.value)
renderOrderTyper({
title: {text: '工单类型分类占比',left: '18px',top: '18px'},
tooltip: {
trigger: 'item'
},
legend: {
top: '40%',
right: '10%',
orient: 'vertical',
icon: 'circle',
itemWidth: 8,
itemHeight: 8
},
series: [
{
type: 'pie',
center: ['40%', '55%'],
radius: ['40%', '70%'],
label: {
show: true,
position: 'center',
formatter: [
'员工单数量',
`{num|${totalQuantity}个}`
].join('\n'),
fontSize: 14,
fontWeight: 'bold',
color: 'gray',
rich: {
num: {
fontSize: 18,
fontWeight: 'bolder',
color:'black',
padding: [10, 0, 0, 0],
}
}
},
avoidLabelOverlap: false,
labelLine: {
show: false
},
data: seriesData.value
}
]
})
}
const goOrderPool = () => {
router.push('/property/business/workOrders')
}
const goToDo = () => {
router.push('/property/business/workOrderPending')
}
onMounted(async () => {
await getBoard()
await fetchWorkOrderCount()
await fetchSatisfactionLevel()
await fetchOrderNumber()
await fetchOrderTyper()
})
</script>
<template>
<div class="panel">
<div class="bulletin-board">
<div class="bulletin-board-title">工单看板</div>
<div class="bulletin-board-content">
<div>
<div>
<div>工单总数</div>
<div>{{ board.workOrdersTotal }}</div>
<div style="color: #1890FF;cursor: pointer" @click="goOrderPool()">点击前往工单池</div>
</div>
<div class="icon-edit"><EditOutlined /></div>
</div>
<div>
<div>
<div>待派工单数</div>
<div>{{ board.notWorkOrdersTotal }}</div>
<div style="color: #1890FF;cursor: pointer" @click="goToDo()">点击前往工单待办</div>
</div>
<div class="icon-edit"><EditOutlined /></div>
</div>
<div>
<div>
<div>未办结超时工单</div>
<div>{{ board.novertimeOrdersTotal }}</div>
<div>处理中的工单数<span style="color: green">{{ board.inHandOrdersTotal }}</span></div>
</div>
<div class="icon-edit"><EditOutlined /></div>
</div>
<div>
<div>
<div>当月工单超时率</div>
<div>{{ board.novertimeOrdersRate }}%</div>
<div>超时工单数<span style="color: red">{{ board.outTimeOrdersTotal }}</span></div>
</div>
<div class="icon-edit"><EditOutlined /></div>
</div>
<div>
<div>
<div>当月满意度</div>
<div>{{ board.monthoSatisfaction }}%</div>
<div>满意度{{ board.satisfaction }}</div>
</div>
<div class="icon-edit"><EditOutlined /></div>
</div>
</div>
</div>
<div class="chart">
<div class="chart-one">
<div>
<div>
<div style="font-size: 20px;font-weight: bold;margin-bottom: 20px;color: #464646">工单计数</div>
<div style="margin-left: 20px;line-height: 30px">
<div>累计处理工单数</div>
<div>{{board.recentWeekWorkOrders?.[0]?.weekCount || '0'}}</div>
<!-- <div>累计回复数</div>-->
<!-- <div>2</div>-->
</div>
</div>
<EchartsUI
ref="workOrderCount"
height="400px"
width="100%"
style="background: #fff; border-radius: 8px;padding-top: 30px"
/>
</div>
<div>
<EchartsUI
ref="satisfactionLevel"
height="400px"
width="100%"
style="background: #fff; border-radius: 8px;padding-top: 18px"
/>
</div>
</div>
<div class="chart-two">
<div>
<EchartsUI
ref="orderNumber"
height="400px"
width="100%"
style="background: #fff; border-radius: 8px;padding-top: 18px"
/>
</div>
<div>
<EchartsUI
ref="orderTyper"
height="400px"
width="100%"
style="background: #fff; border-radius: 8px"
/>
</div>
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.panel{
width: 100%;
padding: 40px;
box-sizing: border-box;
.bulletin-board{
.bulletin-board-title{
font-size: 25px;
font-weight: bold;
margin-bottom: 20px;
}
.bulletin-board-content{
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 40px;
> div{
height: auto;
background-color: #FFFFFF;
padding: 18px;
border-radius: 10px;
display: flex;
justify-content: space-between;
> div:first-child {
line-height: 32px;
div:nth-child(2) {
font-size: 20px;
font-weight: bold;
}
}
.icon-edit{
font-size: 30px;
}
}
}
}
.chart{
.chart-one{
margin-top:40px;
display: grid;
grid-template-columns: 2fr 1fr;
gap: 40px;
>div:first-child{
background-color: #FFFFFF;
border-radius: 8px;
display: grid;
grid-template-columns: 1fr 6fr;
>div:first-child{
padding: 18px 0 0 18px;
}
}
}
.chart-two{
margin-top:40px;
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 40px;
}
}
}
</style>