index.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842
  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. select: select,
  15. }"
  16. :action-list="[
  17. {
  18. text: 'Excel导入',
  19. action: () => openExcel(),
  20. disabled: false,
  21. },
  22. {
  23. text: '添加订单',
  24. action: () => openModal('add'),
  25. },
  26. ]"
  27. @get-list="getList"
  28. >
  29. <template #code="{ item }">
  30. <div
  31. style="cursor: pointer; color: #409eff"
  32. @click="handleClickCode(item)"
  33. >
  34. {{ item.code }}
  35. </div>
  36. </template>
  37. <template #address="{ item }">
  38. <div>
  39. {{ item.countryName }}, {{ item.provinceName }} ,
  40. {{ item.cityName }}
  41. </div>
  42. </template>
  43. </byTable>
  44. </div>
  45. <el-dialog
  46. :title="modalType == 'add' ? '添加订单' : '调仓接收'"
  47. v-model="dialogVisible"
  48. width="800"
  49. v-loading="loading"
  50. >
  51. <byForm
  52. :formConfig="formConfig"
  53. :formOption="formOption"
  54. v-model="formData.data"
  55. :rules="rules"
  56. ref="byform"
  57. >
  58. <template #distributionCenter>
  59. <div>
  60. <el-autocomplete
  61. v-model="formData.data.distributionCenter"
  62. :fetch-suggestions="querySearchPerson"
  63. clearable
  64. class="inline-input w-50"
  65. placeholder="请输入"
  66. @select="handlePerson"
  67. >
  68. </el-autocomplete>
  69. </div>
  70. </template>
  71. <template #countryId>
  72. <div>
  73. <el-select
  74. v-model="formData.data.countryId"
  75. placeholder="国家"
  76. @change="(val) => getCityData(val, '20', true)"
  77. >
  78. <el-option
  79. v-for="item in countryData"
  80. :label="item.chineseName"
  81. :value="item.id"
  82. >
  83. </el-option>
  84. </el-select>
  85. </div>
  86. </template>
  87. <template #provinceId>
  88. <div>
  89. <selectCity
  90. placeholder="省/洲"
  91. @change="(val) => getCityData(val, '30', true)"
  92. addressId="provinceId"
  93. addressName="provinceName"
  94. v-model="formData.data"
  95. :data="provinceData"
  96. >
  97. </selectCity>
  98. </div>
  99. </template>
  100. <template #cityId>
  101. <div>
  102. <selectCity
  103. placeholder="城市"
  104. addressId="cityId"
  105. addressName="cityName"
  106. v-model="formData.data"
  107. :data="cityData"
  108. >
  109. </selectCity>
  110. </div>
  111. </template>
  112. <template #products>
  113. <div style="width: 100%">
  114. <el-button
  115. type="primary"
  116. @click="openProduct = true"
  117. style="margin-bottom: 10px"
  118. >
  119. 添加物品
  120. </el-button>
  121. <el-table :data="formData.data.jdOrderDetailsList">
  122. <el-table-column prop="productCode" label="产品编码" />
  123. <el-table-column prop="productName" label="产品名称" />
  124. <el-table-column prop="price" label="单价" min-width="150">
  125. <template #default="{ row, $index }">
  126. <el-form-item
  127. :prop="'jdOrderDetailsList.' + $index + '.price'"
  128. :rules="rules.price"
  129. :inline-message="true"
  130. >
  131. <el-input-number
  132. v-model="row.price"
  133. :precision="4"
  134. :controls="false"
  135. :min="0"
  136. @change="totalAmount"
  137. onmousewheel="return false;"
  138. />
  139. </el-form-item>
  140. </template>
  141. </el-table-column>
  142. <el-table-column prop="quantity" label="数量" min-width="150">
  143. <template #default="{ row, $index }">
  144. <el-form-item
  145. :prop="'jdOrderDetailsList.' + $index + '.quantity'"
  146. :rules="rules.quantity"
  147. :inline-message="true"
  148. >
  149. <el-input-number
  150. v-model="row.quantity"
  151. :precision="4"
  152. :controls="false"
  153. :min="0"
  154. @change="totalAmount"
  155. onmousewheel="return false;"
  156. />
  157. </el-form-item>
  158. </template>
  159. </el-table-column>
  160. <el-table-column prop="total" label="小计" />
  161. <el-table-column prop="remark" label="备注" min-width="200">
  162. <template #default="{ row, $index }">
  163. <el-form-item
  164. :prop="'jdOrderDetailsList.' + $index + '.remark'"
  165. :rules="rules.remark"
  166. :inline-message="true"
  167. >
  168. <el-input v-model="row.remark" placeholder="请输入" />
  169. </el-form-item>
  170. </template>
  171. </el-table-column>
  172. <el-table-column
  173. prop="zip"
  174. label="操作"
  175. width="60"
  176. fixed="right"
  177. align="center"
  178. >
  179. <template #default="{ $index }">
  180. <el-button type="primary" link @click="handleRemove($index)"
  181. >删除</el-button
  182. >
  183. </template>
  184. </el-table-column>
  185. </el-table>
  186. </div>
  187. </template>
  188. </byForm>
  189. <template #footer>
  190. <el-button @click="dialogVisible = false" size="large">取 消</el-button>
  191. <el-button
  192. type="primary"
  193. v-no-double-click="submitForm"
  194. size="large"
  195. :loading="submitLoading"
  196. >
  197. 确 定
  198. </el-button>
  199. </template>
  200. </el-dialog>
  201. <el-dialog
  202. v-model="openProduct"
  203. title="选择产品"
  204. width="70%"
  205. append-to-body
  206. >
  207. <SelectProduct @handleSelect="handleSelect"></SelectProduct>
  208. <template #footer>
  209. <span class="dialog-footer">
  210. <el-button @click="openProduct = false">取消</el-button>
  211. </span>
  212. </template>
  213. </el-dialog>
  214. <el-dialog
  215. v-model="openDetails"
  216. title="订单详情"
  217. width="40%"
  218. append-to-body
  219. >
  220. <OrderDetails
  221. :orderData="formData.orderData"
  222. :key="formData.orderData.id"
  223. ></OrderDetails>
  224. <template #footer>
  225. <span class="dialog-footer">
  226. <el-button @click="openDetails = false">取消</el-button>
  227. </span>
  228. </template>
  229. </el-dialog>
  230. <el-dialog
  231. title="Excel导入"
  232. v-model="openExcelDialog"
  233. width="400"
  234. v-loading="excelLoading"
  235. >
  236. <div style="margin-bottom: 10px">导入前请先选择客户</div>
  237. <el-select v-model="importData.customerId" placeholder="请选择客户">
  238. <el-option
  239. v-for="item in warehouseList"
  240. :key="item.id"
  241. :label="item.name"
  242. :value="item.id"
  243. />
  244. </el-select>
  245. <div style="margin-top: 20px" v-show="importData.customerId">
  246. <div style="margin-bottom: 10px">上传附件</div>
  247. <el-upload
  248. :action="actionUrl + '/jdOrder/excelImport'"
  249. :data="importData"
  250. :headers="headers"
  251. :on-success="handleSuccess"
  252. :on-progress="handleProgress"
  253. :show-file-list="false"
  254. :on-error="handleError"
  255. accept=".xlsx"
  256. >
  257. <el-button type="primary">选择</el-button>
  258. </el-upload>
  259. </div>
  260. <template #footer>
  261. <el-button @click="openExcelDialog = false">取 消</el-button>
  262. <!-- <el-button
  263. type="primary"
  264. @click="submitExcel()"
  265. :loading="submitLoading"
  266. >
  267. 确 定
  268. </el-button> -->
  269. </template>
  270. </el-dialog>
  271. </div>
  272. </template>
  273. <script setup>
  274. /* eslint-disable vue/no-unused-components */
  275. import { ElMessage, ElMessageBox } from "element-plus";
  276. import byTable from "@/components/byTable/index";
  277. import byForm from "@/components/byForm/index";
  278. import { computed, defineComponent, ref } from "vue";
  279. import useUserStore from "@/store/modules/user";
  280. import SelectProduct from "@/components/WDLY/product/SelectProduct";
  281. import OrderDetails from "@/components/WDLY/order/details";
  282. import selectCity from "@/components/selectCity/index.vue";
  283. import { getToken } from "@/utils/auth";
  284. const headers = ref({ Authorization: "Bearer " + getToken() });
  285. const actionUrl = import.meta.env.VITE_APP_BASE_API;
  286. const loading = ref(false);
  287. const submitLoading = ref(false);
  288. const sourceList = ref({
  289. data: [],
  290. pagination: {
  291. total: 3,
  292. pageNum: 1,
  293. pageSize: 10,
  294. },
  295. });
  296. let dialogVisible = ref(false);
  297. let openProduct = ref(false);
  298. let openDetails = ref(false);
  299. const importData = reactive({});
  300. let roomDialogVisible = ref(false);
  301. let excelLoading = ref(false);
  302. let modalType = ref("add");
  303. let rules = ref({
  304. customerId: [
  305. {
  306. required: true,
  307. message: "请选择客户",
  308. trigger: "change",
  309. },
  310. ],
  311. type: [
  312. {
  313. required: true,
  314. message: "请选择订单类型",
  315. trigger: "change",
  316. },
  317. ],
  318. countryId: [
  319. {
  320. required: true,
  321. message: "请选择国家",
  322. trigger: "change",
  323. },
  324. ],
  325. // provinceId: [
  326. // {
  327. // required: true,
  328. // message: "请选择省/洲",
  329. // trigger: "change",
  330. // },
  331. // ],
  332. // cityId: [
  333. // {
  334. // required: true,
  335. // message: "请选择城市",
  336. // trigger: "change",
  337. // },
  338. // ],
  339. code: [
  340. {
  341. required: true,
  342. message: "请输入订单编号",
  343. trigger: "blur",
  344. },
  345. ],
  346. contactPerson: [
  347. {
  348. required: true,
  349. message: "请输入收货负责人",
  350. trigger: "blur",
  351. },
  352. ],
  353. contactNumber: [
  354. {
  355. required: true,
  356. message: "请输入收货电话",
  357. trigger: "blur",
  358. },
  359. ],
  360. detailedAddress: [
  361. {
  362. required: true,
  363. message: "请输入详细地址",
  364. trigger: "blur",
  365. },
  366. ],
  367. price: [
  368. {
  369. required: true,
  370. message: "请输入单价",
  371. trigger: "blur",
  372. },
  373. ],
  374. quantity: [
  375. {
  376. required: true,
  377. message: "请输入数量",
  378. trigger: "blur",
  379. },
  380. ],
  381. distributionCenter: [
  382. {
  383. required: true,
  384. message: "请输入/选择配送中心",
  385. trigger: "blur",
  386. },
  387. ],
  388. });
  389. const { proxy } = getCurrentInstance();
  390. const selectConfig = reactive([
  391. {
  392. label: "入库状态",
  393. prop: "status",
  394. data: [
  395. {
  396. label: "未出库",
  397. value: "1",
  398. },
  399. {
  400. label: "部分出库",
  401. value: "2",
  402. },
  403. {
  404. label: "已出库",
  405. value: "3",
  406. },
  407. ],
  408. },
  409. ]);
  410. const config = computed(() => {
  411. return [
  412. {
  413. attrs: {
  414. label: "订单编号",
  415. prop: "code",
  416. },
  417. },
  418. {
  419. attrs: {
  420. label: "客户名称",
  421. prop: "customerName",
  422. },
  423. },
  424. {
  425. attrs: {
  426. label: "配送中心",
  427. prop: "distributionCenter",
  428. },
  429. },
  430. {
  431. attrs: {
  432. label: "所在城市",
  433. prop: "address",
  434. slot: "address",
  435. },
  436. },
  437. {
  438. attrs: {
  439. label: "详细地址",
  440. prop: "detailedAddress",
  441. },
  442. },
  443. {
  444. attrs: {
  445. label: "收货负责人",
  446. prop: "contactPerson",
  447. },
  448. },
  449. {
  450. attrs: {
  451. label: "收货电话",
  452. prop: "contactNumber",
  453. },
  454. },
  455. {
  456. attrs: {
  457. label: "订单金额",
  458. prop: "amount",
  459. },
  460. render(amount) {
  461. return proxy.moneyFormat(amount, 2);
  462. },
  463. },
  464. {
  465. attrs: {
  466. label: "出库状态",
  467. prop: "status",
  468. },
  469. render(status) {
  470. return status == 1 ? "未出库" : status == 2 ? "部分出库" : "已出库";
  471. },
  472. },
  473. ];
  474. });
  475. let formData = reactive({
  476. data: {},
  477. treeData: [],
  478. orderData: {},
  479. });
  480. const formOption = reactive({
  481. inline: true,
  482. labelWidth: 100,
  483. itemWidth: 100,
  484. rules: [],
  485. });
  486. const byform = ref(null);
  487. const treeData = ref([]);
  488. const formConfig = reactive([
  489. {
  490. type: "title",
  491. title: "基础信息",
  492. },
  493. {
  494. type: "select",
  495. prop: "customerId",
  496. label: "客户名称",
  497. isLoad: {
  498. url: "/customer/page",
  499. req: {
  500. pageNum: 1,
  501. pageSize: 9999,
  502. },
  503. labelKey: "name",
  504. labelVal: "id",
  505. method: "post",
  506. resUrl: "rows",
  507. },
  508. itemWidth: 30,
  509. },
  510. {
  511. type: "input",
  512. prop: "code",
  513. label: "订单编号",
  514. itemWidth: 20,
  515. },
  516. {
  517. type: "slot",
  518. prop: "distributionCenter",
  519. label: "配送中心",
  520. slotName: "distributionCenter",
  521. },
  522. {
  523. type: "input",
  524. prop: "contactPerson",
  525. label: "收货信息",
  526. itemWidth: 20,
  527. placeholder: "收货负责人",
  528. },
  529. {
  530. type: "input",
  531. prop: "contactNumber",
  532. label: " ",
  533. itemWidth: 80,
  534. placeholder: "收货电话",
  535. style: {
  536. width: "30%",
  537. },
  538. },
  539. {
  540. type: "slot",
  541. slotName: "countryId",
  542. prop: "countryId",
  543. label: "详细地址",
  544. itemWidth: 33.33,
  545. },
  546. {
  547. type: "slot",
  548. slotName: "provinceId",
  549. label: " ",
  550. itemWidth: 33.33,
  551. },
  552. {
  553. type: "slot",
  554. slotName: "cityId",
  555. prop: "cityId",
  556. label: " ",
  557. itemWidth: 33.33,
  558. },
  559. {
  560. type: "input",
  561. itemType: "textarea",
  562. prop: "detailedAddress",
  563. },
  564. {
  565. type: "title",
  566. title: "订单明细",
  567. },
  568. {
  569. type: "slot",
  570. slotName: "products",
  571. },
  572. {
  573. type: "input",
  574. prop: "amountMoney",
  575. label: "订单金额",
  576. disabled: true,
  577. itemWidth: 20,
  578. },
  579. ]);
  580. const getList = async (req) => {
  581. sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
  582. loading.value = true;
  583. proxy.post("/jdOrder/page", sourceList.value.pagination).then((message) => {
  584. console.log(message);
  585. sourceList.value.data = message.rows;
  586. sourceList.value.pagination.total = message.total;
  587. setTimeout(() => {
  588. loading.value = false;
  589. }, 200);
  590. });
  591. };
  592. const openModal = () => {
  593. dialogVisible.value = true;
  594. modalType.value = "add";
  595. formData.data = {
  596. jdOrderDetailsList: [],
  597. countryId: "44",
  598. };
  599. getCityData(formData.data.countryId, "20");
  600. };
  601. const submitForm = () => {
  602. console.log(byform.value);
  603. byform.value.handleSubmit((valid) => {
  604. const list = formData.data.jdOrderDetailsList;
  605. if (!list.length > 0)
  606. return ElMessage({
  607. message: `请添加订单明细!`,
  608. type: "info",
  609. });
  610. for (let i = 0; i < list.length; i++) {
  611. const e = list[i];
  612. if (e.quantity == 0) {
  613. return ElMessage({
  614. message: `数量不能为0!`,
  615. type: "info",
  616. });
  617. }
  618. }
  619. submitLoading.value = true;
  620. proxy.post("/jdOrder/" + modalType.value, formData.data).then(
  621. (res) => {
  622. ElMessage({
  623. message: modalType.value == "add" ? "添加成功" : "编辑成功",
  624. type: "success",
  625. });
  626. dialogVisible.value = false;
  627. submitLoading.value = false;
  628. getList();
  629. },
  630. (err) => (submitLoading.value = false)
  631. );
  632. });
  633. };
  634. const getDtl = (row, status) => {
  635. const statusNmae = status == 2 ? "结束" : "取消";
  636. // 弹窗提示是否删除
  637. ElMessageBox.confirm(`您确定执行${statusNmae}操作吗?`, "提示", {
  638. confirmButtonText: "确定",
  639. cancelButtonText: "取消",
  640. type: "warning",
  641. }).then(() => {
  642. // 删除
  643. proxy
  644. .post("/orderInfo/edit", {
  645. id: row.id,
  646. status,
  647. })
  648. .then((res) => {
  649. ElMessage({
  650. message: "操作成功",
  651. type: "success",
  652. });
  653. getList();
  654. });
  655. });
  656. };
  657. const warehouseList = ref([]);
  658. const salesType = ref([]);
  659. const getDict = () => {
  660. proxy.getDict(["order_sales_type"]).then((res) => {
  661. salesType.value = res["order_sales_type"];
  662. formConfig[1].data = salesType.value.map((x) => ({
  663. label: x.dictValue,
  664. value: x.dictKey,
  665. }));
  666. });
  667. };
  668. const countryData = ref([]);
  669. const provinceData = ref([]);
  670. const cityData = ref([]);
  671. const getCityData = (id, type, flag) => {
  672. proxy.post("/customizeArea/list", { parentId: id }).then((res) => {
  673. if (type === "20") {
  674. provinceData.value = res;
  675. if (flag) {
  676. formData.data.provinceId = "";
  677. formData.data.provinceName = "";
  678. formData.data.cityId = "";
  679. formData.data.cityName = "";
  680. }
  681. } else if (type === "30") {
  682. cityData.value = res;
  683. if (flag) {
  684. formData.data.cityId = "";
  685. formData.data.cityName = "";
  686. }
  687. } else {
  688. countryData.value = res;
  689. }
  690. });
  691. };
  692. getCityData("0");
  693. getList();
  694. // getDict();
  695. const totalAmount = () => {
  696. let sum = 0;
  697. for (let i = 0; i < formData.data.jdOrderDetailsList.length; i++) {
  698. const e = formData.data.jdOrderDetailsList[i];
  699. e.total = (e.price * 1000000 * e.quantity) / 1000000;
  700. sum += e.total;
  701. }
  702. formData.data.amountMoney = sum;
  703. };
  704. const handleSelect = (row) => {
  705. const flag = formData.data.jdOrderDetailsList.some(
  706. (x) => x.productId === row.id
  707. );
  708. if (flag)
  709. return ElMessage({
  710. message: "该物品已选择",
  711. type: "info",
  712. });
  713. formData.data.jdOrderDetailsList.push({
  714. productName: row.name,
  715. productCode: row.code,
  716. productId: row.id,
  717. total: "",
  718. quantity: null,
  719. price: null,
  720. remark: "",
  721. });
  722. return ElMessage({
  723. message: "选择成功",
  724. type: "success",
  725. });
  726. };
  727. const handleRemove = (index) => {
  728. formData.data.jdOrderDetailsList.splice(index, 1);
  729. totalAmount();
  730. return ElMessage({
  731. message: "删除成功",
  732. type: "success",
  733. });
  734. };
  735. const handleClickCode = (row) => {
  736. formData.orderData = row;
  737. openDetails.value = true;
  738. };
  739. let openExcelDialog = ref(false);
  740. const openExcel = () => {
  741. importData.customerId = "";
  742. openExcelDialog.value = true;
  743. };
  744. const handleProgress = () => {
  745. excelLoading.value = true;
  746. };
  747. const handleError = (err) => {
  748. console.log(err, "aas");
  749. ElMessage({
  750. message: `${err},请重试!`,
  751. type: "info",
  752. });
  753. openExcelDialog.value = false;
  754. excelLoading.value = false;
  755. };
  756. const handleSuccess = (res) => {
  757. if (res.code != 200) {
  758. return ElMessage({
  759. message: `${res.msg},请重试!`,
  760. type: "info",
  761. });
  762. } else {
  763. ElMessage({
  764. message: "导入成功!",
  765. type: "success",
  766. });
  767. openExcelDialog.value = false;
  768. excelLoading.value = false;
  769. getList();
  770. }
  771. };
  772. const createFilter = (queryString) => {
  773. return (restaurant) => {
  774. return (
  775. restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0
  776. );
  777. };
  778. };
  779. const distributionCenterData = ref([]);
  780. const querySearchPerson = (queryString, callback) => {
  781. const results = queryString
  782. ? distributionCenterData.value.filter(createFilter(queryString))
  783. : distributionCenterData.value;
  784. callback(results);
  785. };
  786. const handlePerson = (item) => {
  787. formData.data.buyContactNumber = item.phone;
  788. };
  789. const getDistributionCenter = () => {
  790. proxy.post("/jdOrder/getDistributionCenter").then(
  791. (res) => {
  792. distributionCenterData.value = res.map((x) => ({
  793. label: x,
  794. value: x,
  795. }));
  796. },
  797. (err) => {
  798. console.log(err);
  799. }
  800. );
  801. proxy.post("/customer/page", { pageNum: 1, pageSize: 9999 }).then(
  802. (res) => {
  803. warehouseList.value = res.rows;
  804. },
  805. (err) => {
  806. console.log(err);
  807. }
  808. );
  809. };
  810. getDistributionCenter();
  811. </script>
  812. <style lang="scss" scoped>
  813. .tenant {
  814. padding: 20px;
  815. }
  816. </style>