1.填写订单-渲染基本信息
-
静态结构(分包)
-
封装请求API
import { http } from '@/utils/http'
import { OrderPreResult } from '@/types/order'export const getmemberOrderPreAPI = () => {
return http<OrderPreResult>({
method: 'GET',
url: '/member/order/pre',
})
} -
初始化调用
// 获取订单信息
const orderPre = ref<OrderPreResult>()
const getmemberOrderPreData = async () => {
const res = await getmemberOrderPreAPI()
orderPre.value = res.result
}
// 初始化调用
onLoad(() => {
getmemberOrderPreData()
}) -
类型声明
-
界面渲染
<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> <!-- 吸底工具栏 -->
2. 收货地址
-
计算默认收货地址
const selectedAddress = computed(() => {
// 查找默认收货地址
return orderPre.value?.userAddresses.find((v) => v.isDefault)
}) -
地址列表页
-
修改收货地址
<view class="item-content" @tap="onChangeAddress(item)">
-
收货地址Store
import { AddressItem } from '@/types/address'
import { defineStore } from 'pinia'
import { ref } from 'vue'export const useAddressStore = defineStore('address', () => {
const selectedAddress = ref<AddressItem>()const changeSelectedAddress = (val: AddressItem) => {
selectedAddress.value = val
}return {
selectedAddress,
changeSelectedAddress,
}
}) -
选中收货地址
// 单纯的阻止冒泡,否则修改页面没法跳转
@tap.stop="() => {}"// 修改收货地址
const onChangeAddress = (item: AddressItem) => {
//修改地址
const addressStore = useAddressStore()
addressStore.changeSelectedAddress(item)
// 返回上一页
uni.navigateBack()
}
3.立即购买

-
封装
export const getmemberOrderPreNowAPI = (data: {
skuId: string
count: string
addressId?: string
}) => {
return http<OrderPreResult>({
method: 'GET',
url: '/member/order/pre/now',
data,
})
} -
立即购买事件,跳转页面传参
@buy-now="onBuyNow"
// 立即购买
const onBuyNow = (ev: SkuPopupEvent) => {
// 跳转并传参
uni.navigateTo({ url:/pagesOrder/create/create?skuId=${ev._id}&count=${ev.buy_num}
})
} -
立即购买
// 页面参数
const query = defineProps<{
// 可有可无
skuId?: string
count?: string
}>()// 获取订单信息
const orderPre = ref<OrderPreResult>()
const getmemberOrderPreData = async () => {
if (query.count && query.skuId) {
const res = await getmemberOrderPreNowAPI({
skuId: query.skuId,
count: query.count,
})
orderPre.value = res.result
} else {
const res = await getmemberOrderPreAPI()
orderPre.value = res.result
}
}
4.提交订单
-
封装请求API
// /member/order
export const postMemberOrderAPI = (data: OrderCreateParams) => {
return http<{ id: string }>({
method: 'POST',
url: '/member/order',
data,
})
} -
类型声明文件
-
提交按钮事件
-
调用接口成功
-
跳转订单详情
// 提交订单
const onOrderSubmit = async () => {
if (!selectedAddress.value?.id) {
uni.showToast({ title: '请选择收货地址' })
}
const res = await postMemberOrderAPI({
addressId: selectedAddress.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,
})
// 关闭当前页面,再跳转
uni.redirectTo({ url:/pagesOrder/detail/detail?id=${res.result.id}
})
} -
无收货地址交互
5.自定义导航栏交互

-
导航栏左上角按钮,返回首页
// 获取页面栈
// pages是一个数组
const pages = getCurrentPages()
// 获取当前页面实例,数组最后一项
const pageInstance = pages.at(-1) as any<navigator v-if="pages.length > 1" open-type="navigateBack" class="back icon-left" ></navigator>
-
滚动驱动的动画
// 页面渲染完毕,绑定动画效果d
onReady(() => {
// 动画效果,导航栏背景色
pageInstance.animate(
'.navbar', // 选择器
[{ backgroundColor: 'transparent' }, { backgroundColor: '#f8f8f8' }], // 关键帧信息
1000, // 动画持续时长
{
scrollSource: '#scroller', // scroll-view 的选择器
startScrollOffset: 0, // 开始滚动偏移量
endScrollOffset: 50, // 停止滚动偏移量
timeRange: 1000, // 时间长度
},
)
// 动画效果,导航栏标题
pageInstance.animate('.navbar .title', [{ color: 'transparent' }, { color: '#000' }], 1000, {
scrollSource: '#scroller',
timeRange: 1000,
startScrollOffset: 0,
endScrollOffset: 50,
})
// 动画效果,导航栏返回按钮
pageInstance.animate('.navbar .back', [{ color: '#fff' }, { color: '#000' }], 1000, {
scrollSource: '#scroller',
timeRange: 1000,
startScrollOffset: 0,
endScrollOffset: 50,
})
})
6.订单状态渲染

-
渲染订单状态
<template v-if="order"> <view class="overview" :style="{ paddingTop: safeAreaInsets!.top + 20 + 'px' }"> <template v-if="order.orderState === OrderState.DaiFuKuan"> <view class="status icon-clock">等待付款</view> <view class="tips"> <text class="money">应付金额: ¥ 99.00</text> <text class="time">支付剩余</text> 00 时 29 分 59 秒 </view> <view class="button">去支付</view> </template> <template v-else> <view class="status"> {{ orderStateList[order.orderState].text }} </view> <view class="button-group"> <navigator class="button" :url="`/pagesOrder/create/create?orderId=${query.id}`" hover-class="none" > 再次购买 </navigator> <view v-if="false" class="button"> 模拟发货 </view> </view> </template> </view> -
订单状态常量
/** 订单状态枚举 /
export enum OrderState {
/* 待付款 /
DaiFuKuan = 1,
/* 待发货 /
DaiFaHuo = 2,
/* 待收货 /
DaiShouHuo = 3,
/* 待评价 /
DaiPingJia = 4,
/* 已完成 /
YiWanCheng = 5,
/* 已取消 */
YiQuXiao = 6,
}/** 订单状态列表 */
export const orderStateList = [
{ id: 0, text: '' },
{ id: 1, text: '待付款' },
{ id: 2, text: '待发货' },
{ id: 3, text: '待收货' },
{ id: 4, text: '待评价' },
{ id: 5, text: '已完成' },
{ id: 6, text: '已取消' },
]
7.待支付倒计时

//倒计时
const onTimeUp = () => {
// 修改订单状态为已取消
order.value!.orderState = OrderState.YiQuXiao
}
<uni-countdown
color="#fff"
:show-colon="false"
:show-day="false"
splitor-color="#fff"
:second="order.countdown"
@timeup="onTimeUp"
/>
8. 代付款-订单支付

// 去支付
const onOrderPay = async () => {
if (import.meta.env.DEV) {
// 开发环境模拟支付
await getPayMockAPI({ orderId: query.id })
} else {
// 正式微信支付
const res = await getPayWxPayMiniPayAPI({ orderId: query.id })
wx.requestPayment(res.result)
}
// 关闭当前页,再跳转
uni.redirectTo({ url: `/pagesOrder/Payment/Payment?id=${query.id}` })
}
主要测试,开发环境模拟支付,即可
9.待发货-模拟发货

-
dev环境
// 是否为开发环境
const isDev = import.meta.env.DEV<view
@tap="onOrderSend"
v-if="isDev && order.orderState === OrderState.DaiFaHuo"
class="button"
>
模拟发货
</view> -
模拟发货,并更新订单状态
// 模拟发货
const onOrderSend = async () => {
if (isDev) {
await getMemberOrderConsignmentByIdAPI(query.id)
// 轻提示
uni.showToast({ icon: 'success', title: '模拟成功' })
// 主动更新订单状态
order.value!.orderState = OrderState.DaiFaHuo
}
}
打包时这里的代码会被自动剔除,优化掉
10.待收货-确认收货
仅在订单状态为待收货时,可确认收货
// 待收货=>确认收货
const onOrderConfirm = () => {
// 二次确认弹窗
uni.showModal({
content: '为保障你的权益,请收到货并确认无误后,再确认收货',
success: async (success) => {
if (success.confirm) {
const res = await putMemberOrderReceiptByIdAPI(query.id)
// 主动更新
order.value = res.result
}
},
})
}
<!-- 待收货状态: 展示确认收货按钮 -->
<view
v-if="order.orderState === OrderState.DaiShouHuo"
@tap="onOrderConfirm"
class="button"
>
确认收货
</view>
11.订单详情-待收货-订单物流
-
封装请求API
-
获取订单详情后
-
判断订单状态
// 获取订单详情
const order = ref<OrderResult>()
const getMemberOrderByIdData = async () => {
const res = await getMemberOrderByIdAPI(query.id)
order.value = res.result
// include的数是否包含在[]前面的这个数组里面,包含就是true,反之
if (
[OrderState.DaiShouHuo, OrderState.DaiPingJia, OrderState.YiWanCheng].includes(
order.value.orderState,
)
) {
getMemberOrderLogisticsByIdData()
}
} -
获取物流信息
注意:仅在订单状态为待收货、待评价、已完成时,可获取物流信息
// 获取物流信息
const logisticList = ref<LogisticItem[]>([])
const getMemberOrderLogisticsByIdData = async () => {
const res = await getMemberOrderLogisticsByIdAPI(query.id)
logisticList.value = res.result.list
}
-
渲染物流信息
<view class="shipment"> <!-- 订单物流信息 --> <view v-for="item in logisticList" :key="item.id" class="item"> <view class="message"> {{ item.text }} </view> <view class="date"> {{ item.time }} </view> </view> <!-- 用户收货地址 --> <view class="locate"> <view class="user"> {{ order.receiverContact }} {{ order.receiverMobile }}</view> <view class="address"> {{ order.receiverAddress }} </view> </view> </view>
12.删除订单
注意:仅在订单状态为待评价,已完成,已取消,可删除订单
-
封装请求API
-
条件渲染&事件绑定
<view
class="button delete"
@tap="onOrderDelete"
v-if="order.orderState >= OrderState.DaiPingJia"
>
删除订单
</view> -
二次确认弹窗
-
调用API成功
-
跳转到订单列表
// 删除订单
const onOrderDelete = () => {
// 二次确认
uni.showModal({
content: '是否删除订单',
success: async (success) => {
if (success.confirm) {
await deleteMemberOrderAPI({ ids: [] })
uni.redirectTo({ url: '/pagesOrder/list/list' })
}
},
})
}
13.订单列表-Tabs滑动切换
-
静态结构
-
Tabs文字渲染
-
点击文字高亮切换
// 高亮下标
const activeIndex = ref(0)<view class="tabs"> <text class="item" @tap="activeIndex = index" v-for="(item, index) in orderTabs" :key="item.title" > {{ item.orderState }} </text> <!-- 游标 --> <view class="cursor" :style="{ left: activeIndex * 20 + '%' }"></view> </view>
-
swiper滑动切换
可以实现上下两个模块的关联,交互<swiper class="swiper" :current="activeIndex" @change="activeIndex = $event.detail.current"> <!-- 滑动项 --> <swiper-item v-for="item in orderTabs" :key="item.title">
14.tabs页面跳转高亮
-
个人中心页
-
页面传参
-
订单详情页
-
接收页面参数
-
查找高亮下标
// 获取页面参数
const query = defineProps<{
type: string
}>()// 高亮下标
const activeIndex = ref(orderTabs.value.findIndex((v) => v.orderState === Number(query.type)))
15.列表渲染
-
封装列表组件
<OrderList />
-
订单状态父传子
// 定义props
const props = defineProps<{
orderState: number
}>() -
封装请求API
-
准备请求参数
// 请求参数
const queryParams: OrderListParams = {
page: 1,
pageSize: 5,
orderState: props.orderState,
}// 获取订单列表
const orderList = ref<OrderItem[]>([])
const getMemberOrderData = async () => {
const res = await getMemberOrderAPI(queryParams)
orderList.value = res.result.items
} -
初始化调用
// 初始化调用
onMounted(() => {
getMemberOrderData()
}) -
页面渲染
16.订单支付

// 订单支付
const onOrderPay = async (id: string) => {
if (import.meta.env.DEV) {
// 开发环境模拟支付
await getPayMockAPI({ orderId: id })
} else {
// 正式微信支付
const res = await getPayWxPayMiniPayAPI({ orderId: id })
wx.requestPayment(res.result)
}
// 成功提示
uni.showToast({ title: '支付成功!' })
// 更新订单状态
const order = orderList.value.find((v) => v.id === id)
order!.orderState = OrderState.DaiFaHuo
}
<view class="button primary" @tap="onOrderPay(order.id)">去支付</view>
17.项目打包-微信小程序端发布上线

pnpm build:mp-weixin
18.项目打包-条件编译和网页端打包
常见问题:按照 uni-app 规范开发可保证多平台兼容,但每个平台有自己的一些特性,该如何处理?
注意事项:网页端不支持微信平台授权登录等功能,可通过条件编译,让代码按条件编译到不同平台。
条件编译语法:通过特殊注释,以 #ifdef 或 #ifndef 加平台名称开头,以 #endif 结尾。
pnpm dev:h5
<script setup lang="ts">
// #ifdef MP-WEIXIN
wx.login()
wx.requestOrderPayment()
// #endif
</script>
<template>
<!-- #ifdef MP-WEIXIN -->
<button open-type="openSetting">授权管理</button>
<button open-type="feedback">问题反馈</button>
<button open-type="contact">联系我们</button>
<!-- #endif -->
</template>
支持: vue, js, ts, css, scss, pages.json 等文件
编译网页端
pnpm build:h5
将绝对定位改为相对定位
// 在manifest中配置
/* 网页端特有配置 */
"h5": {
"router": {
"base": "./"
}
},
// 最后重启,pnpm build:h5