diff --git a/src/components/HabitArea.vue b/src/components/HabitArea.vue
index 83f9c73..e135b35 100644
--- a/src/components/HabitArea.vue
+++ b/src/components/HabitArea.vue
@@ -158,7 +158,8 @@ const habits = {
noPickyEating: { name: '不挑食', icon: '🥦' },
washHands: { name: '勤洗手', icon: '🧼' },
homeworkFast: { name: '写作业快', icon: '📝' },
- earlySleep: { name: '早睡', icon: '🌙' }
+ earlySleep: { name: '早睡', icon: '🌙' },
+ cleanRoom: { name: '打扫卫生', icon: '🧹' }
};
// 坏习惯数据
@@ -174,7 +175,7 @@ const monsters = {
boss: {
name: '坏习惯大魔王',
health: 500,
- habits: ['brushTeeth', 'noBedLate', 'noPickyEating', 'washHands', 'homeworkFast', 'earlySleep']
+ habits: ['brushTeeth', 'noBedLate', 'noPickyEating', 'washHands', 'homeworkFast', 'earlySleep', 'cleanRoom']
}
};
@@ -190,7 +191,7 @@ const badges = computed(() => starEnergyStore.badges);
// 检查习惯是否已打卡
const isChecked = (habit: keyof typeof habitData.value) => {
const today = new Date().toISOString().split('T')[0];
- return habitData.value[habit].lastChecked === today;
+ return habitData.value[habit]?.lastChecked === today;
};
// 打卡习惯
diff --git a/src/components/RewardArea.vue b/src/components/RewardArea.vue
index 9ececd3..77046ba 100644
--- a/src/components/RewardArea.vue
+++ b/src/components/RewardArea.vue
@@ -65,13 +65,38 @@
🎉 已兑换的奖励
+
+
+ 已兑换:
+ {{ claimedRewards.length }} 个
+
+
+ 已给孩子:
+ {{ givenRewards.length }} 个
+
+
+ 待领取:
+ {{ claimedRewards.length - givenRewards.length }} 个
+
+
- {{ getRewardById(id)?.emoji }} {{ getRewardById(id)?.name }}
+
+ {{ getRewardById(id)?.emoji }} {{ getRewardById(id)?.name }}
+
+
+
已给孩子 ✓
@@ -110,6 +135,9 @@ const currentCategory = ref('all');
// 已兑换奖励ID列表
const claimedRewards = computed(() => starEnergyStore.claimedRewards);
+// 已给孩子的奖励ID列表
+const givenRewards = computed(() => starEnergyStore.getGivenRewards || []);
+
// 弹窗状态
const showSuccessModal = ref(false);
const showInsufficientModal = ref(false);
@@ -166,7 +194,7 @@ const rewards = [
id: 'park_50',
name: '去公园玩',
description: '可以和爸爸妈妈去公园玩!',
- cost: 50,
+ cost: 100,
emoji: '🎡',
category: 'activity'
},
@@ -191,7 +219,7 @@ const rewards = [
id: 'zoo_100',
name: '去动物园',
description: '可以去动物园看小动物!',
- cost: 100,
+ cost: 500,
emoji: '🦁',
category: 'activity'
},
@@ -200,7 +228,7 @@ const rewards = [
id: 'lego_200',
name: '乐高积木套装',
description: '可以获得一套乐高积木!',
- cost: 200,
+ cost: 400,
emoji: '🧱',
category: 'toy'
},
@@ -224,7 +252,7 @@ const rewards = [
id: 'amusement_200',
name: '游乐园一日游',
description: '可以和爸爸妈妈去游乐园玩一整天!',
- cost: 200,
+ cost: 500,
emoji: '🎢',
category: 'activity'
},
@@ -232,7 +260,7 @@ const rewards = [
id: 'bike_200',
name: '自行车一辆',
description: '可以获得一辆全新的自行车!',
- cost: 200,
+ cost: 1000,
emoji: '🚲',
category: 'toy'
},
@@ -250,7 +278,7 @@ const rewards = [
id: 'family_trip_500',
name: '家庭旅行',
description: '可以和家人一起去旅行!',
- cost: 500,
+ cost: 1000,
emoji: '✈️',
category: 'activity'
},
@@ -258,7 +286,7 @@ const rewards = [
id: 'game_console_500',
name: '游戏机',
description: '可以获得一台游戏机!',
- cost: 500,
+ cost: 2000,
emoji: '🎮',
category: 'toy'
},
@@ -372,7 +400,12 @@ const redeemReward = (reward: any) => {
// 根据ID获取奖励
const getRewardById = (id: string) => {
- return rewards.find(reward => reward.id === id);
+ return rewards.find(reward => reward.id === id) || { emoji: '🎁', name: '未知奖励' };
+};
+
+// 标记奖励为已给孩子
+const markRewardAsGiven = (rewardId: string) => {
+ starEnergyStore.markRewardAsGiven(rewardId);
};
// 关闭弹窗
@@ -661,9 +694,41 @@ const closeModal = () => {
animation: bounce 2s ease-in-out infinite;
}
+/* 奖励统计 */
+.reward-stats {
+ display: flex;
+ justify-content: space-around;
+ margin-bottom: 20px;
+ padding: 15px;
+ background: linear-gradient(135deg, #98FB98, #90EE90);
+ border-radius: 20px;
+ border: 3px solid #32CD32;
+}
+
+.stat-item {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 5px;
+}
+
+.stat-label {
+ font-size: 14px;
+ color: #006400;
+ font-weight: bold;
+ font-family: var(--cartoon-font);
+}
+
+.stat-value {
+ font-size: 18px;
+ color: #006400;
+ font-weight: bold;
+ font-family: var(--cartoon-font);
+}
+
.claimed-grid {
display: grid;
- grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
+ grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
gap: 15px;
}
@@ -677,6 +742,53 @@ const closeModal = () => {
color: white;
box-shadow: 0 4px 10px rgba(255, 215, 0, 0.4);
animation: bounce 2s ease-in-out infinite;
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ min-height: 100px;
+}
+
+.claimed-card.given {
+ background: linear-gradient(135deg, #98FB98, #32CD32);
+ border: 3px solid #228B22;
+}
+
+.claimed-content {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 10px;
+}
+
+.give-btn {
+ background: rgba(255, 255, 255, 0.9);
+ color: #8B4513;
+ border: none;
+ padding: 8px 16px;
+ border-radius: 12px;
+ font-size: 12px;
+ font-weight: bold;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ font-family: var(--cartoon-font);
+}
+
+.give-btn:hover {
+ background: white;
+ transform: translateY(-2px);
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
+}
+
+.given-badge {
+ background: rgba(255, 255, 255, 0.3);
+ color: white;
+ padding: 6px 12px;
+ border-radius: 10px;
+ font-size: 12px;
+ font-weight: bold;
+ font-family: var(--cartoon-font);
+ border: 2px solid rgba(255, 255, 255, 0.5);
}
/* 弹窗 */
diff --git a/src/stores/starEnergy.ts b/src/stores/starEnergy.ts
index 74aef13..cb0a4d1 100644
--- a/src/stores/starEnergy.ts
+++ b/src/stores/starEnergy.ts
@@ -33,9 +33,45 @@ export const useStarEnergyStore = defineStore('starEnergy', {
// 尝试从 localStorage 加载保存的数据
const savedData = loadFromLocalStorage();
+ // 获取当前日期
+ const today = new Date().toDateString();
+
+ // 检查是否需要重置怪兽状态和已兑换奖励
+ let monsters = savedData?.monsters;
+ let lastResetDate = savedData?.lastResetDate;
+ let claimedRewards = savedData?.claimedRewards;
+ let givenRewards = savedData?.givenRewards;
+ let bossDefeats = savedData?.bossDefeats;
+
+ // 防御性检查
+ if (!Array.isArray(claimedRewards)) {
+ claimedRewards = [];
+ }
+ if (!Array.isArray(givenRewards)) {
+ givenRewards = [];
+ }
+ if (typeof bossDefeats !== 'number') {
+ bossDefeats = 0;
+ }
+
+ // 如果是新的一天,重置怪兽状态和已兑换奖励
+ if (!lastResetDate || lastResetDate !== today) {
+ monsters = {
+ boss: {
+ name: '坏习惯大魔王',
+ health: 500,
+ defeated: false,
+ habits: ['brushTeeth', 'noBedLate', 'noPickyEating', 'washHands', 'homeworkFast', 'earlySleep', 'cleanRoom']
+ }
+ };
+ claimedRewards = []; // 重置已兑换奖励
+ givenRewards = []; // 重置已给孩子的奖励
+ lastResetDate = today;
+ }
+
return {
// 星星能量总数
- total: savedData?.total || 20,
+ total: typeof savedData?.total === 'number' ? savedData.total : 20,
// 各区域的星星能量
areas: savedData?.areas || {
knowledge: 0,
@@ -45,59 +81,76 @@ export const useStarEnergyStore = defineStore('starEnergy', {
parent: 0
},
// 习惯打卡记录
- habits: savedData?.habits || {
+ habits: {
brushTeeth: {
name: '刷牙',
count: 0,
streak: 0,
- lastChecked: null as string | null
+ lastChecked: null as string | null,
+ ...savedData?.habits?.brushTeeth
},
noBedLate: {
name: '不赖床',
count: 0,
streak: 0,
- lastChecked: null as string | null
+ lastChecked: null as string | null,
+ ...savedData?.habits?.noBedLate
},
noPickyEating: {
name: '不挑食',
count: 0,
streak: 0,
- lastChecked: null as string | null
+ lastChecked: null as string | null,
+ ...savedData?.habits?.noPickyEating
},
washHands: {
name: '勤洗手',
count: 0,
streak: 0,
- lastChecked: null as string | null
+ lastChecked: null as string | null,
+ ...savedData?.habits?.washHands
},
homeworkFast: {
name: '写作业快',
count: 0,
streak: 0,
- lastChecked: null as string | null
+ lastChecked: null as string | null,
+ ...savedData?.habits?.homeworkFast
},
earlySleep: {
name: '早睡',
count: 0,
streak: 0,
- lastChecked: null as string | null
+ lastChecked: null as string | null,
+ ...savedData?.habits?.earlySleep
+ },
+ cleanRoom: {
+ name: '打扫卫生',
+ count: 0,
+ streak: 0,
+ lastChecked: null as string | null,
+ ...savedData?.habits?.cleanRoom
}
},
// 怪兽状态
- monsters: {
+ monsters: monsters || {
boss: {
name: '坏习惯大魔王',
- health: (savedData?.monsters && 'boss' in savedData.monsters && !savedData.monsters.boss.defeated) ? savedData.monsters.boss.health : 500,
- defeated: (savedData?.monsters && 'boss' in savedData.monsters) ? savedData.monsters.boss.defeated : false,
- habits: ['brushTeeth', 'noBedLate', 'noPickyEating', 'washHands', 'homeworkFast', 'earlySleep']
+ health: 500,
+ defeated: false,
+ habits: ['brushTeeth', 'noBedLate', 'noPickyEating', 'washHands', 'homeworkFast', 'earlySleep', 'cleanRoom']
}
},
// 勋章
- badges: savedData?.badges || [] as string[],
+ badges: Array.isArray(savedData?.badges) ? savedData.badges : [] as string[],
// 已兑换奖励
- claimedRewards: savedData?.claimedRewards || [] as string[],
+ claimedRewards: claimedRewards,
+ // 已给孩子的奖励
+ givenRewards: givenRewards,
// 击败BOSS次数
- bossDefeats: savedData?.bossDefeats || 0
+ bossDefeats: bossDefeats,
+ // 上次重置日期
+ lastResetDate: lastResetDate || today
};
},
@@ -120,6 +173,9 @@ export const useStarEnergyStore = defineStore('starEnergy', {
// 获取已兑换奖励
getClaimedRewards: (state) => state.claimedRewards,
+ // 获取已给孩子的奖励
+ getGivenRewards: (state) => state.givenRewards,
+
// 获取击败BOSS次数
getBossDefeats: (state) => state.bossDefeats
},
@@ -133,7 +189,10 @@ export const useStarEnergyStore = defineStore('starEnergy', {
habits: this.habits,
monsters: this.monsters,
badges: this.badges,
- claimedRewards: this.claimedRewards
+ claimedRewards: this.claimedRewards,
+ givenRewards: this.givenRewards,
+ bossDefeats: this.bossDefeats,
+ lastResetDate: this.lastResetDate
};
saveToLocalStorage(data);
},
@@ -160,11 +219,19 @@ export const useStarEnergyStore = defineStore('starEnergy', {
const today = new Date().toISOString().split('T')[0];
const habitData = this.habits[habit];
+ // 检查习惯数据是否存在
+ if (!habitData) {
+ return;
+ }
+
// 防止重复打卡
if (habitData.lastChecked === today) {
return;
}
+ // 保存原来的lastChecked值用于连续打卡计算
+ const originalLastChecked = habitData.lastChecked;
+
// 更新打卡记录
habitData.count++;
habitData.lastChecked = today;
@@ -174,7 +241,7 @@ export const useStarEnergyStore = defineStore('starEnergy', {
yesterday.setDate(yesterday.getDate() - 1);
const yesterdayStr = yesterday.toISOString().split('T')[0];
- if (habitData.lastChecked === yesterdayStr) {
+ if (originalLastChecked === yesterdayStr) {
habitData.streak++;
} else {
habitData.streak = 1;
@@ -187,6 +254,9 @@ export const useStarEnergyStore = defineStore('starEnergy', {
if (habitData.streak % 3 === 0) {
this.addEnergy(5, 'habit');
}
+
+ // 保存数据
+ this.$persist();
},
// 攻击怪兽
@@ -259,6 +329,27 @@ export const useStarEnergyStore = defineStore('starEnergy', {
return true;
},
+ // 标记奖励为已给孩子
+ markRewardAsGiven(rewardId: string) {
+ if (!this.givenRewards.includes(rewardId)) {
+ this.givenRewards.push(rewardId);
+ this.$persist();
+ return true;
+ }
+ return false;
+ },
+
+ // 取消标记奖励为已给孩子
+ unmarkRewardAsGiven(rewardId: string) {
+ const index = this.givenRewards.indexOf(rewardId);
+ if (index > -1) {
+ this.givenRewards.splice(index, 1);
+ this.$persist();
+ return true;
+ }
+ return false;
+ },
+
// 重置所有数据(清除游戏进度)
resetAll() {
this.total = 0;
@@ -305,6 +396,12 @@ export const useStarEnergyStore = defineStore('starEnergy', {
count: 0,
streak: 0,
lastChecked: null
+ },
+ cleanRoom: {
+ name: '打扫卫生',
+ count: 0,
+ streak: 0,
+ lastChecked: null
}
};
this.monsters = {
@@ -312,11 +409,12 @@ export const useStarEnergyStore = defineStore('starEnergy', {
name: '坏习惯大魔王',
health: 500,
defeated: false,
- habits: ['brushTeeth', 'noBedLate', 'noPickyEating', 'washHands', 'homeworkFast', 'earlySleep']
+ habits: ['brushTeeth', 'noBedLate', 'noPickyEating', 'washHands', 'homeworkFast', 'earlySleep', 'cleanRoom']
}
};
this.badges = [];
this.claimedRewards = [];
+ this.givenRewards = [];
this.bossDefeats = 0;
const user = getCurrentUser();
localStorage.removeItem(`starEnergyData_${user}`);