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.

1815 lines
61 KiB

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