index.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. <template>
  2. <div class="cost-audit-management">
  3. <!-- 成本审核项目列表页面 -->
  4. <div class="audit-list-container">
  5. <div class="search-section">
  6. 监审项目名称:
  7. <el-input
  8. v-model="searchQuery"
  9. placeholder="请输入监审项目名称"
  10. style="width: 300px; margin-right: 10px"
  11. clearable
  12. />
  13. <el-button
  14. type="primary"
  15. icon="iconfont-5039297 icon-chaxun"
  16. @click="handleSearch"
  17. >
  18. 查询
  19. </el-button>
  20. <el-button
  21. type="primary"
  22. plain
  23. icon="iconfont-5039297 icon-zhongzhi"
  24. style="margin-left: 10px"
  25. @click="handleReset"
  26. >
  27. 重置
  28. </el-button>
  29. </div>
  30. <el-table
  31. v-loading="loading"
  32. class="mb10"
  33. :data="auditProjectList"
  34. style="width: 100%"
  35. border
  36. default-expand-all
  37. row-key="id"
  38. :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
  39. >
  40. <el-table-column
  41. type="index"
  42. label="序号"
  43. width="80"
  44. header-align="center"
  45. align="center"
  46. >
  47. <template slot-scope="scope">
  48. <!-- 只显示父节点的序号 -->
  49. <span v-if="scope.row.children">
  50. {{ getParentNodeIndex(scope.row) }}
  51. </span>
  52. <span v-else></span>
  53. </template>
  54. </el-table-column>
  55. <el-table-column
  56. prop="projectName"
  57. label="成本监审项目名称"
  58. show-overflow-tooltip
  59. header-align="center"
  60. align="left"
  61. />
  62. <el-table-column
  63. prop="auditObject"
  64. label="监审对象"
  65. header-align="center"
  66. align="left"
  67. />
  68. <el-table-column
  69. prop="auditPeriod"
  70. label="监审期间"
  71. header-align="center"
  72. align="center"
  73. width="120"
  74. />
  75. <el-table-column
  76. prop="source"
  77. label="立项来源"
  78. header-align="center"
  79. align="center"
  80. width="100"
  81. />
  82. <el-table-column
  83. prop="form"
  84. label="监审形式"
  85. header-align="center"
  86. align="center"
  87. width="100"
  88. />
  89. <el-table-column
  90. prop="currentNodeName"
  91. label="状态"
  92. align="center"
  93. width="150"
  94. >
  95. <template slot-scope="scope">
  96. <span v-if="!scope.row.isSubTask">
  97. <span v-if="scope.row.currentNode === 'gd'">
  98. {{ scope.row.currentNodeName }}
  99. </span>
  100. <span v-else>
  101. {{ scope.row.currentNodeName }}-{{ scope.row.statusName }}
  102. </span>
  103. </span>
  104. <span v-else>{{ scope.row.statusName }}</span>
  105. </template>
  106. </el-table-column>
  107. <el-table-column label="操作" align="center" width="260">
  108. <template slot-scope="scope">
  109. <span v-if="!scope.row.isSubTask" class="action-buttons">
  110. <el-button type="text" @click="handleViewTaskDetail(scope.row)">
  111. 任务详情
  112. </el-button>
  113. <el-button type="text" @click="handleOpenMainDetails(scope.row)">
  114. 任务办理
  115. </el-button>
  116. <el-button type="text" @click="handleCheckRecord(scope.row)">
  117. 备忘录
  118. </el-button>
  119. </span>
  120. <span v-if="scope.row.isSubTask" class="action-buttons">
  121. <el-button
  122. v-if="
  123. scope.row.currentNode === 'clcs' &&
  124. (scope.row.status === '200' || scope.row.status === '600')
  125. "
  126. type="text"
  127. @click="handleOpenDetails(scope.row)"
  128. >
  129. 资料初审
  130. </el-button>
  131. <el-button
  132. v-if="
  133. (scope.row.currentNode === 'sdsh' ||
  134. scope.row.currentNode === 'yjfk') &&
  135. scope.row.status === '200'
  136. "
  137. type="text"
  138. @click="handleOpenDetails(scope.row)"
  139. >
  140. 成本审核
  141. </el-button>
  142. <el-button
  143. v-if="
  144. scope.row.currentNode === 'yjgz' && scope.row.status === '200'
  145. "
  146. type="text"
  147. @click="handleOpenDetails(scope.row)"
  148. >
  149. 意见告知
  150. </el-button>
  151. <el-button
  152. v-if="
  153. (scope.row.currentNode === 'yjfk' &&
  154. scope.row.status === '260') ||
  155. (scope.row.currentNode === 'jtsy' &&
  156. scope.row.status === '200')
  157. "
  158. type="text"
  159. @click="handleOpenDetails(scope.row, 'shenhe')"
  160. >
  161. 审核
  162. </el-button>
  163. <el-button
  164. v-if="scope.row.status === '300'"
  165. type="text"
  166. @click="handleHf(scope.row)"
  167. >
  168. 恢复
  169. </el-button>
  170. <el-button
  171. type="text"
  172. @click="handleMessage(scope.row, 'chengben')"
  173. >
  174. 查看
  175. </el-button>
  176. </span>
  177. </template>
  178. </el-table-column>
  179. </el-table>
  180. <el-pagination
  181. background
  182. layout="total, sizes, prev, pager, next"
  183. :current-page="pageNum"
  184. :page-sizes="[10, 20, 30, 40]"
  185. :page-size="pageSize"
  186. :total="total"
  187. @current-change="handleCurrentChange"
  188. @size-change="handleSizeChange"
  189. />
  190. </div>
  191. <!-- 详情弹窗组件 -->
  192. <details-dialog
  193. :id="selectedProject && selectedProject.id"
  194. ref="detailsRef"
  195. :selected-project="selectedProject"
  196. :visible.sync="detailsVisible"
  197. :current-node="selectedProject && selectedProject.currentNode"
  198. :current-status="selectedProject && selectedProject.status"
  199. :is-shenhe="isShenhe"
  200. @close="handleDetailsClose"
  201. @refresh="handleRefresh"
  202. />
  203. <!-- 主详情弹窗组件 -->
  204. <mainDetailsDialog
  205. :id="selectedProject && selectedProject.id"
  206. ref="mainDetailsRef"
  207. :project="selectedProject"
  208. :visible.sync="mainDetailsVisible"
  209. :current-node="selectedProject && selectedProject.currentNode"
  210. :current-status="selectedProject && selectedProject.status"
  211. @close="handleMainDetailsClose"
  212. @refresh="handleMainRefresh"
  213. />
  214. <taskInfo ref="taskInfo" />
  215. <!-- 成本监审信息弹窗 -->
  216. <cbjs-info
  217. :id="cbjsInfoData && cbjsInfoData.id"
  218. :selected-project="cbjsInfoData"
  219. :visible.sync="cbjsInfoVisible"
  220. :current-node="cbjsInfoData && cbjsInfoData.currentNode"
  221. :current-status="cbjsInfoData && cbjsInfoData.status"
  222. />
  223. <taskDetail ref="taskDetail" />
  224. <!-- 成本监审任务制定弹窗(用于“任务详情”只读查看) -->
  225. <task-customized-release-dialog
  226. :visible.sync="taskReleaseDialogVisible"
  227. :project="project"
  228. :is-view="true"
  229. @backToList="taskReleaseDialogVisible = false"
  230. @close="taskReleaseDialogVisible = false"
  231. />
  232. </div>
  233. </template>
  234. <script>
  235. import { doProcessBtn } from '@/api/dataPreliminaryReview'
  236. import detailsDialog from './details.vue'
  237. import mainDetailsDialog from './mainDetails.vue'
  238. // 成本监审任务列表API
  239. import { getReviewTaskList } from '@/api/audit/auditIndex'
  240. import taskInfo from '@/components/task/taskInfo.vue'
  241. import cbjsInfo from '@/components/task/cbjsInfo.vue'
  242. import taskDetail from '@/components/task/taskDetail.vue'
  243. import TaskCustomizedReleaseDialog from '@/components/task/TaskCustomizedReleaseDialog.vue'
  244. import { getCostProjectDetail } from '@/api/taskCustomizedRelease.js'
  245. import { dictMixin } from '@/mixins/useDict'
  246. export default {
  247. name: 'CostAuditManagement',
  248. components: {
  249. detailsDialog,
  250. taskInfo,
  251. cbjsInfo,
  252. mainDetailsDialog,
  253. taskDetail,
  254. TaskCustomizedReleaseDialog,
  255. },
  256. mixins: [dictMixin],
  257. data() {
  258. return {
  259. isShenhe: false,
  260. dictData: {
  261. projectProposal: [],
  262. },
  263. // 分页相关
  264. pageNum: 1,
  265. pageSize: 10,
  266. total: 0,
  267. // 搜索相关
  268. searchQuery: '',
  269. // 列表数据
  270. auditProjectList: [],
  271. // 加载状态
  272. loading: false,
  273. // 详情弹窗相关
  274. detailsVisible: false,
  275. selectedProject: null,
  276. // cbjsInfo弹窗相关
  277. cbjsInfoVisible: false,
  278. cbjsInfoData: null,
  279. mainDetailsVisible: false,
  280. // 任务详情(项目)弹窗
  281. taskReleaseDialogVisible: false,
  282. project: {},
  283. isView: true,
  284. }
  285. },
  286. created() {
  287. this.loadAuditProjectList()
  288. },
  289. methods: {
  290. // 获取父节点的连续序号
  291. getParentNodeIndex(row) {
  292. // 过滤出所有父节点
  293. const parentNodes = this.auditProjectList.filter(
  294. (item) => item.children && item.children.length > 0
  295. )
  296. // 找到当前行在父节点数组中的索引
  297. const index = parentNodes.findIndex((item) => item.id === row.id)
  298. // 返回序号(索引+1)
  299. return index + 1
  300. },
  301. // 加载审核项目列表
  302. async loadAuditProjectList() {
  303. try {
  304. this.loading = true
  305. // 调用API获取数据
  306. const params = {
  307. pageNum: this.pageNum,
  308. pageSize: this.pageSize,
  309. projectName: this.searchQuery,
  310. }
  311. const response = await getReviewTaskList(params)
  312. // 根据API返回格式处理数据
  313. if (response.state && response.value) {
  314. // 获取记录列表
  315. const records = response.value.records || []
  316. // 转换数据格式,将childTasks转换为children以适应表格组件
  317. this.auditProjectList = records.map((record) => {
  318. return {
  319. id: record.id,
  320. projectName: record.projectName,
  321. auditObject: record.auditedUnitName,
  322. auditPeriod: record.auditPeriod,
  323. source: this.getSourceTypeText(record.sourceType),
  324. // form: this.getAuditTypeText(record.auditType),
  325. form: record.auditTypeName,
  326. status: this.getStatusText(record.status),
  327. statusName: record.statusName,
  328. isSubTask: record.pid !== '0',
  329. currentNodeName: record.currentNodeName,
  330. currentNode: record.currentNode,
  331. projectId: record.projectId,
  332. auditedUnitId: record.auditedUnitId,
  333. children: record.childTasks
  334. ? record.childTasks.map((child) => ({
  335. id: child.id,
  336. projectName: child.projectName,
  337. auditObject: child.auditedUnitName,
  338. auditPeriod: record.auditPeriod, // 子任务可能使用父任务的审核期间
  339. source: '',
  340. form: '',
  341. currentNode: child.currentNode,
  342. status: child.status,
  343. statusName: child.statusName,
  344. isSubTask: true,
  345. projectId: child.projectId,
  346. auditedUnitId: child.auditedUnitId,
  347. taskId: child.id,
  348. catalogId: child.catalogId,
  349. }))
  350. : [],
  351. }
  352. })
  353. // 设置总数
  354. this.total = response.value.total || 0
  355. } else {
  356. this.auditProjectList = []
  357. this.total = 0
  358. this.$message.warning('未获取到审核项目数据')
  359. }
  360. } catch (error) {
  361. // this.$message.error('加载审核项目列表失败')
  362. console.error('加载审核项目列表失败:', error)
  363. } finally {
  364. this.loading = false
  365. }
  366. },
  367. // 获取来源类型文本
  368. getSourceTypeText(type) {
  369. return this.getDictName('projectProposal', type)
  370. },
  371. // 获取审核类型文本
  372. getAuditTypeText(type) {
  373. const typeMap = {
  374. 1: '定期监审',
  375. 2: '定调价监审',
  376. // 可根据实际需求补充其他类型
  377. }
  378. return typeMap[type] || type
  379. },
  380. // 获取状态文本
  381. getStatusText(status) {
  382. const statusMap = {
  383. ccls: '资料初审',
  384. 200: '审核通过',
  385. clcs: '审核中', // 添加clcs状态映射为审核中
  386. // 可根据实际需求补充其他状态
  387. }
  388. return statusMap[status] || status
  389. },
  390. // 搜索
  391. handleSearch() {
  392. // 搜索逻辑
  393. this.loadAuditProjectList()
  394. },
  395. // 重置
  396. handleReset() {
  397. // 重置搜索条件
  398. this.searchQuery = ''
  399. // 重新加载数据
  400. this.loadAuditProjectList()
  401. },
  402. // 查看任务详情
  403. handleViewTaskDetail(row) {
  404. // 使用成本监审任务制定弹窗(只读)
  405. this.openTaskReleaseDialog(row)
  406. },
  407. // 打开成本监审任务制定弹窗(只读查看)
  408. openTaskReleaseDialog(row) {
  409. if (!row) return
  410. const projectId =
  411. row.projectId || row.projectID || row.id || row.taskId || ''
  412. if (!projectId) {
  413. this.$message &&
  414. this.$message.warning &&
  415. this.$message.warning('缺少项目ID,无法查看详情')
  416. return
  417. }
  418. this.isView = true
  419. getCostProjectDetail({ id: projectId })
  420. .then((res) => {
  421. this.project = (res && res.value) || {}
  422. this.taskReleaseDialogVisible = true
  423. })
  424. .catch(() => {
  425. // 回退:接口失败时至少展示当前行数据
  426. this.project = row || {}
  427. this.taskReleaseDialogVisible = true
  428. })
  429. },
  430. // 打开详情弹窗
  431. handleOpenDetails(project, type) {
  432. this.selectedProject = project
  433. this.isShenhe = type === 'shenhe'
  434. this.detailsVisible = true
  435. this.$nextTick(() => {
  436. if (this.$refs.detailsRef) {
  437. this.$refs.detailsRef.open()
  438. }
  439. })
  440. },
  441. handleOpenMainDetails(project) {
  442. // console.log('project', project)
  443. this.selectedProject = project
  444. this.mainDetailsVisible = true
  445. },
  446. // 详情弹窗关闭处理
  447. handleDetailsClose() {
  448. this.selectedProject = null
  449. this.detailsVisible = false
  450. // 可以在这里添加刷新列表的逻辑
  451. },
  452. // 刷新表格数据(可选重置到第一页)
  453. handleRefresh(payload) {
  454. if (payload && payload.resetToFirst) {
  455. this.pageNum = 1
  456. }
  457. this.loadAuditProjectList()
  458. },
  459. // 主详情弹窗关闭处理
  460. handleMainDetailsClose() {
  461. this.selectedProject = null
  462. this.mainDetailsVisible = false
  463. },
  464. // 主详情刷新处理
  465. handleMainRefresh() {
  466. // 刷新列表数据
  467. this.loadAuditProjectList()
  468. },
  469. // 查记录
  470. handleCheckRecord(project) {
  471. // memoManage
  472. this.$router.push({
  473. name: 'memoManage',
  474. // params: { projectId: project.id }
  475. })
  476. },
  477. // 恢复任务
  478. async handleHf(row) {
  479. if (!row || !row.id) {
  480. this.$message.error('缺少任务ID')
  481. return
  482. }
  483. // 弹出确认对话框
  484. this.$confirm('确定要恢复此任务吗?', '恢复任务', {
  485. confirmButtonText: '确定',
  486. cancelButtonText: '取消',
  487. type: 'warning',
  488. })
  489. .then(async () => {
  490. try {
  491. const params = {
  492. taskId: row.id,
  493. key: 2,
  494. status: 200,
  495. processNodeKey: row.currentNode,
  496. }
  497. const response = await doProcessBtn(params)
  498. if (response && response.code === 200) {
  499. this.$message.success('恢复任务成功')
  500. // 刷新列表
  501. this.loadAuditProjectList()
  502. } else {
  503. this.$message.error(response?.message || '恢复任务失败')
  504. }
  505. } catch (error) {
  506. // this.$message.error('恢复任务失败')
  507. console.error('恢复任务失败:', error)
  508. }
  509. })
  510. .catch(() => {
  511. // 用户取消操作
  512. this.$message.info('已取消恢复任务')
  513. })
  514. },
  515. // 分页处理
  516. handleSizeChange(size) {
  517. this.pageSize = size
  518. this.loadAuditProjectList()
  519. },
  520. handleCurrentChange(current) {
  521. this.pageNum = current
  522. this.loadAuditProjectList()
  523. },
  524. // 查看 - 修改为打开cbjsInfo弹窗
  525. handleMessage(row, type) {
  526. if (type === 'chengben') {
  527. this.cbjsInfoData = row
  528. this.cbjsInfoVisible = true
  529. } else {
  530. this.$refs.taskInfo.open(row, type)
  531. }
  532. },
  533. },
  534. }
  535. </script>
  536. <style scoped>
  537. .cost-audit-management {
  538. padding: 20px;
  539. }
  540. /* 列表页面样式 */
  541. .search-section {
  542. margin-bottom: 20px;
  543. }
  544. .action-buttons {
  545. font-size: 12px;
  546. }
  547. .action-buttons a {
  548. color: #409eff;
  549. text-decoration: none;
  550. }
  551. .separator {
  552. margin: 0 5px;
  553. color: #999;
  554. }
  555. .note-section {
  556. margin-top: 20px;
  557. }
  558. .note-text {
  559. color: #f56c6c;
  560. font-size: 12px;
  561. margin: 5px 0;
  562. }
  563. /* 详情页面样式 */
  564. .audit-detail-container {
  565. margin-top: 20px;
  566. }
  567. .detail-form {
  568. margin-top: 20px;
  569. }
  570. .tab-content {
  571. padding: 20px;
  572. background-color: #f9f9f9;
  573. min-height: 200px;
  574. }
  575. /* 办理页面样式 */
  576. .audit-process-container {
  577. margin-top: 20px;
  578. }
  579. .process-actions {
  580. margin-bottom: 20px;
  581. }
  582. .process-actions .el-button {
  583. margin-right: 10px;
  584. }
  585. /* 响应式设计 */
  586. @media (max-width: 768px) {
  587. .process-steps {
  588. flex-direction: column;
  589. }
  590. .step-line {
  591. width: 2px;
  592. height: 20px;
  593. margin: 5px 0;
  594. }
  595. .documents-layout {
  596. flex-direction: column;
  597. }
  598. .documents-type-list {
  599. width: 100%;
  600. margin-right: 0;
  601. margin-bottom: 20px;
  602. }
  603. .meeting-form .el-row {
  604. flex-direction: column;
  605. }
  606. .meeting-form .el-col {
  607. width: 100%;
  608. }
  609. }
  610. </style>