perf: tenant-dropdown
							parent
							
								
									56b4751be1
								
							
						
					
					
						commit
						5b4846e93d
					
				|  | @ -1,11 +1,13 @@ | |||
| <script lang="ts" setup> | ||||
| import type { NotificationItem } from '@vben/layouts'; | ||||
| 
 | ||||
| import type { SystemTenantApi } from '#/api/system/tenant'; | ||||
| 
 | ||||
| import { computed, onMounted, ref, watch } from 'vue'; | ||||
| 
 | ||||
| import { AuthenticationLoginExpiredModal, useVbenModal } from '@vben/common-ui'; | ||||
| import { VBEN_DOC_URL, VBEN_GITHUB_URL } from '@vben/constants'; | ||||
| import { useWatermark } from '@vben/hooks'; | ||||
| import { useTabs, useWatermark } from '@vben/hooks'; | ||||
| import { | ||||
|   AntdProfileOutlined, | ||||
|   BookOpenText, | ||||
|  | @ -16,30 +18,37 @@ import { | |||
|   BasicLayout, | ||||
|   LockScreen, | ||||
|   Notification, | ||||
|   TenantDropdown, | ||||
|   UserDropdown, | ||||
| } from '@vben/layouts'; | ||||
| import { preferences } from '@vben/preferences'; | ||||
| import { useAccessStore, useUserStore } from '@vben/stores'; | ||||
| import { formatDateTime, openWindow } from '@vben/utils'; | ||||
| 
 | ||||
| import { message } from 'ant-design-vue'; | ||||
| 
 | ||||
| import { | ||||
|   getUnreadNotifyMessageCount, | ||||
|   getUnreadNotifyMessageList, | ||||
|   updateAllNotifyMessageRead, | ||||
|   updateNotifyMessageRead, | ||||
| } from '#/api/system/notify/message'; | ||||
| import { getSimpleTenantList } from '#/api/system/tenant'; | ||||
| import { $t } from '#/locales'; | ||||
| import { router } from '#/router'; | ||||
| import { useAuthStore } from '#/store'; | ||||
| import LoginForm from '#/views/_core/authentication/login.vue'; | ||||
| 
 | ||||
| import Help from './components/help.vue'; | ||||
| import TenantDropdown from './components/tenant-dropdown.vue'; | ||||
| 
 | ||||
| // 租户列表 | ||||
| const tenants = ref<SystemTenantApi.Tenant[]>([]); | ||||
| 
 | ||||
| const userStore = useUserStore(); | ||||
| const authStore = useAuthStore(); | ||||
| const accessStore = useAccessStore(); | ||||
| const { destroyWatermark, updateWatermark } = useWatermark(); | ||||
| const { closeOtherTabs, refreshTab } = useTabs(); | ||||
| 
 | ||||
| const notifications = ref<NotificationItem[]>([]); | ||||
| const unreadCount = ref(0); | ||||
|  | @ -148,10 +157,33 @@ function handleNotificationOpen(open: boolean) { | |||
|   handleNotificationGetUnreadCount(); | ||||
| } | ||||
| 
 | ||||
| /** 获取租户列表 */ | ||||
| async function handleGetTenantList() { | ||||
|   tenants.value = await getSimpleTenantList(); | ||||
| } | ||||
| 
 | ||||
| /** 处理租户切换 */ | ||||
| async function handleTenantChange(tenant: SystemTenantApi.Tenant) { | ||||
|   if (!tenant || !tenant.id) { | ||||
|     message.error('切换租户失败'); | ||||
|     return; | ||||
|   } | ||||
|   // 设置访问租户 ID | ||||
|   accessStore.setVisitTenantId(tenant.id as number); | ||||
|   // 关闭其他标签页,只保留当前页 | ||||
|   await closeOtherTabs(); | ||||
|   // 刷新当前页面 | ||||
|   await refreshTab(); | ||||
|   // 提示切换成功 | ||||
|   message.success(`切换当前租户为: ${tenant.name}`); | ||||
| } | ||||
| 
 | ||||
| // ========== 初始化 ========== | ||||
| onMounted(() => { | ||||
|   // 首次加载未读数量 | ||||
|   handleNotificationGetUnreadCount(); | ||||
|   // 获取租户列表 | ||||
|   handleGetTenantList(); | ||||
|   // 轮询刷新未读数量 | ||||
|   setInterval( | ||||
|     () => { | ||||
|  | @ -204,7 +236,14 @@ watch( | |||
|       /> | ||||
|     </template> | ||||
|     <template #header-right-1> | ||||
|       <TenantDropdown class="mr-2 w-44" /> | ||||
|       <div v-access:code="['system:tenant:visit']"> | ||||
|         <TenantDropdown | ||||
|           class="mr-2" | ||||
|           :tenant-list="tenants" | ||||
|           :visit-tenant-id="accessStore.visitTenantId" | ||||
|           @success="handleTenantChange" | ||||
|         /> | ||||
|       </div> | ||||
|     </template> | ||||
|     <template #extra> | ||||
|       <AuthenticationLoginExpiredModal | ||||
|  |  | |||
|  | @ -1,63 +0,0 @@ | |||
| <script lang="ts" setup> | ||||
| import type { SelectValue } from 'ant-design-vue/es/select'; | ||||
| 
 | ||||
| import type { SystemTenantApi } from '#/api/system/tenant'; | ||||
| 
 | ||||
| import { onMounted, ref } from 'vue'; | ||||
| 
 | ||||
| import { useAccess } from '@vben/access'; | ||||
| import { isTenantEnable, useTabs } from '@vben/hooks'; | ||||
| import { useAccessStore } from '@vben/stores'; | ||||
| 
 | ||||
| import { message, Select } from 'ant-design-vue'; | ||||
| 
 | ||||
| import { getSimpleTenantList } from '#/api/system/tenant'; | ||||
| import { $t } from '#/locales'; | ||||
| 
 | ||||
| const { closeOtherTabs, refreshTab } = useTabs(); | ||||
| 
 | ||||
| const { hasAccessByCodes } = useAccess(); | ||||
| const accessStore = useAccessStore(); | ||||
| 
 | ||||
| const tenantEnable = isTenantEnable(); | ||||
| 
 | ||||
| // 当前访问的租户 ID | ||||
| const value = ref<number | undefined>(accessStore.visitTenantId ?? undefined); | ||||
| // 租户列表 | ||||
| const tenants = ref<SystemTenantApi.Tenant[]>([]); | ||||
| 
 | ||||
| async function handleChange(id: SelectValue) { | ||||
|   // 设置访问租户 ID | ||||
|   accessStore.setVisitTenantId(id as number); | ||||
|   // 关闭其他标签页,只保留当前页 | ||||
|   await closeOtherTabs(); | ||||
|   // 刷新当前页面 | ||||
|   await refreshTab(); | ||||
|   // 提示切换成功 | ||||
|   const tenant = tenants.value.find((item) => item.id === id); | ||||
|   if (tenant) { | ||||
|     message.success(`切换当前租户为: ${tenant.name}`); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| onMounted(async () => { | ||||
|   if (!tenantEnable) { | ||||
|     return; | ||||
|   } | ||||
|   tenants.value = await getSimpleTenantList(); | ||||
| }); | ||||
| </script> | ||||
| <template> | ||||
|   <div v-if="tenantEnable && hasAccessByCodes(['system:tenant:visit'])"> | ||||
|     <Select | ||||
|       v-model:value="value" | ||||
|       :field-names="{ label: 'name', value: 'id' }" | ||||
|       :options="tenants" | ||||
|       :placeholder="$t('page.tenant.placeholder')" | ||||
|       :dropdown-style="{ position: 'fixed', zIndex: 1666 }" | ||||
|       allow-clear | ||||
|       class="w-40" | ||||
|       @change="handleChange" | ||||
|     /> | ||||
|   </div> | ||||
| </template> | ||||
|  | @ -7,5 +7,6 @@ export { default as AuthenticationLayoutToggle } from './layout-toggle.vue'; | |||
| export * from './lock-screen'; | ||||
| export * from './notification'; | ||||
| export * from './preferences'; | ||||
| export * from './tenant-dropdown'; | ||||
| export * from './theme-toggle'; | ||||
| export * from './user-dropdown'; | ||||
|  |  | |||
|  | @ -0,0 +1 @@ | |||
| export { default as TenantDropdown } from './tenant-dropdown.vue'; | ||||
|  | @ -0,0 +1,76 @@ | |||
| <script lang="ts" setup> | ||||
| import { computed } from 'vue'; | ||||
| 
 | ||||
| import { isTenantEnable } from '@vben/hooks'; | ||||
| 
 | ||||
| import { | ||||
|   Button, | ||||
|   DropdownMenu, | ||||
|   DropdownMenuContent, | ||||
|   DropdownMenuGroup, | ||||
|   DropdownMenuItem, | ||||
|   DropdownMenuTrigger, | ||||
| } from '@vben-core/shadcn-ui'; | ||||
| 
 | ||||
| interface Tenant { | ||||
|   id?: number; | ||||
|   name: string; | ||||
|   packageId: number; | ||||
|   contactName: string; | ||||
|   contactMobile: string; | ||||
|   accountCount: number; | ||||
|   expireTime: Date; | ||||
|   website: string; | ||||
|   status: number; | ||||
| } | ||||
| 
 | ||||
| defineOptions({ | ||||
|   name: 'TenantDropdown', | ||||
| }); | ||||
| 
 | ||||
| const props = defineProps<{ | ||||
|   tenantList?: Tenant[]; | ||||
|   visitTenantId?: null | number; | ||||
| }>(); | ||||
| 
 | ||||
| const emit = defineEmits(['success']); | ||||
| 
 | ||||
| const tenantEnable = isTenantEnable(); | ||||
| 
 | ||||
| // 租户列表 | ||||
| const tenants = computed(() => props.tenantList ?? []); | ||||
| 
 | ||||
| async function handleChange(id: number | undefined) { | ||||
|   if (!id) { | ||||
|     return; | ||||
|   } | ||||
|   const tenant = tenants.value.find((item) => item.id === id); | ||||
| 
 | ||||
|   emit('success', tenant); | ||||
| } | ||||
| </script> | ||||
| <template> | ||||
|   <DropdownMenu v-if="tenantEnable"> | ||||
|     <DropdownMenuTrigger as-child> | ||||
|       <Button | ||||
|         variant="outline" | ||||
|         class="hover:bg-accent ml-1 mr-2 h-8 w-24 cursor-pointer rounded-full p-1.5" | ||||
|       > | ||||
|         {{ tenants.find((item) => item.id === visitTenantId)?.name }} | ||||
|       </Button> | ||||
|     </DropdownMenuTrigger> | ||||
|     <DropdownMenuContent class="w-56 p-0 pb-1"> | ||||
|       <DropdownMenuGroup> | ||||
|         <DropdownMenuItem | ||||
|           v-for="tenant in tenants" | ||||
|           :key="tenant.id" | ||||
|           :disabled="tenant.id === visitTenantId" | ||||
|           class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8" | ||||
|           @click="handleChange(tenant.id)" | ||||
|         > | ||||
|           {{ tenant.name }} | ||||
|         </DropdownMenuItem> | ||||
|       </DropdownMenuGroup> | ||||
|     </DropdownMenuContent> | ||||
|   </DropdownMenu> | ||||
| </template> | ||||
		Loading…
	
		Reference in New Issue
	
	 xingyu4j
						xingyu4j