فهرست منبع

feat: 流程模型分类排序功能实现、数据获取分组逻辑优化、排序状态下按钮显示逻辑控制

GoldenZqqq 10 ماه پیش
والد
کامیت
91ea4b7936
3فایلهای تغییر یافته به همراه135 افزوده شده و 296 حذف شده
  1. 63 55
      src/views/bpm/model/CategoryDraggableModel.vue
  2. 72 39
      src/views/bpm/model/index_new.vue
  3. 0 202
      src/views/bpm/model/mock.js

+ 63 - 55
src/views/bpm/model/CategoryDraggableModel.vue

@@ -1,38 +1,51 @@
 <template>
   <!-- 默认使其全部展开 -->
-  <el-collapse :modelValue="title">
-    <el-collapse-item :name="title">
+  <el-collapse v-model="activeCollapse">
+    <el-collapse-item :name="categoryInfo.id">
       <template #icon="{ isActive }">
-        <div
-          class="ml-20px flex items-center"
-          :class="['transition-transform duration-300', isActive ? 'rotate-180' : 'rotate-0']"
-        >
-          <Icon icon="ep:arrow-down-bold" color="#999" />
-        </div>
-        <div class="ml-auto mr-45px flex items-center">
-          <template v-if="!isSorting">
-            <el-button link type="info" class="mr-20px" @click.stop="handleSort">
-              <Icon icon="fa:sort-amount-desc" class="mr-5px" />
-              排序
-            </el-button>
-            <el-dropdown @command="(command) => handleCategoryCommand(command)" placement="bottom">
-              <el-button link type="info" @click.stop="handleGroup">
-                <Icon icon="ep:setting" class="mr-5px" />
-                分类
+        <div class="flex-1 flex" v-if="!isCategorySorting">
+          <div
+            class="ml-20px flex items-center"
+            :class="['transition-transform duration-300', isActive ? 'rotate-180' : 'rotate-0']"
+          >
+            <Icon icon="ep:arrow-down-bold" color="#999" />
+          </div>
+          <div class="ml-auto mr-45px flex items-center">
+            <template v-if="!isModelSorting">
+              <el-button
+                v-if="categoryInfo.modelList.length > 0"
+                link
+                type="info"
+                class="mr-20px"
+                @click.stop="handleSort"
+              >
+                <Icon icon="fa:sort-amount-desc" class="mr-5px" />
+                排序
               </el-button>
-              <template #dropdown>
-                <el-dropdown-menu>
-                  <el-dropdown-item command="handleRename"> 重命名 </el-dropdown-item>
-                  <el-dropdown-item command="handleDeleteGroup"> 删除该类 </el-dropdown-item>
-                </el-dropdown-menu>
-              </template>
-            </el-dropdown>
-          </template>
-          <template v-else>
-            <el-button @click.stop="cancelSort"> 取 消 </el-button>
-            <el-button type="primary" @click.stop="saveSort"> 保存排序 </el-button>
-          </template>
+              <el-dropdown
+                @command="(command) => handleCategoryCommand(command)"
+                placement="bottom"
+              >
+                <el-button link type="info" @click.stop="handleGroup">
+                  <Icon icon="ep:setting" class="mr-5px" />
+                  分类
+                </el-button>
+                <template #dropdown>
+                  <el-dropdown-menu>
+                    <el-dropdown-item command="handleRename"> 重命名 </el-dropdown-item>
+                    <el-dropdown-item command="handleDeleteGroup"> 删除该类 </el-dropdown-item>
+                  </el-dropdown-menu>
+                </template>
+              </el-dropdown>
+            </template>
+            <template v-else>
+              <el-button @click.stop="cancelSort"> 取 消 </el-button>
+              <el-button type="primary" @click.stop="saveSort"> 保存排序 </el-button>
+            </template>
+            <!-- <el-button v-else type="primary" @click.stop="addModel"> 新建模型 </el-button> -->
+          </div>
         </div>
+        <div></div>
       </template>
       <template #title>
         <div class="flex items-center">
@@ -43,12 +56,12 @@
               class="ml-10px category-drag-icon cursor-move text-#8a909c"
             />
           </el-tooltip>
-          <h3 class="ml-20px mr-8px text-18px">{{ title }}</h3>
-          <div class="color-gray-600 text-16px"> ({{ dataList?.length || 0 }}) </div>
+          <h3 class="ml-20px mr-8px text-18px">{{ categoryInfo.name }}</h3>
+          <div class="color-gray-600 text-16px"> ({{ categoryInfo.modelList?.length || 0 }}) </div>
         </div>
       </template>
       <el-table
-        :class="title"
+        :class="categoryInfo.name"
         ref="tableRef"
         :header-cell-style="{ backgroundColor: isDark ? '' : '#edeff0', paddingLeft: '10px' }"
         :cell-style="{ paddingLeft: '10px' }"
@@ -58,7 +71,7 @@
         <el-table-column label="流程名" prop="name" min-width="150">
           <template #default="scope">
             <div class="flex items-center">
-              <el-tooltip content="拖动排序" v-if="isSorting">
+              <el-tooltip content="拖动排序" v-if="isModelSorting">
                 <Icon
                   icon="ic:round-drag-indicator"
                   class="drag-icon cursor-move text-#8a909c mr-10px"
@@ -231,11 +244,11 @@ import { cloneDeep } from 'lodash-es'
 
 defineOptions({ name: 'BpmModel' })
 
+const activeCollapse: any = ref([])
 const renameVisible = ref(false)
 const props = defineProps({
   // 分类后的数据
-  dataList: propTypes.object.def([]),
-  title: propTypes.string.def(''),
+  categoryInfo: propTypes.object.def([]),
   isCategorySorting: propTypes.bool.def(false)
 })
 const emit = defineEmits(['success'])
@@ -245,7 +258,7 @@ const isDark = computed(() => appStore.getIsDark)
 const { t } = useI18n() // 国际化
 const { push } = useRouter() // 路由
 const userStore = useUserStoreWithOut() // 用户信息缓存
-const isSorting = ref(false) // 是否正处于排序状态
+const isModelSorting = ref(false) // 是否正处于排序状态
 const tableData: any = ref([])
 const originalData: any = ref([]) // 原始数据
 
@@ -270,7 +283,7 @@ const handleCommand = (command: string, row: any) => {
 const handleCategoryCommand = (command: string) => {
   switch (command) {
     case 'handleRename':
-      renameVal.value = props.title
+      renameVal.value = props.categoryInfo.name
       renameVisible.value = true
       break
     case 'handleDeleteGroup':
@@ -390,8 +403,8 @@ const isManagerUser = (row: any) => {
 /* 排序 */
 const handleSort = () => {
   // 保存初始数据
-  originalData.value = cloneDeep(props.dataList)
-  isSorting.value = true
+  originalData.value = cloneDeep(props.categoryInfo.modelList)
+  isModelSorting.value = true
   initSort()
 }
 
@@ -400,13 +413,13 @@ const saveSort = () => {
   console.log(tableData.value)
   // 刷新列表
   emit('success')
-  isSorting.value = false
+  isModelSorting.value = false
 }
 
 const cancelSort = () => {
   // 恢复初始数据
   tableData.value = cloneDeep(originalData.value)
-  isSorting.value = false
+  isModelSorting.value = false
 }
 
 /* 分类 */
@@ -416,7 +429,7 @@ const handleGroup = () => {
 const tableRef = ref()
 // 创建拖拽实例
 const initSort = () => {
-  const table = document.querySelector(`.${props.title} .el-table__body-wrapper tbody`)
+  const table = document.querySelector(`.${props.categoryInfo.name} .el-table__body-wrapper tbody`)
   Sortable.create(table, {
     group: 'shared',
     animation: 150,
@@ -437,7 +450,7 @@ const initSort = () => {
 
 // 更新表格数据
 const updateTableData = () => {
-  tableData.value = cloneDeep(props.dataList)
+  tableData.value = cloneDeep(props.categoryInfo.modelList)
 }
 
 const renameVal = ref('')
@@ -450,17 +463,18 @@ const handleRenameConfirm = () => {
 
 // 删除分类
 const handleDeleteGroup = async () => {
-  if (props.dataList.length > 0) {
+  if (props.categoryInfo.modelList.length > 0) {
     return message.warning('该分类下仍有流程定义,不允许删除')
   }
   await message.confirm('确认删除分类吗?')
   // 实际调用接口删除
 }
-onMounted(() => {
-  updateTableData()
-})
 
-defineExpose({ updateTableData })
+watch(() => props.categoryInfo.modelList, updateTableData, { immediate: true })
+
+defineExpose({
+  activeCollapse
+})
 </script>
 
 <style lang="scss">
@@ -476,12 +490,6 @@ defineExpose({ updateTableData })
 </style>
 <style lang="scss" scoped>
 :deep() {
-  .el-form--inline .el-form-item {
-    margin-right: 10px;
-  }
-  .el-divider--horizontal {
-    margin-top: 6px;
-  }
   .el-collapse,
   .el-collapse-item__header,
   .el-collapse-item__wrap {

+ 72 - 39
src/views/bpm/model/index_new.vue

@@ -5,7 +5,7 @@
       <!-- 搜索工作栏 -->
       <el-form
         v-if="!isCategorySorting"
-        class="-mb-15px flex"
+        class="-mb-15px flex mr-10px"
         :model="queryParams"
         ref="queryFormRef"
         :inline="true"
@@ -50,36 +50,35 @@
           </el-dropdown>
         </el-form-item>
       </el-form>
-      <template v-else>
-        <el-button type="primary" @click="cancelSort"> 取 消 </el-button>
+      <div class="mr-20px" v-else>
+        <el-button @click="cancelSort"> 取 消 </el-button>
         <el-button type="primary" @click="saveSort"> 保存排序 </el-button>
-      </template>
+      </div>
     </div>
 
     <el-divider />
 
     <!-- 分类卡片组 -->
     <div class="px-15px">
-      <ContentWrap
-        v-loading="loading"
-        :body-style="{ padding: 0 }"
-        v-for="(list, title) in categoryGroup"
-        :key="title"
-      >
-        <CategoryDraggableModel
-          ref="draggableModelRef"
-          :isCategorySorting="isCategorySorting"
-          :dataList="list"
-          :title="title"
-          @success="getList"
-        />
-      </ContentWrap>
+      <draggable v-model="categoryGroup" item-key="id" :animation="400">
+        <template #item="{ element }">
+          <ContentWrap v-loading="loading" :body-style="{ padding: 0 }" :key="element.id">
+            <CategoryDraggableModel
+              ref="categoryDraggableModelRef"
+              :isCategorySorting="isCategorySorting"
+              :categoryInfo="element"
+              @success="getAllModel"
+            />
+          </ContentWrap>
+        </template>
+      </draggable>
     </div>
   </ContentWrap>
 
   <!-- 表单弹窗:添加/修改流程 -->
-  <ModelForm ref="formRef" @success="getList" />
-
+  <ModelForm ref="formRef" @success="getAllModel" />
+  <!-- 表单弹窗:添加/修改分类 -->
+  <CategoryForm ref="categoryFormRef" @success="getList" />
   <!-- 弹窗:表单详情 -->
   <Dialog title="表单详情" v-model="formDetailVisible" width="800">
     <form-create :rule="formDetailPreview.rule" :option="formDetailPreview.option" />
@@ -87,15 +86,18 @@
 </template>
 
 <script lang="ts" setup>
+import draggable from 'vuedraggable'
+import { CategoryApi } from '@/api/bpm/category'
 import * as ModelApi from '@/api/bpm/model'
 import ModelForm from './ModelForm.vue'
-import { groupBy } from 'lodash-es'
-import { mockData } from './mock'
+import CategoryForm from '../category/CategoryForm.vue'
+import { groupBy, cloneDeep } from 'lodash-es'
 import CategoryDraggableModel from './CategoryDraggableModel.vue'
 
 defineOptions({ name: 'BpmModel' })
 
-const draggableModelRef = ref()
+const categoryDraggableModelRef = ref()
+const categoryFormRef = ref()
 const loading = ref(true) // 列表的加载中
 const isCategorySorting = ref(false) // 是否正处于排序状态
 const queryParams = reactive({
@@ -106,26 +108,32 @@ const queryParams = reactive({
   category: undefined
 })
 const queryFormRef = ref() // 搜索的表单
-const categoryGroup = ref<any>({}) // 按照category分组的数据
+const categoryGroup: any = ref([]) // 按照category分组的数据
+const originalData: any = ref([])
+// 查询所有分类数据
+const getAllCategory = async () => {
+  // TODO 芋艿:这里需要一个不分页查全部的流程分类接口
+  const data = await CategoryApi.getCategoryPage(queryParams)
+  categoryGroup.value = data.list.map((item) => ({ ...item, modelList: [] }))
+}
 
-/** 查询列表 */
-const getList = async () => {
-  loading.value = true
-  try {
-    // TODO 芋艿:这里需要一个不分页查全部的流程模型接口,并且每条数据都应包含categoryId字段,用于重命名/删除分类。
-    const data = await ModelApi.getModelPage(queryParams)
-    data.list = mockData
-    categoryGroup.value = groupBy(data.list, 'categoryName')
-    draggableModelRef.value?.updateTableData()
-  } finally {
-    loading.value = false
-  }
+/** 查询所有流程模型接口 */
+const getAllModel = async () => {
+  // TODO 芋艿:这里需要一个不分页查全部的流程模型接口
+  const data = await ModelApi.getModelPage(queryParams)
+  const groupedData = groupBy(data.list, 'categoryName')
+  Object.keys(groupedData).forEach((key) => {
+    const category = categoryGroup.value.find((item) => item.name === key)
+    if (category) {
+      category.modelList = groupedData[key]
+    }
+  })
 }
 
 /** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.pageNo = 1
-  getList()
+  getAllModel()
 }
 
 /** 添加/修改操作 */
@@ -155,21 +163,40 @@ const handleCommand = (command: string) => {
 }
 
 // 新建分类
-const handleAddCategory = () => {}
+const handleAddCategory = () => {
+  categoryFormRef.value.open('create')
+}
 // 分类排序
 const handleSort = () => {
+  // 保存初始数据
+  originalData.value = cloneDeep(categoryGroup.value)
   isCategorySorting.value = true
+  categoryDraggableModelRef.value?.forEach((element) => {
+    element.activeCollapse = []
+  })
 }
 // 取消排序
 const cancelSort = () => {
+  // 恢复初始数据
+  categoryGroup.value = cloneDeep(originalData.value)
   isCategorySorting.value = false
 }
 // 保存排序
 const saveSort = () => {}
 
+const getList = async () => {
+  loading.value = true
+  try {
+    await getAllCategory()
+    await getAllModel()
+  } finally {
+    loading.value = false
+  }
+}
+
 /** 初始化 **/
 onMounted(async () => {
-  await getList()
+  getList()
 })
 </script>
 
@@ -178,5 +205,11 @@ onMounted(async () => {
   .el-card {
     border-radius: 8px;
   }
+  .el-form--inline .el-form-item {
+    margin-right: 10px;
+  }
+  .el-divider--horizontal {
+    margin-top: 6px;
+  }
 }
 </style>

+ 0 - 202
src/views/bpm/model/mock.js

@@ -1,202 +0,0 @@
-export const mockData = [
-  {
-    key: 'out_apply',
-    name: '外出申请',
-    description: null,
-    category: '1',
-    categoryName: '测试1',
-    formType: 20,
-    formId: null,
-    formCustomCreatePath: '/OA/goingOut/create',
-    formCustomViewPath: '/OA/goingOut/detail',
-    id: 'ff8f8bab-4d4e-11ef-8201-0242ac130002',
-    formName: null,
-    createTime: 1722218716216,
-    processDefinition: {
-      id: 'out_apply:4:7f56d464-4eec-11ef-8c3a-0242ac130002',
-      version: 4,
-      deploymentTime: 1722396312641,
-      suspensionState: 1
-    }
-  },
-  {
-    key: 'contract_change_history',
-    name: '合同变更申请',
-    description: null,
-    category: '2',
-    categoryName: '测试2',
-    formType: 20,
-    formId: null,
-    formCustomCreatePath: '/project/changeRecord/detail',
-    formCustomViewPath: '/project/changeRecord/detail',
-    id: '0c689067-3a92-11ef-b7f0-0242ac130002',
-    formName: null,
-    createTime: 1720158441959,
-    processDefinition: {
-      id: 'contract_change_history:1:f69fff4f-3a9a-11ef-b7f0-0242ac130002',
-      version: 1,
-      deploymentTime: 1720162270788,
-      suspensionState: 1
-    }
-  },
-  {
-    key: 'expenses_claim',
-    name: '费用报销申请',
-    description: null,
-    category: '1',
-    categoryName: '测试1',
-    formType: 20,
-    formId: null,
-    formCustomCreatePath: '/finance/reimbursement/detail',
-    formCustomViewPath: '/finance/reimbursement/detail',
-    id: '0310ad0c-351e-11ef-a653-0242ac130002',
-    formName: null,
-    createTime: 1719558848849,
-    processDefinition: {
-      id: 'expenses_claim:5:a043a1d8-4eec-11ef-8c3a-0242ac130002',
-      version: 5,
-      deploymentTime: 1722396367911,
-      suspensionState: 1
-    }
-  },
-  {
-    key: 'out_business_apply',
-    name: '申请单',
-    description: null,
-    category: '2',
-    categoryName: '测试2',
-    formType: 20,
-    formId: null,
-    formCustomCreatePath: '/finance/businessTripApply/detail',
-    formCustomViewPath: '/finance/businessTripApply/detail',
-    id: '279e27a4-3393-11ef-8401-0242ac130002',
-    formName: null,
-    createTime: 1719389258966,
-    processDefinition: {
-      id: 'out_business_apply:9:a7b2d4e2-430f-11ef-876f-0242ac130002',
-      version: 9,
-      deploymentTime: 1721091998780,
-      suspensionState: 1
-    }
-  },
-  {
-    key: 'pms_project_delay_application',
-    name: '项目延时申请',
-    description: null,
-    category: '2',
-    categoryName: '测试2',
-    formType: 20,
-    formId: null,
-    formCustomCreatePath: '/project/workHourDelay/create',
-    formCustomViewPath: '/project/workHourDelay/detail',
-    id: '46d87275-27c7-11ef-b258-0242ac130002',
-    formName: null,
-    createTime: 1718092231234,
-    processDefinition: {
-      id: 'b7ed308a-430f-11ef-876f-0242ac130002',
-      version: 5,
-      deploymentTime: 1721092026059,
-      suspensionState: 1
-    }
-  },
-  {
-    key: 'pms_project_result_approval',
-    name: '项目成果审核',
-    description: null,
-    category: '2',
-    categoryName: '测试2',
-    formType: 20,
-    formId: null,
-    formCustomCreatePath: '/project/projectTaskResult/detail',
-    formCustomViewPath: '/project/projectTaskResult/detail',
-    id: '4a15d4f8-23cc-11ef-8dd0-0242ac130002',
-    formName: null,
-    createTime: 1717654579502,
-    processDefinition: {
-      id: 'dd3cc360-4eec-11ef-8c3a-0242ac130002',
-      version: 6,
-      deploymentTime: 1722396470232,
-      suspensionState: 1
-    }
-  },
-  {
-    key: 'pms_contract',
-    name: '合同管理',
-    description: null,
-    category: '2',
-    categoryName: '测试2',
-    formType: 20,
-    formId: null,
-    formCustomCreatePath: '/sales/contract/create',
-    formCustomViewPath: '/sales/contract/detail',
-    id: '8317cb71-0d1a-11ef-8445-70b5e844a623',
-    formName: null,
-    createTime: 1715159299146,
-    processDefinition: {
-      id: 'pms_contract:5:c7d6012a-29f2-11ef-a08d-0242ac130002',
-      version: 5,
-      deploymentTime: 1718330818270,
-      suspensionState: 1
-    }
-  },
-  {
-    key: 'pms_consult_task_act',
-    name: '咨询任务书',
-    description: null,
-    category: '1',
-    categoryName: '测试1',
-    formType: 20,
-    formId: null,
-    formCustomCreatePath: '/consultTask/create',
-    formCustomViewPath: '/consultTask/detail',
-    id: '47fad8e4-0b91-11ef-b841-70b5e844a623',
-    formName: null,
-    createTime: 1714990407756,
-    processDefinition: {
-      id: 'pms_consult_task_act:1:67c2ae59-0b91-11ef-b841-70b5e844a623',
-      version: 1,
-      deploymentTime: 1714990460960,
-      suspensionState: 1
-    }
-  },
-  {
-    key: 'pms_project',
-    name: '立项管理',
-    description: null,
-    category: '1',
-    categoryName: '测试1',
-    formType: 20,
-    formId: null,
-    formCustomCreatePath: '/project/applyProject/create',
-    formCustomViewPath: '/project/applyProject/detail',
-    id: 'f0ba6bde-0b90-11ef-b841-70b5e844a623',
-    formName: null,
-    createTime: 1714990261372,
-    processDefinition: {
-      id: 'pms_project:6:b9e4e33b-2c6c-11ef-8386-0242ac130002',
-      version: 6,
-      deploymentTime: 1718603095738,
-      suspensionState: 1
-    }
-  },
-  {
-    key: 'invoice_apply_manage',
-    name: '开票申请',
-    description: 'asdas',
-    category: '1',
-    categoryName: '测试1',
-    formType: 20,
-    formId: null,
-    formCustomCreatePath: '/sales/invoice/create',
-    formCustomViewPath: '/sales/invoice/detail',
-    id: '7ec07575-0605-11ef-ab76-cc96e508c010',
-    formName: null,
-    createTime: 1714380614292,
-    processDefinition: {
-      id: 'invoice_apply_manage:8:665a8c40-44c9-11ef-9813-0242ac130002',
-      version: 8,
-      deploymentTime: 1721281726671,
-      suspensionState: 1
-    }
-  }
-]