index.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  1. <template>
  2. <div class="ele-body">
  3. <el-card shadow="never" v-loading="loading">
  4. <div class="ele-border-lighter form-content" v-loading="loading">
  5. <search-quotation @search="reload"></search-quotation>
  6. <!-- 数据表格 -->
  7. <ele-pro-table
  8. ref="table"
  9. :columns="columns"
  10. :datasource="datasource"
  11. height="calc(100vh - 375px)"
  12. full-height="calc(100vh - 116px)"
  13. tool-class="ele-toolbar-form"
  14. :selection.sync="selection"
  15. :page-size="20"
  16. @columns-change="handleColumnChange"
  17. :cache-key="cacheKeyUrl"
  18. >
  19. <!-- 表头工具栏 -->
  20. <template v-slot:toolbar>
  21. <el-button
  22. size="small"
  23. type="primary"
  24. icon="el-icon-plus"
  25. class="ele-btn-icon"
  26. @click="openEdit('add', {})"
  27. >
  28. 新建
  29. </el-button>
  30. <el-button
  31. size="small"
  32. type="danger"
  33. el-icon-delete
  34. class="ele-btn-icon"
  35. @click="allDelBtn"
  36. :disabled="selection?.length === 0"
  37. >
  38. 批量删除
  39. </el-button>
  40. <el-button
  41. type="primary"
  42. size="small"
  43. icon="el-icon-upload2"
  44. @click="uploadFile"
  45. >导入</el-button
  46. >
  47. <el-button
  48. type="primary"
  49. size="small"
  50. icon="el-icon-download"
  51. @click="exportRowInfo()"
  52. :disabled="selection?.length !== 1"
  53. >导出</el-button
  54. >
  55. <el-button
  56. type="primary"
  57. size="small"
  58. @click="updatePrice()"
  59. :disabled="!canBatchUpdatePrice"
  60. >批量更新价格</el-button
  61. >
  62. </template>
  63. <!-- 查看详情列 -->
  64. <template v-slot:contactName="{ row }">
  65. <el-link type="primary" :underline="false" @click="openDetail(row)">
  66. {{ row.contactName }}
  67. </el-link>
  68. </template>
  69. <!-- 附件 -->
  70. <template v-slot:askFile="{ row }">
  71. <fileMain
  72. type="view"
  73. v-model="row.askFile"
  74. v-if="row.askFile?.length"
  75. ></fileMain>
  76. </template>
  77. <!-- 操作列 -->
  78. <template v-slot:action="{ row }">
  79. <el-link
  80. type="primary"
  81. :underline="false"
  82. icon="el-icon-edit"
  83. @click="openEdit('copy', row)"
  84. >
  85. 复制
  86. </el-link>
  87. <el-link
  88. type="primary"
  89. :underline="false"
  90. icon="el-icon-edit"
  91. v-if="
  92. (isNeed_process_is_close && [0, 3].includes(row.status)) ||
  93. !isNeed_process_is_close
  94. "
  95. @click="openEdit('edit', row)"
  96. >
  97. 修改
  98. </el-link>
  99. <el-link
  100. type="primary"
  101. :underline="false"
  102. icon="el-icon-plus"
  103. v-if="isNeed_process_is_close && [0, 3].includes(row.status)"
  104. @click="quotationSubmit(row)"
  105. >
  106. 提交
  107. </el-link>
  108. <el-link
  109. type="primary"
  110. :underline="false"
  111. icon="el-icon-plus"
  112. v-if="[2].includes(row.status) && [1].includes(row.dataStatus)"
  113. @click="addGenerateContract(row)"
  114. >
  115. 生成合同
  116. </el-link>
  117. <el-link
  118. type="danger"
  119. :underline="false"
  120. v-if="[2].includes(row.status) && [1].includes(row.dataStatus)"
  121. @click="setQuoteStatus(row)"
  122. >
  123. 终止
  124. </el-link>
  125. <el-popconfirm
  126. class="ele-action"
  127. title="确定要删除此信息吗?"
  128. @confirm="remove([row.id])"
  129. >
  130. <template v-slot:reference>
  131. <el-link
  132. type="danger"
  133. :underline="false"
  134. icon="el-icon-delete"
  135. v-if="
  136. (isNeed_process_is_close && [0, 3].includes(row.status)) ||
  137. !isNeed_process_is_close
  138. "
  139. >
  140. 删除
  141. </el-link>
  142. </template>
  143. </el-popconfirm>
  144. </template>
  145. </ele-pro-table>
  146. </div>
  147. </el-card>
  148. <add-dialog
  149. ref="addDialogRef"
  150. @done="reload"
  151. :contactData="contactData"
  152. :businessOpportunityData="businessOpportunityData"
  153. ></add-dialog>
  154. <detail-dialog ref="contactDetailDialogRef"></detail-dialog>
  155. <!-- 多选删除弹窗 -->
  156. <pop-modal
  157. :visible.sync="delVisible"
  158. content="是否确定删除?"
  159. @done="commitBtn"
  160. />
  161. <addContractBookDialog
  162. ref="addContractBookDialogRef"
  163. :categoryTreeList="treeList"
  164. :contactData="contactData"
  165. :businessOpportunityData="businessOpportunityData"
  166. ></addContractBookDialog>
  167. <process-submit-dialog
  168. api-fun-name="quoteUpdateStatusAPI"
  169. :processSubmitDialogFlag.sync="processSubmitDialogFlag"
  170. :isCloseRefresh="false"
  171. v-if="processSubmitDialogFlag"
  172. ref="processSubmitDialogRef"
  173. @reload="reload"
  174. ></process-submit-dialog>
  175. <importDialog
  176. ref="importDialogRef"
  177. @success="reload"
  178. :fileUrl="'/eom/quote/downLoadTemplate'"
  179. :isWeb="false"
  180. fileName="报价管理导入模板"
  181. apiUrl="/eom/quote/importFile"
  182. />
  183. </div>
  184. </template>
  185. <script>
  186. import searchQuotation from './components/searchQuotation.vue';
  187. import addDialog from './components/addDialog.vue';
  188. import detailDialog from './components/detailDialog.vue';
  189. import popModal from '@/components/pop-modal';
  190. import { reviewStatus } from '@/enum/dict';
  191. import addContractBookDialog from '@/views/contractManage/contractBook/components/addDialog.vue';
  192. import { contactTypeTree, contactDetail } from '@/api/saleManage/contact';
  193. import importDialog from '@/components/upload/import-dialog.vue';
  194. // import fileMain from '@/components/addDoc/index.vue';
  195. import {
  196. getTableList,
  197. getDetail,
  198. deleteInformation,
  199. submit,
  200. quoteUpdateStatus,
  201. exportByPathId,
  202. updateProductPrice
  203. } from '@/api/saleManage/quotation';
  204. import dictMixins from '@/mixins/dictMixins';
  205. import processSubmitDialog from '@/BIZComponents/processSubmitDialog/processSubmitDialog.vue';
  206. import tabMixins from '@/mixins/tableColumnsMixin';
  207. export default {
  208. mixins: [dictMixins, tabMixins],
  209. components: {
  210. processSubmitDialog,
  211. searchQuotation,
  212. popModal,
  213. addDialog,
  214. detailDialog,
  215. importDialog,
  216. addContractBookDialog
  217. // fileMain
  218. },
  219. props: {
  220. contactData: {
  221. default: () => {
  222. return {};
  223. }
  224. },
  225. businessOpportunityData: {
  226. //商机
  227. default: () => {
  228. return {};
  229. }
  230. }
  231. },
  232. data() {
  233. return {
  234. selection: [], //单选中集合
  235. delVisible: false, //批量删除弹框状态
  236. loading: false, // 加载状态
  237. processSubmitDialogFlag: false,
  238. treeList: [],
  239. columns: [
  240. {
  241. width: 45,
  242. type: 'selection',
  243. columnKey: 'selection',
  244. align: 'center'
  245. },
  246. {
  247. columnKey: 'index',
  248. label: '序号',
  249. type: 'index',
  250. width: 55,
  251. align: 'center',
  252. showOverflowTooltip: true,
  253. fixed: 'left'
  254. },
  255. {
  256. prop: 'code',
  257. label: '编码',
  258. align: 'center',
  259. showOverflowTooltip: true,
  260. minWidth: 200
  261. },
  262. {
  263. prop: 'contactName',
  264. label: '询价方名称',
  265. align: 'center',
  266. slot: 'contactName',
  267. showOverflowTooltip: true,
  268. minWidth: 200
  269. },
  270. {
  271. prop: 'contactLinkName',
  272. label: '询价方联系人',
  273. align: 'center',
  274. showOverflowTooltip: true,
  275. minWidth: 140
  276. },
  277. {
  278. prop: 'contactTel',
  279. label: '询价方联系电话',
  280. align: 'center',
  281. showOverflowTooltip: true,
  282. minWidth: 140
  283. },
  284. {
  285. prop: 'productNames',
  286. label: '产品名称',
  287. align: 'center',
  288. showOverflowTooltip: true,
  289. minWidth: 140
  290. },
  291. {
  292. prop: 'type',
  293. label: '报价类型',
  294. align: 'center',
  295. showOverflowTooltip: true,
  296. minWidth: 120,
  297. formatter: (_row, _column, cellValue) => {
  298. // 根据type值转换显示文本
  299. if (_row.type === 1) return '产品销售';
  300. if (_row.type === 2) return '生产加工';
  301. return ''; // 其他情况显示空
  302. }
  303. },
  304. {
  305. prop: 'quoteName',
  306. label: '报价方名称',
  307. align: 'center',
  308. showOverflowTooltip: true,
  309. minWidth: 200
  310. },
  311. {
  312. prop: 'quoteLinkName',
  313. label: '报价方联系人',
  314. align: 'center',
  315. showOverflowTooltip: true,
  316. minWidth: 140
  317. },
  318. {
  319. prop: 'quoteTel',
  320. label: '报价方联系电话',
  321. align: 'center',
  322. showOverflowTooltip: true,
  323. minWidth: 140
  324. },
  325. {
  326. prop: 'deliveryDate',
  327. label: '交货日期',
  328. align: 'center',
  329. showOverflowTooltip: true,
  330. minWidth: 100
  331. },
  332. {
  333. prop: 'settlementModeName',
  334. label: '付款方式',
  335. align: 'center',
  336. showOverflowTooltip: true,
  337. minWidth: 100
  338. },
  339. // {
  340. // prop: 'taxRate',
  341. // label: '税率',
  342. // align: 'center',
  343. // showOverflowTooltip: true,
  344. // minWidth: 140,
  345. // formatter: (_row, _column, cellValue) => {
  346. // return _row.taxRate ? _row.taxRate + '%' : '';
  347. // }
  348. // },
  349. {
  350. prop: 'totalPrice',
  351. label: '总金额',
  352. align: 'center',
  353. showOverflowTooltip: true,
  354. minWidth: 100
  355. },
  356. {
  357. prop: 'askFile',
  358. label: '附件',
  359. align: 'center',
  360. showOverflowTooltip: true,
  361. slot: 'askFile',
  362. minWidth: 130
  363. },
  364. {
  365. prop: 'dataStatus',
  366. label: '启用状态',
  367. align: 'center',
  368. showOverflowTooltip: true,
  369. minWidth: 100,
  370. formatter: (_row, _column, cellValue) => {
  371. return _row.dataStatus === 1 ? '正常' : '终止';
  372. }
  373. },
  374. {
  375. prop: 'status',
  376. label: '审核状态',
  377. align: 'center',
  378. showOverflowTooltip: true,
  379. minWidth: 100,
  380. formatter: (_row, _column, cellValue) => {
  381. return reviewStatus[_row.status];
  382. }
  383. },
  384. {
  385. prop: 'createUserName',
  386. label: '创建人',
  387. align: 'center',
  388. showOverflowTooltip: true,
  389. minWidth: 80
  390. },
  391. {
  392. prop: 'createTime',
  393. label: '创建时间',
  394. align: 'center',
  395. showOverflowTooltip: true,
  396. minWidth: 170,
  397. formatter: (_row, _column, cellValue) => {
  398. return this.$util.toDateString(cellValue);
  399. }
  400. },
  401. {
  402. columnKey: 'action',
  403. label: '操作',
  404. width: 230,
  405. align: 'center',
  406. resizable: false,
  407. slot: 'action',
  408. showOverflowTooltip: true,
  409. fixed: 'right'
  410. }
  411. ],
  412. cacheKeyUrl: 'eos-5569a1b1-saleManage-quotation'
  413. };
  414. },
  415. created() {
  416. this.requestDict('客户状态');
  417. this.getTreeData();
  418. },
  419. computed: {
  420. canBatchUpdatePrice() {
  421. if (this.selection?.length === 0) {
  422. return false; // 没有选中项,禁用
  423. }
  424. return this.selection.every((row) => [0, 3].includes(row.status));
  425. }
  426. },
  427. methods: {
  428. quoteUpdateStatus,
  429. /* 表格数据源 */
  430. datasource({ page, limit, where, order }) {
  431. if (this.contactData.id) {
  432. where['contactId'] = this.contactData.id;
  433. }
  434. if (this.businessOpportunityData.id) {
  435. where['opportunityId'] = this.businessOpportunityData.id;
  436. }
  437. return getTableList({
  438. pageNum: page,
  439. size: limit,
  440. ...where
  441. });
  442. },
  443. //导出
  444. exportRowInfo() {
  445. const ids = this.selection.map((row) => row.id);
  446. if (ids.length === 0) {
  447. this.$message.warning('请选择需要导出的数据');
  448. return;
  449. }
  450. if (ids.length > 1) {
  451. this.$message.warning('只能选择一条数据进行导出');
  452. return;
  453. }
  454. exportByPathId(ids);
  455. },
  456. updatePrice() {
  457. const ids = this.selection.map((row) => row.id);
  458. updateProductPrice(ids);
  459. },
  460. //获取合同分类
  461. async getTreeData() {
  462. try {
  463. this.treeLoading = true;
  464. const res = await contactTypeTree({ id: '20' });
  465. this.treeLoading = false;
  466. if (res?.code === '0') {
  467. this.treeList = res.data;
  468. return this.treeList;
  469. }
  470. } catch (error) {}
  471. this.treeLoading = false;
  472. },
  473. /* 刷新表格 */
  474. reload(where) {
  475. this.$refs.table.reload({ page: 1, where });
  476. },
  477. //导入
  478. uploadFile() {
  479. this.$refs.importDialogRef.open();
  480. },
  481. //新增编辑
  482. openEdit(type, row) {
  483. this.$refs.addDialogRef.open(type, row, row.id);
  484. this.$refs.addDialogRef.$refs.form &&
  485. this.$refs.addDialogRef.$refs.form.clearValidate();
  486. },
  487. //批量删除
  488. allDelBtn() {
  489. if (this.selection.length === 0) return;
  490. let flag = this.selection.some((item) => [1, 2].includes(item.status));
  491. if (flag)
  492. return this.$message.warning('抱歉已审核、审核中的数据不能删除,请检查');
  493. this.delVisible = true;
  494. },
  495. //删除接口
  496. remove(delData) {
  497. deleteInformation(delData).then((res) => {
  498. this.$message.success('删除成功!');
  499. this.reload();
  500. });
  501. },
  502. //删除弹框确定
  503. commitBtn() {
  504. const dataId = this.selection.map((v) => v.id);
  505. this.remove(dataId);
  506. },
  507. async setQuoteStatus(row) {
  508. await quoteUpdateStatus({ id: row.id, status: 2 });
  509. this.$message.success('操作成功!');
  510. this.reload();
  511. },
  512. //新增合同
  513. async addGenerateContract(row) {
  514. //获取详情
  515. const data = await getDetail(row.id);
  516. const contact = await contactDetail(data.contactId);
  517. let obj = {
  518. contractVO: {
  519. categoryId: '',
  520. categoryName: '',
  521. contractEndDate: '',
  522. contractFile: [],
  523. contractNo: '',
  524. contractNumber: '',
  525. contractStartDate: '',
  526. createDept: '',
  527. createTime: '',
  528. createUsername: '',
  529. discountTotalPrice: '',
  530. enabled: '',
  531. id: '',
  532. opportunityId: '',
  533. partaAddress: data.contactAddress,
  534. partaEmail: data.contactEmail,
  535. partaFax: data.contactFax,
  536. partaId: data.contactId,
  537. partaLinkId: data.contactLinkId,
  538. partaLinkName: data.contactLinkName,
  539. partaName: data.contactName,
  540. partaTel: data.contactTel,
  541. partaUnifiedSocialCreditCode: '',
  542. partbAddress: data.quoteAddress,
  543. partbEmail: data.quoteEmail,
  544. partbFax: data.quoteFax,
  545. partbId: data.quoteCompanyId,
  546. partbLinkId: data.quoteLinkId,
  547. partbLinkName: data.quoteLinkName,
  548. partbName: data.quoteName,
  549. partbTel: data.quoteTel,
  550. partbUnifiedSocialCreditCode: '',
  551. receiptPaymentType: '',
  552. reviewerId: '',
  553. reviewerName: '',
  554. reviewerTime: '',
  555. sourceId: row.id,
  556. sourceType: 1,
  557. sourceName: data.code,
  558. status: '',
  559. totalPrice: data.totalPrice,
  560. discountTotalPrice: data.totalPrice,
  561. type: '1',
  562. typeName: '销售合同',
  563. updateUsername: '',
  564. sourceCode: row.code,
  565. contractName: contact.base.simpleName,
  566. settlementModeName: data.settlementModeName,
  567. settlementMode: data.settlementMode
  568. },
  569. receiptPaymentList: [],
  570. productList: data.quoteProductList
  571. };
  572. // return;
  573. this.$refs.addContractBookDialogRef.open('add', obj, true, 'quotation');
  574. },
  575. //查看详情
  576. openDetail(row) {
  577. this.$refs.contactDetailDialogRef.open(row);
  578. },
  579. quotationSubmit(res) {
  580. this.processSubmitDialogFlag = true;
  581. this.$nextTick(() => {
  582. let params = {
  583. businessId: res.id,
  584. businessKey: 'quote_approve',
  585. formCreateUserId: res.createUserId,
  586. variables: {
  587. businessCode: res.code,
  588. businessName: res.contactName,
  589. businessType: '报价单'
  590. }
  591. // callBackMethodType : '1',
  592. // callBackMethod : 'proTargetPlanApproveApiImpl.updatePlanApprovalStatus',
  593. // pcHandle : '/bpm/handleTask/components/project-manage/plan-manage/submit.vue',
  594. // pcView : '/bpm/handleTask/components/project-manage/plan-manage/detailDialog.vue',
  595. // miniHandle : '',
  596. // miniView : '',
  597. };
  598. this.$refs.processSubmitDialogRef.init(params);
  599. });
  600. // submit({
  601. // businessId: res.id
  602. // }).then((res) => {
  603. // this.$message.success('提交成功!');
  604. // this.reload();
  605. // });
  606. }
  607. }
  608. };
  609. </script>
  610. <style lang="scss" scoped>
  611. :deep(.el-link--inner) {
  612. margin-left: 0px !important;
  613. }
  614. .sys-organization-list {
  615. height: calc(100vh - 264px);
  616. box-sizing: border-box;
  617. border-width: 1px;
  618. border-style: solid;
  619. overflow: auto;
  620. }
  621. .sys-organization-list :deep(.el-tree-node__content) {
  622. height: 40px;
  623. & > .el-tree-node__expand-icon {
  624. margin-left: 10px;
  625. }
  626. }
  627. </style>