Prechádzať zdrojové kódy

Merge branch 'master' of http://git.liuniu946.com/xiemingyang/zhengyi

xiemingyang 3 rokov pred
rodič
commit
8caea99c7c

+ 74 - 39
pages.json

@@ -1,46 +1,75 @@
 {
-	"pages": [
+	"pages": [{
+			"path": "pages/index/index",
+			"style": {
+				"enablePullDownRefresh": true,
+				// #ifdef MP
+				"navigationStyle": "custom",
+				// #endif
+				// #ifndef MP
+				"app-plus": {
+					"titleNView": {
+						"type": "transparent",
+						"searchInput": {
+							"backgroundColor": "rgba(231, 231, 231,.7)",
+							"borderRadius": "16px",
+							"placeholder": "请输入关键字",
+							"disabled": true,
+							"placeholderColor": "#606266",
+							"align": "left"
+						}
+					}
+				},
+				// #endif
+				"navigationBarTitleText": "商城首页"
+			}
+		},
 		{
-				"path": "pages/index/index",
-				"style": {
-					"enablePullDownRefresh": true,
-					// #ifdef MP
-					"navigationStyle": "custom",
-					// #endif
-					// #ifndef MP
-					"app-plus": {
-						"titleNView": {
-							"type": "transparent",
-							"searchInput": {
-								"backgroundColor": "rgba(231, 231, 231,.7)",
-								"borderRadius": "16px",
-								"placeholder": "请输入关键字",
-								"disabled": true,
-								"placeholderColor": "#606266",
-								"align": "left"
-							},
-							"buttons": [{
-									"fontSrc": "/static/yticon.ttf",
-									"text": "\ue60d",
-									"fontSize": "26",
-									"color": "#303133",
-									"float": "left",
-									"background": "rgba(0,0,0,0)"
-								},
-								{
-									"fontSrc": "/static/yticon.ttf",
-									"text": "\ue744",
-									"fontSize": "27",
-									"color": "#303133",
-									"background": "rgba(0,0,0,0)"
-								}
-							]
+			"path": "pages/category/category",
+			"style": {
+				// #ifdef APP-PLUS
+				"navigationStyle": "custom",
+				// #endif
+				// #ifndef MP
+				"app-plus": {
+					"bounce": "none",
+					"titleNView": {
+						"searchInput": {
+							"backgroundColor": "rgba(231, 231, 231,.7)",
+							"borderRadius": "16px",
+							"placeholder": "商品搜索",
+							"disabled": true,
+							"placeholderColor": "#606266",
+							"align": "left"
 						}
-					},
-					// #endif
-					"navigationBarTitleText": "商城首页"
-				}
+					}
+				},
+				// #endif
+				"navigationBarTitleText": "分类",
+				"navigationBarBackgroundColor":"#FFFFFF"
+			}
+		}, {
+			"path": "pages/cart/cart",
+			"style": {
+				"navigationBarTitleText": "购物车",
+				"navigationBarBackgroundColor":"#FFFFFF",
+				"navigationBarTextStyle":"black"
 			}
+		},
+		{
+			"path": "pages/user/user",
+			"style": {
+				"navigationBarTitleText": "个人中心"
+			}
+		},
+		{
+			"path": "pages/story/story",
+			"style": {
+				"navigationBarTitleText": "品牌中心",
+				"navigationBarBackgroundColor":"#FFFFFF",
+				"navigationBarTextStyle":"black"
+			}
+		}
 	],
 	"tabBar": {
 		"color": "#C0C4CC",
@@ -59,6 +88,12 @@
 				"selectedIconPath": "static/tabBar/tab-cate-current.png",
 				"text": "分类"
 			},
+			{
+				"pagePath": "pages/story/story",
+				"iconPath": "static/tabBar/tab-cart.png",
+				"selectedIconPath": "static/tabBar/tab-cart-current.png",
+				"text": "品牌故事"
+			},
 			{
 				"pagePath": "pages/cart/cart",
 				"iconPath": "static/tabBar/tab-cart.png",

+ 535 - 0
pages/cart/cart.vue

@@ -0,0 +1,535 @@
+<template>
+	<view class="container">
+		<!-- 空白页 -->
+		<view v-if="!hasLogin || empty === true" class="empty">
+			<image src="/static/error/emptyCart.png" class="emptyImg" mode="aspectFit"></image>
+			<view v-if="hasLogin" class="empty-tips">
+				空空如也
+				<navigator class="navigator" v-if="hasLogin" url="../index/index" open-type="switchTab">随便逛逛></navigator>
+			</view>
+			<view v-else class="empty-tips">
+				空空如也
+				<view class="navigator" @click="navToLogin">去登陆></view>
+			</view>
+		</view>
+		<view v-else>
+			<!-- 购物车头部 -->
+			<view class="cart-hand flex">
+				<view class="hand-tit">
+					购物车共 <text>{{ ' '+cartList.length}} 件</text>商品
+				</view>
+				<view class="hand-btn" @click="clearCart()">
+					清空购物车
+				</view>
+			</view>
+			<!-- 列表 -->
+			<view class="cart-list">
+				<block v-for="(item, index) in cartList" :key="item.id">
+					<view class="cart-item" :class="{ 'b-b': index !== cartList.length - 1 }">
+						<view class="image-wrapper">
+							<image
+								:src="item.productInfo.image"
+								:class="[item.loaded]"
+								mode="aspectFill"
+								lazy-load
+								@load="onImageLoad('cartList', index)"
+								@error="onImageError('cartList', index)"
+							></image>
+							<view class="iconfont iconroundcheckfill checkbox" :class="{ checked: item.checked }" @click="check('item', index)"></view>
+						</view>
+						<view class="item-right">
+							<text class="clamp title">{{ item.productInfo.store_name }}</text>
+							<text class="attr">{{ item.productInfo.attrInfo.suk }}</text>
+							<text class="price">¥{{ item.productInfo.price }}</text>
+							<view class="munbox flex" >
+								<image src="../../static/img/reduce.png" mode="" @click="reduce(item,index)"></image>
+								<input type="number" :value="item.cart_num" disabled/>
+								<image src="../../static/img/add.png" mode="" @click="add(item)"></image>
+							</view>
+						</view>
+					</view>
+				</block>
+			</view>
+			<!-- 底部菜单栏 -->
+			<view class="action-section">
+				<view class="checkbox">
+					<view class="iconfont iconroundcheckfill icon-checked-box" @click="check('all')" :class="{ 'icon-checked': allChecked }"></view>
+				</view>
+				<view class="total-box">
+					<text class="price">¥{{ total }}</text>
+					
+				</view>
+				<button type="primary" class="no-border confirm-btn" @click="createOrder">去结算</button>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+// import { getCartList, getCartNum, cartDel } from '@/api/user.js';
+import { mapState } from 'vuex';
+import uniNumberBox from '@/components/uni-number-box.vue';
+import { saveUrl, interceptor } from '@/utils/loginUtils.js';
+export default {
+	components: {
+		uniNumberBox
+	},
+	data() {
+		return {
+			total: 0, //总价格
+			allChecked: false, //全选状态  true|false
+			empty: false, //空白页现实  true|false
+			cartList: []
+		};
+	},
+	onShow() {
+		// 只有登录时才加载数据
+		if (this.hasLogin) {
+			this.loadData();
+		}
+	},
+	watch: {
+		//显示空白页
+		cartList(e) {
+			let empty = e.length === 0 ? true : false;
+			if (this.empty !== empty) {
+				this.empty = empty;
+			}
+		}
+	},
+	computed: {
+		...mapState('user', ['hasLogin'])
+	},
+	methods: {
+		reduce(item,index) {
+			if(item.cart_num == 1) {
+				uni.showModal({
+					content: '删除该商品?',
+					success: e => {
+						if (e.confirm) {
+							this.deleteCartItem(index)
+						}
+					}
+				});
+				
+			}else {
+				item.cart_num--
+				this.newNumberChange(item)
+			}
+		},
+		add(item) {
+			console.log(item)
+			if(item.productInfo.stock > item.cart_num) {
+				item.cart_num++
+				this.newNumberChange(item)
+			}else {
+				return 
+			}
+		},
+		//请求数据
+		async loadData() {
+			let obj = this;
+			getCartList({})
+				.then(function(e) {
+					// 获取当前购物车物品增加数量
+					let nub = obj.cartList.length;
+					// 获取之前对象数组
+					let aArray = obj.cartList.reverse();
+					// 获取返回数据对象数组
+					let bArray = e.data.valid.reverse();
+					obj.cartList = bArray
+						.map((item, ind) => {
+							// 设置返回数据默认为勾选状态
+							item.checked = true;
+							// 获取相同数组之前对象的数据
+							let carlist = aArray[ind];
+							// 判断之前是否已经加载完毕
+							if (carlist && carlist.loaded == 'loaded') {
+								item.loaded = 'loaded';
+							}
+							return item;
+						})
+						.reverse();
+					obj.calcTotal(); //计算总价
+				})
+				.catch(function(e) {
+					console.log(e);
+				});
+		},
+		//监听image加载完成
+		onImageLoad(key, index) {
+			// 修改载入完成后图片class样式
+			this.$set(this[key][index], 'loaded', 'loaded');
+		},
+		//监听image加载失败
+		onImageError(key, index) {
+			this[key][index].image = '/static/error/errorImage.jpg';
+		},
+		// 跳转到登录页
+		navToLogin() {
+			// 保存地址
+			saveUrl();
+			// 登录拦截
+			interceptor();
+		},
+		//选中状态处理
+		check(type, index) {
+			if (type === 'item') {
+				this.cartList[index].checked = !this.cartList[index].checked;
+			} else {
+				const checked = !this.allChecked;
+				const list = this.cartList;
+				list.forEach(item => {
+					item.checked = checked;
+				});
+				this.allChecked = checked;
+			}
+			this.calcTotal(type);
+		},
+		//数量
+		numberChange(data) {
+			let arr = this.cartList[data.index];
+			arr.cart_num = data.number;
+			getCartNum({ id: arr.id, number: data.number })
+				.then(e => {
+					console.log(e);
+				})
+				.catch(function(e) {
+					console.log(e);
+				});
+			this.calcTotal();
+		},
+		newNumberChange(item) {
+			getCartNum({ id: item.id, number: item.cart_num })
+				.then(e => {
+					console.log(e);
+				})
+				.catch(function(e) {
+					console.log(e);
+				});
+			this.calcTotal();
+		},
+		//删除
+		deleteCartItem(index) {
+			let list = this.cartList;
+			let row = list[index];
+			let id = row.id;
+			cartDel({
+				ids: id
+			});
+			this.cartList.splice(index, 1);
+			uni.hideLoading();
+			this.calcTotal();
+		},
+		//清空
+		clearCart() {
+			uni.showModal({
+				content: '清空购物车?',
+				success: e => {
+					if (e.confirm) {
+						let st = this.cartList.map(e => {
+							return e.id;
+						});
+						cartDel({
+							ids: st.join(',')
+						}).then(e => {
+							console.log(e);
+						});
+						this.cartList = [];
+					}
+				}
+			});
+		},
+		//计算总价
+		calcTotal() {
+			let list = this.cartList;
+			if (list.length === 0) {
+				this.empty = true;
+				return;
+			}
+			let total = 0;
+			let checked = true;
+			list.forEach(item => {
+				if (item.checked === true) {
+					total += item.productInfo.price * item.cart_num;
+				} else if (checked === true) {
+					checked = false;
+				}
+			});
+			this.allChecked = checked;
+			this.total = Number(total.toFixed(2));
+		},
+		//创建订单
+		createOrder() {
+			let list = this.cartList;
+			let goodsData = [];
+			list.forEach(item => {
+				if (item.checked) {
+					goodsData.push(item.id);
+				}
+			});
+
+			uni.navigateTo({
+				url: '/pages/order/createOrder?id=' + goodsData.join(',')
+			});
+		}
+	}
+};
+</script>
+
+<style lang="scss">
+.container {
+	padding-bottom: 134rpx;
+	background-color: $page-color-base;
+	/* 空白页 */
+	.empty {
+		position: fixed;
+		left: 0;
+		top: 0;
+		width: 100%;
+		height: 100vh;
+		padding-bottom: 100rpx;
+		display: flex;
+		justify-content: center;
+		flex-direction: column;
+		align-items: center;
+		background: #fff;
+		.emptyImg {
+			width: 300rpx;
+			height: 250rpx;
+			margin-bottom: 30rpx;
+		}
+		.empty-tips {
+			display: flex;
+			font-size: $font-sm + 2rpx;
+			color: $font-color-disabled;
+			.navigator {
+				color: $uni-color-primary;
+				margin-left: 16rpx;
+			}
+		}
+	}
+}
+/* 购物车列表项 */
+.cart-item {
+	width: 710rpx;
+	height: 210rpx;
+	background: #FFFFFF;
+	box-shadow: 0px 0px 10rpx 0rpx rgba(0, 0, 0, 0.1);
+	border-radius: 10rpx;
+	margin: 20rpx auto;
+	
+	display: flex;
+	position: relative;
+	padding: 30rpx 26rpx 30rpx 80rpx;
+	.image-wrapper {
+		width: 150rpx;
+		height: 150rpx;
+		flex-shrink: 0;
+		position: relative;
+		image {
+			border-radius: 8rpx;
+		}
+	}
+	.checkbox {
+		position: absolute;
+		top: 0;
+		bottom: 0;
+		left: -65rpx;
+		margin: auto 0;
+		height: 50rpx;
+		z-index: 8;
+		font-size: 44rpx;
+		line-height: 1;
+		padding: 4rpx;
+		color: $font-color-disabled;
+		background: #fff;
+		border-radius: 50px;
+	}
+	.item-right {
+		display: flex;
+		flex-direction: column;
+		flex: 1;
+		overflow: hidden;
+		position: relative;
+		padding-left: 30rpx;
+		.munbox {
+			width: 144rpx;
+			height: 44rpx;
+			position: absolute;
+			bottom: 0;
+			right: 0;
+			input {
+				display: inline-block;
+				text-align: center;
+			}
+			image {
+				flex-shrink: 0;
+				width: 44rpx;
+				height: 44rpx;
+			}
+		}
+		.title,
+		.price {
+			font-size: $font-base + 2rpx;
+			color: $font-color-dark;
+			height: 40rpx;
+			line-height: 40rpx;
+		}
+		.attr {
+			font-size: $font-sm + 2rpx;
+			color: $font-color-light;
+			height: 50rpx;
+			line-height: 50rpx;
+			
+			font-size: 26rpx;
+			font-family: PingFang SC;
+			font-weight: bold;
+			color: #999999;
+		}
+		.price {
+			// height: 50rpx;
+			// line-height: 50rpx;
+			padding-top: 20rpx;
+			font-size: 34rpx;
+			font-family: PingFang SC;
+			font-weight: bold;
+			color: #FF4C4C;
+		}
+		.step {
+			margin-top: 20rpx;
+		}
+		.title {
+			font-size: 34rpx;
+			font-family: PingFang SC;
+			font-weight: bold;
+			color: #333333;
+		}
+	}
+	.del-btn {
+		padding: 4rpx 10rpx;
+		font-size: 34rpx;
+		height: 50rpx;
+		color: $font-color-light;
+	}
+}
+/* 底部栏 */
+.action-section {
+	/* #ifdef H5 */
+	margin-bottom: 100rpx;
+	/* #endif */
+	position: fixed;
+	left: 30rpx;
+	bottom: 30rpx;
+	z-index: 95;
+	display: flex;
+	align-items: center;
+	width: 690rpx;
+	height: 100rpx;
+	padding: 0 30rpx;
+	background: rgba(255, 255, 255, 0.9);
+	box-shadow: 0 0 20rpx 0 rgba(0, 0, 0, 0.5);
+	border-radius: 16rpx;
+	.checkbox {
+		height: 52rpx;
+		position: relative;
+		.icon-checked-box {
+			border-radius: 50rpx;
+			background-color: #ffffff;
+			width: 52rpx;
+			height: 100%;
+			position: relative;
+			z-index: 5;
+			font-size: 53rpx;
+			line-height: 1;
+			color: $font-color-light;
+		}
+		.icon-checked {
+			color: $base-color;
+		}
+	}
+	.clear-btn {
+		position: absolute;
+		left: 26rpx;
+		top: 0;
+		z-index: 4;
+		width: 0;
+		height: 52rpx;
+		line-height: 52rpx;
+		padding-left: 38rpx;
+		font-size: $font-base;
+		color: #fff;
+		background: $font-color-disabled;
+		border-radius: 0 50px 50px 0;
+		opacity: 0;
+		transition: 0.2s;
+		&.show {
+			opacity: 1;
+			width: 120rpx;
+		}
+	}
+	.total-box {
+		flex: 1;
+		display: flex;
+		flex-direction: column;
+		text-align: right;
+		padding-right: 40rpx;
+		
+		.price {
+			font-size: $font-lg;
+			color: $font-color-dark;
+		}
+		.coupon {
+			font-size: $font-sm;
+			color: $font-color-light;
+			text {
+				color: $font-color-dark;
+			}
+		}
+	}
+	.confirm-btn {
+		padding: 0 38rpx;
+		margin: 0;
+		border-radius: 100px;
+		height: 76rpx;
+		line-height: 76rpx;
+		font-size: $font-base + 2rpx;
+		background: $base-color;
+	}
+}
+/* 复选框选中状态 */
+.action-section .checkbox.checked,
+.cart-item .checkbox.checked {
+	color: $base-color;
+}
+.cart-hand {
+	width: 750rpx;
+	height: 88rpx;
+	background: #FFFFFF;
+	font-size: 30rpx;
+	font-family: PingFang SC;
+	font-weight: bold;
+	color: #333333;
+	line-height: 88rpx;
+	padding-left: 28rpx;
+	padding-right: 26rpx;
+	.hand-tit {
+		text {
+			color: #FF4C4C;
+		}
+	
+	}
+	.hand-btn {
+		width: 164rpx;
+		height: 62rpx;
+		border: 2rpx solid #FF4C4C;
+		border-radius: 31rpx;
+		font-size: 26rpx;
+		font-family: PingFang SC;
+		font-weight: bold;
+		color: #FF4C4C;
+		line-height: 62rpx;
+		text-align: center;
+	}
+}
+</style>

+ 216 - 0
pages/category/category.vue

@@ -0,0 +1,216 @@
+<template>
+	<view class="content">
+		<scroll-view scroll-y class="left-aside">
+			<view v-for="item in flist" :key="item.id" class="f-item b-b" :class="{ active: item.id === currentId }" @click="tabtap(item)">{{ item.cate_name }}</view>
+		</scroll-view>
+		<scroll-view scroll-with-animation scroll-y class="right-aside" @scroll="asideScroll" :scroll-top="tabScrollTop">
+			<view v-for="item in flist" :key="item.id" class="s-list" :id="'main-' + item.id">
+				<text class="s-item">{{ item.cate_name }}</text>
+				<view class="t-list ">
+					<view @click="navToList(item.id, titem.id)" class="t-item" v-for="titem in item.children" :key="titem.id">
+						<image :src="titem.pic"></image>
+						<text>{{ titem.cate_name }}</text>
+					</view>
+				</view>
+			</view>
+		</scroll-view>
+	</view>
+</template>
+
+<script>
+// import { getCategoryList } from '@/api/product.js';
+export default {
+	data() {
+		return {
+			sizeCalcState: false,
+			tabScrollTop: 0,
+			currentId: 9,
+			flist: [],
+		};
+	},
+	onLoad() {
+		this.loadData();
+	},
+	// 监听导航栏输入框点击事件
+	onNavigationBarSearchInputClicked(e) {
+		uni.navigateTo({
+			url: '/pages/product/search'
+		});
+	},
+	methods: {
+		// 载入数据
+		async loadData() {
+			let obj = this;
+			getCategoryList({})
+				.then(({ data }) => {
+					obj.flist = data.map(function(s) {
+						return s;
+					});
+				})
+				.catch(err => {
+					console.log(err);
+				});
+		},
+		//一级分类点击
+		tabtap(item) {
+			console.log(item);
+			// 判断有没有初始化页面高度对象数据
+			if (!this.sizeCalcState) {
+				this.calcSize();
+			}
+			// 获取当前点击的id
+			this.currentId = item.id;
+			console.log(item.top);
+			this.tabScrollTop = item.top;
+			console.log(this.tabScrollTop);
+		},
+		//右侧栏滚动
+		asideScroll(e) {
+			// 判断有没有初始化页面高度对象数据
+			if (!this.sizeCalcState) {
+				this.calcSize();
+			}
+			let scrollTop = e.detail.scrollTop;
+			let box = 0; //列表包裹框高度初始化
+			let bottom = 10; //距离页面底部多少像素左侧列表切换到最后一个一级分类
+			// 查询当前页面对象
+			let view = uni.createSelectorQuery().select('.content');
+			view.fields(
+				{
+					id: true,
+					dataset: true,
+					rect: true,
+					size: true,
+					scrollOffset: true
+				},
+				function(e) {
+					// 保存包裹框高度
+					box = e.height;
+				}
+			).exec();
+			// 获取所有距离顶部大于滚轮距离页面高度的所有分类
+			let tabs = this.flist.filter(item =>( item.top-10) <= scrollTop).reverse();
+			if (tabs.length > 0) {
+				// 判断是否已经到达滚轮底部
+				if (box + scrollTop + bottom >= e.detail.scrollHeight) {
+					this.currentId = this.flist[this.flist.length - 1].id;
+				} else {
+					this.currentId = tabs[0].id;
+				}
+			}
+		},
+		//计算右侧栏每个tab的高度等信息
+		calcSize() {
+			let h = 0;
+			this.flist.forEach(item => {
+				let view = uni.createSelectorQuery().select('#main-' + item.id);
+				view.fields(
+					{
+						size: true
+					},
+					data => {
+						item.top = h;
+						h += data.height;
+						item.bottom = h;
+					}
+				).exec();
+			});
+			this.sizeCalcState = true;
+		},
+		navToList(sid, tid) {
+			// 点击导航跳转到详细页面
+			uni.navigateTo({
+				url: '/pages/product/list?fid='+this.currentId+'&sid='+sid+'&tid='+tid
+			});
+		}
+	}
+};
+</script>
+
+<style lang="scss">
+page,
+.content {
+	height: 100%;
+	background-color: #f8f8f8;
+}
+
+.content {
+	display: flex;
+}
+.left-aside {
+	flex-shrink: 0;
+	width: 200rpx;
+	height: 100%;
+	background-color: #fff;
+}
+.f-item {
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	width: 100%;
+	height: 100rpx;
+	font-size: 28rpx;
+	color: $font-color-base;
+	position: relative;
+	&.active {
+		color: $base-color;
+		background: #f8f8f8;
+		&:before {
+			content: '';
+			position: absolute;
+			left: 0;
+			top: 50%;
+			transform: translateY(-50%);
+			height: 36rpx;
+			width: 8rpx;
+			background-color: $base-color;
+			border-radius: 0 4px 4px 0;
+			opacity: 0.8;
+		}
+	}
+}
+
+.right-aside {
+	flex: 1;
+	overflow: hidden;
+	padding-left: 20rpx;
+	padding-right: 20rpx;
+}
+.s-item {
+	display: flex;
+	align-items: center;
+	height: 70rpx;
+	padding-top: 8rpx;
+	font-size: 28rpx;
+	color: $font-color-dark;
+}
+.t-list {
+	display: flex;
+	flex-wrap: wrap;
+	border-radius: 15rpx;
+	width: 100%;
+	background: #fff;
+	padding-top: 12rpx;
+	&:after {
+		content: '';
+		flex: 99;
+		height: 0;
+	}
+}
+.t-item {
+	flex-shrink: 0;
+	display: flex;
+	justify-content: center;
+	align-items: center;
+	flex-direction: column;
+	width: 171rpx;
+	font-size: 26rpx;
+	color: #666;
+	padding-bottom: 20rpx;
+
+	image {
+		width: 140rpx;
+		height: 140rpx;
+	}
+}
+</style>

+ 1 - 1
pages/index/index.vue

@@ -1251,6 +1251,6 @@ page {
 <script>
 </script>
 
-<style>
+<style lang="scss">
 </style>
 >>>>>>> 1062124a14605e6952753b8ba2e3f401c676404f

+ 8 - 0
pages/story/story.vue

@@ -0,0 +1,8 @@
+<template>
+</template>
+
+<script>
+</script>
+
+<style>
+</style>

+ 8 - 0
pages/user/user.vue

@@ -0,0 +1,8 @@
+<template>
+</template>
+
+<script>
+</script>
+
+<style>
+</style>

BIN
static/img/add.png


BIN
static/img/reduce.png