Uniapp + Vue3 + Vite +Uview + Pinia 实现提交订单以及支付功能(最新附源码保姆级)
- 1 效果展示
- 2 提交订单
- 2.1 cart.js
- 2.2 submit-order.vue
- 3、支付页面
-
1 效果展示
2 提交订单
2.1 cart.js
import {defineStore
} from 'pinia';
import {reactive,computed
} from 'vue';export const useCartStore = defineStore('cart', () => {const state = reactive({cartItems: [], allChose: false });const setCartItems = (items) => {state.cartItems = items.map(item => ({...item,isChoose: false, num: item.num || 1 }));saveCartToLocalStorage(); };const selectedItemsCount = computed(() => {return state.cartItems.reduce((count, shop) => {return count + shop.items.filter(item => item.isChoose).reduce((shopCount, item) =>shopCount + item.num, 0);}, 0);});const totalSelectedPrice = computed(() => {return state.cartItems.reduce((total, shop) => {return total + shop.items.filter(item => item.isChoose).reduce((shopTotal, item) =>shopTotal + item.price * item.num, 0);}, 0);});const toggleItemChoose = (shopName, itemId) => {const shop = state.cartItems.find(shop => shop.shopName === shopName);console.log(shop);if (shop) {const cartItem = shop.items.find(cartItem => cartItem.id === itemId);if (cartItem) {cartItem.isChoose = !cartItem.isChoose;}updateAllChoseStatus(); saveCartToLocalStorage();}};const changeItemQuantity = (shopName, itemId, quantity) => {const shop = state.cartItems.find(shop => shop.shopName === shopName);if (shop) {const cartItem = shop.items.find(cartItem => cartItem.id === itemId);if (cartItem) {cartItem.num = quantity;}saveCartToLocalStorage();}};const selectedItems = computed(() => {const groupedSelectedItems = [];state.cartItems.forEach(shop => {const selectedShopItems = shop.items.filter(item => item.isChoose);if (selectedShopItems.length > 0) {const groupedShop = groupedSelectedItems.find(group => group.shopName === shop.shopName);if (groupedShop) {groupedShop.items.push(...selectedShopItems);if (!groupedShop.hasOwnProperty('notes')) {groupedShop.notes = "";}} else {groupedSelectedItems.push({shopName: shop.shopName,items: selectedShopItems,notes: ""});}}});return groupedSelectedItems;});const toggleAllChose = () => {state.allChose = !state.allChose;state.cartItems.forEach(shop => {shop.items.forEach(item => {item.isChoose = state.allChose;});});saveCartToLocalStorage();};const updateAllChoseStatus = () => {state.allChose = state.cartItems.every(shop =>shop.items.every(item => item.isChoose));};const saveCartToLocalStorage = () => {localStorage.setItem('cartItems', JSON.stringify(state.cartItems));};const loadCartFromLocalStorage = () => {const savedCart = localStorage.getItem('cartItems');if (savedCart) {state.cartItems = JSON.parse(savedCart);}};return {state,setCartItems, selectedItems,selectedItemsCount,totalSelectedPrice,toggleItemChoose,changeItemQuantity,toggleAllChose,loadCartFromLocalStorage};
});
2.2 submit-order.vue
<template><view class=""><AddressVue></AddressVue><view class="card"><template v-for="(info, j) in selectedItems" :key="j"><view class="cart-data card-shadow"><view class="" style="display: flex;">{{info.shopName}}<up-icon name="arrow-right"></up-icon></view><template v-for="(item, index) in info.items" :key="index"><view class=""style="display: flex;padding: 20rpx 0;align-items: center;width: 100%;justify-content: space-around;"><view class="cart-image"><up-image :src="item.image" mode="widthFix" height="200rpx" width="220rpx"radius="10"></up-image></view><view><view class="cart-right"><view style="margin-bottom: 10rpx;font-size: 30rpx;">{{item.title}}</view><view style="margin-bottom: 20rpx;font-size: 26rpx;color: #7d7e80;">{{item.type}}</view><view class="" style="display: flex;align-items: center;"><up-text mode="price" :text="item.price"></up-text><view class="" style="width: 10rpx;"></view><up-number-box v-model="item.num"@change="val => changeItemQuantity(item,item.iid, val.value)"min="1"></up-number-box></view></view></view></view></template><view class="notes" @click="writeNoteFun(j)"><view style="flex: 1;">订单备注</view><view style="display: flex;color: #7d7e80;width: 400rpx;justify-content: end;" ><up-text :text="info.notes.length==0?'无备注':info.notes" :lines="1"></up-text><up-icon name="arrow-right"></up-icon></view></view><!-- 弹出层输入备注 --><up-popup :show="show" mode="bottom" @close="close" zIndex="9999999" round="20rpx"><view class="" style="text-align: center;height: 60rpx;line-height: 60rpx;margin-top: 20rpx;">订单备注</view><view style="padding: 20rpx 40rpx;"><up-textarea v-model="selectedItems[noteIndex].notes" placeholder="请输入内容" count focusmaxlength="200" height="240rpx"></up-textarea></view><view class="" style="display: flex;padding: 20rpx 40rpx;margin-top: 100rpx;"><up-button text="确定" type="warning" shape="circle" @click="enterNoteInputFun()"></up-button></view></up-popup></view></template></view><view class="" style="height: 150rpx;"></view><view class="foot card"><view class="card-connect"><view class="" style="display: flex; align-items: center;"><view style="padding-left: 20rpx;font-size: 24rpx;">已选{{selectedItemsCount}}件,合计</view><view class="" style="display: flex;flex: 1;"><up-text mode="price" :text="totalSelectedPrice" color="red" size="18"></up-text></view></view><view class="" style="width: 20rpx;position: relative;"></view><view class="" style="position: absolute;right: 40rpx;"><view class="" style="display: flex;"><up-button type="error" text="去支付" shape="circle" style="width: 150rpx;"@click="toPayFun"></up-button></view></view><up-toast ref="uToastRef"></up-toast></view></view></view>
</template><script setup>import {ref,onMounted} from 'vue';import AddressVue from '@/pages/components/User/Address.vue';import {useCartStore} from '@/pages/store/cart/cart.js'import {storeToRefs} from "pinia";const cartStore = useCartStore();const {state,selectedItemsCount,totalSelectedPrice,selectedItems} = storeToRefs(cartStore);const {toggleItemChoose,changeItemQuantity,toggleAllChose} = cartStore;const show = ref(false);const noteIndex = ref(0);const writeNoteFun = (index) => {noteIndex.value = index;show.value = true;}const close = () => {show.value = false;}const enterNoteInputFun = () => {show.value = false;}const toPayFun = () => {uni.navigateTo({url: "/pages/src/home/order-pay/order-pay"})}onMounted(() => {});
</script><style lang="scss" scoped>.notes {padding-top: 20rpx;display: flex;width: 100%;justify-content: space-between;}.foot {position: fixed;bottom: 0;left: 0;width: 90%;height: 100rpx;background-color: #FFF;display: flex;align-items: center;.card-connect {display: flex;align-items: center;justify-content: space-between;}}.card {margin: 20rpx;padding: 20rpx;background-color: #FFF;border-radius: 20rpx;}.card-shadow {border-radius: 20rpx;box-shadow: 10rpx 10rpx 10rpx 10rpx rgba(0.2, 0.1, 0.2, 0.2);}.cart-data {margin-bottom: 40rpx;padding: 20rpx;display: flex;flex-wrap: wrap;align-items: center;.cart-image {}.cart-right {display: flex;flex-direction: column;padding-left: 20rpx;}}
</style>
3、支付页面
order-pay.vue
<template><view><view class="" style="display: flex;"><up-steps current="1" style="display: flex;"><up-steps-item title="提交订单成功" :desc="nowDate"></up-steps-item><up-steps-item title="选择支付方式" desc=""></up-steps-item><up-steps-item title="卖家确认发货" desc="24小时内"></up-steps-item></up-steps></view><view class="card"><view class="" style="text-align: center;padding-top: 40rpx;">订单金额</view><view class="" style="display: flex;justify-content: center;padding: 60rpx 0 20rpx 0;"><up-text mode="price" :text="totalSelectedPrice" color="red" size="40"></up-text></view><view class="" style="text-align: center;padding-top: 20rpx;"><text>订单提交成功,请在10分钟内完成支付</text></view><view class="" style="height: 100rpx;"></view><up-divider text="请您选择付款方式"></up-divider><view class=""><radio-group @change="radioChange"><view class="" style="width: 100%;"><view class=""style="display: flex;align-items: center;width: 100%;justify-content: space-between;"><up-icon name="weixin-circle-fill" size="40" color="green"></up-icon><text style="padding-left: 20rpx;flex: 1;">微信支付</text><radio :checked="true" value="1"></radio></view><view class=""style="display: flex;align-items: center;width: 100%;justify-content: space-between;margin-top: 20rpx;"><up-icon name="zhifubao-circle-fill" size="40" color="blue"></up-icon><text style="padding-left: 20rpx;flex: 1;">支付宝支付</text><radio style="right: 0;" value="2"></radio></view></view></radio-group></view></view><view class="" style="display: flex;margin-top: 40rpx;padding: 0 20rpx;"><up-button type="error" text="确认支付" shape="circle" @click="toPayFun"></up-button></view></view>
</template><script setup>import {timeFormat} from 'uview-plus';import {reactive,ref} from 'vue';const nowDate = timeFormat(new Date().getTime(), 'hh:MM:ss');import {useCartStore} from '@/pages/store/cart/cart.js'import {storeToRefs} from "pinia";const cartStore = useCartStore();const {totalSelectedPrice,selectedItems} = storeToRefs(cartStore);const radiovalue = ref();const radioChange = (e) => {radiovalue.value = e.detail.value;};const toPayFun = () =>{}
</script><style lang="less" scoped>.card {margin: 20rpx;padding: 20rpx;background-color: #FFF;border-radius: 20rpx;}
</style>