index.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. <template>
  2. <el-card shadow="always" :body-style="{ padding: '10px' }">
  3. <div class="app-container">
  4. <el-row :gutter="10">
  5. <el-col :span="10">
  6. <div class="table-area">
  7. <el-button
  8. class="mb10"
  9. type="success"
  10. size="small"
  11. @click="handleRefresh"
  12. :icon="loading ? 'el-icon-loading' : 'el-icon-refresh'"
  13. :disabled="loading"
  14. >刷新
  15. </el-button>
  16. <el-table
  17. :data="leftTableData"
  18. border
  19. stripe
  20. @selection-change="handleSelectionChange"
  21. @cell-click="cellClick"
  22. highlight-current-row
  23. >
  24. <!-- <el-table-column type="selection" width="55" /> -->
  25. <el-table-column type="index" label="序号" width="50" />
  26. <el-table-column
  27. align="center"
  28. prop="customerName"
  29. label="客户名称"
  30. >
  31. </el-table-column>
  32. <el-table-column
  33. align="center"
  34. prop="saleOrderNo"
  35. label="销售单号"
  36. >
  37. </el-table-column>
  38. <el-table-column
  39. align="center"
  40. prop="noticeNumber"
  41. label="通知单号"
  42. >
  43. </el-table-column>
  44. <el-table-column
  45. align="center"
  46. prop="noticeDate"
  47. label="开单日期"
  48. >
  49. </el-table-column>
  50. </el-table></div
  51. ></el-col>
  52. <el-col :span="14">
  53. <div class="form-area">
  54. <el-row :gutter="20">
  55. <el-form
  56. :model="form"
  57. ref="form"
  58. label-width="80px"
  59. :inline="true"
  60. size="mini"
  61. :rules="rules"
  62. >
  63. <el-col :span="16">
  64. <el-form-item label="通知单号" prop="noticeNumber">
  65. <div class="text-area">
  66. <span class="mr10">{{ form.noticeNumber }}</span>
  67. <span>{{ form.documentTypeName }}</span>
  68. </div>
  69. </el-form-item>
  70. </el-col>
  71. <el-col :span="8">
  72. <el-form-item label="销售员" prop="salesman">
  73. {{ form.salesman }}
  74. </el-form-item>
  75. </el-col>
  76. <el-col :span="16">
  77. <el-form-item label="客户名称" prop="customerName">
  78. {{ form.customerName }}
  79. </el-form-item>
  80. </el-col>
  81. <el-col :span="8">
  82. <el-form-item label="售货单位" prop="sellingUnit">
  83. {{ form.sellingUnit }}
  84. </el-form-item>
  85. </el-col>
  86. <el-col :span="16">
  87. <el-form-item label="货车信息" prop="truckRegistration">
  88. {{ form.truckRegistration }}
  89. </el-form-item>
  90. </el-col>
  91. <el-col :span="8">
  92. <el-form-item label="发货员" prop="deliveryClerk">
  93. {{ form.deliveryClerk }}
  94. </el-form-item>
  95. </el-col>
  96. <el-col :span="24">
  97. <el-form-item label="备注" prop="dispatchNoteRemark">
  98. {{ form.dispatchNoteRemark }}
  99. </el-form-item>
  100. </el-col>
  101. <el-col :span="12">
  102. <el-form-item label="发货日期" prop="deliveryDate">
  103. <el-date-picker
  104. v-model="form.deliveryDate"
  105. type="date"
  106. size="mini"
  107. placeholder="选择日期"
  108. >
  109. </el-date-picker>
  110. </el-form-item>
  111. </el-col>
  112. <el-col :span="12">
  113. <el-form-item label="发货仓库" prop="deliveryWarehouse">
  114. <el-select
  115. v-model="form.deliveryWarehouse"
  116. clearable
  117. filterable
  118. >
  119. <el-option
  120. v-for="item in warehouseList"
  121. :key="item.id"
  122. :label="item.warehouseName"
  123. :value="item.id"
  124. >
  125. </el-option>
  126. </el-select>
  127. </el-form-item>
  128. </el-col>
  129. <!-- <el-col :span="12">
  130. <el-form-item label="调拨仓库" prop="transferWarehouse">
  131. <el-select
  132. v-model="form.transferWarehouse"
  133. clearable
  134. filterable
  135. >
  136. <el-option
  137. v-for="item in warehouseList"
  138. :key="item.id"
  139. :label="item.warehouseName"
  140. :value="item.id"
  141. >
  142. </el-option>
  143. </el-select>
  144. </el-form-item>
  145. </el-col> -->
  146. <el-col :span="24">
  147. <el-form-item>
  148. <el-button type="primary" @click="outStockHandler"
  149. >出库
  150. </el-button>
  151. <el-button @click="refreshHandler">刷新</el-button>
  152. </el-form-item>
  153. </el-col>
  154. </el-form>
  155. </el-row>
  156. <el-table
  157. :data="saleProductInfoList"
  158. border
  159. stripe
  160. :span-method="objectSpanMethod"
  161. :row-class-name="tableRowClassName"
  162. >
  163. <el-table-column align="center" label="编码" prop="productCode">
  164. </el-table-column>
  165. <el-table-column align="center" label="品名" prop="productName">
  166. </el-table-column>
  167. <el-table-column align="center" label="批号" prop="lotNum" v-if="this.dlotNum">
  168. </el-table-column>
  169. <el-table-column
  170. align="center"
  171. label="规格"
  172. prop="productSpecifications"
  173. >
  174. </el-table-column>
  175. <el-table-column align="center" label="颜色" prop="productColor">
  176. </el-table-column>
  177. <!-- <el-table-column align="center" label="批号" prop="lotNum">
  178. </el-table-column>
  179. <el-table-column align="center" label="等级" prop="levels">
  180. </el-table-column> -->
  181. <el-table-column align="center" label="通知">
  182. <el-table-column
  183. align="center"
  184. label="重量"
  185. prop="actualWeight"
  186. >
  187. </el-table-column>
  188. </el-table-column>
  189. <el-table-column align="center" label="实发">
  190. <!-- <el-table-column
  191. align="center"
  192. label="总箱数"
  193. prop="coutBoxNum"
  194. >
  195. <template slot-scope="scope">
  196. <el-input
  197. v-model="scope.row.coutBoxNum"
  198. size="mini"
  199. @input="iptChange"
  200. ></el-input>
  201. </template>
  202. </el-table-column> -->
  203. <el-table-column
  204. align="center"
  205. label="箱数"
  206. prop="oldActualBoxNum"
  207. >
  208. <template slot-scope="scope">
  209. <el-input
  210. v-model="scope.row.oldActualBoxNum"
  211. size="mini"
  212. @input="iptChange"
  213. ></el-input>
  214. </template>
  215. </el-table-column>
  216. <!-- <el-table-column
  217. align="center"
  218. label="总重量"
  219. prop="coutweight"
  220. >
  221. <template slot-scope="scope">
  222. <el-input
  223. v-model="scope.row.coutweight"
  224. size="mini"
  225. @input="iptChange"
  226. ></el-input>
  227. </template>
  228. </el-table-column> -->
  229. <el-table-column
  230. align="center"
  231. label="重量"
  232. prop="oldActualWeight"
  233. >
  234. <template slot-scope="scope">
  235. <el-input
  236. v-model="scope.row.oldActualWeight"
  237. size="mini"
  238. @input="iptChange"
  239. ></el-input>
  240. </template>
  241. </el-table-column>
  242. </el-table-column>
  243. </el-table>
  244. </div>
  245. </el-col>
  246. </el-row>
  247. </div>
  248. </el-card>
  249. </template>
  250. <script>
  251. import {
  252. productInvoiceList,
  253. saleStorageDetails,
  254. queryDropDownBoxData,
  255. noticeOutStorage,
  256. oldNoticeOutStorage,
  257. } from "@/api/tablelist/commonTable";
  258. import { mapState } from "vuex";
  259. export default {
  260. name: "OutStock",
  261. props: [],
  262. dicts: ["billing_type", "document_type"],
  263. components: {},
  264. data() {
  265. return {
  266. spanArr: [], // 用于记录每个 productCode 的跨行信息
  267. loading: false,
  268. dlotNum: false,
  269. currentIndex: "",
  270. form: {
  271. noticeNumber: "", //通知单号
  272. documentType: "", //通知单类型
  273. documentTypeName: "",
  274. salesman: "", //销售员
  275. sellingUnit: "", //售货单位
  276. truckRegistration: "", //货车信息
  277. drawer: "", //开票员
  278. deliveryClerk: "", // 发货员
  279. dispatchNoteRemark: "", //备注
  280. customerName: "", //客户名称
  281. deliveryDate: new Date(), //发货日期
  282. deliveryWarehouse: "", //发货仓库
  283. transferWarehouse: "", //调拨仓库
  284. id: "",
  285. },
  286. leftTableData: [],
  287. warehouseList: [],
  288. saleProductInfoList: [],
  289. rules: {
  290. deliveryDate: [
  291. { required: true, message: "请选择发货日期", trigger: "change" },
  292. ],
  293. deliveryWarehouse: [
  294. { required: true, message: "请选择发货仓库", trigger: "change" },
  295. ],
  296. transferWarehouse: [
  297. { required: true, message: "请选择调拨仓库", trigger: "change" },
  298. ],
  299. },
  300. };
  301. },
  302. methods: {
  303. iptChange(value) {
  304. console.log(value);
  305. this.$forceUpdate(); //强制刷新
  306. },
  307. tableRowClassName({ row, rowIndex }) {
  308. if (!row.actualWeight && row.actualWeight != 0) {
  309. return "warning-row";
  310. }
  311. },
  312. objectSpanMethod({ row, column, rowIndex, columnIndex }) {
  313. // 重量
  314. if (columnIndex === 6 || columnIndex === 7 || columnIndex === 9) {
  315. const prevRow2 = this.saleProductInfoList[rowIndex - 1]; //上一行数据
  316. let nextRow2 = this.saleProductInfoList[rowIndex + 1]; //下一行数据
  317. // 当上一行的数据等于当前行数据时,当前行单元格隐藏
  318. if (
  319. prevRow2 &&
  320. prevRow2.productCode == row.productCode &&
  321. prevRow2.productColor == row.productColor
  322. ) {
  323. return { rowspan: 0, colspan: 0 };
  324. } else {
  325. // 反之,则循环判断若下一行数据等于当前行数据,则当前行开始进行合并单元格
  326. let countRowspan2 = 1; //用于合并计数多少单元格
  327. while (
  328. nextRow2 &&
  329. nextRow2.productCode == row.productCode &&
  330. nextRow2.productColor == row.productColor
  331. ) {
  332. nextRow2 = this.saleProductInfoList[++countRowspan2 + rowIndex];
  333. }
  334. if (countRowspan2 > 1) {
  335. // this.saleProductInfoList[rowIndex].coutBoxNum = 9;
  336. return { rowspan: countRowspan2, colspan: 1 };
  337. }
  338. }
  339. }
  340. },
  341. // 刷新回调
  342. async handleRefresh() {
  343. this.loading = true;
  344. await this.initData();
  345. await this.initWarehouse();
  346. this.loading = false;
  347. },
  348. // 左侧表格点击回调
  349. cellClick(row, column, cell, event) {
  350. this.currentIndex = this.leftTableData.findIndex(
  351. (item) => item.id == row.id
  352. );
  353. this.initFormData();
  354. },
  355. // 刷新回调
  356. refreshHandler() {
  357. this.initFormData();
  358. },
  359. // 出库回调
  360. outStockHandler() {
  361. this.$refs.form.validate(async (valid) => {
  362. if (valid) {
  363. this.$confirm("是否确认出库?", "提示", {
  364. confirmButtonText: "确定",
  365. cancelButtonText: "取消",
  366. type: "warning",
  367. })
  368. .then(async () => {
  369. let payLoad = { ...this.form };
  370. payLoad.oldProductInvoiceList = this.saleProductInfoList;
  371. payLoad.transferWarehouse = payLoad.deliveryWarehouse;
  372. payLoad.saleOrderNo =
  373. this.leftTableData[this.currentIndex || 0].saleOrderNo;
  374. if (!this.form.id) {
  375. return;
  376. }
  377. delete payLoad.documentTypeName;
  378. let res = await oldNoticeOutStorage(payLoad);
  379. if (res.code == 200) {
  380. this.$message.success("出库成功");
  381. this.currentIndex = 0;
  382. await this.initData();
  383. this.refreshHandler();
  384. } else {
  385. this.$message.error(res.msg);
  386. }
  387. })
  388. .catch(() => {
  389. this.$message({
  390. type: "info",
  391. message: "已取消出库",
  392. });
  393. });
  394. } else {
  395. return false;
  396. }
  397. });
  398. },
  399. handleSelectionChange() {},
  400. // 初始化仓库选项数据
  401. async initWarehouse() {
  402. try {
  403. let payload = [
  404. {
  405. basicMap: {
  406. tableName: "warehouse",
  407. },
  408. conditionMap: {
  409. warehouse_type: ["1"],
  410. },
  411. },
  412. ];
  413. let res = await queryDropDownBoxData(payload);
  414. if (res.code == 200) {
  415. this.warehouseList = res.data.resultMap?.warehouse || [];
  416. } else {
  417. throw new Error(res.msg);
  418. }
  419. } catch (error) {}
  420. },
  421. // 初始化数据
  422. async initData() {
  423. try {
  424. let payload = {
  425. isEnablePaging: false,
  426. status: 1,
  427. };
  428. let res = await productInvoiceList(payload);
  429. if (res.code == 200) {
  430. this.leftTableData = res.rows;
  431. if (this.leftTableData.length > 0) {
  432. this.currentIndex = 0;
  433. this.initFormData();
  434. }
  435. } else {
  436. throw new Error(res.msg);
  437. }
  438. } catch (error) {}
  439. },
  440. // 根据字典获取文件类型
  441. getdocumentTypeName(value) {
  442. return (
  443. this.dict.type.document_type.find((item) => {
  444. return item.value === value;
  445. })?.label || ""
  446. );
  447. },
  448. // 加载表单数据
  449. async initFormData() {
  450. // let { id, customerName } = this.leftTableData[this.currentIndex];
  451. let id = false,
  452. customerName;
  453. if (this.leftTableData[this.currentIndex]) {
  454. id = this.leftTableData[this.currentIndex].id;
  455. customerName = this.leftTableData[this.currentIndex].customerName;
  456. }
  457. if (!id) {
  458. //重置表单数据
  459. Object.assign(this.form, {
  460. noticeNumber: "", //通知单号
  461. documentType: "", //通知单类型
  462. documentTypeName: "", //通知单类型 名
  463. salesman: "", //销售员
  464. sellingUnit: "", //售货单位
  465. truckRegistration: "", //货车信息
  466. dispatchNoteRemark: "", //备注
  467. customerName: "", //客户名称
  468. deliveryClerk: "", //发货员
  469. id: "",
  470. });
  471. return;
  472. }
  473. try {
  474. let res = await saleStorageDetails(id);
  475. if (res.code == 200) {
  476. let {
  477. noticeNumber, //通知单号
  478. documentType, //通知单类型
  479. salesman, //销售员
  480. sellingUnit, //售货单位
  481. truckRegistration, //货车信息
  482. drawer, //开票员
  483. dispatchNoteRemark, //备注
  484. saleProductInfoList, //产品信息
  485. id,
  486. } = res.data;
  487. let documentTypeName = this.getdocumentTypeName(documentType);
  488. // let list = saleProductInfoList.sort( (a,b)=>{
  489. // let {productColor : colorA,productCode :codeA}=a
  490. // let {productColor : colorB,productCode : codeB}=b
  491. // return (colorA+codeA)-(colorB-codeB)
  492. // })
  493. this.saleProductInfoList = saleProductInfoList;
  494. // 使用 reduce 方法来累加相同 productCode 和 productColor 的第一条数据的 boxNum
  495. const codeColorSums = this.saleProductInfoList.reduce(
  496. (acc, curr, index) => {
  497. // 创建一个用于组合 productCode 和 productColor 的键
  498. const key = `${curr.productCode}-${curr.productColor}`;
  499. // 检查当前 key 是否已经存在
  500. if (!acc[key]) {
  501. // 如果不存在,添加 key 作为键,并将 boxNum 设置为当前值
  502. acc[key] = {
  503. firstIndex: index,
  504. sum: curr.boxNum,
  505. weight: curr.weight,
  506. count: 1,
  507. };
  508. } else {
  509. acc[key].count++; // 增加计数
  510. acc[key].sum += curr.boxNum;
  511. acc[key].weight += curr.weight;
  512. }
  513. return acc;
  514. },
  515. {}
  516. );
  517. this.saleProductInfoList.forEach((item, index) => {
  518. if (codeColorSums[`${item.productCode}-${item.productColor}`]) {
  519. item.coutBoxNum =
  520. codeColorSums[`${item.productCode}-${item.productColor}`].sum;
  521. item.coutweight =
  522. codeColorSums[
  523. `${item.productCode}-${item.productColor}`
  524. ].weight.toFixed(2);
  525. }
  526. });
  527. if(this.saleProductInfoList.length > 0){
  528. if(this.saleProductInfoList[0].lotNum == null || this.saleProductInfoList[0].lotNum == '' || this.saleProductInfoList[0].lotNum == undefined){
  529. this.dlotNum = false;
  530. }else{
  531. this.dlotNum = true;
  532. }
  533. }else{
  534. this.dlotNum = false;
  535. }
  536. Object.assign(this.form, {
  537. noticeNumber, //通知单号
  538. documentType, //通知单类型
  539. documentTypeName, //通知单类型 名
  540. salesman, //销售员
  541. sellingUnit, //售货单位
  542. truckRegistration, //货车信息
  543. dispatchNoteRemark, //备注
  544. customerName, //客户名称
  545. id,
  546. });
  547. this.form.deliveryClerk = this.nickName;
  548. } else {
  549. console.log(res);
  550. this.$message.error("网络异常");
  551. }
  552. } catch (error) {
  553. console.log(error);
  554. }
  555. },
  556. },
  557. computed: {
  558. ...mapState({
  559. nickName: (state) => state.user.nickName,
  560. }),
  561. },
  562. mounted() {
  563. this.initData();
  564. this.initWarehouse();
  565. },
  566. };
  567. </script>
  568. <style scoped lang="scss">
  569. .app-container {
  570. display: flex;
  571. width: 100%;
  572. .table-area {
  573. // width: 600px;
  574. }
  575. .form-area {
  576. // flex: 1;
  577. }
  578. }
  579. ::v-deep .el-table__body tr.current-row > td.el-table__cell {
  580. background-color: #55e905 !important;
  581. }
  582. .table-data > .gutter {
  583. display: table-cell !important;
  584. }
  585. ::v-deep .el-table .warning-row {
  586. color: red;
  587. }
  588. </style>