From cf1a91f38fe89a1497154c28b5739b6b216f0894 Mon Sep 17 00:00:00 2001 From: bunny <1319900154@qq.com> Date: Fri, 16 May 2025 21:55:58 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20=E7=A4=BE=E5=8C=BA=E5=AE=8C?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/server.ts | 2 +- mock/bid-data.ts | 2 +- mock/community.ts | 45 ++++++- mock/smart-park.ts | 8 +- package.json | 4 +- src/api/bigData.ts | 2 +- src/api/community.ts | 14 ++- src/api/smartPark.ts | 4 +- src/store/modules/community.ts | 30 +++-- src/store/modules/smartPark.ts | 4 +- .../community/charts/left-footer-chart.tsx | 1 - src/views/community/charts/right-body.tsx | 0 src/views/community/charts/right-footer.tsx | 115 ++++++++++++++++++ src/views/community/charts/right-header.tsx | 56 +++++++++ .../components/community-content.vue | 6 +- .../community/components/community-left.vue | 2 +- .../community/components/community-right.vue | 64 +++++++++- 17 files changed, 323 insertions(+), 36 deletions(-) delete mode 100644 src/views/community/charts/right-body.tsx create mode 100644 src/views/community/charts/right-footer.tsx create mode 100644 src/views/community/charts/right-header.tsx diff --git a/build/server.ts b/build/server.ts index 6ec5454..87da10a 100644 --- a/build/server.ts +++ b/build/server.ts @@ -16,7 +16,7 @@ export const server = (mode: string) => { '/api': { target: VITE_APP_URL, changeOrigin: true, - rewrite: (path: string) => path.replace(/^\/admin/, '/api'), + rewrite: (path: string) => path.replace(/^\/api/, '/api'), }, '/mock': { target: VITE_APP_URL, diff --git a/mock/bid-data.ts b/mock/bid-data.ts index 7f6ab57..bb5a67e 100644 --- a/mock/bid-data.ts +++ b/mock/bid-data.ts @@ -1,6 +1,6 @@ import { defineFakeRoute } from 'vite-plugin-fake-server'; -const BASE_URL = '/api/big-data'; +const BASE_URL = '/mock/big-data'; const randomNumber = (range: number = 100) => { return parseInt((Math.random() * range).toFixed(0)); diff --git a/mock/community.ts b/mock/community.ts index b5e9b95..681e8a5 100644 --- a/mock/community.ts +++ b/mock/community.ts @@ -1,5 +1,7 @@ import { defineFakeRoute } from 'vite-plugin-fake-server/client'; +const BASE_URL = '/mock/community'; + const randomNumber = (range: number = 100) => { return parseInt((Math.random() * range).toFixed(0)); }; @@ -7,7 +9,7 @@ const randomNumber = (range: number = 100) => { export default defineFakeRoute([ // 设备总数 { - url: '/api/community/devices-amount', + url: `${BASE_URL}/devices-amount`, method: 'GET', response: () => ({ code: 200, @@ -25,7 +27,7 @@ export default defineFakeRoute([ }, // 预警概览 { - url: '/api/community/alarms-overview', + url: `${BASE_URL}/alarms-overview`, method: 'GET', response: () => ({ code: 200, @@ -40,7 +42,7 @@ export default defineFakeRoute([ }, // 中间顶部区域 { - url: '/api/community/community-statistics', + url: `${BASE_URL}/community-statistics`, method: 'GET', response: () => ({ code: 200, @@ -58,12 +60,12 @@ export default defineFakeRoute([ }, // 中间区域设备运行状态 { - url: '/api/community/devices-status', + url: `${BASE_URL}/devices-status`, method: 'GET', response: () => ({ code: 200, data: { - devcies: [ + devices: [ { title: '正常运行总数', total: randomNumber(100), @@ -86,4 +88,37 @@ export default defineFakeRoute([ message: '操作成功', }), }, + // 数据统计 + { + url: `${BASE_URL}/data-statistics`, + method: 'GET', + response: () => ({ + code: 200, + data: [ + { name: '园区面积', value: randomNumber(9999) }, + { name: '绿化面积', value: randomNumber(9999) }, + { name: '道路面积', value: randomNumber(9999) }, + { name: '新能源车', value: randomNumber(9999) }, + { name: '安防在线率', value: randomNumber(9999) }, + { name: '安防在线率', value: randomNumber(9999) }, + ], + message: '操作成功', + }), + }, + // 服务项目 + { + url: `${BASE_URL}/server-project`, + method: 'GET', + response: () => ({ + code: 200, + data: Array(15) + .fill(0) + .map((_, index) => ({ + name: `服务项目-${index}`, + left: randomNumber(), + right: randomNumber(), + })), + message: '操作成功', + }), + }, ]); diff --git a/mock/smart-park.ts b/mock/smart-park.ts index 70a628b..d44ac35 100644 --- a/mock/smart-park.ts +++ b/mock/smart-park.ts @@ -1,5 +1,7 @@ import { defineFakeRoute } from 'vite-plugin-fake-server'; +const BASE_URL = '/mock/smart-park'; + const randomNumber = (range: number = 100) => { return parseInt((Math.random() * range).toFixed(0)); }; @@ -14,7 +16,7 @@ const mockRoadStatus = () => { export default defineFakeRoute([ // 道路状况 { - url: '/api/smart-park/road-status', + url: `${BASE_URL}/road-status`, method: 'GET', response: () => ({ code: 200, @@ -50,7 +52,7 @@ export default defineFakeRoute([ }, // 车辆监控 { - url: '/api/smart-park/monitor', + url: `${BASE_URL}/monitor`, method: 'GET', response: () => ({ code: 200, @@ -65,7 +67,7 @@ export default defineFakeRoute([ }, // 车流量 { - url: '/api/smart-park/flow-rate', + url: `${BASE_URL}/flow-rate`, method: 'GET', response: () => ({ code: 200, diff --git a/package.json b/package.json index 09845e9..83f8ebc 100644 --- a/package.json +++ b/package.json @@ -72,12 +72,12 @@ "@vitejs/plugin-vue": "^5.2.1", "@vue/tsconfig": "^0.7.0", "eslint-plugin-simple-import-sort": "^12.1.1", + "jiti": "^2.4.2", "typescript": "~5.7.2", "vite": "6.2.6", "vite-plugin-compression": "^0.5.1", - "vue-tsc": "^2.2.0", "vite-plugin-vue-devtools": "^7.7.2", - "jiti": "^2.4.2" + "vue-tsc": "^2.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0", diff --git a/src/api/bigData.ts b/src/api/bigData.ts index eb7f4ac..99f4349 100644 --- a/src/api/bigData.ts +++ b/src/api/bigData.ts @@ -1,4 +1,4 @@ -import request from '@/api/server/request'; +import request from '@/api/server/requestMock'; /* 规模效益 */ export const getScaleProfit = (data: any) => { diff --git a/src/api/community.ts b/src/api/community.ts index 0d0d650..986005c 100644 --- a/src/api/community.ts +++ b/src/api/community.ts @@ -1,4 +1,4 @@ -import request from '@/api/server/request'; +import request from '@/api/server/requestMock'; /* 设备总数 */ export const getCommunityDevicesAmount = () => { @@ -15,6 +15,16 @@ export const getCommunityStatistics = () => { }; /* 设备运行状态 */ -export const getCommityDeicesStatus = () => { +export const getCommunityDeicesStatus = () => { return request.get('/community/devices-status'); }; + +/* 数据统计 */ +export const getDataStatistics = () => { + return request.get('community/data-statistics'); +}; + +/* 右侧底部服务项目 */ +export const getServerProject = () => { + return request.get('community/server-project'); +}; diff --git a/src/api/smartPark.ts b/src/api/smartPark.ts index e499867..451aafb 100644 --- a/src/api/smartPark.ts +++ b/src/api/smartPark.ts @@ -1,7 +1,7 @@ -import request from '@/api/server/request'; +import request from '@/api/server/requestMock'; /* 实时道路 */ -export const gethRoadStatus = () => { +export const getRoadStatus = () => { return request.get('/smart-park/road-status'); }; diff --git a/src/store/modules/community.ts b/src/store/modules/community.ts index 5232a4c..7fdf79e 100644 --- a/src/store/modules/community.ts +++ b/src/store/modules/community.ts @@ -2,9 +2,11 @@ import { defineStore } from 'pinia'; import { getAlarmsOverview, - getCommityDeicesStatus, + getCommunityDeicesStatus, getCommunityDevicesAmount, getCommunityStatistics, + getDataStatistics, + getServerProject, } from '@/api/community'; export const useCommunityStore = defineStore('communityStore', { @@ -16,28 +18,36 @@ export const useCommunityStore = defineStore('communityStore', { // 统计列表 statisticsList: [], // 设备状态 - deviceStatus: { devcies: [], security: 0 }, + deviceStatus: { devices: [], security: 0 }, + // 数据统计 + dataStatistics: [], + // 右侧底部服务项目 + serverProject: [], }), actions: { /* 设备总数 */ async fetchCommunityDevicesAmount() { - const result = await getCommunityDevicesAmount(); - - this.devicesList = result; + this.devicesList = await getCommunityDevicesAmount(); }, /* 预警概览 */ async fetchAlarmsOverview() { - const result = await getAlarmsOverview(); - this.alarmOverviewList = result; + this.alarmOverviewList = await getAlarmsOverview(); }, /* 社区统计 */ async fetchCommunityStatisticsList() { this.statisticsList = await getCommunityStatistics(); }, /* 设备状态 */ - async fetchCommityDeicesStatus() { - const result = await getCommityDeicesStatus(); - this.deviceStatus = result; + async fetchCommunityDeicesStatus() { + this.deviceStatus = await getCommunityDeicesStatus(); + }, + /* 数据统计 */ + async fetchDataStatistics() { + this.dataStatistics = await getDataStatistics(); + }, + /* 右侧底部服务项目 */ + async fetchServerProject() { + this.serverProject = await getServerProject(); }, }, }); diff --git a/src/store/modules/smartPark.ts b/src/store/modules/smartPark.ts index eecb229..6fcd71e 100644 --- a/src/store/modules/smartPark.ts +++ b/src/store/modules/smartPark.ts @@ -1,6 +1,6 @@ import { defineStore } from 'pinia'; -import { gethRoadStatus, getTollgateMonitoringData, getTrafficStatistics } from '@/api/smartPark'; +import { getRoadStatus, getTollgateMonitoringData, getTrafficStatistics } from '@/api/smartPark'; export const useSmartPark = defineStore('smartparkStore', { state: () => ({ @@ -16,7 +16,7 @@ export const useSmartPark = defineStore('smartparkStore', { actions: { /* 道路情况 */ async fetchRoadStatus() { - const result: any = await gethRoadStatus(); + const result: any = await getRoadStatus(); this.roadStatus = result.entrances; this.roadStatusSuggest = result.suggest; }, diff --git a/src/views/community/charts/left-footer-chart.tsx b/src/views/community/charts/left-footer-chart.tsx index 4929699..b380230 100644 --- a/src/views/community/charts/left-footer-chart.tsx +++ b/src/views/community/charts/left-footer-chart.tsx @@ -7,7 +7,6 @@ import { debounceChart } from '@/utils/chart'; let myChart = null; /* 随机颜色 */ - const colors = ['#3D7FFF', '#00FFFF', '#FF1190', '#FEDB65']; const option = ref({ diff --git a/src/views/community/charts/right-body.tsx b/src/views/community/charts/right-body.tsx deleted file mode 100644 index e69de29..0000000 diff --git a/src/views/community/charts/right-footer.tsx b/src/views/community/charts/right-footer.tsx new file mode 100644 index 0000000..9cd6e5b --- /dev/null +++ b/src/views/community/charts/right-footer.tsx @@ -0,0 +1,115 @@ +import 'echarts/lib/component/dataZoom'; + +import type { EChartsOption } from 'echarts'; +import { defineComponent, onMounted, type Ref, ref, watch } from 'vue'; + +import echarts from '@/plugins/echarts'; + +const option = ref({ + tooltip: { + trigger: 'axis', + axisPointer: { type: 'line' }, + }, + grid: { + top: 0, + left: '0', + right: '0', + bottom: '0', + containLabel: false, + }, + xAxis: { show: false, type: 'value' }, + yAxis: { show: false, type: 'category' }, + series: [ + { + name: 'Direct', + type: 'bar', + stack: 'total', + label: { show: true, formatter: ({ value }) => `${value}%`, fontWeight: 1000, fontSize: 14 }, + emphasis: { + focus: 'series', + }, + itemStyle: { + borderRadius: [4], + color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [ + { offset: 0, color: '#17EAFE' }, + { offset: 1, color: '#009CD7' }, + ]), + }, + barWidth: 20, + data: [320], + }, + { + type: 'bar', + stack: 'total', + label: { show: true, formatter: ({ value }) => `${value}%`, fontWeight: 1000, fontSize: 14 }, + itemStyle: { + borderRadius: [4], + color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [ + { offset: 0, color: '#00FFBC' }, + { offset: 1, color: '#09ADA7' }, + ]), + }, + barWidth: 20, + emphasis: { + focus: 'series', + }, + data: [120], + }, + ], +}); + +/** 绘制图表 */ +export const renderLeftHeaderEcharts: any = ( + myChart: Ref, + element: Ref +) => { + myChart.value = echarts.init(element.value, null, { + renderer: 'canvas', + devicePixelRatio: window.devicePixelRatio, + }); + + myChart.value?.setOption(option.value); +}; + +/** 更新图标数据 */ +const updateChart = (myChart: Ref, props: any) => { + const series = myChart.value.getOption().series; + const sum = props.dataLeft + props.dataRight; + const right = +(props.dataRight / sum).toFixed(2); + const left = +(props.dataLeft / sum).toFixed(2); + + series[0].data[0] = Math.round(left * 100); + series[1].data[0] = Math.round(right * 100); + + myChart.value?.setOption({ series }); +}; + +const RightFooterChart = defineComponent({ + name: 'RightFooterChart', + props: { dataLeft: { type: Number }, dataRight: { type: Number }, title: { type: String } }, + setup(props) { + const myChartRef = ref(); + const chartRef = ref(); + + onMounted(() => { + renderLeftHeaderEcharts(myChartRef, chartRef); + updateChart(myChartRef, props); + + watch( + () => [props.dataLeft, () => props.dataRight], + () => { + updateChart(myChartRef, props); + } + ); + }); + + return () => ( +
+ {props.title} +
+
+ ); + }, +}); + +export default RightFooterChart; diff --git a/src/views/community/charts/right-header.tsx b/src/views/community/charts/right-header.tsx new file mode 100644 index 0000000..718d5b0 --- /dev/null +++ b/src/views/community/charts/right-header.tsx @@ -0,0 +1,56 @@ +import type { EChartsOption } from 'echarts'; +import { type Ref, ref } from 'vue'; + +import echarts from '@/plugins/echarts'; +import { debounceChart } from '@/utils/chart'; + +let myChart = null; + +/* 随机颜色 */ +const colors = ['#3D7FFF', '#00FFFF', '#FF1190', '#FEDB65', '#FE9B45']; + +const option = ref({ + backgroundColor: 'transparent', + grid: { top: 0, right: 0, bottom: 0, left: 0, containLabel: true }, + tooltip: { trigger: 'item' }, + series: [ + { + name: '名称', + type: 'pie', + radius: [14, 100], + center: ['50%', '50%'], + roseType: 'area', + itemStyle: { borderRadius: 4 }, + data: [], + label: { distanceToLabelLine: 4, position: 'insideBottom' }, + labelLine: { show: true, length: 1, length2: 0, smooth: true }, + }, + ], +}); + +/** 渲染图表 */ +export const renderRightHeaderChart = (element: Ref) => { + myChart = echarts.init(element.value, null, { + renderer: 'canvas', + devicePixelRatio: window.devicePixelRatio, + }); + + debounceChart(myChart); + + myChart.setOption(option.value); +}; + +/** 更新图标数据 */ +export const updateRightHeaderChart = (props: any) => { + const series = myChart?.getOption()?.series; + + series[0].data = props.list?.map((item, index) => ({ + name: item.name, + value: item.value, + itemStyle: { color: colors[index], borderRadius: 10 }, + })); + + const title = myChart?.getOption()?.title; + + myChart.setOption({ series, title }); +}; diff --git a/src/views/community/components/community-content.vue b/src/views/community/components/community-content.vue index 88648dc..999e227 100644 --- a/src/views/community/components/community-content.vue +++ b/src/views/community/components/community-content.vue @@ -18,7 +18,7 @@ const securityCharRef = ref(); /* 初始化数据 */ const initData = async () => { await communityStore.fetchCommunityStatisticsList(); - await communityStore.fetchCommityDeicesStatus(); + await communityStore.fetchCommunityDeicesStatus(); updateBodyChart({ data: deviceStatus.value.security }); }; @@ -63,7 +63,7 @@ onMounted(() => {
@@ -76,7 +76,7 @@ onMounted(() => {
diff --git a/src/views/community/components/community-left.vue b/src/views/community/components/community-left.vue index 92f565c..adc1c0c 100644 --- a/src/views/community/components/community-left.vue +++ b/src/views/community/components/community-left.vue @@ -5,7 +5,7 @@ import { onMounted, ref } from 'vue'; import DigitalNumber from '@/components/DigitalNumber/DigitalNumber'; import { useCommunityStore } from '@/store/modules/community'; -import { renderBodyChart, updateBodyChart } from '@/views/community/charts/left-body-chart'; +import { renderBodyChart, updateBodyChart } from '@/views/community/charts/left-footer-chart'; import LeftHeaderChart from '@/views/community/charts/left-header-chart'; import CommonPanel from '@/views/community/components/CommonPanel.vue'; diff --git a/src/views/community/components/community-right.vue b/src/views/community/components/community-right.vue index 451e46f..410b235 100644 --- a/src/views/community/components/community-right.vue +++ b/src/views/community/components/community-right.vue @@ -1,20 +1,80 @@