1.购物车关联store对象
javascript
import { ComponentWithStore } from 'mobx-miniprogram-bindings'
import { userStore } from '@/stores/userstore'
import { reqCartList } from '@/api/cart'
ComponentWithStore({
storeBindings: {
store: userStore,
fields: ['token']
},
data: {
cartList: [],
emptyDes: '还没有添加商品,快去添加'
},
methods: {
async getCartListTip() {
const { token } = this.data
console.log(token)
},
onShow() {
this.getCartListTip()
}
}
})
2.获取渲染购物车列表
javascript
import { ComponentWithStore } from 'mobx-miniprogram-bindings'
import { userStore } from '@/stores/userstore'
import { reqCartList } from '@/api/cart'
ComponentWithStore({
storeBindings: {
store: userStore,
fields: ['token']
},
data: {
cartList: [],
emptyDes: '还没有添加商品,快去添加吧~'
},
methods: {
async showTipGetList() {
const { token, cartList } = this.data
if (!token) {
return this.setData({
emptyDes: '您尚未登录,点击登录获取更多权益',
cartList: []
})
}
const res = await reqCartList()
if (res.code === 200) {
this.setData({
cartList: res.data,
emptyDes: cartList.length === 0 && '还没有添加商品,快去添加'
})
}
},
onShow() {
this.showTipGetList()
}
}
})
html
<view>
<view
wx:if="{{ token && cartList.length }}"
class="container goods-wrap"
bindtap="onSwipeCellPageTap"
>
<view class="cart-wrap">
<view class="goods-item" wx:for="{{ cartList }}" wx:key="goodsId ">
<van-swipe-cell class="goods-swipe" right-width="{{ 65 }}">
<view class="goods-info">
<view class="left">
<van-checkbox
checked-color="#FA4126"
value="{{ item.checked }}"
></van-checkbox>
</view>
<view class="mid">
<image class="img" src="{{ item.imageUrl }}" />
</view>
<view class="right">
<view class="title"> {{ item.name }} </view>
<view class="buy">
<view class="price">
<view class="symbol">¥</view>
<view class="num">{{ item.price }}</view>
</view>
<view class="buy-btn">
<van-stepper value="{{ item.count }}" />
</view>
</view>
</view>
</view>
<view slot="right" class="van-swipe-cell__right">删除</view>
</van-swipe-cell>
</view>
</view>
<van-submit-bar price="{{ 3050 }}" button-text="去结算" tip="{{ true }}">
<van-checkbox value="{{ true }}" checked-color="#FA4126"> 全选 </van-checkbox>
</van-submit-bar>
</view>
<van-empty wx:else description="{{ emptyDes }}">
<navigator url="/pages/index/index" wx:if="{{ token }}">
<van-button round type="danger" class="bottom-button">去购物</van-button>
</navigator>
<navigator url="/pages/login/login" wx:else>
<van-button round type="danger" class="bottom-button">去登录</van-button>
</navigator>
</van-empty>
</view>
3.更新商品购买状态
html
<view>
<view
wx:if="{{ token && cartList.length }}"
class="container goods-wrap"
bindtap="onSwipeCellPageTap"
>
<view class="cart-wrap">
<view class="goods-item" wx:for="{{ cartList }}" wx:key="goodsId ">
<van-swipe-cell class="goods-swipe" right-width="{{ 65 }}">
<view class="goods-info">
<view class="left">
<van-checkbox
checked-color="#FA4126"
value="{{ item.checked }}"
></van-checkbox>
</view>
<view class="mid">
<image class="img" src="{{ item.imageUrl }}" />
</view>
<view class="right">
<view class="title"> {{ item.name }} </view>
<view class="buy">
<view class="price">
<view class="symbol">¥</view>
<view class="num">{{ item.price }}</view>
</view>
<view class="buy-btn">
<van-stepper value="{{ item.count }}" />
</view>
</view>
</view>
</view>
<view slot="right" class="van-swipe-cell__right">删除</view>
</van-swipe-cell>
</view>
</view>
<van-submit-bar price="{{ 3050 }}" button-text="去结算" tip="{{ true }}">
<van-checkbox value="{{ true }}" checked-color="#FA4126"> 全选 </van-checkbox>
</van-submit-bar>
</view>
<van-empty wx:else description="{{ emptyDes }}">
<navigator url="/pages/index/index" wx:if="{{ token }}">
<van-button round type="danger" class="bottom-button">去购物</van-button>
</navigator>
<navigator url="/pages/login/login" wx:else>
<van-button round type="danger" class="bottom-button">去登录</van-button>
</navigator>
</van-empty>
</view>
4.更新商品购买状态
javascript
<van-checkbox
checked-color="#FA4126"
value="{{ item.isChecked }}"
bind:change="updateChecked"
data-id="{{ item.goodsId }}"
data-index="{{ index }}"
></van-checkbox>
javascript
import { reqCartList, reqUpdateGoodStatus } from '../../../api/cart'
import { storeBindingsBehavior } from 'mobx-miniprogram-bindings'
import store from '../../../stores/index'
Component({
methods: {
async updateChecked(event) {
const { detail } = event
const { id, index } = event.target.dataset
const isChecked = detail ? 1 : 0
const res = await reqUpdateGoodStatus(id, isChecked)
if (res.code === 200) {
this.setData({
[`cartList[${index}].isChecked`]: isChecked
})
}
},
async getCartList() {
}
}
})
5.按钮选中
安装框架 computed
javascript
const computedBehavior = require('miniprogram-computed').behavior
Component({
behaviors: [computedBehavior],
computed: {
selectAllStatus(data) {
return data.cartList.length !== 0 && data.cartList.every((item) => item.isChecked === 1)
}
},
})
6.全选和全不选
javascript
<van-submit-bar price="{{ 3050 }}" button-text="去结算" tip="{{ true }}">
<van-checkbox
value="{{ selectAllStatus }}"
checked-color="#FA4126"
bind:change="onChangeCheckAll"
>
全选
</van-checkbox>
</van-submit-bar>
javascript
Component({
methods: {
async onChangeCheckAll(event) {
const isChecked = event.detail ? 1 : 0
const res = await reqCheckAll(isChecked)
if (res.code === 200) {
const newCart = JSON.parse(JSON.stringify(this.data.cartList))
newCart.forEach((item) => (item.isChecked = isChecked))
this.setData({
cartList: newCart
})
}
},
}
})
7.更新商品购买数量
javascript
const reg = /^([1-9]|[1-9]\d|1\d{2}|200)$/
javascript
<van-stepper
integer
min="1"
max="200"
value="{{ item.count }}"
data-id="{{ item.goodsId }}"
data-oldbuynum="{{ item.count }}"
data-index="{{ index }}"
bindchange="changeBuyNum"
/>
javascript
async changeBuyNum(event) {
let buynum = event.detail > 200 ? 200 : event.detail
const { id: goodsId, index, oldbuynum } = event.target.dataset
const reg = /^([1-9]|[1-9]\d|1\d{2}|200)$/
const regRes = reg.test(buynum)
if (!regRes) {
this.setData({
[`cartList[${index}].count`]: oldbuynum
})
return
}
const disCount = buynum - oldbuynum
if (disCount === 0) return
const res = await reqAddCart({ goodsId, count: disCount })
if (res.code === 200) {
this.setData({
[`cartList[${index}].count`]: buynum,
[`cartList[${index}].isChecked`]: 1
})
}
}
\
8.商品购买数量防抖
javascript
import { debounce } from 'miniprogram-licia'
changeBuyNum: debounce(async function (event) {
}, 500)
9.商品合计
javascript
<van-submit-bar
wx:if="{{ cartList.length }}"
price="{{ totalPrice }}"
button-text="去结算"
tip="{{ true }}"
>
<van-checkbox
value="{{ selectAllStatus }}"
checked-color="#FA4126"
bindchange="selectAllStatus"
>
全选
</van-checkbox>
</van-submit-bar>
javascript
import {
reqCartList,
reqUpdateChecked,
reqCheckAllStatus,
reqAddCart,
reqDelCartGoods
} from '@/api/cart'
import { swipeCellBehavior } from '@/behaviors/swipeCell'
ComponentWithStore({
behaviors: [swipeCellBehavior, computedBehavior],
methods: {
async delCartGoods(event) {
const { id } = event.currentTarget.dataset
const modalRes = await wx.modal({
content: '您确认删除该商品吗 ?'
})
if (modalRes) {
await reqDelCartGoods(id)
this.showTipGetList()
}
},
onHide() {
this.onSwipeCellCommonClick()
}
}
})
10.删除购物车中的商品
javascript
/**
* @description 删除购物车中的商品
* @param {*} goodsId 商品ID
* @returns Promise
*/
export const reqDelGood = (goodsId) => {
return http.get(`/mall-api/cart/delete/${goodsId}`)
}
javascript
<van-icon
bindtap="delCartGood"
data-id="{{ item.goodsId }}"
size="18px"
color="#71797f"
name="delete"
class="del"
/>
11.结算页面跳转
javascript
"subPackages": [
{
"root": "modules/settingModule",
"name": "settingModule",
"pages": [
"pages/address/add/index",
"pages/address/list/index",
"pages/profile/profile"
]
},
{
"root": "modules/goodModule",
"name": "goodModule",
"pages": ["pages/goods/list/list", "pages/goods/detail/detail"]
},
{
"root": "modules/orderPayModule",
"name": "orderPayModule",
"pages": [
"pages/order/detail/detail",
"pages/order/list/list"
]
}
],
"preloadRule": {
"pages/settings/settings": {
"network": "all",
"packages": ["settingModule"]
},
"pages/category/category": {
"network": "all",
"packages": ["goodModule"]
},
"pages/cart/cart": {
"network": "all",
"packages": ["orderPayModule"]
}
}
javascript
toOrder() {
if (this.data.totalPrice === 0) {
wx.toast({
title: '请选择需要购买的商品'
})
return
}
wx.navigateTo({
url: '/modules/orderPayModule/pages/order/detail/detail'
})
}
javascript
<van-submit-bar
wx:if="{{ cartList.length }}"
price="{{ totalPrice * 100 }}"
button-text="去结算"
tip="{{ true }}"
bindsubmit="toOrder"
>
<van-checkbox
value="{{ selectAllStatus }}"
checked-color="#FA4126"
bindchange="selectAllStatus"
>
全选
</van-checkbox>
</van-submit-bar>
封装结算接口API
javascript
import http from '@/utils/http'
/**
* @description 获取订单详情
* @returns Promise
*/
export const reqOrderInfo = () => {
return http.get('/order/trade')
}
/**
* @description 获取订单收货地址
* @returns Promise
*/
export const reqOrderAddress = () => {
return http.get('/userAddress/getOrderAddress')
}
/**
* @description 获取立即购买商品的详情信息
* @param { Object } params { goodsId: 商品 Id, blessing:祝福语 }
* @returns Promise
*/
export const reqBuyNowGoods = ({ goodsId, ...data }) => {
return http.get(`/order/buy/${goodsId}`, data)
}
/**
* @description 提交订单
* @returns Promise
*/
export const reqSubmitOrder = () => {
return http.post('/order/submitOrder')
}
/**
* @description 获取微信预支付信息
* @param {*} orderNo 订单 ID
* @returns Promise
*/
export const reqPreBuyInfo = (orderNo) => {
return http.get(`/webChat/createJsapi/${orderNo}`)
}
/**
* @description 微信支付状态查询
* @param {*} orderNo
* @returns Promise
*/
export const reqPayStatus = (orderNo) => {
return http.get(`/webChat/queryPayStatus/${orderNo}`)
}
12.获取收货地址
html
<view class="container order">
<view class="address-card">
<view wx:if="{{ !tradeAddress.id }}" class="add-address" bindtap="toAddress">
<van-icon size="22px" name="add" />
<view>添加收货地址</view>
</view>
<view wx:else class="order-address flex">
<view class="address-content">
<view class="title">{{ tradeAddress.fullAddress }}</view>
<view class="detail">{{ tradeAddress.address }}</view>
<view class="info flex">
<text>{{ tradeAddress.name }}</text>
<text>{{ tradeAddress.phone }}</text>
</view>
</view>
<view class="select-address">
<navigator class="navigator" url="/modules/settingModule/pages/address/list/index">
<van-icon color="#bbb" name="arrow" size="22px" />
</navigator>
</view>
</view>
<view class="top-line"></view>
</view>
<view class="order-info">
</view>
</view>
javascript
import { reqOrderAddress } from '../../../api/order'
Page({
data: {
orderAddress: {}
},
async getAddress() {
const { data: orderAddress } = await reqOrderAddress()
this.setData({
orderAddress
})
},
onShow() {
this.getAddress()
}
})
13.更新收货地址
javascript
App({
globalData: {
address: {}
}
})
javascript
<view class="select-address">
<navigator
class="navigator"
url="/modules/settingModule/pages/address/list/index?flag=1"
>
<van-icon color="#bbb" name="arrow" size="22px" />
</navigator>
</view>
14.获取订单详细数据
javascript
<view class="select-address">
<navigator
class="navigator"
url="/modules/settingModule/pages/address/list/index?flag=1"
>
<van-icon color="#bbb" name="arrow" size="22px" />
</navigator>
</view>
javascript
import { reqOrderAddress, reqOrderInfo } from '@/api/orderpay'
Page({
data: {
orderAddress: {},
orderInfo: {},
},
async getOrderInfo() {
const { data: orderInfo } = await reqOrderInfo()
const orderGoods = orderInfo.cartVoList.find((item) => item.blessing !== '')
this.setData({
orderInfo,
blessing: orderGoods && orderGoods.blessing
})
},
onShow() {
this.getAddress()
this.getOrderInfo()
},
})
15.立即购买商品数据
javascript
import {
reqOrderAddress,
reqOrderInfo,
reqBuyNowGoods
} from '@/api/orderpay'
Page({
async getOrderInfo() {
const { goodsId, blessing } = this.data
const { data: orderInfo } = goodsId
? await reqBuyNowGoods({ goodsId, blessing })
: await reqOrderInfo()
this.setData({
orderInfo
})
}
onLoad (options) {
this.setData({
...options
})
},
onShow() {
this.getAddress()
this.getOrderInfo()
}
})
16.商品结算
javascript
import { reqOrderAddress, reqOrderInfo, reqBuyNowGoods } from '@/api/orderpay'
import Schema from 'async-validator'
import { formatTime } from '@/utils/formatTime'
const app = getApp()
Page({
data: {
buyName: '',
buyPhone: '',
deliveryDate: '',
blessing: '',
show: false,
orderAddress: {},
orderInfo: {},
minDate: new Date().getTime(),
currentDate: new Date().getTime()
},
async submitOrder() {
const {
buyName,
buyPhone,
deliveryDate,
blessing,
orderInfo,
orderAddress
} = this.data
const params = {
buyName,
buyPhone,
deliveryDate,
remarks: blessing,
cartList: orderInfo.cartVoList,
userAddressId: orderAddress.id
}
const { valid } = await this.validatorPerson(params)
console.log(valid)
},
validatorPerson(params) {
const nameRegExp = '^[a-zA-Z\\d\\u4e00-\\u9fa5]+$'
const phoneReg = '^1(?:3\\d|4[4-9]|5[0-35-9]|6[67]|7[0-8]|8\\d|9\\d)\\d{8}$'
const rules = {
userAddressId: [{ required: true, message: '请选择收货地址' }],
buyName: [
{ required: true, message: '请输入收货人姓名' },
{ pattern: nameRegExp, message: '收货人姓名不合法' }
],
buyPhone: [
{ required: true, message: '请输入收货人手机号' },
{ pattern: phoneReg, message: '收货人手机号不合法' }
],
deliveryDate: { required: true, message: '请选择送达时间' }
}
const validator = new Schema(rules)
return new Promise((resolve) => {
validator.validate(params, (errors) => {
if (errors) {
wx.toast({ title: errors[0].message })
resolve({ valid: false })
} else {
resolve({ valid: true })
}
})
})
},
})
17.支付流程图

18.创建订单
javascript
import {
reqOrderAddress,
reqOrderInfo,
reqBuyNowGoods,
reqSubmitOrder
} from '@/api/orderpay'
Page({
async submitOrder() {
const {
buyName,
buyPhone,
deliveryDate,
blessing,
orderAddress,
orderInfo
} = this.data
const params = {
buyName,
buyPhone,
cartList: orderInfo.cartVoList,
deliveryDate,
remarks: blessing,
userAddressId: orderAddress.id
}
const { valid } = await this.validatorPerson(params)
if (!valid) return
const res = await reqSubmitOrder(params)
if (res.code === 200) {
this.orderNo = res.data
}
}
})
19.获取预付单信息
javascript
Page({
async submitOrder() {
const {
buyName,
buyPhone,
deliveryDate,
blessing,
orderAddress,
orderInfo
} = this.data
const params = {
buyName,
buyPhone,
cartList: orderInfo.cartVoList,
deliveryDate,
remarks: blessing,
userAddressId: orderAddress.id
}
const { valid } = await this.validatorPerson(params)
if (!valid) return
const res = await reqSubmitOrder(params)
if (res.code === 200) {
this.orderNo = res.data
this.advancePay()
}
},
async advancePay() {
const payParams = await reqPrePayInfo(this.orderNo)
if (payParams.code === 200) {
console.log(res.data)
}
},
})
20.查询支付状态
javascript
async advancePay() {
try {
const payParams = await reqPrePayInfo(this.orderNo)
if (payParams.code === 200) {
const payInfo = await wx.requestPayment(payParams.data)
if (payInfo.errMsg === 'requestPayment:ok') {
const payStatus = await reqPayStatus(this.orderNo)
if (payStatus.code === 200) {
wx.redirectTo({
url: '/pages/order/list/index',
success: () => {
wx.toast({
title: '支付成功',
icon: 'success
})
}
})
}
}
}
} catch (error) {
wx.toast({
title: '支付失败,请联系客服',
icon: 'error'
})
}
}