addSample.vue 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289
  1. <template>
  2. <ele-modal
  3. :visible.sync="visible"
  4. :title="title"
  5. width="80%"
  6. append-to-body
  7. :maxable="true"
  8. @close="cancel"
  9. >
  10. <div class="switch" v-if="type == 'view'">
  11. <div class="switch_left">
  12. <ul>
  13. <li
  14. v-for="item in tabOptions"
  15. :key="item.key"
  16. :class="{ active: activeComp == item.key }"
  17. @click="activeComp = item.key"
  18. >
  19. {{ item.name }}
  20. </li>
  21. </ul>
  22. </div>
  23. </div>
  24. <el-form
  25. v-show="activeComp === 'main'"
  26. ref="form"
  27. :model="form"
  28. :rules="rules"
  29. label-width="120px"
  30. class="el-form-box"
  31. :disabled="type == 'view'"
  32. >
  33. <header-title title="基本信息"></header-title>
  34. <el-row>
  35. <el-col :span="8">
  36. <el-form-item label="质检工单编码:" prop="qualityWorkOrderCode">
  37. <el-input
  38. :disabled="!isSampleRecord || (isSampleRecord && type != 'add')"
  39. readonly
  40. v-model="form.qualityWorkOrderCode"
  41. placeholder=" "
  42. @click.native="$refs.inspectionWorkDialog.open()"
  43. />
  44. </el-form-item>
  45. </el-col>
  46. <el-col :span="8">
  47. <el-form-item label="质检工单名称:" prop="qualityWorkOrderName">
  48. <el-input
  49. disabled
  50. v-model="form.qualityWorkOrderName"
  51. placeholder=" "
  52. />
  53. </el-form-item>
  54. </el-col>
  55. <el-col :span="8">
  56. <el-form-item label="来源单号:" prop="sourceCode">
  57. <el-input
  58. disabled
  59. :value="form.qualityPlanCode || form.workOrderCode"
  60. placeholder=" "
  61. />
  62. </el-form-item>
  63. </el-col>
  64. <el-col :span="8">
  65. <el-form-item label="类型:" prop="qualityType">
  66. <DictSelection
  67. dictName="质检计划类型"
  68. v-model="form.qualityType"
  69. disabled
  70. ></DictSelection>
  71. </el-form-item>
  72. </el-col>
  73. <el-col :span="8">
  74. <el-form-item label="编码:" prop="productCode">
  75. <el-input disabled v-model="form.productCode" placeholder=" " />
  76. </el-form-item>
  77. </el-col>
  78. <el-col :span="8">
  79. <el-form-item label="名称:" prop="productName">
  80. <el-input disabled v-model="form.productName" placeholder=" " />
  81. </el-form-item>
  82. </el-col>
  83. <el-col :span="8">
  84. <el-form-item label="批次号:" prop="batchNo">
  85. <el-input disabled v-model="form.batchNo" placeholder=" " />
  86. </el-form-item>
  87. </el-col>
  88. <el-col :span="8">
  89. <el-form-item label="规格:" prop="specification">
  90. <el-input disabled v-model="form.specification" placeholder=" " />
  91. </el-form-item>
  92. </el-col>
  93. <el-col :span="8">
  94. <el-form-item label="型号:" prop="modelType">
  95. <el-input disabled v-model="form.modelType" placeholder=" " />
  96. </el-form-item>
  97. </el-col>
  98. <el-col :span="8">
  99. <el-form-item label="牌号:" prop="brandNo">
  100. <el-input disabled v-model="form.brandNo" placeholder=" " />
  101. </el-form-item>
  102. </el-col>
  103. <el-col :span="8">
  104. <el-form-item label="总数:" prop="total">
  105. <el-input disabled v-model="form.total" placeholder=" ">
  106. <template slot="append">
  107. {{ tableList[0]?.measureUnit }}
  108. </template>
  109. </el-input>
  110. </el-form-item>
  111. </el-col>
  112. <!-- <el-col :span="8">
  113. <el-form-item label="样品数:" prop="sampleQuantity">
  114. <el-input disabled v-model="form.sampleQuantity" placeholder=" ">
  115. <template slot="append">
  116. {{ form.qualityMode == 1 ? form.measureUnit : form.unit }}
  117. </template>
  118. </el-input>
  119. </el-form-item>
  120. </el-col> -->
  121. </el-row>
  122. <header-title title="来源清单"></header-title>
  123. <ele-pro-table
  124. ref="sourceTable"
  125. :columns="tableColumns"
  126. :datasource="tableList"
  127. :initLoad="false"
  128. :needPage="false"
  129. height="300px"
  130. full-height="calc(100vh - 120px)"
  131. :selection.sync="selection"
  132. >
  133. <template v-slot:toolbar>
  134. 累计取样数量:{{ workSampleQuantity
  135. }}{{
  136. form.conditionType == '1' ? tableList[0]?.measureUnit : form.unit
  137. }}
  138. </template>
  139. </ele-pro-table>
  140. <header-title title="请样信息"> </header-title>
  141. <el-row>
  142. <el-col :span="8">
  143. <el-form-item label="请样目的:" prop="pleasePurpose">
  144. <el-input
  145. v-model="form.pleasePurpose"
  146. placeholder="请输入"
  147. ></el-input>
  148. </el-form-item>
  149. </el-col>
  150. </el-row>
  151. <el-row>
  152. <el-col :span="8">
  153. <el-form-item label="请样数量:" prop="pleaseQuantity">
  154. <el-input v-model="form.pleaseQuantity" placeholder="请输入">
  155. <template slot="append">
  156. {{ tableList[0]?.measureUnit }}
  157. </template>
  158. </el-input>
  159. </el-form-item>
  160. </el-col>
  161. <!-- <el-col :span="4">
  162. <el-form-item label="单位:" prop="pleaseUnit">
  163. <DictSelection
  164. dictName="计量单位"
  165. clearable
  166. v-model="form.pleaseUnit"
  167. filter-placeholder="请输入计量单位搜索"
  168. @change="changeSamUnit"
  169. ></DictSelection>
  170. </el-form-item>
  171. </el-col> -->
  172. </el-row>
  173. <header-title title="取样信息"> </header-title>
  174. <el-row>
  175. <el-col :span="8">
  176. <el-form-item label="质检方式:" prop="qualityMode">
  177. <DictSelection
  178. dictName="取样类型"
  179. v-model="form.qualityMode"
  180. @change="handleQualityModeChange"
  181. :disabled="form.isFirstSampling != '1'"
  182. ></DictSelection>
  183. </el-form-item>
  184. </el-col>
  185. <el-col :span="8">
  186. <el-form-item label="记录方法:" prop="recordingMethod">
  187. <el-select
  188. style="width: 100%"
  189. v-model="form.recordingMethod"
  190. placeholder="请选择"
  191. :disabled="form.isFirstSampling != '1'"
  192. >
  193. <el-option
  194. v-for="item in sampleQuantityList"
  195. :label="item.label"
  196. :value="item.value"
  197. :key="item.value"
  198. ></el-option>
  199. </el-select>
  200. </el-form-item>
  201. </el-col>
  202. </el-row>
  203. <el-row v-if="form.qualityMode == '2'">
  204. <el-col :span="8">
  205. <el-form-item label="取样:" prop="conditionType">
  206. <el-select
  207. style="width: 100%"
  208. v-model="form.conditionType"
  209. placeholder="请选择"
  210. :disabled="form.isFirstSampling != '1'"
  211. >
  212. <el-option
  213. v-for="item in sampleNumberList"
  214. :label="item.label"
  215. :value="item.value"
  216. :key="item.value"
  217. ></el-option>
  218. </el-select>
  219. </el-form-item>
  220. </el-col>
  221. <el-col :span="16">
  222. <el-row>
  223. <el-col :span="6" v-if="form.conditionType == 2">
  224. <el-form-item prop="quantity">
  225. <el-input
  226. v-model="form.quantity"
  227. placeholder="请输入"
  228. ></el-input>
  229. </el-form-item>
  230. </el-col>
  231. <el-col :span="6" v-if="form.conditionType == 2">
  232. <el-form-item prop="unit" label-width="0">
  233. <DictSelection
  234. dictName="计量单位"
  235. clearable
  236. :disabled="form.isFirstSampling != '1'"
  237. v-model="form.unit"
  238. filter-placeholder="请输入计量单位搜索"
  239. ></DictSelection>
  240. </el-form-item>
  241. </el-col>
  242. <el-col :span="8" v-if="form.conditionType == 2">
  243. <el-form-item prop="portion" label="数量">
  244. <el-input
  245. v-model="form.portion"
  246. placeholder="请输入"
  247. ></el-input>
  248. </el-form-item>
  249. </el-col>
  250. <el-col :span="10" v-if="form.conditionType == 1">
  251. <el-form-item prop="portion" label="数量">
  252. <el-input
  253. v-model="form.portion"
  254. placeholder="请输入"
  255. ></el-input>
  256. </el-form-item>
  257. </el-col>
  258. <el-col :span="10" v-if="form.conditionType == 1">
  259. <el-form-item prop="unit" label="单位">
  260. <el-select
  261. v-model="form.packingUnit"
  262. placeholder="请选择"
  263. :disabled="form.isFirstSampling != '1'"
  264. >
  265. <el-option
  266. v-for="item in packingSpecificationOption"
  267. :key="item.id"
  268. :label="item.conversionUnit"
  269. :value="item.id"
  270. @click.native="handlePackingUnitChange(item)"
  271. >
  272. </el-option>
  273. </el-select>
  274. </el-form-item>
  275. </el-col>
  276. <el-col
  277. :span="4"
  278. style="text-align: right"
  279. v-if="form.conditionType == 2 && type != 'view'"
  280. >
  281. <el-button
  282. type="primary"
  283. size="mini"
  284. @click="handleSampleSubmit"
  285. style="margin-right: 12px"
  286. >确认</el-button
  287. >
  288. </el-col>
  289. <el-col
  290. :span="4"
  291. style="text-align: right"
  292. v-if="form.conditionType == 1 && type != 'view'"
  293. >
  294. <el-button
  295. type="primary"
  296. size="mini"
  297. @click="handleSampleSubmit"
  298. style="margin-right: 12px"
  299. >确认</el-button
  300. >
  301. </el-col>
  302. </el-row>
  303. </el-col>
  304. </el-row>
  305. <header-title title="样品信息"></header-title>
  306. <ele-pro-table
  307. ref="showSampleListTable"
  308. :columns="tableColumns1"
  309. :datasource="sampleList"
  310. :needPage="false"
  311. height="400px"
  312. full-height="calc(100vh - 120px)"
  313. ></ele-pro-table>
  314. </el-form>
  315. <bpmDetail
  316. v-if="activeComp == 'bpm' && form.processInstanceId"
  317. :id="form.processInstanceId"
  318. ></bpmDetail>
  319. <template v-slot:footer>
  320. <el-button
  321. type="primary"
  322. @click="save()"
  323. v-loading="loading"
  324. v-if="type != 'view'"
  325. >确认</el-button
  326. >
  327. <el-button @click="cancel">关闭</el-button>
  328. </template>
  329. <inspectionWorkDialog
  330. ref="inspectionWorkDialog"
  331. @changeParent="changeParent"
  332. ></inspectionWorkDialog>
  333. </ele-modal>
  334. </template>
  335. <script>
  336. const defForm = {
  337. code: '', //编码
  338. name: '', //名称
  339. conditionType: '',
  340. quantity: '',
  341. unit: '',
  342. portion: '',
  343. qualityMode: '',
  344. recordingMethod: 1,
  345. pleaseQuantity: '',
  346. pleasePurpose: '',
  347. pleaseUnit: '',
  348. sampleQuantity: '',
  349. qualityWorkOrderId: '',
  350. qualityWorkOrderCode: '',
  351. qualityWorkOrderName: '',
  352. isFirstSampling: ''
  353. };
  354. import {
  355. queryQualityInventory,
  356. queryQualityTempleContent
  357. } from '@/api/inspectionWork';
  358. import {
  359. samplingrecordSave,
  360. getById,
  361. samplingrecordUpdate,
  362. samplingRecordsPage
  363. } from '@/api/samplingRecords';
  364. import bpmDetail from '@/views/bpm/processInstance/detail.vue';
  365. import inspectionWorkDialog from '@/views/inspectionWork/components/inspectionWorkDialog.vue';
  366. import { getCodeList, getCode } from '@/api/login';
  367. export default {
  368. components: { bpmDetail, inspectionWorkDialog },
  369. props: {
  370. isSampleRecord: {
  371. default: false
  372. }
  373. },
  374. data() {
  375. return {
  376. form: { ...defForm },
  377. activeComp: 'main',
  378. tabOptions: [
  379. { key: 'main', name: '取样详情' },
  380. { key: 'bpm', name: '流程详情' }
  381. ],
  382. workSampleQuantity: 0,
  383. visible: false,
  384. loading: false,
  385. rules: {
  386. qualityWorkOrderCode: [
  387. { required: true, message: '请选择质检工单', trigger: 'change' }
  388. ],
  389. qualityMode: [
  390. { required: true, message: '请选择质检方式', trigger: 'change' }
  391. ],
  392. recordingMethod: [
  393. { required: true, message: '请选择记录方法', trigger: 'change' }
  394. ],
  395. conditionType: [
  396. { required: true, message: '请选择取样类型', trigger: 'change' }
  397. ],
  398. quantity: [{ required: true, message: '请输入', trigger: 'change' }],
  399. portion: [{ required: true, message: '请输入', trigger: 'change' }],
  400. unit: [{ required: true, message: '请选择', trigger: 'change' }]
  401. },
  402. sampleQuantityList: [
  403. { label: '批样', value: 1 },
  404. { label: '单样全部', value: 2 }
  405. ],
  406. sampleNumberList: [
  407. { label: '取整样', value: 1 },
  408. { label: '取小样', value: 2 }
  409. ],
  410. selection: [],
  411. tableColumns1: [
  412. {
  413. label: '样品编码',
  414. prop: 'sampleCode',
  415. width: '200',
  416. align: 'center',
  417. fixed: 'left'
  418. },
  419. {
  420. label: '编码',
  421. prop: 'categoryCode',
  422. align: 'center',
  423. fixed: 'left'
  424. },
  425. {
  426. label: '名称',
  427. prop: 'categoryName',
  428. align: 'center'
  429. },
  430. { label: '批次号', prop: 'batchNo', align: 'center' },
  431. { label: '发货条码', prop: 'barcodes', align: 'center' },
  432. { label: '包装编码', prop: 'packageNo', align: 'center' },
  433. { label: '包装数量', prop: 'packingQuantity', align: 'center' },
  434. { label: '包装单位', prop: 'packingUnit', align: 'center' },
  435. { label: '计量数量', prop: 'measureQuantity', align: 'center' },
  436. { label: '计量单位', prop: 'measureUnit', align: 'center' },
  437. {
  438. label: '供应商名称',
  439. prop: 'supplierName',
  440. align: 'center',
  441. width: '120'
  442. },
  443. {
  444. label: '供应商代号',
  445. prop: 'supplierCode',
  446. align: 'center',
  447. width: '120'
  448. },
  449. {
  450. label: '物料代号',
  451. prop: 'materielDesignation',
  452. align: 'center',
  453. slot: 'materielDesignation',
  454. width: '120'
  455. },
  456. {
  457. label: '客户代号',
  458. prop: 'clientCode',
  459. align: 'center',
  460. slot: 'clientCode',
  461. width: '120'
  462. },
  463. {
  464. label: '刻码',
  465. prop: 'engrave',
  466. align: 'center',
  467. slot: 'engrave',
  468. width: '120'
  469. },
  470. {
  471. label: '机型',
  472. prop: 'modelKey',
  473. align: 'center',
  474. showOverflowTooltip: true
  475. },
  476. {
  477. label: '颜色',
  478. prop: 'colorKey',
  479. align: 'center',
  480. showOverflowTooltip: true
  481. },
  482. {
  483. label: '重量',
  484. prop: 'weight',
  485. align: 'center',
  486. slot: 'weight',
  487. width: '120'
  488. },
  489. {
  490. label: '重量单位',
  491. prop: 'weightUnit',
  492. align: 'center',
  493. width: 100
  494. },
  495. { label: '仓库', prop: 'warehouseName', align: 'center', width: 100 },
  496. { label: '货区', prop: 'areaName', align: 'center' },
  497. { label: '货架', prop: 'goodsShelfName', align: 'center' },
  498. { label: '货位', prop: 'goodsAllocationName', align: 'center' },
  499. { label: '生产日期', prop: 'productionDate', align: 'center' },
  500. { label: '采购日期', prop: 'purchaseDate', align: 'center' }
  501. ],
  502. tableColumns: [
  503. {
  504. columnKey: 'selection',
  505. type: 'selection',
  506. width: 45,
  507. align: 'center'
  508. },
  509. {
  510. columnKey: 'index',
  511. label: '序号',
  512. type: 'index',
  513. width: 55,
  514. align: 'center',
  515. fixed: 'left'
  516. },
  517. {
  518. label: '编码',
  519. prop: 'categoryCode',
  520. width: 150,
  521. align: 'center',
  522. showOverflowTooltip: true
  523. },
  524. {
  525. label: '名称',
  526. prop: 'categoryName',
  527. width: '150',
  528. align: 'center',
  529. width: 120,
  530. showOverflowTooltip: true
  531. },
  532. {
  533. label: '批次号',
  534. prop: 'batchNo',
  535. align: 'center',
  536. width: 120,
  537. showOverflowTooltip: true
  538. },
  539. {
  540. label: '发货条码',
  541. prop: 'barcodes',
  542. align: 'center',
  543. showOverflowTooltip: true
  544. },
  545. {
  546. label: '包装编码',
  547. prop: 'packageNo',
  548. align: 'center',
  549. width: 120,
  550. showOverflowTooltip: true
  551. },
  552. { label: '包装数量', prop: 'packingQuantity', align: 'center' },
  553. { label: '包装单位', prop: 'packingUnit', align: 'center' },
  554. { label: '计量数量', prop: 'measureQuantity', align: 'center' },
  555. { label: '计量单位', prop: 'measureUnit', align: 'center' },
  556. { label: '物料代号', prop: 'materielDesignation', align: 'center' },
  557. { label: '客户代号', prop: 'clientCode', align: 'center' },
  558. {
  559. label: '供应商名称',
  560. prop: 'supplierName',
  561. align: 'center',
  562. width: 120,
  563. showOverflowTooltip: true
  564. },
  565. {
  566. label: '供应商代号',
  567. prop: 'supplierCode',
  568. align: 'center',
  569. width: '120',
  570. showOverflowTooltip: true
  571. },
  572. { label: '刻码', prop: 'engrave', align: 'center' },
  573. {
  574. label: '机型',
  575. prop: 'modelKey',
  576. align: 'center',
  577. showOverflowTooltip: true
  578. },
  579. {
  580. label: '颜色',
  581. prop: 'colorKey',
  582. align: 'center',
  583. showOverflowTooltip: true
  584. },
  585. { label: '重量', prop: 'weight', align: 'center' },
  586. { label: '重量单位', prop: 'weightUnit', align: 'center' },
  587. {
  588. label: '仓库',
  589. prop: 'warehouseName',
  590. align: 'center',
  591. width: 120,
  592. showOverflowTooltip: true
  593. },
  594. { label: '货区', prop: 'areaName', align: 'center' },
  595. { label: '货架', prop: 'goodsShelfName', align: 'center' },
  596. { label: '货位', prop: 'goodsAllocationName', align: 'center' },
  597. {
  598. label: '生产日期',
  599. prop: 'productionDate',
  600. align: 'center',
  601. width: 120,
  602. showOverflowTooltip: true
  603. },
  604. {
  605. label: '采购日期',
  606. prop: 'purchaseDate',
  607. align: 'center',
  608. width: 120,
  609. showOverflowTooltip: true
  610. }
  611. ],
  612. packingSpecificationOption: [],
  613. sampleList: [],
  614. schemeList: [],
  615. tableList: [],
  616. type: 'add',
  617. title: ''
  618. };
  619. },
  620. computed: {},
  621. created() {},
  622. methods: {
  623. handlePackingUnitChange(val) {
  624. this.$set(this.form, 'unit', val.conversionUnit);
  625. },
  626. async open(type, row) {
  627. this.activeComp = 'main';
  628. this.visible = true;
  629. this.type = type;
  630. this.title =
  631. type == 'add' ? '取样' : type == 'edit' ? '修改取样' : '详情';
  632. if (type == 'add') {
  633. if (row) {
  634. this.init(row);
  635. }
  636. } else {
  637. this.getById(row.id);
  638. }
  639. },
  640. async init(row) {
  641. let data = await samplingRecordsPage({
  642. qualityWorkOrderId: row.id
  643. });
  644. let list = data.list.filter((item) => item.status === 0);
  645. if (list?.length) {
  646. this.getById(list[0].id);
  647. this.type = 'edit';
  648. this.title = '修改取样';
  649. } else {
  650. row.sourceCode = row.qualityPlanCode || row.workOrderCode;
  651. this.form = JSON.parse(JSON.stringify(row));
  652. this.form.qualityWorkOrderId = row.id;
  653. this.form.qualityWorkOrderCode = row.code;
  654. this.form.qualityWorkOrderName = row.name;
  655. this.workSampleQuantity = Number(row.sampleQuantity) || 0;
  656. if (!data?.list.length) {
  657. this.form.isFirstSampling = 1;
  658. } else {
  659. this.$set(this.form, 'unit', data?.list[0].unit);
  660. }
  661. await this.datasource(data?.list[0]?.unit);
  662. await this.queryQualityTempleContent(
  663. !data?.list.length && row.qualityMode == 1
  664. );
  665. }
  666. },
  667. getById(id) {
  668. getById(id).then((res) => {
  669. this.workSampleQuantity =
  670. Number(res.qualityWorkOrderVO.sampleQuantity) || 0;
  671. [
  672. 'id',
  673. 'code',
  674. 'name',
  675. 'createTime',
  676. 'createUserId',
  677. 'status',
  678. 'approvalStatus',
  679. 'approvalUserId',
  680. 'sampleQuantity',
  681. 'processInstanceId'
  682. ].forEach((it) => {
  683. delete res.qualityWorkOrderVO[it];
  684. });
  685. this.form = { ...res, ...res.qualityWorkOrderVO };
  686. this.datasource(this.form.unit);
  687. this.queryQualityTempleContent();
  688. if (this.form.qualityMode == 2) {
  689. if (res.qualityWorkOrderVO.conditionType == 1) {
  690. // if (res.unit != res.qualitySampleList[0].measureUnit) {
  691. // this.$set(this.form, 'portion', res.qualitySampleList.length);
  692. // } else {
  693. // }
  694. this.$set(this.form, 'portion', res.quantity);
  695. this.$set(this.form, 'quantity', 0);
  696. } else {
  697. this.$set(this.form, 'portion', res.copies);
  698. // this.$set(this.form, 'quantity', res.quantity / res.copies);
  699. }
  700. }
  701. this.sampleList = res.qualitySampleList;
  702. });
  703. },
  704. /* 查询质检模板内容 */
  705. async queryQualityTempleContent(is) {
  706. const res = await queryQualityTempleContent({
  707. qualityWorkerId: this.form.qualityWorkOrderId,
  708. page: 1,
  709. size: 10000
  710. });
  711. this.schemeList = res.list;
  712. if (is) {
  713. this.updatePackingList();
  714. }
  715. },
  716. cancel() {
  717. this.form = {
  718. ...defForm
  719. };
  720. this.schemeList = [];
  721. this.packingSpecificationOption = [];
  722. this.sampleList = [];
  723. this.tableList = [];
  724. this.visible = false;
  725. },
  726. changeParent(row) {
  727. this.init(row);
  728. },
  729. async datasource(unit) {
  730. const res = await queryQualityInventory({
  731. qualityWorkerId: this.form.qualityWorkOrderId,
  732. pageNum: 1,
  733. size: -1
  734. });
  735. let o = res.list[0];
  736. let listArr = [];
  737. if (o.measureUnit) {
  738. listArr.push({
  739. packageCellTotal: 1,
  740. conversionUnit: o.measureUnit,
  741. id: '111'
  742. });
  743. }
  744. if (o.packingUnit) {
  745. listArr.push({
  746. packageCellTotal: o.measureQuantity - 0,
  747. conversionUnit: o.packingUnit,
  748. id: '222'
  749. });
  750. }
  751. if (unit) {
  752. this.$set(
  753. this.form,
  754. 'packingUnit',
  755. listArr.find((item) => unit == item.conversionUnit)?.id
  756. );
  757. }
  758. this.form.pleaseUnit = res.list[0]?.measureUnit;
  759. res.list.map((el) => {
  760. el.weightProportion = el.weight
  761. ? (el.weight / el.measureQuantity).toFixed(4)
  762. : 0;
  763. el.weightProportion = el.weightProportion - 0;
  764. });
  765. this.packingSpecificationOption = listArr;
  766. this.tableList = res.list;
  767. return res;
  768. },
  769. handleSampleSubmit() {
  770. // this.$refs.ruleForm.validate((valid) => {
  771. // if (valid) {
  772. let params = {
  773. conditionType: this.form.conditionType,
  774. quantity: this.form.quantity,
  775. sampleUnit: this.form.unit,
  776. portion: this.form.portion
  777. };
  778. let specifications = this.packingSpecificationOption.find(
  779. (el) => el.id == this.form.packingUnit
  780. );
  781. this.sampleFn(params, specifications);
  782. // }
  783. // });
  784. },
  785. async sampleFn(data, specifications) {
  786. this.sampleList = [];
  787. if (!this.selection || this.selection.length == 0) {
  788. this.$message.warning('请先选择来源清单!');
  789. return;
  790. }
  791. const quantity = data.quantity || 1;
  792. const unit = data.sampleUnit;
  793. const sampleCount = Number(data.portion);
  794. try {
  795. // 2 取小样
  796. if (this.form.conditionType == 2) {
  797. if (!this.validateMeasureQuantity(quantity, unit, sampleCount))
  798. return; //取样数量验证
  799. if (unit === 'KG' && !this.validateWeight(quantity, sampleCount))
  800. return; // 若计量单位为重量,还需验证总重量是否足够
  801. await this.getNewFullSampleList(
  802. Math.ceil(sampleCount),
  803. // sampleCount,
  804. quantity,
  805. unit,
  806. specifications
  807. );
  808. } else {
  809. let isFlag = this.validateSampleQuantity(
  810. sampleCount,
  811. specifications
  812. );
  813. if (!isFlag) return;
  814. if (this.form.inspectionStandards == 1) {
  815. await this.getNewFullSampleList(
  816. Math.ceil(sampleCount),
  817. quantity,
  818. unit,
  819. specifications
  820. );
  821. } else {
  822. await this.handleWeightFullSample(sampleCount, specifications);
  823. }
  824. }
  825. } catch (error) {
  826. console.error('取样处理失败:', error);
  827. this.$message.error('取样处理失败');
  828. }
  829. },
  830. validateWeight(quantity, sampleCount) {
  831. let totalMaxPossible = 0;
  832. this.selection.forEach((item) => {
  833. totalMaxPossible += item.measureQuantity / quantity;
  834. });
  835. if (totalMaxPossible < sampleCount) {
  836. this.$message.info(`最大取样条数为${totalMaxPossible}`);
  837. return false;
  838. }
  839. let totalWeight = this.selection.reduce(
  840. (sum, item) => sum + item.weight,
  841. 0
  842. );
  843. const weightUnit = this.selection[0].weightUnit;
  844. if (weightUnit === 'G') totalWeight /= 1000;
  845. if (quantity * sampleCount > totalWeight) {
  846. this.$message.info('取样计量重量不能大于总计量重量');
  847. return false;
  848. }
  849. const invalidItem = this.selection.find((item) => {
  850. const weight =
  851. item.weightUnit === 'G' ? item.weight / 1000 : item.weight;
  852. return weight < quantity;
  853. });
  854. if (invalidItem) {
  855. this.$message.info('勾选条目重量小于取样重量');
  856. return false;
  857. }
  858. return true;
  859. },
  860. validateMeasureQuantity(quantity, unit, sampleCount) {
  861. if (quantity <= 0) {
  862. this.$message.info('取样计量数量必须大于0');
  863. return false;
  864. }
  865. const totalQuantity =
  866. this.selection.reduce((sum, item) => sum + item.measureQuantity, 0) -
  867. this.workSampleQuantity;
  868. if (
  869. this.selection[0].measureUnit === unit &&
  870. quantity * sampleCount > totalQuantity
  871. ) {
  872. this.$message.info('取样计量数量不能大于总计量数量');
  873. return false;
  874. }
  875. const invalidItem = this.selection.find(
  876. (item) => item.measureQuantity < quantity
  877. );
  878. if (invalidItem) {
  879. this.$message.info('条目计量数量小于取样计量数量');
  880. return false;
  881. }
  882. return true;
  883. },
  884. async handleWeightFullSample(sampleCount, specifications) {
  885. const dataList = [];
  886. let currentNum = sampleCount - this.selection.length;
  887. let currentNum1 = sampleCount;
  888. for (const item of this.selection) {
  889. const qualitySampleTemplateList = item.qualitySampleTemplateList
  890. ?.length
  891. ? JSON.parse(JSON.stringify(item.qualitySampleTemplateList))
  892. : JSON.parse(
  893. JSON.stringify(
  894. this.schemeList.map((item) => {
  895. item['qualityResults'] = 1;
  896. return item;
  897. })
  898. )
  899. );
  900. if (sampleCount >= this.selection.length) {
  901. dataList.push({
  902. ...item,
  903. measureQuantity: 1, //作为计量数量
  904. sampleCode: await getCode('sample_code'),
  905. qualitySampleTemplateList
  906. });
  907. } else {
  908. if (dataList.length < sampleCount) {
  909. dataList.push({
  910. ...item,
  911. measureQuantity: currentNum1 > 1 ? 1 : currentNum1, //作为计量数量
  912. sampleCode: await getCode('sample_code'),
  913. qualitySampleTemplateList
  914. });
  915. currentNum1 -= 1;
  916. }
  917. }
  918. }
  919. if (sampleCount > this.selection.length) {
  920. dataList.forEach((item) => {
  921. if (currentNum > 0) {
  922. let data = this.selection.find((val) => val.id == item.id);
  923. item['measureQuantity'] =
  924. data.measureQuantity - 1 - currentNum > 0
  925. ? currentNum + 1
  926. : data.measureQuantity;
  927. currentNum = currentNum - (data.measureQuantity - 1);
  928. }
  929. });
  930. }
  931. // 更改 从新计算 样品清单 取整样 数据
  932. if (specifications && specifications.id) {
  933. // let proportion = (obj.weight / obj.measureQuantity).toFixed(2);
  934. dataList.map((el) => {
  935. el.measureQuantity =
  936. el.measureQuantity * specifications.packageCellTotal;
  937. el.weight = this.formatNumber(
  938. el.measureQuantity,
  939. el.weightProportion
  940. );
  941. });
  942. }
  943. // 更改
  944. this.sampleList = dataList;
  945. this.getTotal();
  946. },
  947. // 小数点数据判断
  948. formatNumber(a, b, maxDecimals = 4) {
  949. if (a == 0 || b == 0 || !a || !b) {
  950. return 0;
  951. }
  952. // 计算乘积
  953. const product = a * b;
  954. // 转换为固定小数位数,然后转换为数字以去除末尾零
  955. const rounded = Number(product.toFixed(maxDecimals));
  956. // 转换为字符串检查是否需要显示小数部分
  957. const str = rounded.toString();
  958. // 如果包含小数点
  959. if (str.indexOf('.') !== -1) {
  960. // 移除末尾的零和小数点(如果后面没有数字了)
  961. return str.replace(/\.?0+$/, '');
  962. }
  963. return str;
  964. },
  965. //从来源数组取样到目标数组
  966. async getNewFullSampleList(
  967. sampleCount,
  968. sampleQuantity,
  969. sampleUnit,
  970. specifications
  971. ) {
  972. const sourceArray = this.selection;
  973. // 检查单位是否匹配
  974. const isUnitMismatch =
  975. sourceArray.length > 0 && sourceArray[0].measureUnit !== sampleUnit;
  976. // 创建副本并计算初始可取样数量
  977. const items = sourceArray.map((item) => ({
  978. ...item,
  979. remainingQuantity: isUnitMismatch
  980. ? Infinity
  981. : item['measureQuantity'], // 剩余可取样数量
  982. maxPossible: item['measureQuantity'] / sampleQuantity // 最大取样次数
  983. }));
  984. const result = [];
  985. let remainingCount = sampleCount;
  986. let count = Math.ceil(remainingCount);
  987. const codeList = await this.batchCodes(count);
  988. let codeIdx = 0;
  989. // 尽可能均匀地从各条目取样
  990. while (remainingCount > 0) {
  991. // 按剩余可取样比例排序
  992. items.sort(
  993. (a, b) =>
  994. b.remainingQuantity / b['measureQuantity'] -
  995. a.remainingQuantity / a['measureQuantity']
  996. );
  997. let distributed = false;
  998. for (const item of items) {
  999. // let values = remainingCount > 1 ? 1 : remainingCount;
  1000. if (
  1001. !isUnitMismatch ||
  1002. (item.remainingQuantity >= sampleQuantity && remainingCount > 0)
  1003. ) {
  1004. let qualitySampleTemplateList = [];
  1005. if (
  1006. item.qualitySampleTemplateList == undefined ||
  1007. item.qualitySampleTemplateList == null ||
  1008. item.qualitySampleTemplateList.length == 0
  1009. ) {
  1010. qualitySampleTemplateList = JSON.parse(
  1011. JSON.stringify(this.schemeList)
  1012. );
  1013. } else {
  1014. qualitySampleTemplateList = item.qualitySampleTemplateList;
  1015. }
  1016. // 添加到结果数组
  1017. // let sampleCode = await this.getSampleCode();
  1018. let sampleCode = codeList[codeIdx];
  1019. if (
  1020. this.form.conditionType == 1 &&
  1021. this.form.inspectionStandards == 1
  1022. ) {
  1023. result.push({
  1024. ...item,
  1025. // measureQuantity: values,
  1026. measureQuantity: 1,
  1027. sampleCode,
  1028. qualitySampleTemplateList
  1029. });
  1030. } else if (this.form.conditionType == 2) {
  1031. let weight = (item.weight / item.maxPossible).toFixed(2);
  1032. result.push({
  1033. ...item,
  1034. measureQuantity: sampleQuantity,
  1035. measureUnit: sampleUnit,
  1036. sampleCode,
  1037. weight,
  1038. qualitySampleTemplateList
  1039. });
  1040. }
  1041. // 更新剩余数量
  1042. if (!isUnitMismatch) {
  1043. item.remainingQuantity -= sampleQuantity;
  1044. }
  1045. remainingCount = (remainingCount - 1).toFixed(2);
  1046. codeIdx++;
  1047. distributed = true;
  1048. }
  1049. }
  1050. // 如果没有分配任何取样
  1051. if (!distributed) {
  1052. break;
  1053. }
  1054. }
  1055. // 判断是不是取整样
  1056. if (
  1057. this.form.conditionType == 1 &&
  1058. specifications &&
  1059. specifications.id
  1060. ) {
  1061. result.map((el) => {
  1062. el.measureQuantity =
  1063. el.measureQuantity * specifications.packageCellTotal;
  1064. el.weight = this.formatNumber(
  1065. el.measureQuantity,
  1066. el.weightProportion
  1067. );
  1068. });
  1069. }
  1070. this.sampleList = result;
  1071. if (this.sampleList.length > sampleCount) {
  1072. this.sampleList = this.sampleList.splice(0, sampleCount);
  1073. }
  1074. this.getTotal();
  1075. },
  1076. // 当计量类型 是数量的时候 取整样 校验
  1077. validateSampleQuantity(sampleCount, specifications) {
  1078. let packingUnit = this.selection[0].packingUnit?.trim() || '';
  1079. let totalS = 0;
  1080. let measureQuantityCount = 0;
  1081. let labelKey =
  1082. packingUnit == specifications.conversionUnit.trim()
  1083. ? 'packingQuantity'
  1084. : 'measureQuantity';
  1085. let labelName = labelKey == 'packingQuantity' ? '包装数量' : '计量数量';
  1086. totalS = this.selection.reduce((total, el) => total + el[labelKey], 0);
  1087. let formTotalS = this.tableList.reduce(
  1088. (total, el) => total + el.measureQuantity,
  1089. 0
  1090. );
  1091. if (sampleCount > totalS) {
  1092. this.$message.info(
  1093. `所填的条目数量不能超过所选${labelName}总和${totalS}`
  1094. );
  1095. return false;
  1096. }
  1097. if (labelKey == 'packingQuantity') {
  1098. measureQuantityCount =
  1099. sampleCount * this.selection[0].measureQuantity;
  1100. } else {
  1101. measureQuantityCount = sampleCount;
  1102. }
  1103. if (measureQuantityCount > formTotalS - this.workSampleQuantity) {
  1104. this.$message.info(
  1105. `取样数量不能大于${formTotalS - this.workSampleQuantity} ${
  1106. this.selection[0].measureUnit
  1107. }`
  1108. );
  1109. return false;
  1110. }
  1111. return true;
  1112. },
  1113. handleQualityModeChange(val) {
  1114. if (val == 1) {
  1115. this.updatePackingList();
  1116. } else {
  1117. this.sampleList = [];
  1118. this.getTotal();
  1119. }
  1120. },
  1121. // 全检
  1122. async updatePackingList() {
  1123. let list = this.tableList;
  1124. let sampleCount = this.form.total;
  1125. const dataList = [];
  1126. let count = list ? list.length : 0;
  1127. console.log(count, 'count');
  1128. const codeList = await this.batchCodes(count);
  1129. for (const [index, item] of list.entries()) {
  1130. const qualitySampleTemplateList = item.qualitySampleTemplateList
  1131. ?.length
  1132. ? JSON.parse(JSON.stringify(item.qualitySampleTemplateList))
  1133. : JSON.parse(
  1134. JSON.stringify(
  1135. this.schemeList.map((item) => {
  1136. item['qualityResults'] = 1;
  1137. return item;
  1138. })
  1139. )
  1140. );
  1141. // if (sampleCount >= list.length) {
  1142. dataList.push({
  1143. ...item,
  1144. measureQuantity: item.measureQuantity, //作为计量数量
  1145. sampleCode: codeList[index],
  1146. qualitySampleTemplateList
  1147. });
  1148. // }
  1149. }
  1150. console.log(dataList, 'dataList');
  1151. this.sampleList = dataList;
  1152. this.getTotal();
  1153. },
  1154. getTotal() {
  1155. this.form.sampleQuantity = this.sampleList
  1156. .reduce((total, el) => total + Number(el.measureQuantity), 0)
  1157. .toFixed(2);
  1158. this.form.sampleWeight = this.sampleList
  1159. .reduce((total, el) => total + Number(el.weight), 0)
  1160. .toFixed(2);
  1161. },
  1162. async batchCodes(count) {
  1163. if (count <= 0) return;
  1164. let params = { count };
  1165. const res = await getCodeList('sample_code', params);
  1166. return res;
  1167. },
  1168. /* 保存编辑 */
  1169. save() {
  1170. if (this.type == 'add') {
  1171. [
  1172. 'id',
  1173. 'code',
  1174. 'name',
  1175. 'createTime',
  1176. 'createUserId',
  1177. 'status',
  1178. 'approvalStatus',
  1179. 'approvalUserId'
  1180. ].forEach((key) => {
  1181. delete this.form[key];
  1182. });
  1183. }
  1184. let data = JSON.parse(JSON.stringify(this.form));
  1185. let api =
  1186. this.type == 'add' ? samplingrecordSave : samplingrecordUpdate;
  1187. this.$refs.form.validate((valid) => {
  1188. if (valid) {
  1189. if (!this.sampleList.length) {
  1190. this.$message.error('样品清单不能为空!');
  1191. return;
  1192. }
  1193. //抽检
  1194. if (data.qualityMode == 2) {
  1195. //取整样
  1196. if (data.conditionType == 1) {
  1197. data.quantity = data.portion;
  1198. // if (data.unit != data.measureUnit) {
  1199. // data.quantity = this.sampleList.reduce(
  1200. // (total, el) => total + Number(el.measureQuantity),
  1201. // 0
  1202. // );
  1203. // } else {
  1204. // data.quantity = this.form.portion;
  1205. // }
  1206. data.measureUnit = this.tableList[0].measureUnit;
  1207. } else {
  1208. data.measureUnit = data.unit;
  1209. data.copies = data.portion;
  1210. // data.quantity = data.quantity * data.copies;
  1211. }
  1212. }
  1213. this.loading = true;
  1214. api({
  1215. ...data,
  1216. sampleList: this.sampleList
  1217. })
  1218. .then((res) => {
  1219. this.$message.success('操作成功');
  1220. this.cancel();
  1221. this.$emit('reload');
  1222. })
  1223. .finally(() => {
  1224. this.loading = false;
  1225. });
  1226. }
  1227. });
  1228. }
  1229. }
  1230. };
  1231. </script>
  1232. <style lang="scss" scoped>
  1233. .basic-details-title {
  1234. margin: 10px 0;
  1235. }
  1236. .title {
  1237. font-size: 16px;
  1238. line-height: 45px;
  1239. }
  1240. .add-product {
  1241. width: 100%;
  1242. display: flex;
  1243. align-items: center;
  1244. justify-content: flex-end;
  1245. font-size: 30px;
  1246. color: #1890ff;
  1247. margin: 10px 0;
  1248. cursor: pointer;
  1249. }
  1250. </style>