material.vue 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319
  1. <template>
  2. <div>
  3. <header-title title="物料清单"></header-title>
  4. <ele-pro-table
  5. ref="table"
  6. row-key="id"
  7. :columns="materialColumns"
  8. :datasource="materialList"
  9. cache-key="prenatal-examination-material-list-table-2511031522"
  10. autoAmendPage
  11. :needPage="false"
  12. @refresh="$emit('refresh')"
  13. >
  14. <template v-slot:toolbar>
  15. <el-button type="primary" @click="openMaterialModal"
  16. >添加物料</el-button
  17. >
  18. </template>
  19. <template v-slot:selectColumn="{ row }">
  20. <el-checkbox
  21. v-model="row.selected"
  22. @change="selectedChange(row)"
  23. ></el-checkbox>
  24. </template>
  25. <template v-slot:feedQuantityHeader>
  26. <el-tooltip
  27. effect="dark"
  28. content="数量是指存在多次投料时,本道工序在本次记录表报工时的累计当时投料数量;"
  29. placement="top"
  30. >
  31. <div>
  32. <span>数量</span>
  33. <i
  34. class="el-icon-info"
  35. style="margin-left: 4px; color: #909399"
  36. ></i>
  37. </div>
  38. </el-tooltip>
  39. </template>
  40. <template v-slot:sumConsumeQuantityHeader>
  41. <el-tooltip
  42. effect="dark"
  43. content="累计消耗数量是指存在多次记录表报工时,本次记录表报工时的累计实时消耗数量;"
  44. placement="top"
  45. >
  46. <div>
  47. <span>累计消耗数量</span>
  48. <i
  49. class="el-icon-info"
  50. style="margin-left: 4px; color: #909399"
  51. ></i>
  52. </div>
  53. </el-tooltip>
  54. </template>
  55. </ele-pro-table>
  56. <header-title title="产出清单" style="margin-top: 20px"></header-title>
  57. <ele-pro-table
  58. ref="table"
  59. row-key="id"
  60. :columns="outputDetailsColumns"
  61. :datasource="localOutputDetails"
  62. cache-key="prenatal-examination-output-list-table-2511031523"
  63. autoAmendPage
  64. :needPage="false"
  65. @refresh="localOutputDetailsRefresh"
  66. >
  67. <template v-slot:reportQuantity="{ row }">
  68. <div>
  69. <!-- {{ reportQuantitymax(row) }} -->
  70. <el-input-number
  71. size="small"
  72. v-model.number="row.reportQuantity"
  73. controls-position="right"
  74. :min="0"
  75. :max="reportQuantitymax(row)"
  76. @change="reportQuantityChange(row)"
  77. ></el-input-number>
  78. </div>
  79. </template>
  80. <template v-slot:qualifiedQuantity="{ row }">
  81. <el-input-number
  82. size="small"
  83. v-model.number="row.qualifiedQuantity"
  84. controls-position="right"
  85. :min="0"
  86. :max="qualifiedQuantityMax(row)"
  87. @change="qualifiedQuantityChange(row)"
  88. ></el-input-number>
  89. </template>
  90. <template v-slot:noQualifiedQuantity="{ row }">
  91. <el-input-number
  92. size="small"
  93. v-model.number="row.noQualifiedQuantity"
  94. controls-position="right"
  95. :min="0"
  96. :max="noQualifiedQuantityMax(row)"
  97. @change="noQualifiedQuantityChange(row)"
  98. ></el-input-number>
  99. </template>
  100. <template v-slot:msg="{ row }">
  101. <el-input
  102. v-model="row.msg"
  103. type="textarea"
  104. rows="1"
  105. autosize
  106. @change="$emit('update:outputDetails', localOutputDetails)"
  107. ></el-input>
  108. </template>
  109. <template v-slot:sumReportQuantityHeader>
  110. <el-tooltip
  111. effect="dark"
  112. content="已报工数量是指存在多次记录表报工时,多次报工数量的累计实时已报工数量;"
  113. placement="top"
  114. >
  115. <div>
  116. <span>已报工数量</span>
  117. <i
  118. class="el-icon-info"
  119. style="margin-left: 4px; color: #909399"
  120. ></i>
  121. </div>
  122. </el-tooltip>
  123. </template>
  124. <template v-slot:sumQualifiedQuantityHeader>
  125. <el-tooltip
  126. effect="dark"
  127. content="合格品数量是指存在多次记录表报工时,多次报工数量的累计实时合格品数量;"
  128. placement="top"
  129. >
  130. <div>
  131. <span>合格总数</span>
  132. <i
  133. class="el-icon-info"
  134. style="margin-left: 4px; color: #909399"
  135. ></i>
  136. </div>
  137. </el-tooltip>
  138. </template>
  139. <template v-slot:sumNoQualifiedQuantityHeader>
  140. <el-tooltip
  141. effect="dark"
  142. content="不合格品数量是指存在多次记录表报工时,多次报工数量的累计实时不合格品数量;"
  143. placement="top"
  144. >
  145. <div>
  146. <span>不合格总数</span>
  147. <i
  148. class="el-icon-info"
  149. style="margin-left: 4px; color: #909399"
  150. ></i>
  151. </div>
  152. </el-tooltip>
  153. </template>
  154. </ele-pro-table>
  155. <materialModal ref="materialModalRef" @confirm="materialConfirm" />
  156. </div>
  157. </template>
  158. <script>
  159. import materialModal from './materialModal.vue';
  160. import {
  161. getMaterialQuotaInfo,
  162. getCategoryAndLevelByCategoryId
  163. } from '@/api/producetaskrecordrulesrecord/index';
  164. export default {
  165. components: {
  166. materialModal
  167. },
  168. props: {
  169. // 物料明细
  170. pickDetails: {
  171. type: Array,
  172. default: () => []
  173. },
  174. // 本次产出明细
  175. outputDetails: {
  176. type: Array,
  177. default: () => []
  178. },
  179. // 上到工序产出明细
  180. preOutputDetails: {
  181. type: Array,
  182. default: () => []
  183. },
  184. sumOutputDetails: {
  185. type: Array,
  186. default: () => []
  187. },
  188. // 工单id
  189. workOrderId: {
  190. type: [String, Number],
  191. required: true
  192. },
  193. // 规则id
  194. ruleId: {
  195. type: [String, Number],
  196. required: false
  197. },
  198. // 工序id
  199. produceTaskId: {
  200. type: [String, Number],
  201. required: true
  202. },
  203. // 工序实例id
  204. produceTaskInstanceId: {
  205. type: [String, Number],
  206. required: true
  207. },
  208. // 工序名称
  209. produceTaskName: {
  210. type: String,
  211. required: true
  212. },
  213. // BOM产品分类id
  214. bomCategoryId: {
  215. type: [String, Number],
  216. required: true
  217. },
  218. // 产出类型 1-物料本身 2-在制品 3-BOM标准产出
  219. outputType: {
  220. type: [Number],
  221. required: true
  222. },
  223. // 产品分类id
  224. categoryId: {
  225. type: [String, Number],
  226. required: false
  227. },
  228. // 执行状态
  229. executeStatus: {
  230. type: [Number],
  231. required: false
  232. }
  233. },
  234. watch: {
  235. pickDetails: {
  236. handler(newVal) {
  237. this.localPickDetails = JSON.parse(JSON.stringify(newVal)).map(
  238. (i) => {
  239. i.ruleId = this.ruleId;
  240. i.bomCategoryId = this.bomCategoryId;
  241. return i;
  242. }
  243. );
  244. },
  245. deep: true,
  246. immediate: true
  247. },
  248. outputDetails: {
  249. handler(newVal) {
  250. this.localOutputDetails = JSON.parse(JSON.stringify(newVal)).map(
  251. (i) => {
  252. i.ruleId = this.ruleId;
  253. i.outputType = this.outputType;
  254. i.bomCategoryId = this.bomCategoryId;
  255. i.id = null;
  256. return i;
  257. }
  258. );
  259. },
  260. deep: true,
  261. immediate: true
  262. },
  263. outputType: {
  264. handler() {
  265. // 重置产出明细
  266. this.localOutputDetails = [];
  267. this.localPickDetails = this.localPickDetails.map((item) => {
  268. return {
  269. ...item,
  270. selected: false
  271. };
  272. });
  273. // 根据不同的类型,重置物料明细
  274. if (this.outputType == 1) {
  275. this.$emit('update:outputDetails', this.localOutputDetails);
  276. // 1-物料本身
  277. } else if (this.outputType == 2) {
  278. // 2-在制品
  279. this.categoryInfoSetOutput();
  280. } else {
  281. // 3 BOM标准产出
  282. this.setMaterialQuotaInfo();
  283. }
  284. }
  285. },
  286. ruleId: {
  287. handler() {
  288. // 更新物料明细的ruleId
  289. this.localPickDetails = this.localPickDetails.map((item) => {
  290. return {
  291. ...item,
  292. ruleId: this.ruleId
  293. };
  294. });
  295. // 更新产出明细的ruleId
  296. this.localOutputDetails = this.localOutputDetails.map((item) => {
  297. return {
  298. ...item,
  299. ruleId: this.ruleId
  300. };
  301. });
  302. // 通知父组件更新
  303. this.$emit('update:pickDetails', this.localPickDetails);
  304. this.$emit('update:outputDetails', this.localOutputDetails);
  305. }
  306. },
  307. produceTaskId: {
  308. handler() {
  309. this.getMaterialQuotaInfo();
  310. this.getCategoryAndLevelByCategoryId();
  311. },
  312. immediate: true
  313. }
  314. },
  315. computed: {
  316. // 物料清单(包含上到工序产出明细)
  317. materialList() {
  318. return this.localPickDetails;
  319. },
  320. // 物料清单表头
  321. materialColumns() {
  322. const list = [
  323. {
  324. width: 45,
  325. type: 'index',
  326. columnKey: 'index',
  327. align: 'center'
  328. },
  329. {
  330. label: '类型',
  331. prop: 'categoryLevelNamePath',
  332. minWidth: 120
  333. },
  334. {
  335. label: '编码',
  336. prop: 'categoryCode',
  337. minWidth: 120
  338. },
  339. {
  340. label: '名称',
  341. prop: 'categoryName',
  342. minWidth: 120
  343. },
  344. {
  345. prop: 'model',
  346. label: '型号',
  347. align: 'center',
  348. showOverflowTooltip: true
  349. },
  350. {
  351. prop: 'specifications',
  352. label: '规格',
  353. align: 'center',
  354. width: 160,
  355. showOverflowTooltip: true
  356. },
  357. {
  358. prop: 'brandNo',
  359. label: '牌号',
  360. align: 'center'
  361. },
  362. {
  363. label: '工序名称',
  364. prop: 'produceTaskName',
  365. minWidth: 120
  366. },
  367. {
  368. label: '数量',
  369. prop: 'feedQuantity',
  370. minWidth: 120,
  371. formatter: (row) => {
  372. return (row.quantity || 0) + (row.unit || '');
  373. },
  374. headerSlot: 'feedQuantityHeader'
  375. },
  376. {
  377. label: '当次消耗数量',
  378. prop: '',
  379. minWidth: 120,
  380. formatter: (row) => {
  381. // 产出为物料
  382. if (this.outputType == 1) {
  383. // 取值产出清单
  384. const outputItem = this.localOutputDetails.find(
  385. (item) => item.categoryCode === row.categoryCode
  386. );
  387. if (outputItem) {
  388. return outputItem.reportQuantity + (row.unit || '');
  389. }
  390. return 0 + (row.unit || '');
  391. } else {
  392. // 产出为在制品 或 BOM标准产出
  393. // 查询基数
  394. if (!this.materialQuotaInfo) {
  395. return '0' + (row.unit || '');
  396. }
  397. // 当前行为在制品 和 BOM标准产出
  398. const preOutputItem = this.localOutputDetails.find(
  399. (item) => item.categoryCode === row.categoryCode
  400. );
  401. if (preOutputItem) {
  402. return (preOutputItem.reportQuantity || 0) + (row.unit || '');
  403. }
  404. // 当前行为原材料
  405. const materialItem = this.materialQuotaInfo.materialQuota.find(
  406. (item) => item.categoryCode === row.categoryCode
  407. );
  408. if (!materialItem) {
  409. return '0' + (row.unit || '');
  410. }
  411. // 需要的物料数量比例
  412. let count =
  413. materialItem.count / this.materialQuotaInfo.baseCount;
  414. // 产出清单的报工数量 当次报工+累计报工
  415. const outputItem = this.localOutputDetails[0];
  416. if (!outputItem) {
  417. return '0' + (row.unit || '');
  418. }
  419. // 当次消耗
  420. let needQuantity = this.formatNumber(
  421. outputItem.reportQuantity * count
  422. );
  423. return needQuantity + (row.unit || '');
  424. }
  425. }
  426. },
  427. {
  428. label: '累计消耗数量',
  429. prop: '',
  430. minWidth: 120,
  431. formatter: (row) => {
  432. if (this.outputType == 1) {
  433. const outputItem = this.localOutputDetails.find(
  434. (item) => item.categoryCode == row.categoryCode
  435. );
  436. // 查询其他工单sumOutputDetails中已产生的bom标准产出和在制品的累计消耗数量
  437. let preCount = 0;
  438. if (this.materialQuotaInfo) {
  439. const materialQuotaItem =
  440. this.materialQuotaInfo.materialQuota.find(
  441. (item) => item.categoryCode === row.categoryCode
  442. );
  443. if (materialQuotaItem) {
  444. // 计算比例
  445. const proportion =
  446. materialQuotaItem.count /
  447. this.materialQuotaInfo.baseCount;
  448. if (this.materialQuotaInfo.standardOutput) {
  449. // BOM标准产出
  450. const preItem = this.sumOutputDetails.find(
  451. (item) =>
  452. item.categoryCode ===
  453. this.materialQuotaInfo.standardOutput.categoryCode
  454. );
  455. if (preItem) {
  456. preCount += this.formatNumber(
  457. preItem.sumReportQuantity * proportion
  458. );
  459. }
  460. }
  461. if (this.categoryInfo) {
  462. // 在制品
  463. const preItem = this.sumOutputDetails.find(
  464. (item) =>
  465. item.categoryCode === this.categoryInfo.categoryCode
  466. );
  467. if (preItem) {
  468. preCount += this.formatNumber(
  469. preItem.sumReportQuantity * proportion
  470. );
  471. }
  472. }
  473. }
  474. }
  475. // debugger;
  476. let count = 0;
  477. if (outputItem) {
  478. if (this.executeStatus === 2) {
  479. // 已执行,处理重新一键报工时,sumReportQuantity包含了当前报工数量
  480. count =
  481. row.sumReportQuantity -
  482. (outputItem.reportQuantityCopy -
  483. outputItem.reportQuantity);
  484. } else {
  485. count = row.sumReportQuantity + outputItem.reportQuantity;
  486. }
  487. } else {
  488. count = row.sumReportQuantity;
  489. }
  490. return count + preCount + (row.unit || '');
  491. } else {
  492. // 当前行为在制品 和 BOM标准产出
  493. const output = this.localOutputDetails.find(
  494. (item) => item.categoryCode === row.categoryCode
  495. );
  496. if (output) {
  497. // 区分已执行状态
  498. if (this.executeStatus === 2) {
  499. // 已执行,处理重新一键报工时,sumReportQuantity包含了当前报工数量
  500. return (
  501. output.sumReportQuantity -
  502. (output.reportQuantityCopy - output.reportQuantity) +
  503. (row.unit || '')
  504. );
  505. }
  506. return (
  507. (output.sumReportQuantity || 0) +
  508. output.reportQuantity +
  509. (row.unit || '')
  510. );
  511. }
  512. // 产出为在制品 或 BOM标准产出 累计消耗数量
  513. if (!this.materialQuotaInfo) {
  514. return row.sumReportQuantity + (row.unit || '');
  515. }
  516. const materialItem = this.materialQuotaInfo.materialQuota.find(
  517. (item) => item.categoryCode === row.categoryCode
  518. );
  519. if (!materialItem) {
  520. return row.sumReportQuantity + (row.unit || '');
  521. }
  522. // 计算在制 标准产出消耗原材料
  523. const outputItem = this.localOutputDetails[0];
  524. if (!outputItem) {
  525. return row.sumReportQuantity + (row.unit || '');
  526. }
  527. // 单位产出所需物料比例
  528. const proportion =
  529. materialItem.count / this.materialQuotaInfo.baseCount;
  530. // 查询其他工单sumOutputDetails中已产生的bom标准产出和在制品的累计消耗数量
  531. let preCount = 0;
  532. // 如果当前物料不是BOM标准产出,则需要加上BOM标准产出的消耗数量
  533. if (
  534. outputItem.categoryCode !=
  535. this.materialQuotaInfo.standardOutput.categoryCode
  536. ) {
  537. // BOM标准产出
  538. const preItem = this.sumOutputDetails.find(
  539. (item) =>
  540. item.categoryCode ===
  541. this.materialQuotaInfo.standardOutput.categoryCode
  542. );
  543. if (preItem) {
  544. preCount += this.formatNumber(
  545. preItem.sumReportQuantity * proportion
  546. );
  547. }
  548. }
  549. // 在制品
  550. if (this.categoryInfo) {
  551. if (
  552. this.categoryInfo.categoryCode != outputItem.categoryCode
  553. ) {
  554. const preItem = this.sumOutputDetails.find(
  555. (item) =>
  556. item.categoryCode === this.categoryInfo.categoryCode
  557. );
  558. if (preItem) {
  559. preCount += this.formatNumber(
  560. preItem.sumReportQuantity * proportion
  561. );
  562. }
  563. }
  564. }
  565. let cumulativeOutputQuantity = 0;
  566. if (this.executeStatus === 2) {
  567. // 已执行,处理重新一键报工时,sumReportQuantity包含了当前报工数量
  568. cumulativeOutputQuantity =
  569. outputItem.sumReportQuantity -
  570. (outputItem.reportQuantityCopy - outputItem.reportQuantity);
  571. } else {
  572. cumulativeOutputQuantity =
  573. outputItem.sumReportQuantity + outputItem.reportQuantity;
  574. }
  575. const needQuantity = this.formatNumber(
  576. cumulativeOutputQuantity * proportion
  577. );
  578. // 已消耗数量转换
  579. const sumReportQuantity = row.sumReportQuantity;
  580. return (
  581. needQuantity + preCount + sumReportQuantity + (row.unit || '')
  582. );
  583. }
  584. },
  585. headerSlot: 'sumConsumeQuantityHeader'
  586. }
  587. ];
  588. if (this.outputType == 1) {
  589. list.push({
  590. prop: '',
  591. label: '选择',
  592. slot: 'selectColumn',
  593. align: 'center',
  594. fixed: 'right'
  595. });
  596. }
  597. return list;
  598. },
  599. // 产出清单表头
  600. outputDetailsColumns() {
  601. return [
  602. {
  603. width: 45,
  604. type: 'index',
  605. columnKey: 'index',
  606. align: 'center'
  607. },
  608. {
  609. label: '类型',
  610. prop: 'categoryLevelNamePath',
  611. minWidth: 120
  612. },
  613. {
  614. label: '编码',
  615. prop: 'categoryCode',
  616. minWidth: 120
  617. },
  618. {
  619. label: '名称',
  620. prop: 'categoryName',
  621. minWidth: 120
  622. },
  623. {
  624. prop: 'model',
  625. label: '型号',
  626. align: 'center',
  627. showOverflowTooltip: true
  628. },
  629. {
  630. prop: 'specifications',
  631. label: '规格',
  632. align: 'center',
  633. width: 160,
  634. showOverflowTooltip: true
  635. },
  636. {
  637. prop: 'brandNo',
  638. label: '牌号',
  639. align: 'center'
  640. },
  641. {
  642. label: '工序名称',
  643. prop: 'produceTaskName',
  644. minWidth: 120
  645. },
  646. {
  647. label: '当次报工数量',
  648. prop: 'reportQuantity',
  649. minWidth: 160,
  650. slot: 'reportQuantity'
  651. },
  652. {
  653. label: '当次合格数量',
  654. prop: 'qualifiedQuantity',
  655. minWidth: 160,
  656. slot: 'qualifiedQuantity'
  657. },
  658. {
  659. label: '当次不合格数量',
  660. prop: 'noQualifiedQuantity',
  661. minWidth: 160,
  662. slot: 'noQualifiedQuantity'
  663. },
  664. {
  665. label: '不合格原因',
  666. prop: 'msg',
  667. minWidth: 160,
  668. slot: 'msg'
  669. },
  670. {
  671. label: '已报工数量',
  672. prop: 'sumReportQuantity',
  673. minWidth: 120,
  674. formatter: (row) => {
  675. let count = row.sumReportQuantity || 0;
  676. if (this.executeStatus === 2) {
  677. // 已执行,处理重新一键报工时,sumReportQuantity包含了当前报工数量
  678. count += row.reportQuantity - row.reportQuantityCopy;
  679. } else {
  680. count += row.reportQuantity;
  681. }
  682. return count + (row.unit || '');
  683. },
  684. headerSlot: 'sumReportQuantityHeader'
  685. },
  686. {
  687. label: '合格总数',
  688. prop: 'sumQualifiedQuantity',
  689. minWidth: 120,
  690. formatter: (row) => {
  691. // 已报工数量
  692. let sumReportQuantity = row.sumReportQuantity || 0;
  693. if (this.executeStatus === 2) {
  694. // 已执行,处理重新一键报工时,sumReportQuantity包含了当前报工数量
  695. sumReportQuantity +=
  696. row.reportQuantity - row.reportQuantityCopy;
  697. } else {
  698. sumReportQuantity += row.reportQuantity;
  699. }
  700. let count = row.sumQualifiedQuantity || 0;
  701. if (this.executeStatus === 2) {
  702. // 已执行,处理重新一键报工时,sumQualifiedQuantity包含了当前报工数量
  703. count += row.qualifiedQuantity - row.qualifiedQuantityCopy;
  704. } else {
  705. count += row.qualifiedQuantity;
  706. }
  707. // 处理缓存后,物料被其他工单报工超出已报工数量问题
  708. if (count > sumReportQuantity) {
  709. count = sumReportQuantity;
  710. }
  711. return count + (row.unit || '');
  712. },
  713. headerSlot: 'sumQualifiedQuantityHeader'
  714. },
  715. {
  716. label: '不合格总数',
  717. prop: 'sumNoQualifiedQuantity',
  718. minWidth: 120,
  719. formatter: (row) => {
  720. // 已报工数量
  721. let sumReportQuantity = row.sumReportQuantity || 0;
  722. if (this.executeStatus === 2) {
  723. // 已执行,处理重新一键报工时,sumReportQuantity包含了当前报工数量
  724. sumReportQuantity +=
  725. row.reportQuantity - row.reportQuantityCopy;
  726. } else {
  727. sumReportQuantity += row.reportQuantity;
  728. }
  729. let count = row.sumNoQualifiedQuantity || 0;
  730. if (this.executeStatus === 2) {
  731. // 已执行,处理重新一键报工时,sumNoQualifiedQuantity包含了当前报工数量
  732. count += row.noQualifiedQuantity - row.noQualifiedQuantityCopy;
  733. } else {
  734. count += row.noQualifiedQuantity;
  735. }
  736. // 处理缓存后,物料被其他工单报工超出已报工数量问题
  737. if (count > sumReportQuantity) {
  738. count = sumReportQuantity;
  739. }
  740. return count + (row.unit || '');
  741. },
  742. headerSlot: 'sumNoQualifiedQuantityHeader'
  743. }
  744. ];
  745. }
  746. },
  747. data() {
  748. return {
  749. localPickDetails: [],
  750. localOutputDetails: [],
  751. // bom配置的 标准产出信息
  752. materialQuotaInfo: null,
  753. // 在制品信息
  754. categoryInfo: null
  755. };
  756. },
  757. methods: {
  758. // 选择物料
  759. openMaterialModal() {
  760. this.$refs.materialModalRef.open(
  761. {
  762. workOrderId: this.workOrderId,
  763. ruleId: this.ruleId,
  764. produceTaskId: this.produceTaskId
  765. },
  766. []
  767. );
  768. },
  769. materialConfirm(data) {
  770. // 选择物料后添加
  771. console.log('data', data);
  772. data.forEach((newItem) => {
  773. const index = this.localPickDetails.findIndex(
  774. (item) => item.categoryCode === newItem.categoryCode
  775. );
  776. if (index !== -1) {
  777. // 存在则替换数量
  778. this.localPickDetails[index].quantity = newItem.quantity;
  779. } else {
  780. const sumItem = this.sumOutputDetails.find(
  781. (item) => item.categoryCode === newItem.categoryCode
  782. );
  783. let sumQualifiedQuantity = 0;
  784. let sumNoQualifiedQuantity = 0;
  785. let sumReportQuantity = 0;
  786. if (sumItem) {
  787. sumQualifiedQuantity = sumItem.sumQualifiedQuantity;
  788. sumNoQualifiedQuantity = sumItem.sumNoQualifiedQuantity;
  789. sumReportQuantity = sumItem.sumReportQuantity;
  790. }
  791. // 不存在则添加
  792. this.localPickDetails.push({
  793. ...newItem,
  794. // 物料的类型
  795. outputType: 1,
  796. reportQuantity: 0,
  797. ruleId: this.ruleId,
  798. bomCategoryId: this.bomCategoryId,
  799. produceTaskId: this.produceTaskId,
  800. produceTaskInstanceId: this.produceTaskInstanceId,
  801. produceTaskName: this.produceTaskName,
  802. workOrderId: this.workOrderId,
  803. sumQualifiedQuantity,
  804. sumNoQualifiedQuantity,
  805. sumReportQuantity
  806. });
  807. }
  808. });
  809. console.log('this.localPickDetails', this.localPickDetails);
  810. this.$emit('update:pickDetails', this.localPickDetails);
  811. },
  812. // bom标准产出赋值
  813. setMaterialQuotaInfo() {
  814. console.log('this.materialQuotaInfo', this.materialQuotaInfo);
  815. if (this.materialQuotaInfo && this.materialQuotaInfo.standardOutput) {
  816. const sumItem = this.sumOutputDetails.find(
  817. (i) =>
  818. i.categoryCode ===
  819. this.materialQuotaInfo.standardOutput.categoryCode
  820. );
  821. let sumQualifiedQuantity = 0;
  822. let sumNoQualifiedQuantity = 0;
  823. let sumReportQuantity = 0;
  824. if (sumItem) {
  825. sumQualifiedQuantity = sumItem.sumQualifiedQuantity;
  826. sumNoQualifiedQuantity = sumItem.sumNoQualifiedQuantity;
  827. sumReportQuantity = sumItem.sumReportQuantity;
  828. }
  829. // 赋值产出
  830. this.localOutputDetails = [
  831. {
  832. ...this.materialQuotaInfo.standardOutput,
  833. id: null,
  834. reportQuantity: 0,
  835. reportQuantityCopy: 0,
  836. qualifiedQuantity: 0,
  837. noQualifiedQuantity: 0,
  838. msg: '',
  839. sumReportQuantity,
  840. sumQualifiedQuantity,
  841. sumNoQualifiedQuantity,
  842. ruleId: this.ruleId,
  843. outputType: this.outputType,
  844. produceTaskId: this.produceTaskId,
  845. produceTaskInstanceId: this.produceTaskInstanceId,
  846. produceTaskName: this.produceTaskName,
  847. workOrderId: this.workOrderId
  848. }
  849. ];
  850. this.$emit('update:outputDetails', this.localOutputDetails);
  851. } else {
  852. this.$message.warning('未配置BOM标准产出信息');
  853. }
  854. },
  855. // 获取bom的产出清单
  856. async getMaterialQuotaInfo() {
  857. if (this.bomCategoryId && this.produceTaskId) {
  858. const data = await getMaterialQuotaInfo(
  859. this.bomCategoryId,
  860. this.produceTaskId
  861. );
  862. console.log('this.materialQuotaInfo', data);
  863. if (JSON.stringify(data) === '{}') {
  864. this.materialQuotaInfo = this.materialQuota;
  865. return;
  866. }
  867. if (data.materialQuota) {
  868. // 过滤数据
  869. data.materialQuota = data.materialQuota.filter((i) => {
  870. return i.isReworkBom != 1;
  871. });
  872. } else {
  873. data.materialQuota = [];
  874. }
  875. this.materialQuotaInfo = data;
  876. console.log('this.materialQuotaInfo', this.materialQuotaInfo);
  877. }
  878. },
  879. // qualifiedQuantityMax 最大合格数量
  880. qualifiedQuantityMax(row) {
  881. return row.reportQuantity;
  882. },
  883. noQualifiedQuantityMax(row) {
  884. return row.reportQuantity;
  885. },
  886. selectedChange(row) {
  887. console.log('row', row);
  888. if (this.outputType != 1) return;
  889. if (row.selected) {
  890. // 判断是否存在
  891. const index = this.localOutputDetails.findIndex(
  892. (item) => item.categoryId === row.categoryId
  893. );
  894. if (index === -1) {
  895. const sumItem = this.sumOutputDetails.find(
  896. (i) => i.categoryCode === row.categoryCode
  897. );
  898. let sumQualifiedQuantity = 0;
  899. let sumNoQualifiedQuantity = 0;
  900. let sumReportQuantity = 0;
  901. if (sumItem) {
  902. sumQualifiedQuantity = sumItem.sumQualifiedQuantity;
  903. sumNoQualifiedQuantity = sumItem.sumNoQualifiedQuantity;
  904. sumReportQuantity = sumItem.sumReportQuantity;
  905. }
  906. // 不存在则添加
  907. this.localOutputDetails.push({
  908. ...row,
  909. id: null,
  910. reportQuantity: 0,
  911. reportQuantityCopy: 0,
  912. qualifiedQuantity: 0,
  913. noQualifiedQuantity: 0,
  914. msg: '',
  915. sumReportQuantity,
  916. sumQualifiedQuantity,
  917. sumNoQualifiedQuantity,
  918. ruleId: this.ruleId,
  919. outputType: this.outputType,
  920. bomCategoryId: this.bomCategoryId,
  921. produceTaskId: this.produceTaskId,
  922. produceTaskInstanceId: this.produceTaskInstanceId,
  923. produceTaskName: this.produceTaskName,
  924. workOrderId: this.workOrderId
  925. });
  926. } else {
  927. this.$message.warning('该物料已存在于产出清单中');
  928. }
  929. } else {
  930. // 取消选择则删除
  931. this.localOutputDetails = this.localOutputDetails.filter(
  932. (item) => !(item.categoryId === row.categoryId)
  933. );
  934. }
  935. console.log('this.localOutputDetails', this.localOutputDetails);
  936. this.$emit('update:outputDetails', this.localOutputDetails);
  937. },
  938. // getCategoryAndLevelByCategoryId 获取产品 在制品信息
  939. async getCategoryAndLevelByCategoryId() {
  940. const data = await getCategoryAndLevelByCategoryId(this.categoryId);
  941. this.categoryInfo = data;
  942. console.log('this.categoryInfo 在制品信息', this.categoryInfo);
  943. },
  944. // 在制品信息 设置产出物
  945. categoryInfoSetOutput() {
  946. if (this.categoryInfo) {
  947. const sumItem = this.sumOutputDetails.find(
  948. (i) => i.categoryCode == this.categoryInfo.categoryCode
  949. );
  950. let sumQualifiedQuantity = 0;
  951. let sumNoQualifiedQuantity = 0;
  952. let sumReportQuantity = 0;
  953. if (sumItem) {
  954. sumQualifiedQuantity = sumItem.sumQualifiedQuantity;
  955. sumNoQualifiedQuantity = sumItem.sumNoQualifiedQuantity;
  956. sumReportQuantity = sumItem.sumReportQuantity;
  957. }
  958. this.localOutputDetails = [
  959. {
  960. ...this.categoryInfo,
  961. id: null,
  962. reportQuantity: 0,
  963. reportQuantityCopy: 0,
  964. qualifiedQuantity: 0,
  965. noQualifiedQuantity: 0,
  966. msg: '',
  967. sumReportQuantity,
  968. sumQualifiedQuantity,
  969. sumNoQualifiedQuantity,
  970. ruleId: this.ruleId,
  971. outputType: this.outputType,
  972. produceTaskId: this.produceTaskId,
  973. produceTaskInstanceId: this.produceTaskInstanceId,
  974. produceTaskName: this.produceTaskName,
  975. workOrderId: this.workOrderId
  976. }
  977. ];
  978. }
  979. this.$emit('update:outputDetails', this.localOutputDetails);
  980. console.log('this.localOutputDetails', this.localOutputDetails);
  981. },
  982. // 计算报工数量最大值
  983. reportQuantitymax(row) {
  984. if (this.outputType == 1) {
  985. // 查询物料本身
  986. let pickItem = this.localPickDetails.find(
  987. (item) => item.categoryCode === row.categoryCode
  988. );
  989. if (!pickItem) {
  990. // 查询上到工序产出明细
  991. pickItem = this.preOutputDetails.find(
  992. (item) => item.categoryCode === row.categoryCode
  993. );
  994. }
  995. // 未找到物料,则不限制
  996. if (!pickItem) return Infinity;
  997. // 查询其他工单sumOutputDetails中已产生的bom标准产出和在制品的累计消耗数量
  998. let preCount = 0;
  999. if (this.materialQuotaInfo) {
  1000. const materialQuotaItem = this.materialQuotaInfo.materialQuota.find(
  1001. (item) => item.categoryCode === row.categoryCode
  1002. );
  1003. if (materialQuotaItem) {
  1004. // 计算比例
  1005. const proportion =
  1006. materialQuotaItem.count / this.materialQuotaInfo.baseCount;
  1007. if (this.materialQuotaInfo.standardOutput) {
  1008. // BOM标准产出
  1009. const preItem = this.sumOutputDetails.find(
  1010. (item) =>
  1011. item.categoryCode ===
  1012. this.materialQuotaInfo.standardOutput.categoryCode
  1013. );
  1014. if (preItem) {
  1015. preCount += this.formatNumber(
  1016. preItem.sumReportQuantity * proportion
  1017. );
  1018. }
  1019. }
  1020. if (this.categoryInfo) {
  1021. // 在制品
  1022. const preItem = this.sumOutputDetails.find(
  1023. (item) => item.categoryCode === this.categoryInfo.categoryCode
  1024. );
  1025. if (preItem) {
  1026. preCount += this.formatNumber(
  1027. preItem.sumReportQuantity * proportion
  1028. );
  1029. }
  1030. }
  1031. }
  1032. }
  1033. // 已执行,处理重新一键报工时,sumReportQuantity包含了当前报工数量
  1034. if (this.executeStatus == 2) {
  1035. const count =
  1036. pickItem.quantity -
  1037. (row.sumReportQuantity - row.reportQuantityCopy) -
  1038. preCount;
  1039. // 如果小于本次报工数量 则返回本次报工数量
  1040. if (count < row.reportQuantityCopy) {
  1041. return row.reportQuantityCopy;
  1042. } else {
  1043. return count;
  1044. }
  1045. } else {
  1046. return pickItem.quantity - pickItem.sumReportQuantity - preCount;
  1047. }
  1048. }
  1049. if (row.outputType == 2 || row.outputType == 3) {
  1050. // 当前行为在制品 和 BOM标准产出
  1051. const preOutputItem = this.preOutputDetails.find(
  1052. (item) => item.categoryCode === row.categoryCode
  1053. );
  1054. // debugger;
  1055. // 存在则当前row为在制品或BOM标准产出
  1056. if (preOutputItem) {
  1057. // 区分已执行状态
  1058. if (this.executeStatus === 2) {
  1059. return (
  1060. preOutputItem.quantity -
  1061. (row.sumReportQuantity - row.reportQuantityCopy)
  1062. );
  1063. }
  1064. return preOutputItem.quantity - row.sumReportQuantity;
  1065. }
  1066. // 基于物料配额限制最大可报工数量(兼容已缓存/已保存一次的编辑场景,并区分已执行状态)
  1067. if (!this.materialQuotaInfo) return Infinity;
  1068. const quota = this.materialQuotaInfo.materialQuota || [];
  1069. if (!quota.length) return Infinity;
  1070. const isExecuted = this.executeStatus === 2;
  1071. const { baseCount } = this.materialQuotaInfo;
  1072. if (!baseCount) return Infinity;
  1073. // 计算每个物料的最大可报工数量
  1074. const maxQuantities = quota.map((item) => {
  1075. let pickItem = this.localPickDetails.find(
  1076. (p) => p.categoryCode === item.categoryCode
  1077. );
  1078. // 从上一道工序产出物中找
  1079. if (!pickItem) {
  1080. pickItem = this.preOutputDetails.find(
  1081. (p) => p.categoryCode === item.categoryCode
  1082. );
  1083. }
  1084. if (!pickItem) {
  1085. return Infinity;
  1086. }
  1087. // 单位产出所需物料比例
  1088. const proportion = item.count / baseCount;
  1089. // 查询其他工单 sumOutputDetails 中已产生的 BOM 标准产出和在制品的累计消耗数量
  1090. let preOutputConsumedProportion = 0;
  1091. // BOM标准产出
  1092. if (
  1093. this.materialQuotaInfo &&
  1094. this.materialQuotaInfo.standardOutput &&
  1095. row.categoryCode !==
  1096. this.materialQuotaInfo.standardOutput.categoryCode
  1097. ) {
  1098. const preStd = this.sumOutputDetails.find(
  1099. (s) =>
  1100. s.categoryCode ===
  1101. this.materialQuotaInfo.standardOutput.categoryCode
  1102. );
  1103. if (preStd) {
  1104. preOutputConsumedProportion += this.formatNumber(
  1105. preStd.sumReportQuantity * proportion
  1106. );
  1107. }
  1108. }
  1109. // 在制品
  1110. if (
  1111. this.categoryInfo &&
  1112. row.categoryCode !== this.categoryInfo.categoryCode
  1113. ) {
  1114. const preWip = this.sumOutputDetails.find(
  1115. (s) => s.categoryCode === this.categoryInfo.categoryCode
  1116. );
  1117. if (preWip) {
  1118. preOutputConsumedProportion += this.formatNumber(
  1119. preWip.sumReportQuantity * proportion
  1120. );
  1121. }
  1122. }
  1123. // 已执行,处理重新一键报工时,sumReportQuantity包含了当前报工数量
  1124. let consumedQuantity = isExecuted
  1125. ? row.sumReportQuantity - row.reportQuantityCopy
  1126. : row.sumReportQuantity;
  1127. // 已执行的比例换算,换算为需要多少物料数量
  1128. const consumedProportion = this.formatNumber(
  1129. consumedQuantity * proportion
  1130. );
  1131. // 最大可报工数量
  1132. let maxQuantity =
  1133. (pickItem.quantity -
  1134. consumedProportion -
  1135. preOutputConsumedProportion) /
  1136. proportion;
  1137. // 向下取整
  1138. return Math.floor(maxQuantity);
  1139. });
  1140. // 返回最小的那个物料的最大可报工数量
  1141. return Math.min(...maxQuantities);
  1142. }
  1143. return Infinity;
  1144. },
  1145. // 判断生成产出清单的物料数量是合格
  1146. async validateOutputQuantities() {
  1147. if (this.localOutputDetails.length == 0) {
  1148. this.$message.warning(`产出清单不能为空`);
  1149. return false;
  1150. }
  1151. for (const item of this.localOutputDetails) {
  1152. if (!item.reportQuantity) {
  1153. this.$message.warning(
  1154. `请填写产出清单【${item.categoryName}】的当次报工数量`
  1155. );
  1156. return false;
  1157. }
  1158. }
  1159. if (this.outputType == 1) {
  1160. if (
  1161. this.localPickDetails.length == 0 &&
  1162. this.preOutputDetails.length == 0
  1163. ) {
  1164. this.$message.warning(`物料清单不能为空`);
  1165. return false;
  1166. }
  1167. for (const item of this.localOutputDetails) {
  1168. let pickitem = this.localPickDetails.find(
  1169. (pick) => pick.categoryCode == item.categoryCode
  1170. );
  1171. // 从上一道工序产出物中找
  1172. if (!pickitem) {
  1173. pickitem = this.preOutputDetails.find(
  1174. (pick) => pick.categoryCode == item.categoryCode
  1175. );
  1176. }
  1177. if (!pickitem) {
  1178. this.$message.warning(
  1179. `所需物料【${item.categoryName}】未在物料清单中找到`
  1180. );
  1181. return false;
  1182. }
  1183. if (item.reportQuantity > item.quantity) {
  1184. this.$message.error(
  1185. `物料【${item.categoryName}】的报工数量不能超过领料数量`
  1186. );
  1187. return false;
  1188. }
  1189. }
  1190. }
  1191. return true;
  1192. },
  1193. // 当次报工修改
  1194. reportQuantityChange(row) {
  1195. // 同步当前合格数量 和 不合格数量为0
  1196. // 默认全部合格
  1197. row.qualifiedQuantity = row.reportQuantity;
  1198. row.noQualifiedQuantity = 0;
  1199. this.$emit('update:outputDetails', this.localOutputDetails);
  1200. },
  1201. // qualifiedQuantityChange 当次合格数量变化 计算 noQualifiedQuantity不合格数量
  1202. qualifiedQuantityChange(row) {
  1203. row.noQualifiedQuantity = row.reportQuantity - row.qualifiedQuantity;
  1204. this.$emit('update:outputDetails', this.localOutputDetails);
  1205. },
  1206. // 不合格数量变化
  1207. noQualifiedQuantityChange(row) {
  1208. row.qualifiedQuantity = row.reportQuantity - row.noQualifiedQuantity;
  1209. this.$emit('update:outputDetails', this.localOutputDetails);
  1210. },
  1211. localOutputDetailsRefresh() {
  1212. if (this.outputType == 1) {
  1213. this.$emit('refresh', 'output');
  1214. } else if (this.outputType == 2) {
  1215. this.getCategoryAndLevelByCategoryId();
  1216. } else {
  1217. this.setMaterialQuotaInfo();
  1218. }
  1219. },
  1220. // 处理数字精度问题,不使用toFixed,避免4舍5入
  1221. formatNumber(value, decimalPlaces = 4) {
  1222. const factor = Math.pow(10, decimalPlaces);
  1223. return Math.floor(value * factor) / factor;
  1224. }
  1225. }
  1226. };
  1227. </script>
  1228. <style></style>