index.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  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="el-icon-search"
  55. type="primary"
  56. @click="generateTableData"
  57. >
  58. 搜索
  59. </el-button>
  60. <el-button
  61. plain
  62. type="primary"
  63. icon="el-icon-refresh"
  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 size="mini" type="text" @click="handleView(row)">
  100. 查看
  101. </el-button>
  102. </template>
  103. <template v-else>
  104. <el-button
  105. size="mini"
  106. type="text"
  107. @click="handleViewTaskDetail(row)"
  108. >
  109. 详情
  110. </el-button>
  111. </template>
  112. </template>
  113. </cost-audit-table>
  114. <!-- 分页 -->
  115. <el-pagination
  116. background
  117. layout="total, sizes, prev, pager, next"
  118. :current-page="pageNum"
  119. :page-sizes="[10, 20, 30, 40]"
  120. :page-size="pageSize"
  121. :total="total"
  122. style="margin-top: 20px; text-align: right"
  123. @current-change="handleCurrentChange"
  124. @size-change="handleSizeChange"
  125. />
  126. </div>
  127. <!-- 详情内容 -->
  128. <div v-if="activeView == 'detail'" class="detail-content">
  129. <detail-tabs
  130. :project="project"
  131. :task-data="taskData"
  132. :is-view="true"
  133. @detailClose="handleDetailClose"
  134. ></detail-tabs>
  135. </div>
  136. <!-- 任务詳情弹窗(统一詳情/查看入口) -->
  137. <task-detail
  138. ref="taskDetail"
  139. :visible.sync="taskDetailVisible"
  140. :is-view="isView"
  141. />
  142. <!-- 成本监审任务制定弹窗(列表“详情/查看”入口使用) -->
  143. <task-customized-release-dialog
  144. :visible.sync="taskReleaseDialogVisible"
  145. :project="project"
  146. :is-view="true"
  147. @backToList="taskReleaseDialogVisible = false"
  148. @close="taskReleaseDialogVisible = false"
  149. />
  150. </div>
  151. </template>
  152. <script>
  153. import { dictMixin, regionMixin } from '@/mixins/useDict'
  154. import detailTabs from '@/views/costAudit/projectInfo/auditTaskManage/taskProgressManage/detailTabs.vue'
  155. import CostAuditTable from '@/components/costAudit/CostAuditTable.vue'
  156. import { getTaskListStatistics, getItemsCount } from '@/api/home'
  157. import TaskDetail from '@/components/task/taskDetail.vue'
  158. import TaskCustomizedReleaseDialog from '@/components/task/TaskCustomizedReleaseDialog.vue'
  159. import { getCostProjectDetail } from '@/api/taskCustomizedRelease.js'
  160. export default {
  161. components: {
  162. detailTabs,
  163. CostAuditTable,
  164. TaskDetail,
  165. TaskCustomizedReleaseDialog,
  166. },
  167. mixins: [dictMixin, regionMixin],
  168. data() {
  169. return {
  170. dictData: {
  171. auditType: [], //监审形式
  172. projectProposal: [], //立项来源
  173. },
  174. activeView: 'list',
  175. loading: false,
  176. isView: true,
  177. searchForm: {
  178. year: '',
  179. areaCode: null,
  180. currentNode: null,
  181. projectName: '',
  182. },
  183. tableData: [],
  184. // 分页相关
  185. pageNum: 1,
  186. pageSize: 10,
  187. total: 0,
  188. // 统计数据
  189. statistics: {
  190. pendingCount: 0,
  191. completedCount: 0,
  192. },
  193. project: {},
  194. taskData: {},
  195. unitList: [],
  196. taskDetailVisible: false,
  197. taskReleaseDialogVisible: false,
  198. // 表格列配置
  199. tableColumns: [
  200. {
  201. prop: 'serialNumber',
  202. label: '序号',
  203. width: 60,
  204. headerAlign: 'center',
  205. align: 'center',
  206. formatter: (row) => {
  207. return row.pid == 0 ? row.parentIndex : ''
  208. },
  209. },
  210. {
  211. prop: 'year',
  212. label: '立项年度',
  213. width: 100,
  214. headerAlign: 'center',
  215. align: 'center',
  216. formatter: (row) => {
  217. return row.year || ''
  218. },
  219. },
  220. {
  221. prop: 'areaName',
  222. label: '立项地区',
  223. width: 100,
  224. headerAlign: 'center',
  225. align: 'center',
  226. },
  227. {
  228. prop: 'projectName',
  229. label: '成本监审项目名称',
  230. headerAlign: 'center',
  231. align: 'left',
  232. showOverflowTooltip: true,
  233. },
  234. {
  235. prop: 'auditedUnitName',
  236. label: '被监审单位',
  237. headerAlign: 'center',
  238. align: 'left',
  239. showOverflowTooltip: true,
  240. },
  241. {
  242. prop: 'auditPeriod',
  243. label: '监审期间',
  244. width: 150,
  245. headerAlign: 'center',
  246. align: 'center',
  247. },
  248. {
  249. prop: 'sourceType',
  250. label: '立项来源',
  251. width: 120,
  252. headerAlign: 'center',
  253. align: 'center',
  254. formatter: (row) => {
  255. return this.getDictName('projectProposal', row.sourceType)
  256. },
  257. },
  258. {
  259. prop: 'auditType',
  260. label: '监审形式',
  261. width: 120,
  262. headerAlign: 'center',
  263. align: 'center',
  264. formatter: (row) => {
  265. return this.getDictName('auditType', row.auditType)
  266. },
  267. },
  268. {
  269. prop: 'currentNodeName',
  270. label: '状态',
  271. width: 100,
  272. headerAlign: 'center',
  273. align: 'center',
  274. },
  275. {
  276. prop: 'operation',
  277. label: '操作',
  278. width: 80,
  279. headerAlign: 'center',
  280. align: 'center',
  281. slotName: 'operation',
  282. },
  283. ],
  284. }
  285. },
  286. computed: {
  287. pendingCount() {
  288. // 计算在办任务数量(非办结状态)
  289. return this.tableData.filter((item) => item.status !== 400).length
  290. },
  291. completedCount() {
  292. // 计算办结任务数量
  293. return this.tableData.filter((item) => item.status === 400).length
  294. },
  295. },
  296. mounted() {
  297. this.getTaskList()
  298. this.getItemsCount()
  299. },
  300. methods: {
  301. getItemsCount() {
  302. return getItemsCount().then((res) => {
  303. this.statistics = res.value
  304. })
  305. },
  306. getTaskList() {
  307. return getTaskListStatistics({
  308. pageNum: this.pageNum,
  309. pageSize: this.pageSize,
  310. year: this.searchForm.year,
  311. areaCode: this.searchForm.areaCode,
  312. currentNode: this.searchForm.currentNode,
  313. projectName: this.searchForm.projectName,
  314. }).then((res) => {
  315. if (res.state && res.value) {
  316. // 获取记录列表
  317. const records = res.value.records || []
  318. // 转换数据格式,将childTasks转换为children以適应表格组件
  319. this.tableData = records.map((record, index) => {
  320. return {
  321. id: record.id,
  322. projectName: record.projectName,
  323. auditedUnitName: record.auditedUnitName,
  324. auditPeriod: record.auditPeriod,
  325. source: this.getSourceTypeText(record.sourceType),
  326. form: this.getAuditTypeText(record.auditType),
  327. status: record.status,
  328. statusName: record.statusName,
  329. isSubTask: record.pid !== '0' && record.pid !== 0,
  330. currentNodeName: record.currentNodeName,
  331. currentNode: record.currentNode,
  332. projectId: record.projectId,
  333. auditedUnitId: record.auditedUnitId,
  334. parentIndex: index + 1, // 母计数作为parentIndex
  335. year: record.year,
  336. sourceType: record.sourceType,
  337. auditType: record.auditType,
  338. isGd: record.isGd,
  339. areaName: record.areaName,
  340. warningStatus: record.warningStatus,
  341. children:
  342. record.childTasks && record.childTasks.length > 0
  343. ? record.childTasks.map((child) => ({
  344. id: child.id,
  345. projectName: child.projectName,
  346. auditedUnitName: child.auditedUnitName,
  347. auditPeriod: child.auditPeriod || record.auditPeriod,
  348. source: child.sourceType
  349. ? this.getSourceTypeText(child.sourceType)
  350. : '',
  351. form: child.auditType
  352. ? this.getAuditTypeText(child.auditType)
  353. : '',
  354. currentNode: child.currentNode,
  355. status: child.status,
  356. statusName: child.statusName,
  357. isSubTask: true,
  358. currentNodeName: child.statusName,
  359. projectId: child.projectId,
  360. auditedUnitId: child.auditedUnitId,
  361. taskId: child.id,
  362. catalogId: child.catalogId,
  363. year: child.year,
  364. sourceType: child.sourceType,
  365. auditType: child.auditType,
  366. isGd: child.isGd,
  367. warningStatus: child.warningStatus,
  368. }))
  369. : [],
  370. }
  371. })
  372. // 设置总数
  373. this.total = res.value.total || records.length
  374. } else {
  375. this.tableData = []
  376. this.total = 0
  377. }
  378. })
  379. },
  380. // 获取来源类型文本
  381. getSourceTypeText(type) {
  382. const typeMap = {
  383. 1: '年度计划内',
  384. 2: '年度计划外',
  385. }
  386. return typeMap[type] || type
  387. },
  388. // 获取审核类型文本
  389. getAuditTypeText(type) {
  390. const typeMap = {
  391. 1: '定期监审',
  392. 2: '定调价监审',
  393. }
  394. return typeMap[type] || type
  395. },
  396. handleReset() {
  397. this.searchForm = {
  398. year: '',
  399. areaCode: null,
  400. currentNode: null,
  401. projectName: '',
  402. }
  403. this.pageNum = 1
  404. this.getTaskList()
  405. },
  406. generateTableData() {
  407. // 查询时重置为第一页
  408. this.pageNum = 1
  409. this.getTaskList()
  410. },
  411. getRowClassName({ row }) {
  412. if (row.isSubTask) {
  413. return 'sub-task-row'
  414. }
  415. return ''
  416. },
  417. handleView(row) {
  418. // 主任务詳情:打开统一任务詳情弹窗
  419. this.isView = true
  420. this.taskDetailVisible = true
  421. this.$nextTick(() => {
  422. this.$refs.taskDetail && this.$refs.taskDetail.open(row, 'chengben')
  423. })
  424. },
  425. handleViewTaskDetail(row) {
  426. this.openTaskReleaseDialog(row)
  427. },
  428. openTaskReleaseDialog(row) {
  429. if (!row) return
  430. const projectId =
  431. row.projectId || row.projectID || row.id || row.taskId || ''
  432. if (!projectId) {
  433. this.$message &&
  434. this.$message.warning &&
  435. this.$message.warning('缺少项目ID,无法查看详情')
  436. return
  437. }
  438. this.isView = true
  439. getCostProjectDetail({ id: projectId })
  440. .then((res) => {
  441. this.project = (res && res.value) || {}
  442. this.taskReleaseDialogVisible = true
  443. })
  444. .catch(() => {
  445. this.project = row || {}
  446. this.taskReleaseDialogVisible = true
  447. })
  448. },
  449. handleDetailClose() {
  450. this.activeView = 'list'
  451. },
  452. // 分页处理
  453. handleSizeChange(size) {
  454. this.pageSize = size
  455. this.pageNum = 1
  456. this.getTaskList()
  457. },
  458. handleCurrentChange(current) {
  459. this.pageNum = current
  460. this.getTaskList()
  461. },
  462. // 地区选择处理 - 只按上佊中最后一级值
  463. handleAreaChange(value) {
  464. if (Array.isArray(value) && value.length > 0) {
  465. // 只保留最后一级的值
  466. this.searchForm.areaCode = value[value.length - 1]
  467. } else {
  468. // 清空时设为null
  469. this.searchForm.areaCode = null
  470. }
  471. },
  472. },
  473. }
  474. </script>
  475. <style scoped>
  476. .task-query-statistics {
  477. padding: 20px;
  478. }
  479. h2 {
  480. margin-bottom: 20px;
  481. font-size: 18px;
  482. color: #303133;
  483. }
  484. .demo-form-inline {
  485. display: flex;
  486. align-items: center;
  487. flex-wrap: wrap;
  488. }
  489. .statistics-info {
  490. text-align: right;
  491. margin-bottom: 20px;
  492. }
  493. .statistics-info span {
  494. margin-right: 30px;
  495. }
  496. .pending-count,
  497. .completed-count {
  498. font-weight: bold;
  499. color: #1890ff;
  500. }
  501. .description {
  502. margin-top: 15px;
  503. padding: 15px;
  504. background-color: #fff7e6;
  505. border: 1px solid #ffe7ba;
  506. border-radius: 4px;
  507. }
  508. .description p {
  509. margin: 0;
  510. line-height: 1.6;
  511. }
  512. /* 子任务样式 */
  513. .el-table .sub-task-row {
  514. background-color: #fafafa !important;
  515. }
  516. /* 响应式布局 */
  517. @media (max-width: 1200px) {
  518. .demo-form-inline {
  519. flex-direction: column;
  520. align-items: flex-start;
  521. }
  522. .demo-form-inline .el-form-item {
  523. margin-right: 0;
  524. margin-bottom: 15px;
  525. }
  526. }
  527. </style>