# 迭代 02 实施步骤规划(分步执行) > 2026-08-28 | 按步骤分批推进,每步有独立产出与验证点 > 关联:技术实现方案.md、程序结构设计.md(02)、R-003(已定稿) ## 总览 | 步骤 | 内容 | 产出 | 验证点 | 依赖 | |---|---|---|---|---| | S1 | 服务端:策略 CRUD 逻辑(settings.js) | id 生成/增删改排序 + 删除联动 | 单元验证:slug 生成、CRUD、删除清份额 | - | | S2 | 服务端:存储清份额(storage.js) | removeStrategyShares/clearStrategy | 清空后 allocations.json 正确 | S1 | | S3 | 服务端:分仓快捷逻辑(manager.js) | 全部移入/清空策略份额 | 单元验证:未分配全部移入、清零 | S2 | | S4 | 服务端:API 新端点(api.js) | strategies/add、remove、move、remove-all-shares | 端点调用正确 + 错误码 | S1-S3 | | S5 | 客户端:基础组件(LoadState/Toast) | 三态加载 + 轻提示 | 组件渲染正确 | - | | S6 | 客户端:SettingsSection CRUD | 新增/重命名/删除(确认)/排序/显隐 UI | UI 操作正确 + 服务端联动 | S4+S5 | | S7 | 客户端:tab 动态注册(index.js) | 策略配置驱动 tabs + 手动刷新提示 | tab 随设置变化 + 提示出现 | S4+S5 | | S8 | 客户端:StrategyTab 快捷操作 | 全部移入/一键清零 | 操作正确 + 确认弹窗 + Toast | S4+S5 | | S9 | 构建 + 安装 + 联调验收 | 全链路 | 对照验收标准.md | S1-S8 | ## 分步细节 ### S1:服务端策略 CRUD(settings.js) - `generateStrategyId(name)`:slug 化(去空格/转小写/非英文转拼音或序号兜底) - `addStrategy / renameStrategy / removeStrategy / moveStrategy` - removeStrategy 联动:删除策略 + 调 storage.removeStrategyShares - **验证**:Node 直接调用,验证 slug 生成、CRUD 后 settings 值正确、删除后份额清空 ### S2:服务端存储清份额(storage.js) - `removeStrategyShares(strategyId)`:遍历 allocations,删除该 strategyId,原子保存 - `clearStrategy(strategyId)`:同 removeStrategyShares(供一键清零复用) - **验证**:构造数据 → 清空 → 文件正确 ### S3:服务端分仓快捷逻辑(manager.js) - `moveAllUnallocatedToStrategy(code, strategyId)`:未分配 = volume - 已分配,全部 add - `clearStrategyShares(strategyId)`:清空该策略全部份额,返回影响的标的列表 - **验证**:真实/模拟持仓数据,全部移入后未分配归零、清零后份额归零 ### S4:服务端 API 新端点(api.js) - `strategies/add`:{ name } → 新增策略 - `strategies/remove`:{ strategyId } → 删除 + 清份额 - `strategies/move`:{ strategyId, dir } → 排序 - `remove-all-shares`:{ strategyId } → 一键清零 - 全部移入复用 add-shares(服务端算未分配 or 客户端传) - **验证**:HTTP 调用各端点,200 + 正确返回;错误码(strategy-not-found 等) ### S5:客户端基础组件(LoadState.jsx / Toast.jsx) - LoadState:loading / error(原因+重试) / success 三态;自动重试 2 次(间隔 2s) - Toast:success(绿) / error(红),3s 自动消失 - **验证**:组件在 tab 中渲染正确(可临时构造 error 态验证) ### S6:客户端 SettingsSection CRUD(O3) - 新增:名称输入 + 按钮 → strategies/add - 重命名:行内编辑 → strategies/update - 删除:确认弹窗(提示份额回未分配)→ strategies/remove - 排序:上移/下移 → strategies/move - 显隐开关保留 - 操作后 Toast 反馈 + 触发「策略已变更」事件(供 S7) - **验证**:完整 CRUD 操作路径 ### S7:客户端 tab 动态注册(O2) - index.js:loadStrategies() → 动态注册策略 tabs(visible=true) - 全部持仓 tab 固定 - 提示「刷新页面后生效」(方案 X);优化项:会话切换自动重拉(方案 Y) - **验证**:增删/隐藏策略后刷新,tab 栏正确变化 ### S8:客户端 StrategyTab 快捷操作(O6) - 行内「全部移入」→ add-shares(shares=未分配) - 顶部「一键清零」→ 确认弹窗 → remove-all-shares - Toast 反馈 + reload - **验证**:操作后份额正确、未分配正确变化 ### S9:构建 + 安装 + 联调验收 - pnpm build(tsdown + wrap-client.mjs) - dsh plugin add 更新安装 - 对照验收标准.md 全链路验收(含断 QMT 验证 O5、CRUD 验证 O3、tab 验证 O2、快捷操作验证 O6) ## 建议执行批次 - **批次 1(S1-S3)**:服务端核心逻辑(策略 CRUD + 清份额 + 快捷分仓)—— 纯服务端可独立验证 - **批次 2(S4)**:服务端 API 端点 —— 打通 HTTP 通道 - **批次 3(S5-S6)**:客户端基础组件 + 设置 CRUD UI - **批次 4(S7-S8)**:客户端 tab 动态化 + 快捷操作 —— 全链路 UI - **批次 5(S9)**:构建安装 + 联调验收 ## 前置技术确认(编码前) 1. ~~slots.unregister 能力~~ → **已确认**:`ctx.slots.register()` 返回 disposer 函数(SlotCore.register 的 return),可注销 entry;动态 tab 注册/注销可行 2. ~~客户端跨组件事件实现方式~~ → **已确认**:无事件机制。设置页保存后就地提示「刷新页面后生效」;tab 更新 = 刷新页面 → 插件重载 → 重新注册(方案 X;方案 Y 会话切换自动更新为优化项) 3. settings scope 更新后的 watch 机制(是否需要监听策略变更) ## 执行进度(2026-08-28) ### ✅ 批次 1-2(S1-S4)服务端已完成并验证 | 步骤 | 状态 | 验证结果 | |---|---|---| | S1 策略 CRUD(settings.js) | ✅ 完成 | slug 生成(长线持有→long-term-hold、网格超市→grid-supermarket、去重→-2)、增删改排序单元测试通过 | | S2 存储清份额(storage.js) | ✅ 完成 | removeStrategyShares 清空策略份额正确(受影响标的列表、记录清理) | | S3 分仓快捷逻辑(manager.js) | ✅ 完成 | 全部移入(未分配 700→1200)、无未分配报错(no-unallocated)、一键清零通过 | | S4 API 新端点(api.js) | ✅ 完成 | strategies/add、remove(联动清份额)、move、move-all-shares、remove-all-shares 全部 HTTP 验证通过 | ### ✅ 批次 3-4(S5-S8)客户端已完成,构建通过 | 步骤 | 状态 | 说明 | |---|---|---| | S5 基础组件 | ✅ 完成 | LoadState.jsx(三态+自动重试2次+手动重试)、Toast.jsx(成功绿/失败红,3s) | | S6 SettingsSection CRUD | ✅ 完成 | 新增/重命名/删除(确认弹窗)/排序/显隐 + 就地「刷新后生效」提示 | | S7 tab 动态注册 | ✅ 完成 | 策略配置驱动注册(slots.register 返回 disposer),全部持仓固定,隐藏策略不注册 | | S8 StrategyTab 快捷操作 | ✅ 完成 | 全部移入(行内)、一键清零(确认弹窗)、LoadState 兜底 | ### 🔄 S9 构建安装 + 联调验收(进行中) | 项 | 状态 | 验证结果 | |---|---|---| | pnpm build | ✅ 完成 | 客户端 bundle 41KB + 服务端 14 模块,lib 产物集成测试通过 | | 宿主加载 | ✅ 完成 | 客户端模块清单含 one-divine-lot(rev a238b5fa84d1),bundle 为新版本(41KB) | | 服务端 API 真实验证 | ✅ 完成 | 新端点全部可用:add/move/remove(联动清份额)/move-all-shares/remove-all-shares | | 快捷操作真实验证 | ✅ 完成 | 全部移入(603028.SH 未分配800→manual-t)、一键清零(manual-t 清零)验证通过,数据已恢复 | | UI 视觉验证 | ⏳ 待老师确认 | 需在浏览器实际查看 tab 动态化、设置 CRUD、快捷操作(当前环境无法自动化浏览器) | ### 待老师确认的 UI 验收项 1. 主窗口 tab 栏:只显示「手动做T」(网格超市 visible=false 不显示)—— O2 动态 tab 2. 设置页「神之一手」:策略 CRUD(新增/重命名/删除弹窗/排序/显隐)+「刷新页面后生效」提示 3. 策略 tab:全部移入(行内)、一键清零(弹窗)、Toast 反馈 4. 加载失败:LoadState 重试(可临时断 QMT 验证)