修改镀锌线ui
This commit is contained in:
@@ -171,19 +171,36 @@ export default {
|
|||||||
color: ["#0066cc", "#409eff", "#66b1ff"],
|
color: ["#0066cc", "#409eff", "#66b1ff"],
|
||||||
padding: [15, 15, 0, 15],
|
padding: [15, 15, 0, 15],
|
||||||
enableScroll: false,
|
enableScroll: false,
|
||||||
legend: {},
|
legend: {
|
||||||
|
show: true,
|
||||||
|
position: "top",
|
||||||
|
fontSize: 10,
|
||||||
|
lineHeight: 14,
|
||||||
|
itemGap: 6
|
||||||
|
},
|
||||||
|
dataLabel: false, // 隐藏数据标签
|
||||||
|
dataPointShape: false, // 隐藏数据点
|
||||||
xAxis: {
|
xAxis: {
|
||||||
disableGrid: true,
|
disableGrid: true,
|
||||||
rotateLabel: true, // 启用标签旋转
|
rotateLabel: true,
|
||||||
itemCount: 6, // 只显示6个标签,避免密集
|
itemCount: 5, // 减少标签数量
|
||||||
labelCount: 6 // 标签数量
|
labelCount: 5,
|
||||||
|
fontSize: 10
|
||||||
},
|
},
|
||||||
yAxis: {
|
yAxis: {
|
||||||
gridType: "dash",
|
gridType: "dash",
|
||||||
dashLength: 4,
|
dashLength: 4,
|
||||||
gridColor: "#e4e7ed",
|
gridColor: "#e4e7ed",
|
||||||
showTitle: true,
|
showTitle: true,
|
||||||
|
fontSize: 10,
|
||||||
data: [{ min: 0, title: "温度(°C)" }]
|
data: [{ min: 0, title: "温度(°C)" }]
|
||||||
|
},
|
||||||
|
extra: {
|
||||||
|
line: {
|
||||||
|
type: "curve",
|
||||||
|
width: 2,
|
||||||
|
activeType: "hollow"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
plantStateDefines: [] // 缓存所有的状态定义
|
plantStateDefines: [] // 缓存所有的状态定义
|
||||||
|
|||||||
@@ -1,267 +1,632 @@
|
|||||||
<template>
|
<template>
|
||||||
<view>
|
<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>
|
||||||
|
|
||||||
|
<!-- 刷新按钮 -->
|
||||||
|
<view class="refresh-btn-fixed" @click="refreshData">
|
||||||
|
<text class="refresh-icon" :class="{ 'rotating': isRefreshing }">⟳</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<scroll-view scroll-y class="scroll-container" v-if="currentTab === 1">
|
||||||
|
<!-- 顶部状态栏 -->
|
||||||
|
<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>
|
||||||
|
|
||||||
<scroll-view scroll-y v-if="currentTab == 2">
|
<!-- 涂装速度监控 -->
|
||||||
|
<view class="section">
|
||||||
|
<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">
|
||||||
|
<view class="section-title">烘干温度趋势</view>
|
||||||
|
<view class="chart-box">
|
||||||
|
<qiun-data-charts type="line" :chartData="tempChartData" :opts="lineChartOpts" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 活套状态 -->
|
||||||
|
<view class="section">
|
||||||
|
<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">
|
||||||
|
<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">
|
||||||
|
<view class="section-title">拉矫参数</view>
|
||||||
|
<view class="metrics-grid-3">
|
||||||
|
<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>
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
|
<scroll-view scroll-y class="scroll-container" v-if="currentTab == 2">
|
||||||
<klp-product-statistic></klp-product-statistic>
|
<klp-product-statistic></klp-product-statistic>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
|
|
||||||
<scroll-view scroll-y v-if="currentTab == 3">
|
<scroll-view scroll-y class="scroll-container" v-if="currentTab == 3">
|
||||||
<klp-shutdown-statistic></klp-shutdown-statistic>
|
<klp-shutdown-statistic></klp-shutdown-statistic>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
|
|
||||||
<scroll-view scroll-y v-if="currentTab == 4">
|
<scroll-view scroll-y class="scroll-container" v-if="currentTab == 4">
|
||||||
<klp-team-performance></klp-team-performance>
|
<klp-team-performance></klp-team-performance>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { getAllPlantStateDefines, listPlantStateHistory } from '@/api/pocket/plantState'
|
import { getAllPlantStateDefines, listPlantStateHistory, getCurrentShift } from '@/api/pocket/plantState'
|
||||||
import config from '@/config'
|
import config from '@/config'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
// 响应式数据(替代 Vue 3 的 ref)
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
currentTab: 1, // 当前选中的标签页
|
currentTab: 1,
|
||||||
tabData: [
|
tabData: [
|
||||||
{ text: "实时监控", value: 1 },
|
{ text: "实时监控", value: 1 },
|
||||||
{ text: "生产统计", value: 2 },
|
{ text: "生产统计", value: 2 },
|
||||||
{ text: "停机统计", value: 3 },
|
{ text: "停机统计", value: 3 },
|
||||||
{ text: "班组绩效", value: 4 }
|
{ text: "班组绩效", value: 4 }
|
||||||
],
|
],
|
||||||
status: [ // 状态指标数据(供 k-metric-card 使用)
|
webStatus: [
|
||||||
{ label: '网络状态', value: '检测中...' },
|
{ label: '网络状态', value: '检测中...' },
|
||||||
{ label: '当前班组', value: '—' }
|
{ label: '当前班组', value: '—' }
|
||||||
],
|
],
|
||||||
plantStateDefines: [] // 缓存所有的状态定义
|
lastUpdateTime: '—',
|
||||||
}
|
isRefreshing: false,
|
||||||
},
|
refreshTimer: null,
|
||||||
// 生命周期钩子(替代 Vue 3 的 onMounted)
|
// 涂装速度(ID=1-3)
|
||||||
mounted() {
|
speedMetrics: [
|
||||||
this.checkNetworkStatus() // 检测网络状态
|
{ label: '出口带钢速度', value: '—', unit: 'm/min' },
|
||||||
this.initPlantStateDefines() // 先加载所有定义
|
{ label: '涂装带钢速度', value: '—', unit: 'm/min' },
|
||||||
},
|
{ label: '圆盘剪速度', value: '—', unit: 'm/min' }
|
||||||
// 方法定义(所有函数需放在 methods 中)
|
],
|
||||||
methods: {
|
// 活套状态(ID=8-10)
|
||||||
// 检测网络状态
|
looperMetrics: [
|
||||||
checkNetworkStatus() {
|
{ label: '入口活套', value: '—', unit: '%' },
|
||||||
const startTime = Date.now()
|
{ label: '出口活套', value: '—', unit: '%' },
|
||||||
|
{ label: '联机活套', value: '—', unit: '%' }
|
||||||
// 使用uni.request测试网络连接速度
|
],
|
||||||
uni.request({
|
// 工艺参数(ID=7, 17-19)
|
||||||
url: config.baseUrl + '/pocket/proPlantStateDefine/allWithValues',
|
processMetrics: [
|
||||||
method: 'GET',
|
{ label: '漂洗温度', value: '—', unit: '°C' },
|
||||||
timeout: 5000,
|
{ label: '烘干温度', value: '—', unit: '°C' },
|
||||||
success: (res) => {
|
{ label: '漂洗电导率', value: '—', unit: 'g/L' },
|
||||||
const responseTime = Date.now() - startTime
|
{ label: '联机活套张力', value: '—', unit: 'kN' }
|
||||||
|
],
|
||||||
// 根据响应时间判断网络状态
|
// 拉矫参数(ID=20-23)
|
||||||
if (responseTime < 500) {
|
tlvMetrics: [
|
||||||
this.status[0].value = '通畅'
|
{ label: '拉矫延伸率', value: '—', unit: '%' },
|
||||||
} else if (responseTime < 2000) {
|
{ label: '破磷机插入量1', value: '—', unit: 'mm' },
|
||||||
this.status[0].value = '卡顿'
|
{ label: '破磷机插入量2', value: '—', unit: 'mm' },
|
||||||
} else {
|
{ label: '破磷机插入量3', value: '—', unit: 'mm' }
|
||||||
this.status[0].value = '异常'
|
],
|
||||||
}
|
// 温度趋势图(ID=4-7, 17)
|
||||||
|
tempChartData: {},
|
||||||
|
lineChartOpts: {
|
||||||
|
color: ["#0066cc", "#409eff", "#66b1ff", "#a0cfff", "#d9ecff"],
|
||||||
|
padding: [15, 15, 0, 15],
|
||||||
|
enableScroll: false,
|
||||||
|
legend: {
|
||||||
|
show: true,
|
||||||
|
position: "top",
|
||||||
|
fontSize: 10,
|
||||||
|
lineHeight: 14,
|
||||||
|
itemGap: 6
|
||||||
},
|
},
|
||||||
fail: () => {
|
dataLabel: false, // 隐藏数据标签
|
||||||
this.status[0].value = '异常'
|
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: {
|
||||||
|
startAutoRefresh() {
|
||||||
|
this.refreshTimer = setInterval(() => {
|
||||||
|
this.refreshData(true)
|
||||||
|
}, 30000)
|
||||||
|
},
|
||||||
|
|
||||||
|
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() {
|
||||||
initPlantStateDefines() {
|
const now = new Date()
|
||||||
uni.showLoading({ title: '加载中' })
|
const hour = String(now.getHours()).padStart(2, '0')
|
||||||
|
const minute = String(now.getMinutes()).padStart(2, '0')
|
||||||
getAllPlantStateDefines().then(response => {
|
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) {
|
if (response.code === 200 && response.data) {
|
||||||
// 缓存所有定义
|
const shiftData = response.data
|
||||||
this.plantStateDefines = response.data
|
const shiftName = this.getShiftName(shiftData.shift)
|
||||||
console.log('状态定义已加载:', this.plantStateDefines)
|
const crewName = this.getCrewName(shiftData.crew)
|
||||||
|
this.webStatus[1].value = `${crewName} / ${shiftName}`
|
||||||
uni.hideLoading()
|
|
||||||
|
|
||||||
// 这里可以根据 plantStateDefines 来处理首页数据
|
|
||||||
// 例如:this.initHomePageData()
|
|
||||||
} else {
|
|
||||||
uni.hideLoading()
|
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
uni.hideLoading()
|
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)
|
console.error('加载状态定义失败:', error)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
updateCurrentMetrics() {
|
||||||
// 根据define ID获取对应的值(工具方法)
|
// 1. 速度监控(ID=1-3)
|
||||||
getValueByDefineId(dataRow, defineId) {
|
const exitSpeed = this.getDefineById(1)
|
||||||
const fieldName = `value${defineId}`
|
const plSpeed = this.getDefineById(2)
|
||||||
return dataRow[fieldName] || null
|
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-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=7, 17-19)
|
||||||
|
const rinseTemp = this.getDefineById(7)
|
||||||
|
const windTemp = this.getDefineById(17)
|
||||||
|
const rinseFlow = this.getDefineById(18)
|
||||||
|
const telTension = this.getDefineById(19)
|
||||||
|
|
||||||
|
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' }
|
||||||
|
]
|
||||||
|
|
||||||
|
// 4. 拉矫参数(ID=20-23)
|
||||||
|
const tlvElong = this.getDefineById(20)
|
||||||
|
const tlvMesh1 = this.getDefineById(21)
|
||||||
|
const tlvMesh2 = this.getDefineById(22)
|
||||||
|
const tlvMesh3 = this.getDefineById(23)
|
||||||
|
|
||||||
|
this.tlvMetrics = [
|
||||||
|
{ label: tlvElong?.comments || '拉矫延伸率', value: this.formatValue(tlvElong?.currentValue), unit: tlvElong?.units || '%' },
|
||||||
|
{ label: tlvMesh1?.comments || '破磷机插入量1', value: this.formatValue(tlvMesh1?.currentValue), unit: tlvMesh1?.units || 'mm' },
|
||||||
|
{ label: tlvMesh2?.comments || '破磷机插入量2', value: this.formatValue(tlvMesh2?.currentValue), unit: tlvMesh2?.units || 'mm' },
|
||||||
|
{ label: tlvMesh3?.comments || '破磷机插入量3', value: this.formatValue(tlvMesh3?.currentValue), unit: tlvMesh3?.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 temp1Data = []
|
||||||
|
const temp2Data = []
|
||||||
|
const temp3Data = []
|
||||||
|
const temp4Data = []
|
||||||
|
const temp5Data = []
|
||||||
|
|
||||||
|
response.rows.forEach(item => {
|
||||||
|
const dateStr = this.formatDate(item.insdate)
|
||||||
|
categories.push(dateStr)
|
||||||
|
temp1Data.push(Number(item.value4) || 0) // 1#酸槽温度
|
||||||
|
temp2Data.push(Number(item.value5) || 0) // 2#酸槽温度
|
||||||
|
temp3Data.push(Number(item.value6) || 0) // 3#酸槽温度
|
||||||
|
temp4Data.push(Number(item.value7) || 0) // 漂洗温度
|
||||||
|
temp5Data.push(Number(item.value17) || 0) // 烘干温度
|
||||||
|
})
|
||||||
|
|
||||||
|
this.tempChartData = {
|
||||||
|
categories: categories.reverse(),
|
||||||
|
series: [
|
||||||
|
{ name: '1#酸槽温度', data: temp1Data.reverse() },
|
||||||
|
{ name: '2#酸槽温度', data: temp2Data.reverse() },
|
||||||
|
{ name: '3#酸槽温度', data: temp3Data.reverse() },
|
||||||
|
{ name: '漂洗温度', data: temp4Data.reverse() },
|
||||||
|
{ name: '烘干温度', data: temp5Data.reverse() }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).catch(error => {
|
||||||
|
if (!isSilent) uni.hideLoading()
|
||||||
|
console.error('加载温度趋势失败:', error)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
getDefineById(id) {
|
||||||
|
return this.plantStateDefines.find(item => item.id == id)
|
||||||
|
},
|
||||||
|
|
||||||
formatDate(dateStr) {
|
formatDate(dateStr) {
|
||||||
if (!dateStr) return ''
|
if (!dateStr) return ''
|
||||||
const date = new Date(dateStr)
|
const date = new Date(dateStr)
|
||||||
return `${date.getMonth() + 1}/${date.getDate()}`
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
page {
|
/* 页面容器 */
|
||||||
background-color: #b2b2b2;
|
.page-container {
|
||||||
height: 100vh;
|
min-height: 100vh;
|
||||||
overflow: auto;
|
background: #f5f7fa;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 简洁标签栏 */
|
/* 标签栏 */
|
||||||
.tab-container {
|
.tab-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
|
||||||
background: #fff;
|
background: #fff;
|
||||||
padding: 0 20rpx;
|
border-bottom: 2rpx solid #e4e7ed;
|
||||||
margin-bottom: 20rpx;
|
|
||||||
border-bottom: 1rpx solid #e8e8e8;
|
|
||||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-item {
|
.tab-item {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 30rpx 0;
|
padding: 28rpx 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
|
|
||||||
.tab-label {
|
.tab-label {
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
color: #666;
|
color: #606266;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.tab-active {
|
&.tab-active {
|
||||||
.tab-label {
|
.tab-label {
|
||||||
color: #1a73e8;
|
color: #0066cc;
|
||||||
font-weight: 600;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-indicator {
|
.tab-indicator {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
width: 50rpx;
|
width: 60rpx;
|
||||||
height: 4rpx;
|
height: 3rpx;
|
||||||
background: #1a73e8;
|
background: #0066cc;
|
||||||
border-radius: 2rpx;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 内容卡片 */
|
/* 刷新按钮 */
|
||||||
.content-card {
|
.refresh-btn-fixed {
|
||||||
background: #fff;
|
position: fixed;
|
||||||
margin-bottom: 20rpx;
|
right: 32rpx;
|
||||||
}
|
bottom: 120rpx;
|
||||||
|
width: 96rpx;
|
||||||
/* 空状态占位 */
|
height: 96rpx;
|
||||||
.empty-placeholder {
|
background: #0066cc;
|
||||||
padding: 100rpx 40rpx;
|
border-radius: 50%;
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
.empty-text {
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 指标容器 */
|
|
||||||
.metric-container {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-around;
|
align-items: center;
|
||||||
background: #fff;
|
justify-content: center;
|
||||||
padding: 0;
|
box-shadow: 0 8rpx 20rpx rgba(0, 102, 204, 0.4);
|
||||||
|
z-index: 999;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
opacity: 0.8;
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 指标项 */
|
.refresh-icon {
|
||||||
.metric-item {
|
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;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 指标卡片 - 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;
|
text-align: center;
|
||||||
padding: 32rpx;
|
}
|
||||||
border-radius: 12rpx;
|
|
||||||
transition: all 0.2s;
|
.metric-name {
|
||||||
|
display: block;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #909399;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.metric-value {
|
.metric-value {
|
||||||
|
display: block;
|
||||||
font-size: 48rpx;
|
font-size: 48rpx;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin-bottom: 16rpx;
|
color: #0066cc;
|
||||||
line-height: 1.2;
|
margin-bottom: 8rpx;
|
||||||
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.metric-label {
|
.metric-unit {
|
||||||
font-size: 28rpx;
|
display: block;
|
||||||
color: #666;
|
font-size: 22rpx;
|
||||||
letter-spacing: 1rpx;
|
color: #909399;
|
||||||
|
|
||||||
.metric-unit {
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #999;
|
|
||||||
margin-left: 4rpx;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 信息容器 */
|
/* 图表容器 */
|
||||||
.info-container {
|
.chart-box {
|
||||||
padding: 20rpx;
|
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 12rpx;
|
border: 1rpx solid #e4e7ed;
|
||||||
}
|
border-radius: 8rpx;
|
||||||
|
padding: 24rpx 16rpx;
|
||||||
.info-row {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin-bottom: 24rpx;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 信息项 */
|
|
||||||
.info-item {
|
|
||||||
flex: 0 0 48%;
|
|
||||||
display: flex;
|
|
||||||
align-items: baseline;
|
|
||||||
padding: 16rpx 20rpx;
|
|
||||||
background: #f8f9fa;
|
|
||||||
border-radius: 10rpx;
|
|
||||||
border: 1rpx solid #e8e8e8;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
background: #f0f2f5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-label {
|
|
||||||
color: #666;
|
|
||||||
font-size: 26rpx;
|
|
||||||
flex-shrink: 0;
|
|
||||||
margin-right: 16rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-value {
|
|
||||||
color: #333;
|
|
||||||
font-size: 28rpx;
|
|
||||||
font-weight: 500;
|
|
||||||
word-break: break-all;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<view>
|
<view class="page-container">
|
||||||
<!-- 简洁标签栏 -->
|
<!-- 简洁标签栏 -->
|
||||||
<view class="tab-container">
|
<view class="tab-container">
|
||||||
<view
|
<view
|
||||||
@@ -14,295 +14,463 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<scroll-view scroll-y v-if="currentTab === 1">
|
<!-- 刷新按钮 -->
|
||||||
<view class="content-card">
|
<view class="refresh-btn-fixed" @click="refreshData">
|
||||||
<view class="metric-container">
|
<text class="refresh-icon" :class="{ 'rotating': isRefreshing }">⟳</text>
|
||||||
<!-- 网络状态指标 -->
|
|
||||||
<view class="metric-item">
|
|
||||||
<view class="metric-value">
|
|
||||||
正常
|
|
||||||
</view>
|
|
||||||
<view class="metric-label">
|
|
||||||
网络状态
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 班组指标 -->
|
<scroll-view scroll-y class="scroll-container" v-if="currentTab === 1">
|
||||||
<view class="metric-item">
|
<!-- 顶部状态栏 -->
|
||||||
<view class="metric-value team-number">
|
<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>
|
||||||
<view class="metric-label">
|
<view class="status-divider"></view>
|
||||||
当前班组
|
<view class="status-item">
|
||||||
|
<text class="status-label">当前班组</text>
|
||||||
|
<text class="status-value">{{ webStatus[1].value }}</text>
|
||||||
</view>
|
</view>
|
||||||
</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>
|
</view>
|
||||||
|
|
||||||
<view class="content-card">
|
<!-- 轧机速度监控 -->
|
||||||
<klp-collapse-panel title="状态统计">
|
<view class="section">
|
||||||
<qiun-data-charts type="line" :chartData="chartData" />
|
<view class="section-title">轧机速度监控</view>
|
||||||
</klp-collapse-panel>
|
<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 class="content-card">
|
|
||||||
<klp-collapse-panel title="轧机状态">
|
|
||||||
<qiun-data-charts type="column" :chartData="chartData" />
|
|
||||||
</klp-collapse-panel>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="content-card">
|
|
||||||
<klp-collapse-panel title="机组跟踪">
|
|
||||||
<view style="padding: 30rpx; display: flex; flex-direction: column; gap: 20rpx;">
|
|
||||||
<view class="device-card">
|
|
||||||
<view class="device-header">
|
|
||||||
<text class="device-name">轧机</text>
|
|
||||||
<text class="device-value">6390000</text>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="device-card">
|
<!-- 机架压下率 -->
|
||||||
<view class="device-header">
|
<view class="section">
|
||||||
<text class="device-name">圆剪盘</text>
|
<view class="section-title">机架压下率</view>
|
||||||
<text class="device-value">6390000</text>
|
<view class="metrics-grid-3">
|
||||||
</view>
|
<view class="metric-box" v-for="(item, index) in reducMetrics" :key="index">
|
||||||
<view class="info-container">
|
<text class="metric-name">{{ item.label }}</text>
|
||||||
<view class="info-row">
|
<text class="metric-value">{{ item.value }}</text>
|
||||||
<view class="info-item">
|
<text class="metric-unit">{{ item.unit }}</text>
|
||||||
<text class="info-label">设备编号:</text>
|
|
||||||
<text class="info-value">M-001</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-item">
|
|
||||||
<text class="info-label">运行状态:</text>
|
|
||||||
<text class="info-value">正常</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="info-row">
|
|
||||||
<view class="info-item">
|
|
||||||
<text class="info-label">当前产量:</text>
|
|
||||||
<text class="info-value">2580 件</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-item">
|
|
||||||
<text class="info-label">合格率:</text>
|
|
||||||
<text class="info-value">98.5%</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="device-card">
|
<!-- 轧制力趋势 -->
|
||||||
<view class="device-header">
|
<view class="section">
|
||||||
<text class="device-name">酸洗</text>
|
<view class="section-title">轧制力趋势</view>
|
||||||
<text class="device-value">6390000</text>
|
<view class="chart-box">
|
||||||
|
<qiun-data-charts type="line" :chartData="forceChartData" :opts="lineChartOpts" />
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="device-card">
|
<!-- 带钢张力 -->
|
||||||
<view class="device-header">
|
<view class="section">
|
||||||
<text class="device-name">入口活套</text>
|
<view class="section-title">带钢张力监控</view>
|
||||||
<text class="device-value">6390000</text>
|
<view class="metrics-grid-3">
|
||||||
</view>
|
<view class="metric-box" v-for="(item, index) in tensionMetrics" :key="index">
|
||||||
<view class="info-container">
|
<text class="metric-name">{{ item.label }}</text>
|
||||||
<view class="info-row">
|
<text class="metric-value">{{ item.value }}</text>
|
||||||
<view class="info-item">
|
<text class="metric-unit">{{ item.unit }}</text>
|
||||||
<text class="info-label">设备编号:</text>
|
|
||||||
<text class="info-value">M-001</text>
|
|
||||||
</view>
|
</view>
|
||||||
<view class="info-item">
|
|
||||||
<text class="info-label">运行状态:</text>
|
|
||||||
<text class="info-value">正常</text>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="info-row">
|
<!-- 功率百分比 -->
|
||||||
<view class="info-item">
|
<view class="section">
|
||||||
<text class="info-label">当前产量:</text>
|
<view class="section-title">机架功率百分比</view>
|
||||||
<text class="info-value">2580 件</text>
|
<view class="metrics-grid-3">
|
||||||
</view>
|
<view class="metric-box" v-for="(item, index) in powerMetrics" :key="index">
|
||||||
<view class="info-item">
|
<text class="metric-name">{{ item.label }}</text>
|
||||||
<text class="info-label">合格率:</text>
|
<text class="metric-value">{{ item.value }}</text>
|
||||||
<text class="info-value">98.5%</text>
|
<text class="metric-unit">{{ item.unit }}</text>
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
|
||||||
</klp-collapse-panel>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="content-card">
|
|
||||||
<klp-collapse-panel title="能耗">
|
|
||||||
<view class="metric-container">
|
|
||||||
<!-- 工艺线速度指标 -->
|
|
||||||
<view class="metric-item">
|
|
||||||
<view class="metric-value">
|
|
||||||
9.9
|
|
||||||
</view>
|
|
||||||
<view class="metric-label">
|
|
||||||
工艺缎带钢线速度
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 出口线速度指标 -->
|
|
||||||
<view class="metric-item">
|
|
||||||
<view class="metric-value team-number">
|
|
||||||
126.0
|
|
||||||
</view>
|
|
||||||
<view class="metric-label">
|
|
||||||
轧机出口带钢线速度
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</klp-collapse-panel>
|
|
||||||
</view>
|
</view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
|
|
||||||
<scroll-view scroll-y v-if="currentTab == 2">
|
<scroll-view scroll-y class="scroll-container" v-if="currentTab == 2">
|
||||||
<klp-product-statistic></klp-product-statistic>
|
<klp-product-statistic></klp-product-statistic>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
|
|
||||||
<scroll-view scroll-y v-if="currentTab == 3">
|
<scroll-view scroll-y class="scroll-container" v-if="currentTab == 3">
|
||||||
<klp-shutdown-statistic></klp-shutdown-statistic>
|
<klp-shutdown-statistic></klp-shutdown-statistic>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
|
|
||||||
<scroll-view scroll-y v-if="currentTab == 4">
|
<scroll-view scroll-y class="scroll-container" v-if="currentTab == 4">
|
||||||
<klp-team-performance></klp-team-performance>
|
<klp-team-performance></klp-team-performance>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { listPlantStateCurrent, listPlantStateHistory } from '@/api/pocket/plantState'
|
import { getAllPlantStateDefines, listPlantStateHistory, getCurrentShift } from '@/api/pocket/plantState'
|
||||||
|
import config from '@/config'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
// 3. 响应式数据(替代 Vue 3 的 ref)
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
currentTab: 1, // 当前激活的标签页(默认实时监控)
|
currentTab: 1,
|
||||||
tabData: [ // 标签页配置
|
tabData: [
|
||||||
{ text: "实时监控", value: 1 },
|
{ text: "实时监控", value: 1 },
|
||||||
{ text: "生产统计", value: 2 },
|
{ text: "生产统计", value: 2 },
|
||||||
{ text: "停机统计", value: 3 },
|
{ text: "停机统计", value: 3 },
|
||||||
{ text: "班组绩效", value: 4 }
|
{ text: "班组绩效", value: 4 }
|
||||||
],
|
],
|
||||||
chartData: {} // 图表数据(初始化空对象,后续加载)
|
webStatus: [
|
||||||
|
{ label: '网络状态', value: '检测中...' },
|
||||||
|
{ label: '当前班组', value: '—' }
|
||||||
|
],
|
||||||
|
lastUpdateTime: '—',
|
||||||
|
isRefreshing: false,
|
||||||
|
refreshTimer: null,
|
||||||
|
// 轧辊速度(ID=36-41)
|
||||||
|
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' }
|
||||||
|
],
|
||||||
|
// 机架压下率(ID=24-29)
|
||||||
|
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: '%' }
|
||||||
|
],
|
||||||
|
// 带钢张力(ID=42-48)
|
||||||
|
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' }
|
||||||
|
],
|
||||||
|
// 功率百分比(ID=49-54)
|
||||||
|
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: '%' }
|
||||||
|
],
|
||||||
|
// 轧制力趋势图(ID=30-35)
|
||||||
|
forceChartData: {},
|
||||||
|
lineChartOpts: {
|
||||||
|
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" // 点击时显示空心点
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plantStateDefines: []
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
// 4. 生命周期钩子(替代 Vue 3 的 onMounted)
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.getServerData(); // 页面挂载后加载图表数据
|
this.loadAllData()
|
||||||
this.loadCurrentState(); // 加载当前状态
|
this.startAutoRefresh()
|
||||||
},
|
},
|
||||||
// 5. 方法定义(所有数据处理与逻辑)
|
|
||||||
|
beforeDestroy() {
|
||||||
|
this.stopAutoRefresh()
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
// 加载当前设备状态
|
startAutoRefresh() {
|
||||||
loadCurrentState() {
|
this.refreshTimer = setInterval(() => {
|
||||||
listPlantStateCurrent({ pageNum: 1, pageSize: 10 }).then(response => {
|
this.refreshData(true)
|
||||||
if (response.code === 200 && response.rows) {
|
}, 30000)
|
||||||
console.log('当前状态数据:', response.rows)
|
},
|
||||||
// 可以根据实际需求更新页面数据
|
|
||||||
|
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 })
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
this.updateLastTime()
|
||||||
console.error('加载设备状态失败:', error)
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
// 从服务器获取图表数据
|
updateLastTime() {
|
||||||
getServerData() {
|
const now = new Date()
|
||||||
uni.showLoading({ title: '加载中' })
|
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: '加载中' })
|
||||||
|
|
||||||
listPlantStateHistory({ pageNum: 1, pageSize: 20 }).then(response => {
|
return getAllPlantStateDefines().then(response => {
|
||||||
uni.hideLoading()
|
if (response.code === 200 && response.data) {
|
||||||
|
this.plantStateDefines = response.data
|
||||||
|
if (!isSilent) console.log('镀锌线1状态定义已加载:', this.plantStateDefines)
|
||||||
|
this.updateCurrentMetrics()
|
||||||
|
return this.loadForceHistory(isSilent)
|
||||||
|
} else {
|
||||||
|
if (!isSilent) uni.hideLoading()
|
||||||
|
}
|
||||||
|
}).catch(error => {
|
||||||
|
if (!isSilent) uni.hideLoading()
|
||||||
|
console.error('加载状态定义失败:', error)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
updateCurrentMetrics() {
|
||||||
|
// 1. 轧辊速度(ID=36-41:rollSpeed1-6)
|
||||||
|
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:reduc1-6)
|
||||||
|
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:tensionForce0-6)
|
||||||
|
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:powerRatio1-6)
|
||||||
|
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 || '%' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
loadForceHistory(isSilent = false) {
|
||||||
|
return listPlantStateHistory({ pageNum: 1, pageSize: 30 }).then(response => {
|
||||||
|
if (!isSilent) uni.hideLoading()
|
||||||
|
|
||||||
if (response.code === 200 && response.rows && response.rows.length > 0) {
|
if (response.code === 200 && response.rows && response.rows.length > 0) {
|
||||||
const categories = []
|
const categories = []
|
||||||
const targetData = []
|
const force1Data = []
|
||||||
const completeData = []
|
const force2Data = []
|
||||||
|
const force3Data = []
|
||||||
|
const force4Data = []
|
||||||
|
const force5Data = []
|
||||||
|
const force6Data = []
|
||||||
|
|
||||||
response.rows.forEach(item => {
|
response.rows.forEach(item => {
|
||||||
const dateStr = this.formatDate(item.insdate)
|
const dateStr = this.formatDate(item.insdate)
|
||||||
categories.push(dateStr)
|
categories.push(dateStr)
|
||||||
targetData.push(item.value1 || 0)
|
force1Data.push(Number(item.value30) || 0) // ID=30
|
||||||
completeData.push(item.value2 || 0)
|
force2Data.push(Number(item.value31) || 0) // ID=31
|
||||||
|
force3Data.push(Number(item.value32) || 0) // ID=32
|
||||||
|
force4Data.push(Number(item.value33) || 0) // ID=33
|
||||||
|
force5Data.push(Number(item.value34) || 0) // ID=34
|
||||||
|
force6Data.push(Number(item.value35) || 0) // ID=35
|
||||||
})
|
})
|
||||||
|
|
||||||
const serverRes = {
|
this.forceChartData = {
|
||||||
categories: categories,
|
categories: categories.reverse(),
|
||||||
series: [
|
series: [
|
||||||
{ name: "目标值", data: targetData },
|
{ name: '1#轧制力', data: force1Data.reverse() },
|
||||||
{ name: "完成量", data: completeData }
|
{ 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.chartData = JSON.parse(JSON.stringify(serverRes))
|
|
||||||
} else {
|
|
||||||
this.loadDefaultChartData()
|
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
uni.hideLoading()
|
if (!isSilent) uni.hideLoading()
|
||||||
console.error('加载历史数据失败:', error)
|
console.error('加载轧制力历史失败:', error)
|
||||||
this.loadDefaultChartData()
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
// 加载默认图表数据
|
getDefineById(id) {
|
||||||
loadDefaultChartData() {
|
return this.plantStateDefines.find(item => item.id == id)
|
||||||
const serverRes = {
|
|
||||||
categories: ["2016", "2017", "2018", "2019", "2020", "2021"],
|
|
||||||
series: [
|
|
||||||
{ name: "目标值", data: [35, 36, 31, 33, 13, 34] },
|
|
||||||
{ name: "完成量", data: [18, 27, 21, 24, 6, 28] }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
this.chartData = JSON.parse(JSON.stringify(serverRes))
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// 格式化日期
|
|
||||||
formatDate(dateStr) {
|
formatDate(dateStr) {
|
||||||
if (!dateStr) return ''
|
if (!dateStr) return ''
|
||||||
const date = new Date(dateStr)
|
const date = new Date(dateStr)
|
||||||
return `${date.getMonth() + 1}/${date.getDate()}`
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
/* 简洁标签栏 */
|
/* 页面容器 */
|
||||||
|
.page-container {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: #f5f7fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 标签栏 */
|
||||||
.tab-container {
|
.tab-container {
|
||||||
display: flex !important;
|
display: flex;
|
||||||
width: 100%;
|
background: #fff;
|
||||||
background: #ffffff;
|
border-bottom: 2rpx solid #e4e7ed;
|
||||||
padding: 0 20rpx;
|
|
||||||
margin-bottom: 20rpx;
|
|
||||||
border-bottom: 1rpx solid #e8e8e8;
|
|
||||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
|
|
||||||
min-height: 88rpx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-item {
|
.tab-item {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 30rpx 10rpx;
|
padding: 28rpx 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab-label {
|
.tab-label {
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
color: #666;
|
color: #606266;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
transition: all 0.3s ease;
|
}
|
||||||
}
|
|
||||||
|
&.tab-active {
|
||||||
.tab-item.tab-active .tab-label {
|
.tab-label {
|
||||||
color: #1a73e8;
|
color: #0066cc;
|
||||||
font-weight: 600;
|
font-weight: 500;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-indicator {
|
.tab-indicator {
|
||||||
@@ -310,121 +478,155 @@ export default {
|
|||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
width: 50rpx;
|
width: 60rpx;
|
||||||
height: 4rpx;
|
height: 3rpx;
|
||||||
background: #1a73e8;
|
background: #0066cc;
|
||||||
border-radius: 2rpx;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 内容卡片 */
|
/* 刷新按钮 */
|
||||||
.content-card {
|
.refresh-btn-fixed {
|
||||||
background: #fff;
|
position: fixed;
|
||||||
margin-bottom: 20rpx;
|
right: 32rpx;
|
||||||
}
|
bottom: 120rpx;
|
||||||
|
width: 96rpx;
|
||||||
/* 指标容器 */
|
height: 96rpx;
|
||||||
.metric-container {
|
background: #0066cc;
|
||||||
|
border-radius: 50%;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-around;
|
align-items: center;
|
||||||
background: #fff;
|
justify-content: center;
|
||||||
padding: 0;
|
box-shadow: 0 8rpx 20rpx rgba(0, 102, 204, 0.4);
|
||||||
|
z-index: 999;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
opacity: 0.8;
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 指标项 */
|
.refresh-icon {
|
||||||
.metric-item {
|
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;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 指标卡片 - 3列布局 */
|
||||||
|
.metrics-grid-3 {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-box {
|
||||||
|
background: #fff;
|
||||||
|
border: 1rpx solid #e4e7ed;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
padding: 28rpx 20rpx;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 32rpx;
|
}
|
||||||
border-radius: 12rpx;
|
|
||||||
transition: all 0.2s;
|
.metric-name {
|
||||||
|
display: block;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #909399;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.metric-value {
|
.metric-value {
|
||||||
|
display: block;
|
||||||
font-size: 48rpx;
|
font-size: 48rpx;
|
||||||
font-weight: 600;
|
|
||||||
margin-bottom: 16rpx;
|
|
||||||
line-height: 1.2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metric-label {
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #666;
|
|
||||||
letter-spacing: 1rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 信息容器 */
|
|
||||||
.info-container {
|
|
||||||
padding: 20rpx;
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 12rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-row {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin-bottom: 24rpx;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 信息项 */
|
|
||||||
.info-item {
|
|
||||||
flex: 0 0 48%;
|
|
||||||
display: flex;
|
|
||||||
align-items: baseline;
|
|
||||||
padding: 16rpx 20rpx;
|
|
||||||
background: #f8f9fa;
|
|
||||||
border-radius: 10rpx;
|
|
||||||
border: 1rpx solid #e8e8e8;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
background: #f0f2f5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-label {
|
|
||||||
color: #666;
|
|
||||||
font-size: 26rpx;
|
|
||||||
flex-shrink: 0;
|
|
||||||
margin-right: 16rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-value {
|
|
||||||
color: #333;
|
|
||||||
font-size: 28rpx;
|
|
||||||
font-weight: 500;
|
|
||||||
word-break: break-all;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 设备卡片 */
|
|
||||||
.device-card {
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 12rpx;
|
|
||||||
overflow: hidden;
|
|
||||||
border: 1rpx solid #e8e8e8;
|
|
||||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
|
|
||||||
}
|
|
||||||
|
|
||||||
.device-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
padding: 20rpx 24rpx;
|
|
||||||
background: #1a73e8;
|
|
||||||
|
|
||||||
.device-name {
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #fff;
|
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
color: #0066cc;
|
||||||
|
margin-bottom: 8rpx;
|
||||||
.device-value {
|
line-height: 1;
|
||||||
font-size: 28rpx;
|
|
||||||
color: #fff;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
|
||||||
|
.metric-unit {
|
||||||
|
display: block;
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 图表容器 */
|
||||||
|
.chart-box {
|
||||||
|
background: #fff;
|
||||||
|
border: 1rpx solid #e4e7ed;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
padding: 24rpx 16rpx;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<view>
|
<view class="page-container">
|
||||||
<!-- 简洁标签栏 -->
|
<!-- 简洁标签栏 -->
|
||||||
<view class="tab-container">
|
<view class="tab-container">
|
||||||
<view
|
<view
|
||||||
@@ -14,295 +14,462 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<scroll-view scroll-y v-if="currentTab === 1">
|
<!-- 刷新按钮 -->
|
||||||
<view class="content-card">
|
<view class="refresh-btn-fixed" @click="refreshData">
|
||||||
<view class="metric-container">
|
<text class="refresh-icon" :class="{ 'rotating': isRefreshing }">⟳</text>
|
||||||
<!-- 网络状态指标 -->
|
</view>
|
||||||
<view class="metric-item">
|
|
||||||
<view class="metric-value">
|
<scroll-view scroll-y class="scroll-container" v-if="currentTab === 1">
|
||||||
正常
|
<!-- 顶部状态栏 -->
|
||||||
</view>
|
<view class="status-bar">
|
||||||
<view class="metric-label">
|
<view class="status-item">
|
||||||
网络状态
|
<text class="status-label">网络状态</text>
|
||||||
</view>
|
<text class="status-value" :class="'status-' + webStatus[0].value">{{ webStatus[0].value }}</text>
|
||||||
</view>
|
</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="metric-item">
|
<view class="section">
|
||||||
<view class="metric-value team-number">
|
<view class="section-title">轧机速度监控</view>
|
||||||
乙 / 中
|
<view class="metrics-grid-3">
|
||||||
</view>
|
<view class="metric-box" v-for="(item, index) in rollSpeedMetrics" :key="index">
|
||||||
<view class="metric-label">
|
<text class="metric-name">{{ item.label }}</text>
|
||||||
当前班组
|
<text class="metric-value">{{ item.value }}</text>
|
||||||
</view>
|
<text class="metric-unit">{{ item.unit }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="content-card">
|
<!-- 机架压下率 -->
|
||||||
<klp-collapse-panel title="状态统计">
|
<view class="section">
|
||||||
<qiun-data-charts type="line" :chartData="chartData" />
|
<view class="section-title">机架压下率</view>
|
||||||
</klp-collapse-panel>
|
<view class="metrics-grid-3">
|
||||||
</view>
|
<view class="metric-box" v-for="(item, index) in reducMetrics" :key="index">
|
||||||
|
<text class="metric-name">{{ item.label }}</text>
|
||||||
<view class="content-card">
|
<text class="metric-value">{{ item.value }}</text>
|
||||||
<klp-collapse-panel title="轧机状态">
|
<text class="metric-unit">{{ item.unit }}</text>
|
||||||
<qiun-data-charts type="column" :chartData="chartData" />
|
|
||||||
</klp-collapse-panel>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="content-card">
|
|
||||||
<klp-collapse-panel title="机组跟踪">
|
|
||||||
<view style="padding: 30rpx; display: flex; flex-direction: column; align-items: stretch; justify-content: center; gap: 20rpx;">
|
|
||||||
<view style="display: flex; justify-content: space-between; align-items: center; padding: 20rpx; background-color: #d9edf6; border-radius: 10rpx;">
|
|
||||||
<text>轧机</text>
|
|
||||||
<text>6390000</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view style="border-radius: 10rpx; overflow: hidden;">
|
|
||||||
<view style="display: flex; justify-content: space-between; align-items: center; padding: 20rpx; background-color: #d9edf6; border: 1px solid #d9edf6;">
|
|
||||||
<text>圆剪盘</text>
|
|
||||||
<text>6390000</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-container">
|
|
||||||
<view class="info-row">
|
|
||||||
<view class="info-item">
|
|
||||||
<text class="info-label">设备编号:</text>
|
|
||||||
<text class="info-value">M-001</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-item">
|
|
||||||
<text class="info-label">运行状态:</text>
|
|
||||||
<text class="info-value">正常</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="info-row">
|
|
||||||
<view class="info-item">
|
|
||||||
<text class="info-label">当前产量:</text>
|
|
||||||
<text class="info-value">2580 件</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-item">
|
|
||||||
<text class="info-label">合格率:</text>
|
|
||||||
<text class="info-value">98.5%</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view style="display: flex; justify-content: space-between; align-items: center; padding: 20rpx; background-color: #d9edf6; border-radius: 10rpx;">
|
|
||||||
<text>酸洗</text>
|
|
||||||
<text>6390000</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view style="border-radius: 10rpx; overflow: hidden;">
|
|
||||||
<view style="display: flex; justify-content: space-between; align-items: center; padding: 20rpx; background-color: #d9edf6; border: 1px solid #d9edf6;">
|
|
||||||
<text>入口活套</text>
|
|
||||||
<text>6390000</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-container">
|
|
||||||
<view class="info-row">
|
|
||||||
<view class="info-item">
|
|
||||||
<text class="info-label">设备编号:</text>
|
|
||||||
<text class="info-value">M-001</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-item">
|
|
||||||
<text class="info-label">运行状态:</text>
|
|
||||||
<text class="info-value">正常</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="info-row">
|
|
||||||
<view class="info-item">
|
|
||||||
<text class="info-label">当前产量:</text>
|
|
||||||
<text class="info-value">2580 件</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-item">
|
|
||||||
<text class="info-label">合格率:</text>
|
|
||||||
<text class="info-value">98.5%</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
</klp-collapse-panel>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="content-card">
|
<!-- 轧制力趋势 -->
|
||||||
<klp-collapse-panel title="能耗">
|
<view class="section">
|
||||||
<view class="metric-container">
|
<view class="section-title">轧制力趋势</view>
|
||||||
<!-- 工艺线速度指标 -->
|
<view class="chart-box">
|
||||||
<view class="metric-item">
|
<qiun-data-charts type="line" :chartData="forceChartData" :opts="lineChartOpts" />
|
||||||
<view class="metric-value">
|
</view>
|
||||||
9.9
|
</view>
|
||||||
</view>
|
|
||||||
<view class="metric-label">
|
|
||||||
工艺缎带钢线速度
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 出口线速度指标 -->
|
<!-- 带钢张力 -->
|
||||||
<view class="metric-item">
|
<view class="section">
|
||||||
<view class="metric-value team-number">
|
<view class="section-title">带钢张力监控</view>
|
||||||
126.0
|
<view class="metrics-grid-3">
|
||||||
</view>
|
<view class="metric-box" v-for="(item, index) in tensionMetrics" :key="index">
|
||||||
<view class="metric-label">
|
<text class="metric-name">{{ item.label }}</text>
|
||||||
轧机出口带钢线速度
|
<text class="metric-value">{{ item.value }}</text>
|
||||||
</view>
|
<text class="metric-unit">{{ item.unit }}</text>
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
</klp-collapse-panel>
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 功率百分比 -->
|
||||||
|
<view class="section">
|
||||||
|
<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>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
|
|
||||||
<scroll-view scroll-y v-if="currentTab == 2">
|
<scroll-view scroll-y class="scroll-container" v-if="currentTab == 2">
|
||||||
<klp-product-statistic></klp-product-statistic>
|
<klp-product-statistic></klp-product-statistic>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
|
|
||||||
<scroll-view scroll-y v-if="currentTab == 3">
|
<scroll-view scroll-y class="scroll-container" v-if="currentTab == 3">
|
||||||
<klp-shutdown-statistic></klp-shutdown-statistic>
|
<klp-shutdown-statistic></klp-shutdown-statistic>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
|
|
||||||
<scroll-view scroll-y v-if="currentTab == 4">
|
<scroll-view scroll-y class="scroll-container" v-if="currentTab == 4">
|
||||||
<klp-team-performance></klp-team-performance>
|
<klp-team-performance></klp-team-performance>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { listPlantStateCurrent, listPlantStateHistory } from '@/api/pocket/plantState'
|
import { getAllPlantStateDefines, listPlantStateHistory, getCurrentShift } from '@/api/pocket/plantState'
|
||||||
|
import config from '@/config'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
// 3. 响应式数据(替代 Vue 3 的 ref)
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
currentTab: 1, // 当前激活的标签页(默认实时监控)
|
currentTab: 1,
|
||||||
tabData: [ // 标签页配置
|
tabData: [
|
||||||
{ text: "实时监控", value: 1 },
|
{ text: "实时监控", value: 1 },
|
||||||
{ text: "生产统计", value: 2 },
|
{ text: "生产统计", value: 2 },
|
||||||
{ text: "停机统计", value: 3 },
|
{ text: "停机统计", value: 3 },
|
||||||
{ text: "班组绩效", value: 4 }
|
{ text: "班组绩效", value: 4 }
|
||||||
],
|
],
|
||||||
chartData: {} // 图表数据(初始化空对象,后续加载)
|
webStatus: [
|
||||||
|
{ label: '网络状态', value: '检测中...' },
|
||||||
|
{ label: '当前班组', value: '—' }
|
||||||
|
],
|
||||||
|
lastUpdateTime: '—',
|
||||||
|
isRefreshing: false,
|
||||||
|
refreshTimer: null,
|
||||||
|
// 轧辊速度(ID=36-41)
|
||||||
|
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' }
|
||||||
|
],
|
||||||
|
// 机架压下率(ID=24-29)
|
||||||
|
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: '%' }
|
||||||
|
],
|
||||||
|
// 带钢张力(ID=42-48)
|
||||||
|
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' }
|
||||||
|
],
|
||||||
|
// 功率百分比(ID=49-54)
|
||||||
|
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: '%' }
|
||||||
|
],
|
||||||
|
// 轧制力趋势图(ID=30-35)
|
||||||
|
forceChartData: {},
|
||||||
|
lineChartOpts: {
|
||||||
|
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" // 点击时显示空心点
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plantStateDefines: []
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
// 4. 生命周期钩子(替代 Vue 3 的 onMounted)
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.getServerData(); // 页面挂载后加载图表数据
|
this.loadAllData()
|
||||||
this.loadCurrentState(); // 加载当前状态
|
this.startAutoRefresh()
|
||||||
},
|
},
|
||||||
// 5. 方法定义(所有数据处理与逻辑)
|
|
||||||
|
beforeDestroy() {
|
||||||
|
this.stopAutoRefresh()
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
// 加载当前设备状态
|
startAutoRefresh() {
|
||||||
loadCurrentState() {
|
this.refreshTimer = setInterval(() => {
|
||||||
listPlantStateCurrent({ pageNum: 1, pageSize: 10 }).then(response => {
|
this.refreshData(true)
|
||||||
if (response.code === 200 && response.rows) {
|
}, 30000)
|
||||||
console.log('当前状态数据:', response.rows)
|
},
|
||||||
// 可以根据实际需求更新页面数据
|
|
||||||
|
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 })
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
this.updateLastTime()
|
||||||
console.error('加载设备状态失败:', error)
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
// 从服务器获取图表数据
|
updateLastTime() {
|
||||||
getServerData() {
|
const now = new Date()
|
||||||
uni.showLoading({ title: '加载中' })
|
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: '加载中' })
|
||||||
|
|
||||||
listPlantStateHistory({ pageNum: 1, pageSize: 20 }).then(response => {
|
return getAllPlantStateDefines().then(response => {
|
||||||
uni.hideLoading()
|
if (response.code === 200 && response.data) {
|
||||||
|
this.plantStateDefines = response.data
|
||||||
|
if (!isSilent) console.log('镀锌线1状态定义已加载:', this.plantStateDefines)
|
||||||
|
this.updateCurrentMetrics()
|
||||||
|
return this.loadForceHistory(isSilent)
|
||||||
|
} else {
|
||||||
|
if (!isSilent) uni.hideLoading()
|
||||||
|
}
|
||||||
|
}).catch(error => {
|
||||||
|
if (!isSilent) uni.hideLoading()
|
||||||
|
console.error('加载状态定义失败:', error)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
updateCurrentMetrics() {
|
||||||
|
// 1. 轧辊速度(ID=36-41:rollSpeed1-6)
|
||||||
|
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:reduc1-6)
|
||||||
|
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:tensionForce0-6)
|
||||||
|
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:powerRatio1-6)
|
||||||
|
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 || '%' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
loadForceHistory(isSilent = false) {
|
||||||
|
return listPlantStateHistory({ pageNum: 1, pageSize: 30 }).then(response => {
|
||||||
|
if (!isSilent) uni.hideLoading()
|
||||||
|
|
||||||
if (response.code === 200 && response.rows && response.rows.length > 0) {
|
if (response.code === 200 && response.rows && response.rows.length > 0) {
|
||||||
const categories = []
|
const categories = []
|
||||||
const targetData = []
|
const force1Data = []
|
||||||
const completeData = []
|
const force2Data = []
|
||||||
|
const force3Data = []
|
||||||
|
const force4Data = []
|
||||||
|
const force5Data = []
|
||||||
|
const force6Data = []
|
||||||
|
|
||||||
response.rows.forEach(item => {
|
response.rows.forEach(item => {
|
||||||
const dateStr = this.formatDate(item.insdate)
|
const dateStr = this.formatDate(item.insdate)
|
||||||
categories.push(dateStr)
|
categories.push(dateStr)
|
||||||
targetData.push(item.value1 || 0)
|
force1Data.push(Number(item.value30) || 0) // ID=30
|
||||||
completeData.push(item.value2 || 0)
|
force2Data.push(Number(item.value31) || 0) // ID=31
|
||||||
|
force3Data.push(Number(item.value32) || 0) // ID=32
|
||||||
|
force4Data.push(Number(item.value33) || 0) // ID=33
|
||||||
|
force5Data.push(Number(item.value34) || 0) // ID=34
|
||||||
|
force6Data.push(Number(item.value35) || 0) // ID=35
|
||||||
})
|
})
|
||||||
|
|
||||||
const serverRes = {
|
this.forceChartData = {
|
||||||
categories: categories,
|
categories: categories.reverse(),
|
||||||
series: [
|
series: [
|
||||||
{ name: "目标值", data: targetData },
|
{ name: '1#轧制力', data: force1Data.reverse() },
|
||||||
{ name: "完成量", data: completeData }
|
{ 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.chartData = JSON.parse(JSON.stringify(serverRes))
|
|
||||||
} else {
|
|
||||||
this.loadDefaultChartData()
|
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
uni.hideLoading()
|
if (!isSilent) uni.hideLoading()
|
||||||
console.error('加载历史数据失败:', error)
|
console.error('加载轧制力历史失败:', error)
|
||||||
this.loadDefaultChartData()
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
// 加载默认图表数据
|
getDefineById(id) {
|
||||||
loadDefaultChartData() {
|
return this.plantStateDefines.find(item => item.id == id)
|
||||||
const serverRes = {
|
|
||||||
categories: ["2016", "2017", "2018", "2019", "2020", "2021"],
|
|
||||||
series: [
|
|
||||||
{ name: "目标值", data: [35, 36, 31, 33, 13, 34] },
|
|
||||||
{ name: "完成量", data: [18, 27, 21, 24, 6, 28] }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
this.chartData = JSON.parse(JSON.stringify(serverRes))
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// 格式化日期
|
|
||||||
formatDate(dateStr) {
|
formatDate(dateStr) {
|
||||||
if (!dateStr) return ''
|
if (!dateStr) return ''
|
||||||
const date = new Date(dateStr)
|
const date = new Date(dateStr)
|
||||||
return `${date.getMonth() + 1}/${date.getDate()}`
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
page {
|
/* 页面容器 */
|
||||||
background-color: #b2b2b2;
|
.page-container {
|
||||||
height: 100vh;
|
min-height: 100vh;
|
||||||
overflow: auto;
|
background: #f5f7fa;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 简洁标签栏 */
|
/* 标签栏 */
|
||||||
.tab-container {
|
.tab-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
|
||||||
background: #fff;
|
background: #fff;
|
||||||
padding: 0 20rpx;
|
border-bottom: 2rpx solid #e4e7ed;
|
||||||
margin-bottom: 20rpx;
|
|
||||||
border-bottom: 1rpx solid #e8e8e8;
|
|
||||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-item {
|
.tab-item {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 30rpx 0;
|
padding: 28rpx 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
|
|
||||||
.tab-label {
|
.tab-label {
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
color: #666;
|
color: #606266;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.tab-active {
|
&.tab-active {
|
||||||
.tab-label {
|
.tab-label {
|
||||||
color: #1a73e8;
|
color: #0066cc;
|
||||||
font-weight: 600;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,93 +478,155 @@ page {
|
|||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
width: 50rpx;
|
width: 60rpx;
|
||||||
height: 4rpx;
|
height: 3rpx;
|
||||||
background: #1a73e8;
|
background: #0066cc;
|
||||||
border-radius: 2rpx;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 内容卡片 */
|
/* 刷新按钮 */
|
||||||
.content-card {
|
.refresh-btn-fixed {
|
||||||
background: #fff;
|
position: fixed;
|
||||||
margin-bottom: 20rpx;
|
right: 32rpx;
|
||||||
}
|
bottom: 120rpx;
|
||||||
|
width: 96rpx;
|
||||||
/* 指标容器 */
|
height: 96rpx;
|
||||||
.metric-container {
|
background: #0066cc;
|
||||||
|
border-radius: 50%;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-around;
|
align-items: center;
|
||||||
background: #fff;
|
justify-content: center;
|
||||||
padding: 0;
|
box-shadow: 0 8rpx 20rpx rgba(0, 102, 204, 0.4);
|
||||||
|
z-index: 999;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
opacity: 0.8;
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 指标项 */
|
.refresh-icon {
|
||||||
.metric-item {
|
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;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 指标卡片 - 3列布局 */
|
||||||
|
.metrics-grid-3 {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-box {
|
||||||
|
background: #fff;
|
||||||
|
border: 1rpx solid #e4e7ed;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
padding: 28rpx 20rpx;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 32rpx;
|
}
|
||||||
border-radius: 12rpx;
|
|
||||||
transition: all 0.2s;
|
.metric-name {
|
||||||
|
display: block;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #909399;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.metric-value {
|
.metric-value {
|
||||||
|
display: block;
|
||||||
font-size: 48rpx;
|
font-size: 48rpx;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin-bottom: 16rpx;
|
color: #0066cc;
|
||||||
line-height: 1.2;
|
margin-bottom: 8rpx;
|
||||||
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.metric-label {
|
.metric-unit {
|
||||||
font-size: 28rpx;
|
display: block;
|
||||||
color: #666;
|
font-size: 22rpx;
|
||||||
letter-spacing: 1rpx;
|
color: #909399;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 信息容器 */
|
/* 图表容器 */
|
||||||
.info-container {
|
.chart-box {
|
||||||
padding: 20rpx;
|
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 12rpx;
|
border: 1rpx solid #e4e7ed;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
padding: 24rpx 16rpx;
|
||||||
}
|
}
|
||||||
|
</style>
|
||||||
.info-row {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin-bottom: 24rpx;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 信息项 */
|
|
||||||
.info-item {
|
|
||||||
flex: 0 0 48%;
|
|
||||||
display: flex;
|
|
||||||
align-items: baseline;
|
|
||||||
padding: 16rpx 20rpx;
|
|
||||||
background: #f8f9fa;
|
|
||||||
border-radius: 10rpx;
|
|
||||||
border: 1rpx solid #e8e8e8;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
background: #f0f2f5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-label {
|
|
||||||
color: #666;
|
|
||||||
font-size: 26rpx;
|
|
||||||
flex-shrink: 0;
|
|
||||||
margin-right: 16rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-value {
|
|
||||||
color: #333;
|
|
||||||
font-size: 28rpx;
|
|
||||||
font-weight: 500;
|
|
||||||
word-break: break-all;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<view>
|
<view class="page-container">
|
||||||
<!-- 简洁标签栏 -->
|
<!-- 简洁标签栏 -->
|
||||||
<view class="tab-container">
|
<view class="tab-container">
|
||||||
<view
|
<view
|
||||||
@@ -14,295 +14,462 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<scroll-view scroll-y v-if="currentTab === 1">
|
<!-- 刷新按钮 -->
|
||||||
<view class="content-card">
|
<view class="refresh-btn-fixed" @click="refreshData">
|
||||||
<view class="metric-container">
|
<text class="refresh-icon" :class="{ 'rotating': isRefreshing }">⟳</text>
|
||||||
<!-- 网络状态指标 -->
|
|
||||||
<view class="metric-item">
|
|
||||||
<view class="metric-value">
|
|
||||||
正常
|
|
||||||
</view>
|
|
||||||
<view class="metric-label">
|
|
||||||
网络状态
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 班组指标 -->
|
<scroll-view scroll-y class="scroll-container" v-if="currentTab === 1">
|
||||||
<view class="metric-item">
|
<!-- 顶部状态栏 -->
|
||||||
<view class="metric-value team-number">
|
<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>
|
||||||
<view class="metric-label">
|
<view class="status-divider"></view>
|
||||||
当前班组
|
<view class="status-item">
|
||||||
|
<text class="status-label">当前班组</text>
|
||||||
|
<text class="status-value">{{ webStatus[1].value }}</text>
|
||||||
</view>
|
</view>
|
||||||
</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>
|
</view>
|
||||||
|
|
||||||
<view class="content-card">
|
<!-- 轧机速度监控 -->
|
||||||
<klp-collapse-panel title="状态统计">
|
<view class="section">
|
||||||
<qiun-data-charts type="line" :chartData="chartData" />
|
<view class="section-title">轧机速度监控</view>
|
||||||
</klp-collapse-panel>
|
<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">
|
||||||
|
<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">
|
||||||
|
<view class="section-title">轧制力趋势</view>
|
||||||
|
<view class="chart-box">
|
||||||
|
<qiun-data-charts type="line" :chartData="forceChartData" :opts="lineChartOpts" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 带钢张力 -->
|
||||||
|
<view class="section">
|
||||||
|
<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>
|
||||||
|
|
||||||
<view class="content-card">
|
<!-- 功率百分比 -->
|
||||||
<klp-collapse-panel title="轧机状态">
|
<view class="section">
|
||||||
<qiun-data-charts type="column" :chartData="chartData" />
|
<view class="section-title">机架功率百分比</view>
|
||||||
</klp-collapse-panel>
|
<view class="metrics-grid-3">
|
||||||
</view>
|
<view class="metric-box" v-for="(item, index) in powerMetrics" :key="index">
|
||||||
|
<text class="metric-name">{{ item.label }}</text>
|
||||||
<view class="content-card">
|
<text class="metric-value">{{ item.value }}</text>
|
||||||
<klp-collapse-panel title="机组跟踪">
|
<text class="metric-unit">{{ item.unit }}</text>
|
||||||
<view style="padding: 30rpx; display: flex; flex-direction: column; align-items: stretch; justify-content: center; gap: 20rpx;">
|
|
||||||
<view style="display: flex; justify-content: space-between; align-items: center; padding: 20rpx; background-color: #d9edf6; border-radius: 10rpx;">
|
|
||||||
<text>轧机</text>
|
|
||||||
<text>6390000</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view style="border-radius: 10rpx; overflow: hidden;">
|
|
||||||
<view style="display: flex; justify-content: space-between; align-items: center; padding: 20rpx; background-color: #d9edf6; border: 1px solid #d9edf6;">
|
|
||||||
<text>圆剪盘</text>
|
|
||||||
<text>6390000</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-container">
|
|
||||||
<view class="info-row">
|
|
||||||
<view class="info-item">
|
|
||||||
<text class="info-label">设备编号:</text>
|
|
||||||
<text class="info-value">M-001</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-item">
|
|
||||||
<text class="info-label">运行状态:</text>
|
|
||||||
<text class="info-value">正常</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="info-row">
|
|
||||||
<view class="info-item">
|
|
||||||
<text class="info-label">当前产量:</text>
|
|
||||||
<text class="info-value">2580 件</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-item">
|
|
||||||
<text class="info-label">合格率:</text>
|
|
||||||
<text class="info-value">98.5%</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view style="display: flex; justify-content: space-between; align-items: center; padding: 20rpx; background-color: #d9edf6; border-radius: 10rpx;">
|
|
||||||
<text>酸洗</text>
|
|
||||||
<text>6390000</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view style="border-radius: 10rpx; overflow: hidden;">
|
|
||||||
<view style="display: flex; justify-content: space-between; align-items: center; padding: 20rpx; background-color: #d9edf6; border: 1px solid #d9edf6;">
|
|
||||||
<text>入口活套</text>
|
|
||||||
<text>6390000</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-container">
|
|
||||||
<view class="info-row">
|
|
||||||
<view class="info-item">
|
|
||||||
<text class="info-label">设备编号:</text>
|
|
||||||
<text class="info-value">M-001</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-item">
|
|
||||||
<text class="info-label">运行状态:</text>
|
|
||||||
<text class="info-value">正常</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="info-row">
|
|
||||||
<view class="info-item">
|
|
||||||
<text class="info-label">当前产量:</text>
|
|
||||||
<text class="info-value">2580 件</text>
|
|
||||||
</view>
|
|
||||||
<view class="info-item">
|
|
||||||
<text class="info-label">合格率:</text>
|
|
||||||
<text class="info-value">98.5%</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</klp-collapse-panel>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="content-card">
|
|
||||||
<klp-collapse-panel title="能耗">
|
|
||||||
<view class="metric-container">
|
|
||||||
<!-- 工艺线速度指标 -->
|
|
||||||
<view class="metric-item">
|
|
||||||
<view class="metric-value">
|
|
||||||
9.9
|
|
||||||
</view>
|
|
||||||
<view class="metric-label">
|
|
||||||
工艺缎带钢线速度
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 出口线速度指标 -->
|
|
||||||
<view class="metric-item">
|
|
||||||
<view class="metric-value team-number">
|
|
||||||
126.0
|
|
||||||
</view>
|
|
||||||
<view class="metric-label">
|
|
||||||
轧机出口带钢线速度
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</klp-collapse-panel>
|
|
||||||
</view>
|
</view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
|
|
||||||
<scroll-view scroll-y v-if="currentTab == 2">
|
<scroll-view scroll-y class="scroll-container" v-if="currentTab == 2">
|
||||||
<klp-product-statistic></klp-product-statistic>
|
<klp-product-statistic></klp-product-statistic>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
|
|
||||||
<scroll-view scroll-y v-if="currentTab == 3">
|
<scroll-view scroll-y class="scroll-container" v-if="currentTab == 3">
|
||||||
<klp-shutdown-statistic></klp-shutdown-statistic>
|
<klp-shutdown-statistic></klp-shutdown-statistic>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
|
|
||||||
<scroll-view scroll-y v-if="currentTab == 4">
|
<scroll-view scroll-y class="scroll-container" v-if="currentTab == 4">
|
||||||
<klp-team-performance></klp-team-performance>
|
<klp-team-performance></klp-team-performance>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { listPlantStateCurrent, listPlantStateHistory } from '@/api/pocket/plantState'
|
import { getAllPlantStateDefines, listPlantStateHistory, getCurrentShift } from '@/api/pocket/plantState'
|
||||||
|
import config from '@/config'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
// 3. 响应式数据(替代 Vue 3 的 ref)
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
currentTab: 1, // 当前激活的标签页(默认实时监控)
|
currentTab: 1,
|
||||||
tabData: [ // 标签页配置
|
tabData: [
|
||||||
{ text: "实时监控", value: 1 },
|
{ text: "实时监控", value: 1 },
|
||||||
{ text: "生产统计", value: 2 },
|
{ text: "生产统计", value: 2 },
|
||||||
{ text: "停机统计", value: 3 },
|
{ text: "停机统计", value: 3 },
|
||||||
{ text: "班组绩效", value: 4 }
|
{ text: "班组绩效", value: 4 }
|
||||||
],
|
],
|
||||||
chartData: {} // 图表数据(初始化空对象,后续加载)
|
webStatus: [
|
||||||
|
{ label: '网络状态', value: '检测中...' },
|
||||||
|
{ label: '当前班组', value: '—' }
|
||||||
|
],
|
||||||
|
lastUpdateTime: '—',
|
||||||
|
isRefreshing: false,
|
||||||
|
refreshTimer: null,
|
||||||
|
// 轧辊速度(ID=36-41)
|
||||||
|
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' }
|
||||||
|
],
|
||||||
|
// 机架压下率(ID=24-29)
|
||||||
|
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: '%' }
|
||||||
|
],
|
||||||
|
// 带钢张力(ID=42-48)
|
||||||
|
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' }
|
||||||
|
],
|
||||||
|
// 功率百分比(ID=49-54)
|
||||||
|
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: '%' }
|
||||||
|
],
|
||||||
|
// 轧制力趋势图(ID=30-35)
|
||||||
|
forceChartData: {},
|
||||||
|
lineChartOpts: {
|
||||||
|
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" // 点击时显示空心点
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plantStateDefines: []
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
// 4. 生命周期钩子(替代 Vue 3 的 onMounted)
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.getServerData(); // 页面挂载后加载图表数据
|
this.loadAllData()
|
||||||
this.loadCurrentState(); // 加载当前状态
|
this.startAutoRefresh()
|
||||||
},
|
},
|
||||||
// 5. 方法定义(所有数据处理与逻辑)
|
|
||||||
|
beforeDestroy() {
|
||||||
|
this.stopAutoRefresh()
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
// 加载当前设备状态
|
startAutoRefresh() {
|
||||||
loadCurrentState() {
|
this.refreshTimer = setInterval(() => {
|
||||||
listPlantStateCurrent({ pageNum: 1, pageSize: 10 }).then(response => {
|
this.refreshData(true)
|
||||||
if (response.code === 200 && response.rows) {
|
}, 30000)
|
||||||
console.log('当前状态数据:', response.rows)
|
},
|
||||||
// 可以根据实际需求更新页面数据
|
|
||||||
|
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 })
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
this.updateLastTime()
|
||||||
console.error('加载设备状态失败:', error)
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
// 从服务器获取图表数据
|
updateLastTime() {
|
||||||
getServerData() {
|
const now = new Date()
|
||||||
uni.showLoading({ title: '加载中' })
|
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: '加载中' })
|
||||||
|
|
||||||
listPlantStateHistory({ pageNum: 1, pageSize: 20 }).then(response => {
|
return getAllPlantStateDefines().then(response => {
|
||||||
uni.hideLoading()
|
if (response.code === 200 && response.data) {
|
||||||
|
this.plantStateDefines = response.data
|
||||||
|
if (!isSilent) console.log('镀锌线1状态定义已加载:', this.plantStateDefines)
|
||||||
|
this.updateCurrentMetrics()
|
||||||
|
return this.loadForceHistory(isSilent)
|
||||||
|
} else {
|
||||||
|
if (!isSilent) uni.hideLoading()
|
||||||
|
}
|
||||||
|
}).catch(error => {
|
||||||
|
if (!isSilent) uni.hideLoading()
|
||||||
|
console.error('加载状态定义失败:', error)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
updateCurrentMetrics() {
|
||||||
|
// 1. 轧辊速度(ID=36-41:rollSpeed1-6)
|
||||||
|
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:reduc1-6)
|
||||||
|
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:tensionForce0-6)
|
||||||
|
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:powerRatio1-6)
|
||||||
|
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 || '%' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
loadForceHistory(isSilent = false) {
|
||||||
|
return listPlantStateHistory({ pageNum: 1, pageSize: 30 }).then(response => {
|
||||||
|
if (!isSilent) uni.hideLoading()
|
||||||
|
|
||||||
if (response.code === 200 && response.rows && response.rows.length > 0) {
|
if (response.code === 200 && response.rows && response.rows.length > 0) {
|
||||||
const categories = []
|
const categories = []
|
||||||
const targetData = []
|
const force1Data = []
|
||||||
const completeData = []
|
const force2Data = []
|
||||||
|
const force3Data = []
|
||||||
|
const force4Data = []
|
||||||
|
const force5Data = []
|
||||||
|
const force6Data = []
|
||||||
|
|
||||||
response.rows.forEach(item => {
|
response.rows.forEach(item => {
|
||||||
const dateStr = this.formatDate(item.insdate)
|
const dateStr = this.formatDate(item.insdate)
|
||||||
categories.push(dateStr)
|
categories.push(dateStr)
|
||||||
targetData.push(item.value1 || 0)
|
force1Data.push(Number(item.value30) || 0) // ID=30
|
||||||
completeData.push(item.value2 || 0)
|
force2Data.push(Number(item.value31) || 0) // ID=31
|
||||||
|
force3Data.push(Number(item.value32) || 0) // ID=32
|
||||||
|
force4Data.push(Number(item.value33) || 0) // ID=33
|
||||||
|
force5Data.push(Number(item.value34) || 0) // ID=34
|
||||||
|
force6Data.push(Number(item.value35) || 0) // ID=35
|
||||||
})
|
})
|
||||||
|
|
||||||
const serverRes = {
|
this.forceChartData = {
|
||||||
categories: categories,
|
categories: categories.reverse(),
|
||||||
series: [
|
series: [
|
||||||
{ name: "目标值", data: targetData },
|
{ name: '1#轧制力', data: force1Data.reverse() },
|
||||||
{ name: "完成量", data: completeData }
|
{ 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.chartData = JSON.parse(JSON.stringify(serverRes))
|
|
||||||
} else {
|
|
||||||
this.loadDefaultChartData()
|
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
uni.hideLoading()
|
if (!isSilent) uni.hideLoading()
|
||||||
console.error('加载历史数据失败:', error)
|
console.error('加载轧制力历史失败:', error)
|
||||||
this.loadDefaultChartData()
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
// 加载默认图表数据
|
getDefineById(id) {
|
||||||
loadDefaultChartData() {
|
return this.plantStateDefines.find(item => item.id == id)
|
||||||
const serverRes = {
|
|
||||||
categories: ["2016", "2017", "2018", "2019", "2020", "2021"],
|
|
||||||
series: [
|
|
||||||
{ name: "目标值", data: [35, 36, 31, 33, 13, 34] },
|
|
||||||
{ name: "完成量", data: [18, 27, 21, 24, 6, 28] }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
this.chartData = JSON.parse(JSON.stringify(serverRes))
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// 格式化日期
|
|
||||||
formatDate(dateStr) {
|
formatDate(dateStr) {
|
||||||
if (!dateStr) return ''
|
if (!dateStr) return ''
|
||||||
const date = new Date(dateStr)
|
const date = new Date(dateStr)
|
||||||
return `${date.getMonth() + 1}/${date.getDate()}`
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
page {
|
/* 页面容器 */
|
||||||
background-color: #b2b2b2;
|
.page-container {
|
||||||
height: 100vh;
|
min-height: 100vh;
|
||||||
overflow: auto;
|
background: #f5f7fa;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 简洁标签栏 */
|
/* 标签栏 */
|
||||||
.tab-container {
|
.tab-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
|
||||||
background: #fff;
|
background: #fff;
|
||||||
padding: 0 20rpx;
|
border-bottom: 2rpx solid #e4e7ed;
|
||||||
margin-bottom: 20rpx;
|
|
||||||
border-bottom: 1rpx solid #e8e8e8;
|
|
||||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-item {
|
.tab-item {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 30rpx 0;
|
padding: 28rpx 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
|
|
||||||
.tab-label {
|
.tab-label {
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
color: #666;
|
color: #606266;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.tab-active {
|
&.tab-active {
|
||||||
.tab-label {
|
.tab-label {
|
||||||
color: #1a73e8;
|
color: #0066cc;
|
||||||
font-weight: 600;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,93 +478,155 @@ page {
|
|||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
width: 50rpx;
|
width: 60rpx;
|
||||||
height: 4rpx;
|
height: 3rpx;
|
||||||
background: #1a73e8;
|
background: #0066cc;
|
||||||
border-radius: 2rpx;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 内容卡片 */
|
/* 刷新按钮 */
|
||||||
.content-card {
|
.refresh-btn-fixed {
|
||||||
background: #fff;
|
position: fixed;
|
||||||
margin-bottom: 20rpx;
|
right: 32rpx;
|
||||||
}
|
bottom: 120rpx;
|
||||||
|
width: 96rpx;
|
||||||
/* 指标容器 */
|
height: 96rpx;
|
||||||
.metric-container {
|
background: #0066cc;
|
||||||
|
border-radius: 50%;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-around;
|
align-items: center;
|
||||||
background: #fff;
|
justify-content: center;
|
||||||
padding: 0;
|
box-shadow: 0 8rpx 20rpx rgba(0, 102, 204, 0.4);
|
||||||
|
z-index: 999;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
opacity: 0.8;
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 指标项 */
|
.refresh-icon {
|
||||||
.metric-item {
|
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;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 指标卡片 - 3列布局 */
|
||||||
|
.metrics-grid-3 {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-box {
|
||||||
|
background: #fff;
|
||||||
|
border: 1rpx solid #e4e7ed;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
padding: 28rpx 20rpx;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 32rpx;
|
}
|
||||||
border-radius: 12rpx;
|
|
||||||
transition: all 0.2s;
|
.metric-name {
|
||||||
|
display: block;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #909399;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.metric-value {
|
.metric-value {
|
||||||
|
display: block;
|
||||||
font-size: 48rpx;
|
font-size: 48rpx;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin-bottom: 16rpx;
|
color: #0066cc;
|
||||||
line-height: 1.2;
|
margin-bottom: 8rpx;
|
||||||
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.metric-label {
|
.metric-unit {
|
||||||
font-size: 28rpx;
|
display: block;
|
||||||
color: #666;
|
font-size: 22rpx;
|
||||||
letter-spacing: 1rpx;
|
color: #909399;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 信息容器 */
|
/* 图表容器 */
|
||||||
.info-container {
|
.chart-box {
|
||||||
padding: 20rpx;
|
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 12rpx;
|
border: 1rpx solid #e4e7ed;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
padding: 24rpx 16rpx;
|
||||||
}
|
}
|
||||||
|
</style>
|
||||||
.info-row {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin-bottom: 24rpx;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 信息项 */
|
|
||||||
.info-item {
|
|
||||||
flex: 0 0 48%;
|
|
||||||
display: flex;
|
|
||||||
align-items: baseline;
|
|
||||||
padding: 16rpx 20rpx;
|
|
||||||
background: #f8f9fa;
|
|
||||||
border-radius: 10rpx;
|
|
||||||
border: 1rpx solid #e8e8e8;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
background: #f0f2f5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-label {
|
|
||||||
color: #666;
|
|
||||||
font-size: 26rpx;
|
|
||||||
flex-shrink: 0;
|
|
||||||
margin-right: 16rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-value {
|
|
||||||
color: #333;
|
|
||||||
font-size: 28rpx;
|
|
||||||
font-weight: 500;
|
|
||||||
word-break: break-all;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
Reference in New Issue
Block a user