homogeneityInspectDialog.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. <template>
  2. <div>
  3. <ele-modal
  4. width="90vw"
  5. :visible.sync="visible"
  6. :close-on-click-modal="false"
  7. row-key="code"
  8. custom-class="ele-dialog-form"
  9. :title="'齐套性检查'"
  10. :maxable="true"
  11. >
  12. <div v-loading="loading">
  13. <el-form label-width="80px" :model="planInfo" class="plan_form">
  14. <el-row :gutter="20" type="flex" style="flex-wrap: wrap">
  15. <el-col :span="8">
  16. <el-form-item label="名称:">
  17. <el-input readonly v-model="planInfo.productName"></el-input>
  18. </el-form-item>
  19. </el-col>
  20. <el-col :span="8">
  21. <el-form-item label="计划编号:">
  22. <el-input readonly v-model="planInfo.code"></el-input>
  23. </el-form-item>
  24. </el-col>
  25. <el-col :span="8">
  26. <el-form-item label="规格:">
  27. <el-input readonly v-model="planInfo.specification"></el-input>
  28. </el-form-item>
  29. </el-col>
  30. <el-col :span="8">
  31. <el-form-item label="型号:">
  32. <el-input readonly v-model="planInfo.model"></el-input>
  33. </el-form-item>
  34. </el-col>
  35. <el-col :span="8">
  36. <el-form-item label="牌号:">
  37. <el-input readonly v-model="planInfo.brandNo"></el-input>
  38. </el-form-item>
  39. </el-col>
  40. <el-col :span="8">
  41. <el-form-item label="计划数量:">
  42. <el-input readonly v-model="planInfo.productNum"></el-input>
  43. </el-form-item>
  44. </el-col>
  45. </el-row>
  46. </el-form>
  47. <div class="form-wrapper">
  48. <div class="left_tree" v-show="leftShow" :style="{ width: leftWidth }">
  49. <el-tree
  50. ref="treeRef"
  51. :expand-on-click-node="false"
  52. :data="cardList"
  53. :props="treeProps"
  54. node-key="id"
  55. highlight-current
  56. @node-click="handleNodeClick"
  57. ></el-tree>
  58. </div>
  59. <div :style="{ width: rightWidth }">
  60. <div>
  61. <ele-pro-table
  62. ref="table"
  63. :needPage="false"
  64. :columns="columns"
  65. key="checkTable"
  66. :init-load="false"
  67. :datasource="datasourceList"
  68. >
  69. <template v-slot:toolbar>
  70. <!-- <el-button type="primary" @click="bulkPurchase" size="mini"
  71. >采购申请</el-button
  72. > -->
  73. </template>
  74. <template v-slot:toolkit>
  75. <el-form
  76. :inline="true"
  77. :model="formInline"
  78. class="demo-form-inline"
  79. >
  80. <el-form-item label="BOM类型">
  81. <el-select
  82. size="mini"
  83. v-model="formInline.bomType"
  84. placeholder="BOM类型"
  85. class="select-type"
  86. @change="bomTypeChange"
  87. >
  88. <el-option
  89. v-for="item in bomListType"
  90. :key="item.id"
  91. :label="item.bomName"
  92. :value="item.id"
  93. >
  94. </el-option>
  95. </el-select>
  96. </el-form-item>
  97. <el-form-item label="BOM版本">
  98. <el-select
  99. class="select-type"
  100. size="mini"
  101. v-model="formInline.bomId"
  102. placeholder="BOM版本"
  103. @change="bomVChange"
  104. >
  105. <el-option
  106. v-for="item in bomListV"
  107. :key="item.bomId"
  108. :label="item.versions"
  109. :value="item.bomId"
  110. >
  111. </el-option>
  112. </el-select>
  113. </el-form-item>
  114. <el-form-item label="最终状态">
  115. <el-select
  116. class="select-type"
  117. size="mini"
  118. v-model="formInline.finalState"
  119. placeholder="最终状态"
  120. @change="finalChange"
  121. >
  122. <el-option
  123. v-for="item in finalStateList"
  124. :key="item.value"
  125. :label="item.label"
  126. :value="item.value"
  127. >
  128. </el-option>
  129. </el-select>
  130. </el-form-item>
  131. </el-form>
  132. </template>
  133. <template v-slot:inventoryQuantity="{ row }">
  134. <el-link
  135. type="primary"
  136. :underline="false"
  137. @click="stockDetail(row)"
  138. >
  139. {{ row.inventoryQuantity }}
  140. </el-link>
  141. </template>
  142. <template v-slot:inTransitNum="{ row }">
  143. <el-link
  144. type="primary"
  145. :underline="false"
  146. @click="currentDetail(row)"
  147. >
  148. {{ row.inTransitNum }}
  149. </el-link>
  150. </template>
  151. <template v-slot:inventoryStatusText="{ row }">
  152. <div
  153. :class="
  154. row.inventoryStatusText == '缺料'
  155. ? 'statusRed'
  156. : 'statusGreen'
  157. "
  158. >
  159. {{ row.inventoryStatusText }}
  160. </div>
  161. </template>
  162. <template v-slot:inTransitStatusText="{ row }">
  163. <div
  164. :class="
  165. row.inTransitStatusText == '缺料'
  166. ? 'statusRed'
  167. : 'statusGreen'
  168. "
  169. >
  170. {{ row.inTransitStatusText }}
  171. </div>
  172. </template>
  173. <template v-slot:finalStateText="{ row }">
  174. <div
  175. :class="
  176. row.finalStateText == '缺料' ? 'statusRed' : 'statusGreen'
  177. "
  178. >
  179. {{ row.finalStateText }}
  180. </div>
  181. </template>
  182. <template v-slot:finishCount="{ row }">
  183. <div>
  184. <div v-if="row.finishCount > 0">{{ row.finishCount }}</div>
  185. <div v-else>-</div>
  186. </div>
  187. </template>
  188. <!-- <template v-slot:action="{ row }">
  189. <el-link
  190. type="primary"
  191. :underline="false"
  192. @click="purchase(row)"
  193. >
  194. 采购申请
  195. </el-link>
  196. </template> -->
  197. </ele-pro-table>
  198. </div>
  199. </div>
  200. </div>
  201. </div>
  202. <div slot="footer">
  203. <el-button plain @click="cancel">取消</el-button>
  204. <!-- <el-button type="primary" @click="confirm">确定</el-button> -->
  205. </div>
  206. </ele-modal>
  207. <stockDetailDialog ref="stockDetailDialog" />
  208. <currentDetailDialog ref="currentDetailDialog" />
  209. <producePlan ref="produceRef" @success="reloads"></producePlan>
  210. <purchaseDialog ref="purchaseDialogRef" />
  211. </div>
  212. </template>
  213. <script>
  214. import {
  215. homogeneityInspect,
  216. homogeneityInspectMerge,
  217. findMaterialInfoByPlanId,
  218. findBomCategoryByCategoryId,
  219. getBom
  220. } from '@/api/productionPlan/index.js';
  221. import { listBomByPlanIdsOverride } from '@/api/materialPlan/index';
  222. import stockDetailDialog from './stockDetailDialog.vue';
  223. import currentDetailDialog from './currentDetailDialog.vue';
  224. import producePlan from '@/views/materialPlan/components/producePlan.vue';
  225. import purchaseDialog from './purchaseDialog.vue';
  226. export default {
  227. components: {
  228. stockDetailDialog,
  229. currentDetailDialog,
  230. producePlan,
  231. purchaseDialog
  232. },
  233. data() {
  234. return {
  235. visible: false,
  236. requiredFormingNum: 0,
  237. formInline: {
  238. finalState: 0
  239. },
  240. finalStateList: [
  241. {
  242. label: '全部',
  243. value: 0
  244. },
  245. {
  246. label: '齐套',
  247. value: 1
  248. },
  249. {
  250. label: '缺料',
  251. value: 2
  252. }
  253. ],
  254. // form: {
  255. // homogeneityInspect: []
  256. // },
  257. columns: [
  258. {
  259. columnKey: 'index',
  260. label: '序号',
  261. type: 'index',
  262. width: 55,
  263. align: 'center',
  264. fixed: 'left'
  265. },
  266. // {
  267. // width: 45,
  268. // type: 'selection',
  269. // columnKey: 'selection',
  270. // align: 'center',
  271. // slot: 'selection',
  272. // fixed: 'left'
  273. // },
  274. {
  275. prop: 'batchNo',
  276. label: '批次号',
  277. align: 'center',
  278. minWidth: 100,
  279. showOverflowTooltip: true
  280. },
  281. {
  282. prop: 'salesCode',
  283. label: '销售订单号',
  284. align: 'center',
  285. minWidth: 100,
  286. showOverflowTooltip: true
  287. },
  288. {
  289. prop: 'code',
  290. label: '物料编码',
  291. align: 'center',
  292. minWidth: 100,
  293. showOverflowTooltip: true
  294. },
  295. {
  296. prop: 'name',
  297. label: '物料名称',
  298. align: 'center',
  299. minWidth: 100,
  300. showOverflowTooltip: true
  301. },
  302. {
  303. prop: 'dosage',
  304. label: '定额数量',
  305. showOverflowTooltip: true,
  306. align: 'center'
  307. },
  308. {
  309. slot: 'inventoryQuantity',
  310. prop: 'inventoryQuantity',
  311. label: '库存数量',
  312. showOverflowTooltip: true,
  313. align: 'center'
  314. },
  315. {
  316. prop: 'secureInventory',
  317. label: '安全库存',
  318. showOverflowTooltip: true,
  319. align: 'center'
  320. },
  321. {
  322. prop: 'lockQuantity',
  323. label: '锁库数量',
  324. showOverflowTooltip: true,
  325. align: 'center'
  326. },
  327. {
  328. slot: 'inventoryStatusText',
  329. prop: 'inventoryStatusText',
  330. label: '库存状态',
  331. align: 'center',
  332. minWidth: 80
  333. },
  334. {
  335. slot: 'inTransitNum',
  336. prop: 'inTransitNum',
  337. label: '在途数量',
  338. align: 'center',
  339. minWidth: 80
  340. },
  341. {
  342. prop: 'inTransitOrdersNum',
  343. label: '在途已关联数量 ',
  344. align: 'center',
  345. minWidth: 120
  346. },
  347. {
  348. slot: 'inTransitStatusText',
  349. prop: 'inTransitStatusText',
  350. label: '在途状态',
  351. align: 'center',
  352. minWidth: 80
  353. },
  354. {
  355. label: '最终可用数量',
  356. prop: 'finalAvailableQuantity',
  357. align: 'center',
  358. minWidth: 110
  359. },
  360. {
  361. label: '最终缺料数量',
  362. prop: 'finalShortageQuantity',
  363. align: 'center',
  364. minWidth: 120
  365. },
  366. {
  367. slot: 'finalStateText',
  368. prop: 'finalStateText',
  369. label: '最终状态',
  370. align: 'center',
  371. minWidth: 80
  372. }
  373. // {
  374. // columnKey: 'action',
  375. // label: '操作',
  376. // width: 120,
  377. // align: 'center',
  378. // resizable: false,
  379. // fixed: 'right',
  380. // slot: 'action'
  381. // }
  382. ],
  383. ids: [],
  384. leftShow: false,
  385. leftWidth: '0%',
  386. rightWidth: '100%',
  387. cardList: [],
  388. treeProps: {
  389. label: 'code',
  390. children: 'children'
  391. },
  392. planInfo: {
  393. salesCode: ''
  394. },
  395. datasourceAllList: [], // 表格物料全部数据
  396. datasourceList: [], // 表格物料数据
  397. bomListV: [], // BOM版本
  398. bomListType: [], // BOM 类型
  399. planId: '',
  400. selectNodeId: '',
  401. loading: false
  402. };
  403. },
  404. watch: {
  405. leftShow(newVal, oldVal) {
  406. if (newVal) {
  407. this.leftWidth = '230px';
  408. this.rightWidth = 'calc(100% - 240px)';
  409. } else {
  410. this.leftWidth = '0';
  411. this.rightWidth = '100%';
  412. }
  413. }
  414. },
  415. mounted() {},
  416. methods: {
  417. handleNodeClick(data) {
  418. this.clearData();
  419. this.getBomData(data);
  420. this.selectNodeId = data.id;
  421. this.planInfo = data;
  422. },
  423. reload(where) {
  424. this.$nextTick(() => {
  425. this.$refs.table.reload({ page: 1, where });
  426. });
  427. },
  428. reloads() {},
  429. /* 表格数据源 */
  430. // datasource({ page, limit, where }) {
  431. // return homogeneityInspect({
  432. // pageNum: page,
  433. // size: limit,
  434. // ...where
  435. // });
  436. // },
  437. stockDetail(row) {
  438. this.$refs.stockDetailDialog.open({ bomCode: row.code });
  439. },
  440. currentDetail(row) {
  441. this.$refs.currentDetailDialog.open({ bomCode: row.code });
  442. },
  443. // 选择BOM类型
  444. async bomTypeChange(e) {
  445. this.formInline.bomType = e;
  446. let data = this.bomListType.find((el) => el.id === e);
  447. if (!data) return;
  448. this.bomListV = data.bomList;
  449. await this.bomVChange(data.bomList[0].bomId);
  450. },
  451. // 选择BOM版本
  452. async bomVChange(e) {
  453. this.formInline.bomId = e;
  454. let data = this.bomListV.find((el) => el.bomId === e);
  455. if (!data) return;
  456. await this.getMaterialData(data);
  457. },
  458. // 获取物料数据信息
  459. async getMaterialData(data) {
  460. let params = { planId: this.planId, bomVersionId: data.bomId };
  461. const result = await findMaterialInfoByPlanId(params);
  462. result.map((item) => {
  463. item.batchNo = this.planInfo.batchNo;
  464. item.salesCode = this.planInfo.salesCode;
  465. item.finalState =
  466. item.finalStateText == '齐套'
  467. ? 1
  468. : item.finalStateText == '缺料'
  469. ? 2
  470. : '';
  471. });
  472. this.datasourceAllList = result;
  473. this.finalChange(0);
  474. },
  475. // 选择状态
  476. finalChange(e) {
  477. if (e === 0 || !e) {
  478. this.datasourceList = this.datasourceAllList;
  479. return;
  480. }
  481. this.datasourceList = this.datasourceAllList.filter(
  482. (item) => item.finalState === e
  483. );
  484. },
  485. // 批量采购
  486. async bulkPurchase(list) {
  487. if (list.length == 0) {
  488. return this.$message.warning('请至少选择一条数据');
  489. }
  490. // let planIds = list.map((item) => item.id);
  491. // let data = {
  492. // planIds: ['1948548495278911490', '1948548022580850689'],
  493. // demandType: '1'
  494. // };
  495. // this.$refs.produceRef.visible = true;
  496. const o = this.cardList.find((el) => el.id === this.selectNodeId);
  497. let obj = JSON.parse(JSON.stringify(o));
  498. obj.materialList = list;
  499. this.$nextTick(() => {
  500. this.$refs.purchaseDialogRef.open([obj], '生产计划');
  501. });
  502. // const result = await listBomByPlanIdsOverride(data);
  503. },
  504. // 采购申请
  505. purchase(row) {
  506. this.bulkPurchase([row]);
  507. },
  508. async open(dataList) {
  509. this.visible = true;
  510. this.cardList = dataList;
  511. if (dataList.length === 1) {
  512. this.leftShow = false;
  513. } else {
  514. this.leftShow = true;
  515. const firstNodeKey = dataList[0].id;
  516. this.$nextTick(() => {
  517. this.$refs.treeRef.setCurrentKey(firstNodeKey);
  518. });
  519. }
  520. this.handleNodeClick(dataList[0]);
  521. },
  522. cancel() {
  523. this.clearData();
  524. this.visible = false;
  525. },
  526. clearData() {
  527. this.formInline = {
  528. finalState: 0
  529. };
  530. this.bomListV = [];
  531. this.bomListType = [];
  532. this.datasourceList = [];
  533. this.datasourceAllList = [];
  534. },
  535. // 获取bom 数据
  536. async getBomData(data) {
  537. this.loading = true;
  538. try {
  539. this.planId = data.id;
  540. const res = await findBomCategoryByCategoryId(data.categoryId);
  541. if (!res || res.length == 0) {
  542. this.loading = false;
  543. this.bomListD = [];
  544. this.datasourceList = [];
  545. return;
  546. }
  547. let obj = {};
  548. let bomMap = {
  549. 1: 'PBOM',
  550. 2: 'MBOM',
  551. 3: 'ABOM',
  552. 4: 'EBOM'
  553. };
  554. res.map((el) => {
  555. el.bomName = bomMap[el.bomType];
  556. let OBMINFO = {
  557. bomId: el.bomId,
  558. bomType: el.type,
  559. versions: `V${el.versions}.0`
  560. };
  561. if (obj[el.bomType]) {
  562. obj[el.bomType].bomList.unshift(OBMINFO);
  563. } else {
  564. obj[el.bomType] = { ...el, bomList: [OBMINFO] };
  565. }
  566. });
  567. let list = Object.values(obj);
  568. this.bomListType = list;
  569. await this.bomTypeChange(list[0].id);
  570. this.loading = false;
  571. } catch (err) {
  572. this.$message.error(err.message);
  573. this.loading = false;
  574. }
  575. },
  576. confirm() {
  577. this.visible = false;
  578. },
  579. async merge() {
  580. this.reload({ planIds: this.ids, productType: 1, merge: 2 });
  581. },
  582. tabClick() {
  583. this.reload({ planIds: this.ids, productType: 1 });
  584. }
  585. }
  586. };
  587. </script>
  588. <style lang="scss" scoped>
  589. .mt20 {
  590. margin-top: 20px;
  591. }
  592. .el-form-item {
  593. margin-bottom: 0 !important;
  594. }
  595. .optionButton {
  596. display: flex;
  597. justify-content: flex-end;
  598. padding-bottom: 3px;
  599. }
  600. .statusRed {
  601. color: red;
  602. }
  603. .statusGreen {
  604. color: green;
  605. }
  606. .planInfo {
  607. }
  608. .form-wrapper {
  609. display: flex;
  610. }
  611. .planInfo {
  612. // display: flex;
  613. font-size: 16px;
  614. }
  615. .plan_form {
  616. .el-col {
  617. margin-bottom: 16px;
  618. }
  619. }
  620. .left_tree {
  621. max-height: 600px;
  622. min-height: 300px;
  623. overflow: auto;
  624. border: 1px solid #ccc;
  625. margin-right: 10px;
  626. }
  627. </style>