Commit 0a3683a186ab55d34a12a5a3c6d794dfa1094ad4

Authored by 无木
1 parent f5e31feb

feat: customized user home page

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