| | |
| | | show-password |
| | | /> |
| | | </ElFormItem> |
| | | <ElFormItem v-if="requiresTenantSelection" prop="tenantId"> |
| | | <ElSelect |
| | | v-model="formData.tenantId" |
| | | class="w-full" |
| | | clearable |
| | | filterable |
| | | :loading="tenantLoading" |
| | | :placeholder="$t('login.placeholder.tenant')" |
| | | > |
| | | <ElOption |
| | | v-for="tenant in tenantOptions" |
| | | :key="tenant.id" |
| | | :label="tenant.name" |
| | | :value="tenant.id" |
| | | /> |
| | | </ElSelect> |
| | | </ElFormItem> |
| | | |
| | | <div class="flex-cb mt-2 text-sm"> |
| | | <ElCheckbox v-model="formData.rememberPassword">{{ |
| | |
| | | |
| | | <script setup> |
| | | import AppConfig from '@/config' |
| | | import { StorageConfig } from '@/utils/storage/storage-config' |
| | | import { useUserStore } from '@/store/modules/user' |
| | | import { useI18n } from 'vue-i18n' |
| | | import { fetchGetUserInfo, fetchLogin, normalizeLoginResponse } from '@/api/auth' |
| | | import { |
| | | fetchGetSystemInfo, |
| | | fetchGetTenantList, |
| | | fetchGetUserInfo, |
| | | fetchLogin, |
| | | normalizeLoginResponse |
| | | } from '@/api/auth' |
| | | import { ElNotification } from 'element-plus' |
| | | defineOptions({ name: 'Login' }) |
| | | const { t, locale } = useI18n() |
| | |
| | | const formData = reactive({ |
| | | username: '', |
| | | password: '', |
| | | tenantId: '', |
| | | rememberPassword: true |
| | | }) |
| | | const loginMode = ref('') |
| | | const tenantLoading = ref(false) |
| | | const tenantOptions = ref([]) |
| | | const requiresTenantSelection = computed(() => loginMode.value === 'OFFLINE') |
| | | const rules = computed(() => ({ |
| | | username: [{ required: true, message: t('login.placeholder.username'), trigger: 'blur' }], |
| | | password: [{ required: true, message: t('login.placeholder.password'), trigger: 'blur' }] |
| | | password: [{ required: true, message: t('login.placeholder.password'), trigger: 'blur' }], |
| | | tenantId: requiresTenantSelection.value |
| | | ? [{ required: true, message: t('login.placeholder.tenant'), trigger: 'change' }] |
| | | : [] |
| | | })) |
| | | const loading = ref(false) |
| | | |
| | | const hydrateRememberedLogin = () => { |
| | | const rememberEnabled = |
| | | localStorage.getItem(StorageConfig.LOGIN_REMEMBER_ENABLED_KEY) !== 'false' |
| | | formData.rememberPassword = rememberEnabled |
| | | if (rememberEnabled) { |
| | | formData.username = localStorage.getItem(StorageConfig.LOGIN_REMEMBER_USERNAME_KEY) || '' |
| | | formData.password = localStorage.getItem(StorageConfig.LOGIN_REMEMBER_PASSWORD_KEY) || '' |
| | | } |
| | | } |
| | | |
| | | const persistRememberedTenant = (tenantId) => { |
| | | if (tenantId === '' || tenantId === null || tenantId === void 0) { |
| | | localStorage.removeItem(StorageConfig.LOGIN_REMEMBER_TENANT_ID_KEY) |
| | | return |
| | | } |
| | | localStorage.setItem(StorageConfig.LOGIN_REMEMBER_TENANT_ID_KEY, String(tenantId)) |
| | | } |
| | | |
| | | const applyDefaultTenantSelection = () => { |
| | | if (!requiresTenantSelection.value || tenantOptions.value.length === 0) { |
| | | formData.tenantId = '' |
| | | return |
| | | } |
| | | |
| | | const rememberedTenantId = localStorage.getItem(StorageConfig.LOGIN_REMEMBER_TENANT_ID_KEY) |
| | | const matchedTenant = tenantOptions.value.find( |
| | | (item) => String(item.id) === String(rememberedTenantId) |
| | | ) |
| | | |
| | | formData.tenantId = matchedTenant?.id ?? tenantOptions.value[0].id |
| | | persistRememberedTenant(formData.tenantId) |
| | | } |
| | | |
| | | const loadLoginSupports = async () => { |
| | | const systemInfo = await fetchGetSystemInfo() |
| | | loginMode.value = systemInfo?.mode || '' |
| | | |
| | | if (!requiresTenantSelection.value) { |
| | | tenantOptions.value = [] |
| | | formData.tenantId = '' |
| | | return |
| | | } |
| | | |
| | | tenantLoading.value = true |
| | | try { |
| | | const tenants = await fetchGetTenantList() |
| | | tenantOptions.value = Array.isArray(tenants) ? tenants : [] |
| | | applyDefaultTenantSelection() |
| | | } finally { |
| | | tenantLoading.value = false |
| | | } |
| | | } |
| | | |
| | | const persistRememberedLogin = () => { |
| | | localStorage.setItem( |
| | | StorageConfig.LOGIN_REMEMBER_ENABLED_KEY, |
| | | String(Boolean(formData.rememberPassword)) |
| | | ) |
| | | |
| | | if (formData.rememberPassword) { |
| | | localStorage.setItem(StorageConfig.LOGIN_REMEMBER_USERNAME_KEY, formData.username || '') |
| | | localStorage.setItem(StorageConfig.LOGIN_REMEMBER_PASSWORD_KEY, formData.password || '') |
| | | } else { |
| | | localStorage.removeItem(StorageConfig.LOGIN_REMEMBER_USERNAME_KEY) |
| | | localStorage.removeItem(StorageConfig.LOGIN_REMEMBER_PASSWORD_KEY) |
| | | } |
| | | |
| | | persistRememberedTenant(formData.tenantId) |
| | | } |
| | | |
| | | const handleSubmit = async () => { |
| | | if (!formRef.value) return |
| | | try { |
| | |
| | | loading.value = true |
| | | const payload = normalizeLoginResponse(await fetchLogin(formData)) |
| | | if (!payload.accessToken) return |
| | | persistRememberedLogin() |
| | | userStore.setToken(payload.accessToken, payload.refreshToken) |
| | | userStore.setLoginStatus(true) |
| | | const userInfo = await fetchGetUserInfo() |
| | |
| | | loading.value = false |
| | | } |
| | | } |
| | | |
| | | watch( |
| | | () => formData.tenantId, |
| | | (value) => { |
| | | if (requiresTenantSelection.value) { |
| | | persistRememberedTenant(value) |
| | | } |
| | | } |
| | | ) |
| | | |
| | | onMounted(async () => { |
| | | hydrateRememberedLogin() |
| | | await loadLoginSupports() |
| | | }) |
| | | |
| | | const showLoginSuccessNotice = () => { |
| | | setTimeout(() => { |
| | | ElNotification({ |