Files

622 lines
15 KiB
Vue
Raw Normal View History

2023-11-14 17:21:03 +08:00
<script setup>
import UvNavbar from "@/uni_modules/uv-navbar/components/uv-navbar/uv-navbar.vue";
import { useRouter } from "@/hooks/useRouter";
import { onLoad, onPageScroll } from "@dcloudio/uni-app";
import { ref, unref } from "vue";
import { useMainStore } from '@/store/store';
import { storeToRefs } from "pinia";
import { orderConfirm, orderCreate } from "@/api/order";
import { useInterface } from "@/hooks/useInterface";
import { addressTabs, discountsPriceRows, payRows, priceRows } from "@/pages/submitOrder/index.data";
import Goods from "@/components/goodsComponents/Goods.vue"
import UvRadioGroup from "@/uni_modules/uv-radio/components/uv-radio-group/uv-radio-group.vue";
import UvRadio from "@/uni_modules/uv-radio/components/uv-radio/uv-radio.vue";
import { doPayment, PayType } from "@/utils/paymentUtils";
import CouponSelect from "@/pages/submitOrder/components/coupon-select.vue";
import Header from "@/components/Header/index.vue"
const {getParams, push, goBack} = useRouter()
const {toast, loading, hideLoading} = useInterface();
const mainStore = useMainStore();
const {selectAddress, defaultAddress, address} = storeToRefs(mainStore);
const routerParams = ref({})
const selectCouponRef = ref(false)
const couponList = ref([])
const selectCoupon = ref({})
const currentCouponId = ref(0)
const cartIds = ref('')
const flag = ref(false)
const selectCouponFn = async (coupon) => {
currentCouponId.value = coupon.couponId
orderDetail.value = await orderConfirm({
cartId: unref(routerParams).cartId,
addressId: unref(selectAddress)?.id || undefined,
couponId: currentCouponId.value
})
selectCouponRef.value.close()
}
const addressTabSelect = ref(0) // 提货方式
/**
* 选择提货方式
* @param tab
*/
function changeAddressTab(tab) {
if (tab.value === 1) {
toast({title: '😒敬请期待😒'})
} else {
addressTabSelect.value = tab.value
}
}
/**
* 去选择地址
*/
function gotoSelectAddress() {
push({url: '/pages/address/address'}, {data: {type: 'select', cartId: unref(routerParams).cartId}})
}
/**
* 获取默认选择的地址
* @returns {Promise<void>}
*/
async function doGetSelectAddress() {
// store内部没有地址就先去获取地址
if (unref(address).length <= 0) {
await mainStore.getAddressList(1)
}
// 获取完地址还是空
if (unref(address).length <= 0) {
return
}
// 没有默认地址设置默认地址
if (!selectAddress.value || !selectAddress.value?.id) {
defaultAddress.value && defaultAddress.value.id ? mainStore.setSelectAddress(defaultAddress.value.id) : mainStore.setSelectAddress(unref(address)[0].id)
}
}
const payType = ref(PayType["0"]) // 支付方式
// 初始订单信息
const orderDetail = ref({
cartInfo: [],
priceGroup: {
costPrice: 0, payIntegral: 0, storeFreePostage: 0, storePostage: 0, totalPrice: 0, vipPrice: 0
}
})
/**
* 获取初始订单信息
* todo 如果没有地址选择地址后需要重新调用
* @returns {Promise<void>}
*/
async function doGetInitConfirmOrder() {
orderDetail.value = await orderConfirm({
cartId: unref(routerParams).cartId,
addressId: unref(selectAddress)?.id || undefined
})
cartIds.value = unref(routerParams).cartId
currentCouponId.value = orderDetail.value.priceGroup.couponId
flag.value = true
}
const subLoading = ref(false) // 加载中
const showCouponSelect = (index) => {
if (index === 0) {
selectCouponRef.value.open()
}
}
async function handleConfirm() {
if (!unref(selectAddress) || !unref(selectAddress).id) {
toast({title: '请先选择地址'})
return
}
subLoading.value = true
try {
const payInfo = await doCreateServiceOrder()
debugger
// 去拉取支付
await doPayment({type: payType.value, payInfo})
// #ifndef H5
push({url: '/pages/payStatus/index?type=1'}, {type: 'redirectTo'})
// #endif
} catch (e) {
console.error(e)
toast({title: '支付失败'})
push({url: '/pages/payStatus/index?type=2'}, {type: 'redirectTo'})
} finally {
subLoading.value = false
mainStore.cartId = null
}
}
/**
* 服务端创建订单
*/
async function doCreateServiceOrder() {
try {
loading({title: '订单创建中...'})
const res = await orderCreate({
key: unref(orderDetail).orderKey,
addressId: unref(selectAddress).id,
bargainId: 0,
combinationId: 0,
couponId: currentCouponId.value,
from: '',
mark: '',
pinkId: 0,
seckillId: 0,
shippingType: addressTabSelect.value,
useIntegral: 0,
isChannel: 1,
});
return res.result
} finally {
hideLoading()
}
}
const scrollTop = ref(0)
onPageScroll(e => {
scrollTop.value = e.scrollTop
})
/**
* 检查路由参数
*/
function checkRouterParam(params) {
if (!params.cartId) {
toast({title: '路由参数错误'})
return
}
routerParams.value = params
}
onLoad(async options => {
try {
const params = getParams(options)
await checkRouterParam(params)
await doGetSelectAddress()
await doGetInitConfirmOrder()
} catch (e) {
console.error(e)
}
})
</script>
2023-10-11 11:27:47 +08:00
<template>
2023-11-14 17:21:03 +08:00
<view class="order-confirm">
<!-- header -->
<Header :scroll-top="scrollTop">
提交订单
</Header>
<!-- 地址 -->
<view class="address-box">
<view
class="address-box__inner"
>
<view class="tab-box">
<!-- tab top -->
<view class="title-row flex flex-ai__center flex-jc__sb">
<view
class="item flex flex-ai__center flex-jc__center"
:class="{active:addressTabSelect === tab.value}"
v-for="tab in addressTabs"
:key="tab.value"
@click.stop="changeAddressTab(tab)"
>
{{ tab.label }}
2023-10-11 11:27:47 +08:00
</view>
2023-11-14 17:21:03 +08:00
</view>
<!-- address info -->
<view
class="address-row flex flex-ai__center flex-jc__sb"
v-if="address.length>0"
@click="gotoSelectAddress"
>
<view
class="flex flex-ai__center"
v-if="selectAddress"
>
<uv-icon
name="map"
size="22"
/>
<view class="info">
<view>
{{ selectAddress.realName }} {{ selectAddress.phone }}
</view>
<view class="address-info">
{{ selectAddress.province }} - {{ selectAddress.city }}- {{ selectAddress.district }} -
{{ selectAddress.detail }}
</view>
</view>
2023-10-11 11:27:47 +08:00
</view>
2023-11-14 17:21:03 +08:00
<image
class="arrow-icon"
src="@/static/images/next.png"
alt=""
/>
2023-10-11 11:27:47 +08:00
</view>
2023-11-14 17:21:03 +08:00
<view
class="address-row flex flex-ai__center flex-jc__sb"
v-else
@click="gotoSelectAddress"
>
点击添加地址
<image
class="arrow-icon"
2023-10-11 11:27:47 +08:00
src="@/static/images/next.png"
alt=""
2023-11-14 17:21:03 +08:00
/>
2023-10-11 11:27:47 +08:00
</view>
</view>
2023-11-14 17:21:03 +08:00
</view>
</view>
<!-- 商品清单 -->
<view
class="main-box goods-box"
v-show="orderDetail.cartInfo.length>0"
>
<view class="title-row flex flex-ai__end">
商品清单
<span class="small">
{{ orderDetail.cartInfo.length }}
</span>
</view>
<template v-for="sku in orderDetail.cartInfo">
<view class="goods-row">
<Goods
info-padding="0 10rpx 20rpx 10rpx"
:goods="sku.productInfo"
row
imgWidth="200rpx"
>
<template #options="{goods}">
<view class="goods-detail">
<view class="sku-row">
{{ goods.attrInfo.sku }}
</view>
<view class="price-row flex flex-ai__center flex-jc__sb">
<view class="price flex flex-ai__end">
{{ sku.truePrice }}
<span class="old-price">
{{ goods.otPrice }}
</span>
</view>
<view class="cart-num">
x{{ sku.cartNum }}
</view>
</view>
</view>
</template>
</Goods>
</view>
</template>
</view>
<!-- 优惠价格信息 -->
<view class="main-box price-box">
<template
v-for="(row,index) in discountsPriceRows"
:key="index"
>
2023-10-11 11:27:47 +08:00
<view
2023-11-14 17:21:03 +08:00
class="row flex flex-ai__center flex-jc__sb"
@click="showCouponSelect(index)"
2023-10-11 11:27:47 +08:00
>
2023-11-14 17:21:03 +08:00
<view class="label">{{ row.label }}</view>
<view class="value">
{{ row.prefix }}
{{ orderDetail["priceGroup"][row.field]?.toFixed(2) }}
<image
class="arrow-icon"
2023-10-11 11:27:47 +08:00
src="@/static/images/next.png"
alt=""
2023-11-14 17:21:03 +08:00
/>
2023-10-11 11:27:47 +08:00
</view>
</view>
2023-11-14 17:21:03 +08:00
</template>
</view>
<view class="coupon-select">
<coupon-select
v-if="flag"
ref="selectCouponRef"
:id="cartIds"
:currentCouponId="currentCouponId"
@submitCoupon="selectCouponFn"
/>
</view>
<!-- 支付方式 -->
<view class="main-box pay-box">
<uv-radio-group
v-model="payType"
class="pay-box__inner flex flex-ai__center flex-jc__center flex-wrap"
shape="circle"
activeColor="#ec6e47"
>
<template
v-for="payItem in payRows"
:key="payItem.type"
2023-10-11 11:27:47 +08:00
>
2023-11-14 17:21:03 +08:00
<view class="pay-item">
<uv-radio
:name="payItem.type"
:disabled="payItem.disabled"
>
<view class="flex flex-ai__center flex-jc__sb">
<view
class="pay_icon"
2023-10-11 11:27:47 +08:00
>
2023-11-14 17:21:03 +08:00
<image
:src="payItem.icon"
2023-10-11 11:27:47 +08:00
alt=""
2023-11-14 17:21:03 +08:00
/>
2023-10-11 11:27:47 +08:00
</view>
2023-11-14 17:21:03 +08:00
<view class="text">
<view>
{{ payItem.label }}
2023-10-11 11:27:47 +08:00
</view>
2023-11-14 17:21:03 +08:00
<view class="e-text">
{{ payItem.eLabel }}
2023-10-11 11:27:47 +08:00
</view>
</view>
2023-11-14 17:21:03 +08:00
</view>
</uv-radio>
2023-10-11 11:27:47 +08:00
</view>
2023-11-14 17:21:03 +08:00
</template>
</uv-radio-group>
</view>
2023-10-11 11:27:47 +08:00
2023-11-14 17:21:03 +08:00
<!-- 价格信息 -->
<view class="main-box price-box">
<template
v-for="(row,index) in priceRows"
:key="index"
>
<view class="row flex flex-ai__center flex-jc__sb">
<view class="label">{{ row.label }}</view>
<view class="value">
{{ row.prefix }}
{{ orderDetail["priceGroup"][row.field]?.toFixed(2) }}
2023-10-11 11:27:47 +08:00
</view>
</view>
2023-11-14 17:21:03 +08:00
</template>
</view>
2023-10-11 11:27:47 +08:00
2023-11-14 17:21:03 +08:00
<!-- 底部操作条 -->
<view class="bottom-empty-height"></view>
<view class="bottom-option-box flex flex-jc__sb flex-ai__center">
<view class="info">
总计{{ orderDetail.priceGroup.totalPrice?.toFixed(2) }}
</view>
<view
class="animation-button sub-button"
:class="{disabled:subLoading}"
@click="handleConfirm"
>
提交订单
2023-10-11 11:27:47 +08:00
</view>
</view>
2023-11-14 17:21:03 +08:00
</view>
2023-10-11 11:27:47 +08:00
</template>
2023-11-14 17:21:03 +08:00
<style
scoped
lang="scss"
>
$bottomHeight: 100rpx;
// global
.main-box {
@include usePadding(35, 0);
margin-top: 20rpx;
width: 100%;
background: $white-color;
2023-10-11 11:27:47 +08:00
}
2023-11-14 17:21:03 +08:00
.arrow-icon {
width: 20rpx;
height: 20rpx;
2023-10-11 11:27:47 +08:00
}
2023-11-14 17:21:03 +08:00
.bottom-empty-height {
width: 100%;
height: $bottomHeight;
padding-bottom: 30rpx;
2023-10-11 11:27:47 +08:00
}
2023-11-14 17:21:03 +08:00
// box
.order-confirm {
position: relative;
2023-10-11 11:27:47 +08:00
2023-11-14 17:21:03 +08:00
.address-box {
@include usePadding(35, 30);
width: 100%;
background: $white-color;
2023-10-11 11:27:47 +08:00
2023-11-14 17:21:03 +08:00
&__inner {
width: 100%;
border: 1px solid #E6E6E6;
box-sizing: border-box;
2023-10-11 11:27:47 +08:00
2023-11-14 17:21:03 +08:00
.tab-box {
width: 100%;
2023-10-11 11:27:47 +08:00
2023-11-14 17:21:03 +08:00
// tab top
.title-row {
.item {
@include usePadding(0, 15);
flex: 1 0 auto;
background: #e6e6e6;
transition: all .4s;
&.active {
background: #333;
color: $white-color;
}
}
}
// address info
.address-row {
@include usePadding(25, 70);
width: 100%;
.info {
margin-left: 20rpx;
.address-info {
color: #333333;
margin: 10rpx 0;
//max-width: 60vw;
//overflow: hidden;
//white-space: nowrap;
//text-overflow: ellipsis;
}
}
}
}
}
2023-10-11 11:27:47 +08:00
}
2023-11-14 17:21:03 +08:00
.goods-box {
.title-row {
@include usePadding(0, 17);
color: #333;
font-size: 32rpx;
border-bottom: 1rpx solid #E6E6E6;
2023-10-11 11:27:47 +08:00
2023-11-14 17:21:03 +08:00
.small {
margin-left: 15rpx;
font-size: 24rpx;
}
2023-10-11 11:27:47 +08:00
}
2023-11-14 17:21:03 +08:00
.goods-row {
@include usePadding(0, 40);
2023-10-11 11:27:47 +08:00
2023-11-14 17:21:03 +08:00
.goods-detail {
width: 100%;
2023-10-11 11:27:47 +08:00
2023-11-14 17:21:03 +08:00
.sku-row {
color: $tips-color;
font-size: 24rpx;
margin-bottom: 30rpx;
}
.price-row {
color: $tips-color;
.price {
color: $primary-color;
font-size: 30rpx;
.old-price {
color: $tips-color;
margin-left: 10rpx;
font-size: 20rpx;
text-decoration: line-through;
}
}
.cart-num {
font-size: 24rpx;
}
}
}
2023-10-11 11:27:47 +08:00
2023-11-14 17:21:03 +08:00
}
2023-10-11 11:27:47 +08:00
}
2023-11-14 17:21:03 +08:00
.price-box {
.row {
@include usePadding(0, 30);
color: #333;
font-size: 28rpx;
border-bottom: 1rpx solid #E6E6E6;
2023-10-11 11:27:47 +08:00
2023-11-14 17:21:03 +08:00
&:last-child {
border-bottom: none;
}
2023-10-11 11:27:47 +08:00
2023-11-14 17:21:03 +08:00
.value {
color: #999;
}
}
2023-10-11 11:27:47 +08:00
}
2023-11-14 17:21:03 +08:00
.pay-box {
2023-10-11 11:27:47 +08:00
2023-11-14 17:21:03 +08:00
:deep(.uv-radio-group ) {
@include usePadding(0, 32);
gap: 20rpx;
2023-10-11 11:27:47 +08:00
2023-11-14 17:21:03 +08:00
.pay-item {
flex: 1 0 45%;
2023-10-11 11:27:47 +08:00
2023-11-14 17:21:03 +08:00
.pay_icon {
width: 63rpx;
margin: 0 20rpx;
aspect-ratio: 1/1;
2023-10-11 11:27:47 +08:00
2023-11-14 17:21:03 +08:00
image {
width: 100%;
height: 100%;
}
}
2023-10-11 11:27:47 +08:00
2023-11-14 17:21:03 +08:00
.text {
font-size: 24rpx;
2023-10-11 11:27:47 +08:00
2023-11-14 17:21:03 +08:00
.e-text {
font-size: 22rpx;
}
}
2023-10-11 11:27:47 +08:00
}
}
}
2023-11-14 17:21:03 +08:00
.bottom-option-box {
position: fixed;
width: 100%;
height: $bottomHeight;
bottom: 0;
left: 0;
background: $white-color;
2023-10-11 11:27:47 +08:00
2023-11-14 17:21:03 +08:00
.info {
@include usePadding(34, 0)
2023-10-11 11:27:47 +08:00
}
2023-11-14 17:21:03 +08:00
.sub-button {
@include usePadding(50, 0);
height: 100%;
2023-10-11 11:27:47 +08:00
2023-11-14 17:21:03 +08:00
display: flex;
align-items: center;
justify-content: center;
transition: all .3s;
2023-10-11 11:27:47 +08:00
2023-11-14 17:21:03 +08:00
}
2023-10-11 11:27:47 +08:00
}
}
2023-11-14 17:21:03 +08:00
:deep(.coupon-select) .uni-popup__wrapper {
height: auto;
max-height: 1000rpx;
overflow-y: auto;
2023-10-11 11:27:47 +08:00
}
</style>