潘志宝
6 天以前 ca22cdd5550cfa0defb0f430c538698182cdaec1
提交 | 用户 | 时间
3e359e 1 <template>
H 2   <div class="flex items-center h-50px">
3     <!-- 头部:分类名 -->
4     <div class="flex items-center">
5       <el-tooltip content="拖动排序" v-if="isCategorySorting">
6         <Icon
7           :size="22"
8           icon="ic:round-drag-indicator"
9           class="ml-10px category-drag-icon cursor-move text-#8a909c"
10         />
11       </el-tooltip>
12       <h3 class="ml-20px mr-8px text-18px">{{ categoryInfo.name }}</h3>
13       <div class="color-gray-600 text-16px"> ({{ categoryInfo.modelList?.length || 0 }}) </div>
14     </div>
15     <!-- 头部:操作 -->
16     <div class="flex-1 flex" v-if="!isCategorySorting">
17       <div
18         v-if="categoryInfo.modelList.length > 0"
19         class="ml-20px flex items-center"
20         :class="[
21           'transition-transform duration-300 cursor-pointer',
22           isExpand ? 'rotate-180' : 'rotate-0'
23         ]"
24         @click="isExpand = !isExpand"
25       >
26         <Icon icon="ep:arrow-down-bold" color="#999" />
27       </div>
28       <div class="ml-auto flex items-center" :class="isModelSorting ? 'mr-15px' : 'mr-45px'">
29         <template v-if="!isModelSorting">
30           <el-button
31             v-if="categoryInfo.modelList.length > 0"
32             link
33             type="info"
34             class="mr-20px"
35             @click.stop="handleModelSort"
36           >
37             <Icon icon="fa:sort-amount-desc" class="mr-5px" />
38             排序
39           </el-button>
40           <el-button v-else link type="info" class="mr-20px" @click.stop="openModelForm('create')">
41             <Icon icon="fa:plus" class="mr-5px" />
42             新建
43           </el-button>
44           <el-dropdown
45             @command="(command) => handleCategoryCommand(command, categoryInfo)"
46             placement="bottom"
47           >
48             <el-button link type="info">
49               <Icon icon="ep:setting" class="mr-5px" />
50               分类
51             </el-button>
52             <template #dropdown>
53               <el-dropdown-menu>
54                 <el-dropdown-item command="handleRename"> 重命名 </el-dropdown-item>
55                 <el-dropdown-item command="handleDeleteCategory"> 删除该类 </el-dropdown-item>
56               </el-dropdown-menu>
57             </template>
58           </el-dropdown>
59         </template>
60         <template v-else>
61           <el-button @click.stop="handleModelSortCancel"> 取 消 </el-button>
62           <el-button type="primary" @click.stop="handleModelSortSubmit"> 保存排序 </el-button>
63         </template>
64       </div>
65     </div>
66   </div>
67   <!-- 模型列表 -->
68   <el-collapse-transition>
69     <div v-show="isExpand">
70       <el-table
71         :class="categoryInfo.name"
72         ref="tableRef"
73         :header-cell-style="{ backgroundColor: isDark ? '' : '#edeff0', paddingLeft: '10px' }"
74         :cell-style="{ paddingLeft: '10px' }"
75         :row-style="{ height: '68px' }"
76         :data="modelList"
77         row-key="id"
78       >
79         <el-table-column label="流程名" prop="name" min-width="150">
80           <template #default="scope">
81             <div class="flex items-center">
82               <el-tooltip content="拖动排序" v-if="isModelSorting">
83                 <Icon
84                   icon="ic:round-drag-indicator"
85                   class="drag-icon cursor-move text-#8a909c mr-10px"
86                 />
87               </el-tooltip>
88               <el-image :src="scope.row.icon" class="h-38px w-38px mr-10px rounded" />
89               {{ scope.row.name }}
90             </div>
91           </template>
92         </el-table-column>
93         <el-table-column label="可见范围" prop="startUserIds" min-width="100">
94           <template #default="scope">
95             <el-text v-if="!scope.row.startUsers || scope.row.startUsers.length === 0">
96               全部可见
97             </el-text>
98             <el-text v-else-if="scope.row.startUsers.length == 1">
99               {{ scope.row.startUsers[0].nickname }}
100             </el-text>
101             <el-text v-else>
102               <el-tooltip
103                 class="box-item"
104                 effect="dark"
105                 placement="top"
106                 :content="scope.row.startUsers.map((user: any) => user.nickname).join('、')"
107               >
108                 {{ scope.row.startUsers[0].nickname }}等 {{ scope.row.startUsers.length }} 人可见
109               </el-tooltip>
110             </el-text>
111           </template>
112         </el-table-column>
113         <el-table-column label="表单信息" prop="formType" min-width="200">
114           <template #default="scope">
115             <el-button
116               v-if="scope.row.formType === BpmModelFormType.NORMAL"
117               type="primary"
118               link
119               @click="handleFormDetail(scope.row)"
120             >
121               <span>{{ scope.row.formName }}</span>
122             </el-button>
123             <el-button
124               v-else-if="scope.row.formType === BpmModelFormType.CUSTOM"
125               type="primary"
126               link
127               @click="handleFormDetail(scope.row)"
128             >
129               <span>{{ scope.row.formCustomCreatePath }}</span>
130             </el-button>
131             <label v-else>暂无表单</label>
132           </template>
133         </el-table-column>
134         <el-table-column label="最后发布" prop="deploymentTime" min-width="250">
135           <template #default="scope">
136             <div class="flex items-center">
137               <span v-if="scope.row.processDefinition" class="w-150px">
138                 {{ formatDate(scope.row.processDefinition.deploymentTime) }}
139               </span>
140               <el-tag v-if="scope.row.processDefinition">
141                 v{{ scope.row.processDefinition.version }}
142               </el-tag>
143               <el-tag v-else type="warning">未部署</el-tag>
144               <el-tag
145                 v-if="scope.row.processDefinition?.suspensionState === 2"
146                 type="warning"
147                 class="ml-10px"
148               >
149                 已停用
150               </el-tag>
151             </div>
152           </template>
153         </el-table-column>
154         <el-table-column label="操作" width="200" fixed="right">
155           <template #default="scope">
156             <el-button
157               link
158               type="primary"
159               @click="openModelForm('update', scope.row.id)"
160               v-hasPermi="['bpm:model:update']"
161               :disabled="!isManagerUser(scope.row)"
162             >
163               修改
164             </el-button>
165             <el-button
166               link
167               class="!ml-5px"
168               type="primary"
169               @click="handleDesign(scope.row)"
170               v-hasPermi="['bpm:model:update']"
171               :disabled="!isManagerUser(scope.row)"
172             >
173               设计
174             </el-button>
175             <el-button
176               link
177               class="!ml-5px"
178               type="primary"
179               @click="handleDeploy(scope.row)"
180               v-hasPermi="['bpm:model:deploy']"
181               :disabled="!isManagerUser(scope.row)"
182             >
183               发布
184             </el-button>
185             <el-dropdown
186               class="!align-middle ml-5px"
187               @command="(command) => handleModelCommand(command, scope.row)"
188               v-hasPermi="['bpm:process-definition:query', 'bpm:model:update', 'bpm:model:delete']"
189             >
190               <el-button type="primary" link>更多</el-button>
191               <template #dropdown>
192                 <el-dropdown-menu>
193                   <el-dropdown-item
194                     command="handleDefinitionList"
195                     v-if="checkPermi(['bpm:process-definition:query'])"
196                   >
197                     历史
198                   </el-dropdown-item>
199                   <el-dropdown-item
200                     command="handleChangeState"
201                     v-if="checkPermi(['bpm:model:update']) && scope.row.processDefinition"
202                     :disabled="!isManagerUser(scope.row)"
203                   >
204                     {{ scope.row.processDefinition.suspensionState === 1 ? '停用' : '启用' }}
205                   </el-dropdown-item>
206                   <el-dropdown-item
207                     type="danger"
208                     command="handleDelete"
209                     v-if="checkPermi(['bpm:model:delete'])"
210                     :disabled="!isManagerUser(scope.row)"
211                   >
212                     删除
213                   </el-dropdown-item>
214                 </el-dropdown-menu>
215               </template>
216             </el-dropdown>
217           </template>
218         </el-table-column>
219       </el-table>
220     </div>
221   </el-collapse-transition>
222
223   <!-- 弹窗:重命名分类 -->
224   <Dialog :fullscreen="false" class="rename-dialog" v-model="renameCategoryVisible" width="400">
225     <template #title>
226       <div class="pl-10px font-bold text-18px"> 重命名分类 </div>
227     </template>
228     <div class="px-30px">
229       <el-input v-model="renameCategoryForm.name" />
230     </div>
231     <template #footer>
232       <div class="pr-25px pb-25px">
233         <el-button @click="renameCategoryVisible = false">取 消</el-button>
234         <el-button type="primary" @click="handleRenameConfirm">确 定</el-button>
235       </div>
236     </template>
237   </Dialog>
238
9259c2 239   <!-- 弹窗:表单详情 -->
H 240   <Dialog title="表单详情" v-model="formDetailVisible" width="800">
241     <form-create :rule="formDetailPreview.rule" :option="formDetailPreview.option" />
242   </Dialog>
243
3e359e 244   <!-- 表单弹窗:添加流程模型 -->
H 245   <ModelForm :categoryId="categoryInfo.code" ref="modelFormRef" @success="emit('success')" />
246 </template>
247
248 <script lang="ts" setup>
249 import ModelForm from './ModelForm.vue'
250 import { CategoryApi, CategoryVO } from '@/api/bpm/category'
251 import Sortable from 'sortablejs'
252 import { propTypes } from '@/utils/propTypes'
253 import { formatDate } from '@/utils/formatTime'
254 import * as ModelApi from '@/api/bpm/model'
255 import * as FormApi from '@/api/bpm/form'
256 import { setConfAndFields2 } from '@/utils/formCreate'
257 import { BpmModelFormType, BpmModelType } from '@/utils/constants'
258 import { checkPermi } from '@/utils/permission'
259 import { useUserStoreWithOut } from '@/store/modules/user'
260 import { useAppStore } from '@/store/modules/app'
261 import { cloneDeep } from 'lodash-es'
262
263 defineOptions({ name: 'BpmModel' })
264
265 const props = defineProps({
266   categoryInfo: propTypes.object.def([]), // 分类后的数据
267   isCategorySorting: propTypes.bool.def(false) // 是否分类在排序
268 })
269 const emit = defineEmits(['success'])
270 const message = useMessage() // 消息弹窗
271 const { t } = useI18n() // 国际化
272 const { push } = useRouter() // 路由
273 const userStore = useUserStoreWithOut() // 用户信息缓存
274 const isDark = computed(() => useAppStore().getIsDark) // 是否黑暗模式
275
276 const isModelSorting = ref(false) // 是否正处于排序状态
277 const originalData: any = ref([]) // 原始数据
278 const modelList: any = ref([]) // 模型列表
279 const isExpand = ref(false) // 是否处于展开状态
280
281 /** '更多'操作按钮 */
282 const handleModelCommand = (command: string, row: any) => {
283   switch (command) {
284     case 'handleDefinitionList':
285       handleDefinitionList(row)
286       break
287     case 'handleDelete':
288       handleDelete(row)
289       break
290     case 'handleChangeState':
291       handleChangeState(row)
292       break
293     default:
294       break
295   }
296 }
297
298 /** '分类'操作按钮 */
299 const handleCategoryCommand = async (command: string, row: any) => {
300   switch (command) {
301     case 'handleRename':
302       renameCategoryForm.value = await CategoryApi.getCategory(row.id)
303       renameCategoryVisible.value = true
304       break
305     case 'handleDeleteCategory':
306       await handleDeleteCategory()
307       break
308     default:
309       break
310   }
311 }
312
313 /** 删除按钮操作 */
314 const handleDelete = async (row: any) => {
315   try {
316     // 删除的二次确认
317     await message.delConfirm()
318     // 发起删除
319     await ModelApi.deleteModel(row.id)
320     message.success(t('common.delSuccess'))
321     // 刷新列表
322     emit('success')
323   } catch {}
324 }
325
326 /** 更新状态操作 */
327 const handleChangeState = async (row: any) => {
328   const state = row.processDefinition.suspensionState
329   const newState = state === 1 ? 2 : 1
330   try {
331     // 修改状态的二次确认
332     const id = row.id
333     debugger
334     const statusState = state === 1 ? '停用' : '启用'
335     const content = '是否确认' + statusState + '流程名字为"' + row.name + '"的数据项?'
336     await message.confirm(content)
337     // 发起修改状态
338     await ModelApi.updateModelState(id, newState)
339     message.success(statusState + '成功')
340     // 刷新列表
341     emit('success')
342   } catch {}
343 }
344
345 /** 设计流程 */
346 const handleDesign = (row: any) => {
347   if (row.type == BpmModelType.BPMN) {
348     push({
349       name: 'BpmModelEditor',
350       query: {
351         modelId: row.id
352       }
353     })
354   } else {
355     push({
356       name: 'SimpleModelDesign',
357       query: {
358         modelId: row.id
359       }
360     })
361   }
362 }
363
364 /** 发布流程 */
365 const handleDeploy = async (row: any) => {
366   try {
367     // 删除的二次确认
368     await message.confirm('是否部署该流程!!')
369     // 发起部署
370     await ModelApi.deployModel(row.id)
371     message.success(t('部署成功'))
372     // 刷新列表
373     emit('success')
374   } catch {}
375 }
376
377 /** 跳转到指定流程定义列表 */
378 const handleDefinitionList = (row: any) => {
379   push({
380     name: 'BpmProcessDefinition',
381     query: {
382       key: row.key
383     }
384   })
385 }
386
387 /** 流程表单的详情按钮操作 */
388 const formDetailVisible = ref(false)
389 const formDetailPreview = ref({
390   rule: [],
391   option: {}
392 })
393 const handleFormDetail = async (row: any) => {
394   if (row.formType == 10) {
395     // 设置表单
396     const data = await FormApi.getForm(row.formId)
397     setConfAndFields2(formDetailPreview, data.conf, data.fields)
398     // 弹窗打开
399     formDetailVisible.value = true
400   } else {
401     await push({
402       path: row.formCustomCreatePath
403     })
404   }
405 }
406
407 /** 判断是否可以操作 */
408 const isManagerUser = (row: any) => {
409   const userId = userStore.getUser.id
410   return row.managerUserIds && row.managerUserIds.includes(userId)
411 }
412
413 /** 处理模型的排序 **/
414 const handleModelSort = () => {
415   // 保存初始数据
416   originalData.value = cloneDeep(props.categoryInfo.modelList)
417   isModelSorting.value = true
418   initSort()
419 }
420
421 /** 处理模型的排序提交 */
422 const handleModelSortSubmit = async () => {
423   // 保存排序
424   const ids = modelList.value.map((item: any) => item.id)
425   await ModelApi.updateModelSortBatch(ids)
426   // 刷新列表
427   isModelSorting.value = false
428   message.success('排序模型成功')
429   emit('success')
430 }
431
432 /** 处理模型的排序取消 */
433 const handleModelSortCancel = () => {
434   // 恢复初始数据
435   modelList.value = cloneDeep(originalData.value)
436   isModelSorting.value = false
437 }
438
439 /** 创建拖拽实例 */
440 const tableRef = ref()
441 const initSort = () => {
442   const table = document.querySelector(`.${props.categoryInfo.name} .el-table__body-wrapper tbody`)
443   Sortable.create(table, {
444     group: 'shared',
445     animation: 150,
446     draggable: '.el-table__row',
447     handle: '.drag-icon',
448     // 结束拖动事件
449     onEnd: ({ newDraggableIndex, oldDraggableIndex }) => {
450       if (oldDraggableIndex !== newDraggableIndex) {
451         modelList.value.splice(
452           newDraggableIndex,
453           0,
454           modelList.value.splice(oldDraggableIndex, 1)[0]
455         )
456       }
457     }
458   })
459 }
460
461 /** 更新 modelList 模型列表 */
462 const updateModeList = () => {
463   modelList.value = cloneDeep(props.categoryInfo.modelList)
464   if (props.categoryInfo.modelList.length > 0) {
465     isExpand.value = true
466   }
467 }
468
469 /** 重命名弹窗确定 */
470 const renameCategoryVisible = ref(false)
471 const renameCategoryForm = ref({
472   name: ''
473 })
474 const handleRenameConfirm = async () => {
475   if (renameCategoryForm.value?.name.length === 0) {
476     return message.warning('请输入名称')
477   }
478   // 发起修改
479   await CategoryApi.updateCategory(renameCategoryForm.value as CategoryVO)
480   message.success('重命名成功')
481   // 刷新列表
482   renameCategoryVisible.value = false
483   emit('success')
484 }
485
486 /** 删除分类 */
487 const handleDeleteCategory = async () => {
488   try {
489     if (props.categoryInfo.modelList.length > 0) {
490       return message.warning('该分类下仍有流程定义,不允许删除')
491     }
492     await message.confirm('确认删除分类吗?')
493     // 发起删除
494     await CategoryApi.deleteCategory(props.categoryInfo.id)
495     message.success(t('common.delSuccess'))
496     // 刷新列表
497     emit('success')
498   } catch {}
499 }
500
501 /** 添加流程模型弹窗 */
502 const modelFormRef = ref()
503 const openModelForm = (type: string, id?: number) => {
504   modelFormRef.value.open(type, id)
505 }
506
507 watch(() => props.categoryInfo.modelList, updateModeList, { immediate: true })
508 watch(
509   () => props.isCategorySorting,
510   (val) => {
511     if (val) isExpand.value = false
512   },
513   { immediate: true }
514 )
515 </script>
516
517 <style lang="scss">
518 .rename-dialog.el-dialog {
519   padding: 0 !important;
520
521   .el-dialog__header {
522     border-bottom: none;
523   }
524
525   .el-dialog__footer {
526     border-top: none !important;
527   }
528 }
529 </style>
530 <style lang="scss" scoped>
531 :deep() {
532   .el-table__cell {
533     overflow: hidden;
534     border-bottom: none !important;
535   }
536 }
537 </style>