|
@@ -0,0 +1,1620 @@
|
|
|
+<template>
|
|
|
+ <div class="hc-layout-box">
|
|
|
+ <div
|
|
|
+ id="wbs-left-tree" :style="`width:${isWbsTreeShow ? leftWidth : 0}px; ${isWbsTreeShow ? '' : 'display: none'}`"
|
|
|
+ class="hc-layout-left-box bg-white" :class="[isWbsTreeShow ? 'show' : '']"
|
|
|
+ >
|
|
|
+ <div class="hc-project-box">
|
|
|
+ <div class="hc-project-icon-box">
|
|
|
+ <HcIcon name="stack" />
|
|
|
+ </div>
|
|
|
+ <div class="project-name-box ml-2">
|
|
|
+ <div class="project-alias">{{ projectInfo?.projectName }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="hc-tree-box">
|
|
|
+ <div class="hc-search-tree-val">
|
|
|
+ <el-input v-model="searchTreeVal" clearable block placeholder="请输入名称关键词检索" @keyup="searchTreeKeyUp">
|
|
|
+ <template #suffix>
|
|
|
+ <HcIcon name="search-2" ui="text-xl iscusor" @click="searchTreeClick" />
|
|
|
+ </template>
|
|
|
+ </el-input>
|
|
|
+ </div>
|
|
|
+ <div v-if="isShowLeft" id="hc-tree-scrollbar" v-loading="treeLoading" class="hc-tree-scrollbar" element-loading-text="获取数据中...">
|
|
|
+ <el-scrollbar v-show="isSearchTree" class="scroll-bar-right-16">
|
|
|
+ <HcDataTree
|
|
|
+ :datas="searchTreeData"
|
|
|
+ is-counts
|
|
|
+ is-type
|
|
|
+ :auto-expand-keys="treeAutoExpandKeys"
|
|
|
+ default-expand-all
|
|
|
+ :menus="treeMenus"
|
|
|
+ @node-tap="wbsElTreeClick"
|
|
|
+ @menu-tap="ElTreeMenuClick"
|
|
|
+ />
|
|
|
+ </el-scrollbar>
|
|
|
+ <el-scrollbar v-show="!isSearchTree" class="scroll-bar-right-16">
|
|
|
+ <HcLazyTree
|
|
|
+ ref="wbstree"
|
|
|
+ :auto-expand-keys="treeAutoExpandKeys"
|
|
|
+ is-counts
|
|
|
+ is-type
|
|
|
+ :menus="treeMenus"
|
|
|
+ @load="treeLoadNode"
|
|
|
+ @node-tap="wbsElTreeClick"
|
|
|
+ @menu-tap="ElTreeMenuClick"
|
|
|
+ />
|
|
|
+ </el-scrollbar>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="hc-tree-foot-tip-box">
|
|
|
+ <div class="dot-view green">已审批</div>
|
|
|
+ <div class="dot-view black">未填报</div>
|
|
|
+ <div class="dot-view orange">已填报-待审批</div>
|
|
|
+ <div class="dot-view blue">已填报-未上报</div>
|
|
|
+ <div class="dot-view red">已隐藏</div>
|
|
|
+ </div>
|
|
|
+ <!-- 左右拖动 -->
|
|
|
+ <div class="horizontal-drag-line" @mousedown="onmousedown" />
|
|
|
+ </div>
|
|
|
+ <div class="hc-layout-content-box">
|
|
|
+ <hc-body padding="0px">
|
|
|
+ <!---展开收缩树 -->
|
|
|
+ <div class="hc-expansion-contraction-tree" @click="setWbsTreeShow">
|
|
|
+ <HcIcon v-show="isWbsTreeShow" name="arrow-left-s" />
|
|
|
+ <HcIcon v-show="!isWbsTreeShow" name="arrow-right-s" />
|
|
|
+ </div>
|
|
|
+ <div style="height: 70px" class="mb-2 flex justify-around">
|
|
|
+ <hc-card>
|
|
|
+ <div style="line-height: 26px;">
|
|
|
+ <div>
|
|
|
+ <div class="text-16px font-800">一键CA</div>
|
|
|
+ <div>暂无任务...</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </hc-card>
|
|
|
+ <hc-card class="ml-2">
|
|
|
+ <div style="line-height: 26px;">
|
|
|
+ <div>
|
|
|
+ <div class="text-16px font-800">re-sign</div>
|
|
|
+ <div>暂无任务...</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </hc-card>
|
|
|
+ <hc-card class="ml-2">
|
|
|
+ <div style="line-height: 26px;">
|
|
|
+ <div>
|
|
|
+ <div class="text-16px font-800">save-sign</div>
|
|
|
+ <div>暂无任务...</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </hc-card>
|
|
|
+ <hc-card class="ml-2">
|
|
|
+ <div v-if="progressObj.totalCount === 0" style="line-height: 26px;">
|
|
|
+ <div>
|
|
|
+ <div class="text-16px font-800">电签检测</div>
|
|
|
+ <div>暂无任务...</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-else style="line-height: 26px;">
|
|
|
+ <div>
|
|
|
+ <div class="text-16px font-800">电签检测 </div>
|
|
|
+ <div class="flex">
|
|
|
+ <el-progress
|
|
|
+ :text-inside="true"
|
|
|
+ :stroke-width="20"
|
|
|
+ :percentage="progressObj.pace"
|
|
|
+ status="success"
|
|
|
+ size="small"
|
|
|
+ style="width: 80%;"
|
|
|
+ />
|
|
|
+ <span class="ml-1">{{ `${progressObj.finishCount}/${progressObj.totalCount}` }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </hc-card>
|
|
|
+ </div>
|
|
|
+ <HcNewCard padding class="basic-info-box">
|
|
|
+ <template #header>
|
|
|
+ <!-- <el-button :disabled="tableCheckedKeys.length <= 0" :loading="reportLoading" hc-btn color="#FF976A" style="color: white;" @click="reportModalClick">
|
|
|
+ <HcIcon name="send-plane-2" />
|
|
|
+ <span>上报</span>
|
|
|
+ </el-button>
|
|
|
+
|
|
|
+
|
|
|
+ <el-button :disabled="tableCheckedKeys.length <= 0" :loading="reportLoading" hc-btn color="#FF976A" style="color: white;" @click="reportModalClick">
|
|
|
+ <HcIcon name="send-plane-2" />
|
|
|
+ <span>上报且审批</span>
|
|
|
+ </el-button> -->
|
|
|
+ <!-- <el-button :disabled="tableCheckedKeys.length <= 0" :loading="signLoading" hc-btn type="primary" @click="resignClick"> <HcIcon name="repeat" />re-sign</el-button> -->
|
|
|
+ <!-- <el-button
|
|
|
+ :disabled="tableCheckedKeys.length <= 0" :loading="saveAginLoading" hc-btn
|
|
|
+ color="#e03997" @click="saveAginClick"
|
|
|
+ >
|
|
|
+ <HcIcon name="save" />
|
|
|
+ <span>save-again</span>
|
|
|
+ </el-button>
|
|
|
+ -->
|
|
|
+
|
|
|
+ <el-button
|
|
|
+ :disabled="tableCheckedKeys.length <= 0" hc-btn
|
|
|
+ color="#52B200"
|
|
|
+ style="color: white;"
|
|
|
+ @click="batchOnlineClick"
|
|
|
+ >
|
|
|
+ <HcIcon name="survey" />
|
|
|
+ <span>电签检测</span>
|
|
|
+ </el-button>
|
|
|
+
|
|
|
+ <!-- <el-button
|
|
|
+ style="color: white;"
|
|
|
+ :disabled="tableCheckedKeys.length <= 0" hc-btn
|
|
|
+ color="#3F9EFF" @click="batchOnline"
|
|
|
+ >
|
|
|
+ <HcIcon name="file-list" />
|
|
|
+ <span>任务列表</span>
|
|
|
+ </el-button> -->
|
|
|
+ </template>
|
|
|
+ <template #search>
|
|
|
+ <div class="flex items-center">
|
|
|
+ <div class="w-32">
|
|
|
+ <el-select v-model="searchForm.majorDateType" clearable placeholder="资料类型">
|
|
|
+ <el-option
|
|
|
+ v-for="item in majorDataTypeOptions"
|
|
|
+ :key="item.value"
|
|
|
+ :label="item.label"
|
|
|
+ :value="item.value"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ <div class="ml-2 w-40">
|
|
|
+ <el-select v-model="searchForm.fileUserIdAndName" clearable placeholder="填报人">
|
|
|
+ <el-option
|
|
|
+ v-for="item in reportingPersonData" :key="item.value" :label="item.label"
|
|
|
+ :value="item.value"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="ml-2 w-40">
|
|
|
+ <el-select v-model="searchForm.sourceType" clearable placeholder="文件类型">
|
|
|
+ <el-option
|
|
|
+ v-for="item in fileTypeData" :key="item.value" :label="item.dictValue"
|
|
|
+ :value="item.dictKey"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ <div class="ml-2 w-40">
|
|
|
+ <el-select v-model="searchForm.taskStatus" clearable placeholder="流程状态">
|
|
|
+ <el-option
|
|
|
+ v-for="item in processStatusData" :key="item.value"
|
|
|
+ :label="item.dictValue" :value="item.dictKey"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ <div class="ml-2 w-40">
|
|
|
+ <el-select v-model="searchForm.chekStatus" clearable placeholder="检测状态">
|
|
|
+ <el-option :value="0" label="未检测" />
|
|
|
+ <el-option :value="1" label="检测中" />
|
|
|
+ <el-option :value="2" label="检测无误" />
|
|
|
+ <el-option :value="3" label="检测有误" />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ <div class="ml-2 w-64">
|
|
|
+ <HcDatePicker :dates="betweenTime" clearable @change="betweenTimeUpdate" />
|
|
|
+ </div>
|
|
|
+ <div class="ml-2 w-60">
|
|
|
+ <el-input
|
|
|
+ v-model="searchForm.queryValue" clearable placeholder="请输入名称关键词检索"
|
|
|
+ @keyup="keyUpEvent"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="ml-2">
|
|
|
+ <el-button type="primary" @click="searchClick">
|
|
|
+ <HcIcon name="search-2" />
|
|
|
+ <span>搜索</span>
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <template #extra>
|
|
|
+ <template v-if="contractInfo?.contractType === 2 || contractInfo?.contractType === 3">
|
|
|
+ <HcNewSwitch :datas="contractTypeTab" :keys="contractTypeTabKey" size="default" @change="contractTypeTabChange" />
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ <HcTable
|
|
|
+ ref="tableListRef" :column="tableListColumn" :datas="tableListData" :loading="tableLoading"
|
|
|
+ is-new :index-style="{ width: 60 }" is-check :check-style="{ width: 29 }"
|
|
|
+ @selection-change="tableSelectionChange"
|
|
|
+ >
|
|
|
+ <template #taskStatusStr="{ row }">
|
|
|
+ <el-tag
|
|
|
+
|
|
|
+ :type="`${row.taskStatusStr === '已审批' ? 'success' : row.taskStatusStr === '待审批' ? 'warning' : row.taskStatusStr === '已废除' ? 'danger' : 'info'}`"
|
|
|
+ class="mx-1" effect="dark"
|
|
|
+ >
|
|
|
+ {{ row.taskStatusStr }}
|
|
|
+ </el-tag>
|
|
|
+ </template>
|
|
|
+ <template #name="{ row }">
|
|
|
+ <span v-loading="row?.bussPreviewLoading" class="text-link" @click="tableRowName(row)">{{ row?.name }}</span>
|
|
|
+ </template>
|
|
|
+ <template #chekStatus="{ row }">
|
|
|
+ <el-tag
|
|
|
+
|
|
|
+ :type="`${row.chekStatus === 2 ? 'success' : row.chekStatus === 1 ? 'warning' : row.chekStatus === 3 ? 'danger' : 'info'}`"
|
|
|
+ class="mx-1" effect="dark"
|
|
|
+ >
|
|
|
+ {{ row.chekStatus === 0 ? '未检测' : row.chekStatus === 1 ? '检测中' : row.chekStatus === 2 ? '检测无误' : '检测有误' }}
|
|
|
+ </el-tag>
|
|
|
+ </template>
|
|
|
+ <template #waitingUserList="{ row }">
|
|
|
+ <template v-for="item in row.waitingUserList">
|
|
|
+ <el-tag
|
|
|
+ v-if="item.waitingUserName"
|
|
|
+ :key="item.waitingUserName"
|
|
|
+ :type="`${item.status === 2 ? 'success' : item.status === 3 ? 'warning' : item.status === 999 ? 'danger' : 'info'}`"
|
|
|
+ class="mx-1" effect="dark"
|
|
|
+ >
|
|
|
+ {{ item.waitingUserName }}
|
|
|
+ </el-tag>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </HcTable>
|
|
|
+ <template #action>
|
|
|
+ <HcPages :pages="searchForm" @change="pageChange" />
|
|
|
+ </template>
|
|
|
+ </HcNewCard>
|
|
|
+ </hc-body>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 批量上报审批 -->
|
|
|
+ <HcReportModal
|
|
|
+ :ids="reportIds"
|
|
|
+ :node-id="primaryKeyId"
|
|
|
+ :table-owner="contractTypeTabKey"
|
|
|
+ :classify-type="classType"
|
|
|
+ :contract-id="contractId"
|
|
|
+ :flow-contract-id="nodeDataInfo?.contractId"
|
|
|
+ :datas="reportDatas"
|
|
|
+ :project-id="projectId"
|
|
|
+ :show="showReportModal"
|
|
|
+ :task-name="reportTaskName"
|
|
|
+ :type-data="reportTypeData"
|
|
|
+ :report-arr="reportArr"
|
|
|
+ type="query"
|
|
|
+ is-datas
|
|
|
+ title="批量上报审批"
|
|
|
+ url="informationWriteQuery/batchTask"
|
|
|
+ @finish="showReportFinish"
|
|
|
+ @hide="showReportModal = false"
|
|
|
+ @tag-close="reportTaskTagClose"
|
|
|
+ />
|
|
|
+
|
|
|
+ <!-- 在线验签 -->
|
|
|
+ <hc-new-drawer v-model="isOnlineVerifyDrawer" modal-class="hc-online-verify-drawer" to-id="app" @close="onlineVerifyDrawerClose">
|
|
|
+ <hc-new-card>
|
|
|
+ <template #header>
|
|
|
+ <div class="online-verify-title">{{ onlineTitle }}</div>
|
|
|
+ </template>
|
|
|
+ <template #extra>
|
|
|
+ <div class="online-verify-icon" @click="onlineVerifyDrawerClose">
|
|
|
+ <HcIcon name="close-circle" />
|
|
|
+ <span class="ml-1">关闭</span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <hc-body split padding="0px" :options="onlineVerifyOptions">
|
|
|
+ <template #left>
|
|
|
+ <hc-new-card>
|
|
|
+ <HcPdf :src="onlineVerifyData.pdfUrl" />
|
|
|
+ </hc-new-card>
|
|
|
+ </template>
|
|
|
+ <hc-new-card>
|
|
|
+ <HcTable :column="cscTableColumn" :datas="cscTableData" is-new :index-style="{ width: 60 }" />
|
|
|
+ </hc-new-card>
|
|
|
+ </hc-body>
|
|
|
+ </hc-new-card>
|
|
|
+ </hc-new-drawer>
|
|
|
+ <!-- 一键重签弹窗 -->
|
|
|
+ <hc-new-dialog v-model="resignModal" title="一键重签" widths="38rem" :loading="signLoading" @close="cancelresign" @save="signClick">
|
|
|
+ <div>
|
|
|
+ 是否重新生成pdf:
|
|
|
+ <el-radio-group v-model="resignModalRadio">
|
|
|
+ <el-radio :value="0">否</el-radio>
|
|
|
+ <el-radio :value="1">是</el-radio>
|
|
|
+ </el-radio-group>
|
|
|
+ </div>
|
|
|
+ </hc-new-dialog>
|
|
|
+ <!-- 一键重签弹窗1 -->
|
|
|
+ <hc-new-dialog v-model="resignModal1" title="一键重签" widths="38rem" :loading="signLoading1" @close="cancelresign1" @save="signClick1">
|
|
|
+ <div>
|
|
|
+ <el-radio-group v-model="resignModalRadio1">
|
|
|
+ <el-radio :value="0">全部电签</el-radio>
|
|
|
+ <el-radio :value="1" :disabled="tableCheckedKeys.length > 1">部分电签</el-radio>
|
|
|
+ </el-radio-group>
|
|
|
+ </div>
|
|
|
+ <div v-if="resignModalRadio1 === 1">
|
|
|
+ <el-checkbox-group v-model="checkTaskUserIds">
|
|
|
+ <el-checkbox v-for="item in tableCheckedKeys[0].waitingUserList" :key="item.id" :label="item.waitingUserName" :value="item.userId">
|
|
|
+ <el-tag
|
|
|
+
|
|
|
+
|
|
|
+ :type="`${item.status === 2 ? 'success' : item.status === 3 ? 'warning' : item.status === 999 ? 'danger' : 'info'}`"
|
|
|
+ class="mx-1" effect="dark"
|
|
|
+ >
|
|
|
+ {{ item.waitingUserName }}
|
|
|
+ </el-tag>
|
|
|
+ </el-checkbox>
|
|
|
+ </el-checkbox-group>
|
|
|
+ </div>
|
|
|
+ </hc-new-dialog>
|
|
|
+ <!-- 重置文件题名弹窗 -->
|
|
|
+ <hc-new-dialog v-model="resignTitleModal" title="重置题名" widths="38rem" :loading="resignTitleSaveLoad" @save="resignTitleSave">
|
|
|
+ <div>
|
|
|
+ 是否更改题名规则:
|
|
|
+ <el-button type="primary" hc-btn size="small" @click="changeRuleClick">规则更改</el-button>
|
|
|
+ </div>
|
|
|
+ </hc-new-dialog>
|
|
|
+ <!-- 规则修改弹窗 -->
|
|
|
+ <hc-new-dialog v-model="ruleModal" title="更改重置题名题名规则" widths="88rem" :loading="ruleModalSaveLoad" @close="ruleModalClose" @save="ruleModalSave">
|
|
|
+ <template #header>
|
|
|
+ <div class="flex flex-col">
|
|
|
+ <div class="mb-4 text-18px">
|
|
|
+ <span>更改重置题名题名规则</span>
|
|
|
+ </div>
|
|
|
+ <div class="flex justify-between justify-items-center text-orange">
|
|
|
+ <p>* 单条修改在表单下拉框选择规则,批量修改在右侧选规则点击【设置】统一更新所有规则</p>
|
|
|
+ <p>* “修改后”仅为展示,【确认】后才会刷新文件题名</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <div class="flex items-center justify-between">
|
|
|
+ <div>批量设置:</div>
|
|
|
+ <el-select
|
|
|
+ v-model="setValue"
|
|
|
+ placeholder="请选择"
|
|
|
+
|
|
|
+ multiple
|
|
|
+ clearable
|
|
|
+ class="custom-select flex-1"
|
|
|
+
|
|
|
+ :popper-append-to-body="false"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="item in nodeTypeData"
|
|
|
+ :key="item.value"
|
|
|
+ :label="item.label"
|
|
|
+ :value="item.value"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ <el-button type="primary" hc-btn size="small" class="ml-2" :disabled="setValue.length === 0" @click="batchSetRule">设置</el-button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div style="position: relative; height: 440px" class="mt-2">
|
|
|
+ <HcTable v-loading="ruleTableLoading" :column="ruleTableColumn" :datas="ruleTableData" :loading="ruleTableLoading">
|
|
|
+ <template #rule="{ row }">
|
|
|
+ <div class="flex items-center">
|
|
|
+ <span class="text-red">*</span>
|
|
|
+ <el-select
|
|
|
+ v-model="row.rule"
|
|
|
+ :class="{ 'error-border': !row.rule || row.rule.length === 0 }"
|
|
|
+ placeholder="请选择"
|
|
|
+ multiple
|
|
|
+ clearable
|
|
|
+ class="custom-select"
|
|
|
+ :popper-append-to-body="false"
|
|
|
+ @change="ruleChange(row)"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="item in nodeTypeData"
|
|
|
+ :key="item.value"
|
|
|
+ :label="item.label"
|
|
|
+ :value="item.value"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </HcTable>
|
|
|
+ </div>
|
|
|
+ </hc-new-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { nextTick, onMounted, ref, watch } from 'vue'
|
|
|
+import { useAppStore } from '~src/store'
|
|
|
+import { getStoreValue, setStoreValue } from '~src/utils/storage'
|
|
|
+import { arrToId, arrToKey, downloadBlob, getArrValue, getObjValue, isNullES, isString } from 'js-fast-way'
|
|
|
+import queryApi from '~api/data-fill/query'
|
|
|
+
|
|
|
+import { eVisaTaskCheckApi } from '~api/other'
|
|
|
+import { toPdfPage } from '~uti/btn-auth'
|
|
|
+import wbsApi from '~api/data-fill/wbs'
|
|
|
+import website from '~src/config'
|
|
|
+import { getDictionaryData } from '~uti/tools'
|
|
|
+import { getDictionary, userConfigSave } from '~api/other'
|
|
|
+import { useClick } from 'hc-vue3-ui'
|
|
|
+
|
|
|
+
|
|
|
+//变量
|
|
|
+const useAppState = useAppStore()
|
|
|
+const projectId = ref(useAppState.getProjectId)
|
|
|
+const contractId = ref(useAppState.getContractId)
|
|
|
+const projectInfo = ref(useAppState.getProjectInfo)
|
|
|
+const contractInfo = ref(useAppState.getContractInfo)
|
|
|
+const userInfo = ref(useAppState.getUserInfo)
|
|
|
+const isCollapse = ref(useAppState.getCollapse)
|
|
|
+const isLayout = ref(useAppState.isLayout)
|
|
|
+const isTemplateType = ref(useAppState.contractInfo?.templateType === 2)
|
|
|
+//变量
|
|
|
+const wbstree = ref(null)
|
|
|
+const wbstreeKey = ref(Math.random())
|
|
|
+//树搜索
|
|
|
+const isSearchTree = ref(false)
|
|
|
+const searchTreeHeight = ref()
|
|
|
+const searchTreeVal = ref('')
|
|
|
+//监听
|
|
|
+watch(() => [useAppState.getCollapse, searchTreeVal.value, useAppState.isLayout], ([Collapse, search, isLay]) => {
|
|
|
+ isCollapse.value = Collapse
|
|
|
+ isLayout.value = isLay || ''
|
|
|
+ if (search.length == 0) {
|
|
|
+ isSearchTree.value = false
|
|
|
+ }
|
|
|
+})
|
|
|
+//是否禁用下载打印按钮
|
|
|
+const isCanDown = ref(false)
|
|
|
+//自动展开缓存
|
|
|
+const treeAutoExpandKeys = ref(getStoreValue('wbsTreeExpandKeys') || [])
|
|
|
+
|
|
|
+//渲染完成
|
|
|
+onMounted(() => {
|
|
|
+ getCheckPdfPaceInfoData()
|
|
|
+ getFileUser()
|
|
|
+ getReportNumber()
|
|
|
+ getFirstTaskStatus()
|
|
|
+ getDictBizClassify()
|
|
|
+ getMajorDataTypeOptions()
|
|
|
+ isCanDown.value = !website.localModel
|
|
|
+ const treeWidth = useAppState.getTreeWidth
|
|
|
+ leftWidth.value = isNullES(treeWidth) || treeWidth <= 0 ? 440 : treeWidth
|
|
|
+
|
|
|
+})
|
|
|
+
|
|
|
+//获取
|
|
|
+const majorDataTypeOptions = ref([])
|
|
|
+const getMajorDataTypeOptions = async () => {
|
|
|
+ majorDataTypeOptions.value = (await getDictionaryData('major_data_type', false)).filter(item => item.value !== 0)
|
|
|
+}
|
|
|
+
|
|
|
+const searchTreeData = ref([])
|
|
|
+
|
|
|
+//回车
|
|
|
+const treeLoading = ref(true)
|
|
|
+const getSearchTreeData = async () => {
|
|
|
+ treeLoading.value = true
|
|
|
+ const { error, code, data } = await queryApi.getTreeNodeByQueryValueAndContractId({
|
|
|
+ contractId: contractId.value,
|
|
|
+ queryValue: searchTreeVal.value,
|
|
|
+ tableOwner:contractTypeTabKey.value,
|
|
|
+ })
|
|
|
+ //判断状态
|
|
|
+ if (!error && code === 200) {
|
|
|
+ let treedata = getArrValue(data)
|
|
|
+ searchTreeData.value = treedata
|
|
|
+ treeLoading.value = false
|
|
|
+
|
|
|
+ } else {
|
|
|
+ treeLoading.value = false
|
|
|
+
|
|
|
+ searchTreeData.value = []
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+//回车
|
|
|
+const searchTreeKeyUp = (e) => {
|
|
|
+ if (e.key === 'Enter') {
|
|
|
+ searchTreeClick()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const searchTreeClick = async () => {
|
|
|
+ if (searchTreeVal.value) {
|
|
|
+ searchTreeHeight.value = document.getElementById('hc-tree-scrollbar').offsetHeight
|
|
|
+ isSearchTree.value = true
|
|
|
+ //treeLoading.value = true
|
|
|
+ getSearchTreeData().then()
|
|
|
+ } else {
|
|
|
+ isSearchTree.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//树相关的变量
|
|
|
+const primaryKeyId = ref('')
|
|
|
+const nodeItemInfo = ref({})
|
|
|
+const nodeDataInfo = ref({})
|
|
|
+
|
|
|
+
|
|
|
+//懒加载的数据
|
|
|
+const treeLoadNode = async ({ node, item, level }, resolve) => {
|
|
|
+ let contractIdRelation = '', parentId = '', primaryKeyId = ''
|
|
|
+ if (level !== 0) {
|
|
|
+ const nodeData = getObjValue(item)
|
|
|
+ contractIdRelation = nodeData?.contractIdRelation || ''
|
|
|
+ parentId = contractIdRelation ? nodeData?.primaryKeyId : nodeData?.id
|
|
|
+ primaryKeyId = nodeData?.id || ''
|
|
|
+ }
|
|
|
+ //获取数据
|
|
|
+ const { data } = await queryApi.queryWbsTreeData({
|
|
|
+ contractId: contractId.value || '',
|
|
|
+ contractIdRelation,
|
|
|
+ primaryKeyId,
|
|
|
+ parentId,
|
|
|
+ // classifyType: contractTypeTabKey.value,
|
|
|
+ classifyType: classType.value,
|
|
|
+ tableOwner:contractTypeTabKey.value,
|
|
|
+ dataTime:new Date(),
|
|
|
+ })
|
|
|
+ resolve(getArrValue(data))
|
|
|
+ treeLoading.value = false
|
|
|
+}
|
|
|
+
|
|
|
+//树被点击
|
|
|
+const wbsElTreeClick = ({ node, data, keys }) => {
|
|
|
+ nodeItemInfo.value = node
|
|
|
+ nodeDataInfo.value = data
|
|
|
+ primaryKeyId.value = data['primaryKeyId'] || ''
|
|
|
+ //缓存自动展开
|
|
|
+ treeAutoExpandKeys.value = keys
|
|
|
+ setStoreValue('wbsTreeExpandKeys', keys)
|
|
|
+ //改变搜索表单数据
|
|
|
+ searchForm.value.wbsId = data['primaryKeyId']
|
|
|
+ //只有监理、指挥合同段才传contractIdRelation
|
|
|
+ if (contractInfo.value?.contractType == 2 || contractInfo.value?.contractType == 3) {
|
|
|
+ searchForm.value.contractIdRelation = data['contractIdRelation']
|
|
|
+ } else {
|
|
|
+ searchForm.value.contractIdRelation = ''
|
|
|
+ }
|
|
|
+ searchForm.value.current = 1
|
|
|
+ getFileUser()
|
|
|
+ getTableData()
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+//搜索条件
|
|
|
+const processStatusData = ref([]) //流程状态
|
|
|
+const reportingPersonData = ref([]) //填报人
|
|
|
+const fileTypeData = ref([]) //文件类型
|
|
|
+const reportBatchData = ref([]) //上报批次
|
|
|
+
|
|
|
+//获取所有填报人
|
|
|
+const getFileUser = async () => {
|
|
|
+ const info = nodeDataInfo.value
|
|
|
+
|
|
|
+ if (!info || !info?.contractIdRelation) {
|
|
|
+ window.$message?.warning('请先点击左侧节点')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const { error, code, data } = await queryApi.getFileUser({
|
|
|
+ contractId: contractId.value,
|
|
|
+ contractIdRelation: contractInfo.value?.contractType === 2 ? info?.contractIdRelation : contractId.value,
|
|
|
+ })
|
|
|
+ //判断状态
|
|
|
+ if (!error && code === 200) {
|
|
|
+ let res = getArrValue(data), userArr = []
|
|
|
+ res.forEach(item => {
|
|
|
+ userArr.push({ label: item['userName'], value: `${item['userId']}-${item['userName']}` })
|
|
|
+ })
|
|
|
+ reportingPersonData.value = userArr
|
|
|
+ } else {
|
|
|
+ reportingPersonData.value = []
|
|
|
+ }
|
|
|
+}
|
|
|
+//获取上报批次
|
|
|
+const getReportNumber = async () => {
|
|
|
+ const { error, code, data } = await queryApi.getReportNumber({
|
|
|
+ contractId: contractId.value,
|
|
|
+ projectId: projectId.value,
|
|
|
+ })
|
|
|
+ //判断状态
|
|
|
+ if (!error && code === 200) {
|
|
|
+ reportBatchData.value = getArrValue(data)
|
|
|
+ } else {
|
|
|
+ reportBatchData.value = []
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+//获取流程状态
|
|
|
+const getFirstTaskStatus = async () => {
|
|
|
+ const { error, code, data } = await queryApi.getFirstTaskStatus()
|
|
|
+ //判断状态
|
|
|
+ if (!error && code === 200) {
|
|
|
+ processStatusData.value = getArrValue(data)
|
|
|
+ } else {
|
|
|
+ processStatusData.value = []
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//获取流程状态分类和文件类型分类
|
|
|
+const getDictBizClassify = async () => {
|
|
|
+ const { error, code, data } = await queryApi.getDictBizClassify({
|
|
|
+ contractId: contractId.value,
|
|
|
+ code: 'fileType',
|
|
|
+ })
|
|
|
+ //判断状态
|
|
|
+ if (!error && code === 200) {
|
|
|
+ fileTypeData.value = getArrValue(data)
|
|
|
+ } else {
|
|
|
+ fileTypeData.value = []
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//搜索表单
|
|
|
+const searchForm = ref({
|
|
|
+ taskStatus: null, fileUserIdAndName: null, sourceType: null, reportNumber: null, betweenTime: null,
|
|
|
+ queryValue: null, contractIdRelation: null, wbsId: null, current: 1, size: 20, total: 0, majorDateType:'',
|
|
|
+ waitingUserStatus:'',
|
|
|
+})
|
|
|
+
|
|
|
+
|
|
|
+//结构类型tab数据和相关处理
|
|
|
+// const contractTypeTabKey = ref('1')
|
|
|
+const contractTypeTabKey = ref(contractInfo.value?.contractType === 2 ? '2' : '1')
|
|
|
+//加载树需要的classType由合同段获取
|
|
|
+const classType = ref(contractInfo.value?.contractType === 2 ? '2' : '1')
|
|
|
+const contractTypeTab = ref([
|
|
|
+ { key: '1', name: '施工数据' },
|
|
|
+ { key: '2', name: '监理数据' },
|
|
|
+])
|
|
|
+//是否显示左边树
|
|
|
+const isShowLeft = ref(true)
|
|
|
+const contractTypeTabChange = (item) => {
|
|
|
+ contractTypeTabKey.value = item?.key
|
|
|
+ //重新加载左边树
|
|
|
+ isShowLeft.value = false
|
|
|
+ setTimeout(()=>{
|
|
|
+ isShowLeft.value = true
|
|
|
+ }, 500)
|
|
|
+ searchClick()
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+//日期时间被选择
|
|
|
+const betweenTime = ref(null)
|
|
|
+const betweenTimeUpdate = ({ arr, query }) => {
|
|
|
+ betweenTime.value = arr
|
|
|
+ searchForm.value.betweenTime = query
|
|
|
+}
|
|
|
+
|
|
|
+//回车搜索
|
|
|
+const keyUpEvent = (e) => {
|
|
|
+ if (e.key === 'Enter') {
|
|
|
+ searchForm.value.current = 1
|
|
|
+ if (searchForm.value?.queryValue) {
|
|
|
+ searchForm.value.queryValue = searchForm.value.queryValue.trim()
|
|
|
+ }
|
|
|
+
|
|
|
+ getTableData()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//搜索
|
|
|
+const searchClick = () => {
|
|
|
+ searchForm.value.current = 1
|
|
|
+ if (searchForm.value?.queryValue) {
|
|
|
+ searchForm.value.queryValue = searchForm.value.queryValue.trim()
|
|
|
+ }
|
|
|
+ wbstreeKey.value = Math.random()
|
|
|
+ getTableData()
|
|
|
+// wbstree.value.resetNode().then((red)=>{
|
|
|
+// if(red){
|
|
|
+// getTableData()
|
|
|
+// }
|
|
|
+
|
|
|
+// })
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+//分页被点击
|
|
|
+const pageChange = ({ current, size }) => {
|
|
|
+ searchForm.value.current = current
|
|
|
+ searchForm.value.size = size
|
|
|
+ getTableData()
|
|
|
+}
|
|
|
+
|
|
|
+//获取数据
|
|
|
+const tableListRef = ref(null)
|
|
|
+const tableLoading = ref(false)
|
|
|
+const tableListColumn = ref([
|
|
|
+ { key: 'name', name: '文件题名' },
|
|
|
+
|
|
|
+ { key: 'taskStatusStr', name: '资料状态', width: 100, align: 'center' },
|
|
|
+ { key: 'chekStatus', name: '检测状态', width: 100, align: 'center' },
|
|
|
+
|
|
|
+ { key: 'fileUserIdAndName', name: '填报人', width: 190, align: 'center' },
|
|
|
+ { key: 'waitingUserList', name: '任务人', align: 'center' },
|
|
|
+
|
|
|
+])
|
|
|
+
|
|
|
+const tableListData = ref([])
|
|
|
+const getTableData = async () => {
|
|
|
+ if (searchForm.value.wbsId) {
|
|
|
+ tableListRef.value?.clearSelection()
|
|
|
+ tableCheckedKeys.value = []
|
|
|
+ tableLoading.value = true
|
|
|
+
|
|
|
+ // const classifyType = getContractTypeKey();
|
|
|
+ const { error, code, data, msg } = await queryApi.getPageData({
|
|
|
+ projectId: projectId.value,
|
|
|
+ contractId: contractId.value,
|
|
|
+ ...searchForm.value,
|
|
|
+ classifyType: contractTypeTabKey.value,
|
|
|
+ })
|
|
|
+ //处理数据
|
|
|
+ tableLoading.value = false
|
|
|
+ if (!error && code === 200) {
|
|
|
+ tableListData.value = getArrValue(data['records'])
|
|
|
+ searchForm.value.total = data.total || 0
|
|
|
+ } else {
|
|
|
+ // window.$message?.error(msg)
|
|
|
+ tableListData.value = []
|
|
|
+ searchForm.value.total = 0
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ window?.$message?.warning('请先选择一个树节点')
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//多选
|
|
|
+const tableCheckedKeys = ref([])
|
|
|
+const tableSelectionChange = (rows) => {
|
|
|
+ tableCheckedKeys.value = rows.filter((item) => {
|
|
|
+ return (item ?? '') !== ''
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+//名称被点击
|
|
|
+const tableRowName = (row) => {
|
|
|
+
|
|
|
+ bussPreview(row)
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+//多表预览
|
|
|
+
|
|
|
+const bussPreview = async (row) => {
|
|
|
+ const info = nodeDataInfo.value
|
|
|
+ row.bussPreviewLoading = true
|
|
|
+ const { error, code, data } = await wbsApi.getBussPdfs({
|
|
|
+ nodeId: row?.wbsId || '',
|
|
|
+ classify: contractTypeTabKey.value,
|
|
|
+ projectId: projectId.value,
|
|
|
+ // contractId: contractId.value
|
|
|
+ contractId: contractInfo.value?.contractType == 2 ? info?.contractIdRelation : contractId.value,
|
|
|
+ })
|
|
|
+
|
|
|
+ row.bussPreviewLoading = false
|
|
|
+ if (!error && code === 200) {
|
|
|
+ toPdfPage(data)
|
|
|
+ //window.open(data, '_blank')
|
|
|
+ } else {
|
|
|
+ window.$message?.warning('获取PDF失败')
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//上报
|
|
|
+const reportIds = ref('')
|
|
|
+const reportTaskName = ref('')
|
|
|
+const reportDatas = ref([])
|
|
|
+const reportTypeData = ref([])
|
|
|
+const showReportModal = ref(false)
|
|
|
+const reportLoading = ref(false)
|
|
|
+const reportArr = ref([])
|
|
|
+const reportModalClick = async () => {
|
|
|
+ const rows = tableCheckedKeys.value
|
|
|
+ //判断是否满足条件
|
|
|
+ const result = rows.every(({ status }) => {
|
|
|
+ return status === 0 || status === 3
|
|
|
+ })
|
|
|
+ //处理数据
|
|
|
+ let newArr = []
|
|
|
+ for (let i = 0; i < rows.length; i++) {
|
|
|
+ newArr.push(rows[i]['wbsId'])
|
|
|
+ }
|
|
|
+ reportTypeData.value = newArr
|
|
|
+
|
|
|
+ let newArr1 = []
|
|
|
+ for (let i = 0; i < rows.length; i++) {
|
|
|
+ newArr1.push(rows[i]['id'])
|
|
|
+ }
|
|
|
+ reportArr.value = newArr1
|
|
|
+ //判断状态
|
|
|
+ if (result) {
|
|
|
+ reportLoading.value = true
|
|
|
+ const taskCheck = await eVisaTaskCheckApi({
|
|
|
+ projectId: projectId.value,
|
|
|
+ contractId: contractId.value,
|
|
|
+ })
|
|
|
+ if (taskCheck) {
|
|
|
+ //初始ID
|
|
|
+ const row = getObjValue(rows[0])
|
|
|
+ reportIds.value = arrToId(rows)
|
|
|
+ //设置任务数据
|
|
|
+ let reportDataArr = []
|
|
|
+ rows.forEach(item => {
|
|
|
+ reportDataArr.push({
|
|
|
+ id: item?.id,
|
|
|
+ name: item?.name,
|
|
|
+ })
|
|
|
+ })
|
|
|
+ reportDatas.value = reportDataArr
|
|
|
+ //设置任务名称
|
|
|
+ reportTaskName.value = rows.length > 1 ? `${row.name}等${rows.length}个文件` : row.name
|
|
|
+ reportLoading.value = false
|
|
|
+ showReportModal.value = true
|
|
|
+ } else {
|
|
|
+ reportLoading.value = false
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ window.$message?.warning('已上报的文件不能进行再次上报,若要重新上报,要先撤回之前的上报,再重新上报')
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//上报的审批内容移除
|
|
|
+const reportTaskTagClose = (index) => {
|
|
|
+ const row = tableCheckedKeys.value[index]
|
|
|
+ tableListRef.value?.toggleRowSelection(row, false)
|
|
|
+}
|
|
|
+
|
|
|
+//上报完成
|
|
|
+const showReportFinish = () => {
|
|
|
+ showReportModal.value = false
|
|
|
+ getTableData()
|
|
|
+}
|
|
|
+
|
|
|
+//下载
|
|
|
+const downloadLoading = ref(false)
|
|
|
+const batchDownload = async () => {
|
|
|
+ const rows = tableCheckedKeys.value
|
|
|
+ const ids = arrToId(rows)
|
|
|
+ //批量下载
|
|
|
+ downloadLoading.value = true
|
|
|
+ const { error, disposition, res } = await queryApi.batchDownloadFileToZip({ ids: ids })
|
|
|
+ //处理数据
|
|
|
+ downloadLoading.value = false
|
|
|
+ if (!error) {
|
|
|
+ if (disposition) {
|
|
|
+ downloadBlob(res, disposition)
|
|
|
+ } else {
|
|
|
+ window.$message?.error('数据异常')
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//打印
|
|
|
+const printLoading = ref(false)
|
|
|
+const batchPrint = async () => {
|
|
|
+ const rows = tableCheckedKeys.value
|
|
|
+ const ids = arrToId(rows)
|
|
|
+ //批量下载
|
|
|
+ printLoading.value = true
|
|
|
+ const { error, code, data } = await queryApi.batchPrint({ ids: ids })
|
|
|
+ //处理数据
|
|
|
+ printLoading.value = false
|
|
|
+ const res = isString(data) ? data ?? '' : ''
|
|
|
+ if (!error && code === 200 && res) {
|
|
|
+ toPdfPage(res)
|
|
|
+ //window.open(res, '_blank')
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//废除
|
|
|
+const batchAbolishClick = () => {
|
|
|
+ const rows = tableCheckedKeys.value
|
|
|
+ //判断是否满足条件
|
|
|
+ const result = rows.every(({ status }) => {
|
|
|
+ return status !== 0 && status !== 3
|
|
|
+ })
|
|
|
+ //判断状态
|
|
|
+ if (result) {
|
|
|
+ //拼接ID
|
|
|
+ const ids = arrToId(rows)
|
|
|
+ window?.$messageBox?.alert('是否废除勾选的已上报文件?', '废除文件', {
|
|
|
+ showCancelButton: true,
|
|
|
+ confirmButtonText: '确定废除',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ callback: (action) => {
|
|
|
+ if (action === 'confirm') {
|
|
|
+ batchAbolishSave(ids)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ window.$message?.warning('未上报的文件不能废除')
|
|
|
+ }
|
|
|
+}
|
|
|
+//废除勾选的已上报文件
|
|
|
+const batchAbolishSave = async (ids) => {
|
|
|
+ const { error, code } = await queryApi.batchAbolish({ ids: ids, projectId:projectId.value, contractId:contractId.value })
|
|
|
+ //处理数据
|
|
|
+ if (!error && code === 200) {
|
|
|
+ window.$message?.success('批量废除成功')
|
|
|
+ tableCheckedKeys.value = []
|
|
|
+ getTableData()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//本地验签
|
|
|
+const localLoading = ref(false)
|
|
|
+const batchLocal = async () => {
|
|
|
+ const rows = tableCheckedKeys.value
|
|
|
+ //判断是否满足条件
|
|
|
+ const result = rows.every(({ status }) => {
|
|
|
+ return status === 2
|
|
|
+ })
|
|
|
+ //判断状态
|
|
|
+ if (result) {
|
|
|
+ const ids = arrToId(rows)
|
|
|
+ //请求数据
|
|
|
+ localLoading.value = true
|
|
|
+ const { error, code, data, disposition, res } = await queryApi.localVerify({
|
|
|
+ ids: ids,
|
|
|
+ })
|
|
|
+ //处理数据
|
|
|
+ localLoading.value = false
|
|
|
+ if (!error && code === 200) {
|
|
|
+ if (disposition) {
|
|
|
+ downloadBlob(res, disposition)
|
|
|
+ } else {
|
|
|
+ window.$message?.error('数据异常')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ window.$message?.warning('存在未审批或未上报数据')
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//在线验签
|
|
|
+const onlineLoading = ref(false)
|
|
|
+const onlineVerifyData = ref({})
|
|
|
+const onlineTitle = ref('')
|
|
|
+const isOnlineVerifyDrawer = ref(false)
|
|
|
+const onlineVerifyOptions = {
|
|
|
+ sizes: [50, 50],
|
|
|
+ snapOffset: 0,
|
|
|
+ minSize: ['10%', '80%'],
|
|
|
+}
|
|
|
+const batchOnline = async () => {
|
|
|
+ const rows = tableCheckedKeys.value
|
|
|
+ if (rows.length > 1) {
|
|
|
+ window.$message?.warning('在线验签只能勾选一条数据进行验签')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ //判断是否满足条件
|
|
|
+ const result = rows.every(({ status }) => {
|
|
|
+ return status === 2
|
|
|
+ })
|
|
|
+ //判断状态
|
|
|
+ if (!result) {
|
|
|
+ window.$message?.warning('存在未审批或未上报数据')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ //发起请求
|
|
|
+ onlineTitle.value = rows[0]?.name
|
|
|
+ const ids = arrToId(rows)
|
|
|
+ onlineLoading.value = true
|
|
|
+ const { error, code, msg, data } = await queryApi.onlineVerify({
|
|
|
+ ids: ids,
|
|
|
+ })
|
|
|
+ //处理数据
|
|
|
+ onlineLoading.value = false
|
|
|
+ if (!error && code === 200) {
|
|
|
+ onlineVerifyData.value = getObjValue(data)
|
|
|
+ cscTableData.value = getArrValue(data['certBeanVOList'])
|
|
|
+ isOnlineVerifyDrawer.value = true
|
|
|
+ } else {
|
|
|
+ onlineVerifyData.value = {}
|
|
|
+ window.$message?.error(msg ?? '操作失败')
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//签名信息
|
|
|
+const cscTableColumn = [
|
|
|
+ { key:'dn', name: '签名者', width: 300 },
|
|
|
+ { key:'time', name: '签名时间', width: 200 },
|
|
|
+ { key:'result', name: '验签结果' },
|
|
|
+]
|
|
|
+const cscTableData = ref([])
|
|
|
+
|
|
|
+//在线验签抽屉被关闭
|
|
|
+const onlineVerifyDrawerClose = () => {
|
|
|
+ isOnlineVerifyDrawer.value = false
|
|
|
+ onlineLoading.value = false
|
|
|
+}
|
|
|
+
|
|
|
+//树展开和收起
|
|
|
+const isWbsTreeShow = ref(true)
|
|
|
+const setWbsTreeShow = () => {
|
|
|
+ isWbsTreeShow.value = !isWbsTreeShow.value
|
|
|
+}
|
|
|
+
|
|
|
+//左右拖动,改变树形结构宽度
|
|
|
+const leftWidth = ref(300)
|
|
|
+//更新配置
|
|
|
+watch(
|
|
|
+ () => leftWidth.value,
|
|
|
+ (diffVal) => {
|
|
|
+
|
|
|
+ setUserConfig(diffVal)
|
|
|
+ },
|
|
|
+)
|
|
|
+const setUserConfig = async (data) => {
|
|
|
+ await useClick()
|
|
|
+ useAppState.setTreeWidth(data)
|
|
|
+ await userConfigSave({ treeWidth: data })
|
|
|
+}
|
|
|
+const onmousedown = () => {
|
|
|
+ let leftNum = 0
|
|
|
+ if (isLayout.value === 'no') {
|
|
|
+ leftNum = 0
|
|
|
+ } else {
|
|
|
+ leftNum = isCollapse.value ? 142 : 272
|
|
|
+ }
|
|
|
+ document.onmousemove = (ve) => {
|
|
|
+ let diffVal = ve.clientX - leftNum
|
|
|
+ if (diffVal >= 310 && diffVal <= 900) {
|
|
|
+ leftWidth.value = diffVal
|
|
|
+ }
|
|
|
+ }
|
|
|
+ document.onmouseup = () => {
|
|
|
+ document.onmousemove = null
|
|
|
+ document.onmouseup = null
|
|
|
+ }
|
|
|
+}
|
|
|
+const allElementsNotEmpty = (str)=> {
|
|
|
+ // 使用split将字符串分割成字符数组
|
|
|
+ // 使用every方法判断每个元素是否不为空字符串
|
|
|
+ return str.split('').every(char => char !== '')
|
|
|
+}
|
|
|
+//一键重签
|
|
|
+const signLoading = ref(false)
|
|
|
+const resignModal = ref(false)
|
|
|
+const resignModalRadio = ref(0)
|
|
|
+const resignClick = async ()=>{
|
|
|
+ const rows = tableCheckedKeys.value
|
|
|
+ if (rows.length <= 0) {
|
|
|
+ window.$message?.warning('勾选错误!只能操作待审批和已审批数据')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ resignModal.value = true
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+const signClick = async () => {
|
|
|
+ const rows = tableCheckedKeys.value
|
|
|
+ //获取任务id
|
|
|
+ const taskIds = arrToKey(rows, 'taskId')
|
|
|
+ const idsArr = taskIds.split(',')
|
|
|
+ let isCan = idsArr.some(ele=>!ele)
|
|
|
+
|
|
|
+ if (isCan) {
|
|
|
+ window.$message?.warning('参数异常,暂不支持该操作')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ //发起请求
|
|
|
+ signLoading.value = true
|
|
|
+ const { error, code, msg } = await queryApi.reSigningEVisa({
|
|
|
+ contractId: contractId.value,
|
|
|
+ projectId: projectId.value,
|
|
|
+ taskIds: taskIds,
|
|
|
+ classifyType: contractTypeTabKey.value,
|
|
|
+ type:resignModalRadio.value,
|
|
|
+ })
|
|
|
+ //处理数据
|
|
|
+ signLoading.value = false
|
|
|
+
|
|
|
+ if (!error && code === 200) {
|
|
|
+ window.$message?.success(msg ?? '提交成功,请请耐心等待重签,可继续操作其它的功能。')
|
|
|
+ getTableData().then()
|
|
|
+ } else {
|
|
|
+ window.$message?.error(msg ?? '操作失败')
|
|
|
+ }
|
|
|
+ resignModal.value = false
|
|
|
+}
|
|
|
+const cancelresign = ()=>{
|
|
|
+ resignModalRadio.value = 0
|
|
|
+ resignModal.value = false
|
|
|
+}
|
|
|
+//重新验签
|
|
|
+const saveAginClick = async ()=>{
|
|
|
+const rows = tableCheckedKeys.value
|
|
|
+const taskIds = rows.map(row => row.taskId)
|
|
|
+if (taskIds.some(id => id)) {
|
|
|
+ window.$message?.warning('勾选错误!只能操作未上报的数据')
|
|
|
+ return
|
|
|
+}
|
|
|
+const objArr = rows.map(row => ({
|
|
|
+ id: row.id,
|
|
|
+ wbsId: row.wbsId,
|
|
|
+ projectId: projectId.value,
|
|
|
+ contractId: contractId.value,
|
|
|
+ }))
|
|
|
+ saveAginLoading.value = true
|
|
|
+ const { error, code, msg } = await queryApi.reSigningEVisaStatus0(objArr)
|
|
|
+ //处理数据
|
|
|
+ saveAginLoading.value = false
|
|
|
+
|
|
|
+ if (!error && code === 200) {
|
|
|
+ window.$message?.success(msg ?? '提交成功,请请耐心等待重签,可继续操作其它的功能。')
|
|
|
+ getTableData().then()
|
|
|
+ } else {
|
|
|
+ window.$message?.error(msg ?? '操作失败')
|
|
|
+ }
|
|
|
+}
|
|
|
+const saveAginLoading = ref(false)
|
|
|
+
|
|
|
+//重置文件题名
|
|
|
+const resignTitleModal = ref(false)
|
|
|
+const resignTitleClick = async ()=>{
|
|
|
+
|
|
|
+ // resignTitleModal.value = true
|
|
|
+ if (isTemplateType.value) {
|
|
|
+
|
|
|
+ resignTitleModal.value = true
|
|
|
+ } else {
|
|
|
+ resignTitleSave()
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+const resignTitleSave = async ()=>{
|
|
|
+ const rows = tableCheckedKeys.value
|
|
|
+ let arr = []
|
|
|
+ rows.forEach(item=>{
|
|
|
+ arr.push({
|
|
|
+ id:item.id,
|
|
|
+ nodeName:'',
|
|
|
+ nameRule:'',
|
|
|
+ })
|
|
|
+ })
|
|
|
+ ruleModalSaveLoad.value = true
|
|
|
+ const { error, code, msg, data } = await queryApi.flushQueryName({
|
|
|
+ type:1,
|
|
|
+ list:arr,
|
|
|
+
|
|
|
+ })
|
|
|
+ //处理数据
|
|
|
+ ruleModalSaveLoad.value = false
|
|
|
+ if (!error && code === 200) {
|
|
|
+ window.$message?.success(msg)
|
|
|
+ resignTitleModal.value = false
|
|
|
+
|
|
|
+ getTableData().then()
|
|
|
+ } else {
|
|
|
+ window.$message?.error(msg || '操作失败')
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+const resignTitleSaveLoad = ref(false)
|
|
|
+
|
|
|
+//规则更改
|
|
|
+const changeRuleClick = async ()=>{
|
|
|
+ await getWbsNodeTypeApi()
|
|
|
+ ruleModal.value = true
|
|
|
+ ruleTableData.value = []
|
|
|
+
|
|
|
+ let arr = tableCheckedKeys.value.map(item=>{
|
|
|
+ return {
|
|
|
+
|
|
|
+ wbsId:item.wbsId,
|
|
|
+ projectId:projectId.value,
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ })
|
|
|
+ let arr1 = await getRuleListData(arr)
|
|
|
+ ruleTableData.value = arr1
|
|
|
+
|
|
|
+ for (let i = 0; i < ruleTableData.value.length; i++) {
|
|
|
+ const currentItem = ruleTableData.value[i]
|
|
|
+ const matchedItem = tableCheckedKeys.value.find(item => item.wbsId === currentItem.wbsId)
|
|
|
+ if (matchedItem) {
|
|
|
+ currentItem.name = matchedItem.name
|
|
|
+ currentItem.id = matchedItem.id
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // ruleTableData.value = arr
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+const ruleModal = ref(false)
|
|
|
+const ruleModalSaveLoad = ref(false)
|
|
|
+const ruleModalClose = ()=>{
|
|
|
+ ruleModal.value = false
|
|
|
+ setValue.value = []
|
|
|
+}
|
|
|
+const ruleModalSave = async ()=>{
|
|
|
+ let isCanSave = ruleTableData.value.every(row => row.rule && row.rule.length > 0)
|
|
|
+ if (!isCanSave) {
|
|
|
+ window.$message.warning('请选择题名规规则')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ let arr = []
|
|
|
+ ruleTableData.value.forEach(item=>{
|
|
|
+ arr.push({
|
|
|
+ id:item.id,
|
|
|
+ nodeName:item.newNodeName,
|
|
|
+ nameRule:item.rule.join('-'),
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ ruleModalSaveLoad.value = true
|
|
|
+ const { error, code, msg, data } = await queryApi.flushQueryName({
|
|
|
+ type:2,
|
|
|
+ list:arr,
|
|
|
+
|
|
|
+ })
|
|
|
+ //处理数据
|
|
|
+ ruleModalSaveLoad.value = false
|
|
|
+ if (!error && code === 200) {
|
|
|
+ window.$message?.success(msg)
|
|
|
+ getTableData().then()
|
|
|
+ ruleModalClose()
|
|
|
+ resignTitleModal.value = false
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+}
|
|
|
+const setValue = ref('')
|
|
|
+
|
|
|
+const ruleTableColumn = ref([
|
|
|
+ { key: 'name', name: '文件题名' },
|
|
|
+ { key: 'newNodeName', name: '修改后' },
|
|
|
+ { key: 'rule', name: '题名规则' },
|
|
|
+])
|
|
|
+const ruleTableData = ref([])
|
|
|
+const batchSetRule = async ()=>{
|
|
|
+ if (setValue.value.length === 0) {
|
|
|
+ window.$message.warning('请选择题名规则')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ ruleTableData.value.forEach( (ele)=>{
|
|
|
+ ele.rule = setValue.value
|
|
|
+ let matchedItems = [] // 存储匹配的项
|
|
|
+ if (ele.rule.length > 0) {
|
|
|
+ // 1. 找出所有匹配的项
|
|
|
+ matchedItems = nodeTypeData.value.filter(dataItem =>
|
|
|
+ ele.rule.includes(dataItem.value),
|
|
|
+ )
|
|
|
+ // 2. 按原始 sort 排序
|
|
|
+ matchedItems.sort((a, b) => a.sort - b.sort)
|
|
|
+
|
|
|
+ // 3. 更新 ele.rule 为排序后的 value 数组
|
|
|
+ ele.rule = matchedItems.map(item => item.value)
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ let arr = []
|
|
|
+ ruleTableData.value.forEach((item)=>{
|
|
|
+ arr.push({
|
|
|
+ wbsId:item.wbsId,
|
|
|
+ nameRule:item.rule.join('-'),
|
|
|
+ })
|
|
|
+ })
|
|
|
+ let afterArr = await getRuleValue(arr)
|
|
|
+
|
|
|
+
|
|
|
+ for (let i = 0; i < ruleTableData.value.length; i++) {
|
|
|
+ const currentItem = ruleTableData.value[i]
|
|
|
+ const matchedItem = afterArr.find(item => item.wbsId === currentItem.wbsId)
|
|
|
+ if (matchedItem) {
|
|
|
+ currentItem.newNodeName = matchedItem.newNodeName
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+const ruleChange = async (ele) => {
|
|
|
+ let str = ''
|
|
|
+ let matchedItems = [] // 存储匹配的项
|
|
|
+
|
|
|
+ if (ele.rule.length > 0) {
|
|
|
+ // 1. 找出所有匹配的项
|
|
|
+ matchedItems = nodeTypeData.value.filter(dataItem =>
|
|
|
+ ele.rule.includes(dataItem.value),
|
|
|
+ )
|
|
|
+
|
|
|
+ // 2. 按原始 sort 排序
|
|
|
+ matchedItems.sort((a, b) => a.sort - b.sort)
|
|
|
+
|
|
|
+ // 3. 更新 ele.rule 为排序后的 value 数组
|
|
|
+ ele.rule = matchedItems.map(item => item.value)
|
|
|
+
|
|
|
+ // 4. 生成连接字符串
|
|
|
+ str = ele.rule.join('-')
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // 5. 调用API
|
|
|
+ let arr = [{
|
|
|
+ wbsId: ele.wbsId,
|
|
|
+ nameRule: str,
|
|
|
+ }]
|
|
|
+
|
|
|
+ let afterArr = await getRuleValue(arr)
|
|
|
+ ele.newNodeName = afterArr[0].newNodeName
|
|
|
+}
|
|
|
+const getRuleLoad = ref(false)
|
|
|
+const ruleTableLoading = ref(false)
|
|
|
+const getRuleListData = async (arr) => {
|
|
|
+
|
|
|
+ ruleTableLoading.value = true
|
|
|
+ const { error, code, msg, data } = await queryApi.getNameRuleList(arr)
|
|
|
+ //处理数据
|
|
|
+ ruleTableLoading.value = false
|
|
|
+ if (!error && code === 200) {
|
|
|
+ return data || ''
|
|
|
+ } else {
|
|
|
+ return ''
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+const getRuleValue = async (arr) => {
|
|
|
+ // 检查 arr 中每一项的 nameRule 是否有值
|
|
|
+ const hasInvalidItem = arr.some(item => !item.nameRule || item.nameRule.length === 0)
|
|
|
+ if (hasInvalidItem) {
|
|
|
+ window.$message.warning('请选择题名规则')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ getRuleLoad.value = true
|
|
|
+ const { error, code, msg, data } = await queryApi.previewNodeName(arr)
|
|
|
+ //处理数据
|
|
|
+ getRuleLoad.value = false
|
|
|
+ if (!error && code === 200) {
|
|
|
+ return data || ''
|
|
|
+ } else {
|
|
|
+ return ''
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+//获取节点类型
|
|
|
+const nodeTypeData = ref([])
|
|
|
+const getWbsNodeTypeApi = async () => {
|
|
|
+ const { data } = await getDictionary({
|
|
|
+ code: 'name_rule',
|
|
|
+ })
|
|
|
+ //处理数据
|
|
|
+ let newArr = []
|
|
|
+ const newData = getArrValue(data)
|
|
|
+ for (let i = 0; i < newData.length; i++) {
|
|
|
+
|
|
|
+ newArr.push({
|
|
|
+ label: newData[i]['dictValue'],
|
|
|
+ value:newData[i]['dictKey'],
|
|
|
+ })
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ nodeTypeData.value = newArr
|
|
|
+}
|
|
|
+//一键重签1
|
|
|
+const resignModal1 = ref(false)
|
|
|
+const resignModalRadio1 = ref(0)
|
|
|
+const resignClick1 = ()=>{
|
|
|
+ const rows = tableCheckedKeys.value
|
|
|
+ if (rows.length <= 0) {
|
|
|
+ window.$message?.warning('勾选错误!只能操作待审批和已审批数据')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ resignModal1.value = true
|
|
|
+}
|
|
|
+const signLoading1 = ref(false)
|
|
|
+const cancelresign1 = ()=>{
|
|
|
+ resignModalRadio1.value = 0
|
|
|
+ resignModal1.value = false
|
|
|
+ checkTaskUserIds.value = []
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+const signClick1 = async () => {
|
|
|
+ const rows = tableCheckedKeys.value
|
|
|
+ //获取任务id
|
|
|
+ const ids = arrToId(rows)
|
|
|
+
|
|
|
+ if (resignModalRadio1.value === 1) {
|
|
|
+ if (checkTaskUserIds.value.length === 0) {
|
|
|
+ return window.$message?.warning('请选择用户')
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ checkTaskUserIds.value = []
|
|
|
+ }
|
|
|
+ //发起请求
|
|
|
+ signLoading1.value = true
|
|
|
+
|
|
|
+
|
|
|
+ const { error, code, msg } = await queryApi.reSigningEVisa1({
|
|
|
+ userIds: checkTaskUserIds.value.length === 1 ? checkTaskUserIds.value[0] : checkTaskUserIds.value.join(','),
|
|
|
+
|
|
|
+ ids: ids,
|
|
|
+
|
|
|
+
|
|
|
+ })
|
|
|
+ //处理数据
|
|
|
+ signLoading1.value = false
|
|
|
+
|
|
|
+ if (!error && code === 200) {
|
|
|
+ window.$message?.success(msg ?? '提交成功,请请耐心等待重签,可继续操作其它的功能。')
|
|
|
+ cancelresign1()
|
|
|
+ getTableData().then()
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+const checkTaskUserIds = ref([])
|
|
|
+const batchOnlineClickLoad = ref(false)
|
|
|
+
|
|
|
+const batchOnlineClick = async ()=>{
|
|
|
+ const rows = tableCheckedKeys.value
|
|
|
+ //获取任务id
|
|
|
+ const ids = arrToId(rows)
|
|
|
+ batchOnlineClickLoad.value = true
|
|
|
+
|
|
|
+ const { error, code, msg } = await queryApi.updateCheckPdfInfo(
|
|
|
+ {
|
|
|
+ classify:contractTypeTabKey.value,
|
|
|
+ type:2,
|
|
|
+ ids,
|
|
|
+ },
|
|
|
+
|
|
|
+ )
|
|
|
+ batchOnlineClickLoad.value = false
|
|
|
+ //处理数据
|
|
|
+ signLoading1.value = false
|
|
|
+
|
|
|
+ if (!error && code === 200) {
|
|
|
+ window.$message?.success(msg )
|
|
|
+ getCheckPdfPaceInfoData()
|
|
|
+ getTableData()
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+const treeMenus = ref([
|
|
|
+ {
|
|
|
+ icon: 'edit',
|
|
|
+ label: '电签检测',
|
|
|
+ key: 'add1',
|
|
|
+ },
|
|
|
+
|
|
|
+])
|
|
|
+
|
|
|
+const ElTreeMenuClick = async ({ key, node, data, keys }) => {
|
|
|
+ nodeItemInfo.value = node
|
|
|
+ nodeDataInfo.value = data
|
|
|
+ setStoreValue('wbsTreeExpandKeys', keys)
|
|
|
+ if (key === 'add1') {
|
|
|
+ window?.$messageBox?.alert('是否进行电签检测?', '电签检测', {
|
|
|
+ showCancelButton: true,
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ callback:async (action) => {
|
|
|
+ if (action === 'confirm') {
|
|
|
+ batchOnlineClickLoad.value = true
|
|
|
+ const { error, code, msg } = await queryApi.updateCheckPdfInfo(
|
|
|
+ {
|
|
|
+ classify:contractTypeTabKey.value,
|
|
|
+ type:1,
|
|
|
+ ids:nodeDataInfo.value.primaryKeyId,
|
|
|
+ },
|
|
|
+
|
|
|
+ )
|
|
|
+ batchOnlineClickLoad.value = false
|
|
|
+ //处理数据
|
|
|
+ signLoading1.value = false
|
|
|
+
|
|
|
+ if (!error && code === 200) {
|
|
|
+ window.$message?.success(msg )
|
|
|
+ getCheckPdfPaceInfoData().then()
|
|
|
+
|
|
|
+ getTableData().then()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ })
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+//获取进度状态
|
|
|
+const progressObj = ref({
|
|
|
+ finishCount:0,
|
|
|
+ totalCount:0,
|
|
|
+ pace:0,
|
|
|
+})
|
|
|
+const getCheckPdfPaceInfoData = async () => {
|
|
|
+ const { error, code, data, msg } = await queryApi.getCheckPdfPaceInfo({
|
|
|
+
|
|
|
+ contractId: contractId.value,
|
|
|
+
|
|
|
+ classify: contractTypeTabKey.value,
|
|
|
+ })
|
|
|
+ //处理数据
|
|
|
+
|
|
|
+ if (!error && code === 200) {
|
|
|
+ progressObj.value = getObjValue(data)
|
|
|
+
|
|
|
+ } else {
|
|
|
+ progressObj.value = {
|
|
|
+ finishCount:0,
|
|
|
+ totalCount:0,
|
|
|
+ pace:0,
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+@import "../../styles/data-fill/query.scss";
|
|
|
+
|
|
|
+.error-border {
|
|
|
+ border: 1px solid red;
|
|
|
+}
|
|
|
+.iscusor {
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+.bg-primary-color {
|
|
|
+ background-color: var(--el-color-primary) ;
|
|
|
+}
|
|
|
+.basic-info-box {
|
|
|
+ height: calc(100% - 77px);
|
|
|
+}
|
|
|
+</style>
|
|
|
+
|
|
|
+<style lang="scss">
|
|
|
+.hc-online-verify-drawer .el-card.hc-new-card-box {
|
|
|
+ .hc-card-header-box {
|
|
|
+ .online-verify-title {
|
|
|
+ font-size: 20px;
|
|
|
+ }
|
|
|
+ .online-verify-icon {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ cursor: pointer;
|
|
|
+ color: #5a5959;
|
|
|
+ i {
|
|
|
+ font-size: 18px;
|
|
|
+ }
|
|
|
+ &:hover {
|
|
|
+ color: var(--el-color-primary);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+.custom-select{
|
|
|
+ .el-select__wrapper {
|
|
|
+ height: 32px;
|
|
|
+ overflow-y: hidden;
|
|
|
+ }
|
|
|
+ .el-select__selection.is-near {
|
|
|
+ height: 32px;
|
|
|
+ overflow-y: hidden;
|
|
|
+ overflow-x: hidden;
|
|
|
+ flex-wrap: nowrap;
|
|
|
+
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|