2025-10-10 16:47:38 +08:00
|
|
|
|
<template>
|
2026-01-04 15:07:47 +08:00
|
|
|
|
<div class="industrial-dashboard">
|
|
|
|
|
|
<!-- Header: 系统标题和当前时间 -->
|
|
|
|
|
|
<div class="dashboard-header">
|
|
|
|
|
|
<div class="header-left">
|
|
|
|
|
|
<h1 class="system-title">生产监控大屏</h1>
|
|
|
|
|
|
<p class="system-subtitle">实时生产数据与设备状态</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="header-right">
|
2025-10-10 16:47:38 +08:00
|
|
|
|
<CurrentTime />
|
2026-01-04 15:07:47 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- KPI指标区域 -->
|
|
|
|
|
|
<el-row :gutter="20" class="kpi-section">
|
|
|
|
|
|
<el-col :span="6" v-for="(kpi, index) in kpiData" :key="index">
|
|
|
|
|
|
<el-card class="kpi-card" :class="`kpi-${index}`">
|
|
|
|
|
|
<div class="kpi-content">
|
|
|
|
|
|
<div class="kpi-icon">
|
|
|
|
|
|
<i :class="kpi.icon"></i>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="kpi-info">
|
|
|
|
|
|
<div class="kpi-label">{{ kpi.label }}</div>
|
|
|
|
|
|
<div class="kpi-value">{{ kpi.value }}</div>
|
|
|
|
|
|
<div class="kpi-unit">{{ kpi.unit }}</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="kpi-trend" :class="kpi.trend">
|
|
|
|
|
|
<i :class="kpi.trend === 'up' ? 'el-icon-top' : 'el-icon-bottom'"></i>
|
|
|
|
|
|
<span>{{ kpi.change }}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 生产状态区域 -->
|
|
|
|
|
|
<el-row :gutter="20" class="status-section">
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-card class="status-card">
|
|
|
|
|
|
<div slot="header" class="card-header">
|
|
|
|
|
|
<span>生产状态</span>
|
|
|
|
|
|
<el-tag :type="productionStatus.type" size="small">{{ productionStatus.text }}</el-tag>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="status-content">
|
|
|
|
|
|
<div class="status-item">
|
|
|
|
|
|
<span class="status-label">当前钢卷号:</span>
|
|
|
|
|
|
<span class="status-value">{{ productionStatus.currentCoilId || '无' }}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="status-item">
|
|
|
|
|
|
<span class="status-label">带钢速度:</span>
|
|
|
|
|
|
<span class="status-value">{{ productionStatus.stripSpeed || '0' }} m/min</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="status-item">
|
|
|
|
|
|
<span class="status-label">产线效率:</span>
|
|
|
|
|
|
<span class="status-value">{{ productionStatus.efficiency || '0' }}%</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-card class="status-card">
|
|
|
|
|
|
<div slot="header" class="card-header">
|
|
|
|
|
|
<span>设备状态</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="equipment-grid">
|
|
|
|
|
|
<div class="equipment-item" v-for="(equipment, index) in equipmentStatus" :key="index">
|
|
|
|
|
|
<div class="equipment-name">{{ equipment.name }}</div>
|
|
|
|
|
|
<el-tag :type="equipment.status === 'running' ? 'success' : equipment.status === 'warning' ? 'warning' : 'danger'" size="mini">
|
|
|
|
|
|
{{ equipment.statusText }}
|
|
|
|
|
|
</el-tag>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-card>
|
2025-10-10 16:47:38 +08:00
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
|
2026-01-04 15:07:47 +08:00
|
|
|
|
<!-- 数据表格区域 -->
|
|
|
|
|
|
<el-row :gutter="20" class="table-section">
|
|
|
|
|
|
<el-col :span="12">
|
2025-10-10 16:47:38 +08:00
|
|
|
|
<el-card>
|
2026-01-04 15:07:47 +08:00
|
|
|
|
<div slot="header" class="card-header">
|
|
|
|
|
|
<span>系统告警信息</span>
|
|
|
|
|
|
<el-badge :value="alarmData.length" class="alarm-badge" v-if="alarmData.length > 0"></el-badge>
|
|
|
|
|
|
</div>
|
2025-10-10 16:47:38 +08:00
|
|
|
|
<MiniTable
|
|
|
|
|
|
v-loading="tableLoading"
|
|
|
|
|
|
:columns="alarmColumns"
|
|
|
|
|
|
:data="alarmData"
|
|
|
|
|
|
:highlightOnRowClick="true"
|
2026-01-04 15:07:47 +08:00
|
|
|
|
tableHeight="280px"
|
2025-10-10 16:47:38 +08:00
|
|
|
|
/>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
</el-col>
|
2026-01-04 15:07:47 +08:00
|
|
|
|
<el-col :span="12">
|
2025-10-10 16:47:38 +08:00
|
|
|
|
<el-card>
|
2026-01-04 15:07:47 +08:00
|
|
|
|
<div slot="header" class="card-header">
|
|
|
|
|
|
<span>换辊信息</span>
|
|
|
|
|
|
</div>
|
2025-10-10 16:47:38 +08:00
|
|
|
|
<MiniTable
|
|
|
|
|
|
v-loading="rollHistoryLoading"
|
|
|
|
|
|
:columns="rollHistoryColumns"
|
|
|
|
|
|
:data="rollHistoryData"
|
2026-01-04 15:07:47 +08:00
|
|
|
|
tableHeight="280px"
|
2025-10-10 16:47:38 +08:00
|
|
|
|
/>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
</el-col>
|
2026-01-04 15:07:47 +08:00
|
|
|
|
</el-row>
|
|
|
|
|
|
|
|
|
|
|
|
<el-row :gutter="20" class="table-section">
|
2025-10-10 16:47:38 +08:00
|
|
|
|
<el-col :span="24">
|
|
|
|
|
|
<el-card>
|
2026-01-04 15:07:47 +08:00
|
|
|
|
<div slot="header" class="card-header">
|
|
|
|
|
|
<span>生产计划</span>
|
|
|
|
|
|
<el-button type="text" size="small" @click="$router.push('/plan')">
|
|
|
|
|
|
查看全部
|
|
|
|
|
|
<i class="el-icon-arrow-right"></i>
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
</div>
|
2025-10-10 16:47:38 +08:00
|
|
|
|
<MiniTable
|
|
|
|
|
|
v-loading="planLoading"
|
|
|
|
|
|
:columns="planColumns"
|
|
|
|
|
|
:data="planData"
|
2026-01-04 15:07:47 +08:00
|
|
|
|
tableHeight="280px"
|
2025-10-10 16:47:38 +08:00
|
|
|
|
/>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
</el-col>
|
2026-01-04 15:07:47 +08:00
|
|
|
|
</el-row>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 过程跟踪区域 -->
|
|
|
|
|
|
<el-row :gutter="20" class="table-section">
|
2025-11-03 10:51:46 +08:00
|
|
|
|
<el-col :span="24">
|
|
|
|
|
|
<el-card>
|
2026-01-04 15:07:47 +08:00
|
|
|
|
<div slot="header" class="card-header">
|
|
|
|
|
|
<span>过程跟踪</span>
|
|
|
|
|
|
<el-button type="text" size="small" @click="$router.push('/track')">
|
|
|
|
|
|
查看详情
|
|
|
|
|
|
<i class="el-icon-arrow-right"></i>
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
</div>
|
2025-11-03 10:51:46 +08:00
|
|
|
|
<TrackMeasure
|
|
|
|
|
|
v-loading="measureLoading"
|
|
|
|
|
|
:columns="measureColumns"
|
|
|
|
|
|
:data="measureData"
|
2026-01-04 15:07:47 +08:00
|
|
|
|
tableHeight="280px"
|
2025-11-03 10:51:46 +08:00
|
|
|
|
/>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
</el-col>
|
2025-10-10 16:47:38 +08:00
|
|
|
|
</el-row>
|
2026-01-04 15:07:47 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- 快速访问菜单 -->
|
|
|
|
|
|
<el-row :gutter="20" class="quick-access-section">
|
|
|
|
|
|
<el-col :span="24">
|
|
|
|
|
|
<el-card>
|
|
|
|
|
|
<div slot="header" class="card-header">
|
|
|
|
|
|
<span>快速访问</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="quick-access-grid">
|
|
|
|
|
|
<div
|
|
|
|
|
|
class="access-item"
|
|
|
|
|
|
v-for="(card, index) in featureCards"
|
|
|
|
|
|
:key="index"
|
|
|
|
|
|
@click="$router.push(card.path)"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div class="access-icon">
|
|
|
|
|
|
<i :class="`el-icon-${card.icon}`"></i>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="access-info">
|
|
|
|
|
|
<div class="access-title">{{ card.title }}</div>
|
|
|
|
|
|
<div class="access-desc">{{ card.desc }}</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="access-arrow">
|
|
|
|
|
|
<i class="el-icon-arrow-right"></i>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
2025-10-10 16:47:38 +08:00
|
|
|
|
</div>
|
2025-11-03 11:16:07 +08:00
|
|
|
|
</template>
|
2025-10-10 16:47:38 +08:00
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
import CurrentTime from "./components/CurrentTime.vue";
|
|
|
|
|
|
import HomeMain from "./components/HomeMain.vue";
|
|
|
|
|
|
import MiniTable from "./components/MiniTable.vue";
|
2026-01-04 15:07:47 +08:00
|
|
|
|
// 引入日志API / 生产相关API
|
2025-10-10 16:47:38 +08:00
|
|
|
|
import { getLogDataPage } from "@/api/l2/log";
|
|
|
|
|
|
import { getRollHistorytList } from '@/api/l2/roller'
|
|
|
|
|
|
import { listPlan } from "@/api/l2/plan";
|
2025-11-03 10:51:46 +08:00
|
|
|
|
import TrackMeasure from "@/components/TrackMeasure/index.vue";
|
2026-01-04 15:07:47 +08:00
|
|
|
|
import { getCurrentProducingPlan, getCurrentProcessParams } from "@/api/business/dashboard";
|
2025-10-10 16:47:38 +08:00
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
|
name: "Index",
|
2025-11-03 10:51:46 +08:00
|
|
|
|
components: { CurrentTime, HomeMain, MiniTable, TrackMeasure },
|
2025-10-10 16:47:38 +08:00
|
|
|
|
data() {
|
|
|
|
|
|
return {
|
2026-01-04 15:07:47 +08:00
|
|
|
|
// KPI指标数据
|
|
|
|
|
|
kpiData: [
|
|
|
|
|
|
{
|
|
|
|
|
|
label: '日产量',
|
|
|
|
|
|
value: '0',
|
|
|
|
|
|
unit: 't',
|
|
|
|
|
|
icon: 'el-icon-data-line',
|
|
|
|
|
|
trend: 'up',
|
|
|
|
|
|
change: '+5.2%'
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
label: '成材率',
|
|
|
|
|
|
value: '0',
|
|
|
|
|
|
unit: '%',
|
|
|
|
|
|
icon: 'el-icon-pie-chart',
|
|
|
|
|
|
trend: 'up',
|
|
|
|
|
|
change: '+1.8%'
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
label: '成品卷数',
|
|
|
|
|
|
value: '0',
|
|
|
|
|
|
unit: '卷',
|
|
|
|
|
|
icon: 'el-icon-box',
|
|
|
|
|
|
trend: 'up',
|
|
|
|
|
|
change: '+12'
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
label: '产线效率',
|
|
|
|
|
|
value: '0',
|
|
|
|
|
|
unit: '%',
|
|
|
|
|
|
icon: 'el-icon-cpu',
|
|
|
|
|
|
trend: 'down',
|
|
|
|
|
|
change: '-2.1%'
|
|
|
|
|
|
}
|
|
|
|
|
|
],
|
|
|
|
|
|
// 生产状态
|
|
|
|
|
|
productionStatus: {
|
|
|
|
|
|
type: 'success',
|
|
|
|
|
|
text: '运行中',
|
|
|
|
|
|
currentCoilId: '',
|
|
|
|
|
|
stripSpeed: '0',
|
|
|
|
|
|
efficiency: '0'
|
|
|
|
|
|
},
|
|
|
|
|
|
// 设备状态
|
|
|
|
|
|
equipmentStatus: [
|
|
|
|
|
|
{ name: '入口段', status: 'running', statusText: '运行中' },
|
|
|
|
|
|
{ name: '炉区', status: 'running', statusText: '运行中' },
|
|
|
|
|
|
{ name: '镀层段', status: 'running', statusText: '运行中' },
|
|
|
|
|
|
{ name: '出口段', status: 'running', statusText: '运行中' },
|
|
|
|
|
|
{ name: '张力控制', status: 'running', statusText: '运行中' },
|
|
|
|
|
|
{ name: '温度控制', status: 'running', statusText: '运行中' }
|
|
|
|
|
|
],
|
|
|
|
|
|
// 快速访问功能卡片
|
|
|
|
|
|
featureCards: [
|
|
|
|
|
|
{ title: "生产计划", desc: "生产计划管理", icon: "s-order", path: "/plan" },
|
|
|
|
|
|
{ title: "日志记录", desc: "日志记录管理", icon: "document", path: "/log" },
|
|
|
|
|
|
{ title: "轧辊管理", desc: "轧辊管理", icon: "setting", path: "/roller" },
|
|
|
|
|
|
{ title: "停机管理", desc: "停机管理", icon: "warning", path: "/stop" },
|
|
|
|
|
|
{ title: "过程跟踪", desc: "实时过程监控", icon: "monitor", path: "/track" },
|
|
|
|
|
|
{ title: "实绩数据", desc: "查看生产实绩数据", icon: "data-analysis", path: "/pdo" }
|
|
|
|
|
|
],
|
|
|
|
|
|
// 表格列配置(与日志字段对应)
|
|
|
|
|
|
alarmColumns: [
|
|
|
|
|
|
{ label: "发生时间", prop: "timestamp", width: "200px" },
|
|
|
|
|
|
{ label: "报警模块", prop: "module", width: "120px" },
|
|
|
|
|
|
{ label: "报警类型", prop: "logtype", width: "120px" },
|
|
|
|
|
|
{ label: "警报内容", prop: "logtext" },
|
|
|
|
|
|
],
|
|
|
|
|
|
rollHistoryColumns: [
|
|
|
|
|
|
{ label: "换辊号", prop: "changeid", width: "120px" },
|
|
|
|
|
|
{ label: "轧辊号", prop: "rollid", width: "120px" },
|
|
|
|
|
|
{ label: "机组", prop: "seton", width: "80px" },
|
|
|
|
|
|
{ label: "班次", prop: "shift", width: "80px" },
|
|
|
|
|
|
{ label: "班组", prop: "crew", width: "80px" },
|
|
|
|
|
|
{ label: "机架号", prop: "standid", width: "100px" },
|
|
|
|
|
|
{ label: "位置", prop: "position", width: "80px" },
|
|
|
|
|
|
{ label: '直径', prop: 'diameter', width: '100px' },
|
|
|
|
|
|
{ label: '粗糙度', prop: 'rough', width: '100px' },
|
|
|
|
|
|
{ label: '凸度', prop: 'crown', width: '100px' },
|
|
|
|
|
|
{ label: '成分', prop: 'composition', width: '100px' },
|
|
|
|
|
|
],
|
|
|
|
|
|
planColumns: [
|
|
|
|
|
|
{ label: '顺序号', prop: 'seqid', width: '80px' },
|
|
|
|
|
|
{ label: '钢卷号', prop: 'coilid', width: '120px' },
|
|
|
|
|
|
{ label: '机组号', prop: 'unitCode', width: '100px' },
|
|
|
|
|
|
{ label: '计划号', prop: 'planid', width: '120px' },
|
|
|
|
|
|
{ label: '计划类型', prop: 'planType', width: '100px' },
|
|
|
|
|
|
{ label: '钢种', prop: 'steelGrade', width: '120px' },
|
|
|
|
|
|
{ label: '出口卷号', prop: 'exitCoilid', width: '120px' },
|
|
|
|
|
|
{ label: '订单号', prop: 'orderNo', width: '120px' },
|
|
|
|
|
|
{ label: '客户代码', prop: 'custommerCode', width: '120px' },
|
|
|
|
|
|
{ label: '上线时间', prop: 'onlineDate', width: '160px' },
|
|
|
|
|
|
{ label: '开始时间', prop: 'startDate', width: '160px' },
|
|
|
|
|
|
{ label: '结束时间', prop: 'endDate', width: '160px' },
|
|
|
|
|
|
],
|
2025-10-10 16:47:38 +08:00
|
|
|
|
alarmData: [], // 表格数据(从API获取)
|
|
|
|
|
|
queryForm: { pageNum: 1, pageSize: 10 }, // 分页参数
|
|
|
|
|
|
tableLoading: false, // 加载状态
|
|
|
|
|
|
rollHistoryData: [], // 轧辊历史数据
|
|
|
|
|
|
rollHistoryLoading: false, // 轧辊历史数据加载状态
|
|
|
|
|
|
planData: [], // 生产计划数据
|
|
|
|
|
|
planLoading: false, // 生产计划数据加载状态
|
2026-01-04 15:07:47 +08:00
|
|
|
|
measureData: [], // 过程跟踪数据
|
|
|
|
|
|
measureLoading: false, // 过程跟踪加载状态
|
|
|
|
|
|
measureColumns: [] // 过程跟踪列配置
|
2025-10-10 16:47:38 +08:00
|
|
|
|
};
|
|
|
|
|
|
},
|
|
|
|
|
|
created() {
|
|
|
|
|
|
// 页面加载时调用API获取数据
|
|
|
|
|
|
this.getLogData();
|
|
|
|
|
|
this.getRollHistorytList();
|
|
|
|
|
|
this.getPlanList();
|
2026-01-04 15:07:47 +08:00
|
|
|
|
this.refreshDashboard();
|
|
|
|
|
|
// 定期刷新数据
|
|
|
|
|
|
this.refreshTimer = setInterval(() => {
|
|
|
|
|
|
this.getLogData();
|
|
|
|
|
|
this.getRollHistorytList();
|
|
|
|
|
|
this.getPlanList();
|
|
|
|
|
|
this.refreshDashboard();
|
|
|
|
|
|
}, 30000); // 每30秒刷新一次
|
|
|
|
|
|
},
|
|
|
|
|
|
beforeDestroy() {
|
|
|
|
|
|
// 组件销毁时清除定时器
|
|
|
|
|
|
if (this.refreshTimer) {
|
|
|
|
|
|
clearInterval(this.refreshTimer);
|
|
|
|
|
|
}
|
2025-10-10 16:47:38 +08:00
|
|
|
|
},
|
|
|
|
|
|
methods: {
|
2026-01-04 15:07:47 +08:00
|
|
|
|
// 获取日志数据
|
2025-10-10 16:47:38 +08:00
|
|
|
|
getLogData() {
|
|
|
|
|
|
this.tableLoading = true;
|
|
|
|
|
|
getLogDataPage(this.queryForm)
|
|
|
|
|
|
.then((response) => {
|
|
|
|
|
|
this.tableLoading = false;
|
2026-01-04 15:07:47 +08:00
|
|
|
|
this.alarmData = response.data.list || []; // 赋值表格数据
|
2025-10-10 16:47:38 +08:00
|
|
|
|
})
|
|
|
|
|
|
.catch((error) => {
|
|
|
|
|
|
this.tableLoading = false;
|
2026-01-04 15:07:47 +08:00
|
|
|
|
console.error("获取日志数据失败:", error);
|
|
|
|
|
|
this.$message.error("获取日志数据失败,请稍后重试");
|
2025-10-10 16:47:38 +08:00
|
|
|
|
});
|
|
|
|
|
|
},
|
2026-01-04 15:07:47 +08:00
|
|
|
|
// 获取轧辊历史列表
|
2025-10-10 16:47:38 +08:00
|
|
|
|
getRollHistorytList() {
|
2026-01-04 15:07:47 +08:00
|
|
|
|
this.rollHistoryLoading = true;
|
2025-10-10 16:47:38 +08:00
|
|
|
|
getRollHistorytList(this.queryForm)
|
|
|
|
|
|
.then((response) => {
|
|
|
|
|
|
this.rollHistoryLoading = false;
|
2026-01-04 15:07:47 +08:00
|
|
|
|
this.rollHistoryData = response.data.list || []; // 赋值表格数据
|
2025-10-10 16:47:38 +08:00
|
|
|
|
})
|
2026-01-04 15:07:47 +08:00
|
|
|
|
.catch((error) => {
|
|
|
|
|
|
this.rollHistoryLoading = false;
|
|
|
|
|
|
console.error("获取轧辊历史数据失败:", error);
|
|
|
|
|
|
});
|
2025-10-10 16:47:38 +08:00
|
|
|
|
},
|
2026-01-04 15:07:47 +08:00
|
|
|
|
// 获取生产计划列表
|
2025-10-10 16:47:38 +08:00
|
|
|
|
getPlanList() {
|
2026-01-04 15:07:47 +08:00
|
|
|
|
this.planLoading = true;
|
2025-10-10 16:47:38 +08:00
|
|
|
|
listPlan(this.queryForm)
|
|
|
|
|
|
.then((response) => {
|
|
|
|
|
|
this.planLoading = false;
|
2026-01-04 15:07:47 +08:00
|
|
|
|
this.planData = (response.data || []).map(item => {
|
2025-10-10 16:47:38 +08:00
|
|
|
|
return {
|
|
|
|
|
|
...item,
|
|
|
|
|
|
onlineDate: item.onlineDate?.replace('T', ' '),
|
|
|
|
|
|
startDate: item.startDate?.replace('T', ' '),
|
|
|
|
|
|
endDate: item.endDate?.replace('T', ' '),
|
|
|
|
|
|
furInDate: item.furInDate?.replace('T', ' '),
|
|
|
|
|
|
furOutDate: item.furOutDate?.replace('T', ' '),
|
|
|
|
|
|
}
|
|
|
|
|
|
}); // 赋值表格数据
|
|
|
|
|
|
})
|
2026-01-04 15:07:47 +08:00
|
|
|
|
.catch((error) => {
|
|
|
|
|
|
this.planLoading = false;
|
|
|
|
|
|
console.error("获取计划数据失败:", error);
|
|
|
|
|
|
});
|
|
|
|
|
|
},
|
|
|
|
|
|
// 从后端刷新首页仪表板数据
|
|
|
|
|
|
refreshDashboard() {
|
|
|
|
|
|
// 1) 当前生产计划
|
|
|
|
|
|
getCurrentProducingPlan().then(res => {
|
|
|
|
|
|
const data = res.data || {};
|
|
|
|
|
|
// 更新生产状态中的卷号等信息
|
|
|
|
|
|
this.productionStatus.currentCoilId = data.coilid || '';
|
|
|
|
|
|
// 这里可以根据需要扩展更多字段,例如钢种、入口规格等
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 2) 当前生产卷的工艺参数
|
|
|
|
|
|
getCurrentProcessParams().then(res => {
|
|
|
|
|
|
const data = res.data || {};
|
|
|
|
|
|
// 带钢速度示例:优先取出口段TR的speedExitSection,其次取入口段POR1/POR2的stripSpeed
|
|
|
|
|
|
let stripSpeed = 0;
|
|
|
|
|
|
const exit = data.exitSection || {};
|
|
|
|
|
|
const entry = data.entrySection || {};
|
|
|
|
|
|
|
|
|
|
|
|
if (exit.TR && (exit.TR.speedExitSection || exit.TR.stripSpeed)) {
|
|
|
|
|
|
stripSpeed = exit.TR.speedExitSection || exit.TR.stripSpeed;
|
|
|
|
|
|
} else if (entry.POR1 && entry.POR1.stripSpeed) {
|
|
|
|
|
|
stripSpeed = entry.POR1.stripSpeed;
|
|
|
|
|
|
} else if (entry.POR2 && entry.POR2.stripSpeed) {
|
|
|
|
|
|
stripSpeed = entry.POR2.stripSpeed;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
this.productionStatus.stripSpeed = stripSpeed || 0;
|
|
|
|
|
|
|
|
|
|
|
|
// 产线效率目前后端没有直接指标,可根据需要后续扩展,这里先保持0或从其他接口获取
|
|
|
|
|
|
// this.productionStatus.efficiency = ...;
|
|
|
|
|
|
|
|
|
|
|
|
// KPI 区域暂时用真实卷号和速度填充一部分,其他可根据后端需要扩展
|
|
|
|
|
|
this.kpiData[0].value = (stripSpeed || 0).toFixed(1); // 用带钢速度临时占位,后续可改为产量
|
|
|
|
|
|
this.kpiData[1].value = '0';
|
|
|
|
|
|
this.kpiData[2].value = '0';
|
|
|
|
|
|
this.kpiData[3].value = this.productionStatus.efficiency || '0';
|
|
|
|
|
|
});
|
2025-10-10 16:47:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
};
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
2026-01-04 15:07:47 +08:00
|
|
|
|
/* 主题色与布局样式 */
|
2025-10-10 16:47:38 +08:00
|
|
|
|
$theme-primary: #a7acb4;
|
|
|
|
|
|
$theme-light: rgba(167, 172, 180, 0.8);
|
|
|
|
|
|
$theme-dark: rgba(140, 145, 153, 0.8);
|
|
|
|
|
|
$theme-bg1: #454c51;
|
|
|
|
|
|
$theme-bg2: #454c51;
|
|
|
|
|
|
$theme-bg3: #1E2227;
|
|
|
|
|
|
$theme-text-light: #f0f0f0;
|
|
|
|
|
|
$theme-text-gray: #c9cdcf;
|
2026-01-04 15:07:47 +08:00
|
|
|
|
|
|
|
|
|
|
.industrial-dashboard {
|
|
|
|
|
|
padding: 20px;
|
|
|
|
|
|
background: #f2f3f5; // 工业风浅灰背景,避免过深色
|
|
|
|
|
|
min-height: calc(100vh - 60px);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 仪表板头部 */
|
|
|
|
|
|
.dashboard-header {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
padding: 20px;
|
|
|
|
|
|
background: #ffffff; // 简洁白色背景,避免低级渐变色
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
|
|
|
|
|
|
|
|
|
|
.header-left {
|
|
|
|
|
|
.system-title {
|
|
|
|
|
|
color: #000;
|
|
|
|
|
|
font-size: 28px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
margin: 0 0 8px 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.system-subtitle {
|
|
|
|
|
|
color: #000;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* KPI区域 */
|
|
|
|
|
|
.kpi-section {
|
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
|
|
|
|
|
|
.kpi-card {
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
|
transform: translateY(-4px);
|
|
|
|
|
|
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.kpi-content {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding: 10px 0;
|
|
|
|
|
|
|
|
|
|
|
|
.kpi-icon {
|
|
|
|
|
|
font-size: 40px;
|
|
|
|
|
|
margin-right: 16px;
|
|
|
|
|
|
color: #409eff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.kpi-info {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
|
|
|
|
|
|
.kpi-label {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: #909399;
|
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.kpi-value {
|
|
|
|
|
|
font-size: 28px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
line-height: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.kpi-unit {
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
color: #909399;
|
|
|
|
|
|
margin-top: 4px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.kpi-trend {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
padding: 4px 8px;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
|
|
|
|
|
|
&.up {
|
|
|
|
|
|
color: #67c23a;
|
|
|
|
|
|
background: rgba(103, 194, 58, 0.1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.down {
|
|
|
|
|
|
color: #f56c6c;
|
|
|
|
|
|
background: rgba(245, 108, 108, 0.1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
i {
|
|
|
|
|
|
margin-right: 4px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.kpi-0 .kpi-icon { color: #409eff; }
|
|
|
|
|
|
&.kpi-1 .kpi-icon { color: #67c23a; }
|
|
|
|
|
|
&.kpi-2 .kpi-icon { color: #e6a23c; }
|
|
|
|
|
|
&.kpi-3 .kpi-icon { color: #f56c6c; }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 状态区域 */
|
|
|
|
|
|
.status-section {
|
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
|
|
|
|
|
|
.status-card {
|
|
|
|
|
|
.card-header {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.status-content {
|
|
|
|
|
|
padding: 10px 0;
|
|
|
|
|
|
|
|
|
|
|
|
.status-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
padding: 12px 0;
|
|
|
|
|
|
border-bottom: 1px solid #ebeef5;
|
|
|
|
|
|
|
|
|
|
|
|
&:last-child {
|
|
|
|
|
|
border-bottom: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.status-label {
|
|
|
|
|
|
color: #909399;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.status-value {
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.equipment-grid {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: repeat(3, 1fr);
|
|
|
|
|
|
gap: 16px;
|
|
|
|
|
|
padding: 10px 0;
|
|
|
|
|
|
|
|
|
|
|
|
.equipment-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding: 12px;
|
|
|
|
|
|
background: #f5f7fa;
|
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
|
background: #ecf5ff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.equipment-name {
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
color: #606266;
|
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 表格区域 */
|
|
|
|
|
|
.table-section {
|
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
|
|
|
|
|
|
.card-header {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
|
|
|
|
|
|
.alarm-badge {
|
|
|
|
|
|
margin-left: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 快速访问区域 */
|
|
|
|
|
|
.quick-access-section {
|
|
|
|
|
|
.quick-access-grid {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: repeat(3, 1fr);
|
|
|
|
|
|
gap: 16px;
|
|
|
|
|
|
padding: 10px 0;
|
|
|
|
|
|
|
|
|
|
|
|
.access-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding: 16px;
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
border: 1px solid #ebeef5;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
|
border-color: #409eff;
|
|
|
|
|
|
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.15);
|
|
|
|
|
|
transform: translateY(-2px);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.access-icon {
|
|
|
|
|
|
font-size: 32px;
|
|
|
|
|
|
color: #409eff;
|
|
|
|
|
|
margin-right: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.access-info {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
|
|
|
|
|
|
.access-title {
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
margin-bottom: 4px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.access-desc {
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
color: #909399;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.access-arrow {
|
|
|
|
|
|
color: #c0c4cc;
|
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 响应式设计 */
|
|
|
|
|
|
@media (max-width: 1200px) {
|
|
|
|
|
|
.quick-access-grid {
|
|
|
|
|
|
grid-template-columns: repeat(2, 1fr) !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@media (max-width: 768px) {
|
|
|
|
|
|
.kpi-section .el-col {
|
|
|
|
|
|
margin-bottom: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.status-section .el-col {
|
|
|
|
|
|
margin-bottom: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.equipment-grid {
|
|
|
|
|
|
grid-template-columns: repeat(2, 1fr) !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.quick-access-grid {
|
|
|
|
|
|
grid-template-columns: 1fr !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.dashboard-header {
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
|
|
|
|
|
|
.header-right {
|
|
|
|
|
|
margin-top: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-10-10 16:47:38 +08:00
|
|
|
|
</style>
|