iZaiZaiA 2 years ago
parent
commit
75c2b1a51e

+ 1 - 1
src/api/request/index.js

@@ -6,7 +6,7 @@ import {getToken} from '~src/api/util/auth';
 import {toSerialize} from "vue-utils-plus"
 
 //默认超时时间
-axios.defaults.timeout = 20000;
+axios.defaults.timeout = 300000;
 //返回其他状态码
 axios.defaults.validateStatus = function (status) {
     return status >= 200 && status <= 500;

+ 159 - 0
src/global/components/hc-sms-auth/index.vue

@@ -0,0 +1,159 @@
+<template>
+    <el-dialog v-model="showModal" title="短信认证" width="26rem" class="hc-modal-border">
+        <el-form ref="reportFormRef" :model="reportModel" :rules="reportRules" label-width="auto" size="large">
+            <el-form-item label="手机号码">
+                <el-input v-model="phoneVal" placeholder="手机号码" disabled/>
+            </el-form-item>
+            <el-form-item class="hc-input-button-group" label="验证码" prop="code">
+                <el-input v-model="reportModel.code" placeholder="请输入验证码"/>
+                <el-button type="primary" size="large" @click="getCodeClick" :disabled="isDisabled">
+                    {{isDisabled ? '倒计时' + currentTime + 's' : '获取验证码'}}
+                </el-button>
+            </el-form-item>
+        </el-form>
+        <template #footer>
+            <div class="dialog-footer">
+                <el-button size="large" @click="cancelClick">
+                    <HcIcon name="close"/>
+                    <span>取消</span>
+                </el-button>
+                <el-button type="primary" hc-btn :loading="isLoading" @click="confirmClick">
+                    <HcIcon name="check"/>
+                    <span>确认</span>
+                </el-button>
+            </div>
+        </template>
+    </el-dialog>
+</template>
+
+<script setup>
+import {ref, watch} from "vue"
+import {useAppStore} from "~src/store";
+import {sendNotice} from '~api/other';
+import config from '~src/config/index';
+import {formValidate} from "vue-utils-plus"
+//参数
+const props = defineProps({
+    show: {
+        type: Boolean,
+        default: false
+    },
+    loading: {
+        type: Boolean,
+        default: false
+    },
+})
+
+//变量
+const userStore = useAppStore()
+const userInfo = ref(userStore.getUserInfo);
+const phoneVal = ref(config.smsPhone + '' || userInfo.value.phone + '')
+const showModal = ref(props.show)
+const isLoading = ref(props.loading)
+
+//监听
+watch(() => [
+    props.show,
+    props.loading,
+    userStore.getUserInfo
+], ([show,  loading, user]) => {
+    userInfo.value = user
+    showModal.value = show
+    isLoading.value = loading
+})
+
+//返回的验证码
+const resCode = ref('')
+//表单
+const reportFormRef = ref(null)
+const reportModel = ref({code: null})
+const reportRules = ref({
+    code: {
+        required: true,
+        validator: (rule, value, callback) => {
+            const code = resCode.value ?? ''
+            if (!code) {
+                callback(new Error('请先获取验证码'))
+            } else if (!value) {
+                callback(new Error('请输入验证码'))
+            } else if (code !== value) {
+                callback(new Error('验证码错误'))
+            } else {
+                callback()
+            }
+        },
+        trigger: "blur",
+    },
+})
+
+//短信验证码
+const isDisabled = ref(false)   //是否开启倒计时
+const totalTime = 60                  //总时间,单位秒
+const recordingTime = ref(0)    //记录时间变量
+const currentTime = ref(0)      //显示时间变量
+
+//获取短信验证码
+const getCodeClick = async () => {
+    const {error, code, msg} = await sendNotice({
+        phone: phoneVal.value
+    },false)
+    //处理数据
+    if (!error && code === 200 && msg) {
+        resCode.value = msg
+        //把显示时间设为总时间
+        currentTime.value = totalTime
+        //开始倒计时
+        isDisabled.value = true
+        //执行倒计时
+        checkingTime();
+        window?.$message?.success('发送成功')
+    } else {
+        resCode.value = ''
+        window?.$message?.error('发送失败')
+    }
+}
+
+//倒计时
+const checkingTime = () => {
+    //判断是否开启
+    if (isDisabled.value) {
+        //判断显示时间是否已到0,判断记录时间是否已到总时间
+        if (currentTime.value > 0 && recordingTime.value <= totalTime) {
+            //记录时间增加 1
+            recordingTime.value ++;
+            //显示时间,用总时间 - 记录时间
+            currentTime.value = totalTime - recordingTime.value;
+            //1秒钟后,再次执行本方法
+            setTimeout(() => {
+                checkingTime();
+            }, 1000)
+        } else {
+            //时间已完成,还原相关变量
+            isDisabled.value = false;		//关闭倒计时
+            recordingTime.value = 0;	//记录时间为0
+            currentTime.value = totalTime;	//显示时间为总时间
+        }
+    } else {
+        //倒计时未开启,初始化默认变量
+        isDisabled.value = false;
+        recordingTime.value = 0;
+        currentTime.value = totalTime;
+    }
+}
+
+//事件
+const emit = defineEmits(['cancel', 'confirm'])
+
+//取消
+const cancelClick = () => {
+    emit('cancel')
+}
+
+//确认
+const confirmClick = async () => {
+    const validate = await formValidate(reportFormRef.value)
+    if (!validate) {
+        emit('confirm')
+    }
+}
+</script>

+ 2 - 0
src/global/components/index.js

@@ -7,6 +7,7 @@ import HcDrawer from './hc-drawer/index.vue'
 import HcUploads from './hc-uploads/index.vue'
 import HcCounter from './hc-counter/index.vue'
 import HcTooltip from './hc-tooltip/index.vue'
+import HcSmsAuth from './hc-sms-auth/index.vue'
 import HcMenuSimple from './hc-menu-simple/index.vue'
 import HcDatePicker from './hc-date-picker/index.vue'
 import HcNewSwitch from './hc-new-switch/index.vue'
@@ -27,6 +28,7 @@ export const setupComponents = (App) => {
     App.component('HcUploads', HcUploads)
     App.component('HcCounter', HcCounter)
     App.component('HcTooltip', HcTooltip)
+    App.component('HcSmsAuth', HcSmsAuth)
     App.component('HcMenuSimple', HcMenuSimple)
     App.component('HcDatePicker', HcDatePicker)
     App.component('HcNewSwitch', HcNewSwitch)

+ 14 - 0
src/styles/app/element.scss

@@ -428,6 +428,20 @@
     box-shadow: 0 0 0 1px var(--el-color-danger) inset;
 }
 
+//表单输入框和按钮组合
+.el-form-item.hc-input-button-group .el-form-item__content {
+    .el-input {
+        flex: 1;
+        .el-input__wrapper {
+            border-radius: 4px 0 0 4px;
+        }
+    }
+    .el-button {
+        border-radius: 0 4px 4px 0;
+    }
+}
+
+
 //设置表单样式
 .hc-table-form-box {
     td {

+ 48 - 0
src/styles/tasks/hc-data.scss

@@ -17,3 +17,51 @@
         width: 126px;
     }
 }
+
+.hc-card-body-flex {
+    position: relative;
+    display: flex;
+    width: 100%;
+    height: 100%;
+    .flex-iframe {
+        flex: 1;
+        position: relative;
+        height: 100%;
+        border:1px solid #777;
+        overflow: hidden;
+        iframe {
+            height: 100%;
+        }
+        &.hc-no-table-form {
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            .table-form-no {
+                position: relative;
+                img {
+                    width: 350px;
+                }
+                .desc {
+                    text-align: center;
+                    font-size: 20px;
+                    color: #aaa;
+                }
+            }
+        }
+    }
+    .flex-table {
+        position: relative;
+        margin-left: 24px;
+        width: 40%;
+        height: 100%;
+        display: flex;
+        flex-direction: column;
+        .data-table {
+            position: relative;
+            flex: 1;
+        }
+        .radio-group-box {
+            margin: 10px 0;
+        }
+    }
+}

+ 8 - 3
src/views/tasks/components/TableCard.vue

@@ -303,8 +303,8 @@ const tableSelectionChange = (rows) => {
 const emit = defineEmits(['rowTaskName','signRules','batchApproval'])
 
 //任务审核
-const rowTaskName = () => {
-    emit('rowTaskName', {})
+const rowTaskName = (row) => {
+    emit('rowTaskName', row)
 }
 
 //设置重签规则
@@ -314,7 +314,12 @@ const setSignRulesClick = () => {
 
 //批量审批
 const batchApprovalTaskClick = () => {
-    emit('batchApproval', {})
+    const rows = tableCheckedKeys.value
+    if (rows.length > 0) {
+        emit('batchApproval', rows)
+    } else {
+        window?.$message?.warning('请先勾选需要审批的数据')
+    }
 }
 </script>
 

+ 239 - 7
src/views/tasks/hc-data.vue

@@ -14,7 +14,51 @@
                            @rowTaskName="rowTaskName" @signRules="setSignRulesClick" @batchApproval="batchApprovalTaskClick"/>
             </template>
         </HcTabsSimple>
+
         <!--任务审核-->
+        <el-dialog v-model="showTaskReviewModal" width="80vw" class="hc-modal-border hc-modal-table">
+            <template #header="{ titleId, titleClass }">
+                <div class="hc-card-header flex items-center">
+                    <div :id="titleId" :class="titleClass">任务审核 【已开启电签】</div>
+                    <div class="ml-6 font-bold text-main" v-if="taskReviewType === '1'">任务名称:{{taskReviewInfo.taskName}}</div>
+                </div>
+            </template>
+            <div class="hc-card-body-flex">
+                <div class="flex-iframe" v-if="batchPdfUrl">
+                    <iframe width='100%' height='100%' frameborder='1' :src="batchPdfUrl"></iframe>
+                </div>
+                <div class="flex-iframe hc-no-table-form" v-else>
+                    <div class="table-form-no">
+                        <img :src="notableform" alt=""/>
+                        <div class="desc">暂无 PDF 数据</div>
+                    </div>
+                </div>
+                <div class="flex-table" :class="sbTableKey === 'key1'?'':'vh'">
+                    <div class="data-table" v-if="taskReviewType==='1'">
+                        <HcTable :column="taskReviewColumns" :datas="taskReviewData" @row-click="rowTaskReviewClick"/>
+                    </div>
+                    <div class="data-table" v-if="taskReviewType==='2'">
+                        <HcTable :column="checkedRowsColumns" :datas="checkedRowsRef" @row-click="rowTaskReviewClick"/>
+                    </div>
+                    <div class="radio-group-box" v-if="sbTableKey === 'key1'">
+                        <span class="label">审批操作:</span>
+                        <el-radio-group v-model="taskReviewForm.flag">
+                            <el-radio label="OK">同意</el-radio>
+                            <el-radio label="NO">废除任务</el-radio>
+                        </el-radio-group>
+                    </div>
+                    <div class="textarea-box" v-if="sbTableKey === 'key1'">
+                        <el-input type="textarea" v-model="taskReviewForm.comment" placeholder="请输入审核意见" :autosize="{ minRows: 3, maxRows: 5 }"/>
+                    </div>
+                </div>
+            </div>
+            <template #footer>
+                <div class="dialog-footer">
+                    <el-button size="large" @click="showTaskReviewModal = false">取消</el-button>
+                    <el-button type="primary" hc-btn :loading="SMSAuthLoading" @click="ConfirmApprovalClick">确认审批</el-button>
+                </div>
+            </template>
+        </el-dialog>
 
         <!--设置重签规则-->
         <el-dialog v-model="showSetSignRulesModal" title="设置重签规则" width="38rem" class="hc-modal-border">
@@ -39,6 +83,9 @@
                 </div>
             </template>
         </el-dialog>
+
+        <!--短信认证-->
+        <HcSmsAuth :show="SMSAuthShow" :loading="SMSAuthLoading" @cancel="SMSAuthCancel" @confirm="SMSAuthConfirm"/>
     </div>
 </template>
 
@@ -47,14 +94,15 @@ import {ref, onMounted} from "vue";
 import {useAppStore} from "~src/store";
 import {useRouter, useRoute} from 'vue-router'
 import TableCard from './components/TableCard.vue';
-import {isType, formValidate, deepClone} from "vue-utils-plus"
+import notableform from '~src/assets/view/notableform.svg';
+import {getObjValue, getArrValue, isString} from "vue-utils-plus"
 import tasksApi from '~api/tasks/data';
+import dayjs from "dayjs"
 
 //初始变量
 const router = useRouter()
 const useRoutes = useRoute()
 const useAppState = useAppStore()
-const { getObjValue,  getArrValue } = isType()
 
 //路由参数
 const routerQuery = useRoutes?.query;
@@ -87,9 +135,197 @@ const sbTableClick = (key) => {
     })
 }
 
+//审批页详情
+const showTaskReviewModal = ref(false)
+const taskReviewType = ref('1')
+const taskReviewInfo = ref({})
+const taskReviewData = ref([])
+const batchPdfUrl = ref('')
+const taskReviewForm = ref({flag: 'OK', comment: ''})
+const taskReviewColumns = ref([
+    {key:'fileName', name: '文件名称'}
+])
 //任务审核
-const rowTaskName = () => {
+const rowTaskName = async (row) => {
+    if (row.formDataId) {
+        taskReviewInfo.value = row
+        const { error, code, data } = await tasksApi.queryApprovalParameter({
+            parallelProcessInstanceId: row['parallelProcessInstanceId'],
+            formDataId: row.formDataId,
+            approvalType: row.approvalType,
+        })
+        if (!error && code === 200) {
+            const approvalFileList = getArrValue(data['approvalFileList'])
+            taskReviewData.value = approvalFileList
+            if (approvalFileList.length > 0) {
+                batchPdfUrl.value = approvalFileList[0].fileUrl
+            }
+            taskReviewType.value = '1'
+            showTaskReviewModal.value = true
+        } else {
+            taskReviewData.value = []
+            batchPdfUrl.value = ''
+        }
+    } else {
+        taskReviewInfo.value = {}
+        taskReviewData.value = []
+        batchPdfUrl.value = ''
+        window?.$message?.warning('此数据异常')
+    }
+}
+
+//批量审批
+const checkedRowsColumns = ref([
+    {key:'taskName', name: '任务名称'}
+])
+const checkedRowsRef = ref([])
+const batchApprovalTaskClick = (rows) => {
+    taskReviewType.value = '2'
+    showTaskReviewModal.value = true
+    queryTaskInfo(rows[0])
+}
 
+//行被点击
+const rowTaskReviewClick = async (row) => {
+    const type = taskReviewType.value
+    if (type === '1') {
+        batchPdfUrl.value = row.fileUrl
+    } else if (row['hc_batchPdfUrl']) {
+        batchPdfUrl.value = row['hc_batchPdfUrl']
+    } else {
+        queryTaskInfo(row)
+    }
+}
+
+//获取PDF数据
+const queryTaskInfo = async (row) => {
+    const { error, code, data } = await tasksApi.queryTaskInfo({
+        formDataId: row['formDataId'] || '',
+        approvalType: row['approvalType']
+    })
+    //处理数据
+    if (!error && code === 200) {
+        const approvalFileList = getArrValue(data['approvalFileList'])
+        if (approvalFileList.length > 0) {
+            batchPdfUrl.value = approvalFileList[0].fileUrl
+            row['hc_batchPdfUrl'] = approvalFileList[0].fileUrl
+        } else {
+            batchPdfUrl.value = ''
+            row['hc_batchPdfUrl'] = ''
+            window?.$message?.warning('PDF获取异常')
+        }
+    } else {
+        batchPdfUrl.value = ''
+        row['hc_batchPdfUrl'] = ''
+        window?.$message?.warning(data.msg || 'PDF异常')
+    }
+}
+
+//确认审批
+const ConfirmApprovalClick = () => {
+    const formData = taskReviewForm.value
+    if (formData.flag === 'NO' && !formData.comment) {
+        window?.$message?.warning('请先输入审核意见')
+    } else {
+        const ShowAuth = isCheckSmsCodeTime()
+        SMSAuthShow.value = ShowAuth
+        //免短信验证
+        if (!ShowAuth) {
+            SMSAuthConfirm()
+        }
+    }
+}
+
+//短信验证有效期
+const smsCodeTime = ref('')
+const checkSmsCode = async () => {
+    const {error, code, data} = await tasksApi.checkSmsCode()
+    //处理数据
+    if (!error && code === 200) {
+        smsCodeTime.value = isString(data) ? data : '';
+    } else {
+        smsCodeTime.value = '';
+    }
+}
+
+//验证短信有效期
+const isCheckSmsCodeTime = () => {
+    const smsTime = smsCodeTime.value;
+    if (!smsTime) {
+        return true
+    } else {
+        const toDayTime = dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss')
+        return dayjs(smsTime).isBefore(toDayTime)
+    }
+}
+
+//短信验证
+const SMSAuthLoading = ref(false)
+const SMSAuthShow = ref(false)
+const SMSAuthConfirm = () => {
+    const type = taskReviewType.value
+    if (type === '1') {
+        saveCompleteApprovalTask()
+    } else {
+        batchCompleteApprovalTask()
+    }
+    checkSmsCode()
+}
+const SMSAuthCancel = () => {
+    SMSAuthShow.value = false
+}
+
+//单个审批
+const saveCompleteApprovalTask = async () => {
+    const DataInfo = taskReviewInfo.value
+    SMSAuthLoading.value = true
+    const {error, code} = await tasksApi.saveCompleteApprovalTask({
+        ...taskReviewForm.value,
+        taskId: DataInfo['taskId'] || '',
+        parallelProcessInstanceId: DataInfo['parallelProcessInstanceId'] || '',
+        formDataId: DataInfo['formDataId'] || '',
+        approvalType: DataInfo['approvalType']
+    },false)
+    //处理数据
+    SMSAuthLoading.value = false
+    if (!error && code === 200) {
+        SMSAuthShow.value = false
+        showTaskReviewModal.value = false
+        window?.$message?.success('审批成功')
+        window?.location?.reload()  //刷新页面
+    } else {
+        window?.$message?.warning('审批异常')
+    }
+}
+
+//批量审批
+const batchCompleteApprovalTask = async() => {
+    const rows = checkedRowsRef.value
+    SMSAuthLoading.value = true
+    let taskIds = rowsToId(rows,'taskId')
+    let parallelProcessInstanceIds = rowsToId(rows,'parallelProcessInstanceId')
+    const {error, code} = await tasksApi.batchCompleteApprovalTask({
+        ...taskReviewForm.value,
+        taskIds,
+        parallelProcessInstanceIds
+    },false)
+    //处理数据
+    SMSAuthLoading.value = false
+    if (!error && code === 200) {
+        SMSAuthShow.value = false
+        showTaskReviewModal.value = false
+        window?.$message?.success('审批成功')
+        window?.location?.reload()  //刷新页面
+    } else {
+        window?.$message?.warning('审批出错')
+    }
+}
+
+//拼接ID
+const rowsToId = (rows,key) => {
+    return rows.map((obj) => {
+        return obj['key'];
+    }).join(",")
 }
 
 //设置重签规则
@@ -101,10 +337,6 @@ const setSignRulesClick = () => {
 }
 const dateUpdateValue = (val) => {
     formReport.value.date = val
-}
-//批量审批
-const batchApprovalTaskClick = () => {
-
 }
 </script>