Browse Source

feat: 发起审批 备选列表选择支持

lanceJiang 5 months ago
parent
commit
fc9c210d76
2 changed files with 222 additions and 137 deletions
  1. 197 119
      src/components/scWorkflow/select.vue
  2. 25 18
      src/views/approve/launch/ItemDrawer.vue

+ 197 - 119
src/components/scWorkflow/select.vue

@@ -8,133 +8,182 @@
 		append-to-body
 		@closed="$emit('closed')"
 	>
-		<template v-if="type === 1">
-			<div class="sc-user-select">
-				<div class="sc-user-select__left">
-					<div class="sc-user-select__search">
-						<el-input v-model="username" prefix-icon="Search" placeholder="搜索成员">
-							<template #append>
-								<el-button icon="Search" @click="search"></el-button>
-							</template>
-						</el-input>
-					</div>
-					<div class="sc-user-select__select">
-						<div v-loading="showGrouploading" class="sc-user-select__tree">
-							<el-scrollbar>
-								<el-tree
-									ref="groupTree"
-									class="menu"
-									:data="group"
-									:node-key="groupProps.key"
-									:props="groupProps"
-									highlight-current
-									:expand-on-click-node="false"
-									:current-node-key="groupId"
-									@node-click="groupClick"
-								/>
-							</el-scrollbar>
-						</div>
-						<div v-loading="showUserloading" class="sc-user-select__user">
-							<div class="sc-user-select__user__list">
-								<el-scrollbar ref="userScrollbar">
+		<template v-if="[1, 3].includes(type)">
+			<template v-if="nodeCandidates.length">
+				<div class="sc-user-select sc-user-select-role">
+					<div class="sc-user-select__left" style="flex: 1">
+						<div class="sc-user-select__select">
+							<div class="sc-user-select__tree">
+								<el-scrollbar>
 									<el-tree
-										ref="userTree"
+										ref="nodeCandidatesTree"
 										class="menu"
-										:data="user"
-										:node-key="userProps.key"
-										:props="userProps"
-										:default-checked-keys="selectedIds"
+										:data="nodeCandidates"
+										:node-key="nodeCandidatesProps.key"
+										:props="nodeCandidatesProps"
 										show-checkbox
+										check-strictly
 										check-on-click-node
-										@check-change="userClick"
-									></el-tree>
+										:expand-on-click-node="false"
+										:default-checked-keys="selectedIds"
+										@check-change="assigneesClick"
+									/>
 								</el-scrollbar>
 							</div>
-							<footer>
-								<el-pagination
-									v-model:currentPage="currentPage"
-									background
-									layout="prev,next"
-									small
-									:total="total"
-									:page-size="pageSize"
-									@current-change="paginationChange"
-								></el-pagination>
-							</footer>
 						</div>
 					</div>
-				</div>
-				<div class="sc-user-select__toicon">
-					<el-icon><arrow-right /></el-icon>
-				</div>
-				<div class="sc-user-select__selected">
-					<header>已选 ({{ selected.length }})</header>
-					<ul style="margin: 0; padding: 0">
-						<el-scrollbar>
-							<li v-for="(item, index) in selected" :key="item.id">
-								<span class="name">
-									<el-avatar class="shrink-0" size="small">{{ item.name?.substring(0, 1) }}</el-avatar>
-									<le-text :value="item.name || '-'"></le-text>
-								</span>
-								<span class="actions">
-									<el-button v-if="index !== 0" icon="ArrowUp" circle size="small" @click="sortItem(index, 'up')" />
-									<el-button v-if="index !== selected.length - 1" icon="ArrowDown" circle size="small" @click="sortItem(index, 'down')" />
-									<el-button type="danger" icon="Delete" circle size="small" @click="deleteSelected(index)" />
-								</span>
-							</li>
-						</el-scrollbar>
-					</ul>
-				</div>
-			</div>
-		</template>
-
-		<template v-if="type === 3">
-			<div class="sc-user-select sc-user-select-role">
-				<div class="sc-user-select__left">
-					<div class="sc-user-select__select">
-						<div v-loading="showGrouploading" class="sc-user-select__tree">
+					<div class="sc-user-select__toicon">
+						<el-icon><ArrowRight /></el-icon>
+					</div>
+					<div class="sc-user-select__selected">
+						<header>已选 ({{ selected.length }})</header>
+						<ul style="padding: 0; margin: 0">
 							<el-scrollbar>
-								<el-tree
-									ref="groupTree"
-									class="menu"
-									:data="role"
-									:node-key="roleProps.key"
-									:props="roleProps"
-									show-checkbox
-									check-strictly
-									check-on-click-node
-									:expand-on-click-node="false"
-									:default-checked-keys="selectedIds"
-									@check-change="roleClick"
-								/>
+								<li v-for="(item, index) in selected" :key="item.id">
+									<span class="name">
+										<le-text :value="item.name || '-'"></le-text>
+									</span>
+									<span class="actions">
+										<el-button v-if="index !== 0" icon="ArrowUp" circle size="small" @click="sortItem(index, 'up')" />
+										<el-button v-if="index !== selected.length - 1" icon="ArrowDown" circle size="small" @click="sortItem(index, 'down')" />
+										<el-button type="danger" icon="Delete" circle size="small" @click="deleteSelected(index)" />
+									</span>
+								</li>
 							</el-scrollbar>
-						</div>
+						</ul>
 					</div>
 				</div>
-				<div class="sc-user-select__toicon">
-					<el-icon><ArrowRight /></el-icon>
-				</div>
-				<div class="sc-user-select__selected">
-					<header>已选 ({{ selected.length }})</header>
-					<ul style="padding: 0; margin: 0">
-						<el-scrollbar>
-							<li v-for="(item, index) in selected" :key="item.id">
-								<span class="name">
-									<le-text :value="item.name || '-'"></le-text>
-								</span>
-								<span class="actions">
-									<el-button v-if="index !== 0" icon="ArrowUp" circle size="small" @click="sortItem(index, 'up')" />
-									<el-button v-if="index !== selected.length - 1" icon="ArrowDown" circle size="small" @click="sortItem(index, 'down')" />
-									<el-button type="danger" icon="Delete" circle size="small" @click="deleteSelected(index)" />
-								</span>
-							</li>
-						</el-scrollbar>
-					</ul>
-				</div>
-			</div>
+			</template>
+			<template v-else>
+				<template v-if="type === 1">
+					<div class="sc-user-select">
+						<div class="sc-user-select__left">
+							<div class="sc-user-select__search">
+								<el-input v-model="username" prefix-icon="Search" placeholder="搜索成员">
+									<template #append>
+										<el-button icon="Search" @click="search"></el-button>
+									</template>
+								</el-input>
+							</div>
+							<div class="sc-user-select__select">
+								<div v-loading="showGrouploading" class="sc-user-select__tree">
+									<el-scrollbar>
+										<el-tree
+											ref="groupTree"
+											class="menu"
+											:data="group"
+											:node-key="groupProps.key"
+											:props="groupProps"
+											highlight-current
+											:expand-on-click-node="false"
+											:current-node-key="groupId"
+											@node-click="groupClick"
+										/>
+									</el-scrollbar>
+								</div>
+								<div v-loading="showUserloading" class="sc-user-select__user">
+									<div class="sc-user-select__user__list">
+										<el-scrollbar ref="userScrollbar">
+											<el-tree
+												ref="userTree"
+												class="menu"
+												:data="user"
+												:node-key="userProps.key"
+												:props="userProps"
+												:default-checked-keys="selectedIds"
+												show-checkbox
+												check-on-click-node
+												@check-change="userClick"
+											></el-tree>
+										</el-scrollbar>
+									</div>
+									<footer>
+										<el-pagination
+											v-model:currentPage="currentPage"
+											background
+											layout="prev,next"
+											small
+											:total="total"
+											:page-size="pageSize"
+											@current-change="paginationChange"
+										></el-pagination>
+									</footer>
+								</div>
+							</div>
+						</div>
+						<div class="sc-user-select__toicon">
+							<el-icon><arrow-right /></el-icon>
+						</div>
+						<div class="sc-user-select__selected">
+							<header>已选 ({{ selected.length }})</header>
+							<ul style="margin: 0; padding: 0">
+								<el-scrollbar>
+									<li v-for="(item, index) in selected" :key="item.id">
+										<span class="name">
+											<el-avatar class="shrink-0" size="small">{{ item.name?.substring(0, 1) }}</el-avatar>
+											<le-text :value="item.name || '-'"></le-text>
+										</span>
+										<span class="actions">
+											<el-button v-if="index !== 0" icon="ArrowUp" circle size="small" @click="sortItem(index, 'up')" />
+											<el-button v-if="index !== selected.length - 1" icon="ArrowDown" circle size="small" @click="sortItem(index, 'down')" />
+											<el-button type="danger" icon="Delete" circle size="small" @click="deleteSelected(index)" />
+										</span>
+									</li>
+								</el-scrollbar>
+							</ul>
+						</div>
+					</div>
+				</template>
+
+				<template v-else-if="type === 3">
+					<div class="sc-user-select sc-user-select-role">
+						<div class="sc-user-select__left">
+							<div class="sc-user-select__select">
+								<div v-loading="showGrouploading" class="sc-user-select__tree">
+									<el-scrollbar>
+										<el-tree
+											ref="groupTree"
+											class="menu"
+											:data="role"
+											:node-key="roleProps.key"
+											:props="roleProps"
+											show-checkbox
+											check-strictly
+											check-on-click-node
+											:expand-on-click-node="false"
+											:default-checked-keys="selectedIds"
+											@check-change="roleClick"
+										/>
+									</el-scrollbar>
+								</div>
+							</div>
+						</div>
+						<div class="sc-user-select__toicon">
+							<el-icon><ArrowRight /></el-icon>
+						</div>
+						<div class="sc-user-select__selected">
+							<header>已选 ({{ selected.length }})</header>
+							<ul style="padding: 0; margin: 0">
+								<el-scrollbar>
+									<li v-for="(item, index) in selected" :key="item.id">
+										<span class="name">
+											<le-text :value="item.name || '-'"></le-text>
+										</span>
+										<span class="actions">
+											<el-button v-if="index !== 0" icon="ArrowUp" circle size="small" @click="sortItem(index, 'up')" />
+											<el-button v-if="index !== selected.length - 1" icon="ArrowDown" circle size="small" @click="sortItem(index, 'down')" />
+											<el-button type="danger" icon="Delete" circle size="small" @click="deleteSelected(index)" />
+										</span>
+									</li>
+								</el-scrollbar>
+							</ul>
+						</div>
+					</div>
+				</template>
+			</template>
 		</template>
 
-		<template v-if="type === 5">
+		<template v-else-if="type === 5">
 			<div class="sc-user-select">
 				<div class="sc-user-select__left">
 					<div class="sc-user-select__search">
@@ -232,7 +281,11 @@ export default {
 	props: {
 		modelValue: { type: Boolean, default: false },
 		minSelected: { type: Number, default: 0 },
-		maxSelected: { type: Number, default: 999999 }
+		maxSelected: { type: Number, default: 999999 },
+		// 候选数据列表
+		candidateAssignees: {
+			type: Array // as {name, id}[]
+		}
 	},
 	data() {
 		return {
@@ -250,6 +303,10 @@ export default {
 				label: 'name',
 				children: 'children'
 			},
+			nodeCandidatesProps: {
+				key: 'id',
+				label: 'name'
+			},
 			formCategoryProps: {
 				key: 'id',
 				label: 'name',
@@ -292,6 +349,9 @@ export default {
 				3: '角色选择',
 				5: '表单分类选择'
 			}[this.type]
+		},
+		nodeCandidates() {
+			return this.candidateAssignees || []
 		}
 	},
 	mounted() {},
@@ -303,7 +363,10 @@ export default {
 			this.value = JSON.parse(JSON.stringify(data || []))
 			this.selected = JSON.parse(JSON.stringify(data || []))
 			this.dialogVisible = true
-
+			// 人员/角色 且有候选数据列表 不做数据查询
+			if ([1, 3].includes(this.type) && this.nodeCandidates.length) {
+				return
+			}
 			if (this.type === 1) {
 				this.getGroup()
 				this.getUser()
@@ -412,10 +475,14 @@ export default {
 		//删除已选
 		deleteSelected(index) {
 			this.selected.splice(index, 1)
-			if (this.type === 1) {
-				this.$refs.userTree.setCheckedKeys(this.selectedIds)
-			} else if (this.type === 3) {
-				this.$refs.groupTree.setCheckedKeys(this.selectedIds)
+			if ([1, 3].includes(this.type)) {
+				// 选择 候选数据
+				let refKey = 'nodeCandidatesTree'
+				if (!this.nodeCandidates.length) {
+					// 选择人 | 角色
+					refKey = this.type === 1 ? 'userTree' : 'groupTree'
+				}
+				this.$refs[refKey].setCheckedKeys(this.selectedIds)
 			} else if (this.type === 5) {
 				this.$refs.formTemplateTree.setCheckedKeys(this.selectedIds)
 			}
@@ -431,6 +498,17 @@ export default {
 				this.selected = this.selected.filter(item => item.id != data.id)
 			}
 		},
+		//角色点击
+		assigneesClick(data, checked) {
+			if (checked) {
+				this.selected.push({
+					id: data.id,
+					name: data.name
+				})
+			} else {
+				this.selected = this.selected.filter(item => item.id != data.id)
+			}
+		},
 		//提交保存
 		save() {
 			this.value.splice(0, this.value.length)

+ 25 - 18
src/views/approve/launch/ItemDrawer.vue

@@ -86,32 +86,36 @@ const emit = defineEmits<{
 	update: [value: string]
 }>()
 const updateModelValue = (bool: boolean) => emit('update:modelValue', bool)
-type Assignee = {
+type Assignee = { name: string; id: string }
+type AssigneeSelectOpts = {
+	minSelected?: number
+	maxSelected?: number
+	candidateAssignees?: Assignee[]
+}
+type AssigneeItem = {
 	type: 1 | 3 // 1: 用户 3: 角色
-	assignees: { [key: string]: any /*name, id*/ }
+	assignees: Assignee[]
 	disabled?: boolean
-	selectOpts?: any
-	// minSelected?: number
-	// maxSelected?: number
+	selectOpts?: AssigneeSelectOpts
 }
 const useSelectRef = ref()
 const assigneeMap = ref<{
-	[key: string]: Assignee
+	[key: string]: AssigneeItem
 }>({})
 const assigneeDesc = ref<{
 	[key: string]: string
 }>({})
 const active_assigneeKey = ref<string>()
-const active_selectOpts = ref({})
-const updateActive_assigneeMap = (assignees: any[]) => {
-	const _cur = assigneeMap.value[active_assigneeKey.value]
+const active_selectOpts = ref<AssigneeSelectOpts>({})
+const updateActive_assigneeMap = (assignees: Assignee[]) => {
+	const _cur = assigneeMap.value[active_assigneeKey.value] as AssigneeItem
 	if (_cur) {
 		_cur.assignees = assignees
 	}
 }
 const selectHandler = (nodeKey: string, type: 1 | 3) => {
 	if (!assigneeMap.value[nodeKey]) {
-		assigneeMap.value[nodeKey] = { assignees: [], type }
+		assigneeMap.value[nodeKey] = { assignees: [], type } as AssigneeItem
 	}
 	const config = assigneeMap.value[nodeKey]
 	active_assigneeKey.value = nodeKey
@@ -170,8 +174,8 @@ let cur_processForm_str = '{}'
 let cur_formStructure = {}
 const processChecked = reactive<{ [nodeKey: string]: any }>({})
 const modelContentConfig = ref<ModelContentConfig | any>({})
-const packageProcess = (data: ModelContentConfig, list = []) => {
-	const new_list = [data]
+const packageProcess = (data: ModelContentConfig, list: ModelContentConfig[] = []) => {
+	const new_list: ModelContentConfig[] = [data]
 	let curData = data
 	while (curData.childNode) {
 		new_list.push(curData.childNode)
@@ -203,7 +207,7 @@ const packageProcess = (data: ModelContentConfig, list = []) => {
 			}
 		} else {
 			// console.log(config.nodeName, 'nodeName 普通节点名称', config, data)
-			// 0,发起人 1,审批人 2,抄送人 3,条件审批 4,条件分支 5,办理子流程 6,定时器在务 7,触发器在务
+			// 0:发起人 1:审批人 2:抄送人 3:条件审批 4:条件分支 5:办理子流程 6:定时器在务 7:触发器在务 8:并行路由 9:包容路由 10:路由分支
 			switch (+config.type) {
 				case 0: {
 					// 发起人
@@ -216,10 +220,10 @@ const packageProcess = (data: ModelContentConfig, list = []) => {
 					if (Reflect.has(config, 'setType')) {
 						let disabled = false
 						let selectOpts = {}
-						const user_fn = () => {
+						const user_fn = (type: 1 | 3 = 1) => {
 							const _key = config.nodeKey
 							if (!assigneeMap.value[_key]) {
-								assigneeMap.value[_key] = { assignees: config.nodeAssigneeList, type: 1, disabled, selectOpts }
+								assigneeMap.value[_key] = { assignees: config.nodeAssigneeList, type, disabled, selectOpts }
 							}
 						}
 						switch (config.setType) {
@@ -240,12 +244,15 @@ const packageProcess = (data: ModelContentConfig, list = []) => {
 								}
 								break
 							case 4:
-								// 发起人自选 (1: 选择一个人, 2: 选择多个人)
+								// 发起人自选 (1: 选择一个人, 2: 选择多个人 3: 自选角色)
 								// const isMultiple = config.selectMode === 2
+								let type = 1
 								if (config.selectMode === 1) {
 									selectOpts = { maxSelected: 1 }
 								}
-								user_fn()
+								// 插入备选列表 candidateAssignees
+								selectOpts = { ...selectOpts, candidateAssignees: config.nodeCandidate?.assignees }
+								user_fn(config.selectMode === 3 ? 3 : 1)
 								break
 							case 5: // 发起人自己 (不能选择)
 								assigneeDesc.value[config.nodeKey] = setTypeOptions_config[5]
@@ -296,7 +303,7 @@ const packageProcess = (data: ModelContentConfig, list = []) => {
 			_list.push(config)
 		}
 		return _list
-	}, list)
+	}, list as ModelContentConfig[])
 }
 const processTimelineList = computed(() => {
 	return packageProcess(modelContentConfig.value)