InRequestForm.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  1. <template>
  2. <div class="app-container">
  3. <!-- 标题 -->
  4. <!-- <div class="app-header">
  5. <h2>{{ dialogTitle }}</h2>
  6. </div> -->
  7. <!-- 左上角按钮容器 -->
  8. <div class="buttons-container">
  9. <el-button
  10. type="primary"
  11. :disabled="formLoading"
  12. plain
  13. size="mini"
  14. @click="submitForm"
  15. >保 存</el-button
  16. >
  17. <el-button type="primary" plain size="mini" @click="add()"
  18. >新增明细</el-button
  19. >
  20. <el-button plain size="mini" @click="handleCancel">返 回</el-button>
  21. </div>
  22. <el-form
  23. ref="formRef"
  24. v-loading="formLoading"
  25. :model="formData"
  26. :rules="formRules"
  27. label-width="150px"
  28. >
  29. <el-col :span="12"
  30. ><el-form-item label="业务类型" prop="businessType">
  31. <el-select
  32. v-model="formData.businessType"
  33. placeholder="请选择业务类型"
  34. @change="changeBusinessType"
  35. >
  36. <el-option
  37. v-for="dict in getDictDatas('inout_business_type')"
  38. :key="dict.value"
  39. :label="dict.label"
  40. :value="dict.value"
  41. />
  42. </el-select> </el-form-item
  43. ></el-col>
  44. <el-col :span="12"
  45. ><el-form-item label="业务分类名称" prop="businessDescribe">
  46. <el-select
  47. v-model="formData.businessDescribe"
  48. :disabled="formData.businessType ? false : true"
  49. placeholder="请选择业务类型"
  50. @change="changeBusinessDescribe"
  51. >
  52. <el-option
  53. v-for="dict in businessDescribeList"
  54. :key="dict.label"
  55. :label="dict.label"
  56. :value="dict.label"
  57. />
  58. </el-select> </el-form-item
  59. ></el-col>
  60. <el-col :span="12"
  61. ><el-form-item label="优先级" prop="priority">
  62. <el-select
  63. v-model="formData.priority"
  64. :disabled="formData.businessType ? false : true"
  65. placeholder="请选择优先级"
  66. >
  67. <el-option
  68. v-for="dict in getDictDatas('priority')"
  69. :key="dict.value"
  70. :label="dict.label"
  71. :value="dict.value"
  72. />
  73. </el-select>
  74. </el-form-item>
  75. </el-col>
  76. <el-col :span="12">
  77. <el-form-item label="供应商编码" prop="supplierCode">
  78. <el-input
  79. v-model="formData.supplierCode"
  80. :disabled="formData.businessType ? false : true"
  81. placeholder="请输入供应商编码"
  82. />
  83. </el-form-item>
  84. </el-col>
  85. <el-col :span="12">
  86. <el-form-item label="客户编码" prop="customerCode">
  87. <el-input
  88. v-model="formData.customerCode"
  89. :disabled="formData.businessType ? false : true"
  90. placeholder="请输入客户编码"
  91. />
  92. </el-form-item>
  93. </el-col>
  94. <el-col :span="12">
  95. <el-form-item label="源单编号" prop="sourceOrderNo">
  96. <el-select
  97. v-model="formData.sourceOrderNo"
  98. filterable
  99. remote
  100. :disabled="formData.businessType ? false : true"
  101. reserve-keyword
  102. placeholder="请输入源单编号"
  103. :remote-method="remoteMethod"
  104. :loading="loading"
  105. @change="changeSourceOrderNo"
  106. >
  107. <el-option
  108. v-for="item in sourceOrderNoList"
  109. :key="item.sourceOrderNo"
  110. :label="item.sourceOrderNo"
  111. :value="item.sourceOrderNo"
  112. />
  113. </el-select>
  114. </el-form-item>
  115. </el-col>
  116. <el-col :span="12">
  117. <el-form-item label="预计出入库时间" prop="expectedTime">
  118. <el-date-picker
  119. v-model="formData.expectedTime"
  120. :disabled="formData.businessType ? false : true"
  121. clearable
  122. type="date"
  123. value-format="timestamp"
  124. placeholder="选择预计出入库时间"
  125. /> </el-form-item
  126. ></el-col>
  127. <el-col :span="12">
  128. <el-form-item label="实际出入库时间" prop="actualTime">
  129. <el-date-picker
  130. v-model="formData.actualTime"
  131. clearable
  132. :disabled="formData.businessType ? false : true"
  133. type="date"
  134. value-format="timestamp"
  135. placeholder="选择实际出入库时间"
  136. /> </el-form-item
  137. ></el-col>
  138. <el-col :span="12">
  139. <el-form-item label="备注" prop="remark">
  140. <el-input
  141. v-model="formData.remark"
  142. :disabled="formData.businessType ? false : true"
  143. placeholder="请输入备注"
  144. /> </el-form-item
  145. ></el-col>
  146. <el-col :span="12">
  147. <el-form-item label="存储地点" prop="warehouseId">
  148. <el-select
  149. v-model="formData.warehouseId"
  150. filterable
  151. remote
  152. :disabled="formData.businessType ? false : true"
  153. reserve-keyword
  154. placeholder="请输入存储地点"
  155. :remote-method="remoteWarehouse"
  156. :loading="loading"
  157. >
  158. <el-option
  159. v-for="item in warehouseList"
  160. :key="item.erpId"
  161. :label="item.name"
  162. :value="item.erpId"
  163. />
  164. </el-select>
  165. </el-form-item>
  166. </el-col>
  167. </el-form>
  168. <el-table :data="formData.list" border size="mini">
  169. <el-table-column
  170. label="源单编号"
  171. align="center"
  172. prop="sourceRequestId"
  173. width="160"
  174. show-overflow-tooltip
  175. />
  176. <el-table-column
  177. label="源单行号"
  178. align="center"
  179. prop="sourceLineNo"
  180. width="160"
  181. show-overflow-tooltip
  182. />
  183. <el-table-column
  184. label="物料编码"
  185. align="center"
  186. prop="materialNo"
  187. width="160"
  188. show-overflow-tooltip
  189. >
  190. <template v-slot="scope">
  191. <el-select
  192. v-model="scope.row.materialNo"
  193. filterable
  194. remote
  195. reserve-keyword
  196. placeholder="请选择物料编码"
  197. :remote-method="
  198. (query) => remoteMaterialSearch(query, 'code', scope.$index)
  199. "
  200. :loading="loading"
  201. @change="(value) => changeMaterial(value, scope.$index, 'code')"
  202. >
  203. <el-option
  204. v-for="item in materialNoList"
  205. :key="item.code"
  206. :label="item.code"
  207. :value="item.code"
  208. />
  209. </el-select>
  210. </template>
  211. </el-table-column>
  212. <el-table-column
  213. label="物料名称"
  214. align="center"
  215. prop="materialName"
  216. width="150"
  217. show-overflow-tooltip
  218. >
  219. <template v-slot="scope">
  220. <el-select
  221. v-model="scope.row.materialName"
  222. filterable
  223. remote
  224. reserve-keyword
  225. placeholder="请选择物料名称"
  226. :remote-method="
  227. (query) => remoteMaterialSearch(query, 'name', scope.$index)
  228. "
  229. :loading="loading"
  230. @change="(value) => changeMaterial(value, scope.$index, 'name')"
  231. >
  232. <el-option
  233. v-for="item in materialNameList"
  234. :key="item.code"
  235. :label="item.name"
  236. :value="item.name"
  237. />
  238. </el-select>
  239. </template>
  240. </el-table-column>
  241. <el-table-column
  242. label="客户编码"
  243. align="center"
  244. prop="customerCode"
  245. width="150"
  246. show-overflow-tooltip
  247. />
  248. <el-table-column
  249. label="客户名称"
  250. align="center"
  251. prop="customerName"
  252. width="160"
  253. show-overflow-tooltip
  254. />
  255. <el-table-column
  256. label="本次出货数量"
  257. align="center"
  258. prop="nowDeliveredQty"
  259. >
  260. <template slot-scope="scope">
  261. <el-input
  262. v-model="scope.row.nowDeliveredQty"
  263. @change="deliverChange"
  264. />
  265. </template>
  266. </el-table-column>
  267. <el-table-column
  268. label="已出货数量"
  269. align="center"
  270. prop="deliveredQty"
  271. width="120"
  272. />
  273. <el-table-column
  274. label="应出货数量"
  275. align="center"
  276. prop="shouldDeliveredQty"
  277. width="120"
  278. />
  279. <el-table-column
  280. label="申请数量"
  281. align="center"
  282. prop="requireQty"
  283. width="120"
  284. />
  285. <el-table-column
  286. label="单位"
  287. align="center"
  288. prop="unitName"
  289. width="150"
  290. show-overflow-tooltip
  291. />
  292. <el-table-column label="行备注" align="center" prop="remark">
  293. <template slot-scope="scope">
  294. <el-input v-model="scope.row.remark" />
  295. </template>
  296. </el-table-column>
  297. <el-table-column
  298. label="操作"
  299. align="center"
  300. fixed="right"
  301. width="150px"
  302. class-name="small-padding fixed-width"
  303. >
  304. <template v-slot="scope">
  305. <el-button
  306. size="mini"
  307. type="text"
  308. icon="el-icon-delete"
  309. @click="handleDelete(scope)"
  310. >删除</el-button
  311. >
  312. </template>
  313. </el-table-column>
  314. </el-table>
  315. <!-- 移除原有的form-footer -->
  316. </div>
  317. </template>
  318. <script>
  319. import * as InRequestApi from "@/api/wms/output/inrequest";
  320. // import ShipmentNotification from "./ShipmentNotification.vue";
  321. export default {
  322. name: "OutRequestForm",
  323. components: {
  324. // ShipmentNotification,
  325. },
  326. data() {
  327. return {
  328. materialNameList: [],
  329. materialNoList: [],
  330. sourceOrderNoList: [],
  331. businessDescribeList: [],
  332. warehouseList: [],
  333. loading: false,
  334. // 页面标题
  335. dialogTitle: "",
  336. // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
  337. formLoading: false,
  338. // 表单参数
  339. formData: {
  340. id: undefined,
  341. requestNo: undefined,
  342. requestType: undefined,
  343. businessType: undefined,
  344. businessCategory: undefined,
  345. businessDescribe: undefined,
  346. businessSubType: undefined,
  347. status: undefined,
  348. priority: undefined,
  349. warehouseId: undefined,
  350. relatedWarehouseId: undefined,
  351. supplierCode: undefined,
  352. customerCode: undefined,
  353. sourceOrderNo: undefined,
  354. expectedTime: undefined,
  355. actualTime: undefined,
  356. totalQty: undefined,
  357. totalSku: undefined,
  358. totalLine: undefined,
  359. remark: undefined,
  360. extendInfo: undefined,
  361. submitter: undefined,
  362. submitTime: undefined,
  363. auditor: undefined,
  364. auditTime: undefined,
  365. erpWriteFlag: undefined,
  366. erpErrMsg: undefined,
  367. erpBackId: undefined,
  368. list: [],
  369. },
  370. // 表单校验
  371. formRules: {
  372. requestNo: [
  373. { required: true, message: "申请单号不能为空", trigger: "blur" },
  374. ],
  375. requestType: [
  376. {
  377. required: true,
  378. message: "申请类型(0入库 1出库)不能为空",
  379. trigger: "change",
  380. },
  381. ],
  382. businessType: [
  383. {
  384. required: true,
  385. message:
  386. "业务类型(0采购入库 3生产退料 4成品入库 6销售退货 8委外退料 9委外入库 11其他入库 13转移调拨 14仓库盘点)不能为空",
  387. trigger: "change",
  388. },
  389. ],
  390. businessSubType: [
  391. {
  392. required: true,
  393. message: "业务子类型(0正常 1补料)不能为空",
  394. trigger: "change",
  395. },
  396. ],
  397. priority: [
  398. {
  399. required: true,
  400. message: "优先级(0普通 1紧急 2加急)不能为空",
  401. trigger: "blur",
  402. },
  403. ],
  404. },
  405. };
  406. },
  407. watch: {
  408. "$route.query.id": {
  409. immediate: true,
  410. handler(newId) {
  411. if (newId) {
  412. this.open(newId);
  413. } else {
  414. this.reset();
  415. }
  416. },
  417. },
  418. },
  419. created() {
  420. // 从路由参数获取ID
  421. const id = this.$route.query.id;
  422. if (id) {
  423. this.open(id);
  424. } else {
  425. this.dialogTitle = "新增";
  426. }
  427. },
  428. methods: {
  429. handleDelete(row) {
  430. console.log(row);
  431. this.formData.list.splice(row.$index, 1);
  432. },
  433. async remoteMaterialSearch(query, type, index) {
  434. if (query) {
  435. this.loading = true;
  436. try {
  437. const params = {};
  438. if (type === "code") {
  439. params.code = query;
  440. } else {
  441. params.name = query;
  442. }
  443. const {
  444. data: { list },
  445. } = await InRequestApi.getMaterialPage(params);
  446. // 每次搜索都重新赋值,保证列表始终是最新数据
  447. if (type === "code") {
  448. this.materialNoList = list || [];
  449. } else {
  450. this.materialNameList = list || [];
  451. }
  452. } catch (error) {
  453. console.error("搜索物料失败:", error);
  454. // 出错时清空列表
  455. if (type === "code") {
  456. this.materialNoList = [];
  457. } else {
  458. this.materialNameList = [];
  459. }
  460. } finally {
  461. this.loading = false;
  462. }
  463. } else {
  464. // 清空对应的列表
  465. if (type === "code") {
  466. this.materialNoList = [];
  467. } else {
  468. this.materialNameList = [];
  469. }
  470. }
  471. },
  472. add() {
  473. if (!this.formData.businessType) {
  474. return this.$message.error("请先选择业务类型");
  475. }
  476. this.formData.list = this.formData.list || [];
  477. this.formData.list.push({});
  478. this.formData = { ...this.formData };
  479. },
  480. changeMaterial(value, index, type) {
  481. // 根据选择的类型获取对应的列表
  482. const list =
  483. type === "code" ? this.materialNoList : this.materialNameList;
  484. // 查找选中的物料信息
  485. let selectedMaterial = null;
  486. if (type === "code") {
  487. selectedMaterial = list.find((item) => item.code === value);
  488. // 如果在当前列表找不到,尝试从另一个列表找
  489. if (!selectedMaterial) {
  490. selectedMaterial = this.materialNameList.find(
  491. (item) => item.code === value
  492. );
  493. }
  494. } else {
  495. selectedMaterial = list.find((item) => item.name === value);
  496. // 如果在当前列表找不到,尝试从另一个列表找
  497. if (!selectedMaterial) {
  498. selectedMaterial = this.materialNoList.find(
  499. (item) => item.name === value
  500. );
  501. }
  502. }
  503. if (selectedMaterial) {
  504. // 更新表单中的物料信息
  505. const newRow = {
  506. ...this.formData.list[index],
  507. materialNo: selectedMaterial.code,
  508. materialName: selectedMaterial.name,
  509. unitName: selectedMaterial.unit || "",
  510. };
  511. // 更新行数据
  512. this.$set(this.formData.list, index, newRow);
  513. // 强制更新列表,确保页面正常展示
  514. this.formData.list = [...this.formData.list];
  515. }
  516. },
  517. remoteMethod(query) {
  518. if (query !== "") {
  519. const that = this;
  520. this.loading = true;
  521. setTimeout(async () => {
  522. this.loading = false;
  523. const { data } = await InRequestApi.getSourceOrder({
  524. businessType: that.formData.businessType,
  525. sourceOrderNo: query,
  526. });
  527. this.sourceOrderNoList = data || [];
  528. }, 200);
  529. } else {
  530. this.sourceOrderNoList = [];
  531. }
  532. },
  533. remoteWarehouse(query) {
  534. if (query !== "") {
  535. const that = this;
  536. this.loading = true;
  537. setTimeout(async () => {
  538. this.loading = false;
  539. const {
  540. data: { list },
  541. } = await InRequestApi.getStockPage({
  542. name: query,
  543. pageSize: 999,
  544. });
  545. this.warehouseList = list || [];
  546. }, 200);
  547. } else {
  548. this.warehouseList = [];
  549. }
  550. },
  551. changeSourceOrderNo(value) {
  552. this.sourceOrderNoList.map((v) => {
  553. if (v.sourceOrderNo == value) {
  554. this.formData.list = v.list;
  555. }
  556. });
  557. },
  558. changeBusinessDescribe(e) {
  559. this.businessDescribeList.map((v) => {
  560. if (v.label == e) {
  561. this.formData.businessCategory = v.value;
  562. }
  563. });
  564. },
  565. async changeBusinessType(value) {
  566. this.formData = {
  567. id: this.formData.id,
  568. businessType: this.formData.businessType,
  569. };
  570. this.formData = { ...this.formData };
  571. const { data } = await InRequestApi.getDictByOrderType({
  572. orderType: this.formData.businessType,
  573. });
  574. this.businessDescribeList = data;
  575. },
  576. /** 初始化数据 */
  577. async open(id) {
  578. this.reset();
  579. // 修改时,设置数据
  580. if (id) {
  581. this.formLoading = true;
  582. try {
  583. const res = await InRequestApi.getInRequest(id);
  584. res.data.businessType = res.data.businessType
  585. ? res.data.businessType.toString()
  586. : "0";
  587. res.data.businessDescribe = res.data.businessDescribe
  588. ? res.data.businessDescribe.toString()
  589. : "";
  590. res.data.priority = res.data.priority
  591. ? res.data.priority.toString()
  592. : "0";
  593. this.formData = res.data;
  594. this.dialogTitle = "修改";
  595. } finally {
  596. this.formLoading = false;
  597. }
  598. } else {
  599. this.dialogTitle = "新增";
  600. }
  601. },
  602. /** 提交按钮 */
  603. async submitForm() {
  604. // 校验主表
  605. await this.$refs["formRef"].validate();
  606. this.formLoading = true;
  607. try {
  608. const data = this.formData;
  609. data.list = data.list
  610. .filter((v) => v.nowDeliveredQty)
  611. .map(
  612. ({
  613. completedQty,
  614. actualQty,
  615. stock_code,
  616. area_code,
  617. location_code,
  618. status,
  619. lineNo,
  620. inventory_status,
  621. ...rest
  622. }) => rest
  623. );
  624. // 修改的提交;
  625. if (data.id) {
  626. await InRequestApi.updateInRequest(data);
  627. this.$modal.msgSuccess("修改成功");
  628. this.$router.back();
  629. return;
  630. }
  631. // 添加的提交
  632. await InRequestApi.createInRequest(data);
  633. this.$modal.msgSuccess("新增成功");
  634. this.$router.back();
  635. } finally {
  636. this.formLoading = false;
  637. }
  638. },
  639. /** 取消按钮 */
  640. handleCancel() {
  641. this.reset();
  642. this.$router.back();
  643. },
  644. /** 表单重置 */
  645. reset() {
  646. this.formData = {
  647. id: undefined,
  648. requestNo: undefined,
  649. requestType: undefined,
  650. businessType: undefined,
  651. businessCategory: undefined,
  652. businessDescribe: undefined,
  653. businessSubType: undefined,
  654. status: undefined,
  655. priority: undefined,
  656. warehouseId: undefined,
  657. relatedWarehouseId: undefined,
  658. supplierCode: undefined,
  659. customerCode: undefined,
  660. sourceOrderNo: undefined,
  661. expectedTime: undefined,
  662. actualTime: undefined,
  663. totalQty: undefined,
  664. totalSku: undefined,
  665. totalLine: undefined,
  666. remark: undefined,
  667. extendInfo: undefined,
  668. submitter: undefined,
  669. submitTime: undefined,
  670. auditor: undefined,
  671. auditTime: undefined,
  672. erpWriteFlag: undefined,
  673. erpErrMsg: undefined,
  674. erpBackId: undefined,
  675. };
  676. this.resetForm("formRef");
  677. },
  678. deliverChange(val) {
  679. // 这里可以写“本次出货数量”变化后的校验或计算逻辑
  680. console.log("deliverChange", val);
  681. },
  682. },
  683. };
  684. </script>
  685. <style scoped>
  686. /* 新增按钮容器样式,将所有按钮放在标题下方 */
  687. .buttons-container {
  688. position: relative;
  689. display: flex;
  690. gap: 10px;
  691. padding: 10px 0;
  692. margin-bottom: 20px;
  693. }
  694. /* 调整app-header的位置 */
  695. .app-header {
  696. margin-bottom: 10px;
  697. }
  698. </style>