Bläddra i källkod

办件中心改造

songxy 11 månader sedan
förälder
incheckning
5f45042495

+ 111 - 2
client/src/api/oa/workflow/index.ts

@@ -14,6 +14,19 @@ export const getFlowTemplateTree = async () => {
     '/workflow'
   )
 }
+// 发起流程
+export const addTProcessEngine = async (templateId: string) => {
+  const formData = new FormData()
+  formData.append('templateId', templateId)
+  return await request.postOriginal(
+    {
+      url: '/TProcessEngine/add',
+      data: formData,
+      headersType: 'application/form-data'
+    },
+    '/workflow'
+  )
+}
 // 获取办件中心汇总数据
 export const getHandlerCaseCenterCount = async (data) => {
   return await request.postOriginal(
@@ -38,17 +51,73 @@ export const recoverActivity = async (data: {
   activityInstanceId: string
   participantId: string
 }) => {
-  // {"activityInstanceId": rowObj.ACTIVITYINSID, "participantId": rowObj.PARTICIPANTID}
+  const keys = Object.keys(data)
+  const formData = new FormData()
+  keys.forEach((key) => {
+    formData.append(key, data[key])
+  })
   return await request.postOriginal(
     {
       url: '/HandlerCaseCenter/recoverActivity',
-      data: data,
+      data: formData,
       headersType: 'application/form-data'
     },
     '/workflow'
   )
 }
 
+//办件中心“解挂”操作
+export const addIHangUp = async (data: { activityInstanceId: string; isRecover: number }) => {
+  const keys = Object.keys(data)
+  const formData = new FormData()
+  keys.forEach((key) => {
+    formData.append(key, data[key])
+  })
+  return await request.postOriginal(
+    {
+      url: '/IHangUp/add',
+      data: formData,
+      headersType: 'application/form-data'
+    },
+    '/workflow'
+  )
+}
+//办件中心“恢复作废”操作
+export const addINullyApply = async (data: {
+  activityInstanceId: string
+  voidFlowInstanceId: string
+  isRecover: number
+}) => {
+  const keys = Object.keys(data)
+  const formData = new FormData()
+  keys.forEach((key) => {
+    formData.append(key, data[key])
+  })
+  return await request.postOriginal(
+    {
+      url: '/INullyApply/add',
+      data: formData,
+      headersType: 'application/form-data'
+    },
+    '/workflow'
+  )
+}
+//办件中心“彻底作废”操作
+export const completelyVoidINullyApply = async (data: { flowInstanceId: string }) => {
+  const keys = Object.keys(data)
+  const formData = new FormData()
+  keys.forEach((key) => {
+    formData.append(key, data[key])
+  })
+  return await request.postOriginal(
+    {
+      url: '/INullyApply/completelyVoid',
+      data: formData,
+      headersType: 'application/form-data'
+    },
+    '/workflow'
+  )
+}
 //办件中心“退回”操作
 export const getCalBackActivity = async (data: {
   activityInstanceId: string
@@ -90,3 +159,43 @@ export const isVoid = async (data: { flowInstanceId: string }) => {
     '/workflow'
   )
 }
+
+//公共待办件提示
+export const openOfficeTip = async (data: {
+  activityInsId: string
+  particiPantId: string
+  isView: true
+}) => {
+  return await request.postOriginal(
+    {
+      url: '/HandlerCaseCenter/openOfficeTip',
+      data: data,
+      headersType: 'application/form-data'
+    },
+    '/workflow'
+  )
+}
+
+//转流程办理页面
+export const saveAndGetUrl = async (data: {
+  activityInsId: string
+  flowInsId: string
+  particiPantId: string
+  status: string
+  userId: string | null
+  isView: boolean
+}) => {
+  const keys = Object.keys(data)
+  const formData = new FormData()
+  keys.forEach((key) => {
+    formData.append(key, data[key])
+  })
+  return await request.postOriginal(
+    {
+      url: '/HandlerCaseCenter/saveAndGetUrl',
+      data: formData,
+      headersType: 'application/form-data'
+    },
+    '/workflow'
+  )
+}

+ 8 - 8
client/src/router/modules/remaining.ts

@@ -119,14 +119,14 @@ const remainingRouter: AppRouteRecordRaw[] = [
           title: '流程查询'
         }
       },
-      // {
-      //   path: 'mainOfficeCenter2',
-      //   component: () => import('@/views/OaSystem/officeCenter/mainOfficeCenter/index.vue'),
-      //   name: 'mainOfficeCenter',
-      //   meta: {
-      //     title: '办件中心'
-      //   }
-      // },
+      {
+        path: 'mainOfficeCenter2',
+        component: () => import('@/views/OaSystem/officeCenter/mainOfficeCenter/index.vue'),
+        name: 'mainOfficeCenter',
+        meta: {
+          title: '办件中心'
+        }
+      },
       {
         path: 'createNewProcess',
         component: () => import('@/views/OaSystem/officeCenter/createNewProcess/index.vue'),

+ 126 - 33
client/src/views/OaSystem/officeCenter/mainOfficeCenter/common.ts

@@ -1,39 +1,39 @@
-type TabType = {
-  name: string
-  key: string
-  value: number
-}
-export const tabConfig: TabType[] = [
-  {
-    name: '待办',
-    key: '1',
-    value: 0
-  },
-  {
-    name: '已完成',
-    key: '90',
-    value: 0
-  },
-  {
-    name: '已退回',
-    key: '40',
-    value: 0
-  },
-  {
-    name: '挂起',
-    key: '20',
-    value: 0
-  },
-  {
-    name: '作废',
-    key: '160',
-    value: 0
-  }
-]
-
 export const TabColumns = {
   //待办
   '1': [
+    {
+      label: '操作',
+      name: 'action',
+      width: 138,
+      frozen: true,
+      fixed: true
+    },
+    { label: '业务编号', align: 'center', name: 'CODE', width: 250, fixed: true },
+    {
+      label: '环节状态',
+      align: 'center',
+      name: 'statusVal',
+      width: 90,
+      fixed: true
+    },
+    {
+      label: '流程描述',
+      align: 'left',
+      name: 'DESCRIBTION',
+      minwidth: 600
+    },
+    { label: '流程名称', align: 'left', name: 'NAME', width: 130, fixed: true },
+    { label: '办理环节', align: 'center', name: 'ACTIVITYNAME', width: 160, fixed: true },
+    {
+      label: '接件时间',
+      align: 'center',
+      name: 'RECEIVE_TIME',
+      width: 160,
+      fixed: true
+    }
+  ],
+  //已完成
+  '90': [
     {
       label: '操作',
       name: 'action',
@@ -65,5 +65,98 @@ export const TabColumns = {
       fixed: true
     },
     { label: '当前在办环节', align: 'center', name: 'currentActivityVal', width: 180, fixed: true }
+  ],
+  //已退回
+  '40': [
+    {
+      label: '操作',
+      name: 'action',
+      width: 138,
+      frozen: true,
+      fixed: true
+    },
+    { label: '业务编号', align: 'center', name: 'CODE', width: 250, fixed: true },
+    {
+      label: '退至环节完成情况',
+      align: 'center',
+      name: 'statusVal',
+      width: 90,
+      fixed: true
+    },
+    {
+      label: '流程描述',
+      align: 'left',
+      name: 'DESCRIBTION',
+      minwidth: 600
+    },
+    { label: '流程名称', align: 'left', name: 'NAME', width: 130, fixed: true },
+    { label: '被退环节', align: 'center', name: 'BACTIVITYNAME', width: 160, fixed: true },
+    { label: '退至环节', align: 'center', name: 'ACTIVITYNAME', width: 160, fixed: true },
+    {
+      label: '退回时间',
+      align: 'center',
+      name: 'CREATE_TIME',
+      width: 160,
+      fixed: true
+    }
+  ],
+  //挂起
+  '20': [
+    {
+      label: '操作',
+      name: 'action',
+      width: 138,
+      frozen: true,
+      fixed: true
+    },
+    {
+      label: '挂起环节(挂起人)',
+      align: 'center',
+      name: 'activityInsName',
+      width: 250,
+      fixed: true
+    },
+    { label: '业务编号', align: 'center', name: 'flowCode', width: 250, fixed: true },
+    {
+      label: '流程描述',
+      align: 'left',
+      name: 'DESCRIBTION',
+      minwidth: 600
+    },
+    { label: '流程名称', align: 'left', name: 'flowName', width: 130, fixed: true },
+    { label: '挂起时间', align: 'center', name: 'hangUpTime', width: 160, fixed: true },
+    {
+      label: '解挂后截止时间',
+      align: 'center',
+      name: 'shouldFinishDate',
+      width: 160,
+      fixed: true
+    }
+  ],
+  //作废
+  '160': [
+    {
+      label: '操作',
+      name: 'action',
+      width: 138,
+      frozen: true,
+      fixed: true
+    },
+    { label: '作废人', align: 'center', name: 'nullyUserName', width: 250, fixed: true },
+    { label: '业务编号', align: 'center', name: 'flowCode', width: 250, fixed: true },
+    {
+      label: '流程描述',
+      align: 'left',
+      name: 'DESCRIBTION',
+      minwidth: 600
+    },
+    { label: '流程名称', align: 'left', name: 'flowName', width: 130, fixed: true },
+    {
+      label: '作废时间',
+      align: 'center',
+      name: 'nullyTime',
+      width: 160,
+      fixed: true
+    }
   ]
 }

+ 357 - 39
client/src/views/OaSystem/officeCenter/mainOfficeCenter/index.vue

@@ -1,14 +1,42 @@
 <template>
   <div class="mainOfficeCenter">
     <div class="header">
-      <el-button type="danger">新建流程</el-button>
+      <el-popover placement="bottom-start" title="" trigger="hover" width="auto">
+        <template #reference>
+          <el-button type="danger">新建流程</el-button>
+        </template>
+        <ul class="flowTemplateBox">
+          <li v-for="(item, index) in flowTemplateTree" :key="index">
+            <span class="title">{{ item['name'] }}</span>
+            <ul v-for="(cItem, cIndex) in item['children']" :key="cIndex">
+              <li
+                @click="addTProcessHandle(cItem)"
+                v-if="
+                  [
+                    '开票申请',
+                    '分包申请',
+                    '外包申请',
+                    '合同签订',
+                    '项目验收',
+                    '项目结项',
+                    '分包合同签订',
+                    '外包合同签订'
+                  ].indexOf(cItem['name']) === -1
+                "
+                >{{ cItem['name'] }}</li
+              >
+            </ul>
+          </li>
+        </ul>
+      </el-popover>
       <ul class="tabs">
         <li
-          v-for="item in tabConfig"
+          v-for="item in tabList"
           :key="item['key']"
           :class="{ active: currentTab === item['key'] }"
+          @click="switchTabHandle(item)"
         >
-          {{ item['name'] }}
+          {{ item['name'] }}({{ item['value'] }})
         </li>
       </ul>
       <div class="search">
@@ -16,9 +44,11 @@
           <el-form-item label="流程名称">
             <el-tree-select
               v-model="value"
-              :data="data"
+              :data="flowTemplateNameTree"
               :render-after-expand="false"
               show-checkbox
+              default-expand-all
+              :props="{ label: 'name', value: 'id', children: 'children' }"
               style="width: 240px"
             />
           </el-form-item>
@@ -26,7 +56,7 @@
             <el-input type="text" />
           </el-form-item>
           <el-form-item>
-            <el-button type="primary">查询</el-button>
+            <el-button type="primary" @click="searchHandle">查询</el-button>
           </el-form-item>
         </el-form>
       </div>
@@ -43,6 +73,7 @@
             color: '#233755',
             height: '50px'
           }"
+          @row-dblclick="dblclickHandle"
         >
           <el-table-column
             v-for="(item, index) in currentColumn"
@@ -50,26 +81,67 @@
             :label="item['label']"
             :prop="item['name']"
           >
-            <template #default="scope">
-              <template v-if="item['name'] === 'statusVal'">
-                <span v-html="scope.row[item['name']]"></span>
+            <template v-if="item['name'] === 'statusVal'" #default="scope">
+              <span v-html="scope.row[item['name']]"></span>
+            </template>
+            <template v-else-if="item['name'] === 'action'" #default="scope">
+              <template v-if="currentTab === '1'">
+                <el-dropdown split-button type="primary">
+                  办理
+                  <template #dropdown>
+                    <el-dropdown-menu>
+                      <el-dropdown-item
+                        v-for="(bItem, bIndex) in scope.row.btnArrJson"
+                        :key="bIndex"
+                        :disabled="!bItem['isEnable']"
+                        >{{ bItem['value'] }}</el-dropdown-item
+                      >
+                    </el-dropdown-menu>
+                  </template>
+                </el-dropdown>
+              </template>
+              <template v-else-if="currentTab === '90'">
+                <el-button type="primary" icon="Search" @click="lookHandle(scope.row)">
+                  查看
+                </el-button>
+                <el-popconfirm title="是否确定追回?" @confirm="recoverActivityHandle(scope.row)">
+                  <template #reference>
+                    <el-button type="warning" icon="RefreshRight"> 追回 </el-button>
+                  </template>
+                </el-popconfirm>
+              </template>
+              <template v-else-if="currentTab === '40'">
+                <el-button type="primary" icon="Search" @click="lookHandle(scope.row)">
+                  查看
+                </el-button>
+              </template>
+              <template v-else-if="currentTab === '20'">
+                <el-button type="primary" icon="Search" @click="lookHandle(scope.row)">
+                  查看
+                </el-button>
+                <el-popconfirm title="是否确定解挂?" @confirm="addIHangUpHandle(scope.row)">
+                  <template #reference>
+                    <el-button type="warning" icon="RefreshRight"> 解挂 </el-button>
+                  </template>
+                </el-popconfirm>
               </template>
-              <template v-else-if="item['name'] === 'action'">
-                <template v-if="currentTab === '1'">
-                  <el-dropdown split-button type="primary">
-                    办理
-                    <template #dropdown>
-                      <el-dropdown-menu>
-                        <el-dropdown-item
-                          v-for="(bItem, bIndex) in scope.row.btnArrJson"
-                          :key="bIndex"
-                          :disabled="!bItem['isEnable']"
-                          >{{ bItem['value'] }}</el-dropdown-item
-                        >
-                      </el-dropdown-menu>
-                    </template>
-                  </el-dropdown>
-                </template>
+              <template v-else-if="currentTab === '160'">
+                <el-button type="primary" icon="Search" @click="lookHandle(scope.row)">
+                  查看
+                </el-button>
+                <el-popconfirm title="是否确定恢复?" @confirm="addINullyApplyHandle(scope.row)">
+                  <template #reference>
+                    <el-button type="warning" icon="RefreshRight"> 恢复 </el-button>
+                  </template>
+                </el-popconfirm>
+                <el-popconfirm
+                  title="是否确定彻底作废?"
+                  @confirm="completelyVoidINullyApplyHandle(scope.row)"
+                >
+                  <template #reference>
+                    <el-button type="warning" icon="RefreshRight"> 彻底作废 </el-button>
+                  </template>
+                </el-popconfirm>
               </template>
             </template>
           </el-table-column>
@@ -90,14 +162,25 @@
 </template>
 
 <script setup lang="ts">
+import { listToTree } from '@/utils/tree'
+import { openFlow } from '@/utils/flow'
 import {
   getHandlerCaseCenterList,
   getHandlerCaseCenterCount,
   getFlowTemplateTreeDataByUser,
-  getFlowTemplateTree
+  getFlowTemplateTree,
+  addTProcessEngine,
+  recoverActivity,
+  addIHangUp,
+  addINullyApply,
+  completelyVoidINullyApply,
+  openOfficeTip,
+  saveAndGetUrl
 } from '@/api/oa/workflow'
-import { tabConfig, TabColumns } from './common'
+import { TabColumns } from './common'
 
+const router = useRouter()
+const message = useMessage()
 const currentTab = ref<string>('1')
 const currentColumn = ref<any[]>(TabColumns[currentTab.value])
 const tableData = ref<any[]>([])
@@ -117,14 +200,14 @@ const sendData = {
   isMobile: false,
   queryMethod: 0,
   toSystemId: '',
-  excludedSystemId: '',
-  page: 1,
-  rows: 15
-}
-const handleCurrentChange = (pageNo: number) => {
-  pageParam.pageNo = pageNo
+  excludedSystemId: ''
 }
+/**
+ * 初始化流程列表
+ */
 const queryHandlerCaseCenterList = () => {
+  sendData['page'] = pageParam['pageNo']
+  sendData['rows'] = pageParam['pageSize']
   const formData = new FormData()
   const keys = Object.keys(sendData)
   for (let key of keys) {
@@ -139,23 +222,230 @@ const queryHandlerCaseCenterList = () => {
       })
     }
     tableData.value = result.rows
+    records.value = result.records
   })
-  getHandlerCaseCenterCount(formData)
 }
 queryHandlerCaseCenterList()
-getFlowTemplateTree()
-const queryFlowTemplateTreeDataByUser = () => {
+const handleCurrentChange = (pageNo: number) => {
+  pageParam['pageNo'] = pageNo
+  queryHandlerCaseCenterList()
+}
+/**
+ *  tab表单汇总统计
+ */
+type TabType = {
+  name: string
+  key: string
+  value: number
+}
+
+const tabList = reactive<TabType[]>([
+  {
+    name: '待办',
+    key: '1',
+    value: 0
+  },
+  {
+    name: '已完成',
+    key: '90',
+    value: 0
+  },
+  {
+    name: '已退回',
+    key: '40',
+    value: 0
+  },
+  {
+    name: '挂起',
+    key: '20',
+    value: 0
+  },
+  {
+    name: '作废',
+    key: '160',
+    value: 0
+  }
+])
+const queryHandlerCaseCenterCount = () => {
+  const formData = new FormData()
+  const keys = Object.keys(sendData)
+  for (let key of keys) {
+    formData.set(key, sendData[key])
+  }
+  getHandlerCaseCenterCount(formData).then((result) => {
+    tabList[0]['value'] = result['NORMAL']
+    tabList[1]['value'] = result['FINISH']
+    tabList[2]['value'] = result['OBSOLETE']
+    tabList[3]['value'] = result['HANG_UP']
+    tabList[4]['value'] = result['CALLBACK']
+  })
+}
+queryHandlerCaseCenterCount()
+//切换tab流程状态选项卡
+const switchTabHandle = (item) => {
+  currentTab.value = item['key']
+  queryFlowTemplateTreeDataByUser(item['key'])
+  sendData['status'] = item['key']
+  pageParam['pageNo'] = 1
+  queryHandlerCaseCenterList()
+}
+/**
+ * 初始化新建流程中流程模板Tree
+ */
+const flowTemplateTree = ref<any>()
+const initFlowTemplateTree = () => {
+  getFlowTemplateTree().then((result) => {
+    flowTemplateTree.value = result.data[0]['children']
+  })
+}
+initFlowTemplateTree()
+
+/**
+ * 通过流程模板发起流程
+ */
+const addTProcessHandle = (item) => {
+  addTProcessEngine(item['id']).then((result) => {
+    router.push({
+      path: '/processContainer',
+      query: {
+        iframe: '1',
+        iFrameId: item['id'],
+        url: result,
+        title: item['name']
+      }
+    })
+  })
+}
+/**
+ * 初始化搜索条件中流程名称Tree结构数据
+ */
+const flowTemplateNameTree = ref<any>()
+const queryFlowTemplateTreeDataByUser = (officeStatus = '1') => {
   const formData = new FormData()
   formData.append('isRight', '0')
-  formData.append('toSystemId', '')
-  formData.append('excludedSystemId', '')
-  formData.append('officeStatus', '1')
-  getFlowTemplateTreeDataByUser(formData)
+  formData.append('toSystemId', '') //后台获取
+  formData.append('excludedSystemId', '') //后台获取
+  formData.append('officeStatus', officeStatus)
+  getFlowTemplateTreeDataByUser(formData).then((result: any) => {
+    flowTemplateNameTree.value = listToTree(result)
+  })
 }
 queryFlowTemplateTreeDataByUser()
 const searchForm = ref({
   name: ''
 })
+const searchHandle = () => {
+  handleCurrentChange(1)
+}
+/***
+ * 双击查看流程详情
+ */
+const dblclickHandle = (item) => {
+  lookHandle(item)
+}
+const isEmpty = (content) => {
+  if (!content || content.replace(/\s*/g, '') == '') {
+    return true
+  } else {
+    return false
+  }
+}
+const lookHandle = (item: any) => {
+  const saveAndGetUrlReqParam = {
+    activityInsId: item['ACTIVITYINSID'],
+    flowInsId: item['FLOWINSID'],
+    particiPantId: item['PARTICIPANTID'],
+    status: item['STATUS'],
+    userId: null,
+    isView: true
+  }
+  //非待办件、委托直接打开
+  if (item['STATUS'] !== '1' && item['STATUS'] !== '2') {
+    saveAndGetUrl(saveAndGetUrlReqParam).then((result: any) => {
+      const officeUrl = result.officeUrl
+      openFlow(router, officeUrl, '流程查看')
+    })
+  } else {
+    openOfficeTip({
+      activityInsId: item['ACTIVITYINSID'],
+      particiPantId: item['PARTICIPANTID'],
+      isView: true
+    }).then((res: any) => {
+      if (!res.msg && res.isTip && !isEmpty(res.tipMsg)) {
+        ElMessageBox.confirm(res.tipMsg, 'Warning', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+          .then(() => {
+            saveAndGetUrl(saveAndGetUrlReqParam).then((result: any) => {
+              const officeUrl = result.officeUrl
+              openFlow(router, officeUrl, '流程查看')
+            })
+          })
+          .catch(() => {})
+      } else {
+        saveAndGetUrl(saveAndGetUrlReqParam).then((result: any) => {
+          const officeUrl = result.officeUrl
+          openFlow(router, officeUrl, '流程查看')
+        })
+      }
+    })
+  }
+}
+/***
+ * 追回
+ */
+const recoverActivityHandle = (item: any) => {
+  recoverActivity({
+    activityInstanceId: item['ACTIVITYINSID'],
+    participantId: item['PARTICIPANTID']
+  }).then((res) => {
+    if (res) {
+      message.success('追回成功!')
+    }
+  })
+}
+
+/***
+ * 解挂
+ */
+const addIHangUpHandle = (item: any) => {
+  addIHangUp({
+    activityInstanceId: item['ACTIVITYINSID'],
+    isRecover: 1
+  }).then((res) => {
+    if (res) {
+      message.success('解挂成功!')
+    }
+  })
+}
+/***
+ * 恢复作废
+ */
+const addINullyApplyHandle = (item: any) => {
+  addINullyApply({
+    activityInstanceId: item['ACTIVITYINSID'],
+    voidFlowInstanceId: item['FLOWINSID'],
+    isRecover: 1
+  }).then((res) => {
+    if (res) {
+      message.success('解挂成功!')
+    }
+  })
+}
+/***
+ * 彻底作废
+ */
+const completelyVoidINullyApplyHandle = (item: any) => {
+  completelyVoidINullyApply({
+    flowInstanceId: item['FLOWINSID']
+  }).then((res) => {
+    if (res) {
+      message.success('解挂成功!')
+    }
+  })
+}
 const tableRef: any = ref(null)
 const tableHeight: any = ref(0)
 onMounted(() => {
@@ -164,6 +454,34 @@ onMounted(() => {
 </script>
 
 <style lang="scss" scoped>
+.flowTemplateBox {
+  white-space: nowrap;
+  padding: 20px;
+  > li {
+    display: inline-block;
+    vertical-align: top;
+    &:not(:first-child) {
+      margin-left: 50px;
+    }
+    > .title {
+      font-weight: bold;
+      font-size: 17px;
+      margin: 0px;
+      color: #333;
+      margin-bottom: 15px;
+      display: block;
+    }
+    > ul {
+      > li {
+        padding: 8px 5px;
+        font-size: 14px;
+        border-radius: 3px;
+        cursor: pointer;
+        color: #333;
+      }
+    }
+  }
+}
 .mainOfficeCenter {
   background-color: #fff;
   padding: 15px;