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.

597 lines
20 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. <script>
  2. import {
  3. getBomTreeStructure, searchQuoteBOMAllCost, searchQuoteBOMAlternativeNo,
  4. searchQuoteBomList,
  5. searchQuoteBOMVersion,
  6. updateQuoteBomList
  7. } from '../../../../../api/quotation/quoteOfBom'
  8. import {Decimal} from "decimal.js";
  9. import fi from "element-ui/src/locale/lang/fi";
  10. export default {
  11. name:'billOfMateriel',
  12. props:{
  13. detail:{
  14. type:Object,
  15. request:true,
  16. },
  17. height:{
  18. type:Number,
  19. default:400,
  20. },
  21. updateTree:{
  22. type:Number,
  23. default: 0,
  24. },
  25. loadingStatus:{
  26. type:Boolean,
  27. default:false,
  28. },
  29. totalCost:{
  30. type:Number,
  31. default:-1,
  32. },
  33. allSearchFlag:{
  34. type:Boolean,
  35. default:false,
  36. },
  37. },
  38. computed:{
  39. BOMAllSearchFlag:{
  40. get(){
  41. return this.allSearchFlag;
  42. },
  43. set(val){
  44. this.$emit("update:allSearchFlag",val)
  45. }
  46. }
  47. },
  48. watch:{
  49. BOMAllSearchFlag(newVal,oldVal){
  50. if (newVal === true){
  51. this.$nextTick(()=>{
  52. this.$refs.tree.setCurrentKey(`${this.selectBom[0]}-${this.selectBom[1]}-${this.selectBom[2]}-${this.selectBom[3]}-${this.selectBom[4]}-${this.selectBom[5]}`)
  53. })
  54. }
  55. this.searchQuoteBomList()
  56. }
  57. },
  58. data(){
  59. return{
  60. BomVersion:{},
  61. BOMVersionList:[],
  62. handoffVersion:false,
  63. treeLoading:false,
  64. bomTreeStructure:[],
  65. bomProps:{
  66. label:'label',
  67. value:'value',
  68. children:'list'
  69. },
  70. dataListLoading:false,
  71. bomDetailList:[],
  72. selectBom:[],
  73. copyBom:[],
  74. columnDetailList:[
  75. {
  76. userId: this.$store.state.user.name,
  77. functionId: 102003,
  78. serialNumber: '102003Table4LineSequence',
  79. tableId: "102003Table4",
  80. tableName: "报价材料信息",
  81. columnProp: 'lineSequence',
  82. headerAlign: "center",
  83. align: "center",
  84. columnLabel: '序号',
  85. columnHidden: false,
  86. columnImage: false,
  87. columnSortable: false,
  88. sortLv: 0,
  89. status: true,
  90. fixed: '',
  91. columnWidth: 50,
  92. },{
  93. userId: this.$store.state.user.name,
  94. functionId: 102003,
  95. serialNumber: '102003Table4PartNo',
  96. tableId: "102003Table4",
  97. tableName: "报价材料信息",
  98. columnProp: 'partNo',
  99. headerAlign: "center",
  100. align: "center",
  101. columnLabel: '产品编码',
  102. columnHidden: false,
  103. columnImage: false,
  104. columnSortable: false,
  105. sortLv: 0,
  106. status: true,
  107. fixed: '',
  108. columnWidth: 120,
  109. },{
  110. userId: this.$store.state.user.name,
  111. functionId: 102003,
  112. serialNumber: '102003Table4ComponentPart',
  113. tableId: "102003Table4",
  114. tableName: "报价材料信息",
  115. columnProp: 'componentPart',
  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: 120,
  126. },{
  127. userId: this.$store.state.user.name,
  128. functionId: 102003,
  129. serialNumber: '102003Table4ComponentPartDesc',
  130. tableId: "102003Table4",
  131. tableName: "报价材料信息",
  132. columnProp: 'componentPartDesc',
  133. headerAlign: "center",
  134. align: "left",
  135. columnLabel: '物料名称',
  136. columnHidden: false,
  137. columnImage: false,
  138. columnSortable: false,
  139. sortLv: 0,
  140. status: true,
  141. fixed: '',
  142. columnWidth: 140,
  143. },{
  144. userId: this.$store.state.user.name,
  145. functionId: 102003,
  146. serialNumber: '102003Table4QtyPerAssembly',
  147. tableId: "102003Table4",
  148. tableName: "报价材料信息",
  149. columnProp: 'qtyPerAssembly',
  150. headerAlign: "center",
  151. align: "right",
  152. columnLabel: '单位用量',
  153. columnHidden: false,
  154. columnImage: false,
  155. columnSortable: false,
  156. sortLv: 0,
  157. status: true,
  158. fixed: '',
  159. columnWidth: 90,
  160. },{
  161. userId: this.$store.state.user.name,
  162. functionId: 102003,
  163. serialNumber: '102003Table4ComponentScrap',
  164. tableId: "102003Table4",
  165. tableName: "报价材料信息",
  166. columnProp: 'componentScrap',
  167. headerAlign: "center",
  168. align: "right",
  169. columnLabel: '调机用量',
  170. columnHidden: false,
  171. columnImage: false,
  172. columnSortable: false,
  173. sortLv: 0,
  174. status: true,
  175. fixed: '',
  176. columnWidth: 90,
  177. },{
  178. userId: this.$store.state.user.name,
  179. functionId: 102003,
  180. serialNumber: '102003Table4ShrinkageFactor',
  181. tableId: "102003Table4",
  182. tableName: "报价材料信息",
  183. columnProp: 'shrinkageFactor',
  184. headerAlign: "center",
  185. align: "right",
  186. columnLabel: '损耗率%',
  187. columnHidden: false,
  188. columnImage: false,
  189. columnSortable: false,
  190. sortLv: 0,
  191. status: true,
  192. fixed: '',
  193. columnWidth: 90,
  194. },{
  195. userId: this.$store.state.user.name,
  196. functionId: 102003,
  197. serialNumber: '102003Table4PrintUnitName',
  198. tableId: "102003Table4",
  199. tableName: "报价材料信息",
  200. columnProp: 'printUnit',
  201. headerAlign: "center",
  202. align: "center",
  203. columnLabel: '单位',
  204. columnHidden: false,
  205. columnImage: false,
  206. columnSortable: false,
  207. sortLv: 0,
  208. status: true,
  209. fixed: '',
  210. columnWidth: 90,
  211. },{
  212. userId: this.$store.state.user.name,
  213. functionId: 102003,
  214. serialNumber: '102003Table4NoteText',
  215. tableId: "102003Table4",
  216. tableName: "报价材料信息",
  217. columnProp: 'noteText',
  218. headerAlign: "center",
  219. align: "left",
  220. columnLabel: '备注',
  221. columnHidden: false,
  222. columnImage: false,
  223. columnSortable: false,
  224. sortLv: 0,
  225. status: true,
  226. fixed: '',
  227. columnWidth: 90,
  228. },{
  229. userId: this.$store.state.user.name,
  230. functionId: 102003,
  231. serialNumber: '102003Table4UnitCost',
  232. tableId: "102003Table4",
  233. tableName: "报价材料信息",
  234. columnProp: 'unitCost',
  235. headerAlign: "center",
  236. align: "right",
  237. columnLabel: '单位成本',
  238. columnHidden: false,
  239. columnImage: false,
  240. columnSortable: false,
  241. sortLv: 0,
  242. status: true,
  243. fixed: '',
  244. columnWidth: 90,
  245. },{
  246. userId: this.$store.state.user.name,
  247. functionId: 102003,
  248. serialNumber: '102003Table4QuoteUnitCost',
  249. tableId: "102003Table4",
  250. tableName: "报价材料信息",
  251. columnProp: 'quoteUnitCost',
  252. headerAlign: "center",
  253. align: "right",
  254. columnLabel: '单位报价成本',
  255. columnHidden: false,
  256. columnImage: false,
  257. columnSortable: false,
  258. sortLv: 0,
  259. status: true,
  260. fixed: 'right',
  261. columnWidth: 90,
  262. },
  263. ],
  264. versionData:{},
  265. BOMAlternativeList:[],
  266. }
  267. },
  268. methods:{
  269. getInventoryPartBom(){
  270. // 请求后端 获得树结构菜单
  271. let params = {
  272. site:this.detail.site,
  273. partId:0,
  274. quoteDetailId:this.detail.quotationDetailId
  275. }
  276. this.treeLoading = true
  277. getBomTreeStructure(params).then(({data})=>{
  278. if (data && data.code === 0){
  279. this.bomTreeStructure = data.rows;
  280. this.$nextTick(()=>{
  281. this.$refs.tree.setCurrentKey(`${this.selectBom[0]}-${this.selectBom[1]}-${this.selectBom[2]}-${this.selectBom[3]}-${this.selectBom[4]}-${this.selectBom[5]}`)
  282. })
  283. this.searchQuoteBomList();
  284. }else {
  285. this.$message.warning(data.msg)
  286. }
  287. this.treeLoading = false;
  288. // this.$emit("update:loadingStatus",this.treeLoading)
  289. }).catch((error)=>{
  290. this.$message.error(error)
  291. this.treeLoading = false;
  292. // this.$emit("update:loadingStatus",this.treeLoading)
  293. })
  294. },
  295. changeSelect(val){
  296. if (this.selectBom.length === 0){
  297. this.updateQuoteBomList();
  298. return
  299. }
  300. this.$confirm('此操作将更换材料信息, 是否继续?', '提示', {
  301. confirmButtonText: '确定',
  302. cancelButtonText: '取消',
  303. type: 'warning'
  304. }).then(() => {
  305. this.updateQuoteBomList();
  306. }).catch(() => {
  307. this.selectBom = JSON.parse(JSON.stringify(this.copyBom))
  308. this.$nextTick(()=>{
  309. this.$refs.tree.setCurrentKey(`${this.selectBom[0]}-${this.selectBom[1]}-${this.selectBom[2]}-${this.selectBom[3]}-${this.selectBom[4]}-${this.selectBom[5]}`)
  310. })
  311. });
  312. },
  313. updateQuoteBomList(){
  314. let params = {
  315. site:this.$store.state.user.site,
  316. testPartNo: this.detail.productNo,
  317. version:this.selectBom[0],
  318. bomType:this.selectBom[2],
  319. alternativeNo:this.selectBom[1],
  320. quoteDetailId:this.detail.quotationDetailId
  321. }
  322. updateQuoteBomList(params).then(({data})=>{
  323. if (data && data.code === 0){
  324. this.$message.success(data.msg)
  325. this.searchQuoteBomList();
  326. }else {
  327. this.$message.warning(data.msg)
  328. }
  329. }).catch((error)=>{
  330. this.$message.error(error)
  331. })
  332. },
  333. setSelectBom(val){
  334. if (val.length === 0){
  335. this.getInventoryPartBom();
  336. return
  337. }
  338. this.selectBom = val
  339. this.getInventoryPartBom();
  340. },
  341. searchQuoteBomList(){
  342. let params = {
  343. site:this.$store.state.user.site,
  344. partNo: this.selectBom[3],
  345. version:this.selectBom[0],
  346. bomType:this.selectBom[2],
  347. alternativeNo:this.selectBom[1],
  348. id:this.selectBom[4],
  349. quoteDetailId:this.detail.quotationDetailId
  350. }
  351. this.searchQuoteBomListPost(params)
  352. },
  353. searchQuoteBomListPost(params){
  354. this.dataListLoading = true;
  355. if (this.BOMAllSearchFlag){
  356. searchQuoteBomList(params).then(({data})=>{
  357. if (data && data.code === 0){
  358. this.bomDetailList = data.rows
  359. this.computedQuoteBomCost();
  360. }else {
  361. this.$message.warning(data.msg)
  362. }
  363. this.dataListLoading = false;
  364. // this.$emit("update:loadingStatus",this.dataListLoading)
  365. }).catch((error)=>{
  366. this.dataListLoading = false;
  367. // this.$emit("update:loadingStatus",this.dataListLoading)
  368. this.$message.error(error)
  369. })
  370. }else {
  371. // this.dataListLoading = false;
  372. searchQuoteBOMAllCost(params).then(({data})=>{
  373. if (data && data.code === 0){
  374. this.bomDetailList = data.rows
  375. this.computedQuoteBomCost();
  376. }else {
  377. this.$message.warning(data.msg)
  378. }
  379. this.dataListLoading = false;
  380. // this.$emit("update:loadingStatus",this.dataListLoading)
  381. }).catch((error)=>{
  382. this.$message.error(error)
  383. this.dataListLoading = false;
  384. // this.$emit("update:loadingStatus",this.dataListLoading)
  385. })
  386. }
  387. },
  388. computedQuoteBomCost(){
  389. this.$emit("update:loadingStatus",true)
  390. for (let i = 0; i < this.bomDetailList.length; i++) {
  391. let bomDetail = this.bomDetailList[i]
  392. // 单位成本
  393. let unitCost = new Decimal(bomDetail.unitCost);
  394. // 调机用量
  395. let componentScrap = new Decimal(bomDetail.componentScrap)
  396. // 单位用量
  397. let qtyPerAssembly = new Decimal(bomDetail.qtyPerAssembly)
  398. // 损耗率
  399. let shrinkageFactor = new Decimal(bomDetail.shrinkageFactor)
  400. // 报价数量
  401. let num = new Decimal(this.detail.quotationDetailQuantity)
  402. let needNum = componentScrap.div(num).add(qtyPerAssembly.div(new Decimal(100).sub(shrinkageFactor).div(new Decimal(100))))
  403. bomDetail.quoteUnitCost = new Decimal(needNum.mul(unitCost).toFixed(4,Decimal.ROUND_HALF_UP)).toSignificantDigits().toNumber()
  404. }
  405. this.$emit("update:totalCost",this.getQuoteBomCost())
  406. // this.$emit("update:loadingStatus",false)
  407. },
  408. getQuoteBomCost(){
  409. // this.searchQuoteBomList();
  410. return this.bomDetailList.reduce((total, currentValue) => {
  411. return total + new Decimal(currentValue.quoteUnitCost).toNumber();
  412. }, 0)
  413. },
  414. nodeClick(val){
  415. this.selectBom = val.value.split("-")
  416. this.bomDetailList=[];
  417. this.$nextTick(()=>{
  418. this.$refs.tree.setCurrentKey(`${this.selectBom[0]}-${this.selectBom[1]}-${this.selectBom[2]}-${this.selectBom[3]}-${this.selectBom[4]}-${this.selectBom[5]}`)
  419. })
  420. this.searchQuoteBomList()
  421. },
  422. clickVersionCheck(){
  423. this.handoffVersion = true;
  424. this.BOMVersionList = [];
  425. this.versionData = {
  426. site:this.detail.site,
  427. partNo:this.selectBom[3],
  428. version:this.selectBom[0],
  429. bomType:this.selectBom[2]
  430. }
  431. this.searchQuoteBOMVersion();
  432. },
  433. searchQuoteBOMVersion(){
  434. let params = {
  435. site:this.detail.site,
  436. quoteDetailId:this.detail.quotationDetailId,
  437. testPartNo:this.selectBom[3],
  438. }
  439. this.BOMVersionList = [];
  440. searchQuoteBOMVersion(params).then(({data})=>{
  441. if (data && data.code === 0){
  442. this.BOMVersionList = data.rows;
  443. this.selectionVersion();
  444. // 查询替代
  445. this.searchBOMAlternative(this.versionData);
  446. }else {
  447. this.$message.warning(data.msg)
  448. }
  449. }).catch((error)=>{
  450. this.$message.error(error)
  451. })
  452. },
  453. clickVersion(row){
  454. this.BomVersion = JSON.parse(JSON.stringify(row));
  455. },
  456. searchBOMAlternative(row){
  457. this.BOMAlternativeList = [];
  458. searchQuoteBOMAlternativeNo(row).then(({data})=>{
  459. if (data && data.code === 0){
  460. this.BOMAlternativeList = data.rows;
  461. }else {
  462. this.$message.warning(data.msg)
  463. }
  464. }).catch((error)=>{
  465. this.$message.error(error)
  466. })
  467. },
  468. alternativeRowStyle({row}){
  469. if (row.version === parseInt(this.selectBom[0]) && row.bomType === this.selectBom[2] && row.alternativeNo === this.selectBom[1]){
  470. return {'background-color': '#E8F7F6', cursor: 'pointer'}
  471. }
  472. },
  473. versionRowStyle({row}){
  474. if (row.version === parseInt(this.versionData.version) && row.bomType === this.versionData.bomType){
  475. return {'background-color': '#E8F7F6', cursor: 'pointer'}
  476. }
  477. },
  478. selectionVersion(){
  479. for (let i = 0; i < this.BOMVersionList.length; i++) {
  480. let BOMVersion = this.BOMVersionList[i]
  481. if (BOMVersion.version === this.versionData.version && BOMVersion.bomType === this.versionData.bomType){
  482. this.versionData = BOMVersion;
  483. return
  484. }
  485. }
  486. },
  487. clickVersionTable(row){
  488. this.versionData = row;
  489. this.searchBOMAlternative(row)
  490. },
  491. clickAlternative(row){
  492. let params = {
  493. site:this.detail.site,
  494. quoteDetailId:this.detail.quotationDetailId,
  495. partNo:row.partNo,
  496. version:row.version,
  497. bomType:row.bomType,
  498. id:this.selectBom[4],
  499. parentId:this.selectBom[5],
  500. alternativeNo:row.alternativeNo,
  501. quoteBomDetailList:this.bomDetailList
  502. }
  503. updateQuoteBomList(params).then(({data})=>{
  504. if (data && data.code === 0){
  505. this.selectBom[0] = row.version;
  506. this.selectBom[2] = row.bomType;
  507. this.selectBom[1] = row.alternativeNo;
  508. this.selectBom[3] = row.partNo;
  509. this.selectBom[4] = data.row.id;
  510. this.selectBom[5] = data.row.parentId;
  511. this.$message.success(data.msg)
  512. this.getInventoryPartBom();
  513. this.$emit("update:updateTree",this.updateTree+1)
  514. this.handoffVersion = false
  515. }else {
  516. this.$message.warning(data.msg)
  517. }
  518. }).catch((error)=>{
  519. this.$message.error(error)
  520. })
  521. },
  522. }
  523. }
  524. </script>
  525. <template>
  526. <div>
  527. <div style="margin-bottom: 5px">
  528. <el-link style="cursor:pointer;" v-if="this.selectBom.length === 6 && bomTreeStructure.length >= 0" @click="clickVersionCheck">切换版本</el-link>
  529. <span style="display: inline-block;width: 20px"></span>
  530. <el-checkbox v-model="BOMAllSearchFlag">全级BOM结构</el-checkbox>
  531. </div>
  532. <el-container>
  533. <el-aside width="24%" style="padding: 0;" :style="{height: height}" v-loading="treeLoading">
  534. <el-tree :data="bomTreeStructure"
  535. :props="bomProps"
  536. @node-click="nodeClick"
  537. :expand-on-click-node="false"
  538. node-key="value" style="height: 100%"
  539. default-expand-all
  540. :current-node-key="`${selectBom[0]}-${selectBom[1]}-${selectBom[2]}-${selectBom[3]}-${selectBom[4]}-${selectBom[5]}`"
  541. highlight-current ref="tree"
  542. ></el-tree>
  543. </el-aside>
  544. <el-main style="padding: 0">
  545. <el-table :data="bomDetailList" :height="height"
  546. stripe border element-loading-text = "数据正在加载中"
  547. v-loading="dataListLoading">
  548. <el-table-column
  549. v-for="(item,index) in columnDetailList" :key="index"
  550. :sortable="item.columnSortable"
  551. :prop="item.columnProp"
  552. :header-align="item.headerAlign"
  553. :show-overflow-tooltip="item.showOverflowTooltip"
  554. :align="item.align"
  555. :fixed="item.fixed===''?false:item.fixed"
  556. :min-width="item.columnWidth"
  557. :label="item.columnLabel">
  558. <template slot-scope="scope">
  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. </el-table-column>
  563. </el-table>
  564. </el-main>
  565. </el-container>
  566. <el-dialog :visible.sync="handoffVersion" v-drag title="BOM版本切换" @close="()=>{
  567. this.BOMVersionList = []
  568. this.BOMAlternativeList = []
  569. }" append-to-body>
  570. <el-table :data="BOMVersionList" :row-style="versionRowStyle" ref="BOMVersionTable" style="margin-top: 8px" border :height="240" @row-click="clickVersionTable">
  571. <el-table-column label="物料编码" prop="partNo" header-align="center" align="center" show-overflow-tooltip min-width="140"/>
  572. <el-table-column label="物料描述" prop="componentPartDesc" header-align="center" align="left" show-overflow-tooltip min-width="200"/>
  573. <el-table-column label="版本" prop="version" header-align="center" align="center" show-overflow-tooltip min-width="60"/>
  574. <el-table-column label="类型" prop="bomType" header-align="center" align="center" show-overflow-tooltip min-width="100"/>
  575. </el-table>
  576. <el-table :data="BOMAlternativeList" :row-style="alternativeRowStyle" border :height="240" style="margin-top: 8px">
  577. <el-table-column label="物料编码" prop="partNo" header-align="center" align="center" show-overflow-tooltip min-width="140"/>
  578. <el-table-column label="物料描述" prop="componentPartDesc" header-align="center" align="left" show-overflow-tooltip min-width="200"/>
  579. <el-table-column label="版本" prop="version" header-align="center" align="center" show-overflow-tooltip min-width="60"/>
  580. <el-table-column label="替代编码" prop="alternativeNo" header-align="center" align="left" show-overflow-tooltip min-width="60"/>
  581. <el-table-column label="类型" prop="bomType" header-align="center" align="center" show-overflow-tooltip min-width="100"/>
  582. <el-table-column label="操作" min-width="80" header-align="center" align="center">
  583. <template slot-scope="{row,$index}">
  584. <span style="color: #888;cursor:no-drop;" v-if="row.version === parseInt(selectBom[0]) && row.bomType === selectBom[2] && row.alternativeNo === selectBom[1]">选择</span>
  585. <el-link style="cursor:pointer;" v-else @click="clickAlternative(row)">选择</el-link>
  586. </template>
  587. </el-table-column>
  588. </el-table>
  589. </el-dialog>
  590. </div>
  591. </template>
  592. <style scoped>
  593. </style>