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