文章底部有个人公众号:热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享? 踩过的坑没必要让别人在再踩,自己复盘也能加深记忆。利己利人、所谓双赢。

一、前言
使用技术栈 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>



















