ソースを参照

feat: 一些优化和问题修复

wuwenyi 1 週間 前
コミット
12b1bab156

+ 1 - 1
src/api/flow/instance.ts

@@ -8,7 +8,7 @@ export function listMyInstance(params?: PageQuery): Promise<PageResult<FlowInsta
 }
 
 export function listInstance(
-  params?: PageQuery & { applicantName?: string; processName?: string; currentNodeName?: string }
+  params?: PageQuery & { applicantName?: string; processName?: string; definitionName?: string; currentNodeName?: string }
 ): Promise<PageResult<FlowInstance>> {
   return http.get('/flow/instance/page', { params })
 }

+ 1 - 1
src/views/analysis/NodeCountChart.vue

@@ -1,5 +1,5 @@
 <template>
-  <el-card shadow="hover" v-loading="loading">
+  <el-card shadow="hover" v-loading="loading" style="height: 100%;">
     <template #header>
       <span>各节点统计</span>
     </template>

+ 3 - 2
src/views/analysis/StuckInstanceTable.vue

@@ -4,8 +4,8 @@
       <div class="detail-header">
         <span>流程明细</span>
         <div class="detail-actions">
-          <el-select v-model="localQuery.processName" placeholder="流程名称" clearable style="width: 160px;" @change="onProcessChange">
-            <el-option v-for="def in definitionList" :key="def.id" :label="def.name" :value="def.name" />
+          <el-select v-model="localQuery.processDefinitionId" placeholder="流程名称" clearable style="width: 160px;" @change="onProcessChange">
+            <el-option v-for="def in definitionList" :key="def.id" :label="def.name" :value="def.id" />
           </el-select>
           <el-input v-model="localQuery.applicantName" placeholder="归属用户" clearable style="width: 140px; margin-left: 8px;" @change="onSearch" />
           <el-select v-model="localQuery.currentNodeName" placeholder="当前节点" clearable style="width: 140px; margin-left: 8px;" @change="onSearch">
@@ -67,6 +67,7 @@ const props = defineProps<{
   query: {
     pageNum: number
     pageSize: number
+    processDefinitionId?: number
     processName: string
     applicantName: string
     currentNodeName: string

+ 3 - 2
src/views/analysis/useAnalysis.ts

@@ -105,7 +105,7 @@ export function useAnalysis() {
   const loadingAll = ref(false)
 
   // 流程明细
-  const instanceQuery = reactive({ pageNum: 1, pageSize: 10, processName: '', applicantName: '', currentNodeName: '' })
+  const instanceQuery = reactive({ pageNum: 1, pageSize: 10, processDefinitionId: undefined as number | undefined, processName: '', applicantName: '', currentNodeName: '' })
   const instanceList = ref<FlowInstance[]>([])
   const instanceTotal = ref(0)
   const loadingInstanceList = ref(false)
@@ -402,7 +402,8 @@ export function useAnalysis() {
       const res = await listInstance({
         pageNum: instanceQuery.pageNum,
         pageSize: instanceQuery.pageSize,
-        processName: instanceQuery.processName || undefined,
+        processDefinitionId: instanceQuery.processDefinitionId,
+        definitionName: instanceQuery.processName || undefined,
         applicantName: instanceQuery.applicantName || undefined,
         currentNodeName: instanceQuery.currentNodeName || undefined,
       })

+ 9 - 3
src/views/flow/definition/index.vue

@@ -532,11 +532,17 @@ const migrateDefinitionList = ref<FlowDefinition[]>([])
 const migrateTargetList = ref<FlowDefinition[]>([])
 const migrating = ref(false)
 
-function openMigrateDialog() {
+async function openMigrateDialog() {
   migrateFromId.value = null
   migrateToId.value = null
   migrateTargetList.value = []
-  migrateDefinitionList.value = [...tableData.value]
+  // 加载全部流程定义(不受分页限制)
+  try {
+    const res = await listDefinition({ pageNum: 1, pageSize: 999 })
+    migrateDefinitionList.value = res.list
+  } catch {
+    migrateDefinitionList.value = [...tableData.value]
+  }
   migrateDialogVisible.value = true
 }
 
@@ -544,7 +550,7 @@ function onMigrateFromChange() {
   migrateToId.value = null
   const from = migrateDefinitionList.value.find(d => d.id === migrateFromId.value)
   if (!from) { migrateTargetList.value = []; return }
-  migrateTargetList.value = migrateDefinitionList.value.filter(d => d.code === from.code && d.id !== from.id)
+  migrateTargetList.value = migrateDefinitionList.value.filter(d => d.id !== from.id)
 }
 
 async function confirmMigrate() {

+ 36 - 2
src/views/flow/execute/InstanceDetail.vue

@@ -128,6 +128,11 @@
                   <el-radio label="rollback">回退</el-radio>
                 </el-radio-group>
               </el-form-item>
+              <el-form-item v-if="form.action === 'pass' && nextNodes.length > 0" label="选择分支">
+                <el-select v-model="form.targetNodeId" placeholder="请选择下一节点" style="width: 100%">
+                  <el-option v-for="n in nextNodes" :key="n.nodeId" :label="n.nodeName" :value="n.nodeId" />
+                </el-select>
+              </el-form-item>
               <el-form-item v-if="form.action === 'rollback'" label="回退说明">
                 <el-alert type="warning" :closable="false" show-icon>
                   <template #title>
@@ -224,7 +229,8 @@
 import { ref, reactive, computed, watch } from 'vue'
 import { ElMessage } from 'element-plus'
 import { getProgress, getInstanceAttachments, updateInstanceFormData } from '@/api/flow/instance'
-import { approveTask, rejectTask, returnTask, addSignTask, getTransferableUsers } from '@/api/flow/task'
+import { approveTask, rejectTask, returnTask, addSignTask, getTransferableUsers, listNextNodes } from '@/api/flow/task'
+import type { NextNode } from '@/types/flow'
 import { beforeFileUpload, getFileUrl, getFileName, parseAttachments, collectAttachmentUrls } from '@/utils/file'
 import { useFileUpload } from '@/composables/useFileUpload'
 import { instanceStatusText, instanceStatusTagType, taskStatusText, taskStatusType, recordActionText, recordActionType } from '@/utils/flow'
@@ -258,9 +264,11 @@ type ApprovalActionType = 'pass' | 'reject' | 'rollback'
 const form = reactive<{
   action: ApprovalActionType
   comment: string
+  targetNodeId?: string
 }>({
   action: 'pass',
-  comment: ''
+  comment: '',
+  targetNodeId: undefined
 })
 
 const fileUpload = reactive(useFileUpload())
@@ -313,6 +321,13 @@ function isImage(url: string): boolean {
 }
 
 // 查找当前登录用户需要处理的待办任务
+// 分支选择
+const nextNodes = ref<NextNode[]>([])
+
+async function loadNextNodes(taskId: number) {
+  try { nextNodes.value = await listNextNodes(taskId) } catch { nextNodes.value = [] }
+}
+
 const myPendingTask = computed<FlowTask | null>(() => {
   if (!progress.value) return null
   for (const node of progress.value.nodes) {
@@ -359,6 +374,10 @@ async function loadProgress() {
 async function submitApprove() {
   const task = myPendingTask.value
   if (!task) return
+  if (form.action === 'pass' && nextNodes.value.length > 0 && !form.targetNodeId) {
+    ElMessage.warning('存在多个下游分支,请选择一个目标节点')
+    return
+  }
   submitting.value = true
   try {
     const data: ApprovalAction = {
@@ -368,6 +387,9 @@ async function submitApprove() {
     if (fileUpload.attachmentList.length > 0) {
       data.attachmentUrls = collectAttachmentUrls(fileUpload.attachmentList)
     }
+    if (form.action === 'pass' && form.targetNodeId) {
+      data.targetNodeId = form.targetNodeId
+    }
     switch (form.action) {
       case 'pass':
         await approveTask(task.id, data)
@@ -483,9 +505,21 @@ watch(() => props.instanceId, (id) => {
   }
 })
 
+// 切换到"通过"时加载下游节点列表
+watch(() => form.action, (action) => {
+  nextNodes.value = []
+  form.targetNodeId = undefined
+  if (action === 'pass' && myPendingTask.value) {
+    loadNextNodes(myPendingTask.value.id)
+  }
+})
+
 watch(() => props.modelValue, async (val) => {
   if (val && props.instanceId) {
     await loadProgress()
+    if (form.action === 'pass' && myPendingTask.value) {
+      loadNextNodes(myPendingTask.value.id)
+    }
     await loadTransferableUsers()
     loadAttachments()
   }

+ 0 - 6
src/views/system/role/index.vue

@@ -150,12 +150,6 @@
         <el-form-item label="排序">
           <el-input-number v-model="deptForm.sort" :min="0" />
         </el-form-item>
-        <el-form-item label="状态">
-          <el-radio-group v-model="deptForm.status">
-            <el-radio :label="1">正常</el-radio>
-            <el-radio :label="0">禁用</el-radio>
-          </el-radio-group>
-        </el-form-item>
       </el-form>
       <template #footer>
         <el-button @click="deptDialogVisible = false">取消</el-button>