# 迭代 01 实施步骤规划(分步执行) > 2026-08-27 | 按步骤分批推进,每步有独立产出与验证点 > 关联:技术实现方案.md、程序结构设计.md ## 总览 | 步骤 | 内容 | 产出 | 验证点 | 依赖 | |---|---|---|---|---| | S1 | 插件骨架 | package.json + 目录 + 空 apply | 包可被识别 | - | | S2 | 数据源适配 | qmt-bridge-rest.js(REST 直连) | fetch QMT 返回真实数据 | S1 | | S3 | 设置管理 | settings.js(策略注册) | 设置中出现策略配置 | S1 | | S4 | 本地存储 | storage.js(allocations.json) | 读写持久化 | S1 | | S5 | 分仓逻辑 | manager.js(份额分配/聚合) | 单元验证分仓计算 | S2+S4 | | S6 | 服务端 RPC API | api.js(connection.rpc) | RPC 端点可调用 | S2+S3+S5 | | S7 | 客户端 tab | client/(conversation.view 注册) | tab 出现在对话/轨迹/上下文后 | S3+S6 | | S8 | 宿主挂载+联调 | cordis.patch.yml + 安装 | 全链路可用 + 验收 | S1-S7 | ## 分步细节 ### S1:插件骨架 - package.json:name/version/main/files + `dsh.client` 声明(web 平台) - 目录:src/、lib/、src/data-source/、src/position/、src/client/ - src/index.js:apply(ctx) 空实现 + name/inject/apply 导出 - **验证**:node 语法检查 + 包结构完整 ### S2:数据源适配(qmt-bridge-rest.js) - src/data-source/types.js:统一数据模型(Position/AssetSummary/DataSource 接口) - src/data-source/qmt-bridge-rest.js: - baseUrl 配置(默认 http://192.168.3.43:8610) - getPositions() / getAsset() / health() - 字段映射(语义字段优先,m_ 回退) - **验证**:独立脚本调用,返回真实持仓/资金数据(对齐快照) ### S3:设置管理(settings.js) - ctx.settings.register('one-divine-lot', schema) - 策略 schema:strategies: [{id, name, visible, order}] - 预置:网格超市、手动做T - **验证**:settings 可读取默认策略;更新后值变化 ### S4:本地存储(storage.js) - 路径:~/.dsh/one-divine-lot/allocations.json - load()/save()/get()/set() - 原子写(临时文件+rename) - **验证**:写入后文件存在,重启读回一致 ### S5:分仓逻辑(position/manager.js) - getAllPositions():全量持仓 - getStrategyPositions(strategyId):按分配份额过滤 - getSummary():各策略份额/市值/盈亏 + 未分配 - allocate():份额分配(校验和 ≤ 总持仓) - **验证**:单元测试分仓计算(如 1000 股 → 网格 600 + 做T 400) ### S6:服务端 RPC API(api.js) - ctx.connection.rpc.intercept('/api', matcher, handler) - 端点:strategies/positions/allocations/summary/strategy/:id/positions - **验证**:通过 DSH RPC 调用端点返回正确数据 ### S7:客户端 tab(client/) - client/index.js:读策略设置 → 注册 conversation.view entries - client/views/StrategyTab.jsx:渲染策略持仓(调 RPC API) - **验证**:tab 出现在对话/轨迹/上下文后,点击加载数据 ### S8:宿主挂载 + 联调验收 - cordis.patch.yml insert 插件行 - 插件安装到 profile(pnpm link 等) - 全链路验收(对照验收标准.md) ## 建议执行批次 - **批次 1(S1-S2)**:骨架 + 数据源 —— 打通「插件→QMT REST」数据读取(纯服务端,可独立验证) - **批次 2(S3-S5)**:设置 + 存储 + 分仓逻辑 —— 核心业务逻辑 - **批次 3(S6)**:RPC API —— 打通「服务端能力 → DSH 通道」 - **批次 4(S7-S8)**:客户端 tab + 宿主挂载 —— 全链路 UI 呈现 ## 前置技术确认(编码前) 1. conversation.view 注册签名(读 dsh-client-ui-conversation slots.d.ts) 2. 插件安装到 profile 的方式(pnpm link / 本地路径) 3. settings 注册在 host plane 的注入方式(ctx.settings 是否对插件可用) ## 执行进度(2026-08-27) ### ✅ 批次 1-2(S1-S4)已完成 | 步骤 | 状态 | 验证结果 | |---|---|---| | S1 插件骨架 | ✅ 完成 | package.json(dsh.client 声明)+ src/index.js 空入口,语法通过 | | S2 数据源适配 | ✅ 完成 | qmt-bridge-rest.js 真实调通 QMT REST:可用性✅、资金✅(总资产129,412.25)、持仓✅(12只,市值85,948) | | S3 设置管理 | ✅ 完成 | settings.js:默认策略(网格超市/手动做T)、可见过滤、排序,逻辑验证通过 | | S4 本地存储 | ✅ 完成 | storage.js:读写/持久化/覆盖/删除验证通过(1000股→网格600+做T400 校验通过) | ### 产出文件 - src/index.js(接入 S2-S4) - src/settings.js - src/storage.js - src/data-source/types.js - src/data-source/qmt-bridge-rest.js ### 下一步(批次 2 剩余 / 批次 3) - S5 分仓逻辑(position/manager.js) - S6 服务端 RPC API(connection.rpc) - S7-S8 客户端 + 宿主挂载 ### ✅ S5 已完成(2026-08-27) | 项 | 结果 | |---|---| | S5 分仓逻辑 | ✅ 完成 position/manager.js:全量持仓/策略持仓/未分配/添加/移出/摘要 | | 验证 | ✅ 真实 QMT 数据:添加(600+400)、超限拦截(>1800拒绝)、移出(400→200)、移出超限拦截、摘要(份额汇总+未分配=1000)全部通过 | | 设计依据 | S5 讨论定稿(Q1股数/Q2允许未分配/Q3人为分组/Q4无统计/Q5策略tab内编辑) | ### 待办(批次 3-4) - S6 服务端 RPC API(connection.rpc) - S7 客户端 tab(全部持仓/网格策略持仓/做T持仓) - S8 宿主挂载 + 联调验收 ### ✅ S6 已完成(2026-08-27) | 项 | 结果 | |---|---| | S6 服务端 RPC API | ✅ 完成 src/api.js:connection.rpc.intercept('/api') 暴露 8 个端点 | | 端点 | positions / strategies / strategy-positions / unallocated / summary / add-shares / remove-shares(+ 未知端点错误) | | 验证 | ✅ 全部端点回归通过;错误码精确(share-limit / share-exceed / unknown-endpoint) | | 模式 | 参照 dsh-api-gateway:intercept('/api', matcher, handler, {authority:'trusted-host'}),RpcResult 格式 {ok, value}/{ok:false, error} | ### 待办(批次 4) - S7 客户端 tab(全部持仓/网格策略持仓/做T持仓) - S8 宿主挂载 + 联调验收 ### 🔄 S7 客户端 tab(部分完成,2026-08-27) **已完成**: - src/client/index.js:客户端插件入口(inject slots/connection,注册 3 个 conversation.view tab:全部持仓/网格策略持仓/做T持仓) - src/client/views/AllPositionsTab.jsx:全部持仓组件(全量+份额标注) - src/client/views/StrategyTab.jsx:策略持仓组件(添加/移出交互) - src/client/views/connection.js:RPC 调用 hook **待完成**: - 构建配置(tsdown/tsconfig + 客户端依赖安装) - 客户端 bundle 构建 + 语法/类型验证 - 与宿主集成测试(S8 时统一) **关键约束**(S7 现实情况): - 客户端插件需要 react/slots/runtime 等依赖(peerDependencies),需安装; - JSX 需要构建工具(tsdown)处理成浏览器 bundle; - 构建环境与宿主挂载(S8)联动,建议 S7+S8 一起验收; - 客户端代码的完整运行验证依赖 DSH web 宿主重启加载。 ### ✅ S7-S8 已完成(2026-08-28) | 项 | 状态 | |---|---| | S7 客户端 tab | ✅ 完成:全部持仓/网格策略持仓/做T持仓 三个 conversation.view tab | | S7 设置菜单 | ✅ 完成:settings.section「神之一手」(策略列表 + 显示开关) | | S8 宿主挂载 | ✅ 完成:插件 link 到 web profile + bundles 加入 + bundle patch 挂载 | | 客户端 bundle | ✅ __ModuleLoader__.load 包装(scripts/wrap-client.mjs) | | 服务端 API | ✅ webServer /odl/api/* 路由(8 端点)—— 修正:不用 RPC(与 api-gateway 冲突) | ### 已解决的问题(实现过程中的关键坑) 1. **RPC 冲突**:/api 通道只能一个 interceptor(api-gateway 占用)→ 改用 webServer 自开路由 2. **slots.register 签名**:component 必须是第二参数 → React #130 崩溃 3. **客户端 bundle 格式**:必须 __ModuleLoader__.load 包装 4. **settings schema**:必须 schemastery z.object(函数式 schema) 5. **endpoint 前缀**:客户端传 one-divine-lot/* 需剥离 ### 验证结果(2026-08-28,真实 QMT 数据) - positions/summary/strategies/add-shares/remove-shares 全部 HTTP 200 - 12 只真实持仓显示正常(老师确认) - 份额添加/移除/持久化工作正常 - 分仓存储文件 allocations.json 已创建