index.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717
  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. placeholder="请输入"
  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="'orderDetailsList.' + $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. placeholder="请输入"
  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="'orderDetailsList.' + $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. @click="submitForm('byform')"
  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. </div>
  231. </template>
  232. <script setup>
  233. /* eslint-disable vue/no-unused-components */
  234. import { ElMessage, ElMessageBox } from "element-plus";
  235. import byTable from "@/components/byTable/index";
  236. import byForm from "@/components/byForm/index";
  237. import { computed, defineComponent, ref } from "vue";
  238. import useUserStore from "@/store/modules/user";
  239. import SelectProduct from "@/components/WDLY/product/SelectProduct";
  240. import OrderDetails from "@/components/WDLY/order/details";
  241. const loading = ref(false);
  242. const submitLoading = ref(false);
  243. const sourceList = ref({
  244. data: [],
  245. pagination: {
  246. total: 3,
  247. pageNum: 1,
  248. pageSize: 10,
  249. },
  250. });
  251. let dialogVisible = ref(false);
  252. let openProduct = ref(false);
  253. let openDetails = ref(false);
  254. let roomDialogVisible = ref(false);
  255. let modalType = ref("add");
  256. let rules = ref({
  257. customerInfoId: [
  258. {
  259. required: true,
  260. message: "请选择客户",
  261. trigger: "change",
  262. },
  263. ],
  264. type: [
  265. {
  266. required: true,
  267. message: "请选择订单类型",
  268. trigger: "change",
  269. },
  270. ],
  271. countryId: [
  272. {
  273. required: true,
  274. message: "请选择国家",
  275. trigger: "change",
  276. },
  277. ],
  278. provinceId: [
  279. {
  280. required: true,
  281. message: "请选择省/洲",
  282. trigger: "change",
  283. },
  284. ],
  285. cityId: [
  286. {
  287. required: true,
  288. message: "请选择城市",
  289. trigger: "change",
  290. },
  291. ],
  292. contacts: [
  293. {
  294. required: true,
  295. message: "请输入姓名",
  296. trigger: "blur",
  297. },
  298. ],
  299. phone: [
  300. {
  301. required: true,
  302. message: "请输入联系电话",
  303. trigger: "blur",
  304. },
  305. ],
  306. detailedAddress: [
  307. {
  308. required: true,
  309. message: "请输入详细地址",
  310. trigger: "blur",
  311. },
  312. ],
  313. price: [
  314. {
  315. required: true,
  316. message: "请输入单价",
  317. trigger: "blur",
  318. },
  319. ],
  320. quantity: [
  321. {
  322. required: true,
  323. message: "请输入数量",
  324. trigger: "blur",
  325. },
  326. ],
  327. });
  328. const { proxy } = getCurrentInstance();
  329. const selectConfig = reactive([
  330. {
  331. label: "订单类型",
  332. prop: "type",
  333. data: [],
  334. },
  335. {
  336. label: "订单状态",
  337. prop: "status",
  338. data: [
  339. {
  340. label: "进行中",
  341. value: "1",
  342. },
  343. {
  344. label: "已完成",
  345. value: "2",
  346. },
  347. {
  348. label: "已取消",
  349. value: "3",
  350. },
  351. ],
  352. },
  353. ]);
  354. const config = computed(() => {
  355. return [
  356. {
  357. attrs: {
  358. label: "订单类型",
  359. prop: "type",
  360. },
  361. render(type) {
  362. return proxy.dictDataEcho(type, salesType.value);
  363. },
  364. },
  365. {
  366. attrs: {
  367. label: "订单编号",
  368. prop: "code",
  369. slot: "code",
  370. },
  371. },
  372. {
  373. attrs: {
  374. label: "客户名称",
  375. prop: "customerName",
  376. },
  377. },
  378. {
  379. attrs: {
  380. label: "订单金额",
  381. prop: "amountMoney",
  382. },
  383. render(money) {
  384. return proxy.moneyFormat(money, 4);
  385. },
  386. },
  387. {
  388. attrs: {
  389. label: "收件人",
  390. prop: "contacts",
  391. },
  392. },
  393. {
  394. attrs: {
  395. label: "联系电话",
  396. prop: "phone",
  397. },
  398. },
  399. {
  400. attrs: {
  401. label: "收件城市",
  402. prop: "address",
  403. slot: "address",
  404. },
  405. },
  406. {
  407. attrs: {
  408. label: "下单时间",
  409. prop: "createTime",
  410. },
  411. },
  412. {
  413. attrs: {
  414. label: "订单状态",
  415. prop: "status",
  416. },
  417. render(status) {
  418. return status == 1 ? "进行中" : status == 2 ? "已完成" : "已取消";
  419. },
  420. },
  421. {
  422. attrs: {
  423. label: "操作",
  424. width: "200",
  425. align: "right",
  426. },
  427. // 渲染 el-button,一般用在最后一列。
  428. renderHTML(row) {
  429. return [
  430. row.status == 1
  431. ? {
  432. attrs: {
  433. label: "结束",
  434. type: "primary",
  435. text: true,
  436. },
  437. el: "button",
  438. click() {
  439. getDtl(row, 2);
  440. },
  441. }
  442. : {},
  443. row.status == 1
  444. ? {
  445. attrs: {
  446. label: "取消",
  447. type: "primary",
  448. text: true,
  449. },
  450. el: "button",
  451. click() {
  452. getDtl(row, 3);
  453. },
  454. }
  455. : {},
  456. ];
  457. },
  458. },
  459. ];
  460. });
  461. let formData = reactive({
  462. data: {},
  463. treeData: [],
  464. orderData: {},
  465. });
  466. const formOption = reactive({
  467. inline: true,
  468. labelWidth: 100,
  469. itemWidth: 100,
  470. rules: [],
  471. });
  472. const byform = ref(null);
  473. const treeData = ref([]);
  474. const formConfig = reactive([
  475. {
  476. type: "select",
  477. prop: "customerInfoId",
  478. label: "客户名称",
  479. isLoad: {
  480. url: "/customer/page",
  481. req: {
  482. pageNum: 1,
  483. pageSize: 9999,
  484. },
  485. labelKey: "name",
  486. labelVal: "id",
  487. method: "post",
  488. resUrl: "rows",
  489. },
  490. },
  491. {
  492. type: "select",
  493. prop: "type",
  494. label: "订单类型",
  495. itemWidth: 100,
  496. data: [],
  497. },
  498. {
  499. type: "input",
  500. prop: "contacts",
  501. label: "收件人",
  502. itemWidth: 20,
  503. placeholder: "姓名",
  504. },
  505. {
  506. type: "input",
  507. prop: "phone",
  508. label: " ",
  509. itemWidth: 30,
  510. placeholder: "联系电话",
  511. },
  512. {
  513. type: "slot",
  514. slotName: "address",
  515. prop: "countryId",
  516. label: "收件地址",
  517. required: true,
  518. },
  519. {
  520. type: "title",
  521. title: "订单明细",
  522. },
  523. {
  524. type: "slot",
  525. slotName: "products",
  526. },
  527. {
  528. type: "input",
  529. prop: "amountMoney",
  530. label: "订单金额",
  531. disabled: true,
  532. itemWidth: 20,
  533. },
  534. ]);
  535. const getList = async (req) => {
  536. sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
  537. loading.value = true;
  538. proxy.post("/orderInfo/page", sourceList.value.pagination).then((message) => {
  539. console.log(message);
  540. sourceList.value.data = message.rows;
  541. sourceList.value.pagination.total = message.total;
  542. setTimeout(() => {
  543. loading.value = false;
  544. }, 200);
  545. });
  546. };
  547. const openModal = () => {
  548. dialogVisible.value = true;
  549. modalType.value = "add";
  550. formData.data = {
  551. orderDetailsList: [],
  552. countryId: "China",
  553. };
  554. getCityData(formData.data.countryId, "20");
  555. };
  556. const submitForm = () => {
  557. console.log(byform.value);
  558. byform.value.handleSubmit((valid) => {
  559. const list = formData.data.orderDetailsList;
  560. if (!list.length > 0)
  561. return ElMessage({
  562. message: `请添加订单明细!`,
  563. type: "info",
  564. });
  565. for (let i = 0; i < list.length; i++) {
  566. const e = list[i];
  567. if (e.quantity == 0) {
  568. return ElMessage({
  569. message: `数量不能为0!`,
  570. type: "info",
  571. });
  572. }
  573. }
  574. submitLoading.value = true;
  575. proxy.post("/orderInfo/" + modalType.value, formData.data).then(
  576. (res) => {
  577. ElMessage({
  578. message: modalType.value == "add" ? "添加成功" : "编辑成功",
  579. type: "success",
  580. });
  581. dialogVisible.value = false;
  582. submitLoading.value = false;
  583. getList();
  584. },
  585. (err) => (submitLoading.value = false)
  586. );
  587. });
  588. };
  589. const getDtl = (row, status) => {
  590. const statusNmae = status == 2 ? "结束" : "取消";
  591. // 弹窗提示是否删除
  592. ElMessageBox.confirm(`您确定执行${statusNmae}操作吗?`, "提示", {
  593. confirmButtonText: "确定",
  594. cancelButtonText: "取消",
  595. type: "warning",
  596. }).then(() => {
  597. // 删除
  598. proxy
  599. .post("/orderInfo/edit", {
  600. id: row.id,
  601. status,
  602. })
  603. .then((res) => {
  604. ElMessage({
  605. message: "操作成功",
  606. type: "success",
  607. });
  608. getList();
  609. });
  610. });
  611. };
  612. const warehouseList = ref([]);
  613. const salesType = ref([]);
  614. const getDict = () => {
  615. proxy.getDict(["order_sales_type"]).then((res) => {
  616. salesType.value = res["order_sales_type"];
  617. formConfig[1].data = salesType.value.map((x) => ({
  618. label: x.dictValue,
  619. value: x.dictKey,
  620. }));
  621. selectConfig[0].data = salesType.value.map((x) => ({
  622. label: x.dictValue,
  623. value: x.dictKey,
  624. }));
  625. });
  626. };
  627. const countryData = ref([]);
  628. const provinceData = ref([]);
  629. const cityData = ref([]);
  630. const getCityData = (id, type, isChange) => {
  631. proxy.post("/areaInfo/list", { parentId: id }).then((res) => {
  632. if (type === "20") {
  633. provinceData.value = res;
  634. if (isChange) {
  635. formData.data.provinceId = "";
  636. formData.data.cityId = "";
  637. }
  638. } else if (type === "30") {
  639. cityData.value = res;
  640. if (isChange) {
  641. formData.data.cityId = "";
  642. }
  643. } else {
  644. countryData.value = res;
  645. }
  646. });
  647. };
  648. getCityData("0");
  649. getList();
  650. getDict();
  651. const totalAmount = () => {
  652. let sum = 0;
  653. for (let i = 0; i < formData.data.orderDetailsList.length; i++) {
  654. const e = formData.data.orderDetailsList[i];
  655. e.total = (e.price * 1000000 * e.quantity) / 1000000;
  656. sum += e.total;
  657. }
  658. formData.data.amountMoney = sum;
  659. };
  660. const handleSelect = (row) => {
  661. const flag = formData.data.orderDetailsList.some(
  662. (x) => x.productId === row.id
  663. );
  664. if (flag)
  665. return ElMessage({
  666. message: "该物品已选择",
  667. type: "info",
  668. });
  669. formData.data.orderDetailsList.push({
  670. productName: row.name,
  671. productCode: row.code,
  672. productId: row.id,
  673. total: "",
  674. quantity: null,
  675. price: null,
  676. });
  677. return ElMessage({
  678. message: "选择成功",
  679. type: "success",
  680. });
  681. };
  682. const handleRemove = (index) => {
  683. formData.data.orderDetailsList.splice(index, 1);
  684. totalAmount();
  685. return ElMessage({
  686. message: "删除成功",
  687. type: "success",
  688. });
  689. };
  690. const handleClickCode = (row) => {
  691. formData.orderData = row;
  692. openDetails.value = true;
  693. };
  694. </script>
  695. <style lang="scss" scoped>
  696. .tenant {
  697. padding: 20px;
  698. }
  699. </style>