index.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  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: '添加订单',
  19. action: () => openModal('add'),
  20. },
  21. ]"
  22. @get-list="getList"
  23. >
  24. <template #code="{ item }">
  25. <div
  26. style="cursor: pointer; color: #409eff"
  27. @click="handleClickCode(item)"
  28. >
  29. {{ item.code }}
  30. </div>
  31. </template>
  32. <template #address="{ item }">
  33. <div>
  34. {{ item.countryName }}, {{ item.provinceName }} ,
  35. {{ item.cityName }}, {{ item.detailedAddress }}
  36. </div>
  37. </template>
  38. </byTable>
  39. </div>
  40. <el-dialog
  41. :title="modalType == 'add' ? '添加订单' : '调仓接收'"
  42. v-model="dialogVisible"
  43. width="800"
  44. v-loading="loading"
  45. >
  46. <byForm
  47. :formConfig="formConfig"
  48. :formOption="formOption"
  49. v-model="formData.data"
  50. :rules="rules"
  51. ref="byform"
  52. >
  53. <template #address>
  54. <el-row style="width: 100%">
  55. <el-col :span="8">
  56. <el-form-item prop="countryId">
  57. <el-select
  58. v-model="formData.data.countryId"
  59. placeholder="国家"
  60. @change="(val) => getCityData(val, '20', true)"
  61. >
  62. <el-option
  63. v-for="item in countryData"
  64. :label="item.chineseName"
  65. :value="item.id"
  66. >
  67. </el-option>
  68. </el-select>
  69. </el-form-item>
  70. </el-col>
  71. <el-col :span="8">
  72. <el-form-item prop="provinceId">
  73. <el-select
  74. v-model="formData.data.provinceId"
  75. placeholder="省/洲"
  76. @change="(val) => getCityData(val, '30', true)"
  77. >
  78. <el-option
  79. v-for="item in provinceData"
  80. :label="item.name"
  81. :value="item.id"
  82. >
  83. </el-option>
  84. </el-select>
  85. </el-form-item>
  86. </el-col>
  87. <el-col :span="8">
  88. <el-form-item prop="cityId">
  89. <el-select v-model="formData.data.cityId" placeholder="城市">
  90. <el-option
  91. v-for="item in cityData"
  92. :label="item.name"
  93. :value="item.id"
  94. >
  95. </el-option>
  96. </el-select>
  97. </el-form-item>
  98. </el-col>
  99. </el-row>
  100. <el-row style="margin-top: 20px; width: 100%">
  101. <el-col :span="24">
  102. <el-form-item prop="detailedAddress">
  103. <el-input
  104. v-model="formData.data.detailedAddress"
  105. type="textarea"
  106. >
  107. </el-input>
  108. </el-form-item>
  109. </el-col>
  110. </el-row>
  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.orderDetailsList">
  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="'orderDetailsList.' + $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. />
  138. </el-form-item>
  139. </template>
  140. </el-table-column>
  141. <el-table-column prop="quantity" label="数量" min-width="150">
  142. <template #default="{ row, $index }">
  143. <el-form-item
  144. :prop="'orderDetailsList.' + $index + '.quantity'"
  145. :rules="rules.quantity"
  146. :inline-message="true"
  147. >
  148. <el-input-number
  149. v-model="row.quantity"
  150. :precision="4"
  151. :controls="false"
  152. :min="0"
  153. @change="totalAmount"
  154. />
  155. </el-form-item>
  156. </template>
  157. </el-table-column>
  158. <el-table-column prop="total" label="小计" />
  159. <el-table-column prop="remark" label="备注" min-width="200">
  160. <template #default="{ row, $index }">
  161. <el-form-item
  162. :prop="'orderDetailsList.' + $index + '.remark'"
  163. :rules="rules.remark"
  164. :inline-message="true"
  165. >
  166. <el-input v-model="row.remark" placeholder="请输入" />
  167. </el-form-item>
  168. </template>
  169. </el-table-column>
  170. <el-table-column
  171. prop="zip"
  172. label="操作"
  173. width="60"
  174. fixed="right"
  175. align="center"
  176. >
  177. <template #default="{ $index }">
  178. <el-button type="primary" link @click="handleRemove($index)"
  179. >删除</el-button
  180. >
  181. </template>
  182. </el-table-column>
  183. </el-table>
  184. </div>
  185. </template>
  186. </byForm>
  187. <template #footer>
  188. <el-button @click="dialogVisible = false" size="large">取 消</el-button>
  189. <el-button
  190. type="primary"
  191. @click="submitForm('byform')"
  192. size="large"
  193. :loading="submitLoading"
  194. >
  195. 确 定
  196. </el-button>
  197. </template>
  198. </el-dialog>
  199. <el-dialog
  200. v-model="openProduct"
  201. title="选择产品"
  202. width="70%"
  203. append-to-body
  204. >
  205. <SelectProduct @handleSelect="handleSelect"></SelectProduct>
  206. <template #footer>
  207. <span class="dialog-footer">
  208. <el-button @click="openProduct = false">取消</el-button>
  209. </span>
  210. </template>
  211. </el-dialog>
  212. <el-dialog
  213. v-model="openDetails"
  214. title="订单详情"
  215. width="40%"
  216. append-to-body
  217. >
  218. <OrderDetails
  219. :orderData="formData.orderData"
  220. :key="formData.orderData.id"
  221. ></OrderDetails>
  222. <template #footer>
  223. <span class="dialog-footer">
  224. <el-button @click="openDetails = false">取消</el-button>
  225. </span>
  226. </template>
  227. </el-dialog>
  228. </div>
  229. </template>
  230. <script setup>
  231. /* eslint-disable vue/no-unused-components */
  232. import { ElMessage, ElMessageBox } from "element-plus";
  233. import byTable from "@/components/byTable/index";
  234. import byForm from "@/components/byForm/index";
  235. import { computed, defineComponent, ref } from "vue";
  236. import useUserStore from "@/store/modules/user";
  237. import SelectProduct from "@/components/WDLY/product/SelectProduct";
  238. import OrderDetails from "@/components/WDLY/order/details";
  239. const loading = ref(false);
  240. const submitLoading = ref(false);
  241. const sourceList = ref({
  242. data: [],
  243. pagination: {
  244. total: 3,
  245. pageNum: 1,
  246. pageSize: 10,
  247. },
  248. });
  249. let dialogVisible = ref(false);
  250. let openProduct = ref(false);
  251. let openDetails = ref(false);
  252. let roomDialogVisible = ref(false);
  253. let modalType = ref("add");
  254. let rules = ref({
  255. customerInfoId: [
  256. {
  257. required: true,
  258. message: "请选择客户",
  259. trigger: "change",
  260. },
  261. ],
  262. type: [
  263. {
  264. required: true,
  265. message: "请选择订单类型",
  266. trigger: "change",
  267. },
  268. ],
  269. countryId: [
  270. {
  271. required: true,
  272. message: "请选择国家",
  273. trigger: "change",
  274. },
  275. ],
  276. provinceId: [
  277. {
  278. required: true,
  279. message: "请选择省/洲",
  280. trigger: "change",
  281. },
  282. ],
  283. cityId: [
  284. {
  285. required: true,
  286. message: "请选择城市",
  287. trigger: "change",
  288. },
  289. ],
  290. contacts: [
  291. {
  292. required: true,
  293. message: "请输入姓名",
  294. trigger: "blur",
  295. },
  296. ],
  297. phone: [
  298. {
  299. required: true,
  300. message: "请输入联系电话",
  301. trigger: "blur",
  302. },
  303. ],
  304. detailedAddress: [
  305. {
  306. required: true,
  307. message: "请输入详细地址",
  308. trigger: "blur",
  309. },
  310. ],
  311. price: [
  312. {
  313. required: true,
  314. message: "请输入单价",
  315. trigger: "blur",
  316. },
  317. ],
  318. quantity: [
  319. {
  320. required: true,
  321. message: "请输入数量",
  322. trigger: "blur",
  323. },
  324. ],
  325. });
  326. const { proxy } = getCurrentInstance();
  327. const selectConfig = reactive([
  328. {
  329. label: "订单类型",
  330. prop: "type",
  331. data: [],
  332. },
  333. {
  334. label: "订单状态",
  335. prop: "status",
  336. data: [
  337. {
  338. label: "进行中",
  339. value: "1",
  340. },
  341. {
  342. label: "已完成",
  343. value: "2",
  344. },
  345. {
  346. label: "已取消",
  347. value: "3",
  348. },
  349. ],
  350. },
  351. ]);
  352. const config = computed(() => {
  353. return [
  354. {
  355. attrs: {
  356. label: "订单类型",
  357. prop: "type",
  358. },
  359. render(type) {
  360. return proxy.dictDataEcho(type, salesType.value);
  361. },
  362. },
  363. {
  364. attrs: {
  365. label: "订单编号",
  366. prop: "code",
  367. slot: "code",
  368. },
  369. },
  370. {
  371. attrs: {
  372. label: "客户名称",
  373. prop: "customerName",
  374. },
  375. },
  376. {
  377. attrs: {
  378. label: "订单金额",
  379. prop: "amountMoney",
  380. },
  381. render(money) {
  382. return proxy.moneyFormat(money, 4);
  383. },
  384. },
  385. {
  386. attrs: {
  387. label: "收件人",
  388. prop: "contacts",
  389. },
  390. },
  391. {
  392. attrs: {
  393. label: "联系电话",
  394. prop: "phone",
  395. },
  396. },
  397. {
  398. attrs: {
  399. label: "收件城市",
  400. prop: "address",
  401. slot: "address",
  402. },
  403. },
  404. {
  405. attrs: {
  406. label: "下单时间",
  407. prop: "createTime",
  408. },
  409. },
  410. {
  411. attrs: {
  412. label: "订单状态",
  413. prop: "status",
  414. },
  415. render(status) {
  416. return status == 1 ? "进行中" : status == 2 ? "已完成" : "已取消";
  417. },
  418. },
  419. {
  420. attrs: {
  421. label: "操作",
  422. width: "200",
  423. align: "right",
  424. },
  425. // 渲染 el-button,一般用在最后一列。
  426. renderHTML(row) {
  427. return [
  428. row.status == 1
  429. ? {
  430. attrs: {
  431. label: "结束",
  432. type: "primary",
  433. text: true,
  434. },
  435. el: "button",
  436. click() {
  437. getDtl(row, 2);
  438. },
  439. }
  440. : {},
  441. row.status == 1
  442. ? {
  443. attrs: {
  444. label: "取消",
  445. type: "primary",
  446. text: true,
  447. },
  448. el: "button",
  449. click() {
  450. getDtl(row, 3);
  451. },
  452. }
  453. : {},
  454. ];
  455. },
  456. },
  457. ];
  458. });
  459. let formData = reactive({
  460. data: {},
  461. treeData: [],
  462. orderData: {},
  463. });
  464. const formOption = reactive({
  465. inline: true,
  466. labelWidth: 100,
  467. itemWidth: 100,
  468. rules: [],
  469. });
  470. const byform = ref(null);
  471. const treeData = ref([]);
  472. const formConfig = reactive([
  473. {
  474. type: "select",
  475. prop: "customerInfoId",
  476. label: "客户名称",
  477. isLoad: {
  478. url: "/customer/page",
  479. req: {
  480. pageNum: 1,
  481. pageSize: 9999,
  482. },
  483. labelKey: "name",
  484. labelVal: "id",
  485. method: "post",
  486. resUrl: "rows",
  487. },
  488. },
  489. {
  490. type: "select",
  491. prop: "type",
  492. label: "订单类型",
  493. itemWidth: 100,
  494. data: [],
  495. },
  496. {
  497. type: "input",
  498. prop: "contacts",
  499. label: "收件人",
  500. itemWidth: 20,
  501. },
  502. {
  503. type: "input",
  504. prop: "phone",
  505. label: " ",
  506. itemWidth: 30,
  507. },
  508. {
  509. type: "slot",
  510. slotName: "address",
  511. prop: "countryId",
  512. label: "收件地址",
  513. required: true,
  514. },
  515. {
  516. type: "title",
  517. title: "订单明细",
  518. },
  519. {
  520. type: "slot",
  521. slotName: "products",
  522. },
  523. {
  524. type: "input",
  525. prop: "amountMoney",
  526. label: "订单金额",
  527. disabled: true,
  528. itemWidth: 20,
  529. },
  530. ]);
  531. const getList = async (req) => {
  532. sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
  533. loading.value = true;
  534. proxy.post("/orderInfo/page", sourceList.value.pagination).then((message) => {
  535. console.log(message);
  536. sourceList.value.data = message.rows;
  537. sourceList.value.pagination.total = message.total;
  538. setTimeout(() => {
  539. loading.value = false;
  540. }, 200);
  541. });
  542. };
  543. const openModal = () => {
  544. dialogVisible.value = true;
  545. modalType.value = "add";
  546. formData.data = {
  547. orderDetailsList: [],
  548. countryId: "China",
  549. };
  550. getCityData(formData.data.countryId, "20");
  551. };
  552. const submitForm = () => {
  553. console.log(byform.value);
  554. byform.value.handleSubmit((valid) => {
  555. const list = formData.data.orderDetailsList;
  556. if (!list.length > 0)
  557. return ElMessage({
  558. message: `请添加订单明细!`,
  559. type: "info",
  560. });
  561. for (let i = 0; i < list.length; i++) {
  562. const e = list[i];
  563. if (e.quantity == 0) {
  564. return ElMessage({
  565. message: `数量不能为0!`,
  566. type: "info",
  567. });
  568. }
  569. }
  570. submitLoading.value = true;
  571. proxy.post("/orderInfo/" + modalType.value, formData.data).then(
  572. (res) => {
  573. ElMessage({
  574. message: modalType.value == "add" ? "添加成功" : "编辑成功",
  575. type: "success",
  576. });
  577. dialogVisible.value = false;
  578. submitLoading.value = false;
  579. getList();
  580. },
  581. (err) => (submitLoading.value = false)
  582. );
  583. });
  584. };
  585. const getDtl = (row, status) => {
  586. const statusNmae = status == 2 ? "结束" : "取消";
  587. // 弹窗提示是否删除
  588. ElMessageBox.confirm(`您确定执行${statusNmae}操作吗?`, "提示", {
  589. confirmButtonText: "确定",
  590. cancelButtonText: "取消",
  591. type: "warning",
  592. }).then(() => {
  593. // 删除
  594. proxy
  595. .post("/orderInfo/edit", {
  596. id: row.id,
  597. status,
  598. })
  599. .then((res) => {
  600. ElMessage({
  601. message: "操作成功",
  602. type: "success",
  603. });
  604. getList();
  605. });
  606. });
  607. };
  608. const warehouseList = ref([]);
  609. const salesType = ref([]);
  610. const getDict = () => {
  611. proxy.getDict(["order_sales_type"]).then((res) => {
  612. salesType.value = res["order_sales_type"];
  613. formConfig[1].data = salesType.value.map((x) => ({
  614. label: x.dictValue,
  615. value: x.dictKey,
  616. }));
  617. selectConfig[0].data = salesType.value.map((x) => ({
  618. label: x.dictValue,
  619. value: x.dictKey,
  620. }));
  621. });
  622. };
  623. const countryData = ref([]);
  624. const provinceData = ref([]);
  625. const cityData = ref([]);
  626. const getCityData = (id, type, isChange) => {
  627. proxy.post("/areaInfo/list", { parentId: id }).then((res) => {
  628. if (type === "20") {
  629. provinceData.value = res;
  630. if (isChange) {
  631. formData.data.provinceId = "";
  632. formData.data.cityId = "";
  633. }
  634. } else if (type === "30") {
  635. cityData.value = res;
  636. if (isChange) {
  637. formData.data.cityId = "";
  638. }
  639. } else {
  640. countryData.value = res;
  641. }
  642. });
  643. };
  644. getCityData("0");
  645. getList();
  646. getDict();
  647. const totalAmount = () => {
  648. let sum = 0;
  649. for (let i = 0; i < formData.data.orderDetailsList.length; i++) {
  650. const e = formData.data.orderDetailsList[i];
  651. e.total = (e.price * 1000000 * e.quantity) / 1000000;
  652. sum += e.total;
  653. }
  654. formData.data.amountMoney = sum;
  655. };
  656. const handleSelect = (row) => {
  657. const flag = formData.data.orderDetailsList.some(
  658. (x) => x.productId === row.id
  659. );
  660. if (flag)
  661. return ElMessage({
  662. message: "该物品已选择",
  663. type: "info",
  664. });
  665. formData.data.orderDetailsList.push({
  666. productName: row.name,
  667. productCode: row.code,
  668. productId: row.id,
  669. total: "",
  670. quantity: null,
  671. price: null,
  672. });
  673. return ElMessage({
  674. message: "选择成功",
  675. type: "success",
  676. });
  677. };
  678. const handleRemove = (index) => {
  679. formData.data.orderDetailsList.splice(index, 1);
  680. totalAmount();
  681. return ElMessage({
  682. message: "删除成功",
  683. type: "success",
  684. });
  685. };
  686. const handleClickCode = (row) => {
  687. formData.orderData = row;
  688. openDetails.value = true;
  689. };
  690. </script>
  691. <style lang="scss" scoped>
  692. .tenant {
  693. padding: 20px;
  694. }
  695. </style>