Преглед изворни кода

feat: 流程模型列表UI重构以及数组分类分组展示逻辑

GoldenZqqq пре 10 месеци
родитељ
комит
c49e8bd3f9
4 измењених фајлова са 638 додато и 803 уклоњено
  1. 206 197
      src/views/bpm/model/index.vue
  2. 432 0
      src/views/bpm/model/index_new.vue
  3. 0 404
      src/views/bpm/model/index_old.vue
  4. 0 202
      src/views/bpm/model/mock.js

+ 206 - 197
src/views/bpm/model/index.vue

@@ -1,192 +1,211 @@
 <template>
+  <doc-alert title="流程设计器(BPMN)" url="https://doc.iocoder.cn/bpm/model-designer-dingding/" />
+  <doc-alert
+    title="流程设计器(钉钉、飞书)"
+    url="https://doc.iocoder.cn/bpm/model-designer-bpmn/"
+  />
+  <doc-alert title="选择审批人、发起人自选" url="https://doc.iocoder.cn/bpm/assignee/" />
+  <doc-alert title="会签、或签、依次审批" url="https://doc.iocoder.cn/bpm/multi-instance/" />
+
+  <ContentWrap>
+    <!-- 搜索工作栏 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="68px"
+    >
+      <el-form-item label="流程标识" prop="key">
+        <el-input
+          v-model="queryParams.key"
+          placeholder="请输入流程标识"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="流程名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入流程名称"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="流程分类" prop="category">
+        <el-select
+          v-model="queryParams.category"
+          placeholder="请选择流程分类"
+          clearable
+          class="!w-240px"
+        >
+          <el-option
+            v-for="category in categoryList"
+            :key="category.code"
+            :label="category.name"
+            :value="category.code"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+        <el-button
+          type="primary"
+          plain
+          @click="openForm('create')"
+          v-hasPermi="['bpm:model:create']"
+        >
+          <Icon icon="ep:plus" class="mr-5px" /> 新建
+        </el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
   <ContentWrap>
-    <div class="flex justify-between pl-20px items-center">
-      <h3>表单管理</h3>
-      <!-- 搜索工作栏 -->
-      <el-form
-        class="-mb-15px flex"
-        :model="queryParams"
-        ref="queryFormRef"
-        :inline="true"
-        label-width="68px"
-      >
-        <el-form-item align="right" prop="key" class="ml-auto">
-          <el-input
-            v-model="queryParams.key"
-            placeholder="搜索流程"
-            clearable
-            @keyup.enter="handleQuery"
-            class="!w-240px"
+    <el-table v-loading="loading" :data="list">
+      <el-table-column label="流程名称" align="center" prop="name" min-width="200" />
+      <el-table-column label="流程图标" align="center" prop="icon" min-width="100">
+        <template #default="scope">
+          <el-image :src="scope.row.icon" class="h-32px w-32px" />
+        </template>
+      </el-table-column>
+      <el-table-column label="可见范围" align="center" prop="startUserIds" min-width="100">
+        <template #default="scope">
+          <el-text v-if="!scope.row.startUsers || scope.row.startUsers.length === 0">
+            全部可见
+          </el-text>
+          <el-text v-else-if="scope.row.startUsers.length == 1">
+            {{ scope.row.startUsers[0].nickname }}
+          </el-text>
+          <el-text v-else>
+            <el-tooltip
+              class="box-item"
+              effect="dark"
+              placement="top"
+              :content="scope.row.startUsers.map((user: any) => user.nickname).join('、')"
+            >
+              {{ scope.row.startUsers[0].nickname }}等 {{ scope.row.startUsers.length }} 人可见
+            </el-tooltip>
+          </el-text>
+        </template>
+      </el-table-column>
+      <el-table-column label="流程分类" align="center" prop="categoryName" min-width="100" />
+      <el-table-column label="表单信息" align="center" prop="formType" min-width="200">
+        <template #default="scope">
+          <el-button
+            v-if="scope.row.formType === 10"
+            type="primary"
+            link
+            @click="handleFormDetail(scope.row)"
           >
-            <template #prefix>
-              <Icon icon="ep:search" class="mx-10px" />
-            </template>
-          </el-input>
-        </el-form-item>
-        <el-form-item>
-          <el-button type="primary" @click="openForm('create')" v-hasPermi="['bpm:model:create']">
-            <Icon icon="ep:plus" class="mr-5px" /> 新建流程
+            <span>{{ scope.row.formName }}</span>
           </el-button>
-        </el-form-item>
-
-        <el-form-item>
-          <el-button type="info" plain>
-            <Icon icon="ep:setting" />
+          <el-button
+            v-else-if="scope.row.formType === 20"
+            type="primary"
+            link
+            @click="handleFormDetail(scope.row)"
+          >
+            <span>{{ scope.row.formCustomCreatePath }}</span>
           </el-button>
-        </el-form-item>
-      </el-form>
-    </div>
-
-    <el-divider />
-
-    <!-- 分类卡片组 -->
-    <div class="px-30px">
-      <ContentWrap v-for="(list, title) in categoryGroup" :key="title">
-        <div class="flex items-center mb-20px">
-          <h3 class="ml-20px mr-8px">{{ title }}</h3>
-          <div class="text-[var(--el-text-color-placeholder)]">({{ list?.length || 0 }})</div>
-        </div>
-        <el-table v-loading="loading" :data="list">
-          <el-table-column label="流程名" align="center" prop="name" min-width="200">
-            <template #default="scope">
-              <div class="flex items-center">
-                <el-image :src="scope.row.icon" class="h-32px w-32px mr-10px rounded" />
-                {{ scope.row.name }}
-              </div>
-            </template>
-          </el-table-column>
-          <el-table-column label="可见范围" align="center" prop="startUserIds" min-width="100">
-            <template #default="scope">
-              <el-text v-if="!scope.row.startUsers || scope.row.startUsers.length === 0">
-                全部可见
-              </el-text>
-              <el-text v-else-if="scope.row.startUsers.length == 1">
-                {{ scope.row.startUsers[0].nickname }}
-              </el-text>
-              <el-text v-else>
-                <el-tooltip
-                  class="box-item"
-                  effect="dark"
-                  placement="top"
-                  :content="scope.row.startUsers.map((user: any) => user.nickname).join('、')"
+          <label v-else>暂无表单</label>
+        </template>
+      </el-table-column>
+      <el-table-column label="最后发布" align="center" prop="deploymentTime" min-width="250">
+        <template #default="scope">
+          <span v-if="scope.row.processDefinition">
+            {{ formatDate(scope.row.processDefinition.deploymentTime) }}
+          </span>
+          <el-tag v-if="scope.row.processDefinition" class="ml-10px">
+            v{{ scope.row.processDefinition.version }}
+          </el-tag>
+          <el-tag v-else type="warning">未部署</el-tag>
+          <el-tag
+            v-if="scope.row.processDefinition?.suspensionState === 2"
+            type="warning"
+            class="ml-10px"
+          >
+            已停用
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" width="200" fixed="right">
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openForm('update', scope.row.id)"
+            v-hasPermi="['bpm:model:update']"
+            :disabled="!isManagerUser(scope.row)"
+          >
+            修改
+          </el-button>
+          <el-button
+            link
+            class="!ml-5px"
+            type="primary"
+            @click="handleDesign(scope.row)"
+            v-hasPermi="['bpm:model:update']"
+            :disabled="!isManagerUser(scope.row)"
+          >
+            设计
+          </el-button>
+          <el-button
+            link
+            class="!ml-5px"
+            type="primary"
+            @click="handleDeploy(scope.row)"
+            v-hasPermi="['bpm:model:deploy']"
+            :disabled="!isManagerUser(scope.row)"
+          >
+            发布
+          </el-button>
+          <el-dropdown
+            class="!align-middle ml-5px"
+            @command="(command) => handleCommand(command, scope.row)"
+            v-hasPermi="['bpm:process-definition:query', 'bpm:model:update', 'bpm:model:delete']"
+          >
+            <el-button type="primary" link>更多</el-button>
+            <template #dropdown>
+              <el-dropdown-menu>
+                <el-dropdown-item
+                  command="handleDefinitionList"
+                  v-if="checkPermi(['bpm:process-definition:query'])"
                 >
-                  {{ scope.row.startUsers[0].nickname }}等 {{ scope.row.startUsers.length }} 人可见
-                </el-tooltip>
-              </el-text>
-            </template>
-          </el-table-column>
-          <el-table-column label="流程分类" align="center" prop="categoryName" min-width="100" />
-          <el-table-column label="表单信息" align="center" prop="formType" min-width="200">
-            <template #default="scope">
-              <el-button
-                v-if="scope.row.formType === 10"
-                type="primary"
-                link
-                @click="handleFormDetail(scope.row)"
-              >
-                <span>{{ scope.row.formName }}</span>
-              </el-button>
-              <el-button
-                v-else-if="scope.row.formType === 20"
-                type="primary"
-                link
-                @click="handleFormDetail(scope.row)"
-              >
-                <span>{{ scope.row.formCustomCreatePath }}</span>
-              </el-button>
-              <label v-else>暂无表单</label>
-            </template>
-          </el-table-column>
-          <el-table-column label="最后发布" align="center" prop="deploymentTime" min-width="250">
-            <template #default="scope">
-              <span v-if="scope.row.processDefinition">
-                {{ formatDate(scope.row.processDefinition.deploymentTime) }}
-              </span>
-              <el-tag v-if="scope.row.processDefinition" class="ml-10px">
-                v{{ scope.row.processDefinition.version }}
-              </el-tag>
-              <el-tag v-else type="warning">未部署</el-tag>
-              <el-tag
-                v-if="scope.row.processDefinition?.suspensionState === 2"
-                type="warning"
-                class="ml-10px"
-              >
-                已停用
-              </el-tag>
-            </template>
-          </el-table-column>
-          <el-table-column label="操作" align="center" width="200" fixed="right">
-            <template #default="scope">
-              <el-button
-                link
-                type="primary"
-                @click="openForm('update', scope.row.id)"
-                v-hasPermi="['bpm:model:update']"
-                :disabled="!isManagerUser(scope.row)"
-              >
-                修改
-              </el-button>
-              <el-button
-                link
-                class="!ml-5px"
-                type="primary"
-                @click="handleDesign(scope.row)"
-                v-hasPermi="['bpm:model:update']"
-                :disabled="!isManagerUser(scope.row)"
-              >
-                设计
-              </el-button>
-              <el-button
-                link
-                class="!ml-5px"
-                type="primary"
-                @click="handleDeploy(scope.row)"
-                v-hasPermi="['bpm:model:deploy']"
-                :disabled="!isManagerUser(scope.row)"
-              >
-                发布
-              </el-button>
-              <el-dropdown
-                class="!align-middle ml-5px"
-                @command="(command) => handleCommand(command, scope.row)"
-                v-hasPermi="[
-                  'bpm:process-definition:query',
-                  'bpm:model:update',
-                  'bpm:model:delete'
-                ]"
-              >
-                <el-button type="primary" link>更多</el-button>
-                <template #dropdown>
-                  <el-dropdown-menu>
-                    <el-dropdown-item
-                      command="handleDefinitionList"
-                      v-if="checkPermi(['bpm:process-definition:query'])"
-                    >
-                      历史
-                    </el-dropdown-item>
-                    <el-dropdown-item
-                      command="handleChangeState"
-                      v-if="checkPermi(['bpm:model:update']) && scope.row.processDefinition"
-                      :disabled="!isManagerUser(scope.row)"
-                    >
-                      {{ scope.row.processDefinition.suspensionState === 1 ? '停用' : '启用' }}
-                    </el-dropdown-item>
-                    <el-dropdown-item
-                      type="danger"
-                      command="handleDelete"
-                      v-if="checkPermi(['bpm:model:delete'])"
-                      :disabled="!isManagerUser(scope.row)"
-                    >
-                      删除
-                    </el-dropdown-item>
-                  </el-dropdown-menu>
-                </template>
-              </el-dropdown>
+                  历史
+                </el-dropdown-item>
+                <el-dropdown-item
+                  command="handleChangeState"
+                  v-if="checkPermi(['bpm:model:update']) && scope.row.processDefinition"
+                  :disabled="!isManagerUser(scope.row)"
+                >
+                  {{ scope.row.processDefinition.suspensionState === 1 ? '停用' : '启用' }}
+                </el-dropdown-item>
+                <el-dropdown-item
+                  type="danger"
+                  command="handleDelete"
+                  v-if="checkPermi(['bpm:model:delete'])"
+                  :disabled="!isManagerUser(scope.row)"
+                >
+                  删除
+                </el-dropdown-item>
+              </el-dropdown-menu>
             </template>
-          </el-table-column>
-        </el-table>
-      </ContentWrap>
-    </div>
+          </el-dropdown>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
   </ContentWrap>
 
   <!-- 表单弹窗:添加/修改流程 -->
@@ -208,8 +227,6 @@ import { CategoryApi } from '@/api/bpm/category'
 import { BpmModelType } from '@/utils/constants'
 import { checkPermi } from '@/utils/permission'
 import { useUserStoreWithOut } from '@/store/modules/user'
-import { groupBy } from 'lodash-es'
-import { mockData } from './mock'
 
 defineOptions({ name: 'BpmModel' })
 
@@ -217,7 +234,10 @@ const message = useMessage() // 消息弹窗
 const { t } = useI18n() // 国际化
 const { push } = useRouter() // 路由
 const userStore = useUserStoreWithOut() // 用户信息缓存
+
 const loading = ref(true) // 列表的加载中
+const total = ref(0) // 列表的总页数
+const list = ref([]) // 列表的数据
 const queryParams = reactive({
   pageNo: 1,
   pageSize: 10,
@@ -227,16 +247,14 @@ const queryParams = reactive({
 })
 const queryFormRef = ref() // 搜索的表单
 const categoryList = ref([]) // 流程分类列表
-const categoryGroup = ref<any>({}) // 按照category分组的数据
 
 /** 查询列表 */
 const getList = async () => {
   loading.value = true
   try {
-    // TODO 芋艿:这里需要一个不分页查全部的流程模型接口
     const data = await ModelApi.getModelPage(queryParams)
-    data.list = mockData
-    categoryGroup.value = groupBy(data.list, 'categoryName')
+    list.value = data.list
+    total.value = data.total
   } finally {
     loading.value = false
   }
@@ -384,12 +402,3 @@ onMounted(async () => {
   categoryList.value = await CategoryApi.getCategorySimpleList()
 })
 </script>
-
-<style lang="scss" scoped>
-:deep(.el-form--inline .el-form-item) {
-  margin-right: 10px;
-}
-:deep(.el-divider--horizontal) {
-  margin-top: 10px;
-}
-</style>

+ 432 - 0
src/views/bpm/model/index_new.vue

@@ -0,0 +1,432 @@
+<template>
+  <ContentWrap>
+    <div class="flex justify-between pl-20px items-center">
+      <h3>表单管理</h3>
+      <!-- 搜索工作栏 -->
+      <el-form
+        class="-mb-15px flex"
+        :model="queryParams"
+        ref="queryFormRef"
+        :inline="true"
+        label-width="68px"
+      >
+        <el-form-item align="right" prop="key" class="ml-auto">
+          <el-input
+            v-model="queryParams.key"
+            placeholder="搜索流程"
+            clearable
+            @keyup.enter="handleQuery"
+            class="!w-240px"
+          >
+            <template #prefix>
+              <Icon icon="ep:search" class="mx-10px" />
+            </template>
+          </el-input>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="openForm('create')" v-hasPermi="['bpm:model:create']">
+            <Icon icon="ep:plus" class="mr-5px" /> 新建流程
+          </el-button>
+        </el-form-item>
+
+        <el-form-item>
+          <el-dropdown placement="bottom-end">
+            <el-button type="info" plain>
+              <Icon icon="ep:setting" />
+            </el-button>
+            <template #dropdown>
+              <el-dropdown-menu>
+                <el-dropdown-item>
+                  <Icon icon="ep:circle-plus" size="13" class="mr-5px" />
+                  新建分组
+                </el-dropdown-item>
+                <el-dropdown-item>
+                  <Icon icon="fa:sort-amount-desc" size="13" class="mr-5px" />
+                  分组排序
+                </el-dropdown-item>
+              </el-dropdown-menu>
+            </template>
+          </el-dropdown>
+        </el-form-item>
+      </el-form>
+    </div>
+
+    <el-divider />
+
+    <!-- 分类卡片组 -->
+    <div class="px-15px">
+      <ContentWrap v-for="(list, title) in categoryGroup" :key="title">
+        <!-- 默认使其全部展开 -->
+        <el-collapse :modelValue="title">
+          <el-collapse-item :name="title">
+            <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" />
+              </div>
+            </template>
+            <template #title>
+              <div class="flex items-center">
+                <h3 class="ml-20px mr-8px text-18px">{{ title }}</h3>
+                <div class="text-[var(--el-text-color-placeholder)] text-16px">
+                  ({{ list?.length || 0 }})
+                </div>
+              </div>
+            </template>
+
+            <el-table v-loading="loading" :data="list">
+              <el-table-column label="流程名" prop="name" min-width="200">
+                <template #default="scope">
+                  <div class="flex items-center">
+                    <el-image :src="scope.row.icon" class="h-32px w-32px mr-10px rounded" />
+                    {{ scope.row.name }}
+                  </div>
+                </template>
+              </el-table-column>
+              <el-table-column label="可见范围" prop="startUserIds" min-width="100">
+                <template #default="scope">
+                  <el-text v-if="!scope.row.startUsers || scope.row.startUsers.length === 0">
+                    全部可见
+                  </el-text>
+                  <el-text v-else-if="scope.row.startUsers.length == 1">
+                    {{ scope.row.startUsers[0].nickname }}
+                  </el-text>
+                  <el-text v-else>
+                    <el-tooltip
+                      class="box-item"
+                      effect="dark"
+                      placement="top"
+                      :content="scope.row.startUsers.map((user: any) => user.nickname).join('、')"
+                    >
+                      {{ scope.row.startUsers[0].nickname }}等
+                      {{ scope.row.startUsers.length }} 人可见
+                    </el-tooltip>
+                  </el-text>
+                </template>
+              </el-table-column>
+              <el-table-column label="表单信息" prop="formType" min-width="200">
+                <template #default="scope">
+                  <el-button
+                    v-if="scope.row.formType === 10"
+                    type="primary"
+                    link
+                    @click="handleFormDetail(scope.row)"
+                  >
+                    <span>{{ scope.row.formName }}</span>
+                  </el-button>
+                  <el-button
+                    v-else-if="scope.row.formType === 20"
+                    type="primary"
+                    link
+                    @click="handleFormDetail(scope.row)"
+                  >
+                    <span>{{ scope.row.formCustomCreatePath }}</span>
+                  </el-button>
+                  <label v-else>暂无表单</label>
+                </template>
+              </el-table-column>
+              <el-table-column label="最后发布" prop="deploymentTime" min-width="250">
+                <template #default="scope">
+                  <span v-if="scope.row.processDefinition">
+                    {{ formatDate(scope.row.processDefinition.deploymentTime) }}
+                  </span>
+                  <el-tag v-if="scope.row.processDefinition" class="ml-10px">
+                    v{{ scope.row.processDefinition.version }}
+                  </el-tag>
+                  <el-tag v-else type="warning">未部署</el-tag>
+                  <el-tag
+                    v-if="scope.row.processDefinition?.suspensionState === 2"
+                    type="warning"
+                    class="ml-10px"
+                  >
+                    已停用
+                  </el-tag>
+                </template>
+              </el-table-column>
+              <el-table-column label="操作" width="200" fixed="right">
+                <template #default="scope">
+                  <el-button
+                    link
+                    type="primary"
+                    @click="openForm('update', scope.row.id)"
+                    v-hasPermi="['bpm:model:update']"
+                    :disabled="!isManagerUser(scope.row)"
+                  >
+                    修改
+                  </el-button>
+                  <el-button
+                    link
+                    class="!ml-5px"
+                    type="primary"
+                    @click="handleDesign(scope.row)"
+                    v-hasPermi="['bpm:model:update']"
+                    :disabled="!isManagerUser(scope.row)"
+                  >
+                    设计
+                  </el-button>
+                  <el-button
+                    link
+                    class="!ml-5px"
+                    type="primary"
+                    @click="handleDeploy(scope.row)"
+                    v-hasPermi="['bpm:model:deploy']"
+                    :disabled="!isManagerUser(scope.row)"
+                  >
+                    发布
+                  </el-button>
+                  <el-dropdown
+                    class="!align-middle ml-5px"
+                    @command="(command) => handleCommand(command, scope.row)"
+                    v-hasPermi="[
+                      'bpm:process-definition:query',
+                      'bpm:model:update',
+                      'bpm:model:delete'
+                    ]"
+                  >
+                    <el-button type="primary" link>更多</el-button>
+                    <template #dropdown>
+                      <el-dropdown-menu>
+                        <el-dropdown-item
+                          command="handleDefinitionList"
+                          v-if="checkPermi(['bpm:process-definition:query'])"
+                        >
+                          历史
+                        </el-dropdown-item>
+                        <el-dropdown-item
+                          command="handleChangeState"
+                          v-if="checkPermi(['bpm:model:update']) && scope.row.processDefinition"
+                          :disabled="!isManagerUser(scope.row)"
+                        >
+                          {{ scope.row.processDefinition.suspensionState === 1 ? '停用' : '启用' }}
+                        </el-dropdown-item>
+                        <el-dropdown-item
+                          type="danger"
+                          command="handleDelete"
+                          v-if="checkPermi(['bpm:model:delete'])"
+                          :disabled="!isManagerUser(scope.row)"
+                        >
+                          删除
+                        </el-dropdown-item>
+                      </el-dropdown-menu>
+                    </template>
+                  </el-dropdown>
+                </template>
+              </el-table-column>
+            </el-table>
+          </el-collapse-item>
+        </el-collapse>
+      </ContentWrap>
+    </div>
+  </ContentWrap>
+
+  <!-- 表单弹窗:添加/修改流程 -->
+  <ModelForm ref="formRef" @success="getList" />
+
+  <!-- 弹窗:表单详情 -->
+  <Dialog title="表单详情" v-model="formDetailVisible" width="800">
+    <form-create :rule="formDetailPreview.rule" :option="formDetailPreview.option" />
+  </Dialog>
+</template>
+
+<script lang="ts" setup>
+import { formatDate } from '@/utils/formatTime'
+import * as ModelApi from '@/api/bpm/model'
+import * as FormApi from '@/api/bpm/form'
+import ModelForm from './ModelForm.vue'
+import { setConfAndFields2 } from '@/utils/formCreate'
+import { CategoryApi } from '@/api/bpm/category'
+import { BpmModelType } from '@/utils/constants'
+import { checkPermi } from '@/utils/permission'
+import { useUserStoreWithOut } from '@/store/modules/user'
+import { groupBy } from 'lodash-es'
+
+defineOptions({ name: 'BpmModel' })
+
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+const { push } = useRouter() // 路由
+const userStore = useUserStoreWithOut() // 用户信息缓存
+const loading = ref(true) // 列表的加载中
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  key: undefined,
+  name: undefined,
+  category: undefined
+})
+const queryFormRef = ref() // 搜索的表单
+const categoryList = ref([]) // 流程分类列表
+const categoryGroup = ref<any>({}) // 按照category分组的数据
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    // TODO 芋艿:这里需要一个不分页查全部的流程模型接口
+    const data = await ModelApi.getModelPage(queryParams)
+    categoryGroup.value = groupBy(data.list, 'categoryName')
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
+
+
+/** '更多'操作按钮 */
+const handleCommand = (command: string, row: any) => {
+  switch (command) {
+    case 'handleDefinitionList':
+      handleDefinitionList(row)
+      break
+    case 'handleDelete':
+      handleDelete(row)
+      break
+    case 'handleChangeState':
+      handleChangeState(row)
+      break
+    default:
+      break
+  }
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (type: string, id?: number) => {
+  formRef.value.open(type, id)
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row: any) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await ModelApi.deleteModel(row.id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 更新状态操作 */
+const handleChangeState = async (row: any) => {
+  const state = row.processDefinition.suspensionState
+  const newState = state === 1 ? 2 : 1
+  try {
+    // 修改状态的二次确认
+    const id = row.id
+    debugger
+    const statusState = state === 1 ? '停用' : '启用'
+    const content = '是否确认' + statusState + '流程名字为"' + row.name + '"的数据项?'
+    await message.confirm(content)
+    // 发起修改状态
+    await ModelApi.updateModelState(id, newState)
+    message.success(statusState + '成功')
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 设计流程 */
+const handleDesign = (row: any) => {
+  if (row.type == BpmModelType.BPMN) {
+    push({
+      name: 'BpmModelEditor',
+      query: {
+        modelId: row.id
+      }
+    })
+  } else {
+    push({
+      name: 'SimpleWorkflowDesignEditor',
+      query: {
+        modelId: row.id
+      }
+    })
+  }
+}
+
+/** 发布流程 */
+const handleDeploy = async (row: any) => {
+  try {
+    // 删除的二次确认
+    await message.confirm('是否部署该流程!!')
+    // 发起部署
+    await ModelApi.deployModel(row.id)
+    message.success(t('部署成功'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 跳转到指定流程定义列表 */
+const handleDefinitionList = (row) => {
+  push({
+    name: 'BpmProcessDefinition',
+    query: {
+      key: row.key
+    }
+  })
+}
+
+/** 流程表单的详情按钮操作 */
+const formDetailVisible = ref(false)
+const formDetailPreview = ref({
+  rule: [],
+  option: {}
+})
+const handleFormDetail = async (row: any) => {
+  if (row.formType == 10) {
+    // 设置表单
+    const data = await FormApi.getForm(row.formId)
+    setConfAndFields2(formDetailPreview, data.conf, data.fields)
+    // 弹窗打开
+    formDetailVisible.value = true
+  } else {
+    await push({
+      path: row.formCustomCreatePath
+    })
+  }
+}
+
+/** 判断是否可以操作 */
+const isManagerUser = (row: any) => {
+  const userId = userStore.getUser.id
+  return row.managerUserIds && row.managerUserIds.includes(userId)
+}
+
+/** 初始化 **/
+onMounted(async () => {
+  await getList()
+  // 查询流程分类列表
+  categoryList.value = await CategoryApi.getCategorySimpleList()
+})
+</script>
+
+<style lang="scss" scoped>
+:deep() {
+  .el-form--inline .el-form-item {
+    margin-right: 10px;
+  }
+  .el-divider--horizontal {
+    margin-top: 10px;
+  }
+  .el-collapse,
+  .el-collapse-item__header,
+  .el-collapse-item__wrap {
+    border: none;
+  }
+  .el-collapse-item__arrow {
+    margin-left: 10px;
+    font-size: 20px;
+    font-weight: 500;
+  }
+}
+</style>

+ 0 - 404
src/views/bpm/model/index_old.vue

@@ -1,404 +0,0 @@
-<template>
-  <doc-alert title="流程设计器(BPMN)" url="https://doc.iocoder.cn/bpm/model-designer-dingding/" />
-  <doc-alert
-    title="流程设计器(钉钉、飞书)"
-    url="https://doc.iocoder.cn/bpm/model-designer-bpmn/"
-  />
-  <doc-alert title="选择审批人、发起人自选" url="https://doc.iocoder.cn/bpm/assignee/" />
-  <doc-alert title="会签、或签、依次审批" url="https://doc.iocoder.cn/bpm/multi-instance/" />
-
-  <ContentWrap>
-    <!-- 搜索工作栏 -->
-    <el-form
-      class="-mb-15px"
-      :model="queryParams"
-      ref="queryFormRef"
-      :inline="true"
-      label-width="68px"
-    >
-      <el-form-item label="流程标识" prop="key">
-        <el-input
-          v-model="queryParams.key"
-          placeholder="请输入流程标识"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
-      </el-form-item>
-      <el-form-item label="流程名称" prop="name">
-        <el-input
-          v-model="queryParams.name"
-          placeholder="请输入流程名称"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
-      </el-form-item>
-      <el-form-item label="流程分类" prop="category">
-        <el-select
-          v-model="queryParams.category"
-          placeholder="请选择流程分类"
-          clearable
-          class="!w-240px"
-        >
-          <el-option
-            v-for="category in categoryList"
-            :key="category.code"
-            :label="category.name"
-            :value="category.code"
-          />
-        </el-select>
-      </el-form-item>
-      <el-form-item>
-        <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
-        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
-        <el-button
-          type="primary"
-          plain
-          @click="openForm('create')"
-          v-hasPermi="['bpm:model:create']"
-        >
-          <Icon icon="ep:plus" class="mr-5px" /> 新建
-        </el-button>
-      </el-form-item>
-    </el-form>
-  </ContentWrap>
-
-  <!-- 列表 -->
-  <ContentWrap>
-    <el-table v-loading="loading" :data="list">
-      <el-table-column label="流程名称" align="center" prop="name" min-width="200" />
-      <el-table-column label="流程图标" align="center" prop="icon" min-width="100">
-        <template #default="scope">
-          <el-image :src="scope.row.icon" class="h-32px w-32px" />
-        </template>
-      </el-table-column>
-      <el-table-column label="可见范围" align="center" prop="startUserIds" min-width="100">
-        <template #default="scope">
-          <el-text v-if="!scope.row.startUsers || scope.row.startUsers.length === 0">
-            全部可见
-          </el-text>
-          <el-text v-else-if="scope.row.startUsers.length == 1">
-            {{ scope.row.startUsers[0].nickname }}
-          </el-text>
-          <el-text v-else>
-            <el-tooltip
-              class="box-item"
-              effect="dark"
-              placement="top"
-              :content="scope.row.startUsers.map((user: any) => user.nickname).join('、')"
-            >
-              {{ scope.row.startUsers[0].nickname }}等 {{ scope.row.startUsers.length }} 人可见
-            </el-tooltip>
-          </el-text>
-        </template>
-      </el-table-column>
-      <el-table-column label="流程分类" align="center" prop="categoryName" min-width="100" />
-      <el-table-column label="表单信息" align="center" prop="formType" min-width="200">
-        <template #default="scope">
-          <el-button
-            v-if="scope.row.formType === 10"
-            type="primary"
-            link
-            @click="handleFormDetail(scope.row)"
-          >
-            <span>{{ scope.row.formName }}</span>
-          </el-button>
-          <el-button
-            v-else-if="scope.row.formType === 20"
-            type="primary"
-            link
-            @click="handleFormDetail(scope.row)"
-          >
-            <span>{{ scope.row.formCustomCreatePath }}</span>
-          </el-button>
-          <label v-else>暂无表单</label>
-        </template>
-      </el-table-column>
-      <el-table-column label="最后发布" align="center" prop="deploymentTime" min-width="250">
-        <template #default="scope">
-          <span v-if="scope.row.processDefinition">
-            {{ formatDate(scope.row.processDefinition.deploymentTime) }}
-          </span>
-          <el-tag v-if="scope.row.processDefinition" class="ml-10px">
-            v{{ scope.row.processDefinition.version }}
-          </el-tag>
-          <el-tag v-else type="warning">未部署</el-tag>
-          <el-tag
-            v-if="scope.row.processDefinition?.suspensionState === 2"
-            type="warning"
-            class="ml-10px"
-          >
-            已停用
-          </el-tag>
-        </template>
-      </el-table-column>
-      <el-table-column label="操作" align="center" width="200" fixed="right">
-        <template #default="scope">
-          <el-button
-            link
-            type="primary"
-            @click="openForm('update', scope.row.id)"
-            v-hasPermi="['bpm:model:update']"
-            :disabled="!isManagerUser(scope.row)"
-          >
-            修改
-          </el-button>
-          <el-button
-            link
-            class="!ml-5px"
-            type="primary"
-            @click="handleDesign(scope.row)"
-            v-hasPermi="['bpm:model:update']"
-            :disabled="!isManagerUser(scope.row)"
-          >
-            设计
-          </el-button>
-          <el-button
-            link
-            class="!ml-5px"
-            type="primary"
-            @click="handleDeploy(scope.row)"
-            v-hasPermi="['bpm:model:deploy']"
-            :disabled="!isManagerUser(scope.row)"
-          >
-            发布
-          </el-button>
-          <el-dropdown
-            class="!align-middle ml-5px"
-            @command="(command) => handleCommand(command, scope.row)"
-            v-hasPermi="['bpm:process-definition:query', 'bpm:model:update', 'bpm:model:delete']"
-          >
-            <el-button type="primary" link>更多</el-button>
-            <template #dropdown>
-              <el-dropdown-menu>
-                <el-dropdown-item
-                  command="handleDefinitionList"
-                  v-if="checkPermi(['bpm:process-definition:query'])"
-                >
-                  历史
-                </el-dropdown-item>
-                <el-dropdown-item
-                  command="handleChangeState"
-                  v-if="checkPermi(['bpm:model:update']) && scope.row.processDefinition"
-                  :disabled="!isManagerUser(scope.row)"
-                >
-                  {{ scope.row.processDefinition.suspensionState === 1 ? '停用' : '启用' }}
-                </el-dropdown-item>
-                <el-dropdown-item
-                  type="danger"
-                  command="handleDelete"
-                  v-if="checkPermi(['bpm:model:delete'])"
-                  :disabled="!isManagerUser(scope.row)"
-                >
-                  删除
-                </el-dropdown-item>
-              </el-dropdown-menu>
-            </template>
-          </el-dropdown>
-        </template>
-      </el-table-column>
-    </el-table>
-    <!-- 分页 -->
-    <Pagination
-      :total="total"
-      v-model:page="queryParams.pageNo"
-      v-model:limit="queryParams.pageSize"
-      @pagination="getList"
-    />
-  </ContentWrap>
-
-  <!-- 表单弹窗:添加/修改流程 -->
-  <ModelForm ref="formRef" @success="getList" />
-
-  <!-- 弹窗:表单详情 -->
-  <Dialog title="表单详情" v-model="formDetailVisible" width="800">
-    <form-create :rule="formDetailPreview.rule" :option="formDetailPreview.option" />
-  </Dialog>
-</template>
-
-<script lang="ts" setup>
-import { formatDate } from '@/utils/formatTime'
-import * as ModelApi from '@/api/bpm/model'
-import * as FormApi from '@/api/bpm/form'
-import ModelForm from './ModelForm.vue'
-import { setConfAndFields2 } from '@/utils/formCreate'
-import { CategoryApi } from '@/api/bpm/category'
-import { BpmModelType } from '@/utils/constants'
-import { checkPermi } from '@/utils/permission'
-import { useUserStoreWithOut } from '@/store/modules/user'
-
-defineOptions({ name: 'BpmModel' })
-
-const message = useMessage() // 消息弹窗
-const { t } = useI18n() // 国际化
-const { push } = useRouter() // 路由
-const userStore = useUserStoreWithOut() // 用户信息缓存
-
-const loading = ref(true) // 列表的加载中
-const total = ref(0) // 列表的总页数
-const list = ref([]) // 列表的数据
-const queryParams = reactive({
-  pageNo: 1,
-  pageSize: 10,
-  key: undefined,
-  name: undefined,
-  category: undefined
-})
-const queryFormRef = ref() // 搜索的表单
-const categoryList = ref([]) // 流程分类列表
-
-/** 查询列表 */
-const getList = async () => {
-  loading.value = true
-  try {
-    const data = await ModelApi.getModelPage(queryParams)
-    list.value = data.list
-    total.value = data.total
-  } finally {
-    loading.value = false
-  }
-}
-
-/** 搜索按钮操作 */
-const handleQuery = () => {
-  queryParams.pageNo = 1
-  getList()
-}
-
-/** 重置按钮操作 */
-const resetQuery = () => {
-  queryFormRef.value.resetFields()
-  handleQuery()
-}
-
-/** '更多'操作按钮 */
-const handleCommand = (command: string, row: any) => {
-  switch (command) {
-    case 'handleDefinitionList':
-      handleDefinitionList(row)
-      break
-    case 'handleDelete':
-      handleDelete(row)
-      break
-    case 'handleChangeState':
-      handleChangeState(row)
-      break
-    default:
-      break
-  }
-}
-
-/** 添加/修改操作 */
-const formRef = ref()
-const openForm = (type: string, id?: number) => {
-  formRef.value.open(type, id)
-}
-
-/** 删除按钮操作 */
-const handleDelete = async (row: any) => {
-  try {
-    // 删除的二次确认
-    await message.delConfirm()
-    // 发起删除
-    await ModelApi.deleteModel(row.id)
-    message.success(t('common.delSuccess'))
-    // 刷新列表
-    await getList()
-  } catch {}
-}
-
-/** 更新状态操作 */
-const handleChangeState = async (row: any) => {
-  const state = row.processDefinition.suspensionState
-  const newState = state === 1 ? 2 : 1
-  try {
-    // 修改状态的二次确认
-    const id = row.id
-    debugger
-    const statusState = state === 1 ? '停用' : '启用'
-    const content = '是否确认' + statusState + '流程名字为"' + row.name + '"的数据项?'
-    await message.confirm(content)
-    // 发起修改状态
-    await ModelApi.updateModelState(id, newState)
-    message.success(statusState + '成功')
-    // 刷新列表
-    await getList()
-  } catch {}
-}
-
-/** 设计流程 */
-const handleDesign = (row: any) => {
-  if (row.type == BpmModelType.BPMN) {
-    push({
-      name: 'BpmModelEditor',
-      query: {
-        modelId: row.id
-      }
-    })
-  } else {
-    push({
-      name: 'SimpleWorkflowDesignEditor',
-      query: {
-        modelId: row.id
-      }
-    })
-  }
-}
-
-/** 发布流程 */
-const handleDeploy = async (row: any) => {
-  try {
-    // 删除的二次确认
-    await message.confirm('是否部署该流程!!')
-    // 发起部署
-    await ModelApi.deployModel(row.id)
-    message.success(t('部署成功'))
-    // 刷新列表
-    await getList()
-  } catch {}
-}
-
-/** 跳转到指定流程定义列表 */
-const handleDefinitionList = (row) => {
-  push({
-    name: 'BpmProcessDefinition',
-    query: {
-      key: row.key
-    }
-  })
-}
-
-/** 流程表单的详情按钮操作 */
-const formDetailVisible = ref(false)
-const formDetailPreview = ref({
-  rule: [],
-  option: {}
-})
-const handleFormDetail = async (row: any) => {
-  if (row.formType == 10) {
-    // 设置表单
-    const data = await FormApi.getForm(row.formId)
-    setConfAndFields2(formDetailPreview, data.conf, data.fields)
-    // 弹窗打开
-    formDetailVisible.value = true
-  } else {
-    await push({
-      path: row.formCustomCreatePath
-    })
-  }
-}
-
-/** 判断是否可以操作 */
-const isManagerUser = (row: any) => {
-  const userId = userStore.getUser.id
-  return row.managerUserIds && row.managerUserIds.includes(userId)
-}
-
-/** 初始化 **/
-onMounted(async () => {
-  await getList()
-  // 查询流程分类列表
-  categoryList.value = await CategoryApi.getCategorySimpleList()
-})
-</script>

+ 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
-    }
-  }
-]