mirror of
https://gitee.com/hhyykk/ipms-sjy-ui.git
synced 2025-02-01 19:24:58 +08:00
feat: Simple设计器-延时器
This commit is contained in:
parent
c144439e5b
commit
f470e0d65b
@ -39,6 +39,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="handler-item-text">包容分支</div>
|
<div class="handler-item-text">包容分支</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="handler-item" @click="addNode(NodeType.DELAY_TIMER_NODE)">
|
||||||
|
<!-- TODO @芋艿 需要更换一下iconfont的图标 -->
|
||||||
|
<div class="handler-item-icon copy">
|
||||||
|
<span class="iconfont icon-size icon-copy"></span>
|
||||||
|
</div>
|
||||||
|
<div class="handler-item-text">延迟器</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<div class="add-icon"><Icon icon="ep:plus" /></div>
|
<div class="add-icon"><Icon icon="ep:plus" /></div>
|
||||||
@ -208,6 +215,16 @@ const addNode = (type: number) => {
|
|||||||
}
|
}
|
||||||
emits('update:childNode', data)
|
emits('update:childNode', data)
|
||||||
}
|
}
|
||||||
|
if (type === NodeType.DELAY_TIMER_NODE) {
|
||||||
|
const data: SimpleFlowNode = {
|
||||||
|
id: 'Activity_' + generateUUID(),
|
||||||
|
name: NODE_DEFAULT_NAME.get(NodeType.DELAY_TIMER_NODE) as string,
|
||||||
|
showText: '',
|
||||||
|
type: NodeType.DELAY_TIMER_NODE,
|
||||||
|
childNode: props.childNode
|
||||||
|
}
|
||||||
|
emits('update:childNode', data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -38,6 +38,12 @@
|
|||||||
@update:model-value="handleModelValueUpdate"
|
@update:model-value="handleModelValueUpdate"
|
||||||
@find:parent-node="findFromParentNode"
|
@find:parent-node="findFromParentNode"
|
||||||
/>
|
/>
|
||||||
|
<!-- 延迟器节点 -->
|
||||||
|
<DelayTimerNode
|
||||||
|
v-if="currentNode && currentNode.type === NodeType.DELAY_TIMER_NODE"
|
||||||
|
:flow-node="currentNode"
|
||||||
|
@update:flow-node="handleModelValueUpdate"
|
||||||
|
/>
|
||||||
<!-- 递归显示孩子节点 -->
|
<!-- 递归显示孩子节点 -->
|
||||||
<ProcessNodeTree
|
<ProcessNodeTree
|
||||||
v-if="currentNode && currentNode.childNode"
|
v-if="currentNode && currentNode.childNode"
|
||||||
@ -60,6 +66,7 @@ import CopyTaskNode from './nodes/CopyTaskNode.vue'
|
|||||||
import ExclusiveNode from './nodes/ExclusiveNode.vue'
|
import ExclusiveNode from './nodes/ExclusiveNode.vue'
|
||||||
import ParallelNode from './nodes/ParallelNode.vue'
|
import ParallelNode from './nodes/ParallelNode.vue'
|
||||||
import InclusiveNode from './nodes/InclusiveNode.vue'
|
import InclusiveNode from './nodes/InclusiveNode.vue'
|
||||||
|
import DelayTimerNode from './nodes/DelayTimerNode.vue'
|
||||||
import { SimpleFlowNode, NodeType } from './consts'
|
import { SimpleFlowNode, NodeType } from './consts'
|
||||||
import { useWatchNode } from './node'
|
import { useWatchNode } from './node'
|
||||||
defineOptions({
|
defineOptions({
|
||||||
|
@ -23,6 +23,11 @@ export enum NodeType {
|
|||||||
*/
|
*/
|
||||||
COPY_TASK_NODE = 12,
|
COPY_TASK_NODE = 12,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 延迟器节点
|
||||||
|
*/
|
||||||
|
DELAY_TIMER_NODE = 13,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 条件节点
|
* 条件节点
|
||||||
*/
|
*/
|
||||||
@ -98,6 +103,8 @@ export interface SimpleFlowNode {
|
|||||||
defaultFlow?: boolean
|
defaultFlow?: boolean
|
||||||
// 活动的状态,用于前端节点状态展示
|
// 活动的状态,用于前端节点状态展示
|
||||||
activityStatus?: TaskStatusEnum
|
activityStatus?: TaskStatusEnum
|
||||||
|
// 延迟设置
|
||||||
|
delaySetting?: DelaySetting
|
||||||
}
|
}
|
||||||
// 候选人策略枚举 ( 用于审批节点。抄送节点 )
|
// 候选人策略枚举 ( 用于审批节点。抄送节点 )
|
||||||
export enum CandidateStrategy {
|
export enum CandidateStrategy {
|
||||||
@ -413,12 +420,14 @@ NODE_DEFAULT_TEXT.set(NodeType.USER_TASK_NODE, '请配置审批人')
|
|||||||
NODE_DEFAULT_TEXT.set(NodeType.COPY_TASK_NODE, '请配置抄送人')
|
NODE_DEFAULT_TEXT.set(NodeType.COPY_TASK_NODE, '请配置抄送人')
|
||||||
NODE_DEFAULT_TEXT.set(NodeType.CONDITION_NODE, '请设置条件')
|
NODE_DEFAULT_TEXT.set(NodeType.CONDITION_NODE, '请设置条件')
|
||||||
NODE_DEFAULT_TEXT.set(NodeType.START_USER_NODE, '请设置发起人')
|
NODE_DEFAULT_TEXT.set(NodeType.START_USER_NODE, '请设置发起人')
|
||||||
|
NODE_DEFAULT_TEXT.set(NodeType.DELAY_TIMER_NODE, '请设置延迟器')
|
||||||
|
|
||||||
export const NODE_DEFAULT_NAME = new Map<number, string>()
|
export const NODE_DEFAULT_NAME = new Map<number, string>()
|
||||||
NODE_DEFAULT_NAME.set(NodeType.USER_TASK_NODE, '审批人')
|
NODE_DEFAULT_NAME.set(NodeType.USER_TASK_NODE, '审批人')
|
||||||
NODE_DEFAULT_NAME.set(NodeType.COPY_TASK_NODE, '抄送人')
|
NODE_DEFAULT_NAME.set(NodeType.COPY_TASK_NODE, '抄送人')
|
||||||
NODE_DEFAULT_NAME.set(NodeType.CONDITION_NODE, '条件')
|
NODE_DEFAULT_NAME.set(NodeType.CONDITION_NODE, '条件')
|
||||||
NODE_DEFAULT_NAME.set(NodeType.START_USER_NODE, '发起人')
|
NODE_DEFAULT_NAME.set(NodeType.START_USER_NODE, '发起人')
|
||||||
|
NODE_DEFAULT_NAME.set(NodeType.DELAY_TIMER_NODE, '延迟器')
|
||||||
|
|
||||||
// 候选人策略。暂时不从字典中取。 后续可能调整。控制显示顺序
|
// 候选人策略。暂时不从字典中取。 后续可能调整。控制显示顺序
|
||||||
export const CANDIDATE_STRATEGY: DictDataVO[] = [
|
export const CANDIDATE_STRATEGY: DictDataVO[] = [
|
||||||
@ -568,3 +577,30 @@ export enum ProcessVariableEnum {
|
|||||||
*/
|
*/
|
||||||
START_USER_ID = 'PROCESS_START_USER_ID'
|
START_USER_ID = 'PROCESS_START_USER_ID'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 延迟设置
|
||||||
|
*/
|
||||||
|
export type DelaySetting = {
|
||||||
|
// 延迟类型
|
||||||
|
delayType: number
|
||||||
|
// 延迟时间表达式
|
||||||
|
delayTime: string
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 延迟类型
|
||||||
|
*/
|
||||||
|
export enum DelayTypeEnum {
|
||||||
|
/**
|
||||||
|
* 固定时长
|
||||||
|
*/
|
||||||
|
FIXED_TIME_DURATION = 1,
|
||||||
|
/**
|
||||||
|
* 固定日期时间
|
||||||
|
*/
|
||||||
|
FIXED_DATE_TIME = 2
|
||||||
|
}
|
||||||
|
export const DELAY_TYPE = [
|
||||||
|
{ label: '固定时长', value: DelayTypeEnum.FIXED_TIME_DURATION },
|
||||||
|
{ label: '固定日期时间', value: DelayTypeEnum.FIXED_DATE_TIME }
|
||||||
|
]
|
||||||
|
@ -0,0 +1,189 @@
|
|||||||
|
<template>
|
||||||
|
<el-drawer
|
||||||
|
:append-to-body="true"
|
||||||
|
v-model="settingVisible"
|
||||||
|
:show-close="false"
|
||||||
|
:size="550"
|
||||||
|
:before-close="saveConfig"
|
||||||
|
>
|
||||||
|
<template #header>
|
||||||
|
<div class="config-header">
|
||||||
|
<input
|
||||||
|
v-if="showInput"
|
||||||
|
type="text"
|
||||||
|
class="config-editable-input"
|
||||||
|
@blur="blurEvent()"
|
||||||
|
v-mountedFocus
|
||||||
|
v-model="nodeName"
|
||||||
|
:placeholder="nodeName"
|
||||||
|
/>
|
||||||
|
<div v-else class="node-name">
|
||||||
|
{{ nodeName }} <Icon class="ml-1" icon="ep:edit-pen" :size="16" @click="clickIcon()" />
|
||||||
|
</div>
|
||||||
|
<div class="divide-line"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div>
|
||||||
|
<el-form ref="formRef" :model="configForm" label-position="top" :rules="formRules">
|
||||||
|
<el-form-item label="延迟时间" prop="delayType">
|
||||||
|
<el-radio-group v-model="configForm.delayType">
|
||||||
|
<el-radio-button
|
||||||
|
v-for="item in DELAY_TYPE"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-if="configForm.delayType === DelayTypeEnum.FIXED_TIME_DURATION">
|
||||||
|
<el-form-item prop="timeDuration">
|
||||||
|
<el-input-number
|
||||||
|
class="mr-2"
|
||||||
|
:style="{ width: '100px' }"
|
||||||
|
v-model="configForm.timeDuration"
|
||||||
|
:min="1"
|
||||||
|
controls-position="right"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-select v-model="configForm.timeUnit" class="mr-2" :style="{ width: '100px' }">
|
||||||
|
<el-option
|
||||||
|
v-for="item in TIME_UNIT_TYPES"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
<el-text>后进入下一节点</el-text>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-if="configForm.delayType === DelayTypeEnum.FIXED_DATE_TIME" prop="dateTime">
|
||||||
|
<el-date-picker
|
||||||
|
class="mr-2"
|
||||||
|
v-model="configForm.dateTime"
|
||||||
|
type="datetime"
|
||||||
|
placeholder="请选择日期和时间"
|
||||||
|
value-format="YYYY-MM-DDTHH:mm:ss"
|
||||||
|
/>
|
||||||
|
<el-text>后进入下一节点</el-text>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<el-divider />
|
||||||
|
<div>
|
||||||
|
<el-button type="primary" @click="saveConfig">确 定</el-button>
|
||||||
|
<el-button @click="closeDrawer">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-drawer>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {
|
||||||
|
SimpleFlowNode,
|
||||||
|
NodeType,
|
||||||
|
TIME_UNIT_TYPES,
|
||||||
|
TimeUnitType,
|
||||||
|
DelayTypeEnum,
|
||||||
|
DELAY_TYPE
|
||||||
|
} from '../consts'
|
||||||
|
import { useWatchNode, useDrawer, useNodeName } from '../node'
|
||||||
|
import { convertTimeUnit } from '../utils'
|
||||||
|
defineOptions({
|
||||||
|
name: 'DelayTimerNodeConfig'
|
||||||
|
})
|
||||||
|
const props = defineProps({
|
||||||
|
flowNode: {
|
||||||
|
type: Object as () => SimpleFlowNode,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 抽屉配置
|
||||||
|
const { settingVisible, closeDrawer, openDrawer } = useDrawer()
|
||||||
|
// 当前节点
|
||||||
|
const currentNode = useWatchNode(props)
|
||||||
|
// 节点名称
|
||||||
|
const { nodeName, showInput, clickIcon, blurEvent } = useNodeName(NodeType.DELAY_TIMER_NODE)
|
||||||
|
// 抄送人表单配置
|
||||||
|
const formRef = ref() // 表单 Ref
|
||||||
|
// 表单校验规则
|
||||||
|
const formRules = reactive({
|
||||||
|
delayType: [{ required: true, message: '延迟时间不能为空', trigger: 'change' }],
|
||||||
|
timeDuration: [{ required: true, message: '延迟时间不能为空', trigger: 'change' }],
|
||||||
|
dateTime: [{ required: true, message: '延迟时间不能为空', trigger: 'change' }]
|
||||||
|
})
|
||||||
|
// 配置表单数据
|
||||||
|
const configForm = ref({
|
||||||
|
delayType: DelayTypeEnum.FIXED_TIME_DURATION,
|
||||||
|
timeDuration: 1,
|
||||||
|
timeUnit: TimeUnitType.HOUR,
|
||||||
|
dateTime: ''
|
||||||
|
})
|
||||||
|
// 保存配置
|
||||||
|
const saveConfig = async () => {
|
||||||
|
if (!formRef) return false
|
||||||
|
const valid = await formRef.value.validate()
|
||||||
|
if (!valid) return false
|
||||||
|
const showText = getShowText()
|
||||||
|
if (!showText) return false
|
||||||
|
currentNode.value.showText = showText
|
||||||
|
if (configForm.value.delayType === DelayTypeEnum.FIXED_TIME_DURATION) {
|
||||||
|
currentNode.value.delaySetting = {
|
||||||
|
delayType: configForm.value.delayType,
|
||||||
|
delayTime: getIsoTimeDuration()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (configForm.value.delayType === DelayTypeEnum.FIXED_DATE_TIME) {
|
||||||
|
currentNode.value.delaySetting = {
|
||||||
|
delayType: configForm.value.delayType,
|
||||||
|
delayTime: configForm.value.dateTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
settingVisible.value = false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
const getShowText = (): string => {
|
||||||
|
let showText = ''
|
||||||
|
if (configForm.value.delayType === DelayTypeEnum.FIXED_TIME_DURATION) {
|
||||||
|
showText = `延迟${configForm.value.timeDuration}${TIME_UNIT_TYPES.find((item) => item.value === configForm.value.timeUnit).label}`
|
||||||
|
}
|
||||||
|
if (configForm.value.delayType === DelayTypeEnum.FIXED_DATE_TIME) {
|
||||||
|
showText = `延迟至${configForm.value.dateTime.replace('T', ' ')}`
|
||||||
|
}
|
||||||
|
return showText
|
||||||
|
}
|
||||||
|
const getIsoTimeDuration = () => {
|
||||||
|
let strTimeDuration = 'PT'
|
||||||
|
if (configForm.value.timeUnit === TimeUnitType.MINUTE) {
|
||||||
|
strTimeDuration += configForm.value.timeDuration + 'M'
|
||||||
|
}
|
||||||
|
if (configForm.value.timeUnit === TimeUnitType.HOUR) {
|
||||||
|
strTimeDuration += configForm.value.timeDuration + 'H'
|
||||||
|
}
|
||||||
|
if (configForm.value.timeUnit === TimeUnitType.DAY) {
|
||||||
|
strTimeDuration += configForm.value.timeDuration + 'D'
|
||||||
|
}
|
||||||
|
return strTimeDuration
|
||||||
|
}
|
||||||
|
// 显示延迟器节点配置, 由父组件传过来
|
||||||
|
const showDelayTimerNodeConfig = (node: SimpleFlowNode) => {
|
||||||
|
nodeName.value = node.name
|
||||||
|
if (node.delaySetting) {
|
||||||
|
configForm.value.delayType = node.delaySetting.delayType
|
||||||
|
// 固定时长
|
||||||
|
if (configForm.value.delayType === DelayTypeEnum.FIXED_TIME_DURATION) {
|
||||||
|
const strTimeDuration = node.delaySetting.delayTime
|
||||||
|
let parseTime = strTimeDuration.slice(2, strTimeDuration.length - 1)
|
||||||
|
let parseTimeUnit = strTimeDuration.slice(strTimeDuration.length - 1)
|
||||||
|
configForm.value.timeDuration = parseInt(parseTime)
|
||||||
|
configForm.value.timeUnit = convertTimeUnit(parseTimeUnit)
|
||||||
|
}
|
||||||
|
// 固定日期时间
|
||||||
|
if (configForm.value.delayType === DelayTypeEnum.FIXED_DATE_TIME) {
|
||||||
|
configForm.value.dateTime = node.delaySetting.delayTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ openDrawer, showDelayTimerNodeConfig }) // 暴露方法给父组件
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
@ -0,0 +1,98 @@
|
|||||||
|
<template>
|
||||||
|
<div class="node-wrapper">
|
||||||
|
<div class="node-container">
|
||||||
|
<div
|
||||||
|
class="node-box"
|
||||||
|
:class="[
|
||||||
|
{ 'node-config-error': !currentNode.showText },
|
||||||
|
`${useTaskStatusClass(currentNode?.activityStatus)}`
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<div class="node-title-container">
|
||||||
|
<!-- TODO @芋艿 需要更换图标 -->
|
||||||
|
<div class="node-title-icon copy-task"><span class="iconfont icon-copy"></span></div>
|
||||||
|
<input
|
||||||
|
v-if="!readonly && showInput"
|
||||||
|
type="text"
|
||||||
|
class="editable-title-input"
|
||||||
|
@blur="blurEvent()"
|
||||||
|
v-mountedFocus
|
||||||
|
v-model="currentNode.name"
|
||||||
|
:placeholder="currentNode.name"
|
||||||
|
/>
|
||||||
|
<div v-else class="node-title" @click="clickTitle">
|
||||||
|
{{ currentNode.name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="node-content" @click="openNodeConfig">
|
||||||
|
<div class="node-text" :title="currentNode.showText" v-if="currentNode.showText">
|
||||||
|
{{ currentNode.showText }}
|
||||||
|
</div>
|
||||||
|
<div class="node-text" v-else>
|
||||||
|
{{ NODE_DEFAULT_TEXT.get(NodeType.DELAY_TIMER_NODE) }}
|
||||||
|
</div>
|
||||||
|
<Icon v-if="!readonly" icon="ep:arrow-right-bold" />
|
||||||
|
</div>
|
||||||
|
<div v-if="!readonly" class="node-toolbar">
|
||||||
|
<div class="toolbar-icon"
|
||||||
|
><Icon color="#0089ff" icon="ep:circle-close-filled" :size="18" @click="deleteNode"
|
||||||
|
/></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 传递子节点给添加节点组件。会在子节点前面添加节点 -->
|
||||||
|
<NodeHandler
|
||||||
|
v-if="currentNode"
|
||||||
|
v-model:child-node="currentNode.childNode"
|
||||||
|
:current-node="currentNode"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<DelayTimerNodeConfig
|
||||||
|
v-if="!readonly && currentNode"
|
||||||
|
ref="nodeSetting"
|
||||||
|
:flow-node="currentNode"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { SimpleFlowNode, NodeType, NODE_DEFAULT_TEXT } from '../consts'
|
||||||
|
import NodeHandler from '../NodeHandler.vue'
|
||||||
|
import { useNodeName2, useWatchNode, useTaskStatusClass } from '../node'
|
||||||
|
import DelayTimerNodeConfig from '../nodes-config/DelayTimerNodeConfig.vue'
|
||||||
|
defineOptions({
|
||||||
|
name: 'DelayTimerNode'
|
||||||
|
})
|
||||||
|
const props = defineProps({
|
||||||
|
flowNode: {
|
||||||
|
type: Object as () => SimpleFlowNode,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 定义事件,更新父组件。
|
||||||
|
const emits = defineEmits<{
|
||||||
|
'update:flowNode': [node: SimpleFlowNode | undefined]
|
||||||
|
}>()
|
||||||
|
// 是否只读
|
||||||
|
const readonly = inject<Boolean>('readonly')
|
||||||
|
// 监控节点的变化
|
||||||
|
const currentNode = useWatchNode(props)
|
||||||
|
// 节点名称编辑
|
||||||
|
const { showInput, blurEvent, clickTitle } = useNodeName2(currentNode, NodeType.DELAY_TIMER_NODE)
|
||||||
|
|
||||||
|
const nodeSetting = ref()
|
||||||
|
// 打开节点配置
|
||||||
|
const openNodeConfig = () => {
|
||||||
|
if (readonly) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
nodeSetting.value.showDelayTimerNodeConfig(currentNode.value)
|
||||||
|
nodeSetting.value.openDrawer()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除节点。更新当前节点为孩子节点
|
||||||
|
const deleteNode = () => {
|
||||||
|
emits('update:flowNode', currentNode.value.childNode)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
Loading…
Reference in New Issue
Block a user