- Maps.vue:一键拉取教师组按钮 + 预览弹窗(科室/成员明细)+ 确认导入 - flow.ts:mapGroupPreview/mapImportGroups API - 含流程编辑器(def-editor)、路由 catch-all、示意图入口存量
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* 编辑器实时校验(方案 §3.5):镜像后端 DefValidator 中"可前端化"的业务规则。
|
||||
*
|
||||
* 分层:error 阻断保存(配置缺失类);warn 仅提示(映射缺失类,允许存草稿、发布时后端拦截)。
|
||||
* 结构类规则(id 唯一/度约束/孤儿/环/START·END 唯一)由结构化生成保证,前端无需校验。
|
||||
* 后端 DefValidator 仍是发布期权威,此处仅作体验前置。
|
||||
*/
|
||||
import { BRANCH_LABELS, DeptOption, EditorItem, EditorModel, MAX_BRANCHES, MIN_BRANCHES } from "./model";
|
||||
|
||||
export type IssueLevel = "error" | "warn";
|
||||
|
||||
export interface Issue {
|
||||
/** 命中节点 uid(画布就地标注);空容器等无归属问题为空 */
|
||||
uid: string;
|
||||
level: IssueLevel;
|
||||
/** 定位路径(主流程 / 主流程·分支①) */
|
||||
path: string;
|
||||
msg: string;
|
||||
/** 状态栏/卡片展示用完整文案 */
|
||||
text: string;
|
||||
}
|
||||
|
||||
export function validateModel(model: EditorModel, depts: DeptOption[]): Issue[] {
|
||||
const issues: Issue[] = [];
|
||||
const push = (uid: string, level: IssueLevel, path: string, msg: string): void => {
|
||||
issues.push({ uid, level, path, msg, text: `${path}:${msg}` });
|
||||
};
|
||||
|
||||
const rec = (items: EditorItem[], path: string): void => {
|
||||
items.forEach((item) => {
|
||||
if (item.kind === "approval") {
|
||||
if (!item.name.trim()) push(item.uid, "error", path, "节点名称不能为空");
|
||||
const a = item.assignee;
|
||||
if (!a) {
|
||||
push(item.uid, "error", path, "未配置审批人");
|
||||
} else if (a.type === "DEPT_KEY") {
|
||||
if (!a.deptKey) {
|
||||
push(item.uid, "error", path, "未选择科室映射");
|
||||
} else {
|
||||
const d = depts.find((x) => x.deptKey === a.deptKey);
|
||||
if (!d) {
|
||||
push(item.uid, "warn", path, `科室映射「${a.deptKey}」不存在,发布会被拦截`);
|
||||
} else if (!d.count) {
|
||||
push(item.uid, "warn", path, `科室「${d.deptName || d.deptKey}」无启用办理人,发布会被拦截`);
|
||||
}
|
||||
}
|
||||
} else if (!a.userIds.length) {
|
||||
push(item.uid, "error", path, "指定用户不能为空");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.branches.length < MIN_BRANCHES) {
|
||||
push(item.uid, "error", path, `并行分支至少保留 ${MIN_BRANCHES} 个`);
|
||||
}
|
||||
if (item.branches.length > MAX_BRANCHES) {
|
||||
push(item.uid, "error", path, `并行分支最多 ${MAX_BRANCHES} 个`);
|
||||
}
|
||||
item.branches.forEach((branch, i) => {
|
||||
const branchPath = `${path}·分支${BRANCH_LABELS[i] || i + 1}`;
|
||||
if (!branch.length) {
|
||||
// 结构化模型不允许空分支(删除最后一个节点会被父级拦截),此处仅兜底
|
||||
push(item.uid, "error", branchPath, "分支为空,请添加审批节点");
|
||||
return;
|
||||
}
|
||||
rec(branch, branchPath);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
rec(model.list, "主流程");
|
||||
return issues;
|
||||
}
|
||||
|
||||
export function countErrors(issues: Issue[]): Issue[] {
|
||||
return issues.filter((i) => i.level === "error");
|
||||
}
|
||||
|
||||
export function countWarns(issues: Issue[]): Issue[] {
|
||||
return issues.filter((i) => i.level === "warn");
|
||||
}
|
||||
Reference in New Issue
Block a user