version 2

This commit is contained in:
2026-03-02 07:02:25 +08:00
parent 0c220d3fe2
commit 6e3f63185d
3 changed files with 242 additions and 31 deletions

View File

@@ -158,7 +158,8 @@ const habits = {
noPickyEating: { name: '不挑食', icon: '🥦' }, noPickyEating: { name: '不挑食', icon: '🥦' },
washHands: { name: '勤洗手', icon: '🧼' }, washHands: { name: '勤洗手', icon: '🧼' },
homeworkFast: { name: '写作业快', icon: '📝' }, homeworkFast: { name: '写作业快', icon: '📝' },
earlySleep: { name: '早睡', icon: '🌙' } earlySleep: { name: '早睡', icon: '🌙' },
cleanRoom: { name: '打扫卫生', icon: '🧹' }
}; };
// 坏习惯数据 // 坏习惯数据
@@ -174,7 +175,7 @@ const monsters = {
boss: { boss: {
name: '坏习惯大魔王', name: '坏习惯大魔王',
health: 500, 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 isChecked = (habit: keyof typeof habitData.value) => {
const today = new Date().toISOString().split('T')[0]; const today = new Date().toISOString().split('T')[0];
return habitData.value[habit].lastChecked === today; return habitData.value[habit]?.lastChecked === today;
}; };
// 打卡习惯 // 打卡习惯

View File

@@ -65,13 +65,38 @@
<!-- 已兑换奖励 --> <!-- 已兑换奖励 -->
<div class="claimed-rewards" v-if="claimedRewards.length > 0"> <div class="claimed-rewards" v-if="claimedRewards.length > 0">
<h3 class="claimed-title">🎉 已兑换的奖励</h3> <h3 class="claimed-title">🎉 已兑换的奖励</h3>
<div class="reward-stats">
<div class="stat-item">
<span class="stat-label">已兑换:</span>
<span class="stat-value">{{ claimedRewards.length }} </span>
</div>
<div class="stat-item">
<span class="stat-label">已给孩子:</span>
<span class="stat-value">{{ givenRewards.length }} </span>
</div>
<div class="stat-item">
<span class="stat-label">待领取:</span>
<span class="stat-value">{{ claimedRewards.length - givenRewards.length }} </span>
</div>
</div>
<div class="claimed-grid"> <div class="claimed-grid">
<div <div
v-for="id in claimedRewards" v-for="id in claimedRewards"
:key="id" :key="id"
class="claimed-card" class="claimed-card"
:class="{ given: givenRewards.includes(id) }"
> >
{{ getRewardById(id)?.emoji }} {{ getRewardById(id)?.name }} <div class="claimed-content">
{{ getRewardById(id)?.emoji }} {{ getRewardById(id)?.name }}
</div>
<button
v-if="!givenRewards.includes(id)"
class="give-btn"
@click="markRewardAsGiven(id)"
>
已给孩子
</button>
<div v-else class="given-badge">已给孩子 </div>
</div> </div>
</div> </div>
</div> </div>
@@ -110,6 +135,9 @@ const currentCategory = ref('all');
// 已兑换奖励ID列表 // 已兑换奖励ID列表
const claimedRewards = computed(() => starEnergyStore.claimedRewards); const claimedRewards = computed(() => starEnergyStore.claimedRewards);
// 已给孩子的奖励ID列表
const givenRewards = computed(() => starEnergyStore.getGivenRewards || []);
// 弹窗状态 // 弹窗状态
const showSuccessModal = ref(false); const showSuccessModal = ref(false);
const showInsufficientModal = ref(false); const showInsufficientModal = ref(false);
@@ -166,7 +194,7 @@ const rewards = [
id: 'park_50', id: 'park_50',
name: '去公园玩', name: '去公园玩',
description: '可以和爸爸妈妈去公园玩!', description: '可以和爸爸妈妈去公园玩!',
cost: 50, cost: 100,
emoji: '🎡', emoji: '🎡',
category: 'activity' category: 'activity'
}, },
@@ -191,7 +219,7 @@ const rewards = [
id: 'zoo_100', id: 'zoo_100',
name: '去动物园', name: '去动物园',
description: '可以去动物园看小动物!', description: '可以去动物园看小动物!',
cost: 100, cost: 500,
emoji: '🦁', emoji: '🦁',
category: 'activity' category: 'activity'
}, },
@@ -200,7 +228,7 @@ const rewards = [
id: 'lego_200', id: 'lego_200',
name: '乐高积木套装', name: '乐高积木套装',
description: '可以获得一套乐高积木!', description: '可以获得一套乐高积木!',
cost: 200, cost: 400,
emoji: '🧱', emoji: '🧱',
category: 'toy' category: 'toy'
}, },
@@ -224,7 +252,7 @@ const rewards = [
id: 'amusement_200', id: 'amusement_200',
name: '游乐园一日游', name: '游乐园一日游',
description: '可以和爸爸妈妈去游乐园玩一整天!', description: '可以和爸爸妈妈去游乐园玩一整天!',
cost: 200, cost: 500,
emoji: '🎢', emoji: '🎢',
category: 'activity' category: 'activity'
}, },
@@ -232,7 +260,7 @@ const rewards = [
id: 'bike_200', id: 'bike_200',
name: '自行车一辆', name: '自行车一辆',
description: '可以获得一辆全新的自行车!', description: '可以获得一辆全新的自行车!',
cost: 200, cost: 1000,
emoji: '🚲', emoji: '🚲',
category: 'toy' category: 'toy'
}, },
@@ -250,7 +278,7 @@ const rewards = [
id: 'family_trip_500', id: 'family_trip_500',
name: '家庭旅行', name: '家庭旅行',
description: '可以和家人一起去旅行!', description: '可以和家人一起去旅行!',
cost: 500, cost: 1000,
emoji: '✈️', emoji: '✈️',
category: 'activity' category: 'activity'
}, },
@@ -258,7 +286,7 @@ const rewards = [
id: 'game_console_500', id: 'game_console_500',
name: '游戏机', name: '游戏机',
description: '可以获得一台游戏机!', description: '可以获得一台游戏机!',
cost: 500, cost: 2000,
emoji: '🎮', emoji: '🎮',
category: 'toy' category: 'toy'
}, },
@@ -372,7 +400,12 @@ const redeemReward = (reward: any) => {
// 根据ID获取奖励 // 根据ID获取奖励
const getRewardById = (id: string) => { 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; 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 { .claimed-grid {
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
gap: 15px; gap: 15px;
} }
@@ -677,6 +742,53 @@ const closeModal = () => {
color: white; color: white;
box-shadow: 0 4px 10px rgba(255, 215, 0, 0.4); box-shadow: 0 4px 10px rgba(255, 215, 0, 0.4);
animation: bounce 2s ease-in-out infinite; 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);
} }
/* 弹窗 */ /* 弹窗 */

View File

@@ -33,9 +33,45 @@ export const useStarEnergyStore = defineStore('starEnergy', {
// 尝试从 localStorage 加载保存的数据 // 尝试从 localStorage 加载保存的数据
const savedData = loadFromLocalStorage(); 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 { return {
// 星星能量总数 // 星星能量总数
total: savedData?.total || 20, total: typeof savedData?.total === 'number' ? savedData.total : 20,
// 各区域的星星能量 // 各区域的星星能量
areas: savedData?.areas || { areas: savedData?.areas || {
knowledge: 0, knowledge: 0,
@@ -45,59 +81,76 @@ export const useStarEnergyStore = defineStore('starEnergy', {
parent: 0 parent: 0
}, },
// 习惯打卡记录 // 习惯打卡记录
habits: savedData?.habits || { habits: {
brushTeeth: { brushTeeth: {
name: '刷牙', name: '刷牙',
count: 0, count: 0,
streak: 0, streak: 0,
lastChecked: null as string | null lastChecked: null as string | null,
...savedData?.habits?.brushTeeth
}, },
noBedLate: { noBedLate: {
name: '不赖床', name: '不赖床',
count: 0, count: 0,
streak: 0, streak: 0,
lastChecked: null as string | null lastChecked: null as string | null,
...savedData?.habits?.noBedLate
}, },
noPickyEating: { noPickyEating: {
name: '不挑食', name: '不挑食',
count: 0, count: 0,
streak: 0, streak: 0,
lastChecked: null as string | null lastChecked: null as string | null,
...savedData?.habits?.noPickyEating
}, },
washHands: { washHands: {
name: '勤洗手', name: '勤洗手',
count: 0, count: 0,
streak: 0, streak: 0,
lastChecked: null as string | null lastChecked: null as string | null,
...savedData?.habits?.washHands
}, },
homeworkFast: { homeworkFast: {
name: '写作业快', name: '写作业快',
count: 0, count: 0,
streak: 0, streak: 0,
lastChecked: null as string | null lastChecked: null as string | null,
...savedData?.habits?.homeworkFast
}, },
earlySleep: { earlySleep: {
name: '早睡', name: '早睡',
count: 0, count: 0,
streak: 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: { boss: {
name: '坏习惯大魔王', name: '坏习惯大魔王',
health: (savedData?.monsters && 'boss' in savedData.monsters && !savedData.monsters.boss.defeated) ? savedData.monsters.boss.health : 500, health: 500,
defeated: (savedData?.monsters && 'boss' in savedData.monsters) ? savedData.monsters.boss.defeated : false, defeated: false,
habits: ['brushTeeth', 'noBedLate', 'noPickyEating', 'washHands', 'homeworkFast', 'earlySleep'] 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次数 // 击败BOSS次数
bossDefeats: savedData?.bossDefeats || 0 bossDefeats: bossDefeats,
// 上次重置日期
lastResetDate: lastResetDate || today
}; };
}, },
@@ -120,6 +173,9 @@ export const useStarEnergyStore = defineStore('starEnergy', {
// 获取已兑换奖励 // 获取已兑换奖励
getClaimedRewards: (state) => state.claimedRewards, getClaimedRewards: (state) => state.claimedRewards,
// 获取已给孩子的奖励
getGivenRewards: (state) => state.givenRewards,
// 获取击败BOSS次数 // 获取击败BOSS次数
getBossDefeats: (state) => state.bossDefeats getBossDefeats: (state) => state.bossDefeats
}, },
@@ -133,7 +189,10 @@ export const useStarEnergyStore = defineStore('starEnergy', {
habits: this.habits, habits: this.habits,
monsters: this.monsters, monsters: this.monsters,
badges: this.badges, badges: this.badges,
claimedRewards: this.claimedRewards claimedRewards: this.claimedRewards,
givenRewards: this.givenRewards,
bossDefeats: this.bossDefeats,
lastResetDate: this.lastResetDate
}; };
saveToLocalStorage(data); saveToLocalStorage(data);
}, },
@@ -160,11 +219,19 @@ export const useStarEnergyStore = defineStore('starEnergy', {
const today = new Date().toISOString().split('T')[0]; const today = new Date().toISOString().split('T')[0];
const habitData = this.habits[habit]; const habitData = this.habits[habit];
// 检查习惯数据是否存在
if (!habitData) {
return;
}
// 防止重复打卡 // 防止重复打卡
if (habitData.lastChecked === today) { if (habitData.lastChecked === today) {
return; return;
} }
// 保存原来的lastChecked值用于连续打卡计算
const originalLastChecked = habitData.lastChecked;
// 更新打卡记录 // 更新打卡记录
habitData.count++; habitData.count++;
habitData.lastChecked = today; habitData.lastChecked = today;
@@ -174,7 +241,7 @@ export const useStarEnergyStore = defineStore('starEnergy', {
yesterday.setDate(yesterday.getDate() - 1); yesterday.setDate(yesterday.getDate() - 1);
const yesterdayStr = yesterday.toISOString().split('T')[0]; const yesterdayStr = yesterday.toISOString().split('T')[0];
if (habitData.lastChecked === yesterdayStr) { if (originalLastChecked === yesterdayStr) {
habitData.streak++; habitData.streak++;
} else { } else {
habitData.streak = 1; habitData.streak = 1;
@@ -187,6 +254,9 @@ export const useStarEnergyStore = defineStore('starEnergy', {
if (habitData.streak % 3 === 0) { if (habitData.streak % 3 === 0) {
this.addEnergy(5, 'habit'); this.addEnergy(5, 'habit');
} }
// 保存数据
this.$persist();
}, },
// 攻击怪兽 // 攻击怪兽
@@ -259,6 +329,27 @@ export const useStarEnergyStore = defineStore('starEnergy', {
return true; 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() { resetAll() {
this.total = 0; this.total = 0;
@@ -305,6 +396,12 @@ export const useStarEnergyStore = defineStore('starEnergy', {
count: 0, count: 0,
streak: 0, streak: 0,
lastChecked: null lastChecked: null
},
cleanRoom: {
name: '打扫卫生',
count: 0,
streak: 0,
lastChecked: null
} }
}; };
this.monsters = { this.monsters = {
@@ -312,11 +409,12 @@ export const useStarEnergyStore = defineStore('starEnergy', {
name: '坏习惯大魔王', name: '坏习惯大魔王',
health: 500, health: 500,
defeated: false, defeated: false,
habits: ['brushTeeth', 'noBedLate', 'noPickyEating', 'washHands', 'homeworkFast', 'earlySleep'] habits: ['brushTeeth', 'noBedLate', 'noPickyEating', 'washHands', 'homeworkFast', 'earlySleep', 'cleanRoom']
} }
}; };
this.badges = []; this.badges = [];
this.claimedRewards = []; this.claimedRewards = [];
this.givenRewards = [];
this.bossDefeats = 0; this.bossDefeats = 0;
const user = getCurrentUser(); const user = getCurrentUser();
localStorage.removeItem(`starEnergyData_${user}`); localStorage.removeItem(`starEnergyData_${user}`);