登录支持选择租户

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) => { export const smsResetPassword = (data: any) => {
return request.post({ url: '/system/auth/reset-password', data }) 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 = { export type UserLoginVO = {
tenantId?: number
username: string username: string
password: string password: string
captchaVerification: string captchaVerification: string

View File

@ -128,7 +128,7 @@ export default {
remember: '记住我', remember: '记住我',
hasUser: '已有账号?去登录', hasUser: '已有账号?去登录',
forgetPassword: '忘记密码?', forgetPassword: '忘记密码?',
tenantNamePlaceholder: '请输入租户名称', tenantNamePlaceholder: '请选择要登录的小区',
usernamePlaceholder: '请输入用户名', usernamePlaceholder: '请输入用户名',
passwordPlaceholder: '请输入密码', passwordPlaceholder: '请输入密码',
codePlaceholder: '请输入验证码', codePlaceholder: '请输入验证码',
@ -455,4 +455,4 @@ export default {
preview: '预览' preview: '预览'
}, },
'OAuth 2.0': 'OAuth 2.0' // 避免菜单名是 OAuth 2.0 时,一直 warn 报错 'OAuth 2.0': 'OAuth 2.0' // 避免菜单名是 OAuth 2.0 时,一直 warn 报错
} }

View File

@ -15,17 +15,6 @@
<LoginFormTitle class="w-full" /> <LoginFormTitle class="w-full" />
</el-form-item> </el-form-item>
</el-col> </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-col :span="24" class="px-10px">
<el-form-item prop="username"> <el-form-item prop="username">
<el-input <el-input
@ -47,6 +36,25 @@
/> />
</el-form-item> </el-form-item>
</el-col> </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-col :span="24" class="px-10px mt-[-20px] mb-[-20px]">
<el-form-item> <el-form-item>
<el-row justify="space-between" style="width: 100%"> <el-row justify="space-between" style="width: 100%">
@ -117,20 +125,28 @@ const redirect = ref<string>('')
const loginLoading = ref(false) const loginLoading = ref(false)
const verify = ref() const verify = ref()
const captchaType = ref('blockPuzzle') // blockPuzzle clickWord pictureWord const captchaType = ref('blockPuzzle') // blockPuzzle clickWord pictureWord
const tenantList = ref<LoginApi.TenantInfo[]>([])
const isFetchingTenants = ref(false)
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN) const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN)
const LoginRules = { const LoginRules = {
tenantName: [required],
username: [required], username: [required],
password: [required] password: [required],
tenantId: [
{
required: true,
message: '请选择租户',
trigger: 'change'
}
]
} }
const loginData = reactive({ const loginData = reactive({
isShowPassword: false, isShowPassword: false,
captchaEnable: import.meta.env.VITE_APP_CAPTCHA_ENABLE, captchaEnable: import.meta.env.VITE_APP_CAPTCHA_ENABLE,
tenantEnable: import.meta.env.VITE_APP_TENANT_ENABLE, tenantEnable: import.meta.env.VITE_APP_TENANT_ENABLE,
loginForm: { loginForm: {
tenantName: import.meta.env.VITE_APP_DEFAULT_LOGIN_TENANT || '', tenantId: undefined as number | undefined,
username: import.meta.env.VITE_APP_DEFAULT_LOGIN_USERNAME || '', username: import.meta.env.VITE_APP_DEFAULT_LOGIN_USERNAME || '',
password: import.meta.env.VITE_APP_DEFAULT_LOGIN_PASSWORD || '', password: import.meta.env.VITE_APP_DEFAULT_LOGIN_PASSWORD || '',
captchaVerification: '', captchaVerification: '',
@ -145,8 +161,94 @@ const socialList = [
{ icon: 'ant-design:alipay-circle-filled', type: 0 } { 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 () => { 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') { if (loginData.captchaEnable === 'false') {
await handleLogin({}) await handleLogin({})
@ -156,11 +258,10 @@ const getCode = async () => {
verify.value.show() verify.value.show()
} }
} }
// ID // ID
const getTenantId = async () => { const setTenantId = () => {
if (loginData.tenantEnable === 'true') { if (loginData.loginForm.tenantId) {
const res = await LoginApi.getTenantIdByName(loginData.loginForm.tenantName) authUtil.setTenantId(loginData.loginForm.tenantId)
authUtil.setTenantId(res)
} }
} }
// //
@ -171,8 +272,7 @@ const getLoginFormCache = () => {
...loginData.loginForm, ...loginData.loginForm,
username: loginForm.username ? loginForm.username : loginData.loginForm.username, username: loginForm.username ? loginForm.username : loginData.loginForm.username,
password: loginForm.password ? loginForm.password : loginData.loginForm.password, password: loginForm.password ? loginForm.password : loginData.loginForm.password,
rememberMe: loginForm.rememberMe, rememberMe: loginForm.rememberMe
tenantName: loginForm.tenantName ? loginForm.tenantName : loginData.loginForm.tenantName
} }
} }
} }
@ -182,7 +282,6 @@ const getTenantByWebsite = async () => {
const website = location.host const website = location.host
const res = await LoginApi.getTenantByWebsite(website) const res = await LoginApi.getTenantByWebsite(website)
if (res) { if (res) {
loginData.loginForm.tenantName = res.name
authUtil.setTenantId(res.id) authUtil.setTenantId(res.id)
} }
} }
@ -192,7 +291,7 @@ const loading = ref() // ElLoading.service 返回的实例
const handleLogin = async (params: any) => { const handleLogin = async (params: any) => {
loginLoading.value = true loginLoading.value = true
try { try {
await getTenantId() setTenantId()
const data = await validForm() const data = await validForm()
if (!data) { if (!data) {
return return
@ -236,8 +335,8 @@ const doSocialLogin = async (type: number) => {
} else { } else {
loginLoading.value = true loginLoading.value = true
if (loginData.tenantEnable === 'true') { if (loginData.tenantEnable === 'true') {
// tenantName // tenantId
await getTenantId() setTenantId()
// //
if (!authUtil.getTenantId()) { if (!authUtil.getTenantId()) {
try { try {