登录调整
parent
19825c7bc3
commit
bfff16cd6b
|
|
@ -115,3 +115,22 @@ export const getUserTenantList = (data: UserTenantListVO) => {
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 切换租户并重新登录
|
||||||
|
export interface SwitchTenantVO {
|
||||||
|
tenantId: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export const switchTenant = (data: SwitchTenantVO) => {
|
||||||
|
return request.post({
|
||||||
|
url: '/system/auth/switch-tenant',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取登录用户的租户列表(已登录状态)
|
||||||
|
export const getLoggedInUserTenantList = () => {
|
||||||
|
return request.get({
|
||||||
|
url: '/system/auth/get-user-tenant-list'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,102 @@
|
||||||
|
<template>
|
||||||
|
<div class="tenant-switch-btn" @click="handleOpenDialog">
|
||||||
|
<Icon icon="ep:location" class="tenant-icon" />
|
||||||
|
<span class="tenant-name">{{ currentTenantName || '选择小区' }}</span>
|
||||||
|
<Icon icon="ep:arrow-down" class="arrow-icon" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<TenantSwitchDialog v-model="dialogVisible" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { useUserStore } from '@/store/modules/user'
|
||||||
|
import TenantSwitchDialog from './TenantSwitchDialog.vue'
|
||||||
|
import * as LoginApi from '@/api/login'
|
||||||
|
|
||||||
|
defineOptions({ name: 'TenantSwitchButton' })
|
||||||
|
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
const loading = ref(false)
|
||||||
|
|
||||||
|
// 当前小区名称
|
||||||
|
const currentTenantName = computed(() => {
|
||||||
|
return userStore.user.tenantName || ''
|
||||||
|
})
|
||||||
|
|
||||||
|
// 打开切换弹窗
|
||||||
|
const handleOpenDialog = () => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前小区信息
|
||||||
|
const getCurrentTenant = async () => {
|
||||||
|
if (currentTenantName.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const res = await LoginApi.getLoggedInUserTenantList()
|
||||||
|
const tenantList = Array.isArray(res) ? res : (res.data || [])
|
||||||
|
|
||||||
|
if (tenantList.length > 0) {
|
||||||
|
const defaultTenant = tenantList.find((t: any) => t.isDefault)
|
||||||
|
if (defaultTenant) {
|
||||||
|
userStore.user.tenantId = defaultTenant.tenantId
|
||||||
|
userStore.user.tenantName = defaultTenant.tenantName
|
||||||
|
} else if (tenantList.length === 1) {
|
||||||
|
userStore.user.tenantId = tenantList[0].tenantId
|
||||||
|
userStore.user.tenantName = tenantList[0].tenantName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取当前小区信息失败:', error)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组件挂载时获取当前小区
|
||||||
|
onMounted(() => {
|
||||||
|
getCurrentTenant()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.tenant-switch-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 8px 20px;
|
||||||
|
min-width: 160px;
|
||||||
|
margin-right: 12px;
|
||||||
|
background: rgba(255, 255, 255, 0.15);
|
||||||
|
border-radius: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s;
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tenant-icon {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tenant-name {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
max-width: 100px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow-icon {
|
||||||
|
font-size: 12px;
|
||||||
|
transition: transform 0.3s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,200 @@
|
||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-model="dialogVisible"
|
||||||
|
title="切换小区"
|
||||||
|
width="500px"
|
||||||
|
:close-on-click-modal="true"
|
||||||
|
>
|
||||||
|
<div v-loading="loading" class="tenant-switch-content">
|
||||||
|
<el-empty v-if="!loading && tenantList.length === 0" description="暂无可切换的小区" />
|
||||||
|
<div v-else class="tenant-list">
|
||||||
|
<div
|
||||||
|
v-for="tenant in tenantList"
|
||||||
|
:key="tenant.tenantId"
|
||||||
|
class="tenant-item"
|
||||||
|
:class="{
|
||||||
|
'tenant-item-active': tenant.isDefault,
|
||||||
|
'tenant-item-disabled': tenant.isDefault
|
||||||
|
}"
|
||||||
|
@click="handleSwitchTenant(tenant)"
|
||||||
|
>
|
||||||
|
<div class="tenant-info">
|
||||||
|
<div class="tenant-name">{{ tenant.tenantName }}</div>
|
||||||
|
<div v-if="tenant.isDefault" class="tenant-tag">
|
||||||
|
当前小区
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Icon v-if="!tenant.isDefault" icon="ep:arrow-right" class="tenant-arrow" />
|
||||||
|
<Icon v-else icon="ep:check" class="tenant-check" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import * as LoginApi from '@/api/login'
|
||||||
|
import { useUserStore } from '@/store/modules/user'
|
||||||
|
import * as authUtil from '@/utils/auth'
|
||||||
|
import { deleteUserCache } from '@/hooks/web/useCache'
|
||||||
|
|
||||||
|
defineOptions({ name: 'TenantSwitchDialog' })
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
const message = useMessage()
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const { push } = useRouter()
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
modelValue: boolean
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
'update:modelValue': [value: boolean]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const dialogVisible = computed({
|
||||||
|
get: () => props.modelValue,
|
||||||
|
set: (value) => emit('update:modelValue', value)
|
||||||
|
})
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
const tenantList = ref<any[]>([])
|
||||||
|
|
||||||
|
// 获取用户小区列表
|
||||||
|
const getTenantList = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const res = await LoginApi.getLoggedInUserTenantList()
|
||||||
|
tenantList.value = Array.isArray(res) ? res : (res.data || [])
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取小区列表失败:', error)
|
||||||
|
message.error('获取小区列表失败')
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 切换小区
|
||||||
|
const handleSwitchTenant = async (tenant: any) => {
|
||||||
|
if (tenant.isDefault) {
|
||||||
|
message.info('当前已是该小区')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await message.confirm(`确定要切换到【${tenant.tenantName}】吗?`, '切换小区')
|
||||||
|
|
||||||
|
loading.value = true
|
||||||
|
|
||||||
|
// 调用切换租户接口
|
||||||
|
const res = await LoginApi.switchTenant({ tenantId: tenant.tenantId })
|
||||||
|
|
||||||
|
// 更新 token(类似登录操作)
|
||||||
|
authUtil.setToken(res)
|
||||||
|
|
||||||
|
// 清除用户缓存
|
||||||
|
deleteUserCache()
|
||||||
|
|
||||||
|
// 重置用户状态
|
||||||
|
userStore.resetState()
|
||||||
|
|
||||||
|
// 重新加载用户信息
|
||||||
|
await userStore.setUserInfoAction()
|
||||||
|
|
||||||
|
message.success('切换成功')
|
||||||
|
dialogVisible.value = false
|
||||||
|
|
||||||
|
// 刷新页面
|
||||||
|
setTimeout(() => {
|
||||||
|
location.reload()
|
||||||
|
}, 500)
|
||||||
|
} catch (error) {
|
||||||
|
if (error !== 'cancel') {
|
||||||
|
console.error('切换小区失败:', error)
|
||||||
|
message.error('切换小区失败')
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听弹窗打开
|
||||||
|
watch(() => props.modelValue, (visible) => {
|
||||||
|
if (visible) {
|
||||||
|
getTenantList()
|
||||||
|
} else {
|
||||||
|
tenantList.value = []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.tenant-switch-content {
|
||||||
|
min-height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tenant-list {
|
||||||
|
max-height: 400px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tenant-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 16px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s;
|
||||||
|
|
||||||
|
&:hover:not(.tenant-item-disabled) {
|
||||||
|
border-color: #1677ff;
|
||||||
|
background-color: #f0f7ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-active {
|
||||||
|
border-color: #1677ff;
|
||||||
|
background-color: #e6f7ff;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-disabled {
|
||||||
|
cursor: default;
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tenant-info {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tenant-name {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tenant-tag {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #1677ff;
|
||||||
|
background-color: rgba(22, 119, 255, 0.1);
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tenant-arrow {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tenant-check {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #1677ff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="tsx">
|
<script lang="tsx">
|
||||||
import { defineComponent, computed } from 'vue'
|
import { defineComponent, computed, ref } from 'vue'
|
||||||
import { Message } from '@/layout/components//Message'
|
import { Message } from '@/layout/components//Message'
|
||||||
import { Collapse } from '@/layout/components/Collapse'
|
import { Collapse } from '@/layout/components/Collapse'
|
||||||
import { UserInfo } from '@/layout/components/UserInfo'
|
import { UserInfo } from '@/layout/components/UserInfo'
|
||||||
|
|
@ -9,6 +9,7 @@ import { SizeDropdown } from '@/layout/components/SizeDropdown'
|
||||||
import { LocaleDropdown } from '@/layout/components/LocaleDropdown'
|
import { LocaleDropdown } from '@/layout/components/LocaleDropdown'
|
||||||
import RouterSearch from '@/components/RouterSearch/index.vue'
|
import RouterSearch from '@/components/RouterSearch/index.vue'
|
||||||
import TenantVisit from '@/layout/components/TenantVisit/index.vue'
|
import TenantVisit from '@/layout/components/TenantVisit/index.vue'
|
||||||
|
import TenantSwitchButton from './TenantSwitchButton.vue'
|
||||||
import { useAppStore } from '@/store/modules/app'
|
import { useAppStore } from '@/store/modules/app'
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
import { useDesign } from '@/hooks/web/useDesign'
|
||||||
import { checkPermi } from '@/utils/permission'
|
import { checkPermi } from '@/utils/permission'
|
||||||
|
|
@ -48,6 +49,14 @@ const hasTenantVisitPermission = computed(
|
||||||
() => import.meta.env.VITE_APP_TENANT_ENABLE === 'true' && checkPermi(['system:tenant:visit'])
|
() => import.meta.env.VITE_APP_TENANT_ENABLE === 'true' && checkPermi(['system:tenant:visit'])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 左侧工具栏显示/隐藏状态(默认隐藏)
|
||||||
|
const showTools = ref(false)
|
||||||
|
|
||||||
|
// 切换工具栏显示
|
||||||
|
const toggleTools = () => {
|
||||||
|
showTools.value = !showTools.value
|
||||||
|
}
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'ToolHeader',
|
name: 'ToolHeader',
|
||||||
setup() {
|
setup() {
|
||||||
|
|
@ -69,6 +78,17 @@ export default defineComponent({
|
||||||
</div>
|
</div>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
<div class="h-full flex items-center">
|
<div class="h-full flex items-center">
|
||||||
|
{/* 折叠/展开工具栏按钮 */}
|
||||||
|
<div
|
||||||
|
class="custom-hover text-white hover:text-white/85"
|
||||||
|
onClick={toggleTools}
|
||||||
|
>
|
||||||
|
<Icon icon={showTools.value ? 'ep:close' : 'ep:menu'} size={18} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 工具栏图标组,根据状态显示/隐藏 */}
|
||||||
|
{showTools.value && (
|
||||||
|
<div class="flex items-center animate-fade-in">
|
||||||
{hasTenantVisitPermission.value ? <TenantVisit /> : undefined}
|
{hasTenantVisitPermission.value ? <TenantVisit /> : undefined}
|
||||||
{screenfull.value ? (
|
{screenfull.value ? (
|
||||||
<Screenfull class="custom-hover text-white hover:text-white/85"></Screenfull>
|
<Screenfull class="custom-hover text-white hover:text-white/85"></Screenfull>
|
||||||
|
|
@ -85,6 +105,10 @@ export default defineComponent({
|
||||||
{message.value ? (
|
{message.value ? (
|
||||||
<Message class="custom-hover text-white hover:text-white/85"></Message>
|
<Message class="custom-hover text-white hover:text-white/85"></Message>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<TenantSwitchButton></TenantSwitchButton>
|
||||||
<UserInfo></UserInfo>
|
<UserInfo></UserInfo>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -110,4 +134,19 @@ $prefix-cls: #{$namespace}-tool-header;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes fade-in {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(-10px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-fade-in {
|
||||||
|
animation: fade-in 0.3s ease-out;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -92,22 +92,3 @@ const toDocument = () => {
|
||||||
</transition>
|
</transition>
|
||||||
</teleport>
|
</teleport>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.fade-bottom-enter-active,
|
|
||||||
.fade-bottom-leave-active {
|
|
||||||
transition:
|
|
||||||
opacity 0.25s,
|
|
||||||
transform 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fade-bottom-enter-from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(-10%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.fade-bottom-leave-to {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(10%);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,8 @@
|
||||||
<el-form-item prop="username">
|
<el-form-item prop="username">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="loginData.loginForm.username"
|
v-model="loginData.loginForm.username"
|
||||||
placeholder="请输入用户名称"
|
placeholder="请输入手机号/用户名"
|
||||||
:prefix-icon="iconAvatar"
|
:prefix-icon="iconAvatar"
|
||||||
@blur="handleUsernameBlur"
|
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
|
|
@ -47,29 +46,9 @@
|
||||||
show-password
|
show-password
|
||||||
type="password"
|
type="password"
|
||||||
@keyup.enter="getCode()"
|
@keyup.enter="getCode()"
|
||||||
@blur="handlePasswordBlur"
|
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<!-- 租户选择 -->
|
|
||||||
<el-form-item v-if="loginData.tenantEnable === 'true'" prop="tenantId">
|
|
||||||
<el-select
|
|
||||||
ref="tenantSelectRef"
|
|
||||||
v-model="loginData.loginForm.tenantId"
|
|
||||||
placeholder="请选择租户"
|
|
||||||
:prefix-icon="iconHouse"
|
|
||||||
style="width: 100%"
|
|
||||||
:disabled="tenantList.length === 0"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="tenant in tenantList"
|
|
||||||
:key="tenant.tenantId"
|
|
||||||
:label="tenant.tenantName"
|
|
||||||
:value="tenant.tenantId"
|
|
||||||
/>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<!-- 记住密码 -->
|
<!-- 记住密码 -->
|
||||||
<div class="login-options">
|
<div class="login-options">
|
||||||
<el-checkbox v-model="loginData.loginForm.rememberMe">
|
<el-checkbox v-model="loginData.loginForm.rememberMe">
|
||||||
|
|
@ -138,21 +117,13 @@ const isFetchingTenants = ref(false)
|
||||||
|
|
||||||
const LoginRules = {
|
const LoginRules = {
|
||||||
username: [required],
|
username: [required],
|
||||||
password: [required],
|
password: [required]
|
||||||
tenantId: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: '请选择租户',
|
|
||||||
trigger: 'change'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const loginData = reactive({
|
const loginData = reactive({
|
||||||
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: {
|
||||||
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: '',
|
||||||
|
|
@ -165,104 +136,8 @@ const loading = ref()
|
||||||
const { push } = useRouter()
|
const { push } = useRouter()
|
||||||
const permissionStore = usePermissionStore()
|
const permissionStore = usePermissionStore()
|
||||||
|
|
||||||
// 用户名失焦时获取租户列表
|
|
||||||
const handleUsernameBlur = async () => {
|
|
||||||
if (loginData.tenantEnable !== 'true') {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
await fetchTenantList()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 密码失焦时获取租户列表
|
|
||||||
const handlePasswordBlur = async () => {
|
|
||||||
if (loginData.tenantEnable !== 'true') {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
await fetchTenantList()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取租户列表
|
|
||||||
const fetchTenantList = async () => {
|
|
||||||
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 === 1) {
|
|
||||||
loginData.loginForm.tenantId = res.tenants[0].tenantId
|
|
||||||
} else {
|
|
||||||
loginData.loginForm.tenantId = undefined
|
|
||||||
}
|
|
||||||
} 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
|
|
||||||
continueLogin()
|
|
||||||
} else {
|
|
||||||
if (tenantSelectRef.value) {
|
|
||||||
tenantSelectRef.value.visible = true
|
|
||||||
}
|
|
||||||
message.info('请选择要登录的租户')
|
|
||||||
}
|
|
||||||
} else if (loginData.tenantEnable === 'true' && tenantList.value.length > 0) {
|
|
||||||
if (!loginData.loginForm.tenantId) {
|
|
||||||
message.error('请选择租户')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
continueLogin()
|
|
||||||
} else {
|
|
||||||
continueLogin()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const continueLogin = () => {
|
|
||||||
if (loginData.captchaEnable === 'false') {
|
if (loginData.captchaEnable === 'false') {
|
||||||
handleLogin({})
|
handleLogin({})
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -270,38 +145,9 @@ const continueLogin = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const setTenantId = () => {
|
|
||||||
if (loginData.loginForm.tenantId) {
|
|
||||||
authUtil.setTenantId(loginData.loginForm.tenantId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getLoginFormCache = () => {
|
|
||||||
const loginForm = authUtil.getLoginForm()
|
|
||||||
if (loginForm) {
|
|
||||||
loginData.loginForm = {
|
|
||||||
...loginData.loginForm,
|
|
||||||
username: loginForm.username ? loginForm.username : loginData.loginForm.username,
|
|
||||||
password: loginForm.password ? loginForm.password : loginData.loginForm.password,
|
|
||||||
rememberMe: loginForm.rememberMe
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getTenantByWebsite = async () => {
|
|
||||||
if (loginData.tenantEnable === 'true') {
|
|
||||||
const website = location.host
|
|
||||||
const res = await LoginApi.getTenantByWebsite(website)
|
|
||||||
if (res) {
|
|
||||||
authUtil.setTenantId(res.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleLogin = async (params: any) => {
|
const handleLogin = async (params: any) => {
|
||||||
loginLoading.value = true
|
loginLoading.value = true
|
||||||
try {
|
try {
|
||||||
setTenantId()
|
|
||||||
await formLogin.value.validate()
|
await formLogin.value.validate()
|
||||||
const loginDataLoginForm = { ...loginData.loginForm }
|
const loginDataLoginForm = { ...loginData.loginForm }
|
||||||
loginDataLoginForm.captchaVerification = params.captchaVerification
|
loginDataLoginForm.captchaVerification = params.captchaVerification
|
||||||
|
|
@ -327,9 +173,20 @@ const handleLogin = async (params: any) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getLoginFormCache = () => {
|
||||||
|
const loginForm = authUtil.getLoginForm()
|
||||||
|
if (loginForm) {
|
||||||
|
loginData.loginForm = {
|
||||||
|
...loginData.loginForm,
|
||||||
|
username: loginForm.username ? loginForm.username : loginData.loginForm.username,
|
||||||
|
password: loginForm.password ? loginForm.password : loginData.loginForm.password,
|
||||||
|
rememberMe: loginForm.rememberMe
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getLoginFormCache()
|
getLoginFormCache()
|
||||||
getTenantByWebsite()
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,14 +29,28 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="楼号" prop="buildingNo">
|
<el-form-item label="楼号" prop="buildingNo">
|
||||||
<el-input v-model="formData.buildingNo" placeholder="请输入楼号" />
|
<el-input
|
||||||
|
v-model.number="formData.buildingNo"
|
||||||
|
placeholder="请输入楼号"
|
||||||
|
type="number"
|
||||||
|
@input="handleNumberInput('buildingNo')"
|
||||||
|
>
|
||||||
|
<template #append>号楼</template>
|
||||||
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="单元号" prop="unitNo">
|
<el-form-item label="单元号" prop="unitNo">
|
||||||
<el-input v-model="formData.unitNo" placeholder="请输入单元号" />
|
<el-input
|
||||||
|
v-model.number="formData.unitNo"
|
||||||
|
placeholder="请输入单元号"
|
||||||
|
type="number"
|
||||||
|
@input="handleNumberInput('unitNo')"
|
||||||
|
>
|
||||||
|
<template #append>单元</template>
|
||||||
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
|
|
@ -125,7 +139,15 @@ const open = async (type: string, id?: number) => {
|
||||||
if (id) {
|
if (id) {
|
||||||
formLoading.value = true
|
formLoading.value = true
|
||||||
try {
|
try {
|
||||||
formData.value = await HouseApi.getHouse(id)
|
const data = await HouseApi.getHouse(id)
|
||||||
|
// 去除楼号和单元号的后缀
|
||||||
|
if (data.buildingNo) {
|
||||||
|
data.buildingNo = String(data.buildingNo).replace(/号楼$/g, '')
|
||||||
|
}
|
||||||
|
if (data.unitNo) {
|
||||||
|
data.unitNo = String(data.unitNo).replace(/单元$/g, '')
|
||||||
|
}
|
||||||
|
formData.value = data
|
||||||
} finally {
|
} finally {
|
||||||
formLoading.value = false
|
formLoading.value = false
|
||||||
}
|
}
|
||||||
|
|
@ -170,4 +192,12 @@ const resetForm = () => {
|
||||||
}
|
}
|
||||||
formRef.value?.resetFields()
|
formRef.value?.resetFields()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 处理数字输入 */
|
||||||
|
const handleNumberInput = (field: string) => {
|
||||||
|
if (formData.value[field] === '') {
|
||||||
|
formData.value[field] = undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -102,8 +102,16 @@
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="序号" align="center" type="index" width="80" />
|
<el-table-column label="序号" align="center" type="index" width="80" />
|
||||||
<el-table-column label="小区名称" align="center" prop="communityName" min-width="120" />
|
<el-table-column label="小区名称" align="center" prop="communityName" min-width="120" />
|
||||||
<el-table-column label="楼号" align="center" prop="buildingNo" width="100" />
|
<el-table-column label="楼号" align="center" prop="buildingNo" width="100">
|
||||||
<el-table-column label="单元号" align="center" prop="unitNo" width="100" />
|
<template #default="scope">
|
||||||
|
{{ scope.row.buildingNo }}号楼
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="单元号" align="center" prop="unitNo" width="100">
|
||||||
|
<template #default="scope">
|
||||||
|
{{ scope.row.unitNo }}单元
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column label="门牌号" align="center" prop="roomNo" width="100" />
|
<el-table-column label="门牌号" align="center" prop="roomNo" width="100" />
|
||||||
<el-table-column label="业主姓名" align="center" prop="ownerName" width="100" />
|
<el-table-column label="业主姓名" align="center" prop="ownerName" width="100" />
|
||||||
<el-table-column label="业主联系方式" align="center" prop="ownerPhone" width="120">
|
<el-table-column label="业主联系方式" align="center" prop="ownerPhone" width="120">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue