addPick.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687
  1. <template>
  2. <ele-modal
  3. title="新建领料单"
  4. :visible.sync="visible"
  5. v-if="visible"
  6. :before-close="handleClose"
  7. :close-on-click-modal="false"
  8. :close-on-press-escape="false"
  9. append-to-body
  10. :maxable="true"
  11. width="95%"
  12. >
  13. <div>
  14. <el-form :model="pickForm" ref="pickForm">
  15. <el-row :gutter="24">
  16. <el-col :span="6">
  17. <el-form-item label="领料单编号" prop="pickCode" label-width="90px">
  18. <el-input v-model="pickForm.pickCode" disabled=""></el-input>
  19. </el-form-item>
  20. </el-col>
  21. <el-col :span="6">
  22. <el-form-item label="领料单名称" prop="pickName" label-width="90px">
  23. <el-input v-model="pickForm.pickName"></el-input>
  24. </el-form-item>
  25. </el-col>
  26. <el-col :span="6">
  27. <el-button type="primary" @click="selectOrder">选择工单</el-button>
  28. </el-col>
  29. </el-row>
  30. </el-form>
  31. <div v-for="(item, idx) in workList" :key="idx">
  32. <el-form
  33. :ref="`form22${idx}`"
  34. :model="{ pickList: item }"
  35. :rules="tableRules"
  36. size="mini"
  37. label-position="left"
  38. >
  39. <div class="tableZ_box">
  40. <div class="row">
  41. <div class="col">
  42. <div class="name">生产工单号</div>
  43. <div class="content">{{ item.code }}</div>
  44. </div>
  45. <div class="col">
  46. <div class="name">产品编码</div>
  47. <div class="content">{{ item.productCode }}</div>
  48. </div>
  49. <div class="col">
  50. <div class="name">产品名称</div>
  51. <div class="content">{{ item.productName }}</div>
  52. </div>
  53. <div class="col">
  54. <div class="name">批次号</div>
  55. <div class="content">{{ item.batchNo }}</div>
  56. </div>
  57. <div class="col">
  58. <div class="name">型号</div>
  59. <div class="content">{{ item.model }}</div>
  60. </div>
  61. <div class="col">
  62. <div class="name">规格</div>
  63. <div class="content">{{ item.specification }}</div>
  64. </div>
  65. <div class="col">
  66. <div class="name">颜色</div>
  67. <div class="content">{{ item.colorKey }}</div>
  68. </div>
  69. <div class="col pd6">
  70. <el-button
  71. type="primary"
  72. size="mini"
  73. @click="openPicking(item.id, item)"
  74. >新增</el-button
  75. >
  76. </div>
  77. </div>
  78. </div>
  79. <div>
  80. <el-table
  81. :ref="`form222${idx}`"
  82. class="table_content"
  83. :max-height="300"
  84. :data="item.pickList"
  85. tooltip-effect="dark"
  86. style="width: 100%"
  87. stripe
  88. border
  89. >
  90. <el-table-column label="序号" type="index" width="60">
  91. <template slot-scope="{ row, $index }">
  92. {{ $index + 1 }}
  93. </template>
  94. </el-table-column>
  95. <el-table-column
  96. label="类型"
  97. prop="rootCategoryLevelId"
  98. width="80"
  99. >
  100. <template slot-scope="{ row, $index }">
  101. <el-tag size="mini">{{
  102. typeName[Number(row.rootCategoryLevelId)]
  103. }}</el-tag>
  104. </template>
  105. </el-table-column>
  106. <el-table-column
  107. label="编码"
  108. prop="assetCode"
  109. show-overflow-tooltip
  110. >
  111. <template slot-scope="{ row, $index }">
  112. <span
  113. v-if="
  114. Object.prototype.hasOwnProperty.call(row, 'isBom') &&
  115. row.isBom == 1
  116. "
  117. style="color: #faad14"
  118. >
  119. {{ row.categoryCode }}
  120. </span>
  121. <span>
  122. {{
  123. row.rootCategoryLevelId == 4 ? row.codeNumber : row.code
  124. }}</span
  125. >
  126. </template>
  127. </el-table-column>
  128. <el-table-column label="名称" prop="name" show-overflow-tooltip>
  129. <template slot-scope="{ row, $index }">
  130. <span
  131. v-if="
  132. Object.prototype.hasOwnProperty.call(row, 'isBom') &&
  133. row.isBom == 1
  134. "
  135. >
  136. {{ row.categoryName }}
  137. </span>
  138. <span> {{ row.name }}</span>
  139. </template>
  140. </el-table-column>
  141. <el-table-column
  142. label="型号"
  143. prop="modelType"
  144. show-overflow-tooltip
  145. >
  146. </el-table-column>
  147. <el-table-column
  148. label="规格"
  149. prop="specification"
  150. show-overflow-tooltip
  151. >
  152. </el-table-column>
  153. <el-table-column
  154. label="批次号"
  155. prop="batchNo"
  156. show-overflow-tooltip
  157. >
  158. </el-table-column>
  159. <el-table-column label="数量" prop="demandQuantity" width="160">
  160. <template slot-scope="{ row, $index }">
  161. <el-form-item>
  162. <el-input
  163. v-model="row.demandQuantity"
  164. @input="changeInput(row, $index, idx)"
  165. size="mini"
  166. style="width: 120px"
  167. >
  168. <template slot="append">{{ row.measuringUnit }}</template>
  169. </el-input>
  170. </el-form-item>
  171. </template>
  172. </el-table-column>
  173. <el-table-column
  174. label="计量库存数量"
  175. prop="availableCountBase"
  176. width="320"
  177. show-overflow-tooltip
  178. >
  179. <template slot-scope="{ row, $index }">
  180. <div v-for="it of row.warehouseList">
  181. <span
  182. v-if="it.availableCountBase != '0'"
  183. style="cursor: pointer"
  184. >{{ it.name ? it.name : it.warehouse_name }}库存数:<span
  185. style="color: green"
  186. >{{ it.availableCountBase }}</span
  187. >{{ row.measuringUnit }},
  188. <span v-if="it.lockQuantity || it.lockQuantity == 0"
  189. >锁库数:<span style="color: red">{{
  190. it.lockQuantity
  191. }}</span
  192. >{{ row.measuringUnit }}
  193. </span></span
  194. >
  195. </div>
  196. </template>
  197. </el-table-column>
  198. <el-table-column
  199. label="领料仓库"
  200. prop="warehouseId"
  201. width="180"
  202. show-overflow-tooltip
  203. >
  204. <template slot-scope="{ row, $index }">
  205. <div
  206. v-if="
  207. Object.prototype.hasOwnProperty.call(row, 'isBom') &&
  208. row.isBom == 1
  209. "
  210. >
  211. <el-select
  212. v-model="row.warehouseIdList"
  213. placeholder="请选择"
  214. filterable
  215. multiple
  216. @change="changeWarehouse(row, $index)"
  217. >
  218. <el-option
  219. v-for="item in row.warehouseList"
  220. :label="item.name"
  221. :value="item.id"
  222. :key="item.id"
  223. >
  224. </el-option>
  225. </el-select>
  226. </div>
  227. <div v-else>
  228. <el-select
  229. v-model="row.warehouseIdList"
  230. placeholder="请选择"
  231. filterable
  232. multiple
  233. @change="changeWarehouse(row, $index)"
  234. >
  235. <el-option
  236. v-for="item in row.warehouseList"
  237. :label="item.warehouse_name"
  238. :value="item.warehouse_id"
  239. :key="item.warehouse_id"
  240. >
  241. </el-option>
  242. </el-select>
  243. </div>
  244. </template>
  245. </el-table-column>
  246. <el-table-column label="操作" fixed="right" width="100px">
  247. <template slot-scope="{ $index, row }">
  248. <el-link type="danger" @click="removeItem(idx, $index)"
  249. >删除</el-link
  250. >
  251. </template>
  252. </el-table-column>
  253. </el-table>
  254. </div>
  255. </el-form>
  256. </div>
  257. </div>
  258. <template slot="footer">
  259. <el-button size="mini" @click="handleClose">取 消</el-button>
  260. <el-button size="mini" type="primary" @click="save()">确 定</el-button>
  261. </template>
  262. <pickingList
  263. isType="pick"
  264. ref="pickingListRef"
  265. @allSelection="allSelection"
  266. ></pickingList>
  267. <produceOrder
  268. v-if="orderShow"
  269. @close="orderShow = false"
  270. @workSelect="workSelect"
  271. ></produceOrder>
  272. </ele-modal>
  273. </template>
  274. <script>
  275. import pickingList from '@/views/produce/components/picking/newPickingList.vue';
  276. import { workorderList, getCode } from '@/api/produce/workOrder';
  277. import produceOrder from './produceOrder.vue';
  278. import { typeName } from '@/views/produce/components/common.js';
  279. import { batchSave } from '@/api/produce/picking';
  280. import { listTask } from '@/api/produce/index';
  281. export default {
  282. components: {
  283. pickingList,
  284. produceOrder
  285. },
  286. props: {},
  287. data() {
  288. return {
  289. visible: true,
  290. workList: [],
  291. rules: {},
  292. pickForm: {
  293. pickCode: null,
  294. pickName: null
  295. },
  296. typeName,
  297. tableRules: {},
  298. produceTaskList: [],
  299. orderShow: false
  300. };
  301. },
  302. computed: {
  303. taskObj() {
  304. return this.$store.state.user.taskObj;
  305. }
  306. },
  307. watch: {},
  308. methods: {
  309. getTaskList() {
  310. listTask().then((res) => {
  311. this.produceTaskList = res;
  312. });
  313. },
  314. getList(ids, taskId) {
  315. const param = { ids, taskId };
  316. workorderList(param).then((res) => {
  317. console.log(res, 'resres');
  318. this.workList = res.map((item) => {
  319. // 处理 pickList 并统一 warehouse 字段
  320. const pickList = item.bomDetailDTOS.map((it) => {
  321. const warehouseList = (it.warehouseList || []).map((wh) => ({
  322. ...wh,
  323. warehouse_id: wh.id,
  324. warehouse_name: wh.name
  325. }));
  326. return {
  327. ...it,
  328. warehouseIdList: it.warehouseId ? [it.warehouseId] : [],
  329. warehouseList
  330. };
  331. });
  332. return {
  333. ...item,
  334. pickList,
  335. bomDetailDTOS: [] // 清空原 bomDetailDTOS
  336. };
  337. });
  338. });
  339. },
  340. async getOrderCode() {
  341. this.pickForm.pickCode = await getCode('pick_order_code');
  342. },
  343. removeItem(idx, index) {
  344. this.workList[idx].pickList.splice(index, 1);
  345. },
  346. handleClose() {
  347. this.$emit('close', false);
  348. },
  349. openPicking(id, item) {
  350. this.$refs.pickingListRef.open(id, item);
  351. },
  352. allSelection(id, list) {
  353. // this.workList.forEach((e) => {
  354. // if (e.id == id) {
  355. // e.pickList = list;
  356. // this.$forceUpdate();
  357. // }
  358. // });
  359. console.log(id, list);
  360. list.forEach((item) => {
  361. item.code = item.categoryCode;
  362. item.name = item.categoryName;
  363. item.modelType = item.modelType ? item.modelType : item.categoryModel;
  364. item.measuringUnit = item.measuringUnit
  365. ? item.measuringUnit
  366. : item.measureUnit;
  367. item.unit = item.unit ? item.unit : item.measureUnit;
  368. });
  369. this.workList.forEach((e) => {
  370. if (e.id == id) {
  371. const newData = [];
  372. if (list.length != 0) {
  373. list.forEach((it) => {
  374. newData.push(this.deepCopy(it));
  375. });
  376. }
  377. // e.pickList = list;
  378. e.pickList = newData;
  379. this.$forceUpdate();
  380. }
  381. });
  382. },
  383. deepCopy(obj, hash = new WeakMap()) {
  384. if (obj === null) return null;
  385. if (obj instanceof Date) return new Date(obj);
  386. if (obj instanceof RegExp) return new RegExp(obj);
  387. if (typeof obj !== 'object' && typeof obj !== 'function') return obj;
  388. if (hash.has(obj)) return hash.get(obj);
  389. const result = Array.isArray(obj) ? [] : {};
  390. hash.set(obj, result);
  391. return Object.keys(obj).reduce((acc, key) => {
  392. acc[key] = this.deepCopy(obj[key], hash);
  393. return acc;
  394. }, result);
  395. },
  396. save() {
  397. if (this.workList.length > 0) {
  398. let bol;
  399. let _i;
  400. bol = this.workList.every((e, i) => {
  401. _i = i;
  402. return (
  403. Object.prototype.hasOwnProperty.call(e, 'pickList') &&
  404. e.pickList.length > 0
  405. );
  406. });
  407. if (!bol) {
  408. this.$message.warning(
  409. `生成工单${this.workList[_i].code}领料不能为空`
  410. );
  411. return false;
  412. }
  413. }
  414. if (this.workList.length > 0) {
  415. let name;
  416. let bol2;
  417. let _i;
  418. this.workList.forEach((e, i) => {
  419. _i = i;
  420. console.log(e.pickList);
  421. bol2 = e.pickList.every((y) => {
  422. name = y.name;
  423. return (
  424. Object.prototype.hasOwnProperty.call(y, 'demandQuantity') &&
  425. Number(y.demandQuantity) > 0
  426. );
  427. });
  428. });
  429. if (!bol2) {
  430. this.$message.warning(
  431. `${this.workList[_i].code}的${name}数量不能为空`
  432. );
  433. return false;
  434. }
  435. }
  436. let _arr = [];
  437. _arr = this.workList.map((m) => {
  438. m.instanceList = [];
  439. m.bomDetailDTOSList = [];
  440. m.pickList.forEach((e) => {
  441. if (
  442. Object.prototype.hasOwnProperty.call(e, 'isBom') &&
  443. e.isBom == 1
  444. ) {
  445. m.bomDetailDTOSList.push(e);
  446. } else {
  447. m.instanceList.push(e);
  448. }
  449. });
  450. m.workOrderId = m.id;
  451. delete m.id;
  452. return {
  453. ...m
  454. };
  455. });
  456. let param = {
  457. allPickList: _arr,
  458. pickName: this.pickForm.pickName,
  459. pickCode: this.pickForm.pickCode
  460. };
  461. batchSave(param).then((res) => {
  462. this.$message.success('领料成功');
  463. this.$emit('close', true);
  464. });
  465. },
  466. selectOrder() {
  467. this.orderShow = true;
  468. },
  469. workSelect(ids, taskId) {
  470. console.log(ids, taskId, 'ids, taskId');
  471. this.getList(ids, taskId);
  472. this.orderShow = false;
  473. },
  474. changeWarehouse(item, index) {},
  475. changeInput(item, index, idx) {
  476. const pickItem = this.workList[idx].pickList[index];
  477. let value = String(item.demandQuantity ?? '');
  478. value = value.replace(/[^\d.]/g, '');
  479. value = value
  480. .replace(/\.{2,}/g, '.')
  481. .replace('.', '$#$')
  482. .replace(/\./g, '')
  483. .replace('$#$', '.');
  484. if (value.includes('.')) {
  485. const [intPart, decPart] = value.split('.');
  486. value = `${intPart}.${decPart.slice(0, 4)}`;
  487. }
  488. this.$set(pickItem, 'demandQuantity', value);
  489. const demandQty = Number(value);
  490. const maxQty = item.warehouseList.reduce((sum, cur) => {
  491. return sum + Number(cur.availableCountBase || 0);
  492. }, 0);
  493. if (!demandQty) {
  494. this.$set(pickItem, 'warehouseIdList', []);
  495. return;
  496. }
  497. if (demandQty >= maxQty) {
  498. this.$set(pickItem, 'demandQuantity', maxQty);
  499. this.$set(
  500. pickItem,
  501. 'warehouseIdList',
  502. item.warehouseList.map((w) => w.warehouse_id)
  503. );
  504. return;
  505. }
  506. let total = 0;
  507. const idsList = [];
  508. for (const w of item.warehouseList) {
  509. total += Number(w.availableCountBase) || 0;
  510. idsList.push(w.warehouse_id);
  511. if (total >= demandQty) break;
  512. }
  513. this.$set(pickItem, 'warehouseIdList', idsList);
  514. }
  515. // changeInput(item, index, idx) {
  516. // if (Number(item.demandQuantity) >= Number(item.availableCountBase)) {
  517. // this.$set(
  518. // this.workList[idx].pickList[index],
  519. // 'demandQuantity',
  520. // Number(item.availableCountBase)
  521. // );
  522. // const idsList = [];
  523. // item.warehouseList.forEach((it) => {
  524. // idsList.push(it.id);
  525. // });
  526. // this.$set(
  527. // this.workList[idx].pickList[index],
  528. // 'warehouseIdList',
  529. // idsList
  530. // );
  531. // } else if (!Number(item.demandQuantity)) {
  532. // this.$set(this.workList[idx].pickList[index], 'warehouseIdList', []);
  533. // } else {
  534. // const idsList = [];
  535. // let totalNum = 0;
  536. // for (let i = 0; i < item.warehouseList.length; i++) {
  537. // totalNum += Number(item.warehouseList[i].availableCountBase);
  538. // if (Number(item.demandQuantity) > totalNum) {
  539. // idsList.push(item.warehouseList[i].id);
  540. // } else {
  541. // idsList.push(item.warehouseList[i].id);
  542. // break;
  543. // }
  544. // }
  545. // this.$set(
  546. // this.workList[0].pickList[index],
  547. // 'warehouseIdList',
  548. // idsList
  549. // );
  550. // }
  551. // }
  552. },
  553. created() {
  554. this.getTaskList();
  555. this.getOrderCode();
  556. }
  557. };
  558. </script>
  559. <style lang="scss" scoped>
  560. .table_content {
  561. margin-bottom: 10px;
  562. }
  563. .tableZ_box {
  564. border: 1px solid #e3e5e5;
  565. margin: 6px 0;
  566. &:last-child {
  567. border-bottom: none;
  568. }
  569. .row {
  570. width: 100%;
  571. display: flex;
  572. }
  573. .col {
  574. width: calc(100% / 5);
  575. display: flex;
  576. align-items: center;
  577. // min-width: 200px;
  578. min-height: 32px;
  579. border-bottom: 1px solid #e3e5e5;
  580. border-right: 1px solid #e3e5e5;
  581. &:last-child {
  582. border-right: none;
  583. }
  584. .name {
  585. display: flex;
  586. align-items: center;
  587. padding: 4px;
  588. width: 60px;
  589. height: 100%;
  590. background-color: #d0e4d5;
  591. color: #000;
  592. }
  593. .content {
  594. padding: 4px 6px;
  595. color: #000;
  596. }
  597. }
  598. .pd6 {
  599. padding: 0 6px;
  600. }
  601. }
  602. </style>
  603. <style>
  604. :v-deep .el-form-item__error {
  605. bottom: -6px !important;
  606. }
  607. </style>