YunaiV 1 жил өмнө
parent
commit
7a15c9496c

+ 1 - 1
pages/goods/index.vue

@@ -138,7 +138,7 @@
 		state.selectedSku = e;
 	}
 
-	// 添加购物车  TODO 芋艿:待测试
+	// 添加购物车
 	function onAddCart(e) {
 		sheep.$store('cart').add(e);
 	}

+ 213 - 193
pages/index/cart.vue

@@ -1,200 +1,220 @@
+<!-- 购物车界面 -->
 <template>
-	<s-layout title="购物车" tabbar="/pages/index/cart" :bgStyle="{ color: '#fff' }">
-		<s-empty v-if="state.list.length === 0" text="购物车空空如也,快去逛逛吧~" icon="/static/cart-empty.png" />
-
-		<!-- 头部 -->
-		<view class="cart-box ss-flex ss-flex-col ss-row-between" v-if="state.list.length">
-			<view class="cart-header ss-flex ss-col-center ss-row-between ss-p-x-30">
-				<view class="header-left ss-flex ss-col-center ss-font-26">
-					共
-					<text class="goods-number ui-TC-Main ss-flex">{{ state.list.length }}</text>
-					件商品
-				</view>
-				<view class="header-right">
-					<button v-if="state.editMode" class="ss-reset-button" @tap="state.editMode = false">
-						取消
-					</button>
-					<button v-else class="ss-reset-button ui-TC-Main" @tap="state.editMode = true">
-						编辑
-					</button>
-				</view>
-			</view>
-			<!-- 内容 -->
-			<view class="cart-content ss-flex-1 ss-p-x-30 ss-m-b-40">
-				<view class="goods-box ss-r-10 ss-m-b-14" v-for="item in state.list" :key="item.id">
-					<view class="ss-flex ss-col-center">
-						<label class="check-box ss-flex ss-col-center ss-p-l-10" @tap="onSelectSingle(item.id)">
-							<radio :checked="state.selectedIds.includes(item.id)" color="var(--ui-BG-Main)"
-								style="transform: scale(0.8)" @tap.stop="onSelectSingle(item.id)" />
-						</label>
-						<s-goods-item :title="item.spu.name" :img="item.spu.picUrl || item.goods.image"
-							:price="item.sku.price/100"
-							:skuText="item.sku.properties.length>1? item.sku.properties.reduce((items2,items)=>items2.valueName+' '+items.valueName):item.sku.properties[0].valueName"
-							priceColor="#FF3000" :titleWidth="400">
-							<template v-if="!state.editMode" v-slot:tool>
-								<su-number-box :min="0" :max="item.sku.stock" :step="1" v-model="item.count"
-									@change="onNumberChange($event, item)"></su-number-box>
-							</template>
-						</s-goods-item>
-					</view>
-				</view>
-			</view>
-			<!-- 底部 -->
-			<su-fixed bottom :val="48" placeholder v-if="state.list.length > 0" :isInset="false">
-				<view class="cart-footer ss-flex ss-col-center ss-row-between ss-p-x-30 border-bottom">
-					<view class="footer-left ss-flex ss-col-center">
-						<label class="check-box ss-flex ss-col-center ss-p-r-30" @tap="onSelectAll">
-							<radio :checked="state.isAllSelected" color="var(--ui-BG-Main)"
-								style="transform: scale(0.8)" @tap.stop="onSelectAll" />
-							<view class="ss-m-l-8"> 全选 </view>
-						</label>
-						<text>合计:</text>
-						<view class="text-price price-text">
-							{{ state.totalPriceSelected }}
-						</view>
-					</view>
-					<view class="footer-right">
-						<button v-if="state.editMode" class="ss-reset-button ui-BG-Main-Gradient pay-btn ui-Shadow-Main"
-							@tap="onDelete">
-							删除
-						</button>
-						<button v-else class="ss-reset-button ui-BG-Main-Gradient pay-btn ui-Shadow-Main"
-							@tap="onConfirm">
-							去结算
-							{{ state.selectedIds?.length ? `(${state.selectedIds.length})` : '' }}
-						</button>
-					</view>
-				</view>
-			</su-fixed>
-		</view>
-	</s-layout>
+  <s-layout title="购物车" tabbar="/pages/index/cart" :bgStyle="{ color: '#fff' }">
+    <s-empty
+      v-if="state.list.length === 0"
+      text="购物车空空如也,快去逛逛吧~"
+      icon="/static/cart-empty.png"
+    />
+
+    <!-- 头部 -->
+    <view class="cart-box ss-flex ss-flex-col ss-row-between" v-if="state.list.length">
+      <view class="cart-header ss-flex ss-col-center ss-row-between ss-p-x-30">
+        <view class="header-left ss-flex ss-col-center ss-font-26">
+          共
+          <text class="goods-number ui-TC-Main ss-flex">{{ state.list.length }}</text>
+          件商品
+        </view>
+        <view class="header-right">
+          <button v-if="state.editMode" class="ss-reset-button" @tap="state.editMode = false">
+            取消
+          </button>
+          <button v-else class="ss-reset-button ui-TC-Main" @tap="state.editMode = true">
+            编辑
+          </button>
+        </view>
+      </view>
+
+      <!-- 内容 -->
+      <view class="cart-content ss-flex-1 ss-p-x-30 ss-m-b-40">
+        <view class="goods-box ss-r-10 ss-m-b-14" v-for="item in state.list" :key="item.id">
+          <view class="ss-flex ss-col-center">
+            <label class="check-box ss-flex ss-col-center ss-p-l-10" @tap="onSelectSingle(item.id)">
+              <radio
+                :checked="state.selectedIds.includes(item.id)"
+                color="var(--ui-BG-Main)"
+                style="transform: scale(0.8)"
+                @tap.stop="onSelectSingle(item.id)"
+              />
+            </label>
+            <s-goods-item
+              :title="item.spu.name"
+              :img="item.sku.picUrl || item.spu.picUrl"
+              :price="fen2yuan(item.sku.price)"
+              :skuText="item.sku.properties.map((property) => property.valueName).join(' ')"
+              priceColor="#FF3000"
+              :titleWidth="400"
+            >
+              <template v-if="!state.editMode" v-slot:tool>
+                <su-number-box
+                  :min="0"
+                  :max="item.sku.stock"
+                  :step="1"
+                  v-model="item.count"
+                  @change="onNumberChange($event, item)"
+                />
+              </template>
+            </s-goods-item>
+          </view>
+        </view>
+      </view>
+
+      <!-- 底部 -->
+      <su-fixed bottom :val="48" placeholder v-if="state.list.length > 0" :isInset="false">
+        <view class="cart-footer ss-flex ss-col-center ss-row-between ss-p-x-30 border-bottom">
+          <view class="footer-left ss-flex ss-col-center">
+            <label class="check-box ss-flex ss-col-center ss-p-r-30" @tap="onSelectAll">
+              <radio
+                :checked="state.isAllSelected"
+                color="var(--ui-BG-Main)"
+                style="transform: scale(0.8)"
+                @tap.stop="onSelectAll"
+              />
+              <view class="ss-m-l-8"> 全选 </view>
+            </label>
+            <text>合计:</text>
+            <view class="text-price price-text">
+              {{ fen2yuan(state.totalPriceSelected) }}
+            </view>
+          </view>
+          <view class="footer-right">
+            <button
+              v-if="state.editMode"
+              class="ss-reset-button ui-BG-Main-Gradient pay-btn ui-Shadow-Main"
+              @tap="onDelete"
+            >
+              删除
+            </button>
+            <button
+              v-else
+              class="ss-reset-button ui-BG-Main-Gradient pay-btn ui-Shadow-Main"
+              @tap="onConfirm"
+            >
+              去结算
+              {{ state.selectedIds?.length ? `(${state.selectedIds.length})` : '' }}
+            </button>
+          </view>
+        </view>
+      </su-fixed>
+    </view>
+  </s-layout>
 </template>
 
 <script setup>
-	import sheep from '@/sheep';
-	import {
-		computed,
-		reactive,
-		unref
-	} from 'vue';
-
-	const sys_navBar = sheep.$platform.navbar;
-	const cart = sheep.$store('cart');
-
-	const state = reactive({
-		editMode: false,
-		list: computed(() => cart.list),
-		selectedList: [],
-		selectedIds: computed(() => cart.selectedIds),
-		isAllSelected: computed(() => cart.isAllSelected),
-		totalPriceSelected: computed(() => cart.totalPriceSelected),
-	});
-	// 单选选中
-	function onSelectSingle(id) {
-		console.log('单选')
-		cart.selectSingle(id);
-	}
-	// 全选
-	function onSelectAll() {
-		cart.selectAll(!state.isAllSelected);
-	}
-
-	// 结算
-	function onConfirm() {
-		let items = []
-		let goods_list = [];
-		state.selectedList = state.list.filter((item) => state.selectedIds.includes(item.id));
-		state.selectedList.map((item) => {
-			console.log(item, '便利');
-			// 此处前端做出修改
-			items.push({
-				skuId: item.sku.id,
-				count: item.count,
-				cartId: item.id,
-			})
-			goods_list.push({
-				// goods_id: item.goods_id,
-				goods_id: item.spu.id,
-				// goods_num: item.goods_num,
-				goods_num: item.count,
-				// 商品价格id真没有
-				// goods_sku_price_id: item.goods_sku_price_id,
-			});
-		});
-		// return;
-		if (goods_list.length === 0) {
-			sheep.$helper.toast('请选择商品');
-			return;
-		}
-		sheep.$router.go('/pages/order/confirm', {
-			data: JSON.stringify({
-				// order_type: 'goods',
-				// goods_list,
-				items,
-				// from: 'cart',
-				deliveryType: 1,
-				pointStatus: false,
-			}),
-		});
-	}
-
-	function onNumberChange(e, cartItem) {
-		if (e === 0) {
-			cart.delete(cartItem.id);
-			return;
-		}
-		if (cartItem.goods_num === e) return;
-		cartItem.goods_num = e;
-		cart.update({
-			goods_id: cartItem.id,
-			goods_num: e,
-			goods_sku_price_id: cartItem.goods_sku_price_id,
-		});
-	}
-	async function onDelete() {
-		cart.delete(state.selectedIds);
-	}
+  import sheep from '@/sheep';
+  import { computed, reactive } from 'vue';
+  import { fen2yuan } from '@/sheep/hooks/useGoods';
+  import { property } from 'lodash/util';
+
+  const sys_navBar = sheep.$platform.navbar;
+  const cart = sheep.$store('cart');
+
+  const state = reactive({
+    editMode: false,
+    list: computed(() => cart.list), // 购物车项的列表
+    selectedIds: computed(() => cart.selectedIds),
+    isAllSelected: computed(() => cart.isAllSelected),
+    totalPriceSelected: computed(() => cart.totalPriceSelected),
+  });
+
+  // 单选
+  function onSelectSingle(id) {
+    cart.selectSingle(id);
+  }
+
+  // 全选
+  function onSelectAll() {
+    cart.selectAll(!state.isAllSelected);
+  }
+
+  // 结算
+  function onConfirm() {
+    const items = state.list
+      .filter((item) => state.selectedIds.includes(item.id))
+      .map((item) => {
+        return {
+          skuId: item.sku.id,
+          count: item.count,
+          cartId: item.id,
+        };
+      });
+    if (items.length === 0) {
+      sheep.$helper.toast('请选择商品');
+      return;
+    }
+    sheep.$router.go('/pages/order/confirm', {
+      data: JSON.stringify({
+        items,
+        // order_type: 'goods',
+        // goods_list,
+        // from: 'cart',
+        deliveryType: 1,
+        pointStatus: false,
+      }),
+    });
+  }
+
+  // 更新数量
+  function onNumberChange(number, cartItem) {
+    if (number === 0) {
+      cart.delete([cartItem.id]);
+      return;
+    }
+    if (cartItem.goods_num === number) {
+      return;
+    }
+    cartItem.goods_num = number;
+    cart.update({
+      goods_id: cartItem.id,
+      goods_num: number,
+    });
+  }
+
+  // 删除
+  async function onDelete() {
+    cart.delete(state.selectedIds);
+  }
 </script>
 
 <style lang="scss" scoped>
-	:deep(.ui-fixed) {
-		height: 72rpx;
-	}
-
-	.cart-box {
-		width: 100%;
-
-		.cart-header {
-			height: 70rpx;
-			background-color: #f6f6f6;
-			width: 100%;
-			position: fixed;
-			left: 0;
-			top: v-bind('sys_navBar') rpx;
-			z-index: 1000;
-			box-sizing: border-box;
-		}
-
-		.cart-footer {
-			height: 100rpx;
-			background-color: #fff;
-
-			.pay-btn {
-				width: 180rpx;
-				height: 70rpx;
-				font-size: 28rpx;
-				line-height: 28rpx;
-				font-weight: 500;
-				border-radius: 40rpx;
-			}
-		}
-
-		.cart-content {
-			margin-top: 70rpx;
-
-			.goods-box {
-				background-color: #fff;
-			}
-		}
-	}
-</style>
+  :deep(.ui-fixed) {
+    height: 72rpx;
+  }
+
+  .cart-box {
+    width: 100%;
+
+    .cart-header {
+      height: 70rpx;
+      background-color: #f6f6f6;
+      width: 100%;
+      position: fixed;
+      left: 0;
+      top: v-bind('sys_navBar') rpx;
+      z-index: 1000;
+      box-sizing: border-box;
+    }
+
+    .cart-footer {
+      height: 100rpx;
+      background-color: #fff;
+
+      .pay-btn {
+        width: 180rpx;
+        height: 70rpx;
+        font-size: 28rpx;
+        line-height: 28rpx;
+        font-weight: 500;
+        border-radius: 40rpx;
+      }
+    }
+
+    .cart-content {
+      margin-top: 70rpx;
+
+      .goods-box {
+        background-color: #fff;
+      }
+    }
+  }
+</style>

+ 1 - 0
sheep/api/cart.js

@@ -15,6 +15,7 @@ export default {
 		request({
 			url: 'cart',
 			method: 'POST',
+      // TODO 芋艿:这里没提示
 			custom: {
 				showSuccess: true,
 				successMsg: '已添加到购物车~',

+ 47 - 0
sheep/api/trade/cart.js

@@ -0,0 +1,47 @@
+import request2 from '@/sheep/request2';
+
+const CartApi = {
+  addCart: (data) => {
+    return request2({
+      url: '/app-api/trade/cart/add',
+      method: 'POST',
+      data: data,
+      // TODO 芋艿:这里没提示
+      custom: {
+        showSuccess: true,
+        successMsg: '已添加到购物车~',
+      }
+    });
+  },
+  updateCartCount: (data) => {
+    return request2({
+      url: '/app-api/trade/cart/update-count',
+      method: 'PUT',
+      data: data
+    });
+  },
+  updateCartSelected: (data) => {
+    return request2({
+      url: '/app-api/trade/cart/update-selected',
+      method: 'PUT',
+      data: data
+    });
+  },
+  deleteCart: (ids) => {
+    return request2({
+      url: '/app-api/trade/cart/delete',
+      method: 'DELETE',
+      params: {
+        ids
+      }
+    });
+  },
+  getCartList: () => {
+    return request2({
+      url: '/app-api/trade/cart/list',
+      method: 'GET',
+    });
+  },
+};
+
+export default CartApi;

+ 48 - 53
sheep/store/cart.js

@@ -1,98 +1,93 @@
 import { defineStore } from 'pinia';
-import cartApi from '@/sheep/api/cart';
+import CartApi from '@/sheep/api/trade/cart';
 
 const cart = defineStore({
   id: 'cart',
   state: () => ({
     list: [], // 购物车列表
     selectedIds: [], // 已选列表
-    isAllSelected: false, //是否全选
-    cartSelectedTotalPrice: '0.00', // 选中项总金额
+    isAllSelected: false, // 是否全选
+    totalPriceSelected: 0, // 选中项总金额
   }),
-  getters: {
-    totalPriceSelected: (state) => {
-      let price = 0;
-      if (!state.selectedIds.length) return price.toFixed(2);
-      state.list.forEach((item) => {
-        price += state.selectedIds.includes(item.id)
-          ? Number(item.sku.price/100) * item.count
-          : 0;
-      });
-      return price.toFixed(2);
-    },
-  },
   actions: {
     // 获取购物车列表
     async getList() {
-      const { data, code } = await cartApi.list();
+      const { data, code } = await CartApi.getCartList();
       if (code === 0) {
         this.list = data.validList;
+
+        // 计算各种关联属性
+        this.selectedIds = [];
+        this.isAllSelected = true;
+        this.totalPriceSelected = 0;
+        this.list.forEach((item) => {
+          if (item.selected) {
+            this.selectedIds.push(item.id);
+            this.totalPriceSelected += item.count * item.sku.price;
+          } else {
+            this.isAllSelected = false;
+          }
+        });
       }
     },
+
     // 添加购物车
     async add(goodsInfo) {
-      const { error } = await cartApi.append({
-        goods_id: goodsInfo.goods_id,
-        goods_num: goodsInfo.goods_num,
-        goods_sku_price_id: goodsInfo.id,
+      // 添加购物项
+      const { code } = await CartApi.addCart({
+        skuId: goodsInfo.id,
+        count: goodsInfo.goods_num,
       });
-      if (error === 0) {
-        this.getList();
+      // 刷新购物车列表
+      if (code === 0) {
+        await this.getList();
       }
     },
 
     // 更新购物车
     async update(goodsInfo) {
-      const { error } = await cartApi.update({
+      const { code } = await CartApi.updateCartCount({
         id: goodsInfo.goods_id,
         count: goodsInfo.goods_num,
-        goods_sku_price_id: goodsInfo.goods_sku_price_id,
       });
-      if (error === 0) {
-        // this.getList();
+      if (code === 0) {
+        await this.getList();
       }
     },
 
     // 移除购物车
     async delete(ids) {
-      if (typeof ids === 'array') {
-        ids = ids.join(',');
-      }
-      const { code } = await cartApi.delete(ids);
+      const { code } = await CartApi.deleteCart(ids.join(','));
       if (code === 0) {
-        this.selectAll(false);
-        this.getList();
+        await this.getList();
       }
     },
 
-    // 选择购物车商品
-    selectSingle(goodsId) {
-      if (!this.selectedIds.includes(goodsId)) {
-        this.selectedIds.push(goodsId);
-      } else {
-        this.selectedIds.splice(this.selectedIds.indexOf(goodsId), 1);
+    // 单选购物车商品
+    async selectSingle(goodsId) {
+      const { code } = await CartApi.updateCartSelected({
+        ids: [goodsId],
+        selected: !this.selectedIds.includes(goodsId), // 取反
+      });
+      if (code === 0) {
+        await this.getList();
       }
-      this.isAllSelected = this.selectedIds.length === this.list.length;
     },
 
-    // 全选
-    selectAll(flag) {
-      this.isAllSelected = flag;
-      if (!flag) {
-        this.selectedIds = [];
-      } else {
-        this.list.forEach((item) => {
-          this.selectedIds.push(item.id);
-        });
+    // 全选购物车商品
+    async selectAll(flag) {
+      const { code } = await CartApi.updateCartSelected({
+        ids: this.list.map((item) => item.id),
+        selected: flag
+      });
+      if (code === 0) {
+        await this.getList();
       }
     },
 
     // 清空购物车
-    emptyList() {
-      this.list = [];
-      this.selectedIds = [];
-      this.isAllSelected = false;
-      this.cartSelectedTotalPrice = '0.00';
+    async emptyList() {
+      await this.delete(this.list.map((item) => item.id));
     },
   },
   persist: {