From 180bc3c40643a640787b72e5880ff96e17c8c33c Mon Sep 17 00:00:00 2001 From: bunny <1319900154@qq.com> Date: Tue, 13 May 2025 20:04:27 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20=E7=A4=BE=E5=8C=BA=E5=B7=A6?= =?UTF-8?q?=E8=BE=B9=E5=92=8C=E4=B8=AD=E9=97=B4=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mock/community.ts | 94 ++++++++++----- src/api/community.ts | 14 +++ src/api/smartPark.ts | 6 +- .../DigitalNumber/DigitalNumber.tsx | 4 +- src/store/modules/community.ts | 35 +++++- src/store/modules/smartPark.ts | 18 ++- src/views/big-data/charts/left-body.tsx | 23 ++-- .../charts/right-bottom-chart.vue | 2 +- .../community/charts/conten-body-chart.tsx | 82 +++++++++++++ .../community/charts/left-body-chart.tsx | 67 +++++++++++ .../community/charts/left-header-chart.tsx | 109 ++++++++++++++++++ .../components/community-content.vue | 70 ++++++----- .../community/components/community-left.vue | 75 +++++++++++- .../components/smart-park-content.vue | 6 +- 14 files changed, 509 insertions(+), 96 deletions(-) create mode 100644 src/views/community/charts/conten-body-chart.tsx create mode 100644 src/views/community/charts/left-body-chart.tsx create mode 100644 src/views/community/charts/left-header-chart.tsx diff --git a/mock/community.ts b/mock/community.ts index e56c902..68cb57e 100644 --- a/mock/community.ts +++ b/mock/community.ts @@ -5,41 +5,81 @@ const randomNumber = (range: number = 100) => { }; export default defineFakeRoute([ + // 设备总数 + { + url: '/api/community/devices-amount', + method: 'GET', + response: () => ({ + code: 200, + data: [ + { name: '设备类型一', outside: randomNumber(), connect: randomNumber() }, + { name: '设备类型二', outside: randomNumber(), connect: randomNumber() }, + { name: '设备类型三', outside: randomNumber(), connect: randomNumber() }, + { name: '设备类型四', outside: randomNumber(), connect: randomNumber() }, + ], + message: '操作成功', + }), + }, + // 预警概览 + { + url: '/api/community/alarms-overview', + method: 'GET', + response: () => ({ + code: 200, + data: { + total: 500000, + list: Array(4) + .fill(0) + .map((_, index) => ({ name: `name-${index}`, value: randomNumber(9999) })), + }, + message: '操作成功', + }), + }, + // 中间顶部区域 { url: '/api/community/community-statistics', method: 'GET', response: () => ({ code: 200, - data: [ - { - name: '统计人口', + data: Array(4) + .fill(0) + .map((_, index) => ({ + name: `统计人口-${index + 1}`, total: randomNumber(9999), - subtitle: '常驻人口', + subtitle: `常驻人口${index + 1}`, subPercent: `${randomNumber()}%`, subTotal: randomNumber(99999), - }, - { - name: '统计人口', - total: randomNumber(9999), - subtitle: '常驻人口', - subPercent: `${randomNumber()}%`, - subTotal: randomNumber(99999), - }, - { - name: '统计人口', - total: randomNumber(9999), - subtitle: '常驻人口', - subPercent: `${randomNumber()}%`, - subTotal: randomNumber(99999), - }, - { - name: '统计人口', - total: randomNumber(9999), - subtitle: '常驻人口', - subPercent: `${randomNumber()}%`, - subTotal: randomNumber(99999), - }, - ], + })), + message: '操作成功', + }), + }, + // 中间区域设备运行状态 + { + url: '/api/community/devices-status', + method: 'GET', + response: () => ({ + code: 200, + data: { + devcies: [ + { + title: '正常运行总数', + total: randomNumber(100), + }, + { + title: '故障总数', + total: randomNumber(100), + }, + { + title: '故障总数', + total: randomNumber(100), + }, + { + title: '故障总数', + total: randomNumber(100), + }, + ], + security: randomNumber(), + }, message: '操作成功', }), }, diff --git a/src/api/community.ts b/src/api/community.ts index 6610482..0d0d650 100644 --- a/src/api/community.ts +++ b/src/api/community.ts @@ -1,6 +1,20 @@ import request from '@/api/server/request'; +/* 设备总数 */ +export const getCommunityDevicesAmount = () => { + return request.get('community/devices-amount'); +}; + +export const getAlarmsOverview = () => { + return request.get('community/alarms-overview'); +}; + /* 社区统计 */ export const getCommunityStatistics = () => { return request.get('community/community-statistics'); }; + +/* 设备运行状态 */ +export const getCommityDeicesStatus = () => { + return request.get('/community/devices-status'); +}; diff --git a/src/api/smartPark.ts b/src/api/smartPark.ts index 16d630c..e499867 100644 --- a/src/api/smartPark.ts +++ b/src/api/smartPark.ts @@ -1,16 +1,16 @@ import request from '@/api/server/request'; /* 实时道路 */ -export const fetchRoadStatus = () => { +export const gethRoadStatus = () => { return request.get('/smart-park/road-status'); }; /* 车辆监控 */ -export const fetchTollgateMonitoringData = () => { +export const getTollgateMonitoringData = () => { return request.get('smart-park/monitor'); }; /* 车流量概览 */ -export const fetchTrafficStatistics = () => { +export const getTrafficStatistics = () => { return request.get('/smart-park/flow-rate'); }; diff --git a/src/components/DigitalNumber/DigitalNumber.tsx b/src/components/DigitalNumber/DigitalNumber.tsx index bb61b5d..70e9934 100644 --- a/src/components/DigitalNumber/DigitalNumber.tsx +++ b/src/components/DigitalNumber/DigitalNumber.tsx @@ -21,11 +21,11 @@ export default defineComponent({ .flat(); return () => ( - <> +
{moneyStringList.map((item, index) => ( {item} ))} - +
); }, }); diff --git a/src/store/modules/community.ts b/src/store/modules/community.ts index b2c9f0d..62d9e21 100644 --- a/src/store/modules/community.ts +++ b/src/store/modules/community.ts @@ -1,15 +1,42 @@ import { defineStore } from 'pinia'; -import { getCommunityStatistics } from '@/api/community'; +import { + getAlarmsOverview, + getCommityDeicesStatus, + getCommunityDevicesAmount, + getCommunityStatistics, +} from '@/api/community'; export const useCommunityStore = defineStore('communityStore', { state: () => ({ - communityStatisticsList: [], + // 设备总数 + devicesList: [], + // 预警概览 + alarmOverviewList: [], + // 统计列表 + statisticsList: [], + // 设备状态 + deviceStatus: { devcies: [], security: undefined }, }), actions: { + /* 设备总数 */ + async fetchCommunityDevicesAmount() { + const result = await getCommunityDevicesAmount(); + this.devicesList = result; + }, + /* 预警概览 */ + async fetchAlarmsOverview() { + const result = await getAlarmsOverview(); + this.alarmOverviewList = result; + }, /* 社区统计 */ - async loadCommunityStatisticsList() { - this.communityStatisticsList = await getCommunityStatistics(); + async fetchCommunityStatisticsList() { + this.statisticsList = await getCommunityStatistics(); + }, + /* 设备状态 */ + async fetchCommityDeicesStatus() { + const result = await getCommityDeicesStatus(); + this.deviceStatus = result; }, }, }); diff --git a/src/store/modules/smartPark.ts b/src/store/modules/smartPark.ts index 5fc3f7b..eecb229 100644 --- a/src/store/modules/smartPark.ts +++ b/src/store/modules/smartPark.ts @@ -1,10 +1,6 @@ import { defineStore } from 'pinia'; -import { - fetchRoadStatus, - fetchTollgateMonitoringData, - fetchTrafficStatistics, -} from '@/api/smartPark'; +import { gethRoadStatus, getTollgateMonitoringData, getTrafficStatistics } from '@/api/smartPark'; export const useSmartPark = defineStore('smartparkStore', { state: () => ({ @@ -19,19 +15,19 @@ export const useSmartPark = defineStore('smartparkStore', { }), actions: { /* 道路情况 */ - async loadRoadStatus() { - const result: any = await fetchRoadStatus(); + async fetchRoadStatus() { + const result: any = await gethRoadStatus(); this.roadStatus = result.entrances; this.roadStatusSuggest = result.suggest; }, /* 卡口车辆监控 */ - async loadTollgateMonitoringData() { - const result = await fetchTollgateMonitoringData(); + async fetchTollgateMonitoringData() { + const result = await getTollgateMonitoringData(); this.tollgateMonitoringData = result; }, /* 车流量概览 */ - async loadFlowRate() { - const result = await fetchTrafficStatistics(); + async fetchFlowRate() { + const result = await getTrafficStatistics(); this.trafficStatistics = result; }, }, diff --git a/src/views/big-data/charts/left-body.tsx b/src/views/big-data/charts/left-body.tsx index 510fc2f..ab93f64 100644 --- a/src/views/big-data/charts/left-body.tsx +++ b/src/views/big-data/charts/left-body.tsx @@ -51,13 +51,25 @@ const renderEcharts: any = (myChart: Ref, element: Ref, props: any) => { + const series = myChart.value.getOption().series; + series[0].data[0].value = props.percent; + series[0].data[0].itemStyle = props.percent >= 20 ? itemStyles[0] : itemStyles[1]; + + myChart.value?.setOption({ series }); +}; + /* 封装组件 */ export const ChartProgress = defineComponent({ + name: 'ChartProgress', props: { percent: { type: Number } }, setup(props) { - const chart = ref(); + // 唯一的 Chart const myChart = ref(); + // 元素 + const chart = ref(); onMounted(() => { renderEcharts(myChart, chart); @@ -75,12 +87,3 @@ export const ChartProgress = defineComponent({ return () =>
; }, }); - -/** 更新图标数据 */ -const updateChart = (myChart: Ref, props: any) => { - const series = myChart.value.getOption().series; - series[0].data[0].value = props.percent; - series[0].data[0].itemStyle = props.percent >= 20 ? itemStyles[0] : itemStyles[1]; - - myChart.value?.setOption({ series }); -}; diff --git a/src/views/business-supervision/charts/right-bottom-chart.vue b/src/views/business-supervision/charts/right-bottom-chart.vue index 48fa3d5..905fa57 100644 --- a/src/views/business-supervision/charts/right-bottom-chart.vue +++ b/src/views/business-supervision/charts/right-bottom-chart.vue @@ -58,7 +58,7 @@ option.value = { type: 'pictorialBar', barWidth: 30, itemStyle: { color: '#0D3770' }, - symbolRepeat: 'true', + symbolRepeat: true, symbolMargin: 3, symbol: 'rect', symbolSize: [30, 4], diff --git a/src/views/community/charts/conten-body-chart.tsx b/src/views/community/charts/conten-body-chart.tsx new file mode 100644 index 0000000..5b2569f --- /dev/null +++ b/src/views/community/charts/conten-body-chart.tsx @@ -0,0 +1,82 @@ +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 option = ref({ + grid: { top: 0, right: 0, bottom: -100, left: 0, containLabel: true }, + series: [ + { + type: 'gauge', + startAngle: 180, + endAngle: 0, + center: ['50%', '75%'], + radius: '90%', + min: 0, + max: 1, + splitNumber: 8, + axisLine: { + lineStyle: { width: 12, color: [[1, '#05C1D3']] }, + }, + pointer: { + show: false, + icon: 'path://M12.8,0.7l12,40.1H0.7L12.8,0.7z', + length: '12%', + width: 20, + offsetCenter: [0, '-60%'], + itemStyle: { + color: 'auto', + }, + }, + axisTick: { + length: 44, + distance: -44, + lineStyle: { color: 'auto', width: 1 }, + }, + splitLine: { + length: 24, + distance: -24, + lineStyle: { color: 'auto', width: 8, miterLimit: 12 }, + }, + progress: { + show: true, + width: 14, + itemStyle: { color: '#707070' }, + }, + axisLabel: { show: false }, + detail: { + fontSize: 18, + offsetCenter: [0, '-9%'], + valueAnimation: true, + formatter: function (value) { + return Math.round(value * 100) + '\n安全指数'; + }, + color: '#05C1D3', + }, + data: [0.5], + }, + ], +}); + +/** 渲染图表 */ +export const renderBodyChart = (element: Ref) => { + myChart = echarts.init(element.value, null, { + renderer: 'canvas', + devicePixelRatio: window.devicePixelRatio, + }); + + debounceChart(myChart); + + myChart.setOption(option.value); +}; + +/** 更新图标数据 */ +export const updateBodyChart = (props: any) => { + const series = myChart?.getOption()?.series; + series[0].data = [props.data / 100]; + + myChart.setOption({ series }); +}; diff --git a/src/views/community/charts/left-body-chart.tsx b/src/views/community/charts/left-body-chart.tsx new file mode 100644 index 0000000..4deb5d6 --- /dev/null +++ b/src/views/community/charts/left-body-chart.tsx @@ -0,0 +1,67 @@ +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']; + +const option = ref({ + title: { + text: '34467', + subtext: '历史预警数', + left: 'center', + top: 'center', + textStyle: { color: '#fff', fontSize: 34 }, + subtextStyle: { color: '#fff', fontSize: 16 }, + }, + grid: { containLabel: false }, + polar: { radius: [60, '100%'] }, + angleAxis: { show: false, startAngle: 90 }, + radiusAxis: { show: false, type: 'category' }, + tooltip: {}, + series: { + type: 'bar', + data: [], + barWidth: 20, + barGap: 0, + coordinateSystem: 'polar', + itemStyle: {}, + label: { show: true, position: 'middle' }, + }, +}); + +/** 渲染图表 */ +export const renderBodyChart = (element: Ref) => { + myChart = echarts.init(element.value, null, { + renderer: 'canvas', + devicePixelRatio: window.devicePixelRatio, + }); + + debounceChart(myChart); + + myChart.setOption(option.value); +}; + +/** 更新图标数据 */ +export const updateBodyChart = (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 total = props.list.reduce((old, item) => old + item.value, 0); + // const angleAxis = myChart?.getOption()?.angleAxis; + // angleAxis[0].max = undefined; + + const title = myChart?.getOption()?.title; + title[0].text = total; + + myChart.setOption({ series, title }); +}; diff --git a/src/views/community/charts/left-header-chart.tsx b/src/views/community/charts/left-header-chart.tsx new file mode 100644 index 0000000..637cdc3 --- /dev/null +++ b/src/views/community/charts/left-header-chart.tsx @@ -0,0 +1,109 @@ +import 'echarts/lib/component/dataZoom'; + +import type { EChartsOption, EChartsType } from 'echarts'; +import { defineComponent, onMounted, type Ref, ref, watch } from 'vue'; + +import echarts from '@/plugins/echarts'; +import { debounceChart } from '@/utils/chart'; + +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: false }, + emphasis: { + focus: 'series', + }, + itemStyle: { + borderRadius: [10], + 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: false }, + itemStyle: { + borderRadius: [10], + 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!); + + debounceChart(myChart.value); +}; + +/** 更新图标数据 */ +const updateChart = (myChart: Ref, props: any) => { + const series = myChart.value.getOption().series; + series[0].data[0] = props.dataLeft; + series[1].data[0] = props.dataRight; + + myChart.value?.setOption({ series }); +}; + +const LeftHeaderChart = defineComponent({ + name: 'LeftHeaderChart', + props: { dataLeft: { type: Number }, dataRight: { type: Number } }, + setup(props) { + const myChartRef = ref(); + const chartRef = ref(); + + onMounted(() => { + renderLeftHeaderEcharts(myChartRef, chartRef); + + watch( + () => [props.dataLeft, () => props.dataRight], + () => { + updateChart(myChartRef, props); + }, + { immediate: true } + ); + }); + + return () =>
; + }, +}); + +export default LeftHeaderChart; diff --git a/src/views/community/components/community-content.vue b/src/views/community/components/community-content.vue index 3be69bf..a4101be 100644 --- a/src/views/community/components/community-content.vue +++ b/src/views/community/components/community-content.vue @@ -1,17 +1,35 @@ @@ -19,11 +37,7 @@ onMounted(() => {
    -
  • +
  • {{ item.name }}

    {{ item.total }}

    @@ -48,37 +62,29 @@ onMounted(() => {
-
-

80

+
+

{{ item.total }}

设备
- 正常运行总数 + {{ item.title }}
-
-

20

+
+
+

{{ item.total }}

设备
- 故障总数 -
-
-
xxxx
-
-

20

- - 设备 -
- 故障总数 -
-
-
-

98%

- - 设备 -
- 故障总数 + {{ item.title }}
@@ -196,8 +202,10 @@ onMounted(() => { /* 中间仪表盘内容 */ .community__instrument-panel { + padding: 20px; width: 286px; height: 169px; + color: #fff; background: url('../images/bg-body-instrument-panel.png'); } } diff --git a/src/views/community/components/community-left.vue b/src/views/community/components/community-left.vue index 11c297c..c7ca6d9 100644 --- a/src/views/community/components/community-left.vue +++ b/src/views/community/components/community-left.vue @@ -1,20 +1,67 @@ @@ -23,10 +70,30 @@ import CommonPanel from '@/views/community/components/CommonPanel.vue'; .community__sidebar { &-digital { width: 100%; + height: 100%; display: flex; - justify-content: flex-end; + flex-direction: column; + justify-content: space-between; - :deep(span) { + .progress-list { + display: flex; + flex-direction: column; + justify-items: center; + margin: 14px 0 0 0; + color: #fff; + + :deep(.progress) { + width: 100%; + height: 20px; + } + + &-content { + display: flex; + justify-content: space-between; + } + } + + :nth-child(1) :deep(span) { float: left; margin: 0 11px 0 0; width: 64px; diff --git a/src/views/smart-park/components/smart-park-content.vue b/src/views/smart-park/components/smart-park-content.vue index 599af2b..7fe38fd 100644 --- a/src/views/smart-park/components/smart-park-content.vue +++ b/src/views/smart-park/components/smart-park-content.vue @@ -15,9 +15,9 @@ const { roadStatus, roadStatusSuggest, tollgateMonitoringData, trafficStatistics storeToRefs(smartPark); const initData = () => { - smartPark.loadRoadStatus(); - smartPark.loadTollgateMonitoringData(); - smartPark.loadFlowRate(); + smartPark.fetchRoadStatus(); + smartPark.fetchTollgateMonitoringData(); + smartPark.fetchFlowRate(); updateChart({ enter: trafficStatistics.value.enter,