Browse Source

Merge branch 'feature/H516100' of wanglj/labsop_h5 into master

徐凯 7 months ago
parent
commit
9582d76791

+ 22 - 0
src/api/platform/execution/flow.ts

@@ -0,0 +1,22 @@
+/*
+ * @Author: wanglj 471442253@qq.com
+ * @Date: 2023-07-11 14:13:56
+ * @LastEditors: wanglj
+ * @LastEditTime: 2024-04-07 11:51:12
+ * @Description: file content
+ * @FilePath: \labsop_meno\frontend\packages\scientific\src\api\base\flow.ts
+ */
+import request from '/@/utils/micro_request.js'
+const basePath = import.meta.env.VITE_WORKFLOW
+export function useFlowApi() {
+	return {
+    // 审批流实例详情
+    getFlowInstance(query?: object) {
+      return request.postRequest(basePath, 'Execution', 'GetInstDetailsById', query);
+    },
+    // 首页审批数量
+    getApprovalSum(query?: object) {
+      return request.postRequest(basePath, 'Statistics', 'GetSelfStatistics', query)
+    }
+	};
+}

+ 48 - 0
src/api/platform/execution/index.ts

@@ -0,0 +1,48 @@
+import request from '/@/utils/micro_request.js'
+const basePath = import.meta.env.VITE_WORKFLOW
+const platPath = import.meta.env.VITE_PLATFORM_API
+// 参数设置
+export function useExecutionApi() {
+  return {
+    // 全部
+    getAllList(query: object) {
+      return request.postRequest(basePath,'Execution','GetList', query)
+    },
+    // 我发起的
+    getOwStartList(query: object) {
+      return request.postRequest(basePath,'Execution','GetOwnStartList', query)
+    },
+    // 需要我审批的
+    getOwApproveList(query: object) {
+      return request.postRequest(basePath,'Execution','GetOwnApproveList', query)
+    },
+    // 审批历史
+    getOwnApprovedList(query: object) {
+      return request.postRequest(basePath,'Execution','GetOwnApprovedList', query)
+    },
+    // 抄送我的
+    getOwnCcList(query: object) {
+      return request.postRequest(basePath,'Execution','GetOwnCcList', query)
+    },
+    // 根据ID查询流程实例
+    getInstanceById(query: object) {
+      return request.postRequest(basePath,'Execution','GetInstanceById', query)
+    },
+    // 根据流程id查询流程参与者
+    getParticipantByProcInstID(query: object) {
+      return request.postRequest(basePath,'Execution','GetParticipantByProcInstID', query)
+    },
+    // 审批
+    approve(query?: object) {
+      return request.postRequest(platPath, 'Workflow', 'Approve', query);
+    },
+    // 审批撤回
+    withdraw(query?: object) {
+      return request.postRequest(basePath, 'Execution', 'WithdrawTask', query);
+    },
+    // 批量审批
+    batchApprove(query?: object) {
+      return request.postRequest(platPath, 'Workflow', 'BatchApprove', query);
+    },
+  }
+}

+ 2 - 0
src/view/entry/mine.vue

@@ -269,6 +269,8 @@
       if (err) return
       showOutDialog.value = false
       ElMessage.success('操作成功')
+      state.list = []
+      state.queryParams.pageNum = 1
       onLoad()
     })
   }

+ 225 - 0
src/view/todo/component/approveTasks.vue

@@ -0,0 +1,225 @@
+<template>
+  <div>
+    <el-dialog :title="dialog.title" v-model="dialog.isShowDialog" width="90%">
+      <el-collapse v-model="activeNames">
+        <el-collapse-item name="2" disabled>
+          <template #title>
+            <el-icon class="header-icon"><info-filled /></el-icon>
+            <span>审批意见</span>
+          </template>
+          <el-form ref="formRef" :rules="rules" :model="state.form" label-position="top" label-width="150px" style="padding: 10px 0">
+            <el-form-item label="审批意见" prop="approveOpinion">
+              <el-input
+                v-model="state.form.approveOpinion"
+                type="textarea"
+                :rows="3"
+                resize="none"
+                placeholder="请输入审批意见"
+                clearable
+                style="width: 100%"
+              ></el-input>
+            </el-form-item>
+            <el-form-item label="审批结果" prop="approveResult">
+              <el-radio-group v-model="state.form.approveResult">
+                <el-radio label="pass">通过</el-radio>
+                <el-radio label="rejection">拒绝</el-radio>
+              </el-radio-group>
+            </el-form-item>
+            <el-form-item v-show="state.taskDetail.isFile && state.form.approveResult === 'pass'" label="附件" prop="fileList">
+              <el-upload
+                ref="upload"
+                :file-list="state.form.fileList"
+                :action="uploadUrl"
+                :before-upload="beforeAvatarFileUpload"
+                :on-success="handleSuccess"
+                :limit="1"
+                :on-exceed="handleExceed"
+                style="width: 100%"
+              >
+                <template #trigger>
+                  <el-button type="primary" size="default">点击上传</el-button>
+                </template>
+              </el-upload>
+            </el-form-item>
+          </el-form>
+        </el-collapse-item>
+      </el-collapse>
+      <template #footer>
+        <el-button @click="dialog.isShowDialog = false">取 消</el-button>
+        <el-button type="primary" @click="onSave">提 交</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup lang="ts" name="approvalForm">
+  import to from 'await-to-js'
+  import { nextTick, reactive, ref } from 'vue'
+  import { ElMessage } from 'element-plus'
+  import { useExecutionApi } from '/@/api/platform/execution'
+  import { useDictApi } from '/@/api/system/dict'
+  import type { UploadFile, UploadUserFile, UploadProps, UploadRawFile } from 'element-plus'
+  import { genFileId } from 'element-plus'
+  import { Session } from '/@/utils/storage'
+
+  // 定义变量内容
+  const uploadUrl = import.meta.env.VITE_UPLOAD
+  const upload = ref()
+  const dictApi = useDictApi()
+  const executionApi = useExecutionApi()
+  const riskLevelOption = ref<RowDicDataType[]>([])
+  const activeNames = ref(['1', '2', '3'])
+  const formRef = ref()
+  const dialog = reactive({
+    type: '',
+    isShowDialog: false,
+    title: '',
+    submitTxt: ''
+  })
+  const idList = ref<[]>([])
+  const state = reactive<PatrolMissionState>({
+    taskDetail: {},
+    detail: {},
+    form: {
+      taskId: 0,
+      approveResult: 'pass',
+      approveOpinion: '',
+      fileList: [] as UploadUserFile[],
+      fileUrl: ''
+    },
+    tableData: {
+      data: [],
+      loading: false,
+      param: {
+        id: 0
+      }
+    }
+  })
+  const checkFileUrl = (rule: any, value: any, callback: any) => {
+    if (state.form.isFile && state.form.approveResult === 'pass') {
+      if (!state.form.fileUrl) {
+        callback(new Error('请上传附件'))
+      }
+    } else {
+      callback()
+    }
+  }
+  const rules = {
+    approveResult: [{ required: true, message: '请选择审批结果', trigger: 'blur' }],
+    approveOpinion: [{ required: true, message: '请输入审批意见', trigger: 'blur' }],
+    fileList: [{ validator: checkFileUrl }]
+  }
+  const beforeAvatarFileUpload = (file: any) => {
+    let isLt10m = file.size / 1024 / 1024 / 20 < 1
+    if (!isLt10m) {
+      ElMessage.error('上传文件大小不能超过 20MB!')
+      return false
+    }
+    return true
+  }
+  const handleExceed: UploadProps['onExceed'] = (files) => {
+    upload.value!.clearFiles()
+    const file = files[0] as UploadRawFile
+    file.uid = genFileId()
+    upload.value!.handleStart(file)
+  }
+  const handleSuccess = (res: any, uploadFile: UploadFile) => {
+    state.form.fileUrl = res.Data
+    state.form.fileList = [
+      {
+        name: uploadFile?.name,
+        url: res.Data,
+        uid: uploadFile?.uid
+      }
+    ]
+  }
+
+  // 初始化表格数据
+  const getTableData = async (id: number) => {
+    state.tableData.loading = true
+    state.tableData.param.id = id
+    const [err, res]: ToResponse = await to(executionApi.getParticipantByProcInstID({ id }))
+    if (err) return
+    const arr = res?.data || []
+    state.tableData.data = arr
+    setTimeout(() => {
+      state.tableData.loading = false
+    }, 500)
+  }
+  // 刷新上级列表
+  const emit = defineEmits(['getParentTableDate'])
+
+  // 保存
+  const onSave = async () => {
+    formRef.value.validate(async (valid: any) => {
+      if (valid) {
+        let params = {
+          paramIds: idList.value,
+          result: state.form.approveResult,
+          opinion: state.form.approveOpinion
+        }
+        const [err]: ToResponse = await to(executionApi.batchApprove(params))
+        if (err) return
+        ElMessage({ type: 'success', message: '提交成功' })
+        dialog.isShowDialog = false
+        emit('getParentTableDate')
+      }
+    })
+  }
+  const getDicts = () => {
+    Promise.all([dictApi.getDictDataByType('RiskLevel')]).then(([riskLevel]) => {
+      riskLevelOption.value = riskLevel.data.values
+    })
+  }
+
+  // 打开弹窗
+  const openDialog = (ids: number[]) => {
+    getDicts()
+    idList.value = ids
+    activeNames.value = ['1', '2', '3']
+    dialog.isShowDialog = true
+    nextTick(() => {
+      formRef.value.resetFields()
+    })
+  }
+
+  // 暴露变量
+  defineExpose({
+    openDialog
+  })
+</script>
+
+<style scoped lang="scss">
+  .system-user-container {
+    :deep(.el-card__body) {
+      display: flex;
+      flex-direction: column;
+      flex: 1;
+      overflow: auto;
+
+      .vxe-table {
+        flex: 1;
+      }
+    }
+  }
+
+  .card-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+
+    span {
+      font-size: 18px;
+      font-weight: bold;
+      color: #2c405e;
+    }
+  }
+
+  :deep(.el-descriptions__label) {
+    width: 10%;
+  }
+
+  :deep(.el-descriptions__content) {
+    width: 23%;
+  }
+</style>

+ 71 - 22
src/view/todo/index.vue

@@ -13,38 +13,59 @@
       <van-tab title="我发起的" name="start"></van-tab>
       <van-tab title="审批历史" name="history"></van-tab>
     </van-tabs>
+    <div v-if="state.status === 'approval'" style="padding: 20px 10px 10px 10px; text-align: right">
+      <van-button type="primary" style="height: 30px" @click="handleBatchApproval">批量审批</van-button>
+    </div>
     <div class="list-container">
       <van-list v-model:loading="state.loading" :finished="state.finished" finished-text="没有更多了" @load="onLoad">
-      <van-cell v-for="item in state.list" :key="item" @click="toDetail(item.id)">
-        <template #default>
-          <div class="list">
-            <header class="flex justify-between">
-              <van-text-ellipsis class="title" :content="item.defName" />
-              <van-tag v-if="item.isFinish == '10'" type="warning">已完成</van-tag>
-              <van-tag v-else-if="item.isFinish == '20'" type="primary">未完成</van-tag>
-            </header>
-            <p class="inst-title">
-              <van-text-ellipsis :content="item.instTitle" />
-            </p>
-            <footer class="flex justify-between">
-              <van-text-ellipsis :content="item.candidate" />
-              <span>{{ formatDate(new Date(item.createdTime), 'YYYY-mm-dd') }}</span>
-            </footer>
-          </div>
-        </template>
-      </van-cell>
-    </van-list>
+        <van-checkbox-group v-model="checkedList">
+          <van-cell v-for="item in state.list" :key="item">
+            <template #default>
+              <div class="list">
+                <div @click="toDetail(item.id)">
+                  <header class="flex justify-between">
+                    <van-text-ellipsis class="title" :content="item.defName" />
+                    <van-tag v-if="item.isFinish == '10'" type="warning">已完成</van-tag>
+                    <van-tag v-else-if="item.isFinish == '20'" type="primary">未完成</van-tag>
+                  </header>
+                  <p class="inst-title">
+                    <van-text-ellipsis :content="item.instTitle" />
+                  </p>
+
+                  <p>
+                    <van-text-ellipsis :content="item.candidate" />
+                  </p>
+                </div>
+
+                <footer class="flex justify-between">
+                  <span>{{ formatDate(new Date(item.createdTime), 'YYYY-mm-dd') }}</span>
+                  <van-checkbox v-if="item.isFinish == '20'" :name="item"></van-checkbox>
+                </footer>
+              </div>
+            </template>
+          </van-cell>
+        </van-checkbox-group>
+      </van-list>
     </div>
+
+    <ApprovalTasksForm ref="approvalTasksForm" @getParentTableDate="batchApprovalSuccessCallback" />
   </div>
 </template>
 
 <script name="home" lang="ts" setup>
   import to from 'await-to-js'
-  import { formatDate } from '/@/utils/formatTime'
-  import { onMounted, reactive, ref } from 'vue'
+  import { showNotify } from 'vant'
+  import { onMounted, reactive, ref, defineAsyncComponent } from 'vue'
   import { useRouter, useRoute } from 'vue-router'
+
+  import { formatDate } from '/@/utils/formatTime'
   import { useExecutionApi } from '/@/api/execution'
   import { useNewsApi } from '/@/api/system/news'
+
+  const ApprovalTasksForm = defineAsyncComponent(() => import('/@/view/todo/component/approveTasks.vue'))
+
+  const approvalTasksForm = ref()
+
   const executionApi = useExecutionApi()
   const newsApi = useNewsApi()
   const router = useRouter()
@@ -60,6 +81,8 @@
     loading: true,
     list: [] as any[]
   })
+  const checkedList = ref([])
+
   const onClickRight = () => {
     router.go(-1)
   }
@@ -81,7 +104,7 @@
     }
     if (err) return
     const list = res?.data?.list || []
-    for(const item of list) {
+    for (const item of list) {
       state.list.push(item)
     }
     state.loading = false
@@ -90,6 +113,28 @@
       state.finished = true
     }
   }
+
+  const batchApprovalSuccessCallback = () => {
+    state.list = []
+    checkedList.value = []
+    state.queryParams.pageNum = 1
+    onLoad()
+  }
+
+  const handleBatchApproval = () => {
+    let ids = checkedList.value.map((item) => ({
+      taskId: item.taskId,
+      relId: item.relId
+    }))
+
+    if (ids.length == 0) {
+      showNotify({ type: 'warning', message: '请选择要审批的任务' })
+      return
+    }
+
+    approvalTasksForm.value.openDialog(ids)
+  }
+
   const toDetail = (id: number) => {
     router.push({
       path: '/todo/detail',
@@ -106,6 +151,10 @@
 
 <style lang="scss" scoped>
   .app-container {
+    padding: 0 !important;
+    .list-container {
+      padding: 0 10px;
+    }
     .van-row .van-button {
       flex: 1;
       & + .van-button {