Commit 0a3683a186ab55d34a12a5a3c6d794dfa1094ad4

Authored by 无木
1 parent f5e31feb

feat: customized user home page

新增自定义的用户首页(可以每个用户都不相同)
CHANGELOG.zh_CN.md
@@ -2,6 +2,8 @@ @@ -2,6 +2,8 @@
2 2
3 - **NoticeList** 添加分页、超长自动省略、标题点击事件、标题删除线等功能 3 - **NoticeList** 添加分页、超长自动省略、标题点击事件、标题删除线等功能
4 - **MixSider** 优化 Mix 菜单布局时 底部折叠按钮 的样式,与其它菜单布局时的风格保持一致 4 - **MixSider** 优化 Mix 菜单布局时 底部折叠按钮 的样式,与其它菜单布局时的风格保持一致
  5 +- 可以为不同的用户指定不同的后台首页:
  6 + - 在`getUserInfo`接口返回的用户信息中增加`homePath`字段(可选)即可为当前用户定制首页路径
5 7
6 ### 🐛 Bug Fixes 8 ### 🐛 Bug Fixes
7 9
@@ -18,6 +20,7 @@ @@ -18,6 +20,7 @@
18 - 修复左侧混合菜单的悬停触发逻辑 20 - 修复左侧混合菜单的悬停触发逻辑
19 - 修复顶栏菜单在显示包含需要隐藏的菜单项目时出错的问题 21 - 修复顶栏菜单在显示包含需要隐藏的菜单项目时出错的问题
20 - 修复悬停触发模式下左侧混合菜单会在没有子菜单且被激活时直接跳转路由 22 - 修复悬停触发模式下左侧混合菜单会在没有子菜单且被激活时直接跳转路由
  23 +- **Breadcrumb** 修复带有重定向的菜单点击无法跳转的问题
21 - **其它** 24 - **其它**
22 - 修复菜单默认折叠的配置不起作用的问题 25 - 修复菜单默认折叠的配置不起作用的问题
23 - 修复`safari`浏览器报错导致网站打不开 26 - 修复`safari`浏览器报错导致网站打不开
mock/sys/user.ts
@@ -11,6 +11,7 @@ export function createFakeUserList() { @@ -11,6 +11,7 @@ export function createFakeUserList() {
11 desc: 'manager', 11 desc: 'manager',
12 password: '123456', 12 password: '123456',
13 token: 'fakeToken1', 13 token: 'fakeToken1',
  14 + homePath: '/dashboard/analysis',
14 roles: [ 15 roles: [
15 { 16 {
16 roleName: 'Super Admin', 17 roleName: 'Super Admin',
@@ -26,6 +27,7 @@ export function createFakeUserList() { @@ -26,6 +27,7 @@ export function createFakeUserList() {
26 avatar: 'https://q1.qlogo.cn/g?b=qq&nk=339449197&s=640', 27 avatar: 'https://q1.qlogo.cn/g?b=qq&nk=339449197&s=640',
27 desc: 'tester', 28 desc: 'tester',
28 token: 'fakeToken2', 29 token: 'fakeToken2',
  30 + homePath: '/dashboard/workbench',
29 roles: [ 31 roles: [
30 { 32 {
31 roleName: 'Tester', 33 roleName: 'Tester',
src/components/Application/src/AppLogo.vue
@@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
17 import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; 17 import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
18 import { useDesign } from '/@/hooks/web/useDesign'; 18 import { useDesign } from '/@/hooks/web/useDesign';
19 import { PageEnum } from '/@/enums/pageEnum'; 19 import { PageEnum } from '/@/enums/pageEnum';
  20 + import { useUserStore } from '/@/store/modules/user';
20 21
21 const props = { 22 const props = {
22 /** 23 /**
@@ -39,6 +40,7 @@ @@ -39,6 +40,7 @@
39 setup(props) { 40 setup(props) {
40 const { prefixCls } = useDesign('app-logo'); 41 const { prefixCls } = useDesign('app-logo');
41 const { getCollapsedShowTitle } = useMenuSetting(); 42 const { getCollapsedShowTitle } = useMenuSetting();
  43 + const userStore = useUserStore();
42 const { title } = useGlobSetting(); 44 const { title } = useGlobSetting();
43 const go = useGo(); 45 const go = useGo();
44 46
@@ -56,7 +58,7 @@ @@ -56,7 +58,7 @@
56 ]); 58 ]);
57 59
58 function goHome() { 60 function goHome() {
59 - go(PageEnum.BASE_HOME); 61 + go(userStore.getUserInfo.homePath || PageEnum.BASE_HOME);
60 } 62 }
61 63
62 return { 64 return {
src/router/guard/permissionGuard.ts
@@ -7,8 +7,12 @@ import { useUserStoreWithOut } from '/@/store/modules/user'; @@ -7,8 +7,12 @@ import { useUserStoreWithOut } from '/@/store/modules/user';
7 7
8 import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic'; 8 import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic';
9 9
  10 +import { RootRoute } from '/@/router/routes';
  11 +
10 const LOGIN_PATH = PageEnum.BASE_LOGIN; 12 const LOGIN_PATH = PageEnum.BASE_LOGIN;
11 13
  14 +const ROOT_PATH = RootRoute.path;
  15 +
12 const whitePathList: PageEnum[] = [LOGIN_PATH]; 16 const whitePathList: PageEnum[] = [LOGIN_PATH];
13 17
14 export function createPermissionGuard(router: Router) { 18 export function createPermissionGuard(router: Router) {
@@ -17,7 +21,17 @@ export function createPermissionGuard(router: Router) { @@ -17,7 +21,17 @@ export function createPermissionGuard(router: Router) {
17 router.beforeEach(async (to, from, next) => { 21 router.beforeEach(async (to, from, next) => {
18 // Jump to the 404 page after processing the login 22 // Jump to the 404 page after processing the login
19 if (from.path === LOGIN_PATH && to.name === PAGE_NOT_FOUND_ROUTE.name) { 23 if (from.path === LOGIN_PATH && to.name === PAGE_NOT_FOUND_ROUTE.name) {
20 - next(PageEnum.BASE_HOME); 24 + next(userStore.getUserInfo.homePath || PageEnum.BASE_HOME);
  25 + return;
  26 + }
  27 +
  28 + if (
  29 + from.path === ROOT_PATH &&
  30 + to.path === PageEnum.BASE_HOME &&
  31 + userStore.getUserInfo.homePath &&
  32 + userStore.getUserInfo.homePath !== PageEnum.BASE_HOME
  33 + ) {
  34 + next(userStore.getUserInfo.homePath);
21 return; 35 return;
22 } 36 }
23 37
src/router/routes/modules/dashboard.ts
@@ -19,7 +19,7 @@ const dashboard: AppRouteModule = { @@ -19,7 +19,7 @@ const dashboard: AppRouteModule = {
19 name: 'Analysis', 19 name: 'Analysis',
20 component: () => import('/@/views/dashboard/analysis/index.vue'), 20 component: () => import('/@/views/dashboard/analysis/index.vue'),
21 meta: { 21 meta: {
22 - affix: true, 22 + // affix: true,
23 title: t('routes.dashboard.analysis'), 23 title: t('routes.dashboard.analysis'),
24 }, 24 },
25 }, 25 },
src/store/modules/multipleTab.ts
@@ -13,6 +13,7 @@ import { getRawRoute } from '/@/utils'; @@ -13,6 +13,7 @@ import { getRawRoute } from '/@/utils';
13 import { MULTIPLE_TABS_KEY } from '/@/enums/cacheEnum'; 13 import { MULTIPLE_TABS_KEY } from '/@/enums/cacheEnum';
14 14
15 import projectSetting from '/@/settings/projectSetting'; 15 import projectSetting from '/@/settings/projectSetting';
  16 +import { useUserStore } from '/@/store/modules/user';
16 17
17 export interface MultipleTabState { 18 export interface MultipleTabState {
18 cacheTabList: Set<string>; 19 cacheTabList: Set<string>;
@@ -181,7 +182,8 @@ export const useMultipleTabStore = defineStore({ @@ -181,7 +182,8 @@ export const useMultipleTabStore = defineStore({
181 if (index === 0) { 182 if (index === 0) {
182 // There is only one tab, then jump to the homepage, otherwise jump to the right tab 183 // There is only one tab, then jump to the homepage, otherwise jump to the right tab
183 if (this.tabList.length === 1) { 184 if (this.tabList.length === 1) {
184 - toTarget = PageEnum.BASE_HOME; 185 + const userStore = useUserStore();
  186 + toTarget = userStore.getUserInfo.homePath || PageEnum.BASE_HOME;
185 } else { 187 } else {
186 // Jump to the right tab 188 // Jump to the right tab
187 const page = this.tabList[index + 1]; 189 const page = this.tabList[index + 1];
src/store/modules/permission.ts
@@ -22,6 +22,7 @@ import { getMenuList } from &#39;/@/api/sys/menu&#39;; @@ -22,6 +22,7 @@ import { getMenuList } from &#39;/@/api/sys/menu&#39;;
22 import { getPermCode } from '/@/api/sys/user'; 22 import { getPermCode } from '/@/api/sys/user';
23 23
24 import { useMessage } from '/@/hooks/web/useMessage'; 24 import { useMessage } from '/@/hooks/web/useMessage';
  25 +import { PageEnum } from '/@/enums/pageEnum';
25 26
26 interface PermissionState { 27 interface PermissionState {
27 // Permission code list 28 // Permission code list
@@ -117,6 +118,32 @@ export const usePermissionStore = defineStore({ @@ -117,6 +118,32 @@ export const usePermissionStore = defineStore({
117 return !ignoreRoute; 118 return !ignoreRoute;
118 }; 119 };
119 120
  121 + /**
  122 + * @description 根据设置的首页path,修正routes中的affix标记(固定首页)
  123 + * */
  124 + const patchHomeAffix = (routes: AppRouteRecordRaw[]) => {
  125 + if (!routes || routes.length === 0) return;
  126 + const homePath = userStore.getUserInfo.homePath || PageEnum.BASE_HOME;
  127 + function patcher(routes: AppRouteRecordRaw[], parentPath = '') {
  128 + if (parentPath) parentPath = parentPath + '/';
  129 + routes.forEach((route: AppRouteRecordRaw) => {
  130 + const { path, children } = route;
  131 + const currentPath = path.startsWith('/') ? path : parentPath + path;
  132 + if (currentPath === homePath) {
  133 + route.meta = Object.assign({}, route.meta, { affix: true });
  134 + throw new Error('end');
  135 + }
  136 + children && children.length > 0 && patcher(children, currentPath);
  137 + });
  138 + }
  139 + try {
  140 + patcher(routes);
  141 + } catch (e) {
  142 + // 已处理完毕跳出循环
  143 + }
  144 + return;
  145 + };
  146 +
120 switch (permissionMode) { 147 switch (permissionMode) {
121 case PermissionModeEnum.ROLE: 148 case PermissionModeEnum.ROLE:
122 routes = filter(asyncRoutes, routeFilter); 149 routes = filter(asyncRoutes, routeFilter);
@@ -176,6 +203,7 @@ export const usePermissionStore = defineStore({ @@ -176,6 +203,7 @@ export const usePermissionStore = defineStore({
176 } 203 }
177 204
178 routes.push(ERROR_LOG_ROUTE); 205 routes.push(ERROR_LOG_ROUTE);
  206 + patchHomeAffix(routes);
179 return routes; 207 return routes;
180 }, 208 },
181 }, 209 },
src/store/modules/user.ts
@@ -88,13 +88,15 @@ export const useUserStore = defineStore({ @@ -88,13 +88,15 @@ export const useUserStore = defineStore({
88 88
89 const sessionTimeout = this.sessionTimeout; 89 const sessionTimeout = this.sessionTimeout;
90 sessionTimeout && this.setSessionTimeout(false); 90 sessionTimeout && this.setSessionTimeout(false);
91 - !sessionTimeout && goHome && (await router.replace(PageEnum.BASE_HOME)); 91 + !sessionTimeout &&
  92 + goHome &&
  93 + (await router.replace(userInfo.homePath || PageEnum.BASE_HOME));
92 return userInfo; 94 return userInfo;
93 } catch (error) { 95 } catch (error) {
94 return Promise.reject(error); 96 return Promise.reject(error);
95 } 97 }
96 }, 98 },
97 - async getUserInfoAction() { 99 + async getUserInfoAction(): Promise<UserInfo> {
98 const userInfo = await getUserInfo(); 100 const userInfo = await getUserInfo();
99 const { roles } = userInfo; 101 const { roles } = userInfo;
100 const roleList = roles.map((item) => item.value) as RoleEnum[]; 102 const roleList = roles.map((item) => item.value) as RoleEnum[];
types/store.d.ts
1 import { ErrorTypeEnum } from '/@/enums/exceptionEnum'; 1 import { ErrorTypeEnum } from '/@/enums/exceptionEnum';
2 import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum'; 2 import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
  3 +import { RoleInfo } from '/@/api/sys/model/userModel';
3 4
4 // Lock screen information 5 // Lock screen information
5 export interface LockInfo { 6 export interface LockInfo {
@@ -35,6 +36,8 @@ export interface UserInfo { @@ -35,6 +36,8 @@ export interface UserInfo {
35 realName: string; 36 realName: string;
36 avatar: string; 37 avatar: string;
37 desc?: string; 38 desc?: string;
  39 + homePath?: string;
  40 + roles: RoleInfo[];
38 } 41 }
39 42
40 export interface BeforeMiniState { 43 export interface BeforeMiniState {