/** 控糖树等级配置(前后端算法需保持一致:每级 50 积分,最高 Lv.9) */ export const TREE_MAX_LEVEL = 9 export const TREE_XP_PER_LEVEL = 50 export const TREE_LEVELS = [ { level: 0, name: '种子眠', emoji: '🫘', mood: '困困', desc: '稳糖种子在土里打盹' }, { level: 1, name: '破土芽', emoji: '🌱', mood: '探头', desc: '探出第一抹新绿' }, { level: 2, name: '展两叶', emoji: '🌿', mood: '好奇', desc: '两片嫩叶迎风展' }, { level: 3, name: '小树苗', emoji: '🪴', mood: '精神', desc: '身子骨硬朗起来' }, { level: 4, name: '青枝繁', emoji: '🌳', mood: '茁壮', desc: '枝叶渐密,元气足' }, { level: 5, name: '拔节高', emoji: '🌲', mood: '挺拔', desc: '一节一节往上蹿' }, { level: 6, name: '稳糖冠', emoji: '💚', mood: '沉稳', desc: '树冠成形,习惯成自然' }, { level: 7, name: '初绽香', emoji: '🌸', mood: '开心', desc: '枝头冒出第一朵花' }, { level: 8, name: '漫开花', emoji: '🌺', mood: '灿烂', desc: '花开满枝,越记越稳' }, { level: 9, name: '圆满树', emoji: '🏆', mood: '荣耀', desc: '满级大树,习惯大师' } ] const WHISPERS_BY_LEVEL = { 0: ['种子在睡觉,记一笔就醒啦。', '今天浇第一滴水,芽就要冒出来。'], 1: ['破土啦!再坚持几天就长高。', '小芽最喜欢规律的记录了。'], 2: ['两片叶子为你鼓掌。', '空腹餐后都记全,我会长得更快。'], 3: ['我已经是一棵小树啦。', '家人点赞的时候,我也会发光。'], 4: ['枝叶越来越密,您真棒。', '连续记录,我会开出更多叶子。'], 5: ['拔节中!习惯比完美更重要。', '再浇一点水,我就更高啦。'], 6: ['习惯成自然,树冠成形啦。', '您今天的坚持,小树都记得。'], 7: ['开花啦!闻到春天的味道了吗?', '稳糖花只开给坚持的人。'], 8: ['满树花香,您已是控糖达人。', '明天继续来,花儿会更艳。'], 9: ['满级大树陪您一路稳糖。', '圆满不是终点,习惯才是。'] } export function calcTreeFromPoints(points) { const pts = Math.max(0, Number(points) || 0) const level = Math.min(TREE_MAX_LEVEL, Math.floor(pts / TREE_XP_PER_LEVEL)) const xpInLevel = level >= TREE_MAX_LEVEL ? TREE_XP_PER_LEVEL : pts % TREE_XP_PER_LEVEL const progress = level >= TREE_MAX_LEVEL ? 100 : Math.round((xpInLevel / TREE_XP_PER_LEVEL) * 100) const meta = TREE_LEVELS[level] || TREE_LEVELS[0] const nextMeta = level < TREE_MAX_LEVEL ? TREE_LEVELS[level + 1] : null const pointsToNext = level >= TREE_MAX_LEVEL ? 0 : TREE_XP_PER_LEVEL - xpInLevel return { level, progress, name: meta.name, emoji: meta.emoji, mood: meta.mood, desc: meta.desc, xpInLevel, xpNeed: TREE_XP_PER_LEVEL, pointsToNext, nextName: nextMeta?.name || '', isMax: level >= TREE_MAX_LEVEL } } export function pickTreeWhisper(level) { const lv = Math.min(TREE_MAX_LEVEL, Math.max(0, Number(level) || 0)) const list = WHISPERS_BY_LEVEL[lv] || WHISPERS_BY_LEVEL[0] return list[Math.floor(Math.random() * list.length)] }