From 187f10bdc00daa3572f01707e8651f1e981cebaf Mon Sep 17 00:00:00 2001 From: FLL <2162874245@qq.com> Date: Wed, 23 Jul 2025 15:23:57 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=A2=E6=88=B7=E6=9C=8D=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../customerService/centerConsole/index.ts | 11 + .../workOrderPending/data.ts | 34 +++ .../workOrderPending/orders-modal.vue | 2 +- .../workOrderProcessed/data.ts | 34 +++ .../customerService/centerConsole/index.vue | 217 +++++++++++++++--- .../contingenPlan/contingenPlan-detail.vue | 26 ++- .../customerService/contingenPlan/data.ts | 4 +- 7 files changed, 287 insertions(+), 41 deletions(-) create mode 100644 apps/web-antd/src/api/property/customerService/centerConsole/index.ts diff --git a/apps/web-antd/src/api/property/customerService/centerConsole/index.ts b/apps/web-antd/src/api/property/customerService/centerConsole/index.ts new file mode 100644 index 00000000..74851739 --- /dev/null +++ b/apps/web-antd/src/api/property/customerService/centerConsole/index.ts @@ -0,0 +1,11 @@ +import { requestClient } from '#/api/request'; + +/** +* 查询客户服务工单看板统计 +* @param params +* @returns +*/ +export function countsList(params?:any) { + return requestClient.get('/property/customerServece/counts', { params }); +} + diff --git a/apps/web-antd/src/views/property/businessManagement/workOrderPending/data.ts b/apps/web-antd/src/views/property/businessManagement/workOrderPending/data.ts index e3d051d0..ab9a9656 100644 --- a/apps/web-antd/src/views/property/businessManagement/workOrderPending/data.ts +++ b/apps/web-antd/src/views/property/businessManagement/workOrderPending/data.ts @@ -1,6 +1,7 @@ import type {FormSchemaGetter} from '#/adapter/form'; import type {VxeGridProps} from '#/adapter/vxe-table'; import {renderDict} from "#/utils/render"; +import {getDictOptions} from "#/utils/dict"; export const querySchema: FormSchemaGetter = () => [ { @@ -62,4 +63,37 @@ export const columns: VxeGridProps['columns'] = [ }, ]; +export const ordersModalSchema: FormSchemaGetter = () => [ + { + label: 'id', + fieldName: 'id', + component: 'Input', + dependencies: { + show: () => false, + triggerFields: [''], + }, + }, + { + label: '状态', + fieldName: 'status', + component: 'Select', + componentProps: { + options: getDictOptions('wy_gdclzt'), + }, + rules: 'selectRequired', + disabled: true + }, + { + label: '处理人', + fieldName: 'handler', + component: 'ApiSelect', + formItemClass: 'col-span-2', + rules: 'selectRequired', + dependencies: { + disabled: (formValue) =>formValue.status === '2' , + triggerFields: ['status'], + }, + }, +] + diff --git a/apps/web-antd/src/views/property/businessManagement/workOrderPending/orders-modal.vue b/apps/web-antd/src/views/property/businessManagement/workOrderPending/orders-modal.vue index df252f63..d6697747 100644 --- a/apps/web-antd/src/views/property/businessManagement/workOrderPending/orders-modal.vue +++ b/apps/web-antd/src/views/property/businessManagement/workOrderPending/orders-modal.vue @@ -10,7 +10,7 @@ import {defaultFormValueGetter, useBeforeCloseDiff} from '#/utils/popup'; import {ordersModalSchema} from './data'; import {personList} from "#/api/property/resident/person"; import {renderDictValue} from "#/utils/render"; -import {onMounted, ref} from "vue"; +import {ref} from "vue"; import { useUserStore } from '@vben/stores'; const userStore = useUserStore(); diff --git a/apps/web-antd/src/views/property/businessManagement/workOrderProcessed/data.ts b/apps/web-antd/src/views/property/businessManagement/workOrderProcessed/data.ts index f283aa89..48c0982a 100644 --- a/apps/web-antd/src/views/property/businessManagement/workOrderProcessed/data.ts +++ b/apps/web-antd/src/views/property/businessManagement/workOrderProcessed/data.ts @@ -3,6 +3,7 @@ import type {VxeGridProps} from '#/adapter/vxe-table'; import {renderDict} from "#/utils/render"; import {h} from "vue"; import {Rate} from "ant-design-vue"; +import {getDictOptions} from "#/utils/dict"; export const querySchema: FormSchemaGetter = () => [ { @@ -103,3 +104,36 @@ export const columns: VxeGridProps['columns'] = [ width: 120, }, ]; + +export const ordersModalSchema: FormSchemaGetter = () => [ + { + label: 'id', + fieldName: 'id', + component: 'Input', + dependencies: { + show: () => false, + triggerFields: [''], + }, + }, + { + label: '状态', + fieldName: 'status', + component: 'Select', + componentProps: { + options: getDictOptions('wy_gdclzt'), + }, + rules: 'selectRequired', + disabled: true + }, + { + label: '处理人', + fieldName: 'handler', + component: 'ApiSelect', + formItemClass: 'col-span-2', + rules: 'selectRequired', + dependencies: { + disabled: (formValue) =>formValue.status === '2' , + triggerFields: ['status'], + }, + }, +] diff --git a/apps/web-antd/src/views/property/customerService/centerConsole/index.vue b/apps/web-antd/src/views/property/customerService/centerConsole/index.vue index 60d1df77..c9d1dc82 100644 --- a/apps/web-antd/src/views/property/customerService/centerConsole/index.vue +++ b/apps/web-antd/src/views/property/customerService/centerConsole/index.vue @@ -2,37 +2,158 @@ import { EditOutlined } from '@ant-design/icons-vue'; import {EchartsUI, type EchartsUIType, useEcharts} from "@vben/plugins/echarts"; import {onMounted, ref} from "vue"; -import {statisticsByTime} from "#/api/property/reportStatistics"; +import {countsList} from '#/api/property/customerService/centerConsole' -const orderLineRef = ref(); -const { renderEcharts } = useEcharts(orderLineRef); +const board = ref ({}) +const getBoard = async () => { + board.value = await countsList(); +} const xAxisData = ref([]); const seriesData = ref([]); -async function fetchOrderTrend() { - const res = await statisticsByTime({ timeUnit: 1 }); - xAxisData.value = res?.time ?? []; - seriesData.value = res?.counts ?? []; - renderEcharts({ - title: { text: '客户续租率趋势' }, + +// 工单计数 +const workOrderCount = ref(); +const { renderEcharts: renderWorkOrderCount } = useEcharts(workOrderCount); +async function fetchWorkOrderCount() { + xAxisData.value = board.value.recentWeekWorkOrders + console.log(xAxisData.value) + renderWorkOrderCount({ tooltip: { trigger: 'axis' }, xAxis: { type: 'category', - data: xAxisData.value, boundaryGap: false, + data: ['06-17周二', '06-17周二', '06-17周二', '06-17周二', '06-17周二', '06-17周二', '06-17周二'] + }, + yAxis: { + type: 'value', + name: '近一周工单数', }, - yAxis: { type: 'value', axisLabel: { formatter: (value) => `${value * 100}%` } }, series: [ { - name: '订单趋势', + data: [6, 2, 0, 1, 0, 0, 1], type: 'line', - data: seriesData.value || [], + areaStyle: {}, smooth: true, - }, - ], + } + ] }); } + +// 满意度指数 +const satisfactionLevel = ref(); +const { renderEcharts: renderSatisfactionLevel } = useEcharts(satisfactionLevel); +async function fetchSatisfactionLevel() { + renderSatisfactionLevel({ + title: {text: '满意度指数',left: '18px'}, + tooltip: { trigger: 'item'}, + radar: { + indicator: [ + {name: '1星', max: 1000}, + {name: '2星', max: 1000}, + {name: '3星', max: 1000}, + {name: '4星', max: 1000}, + {name: '5星', max: 1000}, + ] + }, + series: [ + { + type: 'radar', + name: '满意度指数', + data: [ + { + value: [500, 400, 800, 600, 400], + } + ] + } + ] + }) +} + +// 近半年工单数 +const orderNumber = ref(); +const { renderEcharts: renderOrderNumber } = useEcharts(orderNumber); +async function fetchOrderNumber() { + renderOrderNumber({ + title: {text: '近半年工单数',left: '18px'}, + legend: {}, + tooltip: { trigger: 'axis' }, + dataset: { + source: [ + ['product', '物业', '入驻员工'], + ['2025-01', 2, 5.8], + ['2025-02', 10.1, 7.4], + ['2025-03', 6.4, 5.2], + ['2025-04', 3.3, 5.8], + ['2025-05', 8.1, 7.4], + ['2025-06', 6.4, 5.2], + ] + }, + xAxis: { type: 'category' }, + yAxis: {}, + series: [{ type: 'bar' }, { type: 'bar' }] + }) +} + +// 工单类型分类占比 +const orderTyper = ref(); +const { renderEcharts: renderOrderTyper } = useEcharts(orderTyper); +async function fetchOrderTyper() { + 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: '员工单数量\n{num|56个}', + 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: [ + { value: 1048, name: 'Search Engine' }, + { value: 735, name: 'Direct' }, + { value: 580, name: 'Email' }, + { value: 484, name: 'Union Ads' }, + { value: 300, name: 'Video Ads' } + ] + } + ] + }) +} + onMounted(async () => { - await fetchOrderTrend(); + await getBoard() + await fetchWorkOrderCount() + await fetchSatisfactionLevel() + await fetchOrderNumber() + await fetchOrderTyper() }) @@ -45,7 +166,7 @@ onMounted(async () => {
工单总数:
-
56
+
{{ board.workOrdersTotal }}
点击前往工单池
@@ -53,7 +174,7 @@ onMounted(async () => {
待派工单数:
-
56
+
{{ board.notWorkOrdersTotal }}
点击前往工单待办
@@ -61,24 +182,24 @@ onMounted(async () => {
未办结超时工单:
-
56
-
处理中的工单数:5
+
{{ board.novertimeOrdersTotal }}
+
处理中的工单数:{{ board.inHandOrdersTotal }}
当月工单超时率:
-
56
-
超时工单数:0
+
{{ board.novertimeOrdersRate }}%
+
超时工单数:{{ board.outTimeOrdersTotal }}
当月满意度:
-
100%
-
满意度:5
+
{{ board.monthoSatisfaction }}%
+
满意度:{{ board.satisfaction }}
@@ -87,25 +208,48 @@ onMounted(async () => {
+
+
工单计数
+
+
累计处理工单数
+
12
+
累计回复数
+
2
+
+
+
+
+
-
+
+
+
-
@@ -158,6 +302,17 @@ onMounted(async () => { 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; diff --git a/apps/web-antd/src/views/property/customerService/contingenPlan/contingenPlan-detail.vue b/apps/web-antd/src/views/property/customerService/contingenPlan/contingenPlan-detail.vue index d245acf0..34d7f2e9 100644 --- a/apps/web-antd/src/views/property/customerService/contingenPlan/contingenPlan-detail.vue +++ b/apps/web-antd/src/views/property/customerService/contingenPlan/contingenPlan-detail.vue @@ -2,7 +2,7 @@ import type {ContingenPlanVO} from '#/api/property/customerService/contingenPlan/model'; import {shallowRef} from 'vue'; import {useVbenModal} from '@vben/common-ui'; -import {Descriptions, DescriptionsItem} from 'ant-design-vue'; +import {Descriptions, DescriptionsItem, Rate} from 'ant-design-vue'; import {contingenPlanInfo} from '#/api/property/customerService/contingenPlan'; import {renderDict} from "#/utils/render"; @@ -29,29 +29,41 @@ async function handleOpenChange(open: boolean) { diff --git a/apps/web-antd/src/views/property/customerService/contingenPlan/data.ts b/apps/web-antd/src/views/property/customerService/contingenPlan/data.ts index 56343370..aef7829e 100644 --- a/apps/web-antd/src/views/property/customerService/contingenPlan/data.ts +++ b/apps/web-antd/src/views/property/customerService/contingenPlan/data.ts @@ -68,7 +68,7 @@ export const columns: VxeGridProps['columns'] = [ }, { title: '发起人', - field: 'initiat', + field: 'initiatName', }, { title: '演练状态', @@ -81,7 +81,7 @@ export const columns: VxeGridProps['columns'] = [ }, { title: '责任人', - field: 'dutyPersion', + field: 'dutyPersionName', }, { title: '完成时间',