index.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. <template>
  2. <div class="task-query-statistics">
  3. <!-- 页面标题 -->
  4. <!-- <h2>成本监审任务查询统计</h2> -->
  5. <div v-if="activeView == 'list'">
  6. <!-- 查询区域 -->
  7. <div class="search-container">
  8. <el-form :inline="true" :model="searchForm" class="demo-form-inline">
  9. <el-form-item label="年度:">
  10. <el-date-picker
  11. v-model="searchForm.year"
  12. type="year"
  13. placeholder="请选择计划年度"
  14. format="yyyy"
  15. value-format="yyyy"
  16. ></el-date-picker>
  17. </el-form-item>
  18. <el-form-item label="地区:">
  19. <el-cascader
  20. v-model="searchForm.areaCode"
  21. :options="districtTree"
  22. :props="districtTreeCascaderProps"
  23. :show-all-levels="false"
  24. clearable
  25. placeholder="请选择地区"
  26. @change="handleAreaChange"
  27. ></el-cascader>
  28. </el-form-item>
  29. <el-form-item label="状态:">
  30. <el-select
  31. v-model="searchForm.currentNode"
  32. placeholder="请选择状态"
  33. >
  34. <el-option label="全部" value=""></el-option>
  35. <el-option label="材料初审" value="clcs"></el-option>
  36. <el-option label="实地审核" value="sdsh"></el-option>
  37. <el-option label="意见告知" value="yjgz"></el-option>
  38. <el-option label="意见反馈" value="yjfk"></el-option>
  39. <el-option label="集体审议" value="jtsy"></el-option>
  40. <el-option label="出具报告" value="cjbg"></el-option>
  41. <el-option label="归档" value="gd"></el-option>
  42. </el-select>
  43. </el-form-item>
  44. <el-form-item label="监审项目名称:">
  45. <el-input
  46. v-model="searchForm.projectName"
  47. placeholder="请输入监审项目名称"
  48. clearable
  49. maxlength="30"
  50. ></el-input>
  51. </el-form-item>
  52. <el-form-item>
  53. <el-button
  54. icon="iconfont-5039297 icon-chaxun"
  55. type="primary"
  56. @click="generateTableData"
  57. >
  58. 搜索
  59. </el-button>
  60. <el-button
  61. plain
  62. type="primary"
  63. icon="iconfont-5039297 icon-zhongzhi"
  64. @click="handleReset"
  65. >
  66. 重置
  67. </el-button>
  68. </el-form-item>
  69. </el-form>
  70. </div>
  71. <!-- 统计信息 -->
  72. <div class="statistics-info">
  73. <span>
  74. 在办事项:
  75. <span class="pending-count">{{ statistics.pendingCount }}</span>
  76. </span>
  77. <span>
  78. 已结事项:
  79. <span class="completed-count">{{ statistics.completedCount }}</span>
  80. </span>
  81. </div>
  82. <!-- 数据表格 -->
  83. <cost-audit-table
  84. v-loading="loading"
  85. :table-data="tableData"
  86. :columns="tableColumns"
  87. :border="true"
  88. :row-class-name="getRowClassName"
  89. :show-pagination="false"
  90. :table-props="{
  91. rowKey: 'id',
  92. treeProps: { children: 'children', hasChildren: 'hasChildren' },
  93. defaultExpandAll: true,
  94. }"
  95. >
  96. <!-- 操作列自定义模板 -->
  97. <template #operation="{ row }">
  98. <template v-if="row.isSubTask">
  99. <el-button
  100. size="mini"
  101. type="text"
  102. @click="handleMessage(row, 'chengben')"
  103. >
  104. 查看
  105. </el-button>
  106. </template>
  107. <template v-else>
  108. <el-button
  109. size="mini"
  110. type="text"
  111. @click="handleViewTaskDetail(row)"
  112. >
  113. 详情
  114. </el-button>
  115. </template>
  116. </template>
  117. <template slot="empty">
  118. <Empty></Empty>
  119. </template>
  120. </cost-audit-table>
  121. <!-- 分页 -->
  122. <el-pagination
  123. background
  124. layout="total, sizes, prev, pager, next"
  125. :current-page="pageNum"
  126. :page-sizes="[10, 20, 30, 40]"
  127. :page-size="pageSize"
  128. :total="total"
  129. style="margin-top: 20px; text-align: right"
  130. @current-change="handleCurrentChange"
  131. @size-change="handleSizeChange"
  132. />
  133. </div>
  134. <!-- 详情内容 -->
  135. <div v-if="activeView == 'detail'" class="detail-content">
  136. <detail-tabs
  137. :project="project"
  138. :task-data="taskData"
  139. :is-view="true"
  140. @detailClose="handleDetailClose"
  141. ></detail-tabs>
  142. </div>
  143. <!-- 任务詳情弹窗(统一詳情/查看入口) -->
  144. <task-detail
  145. ref="taskDetail"
  146. :visible.sync="taskDetailVisible"
  147. :is-view="isView"
  148. />
  149. <!-- 成本监审任务制定弹窗(列表“详情/查看”入口使用) -->
  150. <task-customized-release-dialog
  151. :visible.sync="taskReleaseDialogVisible"
  152. :project="project"
  153. :is-view="true"
  154. @backToList="taskReleaseDialogVisible = false"
  155. @close="taskReleaseDialogVisible = false"
  156. />
  157. <!-- 成本监审信息弹窗 -->
  158. <cbjs-info
  159. v-if="cbjsInfoData"
  160. :id="cbjsInfoData.id || ''"
  161. :selected-project="cbjsInfoData"
  162. :visible.sync="cbjsInfoVisible"
  163. :current-node="cbjsInfoData.currentNode || ''"
  164. :current-status="cbjsInfoData.status || ''"
  165. :survey-template-id="cbjsInfoData.surveyTemplateId || ''"
  166. />
  167. </div>
  168. </template>
  169. <script>
  170. import { dictMixin, regionMixin } from '@/mixins/useDict'
  171. import detailTabs from '@/views/costAudit/projectInfo/auditTaskManage/taskProgressManage/detailTabs.vue'
  172. import CostAuditTable from '@/components/costAudit/CostAuditTable.vue'
  173. import { getTaskListStatistics, getItemsCount } from '@/api/home'
  174. import TaskDetail from '@/components/task/taskDetail.vue'
  175. import TaskCustomizedReleaseDialog from '@/components/task/TaskCustomizedReleaseDialog.vue'
  176. import { getCostProjectDetail } from '@/api/taskCustomizedRelease.js'
  177. import cbjsInfo from '@/components/task/cbjsInfo.vue'
  178. export default {
  179. components: {
  180. detailTabs,
  181. CostAuditTable,
  182. TaskDetail,
  183. TaskCustomizedReleaseDialog,
  184. cbjsInfo,
  185. },
  186. mixins: [dictMixin, regionMixin],
  187. data() {
  188. return {
  189. dictData: {
  190. auditType: [], //监审形式
  191. projectProposal: [], //立项来源
  192. },
  193. activeView: 'list',
  194. loading: false,
  195. isView: true,
  196. searchForm: {
  197. year: '',
  198. areaCode: null,
  199. currentNode: null,
  200. projectName: '',
  201. },
  202. tableData: [],
  203. // 分页相关
  204. pageNum: 1,
  205. pageSize: 10,
  206. total: 0,
  207. // 成本监审信息弹窗相关
  208. cbjsInfoData: null, // 存储当前选中的成本监审信息
  209. cbjsInfoVisible: false, // 控制成本监审信息弹窗的显示/隐藏
  210. // 统计数据
  211. statistics: {
  212. pendingCount: 0,
  213. completedCount: 0,
  214. },
  215. project: {},
  216. taskData: {},
  217. unitList: [],
  218. taskDetailVisible: false,
  219. taskReleaseDialogVisible: false,
  220. // 表格列配置
  221. tableColumns: [
  222. {
  223. prop: 'serialNumber',
  224. label: '序号',
  225. width: 60,
  226. headerAlign: 'center',
  227. align: 'center',
  228. formatter: (row) => {
  229. return row.pid == 0 ? row.parentIndex : ''
  230. },
  231. },
  232. {
  233. prop: 'year',
  234. label: '立项年度',
  235. width: 100,
  236. headerAlign: 'center',
  237. align: 'center',
  238. formatter: (row) => {
  239. return row.year || ''
  240. },
  241. },
  242. {
  243. prop: 'areaName',
  244. label: '立项地区',
  245. width: 100,
  246. headerAlign: 'center',
  247. align: 'center',
  248. },
  249. {
  250. prop: 'projectName',
  251. label: '成本监审项目名称',
  252. headerAlign: 'center',
  253. align: 'left',
  254. showOverflowTooltip: true,
  255. },
  256. {
  257. prop: 'auditedUnitName',
  258. label: '被监审单位',
  259. headerAlign: 'center',
  260. align: 'left',
  261. showOverflowTooltip: true,
  262. },
  263. {
  264. prop: 'auditPeriod',
  265. label: '监审期间',
  266. width: 150,
  267. headerAlign: 'center',
  268. align: 'center',
  269. },
  270. {
  271. prop: 'sourceType',
  272. label: '立项来源',
  273. width: 120,
  274. headerAlign: 'center',
  275. align: 'center',
  276. formatter: (row) => {
  277. return this.getDictName('projectProposal', row.sourceType)
  278. },
  279. },
  280. {
  281. prop: 'auditType',
  282. label: '监审形式',
  283. width: 120,
  284. headerAlign: 'center',
  285. align: 'center',
  286. formatter: (row) => {
  287. return this.getDictName('auditType', row.auditType)
  288. },
  289. },
  290. {
  291. prop: 'currentNodeName',
  292. label: '状态',
  293. width: 100,
  294. headerAlign: 'center',
  295. align: 'center',
  296. },
  297. {
  298. prop: 'operation',
  299. label: '操作',
  300. width: 80,
  301. headerAlign: 'center',
  302. align: 'center',
  303. slotName: 'operation',
  304. },
  305. ],
  306. }
  307. },
  308. computed: {
  309. pendingCount() {
  310. // 计算在办任务数量(非办结状态)
  311. return this.tableData.filter((item) => item.status !== 400).length
  312. },
  313. completedCount() {
  314. // 计算办结任务数量
  315. return this.tableData.filter((item) => item.status === 400).length
  316. },
  317. },
  318. mounted() {
  319. this.getTaskList()
  320. this.getItemsCount()
  321. },
  322. methods: {
  323. getItemsCount() {
  324. return getItemsCount().then((res) => {
  325. this.statistics = res.value
  326. })
  327. },
  328. getTaskList() {
  329. return getTaskListStatistics({
  330. pageNum: this.pageNum,
  331. pageSize: this.pageSize,
  332. year: this.searchForm.year,
  333. areaCode: this.searchForm.areaCode,
  334. currentNode: this.searchForm.currentNode,
  335. projectName: this.searchForm.projectName,
  336. }).then((res) => {
  337. if (res.state && res.value) {
  338. // 获取记录列表
  339. const records = res.value.records || []
  340. // 转换数据格式,将childTasks转换为children以適应表格组件
  341. this.tableData = records.map((record, index) => {
  342. return {
  343. id: record.id,
  344. projectName: record.projectName,
  345. auditedUnitName: record.auditedUnitName,
  346. auditPeriod: record.auditPeriod,
  347. source: this.getSourceTypeText(record.sourceType),
  348. form: this.getAuditTypeText(record.auditType),
  349. status: record.status,
  350. statusName: record.statusName,
  351. isSubTask: record.pid !== '0' && record.pid !== 0,
  352. currentNodeName: record.currentNodeName,
  353. currentNode: record.currentNode,
  354. projectId: record.projectId,
  355. auditedUnitId: record.auditedUnitId,
  356. parentIndex: index + 1, // 母计数作为parentIndex
  357. year: record.year,
  358. sourceType: record.sourceType,
  359. auditType: record.auditType,
  360. isGd: record.isGd,
  361. areaName: record.areaName,
  362. warningStatus: record.warningStatus,
  363. children:
  364. record.childTasks && record.childTasks.length > 0
  365. ? record.childTasks.map((child) => ({
  366. id: child.id,
  367. projectName: child.projectName,
  368. auditedUnitName: child.auditedUnitName,
  369. auditPeriod: child.auditPeriod || record.auditPeriod,
  370. source: child.sourceType
  371. ? this.getSourceTypeText(child.sourceType)
  372. : '',
  373. form: child.auditType
  374. ? this.getAuditTypeText(child.auditType)
  375. : '',
  376. currentNode: child.currentNode,
  377. status: child.status,
  378. statusName: child.statusName,
  379. isSubTask: true,
  380. currentNodeName: child.statusName,
  381. projectId: child.projectId,
  382. auditedUnitId: child.auditedUnitId,
  383. taskId: child.id,
  384. catalogId: child.catalogId,
  385. year: child.year,
  386. sourceType: child.sourceType,
  387. auditType: child.auditType,
  388. isGd: child.isGd,
  389. warningStatus: child.warningStatus,
  390. }))
  391. : [],
  392. }
  393. })
  394. // 设置总数
  395. this.total = res.value.total || records.length
  396. } else {
  397. this.tableData = []
  398. this.total = 0
  399. }
  400. })
  401. },
  402. // 获取来源类型文本
  403. getSourceTypeText(type) {
  404. const typeMap = {
  405. 1: '年度计划内',
  406. 2: '年度计划外',
  407. }
  408. return typeMap[type] || type
  409. },
  410. // 获取审核类型文本
  411. getAuditTypeText(type) {
  412. const typeMap = {
  413. 1: '定期监审',
  414. 2: '定调价监审',
  415. }
  416. return typeMap[type] || type
  417. },
  418. handleReset() {
  419. this.searchForm = {
  420. year: '',
  421. areaCode: null,
  422. currentNode: null,
  423. projectName: '',
  424. }
  425. this.pageNum = 1
  426. this.getTaskList()
  427. },
  428. generateTableData() {
  429. // 查询时重置为第一页
  430. this.pageNum = 1
  431. this.getTaskList()
  432. },
  433. getRowClassName({ row }) {
  434. if (row.isSubTask) {
  435. return 'sub-task-row'
  436. }
  437. return ''
  438. },
  439. handleView(row) {
  440. // 主任务詳情:打开统一任务詳情弹窗
  441. this.isView = true
  442. this.taskDetailVisible = true
  443. this.$nextTick(() => {
  444. this.$refs.taskDetail && this.$refs.taskDetail.open(row, 'chengben')
  445. })
  446. },
  447. handleViewTaskDetail(row) {
  448. this.openTaskReleaseDialog(row)
  449. },
  450. openTaskReleaseDialog(row) {
  451. if (!row) return
  452. const projectId =
  453. row.projectId || row.projectID || row.id || row.taskId || ''
  454. if (!projectId) {
  455. this.$message &&
  456. this.$message.warning &&
  457. this.$message.warning('缺少项目ID,无法查看详情')
  458. return
  459. }
  460. this.isView = true
  461. getCostProjectDetail({ id: projectId })
  462. .then((res) => {
  463. this.project = (res && res.value) || {}
  464. this.taskReleaseDialogVisible = true
  465. })
  466. .catch(() => {
  467. this.project = row || {}
  468. this.taskReleaseDialogVisible = true
  469. })
  470. },
  471. handleDetailClose() {
  472. this.activeView = 'list'
  473. },
  474. // 分页处理
  475. handleSizeChange(size) {
  476. this.pageSize = size
  477. this.pageNum = 1
  478. this.getTaskList()
  479. },
  480. handleCurrentChange(current) {
  481. this.pageNum = current
  482. this.getTaskList()
  483. },
  484. // 地区选择处理 - 只按上佊中最后一级值
  485. handleAreaChange(value) {
  486. if (Array.isArray(value) && value.length > 0) {
  487. // 只保留最后一级的值
  488. this.searchForm.areaCode = value[value.length - 1]
  489. } else {
  490. // 清空时设为null
  491. this.searchForm.areaCode = null
  492. }
  493. },
  494. // 查看 - 修改为打开cbjsInfo弹窗
  495. handleMessage(row, type) {
  496. if (type === 'chengben') {
  497. // 确保 row 存在并且包含必要的属性
  498. if (row) {
  499. this.cbjsInfoData = {
  500. ...row,
  501. taskId: row.id,
  502. surveyTemplateId: row.surveyTemplateId || '', // 确保 surveyTemplateId 有默认值
  503. currentNode: row.currentNode || '',
  504. status: row.status || '',
  505. }
  506. console.log(this.cbjsInfoData, '数据')
  507. this.cbjsInfoVisible = true
  508. } else {
  509. console.warn('行数据为空,无法打开弹窗')
  510. this.$message.warning('无法查看:数据异常')
  511. }
  512. } else if (this.$refs.taskInfo) {
  513. this.$refs.taskInfo.open(row, type)
  514. } else {
  515. console.warn('taskInfo 组件未找到,请确保已正确导入和注册')
  516. this.$message.warning('功能暂不可用,请联系管理员')
  517. }
  518. },
  519. },
  520. }
  521. </script>
  522. <style scoped>
  523. .task-query-statistics {
  524. padding: 20px;
  525. }
  526. h2 {
  527. margin-bottom: 20px;
  528. font-size: 18px;
  529. color: #303133;
  530. }
  531. .demo-form-inline {
  532. display: flex;
  533. align-items: center;
  534. flex-wrap: wrap;
  535. }
  536. .statistics-info {
  537. text-align: right;
  538. margin-bottom: 20px;
  539. }
  540. .statistics-info span {
  541. margin-right: 30px;
  542. }
  543. .pending-count,
  544. .completed-count {
  545. font-weight: bold;
  546. color: #1890ff;
  547. }
  548. .description {
  549. margin-top: 15px;
  550. padding: 15px;
  551. background-color: #fff7e6;
  552. border: 1px solid #ffe7ba;
  553. border-radius: 4px;
  554. }
  555. .description p {
  556. margin: 0;
  557. line-height: 1.6;
  558. }
  559. /* 子任务样式 */
  560. .el-table .sub-task-row {
  561. background-color: #fafafa !important;
  562. }
  563. /* 响应式布局 */
  564. @media (max-width: 1200px) {
  565. .demo-form-inline {
  566. flex-direction: column;
  567. align-items: flex-start;
  568. }
  569. .demo-form-inline .el-form-item {
  570. margin-right: 0;
  571. margin-bottom: 15px;
  572. }
  573. }
  574. </style>