fix: 修复表单校验回调弃用与 BPMN 告警
- 将 web-antd、web-antdv-next、web-ele 中的表单 validator 从 callback 改为 Promise - 为 BPMN viewer 的 xml 增加空值兜底,避免 undefined prop warning - 移除流程详情用户选择弹窗的无效 title 透传 - 调整 simple-bpm-viewer 函数声明顺序,避免 immediate watch 初始化时报错
This commit is contained in:
@@ -112,41 +112,37 @@ export namespace ThingModelApi {
|
||||
|
||||
/** 生成「必填 + 数字」类校验器:拼到 size / length / 枚举值上 */
|
||||
function buildRequiredNumberValidator(label: string) {
|
||||
return (_rule: any, value: any, callback: any) => {
|
||||
return (_rule: any, value: any) => {
|
||||
if (isEmpty(value)) {
|
||||
callback(new Error(`${label}不能为空`));
|
||||
return;
|
||||
return Promise.reject(new Error(`${label}不能为空`));
|
||||
}
|
||||
if (Number.isNaN(Number(value))) {
|
||||
callback(new Error(`${label}必须是数字`));
|
||||
return;
|
||||
return Promise.reject(new Error(`${label}必须是数字`));
|
||||
}
|
||||
callback();
|
||||
return Promise.resolve();
|
||||
};
|
||||
}
|
||||
|
||||
/** 生成「标识符样式」名称校验器:开头需为中文 / 英文 / 数字,整体仅允许中文、英文、数字、下划线、短划线,长度 ≤ 20 */
|
||||
export function buildIdentifierLikeNameValidator(label: string) {
|
||||
return (_rule: any, value: string, callback: any) => {
|
||||
return (_rule: any, value: string) => {
|
||||
if (isEmpty(value)) {
|
||||
callback(new Error(`${label}不能为空`));
|
||||
return;
|
||||
return Promise.reject(new Error(`${label}不能为空`));
|
||||
}
|
||||
if (!/^[一-龥A-Za-z0-9]/.test(value)) {
|
||||
callback(new Error(`${label}必须以中文、英文字母或数字开头`));
|
||||
return;
|
||||
return Promise.reject(
|
||||
new Error(`${label}必须以中文、英文字母或数字开头`),
|
||||
);
|
||||
}
|
||||
if (!/^[一-龥A-Za-z0-9][\w一-龥-]*$/.test(value)) {
|
||||
callback(
|
||||
return Promise.reject(
|
||||
new Error(`${label}只能包含中文、英文字母、数字、下划线和短划线`),
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (value.length > 20) {
|
||||
callback(new Error(`${label}长度不能超过 20 个字符`));
|
||||
return;
|
||||
return Promise.reject(new Error(`${label}长度不能超过 20 个字符`));
|
||||
}
|
||||
callback();
|
||||
return Promise.resolve();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -170,7 +166,7 @@ export const ThingModelFormRules: Record<string, Rule[]> = {
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
validator: (_rule: any, value: string, callback: any) => {
|
||||
validator: (_rule: any, value: string) => {
|
||||
const reservedKeywords = [
|
||||
'set',
|
||||
'get',
|
||||
@@ -181,18 +177,16 @@ export const ThingModelFormRules: Record<string, Rule[]> = {
|
||||
'value',
|
||||
];
|
||||
if (reservedKeywords.includes(value)) {
|
||||
callback(
|
||||
return Promise.reject(
|
||||
new Error(
|
||||
'set, get, post, property, event, time, value 是系统保留字段,不能用于标识符定义',
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (/^\d+$/.test(value)) {
|
||||
callback(new Error('标识符不能是纯数字'));
|
||||
return;
|
||||
return Promise.reject(new Error('标识符不能是纯数字'));
|
||||
}
|
||||
callback();
|
||||
return Promise.resolve();
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
|
||||
@@ -15,8 +15,8 @@ import '../theme/index.scss';
|
||||
|
||||
const props = defineProps({
|
||||
xml: {
|
||||
default: '',
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
view: {
|
||||
type: Object,
|
||||
@@ -185,12 +185,12 @@ const onSelectElement = (element: any) => {
|
||||
};
|
||||
|
||||
/** 初始化 BPMN 视图 */
|
||||
const importXML = async (xml: string) => {
|
||||
const importXML = async (xml?: string) => {
|
||||
// 清空流程图
|
||||
clearViewer();
|
||||
|
||||
// 初始化流程图
|
||||
if (xml !== null && xml !== '') {
|
||||
if (xml) {
|
||||
try {
|
||||
bpmnViewer.value = new BpmnViewer({
|
||||
additionalModules: [MoveCanvasModule],
|
||||
@@ -303,7 +303,7 @@ const setProcessStatus = (view: any) => {
|
||||
watch(
|
||||
() => props.xml,
|
||||
(newXml) => {
|
||||
importXML(newXml);
|
||||
importXML(newXml || '');
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
@@ -318,7 +318,7 @@ watch(
|
||||
|
||||
/** mounted:初始化 */
|
||||
onMounted(() => {
|
||||
importXML(props.xml);
|
||||
importXML(props.xml || '');
|
||||
setProcessStatus(props.view);
|
||||
});
|
||||
|
||||
|
||||
@@ -68,20 +68,18 @@ const rules: Record<string, Rule[]> = {
|
||||
key: [
|
||||
{ required: true, message: '流程标识不能为空', trigger: 'blur' },
|
||||
{
|
||||
validator: (_rule: any, value: string, callback: any) => {
|
||||
validator: (_rule: any, value: string) => {
|
||||
if (!value) {
|
||||
callback();
|
||||
return;
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (!/^[a-z_][-\w.$]*$/i.test(value)) {
|
||||
callback(
|
||||
return Promise.reject(
|
||||
new Error(
|
||||
'只能包含字母、数字、下划线、连字符和点号,且必须以字母或下划线开头',
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
callback();
|
||||
return Promise.resolve();
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
|
||||
@@ -67,7 +67,7 @@ const startUserSelectTasks = ref<UserTask[]>([]);
|
||||
const startUserSelectAssignees = ref<Record<string, number[]>>({});
|
||||
const tempStartUserSelectAssignees = ref<Record<string, number[]>>({});
|
||||
|
||||
const bpmnXML = ref<string | undefined>(undefined);
|
||||
const bpmnXML = ref('');
|
||||
const simpleJson = ref<string | undefined>(undefined);
|
||||
|
||||
const activeTab = ref('form');
|
||||
@@ -158,7 +158,7 @@ async function initProcessInfo(row: any, formVariables?: any) {
|
||||
const processDefinitionDetail: BpmProcessDefinitionApi.ProcessDefinition =
|
||||
await getProcessDefinition(row.id);
|
||||
if (processDefinitionDetail) {
|
||||
bpmnXML.value = processDefinitionDetail.bpmnXml;
|
||||
bpmnXML.value = processDefinitionDetail.bpmnXml || '';
|
||||
simpleJson.value = processDefinitionDetail.simpleModel;
|
||||
}
|
||||
// 情况二:业务表单
|
||||
|
||||
@@ -9,7 +9,7 @@ const props = withDefaults(
|
||||
defineProps<{
|
||||
bpmnXml?: string;
|
||||
loading?: boolean; // 是否加载中
|
||||
modelView?: object;
|
||||
modelView?: Record<string, any>;
|
||||
}>(),
|
||||
{
|
||||
loading: false,
|
||||
@@ -29,8 +29,10 @@ watch(
|
||||
async (newModelView) => {
|
||||
// 加载最新
|
||||
if (newModelView) {
|
||||
// @ts-expect-error: viewer instance type is broader than local ref typing
|
||||
view.value = newModelView;
|
||||
view.value = {
|
||||
...newModelView,
|
||||
bpmnXml: newModelView.bpmnXml || '',
|
||||
};
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
@@ -40,7 +42,7 @@ watch(
|
||||
watch(
|
||||
() => props.bpmnXml,
|
||||
(value) => {
|
||||
view.value.bpmnXml = value;
|
||||
view.value.bpmnXml = value || '';
|
||||
},
|
||||
);
|
||||
</script>
|
||||
@@ -52,7 +54,7 @@ watch(
|
||||
>
|
||||
<MyProcessViewer
|
||||
key="processViewer"
|
||||
:xml="view.bpmnXml"
|
||||
:xml="view.bpmnXml || ''"
|
||||
:view="view"
|
||||
class="h-full min-h-[500px] w-full"
|
||||
/>
|
||||
|
||||
@@ -26,57 +26,14 @@ const simpleModel = ref<any>({});
|
||||
const tasks = ref([]); // 用户任务
|
||||
const processInstance = ref(); // 流程实例
|
||||
|
||||
/** 监控模型视图 包括任务列表、进行中的活动节点编号等 */
|
||||
watch(
|
||||
() => props.modelView,
|
||||
async (newModelView) => {
|
||||
if (newModelView) {
|
||||
tasks.value = newModelView.tasks;
|
||||
processInstance.value = newModelView.processInstance;
|
||||
// 已经拒绝的活动节点编号集合,只包括 UserTask
|
||||
const rejectedTaskActivityIds: string[] =
|
||||
newModelView.rejectedTaskActivityIds;
|
||||
// 进行中的活动节点编号集合, 只包括 UserTask
|
||||
const unfinishedTaskActivityIds: string[] =
|
||||
newModelView.unfinishedTaskActivityIds;
|
||||
// 已经完成的活动节点编号集合, 包括 UserTask、Gateway 等
|
||||
const finishedActivityIds: string[] =
|
||||
newModelView.finishedTaskActivityIds;
|
||||
// 已经完成的连线节点编号集合,只包括 SequenceFlow
|
||||
const finishedSequenceFlowActivityIds: string[] =
|
||||
newModelView.finishedSequenceFlowActivityIds;
|
||||
setSimpleModelNodeTaskStatus(
|
||||
newModelView.simpleModel,
|
||||
newModelView.processInstance?.status,
|
||||
rejectedTaskActivityIds,
|
||||
unfinishedTaskActivityIds,
|
||||
finishedActivityIds,
|
||||
finishedSequenceFlowActivityIds,
|
||||
);
|
||||
simpleModel.value = newModelView.simpleModel || {};
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
/** 监控模型结构数据 */
|
||||
watch(
|
||||
() => props.simpleJson,
|
||||
async (value) => {
|
||||
if (value) {
|
||||
simpleModel.value = JSON.parse(value);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const setSimpleModelNodeTaskStatus = (
|
||||
function setSimpleModelNodeTaskStatus(
|
||||
simpleModel: SimpleFlowNode | undefined,
|
||||
processStatus: number,
|
||||
rejectedTaskActivityIds: string[],
|
||||
unfinishedTaskActivityIds: string[],
|
||||
finishedActivityIds: string[],
|
||||
finishedSequenceFlowActivityIds: string[],
|
||||
) => {
|
||||
) {
|
||||
if (!simpleModel) {
|
||||
return;
|
||||
}
|
||||
@@ -166,7 +123,50 @@ const setSimpleModelNodeTaskStatus = (
|
||||
finishedActivityIds,
|
||||
finishedSequenceFlowActivityIds,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/** 监控模型视图 包括任务列表、进行中的活动节点编号等 */
|
||||
watch(
|
||||
() => props.modelView,
|
||||
async (newModelView) => {
|
||||
if (newModelView) {
|
||||
tasks.value = newModelView.tasks;
|
||||
processInstance.value = newModelView.processInstance;
|
||||
// 已经拒绝的活动节点编号集合,只包括 UserTask
|
||||
const rejectedTaskActivityIds: string[] =
|
||||
newModelView.rejectedTaskActivityIds;
|
||||
// 进行中的活动节点编号集合, 只包括 UserTask
|
||||
const unfinishedTaskActivityIds: string[] =
|
||||
newModelView.unfinishedTaskActivityIds;
|
||||
// 已经完成的活动节点编号集合, 包括 UserTask、Gateway 等
|
||||
const finishedActivityIds: string[] =
|
||||
newModelView.finishedTaskActivityIds;
|
||||
// 已经完成的连线节点编号集合,只包括 SequenceFlow
|
||||
const finishedSequenceFlowActivityIds: string[] =
|
||||
newModelView.finishedSequenceFlowActivityIds;
|
||||
setSimpleModelNodeTaskStatus(
|
||||
newModelView.simpleModel,
|
||||
newModelView.processInstance?.status,
|
||||
rejectedTaskActivityIds,
|
||||
unfinishedTaskActivityIds,
|
||||
finishedActivityIds,
|
||||
finishedSequenceFlowActivityIds,
|
||||
);
|
||||
simpleModel.value = newModelView.simpleModel || {};
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
/** 监控模型结构数据 */
|
||||
watch(
|
||||
() => props.simpleJson,
|
||||
async (value) => {
|
||||
if (value) {
|
||||
simpleModel.value = JSON.parse(value);
|
||||
}
|
||||
},
|
||||
);
|
||||
</script>
|
||||
<template>
|
||||
<div v-loading="loading">
|
||||
|
||||
@@ -482,7 +482,6 @@ defineExpose({ setCustomApproveUsers, batchSetCustomApproveUsers });
|
||||
class="w-3/5"
|
||||
v-model:value="selectedUsers"
|
||||
:multiple="true"
|
||||
title="选择用户"
|
||||
@confirm="handleUserSelectConfirm"
|
||||
@closed="handleUserSelectClosed"
|
||||
@cancel="handleUserSelectCancel"
|
||||
|
||||
@@ -122,23 +122,21 @@ function normalizeFormData(result: any): RuleSceneApi.SceneRule {
|
||||
}
|
||||
|
||||
/** 触发器校验 */
|
||||
function validateTriggers(_rule: any, value: any, callback: any) {
|
||||
function validateTriggers(_rule: any, value: any) {
|
||||
const error = validateSceneRuleTriggers(value);
|
||||
if (error) {
|
||||
callback(new Error(error));
|
||||
return;
|
||||
return Promise.reject(new Error(error));
|
||||
}
|
||||
callback();
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/** 执行器校验 */
|
||||
function validateActions(_rule: any, value: any, callback: any) {
|
||||
function validateActions(_rule: any, value: any) {
|
||||
const error = validateSceneRuleActions(value);
|
||||
if (error) {
|
||||
callback(new Error(error));
|
||||
return;
|
||||
return Promise.reject(new Error(error));
|
||||
}
|
||||
callback();
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const formRules = reactive({
|
||||
|
||||
@@ -35,51 +35,44 @@ function deleteEnum(index: number) {
|
||||
}
|
||||
|
||||
/** 校验单项枚举值:必填、数字、不重复 */
|
||||
function validateEnumValue(_rule: any, value: any, callback: any) {
|
||||
function validateEnumValue(_rule: any, value: any) {
|
||||
if (isEmpty(value)) {
|
||||
callback(new Error('枚举值不能为空'));
|
||||
return;
|
||||
return Promise.reject(new Error('枚举值不能为空'));
|
||||
}
|
||||
if (Number.isNaN(Number(value))) {
|
||||
callback(new Error('枚举值必须是数字'));
|
||||
return;
|
||||
return Promise.reject(new Error('枚举值必须是数字'));
|
||||
}
|
||||
const sameCount = dataSpecsList.value.filter(
|
||||
(it) => it.value === value,
|
||||
).length;
|
||||
if (sameCount > 1) {
|
||||
callback(new Error('枚举值不能重复'));
|
||||
return;
|
||||
return Promise.reject(new Error('枚举值不能重复'));
|
||||
}
|
||||
callback();
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/** 校验整个枚举列表:非空、无空项、无非法数字、无重复 */
|
||||
function validateEnumList(_rule: any, _value: any, callback: any) {
|
||||
function validateEnumList(_rule: any, _value: any) {
|
||||
if (isEmpty(dataSpecsList.value)) {
|
||||
callback(new Error('请至少添加一个枚举项'));
|
||||
return;
|
||||
return Promise.reject(new Error('请至少添加一个枚举项'));
|
||||
}
|
||||
const hasEmpty = dataSpecsList.value.some(
|
||||
(item) => isEmpty(item.value) || isEmpty(item.name),
|
||||
);
|
||||
if (hasEmpty) {
|
||||
callback(new Error('存在未填写的枚举值或描述'));
|
||||
return;
|
||||
return Promise.reject(new Error('存在未填写的枚举值或描述'));
|
||||
}
|
||||
const hasInvalidNumber = dataSpecsList.value.some((item) =>
|
||||
Number.isNaN(Number(item.value)),
|
||||
);
|
||||
if (hasInvalidNumber) {
|
||||
callback(new Error('存在非数字的枚举值'));
|
||||
return;
|
||||
return Promise.reject(new Error('存在非数字的枚举值'));
|
||||
}
|
||||
const values = dataSpecsList.value.map((item) => item.value);
|
||||
if (new Set(values).size !== values.length) {
|
||||
callback(new Error('存在重复的枚举值'));
|
||||
return;
|
||||
return Promise.reject(new Error('存在重复的枚举值'));
|
||||
}
|
||||
callback();
|
||||
return Promise.resolve();
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -36,53 +36,46 @@ function unitChange(unitSpecs: any) {
|
||||
}
|
||||
|
||||
/** 校验最小值 */
|
||||
function validateMin(_rule: any, _value: any, callback: any) {
|
||||
function validateMin(_rule: any, _value: any) {
|
||||
const min = Number(dataSpecs.value.min);
|
||||
const max = Number(dataSpecs.value.max);
|
||||
if (Number.isNaN(min)) {
|
||||
callback(new Error('请输入有效的数值'));
|
||||
return;
|
||||
return Promise.reject(new Error('请输入有效的数值'));
|
||||
}
|
||||
if (!Number.isNaN(max) && min >= max) {
|
||||
callback(new Error('最小值必须小于最大值'));
|
||||
return;
|
||||
return Promise.reject(new Error('最小值必须小于最大值'));
|
||||
}
|
||||
callback();
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/** 校验最大值 */
|
||||
function validateMax(_rule: any, _value: any, callback: any) {
|
||||
function validateMax(_rule: any, _value: any) {
|
||||
const min = Number(dataSpecs.value.min);
|
||||
const max = Number(dataSpecs.value.max);
|
||||
if (Number.isNaN(max)) {
|
||||
callback(new Error('请输入有效的数值'));
|
||||
return;
|
||||
return Promise.reject(new Error('请输入有效的数值'));
|
||||
}
|
||||
if (!Number.isNaN(min) && max <= min) {
|
||||
callback(new Error('最大值必须大于最小值'));
|
||||
return;
|
||||
return Promise.reject(new Error('最大值必须大于最小值'));
|
||||
}
|
||||
callback();
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/** 校验步长 */
|
||||
function validateStep(_rule: any, _value: any, callback: any) {
|
||||
function validateStep(_rule: any, _value: any) {
|
||||
const step = Number(dataSpecs.value.step);
|
||||
if (Number.isNaN(step)) {
|
||||
callback(new Error('请输入有效的数值'));
|
||||
return;
|
||||
return Promise.reject(new Error('请输入有效的数值'));
|
||||
}
|
||||
if (step <= 0) {
|
||||
callback(new Error('步长必须大于 0'));
|
||||
return;
|
||||
return Promise.reject(new Error('步长必须大于 0'));
|
||||
}
|
||||
const min = Number(dataSpecs.value.min);
|
||||
const max = Number(dataSpecs.value.max);
|
||||
if (!Number.isNaN(min) && !Number.isNaN(max) && step > max - min) {
|
||||
callback(new Error('步长不能大于最大值与最小值的差值'));
|
||||
return;
|
||||
return Promise.reject(new Error('步长不能大于最大值与最小值的差值'));
|
||||
}
|
||||
callback();
|
||||
return Promise.resolve();
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -33,12 +33,11 @@ const structFormRef = ref();
|
||||
const formData = ref<any>(buildEmptyFormData());
|
||||
|
||||
/** 校验结构体属性对象非空 */
|
||||
function validateStructSpecsList(_rule: any, _value: any, callback: any) {
|
||||
function validateStructSpecsList(_rule: any, _value: any) {
|
||||
if (isEmpty(dataSpecsList.value)) {
|
||||
callback(new Error('请至少添加一个结构体属性对象'));
|
||||
return;
|
||||
return Promise.reject(new Error('请至少添加一个结构体属性对象'));
|
||||
}
|
||||
callback();
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
|
||||
@@ -114,41 +114,37 @@ export namespace ThingModelApi {
|
||||
|
||||
/** 生成「必填 + 数字」类校验器:拼到 size / length / 枚举值上 */
|
||||
function buildRequiredNumberValidator(label: string) {
|
||||
return (_rule: any, value: any, callback: any) => {
|
||||
return (_rule: any, value: any) => {
|
||||
if (isEmpty(value)) {
|
||||
callback(new Error(`${label}不能为空`));
|
||||
return;
|
||||
return Promise.reject(new Error(`${label}不能为空`));
|
||||
}
|
||||
if (Number.isNaN(Number(value))) {
|
||||
callback(new Error(`${label}必须是数字`));
|
||||
return;
|
||||
return Promise.reject(new Error(`${label}必须是数字`));
|
||||
}
|
||||
callback();
|
||||
return Promise.resolve();
|
||||
};
|
||||
}
|
||||
|
||||
/** 生成「标识符样式」名称校验器:开头需为中文 / 英文 / 数字,整体仅允许中文、英文、数字、下划线、短划线,长度 ≤ 20 */
|
||||
export function buildIdentifierLikeNameValidator(label: string) {
|
||||
return (_rule: any, value: string, callback: any) => {
|
||||
return (_rule: any, value: string) => {
|
||||
if (isEmpty(value)) {
|
||||
callback(new Error(`${label}不能为空`));
|
||||
return;
|
||||
return Promise.reject(new Error(`${label}不能为空`));
|
||||
}
|
||||
if (!/^[一-龥A-Za-z0-9]/.test(value)) {
|
||||
callback(new Error(`${label}必须以中文、英文字母或数字开头`));
|
||||
return;
|
||||
return Promise.reject(
|
||||
new Error(`${label}必须以中文、英文字母或数字开头`),
|
||||
);
|
||||
}
|
||||
if (!/^[一-龥A-Za-z0-9][\w一-龥-]*$/.test(value)) {
|
||||
callback(
|
||||
return Promise.reject(
|
||||
new Error(`${label}只能包含中文、英文字母、数字、下划线和短划线`),
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (value.length > 20) {
|
||||
callback(new Error(`${label}长度不能超过 20 个字符`));
|
||||
return;
|
||||
return Promise.reject(new Error(`${label}长度不能超过 20 个字符`));
|
||||
}
|
||||
callback();
|
||||
return Promise.resolve();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -172,7 +168,7 @@ export const ThingModelFormRules: Record<string, FormItemRule[]> = {
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
validator: (_rule: any, value: string, callback: any) => {
|
||||
validator: (_rule: any, value: string) => {
|
||||
const reservedKeywords = [
|
||||
'set',
|
||||
'get',
|
||||
@@ -183,18 +179,16 @@ export const ThingModelFormRules: Record<string, FormItemRule[]> = {
|
||||
'value',
|
||||
];
|
||||
if (reservedKeywords.includes(value)) {
|
||||
callback(
|
||||
return Promise.reject(
|
||||
new Error(
|
||||
'set, get, post, property, event, time, value 是系统保留字段,不能用于标识符定义',
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (/^\d+$/.test(value)) {
|
||||
callback(new Error('标识符不能是纯数字'));
|
||||
return;
|
||||
return Promise.reject(new Error('标识符不能是纯数字'));
|
||||
}
|
||||
callback();
|
||||
return Promise.resolve();
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
|
||||
@@ -25,8 +25,8 @@ import '../theme/index.scss';
|
||||
|
||||
const props = defineProps({
|
||||
xml: {
|
||||
default: '',
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
view: {
|
||||
type: Object,
|
||||
@@ -269,12 +269,12 @@ const onSelectElement = (element: any) => {
|
||||
};
|
||||
|
||||
/** 初始化 BPMN 视图 */
|
||||
const importXML = async (xml: string) => {
|
||||
const importXML = async (xml?: string) => {
|
||||
// 清空流程图
|
||||
clearViewer();
|
||||
|
||||
// 初始化流程图
|
||||
if (xml !== null && xml !== '') {
|
||||
if (xml) {
|
||||
try {
|
||||
bpmnViewer.value = new BpmnViewer({
|
||||
additionalModules: [MoveCanvasModule],
|
||||
@@ -387,7 +387,7 @@ const setProcessStatus = (view: any) => {
|
||||
watch(
|
||||
() => props.xml,
|
||||
(newXml) => {
|
||||
importXML(newXml);
|
||||
importXML(newXml || '');
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
@@ -402,7 +402,7 @@ watch(
|
||||
|
||||
/** mounted:初始化 */
|
||||
onMounted(() => {
|
||||
importXML(props.xml);
|
||||
importXML(props.xml || '');
|
||||
setProcessStatus(props.view);
|
||||
});
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ const startUserSelectTasks = ref<UserTask[]>([]);
|
||||
const startUserSelectAssignees = ref<Record<string, number[]>>({});
|
||||
const tempStartUserSelectAssignees = ref<Record<string, number[]>>({});
|
||||
|
||||
const bpmnXML = ref<string | undefined>(undefined);
|
||||
const bpmnXML = ref('');
|
||||
const simpleJson = ref<string | undefined>(undefined);
|
||||
|
||||
const activeTab = ref('form');
|
||||
@@ -167,7 +167,7 @@ async function initProcessInfo(row: any, formVariables?: any) {
|
||||
const processDefinitionDetail: BpmProcessDefinitionApi.ProcessDefinition =
|
||||
await getProcessDefinition(row.id);
|
||||
if (processDefinitionDetail) {
|
||||
bpmnXML.value = processDefinitionDetail.bpmnXml;
|
||||
bpmnXML.value = processDefinitionDetail.bpmnXml || '';
|
||||
simpleJson.value = processDefinitionDetail.simpleModel;
|
||||
}
|
||||
// 情况二:业务表单
|
||||
|
||||
@@ -9,7 +9,7 @@ const props = withDefaults(
|
||||
defineProps<{
|
||||
bpmnXml?: string;
|
||||
loading?: boolean; // 是否加载中
|
||||
modelView?: object;
|
||||
modelView?: Record<string, any>;
|
||||
}>(),
|
||||
{
|
||||
loading: false,
|
||||
@@ -29,8 +29,10 @@ watch(
|
||||
async (newModelView) => {
|
||||
// 加载最新
|
||||
if (newModelView) {
|
||||
// @ts-expect-error: viewer instance type is broader than local ref typing
|
||||
view.value = newModelView;
|
||||
view.value = {
|
||||
...newModelView,
|
||||
bpmnXml: newModelView.bpmnXml || '',
|
||||
};
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
@@ -40,7 +42,7 @@ watch(
|
||||
watch(
|
||||
() => props.bpmnXml,
|
||||
(value) => {
|
||||
view.value.bpmnXml = value;
|
||||
view.value.bpmnXml = value || '';
|
||||
},
|
||||
);
|
||||
</script>
|
||||
@@ -52,7 +54,7 @@ watch(
|
||||
>
|
||||
<MyProcessViewer
|
||||
key="processViewer"
|
||||
:xml="view.bpmnXml"
|
||||
:xml="view.bpmnXml || ''"
|
||||
:view="view"
|
||||
class="h-full min-h-[500px] w-full"
|
||||
/>
|
||||
|
||||
@@ -26,57 +26,14 @@ const simpleModel = ref<any>({});
|
||||
const tasks = ref([]); // 用户任务
|
||||
const processInstance = ref(); // 流程实例
|
||||
|
||||
/** 监控模型视图 包括任务列表、进行中的活动节点编号等 */
|
||||
watch(
|
||||
() => props.modelView,
|
||||
async (newModelView) => {
|
||||
if (newModelView) {
|
||||
tasks.value = newModelView.tasks;
|
||||
processInstance.value = newModelView.processInstance;
|
||||
// 已经拒绝的活动节点编号集合,只包括 UserTask
|
||||
const rejectedTaskActivityIds: string[] =
|
||||
newModelView.rejectedTaskActivityIds;
|
||||
// 进行中的活动节点编号集合, 只包括 UserTask
|
||||
const unfinishedTaskActivityIds: string[] =
|
||||
newModelView.unfinishedTaskActivityIds;
|
||||
// 已经完成的活动节点编号集合, 包括 UserTask、Gateway 等
|
||||
const finishedActivityIds: string[] =
|
||||
newModelView.finishedTaskActivityIds;
|
||||
// 已经完成的连线节点编号集合,只包括 SequenceFlow
|
||||
const finishedSequenceFlowActivityIds: string[] =
|
||||
newModelView.finishedSequenceFlowActivityIds;
|
||||
setSimpleModelNodeTaskStatus(
|
||||
newModelView.simpleModel,
|
||||
newModelView.processInstance?.status,
|
||||
rejectedTaskActivityIds,
|
||||
unfinishedTaskActivityIds,
|
||||
finishedActivityIds,
|
||||
finishedSequenceFlowActivityIds,
|
||||
);
|
||||
simpleModel.value = newModelView.simpleModel || {};
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
/** 监控模型结构数据 */
|
||||
watch(
|
||||
() => props.simpleJson,
|
||||
async (value) => {
|
||||
if (value) {
|
||||
simpleModel.value = JSON.parse(value);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const setSimpleModelNodeTaskStatus = (
|
||||
function setSimpleModelNodeTaskStatus(
|
||||
simpleModel: SimpleFlowNode | undefined,
|
||||
processStatus: number,
|
||||
rejectedTaskActivityIds: string[],
|
||||
unfinishedTaskActivityIds: string[],
|
||||
finishedActivityIds: string[],
|
||||
finishedSequenceFlowActivityIds: string[],
|
||||
) => {
|
||||
) {
|
||||
if (!simpleModel) {
|
||||
return;
|
||||
}
|
||||
@@ -166,7 +123,50 @@ const setSimpleModelNodeTaskStatus = (
|
||||
finishedActivityIds,
|
||||
finishedSequenceFlowActivityIds,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/** 监控模型视图 包括任务列表、进行中的活动节点编号等 */
|
||||
watch(
|
||||
() => props.modelView,
|
||||
async (newModelView) => {
|
||||
if (newModelView) {
|
||||
tasks.value = newModelView.tasks;
|
||||
processInstance.value = newModelView.processInstance;
|
||||
// 已经拒绝的活动节点编号集合,只包括 UserTask
|
||||
const rejectedTaskActivityIds: string[] =
|
||||
newModelView.rejectedTaskActivityIds;
|
||||
// 进行中的活动节点编号集合, 只包括 UserTask
|
||||
const unfinishedTaskActivityIds: string[] =
|
||||
newModelView.unfinishedTaskActivityIds;
|
||||
// 已经完成的活动节点编号集合, 包括 UserTask、Gateway 等
|
||||
const finishedActivityIds: string[] =
|
||||
newModelView.finishedTaskActivityIds;
|
||||
// 已经完成的连线节点编号集合,只包括 SequenceFlow
|
||||
const finishedSequenceFlowActivityIds: string[] =
|
||||
newModelView.finishedSequenceFlowActivityIds;
|
||||
setSimpleModelNodeTaskStatus(
|
||||
newModelView.simpleModel,
|
||||
newModelView.processInstance?.status,
|
||||
rejectedTaskActivityIds,
|
||||
unfinishedTaskActivityIds,
|
||||
finishedActivityIds,
|
||||
finishedSequenceFlowActivityIds,
|
||||
);
|
||||
simpleModel.value = newModelView.simpleModel || {};
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
/** 监控模型结构数据 */
|
||||
watch(
|
||||
() => props.simpleJson,
|
||||
async (value) => {
|
||||
if (value) {
|
||||
simpleModel.value = JSON.parse(value);
|
||||
}
|
||||
},
|
||||
);
|
||||
</script>
|
||||
<template>
|
||||
<div v-loading="loading">
|
||||
|
||||
@@ -14,13 +14,7 @@ import {
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
import { formatDateTime, isEmpty } from '@vben/utils';
|
||||
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
Timeline,
|
||||
TimelineItem,
|
||||
Tooltip,
|
||||
} from 'antdv-next';
|
||||
import { Avatar, Button, Timeline, TimelineItem, Tooltip } from 'antdv-next';
|
||||
|
||||
import { UserSelectModal } from '#/views/system/user/components';
|
||||
|
||||
@@ -488,7 +482,6 @@ defineExpose({ setCustomApproveUsers, batchSetCustomApproveUsers });
|
||||
class="w-3/5"
|
||||
v-model:value="selectedUsers"
|
||||
:multiple="true"
|
||||
title="选择用户"
|
||||
@confirm="handleUserSelectConfirm"
|
||||
@closed="handleUserSelectClosed"
|
||||
@cancel="handleUserSelectCancel"
|
||||
|
||||
@@ -111,42 +111,38 @@ export namespace ThingModelApi {
|
||||
}
|
||||
|
||||
/** 生成「必填 + 数字」类校验器:拼到 size / length / 枚举值上 */
|
||||
function buildRequiredNumberValidator(label: string) {
|
||||
return (_rule: any, value: any, callback: any) => {
|
||||
function buildRequiredNumberValidator(label: string): any {
|
||||
return (_rule: any, value: any) => {
|
||||
if (isEmpty(value)) {
|
||||
callback(new Error(`${label}不能为空`));
|
||||
return;
|
||||
return Promise.reject(new Error(`${label}不能为空`));
|
||||
}
|
||||
if (Number.isNaN(Number(value))) {
|
||||
callback(new Error(`${label}必须是数字`));
|
||||
return;
|
||||
return Promise.reject(new Error(`${label}必须是数字`));
|
||||
}
|
||||
callback();
|
||||
return Promise.resolve();
|
||||
};
|
||||
}
|
||||
|
||||
/** 生成「标识符样式」名称校验器:开头需为中文 / 英文 / 数字,整体仅允许中文、英文、数字、下划线、短划线,长度 ≤ 20 */
|
||||
export function buildIdentifierLikeNameValidator(label: string) {
|
||||
return (_rule: any, value: string, callback: any) => {
|
||||
export function buildIdentifierLikeNameValidator(label: string): any {
|
||||
return (_rule: any, value: string) => {
|
||||
if (isEmpty(value)) {
|
||||
callback(new Error(`${label}不能为空`));
|
||||
return;
|
||||
return Promise.reject(new Error(`${label}不能为空`));
|
||||
}
|
||||
if (!/^[一-龥A-Za-z0-9]/.test(value)) {
|
||||
callback(new Error(`${label}必须以中文、英文字母或数字开头`));
|
||||
return;
|
||||
return Promise.reject(
|
||||
new Error(`${label}必须以中文、英文字母或数字开头`),
|
||||
);
|
||||
}
|
||||
if (!/^[一-龥A-Za-z0-9][\w一-龥-]*$/.test(value)) {
|
||||
callback(
|
||||
return Promise.reject(
|
||||
new Error(`${label}只能包含中文、英文字母、数字、下划线和短划线`),
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (value.length > 20) {
|
||||
callback(new Error(`${label}长度不能超过 20 个字符`));
|
||||
return;
|
||||
return Promise.reject(new Error(`${label}长度不能超过 20 个字符`));
|
||||
}
|
||||
callback();
|
||||
return Promise.resolve();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -170,7 +166,7 @@ export const ThingModelFormRules: Record<string, FormItemRule[]> = {
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
validator: (_rule: any, value: string, callback: any) => {
|
||||
validator: ((_rule: any, value: string) => {
|
||||
const reservedKeywords = [
|
||||
'set',
|
||||
'get',
|
||||
@@ -181,19 +177,17 @@ export const ThingModelFormRules: Record<string, FormItemRule[]> = {
|
||||
'value',
|
||||
];
|
||||
if (reservedKeywords.includes(value)) {
|
||||
callback(
|
||||
return Promise.reject(
|
||||
new Error(
|
||||
'set, get, post, property, event, time, value 是系统保留字段,不能用于标识符定义',
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (/^\d+$/.test(value)) {
|
||||
callback(new Error('标识符不能是纯数字'));
|
||||
return;
|
||||
return Promise.reject(new Error('标识符不能是纯数字'));
|
||||
}
|
||||
callback();
|
||||
},
|
||||
return Promise.resolve();
|
||||
}) as any,
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
|
||||
@@ -22,8 +22,8 @@ import '../theme/index.scss';
|
||||
|
||||
const props = defineProps({
|
||||
xml: {
|
||||
default: '',
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
view: {
|
||||
type: Object,
|
||||
@@ -192,12 +192,12 @@ const onSelectElement = (element: any) => {
|
||||
};
|
||||
|
||||
/** 初始化 BPMN 视图 */
|
||||
const importXML = async (xml: string) => {
|
||||
const importXML = async (xml?: string) => {
|
||||
// 清空流程图
|
||||
clearViewer();
|
||||
|
||||
// 初始化流程图
|
||||
if (xml !== null && xml !== '') {
|
||||
if (xml) {
|
||||
try {
|
||||
bpmnViewer.value = new BpmnViewer({
|
||||
additionalModules: [MoveCanvasModule],
|
||||
@@ -310,7 +310,7 @@ const setProcessStatus = (view: any) => {
|
||||
watch(
|
||||
() => props.xml,
|
||||
(newXml) => {
|
||||
importXML(newXml);
|
||||
importXML(newXml || '');
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
@@ -325,7 +325,7 @@ watch(
|
||||
|
||||
/** mounted:初始化 */
|
||||
onMounted(() => {
|
||||
importXML(props.xml);
|
||||
importXML(props.xml || '');
|
||||
setProcessStatus(props.view);
|
||||
});
|
||||
|
||||
|
||||
@@ -70,21 +70,19 @@ const rules: Record<string, FormItemRule[]> = {
|
||||
key: [
|
||||
{ required: true, message: '流程标识不能为空', trigger: 'blur' },
|
||||
{
|
||||
validator: (_rule: any, value: string, callback: any) => {
|
||||
validator: ((_rule: any, value: string) => {
|
||||
if (!value) {
|
||||
callback();
|
||||
return;
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (!/^[a-z_][-\w.$]*$/i.test(value)) {
|
||||
callback(
|
||||
return Promise.reject(
|
||||
new Error(
|
||||
'只能包含字母、数字、下划线、连字符和点号,且必须以字母或下划线开头',
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
callback();
|
||||
},
|
||||
return Promise.resolve();
|
||||
}) as any,
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
|
||||
@@ -75,7 +75,7 @@ const startUserSelectTasks = ref<UserTask[]>([]);
|
||||
const startUserSelectAssignees = ref<Record<string, number[]>>({});
|
||||
const tempStartUserSelectAssignees = ref<Record<string, number[]>>({});
|
||||
|
||||
const bpmnXML = ref<string | undefined>(undefined);
|
||||
const bpmnXML = ref('');
|
||||
const simpleJson = ref<string | undefined>(undefined);
|
||||
|
||||
// @ts-expect-error unused
|
||||
@@ -168,7 +168,7 @@ async function initProcessInfo(row: any, formVariables?: any) {
|
||||
const processDefinitionDetail: BpmProcessDefinitionApi.ProcessDefinition =
|
||||
await getProcessDefinition(row.id);
|
||||
if (processDefinitionDetail) {
|
||||
bpmnXML.value = processDefinitionDetail.bpmnXml;
|
||||
bpmnXML.value = processDefinitionDetail.bpmnXml || '';
|
||||
simpleJson.value = processDefinitionDetail.simpleModel;
|
||||
}
|
||||
// 情况二:业务表单
|
||||
|
||||
@@ -9,7 +9,7 @@ const props = withDefaults(
|
||||
defineProps<{
|
||||
bpmnXml?: string;
|
||||
loading?: boolean; // 是否加载中
|
||||
modelView?: object;
|
||||
modelView?: Record<string, any>;
|
||||
}>(),
|
||||
{
|
||||
loading: false,
|
||||
@@ -29,8 +29,10 @@ watch(
|
||||
async (newModelView) => {
|
||||
// 加载最新
|
||||
if (newModelView) {
|
||||
// @ts-expect-error: viewer instance type is broader than local ref typing
|
||||
view.value = newModelView;
|
||||
view.value = {
|
||||
...newModelView,
|
||||
bpmnXml: newModelView.bpmnXml || '',
|
||||
};
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
@@ -40,7 +42,7 @@ watch(
|
||||
watch(
|
||||
() => props.bpmnXml,
|
||||
(value) => {
|
||||
view.value.bpmnXml = value;
|
||||
view.value.bpmnXml = value || '';
|
||||
},
|
||||
);
|
||||
</script>
|
||||
@@ -52,7 +54,7 @@ watch(
|
||||
>
|
||||
<MyProcessViewer
|
||||
key="processViewer"
|
||||
:xml="view.bpmnXml"
|
||||
:xml="view.bpmnXml || ''"
|
||||
:view="view"
|
||||
class="h-full min-h-[500px] w-full"
|
||||
/>
|
||||
|
||||
@@ -26,57 +26,14 @@ const simpleModel = ref<any>({});
|
||||
const tasks = ref([]); // 用户任务
|
||||
const processInstance = ref(); // 流程实例
|
||||
|
||||
/** 监控模型视图 包括任务列表、进行中的活动节点编号等 */
|
||||
watch(
|
||||
() => props.modelView,
|
||||
async (newModelView) => {
|
||||
if (newModelView) {
|
||||
tasks.value = newModelView.tasks;
|
||||
processInstance.value = newModelView.processInstance;
|
||||
// 已经拒绝的活动节点编号集合,只包括 UserTask
|
||||
const rejectedTaskActivityIds: string[] =
|
||||
newModelView.rejectedTaskActivityIds;
|
||||
// 进行中的活动节点编号集合, 只包括 UserTask
|
||||
const unfinishedTaskActivityIds: string[] =
|
||||
newModelView.unfinishedTaskActivityIds;
|
||||
// 已经完成的活动节点编号集合, 包括 UserTask、Gateway 等
|
||||
const finishedActivityIds: string[] =
|
||||
newModelView.finishedTaskActivityIds;
|
||||
// 已经完成的连线节点编号集合,只包括 SequenceFlow
|
||||
const finishedSequenceFlowActivityIds: string[] =
|
||||
newModelView.finishedSequenceFlowActivityIds;
|
||||
setSimpleModelNodeTaskStatus(
|
||||
newModelView.simpleModel,
|
||||
newModelView.processInstance?.status,
|
||||
rejectedTaskActivityIds,
|
||||
unfinishedTaskActivityIds,
|
||||
finishedActivityIds,
|
||||
finishedSequenceFlowActivityIds,
|
||||
);
|
||||
simpleModel.value = newModelView.simpleModel || {};
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
/** 监控模型结构数据 */
|
||||
watch(
|
||||
() => props.simpleJson,
|
||||
async (value) => {
|
||||
if (value) {
|
||||
simpleModel.value = JSON.parse(value);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const setSimpleModelNodeTaskStatus = (
|
||||
function setSimpleModelNodeTaskStatus(
|
||||
simpleModel: SimpleFlowNode | undefined,
|
||||
processStatus: number,
|
||||
rejectedTaskActivityIds: string[],
|
||||
unfinishedTaskActivityIds: string[],
|
||||
finishedActivityIds: string[],
|
||||
finishedSequenceFlowActivityIds: string[],
|
||||
) => {
|
||||
) {
|
||||
if (!simpleModel) {
|
||||
return;
|
||||
}
|
||||
@@ -166,7 +123,50 @@ const setSimpleModelNodeTaskStatus = (
|
||||
finishedActivityIds,
|
||||
finishedSequenceFlowActivityIds,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/** 监控模型视图 包括任务列表、进行中的活动节点编号等 */
|
||||
watch(
|
||||
() => props.modelView,
|
||||
async (newModelView) => {
|
||||
if (newModelView) {
|
||||
tasks.value = newModelView.tasks;
|
||||
processInstance.value = newModelView.processInstance;
|
||||
// 已经拒绝的活动节点编号集合,只包括 UserTask
|
||||
const rejectedTaskActivityIds: string[] =
|
||||
newModelView.rejectedTaskActivityIds;
|
||||
// 进行中的活动节点编号集合, 只包括 UserTask
|
||||
const unfinishedTaskActivityIds: string[] =
|
||||
newModelView.unfinishedTaskActivityIds;
|
||||
// 已经完成的活动节点编号集合, 包括 UserTask、Gateway 等
|
||||
const finishedActivityIds: string[] =
|
||||
newModelView.finishedTaskActivityIds;
|
||||
// 已经完成的连线节点编号集合,只包括 SequenceFlow
|
||||
const finishedSequenceFlowActivityIds: string[] =
|
||||
newModelView.finishedSequenceFlowActivityIds;
|
||||
setSimpleModelNodeTaskStatus(
|
||||
newModelView.simpleModel,
|
||||
newModelView.processInstance?.status,
|
||||
rejectedTaskActivityIds,
|
||||
unfinishedTaskActivityIds,
|
||||
finishedActivityIds,
|
||||
finishedSequenceFlowActivityIds,
|
||||
);
|
||||
simpleModel.value = newModelView.simpleModel || {};
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
/** 监控模型结构数据 */
|
||||
watch(
|
||||
() => props.simpleJson,
|
||||
async (value) => {
|
||||
if (value) {
|
||||
simpleModel.value = JSON.parse(value);
|
||||
}
|
||||
},
|
||||
);
|
||||
</script>
|
||||
<template>
|
||||
<div v-loading="loading">
|
||||
|
||||
@@ -486,7 +486,6 @@ defineExpose({ setCustomApproveUsers, batchSetCustomApproveUsers });
|
||||
class="w-3/5"
|
||||
v-model="selectedUsers"
|
||||
:multiple="true"
|
||||
title="选择用户"
|
||||
@confirm="handleUserSelectConfirm"
|
||||
@closed="handleUserSelectClosed"
|
||||
@cancel="handleUserSelectCancel"
|
||||
|
||||
@@ -122,23 +122,21 @@ function normalizeFormData(result: any): RuleSceneApi.SceneRule {
|
||||
}
|
||||
|
||||
/** 触发器校验 */
|
||||
function validateTriggers(_rule: any, value: any, callback: any) {
|
||||
function validateTriggers(_rule: any, value: any) {
|
||||
const error = validateSceneRuleTriggers(value);
|
||||
if (error) {
|
||||
callback(new Error(error));
|
||||
return;
|
||||
return Promise.reject(new Error(error));
|
||||
}
|
||||
callback();
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/** 执行器校验 */
|
||||
function validateActions(_rule: any, value: any, callback: any) {
|
||||
function validateActions(_rule: any, value: any) {
|
||||
const error = validateSceneRuleActions(value);
|
||||
if (error) {
|
||||
callback(new Error(error));
|
||||
return;
|
||||
return Promise.reject(new Error(error));
|
||||
}
|
||||
callback();
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const formRules = reactive({
|
||||
|
||||
@@ -35,52 +35,45 @@ function deleteEnum(index: number) {
|
||||
}
|
||||
|
||||
/** 校验单项枚举值:必填、数字、不重复 */
|
||||
function validateEnumValue(_rule: any, value: any, callback: any) {
|
||||
const validateEnumValue: any = (_rule: any, value: any) => {
|
||||
if (isEmpty(value)) {
|
||||
callback(new Error('枚举值不能为空'));
|
||||
return;
|
||||
return Promise.reject(new Error('枚举值不能为空'));
|
||||
}
|
||||
if (Number.isNaN(Number(value))) {
|
||||
callback(new Error('枚举值必须是数字'));
|
||||
return;
|
||||
return Promise.reject(new Error('枚举值必须是数字'));
|
||||
}
|
||||
const sameCount = dataSpecsList.value.filter(
|
||||
(it) => it.value === value,
|
||||
).length;
|
||||
if (sameCount > 1) {
|
||||
callback(new Error('枚举值不能重复'));
|
||||
return;
|
||||
return Promise.reject(new Error('枚举值不能重复'));
|
||||
}
|
||||
callback();
|
||||
}
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
/** 校验整个枚举列表:非空、无空项、无非法数字、无重复 */
|
||||
function validateEnumList(_rule: any, _value: any, callback: any) {
|
||||
const validateEnumList: any = (_rule: any, _value: any) => {
|
||||
if (isEmpty(dataSpecsList.value)) {
|
||||
callback(new Error('请至少添加一个枚举项'));
|
||||
return;
|
||||
return Promise.reject(new Error('请至少添加一个枚举项'));
|
||||
}
|
||||
const hasEmpty = dataSpecsList.value.some(
|
||||
(item) => isEmpty(item.value) || isEmpty(item.name),
|
||||
);
|
||||
if (hasEmpty) {
|
||||
callback(new Error('存在未填写的枚举值或描述'));
|
||||
return;
|
||||
return Promise.reject(new Error('存在未填写的枚举值或描述'));
|
||||
}
|
||||
const hasInvalidNumber = dataSpecsList.value.some((item) =>
|
||||
Number.isNaN(Number(item.value)),
|
||||
);
|
||||
if (hasInvalidNumber) {
|
||||
callback(new Error('存在非数字的枚举值'));
|
||||
return;
|
||||
return Promise.reject(new Error('存在非数字的枚举值'));
|
||||
}
|
||||
const values = dataSpecsList.value.map((item) => item.value);
|
||||
if (new Set(values).size !== values.length) {
|
||||
callback(new Error('存在重复的枚举值'));
|
||||
return;
|
||||
return Promise.reject(new Error('存在重复的枚举值'));
|
||||
}
|
||||
callback();
|
||||
}
|
||||
return Promise.resolve();
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -29,54 +29,47 @@ function unitChange(unitSpecs: any) {
|
||||
}
|
||||
|
||||
/** 校验最小值 */
|
||||
function validateMin(_rule: any, _value: any, callback: any) {
|
||||
const validateMin: any = (_rule: any, _value: any) => {
|
||||
const min = Number(dataSpecs.value.min);
|
||||
const max = Number(dataSpecs.value.max);
|
||||
if (Number.isNaN(min)) {
|
||||
callback(new Error('请输入有效的数值'));
|
||||
return;
|
||||
return Promise.reject(new Error('请输入有效的数值'));
|
||||
}
|
||||
if (!Number.isNaN(max) && min >= max) {
|
||||
callback(new Error('最小值必须小于最大值'));
|
||||
return;
|
||||
return Promise.reject(new Error('最小值必须小于最大值'));
|
||||
}
|
||||
callback();
|
||||
}
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
/** 校验最大值 */
|
||||
function validateMax(_rule: any, _value: any, callback: any) {
|
||||
const validateMax: any = (_rule: any, _value: any) => {
|
||||
const min = Number(dataSpecs.value.min);
|
||||
const max = Number(dataSpecs.value.max);
|
||||
if (Number.isNaN(max)) {
|
||||
callback(new Error('请输入有效的数值'));
|
||||
return;
|
||||
return Promise.reject(new Error('请输入有效的数值'));
|
||||
}
|
||||
if (!Number.isNaN(min) && max <= min) {
|
||||
callback(new Error('最大值必须大于最小值'));
|
||||
return;
|
||||
return Promise.reject(new Error('最大值必须大于最小值'));
|
||||
}
|
||||
callback();
|
||||
}
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
/** 校验步长 */
|
||||
function validateStep(_rule: any, _value: any, callback: any) {
|
||||
const validateStep: any = (_rule: any, _value: any) => {
|
||||
const step = Number(dataSpecs.value.step);
|
||||
if (Number.isNaN(step)) {
|
||||
callback(new Error('请输入有效的数值'));
|
||||
return;
|
||||
return Promise.reject(new Error('请输入有效的数值'));
|
||||
}
|
||||
if (step <= 0) {
|
||||
callback(new Error('步长必须大于 0'));
|
||||
return;
|
||||
return Promise.reject(new Error('步长必须大于 0'));
|
||||
}
|
||||
const min = Number(dataSpecs.value.min);
|
||||
const max = Number(dataSpecs.value.max);
|
||||
if (!Number.isNaN(min) && !Number.isNaN(max) && step > max - min) {
|
||||
callback(new Error('步长不能大于最大值与最小值的差值'));
|
||||
return;
|
||||
return Promise.reject(new Error('步长不能大于最大值与最小值的差值'));
|
||||
}
|
||||
callback();
|
||||
}
|
||||
return Promise.resolve();
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -33,13 +33,12 @@ const structFormRef = ref();
|
||||
const formData = ref<any>(buildEmptyFormData());
|
||||
|
||||
/** 校验结构体属性对象非空 */
|
||||
function validateStructSpecsList(_rule: any, _value: any, callback: any) {
|
||||
const validateStructSpecsList: any = (_rule: any, _value: any) => {
|
||||
if (isEmpty(dataSpecsList.value)) {
|
||||
callback(new Error('请至少添加一个结构体属性对象'));
|
||||
return;
|
||||
return Promise.reject(new Error('请至少添加一个结构体属性对象'));
|
||||
}
|
||||
callback();
|
||||
}
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
async onConfirm() {
|
||||
|
||||
Reference in New Issue
Block a user