Merge branch 'abp' of https://gitee.com/ccnetcore/Yi into abp
This commit is contained in:
@@ -1,2 +1,4 @@
|
|||||||
|
# 接口前缀
|
||||||
VITE_APP_BASEAPI="/api-dev"
|
VITE_APP_BASEAPI="/api-dev"
|
||||||
VITE_APP_URL="http://localhost:19001/api/app"
|
VITE_APP_URL="http://localhost:19001/api/app"
|
||||||
|
VITE_APP_ENV_NAME = "dev"
|
||||||
@@ -1 +1,4 @@
|
|||||||
VITE_APP_BASEAPI="/prod-api"
|
# 接口前缀
|
||||||
|
VITE_APP_BASEAPI="/prod-api"
|
||||||
|
|
||||||
|
VITE_APP_ENV_NAME = "production"
|
||||||
65
Yi.BBS.Vue3/src/apis/auth.js
Normal file
65
Yi.BBS.Vue3/src/apis/auth.js
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import request from "@/config/axios/service";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户登录
|
||||||
|
* @param {*} data 账号密码
|
||||||
|
*/
|
||||||
|
export function userLogin(data) {
|
||||||
|
return request({
|
||||||
|
url: `/account/login`,
|
||||||
|
method: "post",
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户注册
|
||||||
|
* @param {*} data 账号密码
|
||||||
|
*/
|
||||||
|
export function userRegister(data) {
|
||||||
|
return request({
|
||||||
|
url: `/account/register`,
|
||||||
|
method: "post",
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户详细信息
|
||||||
|
*/
|
||||||
|
export function getUserDetailInfo() {
|
||||||
|
return request({
|
||||||
|
url: `/account`,
|
||||||
|
method: "get",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户退出
|
||||||
|
*/
|
||||||
|
export function userLogout() {
|
||||||
|
return request({
|
||||||
|
url: `/account/logout`,
|
||||||
|
method: "post",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取验证码
|
||||||
|
*/
|
||||||
|
export function getCodeImg() {
|
||||||
|
return request({
|
||||||
|
url: `/account/captcha-image`,
|
||||||
|
method: "get",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取短信验证码
|
||||||
|
*/
|
||||||
|
export function getCodePhone(data) {
|
||||||
|
return request({
|
||||||
|
url: `/account/captcha-phone`,
|
||||||
|
method: "post",
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import myaxios from '@/utils/request'
|
import request from "@/config/axios/service";
|
||||||
|
|
||||||
//获取配置
|
//获取配置
|
||||||
export function getAll(){
|
export function getAll() {
|
||||||
return myaxios({
|
return request({
|
||||||
url: '/config',
|
url: "/config",
|
||||||
method: 'get'
|
method: "get",
|
||||||
})
|
});
|
||||||
};
|
}
|
||||||
|
|||||||
13
Yi.BBS.Vue3/src/config/axios/ErrorCode.js
Normal file
13
Yi.BBS.Vue3/src/config/axios/ErrorCode.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
export default {
|
||||||
|
"000": "操作太频繁,请勿重复请求",
|
||||||
|
401: "当前操作没有权限,请退出重试",
|
||||||
|
403: "当前操作没有权限,请退出重试",
|
||||||
|
404: "资源不存在",
|
||||||
|
417: "未绑定登录账号,请使用密码登录后绑定",
|
||||||
|
423: "演示环境不能操作,如需了解联系",
|
||||||
|
426: "用户名不存在或密码错误",
|
||||||
|
428: "验证码错误,请重新输入",
|
||||||
|
429: "请求过频繁",
|
||||||
|
479: "演示环境,没有权限操作",
|
||||||
|
default: "系统未知错误,请反馈给管理员",
|
||||||
|
};
|
||||||
34
Yi.BBS.Vue3/src/config/axios/config.js
Normal file
34
Yi.BBS.Vue3/src/config/axios/config.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
const config = {
|
||||||
|
/**
|
||||||
|
* api请求基础路径
|
||||||
|
*/
|
||||||
|
base_url: {
|
||||||
|
// 开发环境接口前缀
|
||||||
|
dev: import.meta.env.VITE_APP_BASEAPI,
|
||||||
|
// 打包生产环境接口前缀
|
||||||
|
pro: window.location.protocol + "//" + window.location.hostname + ":19001",
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接口请求前缀
|
||||||
|
*/
|
||||||
|
pre_interface: import.meta.env.VITE_APP_BASEAPI,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接口成功返回状态码
|
||||||
|
*/
|
||||||
|
result_code: "0000",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接口请求超时时间
|
||||||
|
*/
|
||||||
|
request_timeout: 60000,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认接口请求类型
|
||||||
|
* 可选值:application/x-www-form-urlencoded multipart/form-data
|
||||||
|
*/
|
||||||
|
default_headers: "application/json",
|
||||||
|
};
|
||||||
|
|
||||||
|
export { config };
|
||||||
89
Yi.BBS.Vue3/src/config/axios/service.js
Normal file
89
Yi.BBS.Vue3/src/config/axios/service.js
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import { config } from "@/config/axios/config";
|
||||||
|
import { Session } from "@/utils/storage";
|
||||||
|
import useAuths from "@/hooks/useAuths";
|
||||||
|
|
||||||
|
const { getToken } = useAuths();
|
||||||
|
|
||||||
|
const { request_timeout } = config;
|
||||||
|
export const PATH_URL = import.meta.env.VITE_APP_BASEAPI;
|
||||||
|
|
||||||
|
// 配置新建一个 axios 实例
|
||||||
|
const service = axios.create({
|
||||||
|
baseURL: PATH_URL, // api 的 base_url
|
||||||
|
timeout: request_timeout, // 请求超时时间
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
hideerror: false, //是否在底层显示错误信息
|
||||||
|
});
|
||||||
|
|
||||||
|
// 添加请求拦截器
|
||||||
|
service.interceptors.request.use(
|
||||||
|
(config) => {
|
||||||
|
// 在发送请求之前做些什么 token
|
||||||
|
const token = getToken();
|
||||||
|
if (token) {
|
||||||
|
config.headers["Authorization"] = `Bearer ${token}`;
|
||||||
|
}
|
||||||
|
if (Session.get("tenantId")) {
|
||||||
|
config.headers["TenantId"] = Session.get("tenantId");
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
// 对请求错误做些什么
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// 添加响应拦截器
|
||||||
|
service.interceptors.response.use(
|
||||||
|
(response) => {
|
||||||
|
return Promise.resolve(response);
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
// 对响应错误做点什么
|
||||||
|
if (error.message.indexOf("timeout") != -1) {
|
||||||
|
ElMessage({
|
||||||
|
type: "danger",
|
||||||
|
message: "网络超时",
|
||||||
|
});
|
||||||
|
} else if (error.message == "Network Error") {
|
||||||
|
ElMessage({
|
||||||
|
type: "danger",
|
||||||
|
message: "网络连接错误",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const res = error.response || {};
|
||||||
|
const status = Number(res.status) || 200;
|
||||||
|
const message = res.data.error.message;
|
||||||
|
if (status === 401) {
|
||||||
|
ElMessage({
|
||||||
|
type: "danger",
|
||||||
|
message,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (status !== 200) {
|
||||||
|
if (status >= 500) {
|
||||||
|
ElMessage({
|
||||||
|
type: "danger",
|
||||||
|
message: "网络开小差了,请稍后再试",
|
||||||
|
});
|
||||||
|
return Promise.reject(new Error(message));
|
||||||
|
}
|
||||||
|
// 避开找不到后端接口的提醒
|
||||||
|
if (status !== 404) {
|
||||||
|
ElMessage({
|
||||||
|
type: "danger",
|
||||||
|
message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(error));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// 导出 axios 实例
|
||||||
|
export default service;
|
||||||
138
Yi.BBS.Vue3/src/hooks/useAuths.js
Normal file
138
Yi.BBS.Vue3/src/hooks/useAuths.js
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
import { ElMessage, ElMessageBox } from "element-plus";
|
||||||
|
import useUserStore from "@/stores/user";
|
||||||
|
import router from "@/router";
|
||||||
|
import { Session, Local } from "@/utils/storage";
|
||||||
|
import { userLogin, getUserDetailInfo, userLogout } from "@/apis/auth";
|
||||||
|
|
||||||
|
const TokenKey = "AccessToken";
|
||||||
|
export const AUTH_MENUS = "AUTH_MENUS";
|
||||||
|
export const AUTH_USER = "AUTH_USER";
|
||||||
|
|
||||||
|
export default function useAuths(opt) {
|
||||||
|
const defaultOpt = {
|
||||||
|
loginUrl: "/login", // 登录页跳转url 默认: /login
|
||||||
|
loginReUrl: "", // 登录页登陆成功后带重定向redirect=的跳转url 默认为空
|
||||||
|
homeUrl: "/index", // 主页跳转url 默认: /index
|
||||||
|
otherQuery: {}, // 成功登录后携带的(除redirect外)其他参数
|
||||||
|
};
|
||||||
|
|
||||||
|
let option = {
|
||||||
|
...defaultOpt,
|
||||||
|
...opt,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取token
|
||||||
|
const getToken = () => {
|
||||||
|
return Session.get(TokenKey);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 存储token到cookies
|
||||||
|
const setToken = (token) => {
|
||||||
|
if (token == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Session.set(TokenKey, token);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 删除token
|
||||||
|
const removeToken = () => {
|
||||||
|
Session.remove(TokenKey);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 退出登录
|
||||||
|
const logoutFun = async () => {
|
||||||
|
let flag = true;
|
||||||
|
try {
|
||||||
|
await userLogout().then((res) => {
|
||||||
|
ElMessage({
|
||||||
|
message: "退出成功",
|
||||||
|
type: "info",
|
||||||
|
duration: 2000,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
flag = await ElMessageBox.confirm(
|
||||||
|
`退出登录失败,是否强制退出?`,
|
||||||
|
"提示",
|
||||||
|
{
|
||||||
|
confirmButtonText: "确 定",
|
||||||
|
cancelButtonText: "取 消",
|
||||||
|
type: "warning",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
//取消
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (flag) {
|
||||||
|
clearStorage();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 清空本地存储的信息
|
||||||
|
const clearStorage = () => {
|
||||||
|
Session.clear();
|
||||||
|
Local.clear();
|
||||||
|
removeToken();
|
||||||
|
window.location.reload();
|
||||||
|
Session.set("vuex", null);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 用户名密码登录
|
||||||
|
const loginFun = async (params) => {
|
||||||
|
const res = await userLogin(params);
|
||||||
|
ElMessage({
|
||||||
|
message: `您好${params.userName},登录成功!`,
|
||||||
|
type: "success",
|
||||||
|
});
|
||||||
|
loginSuccess(res);
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取用户基本信息、角色、菜单权限
|
||||||
|
const getUserInfo = async () => {
|
||||||
|
try {
|
||||||
|
let { data } = await getUserDetailInfo();
|
||||||
|
// useUserStore
|
||||||
|
// store.dispatch("updateUserInfo", result);
|
||||||
|
return data;
|
||||||
|
} catch (error) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 登录成功之后的操作
|
||||||
|
const loginSuccess = async (res) => {
|
||||||
|
const { token } = res.data;
|
||||||
|
|
||||||
|
setToken(token);
|
||||||
|
try {
|
||||||
|
// 存储用户信息
|
||||||
|
await getUserInfo(); // 用户信息
|
||||||
|
// 登录成功后 路由跳转
|
||||||
|
router.replace({
|
||||||
|
path: option.loginReUrl ? option.loginReUrl : option.homeUrl,
|
||||||
|
query: option.otherQuery,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
removeToken();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
getToken,
|
||||||
|
setToken,
|
||||||
|
removeToken,
|
||||||
|
loginFun,
|
||||||
|
getUserInfo,
|
||||||
|
logoutFun,
|
||||||
|
clearStorage,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,65 +1,52 @@
|
|||||||
import router from './router'
|
import router from "./router";
|
||||||
import { ElMessage } from 'element-plus'
|
import useAuths from "@/hooks/useAuths";
|
||||||
import NProgress from 'nprogress'
|
import { ElMessage } from "element-plus";
|
||||||
import 'nprogress/nprogress.css'
|
import NProgress from "nprogress";
|
||||||
import { getToken } from '@/utils/auth'
|
import "nprogress/nprogress.css";
|
||||||
import { isRelogin } from '@/utils/request'
|
import useUserStore from "@/stores/user";
|
||||||
import useUserStore from '@/stores/user'
|
|
||||||
|
|
||||||
|
|
||||||
NProgress.configure({ showSpinner: false });
|
NProgress.configure({ showSpinner: false });
|
||||||
|
const { getToken, logoutFun } = useAuths();
|
||||||
const whiteList = ['/login', '/auth-redirect', '/bind', '/register'];
|
const whiteList = ["/login", "/auth-redirect", "/bind", "/register"];
|
||||||
|
|
||||||
router.beforeEach((to, from, next) => {
|
router.beforeEach((to, from, next) => {
|
||||||
NProgress.start()
|
NProgress.start();
|
||||||
if (getToken()) {
|
const hasToken = getToken();
|
||||||
// to.meta.title && useSettingsStore().setTitle(to.meta.title)
|
if (hasToken) {
|
||||||
/* has token*/
|
if (to.path === "/login") {
|
||||||
if (to.path === '/login') {
|
// 已经登陆跳转到首页
|
||||||
next({ path: '/' })
|
next({ path: "/" });
|
||||||
NProgress.done()
|
NProgress.done();
|
||||||
} else {
|
} else {
|
||||||
|
if (useUserStore().roles.length === 0) {
|
||||||
if (useUserStore().roles.length === 0)
|
|
||||||
{
|
|
||||||
isRelogin.show = true
|
|
||||||
// 判断当前用户是否已拉取完user_info信息
|
// 判断当前用户是否已拉取完user_info信息
|
||||||
useUserStore().getInfo().then(() => {
|
useUserStore()
|
||||||
isRelogin.show = false
|
.getInfo()
|
||||||
//这里不需要动态路由
|
.then(() => {
|
||||||
// usePermissionStore().generateRoutes().then(accessRoutes => {
|
next({ ...to, replace: true });
|
||||||
// // 根据roles权限生成可访问的路由表
|
|
||||||
// accessRoutes.forEach(route => {
|
|
||||||
// if (!isHttp(route.path)) {
|
|
||||||
// router.addRoute(route) // 动态添加可访问路由表
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
|
|
||||||
// })
|
|
||||||
next({ ...to, replace: true })
|
|
||||||
}).catch(err => {
|
|
||||||
useUserStore().logOut().then(() => {
|
|
||||||
ElMessage.error(err)
|
|
||||||
next({ path: '/' })
|
|
||||||
})
|
})
|
||||||
})
|
.catch((err) => {
|
||||||
|
logoutFun.then(() => {
|
||||||
|
ElMessage.error(err);
|
||||||
|
next({ path: "/" });
|
||||||
|
});
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
next()
|
next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 没有token
|
// 没有token
|
||||||
if (whiteList.indexOf(to.path) !== -1) {
|
if (whiteList.indexOf(to.path) !== -1) {
|
||||||
// 在免登录白名单,直接进入
|
// 在免登录白名单,直接进入
|
||||||
next()
|
next();
|
||||||
} else {
|
} else {
|
||||||
next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页
|
next(`/login?redirect=${to.path}&unTourist=true`); // 否则全部重定向到登录页
|
||||||
NProgress.done()
|
NProgress.done();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
router.afterEach(() => {
|
router.afterEach(() => {
|
||||||
NProgress.done()
|
NProgress.done();
|
||||||
})
|
});
|
||||||
|
|||||||
@@ -1,76 +1,74 @@
|
|||||||
import { createRouter, createWebHistory } from 'vue-router'
|
import { createRouter, createWebHistory } from "vue-router";
|
||||||
import Layout from '../layout/Index.vue'
|
import Layout from "../layout/Index.vue";
|
||||||
import NotFound from '../views/error/404.vue'
|
import NotFound from "../views/error/404.vue";
|
||||||
import LoginLayout from '../layout/LoginLayout.vue'
|
import LoginLayout from "../layout/LoginLayout.vue";
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(import.meta.env.BASE_URL),
|
history: createWebHistory(import.meta.env.BASE_URL),
|
||||||
scrollBehavior(to, from, savedPosition) {
|
scrollBehavior(to, from, savedPosition) {
|
||||||
// 始终滚动到顶部
|
// 始终滚动到顶部
|
||||||
return { top: 0 }
|
return { top: 0 };
|
||||||
},
|
},
|
||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
name:'test',
|
name: "test",
|
||||||
path: '/test',
|
path: "/test",
|
||||||
component: () => import('../views/Test.vue')
|
component: () => import("../views/Test.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
path: "/loginLayout",
|
||||||
path: '/loginLayout',
|
name: "loginLayout",
|
||||||
name: 'loginLayout',
|
|
||||||
component: LoginLayout,
|
component: LoginLayout,
|
||||||
redirect: '/login' ,
|
redirect: "/login",
|
||||||
children :[
|
children: [
|
||||||
{
|
{
|
||||||
name:'login',
|
name: "login",
|
||||||
path: '/login',
|
path: "/login",
|
||||||
component: () => import('../views/Login.vue')
|
component: () => import("../views/Login.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name:'register',
|
name: "register",
|
||||||
path: '/register',
|
path: "/register",
|
||||||
component: () => import('../views/Register.vue')
|
component: () => import("../views/Register.vue"),
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/',
|
path: "/",
|
||||||
name: 'layout',
|
name: "layout",
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/index' ,
|
redirect: "/index",
|
||||||
children :[
|
children: [
|
||||||
{
|
{
|
||||||
name:'index',
|
name: "index",
|
||||||
path: '/index',
|
path: "/index",
|
||||||
component: () => import('../views/Index.vue')
|
component: () => import("../views/Index.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name:'article',
|
name: "article",
|
||||||
path: '/article/:discussId/:articleId?',
|
path: "/article/:discussId/:articleId?",
|
||||||
component: () => import('../views/Article.vue')
|
component: () => import("../views/Article.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name:'discuss',
|
name: "discuss",
|
||||||
path: '/discuss/:plateId?',
|
path: "/discuss/:plateId?",
|
||||||
component: () => import('../views/Discuss.vue')
|
component: () => import("../views/Discuss.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
//artType:discuss主题、article文章
|
//artType:discuss主题、article文章
|
||||||
//operType:create创建、update更新
|
//operType:create创建、update更新
|
||||||
name:'editArt',
|
name: "editArt",
|
||||||
path:'/editArt',
|
path: "/editArt",
|
||||||
component:()=>import('../views/EditArticle.vue')
|
component: () => import("../views/EditArticle.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name:'profile',
|
name: "profile",
|
||||||
path:'/profile',
|
path: "/profile",
|
||||||
component:()=>import('../views/profile/Index.vue')
|
component: () => import("../views/profile/Index.vue"),
|
||||||
|
},
|
||||||
}
|
],
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{ path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound },
|
{ path: "/:pathMatch(.*)*", name: "NotFound", component: NotFound },
|
||||||
]
|
],
|
||||||
})
|
});
|
||||||
|
|
||||||
export default router
|
export default router;
|
||||||
|
|||||||
@@ -1,98 +1,109 @@
|
|||||||
import { login, logout, getInfo,register } from '@/apis/accountApi'
|
import { login, logout, getInfo, register } from "@/apis/accountApi";
|
||||||
import { getToken, setToken, removeToken } from '@/utils/auth'
|
import { getUserDetailInfo } from "@/apis/auth";
|
||||||
import { defineStore } from 'pinia'
|
import useAuths from "@/hooks/useAuths";
|
||||||
const useUserStore = defineStore('user',
|
import { defineStore } from "pinia";
|
||||||
{
|
|
||||||
state: () => ({
|
const { getToken, setToken, removeToken } = useAuths();
|
||||||
id:'',
|
|
||||||
token: getToken(),
|
const useUserStore = defineStore("user", {
|
||||||
name: '游客',
|
state: () => ({
|
||||||
userName:'',
|
id: "",
|
||||||
icon: null,
|
token: getToken(),
|
||||||
roles: [],
|
name: "游客",
|
||||||
permissions: []
|
userName: "",
|
||||||
}),
|
icon: null,
|
||||||
getters: {
|
roles: [],
|
||||||
},
|
permissions: [],
|
||||||
actions: {
|
}),
|
||||||
// 登录
|
getters: {},
|
||||||
login(userInfo) {
|
actions: {
|
||||||
const userName = userInfo.userName.trim()
|
// 登录
|
||||||
const password = userInfo.password
|
login(userInfo) {
|
||||||
const code = userInfo.code
|
const userName = userInfo.userName.trim();
|
||||||
const uuid = userInfo.uuid
|
const password = userInfo.password;
|
||||||
return new Promise((resolve, reject) => {
|
const code = userInfo.code;
|
||||||
login(userName, password, code, uuid).then(response => {
|
const uuid = userInfo.uuid;
|
||||||
const res=response.data;
|
return new Promise((resolve, reject) => {
|
||||||
|
login(userName, password, code, uuid)
|
||||||
|
.then((response) => {
|
||||||
|
const res = response.data;
|
||||||
setToken(res.token);
|
setToken(res.token);
|
||||||
this.token = res.token;
|
this.token = res.token;
|
||||||
resolve(response);
|
resolve(response);
|
||||||
}).catch(error => {
|
|
||||||
reject(error)
|
|
||||||
})
|
})
|
||||||
})
|
.catch((error) => {
|
||||||
},
|
reject(error);
|
||||||
// 获取用户信息
|
});
|
||||||
getInfo() {
|
});
|
||||||
return new Promise((resolve, reject) => {
|
},
|
||||||
getInfo().then(response => {
|
// 获取用户信息
|
||||||
const res=response.data;
|
getInfo() {
|
||||||
const user = res.user
|
return new Promise((resolve, reject) => {
|
||||||
const avatar = (user.icon == "" || user.icon == null) ? "/src/assets/logo.ico" : import.meta.env.VITE_APP_BASEAPI + "/file/"+user.icon;
|
getUserDetailInfo()
|
||||||
|
.then((response) => {
|
||||||
if (res.roleCodes && res.roleCodes.length > 0) { // 验证返回的roles是否是一个非空数组
|
const res = response.data;
|
||||||
this.roles = res.roleCodes
|
const user = res.user;
|
||||||
this.permissions = res.permissionCodes
|
const avatar =
|
||||||
|
user.icon == "" || user.icon == null
|
||||||
|
? "/src/assets/logo.ico"
|
||||||
|
: import.meta.env.VITE_APP_BASEAPI + "/file/" + user.icon;
|
||||||
|
|
||||||
|
if (res.roleCodes && res.roleCodes.length > 0) {
|
||||||
|
// 验证返回的roles是否是一个非空数组
|
||||||
|
this.roles = res.roleCodes;
|
||||||
|
this.permissions = res.permissionCodes;
|
||||||
// this.roles = ["admin"];
|
// this.roles = ["admin"];
|
||||||
// this.permissions=["*:*:*"]
|
// this.permissions=["*:*:*"]
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this.roles = ['ROLE_DEFAULT']
|
this.roles = ["ROLE_DEFAULT"];
|
||||||
}
|
}
|
||||||
// this.roles = ["admin"];
|
// this.roles = ["admin"];
|
||||||
// this.permissions=["*:*:*"]
|
// this.permissions=["*:*:*"]
|
||||||
this.name = user.nick
|
this.name = user.nick;
|
||||||
this.icon = avatar;
|
this.icon = avatar;
|
||||||
|
|
||||||
this.userName=user.userName;
|
this.userName = user.userName;
|
||||||
this.id=user.id;
|
this.id = user.id;
|
||||||
resolve(res)
|
resolve(res);
|
||||||
}).catch(error => {
|
|
||||||
reject(error)
|
|
||||||
})
|
})
|
||||||
})
|
.catch((error) => {
|
||||||
},
|
reject(error);
|
||||||
// 退出系统
|
});
|
||||||
logOut() {
|
});
|
||||||
return new Promise((resolve, reject) => {
|
},
|
||||||
logout().then(() => {
|
// 退出系统
|
||||||
this.token = ''
|
logOut() {
|
||||||
this.roles = []
|
return new Promise((resolve, reject) => {
|
||||||
this.permissions = []
|
logout()
|
||||||
removeToken()
|
.then(() => {
|
||||||
resolve()
|
this.token = "";
|
||||||
}).catch(error => {
|
this.roles = [];
|
||||||
reject(error)
|
this.permissions = [];
|
||||||
|
removeToken();
|
||||||
|
resolve();
|
||||||
})
|
})
|
||||||
})
|
.catch((error) => {
|
||||||
},
|
reject(error);
|
||||||
// 注册
|
});
|
||||||
register(userInfo) {
|
});
|
||||||
const userName = userInfo.userName.trim()
|
},
|
||||||
const password = userInfo.password.trim()
|
// 注册
|
||||||
const phone = userInfo.phone;
|
register(userInfo) {
|
||||||
const uuid = userInfo.uuid;
|
const userName = userInfo.userName.trim();
|
||||||
const code=userInfo.code;
|
const password = userInfo.password.trim();
|
||||||
return new Promise((resolve, reject) => {
|
const phone = userInfo.phone;
|
||||||
register(userName,password,phone,code,uuid).then(response => {
|
const uuid = userInfo.uuid;
|
||||||
resolve(response);
|
const code = userInfo.code;
|
||||||
}).catch(error => {
|
return new Promise((resolve, reject) => {
|
||||||
reject(error)
|
register(userName, password, phone, code, uuid)
|
||||||
})
|
.then((response) => {
|
||||||
})
|
resolve(response);
|
||||||
},
|
})
|
||||||
|
.catch((error) => {
|
||||||
},
|
reject(error);
|
||||||
})
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
export default useUserStore;
|
export default useUserStore;
|
||||||
|
|
||||||
140
Yi.BBS.Vue3/src/utils/file.js
Normal file
140
Yi.BBS.Vue3/src/utils/file.js
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
/**
|
||||||
|
* 根据后缀判断文件类型
|
||||||
|
* @param {string} fileName 文件后缀名
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function matchType(fileName) {
|
||||||
|
// 后缀获取
|
||||||
|
let suffix = "";
|
||||||
|
// 获取类型结果
|
||||||
|
let result = "";
|
||||||
|
try {
|
||||||
|
let flieArr = fileName.split(".");
|
||||||
|
suffix = flieArr[flieArr.length - 1];
|
||||||
|
} catch (err) {
|
||||||
|
suffix = "";
|
||||||
|
}
|
||||||
|
// fileName无后缀返回 false
|
||||||
|
if (!suffix) {
|
||||||
|
result = false;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// 图片格式
|
||||||
|
let imglist = ["png", "jpg", "jpeg", "bmp", "gif"];
|
||||||
|
// 进行图片匹配
|
||||||
|
result = imglist.some(function (item) {
|
||||||
|
return item == suffix;
|
||||||
|
});
|
||||||
|
if (result) {
|
||||||
|
result = "image";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// 匹配txt
|
||||||
|
let txtlist = ["txt"];
|
||||||
|
result = txtlist.some(function (item) {
|
||||||
|
return item == suffix;
|
||||||
|
});
|
||||||
|
if (result) {
|
||||||
|
result = "txt";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// 匹配 excel
|
||||||
|
let excelist = ["xls", "xlsx"];
|
||||||
|
result = excelist.some(function (item) {
|
||||||
|
return item == suffix;
|
||||||
|
});
|
||||||
|
if (result) {
|
||||||
|
result = "excel";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// 匹配 word
|
||||||
|
let wordlist = ["doc", "docx"];
|
||||||
|
result = wordlist.some(function (item) {
|
||||||
|
return item == suffix;
|
||||||
|
});
|
||||||
|
if (result) {
|
||||||
|
result = "word";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// 匹配 pdf
|
||||||
|
let pdflist = ["pdf"];
|
||||||
|
result = pdflist.some(function (item) {
|
||||||
|
return item == suffix;
|
||||||
|
});
|
||||||
|
if (result) {
|
||||||
|
result = "pdf";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// 匹配 ppt
|
||||||
|
let pptlist = ["ppt"];
|
||||||
|
result = pptlist.some(function (item) {
|
||||||
|
return item == suffix;
|
||||||
|
});
|
||||||
|
if (result) {
|
||||||
|
result = "ppt";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// 匹配 视频
|
||||||
|
let videolist = ["mp4", "m2v", "mkv"];
|
||||||
|
result = videolist.some(function (item) {
|
||||||
|
return item == suffix;
|
||||||
|
});
|
||||||
|
if (result) {
|
||||||
|
result = "video";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// 匹配 音频
|
||||||
|
let radiolist = ["mp3", "wav", "wmv"];
|
||||||
|
result = radiolist.some(function (item) {
|
||||||
|
return item == suffix;
|
||||||
|
});
|
||||||
|
if (result) {
|
||||||
|
result = "radio";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// 其他 文件类型
|
||||||
|
result = "other";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* url处理
|
||||||
|
* @param {string} path url路径
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function convertToUrl(path) {
|
||||||
|
// 替换反斜杠为正斜杠
|
||||||
|
const normalizedPathWithSlashes = path.replace(/\\/g, "/");
|
||||||
|
// 去掉开始的点号和反斜杠
|
||||||
|
const removedDotsAndSlashes = normalizedPathWithSlashes.replace(/^\.\//, "");
|
||||||
|
// 添加斜杠作为根路径
|
||||||
|
const url = `/${removedDotsAndSlashes}`;
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载文件
|
||||||
|
*
|
||||||
|
* @param {*} path 下载地址/下载请求地址。
|
||||||
|
* @param {string} name 下载文件的名字(考虑到兼容性问题,最好加上后缀名
|
||||||
|
*/
|
||||||
|
export const downLoadFile = (path, name) => {
|
||||||
|
const link = document.createElement("a");
|
||||||
|
link.href = path;
|
||||||
|
link.download = name;
|
||||||
|
|
||||||
|
if (isMobileDevice()) {
|
||||||
|
link.target = "_blank";
|
||||||
|
link.rel = "noopener noreferrer";
|
||||||
|
}
|
||||||
|
|
||||||
|
link.style.display = "none";
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 判断是否移动设备
|
||||||
|
export function isMobileDevice() {
|
||||||
|
return /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent);
|
||||||
|
}
|
||||||
53
Yi.BBS.Vue3/src/utils/storage.js
Normal file
53
Yi.BBS.Vue3/src/utils/storage.js
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/**
|
||||||
|
* window.localStorage 浏览器永久缓存
|
||||||
|
* @method set 设置永久缓存
|
||||||
|
* @method get 获取永久缓存
|
||||||
|
* @method remove 移除永久缓存
|
||||||
|
* @method clear 移除全部永久缓存
|
||||||
|
*/
|
||||||
|
export const Local = {
|
||||||
|
// 设置永久缓存
|
||||||
|
set(key, val) {
|
||||||
|
window.localStorage.setItem(key, JSON.stringify(val));
|
||||||
|
},
|
||||||
|
// 获取永久缓存
|
||||||
|
get(key) {
|
||||||
|
let json = window.localStorage.getItem(key);
|
||||||
|
return JSON.parse(json);
|
||||||
|
},
|
||||||
|
// 移除永久缓存
|
||||||
|
remove(key) {
|
||||||
|
window.localStorage.removeItem(key);
|
||||||
|
},
|
||||||
|
// 移除全部永久缓存
|
||||||
|
clear() {
|
||||||
|
window.localStorage.clear();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* window.sessionStorage 浏览器会话临时缓存
|
||||||
|
* @method set 设置临时缓存
|
||||||
|
* @method get 获取临时缓存
|
||||||
|
* @method remove 移除临时缓存
|
||||||
|
* @method clear 移除全部临时缓存
|
||||||
|
*/
|
||||||
|
export const Session = {
|
||||||
|
// 设置临时缓存
|
||||||
|
set(key, val) {
|
||||||
|
window.sessionStorage.setItem(key, JSON.stringify(val));
|
||||||
|
},
|
||||||
|
// 获取临时缓存
|
||||||
|
get(key) {
|
||||||
|
let json = window.sessionStorage.getItem(key);
|
||||||
|
return JSON.parse(json);
|
||||||
|
},
|
||||||
|
// 移除临时缓存
|
||||||
|
remove(key) {
|
||||||
|
window.sessionStorage.removeItem(key);
|
||||||
|
},
|
||||||
|
// 移除全部临时缓存
|
||||||
|
clear() {
|
||||||
|
window.sessionStorage.clear();
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -1,47 +1,50 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="login-wrapper">
|
<div class="login-wrapper">
|
||||||
<h1>{{configStore.name}}-登录</h1>
|
<h1>{{ configStore.name }}-登录</h1>
|
||||||
<div class="login-form">
|
<div class="login-form">
|
||||||
|
<el-form ref="loginFormRef" :model="loginForm" :rules="rules">
|
||||||
<el-form ref="loginFormRef" v-model="loginForm" :rules="rules" >
|
<div class="username form-item">
|
||||||
|
<el-form-item prop="userName">
|
||||||
<div class="username form-item">
|
<span>使用账号</span>
|
||||||
<el-form-item prop="userName">
|
<input
|
||||||
<span>使用账号</span>
|
type="text"
|
||||||
<input type="text" class="input-item" v-model="loginForm.userName">
|
class="input-item"
|
||||||
</el-form-item>
|
v-model="loginForm.userName"
|
||||||
</div>
|
/>
|
||||||
|
</el-form-item>
|
||||||
<div class="password form-item">
|
|
||||||
<el-form-item prop="password">
|
|
||||||
<span>密码</span>
|
|
||||||
<input type="password" class="input-item" v-model="loginForm.password">
|
|
||||||
</el-form-item>
|
|
||||||
</div>
|
|
||||||
</el-form>
|
|
||||||
<RouterLink to="/register" > 没有账号?前往注册</RouterLink>
|
|
||||||
<button class="login-btn" @click="login">登 录</button>
|
|
||||||
<button class="login-btn" @click="guestlogin">游客临时登录</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="password form-item">
|
||||||
|
<el-form-item prop="password">
|
||||||
|
<span>密码</span>
|
||||||
<div class="divider">
|
<input
|
||||||
<span class="line"></span>
|
type="password"
|
||||||
<span class="divider-text">其他方式登录</span>
|
class="input-item"
|
||||||
<span class="line"></span>
|
v-model="loginForm.password"
|
||||||
</div>
|
/>
|
||||||
|
</el-form-item>
|
||||||
<div class="other-login-wrapper">
|
|
||||||
<div class="other-login-item">
|
|
||||||
<img src="@/assets/login_images/QQ.png" alt="">
|
|
||||||
</div>
|
|
||||||
<div class="other-login-item">
|
|
||||||
<img src="@/assets/login_images/WeChat.png" alt="">
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</el-form>
|
||||||
|
<RouterLink to="/register"> 没有账号?前往注册</RouterLink>
|
||||||
|
<button class="login-btn" @click="login(loginFormRef)">登 录</button>
|
||||||
|
<button class="login-btn" @click="guestlogin">游客临时登录</button>
|
||||||
</div>
|
</div>
|
||||||
<!-- <h2> 登录-欢迎</h2>
|
|
||||||
|
<div class="divider">
|
||||||
|
<span class="line"></span>
|
||||||
|
<span class="divider-text">其他方式登录</span>
|
||||||
|
<span class="line"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="other-login-wrapper">
|
||||||
|
<div class="other-login-item">
|
||||||
|
<img src="@/assets/login_images/QQ.png" alt="" />
|
||||||
|
</div>
|
||||||
|
<div class="other-login-item">
|
||||||
|
<img src="@/assets/login_images/WeChat.png" alt="" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- <h2> 登录-欢迎</h2>
|
||||||
<el-input v-model="loginForm.userName" placeholder="用户名" />
|
<el-input v-model="loginForm.userName" placeholder="用户名" />
|
||||||
<el-input v-model="loginForm.password" placeholder="密码" show-password />
|
<el-input v-model="loginForm.password" placeholder="密码" show-password />
|
||||||
<el-button class="login-btn" type="primary" @click="login">登录</el-button>
|
<el-button class="login-btn" type="primary" @click="login">登录</el-button>
|
||||||
@@ -49,53 +52,51 @@
|
|||||||
<el-button class="login-btn" type="primary" @click="guestlogin">游客临时登录</el-button> -->
|
<el-button class="login-btn" type="primary" @click="guestlogin">游客临时登录</el-button> -->
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { reactive } from 'vue';
|
import { ref, reactive } from "vue";
|
||||||
import { useRouter, useRoute } from 'vue-router';
|
import { useRouter, useRoute } from "vue-router";
|
||||||
import useUserStore from '@/stores/user.js'
|
import useUserStore from "@/stores/user.js";
|
||||||
import useConfigStore from "@/stores/config";
|
import useConfigStore from "@/stores/config";
|
||||||
const configStore= useConfigStore();
|
import useAuths from "@/hooks/useAuths";
|
||||||
|
const configStore = useConfigStore();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
|
const { loginFun } = useAuths();
|
||||||
|
|
||||||
|
const loginFormRef = ref();
|
||||||
const rules = reactive({
|
const rules = reactive({
|
||||||
userName: [
|
userName: [{ required: true, message: "请输入账号名", trigger: "blur" }],
|
||||||
{ required: true, message: '请输入账号名', trigger: 'blur' },
|
password: [{ required: true, message: "请输入密码", trigger: "blur" }],
|
||||||
{ min: 3, message: '至少大于等于3位', trigger: 'blur' },
|
});
|
||||||
],
|
|
||||||
password:[
|
|
||||||
{ required: true, message: '请输入密码', trigger: 'blur' },
|
|
||||||
{ min: 3, message: '至少大于等于6位', trigger: 'blur' },
|
|
||||||
|
|
||||||
]})
|
|
||||||
const loginForm = reactive({
|
const loginForm = reactive({
|
||||||
userName: "cc",
|
userName: "cc",
|
||||||
password: "123456",
|
password: "123456",
|
||||||
uuid: "",
|
uuid: "",
|
||||||
code: ""
|
code: "",
|
||||||
})
|
});
|
||||||
const guestlogin = async () => {
|
const guestlogin = async () => {
|
||||||
loginForm.userName = "guest";
|
loginForm.userName = "guest";
|
||||||
loginForm.password = "123456"
|
loginForm.password = "123456";
|
||||||
await userStore.login(loginForm);
|
await userStore.login(loginForm);
|
||||||
const redirect = route.query?.redirect ?? '/index'
|
const redirect = route.query?.redirect ?? "/index";
|
||||||
router.push(redirect)
|
router.push(redirect);
|
||||||
}
|
};
|
||||||
const login = async () => {
|
const login = async (formEl) => {
|
||||||
const response = await userStore.login(loginForm).catch((e) => {
|
if (!formEl) return;
|
||||||
loginForm.password = "";
|
await formEl.validate((valid) => {
|
||||||
});
|
if (valid) {
|
||||||
if (response!=undefined) {
|
try {
|
||||||
|
loginFun(loginForm);
|
||||||
|
} catch (error) {
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: `您好${loginForm.userName},登录成功!`,
|
message: error.message,
|
||||||
type: 'success',
|
type: "error",
|
||||||
})
|
duration: 2000,
|
||||||
|
});
|
||||||
const redirect = route.query?.redirect ?? '/index'
|
}
|
||||||
router.push(redirect)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
<style src="@/assets/styles/login.scss" scoped></style>
|
<style src="@/assets/styles/login.scss" scoped></style>
|
||||||
|
|||||||
Reference in New Issue
Block a user