From 8a65f4690c60ed4b935d6ad69686656c9b1c2a08 Mon Sep 17 00:00:00 2001 From: fengerli <528575642@qq.com> Date: Tue, 9 Sep 2025 17:02:39 +0800 Subject: [PATCH] =?UTF-8?q?=E9=A6=96=E9=A1=B5=E5=9B=BE=E8=A1=A8=E5=8A=A8?= =?UTF-8?q?=E6=80=81=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/home/index.ts | 21 +- .../equipmentManagement/devices/index.vue | 4 - src/views/index.vue | 372 ++++++++++-------- 3 files changed, 234 insertions(+), 163 deletions(-) diff --git a/src/api/home/index.ts b/src/api/home/index.ts index bdf8456..2524e7b 100644 --- a/src/api/home/index.ts +++ b/src/api/home/index.ts @@ -16,9 +16,28 @@ export const getEquipmentClassification = (params) => { params: params }); }; +// 获取设备使用情况 +export const getEquipmentUsageData = (range, params = {}) => { + return request({ + url: `/api/device/homepage/getEquipmentUsageData/${range}`, + method: 'get', + params: params + }); +}; + +// 获取报警信息 +export const getAlarmInformation = (params) => { + return request({ + url: `/api/device/homepage/getAlarmInformation`, + method: 'get', + params: params + }); +}; export default { getDataOverview, - getEquipmentClassification + getEquipmentClassification, + getEquipmentUsageData, + getAlarmInformation } \ No newline at end of file diff --git a/src/views/equipmentManagement/devices/index.vue b/src/views/equipmentManagement/devices/index.vue index 5d32c52..d219b27 100644 --- a/src/views/equipmentManagement/devices/index.vue +++ b/src/views/equipmentManagement/devices/index.vue @@ -565,21 +565,17 @@ const handleDeviceTypeChange = async (deviceTypeId: string | number) => { //两个都有值:显示两个字段 + 都加校验 showMacField.value = true; showImeiField.value = true; - rules.value.deviceMac = [{ required: true, message: '请输入设备MAC', trigger: 'blur' }]; - rules.value.deviceImei = [{ required: true, message: '请输入设备IMEI', trigger: 'blur' }]; console.log('两个字段都有值'); } else if (hasMac) { showMacField.value = true; showImeiField.value = false; - rules.value.deviceMac = [{ required: true, message: '请输入设备MAC', trigger: 'blur' }]; rules.value.deviceImei = []; console.log('只有 Mac 有值'); } else if (hasImei) { showImeiField.value = true; showMacField.value = false; - rules.value.deviceImei = [{ required: true, message: '请输入设备IMEI', trigger: 'blur' }]; rules.value.deviceMac = []; console.log('只有 Imei 有值'); } diff --git a/src/views/index.vue b/src/views/index.vue index 552b9ab..04cae75 100644 --- a/src/views/index.vue +++ b/src/views/index.vue @@ -77,14 +77,21 @@

设备使用频次

- - + +
+
+ 近半年 +
+
+ 近一年 +
+
@@ -105,12 +112,12 @@
-
-
365
+
+
{{ alarmsData.alarmsTotal }}
报警总数
-
-
300
+
+
{{ alarmsData.processingAlarm }}
总处理报警
@@ -148,6 +155,8 @@ const DataOverview = ref({ }); const deviceTypeOptions = ref([]); //设备类型 const deviceType = ref() +const activeTab = ref('1'); +const alarmsData = ref() // ---------------------- 基础数据 ---------------------- // 设备分类数据 const deviceList = ref([ @@ -155,9 +164,6 @@ const deviceList = ref([ { name: "蓝牙设备", current: 0, total: 0 }, { name: "4G&蓝牙设备", current: 0, total: 0 }, ]); -// 时间范围(控制设备使用频次图表) -const timeRange = ref('halfYear'); - // ---------------------- 图表Ref(用于挂载图表实例) ---------------------- const frequencyChartRef = ref(null); // 设备使用频次折线图 const alarmRingChartRef = ref(null); // 报警环形图 @@ -183,141 +189,155 @@ const handleControlPanel = () => { }; // ---------------------- 图表初始化方法 ---------------------- -/** - * 1. 设备使用频次折线图 - */ -const initFrequencyChart = () => { +const initFrequencyChart = async (range: any = '1', deviceTypeId: any) => { if (!frequencyChartRef.value) return; - - // 初始化图表实例 frequencyChartInstance = echarts.init(frequencyChartRef.value); - - // 假数据:按时间范围区分 - const chartData = timeRange.value === 'halfYear' - ? { - xAxis: ['1月', '2月', '3月', '4月', '5月', '6月'], - yAxis: [320, 280, 450, 380, 520, 480], // 近半年使用次数 - peak: { name: '峰值', value: 520, month: '5月' } + try { + let data = { + deviceTypeId: deviceTypeId } - : { - xAxis: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'], - yAxis: [320, 280, 450, 380, 520, 480, 550, 620, 580, 490, 530, 650], // 近一年使用次数 - peak: { name: '峰值', value: 650, month: '12月' } + const res = await api.getEquipmentUsageData(range, data); + const monthData = res.data[0] || {}; + const monthKeys = ['m1', 'm2', 'm3', 'm4', 'm5', 'm6', 'm7', 'm8', 'm9', 'm10', 'm11', 'm12']; + const monthNames = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']; + // 3. 计算时间范围(核心逻辑) + let filteredKeys, filteredNames, yAxisData; + const today = new Date(); + const currentMonth = today.getMonth(); + if (range === '1') { + const result = []; + for (let i = 0; i < 6; i++) { + const targetMonth = (currentMonth - i + 12) % 12; + result.push(targetMonth); + } + const recent6Months = result.reverse(); + // 匹配接口字段和名称 + filteredKeys = recent6Months.map(monthIndex => monthKeys[monthIndex]); + filteredNames = recent6Months.map(monthIndex => monthNames[monthIndex]); + yAxisData = filteredKeys.map(key => monthData[key] || 0); + } else { + // 近一年:全部12个月(1月→12月) + filteredKeys = monthKeys; + filteredNames = monthNames; + yAxisData = filteredKeys.map(key => monthData[key] || 0); + } + const chartData = { + xAxis: filteredNames, + yAxis: yAxisData, + peak: { name: '峰值', value: 0, month: '' } }; - - // ECharts配置项 - const option = { - tooltip: { - trigger: 'axis', - formatter: '{b}: {c} 次' - }, - grid: { - left: '3%', - right: '4%', - bottom: '3%', - containLabel: true - }, - xAxis: { - type: 'category', - data: chartData.xAxis, - axisLabel: { - interval: 0 // 强制显示所有x轴标签 - } - }, - yAxis: { - type: 'value', - name: '使用次数', - min: 0, - max: Math.max(...chartData.yAxis) + 100 // y轴最大值留有余量 - }, - series: [ - { - name: '使用频次', - type: 'line', - data: chartData.yAxis, - smooth: false, // 平滑折线 - lineStyle: { - width: 3, - color: '#409eff' - }, - itemStyle: { - color: '#409eff', - radius: 5 - }, - areaStyle: { - color: { - type: 'linear', - x: 0, - y: 0, - x2: 0, - y2: 1, - colorStops: [{ - offset: 0, color: 'rgba(64, 158, 255, 0.3)' - }, { - offset: 1, color: 'rgba(64, 158, 255, 0)' - }] - } - }, - // 标记峰值 - markPoint: { - data: [{ - name: chartData.peak.name, - value: chartData.peak.value, - xAxis: chartData.xAxis.indexOf(chartData.peak.month), - yAxis: chartData.peak.value, - itemStyle: { - color: '#ff4d4f' + if (yAxisData.length) { + const maxVal = Math.max(...yAxisData); + const maxIndex = yAxisData.indexOf(maxVal); + chartData.peak = { + name: '峰值', + value: maxVal, + month: chartData.xAxis[maxIndex] || '' + }; + } + const option = { + tooltip: { trigger: 'axis', formatter: '{b}: {c} 次' }, + grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true }, + xAxis: { + type: 'category', + data: chartData.xAxis, + axisLabel: { interval: 0 } + }, + yAxis: { + type: 'value', + name: '使用次数', + min: 0, + max: chartData.yAxis.length ? Math.max(...chartData.yAxis) + 100 : 100 + }, + series: [ + { + name: '使用频次', + type: 'line', + data: chartData.yAxis, + smooth: false, + lineStyle: { width: 3, color: '#409eff' }, + itemStyle: { color: '#409eff', radius: 5 }, + areaStyle: { + color: { + type: 'linear', + x: 0, y: 0, x2: 0, y2: 1, + colorStops: [ + { offset: 0, color: 'rgba(64, 158, 255, 0.3)' }, + { offset: 1, color: 'rgba(64, 158, 255, 0)' } + ] } - }] + }, + markPoint: { + data: chartData.peak.value + ? [{ + name: chartData.peak.name, + value: chartData.peak.value, + xAxis: chartData.xAxis.indexOf(chartData.peak.month), + yAxis: chartData.peak.value, + itemStyle: { color: '#409eff' } + }] + : [] + } } - } - ] - }; - - // 渲染图表 - frequencyChartInstance.setOption(option); + ] + }; + frequencyChartInstance.setOption(option); + } catch (error) { + } }; - /** * 2. 报警环形图(今日报警处理占比) */ -const initAlarmRingChart = () => { +const initAlarmRingChart = async () => { if (!alarmRingChartRef.value) return; - alarmRingChartInstance = echarts.init(alarmRingChartRef.value); - - // 假数据:今日报警6次,已处理6次 - const option = { - tooltip: { - trigger: 'item', - formatter: '{b}: {c} 次 ({d}%)' - }, - series: [ - { - type: 'pie', - radius: ['50%', '60%'], // 环形半径 - center: ['50%', '50%'], // 居中显示 - avoidLabelOverlap: false, - label: { - show: true, - position: 'center', - formatter: '6/6\n今日报警/处理', // 中心显示“今日 已处理/总数” - fontSize: 16, - fontWeight: 'bold', - color: '#333' - }, - labelLine: { - show: false - }, - data: [ - { value: 6, name: '已处理报警', itemStyle: { color: '#07BE75' } }, - { value: 0, name: '未处理报警', itemStyle: { color: '#F65757' } } - ] - } - ] - }; - - alarmRingChartInstance.setOption(option); + try { + const res = await api.getAlarmInformation({}); + const { alarmsTotalToday = 0, processingAlarmToday = 0 } = res.data || {}; + alarmsData.value = res.data || '0' + alarmRingChartInstance = echarts.init(alarmRingChartRef.value); + const option = { + tooltip: { + trigger: 'item', + formatter: '{b}: {c} 次 ({d}%)' // 显示数量和百分比 + }, + series: [ + { + type: 'pie', + radius: ['50%', '60%'], // 环形半径 + center: ['50%', '50%'], // 居中显示 + avoidLabelOverlap: false, + label: { + show: true, + position: 'center', + formatter: `${alarmsTotalToday}/${processingAlarmToday}\n今日报警/处理`, + fontSize: 16, + fontWeight: 'bold', + color: '#333' + }, + labelLine: { + show: false // 隐藏标签连接线 + }, + data: [ + { + value: alarmsTotalToday, + name: '已处理报警', + itemStyle: { color: '#07BE75' } // 绿色:已处理 + }, + { + value: processingAlarmToday, + name: '未处理报警', + itemStyle: { color: '#F65757' } // 红色:未处理 + } + ] + } + ] + }; + alarmRingChartInstance.setOption(option); + // 报警柱状图 + initAlarmBarChart() + } catch (error) { + } }; /** @@ -325,14 +345,23 @@ const initAlarmRingChart = () => { */ const initAlarmBarChart = () => { if (!alarmBarChartRef.value) return; + const alarmTypeMap = [ + { name: '强制报警', field: 'alarmForced' }, // alarmForced + { name: '撞击闯入', field: 'intrusionImpact' }, // intrusionImpact + { name: '手动报警', field: 'alarmManual' }, // alarmManual + { name: '电子围栏', field: 'fenceElectronic' } // fenceElectronic + ]; - alarmBarChartInstance = echarts.init(alarmBarChartRef.value); - - // 假数据:各类型报警次数 - const alarmTypes = ['强制报警', '撞击闯入', '手动报警', '电子围栏']; - const alarmCounts = [50, 35, 65, 50]; // 对应各类型次数 - - // ECharts配置项 + const alarmTypes = alarmTypeMap.map(item => item.name); + const alarmCounts = alarmTypeMap.map(item => { + const value = alarmsData.value[item.field]; // 提取对应字段值 + console.log(`${item.name}数值:`, value); // 打印每个类型的数值 + return value; + }); + const commonGradient = new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { offset: 0, color: 'rgba(246, 87, 87, 1)' }, // 渐变起点:#F65757(不透明) + { offset: 1, color: 'rgba(224, 52, 52, 0)' } // 渐变终点:#E03434(全透明) + ]); const option = { tooltip: { trigger: 'axis', @@ -348,8 +377,7 @@ const initAlarmBarChart = () => { type: 'category', data: alarmTypes, axisLabel: { - interval: 0, - //rotate: 15 // 标签旋转,避免重叠 + interval: 0 // 强制显示所有标签 } }, yAxis: { @@ -362,28 +390,29 @@ const initAlarmBarChart = () => { name: '报警次数', type: 'bar', data: alarmCounts, - barWidth: '40%', + barWidth: '20%', itemStyle: { - color: (params: any) => { - // 不同类型报警用不同颜色 - const colors = ['#ff4d4f', '#e6a23c', '#409eff', '#67c23a']; - return colors[params.dataIndex]; - } + color: commonGradient, // 所有柱子共用同一渐变色 + borderRadius: 4 // 统一4px圆角 } } ] }; - + // 4. 初始化并渲染图表 + alarmBarChartInstance = echarts.init(alarmBarChartRef.value); alarmBarChartInstance.setOption(option); }; - // ---------------------- 图表更新方法(时间范围切换时) ---------------------- -const updateFrequencyChart = () => { - // 先销毁旧实例,再重新初始化 +const updateFrequencyChart = (tabValue: any) => { + activeTab.value = tabValue; if (frequencyChartInstance) { frequencyChartInstance.dispose(); } - initFrequencyChart(); + initFrequencyChart(tabValue, ''); +}; +const handleDeviceTypeChange = (all) => { + initFrequencyChart(activeTab.value, all); + }; // 首页统计接口 const getData = async () => { @@ -437,9 +466,8 @@ const getData = async () => { // ---------------------- 生命周期钩子(初始化/销毁图表) ---------------------- onMounted(() => { // 页面加载时初始化所有图表 - initFrequencyChart(); + initFrequencyChart('1', ''); initAlarmRingChart(); - initAlarmBarChart(); getData() // 监听窗口 resize,自动调整图表大小 @@ -461,7 +489,7 @@ onUnmounted(() => {