diff --git a/components.d.ts b/components.d.ts index 7c60292..71a433d 100644 --- a/components.d.ts +++ b/components.d.ts @@ -68,6 +68,7 @@ declare module 'vue' { TySidebar: typeof import('./src/components/ty-sidebar.vue')['default'] TyTable: typeof import('./src/components/ty-table.vue')['default'] TyTabs: typeof import('./src/components/ty-tabs.vue')['default'] + TyTenantSwitch: typeof import('./src/components/ty-tenant-switch.vue')['default'] } export interface GlobalDirectives { vLoading: typeof import('element-plus/es')['ElLoadingDirective'] @@ -132,4 +133,5 @@ declare global { const TySidebar: typeof import('./src/components/ty-sidebar.vue')['default'] const TyTable: typeof import('./src/components/ty-table.vue')['default'] const TyTabs: typeof import('./src/components/ty-tabs.vue')['default'] + const TyTenantSwitch: typeof import('./src/components/ty-tenant-switch.vue')['default'] } \ No newline at end of file diff --git a/src/api/auth.ts b/src/api/auth.ts index 26a8b46..507cbe5 100644 --- a/src/api/auth.ts +++ b/src/api/auth.ts @@ -58,3 +58,16 @@ export interface TenantBrand { export function fetchBrand(signal?: AbortSignal): Promise { return http.get('/auth/brand', { signal }) } + +export interface SwitchTenantResult { + accessToken: string + refreshToken: string + expiresIn: number + tenantCode: string + tenantName: string +} + +/** 平台超管切换租户。 */ +export function switchTenant(tenantCode: string): Promise { + return http.post('/auth/switch-tenant', { tenantCode }) +} diff --git a/src/components/ty-header.vue b/src/components/ty-header.vue index 244f52d..880fa86 100644 --- a/src/components/ty-header.vue +++ b/src/components/ty-header.vue @@ -50,6 +50,7 @@ + diff --git a/src/components/ty-tenant-switch.vue b/src/components/ty-tenant-switch.vue new file mode 100644 index 0000000..abb3d29 --- /dev/null +++ b/src/components/ty-tenant-switch.vue @@ -0,0 +1,64 @@ + + + + + diff --git a/src/stores/modules/auth.ts b/src/stores/modules/auth.ts index 702df5a..3dbc03f 100644 --- a/src/stores/modules/auth.ts +++ b/src/stores/modules/auth.ts @@ -1,7 +1,7 @@ import { computed, ref } from 'vue'; import { defineStore } from 'pinia'; import { http } from '@/api/http'; -import { fetchBrand, login as loginApi, type LoginResult, type TenantBrand } from '@/api/auth'; +import { fetchBrand, login as loginApi, switchTenant as switchTenantApi, type LoginResult, type TenantBrand } from '@/api/auth'; import { clearTokens, getAccessToken, getMustChangePassword, getRefreshToken, setMustChangePassword, setTokens } from '@/utils/token'; export const useAuthStore = defineStore('authStore', () => { @@ -16,6 +16,16 @@ export const useAuthStore = defineStore('authStore', () => { brand.value = await fetchBrand(); } + /** 平台超管切换租户:换 token 后由调用方刷新页面重建上下文。 */ + async function switchTenant(tenantCode: string): Promise { + const data = await switchTenantApi(tenantCode); + setTokens(data.accessToken, data.refreshToken); + accessToken.value = data.accessToken; + refreshToken.value = data.refreshToken; + mustChangePassword.value = false; + setMustChangePassword(false); + } + async function login(username: string, password: string, tenantCode?: string): Promise { const data = await loginApi(username, password, tenantCode); if ('accessToken' in data) { @@ -49,5 +59,5 @@ export const useAuthStore = defineStore('authStore', () => { setMustChangePassword(false); } - return { accessToken, refreshToken, isAuthenticated, mustChangePassword, brand, login, logout, reset, fetchBrandState }; + return { accessToken, refreshToken, isAuthenticated, mustChangePassword, brand, login, logout, reset, fetchBrandState, switchTenant }; });