Files
kyugao ec02a791ee 迭代22+23: 策略tab静态化 + 计算字段(数字/判定型)+ 网格超市信号字段
- R-027 静态化:策略恒为内置两项(不可增删改名,保留显隐/排序);设置页移除「策略分组」;
  字段配置入口迁到策略 tab 内「列设置」旁(FieldConfigDialog + schema-update 单策略写入)
- R-026 计算字段:自写公式引擎(中文变量、四则/括号/round·abs·min·max、缺值短路→—)+
  变量目录(行情/合约/持仓/自定义字段)+ strategy-positions 逐行现算(只读内存缓存,不落库、列只读)
- R-028 判定型:比较运算 + and/or + inferResultKind + 结果类型一致性校验 + 判定列 ✓/— 渲染;
  网格超市落地 可下空单=涨停价>基准值+网格大小、可下多单=跌停价<基准值-网格大小
- 变量选择改标签平铺(老师反馈);公式手册 docs/99-其他材料/计算字段公式说明.md
- 约束同步:产品约束-002/003/004/009/013/014、技术约束-014/015/022/023/024、UI约束-002/003/005/008
- 回归:新增 test-r026/test-r027,更新 r011/r013/r017,17 个脚本全绿;typecheck/build 通过
2026-09-10 14:05:06 +08:00

165 lines
15 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.
# 迭代 22 UI 交互设计:字段配置入口迁移 + 策略计算字段
> 依据:**R-027(重构·第一阶段,已定稿)** + **R-026(计算字段·第二阶段,已定稿)** + PLAN-019 日期:2026-09-10
> 状态:**已定稿**(D-1D-7 老师逐项拍板;2026-09-10 因入口迁移(R-027)同步修订;D-8~D-9 为 AI 默认项,老师可否决)
> 视觉基线:UI约束-004--dsw-* token)、UI约束-006ExpandChevron)、UI约束-007(间隙高亮线);UI约束-005 待随本次修订
> 复用:ColumnSettingsPopover(列设置)、StrategyFieldsEditor(改造为弹层内容)、ToastFieldCellEditor 不参与(formula 不可编辑)
## 1. 交互总览(一句话)
策略 tab 顶部**「字段配置」+「列设置」**两个按钮:字段配置管**字段定义**(含计算字段的公式),列设置管**列的显隐与顺序**;
字段定义保存后表格列自动跟随;计算字段列**只读**展示服务端实时算出的值(缺数据 `—`)。
> 本次修订要点(R-027):字段配置入口从「设置页 → 策略分组 → 策略行展开」**迁到策略 tab 内**,与列设置并列;设置页不再有「策略分组」子 tab。
## 2. 控件布局(示意)
### 2.1 策略 tab 顶栏
```
┌─ 策略 tab:网格超市 ─────────────────────────────────────────────┐
│ 持仓 13 只 · 今日盈亏 … [历史持仓 ▾] [字段配置] [列设置] │
│ ┌ 持仓表 ─────────────────────────────────────────────────────┐ │
│ │ | | 代码 | 名称 | 现价 | ƒ 盈亏比例 | … | 操作 | │ │
│ └─────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
```
- 两按钮同层级、同视觉族(现有「列设置」按钮样式),**字段配置**在左、**列设置**在右(先定义字段、再排列,顺序符合操作动线)。
### 2.2 字段配置弹层(列表 + 表单)
```
┌─ 字段配置:网格超市 ─────────────────────────────────────────┐
│ 自定义字段(5) [+ 添加字段] │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 展示名 key 类型 公式/默认 单位 操作 │ │
│ │ 网格上边界 grid_ceiling 数字 默认 11 元 编辑 删除│
│ │ 基准值 current_base 数字 默认 10 元 编辑 删除│
│ │ ƒ 盈亏比例 pctProfit 计算 (现价 ÷ 成本价 - 1)×100 % 编辑 删除│
│ └──────────────────────────────────────────────────────────┘ │
│ 字段增删后,持仓表列自动跟随(新增列默认追加末尾、删除列自动移除)│
│ [关闭] [保存字段] │
└────────────────────────────────────────────────────────────────┘
```
- 弹层形态(D-9):锚定弹层(与列设置同源视觉),宽度约 520px、最大高度约 70vh、内容超出内部滚动;
- **保存字段**按钮在弹层底部(右对齐,主色实心);**关闭**在左(次按钮);
- 有未保存改动时点「关闭」/ 外点/Esc → 二次确认「有未保存的字段改动,确定放弃?」(D-8)。
### 2.3 字段表单 · 类型 = 计算(第二阶段)
```
┌─ 添加字段 / 编辑字段 ────────────────────────────────────────────┐
│ 展示名 [盈亏比例 ] 标识 [pctProfit ] 类型 [计算 ▾] │
│ 单位 [% ] 小数位 [2] │
│ ┌ 公式 ───────────────────────────────────────────────────────┐ │
│ │ (现价 ÷ 成本价 - 1) × 100 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ [试算] 试算:平安银行 000001.SZ → 6.67 % │
│ 行情 [现价] [昨收] [今开] [最高] [最低] [成交量] [成交额] │
│ 合约 [涨停价] [跌停价] 持仓 [份额] [成本价] [最后成交价] │
│ 自定义 [网格大小] [基准值] [网格交易量] ← 点 tag 插入公式 │
│ 可用变量 行情:现价 昨收 今开 最高 最低 成交量 成交额 │
│ 合约:涨停价 跌停价 │
│ 持仓:份额 成本价 最后成交价 │
│ 自定义:网格大小 基准值 网格交易量 ← 本策略手填字段 │
│ [取消] [确定] │
└─────────────────────────────────────────────────────────────────┘
```
> 其余四类(文本/数字/布尔/枚举)表单形态不变,仅「类型」下拉多一项「计算」;选「计算」时隐藏默认值、显示公式区与小数位。
### 2.4 策略持仓表(只读计算列)
```
| | 代码 | 名称 | 现价 | 成本价 | 份额 | ƒ 盈亏比例 | ƒ 浮动盈亏 | 操作 |
|▸| 000001.SZ | 平安银行 | 11.20 | 10.50 | 1000 | 6.67 % | 700.00 元 | 全部移入/移出 |
```
- 表头 `ƒ`tertiary 色,`title="计算字段(只读)"`)+ 列名;悬停列头或单元格 title 显示公式原文(`= (现价 ÷ 成本价 - 1) × 100`);
- 单元格点击**不进入内联编辑**;手填字段列的行为不变(点击即编辑)。
### 2.5 列设置弹层(ColumnSettingsPopover
- 计算字段与手填字段同列混排(名称显示 `ƒ 盈亏比例`);显隐勾选 / 拖拽排序 / 间隙高亮线 / 立即持久化**零改动**。
## 3. 字段配置弹层状态机
| 状态 | 外观 | 交互 |
|---|---|---|
| 初始 | 列表(含公式原文列)+ 底部「保存字段」(无改动时禁用/次色) | 可添加/编辑/删除字段 |
| 有未保存改动 | 「保存字段」主色可点;关闭类动作触发放弃确认 | 保存 → 调 `strategies/schema-update` |
| 保存中 | 「保存字段」disabled(文案「保存中…」) | 防重入 |
| 保存成功 | Toast「字段已保存」+ 弹层关闭(或保持打开并刷新)+ 表格列同步跟随 | — |
| 保存失败 | Toast 错误 + 弹层不关闭 + 改动保留 | 可重试 |
| 公式校验失败(计算字段) | 表单内公式框**描红** + 错误行(`语法错误:第 8 字符处缺少运算符` / `未知变量「网格距」` | 表单不关闭,光标回公式框 |
| 试算中 | 「试算」disabled(「试算中…」) | 防重入 |
| 试算成功/失败 | 行内 `试算:平安银行 000001.SZ → 6.67 %` / error 色原因(`该策略当前无持仓` | 不阻塞保存 |
## 4. 交互细节
1. **打开入口**:点策略 tab 顶栏「字段配置」→ 弹层打开并显示**本策略**字段定义(各自 tab 管自己,Q4);数据来源沿用 `strategies` 端点(取当前策略 configSchema)。
2. **字段列表**:列 = 展示名 / key / 类型 / 公式或默认值 / 单位 / 操作(编辑、删除);计算字段无默认值,公式列等宽、单行省略、悬停全文。
3. **添加/编辑字段**:沿用现有表单(展示名 → 自动生成 key、类型下拉、枚举选项、默认值、单位)**新增**「计算」分支(见 2.3);`类型` 下拉:文本 / 数字 / 布尔 / 枚举 / **计算**
4. **删除字段**:列表内即时移除(弹层内草稿),**保存**后生效;保存后该列自动消失(归一化跟随),行内残留旧值按 R-013 既有防御隐藏。
5. **保存**:调新增单策略端点 `strategies/schema-update { strategyId, configSchema }`;成功后 Toast + 刷新当前策略数据(列与字段同步);**不写 values 列**、不动份额账本。
6. **变量插入**(计算字段,2026-09-10 老师反馈改为标签平铺):公式框下方按分组(行情 / 合约 / 持仓 / 自定义字段)**平铺变量 tag**(胶囊形、悬停显示释义),点选即插入到公式框光标处(无光标信息则追加末尾并补空格);不自弹下拉菜单。
7. **变量命名规则**(D-1 已拍板):内置变量固定中文名(现价/昨收/今开/最高/最低/成交量/成交额/涨停价/跌停价/份额/成本价/最后成交价);自定义字段以其**展示名**作变量名。
8. **保存校验(服务端)**:① 公式非空且语法合法;② 变量全部存在;③ 同策略字段展示名唯一、且不与内置变量名冲突;④ 仅引用**非公式字段**(目录层排除)。失败 → Toast + 公式框描红 + 定位文案。
9. **试算**:服务端取该策略一行真实持仓(优先份额 > 0 首行)→ 变量目录取数 → 求值 → 返回 {`code`,`name`,`value`};前端按单位/小数位格式化显示。
10. **持仓表只读渲染**:按小数位 + 单位格式化为 `6.67 %` / `700.00 元`;悬停显示公式原文。
11. **刷新语义**(已知取舍):计算列随 `strategy-positions` 轮询刷新(行情服务端 5s 更新,列值刷新粒度 = 接口轮询周期);不与 `PriceCell` 实时高亮联动。
12. **历史持仓行**:计算列显示 `—`(清仓行无「现价」语义,不做历史时点计算)。
13. **旧公式引用已删变量**D-4 已拍板):字段列表给 `⚠` 标记 + 悬停原因;运行期该列显示 `—`
14. **设置页**(第一阶段):不再有「策略分组」子 tab;Tab 设置里策略行与内置行同权(显隐 + 拖拽排序 + 间隙高亮线),**不提供**新增/重命名/删除任何入口。
15. **键盘/可及**:Esc / 外点关闭弹层(有未保存改动则确认);`ƒ``⚠` 标记均带 title 文本(不单靠颜色表意)。
## 5. 空态与边界
| 场景 | UI |
|---|---|
| 本策略尚无字段 | 弹层列表空态:「尚未配置字段 —— 点击「+ 添加字段」为本策略添加(该策略下每个持仓按此定义填写值)」 |
| 该策略无手填字段(配计算字段时) | 变量菜单「自定义」分组空态:「本策略暂无手填字段」 |
| 该策略当前无持仓 | 试算行内:「暂无可试算的持仓数据(保存不受影响)」 |
| 行情缺失 | 计算列单元格 `—`tertiary 色,不报错) |
| 计算失败(除零/非有限) | 单元格 `—` |
| 公式为空 / 未知变量 / 变量名冲突 | 拒绝保存 + 公式框描红 + 具体文案(见 §4.8) |
| 弹层有未保存改动时关闭 | 二次确认「有未保存的字段改动,确定放弃?」(D-8,AI 默认) |
| 未分配持仓 / 无 holding 锚点行 | 计算列照常显示(公式只用行情 + 持仓账本,不依赖 holding 锚点) |
| 设置页 | 仅「Tab 设置 / QMT 连接配置」两个子 tab |
## 6. 组件落点(技术方案阶段细化)
- `src/client/views/StrategyTab.jsx`:顶栏新增「字段配置」按钮(列设置旁)+ 弹层开关;计算列只读渲染(`ƒ` 表头 + title + 格式化 + `—`);
- `src/client/views/FieldConfigDialog.jsx`(**新增**):字段配置弹层容器(宽度/滚动/底部按钮/放弃确认),内容复用改造后的 StrategyFieldsEditor
- `src/client/views/StrategyFieldsEditor.jsx`(**改造**):作为弹层内容;保存回调改单策略端点;类型下拉加「计算」+ 公式分支(公式框 / 变量选择器 / 试算 / 小数位);
- `src/client/views/SettingsSection.jsx`(**改造**):移除「策略分组」子 tab(含 CRUD 与确认弹窗);
- `src/client/views/ColumnSettingsPopover.jsx`:列名 `ƒ` 前缀(仅文案);
- 服务端(技术方案阶段):`strategies` 常量 + tabs 策略条目固定 + 存储归一化;`strategies/schema-update` 单策略字段端点;变量目录 + 表达式引擎 + `strategy-positions` 现算 + 校验/试算端点;
- 零改动面:`FieldCellEditor`(formula 不进入)、列配置持久化与归一化、历史持仓路径、份额账本与交易归属。
## 7. 已拍板决策(2026-09-10 老师逐项确认)
| # | 问题 | 结论 |
|---|---|---|
| D-1 | 变量命名细则 | 内置固定中文名;自定义字段用**展示名**(新增唯一性 + 不与内置名冲突校验) |
| D-2 | 计算列视觉区分 | 表头 `ƒ` 前缀 + 悬停看公式;不加背景色 |
| D-3 | 试算预览 | 本期做 |
| D-4 | 已删变量的提示 | 字段列表 `⚠` 标记 + 悬停原因;运行期 `—` |
| D-5 | 小数位 | 数字输入 0-4,默认 2 |
| D-6 | 公式框能力 | 等宽字体 + 选择器插入;不做实时高亮/自动补全 |
| D-7 | 约束文档更正 | 一并更正 UI约束-005 + 新增计算字段约束条目 |
| D-8 | 弹层未保存改动的关闭行为 | **AI 默认**:二次确认放弃;老师可否决(备选:直接丢弃 / 禁止关闭) |
| D-9 | 弹层形态 | **AI 默认**:锚定弹层(与列设置同源视觉),~520px 宽、70vh 高、内部滚动;老师可否决(备选:右侧抽屉 / 居中模态) |
## 8. 约束与历史需求联动(实施时执行)
- **约束修订**R-027):产品约束-002/003/004(标签体系 / 标签自定义 + 显示开关场景收敛为「固定两策略 + 字段自定义」)、产品约束-009(Tab 统一管理中「策略条目动态化」条款)、UI约束-002(设置页子 tab 构成:移除策略分组)、UI约束-003(Tab 设置:策略行不再随 CRUD 增删)、**UI约束-005**(字段配置 UI 入口迁移 + 更正为「表格列化 + 单元格内联编辑」现状);
- **约束新增**R-026):拟 UI约束-008(计算字段表单 + 只读计算列)、产品功能约束(计算字段语义:不落库 / 只读 / 仅非公式变量)、技术方案约束(变量目录 + 表达式引擎 + 服务端现算);
- **历史需求取代**:R-003(策略 CRUD)→ 退役;R-011(Tab 统一管理)→ 策略条目动态化部分取代、显隐排序机制保留;R-013 → 字段模型/列机制保留、入口条款取代(均由 R-027 取代,索引标注追溯)。
## 9. 待确认/顺带发现
- 无(D-8 / D-9 为 AI 默认项,老师如有异议直接改判)。