V u e 初 始 项 目 结 构 Vue初始项目结构 Vue初始项目结构
一 assets
二 components
Login.vue
<template>
<div class="login-container">
<el-row>
<el-col :span="4" :offset="10">
<h1 class='page-title'>管理系统</h1>
<el-form ref="loginForm" :model="loginForm" label-width="80px" class='login-form' :rules="rules">
<el-form-item label="手机" prop="username">
<el-input v-model="loginForm.username"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="loginForm.password" type="password"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">登录</el-button>
</el-form-item>
</el-form>
</el-col>
</el-row>
</div>
</template>
<script>
import {Button,Row,Col,Form,Input,FormItem} from "element-ui"
// import axios from "axios"
export default {
name: 'Login',
data(){
let validateTel = (rule, value, callback) => {
if(!value.match(/1[3456789]\d{9}/)){
callback(new Error("请输入正确的手机号码!"))
}else{
callback()
}
}
return {
loginForm: {
username: "",
password: ""
},
rules: {
username: [
{required: true,message: "请输入手机号码!",trigger: "blur"},
{validator: validateTel,trigger: "blur"}
],
password: [
{required: true,message: "请输入密码!",trigger: "blur"},
{min: 6, max: 20,message: "密码字符应该在6-20之间!",trigger: "blur"},
]
}
}
},
components: {
[Button.name]: Button,
[Row.name]: Row,
[Col.name]: Col,
[Form.name]: Form,
[Input.name]: Input,
[FormItem.name]: FormItem
},
methods: {
onSubmit(){
this.$refs['loginForm'].validate(valid => {
if(!valid){
console.log("验证失败!")
return
}
const params = {
username: this.loginForm.username,
password: this.loginForm.password
}
this.$loading.show()
this.$http.login(params).then(res => {
const data = res.data;
const token = data.token;
const user = data.user;
this.$auth.setUserToken(user,token)
this.$router.push("/")
this.$loading.hide()
}).catch(err => {
console.log(err);
this.$loading.hide()
})
})
}
}
}
</script>
<style lang="scss">
body{
background-color: #eee;
}
.login-container{
padding-top: 80px;
.page-title{
text-align: center;
}
.login-form{
padding-top: 40px;
}
}
</style>
Frame.vue
<template>
<div class="frame">
<el-container class="frame-container">
<el-header class="header">
<a href="/" class='brand'><strong>知了</strong>商户平台</a>
<div class="header-content">
<div class="greet">欢迎,{{$auth.user.username}}!</div>
<div class="signout" @click="onLogout">退出登录</div>
</div>
</el-header>
<el-container>
<el-aside width="200px" class="aside">
<el-row class="menu-row">
<el-col :span="24">
<el-menu
default-active="/"
background-color="#545c64"
class="el-menu"
active-text-color="#fff"
text-color="#ddd"
:router="true"
>
<el-menu-item index="/">
<i class="el-icon-s-home"></i>
<span slot="title">首页</span>
</el-menu-item>
<el-menu-item index="/merchant">
<i class="el-icon-menu"></i>
<span slot="title">商家</span>
</el-menu-item>
<el-menu-item index="/user">
<i class="el-icon-user-solid"></i>
<span slot="title">用户</span>
</el-menu-item>
<el-menu-item index="/order">
<i class="el-icon-s-order"></i>
<span slot="title">订单</span>
</el-menu-item>
</el-menu>
</el-col>
</el-row>
</el-aside>
<el-container>
<el-main class="main">
<router-view></router-view>
</el-main>
<el-footer class="footer">这是Footer</el-footer>
</el-container>
</el-container>
</el-container>
</div>
</template>
<script type="text/ecmascript-6">
import {Container,Header,Aside,Main,Footer,Row,Col,Menu,MenuItem} from "element-ui"
export default {
name: "Frame",
data() {
return {}
},
components: {
[Container.name]: Container,
[Header.name]: Header,
[Aside.name]: Aside,
[Main.name]: Main,
[Footer.name]: Footer,
[Row.name]: Row,
[Col.name]: Col,
[Menu.name]: Menu,
[MenuItem.name]: MenuItem
},
methods: {
onLogout(){
// JWToken
this.$auth.clearUserToken()
this.$router.replace("/login")
}
}
}
</script>
<style scoped lang='scss'>
.frame-container{
height: 100vh;
.header{
height: 200px;
background: #00a65a;
display: flex;
.brand{
width: 200px;
margin-left: -20px;
background-color:#008d4c;
font-size: 20px;
color: #fff;
display:flex;
justify-content: center;
align-items: center;
}
.header-content{
flex: 1;
display: flex;
justify-content: space-between;
align-items: center;
margin-left: 20px;
color: #fff;
.signout{
cursor: pointer;
}
}
}
.aside{
background-color: #545c64;
.el-menu{
.is-active{
background-color: #434a50!important;
}
}
}
.main{
// background: salmon;
}
.footer{
background: gray;
}
}
</style>
<style scoped>
.aside >>> .el-menu{
border-right: none;
}
</style>
三 styles
init.css
a,
abbr,
acronym,
address,
applet,
article,
aside,
audio,
b,
big,
blockquote,
body,
canvas,
caption,
center,
cite,
code,
dd,
del,
details,
dfn,
div,
dl,
dt,
em,
embed,
fieldset,
figcaption,
figure,
footer,
form,
h1,
h2,
h3,
h4,
h5,
h6,
header,
hgroup,
html,
i,
iframe,
img,
ins,
kbd,
label,
legend,
li,
mark,
menu,
nav,
object,
ol,
output,
p,
pre,
q,
ruby,
s,
samp,
section,
small,
span,
strike,
strong,
sub,
summary,
sup,
table,
tbody,
td,
tfoot,
th,
thead,
time,
tr,
tt,
u,
ul,
var,
video {
margin: 0;
padding: 0;
border: 0;
font-family: "PingFangSC-Regular", Hiragino Sans GB, Arial, Helvetica, "\5B8B\4F53", sans-serif;
}
四 utils
4.1 auth.js
const USER_KEY = "USER_KEY"
const TOKEN_KEY = "JWT_TOKEN_KEY"
class Auth{
constructor(){
this.token = null
this.user = null
this.token = localStorage.getItem(TOKEN_KEY)
const userJson = localStorage.getItem(USER_KEY)
if(userJson){
this.user = JSON.parse(userJson)
}
}
static getInstance(){
if(!this._instance){
this._instance = new Auth()
}
return this._instance
}
setUserToken(user,token){
this.user = user
this.token = token
localStorage.setItem(USER_KEY,JSON.stringify(user))
localStorage.setItem(TOKEN_KEY,token)
}
clearUserToken(){
this.user = null;
this.token = null;
localStorage.removeItem(USER_KEY)
localStorage.removeItem(TOKEN_KEY)
}
get is_authed(){
if(this.user && this.token){
return true
}else{
return false
}
}
}
export default Auth.getInstance()
保证始终面对的是一个对象
4.2http网络封装
import axios from "axios"
import auth from "./auth"
import router from "../routes"
const BASE_URL = 'http://127.0.0.1:8000'
class Http {
constructor() {
this.http = axios.create({
baseURL: BASE_URL,
timeout: 1000
});
// 请求之前的拦截器,用来设置JWT
this.http.interceptors.request.use(config => {
const token = auth.token
if(token){
config.headers.common.Authorization = "JWT " + token
}
return config
})
// 响应之后的拦截器
this.http.interceptors.response.use(response => {
return response
},err => {
// auth.clearUserToken()
// router.replace("/login")
console.log(err.response)
console.log("==========")
return Promise.reject(err)
})
}
login(params){
const url = "/cms/login"
return this.http.post(url,params)
}
getMerchants(page=1){
const url = "/cms/merchant?page="+page
return this.http.get(url)
}
addMerchant(data){
const url = "/cms/merchant"
return this.http.post(url,data)
}
getMerchant(merchant_id){
const url = "/cms/merchant/" + merchant_id
return this.http.get(url)
}
updateMerchant(merchant_id,data){
const url = "/cms/merchant/" + merchant_id
return this.http.put(url,data)
}
getCategories(merchant_id){
const url = "/cms/category/merchant/"+merchant_id
return this.http.get(url)
}
updateCategory(category_id,data){
const url = "/cms/category/" + category_id
return this.http.put(url,data)
}
addCategory(data){
const url = "/cms/category"
return this.http.post(url,data)
}
deleteCategory(category_id){
const url = "/cms/category/" + category_id
return this.http.delete(url)
}
addGoods(data){
const url = "/cms/goods"
return this.http.post(url,data)
}
}
export default new Http()
4.3 loading.js
import {Loading} from "element-ui"
class MTLoading{
show(text=null){
this.loading = Loading.service({
fullscreen: true,
background: "rgba(0, 0, 0, 0.7)",
spinner: "el-icon-loading",
text: text?text:"正在加载中..."
})
}
hide(){
if(this.loading){
this.loading.close()
}
}
}
export default new MTLoading()
4.4 message.js
import {
Message
} from "element-ui"
class MTMessage {
constructor() {
this.config = {
showClose: true,
duration: 2000
}
}
show() {
Message(JSON.parse(JSON.stringify(this.config)))
}
success(message = "恭喜!操作成功!") {
this.config.type = "success"
this.config.message = message
this.show()
}
info(message = "") {
this.config.type = 'info'
this.config.message = message
this.show()
}
warning(message = "") {
this.config.type = 'warning'
this.config.message = message
this.show()
}
error(message = "") {
this.config.type = 'error'
this.config.message = message
this.show()
}
}
const message = new MTMessage()
export default message
五 main.js
import Vue from 'vue'
import App from './App.vue'
import router from "./routes"
import axios from "axios"
import auth from "./utils/auth"
import http from "./utils/http"
import loading from "./utils/loading"
import message from "./utils/message"
Vue.config.productionTip = false
Vue.prototype.$auth = auth
Vue.prototype.$http = http
Vue.prototype.$loading = loading
Vue.prototype.$message = message
new Vue({
render: h => h(App),
router
}).$mount('#app')
六 routes.js
import VueRouter from "vue-router"
import Vue from "vue"
import Frame from "./components/Frame"
import Login from "./components/Login"
import Index from "./components/Index"
import Merchant from "./components/Merchant"
import Order from "./components/Order"
import User from "./components/User"
import MerchantDetail from "./components/MerchantDetail"
Vue.use(VueRouter)
const router = new VueRouter({
routes: [
{
path: "/",
component: Frame,
children: [
{path: "",component: Index,name:"index"},
{path: "merchant",component: Merchant,name: "merchant"},
{path: "order",component: Order,name:"order"},
{path: "user",component: User,name: "user"},
{path: "merchant/detail",component: MerchantDetail,name: "merchant_detail"},
]
},
{
path: "/login",
component: Login,
name: "login"
}
]
})
export default router