index.vue 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735
  1. <template>
  2. <div class="ele-body">
  3. <el-card shadow="never">
  4. <ele-split-layout
  5. width="180px"
  6. allow-collapse
  7. :right-style="{ overflow: 'hidden' }"
  8. >
  9. <div>
  10. <div
  11. class="ele-border-lighter sys-organization-list"
  12. style="margin-left: 10px"
  13. >
  14. <AssetTree
  15. @handleNodeClick="handleNodeClick"
  16. :defaultExpandAll="true"
  17. code="XM1"
  18. ref="treeList"
  19. />
  20. </div>
  21. </div>
  22. <template v-slot:content>
  23. <el-card shadow="never">
  24. <index-search @search="reload" />
  25. <!-- 数据表格 -->
  26. <ele-pro-table
  27. ref="table"
  28. row-key="id"
  29. :columns="columns"
  30. :datasource="datasource"
  31. height="calc(100vh - 400px)"
  32. full-height="calc(100vh - 116px)"
  33. :default-expand-all="true"
  34. cache-key="project-initiationTable"
  35. :selection.sync="selection"
  36. :tree-props="{ children: 'projectList' }"
  37. @done="onDone"
  38. :indent="15"
  39. :initLoad="false"
  40. >
  41. <!-- :lazy="true"-->
  42. <!-- 表头工具栏 -->
  43. <template v-slot:toolbar>
  44. <el-button
  45. size="small"
  46. type="primary"
  47. icon="el-icon-plus"
  48. class="ele-btn-icon"
  49. v-if="$hasPermission('pro:projects:save')"
  50. @click="openEdit('', 'add')"
  51. >
  52. 新建
  53. </el-button>
  54. <el-button
  55. size="small"
  56. type="danger"
  57. icon="el-icon-delete"
  58. class="ele-btn-icon"
  59. v-if="$hasPermission('pro:projects:delete')"
  60. @click="allDelBtn"
  61. >
  62. 删除
  63. </el-button>
  64. <!-- <el-button-->
  65. <!-- size="small"-->
  66. <!-- type="danger"-->
  67. <!-- icon="el-icon-remove-outline"-->
  68. <!-- class="ele-btn-icon"-->
  69. <!-- @click="handleStatus('4')"-->
  70. <!-- >-->
  71. <!-- 终止-->
  72. <!-- </el-button>-->
  73. <!-- <el-button-->
  74. <!-- size="small"-->
  75. <!-- type="warning"-->
  76. <!-- icon="el-icon-video-play"-->
  77. <!-- class="ele-btn-icon"-->
  78. <!-- @click="handleStatus('2')"-->
  79. <!-- >-->
  80. <!-- 暂停-->
  81. <!-- </el-button>-->
  82. <!-- <el-button-->
  83. <!-- size="small"-->
  84. <!-- type="primary"-->
  85. <!-- icon="el-icon-video-pause"-->
  86. <!-- class="ele-btn-icon"-->
  87. <!-- @click="handleStatus('1')"-->
  88. <!-- >-->
  89. <!-- 启动-->
  90. <!-- </el-button>-->
  91. <!-- <el-button class="el-icon-sort" size="small" @click="expandAll">-->
  92. <!-- 展开/折叠-->
  93. <!-- </el-button>-->
  94. <!-- <div class="el-button--primary">122222</div> -->
  95. </template>
  96. <template v-slot:code="{ row }">
  97. <el-button
  98. type="text"
  99. @click="handelBOMConstructDetail(row, 'view')"
  100. >{{ row.code }}</el-button
  101. >
  102. </template>
  103. <template v-slot:status="{ row }">
  104. {{ getDictV('pro_projects_status', row.status) }}
  105. </template>
  106. <!-- <template v-slot:type="{ row }">
  107. {{ getDictV('pro_projects_type', row.type) }}
  108. </template> -->
  109. <template v-slot:isOverTime="{ row }">
  110. <el-tag v-if="row.isOverTime == 0" type="success">正常</el-tag>
  111. <el-tag v-else type="danger">超时</el-tag>
  112. </template>
  113. <template v-slot:isOverbudget="{ row }">
  114. <el-tag v-if="row.isOverbudget == 0" type="success">否</el-tag>
  115. <el-tag v-else type="danger">是</el-tag>
  116. </template>
  117. <template v-slot:speedPercent="{ row }">
  118. <el-progress
  119. :stroke-width="20"
  120. text-color="#606266"
  121. :text-inside="true"
  122. :percentage="row.speedPercent || 0"
  123. :color="customColorMethod"
  124. ></el-progress>
  125. </template>
  126. <!-- 操作列 -->
  127. <template v-slot:action="{ row }">
  128. <el-link
  129. type="primary"
  130. :underline="false"
  131. icon="el-icon-plus"
  132. @click="processSubmit(row)"
  133. v-if="[0, 3].includes(row.processStatus)"
  134. >
  135. 提交
  136. </el-link>
  137. <el-link
  138. type="primary"
  139. :underline="false"
  140. icon="el-icon-edit"
  141. v-if="
  142. [0, 3].includes(row.processStatus) &&
  143. $hasPermission('pro:projects:update')
  144. "
  145. @click="openEdit(row, 'edit')"
  146. >
  147. 修改
  148. </el-link>
  149. <el-popconfirm
  150. class="ele-action"
  151. title="确定要删除吗?"
  152. v-if="
  153. [0, 3].includes(row.processStatus) &&
  154. $hasPermission('pro:projects:delete')
  155. "
  156. @confirm="remove([row.id])"
  157. >
  158. <template v-slot:reference>
  159. <el-link
  160. type="danger"
  161. :underline="false"
  162. icon="el-icon-delete"
  163. >
  164. 删除
  165. </el-link>
  166. </template>
  167. </el-popconfirm>
  168. <el-dropdown trigger="click">
  169. <span class="el-dropdown-link">
  170. 操作菜单<i class="el-icon-arrow-down el-icon--right"></i>
  171. </span>
  172. <el-dropdown-menu slot="dropdown">
  173. <el-dropdown-item
  174. v-if="
  175. ![0, 1, 3].includes(row.processStatus) &&
  176. ![4, 2, 3].includes(row.status) &&
  177. $hasPermission('pro:projects:update')
  178. "
  179. >
  180. <el-link
  181. icon="el-icon-success"
  182. type="success"
  183. :underline="false"
  184. @click="handleStatus(projectsFinishAPI, '完成', row)"
  185. >完成
  186. </el-link>
  187. </el-dropdown-item>
  188. <el-dropdown-item
  189. v-if="
  190. ![0, 1, 3].includes(row.processStatus) &&
  191. ![4, 2, 3].includes(row.status) &&
  192. $hasPermission('pro:projects:update')
  193. "
  194. >
  195. <el-link
  196. icon="el-icon-video-pause"
  197. type="warning"
  198. :underline="false"
  199. @click="handleStatus(projectsPauseAPI, '暂停', row)"
  200. >暂停
  201. </el-link>
  202. </el-dropdown-item>
  203. <el-dropdown-item
  204. v-if="
  205. ![0, 1, 3].includes(row.processStatus) &&
  206. ![4, 1, 0, 3].includes(row.status) &&
  207. $hasPermission('pro:projects:update')
  208. "
  209. >
  210. <el-link
  211. icon="el-icon-video-play"
  212. type="success"
  213. :underline="false"
  214. @click="handleStatus(projectsStartupAPI, '启动', row)"
  215. >启动
  216. </el-link>
  217. </el-dropdown-item>
  218. <el-dropdown-item
  219. v-if="
  220. ![0, 1, 3].includes(row.processStatus) &&
  221. ![4, 3].includes(row.status) &&
  222. $hasPermission('pro:projects:update')
  223. "
  224. >
  225. <el-link
  226. icon="el-icon-error"
  227. type="danger"
  228. :underline="false"
  229. @click="
  230. handleStatus(projectsTerminationAPI, '终止', row)
  231. "
  232. >终止</el-link
  233. >
  234. </el-dropdown-item>
  235. <el-dropdown-item>
  236. <el-link
  237. icon="el-icon-info"
  238. type="primary"
  239. :underline="false"
  240. @click="handelBOMConstructDetail(row)"
  241. >
  242. 项目信息
  243. </el-link>
  244. </el-dropdown-item>
  245. <el-dropdown-item
  246. divided
  247. v-if="
  248. [0, 1, 2, 3].includes(row.processStatus) &&
  249. [0, 1].includes(row.status)
  250. "
  251. >
  252. <el-link
  253. icon="el-icon-circle-plus"
  254. type="primary"
  255. :underline="false"
  256. @click="handleAddPlan(row)"
  257. >
  258. 新增计划
  259. </el-link>
  260. </el-dropdown-item>
  261. </el-dropdown-menu>
  262. </el-dropdown>
  263. </template>
  264. </ele-pro-table>
  265. </el-card>
  266. </template>
  267. <!-- 编辑弹窗 -->
  268. <add-or-edit-dialog
  269. v-if="addOrEditDialogFlag"
  270. @reload="reload"
  271. :addOrEditDialogFlag.sync="addOrEditDialogFlag"
  272. ref="addOrEditDialogRef"
  273. ></add-or-edit-dialog>
  274. <detail-dialog
  275. v-if="detailDialogFlag"
  276. :detailDialogFlag.sync="detailDialogFlag"
  277. ref="detailDialogRef"
  278. ></detail-dialog>
  279. <!-- 新增计划 -->
  280. <add-plan-dialog
  281. v-if="addPlanDialogFLag"
  282. @reload="reload"
  283. :addOrEditDialogFlag.sync="addPlanDialogFLag"
  284. ref="addPlanDialogRef"
  285. ></add-plan-dialog>
  286. <!-- 多选删除弹窗 -->
  287. <pop-modal
  288. :visible.sync="delVisible"
  289. content="是否确定删除?"
  290. @done="commitBtn"
  291. />
  292. <process-submit-dialog
  293. :processSubmitDialogFlag.sync="processSubmitDialogFlag"
  294. v-if="processSubmitDialogFlag"
  295. ref="processSubmitDialogRef"
  296. @reload="reload"
  297. ></process-submit-dialog>
  298. <ProjectDetailDialog
  299. ref="ProjectDetailDialogFlag"
  300. @reload="reload"
  301. ></ProjectDetailDialog>
  302. </ele-split-layout>
  303. </el-card>
  304. </div>
  305. </template>
  306. <script>
  307. import ProjectDetailDialog from '@/views/BOMmanage/ProjectDetailDialog.vue';
  308. import processSubmitDialog from '@/BIZComponents/processSubmitDialog/processSubmitDialog.vue';
  309. import indexSearch from './components/index-search.vue';
  310. import addOrEditDialog from './components/addOrEditDialog.vue';
  311. import addPlanDialog from '../planManage/components/addOrEditDialog.vue';
  312. import detailDialog from './components/detailDialog.vue';
  313. import {
  314. projectsDeleteAPI,
  315. projectsPageAPI,
  316. submit,
  317. projectsFinishAPI,
  318. projectsPauseAPI,
  319. projectsStartupAPI,
  320. projectsTerminationAPI,
  321. getMyProjectsPage
  322. } from '@/api/project-manage';
  323. import { reviewStatusEnum } from '@/enum/dict';
  324. import { mapGetters } from 'vuex';
  325. import { getByCode } from '@/api/system/dictionary-data';
  326. import popModal from '@/components/pop-modal/index.vue';
  327. import AssetTree from '@/components/AssetTree';
  328. export default {
  329. name: 'index',
  330. components: {
  331. popModal,
  332. addOrEditDialog,
  333. detailDialog,
  334. indexSearch,
  335. processSubmitDialog,
  336. addPlanDialog,
  337. AssetTree,
  338. ProjectDetailDialog
  339. },
  340. computed: {
  341. ...mapGetters(['getDictValue']),
  342. columns() {
  343. return [
  344. {
  345. width: 45,
  346. type: 'selection',
  347. columnKey: 'selection',
  348. align: 'center'
  349. },
  350. {
  351. columnKey: 'index',
  352. label: '序号',
  353. type: 'index',
  354. width: 55,
  355. align: 'center',
  356. showOverflowTooltip: true
  357. },
  358. {
  359. prop: 'typeName',
  360. label: '项目类型',
  361. showOverflowTooltip: true,
  362. minWidth: 150,
  363. align: 'center'
  364. // slot: 'type',
  365. },
  366. {
  367. prop: 'code',
  368. label: '项目编码',
  369. showOverflowTooltip: true,
  370. minWidth: 160,
  371. slot: 'code',
  372. align: 'center'
  373. },
  374. {
  375. prop: 'name',
  376. label: '项目名称',
  377. align: 'center',
  378. showOverflowTooltip: true,
  379. minWidth: 140
  380. },
  381. {
  382. prop: 'responsibleDeptName',
  383. label: '负责部门',
  384. align: 'center',
  385. showOverflowTooltip: true,
  386. minWidth: 100
  387. },
  388. {
  389. prop: 'responsibleUserName',
  390. label: '项目经理',
  391. align: 'center',
  392. showOverflowTooltip: true,
  393. minWidth: 100
  394. },
  395. {
  396. prop: 'teamName',
  397. label: '项目团队',
  398. align: 'center',
  399. showOverflowTooltip: true,
  400. minWidth: 100
  401. },
  402. {
  403. prop: 'cycle',
  404. label: '项目周期',
  405. align: 'center',
  406. showOverflowTooltip: true,
  407. minWidth: 100
  408. },
  409. {
  410. prop: 'budget',
  411. label: '项目预算',
  412. align: 'center',
  413. showOverflowTooltip: true,
  414. minWidth: 110,
  415. formatter: (_row, _column, cellValue) => {
  416. return cellValue
  417. ? cellValue +
  418. this.getDictV('pro_projects_budget_unit', _row.unit)
  419. : '';
  420. }
  421. },
  422. {
  423. prop: 'planStartDate',
  424. label: '计划开始日期',
  425. align: 'center',
  426. showOverflowTooltip: true,
  427. minWidth: 120
  428. },
  429. {
  430. prop: 'planEndDate',
  431. label: '计划完成日期',
  432. align: 'center',
  433. showOverflowTooltip: true,
  434. minWidth: 120
  435. },
  436. {
  437. prop: 'realStartTime',
  438. label: '实际开始日期',
  439. align: 'center',
  440. showOverflowTooltip: true,
  441. minWidth: 120
  442. },
  443. {
  444. prop: 'realEndTime',
  445. label: '实际完成日期',
  446. align: 'center',
  447. showOverflowTooltip: true,
  448. minWidth: 120
  449. },
  450. {
  451. prop: 'cost',
  452. label: '费用(元)',
  453. align: 'center',
  454. showOverflowTooltip: true,
  455. minWidth: 140
  456. },
  457. {
  458. prop: 'status',
  459. label: '项目状态',
  460. align: 'center',
  461. showOverflowTooltip: true,
  462. minWidth: 100,
  463. slot: 'status'
  464. },
  465. {
  466. prop: 'processStatus',
  467. label: '审核状态',
  468. align: 'center',
  469. showOverflowTooltip: true,
  470. minWidth: 100,
  471. formatter: (_row, _column, cellValue) => {
  472. return reviewStatusEnum[_row.processStatus].label;
  473. }
  474. },
  475. {
  476. prop: 'isOverTime',
  477. label: '是否超时',
  478. align: 'center',
  479. showOverflowTooltip: true,
  480. minWidth: 100,
  481. slot: 'isOverTime'
  482. },
  483. {
  484. prop: 'isOverbudget',
  485. label: '是否超预算',
  486. align: 'center',
  487. showOverflowTooltip: true,
  488. minWidth: 100,
  489. slot: 'isOverbudget'
  490. },
  491. {
  492. prop: 'speedPercent',
  493. label: '项目进度',
  494. align: 'center',
  495. showOverflowTooltip: true,
  496. minWidth: 150,
  497. slot: 'speedPercent'
  498. },
  499. {
  500. columnKey: 'action',
  501. label: '操作',
  502. width: 280,
  503. align: 'center',
  504. resizable: false,
  505. slot: 'action',
  506. fixed: 'right'
  507. }
  508. ];
  509. }
  510. },
  511. data() {
  512. return {
  513. projectsFinishAPI: projectsFinishAPI,
  514. projectsPauseAPI: projectsPauseAPI,
  515. projectsStartupAPI: projectsStartupAPI,
  516. projectsTerminationAPI: projectsTerminationAPI,
  517. parentId:'',
  518. selection: [],
  519. dictList: [],
  520. // 表格列配置
  521. // 是否显示编辑弹窗
  522. addOrEditDialogFlag: false,
  523. detailDialogFlag: false,
  524. processSubmitDialogFlag: false,
  525. delVisible: false,
  526. addPlanDialogFLag: false,
  527. // 全部菜单数据
  528. menuList: [],
  529. // 展开折叠
  530. expandAllFlag: false
  531. };
  532. },
  533. async created() {
  534. console.log(111);
  535. },
  536. watch: {
  537. $route() {
  538. this.reload && this.reload();
  539. }
  540. },
  541. methods: {
  542. getDictV(code, val) {
  543. if (!this.dictList[code]) return '';
  544. return this.dictList[code].find((item) => item.value == val)?.label;
  545. },
  546. async getDictList(code) {
  547. let { data: res } = await getByCode(code);
  548. this.dictList[code] = res.map((item) => {
  549. let values = Object.keys(item);
  550. return {
  551. value: values[0],
  552. label: item[values[0]]
  553. };
  554. });
  555. },
  556. handelBOMConstructDetail(row, type = '') {
  557. // this.$router.push({
  558. // path: '/BOMmanage/details',
  559. // query: {
  560. // id: row.id,
  561. // type
  562. // }
  563. // });
  564. this.$refs.ProjectDetailDialogFlag.open(row, type);
  565. },
  566. customColorMethod(percentage) {
  567. if (percentage < 30) {
  568. return '#909399';
  569. } else if (percentage < 70) {
  570. return '#e6a23c';
  571. } else {
  572. return '#67c23a';
  573. }
  574. },
  575. /* 表格数据源 */
  576. async datasource({ page, limit, where, parent }) {
  577. await this.getDictList('pro_projects_status');
  578. await this.getDictList('pro_projects_type');
  579. await this.getDictList('pro_projects_budget_unit');
  580. // /project-manage/myProject
  581. const api =
  582. this.$route.path == '/project-manage/myProject'
  583. ? getMyProjectsPage
  584. : projectsPageAPI;
  585. return api({
  586. pageNum: page,
  587. size: limit,
  588. parentId: parent?.id ?? '0',
  589. // parentId:this.parentId,
  590. ...where,
  591. type: this.treeId
  592. });
  593. },
  594. onDone(row) {
  595. console.log(row);
  596. },
  597. /* 刷新表格 */
  598. reload(where) {
  599. this.$refs.table.reload({ where, size: 1, pageNum: 10, parentId: '0' });
  600. this.$refs.table.reRenderTable();
  601. },
  602. handleNodeClick(data, node) {
  603. this.parentId=data.parentId
  604. this.treeId = data.id;
  605. this.reload();
  606. },
  607. /* 显示编辑 */
  608. openEdit(row = {}, type) {
  609. this.addOrEditDialogFlag = true;
  610. this.$nextTick(() => {
  611. this.$refs.addOrEditDialogRef.init(row, type);
  612. });
  613. },
  614. openDetail(row = {}) {
  615. this.detailDialogFlag = true;
  616. this.$nextTick(() => {
  617. this.$refs.detailDialogRef.init(row);
  618. });
  619. },
  620. handleAddPlan(row) {
  621. console.log(row);
  622. this.addPlanDialogFLag = true;
  623. this.$nextTick(() => {
  624. row.projectId = row.id;
  625. this.$refs.addPlanDialogRef.init(row, 'add');
  626. });
  627. },
  628. async handleStatus(API, msg, row) {
  629. let message = '确定' + msg + '该项目吗';
  630. this.$confirm(message, '提示', {
  631. type: 'warning'
  632. })
  633. .then(async () => {
  634. await API(row.id);
  635. this.$message.success('操作成功');
  636. this.reload();
  637. })
  638. .catch(() => {});
  639. },
  640. //流程提交
  641. processSubmit(row) {
  642. this.processSubmitDialogFlag = true;
  643. this.$nextTick(() => {
  644. let params = {
  645. businessId: row.id,
  646. businessKey: 'pro_project_approve',
  647. formCreateUserId: row.createUserId
  648. };
  649. this.$refs.processSubmitDialogRef.init(params);
  650. });
  651. // submit({
  652. // projectId: row.id
  653. // }).then((res) => {
  654. // this.$message.success('提交成功');
  655. // this.reload();
  656. // });
  657. },
  658. //批量删除
  659. allDelBtn() {
  660. if (this.selection.length === 0) return;
  661. let flag = this.selection.some((item) =>
  662. [1, 2].includes(item.processStatus)
  663. );
  664. if (flag)
  665. return this.$message.warning(
  666. '抱歉已审核、审核中的数据不能删除,请检查'
  667. );
  668. this.delVisible = true;
  669. },
  670. //删除弹框确定
  671. commitBtn() {
  672. const dataId = this.selection.map((v) => v.id);
  673. this.remove(dataId);
  674. },
  675. /* 删除 */
  676. remove(ids) {
  677. const loading = this.$loading({ lock: true });
  678. projectsDeleteAPI(ids)
  679. .then((res) => {
  680. loading.close();
  681. this.$message.success('删除成功');
  682. this.reload();
  683. })
  684. .catch((e) => {
  685. loading.close();
  686. // this.$message.error(e.message);
  687. });
  688. },
  689. /* 展开/折叠全部 */
  690. expandAll() {
  691. this.expandAllFlag = !this.expandAllFlag;
  692. this.$refs.table.toggleRowExpansionAll(this.expandAllFlag);
  693. }
  694. }
  695. };
  696. </script>
  697. <style lang="scss" scoped>
  698. :deep(.el-link--inner) {
  699. margin-left: 0px !important;
  700. }
  701. ::v-deep .el-dropdown-link {
  702. cursor: pointer;
  703. color: #188ffd;
  704. }
  705. ::v-deep .el-dropdown-menu__item {
  706. .el-link {
  707. width: 100%;
  708. display: flex;
  709. flex: 1;
  710. justify-content: flex-start;
  711. }
  712. }
  713. .sys-organization-list {
  714. height: calc(100vh - 230px);
  715. box-sizing: border-box;
  716. border-width: 1px;
  717. border-style: solid;
  718. overflow: auto;
  719. }
  720. .sys-organization-list :deep(.el-tree-node__content) {
  721. height: 40px;
  722. & > .el-tree-node__expand-icon {
  723. margin-left: 10px;
  724. }
  725. }
  726. </style>