Files
admin-vben5/apps/web-antd/src/views/property/customerService/centerConsole/index.vue

349 lines
8.7 KiB
Vue
Raw Normal View History

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