index.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  1. <template>
  2. <div class="tenant">
  3. <!-- <Banner /> -->
  4. <div class="content">
  5. <byTable
  6. :source="sourceList.data"
  7. :pagination="sourceList.pagination"
  8. :config="config"
  9. :loading="loading"
  10. highlight-current-row
  11. :selectConfig="selectConfig"
  12. :table-events="{
  13. //element talbe事件都能传
  14. }"
  15. :action-list="[
  16. {
  17. text: 'Excel导入',
  18. action: () => openExcel(),
  19. disabled: false,
  20. },
  21. {
  22. text: '添加退货',
  23. action: () => openModal(),
  24. },
  25. ]"
  26. @get-list="getList"
  27. >
  28. <template #fileSlot="{ item }">
  29. <div
  30. style="cursor: pointer; color: #409eff"
  31. @click="handleClickFile(item)"
  32. >
  33. {{ item.fileName }}
  34. </div>
  35. </template>
  36. </byTable>
  37. </div>
  38. <el-dialog
  39. :title="
  40. modalType === 'add'
  41. ? '添加退货'
  42. : modalType === 'edit'
  43. ? '编辑退货'
  44. : '退货详情'
  45. "
  46. v-model="dialogVisible"
  47. width="800"
  48. v-loading="loading"
  49. destroy-on-close
  50. >
  51. <byForm
  52. :formConfig="formConfig"
  53. :formOption="formOption"
  54. v-model="formData.data"
  55. :rules="rules"
  56. ref="byform"
  57. >
  58. <template #detailSlot>
  59. <div style="width: 100%">
  60. <el-button
  61. type="primary"
  62. @click="openProduct = true"
  63. style="margin-bottom: 10px"
  64. v-if="modalType != 'detail'"
  65. >
  66. 添加产品
  67. </el-button>
  68. <el-table :data="formData.data.jdBackDetailsList">
  69. <el-table-column prop="productCode" label="产品编码" />
  70. <el-table-column prop="productName" label="产品名称" />
  71. <el-table-column prop="quantity" label="退货数量" min-width="150">
  72. <template #default="{ row, $index }">
  73. <el-form-item
  74. :prop="'jdBackDetailsList.' + $index + '.quantity'"
  75. :rules="rules.quantity"
  76. :inline-message="true"
  77. >
  78. <el-input-number
  79. v-model="row.quantity"
  80. :precision="4"
  81. :controls="false"
  82. :min="0"
  83. onmousewheel="return false;"
  84. />
  85. </el-form-item>
  86. </template>
  87. </el-table-column>
  88. <el-table-column
  89. prop="zip"
  90. label="操作"
  91. width="100"
  92. v-if="modalType != 'detail'"
  93. >
  94. <template #default="{ $index }">
  95. <el-button type="primary" link @click="handleRemove($index)"
  96. >删除</el-button
  97. >
  98. </template>
  99. </el-table-column>
  100. </el-table>
  101. </div>
  102. </template>
  103. </byForm>
  104. <template #footer v-if="modalType != 'detail'">
  105. <el-button @click="dialogVisible = false" size="large">取 消</el-button>
  106. <el-button
  107. type="primary"
  108. @click="submitForm()"
  109. size="large"
  110. :loading="submitLoading"
  111. >
  112. 确 定
  113. </el-button>
  114. </template>
  115. </el-dialog>
  116. <el-dialog
  117. v-model="openProduct"
  118. title="选择产品"
  119. width="70%"
  120. append-to-body
  121. >
  122. <SelectProduct @handleSelect="handleSelect"></SelectProduct>
  123. <template #footer>
  124. <span class="dialog-footer">
  125. <el-button @click="openProduct = false">取消</el-button>
  126. </span>
  127. </template>
  128. </el-dialog>
  129. <el-dialog
  130. title="Excel导入"
  131. v-model="openExcelDialog"
  132. width="400"
  133. v-loading="excelLoading"
  134. >
  135. <div style="margin-bottom: 10px">导入前请先选择仓库</div>
  136. <el-select v-model="importData.warehouseId" placeholder="请选择仓库">
  137. <el-option
  138. v-for="item in warehouseList"
  139. :key="item.id"
  140. :label="item.name"
  141. :value="item.id"
  142. />
  143. </el-select>
  144. <div style="margin-top: 20px" v-show="importData.warehouseId">
  145. <el-upload
  146. :action="actionUrl + '/jdBack/excelImport'"
  147. :data="importData"
  148. :headers="headers"
  149. :on-success="handleSuccess"
  150. :on-progress="handleProgress"
  151. :show-file-list="false"
  152. :on-error="handleError"
  153. accept=".xlsx"
  154. >
  155. <el-button type="primary">点击导入</el-button>
  156. </el-upload>
  157. </div>
  158. <template #footer>
  159. <el-button @click="openExcelDialog = false" size="large"
  160. >取 消</el-button
  161. >
  162. <!-- <el-button
  163. type="primary"
  164. @click="submitExcel()"
  165. size="large"
  166. :loading="submitLoading"
  167. >
  168. 确 定
  169. </el-button> -->
  170. </template>
  171. </el-dialog>
  172. </div>
  173. </template>
  174. <script setup>
  175. import { ElMessage, ElMessageBox } from "element-plus";
  176. import byTable from "@/components/byTable/index";
  177. import byForm from "@/components/byForm/index";
  178. import { watch } from "vue";
  179. import SelectProduct from "@/components/WDLY/product/SelectProduct";
  180. import { getToken } from "@/utils/auth";
  181. const uploadData = ref({});
  182. const headers = ref({ Authorization: "Bearer " + getToken() });
  183. const actionUrl = import.meta.env.VITE_APP_BASE_API;
  184. const loading = ref(false);
  185. const submitLoading = ref(false);
  186. const sourceList = ref({
  187. data: [],
  188. pagination: {
  189. total: 3,
  190. pageNum: 1,
  191. pageSize: 10,
  192. },
  193. });
  194. let dialogVisible = ref(false);
  195. let openProduct = ref(false);
  196. let openExcelDialog = ref(false);
  197. let excelLoading = ref(false);
  198. let modalType = ref("add");
  199. let rules = ref({
  200. warehouseId: [{ required: true, message: "请选择仓库", trigger: "change" }],
  201. logisticsCompanyCode: [
  202. { required: true, message: "请选择物流公司", trigger: "change" },
  203. ],
  204. logisticsCode: [
  205. { required: true, message: "请输入物流/快递单号", trigger: "blur" },
  206. ],
  207. quantity: [{ required: true, message: "请输入退货数量", trigger: "blur" }],
  208. });
  209. const { proxy } = getCurrentInstance();
  210. const selectConfig = reactive([
  211. {
  212. label: "数据来源",
  213. prop: "type",
  214. data: [
  215. {
  216. label: "手动创建",
  217. value: "1",
  218. },
  219. {
  220. label: "批量导入",
  221. value: "2",
  222. },
  223. ],
  224. },
  225. {
  226. label: "退货状态",
  227. prop: "status",
  228. data: [
  229. {
  230. label: "新建",
  231. value: "1",
  232. },
  233. {
  234. label: "运输中",
  235. value: "2",
  236. },
  237. {
  238. label: "待质检",
  239. value: "3",
  240. },
  241. ],
  242. },
  243. ]);
  244. const config = computed(() => {
  245. return [
  246. {
  247. attrs: {
  248. label: "数据来源",
  249. prop: "type",
  250. },
  251. render(type) {
  252. return type == 1 ? "手动创建" : "批量导入";
  253. },
  254. },
  255. {
  256. attrs: {
  257. label: "仓库名称",
  258. prop: "warehouseName",
  259. },
  260. },
  261. {
  262. attrs: {
  263. label: "物流/快递公司",
  264. prop: "logisticsCompanyName",
  265. },
  266. },
  267. {
  268. attrs: {
  269. label: "物流/快递单号",
  270. prop: "logisticsCode",
  271. },
  272. },
  273. {
  274. attrs: {
  275. label: "创建时间",
  276. prop: "createTime",
  277. },
  278. },
  279. {
  280. attrs: {
  281. label: "退货状态",
  282. prop: "status",
  283. },
  284. render(status) {
  285. return status == 1 ? "新建" : status == 2 ? "运输中 " : "待质检";
  286. },
  287. },
  288. {
  289. attrs: {
  290. label: "操作",
  291. width: "240",
  292. align: "right",
  293. },
  294. renderHTML(row) {
  295. return [
  296. row.status < 2
  297. ? {
  298. attrs: {
  299. label: "修改",
  300. type: "primary",
  301. text: true,
  302. },
  303. el: "button",
  304. click() {
  305. getDtl(row, "edit");
  306. },
  307. }
  308. : {},
  309. row.status < 2
  310. ? {
  311. attrs: {
  312. label: "删除",
  313. type: "primary",
  314. text: true,
  315. },
  316. el: "button",
  317. click() {
  318. // 弹窗提示是否删除
  319. ElMessageBox.confirm(
  320. "此操作将永久删除该数据, 是否继续?",
  321. "提示",
  322. {
  323. confirmButtonText: "确定",
  324. cancelButtonText: "取消",
  325. type: "warning",
  326. }
  327. ).then(() => {
  328. // 删除
  329. proxy
  330. .post("/jdBack/delete", {
  331. id: row.id,
  332. })
  333. .then((res) => {
  334. ElMessage({
  335. message: "删除成功",
  336. type: "success",
  337. });
  338. getList();
  339. });
  340. });
  341. },
  342. }
  343. : {},
  344. {
  345. attrs: {
  346. label: "查看",
  347. type: "primary",
  348. text: true,
  349. },
  350. el: "button",
  351. click() {
  352. getDtl(row, "detail");
  353. },
  354. },
  355. ];
  356. },
  357. },
  358. ];
  359. });
  360. let formData = reactive({
  361. data: {},
  362. });
  363. const formOption = reactive({
  364. inline: true,
  365. labelWidth: 100,
  366. itemWidth: 100,
  367. });
  368. const byform = ref(null);
  369. let formConfig = reactive([
  370. {
  371. type: "title",
  372. title: "退货信息",
  373. },
  374. {
  375. type: "select",
  376. prop: "warehouseId",
  377. label: "仓库名称",
  378. itemWidth: 100,
  379. disabled: false,
  380. data: [],
  381. },
  382. {
  383. type: "select",
  384. label: "物流/快递信息",
  385. prop: "logisticsCompanyCode",
  386. itemWidth: 50,
  387. placeholder: "物流/快递公司",
  388. filterable: true,
  389. data: [],
  390. style: {
  391. width: "100%",
  392. },
  393. },
  394. {
  395. type: "input",
  396. label: " ",
  397. prop: "logisticsCode",
  398. itemWidth: 50,
  399. placeholder: "物流/快递单号",
  400. },
  401. {
  402. type: "slot",
  403. slotName: "detailSlot",
  404. label: "退货明细",
  405. },
  406. ]);
  407. const configData = [
  408. [
  409. {
  410. type: "input",
  411. prop: "supplyName",
  412. label: "供应商",
  413. disabled: true,
  414. itemWidth: 50,
  415. },
  416. {
  417. type: "input",
  418. prop: "purchaseCode",
  419. label: "采购单号",
  420. disabled: true,
  421. itemWidth: 50,
  422. },
  423. {
  424. type: "select",
  425. label: "物流信息",
  426. prop: "logisticsCompanyCode",
  427. itemWidth: 50,
  428. style: {
  429. width: "100%",
  430. },
  431. },
  432. {
  433. type: "input",
  434. label: " ",
  435. prop: "code",
  436. itemWidth: 50,
  437. },
  438. {
  439. type: "slot",
  440. slotName: "detailSlot",
  441. label: "发货明细",
  442. },
  443. ],
  444. [
  445. {
  446. type: "input",
  447. prop: "supplyName",
  448. label: "供应商",
  449. disabled: true,
  450. itemWidth: 50,
  451. },
  452. {
  453. type: "input",
  454. prop: "purchaseCode",
  455. label: "采购单号",
  456. disabled: true,
  457. itemWidth: 50,
  458. },
  459. {
  460. type: "select",
  461. label: "物流/快递单号",
  462. prop: "deliverGoodsId",
  463. itemWidth: 50,
  464. style: {
  465. width: "100%",
  466. },
  467. },
  468. {
  469. type: "slot",
  470. slotName: "detailSlot",
  471. label: "发货明细",
  472. },
  473. ],
  474. ];
  475. const deliverData = ref([]);
  476. const getList = async (req) => {
  477. sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
  478. loading.value = true;
  479. proxy.post("/jdBack/page", sourceList.value.pagination).then((message) => {
  480. console.log(message);
  481. sourceList.value.data = message.rows;
  482. sourceList.value.pagination.total = message.total;
  483. setTimeout(() => {
  484. loading.value = false;
  485. }, 200);
  486. });
  487. };
  488. const submitForm = () => {
  489. byform.value.handleSubmit((valid) => {
  490. const list = formData.data.jdBackDetailsList;
  491. if (!list.length > 0) {
  492. return ElMessage({
  493. message: `请添加退货明细`,
  494. type: "info",
  495. });
  496. }
  497. for (let i = 0; i < list.length; i++) {
  498. const e = list[i];
  499. if (e.quantity == 0) {
  500. return ElMessage({
  501. message: `退货数量不能为0!`,
  502. type: "info",
  503. });
  504. }
  505. }
  506. loading.value = true;
  507. submitLoading.value = true;
  508. proxy.post("/jdBack/" + modalType.value, formData.data).then(
  509. (res) => {
  510. ElMessage({
  511. message: `操作成功!`,
  512. type: "success",
  513. });
  514. dialogVisible.value = false;
  515. submitLoading.value = false;
  516. loading.value = false;
  517. getList();
  518. },
  519. (err) => (submitLoading.value = false)
  520. );
  521. });
  522. };
  523. const getDtl = (row, type) => {
  524. modalType.value = type;
  525. proxy.post("/jdBack/detail", { id: row.id }).then((res) => {
  526. formData.data = res;
  527. dialogVisible.value = true;
  528. });
  529. };
  530. const importData = reactive({});
  531. const handleEdit = (row, status) => {
  532. let purchaseStatusName = status == 88 ? "作废" : "终止";
  533. const data = { ...row, purchaseStatus: status };
  534. // 弹窗提示是否删除
  535. ElMessageBox.confirm(
  536. `此操作将${purchaseStatusName}该数据, 是否继续?`,
  537. "提示",
  538. {
  539. confirmButtonText: "确定",
  540. cancelButtonText: "取消",
  541. type: "warning",
  542. }
  543. ).then(() => {
  544. // 删除
  545. proxy.post("/purchase/edit", data).then((res) => {
  546. ElMessage({
  547. message: `${purchaseStatusName}成功`,
  548. type: "success",
  549. });
  550. getList();
  551. });
  552. });
  553. };
  554. const logisticsData = ref([]);
  555. const getLogisticsData = (row) => {
  556. proxy.post("/companyInfo/list", { pageNum: 1, pageSize: 999 }).then((res) => {
  557. // logisticsData.value = res.reverse().slice(0, 100); //截取前100
  558. logisticsData.value = res.reverse();
  559. formConfig[2].data = logisticsData.value.map((x) => ({
  560. label: x.name,
  561. value: x.code,
  562. }));
  563. });
  564. };
  565. watch(modalType, (val) => {
  566. if (val) {
  567. formConfig[1].disabled = val == "detail" ? true : false;
  568. formConfig[2].disabled = val == "detail" ? true : false;
  569. formConfig[3].disabled = val == "detail" ? true : false;
  570. }
  571. });
  572. const openModal = () => {
  573. dialogVisible.value = true;
  574. modalType.value = "add";
  575. formData.data = {
  576. type: "1",
  577. status: "1",
  578. jdBackDetailsList: [],
  579. };
  580. };
  581. const warehouseList = ref([]);
  582. const warehouseListData = () => {
  583. // // 币种数据
  584. proxy
  585. .post("/warehouse/page", {
  586. pageNum: 1,
  587. pageSize: 10,
  588. })
  589. .then((message) => {
  590. warehouseList.value = message.rows;
  591. formConfig[1].data = message.rows.map((x) => ({
  592. label: x.name,
  593. value: x.id,
  594. }));
  595. });
  596. };
  597. getList();
  598. getLogisticsData();
  599. warehouseListData();
  600. const handleSelect = (row) => {
  601. const flag = formData.data.jdBackDetailsList.some(
  602. (x) => x.productId === row.id
  603. );
  604. if (flag)
  605. return ElMessage({
  606. message: "该物品已选择",
  607. type: "info",
  608. });
  609. formData.data.jdBackDetailsList.push({
  610. quantity: null,
  611. productName: row.name,
  612. productCode: row.code,
  613. productId: row.id,
  614. });
  615. return ElMessage({
  616. message: "选择成功",
  617. type: "success",
  618. });
  619. };
  620. const handleRemove = (index) => {
  621. formData.data.jdBackDetailsList.splice(index, 1);
  622. return ElMessage({
  623. message: "删除成功",
  624. type: "success",
  625. });
  626. };
  627. const openExcel = () => {
  628. openExcelDialog.value = true;
  629. importData.warehouseId = "";
  630. };
  631. const handleProgress = () => {
  632. excelLoading.value = true;
  633. };
  634. const handleError = (err) => {
  635. console.log(res);
  636. ElMessage({
  637. message: `${err},请重试!`,
  638. type: "info",
  639. });
  640. openExcelDialog.value = false;
  641. excelLoading.value = false;
  642. };
  643. const handleSuccess = (res) => {
  644. if (res.code != 200) {
  645. return ElMessage({
  646. message: `${res.msg},请重试!`,
  647. type: "info",
  648. });
  649. } else {
  650. ElMessage({
  651. message: "导入成功!",
  652. type: "success",
  653. });
  654. openExcelDialog.value = false;
  655. excelLoading.value = false;
  656. getList();
  657. }
  658. };
  659. </script>
  660. <style lang="scss" scoped>
  661. .tenant {
  662. padding: 20px;
  663. }
  664. </style>