version 2
This commit is contained in:
@@ -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;
|
||||
};
|
||||
|
||||
// 打卡习惯
|
||||
|
||||
@@ -65,13 +65,38 @@
|
||||
<!-- 已兑换奖励 -->
|
||||
<div class="claimed-rewards" v-if="claimedRewards.length > 0">
|
||||
<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
|
||||
v-for="id in claimedRewards"
|
||||
:key="id"
|
||||
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>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/* 弹窗 */
|
||||
|
||||
@@ -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}`);
|
||||
|
||||
Reference in New Issue
Block a user