5.项目代码
5.1.前端代码
5.1.1.Index组件
注意点:
- 修改图片路径,包括css中背景图片路径。
- style中添加scoped。
- 将静态工程中的 icon.css内容添加到style中。
<template>
<div class="wrapper">
<!-- header部分 -->
<header>
<div class="icon-location-box">
<div class="icon-location"></div>
</div>
<div class="location-text">沈阳市规划大厦<i class="fa fa-caret-down"></i></div>
</header>
<!-- search部分 -->
<!--
搜索框部分(此块与search-fixed-top块宽度高度一致,用于当
search-fixed-top块固定后,挡住下面块不要窜上去)
-->
<div class="search">
<!-- 当滚动条超过上面的定位块时,search-fixed-top块变成固定在顶部。 -->
<div class="search-fixed-top" ref="fixedBox">
<!-- 搜索框部分中间的白框 -->
<div class="search-box">
<i class="fa fa-search"></i>搜索饿了么商家、商品名称
</div>
</div>
</div>
<!-- 点餐分类部分 -->
<ul class="foodtype">
<li @click="toBusinessList(1)">
<img src="../assets/dcfl01.png">
<p>美食</p>
</li>
<li @click="toBusinessList(2)">
<img src="../assets/dcfl02.png">
<p>早餐</p>
</li>
<li @click="toBusinessList(3)">
<img src="../assets/dcfl03.png">
<p>跑腿代购</p>
</li>
<li @click="toBusinessList(4)">
<img src="../assets/dcfl04.png">
<p>汉堡披萨</p>
</li>
<li @click="toBusinessList(5)">
<img src="../assets/dcfl05.png">
<p>甜品饮品</p>
</li>
<li @click="toBusinessList(6)">
<img src="../assets/dcfl06.png">
<p>速食简餐</p>
</li>
<li @click="toBusinessList(7)">
<img src="../assets/dcfl07.png">
<p>地方小吃</p>
</li>
<li @click="toBusinessList(8)">
<img src="../assets/dcfl08.png">
<p>米粉面馆</p>
</li>
<li @click="toBusinessList(9)">
<img src="../assets/dcfl09.png">
<p>包子粥铺</p>
</li>
<li @click="toBusinessList(10)">
<img src="../assets/dcfl10.png">
<p>炸鸡炸串</p>
</li>
</ul>
<!-- 横幅广告部分(注意:此处有背景图片) -->
<div class="banner">
<h3>品质套餐</h3>
<p>搭配齐全吃得好</p>
<a>立即抢购 ></a>
</div>
<!-- 超级会员部分 -->
<div class="supermember">
<div class="left">
<img src="../assets/super_member.png">
<h3>超级会员</h3>
<p>• 每月享超值权益</p>
</div>
<div class="right">
立即开通 >
</div>
</div>
<!-- 推荐商家部分 -->
<div class="recommend">
<div class="recommend-line"></div>
<p>推荐商家</p>
<div class="recommend-line"></div>
</div>
<!-- 推荐方式部分 -->
<ul class="recommendtype">
<li>综合排序<i class="fa fa-caret-down"></i></li>
<li>距离最近</li>
<li>销量最高</li>
<li>筛选<i class="fa fa-filter"></i></li>
</ul>
<!-- 推荐商家列表部分 -->
<ul class="business">
<li>
<img src="../assets/sj01.png">
<div class="business-info">
<div class="business-info-h">
<h3>万家饺子(软件园E18店)</h3>
<div class="business-info-like">•</div>
</div>
<div class="business-info-star">
<div class="business-info-star-left">
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
<p>4.9 月售345单</p>
</div>
<div class="business-info-star-right">
蜂鸟专送
</div>
</div>
<div class="business-info-delivery">
<p>¥15起送 | ¥3配送</p>
<p>3.22km | 30分钟</p>
</div>
<div class="business-info-explain">
<div>各种饺子</div>
</div>
<div class="business-info-promotion">
<div class="business-info-promotion-left">
<div class="business-info-promotion-left-incon">新</div>
<p>饿了么新用户首单立减9元</p>
</div>
<div class="business-info-promotion-right">
<p>2个活动</p>
<i class="fa fa-caret-down"></i>
</div>
</div>
<div class="business-info-promotion">
<div class="business-info-promotion-left">
<div class="business-info-promotion-left-incon" style="background-color: #F1884F;">特</div>
<p>特价商品5元起</p>
</div>
</div>
</div>
</li>
<li>
<img src="../assets/sj02.png">
<div class="business-info">
<div class="business-info-h">
<h3>小锅饭豆腐馆(全运店)</h3>
<div class="business-info-like">•</div>
</div>
<div class="business-info-star">
<div class="business-info-star-left">
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
<p>4.9 月售345单</p>
</div>
<div class="business-info-star-right">
蜂鸟专送
</div>
</div>
<div class="business-info-delivery">
<p>¥15起送 | ¥3配送</p>
<p>3.22km | 30分钟</p>
</div>
<div class="business-info-explain">
<div>各种饺子</div>
</div>
<div class="business-info-promotion">
<div class="business-info-promotion-left">
<div class="business-info-promotion-left-incon">新</div>
<p>饿了么新用户首单立减9元</p>
</div>
<div class="business-info-promotion-right">
<p>2个活动</p>
<i class="fa fa-caret-down"></i>
</div>
</div>
<div class="business-info-promotion">
<div class="business-info-promotion-left">
<div class="business-info-promotion-left-incon">特</div>
<p>特价商品5元起</p>
</div>
</div>
</div>
</li>
<li>
<img src="../assets/sj03.png">
<div class="business-info">
<div class="business-info-h">
<h3>麦当劳麦乐送(全运路店)</h3>
<div class="business-info-like">•</div>
</div>
<div class="business-info-star">
<div class="business-info-star-left">
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
<p>4.9 月售345单</p>
</div>
<div class="business-info-star-right">
蜂鸟专送
</div>
</div>
<div class="business-info-delivery">
<p>¥15起送 | ¥3配送</p>
<p>3.22km | 30分钟</p>
</div>
<div class="business-info-explain">
<div>各种饺子</div>
</div>
<div class="business-info-promotion">
<div class="business-info-promotion-left">
<div class="business-info-promotion-left-incon">新</div>
<p>饿了么新用户首单立减9元</p>
</div>
<div class="business-info-promotion-right">
<p>2个活动</p>
<i class="fa fa-caret-down"></i>
</div>
</div>
<div class="business-info-promotion">
<div class="business-info-promotion-left">
<div class="business-info-promotion-left-incon">特</div>
<p>特价商品5元起</p>
</div>
</div>
</div>
</li>
<li>
<img src="../assets/sj04.png">
<div class="business-info">
<div class="business-info-h">
<h3>米村拌饭(浑南店)</h3>
<div class="business-info-like">•</div>
</div>
<div class="business-info-star">
<div class="business-info-star-left">
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
<p>4.9 月售345单</p>
</div>
<div class="business-info-star-right">
蜂鸟专送
</div>
</div>
<div class="business-info-delivery">
<p>¥15起送 | ¥3配送</p>
<p>3.22km | 30分钟</p>
</div>
<div class="business-info-explain">
<div>各种饺子</div>
</div>
<div class="business-info-promotion">
<div class="business-info-promotion-left">
<div class="business-info-promotion-left-incon">新</div>
<p>饿了么新用户首单立减9元</p>
</div>
<div class="business-info-promotion-right">
<p>2个活动</p>
<i class="fa fa-caret-down"></i>
</div>
</div>
<div class="business-info-promotion">
<div class="business-info-promotion-left">
<div class="business-info-promotion-left-incon">特</div>
<p>特价商品5元起</p>
</div>
</div>
</div>
</li>
<li>
<img src="../assets/sj05.png">
<div class="business-info">
<div class="business-info-h">
<h3>申记串道(中海康城店)</h3>
<div class="business-info-like">•</div>
</div>
<div class="business-info-star">
<div class="business-info-star-left">
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
<p>4.9 月售345单</p>
</div>
<div class="business-info-star-right">
蜂鸟专送
</div>
</div>
<div class="business-info-delivery">
<p>¥15起送 | ¥3配送</p>
<p>3.22km | 30分钟</p>
</div>
<div class="business-info-explain">
<div>各种饺子</div>
</div>
<div class="business-info-promotion">
<div class="business-info-promotion-left">
<div class="business-info-promotion-left-incon">新</div>
<p>饿了么新用户首单立减9元</p>
</div>
<div class="business-info-promotion-right">
<p>2个活动</p>
<i class="fa fa-caret-down"></i>
</div>
</div>
<div class="business-info-promotion">
<div class="business-info-promotion-left">
<div class="business-info-promotion-left-incon">特</div>
<p>特价商品5元起</p>
</div>
</div>
</div>
</li>
</ul>
<!-- 底部菜单部分 -->
<Footer></Footer>
</div>
</template>
<script>
//导入共通组件
import Footer from '../components/Footer.vue';
export default {
name: 'Index',
mounted() {
document.onscroll = ()=> {
//获取滚动条位置
let s1 = document.documentElement.scrollTop;
let s2 = document.body.scrollTop;
let scroll = s1 == 0 ? s2 : s1;
//获取视口宽度
let width = document.documentElement.clientWidth;
//获取顶部固定块
let search = this.$refs.fixedBox;
//判断滚动条超过视口宽度的12%时,搜索块变固定定位
if (scroll > width * 0.12) {
search.style.position = 'fixed';
search.style.left = '0';
search.style.top = '0';
} else {
search.style.position = 'static';
}
}
},
destroyed() {
//当切换到其他组件时,就不需要document滚动条事件,所以将此事件去掉
document.onscroll = null;
},
components:{
Footer
},
methods:{
toBusinessList(orderTypeId){
this.$router.push({path:'/businessList',query:{orderTypeId:orderTypeId}});
}
}
}
</script>
<style scoped>
/****************** 总容器 ******************/
.wrapper {
width: 100%;
height: 100%;
}
/****************** header ******************/
.wrapper header {
width: 100%;
height: 12vw;
background-color: #0097FF;
display: flex;
align-items: center;
}
.wrapper header .icon-location-box {
width: 3.5vw;
height: 3.5vw;
margin: 0 1vw 0 3vw;
}
.wrapper header .location-text {
font-size: 4.5vw;
font-weight: 700;
color: #fff;
}
.wrapper header .location-text .fa-caret-down {
margin-left: 1vw;
}
/****************** search ******************/
.wrapper .search {
width: 100%;
height: 13vw;
}
.wrapper .search .search-fixed-top {
width: 100%;
height: 13vw;
background-color: #0097FF;
display: flex;
justify-content: center;
align-items: center;
}
.wrapper .search .search-fixed-top .search-box {
width: 90%;
height: 9vw;
background-color: #fff;
border-radius: 2px;
display: flex;
justify-content: center;
align-items: center;
font-size: 3.5vw;
color: #AEAEAE;
font-family: "宋体";
/*此样式是让文本选中状态无效*/
user-select: none;
}
.wrapper .search .search-fixed-top .search-box .fa-search {
margin-right: 1vw;
}
/****************** 点餐分类部分 ******************/
.wrapper .foodtype {
width: 100%;
height: 48vw;
display: flex;
flex-wrap: wrap;
justify-content: space-around;
/*要使用align-content。10个子元素将自动换行为两行,而且两行作为一个整体垂直居中*/
align-content: center;
}
.wrapper .foodtype li {
/*一共10个子元素,通过计算,子元素宽度在16.7 ~ 20 之间,才能保证换两行*/
width: 18vw;
height: 20vw;
display: flex;
/*弹性盒子主轴方向设为column,然后仍然是垂直水平方向居中*/
flex-direction: column;
justify-content: center;
align-items: center;
user-select: none;
cursor: pointer;
}
.wrapper .foodtype li img {
width: 12vw;
/*视频讲解时高度设置为12vw,实际上设置为10.3vw更佳*/
height: 10.3vw;
}
.wrapper .foodtype li p {
font-size: 3.2vw;
color: #666;
}
/****************** 横幅广告部分 ******************/
.wrapper .banner {
/**
* 设置容器宽度95%,然后水平居中,这样两边留白;
* 这里不能用padding,因为背景图片也会覆盖padding
*/
width: 95%;
margin: 0 auto;
height: 29vw;
/*此三个样式组合,可以保证背景图片充满整个容器*/
background-image: url(../assets/index_banner.png);
background-repeat: no-repeat;
background-size: cover;
box-sizing: border-box;
padding: 2vw 6vw;
}
.wrapper .banner h3 {
font-size: 4.2vw;
margin-bottom: 1.2vw;
}
.wrapper .banner p {
font-size: 3.4vw;
color: #666;
margin-bottom: 2.4vw;
}
.wrapper .banner a {
font-size: 3vw;
color: #C79060;
font-weight: 700;
}
/****************** 超级会员部分 ******************/
.wrapper .supermember {
/*这里也设置容器宽度95%,不能用padding,因为背景色也会充满padding*/
width: 95%;
margin: 0 auto;
height: 11.5vw;
background-color: #FEEDC1;
margin-top: 1.3vw;
border-radius: 2px;
color: #644F1B;
display: flex;
justify-content: space-between;
align-items: center;
}
.wrapper .supermember .left {
display: flex;
align-items: center;
margin-left: 4vw;
user-select: none;
}
.wrapper .supermember .left img {
width: 6vw;
height: 6vw;
margin-right: 2vw;
}
.wrapper .supermember .left h3 {
font-size: 4vw;
margin-right: 2vw;
}
.wrapper .supermember .left p {
font-size: 3vw;
}
.wrapper .supermember .right {
font-size: 3vw;
margin-right: 4vw;
cursor: pointer;
}
/****************** 推荐商家部分 ******************/
.wrapper .recommend {
width: 100%;
height: 14vw;
display: flex;
justify-content: center;
align-items: center;
}
.wrapper .recommend .recommend-line {
width: 6vw;
height: 0.2vw;
background-color: #888;
}
.wrapper .recommend p {
font-size: 4vw;
margin: 0 4vw;
}
/****************** 推荐方式部分 ******************/
.wrapper .recommendtype {
width: 100%;
height: 5vw;
margin-bottom: 5vw;
display: flex;
justify-content: space-around;
align-items: center;
}
.wrapper .recommendtype li {
font-size: 3.5vw;
color: #555;
}
/****************** 推荐商家列表部分 ******************/
.wrapper .business {
width: 100%;
margin-bottom: 14vw;
}
.wrapper .business li {
width: 100%;
box-sizing: border-box;
padding: 2.5vw;
user-select: none;
border-bottom: solid 1px #DDD;
display: flex;
}
.wrapper .business li img {
width: 18vw;
height: 18vw;
}
.wrapper .business li .business-info {
width: 100%;
box-sizing: border-box;
padding-left: 3vw;
}
.wrapper .business li .business-info .business-info-h {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2vw;
}
.wrapper .business li .business-info .business-info-h h3 {
font-size: 4vw;
color: #333;
}
.wrapper .business li .business-info .business-info-h .business-info-like {
width: 1.6vw;
height: 3.4vw;
background-color: #666;
color: #fff;
font-size: 4vw;
margin-right: 4vw;
display: flex;
justify-content: center;
align-items: center;
}
.wrapper .business li .business-info .business-info-star {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2vw;
font-size: 3.1vw;
}
.wrapper .business li .business-info .business-info-star .business-info-star-left {
display: flex;
align-items: center;
}
.wrapper .business li .business-info .business-info-star .business-info-star-left .fa-star {
color: #FEC80E;
margin-right: 0.5vw;
}
.wrapper .business li .business-info .business-info-star .business-info-star-left p {
color: #666;
margin-left: 1vw;
}
.wrapper .business li .business-info .business-info-star .business-info-star-right {
background-color: #0097FF;
color: #fff;
font-size: 2.4vw;
border-radius: 2px;
padding: 0 0.6vw;
}
.wrapper .business li .business-info .business-info-delivery {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2vw;
color: #666;
font-size: 3.1vw;
}
.wrapper .business li .business-info .business-info-explain {
display: flex;
align-items: center;
margin-bottom: 3vw;
}
.wrapper .business li .business-info .business-info-explain div {
border: solid 1px #DDD;
font-size: 2.8vw;
color: #666;
border-radius: 3px;
padding: 0 0.1vw;
}
.wrapper .business li .business-info .business-info-promotion {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.8vw;
}
.wrapper .business li .business-info .business-info-promotion .business-info-promotion-left {
display: flex;
align-items: center;
}
.wrapper .business li .business-info .business-info-promotion .business-info-promotion-left .business-info-promotion-left-incon {
width: 4vw;
height: 4vw;
background-color: #70BC46;
border-radius: 3px;
font-size: 3vw;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
}
.wrapper .business li .business-info .business-info-promotion .business-info-promotion-left p {
color: #666;
font-size: 3vw;
margin-left: 2vw;
}
.wrapper .business li .business-info .business-info-promotion .business-info-promotion-right {
display: flex;
align-items: center;
font-size: 2.5vw;
color: #999;
}
.wrapper .business li .business-info .business-info-promotion .business-info-promotion-right p {
margin-right: 2vw;
}
</style>
5.1.2.BusinessList组件
<template>
<div class="wrapper">
<!-- header部分 -->
<header>
<p>商家列表</p>
</header>
<!-- 商家列表部分 -->
<ul class="business">
<li v-for="item in businessArr" @click="toBusinessInfo(item.businessId)">
<div class="business-img">
<img :src="item.businessImg">
<div class="business-img-quantity" v-show="item.quantity>0">{{item.quantity}}</div>
</div>
<div class="business-info">
<h3>{{item.businessName}}</h3>
<p>¥{{item.starPrice}}起送 | ¥{{item.deliveryPrice}}配送</p>
<p>{{item.businessExplain}}</p>
</div>
</li>
</ul>
<!-- 底部菜单部分 -->
<Footer></Footer>
</div>
</template>
<script>
import Footer from '../components/Footer.vue';
export default{
name:'BusinessList',
data(){
return {
orderTypeId: this.$route.query.orderTypeId,
businessArr:[],
user:{}
}
},
created() {
this.user = this.$getSessionStorage('user');
//根据orderTypeId查询商家信息
this.$axios.post('BusinessController/listBusinessByOrderTypeId',this.$qs.stringify({
orderTypeId:this.orderTypeId
})).then(response=>{
this.businessArr = response.data;
//判断是否登录
if(this.user!=null){
this.listCart();
}
}).catch(error=>{
console.error(error);
});
},
components:{
Footer
},
methods:{
listCart(){
this.$axios.post('CartController/listCart',this.$qs.stringify({
userId:this.user.userId
})).then(response=>{
let cartArr = response.data;
//遍历所有食品列表
for(let businessItem of this.businessArr){
businessItem.quantity = 0;
for(let cartItem of cartArr){
if(cartItem.businessId==businessItem.businessId){
businessItem.quantity += cartItem.quantity;
}
}
}
this.businessArr.sort();
}).catch(error=>{
console.error(error);
});
},
toBusinessInfo(businessId){
this.$router.push({path:'/businessInfo',query:{businessId:businessId}});
}
}
}
</script>
<style scoped>
/****************** 总容器 ******************/
.wrapper {
width: 100%;
height: 100%;
}
/****************** header部分 ******************/
.wrapper header {
width: 100%;
height: 12vw;
background-color: #0097FF;
color: #fff;
font-size: 4.8vw;
position: fixed;
left: 0;
top: 0;
z-index: 1000;
display: flex;
justify-content: center;
align-items: center;
}
/****************** 商家列表部分 ******************/
.wrapper .business {
width: 100%;
margin-top: 12vw;
margin-bottom: 14vw;
}
.wrapper .business li {
width: 100%;
box-sizing: border-box;
padding: 2.5vw;
border-bottom: solid 1px #DDD;
user-select: none;
cursor: pointer;
display: flex;
align-items: center;
}
.wrapper .business li .business-img {
/*这里设置为相当定位,成为business-img-quantity元素的父元素*/
position: relative;
}
.wrapper .business li .business-img img {
width: 20vw;
height: 20vw;
}
.wrapper .business li .business-img .business-img-quantity {
width: 5vw;
height: 5vw;
background-color: red;
color: #fff;
font-size: 3.6vw;
border-radius: 2.5vw;
display: flex;
justify-content: center;
align-items: center;
/*设置成绝对定位,不占文档流空间*/
position: absolute;
right: -1.5vw;
top: -1.5vw;
}
.wrapper .business li .business-info {
margin-left: 3vw;
}
.wrapper .business li .business-info h3 {
font-size: 3.8vw;
color: #555;
}
.wrapper .business li .business-info p {
font-size: 3vw;
color: #888;
margin-top: 2vw;
}
</style>
5.1.3.BusinessInfo组件
<template>
<div class="wrapper">
<!-- header部分 -->
<header>
<p>商家信息</p>
</header>
<!-- 商家logo部分 -->
<div class="business-logo">
<img :src="business.businessImg">
</div>
<!-- 商家信息部分 -->
<div class="business-info">
<h1>{{business.businessName}}</h1>
<p>¥{{business.starPrice}}起送 ¥{{business.deliveryPrice}}配送</p>
<p>{{business.businessExplain}}</p>
</div>
<!-- 食品列表部分 -->
<ul class="food">
<li v-for="(item,index) in foodArr">
<div class="food-left">
<img :src="item.foodImg">
<div class="food-left-info">
<h3>{{item.foodName}}</h3>
<p>{{item.foodExplain}}</p>
<p>¥{{item.foodPrice}}</p>
</div>
</div>
<div class="food-right">
<div>
<i class="fa fa-minus-circle" @click="minus(index)" v-show="item.quantity!=0"></i>
</div>
<p><span v-show="item.quantity!=0">{{item.quantity}}</span></p>
<div>
<i class="fa fa-plus-circle" @click="add(index)"></i>
</div>
</div>
</li>
</ul>
<!-- 购物车部分 -->
<div class="cart">
<div class="cart-left">
<div class="cart-left-icon" :style="totalQuantity==0?'background-color:#505051;':'background-color:#3190E8;'">
<i class="fa fa-shopping-cart"></i>
<div class="cart-left-icon-quantity" v-show="totalQuantity!=0">{{totalQuantity}}</div>
</div>
<div class="cart-left-info">
<p>¥{{totalPrice}}</p>
<p>另需配送费{{business.deliveryPrice}}元</p>
</div>
</div>
<div class="cart-right">
<!-- 不够起送费 -->
<div class="cart-right-item" v-show="totalSettle<business.starPrice" style="background-color: #535356;cursor: default;">
¥{{business.starPrice}}起送
</div>
<!-- 达到起送费 -->
<div class="cart-right-item" @click="toOrder" v-show="totalSettle>=business.starPrice">
去结算
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'BusinessInfo',
data() {
return {
businessId: this.$route.query.businessId,
business: {},
foodArr: [],
user: {}
}
},
created() {
this.user = this.$getSessionStorage('user');
//根据businessId查询商家信息
this.$axios.post('BusinessController/getBusinessById', this.$qs.stringify({
businessId: this.businessId
})).then(response => {
this.business = response.data;
}).catch(error => {
console.error(error);
});
//根据businessId查询所属食品信息
this.$axios.post('FoodController/listFoodByBusinessId', this.$qs.stringify({
businessId: this.businessId
})).then(response => {
this.foodArr = response.data;
for (let i = 0; i < this.foodArr.length; i++) {
this.foodArr[i].quantity = 0;
}
//如果已登录,那么需要去查询购物车中是否已经选购了某个食品
if (this.user != null) {
this.listCart();
}
}).catch(error => {
console.error(error);
});
},
methods: {
listCart() {
this.$axios.post('CartController/listCart', this.$qs.stringify({
businessId: this.businessId,
userId: this.user.userId
})).then(response => {
let cartArr = response.data;
//遍历所有食品列表
for (let foodItem of this.foodArr) {
foodItem.quantity = 0;
for (let cartItem of cartArr) {
if (cartItem.foodId == foodItem.foodId) {
foodItem.quantity = cartItem.quantity;
}
}
}
this.foodArr.sort();
}).catch(error => {
console.error(error);
});
},
add(index) {
//首先做登录验证
if (this.user == null) {
this.$router.push({
path: '/login'
});
return;
}
if (this.foodArr[index].quantity == 0) {
//做insert
this.savaCart(index);
} else {
//做update
this.updateCart(index, 1);
}
},
minus(index) {
//首先做登录验证
if (this.user == null) {
this.$router.push({
path: '/login'
});
return;
}
if (this.foodArr[index].quantity > 1) {
//做update
this.updateCart(index, -1);
} else {
//做delete
this.removeCart(index);
}
},
savaCart(index) {
this.$axios.post('CartController/saveCart', this.$qs.stringify({
businessId: this.businessId,
userId: this.user.userId,
foodId: this.foodArr[index].foodId
})).then(response => {
if (response.data == 1) {
//此食品数量要更新为1;
this.foodArr[index].quantity = 1;
this.foodArr.sort();
} else {
alert('向购物车中添加食品失败!');
}
}).catch(error => {
console.error(error);
});
},
updateCart(index, num) {
this.$axios.post('CartController/updateCart', this.$qs.stringify({
businessId: this.businessId,
userId: this.user.userId,
foodId: this.foodArr[index].foodId,
quantity: this.foodArr[index].quantity + num
})).then(response => {
if (response.data == 1) {
//此食品数量要更新为1或-1;
this.foodArr[index].quantity += num;
this.foodArr.sort();
} else {
alert('向购物车中更新食品失败!');
}
}).catch(error => {
console.error(error);
});
},
removeCart(index) {
this.$axios.post('CartController/removeCart', this.$qs.stringify({
businessId: this.businessId,
userId: this.user.userId,
foodId: this.foodArr[index].foodId
})).then(response => {
if (response.data == 1) {
//此食品数量要更新为0;视图的减号和数量要消失
this.foodArr[index].quantity = 0;
this.foodArr.sort();
} else {
alert('从购物车中删除食品失败!');
}
}).catch(error => {
console.error(error);
});
},
toOrder() {
this.$router.push({
path: '/orders',
query: {
businessId: this.business.businessId
}
});
}
},
computed: {
//食品总价格
totalPrice() {
let total = 0;
for (let item of this.foodArr) {
total += item.foodPrice * item.quantity;
}
return total;
},
//食品总数量
totalQuantity() {
let quantity = 0;
for (let item of this.foodArr) {
quantity += item.quantity;
}
return quantity;
},
//结算总价格
totalSettle() {
return this.totalPrice + this.business.deliveryPrice;
}
}
}
</script>
<style scoped>
/****************** 总容器 ******************/
.wrapper {
width: 100%;
height: 100%;
}
/****************** header部分 ******************/
.wrapper header {
width: 100%;
height: 12vw;
background-color: #0097FF;
color: #fff;
font-size: 4.8vw;
position: fixed;
left: 0;
top: 0;
z-index: 1000;
display: flex;
justify-content: center;
align-items: center;
}
/****************** 商家logo部分 ******************/
.wrapper .business-logo {
width: 100%;
height: 35vw;
/*使用上外边距避开header部分*/
margin-top: 12vw;
display: flex;
justify-content: center;
align-items: center;
}
.wrapper .business-logo img {
width: 40vw;
height: 30vw;
border-radius: 5px;
}
/****************** 商家信息部分 ******************/
.wrapper .business-info {
width: 100%;
height: 20vw;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.wrapper .business-info h1 {
font-size: 5vw;
}
.wrapper .business-info p {
font-size: 3vw;
color: #666;
margin-top: 1vw;
}
/****************** 食品列表部分 ******************/
.wrapper .food {
width: 100%;
/*使用下外边距避开footer部分*/
margin-bottom: 14vw;
}
.wrapper .food li {
width: 100%;
box-sizing: border-box;
padding: 2.5vw;
user-select: none;
display: flex;
justify-content: space-between;
align-items: center;
}
.wrapper .food li .food-left {
display: flex;
align-items: center;
}
.wrapper .food li .food-left img {
width: 20vw;
height: 20vw;
}
.wrapper .food li .food-left .food-left-info {
margin-left: 3vw;
}
.wrapper .food li .food-left .food-left-info h3 {
font-size: 3.8vw;
color: #555;
}
.wrapper .food li .food-left .food-left-info p {
font-size: 3vw;
color: #888;
margin-top: 2vw;
}
.wrapper .food li .food-right {
width: 16vw;
display: flex;
justify-content: space-between;
align-items: center;
}
.wrapper .food li .food-right .fa-minus-circle {
font-size: 5.5vw;
color: #999;
cursor: pointer;
}
.wrapper .food li .food-right p {
font-size: 3.6vw;
color: #333;
}
.wrapper .food li .food-right .fa-plus-circle {
font-size: 5.5vw;
color: #0097EF;
cursor: pointer;
}
/****************** 购物车部分 ******************/
.wrapper .cart {
width: 100%;
height: 14vw;
position: fixed;
left: 0;
bottom: 0;
display: flex;
}
.wrapper .cart .cart-left {
flex: 2;
background-color: #505051;
display: flex;
}
.wrapper .cart .cart-left .cart-left-icon {
width: 16vw;
height: 16vw;
box-sizing: border-box;
border: solid 1.6vw #444;
border-radius: 8vw;
background-color: #3190E8;
font-size: 7vw;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
margin-top: -4vw;
margin-left: 3vw;
position: relative;
}
.wrapper .cart .cart-left .cart-left-icon-quantity {
width: 5vw;
height: 5vw;
border-radius: 2.5vw;
background-color: red;
color: #fff;
font-size: 3.6vw;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
right: -1.5vw;
top: -1.5vw;
}
.wrapper .cart .cart-left .cart-left-info p:first-child {
font-size: 4.5vw;
color: #fff;
margin-top: 1vw;
}
.wrapper .cart .cart-left .cart-left-info p:last-child {
font-size: 2.8vw;
color: #AAA;
}
.wrapper .cart .cart-right {
flex: 1;
}
/*达到起送费时的样式*/
.wrapper .cart .cart-right .cart-right-item {
width: 100%;
height: 100%;
background-color: #38CA73;
color: #fff;
font-size: 4.5vw;
font-weight: 700;
user-select: none;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
}
/*不够起送费时的样式(只有背景色和鼠标样式的区别)*/
/*
.wrapper .cart .cart-right .cart-right-item{
width: 100%;
height: 100%;
background-color: #535356;
color: #fff;
font-size: 4.5vw;
font-weight: 700;
user-select: none;
display: flex;
justify-content: center;
align-items: center;
}
*/
</style>
5.1.4.Order组件
<template>
<div class="wrapper">
<!-- header部分 -->
<header>
<p>确认订单</p>
</header>
<!-- 订单信息部分 -->
<div class="order-info">
<h5>订单配送至:</h5>
<div class="order-info-address" @click="toUserAddress">
<p>{{deliveryaddress!=null?deliveryaddress.address:'请选择送货地址'}}</p>
<i class="fa fa-angle-right"></i>
</div>
<p>{{user.userName}}{{user.userSex | sexFilter}} {{user.userId}}</p>
</div>
<h3>{{business.businessName}}</h3>
<!-- 订单明细部分 -->
<ul class="order-detailed">
<li v-for="item in cartArr">
<div class="order-detailed-left">
<img :src="item.food.foodImg">
<p>{{item.food.foodName}} x {{item.quantity}}</p>
</div>
<p>¥{{item.food.foodPrice*item.quantity}}</p>
</li>
</ul>
<div class="order-deliveryfee">
<p>配送费</p>
<p>¥{{business.deliveryPrice}}</p>
</div>
<!-- 合计部分 -->
<div class="total">
<div class="total-left">
¥{{totalPrice}}
</div>
<div class="total-right" @click="toPayment">
去支付
</div>
</div>
</div>
</template>
<script>
export default{
name:'Orders',
data(){
return {
businessId:this.$route.query.businessId,
business:{},
user:{},
cartArr:[],
deliveryaddress:{}
}
},
created() {
this.user = this.$getSessionStorage('user');
this.deliveryaddress = this.$getLocalStorage(this.user.userId);
//查询当前商家
this.$axios.post('BusinessController/getBusinessById',this.$qs.stringify({
businessId:this.businessId
})).then(response=>{
this.business = response.data;
}).catch(error=>{
console.error(error);
});
//查询当前用户在购物车中的当前商家食品列表
this.$axios.post('CartController/listCart',this.$qs.stringify({
userId:this.user.userId,
businessId:this.businessId
})).then(response=>{
this.cartArr = response.data;
}).catch(error=>{
console.error(error);
});
},
computed:{
totalPrice(){
let totalPrice = 0;
for(let cartItem of this.cartArr){
totalPrice += cartItem.food.foodPrice*cartItem.quantity;
}
totalPrice += this.business.deliveryPrice;
return totalPrice;
}
},
filters:{
sexFilter(value){
return value==1?'先生':'女士';
}
},
methods:{
toUserAddress(){
this.$router.push({path:'/userAddress',query:{businessId:this.businessId}});
},
toPayment(){
if(this.deliveryaddress==null){
alert('请选择送货地址!');
return;
}
//创建订单
this.$axios.post('OrdersController/createOrders',this.$qs.stringify({
userId:this.user.userId,
businessId:this.businessId,
daId:this.deliveryaddress.daId,
orderTotal:this.totalPrice
})).then(response=>{
let orderId = response.data;
if(orderId>0){
this.$router.push({path:'/payment',query:{orderId:orderId}});
}else{
alert('创建订单失败!');
}
}).catch(error=>{
console.error(error);
});
}
}
}
</script>
<style scoped>
/****************** 总容器 ******************/
.wrapper {
width: 100%;
height: 100%;
}
/****************** header部分 ******************/
.wrapper header {
width: 100%;
height: 12vw;
background-color: #0097FF;
color: #fff;
font-size: 4.8vw;
position: fixed;
left: 0;
top: 0;
z-index: 1000;
display: flex;
justify-content: center;
align-items: center;
}
/****************** 订单信息部分 ******************/
.wrapper .order-info {
/*注意这里,不设置高,靠内容撑开。因为地址有可能折行*/
width: 100%;
margin-top: 12vw;
background-color: #0097EF;
box-sizing: border-box;
padding: 2vw;
color: #fff;
}
.wrapper .order-info h5 {
font-size: 3vw;
font-weight: 300;
}
.wrapper .order-info .order-info-address {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
font-weight: 700;
user-select: none;
cursor: pointer;
margin: 1vw 0;
}
.wrapper .order-info .order-info-address p {
width: 90%;
font-size: 5vw;
}
.wrapper .order-info .order-info-address i {
font-size: 6vw;
}
.wrapper .order-info p {
font-size: 3vw;
}
.wrapper h3 {
box-sizing: border-box;
padding: 3vw;
font-size: 4vw;
color: #666;
border-bottom: solid 1px #DDD;
}
/****************** 订单明细部分 ******************/
.wrapper .order-detailed {
width: 100%;
}
.wrapper .order-detailed li {
width: 100%;
height: 16vw;
box-sizing: border-box;
padding: 3vw;
color: #666;
display: flex;
justify-content: space-between;
align-items: center;
}
.wrapper .order-detailed li .order-detailed-left {
display: flex;
align-items: center;
}
.wrapper .order-detailed li .order-detailed-left img {
width: 10vw;
height: 10vw;
}
.wrapper .order-detailed li .order-detailed-left p {
font-size: 3.5vw;
margin-left: 3vw;
}
.wrapper .order-detailed li p {
font-size: 3.5vw;
}
.wrapper .order-deliveryfee {
width: 100%;
height: 16vw;
box-sizing: border-box;
padding: 3vw;
color: #666;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 3.5vw;
}
/****************** 订单合计部分 ******************/
.wrapper .total {
width: 100%;
height: 14vw;
position: fixed;
left: 0;
bottom: 0;
display: flex;
}
.wrapper .total .total-left {
flex: 2;
background-color: #505051;
color: #fff;
font-size: 4.5vw;
font-weight: 700;
user-select: none;
display: flex;
justify-content: center;
align-items: center;
}
.wrapper .total .total-right {
flex: 1;
background-color: #38CA73;
color: #fff;
font-size: 4.5vw;
font-weight: 700;
user-select: none;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
}
</style>
5.1.5.Payment组件
<template>
<div class="wrapper">
<!-- header部分 -->
<header>
<p>在线支付</p>
</header>
<!-- 订单信息部分 -->
<h3>订单信息:</h3>
<div class="order-info">
<p>
{{orders.business.businessName}}
<i class="fa fa-caret-down" @click="detailetShow"></i>
</p>
<p>¥{{orders.orderTotal}}</p>
</div>
<!-- 订单明细部分 -->
<ul class="order-detailet" v-show="isShowDetailet">
<li v-for="item in orders.list">
<p>{{item.food.foodName}} x {{item.quantity}}</p>
<p>¥{{item.food.foodPrice*item.quantity}}</p>
</li>
<li>
<p>配送费</p>
<p>¥{{orders.business.deliveryPrice}}</p>
</li>
</ul>
<!-- 支付方式部分 -->
<ul class="payment-type">
<li>
<img src="../assets/alipay.png">
<i class="fa fa-check-circle"></i>
</li>
<li>
<img src="../assets/wechat.png">
</li>
</ul>
<div class="payment-button">
<button>确认支付</button>
</div>
<!-- 底部菜单部分 -->
<Footer></Footer>
</div>
</template>
<script>
import Footer from '../components/Footer.vue';
export default {
name: 'Payment',
data(){
return {
orderId:this.$route.query.orderId,
orders:{
business:{}
},
isShowDetailet:false
}
},
created() {
this.$axios.post('OrdersController/getOrdersById',this.$qs.stringify({
orderId:this.orderId
})).then(response=>{
this.orders = response.data;
}).catch(error=>{
console.error(error);
});
},
mounted() {
//这里的代码是实现:一旦路由到在线支付组件,就不能回到订单确认组件。
//先将当前url添加到history对象中
history.pushState(null,null,document.URL);
//popstate事件能够监听history对象的变化
window.onpopstate = () => {
this.$router.push({path:'/index'});
}
},
destroyed() {
window.onpopstate = null;
},
methods:{
detailetShow(){
this.isShowDetailet = !this.isShowDetailet;
}
},
components: {
Footer
}
}
</script>
<style scoped>
/****************** 总容器 ******************/
.wrapper {
width: 100%;
height: 100%;
}
/****************** header部分 ******************/
.wrapper header {
width: 100%;
height: 12vw;
background-color: #0097FF;
color: #fff;
font-size: 4.8vw;
position: fixed;
left: 0;
top: 0;
z-index: 1000;
display: flex;
justify-content: center;
align-items: center;
}
/****************** 订单信息部分 ******************/
.wrapper h3 {
margin-top: 12vw;
box-sizing: border-box;
padding: 4vw 4vw 0;
font-size: 4vw;
font-weight: 300;
color: #999;
}
.wrapper .order-info {
box-sizing: border-box;
padding: 4vw;
font-size: 4vw;
color: #666;
display: flex;
justify-content: space-between;
align-items: center;
}
.wrapper .order-info p:last-child {
color: orangered;
}
/****************** 订单明细部分 ******************/
.wrapper .order-detailet {
width: 100%;
}
.wrapper .order-detailet li {
width: 100%;
box-sizing: border-box;
padding: 1vw 4vw;
display: flex;
justify-content: space-between;
align-items: center;
}
.wrapper .order-detailet li p {
font-size: 3vw;
color: #666;
}
/****************** 支付方式部分 ******************/
.wrapper .payment-type {
width: 100%;
}
.wrapper .payment-type li {
width: 100%;
box-sizing: border-box;
padding: 4vw;
display: flex;
justify-content: space-between;
align-items: center;
}
.wrapper .payment-type li img {
width: 33vw;
height: 8.9vw;
}
.wrapper .payment-type li .fa-check-circle {
font-size: 5vw;
color: #38CA73;
}
.wrapper .payment-button {
width: 100%;
box-sizing: border-box;
padding: 4vw;
}
.wrapper .payment-button button {
width: 100%;
height: 10vw;
border: none;
/*去掉外轮廓线*/
outline: none;
border-radius: 4px;
background-color: #38CA73;
color: #fff;
}
</style>
5.1.6.UserAddress组件
<template>
<div class="wrapper">
<!-- header部分 -->
<header>
<p>地址管理</p>
</header>
<!-- 地址列表部分 -->
<ul class="addresslist">
<li v-for="item in deliveryAddressArr">
<div class="addresslist-left" @click="setDeliveryAddress(item)">
<h3>{{item.contactName}}{{item.contactSex | sexFilter}} {{item.contactTel}}</h3>
<p>{{item.address}}</p>
</div>
<div class="addresslist-right">
<i class="fa fa-edit" @click="editUserAddress(item.daId)"></i>
<i class="fa fa-remove" @click="removeUserAddress(item.daId)"></i>
</div>
</li>
</ul>
<!-- 新增地址部分 -->
<div class="addbtn" @click="toAddUserAddress">
<i class="fa fa-plus-circle"></i>
<p>新增收货地址</p>
</div>
<!-- 底部菜单部分 -->
<Footer></Footer>
</div>
</template>
<script>
import Footer from '../components/Footer.vue';
export default{
name:'UserAddress',
data(){
return {
businessId:this.$route.query.businessId,
user:{},
deliveryAddressArr:[]
}
},
created() {
this.user = this.$getSessionStorage('user');
this.listDeliveryAddressByUserId();
},
components:{
Footer
},
filters:{
sexFilter(value){
return value==1?'先生':'女士';
}
},
methods:{
listDeliveryAddressByUserId(){
//查询送货地址
this.$axios.post('DeliveryAddressController/listDeliveryAddressByUserId',this.$qs.stringify({
userId:this.user.userId
})).then(response=>{
this.deliveryAddressArr = response.data;
}).catch(error=>{
console.error(error);
});
},
setDeliveryAddress(deliveryAddress){
//把用户选择的默认送货地址存储到localStorage中
this.$setLocalStorage(this.user.userId,deliveryAddress);
this.$router.push({path:'/orders',query:{businessId:this.businessId}});
},
toAddUserAddress(){
this.$router.push({path:'/addUserAddress',query:{businessId:this.businessId}});
},
editUserAddress(daId){
this.$router.push({path:'/editUserAddress',query:{businessId:this.businessId,daId:daId}});
},
removeUserAddress(daId){
if(!confirm('确认要删除此送货地址吗?')){
return;
}
this.$axios.post('DeliveryAddressController/removeDeliveryAddress',this.$qs.stringify({
daId:daId
})).then(response=>{
if(response.data>0){
let deliveryAddress = this.$getLocalStorage(this.user.userId);
if(deliveryAddress!=null&&deliveryAddress.daId==daId){
this.$removeLocalStorage(this.user.userId);
}
this.listDeliveryAddressByUserId();
}else{
alert('删除地址失败!');
}
}).catch(error=>{
console.error(error);
});
}
}
}
</script>
<style scoped>
/*************** 总容器 ***************/
.wrapper {
width: 100%;
height: 100%;
background-color: #F5F5F5;
}
/*************** header ***************/
.wrapper header {
width: 100%;
height: 12vw;
background-color: #0097FF;
display: flex;
justify-content: space-around;
align-items: center;
color: #fff;
font-size: 4.8vw;
position: fixed;
left: 0;
top: 0;
/*保证在最上层*/
z-index: 1000;
}
/*************** addresslist ***************/
.wrapper .addresslist {
width: 100%;
margin-top: 12vw;
background-color: #fff;
}
.wrapper .addresslist li {
width: 100%;
box-sizing: border-box;
border-bottom: solid 1px #DDD;
padding: 3vw;
display: flex;
}
.wrapper .addresslist li .addresslist-left {
flex: 5;
/*左边这块区域是可以点击的*/
user-select: none;
cursor: pointer;
}
.wrapper .addresslist li .addresslist-left h3 {
font-size: 4.6vw;
font-weight: 300;
color: #666;
}
.wrapper .addresslist li .addresslist-left p {
font-size: 4vw;
color: #666;
}
.wrapper .addresslist li .addresslist-right {
flex: 1;
font-size: 5.6vw;
color: #999;
cursor: pointer;
display: flex;
justify-content: space-around;
align-items: center;
}
/*************** 新增地址部分 ***************/
.wrapper .addbtn {
width: 100%;
height: 14vw;
border-top: solid 1px #DDD;
border-bottom: solid 1px #DDD;
background-color: #fff;
margin-top: 4vw;
display: flex;
justify-content: center;
align-items: center;
font-size: 4.5vw;
color: #0097FF;
user-select: none;
cursor: pointer;
}
.wrapper .addbtn p {
margin-left: 2vw;
}
</style>
5.1.7.AddUserAddress组件
<template>
<div class="wrapper">
<!-- header部分 -->
<header>
<p>新增送货地址</p>
</header>
<!-- 表单部分 -->
<ul class="form-box">
<li>
<div class="title">
联系人:
</div>
<div class="content">
<input type="text" v-model="deliveryAddress.contactName" placeholder="联系人姓名">
</div>
</li>
<li>
<div class="title">
性别:
</div>
<div class="content" style="font-size: 3vw;">
<input type="radio" v-model="deliveryAddress.contactSex" value="1" style="width:6vw;height:3.2vw;">男
<input type="radio" v-model="deliveryAddress.contactSex" value="0" style="width:6vw;height:3.2vw;">女
</div>
</li>
<li>
<div class="title">
电话:
</div>
<div class="content">
<input type="tel" v-model="deliveryAddress.contactTel" placeholder="电话">
</div>
</li>
<li>
<div class="title">
收货地址:
</div>
<div class="content">
<input type="text" v-model="deliveryAddress.address" placeholder="收货地址">
</div>
</li>
</ul>
<div class="button-add">
<button @click="addUserAddress">保存</button>
</div>
<!-- 底部菜单部分 -->
<Footer></Footer>
</div>
</template>
<script>
import Footer from '../components/Footer.vue';
export default {
name: 'AddUserAddress',
data() {
return {
businessId:this.$route.query.businessId,
user:{},
deliveryAddress:{
contactName:'',
contactSex:1,
contactTel:'',
address:''
}
}
},
created() {
this.user = this.$getSessionStorage('user');
},
components: {
Footer
},
methods: {
addUserAddress(){
if(this.deliveryAddress.contactName==''){
alert('联系人姓名不能为空!');
return;
}
if(this.deliveryAddress.contactTel==''){
alert('联系人电话不能为空!');
return;
}
if(this.deliveryAddress.address==''){
alert('联系人地址不能为空!');
return;
}
this.deliveryAddress.userId = this.user.userId;
this.$axios.post('DeliveryAddressController/saveDeliveryAddress', this.$qs.stringify(
this.deliveryAddress
)).then(response => {
if(response.data>0){
this.$router.push({path:'/userAddress',query:{businessId:this.businessId}});
}else{
alert('新增地址失败!');
}
}).catch(error => {
console.error(error);
});
}
}
}
</script>
<style scoped>
/*************** 总容器 ***************/
.wrapper {
width: 100%;
height: 100%;
}
/*************** header ***************/
.wrapper header {
width: 100%;
height: 12vw;
background-color: #0097FF;
display: flex;
justify-content: space-around;
align-items: center;
color: #fff;
font-size: 4.8vw;
position: fixed;
left: 0;
top: 0;
/*保证在最上层*/
z-index: 1000;
}
/*************** (表单信息) ***************/
.wrapper .form-box {
width: 100%;
margin-top: 12vw;
}
.wrapper .form-box li {
box-sizing: border-box;
padding: 4vw 3vw 0vw 3vw;
display: flex;
}
.wrapper .form-box li .title {
flex: 0 0 18vw;
font-size: 3vw;
font-weight: 700;
color: #666;
}
.wrapper .form-box li .content {
flex: 1;
display: flex;
align-items: center;
}
.wrapper .form-box li .content input {
border: none;
outline: none;
width: 100%;
height: 4vw;
font-size: 3vw;
}
.wrapper .button-add {
box-sizing: border-box;
padding: 4vw 3vw 0vw 3vw;
}
.wrapper .button-add button {
width: 100%;
height: 10vw;
font-size: 3.8vw;
font-weight: 700;
border: none;
outline: none;
border-radius: 4px;
color: #fff;
background-color: #38CA73;
}
</style>
5.1.8.EditUserAddress组件
<template>
<div class="wrapper">
<!-- header部分 -->
<header>
<p>编辑送货地址</p>
</header>
<!-- 表单部分 -->
<ul class="form-box">
<li>
<div class="title">
联系人:
</div>
<div class="content">
<input type="text" v-model="deliveryAddress.contactName" placeholder="联系人姓名">
</div>
</li>
<li>
<div class="title">
性别:
</div>
<div class="content" style="font-size: 3vw;">
<input type="radio" v-model="deliveryAddress.contactSex" value="1" style="width:6vw;height:3.2vw;" checked>男
<input type="radio" v-model="deliveryAddress.contactSex" value="0" style="width:6vw;height:3.2vw;">女
</div>
</li>
<li>
<div class="title">
电话:
</div>
<div class="content">
<input type="tel" v-model="deliveryAddress.contactTel" placeholder="电话">
</div>
</li>
<li>
<div class="title">
收货地址:
</div>
<div class="content">
<input type="text" v-model="deliveryAddress.address" placeholder="收货地址">
</div>
</li>
</ul>
<div class="button-add">
<button @click="editUserAddress">更新</button>
</div>
<!-- 底部菜单部分 -->
<Footer></Footer>
</div>
</template>
<script>
import Footer from '../components/Footer.vue';
export default {
name: 'EditUserAddress',
data() {
return {
businessId: this.$route.query.businessId,
daId: this.$route.query.daId,
user: {},
deliveryAddress: {}
}
},
created() {
this.user = this.$getSessionStorage('user');
this.$axios.post('DeliveryAddressController/getDeliveryAddressById', this.$qs.stringify({
daId:this.daId
})).then(response => {
this.deliveryAddress = response.data;
}).catch(error => {
console.error(error);
});
},
components: {
Footer
},
methods: {
editUserAddress() {
if (this.deliveryAddress.contactName == '') {
alert('联系人姓名不能为空!');
return;
}
if (this.deliveryAddress.contactTel == '') {
alert('联系人电话不能为空!');
return;
}
if (this.deliveryAddress.address == '') {
alert('联系人地址不能为空!');
return;
}
this.$axios.post('DeliveryAddressController/updateDeliveryAddress', this.$qs.stringify(
this.deliveryAddress
)).then(response => {
if (response.data > 0) {
this.$router.push({
path: '/userAddress',
query: {
businessId: this.businessId
}
});
} else {
alert('更新地址失败!');
}
}).catch(error => {
console.error(error);
});
}
}
}
</script>
<style scoped>
/*************** 总容器 ***************/
.wrapper {
width: 100%;
height: 100%;
}
/*************** header ***************/
.wrapper header {
width: 100%;
height: 12vw;
background-color: #0097FF;
display: flex;
justify-content: space-around;
align-items: center;
color: #fff;
font-size: 4.8vw;
position: fixed;
left: 0;
top: 0;
/*保证在最上层*/
z-index: 1000;
}
/*************** (表单信息) ***************/
.wrapper .form-box {
width: 100%;
margin-top: 12vw;
}
.wrapper .form-box li {
box-sizing: border-box;
padding: 4vw 3vw 0vw 3vw;
display: flex;
}
.wrapper .form-box li .title {
flex: 0 0 18vw;
font-size: 3vw;
font-weight: 700;
color: #666;
}
.wrapper .form-box li .content {
flex: 1;
display: flex;
align-items: center;
}
.wrapper .form-box li .content input {
border: none;
outline: none;
width: 100%;
height: 4vw;
font-size: 3vw;
}
.wrapper .button-add {
box-sizing: border-box;
padding: 4vw 3vw 0vw 3vw;
}
.wrapper .button-add button {
width: 100%;
height: 10vw;
font-size: 3.8vw;
font-weight: 700;
border: none;
outline: none;
border-radius: 4px;
color: #fff;
background-color: #38CA73;
}
</style>
5.1.9.OrderList组件
<template>
<div class="wrapper">
<!-- header部分 -->
<header>
<p>我的订单</p>
</header>
<!-- 订单列表部分 -->
<h3>未支付订单信息:</h3>
<ul class="order">
<li v-for="item in orderArr" v-if="item.orderState==0">
<div class="order-info">
<p>
{{item.business.businessName}}
<i class="fa fa-caret-down" @click="detailetShow(item)"></i>
</p>
<div class="order-info-right">
<p>¥{{item.orderTotal}}</p>
<div class="order-info-right-icon">去支付</div>
</div>
</div>
<ul class="order-detailet" v-show="item.isShowDetailet">
<li v-for="odItem in item.list">
<p>{{odItem.food.foodName}} x {{odItem.quantity}}</p>
<p>¥{{odItem.food.foodPrice*odItem.quantity}}</p>
</li>
<li>
<p>配送费</p>
<p>¥{{item.business.deliveryPrice}}</p>
</li>
</ul>
</li>
</ul>
<h3>已支付订单信息:</h3>
<ul class="order">
<li v-for="item in orderArr" v-if="item.orderState==1">
<div class="order-info">
<p>
{{item.business.businessName}}
<i class="fa fa-caret-down" @click="detailetShow(item)"></i>
</p>
<div class="order-info-right">
<p>¥{{item.orderTotal}}</p>
</div>
</div>
<ul class="order-detailet" v-show="item.isShowDetailet">
<li v-for="odItem in item.list">
<p>{{odItem.food.foodName}} x {{odItem.quantity}}</p>
<p>¥{{odItem.food.foodPrice*odItem.quantity}}</p>
</li>
<li>
<p>配送费</p>
<p>¥{{item.business.deliveryPrice}}</p>
</li>
</ul>
</li>
</ul>
<!-- 底部菜单部分 -->
<Footer></Footer>
</div>
</template>
<script>
import Footer from '../components/Footer.vue';
export default{
name:'OrderList',
data(){
return {
orderArr:[],
user:{}
}
},
created() {
this.user = this.$getSessionStorage('user');
this.$axios.post('OrdersController/listOrdersByUserId',this.$qs.stringify({
userId:this.user.userId
})).then(response=>{
let result = response.data;
for(let orders of result){
orders.isShowDetailet = false;
}
this.orderArr = result;
}).catch(error=>{
console.error(error);
});
},
methods:{
detailetShow(orders){
orders.isShowDetailet = !orders.isShowDetailet;
}
},
components:{
Footer
}
}
</script>
<style scoped>
/****************** 总容器 ******************/
.wrapper {
width: 100%;
height: 100%;
}
/****************** header部分 ******************/
.wrapper header {
width: 100%;
height: 12vw;
background-color: #0097FF;
color: #fff;
font-size: 4.8vw;
position: fixed;
left: 0;
top: 0;
z-index: 1000;
display: flex;
justify-content: center;
align-items: center;
}
/****************** 历史订单列表部分 ******************/
.wrapper h3 {
margin-top: 12vw;
box-sizing: border-box;
padding: 4vw;
font-size: 4vw;
font-weight: 300;
color: #999;
}
.wrapper .order {
width: 100%;
}
.wrapper .order li {
width: 100%;
}
.wrapper .order li .order-info {
box-sizing: border-box;
padding: 2vw 4vw;
font-size: 4vw;
color: #666;
display: flex;
justify-content: space-between;
align-items: center;
}
.wrapper .order li .order-info .order-info-right {
display: flex;
}
.wrapper .order li .order-info .order-info-right .order-info-right-icon {
background-color: #f90;
color: #fff;
border-radius: 3px;
margin-left: 2vw;
user-select: none;
cursor: pointer;
}
.wrapper .order li .order-detailet {
width: 100%;
}
.wrapper .order li .order-detailet li {
width: 100%;
box-sizing: border-box;
padding: 1vw 4vw;
color: #666;
font-size: 3vw;
display: flex;
justify-content: space-between;
align-items: center;
}
</style>
5.1.10.Login组件
<template>
<div class="wrapper">
<!-- header部分 -->
<header>
<p>用户登陆</p>
</header>
<!-- 表单部分 -->
<ul class="form-box">
<li>
<div class="title">
手机号码:
</div>
<div class="content">
<input type="text" v-model="userId" placeholder="手机号码">
</div>
</li>
<li>
<div class="title">
密码:
</div>
<div class="content">
<input type="password" v-model="password" placeholder="密码">
</div>
</li>
</ul>
<div class="button-login">
<button @click="login">登陆</button>
</div>
<div class="button-register">
<button @click="register">去注册</button>
</div>
<!-- 底部菜单部分 -->
<Footer></Footer>
</div>
</template>
<script>
import Footer from '../components/Footer.vue';
export default{
name:'Login',
data(){
return {
userId:'',
password:''
}
},
methods:{
login(){
if(this.userId==''){
alert('手机号码不能为空!');
return;
}
if(this.password==''){
alert('密码不能为空!');
return;
}
//登录请求
this.$axios.post('UserController/getUserByIdByPass',this.$qs.stringify({
userId:this.userId,
password:this.password
})).then(response=>{
let user = response.data;
if(user==null){
alert('用户名或密码不正确!');
}else{
//sessionstorage有容量限制,为了防止数据溢出,所以不将userImg数据放入session中
user.userImg = '';
this.$setSessionStorage('user',user);
this.$router.go(-1);
}
}).catch(error=>{
console.error(error);
});
},
register(){
this.$router.push({path:'register'});
}
},
components:{
Footer
}
}
</script>
<style scoped>
/****************** 总容器 ******************/
.wrapper {
width: 100%;
height: 100%;
}
/****************** header部分 ******************/
.wrapper header {
width: 100%;
height: 12vw;
background-color: #0097FF;
color: #fff;
font-size: 4.8vw;
position: fixed;
left: 0;
top: 0;
z-index: 1000;
display: flex;
justify-content: center;
align-items: center;
}
/****************** 表单部分 ******************/
.wrapper .form-box {
width: 100%;
margin-top: 12vw;
}
.wrapper .form-box li {
box-sizing: border-box;
padding: 4vw 3vw 0 3vw;
display: flex;
align-items: center;
}
.wrapper .form-box li .title {
flex: 0 0 18vw;
font-size: 3vw;
font-weight: 700;
color: #666;
}
.wrapper .form-box li .content {
flex: 1;
}
.wrapper .form-box li .content input {
border: none;
outline: none;
width: 100%;
height: 4vw;
font-size: 3vw;
}
.wrapper .button-login {
width: 100%;
box-sizing: border-box;
padding: 4vw 3vw 0 3vw;
}
.wrapper .button-login button {
width: 100%;
height: 10vw;
font-size: 3.8vw;
font-weight: 700;
color: #fff;
background-color: #38CA73;
border-radius: 4px;
border: none;
outline: none;
}
.wrapper .button-register {
width: 100%;
box-sizing: border-box;
padding: 4vw 3vw 0 3vw;
}
.wrapper .button-register button {
width: 100%;
height: 10vw;
font-size: 3.8vw;
font-weight: 700;
/*与上面登陆按钮不同的只有颜色、背景色、边框不同*/
color: #666;
background-color: #EEE;
border: solid 1px #DDD;
border-radius: 4px;
border: none;
outline: none;
}
/****************** 底部菜单部分 ******************/
.wrapper .footer {
width: 100%;
height: 14vw;
border-top: solid 1px #DDD;
background-color: #fff;
position: fixed;
left: 0;
bottom: 0;
display: flex;
justify-content: space-around;
align-items: center;
}
.wrapper .footer li {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #999;
user-select: none;
cursor: pointer;
}
.wrapper .footer li p {
font-size: 2.8vw;
}
.wrapper .footer li i {
font-size: 5vw;
}
</style>
5.1.11.Register组件
<template>
<div class="wrapper">
<!-- header部分 -->
<header>
<p>用户注册</p>
</header>
<!-- 表单部分 -->
<ul class="form-box">
<li>
<div class="title">
手机号码:
</div>
<div class="content">
<input type="text" @blur="checkUserId" v-model="user.userId" placeholder="手机号码">
</div>
</li>
<li>
<div class="title">
密码:
</div>
<div class="content">
<input type="password" v-model="user.password" placeholder="密码">
</div>
</li>
<li>
<div class="title">
确认密码:
</div>
<div class="content">
<input type="password" v-model="confirmPassword" placeholder="确认密码">
</div>
</li>
<li>
<div class="title">
用户名称:
</div>
<div class="content">
<input type="text" v-model="user.userName" placeholder="用户名称">
</div>
</li>
<li>
<div class="title">
性别:
</div>
<div class="content" style="font-size: 3vw;">
<input type="radio" v-model="user.userSex" value="1" style="width:6vw;height: 3.2vw;">男
<input type="radio" v-model="user.userSex" value="0" style="width:6vw;height: 3.2vw;">女
</div>
</li>
</ul>
<div class="button-login">
<button @click="register">注册</button>
</div>
<!-- 底部菜单部分 -->
<Footer></Footer>
</div>
</template>
<script>
import Footer from '../components/Footer.vue';
export default {
name: 'Register',
data() {
return {
user:{
userId:'',
password:'',
userName:'',
userSex:1
},
confirmPassword:''
}
},
methods: {
checkUserId(){
this.$axios.post('UserController/getUserById', this.$qs.stringify({
userId: this.user.userId,
})).then(response => {
if(response.data==1){
this.user.userId = '';
alert('此手机号码已存在!')
}
}).catch(error => {
console.error(error);
});
},
register() {
if (this.user.userId == '') {
alert('手机号码不能为空!');
return;
}
if (this.user.password == '') {
alert('密码不能为空!');
return;
}
if (this.user.password != this.confirmPassword) {
alert('两次输入的密码不一致!');
return;
}
if (this.user.userName == '') {
alert('用户名不能为空!');
return;
}
//注册请求
this.$axios.post('UserController/saveUser', this.$qs.stringify(
this.user
)).then(response => {
if(response.data>0){
alert('注册成功!');
this.$router.go(-1);
}else{
alert('注册失败!');
}
}).catch(error => {
console.error(error);
});
}
},
components: {
Footer
}
}
</script>
<style scoped>
/****************** 总容器 ******************/
.wrapper {
width: 100%;
height: 100%;
}
/****************** header部分 ******************/
.wrapper header {
width: 100%;
height: 12vw;
background-color: #0097FF;
color: #fff;
font-size: 4.8vw;
position: fixed;
left: 0;
top: 0;
z-index: 1000;
display: flex;
justify-content: center;
align-items: center;
}
/****************** 表单部分 ******************/
.wrapper .form-box {
width: 100%;
margin-top: 12vw;
}
.wrapper .form-box li {
box-sizing: border-box;
padding: 4vw 3vw 0 3vw;
display: flex;
align-items: center;
}
.wrapper .form-box li .title {
flex: 0 0 18vw;
font-size: 3vw;
font-weight: 700;
color: #666;
}
.wrapper .form-box li .content {
flex: 1;
}
.wrapper .form-box li .content input {
border: none;
outline: none;
width: 100%;
height: 4vw;
font-size: 3vw;
}
.wrapper .button-login {
width: 100%;
box-sizing: border-box;
padding: 4vw 3vw 0 3vw;
}
.wrapper .button-login button {
width: 100%;
height: 10vw;
font-size: 3.8vw;
font-weight: 700;
color: #fff;
background-color: #38CA73;
border-radius: 4px;
border: none;
outline: none;
}
.wrapper .button-register {
width: 100%;
box-sizing: border-box;
padding: 4vw 3vw 0 3vw;
}
.wrapper .button-register button {
width: 100%;
height: 10vw;
font-size: 3.8vw;
font-weight: 700;
color: #666;
background-color: #EEE;
border-radius: 4px;
border: none;
outline: none;
border: solid 1px #DDD;
}
</style>
5.1.12.Footer共通组件
<template>
<ul class="footer">
<li @click="toIndex">
<i class="fa fa-home"></i>
<p>首页</p>
</li>
<li>
<i class="fa fa-compass"></i>
<p>发现</p>
</li>
<li @click="toOrderList">
<i class="fa fa-file-text-o"></i>
<p>订单</p>
</li>
<li>
<i class="fa fa-user-o"></i>
<p>我的</p>
</li>
</ul>
</template>
<script>
export default{
name:'Footer',
methods:{
toIndex(){
this.$router.push({path:'/index'});
},
toOrderList(){
this.$router.push({path:'/orderList'});
}
}
}
</script>
<style>
.wrapper .footer {
width: 100%;
height: 14vw;
border-top: solid 1px #DDD;
background-color: #fff;
position: fixed;
left: 0;
bottom: 0;
display: flex;
justify-content: space-around;
align-items: center;
}
.wrapper .footer li {
/*li本身的尺寸完全由内容撑起*/
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #999;
user-select: none;
cursor: pointer;
}
.wrapper .footer li p {
font-size: 2.8vw;
}
.wrapper .footer li i {
font-size: 5vw;
}
</style>