comprehensiveQuery.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. <template>
  2. <div class="comprehensive-query">
  3. <!-- 搜索区域 -->
  4. <div class="search-area">
  5. <el-form :model="searchForm" inline class="search-form">
  6. <el-form-item label="项目名称:">
  7. <el-input
  8. v-model="searchForm.projectName"
  9. placeholder="请输入项目名称"
  10. style="width: 200px"
  11. clearable
  12. ></el-input>
  13. </el-form-item>
  14. <el-form-item label="监审期间:">
  15. <el-date-picker
  16. v-model="searchForm.startYear"
  17. type="year"
  18. placeholder="选择开始年份"
  19. style="width: 150px"
  20. clearable
  21. format="yyyy年"
  22. value-format="yyyy"
  23. ></el-date-picker>
  24. <span style="margin: 0 5px">~</span>
  25. <el-date-picker
  26. v-model="searchForm.endYear"
  27. type="year"
  28. placeholder="选择结束年份"
  29. style="width: 150px"
  30. clearable
  31. format="yyyy年"
  32. value-format="yyyy"
  33. ></el-date-picker>
  34. </el-form-item>
  35. <el-form-item label="被监审单位:">
  36. <!-- <el-input
  37. v-model="searchForm.auditedUnitName"
  38. placeholder="请输入被监审单位"
  39. style="width: 200px"
  40. clearable
  41. ></el-input> -->
  42. <el-select
  43. v-model="searchForm.auditedUnitId"
  44. placeholder="请选择被监审单位"
  45. style="width: 200px"
  46. clearable
  47. filterable
  48. allow-create
  49. default-first-option
  50. >
  51. <el-option
  52. v-for="item in auditedUnitOptions"
  53. :key="item.unitId"
  54. :label="item.unitName"
  55. :value="item.unitId"
  56. ></el-option>
  57. </el-select>
  58. </el-form-item>
  59. <el-form-item label="立项年度:">
  60. <el-date-picker
  61. v-model="searchForm.year"
  62. type="year"
  63. placeholder="选择立项年度"
  64. style="width: 150px"
  65. clearable
  66. format="yyyy年"
  67. value-format="yyyy"
  68. ></el-date-picker>
  69. </el-form-item>
  70. <el-form-item>
  71. <el-button type="primary" icon="el-icon-search" @click="handleQuery">
  72. 查询
  73. </el-button>
  74. <el-button
  75. icon="el-icon-refresh"
  76. style="margin-left: 10px"
  77. @click="handleReset"
  78. >
  79. 重置
  80. </el-button>
  81. </el-form-item>
  82. </el-form>
  83. </div>
  84. <!-- 表格区域 -->
  85. <div class="table-area">
  86. <el-table
  87. v-loading="loading"
  88. :data="auditProjectList"
  89. :border="true"
  90. :stripe="false"
  91. :span-method="handleSpanMethod"
  92. :row-style="rowStyle"
  93. :row-class-name="'no-stripe-row'"
  94. >
  95. <!-- 序号列 -->
  96. <el-table-column
  97. prop="index"
  98. label="序号"
  99. width="80"
  100. header-align="center"
  101. align="center"
  102. >
  103. <template slot-scope="scope">
  104. {{ getParentNodeIndex(scope.row, scope.$index) }}
  105. </template>
  106. </el-table-column>
  107. <!-- 立项年度 -->
  108. <el-table-column
  109. prop="year"
  110. label="立项年度"
  111. width="100"
  112. header-align="center"
  113. align="center"
  114. ></el-table-column>
  115. <!-- 监审地区 -->
  116. <el-table-column
  117. prop="areaName"
  118. label="监审地区"
  119. width="100"
  120. header-align="center"
  121. align="center"
  122. ></el-table-column>
  123. <!-- 成本监审项目名称 -->
  124. <el-table-column
  125. prop="projectName"
  126. label="成本监审项目名称"
  127. align="left"
  128. header-align="center"
  129. >
  130. <template slot-scope="scope">
  131. <a
  132. href="javascript:;"
  133. class="link-text"
  134. @click="handleViewTaskDetail(scope.row)"
  135. >
  136. {{ scope.row.projectName }}
  137. </a>
  138. </template>
  139. </el-table-column>
  140. <!-- 监审对象 -->
  141. <el-table-column
  142. prop="auditObject"
  143. label="监审对象"
  144. header-align="center"
  145. ></el-table-column>
  146. <!-- 监审期间 -->
  147. <el-table-column
  148. prop="auditPeriod"
  149. label="监审期间"
  150. width="200"
  151. header-align="center"
  152. align="center"
  153. ></el-table-column>
  154. <!-- 监审形式 -->
  155. <el-table-column
  156. prop="auditTypeName"
  157. label="监审形式"
  158. width="120"
  159. header-align="center"
  160. align="center"
  161. >
  162. <!-- <template slot-scope="scope">
  163. {{ getDictName('auditType', scope.row.auditType) }}
  164. </template> -->
  165. </el-table-column>
  166. <!-- 监审主体 -->
  167. <el-table-column
  168. prop="orgName"
  169. label="监审主体"
  170. align="left"
  171. header-align="center"
  172. ></el-table-column>
  173. <!-- 下载 -->
  174. <el-table-column
  175. label="下载"
  176. width="200"
  177. align="center"
  178. header-align="center"
  179. >
  180. <template slot-scope="scope">
  181. <el-button
  182. type="text"
  183. size="small"
  184. @click="handleMessage(scope.row, 'chengben')"
  185. >
  186. 监审任务
  187. </el-button>
  188. <el-button
  189. type="text"
  190. size="small"
  191. @click="handleDownloadFile(scope.row)"
  192. >
  193. 监审卷宗
  194. </el-button>
  195. </template>
  196. </el-table-column>
  197. </el-table>
  198. <!-- 分页组件 -->
  199. <div class="pagination-container">
  200. <el-pagination
  201. :current-page="pagination.currentPage"
  202. :page-size="pagination.pageSize"
  203. :total="pagination.total"
  204. :page-sizes="pagination.pageSizes"
  205. layout="total, sizes, prev, pager, next, jumper"
  206. @size-change="handleSizeChange"
  207. @current-change="handleCurrentChange"
  208. ></el-pagination>
  209. </div>
  210. </div>
  211. <!-- 成本监审任务制定弹窗(用于“主任务”查看) -->
  212. <task-customized-release-dialog
  213. :visible.sync="taskReleaseDialogVisible"
  214. :project="project"
  215. :is-view="true"
  216. @backToList="taskReleaseDialogVisible = false"
  217. @close="taskReleaseDialogVisible = false"
  218. />
  219. <!-- 成本监审信息弹窗(用于“子任务”按钮) -->
  220. <cbjs-info
  221. :id="cbjsInfoData && cbjsInfoData.id"
  222. :selected-project="cbjsInfoData"
  223. :visible.sync="cbjsInfoVisible"
  224. :current-node="cbjsInfoData && cbjsInfoData.currentNode"
  225. :current-status="cbjsInfoData && cbjsInfoData.status"
  226. />
  227. </div>
  228. </template>
  229. <script>
  230. import { getReviewTaskList } from '@/api/audit/auditIndex'
  231. // import { dictMixin } from '@/mixins/useDict'
  232. import TaskCustomizedReleaseDialog from '@/components/task/TaskCustomizedReleaseDialog.vue'
  233. import cbjsInfo from './components/cbjsInfo.vue'
  234. import { getCostProjectDetail } from '@/api/taskCustomizedRelease.js'
  235. import { getAllUnitList } from '@/api/auditEntityManage.js'
  236. export default {
  237. name: 'ComprehensiveQuery',
  238. components: {
  239. TaskCustomizedReleaseDialog,
  240. cbjsInfo,
  241. },
  242. // mixins: [dictMixin],
  243. data() {
  244. return {
  245. dictData: {
  246. auditType: [], // 监审形式
  247. },
  248. // 搜索表单数据
  249. searchForm: {
  250. projectName: '',
  251. startYear: '',
  252. endYear: '',
  253. auditedUnitId: '',
  254. year: '',
  255. },
  256. // 表格数据
  257. auditProjectList: [],
  258. // 行合并映射表(当前页)
  259. rowSpanMap: {},
  260. // 分页配置
  261. pagination: {
  262. currentPage: 1,
  263. pageSize: 10,
  264. total: 0,
  265. pageSizes: [10, 20, 50],
  266. },
  267. // 任务详情弹窗相关
  268. taskReleaseDialogVisible: false,
  269. project: {},
  270. isView: true,
  271. // 成本监审信息弹窗相关
  272. cbjsInfoVisible: false,
  273. cbjsInfoData: null,
  274. loading: false,
  275. auditedUnitOptions: [],
  276. }
  277. },
  278. mounted() {
  279. this.getOptions()
  280. this.handleQuery()
  281. },
  282. methods: {
  283. getOptions() {
  284. getAllUnitList()
  285. .then((res) => {
  286. if (res && res.value) {
  287. this.auditedUnitOptions = res.value
  288. }
  289. })
  290. .catch((e) => {
  291. console.warn('获取单位列表失败', e)
  292. })
  293. },
  294. // 加载项目列表(优化分页数据处理)
  295. async handleQuery() {
  296. try {
  297. this.loading = true
  298. const params = {
  299. pageNum: this.pagination.currentPage,
  300. pageSize: this.pagination.pageSize,
  301. isGd: 1,
  302. type: 1,
  303. ...this.searchForm,
  304. }
  305. const response = await getReviewTaskList(params)
  306. if (response.state && response.value) {
  307. const records = response.value.records || []
  308. this.auditProjectList = []
  309. this.rowSpanMap = {} // 重置为当前页的合并映射
  310. records.forEach((record) => {
  311. // 处理父项(保留用于当前页合并计算,会被隐藏)
  312. const parentRow = {
  313. ...record,
  314. // 合并列:这些列会被合并显示
  315. year: record.year, // 立项年度
  316. areaName: record.areaName, // 监审地区
  317. projectName: record.projectName, // 成本监审项目名称
  318. // 非合并列(父行会被隐藏,这些值不会显示)
  319. auditObject: record.auditedUnitName || record.auditObject || '',
  320. auditPeriod: record.auditPeriod || record.auditPeriodName || '',
  321. auditType: record.auditType || record.auditTypeName || '',
  322. orgName: record.orgName || record.orgFullName || '',
  323. status: this.getStatusText(record.status),
  324. isSubTask: record.pid !== '0',
  325. isParent: true,
  326. hasChildren:
  327. !!record.childTasks && record.childTasks.length > 0,
  328. }
  329. this.auditProjectList.push(parentRow)
  330. // 处理子项(仅当前页内的子行)
  331. if (record.childTasks && record.childTasks.length > 0) {
  332. // 记录当前页父项的合并行数(父行+子行)
  333. this.rowSpanMap[record.id] = record.childTasks.length + 1
  334. record.childTasks.forEach((child) => {
  335. this.auditProjectList.push({
  336. ...child,
  337. // 合并列:这些列会被合并显示,使用父项的值
  338. year: child.year || record.year, // 立项年度
  339. areaName: child.areaName || record.areaName, // 监审地区
  340. projectName: record.projectName, // 继承父项项目名称
  341. // 非合并列:每行独立显示,使用子项自己的值
  342. auditObject: child.auditedUnitName || '', // 监审对象(子项自己的被监审单位)
  343. auditPeriod: child.auditPeriod || record.auditPeriod || '', // 监审期间
  344. auditType: child.auditType || record.auditType || '', // 监审形式
  345. auditTypeName: record.auditTypeName || '', // 监审形式名称
  346. orgName:
  347. child.orgName ||
  348. child.orgFullName ||
  349. record.orgName ||
  350. record.orgFullName ||
  351. '', // 监审主体
  352. status: this.getStatusText(child.status),
  353. isSubTask: true,
  354. parentId: record.id,
  355. isParent: false,
  356. })
  357. })
  358. }
  359. })
  360. // 使用接口返回的总条数(而非当前页长度)
  361. this.pagination.total = response.value.total || 0
  362. } else {
  363. this.auditProjectList = []
  364. this.rowSpanMap = {}
  365. this.pagination.total = 0
  366. this.$message.warning('未获取到项目数据')
  367. }
  368. } catch (error) {
  369. console.error('加载审核项目列表失败:', error)
  370. this.auditProjectList = []
  371. this.rowSpanMap = {}
  372. this.pagination.total = 0
  373. } finally {
  374. this.loading = false
  375. }
  376. },
  377. // 获取状态文本
  378. getStatusText(status) {
  379. const statusMap = {
  380. ccls: '资料初审',
  381. 200: '审核通过',
  382. clcs: '审核中',
  383. }
  384. return statusMap[status] || status
  385. },
  386. // 处理重置
  387. handleReset() {
  388. this.searchForm = {
  389. projectName: '',
  390. startYear: '',
  391. endYear: '',
  392. auditedUnitName: '',
  393. year: '',
  394. }
  395. this.pagination.currentPage = 1 // 重置页码
  396. this.handleQuery()
  397. },
  398. // 处理分页大小变化
  399. handleSizeChange(size) {
  400. this.pagination.pageSize = size
  401. this.pagination.currentPage = 1 // 页码重置为1
  402. this.handleQuery() // 重新加载当前页数据
  403. },
  404. // 处理页码变化
  405. handleCurrentChange(current) {
  406. this.pagination.currentPage = current
  407. this.handleQuery() // 重新加载当前页数据
  408. },
  409. // 处理分页变化(兼容旧接口)
  410. handlePaginationChange(pagination) {
  411. this.pagination = { ...this.pagination, ...pagination }
  412. this.handleQuery() // 重新加载当前页数据
  413. },
  414. // 处理下载监审卷宗
  415. handleDownloadFile(row) {
  416. console.log('下载监审卷宗:', row)
  417. this.$message.success('监审卷宗功能待实现')
  418. },
  419. // 查看任务详情
  420. handleViewTaskDetail(row) {
  421. this.openTaskReleaseDialog(row)
  422. },
  423. // 打开成本监审任务制定弹窗(只读查看)
  424. openTaskReleaseDialog(row) {
  425. if (!row) return
  426. const projectId = row.projectId || row.id || ''
  427. if (!projectId) {
  428. this.$message.warning('缺少项目ID,无法查看详情')
  429. return
  430. }
  431. this.project = row
  432. this.isView = true
  433. this.taskReleaseDialogVisible = true
  434. // getCostProjectDetail({ id: projectId })
  435. // .then((res) => {
  436. // this.project = (res && res.value) || {}
  437. // this.taskReleaseDialogVisible = true
  438. // })
  439. // .catch(() => {
  440. // this.project = row || {}
  441. // this.taskReleaseDialogVisible = true
  442. // })
  443. },
  444. // 查看成本监审信息
  445. handleMessage(row, type) {
  446. if (type === 'chengben') {
  447. this.cbjsInfoData = row
  448. this.cbjsInfoData.taskId = row.id || {}
  449. this.cbjsInfoVisible = true
  450. }
  451. },
  452. // 生成连续序号(基于当前页可见行)
  453. getParentNodeIndex(row, index) {
  454. // 过滤当前页可见行(排除父行)
  455. const visibleRows = this.auditProjectList.filter(
  456. (item) => !item.isParent
  457. )
  458. // 查找当前行在可见行中的索引
  459. const visibleIndex = visibleRows.findIndex((item) => item.id === row.id)
  460. return visibleIndex !== -1 ? visibleIndex + 1 : index + 1
  461. },
  462. // 隐藏父行样式
  463. rowStyle({ row }) {
  464. if (row.isParent) {
  465. return {
  466. display: 'none',
  467. height: '0px !important',
  468. padding: '0px !important',
  469. border: 'none !important',
  470. }
  471. }
  472. return {}
  473. },
  474. // 处理合并单元格逻辑(基于当前页数据)
  475. handleSpanMethod({ row, column, rowIndex }) {
  476. const mergeColumns = ['year', 'areaName', 'projectName']
  477. const columnProp = column && column.property
  478. // 父行:所有列都隐藏(通过 rowStyle 已经隐藏,这里确保不显示)
  479. if (row.isParent) {
  480. return { rowspan: 0, colspan: 0 }
  481. }
  482. // 非合并列:不合并,正常显示
  483. if (!mergeColumns.includes(columnProp)) {
  484. return { rowspan: 1, colspan: 1 }
  485. }
  486. // 合并列:只处理子行的合并逻辑
  487. if (!row.parentId) {
  488. // 没有父行的行(无子项的父项),不合并
  489. return { rowspan: 1, colspan: 1 }
  490. }
  491. // 在当前页数据中查找父行
  492. const parentRow = this.auditProjectList.find(
  493. (item) => item.id === row.parentId
  494. )
  495. // 父行不在当前页时不合并
  496. if (!parentRow) {
  497. return { rowspan: 1, colspan: 1 }
  498. }
  499. const spanCount = this.rowSpanMap[parentRow.id] || 1
  500. // 判断是否是当前页父行的第一个子行
  501. if (this.isFirstChildInCurrentPage(parentRow.id, rowIndex)) {
  502. // 合并行数 = 子行数量(因为父行被隐藏了)
  503. const childCount = spanCount - 1
  504. return { rowspan: childCount, colspan: 1 }
  505. } else {
  506. // 其他子行的合并列隐藏
  507. return { rowspan: 0, colspan: 0 }
  508. }
  509. },
  510. // 判断是否是当前页父行的第一个子行
  511. isFirstChildInCurrentPage(parentId, currentIndex) {
  512. // 在当前页数据中查找父行索引
  513. const parentIndex = this.auditProjectList.findIndex(
  514. (item) => item.id === parentId
  515. )
  516. // 父行不在当前页或索引错误时返回false
  517. if (parentIndex === -1) return false
  518. // 第一个子行索引 = 父行索引 + 1(当前页内有效)
  519. return currentIndex === parentIndex + 1
  520. },
  521. },
  522. }
  523. </script>
  524. <style lang="scss" scoped>
  525. @import '@/styles/costAudit.scss';
  526. .comprehensive-query {
  527. padding: 20px;
  528. }
  529. // 表格区域样式
  530. .table-area {
  531. margin-top: 20px;
  532. }
  533. // 分页组件样式
  534. .pagination-container {
  535. margin-top: 20px;
  536. display: flex;
  537. justify-content: flex-end;
  538. align-items: center;
  539. }
  540. // 覆盖斑马纹样式
  541. ::v-deep .no-stripe-row {
  542. background-color: #ffffff !important;
  543. }
  544. ::v-deep .el-table__body tr {
  545. background-color: #ffffff !important;
  546. }
  547. // 确保合并单元格边框正常
  548. ::v-deep .el-table__cell {
  549. border-right: 1px solid #ebeef5 !important;
  550. }
  551. ::v-deep .el-table__header th {
  552. border-right: 1px solid #ebeef5 !important;
  553. }
  554. </style>