chore: 完善切换租户组件
This commit is contained in:
parent
15acc1ff68
commit
28c88c485f
@ -1,17 +1,60 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
import { computed, onMounted, ref } from 'vue';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
import type { SelectOption } from 'naive-ui';
|
import type { SelectOption } from 'naive-ui';
|
||||||
import { useLoading } from '@sa/hooks';
|
import { useLoading } from '@sa/hooks';
|
||||||
import { fetchTenantList } from '@/service/api';
|
import { fetchTenantList } from '@/service/api';
|
||||||
|
import { fetchChangeTenant, fetchClearTenant } from '@/service/api/system/tenant';
|
||||||
|
import { useTabStore } from '@/store/modules/tab';
|
||||||
|
import { useAuth } from '@/hooks/business/auth';
|
||||||
|
|
||||||
|
const { hasRole } = useAuth();
|
||||||
|
const { clearTabs } = useTabStore();
|
||||||
|
const router = useRouter();
|
||||||
defineOptions({ name: 'TenantSelect' });
|
defineOptions({ name: 'TenantSelect' });
|
||||||
|
|
||||||
const value = defineModel<CommonType.IdType>('value', { required: false, default: '000000' });
|
interface Props {
|
||||||
const enabled = defineModel<boolean>('enabled', { required: false, default: false });
|
clearable?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
withDefaults(defineProps<Props>(), {
|
||||||
|
clearable: false
|
||||||
|
});
|
||||||
|
|
||||||
|
const tenantId = defineModel<CommonType.IdType>('tenantId', { required: false, default: undefined });
|
||||||
|
const enabled = defineModel<boolean>('enabled', { required: false, default: true });
|
||||||
|
|
||||||
|
const lastSelected = ref<CommonType.IdType>();
|
||||||
|
|
||||||
const tenantOption = ref<SelectOption[]>([]);
|
const tenantOption = ref<SelectOption[]>([]);
|
||||||
const { loading, startLoading, endLoading } = useLoading();
|
const { loading, startLoading, endLoading } = useLoading();
|
||||||
|
|
||||||
|
const showTenantSelect = computed<boolean>(() => {
|
||||||
|
return hasRole('superadmin') && enabled.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
async function handleChangeTenant(_tenantId: CommonType.IdType) {
|
||||||
|
if (!_tenantId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (lastSelected.value === _tenantId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await fetchChangeTenant(_tenantId);
|
||||||
|
lastSelected.value = _tenantId;
|
||||||
|
window.$message?.success('切换租户成功');
|
||||||
|
clearTabs();
|
||||||
|
router.push('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleClearTenant() {
|
||||||
|
await fetchClearTenant();
|
||||||
|
lastSelected.value = '';
|
||||||
|
window.$message?.success('切换为默认租户');
|
||||||
|
clearTabs();
|
||||||
|
router.push('/');
|
||||||
|
}
|
||||||
|
|
||||||
async function handleFetchTenantList() {
|
async function handleFetchTenantList() {
|
||||||
startLoading();
|
startLoading();
|
||||||
const { data, error } = await fetchTenantList();
|
const { data, error } = await fetchTenantList();
|
||||||
@ -25,16 +68,23 @@ async function handleFetchTenantList() {
|
|||||||
});
|
});
|
||||||
endLoading();
|
endLoading();
|
||||||
}
|
}
|
||||||
|
onMounted(async () => {
|
||||||
handleFetchTenantList();
|
if (!hasRole('superadmin')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await handleFetchTenantList();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NSelect
|
<NSelect
|
||||||
v-if="enabled"
|
v-if="showTenantSelect"
|
||||||
v-model:value="value"
|
v-model:value="tenantId"
|
||||||
placeholder="请选择/输入公司名称"
|
:clearable="clearable"
|
||||||
|
placeholder="请选择租户"
|
||||||
:options="tenantOption"
|
:options="tenantOption"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
|
@update:value="handleChangeTenant"
|
||||||
|
@clear="handleClearTenant"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
@ -9,7 +9,7 @@ export function useFormRules() {
|
|||||||
userName: {
|
userName: {
|
||||||
pattern: REG_USER_NAME,
|
pattern: REG_USER_NAME,
|
||||||
message: $t('form.userName.invalid'),
|
message: $t('form.userName.invalid'),
|
||||||
trigger: 'change'
|
trigger: ['change', 'blur']
|
||||||
},
|
},
|
||||||
phone: {
|
phone: {
|
||||||
pattern: REG_PHONE,
|
pattern: REG_PHONE,
|
||||||
@ -19,7 +19,7 @@ export function useFormRules() {
|
|||||||
pwd: {
|
pwd: {
|
||||||
pattern: REG_PWD,
|
pattern: REG_PWD,
|
||||||
message: $t('form.pwd.invalid'),
|
message: $t('form.pwd.invalid'),
|
||||||
trigger: 'change'
|
trigger: ['change', 'blur']
|
||||||
},
|
},
|
||||||
code: {
|
code: {
|
||||||
pattern: REG_CODE_SIX,
|
pattern: REG_CODE_SIX,
|
||||||
|
@ -48,7 +48,7 @@ watch(tenantId, async () => {
|
|||||||
<GlobalBreadcrumb v-if="!appStore.isMobile" class="ml-12px" />
|
<GlobalBreadcrumb v-if="!appStore.isMobile" class="ml-12px" />
|
||||||
</div>
|
</div>
|
||||||
<div class="h-full flex-y-center justify-end">
|
<div class="h-full flex-y-center justify-end">
|
||||||
<TenantSelect v-if="authStore.userInfo?.user?.userId === 1" class="mr-12px w-150px" />
|
<TenantSelect class="mr-12px w-150px" :clearable="true" />
|
||||||
<GlobalSearch />
|
<GlobalSearch />
|
||||||
<FullScreen v-if="!appStore.isMobile" :full="isFullscreen" @click="toggle" />
|
<FullScreen v-if="!appStore.isMobile" :full="isFullscreen" @click="toggle" />
|
||||||
<LangSwitch
|
<LangSwitch
|
||||||
|
@ -54,3 +54,11 @@ export function fetchChangeTenant(tenantId: CommonType.IdType) {
|
|||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 清空租户 */
|
||||||
|
export function fetchClearTenant() {
|
||||||
|
return request<boolean>({
|
||||||
|
url: '/system/tenant/dynamic/clear',
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -3,14 +3,12 @@ import { computed, reactive, ref } from 'vue';
|
|||||||
import type { SelectOption } from 'naive-ui';
|
import type { SelectOption } from 'naive-ui';
|
||||||
import { useLoading } from '@sa/hooks';
|
import { useLoading } from '@sa/hooks';
|
||||||
import { fetchCaptchaCode, fetchTenantList } from '@/service/api';
|
import { fetchCaptchaCode, fetchTenantList } from '@/service/api';
|
||||||
// import { fetchGetConfigDetail } from '@/service/api/system/config';
|
|
||||||
import { fetchSocialAuthBinding } from '@/service/api/system';
|
import { fetchSocialAuthBinding } from '@/service/api/system';
|
||||||
import { useAuthStore } from '@/store/modules/auth';
|
import { useAuthStore } from '@/store/modules/auth';
|
||||||
import { useRouterPush } from '@/hooks/common/router';
|
import { useRouterPush } from '@/hooks/common/router';
|
||||||
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
||||||
import { localStg } from '@/utils/storage';
|
import { localStg } from '@/utils/storage';
|
||||||
import { $t } from '@/locales';
|
import { $t } from '@/locales';
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'PwdLogin'
|
name: 'PwdLogin'
|
||||||
});
|
});
|
||||||
@ -19,12 +17,15 @@ const authStore = useAuthStore();
|
|||||||
const { toggleLoginModule } = useRouterPush();
|
const { toggleLoginModule } = useRouterPush();
|
||||||
const { formRef, validate } = useNaiveForm();
|
const { formRef, validate } = useNaiveForm();
|
||||||
const { loading: codeLoading, startLoading: startCodeLoading, endLoading: endCodeLoading } = useLoading();
|
const { loading: codeLoading, startLoading: startCodeLoading, endLoading: endCodeLoading } = useLoading();
|
||||||
|
const { loading: tenantLoading, startLoading: startTenantLoading, endLoading: endTenantLoading } = useLoading();
|
||||||
|
|
||||||
const codeUrl = ref<string>();
|
const codeUrl = ref<string>();
|
||||||
const captchaEnabled = ref<boolean>(false);
|
const captchaEnabled = ref<boolean>(false);
|
||||||
const tenantEnabled = ref<boolean>(false);
|
|
||||||
const registerEnabled = ref<boolean>(false);
|
const registerEnabled = ref<boolean>(false);
|
||||||
const remberMe = ref<boolean>(false);
|
const remberMe = ref<boolean>(false);
|
||||||
|
|
||||||
|
const tenantEnabled = ref<boolean>(false);
|
||||||
|
|
||||||
const tenantOption = ref<SelectOption[]>([]);
|
const tenantOption = ref<SelectOption[]>([]);
|
||||||
|
|
||||||
const model: Api.Auth.PwdLoginForm = reactive({
|
const model: Api.Auth.PwdLoginForm = reactive({
|
||||||
@ -32,7 +33,6 @@ const model: Api.Auth.PwdLoginForm = reactive({
|
|||||||
username: '',
|
username: '',
|
||||||
password: ''
|
password: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
type RuleKey = Extract<keyof Api.Auth.PwdLoginForm, 'username' | 'password' | 'code' | 'tenantId'>;
|
type RuleKey = Extract<keyof Api.Auth.PwdLoginForm, 'username' | 'password' | 'code' | 'tenantId'>;
|
||||||
|
|
||||||
const rules = computed<Record<RuleKey, App.Global.FormRule[]>>(() => {
|
const rules = computed<Record<RuleKey, App.Global.FormRule[]>>(() => {
|
||||||
@ -41,13 +41,28 @@ const rules = computed<Record<RuleKey, App.Global.FormRule[]>>(() => {
|
|||||||
|
|
||||||
const loginRules: Record<RuleKey, App.Global.FormRule[]> = {
|
const loginRules: Record<RuleKey, App.Global.FormRule[]> = {
|
||||||
username: [...formRules.userName, { required: true }],
|
username: [...formRules.userName, { required: true }],
|
||||||
password: [...formRules.pwd, { required: true }],
|
password: [createRequiredRule($t('form.pwd.required'))],
|
||||||
code: captchaEnabled.value ? [createRequiredRule($t('form.code.required'))] : [],
|
code: captchaEnabled.value ? [createRequiredRule($t('form.code.required'))] : [],
|
||||||
tenantId: tenantEnabled.value ? formRules.tenantId : []
|
tenantId: tenantEnabled.value ? formRules.tenantId : []
|
||||||
};
|
};
|
||||||
|
|
||||||
return loginRules;
|
return loginRules;
|
||||||
});
|
});
|
||||||
|
async function handleFetchTenantList() {
|
||||||
|
startTenantLoading();
|
||||||
|
const { data, error } = await fetchTenantList();
|
||||||
|
if (error) return;
|
||||||
|
tenantEnabled.value = data.tenantEnabled;
|
||||||
|
tenantOption.value = data.voList.map(tenant => {
|
||||||
|
return {
|
||||||
|
label: tenant.companyName,
|
||||||
|
value: tenant.tenantId
|
||||||
|
};
|
||||||
|
});
|
||||||
|
endTenantLoading();
|
||||||
|
}
|
||||||
|
|
||||||
|
handleFetchTenantList();
|
||||||
|
|
||||||
async function handleSubmit() {
|
async function handleSubmit() {
|
||||||
await validate();
|
await validate();
|
||||||
@ -66,20 +81,6 @@ async function handleSubmit() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleFetchTenantList() {
|
|
||||||
const { data, error } = await fetchTenantList();
|
|
||||||
if (error) return;
|
|
||||||
tenantEnabled.value = data.tenantEnabled;
|
|
||||||
tenantOption.value = data.voList.map(tenant => {
|
|
||||||
return {
|
|
||||||
label: tenant.companyName,
|
|
||||||
value: tenant.tenantId
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleFetchTenantList();
|
|
||||||
|
|
||||||
async function handleFetchCaptchaCode() {
|
async function handleFetchCaptchaCode() {
|
||||||
startCodeLoading();
|
startCodeLoading();
|
||||||
const { data, error } = await fetchCaptchaCode();
|
const { data, error } = await fetchCaptchaCode();
|
||||||
@ -121,8 +122,14 @@ async function handleSocialLogin(type: Api.System.SocialSource) {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NForm ref="formRef" :model="model" :rules="rules" size="large" :show-label="false" @keyup.enter="handleSubmit">
|
<NForm ref="formRef" :model="model" :rules="rules" size="large" :show-label="false" @keyup.enter="handleSubmit">
|
||||||
<NFormItem v-if="tenantEnabled" path="tenantId">
|
<NFormItem path="tenantId">
|
||||||
<TenantSelect v-model:value="model.tenantId" :enabled="tenantEnabled" />
|
<NSelect
|
||||||
|
v-if="tenantEnabled"
|
||||||
|
v-model:value="model.tenantId"
|
||||||
|
placeholder="请选择租户"
|
||||||
|
:options="tenantOption"
|
||||||
|
:loading="tenantLoading"
|
||||||
|
/>
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
<NFormItem path="username">
|
<NFormItem path="username">
|
||||||
<NInput v-model:value="model.username" :placeholder="$t('page.login.common.userNamePlaceholder')" />
|
<NInput v-model:value="model.username" :placeholder="$t('page.login.common.userNamePlaceholder')" />
|
||||||
|
@ -1,7 +1,46 @@
|
|||||||
<script setup lang="ts"></script>
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import { useAppStore } from '@/store/modules/app';
|
||||||
|
import HeaderBanner from './modules/header-banner.vue';
|
||||||
|
import CardData from './modules/card-data.vue';
|
||||||
|
import LineChart from './modules/line-chart.vue';
|
||||||
|
import PieChart from './modules/pie-chart.vue';
|
||||||
|
import ProjectNews from './modules/project-news.vue';
|
||||||
|
import CreativityBanner from './modules/creativity-banner.vue';
|
||||||
|
|
||||||
|
const appStore = useAppStore();
|
||||||
|
|
||||||
|
const gap = computed(() => (appStore.isMobile ? 0 : 16));
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FileUpload />
|
<NSpace vertical :size="16">
|
||||||
|
<NAlert :title="$t('common.warning')" type="warning">
|
||||||
|
{{ $t('page.home.branchDesc') }}
|
||||||
|
</NAlert>
|
||||||
|
<HeaderBanner />
|
||||||
|
<CardData />
|
||||||
|
<NGrid :x-gap="gap" :y-gap="16" responsive="screen" item-responsive>
|
||||||
|
<NGi span="24 s:24 m:14">
|
||||||
|
<NCard :bordered="false" class="card-wrapper">
|
||||||
|
<LineChart />
|
||||||
|
</NCard>
|
||||||
|
</NGi>
|
||||||
|
<NGi span="24 s:24 m:10">
|
||||||
|
<NCard :bordered="false" class="card-wrapper">
|
||||||
|
<PieChart />
|
||||||
|
</NCard>
|
||||||
|
</NGi>
|
||||||
|
</NGrid>
|
||||||
|
<NGrid :x-gap="gap" :y-gap="16" responsive="screen" item-responsive>
|
||||||
|
<NGi span="24 s:24 m:14">
|
||||||
|
<ProjectNews />
|
||||||
|
</NGi>
|
||||||
|
<NGi span="24 s:24 m:10">
|
||||||
|
<CreativityBanner />
|
||||||
|
</NGi>
|
||||||
|
</NGrid>
|
||||||
|
</NSpace>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
Loading…
Reference in New Issue
Block a user