""" Multi-theme color and visual style manager for the universal data report generator. """ from pptx.dml.color import RGBColor from report_config import ThemeConfig, ThemePreset PRESETS = { ThemePreset.BUSINESS_CLASSIC: ThemeConfig( preset=ThemePreset.BUSINESS_CLASSIC, name='商务经典', primary='#1E3A5F', accent='#10B981', accent_neg='#EF4444', secondary='#64748B', dark='#1F3A5C', white='#FFFFFF', gray_bg='#F2F2F2', card_bg='#E7F0F7', text='#333333', text_gray='#666666', line='#D9D9D9', chart_series=[ '#1E3A5F', '#10B981', '#ED7D31', '#64748B', '#EF4444', '#707070', '#4472C4', '#5B9BD5', ], ), ThemePreset.FRESH_SIMPLE: ThemeConfig( preset=ThemePreset.FRESH_SIMPLE, name='清新简约', primary='#1B8A5E', accent='#10B981', accent_neg='#EF4444', secondary='#94A3B8', dark='#0F5C3B', white='#FFFFFF', gray_bg='#F8FAFC', card_bg='#ECFDF5', text='#1E293B', text_gray='#64748B', line='#E2E8F0', chart_series=[ '#1B8A5E', '#3B82F6', '#F59E0B', '#94A3B8', '#EF4444', '#8B5CF6', '#06B6D4', '#10B981', ], ), ThemePreset.DARK_PROFESSIONAL: ThemeConfig( preset=ThemePreset.DARK_PROFESSIONAL, name='深色专业', primary='#1E293B', accent='#38BDF8', accent_neg='#F87171', secondary='#94A3B8', dark='#0F172A', white='#FFFFFF', gray_bg='#F1F5F9', card_bg='#E2E8F0', text='#1E293B', text_gray='#475569', line='#CBD5E1', chart_series=[ '#1E293B', '#38BDF8', '#F59E0B', '#94A3B8', '#F87171', '#A78BFA', '#34D399', '#FB923C', ], ), ThemePreset.WARM_BRAND: ThemeConfig( preset=ThemePreset.WARM_BRAND, name='温暖品牌', primary='#C2410C', accent='#F97316', accent_neg='#DC2626', secondary='#78716C', dark='#7C2D12', white='#FFFFFF', gray_bg='#FFFBEB', card_bg='#FFF7ED', text='#292524', text_gray='#78716C', line='#D6D3D1', chart_series=[ '#C2410C', '#F97316', '#EAB308', '#78716C', '#DC2626', '#84CC16', '#06B6D4', '#A855F7', ], ), } def get_theme(preset: ThemePreset, custom_overrides: dict = None) -> ThemeConfig: if preset == ThemePreset.CUSTOM: config = ThemeConfig(preset=ThemePreset.CUSTOM, name='自定义主题') if custom_overrides: for k, v in custom_overrides.items(): if hasattr(config, k): setattr(config, k, v) return config return PRESETS.get(preset, PRESETS[ThemePreset.BUSINESS_CLASSIC]) def theme_to_rgb_colors(theme: ThemeConfig) -> dict: return { 'primary': _hex_to_rgb(theme.primary), 'accent': _hex_to_rgb(theme.accent), 'accent_neg': _hex_to_rgb(theme.accent_neg), 'secondary': _hex_to_rgb(theme.secondary), 'dark': _hex_to_rgb(theme.dark), 'white': _hex_to_rgb(theme.white), 'gray_bg': _hex_to_rgb(theme.gray_bg), 'card_bg': _hex_to_rgb(theme.card_bg), 'text': _hex_to_rgb(theme.text), 'text_gray': _hex_to_rgb(theme.text_gray), 'line': _hex_to_rgb(theme.line), 'green': _hex_to_rgb(theme.accent), 'red': _hex_to_rgb(theme.accent_neg), 'orange': _hex_to_rgb(theme.chart_series[2]) if len(theme.chart_series) > 2 else RGBColor(0xED, 0x7D, 0x31), 'series': [_hex_to_rgb(c) for c in theme.chart_series], } def _hex_to_rgb(hex_str: str) -> RGBColor: hex_str = hex_str.lstrip('#') if len(hex_str) == 6: return RGBColor(int(hex_str[0:2], 16), int(hex_str[2:4], 16), int(hex_str[4:6], 16)) return RGBColor(0x33, 0x33, 0x33) def list_themes() -> list[dict]: result = [] for preset, config in PRESETS.items(): result.append({ 'key': preset.value, 'name': config.name, 'primary': config.primary, 'accent': config.accent, }) result.append({ 'key': 'custom', 'name': '自定义主题', 'primary': '自定义', 'accent': '自定义', }) return result if __name__ == '__main__': for t in list_themes(): print(f"{t['key']}: {t['name']} (primary={t['primary']}, accent={t['accent']})")