dash.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. <template>
  2. <div class="full-height full-width flex flex-col">
  3. <div class="flex flex-col padding white-bg">
  4. <div class="flex flex-align-center tip">
  5. <el-icon class="ml-20" color="#BC002D">
  6. <WarningFilled/>
  7. </el-icon>
  8. <span class="ml-5">项目总投资额<span
  9. class="main-color bold">{{ num ? Number.parseFloat(num).toLocaleString() : '0' }}</span>万元</span>
  10. </div>
  11. <div class="flex ml-20 hide-scrollbar" style="overflow-x: scroll;width: 86vw;"
  12. v-show='numList && numList.length > 0'>
  13. <div v-for="(item,index) in numList" :key='item.id' :class="active === index ? 'total-s' : 'total'"
  14. class="flex flex-center flex-justify-between mt-20 bold font-16 pointer" @click='switchTab(item,index)'
  15. >
  16. <span class=" sp">{{ item.name }}</span>
  17. <span class=" sp1 ">{{ item.number }}<span class="grey font-13">个</span></span>
  18. </div>
  19. </div>
  20. <div class='flex flex-center flex-justify-start'>
  21. <base-button class="ml-20 mt-20" icon="Plus" title="新增"
  22. @click="showAdd = true"/>
  23. <base-button class="ml-20 mt-20" icon="el-icon-upload" title="数据导入"
  24. @click="diaType = 0"/>
  25. <base-button class="ml-20 mt-20" icon="el-icon-download" title="数据导出"
  26. @click="diaType = 1"/>
  27. <base-button class="ml-20 mt-20" type="0" icon="el-icon-download" title="汇总数据导出"
  28. @click="diaType = 2"/>
  29. </div>
  30. </div>
  31. <avue-crud ref="crud"
  32. v-model="form"
  33. v-model:page="page"
  34. :before-open="beforeOpen"
  35. :data="data"
  36. :option="option"
  37. :table-loading="loading"
  38. class="curd"
  39. @row-del="rowDel"
  40. @tree-load="treeLoad"
  41. @current-change="currentChange"
  42. @size-change="sizeChange"
  43. @refresh-change="refreshChange"
  44. @selection-change="selectionChange"
  45. @on-load="onLoad">
  46. <template #menu="{row}">
  47. <el-button v-if='user.info.viewStage !== 1' icon="Upload" type='primary' text @click="track(row)"> {{
  48. row.is_report === 1 ? "项目已上报" : "项目上报"
  49. }}
  50. </el-button>
  51. </template>
  52. <template #plan_storage_time-header="{column}">
  53. <div class='flex flex-center'>
  54. <div class='mr-5'>{{ (column || {}).label }}</div>
  55. <el-tooltip content='红色为计划开工时间,蓝色为实际开工时间'>
  56. <el-icon>
  57. <InfoFilled/>
  58. </el-icon>
  59. </el-tooltip>
  60. </div>
  61. </template>
  62. <template #plan_storage_time="{row}">
  63. <div class='flex flex-center'>
  64. <div class='mr-5 red' v-if='row.plan_storage_time !== undefined && row.is_storage === 0 '>
  65. {{ row.plan_storage_time.substring(0, 10) }}
  66. </div>
  67. <div class='mr-5 blue' v-else>{{ row.storage_time ? row.storage_time.substring(0, 10) : '' }}</div>
  68. </div>
  69. </template>
  70. <template #plan_commencement_time-header="{column}">
  71. <div class='flex flex-center'>
  72. <div class='mr-5'>{{ (column || {}).label }}</div>
  73. <el-tooltip content='红色为计划开工时间,蓝色为实际开工时间'>
  74. <el-icon>
  75. <InfoFilled/>
  76. </el-icon>
  77. </el-tooltip>
  78. </div>
  79. </template>
  80. <template #plan_commencement_time="{row}">
  81. <div class='flex flex-center'>
  82. <div class='mr-5 red'
  83. v-if='row.plan_commencement_time !== undefined && (row.is_start === undefined ||row.is_start === 0 )'>{{
  84. row.plan_commencement_time.substring(0, 10)
  85. }}
  86. </div>
  87. <div class='mr-5 blue' v-else>{{ row.start_time ? row.start_time.substring(0, 10) : '' }}</div>
  88. </div>
  89. </template>
  90. </avue-crud>
  91. <!-- 新增-->
  92. <el-dialog v-model="showAdd"
  93. append-to-body
  94. center
  95. title="新增项目"
  96. width="35%">
  97. <div v-loading='addLoading'>
  98. <el-form ref='form' :model="projectForm" class="lab mt-20" label-width="100px" :rules="rules">
  99. <div class="flex flex-center flex-col mr-20">
  100. <el-form-item class="full-width" label="项目名称" prop='name'>
  101. <el-input
  102. v-model="projectForm.name"
  103. clearable
  104. placeholder="输入项目名称"
  105. />
  106. </el-form-item>
  107. <el-form-item class="full-width" label="项目总投" prop='totalAmount'>
  108. <el-input
  109. v-model="projectForm.totalAmount"
  110. clearable
  111. placeholder="输入项目总投(万元)"
  112. >
  113. <template #append>(万元)</template>
  114. </el-input>
  115. </el-form-item>
  116. <!-- <el-form-item class="full-width" label="项目类型" prop='projectType'>-->
  117. <!-- <el-select-->
  118. <!-- v-model="projectForm.projectType"-->
  119. <!-- clearable-->
  120. <!-- placeholder="选择项目类型"-->
  121. <!-- style="width: 100%"-->
  122. <!-- >-->
  123. <!-- <el-option-->
  124. <!-- v-for="item in typeList"-->
  125. <!-- :key="item.id"-->
  126. <!-- :label="item.name"-->
  127. <!-- :value="item.id"-->
  128. <!-- />-->
  129. <!-- </el-select>-->
  130. <!-- </el-form-item>-->
  131. <el-form-item class="full-width" label="项目标签" prop='tags'>
  132. <el-select
  133. v-model="projectForm.tags"
  134. clearable
  135. placeholder="选择项目标签"
  136. style="width: 100%"
  137. >
  138. <el-option
  139. v-for="item in tagsList"
  140. :key="item.dictKey"
  141. :label="item.dictValue"
  142. :value="item.dictKey"
  143. />
  144. </el-select>
  145. </el-form-item>
  146. <el-form-item class="full-width" label="建设内容">
  147. <el-input
  148. v-model="projectForm.introduction"
  149. :rows="6"
  150. clearable
  151. placeholder="输入项目建设内容"
  152. type="textarea"
  153. />
  154. </el-form-item>
  155. <div class="flex flex-center mt-10">
  156. <base-button class="mr-20" icon="Close" title="取消" type="0" @click="showAdd = false"/>
  157. <base-button icon="Check" title="保存" @click="projectSave"/>
  158. </div>
  159. </div>
  160. </el-form>
  161. </div>
  162. </el-dialog>
  163. <form-dialog :dialogType="diaType" @close="formDialogClose" @export='exportExcel' :ids='selectList'/>
  164. <summary-dialog :dialogType="diaType" @close="diaType = -1"
  165. :select-num='selectList.length === 0 ? page.total : selectList.length'
  166. @export='exportExcelTotal'/>
  167. </div>
  168. </template>
  169. <script>
  170. import BaseButton from '../../../components/base-button.vue'
  171. import permissionStore from '@/store/permission.js'
  172. import formDialog from '@/views/home/component/form_dialog.vue'
  173. import {getLazyList} from '@/api/project/index.js'
  174. import summaryDialog from '@/views/home/component/summary_dialog.vue'
  175. import {useStore} from '@/store/user.js'
  176. export default {
  177. name: 'dash',
  178. components: {BaseButton, formDialog, summaryDialog},
  179. setup() {
  180. const permissions = permissionStore()
  181. const user = useStore()
  182. return {permissions, user}
  183. },
  184. data() {
  185. return {
  186. dialogLoading: false,
  187. disable: false,
  188. showAdd: false,
  189. active: 0,
  190. loading: false,
  191. addLoading: false,
  192. data: [],
  193. form: {},
  194. option: {
  195. menuType: 'menu',
  196. menuBtnTitle: '操作',
  197. refreshBtn: false,
  198. tip: false,
  199. lazy: true,
  200. columnBtn: false,
  201. searchShow: true,
  202. selection: true,
  203. editBtn: true,
  204. editBtnText: '资料管理',
  205. editBtnIcon: 'Document',
  206. addBtn: false,
  207. delBtn: true,
  208. border: true,
  209. reserveSelection: true,
  210. align: 'center',
  211. viewBtn: true,
  212. viewBtnText: '详情',
  213. dialogClickModal: false,
  214. column: [
  215. {
  216. label: '项目名称',
  217. prop: 'name',
  218. addDisplay: false,
  219. editDisplay: false,
  220. fixed: true,
  221. minWidth: 200
  222. },
  223. {
  224. label: '项目情况',
  225. prop: 'project_stage',
  226. type: 'select',
  227. width: 120,
  228. dicUrl: '/api/blade-system/dict-biz/dictionary?code=project-situation',
  229. props: {
  230. label: 'dictValue',
  231. value: 'dictKey'
  232. }
  233. },
  234. {
  235. label: '项目总投资(万元)',
  236. prop: 'total_amount',
  237. width: 120,
  238. type: 'number',
  239. precision: 2,
  240. formatter: (val, value, label) => {
  241. return val.total_amount.toLocaleString()
  242. }
  243. },
  244. {
  245. label: '责任单位',
  246. prop: 'responsible_unit'
  247. },
  248. {
  249. label: '子项目数量',
  250. prop: 'lot',
  251. width: 120,
  252. hide: true
  253. },
  254. {
  255. label: '是否入库',
  256. prop: 'is_storage',
  257. width: 120,
  258. dicData: [
  259. {
  260. label: '否',
  261. value: 0
  262. },
  263. {
  264. label: '是',
  265. value: 1
  266. }
  267. ]
  268. },
  269. {
  270. label: '计划(实际)入库时间',
  271. prop: 'plan_storage_time',
  272. width: 120,
  273. formatter: (val, value, label) => {
  274. return value.substring(0, 10)
  275. }
  276. },
  277. {
  278. label: '是否开工',
  279. prop: 'is_start',
  280. width: 120,
  281. dicData: [
  282. {
  283. label: '否',
  284. value: 0
  285. },
  286. {
  287. label: '是',
  288. value: 1
  289. }
  290. ]
  291. },
  292. {
  293. label: '计划(实际)开工时间',
  294. prop: 'plan_commencement_time',
  295. width: 120,
  296. formatter: (val, value, label) => {
  297. return value.substring(0, 10)
  298. }
  299. },
  300. {
  301. label: '认定时间',
  302. prop: 'year',
  303. width: 160,
  304. }]
  305. },
  306. page: {
  307. size: 10,
  308. current: 1,
  309. total: 0
  310. },
  311. stage: [],
  312. numList: [],
  313. typeList: [],
  314. tagsList: [],
  315. num: '',
  316. projectForm: {
  317. name: '',
  318. totalAmount: '',
  319. projectType: '1589613582090166274',
  320. tags: '',
  321. introduction: ''
  322. },
  323. rules: {
  324. name: [
  325. {required: true, message: '请输入项目名称', trigger: 'blur'}
  326. ],
  327. projectType: [
  328. {
  329. required: true,
  330. message: '请选择项目类型',
  331. trigger: 'change'
  332. }
  333. ],
  334. tags: [
  335. {
  336. required: true,
  337. message: '请选择项目标签',
  338. trigger: 'change'
  339. }
  340. ]
  341. },
  342. diaType: -1,
  343. parentId: 0,
  344. queryData: null,
  345. owerQuery: {},
  346. projectStageQuery: {},
  347. selectList: []
  348. }
  349. },
  350. created() {
  351. const index = this.option.column.findIndex(sub => sub.prop === 'lot')
  352. const indexLabel = this.option.column.findIndex(sub => sub.prop === 'responsible_unit')
  353. console.log(indexLabel)
  354. if (this.user.info.viewStage === 1) { // 发改
  355. this.option.column[index].hide = true
  356. this.option.column[indexLabel].label = '责任单位'
  357. } else {
  358. this.option.column[index].hide = false
  359. this.option.column[indexLabel].label = '责任股(科)室'
  360. }
  361. this.$bus.on('serach', (res, type) => {
  362. this.owerQuery = res
  363. if (res.type === false) {
  364. this.projectStageQuery.projectStage = ''
  365. this.active = 0
  366. }
  367. this.onLoad(Object.assign(this.owerQuery, this.projectStageQuery))
  368. this.getNumList(Object.assign(this.owerQuery, this.projectStageQuery))
  369. })
  370. this.getTypeList()
  371. this.getNumList()
  372. },
  373. unmounted() {
  374. sessionStorage.removeItem('selectList')
  375. },
  376. methods: {
  377. switchTab(item, index) {
  378. this.active = index
  379. this.num = this.numList[index].totalAmount
  380. this.projectStageQuery = {projectStage: item.dictKey}
  381. this.onLoad(Object.assign(this.owerQuery, this.projectStageQuery))
  382. },
  383. onLoad(query = {}) {
  384. this.loading = true
  385. const data = {...this.owerQuery, parentId: this.parentId}
  386. this.queryData = data
  387. this.$api.project.projectList(this.page.currentPage, this.page.pageSize, this.queryData).then(res => {
  388. this.loading = false
  389. if (res.code === 200) {
  390. this.data = res.data.records.map(e => {
  391. e.projectStage = e.projectStage + ''
  392. e.selected = true
  393. return e
  394. })
  395. this.page.total = res.data.total
  396. }
  397. }).finally(() => {
  398. this.loading = false
  399. })
  400. },
  401. selectionChange(list) {
  402. this.selectList = list.map(sub => sub.id)
  403. },
  404. beforeOpen(done, type) {
  405. if (['edit'].includes(type)) {
  406. if (this.user.info.account !== '15368241401') {
  407. this.$confirm('暂未授权使用', {
  408. confirmButtonText: '确定',
  409. cancelButtonText: '取消',
  410. type: 'warning'
  411. })
  412. } else {
  413. this.$router.push({
  414. path: '/home/details',
  415. query: {id: this.form.id, type: '0', ownerId: this.form.createUser}
  416. })
  417. }
  418. } else if (type === 'view') {
  419. this.$router.push({
  420. path: '/home/pro_detail',
  421. query: {id: this.form.id, projectStage: this.form.project_stage}
  422. })
  423. }
  424. },
  425. currentChange(currentPage) {
  426. this.page.current = currentPage
  427. },
  428. sizeChange(pageSize) {
  429. this.page.size = pageSize
  430. },
  431. refreshChange() {
  432. this.onLoad()
  433. },
  434. treeLoad(tree, treeNode, resolve) {
  435. this.loading = true
  436. getLazyList(tree.id).then(res => {
  437. this.loading = false
  438. resolve(res.data.data.childrenList.map(e => {
  439. e.project_stage = e.project_stage.toString()
  440. return e
  441. }))
  442. })
  443. },
  444. rowDel(row) {
  445. this.$confirm('确定删除选择的项目?', {
  446. confirmButtonText: '确定',
  447. cancelButtonText: '取消',
  448. type: 'warning'
  449. })
  450. .then(() => {
  451. this.$api.project.projectRemove({ids: row.id}).then(res => {
  452. if (res.code === 200) {
  453. this.$message.success(res.msg)
  454. this.onLoad()
  455. } else {
  456. this.$message.error(res.msg)
  457. }
  458. })
  459. })
  460. },
  461. getNumList(data) {
  462. this.$api.project.userNunList(data).then(res => {
  463. if (res.code === 200) {
  464. this.numList = res.data.projectStage
  465. this.num = res.data.projectStage[0].totalAmount
  466. }
  467. })
  468. },
  469. getTypeList() {
  470. this.$api.project.typeList({type: 1, size: 999, current: 1}).then(res => {
  471. this.typeList = res.data.records
  472. })
  473. this.$api.common.dicList({code: 'project-tags'}).then(res => {
  474. if (res.code === 200) {
  475. this.tagsList = res.data
  476. }
  477. })
  478. },
  479. track(res) {
  480. if (res.is_report === 1) {
  481. this.$message.error('该项目已经上报')
  482. return
  483. }
  484. this.$confirm(res.project_stage === 1 ? '上报后该项目情况将更新为正式项目,请确认项目相关信息已经审核完成' : '是否确定进行项目上报', {
  485. confirmButtonText: '确定',
  486. cancelButtonText: '取消',
  487. type: 'warning'
  488. }).then(() => {
  489. const data = {id: res.id, is_report: 1, project_stage: res.project_stage === 1 ? 2 : res.project_stage}
  490. this.$api.project.proUpdate(data).then(res => {
  491. if (res.code === 200) {
  492. this.onLoad()
  493. this.$message.success(res.msg)
  494. } else {
  495. this.$message.error(res.msg)
  496. }
  497. })
  498. })
  499. },
  500. projectSave() {
  501. if (this.disable) {
  502. this.$message.error('正在处理,请稍后...')
  503. return
  504. }
  505. this.$refs.form.validate((valid) => {
  506. if (valid) {
  507. this.disable = true
  508. this.addLoading = true
  509. this.$api.project.projectAdd(this.projectForm).then(res => {
  510. this.disable = false
  511. this.addLoading = false
  512. if (res.code === 200) {
  513. this.showAdd = false
  514. this.$message.success(res.msg)
  515. this.onLoad()
  516. } else {
  517. this.showAdd = false
  518. this.$message.error(res.msg)
  519. }
  520. })
  521. }
  522. })
  523. },
  524. formDialogClose() {
  525. if (this.diaType === 0) {
  526. this.onLoad()
  527. }
  528. this.diaType = -1
  529. },
  530. exportExcel(res) {
  531. const data = Object.assign({...this.queryData}, {
  532. columnName: res,
  533. projectIds: this.selectList.join(','),
  534. previewType: 1
  535. })
  536. this.$router.push({query: data, path: '/home/excel'})
  537. },
  538. exportExcelTotal(item) {
  539. const dataIds = {...this.queryData, ...item, projectIds: this.selectList.join(','), previewType: 2}
  540. this.$router.push({query: dataIds, path: '/home/excel'})
  541. }
  542. }
  543. }
  544. </script>
  545. <style lang="scss" scoped>
  546. .tip {
  547. width: 260px;
  548. height: 38px;
  549. background-color: #FBF6ED;
  550. font-weight: 500;
  551. flex-wrap: nowrap;
  552. margin-left: 20px;
  553. }
  554. .total-s {
  555. width: 200px;
  556. height: 50px;
  557. border: 1px solid #825618;
  558. border-radius: 10px;
  559. margin-right: 20px;
  560. box-shadow: 2px 2px 10px 2px rgba(113, 73, 39, 0.3);
  561. .sp {
  562. color: #ECAB56;
  563. white-space: nowrap;
  564. margin-left: 20px;
  565. }
  566. .sp1 {
  567. color: #ECAB56;
  568. margin-right: 20px;
  569. }
  570. }
  571. .total {
  572. width: 200px;
  573. height: 50px;
  574. border-radius: 10px;
  575. margin-right: 20px;
  576. background-color: #F0F2F7;
  577. .sp {
  578. color: #707070;
  579. white-space: nowrap;
  580. margin-left: 20px;
  581. }
  582. .sp1 {
  583. color: #825618;
  584. margin-right: 20px;
  585. }
  586. }
  587. .curd {
  588. :deep(.avue-crud__menu) {
  589. min-height: 10px;
  590. }
  591. }
  592. </style>