import { getToken } from '@/utils/auth' import { getUserConfig, editUserConfig } from '@/api' import { forceApplyTabBarTheme } from '@/utils/themeGlobal' // 全新主题预设 - 温暖生活风 // 设计特点:燕麦底色、低饱和、手作感、留白充足、去AI化 export const THEME_PRESETS = { // 暖陶色 - 默认主主题(温暖、自然、生活感) default: { name: '暖陶', primaryColor: '#C68E3F', secondaryColor: '#4A9E7F', accentColor: '#B85C3A', dangerColor: '#C75B4A', warningColor: '#D4A24A', successColor: '#5B9E6E', successColorRGB: '91, 158, 110', infoColor: '#5B8DB8', pendingColor: '#F5EDE4', bgColor: '#FAF6F0', bgGradientStart: '#F7F3ED', bgGradientEnd: '#FAF6F0', cardBgColor: '#FFFCF8', cardBgBlur: 'rgba(255, 252, 248, 0.92)', textPrimary: '#3D3630', textSecondary: '#7A7066', textTertiary: '#9A9088', textDisabled: '#B0A89E', textLight: '#EDE8E1', borderColor: '#E8E2DA', borderLight: '#F2EDE6', inputBgColor: '#F7F3ED', shadowColor: 'rgba(198, 142, 63, 0.18)', shadowLight: 'rgba(61, 54, 48, 0.04)', shadowMedium: 'rgba(61, 54, 48, 0.08)', shadowStrong: 'rgba(61, 54, 48, 0.12)', gradientStart: '#B85C3A', gradientEnd: '#C68E3F', gradientSoft: 'linear-gradient(135deg, #B85C3A 0%, #C68E3F 100%)', gradientVibrant: 'linear-gradient(135deg, #A04A2E 0%, #B85C3A 50%, #C68E3F 100%)', priorityHigh: '#C75B4A', priorityMiddle: '#D4A24A', priorityLow: '#5B9E6E', checkboxColor: '#FFFFFF', moodHappy: '#D4A24A', moodCalm: '#5B9E6E', moodSad: '#7B9EB8', moodAngry: '#C75B4A', moodNeutral: '#B0A89E', incomeColor: '#5B9E6E', expendColor: '#C75B4A' }, // 青苔 - 自然清新 mint: { name: '青苔', primaryColor: '#4A9E7F', secondaryColor: '#6DB89A', accentColor: '#3D8568', dangerColor: '#C75B4A', warningColor: '#D4A24A', successColor: '#5B9E6E', infoColor: '#5B8DB8', pendingColor: '#EEF5F1', bgColor: '#F5F8F3', bgGradientStart: '#F0F4ED', bgGradientEnd: '#F5F8F3', cardBgColor: '#FAFCF8', cardBgBlur: 'rgba(250, 252, 248, 0.92)', textPrimary: '#2D3A30', textSecondary: '#6B7D6E', textTertiary: '#8B9A8E', textDisabled: '#A3B0A6', textLight: '#E5EBE7', borderColor: '#D8E2DA', borderLight: '#E8EDE9', inputBgColor: '#EEF5F1', shadowColor: 'rgba(74, 158, 127, 0.1)', shadowLight: 'rgba(45, 58, 48, 0.04)', shadowMedium: 'rgba(45, 58, 48, 0.07)', shadowStrong: 'rgba(45, 58, 48, 0.11)', gradientStart: '#3D8568', gradientEnd: '#4A9E7F', gradientSoft: 'linear-gradient(135deg, #3D8568 0%, #4A9E7F 100%)', gradientVibrant: 'linear-gradient(135deg, #2D6B53 0%, #3D8568 50%, #4A9E7F 100%)', priorityHigh: '#C75B4A', priorityMiddle: '#D4A24A', priorityLow: '#5B9E6E', checkboxColor: '#FFFFFF', moodHappy: '#D4A24A', moodCalm: '#4A9E7F', moodSad: '#7B9EB8', moodAngry: '#C75B4A', moodNeutral: '#A3B0A6', incomeColor: '#5B9E6E', expendColor: '#C75B4A' }, // 藕粉 - 柔和温婉 cherry: { name: '藕粉', primaryColor: '#C4908A', secondaryColor: '#D5A9A4', accentColor: '#B07872', dangerColor: '#C75B4A', warningColor: '#D4A24A', successColor: '#5B9E6E', infoColor: '#5B8DB8', pendingColor: '#F8F0EF', bgColor: '#FAF5F3', bgGradientStart: '#F6F0EE', bgGradientEnd: '#FAF5F3', cardBgColor: '#FDF9F8', cardBgBlur: 'rgba(253, 249, 248, 0.92)', textPrimary: '#3D3332', textSecondary: '#7A6C6A', textTertiary: '#9A8C8A', textDisabled: '#B0A5A3', textLight: '#EDE5E3', borderColor: '#E5DAD7', borderLight: '#F0E8E5', inputBgColor: '#F8F0EF', shadowColor: 'rgba(196, 144, 138, 0.1)', shadowLight: 'rgba(61, 51, 50, 0.04)', shadowMedium: 'rgba(61, 51, 50, 0.07)', shadowStrong: 'rgba(61, 51, 50, 0.11)', gradientStart: '#B07872', gradientEnd: '#C4908A', gradientSoft: 'linear-gradient(135deg, #B07872 0%, #C4908A 100%)', gradientVibrant: 'linear-gradient(135deg, #9A5E5A 0%, #B07872 50%, #C4908A 100%)', priorityHigh: '#C75B4A', priorityMiddle: '#D4A24A', priorityLow: '#5B9E6E', checkboxColor: '#FFFFFF', moodHappy: '#D4A24A', moodCalm: '#5B9E6E', moodSad: '#7B9EB8', moodAngry: '#C75B4A', moodNeutral: '#B0A5A3', incomeColor: '#5B9E6E', expendColor: '#C75B4A' }, // 暮蓝 - 沉静夜色 sky: { name: '暮蓝', primaryColor: '#5B8DB8', secondaryColor: '#7BA7C6', accentColor: '#4978A0', dangerColor: '#C75B4A', warningColor: '#D4A24A', successColor: '#5B9E6E', infoColor: '#5B8DB8', pendingColor: '#EEF2F6', bgColor: '#F3F5F8', bgGradientStart: '#EEF1F5', bgGradientEnd: '#F3F5F8', cardBgColor: '#F8FAFB', cardBgBlur: 'rgba(248, 250, 251, 0.92)', textPrimary: '#2D343D', textSecondary: '#6B7580', textTertiary: '#8B95A0', textDisabled: '#A3ABB5', textLight: '#E5E9ED', borderColor: '#D8DEE4', borderLight: '#E8ECF0', inputBgColor: '#EEF2F6', shadowColor: 'rgba(91, 141, 184, 0.1)', shadowLight: 'rgba(45, 52, 61, 0.04)', shadowMedium: 'rgba(45, 52, 61, 0.07)', shadowStrong: 'rgba(45, 52, 61, 0.11)', gradientStart: '#4978A0', gradientEnd: '#5B8DB8', gradientSoft: 'linear-gradient(135deg, #4978A0 0%, #5B8DB8 100%)', gradientVibrant: 'linear-gradient(135deg, #355E80 0%, #4978A0 50%, #5B8DB8 100%)', priorityHigh: '#C75B4A', priorityMiddle: '#D4A24A', priorityLow: '#5B9E6E', checkboxColor: '#FFFFFF', moodHappy: '#D4A24A', moodCalm: '#5B9E6E', moodSad: '#5B8DB8', moodAngry: '#C75B4A', moodNeutral: '#A3ABB5', incomeColor: '#5B9E6E', expendColor: '#C75B4A' }, // 深夜模式 - 暗色温暖 dark: { name: '深夜', primaryColor: '#D4AA60', secondaryColor: '#7DB89A', accentColor: '#C68E3F', dangerColor: '#D47060', warningColor: '#D4AA60', successColor: '#6DB89A', infoColor: '#7BA7C6', pendingColor: '#2A2824', bgColor: '#1E1D1A', bgGradientStart: '#252420', bgGradientEnd: '#1E1D1A', cardBgColor: '#2A2824', cardBgBlur: 'rgba(42, 40, 36, 0.92)', textPrimary: '#E8E2DA', textSecondary: '#9A9088', textTertiary: '#807870', textDisabled: '#6B6360', textLight: '#2A2824', borderColor: '#3A3632', borderLight: '#302E2A', inputBgColor: '#252420', shadowColor: 'rgba(212, 170, 96, 0.15)', shadowLight: 'rgba(0, 0, 0, 0.3)', shadowMedium: 'rgba(0, 0, 0, 0.4)', shadowStrong: 'rgba(0, 0, 0, 0.5)', gradientStart: '#D4AA60', gradientEnd: '#C68E3F', gradientSoft: 'linear-gradient(135deg, #D4AA60 0%, #C68E3F 100%)', gradientVibrant: 'linear-gradient(135deg, #C68E3F 0%, #D4AA60 50%, #E0C080 100%)', priorityHigh: '#D47060', priorityMiddle: '#D4AA60', priorityLow: '#6DB89A', checkboxColor: '#2A2824', moodHappy: '#D4AA60', moodCalm: '#6DB89A', moodSad: '#7BA7C6', moodAngry: '#D47060', moodNeutral: '#9A9088', incomeColor: '#6DB89A', expendColor: '#D47060' }, // 薰衣 - 梦幻紫韵 cream: { name: '薰衣', primaryColor: '#957BB7', secondaryColor: '#B099D4', accentColor: '#7A60A0', dangerColor: '#C87888', warningColor: '#D4A060', successColor: '#7AB884', infoColor: '#9A8AC8', pendingColor: '#F3EFF8', bgColor: '#F6F3FA', bgGradientStart: '#F0ECF6', bgGradientEnd: '#F6F3FA', cardBgColor: '#FBFAFD', cardBgBlur: 'rgba(251, 250, 253, 0.92)', textPrimary: '#2E2240', textSecondary: '#6B5B7A', textTertiary: '#8B7B9A', textDisabled: '#B8AEC8', textLight: '#E8E0F0', borderColor: '#DDD4E8', borderLight: '#EBE4F0', inputBgColor: '#F3EFF8', shadowColor: 'rgba(149, 123, 183, 0.1)', shadowLight: 'rgba(46, 34, 64, 0.04)', shadowMedium: 'rgba(46, 34, 64, 0.07)', shadowStrong: 'rgba(46, 34, 64, 0.11)', gradientStart: '#7A60A0', gradientEnd: '#957BB7', gradientSoft: 'linear-gradient(135deg, #7A60A0 0%, #957BB7 100%)', gradientVibrant: 'linear-gradient(135deg, #5A4580 0%, #7A60A0 50%, #957BB7 100%)', priorityHigh: '#C87888', priorityMiddle: '#D4A060', priorityLow: '#7AB884', checkboxColor: '#FFFFFF', moodHappy: '#D4A060', moodCalm: '#7AB884', moodSad: '#957BB7', moodAngry: '#C87888', moodNeutral: '#B8AEC8', incomeColor: '#7AB884', expendColor: '#C87888' }, // 柑橘 - 活力明亮 ocean: { name: '柑橘', primaryColor: '#D4824A', secondaryColor: '#E09A6A', accentColor: '#C07040', dangerColor: '#C86060', warningColor: '#C8A040', successColor: '#6AA87A', infoColor: '#B89070', pendingColor: '#FDF0E8', bgColor: '#FDF6F0', bgGradientStart: '#F8F0E8', bgGradientEnd: '#FDF6F0', cardBgColor: '#FEFCFA', cardBgBlur: 'rgba(254, 252, 250, 0.92)', textPrimary: '#3D281A', textSecondary: '#7A5E48', textTertiary: '#9A7E68', textDisabled: '#C8B8A8', textLight: '#F0E4D8', borderColor: '#E8D8CC', borderLight: '#F2E8E0', inputBgColor: '#FDF0E8', shadowColor: 'rgba(212, 130, 74, 0.1)', shadowLight: 'rgba(61, 40, 26, 0.04)', shadowMedium: 'rgba(61, 40, 26, 0.07)', shadowStrong: 'rgba(61, 40, 26, 0.11)', gradientStart: '#C07040', gradientEnd: '#D4824A', gradientSoft: 'linear-gradient(135deg, #C07040 0%, #D4824A 100%)', gradientVibrant: 'linear-gradient(135deg, #9A5530 0%, #C07040 50%, #D4824A 100%)', priorityHigh: '#C86060', priorityMiddle: '#C8A040', priorityLow: '#6AA87A', checkboxColor: '#FFFFFF', moodHappy: '#D4824A', moodCalm: '#6AA87A', moodSad: '#7B9EB8', moodAngry: '#C86060', moodNeutral: '#C8B8A8', incomeColor: '#6AA87A', expendColor: '#C86060' }, // 薄荷 - 清凉冰爽 matcha: { name: '薄荷', primaryColor: '#5BA8A0', secondaryColor: '#7BC4BC', accentColor: '#4A968E', dangerColor: '#C07078', warningColor: '#C8A860', successColor: '#5A9B6A', infoColor: '#7AB8B0', pendingColor: '#E8F4F2', bgColor: '#F0F7F6', bgGradientStart: '#E8F2F0', bgGradientEnd: '#F0F7F6', cardBgColor: '#F8FBFB', cardBgBlur: 'rgba(248, 251, 251, 0.92)', textPrimary: '#1A3330', textSecondary: '#4A7A74', textTertiary: '#6A9A94', textDisabled: '#A0C8C0', textLight: '#D8EBE8', borderColor: '#C8DDD8', borderLight: '#E0EBE8', inputBgColor: '#E8F4F2', shadowColor: 'rgba(91, 168, 160, 0.1)', shadowLight: 'rgba(26, 51, 48, 0.04)', shadowMedium: 'rgba(26, 51, 48, 0.07)', shadowStrong: 'rgba(26, 51, 48, 0.11)', gradientStart: '#4A968E', gradientEnd: '#5BA8A0', gradientSoft: 'linear-gradient(135deg, #4A968E 0%, #5BA8A0 100%)', gradientVibrant: 'linear-gradient(135deg, #357A72 0%, #4A968E 50%, #5BA8A0 100%)', priorityHigh: '#C07078', priorityMiddle: '#C8A860', priorityLow: '#5A9B6A', checkboxColor: '#FFFFFF', moodHappy: '#D4A24A', moodCalm: '#5BA8A0', moodSad: '#7B9EB8', moodAngry: '#C07078', moodNeutral: '#A0C8C0', incomeColor: '#5A9B6A', expendColor: '#C07078' } } // 统一本地存储key(核心存储完整配置,避免冗余) export const THEME_STORAGE_KEY = 'user_current_theme' // 默认主题key export const DEFAULT_THEME_KEY = 'default' // 全局主题变更事件名(标准化) export const THEME_CHANGE_EVENT = 'themeChanged' // ===================== 本地存储方法(统一逻辑 + 强容错) ===================== export const saveThemeConfigToStorage = (themeConfig) => { try { const pureConfig = JSON.parse(JSON.stringify(themeConfig)) uni.setStorageSync(THEME_STORAGE_KEY, JSON.stringify(pureConfig)) } catch (e) { console.error('【主题】保存到本地失败:', e) } } export const getThemeConfigFromStorage = () => { try { const themeStr = uni.getStorageSync(THEME_STORAGE_KEY) if (!themeStr) return THEME_PRESETS[DEFAULT_THEME_KEY] const config = JSON.parse(themeStr) const requiredFields = ['primaryColor', 'bgColor', 'textPrimary'] const isValid = requiredFields.every(field => config[field]) return isValid ? config : THEME_PRESETS[DEFAULT_THEME_KEY] } catch (e) { console.warn('【主题】读取本地配置失败,使用默认:', e) return THEME_PRESETS[DEFAULT_THEME_KEY] } } export const saveThemeKeyToStorage = (themeKey) => { const validKey = THEME_PRESETS[themeKey] ? themeKey : DEFAULT_THEME_KEY uni.setStorageSync('selectedTheme', validKey) } export const getThemeKeyFromStorage = () => { const themeKey = uni.getStorageSync('selectedTheme') return THEME_PRESETS[themeKey] ? themeKey : DEFAULT_THEME_KEY } // ===================== 后端接口相关(异步容错 + 无token降级) ===================== export const getThemeFromServer = async () => { if (!getToken()) { console.log('【主题】未登录,使用本地主题key') return getThemeKeyFromStorage() } try { const res = await getUserConfig() const serverThemeKey = res?.theme console.log('【主题】从后端获取到key:', serverThemeKey) const validKey = THEME_PRESETS[serverThemeKey] ? serverThemeKey : DEFAULT_THEME_KEY saveThemeKeyToStorage(validKey) saveThemeConfigToStorage(THEME_PRESETS[validKey]) return validKey } catch (error) { console.warn('【主题】从后端获取失败,使用本地缓存:', error) return getThemeKeyFromStorage() } } export const saveThemeToServer = async (themeKey) => { if (!getToken() || !THEME_PRESETS[themeKey]) return false try { await editUserConfig({ theme: themeKey }) console.log(`【主题】同步到后端成功:${themeKey}`) return true } catch (error) { console.error(`【主题】同步到后端失败:${themeKey}`, error) return false } } // ===================== 全局主题注入(核心:保证全项目数据一致) ===================== export const injectTheme = (themeKey) => { const validKey = THEME_PRESETS[themeKey] ? themeKey : DEFAULT_THEME_KEY const themeConfig = THEME_PRESETS[validKey] console.log('【主题】注入全局配置:', validKey, themeConfig) const appInstance = getApp({ allowDefault: true }) if (appInstance) { appInstance.globalData = appInstance.globalData || {} appInstance.globalData.themeConfig = JSON.parse(JSON.stringify(themeConfig)) appInstance.globalData.themeKey = validKey } saveThemeKeyToStorage(validKey) saveThemeConfigToStorage(themeConfig) uni.$emit(THEME_CHANGE_EVENT, { key: validKey, config: themeConfig }) Promise.resolve().then(() => { forceApplyTabBarTheme(themeConfig) setTimeout(() => { forceApplyTabBarTheme(themeConfig) }, 100) setTimeout(() => { forceApplyTabBarTheme(themeConfig) }, 300) }) } // ===================== 对外暴露的核心方法(一站式调用) ===================== export const switchTheme = async (themeKey, showToast = true) => { const validKey = THEME_PRESETS[themeKey] ? themeKey : DEFAULT_THEME_KEY try { const serverPromise = saveThemeToServer(validKey) injectTheme(validKey) if (showToast) { const serverSuccess = await serverPromise uni.showToast({ title: serverSuccess ? `${THEME_PRESETS[validKey].name}切换成功` : `${THEME_PRESETS[validKey].name}已生效,云端同步失败`, icon: 'none', duration: 1500 }) } else { await serverPromise } return true } catch (error) { injectTheme(validKey) if (showToast) { uni.showToast({ title: `${THEME_PRESETS[validKey].name}已生效,云端同步失败`, icon: 'none', duration: 2000 }) } return false } } export const initTheme = async () => { try { const themeKey = await getThemeFromServer() injectTheme(themeKey) return JSON.parse(JSON.stringify(THEME_PRESETS[themeKey])) } catch (error) { console.error('【主题】初始化失败,使用默认配置:', error) injectTheme(DEFAULT_THEME_KEY) return JSON.parse(JSON.stringify(THEME_PRESETS[DEFAULT_THEME_KEY])) } }