Files
workspace/code/fms-workflow-refactor-backup-20260923/workflow/designer/constants.js
T
2026-09-23 16:54:54 +08:00

309 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 流程设计器 —— 枚举与节点元数据。
*
* 取值全部来自《FMS工作流与审批设计》与《FMS审批流程交互重构设计》:
* - 节点类型 b_node_type §4.4 / §6.4
* - 审批方式 b_approval_mode §6.4 / §9
* - 驳回策略 b_reject_mode §6.4 / §9.7
* - 审批人解析 b_actor_type §6.6
* - 条件操作符 §7.1
* - 审批行为开关 §5.2(全部落 b_config_json,不新增列)
*
* 数据库存稳定编码,中文文案只在本文件出现一次,页面直接引用。
* 唯一的例外是条件操作符文案:高级查询(fms-module-common/queryUtils.js)已经
* 定义了同一批操作符的文案与多语言键,这里复用而不是复制第二份翻译。
*/
import { operatorLabel } from '@/components/fms-module-common/queryUtils'
/** 领域草稿结构版本(《FMS审批流程交互重构设计》§6.1) */
export const SCHEMA_VERSION = 2
/** 工作流节点类型(落 wf_node.b_node_type) */
export const NODE_TYPES = {
START: 'start',
USER_TASK: 'user_task',
CC_TASK: 'cc_task',
EXCLUSIVE_GATEWAY: 'exclusive_gateway',
PARALLEL_GATEWAY: 'parallel_gateway',
SERVICE_TASK: 'service_task',
END: 'end',
}
/**
* 领域节点类型 ↔ LogicFlow 画布类型(《FMS工作流与审批设计》§19.5)。
* 画布类型只是前端渲染类型,落库一律用领域类型。
*/
export const NODE_TYPE_TO_CANVAS = {
[NODE_TYPES.START]: 'fms-start',
[NODE_TYPES.USER_TASK]: 'fms-user-task',
[NODE_TYPES.CC_TASK]: 'fms-cc-task',
[NODE_TYPES.EXCLUSIVE_GATEWAY]: 'fms-exclusive-gateway',
[NODE_TYPES.PARALLEL_GATEWAY]: 'fms-parallel-gateway',
[NODE_TYPES.SERVICE_TASK]: 'fms-service-task',
[NODE_TYPES.END]: 'fms-end',
}
/** 画布类型 → 领域节点类型(事件回调里反查用) */
export const CANVAS_TO_NODE_TYPE = Object.fromEntries(
Object.entries(NODE_TYPE_TO_CANVAS).map(([nodeType, canvasType]) => [canvasType, nodeType]),
)
/**
* 卡片模式(钉钉式纵向卡片)允许的节点类型(§3.1)。
* 出现其它类型说明流程不再是单链路,只能留在高级模式编辑。
*/
export const LINEAR_NODE_TYPES = [NODE_TYPES.START, NODE_TYPES.USER_TASK, NODE_TYPES.CC_TASK, NODE_TYPES.END]
/** 会让流程超出单链路的节点类型(§3.1 单链路判定) */
export const BRANCH_NODE_TYPES = [
NODE_TYPES.EXCLUSIVE_GATEWAY,
NODE_TYPES.PARALLEL_GATEWAY,
NODE_TYPES.SERVICE_TASK,
]
/**
* 节点元数据:左侧面板顺序、显示名、形状、尺寸与配色。
*
* 画布是 SVG,fill/stroke 走的是表现属性而不是 CSS,`var(--fms-*)` 在这里不生效,
* 因此配色写成字面量(与 tokens.css 同色系)。深色模式下的画布配色待后续统一处理。
*/
export const NODE_META = {
[NODE_TYPES.START]: {
label: '开始',
shape: 'circle',
size: { r: 26 },
style: { fill: '#ecfdf5', stroke: '#16a34a' },
/** 开始节点不可删除、不可改属性 */
fixed: true,
hint: '流程入口,有且只有一个',
},
[NODE_TYPES.USER_TASK]: {
label: '人工审批',
shape: 'rect',
size: { width: 160, height: 48 },
style: { fill: '#eef2ff', stroke: '#4f46e5' },
hint: '由审批人处理的节点',
},
[NODE_TYPES.CC_TASK]: {
label: '抄送',
shape: 'rect',
size: { width: 160, height: 48 },
style: { fill: '#f0f9ff', stroke: '#0284c7' },
hint: '只通知不产生待办,自动完成',
},
[NODE_TYPES.EXCLUSIVE_GATEWAY]: {
label: '条件分支',
shape: 'diamond',
size: { rx: 34, ry: 34 },
style: { fill: '#fff7ed', stroke: '#ea580c' },
hint: '按连线条件择一分支,必须有默认出口',
},
[NODE_TYPES.PARALLEL_GATEWAY]: {
label: '并行分支',
shape: 'diamond',
size: { rx: 34, ry: 34 },
style: { fill: '#f5f3ff', stroke: '#7c3aed' },
hint: '所有出线同时激活',
},
[NODE_TYPES.SERVICE_TASK]: {
label: '服务节点',
shape: 'rect',
size: { width: 160, height: 48 },
style: { fill: '#fefce8', stroke: '#ca8a04' },
hint: '后端服务动作,第一阶段仅占位',
},
[NODE_TYPES.END]: {
label: '结束',
shape: 'circle',
size: { r: 26 },
style: { fill: '#f4f4f5', stroke: '#71717a' },
fixed: true,
hint: '流程出口,可以有多个',
},
}
/** 左侧面板的展示顺序 */
export const NODE_PALETTE_ORDER = [
NODE_TYPES.START,
NODE_TYPES.USER_TASK,
NODE_TYPES.CC_TASK,
NODE_TYPES.EXCLUSIVE_GATEWAY,
NODE_TYPES.PARALLEL_GATEWAY,
NODE_TYPES.SERVICE_TASK,
NODE_TYPES.END,
]
/** 卡片模式「插入节点」可选的类型(开始/结束是固定端点,不参与插入) */
export const INSERTABLE_NODE_TYPES = [NODE_TYPES.USER_TASK, NODE_TYPES.CC_TASK]
/** 需要配审批人/抄送人的节点类型 */
export const ACTOR_NODE_TYPES = [NODE_TYPES.USER_TASK, NODE_TYPES.CC_TASK]
/**
* 审批方式 b_approval_mode(§6.4)。
* param 指向需要额外填写的参数:N 人通过要人数、按比例通过要比例。
*/
export const APPROVAL_MODES = [
{ value: 'single', label: '单人审批', param: null },
{ value: 'any', label: '或签(任一人通过)', param: null },
{ value: 'all', label: '会签(全部通过)', param: null },
{ value: 'serial', label: '串行会签', param: null },
{ value: 'n_of_m', label: 'N 人通过', param: 'requiredCount' },
{ value: 'percentage', label: '按比例通过', param: 'requiredRatio' },
]
/** 驳回策略 b_reject_mode(§9.7) */
export const REJECT_MODES = [
{ value: 'terminate', label: '驳回即结束(一票否决)' },
{ value: 'return_initiator', label: '退回发起人' },
{ value: 'return_previous', label: '退回上一节点' },
]
/**
* 审批人解析类型 b_actor_type(§6.6)。
* control 决定属性抽屉用哪种控件取 b_actor_ref:
* user/position/org_role → 选择器(提交稳定编码)
* field → 字段选择器(字段必须来自当前模块 s_field)
* dept → 部门来源固定选项
* resolver → 后端注册的解析器编码
* none → 无参,靠流程上下文解析
*/
export const ACTOR_TYPES = [
{ value: 'user', label: '指定用户', control: 'user' },
{ value: 'initiator', label: '发起人', control: 'none' },
{ value: 'initiator_manager', label: '发起人直属领导', control: 'none' },
{ value: 'dept_manager', label: '部门负责人', control: 'dept' },
{ value: 'position', label: '岗位', control: 'position' },
{ value: 'org_role', label: '组织角色', control: 'org_role' },
{ value: 'field_user', label: '业务字段用户', control: 'field' },
{ value: 'custom', label: '自定义解析器', control: 'resolver' },
]
/** 需要填 b_actor_ref 的解析类型(由 control 派生,避免两处维护) */
export const ACTOR_TYPES_WITH_REF = ACTOR_TYPES.filter((item) => item.control !== 'none').map(
(item) => item.value,
)
/** 部门负责人的部门来源(§5.2「可选择发起人部门或业务部门」,编码存 b_actor_ref) */
export const DEPT_MANAGER_SOURCES = [
{ value: 'initiator_dept', label: '发起人所属部门' },
{ value: 'business_dept', label: '业务归属部门' },
]
/** 审批人解析为空时的兜底 b_fallback_type(§6.6) */
export const FALLBACK_TYPES = [
{ value: 'none', label: '不兜底(阻塞并告警)' },
{ value: 'admin', label: '转交管理员' },
{ value: 'initiator', label: '转交发起人' },
{ value: 'custom', label: '自定义解析器' },
]
/** 兜底策略里需要填编码的类型 */
export const FALLBACK_TYPES_WITH_REF = ['custom']
/**
* 节点审批行为开关(§5.2)。
* 全部落在 wf_node.b_config_json,不为了每个开关新增一列(§7.2)。
*/
export const NODE_BEHAVIOR_FLAGS = [
{
key: 'allowInitiator',
label: '允许申请人自审',
hint: '默认关闭;关闭时发起人不会成为本节点审批人',
},
{
key: 'excludePreviousActors',
label: '排除前序审批人',
hint: '已在前面节点审批过的人不再重复收到待办',
},
{ key: 'allowClaim', label: '允许抢占', hint: '候选人可主动认领待办' },
{ key: 'allowTransfer', label: '允许转交', hint: '审批人可把待办转交他人' },
{ key: 'allowDelegate', label: '允许委托', hint: '审批人可临时委托他人处理' },
{ key: 'allowAddApprover', label: '允许加签', hint: '审批人可向当前节点追加审批人' },
{ key: 'commentRequired', label: '审批意见必填', hint: '提交审批动作时必须填写意见' },
]
/** 业务事件 b_event(§6.3) */
export const BINDING_EVENTS = [
{ value: 'submit', label: '送审' },
{ value: 'resubmit', label: '重新提交' },
{ value: 'change', label: '变更' },
]
/** 版本状态 b_status(§4.2) */
export const VERSION_STATUS = [
{ value: 'draft', label: '草稿', tag: 'secondary' },
{ value: 'published', label: '已发布', tag: 'success' },
{ value: 'retired', label: '已停用', tag: 'default' },
]
/** 草稿保存状态(§8.2 工具栏),仅前端状态 */
export const DRAFT_STATUS = {
IDLE: 'idle',
DIRTY: 'dirty',
SAVING: 'saving',
SAVED: 'saved',
ERROR: 'error',
}
export const DRAFT_STATUS_LABEL = {
idle: '未修改',
dirty: '未保存',
saving: '保存中',
saved: '已保存',
error: '保存失败',
}
/** 编辑器模式(§3.3)——只放组件状态,不落库、不进草稿 */
export const EDITOR_MODES = {
STEP: 'step',
CANVAS: 'canvas',
}
/**
* 条件 AST 的逻辑节点(§7.1)。
* 连线条件为空表示默认出口,条件分支节点必须保留一条这样的连线。
*/
export const CONDITION_LOGICS = [
{ value: 'all', label: '全部满足(且)' },
{ value: 'any', label: '任一满足(或)' },
]
/**
* 工作流条件支持的操作符(§7.1)。
* 只列编码,文案由 queryUtils.operatorLabel 提供(高级查询与工作流共用一套翻译)。
*/
export const CONDITION_OPERATORS = [
'eq',
'ne',
'gt',
'ge',
'lt',
'le',
'in',
'not_in',
'like',
'is_null',
'is_not_null',
'between',
]
/** 不需要填值的操作符 */
export const OPERATORS_WITHOUT_VALUE = ['is_null', 'is_not_null']
/** 值是多选列表的操作符 */
export const OPERATORS_WITH_LIST_VALUE = ['in', 'not_in']
/** 值是区间的操作符 */
export const OPERATORS_WITH_RANGE_VALUE = ['between']
/** 操作符显示文案:多语言键优先,缺翻译回退中文(与高级查询同一份定义) */
export function conditionOperatorLabel(operator, translate) {
return operatorLabel(operator, translate)
}
/** 按编码取中文名,找不到回落到编码本身 */
export function labelOf(list, value) {
return list.find((item) => item.value === value)?.label || value || ''
}