|
|
@@ -40,14 +40,14 @@
|
|
|
<span class="date-text">{{ currentDate }}</span>
|
|
|
<span class="time-text">{{ currentTime }}</span>
|
|
|
</div>
|
|
|
- <!-- <span class="fullscreen-toggle" @click.passive="onFullscreen">
|
|
|
+ <span class="fullscreen-toggle" @click.passive="onFullscreen">
|
|
|
<i
|
|
|
v-if="isFullscreen"
|
|
|
title="取消全屏"
|
|
|
class="el-icon-_screen-restore"
|
|
|
/>
|
|
|
<i v-else title="全屏" class="el-icon-_screen-full" />
|
|
|
- </span> -->
|
|
|
+ </span>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -179,17 +179,42 @@
|
|
|
|
|
|
<script>
|
|
|
import * as echarts from 'echarts'
|
|
|
+import { component } from 'vue-fullscreen'
|
|
|
import TrendChart from './components/TrendChart.vue'
|
|
|
import StatCard from './components/StatCard.vue'
|
|
|
import { deviceIndexStatistics } from '@/api/main/index.js'
|
|
|
|
|
|
|
|
|
-// 模拟数据
|
|
|
-const yearMonths = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
|
|
|
+// 默认周 x 轴数据(无真实数据时的占位)
|
|
|
const weekDays = ['第1周', '第2周', '第3周', '第4周']
|
|
|
|
|
|
-function genData(base, variance, count) {
|
|
|
- return Array.from({ length: count }, () => Math.round(base + (Math.random() - 0.5) * variance))
|
|
|
+// 固定场站列表
|
|
|
+const FIXED_STATIONS = ['5#站', '6#站', '7#站']
|
|
|
+
|
|
|
+// 固定 12 个月份的 x 轴标签
|
|
|
+const MONTHS_12 = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
|
|
|
+
|
|
|
+// 将 API 数据 [{stationName, dateTime, rate}] 格式化为 chart 所需的 xData(固定12月) + seriesConfig
|
|
|
+// 始终按 FIXED_STATIONS 顺序输出,无数据月份补 0
|
|
|
+function formatTrendData(list, valueKey, colors) {
|
|
|
+ const valueField = valueKey || 'rate'
|
|
|
+ const stationMap = {}
|
|
|
+
|
|
|
+ list.forEach((item) => {
|
|
|
+ const station = item.stationName
|
|
|
+ const month = parseInt(item.dateTime.split('-')[1]) // "2026-05" → 5
|
|
|
+ const monthLabel = MONTHS_12[month - 1] // 5 → "5月"
|
|
|
+ if (!stationMap[station]) stationMap[station] = {}
|
|
|
+ stationMap[station][monthLabel] = item[valueField]
|
|
|
+ })
|
|
|
+
|
|
|
+ const seriesConfig = FIXED_STATIONS.map((name, idx) => ({
|
|
|
+ name,
|
|
|
+ data: MONTHS_12.map((m) => stationMap[name]?.[m] ?? 0), // 缺月/缺站统一补 0
|
|
|
+ color: colors[idx % colors.length]
|
|
|
+ }))
|
|
|
+
|
|
|
+ return { xData: MONTHS_12, seriesConfig }
|
|
|
}
|
|
|
|
|
|
const palette = ['#3b82f6', '#22d3ee', '#facc15', '#f87171', '#a78bfa', '#34d399']
|
|
|
@@ -252,26 +277,18 @@ function makeMultiLineOption(xData, seriesConfig, unit) {
|
|
|
|
|
|
export default {
|
|
|
name: 'DeviceDashboard',
|
|
|
- components: { TrendChart, StatCard },
|
|
|
+ components: { VueFullscreen: component, TrendChart, StatCard },
|
|
|
data() {
|
|
|
return {
|
|
|
isFullscreen: false,
|
|
|
+ currentDate: '',
|
|
|
+ currentTime: '',
|
|
|
selectedStation: 'station-6',
|
|
|
stationList: [
|
|
|
{ label: '5#场站', value: 'station-5' },
|
|
|
{ label: '6#场站', value: 'station-6' },
|
|
|
{ label: '7#场站', value: 'station-7' }
|
|
|
],
|
|
|
- comprehensiveList: [
|
|
|
- { label: '设备总数', value: 350, unit: '台' },
|
|
|
- { label: '运行中', value: 345, unit: '台' },
|
|
|
- { label: '维修中', value: 5, unit: '台' },
|
|
|
- { label: '离线设备', value: 0, unit: '台' },
|
|
|
- { label: '本年新增', value: 12, unit: '台' },
|
|
|
- { label: '本月新增', value: 2, unit: '台' },
|
|
|
- { label: '年运行率', value: 96.5, unit: '%' },
|
|
|
- { label: '月运行率', value: 98.2, unit: '%' }
|
|
|
- ],
|
|
|
statsCardList: [
|
|
|
{ label: '设备总数', value: 350, unit: '台', key: 'totalNum', bgimg: require('@/assets/pcs/runDevice.png'), valueColor: '#409EFF', icon: 'el-icon-monitor', iconColor: '#409EFF', iconBg: '#ecf5ff'},
|
|
|
{ label: '运行数', value: 345, unit: '台', key: 'runNum', bgimg: require('@/assets/pcs/successInfo.png'), valueColor: '#67C23A', icon: 'el-icon-play', iconColor: '#67C23A', iconBg: '#ecf5ff'},
|
|
|
@@ -285,80 +302,113 @@ export default {
|
|
|
monthRepairCountOption: {}
|
|
|
}
|
|
|
},
|
|
|
- computed: {
|
|
|
- currentDate() {
|
|
|
- const d = new Date()
|
|
|
- return d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate()
|
|
|
- },
|
|
|
- currentTime() {
|
|
|
- const d = new Date()
|
|
|
- return d.getHours().toString().padStart(2, '0') + ':' +
|
|
|
- d.getMinutes().toString().padStart(2, '0') + ':' +
|
|
|
- d.getSeconds().toString().padStart(2, '0')
|
|
|
- }
|
|
|
- },
|
|
|
+ computed: {},
|
|
|
mounted() {
|
|
|
- this.initStatisticsCard()
|
|
|
+ this.updateTime()
|
|
|
this.initCharts()
|
|
|
this.updateTimer = setInterval(this.updateTime, 1000)
|
|
|
+ window.addEventListener('resize', this.handleResize)
|
|
|
},
|
|
|
beforeDestroy() {
|
|
|
clearInterval(this.updateTimer)
|
|
|
+ window.removeEventListener('resize', this.handleResize)
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ isFullscreen: {
|
|
|
+ handler() {
|
|
|
+ this.$nextTick(() => this.handleResize())
|
|
|
+ }
|
|
|
+ }
|
|
|
},
|
|
|
methods: {
|
|
|
onFullscreen() {
|
|
|
this.isFullscreen = !this.isFullscreen;
|
|
|
},
|
|
|
- async initStatisticsCard() {
|
|
|
- const res = await deviceIndexStatistics()
|
|
|
- console.log('res', res)
|
|
|
- this.statsCardList.forEach((item) => {
|
|
|
- item.value = res[item.key];
|
|
|
- });
|
|
|
+ handleResize() {
|
|
|
+ const { clientWidth, clientHeight } = document.documentElement
|
|
|
+ const containers = document.getElementsByClassName('box-container')
|
|
|
+ Array.from(containers).forEach((item) => {
|
|
|
+ if (this.isFullscreen) {
|
|
|
+ item.style.height = clientHeight + 'px'
|
|
|
+ item.style.width = clientWidth + 'px'
|
|
|
+ } else {
|
|
|
+ item.style.height = clientHeight - 100 + 'px'
|
|
|
+ item.style.width = clientWidth - 240 + 'px'
|
|
|
+ }
|
|
|
+ })
|
|
|
+ this.$nextTick(() => {
|
|
|
+ Object.values(this.$children).forEach(child => {
|
|
|
+ child.chartInstance && child.chartInstance.resize()
|
|
|
+ })
|
|
|
+ })
|
|
|
},
|
|
|
+
|
|
|
updateTime() {
|
|
|
- this.$forceUpdate()
|
|
|
+ const now = new Date()
|
|
|
+ const y = now.getFullYear()
|
|
|
+ const m = (now.getMonth() + 1)
|
|
|
+ const d = now.getDate()
|
|
|
+ this.currentDate = y + '-' + m + '-' + d
|
|
|
+ this.currentTime =
|
|
|
+ now.getHours().toString().padStart(2, '0') + ':' +
|
|
|
+ now.getMinutes().toString().padStart(2, '0') + ':' +
|
|
|
+ now.getSeconds().toString().padStart(2, '0')
|
|
|
},
|
|
|
- initCharts() {
|
|
|
- this.yearRunRateOption = makeMultiLineOption(yearMonths, [
|
|
|
- { name: '5#场站', data: genData(96, 6, 12), color: '#3b82f6' },
|
|
|
- { name: '6#场站', data: genData(94, 8, 12), color: '#22d3ee' },
|
|
|
- { name: '7#场站', data: genData(97, 5, 12), color: '#facc15' }
|
|
|
- ], '%')
|
|
|
+ async initCharts() {
|
|
|
+ const res = await deviceIndexStatistics()
|
|
|
+ console.log('res', res)
|
|
|
+ this.statsCardList.forEach((item) => {
|
|
|
+ item.value = res[item.key];
|
|
|
+ });
|
|
|
+
|
|
|
+ // ========== 年运行率趋势图 — nyxlList ==========
|
|
|
+ if (res.nyxlList && res.nyxlList.length) {
|
|
|
+ const { xData, seriesConfig } = formatTrendData(res.nyxlList, 'rate', palette)
|
|
|
+ this.yearRunRateOption = makeMultiLineOption(xData, seriesConfig, '%')
|
|
|
+ } else {
|
|
|
+ this.yearRunRateOption = makeMultiLineOption(MONTHS_12, [
|
|
|
+ { name: '暂无数据', data: new Array(12).fill(0), color: '#8ba3c7' }
|
|
|
+ ], '%')
|
|
|
+ }
|
|
|
|
|
|
- this.monthRunRateOption = makeMultiLineOption(yearMonths, [
|
|
|
- { name: '5#场站', data: genData(96, 5, 12), color: '#3b82f6' },
|
|
|
- { name: '6#场站', data: genData(95, 7, 12), color: '#22d3ee' },
|
|
|
- { name: '7#场站', data: genData(95, 7, 12), color: '#22d3ee' }
|
|
|
- ], '%')
|
|
|
+ // ========== 月运行率趋势图 — byList ==========
|
|
|
+ if (res.byList && res.byList.length) {
|
|
|
+ const { xData: x2, seriesConfig: sc2 } = formatTrendData(res.byList, 'rate', palette)
|
|
|
+ this.monthRunRateOption = makeMultiLineOption(x2, sc2, '%')
|
|
|
+ } else {
|
|
|
+ this.monthRunRateOption = makeMultiLineOption(MONTHS_12, [
|
|
|
+ { name: '暂无数据', data: new Array(12).fill(0), color: '#8ba3c7' }
|
|
|
+ ], '%')
|
|
|
+ }
|
|
|
|
|
|
- this.yearFaultRateOption = makeMultiLineOption(yearMonths, [
|
|
|
- { name: '5#场站', data: genData(4, 3, 12), color: '#f87171' },
|
|
|
- { name: '6#场站', data: genData(3, 4, 12), color: '#facc15' },
|
|
|
- { name: '7#场站', data: genData(2, 3, 12), color: '#8ba3c7' }
|
|
|
- ], '%')
|
|
|
+ // ========== 年故障率趋势图 — gzwxList ==========
|
|
|
+ if (res.gzwxList && res.gzwxList.length) {
|
|
|
+ const { xData: x3, seriesConfig: sc3 } = formatTrendData(res.gzwxList, 'rate', ['#f87171', '#facc15', '#8ba3c7'])
|
|
|
+ this.yearFaultRateOption = makeMultiLineOption(x3, sc3, '%')
|
|
|
+ } else {
|
|
|
+ this.yearFaultRateOption = makeMultiLineOption(MONTHS_12, [
|
|
|
+ { name: '暂无数据', data: new Array(12).fill(0), color: '#8ba3c7' }
|
|
|
+ ], '%')
|
|
|
+ }
|
|
|
|
|
|
- this.monthRunRateOption2 = makeMultiLineOption(yearMonths, [
|
|
|
- { name: '5#场站', data: genData(97, 4, 12), color: '#3b82f6' },
|
|
|
- { name: '6#场站', data: genData(95, 6, 12), color: '#22d3ee' },
|
|
|
- { name: '7#场站', data: genData(98, 3, 12), color: '#a78bfa' }
|
|
|
+ // ========== 月运行率趋势图2(暂用模拟,后续可接入其他数据源)==========
|
|
|
+ this.monthRunRateOption2 = makeMultiLineOption(MONTHS_12, [
|
|
|
+ { name: '暂无数据', data: new Array(12).fill(0), color: '#a78bfa' }
|
|
|
], '%')
|
|
|
|
|
|
- const repairTotal = genData(8, 6, 12).map(v => Math.max(2, v))
|
|
|
- const repairDevice = genData(5, 4, 12).map(v => Math.max(1, v))
|
|
|
- const repairOther = genData(3, 3, 12).map(v => Math.max(0, v))
|
|
|
- this.yearRepairCountOption = makeMultiLineOption(yearMonths, [
|
|
|
- { name: '5#场站', data: repairTotal, color: '#f87171' },
|
|
|
- { name: '6#场站', data: repairDevice, color: '#facc15' },
|
|
|
- { name: '7#场站', data: repairOther, color: '#3b82f6' }
|
|
|
- ], '次')
|
|
|
+ // ========== 年维修次数趋势图 — jhwxList ==========
|
|
|
+ if (res.jhwxList && res.jhwxList.length) {
|
|
|
+ const { xData: x5, seriesConfig: sc5 } = formatTrendData(res.jhwxList, 'rate', ['#f87171', '#facc15', '#3b82f6'])
|
|
|
+ this.yearRepairCountOption = makeMultiLineOption(x5, sc5, '次')
|
|
|
+ } else {
|
|
|
+ this.yearRepairCountOption = makeMultiLineOption(MONTHS_12, [
|
|
|
+ { name: '暂无数据', data: new Array(12).fill(0), color: '#8ba3c7' }
|
|
|
+ ], '次')
|
|
|
+ }
|
|
|
|
|
|
- const monthRepair1 = genData(2, 3, 4).map(v => Math.max(0, v))
|
|
|
- const monthRepair2 = genData(1, 2, 4).map(v => Math.max(0, v))
|
|
|
- this.monthRepairCountOption = makeMultiLineOption(weekDays, [
|
|
|
- { name: '5#场站', data: monthRepair1, color: '#f87171' },
|
|
|
- { name: '6#场站', data: monthRepair2, color: '#3b82f6' },
|
|
|
- { name: '7#场站', data: monthRepair1, color: '#f87171' },
|
|
|
+ // ========== 月维修次数趋势图(暂用默认占位)==========
|
|
|
+ this.monthRepairCountOption = makeMultiLineOption(MONTHS_12, [
|
|
|
+ { name: '暂无数据', data: new Array(12).fill(0), color: '#f87171' }
|
|
|
], '次')
|
|
|
},
|
|
|
}
|