Files
DCU_DesktopController/css/base.css
T
cbb eac3717f9a feat: 添加局域网设备发现功能和链路胶囊优化
- 实现局域网设备发现面板,支持探测ESP32中继板并自动切换端点
- 添加POST /api/lan/probe接口用于设备探测,返回三态判决结果
- 实现快扫和全段扫描两种模式,支持种子地址优先探测
- 添加端点唯一写手机制,防止多处同时修改设备IP
- 优化链路胶囊UI显示WiFi/EtherCAT/BLE连接状态和设备名称
- 修复EtherCAT链路OTA刷写期间PDO循环暂停和AL状态处理问题
- 调整PDO周期设置范围为0.125-4ms,支持亚毫秒显示为微秒
- 添加ESP32 WiFi使能开关控件样式和数据来源角标显示
2026-10-13 00:48:34 +08:00

242 lines
9.5 KiB
CSS
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.
/* ============================================================
base.css — DCU Mission Control · 设计令牌与全局基底
风格:深色测控台(deep blue-slate),多色子系统语义配色
子系统色:ESP32=青绿 · GD32=琥珀 · BLE=蓝 · CAN=绿 · 内存/调试=紫
============================================================ */
:root {
/* ---- 底色层次:深蓝灰,层层抬升,拒绝纯黑 ---- */
--bg-root: #0a0f1a;
--bg-panel: #0e1624;
--bg-card: #131d2e;
--bg-elevated: #1a2740;
--bg-input: #0b1220;
--bg-hover: #20304c;
/* ---- 边框 ---- */
--border: #21304a;
--border-strong: #2e4262;
--border-subtle: #1a2740;
/* ---- 文字 ---- */
--text: #e9f0fa;
--text-dim: #93a8c4;
--text-label: #617a99;
/* ---- 子系统语义色 ---- */
--esp32: #2fd8c1; /* 青绿:ESP32 / 主操作 / WiFi OTA */
--esp32-hi: #6ff2e0;
--esp32-dim: rgba(47,216,193,.14);
--gd32: #fcbf3f; /* 琥珀:GD32 / 中继 OTA */
--gd32-hi: #ffd97a;
--gd32-dim: rgba(252,191,63,.14);
--ble: #5fa8ff; /* 蓝:BLE 蓝牙通道 */
--ble-hi: #93c6ff;
--ble-dim: rgba(95,168,255,.14);
--can: #43d97b; /* 绿:CAN 总线 / 健康 */
--can-hi: #7deda6;
--can-dim: rgba(67,217,123,.14);
--motor: #22d3ee; /* 青:电机控制台 */
--motor-hi: #67e8f9;
--motor-dim: rgba(34,211,238,.14);
--mem: #a88bfa; /* 紫:内存 / 调试 / 日志 */
--mem-hi: #c7b3ff;
--mem-dim: rgba(168,139,250,.14);
/* ---- 状态语义色 ---- */
--green: #3ddc8e;
--amber: #fcbf3f;
--red: #ff6b6b;
--red-dim: rgba(255,107,107,.14);
/* ---- 兼容旧令牌(大量旧样式引用,勿删)---- */
--accent: var(--esp32);
--accent-dim: var(--esp32-dim);
--border-focus: var(--esp32);
/* ---- 圆角 ---- */
--radius-sm: 8px;
--radius: 12px;
--radius-lg: 16px;
/* ---- 字体 ----
沿用原始系统字体方案:中文优先苹方/雅黑,西文 Segoe UI;
mono 用于 SHA / HEX / 日志 / 数值(SF Mono → Fira Code → Cascadia → Consolas)。
--font-display 保留变量名以兼容既有引用,指向同一系统栈。 */
--font-display: "PingFang SC","Microsoft YaHei","Segoe UI",system-ui,sans-serif;
--font: "PingFang SC","Microsoft YaHei","Segoe UI",system-ui,sans-serif;
--font-mono: "SF Mono","Fira Code","Cascadia Code","Consolas",monospace;
/* ---- 间距 / 阴影 ---- */
--gap: 18px;
--shadow-card: 0 10px 30px rgba(3,7,16,.45), 0 1px 0 rgba(255,255,255,.03) inset;
--shadow-pop: 0 18px 48px rgba(3,7,16,.6);
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html, body {
height: 100%;
background: var(--bg-root);
color: var(--text);
font-family: var(--font);
font-size: 14px;
line-height: 1.55;
-webkit-font-smoothing: antialiased;
overflow-x: hidden;
}
/* ---- 环境光背景:细网格 + 双色氛围辉光 + 顶部扫光 ----
网格提供"工程图纸"质感;左上青绿、右下琥珀的两团极淡辉光
暗示 ESP32 / GD32 双核子系统,随视口固定,营造纵深。 */
body::before {
content: "";
position: fixed; inset: 0; z-index: 0; pointer-events: none;
background-image:
linear-gradient(rgba(148,180,226,.035) 1px, transparent 1px),
linear-gradient(90deg, rgba(148,180,226,.035) 1px, transparent 1px);
background-size: 44px 44px;
mask-image: radial-gradient(ellipse 120% 90% at 50% -8%, black 30%, transparent 78%);
}
body::after {
content: "";
position: fixed; inset: 0; z-index: 0; pointer-events: none;
background:
radial-gradient(900px 520px at 8% -10%, rgba(47,216,193,.10), transparent 60%),
radial-gradient(820px 560px at 100% 112%, rgba(252,191,63,.07), transparent 62%),
radial-gradient(700px 480px at 88% -6%, rgba(95,168,255,.06), transparent 60%);
}
.container {
position: relative; z-index: 1;
max-width: 1480px; margin: 0 auto; padding: 26px 32px 44px;
}
/* ---- 全局滚动条 ---- */
::-webkit-scrollbar { width: 9px; height: 9px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
background: var(--border-strong); border-radius: 99px;
border: 2px solid var(--bg-root);
}
::-webkit-scrollbar-thumb:hover { background: #3a5378; }
/* ---- 选区 ---- */
::selection { background: rgba(47,216,193,.28); color: #eafffb; }
/* ---- 通用等宽数字(让指标/百分比对齐、不跳动)---- */
.tabular { font-variant-numeric: tabular-nums; }
/* ---- focus 可见性(键盘可达性)---- */
:focus-visible {
outline: 2px solid var(--esp32);
outline-offset: 2px;
border-radius: 4px;
}
/* ============================================================
局域网设备发现(js/common/lan-picker.js)
这里只放弹窗本身和它特有的排布。按钮 / 表单 / 输入框 / 列表行
一律复用 layout.css 的既有类(.btn .btn-outline .btn-sm .input
.input-group .form-label .jump-history-item .jh-tag .jh-msg .jh-time
与 .ok/.err/.info 状态色),不再另造一套控件外观。
============================================================ */
.lan-slot { display: flex; align-items: center; gap: 8px; padding: 0 6px; }
/* 遮罩:居中弹出 + 周围高斯模糊(backdrop-filter 作用于遮罩下方的整个页面) */
.lan-mask {
position: fixed; inset: 0; z-index: 900;
display: none; align-items: center; justify-content: center;
padding: 24px;
background: rgba(4, 8, 14, .62);
-webkit-backdrop-filter: blur(9px) saturate(.85);
backdrop-filter: blur(9px) saturate(.85);
animation: lanFade .16s ease;
}
.lan-mask.show { display: flex; }
@keyframes lanFade { from { opacity: 0; } to { opacity: 1; } }
@keyframes lanPop {
from { opacity: 0; transform: translateY(10px) scale(.985); }
to { opacity: 1; transform: none; }
}
/* 盒子沿用 .card 的渐变底与顶部子系统色带,描边/阴影/圆角同 .modal-box */
.lan-box {
position: relative;
width: min(760px, 100%); max-height: min(82vh, 780px);
overflow: auto;
background: linear-gradient(170deg, var(--bg-card) 0%, rgba(15,23,38,.96) 100%);
border: 1px solid var(--border-strong);
border-radius: var(--radius-lg);
box-shadow: 0 24px 64px rgba(0,0,0,.6);
animation: lanPop .18s ease;
}
.lan-box::before {
content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2px;
background: linear-gradient(90deg, var(--esp32) 0%, var(--ble) 55%, var(--gd32) 100%);
opacity: .8;
border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}
.lan-head {
position: sticky; top: 0; z-index: 2;
display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
padding: 14px 18px; border-bottom: 1px solid var(--border-subtle);
font-family: var(--font-display); font-size: 13px; font-weight: 600;
letter-spacing: .05em; color: var(--text);
background: linear-gradient(170deg, var(--bg-card) 0%, rgba(15,23,38,.96) 100%);
}
.lan-ep {
font-family: var(--font-mono); font-size: 11px; font-weight: 400;
letter-spacing: 0; color: var(--text-dim);
}
.lan-head .btn { margin-left: auto; }
.lan-body { padding: 14px 18px 18px; display: flex; flex-direction: column; gap: 12px; }
.lan-tools { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.lan-field { display: flex; align-items: center; gap: 8px; }
.lan-field .form-label { margin-bottom: 0; }
.lan-field .input { width: 172px; padding: 7px 10px; font-size: 12px; }
.lan-check {
display: flex; align-items: center; gap: 6px; cursor: pointer;
font-family: var(--font-display); font-size: 11px;
letter-spacing: .08em; text-transform: uppercase; color: var(--text-label);
}
.lan-progress { font-family: var(--font-mono); font-size: 11.5px; color: var(--text-label); }
.lan-progress.lan-busy { color: var(--esp32); }
/* 列表行 = .jump-history-item 既有排布,但改成网格:
没有操作按钮的"当前端点"行和有按钮的行才能按同一套列宽对齐
(flex 布局下两行的右侧列会各自漂移,就是"对不齐"的来源)。 */
.lan-list {
list-style: none; margin: 0; padding: 0; overflow: hidden;
border: 1px solid var(--border); border-radius: var(--radius-sm);
background: var(--bg-card);
}
.lan-list .jump-history-item {
display: grid; align-items: center; gap: 8px;
grid-template-columns: 46px minmax(0, 1fr) auto 52px;
padding: 6px 12px; cursor: pointer;
}
.lan-list .jump-history-item > .jh-msg { min-width: 0; }
.lan-list .jump-history-item > .jh-time { text-align: right; }
.lan-list .jump-history-item > .lan-sub { grid-column: 1 / -1; }
.lan-list .jump-history-item:hover { background: var(--bg-hover); }
.lan-list .jump-history-item.lan-cur { background: var(--esp32-dim); }
.lan-list .jump-history-item.lan-stale { opacity: .55; }
.lan-ip { color: var(--text); font-weight: 700; }
.lan-meta { color: var(--text-dim); font-weight: 400; }
.lan-acts { display: flex; gap: 4px; flex-shrink: 0; }
.lan-sub { flex-basis: 100%; font-size: 11px; color: var(--text-label); }
.lan-empty, .lan-cut { padding: 12px; font-size: 12px; color: var(--text-dim); text-align: center; }
.lan-note { min-height: 1.2em; font-family: var(--font-mono); font-size: 11.5px; color: var(--text-dim); }
.lan-note-warn { color: var(--amber); }
.lan-note-error { color: var(--red); }
.lan-misc {
display: flex; flex-direction: column; gap: 8px;
border-top: 1px solid var(--border-subtle); padding-top: 12px;
}
.lan-block { font-family: var(--font-mono); font-size: 11.5px; color: var(--text-label); }
.lan-block b { color: var(--text-dim); font-weight: 600; }
.lan-block ul { margin: 4px 0 0; padding-left: 18px; }
.lan-hint { color: var(--text-dim); }