一、Mall项目简介
客户使用的业务服务:PC端前台采用传统html开发,(小程序,移动web,移动app)采用uniapp开发
管理员使用的业务服务:PC端后台管理端采用vue脚手架开发
Mall后台管理系统采用前后端分离的开发模式
前端项目是基于Vue的SPA(单页应用程序)项目
后台功能图
前端技术栈:Vue,Vue-Router,Element-UI,Axios,Echarts
后端技术栈:SSM,Mysql
二、项目初始化
A.安装Vue脚手架
B.通过脚手架创建项目
C.配置路由
D.配置Element-UI:在插件中安装,搜索vue-cli-plugin-element
E.配置Axios:在依赖中安装,搜索axios(运行依赖)
F.初始化git仓库
G.将本地项目托管到github或者码云中
三、代码
登录模块项目结构图
App.vue
<template>
<div id="app">
<!-- 路由占位符 -->
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'app'
}
</script>
<style>
</style>
Login.vue
<template>
<div class="login_container">
<div class="login_box">
<!-- 登录表单区域 -->
<el-form ref="loginFormRef" :model="loginForm" :rules="loginFormRules" label-width="0px" class="login_form">
<h1>Mall后台管理</h1>
<!-- 用户名 -->
<el-form-item prop="username">
<el-input v-model="loginForm.username" prefix-icon="iconfont icon-yonghu"></el-input>
</el-form-item>
<!-- 密码 -->
<el-form-item prop="password">
<el-input v-model="loginForm.password" prefix-icon="iconfont icon-yanjing_bi" type="password"></el-input>
</el-form-item>
<!-- 按钮区域 -->
<el-form-item class="login_btn">
<el-button type="primary" @click="login">登录</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
export default {
data() {
return {
// 登录表单的数据绑定对象
loginForm: {
username: 'beizhen',
password: '123456'
},
// 登录表单的验证规则
loginFormRules: {
// 验证用户名是否合法
username: [{
required: true,
message: '请输入用户名',
trigger: 'blur'
},
{
min: 2,
max: 16,
message: '长度在 2 到 16 个字符',
trigger: 'blur'
}
],
// 验证密码是否合法
password: [{
required: true,
message: '请输入密码',
trigger: 'blur'
},
{
min: 6,
max: 18,
message: '长度在 6 到 18 个字符',
trigger: 'blur'
}
]
}
}
},
methods: {
// 登录前先验证表单输入框的值是否合法
login() {
this.$refs.loginFormRef.validate(async valid =>{
if(!valid) return;
const {data : res} = await this.$http.post("mall/user/login",this.loginForm);
if(res.meta.status !== 200) return this.$message.error(res.meta.msg);
this.$message.success(res.meta.msg);
//将登陆成功之后的token保存到客户端的sessionStorage
window.sessionStorage.setItem("token",res.data.token);
//通过编程式导航跳转到后台主页
this.$router.push("/home");
})
}
}
}
</script>
<style lang="less" scoped="scoped">
.login_container {
background-color: black;
height: 100%;
}
.login_form {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.login_box {
width: 450px;
height: 300px;
background-color: ghostwhite;
border-radius: 2px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.login_btn {
position: absolute;
left: 50%;
transform: translate(-50%);
}
</style>
Home.vue
<template>
<div>
<el-button type="info" @click="logout">退出</el-button>
</div>
</template>
<script>
export default {
methods:{
logout(){
//清空token
window.sessionStorage.clear();
//跳转登陆页
this.$router.push("/login");
}
}
};
</script>
<style lang="less" scoped="scoped">
</style>
全局样式global.css
/* 全局样式表 */
html,
body,
#app{
height: 100%;
margin: 0;
padding: 0;
}
阿里巴巴图标样式iconfont.css
@font-face {font-family: "iconfont";
src: url('//at.alicdn.com/t/font_2282747_nnb35kjm1ii.eot?t=1608803274048'); /* IE9 */
src: url('//at.alicdn.com/t/font_2282747_nnb35kjm1ii.eot?t=1608803274048#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAXMAAsAAAAACygAAAV/AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDdAqITIcSATYCJAMgCxIABCAFhG0HbxuTCSMRtntw0pL95QFP5t6oDESNahCCMrK4GaXNiAB3VXXJ0zVpFMMCcTS1/NZUuM95Hzz1a+Xr3zO7f/HmgEEFAFCxIpJRqTgglzoVYBjKQ4OK/Am/OqiYFGTSORjAH6TLTU4HIAB4+Ha+q39ZF1pJht2Ih7JbQAMdDHe1tvaY7d4hGjIlUhLzmSFSTxqfRaRD7XTmt+bqnkj4qHdHaJ882mIWKJ00e8RgDCZu/fz9Xv1J1Zjnt32XyPvuj45FUwWNRwk0oKi0kW2AE8StY+MYlcxh19MQEJRFBTJTuvXDcpgnCZBVPXE0NhPmVPCE9fkIVwZyosmmzeYisDP4ffmpEwuGmzGf1YtpP45WKjo7S4f+ryrAhxjqLgnwB4KCCsDRvZ2Y3gIetStQQXWwhhEIeNZfVDxDVVVjVapeVPV50/+uMBOwNJoGbVDO0v7hGX4upGDiMNDHdfx4hjqA4pkRDp6ZGiF4Zm2ED89cjTB4Vm6EH8+bwrhAtcd7QCLIAHkQvVlTOVxAxtpfarwkJhuE42PCMZ7/9vi4kRdlB1MBIBSFvHmThpDKJSwEjlASNzUkabepM0CJtJfkljkqCn+TlsPzbQCA5bYQcoAQssKhzSyNA6IFqESzZ84FIO8kcImV5DM33RPIcsB12nLQHFrOa4sfUSIQaSvtqkQIldrnYeEXSZFVc24rJyZ12xJ4d64gXCoCB8C1bXuIfqZPnOjqbL/dzaf6/BZWAQQd3mvBbSUQElLD2xH/mFxSgVA8r2SlyOZIYh71lN5QITBdo6zMX/AZqcyWkAMU4SJjBNZFOzdhINErfaAijwlWXuMzUNxEW+WwM8PvpfjlWzi4l3FoKSe9dAtfhm4ld9njf/LEjYljZs8aEHdpxYwc2QiFu95fMmD6RtSxpPnLlhwu+ppUXG55ZZuZOyw7FvRMaz//6ZhBrsXqJuMvN78CM+y99HjQs7zdvGdjk+iUkM9Injd9yQW5UsmQ2hrJsIK1U103ytmSPaf0anBNbKNY28QcFweZ4K78TyMfU4f1OLkrPFbt4F9v5zcf87TfkjOXnCFLcnIe94OSpqpm3v7m5O+ZkfM3OWbJnLnv5OmH7IT9+7ZFhvUZS6OBg4qT3ka2rGfP2vdPjgRnWE2V1r29eu0OoLMzv1/nz6d809MtBWh+z5KhrhtlzjD5WEHP4qE9l+mGo1ifVdyQ9WlCPfLW3FWXuoR80jHJX6/bd5v0zyU+lIu6MleobJVl1CowMMM7x8qHfrmkt0C35x/x7KeaX9Md8R0vXrLxD4B56YfNtLPCzvh3U5F7Rb8ODQ0d+uVNcmnCJvyHjgEmWhBS2I2nHo1bc1+kqTl40+Tu7/EHnUM5x+Muhn3ywvY+2G/2755BViL4UD2wv4De5oKs/cpD+L8ZGsdrZrfy0xXqmL3Mtg//KI4N23sbGRP1VUf/Z9hwR2/sWlD+vx2keccyoLZ/5nbKZY7mNCM2lPk5Nuqs1f1DaBoQtNbAx52P416X3kTq0SCsxAQMv0xQVgHZoVeAK6QBfKyWEFROx+tD4pmDKIkAUMZ6BMLjPBhRl0B53CI79LvgSuIt+HiiEDQANb9jyG2vUv34xlgJtlCfwDaUlB2Tx3DsN+ocKk47A9k/cm9rMB1N8r0vTMhdnNPv9UxEgWKK8ImehyEQdEwOGxkZkW43HivSN40aioNH3hgrwRaoT4BtKClvfXks/Pw36hwqrphVNf1H7u3ugSkjJhTkL5yoZp3K5H6vZwhuKkDxoykCnziJwWoT0JEPc9jICNOg2e0Y49UULR4N741negcQxHy7lVTaWOf5cTnTv5yq5GzSw7NBz/uYeU9R29sTJW3yTZPpkO/P9pSrtF7edfmtMw4HAwA=') format('woff2'),
url('//at.alicdn.com/t/font_2282747_nnb35kjm1ii.woff?t=1608803274048') format('woff'),
url('//at.alicdn.com/t/font_2282747_nnb35kjm1ii.ttf?t=1608803274048') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
url('//at.alicdn.com/t/font_2282747_nnb35kjm1ii.svg?t=1608803274048#iconfont') format('svg'); /* iOS 4.1- */
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-ok:before {
content: "\e611";
}
.icon-yanjing-zheng:before {
content: "\e621";
}
.icon-yanjing_bi:before {
content: "\e601";
}
.icon-yonghu:before {
content: "\e603";
}
.icon-cuowu:before {
content: "\e770";
}
.icon-ziyuan75:before {
content: "\e617";
}
.icon-xuanze-:before {
content: "\e663";
}
element.js
import Vue from 'vue'
import {
Button,
Form,
FormItem,
Input,
Message
} from 'element-ui'
Vue.use(Button)
Vue.use(Form)
Vue.use(FormItem)
Vue.use(Input)
//全局挂载
Vue.prototype.$message = Message
index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Login from '../components/Login.vue'
import Home from '../components/Home.vue'
Vue.use(VueRouter)
const routes = [
{ path:'/', redirect:'/login' },
{ path:'/login', component:Login },
{ path:'/home', component:Home }
]
const router = new VueRouter({
routes
})
// 挂载路由导航守卫(控制页面访问权限)
router.beforeEach((to,from,next) => {
if(to.path === '/login') return next()
//获取token
const tokenStr = window.sessionStorage.getItem('token');
if(!tokenStr) return next('/login');
next();
})
export default router
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import './plugins/element.js'
// 导入字体图标
import './assets/fonts/iconfont.css'
// 导入全局样式表
import './assets/css/global.css'
import axios from 'axios'
// 配置请求的跟路径
axios.defaults.baseURL = "http://localhost:8080/"
Vue.prototype.$http = axios
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App)
}).$mount('#app')
vue.config.js
module.exports = {
devServer: {
port: 8081,
open: true
}
}