Files

525 lines
15 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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]))
}
}