fix(pet): человекочитаемые подписи в ленте XP питомца
Лента «последних начислений» печатала сырые коды причин из xp_log (achievement:cr_5_lessons, tb:math-6-ch1-ach-start, lesson_complete). Добавлен резолвер _xpReasonLabel: achievement:<slug> -> «Достижение «<title>»» через ACHIEVEMENT_DEFS, tb:* -> «Учебник», недостающие фиксированные причины (lesson_complete/daily_goal/daily_activity/ lab_experiment), сохранение уже-читаемых фраз, фолбэк «Награда». Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,36 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
const db = require('../db/db');
|
const db = require('../db/db');
|
||||||
const { awardCoins } = require('./gamificationController');
|
const { awardCoins } = require('./gamificationController');
|
||||||
|
const { ACHIEVEMENT_DEFS } = require('./gamification/_shared');
|
||||||
|
|
||||||
|
/* ── XP-log reason → человекочитаемый ярлык для ленты активности питомца ──
|
||||||
|
Сырые коды причин (`achievement:slug`, `tb:...`, `lesson_complete`, …)
|
||||||
|
не должны попадать в UID — резолвим их в понятные подписи. */
|
||||||
|
const SOURCE_LABELS = {
|
||||||
|
hangman_win: 'Виселица', crossword_win: 'Кроссворд',
|
||||||
|
test_answer: 'Тест', challenge: 'Задание',
|
||||||
|
lab_activity: 'Лаборатория', lab_experiment: 'Лаборатория',
|
||||||
|
assignment: 'Домашнее задание',
|
||||||
|
pet_petting: 'Поглаживание', pet_feeding: 'Кормёжка питомца',
|
||||||
|
mood_ecstatic: 'Бонус настроения', correct_answers: 'Тест',
|
||||||
|
test_complete: 'Тест', 'test_90+': 'Тест 90%+', test_perfect: 'Тест 100%',
|
||||||
|
daily_activity: 'Активность дня', daily_goal: 'Цель дня',
|
||||||
|
lesson_complete: 'Урок пройден',
|
||||||
|
};
|
||||||
|
const _ACH_TITLE = new Map(ACHIEVEMENT_DEFS.map(a => [a.slug, a.title]));
|
||||||
|
|
||||||
|
function _xpReasonLabel(reason) {
|
||||||
|
if (!reason) return 'Награда';
|
||||||
|
if (reason.startsWith('achievement:')) {
|
||||||
|
const t = _ACH_TITLE.get(reason.slice('achievement:'.length));
|
||||||
|
return t ? `Достижение «${t}»` : 'Достижение';
|
||||||
|
}
|
||||||
|
if (reason.startsWith('tb:')) return 'Учебник';
|
||||||
|
if (SOURCE_LABELS[reason]) return SOURCE_LABELS[reason];
|
||||||
|
// Уже читаемая фраза (например «Испытание: …») — содержит пробел/кириллицу.
|
||||||
|
if (/[А-Яа-яЁё ]/.test(reason)) return reason;
|
||||||
|
return 'Награда';
|
||||||
|
}
|
||||||
|
|
||||||
const BG_SHOP = [
|
const BG_SHOP = [
|
||||||
{ id:'space', name:'Космос', price:50, desc:'Звёздный простор' },
|
{ id:'space', name:'Космос', price:50, desc:'Звёздный простор' },
|
||||||
@@ -115,19 +145,11 @@ function getPet(req, res) {
|
|||||||
weeklyXP.push({ day: d.toLocaleDateString('ru', { weekday: 'short' }), xp: weekMap.get(dateStr) || 0 });
|
weeklyXP.push({ day: d.toLocaleDateString('ru', { weekday: 'short' }), xp: weekMap.get(dateStr) || 0 });
|
||||||
}
|
}
|
||||||
|
|
||||||
const SOURCE_LABELS = {
|
|
||||||
hangman_win: 'Виселица', crossword_win: 'Кроссворд',
|
|
||||||
test_answer: 'Тест', challenge: 'Задание',
|
|
||||||
lab_activity: 'Лаборатория', assignment: 'Домашнее задание',
|
|
||||||
pet_petting: 'Поглаживание', pet_feeding: 'Кормёжка питомца',
|
|
||||||
mood_ecstatic: 'Бонус настроения', correct_answers: 'Тест',
|
|
||||||
test_complete: 'Тест', 'test_90+': 'Тест 90%+', test_perfect: 'Тест 100%',
|
|
||||||
};
|
|
||||||
const rawActivity = db.prepare(
|
const rawActivity = db.prepare(
|
||||||
"SELECT amount, reason, created_at FROM xp_log WHERE user_id = ? ORDER BY created_at DESC LIMIT 6"
|
"SELECT amount, reason, created_at FROM xp_log WHERE user_id = ? ORDER BY created_at DESC LIMIT 6"
|
||||||
).all(req.user.id);
|
).all(req.user.id);
|
||||||
const recentActivity = rawActivity.map(r => ({
|
const recentActivity = rawActivity.map(r => ({
|
||||||
xp: r.amount, label: SOURCE_LABELS[r.reason] || r.reason, at: r.created_at,
|
xp: r.amount, label: _xpReasonLabel(r.reason), at: r.created_at,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const pettingCooldown = user.pet_last_petted
|
const pettingCooldown = user.pet_last_petted
|
||||||
|
|||||||
Reference in New Issue
Block a user