# Conflicts:
#	package.json
This commit is contained in:
YunaiV
2024-03-28 19:30:02 +08:00
112 changed files with 6021 additions and 1847 deletions

View File

@ -25,6 +25,9 @@ defineProps({
</template>
<Icon :size="14" class="ml-5px" icon="ep:question-filled" />
</ElTooltip>
<div class="flex flex-grow pl-20px">
<slot name="header"></slot>
</div>
</div>
</template>
<div>

View File

@ -180,12 +180,12 @@ defineExpose({
</script>
<template>
<div class="z-99 border-1 border-[var(--el-border-color)] border-solid">
<div class="border-1 border-solid border-[var(--tags-view-border-color)] z-10">
<!-- 工具栏 -->
<Toolbar
:editor="editorRef"
:editorId="editorId"
class="border-0 b-b-1 border-[var(--el-border-color)] border-solid"
class="border-0 b-b-1 border-solid border-[var(--tags-view-border-color)]"
/>
<!-- 编辑器 -->
<Editor

View File

@ -12,7 +12,7 @@ export function createImageViewer(options: ImageViewerProps) {
initialIndex = 0,
infinite = true,
hideOnClickModal = false,
appendToBody = false,
teleported = false,
zIndex = 2000,
show = true
} = options
@ -23,7 +23,7 @@ export function createImageViewer(options: ImageViewerProps) {
propsData.initialIndex = initialIndex
propsData.infinite = infinite
propsData.hideOnClickModal = hideOnClickModal
propsData.appendToBody = appendToBody
propsData.teleported = teleported
propsData.zIndex = zIndex
propsData.show = show

View File

@ -13,7 +13,7 @@ const props = defineProps({
initialIndex: propTypes.number.def(0),
infinite: propTypes.bool.def(true),
hideOnClickModal: propTypes.bool.def(false),
appendToBody: propTypes.bool.def(false),
teleported: propTypes.bool.def(false),
show: propTypes.bool.def(false)
})

View File

@ -4,6 +4,6 @@ export interface ImageViewerProps {
initialIndex?: number
infinite?: boolean
hideOnClickModal?: boolean
appendToBody?: boolean
teleported?: boolean
show?: boolean
}

View File

@ -53,7 +53,7 @@ const props = defineProps({
}
})
const emit = defineEmits(['update:page', 'update:limit', 'pagination', 'pagination'])
const emit = defineEmits(['update:page', 'update:limit', 'pagination'])
const currentPage = computed({
get() {
return props.page

View File

@ -26,7 +26,7 @@
placeholder="请输入菜单内容"
:remote-method="remoteMethod"
class="overflow-hidden transition-all-600"
:class="showTopSearch ? 'w-220px ml2' : 'w-0'"
:class="showTopSearch ? '!w-220px ml2' : '!w-0'"
@change="handleChange"
>
<el-option

View File

@ -0,0 +1,237 @@
/* stylelint-disable order/properties-order */
<template>
<div class="add-node-btn-box">
<div class="add-node-btn">
<el-popover placement="right-start" v-model="visible" width="auto">
<div class="add-node-popover-body">
<a class="add-node-popover-item approver" @click="addType(1)">
<div class="item-wrapper">
<span class="iconfont"></span>
</div>
<p>审批人</p>
</a>
<a class="add-node-popover-item notifier" @click="addType(2)">
<div class="item-wrapper">
<span class="iconfont"></span>
</div>
<p>抄送人</p>
</a>
<a class="add-node-popover-item condition" @click="addType(4)">
<div class="item-wrapper">
<span class="iconfont"></span>
</div>
<p>条件分支</p>
</a>
</div>
<template #reference>
<button class="btn" type="button">
<span class="iconfont"></span>
</button>
</template>
</el-popover>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
let props = defineProps({
childNodeP: {
type: Object,
default: () => ({})
}
})
let emits = defineEmits(['update:childNodeP'])
let visible = ref(false)
const addType = (type) => {
visible.value = false
if (type != 4) {
var data
if (type == 1) {
data = {
nodeName: '审核人',
error: true,
type: 1,
settype: 1,
selectMode: 0,
selectRange: 0,
directorLevel: 1,
examineMode: 1,
noHanderAction: 1,
examineEndDirectorLevel: 0,
childNode: props.childNodeP,
nodeUserList: []
}
} else if (type == 2) {
data = {
nodeName: '抄送人',
type: 2,
ccSelfSelectFlag: 1,
childNode: props.childNodeP,
nodeUserList: []
}
}
emits('update:childNodeP', data)
} else {
emits('update:childNodeP', {
nodeName: '路由',
type: 4,
childNode: null,
conditionNodes: [
{
nodeName: '条件1',
error: true,
type: 3,
priorityLevel: 1,
conditionList: [],
nodeUserList: [],
childNode: props.childNodeP
},
{
nodeName: '条件2',
type: 3,
priorityLevel: 2,
conditionList: [],
nodeUserList: [],
childNode: null
}
]
})
}
}
</script>
<style scoped lang="scss">
.add-node-btn-box {
width: 240px;
display: inline-flex;
-ms-flex-negative: 0;
flex-shrink: 0;
-webkit-box-flex: 1;
-ms-flex-positive: 1;
position: relative;
&:before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: -1;
margin: auto;
width: 2px;
height: 100%;
background-color: #cacaca;
}
.add-node-btn {
user-select: none;
width: 240px;
padding: 20px 0 32px;
display: flex;
-webkit-box-pack: center;
justify-content: center;
flex-shrink: 0;
-webkit-box-flex: 1;
flex-grow: 1;
.btn {
outline: none;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.1);
width: 30px;
height: 30px;
background: #3296fa;
border-radius: 50%;
position: relative;
border: none;
line-height: 30px;
-webkit-transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
.iconfont {
color: #fff;
font-size: 16px;
}
&:hover {
transform: scale(1.3);
box-shadow: 0 13px 27px 0 rgba(0, 0, 0, 0.1);
}
&:active {
transform: none;
background: #1e83e9;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.1);
}
}
}
}
.add-node-popover-body {
display: flex;
.add-node-popover-item {
margin-right: 10px;
cursor: pointer;
text-align: center;
flex: 1;
color: #191f25 !important;
.item-wrapper {
user-select: none;
display: inline-block;
width: 80px;
height: 80px;
margin-bottom: 5px;
background: #fff;
border: 1px solid #e2e2e2;
border-radius: 50%;
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
.iconfont {
font-size: 35px;
line-height: 80px;
}
}
&.approver {
.item-wrapper {
color: #ff943e;
}
}
&.notifier {
.item-wrapper {
color: #3296fa;
}
}
&.condition {
.item-wrapper {
color: #15bc83;
}
}
&:hover {
.item-wrapper {
background: #3296fa;
box-shadow: 0 10px 20px 0 rgba(50, 150, 250, 0.4);
}
.iconfont {
color: #fff;
}
}
&:active {
.item-wrapper {
box-shadow: none;
background: #eaeaea;
}
.iconfont {
color: inherit;
}
}
}
}
</style>

View File

@ -0,0 +1,297 @@
<!-- eslint-disable vue/no-mutating-props -->
<!--
* @Date: 2022-09-21 14:41:53
* @LastEditors: StavinLi 495727881@qq.com
* @LastEditTime: 2023-05-24 15:20:24
* @FilePath: /Workflow-Vue3/src/components/nodeWrap.vue
-->
<template>
<div class="node-wrap" v-if="nodeConfig.type < 3">
<div class="node-wrap-box" :class="(nodeConfig.type == 0 ? 'start-node ' : '') +(isTried && nodeConfig.error ? 'active error' : '')">
<div class="title" :style="`background: rgb(${bgColors[nodeConfig.type]});`">
<span v-if="nodeConfig.type == 0">{{ nodeConfig.nodeName }}</span>
<template v-else>
<span class="iconfont">{{nodeConfig.type == 1?'':''}}</span>
<input
v-if="isInput"
type="text"
class="ant-input editable-title-input"
@blur="blurEvent()"
@focus="$event.currentTarget.select()"
v-focus
v-model="nodeConfig.nodeName"
:placeholder="defaultText"
/>
<span v-else class="editable-title" @click="clickEvent()">{{ nodeConfig.nodeName }}</span>
<i class="anticon anticon-close close" @click="delNode"></i>
</template>
</div>
<div class="content" @click="setPerson">
<div class="text">
<span class="placeholder" v-if="!showText">请选择{{defaultText}}</span>
{{showText}}
</div>
<i class="anticon anticon-right arrow"></i>
</div>
<div class="error_tip" v-if="isTried && nodeConfig.error">
<i class="anticon anticon-exclamation-circle"></i>
</div>
</div>
<addNode v-model:childNodeP="nodeConfig.childNode" />
</div>
<div class="branch-wrap" v-if="nodeConfig.type == 4">
<div class="branch-box-wrap">
<div class="branch-box">
<button class="add-branch" @click="addTerm">添加条件</button>
<div class="col-box" v-for="(item, index) in nodeConfig.conditionNodes" :key="index">
<div class="condition-node">
<div class="condition-node-box">
<div class="auto-judge" :class="isTried && item.error ? 'error active' : ''">
<div class="sort-left" v-if="index != 0" @click="arrTransfer(index, -1)">&lt;</div>
<div class="title-wrapper">
<input
v-if="isInputList[index]"
type="text"
class="ant-input editable-title-input"
@blur="blurEvent(index)"
@focus="$event.currentTarget.select()"
v-model="item.nodeName"
/>
<span v-else class="editable-title" @click="clickEvent(index)">{{ item.nodeName }}</span>
<span class="priority-title" @click="setPerson(item.priorityLevel)">优先级{{ item.priorityLevel }}</span>
<i class="anticon anticon-close close" @click="delTerm(index)"></i>
</div>
<div class="sort-right" v-if="index != nodeConfig.conditionNodes.length - 1" @click="arrTransfer(index)">&gt;</div>
<div class="content" @click="setPerson(item.priorityLevel)">{{ conditionStr(nodeConfig, index) }}</div>
<div class="error_tip" v-if="isTried && item.error">
<i class="anticon anticon-exclamation-circle"></i>
</div>
</div>
<addNode v-model:childNodeP="item.childNode" />
</div>
</div>
<nodeWrap v-if="item.childNode" v-model:nodeConfig="item.childNode" />
<template v-if="index == 0">
<div class="top-left-cover-line"></div>
<div class="bottom-left-cover-line"></div>
</template>
<template v-if="index == nodeConfig.conditionNodes.length - 1">
<div class="top-right-cover-line"></div>
<div class="bottom-right-cover-line"></div>
</template>
</div>
</div>
<addNode v-model:childNodeP="nodeConfig.childNode" />
</div>
</div>
<nodeWrap v-if="nodeConfig.childNode" v-model:nodeConfig="nodeConfig.childNode" />
</template>
<script setup>
import addNode from './addNode.vue'
import { onMounted, ref, watch, getCurrentInstance, computed } from 'vue'
import {
arrToStr,
conditionStr,
setApproverStr,
copyerStr,
bgColors,
placeholderList
} from './util'
import { useWorkFlowStoreWithOut } from '@/store/modules/simpleWorkflow'
let _uid = getCurrentInstance().uid
let props = defineProps({
nodeConfig: {
type: Object,
default: () => ({})
},
flowPermission: {
type: Object,
// eslint-disable-next-line vue/require-valid-default-prop
default: () => []
}
})
let defaultText = computed(() => {
return placeholderList[props.nodeConfig.type]
})
let showText = computed(() => {
if (props.nodeConfig.type == 0) return arrToStr(props.flowPermission) || '所有人'
if (props.nodeConfig.type == 1) return setApproverStr(props.nodeConfig)
return copyerStr(props.nodeConfig)
})
let isInputList = ref([])
let isInput = ref(false)
const resetConditionNodesErr = () => {
for (var i = 0; i < props.nodeConfig.conditionNodes.length; i++) {
// eslint-disable-next-line vue/no-mutating-props
props.nodeConfig.conditionNodes[i].error =
conditionStr(props.nodeConfig, i) == '请设置条件' &&
i != props.nodeConfig.conditionNodes.length - 1
}
}
onMounted(() => {
if (props.nodeConfig.type == 1) {
// eslint-disable-next-line vue/no-mutating-props
props.nodeConfig.error = !setApproverStr(props.nodeConfig)
} else if (props.nodeConfig.type == 2) {
// eslint-disable-next-line vue/no-mutating-props
props.nodeConfig.error = !copyerStr(props.nodeConfig)
} else if (props.nodeConfig.type == 4) {
resetConditionNodesErr()
}
})
let emits = defineEmits(['update:flowPermission', 'update:nodeConfig'])
let store = useWorkFlowStoreWithOut()
let {
setPromoter,
setApprover,
setCopyer,
setCondition,
setFlowPermission,
setApproverConfig,
setCopyerConfig,
setConditionsConfig
} = store
let isTried = computed(() => store.isTried)
let flowPermission1 = computed(() => store.flowPermission1)
let approverConfig1 = computed(() => store.approverConfig1)
let copyerConfig1 = computed(() => store.copyerConfig1)
let conditionsConfig1 = computed(() => store.conditionsConfig1)
watch(flowPermission1, (flow) => {
if (flow.flag && flow.id === _uid) {
emits('update:flowPermission', flow.value)
}
})
watch(approverConfig1, (approver) => {
if (approver.flag && approver.id === _uid) {
emits('update:nodeConfig', approver.value)
}
})
watch(copyerConfig1, (copyer) => {
if (copyer.flag && copyer.id === _uid) {
emits('update:nodeConfig', copyer.value)
}
})
watch(conditionsConfig1, (condition) => {
if (condition.flag && condition.id === _uid) {
emits('update:nodeConfig', condition.value)
}
})
const clickEvent = (index) => {
if (index || index === 0) {
isInputList.value[index] = true
} else {
isInput.value = true
}
}
const blurEvent = (index) => {
if (index || index === 0) {
isInputList.value[index] = false
// eslint-disable-next-line vue/no-mutating-props
props.nodeConfig.conditionNodes[index].nodeName =
props.nodeConfig.conditionNodes[index].nodeName || '条件'
} else {
isInput.value = false
// eslint-disable-next-line vue/no-mutating-props
props.nodeConfig.nodeName = props.nodeConfig.nodeName || defaultText
}
}
const delNode = () => {
emits('update:nodeConfig', props.nodeConfig.childNode)
}
const addTerm = () => {
let len = props.nodeConfig.conditionNodes.length + 1
// eslint-disable-next-line vue/no-mutating-props
props.nodeConfig.conditionNodes.push({
nodeName: '条件' + len,
type: 3,
priorityLevel: len,
conditionList: [],
nodeUserList: [],
childNode: null
})
resetConditionNodesErr()
emits('update:nodeConfig', props.nodeConfig)
}
const delTerm = (index) => {
// eslint-disable-next-line vue/no-mutating-props
props.nodeConfig.conditionNodes.splice(index, 1)
props.nodeConfig.conditionNodes.map((item, index) => {
item.priorityLevel = index + 1
item.nodeName = `条件${index + 1}`
})
resetConditionNodesErr()
emits('update:nodeConfig', props.nodeConfig)
if (props.nodeConfig.conditionNodes.length == 1) {
if (props.nodeConfig.childNode) {
if (props.nodeConfig.conditionNodes[0].childNode) {
reData(props.nodeConfig.conditionNodes[0].childNode, props.nodeConfig.childNode)
} else {
// eslint-disable-next-line vue/no-mutating-props
props.nodeConfig.conditionNodes[0].childNode = props.nodeConfig.childNode
}
}
emits('update:nodeConfig', props.nodeConfig.conditionNodes[0].childNode)
}
}
const reData = (data, addData) => {
if (!data.childNode) {
data.childNode = addData
} else {
reData(data.childNode, addData)
}
}
const setPerson = (priorityLevel) => {
var { type } = props.nodeConfig
if (type == 0) {
setPromoter(true)
setFlowPermission({
value: props.flowPermission,
flag: false,
id: _uid
})
} else if (type == 1) {
setApprover(true)
setApproverConfig({
value: {
...JSON.parse(JSON.stringify(props.nodeConfig)),
...{ settype: props.nodeConfig.settype ? props.nodeConfig.settype : 1 }
},
flag: false,
id: _uid
})
} else if (type == 2) {
setCopyer(true)
setCopyerConfig({
value: JSON.parse(JSON.stringify(props.nodeConfig)),
flag: false,
id: _uid
})
} else {
setCondition(true)
setConditionsConfig({
value: JSON.parse(JSON.stringify(props.nodeConfig)),
priorityLevel,
flag: false,
id: _uid
})
}
}
const arrTransfer = (index, type = 1) => {
//向左-1,向右1
// eslint-disable-next-line vue/no-mutating-props
props.nodeConfig.conditionNodes[index] = props.nodeConfig.conditionNodes.splice(
index + type,
1,
props.nodeConfig.conditionNodes[index]
)[0]
props.nodeConfig.conditionNodes.map((item, index) => {
item.priorityLevel = index + 1
})
resetConditionNodesErr()
emits('update:nodeConfig', props.nodeConfig)
}
</script>

View File

@ -0,0 +1,165 @@
/**
* todo
*/
export const arrToStr = (arr?: [{ name: string }]) => {
if (arr) {
return arr
.map((item) => {
return item.name
})
.toString()
}
}
export const setApproverStr = (nodeConfig: any) => {
if (nodeConfig.settype == 1) {
if (nodeConfig.nodeUserList.length == 1) {
return nodeConfig.nodeUserList[0].name
} else if (nodeConfig.nodeUserList.length > 1) {
if (nodeConfig.examineMode == 1) {
return arrToStr(nodeConfig.nodeUserList)
} else if (nodeConfig.examineMode == 2) {
return nodeConfig.nodeUserList.length + '人会签'
}
}
} else if (nodeConfig.settype == 2) {
const level =
nodeConfig.directorLevel == 1 ? '直接主管' : '第' + nodeConfig.directorLevel + '级主管'
if (nodeConfig.examineMode == 1) {
return level
} else if (nodeConfig.examineMode == 2) {
return level + '会签'
}
} else if (nodeConfig.settype == 4) {
if (nodeConfig.selectRange == 1) {
return '发起人自选'
} else {
if (nodeConfig.nodeUserList.length > 0) {
if (nodeConfig.selectRange == 2) {
return '发起人自选'
} else {
return '发起人从' + nodeConfig.nodeUserList[0].name + '中自选'
}
} else {
return ''
}
}
} else if (nodeConfig.settype == 5) {
return '发起人自己'
} else if (nodeConfig.settype == 7) {
return '从直接主管到通讯录中级别最高的第' + nodeConfig.examineEndDirectorLevel + '个层级主管'
}
}
export const copyerStr = (nodeConfig: any) => {
if (nodeConfig.nodeUserList.length != 0) {
return arrToStr(nodeConfig.nodeUserList)
} else {
if (nodeConfig.ccSelfSelectFlag == 1) {
return '发起人自选'
}
}
}
export const conditionStr = (nodeConfig, index) => {
const { conditionList, nodeUserList } = nodeConfig.conditionNodes[index]
if (conditionList.length == 0) {
return index == nodeConfig.conditionNodes.length - 1 &&
nodeConfig.conditionNodes[0].conditionList.length != 0
? '其他条件进入此流程'
: '请设置条件'
} else {
let str = ''
for (let i = 0; i < conditionList.length; i++) {
const {
columnId,
columnType,
showType,
showName,
optType,
zdy1,
opt1,
zdy2,
opt2,
fixedDownBoxValue
} = conditionList[i]
if (columnId == 0) {
if (nodeUserList.length != 0) {
str += '发起人属于:'
str +=
nodeUserList
.map((item) => {
return item.name
})
.join('或') + ' 并且 '
}
}
if (columnType == 'String' && showType == '3') {
if (zdy1) {
str += showName + '属于:' + dealStr(zdy1, JSON.parse(fixedDownBoxValue)) + ' 并且 '
}
}
if (columnType == 'Double') {
if (optType != 6 && zdy1) {
const optTypeStr = ['', '<', '>', '≤', '=', '≥'][optType]
str += `${showName} ${optTypeStr} ${zdy1} 并且 `
} else if (optType == 6 && zdy1 && zdy2) {
str += `${zdy1} ${opt1} ${showName} ${opt2} ${zdy2} 并且 `
}
}
}
return str ? str.substring(0, str.length - 4) : '请设置条件'
}
}
export const dealStr = (str: string, obj) => {
const arr = []
const list = str.split(',')
for (const elem in obj) {
list.map((item) => {
if (item == elem) {
arr.push(obj[elem].value)
}
})
}
return arr.join('或')
}
export const removeEle = (arr, elem, key = 'id') => {
let includesIndex
arr.map((item, index) => {
if (item[key] == elem[key]) {
includesIndex = index
}
})
arr.splice(includesIndex, 1)
}
export const bgColors = ['87, 106, 149', '255, 148, 62', '50, 150, 250']
export const placeholderList = ['发起人', '审核人', '抄送人']
export const setTypes = [
{ value: 1, label: '指定成员' },
{ value: 2, label: '主管' },
{ value: 4, label: '发起人自选' },
{ value: 5, label: '发起人自己' },
{ value: 7, label: '连续多级主管' }
]
export const selectModes = [
{ value: 1, label: '选一个人' },
{ value: 2, label: '选多个人' }
]
export const selectRanges = [
{ value: 1, label: '全公司' },
{ value: 2, label: '指定成员' },
{ value: 3, label: '指定角色' }
]
export const optTypes = [
{ value: '1', label: '小于' },
{ value: '2', label: '大于' },
{ value: '3', label: '小于等于' },
{ value: '4', label: '等于' },
{ value: '5', label: '大于等于' },
{ value: '6', label: '介于两个数之间' }
]

File diff suppressed because it is too large Load Diff

View File

@ -436,7 +436,7 @@ const initBpmnModeler = () => {
// bpmnModeler.createDiagram()
console.log(bpmnModeler, 'bpmnModeler111111')
// console.log(bpmnModeler, 'bpmnModeler111111')
emit('init-finished', bpmnModeler)
initModelListeners()
}
@ -666,10 +666,10 @@ const previewProcessJson = () => {
}
/* ------------------------------------------------ 芋道源码 methods ------------------------------------------------------ */
const processSave = async () => {
console.log(bpmnModeler, 'bpmnModelerbpmnModelerbpmnModelerbpmnModeler')
// console.log(bpmnModeler, 'bpmnModelerbpmnModelerbpmnModelerbpmnModeler')
const { err, xml } = await bpmnModeler.saveXML()
console.log(err, 'errerrerrerrerr')
console.log(xml, 'xmlxmlxmlxmlxml')
// console.log(err, 'errerrerrerrerr')
// console.log(xml, 'xmlxmlxmlxmlxml')
// 读取异常时抛出异常
if (err) {
// this.$modal.msgError('保存模型失败,请重试!')

View File

@ -115,19 +115,19 @@ const highlightDiagram = async () => {
if (!task) {
return
}
//进行中的任务已经高亮过了,则不高亮后面的任务了
// 进行中的任务已经高亮过了,则不高亮后面的任务了
if (findProcessTask) {
removeTaskDefinitionKeyList.push(n.id)
return
}
// 高亮任务
canvas.addMarker(n.id, getResultCss(task.result))
canvas.addMarker(n.id, getResultCss(task.status))
//标记是否高亮了进行中任务
if (task.result === 1) {
if (task.status === 1) {
findProcessTask = true
}
// 如果非通过,就不走后面的线条了
if (task.result !== 2) {
if (task.status !== 2) {
return
}
// 处理 outgoing 出线
@ -194,6 +194,7 @@ const highlightDiagram = async () => {
})
} else if (n.$type === 'bpmn:StartEvent') {
// 开始节点
canvas.addMarker(n.id, 'highlight')
n.outgoing?.forEach((nn) => {
// outgoing 例如说【bpmn:SequenceFlow】连线
// 获得连线是否有指向目标。如果有,则进行高亮
@ -205,10 +206,10 @@ const highlightDiagram = async () => {
})
} else if (n.$type === 'bpmn:EndEvent') {
// 结束节点
if (!processInstance.value || processInstance.value.result === 1) {
if (!processInstance.value || processInstance.value.status === 1) {
return
}
canvas.addMarker(n.id, getResultCss(processInstance.value.result))
canvas.addMarker(n.id, getResultCss(processInstance.value.status))
} else if (n.$type === 'bpmn:ServiceTask') {
//服务任务
if (activity.startTime > 0 && activity.endTime === 0) {
@ -223,39 +224,49 @@ const highlightDiagram = async () => {
canvas.addMarker(out.id, getResultCss(2))
})
}
} else if (n.$type === 'bpmn:SequenceFlow') {
let targetActivity = activityList.find((m: any) => m.key === n.targetRef.id)
if (targetActivity) {
canvas.addMarker(n.id, getActivityHighlightCss(targetActivity))
}
}
})
if (!isEmpty(removeTaskDefinitionKeyList)) {
taskList.value = taskList.value.filter(
(item) => !removeTaskDefinitionKeyList.includes(item.definitionKey)
(item) => !removeTaskDefinitionKeyList.includes(item.taskDefinitionKey)
)
}
}
const getActivityHighlightCss = (activity) => {
return activity.endTime ? 'highlight' : 'highlight-todo'
}
const getResultCss = (result) => {
if (result === 1) {
const getResultCss = (status) => {
if (status === 1) {
// 审批中
return 'highlight-todo'
} else if (result === 2) {
} else if (status === 2) {
// 已通过
return 'highlight'
} else if (result === 3) {
} else if (status === 3) {
// 不通过
return 'highlight-reject'
} else if (result === 4) {
} else if (status === 4) {
// 已取消
return 'highlight-cancel'
} else if (result === 5) {
} else if (status === 5) {
// 退回
return 'highlight-return'
} else if (result === 6) {
} else if (status === 6) {
// 委派
return 'highlight-return'
} else if (result === 7 || result === 8 || result === 9) {
// 待后加签任务完成/待前加签任务完成/待前置任务完成
return 'highlight-return'
return 'highlight-todo'
} else if (status === 7) {
// 审批通过中
return 'highlight-todo'
} else if (status === 0) {
// 待审批
return 'highlight-todo'
}
return ''
}
@ -296,10 +307,10 @@ const elementHover = (element) => {
!elementOverlayIds.value && (elementOverlayIds.value = {})
!overlays.value && (overlays.value = bpmnModeler.get('overlays'))
// 展示信息
console.log(activityLists.value, 'activityLists.value')
console.log(element.value, 'element.value')
// console.log(activityLists.value, 'activityLists.value')
// console.log(element.value, 'element.value')
const activity = activityLists.value.find((m) => m.key === element.value.id)
console.log(activity, 'activityactivityactivityactivity')
// console.log(activity, 'activityactivityactivityactivity')
if (!activity) {
return
}
@ -313,15 +324,14 @@ const elementHover = (element) => {
<p>部门:${processInstance.value.startUser.deptName}</p>
<p>创建时间:${formatDate(processInstance.value.createTime)}`
} else if (element.value.type === 'bpmn:UserTask') {
// debugger
let task = taskList.value.find((m) => m.id === activity.taskId) // 找到活动对应的 taskId
if (!task) {
return
}
let optionData = getIntDictOptions(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT)
let optionData = getIntDictOptions(DICT_TYPE.BPM_TASK_STATUS)
let dataResult = ''
optionData.forEach((element) => {
if (element.value == task.result) {
if (element.value == task.status) {
dataResult = element.label
}
})
@ -333,7 +343,7 @@ const elementHover = (element) => {
// <p>部门:${task.assigneeUser.deptName}</p>
// <p>结果:${getIntDictOptions(
// DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT,
// task.result
// task.status
// )}</p>
// <p>创建时间:${formatDate(task.createTime)}</p>`
if (task.endTime) {
@ -351,29 +361,30 @@ const elementHover = (element) => {
}
console.log(html)
} else if (element.value.type === 'bpmn:EndEvent' && processInstance.value) {
let optionData = getIntDictOptions(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT)
let optionData = getIntDictOptions(DICT_TYPE.BPM_TASK_STATUS)
let dataResult = ''
optionData.forEach((element) => {
if (element.value == processInstance.value.result) {
if (element.value == processInstance.value.status) {
dataResult = element.label
}
})
html = `<p>结果:${dataResult}</p>`
// html = `<p>结果:${getIntDictOptions(
// DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT,
// processInstance.value.result
// processInstance.value.status
// )}</p>`
if (processInstance.value.endTime) {
html += `<p>结束时间:${formatDate(processInstance.value.endTime)}</p>`
}
}
console.log(html, 'html111111111111111')
// console.log(html, 'html111111111111111')
elementOverlayIds.value[element.value.id] = toRaw(overlays.value)?.add(element.value, {
position: { left: 0, bottom: 0 },
html: `<div class="element-overlays">${html}</div>`
})
}
}
// 流程图的元素被 out
const elementOut = (element) => {
toRaw(overlays.value).remove({ element })
@ -389,6 +400,7 @@ onMounted(() => {
// 初始模型的监听器
initModelListeners()
})
onBeforeUnmount(() => {
// this.$once('hook:beforeDestroy', () => {
// })
@ -427,7 +439,7 @@ watch(
)
</script>
<style>
<style lang="scss">
/** 处理中 */
.highlight-todo.djs-connection > .djs-visual > path {
stroke: #1890ff !important;
@ -501,6 +513,10 @@ watch(
stroke: green !important;
}
.djs-element.highlight > .djs-visual > path {
stroke: green !important;
}
/** 不通过 */
.highlight-reject.djs-shape .djs-visual > :nth-child(1) {
fill: red !important;
@ -520,6 +536,7 @@ watch(
.highlight-reject.djs-connection > .djs-visual > path {
stroke: red !important;
marker-end: url(#sequenceflow-end-white-success) !important;
}
.highlight-reject:not(.djs-connection) .djs-visual > :nth-child(1) {

View File

@ -332,6 +332,16 @@
"name": "multiinstance_condition",
"isAttr": true,
"type": "String"
},
{
"name": "candidateStrategy",
"isAttr": true,
"type": "String"
},
{
"name": "candidateParam",
"isAttr": true,
"type": "String"
}
]
},

View File

@ -319,6 +319,16 @@
"name": "priority",
"isAttr": true,
"type": "String"
},
{
"name": "candidateStrategy",
"isAttr": true,
"type": "String"
},
{
"name": "candidateParam",
"isAttr": true,
"type": "String"
}
]
},

View File

@ -319,6 +319,16 @@
"name": "priority",
"isAttr": true,
"type": "String"
},
{
"name": "candidateStrategy",
"isAttr": true,
"type": "String"
},
{
"name": "candidateParam",
"isAttr": true,
"type": "String"
}
]
},

View File

@ -24,15 +24,10 @@
</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" /> -->
友情提示使用
<router-link :to="{ path: '/bpm/manager/form' }"
><el-link type="danger">流程表单</el-link>
</router-link>
替代提供更好的表单设计功能
<element-form :id="elementId" :type="elementType" />
</el-collapse-item>
<el-collapse-item name="task" v-if="elementType.indexOf('Task') !== -1" key="task">
<template #title><Icon icon="ep:checked" />任务</template>
<template #title><Icon icon="ep:checked" />任务审批人</template>
<element-task :id="elementId" :type="elementType" />
</el-collapse-item>
<el-collapse-item
@ -40,7 +35,7 @@
v-if="elementType.indexOf('Task') !== -1"
key="multiInstance"
>
<template #title><Icon icon="ep:help-filled" />多实例</template>
<template #title><Icon icon="ep:help-filled" />多实例会签配置</template>
<element-multi-instance :business-object="elementBusinessObject" :type="elementType" />
</el-collapse-item>
<el-collapse-item name="listeners" key="listeners">

View File

@ -3,13 +3,6 @@
<el-form label-width="90px" :model="needProps" :rules="rules">
<div v-if="needProps.type == 'bpmn:Process'">
<!-- 如果是 Process 信息的时候使用自定义表单 -->
<el-link
href="https://doc.iocoder.cn/bpm/#_3-%E6%B5%81%E7%A8%8B%E5%9B%BE%E7%A4%BA%E4%BE%8B"
type="danger"
target="_blank"
>
如何实现实现会签或签
</el-link>
<el-form-item label="流程标识" prop="id">
<el-input
v-model="needProps.id"
@ -68,13 +61,13 @@ const resetBaseInfo = () => {
console.log(bpmnElement.value, 'bpmnElement')
bpmnElement.value = bpmnInstances()?.bpmnElement
console.log(bpmnElement.value, 'resetBaseInfo11111111111')
// 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')
// console.log(elementBaseInfo.value, 'elementBaseInfo22222222222')
}
const handleKeyUpdate = (value) => {
// 校验 value 的值,只有 XML NCName 通过的情况下,才进行赋值。否则,会导致流程图报错,无法绘制的问题
@ -121,11 +114,11 @@ const updateBaseInfo = (key) => {
// id: elementBaseInfo.value[key]
// // di: { id: `${elementBaseInfo.value[key]}_di` }
// }
console.log(elementBaseInfo, 'elementBaseInfo11111111111')
// console.log(elementBaseInfo, 'elementBaseInfo11111111111')
needProps.value = { ...elementBaseInfo.value, ...needProps.value }
if (key === 'id') {
console.log('jinru')
// console.log('jinru')
console.log(window, 'window')
console.log(bpmnElement.value, 'bpmnElement')
console.log(toRaw(bpmnElement.value), 'bpmnElement')
@ -138,20 +131,11 @@ const updateBaseInfo = (key) => {
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), attrObj)
}
}
onMounted(() => {
// 针对上传的 bpmn 流程图时,需要延迟 1 秒的时间,保证 key 和 name 的更新
setTimeout(() => {
console.log(props.model, 'props.model')
handleKeyUpdate(props.model.key)
handleNameUpdate(props.model.name)
console.log(props, 'propsssssssssssssssssssss')
}, 1000)
})
watch(
() => props.businessObject,
(val) => {
console.log(val, 'val11111111111111111111')
// console.log(val, 'val11111111111111111111')
if (val) {
// nextTick(() => {
resetBaseInfo()
@ -159,6 +143,18 @@ watch(
}
}
)
watch(
() => props.model?.key,
(val) => {
// 针对上传的 bpmn 流程图时,保证 key 和 name 的更新
if (val) {
handleKeyUpdate(props.model.key)
handleNameUpdate(props.model.name)
}
}
)
// watch(
// () => ({ ...props }),
// (oldVal, newVal) => {

View File

@ -1,228 +1,233 @@
<template>
<div class="panel-tab__content">
<el-form label-width="80px">
<el-form-item label="表单标识">
<el-input v-model="formKey" clearable @change="updateElementFormKey" />
</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-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>
<!-- <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>
<!-- <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>
<!-- &lt;!&ndash; 枚举值设置 &ndash;&gt;-->
<!-- <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>
<!-- &lt;!&ndash; 校验规则 &ndash;&gt;-->
<!-- <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>
<!-- &lt;!&ndash; 表单属性 &ndash;&gt;-->
<!-- <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>
<!-- &lt;!&ndash; 底部按钮 &ndash;&gt;-->
<!-- <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>
<!-- <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({
@ -263,6 +268,9 @@ 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') ||
@ -421,7 +429,7 @@ const saveField = () => {
// 移除某个 字段的 配置项
const removeFieldOptionItem = (option, index, type) => {
console.log(option, 'option')
// console.log(option, 'option')
if (type === 'property') {
fieldPropertiesList.value.splice(index, 1)
return
@ -451,6 +459,11 @@ const updateElementExtensions = () => {
})
}
const formList = ref([]) // 流程表单的下拉框的数据
onMounted(async () => {
formList.value = await FormApi.getFormSimpleList()
})
watch(
() => props.id,
(val) => {

View File

@ -26,8 +26,16 @@
type="primary"
preIcon="ep:plus"
title="添加监听器"
size="small"
@click="openListenerForm(null)"
/>
<XButton
type="success"
preIcon="ep:select"
title="选择监听器"
size="small"
@click="openProcessListenerDialog"
/>
</div>
<!-- 监听器 编辑/创建 部分 -->
@ -240,11 +248,21 @@
</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 } from './utilSelf'
import {
initListenerType,
initListenerForm,
listenerType,
fieldType,
initListenerForm2
} from './utilSelf'
import ProcessListenerDialog from './ProcessListenerDialog.vue'
defineOptions({ name: 'ElementListeners' })
@ -284,6 +302,7 @@ const resetListenersList = () => {
}
// 打开 监听器详情 侧边栏
const openListenerForm = (listener, index?) => {
// debugger
if (listener) {
listenerForm.value = initListenerForm(listener)
editingListenerIndex.value = index
@ -321,6 +340,7 @@ const openListenerFieldForm = (field, index?) => {
}
// 保存监听器注入字段
const saveListenerFiled = async () => {
// debugger
let validateStatus = await listenerFieldFormRef.value.validate()
if (!validateStatus) return // 验证不通过直接返回
if (editingListenerFieldIndex.value === -1) {
@ -337,6 +357,7 @@ const saveListenerFiled = async () => {
}
// 移除监听器字段
const removeListenerField = (index) => {
// debugger
ElMessageBox.confirm('确认移除该字段吗?', '提示', {
confirmButtonText: '确 认',
cancelButtonText: '取 消'
@ -349,6 +370,7 @@ const removeListenerField = (index) => {
}
// 移除监听器
const removeListener = (index) => {
debugger
ElMessageBox.confirm('确认移除该监听器吗?', '提示', {
confirmButtonText: '确 认',
cancelButtonText: '取 消'
@ -365,6 +387,7 @@ const removeListener = (index) => {
}
// 保存监听器配置
const saveListenerConfig = async () => {
// debugger
let validateStatus = await listenerFormRef.value.validate()
if (!validateStatus) return // 验证不通过直接返回
const listenerObject = createListenerObject(listenerForm.value, false, prefix)
@ -389,6 +412,28 @@ const saveListenerConfig = async () => {
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) => {

View File

@ -0,0 +1,83 @@
<!-- 执行器选择 -->
<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 { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗
const dialogVisible = ref(false) // 弹窗的是否展示
const loading = ref(true) // 列表的加载中
const list = ref<ProcessListenerVO[]>([]) // 列表的数据
const total = ref(0) // 列表的总页数
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
type: undefined,
status: CommonStatusEnum.ENABLE
})
/** 打开弹窗 */
const open = async (type: string) => {
dialogVisible.value = true
loading.value = true
try {
queryParams.pageNo = 1
queryParams.type = type
const data = await ProcessListenerApi.getProcessListenerPage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
/** 提交表单 */
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
const select = async (row) => {
dialogVisible.value = false
// 发送操作成功的事件
emit('select', row)
}
</script>

View File

@ -39,6 +39,13 @@
title="添加监听器"
@click="openListenerForm(null)"
/>
<XButton
type="success"
preIcon="ep:select"
title="选择监听器"
size="small"
@click="openProcessListenerDialog"
/>
</div>
<!-- 监听器 编辑/创建 部分 -->
@ -286,11 +293,22 @@
</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 } from './utilSelf'
import {
initListenerForm,
initListenerType,
eventType,
listenerType,
fieldType,
initListenerForm2
} from './utilSelf'
import ProcessListenerDialog from '@/components/bpmnProcessDesigner/package/penal/listeners/ProcessListenerDialog.vue'
defineOptions({ name: 'UserTaskListeners' })
@ -437,6 +455,28 @@ const removeListenerField = (field, index) => {
.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) => {

View File

@ -40,6 +40,33 @@ export function initListenerType(listener) {
}
}
/** 将 ProcessListenerDO 转换成 initListenerForm 想同的 Form 对象 */
export function initListenerForm2(processListener) {
if (processListener.valueType === 'class') {
return {
listenerType: 'classListener',
class: processListener.value,
event: processListener.event,
fields: []
}
} else if (processListener.valueType === 'expression') {
return {
listenerType: 'expressionListener',
expression: processListener.value,
event: processListener.event,
fields: []
}
} else if (processListener.valueType === 'delegateExpression') {
return {
listenerType: 'delegateExpressionListener',
delegateExpression: processListener.value,
event: processListener.event,
fields: []
}
}
throw new Error('未知的监听器类型')
}
export const listenerType = {
classListener: 'Java 类',
expressionListener: '表达式',

View File

@ -1,11 +1,15 @@
<template>
<div class="panel-tab__content">
<el-form label-width="90px">
<el-form-item label="回路特性">
<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="StandardLoop" />
<el-option label="无" value="Null" />
</el-select>
</el-form-item>
@ -15,7 +19,7 @@
loopCharacteristics === 'SequentialMultiInstance'
"
>
<el-form-item label="循环数" key="loopCardinality">
<el-form-item label="循环数" key="loopCardinality">
<el-input
v-model="loopInstanceForm.loopCardinality"
clearable
@ -25,7 +29,8 @@
<el-form-item label="集合" key="collection" v-show="false">
<el-input v-model="loopInstanceForm.collection" clearable @change="updateLoopBase" />
</el-form-item>
<el-form-item label="元素变量" key="elementVariable">
<!-- 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">
@ -35,7 +40,8 @@
@change="updateLoopCondition"
/>
</el-form-item>
<el-form-item label="异步状态" key="async">
<!-- add by 芋艿:由于「异步状态」暂时用不到,所以这里 display 为 none -->
<el-form-item label="异步状态" key="async" style="display: none">
<el-checkbox
v-model="loopInstanceForm.asyncBefore"
label="异步前"
@ -124,6 +130,7 @@ const getElementLoop = (businessObject) => {
businessObject.loopCharacteristics.extensionElements.values[0].body
}
}
const changeLoopCharacteristicsType = (type) => {
// this.loopInstanceForm = { ...this.defaultLoopInstanceForm }; // 切换类型取消原表单配置
// 取消多实例配置
@ -160,6 +167,7 @@ const changeLoopCharacteristicsType = (type) => {
loopCharacteristics: toRaw(multiLoopInstance.value)
})
}
// 循环基数
const updateLoopCardinality = (cardinality) => {
let loopCardinality = null
@ -176,6 +184,7 @@ const updateLoopCardinality = (cardinality) => {
}
)
}
// 完成条件
const updateLoopCondition = (condition) => {
let completionCondition = null
@ -192,6 +201,7 @@ const updateLoopCondition = (condition) => {
}
)
}
// 重试周期
const updateLoopTimeCycle = (timeCycle) => {
const extensionElements = bpmnInstances().moddle.create('bpmn:ExtensionElements', {
@ -209,6 +219,7 @@ const updateLoopTimeCycle = (timeCycle) => {
}
)
}
// 直接更新的基础信息
const updateLoopBase = () => {
bpmnInstances().modeling.updateModdleProperties(
@ -220,6 +231,7 @@ const updateLoopBase = () => {
}
)
}
// 各异步状态
const updateLoopAsync = (key) => {
const { asyncBefore, asyncAfter } = loopInstanceForm.value
@ -238,6 +250,20 @@ const updateLoopAsync = (key) => {
)
}
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 }')
}
}
onBeforeUnmount(() => {
multiLoopInstance.value = null
bpmnElement.value = null

View File

@ -1,7 +1,8 @@
<template>
<div class="panel-tab__content">
<el-form size="small" label-width="90px">
<el-form-item label="异步延续">
<!-- add by 芋艿由于异步延续暂时用不到所以这里 display none -->
<el-form-item label="异步延续" style="display: none">
<el-checkbox
v-model="taskConfigForm.asyncBefore"
label="异步前"

View File

@ -0,0 +1,68 @@
<!-- 表达式选择 -->
<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 { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗
const dialogVisible = ref(false) // 弹窗的是否展示
const loading = ref(true) // 列表的加载中
const list = ref<ProcessExpressionVO[]>([]) // 列表的数据
const total = ref(0) // 列表的总页数
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
type: undefined,
status: CommonStatusEnum.ENABLE
})
/** 打开弹窗 */
const open = async (type: string) => {
dialogVisible.value = true
loading.value = true
try {
queryParams.pageNo = 1
queryParams.type = type
const data = await ProcessExpressionApi.getProcessExpressionPage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
/** 提交表单 */
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
const select = async (row) => {
dialogVisible.value = false
// 发送操作成功的事件
emit('select', row)
}
</script>

View File

@ -1,85 +1,204 @@
<template>
<div style="margin-top: 16px">
<!-- <el-form-item label="处理用户">-->
<!-- <el-select v-model="userTaskForm.assignee" @change="updateElementTask('assignee')">-->
<!-- <el-option v-for="ak in mockData" :key="'ass-' + ak" :label="`用户${ak}`" :value="`user${ak}`" />-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<!-- <el-form-item label="候选用户">-->
<!-- <el-select v-model="userTaskForm.candidateUsers" multiple collapse-tags @change="updateElementTask('candidateUsers')">-->
<!-- <el-option v-for="uk in mockData" :key="'user-' + uk" :label="`用户${uk}`" :value="`user${uk}`" />-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<!-- <el-form-item label="候选分组">-->
<!-- <el-select v-model="userTaskForm.candidateGroups" multiple collapse-tags @change="updateElementTask('candidateGroups')">-->
<!-- <el-option v-for="gk in mockData" :key="'ass-' + gk" :label="`分组${gk}`" :value="`group${gk}`" />-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<el-form-item label="到期时间">
<el-input v-model="userTaskForm.dueDate" clearable @change="updateElementTask('dueDate')" />
</el-form-item>
<el-form-item label="跟踪时间">
<el-input
v-model="userTaskForm.followUpDate"
<el-form label-width="100px">
<el-form-item label="规则类型" prop="candidateStrategy">
<el-select
v-model="userTaskForm.candidateStrategy"
clearable
@change="updateElementTask('followUpDate')"
style="width: 100%"
@change="changeCandidateStrategy"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.BPM_TASK_CANDIDATE_STRATEGY)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item
v-if="userTaskForm.candidateStrategy == 10"
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 == 20 || userTaskForm.candidateStrategy == 21"
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 label="优先级">
<el-input v-model="userTaskForm.priority" clearable @change="updateElementTask('priority')" />
<el-form-item
v-if="userTaskForm.candidateStrategy == 22"
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>
友情提示任务的分配规则使用
<router-link target="_blank" :to="{ path: '/bpm/manager/model' }"
><el-link type="danger">流程模型</el-link>
</router-link>
下的分配规则替代提供指定角色部门负责人部门成员岗位工作组自定义脚本等 7
种维护的任务分配维度更加灵活
</div>
<el-form-item
v-if="userTaskForm.candidateStrategy == 30"
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 === 40"
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 === 60"
label="流程表达式"
prop="candidateParam"
>
<el-input
type="textarea"
v-model="userTaskForm.candidateParam[0]"
clearable
style="width: 72%"
@change="updateElementTask"
/>
<el-button class="ml-5px" size="small" type="success" @click="openProcessExpressionDialog"
>选择表达式</el-button
>
<!-- 选择弹窗 -->
<ProcessExpressionDialog ref="processExpressionDialogRef" @select="selectProcessExpression" />
</el-form-item>
</el-form>
</template>
<script lang="ts" setup>
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
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'
defineOptions({ name: 'UserTask' })
const props = defineProps({
id: String,
type: String
})
const defaultTaskForm = ref({
assignee: '',
candidateUsers: [],
candidateGroups: [],
dueDate: '',
followUpDate: '',
priority: ''
const userTaskForm = ref({
candidateStrategy: undefined, // 分配规则
candidateParam: [] // 分配选项
})
const userTaskForm = ref<any>({})
// const mockData=ref([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
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 resetTaskForm = () => {
for (let key in defaultTaskForm.value) {
let value
if (key === 'candidateUsers' || key === 'candidateGroups') {
value = bpmnElement.value?.businessObject[key]
? bpmnElement.value.businessObject[key].split(',')
: []
const businessObject = bpmnElement.value.businessObject
if (!businessObject) {
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 {
value = bpmnElement.value?.businessObject[key] || defaultTaskForm.value[key]
userTaskForm.value.candidateParam = businessObject.candidateParam
.split(',')
.map((item) => +item)
}
userTaskForm.value[key] = value
} else {
userTaskForm.value.candidateParam = []
}
}
const updateElementTask = (key) => {
const taskAttr = Object.create(null)
if (key === 'candidateUsers' || key === 'candidateGroups') {
taskAttr[key] =
userTaskForm.value[key] && userTaskForm.value[key].length
? userTaskForm.value[key].join()
: null
} else {
taskAttr[key] = userTaskForm.value[key] || null
}
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), taskAttr)
/** 更新 candidateStrategy 字段时,需要清空 candidateParam并触发 bpmn 图更新 */
const changeCandidateStrategy = () => {
userTaskForm.value.candidateParam = []
updateElementTask()
}
/** 选中某个 options 时候,更新 bpmn 图 */
const updateElementTask = () => {
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
candidateStrategy: userTaskForm.value.candidateStrategy,
candidateParam: userTaskForm.value.candidateParam.join(',')
})
}
// 打开监听器弹窗
const processExpressionDialogRef = ref()
const openProcessExpressionDialog = async () => {
processExpressionDialogRef.value.open()
}
const selectProcessExpression = (expression) => {
userTaskForm.value.candidateParam = [expression.expression]
}
watch(
@ -92,6 +211,21 @@ watch(
},
{ 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
})

View File

@ -2,6 +2,7 @@ import { toRaw } from 'vue'
const bpmnInstances = () => (window as any)?.bpmnInstances
// 创建监听器实例
export function createListenerObject(options, isTask, prefix) {
debugger
const listenerObj = Object.create(null)
listenerObj.event = options.event
isTask && (listenerObj.id = options.id) // 任务监听器特有的 id 字段