From 0dd098213ccc9d31a092d82bf43774faa6bb7ff6 Mon Sep 17 00:00:00 2001 From: hezhaohui Date: Fri, 17 Jul 2026 10:28:02 +0800 Subject: [PATCH] =?UTF-8?q?feat(header):=20=E6=96=B0=E5=A2=9E=E4=B8=9A?= =?UTF-8?q?=E5=8A=A1=E7=BA=BF=E5=88=87=E6=8D=A2=E5=99=A8=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 stores/businessLine.ts:Pinia 状态管理,持久化到 localStorage - 新增 components/BusinessLineSwitcher.vue:企业微信式下拉切换器 - 修改 AppHeader.vue:在环境标签后集成切换器 - 预置 5 条业务线 mock 数据(LAS/Kodo/LTOKEN/灵矽/MAAS) - 更新 components.d.ts 自动类型声明 --- frontend/components.d.ts | 1 + .../src/components/BusinessLineSwitcher.vue | 230 ++++++++++++++++++ frontend/src/components/Layout/AppHeader.vue | 4 +- frontend/src/stores/businessLine.ts | 107 ++++++++ 4 files changed, 341 insertions(+), 1 deletion(-) create mode 100644 frontend/src/components/BusinessLineSwitcher.vue create mode 100644 frontend/src/stores/businessLine.ts 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 @@ + + + + + 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 统一基础设施平台 ● 生产环境 +
@@ -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, + } +})