创建项目
此处不做详细描述,请参考:项目创建
添加环境变量
新建.env.development
文件
VUE_APP_BASE_API = http
://localhost:3000
新建 .env.production
文件(根据项目需求,选择性创建)
VUE_APP_BASE_API = https
://api.xxx.xxx
安装基础依赖
yarn add element-ui axios moment
全局过滤器
新增 src/filters/index.js
文件
import moment from "moment";
/**
* "Fri Dec 10 2021 01:01:49 GMT+0800 (China Standard Time)" => "2021年12月10日凌晨1点01分"
* @param {number} num
*/
export function dateFormat(value) {
if (!value) {
return "";
}
moment.locale("zh-cn");
return moment(value).format("LL");
}
/**
* 10000 => "10,000"
* @param {number} num
*/
export function thousandFormat(num) {
const result = (+num || 0).toString().replace(/^-?\d+/g, m => m.replace(/(?=(?!\b)(\d{3})+$)/g, ","));
return result + "元";
}
注册依赖
在 src/main.js
中
.
.
import
ElementUI
from
"element-ui";
import "element-ui/lib/theme-chalk/index.css";
Vue.config.productionTip = false;
Vue.use(ElementUI);
// 注册全局过滤器
import * as filters from "./filters";
Object.keys(filters).forEach((key) => {
Vue.filter(key, filters[key]);
});
.
.
封装 axios
新增 src/utils/request.js
文件
import axios from "axios";
import { MessageBox, Message } from "element-ui";
import store from "@/store";
import { getToken } from "@/utils/auth";
// 创建axios实例
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
// baseURL: "/api", // url = base url + request url
// withCredentials: true, // 当跨域请求时,发送 cookies
timeout: 5000, // 请求超时时间
});
// request拦截器
service.interceptors.request.use(
(config) => {
// do something 在发送请求前
if (store.getters.token) {
// 让每个请求携带token
// ["X-Token"]为自定义key
// 请根据实际情况自行修改
config.headers["token"] = getToken();
}
return config;
},
(error) => {
// do something 当请求错误
console.log(error); // for debug
return Promise.reject(error);
}
);
// respone拦截器
service.interceptors.response.use(
/**
* 如果你想获取 http 信息,例如 headers 或 status
* 请 return response => response
*/
/**
* 下面的注释为通过response自定义code来标示请求状态,当code返回如下情况为权限有问题,登出并返回到登录页
* 如通过xmlhttprequest 状态码标识 逻辑可写在下面error中
*/
(response) => {
const res = response.data;
// 如果返回的自定义code不是20000, 认定为error。
if (res.code !== 20000) {
Message({
message: res.message || "Error",
type: "error",
duration: 5 * 1000,
});
// 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了;
if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
// 重新登录
MessageBox.confirm(
"你已被登出,可以取消继续留在该页面,或者重新登录",
"确定登出",
{
confirmButtonText: "重新登录",
cancelButtonText: "取消",
type: "warning",
}
).then(() => {
store.dispatch("user/resetToken").then(() => {
// 为了重新实例化vue-router对象 避免bug
location.reload();
});
});
}
return Promise.reject(new Error(res.message || "Error"));
} else {
return res;
}
},
(error) => {
console.log("err" + error); // for debug
Message({
message: error.message,
type: "error",
duration: 5 * 1000,
});
return Promise.reject(error);
}
);
export default service;
由于上面 request
拦截器中读取 token
是从 cookie
中读的,所以接下来我们要配置 cookie
。
配置 cookie
1、装包
yarn add js-cookie
新增 src/utils/auth.js
文件
import Cookies from "js-cookie";
// cookie中key的命名
const TokenKey = "Admin-Token";
/**
* 获取cookie中的token
* @returns {*}
*/
export function getToken() {
return Cookies.get(TokenKey);
}
/**
* 设置token到cookie中
* @param token
* @param remember
* @returns {*}
*/
export function setToken(token, remember = false) {
// 记住我
if (remember) {
return Cookies.set(TokenKey, token, { expires: 7 })
}
return Cookies.set(TokenKey, token);
}
/**
* 删除cookie中的token
* @returns {*}
*/
export function removeToken() {
return Cookies.remove(TokenKey);
}
CSS 文件
1、新建 src/styles/common.scss
文件
a {
color: #1f99b0;
text-decoration: none;
}
.clear:after {
display: block;
content: "clear";
height: 0;
clear: both;
overflow: hidden;
visibility: hidden;
}
2、新建 src/styles/element-ui.scss
文件
.el-menu-item.is-active {
color: #1f99b0 !important;
}
.el-switch.is-checked .el-switch__core {
border-color: #1f99b0 !important;
background-color: #1f99b0 !important;
}
.el-button--primary {
color: #fff !important;
background-color: #1f99b0 !important;
border-color: #1f99b0 !important;
}
.el-menu-item:focus, .el-menu-item:hover {
background-color: #e1f0f0 !important;
}
.el-submenu__title:hover {
background-color: #e1f0f0 !important;
}
3、新建 src/styles/layouts.scss
文件
html, body {
height: 100%;
margin: 0;
}
.el-container, .el-aside, .el-aside .el-col, .el-menu {
height: 100%;
}
.el-header, .el-footer {
background-color: #e1f0f0;
color: #333;
height: 60px;
line-height: 60px;
}
.el-header {
.logo {
height: 40px;
margin-top: 10px;
float: left;
}
h1 {
margin: 0 0 0 20px;
font-size: 18px;
font-weight: normal;
float: left;
line-height: 60px;;
}
}
.el-footer {
text-align: center;
}
.el-aside {
background-color: #e1f0f0;
color: #333;
line-height: 200px;
}
.el-main {
color: #333;
overflow: visible;
}
4、新建 src/styles/index.scss
文件
@import './layouts.scss';
@import './common.scss';
@import './element-ui.scss';
后台首页
修改 src/views/Home.vue
文件
<template>
<div class="home">
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>仪表盘</el-breadcrumb-item>
</el-breadcrumb>
<el-divider></el-divider>
<el-card class="box-card">
<div slot="header" class="clearfix">
长乐未央 <br />
是什么意思?
</div>
<div class="info">
汉时,有长乐宫又有未央宫。"长乐未央"四字,常见于汉宫瓦当。
"长乐"的"乐",最早出自周公旦制礼作"乐"的乐。"乐者,天地之和也"《礼记·乐记》,"乐"的本质是"和"。"未央"意为未尽,没有穷尽。最早出自诗经(庭燎.小雅)夜如何其?夜未央,庭燎之光。
"长乐未央"意为永远快乐,没有穷尽。
</div>
</el-card>
</div>
</template>
<script>
export default {
name: "Home"
};
</script>
<style scoped lang="scss">
.info {
font-size: 14px;
}
</style>
布局模板
1、新建 src/components/layouts/Aside.vue
组件
<template>
<el-aside width="200px">
<el-col>
<el-menu
:router="true"
default-active="/"
class="el-menu-vertical-demo"
>
<el-menu-item index="/">
<i class="el-icon-pie-chart"></i>
<span slot="title">仪表盘</span>
</el-menu-item>
<el-submenu index="article_manage">
<template slot="title">
<i class="el-icon-document"></i>
<span>新闻管理</span>
</template>
<el-menu-item index="/articles">新闻</el-menu-item>
<el-menu-item index="/articles/trash">回收站</el-menu-item>
</el-submenu>
<el-menu-item index="/users">
<i class="el-icon-user"></i>
<span slot="title">用户管理</span>
</el-menu-item>
<el-menu-item index="/settings">
<i class="el-icon-setting"></i>
<span slot="title">系统设置</span>
</el-menu-item>
</el-menu>
</el-col>
</el-aside>
</template>
2、修改 src/App.vue
文件
<template>
<el-container>
<el-header>
<img src="https://images.clwy.cn/common/logo.png" alt="长乐未央Logo" class="logo">
<h1>长乐未央后台管理</h1>
</el-header>
<el-container>
<Aside />
<el-container>
<el-main>
<router-view />
</el-main>
<el-footer>Copyright 2013-2022 CLWY Inc. All Rights Reserved.</el-footer>
</el-container>
</el-container>
</el-container>
</template>
<script>
import Aside from "@/components/layouts/Aside";
export default {
components: { Aside }
};
</script>
最后引入 css
1、修改 src/main.js
文件
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import ElementUI from "element-ui";
import "element-ui/lib/theme-chalk/index.css";
import "@/styles/index.scss"; // 引入所有 css
Vue.config.productionTip = false;
Vue.use(ElementUI);
// 注册全局过滤器
import * as filters from "./filters";
Object.keys(filters).forEach((key) => {
Vue.filter(key, filters[key]);
});
new Vue({
router,
store,
render: (h) => h(App)
}).$mount("#app");
2、修改 src/router/index.js
,将路由修改为懒加载模式
import Vue from "vue";
import VueRouter from "vue-router";
Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "Home",
component: () => import("../views/Home.vue")
}
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes
});
export default router;
最终后台首页效果图如下: