版本号自己定:点编辑,整列版本进编辑态,取消/保存收尾

用户的目的是**自己改版本号**,不是让系统替他递增;顺带把上一轮那些
指示性交互全撤了 —— 这软件给专业业务设计人员用,不需要「点我改」的提示条。

界面:
  · 顶栏 编辑 → 取消 / 保存(与流程图卡「编辑 → 保存」同一套手势);
  · 行内两个字段:号(自己编)与名(各版不同),行尾 删除;
  · 改动攒在草稿里,按保存一趟落库;取消原样退出;
  · **删掉**:改名指示条、「点我改」虚下划线、`删掉 v4`/`激活 v4` 这类复述钮名的浮字。
    只留下禁用态那一句(生效版先停用 / 还不闭合),那不是指示,是钮为什么点不动。

后端 —— 号从「系统递增」放开为「设计人员自己编」,两道闸是数据本身要求的:
  · 撞号拒(VersionTakenError,409);
  · 在途钉版拒改号(那些单正按这个号找定义,搬号等于抽它们脚下的地板);
  · 已完结的单**跟着改指**:号在三处(包的列、definition、workflow.packageVersion)
    一起改 —— 号只是这一版的名牌,搬号连引用一起搬,留痕仍指同一份定义。
    先前写成「跑过单就不许改号」,实测等于任何试跑过的包永远编不了号,是过闸。
  · 名不设闸:标签不参与流转,在途钉版也能改;改名只动这一版(推翻前一日的
    「及于整条流」)—— 各版本正是靠名字互相区分,全同名等于没名字。

路由 POST /api/gov/process/:id/:version/edit 取代 …/:id/rename(单一消费者是本仓前端);
CONTRACT.md 与产品设计.md 同步,api-report 快照随本次提交。

实测(丁子乔账号,测后已 reset-runs 清运行数据):v4→v2→v4 往返,列表、画布图签、
库里三处同步;在途单存在时改号如实报 409 并原样退回。五闸绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
2026-07-29 22:15:19 +08:00
co-authored by Claude Opus 5
parent 05c0a57cad
commit f631b5b8bb
18 changed files with 405 additions and 179 deletions
+15 -2
View File
@@ -56,8 +56,15 @@ export type ProcessService = {
instancesOf(workflowId: string): Promise<NodeInstance[]>;
/** 删一版:生效版与在途钉版都不许删(见 `ActiveVersionError` / `PinnedVersionError`) */
deleteVersion(id: string, version: number): Promise<ProcessPackage[]>;
/** 改名:名字是这条流的身份,一次改及于所有版本 */
rename(id: string, name: string): Promise<ProcessPackage[]>;
/**
* 改版本记录:**号与名**,只动这一版 —— 号自己定。
* 名不设闸(标签不参与流转);号设两道:不许撞同流已有号(`VersionTakenError`)、
* 在途钉版不许改号(`PinnedVersionError`);已完结的单跟着改指,留痕不失真。
*/
editVersion(id: string, version: number, patch: {
version?: number;
name?: string;
}): Promise<ProcessPackage[]>;
nodeOwners(packageId: string): Promise<Record<string, string>>;
setNodeOwner(packageId: string, nodeId: string, staffId: string | undefined): Promise<void>;
/** 任务终态到达:完成即继续流转;非完成即走声明的失败走向 */
@@ -101,6 +108,12 @@ export declare class PinnedVersionError extends Error {
readonly inFlight: number;
constructor(packageId: string, version: number, inFlight: number);
}
/** 号被占:同一条流里版本号唯一 —— 换个号,或先把占号那版删了 */
export declare class VersionTakenError extends Error {
readonly packageId: string;
readonly version: number;
constructor(packageId: string, version: number);
}
export declare class PositionVacantError extends Error {
readonly position: string;
constructor(position: string);
+1 -1
View File
@@ -2,7 +2,7 @@
* module: process —— 唯一出口。只做 re-export,不写逻辑(编码规范 §10.1)。
*/
export type { ActivityContractFace, AssembleScope, Candidate, ClosureInput, ClosureReport, ClosureViolation, NodeInstance, OwnerSpec, ProcessPackage, ProcessService, ResolveContext, Resolution, StartWorkflowInput, WorkflowRecord, WorkflowState, } from './contract.ts';
export { ActiveVersionError, CallInterfaceViolationError, NotClosedError, PinnedVersionError, PositionVacantError, StaleVersionError } from './contract.ts';
export { ActiveVersionError, CallInterfaceViolationError, NotClosedError, VersionTakenError, PinnedVersionError, PositionVacantError, StaleVersionError } from './contract.ts';
export type { FlowRuntime, ActivityDirectory, ApprovalGateway, Clock, FlowEventPublisher, IdGenerator, OrgDirectory, ProcessStore, ReceiptNotifier, Sfeel, TaskGateway, } from './port.ts';
export type { ProcessServiceDeps } from './internal/usecase/process-service.ts';
export { createProcessService } from './internal/usecase/process-service.ts';
+8 -2
View File
@@ -68,8 +68,14 @@ export type ProcessStore = {
/** 只改状态,不动定义 —— state 在列上与 definition 里各存一份,两处要一起改 */
setPackageState(id: string, version: number, state: 'active' | 'retired'): Promise<void>;
deletePackage(id: string, version: number): Promise<void>;
/** 改名及于这条流的所有版本 —— 名字是流的身份,不是版本的属性 */
renameFlow(id: string, name: string): Promise<void>;
/** 只改一版的名 —— 名字是版本自己的属性(列上与 definition 里各一份,两处一起改) */
renameVersion(id: string, version: number, name: string): Promise<void>;
/**
* 改版本号 —— 号在三处:包的列上、definition 里、**跑过的单的 `packageVersion` 上**。
* 三处一起改:号只是这一版的名牌,搬号连引用一起搬,谁也不会指空或指错。
* 撞号与在途钉版由用例层先挡。
*/
renumberVersion(id: string, from: number, to: number): Promise<void>;
getPackage(id: string, version?: number): Promise<ProcessPackage | undefined>;
listPackages(): Promise<ProcessPackage[]>;
insertWorkflow(record: WorkflowRecord): Promise<void>;
+11 -5
View File
@@ -1053,17 +1053,23 @@ export declare const deleteProcessVersionRoute: {
}, z.core.$strip>;
};
/**
* 改名 —— 名字是**这条流的身份**,不是某一版的属性:一次改及于它的所有版本。
* (版本列表上只显示 v1/v2…,若只改一版的名,列表上什么也看不见,人会以为没生效。)
* 改版本记录 —— **版本号自己定**(2026-07-29 用户定)、名字随之:改哪版只动哪版。
*
* 号从前只能由系统递增。设计人员要能自己编号(1 / 2 / 10 都行),所以放开;
* 两条约束是数据本身要求的:号不许撞同流已有版本;**在途钉版不许改号**
* (那些单正按这个号找定义)。已完结的单跟着改指 —— 号只是这一版的名牌,
* 搬号连引用一起搬,留痕仍指同一份定义。
*/
export declare const renameProcessRoute: {
export declare const editProcessVersionRoute: {
readonly method: "POST";
readonly path: "/api/gov/process/:id/rename";
readonly path: "/api/gov/process/:id/:version/edit";
readonly params: z.ZodObject<{
id: z.ZodString;
version: z.ZodString;
}, z.core.$strip>;
readonly body: z.ZodObject<{
name: z.ZodString;
version: z.ZodOptional<z.ZodNumber>;
name: z.ZodOptional<z.ZodString>;
}, z.core.$strip>;
readonly output: z.ZodObject<{
packages: z.ZodArray<z.ZodObject<{