index.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. <template>
  2. <div>
  3. <el-card class="box-card">
  4. <el-tabs v-model="activeName" type="card" @tab-change="changeActiveName">
  5. <el-tab-pane label="待备料" name="first">
  6. <byTable
  7. :hideTable="true"
  8. :hidePagination="true"
  9. :source="sourceList.data"
  10. :pagination="sourceList.pagination"
  11. :config="config"
  12. :searchConfig="searchConfig"
  13. highlight-current-row
  14. :action-list="[
  15. {
  16. text: '打印备料单',
  17. action: () => outExcel(),
  18. },
  19. {
  20. text: '快捷出库',
  21. action: () => clickQuickDelivery(),
  22. },
  23. ]"
  24. @get-list="getList"
  25. @clickReset="clickReset">
  26. </byTable>
  27. <table class="table-class" border="0" cellpadding="0" cellspacing="0" v-loading="loading">
  28. <tr>
  29. <th style="width: 200px">BOM品号</th>
  30. <th style="min-width: 320px">BOM品名</th>
  31. <th style="width: 200px">SKU品号</th>
  32. <th style="width: 120px; text-align: center">数量小计</th>
  33. <th style="width: 140px; text-align: center">数量总计</th>
  34. </tr>
  35. <tbody v-for="(item, index) in sourceList.data" :key="index">
  36. <tr v-for="(itemSKU, indexSKU) in item.skuInfoList" :key="indexSKU">
  37. <td v-if="indexSKU === 0" :rowspan="item.skuInfoList.length">{{ item.bomSpecCode }}</td>
  38. <td v-if="indexSKU === 0" :rowspan="item.skuInfoList.length">{{ item.bomSpecName }}</td>
  39. <td>{{ itemSKU.skuSpecCode }}</td>
  40. <td style="text-align: center">{{ itemSKU.quantity }}</td>
  41. <td v-if="indexSKU === 0" :rowspan="item.skuInfoList.length" style="text-align: center">{{ item.totalQuantity }}</td>
  42. </tr>
  43. </tbody>
  44. </table>
  45. </el-tab-pane>
  46. <el-tab-pane label="已备料" name="second">
  47. <byTable
  48. :source="sourceListTwo.data"
  49. :pagination="sourceListTwo.pagination"
  50. :config="configTwo"
  51. :loading="loading"
  52. :searchConfig="searchConfigTwo"
  53. highlight-current-row
  54. @get-list="getListTwo"
  55. @clickReset="clickResetTwo">
  56. <template #blueprint="{ item }">
  57. <div>
  58. <img
  59. v-if="item.blueprint"
  60. style="margin-top: 3px; width: 40px; height: 40px; cursor: pointer; object-fit: contain; vertical-align: middle"
  61. v-lazy="item.blueprint"
  62. @click="openFile(item.blueprint)" />
  63. </div>
  64. </template>
  65. <template #size="{ item }">
  66. <span>{{ `${item.length} * ${item.width} * ${item.height}` }}</span>
  67. </template>
  68. </byTable>
  69. </el-tab-pane>
  70. </el-tabs>
  71. </el-card>
  72. <el-dialog title="打印" v-if="openPrint" v-model="openPrint" width="1200px">
  73. <div v-loading="loadingPrint">
  74. <div style="height: calc(100vh - 174px); overflow-y: auto; overflow-x: hidden">
  75. <div class="printBomList" id="printMe">
  76. <div class="t">生产备料单</div>
  77. <div class="time" style="text-align: right">
  78. {{ printTime }}
  79. </div>
  80. <table border="1" cellspacing="0" class="table">
  81. <thead>
  82. <tr>
  83. <td style="width: 54px; text-align: center">编号</td>
  84. <td style="width: 120px">图稿类型</td>
  85. <td style="width: 120px">规格</td>
  86. <td style="width: 120px">颜色</td>
  87. <td style="width: 120px">BOM品号</td>
  88. <td>图稿名称</td>
  89. <td style="width: 130px">SKU品号</td>
  90. <td style="width: 90px; text-align: center">数量小计</td>
  91. <td style="width: 90px; text-align: center">数量总计</td>
  92. </tr>
  93. </thead>
  94. <tbody v-if="formData && formData.length > 0">
  95. <tr v-for="(item, index) in formData" :key="index">
  96. <td style="text-align: center">{{ item.index }}</td>
  97. <td>{{ dictKeyValue(item.machinedPanel, useUserStore().allDict["charge_item"]) }}</td>
  98. <td :rowspan="item.specIndex" v-if="item.specStatus">{{ item.spec }}</td>
  99. <td :rowspan="item.colourIndex" v-if="item.colourStatus">{{ item.colour }}</td>
  100. <td :rowspan="item.bomIndex" v-if="item.bomStatus">{{ item.bomSpecCode }}</td>
  101. <td>{{ item.artworkName }}</td>
  102. <td>{{ item.skuSpecCode }}</td>
  103. <td style="text-align: center">{{ item.quantity }}</td>
  104. <td :rowspan="item.bomIndex" v-if="item.bomStatus" style="text-align: center">{{ item.totalQuantity }}</td>
  105. </tr>
  106. </tbody>
  107. </table>
  108. </div>
  109. </div>
  110. <div style="text-align: center; margin: 10px">
  111. <el-button @click="openPrint = false" size="large">取消</el-button>
  112. <el-button type="primary" v-print="printObj" size="large">打印</el-button>
  113. </div>
  114. </div>
  115. </el-dialog>
  116. <el-dialog title="快捷出库" v-if="openQuick" v-model="openQuick" width="90%">
  117. <Quick :pagination="sourceList.pagination" @clickCancel="clickCancel"></Quick>
  118. </el-dialog>
  119. </div>
  120. </template>
  121. <script setup>
  122. import byTable from "/src/components/byTable/index";
  123. import moment from "moment";
  124. import Quick from "/src/views/production/operation/batching/quick";
  125. const { proxy } = getCurrentInstance();
  126. const activeName = ref("first");
  127. const departmentList = ref([{ dictKey: "0", dictValue: "胜德体育" }]);
  128. const sourceList = ref({
  129. data: [],
  130. pagination: {
  131. bomSpecCode: "",
  132. bomSpecName: "",
  133. skuSpecCode: "",
  134. skuSpecName: "",
  135. departmentId: "1689164627162529793",
  136. },
  137. });
  138. const sourceListTwo = ref({
  139. data: [],
  140. pagination: {
  141. total: 0,
  142. pageNum: 1,
  143. pageSize: 10,
  144. type: "1",
  145. orderCode: "",
  146. orderWlnCode: "",
  147. bomSpecCode: "",
  148. bomSpecName: "",
  149. skuSpecCode: "",
  150. skuSpecName: "",
  151. departmentId: "",
  152. width: "",
  153. },
  154. });
  155. const loading = ref(false);
  156. const searchConfig = computed(() => {
  157. return [
  158. {
  159. type: "input",
  160. prop: "bomSpecCode",
  161. label: "BOM品号",
  162. },
  163. {
  164. type: "input",
  165. prop: "bomSpecName",
  166. label: "BOM品名",
  167. },
  168. {
  169. type: "input",
  170. prop: "skuSpecCode",
  171. label: "SKU品号",
  172. },
  173. {
  174. type: "input",
  175. prop: "skuSpecName",
  176. label: "SKU品名",
  177. },
  178. {
  179. type: "select",
  180. prop: "departmentId",
  181. data: departmentList.value,
  182. label: "事业部",
  183. clearable: true,
  184. },
  185. ];
  186. });
  187. const searchConfigTwo = computed(() => {
  188. return [
  189. {
  190. type: "input",
  191. prop: "orderCode",
  192. label: "订单号",
  193. },
  194. {
  195. type: "input",
  196. prop: "orderWlnCode",
  197. label: "万里牛单号",
  198. },
  199. {
  200. type: "input",
  201. prop: "bomSpecCode",
  202. label: "BOM品号",
  203. },
  204. {
  205. type: "input",
  206. prop: "bomSpecName",
  207. label: "BOM品名",
  208. },
  209. {
  210. type: "input",
  211. prop: "skuSpecCode",
  212. label: "SKU品号",
  213. },
  214. {
  215. type: "input",
  216. prop: "skuSpecName",
  217. label: "SKU品名",
  218. },
  219. {
  220. type: "select",
  221. prop: "departmentId",
  222. data: departmentList.value,
  223. label: "事业部",
  224. },
  225. {
  226. type: "input",
  227. prop: "width",
  228. label: "幅宽(cm)",
  229. },
  230. ];
  231. });
  232. const config = computed(() => {
  233. return [
  234. {
  235. attrs: {
  236. label: "BOM品号",
  237. prop: "bomSpecCode",
  238. width: 200,
  239. },
  240. },
  241. {
  242. attrs: {
  243. label: "BOM品名",
  244. prop: "bomSpecName",
  245. "min-width": 320,
  246. },
  247. },
  248. {
  249. attrs: {
  250. label: "SKU品号",
  251. prop: "skuSpecCode",
  252. width: 180,
  253. },
  254. },
  255. {
  256. attrs: {
  257. label: "数量",
  258. prop: "quantity",
  259. width: 120,
  260. },
  261. },
  262. ];
  263. });
  264. const configTwo = computed(() => {
  265. return [
  266. {
  267. attrs: {
  268. label: "设计图",
  269. slot: "blueprint",
  270. width: 80,
  271. },
  272. },
  273. {
  274. attrs: {
  275. label: "事业部",
  276. prop: "departmentName",
  277. width: 160,
  278. },
  279. },
  280. {
  281. attrs: {
  282. label: "BOM品号",
  283. prop: "bomSpecCode",
  284. width: 160,
  285. },
  286. },
  287. {
  288. attrs: {
  289. label: "BOM品名",
  290. prop: "bomSpecName",
  291. "min-width": 240,
  292. },
  293. },
  294. {
  295. attrs: {
  296. label: "SKU品号",
  297. prop: "skuSpecCode",
  298. width: 160,
  299. },
  300. },
  301. {
  302. attrs: {
  303. label: "SKU品名",
  304. prop: "skuSpecName",
  305. "min-width": 200,
  306. },
  307. },
  308. {
  309. attrs: {
  310. label: "尺寸(长宽高,cm)",
  311. slot: "size",
  312. width: 160,
  313. },
  314. },
  315. {
  316. attrs: {
  317. label: "数量",
  318. prop: "quantity",
  319. width: 100,
  320. },
  321. },
  322. {
  323. attrs: {
  324. label: "投产时间",
  325. prop: "createTime",
  326. width: 160,
  327. align: "center",
  328. },
  329. },
  330. {
  331. attrs: {
  332. label: "订单号",
  333. prop: "orderCode",
  334. width: 160,
  335. },
  336. },
  337. {
  338. attrs: {
  339. label: "万里牛单号",
  340. prop: "orderWlnCode",
  341. width: 160,
  342. },
  343. },
  344. ];
  345. });
  346. const getList = async (req, status) => {
  347. if (status) {
  348. sourceList.value.pagination = {
  349. departmentId: "1689164627162529793",
  350. };
  351. } else {
  352. sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
  353. }
  354. loading.value = true;
  355. proxy.post("/stockPreparation/uncompletedList", sourceList.value.pagination).then((res) => {
  356. sourceList.value.data = res;
  357. setTimeout(() => {
  358. loading.value = false;
  359. }, 200);
  360. });
  361. };
  362. getList();
  363. const clickReset = () => {
  364. getList("", true);
  365. };
  366. const getListTwo = async (req, status) => {
  367. if (status) {
  368. sourceListTwo.value.pagination = {
  369. pageNum: sourceListTwo.value.pagination.pageNum,
  370. pageSize: sourceListTwo.value.pagination.pageSize,
  371. };
  372. } else {
  373. sourceListTwo.value.pagination = { ...sourceListTwo.value.pagination, ...req };
  374. }
  375. loading.value = true;
  376. proxy.post("/stockPreparation/completedPage", sourceListTwo.value.pagination).then((res) => {
  377. sourceListTwo.value.data = res.rows;
  378. sourceListTwo.value.pagination.total = res.total;
  379. setTimeout(() => {
  380. loading.value = false;
  381. }, 200);
  382. });
  383. };
  384. const clickResetTwo = () => {
  385. getListTwo("", true);
  386. };
  387. const changeActiveName = (val) => {
  388. if (val === "first") {
  389. getList();
  390. } else {
  391. getListTwo();
  392. }
  393. };
  394. const getDemandData = () => {
  395. proxy.post("/department/page", { pageNum: 1, pageSize: 999 }).then((res) => {
  396. if (res.rows && res.rows.length > 0) {
  397. departmentList.value = departmentList.value.concat(
  398. res.rows.map((item) => {
  399. return {
  400. dictKey: item.id,
  401. dictValue: item.name,
  402. };
  403. })
  404. );
  405. }
  406. });
  407. };
  408. getDemandData();
  409. const openFile = (path) => {
  410. window.open(path);
  411. };
  412. const openPrint = ref(false);
  413. const printTime = ref("");
  414. const formData = ref([]);
  415. const loadingPrint = ref(false);
  416. const outExcel = () => {
  417. formData.value = [];
  418. printTime.value = moment().format("yyyy-MM-DD HH:mm:ss");
  419. loadingPrint.value = true;
  420. openPrint.value = true;
  421. proxy.post("/stockPreparation/printUncompletedList", sourceList.value.pagination).then((res) => {
  422. if (res && res.length > 0) {
  423. for (let i = 0; i < res.length; i++) {
  424. if (res[i].colourGroupingInfoList && res[i].colourGroupingInfoList.length > 0) {
  425. res[i].specIndex = 0;
  426. for (let j = 0; j < res[i].colourGroupingInfoList.length; j++) {
  427. res[i].colourGroupingInfoList[j].colourIndex = 0;
  428. let colourGroupingInfoList = res[i].colourGroupingInfoList[j];
  429. if (colourGroupingInfoList.uncompletedVoList && colourGroupingInfoList.uncompletedVoList.length > 0) {
  430. for (let x = 0; x < colourGroupingInfoList.uncompletedVoList.length; x++) {
  431. res[i].colourGroupingInfoList[j].uncompletedVoList[x].bomIndex = 0;
  432. let uncompletedVoList = colourGroupingInfoList.uncompletedVoList[x];
  433. if (uncompletedVoList.skuInfoList && uncompletedVoList.skuInfoList.length > 0) {
  434. for (let y = 0; y < uncompletedVoList.skuInfoList.length; y++) {
  435. res[i].specIndex++;
  436. res[i].colourGroupingInfoList[j].colourIndex++;
  437. res[i].colourGroupingInfoList[j].uncompletedVoList[x].bomIndex++;
  438. }
  439. }
  440. }
  441. }
  442. }
  443. }
  444. }
  445. }
  446. let list = [];
  447. if (res && res.length > 0) {
  448. let index = 0;
  449. for (let i = 0; i < res.length; i++) {
  450. if (res[i].colourGroupingInfoList && res[i].colourGroupingInfoList.length > 0) {
  451. let specStatus = true;
  452. for (let j = 0; j < res[i].colourGroupingInfoList.length; j++) {
  453. let colourStatus = true;
  454. let colourGroupingInfoList = res[i].colourGroupingInfoList[j];
  455. if (colourGroupingInfoList.uncompletedVoList && colourGroupingInfoList.uncompletedVoList.length > 0) {
  456. for (let x = 0; x < colourGroupingInfoList.uncompletedVoList.length; x++) {
  457. let bomStatus = true;
  458. let uncompletedVoList = colourGroupingInfoList.uncompletedVoList[x];
  459. if (uncompletedVoList.skuInfoList && uncompletedVoList.skuInfoList.length > 0) {
  460. for (let y = 0; y < uncompletedVoList.skuInfoList.length; y++) {
  461. let skuInfoList = uncompletedVoList.skuInfoList[y];
  462. index++;
  463. list.push({
  464. index: index,
  465. spec: res[i].spec,
  466. colour: colourGroupingInfoList.colour,
  467. bomSpecCode: uncompletedVoList.bomSpecCode,
  468. artworkName: skuInfoList.artworkName,
  469. skuSpecCode: skuInfoList.skuSpecCode,
  470. machinedPanel: skuInfoList.machinedPanel,
  471. quantity: skuInfoList.quantity,
  472. totalQuantity: uncompletedVoList.totalQuantity,
  473. specStatus: specStatus,
  474. specIndex: res[i].specIndex,
  475. colourStatus: colourStatus,
  476. colourIndex: res[i].colourGroupingInfoList[j].colourIndex,
  477. bomStatus: bomStatus,
  478. bomIndex: res[i].colourGroupingInfoList[j].uncompletedVoList[x].bomIndex,
  479. });
  480. specStatus = false;
  481. colourStatus = false;
  482. bomStatus = false;
  483. }
  484. }
  485. }
  486. }
  487. }
  488. }
  489. }
  490. }
  491. formData.value = Object.freeze(list);
  492. loadingPrint.value = false;
  493. });
  494. };
  495. const printObj = ref({
  496. id: "printMe",
  497. popTitle: "",
  498. extraCss: "https://cdn.bootcdn.net/ajax/libs/animate.css/4.1.1/animate.compat.css, https://cdn.bootcdn.net/ajax/libs/hover.css/2.3.1/css/hover-min.css",
  499. extraHead: '<meta http-equiv="Content-Language"content="zh-cn"/>',
  500. });
  501. const openQuick = ref(false);
  502. const clickQuickDelivery = () => {
  503. openQuick.value = true;
  504. };
  505. const clickCancel = (status) => {
  506. openQuick.value = false;
  507. if (status) {
  508. getList();
  509. }
  510. };
  511. </script>
  512. <style lang="scss" scoped>
  513. ::v-deep(.el-input-number .el-input__inner) {
  514. text-align: left;
  515. }
  516. .printBomList {
  517. width: 100%;
  518. .t {
  519. text-align: center;
  520. font-size: 26px;
  521. font-weight: 700;
  522. margin: 10px 0px;
  523. }
  524. .time {
  525. margin-bottom: 10px;
  526. }
  527. .table {
  528. width: 100%;
  529. td {
  530. padding: 10px;
  531. }
  532. }
  533. }
  534. :deep(.el-dialog) {
  535. margin-top: 10px !important;
  536. margin-bottom: 10px !important;
  537. }
  538. .table-class {
  539. width: 100%;
  540. font-size: 14px;
  541. border: 1px solid #eeeeee;
  542. }
  543. .table-class th {
  544. height: 35px;
  545. line-height: 35px;
  546. padding: 0 12px;
  547. text-align: left;
  548. background-color: #eeeeee !important;
  549. border-right: 1px solid #eeeeee;
  550. }
  551. .table-class td {
  552. height: 35px;
  553. line-height: 35px;
  554. padding: 8px 12px;
  555. text-align: left;
  556. border-bottom: 1px solid #eeeeee;
  557. border-right: 1px solid #eeeeee;
  558. }
  559. </style>