style+feat: 金属灰深蓝工业主题 + 紧凑组件 + 工业控制首页

- 主题色:深钢蓝#1c2b3a侧边栏 + 金属灰#607d8b + 海军蓝#1d4e89主色
- 去除所有绿色,成功态改用钢蓝
- 全局组件缩小:输入框28px/按钮12px/表格行5px/表单间距12px
- 新首页:状态栏+KPI卡片+双机架工艺参数+计划表+L2/L3通信状态

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-28 13:37:01 +08:00
parent 8ce9489c92
commit ffe3a0e612
5 changed files with 571 additions and 276 deletions

View File

@@ -1,169 +1,366 @@
<template>
<div class="app-container home">
<el-row :gutter="20">
<el-col :xs="24" :sm="24" :md="12" :lg="14">
<el-card class="update-log">
<div slot="header" class="clearfix">
<span>联系信息</span>
<div class="mill-dashboard">
<!-- 顶部状态栏 -->
<div class="status-bar">
<div class="status-bar__left">
<span class="system-name">冷轧双机架二级控制系统</span>
<span class="divider">|</span>
<span class="unit-tag">2FK 机组</span>
</div>
<div class="status-bar__right">
<span class="sys-status online">
<i class="el-icon-connection"></i> 系统在线
</span>
<span class="clock">{{ currentTime }}</span>
</div>
</div>
<!-- KPI 汇总卡片 -->
<el-row :gutter="12" class="kpi-row">
<el-col :span="6" v-for="kpi in kpiList" :key="kpi.label">
<div class="kpi-card">
<div class="kpi-card__icon" :style="{ background: kpi.color }">
<i :class="kpi.icon"></i>
</div>
<div class="body">
<p>
<i class="el-icon-user-solid"></i> QQ群
<a href="https://jq.qq.com/?_wv=1027&k=2zE87c2G" target="_blank"
> 782924350</a
>
</p>
<p>
<i class="el-icon-chat-dot-round"></i> 微信<a
>Almost-2y</a
>
</p>
<p style="color: #f54a4a;font-size:16px">
<i class="el-icon-bell"></i> 说明<a
>技术咨询业务定制等其它支持可添加 微信: Almost-2y / QQ: 846249920 进行沟通交流</a
>
</p>
<p>
<i class="el-icon-shopping-bag-2"></i> 腾讯云秒杀<a style="color: #365be4" href="https://curl.qcloud.com/W5KFkBG4" target="_blank"
>点我进入</a>
</p>
<p>
<i class="el-icon-shopping-bag-2"></i> 腾讯云服务器<a style="color: #365be4" href="https://curl.qcloud.com/AacfyRxq" target="_blank"
>点我进入</a>
</p>
<p>
<i class="el-icon-shopping-bag-2"></i> 阿里云优惠<a style="color: #365be4" href="https://www.aliyun.com/activity/daily/bestoffer?userCode=q2b8atsa" target="_blank"
>点我进入</a>
</p>
<p>
<i class="el-icon-shopping-bag-2"></i> 阿里云服务器<a style="color: #365be4" href="https://www.aliyun.com/daily-act/ecs/activity_selection?userCode=q2b8atsa" target="_blank"
>点我进入</a>
</p>
<div class="kpi-card__body">
<div class="kpi-card__value">{{ kpi.value }}</div>
<div class="kpi-card__label">{{ kpi.label }}</div>
</div>
</el-card>
</el-col>
<el-col :xs="24" :sm="24" :md="12" :lg="10">
<el-card class="update-log">
<div slot="header" class="clearfix">
<span>捐赠支持</span>
</div>
<div class="body">
<img
src="https://foruda.gitee.com/images/1672215449995765124/596b46c3_2042292.png"
alt="donate"
width="100%"
/>
<span style="display: inline-block; height: 30px; line-height: 30px"
>可以请作者喝杯咖啡以示鼓励</span
>
</div>
</el-card>
</div>
</el-col>
</el-row>
<el-divider />
<el-row :gutter="20">
<el-col :xs="24" :sm="24" :md="12" :lg="8">
<el-card class="update-log">
<div slot="header" class="clearfix">
<span>流程功能列表</span>
<!-- 机架状态 + 工艺参数 -->
<el-row :gutter="12" class="stand-row">
<el-col :span="12" v-for="stand in stands" :key="stand.name">
<div class="stand-card">
<div class="stand-card__header">
<span class="stand-name">{{ stand.name }}</span>
<span :class="['stand-badge', stand.running ? 'running' : 'stopped']">
{{ stand.running ? '▶ 运行中' : '■ 停机' }}
</span>
</div>
<p>1.单节点配置表单</p>
<p>2.多实例会签任务</p>
<p>3.节点任务/执行监听器</p>
<p>4.动态配置任务候选人</p>
<p>5.其它模块优化</p>
</el-card>
</el-col>
<el-col :xs="24" :sm="24" :md="12" :lg="16">
<el-card class="update-log">
<div slot="header" class="clearfix">
<span>流程演示</span>
<div class="stand-card__params">
<div class="param-item" v-for="p in stand.params" :key="p.label">
<span class="param-label">{{ p.label }}</span>
<span class="param-val">{{ p.value }}</span>
<span class="param-u">{{ p.unit }}</span>
</div>
</div>
<img style="width: 850px" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f248dea817f74341b70f4087f425975b~tplv-k3u1fbpfcp-watermark.image?"/>
</el-card>
<div class="stand-card__footer">
<span>当前卷号<b>{{ stand.coilNo }}</b></span>
<span>钢种<b>{{ stand.steelGrade }}</b></span>
<span>班次<b>{{ stand.shift }}</b></span>
</div>
</div>
</el-col>
</el-row>
<!-- 最近生产计划 & 通信状态 -->
<el-row :gutter="12" class="bottom-row">
<el-col :span="17">
<div class="table-card">
<div class="table-card__header">
<span><i class="el-icon-document"></i> 近期生产计划</span>
<el-button type="primary" size="mini" @click="$router.push('/mill/plan')">查看全部</el-button>
</div>
<el-table :data="planList" size="mini" stripe border style="width:100%">
<el-table-column prop="planNo" label="计划号" width="130" />
<el-table-column prop="inMatNo" label="入口钢卷号" width="130" />
<el-table-column prop="sgSign" label="钢种" width="80" />
<el-table-column prop="inMatThick" label="目标厚度(mm)" width="100" align="right" />
<el-table-column prop="inMatWidth" label="宽度(mm)" width="90" align="right" />
<el-table-column prop="planStatus" label="状态" width="80" align="center">
<template slot-scope="{ row }">
<el-tag :type="statusType(row.planStatus)" size="mini">{{ statusText(row.planStatus) }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" min-width="130" />
</el-table>
</div>
</el-col>
<el-col :span="7">
<div class="comm-card">
<div class="table-card__header">
<span><i class="el-icon-cpu"></i> L2/L3 通信状态</span>
</div>
<div class="comm-item" v-for="c in commStatus" :key="c.label">
<span class="comm-label">{{ c.label }}</span>
<span :class="['comm-dot', c.ok ? 'ok' : 'err']"></span>
<span :class="['comm-state', c.ok ? 'ok' : 'err']">{{ c.ok ? '正常' : '断开' }}</span>
<span class="comm-time">{{ c.lastTime }}</span>
</div>
</div>
</el-col>
</el-row>
</div>
</template>
<script>
export default {
name: "index",
name: 'MillDashboard',
data() {
return {
// 版本号
version: "3.4.0",
};
currentTime: '',
timer: null,
kpiList: [
{ label: '今日计划数', value: 24, icon: 'el-icon-document', color: '#1d4e89' },
{ label: '已完成', value: 18, icon: 'el-icon-circle-check', color: '#2471a3' },
{ label: '在产中', value: 2, icon: 'el-icon-loading', color: '#d68910' },
{ label: '异常/待处理', value: 1, icon: 'el-icon-warning-outline', color: '#c0392b' }
],
stands: [
{
name: '1# 机架(入口机架)',
running: true,
coilNo: 'C2026042800012',
steelGrade: 'DC04',
shift: '甲班',
params: [
{ label: '入口厚度', value: '2.500', unit: 'mm' },
{ label: '出口厚度', value: '1.800', unit: 'mm' },
{ label: '轧制速度', value: '380', unit: 'm/min' },
{ label: '轧制力', value: '12400', unit: 'kN' },
{ label: '前张力', value: '85.0', unit: 'kN' },
{ label: '后张力', value: '92.0', unit: 'kN' }
]
},
{
name: '2# 机架(出口机架)',
running: true,
coilNo: 'C2026042800012',
steelGrade: 'DC04',
shift: '甲班',
params: [
{ label: '入口厚度', value: '1.800', unit: 'mm' },
{ label: '出口厚度', value: '0.800', unit: 'mm' },
{ label: '轧制速度', value: '855', unit: 'm/min' },
{ label: '轧制力', value: '9800', unit: 'kN' },
{ label: '前张力', value: '110.0', unit: 'kN' },
{ label: '后张力', value: '85.0', unit: 'kN' }
]
}
],
planList: [
{ planNo: 'P20260428001', inMatNo: 'C2026042800012', sgSign: 'DC04', inMatThick: '2.500', inMatWidth: '1250', planStatus: 1, createTime: '2026-04-28 08:00:10' },
{ planNo: 'P20260428002', inMatNo: 'C2026042800013', sgSign: 'SPCC', inMatThick: '2.000', inMatWidth: '1000', planStatus: 0, createTime: '2026-04-28 08:01:05' },
{ planNo: 'P20260428003', inMatNo: 'C2026042800014', sgSign: 'DC01', inMatThick: '2.800', inMatWidth: '1100', planStatus: 0, createTime: '2026-04-28 08:01:30' },
{ planNo: 'P20260427021', inMatNo: 'C2026042700085', sgSign: 'DC04', inMatThick: '3.000', inMatWidth: '1250', planStatus: 2, createTime: '2026-04-27 21:15:00' },
{ planNo: 'P20260427020', inMatNo: 'C2026042700084', sgSign: 'SPCE', inMatThick: '2.500', inMatWidth: '900', planStatus: 2, createTime: '2026-04-27 20:50:00' }
],
commStatus: [
{ label: 'L3→L2 作业命令', ok: true, lastTime: '13:24:08' },
{ label: 'L2→L3 计划应答', ok: true, lastTime: '13:24:09' },
{ label: 'L2→L3 产出信息', ok: true, lastTime: '13:20:33' },
{ label: 'L3→L2 产出应答', ok: false, lastTime: '12:58:01' }
]
}
},
mounted() {
this.updateTime()
this.timer = setInterval(this.updateTime, 1000)
},
beforeDestroy() {
clearInterval(this.timer)
},
methods: {
goTarget(href) {
window.open(href, "_blank");
updateTime() {
const now = new Date()
const pad = n => String(n).padStart(2, '0')
this.currentTime = `${now.getFullYear()}-${pad(now.getMonth()+1)}-${pad(now.getDate())} ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`
},
},
};
</script>
<style scoped lang="scss">
.home {
blockquote {
padding: 10px 20px;
margin: 0 0 20px;
font-size: 17.5px;
border-left: 5px solid #eee;
}
hr {
margin-top: 20px;
margin-bottom: 20px;
border: 0;
border-top: 1px solid #eee;
}
.col-item {
margin-bottom: 20px;
}
ul {
padding: 0;
margin: 0;
}
font-family: "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 13px;
color: #676a6c;
overflow-x: hidden;
ul {
list-style-type: none;
}
h4 {
margin-top: 0px;
}
h2 {
margin-top: 10px;
font-size: 26px;
font-weight: 100;
}
p {
margin-top: 10px;
b {
font-weight: 700;
}
}
.update-log {
ol {
display: block;
list-style-type: decimal;
margin-block-start: 1em;
margin-block-end: 1em;
margin-inline-start: 0;
margin-inline-end: 0;
padding-inline-start: 40px;
statusText(s) {
return { 0: '待生产', 1: '生产中', 2: '已完成', 3: '已撤销' }[s] || '-'
},
statusType(s) {
return { 0: 'info', 1: 'warning', 2: '', 3: 'danger' }[s] || 'info'
}
}
}
</style>
</script>
<style scoped lang="scss">
.mill-dashboard {
padding: 12px 16px;
background: #f0f2f5;
min-height: 100%;
font-size: 12px;
color: #2c3e50;
}
/* ── 顶部状态栏 ── */
.status-bar {
display: flex;
align-items: center;
justify-content: space-between;
background: #1c2b3a;
color: #ecf0f1;
padding: 0 16px;
height: 36px;
border-radius: 3px;
margin-bottom: 12px;
font-size: 12px;
&__left {
display: flex;
align-items: center;
gap: 10px;
}
&__right {
display: flex;
align-items: center;
gap: 16px;
}
}
.system-name { font-weight: 700; font-size: 13px; letter-spacing: .5px; }
.divider { color: #4a6275; }
.unit-tag { background: #1d4e89; padding: 1px 8px; border-radius: 2px; font-size: 11px; }
.sys-status { font-size: 11px; &.online { color: #7fb3d3; } }
.clock { font-family: 'Courier New', monospace; font-size: 12px; color: #aab7c4; }
/* ── KPI 卡片 ── */
.kpi-row { margin-bottom: 12px; }
.kpi-card {
background: #ffffff;
border: 1px solid #dde1e6;
border-radius: 3px;
padding: 12px;
display: flex;
align-items: center;
gap: 12px;
box-shadow: 0 1px 4px rgba(0,0,0,.05);
&__icon {
width: 42px; height: 42px;
border-radius: 4px;
display: flex; align-items: center; justify-content: center;
font-size: 18px; color: #ffffff;
flex-shrink: 0;
}
&__value {
font-size: 24px; font-weight: 700;
color: #1c2b3a; line-height: 1;
font-family: 'Courier New', monospace;
}
&__label {
font-size: 11px; color: #7f8c8d;
margin-top: 3px;
}
}
/* ── 机架状态卡片 ── */
.stand-row { margin-bottom: 12px; }
.stand-card {
background: #ffffff;
border: 1px solid #dde1e6;
border-radius: 3px;
box-shadow: 0 1px 4px rgba(0,0,0,.05);
overflow: hidden;
&__header {
background: #1c2b3a;
color: #ecf0f1;
padding: 7px 12px;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 12px;
font-weight: 700;
}
&__params {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1px;
background: #e4e7ed;
border-bottom: 1px solid #e4e7ed;
}
&__footer {
padding: 6px 12px;
font-size: 11px;
color: #606266;
display: flex;
gap: 20px;
background: #fafafa;
b { color: #1c2b3a; }
}
}
.stand-name { letter-spacing: .5px; }
.stand-badge {
font-size: 11px; padding: 2px 8px;
border-radius: 2px; font-weight: 600;
&.running { background: #1d4e89; color: #fff; }
&.stopped { background: #c0392b; color: #fff; }
}
.param-item {
background: #ffffff;
padding: 7px 10px;
display: flex;
align-items: baseline;
gap: 4px;
}
.param-label {
font-size: 11px; color: #7f8c8d;
min-width: 52px; flex-shrink: 0;
}
.param-val {
font-family: 'Courier New', monospace;
font-size: 15px; font-weight: 700;
color: #1d4e89;
}
.param-u { font-size: 10px; color: #95a5a6; }
/* ── 底部表格 & 通信状态 ── */
.bottom-row {}
.table-card, .comm-card {
background: #ffffff;
border: 1px solid #dde1e6;
border-radius: 3px;
box-shadow: 0 1px 4px rgba(0,0,0,.05);
overflow: hidden;
}
.table-card__header {
background: #f7f9fc;
border-bottom: 1px solid #e4e7ed;
padding: 7px 12px;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 12px;
font-weight: 600;
color: #1c2b3a;
}
/* 通信状态 */
.comm-item {
display: flex;
align-items: center;
padding: 7px 12px;
border-bottom: 1px solid #f0f2f5;
font-size: 11px;
gap: 6px;
&:last-child { border-bottom: none; }
}
.comm-label { flex: 1; color: #4a5568; }
.comm-dot {
width: 7px; height: 7px; border-radius: 50%;
&.ok { background: #2471a3; box-shadow: 0 0 4px #2471a3; }
&.err { background: #c0392b; box-shadow: 0 0 4px #c0392b; animation: alarmBlink 1.2s infinite; }
}
.comm-state {
font-weight: 600; width: 28px;
&.ok { color: #2471a3; }
&.err { color: #c0392b; }
}
.comm-time { color: #95a5a6; font-family: 'Courier New', monospace; font-size: 11px; }
@keyframes alarmBlink { 0%,100%{opacity:1} 50%{opacity:.2} }
</style>