## 背景(来源:调度员 2026-09-06 产品走查,维护者以 /os-project-pm-dispatch 放行本批) 分公司核对人员清空「待我核对」队列要逐条走「更多操作 → 确认无误 → 确认」,10 条 30 击,三人合计 90 击(UI 实测 K-5);数据调整、加减分的新建表单把「状态、审批人、审批时间、审批意见、落地时间」暴露给填报人员,「状态」必填无默认值且下拉列出会被 hook 拒绝的值,要试错两次才能建出草稿(K-6),新建成功后弹出记录抽屉挡住「新建」(K-7)。 ## 范围 1. **核对任务批量确认**(`src/views/index.ts` `CheckTaskViews.pending`):开启多选,`bulkActions` 挂「确认无误」(spec `view.zod.ts` 支持 `bulkActions: ['<action>']` 逐记录派发);「提出争议」保持单条(理由必填)。若现有确认动作不适合逐记录派发,新增一个同语义动作,状态推进仍走 hook。 2. **数据调整表单收敛**(`src/views/index.ts` `AdjustmentViews.formViews`):新建/编辑表单只留 填报单、调整的指标明细、调整类型、调整后值、申请理由;`status`、`requested_by`、`decided_by`、`decided_at`、`decision_reason`、`applied_at`、`old_value` 从可编辑字段移出(记录页只读展示);`status` 默认「草稿」由 `src/hooks/adjustment.hook.ts` 在 beforeInsert 补齐(仅当输入未带 status);「调整前值」在保存时由 hook 回填(现状)并在表单选中明细后即时显示——若平台表单不支持联动带出,如实记录。 3. **加减分表单收敛**(`BonusViews.formViews` 与 `src/hooks/bonus.hook.ts`):同 2,只留 填报单、事项、类型、分值、依据;状态默认草稿;审批字段只读。 4. **新建后不弹记录抽屉**:查平台表单 `afterSubmit`/`onSuccess` 类配置(spec FormViewSchema 尾部「What happens after a successful submit」),设为回列表;不支持则如实记录并只上报。 5. 文案守 std-copy;新增 label 走 `pnpm i18n:extract`。 ## 不做 不改核对任务生成范围(#27);不改加减分/调整的审批口径(第 10 章第 6 项);不动 `src/hooks/sheet.hook.ts` 与计分。 ## 方案分级与放行(调度员) 改已有视图 + 两个 hook 的 beforeInsert 默认值 = 中风险;hook 改动只允许「输入未带 status 时置草稿」这一条,不得改状态机规则。开工前在本单评论列表单字段前后对照与 hook 改动 diff 说明,一致即开工。 ## 验收标准 1. 分公司核对人员在「待我核对」勾选多条一次「确认无误」,10 条 ≤ 4 击;争议仍必须单条填理由;批量确认后核对任务的处理人/处理时间按现状规则(若现状不盖章,如实记录,不在本单修)。 2. 填报人员新建数据调整只填业务字段一次成功,状态为草稿,再「提交审批」;人力审核/负责人审批路径不变;`scripts/software-flow.mjs` 的调整用例仍 PASS。 3. 人力审核登记加减分同上;负责人审批不变。 4. 新建后不弹抽屉或如实记录平台缺口。 5. `pnpm verify` 绿;两脚本全 PASS;测试报告(岗位截图 + 点击数前后)与符合度清单挂本单评论,截图走 `acceptance-evidence`。 ## 测试计划草稿 T1 批量确认 10 条计击 | T2 争议单条必填 | T3 调整表单一次成功 + 审批链 | T4 加减分表单一次成功 + 审批链 | T5 抽屉行为 | T6 两脚本 + verify
Activity
baozhoutao commentedon Sep 6, 2026
issue-37 bulk-confirm-forms-,worktree/Users/baozhoutao/GitHub/kpi-issue-37 bulk-confirm-forms-,基线 main @ c197bf4。派发开发子 agent(Opus)。baozhoutao commentedon Sep 6, 2026
issue-37-bulk-confirm-forms//Users/baozhoutao/GitHub/kpi-issue-37-bulk-confirm-forms(上一条认领评论的名称为脚本拼接笔误)。baozhoutao commentedon Sep 6, 2026
开工前方案说明(#37)
基线 main @ c197bf4;worktree
issue-37-bulk-confirm-forms,dev 端口 3113,档案software。下面三段(批量动作实现方式 / 表单字段前后对照 / hook 改动 diff)与本单放行方向核对一致即开工。0. 改前实测基线(先跑一遍现状,数字不是从需求抄的)
档案数据:方案发布 → 11 张填报单全部填数提交 → 每名分公司核对人员得 10 条「待我核对」(与本单 K-5 的 10 条一致)。
「状态」下拉在两张表单上都实测到本单说的问题:数据调整列出
草稿 / 待审批 / 已批准 / 已否决,加减分列出待审批 / 已批准 / 已否决—— 后两项都会被状态机(initialStates: ['draft'])拒掉,填报人员只有第一项是能建出来的。K-7 也复现,但表现分两种,由平台按对象字段数决定,不是本项目配的:加减分(10 个字段)新建成功后弹记录抽屉盖住列表和「新建」;数据调整(15 个字段)新建成功后整页跳到记录页。两种都离开了列表。
1. 核对任务批量确认 —— 实现方式
src/views/index.ts的CheckTaskViews.listViews.pending上加两个键:ui/view.zod.ts的bulkActions裸字符串形式就是「逐记录派发」:渲染器按名字在对象动作里找到kpi_check_confirm,带上它自己的 label、params(核对意见,选填)、visible谓词,对勾选的每条记录各发一次,recordId由该行记录带出。动作体一个字没改,状态推进仍然全部落在src/hooks/check-task.hook.ts(岗位校验、填报单状态校验、盖章、留痕、全部确认后自动推进)—— 本单不动这个 hook。visible谓词record.status != 'confirmed'会在派发前逐条过滤,列表已投影status列,谓词求得出值。bulkActions,保持行内单条 + 争议内容必填。bulkActionDefs用不上:那是给「一次调用覆盖整个选区」的聚合动作(execution: 'aggregate')和纯数据面批改用的,本项要的是逐条走 hook。预期改后击数:全选(1)+「确认无误」(1)+ 弹窗执行(1)= 3 击,满足「10 条 ≤ 4 击」。
2. 数据调整表单字段前后对照(
AdjustmentViews.formViews.form)sheetlineadjust_typenew_valuereasonold_valuestatusbeforeInsert补「草稿」requested_bydecided_bydecided_atdecision_reasonapplied_at改后表单剩 5 个字段,分区从「调整申请 + 审批」两段收敛成一段。移出 ≠ 删掉:记录详情页的字段清单来自对象定义、不来自表单视图(与此前收敛填报明细表单时同一条路),已实测记录页仍完整显示 调整前值 / 状态 / 审批人 / 审批时间 / 落地时间。
「调整前值」选完明细即时带出:平台做不到,如实记录。 实测选中指标明细后,表单里的「调整前值」仍是空(改前改后都一样)—— 控制台表单没有「按 lookup 选中值回查另一对象字段并回填本表单」的联动能力,ObjectStack 表达这类派生值的正规做法是对象上的公式/汇总字段,而本单「不新增字段」。所以维持现状:保存时由 hook 回填,记录页看得到。这一条会在符合度清单里标⚠️ 并挂平台上报链接。
3. 加减分表单字段前后对照(
BonusViews.formViews.form)sheettitlebonus_typepointsreasonstatusbeforeInsert补「待审批」(机器值draft)signed_pointsapproved_byapproved_at4. hook 改动 diff(只加「输入未带 status 时置默认」一条,状态机规则一个字不动)
src/hooks/adjustment.hook.ts,beforeInsert分支内、现有赋值旁边加一行:if (ctx.event === 'beforeInsert') { input.sheet = line.sheet; input.plan = sheet?.plan ?? null; input.subject = sheet?.subject ?? null; input.old_value = row.adjust_type === 'result' ? toNumber(line.final_score) : toNumber(line.actual_value); if (!input.requested_by) input.requested_by = actorId(ctx); + if (!input.status) input.status = 'draft'; return; }src/hooks/bonus.hook.ts,handler里岗位校验之前加:const points = toNumber(row.points) ?? 0; input.signed_points = row.bonus_type === 'deduct' ? -points : points; + if (ctx.event === 'beforeInsert' && !input.status) input.status = 'draft';两处都是「仅当输入未带 status」才置值 —— 带了 status 的写入(按钮、脚本、导入)行为完全不变,状态机
transitions/initialStates、岗位校验、归档锁、已批准锁一律不动。requiredBonusPosition()这个纯函数(单元测试点)也不改。5. 新建后不弹抽屉 —— 先说结论,实现时以实测为准
查了平台侧:spec
FormViewSchema.submitBehavior(thank-you/redirect/continue/next-record)只在表单自己决定跳转时生效;而控制台列表页的「新建」走的是应用外壳的模态表单,它给表单传了onSuccess回调,按源码onSuccess优先于submitBehavior,且这个回调的去向由对象的可见字段数算出来(≥12 → 记录页,否则 → 记录抽屉),既不读submitBehavior,也不读列表视图的navigation。也就是说本单第 4 项在 17.2.0 上没有元数据开关。按项目纪律:不绕行(不靠给对象加字段去凑字段数、不改平台包),如实记录 + 只上报 objectstack-ai/objectstack(现象 / 最小复现 / 期望能力 / 平台版本 17.2.0),符合度清单该条标⚠️ 并引用上报链接。动手时会再用实测复核一遍这个结论,复核结果照实写进测试报告。
改动面
只动:
src/views/index.ts的CheckTaskViews/AdjustmentViews/BonusViews三段、src/hooks/adjustment.hook.ts、src/hooks/bonus.hook.ts、翻译包重生成。不动src/actions/index.ts(复用现有动作,不需要新增)、不动sheet.hook.ts/check-task.hook.ts/entry-line.hook.ts/src/lib/src/objects/scripts/docs。baozhoutao commentedon Sep 6, 2026
测试报告 · #37 核对任务批量确认;数据调整与加减分表单只留业务字段、状态默认草稿
结论:通过(1 项平台受限,已上报并如实记录)。 6 条测试计划全部执行,T1–T4、T6 通过;T5「新建后不弹抽屉」在 17.2.0 上没有元数据开关,平台侧问题已提 objectstack-ai/objectstack#16381,本单不绕行、不打补丁。
issue-37-bulk-confirm-forms@b27d441(基线 main @c197bf4)OS_SEED_PROFILE=software,SQLite 本实例库(截图轮为空库重建)locale=zh-CNPassw0rd!23acceptance-evidence,目录issue-37/,commit4ae42dd6fbaa856f548c8d68f3ce2e174897641e(26 张,已用 contents API 复核)点击数前后对照(各自从列表页起计,不含登录)
T1 批量确认 10 条 —— 通过
改前:列表没有多选框,只有行尾「更多操作」。
改后:表头出现全选框,勾选后底部批量条出现「确认无误」;弹窗先收「核对意见(选填)」,再列出受影响的 10 条二次确认,执行后队列清空。
数据面复核(管理员 REST):华东 10 条全部
confirmed,处理人与处理时间逐条盖章(核对人 陈东 / 核对时间 2026-09-06 12:52),审核记录逐条写入confirm;3 家分公司全部确认的 7 张填报单自动推进到「人力审核中」—— 批量走的是与单条完全相同的 hook 路径,一条规则也没绕开。T2 争议仍是单条 + 理由必填 —— 通过
勾选记录后批量条上只有「确认无误」,没有「提出争议」;行内「提出争议」仍是单条弹窗,内容留空点「确认」被当场拦下(「争议内容(必填) 为必填项」),填写后提交成功,意见与处理人一并留痕。
T3 数据调整表单一次成功 + 审批链 —— 通过
改前表单 12 个字段(含状态、申请人、审批人、审批时间、审批意见、落地时间),「状态」必填无默认值,下拉里列着会被状态机拒掉的「已批准」「已否决」;「审批意见」在申请表单上还是可编辑的。
改后只剩 填报单 / 调整的指标明细 / 调整类型 / 调整后值 / 调整原因 五项,一次填完即建成草稿;记录页上「调整前值」已由 hook 按所选明细回填为 60.0000,状态、审批人、审批时间、落地时间照常只读可见。
审批链未变:赵敏「提交审批」→ 待审批 → 马丽(人力审核)「批准并落地」→ 已批准;审批人 / 审批时间 / 落地时间 / 审批意见全部落库。
T4 加减分表单一次成功 + 审批链 —— 通过
改前 9 个字段;改后只剩 所属填报单 / 事项 / 类型 / 分值 / 依据 五项,一次建成「待审批」,计入分值由 hook 按类型算出。何平(人力负责人)批准后盖章,岗位分离规则未变。
状态机没有被放宽(负面用例,REST 直发):
hook 只补空缺,带了状态的写入行为一个字没变。
T5 新建后的抽屉行为 —— 平台受限,如实记录
改前实测两种表现,都由平台按对象的可见字段数决定:加减分(10 个字段)新建后弹记录抽屉盖住列表与「新建」;数据调整(15 个字段)新建后整页跳记录页。
按本单第 4 项查了 spec 的
FormViewSchema.submitBehavior,并实测验证:在BonusViews.formViews.form上显式声明submitBehavior: { kind: 'continue' },pnpm validate通过且无告警,重启后新建加减分照样弹抽屉,声明完全无效(该探针已回滚,不在提交里)。读
@objectstack/console@17.2.0产物可以对上:列表「新建」由应用外壳渲染成formType: 'modal'并传入onSuccess,而表单的提交处理是if (e.onSuccess) … else if (e.submitBehavior) …——onSuccess短路了submitBehavior;那个onSuccess的去向由recordSurface(objectDef)按「可见字段数 ≥ 12 → 记录页,否则 → 抽屉」算出,既不读submitBehavior,也不读列表视图的navigation。没有任何元数据开关。按项目纪律停手:不改平台包、不给对象凑字段数绕行、不降级冒充完成。已上报 objectstack-ai/objectstack#16381(现象 / 最小复现 / 期望能力 / 平台版本 17.2.0)。改后行为与改前一致,没有回退。
T6 两脚本 + verify —— 通过
两脚本各在空库重建的实例上跑(
software与默认两个档案各重建一次,rm -rf dist后重启)。回归:待办工作台
工作台「待我核对」区块(待办工作台的产物)不受影响:10 条待办正常列出,行操作菜单照常。
未覆盖 / 需要说明
baozhoutao commentedon Sep 6, 2026
需求符合度清单 · #37
逐条对照本单正文的每个要求(触发操作、每个字段、每条校验、输出反馈、每条验收标准),三态标注。测试报告见上一条评论。
1. 核对任务批量确认(正文 §范围 1)
CheckTaskViews.pending开启多选selection: { type: 'multiple' };实测表头出现全选框,底部出现「已选择 N 项」批量条bulkActions挂「确认无误」bulkActions: ['kpi_check_confirm'],spec 的裸字符串形式(逐记录派发)bulkActionDefs;实测 10 条各自落库,decided_by/decided_at逐条盖章,审核记录逐条写入bulkActions;批量条上只有「确认无误」;行内单条弹窗,内容留空被拦下check-task.hook.ts未改;岗位校验 / 填报单状态校验 / 盖章 / 留痕 / 全部确认后自动推进全部照常(7 张填报单自动进入「人力审核中」)kpi_check_confirm适合逐记录派发,故未新增动作,src/actions/index.ts零改动 —— 正文允许的两条路里选了不新增的那条2. 数据调整表单收敛(正文 §范围 2)
status/requested_by/decided_by/decided_at/decision_reason/applied_at/old_value移出可编辑字段decision_reason原来在申请表单上可编辑,一并移出status默认「草稿」由adjustment.hook.ts在 beforeInsert 补齐if (!input.status) input.status = 'draft';status=approved直接新建仍被状态机以invalid_initial_state拒(400)3. 加减分表单收敛(正文 §范围 3)
bonus.hook.tsbeforeInsert 补draft(界面文案「待审批」);实测一次建成status/signed_points/approved_by/approved_at移出表单,记录页只读可见status=approved直接登记仍被拒(400)4. 新建后不弹记录抽屉(正文 §范围 4)
afterSubmit/onSuccess类配置,设为回列表submitBehavior:实测显式声明submitBehavior: { kind: 'continue' },pnpm validate通过且无告警,新建后照样弹抽屉(截图见测试报告 T5)。去向由recordSurface(objectDef)按「对象可见字段数 ≥ 12 → 记录页,否则 → 抽屉」算出,既不读submitBehavior也不读列表视图navigation,没有元数据开关。出口 = 平台能力受限 → 上报记录:objectstack-ai/objectstack#16381(含现象、最小复现、期望能力、平台版本 17.2.0)。正文本项已写明「不支持则如实记录并只上报」5. 文案与元数据规范(正文 §范围 5)
pnpm i18n:extractsrc/translations/zh-CN.objects.generated.ts(删掉随「审批」分区一起消失的 3 个词条),pnpm i18n:extract:check新鲜度门禁通过src/objects/零改动6. 不做清单(正文 §不做)
sheet.hook.ts零改动requiredBonusPosition()与两个 hook 的审批分支一字未动;e2e 的 T59/T66/T68 岗位分离用例全 PASSsheet.hook.ts与计分src/lib/scoring.ts、sheet.hook.ts零改动7. 验收标准逐条
scripts/software-flow.mjs的调整用例仍 PASSpnpm verify绿acceptance-evidence4ae42dd6fbaa856f548c8d68f3ce2e174897641e,26 张,已用 contents API 复核非 ✅ 条目汇总(共 2 条,同一个根因,同一个出口)
submitBehavior后行为无变化)两条都不是「先简化实现」:2.4 的现状能力(保存时回填 + 记录页展示)是本单正文点名认可的兜底;4.1 在 17.2.0 上不存在任何合法的元数据路径,唯一的替代是改平台包或给对象凑字段数,都是本项目明令禁止的绕行。
baozhoutao commentedon Sep 6, 2026
交接验收侧 @baozhoutao。
PR:https://github.com/objectstack-ai/kpi/pull/42(分支
issue-37-bulk-confirm-forms@b27d441,基线 main @c197bf4;正文不含自动关闭关键字,开发侧不自行合并)状态:
status:自测报告中→status:PR审查中acceptance-evidence分支issue-37/,commit4ae42dd6fbaa856f548c8d68f3ce2e174897641e(26 张)需要验收侧留意的一项:正文第 4 项「新建后不弹记录抽屉」在平台 17.2.0 上没有元数据开关(实测声明
submitBehavior无效),已按纪律停手并上报 objectstack-ai/objectstack#16381,本单未绕行、未回退。符合度清单里标为非 ✅ 并附了出口。Merge pull request #42: bulk check confirmation; adjustment and bonus…
baozhoutao commentedon Sep 6, 2026
合并记录(调度员,2026-09-06)
i18n:extract:check530/530;verify 139 单测绿、software-flow 55/55、e2e-flow 74/74。submitBehavior在列表新建路径不生效,去向由字段数启发式决定),只上报不修复,出口 console: 列表「新建」成功后的去向只由对象字段数决定,form view 的 submitBehavior 在这条路径上解析通过却静默无效 objectstack#16381;批量确认沿用既有动作逐记录派发,未新增动作。!input.status也覆盖 null/空串(合理);清单 5.2 措辞「删 3 词条」实为 1 词条;批量部分失败的反馈形态由平台渲染器决定。status:PM验收中,处理人不变(验收侧)。