浏览代码

上报弹窗增加

duy 3 月之前
父节点
当前提交
4af39595b8

+ 229 - 0
src/views/transfer/components/HcReport.vue

@@ -0,0 +1,229 @@
+<template>
+    <hc-new-dialog v-model="isShow" title="批量上报" widths="47rem" @close="cancelReportClick">
+        <el-form ref="formRef" :model="formModel" :rules="formRules" label-width="auto" size="large">
+            <el-form-item label="任务名称" prop="taskName">
+                <el-input v-model="formModel.taskName" disabled />
+            </el-form-item>
+            <el-form-item label="任务描述" prop="taskContent">
+                <el-input v-model="formModel.taskContent" :autosize="{ minRows: 3, maxRows: 5 }" placeholder="请输入任务描述" type="textarea" />
+            </el-form-item>
+            <el-form-item label="任务流程" prop="fixedFlowId">
+                <el-select v-model="formModel.fixedFlowId" block @change="handleProcessValue">
+                    <template v-for="item in processData" :key="item.id">
+                        <el-option :disabled="item.disabled" :label="item.fixedFlowName" :value="item.id" />
+                    </template>
+                </el-select>
+            </el-form-item>
+            <el-form-item v-if="diyProcessUser" label="任务人" prop="userIds">
+                <HcTasksUserVue class="w-full" @change="diyProcessUserChange" />
+            </el-form-item>
+            <el-form-item v-else label="任务人">
+                <div class="form-item-div">{{ linkUserJoinString }}</div>
+            </el-form-item>
+            <el-form-item label="上报批次">
+                <HcCounter v-model="formModel.batch" />
+            </el-form-item>
+            <el-form-item label="限定审批时间">
+                <HcCounter v-model="formModel.restrictDay" text="(天)" />
+            </el-form-item>
+        </el-form>
+        <template #footer>
+            <div class="dialog-footer">
+                <el-button @click="cancelReportClick">取消</el-button>
+                <el-button :loading="formReportLoading" hc-btn type="primary" @click="formReportClick">提交</el-button>
+            </div>
+        </template>
+    </hc-new-dialog>
+</template>
+
+<script setup>
+import { ref, watch } from 'vue'
+import tasksFlowApi from '~api/tasks/flow'
+import { arrIndex, arrToKey, formValidate, getArrValue } from 'js-fast-way'
+import HcTasksUserVue from './hc-tasks-user/index.vue'
+import { useAppStore } from '~src/store'
+
+const props = defineProps({
+    show: {
+        type: Boolean,
+        default: false,
+    },
+    data: {
+        type: Array,
+        default: () => ([]),
+    },
+})
+
+const emit = defineEmits(['hide', 'finish'])
+
+//初始变量
+const useAppState = useAppStore()
+const projectId = ref(useAppState.getProjectId)
+const contractId = ref(useAppState.getContractId)
+const isShow = ref(props.show)
+
+const formModel = ref({ batch: 1, restrictDay: 1 })
+
+//监听
+watch(() => [
+    props.projectId,
+    props.contractId,
+
+], ([pid, cid]) => {
+    projectId.value = pid
+    contractId.value = cid
+
+
+})
+
+//监听
+watch(() => props.show, (val) => {
+    isShow.value = val
+    setReportData(val)
+})
+
+
+//表单
+const formRef = ref(null)
+
+const formRules = ref({
+    taskContent: {
+        required: false,
+        trigger: 'blur',
+        message: '请输入任务描述',
+    },
+    fixedFlowId: {
+        required: true,
+        trigger: 'blur',
+        message: '请选择任务流程',
+    },
+    userIds: {
+        required: true,
+        trigger: 'blur',
+        message: '请选择任务人',
+    },
+})
+
+//处理上报数据
+const setReportData = (show) => {
+    if (!show) return false
+    let taskName = '', ids = ''
+    for (let i = 0; i < props.data.length; i++) {
+        const item = props.data[i]
+        ids = ids ? `${ids},${item.id}` : item.id
+        taskName = taskName ? `${taskName},${item.fileName}` : item.fileName
+    }
+    formModel.value.dataIds = ids
+    formModel.value.taskName = taskName
+    //获取任务流程
+    processData.value = []
+    getProcessDatasApi()
+}
+
+//获取流程数据
+const processDefaultData = [{ id: 0, fixedFlowName: '自定义流程', disabled: false }]
+const processData = ref([])
+
+const getProcessDatasApi = () => {
+    if (isShow.value) {
+        getProcessData()
+    }
+}
+
+//获取流程数据
+const linkUserJoinString = ref('')
+const getProcessData = async () => {
+    linkUserJoinString.value = ''
+    const { error, code, data } = await tasksFlowApi.getPageData({
+        projectId: projectId.value,
+        contractId: contractId.value,
+        current: 1, size: 100,
+    })
+    if (!error && code === 200) {
+        const arr = getArrValue(data['records'])
+        processData.value = [...processDefaultData, ...arr]
+    } else {
+        processData.value = processDefaultData
+    }
+}
+
+//流程数据切换
+const diyProcessUser = ref(false)
+const handleProcessValue = (val) => {
+    if (val > 0) {
+        diyProcessUser.value = false
+        const list = processData.value
+        const index = arrIndex(list, 'id', val)
+        linkUserJoinString.value = list[index]?.linkUserJoinString
+    } else {
+        linkUserJoinString.value = ''
+        diyProcessUser.value = true
+    }
+}
+
+//自定义流程任务人选择完毕
+const diyProcessUserChange = (user) => {
+    let userArr = user
+    formModel.value.userIds = arrToKey(userArr, 'userId', ',')
+}
+
+//取消
+const cancelReportClick = () => {
+    linkUserJoinString.value = ''
+    isShow.value = false
+    emit('hide', false)
+    formModel.value.taskContent = ''
+    formModel.value.fixedFlowId = ''
+
+
+}
+
+//上报
+const formReportClick = async () => {
+    const res = await formValidate(formRef.value)
+    if (res) await batchApprovalApi()
+}
+
+//上报请求
+const formReportLoading = ref(false)
+const batchApprovalApi = async () => {
+    formReportLoading.value = true
+    //发起请求
+    const { error, code, data } = await tasksFlowApi.batchReportTaskArchive({
+        ...formModel.value,
+        contractId: contractId.value,
+        projectId: projectId.value,
+    })
+    linkUserJoinString.value = ''
+    formReportLoading.value = false
+    if (!error && code === 200) {
+        isShow.value = false
+        window.$message?.success('上报成功')
+        emit('hide', false)
+        emit('finish', data)
+    } else {
+        processData.value = []
+    }
+    emit('hide', false)
+    emit('finish')
+    formModel.value.taskContent = ''
+    formModel.value.fixedFlowId = ''
+}
+</script>
+
+<style lang="scss">
+.task-tag-data-box {
+    position: relative;
+    border: 1px solid #e0e0e6;
+    border-radius: 4px;
+    padding: 5px;
+    min-height: 40px;
+    display: flex;
+    align-items: center;
+    flex-flow: row wrap;
+    width: 100%;
+    .el-tag {
+        margin: 5px;
+    }
+}
+</style>

+ 340 - 0
src/views/transfer/components/hc-tasks-user/index.vue

@@ -0,0 +1,340 @@
+<template>
+    <div class="hc-tasks-user">
+        <div class="tasks-user-box">
+            <div class="tag-user-list" @click="showModalClick">
+                <template v-for="(item, index) in UserDataList" :key="index">
+                    <el-tag>{{ setCheckboxUserName(item) }}</el-tag>
+                    <HcIcon v-if="(UserDataList.length - 1) > index" name="arrow-right" ui="arrow-icon-tag" />
+                </template>
+                <div v-if="UserDataList.length <= 0" class="tasks-placeholder">点击这里选择任务人</div>
+            </div>
+        </div>
+
+        <!-- 选择任务人 -->
+        <el-dialog v-model="showModal" class="hc-modal-border hc-modal-nop" destroy-on-close draggable title="选择任务人" width="62rem">
+            <div class="hc-tasks-user-modal-content-box">
+                <div class="tree-box">
+                    <el-scrollbar>
+                        <ElTree
+                            v-if="isShowTree" :data="ElTreeData" :default-expanded-keys="[0]" :props="ElTreeProps"
+                            accordion
+                            class="hc-tree-node-box" highlight-current node-key="roleId" @node-click="ElTreeNodeClick"
+                        />
+                    </el-scrollbar>
+                </div>
+                <div class="user-box">
+                    <div class="y-user-list-box">
+                        <div class="title-box">
+                            <div class="title">可选择</div>
+                        </div>
+                        <div class="user-list">
+                            <el-scrollbar>
+                                <el-checkbox-group v-model="checkboxUserList">
+                                    <template v-for="(item, index) in signUserList" :key="index">
+                                        <div class="user-item checkbox-li">
+                                            <el-checkbox :value="`${item.certificateUserName}-${item.certificateUserId}`">
+                                                <div class="item-user-name">{{ item.certificateUserName }}</div>
+                                            </el-checkbox>
+                                        </div>
+                                    </template>
+                                </el-checkbox-group>
+                            </el-scrollbar>
+                        </div>
+                    </div>
+                    <div class="s-user-list-box">
+                        <div class="title-box">
+                            <div class="title">已选择({{ checkboxUserList.length }})</div>
+                            <el-button plain size="small" @click="sequenceModal = true">调整顺序</el-button>
+                        </div>
+                        <div class="user-list">
+                            <el-scrollbar>
+                                <template v-for="(item, index) in checkboxUserList" :key="index">
+                                    <el-tag closable @close="delCheckboxUser(index)">{{ setCheckboxUserName(item) }}</el-tag>
+                                </template>
+                            </el-scrollbar>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <template #footer>
+                <div class="dialog-footer">
+                    <el-button size="large" @click="showModal = false">
+                        <HcIcon name="close" />
+                        <span>取消</span>
+                    </el-button>
+                    <el-button :loading="sureSignUserLoading" hc-btn type="primary" @click="sureSignUserClick">
+                        <HcIcon name="check" />
+                        <span>确定</span>
+                    </el-button>
+                </div>
+            </template>
+        </el-dialog>
+
+        <!-- 调整顺序 -->
+        <el-dialog v-model="sequenceModal" append-to-body class="hc-modal-border" destroy-on-close draggable title="调整顺序" width="38rem">
+            <el-alert :closable="false" title="可拖动排序,也可在后面点击图标,切换排序" type="warning" />
+            <div class="sort-node-body-box list-group header">
+                <div class="list-group-item">
+                    <div class="index-box">序号</div>
+                    <div class="title-box">任务人</div>
+                    <div class="icon-box">排序</div>
+                </div>
+            </div>
+            <Draggable :list="checkboxUserList" class="sort-node-body-box list-group" ghost-class="ghost" item-key="id" @end="sortNodeDrag = false" @start="sortNodeDrag = true">
+                <template #item="{ element, index }">
+                    <div class="list-group-item">
+                        <div class="index-box">{{ index + 1 }}</div>
+                        <div class="title-box">{{ setCheckboxUserName(element) }}</div>
+                        <div class="icon-box">
+                            <span class="icon" @click="downSortClick(index)">
+                                <HcIcon name="arrow-down" ui="text-lg" />
+                            </span>
+                            <span class="icon" @click="upSortClick(index)">
+                                <HcIcon name="arrow-up" ui="text-lg" />
+                            </span>
+                        </div>
+                    </div>
+                </template>
+            </Draggable>
+            <template #footer>
+                <div class="dialog-footer">
+                    <el-button size="large" @click="sequenceModal = false">取消</el-button>
+                    <el-button hc-btn type="primary" @click="sequenceModal = false">确认</el-button>
+                </div>
+            </template>
+        </el-dialog>
+    </div>
+</template>
+
+<script setup>
+import { onMounted, ref, watch } from 'vue'
+import tasksFlowApi from '~api/tasks/flow'
+import { deepClone, getArrValue } from 'js-fast-way'
+import { useAppStore } from '~src/store'
+import Draggable from 'vuedraggable'
+
+//参数
+const props = defineProps({
+    users: {
+        type: String,
+        default: '',
+    },
+})
+
+//事件
+const emit = defineEmits(['change'])
+
+//初始变量
+const useAppState = useAppStore()
+const projectId = ref(useAppState.getProjectId)
+const contractId = ref(useAppState.getContractId)
+
+
+//变量
+const showModal = ref(false)
+const sequenceModal = ref(false)
+const checkboxUserList = ref([])
+const UserDataList = ref([])
+
+//树数据
+const ElTreeProps = { children: 'childRoleList', label: 'roleName' }
+const ElTreeData = ref([{
+    roleName: '全部人员',
+    roleId: 0,
+    childRoleList: [],
+    signPfxFileList: [],
+}])
+const isShowTree = ref(true)
+//监听
+watch(() => [
+    props.users,
+    props.projectId,
+    props.contractId,
+], ([users, pid, cid]) => {
+    projectId.value = pid
+    contractId.value = cid
+    setUserDataList(users)
+})
+
+//渲染完成
+onMounted(() => {
+    setUserDataList(props.users)
+    queryAllRoleList()
+})
+
+//处理用户数据
+const setUserDataList = (users) => {
+    if (users) {
+        const usersArr = users.split(',')
+        UserDataList.value = usersArr
+        checkboxUserList.value = usersArr
+    } else {
+        UserDataList.value = []
+        checkboxUserList.value = []
+    }
+}
+
+//展开弹窗
+const showModalClick = () => {
+    showModal.value = true
+}
+
+//获取系统所有角色划分
+const signUserList = ref([])
+const queryAllRoleList = async () => {
+    isShowTree.value = false
+    const { error, code, data } = await tasksFlowApi.queryAllRoleList({
+        contractId: contractId.value,
+    })
+    isShowTree.value = true
+    //处理数据
+    if (!error && code === 200) {
+        let signList = [], dataArr = getArrValue(data)
+        ElTreeData.value[0].childRoleList = dataArr
+        if (dataArr.length > 0) {
+            dataArr.forEach(item => {
+                signList = signList.concat(item.signPfxFileList)
+            })
+        }
+        ElTreeData.value[0].signPfxFileList = signList
+        signUserList.value = signList
+    } else {
+        signUserList.value = []
+        ElTreeData.value[0].childRoleList = []
+        ElTreeData.value[0].signPfxFileList = []
+    }
+}
+
+//树被点击
+const ElTreeNodeClick = (data) => {
+    signUserList.value = getArrValue(data?.signPfxFileList)
+}
+
+//处理已选择的用户问题
+const setCheckboxUserName = (item) => {
+    if (item) {
+        const itemArr = item.split('-')
+        if (itemArr.length > 0 && itemArr[0]) {
+            return itemArr[0]
+        } else {
+            return ''
+        }
+    } else {
+        return ''
+    }
+}
+
+//删除已选择的用户
+const delCheckboxUser = (index) => {
+    checkboxUserList.value.splice(index, 1)
+}
+
+//排序
+const sortNodeDrag = ref(false)
+//向下
+const downSortClick = (index) => {
+    const indexs = index + 1
+    const data = checkboxUserList.value
+    if (indexs !== data.length) {
+        const tmp = data.splice(indexs, 1)
+        checkboxUserList.value.splice(index, 0, tmp[0])
+    } else {
+        window?.$message?.warning('已经处于置底,无法下移')
+    }
+}
+//向上
+const upSortClick = (index) => {
+    const data = checkboxUserList.value || []
+    if (index !== 0) {
+        const tmp = data.splice(index - 1, 1)
+        checkboxUserList.value.splice(index, 0, tmp[0])
+    } else {
+        window?.$message?.warning('已经处于置顶,无法上移')
+    }
+}
+
+//确认选择
+const sureSignUserLoading = ref(false)
+const sureSignUserClick = async () => {
+    let flowJson = {}, newUser = [], newUserId = [], users = ''
+    const dataList = deepClone(checkboxUserList.value)
+    UserDataList.value = dataList
+    if (dataList.length <= 0) {
+        window.$message?.warning('请先选择任务人员,或点击取消')
+        return false
+    }
+    sureSignUserLoading.value = true
+    //封装数据
+    dataList.forEach(item => {
+        const itemArr = item.split('-')
+        if (itemArr.length > 0 && itemArr[0]) {
+            users = users ? `${users},${item}` : item
+            newUser.push({
+                userId: itemArr[1],
+                userName: itemArr[0],
+            })
+            newUserId.push(itemArr[1])
+        }
+    })
+    //效验人员
+
+
+    const { error, code, data, msg } = await tasksFlowApi.checkTaskUserCertificateInfo({
+        userIds: newUserId.join(','),
+    })
+    if (!error && code === 200) {
+        emit('change', newUser, newUserId, users)
+        //关闭弹窗
+        showModal.value = false
+    } else {
+        window.$message?.error(msg || '操作失败')
+    }
+
+    sureSignUserLoading.value = false
+
+}
+</script>
+
+<style lang="scss" scoped>
+@import './style.scss';
+</style>
+
+<style lang="scss">
+.hc-tasks-user .tasks-user-box .tag-user-list {
+    .el-tag {
+        --el-icon-size: 14px;
+        padding: 0 10px;
+        height: 26px;
+        margin: 4px 0;
+    }
+}
+.hc-tasks-user-modal-content-box {
+    .checkbox-li .el-checkbox {
+        width: 100%;
+        .el-checkbox__input {
+            position: absolute;
+            right: 0;
+            .el-checkbox__inner {
+                width: 18px;
+                height: 18px;
+                &:after {
+                    height: 9px;
+                    left: 6px;
+                    top: 2px;
+                }
+            }
+        }
+        .el-checkbox__label {
+            flex: 1;
+            padding-left: 0;
+            padding-right: 20px;
+        }
+    }
+    .user-list {
+        .el-tag {
+            margin-right: 10px;
+            margin-top: 12px;
+        }
+    }
+}
+</style>

+ 147 - 0
src/views/transfer/components/hc-tasks-user/style.scss

@@ -0,0 +1,147 @@
+.hc-tasks-user {
+    position: relative;
+    .tasks-user-box {
+        position: relative;
+        border: 1px solid #e0e0e6;
+        border-radius: 4px;
+        padding: 0 12px;
+        cursor: pointer;
+        min-height: 40px;
+        .tag-user-list {
+            position: relative;
+            display: flex;
+            align-items: center;
+            flex-flow: row wrap;
+            min-height: inherit;
+            .tasks-placeholder {
+                color: #a9abb2;
+                font-size: 14px;
+            }
+            .arrow-icon-tag {
+                position: relative;
+                color: #a9abb2;
+                font-size: 18px;
+                margin: 0 8px;
+            }
+        }
+    }
+}
+
+.hc-tasks-user-modal-content-box {
+    position: relative;
+    display: flex;
+    height: 460px;
+    .tree-box {
+        flex: 1;
+        user-select: none;
+        position: relative;
+        padding: 20px;
+        overflow: hidden;
+        border-right: 1px solid #EEEEEE;
+    }
+    .user-box {
+        flex: 2;
+        position: relative;
+        display: flex;
+        flex-direction: column;
+        .y-user-list-box, .s-user-list-box {
+            position: relative;
+            overflow: hidden;
+            display: flex;
+            flex-direction: column;
+            .title-box {
+                position: relative;
+                padding: 2px 24px;
+                display: flex;
+                align-items: center;
+                border-bottom: 1px solid #EEEEEE;
+                background-color: #F8F8F8;
+                color: #838791;
+                .title {
+                    flex: auto;
+                }
+            }
+            .user-list {
+                position: relative;
+                overflow: hidden;
+                padding: 0 24px;
+                .user-item {
+                    position: relative;
+                    padding: 4px 0;
+                }
+                .user-item + .user-item {
+                    border-top: 1px dashed #EEEEEE;
+                }
+            }
+        }
+        .y-user-list-box {
+            flex: 1;
+            .user-list {
+                flex: 1;
+            }
+        }
+        .s-user-list-box {
+            position: relative;
+            border-top: 1px solid #EEEEEE;
+            .user-list {
+                height: 6rem;
+            }
+        }
+    }
+}
+
+.sort-node-body-box.list-group {
+    position: relative;
+    min-height: 20px;
+    border: 1px solid #EEEEEE;
+    .list-group-item {
+        position: relative;
+        display: flex;
+        align-items: center;
+        padding: 6px 15px;
+        cursor: move;
+        transition: background 0.2s;
+        .index-box {
+            position: relative;
+            width: 50px;
+        }
+        .title-box {
+            position: relative;
+            padding-right: 24px;
+            flex: 1;
+        }
+        .icon-box {
+            position: relative;
+            font-size: 18px;
+            display: flex;
+            align-items: center;
+            .icon {
+                cursor: pointer;
+                display: flex;
+                align-items: center;
+            }
+        }
+        &:first-child .icon-box i:last-child,
+        &:last-child .icon-box i:first-child {
+            cursor: default;
+            color: #aaaaaa;
+        }
+        &:hover {
+            background: var(--el-color-primary-light-9);
+        }
+    }
+    .list-group-item + .list-group-item {
+        border-top: 1px solid #EEEEEE;
+    }
+    &.header {
+        border-bottom: 0;
+        .list-group-item {
+            cursor: default;
+            padding: 8px 15px;
+            background-color: #F8F8F8;
+            .index-box, .title-box, .icon-box {
+                font-size: 14px;
+            }
+        }
+    }
+}

+ 12 - 1
src/views/transfer/move-submit.vue

@@ -31,6 +31,8 @@
                 <hc-pdf :src="pdfUrl" viewer="" />
             </template>
         </hc-tabs-simple>
+        <!-- 批量上报 -->
+        <HcReport :data="reportData" :show="isReportDialog" @finish="reportFinish" @hide="isReportDialog = false" />
     </div>
 </template>
 
@@ -38,6 +40,7 @@
 import { ref } from 'vue'
 import { getExcelHtml } from '~api/other'
 import { isString } from 'js-fast-way'
+import HcReport from './components/HcReport.vue'
 //类型处理
 const tabsKey = ref('one')
 const tabsData = ref([
@@ -48,7 +51,6 @@ const tabsData = ref([
 ])
 
 const tabsChange = (item) => {
-    console.log(item)
     if (tabsKey.value === 'one') {
         getExcelHtmlData()
     }
@@ -61,7 +63,16 @@ const saveClick = () => {
 
 const reportClick = () => {
  console.log('上报')   
+ isReportDialog.value = true
 }
+const isReportDialog = ref(false)
+const reportData = ref([])
+
+//上报完成
+const reportFinish = () => {
+ 
+}
+
 //表单填报
 const tableFormRef = ref(null)
 const tableFormData = ref({})