Compare commits
No commits in common. "19757a9a495c7b9a4456fb1b18f1771bf81d9572" and "5b5f0638b3fb33cb3ebcbb091426770cb023ecd3" have entirely different histories.
19757a9a49
...
5b5f0638b3
@ -9,4 +9,4 @@ VITE_APP_PORT = 8090
|
|||||||
VITE_APP_BASE_API = '/api'
|
VITE_APP_BASE_API = '/api'
|
||||||
|
|
||||||
# proxy代理配置
|
# proxy代理配置
|
||||||
VITE_APP_API_URL = 'http://192.168.1.7:12500/'
|
VITE_APP_API_URL = ' http://192.168.1.7:12500/'
|
||||||
|
|||||||
@ -6,4 +6,4 @@ VITE_APP_PORT = 3000
|
|||||||
VITE_APP_BASE_API = '/zsqy'
|
VITE_APP_BASE_API = '/zsqy'
|
||||||
|
|
||||||
# proxy代理配置
|
# proxy代理配置
|
||||||
VITE_APP_API_URL = "http://175.27.240.186:12500"
|
VITE_APP_API_URL = ""
|
||||||
|
|||||||
@ -2,8 +2,6 @@ import axios, { AxiosResponse, AxiosRequestConfig } from "axios";
|
|||||||
import { ResultEnum } from "@/enums/httpEnum";
|
import { ResultEnum } from "@/enums/httpEnum";
|
||||||
// import { ErrorPageNameMap } from "@/enums/pageEnum";
|
// import { ErrorPageNameMap } from "@/enums/pageEnum";
|
||||||
// import { redirectErrorPage } from "@/utils";
|
// import { redirectErrorPage } from "@/utils";
|
||||||
import { storage } from "@/utils";
|
|
||||||
import { StorageEnum } from "@/enums/storageEnum";
|
|
||||||
|
|
||||||
const axiosInstance = axios.create({
|
const axiosInstance = axios.create({
|
||||||
baseURL: import.meta.env.DEV
|
baseURL: import.meta.env.DEV
|
||||||
@ -15,7 +13,6 @@ const axiosInstance = axios.create({
|
|||||||
// 请求拦截器
|
// 请求拦截器
|
||||||
axiosInstance.interceptors.request.use(
|
axiosInstance.interceptors.request.use(
|
||||||
(config) => {
|
(config) => {
|
||||||
config.headers.Authorization = storage.get(StorageEnum.ZS_ACCESS_TOKEN);
|
|
||||||
return config;
|
return config;
|
||||||
},
|
},
|
||||||
(error: AxiosRequestConfig) => {
|
(error: AxiosRequestConfig) => {
|
||||||
@ -26,7 +23,10 @@ axiosInstance.interceptors.request.use(
|
|||||||
// 响应拦截器
|
// 响应拦截器
|
||||||
axiosInstance.interceptors.response.use(
|
axiosInstance.interceptors.response.use(
|
||||||
(res: AxiosResponse) => {
|
(res: AxiosResponse) => {
|
||||||
const { message, success } = res.data as IResponse;
|
const { message, success } = res.data as {
|
||||||
|
success: boolean;
|
||||||
|
message: string;
|
||||||
|
};
|
||||||
|
|
||||||
// 如果是文件流,直接过
|
// 如果是文件流,直接过
|
||||||
if (res.config.responseType === "blob") return Promise.resolve(res.data);
|
if (res.config.responseType === "blob") return Promise.resolve(res.data);
|
||||||
|
|||||||
@ -17,6 +17,9 @@ export const get = (url: string, params?: object) => {
|
|||||||
url: url,
|
url: url,
|
||||||
method: RequestHttpEnum.GET,
|
method: RequestHttpEnum.GET,
|
||||||
params: params,
|
params: params,
|
||||||
|
headers: {
|
||||||
|
Authorization: "7df1bd95-bf13-4660-a07d-90b8b1b314e8",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -27,6 +30,7 @@ export const post = (url: string, data?: object, headersType?: string) => {
|
|||||||
data: data,
|
data: data,
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": headersType || ContentTypeEnum.JSON,
|
"Content-Type": headersType || ContentTypeEnum.JSON,
|
||||||
|
Authorization: "7df1bd95-bf13-4660-a07d-90b8b1b314e8",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
1
src/api/system/index.ts
Normal file
1
src/api/system/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from "./menu";
|
||||||
@ -1,25 +0,0 @@
|
|||||||
import { get, post } from "@/api/http";
|
|
||||||
|
|
||||||
const fix = "/role";
|
|
||||||
|
|
||||||
const url = {
|
|
||||||
insert: `${fix}/insert`,
|
|
||||||
page: `${fix}/page`,
|
|
||||||
update: `${fix}/update`,
|
|
||||||
delete: `${fix}/delete`,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const insertRule = (params: Object) => {
|
|
||||||
return post(url.insert, params);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getRuleList = (params: Object) => {
|
|
||||||
return get(url.page, params);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const updateRule = (params: Object) => {
|
|
||||||
return post(url.update, params);
|
|
||||||
};
|
|
||||||
export const deleteRule = (params: Object) => {
|
|
||||||
return post(url.delete, params);
|
|
||||||
};
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
import { get, post } from "@/api/http";
|
|
||||||
|
|
||||||
const fix = "/roleMenu";
|
|
||||||
|
|
||||||
const url = {
|
|
||||||
queryMenuByRole: `${fix}/queryMenuByRole`, // 根据角色查询菜单
|
|
||||||
save: `${fix}/save`, // 保存角色菜单
|
|
||||||
};
|
|
||||||
|
|
||||||
export const queryMenuByRole = (params: Object) => {
|
|
||||||
return get(url.queryMenuByRole, params);
|
|
||||||
};
|
|
||||||
export const saveRoleMenu = (params: Object) => {
|
|
||||||
return post(url.save, params);
|
|
||||||
};
|
|
||||||
@ -1,36 +0,0 @@
|
|||||||
import { get, post } from "@/api/http";
|
|
||||||
|
|
||||||
const fix = "/user";
|
|
||||||
|
|
||||||
const url = {
|
|
||||||
login: `${fix}/login`,
|
|
||||||
userInfo: `${fix}/userInfo`,
|
|
||||||
insert: `${fix}/insert`,
|
|
||||||
page: `${fix}/page`,
|
|
||||||
update: `${fix}/update`,
|
|
||||||
delete: `${fix}/delete`,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const login = (params: Object) => {
|
|
||||||
return post(url.login, params);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getUserInfo = () => {
|
|
||||||
return get(url.userInfo);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const insertUser = (params: Object) => {
|
|
||||||
return post(url.insert, params);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getUserList = (params: Object) => {
|
|
||||||
return get(url.page, params);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const updateUser = (params: Object) => {
|
|
||||||
return post(url.update, params);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const deleteUser = (params: Object) => {
|
|
||||||
return post(url.delete, params);
|
|
||||||
};
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
// 用户角色关系
|
|
||||||
import { get, post } from "@/api/http";
|
|
||||||
const fix = "/userRole";
|
|
||||||
const url = {
|
|
||||||
save: `${fix}/save`,
|
|
||||||
queryMenuTree: `${fix}/queryMenuTree `,
|
|
||||||
};
|
|
||||||
export const saveUserRole = (params: Object) => {
|
|
||||||
return post(url.save, params);
|
|
||||||
};
|
|
||||||
export const queryUserRole = (params: Object) => {
|
|
||||||
return get(url.queryMenuTree, params);
|
|
||||||
};
|
|
||||||
@ -47,14 +47,12 @@ export function useDataSource(
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
const { request, pagination, beforeRequest, afterRequest }: any =
|
const { request, pagination, beforeRequest, afterRequest }: any =
|
||||||
unref(propsRef);
|
unref(propsRef);
|
||||||
|
|
||||||
if (!request) return;
|
if (!request) return;
|
||||||
//组装分页信息
|
//组装分页信息
|
||||||
const pageField = APISETTING.pageField;
|
const pageField = APISETTING.pageField;
|
||||||
const sizeField = APISETTING.sizeField;
|
const sizeField = APISETTING.sizeField;
|
||||||
const totalField = APISETTING.totalField;
|
const totalField = APISETTING.totalField;
|
||||||
const listField = APISETTING.listField;
|
const listField = APISETTING.listField;
|
||||||
|
|
||||||
const itemCount = APISETTING.countField;
|
const itemCount = APISETTING.countField;
|
||||||
let pageParams = {};
|
let pageParams = {};
|
||||||
const { page = 1, pageSize = 10 } = unref(
|
const { page = 1, pageSize = 10 } = unref(
|
||||||
@ -73,7 +71,7 @@ export function useDataSource(
|
|||||||
|
|
||||||
let params = {
|
let params = {
|
||||||
...pageParams,
|
...pageParams,
|
||||||
...opt,
|
// ...opt,
|
||||||
};
|
};
|
||||||
// console.log(opt);
|
// console.log(opt);
|
||||||
|
|
||||||
@ -82,7 +80,6 @@ export function useDataSource(
|
|||||||
params = (await beforeRequest(params)) || params;
|
params = (await beforeRequest(params)) || params;
|
||||||
}
|
}
|
||||||
const res = await request(params);
|
const res = await request(params);
|
||||||
|
|
||||||
const resultTotal = res[totalField];
|
const resultTotal = res[totalField];
|
||||||
const currentPage = res[pageField];
|
const currentPage = res[pageField];
|
||||||
const total = res[itemCount];
|
const total = res[itemCount];
|
||||||
|
|||||||
@ -1,13 +0,0 @@
|
|||||||
import logoImage from "@/assets/images/logo.png";
|
|
||||||
interface WebsiteConfig {
|
|
||||||
title: string;
|
|
||||||
logo: string;
|
|
||||||
loginImage: string;
|
|
||||||
loginDesc: string;
|
|
||||||
}
|
|
||||||
export const websiteConfig: WebsiteConfig = Object.freeze({
|
|
||||||
title: "中盛起元基础框架",
|
|
||||||
logo: logoImage,
|
|
||||||
loginImage: logoImage,
|
|
||||||
loginDesc: "中盛起元基础框架",
|
|
||||||
});
|
|
||||||
@ -2,7 +2,6 @@
|
|||||||
* @description: 请求结果集
|
* @description: 请求结果集
|
||||||
*/
|
*/
|
||||||
export enum ResultEnum {
|
export enum ResultEnum {
|
||||||
STATUS = 200,
|
|
||||||
DATA_SUCCESS = 0,
|
DATA_SUCCESS = 0,
|
||||||
SUCCESS = 2000,
|
SUCCESS = 2000,
|
||||||
SERVER_ERROR = 500,
|
SERVER_ERROR = 500,
|
||||||
|
|||||||
@ -1,17 +1,12 @@
|
|||||||
import { ResultEnum } from "@/enums/httpEnum";
|
import { ResultEnum } from "@/enums/httpEnum";
|
||||||
|
|
||||||
export enum PageEnum {
|
export enum PageEnum {
|
||||||
// 登录
|
|
||||||
BASE_LOGIN = "/login",
|
|
||||||
BASE_LOGIN_NAME = "lOGIN",
|
|
||||||
//重定向
|
|
||||||
REDIRECT = "/redirect",
|
|
||||||
REDIRECT_NAME = "Redirect",
|
|
||||||
// 首页
|
|
||||||
BASE_HOME = "/system/menu",
|
|
||||||
// 错误
|
// 错误
|
||||||
ERROR_PAGE_NAME_403 = "ErrorPage403",
|
ERROR_PAGE_NAME_403 = "ErrorPage403",
|
||||||
ERROR_PAGE_NAME_404 = "ErrorPage404",
|
ERROR_PAGE_NAME_404 = "ErrorPage404",
|
||||||
|
BASE_LOGIN = "/login",
|
||||||
|
REDIRECT = "/redirect",
|
||||||
|
REDIRECT_NAME = "Redirect",
|
||||||
// ERROR_PAGE_NAME_500 = "ErrorPage500",
|
// ERROR_PAGE_NAME_500 = "ErrorPage500",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,9 +2,7 @@ export enum StorageEnum {
|
|||||||
// 全局设置
|
// 全局设置
|
||||||
ZS_SYSTEM_SETTING_STORE = "YSTEM_SETTING",
|
ZS_SYSTEM_SETTING_STORE = "YSTEM_SETTING",
|
||||||
// token 等信息
|
// token 等信息
|
||||||
ZS_ACCESS_TOKEN = "ACCESS_TOKEN",
|
ZS_ACCESS_TOKEN_STORE = "ACCESS_TOKEN",
|
||||||
// 登录信息
|
// 登录信息
|
||||||
ZS_LOGIN_INFO_STORE = "LOGIN_INFO",
|
ZS_LOGIN_INFO_STORE = "LOGIN_INFO",
|
||||||
// 当前用户信息
|
|
||||||
ZS_CURRENT_USER = "CURRENT_USER",
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { UserOutlined } from "@vicons/antd";
|
import { UserOutlined } from "@vicons/antd";
|
||||||
import { useUserStore } from "@/store/modules/user";
|
import { logout } from "@/utils";
|
||||||
const userStore = useUserStore();
|
|
||||||
//头像下拉菜单
|
//头像下拉菜单
|
||||||
const avatarSelect = (key) => {
|
const avatarSelect = (key) => {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
@ -20,7 +19,7 @@ const avatarOptions = [
|
|||||||
|
|
||||||
// 退出登录
|
// 退出登录
|
||||||
const doLogout = () => {
|
const doLogout = () => {
|
||||||
userStore.logout();
|
logout();
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -13,12 +13,11 @@
|
|||||||
<aside>
|
<aside>
|
||||||
<n-space vertical class="sider-top"> 中盛起元基础框架 </n-space>
|
<n-space vertical class="sider-top"> 中盛起元基础框架 </n-space>
|
||||||
<n-menu
|
<n-menu
|
||||||
:options="menus"
|
:options="generatorMenu(asyncRoutes)"
|
||||||
:collapsed-width="64"
|
:collapsed-width="60"
|
||||||
:collapsed-icon-size="20"
|
:collapsed-icon-size="22"
|
||||||
:indent="24"
|
|
||||||
:expanded-keys="state.openKeys"
|
:expanded-keys="state.openKeys"
|
||||||
:value="getSelectedKeys"
|
:value="currentRoute.meta?.activeMenu"
|
||||||
@update:value="clickMenuItem"
|
@update:value="clickMenuItem"
|
||||||
@update:expanded-keys="menuExpanded"
|
@update:expanded-keys="menuExpanded"
|
||||||
/>
|
/>
|
||||||
@ -29,9 +28,8 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
|
import { asyncRoutes } from "@/router";
|
||||||
import { routerTurnByName, generatorMenu } from "@/utils";
|
import { routerTurnByName, generatorMenu } from "@/utils";
|
||||||
import { useAsyncRouteStore } from "@/store/modules/asyncRoute";
|
|
||||||
|
|
||||||
// 当前路由
|
// 当前路由
|
||||||
const currentRoute = useRoute();
|
const currentRoute = useRoute();
|
||||||
// 获取当前打开的子菜单
|
// 获取当前打开的子菜单
|
||||||
@ -39,49 +37,12 @@ const matched = currentRoute.matched;
|
|||||||
const getOpenKeys =
|
const getOpenKeys =
|
||||||
matched && matched.length ? matched.map((item) => item.name) : [];
|
matched && matched.length ? matched.map((item) => item.name) : [];
|
||||||
|
|
||||||
const asyncRouteStore = useAsyncRouteStore();
|
|
||||||
const menus = ref<any[]>([]);
|
|
||||||
const selectedKeys = ref<string>(currentRoute.name as string);
|
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
openKeys: getOpenKeys,
|
openKeys: getOpenKeys,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 跟随页面路由变化,切换菜单选中状态
|
|
||||||
watch(
|
|
||||||
() => currentRoute.fullPath,
|
|
||||||
() => {
|
|
||||||
console.log(123);
|
|
||||||
updateMenu();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
function updateSelectedKeys() {
|
|
||||||
const matched = currentRoute.matched;
|
|
||||||
state.openKeys = matched.map((item) => item.name);
|
|
||||||
const activeMenu: string = (currentRoute.meta?.activeMenu as string) || "";
|
|
||||||
selectedKeys.value = activeMenu
|
|
||||||
? (activeMenu as string)
|
|
||||||
: (currentRoute.name as string);
|
|
||||||
|
|
||||||
console.log(selectedKeys.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateMenu() {
|
|
||||||
menus.value = generatorMenu(asyncRouteStore.getMenus);
|
|
||||||
updateSelectedKeys();
|
|
||||||
}
|
|
||||||
|
|
||||||
const getSelectedKeys = computed(() => {
|
|
||||||
return unref(selectedKeys);
|
|
||||||
});
|
|
||||||
|
|
||||||
const clickMenuItem = (key: string) => {
|
const clickMenuItem = (key: string) => {
|
||||||
if (/http(s)?:/.test(key)) {
|
routerTurnByName(key);
|
||||||
window.open(key);
|
|
||||||
} else {
|
|
||||||
routerTurnByName(key);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//展开菜单
|
//展开菜单
|
||||||
@ -102,6 +63,7 @@ function menuExpanded(openKeys: string[]) {
|
|||||||
function findChildrenLen(key: string) {
|
function findChildrenLen(key: string) {
|
||||||
if (!key) return false;
|
if (!key) return false;
|
||||||
const subRouteChildren: string[] = [];
|
const subRouteChildren: string[] = [];
|
||||||
|
const menus = generatorMenu(asyncRoutes);
|
||||||
for (const { children, key } of unref(menus)) {
|
for (const { children, key } of unref(menus)) {
|
||||||
if (children && children.length) {
|
if (children && children.length) {
|
||||||
subRouteChildren.push(key as string);
|
subRouteChildren.push(key as string);
|
||||||
@ -110,9 +72,7 @@ function findChildrenLen(key: string) {
|
|||||||
return subRouteChildren.includes(key);
|
return subRouteChildren.includes(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
// onMounted(() => {});
|
||||||
updateMenu();
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@ -122,5 +82,6 @@ onMounted(() => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
|
// margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
import { RouteRecordRaw } from "vue-router";
|
import { RouteRecordRaw } from "vue-router";
|
||||||
import type { AppRouteRecordRaw } from "@/router/types";
|
import type { AppRouteRecordRaw } from "@/router/types";
|
||||||
import { ErrorPage404, ErrorPage403, Layout } from "@/router/constant";
|
import { ErrorPage404, ErrorPage403 } from "@/router/constant";
|
||||||
import { PageEnum } from "@/enums/pageEnum";
|
import { PageEnum } from "@/enums/pageEnum";
|
||||||
// import { GoReload } from "@/components/GoReload";
|
// import { GoReload } from "@/components/GoReload";
|
||||||
|
|
||||||
export const LoginRoute: RouteRecordRaw = {
|
export const LoginRoute: RouteRecordRaw = {
|
||||||
path: PageEnum.BASE_LOGIN,
|
path: "/login",
|
||||||
name: PageEnum.BASE_LOGIN_NAME,
|
name: "Login",
|
||||||
component: () => import("@/views/login/index.vue"),
|
component: () => import("@/views/login/index.vue"),
|
||||||
meta: {
|
meta: {
|
||||||
title: "登录",
|
title: "登录",
|
||||||
@ -40,25 +40,14 @@ export const HttpErrorPage: RouteRecordRaw[] = [
|
|||||||
// },
|
// },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const ErrorPageRoute: RouteRecordRaw = {
|
export const ErrorPageRoute: AppRouteRecordRaw = {
|
||||||
path: "/:path(.*)*",
|
path: "/:path(.*)*",
|
||||||
name: "ErrorPage",
|
name: "ErrorPage",
|
||||||
component: Layout,
|
component: ErrorPage404,
|
||||||
meta: {
|
meta: {
|
||||||
title: "ErrorPage",
|
title: PageEnum.ERROR_PAGE_NAME_404,
|
||||||
// hideBreadcrumb: true,
|
hideBreadcrumb: true,
|
||||||
},
|
},
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: "/:path(.*)*",
|
|
||||||
name: "ErrorPageSon",
|
|
||||||
component: ErrorPage404,
|
|
||||||
meta: {
|
|
||||||
title: "ErrorPage",
|
|
||||||
// hideBreadcrumb: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// export const ReloadRoute: AppRouteRecordRaw = {
|
// export const ReloadRoute: AppRouteRecordRaw = {
|
||||||
@ -70,23 +59,22 @@ export const ErrorPageRoute: RouteRecordRaw = {
|
|||||||
// },
|
// },
|
||||||
// };
|
// };
|
||||||
|
|
||||||
export const RedirectRoute: AppRouteRecordRaw = {
|
// export const RedirectRoute: AppRouteRecordRaw = {
|
||||||
path: PageEnum.REDIRECT,
|
// path: PageEnum.REDIRECT,
|
||||||
name: PageEnum.REDIRECT_NAME,
|
// name: PageEnum.REDIRECT_NAME,
|
||||||
component: Layout,
|
// component: Layout,
|
||||||
meta: {
|
// meta: {
|
||||||
title: PageEnum.REDIRECT_NAME,
|
// title: PageEnum.REDIRECT_NAME,
|
||||||
hideBreadcrumb: true,
|
// },
|
||||||
},
|
// children: [
|
||||||
children: [
|
// {
|
||||||
{
|
// path: "/redirect/:path(.*)",
|
||||||
path: "/redirect/:path(.*)",
|
// name: PageEnum.REDIRECT_NAME,
|
||||||
name: PageEnum.REDIRECT_NAME,
|
// component: () => import("@/views/redirect/index.vue"),
|
||||||
component: () => import("@/views/redirect/index.vue"),
|
// meta: {
|
||||||
meta: {
|
// title: PageEnum.REDIRECT_NAME,
|
||||||
title: PageEnum.REDIRECT_NAME,
|
// hideBreadcrumb: true,
|
||||||
hideBreadcrumb: true,
|
// },
|
||||||
},
|
// },
|
||||||
},
|
// ],
|
||||||
],
|
// };
|
||||||
};
|
|
||||||
|
|||||||
@ -1,126 +0,0 @@
|
|||||||
import { getMenuTree } from "@/api/system/menu";
|
|
||||||
import { constantRouterIcon } from "./icons";
|
|
||||||
import { RouteRecordRaw } from "vue-router";
|
|
||||||
import { Layout, ParentLayout } from "@/router/constant";
|
|
||||||
// import { storage } from "@/utils";
|
|
||||||
// import { StorageEnum } from "@/enums/storageEnum";
|
|
||||||
import type { AppRouteRecordRaw } from "@/router/types";
|
|
||||||
|
|
||||||
const Iframe = () => import("@/views/iframe/index.vue");
|
|
||||||
const LayoutMap = new Map<string, () => Promise<typeof import("*.vue")>>();
|
|
||||||
|
|
||||||
LayoutMap.set("Layout", Layout);
|
|
||||||
LayoutMap.set("iframe", Iframe);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 格式化 后端 结构信息并递归生成层级路由表
|
|
||||||
* @param routerMap
|
|
||||||
* @param parent
|
|
||||||
* @returns {*}
|
|
||||||
*/
|
|
||||||
export const generateRoutes = (routerMap, parent?): any[] => {
|
|
||||||
return routerMap.map((item) => {
|
|
||||||
const currentRoute: any = {
|
|
||||||
// 路由地址 动态拼接生成如 /dashboard/workplace
|
|
||||||
path: `${(parent && parent.path) ?? ""}/${item.path}`,
|
|
||||||
// 路由名称,建议唯一
|
|
||||||
name: item.name ?? "",
|
|
||||||
key: item.name ?? "",
|
|
||||||
// 该路由对应页面的 组件
|
|
||||||
component: item.component,
|
|
||||||
// meta: 页面标题, 菜单图标, 页面权限(供指令权限用,可去掉)
|
|
||||||
meta: {
|
|
||||||
...item.meta,
|
|
||||||
label: item.meta.title,
|
|
||||||
icon: constantRouterIcon[item.meta.icon] || null,
|
|
||||||
permissions: item.meta.permissions || null,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// 为了防止出现后端返回结果不规范,处理有可能出现拼接出两个 反斜杠
|
|
||||||
currentRoute.path = currentRoute.path.replace("//", "/");
|
|
||||||
// 重定向
|
|
||||||
item.redirect && (currentRoute.redirect = item.redirect);
|
|
||||||
// 是否有子菜单,并递归处理
|
|
||||||
if (item.children && item.children.length > 0) {
|
|
||||||
//如果未定义 redirect 默认第一个子路由为 redirect
|
|
||||||
!item.redirect &&
|
|
||||||
(currentRoute.redirect = `${item.path}/${item.children[0].path}`);
|
|
||||||
// Recursion
|
|
||||||
currentRoute.children = generateRoutes(item.children, currentRoute);
|
|
||||||
}
|
|
||||||
return currentRoute;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 动态生成菜单
|
|
||||||
* @returns {Promise<Router>}
|
|
||||||
*/
|
|
||||||
export const generateDynamicRoutes = async (): Promise<RouteRecordRaw[]> => {
|
|
||||||
const { data } = await getMenuTree();
|
|
||||||
const router = generateRoutes(data);
|
|
||||||
asyncImportRoute(router);
|
|
||||||
return router;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查找views中对应的组件文件
|
|
||||||
* */
|
|
||||||
let viewsModules: Record<string, () => Promise<Recordable>>;
|
|
||||||
export const asyncImportRoute = (
|
|
||||||
routes: AppRouteRecordRaw[] | undefined
|
|
||||||
): void => {
|
|
||||||
viewsModules = viewsModules || import.meta.glob("../views/**/*.{vue,tsx}");
|
|
||||||
|
|
||||||
if (!routes) return;
|
|
||||||
routes.forEach((item) => {
|
|
||||||
if (!item.component && item.meta?.frameSrc) {
|
|
||||||
item.component = "iframe";
|
|
||||||
}
|
|
||||||
const { component, name } = item;
|
|
||||||
|
|
||||||
const { children } = item;
|
|
||||||
if (component) {
|
|
||||||
const layoutFound = LayoutMap.get(component as string);
|
|
||||||
// console.log(layoutFound, "layoutFound");
|
|
||||||
|
|
||||||
if (layoutFound) {
|
|
||||||
item.component = layoutFound;
|
|
||||||
} else {
|
|
||||||
item.component = dynamicImport(viewsModules, component as string);
|
|
||||||
}
|
|
||||||
} else if (name) {
|
|
||||||
item.component = ParentLayout;
|
|
||||||
}
|
|
||||||
|
|
||||||
children && asyncImportRoute(children);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 动态导入
|
|
||||||
* */
|
|
||||||
export const dynamicImport = (
|
|
||||||
viewsModules: Record<string, () => Promise<Recordable>>,
|
|
||||||
component: string
|
|
||||||
) => {
|
|
||||||
const keys = Object.keys(viewsModules);
|
|
||||||
const matchKeys = keys.filter((key) => {
|
|
||||||
let k = key.replace("../views", "");
|
|
||||||
|
|
||||||
const lastIndex = k.lastIndexOf(".");
|
|
||||||
k = k.substring(0, lastIndex);
|
|
||||||
return k === component;
|
|
||||||
});
|
|
||||||
if (matchKeys?.length === 1) {
|
|
||||||
const matchKey = matchKeys[0];
|
|
||||||
return viewsModules[matchKey];
|
|
||||||
}
|
|
||||||
if (matchKeys?.length > 1) {
|
|
||||||
console.warn(
|
|
||||||
"Please do not create `.vue` and `.TSX` files with the same file name in the same hierarchical directory under the views folder. This will cause dynamic introduction failure"
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
import { renderIcon } from "@/utils/index";
|
|
||||||
import { DashboardOutlined } from "@vicons/antd";
|
|
||||||
|
|
||||||
//前端路由图标映射表
|
|
||||||
export const constantRouterIcon = {
|
|
||||||
DashboardOutlined: renderIcon(DashboardOutlined),
|
|
||||||
};
|
|
||||||
@ -1,41 +1,49 @@
|
|||||||
import type { App } from "vue";
|
import type { App } from "vue";
|
||||||
import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router";
|
import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router";
|
||||||
|
|
||||||
import { createRouterGuards } from "./router-guards";
|
import { createRouterGuards } from "./router-guards";
|
||||||
import { LoginRoute, RedirectRoute } from "@/router/base";
|
import { HttpErrorPage, LoginRoute, ErrorPageRoute } from "@/router/base";
|
||||||
// import type { IModuleType } from "./types";
|
|
||||||
|
|
||||||
// const modules = import.meta.glob<IModuleType>("./modules/**/*router.ts", {
|
// import modules from "@/router/modules";
|
||||||
// eager: true,
|
import type { IModuleType } from "./types";
|
||||||
// });
|
|
||||||
|
|
||||||
// const routeModuleList: RouteRecordRaw[] = Object.keys(modules).reduce<
|
const modules = import.meta.glob<IModuleType>("./modules/**/*router.ts", {
|
||||||
// RouteRecordRaw[]
|
eager: true,
|
||||||
// >((list, key) => {
|
});
|
||||||
// const mod = modules[key].default ?? {};
|
|
||||||
// const modList = Array.isArray(mod) ? [...mod] : [mod];
|
|
||||||
// return [...list, ...modList];
|
|
||||||
// }, []);
|
|
||||||
|
|
||||||
// function sortRoute(a, b) {
|
const routeModuleList: RouteRecordRaw[] = Object.keys(modules).reduce<
|
||||||
// return (a.meta?.sort ?? 0) - (b.meta?.sort ?? 0);
|
RouteRecordRaw[]
|
||||||
// }
|
>((list, key) => {
|
||||||
|
const mod = modules[key].default ?? {};
|
||||||
|
const modList = Array.isArray(mod) ? [...mod] : [mod];
|
||||||
|
return [...list, ...modList];
|
||||||
|
}, []);
|
||||||
|
|
||||||
// routeModuleList.sort(sortRoute);
|
function sortRoute(a, b) {
|
||||||
|
return (a.meta?.sort ?? 0) - (b.meta?.sort ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
routeModuleList.sort(sortRoute);
|
||||||
|
|
||||||
export const RootRoute: RouteRecordRaw = {
|
export const RootRoute: RouteRecordRaw = {
|
||||||
path: "/",
|
path: "/",
|
||||||
name: "Root",
|
name: "Root",
|
||||||
redirect: "/system/menu",
|
redirect: "/system",
|
||||||
meta: {
|
meta: {
|
||||||
title: "Root",
|
title: "Root",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
//需要验证权限
|
//需要验证权限
|
||||||
export const asyncRoutes = [];
|
export const asyncRoutes = [...routeModuleList];
|
||||||
|
|
||||||
//普通路由 无需验证权限
|
const constantRouter: any[] = [
|
||||||
export const constantRouter: any[] = [LoginRoute, RootRoute, RedirectRoute];
|
LoginRoute,
|
||||||
|
RootRoute,
|
||||||
|
...asyncRoutes,
|
||||||
|
ErrorPageRoute,
|
||||||
|
...HttpErrorPage,
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建路由
|
* 创建路由
|
||||||
|
|||||||
42
src/router/modules/menu.router.ts
Normal file
42
src/router/modules/menu.router.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { RouteRecordRaw } from "vue-router";
|
||||||
|
import { Layout } from "@/router/constant";
|
||||||
|
import { renderIcon } from "@/utils";
|
||||||
|
// import { icons } from "@/plugins";
|
||||||
|
import { OptionsSharp } from "@vicons/ionicons5";
|
||||||
|
|
||||||
|
// 引入路径
|
||||||
|
const importPath = {
|
||||||
|
MENU: () => import("@/views/system/menu/menu.vue"),
|
||||||
|
};
|
||||||
|
|
||||||
|
const systemRoutes: RouteRecordRaw = {
|
||||||
|
path: "/system",
|
||||||
|
name: "System",
|
||||||
|
redirect: "/system/menu",
|
||||||
|
component: Layout,
|
||||||
|
meta: {
|
||||||
|
title: "系统设置",
|
||||||
|
icons: renderIcon(OptionsSharp),
|
||||||
|
sort: 1,
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: "menu",
|
||||||
|
name: "system_menu",
|
||||||
|
meta: {
|
||||||
|
title: "菜单权限管理",
|
||||||
|
},
|
||||||
|
component: importPath["MENU"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "role",
|
||||||
|
name: "system_role",
|
||||||
|
meta: {
|
||||||
|
title: "角色权限管理",
|
||||||
|
},
|
||||||
|
component: () => import("@/views/system/role/role.vue"),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default systemRoutes;
|
||||||
@ -1,123 +1,35 @@
|
|||||||
import { Router, isNavigationFailure } from "vue-router";
|
import { Router } from "vue-router";
|
||||||
import type { RouteRecordRaw } from "vue-router";
|
|
||||||
import { loginCheck } from "@/utils/router";
|
import { loginCheck } from "@/utils/router";
|
||||||
import { useUser } from "@/store/modules/user";
|
|
||||||
import { useAsyncRoute } from "@/store/modules/asyncRoute";
|
|
||||||
import { PageEnum } from "@/enums/pageEnum";
|
|
||||||
import { ErrorPageRoute } from "@/router/base";
|
|
||||||
|
|
||||||
const LOGIN_PATH = PageEnum.BASE_LOGIN;
|
export function createRouterGuards(router: Router) {
|
||||||
const whitePathList = [LOGIN_PATH]; // 没有重定向白名单
|
|
||||||
|
|
||||||
export async function createRouterGuards(router: Router) {
|
|
||||||
const userStore = useUser();
|
|
||||||
const asyncRouteStore = useAsyncRoute();
|
|
||||||
// 前置;
|
// 前置;
|
||||||
router.beforeEach(async (to, from, next) => {
|
router.beforeEach(async (to, from, next) => {
|
||||||
const Loading = window["$loading"] || null;
|
const Loading = window["$loading"];
|
||||||
Loading && Loading.start();
|
Loading && Loading.start();
|
||||||
|
const isErrorPage = router
|
||||||
if (from.path === LOGIN_PATH && to.name === "errorPage") {
|
.getRoutes()
|
||||||
next(PageEnum.BASE_HOME);
|
.findIndex((item) => item.name === to.name);
|
||||||
return;
|
if (isErrorPage === -1) {
|
||||||
}
|
next({ name: "ErrorPage404" });
|
||||||
|
|
||||||
if (whitePathList.includes(to.path as PageEnum)) {
|
|
||||||
next();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!loginCheck()) {
|
if (!loginCheck()) {
|
||||||
// 不需要登录鉴权的路由
|
if (to.name === "Login") {
|
||||||
if (to.meta.ignoreAuth) {
|
|
||||||
next();
|
next();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
// 重定向到登录页
|
next({ name: "Login" });
|
||||||
const redirectData: {
|
|
||||||
path: string;
|
|
||||||
replace: boolean;
|
|
||||||
query?: Recordable<string>;
|
|
||||||
} = {
|
|
||||||
path: LOGIN_PATH,
|
|
||||||
replace: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (to.path) {
|
|
||||||
redirectData.query = {
|
|
||||||
...redirectData.query,
|
|
||||||
redirect: to.path,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
next(redirectData);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asyncRouteStore.getIsDynamicRouteAdded) {
|
next();
|
||||||
next();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await userStore.getInfo();
|
|
||||||
const routes = await asyncRouteStore.generateRoutes();
|
|
||||||
|
|
||||||
// 动态添加可访问路由表
|
|
||||||
routes.forEach((item: unknown) => {
|
|
||||||
router.addRoute(item as unknown as RouteRecordRaw);
|
|
||||||
});
|
|
||||||
|
|
||||||
//添加404
|
|
||||||
const isErrorPage = router
|
|
||||||
.getRoutes()
|
|
||||||
.findIndex((item) => item.name === ErrorPageRoute.name);
|
|
||||||
|
|
||||||
if (isErrorPage === -1) {
|
|
||||||
router.addRoute(ErrorPageRoute as unknown as RouteRecordRaw);
|
|
||||||
}
|
|
||||||
|
|
||||||
const redirectPath = (from.query.redirect || to.path) as string;
|
|
||||||
|
|
||||||
const redirect = decodeURIComponent(redirectPath);
|
|
||||||
const nextData =
|
|
||||||
to.path === redirect ? { ...to, replace: true } : { path: redirect };
|
|
||||||
asyncRouteStore.setDynamicRouteAdded(true);
|
|
||||||
next(nextData);
|
|
||||||
Loading && Loading.finish();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
router.afterEach((to, _, failure) => {
|
router.afterEach((to) => {
|
||||||
|
const Loading = window["$loading"];
|
||||||
document.title = (to?.meta?.title as string) || document.title;
|
document.title = (to?.meta?.title as string) || document.title;
|
||||||
if (isNavigationFailure(failure)) {
|
|
||||||
console.log("导航失败", failure);
|
|
||||||
}
|
|
||||||
const asyncRouteStore = useAsyncRoute();
|
|
||||||
// 在这里设置需要缓存的组件名称
|
|
||||||
const keepAliveComponents = asyncRouteStore.keepAliveComponents;
|
|
||||||
const currentComName: any = to.matched.find(
|
|
||||||
(item) => item.name == to.name
|
|
||||||
)?.name;
|
|
||||||
if (
|
|
||||||
currentComName &&
|
|
||||||
!keepAliveComponents.includes(currentComName) &&
|
|
||||||
to.meta?.keepAlive
|
|
||||||
) {
|
|
||||||
// 需要缓存的组件
|
|
||||||
keepAliveComponents.push(currentComName);
|
|
||||||
} else if (!to.meta?.keepAlive || to.name == "Redirect") {
|
|
||||||
// 不需要缓存的组件
|
|
||||||
const index = asyncRouteStore.keepAliveComponents.findIndex(
|
|
||||||
(name) => name == currentComName
|
|
||||||
);
|
|
||||||
if (index != -1) {
|
|
||||||
keepAliveComponents.splice(index, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
asyncRouteStore.setKeepAliveComponents(keepAliveComponents);
|
|
||||||
const Loading = window["$loading"] || null;
|
|
||||||
Loading && Loading.finish();
|
Loading && Loading.finish();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 错误
|
||||||
router.onError((error) => {
|
router.onError((error) => {
|
||||||
console.log(error, "路由错误");
|
console.log(error, "路由错误");
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,107 +0,0 @@
|
|||||||
import { defineStore } from "pinia";
|
|
||||||
import { RouteRecordRaw } from "vue-router";
|
|
||||||
import { store } from "@/store";
|
|
||||||
import { asyncRoutes, constantRouter } from "@/router/index";
|
|
||||||
import { generateDynamicRoutes } from "@/router/generator";
|
|
||||||
|
|
||||||
interface TreeHelperConfig {
|
|
||||||
id: string;
|
|
||||||
children: string;
|
|
||||||
pid: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const DEFAULT_CONFIG: TreeHelperConfig = {
|
|
||||||
id: "id",
|
|
||||||
children: "children",
|
|
||||||
pid: "pid",
|
|
||||||
};
|
|
||||||
|
|
||||||
const getConfig = (config: Partial<TreeHelperConfig>) =>
|
|
||||||
Object.assign({}, DEFAULT_CONFIG, config);
|
|
||||||
|
|
||||||
export interface IAsyncRouteState {
|
|
||||||
menus: RouteRecordRaw[];
|
|
||||||
routers: any[];
|
|
||||||
routersAdded: any[];
|
|
||||||
keepAliveComponents: string[];
|
|
||||||
isDynamicRouteAdded: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
function filter<T = any>(
|
|
||||||
tree: T[],
|
|
||||||
func: (n: T) => boolean,
|
|
||||||
config: Partial<TreeHelperConfig> = {}
|
|
||||||
): T[] {
|
|
||||||
config = getConfig(config);
|
|
||||||
const children = config.children as string;
|
|
||||||
|
|
||||||
function listFilter(list: T[]) {
|
|
||||||
return list
|
|
||||||
.map((node: any) => ({ ...node }))
|
|
||||||
.filter((node) => {
|
|
||||||
node[children] = node[children] && listFilter(node[children]);
|
|
||||||
return func(node) || (node[children] && node[children].length);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return listFilter(tree);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useAsyncRouteStore = defineStore({
|
|
||||||
id: "app-async-route",
|
|
||||||
state: (): IAsyncRouteState => ({
|
|
||||||
menus: [],
|
|
||||||
routers: constantRouter,
|
|
||||||
routersAdded: [],
|
|
||||||
keepAliveComponents: [],
|
|
||||||
// Whether the route has been dynamically added
|
|
||||||
isDynamicRouteAdded: false,
|
|
||||||
}),
|
|
||||||
getters: {
|
|
||||||
getMenus(): RouteRecordRaw[] {
|
|
||||||
return this.menus;
|
|
||||||
},
|
|
||||||
getIsDynamicRouteAdded(): boolean {
|
|
||||||
return this.isDynamicRouteAdded;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
getRouters() {
|
|
||||||
return toRaw(this.routersAdded);
|
|
||||||
},
|
|
||||||
setDynamicRouteAdded(added: boolean) {
|
|
||||||
this.isDynamicRouteAdded = added;
|
|
||||||
},
|
|
||||||
// 设置动态路由
|
|
||||||
setRouters(routers: RouteRecordRaw[]) {
|
|
||||||
this.routersAdded = routers;
|
|
||||||
this.routers = constantRouter.concat(routers);
|
|
||||||
},
|
|
||||||
setMenus(menus: RouteRecordRaw[]) {
|
|
||||||
// 设置动态路由
|
|
||||||
this.menus = menus;
|
|
||||||
},
|
|
||||||
setKeepAliveComponents(compNames: string[]) {
|
|
||||||
// 设置需要缓存的组件
|
|
||||||
this.keepAliveComponents = compNames;
|
|
||||||
},
|
|
||||||
async generateRoutes() {
|
|
||||||
let accessedRouters;
|
|
||||||
// 动态获取菜单
|
|
||||||
try {
|
|
||||||
accessedRouters = await generateDynamicRoutes();
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
// accessedRouters = accessedRouters.filter(routeFilter);
|
|
||||||
this.setRouters(accessedRouters);
|
|
||||||
this.setMenus(accessedRouters);
|
|
||||||
return toRaw(accessedRouters);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Need to be used outside the setup
|
|
||||||
export function useAsyncRoute() {
|
|
||||||
return useAsyncRouteStore(store);
|
|
||||||
}
|
|
||||||
@ -1,106 +0,0 @@
|
|||||||
import { defineStore } from "pinia";
|
|
||||||
import { store } from "@/store";
|
|
||||||
import { StorageEnum } from "@/enums/storageEnum";
|
|
||||||
import { ResultEnum } from "@/enums/httpEnum";
|
|
||||||
import { storage, routerTurnByName } from "@/utils";
|
|
||||||
import { login, getUserInfo } from "@/api/system/user";
|
|
||||||
import { PageEnum } from "@/enums/pageEnum";
|
|
||||||
export type UserInfoType = {
|
|
||||||
// TODO: add your own data
|
|
||||||
name: string;
|
|
||||||
email: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface IUserState {
|
|
||||||
token: string;
|
|
||||||
username: string;
|
|
||||||
welcome: string;
|
|
||||||
avatar: string;
|
|
||||||
permissions: any[];
|
|
||||||
info: UserInfoType;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useUserStore = defineStore({
|
|
||||||
id: "app-user",
|
|
||||||
state: (): IUserState => ({
|
|
||||||
token: storage.get(StorageEnum.ZS_ACCESS_TOKEN, ""),
|
|
||||||
username: "",
|
|
||||||
welcome: "",
|
|
||||||
avatar: "",
|
|
||||||
permissions: [],
|
|
||||||
info: storage.get(StorageEnum.ZS_CURRENT_USER, {}),
|
|
||||||
}),
|
|
||||||
getters: {
|
|
||||||
getToken(): string {
|
|
||||||
return this.token;
|
|
||||||
},
|
|
||||||
getAvatar(): string {
|
|
||||||
return this.avatar;
|
|
||||||
},
|
|
||||||
getNickname(): string {
|
|
||||||
return this.username;
|
|
||||||
},
|
|
||||||
getPermissions(): [any][] {
|
|
||||||
return this.permissions;
|
|
||||||
},
|
|
||||||
getUserInfo(): UserInfoType {
|
|
||||||
return this.info;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
setToken(token: string) {
|
|
||||||
this.token = token;
|
|
||||||
},
|
|
||||||
setAvatar(avatar: string) {
|
|
||||||
this.avatar = avatar;
|
|
||||||
},
|
|
||||||
setPermissions(permissions) {
|
|
||||||
this.permissions = permissions;
|
|
||||||
},
|
|
||||||
setUserInfo(info: UserInfoType) {
|
|
||||||
this.info = info;
|
|
||||||
},
|
|
||||||
// 登录
|
|
||||||
async login(params: any) {
|
|
||||||
const res = await login(params);
|
|
||||||
const { data } = res;
|
|
||||||
if (res.status === ResultEnum.STATUS) {
|
|
||||||
const ex = 7 * 24 * 60 * 60;
|
|
||||||
storage.set(StorageEnum.ZS_ACCESS_TOKEN, data, ex);
|
|
||||||
this.setToken(data);
|
|
||||||
// this.setUserInfo(result);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
},
|
|
||||||
|
|
||||||
// 获取用户信息
|
|
||||||
async getInfo() {
|
|
||||||
const { data } = await getUserInfo();
|
|
||||||
console.log(data, "用户信息");
|
|
||||||
|
|
||||||
// if (result.permissions && result.permissions.length) {
|
|
||||||
// const permissionsList = result.permissions;
|
|
||||||
// this.setPermissions(permissionsList);
|
|
||||||
this.setUserInfo(data);
|
|
||||||
// } else {
|
|
||||||
// throw new Error("getInfo: permissionsList must be a non-null array !");
|
|
||||||
// }
|
|
||||||
this.setAvatar(data.avatar);
|
|
||||||
return data;
|
|
||||||
},
|
|
||||||
|
|
||||||
// 登出
|
|
||||||
async logout() {
|
|
||||||
this.setPermissions([]);
|
|
||||||
this.setUserInfo({ name: "", email: "" });
|
|
||||||
storage.remove(StorageEnum.ZS_ACCESS_TOKEN);
|
|
||||||
storage.remove(StorageEnum.ZS_CURRENT_USER);
|
|
||||||
routerTurnByName(PageEnum.BASE_LOGIN_NAME);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Need to be used outside the setup
|
|
||||||
export function useUser() {
|
|
||||||
return useUserStore(store);
|
|
||||||
}
|
|
||||||
@ -22,10 +22,12 @@
|
|||||||
width: 10px;
|
width: 10px;
|
||||||
height: 22px;
|
height: 22px;
|
||||||
content: "";
|
content: "";
|
||||||
background: linear-gradient(90deg,
|
background: linear-gradient(
|
||||||
#3db8ff 0%,
|
90deg,
|
||||||
rgb(53 138 225 / 77%) 52%,
|
#3db8ff 0%,
|
||||||
#3db8ff 100%);
|
rgb(53 138 225 / 77%) 52%,
|
||||||
|
#3db8ff 100%
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -152,7 +152,7 @@ export function on(
|
|||||||
export function off(
|
export function off(
|
||||||
element: Element | HTMLElement | Document | Window,
|
element: Element | HTMLElement | Document | Window,
|
||||||
event: string,
|
event: string,
|
||||||
handler: any
|
handler: Fn
|
||||||
): void {
|
): void {
|
||||||
if (element && event && handler) {
|
if (element && event && handler) {
|
||||||
element.removeEventListener(event, handler, false);
|
element.removeEventListener(event, handler, false);
|
||||||
@ -161,9 +161,9 @@ export function off(
|
|||||||
|
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
export function once(el: HTMLElement, event: string, fn: EventListener): void {
|
export function once(el: HTMLElement, event: string, fn: EventListener): void {
|
||||||
const listener: EventListener = function (this: any, evt: Event) {
|
const listener = function (this: any, ...args: unknown[]) {
|
||||||
if (fn) {
|
if (fn) {
|
||||||
fn.call(this, evt);
|
fn.apply(this, args);
|
||||||
}
|
}
|
||||||
off(el, event, listener);
|
off(el, event, listener);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -38,13 +38,11 @@ export function generatorMenu(routerMap: Array<any>) {
|
|||||||
key: info.name,
|
key: info.name,
|
||||||
icon: isRoot ? item.meta?.icons : info.meta?.icons,
|
icon: isRoot ? item.meta?.icons : info.meta?.icons,
|
||||||
};
|
};
|
||||||
|
|
||||||
// 是否有子菜单,并递归处理
|
// 是否有子菜单,并递归处理
|
||||||
if (info.children && info.children.length > 0) {
|
if (info.children && info.children.length > 0) {
|
||||||
// Recursion
|
// Recursion
|
||||||
currentMenu.children = generatorMenu(info.children);
|
currentMenu.children = generatorMenu(info.children);
|
||||||
}
|
}
|
||||||
|
|
||||||
return currentMenu;
|
return currentMenu;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
import { ResultEnum } from "@/enums/httpEnum";
|
import { ResultEnum } from "@/enums/httpEnum";
|
||||||
import { ErrorPageNameMap } from "@/enums/pageEnum";
|
import { ErrorPageNameMap } from "@/enums/pageEnum";
|
||||||
import { cryptoDecode } from "./crypto";
|
import { clearLocalStorage, getLocalStorage } from "./storage";
|
||||||
import { StorageEnum } from "@/enums/storageEnum";
|
import { StorageEnum } from "@/enums/storageEnum";
|
||||||
import { storage } from "@/utils/storage";
|
import { cryptoDecode } from "./crypto";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* * 根据名字跳转路由
|
* * 根据名字跳转路由
|
||||||
* @param pageName
|
* @param pageName
|
||||||
@ -74,16 +73,23 @@ export const openNewWindow = (url: string) => {
|
|||||||
*/
|
*/
|
||||||
export const loginCheck = () => {
|
export const loginCheck = () => {
|
||||||
try {
|
try {
|
||||||
const token = storage.get(StorageEnum.ZS_ACCESS_TOKEN);
|
const info = getLocalStorage(StorageEnum.ZS_LOGIN_INFO_STORE);
|
||||||
|
if (!info) return false;
|
||||||
|
const decodeInfo = cryptoDecode(info);
|
||||||
|
|
||||||
if (token) return true;
|
if (decodeInfo) {
|
||||||
// const decodeInfo = cryptoDecode(info);
|
return true;
|
||||||
|
}
|
||||||
// if (decodeInfo) {
|
return false;
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
// return false;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* * 退出
|
||||||
|
*/
|
||||||
|
export const logout = () => {
|
||||||
|
clearLocalStorage(StorageEnum.ZS_LOGIN_INFO_STORE);
|
||||||
|
routerTurnByName("Login");
|
||||||
|
};
|
||||||
|
|||||||
@ -1,128 +1,70 @@
|
|||||||
// 默认缓存期限为7天
|
/**
|
||||||
const DEFAULT_CACHE_TIME = 60 * 60 * 24 * 7;
|
* * 存储本地会话数据
|
||||||
|
* @param k 键名
|
||||||
|
* @param v 键值(无需stringiiy)
|
||||||
|
* @returns RemovableRef
|
||||||
|
*/
|
||||||
|
export const setLocalStorage = <T>(k: string, v: T) => {
|
||||||
|
try {
|
||||||
|
window.localStorage.setItem(k, JSON.stringify(v));
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建本地缓存对象
|
* * 获取本地会话数据
|
||||||
* @param {string=} prefixKey -
|
* @param k 键名
|
||||||
* @param {Object} [storage=localStorage] - sessionStorage | localStorage
|
* @returns any
|
||||||
*/
|
*/
|
||||||
|
export const getLocalStorage = (k: string) => {
|
||||||
export default class Storage {
|
const item = window.localStorage.getItem(k);
|
||||||
private storage: globalThis.Storage;
|
try {
|
||||||
private prefixKey?: string;
|
return item ? JSON.parse(item) : item;
|
||||||
|
} catch (err) {
|
||||||
constructor(prefixKey = "", storage = localStorage) {
|
return item;
|
||||||
this.storage = storage;
|
|
||||||
this.prefixKey = prefixKey;
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private getKey(key: string) {
|
/**
|
||||||
return `${this.prefixKey}${key}`.toUpperCase();
|
* * 清除本地会话数据
|
||||||
|
* @param name
|
||||||
|
*/
|
||||||
|
export const clearLocalStorage = (name: string) => {
|
||||||
|
window.localStorage.removeItem(name);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* * 存储临时会话数据
|
||||||
|
* @param k 键名
|
||||||
|
* @param v 键值
|
||||||
|
* @returns RemovableRef
|
||||||
|
*/
|
||||||
|
export const setSessionStorage = <T>(k: string, v: T) => {
|
||||||
|
try {
|
||||||
|
window.sessionStorage.setItem(k, JSON.stringify(v));
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 设置缓存
|
* * 获取临时会话数据
|
||||||
* @param {string} key 缓存键
|
* @returns any
|
||||||
* @param {*} value 缓存值
|
*/
|
||||||
* @param expire
|
export const getSessionStorage: (k: string) => any = (k: string) => {
|
||||||
*/
|
const item = window.sessionStorage.getItem(k);
|
||||||
set(key: string, value: any, expire: number | null = DEFAULT_CACHE_TIME) {
|
try {
|
||||||
const stringData = JSON.stringify({
|
return item ? JSON.parse(item) : item;
|
||||||
value,
|
} catch (err) {
|
||||||
expire: expire !== null ? new Date().getTime() + expire * 1000 : null,
|
return item;
|
||||||
});
|
|
||||||
this.storage.setItem(this.getKey(key), stringData);
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 读取缓存
|
* * 清除本地会话数据
|
||||||
* @param {string} key 缓存键
|
* @param name
|
||||||
* @param {*=} def 默认值
|
*/
|
||||||
*/
|
export const clearSessioStorage = (name: string) => {
|
||||||
get(key: string, def: any = null) {
|
window.sessionStorage.removeItem(name);
|
||||||
const item = this.storage.getItem(this.getKey(key));
|
};
|
||||||
if (item) {
|
|
||||||
try {
|
|
||||||
const data = JSON.parse(item);
|
|
||||||
const { value, expire } = data;
|
|
||||||
// 在有效期内直接返回
|
|
||||||
if (expire === null || expire >= Date.now()) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
this.remove(key);
|
|
||||||
} catch (e) {
|
|
||||||
return def;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return def;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从缓存删除某项
|
|
||||||
* @param {string} key
|
|
||||||
*/
|
|
||||||
remove(key: string) {
|
|
||||||
this.storage.removeItem(this.getKey(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 清空所有缓存
|
|
||||||
* @memberOf Cache
|
|
||||||
*/
|
|
||||||
clear(): void {
|
|
||||||
this.storage.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置cookie
|
|
||||||
* @param {string} name cookie 名称
|
|
||||||
* @param {*} value cookie 值
|
|
||||||
* @param {number=} expire 过期时间
|
|
||||||
* 如果过期时间未设置,默认关闭浏览器自动删除
|
|
||||||
* @example
|
|
||||||
*/
|
|
||||||
setCookie(
|
|
||||||
name: string,
|
|
||||||
value: any,
|
|
||||||
expire: number | null = DEFAULT_CACHE_TIME
|
|
||||||
) {
|
|
||||||
document.cookie = `${this.getKey(name)}=${value}; Max-Age=${expire}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据名字获取cookie值
|
|
||||||
* @param name
|
|
||||||
*/
|
|
||||||
getCookie(name: string): string {
|
|
||||||
const cookieArr = document.cookie.split("; ");
|
|
||||||
for (let i = 0, length = cookieArr.length; i < length; i++) {
|
|
||||||
const kv = cookieArr[i].split("=");
|
|
||||||
if (kv[0] === this.getKey(name)) {
|
|
||||||
return kv[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据名字删除指定的cookie
|
|
||||||
* @param {string} key
|
|
||||||
*/
|
|
||||||
removeCookie(key: string) {
|
|
||||||
this.setCookie(key, 1, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 清空cookie,使所有cookie失效
|
|
||||||
*/
|
|
||||||
clearCookie(): void {
|
|
||||||
const keys = document.cookie.match(/[^ =;]+(?==)/g);
|
|
||||||
if (keys) {
|
|
||||||
for (let i = keys.length; i--; ) {
|
|
||||||
document.cookie = keys[i] + "=0;expire=" + new Date(0).toUTCString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const storage = new Storage("");
|
|
||||||
|
|||||||
@ -61,19 +61,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { reactive, ref } from "vue";
|
||||||
import { PersonOutline, LockClosedOutline } from "@vicons/ionicons5";
|
import { PersonOutline, LockClosedOutline } from "@vicons/ionicons5";
|
||||||
import { useUserStore } from "@/store/modules/user";
|
import logoImage from "@/assets/images/logo.png";
|
||||||
// import { routerTurnByName, cryptoEncode } from "@/utils";
|
import { routerTurnByName, cryptoEncode, setLocalStorage } from "@/utils";
|
||||||
// import { StorageEnum } from "@/enums/storageEnum";
|
import { StorageEnum } from "@/enums/storageEnum";
|
||||||
import { ResultEnum } from "@/enums/httpEnum";
|
const { ZS_LOGIN_INFO_STORE } = StorageEnum;
|
||||||
import { PageEnum } from "@/enums/pageEnum";
|
|
||||||
import { useRoute, useRouter } from "vue-router";
|
|
||||||
import { websiteConfig } from "@/config/website.config";
|
|
||||||
const userStore = useUserStore();
|
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
const route = useRoute();
|
|
||||||
|
|
||||||
interface FormState {
|
interface FormState {
|
||||||
username: string;
|
username: string;
|
||||||
password: string;
|
password: string;
|
||||||
@ -84,7 +77,7 @@ const loading = ref(false);
|
|||||||
|
|
||||||
const formInline = reactive({
|
const formInline = reactive({
|
||||||
username: "admin",
|
username: "admin",
|
||||||
password: "123456",
|
password: "zsqy123",
|
||||||
isCaptcha: true,
|
isCaptcha: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -93,9 +86,16 @@ const rules = {
|
|||||||
password: { required: true, message: "请输入密码", trigger: "blur" },
|
password: { required: true, message: "请输入密码", trigger: "blur" },
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = (e) => {
|
const websiteConfig = {
|
||||||
|
title: "中盛起元基础框架",
|
||||||
|
logo: logoImage,
|
||||||
|
loginImage: logoImage,
|
||||||
|
loginDesc: "中盛起元基础框架",
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = (e: any) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
formRef.value.validate(async (errors) => {
|
formRef.value.validate(async (errors: any) => {
|
||||||
if (!errors) {
|
if (!errors) {
|
||||||
const { username, password } = formInline;
|
const { username, password } = formInline;
|
||||||
window["$message"].loading("登录中...");
|
window["$message"].loading("登录中...");
|
||||||
@ -106,25 +106,27 @@ const handleSubmit = (e) => {
|
|||||||
password,
|
password,
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
if (params.username === "admin" && params.password === "zsqy123") {
|
||||||
const { status } = await userStore.login(params);
|
window["$message"].success("登录成功,即将进入系统");
|
||||||
window["$message"].destroyAll();
|
setLocalStorage(
|
||||||
if (status == ResultEnum.STATUS) {
|
ZS_LOGIN_INFO_STORE,
|
||||||
const toPath = decodeURIComponent(
|
cryptoEncode(
|
||||||
(route.query?.redirect || "/") as string
|
JSON.stringify({
|
||||||
);
|
username,
|
||||||
window["$message"].success("登录成功,即将进入系统");
|
password,
|
||||||
if (route.name === PageEnum.BASE_LOGIN_NAME) {
|
})
|
||||||
router.replace("/");
|
)
|
||||||
} else router.replace(toPath);
|
);
|
||||||
} else {
|
setTimeout(() => {
|
||||||
window["$message"].info("登录失败");
|
routerTurnByName("Root", true);
|
||||||
}
|
}, 3000);
|
||||||
} finally {
|
} else {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
window["$message"].error("用户名或密码错误");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
window["$message"].error("请填写完整信息,并且进行验证码校验");
|
loading.value = false;
|
||||||
|
window["$message"].error("用户名或密码错误");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,22 +0,0 @@
|
|||||||
<script lang="tsx">
|
|
||||||
import { defineComponent, onBeforeMount } from "vue";
|
|
||||||
import { useRoute, useRouter } from "vue-router";
|
|
||||||
import { NEmpty } from "naive-ui";
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "Redirect",
|
|
||||||
setup() {
|
|
||||||
const route = useRoute();
|
|
||||||
const router = useRouter();
|
|
||||||
onBeforeMount(() => {
|
|
||||||
const { params, query } = route;
|
|
||||||
const { path } = params;
|
|
||||||
router.replace({
|
|
||||||
path: "/" + (Array.isArray(path) ? path.join("/") : path),
|
|
||||||
query,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return () => <NEmpty />;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
@ -97,7 +97,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { insertMenu } from "@/api/system/menu";
|
import { insertMenu } from "@/api/system";
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
title: {
|
title: {
|
||||||
type: String,
|
type: String,
|
||||||
|
|||||||
@ -340,7 +340,7 @@ const selectedTree = (keys) => {
|
|||||||
|
|
||||||
const handleDel = async () => {
|
const handleDel = async () => {
|
||||||
const res = await deleteMenu({ id: formParams.id });
|
const res = await deleteMenu({ id: formParams.id });
|
||||||
if (res.status === 200) window["$message"].success("删除成功!");
|
if (res.status) window["$message"].success("删除成功!");
|
||||||
getMenuTreeApi();
|
getMenuTreeApi();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -353,7 +353,7 @@ const formSubmit = () => {
|
|||||||
formRef.value.validate(async (errors: boolean) => {
|
formRef.value.validate(async (errors: boolean) => {
|
||||||
if (!errors) {
|
if (!errors) {
|
||||||
const res = await updateMenu(formParams);
|
const res = await updateMenu(formParams);
|
||||||
if (res.status === 200) window["$message"].success("修改成功");
|
if (res.status) window["$message"].success("修改成功");
|
||||||
getMenuTreeApi();
|
getMenuTreeApi();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,32 +1,36 @@
|
|||||||
import { h } from "vue";
|
import { h } from 'vue';
|
||||||
import { NTag } from "naive-ui";
|
import { NTag } from 'naive-ui';
|
||||||
|
|
||||||
export const columns = [
|
export const columns = [
|
||||||
{
|
{
|
||||||
title: "ID",
|
title: 'id',
|
||||||
key: "id",
|
key: 'id',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "角色名称",
|
title: '角色名称',
|
||||||
key: "roleName",
|
key: 'name',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "说明",
|
title: '说明',
|
||||||
key: "description",
|
key: 'explain',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "状态",
|
title: '是否默认角色',
|
||||||
key: "status",
|
key: 'isDefault',
|
||||||
render(row) {
|
render(row) {
|
||||||
return h(
|
return h(
|
||||||
NTag,
|
NTag,
|
||||||
{
|
{
|
||||||
type: row.status ? "success" : "error",
|
type: row.isDefault ? 'success' : 'error',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
default: () => (row.status ? "正常" : "冻结"),
|
default: () => (row.isDefault ? '是' : '否'),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
key: 'create_date',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@ -1,108 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { insertRule } from "@/api/system/role";
|
|
||||||
const props = defineProps({
|
|
||||||
formRoleValue: {
|
|
||||||
type: Object,
|
|
||||||
default: () => ({}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const formRef = ref();
|
|
||||||
const { formRoleValue } = toRefs(props);
|
|
||||||
const roleTitle = ref("新增角色");
|
|
||||||
const formBtnLoading = ref(false);
|
|
||||||
const showRoleModal = ref(false);
|
|
||||||
const rules = {
|
|
||||||
roleName: {
|
|
||||||
required: true,
|
|
||||||
message: "请输入角色名称",
|
|
||||||
trigger: "blur",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
// 提交表单
|
|
||||||
const confirmForm = () => {
|
|
||||||
formRef.value.validate(async (errors: any) => {
|
|
||||||
if (!errors) {
|
|
||||||
formRoleValue.value.id ? updateRuleApi() : insertRuleApi();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 修改
|
|
||||||
const updateRuleApi = () => {};
|
|
||||||
|
|
||||||
// 新增
|
|
||||||
const insertRuleApi = async () => {
|
|
||||||
const { roleName, description, status } = formRoleValue.value;
|
|
||||||
const params = {
|
|
||||||
roleName,
|
|
||||||
description,
|
|
||||||
status,
|
|
||||||
};
|
|
||||||
const res = await insertRule(params);
|
|
||||||
if (res.status === 200) window["$message"].success("新增成功!");
|
|
||||||
};
|
|
||||||
|
|
||||||
const init = (str: string) => {
|
|
||||||
if (str === "add") {
|
|
||||||
roleTitle.value = "新增角色";
|
|
||||||
} else {
|
|
||||||
roleTitle.value = "编辑角色";
|
|
||||||
}
|
|
||||||
showRoleModal.value = true;
|
|
||||||
};
|
|
||||||
const close = () => {
|
|
||||||
showRoleModal.value = false;
|
|
||||||
};
|
|
||||||
defineExpose({
|
|
||||||
init,
|
|
||||||
close,
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<!-- 新增角色 -->
|
|
||||||
<n-modal
|
|
||||||
v-model:show="showRoleModal"
|
|
||||||
:show-icon="false"
|
|
||||||
preset="dialog"
|
|
||||||
:title="roleTitle"
|
|
||||||
>
|
|
||||||
<n-form
|
|
||||||
ref="formRef"
|
|
||||||
:rules="rules"
|
|
||||||
label-placement="left"
|
|
||||||
label-width="auto"
|
|
||||||
:model="formRoleValue"
|
|
||||||
require-mark-placement="right-hanging"
|
|
||||||
>
|
|
||||||
<n-form-item label="角色名称" path="roleName">
|
|
||||||
<n-input
|
|
||||||
v-model:value="formRoleValue.roleName"
|
|
||||||
placeholder="输入角色名称"
|
|
||||||
/>
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item label="状态">
|
|
||||||
<n-radio-group v-model:value="formRoleValue.status" name="radiogroup1">
|
|
||||||
<n-space>
|
|
||||||
<n-radio :value="0"> 冻结 </n-radio>
|
|
||||||
<n-radio :value="1"> 启用 </n-radio>
|
|
||||||
</n-space>
|
|
||||||
</n-radio-group>
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item label="描述">
|
|
||||||
<n-input
|
|
||||||
v-model:value="formRoleValue.description"
|
|
||||||
type="textarea"
|
|
||||||
placeholder="请输入描述"
|
|
||||||
/>
|
|
||||||
</n-form-item>
|
|
||||||
</n-form>
|
|
||||||
<template #action>
|
|
||||||
<n-space>
|
|
||||||
<n-button type="primary" :loading="formBtnLoading" @click="confirmForm"
|
|
||||||
>提交</n-button
|
|
||||||
>
|
|
||||||
</n-space>
|
|
||||||
</template>
|
|
||||||
</n-modal>
|
|
||||||
</template>
|
|
||||||
@ -1,247 +1,6 @@
|
|||||||
|
<script setup lang="ts"></script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>345</div>
|
||||||
<n-card :bordered="false" class="mt-4 proCard">
|
|
||||||
<BasicTable
|
|
||||||
:columns="columns"
|
|
||||||
:request="loadDataTable"
|
|
||||||
:row-key="(row) => row.id"
|
|
||||||
ref="actionRef"
|
|
||||||
:actionColumn="actionColumn"
|
|
||||||
@update:checked-row-keys="onCheckedRow"
|
|
||||||
>
|
|
||||||
<template #tableTitle>
|
|
||||||
<n-button type="primary" @click="addRole">
|
|
||||||
<template #icon>
|
|
||||||
<n-icon>
|
|
||||||
<PlusOutlined />
|
|
||||||
</n-icon>
|
|
||||||
</template>
|
|
||||||
添加角色
|
|
||||||
</n-button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #action>
|
|
||||||
<TableAction />
|
|
||||||
</template>
|
|
||||||
</BasicTable>
|
|
||||||
</n-card>
|
|
||||||
|
|
||||||
<!-- 添加角色 -->
|
|
||||||
<RoleModal ref="formRole" :formRoleValue="formRoleValue" />
|
|
||||||
|
|
||||||
<!-- 菜单权限 -->
|
|
||||||
<n-modal
|
|
||||||
v-model:show="showModal"
|
|
||||||
:show-icon="false"
|
|
||||||
preset="dialog"
|
|
||||||
:title="editRoleTitle"
|
|
||||||
>
|
|
||||||
<div class="py-3 menu-list">
|
|
||||||
<n-tree
|
|
||||||
block-line
|
|
||||||
cascade
|
|
||||||
checkable
|
|
||||||
:virtual-scroll="true"
|
|
||||||
:data="treeData"
|
|
||||||
:expanded-keys="expandedKeys"
|
|
||||||
:checked-keys="checkedKeys"
|
|
||||||
style="max-height: 950px; overflow: hidden"
|
|
||||||
@update:checked-keys="checkedTree"
|
|
||||||
@update:expanded-keys="onExpandedKeys"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<template #action>
|
|
||||||
<n-space>
|
|
||||||
<n-button type="info" ghost icon-placement="left" @click="packHandle">
|
|
||||||
全部{{ expandedKeys.length ? "收起" : "展开" }}
|
|
||||||
</n-button>
|
|
||||||
|
|
||||||
<n-button
|
|
||||||
type="info"
|
|
||||||
ghost
|
|
||||||
icon-placement="left"
|
|
||||||
@click="checkedAllHandle"
|
|
||||||
>
|
|
||||||
全部{{ checkedAll ? "取消" : "选择" }}
|
|
||||||
</n-button>
|
|
||||||
<n-button
|
|
||||||
type="primary"
|
|
||||||
:loading="formBtnLoading"
|
|
||||||
@click="confirmForm"
|
|
||||||
>提交</n-button
|
|
||||||
>
|
|
||||||
</n-space>
|
|
||||||
</template>
|
|
||||||
</n-modal>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
<style scoped lang="scss"></style>
|
||||||
<script lang="ts" setup>
|
|
||||||
import { BasicTable, TableAction } from "@/components/Table";
|
|
||||||
|
|
||||||
import { columns } from "./columns";
|
|
||||||
import { PlusOutlined } from "@vicons/antd";
|
|
||||||
import { getTreeAll } from "@/utils";
|
|
||||||
import { getRuleList } from "@/api/system/role";
|
|
||||||
import { getMenuTree } from "@/api/system/menu";
|
|
||||||
import { queryMenuByRole, saveRoleMenu } from "@/api/system/roleMenu";
|
|
||||||
|
|
||||||
const actionRef = ref();
|
|
||||||
const formRole = ref();
|
|
||||||
const formRoleValue = reactive({
|
|
||||||
id: null,
|
|
||||||
roleName: "",
|
|
||||||
roleCode: null,
|
|
||||||
status: 1,
|
|
||||||
description: "",
|
|
||||||
});
|
|
||||||
const lastMenuIds = ref([]);
|
|
||||||
const showModal = ref(false);
|
|
||||||
const formBtnLoading = ref(false);
|
|
||||||
const checkedAll = ref(false);
|
|
||||||
const editRoleTitle = ref("");
|
|
||||||
const treeData = ref([]);
|
|
||||||
const expandedKeys = ref([]);
|
|
||||||
const checkedKeys: Ref<any[]> = ref([]);
|
|
||||||
const roleId = ref(null);
|
|
||||||
const params = reactive({
|
|
||||||
roleName: "",
|
|
||||||
});
|
|
||||||
|
|
||||||
const actionColumn = reactive({
|
|
||||||
width: 250,
|
|
||||||
title: "操作",
|
|
||||||
key: "action",
|
|
||||||
fixed: "right",
|
|
||||||
render(record) {
|
|
||||||
return h(TableAction, {
|
|
||||||
style: "button",
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
label: "菜单权限",
|
|
||||||
onClick: handleMenuAuth.bind(null, record),
|
|
||||||
// 根据业务控制是否显示 isShow 和 auth 是并且关系
|
|
||||||
ifShow: () => {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "编辑",
|
|
||||||
onClick: handleEdit.bind(null, record),
|
|
||||||
ifShow: () => {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "删除",
|
|
||||||
onClick: handleDelete.bind(null, record),
|
|
||||||
// 根据业务控制是否显示 isShow 和 auth 是并且关系
|
|
||||||
ifShow: () => {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const mapTreeData = (data) => {
|
|
||||||
return data.map((ele) => ({
|
|
||||||
...ele,
|
|
||||||
key: ele.id,
|
|
||||||
label: ele.meta.title,
|
|
||||||
children: ele.children ? mapTreeData(ele.children) : undefined,
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
// 新增按钮
|
|
||||||
const addRole = () => {
|
|
||||||
formRole.value.init("add");
|
|
||||||
};
|
|
||||||
|
|
||||||
const loadDataTable = async (res: any) => {
|
|
||||||
let _params = {
|
|
||||||
...unref(params),
|
|
||||||
...res,
|
|
||||||
};
|
|
||||||
const { data } = await getRuleList(_params);
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
function onCheckedRow(rowKeys: any[]) {
|
|
||||||
console.log(rowKeys);
|
|
||||||
}
|
|
||||||
|
|
||||||
function reloadTable() {
|
|
||||||
actionRef.value.reload();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function confirmForm(e: any) {
|
|
||||||
e.preventDefault();
|
|
||||||
formBtnLoading.value = true;
|
|
||||||
const res = await saveRoleMenu({
|
|
||||||
roleId: roleId.value,
|
|
||||||
menuIds: checkedKeys.value,
|
|
||||||
lastMenuIds: lastMenuIds.value,
|
|
||||||
});
|
|
||||||
if (res.status === 200) {
|
|
||||||
showModal.value = false;
|
|
||||||
reloadTable();
|
|
||||||
window["$message"].success("保存成功");
|
|
||||||
formBtnLoading.value = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleEdit(record: Recordable) {
|
|
||||||
console.log("点击了编辑", record);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleDelete(record: Recordable) {
|
|
||||||
console.log("点击了删除", record);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleMenuAuth(record: Recordable) {
|
|
||||||
editRoleTitle.value = `分配 ${record.roleName} 的菜单权限`;
|
|
||||||
roleId.value = record.id;
|
|
||||||
const res = await queryMenuByRole({ roleId: record.id });
|
|
||||||
lastMenuIds.value = res.data;
|
|
||||||
|
|
||||||
checkedKeys.value = res.data; // 根据roleid查询权限菜单
|
|
||||||
showModal.value = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkedTree(keys) {
|
|
||||||
checkedKeys.value = keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
function onExpandedKeys(keys) {
|
|
||||||
expandedKeys.value = keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
function packHandle() {
|
|
||||||
if (expandedKeys.value.length) {
|
|
||||||
expandedKeys.value = [];
|
|
||||||
} else {
|
|
||||||
expandedKeys.value = treeData.value.map((item: any) => item.key) as [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkedAllHandle() {
|
|
||||||
if (!checkedAll.value) {
|
|
||||||
checkedKeys.value = getTreeAll(treeData.value);
|
|
||||||
checkedAll.value = true;
|
|
||||||
} else {
|
|
||||||
checkedKeys.value = [];
|
|
||||||
checkedAll.value = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
const treeMenuList = await getMenuTree();
|
|
||||||
const res = mapTreeData(treeMenuList.data);
|
|
||||||
expandedKeys.value = treeMenuList.data.map((item) => item.key);
|
|
||||||
treeData.value = res;
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
|
||||||
|
|||||||
@ -1,51 +0,0 @@
|
|||||||
import { h } from "vue";
|
|
||||||
import { NTag } from "naive-ui";
|
|
||||||
|
|
||||||
export const columns = [
|
|
||||||
{
|
|
||||||
title: "用户名",
|
|
||||||
key: "username",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "真实姓名",
|
|
||||||
key: "realname",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "手机号",
|
|
||||||
key: "phone",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "电子邮箱",
|
|
||||||
key: "email",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "用户类型",
|
|
||||||
key: "userType",
|
|
||||||
render(row) {
|
|
||||||
return h(
|
|
||||||
NTag,
|
|
||||||
{
|
|
||||||
type: row.userType === 1 ? "success" : "info",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
default: () => (row.userType === 1 ? "员工" : "用户"),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "性别",
|
|
||||||
key: "sex",
|
|
||||||
render(row) {
|
|
||||||
return h(
|
|
||||||
NTag,
|
|
||||||
{
|
|
||||||
type: row.sex === 1 ? "success" : "info",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
default: () => (row.sex === 1 ? "男" : "女"),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
@ -1,135 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { insertUser } from "@/api/system/user";
|
|
||||||
const props = defineProps({
|
|
||||||
formRoleValue: {
|
|
||||||
type: Object,
|
|
||||||
default: () => ({}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const formRef = ref();
|
|
||||||
const { formRoleValue } = toRefs(props);
|
|
||||||
const roleTitle = ref("新增角色");
|
|
||||||
const formBtnLoading = ref(false);
|
|
||||||
const showRoleModal = ref(false);
|
|
||||||
const rules = {
|
|
||||||
roleName: {
|
|
||||||
required: true,
|
|
||||||
message: "请输入角色名称",
|
|
||||||
trigger: "blur",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// 提交表单
|
|
||||||
const confirmForm = () => {
|
|
||||||
formRef.value.validate(async (errors: any) => {
|
|
||||||
if (!errors) {
|
|
||||||
formRoleValue.value.id ? updateUserApi() : insertUserApi();
|
|
||||||
} else {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 修改
|
|
||||||
const updateUserApi = () => {};
|
|
||||||
|
|
||||||
// 新增
|
|
||||||
const insertUserApi = async () => {
|
|
||||||
const res = await insertUser(formRoleValue.value);
|
|
||||||
if (res.status === 200) window["$message"].success("新增成功!");
|
|
||||||
};
|
|
||||||
|
|
||||||
const init = (str: string) => {
|
|
||||||
if (str === "add") {
|
|
||||||
roleTitle.value = "新增用户";
|
|
||||||
} else {
|
|
||||||
roleTitle.value = "编辑用户";
|
|
||||||
}
|
|
||||||
showRoleModal.value = true;
|
|
||||||
};
|
|
||||||
const close = () => {
|
|
||||||
showRoleModal.value = false;
|
|
||||||
};
|
|
||||||
defineExpose({
|
|
||||||
init,
|
|
||||||
close,
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<!-- 新增角色 -->
|
|
||||||
<n-modal
|
|
||||||
v-model:show="showRoleModal"
|
|
||||||
:show-icon="false"
|
|
||||||
preset="dialog"
|
|
||||||
:title="roleTitle"
|
|
||||||
>
|
|
||||||
<n-form
|
|
||||||
ref="formRef"
|
|
||||||
:rules="rules"
|
|
||||||
label-placement="left"
|
|
||||||
label-width="auto"
|
|
||||||
:model="formRoleValue"
|
|
||||||
require-mark-placement="right-hanging"
|
|
||||||
>
|
|
||||||
<n-form-item label="用户名" path="username">
|
|
||||||
<n-input
|
|
||||||
v-model:value="formRoleValue.username"
|
|
||||||
placeholder="请输入用户名"
|
|
||||||
/>
|
|
||||||
</n-form-item>
|
|
||||||
|
|
||||||
<n-form-item label="真实姓名">
|
|
||||||
<n-input
|
|
||||||
v-model:value="formRoleValue.realname"
|
|
||||||
placeholder="请输入真实姓名"
|
|
||||||
/>
|
|
||||||
</n-form-item>
|
|
||||||
|
|
||||||
<n-form-item label="电子邮箱">
|
|
||||||
<n-input
|
|
||||||
v-model:value="formRoleValue.email"
|
|
||||||
placeholder="请输入电子邮箱"
|
|
||||||
/>
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item label="手机号">
|
|
||||||
<n-input
|
|
||||||
v-model:value="formRoleValue.phone"
|
|
||||||
placeholder="请输入手机号"
|
|
||||||
/>
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item label="密码">
|
|
||||||
<n-input
|
|
||||||
type="password"
|
|
||||||
v-model:value="formRoleValue.password"
|
|
||||||
placeholder="请输入密码"
|
|
||||||
/>
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item label="性别">
|
|
||||||
<n-radio-group v-model:value="formRoleValue.sex" name="radiogroup1">
|
|
||||||
<n-space>
|
|
||||||
<n-radio :value="0"> 女 </n-radio>
|
|
||||||
<n-radio :value="1"> 男 </n-radio>
|
|
||||||
</n-space>
|
|
||||||
</n-radio-group>
|
|
||||||
</n-form-item>
|
|
||||||
<n-form-item label="用户类型">
|
|
||||||
<n-radio-group
|
|
||||||
v-model:value="formRoleValue.userType"
|
|
||||||
name="radiogroup1"
|
|
||||||
>
|
|
||||||
<n-space>
|
|
||||||
<n-radio :value="2"> 用户 </n-radio>
|
|
||||||
<n-radio :value="1"> 员工 </n-radio>
|
|
||||||
</n-space>
|
|
||||||
</n-radio-group>
|
|
||||||
</n-form-item>
|
|
||||||
</n-form>
|
|
||||||
<template #action>
|
|
||||||
<n-space>
|
|
||||||
<n-button type="primary" :loading="formBtnLoading" @click="confirmForm"
|
|
||||||
>提交</n-button
|
|
||||||
>
|
|
||||||
</n-space>
|
|
||||||
</template>
|
|
||||||
</n-modal>
|
|
||||||
</template>
|
|
||||||
@ -1,228 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<n-card :bordered="false" class="mt-4 proCard">
|
|
||||||
<BasicTable
|
|
||||||
:columns="columns"
|
|
||||||
:request="loadDataTable"
|
|
||||||
:row-key="(row) => row.id"
|
|
||||||
ref="actionRef"
|
|
||||||
:actionColumn="actionColumn"
|
|
||||||
@update:checked-row-keys="onCheckedRow"
|
|
||||||
>
|
|
||||||
<template #tableTitle>
|
|
||||||
<n-button type="primary" @click="addRole">
|
|
||||||
<template #icon>
|
|
||||||
<n-icon>
|
|
||||||
<PlusOutlined />
|
|
||||||
</n-icon>
|
|
||||||
</template>
|
|
||||||
添加用户
|
|
||||||
</n-button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #action>
|
|
||||||
<TableAction />
|
|
||||||
</template>
|
|
||||||
</BasicTable>
|
|
||||||
</n-card>
|
|
||||||
|
|
||||||
<!-- 添加角色 -->
|
|
||||||
<UserModal ref="formRole" :formRoleValue="formRoleValue" />
|
|
||||||
|
|
||||||
<!-- 分配角色 -->
|
|
||||||
<n-modal
|
|
||||||
v-model:show="showModal"
|
|
||||||
:show-icon="false"
|
|
||||||
preset="dialog"
|
|
||||||
:title="editRoleTitle"
|
|
||||||
>
|
|
||||||
<n-form
|
|
||||||
ref="formRef"
|
|
||||||
:rules="rules"
|
|
||||||
label-placement="left"
|
|
||||||
label-width="auto"
|
|
||||||
:model="formRoleValue"
|
|
||||||
require-mark-placement="right-hanging"
|
|
||||||
>
|
|
||||||
<n-form-item label="用户名">
|
|
||||||
<n-input
|
|
||||||
disabled
|
|
||||||
v-model:value="formRoleValue.username"
|
|
||||||
placeholder="请输入用户名"
|
|
||||||
/>
|
|
||||||
</n-form-item>
|
|
||||||
|
|
||||||
<n-form-item label="真实姓名">
|
|
||||||
<n-input
|
|
||||||
disabled
|
|
||||||
v-model:value="formRoleValue.realname"
|
|
||||||
placeholder="请输入真实姓名"
|
|
||||||
/>
|
|
||||||
</n-form-item>
|
|
||||||
|
|
||||||
<n-form-item label="角色" path="roleIds">
|
|
||||||
<n-select
|
|
||||||
label-field="roleName"
|
|
||||||
value-field="id"
|
|
||||||
multiple
|
|
||||||
clearable
|
|
||||||
v-model:value="formRoleValue.roleIds"
|
|
||||||
:options="roleOptions"
|
|
||||||
/>
|
|
||||||
</n-form-item>
|
|
||||||
</n-form>
|
|
||||||
<template #action>
|
|
||||||
<n-space>
|
|
||||||
<n-button
|
|
||||||
type="primary"
|
|
||||||
:loading="formBtnLoading"
|
|
||||||
@click="confirmForm"
|
|
||||||
>提交</n-button
|
|
||||||
>
|
|
||||||
</n-space>
|
|
||||||
</template>
|
|
||||||
</n-modal>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { BasicTable, TableAction } from "@/components/Table";
|
|
||||||
|
|
||||||
import { columns } from "./columns";
|
|
||||||
import { PlusOutlined } from "@vicons/antd";
|
|
||||||
import { getUserList, updateUser } from "@/api/system/user";
|
|
||||||
import { getRuleList } from "@/api/system/role";
|
|
||||||
import { saveUserRole } from "@/api/system/userrole";
|
|
||||||
const actionRef = ref();
|
|
||||||
const formRef = ref();
|
|
||||||
const formRole = ref();
|
|
||||||
const rules = {
|
|
||||||
// roleIds: {
|
|
||||||
// type: "array",
|
|
||||||
// required: true,
|
|
||||||
// message: "请选择角色",
|
|
||||||
// trigger: ["blur", "change"],
|
|
||||||
// },
|
|
||||||
};
|
|
||||||
const roleIds = ref([]);
|
|
||||||
const formRoleValue = reactive({
|
|
||||||
id: null,
|
|
||||||
username: "",
|
|
||||||
realname: null,
|
|
||||||
password: "123456",
|
|
||||||
userType: 2,
|
|
||||||
sex: 1,
|
|
||||||
email: "",
|
|
||||||
phone: "",
|
|
||||||
status: 1,
|
|
||||||
skinColor: "white",
|
|
||||||
roleIds: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const roleOptions = ref([]);
|
|
||||||
|
|
||||||
const showModal = ref(false);
|
|
||||||
const formBtnLoading = ref(false);
|
|
||||||
const editRoleTitle = ref("");
|
|
||||||
const params = reactive({
|
|
||||||
username: "",
|
|
||||||
});
|
|
||||||
|
|
||||||
const actionColumn = reactive({
|
|
||||||
width: 250,
|
|
||||||
title: "操作",
|
|
||||||
key: "action",
|
|
||||||
fixed: "right",
|
|
||||||
render(record) {
|
|
||||||
return h(TableAction, {
|
|
||||||
style: "button",
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
label: "配置角色",
|
|
||||||
onClick: handleMenuAuth.bind(null, record),
|
|
||||||
// 根据业务控制是否显示 isShow 和 auth 是并且关系
|
|
||||||
ifShow: () => {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "编辑",
|
|
||||||
onClick: handleEdit.bind(null, record),
|
|
||||||
ifShow: () => {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "删除",
|
|
||||||
onClick: handleDelete.bind(null, record),
|
|
||||||
// 根据业务控制是否显示 isShow 和 auth 是并且关系
|
|
||||||
ifShow: () => {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// 新增按钮
|
|
||||||
const addRole = () => {
|
|
||||||
formRole.value.init("add");
|
|
||||||
};
|
|
||||||
|
|
||||||
const loadDataTable = async (res: any) => {
|
|
||||||
let _params = {
|
|
||||||
...unref(params),
|
|
||||||
...res,
|
|
||||||
};
|
|
||||||
const { data } = await getUserList(_params);
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
function onCheckedRow(rowKeys: any[]) {
|
|
||||||
console.log(rowKeys);
|
|
||||||
}
|
|
||||||
|
|
||||||
function reloadTable() {
|
|
||||||
actionRef.value.reload();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function confirmForm() {
|
|
||||||
formRef.value.validate(async (errors: any) => {
|
|
||||||
if (!errors) {
|
|
||||||
formBtnLoading.value = true;
|
|
||||||
|
|
||||||
const res = await saveUserRole({
|
|
||||||
userId: formRoleValue.id,
|
|
||||||
roleIds: formRoleValue.roleIds,
|
|
||||||
});
|
|
||||||
if (res.status === 200) {
|
|
||||||
showModal.value = false;
|
|
||||||
window["$message"].success("保存成功");
|
|
||||||
reloadTable();
|
|
||||||
formBtnLoading.value = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleEdit(record: Recordable) {
|
|
||||||
Object.assign(formRoleValue, record);
|
|
||||||
formRole.value.init("edit");
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleDelete(record: Recordable) {}
|
|
||||||
|
|
||||||
async function handleMenuAuth(record: Recordable) {
|
|
||||||
editRoleTitle.value = `分配 ${record.realname} 的角色权限`;
|
|
||||||
Object.assign(formRoleValue, record);
|
|
||||||
showModal.value = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
const { data } = await getRuleList({ current: 1, size: 100 });
|
|
||||||
roleOptions.value = data.records;
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
|
||||||
3
types/components.d.ts
vendored
3
types/components.d.ts
vendored
@ -17,9 +17,7 @@ declare module '@vue/runtime-core' {
|
|||||||
Histogram: typeof import('./../src/components/Charts/Histogram.vue')['default']
|
Histogram: typeof import('./../src/components/Charts/Histogram.vue')['default']
|
||||||
Line: typeof import('./../src/components/Charts/Line.vue')['default']
|
Line: typeof import('./../src/components/Charts/Line.vue')['default']
|
||||||
Main: typeof import('./../src/layout/components/Main/index.vue')['default']
|
Main: typeof import('./../src/layout/components/Main/index.vue')['default']
|
||||||
MenuModal: typeof import('./../src/views/system/role/components/MenuModal.vue')['default']
|
|
||||||
Ring: typeof import('./../src/components/Charts/Ring.vue')['default']
|
Ring: typeof import('./../src/components/Charts/Ring.vue')['default']
|
||||||
RoleModal: typeof import('./../src/views/system/role/components/RoleModal.vue')['default']
|
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
Sider: typeof import('./../src/layout/components/Sider/index.vue')['default']
|
Sider: typeof import('./../src/layout/components/Sider/index.vue')['default']
|
||||||
@ -27,6 +25,5 @@ declare module '@vue/runtime-core' {
|
|||||||
Table: typeof import('./../src/components/Table/src/Table.vue')['default']
|
Table: typeof import('./../src/components/Table/src/Table.vue')['default']
|
||||||
TableAction: typeof import('./../src/components/Table/src/components/TableAction.vue')['default']
|
TableAction: typeof import('./../src/components/Table/src/components/TableAction.vue')['default']
|
||||||
TransitionMain: typeof import('./../src/layout/components/TransitionMain/index.vue')['default']
|
TransitionMain: typeof import('./../src/layout/components/TransitionMain/index.vue')['default']
|
||||||
UserModal: typeof import('./../src/views/system/user/components/UserModal.vue')['default']
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user