import { computed, ref } from 'vue' const THEME_SKIN_STORAGE_KEY = 'x-financial-theme-skin' const DEFAULT_THEME_SKIN_ID = 'sky' const DEFAULT_SEMANTIC_COLORS = { success: '#2f855a', successHover: '#276749', successActive: '#22543d', successSoft: '#f0f7f2', successLine: '#cde6d5', warning: '#b7791f', warningHover: '#975a16', warningActive: '#7b4514', warningSoft: '#fff8eb', warningLine: '#efd9af', danger: '#dc2626', dangerHover: '#b91c1c', dangerActive: '#991b1b', dangerSoft: '#fef2f2', dangerLine: '#fecaca', info: '#475569', infoHover: '#334155', infoActive: '#1e293b', infoSoft: '#f1f5f9', infoLine: '#cbd5e1' } export const THEME_SKIN_OPTIONS = [ { id: 'sky', label: '浅蓝企业', desc: '默认皮肤,降低蓝色饱和度,适合财务 SaaS 和审批后台。', primary: '#3a7ca5', primaryHover: '#2f6d95', primaryActive: '#255b7d', primarySoft: '#eaf4fa', primarySoftStrong: '#d4e8f3', secondary: '#4f6f9f', chartBlue: '#4f6f9f', chartPurple: '#6e7fa6', chartAmber: '#b58b4c' }, { id: 'blue', label: '湖蓝灰', desc: '偏灰的湖蓝色,弱化科技感,更适合高密度运营页面。', primary: '#477c9e', primaryHover: '#3a6a89', primaryActive: '#305873', primarySoft: '#edf5f8', primarySoftStrong: '#d8e8ef', secondary: '#5d7288', chartBlue: '#477c9e', chartPurple: '#77799c', chartAmber: '#b28a54' }, { id: 'navy', label: '稳健蓝', desc: '偏金融和管理驾驶舱的稳重蓝,适合长时间办公查看。', primary: '#4b6f95', primaryHover: '#405f80', primaryActive: '#354e69', primarySoft: '#eef3f8', primarySoftStrong: '#dbe6f0', secondary: '#6b7280', chartBlue: '#4b6f95', chartPurple: '#69769d', chartAmber: '#aa8a55' }, { id: 'teal', label: '雾青', desc: '保留绿色倾向但降低鲜艳度,比旧绿色更克制。', primary: '#3f827c', primaryHover: '#36706b', primaryActive: '#2d5c58', primarySoft: '#eef8f6', primarySoftStrong: '#d8ebe8', secondary: '#4f6f9f', chartBlue: '#4f7f9f', chartPurple: '#708099', chartAmber: '#b18a53' }, { id: 'legacy-green', label: '经典绿', desc: '保留旧版系统绿色,适合继续沿用原有品牌记忆。', primary: '#10b981', primaryHover: '#059669', primaryActive: '#047857', primarySoft: '#ecfdf5', primarySoftStrong: '#d1fae5', secondary: '#2563eb', chartBlue: '#2563eb', chartPurple: '#6d6a9f', chartAmber: '#b88a44' }, { id: 'sage', label: '鼠尾草绿', desc: '低饱和灰绿色,比经典绿更安静,适合企业内控场景。', primary: '#5f8d72', primaryHover: '#517b62', primaryActive: '#436653', primarySoft: '#f0f7f2', primarySoftStrong: '#dcebe0', secondary: '#4f6f9f', chartBlue: '#4f748f', chartPurple: '#7a7898', chartAmber: '#a98753' }, { id: 'slate', label: '石板灰蓝', desc: '弱主色方案,适合审计、规则和报表密集页面。', primary: '#64748b', primaryHover: '#526174', primaryActive: '#3f4a5a', primarySoft: '#f1f5f9', primarySoftStrong: '#e2e8f0', secondary: '#3a7ca5', chartBlue: '#5d7590', chartPurple: '#77748f', chartAmber: '#a88955' }, { id: 'soft-violet', label: '灰紫蓝', desc: '保留一点智能系统气质,但用灰度压低 AI 感和饱和度。', primary: '#6d6a9f', primaryHover: '#5f5b8c', primaryActive: '#504c78', primarySoft: '#f2f1f8', primarySoftStrong: '#e2e0ef', secondary: '#477c9e', chartBlue: '#4f7495', chartPurple: '#6d6a9f', chartAmber: '#a98857' } ] const activeThemeSkinId = ref(DEFAULT_THEME_SKIN_ID) function findThemeSkin(id) { return THEME_SKIN_OPTIONS.find((skin) => skin.id === id) || THEME_SKIN_OPTIONS[0] } function hexToRgb(hex) { const normalized = String(hex || '').replace('#', '') const value = normalized.length === 3 ? normalized.split('').map((item) => item + item).join('') : normalized const numberValue = Number.parseInt(value, 16) if (!Number.isFinite(numberValue) || value.length !== 6) { return '58, 124, 165' } return [ (numberValue >> 16) & 255, (numberValue >> 8) & 255, numberValue & 255 ].join(', ') } function setVariables(root, variables) { Object.entries(variables).forEach(([key, value]) => { root.style.setProperty(key, value) }) } function applyThemeSkin(skin) { if (typeof document === 'undefined') { return } const root = document.documentElement const primaryRgb = hexToRgb(skin.primary) const secondaryRgb = hexToRgb(skin.secondary) const successRgb = hexToRgb(DEFAULT_SEMANTIC_COLORS.success) const warningRgb = hexToRgb(DEFAULT_SEMANTIC_COLORS.warning) const dangerRgb = hexToRgb(DEFAULT_SEMANTIC_COLORS.danger) const infoRgb = hexToRgb(DEFAULT_SEMANTIC_COLORS.info) root.dataset.themeSkin = skin.id setVariables(root, { '--primary': skin.primary, '--primary-hover': skin.primaryHover, '--primary-active': skin.primaryActive, '--primary-soft': skin.primarySoft, '--primary-soft-strong': skin.primarySoftStrong, '--primary-rgb': primaryRgb, '--secondary': skin.secondary, '--secondary-rgb': secondaryRgb, '--theme-secondary': skin.secondary, '--theme-secondary-rgb': secondaryRgb, '--theme-primary': skin.primary, '--theme-primary-hover': skin.primaryHover, '--theme-primary-active': skin.primaryActive, '--theme-primary-soft': skin.primarySoft, '--theme-primary-soft-strong': skin.primarySoftStrong, '--theme-primary-light-5': 'color-mix(in srgb, var(--theme-primary) 46%, white)', '--theme-primary-light-9': 'color-mix(in srgb, var(--theme-primary) 8%, white)', '--theme-primary-rgb': primaryRgb, '--theme-primary-shadow': `rgba(${primaryRgb}, 0.16)`, '--theme-focus-ring': `rgba(${primaryRgb}, 0.12)`, '--theme-gradient-primary': `linear-gradient(135deg, ${skin.primary}, ${skin.primaryActive})`, '--chart-primary': skin.primary, '--chart-primary-rgb': primaryRgb, '--chart-blue': skin.chartBlue, '--chart-purple': skin.chartPurple, '--chart-amber': skin.chartAmber, '--success': DEFAULT_SEMANTIC_COLORS.success, '--success-hover': DEFAULT_SEMANTIC_COLORS.successHover, '--success-active': DEFAULT_SEMANTIC_COLORS.successActive, '--success-soft': DEFAULT_SEMANTIC_COLORS.successSoft, '--success-line': DEFAULT_SEMANTIC_COLORS.successLine, '--success-rgb': successRgb, '--warning': DEFAULT_SEMANTIC_COLORS.warning, '--warning-hover': DEFAULT_SEMANTIC_COLORS.warningHover, '--warning-active': DEFAULT_SEMANTIC_COLORS.warningActive, '--warning-soft': DEFAULT_SEMANTIC_COLORS.warningSoft, '--warning-line': DEFAULT_SEMANTIC_COLORS.warningLine, '--warning-rgb': warningRgb, '--danger': DEFAULT_SEMANTIC_COLORS.danger, '--danger-hover': DEFAULT_SEMANTIC_COLORS.dangerHover, '--danger-active': DEFAULT_SEMANTIC_COLORS.dangerActive, '--danger-soft': DEFAULT_SEMANTIC_COLORS.dangerSoft, '--danger-line': DEFAULT_SEMANTIC_COLORS.dangerLine, '--danger-rgb': dangerRgb, '--info': DEFAULT_SEMANTIC_COLORS.info, '--info-hover': DEFAULT_SEMANTIC_COLORS.infoHover, '--info-active': DEFAULT_SEMANTIC_COLORS.infoActive, '--info-soft': DEFAULT_SEMANTIC_COLORS.infoSoft, '--info-line': DEFAULT_SEMANTIC_COLORS.infoLine, '--info-rgb': infoRgb, '--el-color-primary': skin.primary, '--el-color-primary-dark-2': skin.primaryActive, '--el-color-primary-light-3': skin.primaryHover, '--el-color-primary-light-5': 'var(--theme-primary-light-5)', '--el-color-primary-light-7': skin.primarySoftStrong, '--el-color-primary-light-8': skin.primarySoft, '--el-color-primary-light-9': 'var(--theme-primary-light-9)' }) } function readStoredThemeSkinId() { if (typeof window === 'undefined') { return DEFAULT_THEME_SKIN_ID } const stored = window.localStorage.getItem(THEME_SKIN_STORAGE_KEY) return findThemeSkin(stored).id } export function installThemeSkin() { const skin = findThemeSkin(readStoredThemeSkinId()) activeThemeSkinId.value = skin.id applyThemeSkin(skin) } export function setThemeSkin(id) { const skin = findThemeSkin(id) activeThemeSkinId.value = skin.id applyThemeSkin(skin) if (typeof window !== 'undefined') { window.localStorage.setItem(THEME_SKIN_STORAGE_KEY, skin.id) } } export function useThemeSkin() { return { activeThemeSkin: computed(() => findThemeSkin(activeThemeSkinId.value)), activeThemeSkinId, setThemeSkin, themeSkinOptions: THEME_SKIN_OPTIONS } }