mirror of
https://gitee.com/cai_xiao_feng/lowflow-design.git
synced 2025-12-06 16:18:22 +08:00
执行监听器
This commit is contained in:
parent
a0c7db739a
commit
d65509f2eb
140
src/typings/auto-imports.d.ts
vendored
140
src/typings/auto-imports.d.ts
vendored
@ -5,73 +5,85 @@
|
||||
// Generated by unplugin-auto-import
|
||||
export {}
|
||||
declare global {
|
||||
const EffectScope: typeof import('vue')['EffectScope']
|
||||
const ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
||||
const ElDivider: typeof import('element-plus/es')['ElDivider']
|
||||
const ElInput: typeof import('element-plus/es')['ElInput']
|
||||
const ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
|
||||
const ElRadio: typeof import('element-plus/es')['ElRadio']
|
||||
const ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||
const computed: typeof import('vue')['computed']
|
||||
const createApp: typeof import('vue')['createApp']
|
||||
const customRef: typeof import('vue')['customRef']
|
||||
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
|
||||
const defineComponent: typeof import('vue')['defineComponent']
|
||||
const effectScope: typeof import('vue')['effectScope']
|
||||
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
|
||||
const getCurrentScope: typeof import('vue')['getCurrentScope']
|
||||
const h: typeof import('vue')['h']
|
||||
const inject: typeof import('vue')['inject']
|
||||
const isProxy: typeof import('vue')['isProxy']
|
||||
const isReactive: typeof import('vue')['isReactive']
|
||||
const isReadonly: typeof import('vue')['isReadonly']
|
||||
const isRef: typeof import('vue')['isRef']
|
||||
const markRaw: typeof import('vue')['markRaw']
|
||||
const nextTick: typeof import('vue')['nextTick']
|
||||
const onActivated: typeof import('vue')['onActivated']
|
||||
const onBeforeMount: typeof import('vue')['onBeforeMount']
|
||||
const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
|
||||
const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
|
||||
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
|
||||
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
|
||||
const onDeactivated: typeof import('vue')['onDeactivated']
|
||||
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
|
||||
const onMounted: typeof import('vue')['onMounted']
|
||||
const onRenderTracked: typeof import('vue')['onRenderTracked']
|
||||
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
|
||||
const onScopeDispose: typeof import('vue')['onScopeDispose']
|
||||
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
|
||||
const onUnmounted: typeof import('vue')['onUnmounted']
|
||||
const onUpdated: typeof import('vue')['onUpdated']
|
||||
const provide: typeof import('vue')['provide']
|
||||
const reactive: typeof import('vue')['reactive']
|
||||
const readonly: typeof import('vue')['readonly']
|
||||
const ref: typeof import('vue')['ref']
|
||||
const resolveComponent: typeof import('vue')['resolveComponent']
|
||||
const shallowReactive: typeof import('vue')['shallowReactive']
|
||||
const shallowReadonly: typeof import('vue')['shallowReadonly']
|
||||
const shallowRef: typeof import('vue')['shallowRef']
|
||||
const toRaw: typeof import('vue')['toRaw']
|
||||
const toRef: typeof import('vue')['toRef']
|
||||
const toRefs: typeof import('vue')['toRefs']
|
||||
const toValue: typeof import('vue')['toValue']
|
||||
const triggerRef: typeof import('vue')['triggerRef']
|
||||
const unref: typeof import('vue')['unref']
|
||||
const useAttrs: typeof import('vue')['useAttrs']
|
||||
const useCssModule: typeof import('vue')['useCssModule']
|
||||
const useCssVars: typeof import('vue')['useCssVars']
|
||||
const useLink: typeof import('vue-router')['useLink']
|
||||
const useRoute: typeof import('vue-router')['useRoute']
|
||||
const useRouter: typeof import('vue-router')['useRouter']
|
||||
const useSlots: typeof import('vue')['useSlots']
|
||||
const watch: typeof import('vue')['watch']
|
||||
const watchEffect: typeof import('vue')['watchEffect']
|
||||
const watchPostEffect: typeof import('vue')['watchPostEffect']
|
||||
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
|
||||
const EffectScope: (typeof import('vue'))['EffectScope']
|
||||
const ElCheckbox: (typeof import('element-plus/es'))['ElCheckbox']
|
||||
const ElDivider: (typeof import('element-plus/es'))['ElDivider']
|
||||
const ElInput: (typeof import('element-plus/es'))['ElInput']
|
||||
const ElInputNumber: (typeof import('element-plus/es'))['ElInputNumber']
|
||||
const ElRadio: (typeof import('element-plus/es'))['ElRadio']
|
||||
const ElSelect: (typeof import('element-plus/es'))['ElSelect']
|
||||
const computed: (typeof import('vue'))['computed']
|
||||
const createApp: (typeof import('vue'))['createApp']
|
||||
const customRef: (typeof import('vue'))['customRef']
|
||||
const defineAsyncComponent: (typeof import('vue'))['defineAsyncComponent']
|
||||
const defineComponent: (typeof import('vue'))['defineComponent']
|
||||
const effectScope: (typeof import('vue'))['effectScope']
|
||||
const getCurrentInstance: (typeof import('vue'))['getCurrentInstance']
|
||||
const getCurrentScope: (typeof import('vue'))['getCurrentScope']
|
||||
const h: (typeof import('vue'))['h']
|
||||
const inject: (typeof import('vue'))['inject']
|
||||
const isProxy: (typeof import('vue'))['isProxy']
|
||||
const isReactive: (typeof import('vue'))['isReactive']
|
||||
const isReadonly: (typeof import('vue'))['isReadonly']
|
||||
const isRef: (typeof import('vue'))['isRef']
|
||||
const markRaw: (typeof import('vue'))['markRaw']
|
||||
const nextTick: (typeof import('vue'))['nextTick']
|
||||
const onActivated: (typeof import('vue'))['onActivated']
|
||||
const onBeforeMount: (typeof import('vue'))['onBeforeMount']
|
||||
const onBeforeRouteLeave: (typeof import('vue-router'))['onBeforeRouteLeave']
|
||||
const onBeforeRouteUpdate: (typeof import('vue-router'))['onBeforeRouteUpdate']
|
||||
const onBeforeUnmount: (typeof import('vue'))['onBeforeUnmount']
|
||||
const onBeforeUpdate: (typeof import('vue'))['onBeforeUpdate']
|
||||
const onDeactivated: (typeof import('vue'))['onDeactivated']
|
||||
const onErrorCaptured: (typeof import('vue'))['onErrorCaptured']
|
||||
const onMounted: (typeof import('vue'))['onMounted']
|
||||
const onRenderTracked: (typeof import('vue'))['onRenderTracked']
|
||||
const onRenderTriggered: (typeof import('vue'))['onRenderTriggered']
|
||||
const onScopeDispose: (typeof import('vue'))['onScopeDispose']
|
||||
const onServerPrefetch: (typeof import('vue'))['onServerPrefetch']
|
||||
const onUnmounted: (typeof import('vue'))['onUnmounted']
|
||||
const onUpdated: (typeof import('vue'))['onUpdated']
|
||||
const provide: (typeof import('vue'))['provide']
|
||||
const reactive: (typeof import('vue'))['reactive']
|
||||
const readonly: (typeof import('vue'))['readonly']
|
||||
const ref: (typeof import('vue'))['ref']
|
||||
const resolveComponent: (typeof import('vue'))['resolveComponent']
|
||||
const shallowReactive: (typeof import('vue'))['shallowReactive']
|
||||
const shallowReadonly: (typeof import('vue'))['shallowReadonly']
|
||||
const shallowRef: (typeof import('vue'))['shallowRef']
|
||||
const toRaw: (typeof import('vue'))['toRaw']
|
||||
const toRef: (typeof import('vue'))['toRef']
|
||||
const toRefs: (typeof import('vue'))['toRefs']
|
||||
const toValue: (typeof import('vue'))['toValue']
|
||||
const triggerRef: (typeof import('vue'))['triggerRef']
|
||||
const unref: (typeof import('vue'))['unref']
|
||||
const useAttrs: (typeof import('vue'))['useAttrs']
|
||||
const useCssModule: (typeof import('vue'))['useCssModule']
|
||||
const useCssVars: (typeof import('vue'))['useCssVars']
|
||||
const useLink: (typeof import('vue-router'))['useLink']
|
||||
const useRoute: (typeof import('vue-router'))['useRoute']
|
||||
const useRouter: (typeof import('vue-router'))['useRouter']
|
||||
const useSlots: (typeof import('vue'))['useSlots']
|
||||
const watch: (typeof import('vue'))['watch']
|
||||
const watchEffect: (typeof import('vue'))['watchEffect']
|
||||
const watchPostEffect: (typeof import('vue'))['watchPostEffect']
|
||||
const watchSyncEffect: (typeof import('vue'))['watchSyncEffect']
|
||||
}
|
||||
// for type re-export
|
||||
declare global {
|
||||
// @ts-ignore
|
||||
export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue'
|
||||
export type {
|
||||
Component,
|
||||
ComponentPublicInstance,
|
||||
ComputedRef,
|
||||
ExtractDefaultPropTypes,
|
||||
ExtractPropTypes,
|
||||
ExtractPublicPropTypes,
|
||||
InjectionKey,
|
||||
PropType,
|
||||
Ref,
|
||||
VNode,
|
||||
WritableComputedRef
|
||||
} from 'vue'
|
||||
import('vue')
|
||||
}
|
||||
|
||||
1
src/typings/components.d.ts
vendored
1
src/typings/components.d.ts
vendored
@ -9,6 +9,7 @@ declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
AdvancedFilter: typeof import('./../components/AdvancedFilter/index.vue')['default']
|
||||
ElAvatar: typeof import('element-plus/es')['ElAvatar']
|
||||
ElBadge: typeof import('element-plus/es')['ElBadge']
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
|
||||
ElCard: typeof import('element-plus/es')['ElCard']
|
||||
|
||||
@ -203,6 +203,7 @@ const addApproval = (node: FlowNode) => {
|
||||
pid: node.id,
|
||||
type: 'approval',
|
||||
name: '审批人',
|
||||
executionListeners: [],
|
||||
child: child,
|
||||
// 属性
|
||||
assigneeType: 'user',
|
||||
|
||||
@ -1,22 +1,62 @@
|
||||
<script setup lang="ts"></script>
|
||||
<script setup lang="ts">
|
||||
import type { FlowNode } from '@/views/flowDesign/nodes/type'
|
||||
import type { Ref } from 'vue'
|
||||
|
||||
const _inject = inject<{
|
||||
readOnly?: Ref<boolean>
|
||||
}>('flowDesign', { readOnly: ref(false) })
|
||||
const $emits = defineEmits<{
|
||||
(e: 'activeNode', node: FlowNode): void
|
||||
}>()
|
||||
const $props = withDefaults(
|
||||
defineProps<{
|
||||
node: FlowNode
|
||||
readOnly?: boolean
|
||||
}>(),
|
||||
{
|
||||
readOnly: false
|
||||
}
|
||||
)
|
||||
const _readOnly = computed(() => _inject.readOnly?.value || $props.readOnly)
|
||||
const activeNode = () => {
|
||||
if (_readOnly.value) return
|
||||
$emits('activeNode', $props.node)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="end-node">
|
||||
<div class="end-node-circle" />
|
||||
<el-text>流程结束</el-text>
|
||||
<div class="node-box">
|
||||
<div class="end-node-circle"></div>
|
||||
<div class="end-node" @click="activeNode">
|
||||
<el-text>{{ node.name }}</el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.end-node {
|
||||
padding: 0 0 30px;
|
||||
.node-box {
|
||||
position: relative;
|
||||
|
||||
.end-node-circle {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
background-color: var(--el-border-color);
|
||||
margin: auto;
|
||||
margin: auto auto 5px;
|
||||
}
|
||||
|
||||
.end-node {
|
||||
position: relative;
|
||||
background: var(--el-border-color-lighter);
|
||||
padding: 7px 24px;
|
||||
border-radius: 24px;
|
||||
cursor: pointer;
|
||||
overflow: visible;
|
||||
z-index: 10;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 0 5px 0 var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -15,9 +15,16 @@ export interface FlowNode {
|
||||
pid?: string
|
||||
name: string
|
||||
type: NodeType
|
||||
executionListeners?: NodeListener[]
|
||||
child?: FlowNode
|
||||
}
|
||||
|
||||
export interface NodeListener {
|
||||
event: string
|
||||
implementationType: 'class' | 'expression' | 'delegateExpression'
|
||||
implementation: string
|
||||
}
|
||||
|
||||
export interface StartNode extends FlowNode {
|
||||
formProperties: FormProperty[]
|
||||
}
|
||||
@ -77,6 +84,8 @@ export interface ApprovalNode extends AssigneeNode {
|
||||
formProperties: FormProperty[]
|
||||
// 操作权限
|
||||
operations: OperationPermissions
|
||||
// 任务监听器
|
||||
taskListeners?: NodeListener[]
|
||||
}
|
||||
|
||||
export interface TimerNode extends FlowNode {
|
||||
|
||||
@ -4,6 +4,7 @@ import type { Field } from '@/components/Render/type'
|
||||
import UserSelector from '@/components/UserSelector/index.vue'
|
||||
import AssigneePanel from './AssigneePanel.vue'
|
||||
import type { Ref } from 'vue'
|
||||
import TaskListeners from './TaskListeners.vue'
|
||||
|
||||
const { fields } = inject<{ fields: Ref<Field[]>; admin: string[] }>('flowDesign', {
|
||||
fields: ref([]),
|
||||
@ -133,6 +134,9 @@ watchEffect(() => {
|
||||
placeholder="指定人员"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item prop="taskListeners" label="任务监听器">
|
||||
<TaskListeners :node="activeData" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="表单权限" name="formPermissions">
|
||||
|
||||
18
src/views/flowDesign/panels/EndPanel.vue
Normal file
18
src/views/flowDesign/panels/EndPanel.vue
Normal file
@ -0,0 +1,18 @@
|
||||
<script setup lang="ts">
|
||||
import type { EndNode } from '../nodes/type'
|
||||
import ExecutionListeners from './ExecutionListeners.vue'
|
||||
|
||||
defineProps<{
|
||||
activeData: EndNode
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-form label-position="top" label-width="90px">
|
||||
<el-form-item prop="executionListeners" label="执行监听器">
|
||||
<ExecutionListeners :node="activeData" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
107
src/views/flowDesign/panels/ExecutionListeners.vue
Normal file
107
src/views/flowDesign/panels/ExecutionListeners.vue
Normal file
@ -0,0 +1,107 @@
|
||||
<script setup lang="ts">
|
||||
import type { FlowNode } from '@/views/flowDesign/nodes/type'
|
||||
|
||||
const props = defineProps<{
|
||||
node: FlowNode
|
||||
}>()
|
||||
const drawer = ref(false)
|
||||
const addListener = () => {
|
||||
if (!props.node.executionListeners) {
|
||||
props.node.executionListeners = []
|
||||
}
|
||||
props.node.executionListeners?.push({
|
||||
event: 'start',
|
||||
implementationType: 'delegateExpression',
|
||||
implementation: ''
|
||||
})
|
||||
}
|
||||
const delListener = (index: number) => {
|
||||
props.node.executionListeners?.splice(index, 1)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<slot>
|
||||
<el-badge :value="node.executionListeners?.length || 0" class="item" type="primary">
|
||||
<el-button icon="Setting" @click="drawer = true"> 配置</el-button>
|
||||
</el-badge>
|
||||
</slot>
|
||||
<el-drawer v-model="drawer" title="执行监听器">
|
||||
<div class="flex-col">
|
||||
<el-button @click="addListener" type="primary" icon="Plus">添加监听器</el-button>
|
||||
<div v-for="(item, index) in node.executionListeners" :key="index" class="listener-box">
|
||||
<el-button
|
||||
class="listener-close"
|
||||
@click="delListener(index)"
|
||||
plain
|
||||
circle
|
||||
icon="CircleClose"
|
||||
size="small"
|
||||
type="danger"
|
||||
/>
|
||||
<el-form-item label="事件" :prop="`executionListeners.${index}.event`">
|
||||
<el-radio-group v-model="item.event">
|
||||
<el-radio-button label="开始" value="start" />
|
||||
<el-radio-button label="结束" value="end" />
|
||||
<el-radio-button label="迁移" value="take" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="类型" :prop="`executionListeners.${index}.implementationType`">
|
||||
<el-radio-group v-model="item.implementationType">
|
||||
<el-radio-button label="委托表达式" value="delegateExpression" />
|
||||
<el-radio-button label="java类" value="class" />
|
||||
<el-radio-button label="表达式" value="expression" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="监听器" :prop="`executionListeners.${index}.implementation`">
|
||||
<template #label>
|
||||
<div class="flex-items-center gap3px">
|
||||
<span>监听器</span>
|
||||
<el-tooltip placement="top-start">
|
||||
<template #content>
|
||||
实现 ExecutionListener 接口 <br />
|
||||
委托表达式:${myExecutionListener} <br />
|
||||
表达式: ${myExecutionListener.notify(execution)} <br />
|
||||
java类:${com.example.listener.MyExecutionListener}
|
||||
</template>
|
||||
<el-icon>
|
||||
<QuestionFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<el-input v-model="item.implementation" placeholder="请输入监听器" clearable>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.listener-box {
|
||||
border: 1px dashed var(--el-border-color);
|
||||
border-radius: var(--el-border-radius-base);
|
||||
margin-top: 10px;
|
||||
padding: 7px;
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--el-color-primary);
|
||||
|
||||
.listener-close {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.listener-close {
|
||||
position: absolute;
|
||||
top: -7px;
|
||||
right: -7px;
|
||||
z-index: 1;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -2,11 +2,13 @@
|
||||
import type { FormProperty, StartNode } from '../nodes/type'
|
||||
import type { Field } from '@/components/Render/type'
|
||||
import type { Ref } from 'vue'
|
||||
import ExecutionListeners from './ExecutionListeners.vue'
|
||||
|
||||
const { fields } = inject<{ fields: Ref<Field[]> }>('flowDesign', { fields: ref([]) })
|
||||
const props = defineProps<{
|
||||
activeData: StartNode
|
||||
}>()
|
||||
const activeName = ref('basicSettings')
|
||||
const allReadonly = computed({
|
||||
get() {
|
||||
return props.activeData.formProperties.every((e) => e.readonly)
|
||||
@ -84,33 +86,46 @@ watchEffect(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-table :data="activeData.formProperties">
|
||||
<el-table-column prop="name" label="字段" />
|
||||
<el-table-column prop="readonly">
|
||||
<template #header>
|
||||
<el-checkbox v-model="allReadonly" label="只读" />
|
||||
</template>
|
||||
<template #default="{ row }">
|
||||
<el-checkbox v-model="row.readonly" @change="changeReadonly(row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="required">
|
||||
<template #header>
|
||||
<el-checkbox v-model="allRequired" label="必填" />
|
||||
</template>
|
||||
<template #default="{ row }">
|
||||
<el-checkbox v-model="row.required" @change="changeRequired(row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="hidden">
|
||||
<template #header>
|
||||
<el-checkbox v-model="allHidden" label="隐藏" />
|
||||
</template>
|
||||
<template #default="{ row }">
|
||||
<el-checkbox v-model="row.hidden" @change="changeHidden(row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-tabs v-model="activeName" stretch class="el-segmented">
|
||||
<el-tab-pane label="基础设置" name="basicSettings">
|
||||
<el-form label-position="top" label-width="90px">
|
||||
<el-form-item prop="executionListeners" label="执行监听器">
|
||||
<ExecutionListeners :node="activeData" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="表单权限" name="formPermissions">
|
||||
<el-table :data="activeData.formProperties">
|
||||
<el-table-column prop="name" label="字段" />
|
||||
<el-table-column prop="readonly">
|
||||
<template #header>
|
||||
<el-checkbox v-model="allReadonly" label="只读" />
|
||||
</template>
|
||||
<template #default="{ row }">
|
||||
<el-checkbox v-model="row.readonly" @change="changeReadonly(row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="required">
|
||||
<template #header>
|
||||
<el-checkbox v-model="allRequired" label="必填" />
|
||||
</template>
|
||||
<template #default="{ row }">
|
||||
<el-checkbox v-model="row.required" @change="changeRequired(row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="hidden">
|
||||
<template #header>
|
||||
<el-checkbox v-model="allHidden" label="隐藏" />
|
||||
</template>
|
||||
<template #default="{ row }">
|
||||
<el-checkbox v-model="row.hidden" @change="changeHidden(row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
<style scoped lang="scss">
|
||||
@import '@/styles/el-segmented.scss';
|
||||
</style>
|
||||
|
||||
107
src/views/flowDesign/panels/TaskListeners.vue
Normal file
107
src/views/flowDesign/panels/TaskListeners.vue
Normal file
@ -0,0 +1,107 @@
|
||||
<script setup lang="ts">
|
||||
import type { ApprovalNode } from '@/views/flowDesign/nodes/type'
|
||||
|
||||
const props = defineProps<{
|
||||
node: ApprovalNode
|
||||
}>()
|
||||
const drawer = ref(false)
|
||||
const addListener = () => {
|
||||
if (!props.node.taskListeners) {
|
||||
props.node.taskListeners = []
|
||||
}
|
||||
props.node.taskListeners?.push({
|
||||
event: 'create',
|
||||
implementationType: 'delegateExpression',
|
||||
implementation: ''
|
||||
})
|
||||
}
|
||||
const delListener = (index: number) => {
|
||||
props.node.taskListeners?.splice(index, 1)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<slot>
|
||||
<el-badge :value="node.taskListeners?.length || 0" class="item" type="primary">
|
||||
<el-button icon="Setting" @click="drawer = true"> 配置</el-button>
|
||||
</el-badge>
|
||||
</slot>
|
||||
<el-drawer v-model="drawer" title="任务监听器">
|
||||
<div class="flex-col">
|
||||
<el-button @click="addListener" type="primary" icon="Plus">添加监听器</el-button>
|
||||
<div v-for="(item, index) in node.taskListeners" :key="index" class="listener-box">
|
||||
<el-button
|
||||
class="listener-close"
|
||||
@click="delListener(index)"
|
||||
plain
|
||||
circle
|
||||
icon="CircleClose"
|
||||
size="small"
|
||||
type="danger"
|
||||
/>
|
||||
<el-form-item label="事件" :prop="`taskListeners.${index}.event`">
|
||||
<el-radio-group v-model="item.event">
|
||||
<el-radio-button label="创建" value="create" />
|
||||
<el-radio-button label="指派" value="assignment" />
|
||||
<el-radio-button label="完成" value="complete" />
|
||||
<el-radio-button label="删除" value="delete" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="类型" :prop="`taskListeners.${index}.implementationType`">
|
||||
<el-radio-group v-model="item.implementationType">
|
||||
<el-radio-button label="委托表达式" value="delegateExpression" />
|
||||
<el-radio-button label="java类" value="class" />
|
||||
<el-radio-button label="表达式" value="expression" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="监听器" :prop="`taskListeners.${index}.implementation`">
|
||||
<template #label>
|
||||
<div class="flex-items-center gap3px">
|
||||
<span>监听器</span>
|
||||
<el-tooltip placement="top-start">
|
||||
<template #content>
|
||||
委托表达式:${myCreateTaskListener} <br />
|
||||
表达式: ${myCreateTaskListener.notify(execution)} <br />
|
||||
java类:${com.example.listener.MyCreateTaskListener}
|
||||
</template>
|
||||
<el-icon>
|
||||
<QuestionFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<el-input v-model="item.implementation" placeholder="请输入监听器" clearable>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.listener-box {
|
||||
border: 1px dashed var(--el-border-color);
|
||||
border-radius: var(--el-border-radius-base);
|
||||
margin-top: 10px;
|
||||
padding: 7px;
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--el-color-primary);
|
||||
|
||||
.listener-close {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.listener-close {
|
||||
position: absolute;
|
||||
top: -7px;
|
||||
right: -7px;
|
||||
z-index: 1;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -7,6 +7,7 @@ import Cc from './CcPanel.vue'
|
||||
import Timer from './TimerPanel.vue'
|
||||
import Notify from './NotifyPanel.vue'
|
||||
import Condition from './ConditionPanel.vue'
|
||||
import End from './EndPanel.vue'
|
||||
import type { FlowNode } from '../nodes/type'
|
||||
|
||||
defineProps<{
|
||||
@ -19,7 +20,8 @@ const panels: Recordable<Component> = {
|
||||
cc: Cc,
|
||||
timer: Timer,
|
||||
notify: Notify,
|
||||
condition: Condition
|
||||
condition: Condition,
|
||||
end: End
|
||||
}
|
||||
const showInput = ref(false)
|
||||
const onClickOutside = () => {
|
||||
|
||||
@ -10,12 +10,14 @@ const process = ref<FlowNode>({
|
||||
pid: undefined,
|
||||
type: 'start',
|
||||
name: '发起人',
|
||||
executionListeners: [],
|
||||
formProperties: [],
|
||||
child: {
|
||||
id: 'end',
|
||||
pid: 'root',
|
||||
type: 'end',
|
||||
name: '结束',
|
||||
name: '流程结束',
|
||||
executionListeners: [],
|
||||
child: undefined
|
||||
} as EndNode
|
||||
} as StartNode)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user