首次提交:初始化项目代码

This commit is contained in:
sunct
2026-07-31 14:42:05 +08:00
commit ecca407485
84 changed files with 24158 additions and 0 deletions
+524
View File
@@ -0,0 +1,524 @@
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]))
}
}