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.

614 lines
20 KiB

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
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
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
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
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
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
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
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
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
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
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
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
  1. <script>
  2. import {
  3. queryQuoteDetailBomTree,
  4. queryQuoteDetailBomTreeLevel,
  5. queryQuoteDetailBomTreeAlternative
  6. } from "@/api/quote/quoteDetailBomTree";
  7. import {queryQuoteDetailBom} from "@/api/quote/quoteDetailBom";
  8. import {changeQuoteDetailBomTree} from "../../../../../api/quote/quoteDetailBomTree";
  9. import {updateQuoteDetailBom} from "../../../../../api/quote/quoteDetailBom";
  10. export default {
  11. name: "quoteDetailBom",
  12. props: {
  13. quoteDetail: {
  14. type: Object,
  15. required: true
  16. },
  17. },
  18. model: {
  19. prop: "quoteDetail",
  20. event: "update"
  21. },
  22. data() {
  23. return {
  24. isAllBom: false,
  25. dataList: [],
  26. treeData: [],
  27. columns: [
  28. {
  29. userId: this.$store.state.user.name,
  30. functionId: 5011,
  31. serialNumber: '5011Table4LineSequence',
  32. tableId: "5011Table4",
  33. tableName: "报价材料信息",
  34. columnProp: 'lineSequence',
  35. headerAlign: "center",
  36. align: "center",
  37. columnLabel: '序号',
  38. columnHidden: false,
  39. columnImage: false,
  40. columnSortable: false,
  41. sortLv: 0,
  42. status: true,
  43. fixed: '',
  44. columnWidth: 50,
  45. }, {
  46. userId: this.$store.state.user.name,
  47. functionId: 5011,
  48. serialNumber: '5011Table4PartNo',
  49. tableId: "5011Table4",
  50. tableName: "报价材料信息",
  51. columnProp: 'partNo',
  52. headerAlign: "center",
  53. align: "left",
  54. columnLabel: '产品编码',
  55. columnHidden: false,
  56. columnImage: false,
  57. columnSortable: false,
  58. sortLv: 0,
  59. status: true,
  60. fixed: '',
  61. columnWidth: 120,
  62. }, {
  63. userId: this.$store.state.user.name,
  64. functionId: 5011,
  65. serialNumber: '5011Table4ComponentPart',
  66. tableId: "5011Table4",
  67. tableName: "报价材料信息",
  68. columnProp: 'componentPart',
  69. headerAlign: "center",
  70. align: "left",
  71. columnLabel: '零部件编码',
  72. columnHidden: false,
  73. columnImage: false,
  74. columnSortable: false,
  75. sortLv: 0,
  76. status: true,
  77. fixed: '',
  78. columnWidth: 120,
  79. }, {
  80. userId: this.$store.state.user.name,
  81. functionId: 5011,
  82. serialNumber: '5011Table4PartDesc',
  83. tableId: "5011Table4",
  84. tableName: "报价材料信息",
  85. columnProp: 'partDesc',
  86. headerAlign: "center",
  87. align: "left",
  88. columnLabel: '物料名称',
  89. columnHidden: false,
  90. columnImage: false,
  91. columnSortable: false,
  92. sortLv: 0,
  93. status: true,
  94. fixed: '',
  95. columnWidth: 160,
  96. }, {
  97. userId: this.$store.state.user.name,
  98. functionId: 5011,
  99. serialNumber: '5011Table4QtyPerAssembly',
  100. tableId: "5011Table4",
  101. tableName: "报价材料信息",
  102. columnProp: 'qtyPerAssembly',
  103. headerAlign: "center",
  104. align: "right",
  105. columnLabel: '单位用量',
  106. columnHidden: false,
  107. columnImage: false,
  108. columnSortable: false,
  109. sortLv: 0,
  110. status: true,
  111. fixed: '',
  112. columnWidth: 90,
  113. }, {
  114. userId: this.$store.state.user.name,
  115. functionId: 5011,
  116. serialNumber: '5011Table4ComponentScrap',
  117. tableId: "5011Table4",
  118. tableName: "报价材料信息",
  119. columnProp: 'componentScrap',
  120. headerAlign: "center",
  121. align: "right",
  122. columnLabel: '调机用量',
  123. columnHidden: false,
  124. columnImage: false,
  125. columnSortable: false,
  126. sortLv: 0,
  127. status: true,
  128. fixed: '',
  129. columnWidth: 90,
  130. },
  131. {
  132. userId: this.$store.state.user.name,
  133. functionId: 5011,
  134. serialNumber: '5011Table4ShrinkageFactor',
  135. tableId: "5011Table4",
  136. tableName: "报价材料信息",
  137. columnProp: 'shrinkageFactor',
  138. headerAlign: "center",
  139. align: "right",
  140. columnLabel: '损耗率%',
  141. columnHidden: false,
  142. columnImage: false,
  143. columnSortable: false,
  144. sortLv: 0,
  145. status: true,
  146. fixed: '',
  147. columnWidth: 90,
  148. },
  149. {
  150. userId: this.$store.state.user.name,
  151. functionId: 5011,
  152. serialNumber: '5011Table4YieldRate',
  153. tableId: "5011Table4",
  154. tableName: "报价材料信息",
  155. columnProp: 'yieldRate',
  156. headerAlign: "center",
  157. align: "right",
  158. columnLabel: '良率%',
  159. columnHidden: false,
  160. columnImage: false,
  161. columnSortable: false,
  162. sortLv: 0,
  163. status: true,
  164. fixed: '',
  165. columnWidth: 90,
  166. },
  167. {
  168. userId: this.$store.state.user.name,
  169. functionId: 5011,
  170. serialNumber: '5011Table4AttritionRate',
  171. tableId: "5011Table4",
  172. tableName: "报价材料信息",
  173. columnProp: 'attritionRate',
  174. headerAlign: "center",
  175. align: "right",
  176. columnLabel: '报价成本损耗',
  177. columnHidden: false,
  178. columnImage: false,
  179. columnSortable: false,
  180. sortLv: 0,
  181. status: true,
  182. fixed: '',
  183. columnWidth: 90,
  184. },
  185. {
  186. userId: this.$store.state.user.name,
  187. functionId: 5011,
  188. serialNumber: '5011Table4PrintUnitName',
  189. tableId: "5011Table4",
  190. tableName: "报价材料信息",
  191. columnProp: 'printUnit',
  192. headerAlign: "center",
  193. align: "center",
  194. columnLabel: '单位',
  195. columnHidden: false,
  196. columnImage: false,
  197. columnSortable: false,
  198. sortLv: 0,
  199. status: true,
  200. fixed: '',
  201. columnWidth: 90,
  202. },
  203. {
  204. userId: this.$store.state.user.name,
  205. functionId: 5011,
  206. serialNumber: '5011Table4UnitPrice',
  207. tableId: "5011Table4",
  208. tableName: "报价材料信息",
  209. columnProp: 'unitPrice',
  210. headerAlign: "center",
  211. align: "right",
  212. columnLabel: '单位标准成本',
  213. columnHidden: false,
  214. columnImage: false,
  215. columnSortable: false,
  216. sortLv: 0,
  217. status: true,
  218. fixed: '',
  219. columnWidth: 90,
  220. },
  221. {
  222. userId: this.$store.state.user.name,
  223. functionId: 5011,
  224. serialNumber: '5011Table4ActualPrice',
  225. tableId: "5011Table4",
  226. tableName: "报价材料信息",
  227. columnProp: 'actualPrice',
  228. headerAlign: "center",
  229. align: "right",
  230. columnLabel: '单位报价成本',
  231. columnHidden: false,
  232. columnImage: false,
  233. columnSortable: false,
  234. sortLv: 0,
  235. status: true,
  236. fixed: '',
  237. columnWidth: 90,
  238. },
  239. {
  240. userId: this.$store.state.user.name,
  241. functionId: 5011,
  242. serialNumber: '5011Table4QuoteUnitPrice',
  243. tableId: "5011Table4",
  244. tableName: "报价材料信息",
  245. columnProp: 'quoteUnitPrice',
  246. headerAlign: "center",
  247. align: "right",
  248. columnLabel: '材料标准总成本',
  249. columnHidden: false,
  250. columnImage: false,
  251. columnSortable: false,
  252. sortLv: 0,
  253. status: true,
  254. fixed: 'right',
  255. columnWidth: 100,
  256. },
  257. {
  258. userId: this.$store.state.user.name,
  259. functionId: 5011,
  260. serialNumber: '5011Table4ActualQuotePrice',
  261. tableId: "5011Table4",
  262. tableName: "报价材料信息",
  263. columnProp: 'actualQuotePrice',
  264. headerAlign: "center",
  265. align: "right",
  266. columnLabel: '材料报价总成本',
  267. columnHidden: false,
  268. columnImage: false,
  269. columnSortable: false,
  270. sortLv: 0,
  271. status: true,
  272. fixed: 'right',
  273. columnWidth: 100,
  274. },
  275. ],
  276. props: {
  277. children: 'list',
  278. label: (data, node) => {
  279. return `${data.partNo}-${data.engChgLevel}-${data.alternativeNo}-${data.bomType}`;
  280. },
  281. },
  282. queryLoading: false,
  283. queryTreeLoading: false,
  284. versionVisible: false,
  285. versionList: [],
  286. alternativeList: [],
  287. bomEngChgLevel: {
  288. partNo: '',
  289. bomType: '',
  290. buNo: '',
  291. site: '',
  292. engChgLevel: null,
  293. },
  294. quoteDetailBom:{},
  295. quoteDetailBomVisible:false,
  296. preValue:undefined,
  297. }
  298. },
  299. methods: {
  300. handleQueryQuoteDetailBomTree() {
  301. let params = {
  302. id: this.quoteDetail.id,
  303. }
  304. this.queryTreeLoading = true;
  305. queryQuoteDetailBomTree(params).then(({data}) => {
  306. if (data && data.code === 0) {
  307. this.treeData = data.rows;
  308. if (this.treeData.length > 0) {
  309. this.$nextTick(() => {
  310. this.$refs.tree.setCurrentKey(this.treeData[0].id);
  311. this.handleQueryQuoteDetailBom();
  312. })
  313. }
  314. this.queryTreeLoading = false;
  315. } else {
  316. this.$message.warning(data.msg);
  317. this.queryTreeLoading = false;
  318. }
  319. }).catch((error) => {
  320. this.$message.error(error);
  321. })
  322. },
  323. nodeClick(data) {
  324. this.handleQueryQuoteDetailBom();
  325. },
  326. handleQueryQuoteDetailBom() {
  327. let params = {
  328. quoteDetailId: this.quoteDetail.id,
  329. treeId: this.$refs.tree.getCurrentKey(),
  330. allTree: this.isAllBom,
  331. }
  332. this.queryLoading = true;
  333. queryQuoteDetailBom(params).then(({data}) => {
  334. if (data && data.code === 0) {
  335. this.dataList = data.rows;
  336. } else {
  337. this.$message.warning(data.msg);
  338. }
  339. this.queryLoading = false;
  340. }).catch((error) => {
  341. this.$message.error(error);
  342. this.queryLoading = false;
  343. })
  344. },
  345. handleCheckedVersion() {
  346. let node = this.$refs.tree.getCurrentNode();
  347. if (node) {
  348. this.bomEngChgLevel = {
  349. partNo: node.partNo,
  350. bomType: node.bomType,
  351. buNo: node.buNo,
  352. site: node.site,
  353. engChgLevel: node.engChgLevel,
  354. alternativeNo: node.alternativeNo,
  355. }
  356. }
  357. this.handleQueryQuoteDetailBomTreeVersion();
  358. this.versionVisible = true
  359. },
  360. handleQueryQuoteDetailBomTreeVersion() {
  361. let params = {
  362. ...this.bomEngChgLevel,
  363. engChgLevel: '',
  364. alternativeNo: '',
  365. }
  366. queryQuoteDetailBomTreeLevel(params).then(({data}) => {
  367. if (data && data.code === 0) {
  368. this.versionList = data.rows;
  369. this.handleQueryQuoteDetailBomAlternative();
  370. } else {
  371. this.$message.warning(data.msg);
  372. }
  373. }).catch((error) => {
  374. this.$message.error(error);
  375. })
  376. },
  377. levelRowStyle({row}) {
  378. if (row.engChgLevel === this.bomEngChgLevel.engChgLevel) {
  379. return {'background-color': '#E8F7F6'};
  380. }
  381. },
  382. alternativeRowStyle({row}) {
  383. if (row.engChgLevel === this.bomEngChgLevel.engChgLevel && row.alternativeNo === this.bomEngChgLevel.alternativeNo) {
  384. return {'background-color': '#E8F7F6'};
  385. }
  386. },
  387. levelRowClick(row) {
  388. this.bomEngChgLevel.partNo = row.partNo;
  389. this.bomEngChgLevel.buNo = row.buNo;
  390. this.bomEngChgLevel.site = row.site;
  391. this.bomEngChgLevel.engChgLevel = row.engChgLevel;
  392. this.bomEngChgLevel.bomType = row.bomType;
  393. this.handleQueryQuoteDetailBomAlternative();
  394. },
  395. handleQueryQuoteDetailBomAlternative() {
  396. let params = {
  397. ...this.bomEngChgLevel
  398. }
  399. queryQuoteDetailBomTreeAlternative(params).then(({data}) => {
  400. if (data && data.code === 0) {
  401. this.alternativeList = data.rows;
  402. } else {
  403. this.$message.warning(data.msg);
  404. }
  405. }).catch((error) => {
  406. this.$message.error(error);
  407. })
  408. },
  409. handleChangeVersion(row) {
  410. let node = this.$refs.tree.getCurrentNode();
  411. let params = {
  412. partNo: row.partNo,
  413. bomType: row.bomType,
  414. buNo: row.buNo,
  415. site: row.site,
  416. engChgLevel: row.engChgLevel,
  417. alternativeNo: row.alternativeNo,
  418. createBy: this.$store.state.user.name,
  419. quoteId: this.quoteDetail.quoteId,
  420. quoteDetailId: this.quoteDetail.id,
  421. quoteNo: this.quoteDetail.quoteNo,
  422. quoteDetailItemNo: this.quoteDetail.itemNo,
  423. versionNo:this.quoteDetail.versionNo,
  424. }
  425. if (node) {
  426. params.id = node.id
  427. params.partNo = node.partNo
  428. params.bomType = node.bomType
  429. params.buNo = node.buNo
  430. params.site = node.site
  431. }
  432. changeQuoteDetailBomTree(params).then(({data}) => {
  433. if (data && data.code === 0) {
  434. this.$message.success(data.msg);
  435. this.versionVisible = false;
  436. this.handleQueryQuoteDetailBomTree();
  437. } else {
  438. this.$message.warning(data.msg);
  439. }
  440. }).catch((error) => {
  441. this.$message.error(error);
  442. })
  443. },
  444. handleJumpToBom(row){
  445. if (this.$router.resolve('part-bomManagement').resolved.name === '404') {
  446. this.$alert('权限不足,访问失败', '警告', {confirmButtonText: '确定',});
  447. } else {
  448. this.$emit('close')
  449. let params = {
  450. name: "part-bomManagement",
  451. params: {
  452. type:'quote',
  453. partNo:row.partNo,
  454. bomType:row.bomType,
  455. engChgLevel:row.engChgLevel,
  456. alternativeNo:row.alternativeNo,
  457. }
  458. }
  459. this.$router.push(params)
  460. }
  461. },
  462. handleUpdateQuoteDetailBom(row){
  463. if (row.attritionRate === undefined || row.attritionRate === null || row.attritionRate <= 0) {
  464. this.$message.warning('报价成本损耗不能为空或小于等于0');
  465. return;
  466. }
  467. let params = {
  468. id:row.id,
  469. attritionRate:row.attritionRate,
  470. }
  471. updateQuoteDetailBom(params).then(({data})=>{
  472. if (data && data.code === 0){
  473. this.$message.success(data.msg);
  474. this.quoteDetailBomVisible = false;
  475. this.handleQueryQuoteDetailBom();
  476. }else{
  477. this.$message.warning(data.msg);
  478. }
  479. }).catch((error)=>{
  480. this.$message.error(error);
  481. })
  482. },
  483. handleClickUpdate(row,column,cell,event){
  484. if (column.label === '报价成本损耗'){
  485. this.quoteDetailBom = {
  486. ...row,
  487. }
  488. this.preValue = row.attritionRate;
  489. this.quoteDetailBomVisible = true;
  490. }
  491. },
  492. handleBlur(row){
  493. if (row.attritionRate === this.preValue) {
  494. this.quoteDetailBomVisible = false;
  495. this.preValue = undefined
  496. }
  497. }
  498. },
  499. created() {
  500. if (this.quoteDetail && this.quoteDetail.id) {
  501. this.handleQueryQuoteDetailBomTree();
  502. }
  503. },
  504. watch: {
  505. 'quoteDetail.id'(newVal, oldVal) {
  506. this.handleQueryQuoteDetailBomTree();
  507. },
  508. isAllBom(newVal, oldVal) {
  509. this.handleQueryQuoteDetailBom();
  510. },
  511. }
  512. }
  513. </script>
  514. <template>
  515. <div>
  516. <div style="margin-bottom: 10px">
  517. <el-link style="margin-right: 20px;cursor: pointer" @click="handleCheckedVersion" v-if="quoteDetail.status === '草稿'">切换版本</el-link>
  518. <el-checkbox v-model="isAllBom">全级BOM结构</el-checkbox>
  519. </div>
  520. <el-container>
  521. <el-aside width="300px" v-loading="queryTreeLoading">
  522. <el-tree
  523. :data="treeData"
  524. :props="props"
  525. :default-expand-all="true"
  526. :expand-on-click-node="false"
  527. node-key="id"
  528. highlight-current
  529. @node-click="nodeClick" ref="tree">
  530. </el-tree>
  531. </el-aside>
  532. <el-main style="padding: 0" class="rq">
  533. <el-table :data="dataList" v-loading="queryLoading" border
  534. @cell-dblclick="handleClickUpdate"
  535. style="width: 100%" :height="420">
  536. <!-- <el-table-column label="操作" align="center">-->
  537. <!-- <template slot-scope="scope">-->
  538. <!-- <a @click="handleClickUpdate(scope.row)">编辑</a>-->
  539. <!-- </template>-->
  540. <!-- </el-table-column>-->
  541. <el-table-column
  542. v-for="(item,index) in columns" :key="index"
  543. :sortable="item.columnSortable"
  544. :prop="item.columnProp"
  545. :header-align="item.headerAlign"
  546. :show-overflow-tooltip="item.showOverflowTooltip"
  547. :align="item.align"
  548. :fixed="item.fixed===''?false:item.fixed"
  549. :min-width="item.columnWidth"
  550. :label="item.columnLabel">
  551. <template slot-scope="scope">
  552. <template v-if="item.columnProp === 'partNo'">
  553. <el-link @click="handleJumpToBom(scope.row)">{{ scope.row[item.columnProp] }}</el-link>
  554. </template>
  555. <template v-else-if="item.columnProp === 'attritionRate' && quoteDetailBomVisible && scope.row.id === quoteDetailBom.id">
  556. <el-input-number v-model="scope.row.attritionRate" @blur="handleBlur(scope.row)" @change="handleUpdateQuoteDetailBom(scope.row)" style="width: 100%" :controls="false" :min="0"></el-input-number>
  557. </template>
  558. <template v-else>
  559. <span v-if="!item.columnHidden">{{ scope.row[item.columnProp] }}</span>
  560. <span v-if="item.columnImage"><img :src="scope.row[item.columnProp]" style="width: 100px; height: 80px"/></span>
  561. </template>
  562. </template>
  563. </el-table-column>
  564. </el-table>
  565. </el-main>
  566. </el-container>
  567. <el-dialog title="BOM版本切换" :visible.sync="versionVisible" append-to-body :close-on-click-modal="false" v-drag
  568. width="900px">
  569. <el-table :data="versionList" :row-style="levelRowStyle" @row-click="levelRowClick" ref="versionTable"
  570. style="width: 100%" border :height="240">
  571. <el-table-column label="物料编码" prop="partNo" header-align="center" align="center" show-overflow-tooltip
  572. min-width="140"/>
  573. <el-table-column label="物料描述" prop="partDesc" header-align="center" align="left" show-overflow-tooltip
  574. min-width="200"/>
  575. <el-table-column label="版本" prop="engChgLevel" header-align="center" align="center" show-overflow-tooltip
  576. min-width="60"/>
  577. <el-table-column label="类型" prop="bomType" header-align="center" align="center" show-overflow-tooltip
  578. min-width="100"/>
  579. </el-table>
  580. <el-table :data="alternativeList" :row-style="alternativeRowStyle" ref="versionTable"
  581. style="width: 100%;margin-top: 20px" border :height="240">
  582. <el-table-column label="物料编码" prop="partNo" header-align="center" align="center" show-overflow-tooltip
  583. min-width="140"/>
  584. <el-table-column label="物料描述" prop="partDesc" header-align="center" align="left" show-overflow-tooltip
  585. min-width="200"/>
  586. <el-table-column label="版本" prop="engChgLevel" header-align="center" align="center" show-overflow-tooltip
  587. min-width="60"/>
  588. <el-table-column label="替代编码" prop="alternativeNo" header-align="center" align="left" show-overflow-tooltip
  589. min-width="60"/>
  590. <el-table-column label="类型" prop="bomType" header-align="center" align="center" show-overflow-tooltip
  591. min-width="100"/>
  592. <el-table-column label="操作" header-align="center" align="center" min-width="100">
  593. <template slot-scope="scope">
  594. <a @click="handleChangeVersion(scope.row)">选择</a>
  595. </template>
  596. </el-table-column>
  597. </el-table>
  598. </el-dialog>
  599. <!-- <el-dialog title="BOM信息" :visible.sync="quoteDetailBomVisible" append-to-body :close-on-click-modal="false" width="450px" v-drag>-->
  600. <!-- </el-dialog>-->
  601. </div>
  602. </template>
  603. <style scoped>
  604. </style>