InRequestForm.vue 22 KB

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