文章底部有个人公众号:热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享? 踩过的坑没必要让别人在再踩,自己复盘也能加深记忆。利己利人、所谓双赢。
一、前言
使用技术栈 SpringBoot + Vue + Mybatis + Mysql
该系统只要稍微修改,就可以作为其它类似的商城系统
具体功能划分如下图所示,这里不在细说。源码已经分享到GitHub:仓库地址:美妆商城系统源码 目前本人 技术有效,如有BUG 或者 好的建议 请提出。我会进一步完善该系统。
二、功能划分
1.1 用户功能
用户功能划分如下
1.2 管理员功能
管理员功能划分如下,同时包含普通用户的所有功能。主要涉及 后台管理。
三、部分页面
1.1 用户部分页面截图
1.2 管理员部分页面截图
四、部分源码
后台java代码
@PostMapping("/login")
public Result<Account> login(@RequestBody Account account, HttpServletRequest request) {
if (StrUtil.isBlank(account.getName()) || StrUtil.isBlank(account.getPassword()) || account.getLevel() == null) {
throw new CustomException(ResultCode.PARAM_LOST_ERROR);
}
Integer level = account.getLevel();
Account login = new Account();
if (1 == level) {
login = adminInfoService.login(account.getName(), account.getPassword());
}
if (3 == level) {
login = userInfoService.login(account.getName(), account.getPassword());
}
request.getSession().setAttribute("user", login);
return Result.success(login);
}
@PostMapping("/register")
public Result<Account> register(@RequestBody Account account) {
Integer level = account.getLevel();
Account login = new Account();
if (1 == level) {
AdminInfo info = new AdminInfo();
BeanUtils.copyProperties(account, info);
info.setAccount(0D);
login = adminInfoService.add(info);
}
if (3 == level) {
UserInfo info = new UserInfo();
BeanUtils.copyProperties(account, info);
info.setAccount(0D);
login = userInfoService.add(info);
}
return Result.success(login);
}
@GetMapping("/logout")
public Result logout(HttpServletRequest request) {
request.getSession().setAttribute("user", null);
return Result.success();
}
页面代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="pragma" content="no-cache"/>
<meta http-equiv="content-type" content="no-cache, must-revalidate"/>
<meta http-equiv="expires" content="Wed, 26 Feb 1997 08:21:57 GMT"/>
<title>购物车信息</title>
<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="css/my.css" rel="stylesheet">
<link href="css/nav.css" rel="stylesheet">
<style>
[v-cloak] {
display: none;
}
td{
vertical-align: middle !important;
}
</style>
</head>
<body style="background-color: #f2dede">
<div id="wrapper" v-cloak>
<!-- 头部开始 -->
<div style="width: 100%; height: 30px; line-height: 30px; background-color: #518657">
<div class="container">
<div class="col-md-6" style="text-align: left">
<a href="/end/page/login.html" target="_blank" style="color: white; margin-right: 20px" >登录</a>
<a href="/end/page/register.html" target="_blank" style="color: white">注册</a>
</div>
<div class="col-md-6" style="color: yellow; text-align: right">
<span v-if="user.name">
欢迎您,{{user.name}}
<a style="color: white" href="javascript:void(0)" @click="logout">退出</a>
<a v-if="isCollect" style="margin-left: 10px" href="collectInfo.html">收藏夹</a>
</span>
</div>
</div>
<hr>
</div>
<div class="container">
<div style="width: 100%; height: 80px;border-bottom: 1px solid #ccc">
<div class="col-md-3" style="height: 80px; display: flex; justify-content: left;align-items: center;
font-size: 30px;">
<a style="color: red;" href="/front/index.html">MakeUp美妆网</a>
</div>
<div class="col-md-9">
<div class="row" style="height: 80px; line-height: 80px">
<ul style="display: flex;">
<li class="nav-item"><a href="index.html">首页</a></li>
<li class="nav-item"><a href="advertiserInfo.html">公告信息</a></li>
<li class="nav-item"><a href="messageInfo.html">在线交流</a></li>
<li class="nav-item"><a href="cartInfo.html" class="nav-item-active">购物车信息</a></li>
<li class="nav-item"><a href="orderInfo.html">订单信息</a></li>
<li class="nav-item"><a href="commentInfo.html">评价信息</a></li>
<li class="nav-item"><a href="javascript:void(0)" @click="personalPage">个人信息</a></li>
<li class="nav-item" v-if="isShow"><a href="/end/page/index.html" target="_blank">进入后台系统</a>
</li>
</ul>
</div>
</div>
</div>
</div>
<!-- 头部结束 -->
<div class="container" style="margin-top: 20px">
<div class="col-md-12">
<h4 style="margin: 10px 0">全部化妆品({{totalCount}})</h4>
<table class="table table-bordered table-hover">
<thead>
<tr style="background-color: #f8eeee">
<th>商品</th>
<th>单价</th>
<th>数量</th>
<th>折扣</th>
<th>小计</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item,index) in cartData" :key="item.id">
<td style="width:230px;">
<div style="display: flex;align-items: center">
<img style="width: 50%; height: 50%" :src=item.imgSrc>
<span style="font-size: 12px; margin-left: 10px">{{item.name}}</span>
</div>
</td>
<td>{{item.price}}</td>
<td>{{item.count}}</td>
<td>{{item.discountDesc}}</td>
<td>{{item.total}}</td>
<td>
<button class="btn btn-danger btn-xs" @click="del(item)">删除</button>
</td>
</tr>
</tbody>
</table>
<div class="layui-row" style="text-align: right">
<div style="margin: 10px 0">应付金额:<span style="color: red; font-weight: bold;margin-left: 10px">¥ {{totalMoney}}</span></div>
<button class="btn btn-info" @click="submitCart()">提交订单</button>
</div>
</div>
</div>
</div>
<script src="js/jquery-1.10.2.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/jquery.metisMenu.js"></script>
<script src="js/vue2.6.11/vue.min.js"></script>
<script src="js/vue2.6.11/axios.js"></script>
<script src="js/my.js"></script>
<script>
new Vue({
el: '#wrapper',
data: {
isCollect: false,
cartData: [],
totalCount: 0,
user: {},
totalMoney: 0,
isShow: false
},
created: function() {
this.loadCartInfo();
},
methods: {
loadCartInfo() {
axios.get('/auth').then(res => {
if (res.data.code === '0') {
this.user = res.data.data;
if (this.user.level !== 3) {
this.isShow = true;
}
axios.get("/cartInfo?userId=" + this.user.id + "&level=" + this.user.level).then(res => {
if (res.data.code === '0') {
let cartData = res.data.data;
cartData.forEach(item => {
this.totalCount += item.count;
item.imgSrc = '/front/img/goods/default.png';
// 获取展示图
if (item.fileIds) {
let fileIds = JSON.parse(item.fileIds);
if (fileIds.length) {
item.imgSrc = '/files/download/' + fileIds[0];
}
}
// 获取小计
item.total = (item.count * item.price * item.discount).toFixed(2);
this.totalMoney += parseFloat(item.total);
// 获取折扣展示
item.discountDesc = item.discount < 1 ? item.discount * 10 + ' 折' : '-'
});
this.cartData = cartData;
} else {
alert(res.data.msg);
}
});
} else {
alert('请先登录');
location.href = '/end/page/login.html';
}
})
},
del(data) {
if (confirm('确定删除订单吗?')) {
axios.delete('/cartInfo/goods/' + this.user.id + '/' + this.user.level + '/' + data.id).then(res => {
if (res.data.code === '0') {
alert('删除成功');
this.loadCartInfo();
}
})
}
},
submitCart() {
if (!this.cartData.length) {
alert('未选择商品');
return;
}
let data = {userId: this.user.id, level: this.user.level, totalPrice: this.totalMoney, goodsList: this.cartData};
axios.post('/orderInfo', data).then(res => {
if (res.data.code === '0') {
location.href = '/front/orderInfo.html'
} else {
alert(res.data.msg);
}
})
},
logout() {
axios.get("/logout").then(res => {
if(res.data.code === '0') {
location.href = '/front/index.html';
} else {
msg('error', res.data.msg);
}
})
}
}
})
</script>
</body>
</html>