1 效果展示
2 提交订单
2.1 cart.js
- // src/pages/store/cart/cart.js
- import {
- defineStore
- } from 'pinia';
- import {
- reactive,
- computed
- } from 'vue';
- export const useCartStore = defineStore('cart', () => {
- // 用 reactive 管理购物车数据
- 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);
- // 检查是否已经有 notes 字段,如果没有则添加
- 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 = () => {
- // 遍历所有店铺的所有商品,如果有一个未选中,则全选状态为 false
- state.allChose = state.cartItems.every(shop =>
- shop.items.every(item => item.isChoose)
- );
- };
- // 将购物车数据保存到 localStorage
- const saveCartToLocalStorage = () => {
- localStorage.setItem('cartItems', JSON.stringify(state.cartItems));
- };
- // 从 localStorage 中恢复购物车数据
- const loadCartFromLocalStorage = () => {
- const savedCart = localStorage.getItem('cartItems');
- if (savedCart) {
- state.cartItems = JSON.parse(savedCart);
- }
- };
- return {
- state,
- setCartItems, // 暴露 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 focus
- maxlength="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";
- // 使用 Pinia store
- 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 为 false
- show.value = false;
- // console.log('close');
- }
- 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;
- /* Tabbar 高度 */
- 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 {
- // flex: 1;
- }
- .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";
- // 使用 Pinia store
- const cartStore = useCartStore();
- // 获取状态和操作
- const {
- totalSelectedPrice,
- selectedItems
- } = storeToRefs(cartStore);
- // up-radio-group的v-model绑定的值如果设置为某个radio的name,就会被默认选中
- 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>
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |