plm前端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1861 lines
63 KiB

2 years ago
1 year ago
2 years ago
2 years ago
1 year ago
2 years ago
2 years ago
1 year ago
2 years ago
1 year ago
2 years ago
2 years ago
3 months ago
2 years ago
2 years ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
1 year ago
1 year ago
2 years ago
2 years ago
5 months ago
2 years ago
1 year ago
2 years ago
1 year ago
2 years ago
1 year ago
2 years ago
7 months ago
7 months ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
1 year ago
2 years ago
2 years ago
1 year ago
2 years ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
1 year ago
2 years ago
3 months ago
2 years ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
2 years ago
2 years ago
2 years ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
3 months ago
2 years ago
3 months ago
2 years ago
1 year ago
2 years ago
2 years ago
2 years ago
12 months ago
7 months ago
2 years ago
12 months ago
7 months ago
2 years ago
12 months ago
2 years ago
12 months ago
2 years ago
12 months ago
2 years ago
12 months ago
2 years ago
2 years ago
12 months ago
2 years ago
12 months ago
2 years ago
2 years ago
12 months ago
2 years ago
1 year ago
2 years ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
1 year ago
2 years ago
1 year ago
2 years ago
1 year ago
1 year ago
2 years ago
  1. <script>
  2. import QuoteSearch from "./primary/quoteSearch.vue";
  3. import QuoteTable from "./primary/quoteTable.vue";
  4. import {
  5. againQuote,
  6. queryQuotePage, queryQuotePageByAnyField,
  7. queryQuoteRoleUser,
  8. removeQuote,
  9. saveQuote,
  10. updateQuote,
  11. updateQuoteStatus,
  12. quoteEditStatus
  13. } from "../../../api/quote/quote";
  14. import QuoteDetail from "./detail/quoteDetail.vue";
  15. import ChooseList from '@/views/modules/common/Chooselist';
  16. import {queryCustomer} from "../../../api/customer/customerInformation";
  17. import DictDataSelect from "../sys/dict-data-select.vue";
  18. import {queryProjectByCustomer} from "../../../api/project/project";
  19. import quotationCustomerContact from "../quotation/sellForQuotation/quotationCustomerContact.vue";
  20. import CustomerInfo from "../quotation/sellForQuotation/customerInfo.vue";
  21. import OssComponents from "../oss/ossComponents.vue";
  22. import quotationProjectInformation from "../quotation/sellForQuotation/quotationProjectInformation.vue";
  23. import {
  24. quotationInformationSearchByAnyField,
  25. searchQuotationByQuotationNo
  26. } from "../../../api/quotation/quotationInformation";
  27. import PriceCheckProperties from "../quotation/priceCheckProperties.vue";
  28. import ApprovalInformation from "../changeManagement/approvalInformation.vue";
  29. import {getPriceCheckPropertiesList} from "../../../api/quotation/priceCheckProperties";
  30. import {getApprovalList, getNodeAuthority, checkSuperAdmin} from "../../../api/changeManagement/changeManagement";
  31. import QuoteGroupDetail from "./detail/quoteGroupDetail.vue";
  32. import {submitChange} from "../../../api/quote/quote";
  33. import {queryQuoteDetail} from "../../../api/quote/quoteDetail";
  34. import FilterSearch from "../../common/filterSearch.vue";
  35. import {queryQuoteGroupDetail} from "../../../api/quote/quoteGroupDetail";
  36. import {checkZeroUnitPrice} from "../../../api/quote/quoteDetailBom";
  37. export default {
  38. name: "quote",
  39. components: {
  40. FilterSearch,
  41. QuoteGroupDetail,
  42. ApprovalInformation, PriceCheckProperties,
  43. quotationProjectInformation, OssComponents, CustomerInfo, quotationCustomerContact,
  44. DictDataSelect,
  45. QuoteDetail,
  46. ChooseList,
  47. QuoteTable, QuoteSearch
  48. },
  49. props:{
  50. isMenu:{
  51. type:Boolean,
  52. default:true,
  53. },
  54. projectNo:{
  55. type:String,
  56. },
  57. height:{
  58. type:[Number,String],
  59. default:'35vh'
  60. }
  61. },
  62. menuId:5011,
  63. data(){
  64. return{
  65. exportLoading: false,
  66. total: 0,
  67. no:1,
  68. size: 20,
  69. quote:{
  70. id: null,
  71. site:"",
  72. quoteNo: "",
  73. customerInquiryNo: "",
  74. insideInquiryNo: "",
  75. buNo: "",
  76. buId: null,
  77. versionNo: "",
  78. status:'',
  79. quoteVersionNo: "",
  80. customerNo: "",
  81. customerDesc: "",
  82. projectNo: "",
  83. projectDesc: "",
  84. finalCustomerNo: "",
  85. finalCustomerDesc:"",
  86. currency: "",
  87. quoteDate: "",
  88. quoter: "",
  89. quoterName: "",
  90. purchase: "",
  91. purchaseName: "",
  92. remark: "",
  93. createBy: "",
  94. createDate: "",
  95. updateBy: "",
  96. updateDate: "",
  97. application: "",
  98. annualDemand: "",
  99. costModel: "UFIDA",
  100. markup:0,
  101. chipPrice:'',
  102. },
  103. quoteForm:{
  104. },
  105. saveQuote:{
  106. },
  107. dataList:[],
  108. columns: [
  109. {
  110. userId: this.$store.state.user.name,
  111. functionId: 5011,
  112. serialNumber: '5011Table1QuoteVersionNo',
  113. tableId: '5011Table1',
  114. tableName: '报价信息表',
  115. columnProp: 'quoteVersionNo',
  116. headerAlign: 'center',
  117. align: 'center',
  118. columnLabel: '报价单号',
  119. columnHidden: false,
  120. columnImage: false,
  121. columnSortable: false,
  122. sortLv: 0,
  123. status: true,
  124. fixed: '',
  125. columnWidth: 180
  126. },
  127. {
  128. userId: this.$store.state.user.name,
  129. functionId: 5011,
  130. serialNumber: '5011Table1QuoteVersionNo',
  131. tableId: '5011Table1',
  132. tableName: '报价信息表',
  133. columnProp: 'buDesc',
  134. headerAlign: 'center',
  135. align: 'center',
  136. columnLabel: 'BU',
  137. columnHidden: false,
  138. columnImage: false,
  139. columnSortable: false,
  140. sortLv: 0,
  141. status: true,
  142. fixed: '',
  143. columnWidth: 80
  144. },
  145. {
  146. userId: this.$store.state.user.name,
  147. functionId: 5011,
  148. serialNumber: '5011Table1QuoteVersionNo',
  149. tableId: '5011Table1',
  150. tableName: '报价信息表',
  151. columnProp: 'inquiryCreateBy',
  152. headerAlign: 'center',
  153. align: 'center',
  154. columnLabel: '销售',
  155. columnHidden: false,
  156. columnImage: false,
  157. columnSortable: false,
  158. sortLv: 0,
  159. status: true,
  160. fixed: '',
  161. columnWidth: 80
  162. },
  163. {
  164. userId: this.$store.state.user.name,
  165. functionId: 5011,
  166. serialNumber: '5011Table1CustomerNo',
  167. tableId: '5011Table1',
  168. tableName: '报价信息表',
  169. columnProp: 'customerNo',
  170. headerAlign: 'center',
  171. align: 'center',
  172. columnLabel: '客户编码',
  173. columnHidden: false,
  174. columnImage: false,
  175. columnSortable: false,
  176. sortLv: 0,
  177. status: true,
  178. fixed: '',
  179. columnWidth: 120
  180. },
  181. {
  182. userId: this.$store.state.user.name,
  183. functionId: 5011,
  184. serialNumber: '5011Table1CustomerDesc',
  185. tableId: '5011Table1',
  186. tableName: '报价信息表',
  187. columnProp: 'customerDesc',
  188. headerAlign: 'center',
  189. align: 'left',
  190. columnLabel: '客户名称',
  191. columnHidden: false,
  192. columnImage: false,
  193. columnSortable: false,
  194. sortLv: 0,
  195. status: true,
  196. fixed: '',
  197. columnWidth: 120
  198. },
  199. {
  200. userId: this.$store.state.user.name,
  201. functionId: 5011,
  202. serialNumber: '5011Table1ProjectNo',
  203. tableId: '5011Table1',
  204. tableName: '报价信息表',
  205. columnProp: 'projectNo',
  206. headerAlign: 'center',
  207. align: 'left',
  208. columnLabel: '项目号',
  209. columnHidden: false,
  210. columnImage: false,
  211. columnSortable: false,
  212. sortLv: 0,
  213. status: true,
  214. fixed: '',
  215. columnWidth: 120
  216. },
  217. {
  218. userId: this.$store.state.user.name,
  219. functionId: 5011,
  220. serialNumber: '5011Table1ProjectDesc',
  221. tableId: '5011Table1',
  222. tableName: '报价信息表',
  223. columnProp: 'projectDesc',
  224. headerAlign: 'center',
  225. align: 'left',
  226. columnLabel: '项目名称',
  227. columnHidden: false,
  228. columnImage: false,
  229. columnSortable: false,
  230. sortLv: 0,
  231. status: true,
  232. fixed: '',
  233. columnWidth: 120
  234. },
  235. {
  236. userId: this.$store.state.user.name,
  237. functionId: 5011,
  238. serialNumber: '5011Table1QuoterName',
  239. tableId: '5011Table1',
  240. tableName: '报价信息表',
  241. columnProp: 'quoterName',
  242. headerAlign: 'center',
  243. align: 'left',
  244. columnLabel: '报价专员',
  245. columnHidden: false,
  246. columnImage: false,
  247. columnSortable: false,
  248. sortLv: 0,
  249. status: true,
  250. fixed: '',
  251. columnWidth: 120
  252. },
  253. {
  254. userId: this.$store.state.user.name,
  255. functionId: 5011,
  256. serialNumber: '5011Table1PurchaseName',
  257. tableId: '5011Table1',
  258. tableName: '报价信息表',
  259. columnProp: 'purchaseName',
  260. headerAlign: 'center',
  261. align: 'left',
  262. columnLabel: '采购专员',
  263. columnHidden: false,
  264. columnImage: false,
  265. columnSortable: false,
  266. sortLv: 0,
  267. status: true,
  268. fixed: '',
  269. columnWidth: 120
  270. },
  271. {
  272. userId: this.$store.state.user.name,
  273. functionId: 5011,
  274. serialNumber: '5011Table1Status',
  275. tableId: '5011Table1',
  276. tableName: '报价信息表',
  277. columnProp: 'status',
  278. headerAlign: 'center',
  279. align: 'center',
  280. columnLabel: '状态',
  281. columnHidden: false,
  282. columnImage: false,
  283. columnSortable: false,
  284. sortLv: 0,
  285. status: true,
  286. fixed: '',
  287. columnWidth: 120
  288. },
  289. {
  290. userId: this.$store.state.user.name,
  291. functionId: 5011,
  292. serialNumber: '5011Table1NodeName',
  293. tableId: '5011Table1',
  294. tableName: '报价信息表',
  295. columnProp: 'nodeName',
  296. headerAlign: 'center',
  297. align: 'center',
  298. columnLabel: '当前审批节点',
  299. columnHidden: false,
  300. columnImage: false,
  301. columnSortable: false,
  302. sortLv: 0,
  303. status: true,
  304. fixed: '',
  305. columnWidth: 120
  306. },
  307. {
  308. userId: this.$store.state.user.name,
  309. functionId: 5011,
  310. serialNumber: '5011Table1ApprovalUsername',
  311. tableId: '5011Table1',
  312. tableName: '报价信息表',
  313. columnProp: 'approvalUsername',
  314. headerAlign: 'center',
  315. align: 'center',
  316. columnLabel: '当前审批人',
  317. columnHidden: false,
  318. columnImage: false,
  319. columnSortable: false,
  320. sortLv: 0,
  321. status: true,
  322. fixed: '',
  323. columnWidth: 120
  324. },
  325. {
  326. userId: this.$store.state.user.name,
  327. functionId: 5011,
  328. serialNumber: '5011Table1QuoteDate',
  329. tableId: '5011Table1',
  330. tableName: '报价信息表',
  331. columnProp: 'quoteDate',
  332. headerAlign: 'center',
  333. align: 'center',
  334. columnLabel: '报价日期',
  335. columnHidden: false,
  336. columnImage: false,
  337. columnSortable: false,
  338. sortLv: 0,
  339. status: true,
  340. fixed: '',
  341. columnWidth: 100
  342. },
  343. {
  344. userId: this.$store.state.user.name,
  345. functionId: 5011,
  346. serialNumber: '5011Table1CustomerInquiryNo',
  347. tableId: '5011Table1',
  348. tableName: '报价信息表',
  349. columnProp: 'customerInquiryNo',
  350. headerAlign: 'center',
  351. align: 'center',
  352. columnLabel: '客户询价单号',
  353. columnHidden: false,
  354. columnImage: false,
  355. columnSortable: false,
  356. sortLv: 0,
  357. status: true,
  358. fixed: '',
  359. columnWidth: 120
  360. },
  361. {
  362. userId: this.$store.state.user.name,
  363. functionId: 5011,
  364. serialNumber: '5011Table1InsideInquiryNo',
  365. tableId: '5011Table1',
  366. tableName: '报价信息表',
  367. columnProp: 'insideInquiryNo',
  368. headerAlign: 'center',
  369. align: 'center',
  370. columnLabel: '内部询价单号',
  371. columnHidden: false,
  372. columnImage: false,
  373. columnSortable: false,
  374. sortLv: 0,
  375. status: true,
  376. fixed: '',
  377. columnWidth: 120
  378. },
  379. {
  380. userId: this.$store.state.user.name,
  381. functionId: 5011,
  382. serialNumber: '5011Table1PlmPartNo',
  383. tableId: '5011Table1',
  384. tableName: '报价信息表',
  385. columnProp: 'plmPartNo',
  386. headerAlign: 'center',
  387. align: 'left',
  388. columnLabel: 'PLM物料编码',
  389. columnHidden: false,
  390. columnImage: false,
  391. columnSortable: false,
  392. sortLv: 0,
  393. status: true,
  394. fixed: '',
  395. columnWidth: 120
  396. },
  397. {
  398. userId: this.$store.state.user.name,
  399. functionId: 5011,
  400. serialNumber: '5011Table1IfsPartNo',
  401. tableId: '5011Table1',
  402. tableName: '报价信息表',
  403. columnProp: 'ifsPartNo',
  404. headerAlign: 'center',
  405. align: 'left',
  406. columnLabel: 'IFS物料编码',
  407. columnHidden: false,
  408. columnImage: false,
  409. columnSortable: false,
  410. sortLv: 0,
  411. status: true,
  412. fixed: '',
  413. columnWidth: 120
  414. },
  415. {
  416. userId: this.$store.state.user.name,
  417. functionId: 5011,
  418. serialNumber: '5011Table1PartDesc',
  419. tableId: '5011Table1',
  420. tableName: '报价信息表',
  421. columnProp: 'partDesc',
  422. headerAlign: 'center',
  423. align: 'left',
  424. columnLabel: '物料名称',
  425. columnHidden: false,
  426. columnImage: false,
  427. columnSortable: false,
  428. sortLv: 0,
  429. status: true,
  430. fixed: '',
  431. columnWidth: 200
  432. },
  433. {
  434. userId: this.$store.state.user.name,
  435. functionId: 5011,
  436. serialNumber: '5011Table1CreateBy',
  437. tableId: '5011Table1',
  438. tableName: '报价信息表',
  439. columnProp: 'createBy',
  440. headerAlign: 'center',
  441. align: 'center',
  442. columnLabel: '创建人',
  443. columnHidden: false,
  444. columnImage: false,
  445. columnSortable: false,
  446. sortLv: 0,
  447. status: true,
  448. fixed: '',
  449. columnWidth: 120
  450. },
  451. {
  452. userId: this.$store.state.user.name,
  453. functionId: 5011,
  454. serialNumber: '5011Table1CreateDate',
  455. tableId: '5011Table1',
  456. tableName: '报价信息表',
  457. columnProp: 'createDate',
  458. headerAlign: 'center',
  459. align: 'center',
  460. columnLabel: '创建时间',
  461. columnHidden: false,
  462. columnImage: false,
  463. columnSortable: false,
  464. sortLv: 0,
  465. status: true,
  466. fixed: '',
  467. columnWidth: 130
  468. },
  469. {
  470. userId: this.$store.state.user.name,
  471. functionId: 5011,
  472. serialNumber: '5011Table1UpdateBy',
  473. tableId: '5011Table1',
  474. tableName: '报价信息表',
  475. columnProp: 'updateBy',
  476. headerAlign: 'center',
  477. align: 'center',
  478. columnLabel: '更新人',
  479. columnHidden: false,
  480. columnImage: false,
  481. columnSortable: false,
  482. sortLv: 0,
  483. status: true,
  484. fixed: '',
  485. columnWidth: 120
  486. },
  487. {
  488. userId: this.$store.state.user.name,
  489. functionId: 5011,
  490. serialNumber: '5011Table1UpdateDate',
  491. tableId: '5011Table1',
  492. tableName: '报价信息表',
  493. columnProp: 'updateDate',
  494. headerAlign: 'center',
  495. align: 'center',
  496. columnLabel: '更新时间',
  497. columnHidden: false,
  498. columnImage: false,
  499. columnSortable: false,
  500. sortLv: 0,
  501. status: true,
  502. fixed: '',
  503. columnWidth: 130
  504. },
  505. ],
  506. searchLoading: false,
  507. saveVisible: false,
  508. saveLoading: false,
  509. activeName:'detail2',
  510. // OA审批相关
  511. superAdmin: false,
  512. rejectVisible: false,
  513. rejectOpinion: '',
  514. plmQuoteArr: [], // plm_quote表字段配置(如annual_sales)
  515. plmQuoteDetailArr: [],
  516. defaultQuoteDetailRow: null, // 默认报价行数据
  517. userBuList: [],
  518. saveRules: {
  519. buId:[{required: true, message: '请选择BU', trigger: ['blur','change']}],
  520. customerNo:[{required: true, message: '请输入客户编码', trigger: ['blur','change']}],
  521. customerDesc:[{required: true, message: '请输入客户名称', trigger: ['blur','change']}],
  522. projectNo:[{required: true, message: '请输入项目编码', trigger: ['blur','change']}],
  523. projectDesc:[{required: true, message: '请输入项目名称', trigger: ['blur','change']}],
  524. // currency:[{required: true, message: '请输入币种', trigger: ['blur','change']}],
  525. quoteDate:[{required: true, message: '请选择报价日期', trigger: ['blur','change']}],
  526. quoter:[{required: true, message: '请输入报价专员', trigger: ['blur','change']}],
  527. },
  528. customerVisible:false,
  529. projectVisible:false,
  530. quoterVisible:false,
  531. purchaseVisible:false,
  532. filterVisible:false,
  533. isFilterSearch: false,
  534. filterSearchData: {},
  535. currentQuote:{
  536. },
  537. userVisible:false,
  538. userTitle:'人员信息',
  539. user:{
  540. username:'',
  541. userDisplay:'',
  542. active:'',
  543. buId:null,
  544. roleNo:'',
  545. },
  546. userDataList:[],
  547. tagNo:undefined,
  548. insideInquiryVisible:false,
  549. detailFlag:false,
  550. ossColumns:[
  551. {
  552. userId: this.$store.state.user.name,
  553. functionId: 5011,
  554. serialNumber: '5011Table2FileName',
  555. tableId: '5011Table2',
  556. tableName: '文件信息表',
  557. columnProp: 'fileName',
  558. headerAlign: 'center',
  559. align: 'left',
  560. columnLabel: '文件名称',
  561. columnHidden: false,
  562. columnImage: false,
  563. columnSortable: false,
  564. sortLv: 0,
  565. status: true,
  566. fixed: '',
  567. columnWidth: 140
  568. },
  569. {
  570. userId: this.$store.state.user.name,
  571. functionId: 5011,
  572. serialNumber: '5011Table2FileRemark',
  573. tableId: '5011Table2',
  574. tableName: '文件信息表',
  575. columnProp: 'fileRemark',
  576. headerAlign: 'center',
  577. align: 'left',
  578. columnLabel: '备注',
  579. columnHidden: false,
  580. columnImage: false,
  581. columnSortable: false,
  582. sortLv: 0,
  583. status: true,
  584. fixed: '',
  585. columnWidth: 240
  586. },
  587. {
  588. userId: this.$store.state.user.name,
  589. functionId: 5011,
  590. serialNumber: '5011Table2CreateDate',
  591. tableId: '5011Table2',
  592. tableName: '文件信息表',
  593. columnProp: 'createDate',
  594. headerAlign: 'center',
  595. align: 'center',
  596. columnLabel: '上传时间',
  597. columnHidden: false,
  598. columnImage: false,
  599. columnSortable: false,
  600. sortLv: 0,
  601. status: true,
  602. fixed: '',
  603. columnWidth: 140
  604. },
  605. {
  606. userId: this.$store.state.user.name,
  607. functionId: 5011,
  608. serialNumber: '5011Table2CreatedBy',
  609. tableId: '5011Table2',
  610. tableName: '文件信息表',
  611. columnProp: 'createBy',
  612. headerAlign: 'center',
  613. align: 'center',
  614. columnLabel: '上传人',
  615. columnHidden: false,
  616. columnImage: false,
  617. columnSortable: false,
  618. sortLv: 0,
  619. status: true,
  620. fixed: '',
  621. columnWidth: 140
  622. }
  623. ],
  624. insideInquiry:{
  625. },
  626. insideInquiryList:[],
  627. priceCheckPropertiesList:[],
  628. approvalList:[],
  629. exportData: [],
  630. exportName: '项目报价'+this.dayjs().format('YYYYMMDDHHmmss'),
  631. exportHeader: ["项目报价"],
  632. exportFooter: [],
  633. searchIndex:0,
  634. // OA审批相关
  635. submitLoading: false,
  636. }
  637. },
  638. methods:{
  639. handleSearch(index){
  640. let params = {
  641. ...this.quoteForm,
  642. no: this.no,
  643. size: this.size,
  644. }
  645. // 查询前先清空当前选中的报价,确保子组件能正确响应数据变化
  646. this.currentQuote = {}
  647. this.searchLoading = true
  648. queryQuotePage(params).then(({data})=>{
  649. if (data && data.code === 0){
  650. this.dataList = data.rows
  651. this.total = data.total
  652. // ❌ 性能优化:注释掉N+1查询问题(每个报价都会发起一次额外查询)
  653. // 这会导致:如果有20条报价,就会执行1+20=21次数据库查询
  654. // 解决方案:如果需要显示明细,应该在SQL中一次性JOIN查询,而不是循环查询
  655. // this.loadQuoteDetailInfo()
  656. if (this.dataList[0] !== undefined) {
  657. this.handleSelect(this.dataList[0])
  658. } else {
  659. this.currentQuote = {}
  660. }
  661. // if (index !== undefined){
  662. // this.handleSelect(this.dataList[index])
  663. // }
  664. }else {
  665. this.$message.error(data.msg)
  666. }
  667. this.searchLoading = false
  668. }).catch(error=>{
  669. this.$message.error(error)
  670. this.searchLoading = false
  671. })
  672. this.isFilterSearch = false
  673. },
  674. loadQuoteDetailInfo(){
  675. // 批量加载每个报价的首条明细数据
  676. this.dataList.forEach(quote => {
  677. queryQuoteGroupDetail({quoteId: quote.id}).then(({data}) => {
  678. if (data && data.code === 0 && data.rows && data.rows.length > 0) {
  679. const firstDetail = data.rows[0]
  680. // 使用$set确保响应式更新
  681. this.$set(quote, 'plmPartNo', firstDetail.plmPartNo)
  682. this.$set(quote, 'ifsPartNo', firstDetail.ifsPartNo)
  683. this.$set(quote, 'partDesc', firstDetail.partDesc)
  684. } else {
  685. // 如果没有明细数据,清空这三个字段
  686. this.$set(quote, 'plmPartNo', '')
  687. this.$set(quote, 'ifsPartNo', '')
  688. this.$set(quote, 'partDesc', '')
  689. }
  690. }).catch(() => {
  691. // 忽略错误,只是显示为空
  692. })
  693. })
  694. },
  695. // 刷新指定报价的首条明细信息
  696. handleRefreshQuoteInfo(quoteId){
  697. console.log('刷新报价明细信息, quoteId:', quoteId)
  698. // 直接重新查询当前页数据,这样可以确保数据同步
  699. this.handleSearch()
  700. },
  701. // ========== OA审批相关方法 ==========
  702. // 校验是否为超级管理员
  703. checkSuperAdmin() {
  704. checkSuperAdmin().then(({data}) => {
  705. this.superAdmin = data.superAdmin
  706. })
  707. },
  708. // 判断当前用户是否是审批人
  709. isApprovalUser() {
  710. if (this.superAdmin) return true
  711. if (!this.currentQuote.approvalUsername) return false
  712. return this.currentQuote.approvalUsername.split(';').includes(this.$store.state.user.name)
  713. },
  714. // 获取流程的配置权限
  715. async getNodeAuthority() {
  716. let tempData = {
  717. site: this.currentQuote.site,
  718. stepId: this.currentQuote.stepId,
  719. menuId: this.$route.meta.menuId
  720. }
  721. await getNodeAuthority(tempData).then(({data}) => {
  722. if (data && data.code === 0) {
  723. this.plmQuoteArr = data.rows.plm_quote || []
  724. this.plmQuoteDetailArr = data.rows.plm_quote_detail || []
  725. }
  726. })
  727. },
  728. // 获取默认报价行的条目明细数据
  729. async getDefaultQuoteDetailRow() {
  730. // 1. 先获取第一个报价明细行(QuoteGroupDetail)
  731. let groupParams = {
  732. quoteId: this.currentQuote.id,
  733. site: this.currentQuote.site,
  734. }
  735. const groupRes = await queryQuoteGroupDetail(groupParams)
  736. if (!groupRes.data || groupRes.data.code !== 0 || !groupRes.data.rows || groupRes.data.rows.length === 0) {
  737. this.defaultQuoteDetailRow = null
  738. return
  739. }
  740. const firstGroupDetail = groupRes.data.rows[0]
  741. // 2. 根据 quoteGroupDetailId 和 currentQuoteDetailItemNo 获取对应的条目明细
  742. let detailParams = {
  743. quoteGroupDetailId: firstGroupDetail.id,
  744. site: this.currentQuote.site,
  745. }
  746. const detailRes = await queryQuoteDetail(detailParams)
  747. if (!detailRes.data || detailRes.data.code !== 0 || !detailRes.data.rows || detailRes.data.rows.length === 0) {
  748. this.defaultQuoteDetailRow = null
  749. return
  750. }
  751. // 3. 如果设置了 currentQuoteDetailItemNo,则按 itemNo 匹配,否则取第一条
  752. const currentItemNo = firstGroupDetail.currentQuoteDetailItemNo
  753. if (currentItemNo) {
  754. this.defaultQuoteDetailRow = detailRes.data.rows.find(row => row.itemNo === currentItemNo) || detailRes.data.rows[0]
  755. } else {
  756. this.defaultQuoteDetailRow = detailRes.data.rows[0]
  757. }
  758. },
  759. // 同意提交
  760. agreeSubmit() {
  761. // 校验报价主表的必填字段
  762. if (this.plmQuoteArr && this.plmQuoteArr.length > 0) {
  763. for (let i = 0; i < this.plmQuoteArr.length; i++) {
  764. const field = this.plmQuoteArr[i]
  765. if (field.required === 'Y') {
  766. const fieldValue = this.saveQuote[field.fieldId]
  767. // 统一判断是否有值(包括勾选字段)
  768. if (!fieldValue && fieldValue !== 0) {
  769. this.$message.warning(field.fieldName + '不能为空!')
  770. return
  771. }
  772. }
  773. }
  774. }
  775. // 校验默认报价行的必填字段
  776. if (this.plmQuoteDetailArr && this.plmQuoteDetailArr.length > 0 && this.defaultQuoteDetailRow) {
  777. for (let i = 0; i < this.plmQuoteDetailArr.length; i++) {
  778. const field = this.plmQuoteDetailArr[i]
  779. if (field.required === 'Y' && !this.defaultQuoteDetailRow[field.fieldId] && this.defaultQuoteDetailRow[field.fieldId] !== 0) {
  780. this.$message.warning(field.fieldName + '不能为空!')
  781. return
  782. }
  783. }
  784. }
  785. this.$confirm('是否确认提交?', '提示', {
  786. confirmButtonText: '确定',
  787. cancelButtonText: '取消',
  788. type: 'warning'
  789. }).then(() => {
  790. this.submitLoading = true
  791. // 提交审批流程(后端会在事务中先更新主表,再提交OA)
  792. let params = {
  793. ...this.currentQuote,
  794. annualSales: this.saveQuote.annualSales, // 传递annualSales
  795. userName: this.$store.state.user.name,
  796. nodeConclusion: 'Y',
  797. menuId: this.$route.meta.menuId
  798. }
  799. submitChange(params).then(({data}) => {
  800. if (data && data.code === 0) {
  801. this.$message({message: '操作成功', type: 'success'})
  802. this.saveVisible = false
  803. this.handleSearch()
  804. } else {
  805. this.$alert(data.msg, '错误', { confirmButtonText: '确定' })
  806. }
  807. this.submitLoading = false
  808. }).catch((error) => {
  809. this.$message.error(error)
  810. this.submitLoading = false
  811. })
  812. })
  813. },
  814. // 驳回提交
  815. rejectSubmit() {
  816. // 校验报价主表的必填字段
  817. if (this.plmQuoteArr && this.plmQuoteArr.length > 0) {
  818. for (let i = 0; i < this.plmQuoteArr.length; i++) {
  819. const field = this.plmQuoteArr[i]
  820. if (field.required === 'Y') {
  821. const fieldValue = this.saveQuote[field.fieldId]
  822. // 统一判断是否有值(包括勾选字段)
  823. if (!fieldValue && fieldValue !== 0) {
  824. this.$message.warning(field.fieldName + '不能为空!')
  825. return
  826. }
  827. }
  828. }
  829. }
  830. // 校验默认报价行的必填字段
  831. if (this.plmQuoteDetailArr && this.plmQuoteDetailArr.length > 0 && this.defaultQuoteDetailRow) {
  832. for (let i = 0; i < this.plmQuoteDetailArr.length; i++) {
  833. const field = this.plmQuoteDetailArr[i]
  834. if (field.required === 'Y' && !this.defaultQuoteDetailRow[field.fieldId] && this.defaultQuoteDetailRow[field.fieldId] !== 0) {
  835. this.$message.warning('默认报价行的' + field.fieldName + '不能为空!')
  836. return
  837. }
  838. }
  839. }
  840. this.$confirm('是否确认驳回?', '提示', {
  841. confirmButtonText: '确定',
  842. cancelButtonText: '取消',
  843. type: 'warning'
  844. }).then(() => {
  845. this.submitLoading = true
  846. // 提交驳回流程(后端会在事务中先更新主表,再提交OA)
  847. let params = {
  848. ...this.currentQuote,
  849. annualSales: this.saveQuote.annualSales, // 传递annualSales
  850. userName: this.$store.state.user.name,
  851. nodeConclusion: 'N',
  852. rejectOpinion: this.rejectOpinion,
  853. menuId: this.$route.meta.menuId
  854. }
  855. submitChange(params).then(({data}) => {
  856. if (data && data.code === 0) {
  857. this.$message({message: '操作成功', type: 'success'})
  858. this.rejectVisible = false
  859. this.saveVisible = false
  860. this.handleSearch()
  861. } else {
  862. this.$alert(data.msg, '错误', { confirmButtonText: '确定' })
  863. }
  864. this.submitLoading = false
  865. }).catch((error) => {
  866. this.$message.error(error)
  867. this.submitLoading = false
  868. })
  869. })
  870. },
  871. // 关闭驳回表单
  872. closeRejectForm() {
  873. this.rejectOpinion = ''
  874. this.rejectVisible = false
  875. },
  876. // ========== OA审批相关方法结束 ==========
  877. handleSelect(row){
  878. if (row){
  879. this.currentQuote = {...row}
  880. } else {
  881. this.currentQuote = {}
  882. }
  883. },
  884. async handleSave(row){
  885. this.$nextTick(()=>{
  886. if (this.$refs.saveForm){
  887. this.$refs.saveForm.clearValidate();
  888. }
  889. })
  890. if (row){
  891. // 先更新 currentQuote,确保 getNodeAuthority 能获取到正确的 stepId
  892. this.currentQuote = {...row}
  893. this.saveQuote = {
  894. ...row
  895. }
  896. // 如果是审批中状态,获取权限配置和默认报价行数据
  897. if (row.status === '审批中') {
  898. await this.getNodeAuthority()
  899. await this.getDefaultQuoteDetailRow()
  900. }
  901. }else {
  902. this.saveQuote = {
  903. ...this.quote,
  904. buNo:'*',
  905. site:this.$store.state.user.site
  906. }
  907. this.$nextTick(()=>{
  908. this.saveQuote.buId = this.userBuList.length > 0? this.userBuList[0].id:null;
  909. })
  910. }
  911. this.saveVisible = true
  912. },
  913. handleSizeChange(size){
  914. this.size = size
  915. if ( this.isFilterSearch === false){
  916. this.handleSearch()
  917. } else {
  918. this.searchByAnyField(this.filterSearchData)
  919. }
  920. },
  921. handlePageChange(no) {
  922. this.no = no
  923. if ( this.isFilterSearch === false){
  924. this.handleSearch()
  925. } else {
  926. this.searchByAnyField(this.filterSearchData)
  927. }
  928. },
  929. handleQueryBu(){
  930. let params = {
  931. username: this.$store.state.user.name,
  932. }
  933. // getSiteAndBuByUserName(params).then(({data}) => {
  934. // if (data && data.code === 0) {
  935. // this.userBuList = data.rows
  936. // }else {
  937. // this.$message.warning(data.msg)
  938. // }
  939. // }).catch((error)=>{
  940. // this.$message.error(error)
  941. // })
  942. },
  943. handleSaveOrUpdateQuote(){
  944. this.$refs.saveForm.validate((valid,obj) => {
  945. if (valid){
  946. if (this.saveQuote.id){
  947. this.handleUpdateQuote();
  948. }else {
  949. this.handleSaveQuote();
  950. }
  951. }else {
  952. let i = 1;
  953. for (let key in obj){
  954. this.$message.warning(obj[key][0].message)
  955. if (i === 1){
  956. return
  957. }
  958. i++;
  959. }
  960. }
  961. })
  962. },
  963. handleSaveQuote(){
  964. let params = {
  965. ...this.saveQuote,
  966. status: '草稿',
  967. action: 'Y',
  968. createBy: this.$store.state.user.name,
  969. }
  970. this.saveLoading = true
  971. saveQuote(params).then(({data})=>{
  972. if (data && data.code === 0){
  973. this.saveVisible = false
  974. this.quoteForm.quoteVersionNo = data.quoteVersionNo
  975. this.$message.success(data.msg)
  976. }else {
  977. this.$message.warning(data.msg)
  978. }
  979. this.handleSearch(0);
  980. this.saveLoading = false
  981. }).catch((error)=>{
  982. this.$message.error(error)
  983. this.saveLoading = false
  984. })
  985. },
  986. handleUpdateQuote(){
  987. let params = {
  988. ...this.saveQuote,
  989. updateBy: this.$store.state.user.name,
  990. }
  991. this.saveLoading = true
  992. updateQuote(params).then(({data})=>{
  993. if (data && data.code === 0){
  994. this.saveVisible = false
  995. this.currentQuote = {
  996. ...this.currentQuote
  997. }
  998. this.$message.success(data.msg)
  999. }else {
  1000. this.$message.warning(data.msg)
  1001. }
  1002. this.handleSearch();
  1003. this.saveLoading = false
  1004. }).catch((error)=>{
  1005. this.$message.error(error)
  1006. this.saveLoading = false
  1007. })
  1008. },
  1009. handleRemove(row){
  1010. this.$confirm('确认删除该报价信息吗?', '提示', {
  1011. confirmButtonText: '确定',
  1012. cancelButtonText: '取消',
  1013. type: 'warning'
  1014. }).then(() => {
  1015. this.handleRemoveQuote(row)
  1016. }).catch(() => {
  1017. })
  1018. },
  1019. handleUpdateStatus(row){
  1020. let params = {
  1021. ...row
  1022. }
  1023. updateQuoteStatus(params).then(({data})=>{
  1024. if (data && data.code === 0){
  1025. this.$message.success(data.msg)
  1026. this.handleSearch();
  1027. this.currentQuote = {
  1028. ...row
  1029. }
  1030. }else {
  1031. this.$message.warning(data.msg)
  1032. }
  1033. }).catch((error)=>{
  1034. this.$message.error(error)
  1035. })
  1036. },
  1037. handleQueryById(row){
  1038. this.saveQuote = {
  1039. ...row
  1040. }
  1041. this.detailFlag = true;
  1042. this.saveVisible = true;
  1043. },
  1044. handleRemoveQuote(row){
  1045. let params = {
  1046. id: row.id,
  1047. }
  1048. removeQuote(params).then(({data})=>{
  1049. if (data && data.code === 0){
  1050. this.$message.success(data.msg)
  1051. if (row.id === this.currentQuote.id){
  1052. this.handleSearch(0);
  1053. }else {
  1054. this.handleSearch();
  1055. }
  1056. }else {
  1057. this.$message.warning(data.msg)
  1058. }
  1059. }).catch((error)=>{
  1060. this.$message.error(error)
  1061. })
  1062. },
  1063. customerNoBlur(){
  1064. let params = {
  1065. site:this.$store.state.user.site,
  1066. customerNo:this.saveQuote.customerNo
  1067. }
  1068. queryCustomer(params).then(({data})=>{
  1069. if (data && data.code === 0 ) {
  1070. if (data.rows && data.rows.length === 1){
  1071. this.saveQuote.customerDesc = data.rows[0].customerDesc
  1072. }else {
  1073. this.saveQuote.customerDesc = ''
  1074. }
  1075. }else {
  1076. this.$message.warning(data.msg)
  1077. }
  1078. }).catch((error)=>{
  1079. this.$message.error(error)
  1080. })
  1081. },
  1082. projectNoBlur(){
  1083. let params = {
  1084. site:this.$store.state.user.site,
  1085. customerId:this.saveQuote.customerNo,
  1086. projectId:this.saveQuote.projectNo
  1087. }
  1088. queryProjectByCustomer(params).then(({data})=>{
  1089. if (data && data.code === 0 ){
  1090. if (data.rows && data.rows.length === 1){
  1091. this.saveQuote.projectDesc = data.rows[0].projectName
  1092. this.saveQuote.finalCustomerNo = data.rows[0].finalCustomerId
  1093. this.saveQuote.finalCustomerDesc = data.rows[0].finalCustomerName
  1094. }else {
  1095. this.saveQuote.projectDesc = ''
  1096. this.saveQuote.finalCustomerNo = ''
  1097. this.saveQuote.finalCustomerDesc = ''
  1098. }
  1099. }else {
  1100. this.$message.warning(data.msg)
  1101. }
  1102. }).catch((error)=>{
  1103. this.$message.error(error)
  1104. })
  1105. },
  1106. handleRowClick(row){
  1107. this.currentQuote = {...row}
  1108. },
  1109. userDblClick(row){
  1110. if (this.quoterVisible){
  1111. this.saveQuote.quoter = row.username
  1112. this.quoterVisible = false
  1113. }else if (this.purchaseVisible){
  1114. this.saveQuote.purchase = row.username
  1115. this.purchaseVisible = false
  1116. }
  1117. this.userVisible = false
  1118. },
  1119. handleQuoterClick(){
  1120. this.userTitle = '报价专员'
  1121. this.user.username = this.saveQuote.quoter
  1122. this.user.userDisplay = ''
  1123. this.user.active = ''
  1124. this.user.buId = this.saveQuote.buId
  1125. this.user.roleNo = 'QUOTER'
  1126. this.quoterVisible = true
  1127. this.handleQueryQuoteRoleUser();
  1128. this.userVisible = true
  1129. },
  1130. handlePurchaseClick(){
  1131. this.userTitle = '采购专员'
  1132. this.user.username = this.saveQuote.purchase
  1133. this.user.userDisplay = ''
  1134. this.user.active = ''
  1135. this.user.buId = this.saveQuote.buId
  1136. this.user.roleNo = 'PURCHASE'
  1137. this.purchaseVisible = true
  1138. this.handleQueryQuoteRoleUser();
  1139. this.userVisible = true
  1140. },
  1141. handleQueryQuoteRoleUser(){
  1142. let params = {
  1143. ...this.user,
  1144. }
  1145. this.userDataList = []
  1146. queryQuoteRoleUser(params).then(({data})=>{
  1147. if (data && data.code === 0){
  1148. this.userDataList = data.rows
  1149. }else {
  1150. this.$message.warning(data.msg)
  1151. }
  1152. }).catch((error)=>{
  1153. this.$message.error(error)
  1154. })
  1155. },
  1156. getBaseList(val){
  1157. this.tagNo = val
  1158. this.$nextTick(() => {
  1159. let strVal = ''
  1160. let conSql = ''
  1161. if (val === 102) {
  1162. strVal = this.saveQuote.customerNo
  1163. }
  1164. if (val === 104) {
  1165. strVal = this.saveQuote.projectNo
  1166. conSql = " and customer_id = '" + this.saveQuote.customerNo + "'"
  1167. }
  1168. if (val === 2000) {
  1169. strVal = this.saveQuote.purchase
  1170. conSql = " and b.site = '" + this.$store.state.user.site + "'"
  1171. }
  1172. if (val === 2002) {
  1173. strVal = this.saveQuote.quoter
  1174. conSql = " and b.site = '" + this.$store.state.user.site + "'"
  1175. }
  1176. this.$refs.baseList.init(val, strVal, conSql)
  1177. })
  1178. },
  1179. getBaseData(val){
  1180. switch (this.tagNo){
  1181. case 102:
  1182. if (this.saveQuote.customerNo !== val.Customer_no) {
  1183. this.saveQuote.projectNo = '';
  1184. this.saveQuote.projectDesc = '';
  1185. }
  1186. this.saveQuote.customerNo = val.Customer_no
  1187. this.saveQuote.customerDesc = val.Customer_desc
  1188. break;
  1189. case 104:
  1190. this.saveQuote.projectNo = val.project_id
  1191. this.saveQuote.projectDesc = val.project_name
  1192. break;
  1193. case 2000:
  1194. this.saveQuote.purchase = val.username
  1195. this.saveQuote.purchaseName = val.user_display
  1196. break
  1197. case 2002:
  1198. this.saveQuote.quoter = val.username
  1199. this.saveQuote.quoterName = val.user_display
  1200. break;
  1201. }
  1202. },
  1203. handleQueryByIds(){
  1204. let params = {
  1205. ids:this.$route.params.ids,
  1206. no:this.no,
  1207. size:this.size,
  1208. createBy:this.$store.state.user.name,
  1209. }
  1210. this.searchLoading = true
  1211. queryQuotePage(params).then(({data})=>{
  1212. if (data && data.code === 0){
  1213. this.dataList = data.rows
  1214. this.total = data.total
  1215. if (this.total > 0){
  1216. this.currentQuote = {...this.dataList[0]}
  1217. // 跳转成功后清空路由参数,避免后续刷新时重复触发
  1218. this.$router.replace({name: 'quote-index', params: {}})
  1219. // 提示用户已定位到新建的报价单
  1220. this.$message.success(`已定位到新建的报价单:${this.dataList[0].quoteVersionNo || ''}`)
  1221. }else {
  1222. this.currentQuote = {}
  1223. this.$message.warning('未查询到对应的报价单')
  1224. }
  1225. }else {
  1226. this.$message.error(data.msg)
  1227. }
  1228. this.searchLoading = false
  1229. }).catch(error=>{
  1230. this.$message.error(error)
  1231. this.searchLoading = false
  1232. })
  1233. },
  1234. handleInquiryBlur(){
  1235. let params = {
  1236. site:this.$store.state.user.site,
  1237. quotationNo:this.saveQuote.insideInquiryNo,
  1238. }
  1239. searchQuotationByQuotationNo(params).then(({data}) => {
  1240. if (data && data.code === 0){
  1241. if (data.data.length === 1){
  1242. this.dblclickInsideInquiry(data.data[0])
  1243. }
  1244. }
  1245. })
  1246. },
  1247. handleAgainQuote(row){
  1248. let params = {
  1249. id: row.id,
  1250. createBy: this.$store.state.user.name,
  1251. }
  1252. this.queryLoading = true
  1253. againQuote(params).then(({data}) => {
  1254. if (data && data.code === 0) {
  1255. this.$message.success(data.msg)
  1256. this.handleSearch();
  1257. } else {
  1258. this.$message.warning(data.msg)
  1259. this.queryLoading = false
  1260. }
  1261. }).catch((error) => {
  1262. this.$message.error(error)
  1263. this.queryLoading = false
  1264. })
  1265. },
  1266. clearModalData(field){
  1267. this.$set(this.saveQuote,field,'')
  1268. },
  1269. handleQueryInquiry(){
  1270. this.insideInquiry = {
  1271. site:this.$store.state.user.site,
  1272. quotationNo:this.saveQuote.insideInquiryNo,
  1273. quotationBatchNo:'',
  1274. quotationItemNo:'',
  1275. testPartNo:'',
  1276. projectName:'',
  1277. finalCustomerName:'',
  1278. quoterName:'',
  1279. partName:'',
  1280. quotationStatus:'审批中',
  1281. }
  1282. this.searchInsideInquiry();
  1283. this.insideInquiryVisible = true
  1284. },
  1285. dblclickInsideInquiry(row){
  1286. this.saveQuote.insideInquiryNo = row.quotationNo
  1287. this.saveQuote.customerNo = row.customerNo
  1288. this.saveQuote.customerDesc = row.customerDesc
  1289. this.saveQuote.projectNo = row.projectId
  1290. this.saveQuote.projectDesc = row.projectName
  1291. this.saveQuote.quoter = row.quoter
  1292. this.saveQuote.quoterName = row.quoterName
  1293. this.saveQuote.finalCustomerNo = row.finalCustomerId
  1294. this.saveQuote.finalCustomerDesc = row.finalCustomerName
  1295. this.saveQuote.purchase = row.tracker
  1296. this.saveQuote.purchaseName = row.trackerName
  1297. this.insideInquiryVisible = false
  1298. },
  1299. searchInsideInquiry(){
  1300. searchQuotationByQuotationNo(this.insideInquiry).then(({data}) => {
  1301. if (data && data.code === 0){
  1302. this.insideInquiryList = data.data;
  1303. }
  1304. })
  1305. },
  1306. getPriceCheckProperties() {
  1307. if (!this.currentQuote && !this.currentQuote.insideInquiryNo){
  1308. this.priceCheckPropertiesList = []
  1309. return
  1310. }
  1311. let params = {
  1312. site: this.saveQuote.site,
  1313. quotationNo: this.currentQuote.insideInquiryNo
  1314. }
  1315. getPriceCheckPropertiesList(params).then(({data}) => {
  1316. if (data && data.code === 0) {
  1317. this.priceCheckPropertiesList = data.rows
  1318. } else {
  1319. this.$message.warning(data.msg)
  1320. }
  1321. }).catch((error) => {
  1322. this.$message.error(error)
  1323. })
  1324. },
  1325. // 查询审批信息
  1326. getApprovalList () {
  1327. let tempData = {
  1328. site: this.$store.state.user.site,
  1329. menuId: this.$route.meta.menuId,
  1330. documentNo: this.currentQuote.quoteVersionNo
  1331. }
  1332. getApprovalList(tempData).then(({data}) => {
  1333. if (data && data.code === 0) {
  1334. this.approvalList = data.rows
  1335. } else {
  1336. this.approvalList = []
  1337. }
  1338. })
  1339. }, startDownload() {
  1340. this.exportLoading = true
  1341. },
  1342. finishDownload() {
  1343. this.exportLoading = false
  1344. },
  1345. fields() {
  1346. let json = "{"
  1347. this.columns.forEach((item, index) => {
  1348. if (index === this.columns.length - 1) {
  1349. json += "\"" + item.columnLabel + "\"" + ":" + "\"" + item.columnProp + "\""
  1350. } else {
  1351. json += "\"" + item.columnLabel + "\"" + ":" + "\"" + item.columnProp + "\"" + ","
  1352. }
  1353. })
  1354. json += "}"
  1355. return eval("(" + json + ")")
  1356. },
  1357. createExportData() {
  1358. return this.dataList;
  1359. },
  1360. searchByAnyField(params){
  1361. params.site = this.$store.state.user.site
  1362. params.no = this.no
  1363. params.size = this.size
  1364. params.userId = this.$store.state.user.id.toString()
  1365. queryQuotePageByAnyField(params).then(({data})=>{
  1366. if (data && data.code === 0){
  1367. this.dataList = data.page.list
  1368. this.total = data.page.totalCount
  1369. // 加载每个报价的明细首条数据
  1370. this.loadQuoteDetailInfo()
  1371. }else {
  1372. this.$message.warning(data.msg)
  1373. }
  1374. }).catch((error)=>{
  1375. this.$message.error(error)
  1376. })
  1377. this.filterSearchData = params
  1378. this.isFilterSearch = true
  1379. this.filterVisible = false
  1380. },
  1381. // 下达(首次提交到OA)
  1382. handleEditStatus(row) {
  1383. const submitIssue = () => {
  1384. this.submitLoading = true
  1385. let params = {
  1386. ...row,
  1387. userName: this.$store.state.user.name,
  1388. menuId: this.$route.meta.menuId
  1389. }
  1390. quoteEditStatus(params).then(({data}) => {
  1391. if (data && data.code === 0) {
  1392. this.$message({message: '操作成功', type: 'success'})
  1393. this.handleSearch()
  1394. } else {
  1395. this.$alert(data.msg, '错误', {
  1396. confirmButtonText: '确定'
  1397. })
  1398. }
  1399. }).catch((error) => {
  1400. this.$message.error(error)
  1401. }).finally(() => {
  1402. this.submitLoading = false
  1403. })
  1404. }
  1405. const doIssue = () => {
  1406. this.$confirm('是否确认下达?', '提示', {
  1407. confirmButtonText: '确定',
  1408. cancelButtonText: '取消',
  1409. type: 'warning'
  1410. }).then(() => {
  1411. submitIssue()
  1412. })
  1413. }
  1414. checkZeroUnitPrice({ quoteId: row.id }).then(({ data }) => {
  1415. if (data && data.code === 0 && data.hasZero) {
  1416. this.$confirm('存在单位成本为0的材料,是否继续下达?', '提示', {
  1417. confirmButtonText: '继续下达',
  1418. cancelButtonText: '取消',
  1419. type: 'warning'
  1420. }).then(() => {
  1421. submitIssue()
  1422. }).catch(() => {})
  1423. } else {
  1424. doIssue()
  1425. }
  1426. }).catch(() => {
  1427. doIssue()
  1428. })
  1429. },
  1430. },
  1431. created() {
  1432. this.checkSuperAdmin() // 校验超级管理员
  1433. // 如果是从OA系统跳转来的(tokenLogin),不在created中查询,由activated处理
  1434. if (this.isMenu && this.searchIndex === 0 && this.$route.params.type !== 'tokenLogin'){
  1435. this.quoteForm = {
  1436. ...this.quote,
  1437. site: this.$store.state.user.site,
  1438. createBy: this.$store.state.user.name,
  1439. }
  1440. this.handleQueryBu();// 查询 BU
  1441. this.handleSearch(0);// 查询报价信息
  1442. }
  1443. this.searchIndex++;
  1444. },
  1445. watch:{
  1446. 'quoteForm.customerNo'(newVal, oldVal){
  1447. this.quoteForm.customerNo = newVal.toUpperCase()
  1448. },
  1449. 'quoteForm.projectNo'(newVal, oldVal){
  1450. this.quoteForm.projectNo = newVal.toUpperCase()
  1451. },
  1452. 'quoteForm.quoteNo'(newVal, oldVal){
  1453. this.quoteForm.quoteNo = newVal.toUpperCase()
  1454. },
  1455. 'saveQuote.customerNo'(newVal, oldVal){
  1456. if (newVal){
  1457. this.saveQuote.customerNo = newVal.toUpperCase()
  1458. }else {
  1459. this.saveQuote.customerDesc = ''
  1460. this.saveQuote.projectNo = ''
  1461. this.saveQuote.projectDesc = ''
  1462. }
  1463. },
  1464. 'saveQuote.projectNo'(newVal, oldVal){
  1465. if (newVal){
  1466. this.saveQuote.projectNo = newVal.toUpperCase()
  1467. this.projectNoBlur();
  1468. }else {
  1469. this.saveQuote.projectDesc = ''
  1470. this.saveQuote.finalCustomerNo = ''
  1471. this.saveQuote.finalCustomerDesc = ''
  1472. }
  1473. },
  1474. 'saveQuote.quoter'(newVal, oldVal){
  1475. if (!newVal){
  1476. this.saveQuote.quoterName = ''
  1477. }
  1478. },
  1479. 'saveQuote.purchase'(newVal, oldVal){
  1480. if (!newVal){
  1481. this.saveQuote.purchaseName = ''
  1482. }
  1483. },
  1484. saveVisible(newVal, oldVal){
  1485. if (newVal === false){
  1486. this.detailFlag = false;
  1487. }
  1488. },
  1489. // 'saveQuote.currency'(newVal, oldVal){
  1490. // this.saveQuote.currency = newVal.toUpperCase()
  1491. // },
  1492. 'currentQuote'(newVal, oldVal){
  1493. if (newVal && this.isMenu){
  1494. this.getPriceCheckProperties();
  1495. this.getApprovalList();
  1496. }
  1497. },
  1498. projectNo(newVal, oldVal){
  1499. if (newVal && !this.isMenu){
  1500. this.quoteForm.projectNo = newVal.toUpperCase()
  1501. this.quoteForm.site = this.$store.state.user.site
  1502. this.handleSearch(0);
  1503. }else {
  1504. this.dataList = []
  1505. this.total = 0
  1506. this.no = 1
  1507. }
  1508. },
  1509. },
  1510. activated() {
  1511. if (!this.isMenu){
  1512. return
  1513. }
  1514. // 优先级最高:从待报价清单页面跳转过来,带有新建的报价单ids
  1515. if (this.$route.params.ids){
  1516. this.handleQueryByIds();
  1517. return // 直接返回,避免执行其他逻辑
  1518. }
  1519. // 从OA系统跳转过来
  1520. if (this.$route.params.type === 'tokenLogin') {
  1521. if (this.$route.params.docNo) {
  1522. this.quoteForm = {
  1523. ...this.quote,
  1524. site: this.$store.state.user.site,
  1525. quoteVersionNo: this.$route.params.docNo,
  1526. }
  1527. }
  1528. this.handleSearch(0);
  1529. return
  1530. }
  1531. // 从项目页面跳转过来
  1532. if (this.$route.params.type === 'project'){
  1533. this.quoteForm = {
  1534. ...this.quote,
  1535. site: this.$store.state.user.site,
  1536. quoteVersionNo: this.$route.params.quoteVersionNo,
  1537. }
  1538. this.handleSearch(0);
  1539. return
  1540. }
  1541. }
  1542. }
  1543. </script>
  1544. <template>
  1545. <div>
  1546. <download-excel v-if="!isMenu"
  1547. :fields="fields()"
  1548. :data="exportData"
  1549. type="xls"
  1550. :name="exportName"
  1551. :header="exportHeader"
  1552. :footer="exportFooter"
  1553. :fetch="createExportData"
  1554. :before-generate="startDownload"
  1555. :before-finish="finishDownload"
  1556. worksheet="导出信息"
  1557. :class="['el-button', 'el-button--primary', 'el-button--medium', {'is-loading': exportLoading}]">
  1558. <i v-if="exportLoading" class="el-icon-loading"></i>
  1559. <span>{{ '导出' }}</span>
  1560. </download-excel>
  1561. <quote-search v-if="isMenu" v-model:quote="quoteForm" @filterSearch="filterVisible = true" @search="handleSearch" @save="handleSave"></quote-search>
  1562. <quote-table v-loading="searchLoading"
  1563. :current-row="currentQuote"
  1564. :columns="columns"
  1565. style="margin-top: 5px"
  1566. :is-menu="isMenu"
  1567. @save="handleSave"
  1568. @remove="handleRemove"
  1569. @rowClick="handleRowClick"
  1570. @updateStatus="handleUpdateStatus"
  1571. @queryById="handleQueryById"
  1572. @againQuote="handleAgainQuote"
  1573. @editStatus="handleEditStatus"
  1574. :data-list="dataList"
  1575. :issue-loading="submitLoading"
  1576. :height="height">
  1577. </quote-table>
  1578. <el-pagination @size-change="handleSizeChange"
  1579. @current-change="handlePageChange"
  1580. :current-page="no"
  1581. :page-sizes="[20, 50, 100, 200, 500]"
  1582. :page-size="size"
  1583. :total="total"
  1584. layout="total,sizes, prev, pager, next, jumper">
  1585. </el-pagination>
  1586. <el-tabs v-if="isMenu" v-model="activeName" type="border-card" style="margin-top: 0;" class="customer-tab">
  1587. <el-tab-pane v-if="isAuth('5011:pane:quoteGroupDetail')" label="报价明细" name="detail">
  1588. <quote-group-detail :quote="currentQuote" :auth-flag="false" :height="'28vh'" @refresh-quote-info="handleRefreshQuoteInfo"></quote-group-detail>
  1589. </el-tab-pane>
  1590. <el-tab-pane v-if="isAuth('5011:pane:quoteDetail')" label="条目明细" name="detail2">
  1591. <quote-detail v-if="activeName === 'detail2'" :save-auth="false" :is-export="true" :quote="currentQuote" :auth-flag="false" :height="'30vh'" @refresh-quote-info="handleRefreshQuoteInfo"></quote-detail>
  1592. </el-tab-pane>
  1593. <el-tab-pane v-if="isAuth('5011:pane:quotationProjectInformation')" label="项目信息" name="quotation_project_information">
  1594. <quotation-project-information height="31vh" :quotation-header="currentQuote"></quotation-project-information>
  1595. </el-tab-pane>
  1596. <el-tab-pane v-if="isAuth('5011:pane:customerInfo')" label="客户信息" name="quotation_customer_information">
  1597. <customer-info height="31vh" :project="currentQuote"></customer-info>
  1598. </el-tab-pane>
  1599. <el-tab-pane v-if="isAuth('5011:pane:quotationCustomerContact')" label="客户联系人" name="quotation_customer_contact">
  1600. <quotation-customer-contact height="28vh" :quotation-header="currentQuote"></quotation-customer-contact>
  1601. </el-tab-pane>
  1602. <el-tab-pane v-if="isAuth('5011:pane:ossComponents1')" label="报价-附件信息" name="quote_oss">
  1603. <oss-components
  1604. :save-visible="isAuth('5011:tab6:save')"
  1605. :download-visible="isAuth('5011:tab6:download')"
  1606. :remove-visible="isAuth('5011:tab6:remove')"
  1607. :preview-visible="isAuth('5011:tab6:preview')"
  1608. label="报价单号"
  1609. height="28vh"
  1610. :columns="ossColumns"
  1611. :order-ref1="currentQuote.site?currentQuote.site:''"
  1612. :order-ref2="currentQuote.quoteVersionNo?currentQuote.quoteVersionNo:''">
  1613. </oss-components>
  1614. </el-tab-pane>
  1615. <el-tab-pane v-if="isAuth('5011:pane:priceCheckProperties')" label="询价-基本信息" name="request">
  1616. <price-check-properties ref="tabProperties"
  1617. v-model:data-list="priceCheckPropertiesList"
  1618. height="31vh"></price-check-properties>
  1619. </el-tab-pane>
  1620. <el-tab-pane v-if="isAuth('5011:pane:ossComponents2')" label="询价-附件信息" name="oss">
  1621. <oss-components
  1622. :save-visible="isAuth('102001001:tab6:save')"
  1623. :download-visible="isAuth('102001001:tab6:download')"
  1624. :remove-visible="isAuth('102001001:tab6:remove')"
  1625. :preview-visible="isAuth('102001001:tab6:preview')"
  1626. label="询价单号"
  1627. height="28vh"
  1628. :columns="ossColumns"
  1629. :order-ref1="currentQuote.site"
  1630. :order-ref2="currentQuote.insideInquiryNo?currentQuote.insideInquiryNo.split('-')[0]:''">
  1631. </oss-components>
  1632. </el-tab-pane>
  1633. <!-- 审批信息 -->
  1634. <el-tab-pane v-if="isAuth('5011:pane:approvalInformation')" label="审批信息" name="approvalInformation">
  1635. <approval-information ref="approvalTable" v-model:data-list="approvalList" :height="300"></approval-information>
  1636. </el-tab-pane>
  1637. </el-tabs>
  1638. <el-dialog :title="saveQuote.id? '报价信息:'+ saveQuote.quoteVersionNo : '报价信息'" v-drag :close-on-click-modal="false" :visible.sync="saveVisible" width="500px" >
  1639. <el-form ref="saveForm" :model="saveQuote" :rules="saveRules" label-position="top" label-width="100px">
  1640. <el-row :gutter="10">
  1641. <el-col :span="8">
  1642. <el-form-item label="内部询价单号" prop="insideInquiryNo" :show-message="false">
  1643. <span slot="label" v-if="!detailFlag">
  1644. <a @click="handleQueryInquiry">内部询价单号</a>
  1645. </span>
  1646. <el-input v-model="saveQuote.insideInquiryNo" readonly @change="handleInquiryBlur" :disabled="detailFlag"></el-input>
  1647. </el-form-item>
  1648. </el-col>
  1649. <el-col :span="8">
  1650. <el-form-item label="报价日期" prop="quoteDate" :show-message="false">
  1651. <el-date-picker style="width: 100%" :disabled="detailFlag" v-model="saveQuote.quoteDate" type="date" value-format='yyyy-MM-dd' format='yyyy-MM-dd'></el-date-picker>
  1652. </el-form-item>
  1653. </el-col>
  1654. <el-col :span="8">
  1655. <el-form-item label="客户询价单号" prop="customerInquiryNo" :show-message="false">
  1656. <el-input v-model="saveQuote.customerInquiryNo" :disabled="detailFlag"></el-input>
  1657. </el-form-item>
  1658. </el-col>
  1659. </el-row>
  1660. <el-row :gutter="10">
  1661. <el-col :span="8">
  1662. <el-form-item label="客户编码" prop="customerNo" :show-message="false">
  1663. <span slot="label" v-if="!detailFlag">
  1664. <a @click="getBaseList(102)">客户编码</a>
  1665. </span>
  1666. <el-input v-model="saveQuote.customerNo" :disabled="detailFlag" @change="customerNoBlur"></el-input>
  1667. </el-form-item>
  1668. </el-col>
  1669. <el-col :span="16">
  1670. <el-form-item label="客户描述" prop="customerDesc" :show-message="false">
  1671. <el-input v-model="saveQuote.customerDesc" disabled></el-input>
  1672. </el-form-item>
  1673. </el-col>
  1674. </el-row>
  1675. <el-row :gutter="10">
  1676. <el-col :span="8">
  1677. <el-form-item label="项目号" prop="projectNo" :show-message="false">
  1678. <span slot="label" v-if="saveQuote.customerNo && !detailFlag">
  1679. <a @click="getBaseList(104)">项目号</a>
  1680. </span>
  1681. <el-input v-model="saveQuote.projectNo" :disabled="!saveQuote.customerNo || detailFlag"></el-input>
  1682. </el-form-item>
  1683. </el-col>
  1684. <el-col :span="16">
  1685. <el-form-item label="项目描述" prop="projectDesc" :show-message="false">
  1686. <el-input v-model="saveQuote.projectDesc" disabled></el-input>
  1687. </el-form-item>
  1688. </el-col>
  1689. </el-row>
  1690. <el-row :gutter="10">
  1691. <el-col :span="8">
  1692. <el-form-item label="终端客户编码" prop="finalCustomerNo" :show-message="false">
  1693. <el-input v-model="saveQuote.finalCustomerNo" disabled></el-input>
  1694. </el-form-item>
  1695. </el-col>
  1696. <el-col :span="16">
  1697. <el-form-item label="终端客户描述" prop="finalCustomerDesc" :show-message="false">
  1698. <el-input v-model="saveQuote.finalCustomerDesc" disabled></el-input>
  1699. </el-form-item>
  1700. </el-col>
  1701. </el-row>
  1702. <el-row :gutter="10">
  1703. <el-col :span="8">
  1704. <el-form-item label="报价专员" prop="quoter" :show-message="false">
  1705. <a slot="label" v-if="!detailFlag" @click="getBaseList(2002)">报价专员</a>
  1706. <el-input v-model="saveQuote.quoterName" readonly :disabled="detailFlag">
  1707. <span slot="suffix" v-show="saveQuote.quoter && !detailFlag" @click="clearModalData('quoter')"><i class="el-icon-circle-close" style="margin-left: 5px;cursor: pointer;"></i></span>
  1708. </el-input>
  1709. </el-form-item>
  1710. </el-col>
  1711. <el-col :span="8">
  1712. <el-form-item label="采购专员" prop="purchase" :show-message="false">
  1713. <a slot="label" v-if="!detailFlag" @click="getBaseList(2000)">采购专员</a>
  1714. <el-input v-model="saveQuote.purchaseName" readonly :disabled="detailFlag">
  1715. <span slot="suffix" v-show="saveQuote.purchase && !detailFlag" @click="clearModalData('purchase')"><i class="el-icon-circle-close" style="margin-left: 5px;cursor: pointer;"></i></span>
  1716. </el-input>
  1717. </el-form-item>
  1718. </el-col>
  1719. <el-col :span="8">
  1720. <el-form-item label=" " prop="purchase" :show-message="false">
  1721. <el-checkbox v-model="saveQuote.annualSales" :disabled="detailFlag" true-label="Y" false-label="N">项目年销售额10M</el-checkbox>
  1722. </el-form-item>
  1723. </el-col>
  1724. <el-col :span="24">
  1725. <el-form-item label="备注" prop="remark" class="auto" :show-message="false">
  1726. <el-input v-model="saveQuote.remark" :disabled="detailFlag" :rows="3" type="textarea"></el-input>
  1727. </el-form-item>
  1728. </el-col>
  1729. </el-row>
  1730. </el-form>
  1731. <div slot="footer" class="dialog-footer">
  1732. <el-button type="primary" v-if="!detailFlag" @click="handleSaveOrUpdateQuote"> </el-button>
  1733. <el-button @click="saveVisible = false"> </el-button>
  1734. <template v-if="saveQuote.status === '审批中' && isApprovalUser()">
  1735. <el-button v-if="isAuth('5011:submit')" type="primary" :loading="submitLoading" @click="agreeSubmit">同意</el-button>
  1736. <el-button v-if="isAuth('5011:reject') && currentQuote.isReject === 'Y'" type="primary" @click="rejectVisible = true">驳回</el-button>
  1737. </template>
  1738. </div>
  1739. </el-dialog>
  1740. <!-- 驳回意见弹窗 -->
  1741. <el-dialog title="驳回" top="30vh" :close-on-click-modal="false" v-drag :visible.sync="rejectVisible" width="500px" append-to-body>
  1742. <el-form label-position="top">
  1743. <el-form-item label="驳回意见" class="auto">
  1744. <el-input type="textarea" v-model="rejectOpinion" :rows="3"></el-input>
  1745. </el-form-item>
  1746. </el-form>
  1747. <el-footer style="text-align:center;height: 30px;line-height: 30px;">
  1748. <el-button type="primary" :loading="submitLoading" @click="rejectSubmit">确定</el-button>
  1749. <el-button type="primary" @click="closeRejectForm">取消</el-button>
  1750. </el-footer>
  1751. </el-dialog>
  1752. <el-dialog title="询价申请" v-drag :visible.sync="insideInquiryVisible" width="1000px" modal-append-to-body :close-on-click-modal="false">
  1753. <el-form label-position="top"
  1754. :model="insideInquiry"
  1755. size="mini">
  1756. <el-row :gutter="10">
  1757. <el-col :span="3">
  1758. <el-form-item label="询价单号">
  1759. <el-input v-model="insideInquiry.quotationNo" clearable/>
  1760. </el-form-item>
  1761. </el-col>
  1762. <el-col :span="3">
  1763. <el-form-item label="申请批次号">
  1764. <el-input v-model="insideInquiry.quotationBatchNo" clearable></el-input>
  1765. </el-form-item>
  1766. </el-col>
  1767. <el-col :span="3">
  1768. <el-form-item label="序号">
  1769. <el-input v-model="insideInquiry.quotationItemNo" clearable></el-input>
  1770. </el-form-item>
  1771. </el-col>
  1772. <el-col :span="3">
  1773. <el-form-item label="项目名称">
  1774. <el-input v-model="insideInquiry.projectName" clearable></el-input>
  1775. </el-form-item>
  1776. </el-col>
  1777. <el-col :span="3">
  1778. <el-form-item label="直接客户名称">
  1779. <el-input v-model="insideInquiry.finalCustomerName" clearable></el-input>
  1780. </el-form-item>
  1781. </el-col>
  1782. <el-col :span="3">
  1783. <el-form-item label="报价专员">
  1784. <el-input v-model="insideInquiry.quoterName" clearable></el-input>
  1785. </el-form-item>
  1786. </el-col>
  1787. <el-col :span="3">
  1788. <el-form-item label="状态">
  1789. <el-select v-model="insideInquiry.quotationStatus" style="width:100%">
  1790. <el-option label="全部" value=""></el-option>
  1791. <el-option label="草稿" value="草稿"></el-option>
  1792. <el-option label="审批中" value="审批中"></el-option>
  1793. <el-option label="已完成" value="已完成"></el-option>
  1794. </el-select>
  1795. </el-form-item>
  1796. </el-col>
  1797. <el-col :span="2">
  1798. <el-form-item label=" ">
  1799. <el-button type="primary" style="padding: 3px 12px" @click="searchInsideInquiry">查询</el-button>
  1800. </el-form-item>
  1801. </el-col>
  1802. </el-row>
  1803. </el-form>
  1804. <el-table :data="insideInquiryList" height="300" stripe border @row-dblclick="dblclickInsideInquiry">
  1805. <el-table-column prop="quotationNo" header-align="center" min-width="120" label="询价单号"/>
  1806. <el-table-column prop="quotationBatchNo" header-align="center" label="询价批次号"/>
  1807. <el-table-column width="60" align="center" header-align="center" prop="quotationItemNo" label="询价序号"/>
  1808. <el-table-column prop="projectName" header-align="center" label="项目名称"/>
  1809. <el-table-column prop="quotationStatus" header-align="center" label="状态"/>
  1810. <el-table-column label="报价专员" header-align="center" prop="quoterName"/>
  1811. <el-table-column label="直接客户编码" header-align="center" prop="finalCustomerId"/>
  1812. <el-table-column label="直接客户名称" header-align="center" prop="finalCustomerName"/>
  1813. </el-table>
  1814. <el-footer style="height:30px;margin-top: 20px;text-align:center">
  1815. <el-button type="primary" @click="insideInquiryVisible = false">关闭</el-button>
  1816. </el-footer>
  1817. </el-dialog>
  1818. <choose-list ref="baseList" @getBaseData="getBaseData"></choose-list>
  1819. <filter-search :visible.sync="filterVisible" ref="filter-search" @search="searchByAnyField"></filter-search>
  1820. </div>
  1821. </template>
  1822. <style scoped>
  1823. .auto /deep/ .el-form-item__content{
  1824. height: auto;
  1825. line-height: 1.5;
  1826. }
  1827. </style>