Browse Source

新增子流程逻辑

hubin 1 year ago
parent
commit
a79f78feee

+ 7 - 1
src/router/index.ts

@@ -76,8 +76,14 @@ export const sysStaticRouter: Array<AppRouteRecordRaw> = [
 			{
 				path: 'index',
 				component: () => import('@/views/flow/create/index.vue'),
-				name: 'flow_create',
+				name: 'flow_create_index',
 				meta: { hidden: true, title: '创建流程', icon: '' }
+			},
+			{
+				path: 'child',
+				component: () => import('@/views/flow/create/child.vue'),
+				name: 'flow_create_child',
+				meta: { hidden: true, title: '创建子流程', icon: '' }
 			}
 		]
 	},

+ 1 - 0
src/store/modules/flow.ts

@@ -10,6 +10,7 @@ export const useFlowStore = defineStore({
 			processKey: '', // 唯一标识
 			processName: '', // 流程定义名称
 			processIcon: 'approval', // 流程图标
+			processType: 'main', // 默认 main 主流程,设置 child 子流程
 			categoryId: '', // 流程组分类ID
 			remark: '', // 备注说明
 			createTime: '', // 创建时间

+ 312 - 0
src/views/flow/create/child.vue

@@ -0,0 +1,312 @@
+<template>
+	<div class="create-approval">
+		<div class="create-approval-header flex flex_align-center">
+			<div v-if="false" class="create-approval-header-back">
+				<el-icon :size="18">
+					<ArrowLeft />
+				</el-icon>
+			</div>
+			<div class="create-approval-header-left-zh">
+				<div class="create-approval-header-name">{{ processName }}</div>
+				<div v-if="false" class="create-approval-header-time">最近保存:6 分钟前</div>
+			</div>
+			<div class="create-approval-header-tab-list">
+				<div
+					v-for="(item, idx) in componentsArr"
+					:key="idx"
+					class="create-approval-header-tab-item"
+					:class="[item.value === activeTab ? 'active' : '']"
+					@click="activeComponent(idx)"
+				>
+					<span class="create-approval-header-tab-counter">{{ idx + 1 }}</span>
+					<span>{{ item.label }}</span>
+				</div>
+			</div>
+			<div class="create-approval-header-right">
+				<el-button type="primary" @click="submitHandler">发布</el-button>
+			</div>
+		</div>
+		<div class="create-approval-main">
+			<component :is="item.component" v-for="(item, idx) in componentsArr" v-show="item.value === activeTab" ref="compRefs" :key="idx" />
+		</div>
+	</div>
+</template>
+
+<script setup name="flow_create">
+import { computed, nextTick, ref } from 'vue'
+import { storeToRefs } from 'pinia'
+import useFlowStore from '@/store/modules/flow'
+import BasicInfoTab from './components/BasicInfo.vue'
+import FlowDesignTab from './components/FlowDesign.vue'
+import { useRoute, useRouter } from 'vue-router'
+import process from '@/api/flow/process'
+import useStore from '@/store'
+import { ElMessage } from 'element-plus'
+const { tagsView } = useStore()
+const router = useRouter()
+const route = useRoute()
+const flowStore = useFlowStore()
+const { categoryId, processId, processIcon, processKey, processName, remark, modelContent, processForm, processSetting } = storeToRefs(flowStore)
+
+const compRefs = ref() // 实例化子组件
+const cache_components = ref({})
+const componentsArr = [
+	{
+		component: BasicInfoTab,
+		label: '基础信息',
+		value: '基础信息'
+		// ref: 'basicInfoRef'
+	},
+	{
+		component: FlowDesignTab,
+		label: '流程设计',
+		value: '流程设计'
+		// ref: 'flowDesignRef'
+	}
+]
+const activeTab = ref('基础信息')
+const removeCurTab = () => {
+	cache_components.value = {}
+	const _view = tagsView.visitedViews.find(v => v.path === '/flow_create/child')
+	if (_view)
+		tagsView.delView(_view).then(res => {
+			const latestView = res.visitedViews.slice(-1)[0]
+			if (latestView && latestView.fullPath) {
+				router.push(latestView.fullPath)
+			} else {
+				router.push('/')
+			}
+			flowStore.$reset()
+		})
+}
+const submitHandler = async () => {
+	// 基础信息
+	// 表单设计
+	// 流程设计
+	// 扩展设置
+	let leavePageFlag = await validateTabs()
+	// let _id = queryObj.value.id
+	// if (_id) {
+	//
+	// } else {
+	// 	leavePageFlag = await validateTabs()
+	// }
+	if (!leavePageFlag) return
+	const params = {
+		categoryId: categoryId.value,
+		processIcon: processIcon.value,
+		processKey: processKey.value,
+		processName: processName.value,
+		remark: remark.value,
+		processId: processId.value,
+		processForm: processForm.value,
+		modelContent: JSON.stringify({
+			key: processKey.value,
+			name: processName.value,
+			nodeConfig: JSON.parse(modelContent.value || '{}')
+		}),
+		processSetting: processSetting.value
+	}
+	const res = await process.progressCreateApi(params)
+	ElMessage.success('操作成功')
+	// 创建完成 删除 当前tab页
+	removeCurTab()
+}
+
+// 切换选项卡之前,做相应的保存操作
+const validateTabs = async () => {
+	const _refs = compRefs.value
+	// await nextTick()
+	for (let i = 0; i < _refs.length; i++) {
+		let bool = true
+		/*// 若没开启过的 tab 需要尝试 进行更新数据
+		if (!cache_components.value[i]) {
+			cache_components.value[i]?.updateCompInfo()
+		}*/
+		const _validate =
+			_refs[i]?.validate ||
+			function () {
+				return Promise.resolve()
+			}
+		await _validate().catch(e => {
+			activeTab.value = componentsArr[i].label
+			if (activeTab.value === '表单设计') {
+				ElMessage.error('请为流程设计表单内容')
+			}
+			bool = false
+		})
+		if (!bool) return false
+	}
+	return true
+}
+
+const activeComponent = index => {
+	const cur = componentsArr[index]
+	if (activeTab.value !== cur.value) {
+		if (activeTab.value === '表单设计') {
+			compRefs.value[1]?.exportJsonEv()
+		}
+		// 当前缓存
+		if (!cache_components.value[index]) {
+			// 更新数据
+			const updateCompInfo = compRefs.value[index]?.updateCompInfo
+			// console.error('刷新数据')
+			// console.error(updateCompInfo, 'updateCompInfo')
+			if (updateCompInfo) {
+				updateCompInfo()
+			}
+		}
+		activeTab.value = cur.value
+	}
+}
+
+const queryObj = computed(() => route.query)
+
+const getCurrentProcessDetailEv = () => {
+	let _id = queryObj.value.id
+	if (_id) {
+		cache_components.value = {}
+		process.processDetailApi(_id).then(res => {
+			processId.value = res.processId
+			categoryId.value = res.categoryId
+			processIcon.value = res.processIcon
+			processKey.value = res.processKey
+			processName.value = res.processName
+			remark.value = res.remark
+			let nodeConfig = JSON.parse(res.modelContent).nodeConfig
+			modelContent.value = JSON.stringify(nodeConfig)
+			processForm.value = res.processForm
+			flowStore.setProcessForm(processForm)
+			flowStore.setProcessSetting(res.processSetting)
+			// 默认执行一次保存
+			const _refs = compRefs.value
+			for (let i = 0; i < _refs.length; i++) {
+				const updateCompInfo = compRefs.value[i]?.updateCompInfo
+				if (updateCompInfo) {
+					updateCompInfo()
+				}
+			}
+		})
+	}
+}
+
+getCurrentProcessDetailEv()
+</script>
+
+<style scoped lang="scss">
+.create-approval {
+	height: 100%;
+	min-width: 1200px;
+	min-height: 600px;
+	overflow: auto;
+
+	&-header {
+		justify-content: flex-start;
+		height: 64px;
+		//z-index: 12;
+		position: relative;
+		box-shadow: 0 1px 6px 0 rgba(0, 0, 0, 0.06);
+		padding-left: 16px;
+		padding-right: 20px;
+
+		&-back {
+			display: flex;
+			justify-content: flex-start;
+			align-items: center;
+			height: 100%;
+			margin-right: 15px;
+		}
+
+		&-left-zh {
+			width: calc(50% - 316.5px);
+			min-width: 248px;
+		}
+
+		&-name {
+			font-weight: 500;
+			font-size: 16px;
+			white-space: nowrap;
+			cursor: pointer;
+			width: -webkit-fit-content;
+			width: -moz-fit-content;
+			width: fit-content;
+			max-width: 100%;
+			height: 24px;
+			overflow: hidden;
+			text-overflow: ellipsis;
+		}
+
+		&-time {
+			width: 100%;
+			height: 20px;
+			line-height: 20px;
+			font-size: 12px;
+			color: #8f959e;
+			overflow: hidden;
+			white-space: nowrap;
+			text-overflow: ellipsis;
+		}
+
+		&-tab-list {
+			margin-left: 10px;
+			flex-shrink: 0;
+			display: flex;
+			justify-content: center;
+		}
+
+		&-tab-item {
+			font-family: PingFang SC, Microsoft YaHei;
+			font-size: 18px;
+			line-height: 28px;
+			color: #646a73;
+			margin-right: 42px;
+			padding: 18px 0;
+			border-bottom: 2px solid transparent;
+			cursor: pointer;
+
+			&.active {
+				// var(--el-color-primary);
+				border-bottom-color: var(--el-color-primary);
+				color: var(--el-color-primary);
+				font-weight: 500;
+
+				.create-approval-header-tab-counter {
+					border-color: var(--el-color-primary);
+					background-color: var(--el-color-primary);
+					color: var(--el-color-white);
+					font-weight: 400;
+				}
+			}
+		}
+
+		&-tab-counter {
+			display: inline-block;
+			margin-right: 6px;
+			width: 24px;
+			height: 24px;
+			border-radius: 50%;
+			border: 1px solid #646a73;
+			font-size: 16px;
+			line-height: 22px;
+			text-align: center;
+		}
+
+		&-right {
+			flex: 1 1;
+			flex-shrink: 0;
+			display: flex;
+			justify-content: flex-end;
+			align-items: center;
+			position: relative;
+			height: 100%;
+			width: -webkit-fit-content;
+			width: -moz-fit-content;
+			width: fit-content;
+		}
+	}
+
+	&-main {
+		height: calc(100% - 64px);
+	}
+}
+</style>

+ 4 - 1
src/views/flow/group/components/listGroup.vue

@@ -48,10 +48,13 @@
 												<span>{{ element.processName }}</span>
 											</div>
 										</div>
-										<div class="group_itemIntro">{{ element.title }}</div>
+										<div class="group_itemIntro">
+											{{ element.title }}
+										</div>
 									</div>
 									<div class="group_itemSeeable">
 										<el-tag round>V{{ element.processVersion }}</el-tag>
+										<el-tag v-if="element.processType === 'child'" type="warning" round>子流程</el-tag>
 										<el-tag v-if="element.processState === 0" type="danger" round>已停用</el-tag>
 									</div>
 									<div class="group_itemSeeable">{{ element.processKey }}</div>

+ 4 - 3
src/views/flow/group/index.vue

@@ -12,7 +12,8 @@
 						<el-button type="primary" plain :icon="CircleCheck" @click="changeComponent('sort')">完 成</el-button>
 						<el-button type="info" plain @click="changeComponent">取 消</el-button>
 					</template>
-					<el-button :type="sortFlag ? 'info' : 'primary'" :icon="Plus" :disabled="sortFlag" @click="createProcessEv">创建审批</el-button>
+					<el-button icon="Plus" @click="createProcessEv('child')">创建子流程</el-button>
+					<el-button :type="sortFlag ? 'info' : 'primary'" icon="Plus" :disabled="sortFlag" @click="createProcessEv('index')">创建审批</el-button>
 				</div>
 			</el-header>
 			<div>
@@ -65,10 +66,10 @@ const searchProcess = async () => {
 	await dyncComponent.value.searchProcessEv({ keyword: keyword.value })
 }
 
-const createProcessEv = () => {
+const createProcessEv = url => {
 	flowStore.$reset()
 	setTimeout(() => {
-		router.push('/flow_create')
+		router.push('/flow_create/' + url)
 	}, 0)
 }
 </script>