style: 西门子 WinCC 工业风格重设计

- 左侧边栏导航替换顶部横向导航
- 色调改为石油蓝绿(#00a3be),去除霓虹蓝
- 卡片头部加左侧色带 accent,去除圆角
- Badge 改为矩形工业风,全大写标签
- 按钮、输入框统一 2px radius
- 导航图标改为 SVG 几何图形替代纯文字缩写
This commit is contained in:
2026-05-27 16:52:53 +08:00
parent 193da0018f
commit d4f334761f
3 changed files with 388 additions and 239 deletions

View File

@@ -14,19 +14,21 @@
--accent-yellow: #{$accent-yellow}; --accent-yellow: #{$accent-yellow};
--accent-red: #{$accent-red}; --accent-red: #{$accent-red};
--accent-cyan: #{$accent-cyan}; --accent-cyan: #{$accent-cyan};
--sms-teal: #{$sms-teal};
--sms-blue: #{$sms-blue}; --sms-blue: #{$sms-blue};
--sms-highlight: #{$sms-highlight};
--status-run: #{$status-run}; --status-run: #{$status-run};
--status-warn: #{$status-warn}; --status-warn: #{$status-warn};
--status-fault: #{$status-fault}; --status-fault: #{$status-fault};
--font-mono: #{$font-mono}; --font-mono: #{$font-mono};
// 向后兼容旧变量名
--sms-highlight: #{$sms-teal};
} }
* { box-sizing: border-box; margin: 0; padding: 0; } * { box-sizing: border-box; margin: 0; padding: 0; }
body { body {
font-family: $font-main; font-family: $font-main;
background: $bg-primary; background: $bg-base;
color: $text-primary; color: $text-primary;
font-size: 13px; font-size: 13px;
} }
@@ -35,54 +37,59 @@ body {
.card { .card {
background: $bg-card; background: $bg-card;
border: 1px solid $border; border: 1px solid $border;
border-radius: 6px; border-radius: 2px;
overflow: hidden; overflow: hidden;
&-header { &-header {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; gap: 8px;
padding: 8px 14px; padding: 7px 12px;
background: $bg-panel; background: $bg-panel;
border-bottom: 1px solid $border; border-bottom: 1px solid $border;
font-size: 12px; border-left: 3px solid $sms-teal;
font-weight: 600; font-size: 11px;
color: $sms-highlight; font-weight: 700;
letter-spacing: .4px; color: $text-primary;
letter-spacing: .6px;
text-transform: uppercase;
.ch-badge { .ch-badge {
margin-left: auto; margin-left: auto;
font-size: 10px; font-size: 10px;
padding: 1px 8px; padding: 1px 6px;
border-radius: 8px; border-radius: 1px;
background: rgba(0,200,255,.1); background: rgba($sms-teal, .12);
color: $sms-highlight; color: $sms-teal;
border: 1px solid rgba(0,200,255,.3); border: 1px solid rgba($sms-teal, .3);
font-weight: 600;
letter-spacing: .4px;
} }
} }
&-body { padding: 12px 14px; } &-body { padding: 12px; }
} }
// ─── 指标卡 ─── // ─── 指标卡 ───
.metric-box { .metric-box {
background: $bg-panel; background: $bg-panel;
border: 1px solid $border; border: 1px solid $border;
border-radius: 5px; border-top: 2px solid $sms-teal;
padding: 10px 14px; border-radius: 2px;
padding: 10px 12px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 4px; gap: 4px;
.mb-label { font-size: 11px; color: $text-secondary; } .mb-label { font-size: 10px; color: $text-secondary; text-transform: uppercase; letter-spacing: .5px; }
.mb-value { .mb-value {
font-size: 22px; font-size: 24px;
font-family: $font-mono; font-family: $font-mono;
font-weight: 700; font-weight: 700;
color: $sms-highlight; color: $sms-teal;
line-height: 1; line-height: 1.1;
} }
.mb-unit { font-size: 11px; color: $text-muted; } .mb-unit { font-size: 10px; color: $text-muted; }
} }
// ─── 数据表格 ─── // ─── 数据表格 ───
@@ -92,25 +99,29 @@ body {
font-size: 12px; font-size: 12px;
th { th {
background: $bg-panel; background: $bg-secondary;
color: $text-secondary; color: $text-secondary;
font-weight: 600; font-weight: 700;
padding: 7px 10px; padding: 6px 10px;
text-align: left; text-align: left;
border-bottom: 1px solid $border; border-bottom: 1px solid $border-light;
white-space: nowrap; white-space: nowrap;
text-transform: uppercase;
font-size: 10px;
letter-spacing: .5px;
} }
td { td {
padding: 6px 10px; padding: 6px 10px;
border-bottom: 1px solid rgba(48,54,61,.5); border-bottom: 1px solid $border;
color: $text-primary; color: $text-primary;
font-family: $font-mono; font-family: $font-mono;
font-size: 12px;
} }
tr:hover td { background: rgba(255,255,255,.02); } tr:hover td { background: rgba($sms-teal, .04); }
.td-num { color: $sms-highlight; } .td-num { color: $sms-teal; }
.td-ok { color: $accent-green; } .td-ok { color: $accent-green; }
.td-warn { color: $accent-yellow; } .td-warn { color: $accent-yellow; }
.td-err { color: $accent-red; } .td-err { color: $accent-red; }
@@ -119,87 +130,119 @@ body {
.table-scroll { .table-scroll {
overflow-x: auto; overflow-x: auto;
&::-webkit-scrollbar { height: 4px; } &::-webkit-scrollbar { height: 3px; }
&::-webkit-scrollbar-thumb { background: $border; } &::-webkit-scrollbar-thumb { background: $border-light; }
} }
// ─── Badge ─── // ─── Badge ───
.badge { .badge {
display: inline-block; display: inline-block;
padding: 1px 8px; padding: 1px 7px;
border-radius: 8px; border-radius: 1px;
font-size: 11px; font-size: 10px;
font-weight: 600; font-weight: 700;
letter-spacing: .4px;
text-transform: uppercase;
&-green { background: #1a3a1f; color: $accent-green; border: 1px solid $accent-green; } &-green { background: rgba($accent-green, .15); color: $accent-green; border-left: 2px solid $accent-green; }
&-yellow { background: #3a2a00; color: $accent-yellow; border: 1px solid $accent-yellow; } &-yellow { background: rgba($accent-yellow,.15); color: $accent-yellow; border-left: 2px solid $accent-yellow; }
&-red { background: #3a0a0a; color: $accent-red; border: 1px solid $accent-red; } &-red { background: rgba($accent-red, .15); color: $accent-red; border-left: 2px solid $accent-red; }
&-blue { background: rgba(0,120,212,.15); color: $sms-highlight; border: 1px solid rgba(0,200,255,.3); } &-blue { background: rgba($sms-teal, .15); color: $sms-teal; border-left: 2px solid $sms-teal; }
&-gray { background: #222; color: $text-muted; border: 1px solid $border; } &-gray { background: rgba($text-muted, .1); color: $text-muted; border-left: 2px solid $text-muted; }
} }
// ─── 按钮 ─── // ─── 按钮 ───
.btn { .btn {
padding: 5px 14px; padding: 4px 14px;
border-radius: 4px; border-radius: 2px;
border: 1px solid; border: 1px solid;
font-size: 12px; font-size: 11px;
font-weight: 600; font-weight: 700;
cursor: pointer; cursor: pointer;
transition: all .15s; transition: all .12s;
user-select: none; user-select: none;
font-family: $font-main; font-family: $font-main;
letter-spacing: .3px;
text-transform: uppercase;
&-primary { background: $sms-blue; border-color: $sms-blue; color: #fff; &:hover { background: #1086e0; } } &-primary {
&-success { background: #1a3a1f; border-color: $accent-green; color: $accent-green; &:hover { background: $accent-green; color: #000; } } background: $sms-blue;
&-danger { background: #3a0a0a; border-color: $accent-red; color: $accent-red; } border-color: $sms-blue;
&-outline { background: transparent; border-color: $border; color: $text-secondary; &:hover { border-color: $sms-highlight; color: $sms-highlight; } } color: #fff;
&:hover { background: lighten($sms-blue, 8%); }
&:disabled { opacity: .5; cursor: not-allowed; }
}
&-success {
background: rgba($accent-green, .12);
border-color: $accent-green;
color: $accent-green;
&:hover { background: rgba($accent-green, .22); }
}
&-danger {
background: rgba($accent-red, .12);
border-color: $accent-red;
color: $accent-red;
}
&-outline {
background: transparent;
border-color: $border-light;
color: $text-secondary;
&:hover { border-color: $sms-teal; color: $sms-teal; }
&:disabled { opacity: .4; cursor: not-allowed; }
}
&.fw { width: 100%; } &.fw { width: 100%; }
} }
// ─── 输入框 ─── // ─── 输入框 ───
.kv-input { .kv-input {
background: $bg-input; background: $bg-input;
border: 1px solid $border; border: 1px solid $border-light;
border-radius: 3px; border-radius: 2px;
color: $text-primary; color: $text-primary;
font-family: $font-mono; font-family: $font-mono;
font-size: 12px; font-size: 12px;
padding: 3px 7px; padding: 4px 8px;
width: 100%; width: 100%;
outline: none; outline: none;
transition: border-color .15s; transition: border-color .12s;
&:focus { border-color: $accent-blue; }
&:focus { border-color: $sms-teal; box-shadow: 0 0 0 1px rgba($sms-teal, .2); }
&:disabled { opacity: .5; color: $text-muted; }
&[type="number"] { -moz-appearance: textfield; &::-webkit-inner-spin-button { display: none; } }
} }
select.kv-input option { background: $bg-panel; }
textarea.kv-input { resize: vertical; min-height: 64px; }
// ─── KV 参数行 ─── // ─── KV 参数行 ───
.kv-grid { display: grid; grid-template-columns: auto 1fr; gap: 4px 14px; align-items: center; } .kv-grid { display: grid; grid-template-columns: auto 1fr; gap: 4px 14px; align-items: center; }
.kv-label { color: $text-secondary; font-size: 12px; white-space: nowrap; } .kv-label { color: $text-secondary; font-size: 11px; white-space: nowrap; letter-spacing: .2px; }
.kv-value { font-family: $font-mono; font-size: 12px; color: $sms-highlight; font-weight: 600; } .kv-value { font-family: $font-mono; font-size: 12px; color: $sms-teal; font-weight: 600; }
.kv-unit { color: $text-muted; font-size: 11px; } .kv-unit { color: $text-muted; font-size: 10px; }
// ─── 进度条 ─── // ─── 进度条 ───
.prog-bar-wrap { background: #111; border-radius: 3px; height: 6px; overflow: hidden; } .prog-bar-wrap { background: $bg-secondary; border-radius: 1px; height: 5px; overflow: hidden; }
.prog-bar-fill { height: 100%; border-radius: 3px; transition: width .4s; } .prog-bar-fill { height: 100%; border-radius: 1px; transition: width .4s; }
// ─── 分区标题 ─── // ─── 分区标题 ───
.sec-title { .sec-title {
font-size: 11px; font-size: 10px;
font-weight: 700; font-weight: 700;
color: $text-muted; color: $text-muted;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 1.2px; letter-spacing: 1.4px;
margin-bottom: 8px; margin-bottom: 8px;
padding-bottom: 4px; padding-bottom: 4px;
border-bottom: 1px solid $border; border-bottom: 1px solid $border;
} }
// ─── Grid helpers ─── // ─── Grid helpers ───
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; } .grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.grid-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 14px; } .grid-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 12px; }
.grid-4 { display: grid; grid-template-columns: repeat(4,1fr); gap: 14px; } .grid-4 { display: grid; grid-template-columns: repeat(4,1fr); gap: 12px; }
.grid-5 { display: grid; grid-template-columns: repeat(5,1fr); gap: 14px; } .grid-5 { display: grid; grid-template-columns: repeat(5,1fr); gap: 12px; }
.section-row { display: flex; gap: 14px; > .card { flex: 1; min-width: 0; } } .section-row { display: flex; gap: 12px; > .card { flex: 1; min-width: 0; } }
.flex-row { display: flex; gap: 10px; align-items: center; } .flex-row { display: flex; gap: 10px; align-items: center; }
.flex-col { display: flex; flex-direction: column; gap: 8px; } .flex-col { display: flex; flex-direction: column; gap: 8px; }
.flex-between{ display: flex; justify-content: space-between; align-items: center; } .flex-between{ display: flex; justify-content: space-between; align-items: center; }
@@ -208,53 +251,59 @@ body {
.fw { width: 100%; } .fw { width: 100%; }
// ─── Element UI 暗色覆写 ─── // ─── Element UI 暗色覆写 ───
.el-loading-mask { background: rgba($bg-card, .7) !important; }
.el-loading-spinner .path { stroke: $sms-teal !important; }
.el-dialog { .el-dialog {
background: $bg-card !important; background: $bg-card !important;
border: 1px solid $border !important; border: 1px solid $border !important;
border-radius: 6px !important; border-radius: 2px !important;
&__header { background: $bg-panel; border-bottom: 1px solid $border; padding: 12px 16px; } &__header { background: $bg-panel; border-bottom: 1px solid $border; border-left: 3px solid $sms-teal; padding: 10px 14px; }
&__title { color: $sms-highlight !important; font-size: 13px; font-weight: 600; } &__title { color: $text-primary !important; font-size: 12px; font-weight: 700; letter-spacing: .4px; text-transform: uppercase; }
&__headerbtn .el-dialog__close { color: $text-secondary !important; } &__headerbtn .el-dialog__close { color: $text-secondary !important; }
&__body { background: $bg-card; color: $text-primary; padding: 16px; } &__body { background: $bg-card; color: $text-primary; padding: 14px; }
&__footer { background: $bg-panel; border-top: 1px solid $border; padding: 10px 16px; } &__footer { background: $bg-panel; border-top: 1px solid $border; padding: 8px 14px; }
} }
.el-form-item__label { color: $text-secondary !important; font-size: 12px; } .el-form-item__label { color: $text-secondary !important; font-size: 11px; }
.el-input__inner, .el-textarea__inner, .el-select .el-input__inner { .el-input__inner, .el-textarea__inner, .el-select .el-input__inner {
background: $bg-input !important; background: $bg-input !important;
border-color: $border !important; border-color: $border-light !important;
border-radius: 2px !important;
color: $text-primary !important; color: $text-primary !important;
font-family: $font-mono; font-family: $font-mono;
font-size: 12px; font-size: 12px;
&:focus { border-color: $sms-blue !important; } &:focus { border-color: $sms-teal !important; }
} }
.el-select-dropdown { .el-select-dropdown {
background: $bg-panel !important; background: $bg-panel !important;
border-color: $border !important; border-color: $border !important;
.el-select-dropdown__item { color: $text-secondary; &.selected, &:hover { color: $sms-highlight; background: rgba(0,200,255,.08); } } border-radius: 2px !important;
.el-select-dropdown__item { color: $text-secondary; &.selected, &:hover { color: $sms-teal; background: rgba($sms-teal, .08); } }
} }
.el-date-editor .el-range-input, .el-date-editor .el-range-input,
.el-date-editor .el-range-separator { background: transparent !important; color: $text-secondary !important; } .el-date-editor .el-range-separator { background: transparent !important; color: $text-secondary !important; }
.el-pagination { .el-pagination {
.el-pager li { background: $bg-panel; color: $text-secondary; border: 1px solid $border; .el-pager li {
&.active { color: $sms-highlight; border-color: $sms-highlight; } } background: $bg-panel; color: $text-secondary; border: 1px solid $border; border-radius: 2px;
button { background: $bg-panel !important; color: $text-secondary !important; border: 1px solid $border; } &.active { color: $sms-teal; border-color: $sms-teal; }
}
button { background: $bg-panel !important; color: $text-secondary !important; border: 1px solid $border; border-radius: 2px; }
} }
.el-input-number .el-input__inner { text-align: left; } .el-radio__label { color: $text-secondary; font-size: 11px; }
.el-radio__inner { background: $bg-input; border-color: $border-light; }
.el-radio__label { color: $text-secondary; font-size: 12px; }
.el-radio__inner { background: $bg-input; border-color: $border; }
.el-radio__input.is-checked .el-radio__inner { background: $sms-blue; border-color: $sms-blue; } .el-radio__input.is-checked .el-radio__inner { background: $sms-blue; border-color: $sms-blue; }
.el-message-box { .el-message-box {
background: $bg-card !important; background: $bg-card !important;
border-color: $border !important; border-color: $border !important;
&__title { color: $text-primary !important; } border-radius: 2px !important;
&__title { color: $text-primary !important; font-size: 12px; }
&__content { color: $text-secondary !important; } &__content { color: $text-secondary !important; }
} }

View File

@@ -1,31 +1,39 @@
// ─── 色彩系统与参考HTML完全一致)─── // ─── 工业暗色调色板(参考西门子 WinCC 风格)───
$bg-primary: #0d1117; $bg-base: #0b0f16;
$bg-secondary: #161b22; $bg-primary: #0f1420;
$bg-card: #1c2230; $bg-secondary: #141a28;
$bg-panel: #212936; $bg-card: #182030;
$bg-input: #0d1117; $bg-panel: #1c2538;
$border: #30363d; $bg-hover: #22304a;
$border-active: #1f6feb; $bg-input: #0b0f16;
$text-primary: #e6edf3; $border: #263044;
$text-secondary: #8b949e; $border-light: #2e3d58;
$text-muted: #6e7681; $border-active:#00a3be;
$accent-blue: #1f6feb; $text-primary: #c8d6e8;
$accent-cyan: #00b4d8; $text-secondary: #6a82a0;
$accent-green: #28a745; $text-muted: #3e5070;
$accent-yellow: #f0a500;
$accent-orange: #e05a00;
$accent-red: #da3633;
$accent-purple: #8957e5;
$sms-blue: #0078d4; // 西门子主色调 - 石油蓝绿
$sms-highlight: #00c8ff; $sms-teal: #00a3be;
$sms-teal-dim: #007a8c;
$sms-blue: #0066b3;
$sms-blue-dim: #004d88;
$status-run: #28a745; // 状态色
$status-stop: #6e7681; $status-run: #3db86e;
$status-warn: #f0a500; $status-warn: #d4880a;
$status-fault: #da3633; $status-fault: #c8322e;
$status-stop: #3e5070;
$font-main: 'Segoe UI', 'Microsoft YaHei', sans-serif; $accent-green: #3db86e;
$accent-yellow: #d4880a;
$accent-red: #c8322e;
$accent-cyan: #00a3be;
$font-main: 'Segoe UI', 'Microsoft YaHei UI', 'PingFang SC', sans-serif;
$font-mono: 'Consolas', 'Courier New', monospace; $font-mono: 'Consolas', 'Courier New', monospace;
// 向后兼容
$sms-highlight: $sms-teal;

View File

@@ -3,13 +3,16 @@
<!-- TOP BAR --> <!-- TOP BAR -->
<div class="top-bar"> <div class="top-bar">
<div class="logo">SMS <span>L2</span></div> <div class="logo">
<div class="sys-title">推拉酸洗线 L2 过程控制系统 &nbsp;|&nbsp; PUSH-PULL PICKLING LINE</div> <span class="logo-mark">S</span>
<span class="logo-text">SIMATIC L2</span>
</div>
<div class="sys-title">推拉酸洗线 · L2 过程控制系统</div>
<div class="spacer"></div> <div class="spacer"></div>
<div class="status-pills"> <div class="status-pills">
<span class="pill run"> 机组运行</span> <span class="pill run"><i class="dot"></i>机组运行</span>
<span class="pill run"> L2在线</span> <span class="pill run"><i class="dot"></i>L2 在线</span>
<span :class="['pill', l3Status]">{{ l3StatusText }}</span> <span :class="['pill', l3Status]"><i class="dot"></i>{{ l3StatusText }}</span>
</div> </div>
<div class="top-user"> <div class="top-user">
<span class="username">{{ user && (user.full_name || user.username) }}</span> <span class="username">{{ user && (user.full_name || user.username) }}</span>
@@ -19,30 +22,34 @@
<div class="clock">{{ clock }}</div> <div class="clock">{{ clock }}</div>
</div> </div>
<!-- NAV BAR --> <!-- BODY -->
<div class="nav-bar"> <div class="body-area">
<div
v-for="item in menuItems"
:key="item.path"
:class="['nav-item', { active: $route.path === item.path }]"
@click="$router.push(item.path)"
>
<span class="nav-icon">{{ item.icon }}</span>
{{ item.title }}
</div>
</div>
<!-- MAIN --> <!-- SIDEBAR -->
<div class="main-area"> <div class="sidebar">
<router-view /> <div
v-for="item in menuItems"
:key="item.path"
:class="['nav-item', { active: $route.path === item.path }]"
@click="$router.push(item.path)"
>
<span class="nav-icon" v-html="item.icon"></span>
<span class="nav-label">{{ item.title }}</span>
</div>
</div>
<!-- MAIN -->
<div class="main-area">
<router-view />
</div>
</div> </div>
<!-- FOOTER --> <!-- FOOTER -->
<div class="footer"> <div class="footer">
<div class="fp"><span class="dot g"></span>数据库 正常</div> <div class="fp"><i class="dot g"></i>数据库</div>
<div class="fp"><span class="dot g"></span>UDP 监听 :9000</div> <div class="fp"><i class="dot g"></i>UDP :9000</div>
<div class="fp"><span :class="['dot', l3Status === 'run' ? 'g' : 'y']"></span>L3 {{ l3StatusText }}</div> <div class="fp"><i :class="['dot', l3Status === 'run' ? 'g' : 'y']"></i>L3 {{ l3StatusText }}</div>
<div style="margin-left:auto;color:var(--text-muted);">推拉酸洗线 L2 MES &nbsp;v1.0.0</div> <div style="margin-left:auto;">推拉酸洗线 L2 MES · v1.0.0</div>
</div> </div>
</div> </div>
@@ -51,19 +58,34 @@
<script> <script>
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
const IC = {
dashboard: `<svg viewBox="0 0 16 16" fill="currentColor"><rect x="1" y="1" width="6" height="6"/><rect x="9" y="1" width="6" height="6"/><rect x="1" y="9" width="6" height="6"/><rect x="9" y="9" width="6" height="6"/></svg>`,
material: `<svg viewBox="0 0 16 16" fill="currentColor"><path d="M8 1L1 4.5v7L8 15l7-3.5v-7L8 1zm0 2l5 2.5v5.5L8 13 3 11V5.5L8 3z"/></svg>`,
production: `<svg viewBox="0 0 16 16" fill="currentColor"><rect x="1" y="9" width="3" height="6"/><rect x="5.5" y="6" width="3" height="9"/><rect x="10" y="2" width="3" height="13"/></svg>`,
plan: `<svg viewBox="0 0 16 16" fill="currentColor"><rect x="2" y="3" width="12" height="2"/><rect x="2" y="7" width="12" height="2"/><rect x="2" y="11" width="7" height="2"/></svg>`,
downtime: `<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="8" cy="8" r="6"/><rect x="5.5" y="5" width="2" height="6" fill="currentColor" stroke="none"/><rect x="8.5" y="5" width="2" height="6" fill="currentColor" stroke="none"/></svg>`,
equipment: `<svg viewBox="0 0 16 16" fill="currentColor"><path d="M8 5.5a2.5 2.5 0 100 5 2.5 2.5 0 000-5zm0 1.5a1 1 0 110 2 1 1 0 010-2zM6.8 1l-.4 1.8a5.2 5.2 0 00-1.6 1L3 3.3 1.3 6l1.5 1.1A5 5 0 002.5 8c0 .3 0 .6.05.9L1.3 10 3 12.7l1.8-.5c.48.4 1 .74 1.6 1L6.8 15h2.4l.4-1.8c.6-.26 1.12-.6 1.6-1l1.8.5L14.7 10l-1.3-1.1c.04-.3.06-.6.06-.9 0-.3-.02-.6-.06-.9L14.7 6 13 3.3l-1.8.5a5.2 5.2 0 00-1.6-1L9.2 1H6.8z"/></svg>`,
inspection: `<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="6.5" cy="6.5" r="4.5"/><line x1="9.9" y1="9.9" x2="14" y2="14"/><circle cx="6.5" cy="6.5" r="1.5" fill="currentColor" stroke="none"/></svg>`,
message: `<svg viewBox="0 0 16 16" fill="currentColor"><path d="M1 2h14v10H9.5L8 14.5 6.5 12H1V2zm1.5 1.5v7h4l1.5 2.2 1.5-2.2h4v-7h-11z"/></svg>`,
process: `<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M1 8 Q3 3 5 8 Q7 13 9 8 Q11 3 13 8 Q14 10.5 15 8"/></svg>`,
tension: `<svg viewBox="0 0 16 16" fill="currentColor"><path d="M8 1a7 7 0 100 14A7 7 0 008 1zm0 1.5a5.5 5.5 0 110 11 5.5 5.5 0 010-11z"/><line x1="8" y1="8" x2="11.5" y2="5" stroke="currentColor" stroke-width="1.5"/><circle cx="8" cy="8" r="1.2"/></svg>`,
quality: `<svg viewBox="0 0 16 16" fill="currentColor"><path d="M8 1l1.9 4.2 4.6.5-3.4 3.1 1 4.5L8 11.2l-4.1 2.1 1-4.5L1.5 5.7l4.6-.5z"/></svg>`,
capacity: `<svg viewBox="0 0 16 16" fill="currentColor"><rect x="1" y="10" width="3" height="5"/><rect x="5.5" y="7" width="3" height="8"/><rect x="10" y="4" width="3" height="11"/></svg>`,
}
const MENU = [ const MENU = [
{ path: '/dashboard', title: '生产看板', icon: 'DB' }, { path: '/dashboard', title: '生产看板', icon: IC.dashboard },
{ path: '/material', title: '物料跟踪', icon: 'MT' }, { path: '/material', title: '物料跟踪', icon: IC.material },
{ path: '/production', title: '实绩管理', icon: 'PR' }, { path: '/production', title: '实绩管理', icon: IC.production },
{ path: '/plan', title: '计划管理', icon: 'PL' }, { path: '/plan', title: '计划管理', icon: IC.plan },
{ path: '/downtime', title: '停机管理', icon: 'DT' }, { path: '/downtime', title: '停机管理', icon: IC.downtime },
{ path: '/equipment', title: '设备管理', icon: 'EQ' }, { path: '/equipment', title: '设备管理', icon: IC.equipment },
{ path: '/inspection', title: '设备巡检', icon: 'INS' }, { path: '/inspection', title: '设备巡检', icon: IC.inspection },
{ path: '/message', title: '报文监控', icon: 'MSG' }, { path: '/message', title: '报文监控', icon: IC.message },
{ path: '/process-model', title: '工艺段模型', icon: 'PM' }, { path: '/process-model', title: '工艺段模型', icon: IC.process },
{ path: '/tension-model', title: '张力设定', icon: 'TM' }, { path: '/tension-model', title: '张力设定', icon: IC.tension },
{ path: '/quality', title: '质量管理', icon: 'QC' }, { path: '/quality', title: '质量管理', icon: IC.quality },
{ path: '/capacity', title: '产能分析', icon: 'CAP' }, { path: '/capacity', title: '产能分析', icon: IC.capacity },
] ]
export default { export default {
@@ -72,7 +94,7 @@ export default {
return { return {
clock: '--:--:--', clock: '--:--:--',
l3Status: 'warn', l3Status: 'warn',
l3StatusText: 'L3待机', l3StatusText: 'L3 待机',
menuItems: MENU, menuItems: MENU,
_timer: null, _timer: null,
} }
@@ -82,8 +104,7 @@ export default {
}, },
mounted() { mounted() {
this._timer = setInterval(() => { this._timer = setInterval(() => {
const now = new Date() this.clock = new Date().toTimeString().slice(0, 8)
this.clock = now.toTimeString().slice(0, 8)
}, 1000) }, 1000)
this.clock = new Date().toTimeString().slice(0, 8) this.clock = new Date().toTimeString().slice(0, 8)
}, },
@@ -109,138 +130,209 @@ export default {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow: hidden; overflow: hidden;
background: $bg-base;
} }
// ─── TOP BAR ─── // ─── TOP BAR ───
.top-bar { .top-bar {
height: 48px; height: 44px;
background: linear-gradient(90deg, #0d1b2e 0%, #0a1628 100%);
border-bottom: 1px solid $border;
display: flex;
align-items: center;
padding: 0 16px;
gap: 16px;
flex-shrink: 0;
.logo {
font-size: 15px;
font-weight: 700;
color: $sms-highlight;
letter-spacing: 1px;
white-space: nowrap;
span { color: $accent-yellow; }
}
.sys-title {
font-size: 12px;
color: $text-secondary;
border-left: 1px solid $border;
padding-left: 16px;
white-space: nowrap;
}
.spacer { flex: 1; }
.status-pills {
display: flex;
gap: 10px;
align-items: center;
}
.top-user {
display: flex;
align-items: center;
gap: 8px;
font-size: 12px;
color: $text-secondary;
.divider { color: $border; }
.logout { cursor: pointer; color: $text-muted; &:hover { color: $sms-highlight; } }
}
.clock {
font-family: $font-mono;
font-size: 13px;
color: $sms-highlight;
min-width: 72px;
text-align: right;
}
}
.pill {
padding: 2px 10px;
border-radius: 10px;
font-size: 11px;
font-weight: 600;
letter-spacing: .5px;
&.run { background: #1a3a1f; color: $status-run; border: 1px solid $status-run; }
&.warn { background: #3a2a00; color: $status-warn; border: 1px solid $status-warn; }
&.stop { background: #222; color: $text-muted; border: 1px solid $border; }
}
// ─── NAV BAR ───
.nav-bar {
height: 38px;
background: $bg-secondary; background: $bg-secondary;
border-bottom: 1px solid $border; border-bottom: 1px solid $border;
display: flex; display: flex;
align-items: stretch; align-items: center;
overflow-x: auto; padding: 0 14px;
gap: 14px;
flex-shrink: 0; flex-shrink: 0;
scrollbar-width: thin; }
scrollbar-color: $border transparent;
&::-webkit-scrollbar { height: 3px; } .logo {
&::-webkit-scrollbar-thumb { background: $border; } display: flex;
align-items: center;
gap: 7px;
flex-shrink: 0;
}
.logo-mark {
width: 24px;
height: 24px;
background: $sms-teal;
color: $bg-base;
font-size: 13px;
font-weight: 900;
display: flex;
align-items: center;
justify-content: center;
border-radius: 1px;
letter-spacing: 0;
}
.logo-text {
font-size: 12px;
font-weight: 700;
color: $text-primary;
letter-spacing: 1.5px;
text-transform: uppercase;
}
.sys-title {
font-size: 11px;
color: $text-secondary;
border-left: 1px solid $border;
padding-left: 14px;
white-space: nowrap;
letter-spacing: .3px;
}
.spacer { flex: 1; }
.status-pills {
display: flex;
gap: 8px;
align-items: center;
}
.pill {
display: flex;
align-items: center;
gap: 5px;
padding: 2px 9px;
border-radius: 1px;
font-size: 10px;
font-weight: 700;
letter-spacing: .5px;
text-transform: uppercase;
.dot {
width: 5px;
height: 5px;
border-radius: 50%;
display: inline-block;
}
&.run { background: rgba($status-run, .12); color: $status-run; border: 1px solid rgba($status-run, .4); .dot { background: $status-run; } }
&.warn { background: rgba($status-warn, .12); color: $status-warn; border: 1px solid rgba($status-warn, .4); .dot { background: $status-warn; } }
&.stop { background: rgba($status-stop, .1); color: $status-stop; border: 1px solid $border; .dot { background: $status-stop; } }
}
.top-user {
display: flex;
align-items: center;
gap: 8px;
font-size: 11px;
color: $text-secondary;
.divider { color: $border-light; }
.logout { cursor: pointer; color: $text-muted; &:hover { color: $sms-teal; } }
}
.clock {
font-family: $font-mono;
font-size: 13px;
font-weight: 700;
color: $sms-teal;
min-width: 70px;
text-align: right;
letter-spacing: 1px;
}
// ─── BODY ───
.body-area {
flex: 1;
display: flex;
overflow: hidden;
}
// ─── SIDEBAR ───
.sidebar {
width: 158px;
flex-shrink: 0;
background: $bg-secondary;
border-right: 1px solid $border;
overflow-y: auto;
scrollbar-width: none;
&::-webkit-scrollbar { display: none; }
padding: 6px 0;
} }
.nav-item { .nav-item {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 5px; gap: 9px;
padding: 0 16px; padding: 9px 14px;
font-size: 12px; font-size: 11px;
font-weight: 500;
color: $text-secondary; color: $text-secondary;
cursor: pointer; cursor: pointer;
white-space: nowrap;
border-bottom: 2px solid transparent;
transition: all .15s;
user-select: none; user-select: none;
border-left: 2px solid transparent;
transition: all .12s;
letter-spacing: .2px;
&:hover { color: $text-primary; background: rgba(255,255,255,.03); } &:hover {
&.active { color: $sms-highlight; border-bottom-color: $sms-highlight; background: rgba(0,200,255,.05); } background: rgba($sms-teal, .06);
color: $text-primary;
}
.nav-icon { font-size: 10px; font-family: $font-mono; color: $text-muted; letter-spacing: .5px; } &.active {
background: rgba($sms-teal, .10);
color: $sms-teal;
border-left-color: $sms-teal;
}
}
.nav-icon {
width: 16px;
height: 16px;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
opacity: .85;
::v-deep svg {
width: 16px;
height: 16px;
}
}
.nav-label {
white-space: nowrap;
} }
// ─── MAIN AREA ─── // ─── MAIN AREA ───
.main-area { .main-area {
flex: 1; flex: 1;
overflow-y: auto; overflow-y: auto;
padding: 14px; padding: 12px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 14px; gap: 12px;
background: $bg-primary;
scrollbar-width: thin; scrollbar-width: thin;
scrollbar-color: $border transparent; scrollbar-color: $border transparent;
&::-webkit-scrollbar { width: 6px; } &::-webkit-scrollbar { width: 5px; }
&::-webkit-scrollbar-thumb { background: $border; border-radius: 3px; } &::-webkit-scrollbar-thumb { background: $border-light; border-radius: 1px; }
} }
// ─── FOOTER ─── // ─── FOOTER ───
.footer { .footer {
height: 26px; height: 24px;
background: $bg-secondary; background: $bg-secondary;
border-top: 1px solid $border; border-top: 1px solid $border;
display: flex; display: flex;
align-items: center; align-items: center;
padding: 0 14px; padding: 0 14px;
gap: 16px; gap: 18px;
font-size: 11px; font-size: 10px;
color: $text-muted; color: $text-muted;
flex-shrink: 0; flex-shrink: 0;
letter-spacing: .3px;
.fp { display: flex; align-items: center; gap: 5px; } .fp { display: flex; align-items: center; gap: 5px; }
.dot { width: 6px; height: 6px; border-radius: 50%; &.g { background: $accent-green; } &.y { background: $accent-yellow; } &.r { background: $accent-red; } } .dot {
width: 5px; height: 5px; border-radius: 50%; display: inline-block;
&.g { background: $status-run; }
&.y { background: $status-warn; }
&.r { background: $status-fault; }
}
} }
</style> </style>