5 changed files with 530 additions and 0 deletions
-
30src/pages.json
-
7src/pages/goods/goods.vue
-
385src/pagesOrder/create/create.vue
-
39src/services/order.ts
-
69src/types/order.d.ts
@ -0,0 +1,385 @@ |
|||||
|
<template> |
||||
|
<scroll-view scroll-y class="viewport"> |
||||
|
<!-- 收货地址 --> |
||||
|
<navigator |
||||
|
v-if="selecteAddress" |
||||
|
class="shipment" |
||||
|
hover-class="none" |
||||
|
url="/pagesMember/address/address?from=order" |
||||
|
> |
||||
|
<view class="user"> {{ selecteAddress.receiver }} {{ selecteAddress.contact }} </view> |
||||
|
<view class="address"> {{ selecteAddress.fullLocation }} {{ selecteAddress.address }} </view> |
||||
|
<text class="icon icon-right"></text> |
||||
|
</navigator> |
||||
|
<navigator |
||||
|
v-else |
||||
|
class="shipment" |
||||
|
hover-class="none" |
||||
|
url="/pagesMember/address/address?from=order" |
||||
|
> |
||||
|
<view class="address"> 请选择收货地址 </view> |
||||
|
<text class="icon icon-right"></text> |
||||
|
</navigator> |
||||
|
|
||||
|
<!-- 商品信息 --> |
||||
|
<view class="goods"> |
||||
|
<navigator |
||||
|
v-for="item in orderPre?.goods" |
||||
|
:key="item.skuId" |
||||
|
:url="`/pages/goods/goods?id=${item.id}`" |
||||
|
class="item" |
||||
|
hover-class="none" |
||||
|
> |
||||
|
<image class="picture" :src="item.picture" /> |
||||
|
<view class="meta"> |
||||
|
<view class="name ellipsis"> {{ item.name }} </view> |
||||
|
<view class="attrs"> {{ item.attrsText }}</view> |
||||
|
<view class="prices"> |
||||
|
<view class="pay-price symbol"> {{ item.payPrice }} </view> |
||||
|
<view class="price symbol"> {{ item.price }} </view> |
||||
|
</view> |
||||
|
<view class="count">x{{ item.count }}</view> |
||||
|
</view> |
||||
|
</navigator> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 配送及支付方式 --> |
||||
|
<view class="related"> |
||||
|
<view class="item"> |
||||
|
<text class="text">配送时间</text> |
||||
|
<picker :range="deliveryList" range-key="text" @change="onChangeDelivery"> |
||||
|
<view class="icon-fonts picker">{{ activeDelivery.text }}</view> |
||||
|
</picker> |
||||
|
</view> |
||||
|
<view class="item"> |
||||
|
<text class="text">订单备注</text> |
||||
|
<input |
||||
|
class="input" |
||||
|
:cursor-spacing="30" |
||||
|
placeholder="选题,建议留言前先与商家沟通确认" |
||||
|
v-model="buyerMessage" |
||||
|
/> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 支付金额 --> |
||||
|
<view class="settlement"> |
||||
|
<view class="item"> |
||||
|
<text class="text">商品总价: </text> |
||||
|
<text class="number symbol">{{ orderPre?.summary.totalPrice.toFixed(2) }}</text> |
||||
|
</view> |
||||
|
<view class="item"> |
||||
|
<text class="text">运费: </text> |
||||
|
<text class="number symbol">{{ orderPre?.summary.postFee.toFixed(2) }}</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
</scroll-view> |
||||
|
|
||||
|
<!-- 吸底工具栏 --> |
||||
|
<view class="toolbar" :style="{ paddingBottom: safeAreaInsets?.bottom + 'px' }"> |
||||
|
<view class="total-pay symbol"> |
||||
|
<text class="number">{{ orderPre?.summary.totalPayPrice.toFixed(2) }}</text> |
||||
|
</view> |
||||
|
<view class="button" :class="{ disabled: !selecteAddress?.id }" @tap="onOrderSubmit"> |
||||
|
提交订单 |
||||
|
</view> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { computed, ref } from 'vue' |
||||
|
import type { OrderPreResult } from '@/types/order' |
||||
|
import { onLoad } from '@dcloudio/uni-app' |
||||
|
import { getMemberOrderPreAPI, getMemberOrderPreNowAPI, postMemberOrderAPI } from '@/services/order' |
||||
|
import { useAddressStore } from '@/stores/modules/address' |
||||
|
|
||||
|
// 获取屏幕边界到安全区域距离 |
||||
|
const { safeAreaInsets } = uni.getSystemInfoSync() |
||||
|
// 订单备注 |
||||
|
const buyerMessage = ref('') |
||||
|
// 配送时间 |
||||
|
const deliveryList = ref([ |
||||
|
{ type: 1, text: '时间不限 (周一至周日)' }, |
||||
|
{ type: 2, text: '工作日送 (周一至周五)' }, |
||||
|
{ type: 3, text: '周末配送 (周六至周日)' }, |
||||
|
]) |
||||
|
// 当前配送时间下标 |
||||
|
const activeIndex = ref(0) |
||||
|
// 当前配送时间 |
||||
|
const activeDelivery = computed(() => deliveryList.value[activeIndex.value]) |
||||
|
// 修改配送时间 |
||||
|
const onChangeDelivery: UniHelper.SelectorPickerOnChange = (ev) => { |
||||
|
activeIndex.value = ev.detail.value |
||||
|
} |
||||
|
|
||||
|
// 页面参数 |
||||
|
const query = defineProps<{ |
||||
|
skuId?: string |
||||
|
count?: string |
||||
|
}>() |
||||
|
|
||||
|
// 获取订单信息 |
||||
|
const orderPre = ref<OrderPreResult>() |
||||
|
const getMemberOrderPreData = async () => { |
||||
|
// 是否有立即购买参数 |
||||
|
if (query.count && query.skuId) { |
||||
|
// 调用立即购买 API |
||||
|
const res = await getMemberOrderPreNowAPI({ |
||||
|
count: query.count, |
||||
|
skuId: query.skuId, |
||||
|
}) |
||||
|
orderPre.value = res.result |
||||
|
} else { |
||||
|
// 调用预付订单 API |
||||
|
const res = await getMemberOrderPreAPI() |
||||
|
orderPre.value = res.result |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
onLoad(() => { |
||||
|
getMemberOrderPreData() |
||||
|
}) |
||||
|
|
||||
|
const addressStore = useAddressStore() |
||||
|
// 收货地址 |
||||
|
const selecteAddress = computed(() => { |
||||
|
return addressStore.selectedAddress || orderPre.value?.userAddresses.find((v) => v.isDefault) |
||||
|
}) |
||||
|
|
||||
|
// 提交订单 |
||||
|
const onOrderSubmit = async () => { |
||||
|
// 没有收货地址提醒 |
||||
|
if (!selecteAddress.value?.id) { |
||||
|
return uni.showToast({ icon: 'none', title: '请选择收货地址' }) |
||||
|
} |
||||
|
// 发送请求 |
||||
|
const res = await postMemberOrderAPI({ |
||||
|
addressId: selecteAddress.value?.id, |
||||
|
buyerMessage: buyerMessage.value, |
||||
|
deliveryTimeType: activeDelivery.value.type, |
||||
|
goods: orderPre.value!.goods.map((v) => ({ count: v.count, skuId: v.skuId })), |
||||
|
payChannel: 2, |
||||
|
payType: 1, |
||||
|
}) |
||||
|
// 关闭当前页面,跳转到订单详情,传递订单id |
||||
|
uni.redirectTo({ url: `/pagesOrder/detail/detail?id=${res.result.id}` }) |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss"> |
||||
|
page { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
height: 100%; |
||||
|
overflow: hidden; |
||||
|
background-color: #f4f4f4; |
||||
|
} |
||||
|
|
||||
|
.symbol::before { |
||||
|
content: '¥'; |
||||
|
font-size: 80%; |
||||
|
margin-right: 5rpx; |
||||
|
} |
||||
|
|
||||
|
.shipment { |
||||
|
margin: 20rpx; |
||||
|
padding: 30rpx 30rpx 30rpx 84rpx; |
||||
|
font-size: 26rpx; |
||||
|
border-radius: 10rpx; |
||||
|
background: url(https://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/images/locate.png) |
||||
|
20rpx center / 50rpx no-repeat #fff; |
||||
|
position: relative; |
||||
|
|
||||
|
.icon { |
||||
|
font-size: 36rpx; |
||||
|
color: #333; |
||||
|
transform: translateY(-50%); |
||||
|
position: absolute; |
||||
|
top: 50%; |
||||
|
right: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.user { |
||||
|
color: #333; |
||||
|
margin-bottom: 5rpx; |
||||
|
} |
||||
|
|
||||
|
.address { |
||||
|
color: #666; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.goods { |
||||
|
margin: 20rpx; |
||||
|
padding: 0 20rpx; |
||||
|
border-radius: 10rpx; |
||||
|
background-color: #fff; |
||||
|
|
||||
|
.item { |
||||
|
display: flex; |
||||
|
padding: 30rpx 0; |
||||
|
border-top: 1rpx solid #eee; |
||||
|
|
||||
|
&:first-child { |
||||
|
border-top: none; |
||||
|
} |
||||
|
|
||||
|
.picture { |
||||
|
width: 170rpx; |
||||
|
height: 170rpx; |
||||
|
border-radius: 10rpx; |
||||
|
margin-right: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.meta { |
||||
|
flex: 1; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
justify-content: center; |
||||
|
position: relative; |
||||
|
} |
||||
|
|
||||
|
.name { |
||||
|
height: 80rpx; |
||||
|
font-size: 26rpx; |
||||
|
color: #444; |
||||
|
} |
||||
|
|
||||
|
.attrs { |
||||
|
line-height: 1.8; |
||||
|
padding: 0 15rpx; |
||||
|
margin-top: 6rpx; |
||||
|
font-size: 24rpx; |
||||
|
align-self: flex-start; |
||||
|
border-radius: 4rpx; |
||||
|
color: #888; |
||||
|
background-color: #f7f7f8; |
||||
|
} |
||||
|
|
||||
|
.prices { |
||||
|
display: flex; |
||||
|
align-items: baseline; |
||||
|
margin-top: 6rpx; |
||||
|
font-size: 28rpx; |
||||
|
|
||||
|
.pay-price { |
||||
|
margin-right: 10rpx; |
||||
|
color: #cf4444; |
||||
|
} |
||||
|
|
||||
|
.price { |
||||
|
font-size: 24rpx; |
||||
|
color: #999; |
||||
|
text-decoration: line-through; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.count { |
||||
|
position: absolute; |
||||
|
bottom: 0; |
||||
|
right: 0; |
||||
|
font-size: 26rpx; |
||||
|
color: #444; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.related { |
||||
|
margin: 20rpx; |
||||
|
padding: 0 20rpx; |
||||
|
border-radius: 10rpx; |
||||
|
background-color: #fff; |
||||
|
|
||||
|
.item { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
min-height: 80rpx; |
||||
|
font-size: 26rpx; |
||||
|
color: #333; |
||||
|
} |
||||
|
|
||||
|
.input { |
||||
|
flex: 1; |
||||
|
text-align: right; |
||||
|
margin: 20rpx 0; |
||||
|
padding-right: 20rpx; |
||||
|
font-size: 26rpx; |
||||
|
color: #999; |
||||
|
} |
||||
|
|
||||
|
.item .text { |
||||
|
width: 125rpx; |
||||
|
} |
||||
|
|
||||
|
.picker { |
||||
|
color: #666; |
||||
|
} |
||||
|
|
||||
|
.picker::after { |
||||
|
content: '\e6c2'; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* 结算清单 */ |
||||
|
.settlement { |
||||
|
margin: 20rpx; |
||||
|
padding: 0 20rpx; |
||||
|
border-radius: 10rpx; |
||||
|
background-color: #fff; |
||||
|
|
||||
|
.item { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: space-between; |
||||
|
height: 80rpx; |
||||
|
font-size: 26rpx; |
||||
|
color: #333; |
||||
|
} |
||||
|
|
||||
|
.danger { |
||||
|
color: #cf4444; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* 吸底工具栏 */ |
||||
|
.toolbar { |
||||
|
position: fixed; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
bottom: calc(var(--window-bottom)); |
||||
|
z-index: 1; |
||||
|
|
||||
|
background-color: #fff; |
||||
|
height: 100rpx; |
||||
|
padding: 0 20rpx; |
||||
|
border-top: 1rpx solid #eaeaea; |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
box-sizing: content-box; |
||||
|
|
||||
|
.total-pay { |
||||
|
font-size: 40rpx; |
||||
|
color: #cf4444; |
||||
|
|
||||
|
.decimal { |
||||
|
font-size: 75%; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.button { |
||||
|
width: 220rpx; |
||||
|
text-align: center; |
||||
|
line-height: 72rpx; |
||||
|
font-size: 26rpx; |
||||
|
color: #fff; |
||||
|
border-radius: 72rpx; |
||||
|
background-color: #27ba9b; |
||||
|
} |
||||
|
|
||||
|
.disabled { |
||||
|
opacity: 0.6; |
||||
|
} |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,39 @@ |
|||||
|
import type { OrderCreateParams, OrderPreResult } from '@/types/order' |
||||
|
import { http } from '@/utils/http' |
||||
|
|
||||
|
/** |
||||
|
* 填写订单-获取预付订单 |
||||
|
*/ |
||||
|
export const getMemberOrderPreAPI = () => { |
||||
|
return http<OrderPreResult>({ |
||||
|
method: 'GET', |
||||
|
url: '/member/order/pre', |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 填写订单-获取立即购买订单 |
||||
|
*/ |
||||
|
export const getMemberOrderPreNowAPI = (data: { |
||||
|
skuId: string |
||||
|
count: string |
||||
|
addressId?: string |
||||
|
}) => { |
||||
|
return http<OrderPreResult>({ |
||||
|
method: 'GET', |
||||
|
url: '/member/order/pre/now', |
||||
|
data, |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 提交订单 |
||||
|
* @param data 请求参数 |
||||
|
*/ |
||||
|
export const postMemberOrderAPI = (data: OrderCreateParams) => { |
||||
|
return http<{ id: string }>({ |
||||
|
method: 'POST', |
||||
|
url: '/member/order', |
||||
|
data, |
||||
|
}) |
||||
|
} |
@ -0,0 +1,69 @@ |
|||||
|
import type { AddressItem } from './address' |
||||
|
|
||||
|
/** 获取预付订单 返回信息 */ |
||||
|
export type OrderPreResult = { |
||||
|
/** 商品集合 [ 商品信息 ] */ |
||||
|
goods: OrderPreGoods[] |
||||
|
/** 结算信息 */ |
||||
|
summary: { |
||||
|
/** 商品总价 */ |
||||
|
totalPrice: number |
||||
|
/** 邮费 */ |
||||
|
postFee: number |
||||
|
/** 应付金额 */ |
||||
|
totalPayPrice: number |
||||
|
} |
||||
|
/** 用户地址列表 [ 地址信息 ] */ |
||||
|
userAddresses: AddressItem[] |
||||
|
} |
||||
|
|
||||
|
/** 商品信息 */ |
||||
|
export type OrderPreGoods = { |
||||
|
/** 属性文字,例如“颜色:瓷白色 尺寸:8寸” */ |
||||
|
attrsText: string |
||||
|
/** 数量 */ |
||||
|
count: number |
||||
|
/** id */ |
||||
|
id: string |
||||
|
/** 商品名称 */ |
||||
|
name: string |
||||
|
/** 实付单价 */ |
||||
|
payPrice: string |
||||
|
/** 图片 */ |
||||
|
picture: string |
||||
|
/** 原单价 */ |
||||
|
price: string |
||||
|
/** SKUID */ |
||||
|
skuId: string |
||||
|
/** 实付价格小计 */ |
||||
|
totalPayPrice: string |
||||
|
/** 小计总价 */ |
||||
|
totalPrice: string |
||||
|
} |
||||
|
|
||||
|
/** 提交订单 请求参数 */ |
||||
|
export type OrderCreateParams = { |
||||
|
/** 所选地址Id */ |
||||
|
addressId: string |
||||
|
/** 配送时间类型,1为不限,2为工作日,3为双休或假日 */ |
||||
|
deliveryTimeType: number |
||||
|
/** 订单备注 */ |
||||
|
buyerMessage: string |
||||
|
/** 商品集合[ 商品信息 ] */ |
||||
|
goods: { |
||||
|
/** 数量 */ |
||||
|
count: number |
||||
|
/** skuId */ |
||||
|
skuId: string |
||||
|
}[] |
||||
|
/** 支付渠道:支付渠道,1支付宝、2微信--支付方式为在线支付时,传值,为货到付款时,不传值 */ |
||||
|
payChannel: 1 | 2 |
||||
|
/** 支付方式,1为在线支付,2为货到付款 */ |
||||
|
payType: 1 | 2 |
||||
|
} |
||||
|
|
||||
|
/** 提交订单 返回信息 */ |
||||
|
export type OrderCreateResult = { |
||||
|
/** 订单Id */ |
||||
|
id: string |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue