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:
@@ -42,9 +42,9 @@ function fmtNum(v, digits = 2) {
|
||||
|
||||
/** 方向样式:红买绿卖 */
|
||||
function directionStyle(direction) {
|
||||
if (direction === 'buy') return { color: '#d32f2f', fontWeight: 'bold' };
|
||||
if (direction === 'sell') return { color: '#2e7d32', fontWeight: 'bold' };
|
||||
return { color: '#999' };
|
||||
if (direction === 'buy') return { color: 'var(--dsw-alias-state-error-primary, #d32f2f)', fontWeight: 'bold' };
|
||||
if (direction === 'sell') return { color: 'var(--dsw-alias-state-success-primary, #2e7d32)', fontWeight: 'bold' };
|
||||
return { color: 'var(--dsw-alias-label-tertiary, #999)' };
|
||||
}
|
||||
function directionText(direction) {
|
||||
if (direction === 'buy') return '买入';
|
||||
@@ -309,7 +309,7 @@ export function TradeRecordsTab() {
|
||||
<select
|
||||
value={strategyFilter}
|
||||
onChange={(e) => setStrategyFilter(e.target.value)}
|
||||
style={{ fontSize: 12, padding: '2px 6px', border: '1px solid #ccc', borderRadius: 4, color: '#555' }}
|
||||
style={{ fontSize: 12, padding: '2px 6px', border: '1px solid var(--dsw-alias-border-l2, #ccc)', borderRadius: 4, color: 'var(--dsw-alias-label-secondary, #555)' }}
|
||||
title="按策略过滤"
|
||||
>
|
||||
<option value="">全部策略</option>
|
||||
@@ -322,14 +322,14 @@ export function TradeRecordsTab() {
|
||||
</div>
|
||||
</div>
|
||||
{attributionSaved && (
|
||||
<div style={{ marginBottom: 8, fontSize: 12, color: attributionSaved.startsWith('保存失败') ? '#c62828' : '#1b5e20', background: attributionSaved.startsWith('保存失败') ? '#fdecea' : '#e8f5e9', padding: '4px 8px', borderRadius: 4 }}>
|
||||
<div style={{ marginBottom: 8, fontSize: 12, color: attributionSaved.startsWith('保存失败') ? 'var(--dsw-alias-state-error-primary, #c62828)' : 'var(--dsw-alias-state-success-primary, #1b5e20)', background: attributionSaved.startsWith('保存失败') ? 'color-mix(in srgb, var(--dsw-alias-state-error-primary, #c62828) 10%, var(--dsw-alias-bg-layer-1, #fff))' : 'color-mix(in srgb, var(--dsw-alias-state-success-primary, #2e7d32) 10%, var(--dsw-alias-bg-layer-1, #fff))', padding: '4px 8px', borderRadius: 4 }}>
|
||||
{attributionSaved}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<LoadState loading={loading && !orders} error={error} onRetry={load} autoRetry={2}>
|
||||
{!orders?.length ? (
|
||||
<div style={{ padding: 32, textAlign: 'center', color: '#999' }}>
|
||||
<div style={{ padding: 32, textAlign: 'center', color: 'var(--dsw-alias-label-tertiary, #999)' }}>
|
||||
<div style={{ fontSize: 15, marginBottom: 8 }}>
|
||||
{range ? range.start + ' ~ ' + range.end + (isHistoryRange ? '(本地历史)' : '') : ''}
|
||||
</div>
|
||||
@@ -340,9 +340,9 @@ export function TradeRecordsTab() {
|
||||
) : (
|
||||
<TradeTable rows={rows} toggleSort={toggleSort} sortKey={sortKey} sortDir={sortDir} arrow={arrow} toggleExpand={toggleExpand} expanded={expanded} attributionCandidates={attributionCandidates} loadCandidates={loadCandidates} setAttribution={setAttribution} />
|
||||
)}
|
||||
<div style={{ marginTop: 8, fontSize: 12, color: '#999' }}>
|
||||
<span style={{ color: '#d32f2f' }}>■ 买</span>
|
||||
<span style={{ marginLeft: 8, color: '#2e7d32' }}>■ 卖</span>
|
||||
<div style={{ marginTop: 8, fontSize: 12, color: 'var(--dsw-alias-label-tertiary, #999)' }}>
|
||||
<span style={{ color: 'var(--dsw-alias-state-error-primary, #d32f2f)' }}>■ 买</span>
|
||||
<span style={{ marginLeft: 8, color: 'var(--dsw-alias-state-success-primary, #2e7d32)' }}>■ 卖</span>
|
||||
<span style={{ marginLeft: 12 }}>点击委托行展开成交明细 · 点击表头排序</span>
|
||||
{isHistoryRange && <span style={{ marginLeft: 12 }}>· 历史数据 = 本地积累</span>}
|
||||
</div>
|
||||
@@ -356,7 +356,7 @@ function TradeTable({ rows, toggleSort, sortKey, sortDir, arrow, toggleExpand, e
|
||||
return (
|
||||
<table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
|
||||
<thead>
|
||||
<tr style={{ textAlign: 'left', borderBottom: '2px solid #ddd' }}>
|
||||
<tr style={{ textAlign: 'left', borderBottom: '2px solid var(--dsw-alias-border-l2, #ddd)' }}>
|
||||
<th style={thStyle}> </th>
|
||||
<th onClick={() => toggleSort('insertTime')} style={thClickStyle}>时间{arrow('insertTime')}</th>
|
||||
<th onClick={() => toggleSort('code')} style={thClickStyle}>代码{arrow('code')}</th>
|
||||
@@ -404,9 +404,9 @@ function OrderRows({ order, expanded, onToggle, attributionCandidates, onLoadCan
|
||||
<tr
|
||||
onClick={onToggle}
|
||||
style={{
|
||||
borderBottom: '1px solid #eee',
|
||||
borderBottom: '1px solid var(--dsw-alias-border-l1, #eee)',
|
||||
cursor: hasTrades ? 'pointer' : 'default',
|
||||
background: expanded ? '#f5f5f5' : 'transparent',
|
||||
background: expanded ? 'var(--dsw-alias-interactive-bg-hover, #f5f5f5)' : 'transparent',
|
||||
}}
|
||||
>
|
||||
<td style={{ ...tdStyle, textAlign: 'center', width: 28 }}>
|
||||
@@ -420,7 +420,7 @@ function OrderRows({ order, expanded, onToggle, attributionCandidates, onLoadCan
|
||||
transition: 'transform .15s ease',
|
||||
transform: expanded ? 'rotate(90deg)' : 'rotate(0deg)',
|
||||
cursor: 'pointer',
|
||||
color: '#2e7d32',
|
||||
color: 'var(--dsw-alias-state-success-primary, #2e7d32)',
|
||||
verticalAlign: 'middle',
|
||||
}}
|
||||
>
|
||||
@@ -434,7 +434,7 @@ function OrderRows({ order, expanded, onToggle, attributionCandidates, onLoadCan
|
||||
/>
|
||||
</svg>
|
||||
) : (
|
||||
<span style={{ color: '#ccc', fontSize: 10 }}>·</span>
|
||||
<span style={{ color: 'var(--dsw-alias-border-l3, #ccc)', fontSize: 10 }}>·</span>
|
||||
)}
|
||||
</td>
|
||||
<td style={tdStyle}>{fmtTime(order.insertTime)}</td>
|
||||
@@ -461,11 +461,11 @@ function OrderRows({ order, expanded, onToggle, attributionCandidates, onLoadCan
|
||||
</td>
|
||||
</tr>
|
||||
{expanded && hasTrades && (
|
||||
<tr style={{ borderBottom: '1px solid #eee', background: '#fafafa' }}>
|
||||
<tr style={{ borderBottom: '1px solid var(--dsw-alias-border-l1, #eee)', background: 'var(--dsw-alias-bg-layer-2, #fafafa)' }}>
|
||||
<td colSpan={16} style={{ padding: '4px 8px 12px' }}>
|
||||
<table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 12, marginTop: 4 }}>
|
||||
<thead>
|
||||
<tr style={{ borderBottom: '1px solid #ddd', color: '#666' }}>
|
||||
<tr style={{ borderBottom: '1px solid var(--dsw-alias-border-l2, #ddd)', color: 'var(--dsw-alias-label-secondary, #666)' }}>
|
||||
<th style={{ ...tdStyle, textAlign: 'left' }}>成交时间</th>
|
||||
<th style={{ ...tdStyle, textAlign: 'right' }}>成交价</th>
|
||||
<th style={{ ...tdStyle, textAlign: 'right' }}>成交量</th>
|
||||
@@ -475,12 +475,12 @@ function OrderRows({ order, expanded, onToggle, attributionCandidates, onLoadCan
|
||||
</thead>
|
||||
<tbody>
|
||||
{order.trades.map((t) => (
|
||||
<tr key={t.tradeId} style={{ borderBottom: '1px solid #f0f0f0' }}>
|
||||
<tr key={t.tradeId} style={{ borderBottom: '1px solid var(--dsw-alias-border-l1, #f0f0f0)' }}>
|
||||
<td style={tdStyle}>{fmtTime(t.tradeTime)}</td>
|
||||
<td style={{ ...tdStyle, textAlign: 'right' }}>{fmtNum(t.price)}</td>
|
||||
<td style={{ ...tdStyle, textAlign: 'right' }}>{fmtNum(t.volume, 0)}</td>
|
||||
<td style={{ ...tdStyle, textAlign: 'right' }}>{fmtNum(t.amount)}</td>
|
||||
<td style={{ ...tdStyle, textAlign: 'right', color: '#999' }}>{t.tradeId}</td>
|
||||
<td style={{ ...tdStyle, textAlign: 'right', color: 'var(--dsw-alias-label-tertiary, #999)' }}>{t.tradeId}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
@@ -517,10 +517,10 @@ function AttributionSelect({ order, candidates, onLoadCandidates, setAttribution
|
||||
style={{
|
||||
fontSize: 12,
|
||||
padding: '2px 4px',
|
||||
border: '1px solid ' + (current ? '#2e7d32' : '#ccc'),
|
||||
border: '1px solid ' + (current ? 'var(--dsw-alias-state-success-primary, #2e7d32)' : 'var(--dsw-alias-border-l2, #ccc)'),
|
||||
borderRadius: 4,
|
||||
background: current ? '#e8f5e9' : '#fff',
|
||||
color: current ? '#1b5e20' : '#999',
|
||||
background: current ? 'color-mix(in srgb, var(--dsw-alias-state-success-primary, #2e7d32) 12%, var(--dsw-alias-bg-layer-1, #fff))' : 'var(--dsw-alias-bg-layer-1, #fff)',
|
||||
color: current ? 'var(--dsw-alias-state-success-primary, #1b5e20)' : 'var(--dsw-alias-label-tertiary, #999)',
|
||||
maxWidth: 120,
|
||||
}}
|
||||
title="设置该委托的策略归属(可随时修改)"
|
||||
|
||||
Reference in New Issue
Block a user