From 435c2f7d2b1748e029c8b669706889b7c1a6f5f0 Mon Sep 17 00:00:00 2001 From: zzy Date: Tue, 21 Apr 2026 00:40:56 +0800 Subject: [PATCH] =?UTF-8?q?=E7=99=BB=E5=BD=95=E6=94=AF=E6=8C=81=E9=80=89?= =?UTF-8?q?=E6=8B=A9=E7=A7=9F=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/login/index.ts | 26 ++++ src/api/login/types.ts | 1 + src/locales/zh-CN.ts | 4 +- src/views/Login/components/LoginForm.vue | 149 +++++++++++++++++++---- 4 files changed, 153 insertions(+), 27 deletions(-) diff --git a/src/api/login/index.ts b/src/api/login/index.ts index 37eb491..dfbb76f 100644 --- a/src/api/login/index.ts +++ b/src/api/login/index.ts @@ -89,3 +89,29 @@ export const reqCheck = (data: any) => { export const smsResetPassword = (data: any) => { return request.post({ url: '/system/auth/reset-password', data }) } + +// 获取用户的租户列表(未登录状态) +export interface UserTenantListVO { + username: string + password: string +} + +export interface TenantInfo { + tenantId: number + tenantName: string + isDefault: boolean +} + +export interface UserTenantListRespVO { + userId: number + username: string + nickname: string + tenants: TenantInfo[] +} + +export const getUserTenantList = (data: UserTenantListVO) => { + return request.post({ + url: '/system/auth/get-user-tenant-list', + data + }) +} diff --git a/src/api/login/types.ts b/src/api/login/types.ts index b5790e6..54e058b 100644 --- a/src/api/login/types.ts +++ b/src/api/login/types.ts @@ -1,4 +1,5 @@ export type UserLoginVO = { + tenantId?: number username: string password: string captchaVerification: string diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index 3b6c2e9..e2349f1 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -128,7 +128,7 @@ export default { remember: '记住我', hasUser: '已有账号?去登录', forgetPassword: '忘记密码?', - tenantNamePlaceholder: '请输入租户名称', + tenantNamePlaceholder: '请选择要登录的小区', usernamePlaceholder: '请输入用户名', passwordPlaceholder: '请输入密码', codePlaceholder: '请输入验证码', @@ -455,4 +455,4 @@ export default { preview: '预览' }, 'OAuth 2.0': 'OAuth 2.0' // 避免菜单名是 OAuth 2.0 时,一直 warn 报错 -} \ No newline at end of file +} diff --git a/src/views/Login/components/LoginForm.vue b/src/views/Login/components/LoginForm.vue index a7ceea7..56714bf 100644 --- a/src/views/Login/components/LoginForm.vue +++ b/src/views/Login/components/LoginForm.vue @@ -15,17 +15,6 @@ - - - - - + + + + + + + @@ -117,20 +125,28 @@ const redirect = ref('') const loginLoading = ref(false) const verify = ref() const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字 pictureWord 文字验证码 +const tenantList = ref([]) +const isFetchingTenants = ref(false) const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN) const LoginRules = { - tenantName: [required], username: [required], - password: [required] + password: [required], + tenantId: [ + { + required: true, + message: '请选择租户', + trigger: 'change' + } + ] } const loginData = reactive({ isShowPassword: false, captchaEnable: import.meta.env.VITE_APP_CAPTCHA_ENABLE, tenantEnable: import.meta.env.VITE_APP_TENANT_ENABLE, loginForm: { - tenantName: import.meta.env.VITE_APP_DEFAULT_LOGIN_TENANT || '', + tenantId: undefined as number | undefined, username: import.meta.env.VITE_APP_DEFAULT_LOGIN_USERNAME || '', password: import.meta.env.VITE_APP_DEFAULT_LOGIN_PASSWORD || '', captchaVerification: '', @@ -145,8 +161,94 @@ const socialList = [ { icon: 'ant-design:alipay-circle-filled', type: 0 } ] +// 获取租户列表 +const fetchTenantList = async () => { + if (loginData.tenantEnable !== 'true') { + return + } + + const username = loginData.loginForm.username?.trim() + const password = loginData.loginForm.password?.trim() + + // 只有当用户名和密码都不为空时才获取租户列表 + if (!username || !password) { + return + } + + // 防止重复请求 + if (isFetchingTenants.value) { + return + } + + isFetchingTenants.value = true + + try { + const res = await LoginApi.getUserTenantList({ + username, + password + }) + + if (!res || !res.tenants || res.tenants.length === 0) { + message.error('无权限访问该系统') + tenantList.value = [] + loginData.loginForm.tenantId = undefined + return + } + + tenantList.value = res.tenants + + // 默认选中第一个租户 + if (res.tenants.length > 0) { + loginData.loginForm.tenantId = res.tenants[0].tenantId + } + } catch (error) { + console.error('获取租户列表失败:', error) + tenantList.value = [] + loginData.loginForm.tenantId = undefined + } finally { + isFetchingTenants.value = false + } +} + // 获取验证码 const getCode = async () => { + // 如果开启了租户功能且还没有获取租户列表,先获取 + if (loginData.tenantEnable === 'true' && tenantList.value.length === 0) { + const username = loginData.loginForm.username?.trim() + const password = loginData.loginForm.password?.trim() + + if (!username || !password) { + message.error('请输入用户名和密码') + return + } + + // 获取租户列表 + await fetchTenantList() + + // 如果获取后仍然没有租户列表,说明无权限 + if (tenantList.value.length === 0) { + return + } + + // 如果只有一个租户,自动选中并继续登录流程 + if (tenantList.value.length === 1) { + loginData.loginForm.tenantId = tenantList.value[0].tenantId + // 单租户直接继续登录 + } else { + // 如果有多个租户但未选择,提示用户选择 + if (!loginData.loginForm.tenantId) { + message.error('请选择租户') + return + } + } + } else if (loginData.tenantEnable === 'true' && tenantList.value.length > 0) { + // 已有租户列表,验证是否已选择 + if (!loginData.loginForm.tenantId) { + message.error('请选择租户') + return + } + } + // 情况一,未开启:则直接登录 if (loginData.captchaEnable === 'false') { await handleLogin({}) @@ -156,11 +258,10 @@ const getCode = async () => { verify.value.show() } } -// 获取租户 ID -const getTenantId = async () => { - if (loginData.tenantEnable === 'true') { - const res = await LoginApi.getTenantIdByName(loginData.loginForm.tenantName) - authUtil.setTenantId(res) +// 设置租户ID +const setTenantId = () => { + if (loginData.loginForm.tenantId) { + authUtil.setTenantId(loginData.loginForm.tenantId) } } // 记住我 @@ -171,8 +272,7 @@ const getLoginFormCache = () => { ...loginData.loginForm, username: loginForm.username ? loginForm.username : loginData.loginForm.username, password: loginForm.password ? loginForm.password : loginData.loginForm.password, - rememberMe: loginForm.rememberMe, - tenantName: loginForm.tenantName ? loginForm.tenantName : loginData.loginForm.tenantName + rememberMe: loginForm.rememberMe } } } @@ -182,7 +282,6 @@ const getTenantByWebsite = async () => { const website = location.host const res = await LoginApi.getTenantByWebsite(website) if (res) { - loginData.loginForm.tenantName = res.name authUtil.setTenantId(res.id) } } @@ -192,7 +291,7 @@ const loading = ref() // ElLoading.service 返回的实例 const handleLogin = async (params: any) => { loginLoading.value = true try { - await getTenantId() + setTenantId() const data = await validForm() if (!data) { return @@ -236,8 +335,8 @@ const doSocialLogin = async (type: number) => { } else { loginLoading.value = true if (loginData.tenantEnable === 'true') { - // 尝试先通过 tenantName 获取租户 - await getTenantId() + // 尝试先通过 tenantId 获取租户 + setTenantId() // 如果获取不到,则需要弹出提示,进行处理 if (!authUtil.getTenantId()) { try {