Files
dygou_go/frontend/styles.css
T
2026-06-26 09:38:14 +08:00

802 lines
20 KiB
CSS

*{margin:0;padding:0;box-sizing:border-box}
:root{
color-scheme:dark;
--bg:#0f1419;
--surface:#161b22;
--surface-2:#1c232c;
--surface-3:#232b36;
--field:#0d1117;
--text:#c9d1d9;
--text-strong:#f0f6fc;
--muted:#8b949e;
--muted-2:#6e7681;
--line:#21262d;
--line-strong:#30363d;
--accent:#388bfd;
--accent-soft:rgba(56,139,253,.12);
--accent-border:rgba(56,139,253,.35);
--danger:#f85149;
--danger-soft:rgba(248,81,73,.12);
--success:#3fb950;
--success-soft:rgba(63,185,80,.12);
--warning:#d29922;
--warning-soft:rgba(210,153,34,.12);
--orange:#f78166;
--orange-soft:rgba(247,129,102,.12);
--shadow:0 1px 0 rgba(0,0,0,.04),0 8px 24px rgba(0,0,0,.18);
--radius:8px;
--radius-sm:6px;
--focus:0 0 0 3px rgba(56,139,253,.3);
}
body[data-theme="light"]{
color-scheme:light;
--bg:#f6f8fa;
--surface:#ffffff;
--surface-2:#f6f8fa;
--surface-3:#eaeef2;
--field:#ffffff;
--text:#1f2328;
--text-strong:#0d1117;
--muted:#656d76;
--muted-2:#8c959f;
--line:#d0d7de;
--line-strong:#afb8c1;
--accent:#0969da;
--accent-soft:rgba(9,105,218,.08);
--accent-border:rgba(9,105,218,.3);
--danger:#cf222e;
--danger-soft:rgba(207,34,46,.08);
--success:#1a7f37;
--success-soft:rgba(26,127,55,.08);
--warning:#9a6700;
--warning-soft:rgba(154,103,0,.1);
--orange:#bc4c00;
--orange-soft:rgba(188,76,0,.08);
--shadow:0 1px 0 rgba(31,35,40,.04),0 8px 24px rgba(140,149,159,.15);
--focus:0 0 0 3px rgba(9,105,218,.3);
}
html,body{height:100vh;overflow:hidden}
body{
font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','PingFang SC','Microsoft YaHei',sans-serif;
background:var(--bg);
color:var(--text);
font-size:13px;
line-height:1.5;
-webkit-font-smoothing:antialiased;
-moz-osx-font-smoothing:grayscale;
}
button,input,select{font:inherit;color:inherit}
::selection{background:var(--accent-soft);color:var(--text-strong)}
::-webkit-scrollbar{width:8px;height:8px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:var(--line-strong);border-radius:999px}
::-webkit-scrollbar-thumb:hover{background:var(--muted-2)}
/* ============ 主布局 ============ */
.app-shell{
display:grid;
grid-template-columns:300px minmax(0,1fr);
height:100vh;
min-width:1080px;
overflow:hidden;
}
.left{
background:var(--surface);
border-right:1px solid var(--line);
display:flex;
flex-direction:column;
min-width:0;
min-height:0;
overflow:hidden;
}
.right{
display:flex;
flex-direction:column;
min-width:0;
min-height:0;
overflow:hidden;
}
/* ============ 品牌区 ============ */
.brand{
display:flex;
align-items:center;
justify-content:space-between;
gap:12px;
padding:16px 18px;
border-bottom:1px solid var(--line);
}
.brand h1{
font-size:15px;
font-weight:600;
color:var(--text-strong);
letter-spacing:-.01em;
}
.brand-sub{
font-size:11px;
color:var(--muted);
margin-top:3px;
letter-spacing:.02em;
}
/* ============ 商品侧栏 ============ */
.left-header{
padding:14px 16px;
border-bottom:1px solid var(--line);
display:flex;
flex-direction:column;
gap:10px;
}
.product-actions{display:flex;gap:6px;align-items:center}
.product-actions .btn-primary{flex:1}
.product-search{
display:flex;
align-items:center;
gap:8px;
background:var(--field);
border:1px solid var(--line);
border-radius:var(--radius-sm);
padding:0 10px;
transition:.15s;
}
.product-search:focus-within{border-color:var(--accent);box-shadow:var(--focus)}
.product-search input{
flex:1;
min-width:0;
height:32px;
border:0;
outline:0;
background:transparent;
font-size:13px;
}
.product-search input::placeholder{color:var(--muted-2)}
.search-icon{color:var(--muted-2);font-size:13px}
.product-search .search-clear{
width:20px;height:20px;
border:0;border-radius:4px;
background:transparent;color:var(--muted);
cursor:pointer;font-size:14px;
display:none;
align-items:center;justify-content:center;
}
.product-search .search-clear:hover{background:var(--surface-3);color:var(--text-strong)}
.selected-product-card{
padding:12px;
border:1px solid var(--line);
border-radius:var(--radius);
background:var(--surface-2);
}
.selected-product-card.has-product{
border-color:var(--accent-border);
background:var(--accent-soft);
}
.selected-product-label{
font-size:10px;
color:var(--muted);
font-weight:600;
text-transform:uppercase;
letter-spacing:.08em;
margin-bottom:6px;
}
.selected-product-name{
font-size:13px;
color:var(--text-strong);
font-weight:600;
line-height:1.4;
word-break:break-all;
}
.selected-product-meta{
display:flex;
gap:6px;
flex-wrap:wrap;
margin-top:8px;
}
.product-meta{
font-size:11px;
color:var(--muted);
padding:0 2px;
}
.product-meta.good{color:var(--success)}
.product-meta.warn{color:var(--warning)}
.left-list{
flex:1;
overflow-y:auto;
padding:6px 8px 12px;
}
.prod-item{
display:grid;
grid-template-columns:40px minmax(0,1fr);
gap:10px;
padding:8px 10px;
margin:2px 0;
border-radius:var(--radius-sm);
cursor:pointer;
border:1px solid transparent;
transition:.12s;
position:relative;
}
.prod-item:hover{background:var(--surface-2)}
.prod-item.active{
background:var(--accent-soft);
border-color:var(--accent-border);
}
.prod-item img{
width:40px;height:40px;
border-radius:var(--radius-sm);
object-fit:cover;
background:var(--field);
border:1px solid var(--line);
}
.pinfo{min-width:0;display:flex;flex-direction:column;justify-content:center;gap:4px}
.pname{
font-size:12.5px;
font-weight:500;
color:var(--text-strong);
white-space:nowrap;
overflow:hidden;
text-overflow:ellipsis;
line-height:1.3;
}
.pmeta{
font-size:11px;
color:var(--muted);
display:flex;
gap:6px;
flex-wrap:wrap;
}
.chip{
display:inline-flex;
align-items:center;
gap:3px;
padding:1px 7px;
border-radius:999px;
background:var(--surface-3);
font-size:11px;
font-weight:500;
white-space:nowrap;
color:var(--muted);
}
.chip-score{color:var(--warning);background:var(--warning-soft)}
.chip-stock{color:var(--success);background:var(--success-soft)}
.chip-stock.low{color:var(--danger);background:var(--danger-soft)}
.empty-state{
text-align:center;
color:var(--muted);
padding:48px 16px;
font-size:12px;
line-height:1.7;
}
/* ============ 顶部控制台 ============ */
.console-head{
padding:14px 20px;
border-bottom:1px solid var(--line);
background:var(--surface);
display:flex;
align-items:center;
justify-content:space-between;
gap:16px;
}
.headline{display:flex;align-items:center;gap:14px;min-width:0}
.headline-title{
font-size:15px;
font-weight:600;
color:var(--text-strong);
letter-spacing:-.01em;
}
.headline-meta{
font-size:12px;
color:var(--muted);
margin-top:2px;
}
.top-actions{display:flex;align-items:center;gap:6px}
.countdown-badge{
display:inline-flex;
align-items:center;
padding:4px 10px;
border-radius:999px;
background:var(--danger-soft);
color:var(--danger);
border:1px solid var(--danger);
font-weight:600;
font-size:12px;
font-variant-numeric:tabular-nums;
}
/* ============ 状态指标条 ============ */
.status-grid{
display:flex;
gap:24px;
padding:12px 20px;
background:var(--surface);
border-bottom:1px solid var(--line);
align-items:center;
}
.metric{
display:flex;
align-items:baseline;
gap:6px;
min-width:0;
}
.metric-label{
font-size:11px;
color:var(--muted);
text-transform:uppercase;
letter-spacing:.06em;
font-weight:500;
}
.metric-value{
color:var(--text-strong);
font-weight:600;
font-size:14px;
font-variant-numeric:tabular-nums;
}
.metric-value.server{color:var(--accent)}
.metric-value.success-num{color:var(--success)}
.metric-value.fail-num{color:var(--danger)}
/* ============ 操作条 ============ */
.control-strip{
padding:12px 20px;
background:var(--surface);
border-bottom:1px solid var(--line);
display:flex;
align-items:center;
justify-content:space-between;
gap:16px;
flex-wrap:wrap;
}
.action-group{display:flex;gap:6px;align-items:center;flex-wrap:wrap}
.schedule-bar{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.schedule-item{
display:flex;
align-items:center;
gap:6px;
}
.schedule-bar label{
color:var(--muted);
font-size:12px;
white-space:nowrap;
}
.schedule-bar input{
height:30px;
padding:0 10px;
background:var(--field);
color:var(--text-strong);
border:1px solid var(--line);
border-radius:var(--radius-sm);
font-size:12.5px;
font-variant-numeric:tabular-nums;
transition:.15s;
}
.schedule-bar input:focus{outline:0;border-color:var(--accent);box-shadow:var(--focus)}
.schedule-bar input#targetTime{width:108px;text-align:center}
.schedule-bar input#advance{width:72px;text-align:center}
/* ============ 按钮 ============ */
.btn{
height:30px;
padding:0 12px;
border:1px solid var(--line);
border-radius:var(--radius-sm);
background:var(--surface-2);
color:var(--text);
cursor:pointer;
font-size:12.5px;
font-weight:500;
white-space:nowrap;
transition:.12s;
display:inline-flex;
align-items:center;
justify-content:center;
gap:6px;
}
.btn:hover{background:var(--surface-3);border-color:var(--line-strong)}
.btn:focus-visible{outline:0;box-shadow:var(--focus)}
.btn:disabled{opacity:.55;cursor:not-allowed}
.btn-primary{
background:var(--accent);
border-color:var(--accent);
color:#fff;
}
.btn-primary:hover{filter:brightness(1.08);background:var(--accent)}
.btn-danger{
background:var(--danger);
border-color:var(--danger);
color:#fff;
}
.btn-danger:hover{filter:brightness(1.08);background:var(--danger)}
.btn-success{
background:var(--success);
border-color:var(--success);
color:#fff;
}
.btn-success:hover{filter:brightness(1.08);background:var(--success)}
.btn-cancel{
background:transparent;
color:var(--danger);
border-color:var(--danger);
}
.btn-cancel:hover{background:var(--danger-soft)}
.btn-ghost{background:transparent;border-color:transparent;color:var(--muted)}
.btn-ghost:hover{color:var(--text-strong);background:var(--surface-2);border-color:var(--line)}
.icon-btn{width:30px;padding:0;font-size:14px}
.btn-compact{height:26px;font-size:11.5px;padding:0 10px}
.stat-pill{
display:inline-flex;
align-items:center;
gap:6px;
height:24px;
padding:0 10px;
border:1px solid var(--line);
border-radius:999px;
background:var(--surface-2);
color:var(--muted);
font-size:11.5px;
font-variant-numeric:tabular-nums;
}
/* ============ 工作区 ============ */
.workspace{
display:grid;
grid-template-columns:minmax(0,1fr) 380px;
gap:14px;
padding:14px 20px 20px;
align-items:stretch;
flex:1;
min-height:0;
overflow:hidden;
}
.panel{
background:var(--surface);
border:1px solid var(--line);
border-radius:var(--radius);
min-width:0;
min-height:0;
display:flex;
flex-direction:column;
overflow:hidden;
height:100%;
}
.panel-head{
padding:10px 14px;
border-bottom:1px solid var(--line);
display:flex;
align-items:center;
justify-content:space-between;
gap:10px;
background:var(--surface);
}
.panel-title{
font-size:13px;
font-weight:600;
color:var(--text-strong);
}
.panel-sub{
font-size:11.5px;
color:var(--muted);
margin-left:8px;
font-weight:400;
}
.panel-head label.stat-pill{cursor:pointer}
.panel-head label.stat-pill input{margin:0;cursor:pointer}
/* ============ 账号表 ============ */
.table-wrap{flex:1;overflow:auto;min-height:0}
table{width:100%;border-collapse:separate;border-spacing:0;font-size:12.5px}
th{
background:var(--surface-2);
padding:8px 12px;
text-align:left;
border-bottom:1px solid var(--line);
position:sticky;
top:0;
z-index:1;
color:var(--muted);
font-size:11px;
font-weight:600;
text-transform:uppercase;
letter-spacing:.04em;
white-space:nowrap;
}
td{padding:9px 12px;border-bottom:1px solid var(--line);vertical-align:middle}
tbody tr:last-child td{border-bottom:0}
tbody tr{transition:.1s}
tbody tr:hover{background:var(--surface-2)}
.select-cell{width:36px}
.status-col{width:96px}
.account-name{font-weight:500;color:var(--text-strong)}
.account-sub{font-size:11px;color:var(--muted);margin-top:2px}
.account-check{display:inline-flex;align-items:center;cursor:pointer}
.check-box{
width:16px;height:16px;
border-radius:4px;
border:1.5px solid var(--line-strong);
background:transparent;
display:flex;align-items:center;justify-content:center;
transition:.15s;
color:#fff;
font-size:10px;
font-weight:700;
}
.check-box.checked{
border-color:var(--accent);
background:var(--accent);
}
.prod-tag{
display:inline-flex;
max-width:200px;
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
background:var(--surface-2);
color:var(--text);
border:1px solid var(--line);
padding:2px 8px;
border-radius:999px;
font-size:11.5px;
}
.status-badge{
display:inline-flex;
align-items:center;
padding:2px 8px;
border-radius:999px;
border:1px solid var(--line);
background:var(--surface-2);
font-size:11px;
font-weight:500;
white-space:nowrap;
}
.status-idle{color:var(--muted)}
.status-ready{color:var(--accent);background:var(--accent-soft);border-color:var(--accent-border)}
.status-success{color:var(--success);background:var(--success-soft);border-color:var(--success)}
.status-fail{color:var(--danger);background:var(--danger-soft);border-color:var(--danger)}
.status-warn{color:var(--warning);background:var(--warning-soft);border-color:var(--warning)}
.cred-ok{color:var(--success)}
.cred-miss{color:var(--danger)}
/* ============ 日志区 ============ */
.side-stack{
display:flex;
flex-direction:column;
gap:14px;
min-height:0;
height:100%;
}
.log-wrap{flex:1;min-height:0}
.log-header{
padding:8px 12px;
border-bottom:1px solid var(--line);
display:flex;
justify-content:space-between;
align-items:center;
gap:8px;
background:var(--surface);
}
.log-tabs{display:flex;gap:2px;align-items:center}
.log-tab{
height:26px;
padding:0 10px;
border-radius:var(--radius-sm);
border:0;
background:transparent;
color:var(--muted);
cursor:pointer;
font-size:11.5px;
font-weight:500;
transition:.12s;
}
.log-tab:hover{color:var(--text-strong);background:var(--surface-2)}
.log-tab.active{
background:var(--accent-soft);
color:var(--accent);
}
.log-panel{
display:none;
flex:1;
min-height:0;
overflow:auto;
padding:10px 12px;
font-family:'SF Mono','Monaco','Consolas','Courier New',monospace;
font-size:11.5px;
line-height:1.7;
background:var(--field);
}
.log-panel.active{display:block}
.log-s{color:var(--success)}
.log-e{color:var(--danger)}
.log-i{color:var(--accent)}
.log-w{color:var(--warning)}
.log-d{color:var(--muted-2)}
.log-result{
background:var(--surface);
padding:6px 9px;
margin:4px 0;
border-radius:var(--radius-sm);
word-break:break-all;
border:1px solid var(--line);
}
.log-cat{
display:inline-block;
min-width:32px;
text-align:center;
margin-right:6px;
padding:0 5px;
border:1px solid var(--line);
border-radius:3px;
color:var(--muted);
font-size:10px;
line-height:1.5;
background:var(--surface);
}
.result-empty{color:var(--muted);padding:14px 4px;font-style:italic}
/* ============ Toast ============ */
.toast-container{
position:fixed;
top:20px;
right:-420px;
z-index:9999;
transition:right .35s cubic-bezier(.16,1,.3,1);
}
.toast-container.show{right:20px}
.toast{
background:var(--surface);
border:1px solid var(--line);
border-left-width:3px;
border-radius:var(--radius);
padding:12px 14px;
margin-bottom:8px;
min-width:300px;
max-width:380px;
box-shadow:var(--shadow);
}
.toast-title{
font-size:12.5px;
font-weight:600;
margin-bottom:3px;
color:var(--text-strong);
}
.toast-body{
font-size:12px;
color:var(--muted);
line-height:1.6;
}
.toast-success{border-left-color:var(--success)}
.toast-success .toast-title{color:var(--success)}
.toast-info{border-left-color:var(--accent)}
.toast-info .toast-title{color:var(--accent)}
.toast-warn{border-left-color:var(--warning)}
.toast-warn .toast-title{color:var(--warning)}
.toast-error{border-left-color:var(--danger)}
.toast-error .toast-title{color:var(--danger)}
/* ============ Modal ============ */
.modal-overlay{
position:fixed;
inset:0;
background:rgba(0,0,0,.5);
z-index:9000;
display:none;
align-items:center;
justify-content:center;
backdrop-filter:blur(4px);
}
.modal-overlay.show{display:flex}
.modal{
background:var(--surface);
border:1px solid var(--line);
border-radius:var(--radius);
width:480px;
max-width:92vw;
max-height:85vh;
overflow-y:auto;
box-shadow:var(--shadow);
}
.modal-header{
display:flex;
align-items:center;
justify-content:space-between;
padding:14px 18px;
border-bottom:1px solid var(--line);
}
.modal-header h3{
font-size:14px;
font-weight:600;
color:var(--text-strong);
}
.modal-close{
width:28px;height:28px;
border:0;border-radius:var(--radius-sm);
background:transparent;color:var(--muted);
cursor:pointer;font-size:18px;
display:flex;align-items:center;justify-content:center;
}
.modal-close:hover{background:var(--surface-2);color:var(--text-strong)}
.modal-body{padding:18px}
.form-group{margin-bottom:14px}
.form-group:last-child{margin-bottom:0}
.form-label{
display:block;
font-size:12px;
font-weight:500;
color:var(--text);
margin-bottom:6px;
}
.form-hint{
font-size:11px;
color:var(--muted);
margin-top:4px;
line-height:1.5;
}
.form-row{display:flex;gap:12px}
.form-row .form-group{flex:1}
.form-input,.form-select{
width:100%;
height:32px;
padding:0 10px;
background:var(--field);
color:var(--text-strong);
border:1px solid var(--line);
border-radius:var(--radius-sm);
font-size:12.5px;
transition:.15s;
}
.form-input:focus,.form-select:focus{outline:0;border-color:var(--accent);box-shadow:var(--focus)}
.toggle-row{
display:flex;
align-items:center;
justify-content:space-between;
padding:6px 0;
}
.toggle-label{font-size:12.5px;color:var(--text-strong);font-weight:500}
.toggle{position:relative;width:36px;height:20px;cursor:pointer}
.toggle input{opacity:0;width:0;height:0}
.toggle-slider{
position:absolute;inset:0;
background:var(--line-strong);
border-radius:999px;
transition:.2s;
}
.toggle-slider::before{
content:"";
position:absolute;
left:2px;top:2px;
width:16px;height:16px;
background:#fff;
border-radius:50%;
transition:.2s;
}
.toggle input:checked+.toggle-slider{background:var(--accent)}
.toggle input:checked+.toggle-slider::before{transform:translateX(16px)}
.modal-footer{
padding:12px 18px;
border-top:1px solid var(--line);
display:flex;
justify-content:flex-end;
gap:8px;
}
/* ============ 响应式 ============ */
@media (max-width: 1180px){
html,body{height:auto;overflow:auto}
.app-shell{display:block;min-width:0;height:auto;overflow:visible}
.left{height:auto;overflow:visible;border-right:0;border-bottom:1px solid var(--line)}
.left-list{max-height:280px}
.right{overflow:visible;min-height:auto}
.status-grid{flex-wrap:wrap;gap:14px 24px}
.control-strip{flex-direction:column;align-items:stretch}
.schedule-bar{justify-content:flex-end}
.workspace{grid-template-columns:1fr;padding:14px;overflow:visible}
.table-wrap{max-height:520px}
.log-wrap{height:360px}
.toast-container{left:12px;right:12px;top:12px}
.toast-container.show{right:12px}
.toast{min-width:0;width:100%;max-width:none}
}