UniappDay06

发布于:2025-08-04 ⋅ 阅读:(8) ⋅ 点赞:(0)

1.填写订单-渲染基本信息

  1. 静态结构(分包)
  2. 封装请求API
import { http } from '@/utils/http'
import { OrderPreResult } from '@/types/order'

export const getmemberOrderPreAPI = () => {
  return http<OrderPreResult>({
    method: 'GET',
    url: '/member/order/pre',
  })
}

  1. 初始化调用
// 获取订单信息
const orderPre = ref<OrderPreResult>()
const getmemberOrderPreData = async () => {
  const res = await getmemberOrderPreAPI()
  orderPre.value = res.result
}
// 初始化调用
onLoad(() => {
  getmemberOrderPreData()
})
  1. 类型声明
  2. 界面渲染
 <!-- 商品信息 -->
    <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="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: true }"> 提交订单 </view>
  </view>

2. 收货地址

  1. 计算默认收货地址
const selectedAddress = computed(() => {
  // 查找默认收货地址
  return orderPre.value?.userAddresses.find((v) => v.isDefault)
})
  1. 地址列表页
  2. 修改收货地址
<view class="item-content" @tap="onChangeAddress(item)">
  1. 收货地址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,
  }
})
  1. 选中收货地址
// 单纯的阻止冒泡,否则修改页面没法跳转
 @tap.stop="() => {}"

// 修改收货地址
const onChangeAddress = (item: AddressItem) => {
  //修改地址
  const addressStore = useAddressStore()
  addressStore.changeSelectedAddress(item)
  // 返回上一页
  uni.navigateBack()
}

3.立即购买

在这里插入图片描述

  1. 封装
export const getmemberOrderPreNowAPI = (data: {
  skuId: string
  count: string
  addressId?: string
}) => {
  return http<OrderPreResult>({
    method: 'GET',
    url: '/member/order/pre/now',
    data,
  })
}
  1. 立即购买事件,跳转页面传参
 @buy-now="onBuyNow"

// 立即购买
const onBuyNow = (ev: SkuPopupEvent) => {
  // 跳转并传参
  uni.navigateTo({ url: `/pagesOrder/create/create?skuId=${ev._id}&count=${ev.buy_num}` })
}
  1. 立即购买
// 页面参数
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.提交订单

  1. 封装请求API
// /member/order
export const postMemberOrderAPI = (data: OrderCreateParams) => {
  return http<{ id: string }>({
    method: 'POST',
    url: '/member/order',
    data,
  })
}
  1. 类型声明文件
  2. 提交按钮事件
  3. 调用接口成功
  4. 跳转订单详情
// 提交订单
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}` })
}
  1. 无收货地址交互

5.自定义导航栏交互

在这里插入图片描述

  1. 导航栏左上角按钮,返回首页
// 获取页面栈
// 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>
  1. 滚动驱动的动画

// 页面渲染完毕,绑定动画效果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.订单状态渲染

在这里插入图片描述

  1. 渲染订单状态
 <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>
  1. 订单状态常量
/** 订单状态枚举 */
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.待发货-模拟发货

在这里插入图片描述

  1. dev环境
// 是否为开发环境
const isDev = import.meta.env.DEV

<view
              @tap="onOrderSend"
              v-if="isDev && order.orderState === OrderState.DaiFaHuo"
              class="button"
            >
              模拟发货
            </view>
  1. 模拟发货,并更新订单状态
// 模拟发货
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.订单详情-待收货-订单物流

  1. 封装请求API
  2. 获取订单详情后
  3. 判断订单状态
// 获取订单详情
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()
  }
}
  1. 获取物流信息

注意:仅在订单状态为待收货、待评价、已完成时,可获取物流信息

// 获取物流信息
const logisticList = ref<LogisticItem[]>([])
const getMemberOrderLogisticsByIdData = async () => {
  const res = await getMemberOrderLogisticsByIdAPI(query.id)
  logisticList.value = res.result.list
}
  1. 渲染物流信息
<!-- 配送状态 -->
      <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.删除订单

注意:仅在订单状态为待评价,已完成,已取消,可删除订单

  1. 封装请求API
  2. 条件渲染&事件绑定
 <view
            class="button delete"
            @tap="onOrderDelete"
            v-if="order.orderState >= OrderState.DaiPingJia"
          >
            删除订单
          </view>
  1. 二次确认弹窗
  2. 调用API成功
  3. 跳转到订单列表
// 删除订单
const onOrderDelete = () => {
  // 二次确认
  uni.showModal({
    content: '是否删除订单',
    success: async (success) => {
      if (success.confirm) {
        await deleteMemberOrderAPI({ ids: [] })
        uni.redirectTo({ url: '/pagesOrder/list/list' })
      }
    },
  })
}

13.订单列表-Tabs滑动切换

  1. 静态结构
  2. Tabs文字渲染
  3. 点击文字高亮切换
// 高亮下标
const activeIndex = ref(0)

<!-- tabs -->
    <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>
  1. swiper滑动切换
    可以实现上下两个模块的关联,交互
<!-- 滑动容器 -->
    <swiper class="swiper" :current="activeIndex" @change="activeIndex = $event.detail.current">
      <!-- 滑动项 -->
      <swiper-item v-for="item in orderTabs" :key="item.title">

14.tabs页面跳转高亮

  1. 个人中心页
  2. 页面传参
  3. 订单详情页
  4. 接收页面参数
  5. 查找高亮下标
// 获取页面参数
const query = defineProps<{
  type: string
}>()

// 高亮下标
const activeIndex = ref(orderTabs.value.findIndex((v) => v.orderState === Number(query.type)))

15.列表渲染

  1. 封装列表组件
 <!-- 订单列表 -->
        <OrderList />
  1. 订单状态父传子
// 定义props
const props = defineProps<{
  orderState: number
}>()
  1. 封装请求API
  2. 准备请求参数
// 请求参数
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
}
  1. 初始化调用
// 初始化调用
onMounted(() => {
  getMemberOrderData()
})
  1. 页面渲染

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

网站公告

今日签到

点亮在社区的每一天
去签到