forked from ChaiHao/BPOS-MVP
三面拆分⑲:审批点卸岗位 —— 负责人一律运营时分配,绑员工组,实例记 assignee
模型(用户定):审批点不绑岗位;节点负责人是运营时分配的,绑定到员工组。 - 契约:approval 节点删 approver(功能属性只剩驳回走向/催办/委托消息); CLOSURE_VIOLATION_KINDS 删 missing-owner-position(岗位不入编排,无岗可核); 治理审批列表删 approverPosition 字段 - 运行时统一口径(活动点=审批点):工作流绑了员工组按组轮值(组员并集最闲者先), 没绑组全员轮值;staffId 稳定排序保证确定性,组员全不在岗退回全员。 ADR-011「绑定先于策略」随岗位退场 —— 工作组快照的成员集合成为轮值池 - 实例记 assignee(迁移 0014 node_instance.assignee_id):分派结果是流转事实 —— 审批箱收件(i.assigneeId === me)、裁决权(同一判据)、员工面链条报实际承接人、 治理台审批列表报人,全部按它认,不再有岗位比对 - closure 卸 positions 入参;desk/desk-approval/governance-ops 三路由改口; web 属性卡删「审批岗位」选择与警示、positions 管线拆除;种子 A5 卸 PM; 导出依赖文件审批段只留编排语义 测试:closure 25、save-package 6、seed 8、graph-to-pkg 5、端到端八例真库全绿; 五闸退出码全过。库:迁移 + v4 就地同步(唯一生效版)。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
@@ -35,13 +35,12 @@ import {
|
||||
St,
|
||||
} from '@web-shared/gov/primitives.tsx';
|
||||
import type { Nav } from '@web-shared/gov/gov-route.ts';
|
||||
import { useGovActivities, useGovPackages, useGovPkgReports, useGovStaff } from '@web-shared/gov/gov-api.ts';
|
||||
import { useGovActivities, useGovPackages, useGovPkgReports } from '@web-shared/gov/gov-api.ts';
|
||||
import type { GovActivities } from '@web-shared/gov/gov-api.ts';
|
||||
import { FlowFigureBlock } from '@web-shared/gov/flow/FlowFigure.tsx';
|
||||
import { packageToGraph } from '@web-shared/gov/flow/pkg-to-graph.ts';
|
||||
import { mergeGraphIntoPackage } from '@web-shared/gov/flow/graph-to-pkg.ts';
|
||||
import type { FlowEdge, FlowGraph, FlowNode } from '@web-shared/gov/flow/flow-layout.ts';
|
||||
import type { SpPosition } from '@web-shared/gov/flow/support.tsx';
|
||||
import { TriggerRulesHome } from '@features/gov-trigger';
|
||||
|
||||
export type HomeProps = { tab: string; nav: Nav };
|
||||
@@ -405,7 +404,6 @@ export function PkgPage({ id, nav }: { id: string; nav: Nav }) {
|
||||
const flowId = id.split('@')[0] ?? id;
|
||||
const q = useGovPackages();
|
||||
const acts = useGovActivities();
|
||||
const staffQ = useGovStaff();
|
||||
|
||||
const versions = (q.data?.packages ?? [])
|
||||
.filter((p) => p.id === flowId)
|
||||
@@ -432,7 +430,6 @@ export function PkgPage({ id, nav }: { id: string; nav: Nav }) {
|
||||
activeVersion={active?.version}
|
||||
nav={nav}
|
||||
activities={acts.data?.activities ?? []}
|
||||
positions={(staffQ.data?.positions ?? []).map((p) => ({ id: p.id, name: p.name, abbr: p.code }))}
|
||||
nextVersion={Math.max(...versions.map((x) => x.version)) + 1}
|
||||
closedOf={(v) => reports.data?.get(`${flowId}@${v}`)?.closed}
|
||||
onPick={(v) => setPinned(v)}
|
||||
@@ -457,7 +454,6 @@ function FlowLab({
|
||||
activeVersion,
|
||||
nav,
|
||||
activities,
|
||||
positions,
|
||||
nextVersion,
|
||||
closedOf,
|
||||
onPick,
|
||||
@@ -468,7 +464,6 @@ function FlowLab({
|
||||
activeVersion: number | undefined;
|
||||
nav: Nav;
|
||||
activities: readonly ActivityRow[];
|
||||
positions: SpPosition[];
|
||||
nextVersion: number;
|
||||
/** 该版本闭合与否(undefined = 报告还没回来)—— 激活按钮据此灰显 */
|
||||
closedOf: (version: number) => boolean | undefined;
|
||||
@@ -671,7 +666,8 @@ function FlowLab({
|
||||
})),
|
||||
approvals: pkg.nodes
|
||||
.filter((n) => n.kind === 'approval')
|
||||
.map((n) => ({ nodeId: n.id, label: n.label, approver: n.approver, reject: n.reject })),
|
||||
// 审批人运营时分配,依赖文件只描述编排语义(驳回走向)
|
||||
.map((n) => ({ nodeId: n.id, label: n.label, reject: n.reject })),
|
||||
};
|
||||
const blob = new Blob([JSON.stringify(doc, null, 2)], { type: 'application/json' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
@@ -1013,29 +1009,10 @@ function FlowLab({
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
{node.flavor === 'approval' && (
|
||||
<Field k="审批岗位" hint="「卡到人的工位」是审批点的功能语义,审批单派给它">
|
||||
<select
|
||||
className="g-select"
|
||||
value={node.owner ?? ''}
|
||||
onChange={(e) =>
|
||||
patch((n) => ({ ...n, owner: e.target.value === '' ? undefined : e.target.value }))
|
||||
}
|
||||
>
|
||||
<option value="">未指定 —— 激活前选一个岗位</option>
|
||||
{positions.map((q2) => (
|
||||
<option key={q2.id} value={q2.abbr}>
|
||||
{q2.abbr} · {q2.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</Field>
|
||||
)}
|
||||
{node.flavor !== 'approval' && (
|
||||
<Note>
|
||||
活动点<b>不带岗位</b> —— 谁来干是运营的事(分派机制未建前,运行时全员轮值、最闲者先)。
|
||||
</Note>
|
||||
)}
|
||||
<Note>
|
||||
编排<b>不带岗位</b> —— 负责人是运营时分配的:工作流绑了员工组按组轮值,
|
||||
没绑组全员轮值(最闲者先)。审批点与活动点同一口径。
|
||||
</Note>
|
||||
{node.kind === 'activity' && node.flavor === 'approval' && (
|
||||
<Note>
|
||||
<b>审批点是系统内置要素</b>,不是活动 —— 声明即用、零开发、不进活动库(一个流程包里需要开发的
|
||||
@@ -1043,9 +1020,6 @@ function FlowLab({
|
||||
(声明式:回指定节点重开新实例 / 终止)· 催办阶梯。运行时它产出<b>审批单</b>而非任务。
|
||||
</Note>
|
||||
)}
|
||||
{node.flavor === 'approval' && node.owner === undefined && (
|
||||
<Note tone="warn">这个审批点还没指定岗位 —— 不指定,起单时就不知道审批单该派给谁。</Note>
|
||||
)}
|
||||
</Prop>
|
||||
|
||||
{node.kind === 'activity' && (
|
||||
|
||||
@@ -143,7 +143,6 @@ function RuntimeHome({ tab, nav }: HomeProps) {
|
||||
title={a.title}
|
||||
sub={`${a.workflowSubject} · ${a.id}`}
|
||||
cols={[
|
||||
{ k: '审批岗位', v: a.approverPosition },
|
||||
{ k: '审批人', v: a.approverName },
|
||||
]}
|
||||
right={
|
||||
|
||||
Reference in New Issue
Block a user