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:
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* R-011 API 层集成测试:handleStrategy tabs 域(联动链路)
|
||||
* 独立内存 mock settings scope + mock manager,验证:
|
||||
* 1. tabs 端点:返回归一化后的统一数组
|
||||
* 2. tabs/update:整表更新(顺序 + 显隐)
|
||||
* 3. strategies/add:联动追加 tab 条目(末尾)
|
||||
* 4. strategies/remove:联动删除 tab 条目 + 清份额(manager)
|
||||
* 5. strategies/update:重命名(tabs 行 name join 跟随)
|
||||
* 纯内存,不触真实数据(技术约束-011)
|
||||
*/
|
||||
import { handleStrategy, STRATEGY_METHODS } from '../src/api/strategies.js';
|
||||
|
||||
let pass = 0, fail = 0;
|
||||
function assert(cond, msg) {
|
||||
if (cond) { pass++; console.log(" ✅ " + msg); }
|
||||
else { fail++; console.log(" ❌ " + msg); }
|
||||
}
|
||||
|
||||
/** 内存 mock scope */
|
||||
function makeScope(initial) {
|
||||
const store = structuredClone(initial ?? {});
|
||||
return {
|
||||
get: () => structuredClone(store),
|
||||
update: async (patch) => { Object.assign(store, structuredClone(patch)); },
|
||||
};
|
||||
}
|
||||
|
||||
const scope = makeScope({
|
||||
strategies: [{ id: "grid-supermarket", name: "网格超市" }],
|
||||
tabs: [
|
||||
{ id: "tab-all", kind: "builtin", refKey: "allPositions", name: "全部持仓", visible: true, order: 0 },
|
||||
{ id: "tab-g", kind: "strategy", refId: "grid-supermarket", name: "网格超市", visible: true, order: 1 },
|
||||
],
|
||||
});
|
||||
const cleared = [];
|
||||
const manager = {
|
||||
async clearStrategyShares(id) { cleared.push(id); },
|
||||
};
|
||||
const runtime = { manager, settings: scope };
|
||||
|
||||
// 1. tabs 端点
|
||||
console.log("\n[1] tabs 端点");
|
||||
const tabs1 = await handleStrategy("tabs", {}, runtime);
|
||||
assert(Array.isArray(tabs1) && tabs1.length === 2, "tabs 返回统一数组");
|
||||
assert(tabs1[0].kind === "builtin" && tabs1[1].kind === "strategy", "内置 + 策略混排");
|
||||
|
||||
// 2. tabs/update 整表更新
|
||||
console.log("\n[2] tabs/update 整表更新");
|
||||
const afterUpdate = await handleStrategy("tabs/update", { tabs: [
|
||||
{ id: "tab-g", kind: "strategy", refId: "grid-supermarket", name: "网格超市", visible: false, order: 0 },
|
||||
{ id: "tab-all", kind: "builtin", refKey: "allPositions", name: "全部持仓", visible: true, order: 1 },
|
||||
] }, runtime);
|
||||
assert(afterUpdate[0].id === "tab-g" && afterUpdate[0].visible === false, "策略 tab 排到前面且隐藏");
|
||||
assert(afterUpdate[1].id === "tab-all", "内置 tab 排后");
|
||||
|
||||
// 3. strategies/add 联动追加 tab
|
||||
console.log("\n[3] strategies/add 联动追加 tab");
|
||||
const added = await handleStrategy("strategies/add", { name: "长线持有" }, runtime);
|
||||
const tabsAfterAdd = await handleStrategy("tabs", {}, runtime);
|
||||
assert(tabsAfterAdd.length === 3, "add 后 tabs 联动新增一条");
|
||||
assert(tabsAfterAdd[2].kind === "strategy" && tabsAfterAdd[2].refId === added.id, "新策略 tab 追加末尾");
|
||||
assert(tabsAfterAdd[2].name === "长线持有", "新策略 tab name 正确");
|
||||
|
||||
// 4. strategies/remove 联动删除 tab + 清份额
|
||||
console.log("\n[4] strategies/remove 联动删除 tab");
|
||||
await handleStrategy("strategies/remove", { strategyId: "grid-supermarket" }, runtime);
|
||||
const tabsAfterRm = await handleStrategy("tabs", {}, runtime);
|
||||
assert(!tabsAfterRm.some((t) => t.refId === "grid-supermarket"), "删除策略后对应 tab 条目消失");
|
||||
assert(tabsAfterRm.some((t) => t.refId === added.id), "其余策略 tab 保留");
|
||||
assert(cleared.includes("grid-supermarket"), "manager.clearStrategyShares 被调用(份额回未分配)");
|
||||
|
||||
// 5. strategies/update 重命名(tabs 行 join 跟随)
|
||||
console.log("\n[5] strategies/update 重命名跟随");
|
||||
await handleStrategy("strategies/update", { strategies: [
|
||||
{ id: added.id, name: "长线持有v2" },
|
||||
] }, runtime);
|
||||
const tabsAfterRename = await handleStrategy("tabs", {}, runtime);
|
||||
assert(tabsAfterRename.find((t) => t.refId === added.id).name === "长线持有v2", "重命名后 tabs 行 name join 跟随(Q4)");
|
||||
|
||||
// 6. 端点表不含 strategies/move
|
||||
console.log("\n[6] strategies/move 已废弃");
|
||||
assert(!STRATEGY_METHODS.has("strategies/move"), "STRATEGY_METHODS 不含 strategies/move");
|
||||
|
||||
console.log("\n结果: " + pass + " 通过 / " + fail + " 失败");
|
||||
if (fail > 0) process.exit(1);
|
||||
Reference in New Issue
Block a user