Bladeren bron

文件收集,上报

ZaiZai 1 jaar geleden
bovenliggende
commit
f05f495888

+ 76 - 51
src/global/components/hc-tasks-user/index.vue

@@ -2,34 +2,40 @@
     <div :class="ui" 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 name="arrow-right" ui="arrow-icon-tag" v-if="(UserDataList.length - 1) > index"/>
+                <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 class="tasks-placeholder" v-if="UserDataList.length <= 0"> 点击这里选择任务人 </div>
+                <div v-if="UserDataList.length <= 0" class="tasks-placeholder">
+                    点击这里选择任务人
+                </div>
             </div>
         </div>
 
-        <!--选择任务人-->
+        <!-- 选择任务人 -->
         <el-dialog v-model="showModal" title="选择任务人" width="62rem" class="hc-modal-border hc-modal-nop" draggable destroy-on-close append-to-body>
             <div class="hc-tasks-user-modal-content-box">
                 <div class="tree-box">
                     <el-scrollbar>
-                        <ElTree class="hc-tree-node-box" :props="ElTreeProps" :data="ElTreeData" node-key="roleId" highlight-current accordion :default-expanded-keys="[0]" @node-click="ElTreeNodeClick"/>
+                        <ElTree class="hc-tree-node-box" :props="ElTreeProps" :data="ElTreeData" node-key="roleId" highlight-current accordion :default-expanded-keys="[0]" @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 class="title">
+                                可选择
+                            </div>
                         </div>
                         <div class="user-list">
                             <el-scrollbar>
                                 <el-checkbox-group v-model="checkboxUserList">
                                     <template v-for="item in signUserList">
                                         <div class="user-item checkbox-li">
-                                            <el-checkbox :label="`${item['certificateUserName']}-${item['certificateUserId']}`">
-                                                <div class="item-user-name">{{item['certificateUserName']}}</div>
+                                            <el-checkbox :label="`${item.certificateUserName}-${item.certificateUserId}`">
+                                                <div class="item-user-name">
+                                                    {{ item.certificateUserName }}
+                                                </div>
                                             </el-checkbox>
                                         </div>
                                     </template>
@@ -39,13 +45,19 @@
                     </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 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 v-for="(item, index) in checkboxUserList" :key="index">
+                                    <el-tag closable @close="delCheckboxUser(index)">
+                                        {{ setCheckboxUserName(item) }}
+                                    </el-tag>
                                 </template>
                             </el-scrollbar>
                         </div>
@@ -55,38 +67,48 @@
             <template #footer>
                 <div class="dialog-footer">
                     <el-button size="large" @click="showModal = false">
-                        <HcIcon name="close"/>
+                        <HcIcon name="close" />
                         <span>取消</span>
                     </el-button>
                     <el-button hc-btn type="primary" :loading="sureSignUserLoading" @click="sureSignUserClick">
-                        <HcIcon name="check"/>
+                        <HcIcon name="check" />
                         <span>确定</span>
                     </el-button>
                 </div>
             </template>
         </el-dialog>
 
-        <!--调整顺序-->
+        <!-- 调整顺序 -->
         <el-dialog v-model="sequenceModal" title="调整顺序" width="38rem" class="hc-modal-border" draggable destroy-on-close append-to-body>
-            <el-alert title="可拖动排序,也可在后面点击图标,切换排序" type="warning" :closable="false"/>
+            <el-alert title="可拖动排序,也可在后面点击图标,切换排序" type="warning" :closable="false" />
             <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 class="index-box">
+                        序号
+                    </div>
+                    <div class="title-box">
+                        任务人
+                    </div>
+                    <div class="icon-box">
+                        排序
+                    </div>
                 </div>
             </div>
             <Draggable class="sort-node-body-box list-group" ghost-class="ghost" :list="checkboxUserList" item-key="id" @start="sortNodeDrag = true" @end="sortNodeDrag = false">
-                <template #item="{element, index}">
+                <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="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"/>
+                                <HcIcon name="arrow-down" ui="text-lg" />
                             </span>
                             <span class="icon" @click="upSortClick(index)">
-                                <HcIcon name="arrow-up" ui="text-lg"/>
+                                <HcIcon name="arrow-up" ui="text-lg" />
                             </span>
                         </div>
                     </div>
@@ -94,8 +116,12 @@
             </Draggable>
             <template #footer>
                 <div class="dialog-footer">
-                    <el-button size="large" @click="sequenceModal = false">取消</el-button>
-                    <el-button type="primary" hc-btn @click="sequenceModal = false">确认</el-button>
+                    <el-button size="large" @click="sequenceModal = false">
+                        取消
+                    </el-button>
+                    <el-button type="primary" hc-btn @click="sequenceModal = false">
+                        确认
+                    </el-button>
                 </div>
             </template>
         </el-dialog>
@@ -103,32 +129,34 @@
 </template>
 
 <script setup>
-import {ref, watch, onMounted} from "vue";
-import tasksFlowApi from '~api/tasks/flow';
-import {getArrValue, deepClone} from "js-fast-way"
-import Draggable from "vuedraggable";
+import { onMounted, ref, watch } from 'vue'
+import tasksFlowApi from '~api/tasks/flow'
+import { deepClone, getArrValue } from 'js-fast-way'
+import Draggable from 'vuedraggable'
 
 //参数
 const props = defineProps({
     ui: {
         type: String,
-        default: ''
+        default: '',
     },
     //选中的用户数组
     users: {
         type: String,
-        default: ''
+        default: '',
     },
     projectId: {
-        type: [String,Number],
-        default: ''
+        type: [String, Number],
+        default: '',
     },
     contractId: {
-        type: [String,Number],
-        default: ''
+        type: [String, Number],
+        default: '',
     },
 })
 
+//事件
+const emit = defineEmits(['change'])
 //变量
 const showModal = ref(false)
 const sequenceModal = ref(false)
@@ -138,12 +166,12 @@ const projectId = ref(props.projectId)
 const contractId = ref(props.contractId)
 
 //树数据
-const ElTreeProps = {children: 'childRoleList', label: 'roleName'}
+const ElTreeProps = { children: 'childRoleList', label: 'roleName' }
 const ElTreeData = ref([{
     roleName: '全部人员',
     roleId: 0,
     childRoleList: [],
-    signPfxFileList: []
+    signPfxFileList: [],
 }])
 
 //监听
@@ -184,7 +212,7 @@ const showModalClick = () => {
 const signUserList = ref([])
 const queryAllRoleList = async () => {
     const { error, code, data } = await tasksFlowApi.queryAllRoleList({
-        contractId: contractId.value
+        contractId: contractId.value,
     })
     //处理数据
     if (!error && code === 200) {
@@ -225,7 +253,7 @@ const setCheckboxUserName = (item) => {
 
 //删除已选择的用户
 const delCheckboxUser = (index) => {
-    checkboxUserList.value.splice(index,1);
+    checkboxUserList.value.splice(index, 1)
 }
 
 //排序
@@ -234,9 +262,9 @@ 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]);
+    if (indexs !== data.length) {
+        const tmp = data.splice(indexs, 1)
+        checkboxUserList.value.splice(index, 0, tmp[0])
     } else {
         window?.$message?.warning('已经处于置底,无法下移')
     }
@@ -244,21 +272,18 @@ const downSortClick = (index) => {
 //向上
 const upSortClick = (index) => {
     const data = checkboxUserList.value || []
-    if(index !== 0) {
-        const tmp = data.splice(index - 1,1);
-        checkboxUserList.value.splice(index,0,tmp[0]);
+    if (index !== 0) {
+        const tmp = data.splice(index - 1, 1)
+        checkboxUserList.value.splice(index, 0, tmp[0])
     } else {
         window?.$message?.warning('已经处于置顶,无法上移')
     }
 }
 
-//事件
-const emit = defineEmits(['change'])
-
 //确认选择
 const sureSignUserLoading = ref(false)
 const sureSignUserClick = () => {
-    let newUser = [], newUserId = [], users = '';
+    let newUser = [], newUserId = [], users = ''
     const dataList = deepClone(checkboxUserList.value)
     UserDataList.value = dataList
     if (dataList.length > 0) {

+ 87 - 110
src/views/file/collection.vue

@@ -15,13 +15,13 @@
             <div v-loading="treeLoading" class="hc-tree-box" element-loading-text="加载中...">
                 <el-scrollbar>
                     <HcTree
-                        ref="treeRef" 
-                        :project-id="projectId" 
-                        :contract-id="contractId" 
-                        :auto-expand-keys="treeAutoExpandKeys" 
+                        ref="treeRef"
+                        :project-id="projectId"
+                        :contract-id="contractId"
+                        :auto-expand-keys="treeAutoExpandKeys"
                         :menus="ElTreeMenu"
-                        @nodeTap="projectTreeClick" 
-                        @nodeLoading="treeNodeLoading" 
+                        @nodeTap="projectTreeClick"
+                        @nodeLoading="treeNodeLoading"
                         @menuTap="ElTreeMenuClick"
                     />
                 </el-scrollbar>
@@ -57,7 +57,7 @@
                         </el-button>
                     </HcTooltip>
                     <HcTooltip keys="file_collection_btn_report">
-                        <el-button hc-btn :disabled="tableCheckedKeys.length <= 0">
+                        <el-button hc-btn :disabled="tableCheckedKeys.length <= 0" @click="reportModalClick">
                             <HcIcon name="send-plane-2" />
                             <span>上报</span>
                         </el-button>
@@ -423,6 +423,9 @@
         </el-dialog>
 
         <HcUploadFile ref="HcUploadFileRef" :options="UploadFileOptions" @progress="HcUploadFileProgress" @success="HcUploadFileSuccess" @finish="HcUploadFileFinish" />
+
+        <!-- 批量编辑 -->
+        <HcReport :show="isReport" :data="reportData" @finish="reportFinish" @hide="isReport = false" />
     </div>
 </template>
 
@@ -431,9 +434,9 @@ import { useAppStore } from '~src/store'
 import { getStoreValue, setStoreValue } from '~src/utils/storage'
 import { nextTick, onMounted, ref, watch } from 'vue'
 import HcTree from '~src/components/tree/hc-tree.vue'
-import HcFileUpload1 from './components/HcFileUpload1.vue'
+import HcReport from './components/HcReport.vue'
 import notableform from '~src/assets/view/notableform.svg'
-import { delMessage, rowsToId, rowsToIdNumArr } from '~uti/tools'
+import { rowsToId } from '~uti/tools'
 import { delMessageV2 } from '~com/message/index.js'
 import archiveFileApi from '~api/archiveFile/archiveFile'
 import { arrKeySort, arrToId, deepClone, getArrValue, getObjVal } from 'js-fast-way'
@@ -446,7 +449,6 @@ const useAppState = useAppStore()
 const projectId = ref(useAppState.getProjectId)
 const contractId = ref(useAppState.getContractId)
 const projectInfo = ref(useAppState.getProjectInfo)
-const contractInfo = ref(useAppState.getContractInfo)
 
 const isCollapse = ref(useAppState.getCollapse)
 const HcUploadFileRef = ref(null)
@@ -454,6 +456,8 @@ const HcUploadFileRef = ref(null)
 //上传进度
 const uploadsLoading = ref(false)
 
+const treeRef = ref(null)
+
 //监听
 watch(() => [
     useAppState.getCollapse,
@@ -479,25 +483,24 @@ const UploadFileOptions = {
     headers: getTokenHeader(),
 }
 
-const { contractType } = contractInfo.value
 const dutyUser = ref('')
 //设置责任者
 const setdutyUser = async ()=>{
-    const { error, code, data, msg } = await archiveFileApi.getDutyUser({
+    const { error, code, data } = await archiveFileApi.getDutyUser({
         contractId: treecontractId.value,
         projectId:projectId.value,
     })
     if (!error && code === 200) {
-            if (data?.contractType === 1) {
+        if (data?.contractType === 1) {
             dutyUser.value = data?.constructionUnitName || ''
-            } else if (data?.contractType === 2) {
-                    dutyUser.value = data?.supervisionUnitName || ''
-            } else if (data?.contractType === 3) {
-                    dutyUser.value = data?.contractorUnitName || ''
-            }
+        } else if (data?.contractType === 2) {
+            dutyUser.value = data?.supervisionUnitName || ''
+        } else if (data?.contractType === 3) {
+            dutyUser.value = data?.contractorUnitName || ''
+        }
     }
-
 }
+
 //打开文件选择框
 const uploadFileClick = () => {
     HcUploadFileRef?.value?.cancelUpload()
@@ -505,7 +508,7 @@ const uploadFileClick = () => {
 }
 
 // 文件上传进度
-const HcUploadFileProgress = ({ file, status }) => {
+const HcUploadFileProgress = () => {
     uploadsLoading.value = true
 }
 // 文件上传成功的回调
@@ -513,38 +516,32 @@ const HcUploadFileSuccess = (res) => {
     console.log('文件上传成功', res)
     uploadsLoading.value = false
     uploadsChange(res.id, res.resData)
- 
+
 }
 //替换文件
 const newHcUploadFileSuccess = (res, row) => {
     let item = res.resData
-         //更新数据
-         row.fileName = item?.originalName
-        row.ossFileName = item?.name || ''
-        row.fileUrl = item?.link || ''
-        row.pdfFileUrl = item?.pdfUrl || ''
-        row.filePage = item?.page || ''
-        row.isUpdateUrl = 1
-
-    //uploadsLoading.value = false
-    // uploadsChange(res.resData)
+    //更新数据
+    row.fileName = item?.originalName
+    row.ossFileName = item?.name || ''
+    row.fileUrl = item?.link || ''
+    row.pdfFileUrl = item?.pdfUrl || ''
+    row.filePage = item?.page || ''
+    row.isUpdateUrl = 1
 }
 
 // 文件全部上传成功
 const HcUploadFileFinish = () => {
-       uploadsLoading.value = false
+    uploadsLoading.value = false
     HcUploadFileRef?.value.setModalShow(false)
-
 }
 
-
 //树加载
 const treeLoading = ref(false)
 const treeNodeLoading = () => {
     treeLoading.value = false
 }
 
-
 const treePanelLoading = ref(false)
 const panelTreeLoading = () => {
     treePanelLoading.value = false
@@ -571,14 +568,13 @@ const searchForm = ref({
 })
 
 //树相关的变量
-const primaryKeyId = ref('')
 const isBuiltDrawing = ref(0)
 const isStorageNode = ref(0)
 const nodeIds = ref('')
 const treecontractId = ref('')
 //自动展开缓存
 const treeAutoExpandKeys = ref(getStoreValue('wbsTreeExpandKeys') || [])
-const projectTreeClick = ({ node, data, keys, key }) => {
+const projectTreeClick = ({ data, keys }) => {
     setStoreValue('wbsTreeExpandKeys', keys)
     treeAutoExpandKeys.value = keys || []
     nodeIds.value = data.id || ''
@@ -594,29 +590,27 @@ const projectTreeClick = ({ node, data, keys, key }) => {
     getTableData()
 }
 //树菜单被点击
-const ElTreeMenuClick = async ({ key, node, data, keys }) => {
+const ElTreeMenuClick = async ({ data, keys }) => {
     setStoreValue('wbsTreeExpandKeys', keys)
     treeAutoExpandKeys.value = keys || []
-         if (data?.extType === 2) {
-            ElTreeMenu.value = [
-                { icon: 'add-circle', label: '新增', key: 'add' },
-                { icon: 'draft', label: '编辑', key: 'edit' },
-                { icon: 'delete-bin', label: '删除', key: 'del' },
-                { icon: 'refresh', label: '目录同步', key: 'sync' },
-                { icon: 'refresh', label: '文件同步', key: 'fileSync' },
-                { icon: 'sort-asc', label: '排序', key: 'sort' },
-            ]
-            
-        } else {
-            ElTreeMenu.value = [
-                { icon: 'add-circle', label: '新增', key: 'add' },
-                { icon: 'draft', label: '编辑', key: 'edit' },
-                { icon: 'delete-bin', label: '删除', key: 'del' },
-                { icon: 'refresh', label: '目录同步', key: 'sync' },
-                { icon: 'sort-asc', label: '排序', key: 'sort' },
-            ]
-        }
-
+    if (data?.extType === 2) {
+        ElTreeMenu.value = [
+            { icon: 'add-circle', label: '新增', key: 'add' },
+            { icon: 'draft', label: '编辑', key: 'edit' },
+            { icon: 'delete-bin', label: '删除', key: 'del' },
+            { icon: 'refresh', label: '目录同步', key: 'sync' },
+            { icon: 'refresh', label: '文件同步', key: 'fileSync' },
+            { icon: 'sort-asc', label: '排序', key: 'sort' },
+        ]
+    } else {
+        ElTreeMenu.value = [
+            { icon: 'add-circle', label: '新增', key: 'add' },
+            { icon: 'draft', label: '编辑', key: 'edit' },
+            { icon: 'delete-bin', label: '删除', key: 'del' },
+            { icon: 'refresh', label: '目录同步', key: 'sync' },
+            { icon: 'sort-asc', label: '排序', key: 'sort' },
+        ]
+    }
 }
 //回车搜索
 const keyUpEvent = (e) => {
@@ -739,37 +733,15 @@ const sortingNoneModalClose = ()=>{
 const sortingItemData = ref([])
 const sortingOldData = ref([])//旧数据,用来对比是否修改名字
 
-//获取数据
-const sortingItemLoading = ref(false)
-const getSortingItemData = () => {
-
-}
-
 //校验
 const tableIsInput = (val, row, key) => {
-    //console.log(!val);
     //检测是否改过案卷名字
-    if (key == 'isName') {
+    if (key === 'isName') {
         row.isChange = true
     }
-
     row[key] = !val
 }
 
-//选择文件
-// const sortingActiveKey = ref('')
-// const sortingSelectFile = (row, index) => {
-//     //取当前展开组的key
-//     const key = sortingActiveKey.value;
-//     const keys = key ? key.split('-') : [];
-//     const active = keys.length > 0 ? keys[1]: -1;
-//     if (Number(active) === index) {
-//         sortingActiveKey.value = null;
-//     } else {
-//         sortingActiveKey.value = `item-${index}`;
-//     }
-// }
-
 const sortingActiveKey = ref([])
 const tableIndex = ref('')
 const sortingSelectFile = (row, index) => {
@@ -790,7 +762,6 @@ const sortingSelectFile = (row, index) => {
 const sortingTableColumn = [
     { key:'name', name: '文件名称' },
 ]
-const sortingTableData = ref([])
 
 //获取数据
 const sortingTableLoading = ref(false)
@@ -808,11 +779,7 @@ const getSortingTableData = async (row, index) => {
     sortingTableLoading.value = false
     if (!error && code === 200) {
         row.list = getArrValue(data['records'])
-
-        setTableCheck(row, index)
-
-
-
+        setTableCheck(row, index).then()
     } else {
         row.list = []
     }
@@ -823,30 +790,26 @@ const sorTableRef = ref([])
 const tableindex = ref('')
 //回显勾选
 const setTableCheck = async (row, index) => {
-    //console.log(row)
     if (row.ids) {
-        const keys = row.ids.split(',')
-        row.list.forEach(async (item)=>{
+        const keys = row.ids.split(','), list = row.list
+        for (let i = 0; i < list.list; i++) {
+            const item = list[i]
             if (keys.indexOf(item.id) > -1) {
                 item.checked = true
                 await nextTick()
                 sorTableRef.value[index].toggleRowSelection(item, true)
-
-
             }
-        })
+        }
     }
 }
 
 //多选
-const sortingTableKeys = ref([])
 const checkList = ref([])
 const arrfliter = ref([])
 const singleCheck = async ({ row })=>{
   let isCheck = false
     let checkrow = JSON.parse(JSON.stringify(row))
     if (checkrow.checked === false || checkrow.checked === undefined) {
-
         if ( checkList.value.length > 0) {
             let arr = checkList.value.filter(e => e.id === checkrow.id)
             if (arr.length > 0) {
@@ -854,49 +817,39 @@ const singleCheck = async ({ row })=>{
                 await nextTick()
                 sorTableRef.value[tableindex.value].toggleRowSelection(row, false)
                 isCheck = true
-
-
-
             } else {
               isCheck = false
                 row.tableindex = tableindex.value
                 checkList.value.push(row)
             }
-
         } else {
             row.tableindex = tableindex.value
             checkList.value.push(row)
         }
-
-
     } else {
         let arr = checkList.value.filter(e => e.id === checkrow.id)
         if (isCheck === false && arr[0]?.checked === true || isCheck) {
             arrfliter.value = checkList.value.filter(e => e.id !== checkrow.id)
-
         } else {
             arrfliter.value = checkList.value
         }
         let newarr = []
         arrfliter.value.forEach((item)=>{
             newarr.push(JSON.parse(JSON.stringify(item)))
-
         })
         checkList.value = newarr
     }
-
-
-
 }
+
 const sortingTableSelection = (rows, list, index) => {
     tableindex.value = index
     if (list) {
         list.forEach(element => {
-                element.checked = false
+            element.checked = false
         })
     }
     rows.forEach((element)=>{
-            element.checked = true
+        element.checked = true
     })
 }
 
@@ -1610,6 +1563,30 @@ const tableRowName = (row) => {
     }
 }
 
+//上报
+const isReport = ref(false)
+const reportData = ref([])
+const reportModalClick = () => {
+    reportData.value = []
+    const rows = tableCheckedKeys.value
+    //判断是否满足条件
+    const result = rows.every(({ status }) => {
+        return status === 0
+    })
+    if (!result) {
+        window.$message?.warning('已上报的文件不能进行再次上报')
+        return false
+    }
+    //展示上报弹窗
+    reportData.value = rows
+    isReport.value = true
+}
+
+//上报完成
+const reportFinish = () => {
+
+}
+
 
 //左右拖动,改变树形结构宽度
 const leftWidth = ref(382)
@@ -1644,11 +1621,11 @@ const onmousedown = () => {
 @import '~style/file/collection.scss';
 .panel-body .el-checkbox{
     height: auto;
-    
+
 }
 .panel-body .el-radio-group{
     width: auto ;
-    
+
 }
 .panel-body .el-checkbox.size-xl .el-checkbox__label, .el-radio.size-xl .el-radio__label {
     // font-size: 16px;

+ 212 - 0
src/views/file/components/HcReport.vue

@@ -0,0 +1,212 @@
+<template>
+    <el-dialog
+        v-model="isShow" title="批量上报" class="hc-modal-border" destroy-on-close draggable width="47rem"
+        append-to-body @closed="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="userTasks">
+                <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 size="large" @click="cancelReportClick">
+                    取消
+                </el-button>
+                <el-button :loading="formReportLoading" hc-btn type="primary" @click="formReportClick">
+                    提交
+                </el-button>
+            </div>
+        </template>
+    </el-dialog>
+</template>
+
+<script setup>
+import { ref, watch } from 'vue'
+//import { ApprovalApi, queryFixedFlow, queryFixedFlow1 } from '~api/other'
+import { arrIndex, 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)
+
+//监听
+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 formModel = ref({ batch: 1, restrictDay: 1 })
+const formRules = ref({
+    taskContent: {
+        required: false,
+        trigger: 'blur',
+        message: '请输入任务描述',
+    },
+    fixedFlowId: {
+        required: true,
+        trigger: 'blur',
+        message: '请选择任务流程',
+    },
+    userTasks: {
+        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.ids = ids
+    formModel.value.taskName = taskName
+    //获取任务流程
+    processData.value = []
+    getProcessDatasApi()
+}
+
+//获取流程数据
+const processDefaultData = [{ id: 0, fixedFlowName: '自定义流程', disabled: false }]
+const processData = ref([])
+const linkUserJoinString = ref('')
+const getProcessDatasApi = () => {
+    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) => {
+    formModel.value.userTasks = user
+}
+
+//取消
+const cancelReportClick = () => {
+    linkUserJoinString.value = ''
+    isShow.value = false
+    emit('hide', false)
+}
+
+//上报
+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 ApprovalApi(ApiUrl.value, {
+        projectId: projectId.value,
+        contractId: contractId.value,
+        ...formModel.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')
+}
+</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>

+ 355 - 0
src/views/file/components/hc-tasks-user/index.vue

@@ -0,0 +1,355 @@
+<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" append-to-body>
+            <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 in signUserList">
+                                        <div class="user-item checkbox-li">
+                                            <el-checkbox :label="`${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" class="hc-modal-border" destroy-on-close draggable append-to-body 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 = () => {
+    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])
+        }
+    })
+    //效验人员
+
+    //关闭弹窗
+    showModal.value = false
+    sureSignUserLoading.value = false
+    emit('change', newUser, newUserId, users)
+}
+</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/file/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;
+            }
+        }
+    }
+}