query.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  1. <template>
  2. <div class="hc-layout-box">
  3. <div class="hc-layout-left-box" id="wbs-left-tree" :style="'width:' + leftWidth + 'px;'">
  4. <div class="hc-project-box">
  5. <div class="hc-project-icon-box">
  6. <HcIcon name="layers"/>
  7. </div>
  8. <div class="ml-2 project-name-box">
  9. <span class="text-xl text-cut project-alias">{{projectInfo['projectAlias']}}</span>
  10. <div class="text-xs text-cut project-name">{{projectInfo['name']}}</div>
  11. </div>
  12. </div>
  13. <div class="hc-tree-box">
  14. <div class="hc-search-tree-val">
  15. <el-input v-model="searchTreeVal" block size="large" placeholder="请输入名称关键词检索" clearable @keyup="searchTreeKeyUp">
  16. <template #suffix>
  17. <HcIcon name="search" ui="text-2xl"/>
  18. </template>
  19. </el-input>
  20. </div>
  21. <div class="hc-tree-scrollbar" v-loading="treeLoading" element-loading-text="获取数据中...">
  22. <el-scrollbar>
  23. <KeepAlive>
  24. <template v-if="isSearchTree">
  25. <HcTreeData :datas="searchTreeData" :autoExpandKeys="treeAutoExpandKeys" isColor @nodeTap="wbsElTreeClick"/>
  26. </template>
  27. <template v-else>
  28. <WbsTree :autoExpandKeys="treeAutoExpandKeys" :projectId="projectId" :contractId="contractId" isColor @nodeTap="wbsElTreeClick"/>
  29. </template>
  30. </KeepAlive>
  31. </el-scrollbar>
  32. </div>
  33. </div>
  34. <div class="hc-tree-foot-tip-box">
  35. <div class="dot-view green">已审批</div>
  36. <div class="dot-view black">未填报</div>
  37. <div class="dot-view orange">已填报-待审批</div>
  38. <div class="dot-view blue">已填报-未上报</div>
  39. </div>
  40. <!--左右拖动-->
  41. <div class="horizontal-drag-line" @mousedown="onmousedown"/>
  42. </div>
  43. <div class="hc-layout-content-box">
  44. <HcCard :scrollbar="false" actionSize="lg">
  45. <template #header>
  46. <HcTooltip keys="query_report">
  47. <el-button type="primary" hc-btn :disabled="tableCheckedKeys.length <= 0" @click="reportModalClick">
  48. <HcIcon name="drive_folder_upload"/>
  49. <span>上报</span>
  50. </el-button>
  51. </HcTooltip>
  52. <HcTooltip keys="query_download">
  53. <el-button hc-btn :disabled="tableCheckedKeys.length <= 0" :loading="downloadLoading" @click="batchDownload">
  54. <HcIcon name="download"/>
  55. <span>下载</span>
  56. </el-button>
  57. </HcTooltip>
  58. <HcTooltip keys="query_print">
  59. <el-button hc-btn :disabled="tableCheckedKeys.length <= 0" :loading="printLoading" @click="batchPrint">
  60. <HcIcon name="print"/>
  61. <span>打印</span>
  62. </el-button>
  63. </HcTooltip>
  64. <HcTooltip keys="query_abolish">
  65. <el-button hc-btn :disabled="tableCheckedKeys.length <= 0" @click="batchAbolishClick">
  66. <HcIcon name="delete"/>
  67. <span>废除</span>
  68. </el-button>
  69. </HcTooltip>
  70. <HcTooltip keys="query_local_attestation">
  71. <el-button hc-btn :disabled="tableCheckedKeys.length <= 0" :loading="localLoading" @click="batchLocal">
  72. <HcIcon name="folder"/>
  73. <span>本地验签</span>
  74. </el-button>
  75. </HcTooltip>
  76. <HcTooltip keys="query_online_attestation">
  77. <el-button hc-btn :disabled="tableCheckedKeys.length <= 0" :loading="onlineLoading" @click="batchOnline">
  78. <HcIcon name="browse_activity"/>
  79. <span>在线验签</span>
  80. </el-button>
  81. </HcTooltip>
  82. </template>
  83. <template #search>
  84. <div class="flex items-center">
  85. <div class="w-40">
  86. <el-select v-model="searchForm.taskStatus" placeholder="流程状态" clearable>
  87. <el-option v-for="item in processStatusData" :key="item.value" :label="item['dictValue']" :value="item['dictKey']"/>
  88. </el-select>
  89. </div>
  90. <div class="w-40 ml-2">
  91. <el-select v-model="searchForm.fileUserIdAndName" placeholder="填报人" clearable>
  92. <el-option v-for="item in reportingPersonData" :key="item.value" :label="item['label']" :value="item['value']"/>
  93. </el-select>
  94. </div>
  95. <div class="w-40 ml-2">
  96. <el-select v-model="searchForm.sourceType" placeholder="文件类型" clearable>
  97. <el-option v-for="item in fileTypeData" :key="item.value" :label="item['dictValue']" :value="item['dictKey']"/>
  98. </el-select>
  99. </div>
  100. <div class="w-32 ml-2">
  101. <el-select v-model="searchForm.reportNumber" placeholder="上报批次" clearable>
  102. <el-option v-for="item in reportBatchData" :key="item.value" :label="item['label']" :value="item['value']"/>
  103. </el-select>
  104. </div>
  105. <div class="w-64 ml-2">
  106. <HcDatePicker :dates="betweenTime" clearable @change="betweenTimeUpdate"/>
  107. </div>
  108. <div class="w-60 ml-2">
  109. <el-input v-model="searchForm.queryValue" placeholder="请输入名称关键词检索" clearable @keyup="keyUpEvent"/>
  110. </div>
  111. <div class="ml-2">
  112. <el-button type="primary" @click="searchClick">搜索</el-button>
  113. </div>
  114. </div>
  115. </template>
  116. <el-scrollbar>
  117. <div class="hc-table-ref-box">
  118. <el-table ref="recycleTableRef" hc :data="tableListData" :loading="tableLoading" stripe @selection-change="tableSelectionChange">
  119. <el-table-column type="selection" width="50" />
  120. <el-table-column prop="num" label="序号" width="80">
  121. <template #default="scope">
  122. {{scope.$index + 1}}
  123. </template>
  124. </el-table-column>
  125. <el-table-column prop="name" label="文件名称" />
  126. <el-table-column prop="startTime" label="开始时间"/>
  127. <el-table-column prop="taskStatusStr" label="流程状态"/>
  128. <el-table-column prop="reportNumber" label="上报批次"/>
  129. <el-table-column prop="fileUserIdAndName" label="填报人"/>
  130. <el-table-column prop="tesk" label="任务人"/>
  131. </el-table>
  132. </div>
  133. </el-scrollbar>
  134. <template #action>
  135. <HcPages :pages="searchForm" @change="pageChange"/>
  136. </template>
  137. </HcCard>
  138. </div>
  139. <!--批量上报审批-->
  140. <HcReportModal title="批量上报审批" url="informationWriteQuery/batchTask" :show="showReportModal" :projectId="projectId" :contractId="contractId"
  141. :taskName="reportTaskName" :ids="reportIds" :addition="reportAddition" @hide="showReportModal = false" @finish="showReportFinish"/>
  142. </div>
  143. </template>
  144. <script setup>
  145. import {ref,watch,onMounted} from "vue";
  146. import {useAppStore} from "~src/store/index";
  147. import WbsTree from "./components/WbsTree.vue"
  148. import HcTreeData from "./components/HcTreeData.vue"
  149. import {getStoreData, setStoreData} from '~src/utils/storage'
  150. import {isType, downloadBlob} from "vue-utils-plus"
  151. import queryApi from '~api/data-fill/query';
  152. //变量
  153. const useAppState = useAppStore()
  154. const {getObjValue, getArrValue, isObjNull} = isType()
  155. const projectId = ref(useAppState.getProjectId);
  156. const contractId = ref(useAppState.getContractId);
  157. const projectInfo = ref(useAppState.getProjectInfo);
  158. const isCollapse = ref(useAppState.getCollapse)
  159. //监听
  160. watch(() => [
  161. useAppState.getCollapse
  162. ], ([Collapse]) => {
  163. isCollapse.value = Collapse
  164. })
  165. //自动展开缓存
  166. const treeAutoExpandKeys = ref(getStoreData('wbsTreeExpandKeys') || [])
  167. //渲染完成
  168. onMounted(() => {
  169. getFileUser()
  170. getReportNumber()
  171. getDictBizClassify('flowTaskStatus')
  172. getDictBizClassify('fileType')
  173. })
  174. //树搜索
  175. const isSearchTree = ref(false)
  176. const searchTreeVal = ref('')
  177. const searchTreeData = ref([])
  178. //回车
  179. const treeLoading = ref(false)
  180. const searchTreeKeyUp = (e) => {
  181. if (e.key === "Enter") {
  182. searchTreeClick()
  183. }
  184. }
  185. const searchTreeClick = async () => {
  186. if (searchTreeVal.value) {
  187. isSearchTree.value = true
  188. treeLoading.value = true
  189. const {error, code, data} = await queryApi.searchContractTree({
  190. contractId: contractId.value,
  191. queryValue: searchTreeVal.value
  192. })
  193. //判断状态
  194. if (!error && code === 200) {
  195. searchTreeData.value = getArrValue(data)
  196. treeLoading.value = false
  197. } else {
  198. treeLoading.value = false
  199. searchTreeData.value = []
  200. }
  201. } else {
  202. treeLoading.value = false
  203. isSearchTree.value = false
  204. }
  205. }
  206. //树相关的变量
  207. const primaryKeyId = ref('')
  208. const nodeItemInfo = ref({})
  209. const nodeDataInfo = ref({})
  210. //树被点击
  211. const wbsElTreeClick = ({node, data, keys}) => {
  212. nodeItemInfo.value = node
  213. nodeDataInfo.value = data
  214. primaryKeyId.value = data['primaryKeyId'] || ''
  215. //缓存自动展开
  216. treeAutoExpandKeys.value = keys
  217. setStoreData('wbsTreeExpandKeys',keys)
  218. //改变搜索表单数据
  219. searchForm.value.wbsId = data['contractIdRelation'] ? data['id'] : data['primaryKeyId']
  220. searchForm.value.contractIdRelation = data['contractIdRelation']
  221. searchForm.value.current = 1;
  222. getTableData()
  223. }
  224. //搜索条件
  225. const processStatusData = ref([]) //流程状态
  226. const reportingPersonData = ref([]) //填报人
  227. const fileTypeData = ref([]) //文件类型
  228. const reportBatchData = ref([]) //上报批次
  229. //获取所有填报人
  230. const getFileUser = async () => {
  231. const {error, code, data} = await queryApi.getFileUser({
  232. contractId: contractId.value
  233. })
  234. //判断状态
  235. if (!error && code === 200) {
  236. let res = getArrValue(data), userArr = [];
  237. res.forEach(item => {
  238. userArr.push({label: item['userName'], value: `${item['userId']}-${item['userName']}`})
  239. })
  240. reportingPersonData.value = userArr
  241. } else {
  242. reportingPersonData.value = []
  243. }
  244. }
  245. //获取上报批次
  246. const getReportNumber = async () => {
  247. const {error, code, data} = await queryApi.getReportNumber({
  248. contractId: contractId.value
  249. })
  250. //判断状态
  251. if (!error && code === 200) {
  252. console.log(data)
  253. //let res = getArrValue(data);
  254. reportBatchData.value = []
  255. } else {
  256. reportBatchData.value = []
  257. }
  258. }
  259. //获取流程状态分类和文件类型分类
  260. const getDictBizClassify = async (type) => {
  261. const {error, code, data} = await queryApi.getDictBizClassify({
  262. contractId: contractId.value,
  263. code: type
  264. })
  265. //判断状态
  266. if (!error && code === 200) {
  267. if (code === 'flowTaskStatus') {
  268. processStatusData.value = getArrValue(data)
  269. } else if (code === 'fileType') {
  270. fileTypeData.value = getArrValue(data)
  271. }
  272. } else {
  273. if (code === 'flowTaskStatus') {
  274. processStatusData.value = []
  275. } else if (code === 'fileType') {
  276. fileTypeData.value = []
  277. }
  278. }
  279. }
  280. //搜索表单
  281. const searchForm = ref({
  282. taskStatus: null, fileUserIdAndName: null, sourceType: null, reportNumber: null, betweenTime: null,
  283. queryValue: null, contractIdRelation: null, wbsId: null, current: 1, size: 20, total: 0
  284. })
  285. //日期时间被选择
  286. const betweenTime = ref(null)
  287. const betweenTimeUpdate = ({val,arr}) => {
  288. betweenTime.value = arr
  289. searchForm.value.betweenTime = `${val['start']}~${val['end']}`
  290. }
  291. //回车搜索
  292. const keyUpEvent = (e) => {
  293. if (e.key === "Enter") {
  294. searchForm.value.current = 1;
  295. getTableData()
  296. }
  297. }
  298. //搜索
  299. const searchClick = () => {
  300. searchForm.value.current = 1;
  301. getTableData()
  302. }
  303. //分页被点击
  304. const pageChange = ({current, size}) => {
  305. searchForm.value.current = current
  306. searchForm.value.size = size
  307. getTableData()
  308. }
  309. //获取数据
  310. const tableLoading = ref(false)
  311. const tableListData = ref([])
  312. const getTableData = async () => {
  313. if (!!searchForm.value.wbsId) {
  314. tableLoading.value = true
  315. const { error, code, data } = await queryApi.getPageData({
  316. projectId: projectId.value,
  317. contractId: contractId.value,
  318. ...searchForm.value
  319. })
  320. //处理数据
  321. tableLoading.value = false
  322. if (!error && code === 200) {
  323. tableListData.value = getArrValue(data['records'])
  324. searchForm.value.total = data.total || 0
  325. } else {
  326. tableListData.value = []
  327. searchForm.value.total = 0
  328. }
  329. } else {
  330. window?.$message?.warning('请先选择一个树节点')
  331. }
  332. }
  333. //多选
  334. const tableCheckedKeys = ref([]);
  335. const tableSelectionChange = (rows) => {
  336. tableCheckedKeys.value = rows.filter((item) => {
  337. return (item??'') !== '';
  338. })
  339. }
  340. //上报
  341. const reportIds = ref('')
  342. const reportTaskName = ref('')
  343. const reportAddition = ref({})
  344. const showReportModal = ref(false)
  345. const reportModalClick = () => {
  346. const rows = tableCheckedKeys.value;
  347. //判断是否满足条件
  348. const result = rows.every(({status})=> {
  349. return status === 0 || status === 3
  350. })
  351. //判断状态
  352. if (result) {
  353. //const info = nodeDataInfo.value;
  354. const row = getObjValue(rows[0])
  355. reportIds.value = rowsToId(rows)
  356. //设置任务名称
  357. reportTaskName.value = rows.length > 1 ? `${row.name}等${rows.length}个文件` : row.name
  358. //reportAddition.value = {contractIdRelation: info['contractIdRelation']}
  359. showReportModal.value = true
  360. } else {
  361. window.$message?.warning('已上报的文件不能进行再次上报,若要重新上报,要先撤回之前的上报,再重新上报')
  362. }
  363. }
  364. //上报完成
  365. const showReportFinish = () => {
  366. showReportModal.value = false
  367. getTableData()
  368. }
  369. //下载
  370. const downloadLoading = ref(false)
  371. const batchDownload = async () => {
  372. const rows = tableCheckedKeys.value;
  373. const ids = rowsToId(rows)
  374. //批量下载
  375. downloadLoading.value = true
  376. const { error, disposition, res } = await queryApi.batchDownloadFileToZip({ids: ids})
  377. //处理数据
  378. downloadLoading.value = false
  379. if (!error) {
  380. if (disposition) {
  381. downloadBlob(res,disposition)
  382. } else {
  383. window.$message?.error('数据异常')
  384. }
  385. }
  386. }
  387. //打印
  388. const printLoading = ref(false)
  389. const batchPrint = async () => {
  390. const rows = tableCheckedKeys.value;
  391. const ids = rowsToId(rows)
  392. //批量下载
  393. printLoading.value = true
  394. const { error, code, data } = await queryApi.batchPrint({ids: ids})
  395. //处理数据
  396. printLoading.value = false
  397. if (!error && code === 200) {
  398. console.log(data)
  399. if (isObjNull(data)) {
  400. window.$message?.error('数据异常')
  401. } else {
  402. //待写
  403. }
  404. }
  405. }
  406. //废除
  407. const batchAbolishClick = async () => {
  408. const rows = tableCheckedKeys.value;
  409. //判断是否满足条件
  410. const result = rows.every(({status})=> {
  411. return status !== 0 && status !== 3
  412. })
  413. //判断状态
  414. if (result) {
  415. //拼接ID
  416. const ids = rowsToId(rows)
  417. window?.$messageBox?.alert('是否废除勾选的已上报文件?', '废除文件', {
  418. showCancelButton: true,
  419. confirmButtonText: '确定废除',
  420. cancelButtonText: '取消',
  421. callback: (action) => {
  422. if (action === 'confirm') {
  423. batchAbolishSave(ids)
  424. }
  425. }
  426. })
  427. } else {
  428. window.$message?.warning('未上报的文件不能废除')
  429. }
  430. }
  431. //废除勾选的已上报文件
  432. const batchAbolishSave = async (ids) => {
  433. const { error, code } = await queryApi.batchAbolish({ids: ids})
  434. //处理数据
  435. if (!error && code === 200) {
  436. window.$message?.success('批量废除成功')
  437. tableCheckedKeys.value = []
  438. getTableData()
  439. }
  440. }
  441. //本地验签
  442. const localLoading = ref(false)
  443. const batchLocal = async () => {
  444. const rows = tableCheckedKeys.value;
  445. //判断是否满足条件
  446. const result = rows.every(({status})=> {
  447. return status === 2
  448. })
  449. //判断状态
  450. if (result) {
  451. const ids = rowsToId(rows)
  452. //请求数据
  453. localLoading.value = true
  454. const { error, code, data } = await queryApi.localVerify({
  455. ids: ids
  456. })
  457. //处理数据
  458. localLoading.value = false
  459. if (!error && code === 200) {
  460. console.log(data)
  461. }
  462. } else {
  463. window.$message?.warning('存在未审批或未上报数据')
  464. }
  465. }
  466. //在线验签
  467. const onlineLoading = ref(false)
  468. const batchOnline = async () => {
  469. const rows = tableCheckedKeys.value;
  470. if (rows.length > 1) {
  471. window.$message?.warning('在线验签只能勾选一条数据进行验签')
  472. return;
  473. }
  474. if (rows[0].status !== 2) {
  475. window.$message?.warning('存在未审批或未上报数据')
  476. return;
  477. }
  478. //发起
  479. onlineLoading.value = true
  480. const { error, code, data } = await queryApi.onlineVerify({
  481. ids: rows[0]['id']
  482. })
  483. //处理数据
  484. localLoading.value = false
  485. if (!error && code === 200) {
  486. console.log(data)
  487. }
  488. }
  489. //拼接ID
  490. const rowsToId = (rows) => {
  491. return rows.map((obj) => {
  492. return obj.id;
  493. }).join(",")
  494. }
  495. //左右拖动,改变树形结构宽度
  496. const leftWidth = ref(382);
  497. const onmousedown = () => {
  498. const leftNum = isCollapse.value ? 142 : 272
  499. document.onmousemove = (ve) => {
  500. let diffVal = ve.clientX - leftNum;
  501. if(diffVal >= 310 && diffVal <= 900) {
  502. leftWidth.value = diffVal;
  503. }
  504. }
  505. document.onmouseup = () => {
  506. document.onmousemove = null;
  507. document.onmouseup = null;
  508. }
  509. }
  510. </script>
  511. <style lang="scss" scoped>
  512. @import "../../styles/data-fill/query.scss";
  513. </style>