Browse Source

订单模块填写订单

template
liruiqiang 4 weeks ago
parent
commit
5b49b3afbd
  1. 30
      src/pages.json
  2. 7
      src/pages/goods/goods.vue
  3. 385
      src/pagesOrder/create/create.vue
  4. 39
      src/services/order.ts
  5. 69
      src/types/order.d.ts

30
src/pages.json

@ -144,6 +144,36 @@
}
}
]
},
{
"root": "pagesOrder",
"pages": [
{
"path": "create/create",
"style": {
"navigationBarTitleText": "填写订单"
}
},
{
"path": "detail/detail",
"style": {
"navigationBarTitleText": "订单详情",
"navigationStyle": "custom"
}
},
{
"path": "payment/payment",
"style": {
"navigationBarTitleText": "支付结果"
}
},
{
"path": "list/list",
"style": {
"navigationBarTitleText": "订单列表"
}
}
]
}
],
//

7
src/pages/goods/goods.vue

@ -128,6 +128,7 @@
backgroundColor: '#E9F8F5',
}"
@add-cart="onAddCart"
@buy-now="onBuyNow"
/>
</template>
@ -249,6 +250,12 @@ const onAddCart = async (ev: SkuPopupEvent) => {
uni.showToast({ title: '添加成功' })
isShowSku.value = false
}
//
const onBuyNow = (ev: SkuPopupEvent) => {
uni.navigateTo({ url: `/pagesOrder/create/create?skuId=${ev._id}&count=${ev.buy_num}` })
isShowSku.value = false
}
</script>
<style lang="scss">

385
src/pagesOrder/create/create.vue

@ -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>

39
src/services/order.ts

@ -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,
})
}

69
src/types/order.d.ts

@ -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
}
Loading…
Cancel
Save