|
@@ -117,7 +117,7 @@
|
|
|
<div class="chart-card chart-trend">
|
|
<div class="chart-card chart-trend">
|
|
|
<div class="chart-header">
|
|
<div class="chart-header">
|
|
|
<span class="chart-title">设备异常趋势图</span>
|
|
<span class="chart-title">设备异常趋势图</span>
|
|
|
- <span class="chart-subtitle">近15天运行数据 (2026-05-29 ~ 2026-06-12)</span>
|
|
|
|
|
|
|
+ <span class="chart-subtitle">近15天运行数据</span>
|
|
|
<div class="chart-legend-custom">
|
|
<div class="chart-legend-custom">
|
|
|
<span class="legend-tag tag-total">异常总数</span>
|
|
<span class="legend-tag tag-total">异常总数</span>
|
|
|
<span class="legend-tag tag-new">新增异常</span>
|
|
<span class="legend-tag tag-new">新增异常</span>
|
|
@@ -147,22 +147,23 @@
|
|
|
<div class="table-card">
|
|
<div class="table-card">
|
|
|
<div class="table-header">
|
|
<div class="table-header">
|
|
|
<span class="table-title">异常设备列表</span>
|
|
<span class="table-title">异常设备列表</span>
|
|
|
- <span class="table-count">共 {{ filteredTableData.length }} 条记录</span>
|
|
|
|
|
|
|
+ <span class="table-count">共 {{ tableTotal }} 条记录</span>
|
|
|
</div>
|
|
</div>
|
|
|
- <el-table :data="paginatedData" border stripe v-loading="loading" max-height="460" size="small">
|
|
|
|
|
- <el-table-column prop="id" label="序号" width="56" align="center" />
|
|
|
|
|
|
|
+ <el-table :data="paginatedData" border stripe v-loading="loading" max-height="460" size="small"
|
|
|
|
|
+ @sort-change="handleSortChange" :default-sort="{ prop: 'alarmTime', order: 'descending' }">
|
|
|
|
|
+ <el-table-column prop="id" label="序号" width="56" align="center" sortable="custom" />
|
|
|
<el-table-column prop="deviceCode" label="设备编号" min-width="140" show-overflow-tooltip />
|
|
<el-table-column prop="deviceCode" label="设备编号" min-width="140" show-overflow-tooltip />
|
|
|
<el-table-column prop="deviceName" label="设备名称" min-width="150" show-overflow-tooltip />
|
|
<el-table-column prop="deviceName" label="设备名称" min-width="150" show-overflow-tooltip />
|
|
|
<el-table-column prop="deviceType" label="设备类型" width="100" />
|
|
<el-table-column prop="deviceType" label="设备类型" width="100" />
|
|
|
- <el-table-column prop="level" label="异常等级" width="100" align="center">
|
|
|
|
|
|
|
+ <el-table-column prop="level" label="异常等级" width="100" align="center" sortable="custom">
|
|
|
<template #default="{ row }">
|
|
<template #default="{ row }">
|
|
|
<el-tag :type="levelTagType(row.level)" size="small">{{ row.level }}</el-tag>
|
|
<el-tag :type="levelTagType(row.level)" size="small">{{ row.level }}</el-tag>
|
|
|
</template>
|
|
</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
<el-table-column prop="alarmDesc" label="异常描述" min-width="220" show-overflow-tooltip />
|
|
<el-table-column prop="alarmDesc" label="异常描述" min-width="220" show-overflow-tooltip />
|
|
|
<el-table-column prop="address" label="安装地址" min-width="200" show-overflow-tooltip />
|
|
<el-table-column prop="address" label="安装地址" min-width="200" show-overflow-tooltip />
|
|
|
- <el-table-column prop="alarmTime" label="异常时间" width="168" />
|
|
|
|
|
- <el-table-column prop="processStatus" label="处理状态" width="100" align="center">
|
|
|
|
|
|
|
+ <el-table-column prop="alarmTime" label="异常时间" width="168" sortable="custom" />
|
|
|
|
|
+ <el-table-column prop="processStatus" label="处理状态" width="100" align="center" sortable="custom">
|
|
|
<template #default="{ row }">
|
|
<template #default="{ row }">
|
|
|
<el-tag :type="row.processStatus === '已修复' ? 'success' : row.processStatus === '处理中' ? 'warning' : 'danger'" size="small">
|
|
<el-tag :type="row.processStatus === '已修复' ? 'success' : row.processStatus === '处理中' ? 'warning' : 'danger'" size="small">
|
|
|
{{ row.processStatus }}
|
|
{{ row.processStatus }}
|
|
@@ -181,7 +182,7 @@
|
|
|
<el-pagination
|
|
<el-pagination
|
|
|
v-model:current-page="currentPage"
|
|
v-model:current-page="currentPage"
|
|
|
v-model:page-size="pageSize"
|
|
v-model:page-size="pageSize"
|
|
|
- :total="filteredTableData.length"
|
|
|
|
|
|
|
+ :total="tableTotal"
|
|
|
layout="total, prev, pager, next"
|
|
layout="total, prev, pager, next"
|
|
|
:page-sizes="[10, 20]"
|
|
:page-sizes="[10, 20]"
|
|
|
small
|
|
small
|
|
@@ -194,10 +195,11 @@
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup>
|
|
<script setup>
|
|
|
-import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref } from 'vue'
|
|
|
|
|
|
|
+import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
|
|
import * as echarts from 'echarts'
|
|
import * as echarts from 'echarts'
|
|
|
import { Clock, CircleCheckFilled, DataAnalysis, Histogram, PieChart, Search, TrendCharts, Warning, WarningFilled } from '@element-plus/icons-vue'
|
|
import { Clock, CircleCheckFilled, DataAnalysis, Histogram, PieChart, Search, TrendCharts, Warning, WarningFilled } from '@element-plus/icons-vue'
|
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
|
|
|
+import { getEquipmentAbnormalList, getEquipmentAbnormalStats } from '@/api/pipeNetwork/gasMonitor'
|
|
|
|
|
|
|
|
const loading = ref(false)
|
|
const loading = ref(false)
|
|
|
const searchKey = ref('')
|
|
const searchKey = ref('')
|
|
@@ -206,83 +208,112 @@ const typeFilter = ref('')
|
|
|
const statusFilter = ref('')
|
|
const statusFilter = ref('')
|
|
|
const currentPage = ref(1)
|
|
const currentPage = ref(1)
|
|
|
const pageSize = ref(10)
|
|
const pageSize = ref(10)
|
|
|
|
|
+const sortProp = ref('alarmTime')
|
|
|
|
|
+const sortOrder = ref('descending')
|
|
|
|
|
|
|
|
let trendChart = null
|
|
let trendChart = null
|
|
|
let typeChart = null
|
|
let typeChart = null
|
|
|
let levelChart = null
|
|
let levelChart = null
|
|
|
|
|
|
|
|
-// ==================== 统计数据 ====================
|
|
|
|
|
-const stats = reactive({
|
|
|
|
|
- total: 28,
|
|
|
|
|
- today: 3,
|
|
|
|
|
- rate: 7.2,
|
|
|
|
|
- processed: 18,
|
|
|
|
|
- pending: 10,
|
|
|
|
|
- processRate: 64.3,
|
|
|
|
|
- critical: 10,
|
|
|
|
|
- normal: 10,
|
|
|
|
|
- minor: 8
|
|
|
|
|
|
|
+// ==================== 统计数据(从API加载) ====================
|
|
|
|
|
+const stats = ref({
|
|
|
|
|
+ total: 0, today: 0, rate: 0, processed: 0, pending: 0,
|
|
|
|
|
+ processRate: 0, critical: 0, normal: 0, minor: 0
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
-const deviceTypeStats = ref([
|
|
|
|
|
- { name: '阀门', count: 4, color: '#e63946' },
|
|
|
|
|
- { name: '调压器', count: 3, color: '#f77f00' },
|
|
|
|
|
- { name: '流量计', count: 4, color: '#2d6a4f' },
|
|
|
|
|
- { name: '窨井盖', count: 5, color: '#7f4f24' },
|
|
|
|
|
- { name: '终端节点', count: 2, color: '#6c757d' },
|
|
|
|
|
- { name: '检查井', count: 1, color: '#b08968' }
|
|
|
|
|
-])
|
|
|
|
|
-
|
|
|
|
|
-// ==================== 趋势数据 ====================
|
|
|
|
|
-const trendDates = [
|
|
|
|
|
- '05-29', '05-30', '05-31', '06-01', '06-02', '06-03', '06-04',
|
|
|
|
|
- '06-05', '06-06', '06-07', '06-08', '06-09', '06-10', '06-11', '06-12'
|
|
|
|
|
-]
|
|
|
|
|
-const trendTotalData = [24, 26, 25, 28, 27, 25, 24, 26, 28, 29, 27, 28, 30, 28, 28]
|
|
|
|
|
-const trendNewData = [ 3, 5, 2, 6, 4, 2, 1, 3, 5, 4, 2, 3, 5, 3, 3]
|
|
|
|
|
-const trendProcessedData = [20, 21, 23, 22, 23, 23, 23, 23, 23, 25, 25, 25, 25, 25, 18]
|
|
|
|
|
-
|
|
|
|
|
-// ==================== 表格数据 ====================
|
|
|
|
|
-const tableData = ref([
|
|
|
|
|
- { id: '1', deviceCode:'GD-FM-001', deviceName:'辰州北路阀门', deviceType:'阀门', level:'严重', alarmDesc:'阀门开度异常,远程控制无响应,现场检查阀体锈蚀严重,存在燃气泄漏风险', address:'辰州北路与天宁路交叉口北侧50米', alarmTime:'2026-06-12 04:23:15', processStatus:'待处理' },
|
|
|
|
|
- { id: '2', deviceCode:'GD-TY-001', deviceName:'辰州路调压站', deviceType:'调压器', level:'严重', alarmDesc:'出口压力波动超限,调压器膜片老化,压力调节范围偏离正常值±15%', address:'辰州中路县政府东侧200米', alarmTime:'2026-06-12 02:15:42', processStatus:'处理中' },
|
|
|
|
|
- { id: '3', deviceCode:'GD-LL-002', deviceName:'迎宾西路计量站', deviceType:'流量计', level:'一般', alarmDesc:'流量计量偏差超出允许范围,瞬时流量数据跳变,疑似传感器零点漂移', address:'迎宾西路与古城路交叉口', alarmTime:'2026-06-11 18:47:30', processStatus:'处理中' },
|
|
|
|
|
- { id: '4', deviceCode:'GD-FM-003', deviceName:'古城北路阀门', deviceType:'阀门', level:'一般', alarmDesc:'阀门关闭不到位,密封面疑似有异物卡滞,泄漏检测仪报警', address:'古城北路中段天宁路南侧100米', alarmTime:'2026-06-11 11:32:08', processStatus:'待处理' },
|
|
|
|
|
- { id: '5', deviceCode:'YJ-JG-004', deviceName:'迎宾路窨井盖', deviceType:'窨井盖', level:'严重', alarmDesc:'井盖倾斜位移超过安全阈值,井盖锁失效,存在行人及车辆安全隐患', address:'迎宾中路公交站台北侧', alarmTime:'2026-06-11 06:55:20', processStatus:'待处理' },
|
|
|
|
|
- { id: '6', deviceCode:'GD-LL-001', deviceName:'辰州北路计量站', deviceType:'流量计', level:'轻微', alarmDesc:'通讯延迟偏高,数据上报间隔从15秒延长至45秒,4G信号强度偏弱', address:'辰州北路与滨江路交叉口附近', alarmTime:'2026-06-10 22:10:05', processStatus:'已修复' },
|
|
|
|
|
- { id: '7', deviceCode:'GD-TY-003', deviceName:'建设路调压柜', deviceType:'调压器', level:'一般', alarmDesc:'调压柜门锁损坏,柜内温湿度传感器读数偏高,可能存在进水风险', address:'建设西路中段加油站对面', alarmTime:'2026-06-10 14:28:45', processStatus:'已修复' },
|
|
|
|
|
- { id: '8', deviceCode:'YJ-JG-001', deviceName:'辰州北路窨井盖', deviceType:'窨井盖', level:'轻微', alarmDesc:'井盖表面沉降3cm,低于路面标高,不影响通行但需定期监测', address:'辰州北路北段人行道', alarmTime:'2026-06-10 08:15:33', processStatus:'已修复' },
|
|
|
|
|
- { id: '9', deviceCode:'GD-FM-004', deviceName:'迎宾东路阀门', deviceType:'阀门', level:'一般', alarmDesc:'阀门操作扭矩偏大,电动执行机构电流异常升高,需润滑维护', address:'迎宾东路东段靠近沅陵大道', alarmTime:'2026-06-09 16:42:18', processStatus:'已修复' },
|
|
|
|
|
- { id: '10', deviceCode:'GD-ZD-002', deviceName:'天宁东路终端', deviceType:'终端节点', level:'严重', alarmDesc:'终端设备离线超过48小时,主备电源均失效,可能遭施工破坏或被盗', address:'天宁东路末端靠近古城路', alarmTime:'2026-06-09 03:08:55', processStatus:'处理中' },
|
|
|
|
|
- { id: '11', deviceCode:'GD-TY-002', deviceName:'古城路调压站', deviceType:'调压器', level:'一般', alarmDesc:'调压站周边有施工活动,振动监测值超标,建议现场确认施工影响范围', address:'古城中路沅陵一中北侧', alarmTime:'2026-06-08 20:35:12', processStatus:'已修复' },
|
|
|
|
|
- { id: '12', deviceCode:'YJ-JG-005', deviceName:'建设路窨井盖', deviceType:'窨井盖', level:'轻微', alarmDesc:'井盖标识磨损严重,编号无法辨识,需重新喷涂或更换标识牌', address:'建设东路商铺门前人行道', alarmTime:'2026-06-08 12:50:40', processStatus:'已修复' },
|
|
|
|
|
- { id: '13', deviceCode:'GD-FM-002', deviceName:'辰州中路阀门', deviceType:'阀门', level:'严重', alarmDesc:'阀门井内积水超过警戒线,排水泵未自动启动,可能淹没电动执行机构', address:'辰州中路与迎宾路交叉口', alarmTime:'2026-06-07 19:22:07', processStatus:'已修复' },
|
|
|
|
|
- { id: '14', deviceCode:'GD-LL-003', deviceName:'建设东路计量柜', deviceType:'流量计', level:'一般', alarmDesc:'计量柜显示屏背光故障,夜间无法读取数据,不影响计量精度', address:'建设东路滨江路口附近', alarmTime:'2026-06-07 09:14:28', processStatus:'已修复' },
|
|
|
|
|
- { id: '15', deviceCode:'YJ-JG-006', deviceName:'滨江路窨井盖', deviceType:'窨井盖', level:'轻微', alarmDesc:'井盖铰链锈蚀松动,开启闭合有异响,建议润滑或更换铰链部件', address:'滨江路沿江步道观景台旁', alarmTime:'2026-06-06 15:30:55', processStatus:'已修复' },
|
|
|
|
|
- { id: '16', deviceCode:'GD-ZD-001', deviceName:'沅陵县政府终端', deviceType:'终端节点', level:'一般', alarmDesc:'终端存储空间使用率达到92%,历史数据清理策略未生效', address:'辰州中街县政府办公大楼', alarmTime:'2026-06-06 08:45:12', processStatus:'已修复' },
|
|
|
|
|
- { id: '17', deviceCode:'YJ-JC-001', deviceName:'辰州路检查井', deviceType:'检查井', level:'一般', alarmDesc:'检查井内可燃气体浓度检测值持续偏高,超标时长超过2小时', address:'辰州中路地下燃气管线上方', alarmTime:'2026-06-05 23:18:40', processStatus:'处理中' },
|
|
|
|
|
- { id: '18', deviceCode:'GD-FM-001', deviceName:'辰州北路阀门', deviceType:'阀门', level:'轻微', alarmDesc:'阀门控制箱密封条老化脱落,雨水渗入痕迹明显,需更换密封件', address:'辰州北路与天宁路交叉口北侧50米', alarmTime:'2026-06-05 10:42:33', processStatus:'已修复' }
|
|
|
|
|
-])
|
|
|
|
|
-
|
|
|
|
|
-const filteredTableData = computed(() => {
|
|
|
|
|
- let data = tableData.value
|
|
|
|
|
- if (searchKey.value) {
|
|
|
|
|
- const kw = searchKey.value.toLowerCase()
|
|
|
|
|
- data = data.filter(row =>
|
|
|
|
|
- row.deviceName.includes(kw) || row.deviceCode.toLowerCase().includes(kw) || row.address.includes(kw)
|
|
|
|
|
- )
|
|
|
|
|
- }
|
|
|
|
|
- if (levelFilter.value) data = data.filter(row => row.level === levelFilter.value)
|
|
|
|
|
- if (typeFilter.value) data = data.filter(row => row.deviceType === typeFilter.value)
|
|
|
|
|
- if (statusFilter.value) data = data.filter(row => row.processStatus === statusFilter.value)
|
|
|
|
|
- return data
|
|
|
|
|
|
|
+const deviceTypeStats = ref([])
|
|
|
|
|
+
|
|
|
|
|
+async function loadStats() {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await getEquipmentAbnormalStats()
|
|
|
|
|
+ if (res.data) {
|
|
|
|
|
+ const d = res.data
|
|
|
|
|
+ stats.value = {
|
|
|
|
|
+ total: d.total || 0, today: d.today || 0, rate: d.rate || 0,
|
|
|
|
|
+ processed: d.processed || 0, pending: d.pending || 0,
|
|
|
|
|
+ processRate: d.processRate || 0, critical: d.critical || 0,
|
|
|
|
|
+ normal: d.normal || 0, minor: d.minor || 0
|
|
|
|
|
+ }
|
|
|
|
|
+ // 设备类型统计
|
|
|
|
|
+ const colors = ['#e63946', '#f77f00', '#2d6a4f', '#7f4f24', '#6c757d', '#b08968']
|
|
|
|
|
+ const typeMap = d.deviceTypeStats || {}
|
|
|
|
|
+ let idx = 0
|
|
|
|
|
+ deviceTypeStats.value = Object.entries(typeMap).map(([name, count]) => ({
|
|
|
|
|
+ name, count, color: colors[idx++ % colors.length]
|
|
|
|
|
+ }))
|
|
|
|
|
+ // 图表数据
|
|
|
|
|
+ chartData.value = {
|
|
|
|
|
+ trend: d.trend || { dates: [], totalData: [], newData: [], fixedData: [] },
|
|
|
|
|
+ typeDistribution: d.typeDistribution || { categories: [], values: [] },
|
|
|
|
|
+ levelStatus: d.levelStatus || { levels: [], pending: [], processing: [], fixed: [] }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (e) { console.error(e) }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// ==================== 图表数据(从API动态加载) ====================
|
|
|
|
|
+const chartData = ref({
|
|
|
|
|
+ trend: { dates: [], totalData: [], newData: [], fixedData: [] },
|
|
|
|
|
+ typeDistribution: { categories: [], values: [] },
|
|
|
|
|
+ levelStatus: { levels: [], pending: [], processing: [], fixed: [] }
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
|
|
+// ==================== 表格数据(从API加载) ====================
|
|
|
|
|
+const tableData = ref([])
|
|
|
|
|
+const tableTotal = ref(0)
|
|
|
|
|
+
|
|
|
|
|
+async function loadList() {
|
|
|
|
|
+ loading.value = true
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await getEquipmentAbnormalList({
|
|
|
|
|
+ pageNum: currentPage.value,
|
|
|
|
|
+ pageSize: pageSize.value,
|
|
|
|
|
+ searchKey: searchKey.value || undefined,
|
|
|
|
|
+ level: levelFilter.value || undefined,
|
|
|
|
|
+ type: typeFilter.value || undefined,
|
|
|
|
|
+ status: statusFilter.value || undefined
|
|
|
|
|
+ })
|
|
|
|
|
+ if (res.data) {
|
|
|
|
|
+ tableData.value = (res.data.rows || []).map((r, i) => ({
|
|
|
|
|
+ ...r,
|
|
|
|
|
+ id: String((currentPage.value - 1) * pageSize.value + i + 1),
|
|
|
|
|
+ level: r.levelText || r.faultLevel,
|
|
|
|
|
+ processStatus: r.processStatus || '待处理',
|
|
|
|
|
+ alarmTime: r.alarmTime || '',
|
|
|
|
|
+ alarmDesc: r.alarmDesc || '',
|
|
|
|
|
+ deviceCode: r.deviceCode || '',
|
|
|
|
|
+ deviceName: r.deviceName || '',
|
|
|
|
|
+ deviceType: r.deviceType || '',
|
|
|
|
|
+ address: r.address || ''
|
|
|
|
|
+ }))
|
|
|
|
|
+ tableTotal.value = res.data.total || 0
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (e) { console.error(e) } finally { loading.value = false }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
const paginatedData = computed(() => {
|
|
const paginatedData = computed(() => {
|
|
|
- const start = (currentPage.value - 1) * pageSize.value
|
|
|
|
|
- return filteredTableData.value.slice(start, start + pageSize.value)
|
|
|
|
|
|
|
+ const list = [...tableData.value]
|
|
|
|
|
+ if (sortProp.value) {
|
|
|
|
|
+ list.sort((a, b) => {
|
|
|
|
|
+ const va = a[sortProp.value] || ''
|
|
|
|
|
+ const vb = b[sortProp.value] || ''
|
|
|
|
|
+ const cmp = typeof va === 'string' ? va.localeCompare(vb) : va - vb
|
|
|
|
|
+ return sortOrder.value === 'descending' ? -cmp : cmp
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ return list
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
|
|
+// 排序切换
|
|
|
|
|
+function handleSortChange({ prop, order }) {
|
|
|
|
|
+ sortProp.value = prop
|
|
|
|
|
+ sortOrder.value = order || 'descending'
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 分页切换时重载
|
|
|
|
|
+watch(currentPage, () => loadList())
|
|
|
|
|
+watch(pageSize, () => { currentPage.value = 1; loadList() })
|
|
|
|
|
+
|
|
|
// ==================== 工具函数 ====================
|
|
// ==================== 工具函数 ====================
|
|
|
function levelTagType(level) {
|
|
function levelTagType(level) {
|
|
|
if (level === '严重') return 'danger'
|
|
if (level === '严重') return 'danger'
|
|
@@ -292,6 +323,7 @@ function levelTagType(level) {
|
|
|
|
|
|
|
|
function handleQuery() {
|
|
function handleQuery() {
|
|
|
currentPage.value = 1
|
|
currentPage.value = 1
|
|
|
|
|
+ loadList()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function handleReset() {
|
|
function handleReset() {
|
|
@@ -300,6 +332,7 @@ function handleReset() {
|
|
|
typeFilter.value = ''
|
|
typeFilter.value = ''
|
|
|
statusFilter.value = ''
|
|
statusFilter.value = ''
|
|
|
currentPage.value = 1
|
|
currentPage.value = 1
|
|
|
|
|
+ loadList()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function handleDetail(row) {
|
|
function handleDetail(row) {
|
|
@@ -347,6 +380,7 @@ function initTrendChart() {
|
|
|
if (!dom) return
|
|
if (!dom) return
|
|
|
if (trendChart) trendChart.dispose()
|
|
if (trendChart) trendChart.dispose()
|
|
|
trendChart = echarts.init(dom)
|
|
trendChart = echarts.init(dom)
|
|
|
|
|
+ const t = chartData.value.trend
|
|
|
trendChart.setOption({
|
|
trendChart.setOption({
|
|
|
tooltip: {
|
|
tooltip: {
|
|
|
trigger: 'axis',
|
|
trigger: 'axis',
|
|
@@ -362,7 +396,7 @@ function initTrendChart() {
|
|
|
grid: { left: 52, right: 44, top: 44, bottom: 32 },
|
|
grid: { left: 52, right: 44, top: 44, bottom: 32 },
|
|
|
xAxis: {
|
|
xAxis: {
|
|
|
type: 'category',
|
|
type: 'category',
|
|
|
- data: trendDates,
|
|
|
|
|
|
|
+ data: t.dates || [],
|
|
|
boundaryGap: false,
|
|
boundaryGap: false,
|
|
|
axisLabel: { color: '#9098a6', fontSize: 12 },
|
|
axisLabel: { color: '#9098a6', fontSize: 12 },
|
|
|
axisLine: { lineStyle: { color: '#d0d5dd' } }
|
|
axisLine: { lineStyle: { color: '#d0d5dd' } }
|
|
@@ -377,7 +411,7 @@ function initTrendChart() {
|
|
|
series: [
|
|
series: [
|
|
|
{
|
|
{
|
|
|
name: '异常总数', type: 'line',
|
|
name: '异常总数', type: 'line',
|
|
|
- data: trendTotalData, smooth: true, symbol: 'circle', symbolSize: 6,
|
|
|
|
|
|
|
+ data: t.totalData || [], smooth: true, symbol: 'circle', symbolSize: 6,
|
|
|
lineStyle: { width: 3, color: '#e63946' },
|
|
lineStyle: { width: 3, color: '#e63946' },
|
|
|
itemStyle: { color: '#e63946', borderColor: '#fff', borderWidth: 2 },
|
|
itemStyle: { color: '#e63946', borderColor: '#fff', borderWidth: 2 },
|
|
|
areaStyle: {
|
|
areaStyle: {
|
|
@@ -389,13 +423,13 @@ function initTrendChart() {
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
|
name: '新增异常', type: 'line',
|
|
name: '新增异常', type: 'line',
|
|
|
- data: trendNewData, smooth: true, symbol: 'emptyCircle', symbolSize: 6,
|
|
|
|
|
|
|
+ data: t.newData || [], smooth: true, symbol: 'emptyCircle', symbolSize: 6,
|
|
|
lineStyle: { width: 2.5, color: '#f77f00' },
|
|
lineStyle: { width: 2.5, color: '#f77f00' },
|
|
|
itemStyle: { color: '#f77f00', borderColor: '#f77f00', borderWidth: 2 }
|
|
itemStyle: { color: '#f77f00', borderColor: '#f77f00', borderWidth: 2 }
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
|
name: '已修复', type: 'line',
|
|
name: '已修复', type: 'line',
|
|
|
- data: trendProcessedData, smooth: true, symbol: 'diamond', symbolSize: 7,
|
|
|
|
|
|
|
+ data: t.fixedData || [], smooth: true, symbol: 'diamond', symbolSize: 7,
|
|
|
lineStyle: { width: 2.5, color: '#2a9d8f', type: 'dashed' },
|
|
lineStyle: { width: 2.5, color: '#2a9d8f', type: 'dashed' },
|
|
|
itemStyle: { color: '#2a9d8f', borderColor: '#fff', borderWidth: 2 }
|
|
itemStyle: { color: '#2a9d8f', borderColor: '#fff', borderWidth: 2 }
|
|
|
}
|
|
}
|
|
@@ -408,15 +442,14 @@ function initTypeChart() {
|
|
|
if (!dom) return
|
|
if (!dom) return
|
|
|
if (typeChart) typeChart.dispose()
|
|
if (typeChart) typeChart.dispose()
|
|
|
typeChart = echarts.init(dom)
|
|
typeChart = echarts.init(dom)
|
|
|
- const categories = ['通讯故障', '设备老化', '外部损坏', '传感器故障', '电源问题', '其他']
|
|
|
|
|
- const values = [8, 7, 5, 4, 3, 1]
|
|
|
|
|
- const colors = ['#457b9d', '#e76f51', '#e63946', '#f77f00', '#6c757d', '#b08968']
|
|
|
|
|
|
|
+ const d = chartData.value.typeDistribution
|
|
|
|
|
+ const colors = ['#457b9d', '#e76f51', '#e63946']
|
|
|
typeChart.setOption({
|
|
typeChart.setOption({
|
|
|
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
|
|
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
|
|
|
grid: { left: 46, right: 20, top: 16, bottom: 32 },
|
|
grid: { left: 46, right: 20, top: 16, bottom: 32 },
|
|
|
xAxis: {
|
|
xAxis: {
|
|
|
type: 'category',
|
|
type: 'category',
|
|
|
- data: categories,
|
|
|
|
|
|
|
+ data: d.categories || [],
|
|
|
axisLabel: { color: '#9098a6', fontSize: 11, rotate: 15 },
|
|
axisLabel: { color: '#9098a6', fontSize: 11, rotate: 15 },
|
|
|
axisLine: { lineStyle: { color: '#d0d5dd' } }
|
|
axisLine: { lineStyle: { color: '#d0d5dd' } }
|
|
|
},
|
|
},
|
|
@@ -427,7 +460,7 @@ function initTypeChart() {
|
|
|
},
|
|
},
|
|
|
series: [{
|
|
series: [{
|
|
|
type: 'bar',
|
|
type: 'bar',
|
|
|
- data: values.map((v, i) => ({ value: v, itemStyle: { color: colors[i], borderRadius: [4, 4, 0, 0] } })),
|
|
|
|
|
|
|
+ data: (d.values || []).map((v, i) => ({ value: v, itemStyle: { color: colors[i] || '#6c757d', borderRadius: [4, 4, 0, 0] } })),
|
|
|
barWidth: 28,
|
|
barWidth: 28,
|
|
|
label: { show: true, position: 'top', color: '#4e5969', fontSize: 12, fontWeight: 600 }
|
|
label: { show: true, position: 'top', color: '#4e5969', fontSize: 12, fontWeight: 600 }
|
|
|
}]
|
|
}]
|
|
@@ -439,6 +472,7 @@ function initLevelChart() {
|
|
|
if (!dom) return
|
|
if (!dom) return
|
|
|
if (levelChart) levelChart.dispose()
|
|
if (levelChart) levelChart.dispose()
|
|
|
levelChart = echarts.init(dom)
|
|
levelChart = echarts.init(dom)
|
|
|
|
|
+ const d = chartData.value.levelStatus
|
|
|
levelChart.setOption({
|
|
levelChart.setOption({
|
|
|
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
|
|
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
|
|
|
legend: {
|
|
legend: {
|
|
@@ -449,7 +483,7 @@ function initLevelChart() {
|
|
|
grid: { left: 46, right: 20, top: 44, bottom: 28 },
|
|
grid: { left: 46, right: 20, top: 44, bottom: 28 },
|
|
|
xAxis: {
|
|
xAxis: {
|
|
|
type: 'category',
|
|
type: 'category',
|
|
|
- data: ['严重', '一般', '轻微'],
|
|
|
|
|
|
|
+ data: d.levels || [],
|
|
|
axisLabel: { color: '#9098a6', fontSize: 12 },
|
|
axisLabel: { color: '#9098a6', fontSize: 12 },
|
|
|
axisLine: { lineStyle: { color: '#d0d5dd' } }
|
|
axisLine: { lineStyle: { color: '#d0d5dd' } }
|
|
|
},
|
|
},
|
|
@@ -462,17 +496,17 @@ function initLevelChart() {
|
|
|
series: [
|
|
series: [
|
|
|
{
|
|
{
|
|
|
name: '待处理', type: 'bar',
|
|
name: '待处理', type: 'bar',
|
|
|
- data: [3, 3, 4], barWidth: 30, barGap: '20%',
|
|
|
|
|
|
|
+ data: d.pending || [], barWidth: 30, barGap: '20%',
|
|
|
itemStyle: { color: '#e63946', borderRadius: [4, 4, 0, 0] }
|
|
itemStyle: { color: '#e63946', borderRadius: [4, 4, 0, 0] }
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
|
name: '处理中', type: 'bar',
|
|
name: '处理中', type: 'bar',
|
|
|
- data: [2, 3, 0], barWidth: 30,
|
|
|
|
|
|
|
+ data: d.processing || [], barWidth: 30,
|
|
|
itemStyle: { color: '#f77f00', borderRadius: [4, 4, 0, 0] }
|
|
itemStyle: { color: '#f77f00', borderRadius: [4, 4, 0, 0] }
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
|
name: '已修复', type: 'bar',
|
|
name: '已修复', type: 'bar',
|
|
|
- data: [5, 7, 6], barWidth: 30,
|
|
|
|
|
|
|
+ data: d.fixed || [], barWidth: 30,
|
|
|
itemStyle: { color: '#2a9d8f', borderRadius: [4, 4, 0, 0] }
|
|
itemStyle: { color: '#2a9d8f', borderRadius: [4, 4, 0, 0] }
|
|
|
}
|
|
}
|
|
|
]
|
|
]
|
|
@@ -492,6 +526,9 @@ function resizeCharts() {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
onMounted(async () => {
|
|
onMounted(async () => {
|
|
|
|
|
+ await nextTick()
|
|
|
|
|
+ // 先加载数据,再初始化图表
|
|
|
|
|
+ await Promise.all([loadStats(), loadList()])
|
|
|
await nextTick()
|
|
await nextTick()
|
|
|
initCharts()
|
|
initCharts()
|
|
|
window.addEventListener('resize', resizeCharts)
|
|
window.addEventListener('resize', resizeCharts)
|