shopConfirm.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800
  1. <template>
  2. <Theme>
  3. <view class="wrap">
  4. <Navbar title="确认订单" fixed border autoBack @leftClick="leftClick">
  5. <template #right>
  6. <navMenu :options="{ icon: 'icon-home', text: '主页' }" />
  7. </template>
  8. </Navbar>
  9. <view class="content">
  10. <view class="cont">
  11. <addressModel @confirm="addressConfirm" v-if="isFree == 1" />
  12. <view
  13. class="card_wrapper"
  14. v-for="(item, index) in orderList"
  15. :key="index"
  16. >
  17. <view class="card_header">
  18. <view class="header_img">
  19. <image
  20. class="img"
  21. :src="`../../static/shop/icon_${item.channel}.png`"
  22. ></image>
  23. </view>
  24. <view class="header_name">{{ item.seller_name }}</view>
  25. </view>
  26. <view class="card_item">
  27. <view
  28. class="card_item_wrapper"
  29. v-for="(val, num) in item.goods"
  30. :key="num"
  31. >
  32. <view class="item_top">
  33. <view class="item_left">
  34. <image :src="val.pic_url" class="item_img"></image>
  35. </view>
  36. <view class="item_middle">
  37. <view class="title">{{ val.title }}</view>
  38. <view class="desc">{{ val.sku_desc }}</view>
  39. </view>
  40. <view class="item_right">
  41. <view class="price">
  42. <text>{{ symbol.symbol }}</text>
  43. <text>{{ Moneyhtml(val.price) }}</text>
  44. </view>
  45. <view class="total_num">X {{ val.total }}</view>
  46. </view>
  47. </view>
  48. </view>
  49. <view class="card_footer">
  50. <up-collapse :border="false" :value="collapseValue">
  51. <up-collapse-item :name="item.seller_id" :border="false">
  52. <template #title>
  53. <view class="collapse_title">
  54. <trans _t="订单总价" />:
  55. </view>
  56. </template>
  57. <template #value>
  58. <view class="collapse_value">
  59. <text>{{ symbol.symbol }} </text>
  60. <text class="item_num">{{
  61. Moneyhtml(item.allAmt)
  62. }}</text>
  63. </view>
  64. </template>
  65. <view class="card_footer_item" style="padding-top: 24rpx">
  66. <view class="item_label"> <trans _t="总价" />: </view>
  67. <view class="item_value item_red">
  68. <text>{{ symbol.symbol }} </text>
  69. <text class="item_num">{{
  70. Moneyhtml(item.allAmt)
  71. }}</text>
  72. </view>
  73. </view>
  74. <view class="card_footer_item">
  75. <view class="item_label">
  76. <trans _t="运费到仓库" />:
  77. </view>
  78. <view class="item_value">
  79. <text>{{ symbol.symbol }}</text>
  80. <text class="item_num">{{
  81. Moneyhtml(item.postAmt)
  82. }}</text>
  83. </view>
  84. </view>
  85. <view class="card_footer_item">
  86. <view class="item_label"> <trans _t="折扣" />: </view>
  87. <view class="item_value item_red">
  88. <text>-{{ symbol.symbol }}</text>
  89. <text class="item_num">{{
  90. Moneyhtml(item.disAMt)
  91. }}</text>
  92. </view>
  93. </view>
  94. <!-- <view class="card_footer_item" v-if="qualityAmount > 0">
  95. <view class="item_label">
  96. <trans _t="增值费用" />:
  97. </view>
  98. <view class="item_value item_red">
  99. <text>{{ symbol.symbol }}</text>
  100. <text class="item_num">{{ Moneyhtml(qualityAmount) }}</text>
  101. </view>
  102. </view> -->
  103. </up-collapse-item>
  104. </up-collapse>
  105. </view>
  106. </view>
  107. </view>
  108. <view class="friendly_reminder">
  109. <trans class="reminder_title" _t="温馨提示" />
  110. <view class="reminder_desc">
  111. <trans _t="提示内容" />
  112. </view>
  113. </view>
  114. <!-- <view class="add_on_box" v-if="orderList.length > 0">
  115. <view class="title">
  116. <trans _t="增值服务" />
  117. <trans _t="免费" class="title-tips" />
  118. </view>
  119. <view class="add_on_content">
  120. <view
  121. class="checkbox-row"
  122. v-for="(item, index) in vas_tiers"
  123. :key="item.serviceType"
  124. >
  125. <up-checkbox
  126. activeColor="var(--black)"
  127. labelSize="14"
  128. labelColor="#676969"
  129. iconSize="16"
  130. name="agree"
  131. usedAlone
  132. v-model:checked="item.selectIsChecked"
  133. class="right-check"
  134. >
  135. <template #label>
  136. <trans class="text" :_t="item.text" />&nbsp;&nbsp;{{
  137. symbol.symbol
  138. }}{{ Moneyhtml(item.price) }}
  139. </template>
  140. </up-checkbox>
  141. <i
  142. class="icon-font icon-question2 question-icon"
  143. @click="openTips(index)"
  144. ></i>
  145. </view>
  146. </view>
  147. </view> -->
  148. <couponModel
  149. :item="couponList"
  150. @change="changeId"
  151. isWidth
  152. style="margin-top: 24rpx"
  153. v-if="isFree == 0"
  154. />
  155. </view>
  156. <view class="footer">
  157. <view class="footer_protocol">
  158. <view class="protocol">
  159. <view
  160. class="protocol_item"
  161. v-for="(item, index) in protocolList"
  162. :key="index"
  163. @click="openAgent(item)"
  164. >
  165. <trans :_t="item.text" />
  166. </view>
  167. </view>
  168. <view class="agreed_protocol">
  169. <view
  170. class="confirm_box"
  171. :class="lang == 'zh' ? 'zh_protocol' : ''"
  172. >
  173. <Tip title="请阅读并同意" :show="tipShow">
  174. <up-checkbox
  175. activeColor="var(--black)"
  176. labelSize="14"
  177. labelColor="#676969"
  178. iconSize="16"
  179. name="agree"
  180. usedAlone
  181. v-model:checked="selectAllChecked"
  182. class="right-check"
  183. >
  184. <template #label>
  185. <trans class="text" _t="我已阅读并同意" />
  186. </template>
  187. </up-checkbox>
  188. </Tip>
  189. </view>
  190. </view>
  191. </view>
  192. <view class="footer_confirm">
  193. <view class="total_info">
  194. <view class="price_num">
  195. <text class="price_text" v-if="qualityAmount > 0">
  196. (
  197. <trans _t="增值费用" />:
  198. <text class="amont_num"
  199. >{{ symbol.symbol }}{{ Moneyhtml(qualityAmount) }}</text
  200. >)
  201. </text>
  202. <text>{{ symbol.symbol }}</text>
  203. <text class="num">{{ Moneyhtml(totalAmount) }}</text>
  204. </view>
  205. <view class="price_text">
  206. <trans _t="总计不含国际运费" />
  207. </view>
  208. </view>
  209. <view class="total_btn" @click="submit">
  210. <trans _t="提交" />
  211. </view>
  212. </view>
  213. </view>
  214. </view>
  215. </view>
  216. <SimpleAgreementModal ref="agreementModal" />
  217. <ValueAddedModel ref="valueAddedModel" />
  218. </Theme>
  219. </template>
  220. <script setup>
  221. import Navbar from "@/components/navbar";
  222. import navMenu from "@/components/nav_menu";
  223. import { onLoad } from "@dcloudio/uni-app";
  224. import { ref, nextTick, computed, watch } from "vue";
  225. import {
  226. SHOP_CART_CONFIRM,
  227. SHOP_CART_FCONFIRM,
  228. SHOP_ORDER_SUBMIT,
  229. SHOP_ORDER_FSUBMIT,
  230. SHOP_GET_SHOPCOUPON,
  231. } from "@/api";
  232. import { Toast, Moneyhtml } from "@/utils";
  233. import { useSystemStore, useTabbarStore, useShopStore } from "@/store";
  234. import Tip from "@/components/tooltip";
  235. import SimpleAgreementModal from "@/components/simpleAgreementModal";
  236. import ValueAddedModel from "./components/valueAddedModel.vue";
  237. import couponModel from "./components/couponModel";
  238. import addressModel from "@/pages/address/components/addressModel";
  239. import { t } from "@/locale";
  240. const useSystem = useSystemStore();
  241. const useTabbar = useTabbarStore();
  242. const useShop = useShopStore();
  243. const symbol = computed(() => useSystem.getSymbol);
  244. const lang = computed(() => useSystem.getLang);
  245. const logistics = computed(() => useShop.getLogistics);
  246. const confirmId = ref("");
  247. const totalAmount = ref(0);
  248. const selectAllChecked = ref(false);
  249. const selectIsChecked = ref(false);
  250. const orderList = ref([]);
  251. const address_id = ref("");
  252. const couponId = ref("");
  253. const isPage = ref("");
  254. const tipShow = ref(false);
  255. const qualityAmount = ref(0);
  256. const agreementModal = ref(null);
  257. const couponList = ref([]);
  258. const checkDate = ref(null);
  259. const isFree = ref(0);
  260. const selectItem = ref(null);
  261. const valueAddedModel = ref(null);
  262. watch(selectAllChecked, (newVal) => {
  263. if (newVal) tipShow.value = false;
  264. });
  265. watch(selectIsChecked, (newVal) => {
  266. buyCart();
  267. });
  268. const protocolList = [
  269. {
  270. text: "违禁物品说明",
  271. type: "violation",
  272. },
  273. {
  274. text: "《服务条款》",
  275. type: "agree",
  276. },
  277. {
  278. text: "退货说明",
  279. type: "retreat",
  280. },
  281. {
  282. text: "免责声明",
  283. type: "disclaimer",
  284. },
  285. ];
  286. const vas_tiers = ref([
  287. {
  288. text: "易碎品加固",
  289. serviceType: "checkAmt",
  290. selectIsChecked: true,
  291. price: 0,
  292. },
  293. {
  294. text: "标准质检",
  295. serviceType: "checkAmt1",
  296. selectIsChecked: true,
  297. price: 0,
  298. },
  299. {
  300. text: "优先采购",
  301. serviceType: "checkAmt2",
  302. selectIsChecked: true,
  303. price: 0,
  304. },
  305. {
  306. text: "个性化拍照",
  307. serviceType: "checkAmt3",
  308. selectIsChecked: true,
  309. price: 0,
  310. },
  311. ]);
  312. watch(
  313. () => vas_tiers.value.map((item) => item.selectIsChecked),
  314. (newVal, oldVal) => {
  315. // buyCart();
  316. },
  317. { deep: true }
  318. );
  319. const addressConfirm = (item) => {
  320. selectItem.value = item;
  321. };
  322. const openTips = (type = 0) => {
  323. valueAddedModel.value && valueAddedModel.value.open(type);
  324. };
  325. const openAgent = (item) => {
  326. agreementModal.value && agreementModal.value.open(item.type);
  327. };
  328. const collapseValue = computed(() => {
  329. let arr = orderList.value.reduce((acc, item) => {
  330. acc.push(item.seller_id);
  331. return acc;
  332. }, []);
  333. return arr;
  334. });
  335. const calculateAll = (arr) => {
  336. let totalQuantity = arr.reduce((sum, item) => sum + item.total, 0);
  337. return totalQuantity;
  338. };
  339. const leftClick = () => {
  340. uni.navigateBack();
  341. // if (isPage.value == "order") {
  342. // uni.navigateBack();
  343. // } else {
  344. // uni.navigateTo({ url: "/pages/index/products?channel=1" });
  345. // }
  346. };
  347. const issubnum = ref(0);
  348. const submit = () => {
  349. if (issubnum.value == 0) {
  350. if (isFree.value == 1) {
  351. if (!selectItem.value.id) return Toast(t("请先添加收件地址"));
  352. }
  353. if (!selectAllChecked.value) return (tipShow.value = true);
  354. shopConfirm();
  355. }
  356. };
  357. const getCoupon = async (money) => {
  358. try {
  359. const res = await SHOP_GET_SHOPCOUPON(money);
  360. couponList.value = res.data || [];
  361. } catch (error) {}
  362. };
  363. const changeId = (id, data) => {
  364. if (id) {
  365. couponId.value = id;
  366. checkDate.value = data;
  367. buyCart();
  368. } else {
  369. couponId.value = "";
  370. checkDate.value = null;
  371. }
  372. };
  373. onLoad((options) => {
  374. confirmId.value = options.comfirmId;
  375. isFree.value = options.isFree || 0;
  376. isPage.value = options.page || "";
  377. nextTick(() => {
  378. buyCart();
  379. });
  380. });
  381. const shopConfirm = async () => {
  382. try {
  383. const URL = isFree.value == 1 ? SHOP_ORDER_FSUBMIT : SHOP_ORDER_SUBMIT;
  384. const res = await URL({
  385. cartids: confirmId.value,
  386. address_id: selectItem.value?.id,
  387. couponId: couponId.value,
  388. isCheck: selectIsChecked.value == false ? 0 : 1,
  389. });
  390. uni.navigateTo({
  391. url: `/pages/shop/payment?oid=${res.data.oid}&page=order&type=order`,
  392. });
  393. } catch (error) {
  394. Toast(error.msg);
  395. }
  396. };
  397. const buyCart = async () => {
  398. try {
  399. const checkedArr = vas_tiers.value.map((item) => item.selectIsChecked);
  400. const params = {
  401. isCheck: checkedArr[0] ? 1 : 0,
  402. isCheck1: checkedArr[1] ? 1 : 0,
  403. isCheck2: checkedArr[2] ? 1 : 0,
  404. isCheck3: checkedArr[3] ? 1 : 0,
  405. };
  406. const URL = isFree.value == 1 ? SHOP_CART_FCONFIRM : SHOP_CART_CONFIRM;
  407. const res = await URL({
  408. cartids: confirmId.value,
  409. ...params,
  410. couponId: couponId.value,
  411. });
  412. orderList.value = res.data.cartList || [];
  413. totalAmount.value = res.data.totalAmount || 0;
  414. qualityAmount.value = res.data.checkAmtAll || 0;
  415. vas_tiers.value.forEach((item) => {
  416. if (item.serviceType == "checkAmt") {
  417. item.price = res.data.checkAmt || 0;
  418. } else if (item.serviceType == "checkAmt1") {
  419. item.price = res.data.checkAmt1 || 0;
  420. } else if (item.serviceType == "checkAmt2") {
  421. item.price = res.data.checkAmt2 || 0;
  422. } else if (item.serviceType == "checkAmt3") {
  423. item.price = res.data.checkAmt3 || 0;
  424. }
  425. });
  426. getCoupon(totalAmount.value);
  427. } catch (error) {
  428. Toast(error.msg);
  429. }
  430. };
  431. </script>
  432. <style lang="less" scoped>
  433. @import url("@/style.less");
  434. .uni-stat-tooltip {
  435. min-width: 400rpx;
  436. max-height: 400rpx;
  437. overflow: scroll;
  438. word-break: break-word;
  439. }
  440. .wrap {
  441. max-height: 100vh;
  442. .confirm_box {
  443. width: 100%;
  444. .hor(end);
  445. .confirm_item {
  446. .ver();
  447. }
  448. }
  449. .zh_protocol {
  450. // .flex_position(flex-end);
  451. // .right-check {
  452. // margin-left: 30rpx;
  453. // }
  454. }
  455. background-color: var(--bg);
  456. .flex();
  457. flex-direction: column;
  458. overflow: hidden;
  459. .content {
  460. flex-grow: 1;
  461. height: calc(100vh - 44px);
  462. overflow: hidden scroll;
  463. .flex();
  464. flex-direction: column;
  465. .cont {
  466. padding: 0 24rpx 48rpx;
  467. flex-grow: 1;
  468. overflow: hidden scroll;
  469. .card_wrapper {
  470. padding: 16rpx 0;
  471. background-color: var(--light);
  472. margin-top: 24rpx;
  473. border-radius: 16rpx;
  474. .card_header {
  475. .ver();
  476. padding: 0 32rpx;
  477. .header_img {
  478. width: 48rpx;
  479. height: 48rpx;
  480. .img {
  481. width: inherit;
  482. height: inherit;
  483. }
  484. }
  485. .header_name {
  486. margin-left: 16rpx;
  487. font-weight: 700;
  488. .size(28rpx);
  489. color: var(--text);
  490. }
  491. }
  492. .card_item {
  493. &_wrapper {
  494. padding: 0 32rpx;
  495. padding-top: 16rpx;
  496. .item_top {
  497. .flex();
  498. column-gap: 16rpx;
  499. padding-bottom: 16rpx;
  500. .item_left {
  501. width: 128rpx;
  502. height: 128rpx;
  503. .item_img {
  504. width: inherit;
  505. height: inherit;
  506. border-radius: 16rpx;
  507. }
  508. }
  509. .item_middle {
  510. flex: 1;
  511. .title {
  512. color: var(--text);
  513. .size(24rpx);
  514. line-height: 48rpx;
  515. font-weight: 700;
  516. .ellipsis(2);
  517. }
  518. .desc {
  519. color: var(--text-01);
  520. .size(24rpx);
  521. font-weight: 400;
  522. line-height: 40rpx;
  523. margin-top: 8rpx;
  524. }
  525. }
  526. .item_right {
  527. flex: 0 0 180rpx;
  528. text-align: right;
  529. .price {
  530. .size(24rpx);
  531. color: var(--red);
  532. font-weight: 700;
  533. line-height: 60rpx;
  534. }
  535. .total_num {
  536. color: #7d8fb3;
  537. .size(24rpx);
  538. font-weight: 400;
  539. line-height: 40rpx;
  540. }
  541. }
  542. }
  543. }
  544. .card_footer {
  545. border-top: 1px solid var(--bg);
  546. /deep/ .u-collapse {
  547. .u-cell--clickable {
  548. background-color: transparent;
  549. }
  550. .u-cell__body {
  551. padding: 0 40rpx;
  552. height: 48rpx;
  553. margin-top: 4rpx;
  554. .u-cell__left-icon-wrap {
  555. margin-right: 0;
  556. }
  557. }
  558. // .u-collapse-item__content{
  559. // padding-top: 24rpx;
  560. // }
  561. .u-collapse-item__content__text {
  562. padding: 0 40rpx;
  563. }
  564. .uicon-arrow-right {
  565. color: var(--black) !important;
  566. .size() !important;
  567. font-weight: 700 !important;
  568. }
  569. }
  570. .collapse_title {
  571. .size(24rpx);
  572. color: var(--text);
  573. font-weight: 500;
  574. }
  575. .collapse_value {
  576. color: var(--red);
  577. font-weight: 700;
  578. .size();
  579. .item_num {
  580. display: inline-block;
  581. margin-left: 8rpx;
  582. }
  583. }
  584. .card_footer_item {
  585. color: var(--text-01);
  586. .size(24rpx);
  587. height: 40rpx;
  588. .flex_position(space-between);
  589. box-sizing: content-box;
  590. .item_value {
  591. &.item_red {
  592. color: var(--red);
  593. }
  594. .item_num {
  595. // .blocked();
  596. display: inline-block;
  597. margin-left: 8rpx;
  598. }
  599. }
  600. }
  601. }
  602. }
  603. }
  604. .friendly_reminder {
  605. padding: 16rpx 24rpx 24rpx;
  606. background-color: var(--light);
  607. margin-top: 20rpx;
  608. border-radius: 16rpx;
  609. color: #346;
  610. .size(24rpx);
  611. min-height: 260rpx;
  612. .reminder_title {
  613. font-weight: 700;
  614. color: var(--text);
  615. .size(28rpx);
  616. line-height: 60rpx;
  617. }
  618. }
  619. .add_on_box {
  620. width: 100%;
  621. padding: 16rpx 24rpx;
  622. background-color: var(--bg-primary);
  623. border-radius: 16rpx;
  624. .title {
  625. color: var(--text);
  626. .size(28rpx);
  627. font-weight: 700;
  628. line-height: 60rpx;
  629. .title-tips {
  630. margin: 0 12rpx;
  631. padding: 2rpx 6rpx;
  632. color: #fff;
  633. .size(24rpx);
  634. background-color: red;
  635. border-radius: 8rpx;
  636. }
  637. }
  638. .add_on_content {
  639. .hor(space-between);
  640. flex-wrap: wrap;
  641. .checkbox-row {
  642. .ver();
  643. }
  644. .question-icon {
  645. margin-left: 8rpx;
  646. font-size: 32rpx;
  647. }
  648. }
  649. }
  650. }
  651. .footer {
  652. padding-bottom: env(safe-area-inset-bottom);
  653. padding-bottom: constant(safe-area-inset-bottom);
  654. box-sizing: border-box;
  655. &_protocol {
  656. background-color: #fff3ea;
  657. padding: 16rpx 24rpx;
  658. .protocol {
  659. .flex_position(flex-end);
  660. flex-wrap: wrap;
  661. &_item {
  662. text-wrap: nowrap;
  663. color: var(--black);
  664. .size(24rpx);
  665. margin-left: 8rpx;
  666. }
  667. }
  668. .agreed_protocol {
  669. // .flex_position(flex-end);
  670. // height: 60rpx;
  671. .text {
  672. .size(28rpx);
  673. color: var(--black);
  674. }
  675. }
  676. }
  677. &_confirm {
  678. background-color: var(--light);
  679. border-top: var(--bor);
  680. height: 120rpx;
  681. .flex_position(flex-end);
  682. padding: 0 24rpx;
  683. .total_info {
  684. .ver(flex-end);
  685. flex-direction: column;
  686. .price_num {
  687. color: var(--red);
  688. .size();
  689. font-weight: 700;
  690. line-height: 48rpx;
  691. .num {
  692. display: inline-block;
  693. margin-left: 8rpx;
  694. }
  695. .icon-question2 {
  696. color: var(--text-01);
  697. font-weight: 400;
  698. .size(40rpx);
  699. margin-left: 8rpx;
  700. }
  701. }
  702. .price_text {
  703. color: var(--text-01);
  704. .size(24rpx);
  705. line-height: 40rpx;
  706. .amont_num {
  707. color: var(--red);
  708. }
  709. }
  710. }
  711. .total_btn {
  712. background-color: var(--black);
  713. color: var(--light);
  714. height: 76rpx;
  715. .size(28rpx);
  716. font-weight: 700;
  717. min-width: 180rpx;
  718. margin-left: 24rpx;
  719. border-radius: 16rpx;
  720. .flex_center();
  721. padding: 16rpx 30rpx;
  722. }
  723. }
  724. }
  725. }
  726. }
  727. </style>