# 搭建Vue3 后台管理框架 —— 项目创建
# 搭建Vue3 后台管理框架 —— 登录页面
最近事多,都是抽点空余时间写一写,从开始写到现在,一点一点的构架,也算是把基础从新巩固一遍,同时也把相关技术多熟悉熟悉,技术一直在更新,学习永不停止。
index.js 路由配置
import { createRouter, createWebHistory } from "vue-router";
import routers from "./module/public";
import NProgress from 'nprogress';
import { USER_TOKEN } from "../utils/LocalDateName";
import { getStorage } from "../utils/PublicFunction";
const onAuthPage = ["/login"];
// 页面加载 进度条
NProgress.configure({
showSpinner: false, // true 开启loading false 关闭
});
const router = createRouter({
history: createWebHistory(), // hash模式:createWebHashHistory,history模式:createWebHistory
scrollBehavior(to, from, savedPosition) {
return savedPosition ? savedPosition : { left: 0, top: 0 }; // 页面初始化保留位置
},
routes: routers
});
// 创建路由守卫
router.beforeEach((to, from, next) => {
// 开启 进度条
NProgress.start()
// 当前路由 不为登录页面 且 没有token 回退到登录页面
if (!onAuthPage.includes(to.path) && !getStorage(USER_TOKEN)) {
next({ path: "/login", replace: true });
} else {
next();
}
});
router.afterEach((to)=>{
// 关闭 进度条
NProgress.done();
})
export default router;
public.js 这个文件存放公共路由 登录 404 等等
export default [
{
path: '/login',
name: 'login',
meta: {
icon: '',
title: '登录',
},
component:() => import('../views/login/Login.vue')
}
]
关于module 是用来存放所有的路由文件
关于nprogress 是一个前端页面加载进度条一个小装饰
nprogress官方
目录结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wxGffG1b-1661763090388)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/262d48ceb3784c37970858bb8c61c3f3~tplv-k3u1fbpfcp-watermark.image?)]
userStores.js 获取用户信息 按钮权限 存储起来
import { defineStore } from "pinia";
import { USER_AUTH, USER_INFO, USER_TOKEN } from "../utils/LocalDateName";
import { getStorage, setStorage, removeStorage } from "../utils/PublicFunction";
import { useMenuStore } from './menuStore'
export const userInfoStore = defineStore("userInfoStore", {
state: () => ({
userInfo: getStorage(USER_INFO) || {}, // 用户信息
userToken: getStorage(USER_TOKEN) || "", // 用户token
userAuth: getStorage(USER_AUTH) || [] // 权限菜单
}),
getters: {
// 判断用户是否登录
isLogin: state => Object.keys(state.userInfo).length > 0
},
actions: {
// 设置用户登录信息
setUserInfo(payload) {
if (payload.user) {
setStorage(USER_INFO, payload.user);
this.userInfo = payload.user;
}
if (payload.token) {
setStorage(USER_TOKEN, payload.token);
this.userToken = payload.token;
}
},
// 设置操作颗粒度权限
setUserAuth(payload) {
if (payload.auth) {
setStorage(USER_AUTH, payload.auth);
this.userAuth = payload.auth;
}
},
// 退出登录清空权限
LoginOut(){
removeStorage(USER_TOKEN)
removeStorage(USER_INFO)
removeStorage(USER_TOKEN)
this.userInfo = {}
useMenuStore.setFunctionMenu([])
}
}
});
menuStores.js 获取功能权限菜单 也就是路由权限
import { defineStore } from "pinia";
import { USER_MENU } from "../utils/LocalDateName";
import { setStorage } from "../utils/PublicFunction";
export const useMenuStore = defineStore("userMenuStore", {
state: () => ({
userMenu: getStorage(USER_MENU) || [] // 功能权限菜单
}),
getters: {},
actions: {
// 获取路由权限菜单
async getFunctionMenu() {
// 请求功能接口 这里请求接口 获取data
setStorage(USER_MENU, data);
},
// 设置
setFunctionMenu(payload){
this.userMenu = payload
}
}
});
目录结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9ixwTiGI-1661763090390)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cf3eece38b7942f9af0a09ed3d9de787~tplv-k3u1fbpfcp-watermark.image?)]
axios 关于axios封装 真的可以说全网满天飞 这里只代表个人想法 肯定有不足得地方
import axios from "axios";
import router from '@/router'
import { message, Modal } from 'ant-design-vue';
import { getStorage } from "./PublicFunction";
import { userInfoStore } from '@/stores/userStores'
class HttpRequest {
static getInsideConfig() { // 设置请求头
return {
headers: { "X-Requested-With": "XMLHttpRequest" } // X-Requested-With : null (返回为文本) XMLHttpRequest (返回JSON格式)
};
};
intercetors(instance) {
// 设置请求拦截 添加token
instance.interceptors.request.use((config)=>{
if(config.url.includes('company-console')){ // 判断请求地址
const authToken = getStorage('USER_TOKEN') // 获取本地存储token
authToken && (config.headers['xh-token'] = authToken) // 请求头添加token
}
return config
}, error => {
return Promise.reject(error)
})
// 响应拦截
instance.interceptors.response.use((response)=>{
if(response.config.url.includes('company-console') && !response.config.url.includes('export') && !response.config.url.includes('download')){
if([401,202].includes(response.data.code)){
userInfoStore.LoginOut()
router.replace({path:'/login'})
}
if(response.data.code && response.data.code !== 401 && response.data.code !== 202){
modal = Modal.error({
title: '错误提示',
content: response.data.msg,
centered: true
});
}
if(response.data.code && response.data.code == 202){
message.warning({
content: response.data.msg,
onClose: () => {
userInfoStore.LoginOut()
router.replace({ path: '/login' });
},
});
}
}
return response.data
},error => {
const { status } = error.response
if(status === 401){
userInfoStore.LoginOut()
router.replace({ path: '/login' });
}
return Promise.reject(error)
})
};
request(options) {
const instance = axios.create();
options = Object.assign({}, HttpRequest.getInsideConfig(), options);
this.intercetors(instance);
return instance(options);
}
}
const httpRequest = new HttpRequest();
export default httpRequest;
目录结构
LocalDateName.js || PublicFunction.js 这个两个文件 传送门可以获取到
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g1JbI7SD-1661763090391)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b8506f982dac4eccac644c7c0bb4b67f~tplv-k3u1fbpfcp-watermark.image?)]
经过这么多天(零碎得时间),才写了这点东西,而且觉得很多地方还需要打磨,暂时想法是先把大体框架打起来然后一点一点打磨吧,现在最大得问题是后端怎么办(后端我不会啊),还在纠结是用前端server实现还是使用后端java技术(后端需要自学)各位jym有什么好的建议。