refactor(auth): 增加锌线系统token管理功能 feat(api): 添加锌线停机记录、生产报表和设备快照API feat(views): 实现锌线实时监控、生产统计和停机统计页面 feat(components): 开发锌线生产报表、停机统计和班组绩效组件 feat(utils): 新增锌线专用请求工具zinc1Request chore(vue.config): 配置锌线API代理
837 lines
36 KiB
Vue
837 lines
36 KiB
Vue
<template>
|
||
<div class="page-container">
|
||
<!-- 刷新按钮(固定在右下角,保留) -->
|
||
<div class="refresh-btn-fixed" @click="refreshData">
|
||
<span class="refresh-icon" :class="{ 'rotating': isRefreshing }">⟳</span>
|
||
</div>
|
||
|
||
<!-- 快速导航菜单(固定在左下角,保留全部导航项) -->
|
||
<div class="nav-menu-fixed" :class="{ 'nav-expanded': navMenuExpanded }">
|
||
<div class="nav-toggle" @click="navMenuExpanded = !navMenuExpanded">
|
||
<span class="nav-toggle-icon">{{ navMenuExpanded ? '✕' : '☰' }}</span>
|
||
</div>
|
||
<div class="nav-items" v-if="navMenuExpanded">
|
||
<div class="nav-item" @click="scrollToSection('speed-monitor')">
|
||
<span class="nav-label">速度监控</span>
|
||
</div>
|
||
<div class="nav-item" @click="scrollToSection('exit-speed-chart')">
|
||
<span class="nav-label">出口速度趋势</span>
|
||
</div>
|
||
<div class="nav-item" @click="scrollToSection('temp-chart')">
|
||
<span class="nav-label">酸槽温度趋势</span>
|
||
</div>
|
||
<div class="nav-item" @click="scrollToSection('looper-status')">
|
||
<span class="nav-label">活套运行状态</span>
|
||
</div>
|
||
<div class="nav-item" @click="scrollToSection('tank-concentration')">
|
||
<span class="nav-label">酸槽浓度监控</span>
|
||
</div>
|
||
<div class="nav-item" @click="scrollToSection('force-chart')">
|
||
<span class="nav-label">轧制力趋势</span>
|
||
</div>
|
||
<div class="nav-item" @click="scrollToSection('process-params')">
|
||
<span class="nav-label">工艺参数</span>
|
||
</div>
|
||
<div class="nav-item" @click="scrollToSection('roll-speed')">
|
||
<span class="nav-label">轧辊速度监控</span>
|
||
</div>
|
||
<div class="nav-item" @click="scrollToSection('reduc-rate')">
|
||
<span class="nav-label">机架压下率</span>
|
||
</div>
|
||
<div class="nav-item" @click="scrollToSection('tension-monitor')">
|
||
<span class="nav-label">带钢张力监控</span>
|
||
</div>
|
||
<div class="nav-item" @click="scrollToSection('power-ratio')">
|
||
<span class="nav-label">机架功率百分比</span>
|
||
</div>
|
||
<div class="nav-item" @click="scrollToSection('paint-speed')">
|
||
<span class="nav-label">涂装速度监控</span>
|
||
</div>
|
||
<div class="nav-item" @click="scrollToSection('tlv-params')">
|
||
<span class="nav-label">拉矫参数</span>
|
||
</div>
|
||
<div class="nav-item" @click="scrollToSection('paint-temp-chart')">
|
||
<span class="nav-label">烘干温度趋势</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 核心:纯实时监控滚动容器 【移除tab判断,直接展示】 -->
|
||
<div class="scroll-container">
|
||
<!-- 顶部状态栏 -->
|
||
<div class="status-bar">
|
||
<div class="status-item">
|
||
<span class="status-label">网络状态</span>
|
||
<span class="status-value" :class="'status-' + webStatus[0].value">{{ webStatus[0].value }}</span>
|
||
</div>
|
||
<div class="status-divider"></div>
|
||
<div class="status-item">
|
||
<span class="status-label">当前班组</span>
|
||
<span class="status-value">{{ webStatus[1].value }}</span>
|
||
</div>
|
||
<div class="status-divider"></div>
|
||
<div class="status-item">
|
||
<span class="status-label">更新时间</span>
|
||
<span class="status-value status-time">{{ lastUpdateTime }}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 速度监控 -->
|
||
<div class="section" id="speed-monitor">
|
||
<div class="section-title">速度监控</div>
|
||
<div class="metrics-grid-3">
|
||
<div class="metric-box" v-for="(item, index) in speedMetrics" :key="index">
|
||
<span class="metric-name">{{ item.label }}</span>
|
||
<span class="metric-value">{{ item.value }}</span>
|
||
<span class="metric-unit">{{ item.unit }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 出口速度趋势 -->
|
||
<div class="section" id="exit-speed-chart">
|
||
<div class="section-title">出口速度趋势</div>
|
||
<div class="chart-box" ref="exitSpeedChart" id="exitSpeedChart"></div>
|
||
</div>
|
||
|
||
<!-- 酸槽温度趋势 -->
|
||
<div class="section" id="temp-chart">
|
||
<div class="section-title">酸槽温度趋势</div>
|
||
<div class="chart-box" ref="tempChart" id="tempChart"></div>
|
||
</div>
|
||
|
||
<!-- 活套运行状态 -->
|
||
<div class="section" id="looper-status">
|
||
<div class="section-title">活套运行状态</div>
|
||
<div class="metrics-grid-3">
|
||
<div class="metric-box" v-for="(item, index) in looperMetrics" :key="index">
|
||
<span class="metric-name">{{ item.label }}</span>
|
||
<span class="metric-value">{{ item.value }}</span>
|
||
<span class="metric-unit">{{ item.unit }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 酸槽浓度监控 -->
|
||
<div class="section" id="tank-concentration">
|
||
<div class="section-title">酸槽浓度监控</div>
|
||
<div class="tank-grid">
|
||
<div class="tank-card" v-for="(tank, index) in tankConcentration" :key="index">
|
||
<div class="tank-header">{{ tank.name }}</div>
|
||
<div class="tank-data">
|
||
<div class="tank-row">
|
||
<span class="data-label">酸浓度</span>
|
||
<span class="data-value">{{ tank.hclCont }} <span class="data-unit">g/L</span></span>
|
||
</div>
|
||
<div class="tank-divider"></div>
|
||
<div class="tank-row">
|
||
<span class="data-label">铁盐浓度</span>
|
||
<span class="data-value">{{ tank.feCont }} <span class="data-unit">g/L</span></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 轧制力趋势 -->
|
||
<div class="section" id="force-chart">
|
||
<div class="section-title">轧制力趋势</div>
|
||
<div class="chart-box" ref="forceChart" id="forceChart"></div>
|
||
</div>
|
||
|
||
<!-- 工艺参数 -->
|
||
<div class="section" id="process-params">
|
||
<div class="section-title">工艺参数</div>
|
||
<div class="metrics-grid-2">
|
||
<div class="metric-box" v-for="(item, index) in processMetrics" :key="index">
|
||
<span class="metric-name">{{ item.label }}</span>
|
||
<span class="metric-value">{{ item.value }}</span>
|
||
<span class="metric-unit">{{ item.unit }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ============ 镀锌线数据 ============ -->
|
||
<div class="section-divider">
|
||
<span class="divider-text">镀锌线监控数据</span>
|
||
</div>
|
||
|
||
<!-- 轧辊速度监控 -->
|
||
<div class="section" id="roll-speed">
|
||
<div class="section-title">轧辊速度监控</div>
|
||
<div class="metrics-grid-3">
|
||
<div class="metric-box" v-for="(item, index) in rollSpeedMetrics" :key="index">
|
||
<span class="metric-name">{{ item.label }}</span>
|
||
<span class="metric-value">{{ item.value }}</span>
|
||
<span class="metric-unit">{{ item.unit }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 机架压下率 -->
|
||
<div class="section" id="reduc-rate">
|
||
<div class="section-title">机架压下率</div>
|
||
<div class="metrics-grid-3">
|
||
<div class="metric-box" v-for="(item, index) in reducMetrics" :key="index">
|
||
<span class="metric-name">{{ item.label }}</span>
|
||
<span class="metric-value">{{ item.value }}</span>
|
||
<span class="metric-unit">{{ item.unit }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 带钢张力监控 -->
|
||
<div class="section" id="tension-monitor">
|
||
<div class="section-title">带钢张力监控</div>
|
||
<div class="metrics-grid-3">
|
||
<div class="metric-box" v-for="(item, index) in tensionMetrics" :key="index">
|
||
<span class="metric-name">{{ item.label }}</span>
|
||
<span class="metric-value">{{ item.value }}</span>
|
||
<span class="metric-unit">{{ item.unit }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 机架功率百分比 -->
|
||
<div class="section" id="power-ratio">
|
||
<div class="section-title">机架功率百分比</div>
|
||
<div class="metrics-grid-3">
|
||
<div class="metric-box" v-for="(item, index) in powerMetrics" :key="index">
|
||
<span class="metric-name">{{ item.label }}</span>
|
||
<span class="metric-value">{{ item.value }}</span>
|
||
<span class="metric-unit">{{ item.unit }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ============ 涂装线数据 ============ -->
|
||
<div class="section-divider">
|
||
<span class="divider-text">涂装线监控数据</span>
|
||
</div>
|
||
|
||
<!-- 涂装速度监控 -->
|
||
<div class="section" id="paint-speed">
|
||
<div class="section-title">涂装速度监控</div>
|
||
<div class="metrics-grid-3">
|
||
<div class="metric-box" v-for="(item, index) in paintSpeedMetrics" :key="index">
|
||
<span class="metric-name">{{ item.label }}</span>
|
||
<span class="metric-value">{{ item.value }}</span>
|
||
<span class="metric-unit">{{ item.unit }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 拉矫参数 -->
|
||
<div class="section" id="tlv-params">
|
||
<div class="section-title">拉矫参数</div>
|
||
<div class="metrics-grid-2">
|
||
<div class="metric-box" v-for="(item, index) in tlvMetrics" :key="index">
|
||
<span class="metric-name">{{ item.label }}</span>
|
||
<span class="metric-value">{{ item.value }}</span>
|
||
<span class="metric-unit">{{ item.unit }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 烘干温度趋势 -->
|
||
<div class="section" id="paint-temp-chart">
|
||
<div class="section-title">烘干温度趋势</div>
|
||
<div class="chart-box" ref="paintTempChart" id="paintTempChart"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
// ✅ 原接口导入 完全未改动
|
||
import { getAllPlantStateDefines, listPlantStateHistory, getCurrentShift } from '@/api/pocket/plantState'
|
||
// ✅ 引入Echarts5.x 兼容Vue2
|
||
import * as echarts from 'echarts'
|
||
// ✅ 引入axios替换uni.request (PC端网络请求)
|
||
import axios from 'axios'
|
||
|
||
export default {
|
||
name: 'RealTimeMonitor',
|
||
data() {
|
||
return {
|
||
webStatus: [
|
||
{ label: '网络状态', value: '检测中...' },
|
||
{ label: '当前班组', value: '—' }
|
||
],
|
||
lastUpdateTime: '—', // 最后更新时间
|
||
isRefreshing: false, // 是否正在刷新
|
||
refreshTimer: null, // 定时器
|
||
navMenuExpanded: false, // 导航菜单是否展开
|
||
// ✅ 移除了 tabData/currentTab 无用属性
|
||
// 速度监控指标(ID=1,2,3)
|
||
speedMetrics: [
|
||
{ label: '出口带钢速度', value: '—', unit: 'm/min' },
|
||
{ label: '酸洗带钢速度', value: '—', unit: 'm/min' },
|
||
{ label: '圆盘剪速度', value: '—', unit: 'm/min' }
|
||
],
|
||
// 活套状态(ID=8,9,10)
|
||
looperMetrics: [
|
||
{ label: '入口活套', value: '—', unit: '%' },
|
||
{ label: '出口活套', value: '—', unit: '%' },
|
||
{ label: '联机活套', value: '—', unit: '%' }
|
||
],
|
||
// 酸槽浓度(ID=11-16)
|
||
tankConcentration: [
|
||
{ name: '1#酸槽', hclCont: '—', feCont: '—' },
|
||
{ name: '2#酸槽', hclCont: '—', feCont: '—' },
|
||
{ name: '3#酸槽', hclCont: '—', feCont: '—' }
|
||
],
|
||
// 其他工艺参数(ID=7,17,18,19,20)
|
||
processMetrics: [
|
||
{ label: '漂洗温度', value: '—', unit: '°C' },
|
||
{ label: '烘干温度', value: '—', unit: '°C' },
|
||
{ label: '漂洗电导率', value: '—', unit: 'g/L' },
|
||
{ label: '联机活套张力', value: '—', unit: 'kN' },
|
||
{ label: '拉矫机延伸率', value: '—', unit: '%' }
|
||
],
|
||
// 镀锌线数据
|
||
rollSpeedMetrics: [
|
||
{ label: '1#机架', value: '—', unit: 'm/min' },
|
||
{ label: '2#机架', value: '—', unit: 'm/min' },
|
||
{ label: '3#机架', value: '—', unit: 'm/min' },
|
||
{ label: '4#机架', value: '—', unit: 'm/min' },
|
||
{ label: '5#机架', value: '—', unit: 'm/min' },
|
||
{ label: '6#机架', value: '—', unit: 'm/min' }
|
||
],
|
||
reducMetrics: [
|
||
{ label: '1#机架', value: '—', unit: '%' },
|
||
{ label: '2#机架', value: '—', unit: '%' },
|
||
{ label: '3#机架', value: '—', unit: '%' },
|
||
{ label: '4#机架', value: '—', unit: '%' },
|
||
{ label: '5#机架', value: '—', unit: '%' },
|
||
{ label: '6#机架', value: '—', unit: '%' }
|
||
],
|
||
tensionMetrics: [
|
||
{ label: '0#张力', value: '—', unit: 'kN' },
|
||
{ label: '1#张力', value: '—', unit: 'kN' },
|
||
{ label: '2#张力', value: '—', unit: 'kN' },
|
||
{ label: '3#张力', value: '—', unit: 'kN' },
|
||
{ label: '4#张力', value: '—', unit: 'kN' },
|
||
{ label: '5#张力', value: '—', unit: 'kN' },
|
||
{ label: '6#张力', value: '—', unit: 'kN' }
|
||
],
|
||
powerMetrics: [
|
||
{ label: '1#机架', value: '—', unit: '%' },
|
||
{ label: '2#机架', value: '—', unit: '%' },
|
||
{ label: '3#机架', value: '—', unit: '%' },
|
||
{ label: '4#机架', value: '—', unit: '%' },
|
||
{ label: '5#机架', value: '—', unit: '%' },
|
||
{ label: '6#机架', value: '—', unit: '%' }
|
||
],
|
||
// 涂装线数据
|
||
paintSpeedMetrics: [
|
||
{ label: '出口带钢速度', value: '—', unit: 'm/min' },
|
||
{ label: '涂装带钢速度', value: '—', unit: 'm/min' },
|
||
{ label: '圆盘剪速度', value: '—', unit: 'm/min' }
|
||
],
|
||
tlvMetrics: [
|
||
{ label: '拉矫延伸率', value: '—', unit: '%' },
|
||
{ label: '破磷机插入量1', value: '—', unit: 'mm' },
|
||
{ label: '破磷机插入量2', value: '—', unit: 'mm' },
|
||
{ label: '破磷机插入量3', value: '—', unit: 'mm' }
|
||
],
|
||
// Echarts图表实例
|
||
exitSpeedChart: null,
|
||
tempChart: null,
|
||
forceChart: null,
|
||
paintTempChart: null,
|
||
// 图表配色与原qiun一致
|
||
lineColor: ["#0066cc", "#409eff", "#66b1ff"],
|
||
forceColor: ["#0066cc", "#409eff", "#66b1ff", "#a0cfff", "#d9ecff", "#ecf5ff"],
|
||
paintColor: ["#0066cc", "#409eff", "#66b1ff", "#a0cfff", "#d9ecff"],
|
||
plantStateDefines: [] // 缓存所有的状态定义
|
||
};
|
||
},
|
||
mounted() {
|
||
this.loadAllData() // 加载所有数据
|
||
this.startAutoRefresh() // 启动自动刷新
|
||
this.initEcharts() // 初始化图表
|
||
window.addEventListener('resize', this.resizeEcharts) // 窗口自适应
|
||
},
|
||
beforeDestroy() {
|
||
this.stopAutoRefresh() // 页面销毁时清除定时器
|
||
window.removeEventListener('resize', this.resizeEcharts)
|
||
this.disposeEcharts() // 销毁图表实例 防内存泄漏
|
||
},
|
||
methods: {
|
||
// ✅ 初始化Echarts图表
|
||
initEcharts() {
|
||
this.exitSpeedChart = echarts.init(document.getElementById('exitSpeedChart'))
|
||
this.tempChart = echarts.init(document.getElementById('tempChart'))
|
||
this.forceChart = echarts.init(document.getElementById('forceChart'))
|
||
this.paintTempChart = echarts.init(document.getElementById('paintTempChart'))
|
||
},
|
||
// ✅ 图表自适应
|
||
resizeEcharts() {
|
||
this.exitSpeedChart && this.exitSpeedChart.resize()
|
||
this.tempChart && this.tempChart.resize()
|
||
this.forceChart && this.forceChart.resize()
|
||
this.paintTempChart && this.paintTempChart.resize()
|
||
},
|
||
// ✅ 销毁图表实例
|
||
disposeEcharts() {
|
||
this.exitSpeedChart && this.exitSpeedChart.dispose()
|
||
this.tempChart && this.tempChart.dispose()
|
||
this.forceChart && this.forceChart.dispose()
|
||
this.paintTempChart && this.paintTempChart.dispose()
|
||
},
|
||
// ✅ 渲染折线图通用方法
|
||
renderLineChart(chart, xData, seriesData, color, yTitle) {
|
||
if(!chart) return
|
||
const option = {
|
||
color: color,
|
||
grid: { left: 30, right: 30, top: 40, bottom: 30 },
|
||
tooltip: { trigger: 'axis' },
|
||
legend: { top: 0, left: 'center', textStyle: { fontSize: 12 } },
|
||
xAxis: { type: 'category', data: xData, axisLine: { show: false } },
|
||
yAxis: {
|
||
type: 'value',
|
||
name: yTitle,
|
||
splitLine: { type: 'dashed', color: '#e4e7ed' }
|
||
},
|
||
series: seriesData.map(item => ({
|
||
name: item.name,
|
||
type: 'line',
|
||
data: item.data,
|
||
smooth: true,
|
||
lineStyle: { width: 2 },
|
||
symbol: 'none'
|
||
}))
|
||
}
|
||
chart.setOption(option, true)
|
||
},
|
||
// 启动自动刷新(每30秒) 逻辑完全未改
|
||
startAutoRefresh() {
|
||
this.refreshTimer = setInterval(() => {
|
||
console.log('自动刷新数据...')
|
||
this.refreshData(true) // 静默刷新
|
||
}, 30000) // 30秒刷新一次
|
||
},
|
||
// 停止自动刷新 逻辑完全未改
|
||
stopAutoRefresh() {
|
||
if (this.refreshTimer) {
|
||
clearInterval(this.refreshTimer)
|
||
this.refreshTimer = null
|
||
}
|
||
},
|
||
// 加载所有数据(初始化) 逻辑完全未改
|
||
loadAllData() {
|
||
this.checkNetworkStatus() // 检测网络状态
|
||
this.loadCurrentShift() // 加载当前班组
|
||
this.initPlantStateDefines() // 加载所有定义
|
||
this.updateLastTime() // 更新时间
|
||
},
|
||
// 刷新数据(手动或自动) ✅ 替换uni弹窗为Element弹窗
|
||
refreshData(isSilent = false) {
|
||
if (this.isRefreshing) return // 防止重复刷新
|
||
this.isRefreshing = true
|
||
|
||
let loading = null
|
||
if (!isSilent) {
|
||
loading = this.$loading({ lock: true, text: '刷新中', spinner: 'el-icon-loading' })
|
||
}
|
||
|
||
Promise.all([
|
||
this.checkNetworkStatus(),
|
||
this.loadCurrentShift(),
|
||
this.initPlantStateDefines(isSilent)
|
||
]).finally(() => {
|
||
this.isRefreshing = false
|
||
loading && loading.close()
|
||
if (!isSilent) {
|
||
this.$message.success('刷新成功')
|
||
}
|
||
this.updateLastTime()
|
||
})
|
||
},
|
||
// 更新最后刷新时间 逻辑完全未改
|
||
updateLastTime() {
|
||
const now = new Date()
|
||
const hour = String(now.getHours()).padStart(2, '0')
|
||
const minute = String(now.getMinutes()).padStart(2, '0')
|
||
const second = String(now.getSeconds()).padStart(2, '0')
|
||
this.lastUpdateTime = `${hour}:${minute}:${second}`
|
||
},
|
||
// 检测网络状态 ✅ 替换uni.request为axios
|
||
checkNetworkStatus() {
|
||
return new Promise((resolve) => {
|
||
const startTime = Date.now()
|
||
axios.get(`http://140.143.206.120:8080/pocket/proPlantStateDefine/allWithValues`, { timeout: 5000 })
|
||
.then(() => {
|
||
const responseTime = Date.now() - startTime
|
||
if (responseTime < 500) this.webStatus[0].value = '通畅'
|
||
else if (responseTime < 2000) this.webStatus[0].value = '卡顿'
|
||
else this.webStatus[0].value = '异常'
|
||
resolve()
|
||
}).catch(() => {
|
||
this.webStatus[0].value = '异常'
|
||
resolve()
|
||
})
|
||
})
|
||
},
|
||
// 加载当前班组信息 逻辑完全未改
|
||
loadCurrentShift() {
|
||
return getCurrentShift().then(response => {
|
||
if (response.code === 200 && response.data) {
|
||
const shiftData = response.data
|
||
const shiftName = this.getShiftName(shiftData.shift)
|
||
const crewName = this.getCrewName(shiftData.crew)
|
||
this.webStatus[1].value = `${crewName} / ${shiftName}`
|
||
}
|
||
}).catch(error => {
|
||
console.error('加载班组信息失败:', error)
|
||
})
|
||
},
|
||
// 获取班次名称 逻辑完全未改
|
||
getShiftName(shift) {
|
||
const shiftMap = { 'A': '早班', 'B': '中班', 'C': '晚班' }
|
||
return shiftMap[shift] || shift || '—'
|
||
},
|
||
// 获取班组名称 逻辑完全未改
|
||
getCrewName(crew) {
|
||
const crewMap = { 1: '甲', 2: '乙', 3: '丙', 4: '丁' }
|
||
return crewMap[crew] || crew || '—'
|
||
},
|
||
// 初始化:加载所有状态定义及其当前值 ✅ 替换uni弹窗为Element弹窗
|
||
initPlantStateDefines(isSilent = false) {
|
||
let loading = null
|
||
if (!isSilent) {
|
||
loading = this.$loading({ lock: true, text: '加载中', spinner: 'el-icon-loading' })
|
||
}
|
||
return getAllPlantStateDefines().then(response => {
|
||
if (response.code === 200 && response.data) {
|
||
this.plantStateDefines = response.data
|
||
this.updateCurrentMetrics()
|
||
return this.loadTempTrend(isSilent)
|
||
}
|
||
}).finally(() => {
|
||
loading && loading.close()
|
||
}).catch(error => {
|
||
loading && loading.close()
|
||
console.error('加载状态定义失败:', error)
|
||
})
|
||
},
|
||
// 更新所有实时指标 逻辑完全未改
|
||
updateCurrentMetrics() {
|
||
// 速度监控
|
||
const exitSpeed = this.getDefineById(1)
|
||
const plSpeed = this.getDefineById(2)
|
||
const trimSpeed = this.getDefineById(3)
|
||
this.speedMetrics = [
|
||
{ label: exitSpeed?.comments || '出口带钢速度', value: this.formatValue(exitSpeed?.currentValue), unit: exitSpeed?.units || 'm/min' },
|
||
{ label: plSpeed?.comments || '酸洗带钢速度', value: this.formatValue(plSpeed?.currentValue), unit: plSpeed?.units || 'm/min' },
|
||
{ label: trimSpeed?.comments || '圆盘剪速度', value: this.formatValue(trimSpeed?.currentValue), unit: trimSpeed?.units || 'm/min' }
|
||
]
|
||
// 活套状态
|
||
const celLooper = this.getDefineById(8)
|
||
const cxlLooper = this.getDefineById(9)
|
||
const telLooper = this.getDefineById(10)
|
||
this.looperMetrics = [
|
||
{ label: celLooper?.comments || '入口重套', value: this.formatValue(celLooper?.currentValue), unit: celLooper?.units || '%' },
|
||
{ label: cxlLooper?.comments || '出口活套', value: this.formatValue(cxlLooper?.currentValue), unit: cxlLooper?.units || '%' },
|
||
{ label: telLooper?.comments || '联机活套', value: this.formatValue(telLooper?.currentValue), unit: telLooper?.units || '%' }
|
||
]
|
||
// 酸槽浓度
|
||
this.tankConcentration = [
|
||
{ name: '1#酸槽', hclCont: this.formatValue(this.getDefineById(11)?.currentValue), feCont: this.formatValue(this.getDefineById(12)?.currentValue) },
|
||
{ name: '2#酸槽', hclCont: this.formatValue(this.getDefineById(13)?.currentValue), feCont: this.formatValue(this.getDefineById(14)?.currentValue) },
|
||
{ name: '3#酸槽', hclCont: this.formatValue(this.getDefineById(15)?.currentValue), feCont: this.formatValue(this.getDefineById(16)?.currentValue) }
|
||
]
|
||
// 工艺参数
|
||
const rinseTemp = this.getDefineById(7)
|
||
const windTemp = this.getDefineById(17)
|
||
const rinseFlow = this.getDefineById(18)
|
||
const telTension = this.getDefineById(19)
|
||
const tlvElong = this.getDefineById(20)
|
||
this.processMetrics = [
|
||
{ label: rinseTemp?.comments || '漂洗温度', value: this.formatValue(rinseTemp?.currentValue), unit: rinseTemp?.units || '°C' },
|
||
{ label: windTemp?.comments || '烘干温度', value: this.formatValue(windTemp?.currentValue), unit: windTemp?.units || '°C' },
|
||
{ label: rinseFlow?.comments || '漂洗电导率', value: this.formatValue(rinseFlow?.currentValue), unit: rinseFlow?.units || 'g/L' },
|
||
{ label: telTension?.comments || '联机活套张力', value: this.formatValue(telTension?.currentValue), unit: telTension?.units || 'kN' },
|
||
{ label: tlvElong?.comments || '拉矫机延伸率', value: this.formatValue(tlvElong?.currentValue), unit: tlvElong?.units || '%' }
|
||
]
|
||
// 镀锌线-轧辊速度
|
||
this.rollSpeedMetrics = [
|
||
{ label: '1#机架', value: this.formatValue(this.getDefineById(36)?.currentValue), unit: 'm/min' },
|
||
{ label: '2#机架', value: this.formatValue(this.getDefineById(37)?.currentValue), unit: 'm/min' },
|
||
{ label: '3#机架', value: this.formatValue(this.getDefineById(38)?.currentValue), unit: 'm/min' },
|
||
{ label: '4#机架', value: this.formatValue(this.getDefineById(39)?.currentValue), unit: 'm/min' },
|
||
{ label: '5#机架', value: this.formatValue(this.getDefineById(40)?.currentValue), unit: 'm/min' },
|
||
{ label: '6#机架', value: this.formatValue(this.getDefineById(41)?.currentValue), unit: 'm/min' }
|
||
]
|
||
// 镀锌线-压下率
|
||
this.reducMetrics = [
|
||
{ label: '1#机架', value: this.formatValue(this.getDefineById(24)?.currentValue), unit: '%' },
|
||
{ label: '2#机架', value: this.formatValue(this.getDefineById(25)?.currentValue), unit: '%' },
|
||
{ label: '3#机架', value: this.formatValue(this.getDefineById(26)?.currentValue), unit: '%' },
|
||
{ label: '4#机架', value: this.formatValue(this.getDefineById(27)?.currentValue), unit: '%' },
|
||
{ label: '5#机架', value: this.formatValue(this.getDefineById(28)?.currentValue), unit: '%' },
|
||
{ label: '6#机架', value: this.formatValue(this.getDefineById(29)?.currentValue), unit: '%' }
|
||
]
|
||
// 镀锌线-张力
|
||
this.tensionMetrics = [
|
||
{ label: '0#张力', value: this.formatValue(this.getDefineById(42)?.currentValue), unit: 'kN' },
|
||
{ label: '1#张力', value: this.formatValue(this.getDefineById(43)?.currentValue), unit: 'kN' },
|
||
{ label: '2#张力', value: this.formatValue(this.getDefineById(44)?.currentValue), unit: 'kN' },
|
||
{ label: '3#张力', value: this.formatValue(this.getDefineById(45)?.currentValue), unit: 'kN' },
|
||
{ label: '4#张力', value: this.formatValue(this.getDefineById(46)?.currentValue), unit: 'kN' },
|
||
{ label: '5#张力', value: this.formatValue(this.getDefineById(47)?.currentValue), unit: 'kN' },
|
||
{ label: '6#张力', value: this.formatValue(this.getDefineById(48)?.currentValue), unit: 'kN' }
|
||
]
|
||
// 镀锌线-功率
|
||
this.powerMetrics = [
|
||
{ label: '1#机架', value: this.formatValue(this.getDefineById(49)?.currentValue), unit: '%' },
|
||
{ label: '2#机架', value: this.formatValue(this.getDefineById(50)?.currentValue), unit: '%' },
|
||
{ label: '3#机架', value: this.formatValue(this.getDefineById(51)?.currentValue), unit: '%' },
|
||
{ label: '4#机架', value: this.formatValue(this.getDefineById(52)?.currentValue), unit: '%' },
|
||
{ label: '5#机架', value: this.formatValue(this.getDefineById(53)?.currentValue), unit: '%' },
|
||
{ label: '6#机架', value: this.formatValue(this.getDefineById(54)?.currentValue), unit: '%' }
|
||
]
|
||
// 涂装线-速度
|
||
this.paintSpeedMetrics = [
|
||
{ label: '出口带钢速度', value: this.formatValue(this.getDefineById(1)?.currentValue), unit: 'm/min' },
|
||
{ label: '涂装带钢速度', value: this.formatValue(this.getDefineById(2)?.currentValue), unit: 'm/min' },
|
||
{ label: '圆盘剪速度', value: this.formatValue(this.getDefineById(3)?.currentValue), unit: 'm/min' }
|
||
]
|
||
// 涂装线-拉矫参数
|
||
this.tlvMetrics = [
|
||
{ label: '拉矫延伸率', value: this.formatValue(this.getDefineById(20)?.currentValue), unit: '%' },
|
||
{ label: '破磷机插入量1', value: this.formatValue(this.getDefineById(21)?.currentValue), unit: 'mm' },
|
||
{ label: '破磷机插入量2', value: this.formatValue(this.getDefineById(22)?.currentValue), unit: 'mm' },
|
||
{ label: '破磷机插入量3', value: this.formatValue(this.getDefineById(23)?.currentValue), unit: 'mm' }
|
||
]
|
||
},
|
||
// 加载历史趋势图数据 ✅ 渲染Echarts图表
|
||
loadTempTrend(isSilent = false) {
|
||
return listPlantStateHistory({ pageNum: 1, pageSize: 30 }).then(response => {
|
||
if (response.code === 200 && response.rows && response.rows.length > 0) {
|
||
const categories = []
|
||
const tank1Data = [];const tank2Data = [];const tank3Data = [];
|
||
const exitSpeedData = [];
|
||
const force1Data = [];const force2Data = [];const force3Data = [];const force4Data = [];const force5Data = [];const force6Data = [];
|
||
const paintTemp1 = [];const paintTemp2 = [];const paintTemp3 = [];const paintTemp4 = [];const paintTemp5 = [];
|
||
|
||
response.rows.forEach(item => {
|
||
const dateStr = this.formatDate(item.insdate)
|
||
categories.push(dateStr)
|
||
tank1Data.push(Number(item.value4) || 0)
|
||
tank2Data.push(Number(item.value5) || 0)
|
||
tank3Data.push(Number(item.value6) || 0)
|
||
exitSpeedData.push(Number(item.value1) || 0)
|
||
force1Data.push(Number(item.value30) || 0)
|
||
force2Data.push(Number(item.value31) || 0)
|
||
force3Data.push(Number(item.value32) || 0)
|
||
force4Data.push(Number(item.value33) || 0)
|
||
force5Data.push(Number(item.value34) || 0)
|
||
force6Data.push(Number(item.value35) || 0)
|
||
paintTemp1.push(Number(item.value4) || 0)
|
||
paintTemp2.push(Number(item.value5) || 0)
|
||
paintTemp3.push(Number(item.value6) || 0)
|
||
paintTemp4.push(Number(item.value7) || 0)
|
||
paintTemp5.push(Number(item.value17) || 0)
|
||
})
|
||
const reverseCate = categories.reverse()
|
||
// 渲染出口速度趋势
|
||
this.renderLineChart(this.exitSpeedChart, reverseCate, [{name:'出口带钢速度',data:exitSpeedData.reverse()}], this.lineColor, 'm/min')
|
||
// 渲染酸槽温度趋势
|
||
this.renderLineChart(this.tempChart, reverseCate, [
|
||
{name:'1#酸槽温度',data:tank1Data.reverse()},
|
||
{name:'2#酸槽温度',data:tank2Data.reverse()},
|
||
{name:'3#酸槽温度',data:tank3Data.reverse()}
|
||
], this.lineColor, '°C')
|
||
// 渲染轧制力趋势
|
||
this.renderLineChart(this.forceChart, reverseCate, [
|
||
{name:'1#轧制力',data:force1Data.reverse()},
|
||
{name:'2#轧制力',data:force2Data.reverse()},
|
||
{name:'3#轧制力',data:force3Data.reverse()},
|
||
{name:'4#轧制力',data:force4Data.reverse()},
|
||
{name:'5#轧制力',data:force5Data.reverse()},
|
||
{name:'6#轧制力',data:force6Data.reverse()}
|
||
], this.forceColor, 'kN')
|
||
// 渲染烘干温度趋势
|
||
this.renderLineChart(this.paintTempChart, reverseCate, [
|
||
{name:'1#酸槽温度',data:paintTemp1.reverse()},
|
||
{name:'2#酸槽温度',data:paintTemp2.reverse()},
|
||
{name:'3#酸槽温度',data:paintTemp3.reverse()},
|
||
{name:'漂洗温度',data:paintTemp4.reverse()},
|
||
{name:'烘干温度',data:paintTemp5.reverse()}
|
||
], this.paintColor, '°C')
|
||
}
|
||
}).catch(error => {
|
||
console.error('加载历史趋势失败:', error)
|
||
})
|
||
},
|
||
// 根据ID获取Define对象 逻辑完全未改
|
||
getDefineById(id) {
|
||
return this.plantStateDefines.find(item => item.id == id)
|
||
},
|
||
// 格式化日期 逻辑完全未改
|
||
formatDate(dateStr) {
|
||
if (!dateStr) return ''
|
||
const date = new Date(dateStr)
|
||
const hour = String(date.getHours()).padStart(2, '0')
|
||
const minute = String(date.getMinutes()).padStart(2, '0')
|
||
return `${hour}:${minute}`
|
||
},
|
||
// 格式化数值 逻辑完全未改
|
||
formatValue(value) {
|
||
if (value === null || value === undefined || value === '') return '—'
|
||
const num = Number(value)
|
||
if (isNaN(num)) return '—'
|
||
return num.toFixed(2)
|
||
},
|
||
// 滚动到指定部分 ✅ PC端原生滚动适配
|
||
scrollToSection(sectionId) {
|
||
document.getElementById(sectionId).scrollIntoView({ behavior: 'smooth' })
|
||
this.navMenuExpanded = false // 点击后关闭菜单
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
// ✅ 所有rpx转px(1rpx=0.5px) PC端完美适配 | 移除tab相关样式
|
||
.page-container {
|
||
min-height: 100vh;
|
||
background: #f5f7fa;
|
||
position: relative;
|
||
}
|
||
|
||
/* 刷新按钮(固定在右下角) */
|
||
.refresh-btn-fixed {
|
||
position: fixed;
|
||
right: 16px;
|
||
bottom: 60px;
|
||
width: 48px;
|
||
height: 48px;
|
||
background: #0066cc;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
box-shadow: 0 4px 10px rgba(0, 102, 204, 0.4);
|
||
z-index: 999;
|
||
cursor: pointer;
|
||
&:active { opacity: 0.8; transform: scale(0.95); }
|
||
}
|
||
.refresh-icon {
|
||
font-size: 24px;
|
||
color: #fff;
|
||
display: block;
|
||
line-height: 1;
|
||
&.rotating { animation: rotate 1s linear infinite; }
|
||
}
|
||
@keyframes rotate { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
|
||
|
||
/* 快速导航菜单(固定在左下角) */
|
||
.nav-menu-fixed {
|
||
position: fixed;
|
||
left: 16px;
|
||
bottom: 60px;
|
||
z-index: 998;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
gap: 6px;
|
||
}
|
||
.nav-toggle {
|
||
width: 48px;height: 48px;
|
||
background: #409eff;
|
||
border-radius: 50%;
|
||
display: flex;align-items: center;justify-content: center;
|
||
box-shadow: 0 4px 10px rgba(64, 158, 255, 0.4);
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
&:active { opacity: 0.8; transform: scale(0.95); }
|
||
}
|
||
.nav-toggle-icon { font-size: 24px; color: #fff; display: block; line-height: 1; }
|
||
.nav-items {
|
||
display: flex;flex-direction: column;gap:4px;
|
||
animation: slideUp 0.3s ease;
|
||
}
|
||
@keyframes slideUp { from { opacity:0; transform: translateY(10px); } to { opacity:1; transform: translateY(0); } }
|
||
.nav-item {
|
||
background: #fff;border:1px solid #409eff;border-radius:4px;
|
||
padding:8px 12px;cursor: pointer;
|
||
box-shadow: 0 2px 6px rgba(64,158,255,0.2);
|
||
transition: all 0.2s ease;
|
||
&:active { background: #f0f9ff; transform: scale(0.95); }
|
||
}
|
||
.nav-label { font-size:13px; color:#409eff; font-weight:500; white-space: nowrap; }
|
||
|
||
/* 滚动容器 - PC端原生滚动 核心修改 */
|
||
.scroll-container {
|
||
height: calc(100vh - 20px);
|
||
padding: 12px;
|
||
overflow-y: auto;
|
||
scroll-behavior: smooth;
|
||
}
|
||
|
||
/* 顶部状态栏 */
|
||
.status-bar {
|
||
display: flex;align-items: center;
|
||
background: #fff;padding:12px 16px;margin-bottom:12px;
|
||
border-radius:4px;border:1px solid #e4e7ed;
|
||
}
|
||
.status-item { flex:1; display:flex;align-items:center;justify-content:center;gap:8px; }
|
||
.status-label { font-size:13px;color:#909399; }
|
||
.status-value {
|
||
font-size:14px;font-weight:500;color:#303133;
|
||
&.status-通畅 { color: #67c23a; }
|
||
&.status-卡顿 { color: #e6a23c; }
|
||
&.status-异常 { color: #f56c6c; }
|
||
&.status-time { color:#909399;font-size:12px; }
|
||
}
|
||
.status-divider { width:1px;height:20px;background:#e4e7ed; }
|
||
|
||
/* 区块样式 */
|
||
.section { margin-bottom:12px; }
|
||
.section-title {
|
||
font-size:15px;font-weight:500;color:#303133;
|
||
margin-bottom:10px;padding-left:8px;border-left:2px solid #0066cc;
|
||
}
|
||
|
||
/* 分隔符 */
|
||
.section-divider {
|
||
display:flex;align-items:center;margin:20px 0 12px 0;padding:0 8px;
|
||
}
|
||
.divider-text {
|
||
font-size:14px;font-weight:600;color:#0066cc;
|
||
padding:0 6px;background:#f5f7fa;
|
||
border-left:2px solid #0066cc;padding-left:8px;
|
||
}
|
||
|
||
/* 指标卡片 - 3列布局 */
|
||
.metrics-grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap:10px; }
|
||
/* 指标卡片 - 2列布局 */
|
||
.metrics-grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap:10px; }
|
||
.metric-box {
|
||
background:#fff;border:1px solid #e4e7ed;border-radius:4px;
|
||
padding:14px 10px;text-align:center;
|
||
}
|
||
.metric-name { display:block;font-size:12px;color:#909399;margin-bottom:8px; }
|
||
.metric-value { display:block;font-size:24px;font-weight:600;color:#0066cc;margin-bottom:4px;line-height:1; }
|
||
.metric-unit { display:block;font-size:11px;color:#909399; }
|
||
|
||
/* 图表容器 */
|
||
.chart-box {
|
||
background:#fff;border:1px solid #e4e7ed;border-radius:4px;
|
||
padding:12px 8px;height:225px;width:100%;
|
||
}
|
||
|
||
/* 酸槽监控网格 */
|
||
.tank-grid { display:grid;grid-template-columns:repeat(3,1fr);gap:10px; }
|
||
.tank-card { background:#fff;border:2px solid #0066cc;border-radius:4px;overflow:hidden; }
|
||
.tank-header { background:#0066cc;color:#fff;font-size:14px;font-weight:500;padding:10px;text-align:center; }
|
||
.tank-data { padding:12px 8px; }
|
||
.tank-row { display:flex;flex-direction:column;align-items:center;padding:6px 0; }
|
||
.data-label { font-size:11px;color:#909399;margin-bottom:4px; }
|
||
.data-value { font-size:18px;font-weight:600;color:#303133; }
|
||
.data-unit { font-size:10px;font-weight:400;color:#909399;margin-left:2px; }
|
||
.tank-divider { height:1px;background:#e4e7ed;margin:6px 0; }
|
||
</style> |