# 迭代复盘:23-计算字段判定型扩展 ## 结论 **实现完成,待老师人工验收**。计算字段由「只出数字」扩展为「数字 / 判定」双结果类型; 网格超市两条网格规则(可下空单 / 可下多单)已可用公式表达,行为与实盘数据一致(真实验证 5 只 / 2 只)。 ## 事实记录 - **引擎**(src/formula/evaluator.js):多字符运算符识别 + 全角 `≥ ≤ ≠ > < =` 归一; 优先级 `or < and < 比较 < 加减 < 乘除`;比较/逻辑求值(缺值短路);`normalizeResult` 布尔直通; 新增 `inferResultKind(ast)`; - **存储**(src/settings.js):`fieldSchema.resultKind`(number|boolean,默认 number)+ `normalizeFields` 归一; - **校验**(src/api/strategies.js):结果类型一致性校验(声明 vs `inferResultKind`),不一致抛 `field-validation`; - **现算**(src/formula/FormulaService.js):`computed` 布尔直通; - **前端**:`StrategyFieldsEditor` 结果类型下拉 + 判定时隐藏小数位 + 运算符提示 + 判定试算(✓ 满足 / — 不满足); `StrategyTab` 判定列渲染 `✓ 字段名`(绿)/ `—`(灰,含缺值与 `false`);列表类型显示 `计算(判定)`; - **验证**:`test-r026` 48 → **71** 条(新增第 7 节判定型 15 条、第 8 节真实夹具端到端 8 条); typecheck 0 错;build 通过(client bundle 197794 bytes);全量 17 脚本全绿。 ## 设计与实现要点(沉淀) 1. **布尔必须先判**:渲染分支若先做 `Number.isFinite(Number(raw))`,`false` 会被当成 `0` 格式化成 `0.00`—— 实现中显式把 `typeof raw === 'boolean'` 放在最前(代码注释标注); 2. **判定型「不满足」= `—` 而非「否」**:缺行情与条件不满足在视觉上同形,避免把「数据缺失」误读为「不可以」; 3. **结果类型显式声明 + 静态推断校验**:避免「公式悄悄变成判定」导致列渲染与语义脱节; 推断只看**顶层**运算(`neg` 下钻),规则简单可预期; 4. **阈值用字段引用而非字面量**:`基准值 + 网格大小` 让规则随字段可调(老师 Q5 拍板)。 ## 偏差 - 无功能偏差;范围按 Q1–Q5 收敛(方案 C 三态信号、`not` 取反未做,已记入「不做」)。 ## 补记(2026-09-10 老师反馈) - 字段配置弹层的变量选择从「+ 插入变量 ▾」下拉改为**标签平铺**(分组成行、点选即插入公式框光标处); 已随迭代实施并重建 bundle(typecheck/build/17 脚本回归全绿)。 ## 遗留 - 判定「不满足」与「缺数据」同显示为 `—`:若老师希望区分(如缺数据显示 `?` 或 tooltip「数据缺失」), 可后续加 hover 原因; - 由老师侧重载插件后手动添加两个字段(或授权我用 `strategies/schema-update` 端点直接写入 settings)。