feat: bpmnProcessDesigner 迁移(纯复制)
This commit is contained in:
@@ -46,10 +46,17 @@
|
|||||||
"@vueuse/core": "catalog:",
|
"@vueuse/core": "catalog:",
|
||||||
"@vueuse/integrations": "catalog:",
|
"@vueuse/integrations": "catalog:",
|
||||||
"ant-design-vue": "catalog:",
|
"ant-design-vue": "catalog:",
|
||||||
|
"bpmn-js": "^17.11.1",
|
||||||
|
"bpmn-js-properties-panel": "5.23.0",
|
||||||
|
"bpmn-js-token-simulation": "^0.36.3",
|
||||||
|
"camunda-bpmn-moddle": "^7.0.1",
|
||||||
"cropperjs": "catalog:",
|
"cropperjs": "catalog:",
|
||||||
"dayjs": "catalog:",
|
"dayjs": "catalog:",
|
||||||
|
"diagram-js": "^12.8.1",
|
||||||
|
"fast-xml-parser": "^4.5.3",
|
||||||
"highlight.js": "catalog:",
|
"highlight.js": "catalog:",
|
||||||
"pinia": "catalog:",
|
"pinia": "catalog:",
|
||||||
|
"steady-xml": "^0.1.0",
|
||||||
"tinymce": "catalog:",
|
"tinymce": "catalog:",
|
||||||
"vue": "catalog:",
|
"vue": "catalog:",
|
||||||
"vue-dompurify-html": "catalog:",
|
"vue-dompurify-html": "catalog:",
|
||||||
|
|||||||
@@ -0,0 +1,700 @@
|
|||||||
|
<template>
|
||||||
|
<div class="my-process-designer">
|
||||||
|
<div
|
||||||
|
class="my-process-designer__header"
|
||||||
|
style="z-index: 999; display: table-row-group"
|
||||||
|
>
|
||||||
|
<slot name="control-header"></slot>
|
||||||
|
<template v-if="!$slots['control-header']">
|
||||||
|
<ElButtonGroup key="file-control">
|
||||||
|
<XButton
|
||||||
|
preIcon="ep:folder-opened"
|
||||||
|
title="打开文件"
|
||||||
|
@click="refFile.click()"
|
||||||
|
/>
|
||||||
|
<el-tooltip effect="light" placement="bottom">
|
||||||
|
<template #content>
|
||||||
|
<div style="color: #409eff">
|
||||||
|
<!-- <el-button link @click="downloadProcessAsXml()">下载为XML文件</el-button> -->
|
||||||
|
<XTextButton
|
||||||
|
title="下载为XML文件"
|
||||||
|
@click="downloadProcessAsXml()"
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<!-- <el-button link @click="downloadProcessAsSvg()">下载为SVG文件</el-button> -->
|
||||||
|
<XTextButton
|
||||||
|
title="下载为SVG文件"
|
||||||
|
@click="downloadProcessAsSvg()"
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<!-- <el-button link @click="downloadProcessAsBpmn()">下载为BPMN文件</el-button> -->
|
||||||
|
<XTextButton
|
||||||
|
title="下载为BPMN文件"
|
||||||
|
@click="downloadProcessAsBpmn()"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<XButton title="下载文件" preIcon="ep:download" />
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip effect="light">
|
||||||
|
<XButton preIcon="ep:view" title="浏览" />
|
||||||
|
<template #content>
|
||||||
|
<!-- <el-button link @click="previewProcessXML">预览XML</el-button> -->
|
||||||
|
<XTextButton title="预览XML" @click="previewProcessXML" />
|
||||||
|
<br />
|
||||||
|
<!-- <el-button link @click="previewProcessJson">预览JSON</el-button> -->
|
||||||
|
<XTextButton title="预览JSON" @click="previewProcessJson" />
|
||||||
|
</template>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip
|
||||||
|
v-if="props.simulation"
|
||||||
|
effect="light"
|
||||||
|
:content="simulationStatus ? '退出模拟' : '开启模拟'"
|
||||||
|
>
|
||||||
|
<XButton preIcon="ep:cpu" title="模拟" @click="processSimulation" />
|
||||||
|
</el-tooltip>
|
||||||
|
</ElButtonGroup>
|
||||||
|
<ElButtonGroup key="align-control">
|
||||||
|
<el-tooltip effect="light" content="向左对齐">
|
||||||
|
<!-- <el-button
|
||||||
|
class="align align-left"
|
||||||
|
icon="el-icon-s-data"
|
||||||
|
@click="elementsAlign('left')"
|
||||||
|
/> -->
|
||||||
|
<XButton
|
||||||
|
preIcon="fa:align-left"
|
||||||
|
class="align align-bottom"
|
||||||
|
@click="elementsAlign('left')"
|
||||||
|
/>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip effect="light" content="向右对齐">
|
||||||
|
<!-- <el-button
|
||||||
|
class="align align-right"
|
||||||
|
icon="el-icon-s-data"
|
||||||
|
@click="elementsAlign('right')"
|
||||||
|
/> -->
|
||||||
|
<XButton
|
||||||
|
preIcon="fa:align-left"
|
||||||
|
class="align align-top"
|
||||||
|
@click="elementsAlign('right')"
|
||||||
|
/>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip effect="light" content="向上对齐">
|
||||||
|
<!-- <el-button
|
||||||
|
class="align align-top"
|
||||||
|
icon="el-icon-s-data"
|
||||||
|
@click="elementsAlign('top')"
|
||||||
|
/> -->
|
||||||
|
<XButton
|
||||||
|
preIcon="fa:align-left"
|
||||||
|
class="align align-left"
|
||||||
|
@click="elementsAlign('top')"
|
||||||
|
/>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip effect="light" content="向下对齐">
|
||||||
|
<!-- <el-button
|
||||||
|
class="align align-bottom"
|
||||||
|
icon="el-icon-s-data"
|
||||||
|
@click="elementsAlign('bottom')"
|
||||||
|
/> -->
|
||||||
|
<XButton
|
||||||
|
preIcon="fa:align-left"
|
||||||
|
class="align align-right"
|
||||||
|
@click="elementsAlign('bottom')"
|
||||||
|
/>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip effect="light" content="水平居中">
|
||||||
|
<!-- <el-button
|
||||||
|
class="align align-center"
|
||||||
|
icon="el-icon-s-data"
|
||||||
|
@click="elementsAlign('center')"
|
||||||
|
/> -->
|
||||||
|
<!-- class="align align-center" -->
|
||||||
|
<XButton
|
||||||
|
preIcon="fa:align-left"
|
||||||
|
class="align align-center"
|
||||||
|
@click="elementsAlign('center')"
|
||||||
|
/>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip effect="light" content="垂直居中">
|
||||||
|
<!-- <el-button
|
||||||
|
class="align align-middle"
|
||||||
|
icon="el-icon-s-data"
|
||||||
|
@click="elementsAlign('middle')"
|
||||||
|
/> -->
|
||||||
|
<XButton
|
||||||
|
preIcon="fa:align-left"
|
||||||
|
class="align align-middle"
|
||||||
|
@click="elementsAlign('middle')"
|
||||||
|
/>
|
||||||
|
</el-tooltip>
|
||||||
|
</ElButtonGroup>
|
||||||
|
<ElButtonGroup key="scale-control">
|
||||||
|
<el-tooltip effect="light" content="缩小视图">
|
||||||
|
<!-- <el-button
|
||||||
|
:disabled="defaultZoom < 0.2"
|
||||||
|
icon="el-icon-zoom-out"
|
||||||
|
@click="processZoomOut()"
|
||||||
|
/> -->
|
||||||
|
<XButton
|
||||||
|
preIcon="ep:zoom-out"
|
||||||
|
@click="processZoomOut()"
|
||||||
|
:disabled="defaultZoom < 0.2"
|
||||||
|
/>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-button>{{ Math.floor(defaultZoom * 10 * 10) + '%' }}</el-button>
|
||||||
|
<el-tooltip effect="light" content="放大视图">
|
||||||
|
<!-- <el-button
|
||||||
|
:disabled="defaultZoom > 4"
|
||||||
|
icon="el-icon-zoom-in"
|
||||||
|
@click="processZoomIn()"
|
||||||
|
/> -->
|
||||||
|
<XButton
|
||||||
|
preIcon="ep:zoom-in"
|
||||||
|
@click="processZoomIn()"
|
||||||
|
:disabled="defaultZoom > 4"
|
||||||
|
/>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip effect="light" content="重置视图并居中">
|
||||||
|
<!-- <el-button icon="el-icon-c-scale-to-original" @click="processReZoom()" /> -->
|
||||||
|
<XButton preIcon="ep:scale-to-original" @click="processReZoom()" />
|
||||||
|
</el-tooltip>
|
||||||
|
</ElButtonGroup>
|
||||||
|
<ElButtonGroup key="stack-control">
|
||||||
|
<el-tooltip effect="light" content="撤销">
|
||||||
|
<!-- <el-button :disabled="!revocable" icon="el-icon-refresh-left" @click="processUndo()" /> -->
|
||||||
|
<XButton
|
||||||
|
preIcon="ep:refresh-left"
|
||||||
|
@click="processUndo()"
|
||||||
|
:disabled="!revocable"
|
||||||
|
/>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip effect="light" content="恢复">
|
||||||
|
<!-- <el-button
|
||||||
|
:disabled="!recoverable"
|
||||||
|
icon="el-icon-refresh-right"
|
||||||
|
@click="processRedo()"
|
||||||
|
/> -->
|
||||||
|
<XButton
|
||||||
|
preIcon="ep:refresh-right"
|
||||||
|
@click="processRedo()"
|
||||||
|
:disabled="!recoverable"
|
||||||
|
/>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip effect="light" content="重新绘制">
|
||||||
|
<!-- <el-button icon="el-icon-refresh" @click="processRestart" /> -->
|
||||||
|
<XButton preIcon="ep:refresh" @click="processRestart()" />
|
||||||
|
</el-tooltip>
|
||||||
|
</ElButtonGroup>
|
||||||
|
</template>
|
||||||
|
<!-- 用于打开本地文件-->
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
id="files"
|
||||||
|
ref="refFile"
|
||||||
|
style="display: none"
|
||||||
|
accept=".xml, .bpmn"
|
||||||
|
@change="importLocalFile"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="my-process-designer__container">
|
||||||
|
<div
|
||||||
|
class="my-process-designer__canvas"
|
||||||
|
ref="bpmnCanvas"
|
||||||
|
id="bpmnCanvas"
|
||||||
|
style="width: 1680px; height: 800px"
|
||||||
|
></div>
|
||||||
|
<!-- <div id="js-properties-panel" class="panel"></div> -->
|
||||||
|
<!-- <div class="my-process-designer__canvas" ref="bpmn-canvas"></div> -->
|
||||||
|
</div>
|
||||||
|
<Dialog
|
||||||
|
title="预览"
|
||||||
|
v-model="previewModelVisible"
|
||||||
|
width="80%"
|
||||||
|
:scroll="true"
|
||||||
|
max-height="600px"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<pre><code v-dompurify-html="highlightedCode(previewResult)" class="hljs"></code></pre>
|
||||||
|
</div>
|
||||||
|
</Dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
// import 'bpmn-js/dist/assets/diagram-js.css' // 左边工具栏以及编辑节点的样式
|
||||||
|
// import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css'
|
||||||
|
// import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css'
|
||||||
|
// import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css'
|
||||||
|
// import 'bpmn-js-properties-panel/dist/assets/bpmn-js-properties-panel.css' // 右侧框样式
|
||||||
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||||
|
import BpmnModeler from 'bpmn-js/lib/Modeler';
|
||||||
|
import DefaultEmptyXML from './plugins/defaultEmpty';
|
||||||
|
// 翻译方法
|
||||||
|
import customTranslate from './plugins/translate/customTranslate';
|
||||||
|
import translationsCN from './plugins/translate/zh';
|
||||||
|
// 模拟流转流程
|
||||||
|
import tokenSimulation from 'bpmn-js-token-simulation';
|
||||||
|
// 标签解析构建器
|
||||||
|
// import bpmnPropertiesProvider from "bpmn-js-properties-panel/lib/provider/bpmn";
|
||||||
|
// import propertiesPanelModule from 'bpmn-js-properties-panel'
|
||||||
|
// import propertiesProviderModule from 'bpmn-js-properties-panel/lib/provider/camunda'
|
||||||
|
// 标签解析 Moddle
|
||||||
|
import camundaModdleDescriptor from './plugins/descriptor/camundaDescriptor.json';
|
||||||
|
import activitiModdleDescriptor from './plugins/descriptor/activitiDescriptor.json';
|
||||||
|
import flowableModdleDescriptor from './plugins/descriptor/flowableDescriptor.json';
|
||||||
|
// 标签解析 Extension
|
||||||
|
import camundaModdleExtension from './plugins/extension-moddle/camunda';
|
||||||
|
import activitiModdleExtension from './plugins/extension-moddle/activiti';
|
||||||
|
import flowableModdleExtension from './plugins/extension-moddle/flowable';
|
||||||
|
// 引入json转换与高亮
|
||||||
|
// import xml2js from 'xml-js'
|
||||||
|
// import xml2js from 'fast-xml-parser'
|
||||||
|
import { XmlNode, XmlNodeType, parseXmlString } from 'steady-xml';
|
||||||
|
// 代码高亮插件
|
||||||
|
// import hljs from 'highlight.js/lib/highlight'
|
||||||
|
// import 'highlight.js/styles/github-gist.css'
|
||||||
|
// hljs.registerLanguage('xml', 'highlight.js/lib/languages/xml')
|
||||||
|
// hljs.registerLanguage('json', 'highlight.js/lib/languages/json')
|
||||||
|
// const eventName = reactive({
|
||||||
|
// name: ''
|
||||||
|
// })
|
||||||
|
import hljs from 'highlight.js'; // 导入代码高亮文件
|
||||||
|
import 'highlight.js/styles/github.css'; // 导入代码高亮样式
|
||||||
|
|
||||||
|
defineOptions({ name: 'MyProcessDesigner' });
|
||||||
|
|
||||||
|
const bpmnCanvas = ref();
|
||||||
|
const refFile = ref();
|
||||||
|
const emit = defineEmits([
|
||||||
|
'destroy',
|
||||||
|
'init-finished',
|
||||||
|
'save',
|
||||||
|
'commandStack-changed',
|
||||||
|
'input',
|
||||||
|
'change',
|
||||||
|
'canvas-viewbox-changed',
|
||||||
|
// eventName.name
|
||||||
|
'element-click',
|
||||||
|
]);
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
value: String, // xml 字符串
|
||||||
|
// valueWatch: true, // xml 字符串的 watch 状态
|
||||||
|
processId: String, // 流程 key 标识
|
||||||
|
processName: String, // 流程 name 名字
|
||||||
|
formId: Number, // 流程 form 表单编号
|
||||||
|
translations: {
|
||||||
|
// 自定义的翻译文件
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
additionalModel: [Object, Array], // 自定义model
|
||||||
|
moddleExtension: {
|
||||||
|
// 自定义moddle
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
onlyCustomizeAddi: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
onlyCustomizeModdle: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
simulation: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
keyboard: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
prefix: {
|
||||||
|
type: String,
|
||||||
|
default: 'camunda',
|
||||||
|
},
|
||||||
|
events: {
|
||||||
|
type: Array,
|
||||||
|
default: () => ['element.click'],
|
||||||
|
},
|
||||||
|
headerButtonSize: {
|
||||||
|
type: String,
|
||||||
|
default: 'small',
|
||||||
|
validator: (value: string) =>
|
||||||
|
['default', 'medium', 'small', 'mini'].indexOf(value) !== -1,
|
||||||
|
},
|
||||||
|
headerButtonType: {
|
||||||
|
type: String,
|
||||||
|
default: 'primary',
|
||||||
|
validator: (value: string) =>
|
||||||
|
['default', 'primary', 'success', 'warning', 'danger', 'info'].indexOf(
|
||||||
|
value,
|
||||||
|
) !== -1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 代码高亮
|
||||||
|
*/
|
||||||
|
const highlightedCode = (code: string) => {
|
||||||
|
// 高亮
|
||||||
|
if (previewType.value === 'json') {
|
||||||
|
code = JSON.stringify(code, null, 2);
|
||||||
|
}
|
||||||
|
const result = hljs.highlight(code, {
|
||||||
|
language: previewType.value,
|
||||||
|
ignoreIllegals: true,
|
||||||
|
});
|
||||||
|
return result.value || ' ';
|
||||||
|
};
|
||||||
|
|
||||||
|
provide('configGlobal', props);
|
||||||
|
let bpmnModeler: any = null;
|
||||||
|
const defaultZoom = ref(1);
|
||||||
|
const previewModelVisible = ref(false);
|
||||||
|
const simulationStatus = ref(false);
|
||||||
|
const previewResult = ref('');
|
||||||
|
const previewType = ref('xml');
|
||||||
|
const recoverable = ref(false);
|
||||||
|
const revocable = ref(false);
|
||||||
|
const additionalModules = computed(() => {
|
||||||
|
console.log(props.additionalModel, 'additionalModel');
|
||||||
|
const Modules: any[] = [];
|
||||||
|
// 仅保留用户自定义扩展模块
|
||||||
|
if (props.onlyCustomizeAddi) {
|
||||||
|
if (
|
||||||
|
Object.prototype.toString.call(props.additionalModel) == '[object Array]'
|
||||||
|
) {
|
||||||
|
return props.additionalModel || [];
|
||||||
|
}
|
||||||
|
return [props.additionalModel];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 插入用户自定义扩展模块
|
||||||
|
if (
|
||||||
|
Object.prototype.toString.call(props.additionalModel) == '[object Array]'
|
||||||
|
) {
|
||||||
|
Modules.push(...(props.additionalModel as any[]));
|
||||||
|
} else {
|
||||||
|
props.additionalModel && Modules.push(props.additionalModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 翻译模块
|
||||||
|
const TranslateModule = {
|
||||||
|
translate: ['value', customTranslate(props.translations || translationsCN)],
|
||||||
|
};
|
||||||
|
Modules.push(TranslateModule);
|
||||||
|
|
||||||
|
// 模拟流转模块
|
||||||
|
if (props.simulation) {
|
||||||
|
Modules.push(tokenSimulation);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据需要的流程类型设置扩展元素构建模块
|
||||||
|
// if (this.prefix === "bpmn") {
|
||||||
|
// Modules.push(bpmnModdleExtension);
|
||||||
|
// }
|
||||||
|
console.log(props.prefix, 'props.prefix ');
|
||||||
|
if (props.prefix === 'camunda') {
|
||||||
|
Modules.push(camundaModdleExtension);
|
||||||
|
}
|
||||||
|
if (props.prefix === 'flowable') {
|
||||||
|
Modules.push(flowableModdleExtension);
|
||||||
|
}
|
||||||
|
if (props.prefix === 'activiti') {
|
||||||
|
Modules.push(activitiModdleExtension);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Modules;
|
||||||
|
});
|
||||||
|
const moddleExtensions = computed(() => {
|
||||||
|
console.log(props.onlyCustomizeModdle, 'props.onlyCustomizeModdle');
|
||||||
|
console.log(props.moddleExtension, 'props.moddleExtension');
|
||||||
|
console.log(props.prefix, 'props.prefix');
|
||||||
|
const Extensions: any = {};
|
||||||
|
// 仅使用用户自定义模块
|
||||||
|
if (props.onlyCustomizeModdle) {
|
||||||
|
return props.moddleExtension || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 插入用户自定义模块
|
||||||
|
if (props.moddleExtension) {
|
||||||
|
for (let key in props.moddleExtension) {
|
||||||
|
Extensions[key] = props.moddleExtension[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据需要的 "流程类型" 设置 对应的解析文件
|
||||||
|
if (props.prefix === 'activiti') {
|
||||||
|
Extensions.activiti = activitiModdleDescriptor;
|
||||||
|
}
|
||||||
|
if (props.prefix === 'flowable') {
|
||||||
|
Extensions.flowable = flowableModdleDescriptor;
|
||||||
|
}
|
||||||
|
if (props.prefix === 'camunda') {
|
||||||
|
Extensions.camunda = camundaModdleDescriptor;
|
||||||
|
}
|
||||||
|
return Extensions;
|
||||||
|
});
|
||||||
|
console.log(additionalModules, 'additionalModules()');
|
||||||
|
console.log(moddleExtensions, 'moddleExtensions()');
|
||||||
|
const initBpmnModeler = () => {
|
||||||
|
if (bpmnModeler) return;
|
||||||
|
let data = document.getElementById('bpmnCanvas');
|
||||||
|
console.log(data, 'data');
|
||||||
|
console.log(props.keyboard, 'props.keyboard');
|
||||||
|
console.log(additionalModules, 'additionalModules()');
|
||||||
|
console.log(moddleExtensions, 'moddleExtensions()');
|
||||||
|
|
||||||
|
bpmnModeler = new BpmnModeler({
|
||||||
|
// container: this.$refs['bpmn-canvas'],
|
||||||
|
// container: getCurrentInstance(),
|
||||||
|
// container: needClass,
|
||||||
|
// container: bpmnCanvas.value,
|
||||||
|
container: data,
|
||||||
|
// width: '100%',
|
||||||
|
// 添加控制板
|
||||||
|
// propertiesPanel: {
|
||||||
|
// parent: '#js-properties-panel'
|
||||||
|
// },
|
||||||
|
keyboard: props.keyboard ? { bindTo: document } : null,
|
||||||
|
// additionalModules: additionalModules.value,
|
||||||
|
additionalModules: additionalModules.value,
|
||||||
|
moddleExtensions: moddleExtensions.value,
|
||||||
|
|
||||||
|
// additionalModules: [
|
||||||
|
// additionalModules.value
|
||||||
|
// propertiesPanelModule,
|
||||||
|
// propertiesProviderModule
|
||||||
|
// propertiesProviderModule
|
||||||
|
// ],
|
||||||
|
// moddleExtensions: { camunda: moddleExtensions.value }
|
||||||
|
});
|
||||||
|
|
||||||
|
// bpmnModeler.createDiagram()
|
||||||
|
|
||||||
|
// console.log(bpmnModeler, 'bpmnModeler111111')
|
||||||
|
emit('init-finished', bpmnModeler);
|
||||||
|
initModelListeners();
|
||||||
|
};
|
||||||
|
|
||||||
|
const initModelListeners = () => {
|
||||||
|
const EventBus = bpmnModeler.get('eventBus');
|
||||||
|
console.log(EventBus, 'EventBus');
|
||||||
|
// 注册需要的监听事件, 将. 替换为 - , 避免解析异常
|
||||||
|
props.events.forEach((event: any) => {
|
||||||
|
EventBus.on(event, function (eventObj) {
|
||||||
|
let eventName = event.replace(/\./g, '-');
|
||||||
|
// eventName.name = eventName
|
||||||
|
let element = eventObj ? eventObj.element : null;
|
||||||
|
console.log(eventName, 'eventName');
|
||||||
|
console.log(element, 'element');
|
||||||
|
emit('element-click', element, eventObj);
|
||||||
|
// emit(eventName, element, eventObj)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// 监听图形改变返回xml
|
||||||
|
EventBus.on('commandStack.changed', async (event) => {
|
||||||
|
try {
|
||||||
|
recoverable.value = bpmnModeler.get('commandStack').canRedo();
|
||||||
|
revocable.value = bpmnModeler.get('commandStack').canUndo();
|
||||||
|
let { xml } = await bpmnModeler.saveXML({ format: true });
|
||||||
|
emit('commandStack-changed', event);
|
||||||
|
emit('input', xml);
|
||||||
|
emit('change', xml);
|
||||||
|
emit('save', xml);
|
||||||
|
} catch (e: any) {
|
||||||
|
console.error(`[Process Designer Warn]: ${e.message || e}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 监听视图缩放变化
|
||||||
|
bpmnModeler.on('canvas.viewbox.changed', ({ viewbox }) => {
|
||||||
|
emit('canvas-viewbox-changed', { viewbox });
|
||||||
|
const { scale } = viewbox;
|
||||||
|
defaultZoom.value = Math.floor(scale * 100) / 100;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/* 创建新的流程图 */
|
||||||
|
const createNewDiagram = async (xml) => {
|
||||||
|
console.log(xml, 'xml');
|
||||||
|
// 将字符串转换成图显示出来
|
||||||
|
let newId = props.processId || `Process_${new Date().getTime()}`;
|
||||||
|
let newName = props.processName || `业务流程_${new Date().getTime()}`;
|
||||||
|
let xmlString = xml || DefaultEmptyXML(newId, newName, props.prefix);
|
||||||
|
try {
|
||||||
|
// console.log(xmlString, 'xmlString')
|
||||||
|
// console.log(this.bpmnModeler.importXML);
|
||||||
|
let { warnings } = await bpmnModeler.importXML(xmlString);
|
||||||
|
console.log(warnings, 'warnings');
|
||||||
|
if (warnings && warnings.length) {
|
||||||
|
warnings.forEach((warn) => console.warn(warn));
|
||||||
|
}
|
||||||
|
} catch (e: any) {
|
||||||
|
console.error(`[Process Designer Warn]: ${e.message || e}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 下载流程图到本地
|
||||||
|
const downloadProcess = async (type) => {
|
||||||
|
try {
|
||||||
|
// 按需要类型创建文件并下载
|
||||||
|
if (type === 'xml' || type === 'bpmn') {
|
||||||
|
const { err, xml } = await bpmnModeler.saveXML();
|
||||||
|
// 读取异常时抛出异常
|
||||||
|
if (err) {
|
||||||
|
console.error(`[Process Designer Warn ]: ${err.message || err}`);
|
||||||
|
}
|
||||||
|
let { href, filename } = setEncoded(type.toUpperCase(), xml);
|
||||||
|
downloadFunc(href, filename);
|
||||||
|
} else {
|
||||||
|
const { err, svg } = await bpmnModeler.saveSVG();
|
||||||
|
// 读取异常时抛出异常
|
||||||
|
if (err) {
|
||||||
|
return console.error(err);
|
||||||
|
}
|
||||||
|
let { href, filename } = setEncoded('SVG', svg);
|
||||||
|
downloadFunc(href, filename);
|
||||||
|
}
|
||||||
|
} catch (e: any) {
|
||||||
|
console.error(`[Process Designer Warn ]: ${e.message || e}`);
|
||||||
|
}
|
||||||
|
// 文件下载方法
|
||||||
|
function downloadFunc(href, filename) {
|
||||||
|
if (href && filename) {
|
||||||
|
let a = document.createElement('a');
|
||||||
|
a.download = filename; //指定下载的文件名
|
||||||
|
a.href = href; // URL对象
|
||||||
|
a.click(); // 模拟点击
|
||||||
|
URL.revokeObjectURL(a.href); // 释放URL 对象
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 根据所需类型进行转码并返回下载地址
|
||||||
|
const setEncoded = (type, data) => {
|
||||||
|
const filename = 'diagram';
|
||||||
|
const encodedData = encodeURIComponent(data);
|
||||||
|
return {
|
||||||
|
filename: `${filename}.${type}`,
|
||||||
|
href: `data:application/${
|
||||||
|
type === 'svg' ? 'text/xml' : 'bpmn20-xml'
|
||||||
|
};charset=UTF-8,${encodedData}`,
|
||||||
|
data: data,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 加载本地文件
|
||||||
|
const importLocalFile = () => {
|
||||||
|
const file = refFile.value.files[0];
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.readAsText(file);
|
||||||
|
reader.onload = function () {
|
||||||
|
let xmlStr = this.result;
|
||||||
|
createNewDiagram(xmlStr);
|
||||||
|
emit('save', xmlStr);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/* ------------------------------------------------ refs methods ------------------------------------------------------ */
|
||||||
|
const downloadProcessAsXml = () => {
|
||||||
|
downloadProcess('xml');
|
||||||
|
};
|
||||||
|
const downloadProcessAsBpmn = () => {
|
||||||
|
downloadProcess('bpmn');
|
||||||
|
};
|
||||||
|
const downloadProcessAsSvg = () => {
|
||||||
|
downloadProcess('svg');
|
||||||
|
};
|
||||||
|
const processSimulation = () => {
|
||||||
|
simulationStatus.value = !simulationStatus.value;
|
||||||
|
console.log(
|
||||||
|
bpmnModeler.get('toggleMode', 'strict'),
|
||||||
|
"bpmnModeler.get('toggleMode')",
|
||||||
|
);
|
||||||
|
props.simulation && bpmnModeler.get('toggleMode', 'strict').toggleMode();
|
||||||
|
};
|
||||||
|
const processRedo = () => {
|
||||||
|
bpmnModeler.get('commandStack').redo();
|
||||||
|
};
|
||||||
|
const processUndo = () => {
|
||||||
|
bpmnModeler.get('commandStack').undo();
|
||||||
|
};
|
||||||
|
const processZoomIn = (zoomStep = 0.1) => {
|
||||||
|
let newZoom = Math.floor(defaultZoom.value * 100 + zoomStep * 100) / 100;
|
||||||
|
if (newZoom > 4) {
|
||||||
|
throw new Error(
|
||||||
|
'[Process Designer Warn ]: The zoom ratio cannot be greater than 4',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
defaultZoom.value = newZoom;
|
||||||
|
bpmnModeler.get('canvas').zoom(defaultZoom.value);
|
||||||
|
};
|
||||||
|
const processZoomOut = (zoomStep = 0.1) => {
|
||||||
|
let newZoom = Math.floor(defaultZoom.value * 100 - zoomStep * 100) / 100;
|
||||||
|
if (newZoom < 0.2) {
|
||||||
|
throw new Error(
|
||||||
|
'[Process Designer Warn ]: The zoom ratio cannot be less than 0.2',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
defaultZoom.value = newZoom;
|
||||||
|
bpmnModeler.get('canvas').zoom(defaultZoom.value);
|
||||||
|
};
|
||||||
|
const processReZoom = () => {
|
||||||
|
defaultZoom.value = 1;
|
||||||
|
bpmnModeler.get('canvas').zoom('fit-viewport', 'auto');
|
||||||
|
};
|
||||||
|
const processRestart = () => {
|
||||||
|
recoverable.value = false;
|
||||||
|
revocable.value = false;
|
||||||
|
createNewDiagram(null);
|
||||||
|
};
|
||||||
|
const elementsAlign = (align) => {
|
||||||
|
const Align = bpmnModeler.get('alignElements');
|
||||||
|
const Selection = bpmnModeler.get('selection');
|
||||||
|
const SelectedElements = Selection.get();
|
||||||
|
if (!SelectedElements || SelectedElements.length <= 1) {
|
||||||
|
ElMessage.warning('请按住 Shift 键选择多个元素对齐');
|
||||||
|
// alert('请按住 Ctrl 键选择多个元素对齐
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ElMessageBox.confirm('自动对齐可能造成图形变形,是否继续?', '警告', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning',
|
||||||
|
}).then(() => {
|
||||||
|
Align.trigger(SelectedElements, align);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/*----------------------------- 方法结束 ---------------------------------*/
|
||||||
|
const previewProcessXML = () => {
|
||||||
|
console.log(bpmnModeler.saveXML, 'bpmnModeler');
|
||||||
|
bpmnModeler.saveXML({ format: true }).then(({ xml }) => {
|
||||||
|
// console.log(xml, 'xml111111')
|
||||||
|
previewResult.value = xml;
|
||||||
|
previewType.value = 'xml';
|
||||||
|
previewModelVisible.value = true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const previewProcessJson = () => {
|
||||||
|
bpmnModeler.saveXML({ format: true }).then(({ xml }) => {
|
||||||
|
const rootNodes = new XmlNode(XmlNodeType.Root, parseXmlString(xml));
|
||||||
|
previewResult.value = rootNodes.parent?.toJSON() as unknown as string;
|
||||||
|
previewType.value = 'json';
|
||||||
|
previewModelVisible.value = true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ------------------------------------------------ 芋道源码 methods ------------------------------------------------------ */
|
||||||
|
onMounted(() => {
|
||||||
|
initBpmnModeler();
|
||||||
|
createNewDiagram(props.value);
|
||||||
|
});
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
if (bpmnModeler) bpmnModeler.destroy();
|
||||||
|
emit('destroy', bpmnModeler);
|
||||||
|
bpmnModeler = null;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,431 @@
|
|||||||
|
<template>
|
||||||
|
<div class="process-viewer">
|
||||||
|
<div style="height: 100%" ref="processCanvas" v-show="!isLoading"></div>
|
||||||
|
<!-- 自定义箭头样式,用于已完成状态下流程连线箭头 -->
|
||||||
|
<defs ref="customDefs">
|
||||||
|
<marker
|
||||||
|
id="sequenceflow-end-white-success"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
refX="11"
|
||||||
|
refY="10"
|
||||||
|
markerWidth="10"
|
||||||
|
markerHeight="10"
|
||||||
|
orient="auto"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
class="success-arrow"
|
||||||
|
d="M 1 5 L 11 10 L 1 15 Z"
|
||||||
|
style="
|
||||||
|
stroke-width: 1px;
|
||||||
|
stroke-linecap: round;
|
||||||
|
stroke-dasharray: 10000, 1;
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
id="conditional-flow-marker-white-success"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
refX="-1"
|
||||||
|
refY="10"
|
||||||
|
markerWidth="10"
|
||||||
|
markerHeight="10"
|
||||||
|
orient="auto"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
class="success-conditional"
|
||||||
|
d="M 0 10 L 8 6 L 16 10 L 8 14 Z"
|
||||||
|
style="
|
||||||
|
stroke-width: 1px;
|
||||||
|
stroke-linecap: round;
|
||||||
|
stroke-dasharray: 10000, 1;
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</marker>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<!-- 审批记录 -->
|
||||||
|
<el-dialog
|
||||||
|
:title="dialogTitle || '审批记录'"
|
||||||
|
v-model="dialogVisible"
|
||||||
|
width="1000px"
|
||||||
|
>
|
||||||
|
<el-row>
|
||||||
|
<el-table
|
||||||
|
:data="selectTasks"
|
||||||
|
size="small"
|
||||||
|
border
|
||||||
|
header-cell-class-name="table-header-gray"
|
||||||
|
>
|
||||||
|
<el-table-column
|
||||||
|
label="序号"
|
||||||
|
header-align="center"
|
||||||
|
align="center"
|
||||||
|
type="index"
|
||||||
|
width="50"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
label="审批人"
|
||||||
|
min-width="100"
|
||||||
|
align="center"
|
||||||
|
v-if="selectActivityType === 'bpmn:UserTask'"
|
||||||
|
>
|
||||||
|
<template #default="scope">
|
||||||
|
{{
|
||||||
|
scope.row.assigneeUser?.nickname ||
|
||||||
|
scope.row.ownerUser?.nickname
|
||||||
|
}}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
label="发起人"
|
||||||
|
prop="assigneeUser.nickname"
|
||||||
|
min-width="100"
|
||||||
|
align="center"
|
||||||
|
v-else
|
||||||
|
/>
|
||||||
|
<el-table-column label="部门" min-width="100" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
{{
|
||||||
|
scope.row.assigneeUser?.deptName ||
|
||||||
|
scope.row.ownerUser?.deptName
|
||||||
|
}}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
:formatter="dateFormatter"
|
||||||
|
align="center"
|
||||||
|
label="开始时间"
|
||||||
|
prop="createTime"
|
||||||
|
min-width="140"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
:formatter="dateFormatter"
|
||||||
|
align="center"
|
||||||
|
label="结束时间"
|
||||||
|
prop="endTime"
|
||||||
|
min-width="140"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
align="center"
|
||||||
|
label="审批状态"
|
||||||
|
prop="status"
|
||||||
|
min-width="90"
|
||||||
|
>
|
||||||
|
<template #default="scope">
|
||||||
|
<dict-tag
|
||||||
|
:type="DICT_TYPE.BPM_TASK_STATUS"
|
||||||
|
:value="scope.row.status"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
align="center"
|
||||||
|
label="审批建议"
|
||||||
|
prop="reason"
|
||||||
|
min-width="120"
|
||||||
|
v-if="selectActivityType === 'bpmn:UserTask'"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
align="center"
|
||||||
|
label="耗时"
|
||||||
|
prop="durationInMillis"
|
||||||
|
width="100"
|
||||||
|
>
|
||||||
|
<template #default="scope">
|
||||||
|
{{ formatPast2(scope.row.durationInMillis) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-row>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- Zoom:放大、缩小 -->
|
||||||
|
<div style="position: absolute; top: 0; left: 0; width: 100%">
|
||||||
|
<el-row type="flex" justify="end">
|
||||||
|
<el-button-group key="scale-control" size="default">
|
||||||
|
<el-button
|
||||||
|
size="default"
|
||||||
|
:plain="true"
|
||||||
|
:disabled="defaultZoom <= 0.3"
|
||||||
|
:icon="ZoomOut"
|
||||||
|
@click="processZoomOut()"
|
||||||
|
/>
|
||||||
|
<el-button size="default" style="width: 90px">
|
||||||
|
{{ Math.floor(defaultZoom * 10 * 10) + '%' }}
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
size="default"
|
||||||
|
:plain="true"
|
||||||
|
:disabled="defaultZoom >= 3.9"
|
||||||
|
:icon="ZoomIn"
|
||||||
|
@click="processZoomIn()"
|
||||||
|
/>
|
||||||
|
<el-button
|
||||||
|
size="default"
|
||||||
|
:icon="ScaleToOriginal"
|
||||||
|
@click="processReZoom()"
|
||||||
|
/>
|
||||||
|
</el-button-group>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import '../theme/index.scss';
|
||||||
|
import BpmnViewer from 'bpmn-js/lib/Viewer';
|
||||||
|
import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas';
|
||||||
|
import { ZoomOut, ZoomIn, ScaleToOriginal } from '@element-plus/icons-vue';
|
||||||
|
import { DICT_TYPE } from '@/utils/dict';
|
||||||
|
import { dateFormatter, formatPast2 } from '@/utils/formatTime';
|
||||||
|
import { BpmProcessInstanceStatus } from '@/utils/constants';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
xml: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
view: {
|
||||||
|
type: Object,
|
||||||
|
require: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const processCanvas = ref();
|
||||||
|
const bpmnViewer = ref<BpmnViewer | null>(null);
|
||||||
|
const customDefs = ref();
|
||||||
|
const defaultZoom = ref(1); // 默认缩放比例
|
||||||
|
const isLoading = ref(false); // 是否加载中
|
||||||
|
|
||||||
|
const processInstance = ref<any>({}); // 流程实例
|
||||||
|
const tasks = ref([]); // 流程任务
|
||||||
|
|
||||||
|
const dialogVisible = ref(false); // 弹窗可见性
|
||||||
|
const dialogTitle = ref<string | undefined>(undefined); // 弹窗标题
|
||||||
|
const selectActivityType = ref<string | undefined>(undefined); // 选中 Task 的活动编号
|
||||||
|
const selectTasks = ref<any[]>([]); // 选中的任务数组
|
||||||
|
|
||||||
|
/** Zoom:恢复 */
|
||||||
|
const processReZoom = () => {
|
||||||
|
defaultZoom.value = 1;
|
||||||
|
bpmnViewer.value?.get('canvas').zoom('fit-viewport', 'auto');
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Zoom:放大 */
|
||||||
|
const processZoomIn = (zoomStep = 0.1) => {
|
||||||
|
let newZoom = Math.floor(defaultZoom.value * 100 + zoomStep * 100) / 100;
|
||||||
|
if (newZoom > 4) {
|
||||||
|
throw new Error(
|
||||||
|
'[Process Designer Warn ]: The zoom ratio cannot be greater than 4',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
defaultZoom.value = newZoom;
|
||||||
|
bpmnViewer.value?.get('canvas').zoom(defaultZoom.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Zoom:缩小 */
|
||||||
|
const processZoomOut = (zoomStep = 0.1) => {
|
||||||
|
let newZoom = Math.floor(defaultZoom.value * 100 - zoomStep * 100) / 100;
|
||||||
|
if (newZoom < 0.2) {
|
||||||
|
throw new Error(
|
||||||
|
'[Process Designer Warn ]: The zoom ratio cannot be less than 0.2',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
defaultZoom.value = newZoom;
|
||||||
|
bpmnViewer.value?.get('canvas').zoom(defaultZoom.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 流程图预览清空 */
|
||||||
|
const clearViewer = () => {
|
||||||
|
if (processCanvas.value) {
|
||||||
|
processCanvas.value.innerHTML = '';
|
||||||
|
}
|
||||||
|
if (bpmnViewer.value) {
|
||||||
|
bpmnViewer.value.destroy();
|
||||||
|
}
|
||||||
|
bpmnViewer.value = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 添加自定义箭头 */
|
||||||
|
// TODO 芋艿:自定义箭头不生效,有点奇怪!!!!相关的 marker-end、marker-start 暂时也注释了!!!
|
||||||
|
const addCustomDefs = () => {
|
||||||
|
if (!bpmnViewer.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const canvas = bpmnViewer.value?.get('canvas');
|
||||||
|
const svg = canvas?._svg;
|
||||||
|
svg.appendChild(customDefs.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 节点选中 */
|
||||||
|
const onSelectElement = (element: any) => {
|
||||||
|
// 清空原选中
|
||||||
|
selectActivityType.value = undefined;
|
||||||
|
dialogTitle.value = undefined;
|
||||||
|
if (!element || !processInstance.value?.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserTask 的情况
|
||||||
|
const activityType = element.type;
|
||||||
|
selectActivityType.value = activityType;
|
||||||
|
if (activityType === 'bpmn:UserTask') {
|
||||||
|
dialogTitle.value = element.businessObject
|
||||||
|
? element.businessObject.name
|
||||||
|
: undefined;
|
||||||
|
selectTasks.value = tasks.value.filter(
|
||||||
|
(item: any) => item?.taskDefinitionKey === element.id,
|
||||||
|
);
|
||||||
|
dialogVisible.value = true;
|
||||||
|
} else if (
|
||||||
|
activityType === 'bpmn:EndEvent' ||
|
||||||
|
activityType === 'bpmn:StartEvent'
|
||||||
|
) {
|
||||||
|
dialogTitle.value = '审批信息';
|
||||||
|
selectTasks.value = [
|
||||||
|
{
|
||||||
|
assigneeUser: processInstance.value.startUser,
|
||||||
|
createTime: processInstance.value.startTime,
|
||||||
|
endTime: processInstance.value.endTime,
|
||||||
|
status: processInstance.value.status,
|
||||||
|
durationInMillis: processInstance.value.durationInMillis,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
dialogVisible.value = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 初始化 BPMN 视图 */
|
||||||
|
const importXML = async (xml: string) => {
|
||||||
|
// 清空流程图
|
||||||
|
clearViewer();
|
||||||
|
|
||||||
|
// 初始化流程图
|
||||||
|
if (xml != null && xml !== '') {
|
||||||
|
try {
|
||||||
|
bpmnViewer.value = new BpmnViewer({
|
||||||
|
additionalModules: [MoveCanvasModule],
|
||||||
|
container: processCanvas.value,
|
||||||
|
});
|
||||||
|
// 增加点击事件
|
||||||
|
bpmnViewer.value.on('element.click', ({ element }) => {
|
||||||
|
onSelectElement(element);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 初始化 BPMN 视图
|
||||||
|
isLoading.value = true;
|
||||||
|
await bpmnViewer.value.importXML(xml);
|
||||||
|
// 自定义成功的箭头
|
||||||
|
addCustomDefs();
|
||||||
|
} catch (e) {
|
||||||
|
clearViewer();
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false;
|
||||||
|
// 高亮流程
|
||||||
|
setProcessStatus(props.view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 高亮流程 */
|
||||||
|
const setProcessStatus = (view: any) => {
|
||||||
|
// 设置相关变量
|
||||||
|
if (!view || !view.processInstance) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
processInstance.value = view.processInstance;
|
||||||
|
tasks.value = view.tasks;
|
||||||
|
if (isLoading.value || !bpmnViewer.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const {
|
||||||
|
unfinishedTaskActivityIds,
|
||||||
|
finishedTaskActivityIds,
|
||||||
|
finishedSequenceFlowActivityIds,
|
||||||
|
rejectedTaskActivityIds,
|
||||||
|
} = view;
|
||||||
|
const canvas = bpmnViewer.value.get('canvas');
|
||||||
|
const elementRegistry = bpmnViewer.value.get('elementRegistry');
|
||||||
|
|
||||||
|
// 已完成节点
|
||||||
|
if (Array.isArray(finishedSequenceFlowActivityIds)) {
|
||||||
|
finishedSequenceFlowActivityIds.forEach((item: any) => {
|
||||||
|
if (item != null) {
|
||||||
|
canvas.addMarker(item, 'success');
|
||||||
|
const element = elementRegistry.get(item);
|
||||||
|
const conditionExpression = element.businessObject.conditionExpression;
|
||||||
|
if (conditionExpression) {
|
||||||
|
canvas.addMarker(item, 'condition-expression');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (Array.isArray(finishedTaskActivityIds)) {
|
||||||
|
finishedTaskActivityIds.forEach((item: any) =>
|
||||||
|
canvas.addMarker(item, 'success'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 未完成节点
|
||||||
|
if (Array.isArray(unfinishedTaskActivityIds)) {
|
||||||
|
unfinishedTaskActivityIds.forEach((item: any) =>
|
||||||
|
canvas.addMarker(item, 'primary'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 被拒绝节点
|
||||||
|
if (Array.isArray(rejectedTaskActivityIds)) {
|
||||||
|
rejectedTaskActivityIds.forEach((item: any) => {
|
||||||
|
if (item != null) {
|
||||||
|
canvas.addMarker(item, 'danger');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 特殊:处理 end 节点的高亮。因为 end 在拒绝、取消时,被后端计算成了 finishedTaskActivityIds 里
|
||||||
|
if (
|
||||||
|
[BpmProcessInstanceStatus.CANCEL, BpmProcessInstanceStatus.REJECT].includes(
|
||||||
|
processInstance.value.status,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
const endNodes = elementRegistry.filter(
|
||||||
|
(element: any) => element.type === 'bpmn:EndEvent',
|
||||||
|
);
|
||||||
|
endNodes.forEach((item: any) => {
|
||||||
|
canvas.removeMarker(item.id, 'success');
|
||||||
|
if (processInstance.value.status === BpmProcessInstanceStatus.CANCEL) {
|
||||||
|
canvas.addMarker(item.id, 'cancel');
|
||||||
|
} else {
|
||||||
|
canvas.addMarker(item.id, 'danger');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.xml,
|
||||||
|
(newXml) => {
|
||||||
|
importXML(newXml);
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.view,
|
||||||
|
(newView) => {
|
||||||
|
setProcessStatus(newView);
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
/** mounted:初始化 */
|
||||||
|
onMounted(() => {
|
||||||
|
importXML(props.xml);
|
||||||
|
setProcessStatus(props.view);
|
||||||
|
});
|
||||||
|
|
||||||
|
/** unmount:销毁 */
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
clearViewer();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import MyProcessDesigner from './ProcessDesigner.vue';
|
||||||
|
|
||||||
|
MyProcessDesigner.install = function (Vue) {
|
||||||
|
Vue.component(MyProcessDesigner.name, MyProcessDesigner);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 流程图的设计器,可编辑
|
||||||
|
export default MyProcessDesigner;
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import MyProcessViewer from './ProcessViewer.vue';
|
||||||
|
|
||||||
|
MyProcessViewer.install = function (Vue) {
|
||||||
|
Vue.component(MyProcessViewer.name, MyProcessViewer);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 流程图的查看器,不可编辑
|
||||||
|
export default MyProcessViewer;
|
||||||
@@ -0,0 +1,440 @@
|
|||||||
|
import { getChildLanes } from 'bpmn-js/lib/features/modeling/util/LaneUtil';
|
||||||
|
import { isAny } from 'bpmn-js/lib/features/modeling/util/ModelingUtil';
|
||||||
|
import { isEventSubProcess, isExpanded } from 'bpmn-js/lib/util/DiUtil';
|
||||||
|
import { is } from 'bpmn-js/lib/util/ModelUtil';
|
||||||
|
import { hasPrimaryModifier } from 'diagram-js/lib/util/Mouse';
|
||||||
|
import { assign, forEach, isArray } from 'min-dash';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A provider for BPMN 2.0 elements context pad
|
||||||
|
*/
|
||||||
|
export default function ContextPadProvider(
|
||||||
|
config,
|
||||||
|
injector,
|
||||||
|
eventBus,
|
||||||
|
contextPad,
|
||||||
|
modeling,
|
||||||
|
elementFactory,
|
||||||
|
connect,
|
||||||
|
create,
|
||||||
|
popupMenu,
|
||||||
|
canvas,
|
||||||
|
rules,
|
||||||
|
translate,
|
||||||
|
) {
|
||||||
|
config = config || {};
|
||||||
|
|
||||||
|
contextPad.registerProvider(this);
|
||||||
|
|
||||||
|
this._contextPad = contextPad;
|
||||||
|
|
||||||
|
this._modeling = modeling;
|
||||||
|
|
||||||
|
this._elementFactory = elementFactory;
|
||||||
|
this._connect = connect;
|
||||||
|
this._create = create;
|
||||||
|
this._popupMenu = popupMenu;
|
||||||
|
this._canvas = canvas;
|
||||||
|
this._rules = rules;
|
||||||
|
this._translate = translate;
|
||||||
|
|
||||||
|
if (config.autoPlace !== false) {
|
||||||
|
this._autoPlace = injector.get('autoPlace', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
eventBus.on('create.end', 250, (event) => {
|
||||||
|
const context = event.context;
|
||||||
|
const shape = context.shape;
|
||||||
|
|
||||||
|
if (!hasPrimaryModifier(event) || !contextPad.isOpen(shape)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const entries = contextPad.getEntries(shape);
|
||||||
|
|
||||||
|
if (entries.replace) {
|
||||||
|
entries.replace.action.click(event, shape);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ContextPadProvider.$inject = [
|
||||||
|
'config.contextPad',
|
||||||
|
'injector',
|
||||||
|
'eventBus',
|
||||||
|
'contextPad',
|
||||||
|
'modeling',
|
||||||
|
'elementFactory',
|
||||||
|
'connect',
|
||||||
|
'create',
|
||||||
|
'popupMenu',
|
||||||
|
'canvas',
|
||||||
|
'rules',
|
||||||
|
'translate',
|
||||||
|
'elementRegistry',
|
||||||
|
];
|
||||||
|
|
||||||
|
ContextPadProvider.prototype.getContextPadEntries = function (element) {
|
||||||
|
const autoPlace = this._autoPlace;
|
||||||
|
const canvas = this._canvas;
|
||||||
|
const connect = this._connect;
|
||||||
|
const contextPad = this._contextPad;
|
||||||
|
const create = this._create;
|
||||||
|
const elementFactory = this._elementFactory;
|
||||||
|
const modeling = this._modeling;
|
||||||
|
const popupMenu = this._popupMenu;
|
||||||
|
const rules = this._rules;
|
||||||
|
const translate = this._translate;
|
||||||
|
|
||||||
|
const actions = {};
|
||||||
|
|
||||||
|
if (element.type === 'label') {
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
const businessObject = element.businessObject;
|
||||||
|
|
||||||
|
function startConnect(event, element) {
|
||||||
|
connect.start(event, element);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeElement() {
|
||||||
|
modeling.removeElements([element]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getReplaceMenuPosition(element) {
|
||||||
|
const Y_OFFSET = 5;
|
||||||
|
|
||||||
|
const diagramContainer = canvas.getContainer();
|
||||||
|
const pad = contextPad.getPad(element).html;
|
||||||
|
|
||||||
|
const diagramRect = diagramContainer.getBoundingClientRect();
|
||||||
|
const padRect = pad.getBoundingClientRect();
|
||||||
|
|
||||||
|
const top = padRect.top - diagramRect.top;
|
||||||
|
const left = padRect.left - diagramRect.left;
|
||||||
|
|
||||||
|
const pos = {
|
||||||
|
x: left,
|
||||||
|
y: top + padRect.height + Y_OFFSET,
|
||||||
|
};
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an append action
|
||||||
|
*
|
||||||
|
* @param {string} type
|
||||||
|
* @param {string} className
|
||||||
|
* @param {string} [title]
|
||||||
|
* @param {object} [options]
|
||||||
|
*
|
||||||
|
* @return {object} descriptor
|
||||||
|
*/
|
||||||
|
function appendAction(type, className, title, options) {
|
||||||
|
if (typeof title !== 'string') {
|
||||||
|
options = title;
|
||||||
|
title = translate('Append {type}', { type: type.replace(/^bpmn:/, '') });
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendStart(event, element) {
|
||||||
|
const shape = elementFactory.createShape(assign({ type }, options));
|
||||||
|
create.start(event, shape, {
|
||||||
|
source: element,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const append = autoPlace
|
||||||
|
? function (event, element) {
|
||||||
|
const shape = elementFactory.createShape(assign({ type }, options));
|
||||||
|
|
||||||
|
autoPlace.append(element, shape);
|
||||||
|
}
|
||||||
|
: appendStart;
|
||||||
|
|
||||||
|
return {
|
||||||
|
group: 'model',
|
||||||
|
className,
|
||||||
|
title,
|
||||||
|
action: {
|
||||||
|
dragstart: appendStart,
|
||||||
|
click: append,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function splitLaneHandler(count) {
|
||||||
|
return function (event, element) {
|
||||||
|
// actual split
|
||||||
|
modeling.splitLane(element, count);
|
||||||
|
|
||||||
|
// refresh context pad after split to
|
||||||
|
// get rid of split icons
|
||||||
|
contextPad.open(element, true);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
isAny(businessObject, ['bpmn:Lane', 'bpmn:Participant']) &&
|
||||||
|
isExpanded(businessObject)
|
||||||
|
) {
|
||||||
|
const childLanes = getChildLanes(element);
|
||||||
|
|
||||||
|
assign(actions, {
|
||||||
|
'lane-insert-above': {
|
||||||
|
group: 'lane-insert-above',
|
||||||
|
className: 'bpmn-icon-lane-insert-above',
|
||||||
|
title: translate('Add Lane above'),
|
||||||
|
action: {
|
||||||
|
click(event, element) {
|
||||||
|
modeling.addLane(element, 'top');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (childLanes.length < 2) {
|
||||||
|
if (element.height >= 120) {
|
||||||
|
assign(actions, {
|
||||||
|
'lane-divide-two': {
|
||||||
|
group: 'lane-divide',
|
||||||
|
className: 'bpmn-icon-lane-divide-two',
|
||||||
|
title: translate('Divide into two Lanes'),
|
||||||
|
action: {
|
||||||
|
click: splitLaneHandler(2),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.height >= 180) {
|
||||||
|
assign(actions, {
|
||||||
|
'lane-divide-three': {
|
||||||
|
group: 'lane-divide',
|
||||||
|
className: 'bpmn-icon-lane-divide-three',
|
||||||
|
title: translate('Divide into three Lanes'),
|
||||||
|
action: {
|
||||||
|
click: splitLaneHandler(3),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assign(actions, {
|
||||||
|
'lane-insert-below': {
|
||||||
|
group: 'lane-insert-below',
|
||||||
|
className: 'bpmn-icon-lane-insert-below',
|
||||||
|
title: translate('Add Lane below'),
|
||||||
|
action: {
|
||||||
|
click(event, element) {
|
||||||
|
modeling.addLane(element, 'bottom');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is(businessObject, 'bpmn:FlowNode')) {
|
||||||
|
if (is(businessObject, 'bpmn:EventBasedGateway')) {
|
||||||
|
assign(actions, {
|
||||||
|
'append.receive-task': appendAction(
|
||||||
|
'bpmn:ReceiveTask',
|
||||||
|
'bpmn-icon-receive-task',
|
||||||
|
translate('Append ReceiveTask'),
|
||||||
|
),
|
||||||
|
'append.message-intermediate-event': appendAction(
|
||||||
|
'bpmn:IntermediateCatchEvent',
|
||||||
|
'bpmn-icon-intermediate-event-catch-message',
|
||||||
|
translate('Append MessageIntermediateCatchEvent'),
|
||||||
|
{ eventDefinitionType: 'bpmn:MessageEventDefinition' },
|
||||||
|
),
|
||||||
|
'append.timer-intermediate-event': appendAction(
|
||||||
|
'bpmn:IntermediateCatchEvent',
|
||||||
|
'bpmn-icon-intermediate-event-catch-timer',
|
||||||
|
translate('Append TimerIntermediateCatchEvent'),
|
||||||
|
{ eventDefinitionType: 'bpmn:TimerEventDefinition' },
|
||||||
|
),
|
||||||
|
'append.condition-intermediate-event': appendAction(
|
||||||
|
'bpmn:IntermediateCatchEvent',
|
||||||
|
'bpmn-icon-intermediate-event-catch-condition',
|
||||||
|
translate('Append ConditionIntermediateCatchEvent'),
|
||||||
|
{ eventDefinitionType: 'bpmn:ConditionalEventDefinition' },
|
||||||
|
),
|
||||||
|
'append.signal-intermediate-event': appendAction(
|
||||||
|
'bpmn:IntermediateCatchEvent',
|
||||||
|
'bpmn-icon-intermediate-event-catch-signal',
|
||||||
|
translate('Append SignalIntermediateCatchEvent'),
|
||||||
|
{ eventDefinitionType: 'bpmn:SignalEventDefinition' },
|
||||||
|
),
|
||||||
|
});
|
||||||
|
} else if (
|
||||||
|
isEventType(
|
||||||
|
businessObject,
|
||||||
|
'bpmn:BoundaryEvent',
|
||||||
|
'bpmn:CompensateEventDefinition',
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
assign(actions, {
|
||||||
|
'append.compensation-activity': appendAction(
|
||||||
|
'bpmn:Task',
|
||||||
|
'bpmn-icon-task',
|
||||||
|
translate('Append compensation activity'),
|
||||||
|
{
|
||||||
|
isForCompensation: true,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
});
|
||||||
|
} else if (
|
||||||
|
!is(businessObject, 'bpmn:EndEvent') &&
|
||||||
|
!businessObject.isForCompensation &&
|
||||||
|
!isEventType(
|
||||||
|
businessObject,
|
||||||
|
'bpmn:IntermediateThrowEvent',
|
||||||
|
'bpmn:LinkEventDefinition',
|
||||||
|
) &&
|
||||||
|
!isEventSubProcess(businessObject)
|
||||||
|
) {
|
||||||
|
assign(actions, {
|
||||||
|
'append.end-event': appendAction(
|
||||||
|
'bpmn:EndEvent',
|
||||||
|
'bpmn-icon-end-event-none',
|
||||||
|
translate('Append EndEvent'),
|
||||||
|
),
|
||||||
|
'append.gateway': appendAction(
|
||||||
|
'bpmn:ExclusiveGateway',
|
||||||
|
'bpmn-icon-gateway-none',
|
||||||
|
translate('Append Gateway'),
|
||||||
|
),
|
||||||
|
'append.append-task': appendAction(
|
||||||
|
'bpmn:UserTask',
|
||||||
|
'bpmn-icon-user-task',
|
||||||
|
translate('Append Task'),
|
||||||
|
),
|
||||||
|
'append.intermediate-event': appendAction(
|
||||||
|
'bpmn:IntermediateThrowEvent',
|
||||||
|
'bpmn-icon-intermediate-event-none',
|
||||||
|
translate('Append Intermediate/Boundary Event'),
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!popupMenu.isEmpty(element, 'bpmn-replace')) {
|
||||||
|
// Replace menu entry
|
||||||
|
assign(actions, {
|
||||||
|
replace: {
|
||||||
|
group: 'edit',
|
||||||
|
className: 'bpmn-icon-screw-wrench',
|
||||||
|
title: '修改类型',
|
||||||
|
action: {
|
||||||
|
click(event, element) {
|
||||||
|
const position = assign(getReplaceMenuPosition(element), {
|
||||||
|
cursor: { x: event.x, y: event.y },
|
||||||
|
});
|
||||||
|
|
||||||
|
popupMenu.open(element, 'bpmn-replace', position);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
isAny(businessObject, [
|
||||||
|
'bpmn:FlowNode',
|
||||||
|
'bpmn:InteractionNode',
|
||||||
|
'bpmn:DataObjectReference',
|
||||||
|
'bpmn:DataStoreReference',
|
||||||
|
])
|
||||||
|
) {
|
||||||
|
assign(actions, {
|
||||||
|
'append.text-annotation': appendAction(
|
||||||
|
'bpmn:TextAnnotation',
|
||||||
|
'bpmn-icon-text-annotation',
|
||||||
|
),
|
||||||
|
|
||||||
|
connect: {
|
||||||
|
group: 'connect',
|
||||||
|
className: 'bpmn-icon-connection-multi',
|
||||||
|
title: translate(
|
||||||
|
`Connect using ${
|
||||||
|
businessObject.isForCompensation ? '' : 'Sequence/MessageFlow or '
|
||||||
|
}Association`,
|
||||||
|
),
|
||||||
|
action: {
|
||||||
|
click: startConnect,
|
||||||
|
dragstart: startConnect,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
isAny(businessObject, [
|
||||||
|
'bpmn:DataObjectReference',
|
||||||
|
'bpmn:DataStoreReference',
|
||||||
|
])
|
||||||
|
) {
|
||||||
|
assign(actions, {
|
||||||
|
connect: {
|
||||||
|
group: 'connect',
|
||||||
|
className: 'bpmn-icon-connection-multi',
|
||||||
|
title: translate('Connect using DataInputAssociation'),
|
||||||
|
action: {
|
||||||
|
click: startConnect,
|
||||||
|
dragstart: startConnect,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is(businessObject, 'bpmn:Group')) {
|
||||||
|
assign(actions, {
|
||||||
|
'append.text-annotation': appendAction(
|
||||||
|
'bpmn:TextAnnotation',
|
||||||
|
'bpmn-icon-text-annotation',
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete element entry, only show if allowed by rules
|
||||||
|
let deleteAllowed = rules.allowed('elements.delete', { elements: [element] });
|
||||||
|
|
||||||
|
if (isArray(deleteAllowed)) {
|
||||||
|
// was the element returned as a deletion candidate?
|
||||||
|
deleteAllowed = deleteAllowed[0] === element;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deleteAllowed) {
|
||||||
|
assign(actions, {
|
||||||
|
delete: {
|
||||||
|
group: 'edit',
|
||||||
|
className: 'bpmn-icon-trash',
|
||||||
|
title: translate('Remove'),
|
||||||
|
action: {
|
||||||
|
click: removeElement,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return actions;
|
||||||
|
};
|
||||||
|
|
||||||
|
// helpers /////////
|
||||||
|
|
||||||
|
function isEventType(eventBo, type, definition) {
|
||||||
|
const isType = eventBo.$instanceOf(type);
|
||||||
|
let isDefinition = false;
|
||||||
|
|
||||||
|
const definitions = eventBo.eventDefinitions || [];
|
||||||
|
forEach(definitions, (def) => {
|
||||||
|
if (def.$type === definition) {
|
||||||
|
isDefinition = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return isType && isDefinition;
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import CustomContextPadProvider from './contentPadProvider';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
__init__: ['contextPadProvider'],
|
||||||
|
contextPadProvider: ['type', CustomContextPadProvider],
|
||||||
|
};
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
export default (key, name, type) => {
|
||||||
|
if (!type) type = 'camunda';
|
||||||
|
const TYPE_TARGET = {
|
||||||
|
activiti: 'http://activiti.org/bpmn',
|
||||||
|
camunda: 'http://bpmn.io/schema/bpmn',
|
||||||
|
flowable: 'http://flowable.org/bpmn',
|
||||||
|
};
|
||||||
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<bpmn2:definitions
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL"
|
||||||
|
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
|
||||||
|
xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"
|
||||||
|
xmlns:di="http://www.omg.org/spec/DD/20100524/DI"
|
||||||
|
id="diagram_${key}"
|
||||||
|
targetNamespace="${TYPE_TARGET[type]}">
|
||||||
|
<bpmn2:process id="${key}" name="${name}" isExecutable="true">
|
||||||
|
</bpmn2:process>
|
||||||
|
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||||
|
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="${key}">
|
||||||
|
</bpmndi:BPMNPlane>
|
||||||
|
</bpmndi:BPMNDiagram>
|
||||||
|
</bpmn2:definitions>`;
|
||||||
|
};
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,101 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import { some } from 'min-dash';
|
||||||
|
|
||||||
|
// const some = require('min-dash').some
|
||||||
|
// const some = some
|
||||||
|
|
||||||
|
const ALLOWED_TYPES = {
|
||||||
|
FailedJobRetryTimeCycle: [
|
||||||
|
'bpmn:StartEvent',
|
||||||
|
'bpmn:BoundaryEvent',
|
||||||
|
'bpmn:IntermediateCatchEvent',
|
||||||
|
'bpmn:Activity',
|
||||||
|
],
|
||||||
|
Connector: ['bpmn:EndEvent', 'bpmn:IntermediateThrowEvent'],
|
||||||
|
Field: ['bpmn:EndEvent', 'bpmn:IntermediateThrowEvent'],
|
||||||
|
};
|
||||||
|
|
||||||
|
function is(element, type) {
|
||||||
|
return (
|
||||||
|
element &&
|
||||||
|
typeof element.$instanceOf === 'function' &&
|
||||||
|
element.$instanceOf(type)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function exists(element) {
|
||||||
|
return element && element.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
function includesType(collection, type) {
|
||||||
|
return (
|
||||||
|
exists(collection) &&
|
||||||
|
some(collection, (element) => {
|
||||||
|
return is(element, type);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function anyType(element, types) {
|
||||||
|
return some(types, (type) => {
|
||||||
|
return is(element, type);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function isAllowed(propName, propDescriptor, newElement) {
|
||||||
|
const name = propDescriptor.name;
|
||||||
|
const types = ALLOWED_TYPES[name.replace(/activiti:/, '')];
|
||||||
|
|
||||||
|
return name === propName && anyType(newElement, types);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ActivitiModdleExtension(eventBus) {
|
||||||
|
eventBus.on(
|
||||||
|
'property.clone',
|
||||||
|
function (context) {
|
||||||
|
const newElement = context.newElement;
|
||||||
|
const propDescriptor = context.propertyDescriptor;
|
||||||
|
|
||||||
|
this.canCloneProperty(newElement, propDescriptor);
|
||||||
|
},
|
||||||
|
this,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActivitiModdleExtension.$inject = ['eventBus'];
|
||||||
|
|
||||||
|
ActivitiModdleExtension.prototype.canCloneProperty = function (
|
||||||
|
newElement,
|
||||||
|
propDescriptor,
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
isAllowed('activiti:FailedJobRetryTimeCycle', propDescriptor, newElement)
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
includesType(newElement.eventDefinitions, 'bpmn:TimerEventDefinition') ||
|
||||||
|
includesType(newElement.eventDefinitions, 'bpmn:SignalEventDefinition') ||
|
||||||
|
is(
|
||||||
|
newElement.loopCharacteristics,
|
||||||
|
'bpmn:MultiInstanceLoopCharacteristics',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAllowed('activiti:Connector', propDescriptor, newElement)) {
|
||||||
|
return includesType(
|
||||||
|
newElement.eventDefinitions,
|
||||||
|
'bpmn:MessageEventDefinition',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAllowed('activiti:Field', propDescriptor, newElement)) {
|
||||||
|
return includesType(
|
||||||
|
newElement.eventDefinitions,
|
||||||
|
'bpmn:MessageEventDefinition',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// module.exports = ActivitiModdleExtension;
|
||||||
|
export default ActivitiModdleExtension;
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* @author igdianov
|
||||||
|
* address https://github.com/igdianov/activiti-bpmn-moddle
|
||||||
|
* */
|
||||||
|
|
||||||
|
import activitiExtension from './activitiExtension';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
__init__: ['ActivitiModdleExtension'],
|
||||||
|
ActivitiModdleExtension: ['type', activitiExtension],
|
||||||
|
};
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import { isFunction, isObject, some } from 'min-dash';
|
||||||
|
|
||||||
|
// const isFunction = isFunction,
|
||||||
|
// isObject = isObject,
|
||||||
|
// some = some
|
||||||
|
// const isFunction = require('min-dash').isFunction,
|
||||||
|
// isObject = require('min-dash').isObject,
|
||||||
|
// some = require('min-dash').some
|
||||||
|
|
||||||
|
const WILDCARD = '*';
|
||||||
|
|
||||||
|
function CamundaModdleExtension(eventBus) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
eventBus.on('moddleCopy.canCopyProperty', (context) => {
|
||||||
|
const parent = context.parent;
|
||||||
|
const property = context.property;
|
||||||
|
|
||||||
|
return self.canCopyProperty(property, parent);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
CamundaModdleExtension.$inject = ['eventBus'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check wether to disallow copying property.
|
||||||
|
*/
|
||||||
|
CamundaModdleExtension.prototype.canCopyProperty = function (property, parent) {
|
||||||
|
// (1) check wether property is allowed in parent
|
||||||
|
if (isObject(property) && !isAllowedInParent(property, parent)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// (2) check more complex scenarios
|
||||||
|
|
||||||
|
if (is(property, 'camunda:InputOutput') && !this.canHostInputOutput(parent)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
isAny(property, ['camunda:Connector', 'camunda:Field']) &&
|
||||||
|
!this.canHostConnector(parent)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is(property, 'camunda:In') && !this.canHostIn(parent)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
CamundaModdleExtension.prototype.canHostInputOutput = function (parent) {
|
||||||
|
// allowed in camunda:Connector
|
||||||
|
const connector = getParent(parent, 'camunda:Connector');
|
||||||
|
|
||||||
|
if (connector) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// special rules inside bpmn:FlowNode
|
||||||
|
const flowNode = getParent(parent, 'bpmn:FlowNode');
|
||||||
|
|
||||||
|
if (!flowNode) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
isAny(flowNode, ['bpmn:StartEvent', 'bpmn:Gateway', 'bpmn:BoundaryEvent'])
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !(is(flowNode, 'bpmn:SubProcess') && flowNode.get('triggeredByEvent'));
|
||||||
|
};
|
||||||
|
|
||||||
|
CamundaModdleExtension.prototype.canHostConnector = function (parent) {
|
||||||
|
const serviceTaskLike = getParent(parent, 'camunda:ServiceTaskLike');
|
||||||
|
|
||||||
|
if (is(serviceTaskLike, 'bpmn:MessageEventDefinition')) {
|
||||||
|
// only allow on throw and end events
|
||||||
|
return (
|
||||||
|
getParent(parent, 'bpmn:IntermediateThrowEvent') ||
|
||||||
|
getParent(parent, 'bpmn:EndEvent')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
CamundaModdleExtension.prototype.canHostIn = function (parent) {
|
||||||
|
const callActivity = getParent(parent, 'bpmn:CallActivity');
|
||||||
|
|
||||||
|
if (callActivity) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const signalEventDefinition = getParent(parent, 'bpmn:SignalEventDefinition');
|
||||||
|
|
||||||
|
if (signalEventDefinition) {
|
||||||
|
// only allow on throw and end events
|
||||||
|
return (
|
||||||
|
getParent(parent, 'bpmn:IntermediateThrowEvent') ||
|
||||||
|
getParent(parent, 'bpmn:EndEvent')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// module.exports = CamundaModdleExtension;
|
||||||
|
export default CamundaModdleExtension;
|
||||||
|
|
||||||
|
// helpers //////////
|
||||||
|
|
||||||
|
function is(element, type) {
|
||||||
|
return (
|
||||||
|
element && isFunction(element.$instanceOf) && element.$instanceOf(type)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isAny(element, types) {
|
||||||
|
return some(types, (t) => {
|
||||||
|
return is(element, t);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getParent(element, type) {
|
||||||
|
if (!type) {
|
||||||
|
return element.$parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is(element, type)) {
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!element.$parent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getParent(element.$parent, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isAllowedInParent(property, parent) {
|
||||||
|
// (1) find property descriptor
|
||||||
|
const descriptor =
|
||||||
|
property.$type && property.$model.getTypeDescriptor(property.$type);
|
||||||
|
|
||||||
|
const allowedIn = descriptor && descriptor.meta && descriptor.meta.allowedIn;
|
||||||
|
|
||||||
|
if (!allowedIn || isWildcard(allowedIn)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// (2) check wether property has parent of allowed type
|
||||||
|
return some(allowedIn, (type) => {
|
||||||
|
return getParent(parent, type);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function isWildcard(allowedIn) {
|
||||||
|
return allowedIn.includes(WILDCARD);
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import extension from './extension';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
__init__: ['camundaModdleExtension'],
|
||||||
|
camundaModdleExtension: ['type', extension],
|
||||||
|
};
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import { some } from 'min-dash';
|
||||||
|
|
||||||
|
// const some = some
|
||||||
|
// const some = require('min-dash').some
|
||||||
|
|
||||||
|
const ALLOWED_TYPES = {
|
||||||
|
FailedJobRetryTimeCycle: [
|
||||||
|
'bpmn:StartEvent',
|
||||||
|
'bpmn:BoundaryEvent',
|
||||||
|
'bpmn:IntermediateCatchEvent',
|
||||||
|
'bpmn:Activity',
|
||||||
|
],
|
||||||
|
Connector: ['bpmn:EndEvent', 'bpmn:IntermediateThrowEvent'],
|
||||||
|
Field: ['bpmn:EndEvent', 'bpmn:IntermediateThrowEvent'],
|
||||||
|
};
|
||||||
|
|
||||||
|
function is(element, type) {
|
||||||
|
return (
|
||||||
|
element &&
|
||||||
|
typeof element.$instanceOf === 'function' &&
|
||||||
|
element.$instanceOf(type)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function exists(element) {
|
||||||
|
return element && element.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
function includesType(collection, type) {
|
||||||
|
return (
|
||||||
|
exists(collection) &&
|
||||||
|
some(collection, (element) => {
|
||||||
|
return is(element, type);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function anyType(element, types) {
|
||||||
|
return some(types, (type) => {
|
||||||
|
return is(element, type);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function isAllowed(propName, propDescriptor, newElement) {
|
||||||
|
const name = propDescriptor.name;
|
||||||
|
const types = ALLOWED_TYPES[name.replace(/flowable:/, '')];
|
||||||
|
|
||||||
|
return name === propName && anyType(newElement, types);
|
||||||
|
}
|
||||||
|
|
||||||
|
function FlowableModdleExtension(eventBus) {
|
||||||
|
eventBus.on(
|
||||||
|
'property.clone',
|
||||||
|
function (context) {
|
||||||
|
const newElement = context.newElement;
|
||||||
|
const propDescriptor = context.propertyDescriptor;
|
||||||
|
|
||||||
|
this.canCloneProperty(newElement, propDescriptor);
|
||||||
|
},
|
||||||
|
this,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
FlowableModdleExtension.$inject = ['eventBus'];
|
||||||
|
|
||||||
|
FlowableModdleExtension.prototype.canCloneProperty = function (
|
||||||
|
newElement,
|
||||||
|
propDescriptor,
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
isAllowed('flowable:FailedJobRetryTimeCycle', propDescriptor, newElement)
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
includesType(newElement.eventDefinitions, 'bpmn:TimerEventDefinition') ||
|
||||||
|
includesType(newElement.eventDefinitions, 'bpmn:SignalEventDefinition') ||
|
||||||
|
is(
|
||||||
|
newElement.loopCharacteristics,
|
||||||
|
'bpmn:MultiInstanceLoopCharacteristics',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAllowed('flowable:Connector', propDescriptor, newElement)) {
|
||||||
|
return includesType(
|
||||||
|
newElement.eventDefinitions,
|
||||||
|
'bpmn:MessageEventDefinition',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAllowed('flowable:Field', propDescriptor, newElement)) {
|
||||||
|
return includesType(
|
||||||
|
newElement.eventDefinitions,
|
||||||
|
'bpmn:MessageEventDefinition',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// module.exports = FlowableModdleExtension;
|
||||||
|
export default FlowableModdleExtension;
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* @author igdianov
|
||||||
|
* address https://github.com/igdianov/activiti-bpmn-moddle
|
||||||
|
* */
|
||||||
|
import flowableExtension from './flowableExtension';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
__init__: ['FlowableModdleExtension'],
|
||||||
|
FlowableModdleExtension: ['type', flowableExtension],
|
||||||
|
};
|
||||||
@@ -0,0 +1,233 @@
|
|||||||
|
import PaletteProvider from 'bpmn-js/lib/features/palette/PaletteProvider';
|
||||||
|
import { assign } from 'min-dash';
|
||||||
|
|
||||||
|
export default function CustomPalette(
|
||||||
|
palette,
|
||||||
|
create,
|
||||||
|
elementFactory,
|
||||||
|
spaceTool,
|
||||||
|
lassoTool,
|
||||||
|
handTool,
|
||||||
|
globalConnect,
|
||||||
|
translate,
|
||||||
|
) {
|
||||||
|
PaletteProvider.call(
|
||||||
|
this,
|
||||||
|
palette,
|
||||||
|
create,
|
||||||
|
elementFactory,
|
||||||
|
spaceTool,
|
||||||
|
lassoTool,
|
||||||
|
handTool,
|
||||||
|
globalConnect,
|
||||||
|
translate,
|
||||||
|
2000,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const F = function () {}; // 核心,利用空对象作为中介;
|
||||||
|
F.prototype = PaletteProvider.prototype; // 核心,将父类的原型赋值给空对象F;
|
||||||
|
|
||||||
|
// 利用中介函数重写原型链方法
|
||||||
|
F.prototype.getPaletteEntries = function () {
|
||||||
|
const actions = {};
|
||||||
|
const create = this._create;
|
||||||
|
const elementFactory = this._elementFactory;
|
||||||
|
const spaceTool = this._spaceTool;
|
||||||
|
const lassoTool = this._lassoTool;
|
||||||
|
const handTool = this._handTool;
|
||||||
|
const globalConnect = this._globalConnect;
|
||||||
|
const translate = this._translate;
|
||||||
|
|
||||||
|
function createAction(type, group, className, title, options) {
|
||||||
|
function createListener(event) {
|
||||||
|
const shape = elementFactory.createShape(assign({ type }, options));
|
||||||
|
|
||||||
|
if (options) {
|
||||||
|
shape.businessObject.di.isExpanded = options.isExpanded;
|
||||||
|
}
|
||||||
|
|
||||||
|
create.start(event, shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
const shortType = type.replace(/^bpmn:/, '');
|
||||||
|
|
||||||
|
return {
|
||||||
|
group,
|
||||||
|
className,
|
||||||
|
title: title || translate('Create {type}', { type: shortType }),
|
||||||
|
action: {
|
||||||
|
dragstart: createListener,
|
||||||
|
click: createListener,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createSubprocess(event) {
|
||||||
|
const subProcess = elementFactory.createShape({
|
||||||
|
type: 'bpmn:SubProcess',
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
isExpanded: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const startEvent = elementFactory.createShape({
|
||||||
|
type: 'bpmn:StartEvent',
|
||||||
|
x: 40,
|
||||||
|
y: 82,
|
||||||
|
parent: subProcess,
|
||||||
|
});
|
||||||
|
|
||||||
|
create.start(event, [subProcess, startEvent], {
|
||||||
|
hints: {
|
||||||
|
autoSelect: [startEvent],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function createParticipant(event) {
|
||||||
|
create.start(event, elementFactory.createParticipantShape());
|
||||||
|
}
|
||||||
|
|
||||||
|
assign(actions, {
|
||||||
|
'hand-tool': {
|
||||||
|
group: 'tools',
|
||||||
|
className: 'bpmn-icon-hand-tool',
|
||||||
|
title: '激活抓手工具',
|
||||||
|
// title: translate("Activate the hand tool"),
|
||||||
|
action: {
|
||||||
|
click(event) {
|
||||||
|
handTool.activateHand(event);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'lasso-tool': {
|
||||||
|
group: 'tools',
|
||||||
|
className: 'bpmn-icon-lasso-tool',
|
||||||
|
title: translate('Activate the lasso tool'),
|
||||||
|
action: {
|
||||||
|
click(event) {
|
||||||
|
lassoTool.activateSelection(event);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'space-tool': {
|
||||||
|
group: 'tools',
|
||||||
|
className: 'bpmn-icon-space-tool',
|
||||||
|
title: translate('Activate the create/remove space tool'),
|
||||||
|
action: {
|
||||||
|
click(event) {
|
||||||
|
spaceTool.activateSelection(event);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'global-connect-tool': {
|
||||||
|
group: 'tools',
|
||||||
|
className: 'bpmn-icon-connection-multi',
|
||||||
|
title: translate('Activate the global connect tool'),
|
||||||
|
action: {
|
||||||
|
click(event) {
|
||||||
|
globalConnect.toggle(event);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'tool-separator': {
|
||||||
|
group: 'tools',
|
||||||
|
separator: true,
|
||||||
|
},
|
||||||
|
'create.start-event': createAction(
|
||||||
|
'bpmn:StartEvent',
|
||||||
|
'event',
|
||||||
|
'bpmn-icon-start-event-none',
|
||||||
|
translate('Create StartEvent'),
|
||||||
|
),
|
||||||
|
'create.intermediate-event': createAction(
|
||||||
|
'bpmn:IntermediateThrowEvent',
|
||||||
|
'event',
|
||||||
|
'bpmn-icon-intermediate-event-none',
|
||||||
|
translate('Create Intermediate/Boundary Event'),
|
||||||
|
),
|
||||||
|
'create.end-event': createAction(
|
||||||
|
'bpmn:EndEvent',
|
||||||
|
'event',
|
||||||
|
'bpmn-icon-end-event-none',
|
||||||
|
translate('Create EndEvent'),
|
||||||
|
),
|
||||||
|
'create.exclusive-gateway': createAction(
|
||||||
|
'bpmn:ExclusiveGateway',
|
||||||
|
'gateway',
|
||||||
|
'bpmn-icon-gateway-none',
|
||||||
|
translate('Create Gateway'),
|
||||||
|
),
|
||||||
|
'create.user-task': createAction(
|
||||||
|
'bpmn:UserTask',
|
||||||
|
'activity',
|
||||||
|
'bpmn-icon-user-task',
|
||||||
|
translate('Create User Task'),
|
||||||
|
),
|
||||||
|
'create.call-activity': createAction(
|
||||||
|
'bpmn:CallActivity',
|
||||||
|
'activity',
|
||||||
|
'bpmn-icon-call-activity',
|
||||||
|
translate('Create Call Activity'),
|
||||||
|
),
|
||||||
|
'create.service-task': createAction(
|
||||||
|
'bpmn:ServiceTask',
|
||||||
|
'activity',
|
||||||
|
'bpmn-icon-service',
|
||||||
|
translate('Create Service Task'),
|
||||||
|
),
|
||||||
|
'create.data-object': createAction(
|
||||||
|
'bpmn:DataObjectReference',
|
||||||
|
'data-object',
|
||||||
|
'bpmn-icon-data-object',
|
||||||
|
translate('Create DataObjectReference'),
|
||||||
|
),
|
||||||
|
'create.data-store': createAction(
|
||||||
|
'bpmn:DataStoreReference',
|
||||||
|
'data-store',
|
||||||
|
'bpmn-icon-data-store',
|
||||||
|
translate('Create DataStoreReference'),
|
||||||
|
),
|
||||||
|
'create.subprocess-expanded': {
|
||||||
|
group: 'activity',
|
||||||
|
className: 'bpmn-icon-subprocess-expanded',
|
||||||
|
title: translate('Create expanded SubProcess'),
|
||||||
|
action: {
|
||||||
|
dragstart: createSubprocess,
|
||||||
|
click: createSubprocess,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'create.participant-expanded': {
|
||||||
|
group: 'collaboration',
|
||||||
|
className: 'bpmn-icon-participant',
|
||||||
|
title: translate('Create Pool/Participant'),
|
||||||
|
action: {
|
||||||
|
dragstart: createParticipant,
|
||||||
|
click: createParticipant,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'create.group': createAction(
|
||||||
|
'bpmn:Group',
|
||||||
|
'artifact',
|
||||||
|
'bpmn-icon-group',
|
||||||
|
translate('Create Group'),
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
return actions;
|
||||||
|
};
|
||||||
|
|
||||||
|
CustomPalette.$inject = [
|
||||||
|
'palette',
|
||||||
|
'create',
|
||||||
|
'elementFactory',
|
||||||
|
'spaceTool',
|
||||||
|
'lassoTool',
|
||||||
|
'handTool',
|
||||||
|
'globalConnect',
|
||||||
|
'translate',
|
||||||
|
];
|
||||||
|
|
||||||
|
CustomPalette.prototype = new F(); // 核心,将 F的实例赋值给子类;
|
||||||
|
CustomPalette.prototype.constructor = CustomPalette; // 修复子类CustomPalette的构造器指向,防止原型链的混乱;
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
// import PaletteModule from "diagram-js/lib/features/palette";
|
||||||
|
// import CreateModule from "diagram-js/lib/features/create";
|
||||||
|
// import SpaceToolModule from "diagram-js/lib/features/space-tool";
|
||||||
|
// import LassoToolModule from "diagram-js/lib/features/lasso-tool";
|
||||||
|
// import HandToolModule from "diagram-js/lib/features/hand-tool";
|
||||||
|
// import GlobalConnectModule from "diagram-js/lib/features/global-connect";
|
||||||
|
// import translate from "diagram-js/lib/i18n/translate";
|
||||||
|
//
|
||||||
|
// import PaletteProvider from "./paletteProvider";
|
||||||
|
//
|
||||||
|
// export default {
|
||||||
|
// __depends__: [PaletteModule, CreateModule, SpaceToolModule, LassoToolModule, HandToolModule, GlobalConnectModule, translate],
|
||||||
|
// __init__: ["paletteProvider"],
|
||||||
|
// paletteProvider: ["type", PaletteProvider]
|
||||||
|
// };
|
||||||
|
|
||||||
|
import CustomPalette from './CustomPalette';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
__init__: ['paletteProvider'],
|
||||||
|
paletteProvider: ['type', CustomPalette],
|
||||||
|
};
|
||||||
@@ -0,0 +1,219 @@
|
|||||||
|
import { assign } from 'min-dash';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A palette provider for BPMN 2.0 elements.
|
||||||
|
*/
|
||||||
|
export default function PaletteProvider(
|
||||||
|
palette,
|
||||||
|
create,
|
||||||
|
elementFactory,
|
||||||
|
spaceTool,
|
||||||
|
lassoTool,
|
||||||
|
handTool,
|
||||||
|
globalConnect,
|
||||||
|
translate,
|
||||||
|
) {
|
||||||
|
this._palette = palette;
|
||||||
|
this._create = create;
|
||||||
|
this._elementFactory = elementFactory;
|
||||||
|
this._spaceTool = spaceTool;
|
||||||
|
this._lassoTool = lassoTool;
|
||||||
|
this._handTool = handTool;
|
||||||
|
this._globalConnect = globalConnect;
|
||||||
|
this._translate = translate;
|
||||||
|
|
||||||
|
palette.registerProvider(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
PaletteProvider.$inject = [
|
||||||
|
'palette',
|
||||||
|
'create',
|
||||||
|
'elementFactory',
|
||||||
|
'spaceTool',
|
||||||
|
'lassoTool',
|
||||||
|
'handTool',
|
||||||
|
'globalConnect',
|
||||||
|
'translate',
|
||||||
|
];
|
||||||
|
|
||||||
|
PaletteProvider.prototype.getPaletteEntries = function () {
|
||||||
|
const actions = {};
|
||||||
|
const create = this._create;
|
||||||
|
const elementFactory = this._elementFactory;
|
||||||
|
const spaceTool = this._spaceTool;
|
||||||
|
const lassoTool = this._lassoTool;
|
||||||
|
const handTool = this._handTool;
|
||||||
|
const globalConnect = this._globalConnect;
|
||||||
|
const translate = this._translate;
|
||||||
|
|
||||||
|
function createAction(type, group, className, title, options) {
|
||||||
|
function createListener(event) {
|
||||||
|
const shape = elementFactory.createShape(assign({ type }, options));
|
||||||
|
|
||||||
|
if (options) {
|
||||||
|
shape.businessObject.di.isExpanded = options.isExpanded;
|
||||||
|
}
|
||||||
|
|
||||||
|
create.start(event, shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
const shortType = type.replace(/^bpmn:/, '');
|
||||||
|
|
||||||
|
return {
|
||||||
|
group,
|
||||||
|
className,
|
||||||
|
title: title || translate('Create {type}', { type: shortType }),
|
||||||
|
action: {
|
||||||
|
dragstart: createListener,
|
||||||
|
click: createListener,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createSubprocess(event) {
|
||||||
|
const subProcess = elementFactory.createShape({
|
||||||
|
type: 'bpmn:SubProcess',
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
isExpanded: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const startEvent = elementFactory.createShape({
|
||||||
|
type: 'bpmn:StartEvent',
|
||||||
|
x: 40,
|
||||||
|
y: 82,
|
||||||
|
parent: subProcess,
|
||||||
|
});
|
||||||
|
|
||||||
|
create.start(event, [subProcess, startEvent], {
|
||||||
|
hints: {
|
||||||
|
autoSelect: [startEvent],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function createParticipant(event) {
|
||||||
|
create.start(event, elementFactory.createParticipantShape());
|
||||||
|
}
|
||||||
|
|
||||||
|
assign(actions, {
|
||||||
|
'hand-tool': {
|
||||||
|
group: 'tools',
|
||||||
|
className: 'bpmn-icon-hand-tool',
|
||||||
|
title: translate('Activate the hand tool'),
|
||||||
|
action: {
|
||||||
|
click(event) {
|
||||||
|
handTool.activateHand(event);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'lasso-tool': {
|
||||||
|
group: 'tools',
|
||||||
|
className: 'bpmn-icon-lasso-tool',
|
||||||
|
title: translate('Activate the lasso tool'),
|
||||||
|
action: {
|
||||||
|
click(event) {
|
||||||
|
lassoTool.activateSelection(event);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'space-tool': {
|
||||||
|
group: 'tools',
|
||||||
|
className: 'bpmn-icon-space-tool',
|
||||||
|
title: translate('Activate the create/remove space tool'),
|
||||||
|
action: {
|
||||||
|
click(event) {
|
||||||
|
spaceTool.activateSelection(event);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'global-connect-tool': {
|
||||||
|
group: 'tools',
|
||||||
|
className: 'bpmn-icon-connection-multi',
|
||||||
|
title: translate('Activate the global connect tool'),
|
||||||
|
action: {
|
||||||
|
click(event) {
|
||||||
|
globalConnect.toggle(event);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'tool-separator': {
|
||||||
|
group: 'tools',
|
||||||
|
separator: true,
|
||||||
|
},
|
||||||
|
'create.start-event': createAction(
|
||||||
|
'bpmn:StartEvent',
|
||||||
|
'event',
|
||||||
|
'bpmn-icon-start-event-none',
|
||||||
|
translate('Create StartEvent'),
|
||||||
|
),
|
||||||
|
'create.intermediate-event': createAction(
|
||||||
|
'bpmn:IntermediateThrowEvent',
|
||||||
|
'event',
|
||||||
|
'bpmn-icon-intermediate-event-none',
|
||||||
|
translate('Create Intermediate/Boundary Event'),
|
||||||
|
),
|
||||||
|
'create.end-event': createAction(
|
||||||
|
'bpmn:EndEvent',
|
||||||
|
'event',
|
||||||
|
'bpmn-icon-end-event-none',
|
||||||
|
translate('Create EndEvent'),
|
||||||
|
),
|
||||||
|
'create.exclusive-gateway': createAction(
|
||||||
|
'bpmn:ExclusiveGateway',
|
||||||
|
'gateway',
|
||||||
|
'bpmn-icon-gateway-none',
|
||||||
|
translate('Create Gateway'),
|
||||||
|
),
|
||||||
|
'create.user-task': createAction(
|
||||||
|
'bpmn:UserTask',
|
||||||
|
'activity',
|
||||||
|
'bpmn-icon-user-task',
|
||||||
|
translate('Create User Task'),
|
||||||
|
),
|
||||||
|
'create.service-task': createAction(
|
||||||
|
'bpmn:ServiceTask',
|
||||||
|
'activity',
|
||||||
|
'bpmn-icon-service',
|
||||||
|
translate('Create Service Task'),
|
||||||
|
),
|
||||||
|
'create.data-object': createAction(
|
||||||
|
'bpmn:DataObjectReference',
|
||||||
|
'data-object',
|
||||||
|
'bpmn-icon-data-object',
|
||||||
|
translate('Create DataObjectReference'),
|
||||||
|
),
|
||||||
|
'create.data-store': createAction(
|
||||||
|
'bpmn:DataStoreReference',
|
||||||
|
'data-store',
|
||||||
|
'bpmn-icon-data-store',
|
||||||
|
translate('Create DataStoreReference'),
|
||||||
|
),
|
||||||
|
'create.subprocess-expanded': {
|
||||||
|
group: 'activity',
|
||||||
|
className: 'bpmn-icon-subprocess-expanded',
|
||||||
|
title: translate('Create expanded SubProcess'),
|
||||||
|
action: {
|
||||||
|
dragstart: createSubprocess,
|
||||||
|
click: createSubprocess,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'create.participant-expanded': {
|
||||||
|
group: 'collaboration',
|
||||||
|
className: 'bpmn-icon-participant',
|
||||||
|
title: translate('Create Pool/Participant'),
|
||||||
|
action: {
|
||||||
|
dragstart: createParticipant,
|
||||||
|
click: createParticipant,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'create.group': createAction(
|
||||||
|
'bpmn:Group',
|
||||||
|
'artifact',
|
||||||
|
'bpmn-icon-group',
|
||||||
|
translate('Create Group'),
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
return actions;
|
||||||
|
};
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
// import translations from "./zh";
|
||||||
|
//
|
||||||
|
// export default function customTranslate(template, replacements) {
|
||||||
|
// replacements = replacements || {};
|
||||||
|
//
|
||||||
|
// // Translate
|
||||||
|
// template = translations[template] || template;
|
||||||
|
//
|
||||||
|
// // Replace
|
||||||
|
// return template.replace(/{([^}]+)}/g, function(_, key) {
|
||||||
|
// let str = replacements[key];
|
||||||
|
// if (
|
||||||
|
// translations[replacements[key]] !== null &&
|
||||||
|
// translations[replacements[key]] !== "undefined"
|
||||||
|
// ) {
|
||||||
|
// // eslint-disable-next-line no-mixed-spaces-and-tabs
|
||||||
|
// str = translations[replacements[key]];
|
||||||
|
// // eslint-disable-next-line no-mixed-spaces-and-tabs
|
||||||
|
// }
|
||||||
|
// return str || "{" + key + "}";
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
export default function customTranslate(translations) {
|
||||||
|
return function (template, replacements) {
|
||||||
|
replacements = replacements || {};
|
||||||
|
// 将模板和翻译字典的键统一转换为小写进行匹配
|
||||||
|
const lowerTemplate = template.toLowerCase();
|
||||||
|
const translation = Object.keys(translations).find(
|
||||||
|
(key) => key.toLowerCase() === lowerTemplate,
|
||||||
|
);
|
||||||
|
|
||||||
|
// 如果找到匹配的翻译,使用翻译后的模板
|
||||||
|
if (translation) {
|
||||||
|
template = translations[translation];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 替换模板中的占位符
|
||||||
|
return template.replaceAll(/\{([^}]+)\}/g, (_, key) => {
|
||||||
|
// 如果替换值存在,返回替换值;否则返回原始占位符
|
||||||
|
return replacements[key] === undefined ? `{${key}}` : replacements[key];
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,246 @@
|
|||||||
|
/**
|
||||||
|
* This is a sample file that should be replaced with the actual translation.
|
||||||
|
*
|
||||||
|
* Checkout https://github.com/bpmn-io/bpmn-js-i18n for a list of available
|
||||||
|
* translations and labels to translate.
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
// 添加部分
|
||||||
|
'Append EndEvent': '追加结束事件',
|
||||||
|
'Append Gateway': '追加网关',
|
||||||
|
'Append Task': '追加任务',
|
||||||
|
'Append Intermediate/Boundary Event': '追加中间抛出事件/边界事件',
|
||||||
|
|
||||||
|
'Activate the global connect tool': '激活全局连接工具',
|
||||||
|
'Append {type}': '添加 {type}',
|
||||||
|
'Add Lane above': '在上面添加道',
|
||||||
|
'Divide into two Lanes': '分割成两个道',
|
||||||
|
'Divide into three Lanes': '分割成三个道',
|
||||||
|
'Add Lane below': '在下面添加道',
|
||||||
|
'Append compensation activity': '追加补偿活动',
|
||||||
|
'Change type': '修改类型',
|
||||||
|
'Connect using Association': '使用关联连接',
|
||||||
|
'Connect using Sequence/MessageFlow or Association':
|
||||||
|
'使用顺序/消息流或者关联连接',
|
||||||
|
'Connect using DataInputAssociation': '使用数据输入关联连接',
|
||||||
|
Remove: '移除',
|
||||||
|
'Activate the hand tool': '激活抓手工具',
|
||||||
|
'Activate the lasso tool': '激活套索工具',
|
||||||
|
'Activate the create/remove space tool': '激活创建/删除空间工具',
|
||||||
|
'Create expanded SubProcess': '创建扩展子过程',
|
||||||
|
'Create IntermediateThrowEvent/BoundaryEvent': '创建中间抛出事件/边界事件',
|
||||||
|
'Create Pool/Participant': '创建池/参与者',
|
||||||
|
'Parallel Multi Instance': '并行多重事件',
|
||||||
|
'Sequential Multi Instance': '时序多重事件',
|
||||||
|
DataObjectReference: '数据对象参考',
|
||||||
|
DataStoreReference: '数据存储参考',
|
||||||
|
Loop: '循环',
|
||||||
|
'Ad-hoc': '即席',
|
||||||
|
'Create {type}': '创建 {type}',
|
||||||
|
Task: '任务',
|
||||||
|
'Send Task': '发送任务',
|
||||||
|
'Receive Task': '接收任务',
|
||||||
|
'User Task': '用户任务',
|
||||||
|
'Manual Task': '手工任务',
|
||||||
|
'Business Rule Task': '业务规则任务',
|
||||||
|
'Service Task': '服务任务',
|
||||||
|
'Script Task': '脚本任务',
|
||||||
|
'Call Activity': '调用活动',
|
||||||
|
'Sub-Process (collapsed)': '子流程(折叠的)',
|
||||||
|
'Sub-Process (expanded)': '子流程(展开的)',
|
||||||
|
'Start Event': '开始事件',
|
||||||
|
StartEvent: '开始事件',
|
||||||
|
'Intermediate Throw Event': '中间事件',
|
||||||
|
'End Event': '结束事件',
|
||||||
|
EndEvent: '结束事件',
|
||||||
|
'Create StartEvent': '创建开始事件',
|
||||||
|
'Create EndEvent': '创建结束事件',
|
||||||
|
'Create Task': '创建任务',
|
||||||
|
'Create User Task': '创建用户任务',
|
||||||
|
'Create Call Activity': '创建调用活动',
|
||||||
|
'Create Service Task': '创建服务任务',
|
||||||
|
'Create Gateway': '创建网关',
|
||||||
|
'Create DataObjectReference': '创建数据对象',
|
||||||
|
'Create DataStoreReference': '创建数据存储',
|
||||||
|
'Create Group': '创建分组',
|
||||||
|
'Create Intermediate/Boundary Event': '创建中间/边界事件',
|
||||||
|
'Message Start Event': '消息开始事件',
|
||||||
|
'Timer Start Event': '定时开始事件',
|
||||||
|
'Conditional Start Event': '条件开始事件',
|
||||||
|
'Signal Start Event': '信号开始事件',
|
||||||
|
'Error Start Event': '错误开始事件',
|
||||||
|
'Escalation Start Event': '升级开始事件',
|
||||||
|
'Compensation Start Event': '补偿开始事件',
|
||||||
|
'Message Start Event (non-interrupting)': '消息开始事件(非中断)',
|
||||||
|
'Timer Start Event (non-interrupting)': '定时开始事件(非中断)',
|
||||||
|
'Conditional Start Event (non-interrupting)': '条件开始事件(非中断)',
|
||||||
|
'Signal Start Event (non-interrupting)': '信号开始事件(非中断)',
|
||||||
|
'Escalation Start Event (non-interrupting)': '升级开始事件(非中断)',
|
||||||
|
'Message Intermediate Catch Event': '消息中间捕获事件',
|
||||||
|
'Message Intermediate Throw Event': '消息中间抛出事件',
|
||||||
|
'Timer Intermediate Catch Event': '定时中间捕获事件',
|
||||||
|
'Escalation Intermediate Throw Event': '升级中间抛出事件',
|
||||||
|
'Conditional Intermediate Catch Event': '条件中间捕获事件',
|
||||||
|
'Link Intermediate Catch Event': '链接中间捕获事件',
|
||||||
|
'Link Intermediate Throw Event': '链接中间抛出事件',
|
||||||
|
'Compensation Intermediate Throw Event': '补偿中间抛出事件',
|
||||||
|
'Signal Intermediate Catch Event': '信号中间捕获事件',
|
||||||
|
'Signal Intermediate Throw Event': '信号中间抛出事件',
|
||||||
|
'Message End Event': '消息结束事件',
|
||||||
|
'Escalation End Event': '定时结束事件',
|
||||||
|
'Error End Event': '错误结束事件',
|
||||||
|
'Cancel End Event': '取消结束事件',
|
||||||
|
'Compensation End Event': '补偿结束事件',
|
||||||
|
'Signal End Event': '信号结束事件',
|
||||||
|
'Terminate End Event': '终止结束事件',
|
||||||
|
'Message Boundary Event': '消息边界事件',
|
||||||
|
'Message Boundary Event (non-interrupting)': '消息边界事件(非中断)',
|
||||||
|
'Timer Boundary Event': '定时边界事件',
|
||||||
|
'Timer Boundary Event (non-interrupting)': '定时边界事件(非中断)',
|
||||||
|
'Escalation Boundary Event': '升级边界事件',
|
||||||
|
'Escalation Boundary Event (non-interrupting)': '升级边界事件(非中断)',
|
||||||
|
'Conditional Boundary Event': '条件边界事件',
|
||||||
|
'Conditional Boundary Event (non-interrupting)': '条件边界事件(非中断)',
|
||||||
|
'Error Boundary Event': '错误边界事件',
|
||||||
|
'Cancel Boundary Event': '取消边界事件',
|
||||||
|
'Signal Boundary Event': '信号边界事件',
|
||||||
|
'Signal Boundary Event (non-interrupting)': '信号边界事件(非中断)',
|
||||||
|
'Compensation Boundary Event': '补偿边界事件',
|
||||||
|
'Exclusive Gateway': '互斥网关',
|
||||||
|
'Parallel Gateway': '并行网关',
|
||||||
|
'Inclusive Gateway': '相容网关',
|
||||||
|
'Complex Gateway': '复杂网关',
|
||||||
|
'Event based Gateway': '事件网关',
|
||||||
|
Transaction: '转运',
|
||||||
|
'Sub Process': '子流程',
|
||||||
|
'Event Sub Process': '事件子流程',
|
||||||
|
'Collapsed Pool': '折叠池',
|
||||||
|
'Expanded Pool': '展开池',
|
||||||
|
|
||||||
|
// Errors
|
||||||
|
'no parent for {element} in {parent}': '在{parent}里,{element}没有父类',
|
||||||
|
'no shape type specified': '没有指定的形状类型',
|
||||||
|
'flow elements must be children of pools/participants':
|
||||||
|
'流元素必须是池/参与者的子类',
|
||||||
|
'out of bounds release': 'out of bounds release',
|
||||||
|
'more than {count} child lanes': '子道大于{count} ',
|
||||||
|
'element required': '元素不能为空',
|
||||||
|
'diagram not part of bpmn:Definitions': '流程图不符合bpmn规范',
|
||||||
|
'no diagram to display': '没有可展示的流程图',
|
||||||
|
'no process or collaboration to display': '没有可展示的流程/协作',
|
||||||
|
'element {element} referenced by {referenced}#{property} not yet drawn':
|
||||||
|
'由{referenced}#{property}引用的{element}元素仍未绘制',
|
||||||
|
'already rendered {element}': '{element} 已被渲染',
|
||||||
|
'failed to import {element}': '导入{element}失败',
|
||||||
|
// 属性面板的参数
|
||||||
|
Id: '编号',
|
||||||
|
Name: '名称',
|
||||||
|
General: '常规',
|
||||||
|
Details: '详情',
|
||||||
|
'Message Name': '消息名称',
|
||||||
|
Message: '消息',
|
||||||
|
Initiator: '创建者',
|
||||||
|
'Asynchronous Continuations': '持续异步',
|
||||||
|
'Asynchronous Before': '异步前',
|
||||||
|
'Asynchronous After': '异步后',
|
||||||
|
'Job Configuration': '工作配置',
|
||||||
|
Exclusive: '排除',
|
||||||
|
'Job Priority': '工作优先级',
|
||||||
|
'Retry Time Cycle': '重试时间周期',
|
||||||
|
Documentation: '文档',
|
||||||
|
'Element Documentation': '元素文档',
|
||||||
|
'History Configuration': '历史配置',
|
||||||
|
'History Time To Live': '历史的生存时间',
|
||||||
|
Forms: '表单',
|
||||||
|
'Form Key': '表单key',
|
||||||
|
'Form Fields': '表单字段',
|
||||||
|
'Business Key': '业务key',
|
||||||
|
'Form Field': '表单字段',
|
||||||
|
ID: '编号',
|
||||||
|
Type: '类型',
|
||||||
|
Label: '名称',
|
||||||
|
'Default Value': '默认值',
|
||||||
|
'Default Flow': '默认流转路径',
|
||||||
|
'Conditional Flow': '条件流转路径',
|
||||||
|
'Sequence Flow': '普通流转路径',
|
||||||
|
Validation: '校验',
|
||||||
|
'Add Constraint': '添加约束',
|
||||||
|
Config: '配置',
|
||||||
|
Properties: '属性',
|
||||||
|
'Add Property': '添加属性',
|
||||||
|
Value: '值',
|
||||||
|
Listeners: '监听器',
|
||||||
|
'Execution Listener': '执行监听',
|
||||||
|
'Event Type': '事件类型',
|
||||||
|
'Listener Type': '监听器类型',
|
||||||
|
'Java Class': 'Java类',
|
||||||
|
Expression: '表达式',
|
||||||
|
'Must provide a value': '必须提供一个值',
|
||||||
|
'Delegate Expression': '代理表达式',
|
||||||
|
Script: '脚本',
|
||||||
|
'Script Format': '脚本格式',
|
||||||
|
'Script Type': '脚本类型',
|
||||||
|
'Inline Script': '内联脚本',
|
||||||
|
'External Script': '外部脚本',
|
||||||
|
Resource: '资源',
|
||||||
|
'Field Injection': '字段注入',
|
||||||
|
Extensions: '扩展',
|
||||||
|
'Input/Output': '输入/输出',
|
||||||
|
'Input Parameters': '输入参数',
|
||||||
|
'Output Parameters': '输出参数',
|
||||||
|
Parameters: '参数',
|
||||||
|
'Output Parameter': '输出参数',
|
||||||
|
'Timer Definition Type': '定时器定义类型',
|
||||||
|
'Timer Definition': '定时器定义',
|
||||||
|
Date: '日期',
|
||||||
|
Duration: '持续',
|
||||||
|
Cycle: '循环',
|
||||||
|
Signal: '信号',
|
||||||
|
'Signal Name': '信号名称',
|
||||||
|
Escalation: '升级',
|
||||||
|
Error: '错误',
|
||||||
|
'Link Name': '链接名称',
|
||||||
|
Condition: '条件名称',
|
||||||
|
'Variable Name': '变量名称',
|
||||||
|
'Variable Event': '变量事件',
|
||||||
|
'Specify more than one variable change event as a comma separated list.':
|
||||||
|
'多个变量事件以逗号隔开',
|
||||||
|
'Wait for Completion': '等待完成',
|
||||||
|
'Activity Ref': '活动参考',
|
||||||
|
'Version Tag': '版本标签',
|
||||||
|
Executable: '可执行文件',
|
||||||
|
'External Task Configuration': '扩展任务配置',
|
||||||
|
'Task Priority': '任务优先级',
|
||||||
|
External: '外部',
|
||||||
|
Connector: '连接器',
|
||||||
|
'Must configure Connector': '必须配置连接器',
|
||||||
|
'Connector Id': '连接器编号',
|
||||||
|
Implementation: '实现方式',
|
||||||
|
'Field Injections': '字段注入',
|
||||||
|
Fields: '字段',
|
||||||
|
'Result Variable': '结果变量',
|
||||||
|
Topic: '主题',
|
||||||
|
'Configure Connector': '配置连接器',
|
||||||
|
'Input Parameter': '输入参数',
|
||||||
|
Assignee: '代理人',
|
||||||
|
'Candidate Users': '候选用户',
|
||||||
|
'Candidate Groups': '候选组',
|
||||||
|
'Due Date': '到期时间',
|
||||||
|
'Follow Up Date': '跟踪日期',
|
||||||
|
Priority: '优先级',
|
||||||
|
'The follow up date as an EL expression (e.g. ${someDate} or an ISO date (e.g. 2015-06-26T09:54:00)':
|
||||||
|
'跟踪日期必须符合EL表达式,如: ${someDate} ,或者一个ISO标准日期,如:2015-06-26T09:54:00',
|
||||||
|
'The due date as an EL expression (e.g. ${someDate} or an ISO date (e.g. 2015-06-26T09:54:00)':
|
||||||
|
'跟踪日期必须符合EL表达式,如: ${someDate} ,或者一个ISO标准日期,如:2015-06-26T09:54:00',
|
||||||
|
Variables: '变量',
|
||||||
|
'Candidate Starter Configuration': '候选人起动器配置',
|
||||||
|
'Candidate Starter Groups': '候选人起动器组',
|
||||||
|
'This maps to the process definition key.': '这映射到流程定义键。',
|
||||||
|
'Candidate Starter Users': '候选人起动器的用户',
|
||||||
|
'Specify more than one user as a comma separated list.':
|
||||||
|
'指定多个用户作为逗号分隔的列表。',
|
||||||
|
'Tasklist Configuration': 'Tasklist配置',
|
||||||
|
Startable: '启动',
|
||||||
|
'Specify more than one group as a comma separated list.':
|
||||||
|
'指定多个组作为逗号分隔的列表。',
|
||||||
|
};
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import './theme/index.scss';
|
||||||
|
import 'bpmn-js/dist/assets/diagram-js.css';
|
||||||
|
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css';
|
||||||
|
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css';
|
||||||
|
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css';
|
||||||
|
|
||||||
|
export { default as MyProcessDesigner } from './designer';
|
||||||
|
export { default as MyProcessViewer } from './designer/index2';
|
||||||
|
export { default as MyProcessPenal } from './penal';
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
<template>
|
||||||
|
<div class="my-process-palette">
|
||||||
|
<div class="test-button" @click="addTask" @mousedown="addTask">
|
||||||
|
测试任务
|
||||||
|
</div>
|
||||||
|
<div class="test-container" id="palette-container">1</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { assign } from 'min-dash';
|
||||||
|
|
||||||
|
defineOptions({ name: 'MyProcessPalette' });
|
||||||
|
|
||||||
|
const bpmnInstances = () => (window as any).bpmnInstances;
|
||||||
|
const addTask = (event, options: any = {}) => {
|
||||||
|
const ElementFactory = bpmnInstances().elementFactory;
|
||||||
|
const create = bpmnInstances().modeler.get('create');
|
||||||
|
|
||||||
|
console.log(ElementFactory, create);
|
||||||
|
|
||||||
|
const shape = ElementFactory.createShape(
|
||||||
|
assign({ type: 'bpmn:UserTask' }, options),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (options) {
|
||||||
|
shape.businessObject.di.isExpanded = options.isExpanded;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(event, 'event');
|
||||||
|
console.log(shape, 'shape');
|
||||||
|
create.start(event, shape);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.my-process-palette {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 80px 20px 20px;
|
||||||
|
|
||||||
|
.test-button {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 8px 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 1px solid rgb(24 144 255 / 80%);
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,358 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="process-panel__container"
|
||||||
|
:style="{ width: `${width}px`, maxHeight: '600px' }"
|
||||||
|
>
|
||||||
|
<el-collapse v-model="activeTab" v-if="isReady">
|
||||||
|
<el-collapse-item name="base">
|
||||||
|
<!-- class="panel-tab__title" -->
|
||||||
|
<template #title>
|
||||||
|
<Icon icon="ep:info-filled" />
|
||||||
|
常规</template
|
||||||
|
>
|
||||||
|
<ElementBaseInfo
|
||||||
|
:id-edit-disabled="idEditDisabled"
|
||||||
|
:business-object="elementBusinessObject"
|
||||||
|
:type="elementType"
|
||||||
|
:model="model"
|
||||||
|
/>
|
||||||
|
</el-collapse-item>
|
||||||
|
<el-collapse-item
|
||||||
|
name="condition"
|
||||||
|
v-if="elementType === 'Process'"
|
||||||
|
key="message"
|
||||||
|
>
|
||||||
|
<template #title><Icon icon="ep:comment" />消息与信号</template>
|
||||||
|
<signal-and-massage />
|
||||||
|
</el-collapse-item>
|
||||||
|
<el-collapse-item
|
||||||
|
name="condition"
|
||||||
|
v-if="conditionFormVisible"
|
||||||
|
key="condition"
|
||||||
|
>
|
||||||
|
<template #title><Icon icon="ep:promotion" />流转条件</template>
|
||||||
|
<flow-condition
|
||||||
|
:business-object="elementBusinessObject"
|
||||||
|
:type="elementType"
|
||||||
|
/>
|
||||||
|
</el-collapse-item>
|
||||||
|
<el-collapse-item name="condition" v-if="formVisible" key="form">
|
||||||
|
<template #title><Icon icon="ep:list" />表单</template>
|
||||||
|
<element-form :id="elementId" :type="elementType" />
|
||||||
|
</el-collapse-item>
|
||||||
|
<el-collapse-item
|
||||||
|
name="task"
|
||||||
|
v-if="isTaskCollapseItemShow(elementType)"
|
||||||
|
key="task"
|
||||||
|
>
|
||||||
|
<template #title
|
||||||
|
><Icon icon="ep:checked" />{{
|
||||||
|
getTaskCollapseItemName(elementType)
|
||||||
|
}}</template
|
||||||
|
>
|
||||||
|
<element-task :id="elementId" :type="elementType" />
|
||||||
|
</el-collapse-item>
|
||||||
|
<el-collapse-item
|
||||||
|
name="multiInstance"
|
||||||
|
v-if="elementType.indexOf('Task') !== -1"
|
||||||
|
key="multiInstance"
|
||||||
|
>
|
||||||
|
<template #title><Icon icon="ep:help-filled" />多人审批方式</template>
|
||||||
|
<element-multi-instance
|
||||||
|
:id="elementId"
|
||||||
|
:business-object="elementBusinessObject"
|
||||||
|
:type="elementType"
|
||||||
|
/>
|
||||||
|
</el-collapse-item>
|
||||||
|
<el-collapse-item name="listeners" key="listeners">
|
||||||
|
<template #title><Icon icon="ep:bell-filled" />执行监听器</template>
|
||||||
|
<element-listeners :id="elementId" :type="elementType" />
|
||||||
|
</el-collapse-item>
|
||||||
|
<el-collapse-item
|
||||||
|
name="taskListeners"
|
||||||
|
v-if="elementType === 'UserTask'"
|
||||||
|
key="taskListeners"
|
||||||
|
>
|
||||||
|
<template #title><Icon icon="ep:bell-filled" />任务监听器</template>
|
||||||
|
<user-task-listeners :id="elementId" :type="elementType" />
|
||||||
|
</el-collapse-item>
|
||||||
|
<el-collapse-item name="extensions" key="extensions">
|
||||||
|
<template #title
|
||||||
|
><Icon icon="ep:circle-plus-filled" />扩展属性</template
|
||||||
|
>
|
||||||
|
<element-properties :id="elementId" :type="elementType" />
|
||||||
|
</el-collapse-item>
|
||||||
|
<el-collapse-item name="other" key="other">
|
||||||
|
<template #title><Icon icon="ep:promotion" />其他</template>
|
||||||
|
<element-other-config :id="elementId" />
|
||||||
|
</el-collapse-item>
|
||||||
|
<el-collapse-item name="customConfig" key="customConfig">
|
||||||
|
<template #title><Icon icon="ep:tools" />自定义配置</template>
|
||||||
|
<element-custom-config
|
||||||
|
:id="elementId"
|
||||||
|
:type="elementType"
|
||||||
|
:business-object="elementBusinessObject"
|
||||||
|
/>
|
||||||
|
</el-collapse-item>
|
||||||
|
<!-- 新增的时间事件配置项 -->
|
||||||
|
<el-collapse-item
|
||||||
|
v-if="elementType === 'IntermediateCatchEvent'"
|
||||||
|
name="timeEvent"
|
||||||
|
>
|
||||||
|
<template #title><Icon icon="ep:timer" />时间事件</template>
|
||||||
|
<TimeEventConfig
|
||||||
|
:businessObject="bpmnElement.value?.businessObject"
|
||||||
|
:key="elementId"
|
||||||
|
/>
|
||||||
|
</el-collapse-item>
|
||||||
|
</el-collapse>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import ElementBaseInfo from './base/ElementBaseInfo.vue';
|
||||||
|
import ElementOtherConfig from './other/ElementOtherConfig.vue';
|
||||||
|
import ElementTask from './task/ElementTask.vue';
|
||||||
|
import ElementMultiInstance from './multi-instance/ElementMultiInstance.vue';
|
||||||
|
import FlowCondition from './flow-condition/FlowCondition.vue';
|
||||||
|
import SignalAndMassage from './signal-message/SignalAndMessage.vue';
|
||||||
|
import ElementListeners from './listeners/ElementListeners.vue';
|
||||||
|
import ElementProperties from './properties/ElementProperties.vue';
|
||||||
|
// import ElementForm from './form/ElementForm.vue'
|
||||||
|
import UserTaskListeners from './listeners/UserTaskListeners.vue';
|
||||||
|
import { getTaskCollapseItemName, isTaskCollapseItemShow } from './task/data';
|
||||||
|
import TimeEventConfig from './time-event-config/TimeEventConfig.vue';
|
||||||
|
import { ref, watch, onMounted } from 'vue';
|
||||||
|
|
||||||
|
defineOptions({ name: 'MyPropertiesPanel' });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 侧边栏
|
||||||
|
* @Author MiyueFE
|
||||||
|
* @Home https://github.com/miyuesc
|
||||||
|
* @Date 2021年3月31日18:57:51
|
||||||
|
*/
|
||||||
|
const props = defineProps({
|
||||||
|
bpmnModeler: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
prefix: {
|
||||||
|
type: String,
|
||||||
|
default: 'camunda',
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: Number,
|
||||||
|
default: 480,
|
||||||
|
},
|
||||||
|
idEditDisabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
model: Object, // 流程模型的数据
|
||||||
|
});
|
||||||
|
|
||||||
|
const activeTab = ref('base');
|
||||||
|
const elementId = ref('');
|
||||||
|
const elementType = ref('');
|
||||||
|
const elementBusinessObject = ref<any>({}); // 元素 businessObject 镜像,提供给需要做判断的组件使用
|
||||||
|
const conditionFormVisible = ref(false); // 流转条件设置
|
||||||
|
const formVisible = ref(false); // 表单配置
|
||||||
|
const bpmnElement = ref();
|
||||||
|
const isReady = ref(false);
|
||||||
|
|
||||||
|
const type = ref('time');
|
||||||
|
const condition = ref('');
|
||||||
|
provide('prefix', props.prefix);
|
||||||
|
provide('width', props.width);
|
||||||
|
|
||||||
|
// 初始化 bpmnInstances
|
||||||
|
const initBpmnInstances = () => {
|
||||||
|
if (!props.bpmnModeler) return false;
|
||||||
|
try {
|
||||||
|
const instances = {
|
||||||
|
modeler: props.bpmnModeler,
|
||||||
|
modeling: props.bpmnModeler.get('modeling'),
|
||||||
|
moddle: props.bpmnModeler.get('moddle'),
|
||||||
|
eventBus: props.bpmnModeler.get('eventBus'),
|
||||||
|
bpmnFactory: props.bpmnModeler.get('bpmnFactory'),
|
||||||
|
elementFactory: props.bpmnModeler.get('elementFactory'),
|
||||||
|
elementRegistry: props.bpmnModeler.get('elementRegistry'),
|
||||||
|
replace: props.bpmnModeler.get('replace'),
|
||||||
|
selection: props.bpmnModeler.get('selection'),
|
||||||
|
};
|
||||||
|
|
||||||
|
// 检查所有实例是否都存在
|
||||||
|
const allInstancesExist = Object.values(instances).every(
|
||||||
|
(instance) => instance,
|
||||||
|
);
|
||||||
|
if (allInstancesExist) {
|
||||||
|
const w = window as any;
|
||||||
|
w.bpmnInstances = instances;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('初始化 bpmnInstances 失败:', error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const bpmnInstances = () => (window as any)?.bpmnInstances;
|
||||||
|
|
||||||
|
// 监听 props.bpmnModeler 然后 initModels
|
||||||
|
const unwatchBpmn = watch(
|
||||||
|
() => props.bpmnModeler,
|
||||||
|
async () => {
|
||||||
|
// 避免加载时 流程图 并未加载完成
|
||||||
|
if (!props.bpmnModeler) {
|
||||||
|
console.log('缺少props.bpmnModeler');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 等待 modeler 初始化完成
|
||||||
|
await nextTick();
|
||||||
|
if (initBpmnInstances()) {
|
||||||
|
isReady.value = true;
|
||||||
|
await nextTick();
|
||||||
|
getActiveElement();
|
||||||
|
} else {
|
||||||
|
console.error('modeler 实例未完全初始化');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('初始化失败:', error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const getActiveElement = () => {
|
||||||
|
if (!isReady.value || !props.bpmnModeler) return;
|
||||||
|
|
||||||
|
// 初始第一个选中元素 bpmn:Process
|
||||||
|
initFormOnChanged(null);
|
||||||
|
props.bpmnModeler.on('import.done', (e) => {
|
||||||
|
console.log(e, 'eeeee');
|
||||||
|
initFormOnChanged(null);
|
||||||
|
});
|
||||||
|
// 监听选择事件,修改当前激活的元素以及表单
|
||||||
|
props.bpmnModeler.on('selection.changed', ({ newSelection }) => {
|
||||||
|
initFormOnChanged(newSelection[0] || null);
|
||||||
|
});
|
||||||
|
props.bpmnModeler.on('element.changed', ({ element }) => {
|
||||||
|
// 保证 修改 "默认流转路径" 类似需要修改多个元素的事件发生的时候,更新表单的元素与原选中元素不一致。
|
||||||
|
if (element && element.id === elementId.value) {
|
||||||
|
initFormOnChanged(element);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 初始化数据
|
||||||
|
const initFormOnChanged = (element) => {
|
||||||
|
if (!isReady.value || !bpmnInstances()) return;
|
||||||
|
|
||||||
|
let activatedElement = element;
|
||||||
|
if (!activatedElement) {
|
||||||
|
activatedElement =
|
||||||
|
bpmnInstances().elementRegistry.find(
|
||||||
|
(el) => el.type === 'bpmn:Process',
|
||||||
|
) ??
|
||||||
|
bpmnInstances().elementRegistry.find(
|
||||||
|
(el) => el.type === 'bpmn:Collaboration',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (!activatedElement) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log(`
|
||||||
|
----------
|
||||||
|
select element changed:
|
||||||
|
id: ${activatedElement.id}
|
||||||
|
type: ${activatedElement.businessObject.$type}
|
||||||
|
----------
|
||||||
|
`);
|
||||||
|
console.log('businessObject: ', activatedElement.businessObject);
|
||||||
|
bpmnInstances().bpmnElement = activatedElement;
|
||||||
|
bpmnElement.value = activatedElement;
|
||||||
|
elementId.value = activatedElement.id;
|
||||||
|
elementType.value = activatedElement.type.split(':')[1] || '';
|
||||||
|
elementBusinessObject.value = JSON.parse(
|
||||||
|
JSON.stringify(activatedElement.businessObject),
|
||||||
|
);
|
||||||
|
conditionFormVisible.value = !!(
|
||||||
|
elementType.value === 'SequenceFlow' &&
|
||||||
|
activatedElement.source &&
|
||||||
|
activatedElement.source.type.indexOf('StartEvent') === -1
|
||||||
|
);
|
||||||
|
formVisible.value =
|
||||||
|
elementType.value === 'UserTask' || elementType.value === 'StartEvent';
|
||||||
|
} catch (error) {
|
||||||
|
console.error('初始化表单数据失败:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
const w = window as any;
|
||||||
|
w.bpmnInstances = null;
|
||||||
|
isReady.value = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => elementId.value,
|
||||||
|
() => {
|
||||||
|
activeTab.value = 'base';
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
function updateNode() {
|
||||||
|
const moddle = window.bpmnInstances?.moddle;
|
||||||
|
const modeling = window.bpmnInstances?.modeling;
|
||||||
|
const elementRegistry = window.bpmnInstances?.elementRegistry;
|
||||||
|
if (!moddle || !modeling || !elementRegistry) return;
|
||||||
|
|
||||||
|
const element = elementRegistry.get(props.businessObject.id);
|
||||||
|
if (!element) return;
|
||||||
|
|
||||||
|
let timerDef = moddle.create('bpmn:TimerEventDefinition', {});
|
||||||
|
if (type.value === 'time') {
|
||||||
|
timerDef.timeDate = moddle.create('bpmn:FormalExpression', {
|
||||||
|
body: condition.value,
|
||||||
|
});
|
||||||
|
} else if (type.value === 'duration') {
|
||||||
|
timerDef.timeDuration = moddle.create('bpmn:FormalExpression', {
|
||||||
|
body: condition.value,
|
||||||
|
});
|
||||||
|
} else if (type.value === 'cycle') {
|
||||||
|
timerDef.timeCycle = moddle.create('bpmn:FormalExpression', {
|
||||||
|
body: condition.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
modeling.updateModdleProperties(element, element.businessObject, {
|
||||||
|
eventDefinitions: [timerDef],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化和监听
|
||||||
|
function syncFromBusinessObject() {
|
||||||
|
if (props.businessObject) {
|
||||||
|
const timerDef = (props.businessObject.eventDefinitions || [])[0];
|
||||||
|
if (timerDef) {
|
||||||
|
if (timerDef.timeDate) {
|
||||||
|
type.value = 'time';
|
||||||
|
condition.value = timerDef.timeDate.body;
|
||||||
|
} else if (timerDef.timeDuration) {
|
||||||
|
type.value = 'duration';
|
||||||
|
condition.value = timerDef.timeDuration.body;
|
||||||
|
} else if (timerDef.timeCycle) {
|
||||||
|
type.value = 'cycle';
|
||||||
|
condition.value = timerDef.timeCycle.body;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onMounted(syncFromBusinessObject);
|
||||||
|
watch(() => props.businessObject, syncFromBusinessObject, { deep: true });
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,194 @@
|
|||||||
|
<template>
|
||||||
|
<div class="panel-tab__content">
|
||||||
|
<el-form label-width="90px" :model="needProps" :rules="rules">
|
||||||
|
<div v-if="needProps.type == 'bpmn:Process'">
|
||||||
|
<!-- 如果是 Process 信息的时候,使用自定义表单 -->
|
||||||
|
<el-form-item label="流程标识" prop="id">
|
||||||
|
<el-input
|
||||||
|
v-model="needProps.id"
|
||||||
|
placeholder="请输入流标标识"
|
||||||
|
:disabled="needProps.id !== undefined && needProps.id.length > 0"
|
||||||
|
@change="handleKeyUpdate"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="流程名称" prop="name">
|
||||||
|
<el-input
|
||||||
|
v-model="needProps.name"
|
||||||
|
placeholder="请输入流程名称"
|
||||||
|
clearable
|
||||||
|
@change="handleNameUpdate"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<el-form-item label="ID">
|
||||||
|
<el-input
|
||||||
|
v-model="elementBaseInfo.id"
|
||||||
|
clearable
|
||||||
|
@change="updateBaseInfo('id')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="名称">
|
||||||
|
<el-input
|
||||||
|
v-model="elementBaseInfo.name"
|
||||||
|
clearable
|
||||||
|
@change="updateBaseInfo('name')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
defineOptions({ name: 'ElementBaseInfo' });
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
businessObject: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
model: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const needProps = ref<any>({});
|
||||||
|
const bpmnElement = ref();
|
||||||
|
const elementBaseInfo = ref<any>({});
|
||||||
|
// 流程表单的下拉框的数据
|
||||||
|
// const forms = ref([])
|
||||||
|
// 流程模型的校验
|
||||||
|
const rules = reactive({
|
||||||
|
id: [{ required: true, message: '流程标识不能为空', trigger: 'blur' }],
|
||||||
|
name: [{ required: true, message: '流程名称不能为空', trigger: 'blur' }],
|
||||||
|
});
|
||||||
|
|
||||||
|
const bpmnInstances = () => (window as any)?.bpmnInstances;
|
||||||
|
const resetBaseInfo = () => {
|
||||||
|
console.log(window, 'window');
|
||||||
|
console.log(bpmnElement.value, 'bpmnElement');
|
||||||
|
|
||||||
|
bpmnElement.value = bpmnInstances()?.bpmnElement;
|
||||||
|
// console.log(bpmnElement.value, 'resetBaseInfo11111111111')
|
||||||
|
elementBaseInfo.value = bpmnElement.value.businessObject;
|
||||||
|
needProps.value['type'] = bpmnElement.value.businessObject.$type;
|
||||||
|
// elementBaseInfo.value['typess'] = bpmnElement.value.businessObject.$type
|
||||||
|
|
||||||
|
// elementBaseInfo.value = JSON.parse(JSON.stringify(bpmnElement.value.businessObject))
|
||||||
|
// console.log(elementBaseInfo.value, 'elementBaseInfo22222222222')
|
||||||
|
};
|
||||||
|
const handleKeyUpdate = (value) => {
|
||||||
|
// 校验 value 的值,只有 XML NCName 通过的情况下,才进行赋值。否则,会导致流程图报错,无法绘制的问题
|
||||||
|
if (!value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!value.match(/[a-zA-Z_][\-_.0-9a-zA-Z$]*/)) {
|
||||||
|
console.log('key 不满足 XML NCName 规则,所以不进行赋值');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log('key 满足 XML NCName 规则,所以进行赋值');
|
||||||
|
|
||||||
|
// 在 BPMN 的 XML 中,流程标识 key,其实对应的是 id 节点
|
||||||
|
elementBaseInfo.value['id'] = value;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
updateBaseInfo('id');
|
||||||
|
}, 100);
|
||||||
|
};
|
||||||
|
const handleNameUpdate = (value) => {
|
||||||
|
console.log(elementBaseInfo, 'elementBaseInfo');
|
||||||
|
if (!value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
elementBaseInfo.value['name'] = value;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
updateBaseInfo('name');
|
||||||
|
}, 100);
|
||||||
|
};
|
||||||
|
// const handleDescriptionUpdate=(value)=> {
|
||||||
|
// TODO 芋艿:documentation 暂时无法修改,后续在看看
|
||||||
|
// this.elementBaseInfo['documentation'] = value;
|
||||||
|
// this.updateBaseInfo('documentation');
|
||||||
|
// }
|
||||||
|
const updateBaseInfo = (key) => {
|
||||||
|
console.log(key, 'key');
|
||||||
|
// 触发 elementBaseInfo 对应的字段
|
||||||
|
const attrObj = Object.create(null);
|
||||||
|
// console.log(attrObj, 'attrObj')
|
||||||
|
attrObj[key] = elementBaseInfo.value[key];
|
||||||
|
// console.log(attrObj, 'attrObj111')
|
||||||
|
// const attrObj = {
|
||||||
|
// id: elementBaseInfo.value[key]
|
||||||
|
// // di: { id: `${elementBaseInfo.value[key]}_di` }
|
||||||
|
// }
|
||||||
|
// console.log(elementBaseInfo, 'elementBaseInfo11111111111')
|
||||||
|
needProps.value = { ...elementBaseInfo.value, ...needProps.value };
|
||||||
|
|
||||||
|
if (key === 'id') {
|
||||||
|
// console.log('jinru')
|
||||||
|
console.log(window, 'window');
|
||||||
|
console.log(bpmnElement.value, 'bpmnElement');
|
||||||
|
console.log(toRaw(bpmnElement.value), 'bpmnElement');
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
|
id: elementBaseInfo.value[key],
|
||||||
|
di: { id: `${elementBaseInfo.value[key]}_di` },
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log(attrObj, 'attrObj');
|
||||||
|
bpmnInstances().modeling.updateProperties(
|
||||||
|
toRaw(bpmnElement.value),
|
||||||
|
attrObj,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.businessObject,
|
||||||
|
(val) => {
|
||||||
|
// console.log(val, 'val11111111111111111111')
|
||||||
|
if (val) {
|
||||||
|
// nextTick(() => {
|
||||||
|
resetBaseInfo();
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.model?.key,
|
||||||
|
(val) => {
|
||||||
|
// 针对上传的 bpmn 流程图时,保证 key 和 name 的更新
|
||||||
|
if (val) {
|
||||||
|
handleKeyUpdate(props.model.key);
|
||||||
|
handleNameUpdate(props.model.name);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// watch(
|
||||||
|
// () => ({ ...props }),
|
||||||
|
// (oldVal, newVal) => {
|
||||||
|
// console.log(oldVal, 'oldVal')
|
||||||
|
// console.log(newVal, 'newVal')
|
||||||
|
// if (newVal) {
|
||||||
|
// needProps.value = newVal
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// immediate: true
|
||||||
|
// }
|
||||||
|
// )
|
||||||
|
// 'model.key': {
|
||||||
|
// immediate: false,
|
||||||
|
// handler: function (val) {
|
||||||
|
// this.handleKeyUpdate(val)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
bpmnElement.value = null;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<template>
|
||||||
|
<div class="panel-tab__content">
|
||||||
|
<component :is="customConfigComponent" v-bind="$props" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { CustomConfigMap } from './data';
|
||||||
|
|
||||||
|
defineOptions({ name: 'ElementCustomConfig' });
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
id: String,
|
||||||
|
type: String,
|
||||||
|
businessObject: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const bpmnInstances = () => (window as any)?.bpmnInstances;
|
||||||
|
const customConfigComponent = ref<any>(null);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.businessObject,
|
||||||
|
() => {
|
||||||
|
if (props.type && props.businessObject) {
|
||||||
|
let val = props.type;
|
||||||
|
if (props.businessObject.eventDefinitions) {
|
||||||
|
val +=
|
||||||
|
props.businessObject.eventDefinitions[0]?.$type.split(':')[1] || '';
|
||||||
|
}
|
||||||
|
customConfigComponent.value = CustomConfigMap[val]?.componet;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
@@ -0,0 +1,286 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-divider content-position="left">审批人超时未处理时</el-divider>
|
||||||
|
<el-form-item label="启用开关" prop="timeoutHandlerEnable">
|
||||||
|
<el-switch
|
||||||
|
v-model="timeoutHandlerEnable"
|
||||||
|
active-text="开启"
|
||||||
|
inactive-text="关闭"
|
||||||
|
@change="timeoutHandlerChange"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
label="执行动作"
|
||||||
|
prop="timeoutHandlerType"
|
||||||
|
v-if="timeoutHandlerEnable"
|
||||||
|
>
|
||||||
|
<el-radio-group
|
||||||
|
v-model="timeoutHandlerType.value"
|
||||||
|
@change="onTimeoutHandlerTypeChanged"
|
||||||
|
>
|
||||||
|
<el-radio-button
|
||||||
|
v-for="item in TIMEOUT_HANDLER_TYPES"
|
||||||
|
:key="item.value"
|
||||||
|
:value="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
/>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="超时时间设置" v-if="timeoutHandlerEnable">
|
||||||
|
<span class="mr-2">当超过</span>
|
||||||
|
<el-form-item prop="timeDuration">
|
||||||
|
<el-input-number
|
||||||
|
class="mr-2"
|
||||||
|
:style="{ width: '100px' }"
|
||||||
|
v-model="timeDuration"
|
||||||
|
:min="1"
|
||||||
|
controls-position="right"
|
||||||
|
@change="
|
||||||
|
() => {
|
||||||
|
updateTimeModdle();
|
||||||
|
updateElementExtensions();
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-select
|
||||||
|
v-model="timeUnit"
|
||||||
|
class="mr-2"
|
||||||
|
:style="{ width: '100px' }"
|
||||||
|
@change="onTimeUnitChange"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in TIME_UNIT_TYPES"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
未处理
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
label="最大提醒次数"
|
||||||
|
prop="maxRemindCount"
|
||||||
|
v-if="timeoutHandlerEnable && timeoutHandlerType.value === 1"
|
||||||
|
>
|
||||||
|
<el-input-number
|
||||||
|
v-model="maxRemindCount"
|
||||||
|
:min="1"
|
||||||
|
:max="10"
|
||||||
|
@change="
|
||||||
|
() => {
|
||||||
|
updateTimeModdle();
|
||||||
|
updateElementExtensions();
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import {
|
||||||
|
TimeUnitType,
|
||||||
|
TIME_UNIT_TYPES,
|
||||||
|
TIMEOUT_HANDLER_TYPES,
|
||||||
|
} from '@/components/SimpleProcessDesignerV2/src/consts';
|
||||||
|
import { convertTimeUnit } from '@/components/SimpleProcessDesignerV2/src/utils';
|
||||||
|
|
||||||
|
defineOptions({ name: 'ElementCustomConfig4BoundaryEventTimer' });
|
||||||
|
const props = defineProps({
|
||||||
|
id: String,
|
||||||
|
type: String,
|
||||||
|
});
|
||||||
|
const prefix = inject('prefix');
|
||||||
|
|
||||||
|
const bpmnElement = ref();
|
||||||
|
const bpmnInstances = () => (window as any)?.bpmnInstances;
|
||||||
|
|
||||||
|
const timeoutHandlerEnable = ref(false);
|
||||||
|
const boundaryEventType = ref();
|
||||||
|
const timeoutHandlerType = ref({
|
||||||
|
value: undefined,
|
||||||
|
});
|
||||||
|
const timeModdle = ref();
|
||||||
|
const timeDuration = ref(6);
|
||||||
|
const timeUnit = ref(TimeUnitType.HOUR);
|
||||||
|
const maxRemindCount = ref(1);
|
||||||
|
|
||||||
|
const elExtensionElements = ref();
|
||||||
|
const otherExtensions = ref();
|
||||||
|
const configExtensions = ref([]);
|
||||||
|
const eventDefinition = ref();
|
||||||
|
|
||||||
|
const resetElement = () => {
|
||||||
|
bpmnElement.value = bpmnInstances().bpmnElement;
|
||||||
|
eventDefinition.value = bpmnElement.value.businessObject.eventDefinitions[0];
|
||||||
|
|
||||||
|
// 获取元素扩展属性 或者 创建扩展属性
|
||||||
|
elExtensionElements.value =
|
||||||
|
bpmnElement.value.businessObject?.extensionElements ??
|
||||||
|
bpmnInstances().moddle.create('bpmn:ExtensionElements', { values: [] });
|
||||||
|
|
||||||
|
// 是否开启自定义用户任务超时处理
|
||||||
|
boundaryEventType.value = elExtensionElements.value.values?.filter(
|
||||||
|
(ex) => ex.$type === `${prefix}:BoundaryEventType`,
|
||||||
|
)?.[0];
|
||||||
|
if (boundaryEventType.value && boundaryEventType.value.value === 1) {
|
||||||
|
timeoutHandlerEnable.value = true;
|
||||||
|
configExtensions.value.push(boundaryEventType.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行动作
|
||||||
|
timeoutHandlerType.value = elExtensionElements.value.values?.filter(
|
||||||
|
(ex) => ex.$type === `${prefix}:TimeoutHandlerType`,
|
||||||
|
)?.[0];
|
||||||
|
if (timeoutHandlerType.value) {
|
||||||
|
configExtensions.value.push(timeoutHandlerType.value);
|
||||||
|
if (eventDefinition.value.timeCycle) {
|
||||||
|
const timeStr = eventDefinition.value.timeCycle.body;
|
||||||
|
const maxRemindCountStr = timeStr.split('/')[0];
|
||||||
|
const timeDurationStr = timeStr.split('/')[1];
|
||||||
|
console.log(maxRemindCountStr);
|
||||||
|
maxRemindCount.value = parseInt(maxRemindCountStr.slice(1));
|
||||||
|
timeDuration.value = parseInt(
|
||||||
|
timeDurationStr.slice(2, timeDurationStr.length - 1),
|
||||||
|
);
|
||||||
|
timeUnit.value = convertTimeUnit(
|
||||||
|
timeDurationStr.slice(timeDurationStr.length - 1),
|
||||||
|
);
|
||||||
|
timeModdle.value = eventDefinition.value.timeCycle;
|
||||||
|
}
|
||||||
|
if (eventDefinition.value.timeDuration) {
|
||||||
|
const timeDurationStr = eventDefinition.value.timeDuration.body;
|
||||||
|
timeDuration.value = parseInt(
|
||||||
|
timeDurationStr.slice(2, timeDurationStr.length - 1),
|
||||||
|
);
|
||||||
|
timeUnit.value = convertTimeUnit(
|
||||||
|
timeDurationStr.slice(timeDurationStr.length - 1),
|
||||||
|
);
|
||||||
|
timeModdle.value = eventDefinition.value.timeDuration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保留剩余扩展元素,便于后面更新该元素对应属性
|
||||||
|
otherExtensions.value =
|
||||||
|
elExtensionElements.value.values?.filter(
|
||||||
|
(ex) =>
|
||||||
|
ex.$type !== `${prefix}:BoundaryEventType` &&
|
||||||
|
ex.$type !== `${prefix}:TimeoutHandlerType`,
|
||||||
|
) ?? [];
|
||||||
|
};
|
||||||
|
|
||||||
|
const timeoutHandlerChange = (val) => {
|
||||||
|
timeoutHandlerEnable.value = val;
|
||||||
|
if (val) {
|
||||||
|
// 启用自定义用户任务超时处理
|
||||||
|
// 边界事件类型 --- 超时
|
||||||
|
boundaryEventType.value = bpmnInstances().moddle.create(
|
||||||
|
`${prefix}:BoundaryEventType`,
|
||||||
|
{
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
configExtensions.value.push(boundaryEventType.value);
|
||||||
|
// 超时处理类型
|
||||||
|
timeoutHandlerType.value = bpmnInstances().moddle.create(
|
||||||
|
`${prefix}:TimeoutHandlerType`,
|
||||||
|
{
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
configExtensions.value.push(timeoutHandlerType.value);
|
||||||
|
// 超时时间表达式
|
||||||
|
timeDuration.value = 6;
|
||||||
|
timeUnit.value = 2;
|
||||||
|
maxRemindCount.value = 1;
|
||||||
|
timeModdle.value = bpmnInstances().moddle.create(`bpmn:Expression`, {
|
||||||
|
body: 'PT6H',
|
||||||
|
});
|
||||||
|
eventDefinition.value.timeDuration = timeModdle.value;
|
||||||
|
} else {
|
||||||
|
// 关闭自定义用户任务超时处理
|
||||||
|
configExtensions.value = [];
|
||||||
|
delete eventDefinition.value.timeDuration;
|
||||||
|
delete eventDefinition.value.timeCycle;
|
||||||
|
}
|
||||||
|
updateElementExtensions();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onTimeoutHandlerTypeChanged = () => {
|
||||||
|
maxRemindCount.value = 1;
|
||||||
|
updateElementExtensions();
|
||||||
|
updateTimeModdle();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onTimeUnitChange = () => {
|
||||||
|
// 分钟,默认是 60 分钟
|
||||||
|
if (timeUnit.value === TimeUnitType.MINUTE) {
|
||||||
|
timeDuration.value = 60;
|
||||||
|
}
|
||||||
|
// 小时,默认是 6 个小时
|
||||||
|
if (timeUnit.value === TimeUnitType.HOUR) {
|
||||||
|
timeDuration.value = 6;
|
||||||
|
}
|
||||||
|
// 天, 默认 1天
|
||||||
|
if (timeUnit.value === TimeUnitType.DAY) {
|
||||||
|
timeDuration.value = 1;
|
||||||
|
}
|
||||||
|
updateTimeModdle();
|
||||||
|
updateElementExtensions();
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateTimeModdle = () => {
|
||||||
|
if (maxRemindCount.value > 1) {
|
||||||
|
timeModdle.value.body =
|
||||||
|
'R' + maxRemindCount.value + '/' + isoTimeDuration();
|
||||||
|
if (!eventDefinition.value.timeCycle) {
|
||||||
|
delete eventDefinition.value.timeDuration;
|
||||||
|
eventDefinition.value.timeCycle = timeModdle.value;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
timeModdle.value.body = isoTimeDuration();
|
||||||
|
if (!eventDefinition.value.timeDuration) {
|
||||||
|
delete eventDefinition.value.timeCycle;
|
||||||
|
eventDefinition.value.timeDuration = timeModdle.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const isoTimeDuration = () => {
|
||||||
|
let strTimeDuration = 'PT';
|
||||||
|
if (timeUnit.value === TimeUnitType.MINUTE) {
|
||||||
|
strTimeDuration += timeDuration.value + 'M';
|
||||||
|
}
|
||||||
|
if (timeUnit.value === TimeUnitType.HOUR) {
|
||||||
|
strTimeDuration += timeDuration.value + 'H';
|
||||||
|
}
|
||||||
|
if (timeUnit.value === TimeUnitType.DAY) {
|
||||||
|
strTimeDuration += timeDuration.value + 'D';
|
||||||
|
}
|
||||||
|
return strTimeDuration;
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateElementExtensions = () => {
|
||||||
|
const extensions = bpmnInstances().moddle.create('bpmn:ExtensionElements', {
|
||||||
|
values: [...otherExtensions.value, ...configExtensions.value],
|
||||||
|
});
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
|
extensionElements: extensions,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.id,
|
||||||
|
(val) => {
|
||||||
|
val &&
|
||||||
|
val.length &&
|
||||||
|
nextTick(() => {
|
||||||
|
resetElement();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
@@ -0,0 +1,760 @@
|
|||||||
|
<!-- UserTask 自定义配置:
|
||||||
|
1. 审批人与提交人为同一人时
|
||||||
|
2. 审批人拒绝时
|
||||||
|
3. 审批人为空时
|
||||||
|
4. 操作按钮
|
||||||
|
5. 字段权限
|
||||||
|
6. 审批类型
|
||||||
|
7. 是否需要签名
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-divider content-position="left">审批类型</el-divider>
|
||||||
|
<el-form-item prop="approveType">
|
||||||
|
<el-radio-group v-model="approveType.value">
|
||||||
|
<el-radio
|
||||||
|
v-for="(item, index) in APPROVE_TYPE"
|
||||||
|
:key="index"
|
||||||
|
:value="item.value"
|
||||||
|
:label="item.value"
|
||||||
|
>
|
||||||
|
{{ item.label }}
|
||||||
|
</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-divider content-position="left">审批人拒绝时</el-divider>
|
||||||
|
<el-form-item prop="rejectHandlerType">
|
||||||
|
<el-radio-group
|
||||||
|
v-model="rejectHandlerType"
|
||||||
|
:disabled="returnTaskList.length === 0"
|
||||||
|
@change="updateRejectHandlerType"
|
||||||
|
>
|
||||||
|
<div class="flex-col">
|
||||||
|
<div v-for="(item, index) in REJECT_HANDLER_TYPES" :key="index">
|
||||||
|
<el-radio
|
||||||
|
:key="item.value"
|
||||||
|
:value="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="rejectHandlerType == RejectHandlerType.RETURN_USER_TASK"
|
||||||
|
label="驳回节点"
|
||||||
|
prop="returnNodeId"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
v-model="returnNodeId"
|
||||||
|
clearable
|
||||||
|
style="width: 100%"
|
||||||
|
@change="updateReturnNodeId"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in returnTaskList"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-divider content-position="left">审批人为空时</el-divider>
|
||||||
|
<el-form-item prop="assignEmptyHandlerType">
|
||||||
|
<el-radio-group
|
||||||
|
v-model="assignEmptyHandlerType"
|
||||||
|
@change="updateAssignEmptyHandlerType"
|
||||||
|
>
|
||||||
|
<div class="flex-col">
|
||||||
|
<div v-for="(item, index) in ASSIGN_EMPTY_HANDLER_TYPES" :key="index">
|
||||||
|
<el-radio
|
||||||
|
:key="item.value"
|
||||||
|
:value="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="assignEmptyHandlerType == AssignEmptyHandlerType.ASSIGN_USER"
|
||||||
|
label="指定用户"
|
||||||
|
prop="assignEmptyHandlerUserIds"
|
||||||
|
span="24"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
v-model="assignEmptyUserIds"
|
||||||
|
clearable
|
||||||
|
multiple
|
||||||
|
style="width: 100%"
|
||||||
|
@change="updateAssignEmptyUserIds"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in userOptions"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.nickname"
|
||||||
|
:value="item.id"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-divider content-position="left">审批人与提交人为同一人时</el-divider>
|
||||||
|
<el-radio-group
|
||||||
|
v-model="assignStartUserHandlerType"
|
||||||
|
@change="updateAssignStartUserHandlerType"
|
||||||
|
>
|
||||||
|
<div class="flex-col">
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in ASSIGN_START_USER_HANDLER_TYPES"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
<el-radio :key="item.value" :value="item.value" :label="item.label" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-radio-group>
|
||||||
|
|
||||||
|
<el-divider content-position="left">操作按钮</el-divider>
|
||||||
|
<div class="button-setting-pane">
|
||||||
|
<div class="button-setting-title">
|
||||||
|
<div class="button-title-label">操作按钮</div>
|
||||||
|
<div class="button-title-label pl-4">显示名称</div>
|
||||||
|
<div class="button-title-label">启用</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="button-setting-item"
|
||||||
|
v-for="(item, index) in buttonsSettingEl"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
<div class="button-setting-item-label">
|
||||||
|
{{ OPERATION_BUTTON_NAME.get(item.id) }}
|
||||||
|
</div>
|
||||||
|
<div class="button-setting-item-label">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="editable-title-input"
|
||||||
|
@blur="btnDisplayNameBlurEvent(index)"
|
||||||
|
v-mountedFocus
|
||||||
|
v-model="item.displayName"
|
||||||
|
:placeholder="item.displayName"
|
||||||
|
v-if="btnDisplayNameEdit[index]"
|
||||||
|
/>
|
||||||
|
<el-button v-else text @click="changeBtnDisplayName(index)"
|
||||||
|
>{{ item.displayName }} <Icon icon="ep:edit"
|
||||||
|
/></el-button>
|
||||||
|
</div>
|
||||||
|
<div class="button-setting-item-label">
|
||||||
|
<el-switch v-model="item.enable" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-divider content-position="left">字段权限</el-divider>
|
||||||
|
<div class="field-setting-pane" v-if="formType === BpmModelFormType.NORMAL">
|
||||||
|
<div class="field-permit-title">
|
||||||
|
<div class="setting-title-label first-title">字段名称</div>
|
||||||
|
<div class="other-titles">
|
||||||
|
<span
|
||||||
|
class="setting-title-label cursor-pointer"
|
||||||
|
@click="updatePermission('READ')"
|
||||||
|
>只读</span
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="setting-title-label cursor-pointer"
|
||||||
|
@click="updatePermission('WRITE')"
|
||||||
|
>可编辑</span
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="setting-title-label cursor-pointer"
|
||||||
|
@click="updatePermission('NONE')"
|
||||||
|
>隐藏</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="field-setting-item"
|
||||||
|
v-for="(item, index) in fieldsPermissionEl"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
<div class="field-setting-item-label">{{ item.title }}</div>
|
||||||
|
<el-radio-group
|
||||||
|
class="field-setting-item-group"
|
||||||
|
v-model="item.permission"
|
||||||
|
>
|
||||||
|
<div class="item-radio-wrap">
|
||||||
|
<el-radio
|
||||||
|
:value="FieldPermissionType.READ"
|
||||||
|
size="large"
|
||||||
|
:label="FieldPermissionType.READ"
|
||||||
|
@change="updateElementExtensions"
|
||||||
|
>
|
||||||
|
<span></span>
|
||||||
|
</el-radio>
|
||||||
|
</div>
|
||||||
|
<div class="item-radio-wrap">
|
||||||
|
<el-radio
|
||||||
|
:value="FieldPermissionType.WRITE"
|
||||||
|
size="large"
|
||||||
|
:label="FieldPermissionType.WRITE"
|
||||||
|
@change="updateElementExtensions"
|
||||||
|
>
|
||||||
|
<span></span>
|
||||||
|
</el-radio>
|
||||||
|
</div>
|
||||||
|
<div class="item-radio-wrap">
|
||||||
|
<el-radio
|
||||||
|
:value="FieldPermissionType.NONE"
|
||||||
|
size="large"
|
||||||
|
:label="FieldPermissionType.NONE"
|
||||||
|
@change="updateElementExtensions"
|
||||||
|
>
|
||||||
|
<span></span>
|
||||||
|
</el-radio>
|
||||||
|
</div>
|
||||||
|
</el-radio-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-divider content-position="left">是否需要签名</el-divider>
|
||||||
|
<el-form-item prop="signEnable">
|
||||||
|
<el-switch
|
||||||
|
v-model="signEnable.value"
|
||||||
|
active-text="是"
|
||||||
|
inactive-text="否"
|
||||||
|
@change="updateElementExtensions"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-divider content-position="left">审批意见</el-divider>
|
||||||
|
<el-form-item prop="reasonRequire">
|
||||||
|
<el-switch
|
||||||
|
v-model="reasonRequire.value"
|
||||||
|
active-text="必填"
|
||||||
|
inactive-text="非必填"
|
||||||
|
@change="updateElementExtensions"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import {
|
||||||
|
ASSIGN_START_USER_HANDLER_TYPES,
|
||||||
|
RejectHandlerType,
|
||||||
|
REJECT_HANDLER_TYPES,
|
||||||
|
ASSIGN_EMPTY_HANDLER_TYPES,
|
||||||
|
AssignEmptyHandlerType,
|
||||||
|
OPERATION_BUTTON_NAME,
|
||||||
|
DEFAULT_BUTTON_SETTING,
|
||||||
|
FieldPermissionType,
|
||||||
|
APPROVE_TYPE,
|
||||||
|
ApproveType,
|
||||||
|
ButtonSetting,
|
||||||
|
} from '@/components/SimpleProcessDesignerV2/src/consts';
|
||||||
|
import * as UserApi from '@/api/system/user';
|
||||||
|
import { useFormFieldsPermission } from '@/components/SimpleProcessDesignerV2/src/node';
|
||||||
|
import { BpmModelFormType } from '@/utils/constants';
|
||||||
|
|
||||||
|
defineOptions({ name: 'ElementCustomConfig4UserTask' });
|
||||||
|
const props = defineProps({
|
||||||
|
id: String,
|
||||||
|
type: String,
|
||||||
|
});
|
||||||
|
const prefix = inject('prefix');
|
||||||
|
|
||||||
|
// 审批人与提交人为同一人时
|
||||||
|
const assignStartUserHandlerTypeEl = ref();
|
||||||
|
const assignStartUserHandlerType = ref();
|
||||||
|
|
||||||
|
// 审批人拒绝时
|
||||||
|
const rejectHandlerTypeEl = ref();
|
||||||
|
const rejectHandlerType = ref();
|
||||||
|
const returnNodeIdEl = ref();
|
||||||
|
const returnNodeId = ref();
|
||||||
|
const returnTaskList = ref([]);
|
||||||
|
|
||||||
|
// 审批人为空时
|
||||||
|
const assignEmptyHandlerTypeEl = ref();
|
||||||
|
const assignEmptyHandlerType = ref();
|
||||||
|
const assignEmptyUserIdsEl = ref();
|
||||||
|
const assignEmptyUserIds = ref();
|
||||||
|
|
||||||
|
// 操作按钮
|
||||||
|
const buttonsSettingEl = ref();
|
||||||
|
const { btnDisplayNameEdit, changeBtnDisplayName, btnDisplayNameBlurEvent } =
|
||||||
|
useButtonsSetting();
|
||||||
|
|
||||||
|
// 字段权限
|
||||||
|
const fieldsPermissionEl = ref([]);
|
||||||
|
const { formType, fieldsPermissionConfig, getNodeConfigFormFields } =
|
||||||
|
useFormFieldsPermission(FieldPermissionType.READ);
|
||||||
|
|
||||||
|
// 审批类型
|
||||||
|
const approveType = ref({ value: ApproveType.USER });
|
||||||
|
|
||||||
|
// 是否需要签名
|
||||||
|
const signEnable = ref({ value: false });
|
||||||
|
|
||||||
|
// 审批意见
|
||||||
|
const reasonRequire = ref({ value: false });
|
||||||
|
|
||||||
|
const elExtensionElements = ref();
|
||||||
|
const otherExtensions = ref();
|
||||||
|
const bpmnElement = ref();
|
||||||
|
const bpmnInstances = () => (window as any)?.bpmnInstances;
|
||||||
|
|
||||||
|
const resetCustomConfigList = () => {
|
||||||
|
bpmnElement.value = bpmnInstances().bpmnElement;
|
||||||
|
|
||||||
|
// 获取可回退的列表
|
||||||
|
returnTaskList.value = findAllPredecessorsExcludingStart(
|
||||||
|
bpmnElement.value.id,
|
||||||
|
bpmnInstances().modeler,
|
||||||
|
);
|
||||||
|
// 获取元素扩展属性 或者 创建扩展属性
|
||||||
|
elExtensionElements.value =
|
||||||
|
bpmnElement.value.businessObject?.extensionElements ??
|
||||||
|
bpmnInstances().moddle.create('bpmn:ExtensionElements', { values: [] });
|
||||||
|
|
||||||
|
// 审批类型
|
||||||
|
approveType.value =
|
||||||
|
elExtensionElements.value.values?.filter(
|
||||||
|
(ex) => ex.$type === `${prefix}:ApproveType`,
|
||||||
|
)?.[0] ||
|
||||||
|
bpmnInstances().moddle.create(`${prefix}:ApproveType`, {
|
||||||
|
value: ApproveType.USER,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 审批人与提交人为同一人时
|
||||||
|
assignStartUserHandlerTypeEl.value =
|
||||||
|
elExtensionElements.value.values?.filter(
|
||||||
|
(ex) => ex.$type === `${prefix}:AssignStartUserHandlerType`,
|
||||||
|
)?.[0] ||
|
||||||
|
bpmnInstances().moddle.create(`${prefix}:AssignStartUserHandlerType`, {
|
||||||
|
value: 1,
|
||||||
|
});
|
||||||
|
assignStartUserHandlerType.value = assignStartUserHandlerTypeEl.value.value;
|
||||||
|
|
||||||
|
// 审批人拒绝时
|
||||||
|
rejectHandlerTypeEl.value =
|
||||||
|
elExtensionElements.value.values?.filter(
|
||||||
|
(ex) => ex.$type === `${prefix}:RejectHandlerType`,
|
||||||
|
)?.[0] ||
|
||||||
|
bpmnInstances().moddle.create(`${prefix}:RejectHandlerType`, { value: 1 });
|
||||||
|
rejectHandlerType.value = rejectHandlerTypeEl.value.value;
|
||||||
|
returnNodeIdEl.value =
|
||||||
|
elExtensionElements.value.values?.filter(
|
||||||
|
(ex) => ex.$type === `${prefix}:RejectReturnTaskId`,
|
||||||
|
)?.[0] ||
|
||||||
|
bpmnInstances().moddle.create(`${prefix}:RejectReturnTaskId`, {
|
||||||
|
value: '',
|
||||||
|
});
|
||||||
|
returnNodeId.value = returnNodeIdEl.value.value;
|
||||||
|
|
||||||
|
// 审批人为空时
|
||||||
|
assignEmptyHandlerTypeEl.value =
|
||||||
|
elExtensionElements.value.values?.filter(
|
||||||
|
(ex) => ex.$type === `${prefix}:AssignEmptyHandlerType`,
|
||||||
|
)?.[0] ||
|
||||||
|
bpmnInstances().moddle.create(`${prefix}:AssignEmptyHandlerType`, {
|
||||||
|
value: 1,
|
||||||
|
});
|
||||||
|
assignEmptyHandlerType.value = assignEmptyHandlerTypeEl.value.value;
|
||||||
|
assignEmptyUserIdsEl.value =
|
||||||
|
elExtensionElements.value.values?.filter(
|
||||||
|
(ex) => ex.$type === `${prefix}:AssignEmptyUserIds`,
|
||||||
|
)?.[0] ||
|
||||||
|
bpmnInstances().moddle.create(`${prefix}:AssignEmptyUserIds`, {
|
||||||
|
value: '',
|
||||||
|
});
|
||||||
|
assignEmptyUserIds.value = assignEmptyUserIdsEl.value.value
|
||||||
|
?.split(',')
|
||||||
|
.map((item) => {
|
||||||
|
// 如果数字超出了最大安全整数范围,则将其作为字符串处理
|
||||||
|
let num = Number(item);
|
||||||
|
return num > Number.MAX_SAFE_INTEGER || num < -Number.MAX_SAFE_INTEGER
|
||||||
|
? item
|
||||||
|
: num;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 操作按钮
|
||||||
|
buttonsSettingEl.value = elExtensionElements.value.values?.filter(
|
||||||
|
(ex) => ex.$type === `${prefix}:ButtonsSetting`,
|
||||||
|
);
|
||||||
|
if (buttonsSettingEl.value.length === 0) {
|
||||||
|
DEFAULT_BUTTON_SETTING.forEach((item) => {
|
||||||
|
buttonsSettingEl.value.push(
|
||||||
|
bpmnInstances().moddle.create(`${prefix}:ButtonsSetting`, {
|
||||||
|
'flowable:id': item.id,
|
||||||
|
'flowable:displayName': item.displayName,
|
||||||
|
'flowable:enable': item.enable,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字段权限
|
||||||
|
if (formType.value === BpmModelFormType.NORMAL) {
|
||||||
|
const fieldsPermissionList = elExtensionElements.value.values?.filter(
|
||||||
|
(ex) => ex.$type === `${prefix}:FieldsPermission`,
|
||||||
|
);
|
||||||
|
fieldsPermissionEl.value = [];
|
||||||
|
getNodeConfigFormFields();
|
||||||
|
fieldsPermissionConfig.value = fieldsPermissionConfig.value;
|
||||||
|
fieldsPermissionConfig.value.forEach((element) => {
|
||||||
|
element.permission =
|
||||||
|
fieldsPermissionList?.find((obj) => obj.field === element.field)
|
||||||
|
?.permission ?? '1';
|
||||||
|
fieldsPermissionEl.value.push(
|
||||||
|
bpmnInstances().moddle.create(`${prefix}:FieldsPermission`, element),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 是否需要签名
|
||||||
|
signEnable.value =
|
||||||
|
elExtensionElements.value.values?.filter(
|
||||||
|
(ex) => ex.$type === `${prefix}:SignEnable`,
|
||||||
|
)?.[0] ||
|
||||||
|
bpmnInstances().moddle.create(`${prefix}:SignEnable`, { value: false });
|
||||||
|
|
||||||
|
// 审批意见
|
||||||
|
reasonRequire.value =
|
||||||
|
elExtensionElements.value.values?.filter(
|
||||||
|
(ex) => ex.$type === `${prefix}:ReasonRequire`,
|
||||||
|
)?.[0] ||
|
||||||
|
bpmnInstances().moddle.create(`${prefix}:ReasonRequire`, { value: false });
|
||||||
|
|
||||||
|
// 保留剩余扩展元素,便于后面更新该元素对应属性
|
||||||
|
otherExtensions.value =
|
||||||
|
elExtensionElements.value.values?.filter(
|
||||||
|
(ex) =>
|
||||||
|
ex.$type !== `${prefix}:AssignStartUserHandlerType` &&
|
||||||
|
ex.$type !== `${prefix}:RejectHandlerType` &&
|
||||||
|
ex.$type !== `${prefix}:RejectReturnTaskId` &&
|
||||||
|
ex.$type !== `${prefix}:AssignEmptyHandlerType` &&
|
||||||
|
ex.$type !== `${prefix}:AssignEmptyUserIds` &&
|
||||||
|
ex.$type !== `${prefix}:ButtonsSetting` &&
|
||||||
|
ex.$type !== `${prefix}:FieldsPermission` &&
|
||||||
|
ex.$type !== `${prefix}:ApproveType` &&
|
||||||
|
ex.$type !== `${prefix}:SignEnable` &&
|
||||||
|
ex.$type !== `${prefix}:ReasonRequire`,
|
||||||
|
) ?? [];
|
||||||
|
|
||||||
|
// 更新元素扩展属性,避免后续报错
|
||||||
|
updateElementExtensions();
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateAssignStartUserHandlerType = () => {
|
||||||
|
assignStartUserHandlerTypeEl.value.value = assignStartUserHandlerType.value;
|
||||||
|
|
||||||
|
updateElementExtensions();
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateRejectHandlerType = () => {
|
||||||
|
rejectHandlerTypeEl.value.value = rejectHandlerType.value;
|
||||||
|
|
||||||
|
returnNodeId.value = returnTaskList.value[0].id;
|
||||||
|
returnNodeIdEl.value.value = returnNodeId.value;
|
||||||
|
|
||||||
|
updateElementExtensions();
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateReturnNodeId = () => {
|
||||||
|
returnNodeIdEl.value.value = returnNodeId.value;
|
||||||
|
|
||||||
|
updateElementExtensions();
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateAssignEmptyHandlerType = () => {
|
||||||
|
assignEmptyHandlerTypeEl.value.value = assignEmptyHandlerType.value;
|
||||||
|
|
||||||
|
updateElementExtensions();
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateAssignEmptyUserIds = () => {
|
||||||
|
assignEmptyUserIdsEl.value.value = assignEmptyUserIds.value.toString();
|
||||||
|
|
||||||
|
updateElementExtensions();
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateElementExtensions = () => {
|
||||||
|
const extensions = bpmnInstances().moddle.create('bpmn:ExtensionElements', {
|
||||||
|
values: [
|
||||||
|
...otherExtensions.value,
|
||||||
|
assignStartUserHandlerTypeEl.value,
|
||||||
|
rejectHandlerTypeEl.value,
|
||||||
|
returnNodeIdEl.value,
|
||||||
|
assignEmptyHandlerTypeEl.value,
|
||||||
|
assignEmptyUserIdsEl.value,
|
||||||
|
approveType.value,
|
||||||
|
...buttonsSettingEl.value,
|
||||||
|
...fieldsPermissionEl.value,
|
||||||
|
signEnable.value,
|
||||||
|
reasonRequire.value,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
|
extensionElements: extensions,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.id,
|
||||||
|
(val) => {
|
||||||
|
val &&
|
||||||
|
val.length &&
|
||||||
|
nextTick(() => {
|
||||||
|
resetCustomConfigList();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
function findAllPredecessorsExcludingStart(elementId, modeler) {
|
||||||
|
const elementRegistry = modeler.get('elementRegistry');
|
||||||
|
const allConnections = elementRegistry.filter(
|
||||||
|
(element) => element.type === 'bpmn:SequenceFlow',
|
||||||
|
);
|
||||||
|
const predecessors = new Set(); // 使用 Set 来避免重复节点
|
||||||
|
const visited = new Set(); // 用于记录已访问的节点
|
||||||
|
|
||||||
|
// 检查是否是开始事件节点
|
||||||
|
function isStartEvent(element) {
|
||||||
|
return element.type === 'bpmn:StartEvent';
|
||||||
|
}
|
||||||
|
|
||||||
|
function findPredecessorsRecursively(element) {
|
||||||
|
// 如果该节点已经访问过,直接返回,避免循环
|
||||||
|
if (visited.has(element)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标记当前节点为已访问
|
||||||
|
visited.add(element);
|
||||||
|
|
||||||
|
// 获取与当前节点相连的所有连接
|
||||||
|
const incomingConnections = allConnections.filter(
|
||||||
|
(connection) => connection.target === element,
|
||||||
|
);
|
||||||
|
|
||||||
|
incomingConnections.forEach((connection) => {
|
||||||
|
const source = connection.source; // 获取前置节点
|
||||||
|
|
||||||
|
// 只添加不是开始事件的前置节点
|
||||||
|
if (!isStartEvent(source)) {
|
||||||
|
predecessors.add(source.businessObject);
|
||||||
|
// 递归查找前置节点
|
||||||
|
findPredecessorsRecursively(source);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetElement = elementRegistry.get(elementId);
|
||||||
|
if (targetElement) {
|
||||||
|
findPredecessorsRecursively(targetElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.from(predecessors); // 返回前置节点数组
|
||||||
|
}
|
||||||
|
|
||||||
|
function useButtonsSetting() {
|
||||||
|
const buttonsSetting = ref<ButtonSetting[]>();
|
||||||
|
// 操作按钮显示名称可编辑
|
||||||
|
const btnDisplayNameEdit = ref<boolean[]>([]);
|
||||||
|
const changeBtnDisplayName = (index: number) => {
|
||||||
|
btnDisplayNameEdit.value[index] = true;
|
||||||
|
};
|
||||||
|
const btnDisplayNameBlurEvent = (index: number) => {
|
||||||
|
btnDisplayNameEdit.value[index] = false;
|
||||||
|
const buttonItem = buttonsSetting.value![index];
|
||||||
|
buttonItem.displayName =
|
||||||
|
buttonItem.displayName || OPERATION_BUTTON_NAME.get(buttonItem.id)!;
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
buttonsSetting,
|
||||||
|
btnDisplayNameEdit,
|
||||||
|
changeBtnDisplayName,
|
||||||
|
btnDisplayNameBlurEvent,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 批量更新权限 */
|
||||||
|
// TODO @lesan:这个页面,有一些 idea 红色报错,咱要不要 fix 下!
|
||||||
|
const updatePermission = (type: string) => {
|
||||||
|
fieldsPermissionEl.value.forEach((field) => {
|
||||||
|
field.permission =
|
||||||
|
type === 'READ'
|
||||||
|
? FieldPermissionType.READ
|
||||||
|
: type === 'WRITE'
|
||||||
|
? FieldPermissionType.WRITE
|
||||||
|
: FieldPermissionType.NONE;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const userOptions = ref<UserApi.UserVO[]>([]); // 用户列表
|
||||||
|
onMounted(async () => {
|
||||||
|
// 获得用户列表
|
||||||
|
userOptions.value = await UserApi.getSimpleUserList();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.button-setting-pane {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-top: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
.button-setting-desc {
|
||||||
|
padding-right: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-setting-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
height: 45px;
|
||||||
|
padding-left: 12px;
|
||||||
|
background-color: #f8fafc0a;
|
||||||
|
border: 1px solid #1f38581a;
|
||||||
|
|
||||||
|
& > :first-child {
|
||||||
|
width: 100px !important;
|
||||||
|
text-align: left !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > :last-child {
|
||||||
|
text-align: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-title-label {
|
||||||
|
width: 150px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #000;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-setting-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
height: 38px;
|
||||||
|
padding-left: 12px;
|
||||||
|
border: 1px solid #1f38581a;
|
||||||
|
border-top: 0;
|
||||||
|
|
||||||
|
& > :first-child {
|
||||||
|
width: 100px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > :last-child {
|
||||||
|
text-align: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-setting-item-label {
|
||||||
|
width: 150px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
text-align: left;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editable-title-input {
|
||||||
|
max-width: 130px;
|
||||||
|
height: 24px;
|
||||||
|
margin-left: 4px;
|
||||||
|
line-height: 24px;
|
||||||
|
border: 1px solid #d9d9d9;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: all 0.3s;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: 0;
|
||||||
|
border-color: #40a9ff;
|
||||||
|
box-shadow: 0 0 0 2px rgb(24 144 255 / 20%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-setting-pane {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
.field-setting-desc {
|
||||||
|
padding-right: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-permit-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
height: 45px;
|
||||||
|
padding-left: 12px;
|
||||||
|
line-height: 45px;
|
||||||
|
background-color: #f8fafc0a;
|
||||||
|
border: 1px solid #1f38581a;
|
||||||
|
|
||||||
|
.first-title {
|
||||||
|
text-align: left !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.other-titles {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-title-label {
|
||||||
|
display: inline-block;
|
||||||
|
width: 100px;
|
||||||
|
padding: 5px 0;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #000;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-setting-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
height: 38px;
|
||||||
|
padding-left: 12px;
|
||||||
|
border: 1px solid #1f38581a;
|
||||||
|
border-top: 0;
|
||||||
|
|
||||||
|
.field-setting-item-label {
|
||||||
|
display: inline-block;
|
||||||
|
width: 100px;
|
||||||
|
min-height: 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
cursor: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-setting-item-group {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.item-radio-wrap {
|
||||||
|
display: inline-block;
|
||||||
|
width: 100px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import BoundaryEventTimer from './components/BoundaryEventTimer.vue';
|
||||||
|
import UserTaskCustomConfig from './components/UserTaskCustomConfig.vue';
|
||||||
|
|
||||||
|
export const CustomConfigMap = {
|
||||||
|
UserTask: {
|
||||||
|
name: '用户任务',
|
||||||
|
componet: UserTaskCustomConfig,
|
||||||
|
},
|
||||||
|
BoundaryEventTimerEventDefinition: {
|
||||||
|
name: '定时边界事件(非中断)',
|
||||||
|
componet: BoundaryEventTimer,
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,218 @@
|
|||||||
|
<template>
|
||||||
|
<div class="panel-tab__content">
|
||||||
|
<el-form :model="flowConditionForm" label-width="90px" size="small">
|
||||||
|
<el-form-item label="流转类型">
|
||||||
|
<el-select v-model="flowConditionForm.type" @change="updateFlowType">
|
||||||
|
<el-option label="普通流转路径" value="normal" />
|
||||||
|
<el-option label="默认流转路径" value="default" />
|
||||||
|
<el-option label="条件流转路径" value="condition" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
label="条件格式"
|
||||||
|
v-if="flowConditionForm.type === 'condition'"
|
||||||
|
key="condition"
|
||||||
|
>
|
||||||
|
<el-select v-model="flowConditionForm.conditionType">
|
||||||
|
<el-option label="表达式" value="expression" />
|
||||||
|
<el-option label="脚本" value="script" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
label="表达式"
|
||||||
|
v-if="
|
||||||
|
flowConditionForm.conditionType &&
|
||||||
|
flowConditionForm.conditionType === 'expression'
|
||||||
|
"
|
||||||
|
key="express"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
v-model="flowConditionForm.body"
|
||||||
|
style="width: 192px"
|
||||||
|
clearable
|
||||||
|
@change="updateFlowCondition"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<template
|
||||||
|
v-if="
|
||||||
|
flowConditionForm.conditionType &&
|
||||||
|
flowConditionForm.conditionType === 'script'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<el-form-item label="脚本语言" key="language">
|
||||||
|
<el-input
|
||||||
|
v-model="flowConditionForm.language"
|
||||||
|
clearable
|
||||||
|
@change="updateFlowCondition"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="脚本类型" key="scriptType">
|
||||||
|
<el-select v-model="flowConditionForm.scriptType">
|
||||||
|
<el-option label="内联脚本" value="inlineScript" />
|
||||||
|
<el-option label="外部脚本" value="externalScript" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
label="脚本"
|
||||||
|
v-if="flowConditionForm.scriptType === 'inlineScript'"
|
||||||
|
key="body"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
v-model="flowConditionForm.body"
|
||||||
|
type="textarea"
|
||||||
|
clearable
|
||||||
|
@change="updateFlowCondition"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
label="资源地址"
|
||||||
|
v-if="flowConditionForm.scriptType === 'externalScript'"
|
||||||
|
key="resource"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
v-model="flowConditionForm.resource"
|
||||||
|
clearable
|
||||||
|
@change="updateFlowCondition"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
defineOptions({ name: 'FlowCondition' });
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
businessObject: Object,
|
||||||
|
type: String,
|
||||||
|
});
|
||||||
|
const flowConditionForm = ref<any>({});
|
||||||
|
const bpmnElement = ref();
|
||||||
|
const bpmnElementSource = ref();
|
||||||
|
const bpmnElementSourceRef = ref();
|
||||||
|
const flowConditionRef = ref();
|
||||||
|
const bpmnInstances = () => (window as any)?.bpmnInstances;
|
||||||
|
const resetFlowCondition = () => {
|
||||||
|
bpmnElement.value = bpmnInstances().bpmnElement;
|
||||||
|
bpmnElementSource.value = bpmnElement.value.source;
|
||||||
|
bpmnElementSourceRef.value = bpmnElement.value.businessObject.sourceRef;
|
||||||
|
// 初始化默认type为default
|
||||||
|
flowConditionForm.value = { type: 'default' };
|
||||||
|
if (
|
||||||
|
bpmnElementSourceRef.value &&
|
||||||
|
bpmnElementSourceRef.value.default &&
|
||||||
|
bpmnElementSourceRef.value.default.id === bpmnElement.value.id
|
||||||
|
) {
|
||||||
|
flowConditionForm.value = { type: 'default' };
|
||||||
|
} else if (!bpmnElement.value.businessObject.conditionExpression) {
|
||||||
|
// 普通
|
||||||
|
flowConditionForm.value = { type: 'normal' };
|
||||||
|
} else {
|
||||||
|
// 带条件
|
||||||
|
const conditionExpression =
|
||||||
|
bpmnElement.value.businessObject.conditionExpression;
|
||||||
|
flowConditionForm.value = { ...conditionExpression, type: 'condition' };
|
||||||
|
// resource 可直接标识 是否是外部资源脚本
|
||||||
|
if (flowConditionForm.value.resource) {
|
||||||
|
// this.$set(this.flowConditionForm, "conditionType", "script");
|
||||||
|
// this.$set(this.flowConditionForm, "scriptType", "externalScript");
|
||||||
|
flowConditionForm.value['conditionType'] = 'script';
|
||||||
|
flowConditionForm.value['scriptType'] = 'externalScript';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (conditionExpression.language) {
|
||||||
|
// this.$set(this.flowConditionForm, "conditionType", "script");
|
||||||
|
// this.$set(this.flowConditionForm, "scriptType", "inlineScript");
|
||||||
|
flowConditionForm.value['conditionType'] = 'script';
|
||||||
|
flowConditionForm.value['scriptType'] = 'inlineScript';
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// this.$set(this.flowConditionForm, "conditionType", "expression");
|
||||||
|
flowConditionForm.value['conditionType'] = 'expression';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const updateFlowType = (flowType) => {
|
||||||
|
// 正常条件类
|
||||||
|
if (flowType === 'condition') {
|
||||||
|
flowConditionRef.value = bpmnInstances().moddle.create(
|
||||||
|
'bpmn:FormalExpression',
|
||||||
|
);
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
|
conditionExpression: flowConditionRef.value,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 默认路径
|
||||||
|
if (flowType === 'default') {
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
|
conditionExpression: null,
|
||||||
|
});
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElementSource.value), {
|
||||||
|
default: toRaw(bpmnElement.value),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 正常路径,如果来源节点的默认路径是当前连线时,清除父元素的默认路径配置
|
||||||
|
if (
|
||||||
|
bpmnElementSourceRef.value.default &&
|
||||||
|
bpmnElementSourceRef.value.default.id === bpmnElement.value.id
|
||||||
|
) {
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElementSource.value), {
|
||||||
|
default: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
|
conditionExpression: null,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const updateFlowCondition = () => {
|
||||||
|
let { conditionType, scriptType, body, resource, language } =
|
||||||
|
flowConditionForm.value;
|
||||||
|
let condition;
|
||||||
|
if (conditionType === 'expression') {
|
||||||
|
condition = bpmnInstances().moddle.create('bpmn:FormalExpression', {
|
||||||
|
body,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (scriptType === 'inlineScript') {
|
||||||
|
condition = bpmnInstances().moddle.create('bpmn:FormalExpression', {
|
||||||
|
body,
|
||||||
|
language,
|
||||||
|
});
|
||||||
|
// this.$set(this.flowConditionForm, "resource", "");
|
||||||
|
flowConditionForm.value['resource'] = '';
|
||||||
|
} else {
|
||||||
|
// this.$set(this.flowConditionForm, "body", "");
|
||||||
|
flowConditionForm.value['body'] = '';
|
||||||
|
condition = bpmnInstances().moddle.create('bpmn:FormalExpression', {
|
||||||
|
resource,
|
||||||
|
language,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
|
conditionExpression: condition,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
bpmnElement.value = null;
|
||||||
|
bpmnElementSource.value = null;
|
||||||
|
bpmnElementSourceRef.value = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.businessObject,
|
||||||
|
(val) => {
|
||||||
|
console.log(val, 'val');
|
||||||
|
nextTick(() => {
|
||||||
|
resetFlowCondition();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,518 @@
|
|||||||
|
<template>
|
||||||
|
<div class="panel-tab__content">
|
||||||
|
<el-form label-width="80px">
|
||||||
|
<el-form-item label="流程表单">
|
||||||
|
<!-- <el-input v-model="formKey" clearable @change="updateElementFormKey" />-->
|
||||||
|
<el-select v-model="formKey" clearable @change="updateElementFormKey">
|
||||||
|
<el-option
|
||||||
|
v-for="form in formList"
|
||||||
|
:key="form.id"
|
||||||
|
:label="form.name"
|
||||||
|
:value="form.id"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<!-- <el-form-item label="业务标识">-->
|
||||||
|
<!-- <el-select v-model="businessKey" @change="updateElementBusinessKey">-->
|
||||||
|
<!-- <el-option v-for="i in fieldList" :key="i.id" :value="i.id" :label="i.label" />-->
|
||||||
|
<!-- <el-option label="无" value="" />-->
|
||||||
|
<!-- </el-select>-->
|
||||||
|
<!-- </el-form-item>-->
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<!--字段列表-->
|
||||||
|
<!-- <div class="element-property list-property">-->
|
||||||
|
<!-- <el-divider><Icon icon="ep:coin" /> 表单字段</el-divider>-->
|
||||||
|
<!-- <el-table :data="fieldList" max-height="240" fit border>-->
|
||||||
|
<!-- <el-table-column label="序号" type="index" width="50px" />-->
|
||||||
|
<!-- <el-table-column label="字段名称" prop="label" min-width="80px" show-overflow-tooltip />-->
|
||||||
|
<!-- <el-table-column-->
|
||||||
|
<!-- label="字段类型"-->
|
||||||
|
<!-- prop="type"-->
|
||||||
|
<!-- min-width="80px"-->
|
||||||
|
<!-- :formatter="(row) => fieldType[row.type] || row.type"-->
|
||||||
|
<!-- show-overflow-tooltip-->
|
||||||
|
<!-- />-->
|
||||||
|
<!-- <el-table-column-->
|
||||||
|
<!-- label="默认值"-->
|
||||||
|
<!-- prop="defaultValue"-->
|
||||||
|
<!-- min-width="80px"-->
|
||||||
|
<!-- show-overflow-tooltip-->
|
||||||
|
<!-- />-->
|
||||||
|
<!-- <el-table-column label="操作" width="90px">-->
|
||||||
|
<!-- <template #default="scope">-->
|
||||||
|
<!-- <el-button type="primary" link @click="openFieldForm(scope, scope.$index)"-->
|
||||||
|
<!-- >编辑</el-button-->
|
||||||
|
<!-- >-->
|
||||||
|
<!-- <el-divider direction="vertical" />-->
|
||||||
|
<!-- <el-button-->
|
||||||
|
<!-- type="primary"-->
|
||||||
|
<!-- link-->
|
||||||
|
<!-- style="color: #ff4d4f"-->
|
||||||
|
<!-- @click="removeField(scope, scope.$index)"-->
|
||||||
|
<!-- >移除</el-button-->
|
||||||
|
<!-- >-->
|
||||||
|
<!-- </template>-->
|
||||||
|
<!-- </el-table-column>-->
|
||||||
|
<!-- </el-table>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- <div class="element-drawer__button">-->
|
||||||
|
<!-- <XButton type="primary" proIcon="ep:plus" title="添加字段" @click="openFieldForm(null, -1)" />-->
|
||||||
|
<!-- </div>-->
|
||||||
|
|
||||||
|
<!--字段配置侧边栏-->
|
||||||
|
<!-- <el-drawer-->
|
||||||
|
<!-- v-model="fieldModelVisible"-->
|
||||||
|
<!-- title="字段配置"-->
|
||||||
|
<!-- :size="`${width}px`"-->
|
||||||
|
<!-- append-to-body-->
|
||||||
|
<!-- destroy-on-close-->
|
||||||
|
<!-- >-->
|
||||||
|
<!-- <el-form :model="formFieldForm" label-width="90px">-->
|
||||||
|
<!-- <el-form-item label="字段ID">-->
|
||||||
|
<!-- <el-input v-model="formFieldForm.id" clearable />-->
|
||||||
|
<!-- </el-form-item>-->
|
||||||
|
<!-- <el-form-item label="类型">-->
|
||||||
|
<!-- <el-select-->
|
||||||
|
<!-- v-model="formFieldForm.typeType"-->
|
||||||
|
<!-- placeholder="请选择字段类型"-->
|
||||||
|
<!-- clearable-->
|
||||||
|
<!-- @change="changeFieldTypeType"-->
|
||||||
|
<!-- >-->
|
||||||
|
<!-- <el-option v-for="(value, key) of fieldType" :label="value" :value="key" :key="key" />-->
|
||||||
|
<!-- </el-select>-->
|
||||||
|
<!-- </el-form-item>-->
|
||||||
|
<!-- <el-form-item label="类型名称" v-if="formFieldForm.typeType === 'custom'">-->
|
||||||
|
<!-- <el-input v-model="formFieldForm.type" clearable />-->
|
||||||
|
<!-- </el-form-item>-->
|
||||||
|
<!-- <el-form-item label="名称">-->
|
||||||
|
<!-- <el-input v-model="formFieldForm.label" clearable />-->
|
||||||
|
<!-- </el-form-item>-->
|
||||||
|
<!-- <el-form-item label="时间格式" v-if="formFieldForm.typeType === 'date'">-->
|
||||||
|
<!-- <el-input v-model="formFieldForm.datePattern" clearable />-->
|
||||||
|
<!-- </el-form-item>-->
|
||||||
|
<!-- <el-form-item label="默认值">-->
|
||||||
|
<!-- <el-input v-model="formFieldForm.defaultValue" clearable />-->
|
||||||
|
<!-- </el-form-item>-->
|
||||||
|
<!-- </el-form>-->
|
||||||
|
|
||||||
|
<!-- <!– 枚举值设置 –>-->
|
||||||
|
<!-- <template v-if="formFieldForm.type === 'enum'">-->
|
||||||
|
<!-- <el-divider key="enum-divider" />-->
|
||||||
|
<!-- <p class="listener-filed__title" key="enum-title">-->
|
||||||
|
<!-- <span><Icon icon="ep:menu" />枚举值列表:</span>-->
|
||||||
|
<!-- <el-button type="primary" @click="openFieldOptionForm(null, -1, 'enum')"-->
|
||||||
|
<!-- >添加枚举值</el-button-->
|
||||||
|
<!-- >-->
|
||||||
|
<!-- </p>-->
|
||||||
|
<!-- <el-table :data="fieldEnumList" key="enum-table" max-height="240" fit border>-->
|
||||||
|
<!-- <el-table-column label="序号" width="50px" type="index" />-->
|
||||||
|
<!-- <el-table-column label="枚举值编号" prop="id" min-width="100px" show-overflow-tooltip />-->
|
||||||
|
<!-- <el-table-column label="枚举值名称" prop="name" min-width="100px" show-overflow-tooltip />-->
|
||||||
|
<!-- <el-table-column label="操作" width="90px">-->
|
||||||
|
<!-- <template #default="scope">-->
|
||||||
|
<!-- <el-button-->
|
||||||
|
<!-- type="primary"-->
|
||||||
|
<!-- link-->
|
||||||
|
<!-- @click="openFieldOptionForm(scope, scope.$index, 'enum')"-->
|
||||||
|
<!-- >编辑</el-button-->
|
||||||
|
<!-- >-->
|
||||||
|
<!-- <el-divider direction="vertical" />-->
|
||||||
|
<!-- <el-button-->
|
||||||
|
<!-- type="primary"-->
|
||||||
|
<!-- link-->
|
||||||
|
<!-- style="color: #ff4d4f"-->
|
||||||
|
<!-- @click="removeFieldOptionItem(scope, scope.$index, 'enum')"-->
|
||||||
|
<!-- >移除</el-button-->
|
||||||
|
<!-- >-->
|
||||||
|
<!-- </template>-->
|
||||||
|
<!-- </el-table-column>-->
|
||||||
|
<!-- </el-table>-->
|
||||||
|
<!-- </template>-->
|
||||||
|
|
||||||
|
<!-- <!– 校验规则 –>-->
|
||||||
|
<!-- <el-divider key="validation-divider" />-->
|
||||||
|
<!-- <p class="listener-filed__title" key="validation-title">-->
|
||||||
|
<!-- <span><Icon icon="ep:menu" />约束条件列表:</span>-->
|
||||||
|
<!-- <el-button type="primary" @click="openFieldOptionForm(null, -1, 'constraint')"-->
|
||||||
|
<!-- >添加约束</el-button-->
|
||||||
|
<!-- >-->
|
||||||
|
<!-- </p>-->
|
||||||
|
<!-- <el-table :data="fieldConstraintsList" key="validation-table" max-height="240" fit border>-->
|
||||||
|
<!-- <el-table-column label="序号" width="50px" type="index" />-->
|
||||||
|
<!-- <el-table-column label="约束名称" prop="name" min-width="100px" show-overflow-tooltip />-->
|
||||||
|
<!-- <el-table-column label="约束配置" prop="config" min-width="100px" show-overflow-tooltip />-->
|
||||||
|
<!-- <el-table-column label="操作" width="90px">-->
|
||||||
|
<!-- <template #default="scope">-->
|
||||||
|
<!-- <el-button-->
|
||||||
|
<!-- type="primary"-->
|
||||||
|
<!-- link-->
|
||||||
|
<!-- @click="openFieldOptionForm(scope, scope.$index, 'constraint')"-->
|
||||||
|
<!-- >编辑</el-button-->
|
||||||
|
<!-- >-->
|
||||||
|
<!-- <el-divider direction="vertical" />-->
|
||||||
|
<!-- <el-button-->
|
||||||
|
<!-- type="primary"-->
|
||||||
|
<!-- link-->
|
||||||
|
<!-- style="color: #ff4d4f"-->
|
||||||
|
<!-- @click="removeFieldOptionItem(scope, scope.$index, 'constraint')"-->
|
||||||
|
<!-- >移除</el-button-->
|
||||||
|
<!-- >-->
|
||||||
|
<!-- </template>-->
|
||||||
|
<!-- </el-table-column>-->
|
||||||
|
<!-- </el-table>-->
|
||||||
|
|
||||||
|
<!-- <!– 表单属性 –>-->
|
||||||
|
<!-- <el-divider key="property-divider" />-->
|
||||||
|
<!-- <p class="listener-filed__title" key="property-title">-->
|
||||||
|
<!-- <span><Icon icon="ep:menu" />字段属性列表:</span>-->
|
||||||
|
<!-- <el-button type="primary" @click="openFieldOptionForm(null, -1, 'property')"-->
|
||||||
|
<!-- >添加属性</el-button-->
|
||||||
|
<!-- >-->
|
||||||
|
<!-- </p>-->
|
||||||
|
<!-- <el-table :data="fieldPropertiesList" key="property-table" max-height="240" fit border>-->
|
||||||
|
<!-- <el-table-column label="序号" width="50px" type="index" />-->
|
||||||
|
<!-- <el-table-column label="属性编号" prop="id" min-width="100px" show-overflow-tooltip />-->
|
||||||
|
<!-- <el-table-column label="属性值" prop="value" min-width="100px" show-overflow-tooltip />-->
|
||||||
|
<!-- <el-table-column label="操作" width="90px">-->
|
||||||
|
<!-- <template #default="scope">-->
|
||||||
|
<!-- <el-button-->
|
||||||
|
<!-- type="primary"-->
|
||||||
|
<!-- link-->
|
||||||
|
<!-- @click="openFieldOptionForm(scope, scope.$index, 'property')"-->
|
||||||
|
<!-- >编辑</el-button-->
|
||||||
|
<!-- >-->
|
||||||
|
<!-- <el-divider direction="vertical" />-->
|
||||||
|
<!-- <el-button-->
|
||||||
|
<!-- type="primary"-->
|
||||||
|
<!-- link-->
|
||||||
|
<!-- style="color: #ff4d4f"-->
|
||||||
|
<!-- @click="removeFieldOptionItem(scope, scope.$index, 'property')"-->
|
||||||
|
<!-- >移除</el-button-->
|
||||||
|
<!-- >-->
|
||||||
|
<!-- </template>-->
|
||||||
|
<!-- </el-table-column>-->
|
||||||
|
<!-- </el-table>-->
|
||||||
|
|
||||||
|
<!-- <!– 底部按钮 –>-->
|
||||||
|
<!-- <div class="element-drawer__button">-->
|
||||||
|
<!-- <el-button>取 消</el-button>-->
|
||||||
|
<!-- <el-button type="primary" @click="saveField">保 存</el-button>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- </el-drawer>-->
|
||||||
|
|
||||||
|
<!-- <el-dialog-->
|
||||||
|
<!-- v-model="fieldOptionModelVisible"-->
|
||||||
|
<!-- :title="optionModelTitle"-->
|
||||||
|
<!-- width="600px"-->
|
||||||
|
<!-- append-to-body-->
|
||||||
|
<!-- destroy-on-close-->
|
||||||
|
<!-- >-->
|
||||||
|
<!-- <el-form :model="fieldOptionForm" label-width="96px">-->
|
||||||
|
<!-- <el-form-item label="编号/ID" v-if="fieldOptionType !== 'constraint'" key="option-id">-->
|
||||||
|
<!-- <el-input v-model="fieldOptionForm.id" clearable />-->
|
||||||
|
<!-- </el-form-item>-->
|
||||||
|
<!-- <el-form-item label="名称" v-if="fieldOptionType !== 'property'" key="option-name">-->
|
||||||
|
<!-- <el-input v-model="fieldOptionForm.name" clearable />-->
|
||||||
|
<!-- </el-form-item>-->
|
||||||
|
<!-- <el-form-item label="配置" v-if="fieldOptionType === 'constraint'" key="option-config">-->
|
||||||
|
<!-- <el-input v-model="fieldOptionForm.config" clearable />-->
|
||||||
|
<!-- </el-form-item>-->
|
||||||
|
<!-- <el-form-item label="值" v-if="fieldOptionType === 'property'" key="option-value">-->
|
||||||
|
<!-- <el-input v-model="fieldOptionForm.value" clearable />-->
|
||||||
|
<!-- </el-form-item>-->
|
||||||
|
<!-- </el-form>-->
|
||||||
|
<!-- <template #footer>-->
|
||||||
|
<!-- <el-button @click="fieldOptionModelVisible = false">取 消</el-button>-->
|
||||||
|
<!-- <el-button type="primary" @click="saveFieldOption">确 定</el-button>-->
|
||||||
|
<!-- </template>-->
|
||||||
|
<!-- </el-dialog>-->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import * as FormApi from '@/api/bpm/form';
|
||||||
|
|
||||||
|
defineOptions({ name: 'ElementForm' });
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
id: String,
|
||||||
|
type: String,
|
||||||
|
});
|
||||||
|
const prefix = inject('prefix');
|
||||||
|
const width = inject('width');
|
||||||
|
|
||||||
|
const formKey = ref(undefined);
|
||||||
|
const businessKey = ref('');
|
||||||
|
const optionModelTitle = ref('');
|
||||||
|
const fieldList = ref<any[]>([]);
|
||||||
|
const formFieldForm = ref<any>({});
|
||||||
|
const fieldType = ref({
|
||||||
|
long: '长整型',
|
||||||
|
string: '字符串',
|
||||||
|
boolean: '布尔类',
|
||||||
|
date: '日期类',
|
||||||
|
enum: '枚举类',
|
||||||
|
custom: '自定义类型',
|
||||||
|
});
|
||||||
|
const formFieldIndex = ref(-1); // 编辑中的字段, -1 为新增
|
||||||
|
const formFieldOptionIndex = ref(-1); // 编辑中的字段配置项, -1 为新增
|
||||||
|
const fieldModelVisible = ref(false);
|
||||||
|
const fieldOptionModelVisible = ref(false);
|
||||||
|
const fieldOptionForm = ref<any>({}); // 当前激活的字段配置项数据
|
||||||
|
const fieldOptionType = ref(''); // 当前激活的字段配置项弹窗 类型
|
||||||
|
const fieldEnumList = ref<any[]>([]); // 枚举值列表
|
||||||
|
const fieldConstraintsList = ref<any[]>([]); // 约束条件列表
|
||||||
|
const fieldPropertiesList = ref<any[]>([]); // 绑定属性列表
|
||||||
|
const bpmnELement = ref();
|
||||||
|
const elExtensionElements = ref();
|
||||||
|
const formData = ref();
|
||||||
|
const otherExtensions = ref();
|
||||||
|
|
||||||
|
const bpmnInstances = () => (window as any)?.bpmnInstances;
|
||||||
|
const resetFormList = () => {
|
||||||
|
bpmnELement.value = bpmnInstances().bpmnElement;
|
||||||
|
formKey.value = bpmnELement.value.businessObject.formKey;
|
||||||
|
// if (formKey.value?.length > 0) {
|
||||||
|
// formKey.value = parseInt(formKey.value)
|
||||||
|
// }
|
||||||
|
// 获取元素扩展属性 或者 创建扩展属性
|
||||||
|
elExtensionElements.value =
|
||||||
|
bpmnELement.value.businessObject.get('extensionElements') ||
|
||||||
|
bpmnInstances().moddle.create('bpmn:ExtensionElements', { values: [] });
|
||||||
|
// 获取元素表单配置 或者 创建新的表单配置
|
||||||
|
formData.value =
|
||||||
|
elExtensionElements.value.values.filter(
|
||||||
|
(ex) => ex.$type === `${prefix}:FormData`,
|
||||||
|
)?.[0] ||
|
||||||
|
bpmnInstances().moddle.create(`${prefix}:FormData`, { fields: [] });
|
||||||
|
|
||||||
|
// 业务标识 businessKey, 绑定在 formData 中
|
||||||
|
businessKey.value = formData.value.businessKey;
|
||||||
|
|
||||||
|
// 保留剩余扩展元素,便于后面更新该元素对应属性
|
||||||
|
otherExtensions.value = elExtensionElements.value.values.filter(
|
||||||
|
(ex) => ex.$type !== `${prefix}:FormData`,
|
||||||
|
);
|
||||||
|
|
||||||
|
// 复制原始值,填充表格
|
||||||
|
fieldList.value = JSON.parse(JSON.stringify(formData.value.fields || []));
|
||||||
|
|
||||||
|
// 更新元素扩展属性,避免后续报错
|
||||||
|
updateElementExtensions();
|
||||||
|
};
|
||||||
|
const updateElementFormKey = () => {
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnELement.value), {
|
||||||
|
formKey: formKey.value,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const updateElementBusinessKey = () => {
|
||||||
|
bpmnInstances().modeling.updateModdleProperties(
|
||||||
|
toRaw(bpmnELement.value),
|
||||||
|
formData.value,
|
||||||
|
{
|
||||||
|
businessKey: businessKey.value,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
// 根据类型调整字段type
|
||||||
|
const changeFieldTypeType = (type) => {
|
||||||
|
// this.$set(this.formFieldForm, "type", type === "custom" ? "" : type);
|
||||||
|
formFieldForm.value['type'] = type === 'custom' ? '' : type;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 打开字段详情侧边栏
|
||||||
|
const openFieldForm = (field, index) => {
|
||||||
|
formFieldIndex.value = index;
|
||||||
|
if (index !== -1) {
|
||||||
|
const FieldObject = formData.value.fields[index];
|
||||||
|
formFieldForm.value = JSON.parse(JSON.stringify(field));
|
||||||
|
// 设置自定义类型
|
||||||
|
// this.$set(this.formFieldForm, "typeType", !this.fieldType[field.type] ? "custom" : field.type);
|
||||||
|
formFieldForm.value['typeType'] = !fieldType.value[field.type]
|
||||||
|
? 'custom'
|
||||||
|
: field.type;
|
||||||
|
// 初始化枚举值列表
|
||||||
|
field.type === 'enum' &&
|
||||||
|
(fieldEnumList.value = JSON.parse(
|
||||||
|
JSON.stringify(FieldObject?.values || []),
|
||||||
|
));
|
||||||
|
// 初始化约束条件列表
|
||||||
|
fieldConstraintsList.value = JSON.parse(
|
||||||
|
JSON.stringify(FieldObject?.validation?.constraints || []),
|
||||||
|
);
|
||||||
|
// 初始化自定义属性列表
|
||||||
|
fieldPropertiesList.value = JSON.parse(
|
||||||
|
JSON.stringify(FieldObject?.properties?.values || []),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
formFieldForm.value = {};
|
||||||
|
// 初始化枚举值列表
|
||||||
|
fieldEnumList.value = [];
|
||||||
|
// 初始化约束条件列表
|
||||||
|
fieldConstraintsList.value = [];
|
||||||
|
// 初始化自定义属性列表
|
||||||
|
fieldPropertiesList.value = [];
|
||||||
|
}
|
||||||
|
fieldModelVisible.value = true;
|
||||||
|
};
|
||||||
|
// 打开字段 某个 配置项 弹窗
|
||||||
|
const openFieldOptionForm = (option, index, type) => {
|
||||||
|
fieldOptionModelVisible.value = true;
|
||||||
|
fieldOptionType.value = type;
|
||||||
|
formFieldOptionIndex.value = index;
|
||||||
|
if (type === 'property') {
|
||||||
|
fieldOptionForm.value = option ? JSON.parse(JSON.stringify(option)) : {};
|
||||||
|
return (optionModelTitle.value = '属性配置');
|
||||||
|
}
|
||||||
|
if (type === 'enum') {
|
||||||
|
fieldOptionForm.value = option ? JSON.parse(JSON.stringify(option)) : {};
|
||||||
|
return (optionModelTitle.value = '枚举值配置');
|
||||||
|
}
|
||||||
|
fieldOptionForm.value = option ? JSON.parse(JSON.stringify(option)) : {};
|
||||||
|
return (optionModelTitle.value = '约束条件配置');
|
||||||
|
};
|
||||||
|
|
||||||
|
// 保存字段 某个 配置项
|
||||||
|
const saveFieldOption = () => {
|
||||||
|
if (formFieldOptionIndex.value === -1) {
|
||||||
|
if (fieldOptionType.value === 'property') {
|
||||||
|
fieldPropertiesList.value.push(fieldOptionForm.value);
|
||||||
|
}
|
||||||
|
if (fieldOptionType.value === 'constraint') {
|
||||||
|
fieldConstraintsList.value.push(fieldOptionForm.value);
|
||||||
|
}
|
||||||
|
if (fieldOptionType.value === 'enum') {
|
||||||
|
fieldEnumList.value.push(fieldOptionForm.value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fieldOptionType.value === 'property' &&
|
||||||
|
fieldPropertiesList.value.splice(
|
||||||
|
formFieldOptionIndex.value,
|
||||||
|
1,
|
||||||
|
fieldOptionForm.value,
|
||||||
|
);
|
||||||
|
fieldOptionType.value === 'constraint' &&
|
||||||
|
fieldConstraintsList.value.splice(
|
||||||
|
formFieldOptionIndex.value,
|
||||||
|
1,
|
||||||
|
fieldOptionForm.value,
|
||||||
|
);
|
||||||
|
fieldOptionType.value === 'enum' &&
|
||||||
|
fieldEnumList.value.splice(
|
||||||
|
formFieldOptionIndex.value,
|
||||||
|
1,
|
||||||
|
fieldOptionForm.value,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
fieldOptionModelVisible.value = false;
|
||||||
|
fieldOptionForm.value = {};
|
||||||
|
};
|
||||||
|
// 保存字段配置
|
||||||
|
const saveField = () => {
|
||||||
|
const { id, type, label, defaultValue, datePattern } = formFieldForm.value;
|
||||||
|
const Field = bpmnInstances().moddle.create(`${prefix}:FormField`, {
|
||||||
|
id,
|
||||||
|
type,
|
||||||
|
label,
|
||||||
|
});
|
||||||
|
defaultValue && (Field.defaultValue = defaultValue);
|
||||||
|
datePattern && (Field.datePattern = datePattern);
|
||||||
|
// 构建属性
|
||||||
|
if (fieldPropertiesList.value && fieldPropertiesList.value.length) {
|
||||||
|
const fieldPropertyList = fieldPropertiesList.value.map((fp) => {
|
||||||
|
return bpmnInstances().moddle.create(`${prefix}:Property`, {
|
||||||
|
id: fp.id,
|
||||||
|
value: fp.value,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
Field.properties = bpmnInstances().moddle.create(`${prefix}:Properties`, {
|
||||||
|
values: fieldPropertyList,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 构建校验规则
|
||||||
|
if (fieldConstraintsList.value && fieldConstraintsList.value.length) {
|
||||||
|
const fieldConstraintList = fieldConstraintsList.value.map((fc) => {
|
||||||
|
return bpmnInstances().moddle.create(`${prefix}:Constraint`, {
|
||||||
|
name: fc.name,
|
||||||
|
config: fc.config,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
Field.validation = bpmnInstances().moddle.create(`${prefix}:Validation`, {
|
||||||
|
constraints: fieldConstraintList,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 构建枚举值
|
||||||
|
if (fieldEnumList.value && fieldEnumList.value.length) {
|
||||||
|
Field.values = fieldEnumList.value.map((fe) => {
|
||||||
|
return bpmnInstances().moddle.create(`${prefix}:Value`, {
|
||||||
|
name: fe.name,
|
||||||
|
id: fe.id,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 更新数组 与 表单配置实例
|
||||||
|
if (formFieldIndex.value === -1) {
|
||||||
|
fieldList.value.push(formFieldForm.value);
|
||||||
|
formData.value.fields.push(Field);
|
||||||
|
} else {
|
||||||
|
fieldList.value.splice(formFieldIndex.value, 1, formFieldForm.value);
|
||||||
|
formData.value.fields.splice(formFieldIndex.value, 1, Field);
|
||||||
|
}
|
||||||
|
updateElementExtensions();
|
||||||
|
fieldModelVisible.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 移除某个 字段的 配置项
|
||||||
|
const removeFieldOptionItem = (option, index, type) => {
|
||||||
|
// console.log(option, 'option')
|
||||||
|
if (type === 'property') {
|
||||||
|
fieldPropertiesList.value.splice(index, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (type === 'enum') {
|
||||||
|
fieldEnumList.value.splice(index, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fieldConstraintsList.value.splice(index, 1);
|
||||||
|
};
|
||||||
|
// 移除 字段
|
||||||
|
const removeField = (field, index) => {
|
||||||
|
console.log(field, 'field');
|
||||||
|
fieldList.value.splice(index, 1);
|
||||||
|
formData.value.fields.splice(index, 1);
|
||||||
|
updateElementExtensions();
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateElementExtensions = () => {
|
||||||
|
// 更新回扩展元素
|
||||||
|
const newElExtensionElements = bpmnInstances().moddle.create(
|
||||||
|
`bpmn:ExtensionElements`,
|
||||||
|
{
|
||||||
|
values: otherExtensions.value.concat(formData.value),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
// 更新到元素上
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnELement.value), {
|
||||||
|
extensionElements: newElExtensionElements,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const formList = ref([]); // 流程表单的下拉框的数据
|
||||||
|
onMounted(async () => {
|
||||||
|
formList.value = await FormApi.getFormSimpleList();
|
||||||
|
formKey.value = parseInt(formKey.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.id,
|
||||||
|
(val) => {
|
||||||
|
val &&
|
||||||
|
val.length &&
|
||||||
|
nextTick(() => {
|
||||||
|
resetFormList();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import MyPropertiesPanel from './PropertiesPanel.vue';
|
||||||
|
|
||||||
|
MyPropertiesPanel.install = function (Vue) {
|
||||||
|
Vue.component(MyPropertiesPanel.name, MyPropertiesPanel);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MyPropertiesPanel;
|
||||||
@@ -0,0 +1,504 @@
|
|||||||
|
<template>
|
||||||
|
<div class="panel-tab__content">
|
||||||
|
<el-table :data="elementListenersList" size="small" border>
|
||||||
|
<el-table-column label="序号" width="50px" type="index" />
|
||||||
|
<el-table-column label="事件类型" min-width="100px" prop="event" />
|
||||||
|
<el-table-column
|
||||||
|
label="监听器类型"
|
||||||
|
min-width="100px"
|
||||||
|
show-overflow-tooltip
|
||||||
|
:formatter="(row) => listenerTypeObject[row.listenerType]"
|
||||||
|
/>
|
||||||
|
<el-table-column label="操作" width="100px">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button
|
||||||
|
size="small"
|
||||||
|
link
|
||||||
|
@click="openListenerForm(scope.row, scope.$index)"
|
||||||
|
>编辑</el-button
|
||||||
|
>
|
||||||
|
<el-divider direction="vertical" />
|
||||||
|
<el-button
|
||||||
|
size="small"
|
||||||
|
link
|
||||||
|
style="color: #ff4d4f"
|
||||||
|
@click="removeListener(scope.$index)"
|
||||||
|
>移除</el-button
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<div class="element-drawer__button">
|
||||||
|
<XButton
|
||||||
|
type="primary"
|
||||||
|
preIcon="ep:plus"
|
||||||
|
title="添加监听器"
|
||||||
|
size="small"
|
||||||
|
@click="openListenerForm(null)"
|
||||||
|
/>
|
||||||
|
<XButton
|
||||||
|
type="success"
|
||||||
|
preIcon="ep:select"
|
||||||
|
title="选择监听器"
|
||||||
|
size="small"
|
||||||
|
@click="openProcessListenerDialog"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 监听器 编辑/创建 部分 -->
|
||||||
|
<el-drawer
|
||||||
|
v-model="listenerFormModelVisible"
|
||||||
|
title="执行监听器"
|
||||||
|
:size="`${width}px`"
|
||||||
|
append-to-body
|
||||||
|
destroy-on-close
|
||||||
|
>
|
||||||
|
<el-form :model="listenerForm" label-width="96px" ref="listenerFormRef">
|
||||||
|
<el-form-item
|
||||||
|
label="事件类型"
|
||||||
|
prop="event"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
|
>
|
||||||
|
<el-select v-model="listenerForm.event">
|
||||||
|
<el-option label="start" value="start" />
|
||||||
|
<el-option label="end" value="end" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
label="监听器类型"
|
||||||
|
prop="listenerType"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
|
>
|
||||||
|
<el-select v-model="listenerForm.listenerType">
|
||||||
|
<el-option
|
||||||
|
v-for="i in Object.keys(listenerTypeObject)"
|
||||||
|
:key="i"
|
||||||
|
:label="listenerTypeObject[i]"
|
||||||
|
:value="i"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="listenerForm.listenerType === 'classListener'"
|
||||||
|
label="Java类"
|
||||||
|
prop="class"
|
||||||
|
key="listener-class"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerForm.class" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="listenerForm.listenerType === 'expressionListener'"
|
||||||
|
label="表达式"
|
||||||
|
prop="expression"
|
||||||
|
key="listener-expression"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerForm.expression" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="listenerForm.listenerType === 'delegateExpressionListener'"
|
||||||
|
label="代理表达式"
|
||||||
|
prop="delegateExpression"
|
||||||
|
key="listener-delegate"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerForm.delegateExpression" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<template v-if="listenerForm.listenerType === 'scriptListener'">
|
||||||
|
<el-form-item
|
||||||
|
label="脚本格式"
|
||||||
|
prop="scriptFormat"
|
||||||
|
key="listener-script-format"
|
||||||
|
:rules="{
|
||||||
|
required: true,
|
||||||
|
trigger: ['blur', 'change'],
|
||||||
|
message: '请填写脚本格式',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerForm.scriptFormat" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
label="脚本类型"
|
||||||
|
prop="scriptType"
|
||||||
|
key="listener-script-type"
|
||||||
|
:rules="{
|
||||||
|
required: true,
|
||||||
|
trigger: ['blur', 'change'],
|
||||||
|
message: '请选择脚本类型',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<el-select v-model="listenerForm.scriptType">
|
||||||
|
<el-option label="内联脚本" value="inlineScript" />
|
||||||
|
<el-option label="外部脚本" value="externalScript" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="listenerForm.scriptType === 'inlineScript'"
|
||||||
|
label="脚本内容"
|
||||||
|
prop="value"
|
||||||
|
key="listener-script"
|
||||||
|
:rules="{
|
||||||
|
required: true,
|
||||||
|
trigger: ['blur', 'change'],
|
||||||
|
message: '请填写脚本内容',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerForm.value" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="listenerForm.scriptType === 'externalScript'"
|
||||||
|
label="资源地址"
|
||||||
|
prop="resource"
|
||||||
|
key="listener-resource"
|
||||||
|
:rules="{
|
||||||
|
required: true,
|
||||||
|
trigger: ['blur', 'change'],
|
||||||
|
message: '请填写资源地址',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerForm.resource" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</el-form>
|
||||||
|
<el-divider />
|
||||||
|
<p class="listener-filed__title">
|
||||||
|
<span><Icon icon="ep:menu" />注入字段:</span>
|
||||||
|
<XButton
|
||||||
|
type="primary"
|
||||||
|
@click="openListenerFieldForm(null)"
|
||||||
|
title="添加字段"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<el-table
|
||||||
|
:data="fieldsListOfListener"
|
||||||
|
size="small"
|
||||||
|
max-height="240"
|
||||||
|
fit
|
||||||
|
border
|
||||||
|
style="flex: none"
|
||||||
|
>
|
||||||
|
<el-table-column label="序号" width="50px" type="index" />
|
||||||
|
<el-table-column label="字段名称" min-width="100px" prop="name" />
|
||||||
|
<el-table-column
|
||||||
|
label="字段类型"
|
||||||
|
min-width="80px"
|
||||||
|
show-overflow-tooltip
|
||||||
|
:formatter="(row) => fieldTypeObject[row.fieldType]"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
label="字段值/表达式"
|
||||||
|
min-width="100px"
|
||||||
|
show-overflow-tooltip
|
||||||
|
:formatter="(row) => row.string || row.expression"
|
||||||
|
/>
|
||||||
|
<el-table-column label="操作" width="130px">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button
|
||||||
|
size="small"
|
||||||
|
link
|
||||||
|
@click="openListenerFieldForm(scope.row, scope.$index)"
|
||||||
|
>编辑</el-button
|
||||||
|
>
|
||||||
|
<el-divider direction="vertical" />
|
||||||
|
<el-button
|
||||||
|
size="small"
|
||||||
|
link
|
||||||
|
style="color: #ff4d4f"
|
||||||
|
@click="removeListenerField(scope.$index)"
|
||||||
|
>移除</el-button
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<div class="element-drawer__button">
|
||||||
|
<el-button @click="listenerFormModelVisible = false">取 消</el-button>
|
||||||
|
<el-button type="primary" @click="saveListenerConfig">保 存</el-button>
|
||||||
|
</div>
|
||||||
|
</el-drawer>
|
||||||
|
|
||||||
|
<!-- 注入西段 编辑/创建 部分 -->
|
||||||
|
<el-dialog
|
||||||
|
title="字段配置"
|
||||||
|
v-model="listenerFieldFormModelVisible"
|
||||||
|
width="600px"
|
||||||
|
append-to-body
|
||||||
|
destroy-on-close
|
||||||
|
>
|
||||||
|
<el-form
|
||||||
|
:model="listenerFieldForm"
|
||||||
|
label-width="96spx"
|
||||||
|
ref="listenerFieldFormRef"
|
||||||
|
style="height: 136px"
|
||||||
|
>
|
||||||
|
<el-form-item
|
||||||
|
label="字段名称:"
|
||||||
|
prop="name"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerFieldForm.name" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
label="字段类型:"
|
||||||
|
prop="fieldType"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
|
>
|
||||||
|
<el-select v-model="listenerFieldForm.fieldType">
|
||||||
|
<el-option
|
||||||
|
v-for="i in Object.keys(fieldTypeObject)"
|
||||||
|
:key="i"
|
||||||
|
:label="fieldTypeObject[i]"
|
||||||
|
:value="i"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="listenerFieldForm.fieldType === 'string'"
|
||||||
|
label="字段值:"
|
||||||
|
prop="string"
|
||||||
|
key="field-string"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerFieldForm.string" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="listenerFieldForm.fieldType === 'expression'"
|
||||||
|
label="表达式:"
|
||||||
|
prop="expression"
|
||||||
|
key="field-expression"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerFieldForm.expression" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button size="small" @click="listenerFieldFormModelVisible = false"
|
||||||
|
>取 消</el-button
|
||||||
|
>
|
||||||
|
<el-button size="small" type="primary" @click="saveListenerFiled"
|
||||||
|
>确 定</el-button
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 选择弹窗 -->
|
||||||
|
<ProcessListenerDialog
|
||||||
|
ref="processListenerDialogRef"
|
||||||
|
@select="selectProcessListener"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ElMessageBox } from 'element-plus';
|
||||||
|
import { createListenerObject, updateElementExtensions } from '../../utils';
|
||||||
|
import {
|
||||||
|
initListenerType,
|
||||||
|
initListenerForm,
|
||||||
|
listenerType,
|
||||||
|
fieldType,
|
||||||
|
initListenerForm2,
|
||||||
|
} from './utilSelf';
|
||||||
|
import ProcessListenerDialog from './ProcessListenerDialog.vue';
|
||||||
|
|
||||||
|
defineOptions({ name: 'ElementListeners' });
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
id: String,
|
||||||
|
type: String,
|
||||||
|
});
|
||||||
|
const prefix = inject('prefix');
|
||||||
|
const width = inject('width');
|
||||||
|
const elementListenersList = ref<any[]>([]); // 监听器列表
|
||||||
|
const listenerForm = ref<any>({}); // 监听器详情表单
|
||||||
|
const listenerFormModelVisible = ref(false); // 监听器 编辑 侧边栏显示状态
|
||||||
|
const fieldsListOfListener = ref<any[]>([]);
|
||||||
|
const listenerFieldForm = ref<any>({}); // 监听器 注入字段 详情表单
|
||||||
|
const listenerFieldFormModelVisible = ref(false); // 监听器 注入字段表单弹窗 显示状态
|
||||||
|
const editingListenerIndex = ref(-1); // 监听器所在下标,-1 为新增
|
||||||
|
const editingListenerFieldIndex = ref(-1); // 字段所在下标,-1 为新增
|
||||||
|
const listenerTypeObject = ref(listenerType);
|
||||||
|
const fieldTypeObject = ref(fieldType);
|
||||||
|
const bpmnElement = ref();
|
||||||
|
const otherExtensionList = ref();
|
||||||
|
const bpmnElementListeners = ref();
|
||||||
|
const listenerFormRef = ref();
|
||||||
|
const listenerFieldFormRef = ref();
|
||||||
|
const bpmnInstances = () => (window as any)?.bpmnInstances;
|
||||||
|
|
||||||
|
const resetListenersList = () => {
|
||||||
|
bpmnElement.value = bpmnInstances().bpmnElement;
|
||||||
|
otherExtensionList.value = [];
|
||||||
|
bpmnElementListeners.value =
|
||||||
|
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
|
||||||
|
(ex) => ex.$type === `${prefix}:ExecutionListener`,
|
||||||
|
) ?? [];
|
||||||
|
elementListenersList.value = bpmnElementListeners.value.map((listener) =>
|
||||||
|
initListenerType(listener),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
// 打开 监听器详情 侧边栏
|
||||||
|
const openListenerForm = (listener, index?) => {
|
||||||
|
// debugger
|
||||||
|
if (listener) {
|
||||||
|
listenerForm.value = initListenerForm(listener);
|
||||||
|
editingListenerIndex.value = index;
|
||||||
|
} else {
|
||||||
|
listenerForm.value = {};
|
||||||
|
editingListenerIndex.value = -1; // 标记为新增
|
||||||
|
}
|
||||||
|
if (listener && listener.fields) {
|
||||||
|
fieldsListOfListener.value = listener.fields.map((field) => ({
|
||||||
|
...field,
|
||||||
|
fieldType: field.string ? 'string' : 'expression',
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
fieldsListOfListener.value = [];
|
||||||
|
listenerForm.value['fields'] = [];
|
||||||
|
}
|
||||||
|
// 打开侧边栏并清楚验证状态
|
||||||
|
listenerFormModelVisible.value = true;
|
||||||
|
nextTick(() => {
|
||||||
|
if (listenerFormRef.value) {
|
||||||
|
listenerFormRef.value.clearValidate();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// 打开监听器字段编辑弹窗
|
||||||
|
const openListenerFieldForm = (field, index?) => {
|
||||||
|
listenerFieldForm.value = field ? JSON.parse(JSON.stringify(field)) : {};
|
||||||
|
editingListenerFieldIndex.value = field ? index : -1;
|
||||||
|
listenerFieldFormModelVisible.value = true;
|
||||||
|
nextTick(() => {
|
||||||
|
if (listenerFieldFormRef.value) {
|
||||||
|
listenerFieldFormRef.value.clearValidate();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// 保存监听器注入字段
|
||||||
|
const saveListenerFiled = async () => {
|
||||||
|
// debugger
|
||||||
|
let validateStatus = await listenerFieldFormRef.value.validate();
|
||||||
|
if (!validateStatus) return; // 验证不通过直接返回
|
||||||
|
if (editingListenerFieldIndex.value === -1) {
|
||||||
|
fieldsListOfListener.value.push(listenerFieldForm.value);
|
||||||
|
listenerForm.value.fields.push(listenerFieldForm.value);
|
||||||
|
} else {
|
||||||
|
fieldsListOfListener.value.splice(
|
||||||
|
editingListenerFieldIndex.value,
|
||||||
|
1,
|
||||||
|
listenerFieldForm.value,
|
||||||
|
);
|
||||||
|
listenerForm.value.fields.splice(
|
||||||
|
editingListenerFieldIndex.value,
|
||||||
|
1,
|
||||||
|
listenerFieldForm.value,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
listenerFieldFormModelVisible.value = false;
|
||||||
|
nextTick(() => {
|
||||||
|
listenerFieldForm.value = {};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// 移除监听器字段
|
||||||
|
const removeListenerField = (index) => {
|
||||||
|
// debugger
|
||||||
|
ElMessageBox.confirm('确认移除该字段吗?', '提示', {
|
||||||
|
confirmButtonText: '确 认',
|
||||||
|
cancelButtonText: '取 消',
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
fieldsListOfListener.value.splice(index, 1);
|
||||||
|
listenerForm.value.fields.splice(index, 1);
|
||||||
|
})
|
||||||
|
.catch(() => console.info('操作取消'));
|
||||||
|
};
|
||||||
|
// 移除监听器
|
||||||
|
const removeListener = (index) => {
|
||||||
|
ElMessageBox.confirm('确认移除该监听器吗?', '提示', {
|
||||||
|
confirmButtonText: '确 认',
|
||||||
|
cancelButtonText: '取 消',
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
bpmnElementListeners.value.splice(index, 1);
|
||||||
|
elementListenersList.value.splice(index, 1);
|
||||||
|
updateElementExtensions(
|
||||||
|
bpmnElement.value,
|
||||||
|
otherExtensionList.value.concat(bpmnElementListeners.value),
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch(() => console.info('操作取消'));
|
||||||
|
};
|
||||||
|
// 保存监听器配置
|
||||||
|
const saveListenerConfig = async () => {
|
||||||
|
// debugger
|
||||||
|
let validateStatus = await listenerFormRef.value.validate();
|
||||||
|
if (!validateStatus) return; // 验证不通过直接返回
|
||||||
|
const listenerObject = createListenerObject(
|
||||||
|
listenerForm.value,
|
||||||
|
false,
|
||||||
|
prefix,
|
||||||
|
);
|
||||||
|
if (editingListenerIndex.value === -1) {
|
||||||
|
bpmnElementListeners.value.push(listenerObject);
|
||||||
|
elementListenersList.value.push(listenerForm.value);
|
||||||
|
} else {
|
||||||
|
bpmnElementListeners.value.splice(
|
||||||
|
editingListenerIndex.value,
|
||||||
|
1,
|
||||||
|
listenerObject,
|
||||||
|
);
|
||||||
|
elementListenersList.value.splice(
|
||||||
|
editingListenerIndex.value,
|
||||||
|
1,
|
||||||
|
listenerForm.value,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// 保存其他配置
|
||||||
|
otherExtensionList.value =
|
||||||
|
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
|
||||||
|
(ex) => ex.$type !== `${prefix}:ExecutionListener`,
|
||||||
|
) ?? [];
|
||||||
|
updateElementExtensions(
|
||||||
|
bpmnElement.value,
|
||||||
|
otherExtensionList.value.concat(bpmnElementListeners.value),
|
||||||
|
);
|
||||||
|
// 4. 隐藏侧边栏
|
||||||
|
listenerFormModelVisible.value = false;
|
||||||
|
listenerForm.value = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 打开监听器弹窗
|
||||||
|
const processListenerDialogRef = ref();
|
||||||
|
const openProcessListenerDialog = async () => {
|
||||||
|
processListenerDialogRef.value.open('execution');
|
||||||
|
};
|
||||||
|
const selectProcessListener = (listener) => {
|
||||||
|
const listenerForm = initListenerForm2(listener);
|
||||||
|
const listenerObject = createListenerObject(listenerForm, false, prefix);
|
||||||
|
bpmnElementListeners.value.push(listenerObject);
|
||||||
|
elementListenersList.value.push(listenerForm);
|
||||||
|
|
||||||
|
// 保存其他配置
|
||||||
|
otherExtensionList.value =
|
||||||
|
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
|
||||||
|
(ex) => ex.$type !== `${prefix}:ExecutionListener`,
|
||||||
|
) ?? [];
|
||||||
|
updateElementExtensions(
|
||||||
|
bpmnElement.value,
|
||||||
|
otherExtensionList.value.concat(bpmnElementListeners.value),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.id,
|
||||||
|
(val) => {
|
||||||
|
val &&
|
||||||
|
val.length &&
|
||||||
|
nextTick(() => {
|
||||||
|
resetListenersList();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
<!-- 执行器选择 -->
|
||||||
|
<template>
|
||||||
|
<Dialog title="请选择监听器" v-model="dialogVisible" width="1024px">
|
||||||
|
<ContentWrap>
|
||||||
|
<el-table
|
||||||
|
v-loading="loading"
|
||||||
|
:data="list"
|
||||||
|
:stripe="true"
|
||||||
|
:show-overflow-tooltip="true"
|
||||||
|
>
|
||||||
|
<el-table-column label="名字" align="center" prop="name" />
|
||||||
|
<el-table-column label="类型" align="center" prop="type">
|
||||||
|
<template #default="scope">
|
||||||
|
<dict-tag
|
||||||
|
:type="DICT_TYPE.BPM_PROCESS_LISTENER_TYPE"
|
||||||
|
:value="scope.row.type"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="事件" align="center" prop="event" />
|
||||||
|
<el-table-column label="值类型" align="center" prop="valueType">
|
||||||
|
<template #default="scope">
|
||||||
|
<dict-tag
|
||||||
|
:type="DICT_TYPE.BPM_PROCESS_LISTENER_VALUE_TYPE"
|
||||||
|
:value="scope.row.valueType"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="值" align="center" prop="value" />
|
||||||
|
<el-table-column label="操作" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button link type="primary" @click="select(scope.row)">
|
||||||
|
选择
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!-- 分页 -->
|
||||||
|
<Pagination
|
||||||
|
:total="total"
|
||||||
|
v-model:page="queryParams.pageNo"
|
||||||
|
v-model:limit="queryParams.pageSize"
|
||||||
|
@pagination="getList"
|
||||||
|
/>
|
||||||
|
</ContentWrap>
|
||||||
|
</Dialog>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {
|
||||||
|
ProcessListenerApi,
|
||||||
|
ProcessListenerVO,
|
||||||
|
} from '@/api/bpm/processListener';
|
||||||
|
import { DICT_TYPE } from '@/utils/dict';
|
||||||
|
import { CommonStatusEnum } from '@/utils/constants';
|
||||||
|
|
||||||
|
/** BPM 流程 表单 */
|
||||||
|
defineOptions({ name: 'ProcessListenerDialog' });
|
||||||
|
|
||||||
|
const dialogVisible = ref(false); // 弹窗的是否展示
|
||||||
|
const loading = ref(true); // 列表的加载中
|
||||||
|
const list = ref<ProcessListenerVO[]>([]); // 列表的数据
|
||||||
|
const total = ref(0); // 列表的总页数
|
||||||
|
const queryParams = reactive({
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
type: '',
|
||||||
|
status: CommonStatusEnum.ENABLE,
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 打开弹窗 */
|
||||||
|
const open = async (type: string) => {
|
||||||
|
queryParams.pageNo = 1;
|
||||||
|
queryParams.type = type;
|
||||||
|
getList();
|
||||||
|
dialogVisible.value = true;
|
||||||
|
};
|
||||||
|
defineExpose({ open }); // 提供 open 方法,用于打开弹窗
|
||||||
|
|
||||||
|
/** 查询列表 */
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
const data = await ProcessListenerApi.getProcessListenerPage(queryParams);
|
||||||
|
list.value = data.list;
|
||||||
|
total.value = data.total;
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 提交表单 */
|
||||||
|
const emit = defineEmits(['success']); // 定义 success 事件,用于操作成功后的回调
|
||||||
|
const select = async (row) => {
|
||||||
|
dialogVisible.value = false;
|
||||||
|
// 发送操作成功的事件
|
||||||
|
emit('select', row);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,564 @@
|
|||||||
|
<template>
|
||||||
|
<div class="panel-tab__content">
|
||||||
|
<el-table :data="elementListenersList" size="small" border>
|
||||||
|
<el-table-column label="序号" width="50px" type="index" />
|
||||||
|
<el-table-column
|
||||||
|
label="事件类型"
|
||||||
|
min-width="80px"
|
||||||
|
show-overflow-tooltip
|
||||||
|
:formatter="(row) => listenerEventTypeObject[row.event]"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
label="事件id"
|
||||||
|
min-width="80px"
|
||||||
|
prop="id"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
label="监听器类型"
|
||||||
|
min-width="80px"
|
||||||
|
show-overflow-tooltip
|
||||||
|
:formatter="(row) => listenerTypeObject[row.listenerType]"
|
||||||
|
/>
|
||||||
|
<el-table-column label="操作" width="90px">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button
|
||||||
|
size="small"
|
||||||
|
link
|
||||||
|
@click="openListenerForm(scope.row, scope.$index)"
|
||||||
|
>编辑</el-button
|
||||||
|
>
|
||||||
|
<el-divider direction="vertical" />
|
||||||
|
<el-button
|
||||||
|
size="small"
|
||||||
|
link
|
||||||
|
style="color: #ff4d4f"
|
||||||
|
@click="removeListener(scope.row, scope.$index)"
|
||||||
|
>移除</el-button
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<div class="element-drawer__button">
|
||||||
|
<XButton
|
||||||
|
size="small"
|
||||||
|
type="primary"
|
||||||
|
preIcon="ep:plus"
|
||||||
|
title="添加监听器"
|
||||||
|
@click="openListenerForm(null)"
|
||||||
|
/>
|
||||||
|
<XButton
|
||||||
|
type="success"
|
||||||
|
preIcon="ep:select"
|
||||||
|
title="选择监听器"
|
||||||
|
size="small"
|
||||||
|
@click="openProcessListenerDialog"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 监听器 编辑/创建 部分 -->
|
||||||
|
<el-drawer
|
||||||
|
v-model="listenerFormModelVisible"
|
||||||
|
title="任务监听器"
|
||||||
|
:size="`${width}px`"
|
||||||
|
append-to-body
|
||||||
|
destroy-on-close
|
||||||
|
>
|
||||||
|
<el-form
|
||||||
|
size="small"
|
||||||
|
:model="listenerForm"
|
||||||
|
label-width="96px"
|
||||||
|
ref="listenerFormRef"
|
||||||
|
>
|
||||||
|
<el-form-item
|
||||||
|
label="事件类型"
|
||||||
|
prop="event"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
|
>
|
||||||
|
<el-select v-model="listenerForm.event">
|
||||||
|
<el-option
|
||||||
|
v-for="i in Object.keys(listenerEventTypeObject)"
|
||||||
|
:key="i"
|
||||||
|
:label="listenerEventTypeObject[i]"
|
||||||
|
:value="i"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
label="监听器ID"
|
||||||
|
prop="id"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerForm.id" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
label="监听器类型"
|
||||||
|
prop="listenerType"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
|
>
|
||||||
|
<el-select v-model="listenerForm.listenerType">
|
||||||
|
<el-option
|
||||||
|
v-for="i in Object.keys(listenerTypeObject)"
|
||||||
|
:key="i"
|
||||||
|
:label="listenerTypeObject[i]"
|
||||||
|
:value="i"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="listenerForm.listenerType === 'classListener'"
|
||||||
|
label="Java类"
|
||||||
|
prop="class"
|
||||||
|
key="listener-class"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerForm.class" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="listenerForm.listenerType === 'expressionListener'"
|
||||||
|
label="表达式"
|
||||||
|
prop="expression"
|
||||||
|
key="listener-expression"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerForm.expression" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="listenerForm.listenerType === 'delegateExpressionListener'"
|
||||||
|
label="代理表达式"
|
||||||
|
prop="delegateExpression"
|
||||||
|
key="listener-delegate"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerForm.delegateExpression" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<template v-if="listenerForm.listenerType === 'scriptListener'">
|
||||||
|
<el-form-item
|
||||||
|
label="脚本格式"
|
||||||
|
prop="scriptFormat"
|
||||||
|
key="listener-script-format"
|
||||||
|
:rules="{
|
||||||
|
required: true,
|
||||||
|
trigger: ['blur', 'change'],
|
||||||
|
message: '请填写脚本格式',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerForm.scriptFormat" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
label="脚本类型"
|
||||||
|
prop="scriptType"
|
||||||
|
key="listener-script-type"
|
||||||
|
:rules="{
|
||||||
|
required: true,
|
||||||
|
trigger: ['blur', 'change'],
|
||||||
|
message: '请选择脚本类型',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<el-select v-model="listenerForm.scriptType">
|
||||||
|
<el-option label="内联脚本" value="inlineScript" />
|
||||||
|
<el-option label="外部脚本" value="externalScript" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="listenerForm.scriptType === 'inlineScript'"
|
||||||
|
label="脚本内容"
|
||||||
|
prop="value"
|
||||||
|
key="listener-script"
|
||||||
|
:rules="{
|
||||||
|
required: true,
|
||||||
|
trigger: ['blur', 'change'],
|
||||||
|
message: '请填写脚本内容',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerForm.value" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="listenerForm.scriptType === 'externalScript'"
|
||||||
|
label="资源地址"
|
||||||
|
prop="resource"
|
||||||
|
key="listener-resource"
|
||||||
|
:rules="{
|
||||||
|
required: true,
|
||||||
|
trigger: ['blur', 'change'],
|
||||||
|
message: '请填写资源地址',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerForm.resource" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-if="listenerForm.event === 'timeout'">
|
||||||
|
<el-form-item
|
||||||
|
label="定时器类型"
|
||||||
|
prop="eventDefinitionType"
|
||||||
|
key="eventDefinitionType"
|
||||||
|
>
|
||||||
|
<el-select v-model="listenerForm.eventDefinitionType">
|
||||||
|
<el-option label="日期" value="date" />
|
||||||
|
<el-option label="持续时长" value="duration" />
|
||||||
|
<el-option label="循环" value="cycle" />
|
||||||
|
<el-option label="无" value="null" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="
|
||||||
|
!!listenerForm.eventDefinitionType &&
|
||||||
|
listenerForm.eventDefinitionType !== 'null'
|
||||||
|
"
|
||||||
|
label="定时器"
|
||||||
|
prop="eventTimeDefinitions"
|
||||||
|
key="eventTimeDefinitions"
|
||||||
|
:rules="{
|
||||||
|
required: true,
|
||||||
|
trigger: ['blur', 'change'],
|
||||||
|
message: '请填写定时器配置',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerForm.eventTimeDefinitions" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<el-divider />
|
||||||
|
<p class="listener-filed__title">
|
||||||
|
<span><Icon icon="ep:menu" />注入字段:</span>
|
||||||
|
<el-button
|
||||||
|
size="small"
|
||||||
|
type="primary"
|
||||||
|
@click="openListenerFieldForm(null)"
|
||||||
|
>添加字段</el-button
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
<el-table
|
||||||
|
:data="fieldsListOfListener"
|
||||||
|
size="small"
|
||||||
|
max-height="240"
|
||||||
|
fit
|
||||||
|
border
|
||||||
|
style="flex: none"
|
||||||
|
>
|
||||||
|
<el-table-column label="序号" width="50px" type="index" />
|
||||||
|
<el-table-column label="字段名称" min-width="100px" prop="name" />
|
||||||
|
<el-table-column
|
||||||
|
label="字段类型"
|
||||||
|
min-width="80px"
|
||||||
|
show-overflow-tooltip
|
||||||
|
:formatter="(row) => fieldTypeObject[row.fieldType]"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
label="字段值/表达式"
|
||||||
|
min-width="100px"
|
||||||
|
show-overflow-tooltip
|
||||||
|
:formatter="(row) => row.string || row.expression"
|
||||||
|
/>
|
||||||
|
<el-table-column label="操作" width="100px">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button
|
||||||
|
size="small"
|
||||||
|
link
|
||||||
|
@click="openListenerFieldForm(scope.row, scope.$index)"
|
||||||
|
>编辑</el-button
|
||||||
|
>
|
||||||
|
<el-divider direction="vertical" />
|
||||||
|
<el-button
|
||||||
|
size="small"
|
||||||
|
link
|
||||||
|
style="color: #ff4d4f"
|
||||||
|
@click="removeListenerField(scope.row, scope.$index)"
|
||||||
|
>移除</el-button
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<div class="element-drawer__button">
|
||||||
|
<el-button size="small" @click="listenerFormModelVisible = false"
|
||||||
|
>取 消</el-button
|
||||||
|
>
|
||||||
|
<el-button size="small" type="primary" @click="saveListenerConfig"
|
||||||
|
>保 存</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</el-drawer>
|
||||||
|
|
||||||
|
<!-- 注入西段 编辑/创建 部分 -->
|
||||||
|
<el-dialog
|
||||||
|
title="字段配置"
|
||||||
|
v-model="listenerFieldFormModelVisible"
|
||||||
|
width="600px"
|
||||||
|
append-to-body
|
||||||
|
destroy-on-close
|
||||||
|
>
|
||||||
|
<el-form
|
||||||
|
:model="listenerFieldForm"
|
||||||
|
size="small"
|
||||||
|
label-width="96px"
|
||||||
|
ref="listenerFieldFormRef"
|
||||||
|
style="height: 136px"
|
||||||
|
>
|
||||||
|
<el-form-item
|
||||||
|
label="字段名称:"
|
||||||
|
prop="name"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerFieldForm.name" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
label="字段类型:"
|
||||||
|
prop="fieldType"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
|
>
|
||||||
|
<el-select v-model="listenerFieldForm.fieldType">
|
||||||
|
<el-option
|
||||||
|
v-for="i in Object.keys(fieldTypeObject)"
|
||||||
|
:key="i"
|
||||||
|
:label="fieldTypeObject[i]"
|
||||||
|
:value="i"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="listenerFieldForm.fieldType === 'string'"
|
||||||
|
label="字段值:"
|
||||||
|
prop="string"
|
||||||
|
key="field-string"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerFieldForm.string" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="listenerFieldForm.fieldType === 'expression'"
|
||||||
|
label="表达式:"
|
||||||
|
prop="expression"
|
||||||
|
key="field-expression"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerFieldForm.expression" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button size="small" @click="listenerFieldFormModelVisible = false"
|
||||||
|
>取 消</el-button
|
||||||
|
>
|
||||||
|
<el-button size="small" type="primary" @click="saveListenerFiled"
|
||||||
|
>确 定</el-button
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 选择弹窗 -->
|
||||||
|
<ProcessListenerDialog
|
||||||
|
ref="processListenerDialogRef"
|
||||||
|
@select="selectProcessListener"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ElMessageBox } from 'element-plus';
|
||||||
|
import { createListenerObject, updateElementExtensions } from '../../utils';
|
||||||
|
import {
|
||||||
|
initListenerForm,
|
||||||
|
initListenerType,
|
||||||
|
eventType,
|
||||||
|
listenerType,
|
||||||
|
fieldType,
|
||||||
|
initListenerForm2,
|
||||||
|
} from './utilSelf';
|
||||||
|
import ProcessListenerDialog from '@/components/bpmnProcessDesigner/package/penal/listeners/ProcessListenerDialog.vue';
|
||||||
|
|
||||||
|
defineOptions({ name: 'UserTaskListeners' });
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
id: String,
|
||||||
|
type: String,
|
||||||
|
});
|
||||||
|
const prefix = inject('prefix');
|
||||||
|
const width = inject('width');
|
||||||
|
const elementListenersList = ref<any[]>([]);
|
||||||
|
const listenerEventTypeObject = ref(eventType);
|
||||||
|
const listenerTypeObject = ref(listenerType);
|
||||||
|
const listenerFormModelVisible = ref(false);
|
||||||
|
const listenerForm = ref<any>({});
|
||||||
|
const fieldTypeObject = ref(fieldType);
|
||||||
|
const fieldsListOfListener = ref<any[]>([]);
|
||||||
|
const listenerFieldFormModelVisible = ref(false); // 监听器 注入字段表单弹窗 显示状态
|
||||||
|
const editingListenerIndex = ref(-1); // 监听器所在下标,-1 为新增
|
||||||
|
const editingListenerFieldIndex = ref(-1); // 字段所在下标,-1 为新增
|
||||||
|
const listenerFieldForm = ref<any>({}); // 监听器 注入字段 详情表单
|
||||||
|
const bpmnElement = ref();
|
||||||
|
const bpmnElementListeners = ref();
|
||||||
|
const otherExtensionList = ref();
|
||||||
|
const listenerFormRef = ref();
|
||||||
|
const listenerFieldFormRef = ref();
|
||||||
|
const bpmnInstances = () => (window as any)?.bpmnInstances;
|
||||||
|
|
||||||
|
const resetListenersList = () => {
|
||||||
|
console.log(
|
||||||
|
bpmnInstances().bpmnElement,
|
||||||
|
'window.bpmnInstances.bpmnElementwindow.bpmnInstances.bpmnElementwindow.bpmnInstances.bpmnElementwindow.bpmnInstances.bpmnElementwindow.bpmnInstances.bpmnElementwindow.bpmnInstances.bpmnElement',
|
||||||
|
);
|
||||||
|
bpmnElement.value = bpmnInstances().bpmnElement;
|
||||||
|
otherExtensionList.value = [];
|
||||||
|
bpmnElementListeners.value =
|
||||||
|
bpmnElement.value.businessObject?.extensionElements?.values.filter(
|
||||||
|
(ex) => ex.$type === `${prefix}:TaskListener`,
|
||||||
|
) ?? [];
|
||||||
|
elementListenersList.value = bpmnElementListeners.value.map((listener) =>
|
||||||
|
initListenerType(listener),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
const openListenerForm = (listener, index?) => {
|
||||||
|
if (listener) {
|
||||||
|
listenerForm.value = initListenerForm(listener);
|
||||||
|
editingListenerIndex.value = index;
|
||||||
|
} else {
|
||||||
|
listenerForm.value = {};
|
||||||
|
editingListenerIndex.value = -1; // 标记为新增
|
||||||
|
}
|
||||||
|
if (listener && listener.fields) {
|
||||||
|
fieldsListOfListener.value = listener.fields.map((field) => ({
|
||||||
|
...field,
|
||||||
|
fieldType: field.string ? 'string' : 'expression',
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
fieldsListOfListener.value = [];
|
||||||
|
listenerForm.value['fields'] = [];
|
||||||
|
}
|
||||||
|
// 打开侧边栏并清楚验证状态
|
||||||
|
listenerFormModelVisible.value = true;
|
||||||
|
nextTick(() => {
|
||||||
|
if (listenerFormRef.value) listenerFormRef.value.clearValidate();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// 移除监听器
|
||||||
|
const removeListener = (listener, index?) => {
|
||||||
|
console.log(listener, 'listener');
|
||||||
|
ElMessageBox.confirm('确认移除该监听器吗?', '提示', {
|
||||||
|
confirmButtonText: '确 认',
|
||||||
|
cancelButtonText: '取 消',
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
bpmnElementListeners.value.splice(index, 1);
|
||||||
|
elementListenersList.value.splice(index, 1);
|
||||||
|
updateElementExtensions(
|
||||||
|
bpmnElement.value,
|
||||||
|
otherExtensionList.value.concat(bpmnElementListeners.value),
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch(() => console.info('操作取消'));
|
||||||
|
};
|
||||||
|
// 保存监听器
|
||||||
|
const saveListenerConfig = async () => {
|
||||||
|
let validateStatus = await listenerFormRef.value.validate();
|
||||||
|
if (!validateStatus) return; // 验证不通过直接返回
|
||||||
|
const listenerObject = createListenerObject(listenerForm.value, true, prefix);
|
||||||
|
if (editingListenerIndex.value === -1) {
|
||||||
|
bpmnElementListeners.value.push(listenerObject);
|
||||||
|
elementListenersList.value.push(listenerForm.value);
|
||||||
|
} else {
|
||||||
|
bpmnElementListeners.value.splice(
|
||||||
|
editingListenerIndex.value,
|
||||||
|
1,
|
||||||
|
listenerObject,
|
||||||
|
);
|
||||||
|
elementListenersList.value.splice(
|
||||||
|
editingListenerIndex.value,
|
||||||
|
1,
|
||||||
|
listenerForm.value,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// 保存其他配置
|
||||||
|
otherExtensionList.value =
|
||||||
|
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
|
||||||
|
(ex) => ex.$type !== `${prefix}:TaskListener`,
|
||||||
|
) ?? [];
|
||||||
|
updateElementExtensions(
|
||||||
|
bpmnElement.value,
|
||||||
|
otherExtensionList.value.concat(bpmnElementListeners.value),
|
||||||
|
);
|
||||||
|
// 4. 隐藏侧边栏
|
||||||
|
listenerFormModelVisible.value = false;
|
||||||
|
listenerForm.value = {};
|
||||||
|
};
|
||||||
|
// 打开监听器字段编辑弹窗
|
||||||
|
const openListenerFieldForm = (field, index?) => {
|
||||||
|
listenerFieldForm.value = field ? JSON.parse(JSON.stringify(field)) : {};
|
||||||
|
editingListenerFieldIndex.value = field ? index : -1;
|
||||||
|
listenerFieldFormModelVisible.value = true;
|
||||||
|
nextTick(() => {
|
||||||
|
if (listenerFieldFormRef.value) listenerFieldFormRef.value.clearValidate();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// 保存监听器注入字段
|
||||||
|
const saveListenerFiled = async () => {
|
||||||
|
let validateStatus = await listenerFieldFormRef.value.validate();
|
||||||
|
if (!validateStatus) return; // 验证不通过直接返回
|
||||||
|
if (editingListenerFieldIndex.value === -1) {
|
||||||
|
fieldsListOfListener.value.push(listenerFieldForm.value);
|
||||||
|
listenerForm.value.fields.push(listenerFieldForm.value);
|
||||||
|
} else {
|
||||||
|
fieldsListOfListener.value.splice(
|
||||||
|
editingListenerFieldIndex.value,
|
||||||
|
1,
|
||||||
|
listenerFieldForm.value,
|
||||||
|
);
|
||||||
|
listenerForm.value.fields.splice(
|
||||||
|
editingListenerFieldIndex.value,
|
||||||
|
1,
|
||||||
|
listenerFieldForm.value,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
listenerFieldFormModelVisible.value = false;
|
||||||
|
nextTick(() => {
|
||||||
|
listenerFieldForm.value = {};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// 移除监听器字段
|
||||||
|
const removeListenerField = (field, index) => {
|
||||||
|
console.log(field, 'field');
|
||||||
|
ElMessageBox.confirm('确认移除该字段吗?', '提示', {
|
||||||
|
confirmButtonText: '确 认',
|
||||||
|
cancelButtonText: '取 消',
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
fieldsListOfListener.value.splice(index, 1);
|
||||||
|
listenerForm.value.fields.splice(index, 1);
|
||||||
|
})
|
||||||
|
.catch(() => console.info('操作取消'));
|
||||||
|
};
|
||||||
|
|
||||||
|
// 打开监听器弹窗
|
||||||
|
const processListenerDialogRef = ref();
|
||||||
|
const openProcessListenerDialog = async () => {
|
||||||
|
processListenerDialogRef.value.open('task');
|
||||||
|
};
|
||||||
|
const selectProcessListener = (listener) => {
|
||||||
|
const listenerForm = initListenerForm2(listener);
|
||||||
|
const listenerObject = createListenerObject(listenerForm, true, prefix);
|
||||||
|
bpmnElementListeners.value.push(listenerObject);
|
||||||
|
elementListenersList.value.push(listenerForm);
|
||||||
|
|
||||||
|
// 保存其他配置
|
||||||
|
otherExtensionList.value =
|
||||||
|
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
|
||||||
|
(ex) => ex.$type !== `${prefix}:TaskListener`,
|
||||||
|
) ?? [];
|
||||||
|
updateElementExtensions(
|
||||||
|
bpmnElement.value,
|
||||||
|
otherExtensionList.value.concat(bpmnElementListeners.value),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.id,
|
||||||
|
(val) => {
|
||||||
|
val &&
|
||||||
|
val.length &&
|
||||||
|
nextTick(() => {
|
||||||
|
resetListenersList();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
export const template = (isTaskListener) => {
|
||||||
|
return `
|
||||||
|
<div class="panel-tab__content">
|
||||||
|
<el-table :data="elementListenersList" size="small" border>
|
||||||
|
<el-table-column label="序号" width="50px" type="index" />
|
||||||
|
<el-table-column label="事件类型" min-width="100px" prop="event" />
|
||||||
|
<el-table-column label="监听器类型" min-width="100px" show-overflow-tooltip :formatter="row => listenerTypeObject[row.listenerType]" />
|
||||||
|
<el-table-column label="操作" width="90px">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button size="small" type="primary" link @click="openListenerForm(scope, scope.$index)">编辑</el-button>
|
||||||
|
<el-divider direction="vertical" />
|
||||||
|
<el-button size="small" type="primary" link style="color: #ff4d4f" @click="removeListener(scope, scope.$index)">移除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<div class="element-drawer__button">
|
||||||
|
<el-button size="small" type="primary" icon="el-icon-plus" @click="openListenerForm(null)">添加监听器</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 监听器 编辑/创建 部分 -->
|
||||||
|
<el-drawer :visible.sync="listenerFormModelVisible" title="执行监听器" :size="width + 'px'" append-to-body destroy-on-close>
|
||||||
|
<el-form size="small" :model="listenerForm" label-width="96px" ref="listenerFormRef" @submit.native.prevent>
|
||||||
|
<el-form-item label="事件类型" prop="event" :rules="{ required: true, trigger: ['blur', 'change'] }">
|
||||||
|
<el-select v-model="listenerForm.event">
|
||||||
|
<el-option label="start" value="start" />
|
||||||
|
<el-option label="end" value="end" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="监听器类型" prop="listenerType" :rules="{ required: true, trigger: ['blur', 'change'] }">
|
||||||
|
<el-select v-model="listenerForm.listenerType">
|
||||||
|
<el-option v-for="i in Object.keys(listenerTypeObject)" :key="i" :label="listenerTypeObject[i]" :value="i" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="listenerForm.listenerType === 'classListener'"
|
||||||
|
label="Java类"
|
||||||
|
prop="class"
|
||||||
|
key="listener-class"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerForm.class" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="listenerForm.listenerType === 'expressionListener'"
|
||||||
|
label="表达式"
|
||||||
|
prop="expression"
|
||||||
|
key="listener-expression"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerForm.expression" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="listenerForm.listenerType === 'delegateExpressionListener'"
|
||||||
|
label="代理表达式"
|
||||||
|
prop="delegateExpression"
|
||||||
|
key="listener-delegate"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerForm.delegateExpression" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<template v-if="listenerForm.listenerType === 'scriptListener'">
|
||||||
|
<el-form-item
|
||||||
|
label="脚本格式"
|
||||||
|
prop="scriptFormat"
|
||||||
|
key="listener-script-format"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本格式' }"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerForm.scriptFormat" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
label="脚本类型"
|
||||||
|
prop="scriptType"
|
||||||
|
key="listener-script-type"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'], message: '请选择脚本类型' }"
|
||||||
|
>
|
||||||
|
<el-select v-model="listenerForm.scriptType">
|
||||||
|
<el-option label="内联脚本" value="inlineScript" />
|
||||||
|
<el-option label="外部脚本" value="externalScript" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="listenerForm.scriptType === 'inlineScript'"
|
||||||
|
label="脚本内容"
|
||||||
|
prop="value"
|
||||||
|
key="listener-script"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本内容' }"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerForm.value" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="listenerForm.scriptType === 'externalScript'"
|
||||||
|
label="资源地址"
|
||||||
|
prop="resource"
|
||||||
|
key="listener-resource"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写资源地址' }"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerForm.resource" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
${
|
||||||
|
isTaskListener
|
||||||
|
? "<el-form-item label='定时器类型' prop='eventDefinitionType' key='eventDefinitionType'>" +
|
||||||
|
"<el-select v-model='listenerForm.eventDefinitionType'>" +
|
||||||
|
"<el-option label='日期' value='date' />" +
|
||||||
|
"<el-option label='持续时长' value='duration' />" +
|
||||||
|
"<el-option label='循环' value='cycle' />" +
|
||||||
|
"<el-option label='无' value='' />" +
|
||||||
|
'</el-select>' +
|
||||||
|
'</el-form-item>' +
|
||||||
|
"<el-form-item v-if='!!listenerForm.eventDefinitionType' label='定时器' prop='eventDefinitions' key='eventDefinitions'>" +
|
||||||
|
"<el-input v-model='listenerForm.eventDefinitions' clearable />" +
|
||||||
|
'</el-form-item>'
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
</el-form>
|
||||||
|
<el-divider />
|
||||||
|
<p class="listener-filed__title">
|
||||||
|
<span><i class="el-icon-menu"></i>注入字段:</span>
|
||||||
|
<el-button size="small" type="primary" @click="openListenerFieldForm(null)">添加字段</el-button>
|
||||||
|
</p>
|
||||||
|
<el-table :data="fieldsListOfListener" size="small" max-height="240" border fit style="flex: none">
|
||||||
|
<el-table-column label="序号" width="50px" type="index" />
|
||||||
|
<el-table-column label="字段名称" min-width="100px" prop="name" />
|
||||||
|
<el-table-column label="字段类型" min-width="80px" show-overflow-tooltip :formatter="row => fieldTypeObject[row.fieldType]" />
|
||||||
|
<el-table-column label="字段值/表达式" min-width="100px" show-overflow-tooltip :formatter="row => row.string || row.expression" />
|
||||||
|
<el-table-column label="操作" width="100px">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button size="small" type="primary" link @click="openListenerFieldForm(scope, scope.$index)">编辑</el-button>
|
||||||
|
<el-divider direction="vertical" />
|
||||||
|
<el-button size="small" type="primary" link style="color: #ff4d4f" @click="removeListenerField(scope, scope.$index)">移除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<div class="element-drawer__button">
|
||||||
|
<el-button size="small" @click="listenerFormModelVisible = false">取 消</el-button>
|
||||||
|
<el-button size="small" type="primary" @click="saveListenerConfig">保 存</el-button>
|
||||||
|
</div>
|
||||||
|
</el-drawer>
|
||||||
|
|
||||||
|
<!-- 注入西段 编辑/创建 部分 -->
|
||||||
|
<el-dialog title="字段配置" :visible.sync="listenerFieldFormModelVisible" width="600px" append-to-body destroy-on-close>
|
||||||
|
<el-form :model="listenerFieldForm" size="small" label-width="96px" ref="listenerFieldFormRef" style="height: 136px" @submit.native.prevent>
|
||||||
|
<el-form-item label="字段名称:" prop="name" :rules="{ required: true, trigger: ['blur', 'change'] }">
|
||||||
|
<el-input v-model="listenerFieldForm.name" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="字段类型:" prop="fieldType" :rules="{ required: true, trigger: ['blur', 'change'] }">
|
||||||
|
<el-select v-model="listenerFieldForm.fieldType">
|
||||||
|
<el-option v-for="i in Object.keys(fieldTypeObject)" :key="i" :label="fieldTypeObject[i]" :value="i" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="listenerFieldForm.fieldType === 'string'"
|
||||||
|
label="字段值:"
|
||||||
|
prop="string"
|
||||||
|
key="field-string"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerFieldForm.string" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="listenerFieldForm.fieldType === 'expression'"
|
||||||
|
label="表达式:"
|
||||||
|
prop="expression"
|
||||||
|
key="field-expression"
|
||||||
|
:rules="{ required: true, trigger: ['blur', 'change'] }"
|
||||||
|
>
|
||||||
|
<el-input v-model="listenerFieldForm.expression" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button size="small" @click="listenerFieldFormModelVisible = false">取 消</el-button>
|
||||||
|
<el-button size="small" type="primary" @click="saveListenerFiled">确 定</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
};
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
// 初始化表单数据
|
||||||
|
export function initListenerForm(listener) {
|
||||||
|
let self = {
|
||||||
|
...listener,
|
||||||
|
};
|
||||||
|
if (listener.script) {
|
||||||
|
self = {
|
||||||
|
...listener,
|
||||||
|
...listener.script,
|
||||||
|
scriptType: listener.script.resource ? 'externalScript' : 'inlineScript',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
listener.event === 'timeout' &&
|
||||||
|
listener.eventDefinitions &&
|
||||||
|
listener.eventDefinitions.length > 0
|
||||||
|
) {
|
||||||
|
let k = '';
|
||||||
|
for (const key in listener.eventDefinitions[0]) {
|
||||||
|
console.log(listener.eventDefinitions, key);
|
||||||
|
if (key.includes('time')) {
|
||||||
|
k = key;
|
||||||
|
self.eventDefinitionType = key.replace('time', '').toLowerCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(k);
|
||||||
|
self.eventTimeDefinitions = listener.eventDefinitions[0][k].body;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function initListenerType(listener) {
|
||||||
|
let listenerType;
|
||||||
|
if (listener.class) listenerType = 'classListener';
|
||||||
|
if (listener.expression) listenerType = 'expressionListener';
|
||||||
|
if (listener.delegateExpression) listenerType = 'delegateExpressionListener';
|
||||||
|
if (listener.script) listenerType = 'scriptListener';
|
||||||
|
return {
|
||||||
|
...JSON.parse(JSON.stringify(listener)),
|
||||||
|
...listener.script,
|
||||||
|
listenerType,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 将 ProcessListenerDO 转换成 initListenerForm 想同的 Form 对象 */
|
||||||
|
export function initListenerForm2(processListener) {
|
||||||
|
switch (processListener.valueType) {
|
||||||
|
case 'class': {
|
||||||
|
return {
|
||||||
|
listenerType: 'classListener',
|
||||||
|
class: processListener.value,
|
||||||
|
event: processListener.event,
|
||||||
|
fields: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case 'delegateExpression': {
|
||||||
|
return {
|
||||||
|
listenerType: 'delegateExpressionListener',
|
||||||
|
delegateExpression: processListener.value,
|
||||||
|
event: processListener.event,
|
||||||
|
fields: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case 'expression': {
|
||||||
|
return {
|
||||||
|
listenerType: 'expressionListener',
|
||||||
|
expression: processListener.value,
|
||||||
|
event: processListener.event,
|
||||||
|
fields: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// No default
|
||||||
|
}
|
||||||
|
throw new Error('未知的监听器类型');
|
||||||
|
}
|
||||||
|
|
||||||
|
export const listenerType = {
|
||||||
|
classListener: 'Java 类',
|
||||||
|
expressionListener: '表达式',
|
||||||
|
delegateExpressionListener: '代理表达式',
|
||||||
|
scriptListener: '脚本',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const eventType = {
|
||||||
|
create: '创建',
|
||||||
|
assignment: '指派',
|
||||||
|
complete: '完成',
|
||||||
|
delete: '删除',
|
||||||
|
update: '更新',
|
||||||
|
timeout: '超时',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const fieldType = {
|
||||||
|
string: '字符串',
|
||||||
|
expression: '表达式',
|
||||||
|
};
|
||||||
@@ -0,0 +1,459 @@
|
|||||||
|
<template>
|
||||||
|
<div class="panel-tab__content">
|
||||||
|
<el-radio-group
|
||||||
|
v-if="type === 'UserTask'"
|
||||||
|
v-model="approveMethod"
|
||||||
|
@change="onApproveMethodChange"
|
||||||
|
>
|
||||||
|
<div class="flex-col">
|
||||||
|
<div v-for="(item, index) in APPROVE_METHODS" :key="index">
|
||||||
|
<el-radio :value="item.value" :label="item.value">
|
||||||
|
{{ item.label }}
|
||||||
|
</el-radio>
|
||||||
|
<el-form-item prop="approveRatio">
|
||||||
|
<el-input-number
|
||||||
|
v-model="approveRatio"
|
||||||
|
:min="10"
|
||||||
|
:max="100"
|
||||||
|
:step="10"
|
||||||
|
size="small"
|
||||||
|
v-if="
|
||||||
|
item.value === ApproveMethodType.APPROVE_BY_RATIO &&
|
||||||
|
approveMethod === ApproveMethodType.APPROVE_BY_RATIO
|
||||||
|
"
|
||||||
|
@change="onApproveRatioChange"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-radio-group>
|
||||||
|
<div v-else>除了UserTask以外节点的多实例待实现</div>
|
||||||
|
<!-- 与Simple设计器配置合并,保留以前的代码 -->
|
||||||
|
<el-form label-width="90px" style="display: none">
|
||||||
|
<el-form-item label="快捷配置">
|
||||||
|
<el-button size="small" @click="changeConfig('依次审批')"
|
||||||
|
>依次审批</el-button
|
||||||
|
>
|
||||||
|
<el-button size="small" @click="changeConfig('会签')">会签</el-button>
|
||||||
|
<el-button size="small" @click="changeConfig('或签')">或签</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="会签类型">
|
||||||
|
<el-select
|
||||||
|
v-model="loopCharacteristics"
|
||||||
|
@change="changeLoopCharacteristicsType"
|
||||||
|
>
|
||||||
|
<el-option label="并行多重事件" value="ParallelMultiInstance" />
|
||||||
|
<el-option label="时序多重事件" value="SequentialMultiInstance" />
|
||||||
|
<el-option label="无" value="Null" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<template
|
||||||
|
v-if="
|
||||||
|
loopCharacteristics === 'ParallelMultiInstance' ||
|
||||||
|
loopCharacteristics === 'SequentialMultiInstance'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<el-form-item label="循环数量" key="loopCardinality">
|
||||||
|
<el-input
|
||||||
|
v-model="loopInstanceForm.loopCardinality"
|
||||||
|
clearable
|
||||||
|
@change="updateLoopCardinality"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="集合" key="collection" v-show="false">
|
||||||
|
<el-input
|
||||||
|
v-model="loopInstanceForm.collection"
|
||||||
|
clearable
|
||||||
|
@change="updateLoopBase"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<!-- add by 芋艿:由于「元素变量」暂时用不到,所以这里 display 为 none -->
|
||||||
|
<el-form-item
|
||||||
|
label="元素变量"
|
||||||
|
key="elementVariable"
|
||||||
|
style="display: none"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
v-model="loopInstanceForm.elementVariable"
|
||||||
|
clearable
|
||||||
|
@change="updateLoopBase"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="完成条件" key="completionCondition">
|
||||||
|
<el-input
|
||||||
|
v-model="loopInstanceForm.completionCondition"
|
||||||
|
clearable
|
||||||
|
@change="updateLoopCondition"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<!-- add by 芋艿:由于「异步状态」暂时用不到,所以这里 display 为 none -->
|
||||||
|
<el-form-item label="异步状态" key="async" style="display: none">
|
||||||
|
<el-checkbox
|
||||||
|
v-model="loopInstanceForm.asyncBefore"
|
||||||
|
label="异步前"
|
||||||
|
value="异步前"
|
||||||
|
@change="updateLoopAsync('asyncBefore')"
|
||||||
|
/>
|
||||||
|
<el-checkbox
|
||||||
|
v-model="loopInstanceForm.asyncAfter"
|
||||||
|
label="异步后"
|
||||||
|
value="异步后"
|
||||||
|
@change="updateLoopAsync('asyncAfter')"
|
||||||
|
/>
|
||||||
|
<el-checkbox
|
||||||
|
v-model="loopInstanceForm.exclusive"
|
||||||
|
v-if="loopInstanceForm.asyncAfter || loopInstanceForm.asyncBefore"
|
||||||
|
label="排除"
|
||||||
|
value="排除"
|
||||||
|
@change="updateLoopAsync('exclusive')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
label="重试周期"
|
||||||
|
prop="timeCycle"
|
||||||
|
v-if="loopInstanceForm.asyncAfter || loopInstanceForm.asyncBefore"
|
||||||
|
key="timeCycle"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
v-model="loopInstanceForm.timeCycle"
|
||||||
|
clearable
|
||||||
|
@change="updateLoopTimeCycle"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import {
|
||||||
|
ApproveMethodType,
|
||||||
|
APPROVE_METHODS,
|
||||||
|
} from '@/components/SimpleProcessDesignerV2/src/consts';
|
||||||
|
|
||||||
|
defineOptions({ name: 'ElementMultiInstance' });
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
businessObject: Object,
|
||||||
|
type: String,
|
||||||
|
id: String,
|
||||||
|
});
|
||||||
|
const prefix = inject('prefix');
|
||||||
|
const loopCharacteristics = ref('');
|
||||||
|
//默认配置,用来覆盖原始不存在的选项,避免报错
|
||||||
|
const defaultLoopInstanceForm = ref({
|
||||||
|
completionCondition: '',
|
||||||
|
loopCardinality: '',
|
||||||
|
extensionElements: [],
|
||||||
|
asyncAfter: false,
|
||||||
|
asyncBefore: false,
|
||||||
|
exclusive: false,
|
||||||
|
});
|
||||||
|
const loopInstanceForm = ref<any>({});
|
||||||
|
const bpmnElement = ref(null);
|
||||||
|
const multiLoopInstance = ref(null);
|
||||||
|
const bpmnInstances = () => (window as any)?.bpmnInstances;
|
||||||
|
|
||||||
|
const getElementLoop = (businessObject) => {
|
||||||
|
if (!businessObject.loopCharacteristics) {
|
||||||
|
loopCharacteristics.value = 'Null';
|
||||||
|
loopInstanceForm.value = {};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
businessObject.loopCharacteristics.$type ===
|
||||||
|
'bpmn:StandardLoopCharacteristics'
|
||||||
|
) {
|
||||||
|
loopCharacteristics.value = 'StandardLoop';
|
||||||
|
loopInstanceForm.value = {};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (businessObject.loopCharacteristics.isSequential) {
|
||||||
|
loopCharacteristics.value = 'SequentialMultiInstance';
|
||||||
|
} else {
|
||||||
|
loopCharacteristics.value = 'ParallelMultiInstance';
|
||||||
|
}
|
||||||
|
// 合并配置
|
||||||
|
loopInstanceForm.value = {
|
||||||
|
...defaultLoopInstanceForm.value,
|
||||||
|
...businessObject.loopCharacteristics,
|
||||||
|
completionCondition:
|
||||||
|
businessObject.loopCharacteristics?.completionCondition?.body ?? '',
|
||||||
|
loopCardinality:
|
||||||
|
businessObject.loopCharacteristics?.loopCardinality?.body ?? '',
|
||||||
|
};
|
||||||
|
// 保留当前元素 businessObject 上的 loopCharacteristics 实例
|
||||||
|
multiLoopInstance.value =
|
||||||
|
bpmnInstances().bpmnElement.businessObject.loopCharacteristics;
|
||||||
|
// 更新表单
|
||||||
|
if (
|
||||||
|
businessObject.loopCharacteristics.extensionElements &&
|
||||||
|
businessObject.loopCharacteristics.extensionElements.values &&
|
||||||
|
businessObject.loopCharacteristics.extensionElements.values.length
|
||||||
|
) {
|
||||||
|
loopInstanceForm.value['timeCycle'] =
|
||||||
|
businessObject.loopCharacteristics.extensionElements.values[0].body;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeLoopCharacteristicsType = (type) => {
|
||||||
|
// this.loopInstanceForm = { ...this.defaultLoopInstanceForm }; // 切换类型取消原表单配置
|
||||||
|
// 取消多实例配置
|
||||||
|
if (type === 'Null') {
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
|
loopCharacteristics: null,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 配置循环
|
||||||
|
if (type === 'StandardLoop') {
|
||||||
|
const loopCharacteristicsObject = bpmnInstances().moddle.create(
|
||||||
|
'bpmn:StandardLoopCharacteristics',
|
||||||
|
);
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
|
loopCharacteristics: loopCharacteristicsObject,
|
||||||
|
});
|
||||||
|
multiLoopInstance.value = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 时序
|
||||||
|
if (type === 'SequentialMultiInstance') {
|
||||||
|
multiLoopInstance.value = bpmnInstances().moddle.create(
|
||||||
|
'bpmn:MultiInstanceLoopCharacteristics',
|
||||||
|
{ isSequential: true },
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
multiLoopInstance.value = bpmnInstances().moddle.create(
|
||||||
|
'bpmn:MultiInstanceLoopCharacteristics',
|
||||||
|
{ collection: '${coll_userList}' },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
|
loopCharacteristics: toRaw(multiLoopInstance.value),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 循环基数
|
||||||
|
const updateLoopCardinality = (cardinality) => {
|
||||||
|
let loopCardinality = null;
|
||||||
|
if (cardinality && cardinality.length) {
|
||||||
|
loopCardinality = bpmnInstances().moddle.create('bpmn:FormalExpression', {
|
||||||
|
body: cardinality,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
bpmnInstances().modeling.updateModdleProperties(
|
||||||
|
toRaw(bpmnElement.value),
|
||||||
|
multiLoopInstance.value,
|
||||||
|
{
|
||||||
|
loopCardinality,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 完成条件
|
||||||
|
const updateLoopCondition = (condition) => {
|
||||||
|
let completionCondition = null;
|
||||||
|
if (condition && condition.length) {
|
||||||
|
completionCondition = bpmnInstances().moddle.create(
|
||||||
|
'bpmn:FormalExpression',
|
||||||
|
{
|
||||||
|
body: condition,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
bpmnInstances().modeling.updateModdleProperties(
|
||||||
|
toRaw(bpmnElement.value),
|
||||||
|
multiLoopInstance.value,
|
||||||
|
{
|
||||||
|
completionCondition,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 重试周期
|
||||||
|
const updateLoopTimeCycle = (timeCycle) => {
|
||||||
|
const extensionElements = bpmnInstances().moddle.create(
|
||||||
|
'bpmn:ExtensionElements',
|
||||||
|
{
|
||||||
|
values: [
|
||||||
|
bpmnInstances().moddle.create(`${prefix}:FailedJobRetryTimeCycle`, {
|
||||||
|
body: timeCycle,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
bpmnInstances().modeling.updateModdleProperties(
|
||||||
|
toRaw(bpmnElement.value),
|
||||||
|
multiLoopInstance.value,
|
||||||
|
{
|
||||||
|
extensionElements,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 直接更新的基础信息
|
||||||
|
const updateLoopBase = () => {
|
||||||
|
bpmnInstances().modeling.updateModdleProperties(
|
||||||
|
toRaw(bpmnElement.value),
|
||||||
|
multiLoopInstance.value,
|
||||||
|
{
|
||||||
|
collection: loopInstanceForm.value.collection || null,
|
||||||
|
elementVariable: loopInstanceForm.value.elementVariable || null,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 各异步状态
|
||||||
|
const updateLoopAsync = (key) => {
|
||||||
|
const { asyncBefore, asyncAfter } = loopInstanceForm.value;
|
||||||
|
let asyncAttr = Object.create(null);
|
||||||
|
if (!asyncBefore && !asyncAfter) {
|
||||||
|
// this.$set(this.loopInstanceForm, "exclusive", false);
|
||||||
|
loopInstanceForm.value['exclusive'] = false;
|
||||||
|
asyncAttr = {
|
||||||
|
asyncBefore: false,
|
||||||
|
asyncAfter: false,
|
||||||
|
exclusive: false,
|
||||||
|
extensionElements: null,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
asyncAttr[key] = loopInstanceForm.value[key];
|
||||||
|
}
|
||||||
|
bpmnInstances().modeling.updateModdleProperties(
|
||||||
|
toRaw(bpmnElement.value),
|
||||||
|
multiLoopInstance.value,
|
||||||
|
asyncAttr,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeConfig = (config) => {
|
||||||
|
if (config === '依次审批') {
|
||||||
|
changeLoopCharacteristicsType('SequentialMultiInstance');
|
||||||
|
updateLoopCardinality('1');
|
||||||
|
updateLoopCondition('${ nrOfCompletedInstances >= nrOfInstances }');
|
||||||
|
} else if (config === '会签') {
|
||||||
|
changeLoopCharacteristicsType('ParallelMultiInstance');
|
||||||
|
updateLoopCondition('${ nrOfCompletedInstances >= nrOfInstances }');
|
||||||
|
} else if (config === '或签') {
|
||||||
|
changeLoopCharacteristicsType('ParallelMultiInstance');
|
||||||
|
updateLoopCondition('${ nrOfCompletedInstances > 0 }');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* -----新版本多实例-----
|
||||||
|
*/
|
||||||
|
const approveMethod = ref();
|
||||||
|
const approveRatio = ref(100);
|
||||||
|
const otherExtensions = ref();
|
||||||
|
const getElementLoopNew = () => {
|
||||||
|
if (props.type === 'UserTask') {
|
||||||
|
const extensionElements =
|
||||||
|
bpmnElement.value.businessObject?.extensionElements ??
|
||||||
|
bpmnInstances().moddle.create('bpmn:ExtensionElements', { values: [] });
|
||||||
|
approveMethod.value = extensionElements.values.filter(
|
||||||
|
(ex) => ex.$type === `${prefix}:ApproveMethod`,
|
||||||
|
)?.[0]?.value;
|
||||||
|
|
||||||
|
otherExtensions.value =
|
||||||
|
extensionElements.values.filter(
|
||||||
|
(ex) => ex.$type !== `${prefix}:ApproveMethod`,
|
||||||
|
) ?? [];
|
||||||
|
|
||||||
|
if (!approveMethod.value) {
|
||||||
|
approveMethod.value = ApproveMethodType.SEQUENTIAL_APPROVE;
|
||||||
|
updateLoopCharacteristics();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const onApproveMethodChange = () => {
|
||||||
|
approveRatio.value = 100;
|
||||||
|
updateLoopCharacteristics();
|
||||||
|
};
|
||||||
|
const onApproveRatioChange = () => {
|
||||||
|
updateLoopCharacteristics();
|
||||||
|
};
|
||||||
|
const updateLoopCharacteristics = () => {
|
||||||
|
// 根据ApproveMethod生成multiInstanceLoopCharacteristics节点
|
||||||
|
if (approveMethod.value === ApproveMethodType.RANDOM_SELECT_ONE_APPROVE) {
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
|
loopCharacteristics: null,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (approveMethod.value === ApproveMethodType.APPROVE_BY_RATIO) {
|
||||||
|
multiLoopInstance.value = bpmnInstances().moddle.create(
|
||||||
|
'bpmn:MultiInstanceLoopCharacteristics',
|
||||||
|
{ isSequential: false, collection: '${coll_userList}' },
|
||||||
|
);
|
||||||
|
multiLoopInstance.value.completionCondition =
|
||||||
|
bpmnInstances().moddle.create('bpmn:FormalExpression', {
|
||||||
|
body:
|
||||||
|
'${ nrOfCompletedInstances/nrOfInstances >= ' +
|
||||||
|
approveRatio.value / 100 +
|
||||||
|
'}',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (approveMethod.value === ApproveMethodType.ANY_APPROVE) {
|
||||||
|
multiLoopInstance.value = bpmnInstances().moddle.create(
|
||||||
|
'bpmn:MultiInstanceLoopCharacteristics',
|
||||||
|
{ isSequential: false, collection: '${coll_userList}' },
|
||||||
|
);
|
||||||
|
multiLoopInstance.value.completionCondition =
|
||||||
|
bpmnInstances().moddle.create('bpmn:FormalExpression', {
|
||||||
|
body: '${ nrOfCompletedInstances > 0 }',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (approveMethod.value === ApproveMethodType.SEQUENTIAL_APPROVE) {
|
||||||
|
multiLoopInstance.value = bpmnInstances().moddle.create(
|
||||||
|
'bpmn:MultiInstanceLoopCharacteristics',
|
||||||
|
{ isSequential: true, collection: '${coll_userList}' },
|
||||||
|
);
|
||||||
|
multiLoopInstance.value.loopCardinality = bpmnInstances().moddle.create(
|
||||||
|
'bpmn:FormalExpression',
|
||||||
|
{
|
||||||
|
body: '1',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
multiLoopInstance.value.completionCondition =
|
||||||
|
bpmnInstances().moddle.create('bpmn:FormalExpression', {
|
||||||
|
body: '${ nrOfCompletedInstances >= nrOfInstances }',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
|
loopCharacteristics: toRaw(multiLoopInstance.value),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加ApproveMethod到ExtensionElements
|
||||||
|
const extensions = bpmnInstances().moddle.create('bpmn:ExtensionElements', {
|
||||||
|
values: [
|
||||||
|
...otherExtensions.value,
|
||||||
|
bpmnInstances().moddle.create(`${prefix}:ApproveMethod`, {
|
||||||
|
value: approveMethod.value,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
|
extensionElements: extensions,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
multiLoopInstance.value = null;
|
||||||
|
bpmnElement.value = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.id,
|
||||||
|
(val) => {
|
||||||
|
if (val) {
|
||||||
|
nextTick(() => {
|
||||||
|
bpmnElement.value = bpmnInstances().bpmnElement;
|
||||||
|
// getElementLoop(val)
|
||||||
|
getElementLoopNew();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
<template>
|
||||||
|
<div class="panel-tab__content">
|
||||||
|
<div class="element-property input-property">
|
||||||
|
<div class="element-property__label">元素文档:</div>
|
||||||
|
<div class="element-property__value">
|
||||||
|
<el-input
|
||||||
|
type="textarea"
|
||||||
|
v-model="documentation"
|
||||||
|
resize="vertical"
|
||||||
|
:autosize="{ minRows: 2, maxRows: 4 }"
|
||||||
|
@input="updateDocumentation"
|
||||||
|
@blur="updateDocumentation"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
defineOptions({ name: 'ElementOtherConfig' });
|
||||||
|
const props = defineProps({
|
||||||
|
id: String,
|
||||||
|
});
|
||||||
|
const documentation = ref('');
|
||||||
|
const bpmnElement = ref();
|
||||||
|
const bpmnInstances = () => (window as any).bpmnInstances;
|
||||||
|
const updateDocumentation = () => {
|
||||||
|
(bpmnElement.value && bpmnElement.value.id === props.id) ||
|
||||||
|
(bpmnElement.value = bpmnInstances().elementRegistry.get(props.id));
|
||||||
|
const documentations = bpmnInstances().bpmnFactory.create(
|
||||||
|
'bpmn:Documentation',
|
||||||
|
{
|
||||||
|
text: documentation.value,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
|
documentation: [documentations],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
bpmnElement.value = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.id,
|
||||||
|
(id) => {
|
||||||
|
if (id && id.length) {
|
||||||
|
nextTick(() => {
|
||||||
|
const documentations =
|
||||||
|
bpmnInstances().bpmnElement.businessObject?.documentation;
|
||||||
|
documentation.value =
|
||||||
|
documentations && documentations.length ? documentations[0].text : '';
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
documentation.value = '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,195 @@
|
|||||||
|
<template>
|
||||||
|
<div class="panel-tab__content">
|
||||||
|
<el-table :data="elementPropertyList" max-height="240" fit border>
|
||||||
|
<el-table-column label="序号" width="50px" type="index" />
|
||||||
|
<el-table-column
|
||||||
|
label="属性名"
|
||||||
|
prop="name"
|
||||||
|
min-width="100px"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
label="属性值"
|
||||||
|
prop="value"
|
||||||
|
min-width="100px"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column label="操作" width="110px">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button
|
||||||
|
link
|
||||||
|
@click="openAttributesForm(scope.row, scope.$index)"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
编辑
|
||||||
|
</el-button>
|
||||||
|
<el-divider direction="vertical" />
|
||||||
|
<el-button
|
||||||
|
link
|
||||||
|
size="small"
|
||||||
|
style="color: #ff4d4f"
|
||||||
|
@click="removeAttributes(scope.row, scope.$index)"
|
||||||
|
>
|
||||||
|
移除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<div class="element-drawer__button">
|
||||||
|
<XButton
|
||||||
|
type="primary"
|
||||||
|
preIcon="ep:plus"
|
||||||
|
title="添加属性"
|
||||||
|
@click="openAttributesForm(null, -1)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-dialog
|
||||||
|
v-model="propertyFormModelVisible"
|
||||||
|
title="属性配置"
|
||||||
|
width="600px"
|
||||||
|
append-to-body
|
||||||
|
destroy-on-close
|
||||||
|
>
|
||||||
|
<el-form :model="propertyForm" label-width="80px" ref="attributeFormRef">
|
||||||
|
<el-form-item label="属性名:" prop="name">
|
||||||
|
<el-input v-model="propertyForm.name" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="属性值:" prop="value">
|
||||||
|
<el-input v-model="propertyForm.value" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="propertyFormModelVisible = false">取 消</el-button>
|
||||||
|
<el-button type="primary" @click="saveAttribute">确 定</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ElMessageBox } from 'element-plus';
|
||||||
|
defineOptions({ name: 'ElementProperties' });
|
||||||
|
const props = defineProps({
|
||||||
|
id: String,
|
||||||
|
type: String,
|
||||||
|
});
|
||||||
|
const prefix = inject('prefix');
|
||||||
|
// const width = inject('width')
|
||||||
|
|
||||||
|
const elementPropertyList = ref<any[]>([]);
|
||||||
|
const propertyForm = ref<any>({});
|
||||||
|
const editingPropertyIndex = ref(-1);
|
||||||
|
const propertyFormModelVisible = ref(false);
|
||||||
|
const bpmnElement = ref();
|
||||||
|
const otherExtensionList = ref();
|
||||||
|
const bpmnElementProperties = ref();
|
||||||
|
const bpmnElementPropertyList = ref();
|
||||||
|
const attributeFormRef = ref();
|
||||||
|
const bpmnInstances = () => (window as any)?.bpmnInstances;
|
||||||
|
|
||||||
|
const resetAttributesList = () => {
|
||||||
|
bpmnElement.value = bpmnInstances().bpmnElement;
|
||||||
|
otherExtensionList.value = []; // 其他扩展配置
|
||||||
|
bpmnElementProperties.value =
|
||||||
|
// bpmnElement.value.businessObject?.extensionElements?.filter((ex) => {
|
||||||
|
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
|
||||||
|
(ex) => {
|
||||||
|
if (ex.$type !== `${prefix}:Properties`) {
|
||||||
|
otherExtensionList.value.push(ex);
|
||||||
|
}
|
||||||
|
return ex.$type === `${prefix}:Properties`;
|
||||||
|
},
|
||||||
|
) ?? [];
|
||||||
|
|
||||||
|
// 保存所有的 扩展属性字段
|
||||||
|
bpmnElementPropertyList.value = bpmnElementProperties.value.reduce(
|
||||||
|
(pre, current) => pre.concat(current.values),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
// 复制 显示
|
||||||
|
elementPropertyList.value = JSON.parse(
|
||||||
|
JSON.stringify(bpmnElementPropertyList.value ?? []),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
const openAttributesForm = (attr, index) => {
|
||||||
|
editingPropertyIndex.value = index;
|
||||||
|
propertyForm.value = index === -1 ? {} : JSON.parse(JSON.stringify(attr));
|
||||||
|
propertyFormModelVisible.value = true;
|
||||||
|
nextTick(() => {
|
||||||
|
if (attributeFormRef.value) attributeFormRef.value.clearValidate();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const removeAttributes = (attr, index) => {
|
||||||
|
console.log(attr, 'attr');
|
||||||
|
ElMessageBox.confirm('确认移除该属性吗?', '提示', {
|
||||||
|
confirmButtonText: '确 认',
|
||||||
|
cancelButtonText: '取 消',
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
elementPropertyList.value.splice(index, 1);
|
||||||
|
bpmnElementPropertyList.value.splice(index, 1);
|
||||||
|
// 新建一个属性字段的保存列表
|
||||||
|
const propertiesObject = bpmnInstances().moddle.create(
|
||||||
|
`${prefix}:Properties`,
|
||||||
|
{
|
||||||
|
values: bpmnElementPropertyList.value,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
updateElementExtensions(propertiesObject);
|
||||||
|
resetAttributesList();
|
||||||
|
})
|
||||||
|
.catch(() => console.info('操作取消'));
|
||||||
|
};
|
||||||
|
const saveAttribute = () => {
|
||||||
|
console.log(propertyForm.value, 'propertyForm.value');
|
||||||
|
const { name, value } = propertyForm.value;
|
||||||
|
if (editingPropertyIndex.value !== -1) {
|
||||||
|
bpmnInstances().modeling.updateModdleProperties(
|
||||||
|
toRaw(bpmnElement.value),
|
||||||
|
toRaw(bpmnElementPropertyList.value)[toRaw(editingPropertyIndex.value)],
|
||||||
|
{
|
||||||
|
name,
|
||||||
|
value,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// 新建属性字段
|
||||||
|
const newPropertyObject = bpmnInstances().moddle.create(
|
||||||
|
`${prefix}:Property`,
|
||||||
|
{
|
||||||
|
name,
|
||||||
|
value,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
// 新建一个属性字段的保存列表
|
||||||
|
const propertiesObject = bpmnInstances().moddle.create(
|
||||||
|
`${prefix}:Properties`,
|
||||||
|
{
|
||||||
|
values: bpmnElementPropertyList.value.concat([newPropertyObject]),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
updateElementExtensions(propertiesObject);
|
||||||
|
}
|
||||||
|
propertyFormModelVisible.value = false;
|
||||||
|
resetAttributesList();
|
||||||
|
};
|
||||||
|
const updateElementExtensions = (properties) => {
|
||||||
|
const extensions = bpmnInstances().moddle.create('bpmn:ExtensionElements', {
|
||||||
|
values: otherExtensionList.value.concat([properties]),
|
||||||
|
});
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
|
extensionElements: extensions,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.id,
|
||||||
|
(val) => {
|
||||||
|
if (val) {
|
||||||
|
val && val.length && resetAttributesList();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
<template>
|
||||||
|
<div class="panel-tab__content">
|
||||||
|
<div class="panel-tab__content--title">
|
||||||
|
<span
|
||||||
|
><Icon
|
||||||
|
icon="ep:menu"
|
||||||
|
style="margin-right: 8px; color: #555"
|
||||||
|
/>消息列表</span
|
||||||
|
>
|
||||||
|
<XButton
|
||||||
|
type="primary"
|
||||||
|
title="创建新消息"
|
||||||
|
preIcon="ep:plus"
|
||||||
|
@click="openModel('message')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<el-table :data="messageList" border>
|
||||||
|
<el-table-column type="index" label="序号" width="60px" />
|
||||||
|
<el-table-column
|
||||||
|
label="消息ID"
|
||||||
|
prop="id"
|
||||||
|
max-width="300px"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
label="消息名称"
|
||||||
|
prop="name"
|
||||||
|
max-width="300px"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
</el-table>
|
||||||
|
<div
|
||||||
|
class="panel-tab__content--title"
|
||||||
|
style="padding-top: 8px; margin-top: 8px; border-top: 1px solid #eee"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
><Icon
|
||||||
|
icon="ep:menu"
|
||||||
|
style="margin-right: 8px; color: #555"
|
||||||
|
/>信号列表</span
|
||||||
|
>
|
||||||
|
<XButton
|
||||||
|
type="primary"
|
||||||
|
title="创建新信号"
|
||||||
|
preIcon="ep:plus"
|
||||||
|
@click="openModel('signal')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<el-table :data="signalList" border>
|
||||||
|
<el-table-column type="index" label="序号" width="60px" />
|
||||||
|
<el-table-column
|
||||||
|
label="信号ID"
|
||||||
|
prop="id"
|
||||||
|
max-width="300px"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
label="信号名称"
|
||||||
|
prop="name"
|
||||||
|
max-width="300px"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<el-dialog
|
||||||
|
v-model="dialogVisible"
|
||||||
|
:title="modelConfig.title"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
width="400px"
|
||||||
|
append-to-body
|
||||||
|
destroy-on-close
|
||||||
|
>
|
||||||
|
<el-form :model="modelObjectForm" label-width="90px">
|
||||||
|
<el-form-item :label="modelConfig.idLabel">
|
||||||
|
<el-input v-model="modelObjectForm.id" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="modelConfig.nameLabel">
|
||||||
|
<el-input v-model="modelObjectForm.name" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||||
|
<el-button type="primary" @click="addNewObject">保 存</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
defineOptions({ name: 'SignalAndMassage' });
|
||||||
|
|
||||||
|
const message = useMessage();
|
||||||
|
const signalList = ref<any[]>([]);
|
||||||
|
const messageList = ref<any[]>([]);
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
const modelType = ref('');
|
||||||
|
const modelObjectForm = ref<any>({});
|
||||||
|
const rootElements = ref();
|
||||||
|
const messageIdMap = ref();
|
||||||
|
const signalIdMap = ref();
|
||||||
|
const modelConfig = computed(() => {
|
||||||
|
if (modelType.value === 'message') {
|
||||||
|
return { title: '创建消息', idLabel: '消息ID', nameLabel: '消息名称' };
|
||||||
|
} else {
|
||||||
|
return { title: '创建信号', idLabel: '信号ID', nameLabel: '信号名称' };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const bpmnInstances = () => (window as any)?.bpmnInstances;
|
||||||
|
|
||||||
|
const initDataList = () => {
|
||||||
|
console.log(window, 'window');
|
||||||
|
rootElements.value = bpmnInstances().modeler.getDefinitions().rootElements;
|
||||||
|
messageIdMap.value = {};
|
||||||
|
signalIdMap.value = {};
|
||||||
|
messageList.value = [];
|
||||||
|
signalList.value = [];
|
||||||
|
rootElements.value.forEach((el) => {
|
||||||
|
if (el.$type === 'bpmn:Message') {
|
||||||
|
messageIdMap.value[el.id] = true;
|
||||||
|
messageList.value.push({ ...el });
|
||||||
|
}
|
||||||
|
if (el.$type === 'bpmn:Signal') {
|
||||||
|
signalIdMap.value[el.id] = true;
|
||||||
|
signalList.value.push({ ...el });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const openModel = (type) => {
|
||||||
|
modelType.value = type;
|
||||||
|
modelObjectForm.value = {};
|
||||||
|
dialogVisible.value = true;
|
||||||
|
};
|
||||||
|
const addNewObject = () => {
|
||||||
|
if (modelType.value === 'message') {
|
||||||
|
if (messageIdMap.value[modelObjectForm.value.id]) {
|
||||||
|
message.error('该消息已存在,请修改id后重新保存');
|
||||||
|
}
|
||||||
|
const messageRef = bpmnInstances().moddle.create(
|
||||||
|
'bpmn:Message',
|
||||||
|
modelObjectForm.value,
|
||||||
|
);
|
||||||
|
rootElements.value.push(messageRef);
|
||||||
|
} else {
|
||||||
|
if (signalIdMap.value[modelObjectForm.value.id]) {
|
||||||
|
message.error('该信号已存在,请修改id后重新保存');
|
||||||
|
}
|
||||||
|
const signalRef = bpmnInstances().moddle.create(
|
||||||
|
'bpmn:Signal',
|
||||||
|
modelObjectForm.value,
|
||||||
|
);
|
||||||
|
rootElements.value.push(signalRef);
|
||||||
|
}
|
||||||
|
dialogVisible.value = false;
|
||||||
|
initDataList();
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initDataList();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
<template>
|
||||||
|
<div class="panel-tab__content">
|
||||||
|
<el-form size="small" label-width="90px">
|
||||||
|
<!-- add by 芋艿:由于「异步延续」暂时用不到,所以这里 display 为 none -->
|
||||||
|
<el-form-item label="异步延续" style="display: none">
|
||||||
|
<el-checkbox
|
||||||
|
v-model="taskConfigForm.asyncBefore"
|
||||||
|
label="异步前"
|
||||||
|
value="异步前"
|
||||||
|
@change="changeTaskAsync"
|
||||||
|
/>
|
||||||
|
<el-checkbox
|
||||||
|
v-model="taskConfigForm.asyncAfter"
|
||||||
|
label="异步后"
|
||||||
|
value="异步后"
|
||||||
|
@change="changeTaskAsync"
|
||||||
|
/>
|
||||||
|
<el-checkbox
|
||||||
|
v-model="taskConfigForm.exclusive"
|
||||||
|
v-if="taskConfigForm.asyncAfter || taskConfigForm.asyncBefore"
|
||||||
|
label="排除"
|
||||||
|
value="排除"
|
||||||
|
@change="changeTaskAsync"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<component :is="witchTaskComponent" v-bind="$props" />
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { installedComponent } from './data';
|
||||||
|
|
||||||
|
defineOptions({ name: 'ElementTaskConfig' });
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
id: String,
|
||||||
|
type: String,
|
||||||
|
});
|
||||||
|
const taskConfigForm = ref({
|
||||||
|
asyncAfter: false,
|
||||||
|
asyncBefore: false,
|
||||||
|
exclusive: false,
|
||||||
|
});
|
||||||
|
const witchTaskComponent = ref();
|
||||||
|
|
||||||
|
const bpmnElement = ref();
|
||||||
|
|
||||||
|
const bpmnInstances = () => (window as any).bpmnInstances;
|
||||||
|
const changeTaskAsync = () => {
|
||||||
|
if (!taskConfigForm.value.asyncBefore && !taskConfigForm.value.asyncAfter) {
|
||||||
|
taskConfigForm.value.exclusive = false;
|
||||||
|
}
|
||||||
|
bpmnInstances().modeling.updateProperties(bpmnInstances().bpmnElement, {
|
||||||
|
...taskConfigForm.value,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.id,
|
||||||
|
() => {
|
||||||
|
bpmnElement.value = bpmnInstances().bpmnElement;
|
||||||
|
taskConfigForm.value.asyncBefore =
|
||||||
|
bpmnElement.value?.businessObject?.asyncBefore;
|
||||||
|
taskConfigForm.value.asyncAfter =
|
||||||
|
bpmnElement.value?.businessObject?.asyncAfter;
|
||||||
|
taskConfigForm.value.exclusive =
|
||||||
|
bpmnElement.value?.businessObject?.exclusive;
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
watch(
|
||||||
|
() => props.type,
|
||||||
|
() => {
|
||||||
|
if (props.type) {
|
||||||
|
witchTaskComponent.value = installedComponent[props.type].component;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import CallActivity from './task-components/CallActivity.vue';
|
||||||
|
import ReceiveTask from './task-components/ReceiveTask.vue';
|
||||||
|
import ScriptTask from './task-components/ScriptTask.vue';
|
||||||
|
import ServiceTask from './task-components/ServiceTask.vue';
|
||||||
|
import UserTask from './task-components/UserTask.vue';
|
||||||
|
|
||||||
|
export const installedComponent = {
|
||||||
|
UserTask: {
|
||||||
|
name: '用户任务',
|
||||||
|
component: UserTask,
|
||||||
|
},
|
||||||
|
ServiceTask: {
|
||||||
|
name: '服务任务',
|
||||||
|
component: ServiceTask,
|
||||||
|
},
|
||||||
|
ScriptTask: {
|
||||||
|
name: '脚本任务',
|
||||||
|
component: ScriptTask,
|
||||||
|
},
|
||||||
|
ReceiveTask: {
|
||||||
|
name: '接收任务',
|
||||||
|
component: ReceiveTask,
|
||||||
|
},
|
||||||
|
CallActivity: {
|
||||||
|
name: '调用活动',
|
||||||
|
component: CallActivity,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getTaskCollapseItemName = (elementType) => {
|
||||||
|
return installedComponent[elementType].name;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const isTaskCollapseItemShow = (elementType) => {
|
||||||
|
return installedComponent[elementType];
|
||||||
|
};
|
||||||
@@ -0,0 +1,325 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-form label-width="100px">
|
||||||
|
<el-form-item label="实例名称" prop="processInstanceName">
|
||||||
|
<el-input
|
||||||
|
v-model="formData.processInstanceName"
|
||||||
|
clearable
|
||||||
|
placeholder="请输入实例名称"
|
||||||
|
@change="updateCallActivityAttr('processInstanceName')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<!-- TODO 需要可选择已存在的流程 -->
|
||||||
|
<el-form-item label="被调用流程" prop="calledElement">
|
||||||
|
<el-input
|
||||||
|
v-model="formData.calledElement"
|
||||||
|
clearable
|
||||||
|
placeholder="请输入被调用流程"
|
||||||
|
@change="updateCallActivityAttr('calledElement')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="继承变量" prop="inheritVariables">
|
||||||
|
<el-switch
|
||||||
|
v-model="formData.inheritVariables"
|
||||||
|
@change="updateCallActivityAttr('inheritVariables')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="继承业务键" prop="inheritBusinessKey">
|
||||||
|
<el-switch
|
||||||
|
v-model="formData.inheritBusinessKey"
|
||||||
|
@change="updateCallActivityAttr('inheritBusinessKey')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item
|
||||||
|
v-if="!formData.inheritBusinessKey"
|
||||||
|
label="业务键表达式"
|
||||||
|
prop="businessKey"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
v-model="formData.businessKey"
|
||||||
|
clearable
|
||||||
|
placeholder="请输入业务键表达式"
|
||||||
|
@change="updateCallActivityAttr('businessKey')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-divider />
|
||||||
|
<div>
|
||||||
|
<div class="mb-10px flex">
|
||||||
|
<el-text>输入参数</el-text>
|
||||||
|
<XButton
|
||||||
|
class="ml-auto"
|
||||||
|
type="primary"
|
||||||
|
preIcon="ep:plus"
|
||||||
|
title="添加参数"
|
||||||
|
size="small"
|
||||||
|
@click="openVariableForm('in', null, -1)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<el-table :data="inVariableList" max-height="240" fit border>
|
||||||
|
<el-table-column
|
||||||
|
label="源"
|
||||||
|
prop="source"
|
||||||
|
min-width="100px"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
label="目标"
|
||||||
|
prop="target"
|
||||||
|
min-width="100px"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column label="操作" width="110px">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button
|
||||||
|
link
|
||||||
|
@click="openVariableForm('in', scope.row, scope.$index)"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
编辑
|
||||||
|
</el-button>
|
||||||
|
<el-divider direction="vertical" />
|
||||||
|
<el-button
|
||||||
|
link
|
||||||
|
size="small"
|
||||||
|
style="color: #ff4d4f"
|
||||||
|
@click="removeVariable('in', scope.$index)"
|
||||||
|
>
|
||||||
|
移除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-divider />
|
||||||
|
<div>
|
||||||
|
<div class="mb-10px flex">
|
||||||
|
<el-text>输出参数</el-text>
|
||||||
|
<XButton
|
||||||
|
class="ml-auto"
|
||||||
|
type="primary"
|
||||||
|
preIcon="ep:plus"
|
||||||
|
title="添加参数"
|
||||||
|
size="small"
|
||||||
|
@click="openVariableForm('out', null, -1)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<el-table :data="outVariableList" max-height="240" fit border>
|
||||||
|
<el-table-column
|
||||||
|
label="源"
|
||||||
|
prop="source"
|
||||||
|
min-width="100px"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
label="目标"
|
||||||
|
prop="target"
|
||||||
|
min-width="100px"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column label="操作" width="110px">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button
|
||||||
|
link
|
||||||
|
@click="openVariableForm('out', scope.row, scope.$index)"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
编辑
|
||||||
|
</el-button>
|
||||||
|
<el-divider direction="vertical" />
|
||||||
|
<el-button
|
||||||
|
link
|
||||||
|
size="small"
|
||||||
|
style="color: #ff4d4f"
|
||||||
|
@click="removeVariable('out', scope.$index)"
|
||||||
|
>
|
||||||
|
移除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<!-- 添加或修改参数 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="variableDialogVisible"
|
||||||
|
title="参数配置"
|
||||||
|
width="600px"
|
||||||
|
append-to-body
|
||||||
|
destroy-on-close
|
||||||
|
>
|
||||||
|
<el-form
|
||||||
|
:model="varialbeFormData"
|
||||||
|
label-width="80px"
|
||||||
|
ref="varialbeFormRef"
|
||||||
|
>
|
||||||
|
<el-form-item label="源:" prop="source">
|
||||||
|
<el-input v-model="varialbeFormData.source" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="目标:" prop="target">
|
||||||
|
<el-input v-model="varialbeFormData.target" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="variableDialogVisible = false">取 消</el-button>
|
||||||
|
<el-button type="primary" @click="saveVariable">确 定</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
defineOptions({ name: 'CallActivity' });
|
||||||
|
const props = defineProps({
|
||||||
|
id: String,
|
||||||
|
type: String,
|
||||||
|
});
|
||||||
|
const prefix = inject('prefix');
|
||||||
|
const message = useMessage();
|
||||||
|
|
||||||
|
const formData = ref({
|
||||||
|
processInstanceName: '',
|
||||||
|
calledElement: '',
|
||||||
|
inheritVariables: false,
|
||||||
|
businessKey: '',
|
||||||
|
inheritBusinessKey: false,
|
||||||
|
calledElementType: 'key',
|
||||||
|
});
|
||||||
|
const inVariableList = ref();
|
||||||
|
const outVariableList = ref();
|
||||||
|
const variableType = ref(); // 参数类型
|
||||||
|
const editingVariableIndex = ref(-1); // 编辑参数下标
|
||||||
|
const variableDialogVisible = ref(false);
|
||||||
|
const varialbeFormRef = ref();
|
||||||
|
const varialbeFormData = ref({
|
||||||
|
source: '',
|
||||||
|
target: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
const bpmnInstances = () => (window as any)?.bpmnInstances;
|
||||||
|
const bpmnElement = ref();
|
||||||
|
const otherExtensionList = ref();
|
||||||
|
|
||||||
|
const initCallActivity = () => {
|
||||||
|
bpmnElement.value = bpmnInstances().bpmnElement;
|
||||||
|
console.log(bpmnElement.value.businessObject, 'callActivity');
|
||||||
|
|
||||||
|
// 初始化所有配置项
|
||||||
|
Object.keys(formData.value).forEach((key) => {
|
||||||
|
formData.value[key] =
|
||||||
|
bpmnElement.value.businessObject[key] ?? formData.value[key];
|
||||||
|
});
|
||||||
|
|
||||||
|
otherExtensionList.value = []; // 其他扩展配置
|
||||||
|
inVariableList.value = [];
|
||||||
|
outVariableList.value = [];
|
||||||
|
// 初始化输入参数
|
||||||
|
bpmnElement.value.businessObject?.extensionElements?.values?.forEach((ex) => {
|
||||||
|
if (ex.$type === `${prefix}:In`) {
|
||||||
|
inVariableList.value.push(ex);
|
||||||
|
} else if (ex.$type === `${prefix}:Out`) {
|
||||||
|
outVariableList.value.push(ex);
|
||||||
|
} else {
|
||||||
|
otherExtensionList.value.push(ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 默认添加
|
||||||
|
// bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
|
// calledElementType: 'key'
|
||||||
|
// })
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateCallActivityAttr = (attr) => {
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
|
[attr]: formData.value[attr],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const openVariableForm = (type, data, index) => {
|
||||||
|
editingVariableIndex.value = index;
|
||||||
|
variableType.value = type;
|
||||||
|
varialbeFormData.value = index === -1 ? {} : { ...data };
|
||||||
|
variableDialogVisible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeVariable = async (type, index) => {
|
||||||
|
try {
|
||||||
|
await message.delConfirm();
|
||||||
|
if (type === 'in') {
|
||||||
|
inVariableList.value.splice(index, 1);
|
||||||
|
}
|
||||||
|
if (type === 'out') {
|
||||||
|
outVariableList.value.splice(index, 1);
|
||||||
|
}
|
||||||
|
updateElementExtensions();
|
||||||
|
} catch {}
|
||||||
|
};
|
||||||
|
|
||||||
|
const saveVariable = () => {
|
||||||
|
if (editingVariableIndex.value === -1) {
|
||||||
|
if (variableType.value === 'in') {
|
||||||
|
inVariableList.value.push(
|
||||||
|
bpmnInstances().moddle.create(`${prefix}:In`, {
|
||||||
|
...varialbeFormData.value,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (variableType.value === 'out') {
|
||||||
|
outVariableList.value.push(
|
||||||
|
bpmnInstances().moddle.create(`${prefix}:Out`, {
|
||||||
|
...varialbeFormData.value,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
updateElementExtensions();
|
||||||
|
} else {
|
||||||
|
if (variableType.value === 'in') {
|
||||||
|
inVariableList.value[editingVariableIndex.value].source =
|
||||||
|
varialbeFormData.value.source;
|
||||||
|
inVariableList.value[editingVariableIndex.value].target =
|
||||||
|
varialbeFormData.value.target;
|
||||||
|
}
|
||||||
|
if (variableType.value === 'out') {
|
||||||
|
outVariableList.value[editingVariableIndex.value].source =
|
||||||
|
varialbeFormData.value.source;
|
||||||
|
outVariableList.value[editingVariableIndex.value].target =
|
||||||
|
varialbeFormData.value.target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
variableDialogVisible.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateElementExtensions = () => {
|
||||||
|
const extensions = bpmnInstances().moddle.create('bpmn:ExtensionElements', {
|
||||||
|
values: [
|
||||||
|
...inVariableList.value,
|
||||||
|
...outVariableList.value,
|
||||||
|
...otherExtensionList.value,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
|
extensionElements: extensions,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.id,
|
||||||
|
(val) => {
|
||||||
|
val &&
|
||||||
|
val.length &&
|
||||||
|
nextTick(() => {
|
||||||
|
initCallActivity();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
<!-- 表达式选择 -->
|
||||||
|
<template>
|
||||||
|
<Dialog title="请选择表达式" v-model="dialogVisible" width="1024px">
|
||||||
|
<ContentWrap>
|
||||||
|
<el-table
|
||||||
|
v-loading="loading"
|
||||||
|
:data="list"
|
||||||
|
:stripe="true"
|
||||||
|
:show-overflow-tooltip="true"
|
||||||
|
>
|
||||||
|
<el-table-column label="名字" align="center" prop="name" />
|
||||||
|
<el-table-column label="表达式" align="center" prop="expression" />
|
||||||
|
<el-table-column label="操作" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button link type="primary" @click="select(scope.row)">
|
||||||
|
选择
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!-- 分页 -->
|
||||||
|
<Pagination
|
||||||
|
:total="total"
|
||||||
|
v-model:page="queryParams.pageNo"
|
||||||
|
v-model:limit="queryParams.pageSize"
|
||||||
|
@pagination="getList"
|
||||||
|
/>
|
||||||
|
</ContentWrap>
|
||||||
|
</Dialog>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { CommonStatusEnum } from '@/utils/constants';
|
||||||
|
import {
|
||||||
|
ProcessExpressionApi,
|
||||||
|
ProcessExpressionVO,
|
||||||
|
} from '@/api/bpm/processExpression';
|
||||||
|
|
||||||
|
/** BPM 流程 表单 */
|
||||||
|
defineOptions({ name: 'ProcessExpressionDialog' });
|
||||||
|
|
||||||
|
const dialogVisible = ref(false); // 弹窗的是否展示
|
||||||
|
const loading = ref(true); // 列表的加载中
|
||||||
|
const list = ref<ProcessExpressionVO[]>([]); // 列表的数据
|
||||||
|
const total = ref(0); // 列表的总页数
|
||||||
|
const queryParams = reactive({
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
type: '',
|
||||||
|
status: CommonStatusEnum.ENABLE,
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 打开弹窗 */
|
||||||
|
const open = (type: string) => {
|
||||||
|
queryParams.pageNo = 1;
|
||||||
|
queryParams.type = type;
|
||||||
|
getList();
|
||||||
|
dialogVisible.value = true;
|
||||||
|
};
|
||||||
|
defineExpose({ open }); // 提供 open 方法,用于打开弹窗
|
||||||
|
|
||||||
|
/** 查询列表 */
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
const data =
|
||||||
|
await ProcessExpressionApi.getProcessExpressionPage(queryParams);
|
||||||
|
list.value = data.list;
|
||||||
|
total.value = data.total;
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 提交表单 */
|
||||||
|
const emit = defineEmits(['success']); // 定义 success 事件,用于操作成功后的回调
|
||||||
|
const select = async (row) => {
|
||||||
|
dialogVisible.value = false;
|
||||||
|
// 发送操作成功的事件
|
||||||
|
emit('select', row);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
<template>
|
||||||
|
<div style="margin-top: 16px">
|
||||||
|
<el-form-item label="消息实例">
|
||||||
|
<div
|
||||||
|
style="
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<el-select v-model="bindMessageId" @change="updateTaskMessage">
|
||||||
|
<el-option
|
||||||
|
v-for="key in Object.keys(messageMap)"
|
||||||
|
:value="key"
|
||||||
|
:label="messageMap[key]"
|
||||||
|
:key="key"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
<XButton
|
||||||
|
type="primary"
|
||||||
|
preIcon="ep:plus"
|
||||||
|
style="margin-left: 8px"
|
||||||
|
@click="openMessageModel"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
<el-dialog
|
||||||
|
v-model="messageModelVisible"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
title="创建新消息"
|
||||||
|
width="400px"
|
||||||
|
append-to-body
|
||||||
|
destroy-on-close
|
||||||
|
>
|
||||||
|
<el-form :model="newMessageForm" size="small" label-width="90px">
|
||||||
|
<el-form-item label="消息ID">
|
||||||
|
<el-input v-model="newMessageForm.id" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="消息名称">
|
||||||
|
<el-input v-model="newMessageForm.name" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button size="small" type="primary" @click="createNewMessage"
|
||||||
|
>确 认</el-button
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
defineOptions({ name: 'ReceiveTask' });
|
||||||
|
const props = defineProps({
|
||||||
|
id: String,
|
||||||
|
type: String,
|
||||||
|
});
|
||||||
|
|
||||||
|
const message = useMessage();
|
||||||
|
|
||||||
|
const bindMessageId = ref('');
|
||||||
|
const newMessageForm = ref<any>({});
|
||||||
|
const messageMap = ref<any>({});
|
||||||
|
const messageModelVisible = ref(false);
|
||||||
|
const bpmnElement = ref<any>();
|
||||||
|
const bpmnMessageRefsMap = ref<any>();
|
||||||
|
const bpmnRootElements = ref<any>();
|
||||||
|
|
||||||
|
const bpmnInstances = () => (window as any).bpmnInstances;
|
||||||
|
const getBindMessage = () => {
|
||||||
|
bpmnElement.value = bpmnInstances().bpmnElement;
|
||||||
|
bindMessageId.value =
|
||||||
|
bpmnElement.value.businessObject?.messageRef?.id || '-1';
|
||||||
|
};
|
||||||
|
const openMessageModel = () => {
|
||||||
|
messageModelVisible.value = true;
|
||||||
|
newMessageForm.value = {};
|
||||||
|
};
|
||||||
|
const createNewMessage = () => {
|
||||||
|
if (messageMap.value[newMessageForm.value.id]) {
|
||||||
|
message.error('该消息已存在,请修改id后重新保存');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const newMessage = bpmnInstances().moddle.create(
|
||||||
|
'bpmn:Message',
|
||||||
|
newMessageForm.value,
|
||||||
|
);
|
||||||
|
bpmnRootElements.value.push(newMessage);
|
||||||
|
messageMap.value[newMessageForm.value.id] = newMessageForm.value.name;
|
||||||
|
bpmnMessageRefsMap.value[newMessageForm.value.id] = newMessage;
|
||||||
|
messageModelVisible.value = false;
|
||||||
|
};
|
||||||
|
const updateTaskMessage = (messageId) => {
|
||||||
|
if (messageId === '-1') {
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
|
messageRef: null,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
|
messageRef: bpmnMessageRefsMap.value[messageId],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
bpmnMessageRefsMap.value = Object.create(null);
|
||||||
|
bpmnRootElements.value =
|
||||||
|
bpmnInstances().modeler.getDefinitions().rootElements;
|
||||||
|
bpmnRootElements.value
|
||||||
|
.filter((el) => el.$type === 'bpmn:Message')
|
||||||
|
.forEach((m) => {
|
||||||
|
bpmnMessageRefsMap.value[m.id] = m;
|
||||||
|
messageMap.value[m.id] = m.name;
|
||||||
|
});
|
||||||
|
messageMap.value['-1'] = '无';
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
bpmnElement.value = null;
|
||||||
|
});
|
||||||
|
watch(
|
||||||
|
() => props.id,
|
||||||
|
() => {
|
||||||
|
// bpmnElement.value = bpmnInstances().bpmnElement
|
||||||
|
nextTick(() => {
|
||||||
|
getBindMessage();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
<template>
|
||||||
|
<div style="margin-top: 16px">
|
||||||
|
<el-form-item label="脚本格式">
|
||||||
|
<el-input
|
||||||
|
v-model="scriptTaskForm.scriptFormat"
|
||||||
|
clearable
|
||||||
|
@input="updateElementTask()"
|
||||||
|
@change="updateElementTask()"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="脚本类型">
|
||||||
|
<el-select v-model="scriptTaskForm.scriptType">
|
||||||
|
<el-option label="内联脚本" value="inline" />
|
||||||
|
<el-option label="外部资源" value="external" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="脚本" v-show="scriptTaskForm.scriptType === 'inline'">
|
||||||
|
<el-input
|
||||||
|
v-model="scriptTaskForm.script"
|
||||||
|
type="textarea"
|
||||||
|
resize="vertical"
|
||||||
|
:autosize="{ minRows: 2, maxRows: 4 }"
|
||||||
|
clearable
|
||||||
|
@input="updateElementTask()"
|
||||||
|
@change="updateElementTask()"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
label="资源地址"
|
||||||
|
v-show="scriptTaskForm.scriptType === 'external'"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
v-model="scriptTaskForm.resource"
|
||||||
|
clearable
|
||||||
|
@input="updateElementTask()"
|
||||||
|
@change="updateElementTask()"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="结果变量">
|
||||||
|
<el-input
|
||||||
|
v-model="scriptTaskForm.resultVariable"
|
||||||
|
clearable
|
||||||
|
@input="updateElementTask()"
|
||||||
|
@change="updateElementTask()"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
defineOptions({ name: 'ScriptTask' });
|
||||||
|
const props = defineProps({
|
||||||
|
id: String,
|
||||||
|
type: String,
|
||||||
|
});
|
||||||
|
const defaultTaskForm = ref({
|
||||||
|
scriptFormat: '',
|
||||||
|
script: '',
|
||||||
|
resource: '',
|
||||||
|
resultVariable: '',
|
||||||
|
});
|
||||||
|
const scriptTaskForm = ref<any>({});
|
||||||
|
const bpmnElement = ref();
|
||||||
|
|
||||||
|
const bpmnInstances = () => (window as any)?.bpmnInstances;
|
||||||
|
|
||||||
|
const resetTaskForm = () => {
|
||||||
|
for (let key in defaultTaskForm.value) {
|
||||||
|
let value =
|
||||||
|
bpmnElement.value?.businessObject[key] || defaultTaskForm.value[key];
|
||||||
|
scriptTaskForm.value[key] = value;
|
||||||
|
}
|
||||||
|
scriptTaskForm.value.scriptType = scriptTaskForm.value.script
|
||||||
|
? 'inline'
|
||||||
|
: 'external';
|
||||||
|
};
|
||||||
|
const updateElementTask = () => {
|
||||||
|
let taskAttr = Object.create(null);
|
||||||
|
taskAttr.scriptFormat = scriptTaskForm.value.scriptFormat || null;
|
||||||
|
taskAttr.resultVariable = scriptTaskForm.value.resultVariable || null;
|
||||||
|
if (scriptTaskForm.value.scriptType === 'inline') {
|
||||||
|
taskAttr.script = scriptTaskForm.value.script || null;
|
||||||
|
taskAttr.resource = null;
|
||||||
|
} else {
|
||||||
|
taskAttr.resource = scriptTaskForm.value.resource || null;
|
||||||
|
taskAttr.script = null;
|
||||||
|
}
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), taskAttr);
|
||||||
|
};
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
bpmnElement.value = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.id,
|
||||||
|
() => {
|
||||||
|
bpmnElement.value = bpmnInstances().bpmnElement;
|
||||||
|
nextTick(() => {
|
||||||
|
resetTaskForm();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-form-item label="执行类型" key="executeType">
|
||||||
|
<el-select v-model="serviceTaskForm.executeType">
|
||||||
|
<el-option label="Java类" value="class" />
|
||||||
|
<el-option label="表达式" value="expression" />
|
||||||
|
<el-option label="代理表达式" value="delegateExpression" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="serviceTaskForm.executeType === 'class'"
|
||||||
|
label="Java类"
|
||||||
|
prop="class"
|
||||||
|
key="execute-class"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
v-model="serviceTaskForm.class"
|
||||||
|
clearable
|
||||||
|
@change="updateElementTask"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="serviceTaskForm.executeType === 'expression'"
|
||||||
|
label="表达式"
|
||||||
|
prop="expression"
|
||||||
|
key="execute-expression"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
v-model="serviceTaskForm.expression"
|
||||||
|
clearable
|
||||||
|
@change="updateElementTask"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="serviceTaskForm.executeType === 'delegateExpression'"
|
||||||
|
label="代理表达式"
|
||||||
|
prop="delegateExpression"
|
||||||
|
key="execute-delegate"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
v-model="serviceTaskForm.delegateExpression"
|
||||||
|
clearable
|
||||||
|
@change="updateElementTask"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
defineOptions({ name: 'ServiceTask' });
|
||||||
|
const props = defineProps({
|
||||||
|
id: String,
|
||||||
|
type: String,
|
||||||
|
});
|
||||||
|
|
||||||
|
const defaultTaskForm = ref({
|
||||||
|
executeType: '',
|
||||||
|
class: '',
|
||||||
|
expression: '',
|
||||||
|
delegateExpression: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
const serviceTaskForm = ref<any>({});
|
||||||
|
const bpmnElement = ref();
|
||||||
|
|
||||||
|
const bpmnInstances = () => (window as any)?.bpmnInstances;
|
||||||
|
|
||||||
|
const resetTaskForm = () => {
|
||||||
|
for (let key in defaultTaskForm.value) {
|
||||||
|
let value =
|
||||||
|
bpmnElement.value?.businessObject[key] || defaultTaskForm.value[key];
|
||||||
|
serviceTaskForm.value[key] = value;
|
||||||
|
if (value) {
|
||||||
|
serviceTaskForm.value.executeType = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateElementTask = () => {
|
||||||
|
let taskAttr = Object.create(null);
|
||||||
|
const type = serviceTaskForm.value.executeType;
|
||||||
|
for (let key in serviceTaskForm.value) {
|
||||||
|
if (key !== 'executeType' && key !== type) taskAttr[key] = null;
|
||||||
|
}
|
||||||
|
taskAttr[type] = serviceTaskForm.value[type] || '';
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), taskAttr);
|
||||||
|
};
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
bpmnElement.value = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.id,
|
||||||
|
() => {
|
||||||
|
bpmnElement.value = bpmnInstances().bpmnElement;
|
||||||
|
nextTick(() => {
|
||||||
|
resetTaskForm();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,520 @@
|
|||||||
|
<template>
|
||||||
|
<el-form label-width="120px">
|
||||||
|
<el-form-item label="规则类型" prop="candidateStrategy">
|
||||||
|
<el-select
|
||||||
|
v-model="userTaskForm.candidateStrategy"
|
||||||
|
clearable
|
||||||
|
style="width: 100%"
|
||||||
|
@change="changeCandidateStrategy"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="(dict, index) in CANDIDATE_STRATEGY"
|
||||||
|
:key="index"
|
||||||
|
:label="dict.label"
|
||||||
|
:value="dict.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="userTaskForm.candidateStrategy == CandidateStrategy.ROLE"
|
||||||
|
label="指定角色"
|
||||||
|
prop="candidateParam"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
v-model="userTaskForm.candidateParam"
|
||||||
|
clearable
|
||||||
|
multiple
|
||||||
|
style="width: 100%"
|
||||||
|
@change="updateElementTask"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in roleOptions"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="
|
||||||
|
userTaskForm.candidateStrategy == CandidateStrategy.DEPT_MEMBER ||
|
||||||
|
userTaskForm.candidateStrategy == CandidateStrategy.DEPT_LEADER ||
|
||||||
|
userTaskForm.candidateStrategy ==
|
||||||
|
CandidateStrategy.MULTI_LEVEL_DEPT_LEADER
|
||||||
|
"
|
||||||
|
label="指定部门"
|
||||||
|
prop="candidateParam"
|
||||||
|
span="24"
|
||||||
|
>
|
||||||
|
<el-tree-select
|
||||||
|
ref="treeRef"
|
||||||
|
v-model="userTaskForm.candidateParam"
|
||||||
|
:data="deptTreeOptions"
|
||||||
|
:props="defaultProps"
|
||||||
|
empty-text="加载中,请稍后"
|
||||||
|
multiple
|
||||||
|
node-key="id"
|
||||||
|
show-checkbox
|
||||||
|
@change="updateElementTask"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="userTaskForm.candidateStrategy == CandidateStrategy.POST"
|
||||||
|
label="指定岗位"
|
||||||
|
prop="candidateParam"
|
||||||
|
span="24"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
v-model="userTaskForm.candidateParam"
|
||||||
|
clearable
|
||||||
|
multiple
|
||||||
|
style="width: 100%"
|
||||||
|
@change="updateElementTask"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in postOptions"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="userTaskForm.candidateStrategy == CandidateStrategy.USER"
|
||||||
|
label="指定用户"
|
||||||
|
prop="candidateParam"
|
||||||
|
span="24"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
v-model="userTaskForm.candidateParam"
|
||||||
|
clearable
|
||||||
|
multiple
|
||||||
|
style="width: 100%"
|
||||||
|
@change="updateElementTask"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in userOptions"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.nickname"
|
||||||
|
:value="item.id"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="userTaskForm.candidateStrategy === CandidateStrategy.USER_GROUP"
|
||||||
|
label="指定用户组"
|
||||||
|
prop="candidateParam"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
v-model="userTaskForm.candidateParam"
|
||||||
|
clearable
|
||||||
|
multiple
|
||||||
|
style="width: 100%"
|
||||||
|
@change="updateElementTask"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in userGroupOptions"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="userTaskForm.candidateStrategy === CandidateStrategy.FORM_USER"
|
||||||
|
label="表单内用户字段"
|
||||||
|
prop="formUser"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
v-model="userTaskForm.candidateParam"
|
||||||
|
clearable
|
||||||
|
style="width: 100%"
|
||||||
|
@change="handleFormUserChange"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="(item, idx) in userFieldOnFormOptions"
|
||||||
|
:key="idx"
|
||||||
|
:label="item.title"
|
||||||
|
:value="item.field"
|
||||||
|
:disabled="!item.required"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="
|
||||||
|
userTaskForm.candidateStrategy === CandidateStrategy.FORM_DEPT_LEADER
|
||||||
|
"
|
||||||
|
label="表单内部门字段"
|
||||||
|
prop="formDept"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
v-model="userTaskForm.candidateParam"
|
||||||
|
clearable
|
||||||
|
style="width: 100%"
|
||||||
|
@change="updateElementTask"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="(item, idx) in deptFieldOnFormOptions"
|
||||||
|
:key="idx"
|
||||||
|
:label="item.title"
|
||||||
|
:value="item.field"
|
||||||
|
:disabled="!item.required"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="
|
||||||
|
userTaskForm.candidateStrategy ==
|
||||||
|
CandidateStrategy.MULTI_LEVEL_DEPT_LEADER ||
|
||||||
|
userTaskForm.candidateStrategy ==
|
||||||
|
CandidateStrategy.START_USER_DEPT_LEADER ||
|
||||||
|
userTaskForm.candidateStrategy ==
|
||||||
|
CandidateStrategy.START_USER_MULTI_LEVEL_DEPT_LEADER ||
|
||||||
|
userTaskForm.candidateStrategy == CandidateStrategy.FORM_DEPT_LEADER
|
||||||
|
"
|
||||||
|
:label="deptLevelLabel!"
|
||||||
|
prop="deptLevel"
|
||||||
|
span="24"
|
||||||
|
>
|
||||||
|
<el-select v-model="deptLevel" clearable @change="updateElementTask">
|
||||||
|
<el-option
|
||||||
|
v-for="(item, index) in MULTI_LEVEL_DEPT"
|
||||||
|
:key="index"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="userTaskForm.candidateStrategy === CandidateStrategy.EXPRESSION"
|
||||||
|
label="流程表达式"
|
||||||
|
prop="candidateParam"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
type="textarea"
|
||||||
|
v-model="userTaskForm.candidateParam[0]"
|
||||||
|
clearable
|
||||||
|
style="width: 100%"
|
||||||
|
@change="updateElementTask"
|
||||||
|
/>
|
||||||
|
<XButton
|
||||||
|
class="!w-1/1 mt-5px"
|
||||||
|
type="success"
|
||||||
|
preIcon="ep:select"
|
||||||
|
title="选择表达式"
|
||||||
|
size="small"
|
||||||
|
@click="openProcessExpressionDialog"
|
||||||
|
/>
|
||||||
|
<!-- 选择弹窗 -->
|
||||||
|
<ProcessExpressionDialog
|
||||||
|
ref="processExpressionDialogRef"
|
||||||
|
@select="selectProcessExpression"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="跳过表达式" prop="skipExpression">
|
||||||
|
<el-input
|
||||||
|
type="textarea"
|
||||||
|
v-model="userTaskForm.skipExpression"
|
||||||
|
clearable
|
||||||
|
style="width: 100%"
|
||||||
|
@change="updateSkipExpression"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import {
|
||||||
|
CANDIDATE_STRATEGY,
|
||||||
|
CandidateStrategy,
|
||||||
|
FieldPermissionType,
|
||||||
|
MULTI_LEVEL_DEPT,
|
||||||
|
} from '@/components/SimpleProcessDesignerV2/src/consts';
|
||||||
|
import { defaultProps, handleTree } from '@/utils/tree';
|
||||||
|
import * as RoleApi from '@/api/system/role';
|
||||||
|
import * as DeptApi from '@/api/system/dept';
|
||||||
|
import * as PostApi from '@/api/system/post';
|
||||||
|
import * as UserApi from '@/api/system/user';
|
||||||
|
import * as UserGroupApi from '@/api/bpm/userGroup';
|
||||||
|
import ProcessExpressionDialog from './ProcessExpressionDialog.vue';
|
||||||
|
import { ProcessExpressionVO } from '@/api/bpm/processExpression';
|
||||||
|
import { useFormFieldsPermission } from '@/components/SimpleProcessDesignerV2/src/node';
|
||||||
|
|
||||||
|
defineOptions({ name: 'UserTask' });
|
||||||
|
const props = defineProps({
|
||||||
|
id: String,
|
||||||
|
type: String,
|
||||||
|
});
|
||||||
|
const prefix = inject('prefix');
|
||||||
|
const userTaskForm = ref({
|
||||||
|
candidateStrategy: undefined, // 分配规则
|
||||||
|
candidateParam: [], // 分配选项
|
||||||
|
skipExpression: '', // 跳过表达式
|
||||||
|
});
|
||||||
|
const bpmnElement = ref();
|
||||||
|
const bpmnInstances = () => (window as any)?.bpmnInstances;
|
||||||
|
|
||||||
|
const roleOptions = ref<RoleApi.RoleVO[]>([]); // 角色列表
|
||||||
|
const deptTreeOptions = ref(); // 部门树
|
||||||
|
const postOptions = ref<PostApi.PostVO[]>([]); // 岗位列表
|
||||||
|
const userOptions = ref<UserApi.UserVO[]>([]); // 用户列表
|
||||||
|
const userGroupOptions = ref<UserGroupApi.UserGroupVO[]>([]); // 用户组列表
|
||||||
|
|
||||||
|
const { formFieldOptions } = useFormFieldsPermission(FieldPermissionType.READ);
|
||||||
|
// 表单内用户字段选项, 必须是必填和用户选择器
|
||||||
|
const userFieldOnFormOptions = computed(() => {
|
||||||
|
return formFieldOptions.filter((item) => item.type === 'UserSelect');
|
||||||
|
});
|
||||||
|
// 表单内部门字段选项, 必须是必填和部门选择器
|
||||||
|
const deptFieldOnFormOptions = computed(() => {
|
||||||
|
return formFieldOptions.filter((item) => item.type === 'DeptSelect');
|
||||||
|
});
|
||||||
|
|
||||||
|
const deptLevel = ref(1);
|
||||||
|
const deptLevelLabel = computed(() => {
|
||||||
|
let label = '部门负责人来源';
|
||||||
|
if (
|
||||||
|
userTaskForm.value.candidateStrategy ==
|
||||||
|
CandidateStrategy.MULTI_LEVEL_DEPT_LEADER
|
||||||
|
) {
|
||||||
|
label = label + '(指定部门向上)';
|
||||||
|
} else if (
|
||||||
|
userTaskForm.value.candidateStrategy == CandidateStrategy.FORM_DEPT_LEADER
|
||||||
|
) {
|
||||||
|
label = label + '(表单内部门向上)';
|
||||||
|
} else {
|
||||||
|
label = label + '(发起人部门向上)';
|
||||||
|
}
|
||||||
|
return label;
|
||||||
|
});
|
||||||
|
|
||||||
|
const otherExtensions = ref();
|
||||||
|
|
||||||
|
const resetTaskForm = () => {
|
||||||
|
const businessObject = bpmnElement.value.businessObject;
|
||||||
|
if (!businessObject) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const extensionElements =
|
||||||
|
businessObject?.extensionElements ??
|
||||||
|
bpmnInstances().moddle.create('bpmn:ExtensionElements', { values: [] });
|
||||||
|
userTaskForm.value.candidateStrategy = extensionElements.values?.filter(
|
||||||
|
(ex) => ex.$type === `${prefix}:CandidateStrategy`,
|
||||||
|
)?.[0]?.value;
|
||||||
|
const candidateParamStr = extensionElements.values?.filter(
|
||||||
|
(ex) => ex.$type === `${prefix}:CandidateParam`,
|
||||||
|
)?.[0]?.value;
|
||||||
|
if (candidateParamStr && candidateParamStr.length > 0) {
|
||||||
|
if (userTaskForm.value.candidateStrategy === CandidateStrategy.EXPRESSION) {
|
||||||
|
// 特殊:流程表达式,只有一个 input 输入框
|
||||||
|
userTaskForm.value.candidateParam = [candidateParamStr];
|
||||||
|
} else if (
|
||||||
|
userTaskForm.value.candidateStrategy ==
|
||||||
|
CandidateStrategy.MULTI_LEVEL_DEPT_LEADER
|
||||||
|
) {
|
||||||
|
// 特殊:多级不部门负责人,需要通过'|'分割
|
||||||
|
userTaskForm.value.candidateParam = candidateParamStr
|
||||||
|
.split('|')[0]
|
||||||
|
.split(',')
|
||||||
|
.map((item) => {
|
||||||
|
// 如果数字超出了最大安全整数范围,则将其作为字符串处理
|
||||||
|
let num = Number(item);
|
||||||
|
return num > Number.MAX_SAFE_INTEGER || num < -Number.MAX_SAFE_INTEGER
|
||||||
|
? item
|
||||||
|
: num;
|
||||||
|
});
|
||||||
|
deptLevel.value = +candidateParamStr.split('|')[1];
|
||||||
|
} else if (
|
||||||
|
userTaskForm.value.candidateStrategy ==
|
||||||
|
CandidateStrategy.START_USER_DEPT_LEADER ||
|
||||||
|
userTaskForm.value.candidateStrategy ==
|
||||||
|
CandidateStrategy.START_USER_MULTI_LEVEL_DEPT_LEADER
|
||||||
|
) {
|
||||||
|
userTaskForm.value.candidateParam = +candidateParamStr;
|
||||||
|
deptLevel.value = +candidateParamStr;
|
||||||
|
} else if (
|
||||||
|
userTaskForm.value.candidateStrategy == CandidateStrategy.FORM_DEPT_LEADER
|
||||||
|
) {
|
||||||
|
userTaskForm.value.candidateParam = candidateParamStr.split('|')[0];
|
||||||
|
deptLevel.value = +candidateParamStr.split('|')[1];
|
||||||
|
} else {
|
||||||
|
userTaskForm.value.candidateParam = candidateParamStr
|
||||||
|
.split(',')
|
||||||
|
.map((item) => {
|
||||||
|
// 如果数字超出了最大安全整数范围,则将其作为字符串处理
|
||||||
|
let num = Number(item);
|
||||||
|
return num > Number.MAX_SAFE_INTEGER || num < -Number.MAX_SAFE_INTEGER
|
||||||
|
? item
|
||||||
|
: num;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
userTaskForm.value.candidateParam = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
otherExtensions.value =
|
||||||
|
extensionElements.values?.filter(
|
||||||
|
(ex) =>
|
||||||
|
ex.$type !== `${prefix}:CandidateStrategy` &&
|
||||||
|
ex.$type !== `${prefix}:CandidateParam`,
|
||||||
|
) ?? [];
|
||||||
|
|
||||||
|
// 跳过表达式
|
||||||
|
if (businessObject.skipExpression != undefined) {
|
||||||
|
userTaskForm.value.skipExpression = businessObject.skipExpression;
|
||||||
|
} else {
|
||||||
|
userTaskForm.value.skipExpression = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 改用通过extensionElements来存储数据
|
||||||
|
return;
|
||||||
|
if (businessObject.candidateStrategy != undefined) {
|
||||||
|
userTaskForm.value.candidateStrategy = parseInt(
|
||||||
|
businessObject.candidateStrategy,
|
||||||
|
) as any;
|
||||||
|
} else {
|
||||||
|
userTaskForm.value.candidateStrategy = undefined;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
businessObject.candidateParam &&
|
||||||
|
businessObject.candidateParam.length > 0
|
||||||
|
) {
|
||||||
|
if (userTaskForm.value.candidateStrategy === 60) {
|
||||||
|
// 特殊:流程表达式,只有一个 input 输入框
|
||||||
|
userTaskForm.value.candidateParam = [businessObject.candidateParam];
|
||||||
|
} else {
|
||||||
|
userTaskForm.value.candidateParam = businessObject.candidateParam
|
||||||
|
.split(',')
|
||||||
|
.map((item) => item);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
userTaskForm.value.candidateParam = [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 更新 candidateStrategy 字段时,需要清空 candidateParam,并触发 bpmn 图更新 */
|
||||||
|
const changeCandidateStrategy = () => {
|
||||||
|
userTaskForm.value.candidateParam = [];
|
||||||
|
deptLevel.value = 1;
|
||||||
|
// 注释 by 芋艿:这个交互很多用户反馈费解,https://t.zsxq.com/xNmas 所以暂时屏蔽
|
||||||
|
// if (userTaskForm.value.candidateStrategy === CandidateStrategy.FORM_USER) {
|
||||||
|
// // 特殊处理表单内用户字段,当只有发起人选项时应选中发起人
|
||||||
|
// if (!userFieldOnFormOptions.value || userFieldOnFormOptions.value.length <= 1) {
|
||||||
|
// userTaskForm.value.candidateStrategy = CandidateStrategy.START_USER
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
updateElementTask();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 选中某个 options 时候,更新 bpmn 图 */
|
||||||
|
const updateElementTask = () => {
|
||||||
|
let candidateParam =
|
||||||
|
userTaskForm.value.candidateParam instanceof Array
|
||||||
|
? userTaskForm.value.candidateParam.join(',')
|
||||||
|
: userTaskForm.value.candidateParam;
|
||||||
|
|
||||||
|
// 特殊处理多级部门情况
|
||||||
|
if (
|
||||||
|
userTaskForm.value.candidateStrategy ==
|
||||||
|
CandidateStrategy.MULTI_LEVEL_DEPT_LEADER ||
|
||||||
|
userTaskForm.value.candidateStrategy == CandidateStrategy.FORM_DEPT_LEADER
|
||||||
|
) {
|
||||||
|
candidateParam += '|' + deptLevel.value;
|
||||||
|
}
|
||||||
|
// 特殊处理发起人部门负责人、发起人连续部门负责人
|
||||||
|
if (
|
||||||
|
userTaskForm.value.candidateStrategy ==
|
||||||
|
CandidateStrategy.START_USER_DEPT_LEADER ||
|
||||||
|
userTaskForm.value.candidateStrategy ==
|
||||||
|
CandidateStrategy.START_USER_MULTI_LEVEL_DEPT_LEADER
|
||||||
|
) {
|
||||||
|
candidateParam = deptLevel.value + '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const extensions = bpmnInstances().moddle.create('bpmn:ExtensionElements', {
|
||||||
|
values: [
|
||||||
|
...otherExtensions.value,
|
||||||
|
bpmnInstances().moddle.create(`${prefix}:CandidateStrategy`, {
|
||||||
|
value: userTaskForm.value.candidateStrategy,
|
||||||
|
}),
|
||||||
|
bpmnInstances().moddle.create(`${prefix}:CandidateParam`, {
|
||||||
|
value: candidateParam,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
|
extensionElements: extensions,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 改用通过extensionElements来存储数据
|
||||||
|
return;
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
|
candidateStrategy: userTaskForm.value.candidateStrategy,
|
||||||
|
candidateParam: userTaskForm.value.candidateParam.join(','),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateSkipExpression = () => {
|
||||||
|
if (
|
||||||
|
userTaskForm.value.skipExpression &&
|
||||||
|
userTaskForm.value.skipExpression !== ''
|
||||||
|
) {
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
|
skipExpression: userTaskForm.value.skipExpression,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
|
||||||
|
skipExpression: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 打开监听器弹窗
|
||||||
|
const processExpressionDialogRef = ref();
|
||||||
|
const openProcessExpressionDialog = async () => {
|
||||||
|
processExpressionDialogRef.value.open();
|
||||||
|
};
|
||||||
|
const selectProcessExpression = (expression: ProcessExpressionVO) => {
|
||||||
|
userTaskForm.value.candidateParam = [expression.expression];
|
||||||
|
updateElementTask();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleFormUserChange = (e) => {
|
||||||
|
if (e === 'PROCESS_START_USER_ID') {
|
||||||
|
userTaskForm.value.candidateParam = [];
|
||||||
|
userTaskForm.value.candidateStrategy = CandidateStrategy.START_USER;
|
||||||
|
}
|
||||||
|
updateElementTask();
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.id,
|
||||||
|
() => {
|
||||||
|
bpmnElement.value = bpmnInstances().bpmnElement;
|
||||||
|
nextTick(() => {
|
||||||
|
resetTaskForm();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
// 获得角色列表
|
||||||
|
roleOptions.value = await RoleApi.getSimpleRoleList();
|
||||||
|
// 获得部门列表
|
||||||
|
const deptOptions = await DeptApi.getSimpleDeptList();
|
||||||
|
deptTreeOptions.value = handleTree(deptOptions, 'id');
|
||||||
|
// 获得岗位列表
|
||||||
|
postOptions.value = await PostApi.getSimplePostList();
|
||||||
|
// 获得用户列表
|
||||||
|
userOptions.value = await UserApi.getSimpleUserList();
|
||||||
|
// 获得用户组列表
|
||||||
|
userGroupOptions.value = await UserGroupApi.getUserGroupSimpleList();
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
bpmnElement.value = null;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,342 @@
|
|||||||
|
<template>
|
||||||
|
<el-tabs v-model="tab">
|
||||||
|
<el-tab-pane label="CRON表达式" name="cron">
|
||||||
|
<div style="margin-bottom: 10px">
|
||||||
|
<el-input
|
||||||
|
v-model="cronStr"
|
||||||
|
readonly
|
||||||
|
style="width: 400px; font-weight: bold"
|
||||||
|
:key="'cronStr'"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; gap: 8px; margin-bottom: 8px">
|
||||||
|
<el-input
|
||||||
|
v-model="fields.second"
|
||||||
|
placeholder="秒"
|
||||||
|
style="width: 80px"
|
||||||
|
:key="'second'"
|
||||||
|
/>
|
||||||
|
<el-input
|
||||||
|
v-model="fields.minute"
|
||||||
|
placeholder="分"
|
||||||
|
style="width: 80px"
|
||||||
|
:key="'minute'"
|
||||||
|
/>
|
||||||
|
<el-input
|
||||||
|
v-model="fields.hour"
|
||||||
|
placeholder="时"
|
||||||
|
style="width: 80px"
|
||||||
|
:key="'hour'"
|
||||||
|
/>
|
||||||
|
<el-input
|
||||||
|
v-model="fields.day"
|
||||||
|
placeholder="天"
|
||||||
|
style="width: 80px"
|
||||||
|
:key="'day'"
|
||||||
|
/>
|
||||||
|
<el-input
|
||||||
|
v-model="fields.month"
|
||||||
|
placeholder="月"
|
||||||
|
style="width: 80px"
|
||||||
|
:key="'month'"
|
||||||
|
/>
|
||||||
|
<el-input
|
||||||
|
v-model="fields.week"
|
||||||
|
placeholder="周"
|
||||||
|
style="width: 80px"
|
||||||
|
:key="'week'"
|
||||||
|
/>
|
||||||
|
<el-input
|
||||||
|
v-model="fields.year"
|
||||||
|
placeholder="年"
|
||||||
|
style="width: 80px"
|
||||||
|
:key="'year'"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<el-tabs v-model="activeField" type="card" style="margin-bottom: 8px">
|
||||||
|
<el-tab-pane
|
||||||
|
v-for="f in cronFieldList"
|
||||||
|
:label="f.label"
|
||||||
|
:name="f.key"
|
||||||
|
:key="f.key"
|
||||||
|
>
|
||||||
|
<div style="margin-bottom: 8px">
|
||||||
|
<el-radio-group v-model="cronMode[f.key]" :key="'radio-' + f.key">
|
||||||
|
<el-radio label="every" :key="'every-' + f.key"
|
||||||
|
>每{{ f.label }}</el-radio
|
||||||
|
>
|
||||||
|
<el-radio label="range" :key="'range-' + f.key"
|
||||||
|
>从
|
||||||
|
<el-input-number
|
||||||
|
v-model="cronRange[f.key][0]"
|
||||||
|
:min="f.min"
|
||||||
|
:max="f.max"
|
||||||
|
size="small"
|
||||||
|
style="width: 60px"
|
||||||
|
:key="'range0-' + f.key"
|
||||||
|
/>
|
||||||
|
到
|
||||||
|
<el-input-number
|
||||||
|
v-model="cronRange[f.key][1]"
|
||||||
|
:min="f.min"
|
||||||
|
:max="f.max"
|
||||||
|
size="small"
|
||||||
|
style="width: 60px"
|
||||||
|
:key="'range1-' + f.key"
|
||||||
|
/>
|
||||||
|
之间每{{ f.label }}</el-radio
|
||||||
|
>
|
||||||
|
<el-radio label="step" :key="'step-' + f.key"
|
||||||
|
>从第
|
||||||
|
<el-input-number
|
||||||
|
v-model="cronStep[f.key][0]"
|
||||||
|
:min="f.min"
|
||||||
|
:max="f.max"
|
||||||
|
size="small"
|
||||||
|
style="width: 60px"
|
||||||
|
:key="'step0-' + f.key"
|
||||||
|
/>
|
||||||
|
开始每
|
||||||
|
<el-input-number
|
||||||
|
v-model="cronStep[f.key][1]"
|
||||||
|
:min="1"
|
||||||
|
:max="f.max"
|
||||||
|
size="small"
|
||||||
|
style="width: 60px"
|
||||||
|
:key="'step1-' + f.key"
|
||||||
|
/>
|
||||||
|
{{ f.label }}</el-radio
|
||||||
|
>
|
||||||
|
<el-radio label="appoint" :key="'appoint-' + f.key"
|
||||||
|
>指定</el-radio
|
||||||
|
>
|
||||||
|
</el-radio-group>
|
||||||
|
</div>
|
||||||
|
<div v-if="cronMode[f.key] === 'appoint'">
|
||||||
|
<el-checkbox-group
|
||||||
|
v-model="cronAppoint[f.key]"
|
||||||
|
:key="'group-' + f.key"
|
||||||
|
>
|
||||||
|
<el-checkbox
|
||||||
|
v-for="n in f.max + 1"
|
||||||
|
:label="pad(n - 1)"
|
||||||
|
:key="'cb-' + f.key + '-' + (n - 1)"
|
||||||
|
>{{ pad(n - 1) }}</el-checkbox
|
||||||
|
>
|
||||||
|
</el-checkbox-group>
|
||||||
|
</div>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="标准格式" name="iso" :key="'iso-tab'">
|
||||||
|
<div style="margin-bottom: 10px">
|
||||||
|
<el-input
|
||||||
|
v-model="isoStr"
|
||||||
|
placeholder="如R1/2025-05-21T21:59:54/P3DT30M30S"
|
||||||
|
style="width: 400px; font-weight: bold"
|
||||||
|
:key="'isoStr'"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div style="margin-bottom: 10px">
|
||||||
|
循环次数:<el-input-number
|
||||||
|
v-model="repeat"
|
||||||
|
:min="1"
|
||||||
|
style="width: 100px"
|
||||||
|
:key="'repeat'"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div style="margin-bottom: 10px">
|
||||||
|
日期时间:<el-date-picker
|
||||||
|
v-model="isoDate"
|
||||||
|
type="datetime"
|
||||||
|
placeholder="选择日期时间"
|
||||||
|
style="width: 200px"
|
||||||
|
:key="'isoDate'"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div style="margin-bottom: 10px">
|
||||||
|
当前时长:<el-input
|
||||||
|
v-model="isoDuration"
|
||||||
|
placeholder="如P3DT30M30S"
|
||||||
|
style="width: 200px"
|
||||||
|
:key="'isoDuration'"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
秒:<el-button
|
||||||
|
v-for="s in [5, 10, 30, 50]"
|
||||||
|
@click="setDuration('S', s)"
|
||||||
|
:key="'sec-' + s"
|
||||||
|
>{{ s }}</el-button
|
||||||
|
>自定义
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
分:<el-button
|
||||||
|
v-for="m in [5, 10, 30, 50]"
|
||||||
|
@click="setDuration('M', m)"
|
||||||
|
:key="'min-' + m"
|
||||||
|
>{{ m }}</el-button
|
||||||
|
>自定义
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
小时:<el-button
|
||||||
|
v-for="h in [4, 8, 12, 24]"
|
||||||
|
@click="setDuration('H', h)"
|
||||||
|
:key="'hour-' + h"
|
||||||
|
>{{ h }}</el-button
|
||||||
|
>自定义
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
天:<el-button
|
||||||
|
v-for="d in [1, 2, 3, 4]"
|
||||||
|
@click="setDuration('D', d)"
|
||||||
|
:key="'day-' + d"
|
||||||
|
>{{ d }}</el-button
|
||||||
|
>自定义
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
月:<el-button
|
||||||
|
v-for="mo in [1, 2, 3, 4]"
|
||||||
|
@click="setDuration('M', mo)"
|
||||||
|
:key="'mon-' + mo"
|
||||||
|
>{{ mo }}</el-button
|
||||||
|
>自定义
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
年:<el-button
|
||||||
|
v-for="y in [1, 2, 3, 4]"
|
||||||
|
@click="setDuration('Y', y)"
|
||||||
|
:key="'year-' + y"
|
||||||
|
>{{ y }}</el-button
|
||||||
|
>自定义
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { ref, watch, computed } from 'vue';
|
||||||
|
const props = defineProps({ value: String });
|
||||||
|
const emit = defineEmits(['change']);
|
||||||
|
|
||||||
|
const tab = ref('cron');
|
||||||
|
const cronStr = ref(props.value || '* * * * * ?');
|
||||||
|
const fields = ref({
|
||||||
|
second: '*',
|
||||||
|
minute: '*',
|
||||||
|
hour: '*',
|
||||||
|
day: '*',
|
||||||
|
month: '*',
|
||||||
|
week: '?',
|
||||||
|
year: '',
|
||||||
|
});
|
||||||
|
const cronFieldList = [
|
||||||
|
{ key: 'second', label: '秒', min: 0, max: 59 },
|
||||||
|
{ key: 'minute', label: '分', min: 0, max: 59 },
|
||||||
|
{ key: 'hour', label: '时', min: 0, max: 23 },
|
||||||
|
{ key: 'day', label: '天', min: 1, max: 31 },
|
||||||
|
{ key: 'month', label: '月', min: 1, max: 12 },
|
||||||
|
{ key: 'week', label: '周', min: 1, max: 7 },
|
||||||
|
{ key: 'year', label: '年', min: 1970, max: 2099 },
|
||||||
|
];
|
||||||
|
const activeField = ref('second');
|
||||||
|
const cronMode = ref({
|
||||||
|
second: 'appoint',
|
||||||
|
minute: 'every',
|
||||||
|
hour: 'every',
|
||||||
|
day: 'every',
|
||||||
|
month: 'every',
|
||||||
|
week: 'every',
|
||||||
|
year: 'every',
|
||||||
|
});
|
||||||
|
const cronAppoint = ref({
|
||||||
|
second: ['00', '01'],
|
||||||
|
minute: [],
|
||||||
|
hour: [],
|
||||||
|
day: [],
|
||||||
|
month: [],
|
||||||
|
week: [],
|
||||||
|
year: [],
|
||||||
|
});
|
||||||
|
const cronRange = ref({
|
||||||
|
second: [0, 1],
|
||||||
|
minute: [0, 1],
|
||||||
|
hour: [0, 1],
|
||||||
|
day: [1, 2],
|
||||||
|
month: [1, 2],
|
||||||
|
week: [1, 2],
|
||||||
|
year: [1970, 1971],
|
||||||
|
});
|
||||||
|
const cronStep = ref({
|
||||||
|
second: [1, 1],
|
||||||
|
minute: [1, 1],
|
||||||
|
hour: [1, 1],
|
||||||
|
day: [1, 1],
|
||||||
|
month: [1, 1],
|
||||||
|
week: [1, 1],
|
||||||
|
year: [1970, 1],
|
||||||
|
});
|
||||||
|
|
||||||
|
function pad(n) {
|
||||||
|
return n < 10 ? '0' + n : '' + n;
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
[fields, cronMode, cronAppoint, cronRange, cronStep],
|
||||||
|
() => {
|
||||||
|
// 组装cron表达式
|
||||||
|
let arr = cronFieldList.map((f) => {
|
||||||
|
if (cronMode.value[f.key] === 'every') return '*';
|
||||||
|
if (cronMode.value[f.key] === 'appoint')
|
||||||
|
return cronAppoint.value[f.key].join(',') || '*';
|
||||||
|
if (cronMode.value[f.key] === 'range')
|
||||||
|
return `${cronRange.value[f.key][0]}-${cronRange.value[f.key][1]}`;
|
||||||
|
if (cronMode.value[f.key] === 'step')
|
||||||
|
return `${cronStep.value[f.key][0]}/${cronStep.value[f.key][1]}`;
|
||||||
|
return fields.value[f.key] || '*';
|
||||||
|
});
|
||||||
|
// week和year特殊处理
|
||||||
|
arr[5] = arr[5] || '?';
|
||||||
|
cronStr.value = arr.join(' ');
|
||||||
|
if (tab.value === 'cron') emit('change', cronStr.value);
|
||||||
|
},
|
||||||
|
{ deep: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
// 标准格式
|
||||||
|
const isoStr = ref('');
|
||||||
|
const repeat = ref(1);
|
||||||
|
const isoDate = ref('');
|
||||||
|
const isoDuration = ref('');
|
||||||
|
function setDuration(type, val) {
|
||||||
|
// 组装ISO 8601字符串
|
||||||
|
let d = isoDuration.value;
|
||||||
|
if (!d.includes(type)) d += val + type;
|
||||||
|
else d = d.replace(new RegExp(`\\d+${type}`), val + type);
|
||||||
|
isoDuration.value = d;
|
||||||
|
updateIsoStr();
|
||||||
|
}
|
||||||
|
function updateIsoStr() {
|
||||||
|
let str = `R${repeat.value}`;
|
||||||
|
if (isoDate.value)
|
||||||
|
str +=
|
||||||
|
'/' +
|
||||||
|
(typeof isoDate.value === 'string'
|
||||||
|
? isoDate.value
|
||||||
|
: new Date(isoDate.value).toISOString());
|
||||||
|
if (isoDuration.value) str += '/' + isoDuration.value;
|
||||||
|
isoStr.value = str;
|
||||||
|
if (tab.value === 'iso') emit('change', isoStr.value);
|
||||||
|
}
|
||||||
|
watch([repeat, isoDate, isoDuration], updateIsoStr);
|
||||||
|
watch(
|
||||||
|
() => props.value,
|
||||||
|
(val) => {
|
||||||
|
if (!val) return;
|
||||||
|
if (tab.value === 'cron') cronStr.value = val;
|
||||||
|
if (tab.value === 'iso') isoStr.value = val;
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div style="margin-bottom: 10px">
|
||||||
|
当前选择:<el-input v-model="isoString" readonly style="width: 300px" />
|
||||||
|
</div>
|
||||||
|
<div v-for="unit in units" :key="unit.key" style="margin-bottom: 8px">
|
||||||
|
<span>{{ unit.label }}:</span>
|
||||||
|
<el-button-group>
|
||||||
|
<el-button
|
||||||
|
v-for="val in unit.presets"
|
||||||
|
:key="val"
|
||||||
|
size="mini"
|
||||||
|
@click="setUnit(unit.key, val)"
|
||||||
|
>{{ val }}</el-button
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
v-model.number="custom[unit.key]"
|
||||||
|
size="mini"
|
||||||
|
style="width: 60px; margin-left: 8px"
|
||||||
|
placeholder="自定义"
|
||||||
|
@change="setUnit(unit.key, custom[unit.key])"
|
||||||
|
/>
|
||||||
|
</el-button-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, watch, computed } from 'vue';
|
||||||
|
const props = defineProps({ value: String });
|
||||||
|
const emit = defineEmits(['change']);
|
||||||
|
|
||||||
|
const units = [
|
||||||
|
{ key: 'Y', label: '年', presets: [1, 2, 3, 4] },
|
||||||
|
{ key: 'M', label: '月', presets: [1, 2, 3, 4] },
|
||||||
|
{ key: 'D', label: '天', presets: [1, 2, 3, 4] },
|
||||||
|
{ key: 'H', label: '时', presets: [4, 8, 12, 24] },
|
||||||
|
{ key: 'm', label: '分', presets: [5, 10, 30, 50] },
|
||||||
|
{ key: 'S', label: '秒', presets: [5, 10, 30, 50] },
|
||||||
|
];
|
||||||
|
const custom = ref({ Y: '', M: '', D: '', H: '', m: '', S: '' });
|
||||||
|
const isoString = ref('');
|
||||||
|
|
||||||
|
function setUnit(key, val) {
|
||||||
|
if (!val || isNaN(val)) {
|
||||||
|
custom.value[key] = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
custom.value[key] = val;
|
||||||
|
updateIsoString();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateIsoString() {
|
||||||
|
let str = 'P';
|
||||||
|
if (custom.value.Y) str += custom.value.Y + 'Y';
|
||||||
|
if (custom.value.M) str += custom.value.M + 'M';
|
||||||
|
if (custom.value.D) str += custom.value.D + 'D';
|
||||||
|
if (custom.value.H || custom.value.m || custom.value.S) str += 'T';
|
||||||
|
if (custom.value.H) str += custom.value.H + 'H';
|
||||||
|
if (custom.value.m) str += custom.value.m + 'M';
|
||||||
|
if (custom.value.S) str += custom.value.S + 'S';
|
||||||
|
isoString.value = str === 'P' ? '' : str;
|
||||||
|
emit('change', isoString.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.value,
|
||||||
|
(val) => {
|
||||||
|
if (!val) return;
|
||||||
|
// 解析ISO 8601字符串到custom
|
||||||
|
const match = val.match(
|
||||||
|
/^P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?$/,
|
||||||
|
);
|
||||||
|
if (match) {
|
||||||
|
custom.value.Y = match[1] || '';
|
||||||
|
custom.value.M = match[2] || '';
|
||||||
|
custom.value.D = match[3] || '';
|
||||||
|
custom.value.H = match[4] || '';
|
||||||
|
custom.value.m = match[5] || '';
|
||||||
|
custom.value.S = match[6] || '';
|
||||||
|
updateIsoString();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,345 @@
|
|||||||
|
<template>
|
||||||
|
<div class="panel-tab__content">
|
||||||
|
<div style="margin-top: 10px">
|
||||||
|
<span>类型:</span>
|
||||||
|
<el-button-group>
|
||||||
|
<el-button
|
||||||
|
size="mini"
|
||||||
|
:type="type === 'time' ? 'primary' : ''"
|
||||||
|
@click="setType('time')"
|
||||||
|
>时间</el-button
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
size="mini"
|
||||||
|
:type="type === 'duration' ? 'primary' : ''"
|
||||||
|
@click="setType('duration')"
|
||||||
|
>持续</el-button
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
size="mini"
|
||||||
|
:type="type === 'cycle' ? 'primary' : ''"
|
||||||
|
@click="setType('cycle')"
|
||||||
|
>循环</el-button
|
||||||
|
>
|
||||||
|
</el-button-group>
|
||||||
|
<el-icon v-if="valid" color="green" style="margin-left: 8px"
|
||||||
|
><CircleCheckFilled
|
||||||
|
/></el-icon>
|
||||||
|
</div>
|
||||||
|
<div style=" display: flex; align-items: center;margin-top: 10px">
|
||||||
|
<span>条件:</span>
|
||||||
|
<el-input
|
||||||
|
v-model="condition"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
style="width: calc(100% - 100px)"
|
||||||
|
:readonly="type !== 'duration' && type !== 'cycle'"
|
||||||
|
@focus="handleInputFocus"
|
||||||
|
@blur="updateNode"
|
||||||
|
>
|
||||||
|
<template #suffix>
|
||||||
|
<el-tooltip v-if="!valid" content="格式错误" placement="top">
|
||||||
|
<el-icon color="orange"><WarningFilled /></el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip :content="helpText" placement="top">
|
||||||
|
<el-icon
|
||||||
|
color="#409EFF"
|
||||||
|
style="cursor: pointer"
|
||||||
|
@click="showHelp = true"
|
||||||
|
><QuestionFilled
|
||||||
|
/></el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-button
|
||||||
|
v-if="type === 'time'"
|
||||||
|
@click="showDatePicker = true"
|
||||||
|
style="margin-left: 4px"
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<Icon icon="ep:calendar" />
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
v-if="type === 'duration'"
|
||||||
|
@click="showDurationDialog = true"
|
||||||
|
style="margin-left: 4px"
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<Icon icon="ep:timer" />
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
v-if="type === 'cycle'"
|
||||||
|
@click="showCycleDialog = true"
|
||||||
|
style="margin-left: 4px"
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<Icon icon="ep:setting" />
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
|
<!-- 时间选择器 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="showDatePicker"
|
||||||
|
title="选择时间"
|
||||||
|
width="400px"
|
||||||
|
@close="showDatePicker = false"
|
||||||
|
>
|
||||||
|
<el-date-picker
|
||||||
|
v-model="dateValue"
|
||||||
|
type="datetime"
|
||||||
|
placeholder="选择日期时间"
|
||||||
|
style="width: 100%"
|
||||||
|
@change="onDateChange"
|
||||||
|
/>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="showDatePicker = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="onDateConfirm">确定</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
<!-- 持续时长选择器 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="showDurationDialog"
|
||||||
|
title="时间配置"
|
||||||
|
width="600px"
|
||||||
|
@close="showDurationDialog = false"
|
||||||
|
>
|
||||||
|
<DurationConfig :value="condition" @change="onDurationChange" />
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="showDurationDialog = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="onDurationConfirm">确定</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
<!-- 循环配置器 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="showCycleDialog"
|
||||||
|
title="时间配置"
|
||||||
|
width="800px"
|
||||||
|
@close="showCycleDialog = false"
|
||||||
|
>
|
||||||
|
<CycleConfig :value="condition" @change="onCycleChange" />
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="showCycleDialog = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="onCycleConfirm">确定</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
<!-- 帮助说明 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="showHelp"
|
||||||
|
title="格式说明"
|
||||||
|
width="600px"
|
||||||
|
@close="showHelp = false"
|
||||||
|
>
|
||||||
|
<div v-html="helpHtml"></div>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="showHelp = false">关闭</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, computed, watch, onMounted } from 'vue';
|
||||||
|
import {
|
||||||
|
CircleCheckFilled,
|
||||||
|
WarningFilled,
|
||||||
|
QuestionFilled,
|
||||||
|
} from '@element-plus/icons-vue';
|
||||||
|
import DurationConfig from './DurationConfig.vue';
|
||||||
|
import CycleConfig from './CycleConfig.vue';
|
||||||
|
import { createListenerObject, updateElementExtensions } from '../../utils';
|
||||||
|
const bpmnInstances = () => (window as any).bpmnInstances;
|
||||||
|
const props = defineProps({ businessObject: Object });
|
||||||
|
const type = ref('time');
|
||||||
|
const condition = ref('');
|
||||||
|
const valid = ref(true);
|
||||||
|
const showDatePicker = ref(false);
|
||||||
|
const showDurationDialog = ref(false);
|
||||||
|
const showCycleDialog = ref(false);
|
||||||
|
const showHelp = ref(false);
|
||||||
|
const dateValue = ref(null);
|
||||||
|
const bpmnElement = ref(null);
|
||||||
|
|
||||||
|
const placeholder = computed(() => {
|
||||||
|
if (type.value === 'time') return '请输入时间';
|
||||||
|
if (type.value === 'duration') return '请输入持续时长';
|
||||||
|
if (type.value === 'cycle') return '请输入循环表达式';
|
||||||
|
return '';
|
||||||
|
});
|
||||||
|
const helpText = computed(() => {
|
||||||
|
if (type.value === 'time') return '选择具体时间';
|
||||||
|
if (type.value === 'duration') return 'ISO 8601格式,如PT1H';
|
||||||
|
if (type.value === 'cycle') return 'CRON表达式或ISO 8601周期';
|
||||||
|
return '';
|
||||||
|
});
|
||||||
|
const helpHtml = computed(() => {
|
||||||
|
if (type.value === 'duration') {
|
||||||
|
return `指定定时器之前要等待多长时间。S表示秒,M表示分,D表示天;P表示时间段,T表示精确到时间的时间段。<br>
|
||||||
|
时间格式依然为ISO 8601格式,一年两个月三天四小时五分六秒内,可以写成P1Y2M3DT4H5M6S。<br>
|
||||||
|
P是开始标记,T是时间和日期分割标记,没有日期只有时间T是不能省去的,比如1小时执行一次应写成PT1H。`;
|
||||||
|
}
|
||||||
|
if (type.value === 'cycle') {
|
||||||
|
return `支持CRON表达式(如0 0/30 * * * ?)或ISO 8601周期(如R3/PT10M)。`;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
});
|
||||||
|
|
||||||
|
// 初始化和监听
|
||||||
|
function syncFromBusinessObject() {
|
||||||
|
if (props.businessObject) {
|
||||||
|
const timerDef = (props.businessObject.eventDefinitions || [])[0];
|
||||||
|
if (timerDef) {
|
||||||
|
if (timerDef.timeDate) {
|
||||||
|
type.value = 'time';
|
||||||
|
condition.value = timerDef.timeDate.body;
|
||||||
|
} else if (timerDef.timeDuration) {
|
||||||
|
type.value = 'duration';
|
||||||
|
condition.value = timerDef.timeDuration.body;
|
||||||
|
} else if (timerDef.timeCycle) {
|
||||||
|
type.value = 'cycle';
|
||||||
|
condition.value = timerDef.timeCycle.body;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onMounted(syncFromBusinessObject);
|
||||||
|
|
||||||
|
// 切换类型
|
||||||
|
function setType(t) {
|
||||||
|
type.value = t;
|
||||||
|
condition.value = '';
|
||||||
|
updateNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输入校验
|
||||||
|
watch([type, condition], () => {
|
||||||
|
valid.value = validate();
|
||||||
|
// updateNode() // 可以注释掉,避免频繁触发
|
||||||
|
});
|
||||||
|
|
||||||
|
function validate() {
|
||||||
|
if (type.value === 'time') {
|
||||||
|
return !!condition.value && !isNaN(Date.parse(condition.value));
|
||||||
|
}
|
||||||
|
if (type.value === 'duration') {
|
||||||
|
return /^P.*$/.test(condition.value);
|
||||||
|
}
|
||||||
|
if (type.value === 'cycle') {
|
||||||
|
return /^([0-9*\/?, ]+|R\d*\/P.*)$/.test(condition.value);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择时间
|
||||||
|
function onDateChange(val) {
|
||||||
|
dateValue.value = val;
|
||||||
|
}
|
||||||
|
function onDateConfirm() {
|
||||||
|
if (dateValue.value) {
|
||||||
|
condition.value = new Date(dateValue.value).toISOString();
|
||||||
|
showDatePicker.value = false;
|
||||||
|
updateNode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 持续时长
|
||||||
|
function onDurationChange(val) {
|
||||||
|
condition.value = val;
|
||||||
|
}
|
||||||
|
function onDurationConfirm() {
|
||||||
|
showDurationDialog.value = false;
|
||||||
|
updateNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 循环
|
||||||
|
function onCycleChange(val) {
|
||||||
|
condition.value = val;
|
||||||
|
}
|
||||||
|
function onCycleConfirm() {
|
||||||
|
showCycleDialog.value = false;
|
||||||
|
updateNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输入框聚焦时弹窗(可选)
|
||||||
|
function handleInputFocus() {
|
||||||
|
if (type.value === 'time') showDatePicker.value = true;
|
||||||
|
if (type.value === 'duration') showDurationDialog.value = true;
|
||||||
|
if (type.value === 'cycle') showCycleDialog.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同步到节点
|
||||||
|
function updateNode() {
|
||||||
|
const moddle = window.bpmnInstances?.moddle;
|
||||||
|
const modeling = window.bpmnInstances?.modeling;
|
||||||
|
const elementRegistry = window.bpmnInstances?.elementRegistry;
|
||||||
|
if (!moddle || !modeling || !elementRegistry) return;
|
||||||
|
|
||||||
|
// 获取元素
|
||||||
|
if (!props.businessObject || !props.businessObject.id) return;
|
||||||
|
const element = elementRegistry.get(props.businessObject.id);
|
||||||
|
if (!element) return;
|
||||||
|
|
||||||
|
// 1. 复用原有 timerDef,或新建
|
||||||
|
let timerDef =
|
||||||
|
element.businessObject.eventDefinitions &&
|
||||||
|
element.businessObject.eventDefinitions[0];
|
||||||
|
if (!timerDef) {
|
||||||
|
timerDef = bpmnInstances().bpmnFactory.create(
|
||||||
|
'bpmn:TimerEventDefinition',
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
modeling.updateProperties(element, {
|
||||||
|
eventDefinitions: [timerDef],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 清空原有
|
||||||
|
delete timerDef.timeDate;
|
||||||
|
delete timerDef.timeDuration;
|
||||||
|
delete timerDef.timeCycle;
|
||||||
|
|
||||||
|
// 3. 设置新的
|
||||||
|
if (type.value === 'time' && condition.value) {
|
||||||
|
timerDef.timeDate = bpmnInstances().bpmnFactory.create(
|
||||||
|
'bpmn:FormalExpression',
|
||||||
|
{
|
||||||
|
body: condition.value,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else if (type.value === 'duration' && condition.value) {
|
||||||
|
timerDef.timeDuration = bpmnInstances().bpmnFactory.create(
|
||||||
|
'bpmn:FormalExpression',
|
||||||
|
{
|
||||||
|
body: condition.value,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else if (type.value === 'cycle' && condition.value) {
|
||||||
|
timerDef.timeCycle = bpmnInstances().bpmnFactory.create(
|
||||||
|
'bpmn:FormalExpression',
|
||||||
|
{
|
||||||
|
body: condition.value,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(element), {
|
||||||
|
eventDefinitions: [timerDef],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.businessObject,
|
||||||
|
(val) => {
|
||||||
|
if (val) {
|
||||||
|
nextTick(() => {
|
||||||
|
syncFromBusinessObject();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* 相关样式 */
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
/* 改变主题色变量 */
|
||||||
|
$--color-primary: #1890ff;
|
||||||
|
$--color-danger: #ff4d4f;
|
||||||
|
|
||||||
|
/* 改变 icon 字体路径变量,必需 */
|
||||||
|
$--font-path: '~element-ui/lib/theme-chalk/fonts';
|
||||||
|
|
||||||
|
@use '~element-ui/packages/theme-chalk/src/index';
|
||||||
|
|
||||||
|
.el-table td,
|
||||||
|
.el-table th {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-drawer__header {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 16px 16px 8px;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 24px;
|
||||||
|
color: #303133;
|
||||||
|
border-bottom: 1px solid #e8e8e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
div[class^='el-drawer']:focus,
|
||||||
|
span:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-drawer__body {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
padding: 16px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-dialog {
|
||||||
|
margin-top: 50vh !important;
|
||||||
|
overflow: hidden;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-dialog__wrapper {
|
||||||
|
max-height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-dialog__header {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 16px 16px 8px;
|
||||||
|
border-bottom: 1px solid #e8e8e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-dialog__body {
|
||||||
|
box-sizing: border-box;
|
||||||
|
max-height: 80vh;
|
||||||
|
padding: 16px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-dialog__footer {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 16px;
|
||||||
|
border-top: 1px solid #e8e8e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-dialog__close {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-select {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-divider:not(.el-divider--horizontal) {
|
||||||
|
margin: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-divider.el-divider--horizontal {
|
||||||
|
margin: 16px 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
@use './process-designer';
|
||||||
|
@use './process-panel';
|
||||||
|
|
||||||
|
$success-color: #4eb819;
|
||||||
|
$primary-color: #409eff;
|
||||||
|
$danger-color: #f56c6c;
|
||||||
|
$cancel-color: #909399;
|
||||||
|
|
||||||
|
.process-viewer {
|
||||||
|
position: relative;
|
||||||
|
background: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PHBhdHRlcm4gaWQ9ImEiIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgcGF0dGVyblVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGggZD0iTTAgMTBoNDBNMTAgMHY0ME0wIDIwaDQwTTIwIDB2NDBNMCAzMGg0ME0zMCAwdjQwIiBmaWxsPSJub25lIiBzdHJva2U9IiNlMGUwZTAiIG9wYWNpdHk9Ii4yIi8+PHBhdGggZD0iTTQwIDBIMHY0MCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZTBlMGUwIi8+PC9wYXR0ZXJuPjwvZGVmcz48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJ1cmwoI2EpIi8+PC9zdmc+')
|
||||||
|
repeat !important;
|
||||||
|
border: 1px solid #efefef;
|
||||||
|
|
||||||
|
.success-arrow {
|
||||||
|
fill: $success-color;
|
||||||
|
stroke: $success-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.success-conditional {
|
||||||
|
fill: white;
|
||||||
|
stroke: $success-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.success.djs-connection {
|
||||||
|
.djs-visual path {
|
||||||
|
stroke: $success-color !important;
|
||||||
|
//marker-end: url(#sequenceflow-end-white-success)!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.success.djs-connection.condition-expression {
|
||||||
|
.djs-visual path {
|
||||||
|
//marker-start: url(#conditional-flow-marker-white-success)!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.success.djs-shape {
|
||||||
|
.djs-visual rect {
|
||||||
|
fill: $success-color !important;
|
||||||
|
fill-opacity: 0.15 !important;
|
||||||
|
stroke: $success-color !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.djs-visual polygon {
|
||||||
|
stroke: $success-color !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.djs-visual path:nth-child(2) {
|
||||||
|
fill: $success-color !important;
|
||||||
|
stroke: $success-color !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.djs-visual circle {
|
||||||
|
fill: $success-color !important;
|
||||||
|
fill-opacity: 0.15 !important;
|
||||||
|
stroke: $success-color !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.primary.djs-shape {
|
||||||
|
.djs-visual rect {
|
||||||
|
fill: $primary-color !important;
|
||||||
|
fill-opacity: 0.15 !important;
|
||||||
|
stroke: $primary-color !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.djs-visual polygon {
|
||||||
|
stroke: $primary-color !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.djs-visual circle {
|
||||||
|
fill: $primary-color !important;
|
||||||
|
fill-opacity: 0.15 !important;
|
||||||
|
stroke: $primary-color !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.danger.djs-shape {
|
||||||
|
.djs-visual rect {
|
||||||
|
fill: $danger-color !important;
|
||||||
|
fill-opacity: 0.15 !important;
|
||||||
|
stroke: $danger-color !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.djs-visual polygon {
|
||||||
|
stroke: $danger-color !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.djs-visual circle {
|
||||||
|
fill: $danger-color !important;
|
||||||
|
fill-opacity: 0.15 !important;
|
||||||
|
stroke: $danger-color !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel.djs-shape {
|
||||||
|
.djs-visual rect {
|
||||||
|
fill: $cancel-color !important;
|
||||||
|
fill-opacity: 0.15 !important;
|
||||||
|
stroke: $cancel-color !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.djs-visual polygon {
|
||||||
|
stroke: $cancel-color !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.djs-visual circle {
|
||||||
|
fill: $cancel-color !important;
|
||||||
|
fill-opacity: 0.15 !important;
|
||||||
|
stroke: $cancel-color !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.process-viewer .djs-tooltip-container,
|
||||||
|
.process-viewer .djs-overlay-container,
|
||||||
|
.process-viewer .djs-palette {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
@@ -0,0 +1,184 @@
|
|||||||
|
@use 'bpmn-js-token-simulation/assets/css/bpmn-js-token-simulation.css';
|
||||||
|
|
||||||
|
// 边框被 token-simulation 样式覆盖了
|
||||||
|
.djs-palette {
|
||||||
|
background: var(--palette-background-color);
|
||||||
|
border: solid 1px var(--palette-border-color) !important;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.my-process-designer {
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.my-process-designer__header {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 36px;
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-button-group {
|
||||||
|
margin: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tooltip__popper {
|
||||||
|
.el-button {
|
||||||
|
width: 100%;
|
||||||
|
padding-right: 8px;
|
||||||
|
padding-left: 8px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-button:hover {
|
||||||
|
color: #fff;
|
||||||
|
background: rgb(64 158 255 / 80%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.align {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
i {
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
content: '|';
|
||||||
|
// transform: rotate(90deg) translate(200%, 60%);
|
||||||
|
transform: rotate(180deg) translate(271%, -10%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.align.align-left i {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.align.align-right i {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.align.align-top i {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.align.align-bottom i {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.align.align-center i {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
// transform: rotate(90deg) translate(0, 60%);
|
||||||
|
transform: rotate(0deg) translate(-0%, -5%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.align.align-middle i {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
// transform: rotate(90deg) translate(0, 60%);
|
||||||
|
transform: rotate(0deg) translate(0, -10%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.my-process-designer__container {
|
||||||
|
display: inline-flex;
|
||||||
|
flex: 1;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.my-process-designer__canvas {
|
||||||
|
position: relative;
|
||||||
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
background: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PHBhdHRlcm4gaWQ9ImEiIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgcGF0dGVyblVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGggZD0iTTAgMTBoNDBNMTAgMHY0ME0wIDIwaDQwTTIwIDB2NDBNMCAzMGg0ME0zMCAwdjQwIiBmaWxsPSJub25lIiBzdHJva2U9IiNlMGUwZTAiIG9wYWNpdHk9Ii4yIi8+PHBhdGggZD0iTTQwIDBIMHY0MCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZTBlMGUwIi8+PC9wYXR0ZXJuPjwvZGVmcz48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJ1cmwoI2EpIi8+PC9zdmc+')
|
||||||
|
repeat !important;
|
||||||
|
|
||||||
|
div.toggle-mode {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.my-process-designer__property-panel {
|
||||||
|
z-index: 10;
|
||||||
|
height: 100%;
|
||||||
|
overflow: scroll;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// svg {
|
||||||
|
// width: 100%;
|
||||||
|
// height: 100%;
|
||||||
|
// min-height: 100%;
|
||||||
|
// overflow: hidden;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//侧边栏配置
|
||||||
|
// .djs-palette .two-column .open {
|
||||||
|
.open {
|
||||||
|
// .djs-palette.open {
|
||||||
|
.djs-palette-entries {
|
||||||
|
div[class^='bpmn-icon-']::before,
|
||||||
|
div[class*='bpmn-icon-']::before {
|
||||||
|
line-height: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.entry {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.entry:hover {
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: -10px;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 100;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: inline-block;
|
||||||
|
width: max-content;
|
||||||
|
padding: 0 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
font-size: 0.5em;
|
||||||
|
font-variant: normal;
|
||||||
|
vertical-align: text-bottom;
|
||||||
|
text-transform: none;
|
||||||
|
text-decoration: inherit;
|
||||||
|
content: attr(title);
|
||||||
|
background: #fafafa;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 0 6px #eee;
|
||||||
|
transform: translateX(100%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
height: 100%;
|
||||||
|
max-height: calc(80vh - 32px);
|
||||||
|
margin: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs {
|
||||||
|
word-break: break-word;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs * {
|
||||||
|
font-family: Consolas, Monaco, monospace;
|
||||||
|
}
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
.process-panel__container {
|
||||||
|
box-sizing: border-box;
|
||||||
|
max-height: 100%;
|
||||||
|
padding: 0 8px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
border-left: 1px solid #eee;
|
||||||
|
box-shadow: 0 0 8px #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-tab__title {
|
||||||
|
padding: 0 8px;
|
||||||
|
font-size: 1.1em;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.2em;
|
||||||
|
|
||||||
|
i {
|
||||||
|
margin-right: 8px;
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-tab__content {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
padding: 8px 16px;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
|
||||||
|
.panel-tab__content--title {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
|
||||||
|
span {
|
||||||
|
flex: 1;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.element-property {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
width: 100%;
|
||||||
|
margin: 8px 0;
|
||||||
|
|
||||||
|
.element-property__label {
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: block;
|
||||||
|
width: 90px;
|
||||||
|
padding-right: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 32px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.element-property__value {
|
||||||
|
flex: 1;
|
||||||
|
line-height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item {
|
||||||
|
width: 100%;
|
||||||
|
padding-bottom: 18px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-property {
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.element-listener-item {
|
||||||
|
display: inline-grid;
|
||||||
|
grid-template-columns: 16px auto 32px 32px;
|
||||||
|
grid-column-gap: 8px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.element-listener-item + .element-listener-item {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.listener-filed__title {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 0;
|
||||||
|
|
||||||
|
span {
|
||||||
|
width: 200px;
|
||||||
|
font-size: 14px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.element-drawer__button {
|
||||||
|
display: inline-flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.element-drawer__button > .el-button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-collapse-item__content {
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-input.is-disabled .el-input__inner {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item.el-form-item--mini {
|
||||||
|
margin-bottom: 0;
|
||||||
|
|
||||||
|
& + .el-form-item {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
import { toRaw } from 'vue';
|
||||||
|
|
||||||
|
const bpmnInstances = () => (window as any)?.bpmnInstances;
|
||||||
|
// 创建监听器实例
|
||||||
|
export function createListenerObject(options, isTask, prefix) {
|
||||||
|
const listenerObj = Object.create(null);
|
||||||
|
listenerObj.event = options.event;
|
||||||
|
isTask && (listenerObj.id = options.id); // 任务监听器特有的 id 字段
|
||||||
|
switch (options.listenerType) {
|
||||||
|
case 'delegateExpressionListener': {
|
||||||
|
listenerObj.delegateExpression = options.delegateExpression;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'expressionListener': {
|
||||||
|
listenerObj.expression = options.expression;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'scriptListener': {
|
||||||
|
listenerObj.script = createScriptObject(options, prefix);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
listenerObj.class = options.class;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 注入字段
|
||||||
|
if (options.fields) {
|
||||||
|
listenerObj.fields = options.fields.map((field) => {
|
||||||
|
return createFieldObject(field, prefix);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 任务监听器的 定时器 设置
|
||||||
|
if (isTask && options.event === 'timeout' && !!options.eventDefinitionType) {
|
||||||
|
const timeDefinition = bpmnInstances().moddle.create(
|
||||||
|
'bpmn:FormalExpression',
|
||||||
|
{
|
||||||
|
body: options.eventTimeDefinitions,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const TimerEventDefinition = bpmnInstances().moddle.create(
|
||||||
|
'bpmn:TimerEventDefinition',
|
||||||
|
{
|
||||||
|
id: `TimerEventDefinition_${uuid(8)}`,
|
||||||
|
[`time${options.eventDefinitionType.replace(/^\S/, (s) => s.toUpperCase())}`]:
|
||||||
|
timeDefinition,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
listenerObj.eventDefinitions = [TimerEventDefinition];
|
||||||
|
}
|
||||||
|
return bpmnInstances().moddle.create(
|
||||||
|
`${prefix}:${isTask ? 'TaskListener' : 'ExecutionListener'}`,
|
||||||
|
listenerObj,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建 监听器的注入字段 实例
|
||||||
|
export function createFieldObject(option, prefix) {
|
||||||
|
const { name, fieldType, string, expression } = option;
|
||||||
|
const fieldConfig =
|
||||||
|
fieldType === 'string' ? { name, string } : { name, expression };
|
||||||
|
return bpmnInstances().moddle.create(`${prefix}:Field`, fieldConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建脚本实例
|
||||||
|
export function createScriptObject(options, prefix) {
|
||||||
|
const { scriptType, scriptFormat, value, resource } = options;
|
||||||
|
const scriptConfig =
|
||||||
|
scriptType === 'inlineScript'
|
||||||
|
? { scriptFormat, value }
|
||||||
|
: { scriptFormat, resource };
|
||||||
|
return bpmnInstances().moddle.create(`${prefix}:Script`, scriptConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新元素扩展属性
|
||||||
|
export function updateElementExtensions(element, extensionList) {
|
||||||
|
const extensions = bpmnInstances().moddle.create('bpmn:ExtensionElements', {
|
||||||
|
values: extensionList,
|
||||||
|
});
|
||||||
|
bpmnInstances().modeling.updateProperties(toRaw(element), {
|
||||||
|
extensionElements: extensions,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建一个id
|
||||||
|
export function uuid(length = 8, chars?) {
|
||||||
|
let result = '';
|
||||||
|
const charsString =
|
||||||
|
chars || '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||||
|
for (let i = length; i > 0; --i) {
|
||||||
|
result += charsString[Math.floor(Math.random() * charsString.length)];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
const hljs = require('highlight.js/lib/core');
|
||||||
|
hljs.registerLanguage('xml', require('highlight.js/lib/languages/xml'));
|
||||||
|
hljs.registerLanguage('json', require('highlight.js/lib/languages/json'));
|
||||||
|
|
||||||
|
module.exports = hljs;
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import BpmnRenderer from 'bpmn-js/lib/draw/BpmnRenderer';
|
||||||
|
|
||||||
|
export default function CustomRenderer(
|
||||||
|
config,
|
||||||
|
eventBus,
|
||||||
|
styles,
|
||||||
|
pathMap,
|
||||||
|
canvas,
|
||||||
|
textRenderer,
|
||||||
|
) {
|
||||||
|
BpmnRenderer.call(
|
||||||
|
this,
|
||||||
|
config,
|
||||||
|
eventBus,
|
||||||
|
styles,
|
||||||
|
pathMap,
|
||||||
|
canvas,
|
||||||
|
textRenderer,
|
||||||
|
2000,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.handlers.label = function () {
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const F = function () {}; // 核心,利用空对象作为中介;
|
||||||
|
F.prototype = BpmnRenderer.prototype; // 核心,将父类的原型赋值给空对象F;
|
||||||
|
CustomRenderer.prototype = new F(); // 核心,将 F的实例赋值给子类;
|
||||||
|
CustomRenderer.prototype.constructor = CustomRenderer; // 修复子类CustomRenderer的构造器指向,防止原型链的混乱;
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import CustomRenderer from './CustomRenderer';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
__init__: ['customRenderer'],
|
||||||
|
customRenderer: ['type', CustomRenderer],
|
||||||
|
};
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import BpmnRules from 'bpmn-js/lib/features/rules/BpmnRules';
|
||||||
|
import inherits from 'inherits';
|
||||||
|
|
||||||
|
export default function CustomRules(eventBus) {
|
||||||
|
BpmnRules.call(this, eventBus);
|
||||||
|
}
|
||||||
|
|
||||||
|
inherits(CustomRules, BpmnRules);
|
||||||
|
|
||||||
|
CustomRules.prototype.canDrop = function () {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
CustomRules.prototype.canMove = function () {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import CustomRules from './CustomRules';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
__init__: ['customRules'],
|
||||||
|
customRules: ['type', CustomRules],
|
||||||
|
};
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/**
|
||||||
|
* This is a sample file that should be replaced with the actual translation.
|
||||||
|
*
|
||||||
|
* Checkout https://github.com/bpmn-io/bpmn-js-i18n for a list of available
|
||||||
|
* translations and labels to translate.
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
'Exclusive Gateway': 'Exklusives Gateway',
|
||||||
|
'Parallel Gateway': 'Paralleles Gateway',
|
||||||
|
'Inclusive Gateway': 'Inklusives Gateway',
|
||||||
|
'Complex Gateway': 'Komplexes Gateway',
|
||||||
|
'Event based Gateway': 'Ereignis-basiertes Gateway',
|
||||||
|
'Message Start Event': '消息启动事件',
|
||||||
|
'Timer Start Event': '定时启动事件',
|
||||||
|
'Conditional Start Event': '条件启动事件',
|
||||||
|
'Signal Start Event': '信号启动事件',
|
||||||
|
'Error Start Event': '错误启动事件',
|
||||||
|
'Escalation Start Event': '升级启动事件',
|
||||||
|
'Compensation Start Event': '补偿启动事件',
|
||||||
|
'Message Start Event (non-interrupting)': '消息启动事件 (非中断)',
|
||||||
|
'Timer Start Event (non-interrupting)': '定时启动事件 (非中断)',
|
||||||
|
'Conditional Start Event (non-interrupting)': '条件启动事件 (非中断)',
|
||||||
|
'Signal Start Event (non-interrupting)': '信号启动事件 (非中断)',
|
||||||
|
'Escalation Start Event (non-interrupting)': '升级启动事件 (非中断)',
|
||||||
|
};
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
// outside.js
|
||||||
|
|
||||||
|
const ctx = '@@clickoutsideContext';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
bind(el, binding, vnode) {
|
||||||
|
const ele = el;
|
||||||
|
const documentHandler = (e) => {
|
||||||
|
if (!vnode.context || ele.contains(e.target)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 调用指令回调
|
||||||
|
if (binding.expression) {
|
||||||
|
vnode.context[el[ctx].methodName](e);
|
||||||
|
} else {
|
||||||
|
el[ctx].bindingFn(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 将方法添加到ele
|
||||||
|
ele[ctx] = {
|
||||||
|
documentHandler,
|
||||||
|
methodName: binding.expression,
|
||||||
|
bindingFn: binding.value,
|
||||||
|
};
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
document.addEventListener('touchstart', documentHandler); // 为document绑定事件
|
||||||
|
});
|
||||||
|
},
|
||||||
|
update(el, binding) {
|
||||||
|
const ele = el;
|
||||||
|
ele[ctx].methodName = binding.expression;
|
||||||
|
ele[ctx].bindingFn = binding.value;
|
||||||
|
},
|
||||||
|
unbind(el) {
|
||||||
|
document.removeEventListener('touchstart', el[ctx].documentHandler); // 解绑
|
||||||
|
delete el[ctx];
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
export function debounce(fn, delay = 500) {
|
||||||
|
let timer;
|
||||||
|
return function (...args) {
|
||||||
|
if (timer) {
|
||||||
|
clearTimeout(timer);
|
||||||
|
timer = null;
|
||||||
|
}
|
||||||
|
timer = setTimeout(fn.bind(this, ...args), delay);
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
function xmlStr2XmlObj(xmlStr) {
|
||||||
|
let xmlObj = {};
|
||||||
|
if (document.all) {
|
||||||
|
const xmlDom = new window.ActiveXObject('Microsoft.XMLDOM');
|
||||||
|
xmlDom.loadXML(xmlStr);
|
||||||
|
xmlObj = xmlDom;
|
||||||
|
} else {
|
||||||
|
xmlObj = new DOMParser().parseFromString(xmlStr, 'text/xml');
|
||||||
|
}
|
||||||
|
return xmlObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
function xml2json(xml) {
|
||||||
|
try {
|
||||||
|
let obj = {};
|
||||||
|
if (xml.children.length > 0) {
|
||||||
|
for (let i = 0; i < xml.children.length; i++) {
|
||||||
|
const item = xml.children.item(i);
|
||||||
|
const nodeName = item.nodeName;
|
||||||
|
if (obj[nodeName] === undefined) {
|
||||||
|
obj[nodeName] = xml2json(item);
|
||||||
|
} else {
|
||||||
|
if (obj[nodeName].push === undefined) {
|
||||||
|
const old = obj[nodeName];
|
||||||
|
obj[nodeName] = [];
|
||||||
|
obj[nodeName].push(old);
|
||||||
|
}
|
||||||
|
obj[nodeName].push(xml2json(item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
obj = xml.textContent;
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function xmlObj2json(xml) {
|
||||||
|
const xmlObj = xmlStr2XmlObj(xml);
|
||||||
|
console.log(xmlObj);
|
||||||
|
let jsonObj = {};
|
||||||
|
if (xmlObj.childNodes.length > 0) {
|
||||||
|
jsonObj = xml2json(xmlObj);
|
||||||
|
}
|
||||||
|
return jsonObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default xmlObj2json;
|
||||||
533
pnpm-lock.yaml
generated
533
pnpm-lock.yaml
generated
@@ -782,18 +782,39 @@ importers:
|
|||||||
ant-design-vue:
|
ant-design-vue:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 4.2.6(vue@3.5.18(typescript@5.9.2))
|
version: 4.2.6(vue@3.5.18(typescript@5.9.2))
|
||||||
|
bpmn-js:
|
||||||
|
specifier: ^17.11.1
|
||||||
|
version: 17.11.1
|
||||||
|
bpmn-js-properties-panel:
|
||||||
|
specifier: 5.23.0
|
||||||
|
version: 5.23.0(@bpmn-io/properties-panel@3.33.0)(bpmn-js@17.11.1)(camunda-bpmn-js-behaviors@1.11.1(bpmn-js@17.11.1)(camunda-bpmn-moddle@7.0.1)(zeebe-bpmn-moddle@1.11.0))(diagram-js@12.8.1)
|
||||||
|
bpmn-js-token-simulation:
|
||||||
|
specifier: ^0.36.3
|
||||||
|
version: 0.36.3
|
||||||
|
camunda-bpmn-moddle:
|
||||||
|
specifier: ^7.0.1
|
||||||
|
version: 7.0.1
|
||||||
cropperjs:
|
cropperjs:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 1.6.2
|
version: 1.6.2
|
||||||
dayjs:
|
dayjs:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 1.11.13
|
version: 1.11.13
|
||||||
|
diagram-js:
|
||||||
|
specifier: ^12.8.1
|
||||||
|
version: 12.8.1
|
||||||
|
fast-xml-parser:
|
||||||
|
specifier: ^4.5.3
|
||||||
|
version: 4.5.3
|
||||||
highlight.js:
|
highlight.js:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 11.11.1
|
version: 11.11.1
|
||||||
pinia:
|
pinia:
|
||||||
specifier: ^3.0.3
|
specifier: ^3.0.3
|
||||||
version: 3.0.3(typescript@5.9.2)(vue@3.5.18(typescript@5.9.2))
|
version: 3.0.3(typescript@5.9.2)(vue@3.5.18(typescript@5.9.2))
|
||||||
|
steady-xml:
|
||||||
|
specifier: ^0.1.0
|
||||||
|
version: 0.1.0
|
||||||
tinymce:
|
tinymce:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 7.9.1
|
version: 7.9.1
|
||||||
@@ -2817,6 +2838,37 @@ packages:
|
|||||||
resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==}
|
resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
|
'@bpmn-io/cm-theme@0.1.0-alpha.2':
|
||||||
|
resolution: {integrity: sha512-ZILgiYzxk3KMvxplUXmdRFQo45/JehDPg5k9tWfehmzUOSE13ssyLPil8uCloMQnb3yyzyOWTjb/wzKXTHlFQw==}
|
||||||
|
|
||||||
|
'@bpmn-io/diagram-js-ui@0.2.3':
|
||||||
|
resolution: {integrity: sha512-OGyjZKvGK8tHSZ0l7RfeKhilGoOGtFDcoqSGYkX0uhFlo99OVZ9Jn1K7TJGzcE9BdKwvA5Y5kGqHEhdTxHvFfw==}
|
||||||
|
|
||||||
|
'@bpmn-io/extract-process-variables@0.8.0':
|
||||||
|
resolution: {integrity: sha512-yAS7ZYX+D56K+luC36u96eRMLb4VHcPUwTUqMZ/Z/Je2gou2DJLRbuBTHAB4jjKt4wFCHSG4B8Y+TrBciEYf4w==}
|
||||||
|
|
||||||
|
'@bpmn-io/feel-editor@1.12.0':
|
||||||
|
resolution: {integrity: sha512-l19PUPZX4DurVNZF06x3mJ0jBNnVpEJTP4tTzVBpgxofxRDWemDjfHWlY+gsuW4QFFGjVL3hV5IIEiZp/oA3Kw==}
|
||||||
|
engines: {node: '>= 16'}
|
||||||
|
|
||||||
|
'@bpmn-io/feel-lint@1.4.0':
|
||||||
|
resolution: {integrity: sha512-1bsdR/9vPD7RQVqWWPk0X0tpjLsYTDrCxIzOVtN/h32o4nPGl0dZBU5m07qaFUGD4wG3eOH4Qim1wexHG8YkBw==}
|
||||||
|
|
||||||
|
'@bpmn-io/feel-lint@2.1.0':
|
||||||
|
resolution: {integrity: sha512-fUGye6KppyowiwUqlfRHpMtXQ8so8jv1rh2LEQp+fhKf+WeLkbokmQwXZbCQe/4Kam/OLQRlx+p3Qnu0IrZQ6A==}
|
||||||
|
|
||||||
|
'@bpmn-io/lang-feel@2.4.0':
|
||||||
|
resolution: {integrity: sha512-0c1pratAD/YTOaivwLd7MljT0/MoDUMpfm87JbtAOBvivRfEr8mel5l8Ig3kgpYJ+xkznLaA9s79ZDKLh/O8ag==}
|
||||||
|
|
||||||
|
'@bpmn-io/lezer-feel@1.9.0':
|
||||||
|
resolution: {integrity: sha512-mV+pj+x0++9zT5/RkOOUNtkT2hpKpGWbXuFR8trJlvJeRe1dL/5yPal/RBcnk3z73tILK4kP6LzXelcsshQCEw==}
|
||||||
|
|
||||||
|
'@bpmn-io/properties-panel@3.33.0':
|
||||||
|
resolution: {integrity: sha512-I41JNpfX7zzKTOpmB84ETt8dnyE4OLDtzNmQBN6m3wEnfFw19VuBa7C0XXMtF/Us1zvy3yFx+dAH//Hgg9e0uQ==}
|
||||||
|
|
||||||
|
'@camunda/feel-builtins@0.2.0':
|
||||||
|
resolution: {integrity: sha512-Jusm8x3Onqze9E5Y0lGGdPj66bnFKLYNwDz+uG4otsEXgSL0FpF+koGHK48LkF9Jqo67KaP1y3zr2y/HIWRePw==}
|
||||||
|
|
||||||
'@changesets/apply-release-plan@7.0.12':
|
'@changesets/apply-release-plan@7.0.12':
|
||||||
resolution: {integrity: sha512-EaET7As5CeuhTzvXTQCRZeBUcisoYPDDcXvgTE/2jmmypKp0RC7LxKj/yzqeh/1qFTZI7oDGFcL1PHRuQuketQ==}
|
resolution: {integrity: sha512-EaET7As5CeuhTzvXTQCRZeBUcisoYPDDcXvgTE/2jmmypKp0RC7LxKj/yzqeh/1qFTZI7oDGFcL1PHRuQuketQ==}
|
||||||
|
|
||||||
@@ -2888,6 +2940,24 @@ packages:
|
|||||||
resolution: {integrity: sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA==}
|
resolution: {integrity: sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA==}
|
||||||
engines: {node: '>=18.0.0'}
|
engines: {node: '>=18.0.0'}
|
||||||
|
|
||||||
|
'@codemirror/autocomplete@6.18.7':
|
||||||
|
resolution: {integrity: sha512-8EzdeIoWPJDsMBwz3zdzwXnUpCzMiCyz5/A3FIPpriaclFCGDkAzK13sMcnsu5rowqiyeQN2Vs2TsOcoDPZirQ==}
|
||||||
|
|
||||||
|
'@codemirror/commands@6.8.1':
|
||||||
|
resolution: {integrity: sha512-KlGVYufHMQzxbdQONiLyGQDUW0itrLZwq3CcY7xpv9ZLRHqzkBSoteocBHtMCoY7/Ci4xhzSrToIeLg7FxHuaw==}
|
||||||
|
|
||||||
|
'@codemirror/language@6.11.3':
|
||||||
|
resolution: {integrity: sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA==}
|
||||||
|
|
||||||
|
'@codemirror/lint@6.8.5':
|
||||||
|
resolution: {integrity: sha512-s3n3KisH7dx3vsoeGMxsbRAgKe4O1vbrnKBClm99PU0fWxmxsx5rR2PfqQgIt+2MMJBHbiJ5rfIdLYfB9NNvsA==}
|
||||||
|
|
||||||
|
'@codemirror/state@6.5.2':
|
||||||
|
resolution: {integrity: sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==}
|
||||||
|
|
||||||
|
'@codemirror/view@6.38.2':
|
||||||
|
resolution: {integrity: sha512-bTWAJxL6EOFLPzTx+O5P5xAO3gTqpatQ2b/ARQ8itfU/v2LlpS3pH2fkL0A3E/Fx8Y2St2KES7ZEV0sHTsSW/A==}
|
||||||
|
|
||||||
'@colors/colors@1.6.0':
|
'@colors/colors@1.6.0':
|
||||||
resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==}
|
resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==}
|
||||||
engines: {node: '>=0.1.90'}
|
engines: {node: '>=0.1.90'}
|
||||||
@@ -3993,6 +4063,18 @@ packages:
|
|||||||
'@keyv/serialize@1.1.0':
|
'@keyv/serialize@1.1.0':
|
||||||
resolution: {integrity: sha512-RlDgexML7Z63Q8BSaqhXdCYNBy/JQnqYIwxofUrNLGCblOMHp+xux2Q8nLMLlPpgHQPoU0Do8Z6btCpRBEqZ8g==}
|
resolution: {integrity: sha512-RlDgexML7Z63Q8BSaqhXdCYNBy/JQnqYIwxofUrNLGCblOMHp+xux2Q8nLMLlPpgHQPoU0Do8Z6btCpRBEqZ8g==}
|
||||||
|
|
||||||
|
'@lezer/common@1.2.3':
|
||||||
|
resolution: {integrity: sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==}
|
||||||
|
|
||||||
|
'@lezer/highlight@1.2.1':
|
||||||
|
resolution: {integrity: sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==}
|
||||||
|
|
||||||
|
'@lezer/lr@1.4.2':
|
||||||
|
resolution: {integrity: sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==}
|
||||||
|
|
||||||
|
'@lezer/markdown@1.4.3':
|
||||||
|
resolution: {integrity: sha512-kfw+2uMrQ/wy/+ONfrH83OkdFNM0ye5Xq96cLlaCy7h5UT9FO54DU4oRoIc0CSBh5NWmWuiIJA7NGLMJbQ+Oxg==}
|
||||||
|
|
||||||
'@manypkg/find-root@1.1.0':
|
'@manypkg/find-root@1.1.0':
|
||||||
resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==}
|
resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==}
|
||||||
|
|
||||||
@@ -4016,6 +4098,9 @@ packages:
|
|||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
'@marijn/find-cluster-break@1.0.2':
|
||||||
|
resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==}
|
||||||
|
|
||||||
'@microsoft/api-extractor-model@7.30.7':
|
'@microsoft/api-extractor-model@7.30.7':
|
||||||
resolution: {integrity: sha512-TBbmSI2/BHpfR9YhQA7nH0nqVmGgJ0xH0Ex4D99/qBDAUpnhA2oikGmdXanbw9AWWY/ExBYIpkmY8dBHdla3YQ==}
|
resolution: {integrity: sha512-TBbmSI2/BHpfR9YhQA7nH0nqVmGgJ0xH0Ex4D99/qBDAUpnhA2oikGmdXanbw9AWWY/ExBYIpkmY8dBHdla3YQ==}
|
||||||
|
|
||||||
@@ -5566,6 +5651,10 @@ packages:
|
|||||||
array-ify@1.0.0:
|
array-ify@1.0.0:
|
||||||
resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==}
|
resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==}
|
||||||
|
|
||||||
|
array-move@4.0.0:
|
||||||
|
resolution: {integrity: sha512-+RY54S8OuVvg94THpneQvFRmqWdAHeqtMzgMW6JNurHxe8rsS07cHQdfGkXnTUXiBcyZ0j3SiDIxxj0RPiqCkQ==}
|
||||||
|
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||||
|
|
||||||
array-timsort@1.0.3:
|
array-timsort@1.0.3:
|
||||||
resolution: {integrity: sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==}
|
resolution: {integrity: sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==}
|
||||||
|
|
||||||
@@ -5702,6 +5791,24 @@ packages:
|
|||||||
resolution: {integrity: sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==}
|
resolution: {integrity: sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
bpmn-js-properties-panel@5.23.0:
|
||||||
|
resolution: {integrity: sha512-4B27LM8oV14A2QWRvazV17h4NxbkNERcqU+AGJmxKImMlLhu9893MWR+pCdTQCTphBdBkuD8ksWm+1wVCedJ7g==}
|
||||||
|
peerDependencies:
|
||||||
|
'@bpmn-io/properties-panel': '>= 3.7'
|
||||||
|
bpmn-js: '>= 11.5'
|
||||||
|
camunda-bpmn-js-behaviors: '>= 0.4'
|
||||||
|
diagram-js: '>= 11.9'
|
||||||
|
|
||||||
|
bpmn-js-token-simulation@0.36.3:
|
||||||
|
resolution: {integrity: sha512-HyiExdi+vENiStn284gIUQkQliiWly4dk2kY9PJILwwuTIoKtvg1zw8LGr9ReNUiScibNbpkt45bR25Oqfq9wA==}
|
||||||
|
engines: {node: '>= 16'}
|
||||||
|
|
||||||
|
bpmn-js@17.11.1:
|
||||||
|
resolution: {integrity: sha512-ywCeTg5kvN8lYkU+fHE+YXTGlfKc55lRBn7zW3k1//toeMNPy/PS/uQiujRWdFhMrH5dbtDvlwWukNw2pjWw8Q==}
|
||||||
|
|
||||||
|
bpmn-moddle@8.1.0:
|
||||||
|
resolution: {integrity: sha512-yI5OAFfYVJwViKTsTsonVfCBPtB3MlefADUORwNIxxBOMp21vnoxuxsdgUWlPH/dvAEZh/+mr8UtqOBNu8NC5Q==}
|
||||||
|
|
||||||
brace-expansion@1.1.12:
|
brace-expansion@1.1.12:
|
||||||
resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==}
|
resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==}
|
||||||
|
|
||||||
@@ -5802,6 +5909,16 @@ packages:
|
|||||||
resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==}
|
resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
|
|
||||||
|
camunda-bpmn-js-behaviors@1.11.1:
|
||||||
|
resolution: {integrity: sha512-It6OLShW7wuMC12Vc6OZPxbtRKX8j5AvqnBktXs5jyfUndqcRNHRkZ7wSEiTqAkHyl6ATNuYmfNUQzqxFyNmKg==}
|
||||||
|
peerDependencies:
|
||||||
|
bpmn-js: '>= 9'
|
||||||
|
camunda-bpmn-moddle: '>= 7'
|
||||||
|
zeebe-bpmn-moddle: '>= 0.18'
|
||||||
|
|
||||||
|
camunda-bpmn-moddle@7.0.1:
|
||||||
|
resolution: {integrity: sha512-Br8Diu6roMpziHdpl66Dhnm0DTnCFMrSD9zwLV08LpD52QA0UsXxU87XfHf08HjuB7ly0Hd1bvajZRpf9hbmYQ==}
|
||||||
|
|
||||||
caniuse-api@3.0.0:
|
caniuse-api@3.0.0:
|
||||||
resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==}
|
resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==}
|
||||||
|
|
||||||
@@ -5885,6 +6002,9 @@ packages:
|
|||||||
class-variance-authority@0.7.1:
|
class-variance-authority@0.7.1:
|
||||||
resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==}
|
resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==}
|
||||||
|
|
||||||
|
classnames@2.5.1:
|
||||||
|
resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==}
|
||||||
|
|
||||||
clean-css@5.3.3:
|
clean-css@5.3.3:
|
||||||
resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==}
|
resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==}
|
||||||
engines: {node: '>= 10.0'}
|
engines: {node: '>= 10.0'}
|
||||||
@@ -6045,6 +6165,9 @@ packages:
|
|||||||
compatx@0.2.0:
|
compatx@0.2.0:
|
||||||
resolution: {integrity: sha512-6gLRNt4ygsi5NyMVhceOCFv14CIdDFN7fQjX1U4+47qVE/+kjPoXMK65KWK+dWxmFzMTuKazoQ9sch6pM0p5oA==}
|
resolution: {integrity: sha512-6gLRNt4ygsi5NyMVhceOCFv14CIdDFN7fQjX1U4+47qVE/+kjPoXMK65KWK+dWxmFzMTuKazoQ9sch6pM0p5oA==}
|
||||||
|
|
||||||
|
component-event@0.2.1:
|
||||||
|
resolution: {integrity: sha512-wGA++isMqiDq1jPYeyv2as/Bt/u+3iLW0rEa+8NQ82jAv3TgqMiCM+B2SaBdn2DfLilLjjq736YcezihRYhfxw==}
|
||||||
|
|
||||||
compress-commons@6.0.2:
|
compress-commons@6.0.2:
|
||||||
resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==}
|
resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==}
|
||||||
engines: {node: '>= 14'}
|
engines: {node: '>= 14'}
|
||||||
@@ -6158,6 +6281,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==}
|
resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==}
|
||||||
engines: {node: '>= 14'}
|
engines: {node: '>= 14'}
|
||||||
|
|
||||||
|
crelt@1.0.6:
|
||||||
|
resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==}
|
||||||
|
|
||||||
cron-parser@4.9.0:
|
cron-parser@4.9.0:
|
||||||
resolution: {integrity: sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==}
|
resolution: {integrity: sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
@@ -6677,6 +6803,24 @@ packages:
|
|||||||
devlop@1.1.0:
|
devlop@1.1.0:
|
||||||
resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
|
resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
|
||||||
|
|
||||||
|
diagram-js-direct-editing@3.2.0:
|
||||||
|
resolution: {integrity: sha512-+pyxeQGBSdLiZX0/tmmsm2qZSvm9YtVzod5W3RMHSTR7VrkUMD6E7EX/W9JQv3ebxO7oIdqFmytmNDDpSHnYEw==}
|
||||||
|
peerDependencies:
|
||||||
|
diagram-js: '*'
|
||||||
|
|
||||||
|
diagram-js@12.8.1:
|
||||||
|
resolution: {integrity: sha512-LF9BiwjbOPpZd0ez5VSlYRbdbEA59YQX43bWvNDp1rLMv0xwZ5yIg4oaYDK82nIQ0kH1tjvoQRpNevMTCgQVyw==}
|
||||||
|
|
||||||
|
diagram-js@14.11.3:
|
||||||
|
resolution: {integrity: sha512-Seq9BHAXfzKS60L4v4Gvgvv72wOtvrfJQAyyPm9pntSZDMzjoodPSXnEUPud1G2zVCMGEUUW++s0reEdaWgkXA==}
|
||||||
|
|
||||||
|
didi@10.2.2:
|
||||||
|
resolution: {integrity: sha512-l8NYkYFXV1izHI65EyT8EXOjUZtKmQkHLTT89cSP7HU5J/G7AOj0dXKtLc04EXYlga99PBY18IPjOeZ+c3DI4w==}
|
||||||
|
engines: {node: '>= 16'}
|
||||||
|
|
||||||
|
didi@9.0.2:
|
||||||
|
resolution: {integrity: sha512-q2+aj+lnJcUweV7A9pdUrwFr4LHVmRPwTmQLtHPFz4aT7IBoryN6Iy+jmFku+oIzr5ebBkvtBCOb87+dJhb7bg==}
|
||||||
|
|
||||||
didyoumean@1.2.2:
|
didyoumean@1.2.2:
|
||||||
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
|
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
|
||||||
|
|
||||||
@@ -6716,6 +6860,13 @@ packages:
|
|||||||
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
|
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
|
||||||
engines: {node: '>= 4'}
|
engines: {node: '>= 4'}
|
||||||
|
|
||||||
|
domify@1.4.2:
|
||||||
|
resolution: {integrity: sha512-m4yreHcUWHBncGVV7U+yQzc12vIlq0jMrtHZ5mW6dQMiL/7skSYNVX9wqKwOtyO9SGCgevrAFEgOCAHmamHTUA==}
|
||||||
|
|
||||||
|
domify@2.0.0:
|
||||||
|
resolution: {integrity: sha512-rmvrrmWQPD/X1A/nPBfIVg4r05792QdG9Z4Prk6oQG0F9zBMDkr0GKAdds1wjb2dq1rTz/ywc4ZxpZbgz0tttg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
dompurify@3.2.6:
|
dompurify@3.2.6:
|
||||||
resolution: {integrity: sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==}
|
resolution: {integrity: sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==}
|
||||||
|
|
||||||
@@ -7240,6 +7391,10 @@ packages:
|
|||||||
fast-uri@3.0.6:
|
fast-uri@3.0.6:
|
||||||
resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==}
|
resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==}
|
||||||
|
|
||||||
|
fast-xml-parser@4.5.3:
|
||||||
|
resolution: {integrity: sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
fastest-levenshtein@1.0.16:
|
fastest-levenshtein@1.0.16:
|
||||||
resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==}
|
resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==}
|
||||||
engines: {node: '>= 4.9.1'}
|
engines: {node: '>= 4.9.1'}
|
||||||
@@ -7262,6 +7417,12 @@ packages:
|
|||||||
fecha@4.2.3:
|
fecha@4.2.3:
|
||||||
resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==}
|
resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==}
|
||||||
|
|
||||||
|
feelers@1.4.0:
|
||||||
|
resolution: {integrity: sha512-CGa/7ILuqoqTaeYeoKsg/4tzu2es9sEEJTmSjdu0lousZBw4V9gcYhHYFNmbrSrKmbAVfOzj6/DsymGJWFIOeg==}
|
||||||
|
|
||||||
|
feelin@3.2.0:
|
||||||
|
resolution: {integrity: sha512-GFDbHsTYk7YXO1tyw1dOjb7IODeAZvNIosdGZThUwPx5XcD/XhO0hnPZXsIbAzSsIdrgGlTEEdby9fZ2gixysA==}
|
||||||
|
|
||||||
fetch-blob@3.2.0:
|
fetch-blob@3.2.0:
|
||||||
resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
|
resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
|
||||||
engines: {node: ^12.20 || >= 14.13}
|
engines: {node: ^12.20 || >= 14.13}
|
||||||
@@ -7593,6 +7754,10 @@ packages:
|
|||||||
h3@1.15.4:
|
h3@1.15.4:
|
||||||
resolution: {integrity: sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ==}
|
resolution: {integrity: sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ==}
|
||||||
|
|
||||||
|
hammerjs@2.0.8:
|
||||||
|
resolution: {integrity: sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==}
|
||||||
|
engines: {node: '>=0.8.0'}
|
||||||
|
|
||||||
happy-dom@17.6.3:
|
happy-dom@17.6.3:
|
||||||
resolution: {integrity: sha512-UVIHeVhxmxedbWPCfgS55Jg2rDfwf2BCKeylcPSqazLz5w3Kri7Q4xdBJubsr/+VUzFLh0VjIvh13RaDA2/Xug==}
|
resolution: {integrity: sha512-UVIHeVhxmxedbWPCfgS55Jg2rDfwf2BCKeylcPSqazLz5w3Kri7Q4xdBJubsr/+VUzFLh0VjIvh13RaDA2/Xug==}
|
||||||
engines: {node: '>=20.0.0'}
|
engines: {node: '>=20.0.0'}
|
||||||
@@ -7659,6 +7824,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==}
|
resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==}
|
||||||
engines: {node: ^16.14.0 || >=18.0.0}
|
engines: {node: ^16.14.0 || >=18.0.0}
|
||||||
|
|
||||||
|
htm@3.1.1:
|
||||||
|
resolution: {integrity: sha512-983Vyg8NwUE7JkZ6NmOqpCZ+sh1bKv2iYTlUkzlWmA5JD2acKoxd4KVxbMmxX/85mtfdnDmTFoNKcg5DGAvxNQ==}
|
||||||
|
|
||||||
html-minifier-terser@6.1.0:
|
html-minifier-terser@6.1.0:
|
||||||
resolution: {integrity: sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==}
|
resolution: {integrity: sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
@@ -7730,6 +7898,9 @@ packages:
|
|||||||
idb@7.1.1:
|
idb@7.1.1:
|
||||||
resolution: {integrity: sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==}
|
resolution: {integrity: sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==}
|
||||||
|
|
||||||
|
ids@1.0.5:
|
||||||
|
resolution: {integrity: sha512-XQ0yom/4KWTL29sLG+tyuycy7UmeaM/79GRtSJq6IG9cJGIPeBz5kwDCguie3TwxaMNIc3WtPi0cTa1XYHicpw==}
|
||||||
|
|
||||||
ieee754@1.2.1:
|
ieee754@1.2.1:
|
||||||
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
|
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
|
||||||
|
|
||||||
@@ -7783,6 +7954,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
|
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
|
||||||
deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
|
deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
|
||||||
|
|
||||||
|
inherits-browser@0.1.0:
|
||||||
|
resolution: {integrity: sha512-CJHHvW3jQ6q7lzsXPpapLdMx5hDpSF3FSh45pwsj6bKxJJ8Nl8v43i5yXnr3BdfOimGHKyniewQtnAIp3vyJJw==}
|
||||||
|
|
||||||
inherits@2.0.4:
|
inherits@2.0.4:
|
||||||
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
||||||
|
|
||||||
@@ -8347,6 +8521,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
|
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
|
|
||||||
|
lezer-feel@1.8.1:
|
||||||
|
resolution: {integrity: sha512-g0eGi7/INNPtPbtcz5ubInc3rSvXuJI5NfmS1hVU1FkaKNdBpwWdxXzrUb4wxr8DNXhXnUs1/a9rO4HaDzII7Q==}
|
||||||
|
|
||||||
lilconfig@3.1.3:
|
lilconfig@3.1.3:
|
||||||
resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==}
|
resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
@@ -8681,6 +8858,15 @@ packages:
|
|||||||
resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==}
|
resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
min-dash@4.2.3:
|
||||||
|
resolution: {integrity: sha512-VLMYQI5+FcD9Ad24VcB08uA83B07OhueAlZ88jBK6PyupTvEJwllTMUqMy0wPGYs7pZUEtEEMWdHB63m3LtEcg==}
|
||||||
|
|
||||||
|
min-dom@4.2.1:
|
||||||
|
resolution: {integrity: sha512-TMoL8SEEIhUWYgkj7XMSgxmwSyGI+4fP2KFFGnN3FbHfbGHVdsLYSz8LoIsgPhz4dWRmLvxWWSMgzZMJW5sZuA==}
|
||||||
|
|
||||||
|
min-dom@5.1.1:
|
||||||
|
resolution: {integrity: sha512-GaKUlguMAofd3OJsB0OkP17i5kucKqErgVCJxPawO9l5NwIPnr28SAr99zzlzMCWWljISBYrnZVWdE2Q92YGFQ==}
|
||||||
|
|
||||||
min-indent@1.0.1:
|
min-indent@1.0.1:
|
||||||
resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
|
resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
@@ -8791,6 +8977,12 @@ packages:
|
|||||||
mlly@1.7.4:
|
mlly@1.7.4:
|
||||||
resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==}
|
resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==}
|
||||||
|
|
||||||
|
moddle-xml@10.1.0:
|
||||||
|
resolution: {integrity: sha512-erWckwLt+dYskewKXJso9u+aAZ5172lOiYxSOqKCPTy7L/xmqH1PoeoA7eVC7oJTt3PqF5TkZzUmbjGH6soQBg==}
|
||||||
|
|
||||||
|
moddle@6.2.3:
|
||||||
|
resolution: {integrity: sha512-bLVN+ZHL3aKnhxc19XtjUfvdJsS3EsiEJC7bT6YPD11qYmTzvsxrGgyYz1Ouof7TZuGw0lDJ1OLmEnxcpQWk3Q==}
|
||||||
|
|
||||||
module-definition@6.0.1:
|
module-definition@6.0.1:
|
||||||
resolution: {integrity: sha512-FeVc50FTfVVQnolk/WQT8MX+2WVcDnTGiq6Wo+/+lJ2ET1bRVi3HG3YlJUfqagNMc/kUlFSoR96AJkxGpKz13g==}
|
resolution: {integrity: sha512-FeVc50FTfVVQnolk/WQT8MX+2WVcDnTGiq6Wo+/+lJ2ET1bRVi3HG3YlJUfqagNMc/kUlFSoR96AJkxGpKz13g==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -8984,6 +9176,12 @@ packages:
|
|||||||
resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
|
resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
object-refs@0.3.0:
|
||||||
|
resolution: {integrity: sha512-eP0ywuoWOaDoiake/6kTJlPJhs+k0qNm4nYRzXLNHj6vh+5M3i9R1epJTdxIPGlhWc4fNRQ7a6XJNCX+/L4FOQ==}
|
||||||
|
|
||||||
|
object-refs@0.4.0:
|
||||||
|
resolution: {integrity: sha512-6kJqKWryKZmtte6QYvouas0/EIJKPI1/MMIuRsiBlNuhIMfqYTggzX2F1AJ2+cDs288xyi9GL7FyasHINR98BQ==}
|
||||||
|
|
||||||
object.assign@4.1.7:
|
object.assign@4.1.7:
|
||||||
resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==}
|
resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -9178,6 +9376,13 @@ packages:
|
|||||||
resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==}
|
resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==}
|
||||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||||
|
|
||||||
|
path-intersection@2.2.1:
|
||||||
|
resolution: {integrity: sha512-9u8xvMcSfuOiStv9bPdnRJQhGQXLKurew94n4GPQCdH1nj9QKC9ObbNoIpiRq8skiOBxKkt277PgOoFgAt3/rA==}
|
||||||
|
|
||||||
|
path-intersection@3.1.0:
|
||||||
|
resolution: {integrity: sha512-3xS3lvv/vuwm5aH2BVvNRvnvwR2Drde7jQClKpCXTYXIMMjcw/EnMhzCgeHwqbCpzi760PEfAkU53vSIlrNr9A==}
|
||||||
|
engines: {node: '>= 14.20'}
|
||||||
|
|
||||||
path-is-absolute@1.0.1:
|
path-is-absolute@1.0.1:
|
||||||
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
|
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@@ -9926,6 +10131,9 @@ packages:
|
|||||||
randombytes@2.1.0:
|
randombytes@2.1.0:
|
||||||
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
|
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
|
||||||
|
|
||||||
|
randomcolor@0.6.2:
|
||||||
|
resolution: {integrity: sha512-Mn6TbyYpFgwFuQ8KJKqf3bqqY9O1y37/0jgSK/61PUxV4QfIMv0+K2ioq8DfOjkBslcjwSzRfIDEXfzA9aCx7A==}
|
||||||
|
|
||||||
range-parser@1.2.1:
|
range-parser@1.2.1:
|
||||||
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
|
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
@@ -10230,6 +10438,9 @@ packages:
|
|||||||
sax@1.4.1:
|
sax@1.4.1:
|
||||||
resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==}
|
resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==}
|
||||||
|
|
||||||
|
saxen@8.1.2:
|
||||||
|
resolution: {integrity: sha512-xUOiiFbc3Ow7p8KMxwsGICPx46ZQvy3+qfNVhrkwfz3Vvq45eGt98Ft5IQaA1R/7Tb5B5MKh9fUR9x3c3nDTxw==}
|
||||||
|
|
||||||
scroll-into-view-if-needed@2.2.31:
|
scroll-into-view-if-needed@2.2.31:
|
||||||
resolution: {integrity: sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==}
|
resolution: {integrity: sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==}
|
||||||
|
|
||||||
@@ -10496,6 +10707,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==}
|
resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
steady-xml@0.1.0:
|
||||||
|
resolution: {integrity: sha512-5sk17qO2wWRtonTNoBhoKAB35OSsGJOa3+NEa6D+1GS+de+ujDWxnflMkXBrviOfkNrPTUqduAdXhrMJs89nAw==}
|
||||||
|
engines: {node: '>=12.0.0'}
|
||||||
|
|
||||||
stop-iteration-iterator@1.1.0:
|
stop-iteration-iterator@1.1.0:
|
||||||
resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==}
|
resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -10595,9 +10810,15 @@ packages:
|
|||||||
strip-literal@3.0.0:
|
strip-literal@3.0.0:
|
||||||
resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==}
|
resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==}
|
||||||
|
|
||||||
|
strnum@1.1.2:
|
||||||
|
resolution: {integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==}
|
||||||
|
|
||||||
stubborn-fs@1.2.5:
|
stubborn-fs@1.2.5:
|
||||||
resolution: {integrity: sha512-H2N9c26eXjzL/S/K+i/RHHcFanE74dptvvjM8iwzwbVcWY/zjBbgRqF3K0DY4+OD+uTTASTBvDoxPDaPN02D7g==}
|
resolution: {integrity: sha512-H2N9c26eXjzL/S/K+i/RHHcFanE74dptvvjM8iwzwbVcWY/zjBbgRqF3K0DY4+OD+uTTASTBvDoxPDaPN02D7g==}
|
||||||
|
|
||||||
|
style-mod@4.1.2:
|
||||||
|
resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==}
|
||||||
|
|
||||||
style-search@0.1.0:
|
style-search@0.1.0:
|
||||||
resolution: {integrity: sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==}
|
resolution: {integrity: sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==}
|
||||||
|
|
||||||
@@ -10823,6 +11044,9 @@ packages:
|
|||||||
tiny-emitter@2.1.0:
|
tiny-emitter@2.1.0:
|
||||||
resolution: {integrity: sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==}
|
resolution: {integrity: sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==}
|
||||||
|
|
||||||
|
tiny-svg@3.1.3:
|
||||||
|
resolution: {integrity: sha512-9mwnPqXInRsBmH/DO6NMxBE++9LsqpVXQSSTZGc5bomoKKvL5OX/Hlotw7XVXP6XLRcHWIzZpxfovGqWKgCypQ==}
|
||||||
|
|
||||||
tinybench@2.9.0:
|
tinybench@2.9.0:
|
||||||
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
|
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
|
||||||
|
|
||||||
@@ -11520,6 +11744,9 @@ packages:
|
|||||||
vxe-table@4.15.10:
|
vxe-table@4.15.10:
|
||||||
resolution: {integrity: sha512-1bTw5PEuwpNCFZdQ326JRw5sgldv96in77RGNQYYhTtsjXIOvmLx82QBThY5UR+r3ig8c2oGz7nsRtN1wBLRAg==}
|
resolution: {integrity: sha512-1bTw5PEuwpNCFZdQ326JRw5sgldv96in77RGNQYYhTtsjXIOvmLx82QBThY5UR+r3ig8c2oGz7nsRtN1wBLRAg==}
|
||||||
|
|
||||||
|
w3c-keyname@2.2.8:
|
||||||
|
resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==}
|
||||||
|
|
||||||
wangeditor@4.7.15:
|
wangeditor@4.7.15:
|
||||||
resolution: {integrity: sha512-aPTdREd8BxXVyJ5MI+LU83FQ7u1EPd341iXIorRNYSOvoimNoZ4nPg+yn3FGbB93/owEa6buLw8wdhYnMCJQLg==}
|
resolution: {integrity: sha512-aPTdREd8BxXVyJ5MI+LU83FQ7u1EPd341iXIorRNYSOvoimNoZ4nPg+yn3FGbB93/owEa6buLw8wdhYnMCJQLg==}
|
||||||
|
|
||||||
@@ -11783,6 +12010,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-rY2A2lSF7zC+l7HH9Mq+83D1dLlsPnEvy8jTouzaptDZM6geqZ3aJe/b7ULCwRURPtWV3vbDjA2DDMdoBol0HQ==}
|
resolution: {integrity: sha512-rY2A2lSF7zC+l7HH9Mq+83D1dLlsPnEvy8jTouzaptDZM6geqZ3aJe/b7ULCwRURPtWV3vbDjA2DDMdoBol0HQ==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
zeebe-bpmn-moddle@1.11.0:
|
||||||
|
resolution: {integrity: sha512-v2PkIAjyZEnzuFHrm9ZhpbEGMgNjYZkUw+H17JxkA7Da+dcbPHbD7fWuBWSbPzNSCOyYYmrH+PL6wp9407ptMg==}
|
||||||
|
|
||||||
zimmerframe@1.1.2:
|
zimmerframe@1.1.2:
|
||||||
resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==}
|
resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==}
|
||||||
|
|
||||||
@@ -12711,6 +12941,70 @@ snapshots:
|
|||||||
'@babel/helper-string-parser': 7.27.1
|
'@babel/helper-string-parser': 7.27.1
|
||||||
'@babel/helper-validator-identifier': 7.27.1
|
'@babel/helper-validator-identifier': 7.27.1
|
||||||
|
|
||||||
|
'@bpmn-io/cm-theme@0.1.0-alpha.2':
|
||||||
|
dependencies:
|
||||||
|
'@codemirror/language': 6.11.3
|
||||||
|
'@codemirror/view': 6.38.2
|
||||||
|
'@lezer/highlight': 1.2.1
|
||||||
|
|
||||||
|
'@bpmn-io/diagram-js-ui@0.2.3':
|
||||||
|
dependencies:
|
||||||
|
htm: 3.1.1
|
||||||
|
preact: 10.27.1
|
||||||
|
|
||||||
|
'@bpmn-io/extract-process-variables@0.8.0':
|
||||||
|
dependencies:
|
||||||
|
min-dash: 4.2.3
|
||||||
|
|
||||||
|
'@bpmn-io/feel-editor@1.12.0':
|
||||||
|
dependencies:
|
||||||
|
'@bpmn-io/feel-lint': 2.1.0
|
||||||
|
'@bpmn-io/lang-feel': 2.4.0
|
||||||
|
'@camunda/feel-builtins': 0.2.0
|
||||||
|
'@codemirror/autocomplete': 6.18.7
|
||||||
|
'@codemirror/commands': 6.8.1
|
||||||
|
'@codemirror/language': 6.11.3
|
||||||
|
'@codemirror/lint': 6.8.5
|
||||||
|
'@codemirror/state': 6.5.2
|
||||||
|
'@codemirror/view': 6.38.2
|
||||||
|
'@lezer/highlight': 1.2.1
|
||||||
|
min-dom: 4.2.1
|
||||||
|
|
||||||
|
'@bpmn-io/feel-lint@1.4.0':
|
||||||
|
dependencies:
|
||||||
|
'@codemirror/language': 6.11.3
|
||||||
|
lezer-feel: 1.8.1
|
||||||
|
|
||||||
|
'@bpmn-io/feel-lint@2.1.0':
|
||||||
|
dependencies:
|
||||||
|
'@bpmn-io/lezer-feel': 1.9.0
|
||||||
|
'@codemirror/language': 6.11.3
|
||||||
|
|
||||||
|
'@bpmn-io/lang-feel@2.4.0':
|
||||||
|
dependencies:
|
||||||
|
'@bpmn-io/lezer-feel': 1.9.0
|
||||||
|
'@codemirror/autocomplete': 6.18.7
|
||||||
|
'@codemirror/language': 6.11.3
|
||||||
|
'@lezer/common': 1.2.3
|
||||||
|
|
||||||
|
'@bpmn-io/lezer-feel@1.9.0':
|
||||||
|
dependencies:
|
||||||
|
'@lezer/highlight': 1.2.1
|
||||||
|
'@lezer/lr': 1.4.2
|
||||||
|
min-dash: 4.2.3
|
||||||
|
|
||||||
|
'@bpmn-io/properties-panel@3.33.0':
|
||||||
|
dependencies:
|
||||||
|
'@bpmn-io/feel-editor': 1.12.0
|
||||||
|
'@codemirror/view': 6.38.2
|
||||||
|
classnames: 2.5.1
|
||||||
|
feelers: 1.4.0
|
||||||
|
focus-trap: 7.6.5
|
||||||
|
min-dash: 4.2.3
|
||||||
|
min-dom: 4.2.1
|
||||||
|
|
||||||
|
'@camunda/feel-builtins@0.2.0': {}
|
||||||
|
|
||||||
'@changesets/apply-release-plan@7.0.12':
|
'@changesets/apply-release-plan@7.0.12':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@changesets/config': 3.1.1
|
'@changesets/config': 3.1.1
|
||||||
@@ -12885,6 +13179,46 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
mime: 3.0.0
|
mime: 3.0.0
|
||||||
|
|
||||||
|
'@codemirror/autocomplete@6.18.7':
|
||||||
|
dependencies:
|
||||||
|
'@codemirror/language': 6.11.3
|
||||||
|
'@codemirror/state': 6.5.2
|
||||||
|
'@codemirror/view': 6.38.2
|
||||||
|
'@lezer/common': 1.2.3
|
||||||
|
|
||||||
|
'@codemirror/commands@6.8.1':
|
||||||
|
dependencies:
|
||||||
|
'@codemirror/language': 6.11.3
|
||||||
|
'@codemirror/state': 6.5.2
|
||||||
|
'@codemirror/view': 6.38.2
|
||||||
|
'@lezer/common': 1.2.3
|
||||||
|
|
||||||
|
'@codemirror/language@6.11.3':
|
||||||
|
dependencies:
|
||||||
|
'@codemirror/state': 6.5.2
|
||||||
|
'@codemirror/view': 6.38.2
|
||||||
|
'@lezer/common': 1.2.3
|
||||||
|
'@lezer/highlight': 1.2.1
|
||||||
|
'@lezer/lr': 1.4.2
|
||||||
|
style-mod: 4.1.2
|
||||||
|
|
||||||
|
'@codemirror/lint@6.8.5':
|
||||||
|
dependencies:
|
||||||
|
'@codemirror/state': 6.5.2
|
||||||
|
'@codemirror/view': 6.38.2
|
||||||
|
crelt: 1.0.6
|
||||||
|
|
||||||
|
'@codemirror/state@6.5.2':
|
||||||
|
dependencies:
|
||||||
|
'@marijn/find-cluster-break': 1.0.2
|
||||||
|
|
||||||
|
'@codemirror/view@6.38.2':
|
||||||
|
dependencies:
|
||||||
|
'@codemirror/state': 6.5.2
|
||||||
|
crelt: 1.0.6
|
||||||
|
style-mod: 4.1.2
|
||||||
|
w3c-keyname: 2.2.8
|
||||||
|
|
||||||
'@colors/colors@1.6.0': {}
|
'@colors/colors@1.6.0': {}
|
||||||
|
|
||||||
'@commitlint/cli@19.8.1(@types/node@24.3.0)(typescript@5.9.2)':
|
'@commitlint/cli@19.8.1(@types/node@24.3.0)(typescript@5.9.2)':
|
||||||
@@ -14053,6 +14387,21 @@ snapshots:
|
|||||||
|
|
||||||
'@keyv/serialize@1.1.0': {}
|
'@keyv/serialize@1.1.0': {}
|
||||||
|
|
||||||
|
'@lezer/common@1.2.3': {}
|
||||||
|
|
||||||
|
'@lezer/highlight@1.2.1':
|
||||||
|
dependencies:
|
||||||
|
'@lezer/common': 1.2.3
|
||||||
|
|
||||||
|
'@lezer/lr@1.4.2':
|
||||||
|
dependencies:
|
||||||
|
'@lezer/common': 1.2.3
|
||||||
|
|
||||||
|
'@lezer/markdown@1.4.3':
|
||||||
|
dependencies:
|
||||||
|
'@lezer/common': 1.2.3
|
||||||
|
'@lezer/highlight': 1.2.1
|
||||||
|
|
||||||
'@manypkg/find-root@1.1.0':
|
'@manypkg/find-root@1.1.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.28.3
|
'@babel/runtime': 7.28.3
|
||||||
@@ -14097,6 +14446,8 @@ snapshots:
|
|||||||
- encoding
|
- encoding
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
'@marijn/find-cluster-break@1.0.2': {}
|
||||||
|
|
||||||
'@microsoft/api-extractor-model@7.30.7(@types/node@24.3.0)':
|
'@microsoft/api-extractor-model@7.30.7(@types/node@24.3.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@microsoft/tsdoc': 0.15.1
|
'@microsoft/tsdoc': 0.15.1
|
||||||
@@ -15876,6 +16227,8 @@ snapshots:
|
|||||||
|
|
||||||
array-ify@1.0.0: {}
|
array-ify@1.0.0: {}
|
||||||
|
|
||||||
|
array-move@4.0.0: {}
|
||||||
|
|
||||||
array-timsort@1.0.3: {}
|
array-timsort@1.0.3: {}
|
||||||
|
|
||||||
array-tree-filter@2.1.0: {}
|
array-tree-filter@2.1.0: {}
|
||||||
@@ -16015,6 +16368,42 @@ snapshots:
|
|||||||
widest-line: 5.0.0
|
widest-line: 5.0.0
|
||||||
wrap-ansi: 9.0.0
|
wrap-ansi: 9.0.0
|
||||||
|
|
||||||
|
bpmn-js-properties-panel@5.23.0(@bpmn-io/properties-panel@3.33.0)(bpmn-js@17.11.1)(camunda-bpmn-js-behaviors@1.11.1(bpmn-js@17.11.1)(camunda-bpmn-moddle@7.0.1)(zeebe-bpmn-moddle@1.11.0))(diagram-js@12.8.1):
|
||||||
|
dependencies:
|
||||||
|
'@bpmn-io/extract-process-variables': 0.8.0
|
||||||
|
'@bpmn-io/properties-panel': 3.33.0
|
||||||
|
array-move: 4.0.0
|
||||||
|
bpmn-js: 17.11.1
|
||||||
|
camunda-bpmn-js-behaviors: 1.11.1(bpmn-js@17.11.1)(camunda-bpmn-moddle@7.0.1)(zeebe-bpmn-moddle@1.11.0)
|
||||||
|
diagram-js: 12.8.1
|
||||||
|
ids: 1.0.5
|
||||||
|
min-dash: 4.2.3
|
||||||
|
min-dom: 4.2.1
|
||||||
|
|
||||||
|
bpmn-js-token-simulation@0.36.3:
|
||||||
|
dependencies:
|
||||||
|
inherits-browser: 0.1.0
|
||||||
|
min-dash: 4.2.3
|
||||||
|
min-dom: 4.2.1
|
||||||
|
randomcolor: 0.6.2
|
||||||
|
|
||||||
|
bpmn-js@17.11.1:
|
||||||
|
dependencies:
|
||||||
|
bpmn-moddle: 8.1.0
|
||||||
|
diagram-js: 14.11.3
|
||||||
|
diagram-js-direct-editing: 3.2.0(diagram-js@14.11.3)
|
||||||
|
ids: 1.0.5
|
||||||
|
inherits-browser: 0.1.0
|
||||||
|
min-dash: 4.2.3
|
||||||
|
min-dom: 4.2.1
|
||||||
|
tiny-svg: 3.1.3
|
||||||
|
|
||||||
|
bpmn-moddle@8.1.0:
|
||||||
|
dependencies:
|
||||||
|
min-dash: 4.2.3
|
||||||
|
moddle: 6.2.3
|
||||||
|
moddle-xml: 10.1.0
|
||||||
|
|
||||||
brace-expansion@1.1.12:
|
brace-expansion@1.1.12:
|
||||||
dependencies:
|
dependencies:
|
||||||
balanced-match: 1.0.2
|
balanced-match: 1.0.2
|
||||||
@@ -16137,6 +16526,16 @@ snapshots:
|
|||||||
|
|
||||||
camelcase@8.0.0: {}
|
camelcase@8.0.0: {}
|
||||||
|
|
||||||
|
camunda-bpmn-js-behaviors@1.11.1(bpmn-js@17.11.1)(camunda-bpmn-moddle@7.0.1)(zeebe-bpmn-moddle@1.11.0):
|
||||||
|
dependencies:
|
||||||
|
bpmn-js: 17.11.1
|
||||||
|
camunda-bpmn-moddle: 7.0.1
|
||||||
|
ids: 1.0.5
|
||||||
|
min-dash: 4.2.3
|
||||||
|
zeebe-bpmn-moddle: 1.11.0
|
||||||
|
|
||||||
|
camunda-bpmn-moddle@7.0.1: {}
|
||||||
|
|
||||||
caniuse-api@3.0.0:
|
caniuse-api@3.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
browserslist: 4.25.3
|
browserslist: 4.25.3
|
||||||
@@ -16254,6 +16653,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
clsx: 2.1.1
|
clsx: 2.1.1
|
||||||
|
|
||||||
|
classnames@2.5.1: {}
|
||||||
|
|
||||||
clean-css@5.3.3:
|
clean-css@5.3.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
source-map: 0.6.1
|
source-map: 0.6.1
|
||||||
@@ -16400,6 +16801,8 @@ snapshots:
|
|||||||
|
|
||||||
compatx@0.2.0: {}
|
compatx@0.2.0: {}
|
||||||
|
|
||||||
|
component-event@0.2.1: {}
|
||||||
|
|
||||||
compress-commons@6.0.2:
|
compress-commons@6.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
crc-32: 1.2.2
|
crc-32: 1.2.2
|
||||||
@@ -16511,6 +16914,8 @@ snapshots:
|
|||||||
crc-32: 1.2.2
|
crc-32: 1.2.2
|
||||||
readable-stream: 4.7.0
|
readable-stream: 4.7.0
|
||||||
|
|
||||||
|
crelt@1.0.6: {}
|
||||||
|
|
||||||
cron-parser@4.9.0:
|
cron-parser@4.9.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
luxon: 3.7.1
|
luxon: 3.7.1
|
||||||
@@ -17096,6 +17501,41 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
dequal: 2.0.3
|
dequal: 2.0.3
|
||||||
|
|
||||||
|
diagram-js-direct-editing@3.2.0(diagram-js@14.11.3):
|
||||||
|
dependencies:
|
||||||
|
diagram-js: 14.11.3
|
||||||
|
min-dash: 4.2.3
|
||||||
|
min-dom: 4.2.1
|
||||||
|
|
||||||
|
diagram-js@12.8.1:
|
||||||
|
dependencies:
|
||||||
|
'@bpmn-io/diagram-js-ui': 0.2.3
|
||||||
|
clsx: 2.1.1
|
||||||
|
didi: 9.0.2
|
||||||
|
hammerjs: 2.0.8
|
||||||
|
inherits-browser: 0.1.0
|
||||||
|
min-dash: 4.2.3
|
||||||
|
min-dom: 4.2.1
|
||||||
|
object-refs: 0.3.0
|
||||||
|
path-intersection: 2.2.1
|
||||||
|
tiny-svg: 3.1.3
|
||||||
|
|
||||||
|
diagram-js@14.11.3:
|
||||||
|
dependencies:
|
||||||
|
'@bpmn-io/diagram-js-ui': 0.2.3
|
||||||
|
clsx: 2.1.1
|
||||||
|
didi: 10.2.2
|
||||||
|
inherits-browser: 0.1.0
|
||||||
|
min-dash: 4.2.3
|
||||||
|
min-dom: 4.2.1
|
||||||
|
object-refs: 0.4.0
|
||||||
|
path-intersection: 3.1.0
|
||||||
|
tiny-svg: 3.1.3
|
||||||
|
|
||||||
|
didi@10.2.2: {}
|
||||||
|
|
||||||
|
didi@9.0.2: {}
|
||||||
|
|
||||||
didyoumean@1.2.2: {}
|
didyoumean@1.2.2: {}
|
||||||
|
|
||||||
dijkstrajs@1.0.3: {}
|
dijkstrajs@1.0.3: {}
|
||||||
@@ -17134,6 +17574,10 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
domelementtype: 2.3.0
|
domelementtype: 2.3.0
|
||||||
|
|
||||||
|
domify@1.4.2: {}
|
||||||
|
|
||||||
|
domify@2.0.0: {}
|
||||||
|
|
||||||
dompurify@3.2.6:
|
dompurify@3.2.6:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/trusted-types': 2.0.7
|
'@types/trusted-types': 2.0.7
|
||||||
@@ -17798,6 +18242,10 @@ snapshots:
|
|||||||
|
|
||||||
fast-uri@3.0.6: {}
|
fast-uri@3.0.6: {}
|
||||||
|
|
||||||
|
fast-xml-parser@4.5.3:
|
||||||
|
dependencies:
|
||||||
|
strnum: 1.1.2
|
||||||
|
|
||||||
fastest-levenshtein@1.0.16: {}
|
fastest-levenshtein@1.0.16: {}
|
||||||
|
|
||||||
fastq@1.19.1:
|
fastq@1.19.1:
|
||||||
@@ -17814,6 +18262,30 @@ snapshots:
|
|||||||
|
|
||||||
fecha@4.2.3: {}
|
fecha@4.2.3: {}
|
||||||
|
|
||||||
|
feelers@1.4.0:
|
||||||
|
dependencies:
|
||||||
|
'@bpmn-io/cm-theme': 0.1.0-alpha.2
|
||||||
|
'@bpmn-io/feel-lint': 1.4.0
|
||||||
|
'@codemirror/autocomplete': 6.18.7
|
||||||
|
'@codemirror/commands': 6.8.1
|
||||||
|
'@codemirror/language': 6.11.3
|
||||||
|
'@codemirror/lint': 6.8.5
|
||||||
|
'@codemirror/state': 6.5.2
|
||||||
|
'@codemirror/view': 6.38.2
|
||||||
|
'@lezer/common': 1.2.3
|
||||||
|
'@lezer/highlight': 1.2.1
|
||||||
|
'@lezer/lr': 1.4.2
|
||||||
|
'@lezer/markdown': 1.4.3
|
||||||
|
feelin: 3.2.0
|
||||||
|
lezer-feel: 1.8.1
|
||||||
|
min-dom: 5.1.1
|
||||||
|
|
||||||
|
feelin@3.2.0:
|
||||||
|
dependencies:
|
||||||
|
'@lezer/lr': 1.4.2
|
||||||
|
lezer-feel: 1.8.1
|
||||||
|
luxon: 3.7.1
|
||||||
|
|
||||||
fetch-blob@3.2.0:
|
fetch-blob@3.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
node-domexception: 1.0.0
|
node-domexception: 1.0.0
|
||||||
@@ -18203,6 +18675,8 @@ snapshots:
|
|||||||
ufo: 1.6.1
|
ufo: 1.6.1
|
||||||
uncrypto: 0.1.3
|
uncrypto: 0.1.3
|
||||||
|
|
||||||
|
hammerjs@2.0.8: {}
|
||||||
|
|
||||||
happy-dom@17.6.3:
|
happy-dom@17.6.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
webidl-conversions: 7.0.0
|
webidl-conversions: 7.0.0
|
||||||
@@ -18268,6 +18742,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
lru-cache: 10.4.3
|
lru-cache: 10.4.3
|
||||||
|
|
||||||
|
htm@3.1.1: {}
|
||||||
|
|
||||||
html-minifier-terser@6.1.0:
|
html-minifier-terser@6.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
camel-case: 4.1.2
|
camel-case: 4.1.2
|
||||||
@@ -18358,6 +18834,8 @@ snapshots:
|
|||||||
|
|
||||||
idb@7.1.1: {}
|
idb@7.1.1: {}
|
||||||
|
|
||||||
|
ids@1.0.5: {}
|
||||||
|
|
||||||
ieee754@1.2.1: {}
|
ieee754@1.2.1: {}
|
||||||
|
|
||||||
ignore@5.3.2: {}
|
ignore@5.3.2: {}
|
||||||
@@ -18393,6 +18871,8 @@ snapshots:
|
|||||||
once: 1.4.0
|
once: 1.4.0
|
||||||
wrappy: 1.0.2
|
wrappy: 1.0.2
|
||||||
|
|
||||||
|
inherits-browser@0.1.0: {}
|
||||||
|
|
||||||
inherits@2.0.4: {}
|
inherits@2.0.4: {}
|
||||||
|
|
||||||
ini@1.3.8: {}
|
ini@1.3.8: {}
|
||||||
@@ -18887,6 +19367,12 @@ snapshots:
|
|||||||
prelude-ls: 1.2.1
|
prelude-ls: 1.2.1
|
||||||
type-check: 0.4.0
|
type-check: 0.4.0
|
||||||
|
|
||||||
|
lezer-feel@1.8.1:
|
||||||
|
dependencies:
|
||||||
|
'@lezer/highlight': 1.2.1
|
||||||
|
'@lezer/lr': 1.4.2
|
||||||
|
min-dash: 4.2.3
|
||||||
|
|
||||||
lilconfig@3.1.3: {}
|
lilconfig@3.1.3: {}
|
||||||
|
|
||||||
lines-and-columns@1.2.4: {}
|
lines-and-columns@1.2.4: {}
|
||||||
@@ -19238,6 +19724,19 @@ snapshots:
|
|||||||
|
|
||||||
mimic-function@5.0.1: {}
|
mimic-function@5.0.1: {}
|
||||||
|
|
||||||
|
min-dash@4.2.3: {}
|
||||||
|
|
||||||
|
min-dom@4.2.1:
|
||||||
|
dependencies:
|
||||||
|
component-event: 0.2.1
|
||||||
|
domify: 1.4.2
|
||||||
|
min-dash: 4.2.3
|
||||||
|
|
||||||
|
min-dom@5.1.1:
|
||||||
|
dependencies:
|
||||||
|
domify: 2.0.0
|
||||||
|
min-dash: 4.2.3
|
||||||
|
|
||||||
min-indent@1.0.1: {}
|
min-indent@1.0.1: {}
|
||||||
|
|
||||||
minimatch@10.0.3:
|
minimatch@10.0.3:
|
||||||
@@ -19343,6 +19842,16 @@ snapshots:
|
|||||||
pkg-types: 1.3.1
|
pkg-types: 1.3.1
|
||||||
ufo: 1.6.1
|
ufo: 1.6.1
|
||||||
|
|
||||||
|
moddle-xml@10.1.0:
|
||||||
|
dependencies:
|
||||||
|
min-dash: 4.2.3
|
||||||
|
moddle: 6.2.3
|
||||||
|
saxen: 8.1.2
|
||||||
|
|
||||||
|
moddle@6.2.3:
|
||||||
|
dependencies:
|
||||||
|
min-dash: 4.2.3
|
||||||
|
|
||||||
module-definition@6.0.1:
|
module-definition@6.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
ast-module-types: 6.0.1
|
ast-module-types: 6.0.1
|
||||||
@@ -19619,6 +20128,10 @@ snapshots:
|
|||||||
|
|
||||||
object-keys@1.1.1: {}
|
object-keys@1.1.1: {}
|
||||||
|
|
||||||
|
object-refs@0.3.0: {}
|
||||||
|
|
||||||
|
object-refs@0.4.0: {}
|
||||||
|
|
||||||
object.assign@4.1.7:
|
object.assign@4.1.7:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind: 1.0.8
|
call-bind: 1.0.8
|
||||||
@@ -19835,6 +20348,10 @@ snapshots:
|
|||||||
|
|
||||||
path-exists@5.0.0: {}
|
path-exists@5.0.0: {}
|
||||||
|
|
||||||
|
path-intersection@2.2.1: {}
|
||||||
|
|
||||||
|
path-intersection@3.1.0: {}
|
||||||
|
|
||||||
path-is-absolute@1.0.1: {}
|
path-is-absolute@1.0.1: {}
|
||||||
|
|
||||||
path-key@3.1.1: {}
|
path-key@3.1.1: {}
|
||||||
@@ -20529,6 +21046,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
safe-buffer: 5.2.1
|
safe-buffer: 5.2.1
|
||||||
|
|
||||||
|
randomcolor@0.6.2: {}
|
||||||
|
|
||||||
range-parser@1.2.1: {}
|
range-parser@1.2.1: {}
|
||||||
|
|
||||||
rc9@2.1.2:
|
rc9@2.1.2:
|
||||||
@@ -20862,6 +21381,8 @@ snapshots:
|
|||||||
|
|
||||||
sax@1.4.1: {}
|
sax@1.4.1: {}
|
||||||
|
|
||||||
|
saxen@8.1.2: {}
|
||||||
|
|
||||||
scroll-into-view-if-needed@2.2.31:
|
scroll-into-view-if-needed@2.2.31:
|
||||||
dependencies:
|
dependencies:
|
||||||
compute-scroll-into-view: 1.0.20
|
compute-scroll-into-view: 1.0.20
|
||||||
@@ -21144,6 +21665,8 @@ snapshots:
|
|||||||
|
|
||||||
stdin-discarder@0.2.2: {}
|
stdin-discarder@0.2.2: {}
|
||||||
|
|
||||||
|
steady-xml@0.1.0: {}
|
||||||
|
|
||||||
stop-iteration-iterator@1.1.0:
|
stop-iteration-iterator@1.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
@@ -21266,8 +21789,12 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
js-tokens: 9.0.1
|
js-tokens: 9.0.1
|
||||||
|
|
||||||
|
strnum@1.1.2: {}
|
||||||
|
|
||||||
stubborn-fs@1.2.5: {}
|
stubborn-fs@1.2.5: {}
|
||||||
|
|
||||||
|
style-mod@4.1.2: {}
|
||||||
|
|
||||||
style-search@0.1.0: {}
|
style-search@0.1.0: {}
|
||||||
|
|
||||||
style-value-types@5.1.2:
|
style-value-types@5.1.2:
|
||||||
@@ -21578,6 +22105,8 @@ snapshots:
|
|||||||
|
|
||||||
tiny-emitter@2.1.0: {}
|
tiny-emitter@2.1.0: {}
|
||||||
|
|
||||||
|
tiny-svg@3.1.3: {}
|
||||||
|
|
||||||
tinybench@2.9.0: {}
|
tinybench@2.9.0: {}
|
||||||
|
|
||||||
tinyexec@0.3.2: {}
|
tinyexec@0.3.2: {}
|
||||||
@@ -22480,6 +23009,8 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- vue
|
- vue
|
||||||
|
|
||||||
|
w3c-keyname@2.2.8: {}
|
||||||
|
|
||||||
wangeditor@4.7.15:
|
wangeditor@4.7.15:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.28.3
|
'@babel/runtime': 7.28.3
|
||||||
@@ -22850,6 +23381,8 @@ snapshots:
|
|||||||
cookie: 1.0.2
|
cookie: 1.0.2
|
||||||
youch-core: 0.3.3
|
youch-core: 0.3.3
|
||||||
|
|
||||||
|
zeebe-bpmn-moddle@1.11.0: {}
|
||||||
|
|
||||||
zimmerframe@1.1.2: {}
|
zimmerframe@1.1.2: {}
|
||||||
|
|
||||||
zip-stream@6.0.1:
|
zip-stream@6.0.1:
|
||||||
|
|||||||
Reference in New Issue
Block a user