npm install -g @vue/cli
//全局安装vue-clinpm uninstall -g vue-cli
//卸载全局vue-clivue --version
,出现以下版本号,则代表成功vue create vue-test
// vue-test为项目名称
分别代表的是:
cd mybolg => npm run serve
启动项目import qs from 'qs';
import axios from "axios";
// import store from "@/store";
import { getAccessToken } from "@/utils/auth";
import { notification } from "ant-design-vue";
export const http = (function http() {
// 创建 axios 实例
const request = axios.create({
// API 请求的默认前缀
baseURL: '/api',
timeout: 10000, // 请求超时时间,10s
transformRequest: [ // 处理接口返回数据格式
(data, config) => {
if (!data) {
return data;
}
// 如果是Form表单就直接跳过JSON转换
if (data instanceof FormData) {
// 如果上传包含文件, 更改 Content-Type
// if(data.has('file')) {
// config['Content-Type'] = 'multipart/form-data';
// config['put']['Content-Type'] = 'multipart/form-data';
// config['post']['Content-Type'] = 'multipart/form-data';
// config['patch']['Content-Type'] = 'multipart/form-data';
// }
return data;
}
// 序列化data
// if (data instanceof Object) {
// for (let key in data) {
// if (data.hasOwnProperty(key) && !data[key]) {
// delete data[key];
// }
// }
// return JSON.stringify(data);
// }
// return data;
return qs.stringify(data, {
arrayFormat: 'brackets',
strictNullHandling: false
});
}
]
});
// 异常拦截处理器
const errorHandler = errorRep => {
if (errorRep.response) {
const {
data: { error },
status
} = errorRep.response,
// 从 coockie 获取 token
token = getAccessToken();
// 身份验证失败
if (status === 401) {
notification.error({
message: "身份验证",
description: "登录过期,需要重新验证身份"
});
// 如果登录了,则退出登录
if (token) {
// store.dispatch("Logout").then(() => {
// setTimeout(() => {
// window.location.reload();
// }, 1500);
// });
}
}
if (status === 403) {
notification.error({
message: "拒绝访问",
description: error.message
});
} else {
notification.error({
message: "错误消息",
description: error.message
});
}
return Promise.reject(error);
}
return Promise.reject(errorRep);
};
// 请求前拦截
request.interceptors.request.use(config => {
const token = getAccessToken();
// 如果 token 存在
// 让每个请求携带自定义 token 请根据实际情况自行修改
if (token) {
config.headers["authorization"] = `Bearer ${token}`;
}
return config;
}, errorHandler);
// 请求后拦截
request.interceptors.response.use(response => {
return response.data;
}, errorHandler);
})();
// 配置http请求方式到Window全局空间中
window.http = http;
let VueHttp = function(vue, ins) {
if (VueHttp.installed) {
return;
}
VueHttp.installed = true;
if (!axios) {
console.error('You have to install axios');
return;
}
vue['axios'] = axios;
Object.defineProperties(vue.prototype, {
axios: {
get() {
return axios;
}
},
$http: {
get() {
return http;
}
}
});
};
export { VueHttp };
export default http;
/* eslint-disable indent */
// nodejs中的path模块
const path = require("path");
/**
* 拆分本地API代理接口
* 通过不同的启动方式, 可以直接运行线上的测试接口
*/
const ApiLocalProxyList = {
'/api/common': {
target: 'http://localhost:6002',
pathRewrite: {
'^/api/common': '',
},
secure: false,
},
'/api/design': {
target: 'http://localhost:6001',
pathRewrite: {
'^/api/design': '',
},
secure: false,
},
};
/**
* 线上代理接口
*/
const ApiOnlineProxyList = {
"/api": {
target: "http://xxx.xxx.xxx.xxx:xxxx",
// pathRewrite: {
// '^/api': ''
// },
secure: false,
},
};
module.exports = {
publicPath: "/",
assetsDir: "assets",
productionSourceMap: false,
chainWebpack: (config) => {
// 修改入口文件
config
.entry("app")
.clear()
.add("./src/main.js")
.end()
.resolve.modules.prepend(path.resolve(__dirname, "./src"))
.end()
.alias.set("vue$", "vue/dist/vue.js")
.set("resize-detector$", "resize-detector/dist/index.js")
.end()
.end()
.plugin("define")
.tap((args) => {
let options = args[0];
let rst = [
Object.assign({
options,
// 增加 环境变量 __DEV__
__DEV__: process.env.NODE_ENV !== "production",
}),
];
return rst;
})
.end()
.plugin("html")
.tap((args) => {
let options = args[0];
return [
Object.assign({
options,
template: "public/index.html",
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true,
},
}),
];
})
.end()
.plugin("copy")
.tap((args) => {
let options = args[0];
if (!options) {
return args;
}
options = [
{
from: path.resolve(__dirname, "./public"),
to: path.resolve(__dirname, `dist/public`),
ignore: ["index.html", ".DS_Store"],
},
];
return [options];
});
},
devServer: {
host: "0.0.0.0",
contentBase: [path.join(__dirname)],
port: 8072, //项目启动端口
proxy: process.env.online ? ApiOnlineProxyList : ApiLocalProxyList,
},
};
import Vue from 'vue';
import Vuex from 'vuex';
import http from "@/utils/request_http";
import { setAccessToken, removeAccessToken } from "@/util/auth";
Vue.use(Vuex);
export const MU_UPATE_AUTH = 'MU_UPATE_AUTH';
export default new Vuex.Store({
state: { //对象数据
auth: {
code: -101, // 没有发送用户信息请求
loading: false
},
},
mutations: { //操作变更state数据
[MU_UPATE_AUTH](state, value) {
if (value && value.isLogin) {
state.auth = value;
setAccessToken(value.token);
} else {
// 传空值时将登录状态初始化
state.auth = {
code: -101,
loading: false,
};
removeAccessToken();
}
}
},
actions: { //触发向上回调到mutations
[MU_UPATE_AUTH](context) {
const req = http.post('/api/common/Login/getAuthInfo').then( // 获取系统登录状态
function(res) {
let roles = res.code > 0 ? {} : {}; //根据业务处理,没有可以去掉
let auth = {
loading: false,
token: res.token,
isLogin: res.code > 0, // true:已经登录 false: 未登录
...res,
...roles
};
context.commit(MU_UPATE_AUTH, auth);
return auth;
},
function() {
console.log('请求失败处理');
}
);
// 保存登录状态
context.commit(MU_UPATE_AUTH, { code: -101, loading: true, request: req });
return req;
}
}
});
import Vue from "vue";
import VueRouter from "vue-router";
import Home from "../views/Home.vue";
Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "Home",
component: Home,
},
{
path: "/about",
name: "About",
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () =>
import(/* webpackChunkName: "about" */ "../views/About.vue"),
},
];
const router = new VueRouter({
routes,
});
// 全局拦截路由
router.beforeEach((to, from, next) => {
// 获取登录状态
const auth = store.state.auth;
// 验证是否需要权限
to.matched.forEach((record) => {
if (record.meta.requiresAuth) {
// 没有用户信息
// 常见情况:
// 1.用户强制刷新了页面, 需要重新发送用户登录信息请求
// 2.用户没有登录直接拷贝的地址粘贴
if (auth.code === -101) {
// 之前没有加载用户信息
let request = auth.request || store.dispatch(MU_UPATE_AUTH);
request.then((rst) => {
// 路由之后
// 确定没有登录
next(afterAuth(to, rst, record) || undefined);
});
} else {
// 路由之后
next(afterAuth(to, auth, record) || undefined);
}
} else {
// 不需要验证的路由
next(); // 确保一定要调用 next()
}
});
});
/**
* 路由跳转验证
* 没有登录或者用户类型不匹配
*
* @param {IAuth} auth
* @param {RouteRecord} record
* @returns {boolean}
*/
function requiresAuth(auth, record) {
// 返回需要验证的情况:
// 1.没有登录
// 2.用户类型定义并且用户类型和对应的路由要求不匹配
// 还没登录、跳转到登录页
if (auth.code < 0) {
return true;
}
// meta设置了userType字段, 需要验证身份
if (record.meta.userType !== undefined) {
if (typeof record.meta.userType === "number") {
// 只需一种角色进入
// 不满足、跳转登录页
return auth.userType !== record.meta.userType;
} else if (record.meta.userType instanceof Array) {
// 允许多重角色
// 不满足、跳转登录页
return record.meta.userType.indexOf(auth.userType) === -1;
} else {
// 其他情况均跳转到登录页
return true;
}
} else {
// 没有设置设置meta的userType字段
// 放过进入下一个路由
return false;
}
}
function afterAuth(to, auth, record) {
// 已经请求过用户信息
if (requiresAuth(auth, record)) {
// 普通页面调转,没有丢失用户登录信息
return {
name: "Home", // 原来是login
query: { redirect: to.fullPath },
};
} else {
return false;
}
}
const originalPush = Router.prototype.push;
Router.prototype.push = function push(location) {
return originalPush.call(this, location).catch((err) => err);
};
export default router;
npm i element-ui -S
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
之后我们的页面就可以使用Element的组件来渲染页面了
Element官网地址:https://element.eleme.cn/#/zh-CN/component/installation
cnpm install scss-loader scss --save
cnpm install sass-loader node-sass --save
在页面文件即可使用
<style lang="scss" scoped>
.aaa{
.bbb {
color: red;
}
}
</style>
参考文章:https://blog.csdn.net/liuxin00020/article/details/106617524