homogeneityInspectDialog.vue 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259
  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. <el-form
  13. :inline="true"
  14. class="demo-form-inline"
  15. label-width="107px"
  16. style="margin-bottom: 16px"
  17. >
  18. <el-form-item label="选择日期:">
  19. <!-- <el-date-picker
  20. v-model="startTime"
  21. type="date"
  22. placeholder="选择日期"
  23. value-format="yyyy-MM-dd"
  24. size="large"
  25. :picker-options="pickerOptions"
  26. >
  27. </el-date-picker> -->
  28. <el-date-picker
  29. v-model="startTime"
  30. type="daterange"
  31. value-format="yyyy-MM-dd"
  32. start-placeholder="开始日期"
  33. end-placeholder="结束日期"
  34. :clearable="false"
  35. :picker-options="pickerOptions"
  36. >
  37. </el-date-picker>
  38. </el-form-item>
  39. <el-form-item>
  40. <el-button type="primary" @click="onSubmit">查询</el-button>
  41. </el-form-item>
  42. </el-form>
  43. <div v-loading="loading">
  44. <el-form label-width="107px" :model="planInfo" class="plan_form">
  45. <el-row :gutter="20" type="flex" style="flex-wrap: wrap">
  46. <el-col :span="6">
  47. <el-form-item label="名称:">
  48. <el-input readonly v-model="planInfo.productName"></el-input>
  49. </el-form-item>
  50. </el-col>
  51. <el-col :span="6">
  52. <el-form-item label="计划编号:">
  53. <el-input readonly v-model="planInfo.code"></el-input>
  54. </el-form-item>
  55. </el-col>
  56. <el-col :span="6">
  57. <el-form-item label="规格:">
  58. <el-input readonly v-model="planInfo.specification"></el-input>
  59. </el-form-item>
  60. </el-col>
  61. <el-col :span="6">
  62. <el-form-item label="型号:">
  63. <el-input readonly v-model="planInfo.model"></el-input>
  64. </el-form-item>
  65. </el-col>
  66. </el-row>
  67. <el-row>
  68. <el-col :span="6">
  69. <el-form-item label="编码:">
  70. <el-input readonly v-model="planInfo.productCode"></el-input>
  71. </el-form-item>
  72. </el-col>
  73. <el-col :span="6">
  74. <el-form-item label="牌号:">
  75. <el-input readonly v-model="planInfo.brandNo"></el-input>
  76. </el-form-item>
  77. </el-col>
  78. <el-col :span="6">
  79. <el-form-item label="计划数量:">
  80. <el-input readonly v-model="planInfo.productNum"></el-input>
  81. </el-form-item>
  82. </el-col>
  83. <el-col :span="6" v-if="produceType == 2">
  84. <el-form-item label="未发总数:">
  85. <el-input
  86. readonly
  87. v-model="kitComInfo.totalUnshippedQuantity"
  88. ></el-input>
  89. </el-form-item>
  90. </el-col>
  91. <el-col :span="6">
  92. <el-form-item label="库存数量:">
  93. <el-input
  94. readonly
  95. v-model="kitComInfo.inventoryQuantity"
  96. ></el-input>
  97. </el-form-item>
  98. </el-col>
  99. <el-col :span="6" v-if="produceType == 2">
  100. <el-form-item label="在制总数:">
  101. <el-input
  102. readonly
  103. v-model="kitComInfo.totalNumberProduction"
  104. ></el-input>
  105. </el-form-item>
  106. </el-col>
  107. <el-col :span="6" v-if="produceType == 2">
  108. <el-form-item label="最终缺料数量:">
  109. <el-input
  110. readonly
  111. v-model="kitComInfo.finalFilledShortCount"
  112. ></el-input>
  113. </el-form-item>
  114. </el-col>
  115. <el-col :span="6">
  116. <el-form-item label="最终状态:">
  117. <el-input
  118. :class="
  119. kitComInfo.finalFilledShortState == '缺料'
  120. ? 'statusRed'
  121. : 'statusGreen'
  122. "
  123. readonly
  124. v-model="kitComInfo.finalFilledShortState"
  125. ></el-input>
  126. </el-form-item>
  127. </el-col>
  128. </el-row>
  129. </el-form>
  130. <div class="form-wrapper">
  131. <div
  132. class="left_tree"
  133. v-show="leftShow"
  134. :style="{ width: leftWidth }"
  135. >
  136. <el-tree
  137. ref="treeRef"
  138. :expand-on-click-node="false"
  139. :data="cardList"
  140. :props="treeProps"
  141. node-key="id"
  142. highlight-current
  143. @node-click="handleNodeClick"
  144. ></el-tree>
  145. </div>
  146. <div :style="{ width: rightWidth }">
  147. <div>
  148. <ele-pro-table
  149. ref="table"
  150. :needPage="false"
  151. :columns="columns"
  152. :init-load="false"
  153. :datasource="datasourceList"
  154. row-key="code"
  155. :cache-key="`ProductionPlanTable`"
  156. border
  157. height="40vh"
  158. key="id"
  159. :selection.sync="selection"
  160. >
  161. <template v-slot:default>
  162. <div class="tool">
  163. <div class="tool_l">
  164. <el-button
  165. v-if="produceType == 2"
  166. type="primary"
  167. @click="bulkPurchase"
  168. size="medium"
  169. >下发采购计划</el-button
  170. >
  171. <el-button
  172. v-if="produceType == 1 && formInline.bomType != 1"
  173. type="primary"
  174. @click="issuePlan"
  175. size="medium"
  176. >下发生产计划</el-button
  177. >
  178. </div>
  179. <div class="tool_r">
  180. <el-form
  181. :inline="true"
  182. :model="formInline"
  183. class="demo-form-inline"
  184. >
  185. <el-form-item label="BOM类型">
  186. <el-select
  187. size="medium"
  188. v-model="formInline.bomType"
  189. placeholder="BOM类型"
  190. class="select-type"
  191. @change="bomTypeChange"
  192. >
  193. <el-option
  194. v-for="item in bomListType"
  195. :key="item.bomType"
  196. :label="item.bomName"
  197. :value="item.bomType"
  198. >
  199. </el-option>
  200. </el-select>
  201. </el-form-item>
  202. <el-form-item label="BOM版本">
  203. <el-select
  204. class="select-type"
  205. size="medium"
  206. v-model="formInline.bomId"
  207. placeholder="BOM版本"
  208. @change="bomVChange"
  209. >
  210. <el-option
  211. v-for="item in bomListV"
  212. :key="item.bomId"
  213. :label="item.versions"
  214. :value="item.bomId"
  215. >
  216. </el-option>
  217. </el-select>
  218. </el-form-item>
  219. <el-form-item label="属性类型" v-if="produceType == 2">
  220. <el-select
  221. size="medium"
  222. v-model="formInline.attributeType"
  223. placeholder="属性类型"
  224. class="select-type"
  225. @change="attributeChange"
  226. >
  227. <el-option
  228. v-for="item in attributeList"
  229. :key="item.value"
  230. :label="item.label"
  231. :value="item.value"
  232. >
  233. </el-option>
  234. </el-select>
  235. </el-form-item>
  236. <el-form-item label="最终状态">
  237. <el-select
  238. class="select-type"
  239. size="medium"
  240. v-model="formInline.finalState"
  241. placeholder="最终状态"
  242. @change="finalChange"
  243. >
  244. <el-option
  245. v-for="item in finalStateList"
  246. :key="item.value"
  247. :label="item.label"
  248. :value="item.value"
  249. >
  250. </el-option>
  251. </el-select>
  252. </el-form-item>
  253. </el-form>
  254. </div>
  255. </div>
  256. </template>
  257. <!-- <template v-slot:toolbar>
  258. <el-button
  259. v-if="produceType == 2"
  260. type="primary"
  261. @click="bulkPurchase"
  262. size="medium"
  263. >下发采购计划</el-button
  264. >
  265. <el-button
  266. v-if="produceType == 1"
  267. type="primary"
  268. @click="issuePlan"
  269. size="medium"
  270. >下发生产计划</el-button
  271. >
  272. </template> -->
  273. <!-- 默认按订单 -->
  274. <template v-slot:toolbar v-if="produceType == 1">
  275. <el-form :inline="true">
  276. <el-form-item label="定额计算方法:">
  277. <el-radio-group
  278. v-model="quota_calculation"
  279. @change="selectCalculate"
  280. >
  281. <el-radio :label="1">按订单数量</el-radio>
  282. <el-radio :label="2">按缺料数量</el-radio>
  283. </el-radio-group>
  284. </el-form-item>
  285. </el-form>
  286. </template>
  287. <template v-slot:toolkit>
  288. <!-- 定额计算方法: 按订单数量 按缺料数量 -->
  289. <el-form :inline="true">
  290. <el-form-item label="基本数量">
  291. <el-input size="medium" v-model="baseCount" disabled>
  292. <template slot="append">{{ baseUnit }}</template>
  293. </el-input>
  294. </el-form-item>
  295. </el-form>
  296. </template>
  297. <template v-slot:inventoryQuantity="{ row }">
  298. <el-link
  299. type="primary"
  300. :underline="false"
  301. @click="stockDetail(row)"
  302. >
  303. {{ row.inventoryQuantity }}
  304. </el-link>
  305. </template>
  306. <template v-slot:inTransitNum="{ row }">
  307. <el-link
  308. type="primary"
  309. :underline="false"
  310. @click="currentDetail(row)"
  311. >
  312. {{ row.inTransitNum }}
  313. </el-link>
  314. </template>
  315. <template v-slot:inventoryStatusText="{ row }">
  316. <div
  317. :class="
  318. row.inventoryStatusText == '缺料'
  319. ? 'statusRed'
  320. : 'statusGreen'
  321. "
  322. >
  323. {{ row.inventoryStatusText }}
  324. </div>
  325. </template>
  326. <template v-slot:inTransitStatusText="{ row }">
  327. <div
  328. :class="
  329. row.inTransitStatusText == '缺料'
  330. ? 'statusRed'
  331. : 'statusGreen'
  332. "
  333. >
  334. {{ row.inTransitStatusText }}
  335. </div>
  336. </template>
  337. <template v-slot:finalStateText="{ row }">
  338. <div
  339. :class="
  340. row.finalStateText == '缺料' ? 'statusRed' : 'statusGreen'
  341. "
  342. >
  343. {{ row.finalStateText }}
  344. </div>
  345. </template>
  346. <template v-slot:numberProductionStateText="{ row }">
  347. <div
  348. :class="
  349. row.numberProductionStateText == '缺料'
  350. ? 'statusRed'
  351. : 'statusGreen'
  352. "
  353. >
  354. {{ row.numberProductionStateText }}
  355. </div>
  356. </template>
  357. <template v-slot:productFinalStateText="{ row }">
  358. <div
  359. :class="
  360. row.productFinalStateText == '缺料'
  361. ? 'statusRed'
  362. : 'statusGreen'
  363. "
  364. >
  365. {{ row.productFinalStateText }}
  366. </div>
  367. </template>
  368. <template v-slot:finishCount="{ row }">
  369. <div>
  370. <div v-if="row.finishCount > 0">{{ row.finishCount }}</div>
  371. <div v-else>-</div>
  372. </div>
  373. </template>
  374. <!-- <template v-slot:action="{ row }">
  375. <el-link
  376. type="primary"
  377. :underline="false"
  378. @click="issuePlan(row)"
  379. >
  380. 下发生产计划
  381. </el-link>
  382. </template> -->
  383. </ele-pro-table>
  384. </div>
  385. </div>
  386. </div>
  387. </div>
  388. <div slot="footer">
  389. <el-button plain @click="cancel">取消</el-button>
  390. <!-- <el-button type="primary" @click="confirm">确定</el-button> -->
  391. </div>
  392. </ele-modal>
  393. <stockDetailDialog ref="stockDetailDialog" />
  394. <currentDetailDialog ref="currentDetailDialog" />
  395. <purchaseDialog ref="purchaseDialogRef" :orderType="2" @success="success" />
  396. <factoryAdd
  397. ref="factoryAddRef"
  398. :isAdd="false"
  399. :factoryType="3"
  400. @close="factoryClose"
  401. ></factoryAdd>
  402. </div>
  403. </template>
  404. <script>
  405. import {
  406. findMaterialInfoByPlanId,
  407. findBomCategoryByCategoryId,
  408. findBomCategoryByCategoryIdV2,
  409. bomVersionList,
  410. listBomType,
  411. getProductKitting
  412. } from '@/api/productionPlan/index.js';
  413. import factoryAdd from './factoryAdd';
  414. import stockDetailDialog from './stockDetailDialog.vue';
  415. import currentDetailDialog from './currentDetailDialog.vue';
  416. import producePlan from '@/views/materialPlan/components/producePlan.vue';
  417. import purchaseDialog from './purchaseDialog.vue';
  418. import { issueProductionPlan } from '@/api/productionPlan/index.js';
  419. export default {
  420. components: {
  421. stockDetailDialog,
  422. currentDetailDialog,
  423. producePlan,
  424. purchaseDialog,
  425. factoryAdd
  426. },
  427. computed: {
  428. fieldShow() {
  429. return this.produceType == 1 && this.quota_calculation === 2;
  430. },
  431. columns() {
  432. return [
  433. {
  434. width: 45,
  435. type: 'selection',
  436. columnKey: 'selection',
  437. align: 'center',
  438. slot: 'selection',
  439. fixed: 'left'
  440. },
  441. {
  442. columnKey: 'index',
  443. label: '序号',
  444. type: 'index',
  445. width: 55,
  446. align: 'center',
  447. fixed: 'left'
  448. },
  449. {
  450. prop: 'batchNo',
  451. label: '批次号',
  452. align: 'center',
  453. minWidth: 100,
  454. showOverflowTooltip: true
  455. },
  456. {
  457. prop: 'bomCode',
  458. label: 'BOM编码',
  459. align: 'center',
  460. minWidth: 100,
  461. showOverflowTooltip: true
  462. },
  463. {
  464. prop: 'code',
  465. label: '物料编码',
  466. align: 'center',
  467. minWidth: 100,
  468. showOverflowTooltip: true
  469. },
  470. {
  471. prop: 'name',
  472. label: '物料名称',
  473. align: 'center',
  474. minWidth: 100,
  475. showOverflowTooltip: true
  476. },
  477. {
  478. prop: 'level',
  479. label: '层级',
  480. align: 'center',
  481. minWidth: 50
  482. },
  483. {
  484. prop: 'supplierName',
  485. label: '供应商',
  486. align: 'center',
  487. showOverflowTooltip: true,
  488. minWidth: 140
  489. },
  490. {
  491. prop: 'demandQuantity',
  492. label: '定额数量',
  493. showOverflowTooltip: true,
  494. align: 'center'
  495. },
  496. {
  497. prop: 'unit',
  498. label: '单位',
  499. showOverflowTooltip: true,
  500. align: 'center',
  501. width: 60
  502. },
  503. {
  504. prop: 'totalUnshippedQuantity',
  505. label: '未发总数',
  506. showOverflowTooltip: true,
  507. align: 'center',
  508. show: this.fieldShow
  509. // show: this.produceType == 1
  510. },
  511. {
  512. slot: 'inventoryQuantity',
  513. prop: 'inventoryQuantity',
  514. label: '库存数量',
  515. showOverflowTooltip: true,
  516. align: 'center'
  517. },
  518. {
  519. prop: 'secureInventory',
  520. label: '安全库存',
  521. showOverflowTooltip: true,
  522. align: 'center'
  523. },
  524. {
  525. prop: 'lockQuantity',
  526. label: '锁库数量',
  527. showOverflowTooltip: true,
  528. align: 'center'
  529. },
  530. {
  531. slot: 'inventoryStatusText',
  532. prop: 'inventoryStatusText',
  533. label: '库存状态',
  534. align: 'center',
  535. minWidth: 80
  536. },
  537. {
  538. slot: 'inTransitNum',
  539. prop: 'inTransitNum',
  540. label: '在途数量',
  541. align: 'center',
  542. minWidth: 80
  543. },
  544. {
  545. prop: 'inTransitOrdersNum',
  546. label: '在途已关联数量 ',
  547. align: 'center',
  548. minWidth: 120
  549. },
  550. {
  551. slot: 'inTransitStatusText',
  552. prop: 'inTransitStatusText',
  553. label: '在途状态',
  554. align: 'center',
  555. minWidth: 80
  556. },
  557. {
  558. prop: 'totalNumberProduction',
  559. label: '在制总数',
  560. showOverflowTooltip: true,
  561. align: 'center',
  562. // show: this.produceType == 1
  563. show: this.fieldShow
  564. },
  565. {
  566. prop: 'numberProductionStateText',
  567. slot: 'numberProductionStateText',
  568. label: '在制齐套',
  569. showOverflowTooltip: true,
  570. align: 'center',
  571. // show: this.produceType == 1
  572. show: this.fieldShow
  573. },
  574. // {
  575. // prop: 'productFinalStateText',
  576. // slot: 'productFinalStateText',
  577. // label: '成品的最终齐套',
  578. // showOverflowTooltip: true,
  579. // align: 'center',
  580. // minWidth: 160,
  581. // show: this.produceType == 1
  582. // },
  583. {
  584. label: '最终可用数量',
  585. prop: 'finalAvailableQuantity',
  586. align: 'center',
  587. minWidth: 110
  588. },
  589. {
  590. label: '最终缺料数量',
  591. prop: 'finalShortageQuantity',
  592. align: 'center',
  593. minWidth: 120
  594. },
  595. {
  596. label: '下发状态',
  597. align: 'center',
  598. minWidth: 90,
  599. fixed: 'right',
  600. formatter: (row) => {
  601. return row.hasIssued ? '已下发' : '未下发';
  602. }
  603. },
  604. {
  605. slot: 'finalStateText',
  606. prop: 'finalStateText',
  607. label: '最终状态',
  608. align: 'center',
  609. minWidth: 80,
  610. fixed: 'right'
  611. }
  612. // {
  613. // columnKey: 'action',
  614. // label: '操作',
  615. // width: 120,
  616. // align: 'center',
  617. // resizable: false,
  618. // fixed: 'right',
  619. // show: this.produceType == 1,
  620. // slot: 'action'
  621. // }
  622. ];
  623. }
  624. },
  625. data() {
  626. return {
  627. visible: false,
  628. kitComInfo: {},
  629. // requiredFormingNum: 0,
  630. formInline: {
  631. finalState: 0,
  632. attributeType: 2,
  633. bomId: '',
  634. time: ''
  635. },
  636. finalStateList: [
  637. {
  638. label: '全部',
  639. value: 0
  640. },
  641. {
  642. label: '齐套',
  643. value: 1
  644. },
  645. {
  646. label: '缺料',
  647. value: 2
  648. }
  649. ],
  650. ids: [],
  651. leftShow: false,
  652. leftWidth: '0%',
  653. rightWidth: '100%',
  654. cardList: [],
  655. treeProps: {
  656. label: 'code',
  657. children: 'children'
  658. },
  659. planInfo: {
  660. salesCode: ''
  661. },
  662. datasourceAllList: [], // 表格物料全部数据
  663. datasourceList: [], // 表格物料数据
  664. bomListV: [], // BOM版本
  665. bomListType: [], // BOM 类型
  666. planId: '',
  667. selectNodeId: '',
  668. loading: false,
  669. produceType: 1,
  670. selection: [],
  671. attributeList: [
  672. {
  673. value: 'all',
  674. label: '全部'
  675. },
  676. {
  677. value: 2,
  678. label: '采购件'
  679. },
  680. {
  681. value: 3,
  682. label: '外协件'
  683. }
  684. ],
  685. baseCount: '',
  686. baseUnit: '',
  687. quota_calculation: 1,
  688. pickerOptions: {
  689. // 限制最大可选日期为今天
  690. disabledDate(time) {
  691. const today = new Date();
  692. return time.getTime() > today.getTime();
  693. }
  694. },
  695. startTime: []
  696. };
  697. },
  698. watch: {
  699. leftShow(newVal, oldVal) {
  700. if (newVal) {
  701. this.leftWidth = '230px';
  702. this.rightWidth = 'calc(100% - 240px)';
  703. } else {
  704. this.leftWidth = '0';
  705. this.rightWidth = '100%';
  706. }
  707. }
  708. },
  709. mounted() {},
  710. methods: {
  711. onSubmit() {},
  712. async handleNodeClick(data) {
  713. this.planInfo = data;
  714. try {
  715. await this.getKitting();
  716. await this.getBomData(data);
  717. this.selectNodeId = data.id;
  718. } catch (e) {
  719. console.log(e, '错误');
  720. }
  721. },
  722. async getKitting() {
  723. let { startTime, endTime } = this.getTimeData();
  724. let params = {
  725. categoryId: this.planInfo.categoryId,
  726. startTime,
  727. endTime
  728. };
  729. const res = await getProductKitting(params);
  730. if (res) {
  731. this.kitComInfo = res;
  732. }
  733. },
  734. getTimeData() {
  735. let startTime = '';
  736. let endTime = '';
  737. if (this.startTime.length > 0) {
  738. startTime = this.startTime[0];
  739. endTime = this.startTime[1];
  740. }
  741. return { startTime, endTime };
  742. },
  743. initTime() {
  744. // 获取当前日期(今天)
  745. const today = new Date(); // 注意:月份是0-based,8月对应7
  746. // 计算三个月前的日期
  747. const threeMonthsAgo = new Date(today);
  748. threeMonthsAgo.setMonth(today.getMonth() - 3);
  749. let start = this.formatDate(threeMonthsAgo);
  750. let end = this.formatDate(today);
  751. this.startTime = [start, end];
  752. },
  753. formatDate(date) {
  754. const year = date.getFullYear();
  755. const month = String(date.getMonth() + 1).padStart(2, '0');
  756. const day = String(date.getDate()).padStart(2, '0');
  757. return `${year}-${month}-${day}`;
  758. },
  759. selectCalculate(val) {
  760. this.attributeChange(this.formInline.attributeType);
  761. },
  762. reload(where) {
  763. this.$nextTick(() => {
  764. this.$refs.table.reload({ page: 1, where });
  765. });
  766. },
  767. stockDetail(row) {
  768. this.$refs.stockDetailDialog.open({ bomCode: row.code });
  769. },
  770. currentDetail(row) {
  771. this.$refs.currentDetailDialog.open({ bomCode: row.code });
  772. },
  773. // 选择BOM类型
  774. async bomTypeChange(e, type) {
  775. this.formInline.bomType = e;
  776. const params = {
  777. categoryId: this.planInfo.categoryId,
  778. bomType: e,
  779. isTemp: 0
  780. };
  781. const res = await bomVersionList(params);
  782. if (!res || res.length == 0) {
  783. this.bomListV = [];
  784. return;
  785. }
  786. let list = [];
  787. res.forEach((el) => {
  788. if (el.status != 1) return;
  789. let obj = {
  790. bomId: el.id,
  791. id: el.id,
  792. versions: `V${el.versions}.0`
  793. };
  794. list.push(obj);
  795. });
  796. this.bomListV = list;
  797. if (type == 'init') {
  798. let obj = list.find((el) => el.bomId == this.planInfo.bomCategoryId);
  799. let id = obj ? obj.bomId : list[0].bomId;
  800. this.formInline.bomId = id;
  801. this.bomVChange(id);
  802. } else {
  803. let id = list[0].bomId;
  804. this.formInline.bomId = id;
  805. this.bomVChange(id);
  806. }
  807. // let data = this.bomListType.find((el) => el.id === e);
  808. // if (!data) return;
  809. // this.bomListV = data.bomList;
  810. // let idx = 0;
  811. // if (type == 'init') {
  812. // idx = data.bomList.findIndex(
  813. // (item) => item.bomId == this.planInfo.bomCategoryId
  814. // );
  815. // }
  816. // const index = idx != -1 ? idx : 0;
  817. // await this.bomVChange(data.bomList[index].bomId);
  818. },
  819. // 选择BOM版本
  820. async bomVChange(e) {
  821. this.formInline.bomId = e;
  822. // return
  823. // let bomData = list.find((el) => el.bomId == e);
  824. // if (!bomData) return;
  825. // let data = this.bomListV.find((el) => el.bomId === e);
  826. this.getMaterialData({ bomId: e }, this.formInline.attributeType);
  827. },
  828. // 查询采购价跟外协件两个类型数据
  829. async dataMerging() {
  830. if (!this.formInline.bomId) {
  831. return;
  832. }
  833. let kitting = this.quota_calculation == 1 ? false : true;
  834. let { startTime, endTime } = this.getTimeData();
  835. let params1 = {
  836. planId: this.planId,
  837. bomVersionId: this.formInline.bomId,
  838. produceType: 2,
  839. startTime,
  840. endTime,
  841. kitting: kitting
  842. };
  843. let params2 = {
  844. planId: this.planId,
  845. bomVersionId: this.formInline.bomId,
  846. produceType: 3,
  847. startTime,
  848. endTime,
  849. kitting: kitting
  850. };
  851. this.loading = true;
  852. try {
  853. // 直接调用接口函数,因为其返回Promise,无需额外包装
  854. let p1 = findMaterialInfoByPlanId(params1);
  855. let p2 = findMaterialInfoByPlanId(params2);
  856. // 使用Promise.all并行执行多个Promise
  857. let results = await Promise.all([p1, p2]);
  858. this.loading = false;
  859. // 这里可以继续对results做后续处理,比如解构等
  860. const [result1, result2] = results;
  861. // 示例:可以接着处理result1和result2,比如合并数据等
  862. const mergeData = this.handleMergedData(result1, result2);
  863. this.resultProcess(mergeData);
  864. } catch (error) {
  865. this.loading = false;
  866. console.error('接口请求出错:', error);
  867. }
  868. },
  869. handleMergedData(result1, result2) {
  870. // 处理合并后的数据逻辑
  871. return [...result1, ...result2];
  872. },
  873. // 切换属性
  874. async attributeChange(e) {
  875. if (e == 'all') {
  876. this.dataMerging();
  877. return;
  878. }
  879. let data = this.bomListV.find(
  880. (el) => el.bomId === this.formInline.bomId
  881. );
  882. if (!data) return;
  883. await this.getMaterialData(data, e);
  884. },
  885. // 获取物料数据信息
  886. async getMaterialData(data, attributeType) {
  887. if (attributeType == 'all') {
  888. this.dataMerging();
  889. return;
  890. }
  891. let kitting = this.quota_calculation == 1 ? false : true;
  892. let produceType =
  893. this.produceType == 1 ? 1 : attributeType == 2 ? 2 : 3;
  894. let { startTime, endTime } = this.getTimeData();
  895. let params = {
  896. planId: this.planId,
  897. bomVersionId: data.bomId,
  898. produceType: produceType,
  899. startTime,
  900. endTime,
  901. kitting: kitting
  902. };
  903. this.loading = true;
  904. try {
  905. const result = await findMaterialInfoByPlanId(params);
  906. this.resultProcess(result);
  907. this.loading = false;
  908. } catch (err) {
  909. this.loading = false;
  910. }
  911. },
  912. // 结果数据处理
  913. resultProcess(result) {
  914. this.datasourceList = [];
  915. if (!result || result.length == 0) {
  916. this.baseCount = '';
  917. this.baseUnit = '';
  918. return;
  919. }
  920. let first = result[0];
  921. this.baseCount = first.baseCount;
  922. this.baseUnit = first.measuringUnit;
  923. result.forEach((item) => {
  924. item.batchNo = this.planInfo.batchNo;
  925. item.salesCode = this.planInfo.salesCode;
  926. item.finalState =
  927. item.finalStateText == '齐套'
  928. ? 1
  929. : item.finalStateText == '缺料'
  930. ? 2
  931. : '';
  932. });
  933. this.datasourceAllList = result;
  934. this.finalChange(this.formInline.finalState);
  935. },
  936. // 选择状态
  937. finalChange(e) {
  938. if (e === 0 || !e) {
  939. this.datasourceList = this.datasourceAllList;
  940. return;
  941. }
  942. this.datasourceList = this.datasourceAllList.filter(
  943. (item) => item.finalState === e
  944. );
  945. },
  946. // 批量采购
  947. async bulkPurchase() {
  948. if (this.selection.length == 0) {
  949. return this.$message.warning('请至少选择一条数据');
  950. }
  951. for (let i = 0; i < this.selection.length; i++) {
  952. let el = this.selection[i];
  953. if (el.finalState == 1) {
  954. return this.$message.warning('必须选择最终状态为缺料的数据');
  955. }
  956. if (el.hasIssued) {
  957. return this.$message.warning('必须选择下发状态为未下发的数据');
  958. }
  959. }
  960. let arr = JSON.parse(JSON.stringify(this.selection));
  961. let obj = this.bomListType.find(
  962. (el) => el.bomType === this.formInline.bomType
  963. );
  964. let data = {
  965. ...this.planInfo,
  966. bomId: this.formInline.bomId,
  967. bomType: obj.bomType
  968. };
  969. this.$refs.purchaseDialogRef.open(arr, data);
  970. },
  971. success() {
  972. this.bomVChange(this.formInline.bomId);
  973. },
  974. async open(dataList, produceType) {
  975. this.initTime();
  976. this.produceType = produceType;
  977. this.visible = true;
  978. this.$nextTick(() => {
  979. this.$refs.table.reRenderTable();
  980. });
  981. // this.$refs.table.reRenderTable();
  982. this.cardList = dataList;
  983. if (dataList.length === 1) {
  984. this.leftShow = false;
  985. } else {
  986. this.leftShow = true;
  987. const firstNodeKey = dataList[0].id;
  988. this.$nextTick(() => {
  989. this.$refs.treeRef.setCurrentKey(firstNodeKey);
  990. });
  991. }
  992. this.handleNodeClick(dataList[0]);
  993. },
  994. cancel() {
  995. this.clearData();
  996. this.visible = false;
  997. },
  998. clearData() {
  999. this.formInline = {
  1000. finalState: 0,
  1001. attributeType: 2,
  1002. bomId: ''
  1003. };
  1004. this.baseCount = '';
  1005. this.baseUnit = '';
  1006. this.bomListV = [];
  1007. this.bomListType = [];
  1008. this.datasourceList = [];
  1009. this.datasourceAllList = [];
  1010. },
  1011. // 获取bom 数据
  1012. async getBomData(data) {
  1013. // this.loading = true;
  1014. try {
  1015. this.planId = data.id;
  1016. let params = { categoryId: data.categoryId };
  1017. const res = await listBomType(params);
  1018. if (!res || res.length === 0) return;
  1019. let bomMap = {
  1020. 1: 'PBOM',
  1021. 2: 'MBOM',
  1022. 3: 'ABOM'
  1023. };
  1024. let list = res.map((item) => {
  1025. return {
  1026. bomType: item.bomType,
  1027. id: item.id,
  1028. bomId: item.id,
  1029. bomName: bomMap[item.bomType]
  1030. };
  1031. });
  1032. let bom = list.find((el) => el.bomType == data.produceType);
  1033. let bomType = bom ? bom.bomType : list[0].bomType;
  1034. this.bomListType = list;
  1035. this.formInline.bomType = bomType;
  1036. this.bomTypeChange(bomType, 'init');
  1037. // console.log(res, 'res 333');
  1038. // const params = {
  1039. // categoryId: data.categoryId,
  1040. // bomType: data.produceType,
  1041. // isTemp: 0
  1042. // };
  1043. // const res = bomVersionList(params);
  1044. return;
  1045. // const res = await findBomCategoryByCategoryIdV2(
  1046. // data.bomCategoryId,
  1047. // this.produceType
  1048. // );
  1049. // this.loading = false;
  1050. // if (!res || res.length == 0) {
  1051. // this.bomListD = [];
  1052. // this.datasourceList = [];
  1053. // return;
  1054. // }
  1055. // let obj = {};
  1056. // let bomMap = {
  1057. // 1: 'PBOM',
  1058. // 2: 'MBOM',
  1059. // 3: 'ABOM'
  1060. // };
  1061. // if (this.produceType == 1) {
  1062. // delete bomMap[1];
  1063. // }
  1064. // let result = res.filter((item) => item.bomType != 1);
  1065. // result.map((el) => {
  1066. // el.bomName = bomMap[el.bomType];
  1067. // let OBMINFO = {
  1068. // bomId: el.bomId,
  1069. // bomType: el.type,
  1070. // versions: `V${el.versions}.0`
  1071. // };
  1072. // if (obj[el.bomType]) {
  1073. // obj[el.bomType].bomList.unshift(OBMINFO);
  1074. // } else {
  1075. // obj[el.bomType] = { ...el, bomList: [OBMINFO] };
  1076. // }
  1077. // });
  1078. // let list = Object.values(obj);
  1079. // if (list.length == 0) return;
  1080. // this.bomListType = list;
  1081. // let bomObj = res.find(
  1082. // (item) => item.bomId == this.planInfo.bomCategoryId
  1083. // );
  1084. // console.log(bomObj, 'bomObj');
  1085. // let idx = 0;
  1086. // if (bomObj && bomObj.bomId) {
  1087. // idx = list.findIndex((item) => item.bomType == bomObj.bomType);
  1088. // }
  1089. // const index = idx != -1 ? idx : 0;
  1090. // await this.bomTypeChange(list[index].id, 'init');
  1091. // this.loading = false;
  1092. } catch (err) {
  1093. this.$message.error(err.message);
  1094. this.loading = false;
  1095. }
  1096. },
  1097. issuePlan() {
  1098. if (this.selection.length == 0) {
  1099. return this.$message.warning('请至少选择一条数据');
  1100. }
  1101. for (let i = 0; i < this.selection.length; i++) {
  1102. let el = this.selection[i];
  1103. if (el.finalState == 1) {
  1104. return this.$message.warning('必须选择最终状态为缺料的数据');
  1105. }
  1106. // if (el.hasIssued) {
  1107. // return this.$message.warning('必须选择下发状态为未下发的数据');
  1108. // }
  1109. }
  1110. let obj = this.bomListType.find(
  1111. (el) => el.bomType === this.formInline.bomType
  1112. );
  1113. const addPOList = this.fieldProcessing(this.selection);
  1114. // this.$alert('确定要将所选的数据下发生产计划吗', {
  1115. // confirmButtonText: '确定',
  1116. // callback: (action) => {
  1117. // let param = {
  1118. // addPOList: addPOList,
  1119. // produceType: obj.bomType,
  1120. // id: this.planInfo.id
  1121. // };
  1122. // batchSave(param).then((res) => {
  1123. // this.$message.success('操作成功');
  1124. // this.bomVChange(this.formInline.bomId);
  1125. // });
  1126. // }
  1127. // });
  1128. this.$confirm('确定要将所选的数据下发生产计划吗?', '提示', {
  1129. confirmButtonText: '确定',
  1130. cancelButtonText: '取消'
  1131. })
  1132. .then(() => {
  1133. let param = {
  1134. addPOList: addPOList,
  1135. produceType: obj.bomType,
  1136. id: this.planInfo.id
  1137. };
  1138. issueProductionPlan(param).then((res) => {
  1139. this.$message.success('操作成功');
  1140. this.bomVChange(this.formInline.bomId);
  1141. });
  1142. })
  1143. .catch(() => {});
  1144. // this.$refs.factoryAddRef.open();
  1145. // this.$refs.factoryAddRef.confirmChoose([row]);
  1146. },
  1147. // 字段处理
  1148. fieldProcessing(arr) {
  1149. // return;
  1150. let list = arr.map((item) => {
  1151. return {
  1152. id: item.resourceBomId,
  1153. categoryId: item.categoryId,
  1154. productCode: item.code,
  1155. productName: item.name,
  1156. specification: item.specification,
  1157. produceRoutingId: item.produceRoutingId || '',
  1158. produceRoutingName: item.produceRoutingName || '',
  1159. requiredFormingNum: item.finalShortageQuantity,
  1160. startTime: this.planInfo.startTime,
  1161. endTime: this.planInfo.endTime,
  1162. unit: item.unit,
  1163. brandNo: item.brandNo || '',
  1164. batchNo: this.planInfo.batchNo,
  1165. model: item.model,
  1166. resourceType: 0
  1167. };
  1168. });
  1169. return list || [];
  1170. },
  1171. factoryClose(val) {
  1172. // this.factoryObj = {};
  1173. },
  1174. onSubmit() {
  1175. this.getKitting();
  1176. this.attributeChange(this.formInline.attributeType);
  1177. }
  1178. // confirm() {
  1179. // this.visible = false;
  1180. // },
  1181. // async merge() {
  1182. // this.reload({ planIds: this.ids, productType: 1, merge: 2 });
  1183. // },
  1184. // tabClick() {
  1185. // this.reload({ planIds: this.ids, productType: 1 });
  1186. // }
  1187. }
  1188. };
  1189. </script>
  1190. <style lang="scss" scoped>
  1191. .mt20 {
  1192. margin-top: 20px;
  1193. }
  1194. .el-form-item {
  1195. margin-bottom: 0 !important;
  1196. }
  1197. .optionButton {
  1198. display: flex;
  1199. justify-content: flex-end;
  1200. padding-bottom: 3px;
  1201. }
  1202. .statusRed {
  1203. color: red;
  1204. :deep(.el-input__inner) {
  1205. color: red;
  1206. }
  1207. }
  1208. .statusGreen {
  1209. color: green;
  1210. :deep(.el-input__inner) {
  1211. color: green;
  1212. }
  1213. }
  1214. .planInfo {
  1215. }
  1216. .form-wrapper {
  1217. display: flex;
  1218. }
  1219. .planInfo {
  1220. // display: flex;
  1221. font-size: 16px;
  1222. }
  1223. .plan_form {
  1224. .el-col {
  1225. margin-bottom: 16px;
  1226. }
  1227. }
  1228. .left_tree {
  1229. max-height: 600px;
  1230. min-height: 300px;
  1231. overflow: auto;
  1232. border: 1px solid #ccc;
  1233. margin-right: 10px;
  1234. }
  1235. .tool {
  1236. display: flex;
  1237. align-items: center;
  1238. justify-content: space-between;
  1239. padding: 5px 10px;
  1240. border-left: 1px solid #ededed;
  1241. border-right: 1px solid #ededed;
  1242. }
  1243. </style>