Files
2026-08-29 16:20:33 +08:00

181 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 程序结构设计:02-分仓管理工具完善与优化
> 迭代设计 v2 的程序结构细化 2026-08-28
> 关联:技术实现方案.md(02)、R-003(已定稿)
## 一、整体目录结构(基于迭代 01 演进)
```
one_divine_lot/
├── package.json # 不变(已有 dsh.client 声明)
├── src/ # 源码(服务端 + 客户端)
│ ├── index.js # 插件入口:apply(ctx),组装各模块(少量调整)
│ ├── settings.js # 设置管理:策略 CRUD 逻辑扩展(新增 id 生成、删除联动)
│ ├── storage.js # 本地存储:allocations.json(新增:清空策略份额)
│ ├── api.js # 服务端 HTTP APIwebServer /odl/api/*):新增端点
│ ├── data-source/
│ │ ├── types.js # 不变
│ │ └── qmt-bridge-rest.js # 不变
│ ├── position/
│ │ └── manager.js # 分仓逻辑:新增全部移入/清空策略份额
│ └── client/
│ ├── index.js # 客户端入口:tab 动态注册(O2 核心改造)
│ └── views/
│ ├── AllPositionsTab.jsx # 加载失败兜底(O5
│ ├── StrategyTab.jsx # 全部移入/一键清零(O6)
│ ├── SettingsSection.jsx # 策略 CRUD 补全(O3
│ ├── connection.jsx # API 调用错误透出增强(O5)
│ ├── LoadState.jsx # 【新增】三态加载组件(O5)
│ └── Toast.jsx # 【新增】轻提示组件(O6/O3)
└── docs/ # 神之一手框架文档(既有)
```
## 二、模块职责与变更点
### 1. index.js(插件入口)
- 基本不变;新增:把「策略配置读取」能力暴露给 api(已由 settings 提供)
- 组装链保持:dataSource → settings → storage → manager → api
### 2. settings.js(设置管理)—— O3 核心
- **现有**registerSettings / getStrategies / getVisibleStrategies / updateStrategies
- **新增**
- `generateStrategyId(name)`:中文/任意名 → 英文 slug(如「长线持有」→ long-term-hold;去空格、转小写、连字符)
- `addStrategy(scope, name)`:生成 id + 追加到列表末尾(order = max+1
- `renameStrategy(scope, id, name)`:只改 name(id 不变,分配数据不受影响)
- `removeStrategy(scope, id)`:删除策略(**联动清空该策略份额** —— 调用 storage 清理 + 更新策略列表)
- `moveStrategy(scope, id, dir)`:上移/下移(调整 order
- 策略 schema 不变(id/name/visible/order
### 3. storage.js(本地存储)—— 配合 O3/O6
- **现有**load/save/get/getAll/set/remove(按 code
- **新增**
- `removeStrategyShares(strategyId)`:遍历所有 code,删除该 strategyId 的份额(删除策略联动)
- `clearStrategy(strategyId)`:同 removeStrategySharesO6 一键清零可复用)
### 4. position/manager.js(分仓逻辑)—— O6
- **现有**getAllPositions/getStrategyPositions/getUnallocated/addToStrategy/removeFromStrategy/getSummary
- **新增**
- `moveAllUnallocatedToStrategy(code, strategyId)`:把某票**全部未分配份额**移入指定策略(O6 全部移入)—— 未分配 = volume - 已分配,一次 add
- `clearStrategyShares(strategyId)`:清空某策略全部份额(O6 一键清零)—— 调 storage.clearStrategy + 返回影响标的列表
- 校验保持:各策略份额之和 ≤ 总持仓
### 5. api.js(服务端 API)—— 承载新端点
- **现有**/odl/api/* 8 端点(webServer 自开路由,技术约束-004
- **新增端点**
- `POST /odl/api/strategies/remove`{ strategyId } → 删除策略 + 联动清份额(O3)
- `POST /odl/api/strategies/move`{ strategyId, dir } → 排序(O3
- `POST /odl/api/strategies/add`:{ name } → 新增(O3,也可并入 update,分开更清晰)
- `POST /odl/api/remove-all-shares`{ strategyId } → 一键清零(O6
- 全部移入复用现有 `add-shares`(shares = 未分配数,由客户端先算好或服务端算)
- `strategies/update` 保留(重命名/显隐仍走整表更新)
- 错误透出:统一错误码(not-found / strategy-not-found / share-limit 等)
### 6. client/index.js(客户端入口)—— O2 核心改造
- **现有**:写死注册 3 个 tab
- **改造**
- 新增 `loadStrategies()`fetch /odl/api/strategies,取 visible=true 列表
- **动态注册**:遍历策略列表,逐个 `slots.register('conversation.view', { id: 'odl-strategy-<slug>', label: 策略名 }, StrategyTab)`
- 全部持仓 tab 固定保留(order 10,数据源 tab
- **刷新机制**:暴露「刷新 tab 栏」函数 —— 重新拉策略配置 → 注销旧策略 tabs → 注册新 tabs
- **变更提示(无事件机制,老师确认)**:设置页保存成功后**就地提示**「策略已变更,刷新页面后生效」(Toast);
- **tab 更新时机**:插件启动时按策略配置注册 tabs → 刷新页面 = 插件重载 = 按最新策略重新注册(基线方案 X);
- **可选优化(方案 Y)**:tab 栏利用「会话切换/重新挂载」时机重新拉策略配置自动更新(无需自定义事件,实现时验证框架挂载钩子,失败则保持方案 X)
- **技术确认(已核实)**`ctx.slots.register(...)` 返回 **disposer 函数**(注销该 entry)——动态注销旧 tabs 可行:注册时保存 disposer 列表,刷新时逐一调用 disposer 移除,再注册新 tabs
### 7. client/views/SettingsSection.jsx —— O3 UI
- **现有**:策略列表 + 显示开关
- **改造**
- 新增策略:输入框 + 按钮 → call strategies/add { name }
- 重命名:行内编辑(改 name → strategies/update
- 删除:删除按钮 → **确认弹窗**(提示「该策略下 N 股将回到未分配」)→ call strategies/remove
- 排序:上移/下移按钮 → call strategies/move
- 保留显示开关
- 操作反馈:Toast(成功/失败)
### 8. client/views/StrategyTab.jsx —— O6 UI
- **现有**:添加(选标的+份额)/ 移出(指定数量)
- **改造**
- 「全部移入」按钮(行内):该票未分配全部移入当前策略(call add-sharesshares=未分配)
- 「一键清零」按钮(顶部):弹窗确认 → call remove-all-shares
- 操作反馈:Toast
- 加载失败:LoadState 兜底(O5
### 9. client/views/AllPositionsTab.jsx —— O5
- **现有**:直接显示/加载失败文字
- **改造**:套 LoadState 三态组件(loading/error+重试/success
### 10. 【新增】client/views/LoadState.jsx —— O5
- 三态组件:loading(加载中)/ error(失败原因 + 重试按钮)/ successchildren
- 自动重试 2 次(间隔 2s)逻辑内置(或由父组件控制)
### 11. 【新增】client/views/Toast.jsx —— O6/O3
- 轻提示:success(绿)/ error(红),3s 自动消失
- 简单实现:全局 state + 定时器,或 React portal
## 三、职责边界(延续迭代 01
| 层 | 文件 | 职责 |
|---|---|---|
| API 封装层 | api.js | 接收 HTTP 请求 → 调业务层 |
| 业务逻辑层 | position/manager.js + settings.js | 分仓逻辑 + 策略管理 |
| 数据源适配层 | data-source/qmt-bridge-rest.js | 真正发 HTTP 到 QMT |
| 存储层 | storage.js | allocations.json 本地持久化 |
**调用链**client → HTTP /odl/api/* → api.js → manager/settings → storage / qmt-bridge-rest → QMT
## 四、数据流(关键路径)
```
【O2 动态 tab】
设置页保存策略变更
→ SettingsSection 调 strategies/update(或 add/remove/move
→ 服务端更新 settings + 联动 storage
→ 客户端 Toast「策略已变更,请手动刷新」+ 刷新按钮
→ 用户点刷新 → 重新 loadStrategies() → 注销旧 tabs → 注册新 tabs
【O3 删除策略】
设置页点删除 → 确认弹窗
→ call strategies/remove { strategyId }
→ settings.removeStrategy + storage.removeStrategyShares(strategyId)
→ 份额回未分配(全部持仓 tab 未分配数增加)
【O6 全部移入】
策略 tab 行内「全部移入」
→ 客户端已知该票未分配数 → call add-shares { code, strategyId, shares: 未分配数 }
→ manager.addToStrategy(校验 ≤ 总持仓)
→ Toast 成功 → reload
【O6 一键清零】
策略 tab 顶部「一键清零」→ 确认弹窗
→ call remove-all-shares { strategyId }
→ manager.clearStrategyShares → storage.clearStrategy
→ Toast 成功 → reload
```
## 五、关键接口签名(待实现时对照类型确认)
- slots.register('conversation.view', {id, label}, Component) —— 动态注册/注销(读 slots.d.ts 确认 unregister
- webServer.register({kind:'prefix', path:'/odl/api', handler}) —— 已有
- settings scope.get()/update() —— 已有
- **事件机制:不需要(老师确认,2026-08-28)**——策略变更的提示在设置页内就地显示,tab 更新靠「刷新页面 → 插件重载 → 重新注册」,全程无跨组件事件;
- 优化(方案 Y):若框架支持会话切换挂载钩子,tab 栏自动重新拉策略配置(仍无事件)
## 六、开发顺序(编码)
1. 服务端:settings.jsadd/rename/remove/move + id 生成)
2. 服务端:storage.jsremoveStrategyShares/clearStrategy
3. 服务端:manager.jsmoveAllUnallocated/clearStrategyShares
4. 服务端:api.js(新端点 + 错误透出)
5. 客户端:LoadState.jsx + Toast.jsx(基础组件)
6. 客户端:SettingsSection CRUD + 确认弹窗
7. 客户端:index.js 动态 tab 注册 + 刷新机制
8. 客户端:StrategyTab 全部移入/一键清零
9. 构建 + 安装 + 联调验收
## 七、非目标(本期不做)
- 表格列可配置(T-006 数据池)
- 数据源状态全局监控(O5 澄清为加载兜底)
- 数据实时刷新/WebSocketT-005
- 持仓信息补全列(O1
- 网格参数管理、做T 记录、风控