Преглед изворни кода

feat:增加切换租户的功能

YunaiV пре 9 месеци
родитељ
комит
c6898c0a99

+ 5 - 0
src/api/system/tenant/index.ts

@@ -41,6 +41,11 @@ export const getTenant = (id: number) => {
   return request.get({ url: '/system/tenant/get?id=' + id })
 }
 
+// 获取租户精简信息列表
+export const getTenantList = () => {
+  return request.get({ url: '/system/tenant/simple-list' })
+}
+
 // 新增租户
 export const createTenant = (data: TenantVO) => {
   return request.post({ url: '/system/tenant/create', data })

+ 14 - 2
src/config/axios/service.ts

@@ -3,7 +3,14 @@ import axios, { AxiosError, AxiosInstance, AxiosResponse, InternalAxiosRequestCo
 import { ElMessage, ElMessageBox, ElNotification } from 'element-plus'
 import qs from 'qs'
 import { config } from '@/config/axios/config'
-import { getAccessToken, getRefreshToken, getTenantId, removeToken, setToken } from '@/utils/auth'
+import {
+  getAccessToken,
+  getRefreshToken,
+  getTenantId,
+  getVisitTenantId,
+  removeToken,
+  setToken
+} from '@/utils/auth'
 import errorCode from './errorCode'
 
 import { resetRouter } from '@/router'
@@ -24,7 +31,7 @@ export const isRelogin = { show: false }
 let requestList: any[] = []
 // 是否正在刷新中
 let isRefreshToken = false
-// 请求白名单,无须token的接口
+// 请求白名单,无须 token 的接口
 const whiteList: string[] = ['/login', '/refresh-token']
 
 // 创建axios实例
@@ -55,6 +62,11 @@ service.interceptors.request.use(
     if (tenantEnable && tenantEnable === 'true') {
       const tenantId = getTenantId()
       if (tenantId) config.headers['tenant-id'] = tenantId
+      // 只有登录时,才设置 visit-tenant-id 访问租户
+      const visitTenantId = getVisitTenantId()
+      if (config.headers.Authorization && visitTenantId) {
+        config.headers['visit-tenant-id'] = visitTenantId
+      }
     }
     const method = config.method?.toUpperCase()
     // 防止 GET 请求缓存

+ 2 - 0
src/hooks/web/useCache.ts

@@ -10,6 +10,7 @@ export const CACHE_KEY = {
   // 用户相关
   ROLE_ROUTERS: 'roleRouters',
   USER: 'user',
+  VisitTenantId: 'visitTenantId',
   // 系统设置
   IS_DARK: 'isDark',
   LANG: 'lang',
@@ -35,5 +36,6 @@ export const deleteUserCache = () => {
   const { wsCache } = useCache()
   wsCache.delete(CACHE_KEY.USER)
   wsCache.delete(CACHE_KEY.ROLE_ROUTERS)
+  wsCache.delete(CACHE_KEY.VisitTenantId)
   // 注意,不要清理 LoginForm 登录表单
 }

+ 46 - 0
src/layout/components/TenantVisit/index.vue

@@ -0,0 +1,46 @@
+<template>
+  <div>
+    <el-select
+      filterable
+      placeholder="请选择租户"
+      class="!w-180px"
+      v-model="value"
+      @change="handleChange"
+      clearable
+    >
+      <el-option v-for="item in tenants" :key="item.id" :label="item.name" :value="item.id" />
+    </el-select>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { ref, onMounted } from 'vue'
+import * as TenantApi from '@/api/system/tenant'
+import { getVisitTenantId, setVisitTenantId } from '@/utils/auth'
+import { useMessage } from '@/hooks/web/useMessage'
+import { useTagsView } from '@/hooks/web/useTagsView'
+
+const message = useMessage() // 消息弹窗
+const tagsView = useTagsView() // 标签页操作
+
+const value = ref(getVisitTenantId()) // 当前选中的租户 ID
+const tenants = ref<any[]>([]) // 租户列表
+
+const handleChange = (id: number) => {
+  // 设置访问租户 ID
+  setVisitTenantId(id)
+  // 关闭其他标签页,只保留当前页
+  tagsView.closeOther()
+  // 刷新当前页面
+  tagsView.refreshPage()
+  // 提示切换成功
+  const tenant = tenants.value.find((item) => item.id === id)
+  if (tenant) {
+    message.success(`切换当前租户为: ${tenant.name}`)
+  }
+}
+
+onMounted(async () => {
+  tenants.value = await TenantApi.getTenantList()
+})
+</script>

+ 6 - 0
src/layout/components/ToolHeader.vue

@@ -8,8 +8,10 @@ import { Breadcrumb } from '@/layout/components/Breadcrumb'
 import { SizeDropdown } from '@/layout/components/SizeDropdown'
 import { LocaleDropdown } from '@/layout/components/LocaleDropdown'
 import RouterSearch from '@/components/RouterSearch/index.vue'
+import TenantVisit from '@/layout/components/TenantVisit/index.vue'
 import { useAppStore } from '@/store/modules/app'
 import { useDesign } from '@/hooks/web/useDesign'
+import { checkPermi } from '@/utils/permission'
 
 const { getPrefixCls, variables } = useDesign()
 
@@ -41,6 +43,9 @@ const locale = computed(() => appStore.getLocale)
 // 消息图标
 const message = computed(() => appStore.getMessage)
 
+// 租户切换权限
+const hasTenantVisitPermission = computed(() => checkPermi(['system:tenant:visit']))
+
 export default defineComponent({
   name: 'ToolHeader',
   setup() {
@@ -62,6 +67,7 @@ export default defineComponent({
           </div>
         ) : undefined}
         <div class="h-full flex items-center">
+          {hasTenantVisitPermission.value ? <TenantVisit /> : undefined}
           {screenfull.value ? (
             <Screenfull class="custom-hover" color="var(--top-header-text-color)"></Screenfull>
           ) : undefined}

+ 10 - 2
src/utils/auth.ts

@@ -67,6 +67,14 @@ export const getTenantId = () => {
   return wsCache.get(CACHE_KEY.TenantId)
 }
 
-export const setTenantId = (username: string) => {
-  wsCache.set(CACHE_KEY.TenantId, username)
+export const setTenantId = (tenantId: number) => {
+  wsCache.set(CACHE_KEY.TenantId, tenantId)
+}
+
+export const getVisitTenantId = () => {
+  return wsCache.get(CACHE_KEY.VisitTenantId)
+}
+
+export const setVisitTenantId = (visitTenantId: number) => {
+  wsCache.set(CACHE_KEY.VisitTenantId, visitTenantId)
 }