登录支持选择租户

master
zzy 2026-04-21 00:40:56 +08:00
parent 356298e599
commit 435c2f7d2b
4 changed files with 153 additions and 27 deletions

View File

@ -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
})
}

View File

@ -1,4 +1,5 @@
export type UserLoginVO = {
tenantId?: number
username: string
password: string
captchaVerification: string

View File

@ -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 报错
}
}

View File

@ -15,17 +15,6 @@
<LoginFormTitle class="w-full" />
</el-form-item>
</el-col>
<el-col :span="24" class="px-10px">
<el-form-item v-if="loginData.tenantEnable === 'true'" prop="tenantName">
<el-input
v-model="loginData.loginForm.tenantName"
:placeholder="t('login.tenantNamePlaceholder')"
:prefix-icon="iconHouse"
link
type="primary"
/>
</el-form-item>
</el-col>
<el-col :span="24" class="px-10px">
<el-form-item prop="username">
<el-input
@ -47,6 +36,25 @@
/>
</el-form-item>
</el-col>
<el-col :span="24" class="px-10px">
<el-form-item v-if="loginData.tenantEnable === 'true'" prop="tenantId">
<el-select
v-model="loginData.loginForm.tenantId"
:placeholder="t('login.tenantNamePlaceholder')"
:prefix-icon="iconHouse"
style="width: 100%"
:disabled="tenantList.length === 0"
@keyup.enter="getCode()"
>
<el-option
v-for="tenant in tenantList"
:key="tenant.tenantId"
:label="tenant.tenantName"
:value="tenant.tenantId"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24" class="px-10px mt-[-20px] mb-[-20px]">
<el-form-item>
<el-row justify="space-between" style="width: 100%">
@ -117,20 +125,28 @@ const redirect = ref<string>('')
const loginLoading = ref(false)
const verify = ref()
const captchaType = ref('blockPuzzle') // blockPuzzle clickWord pictureWord
const tenantList = ref<LoginApi.TenantInfo[]>([])
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 {