新增 与后端对接
This commit is contained in:
parent
910a3a5837
commit
ac2a6caa1e
|
|
@ -6,3 +6,5 @@ VITE_PUBLIC_PATH = /
|
|||
|
||||
# 开发环境路由历史模式(Hash模式传"hash"、HTML5模式传"h5"、Hash模式带base参数传"hash,base参数"、HTML5模式带base参数传"h5,base参数")
|
||||
VITE_ROUTER_HISTORY = "hash"
|
||||
|
||||
VITE_API_BASEURL = "http://localhost:5199/api"
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import removeNoMatch from "vite-plugin-router-warn";
|
|||
import { visualizer } from "rollup-plugin-visualizer";
|
||||
import removeConsole from "vite-plugin-remove-console";
|
||||
import { codeInspectorPlugin } from "code-inspector-plugin";
|
||||
import { vitePluginFakeServer } from "vite-plugin-fake-server";
|
||||
// import { vitePluginFakeServer } from "vite-plugin-fake-server";
|
||||
|
||||
export function getPluginsList(
|
||||
VITE_CDN: boolean,
|
||||
|
|
@ -41,12 +41,12 @@ export function getPluginsList(
|
|||
*/
|
||||
removeNoMatch(),
|
||||
// mock支持
|
||||
vitePluginFakeServer({
|
||||
logger: false,
|
||||
include: "mock",
|
||||
infixName: false,
|
||||
enableProd: true
|
||||
}),
|
||||
// vitePluginFakeServer({
|
||||
// logger: false,
|
||||
// include: "mock",
|
||||
// infixName: false,
|
||||
// enableProd: true
|
||||
// }),
|
||||
// svg组件化支持
|
||||
svgLoader(),
|
||||
// 自动按需加载图标
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@ export default defineFakeRoute([
|
|||
url: "/login",
|
||||
method: "post",
|
||||
response: ({ body }) => {
|
||||
if (body.username === "admin") {
|
||||
if (body.userName === "admin") {
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
avatar: "https://avatars.githubusercontent.com/u/44761321",
|
||||
username: "admin",
|
||||
nickname: "小铭",
|
||||
userName: "admin",
|
||||
nickName: "小铭",
|
||||
// 一个用户可能有多个角色
|
||||
roles: ["admin"],
|
||||
// 按钮级别权限
|
||||
|
|
@ -27,8 +27,8 @@ export default defineFakeRoute([
|
|||
success: true,
|
||||
data: {
|
||||
avatar: "https://avatars.githubusercontent.com/u/52823142",
|
||||
username: "common",
|
||||
nickname: "小林",
|
||||
userName: "common",
|
||||
nickName: "小林",
|
||||
roles: ["common"],
|
||||
permissions: ["permission:btn:add", "permission:btn:edit"],
|
||||
accessToken: "eyJhbGciOiJIUzUxMiJ9.common",
|
||||
|
|
|
|||
|
|
@ -6,5 +6,5 @@ type Result = {
|
|||
};
|
||||
|
||||
export const getAsyncRoutes = () => {
|
||||
return http.request<Result>("get", "/get-async-routes");
|
||||
return http.request<Result>("get", "/Menu/AdminMenu");
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
import { http } from "@/utils/http";
|
||||
import type { Res } from "@/utils/http/types";
|
||||
|
||||
export type UserResult = {
|
||||
success: boolean;
|
||||
data: {
|
||||
/** 头像 */
|
||||
avatar: string;
|
||||
/** 用户名 */
|
||||
username: string;
|
||||
userName: string;
|
||||
/** 昵称 */
|
||||
nickname: string;
|
||||
nickName: string;
|
||||
/** 当前登录用户的角色 */
|
||||
roles: Array<string>;
|
||||
/** 按钮级别权限 */
|
||||
|
|
@ -20,7 +19,6 @@ export type UserResult = {
|
|||
/** `accessToken`的过期时间(格式'xxxx/xx/xx xx:xx:xx') */
|
||||
expires: Date;
|
||||
};
|
||||
};
|
||||
|
||||
export type RefreshTokenResult = {
|
||||
success: boolean;
|
||||
|
|
@ -36,7 +34,7 @@ export type RefreshTokenResult = {
|
|||
|
||||
/** 登录 */
|
||||
export const getLogin = (data?: object) => {
|
||||
return http.request<UserResult>("post", "/login", { data });
|
||||
return http.request<Res<UserResult>>("post", "/Admin/Login", { data });
|
||||
};
|
||||
|
||||
/** 刷新`token` */
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ const {
|
|||
logout,
|
||||
onPanel,
|
||||
pureApp,
|
||||
username,
|
||||
userName,
|
||||
userAvatar,
|
||||
avatarsStyle,
|
||||
toggleSideBar
|
||||
|
|
@ -50,7 +50,7 @@ const {
|
|||
<el-dropdown trigger="click">
|
||||
<span class="el-dropdown-link navbar-bg-hover select-none">
|
||||
<img :src="userAvatar" :style="avatarsStyle" />
|
||||
<p v-if="username" class="dark:text-white">{{ username }}</p>
|
||||
<p v-if="userName" class="dark:text-white">{{ userName }}</p>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu class="logout">
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ const {
|
|||
logout,
|
||||
onPanel,
|
||||
getLogo,
|
||||
username,
|
||||
userName,
|
||||
userAvatar,
|
||||
backTopMenu,
|
||||
avatarsStyle
|
||||
|
|
@ -81,7 +81,7 @@ onMounted(() => {
|
|||
<el-dropdown trigger="click">
|
||||
<span class="el-dropdown-link navbar-bg-hover">
|
||||
<img :src="userAvatar" :style="avatarsStyle" />
|
||||
<p v-if="username" class="dark:text-white">{{ username }}</p>
|
||||
<p v-if="userName" class="dark:text-white">{{ userName }}</p>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu class="logout">
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ const {
|
|||
logout,
|
||||
onPanel,
|
||||
resolvePath,
|
||||
username,
|
||||
userName,
|
||||
userAvatar,
|
||||
getDivStyle,
|
||||
avatarsStyle
|
||||
|
|
@ -101,7 +101,7 @@ watch(
|
|||
<el-dropdown trigger="click">
|
||||
<span class="el-dropdown-link navbar-bg-hover select-none">
|
||||
<img :src="userAvatar" :style="avatarsStyle" />
|
||||
<p v-if="username" class="dark:text-white">{{ username }}</p>
|
||||
<p v-if="userName" class="dark:text-white">{{ userName }}</p>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu class="logout">
|
||||
|
|
|
|||
|
|
@ -88,7 +88,10 @@ const expandCloseIcon = computed(() => {
|
|||
const onlyOneChild: menuType = ref(null);
|
||||
|
||||
function hasOneShowingChild(children: menuType[] = [], parent: menuType) {
|
||||
const showingChildren = children.filter((item: any) => {
|
||||
const showingChildren =
|
||||
children == null
|
||||
? []
|
||||
: children.filter((item: any) => {
|
||||
onlyOneChild.value = item;
|
||||
return true;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -45,14 +45,14 @@ export function useNav() {
|
|||
});
|
||||
|
||||
/** 昵称(如果昵称为空则显示用户名) */
|
||||
const username = computed(() => {
|
||||
return isAllEmpty(useUserStoreHook()?.nickname)
|
||||
? useUserStoreHook()?.username
|
||||
: useUserStoreHook()?.nickname;
|
||||
const userName = computed(() => {
|
||||
return isAllEmpty(useUserStoreHook()?.nickName)
|
||||
? useUserStoreHook()?.userName
|
||||
: useUserStoreHook()?.nickName;
|
||||
});
|
||||
|
||||
const avatarsStyle = computed(() => {
|
||||
return username.value ? { marginRight: "10px" } : "";
|
||||
return userName.value ? { marginRight: "10px" } : "";
|
||||
});
|
||||
|
||||
const isCollapse = computed(() => {
|
||||
|
|
@ -149,7 +149,7 @@ export function useNav() {
|
|||
getLogo,
|
||||
isCollapse,
|
||||
pureApp,
|
||||
username,
|
||||
userName,
|
||||
userAvatar,
|
||||
avatarsStyle,
|
||||
tooltipEffect
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ const modulesRoutes = import.meta.glob("/src/views/**/*.{vue,tsx}");
|
|||
|
||||
// 动态路由
|
||||
import { getAsyncRoutes } from "@/api/routes";
|
||||
|
||||
function handRank(routeInfo: any) {
|
||||
const { name, path, parentId, meta } = routeInfo;
|
||||
return isAllEmpty(parentId)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ export const usePermissionStore = defineStore("pure-permission", {
|
|||
actions: {
|
||||
/** 组装整体路由生成的菜单 */
|
||||
handleWholeMenus(routes: any[]) {
|
||||
debugger;
|
||||
this.wholeMenus = filterNoPermissionTree(
|
||||
filterTree(ascending(this.constantMenus.concat(routes)))
|
||||
);
|
||||
|
|
|
|||
|
|
@ -15,15 +15,16 @@ import {
|
|||
} from "@/api/user";
|
||||
import { useMultiTagsStoreHook } from "./multiTags";
|
||||
import { type DataInfo, setToken, removeToken, userKey } from "@/utils/auth";
|
||||
import type { Res } from "@/utils/http/types";
|
||||
|
||||
export const useUserStore = defineStore("pure-user", {
|
||||
state: (): userType => ({
|
||||
// 头像
|
||||
avatar: storageLocal().getItem<DataInfo<number>>(userKey)?.avatar ?? "",
|
||||
// 用户名
|
||||
username: storageLocal().getItem<DataInfo<number>>(userKey)?.username ?? "",
|
||||
userName: storageLocal().getItem<DataInfo<number>>(userKey)?.userName ?? "",
|
||||
// 昵称
|
||||
nickname: storageLocal().getItem<DataInfo<number>>(userKey)?.nickname ?? "",
|
||||
nickName: storageLocal().getItem<DataInfo<number>>(userKey)?.nickName ?? "",
|
||||
// 页面级别权限
|
||||
roles: storageLocal().getItem<DataInfo<number>>(userKey)?.roles ?? [],
|
||||
// 按钮级别权限
|
||||
|
|
@ -40,12 +41,12 @@ export const useUserStore = defineStore("pure-user", {
|
|||
this.avatar = avatar;
|
||||
},
|
||||
/** 存储用户名 */
|
||||
SET_USERNAME(username: string) {
|
||||
this.username = username;
|
||||
SET_USERNAME(userName: string) {
|
||||
this.userName = userName;
|
||||
},
|
||||
/** 存储昵称 */
|
||||
SET_NICKNAME(nickname: string) {
|
||||
this.nickname = nickname;
|
||||
SET_NICKNAME(nickName: string) {
|
||||
this.nickName = nickName;
|
||||
},
|
||||
/** 存储角色 */
|
||||
SET_ROLES(roles: Array<string>) {
|
||||
|
|
@ -65,10 +66,10 @@ export const useUserStore = defineStore("pure-user", {
|
|||
},
|
||||
/** 登入 */
|
||||
async loginByUsername(data) {
|
||||
return new Promise<UserResult>((resolve, reject) => {
|
||||
return new Promise<Res<UserResult>>((resolve, reject) => {
|
||||
getLogin(data)
|
||||
.then(data => {
|
||||
if (data?.success) setToken(data.data);
|
||||
if (data?.code == 200) setToken(data.data);
|
||||
resolve(data);
|
||||
})
|
||||
.catch(error => {
|
||||
|
|
@ -78,7 +79,7 @@ export const useUserStore = defineStore("pure-user", {
|
|||
},
|
||||
/** 前端登出(不调用接口) */
|
||||
logOut() {
|
||||
this.username = "";
|
||||
this.userName = "";
|
||||
this.roles = [];
|
||||
this.permissions = [];
|
||||
removeToken();
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ export type setType = {
|
|||
|
||||
export type userType = {
|
||||
avatar?: string;
|
||||
username?: string;
|
||||
nickname?: string;
|
||||
userName?: string;
|
||||
nickName?: string;
|
||||
roles?: Array<string>;
|
||||
permissions?: Array<string>;
|
||||
isRemembered?: boolean;
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@ export interface DataInfo<T> {
|
|||
/** 头像 */
|
||||
avatar?: string;
|
||||
/** 用户名 */
|
||||
username?: string;
|
||||
userName?: string;
|
||||
/** 昵称 */
|
||||
nickname?: string;
|
||||
nickName?: string;
|
||||
/** 当前登录用户的角色 */
|
||||
roles?: Array<string>;
|
||||
/** 当前登录用户的按钮级别权限 */
|
||||
|
|
@ -43,7 +43,7 @@ export function getToken(): DataInfo<number> {
|
|||
* @description 设置`token`以及一些必要信息并采用无感刷新`token`方案
|
||||
* 无感刷新:后端返回`accessToken`(访问接口使用的`token`)、`refreshToken`(用于调用刷新`accessToken`的接口时所需的`token`,`refreshToken`的过期时间(比如30天)应大于`accessToken`的过期时间(比如2小时))、`expires`(`accessToken`的过期时间)
|
||||
* 将`accessToken`、`expires`、`refreshToken`这三条信息放在key值为authorized-token的cookie里(过期自动销毁)
|
||||
* 将`avatar`、`username`、`nickname`、`roles`、`permissions`、`refreshToken`、`expires`这七条信息放在key值为`user-info`的localStorage里(利用`multipleTabsKey`当浏览器完全关闭后自动销毁)
|
||||
* 将`avatar`、`userName`、`nickName`、`roles`、`permissions`、`refreshToken`、`expires`这七条信息放在key值为`user-info`的localStorage里(利用`multipleTabsKey`当浏览器完全关闭后自动销毁)
|
||||
*/
|
||||
export function setToken(data: DataInfo<Date>) {
|
||||
let expires = 0;
|
||||
|
|
@ -68,47 +68,47 @@ export function setToken(data: DataInfo<Date>) {
|
|||
: {}
|
||||
);
|
||||
|
||||
function setUserKey({ avatar, username, nickname, roles, permissions }) {
|
||||
function setUserKey({ avatar, userName, nickName, roles, permissions }) {
|
||||
useUserStoreHook().SET_AVATAR(avatar);
|
||||
useUserStoreHook().SET_USERNAME(username);
|
||||
useUserStoreHook().SET_NICKNAME(nickname);
|
||||
useUserStoreHook().SET_USERNAME(userName);
|
||||
useUserStoreHook().SET_NICKNAME(nickName);
|
||||
useUserStoreHook().SET_ROLES(roles);
|
||||
useUserStoreHook().SET_PERMS(permissions);
|
||||
storageLocal().setItem(userKey, {
|
||||
refreshToken,
|
||||
expires,
|
||||
avatar,
|
||||
username,
|
||||
nickname,
|
||||
userName,
|
||||
nickName,
|
||||
roles,
|
||||
permissions
|
||||
});
|
||||
}
|
||||
|
||||
if (data.username && data.roles) {
|
||||
const { username, roles } = data;
|
||||
if (data.userName && data.roles) {
|
||||
const { userName, roles } = data;
|
||||
setUserKey({
|
||||
avatar: data?.avatar ?? "",
|
||||
username,
|
||||
nickname: data?.nickname ?? "",
|
||||
userName,
|
||||
nickName: data?.nickName ?? "",
|
||||
roles,
|
||||
permissions: data?.permissions ?? []
|
||||
});
|
||||
} else {
|
||||
const avatar =
|
||||
storageLocal().getItem<DataInfo<number>>(userKey)?.avatar ?? "";
|
||||
const username =
|
||||
storageLocal().getItem<DataInfo<number>>(userKey)?.username ?? "";
|
||||
const nickname =
|
||||
storageLocal().getItem<DataInfo<number>>(userKey)?.nickname ?? "";
|
||||
const userName =
|
||||
storageLocal().getItem<DataInfo<number>>(userKey)?.userName ?? "";
|
||||
const nickName =
|
||||
storageLocal().getItem<DataInfo<number>>(userKey)?.nickName ?? "";
|
||||
const roles =
|
||||
storageLocal().getItem<DataInfo<number>>(userKey)?.roles ?? [];
|
||||
const permissions =
|
||||
storageLocal().getItem<DataInfo<number>>(userKey)?.permissions ?? [];
|
||||
setUserKey({
|
||||
avatar,
|
||||
username,
|
||||
nickname,
|
||||
userName,
|
||||
nickName,
|
||||
roles,
|
||||
permissions
|
||||
});
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import { useUserStoreHook } from "@/store/modules/user";
|
|||
|
||||
// 相关配置请参考:www.axios-js.com/zh-cn/docs/#axios-request-config-1
|
||||
const defaultConfig: AxiosRequestConfig = {
|
||||
baseURL: import.meta.env.VITE_API_BASEURL,
|
||||
// 请求超时时间
|
||||
timeout: 10000,
|
||||
headers: {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,11 @@ export interface PureHttpError extends AxiosError {
|
|||
isCancelRequest?: boolean;
|
||||
}
|
||||
|
||||
export type Res<T> = {
|
||||
code: number;
|
||||
data: T;
|
||||
message: string;
|
||||
};
|
||||
export interface PureHttpResponse extends AxiosResponse {
|
||||
config: PureHttpRequestConfig;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { removeToken, setToken, type DataInfo } from "./auth";
|
|||
import { subBefore, getQueryMap } from "@pureadmin/utils";
|
||||
|
||||
/**
|
||||
* 简版前端单点登录,根据实际业务自行编写,平台启动后本地可以跳后面这个链接进行测试 http://localhost:8848/#/permission/page/index?username=sso&roles=admin&accessToken=eyJhbGciOiJIUzUxMiJ9.admin
|
||||
* 简版前端单点登录,根据实际业务自行编写,平台启动后本地可以跳后面这个链接进行测试 http://localhost:8848/#/permission/page/index?userName=sso&roles=admin&accessToken=eyJhbGciOiJIUzUxMiJ9.admin
|
||||
* 划重点:
|
||||
* 判断是否为单点登录,不为则直接返回不再进行任何逻辑处理,下面是单点登录后的逻辑处理
|
||||
* 1.清空本地旧信息;
|
||||
|
|
@ -13,7 +13,7 @@ import { subBefore, getQueryMap } from "@pureadmin/utils";
|
|||
(function () {
|
||||
// 获取 url 中的参数
|
||||
const params = getQueryMap(location.href) as DataInfo<Date>;
|
||||
const must = ["username", "roles", "accessToken"];
|
||||
const must = ["userName", "roles", "accessToken"];
|
||||
const mustLength = must.length;
|
||||
if (Object.keys(params).length !== mustLength) return;
|
||||
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@ dataThemeChange(overallStyle.value);
|
|||
const { title } = useNav();
|
||||
|
||||
const ruleForm = reactive({
|
||||
username: "admin",
|
||||
password: "admin123"
|
||||
account: "admin",
|
||||
password: "123456"
|
||||
});
|
||||
|
||||
const onLogin = async (formEl: FormInstance | undefined) => {
|
||||
|
|
@ -48,11 +48,11 @@ const onLogin = async (formEl: FormInstance | undefined) => {
|
|||
loading.value = true;
|
||||
useUserStoreHook()
|
||||
.loginByUsername({
|
||||
username: ruleForm.username,
|
||||
account: ruleForm.account,
|
||||
password: ruleForm.password
|
||||
})
|
||||
.then(res => {
|
||||
if (res.success) {
|
||||
if ((res.code = 200)) {
|
||||
// 获取后端路由
|
||||
return initRouter().then(() => {
|
||||
disabled.value = true;
|
||||
|
|
@ -112,12 +112,14 @@ useEventListener(document, "keydown", ({ code }) => {
|
|||
<h2 class="outline-hidden">{{ title }}</h2>
|
||||
</Motion>
|
||||
|
||||
<el-form
|
||||
<!-- <el-form
|
||||
ref="ruleFormRef"
|
||||
:model="ruleForm"
|
||||
:rules="loginRules"
|
||||
size="large"
|
||||
>
|
||||
> -->
|
||||
|
||||
<el-form ref="ruleFormRef" :model="ruleForm" size="large">
|
||||
<Motion :delay="100">
|
||||
<el-form-item
|
||||
:rules="[
|
||||
|
|
@ -127,10 +129,10 @@ useEventListener(document, "keydown", ({ code }) => {
|
|||
trigger: 'blur'
|
||||
}
|
||||
]"
|
||||
prop="username"
|
||||
prop="account"
|
||||
>
|
||||
<el-input
|
||||
v-model="ruleForm.username"
|
||||
v-model="ruleForm.account"
|
||||
clearable
|
||||
placeholder="账号"
|
||||
:prefix-icon="useRenderIcon(User)"
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ const elStyle = computed((): CSSProperties => {
|
|||
};
|
||||
});
|
||||
|
||||
const username = ref(useUserStoreHook()?.username);
|
||||
const userName = ref(useUserStoreHook()?.userName);
|
||||
|
||||
const options = [
|
||||
{
|
||||
|
|
@ -31,9 +31,9 @@ const options = [
|
|||
|
||||
function onChange() {
|
||||
useUserStoreHook()
|
||||
.loginByUsername({ username: username.value, password: "admin123" })
|
||||
.loginByUsername({ userName: userName.value, password: "admin123" })
|
||||
.then(res => {
|
||||
if (res.success) {
|
||||
if (res.code === 200) {
|
||||
storageLocal().removeItem("async-routes");
|
||||
usePermissionStoreHook().clearAllCachePage();
|
||||
initRouter();
|
||||
|
|
@ -50,10 +50,10 @@ function onChange() {
|
|||
<el-card shadow="never" :style="elStyle">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>当前角色:{{ username }}</span>
|
||||
<span>当前角色:{{ userName }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-select v-model="username" class="w-[160px]!" @change="onChange">
|
||||
<el-select v-model="userName" class="w-[160px]!" @change="onChange">
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ declare global {
|
|||
showLogo?: boolean;
|
||||
showModel?: string;
|
||||
menuSearchHistory?: number;
|
||||
username?: string;
|
||||
userName?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue