feat(theme): 实现日夜主题自动切换功能

- 添加日夜主题CSS变量定义,支持琥珀夜光和暖白琥珀两种风格
- 实现主题切换逻辑,根据时间自动切换白天(light)和夜间(dark)主题
- 在App.vue中集成主题初始化和token恢复功能
- 更新全局样式类应用主题颜色变量,包括卡片、文本、边框等
- 创建主题混入(mixin)供各页面使用,确保主题同步更新
- 实现导航栏和TabBar主题动态切换,提升用户体验
- 添加API服务层封装HaveADrink SDK,统一处理认证和请求
- 优化DrinkCard组件显示饮酒感受信息,丰富打卡记录展示
- 更新项目依赖配置,集成新的API客户端库
This commit is contained in:
cg
2026-07-16 22:47:38 +08:00
parent 145976f221
commit 860136bceb
22 changed files with 7051 additions and 155 deletions
+73 -12
View File
@@ -1,5 +1,5 @@
<template>
<view class="page-container profile-page safe-bottom">
<view :class="themeClass" class="page-container profile-page safe-bottom">
<!-- 用户头部 -->
<view class="profile-header">
<view class="profile-glow"></view>
@@ -108,11 +108,13 @@
<script>
import AchievementBadge from '../../components/AchievementBadge.vue'
import { getRecords, getUserInfo } from '../../common/mock-data'
import { calcStats, checkAchievements } from '../../common/utils'
import client, { clearAuth } from '../../common/api'
import { checkAchievements } from '../../common/utils'
import { ACHIEVEMENTS, DRINK_CATEGORIES } from '../../common/constants'
import themeMixin from '../../common/theme-mixin'
export default {
mixins: [themeMixin],
components: { AchievementBadge },
data() {
return {
@@ -136,11 +138,67 @@ export default {
this.loadData()
},
methods: {
loadData() {
this.user = getUserInfo()
const records = getRecords()
this.stats = calcStats(records)
this.achievementList = checkAchievements(this.stats, ACHIEVEMENTS)
async loadData() {
try {
const [userResp, statsResp, achieveResp] = await Promise.allSettled([
client.GetUserProfile({}),
client.GetStatsOverview({}),
client.GetAchievements({})
])
// 用户信息
if (userResp.status === 'fulfilled' && userResp.value) {
this.user = userResp.value.data || userResp.value
} else {
try {
this.user = JSON.parse(uni.getStorageSync('user_info') || '{}')
} catch (e) { this.user = {} }
}
// 统计概览
if (statsResp.status === 'fulfilled' && statsResp.value) {
const s = statsResp.value.data || statsResp.value
this.stats = {
weekDrinkCount: s.weekDrinkCount || 0,
weekCups: s.weekCups || 0,
monthDrinkCount: s.monthDrinkCount || 0,
monthCups: s.monthCups || 0,
streak: s.streak || 0,
streakType: String(s.streakType || 'drank'),
totalDays: s.totalDays || 0,
totalRecords: s.totalRecords || 0,
totalCups: s.totalCups || 0,
favCategory: s.favCategory ? String(s.favCategory) : null,
categoryVariety: s.categoryVariety || 0
}
}
// 成就列表
if (achieveResp.status === 'fulfilled' && achieveResp.value) {
const list = achieveResp.value.list || achieveResp.value.data || achieveResp.value
if (Array.isArray(list) && list.length > 0) {
this.achievementList = list.map(a => ({
id: a.achievement_id || a.id,
name: a.name,
desc: a.desc,
icon: a.icon,
condition: a.condition || '',
unlocked: !!a.unlocked
}))
} else {
// API 返回空,降级本地计算
this.achievementList = checkAchievements(this.stats, ACHIEVEMENTS)
}
} else {
this.achievementList = checkAchievements(this.stats, ACHIEVEMENTS)
}
} catch (e) {
console.warn('加载个人数据失败:', e)
try {
this.user = JSON.parse(uni.getStorageSync('user_info') || '{}')
} catch (err) { this.user = {} }
this.achievementList = checkAchievements(this.stats, ACHIEVEMENTS)
}
},
showAchievementDetail(a) {
this.detailAchievement = a
@@ -172,9 +230,7 @@ export default {
confirmColor: '#FF6B6B',
success: (res) => {
if (res.confirm) {
uni.removeStorageSync('is_logged_in')
uni.removeStorageSync('is_guest')
uni.removeStorageSync('user_info')
clearAuth()
uni.reLaunch({ url: '/pages/login/login' })
}
}
@@ -239,6 +295,7 @@ export default {
.profile-name {
font-size: $fs-xl;
font-weight: $fw-bold;
color: $text-primary;
margin-bottom: $sp-xs;
}
@@ -256,6 +313,7 @@ export default {
display: block;
font-size: $fs-lg;
font-weight: $fw-bold;
color: $text-primary;
margin-bottom: $sp-lg;
}
@@ -274,6 +332,7 @@ export default {
display: block;
font-size: $fs-2xl;
font-weight: $fw-bold;
color: $text-primary;
margin-bottom: $sp-xs;
}
@@ -299,6 +358,7 @@ export default {
display: block;
font-size: $fs-3xl;
font-weight: $fw-black;
color: $text-primary;
}
.streak-emoji {
@@ -326,6 +386,7 @@ export default {
align-items: center;
gap: $sp-md;
padding: $sp-lg 0;
color: $text-primary;
&:active {
opacity: 0.7;
@@ -364,7 +425,7 @@ export default {
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.7);
background: var(--overlay-modal, rgba(0, 0, 0, 0.7));
display: flex;
align-items: center;
justify-content: center;