Skip to content

Commit 137b33e

Browse files
committed
【功能新增】 仿钉钉流程模型增加浏览模式
1 parent d477b35 commit 137b33e

17 files changed

+436
-58
lines changed

src/components/SimpleProcessDesignerV2/src/NodeHandler.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
v-model:visible="popoverShow"
77
placement="right-start"
88
width="auto"
9+
v-if="!readonly"
910
>
1011
<div class="handler-item-wrapper">
1112
<div class="handler-item" @click="addNode(NodeType.USER_TASK_NODE)">
@@ -78,6 +79,8 @@ const props = defineProps({
7879
7980
const emits = defineEmits(['update:childNode'])
8081
82+
const readonly = inject<Boolean>('readonly') // 是否只读
83+
8184
const addNode = (type: number) => {
8285
popoverShow.value = false
8386
if (type === NodeType.USER_TASK_NODE) {

src/components/SimpleProcessDesignerV2/src/ProcessNodeTree.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
/>
4848

4949
<!-- 结束节点 -->
50-
<EndEventNode v-if="currentNode && currentNode.type === NodeType.END_EVENT_NODE" />
50+
<EndEventNode v-if="currentNode && currentNode.type === NodeType.END_EVENT_NODE" :flow-node="currentNode" />
5151
</template>
5252
<script setup lang="ts">
5353
import StartUserNode from './nodes/StartUserNode.vue'

src/components/SimpleProcessDesignerV2/src/SimpleProcessDesigner.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ const props = defineProps({
5757
required: true
5858
}
5959
})
60-
const loading = ref(true)
60+
const loading = ref(false)
6161
const formFields = ref<string[]>([])
6262
const formType = ref(20)
6363
const roleOptions = ref<RoleApi.RoleVO[]>([]) // 角色列表
@@ -66,6 +66,7 @@ const userOptions = ref<UserApi.UserVO[]>([]) // 用户列表
6666
const deptOptions = ref<DeptApi.DeptVO[]>([]) // 部门列表
6767
const deptTreeOptions = ref()
6868
const userGroupOptions = ref<UserGroupApi.UserGroupVO[]>([]) // 用户组列表
69+
provide('readonly', false)
6970
provide('formFields', formFields)
7071
provide('formType', formType)
7172
provide('roleList', roleOptions)
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<template>
2+
<div class="simple-flow-canvas" v-loading="loading">
3+
<div class="simple-flow-container">
4+
<div class="scale-container" :style="`transform: scale(${scaleValue / 100});`">
5+
<ProcessNodeTree v-if="processNodeTree" v-model:flow-node="processNodeTree"/>
6+
</div>
7+
</div>
8+
</div>
9+
</template>
10+
11+
<script setup lang="ts">
12+
import ProcessNodeTree from './ProcessNodeTree.vue'
13+
import { SimpleFlowNode } from './consts'
14+
15+
defineOptions({
16+
name: 'SimpleProcessRender'
17+
})
18+
19+
const props = defineProps({
20+
flowNode: {
21+
type: Object as () => SimpleFlowNode,
22+
required: true
23+
}
24+
})
25+
const loading = ref(false)
26+
27+
watch(
28+
() => props.flowNode,
29+
(newValue) => {
30+
processNodeTree.value = newValue
31+
}
32+
)
33+
const processNodeTree = ref<SimpleFlowNode | undefined>(props.flowNode)
34+
provide('readonly', true)
35+
let scaleValue = ref(100)
36+
const MAX_SCALE_VALUE = 200
37+
const MIN_SCALE_VALUE = 50
38+
// 放大
39+
const zoomOut = () => {
40+
if (scaleValue.value == MAX_SCALE_VALUE) {
41+
return
42+
}
43+
scaleValue.value += 10
44+
}
45+
// 缩小
46+
const zoomIn = () => {
47+
if (scaleValue.value == MIN_SCALE_VALUE) {
48+
return
49+
}
50+
scaleValue.value -= 10
51+
}
52+
53+
// onMounted(async () => {
54+
// try {
55+
// loading.value = true
56+
// if (props.view) {
57+
// processNodeTree.value = props.view.simpleModel
58+
// }
59+
// } finally {
60+
// loading.value = false
61+
// }
62+
// })
63+
</script>

src/components/SimpleProcessDesignerV2/src/consts.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// @ts-ignore
22
import { DictDataVO } from '@/api/system/dict/types'
3-
3+
import { TaskStatusEnum } from '@/api/bpm/task'
44
/**
55
* 节点类型
66
*/
@@ -96,6 +96,8 @@ export interface SimpleFlowNode {
9696
conditionGroups?: ConditionGroup
9797
// 是否默认的条件
9898
defaultFlow?: boolean
99+
// 活动的状态,用于前端节点状态展示
100+
activityStatus? : TaskStatusEnum
99101
}
100102
// 候选人策略枚举 ( 用于审批节点。抄送节点 )
101103
export enum CandidateStrategy {
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import SimpleProcessDesigner from './SimpleProcessDesigner.vue'
2+
import SimpleProcessViewer from './SimpleProcessViewer.vue'
23
import '../theme/simple-process-designer.scss'
34

4-
export { SimpleProcessDesigner }
5+
export { SimpleProcessDesigner, SimpleProcessViewer }

src/components/SimpleProcessDesignerV2/src/node.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { cloneDeep } from 'lodash-es'
2+
import { TaskStatusEnum } from '@/api/bpm/task'
23
import * as RoleApi from '@/api/system/role'
34
import * as DeptApi from '@/api/system/dept'
45
import * as PostApi from '@/api/system/post'
@@ -476,3 +477,26 @@ export function useNodeName2(node: Ref<SimpleFlowNode>, nodeType: NodeType) {
476477
blurEvent
477478
}
478479
}
480+
481+
/**
482+
* @description 根据节点任务状态,获取节点任务状态样式
483+
*/
484+
export function useTaskStatusClass(taskStatus: TaskStatusEnum | undefined) : string {
485+
if (!taskStatus) {
486+
return ''
487+
}
488+
if (taskStatus === TaskStatusEnum.APPROVE ) {
489+
return 'status-pass'
490+
}
491+
if (taskStatus === TaskStatusEnum.RUNNING ) {
492+
return 'status-running'
493+
}
494+
if (taskStatus === TaskStatusEnum.REJECT ) {
495+
return 'status-reject'
496+
}
497+
if (taskStatus === TaskStatusEnum.CANCEL ) {
498+
return 'status-cancel'
499+
}
500+
501+
return '';
502+
}

src/components/SimpleProcessDesignerV2/src/nodes/CopyTaskNode.vue

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<div class="node-title-container">
66
<div class="node-title-icon copy-task"><span class="iconfont icon-copy"></span></div>
77
<input
8-
v-if="showInput"
8+
v-if="!readonly && showInput"
99
type="text"
1010
class="editable-title-input"
1111
@blur="blurEvent()"
@@ -24,9 +24,9 @@
2424
<div class="node-text" v-else>
2525
{{ NODE_DEFAULT_TEXT.get(NodeType.COPY_TASK_NODE) }}
2626
</div>
27-
<Icon icon="ep:arrow-right-bold" />
27+
<Icon v-if="!readonly" icon="ep:arrow-right-bold" />
2828
</div>
29-
<div class="node-toolbar">
29+
<div v-if="!readonly" class="node-toolbar">
3030
<div class="toolbar-icon"
3131
><Icon color="#0089ff" icon="ep:circle-close-filled" :size="18" @click="deleteNode"
3232
/></div>
@@ -36,7 +36,7 @@
3636
<!-- 传递子节点给添加节点组件。会在子节点前面添加节点 -->
3737
<NodeHandler v-if="currentNode" v-model:child-node="currentNode.childNode" />
3838
</div>
39-
<CopyTaskNodeConfig v-if="currentNode" ref="nodeSetting" :flow-node="currentNode" />
39+
<CopyTaskNodeConfig v-if="!readonly && currentNode" ref="nodeSetting" :flow-node="currentNode" />
4040
</div>
4141
</template>
4242
<script setup lang="ts">
@@ -57,7 +57,8 @@ const props = defineProps({
5757
const emits = defineEmits<{
5858
'update:flowNode': [node: SimpleFlowNode | undefined]
5959
}>()
60-
60+
// 是否只读
61+
const readonly = inject<Boolean>('readonly')
6162
// 监控节点的变化
6263
const currentNode = useWatchNode(props)
6364
// 节点名称编辑
@@ -66,6 +67,9 @@ const { showInput, blurEvent, clickTitle } = useNodeName2(currentNode, NodeType.
6667
const nodeSetting = ref()
6768
// 打开节点配置
6869
const openNodeConfig = () => {
70+
if (readonly) {
71+
return
72+
}
6973
nodeSetting.value.showCopyTaskNodeConfig(currentNode.value)
7074
nodeSetting.value.openDrawer()
7175
}
Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,27 @@
11
<template>
22
<div class="end-node-wrapper">
3-
<div class="end-node-box">
3+
<div class="end-node-box" :class="taskStatusClass">
44
<span class="node-fixed-name" title="结束">结束</span>
55
</div>
66
</div>
77
</template>
88
<script setup lang="ts">
9+
import { SimpleFlowNode } from '../consts'
10+
import { useWatchNode, useTaskStatusClass } from '../node'
11+
912
defineOptions({
1013
name: 'EndEventNode'
1114
})
15+
const props = defineProps({
16+
flowNode: {
17+
type: Object as () => SimpleFlowNode,
18+
default: () => null
19+
}
20+
})
21+
// 监控节点变化
22+
const currentNode = useWatchNode(props)
23+
// 节点任务状态样式
24+
const taskStatusClass = useTaskStatusClass(currentNode.value?.activityStatus)
25+
1226
</script>
1327
<style lang="scss" scoped></style>

src/components/SimpleProcessDesignerV2/src/nodes/ExclusiveNode.vue

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
<template>
22
<div class="branch-node-wrapper">
33
<div class="branch-node-container">
4-
<el-button class="branch-node-add" color="#67c23a" @click="addCondition" plain>添加条件</el-button>
4+
<div v-if="readonly" class="branch-node-readonly" :class="taskStatusClass">
5+
<span class="iconfont icon-exclusive icon-size"></span>
6+
</div>
7+
<el-button v-else class="branch-node-add" color="#67c23a" @click="addCondition" plain
8+
>添加条件</el-button
9+
>
10+
511
<div
612
class="branch-node-item"
713
v-for="(item, index) in currentNode.conditionNodes"
@@ -17,9 +23,9 @@
1723
</template>
1824
<div class="node-wrapper">
1925
<div class="node-container">
20-
<div class="node-box" :class="{ 'node-config-error': !item.showText }">
26+
<div class="node-box" :class="[{ 'node-config-error': !item.showText }, `${useTaskStatusClass(item.activityStatus)}`]">
2127
<div class="branch-node-title-container">
22-
<div v-if="showInputs[index]">
28+
<div v-if="!readonly && showInputs[index]">
2329
<input
2430
type="text"
2531
class="input-max-width editable-title-input"
@@ -39,7 +45,10 @@
3945
{{ NODE_DEFAULT_TEXT.get(NodeType.CONDITION_NODE) }}
4046
</div>
4147
</div>
42-
<div class="node-toolbar" v-if="index + 1 !== currentNode.conditionNodes?.length">
48+
<div
49+
class="node-toolbar"
50+
v-if="!readonly && index + 1 !== currentNode.conditionNodes?.length"
51+
>
4352
<div class="toolbar-icon">
4453
<Icon
4554
color="#0089ff"
@@ -87,6 +96,7 @@ import NodeHandler from '../NodeHandler.vue'
8796
import ProcessNodeTree from '../ProcessNodeTree.vue'
8897
import { SimpleFlowNode, NodeType, NODE_DEFAULT_TEXT } from '../consts'
8998
import { getDefaultConditionNodeName } from '../utils'
99+
import { useTaskStatusClass } from '../node'
90100
import { generateUUID } from '@/utils'
91101
import ConditionNodeConfig from '../nodes-config/ConditionNodeConfig.vue'
92102
const { proxy } = getCurrentInstance() as any
@@ -109,9 +119,11 @@ const emits = defineEmits<{
109119
nodeType: number
110120
]
111121
}>()
112-
122+
// 是否只读
123+
const readonly = inject<Boolean>('readonly')
113124
const currentNode = ref<SimpleFlowNode>(props.flowNode)
114-
// const conditionNodes = computed(() => currentNode.value.conditionNodes);
125+
// 节点状态样式
126+
const taskStatusClass = useTaskStatusClass(currentNode.value?.activityStatus)
115127
116128
watch(
117129
() => props.flowNode,
@@ -135,6 +147,9 @@ const clickEvent = (index: number) => {
135147
}
136148
137149
const conditionNodeConfig = (nodeId: string) => {
150+
if (readonly) {
151+
return
152+
}
138153
const conditionNode = proxy.$refs[nodeId][0]
139154
conditionNode.open()
140155
}

0 commit comments

Comments
 (0)