style: 西门子 WinCC 工业风格重设计
- 左侧边栏导航替换顶部横向导航 - 色调改为石油蓝绿(#00a3be),去除霓虹蓝 - 卡片头部加左侧色带 accent,去除圆角 - Badge 改为矩形工业风,全大写标签 - 按钮、输入框统一 2px radius - 导航图标改为 SVG 几何图形替代纯文字缩写
This commit is contained in:
@@ -3,13 +3,16 @@
|
||||
|
||||
<!-- ─── TOP BAR ─── -->
|
||||
<div class="top-bar">
|
||||
<div class="logo">SMS <span>L2</span></div>
|
||||
<div class="sys-title">推拉酸洗线 L2 过程控制系统 | PUSH-PULL PICKLING LINE</div>
|
||||
<div class="logo">
|
||||
<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="status-pills">
|
||||
<span class="pill run">● 机组运行</span>
|
||||
<span class="pill run">● L2在线</span>
|
||||
<span :class="['pill', l3Status]">{{ l3StatusText }}</span>
|
||||
<span class="pill run"><i class="dot"></i>机组运行</span>
|
||||
<span class="pill run"><i class="dot"></i>L2 在线</span>
|
||||
<span :class="['pill', l3Status]"><i class="dot"></i>{{ l3StatusText }}</span>
|
||||
</div>
|
||||
<div class="top-user">
|
||||
<span class="username">{{ user && (user.full_name || user.username) }}</span>
|
||||
@@ -19,30 +22,34 @@
|
||||
<div class="clock">{{ clock }}</div>
|
||||
</div>
|
||||
|
||||
<!-- ─── NAV BAR ─── -->
|
||||
<div class="nav-bar">
|
||||
<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>
|
||||
<!-- ─── BODY ─── -->
|
||||
<div class="body-area">
|
||||
|
||||
<!-- ─── MAIN ─── -->
|
||||
<div class="main-area">
|
||||
<router-view />
|
||||
<!-- ─── SIDEBAR ─── -->
|
||||
<div class="sidebar">
|
||||
<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>
|
||||
|
||||
<!-- ─── FOOTER ─── -->
|
||||
<div class="footer">
|
||||
<div class="fp"><span class="dot g"></span>数据库 正常</div>
|
||||
<div class="fp"><span class="dot g"></span>UDP 监听 :9000</div>
|
||||
<div class="fp"><span :class="['dot', l3Status === 'run' ? 'g' : 'y']"></span>L3 {{ l3StatusText }}</div>
|
||||
<div style="margin-left:auto;color:var(--text-muted);">推拉酸洗线 L2 MES v1.0.0</div>
|
||||
<div class="fp"><i class="dot g"></i>数据库</div>
|
||||
<div class="fp"><i class="dot g"></i>UDP :9000</div>
|
||||
<div class="fp"><i :class="['dot', l3Status === 'run' ? 'g' : 'y']"></i>L3 {{ l3StatusText }}</div>
|
||||
<div style="margin-left:auto;">推拉酸洗线 L2 MES · v1.0.0</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -51,19 +58,34 @@
|
||||
<script>
|
||||
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 = [
|
||||
{ path: '/dashboard', title: '生产看板', icon: 'DB' },
|
||||
{ path: '/material', title: '物料跟踪', icon: 'MT' },
|
||||
{ path: '/production', title: '实绩管理', icon: 'PR' },
|
||||
{ path: '/plan', title: '计划管理', icon: 'PL' },
|
||||
{ path: '/downtime', title: '停机管理', icon: 'DT' },
|
||||
{ path: '/equipment', title: '设备管理', icon: 'EQ' },
|
||||
{ path: '/inspection', title: '设备巡检', icon: 'INS' },
|
||||
{ path: '/message', title: '报文监控', icon: 'MSG' },
|
||||
{ path: '/process-model', title: '工艺段模型', icon: 'PM' },
|
||||
{ path: '/tension-model', title: '张力设定', icon: 'TM' },
|
||||
{ path: '/quality', title: '质量管理', icon: 'QC' },
|
||||
{ path: '/capacity', title: '产能分析', icon: 'CAP' },
|
||||
{ path: '/dashboard', title: '生产看板', icon: IC.dashboard },
|
||||
{ path: '/material', title: '物料跟踪', icon: IC.material },
|
||||
{ path: '/production', title: '实绩管理', icon: IC.production },
|
||||
{ path: '/plan', title: '计划管理', icon: IC.plan },
|
||||
{ path: '/downtime', title: '停机管理', icon: IC.downtime },
|
||||
{ path: '/equipment', title: '设备管理', icon: IC.equipment },
|
||||
{ path: '/inspection', title: '设备巡检', icon: IC.inspection },
|
||||
{ path: '/message', title: '报文监控', icon: IC.message },
|
||||
{ path: '/process-model', title: '工艺段模型', icon: IC.process },
|
||||
{ path: '/tension-model', title: '张力设定', icon: IC.tension },
|
||||
{ path: '/quality', title: '质量管理', icon: IC.quality },
|
||||
{ path: '/capacity', title: '产能分析', icon: IC.capacity },
|
||||
]
|
||||
|
||||
export default {
|
||||
@@ -72,7 +94,7 @@ export default {
|
||||
return {
|
||||
clock: '--:--:--',
|
||||
l3Status: 'warn',
|
||||
l3StatusText: 'L3待机',
|
||||
l3StatusText: 'L3 待机',
|
||||
menuItems: MENU,
|
||||
_timer: null,
|
||||
}
|
||||
@@ -82,8 +104,7 @@ export default {
|
||||
},
|
||||
mounted() {
|
||||
this._timer = setInterval(() => {
|
||||
const now = new Date()
|
||||
this.clock = now.toTimeString().slice(0, 8)
|
||||
this.clock = new Date().toTimeString().slice(0, 8)
|
||||
}, 1000)
|
||||
this.clock = new Date().toTimeString().slice(0, 8)
|
||||
},
|
||||
@@ -109,138 +130,209 @@ export default {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
background: $bg-base;
|
||||
}
|
||||
|
||||
// ─── TOP BAR ───
|
||||
.top-bar {
|
||||
height: 48px;
|
||||
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;
|
||||
height: 44px;
|
||||
background: $bg-secondary;
|
||||
border-bottom: 1px solid $border;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
overflow-x: auto;
|
||||
align-items: center;
|
||||
padding: 0 14px;
|
||||
gap: 14px;
|
||||
flex-shrink: 0;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: $border transparent;
|
||||
&::-webkit-scrollbar { height: 3px; }
|
||||
&::-webkit-scrollbar-thumb { background: $border; }
|
||||
}
|
||||
|
||||
.logo {
|
||||
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 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
padding: 0 16px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
gap: 9px;
|
||||
padding: 9px 14px;
|
||||
font-size: 11px;
|
||||
color: $text-secondary;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
border-bottom: 2px solid transparent;
|
||||
transition: all .15s;
|
||||
user-select: none;
|
||||
border-left: 2px solid transparent;
|
||||
transition: all .12s;
|
||||
letter-spacing: .2px;
|
||||
|
||||
&:hover { color: $text-primary; background: rgba(255,255,255,.03); }
|
||||
&.active { color: $sms-highlight; border-bottom-color: $sms-highlight; background: rgba(0,200,255,.05); }
|
||||
&:hover {
|
||||
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 {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 14px;
|
||||
padding: 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
gap: 12px;
|
||||
background: $bg-primary;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: $border transparent;
|
||||
&::-webkit-scrollbar { width: 6px; }
|
||||
&::-webkit-scrollbar-thumb { background: $border; border-radius: 3px; }
|
||||
&::-webkit-scrollbar { width: 5px; }
|
||||
&::-webkit-scrollbar-thumb { background: $border-light; border-radius: 1px; }
|
||||
}
|
||||
|
||||
// ─── FOOTER ───
|
||||
.footer {
|
||||
height: 26px;
|
||||
height: 24px;
|
||||
background: $bg-secondary;
|
||||
border-top: 1px solid $border;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 14px;
|
||||
gap: 16px;
|
||||
font-size: 11px;
|
||||
gap: 18px;
|
||||
font-size: 10px;
|
||||
color: $text-muted;
|
||||
flex-shrink: 0;
|
||||
letter-spacing: .3px;
|
||||
|
||||
.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>
|
||||
|
||||
Reference in New Issue
Block a user