Skip to content

Commit 8e6c1ab

Browse files
authored
feat: login dialog (#37)
* chore: login-dialog demo * Merge branch 'main' into login-dialog * chore: update dialog * Merge branch 'main' into login-dialog * chore: accept login params * chore: redirect to login or show login dialog
1 parent 0f246f7 commit 8e6c1ab

File tree

13 files changed

+174
-73
lines changed

13 files changed

+174
-73
lines changed

apps/web-antd/src/layouts/basic.vue

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
<script lang="ts" setup>
2-
import type { NotificationItem } from '@vben/layouts';
3-
4-
import { computed, ref } from 'vue';
2+
import { computed, ref, toRefs } from 'vue';
53
import { useRouter } from 'vue-router';
64
75
import { LOGIN_PATH } from '@vben/constants';
86
import { IcRoundCreditScore, MdiDriveDocument, MdiGithub } from '@vben/icons';
9-
import { BasicLayout, Notification, UserDropdown } from '@vben/layouts';
7+
import {
8+
BasicLayout,
9+
LoginDialog,
10+
Notification,
11+
NotificationItem,
12+
UserDropdown,
13+
} from '@vben/layouts';
1014
import { openWindow } from '@vben/utils';
1115
import { preferences } from '@vben-core/preferences';
1216
@@ -80,7 +84,8 @@ const menus = computed(() => [
8084
]);
8185
8286
const appStore = useAppStore();
83-
const { userInfo } = useAccessStore();
87+
const accessStore = useAccessStore();
88+
const { showLoginDialog, userInfo } = toRefs(accessStore);
8489
const router = useRouter();
8590
8691
async function handleLogout() {
@@ -118,5 +123,13 @@ function handleMakeAll() {
118123
@make-all="handleMakeAll"
119124
/>
120125
</template>
126+
<template #dialog>
127+
<LoginDialog
128+
:open="showLoginDialog"
129+
password-placeholder="123456"
130+
username-placeholder="vben"
131+
@login="accessStore.authLogin"
132+
/>
133+
</template>
121134
</BasicLayout>
122135
</template>

apps/web-antd/src/router/guard.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,25 @@ function setupAccessGuard(router: Router) {
9292

9393
// 生成路由表
9494
// 当前登录用户拥有的角色标识列表
95-
const userInfo =
96-
accessStore.userInfo || (await accessStore.fetchUserInfo());
97-
98-
const userRoles = userInfo.roles ?? [];
95+
let userRoles: string[] = [];
96+
try {
97+
const userInfo =
98+
accessStore.userInfo || (await accessStore.fetchUserInfo());
99+
userRoles = userInfo.roles ?? [];
100+
} catch (error: any) {
101+
if (error.status === 409) {
102+
accessStore.setShowLoginDialog(true);
103+
} else if (error.status === 401) {
104+
accessStore.reset();
105+
return {
106+
path: LOGIN_PATH,
107+
// 如不需要,直接删除 query
108+
query: { redirect: encodeURIComponent(to.fullPath) },
109+
// 携带当前跳转的页面,登录后重新跳转该页面
110+
replace: true,
111+
};
112+
}
113+
}
99114

100115
// 生成菜单和路由
101116
const { accessibleMenus, accessibleRoutes } = await generateAccess({

apps/web-antd/src/store/modules/access.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ export const useAccessStore = defineStore('access', () => {
1717
const router = useRouter();
1818
const loading = ref(false);
1919

20+
const showLoginDialog = ref(false);
21+
function setShowLoginDialog(value: boolean) {
22+
showLoginDialog.value = value;
23+
}
24+
2025
const accessToken = computed(() => coreStoreAccess.accessToken);
2126
const userRoles = computed(() => coreStoreAccess.userRoles);
2227
const userInfo = computed(() => coreStoreAccess.userInfo);
@@ -65,6 +70,7 @@ export const useAccessStore = defineStore('access', () => {
6570
coreStoreAccess.setUserInfo(userInfo);
6671
coreStoreAccess.setAccessCodes(accessCodes);
6772

73+
showLoginDialog.value = false;
6874
onSuccess
6975
? await onSuccess?.()
7076
: await router.push(userInfo.homePath || DEFAULT_HOME_PATH);
@@ -99,6 +105,8 @@ export const useAccessStore = defineStore('access', () => {
99105
reset,
100106
setAccessMenus,
101107
setAccessRoutes,
108+
setShowLoginDialog,
109+
showLoginDialog,
102110
userInfo,
103111
userRoles,
104112
};

packages/@core/ui-kit/layout-ui/src/vben-layout.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,7 @@ function handleOpenMenu() {
565565
<slot name="footer"></slot>
566566
</LayoutFooter>
567567
</div>
568+
<slot name="extra"></slot>
568569
<div
569570
v-if="maskVisible"
570571
:style="maskStyle"

packages/business/layouts/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
"@vben-core/stores": "workspace:*",
4949
"@vben-core/tabs-ui": "workspace:*",
5050
"@vben-core/toolkit": "workspace:*",
51+
"@vben/universal-ui": "workspace:*",
5152
"@vueuse/core": "^10.11.0",
5253
"vue": "^3.4.31",
5354
"vue-router": "^4.4.0"

packages/business/layouts/src/basic/layout.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,5 +277,9 @@ function clearPreferencesAndLogout() {
277277
/>
278278
</LayoutFooter>
279279
</template>
280+
281+
<template #extra>
282+
<slot name="dialog"></slot>
283+
</template>
280284
</VbenAdminLayout>
281285
</template>

packages/business/layouts/src/widgets/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export { default as CozeAssistant } from './coze-assistant.vue';
44
export * from './global-search';
55
export { default as LanguageToggle } from './language-toggle.vue';
66
export { default as AuthenticationLayoutToggle } from './layout-toggle.vue';
7+
export * from './login-dialog';
78
export * from './notification';
89
export * from './preferences';
910
export * from './theme-toggle';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as LoginDialog } from './login-dialog.vue';
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<script setup lang="ts">
2+
import { computed } from 'vue';
3+
4+
import {
5+
AuthenticationLogin,
6+
AuthenticationProps,
7+
LoginAndRegisterParams,
8+
} from '@vben/universal-ui';
9+
import { Dialog, DialogContent } from '@vben-core/shadcn-ui';
10+
11+
interface Props extends AuthenticationProps {
12+
open: boolean;
13+
}
14+
15+
defineOptions({
16+
name: 'LoginDialog',
17+
});
18+
19+
const props = withDefaults(defineProps<Props>(), {
20+
open: false,
21+
});
22+
23+
const emit = defineEmits<{
24+
login: [LoginAndRegisterParams];
25+
}>();
26+
27+
const loginProps = computed(() => {
28+
const { open: _, ...rest } = props;
29+
return rest;
30+
});
31+
</script>
32+
33+
<template>
34+
<div>
35+
<Dialog :open="open" class="flex items-center justify-center">
36+
<DialogContent
37+
class="top-[50%] w-full translate-y-[-50%] border-none p-0 shadow-xl sm:w-[600px] sm:rounded-2xl"
38+
>
39+
<div class="p-4">
40+
<AuthenticationLogin
41+
v-bind="loginProps"
42+
@submit="(e) => emit('login', e)"
43+
/>
44+
</div>
45+
</DialogContent>
46+
</Dialog>
47+
</div>
48+
</template>

packages/business/universal-ui/src/authentication/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,8 @@ export { default as AuthenticationForgetPassword } from './forget-password.vue';
33
export { default as AuthenticationLogin } from './login.vue';
44
export { default as AuthenticationQrCodeLogin } from './qrcode-login.vue';
55
export { default as AuthenticationRegister } from './register.vue';
6-
export type { LoginAndRegisterParams, LoginCodeParams } from './typings';
6+
export type {
7+
AuthenticationProps,
8+
LoginAndRegisterParams,
9+
LoginCodeParams,
10+
} from './typings';

0 commit comments

Comments
 (0)