feat(Tab设置+UI主题): 迭代09 Tab设置统一管理 + 迭代10 UI适配DSH主题

迭代09 (R-011): Tab 设置统一管理所有会话 tab
- settings.tabs 布尔对象 → 统一有序数组 (kind: builtin|strategy)
- 旧配置 schema union 兼容 + 读取归一化无感迁移
- strategies 收窄为 {id,name},策略行 name join 自动跟随改名
- 策略增删联动 tabs 条目 (add 追加末尾 / remove 联动删除)
- 客户端统一注册读 tabs 数组,内置与策略可任意混排
- 设置页 Tab 设置子 tab:混排表格 + 拖动手柄 + 显隐开关 + 落点立即持久化
- 策略分组瘦身:仅 新增/重命名/删除 + 指引提示
- 回归测试: test-r011-tabs (23) + test-r011-api (12)

迭代10 (R-012): UI 适配 DSH 浅色/深色/跟随系统主题
- 10 个视图文件 141 处硬编码色 → var(--dsw-alias-*, fallback)
- 语义映射: bg-layer/label/border/state/button-contrast 等
- 淡底 color-mix 自适应;遮罩 bg-mask-1;阴影 shadow-lv3
This commit is contained in:
2026-09-02 14:00:56 +08:00
parent 35f2ad1a23
commit 4ac8a29805
15 changed files with 629 additions and 385 deletions
+13 -13
View File
@@ -21,18 +21,18 @@ function MenuItem({ item, selected, onSelect }) {
onClick={() => onSelect(item)}
style={{
display: 'flex', alignItems: 'center', gap: 8, width: '100%', textAlign: 'left',
padding: '8px 12px', border: 'none', cursor: 'pointer', background: selected ? '#e8f5e9' : 'transparent',
fontSize: 13, color: '#333',
padding: '8px 12px', border: 'none', cursor: 'pointer', background: selected ? 'color-mix(in srgb, var(--dsw-alias-state-success-primary, #2e7d32) 12%, var(--dsw-alias-bg-layer-1, #fff))' : 'transparent',
fontSize: 13, color: 'var(--dsw-alias-label-primary, #333)',
}}
onMouseEnter={(e) => { if (!selected) e.currentTarget.style.background = '#f5f5f5'; }}
onMouseEnter={(e) => { if (!selected) e.currentTarget.style.background = 'var(--dsw-alias-interactive-bg-hover, #f5f5f5)'; }}
onMouseLeave={(e) => { if (!selected) e.currentTarget.style.background = 'transparent'; }}
>
<span style={{ width: 16, flex: 'none', color: '#2e7d32', fontWeight: 700 }}>{selected ? '✓' : ''}</span>
<span style={{ width: 16, flex: 'none', color: 'var(--dsw-alias-state-success-primary, #2e7d32)', fontWeight: 700 }}>{selected ? '✓' : ''}</span>
<span style={{ flex: 1, minWidth: 0 }}>
<span style={{ display: 'block', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{item.name}</span>
<span style={{ display: 'block', fontSize: 11, color: '#999', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{item.baseUrl}</span>
<span style={{ display: 'block', fontSize: 11, color: 'var(--dsw-alias-label-tertiary, #999)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{item.baseUrl}</span>
</span>
{item.isDefault && <span style={{ flex: 'none', fontSize: 11, color: '#1565c0', border: '1px solid #90caf9', borderRadius: 8, padding: '0 6px' }}>默认</span>}
{item.isDefault && <span style={{ flex: 'none', fontSize: 11, color: 'var(--dsw-alias-state-business-primary, #1565c0)', border: '1px solid var(--dsw-alias-border-l3, #90caf9)', borderRadius: 8, padding: '0 6px' }}>默认</span>}
</button>
);
}
@@ -75,7 +75,7 @@ function QmtHealthIndicator() {
}, [load]);
// 状态推导:null=灰(未知/加载中),healthy=true=绿,false=红
const color = health === null ? '#bbb' : (health.healthy ? '#2e7d32' : '#d32f2f');
const color = health === null ? 'var(--dsw-alias-label-tertiary, #bbb)' : (health.healthy ? 'var(--dsw-alias-state-success-primary, #2e7d32)' : 'var(--dsw-alias-state-error-primary, #d32f2f)');
const title = health === null
? 'QMT 健康状态获取中…(点击立即检测)'
: (health.healthy
@@ -91,7 +91,7 @@ function QmtHealthIndicator() {
style={{
display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
width: 10, height: 10, borderRadius: '50%', background: color, flex: 'none',
boxShadow: color !== '#bbb' ? '0 0 4px ' + color : 'none',
boxShadow: health === null ? 'none' : '0 0 4px ' + color,
cursor: 'pointer',
opacity: refreshing ? 0.5 : 1,
transition: 'opacity .2s',
@@ -181,13 +181,13 @@ function ChipInner() {
role="menu"
style={{
position: 'absolute', top: 'calc(100% + 4px)', right: 0, zIndex: 10001,
minWidth: 220, maxWidth: 300, background: '#fff', border: '1px solid #ddd',
borderRadius: 8, boxShadow: '0 4px 16px rgba(0,0,0,0.15)', padding: '4px 0',
minWidth: 220, maxWidth: 300, background: 'var(--dsw-alias-bg-layer-1, #fff)', border: '1px solid var(--dsw-alias-border-l2, #ddd)',
borderRadius: 8, boxShadow: 'var(--dsw-shadow-lv3, 0 4px 16px rgba(0,0,0,0.15))', padding: '4px 0',
}}
>
<div style={{ padding: '4px 12px', fontSize: 11, color: '#999' }}>切换 QMT 连接</div>
<div style={{ padding: '4px 12px', fontSize: 11, color: 'var(--dsw-alias-label-tertiary, #999)' }}>切换 QMT 连接</div>
{state.list.length === 0 ? (
<div style={{ padding: '10px 12px', fontSize: 12, color: '#888' }}>
<div style={{ padding: '10px 12px', fontSize: 12, color: 'var(--dsw-alias-label-secondary, #888)' }}>
暂无连接配置请进 设置 神之一手 QMT 连接配置 添加
</div>
) : (
@@ -200,7 +200,7 @@ function ChipInner() {
/>
))
)}
<div style={{ borderTop: '1px solid #eee', marginTop: 4, padding: '6px 12px', fontSize: 11, color: '#999' }}>
<div style={{ borderTop: '1px solid var(--dsw-alias-border-l1, #eee)', marginTop: 4, padding: '6px 12px', fontSize: 11, color: 'var(--dsw-alias-label-tertiary, #999)' }}>
管理配置请进 设置 神之一手 QMT 连接配置
</div>
</div>