Files
klp-mono/apps/hand-factory/components/lines/zinc3.vue
2025-12-07 12:54:39 +08:00

596 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

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

<template>
<view class="page-container">
<!-- 简洁标签栏 -->
<view class="tab-container">
<view
v-for="item in tabData"
:key="item.value"
@click="currentTab = item.value"
class="tab-item"
:class="{ 'tab-active': currentTab === item.value }"
>
<text class="tab-label">{{ item.text }}</text>
<view class="tab-indicator" v-if="currentTab === item.value"></view>
</view>
</view>
<!-- 刷新按钮 -->
<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="disabled-container">
<view class="disabled-icon">🔒</view>
<view class="disabled-title">该功能未启用</view>
<view class="disabled-desc">镀锌线3实时监控功能暂未启用请联系管理员</view>
</view>
</scroll-view>
<scroll-view scroll-y class="scroll-container" v-if="currentTab == 2">
<klp-product-statistic></klp-product-statistic>
</scroll-view>
<scroll-view scroll-y class="scroll-container" v-if="currentTab == 3">
<klp-shutdown-statistic></klp-shutdown-statistic>
</scroll-view>
<scroll-view scroll-y class="scroll-container" v-if="currentTab == 4">
<klp-team-performance></klp-team-performance>
</scroll-view>
</view>
</template>
<script>
import { getAllPlantStateDefines, listPlantStateHistory, getCurrentShift } from '@/api/pocket/plantState'
import config from '@/config'
export default {
data() {
return {
currentTab: 1,
tabData: [
{ text: "实时监控", value: 1 },
{ text: "生产统计", value: 2 },
{ text: "停机统计", value: 3 },
{ text: "班组绩效", value: 4 }
],
webStatus: [
{ label: '网络状态', value: '检测中...' },
{ label: '当前班组', value: '—' }
],
lastUpdateTime: '—',
isRefreshing: false,
refreshTimer: null,
// 轧辊速度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: []
};
},
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() {
const now = new Date()
const hour = String(now.getHours()).padStart(2, '0')
const minute = String(now.getMinutes()).padStart(2, '0')
const second = String(now.getSeconds()).padStart(2, '0')
this.lastUpdateTime = `${hour}:${minute}:${second}`
},
checkNetworkStatus() {
return new Promise((resolve) => {
const startTime = Date.now()
uni.request({
url: config.baseUrl + '/pocket/proPlantStateDefine/allWithValues',
method: 'GET',
timeout: 5000,
success: (res) => {
const responseTime = Date.now() - startTime
if (responseTime < 500) {
this.webStatus[0].value = '通畅'
} else if (responseTime < 2000) {
this.webStatus[0].value = '卡顿'
} else {
this.webStatus[0].value = '异常'
}
resolve()
},
fail: () => {
this.webStatus[0].value = '异常'
resolve()
}
})
})
},
loadCurrentShift() {
return getCurrentShift().then(response => {
if (response.code === 200 && response.data) {
const shiftData = response.data
const shiftName = this.getShiftName(shiftData.shift)
const crewName = this.getCrewName(shiftData.crew)
this.webStatus[1].value = `${crewName} / ${shiftName}`
}
}).catch(error => {
console.error('加载班组信息失败:', error)
})
},
getShiftName(shift) {
const shiftMap = { 'A': '早班', 'B': '中班', 'C': '晚班' }
return shiftMap[shift] || shift || '—'
},
getCrewName(crew) {
const crewMap = { 1: '甲', 2: '乙', 3: '丙', 4: '丁' }
return crewMap[crew] || crew || '—'
},
initPlantStateDefines(isSilent = false) {
if (!isSilent) uni.showLoading({ title: '加载中' })
return getAllPlantStateDefines().then(response => {
if (response.code === 200 && response.data) {
this.plantStateDefines = response.data
if (!isSilent) console.log('镀锌线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-41rollSpeed1-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-29reduc1-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-48tensionForce0-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-54powerRatio1-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) {
const categories = []
const force1Data = []
const force2Data = []
const force3Data = []
const force4Data = []
const force5Data = []
const force6Data = []
response.rows.forEach(item => {
const dateStr = this.formatDate(item.insdate)
categories.push(dateStr)
force1Data.push(Number(item.value30) || 0) // ID=30
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
})
this.forceChartData = {
categories: categories.reverse(),
series: [
{ name: '1#轧制力', data: force1Data.reverse() },
{ name: '2#轧制力', data: force2Data.reverse() },
{ name: '3#轧制力', data: force3Data.reverse() },
{ name: '4#轧制力', data: force4Data.reverse() },
{ name: '5#轧制力', data: force5Data.reverse() },
{ name: '6#轧制力', data: force6Data.reverse() }
]
}
}
}).catch(error => {
if (!isSilent) uni.hideLoading()
console.error('加载轧制力历史失败:', error)
})
},
getDefineById(id) {
return this.plantStateDefines.find(item => item.id == id)
},
formatDate(dateStr) {
if (!dateStr) return ''
const date = new Date(dateStr)
const hour = String(date.getHours()).padStart(2, '0')
const minute = String(date.getMinutes()).padStart(2, '0')
return `${hour}:${minute}`
},
formatValue(value) {
if (value === null || value === undefined || value === '') return '—'
const num = Number(value)
if (isNaN(num)) return '—'
return num.toFixed(2)
}
}
};
</script>
<style scoped lang="scss">
/* 页面容器 */
.page-container {
min-height: 100vh;
background: #f5f7fa;
}
/* 标签栏 */
.tab-container {
display: flex;
background: #fff;
border-bottom: 2rpx solid #e4e7ed;
}
.tab-item {
flex: 1;
text-align: center;
padding: 28rpx 0;
position: relative;
.tab-label {
font-size: 28rpx;
color: #606266;
font-weight: 400;
}
&.tab-active {
.tab-label {
color: #0066cc;
font-weight: 500;
}
}
.tab-indicator {
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 60rpx;
height: 3rpx;
background: #0066cc;
}
}
/* 刷新按钮 */
.refresh-btn-fixed {
position: fixed;
right: 32rpx;
bottom: 120rpx;
width: 96rpx;
height: 96rpx;
background: #0066cc;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 8rpx 20rpx rgba(0, 102, 204, 0.4);
z-index: 999;
&:active {
opacity: 0.8;
transform: scale(0.95);
}
}
.refresh-icon {
font-size: 48rpx;
color: #fff;
display: block;
line-height: 1;
&.rotating {
animation: rotate 1s linear infinite;
}
}
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
/* 滚动容器 */
.scroll-container {
height: calc(100vh - 96rpx);
padding: 24rpx;
}
/* 顶部状态栏 */
.status-bar {
display: flex;
align-items: center;
background: #fff;
padding: 24rpx 32rpx;
margin-bottom: 24rpx;
border-radius: 8rpx;
border: 1rpx solid #e4e7ed;
}
.status-item {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
gap: 16rpx;
}
.status-label {
font-size: 26rpx;
color: #909399;
}
.status-value {
font-size: 28rpx;
font-weight: 500;
color: #303133;
&.status-通畅 { color: #67c23a; }
&.status-卡顿 { color: #e6a23c; }
&.status-异常 { color: #f56c6c; }
&.status-time {
color: #909399;
font-size: 24rpx;
}
}
.status-divider {
width: 1rpx;
height: 40rpx;
background: #e4e7ed;
}
/* 区块样式 */
.section {
margin-bottom: 24rpx;
}
.section-title {
font-size: 30rpx;
font-weight: 500;
color: #303133;
margin-bottom: 20rpx;
padding-left: 16rpx;
border-left: 4rpx solid #0066cc;
}
/* 指标卡片 - 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;
}
.metric-name {
display: block;
font-size: 24rpx;
color: #909399;
margin-bottom: 16rpx;
}
.metric-value {
display: block;
font-size: 48rpx;
font-weight: 600;
color: #0066cc;
margin-bottom: 8rpx;
line-height: 1;
}
.metric-unit {
display: block;
font-size: 22rpx;
color: #909399;
}
/* 图表容器 */
.chart-box {
background: #fff;
border: 1rpx solid #e4e7ed;
border-radius: 8rpx;
padding: 24rpx 16rpx;
}
/* 未启用容器 */
.disabled-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: calc(100vh - 200rpx);
padding: 40rpx;
text-align: center;
}
.disabled-icon {
font-size: 120rpx;
margin-bottom: 32rpx;
opacity: 0.6;
}
.disabled-title {
font-size: 32rpx;
font-weight: 600;
color: #303133;
margin-bottom: 16rpx;
}
.disabled-desc {
font-size: 26rpx;
color: #909399;
line-height: 1.6;
}
</style>