diff --git a/frontend/components.d.ts b/frontend/components.d.ts
index 6d63c3e..4380d44 100644
--- a/frontend/components.d.ts
+++ b/frontend/components.d.ts
@@ -11,6 +11,7 @@ declare module 'vue' {
AppMain: typeof import('./src/components/Layout/AppMain.vue')['default']
AppSidebar: typeof import('./src/components/Layout/AppSidebar.vue')['default']
AuditLogTable: typeof import('./src/components/AuditLogTable.vue')['default']
+ BusinessLineSwitcher: typeof import('./src/components/BusinessLineSwitcher.vue')['default']
ElButton: typeof import('element-plus/es')['ElButton']
ElIcon: typeof import('element-plus/es')['ElIcon']
ElInput: typeof import('element-plus/es')['ElInput']
diff --git a/frontend/src/components/BusinessLineSwitcher.vue b/frontend/src/components/BusinessLineSwitcher.vue
new file mode 100644
index 0000000..c13e03e
--- /dev/null
+++ b/frontend/src/components/BusinessLineSwitcher.vue
@@ -0,0 +1,230 @@
+
+
+
+
+ {{ currentBL?.iconText }}
+
+
{{ currentBL?.name || '未选择' }}
+
{{ currentBL.role }} · 授权 {{ authCount }} 子系统
+
▼
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/components/Layout/AppHeader.vue b/frontend/src/components/Layout/AppHeader.vue
index 3833271..41ca71d 100644
--- a/frontend/src/components/Layout/AppHeader.vue
+++ b/frontend/src/components/Layout/AppHeader.vue
@@ -5,6 +5,7 @@
xinfra 统一基础设施平台
● 生产环境
+
@@ -23,7 +24,7 @@
{{ userInitial }}
{{ user?.display_name || '未登录' }}
-
LDAP · {{ user?.business_line || '' }}业务线
+
LDAP · {{ user?.business_line || '' }}
退出
@@ -36,6 +37,7 @@ import { useAuthStore } from '@/stores/auth'
import { useTheme } from '@/composables/useTheme'
import { useAuth } from '@/composables/useAuth'
import { Moon, Sunny } from '@element-plus/icons-vue'
+import BusinessLineSwitcher from '@/components/BusinessLineSwitcher.vue'
const authStore = useAuthStore()
const { logout } = useAuth()
diff --git a/frontend/src/stores/businessLine.ts b/frontend/src/stores/businessLine.ts
new file mode 100644
index 0000000..e7b69ab
--- /dev/null
+++ b/frontend/src/stores/businessLine.ts
@@ -0,0 +1,107 @@
+import { defineStore } from 'pinia'
+import { ref, computed } from 'vue'
+
+export interface BusinessLine {
+ id: string
+ name: string
+ ou: string
+ role: string
+ iconText: string
+ iconBg: string
+ iconColor: string
+ authorized: boolean
+}
+
+const STORAGE_KEY = 'xinfra-current-bl'
+
+// TODO: 替换为真实 API 调用
+const MOCK_BUSINESS_LINES: BusinessLine[] = [
+ {
+ id: 'las',
+ name: 'LAS 业务线',
+ ou: 'ou=las',
+ role: 'SRE',
+ iconText: 'LA',
+ iconBg: '#1A1430',
+ iconColor: '#C9A6FF',
+ authorized: true,
+ },
+ {
+ id: 'kodo',
+ name: 'Kodo 业务线',
+ ou: 'ou=kodo',
+ role: '研发',
+ iconText: 'KO',
+ iconBg: '#0E1C2C',
+ iconColor: '#8EC8FF',
+ authorized: true,
+ },
+ {
+ id: 'lingxi',
+ name: '灵矽 业务线',
+ ou: 'ou=lingxi',
+ role: '未授权',
+ iconText: 'LX',
+ iconBg: '#241B0A',
+ iconColor: '#FFC97A',
+ authorized: false,
+ },
+ {
+ id: 'ltoken',
+ name: 'LTOKEN 业务线',
+ ou: 'ou=ltoken',
+ role: '研发',
+ iconText: 'LT',
+ iconBg: '#1A2A1A',
+ iconColor: '#A6FFB0',
+ authorized: true,
+ },
+ {
+ id: 'maas',
+ name: 'MAAS 业务线',
+ ou: 'ou=maas',
+ role: '未授权',
+ iconText: 'MA',
+ iconBg: '#2A1A2A',
+ iconColor: '#FFB0E0',
+ authorized: false,
+ },
+]
+
+function loadSavedBL(): BusinessLine | null {
+ try {
+ const saved = localStorage.getItem(STORAGE_KEY)
+ if (saved) return JSON.parse(saved)
+ } catch {
+ // ignore
+ }
+ return null
+}
+
+export const useBusinessLineStore = defineStore('businessLine', () => {
+ const businessLines = ref(MOCK_BUSINESS_LINES)
+ const currentBL = ref(loadSavedBL())
+
+ // 默认选中第一个已授权的业务线
+ if (!currentBL.value) {
+ currentBL.value = businessLines.value.find((bl) => bl.authorized) || null
+ }
+
+ const authorizedBLs = computed(() =>
+ businessLines.value.filter((bl) => bl.authorized),
+ )
+
+ function switchBL(id: string) {
+ const bl = businessLines.value.find((b) => b.id === id)
+ if (!bl || !bl.authorized) return
+ currentBL.value = bl
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(bl))
+ }
+
+ return {
+ businessLines,
+ currentBL,
+ authorizedBLs,
+ switchBL,
+ }
+})