Files
klp-mono/apps/hand-factory/components/lines/acidity.vue
2026-01-15 20:18:37 +08:00

1323 lines
42 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="page-container">
<!-- 简洁标签栏 -->
<view class="tab-container">
<view
v-for="item in tabData"
:key="item.value"
@click="currentTab = item.value"
class="tab-item"
:class="{ 'tab-active': currentTab === item.value }"
>
<text class="tab-label">{{ item.text }}</text>
<view class="tab-indicator" v-if="currentTab === item.value"></view>
</view>
</view>
<!-- 刷新按钮固定在右下角所有tab都显示 -->
<view class="refresh-btn-fixed" @click="refreshData">
<text class="refresh-icon" :class="{ 'rotating': isRefreshing }"></text>
</view>
<!-- 快速导航菜单固定在左下角 -->
<view class="nav-menu-fixed" :class="{ 'nav-expanded': navMenuExpanded }">
<view class="nav-toggle" @click="navMenuExpanded = !navMenuExpanded">
<text class="nav-toggle-icon">{{ navMenuExpanded ? '✕' : '☰' }}</text>
</view>
<view class="nav-items" v-if="navMenuExpanded">
<view class="nav-item" @click="scrollToSection('speed-monitor')">
<text class="nav-label">速度监控</text>
</view>
<view class="nav-item" @click="scrollToSection('exit-speed-chart')">
<text class="nav-label">出口速度趋势</text>
</view>
<view class="nav-item" @click="scrollToSection('temp-chart')">
<text class="nav-label">酸槽温度趋势</text>
</view>
<view class="nav-item" @click="scrollToSection('looper-status')">
<text class="nav-label">活套运行状态</text>
</view>
<view class="nav-item" @click="scrollToSection('tank-concentration')">
<text class="nav-label">酸槽浓度监控</text>
</view>
<view class="nav-item" @click="scrollToSection('force-chart')">
<text class="nav-label">轧制力趋势</text>
</view>
<view class="nav-item" @click="scrollToSection('process-params')">
<text class="nav-label">工艺参数</text>
</view>
<view class="nav-item" @click="scrollToSection('roll-speed')">
<text class="nav-label">轧辊速度监控</text>
</view>
<view class="nav-item" @click="scrollToSection('reduc-rate')">
<text class="nav-label">机架压下率</text>
</view>
<view class="nav-item" @click="scrollToSection('tension-monitor')">
<text class="nav-label">带钢张力监控</text>
</view>
<view class="nav-item" @click="scrollToSection('power-ratio')">
<text class="nav-label">机架功率百分比</text>
</view>
<view class="nav-item" @click="scrollToSection('paint-speed')">
<text class="nav-label">涂装速度监控</text>
</view>
<view class="nav-item" @click="scrollToSection('tlv-params')">
<text class="nav-label">拉矫参数</text>
</view>
<view class="nav-item" @click="scrollToSection('paint-temp-chart')">
<text class="nav-label">烘干温度趋势</text>
</view>
</view>
</view>
<scroll-view scroll-y class="scroll-container" v-if="currentTab === 1" :scroll-into-view="scrollIntoView">
<!-- 顶部状态栏 -->
<view class="status-bar">
<view class="status-item">
<text class="status-label">网络状态</text>
<text class="status-value" :class="'status-' + webStatus[0].value">{{ webStatus[0].value }}</text>
</view>
<view class="status-divider"></view>
<view class="status-item">
<text class="status-label">当前班组</text>
<text class="status-value">{{ webStatus[1].value }}</text>
</view>
<view class="status-divider"></view>
<view class="status-item">
<text class="status-label">更新时间</text>
<text class="status-value status-time">{{ lastUpdateTime }}</text>
</view>
</view>
<!-- 速度监控 -->
<view class="section" id="speed-monitor">
<view class="section-title">速度监控</view>
<view class="metrics-grid-3">
<view class="metric-box" v-for="(item, index) in speedMetrics" :key="index">
<text class="metric-name">{{ item.label }}</text>
<text class="metric-value">{{ item.value }}</text>
<text class="metric-unit">{{ item.unit }}</text>
</view>
</view>
</view>
<!-- 出口速度趋势 -->
<view class="section" id="exit-speed-chart">
<view class="section-title">出口速度趋势</view>
<view class="chart-box">
<qiun-data-charts type="line" :chartData="exitSpeedChartData" :opts="lineChartOpts" />
</view>
</view>
<!-- 酸槽温度趋势 -->
<view class="section" id="temp-chart">
<view class="section-title">酸槽温度趋势</view>
<view class="chart-box">
<qiun-data-charts type="line" :chartData="tempChartData" :opts="lineChartOpts" />
</view>
</view>
<!-- 活套运行状态 -->
<view class="section" id="looper-status">
<view class="section-title">活套运行状态</view>
<view class="metrics-grid-3">
<view class="metric-box" v-for="(item, index) in looperMetrics" :key="index">
<text class="metric-name">{{ item.label }}</text>
<text class="metric-value">{{ item.value }}</text>
<text class="metric-unit">{{ item.unit }}</text>
</view>
</view>
</view>
<!-- 酸槽浓度监控 -->
<view class="section" id="tank-concentration">
<view class="section-title">酸槽浓度监控</view>
<view class="tank-grid">
<view class="tank-card" v-for="(tank, index) in tankConcentration" :key="index">
<view class="tank-header">{{ tank.name }}</view>
<view class="tank-data">
<view class="tank-row">
<text class="data-label">酸浓度</text>
<text class="data-value">{{ tank.hclCont }} <text class="data-unit">g/L</text></text>
</view>
<view class="tank-divider"></view>
<view class="tank-row">
<text class="data-label">铁盐浓度</text>
<text class="data-value">{{ tank.feCont }} <text class="data-unit">g/L</text></text>
</view>
</view>
</view>
</view>
</view>
<!-- 轧制力趋势 -->
<view class="section" id="force-chart">
<view class="section-title">轧制力趋势</view>
<view class="chart-box">
<qiun-data-charts type="line" :chartData="forceChartData" :opts="forceLineChartOpts" />
</view>
</view>
<!-- 工艺参数 -->
<view class="section" id="process-params">
<view class="section-title">工艺参数</view>
<view class="metrics-grid-2">
<view class="metric-box" v-for="(item, index) in processMetrics" :key="index">
<text class="metric-name">{{ item.label }}</text>
<text class="metric-value">{{ item.value }}</text>
<text class="metric-unit">{{ item.unit }}</text>
</view>
</view>
</view>
<!-- ============ 镀锌线数据 ============ -->
<view class="section-divider">
<text class="divider-text">镀锌线监控数据</text>
</view>
<!-- 轧辊速度监控 -->
<view class="section" id="roll-speed">
<view class="section-title">轧辊速度监控</view>
<view class="metrics-grid-3">
<view class="metric-box" v-for="(item, index) in rollSpeedMetrics" :key="index">
<text class="metric-name">{{ item.label }}</text>
<text class="metric-value">{{ item.value }}</text>
<text class="metric-unit">{{ item.unit }}</text>
</view>
</view>
</view>
<!-- 机架压下率 -->
<view class="section" id="reduc-rate">
<view class="section-title">机架压下率</view>
<view class="metrics-grid-3">
<view class="metric-box" v-for="(item, index) in reducMetrics" :key="index">
<text class="metric-name">{{ item.label }}</text>
<text class="metric-value">{{ item.value }}</text>
<text class="metric-unit">{{ item.unit }}</text>
</view>
</view>
</view>
<!-- 带钢张力监控 -->
<view class="section" id="tension-monitor">
<view class="section-title">带钢张力监控</view>
<view class="metrics-grid-3">
<view class="metric-box" v-for="(item, index) in tensionMetrics" :key="index">
<text class="metric-name">{{ item.label }}</text>
<text class="metric-value">{{ item.value }}</text>
<text class="metric-unit">{{ item.unit }}</text>
</view>
</view>
</view>
<!-- 机架功率百分比 -->
<view class="section" id="power-ratio">
<view class="section-title">机架功率百分比</view>
<view class="metrics-grid-3">
<view class="metric-box" v-for="(item, index) in powerMetrics" :key="index">
<text class="metric-name">{{ item.label }}</text>
<text class="metric-value">{{ item.value }}</text>
<text class="metric-unit">{{ item.unit }}</text>
</view>
</view>
</view>
<!-- ============ 涂装线数据 ============ -->
<view class="section-divider">
<text class="divider-text">涂装线监控数据</text>
</view>
<!-- 涂装速度监控 -->
<view class="section" id="paint-speed">
<view class="section-title">涂装速度监控</view>
<view class="metrics-grid-3">
<view class="metric-box" v-for="(item, index) in paintSpeedMetrics" :key="index">
<text class="metric-name">{{ item.label }}</text>
<text class="metric-value">{{ item.value }}</text>
<text class="metric-unit">{{ item.unit }}</text>
</view>
</view>
</view>
<!-- 拉矫参数 -->
<view class="section" id="tlv-params">
<view class="section-title">拉矫参数</view>
<view class="metrics-grid-2">
<view class="metric-box" v-for="(item, index) in tlvMetrics" :key="index">
<text class="metric-name">{{ item.label }}</text>
<text class="metric-value">{{ item.value }}</text>
<text class="metric-unit">{{ item.unit }}</text>
</view>
</view>
</view>
<!-- 烘干温度趋势 -->
<view class="section" id="paint-temp-chart">
<view class="section-title">烘干温度趋势</view>
<view class="chart-box">
<qiun-data-charts type="line" :chartData="paintTempChartData" :opts="paintLineChartOpts" />
</view>
</view>
</scroll-view>
<scroll-view scroll-y class="scroll-container" v-if="currentTab == 2">
<klp-product-statistic></klp-product-statistic>
</scroll-view>
<scroll-view scroll-y class="scroll-container" v-if="currentTab == 3">
<klp-shutdown-statistic></klp-shutdown-statistic>
</scroll-view>
<scroll-view scroll-y class="scroll-container" v-if="currentTab == 4">
<klp-team-performance></klp-team-performance>
</scroll-view>
</view>
</template>
<script>
import { getAllPlantStateDefines, listPlantStateHistory, getCurrentShift } from '@/api/pocket/plantState'
import config from '@/config'
export default {
data() {
return {
currentTab: 1,
tabData: [
{ text: "实时监控", value: 1 },
{ text: "生产统计", value: 2 },
{ text: "停机统计", value: 3 },
{ text: "班组绩效", value: 4 }
],
webStatus: [
{ label: '网络状态', value: '检测中...' },
{ label: '当前班组', value: '—' }
],
lastUpdateTime: '—', // 最后更新时间
isRefreshing: false, // 是否正在刷新
refreshTimer: null, // 定时器
navMenuExpanded: false, // 导航菜单是否展开
scrollIntoView: '', // 滚动目标
// 速度监控指标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' }
],
// 温度趋势图数据ID=4,5,6
tempChartData: {},
// 出口速度趋势图数据ID=1
exitSpeedChartData: {},
// 轧制力趋势图数据ID=30-35
forceChartData: {},
// 涂装线温度趋势图数据ID=4-7, 17
paintTempChartData: {},
lineChartOpts: {
color: ["#0066cc", "#409eff", "#66b1ff"],
padding: [15, 15, 0, 15],
enableScroll: false,
legend: {
show: true,
position: "top",
fontSize: 10,
lineHeight: 14,
itemGap: 6
},
dataLabel: false, // 隐藏数据标签
dataPointShape: false, // 隐藏数据点
xAxis: {
disableGrid: true,
rotateLabel: true,
itemCount: 5, // 减少标签数量
labelCount: 5,
fontSize: 10
},
yAxis: {
gridType: "dash",
dashLength: 4,
gridColor: "#e4e7ed",
showTitle: true,
fontSize: 10,
data: [{ min: 0, title: "m/min" }]
},
extra: {
line: {
type: "curve",
width: 2,
activeType: "hollow"
}
}
},
forceLineChartOpts: {
color: ["#0066cc", "#409eff", "#66b1ff", "#a0cfff", "#d9ecff", "#ecf5ff"],
padding: [15, 15, 0, 15],
enableScroll: false,
legend: {
show: true,
position: "top",
fontSize: 10,
lineHeight: 14,
itemGap: 6
},
dataLabel: false,
dataPointShape: false,
xAxis: {
disableGrid: true,
rotateLabel: true,
itemCount: 5,
labelCount: 5,
fontSize: 10
},
yAxis: {
gridType: "dash",
dashLength: 4,
gridColor: "#e4e7ed",
showTitle: true,
fontSize: 10,
data: [{ min: 0, title: "轧制力(kN)" }]
},
extra: {
line: {
type: "curve",
width: 2,
activeType: "hollow"
}
}
},
paintLineChartOpts: {
color: ["#0066cc", "#409eff", "#66b1ff", "#a0cfff", "#d9ecff"],
padding: [15, 15, 0, 15],
enableScroll: false,
legend: {
show: true,
position: "top",
fontSize: 10,
lineHeight: 14,
itemGap: 6
},
dataLabel: false,
dataPointShape: false,
xAxis: {
disableGrid: true,
rotateLabel: true,
itemCount: 5,
labelCount: 5,
fontSize: 10
},
yAxis: {
gridType: "dash",
dashLength: 4,
gridColor: "#e4e7ed",
showTitle: true,
fontSize: 10,
data: [{ min: 0, title: "温度(°C)" }]
},
extra: {
line: {
type: "curve",
width: 2,
activeType: "hollow"
}
}
},
plantStateDefines: [] // 缓存所有的状态定义
};
},
mounted() {
this.loadAllData() // 加载所有数据
this.startAutoRefresh() // 启动自动刷新
},
beforeDestroy() {
this.stopAutoRefresh() // 页面销毁时清除定时器
},
methods: {
// 启动自动刷新每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() // 更新时间
},
// 刷新数据(手动或自动)
refreshData(isSilent = false) {
if (this.isRefreshing) return // 防止重复刷新
this.isRefreshing = true
if (!isSilent) {
uni.showLoading({ title: '刷新中' })
}
// 依次刷新各个数据
Promise.all([
this.checkNetworkStatus(),
this.loadCurrentShift(),
this.initPlantStateDefines(isSilent)
]).finally(() => {
this.isRefreshing = false
if (!isSilent) {
uni.hideLoading()
uni.showToast({ title: '刷新成功', icon: 'success', duration: 1500 })
}
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}`
},
// 检测网络状态
checkNetworkStatus() {
return new Promise((resolve) => {
const startTime = Date.now()
uni.request({
url: config.baseUrl + '/pocket/proPlantStateDefine/allWithValues',
method: 'GET',
timeout: 5000,
success: (res) => {
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()
},
fail: () => {
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 || '—'
},
// 初始化:加载所有状态定义及其当前值
initPlantStateDefines(isSilent = false) {
if (!isSilent) {
uni.showLoading({ title: '加载中' })
}
return getAllPlantStateDefines().then(response => {
if (response.code === 200 && response.data) {
this.plantStateDefines = response.data
if (!isSilent) {
console.log('状态定义已加载:', this.plantStateDefines)
}
// 更新所有实时指标
this.updateCurrentMetrics()
// 加载温度趋势图
return this.loadTempTrend(isSilent)
} else {
if (!isSilent) {
uni.hideLoading()
}
}
}).catch(error => {
if (!isSilent) {
uni.hideLoading()
}
console.error('加载状态定义失败:', error)
})
},
// 更新所有实时指标
updateCurrentMetrics() {
// ===== 酸轧线数据 =====
// 1. 速度监控ID=1,2,3
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'
}
]
// 2. 活套状态ID=8,9,10
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 || '%'
}
]
// 3. 酸槽浓度ID=11-16
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)
}
]
// 4. 其他工艺参数ID=7,17,18,19,20
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 || '%'
}
]
// ===== 镀锌线数据 =====
// 1. 轧辊速度ID=36-41
this.rollSpeedMetrics = [
{ label: '1#机架', value: this.formatValue(this.getDefineById(36)?.currentValue), unit: this.getDefineById(36)?.units || 'm/min' },
{ label: '2#机架', value: this.formatValue(this.getDefineById(37)?.currentValue), unit: this.getDefineById(37)?.units || 'm/min' },
{ label: '3#机架', value: this.formatValue(this.getDefineById(38)?.currentValue), unit: this.getDefineById(38)?.units || 'm/min' },
{ label: '4#机架', value: this.formatValue(this.getDefineById(39)?.currentValue), unit: this.getDefineById(39)?.units || 'm/min' },
{ label: '5#机架', value: this.formatValue(this.getDefineById(40)?.currentValue), unit: this.getDefineById(40)?.units || 'm/min' },
{ label: '6#机架', value: this.formatValue(this.getDefineById(41)?.currentValue), unit: this.getDefineById(41)?.units || 'm/min' }
]
// 2. 机架压下率ID=24-29
this.reducMetrics = [
{ label: '1#机架', value: this.formatValue(this.getDefineById(24)?.currentValue), unit: this.getDefineById(24)?.units || '%' },
{ label: '2#机架', value: this.formatValue(this.getDefineById(25)?.currentValue), unit: this.getDefineById(25)?.units || '%' },
{ label: '3#机架', value: this.formatValue(this.getDefineById(26)?.currentValue), unit: this.getDefineById(26)?.units || '%' },
{ label: '4#机架', value: this.formatValue(this.getDefineById(27)?.currentValue), unit: this.getDefineById(27)?.units || '%' },
{ label: '5#机架', value: this.formatValue(this.getDefineById(28)?.currentValue), unit: this.getDefineById(28)?.units || '%' },
{ label: '6#机架', value: this.formatValue(this.getDefineById(29)?.currentValue), unit: this.getDefineById(29)?.units || '%' }
]
// 3. 带钢张力ID=42-48
this.tensionMetrics = [
{ label: '0#张力', value: this.formatValue(this.getDefineById(42)?.currentValue), unit: this.getDefineById(42)?.units || 'kN' },
{ label: '1#张力', value: this.formatValue(this.getDefineById(43)?.currentValue), unit: this.getDefineById(43)?.units || 'kN' },
{ label: '2#张力', value: this.formatValue(this.getDefineById(44)?.currentValue), unit: this.getDefineById(44)?.units || 'kN' },
{ label: '3#张力', value: this.formatValue(this.getDefineById(45)?.currentValue), unit: this.getDefineById(45)?.units || 'kN' },
{ label: '4#张力', value: this.formatValue(this.getDefineById(46)?.currentValue), unit: this.getDefineById(46)?.units || 'kN' },
{ label: '5#张力', value: this.formatValue(this.getDefineById(47)?.currentValue), unit: this.getDefineById(47)?.units || 'kN' },
{ label: '6#张力', value: this.formatValue(this.getDefineById(48)?.currentValue), unit: this.getDefineById(48)?.units || 'kN' }
]
// 4. 功率百分比ID=49-54
this.powerMetrics = [
{ label: '1#机架', value: this.formatValue(this.getDefineById(49)?.currentValue), unit: this.getDefineById(49)?.units || '%' },
{ label: '2#机架', value: this.formatValue(this.getDefineById(50)?.currentValue), unit: this.getDefineById(50)?.units || '%' },
{ label: '3#机架', value: this.formatValue(this.getDefineById(51)?.currentValue), unit: this.getDefineById(51)?.units || '%' },
{ label: '4#机架', value: this.formatValue(this.getDefineById(52)?.currentValue), unit: this.getDefineById(52)?.units || '%' },
{ label: '5#机架', value: this.formatValue(this.getDefineById(53)?.currentValue), unit: this.getDefineById(53)?.units || '%' },
{ label: '6#机架', value: this.formatValue(this.getDefineById(54)?.currentValue), unit: this.getDefineById(54)?.units || '%' }
]
// ===== 涂装线数据 =====
// 1. 涂装速度ID=1-3与酸轧线相同
this.paintSpeedMetrics = [
{ label: '出口带钢速度', value: this.formatValue(this.getDefineById(1)?.currentValue), unit: this.getDefineById(1)?.units || 'm/min' },
{ label: '涂装带钢速度', value: this.formatValue(this.getDefineById(2)?.currentValue), unit: this.getDefineById(2)?.units || 'm/min' },
{ label: '圆盘剪速度', value: this.formatValue(this.getDefineById(3)?.currentValue), unit: this.getDefineById(3)?.units || 'm/min' }
]
// 2. 拉矫参数ID=20-23
this.tlvMetrics = [
{ label: '拉矫延伸率', value: this.formatValue(this.getDefineById(20)?.currentValue), unit: this.getDefineById(20)?.units || '%' },
{ label: '破磷机插入量1', value: this.formatValue(this.getDefineById(21)?.currentValue), unit: this.getDefineById(21)?.units || 'mm' },
{ label: '破磷机插入量2', value: this.formatValue(this.getDefineById(22)?.currentValue), unit: this.getDefineById(22)?.units || 'mm' },
{ label: '破磷机插入量3', value: this.formatValue(this.getDefineById(23)?.currentValue), unit: this.getDefineById(23)?.units || 'mm' }
]
},
// 加载历史趋势图数据(温度、出口速度、轧制力)
loadTempTrend(isSilent = false) {
return listPlantStateHistory({ pageNum: 1, pageSize: 30 }).then(response => {
if (!isSilent) {
uni.hideLoading()
}
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 tank1Temp = this.getDefineById(4)
const tank2Temp = this.getDefineById(5)
const tank3Temp = this.getDefineById(6)
const exitSpeed = this.getDefineById(1)
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)
})
// 温度趋势
this.tempChartData = {
categories: categories.reverse(),
series: [
{ name: tank1Temp?.comments || '1#酸槽温度', data: tank1Data.reverse() },
{ name: tank2Temp?.comments || '2#酸槽温度', data: tank2Data.reverse() },
{ name: tank3Temp?.comments || '3#酸槽温度', data: tank3Data.reverse() }
]
}
// 出口速度趋势
this.exitSpeedChartData = {
categories: categories,
series: [
{ name: exitSpeed?.comments || '出口带钢速度', data: exitSpeedData.reverse() }
]
}
// 轧制力趋势
this.forceChartData = {
categories: categories,
series: [
{ 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() }
]
}
// 涂装线温度趋势ID=4-7, 17
const paintTemp1Data = []
const paintTemp2Data = []
const paintTemp3Data = []
const paintTemp4Data = []
const paintTemp5Data = []
response.rows.forEach(item => {
paintTemp1Data.push(Number(item.value4) || 0) // ID=4
paintTemp2Data.push(Number(item.value5) || 0) // ID=5
paintTemp3Data.push(Number(item.value6) || 0) // ID=6
paintTemp4Data.push(Number(item.value7) || 0) // ID=7
paintTemp5Data.push(Number(item.value17) || 0) // ID=17
})
this.paintTempChartData = {
categories: categories,
series: [
{ name: '1#酸槽温度', data: paintTemp1Data.reverse() },
{ name: '2#酸槽温度', data: paintTemp2Data.reverse() },
{ name: '3#酸槽温度', data: paintTemp3Data.reverse() },
{ name: '漂洗温度', data: paintTemp4Data.reverse() },
{ name: '烘干温度', data: paintTemp5Data.reverse() }
]
}
}
}).catch(error => {
if (!isSilent) {
uni.hideLoading()
}
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}`
},
// 格式化数值保留2位小数
formatValue(value) {
if (value === null || value === undefined || value === '') return '—'
const num = Number(value)
if (isNaN(num)) return '—'
return num.toFixed(2)
},
// 滚动到指定部分
scrollToSection(sectionId) {
this.scrollIntoView = sectionId
this.navMenuExpanded = false // 点击后关闭菜单
}
}
};
</script>
<style scoped lang="scss">
/* 页面容器 */
.page-container {
min-height: 100vh;
background: #f5f7fa;
}
/* 标签栏 */
.tab-container {
display: flex;
background: #fff;
border-bottom: 2rpx solid #e4e7ed;
}
.tab-item {
flex: 1;
text-align: center;
padding: 28rpx 0;
position: relative;
.tab-label {
font-size: 28rpx;
color: #606266;
font-weight: 400;
}
&.tab-active {
.tab-label {
color: #0066cc;
font-weight: 500;
}
}
.tab-indicator {
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 60rpx;
height: 3rpx;
background: #0066cc;
}
}
/* 刷新按钮(固定在右下角) */
.refresh-btn-fixed {
position: fixed;
right: 32rpx;
bottom: 120rpx;
width: 96rpx;
height: 96rpx;
background: #0066cc;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 8rpx 20rpx rgba(0, 102, 204, 0.4);
z-index: 999;
&:active {
opacity: 0.8;
transform: scale(0.95);
}
}
/* 快速导航菜单(固定在左下角) */
.nav-menu-fixed {
position: fixed;
left: 32rpx;
bottom: 120rpx;
z-index: 998;
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 12rpx;
}
.nav-toggle {
width: 96rpx;
height: 96rpx;
background: #409eff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 8rpx 20rpx rgba(64, 158, 255, 0.4);
transition: all 0.3s ease;
&:active {
opacity: 0.8;
transform: scale(0.95);
}
}
.nav-toggle-icon {
font-size: 48rpx;
color: #fff;
display: block;
line-height: 1;
}
.nav-items {
display: flex;
flex-direction: column;
gap: 8rpx;
animation: slideUp 0.3s ease;
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(20rpx);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.nav-item {
background: #fff;
border: 2rpx solid #409eff;
border-radius: 8rpx;
padding: 16rpx 24rpx;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4rpx 12rpx rgba(64, 158, 255, 0.2);
transition: all 0.2s ease;
&:active {
background: #f0f9ff;
transform: scale(0.95);
}
}
.nav-label {
font-size: 26rpx;
color: #409eff;
font-weight: 500;
white-space: nowrap;
}
.refresh-icon {
font-size: 48rpx;
color: #fff;
display: block;
line-height: 1;
&.rotating {
animation: rotate 1s linear infinite;
}
}
@keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
/* 滚动容器 */
.scroll-container {
height: calc(100vh - 96rpx);
padding: 24rpx;
}
/* 顶部状态栏 */
.status-bar {
display: flex;
align-items: center;
background: #fff;
padding: 24rpx 32rpx;
margin-bottom: 24rpx;
border-radius: 8rpx;
border: 1rpx solid #e4e7ed;
}
.status-item {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
gap: 16rpx;
}
.status-label {
font-size: 26rpx;
color: #909399;
}
.status-value {
font-size: 28rpx;
font-weight: 500;
color: #303133;
&.status-通畅 {
color: #67c23a;
}
&.status-卡顿 {
color: #e6a23c;
}
&.status-异常 {
color: #f56c6c;
}
&.status-time {
color: #909399;
font-size: 24rpx;
}
}
.status-divider {
width: 1rpx;
height: 40rpx;
background: #e4e7ed;
}
/* 区块样式 */
.section {
margin-bottom: 24rpx;
}
.section-title {
font-size: 30rpx;
font-weight: 500;
color: #303133;
margin-bottom: 20rpx;
padding-left: 16rpx;
border-left: 4rpx solid #0066cc;
}
/* 分隔符 */
.section-divider {
display: flex;
align-items: center;
margin: 40rpx 0 24rpx 0;
padding: 0 16rpx;
}
.divider-text {
font-size: 28rpx;
font-weight: 600;
color: #0066cc;
padding: 0 12rpx;
background: #f5f7fa;
border-left: 4rpx solid #0066cc;
padding-left: 16rpx;
}
/* 指标卡片 - 3列布局 */
.metrics-grid-3 {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20rpx;
}
/* 指标卡片 - 2列布局 */
.metrics-grid-2 {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20rpx;
}
.metric-box {
background: #fff;
border: 1rpx solid #e4e7ed;
border-radius: 8rpx;
padding: 28rpx 20rpx;
text-align: center;
}
.metric-name {
display: block;
font-size: 24rpx;
color: #909399;
margin-bottom: 16rpx;
}
.metric-value {
display: block;
font-size: 48rpx;
font-weight: 600;
color: #0066cc;
margin-bottom: 8rpx;
line-height: 1;
}
.metric-unit {
display: block;
font-size: 22rpx;
color: #909399;
}
/* 图表容器 */
.chart-box {
background: #fff;
border: 1rpx solid #e4e7ed;
border-radius: 8rpx;
padding: 24rpx 16rpx;
}
/* 酸槽监控网格 */
.tank-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20rpx;
}
.tank-card {
background: #fff;
border: 2rpx solid #0066cc;
border-radius: 8rpx;
overflow: hidden;
}
.tank-header {
background: #0066cc;
color: #fff;
font-size: 28rpx;
font-weight: 500;
padding: 20rpx;
text-align: center;
}
.tank-data {
padding: 24rpx 16rpx;
}
.tank-row {
display: flex;
flex-direction: column;
align-items: center;
padding: 12rpx 0;
}
.data-label {
font-size: 22rpx;
color: #909399;
margin-bottom: 8rpx;
}
.data-value {
font-size: 36rpx;
font-weight: 600;
color: #303133;
}
.data-unit {
font-size: 20rpx;
font-weight: 400;
color: #909399;
margin-left: 4rpx;
}
.tank-divider {
height: 1rpx;
background: #e4e7ed;
margin: 12rpx 0;
}
</style>