InRequestForm.vue 21 KB

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