日期: 2026-07-17
范围: web-admin /#/system-manage/oa-approval/start 发起弹窗底部「审批流程」;backend preview_start_flow / flow-preview API
关联:
docs/superpowers/specs/2026-07-15-oa-start-flow-preview-design.md(首版方案 B:条件全展)docs/superpowers/specs/2026-07-15-oa-condition-from-form-design.md(条件字段来源与必填约定)backend/app/services/oa_engine.py — _match_condition_group、preview_start_flow关系: 本规格取代首版中「条件分支全部支路展开」与非目标「条件随表单实时裁剪」;人员解析、卡片样式、线性流程展示仍沿用 2026-07-15 规格。
含条件分支的流程在发起预览中并列展示所有支路(如「条件1」与「默认」),并标注「实际路径以提交时表单为准」。用户无法在提交前看到将实际走的那一条链,与钉钉「填齐必填后再出流程」的体验不一致。
| 项 | 结论 |
|---|---|
| 未确定时 UI | 钉钉式占位文案,不展开条件1/默认等支路 |
| 占位文案 | 「必填信息填写后,流程将自动显示」 |
| 已确定时 UI | 仅最终路径时间轴(节点名 + 签批方式 + meta + 人员 chip) |
| 「可确定」依据 | 流程树中条件分支所引用的表单字段在 formData 中均已有有效值 |
| 发起人自选 | 不作为整段预览的门闩;路径已确定即出链,未选人时该节点 people 为空 |
| 与提交一致性 | 分支匹配复用 _match_condition_group(form_data),与 advance_from 同源 |
| 刷新时机 | 表单值变化防抖刷新;自选人变化立即/短防抖刷新 |
┌─────────────────────┐
│ 打开发起弹窗 / 改表单 │
└──────────┬──────────┘
▼
流程树是否含 condition?
/ \
否 是
│ │
▼ ▼
【已确定】 条件引用字段是否均有值?
展示完整链 / \
否 是
│ │
▼ ▼
【待确定】 【已确定】
仅占位文案 只走命中支路 + 解析人
| 状态 | resolved |
前端展示 |
|---|---|---|
| 待确定 | false |
标题「审批流程」+ 占位文案;steps 为空或忽略 |
| 已确定 | true |
标题 + 时间轴 steps(可含右侧 hint,如「按当前发起人解析审批人」) |
加载中:沿用现有 v-loading,不闪占位与时间轴之间的错误态。
从发布版 flow_tree_json 根节点递归:
type=condition 节点,遍历 conditionGroups;isDefault 或无 rules/when 的空规则组);rules[] 收集 field;若仅有历史 when 字符串,用与引擎一致的方式解析出 {field} 占位符(若无法解析,视为该组不增加门闩字段,匹配仍走引擎)。去重后得到集合 conditionFields。
对每个 field,取 formData[field]:
null / undefined / ''(trim 后)→ 未填;0、布尔 false → 视为已填(合法取值)。任一 conditionFields 未填 → resolved=false。
无 condition 节点,或 conditionFields 为空(仅有默认支)→ 直接 resolved=true,按主链(或默认支)预览。
resolved=true 时:
condition:调用 _match_condition_group(groups, form_data),仅递归命中组的 child,不再把其它组写入 steps;type=branch 的「条件1 / 默认」占位步(最终链上无需分支标题卡,与钉钉「直接出后续审批人」一致);child(若有)继续行走;approval / cc / start / end 人员解析逻辑与现网 preview_start_flow 一致。若字段齐但 _match_condition_group 返回 None(异常配置):resolved=false,占位文案可改为「流程条件无法匹配,请检查表单或联系管理员」(可选;首版可仍用统一占位句,并在 resolveError 级日志/接口字段暴露)。
将
GET /api/admin/oa-approval/templates/{appId}/flow-preview?initiatorSelectUserIds=
改为(推荐):
POST /api/admin/oa-approval/templates/{appId}/flow-preview
Body:
{
"formData": { "days": 5 },
"initiatorSelectUserIds": ["user-id-1"]
}
兼容:若短期内保留 GET,则无法可靠传复杂 formData;本期以 POST 为准,前端切换后可删除 GET 或让 GET 仅支持无条件线性预览。
{
"resolved": true,
"message": "",
"steps": [
{
"id": "n_start",
"type": "start",
"name": "发起人",
"signMode": "",
"assigneeType": "",
"meta": "",
"people": [{ "id": "...", "nickName": "系统管理员" }],
"resolveError": ""
}
]
}
| 字段 | 说明 |
|---|---|
resolved |
false 时前端只显示 message(或默认占位句),不渲染时间轴 |
message |
resolved=false 时默认「必填信息填写后,流程将自动显示」;可覆盖异常文案 |
steps |
resolved=true 时为最终路径;false 时建议 [] |
单步结构与现有 OaFlowPreviewStep 一致。
OaFlowPreview.vue:增加 resolved(或由父级根据接口决定);resolved===false 时展示占位区块(样式对齐 Fresh Mint:浅底、居中/左对齐 muted 文案),隐藏 chain。start/index.vue:
loadFlowPreview 改为 POST,传入当前 formData 与自选人;watch(formData, …, { deep: true }) + debounce(建议 300ms);initiatorSelectUserIds 的 watch;web-admin/src/api/oaApproval.ts — fetchOaFlowPreview(appId, { formData, initiatorSelectUserIds }) 改为 POST;类型增加 resolved、message。
oa_approval.py:新增/替换为 POST handler,解析 body。oa_engine.preview_start_flow:增加 form_data 参数;实现字段收集、resolved 门闩、条件单路行走。_collect_condition_fields(root) -> List[str]、_form_value_present(form_data, field) -> bool,便于单测。resolved=false 时根本不 walk 条件子树亦可:直接返回空 steps)。resolved=true,steps 含 start→approval→end。resolved=false,steps=[],message 为占位句。resolved=true,initiator_select 节点 people 为空。| 文件 | 职责 |
|---|---|
backend/app/services/oa_engine.py |
preview_start_flow 门闩 + 单路 walk |
backend/app/api/oa_approval.py |
POST flow-preview |
backend/tests/… |
预览解析单测(新建或挂现有 oa 测试) |
web-admin/src/api/oaApproval.ts |
POST 客户端 |
web-admin/src/components/oa-approval/OaFlowPreview.vue |
待确定占位 UI |
web-admin/src/views/oa-approval/start/index.vue |
formData 防抖刷新 |
docs/superpowers/specs/2026-07-15-oa-start-flow-preview-design.md |
文首增加「条件展示见 2026-07-17 规格」指向(实现时可补一行) |
dialog-form-layout;预览区块视觉延续 Fresh Mint / 现有 OaFlowPreview 风格。| 阶段 | 内容 |
|---|---|
| P0(本期) | POST + resolved 门闩 + 单路预览 + 占位文案 + 前端防抖 |
| P1(可选) | 匹配失败专用文案;从 when 公式提取字段的更完整解析;mockup HTML 更新 |
| 日期 | 说明 |
|---|---|
| 2026-07-17 | 初稿:钉钉式待确定占位 + 确定后最终路径;用户确认自选不挡整段预览 |