index.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  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. ></el-cascader>
  27. </el-form-item>
  28. <el-form-item label="状态:">
  29. <el-select v-model="searchForm.status" placeholder="请选择状态">
  30. <el-option label="全部" value="全部"></el-option>
  31. <el-option label="实地审核" value="实地审核"></el-option>
  32. <el-option label="审核中" value="审核中"></el-option>
  33. <el-option label="审核通过" value="审核通过"></el-option>
  34. <el-option label="办结" value="办结"></el-option>
  35. </el-select>
  36. </el-form-item>
  37. <el-form-item label="监审项目名称:">
  38. <el-input
  39. v-model="searchForm.projectName"
  40. placeholder="请输入监审项目名称"
  41. clearable
  42. ></el-input>
  43. </el-form-item>
  44. <el-form-item>
  45. <el-button
  46. icon="el-icon-search"
  47. type="primary"
  48. @click="generateTableData"
  49. >
  50. 搜索
  51. </el-button>
  52. <el-button
  53. plain
  54. type="primary"
  55. icon="el-icon-refresh"
  56. @click="handleReset"
  57. >
  58. 重置
  59. </el-button>
  60. </el-form-item>
  61. </el-form>
  62. </div>
  63. <!-- 统计信息 -->
  64. <div class="statistics-info">
  65. <span>
  66. 在办事项:
  67. <span class="pending-count">{{ pendingCount }}</span>
  68. </span>
  69. <span>
  70. 已结事项:
  71. <span class="completed-count">{{ completedCount }}</span>
  72. </span>
  73. </div>
  74. <!-- 数据表格 -->
  75. <cost-audit-table
  76. v-loading="loading"
  77. :table-data="tableData"
  78. :columns="tableColumns"
  79. :border="true"
  80. :row-class-name="getRowClassName"
  81. :show-pagination="false"
  82. :table-props="{
  83. rowKey: 'id',
  84. treeProps: { children: 'children', hasChildren: 'hasChildren' },
  85. defaultExpandAll: true,
  86. }"
  87. >
  88. <!-- 操作列自定义模板 -->
  89. <template #operation="{ row }">
  90. <el-button size="mini" type="text" @click="handleView(row)">
  91. 查看
  92. </el-button>
  93. </template>
  94. </cost-audit-table>
  95. </div>
  96. <!-- 详情内容 -->
  97. <div v-if="activeView == 'detail'" class="detail-content">
  98. <detail-tabs
  99. :project="project"
  100. :task-data="taskData"
  101. :is-view="true"
  102. @detailClose="handleDetailClose"
  103. ></detail-tabs>
  104. </div>
  105. </div>
  106. </template>
  107. <script>
  108. import { dictMixin, regionMixin } from '@/mixins/useDict'
  109. import detailTabs from '@/views/costAudit/projectInfo/auditTaskManage/taskProgressManage/detailTabs.vue'
  110. import { taskList } from '@/api/taskProgressManage'
  111. import { getAllUnitList } from '@/api/auditEntityManage'
  112. import CostAuditTable from '@/components/costAudit/CostAuditTable.vue'
  113. import { getCostProjectDetail } from '@/api/taskCustomizedRelease.js'
  114. export default {
  115. components: {
  116. detailTabs,
  117. CostAuditTable,
  118. },
  119. mixins: [dictMixin, regionMixin],
  120. data() {
  121. return {
  122. dictData: {
  123. auditType: [], //监审形式
  124. projectProposal: [], //立项来源
  125. },
  126. activeView: 'list',
  127. loading: false,
  128. isView: true,
  129. searchForm: {
  130. year: '',
  131. areaCode: '',
  132. status: '全部',
  133. projectName: '',
  134. },
  135. tableData: [],
  136. // 统计数据
  137. statistics: {
  138. pending: 0,
  139. completed: 0,
  140. },
  141. project: {},
  142. taskData: {},
  143. unitList: [],
  144. // 表格列配置
  145. tableColumns: [
  146. {
  147. prop: 'serialNumber',
  148. label: '序号',
  149. width: 60,
  150. align: 'center',
  151. formatter: (row) => {
  152. return row.pid == 0 ? row.parentIndex : ''
  153. },
  154. },
  155. {
  156. prop: 'year',
  157. label: '立项年度',
  158. width: 100,
  159. align: 'center',
  160. formatter: (row) => {
  161. return row.year || ''
  162. },
  163. },
  164. {
  165. prop: 'region',
  166. label: '立项地区',
  167. width: 100,
  168. align: 'center',
  169. },
  170. {
  171. prop: 'projectName',
  172. label: '成本监审项目名称',
  173. showOverflowTooltip: true,
  174. },
  175. {
  176. prop: 'auditedUnitId',
  177. label: '被监审单位',
  178. showOverflowTooltip: true,
  179. formatter: (row) => {
  180. return this.getUnitName(row.auditedUnitId)
  181. },
  182. },
  183. {
  184. prop: 'auditPeriod',
  185. label: '监审期间',
  186. width: 150,
  187. align: 'center',
  188. },
  189. {
  190. prop: 'sourceType',
  191. label: '立项来源',
  192. width: 120,
  193. align: 'center',
  194. formatter: (row) => {
  195. return this.getDictName('projectProposal', row.sourceType)
  196. },
  197. },
  198. {
  199. prop: 'auditType',
  200. label: '监审形式',
  201. width: 120,
  202. align: 'center',
  203. formatter: (row) => {
  204. return this.getDictName('auditType', row.auditType)
  205. },
  206. },
  207. {
  208. prop: 'status',
  209. label: '状态',
  210. width: 100,
  211. align: 'center',
  212. formatter: (row) => {
  213. return this.getStatusName(row.status)
  214. },
  215. },
  216. {
  217. prop: 'operation',
  218. label: '操作',
  219. width: 80,
  220. align: 'center',
  221. slotName: 'operation',
  222. },
  223. ],
  224. }
  225. },
  226. computed: {
  227. pendingCount() {
  228. // 计算在办任务数量(非办结状态)
  229. return this.tableData.filter((item) => item.status !== 400).length
  230. },
  231. completedCount() {
  232. // 计算办结任务数量
  233. return this.tableData.filter((item) => item.status === 400).length
  234. },
  235. },
  236. mounted() {
  237. this.getAllUnitList()
  238. this.generateTableData()
  239. },
  240. methods: {
  241. handleReset() {
  242. this.searchForm = {
  243. year: '',
  244. areaCode: '',
  245. status: '',
  246. projectName: '',
  247. }
  248. this.generateTableData()
  249. },
  250. getAllUnitList() {
  251. getAllUnitList().then((res) => {
  252. this.unitList = res.value || []
  253. })
  254. },
  255. getUnitName(unitId) {
  256. // 直接处理unitId值
  257. if (unitId && typeof unitId === 'string' && unitId.includes(',')) {
  258. // 如果包含逗号,分割成数组并查找对应的unitName
  259. const unitIds = unitId.split(',')
  260. return unitIds
  261. .map((id) => {
  262. const unit = this.unitList.find((item) => item.unitId == id)
  263. return unit ? unit.unitName : ''
  264. })
  265. .filter((name) => name) // 过滤空值
  266. .join('、')
  267. } else {
  268. // 单个unitId的情况
  269. const unit = this.unitList.find((item) => item.unitId == unitId)
  270. return unit ? unit.unitName : ''
  271. }
  272. },
  273. getStatusName(status) {
  274. // 100待提交、200审核中、400办结、300中止
  275. switch (status) {
  276. case '100':
  277. return '待提交'
  278. case '200':
  279. return '审核中'
  280. case '400':
  281. return '办结'
  282. case '300':
  283. return '中止'
  284. default:
  285. return status
  286. }
  287. },
  288. generateTableData() {
  289. this.loading = true
  290. taskList({
  291. projectName: this.searchForm.projectName,
  292. year: this.searchForm.year,
  293. })
  294. .then((res) => {
  295. this.tableData = res.value
  296. // 移除不需要的属性
  297. this.tableData = this.removeItemFromTree(this.tableData)
  298. let parentIndex = 1
  299. this.tableData.forEach((item, index) => {
  300. if (item.pid == 0) {
  301. item.parentIndex = parentIndex++
  302. }
  303. })
  304. this.loading = false
  305. })
  306. .catch(() => {
  307. this.loading = false
  308. this.$message.error('获取数据失败')
  309. })
  310. },
  311. removeItemFromTree(treeData) {
  312. // 边界条件检查
  313. if (!treeData || !Array.isArray(treeData)) {
  314. return []
  315. }
  316. // 创建新数组,避免修改原数据
  317. return treeData.map((item) => {
  318. // 创建当前节点的副本
  319. const newItem = { ...item }
  320. // 如果有hasChildren属性则删除
  321. if ('hasChildren' in newItem) {
  322. delete newItem.hasChildren
  323. }
  324. // 递归处理子节点 先检查children是否存在且为数组
  325. if (
  326. newItem.children &&
  327. Array.isArray(newItem.children) &&
  328. newItem.children.length > 0
  329. ) {
  330. newItem.children = this.removeItemFromTree(newItem.children)
  331. }
  332. return newItem
  333. })
  334. },
  335. getRowClassName({ row }) {
  336. if (row.isSubTask) {
  337. return 'sub-task-row'
  338. }
  339. return ''
  340. },
  341. handleView(row) {
  342. this.taskData = row
  343. this.getProject()
  344. this.activeView = 'detail'
  345. },
  346. getProject() {
  347. getCostProjectDetail({
  348. id: this.taskData.projectId,
  349. })
  350. .then((res) => {
  351. this.project = {
  352. ...res.value,
  353. }
  354. })
  355. .catch(() => {
  356. this.project = this.taskData
  357. })
  358. },
  359. handleDetailClose() {
  360. this.activeView = 'list'
  361. },
  362. calculateStatistics() {
  363. // 计算在办和办结任务数量
  364. let pendingCount = 0
  365. let completedCount = 0
  366. this.tableData.forEach((item) => {
  367. if (item.status === '办结') {
  368. completedCount++
  369. } else {
  370. pendingCount++
  371. }
  372. })
  373. this.statistics = {
  374. pending: pendingCount,
  375. completed: completedCount,
  376. }
  377. },
  378. },
  379. }
  380. </script>
  381. <style scoped>
  382. .task-query-statistics {
  383. padding: 20px;
  384. }
  385. h2 {
  386. margin-bottom: 20px;
  387. font-size: 18px;
  388. color: #303133;
  389. }
  390. .demo-form-inline {
  391. display: flex;
  392. align-items: center;
  393. flex-wrap: wrap;
  394. }
  395. .statistics-info {
  396. text-align: right;
  397. margin-bottom: 20px;
  398. }
  399. .statistics-info span {
  400. margin-right: 30px;
  401. }
  402. .pending-count,
  403. .completed-count {
  404. font-weight: bold;
  405. color: #1890ff;
  406. }
  407. .description {
  408. margin-top: 15px;
  409. padding: 15px;
  410. background-color: #fff7e6;
  411. border: 1px solid #ffe7ba;
  412. border-radius: 4px;
  413. }
  414. .description p {
  415. margin: 0;
  416. line-height: 1.6;
  417. }
  418. /* 子任务样式 */
  419. .el-table .sub-task-row {
  420. background-color: #fafafa !important;
  421. }
  422. /* 响应式布局 */
  423. @media (max-width: 1200px) {
  424. .demo-form-inline {
  425. flex-direction: column;
  426. align-items: flex-start;
  427. }
  428. .demo-form-inline .el-form-item {
  429. margin-right: 0;
  430. margin-bottom: 15px;
  431. }
  432. }
  433. </style>