소스 검색

上传文件至 'pages/cart'

linwenxin 4 달 전
부모
커밋
bc71c9b6ce
1개의 변경된 파일709개의 추가작업 그리고 0개의 파일을 삭제
  1. 709 0
      pages/cart/index.vue

+ 709 - 0
pages/cart/index.vue

@@ -0,0 +1,709 @@
+<template>
+	<view class="app-container" :class="isNoticebar ? 'hasNoticebar' : ''">
+		<view class="noticebar" v-if="isNoticebar">
+			<uni-notice-bar v-if="noticeContent" scrollable="true" single="true" showClose="true" :text="noticeContent"
+				background-color="#f6e6e7" color="#de3749" @close="closeNoticebar"></uni-notice-bar>
+		</view>
+
+		<view class="top" :class="isNoticebar ? 'hasNoticebar' : ''">
+			<view class="total">共{{ totalNum }}件商品</view>
+			<view v-if="!isEditor" @tap="isEditor = !isEditor">编辑</view>
+			<view v-else @tap="isEditor = !isEditor">完成</view>
+		</view>
+		<view class="list">
+			<block v-for="(item, index) in goodsList" :key="index">
+				<view class="item">
+					<view class="check" v-if="item.selected" @tap="selectList(index)">
+						<image src="@/static/icon/select_1.png" mode=""></image>
+					</view>
+					<view class="check" v-else @tap="selectList(index)">
+						<image src="@/static/icon/select_0.png" mode="" />
+					</view>
+					<image :src="item.goodsImg" mode="aspectFill" class="img"></image>
+					<view class="right">
+						<view class="title ellipsis-2">{{ item.goodsName }}</view>
+						<view class="des ellipsis">{{ item.specValue }}</view>
+						<view class="last">
+							<view class="price">
+								<view class="price-1">¥{{ item.price | numToFixed }}</view>
+								<view class="price-2">¥{{ item.orgPrice | numToFixed }}</view>
+							</view>
+							<u-number-box @tap.stop v-model="item.num" :min="1" :buttonSize="26"
+								iconStyle="font-size: 12px;" @change="changeCount($event, index)">
+							</u-number-box>
+						</view>
+					</view>
+				</view>
+			</block>
+		</view>
+		<no-data v-if="!goodsList.length" :showText="'购物车暂无商品'"></no-data>
+
+
+		<view
+			style="width: 100%;display: flex;justify-content: space-between;align-items: center;margin-bottom: 20rpx;margin-top: 20rpx;">
+			<view style="width: 30%;height: 2rpx;background: #a8a8a8;"></view>
+			<view style="font-size: 24rpx;color: #8a8a8a;">猜你想要</view>
+			<view style="width: 30%;height: 2rpx;background: #a8a8a8;"></view>
+		</view>
+		<view class="goods-waterfall-list">
+			<view class="left">
+				<block v-for="(item, index) in goodsList2" :key='index'>
+					<view class="item" v-if="index%2==0" @tap="toGoodsDetail(item.goodsId)">
+						<view class="image">
+							<image :src="item.imgUrl" mode="aspectFill" class="img"></image>
+							<image :src="item.logo" mode="aspectFill" class="water" v-if="item.isShowWater"></image>
+						</view>
+						<view class="content">
+							<view class="title ellipsis-2">{{item.goodsName}}</view>
+							<view class="tags" v-if="item.tags1 && item.tags1.length > 0">
+								<view class="it" v-for="(it, idx) in item.tags1" :key="idx">{{it}}</view>
+							</view>
+							<view class="price">
+								<view class="price-1">¥{{item.goodsPrice | numToFixed}}</view>
+								<view class="price-2">¥{{item.orgGoodsPrice | numToFixed}}</view>
+							</view>
+							<view class="tags2" v-if="item.tags2 && item.tags2.length > 0">
+								<view class="it" v-for="(it, idx) in item.tags2" :key="idx">{{it}}</view>
+							</view>
+							<view class="text">销量:{{item.soldNum}}</view>
+						</view>
+					</view>
+				</block>
+			</view>
+			<view class="right">
+				<block v-for="(item, index) in goodsList2" :key='index'>
+					<view class="item" v-if="index%2==1" @tap="toGoodsDetail(item.goodsId)">
+						<view class="image">
+							<image :src="item.imgUrl" mode="aspectFill" class="img"></image>
+							<image :src="item.logo" mode="aspectFill" class="water" v-if="item.isShowWater"></image>
+						</view>
+						<view class="content">
+							<view class="title ellipsis-2">{{item.goodsName}}</view>
+							<view class="tags" v-if="item.tags1 && item.tags1.length > 0">
+								<view class="it" v-for="(it, idx) in item.tags1" :key="idx">{{it}}</view>
+							</view>
+							<view class="price">
+								<view class="price-1">¥{{item.goodsPrice | numToFixed}}</view>
+								<view class="price-2">¥{{item.orgGoodsPrice | numToFixed}}</view>
+							</view>
+							<view class="tags2" v-if="item.tags2 && item.tags2.length > 0">
+								<view class="it" v-for="(it, idx) in item.tags2" :key="idx">{{it}}</view>
+							</view>
+							<view class="text">销量:{{item.soldNum}}</view>
+						</view>
+					</view>
+				</block>
+			</view>
+		</view>
+
+
+
+		<view class="bottom">
+			<view class="check" @tap="selectAll">
+				<image src="@/static/icon/select_1.png" mode="" v-if="selectAllStatus" />
+				<image src="@/static/icon/select_0.png" mode="" v-else />
+				<text class="text">全选</text>
+			</view>
+			<view class="right" v-if="!isEditor">
+				<view class="price">
+					合计:<text>¥{{ totalPrice }}</text>
+				</view>
+				<view class="button"><button @tap="toOrder">去结算</button></view>
+			</view>
+			<view class="right" v-else>
+				<button class="delete" @tap="clickDelete">删除</button>
+			</view>
+		</view>
+
+		<u-popup :round="10" :show="isShowPhoneDialog">
+			<view class="phone-dialog">
+				<view class="content">
+					<view>申请获取以下权限</view>
+					<text>获得你的公开信息(手机号码)</text>
+				</view>
+				<view class="btn">
+					<button @tap="isShowPhoneDialog = false">取消</button>
+					<button type="primary" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">
+						确定授权
+					</button>
+				</view>
+			</view>
+		</u-popup>
+
+		<modal-dialog showText="确定要删除选中的商品吗?" :isShowDialog="isDialog" @cancel="isDialog = false"
+			@confirm="confirmDelete"></modal-dialog>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex';
+	import modalDialog from '@/components/modalDialog.vue';
+
+	export default {
+		components: {
+			modalDialog,
+		},
+		data() {
+			return {
+				goodsList: [],
+				totalPrice: 0, // 总价,初始为0
+				totalNum: 0,
+				selectAllStatus: true, // 全选状态,默认全选
+				isEditor: false, // 是否编辑
+				isDialog: false, // 是否显示删除弹窗
+				isNoticebar: false, // 是否显示通告栏
+				noticeContent: '', // 公告内容
+				isShowPhoneDialog: false,
+
+				goodsList2: [],
+				pageNum: 1,
+				pageSize: 8,
+				noMore: false,
+			};
+		},
+		computed: {
+			...mapState(['userInfo', 'isLogin', 'userId']),
+		},
+		onShow() {
+			this.getGoodsList();
+			this.goodsList2 = [];
+			this.getGoodsList22();
+		},
+		onLoad() {
+			this.getNoticebar();
+		},
+
+		// 下拉刷新
+		onPullDownRefresh() {
+			this.pageNum = 1;
+			this.getGoodsList22();
+		},
+
+		// 上拉加载
+		onReachBottom() {
+			this.getGoodsList22(1);
+		},
+
+		methods: {
+
+			// 获取商品列表
+			getGoodsList22(loadMore) {
+				if (this.noMore && loadMore) return;
+				this.noMore = false
+				if (!loadMore) {
+					this.pageNum = 1;
+				}
+				this.$axios({
+					url: '/goods/list/sort/page',
+					method: 'get',
+					params: {
+						pageNum: this.pageNum,
+						pageSize: this.pageSize,
+						categoryId: '',
+						sort: 5,
+					},
+					isLoading: !loadMore
+				}).then(res => {
+					res.data.records.forEach(item => {
+						if (item.logo && item.logoStartTime) {
+							item.isShowWater = this.$compareTime(item.logoStartTime, item.logoEndTime);
+						} else {
+							item.isShowWater = false;
+						}
+					})
+					let _list = res.data.records;
+					let pageTotal = res.data.pages;
+					if (this.pageNum >= pageTotal) {
+						this.noMore = true;
+					}
+					if (_list.length) {
+						this.pageNum += 1
+					}
+					if (loadMore) {
+						this.goodsList2 = this.goodsList.concat(_list);
+					} else {
+						this.goodsList2 = _list;
+					}
+				})
+			},
+
+			// 进入商品详情
+			toGoodsDetail(id) {
+				if (!id) {
+					return false;
+				}
+
+				this.$axios({
+						url: '/goods/detail',
+						method: 'get',
+						params: {
+							goodsId: id,
+							userId: this.userId,
+						},
+					})
+					.then((res) => {
+						uni.navigateTo({
+							url: '/packageGoods/pages/detail?id=' + id
+						})
+					})
+					.catch((res) => {
+						uni.switchTab({
+							url: '/pages/goods/all'
+						});
+					})
+					.finally((res) => {});
+			},
+			// 获取手机号
+			getPhoneNumber(e) {
+				if (e?.detail?.iv && e?.detail?.encryptedData) {
+					this.$axios({
+						url: '/user/mobile/grant',
+						params: {
+							userId: this.userId,
+							iv: e.detail.iv,
+							encryptedData: e.detail.encryptedData,
+						},
+					}).then((res) => {
+						uni.setStorageSync('token', res.data.token);
+						uni.setStorageSync('isActiveLogout', false);
+						this.isShowPhoneDialog = false;
+						this.$getUserInfo();
+					});
+				}
+			},
+			// 获取公告栏
+			getNoticebar() {
+				this.$axios({
+					url: '/shpping/cart/notice',
+					method: 'get',
+					params: {
+						userId: this.userId,
+					},
+				}).then((res) => {
+					this.noticeContent = res.data;
+					this.isNoticebar = res.data ? true : false;
+				});
+			},
+
+			// 获取商品列表
+			getGoodsList() {
+				this.$axios({
+					url: '/shpping/cart/list',
+					method: 'get',
+					params: {
+						userId: this.userId,
+					},
+				}).then((res) => {
+					this.goodsList = res.data.shoppingCartLists;
+					this.totalNum = res.data.totalNum;
+					this.goodsList.forEach((item, index) => {
+						item.selected = true;
+					});
+					this.selectAllStatus = true;
+					this.getTotalPrice();
+				});
+			},
+
+			// 统计总价
+			getTotalPrice() {
+				// 获取购物车列表
+				let goodsList = this.goodsList;
+				let total = 0;
+				// 循环列表
+				for (let i = 0; i < goodsList.length; i++) {
+					// 判断选中才会计算价格
+					if (goodsList[i].selected) {
+						// 所有价格加起来
+						total += goodsList[i].num * goodsList[i].price;
+					}
+				}
+				// 赋值到data中渲染到页面
+				this.goodsList = goodsList;
+				this.totalPrice = total.toFixed(2);
+			},
+
+			// 选择事件
+			selectList(index) {
+				// 获取购物车列表
+				let goodsList = this.goodsList;
+				// 获取当前商品的选中状态
+				let selected = goodsList[index].selected;
+				// 改变状态
+				goodsList[index].selected = !selected;
+				this.goodsList = goodsList;
+
+				// 改变全选状态
+				for (var i = 0; i < this.goodsList.length; i++) {
+					// 当状态为全选时,每个元素其中有一个为false,则取消全选
+					// 当状态为非全选时,每个元素都为true,则全选
+					if (this.selectAllStatus) {
+						if (!this.goodsList[i].selected) {
+							this.selectAllStatus = false;
+							break;
+						}
+					} else {
+						if (this.goodsList[i].selected) {
+							this.selectAllStatus = true;
+						} else {
+							this.selectAllStatus = false;
+							break;
+						}
+					}
+				}
+
+				// 重新获取总价
+				this.getTotalPrice();
+			},
+
+			// 全选事件
+			selectAll(e) {
+				// 是否全选状态
+				let selectAllStatus = this.selectAllStatus;
+				selectAllStatus = !selectAllStatus;
+				let goodsList = this.goodsList;
+				for (let i = 0; i < goodsList.length; i++) {
+					// 改变所有商品状态
+					goodsList[i].selected = selectAllStatus;
+				}
+				this.selectAllStatus = selectAllStatus;
+				this.goodsList = goodsList;
+				// 重新获取总价
+				this.getTotalPrice();
+			},
+
+			// 更改数量
+			changeCount(e, index) {
+				this.goodsList[index].num = e.value;
+				this.initCart();
+			},
+
+			// 修改数量后更新购物车数据
+			initCart() {
+				let buyGoods = [];
+				this.goodsList.forEach((item, index) => {
+					let goodsItem = {
+						goodsId: item.goodsId,
+						goodsSpecId: item.goodsSpecId,
+						num: item.num,
+						shoppingCartId: item.shoppingCartId,
+						secKillId: item.secKillId || '',
+						promotionGroupId: item.promotionGroupId || '',
+					};
+					buyGoods.push(goodsItem);
+				});
+				this.$axios({
+					url: '/shpping/cart/add',
+					type: 'application/json',
+					params: {
+						userId: this.userId,
+						buyGoods: buyGoods,
+					},
+				}).then((res) => {
+					this.totalNum = res.data.totalNum;
+					this.getTotalPrice();
+				});
+			},
+
+			// 点击删除
+			clickDelete() {
+				let delIds = [];
+				for (let i = 0; i < this.goodsList.length; i++) {
+					if (this.goodsList[i].selected) {
+						delIds.push(this.goodsList[i].shoppingCartId);
+					}
+				}
+				if (delIds.length < 1) {
+					return this.$toast('至少选择一件商品');
+				}
+				this.isDialog = true;
+			},
+
+			// 确认删除
+			confirmDelete() {
+				let delIds = [];
+				for (let i = 0; i < this.goodsList.length; i++) {
+					if (this.goodsList[i].selected) {
+						delIds.push(this.goodsList[i].shoppingCartId);
+					}
+				}
+				this.$axios({
+					url: '/shpping/cart/remove',
+					params: {
+						shoppingCartIds: delIds,
+						userId: this.userId,
+					},
+				}).then((res) => {
+					this.isDialog = false;
+					this.isEditor = false;
+					this.$successToast('删除成功');
+					this.getGoodsList();
+				});
+			},
+
+			// 去结算
+			toOrder() {
+				let buyList = [];
+				this.goodsList.forEach((item, index) => {
+					if (item.selected) {
+						let goodsItem = {
+							goodsId: item.goodsId,
+							goodsSpecId: item.goodsSpecId,
+							num: item.num,
+							shoppingCartId: item.shoppingCartId,
+							secKillId: item.secKillId || '',
+							promotionGroupId: item.promotionGroupId || '',
+						};
+						buyList.push(goodsItem);
+					}
+				});
+				if (buyList.length < 1) {
+					return this.$toast('至少选择一件商品');
+				}
+				if (!this.userInfo.mobile) {
+					this.isShowPhoneDialog = true;
+					return;
+				}
+				// 跳转结算页面
+				uni.navigateTo({
+					url: '/packageGoods/pages/order?buyList=' + JSON.stringify(buyList),
+				});
+			},
+
+			// 关闭通告栏
+			closeNoticebar() {
+				this.isNoticebar = false;
+			},
+		},
+	};
+</script>
+
+<style lang="scss">
+	.app-container {
+		background: #f4f2f2;
+		box-sizing: border-box;
+	}
+
+	.app-container {
+		height: auto;
+		padding: 110rpx 0;
+
+		&.hasNoticebar {
+			padding-top: 174rpx;
+		}
+
+		.noticebar {
+			position: fixed;
+			top: 0;
+			left: 0;
+			width: 100%;
+			z-index: 100;
+		}
+
+		.top {
+			position: fixed;
+			top: 0;
+			left: 0;
+			z-index: 99;
+			width: 100%;
+			padding: 0 20rpx;
+			box-sizing: border-box;
+			background: #ffffff;
+			height: 88rpx;
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			border-bottom: 1px solid #f4f2f2;
+
+			&.hasNoticebar {
+				top: 64rpx;
+			}
+
+			.total {
+				font-size: 32rpx;
+			}
+		}
+
+		.list {
+			padding: 0 20rpx;
+
+			.item {
+				margin-bottom: 20rpx;
+				border-radius: 10rpx;
+				padding: 20rpx 20rpx;
+				display: flex;
+				align-items: center;
+				background: #ffffff;
+
+				.check {
+					image {
+						width: 32rpx;
+						height: 32rpx;
+						display: block;
+					}
+				}
+
+				.img {
+					width: 180rpx;
+					height: 180rpx;
+					display: block;
+					margin: 0 20rpx;
+					flex-shrink: 0;
+				}
+
+				.right {
+					width: 420rpx;
+					height: 190rpx;
+					display: flex;
+					justify-content: space-between;
+					flex-direction: column;
+
+					.title {
+						font-size: 28rpx;
+						color: #333333;
+						line-height: 36rpx;
+					}
+
+					.des {
+						font-size: 24rpx;
+						color: #999999;
+						line-height: 36rpx;
+					}
+
+					.last {
+						display: flex;
+						justify-content: space-between;
+						align-items: center;
+
+						.price {
+							display: flex;
+							flex-direction: column;
+						}
+
+						.price-1 {
+							font-size: 32rpx;
+							color: #ff3f42;
+							line-height: 36rpx;
+						}
+
+						.price-2 {
+							font-size: 26rpx;
+							color: #666666;
+							line-height: 30rpx;
+							text-decoration: line-through;
+						}
+					}
+				}
+			}
+		}
+
+		.bottom {
+			position: fixed;
+			left: 0;
+			bottom: 0;
+			z-index: 99;
+			width: 100%;
+			box-sizing: border-box;
+			background: #ffffff;
+			height: 100rpx;
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			padding: 0 20rpx;
+			border-top: 1px solid #f4f2f2;
+
+			.check {
+				display: flex;
+				align-items: center;
+
+				image {
+					width: 32rpx;
+					height: 32rpx;
+					display: block;
+					margin-right: 20rpx;
+				}
+			}
+
+			.right {
+				display: flex;
+				align-items: center;
+
+				.price {
+					font-size: 28rpx;
+					line-height: 36rpx;
+
+					text {
+						color: #ff3f42;
+					}
+
+					margin-right: 20rpx;
+				}
+
+				.button {
+					button {
+						height: 80rpx;
+						line-height: 80rpx;
+						padding: 0;
+						border-radius: 80rpx;
+						font-size: 30rpx;
+						color: #fff;
+						background: linear-gradient(-90deg, #ff3f42 0%, #fe781f 100%);
+						padding: 0 40rpx;
+					}
+				}
+
+				.delete {
+					width: 170rpx;
+					height: 80rpx;
+					line-height: 80rpx;
+					text-align: center;
+					padding: 0;
+					border-radius: 80rpx;
+					font-size: 30rpx;
+					color: #ff3f42;
+					border: 1px solid #ff3f42;
+				}
+			}
+		}
+	}
+
+	.phone-dialog {
+		padding: 40rpx;
+		box-sizing: border-box;
+
+		.content {
+			margin-top: 30rpx;
+			margin-bottom: 30rpx;
+			line-height: 50rpx;
+
+			text {
+				color: #9d9d9d;
+			}
+		}
+
+		.btn {
+			display: flex;
+			justify-content: center;
+			margin-top: 60rpx;
+
+			button::after {
+				border: none;
+			}
+
+			button {
+				width: 180rpx;
+				height: 70rpx;
+				line-height: 70rpx;
+				margin: 0;
+				font-size: 28rpx;
+				margin: 0 30rpx;
+
+				&:first-child {
+					background: #f5f5f5;
+					color: #00ba5c;
+				}
+			}
+		}
+	}
+</style>