🎉 feat: initialize 宇之然AI维度 project
- uni-app Vue3 frontend with dark glassmorphism theme - 5 AI dimensions: Origin / Development / Current / Learning / Trend - AI Chat system prompt updated from geometry to AI - 23 AI knowledge articles initialized in DB - Trend API + cron job for daily news - Product pricing (Pro ¥19.9, VIP ¥39.9) - Pinia stores + API utilities - AGENTS.md documentation
This commit is contained in:
@@ -0,0 +1,288 @@
|
||||
const { PinyinAchievement, PinyinProgress } = require('../../models/pinyin');
|
||||
|
||||
/**
|
||||
* 获取成就列表
|
||||
* GET /api/pinyin/achievements
|
||||
*/
|
||||
exports.getAchievements = async (req, res) => {
|
||||
try {
|
||||
const { type } = req.query;
|
||||
|
||||
const query = { isActive: true };
|
||||
if (type) query.type = type;
|
||||
|
||||
const achievements = await PinyinAchievement.find(query)
|
||||
.sort({ order: 1, createdAt: 1 })
|
||||
.select('-__v');
|
||||
|
||||
res.json({
|
||||
code: 0,
|
||||
message: 'success',
|
||||
data: {
|
||||
list: achievements
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取成就列表失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '获取成就列表失败',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取用户已获得的成就
|
||||
* GET /api/pinyin/achievements/my
|
||||
*/
|
||||
exports.getMyAchievements = async (req, res) => {
|
||||
try {
|
||||
const userId = req.user._id;
|
||||
|
||||
const progress = await PinyinProgress.findOne({ userId });
|
||||
|
||||
if (!progress || !progress.achievements || progress.achievements.length === 0) {
|
||||
return res.json({
|
||||
code: 0,
|
||||
message: 'success',
|
||||
data: {
|
||||
total: 0,
|
||||
list: []
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 获取成就详情
|
||||
const achievementCodes = progress.achievements.map(a => a.code);
|
||||
const achievements = await PinyinAchievement.find({
|
||||
code: { $in: achievementCodes }
|
||||
}).select('-__v');
|
||||
|
||||
// 合并获得时间
|
||||
const achievementsWithTime = achievements.map(ach => {
|
||||
const userAch = progress.achievements.find(a => a.code === ach.code);
|
||||
return {
|
||||
...ach.toObject(),
|
||||
obtainedAt: userAch ? userAch.obtainedAt : null
|
||||
};
|
||||
});
|
||||
|
||||
res.json({
|
||||
code: 0,
|
||||
message: 'success',
|
||||
data: {
|
||||
total: achievementsWithTime.length,
|
||||
list: achievementsWithTime
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取用户成就失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '获取用户成就失败',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 检查成就达成
|
||||
* POST /api/pinyin/achievements/check
|
||||
*/
|
||||
exports.checkAchievements = async (req, res) => {
|
||||
try {
|
||||
const userId = req.user._id;
|
||||
|
||||
const progress = await PinyinProgress.findOne({ userId });
|
||||
if (!progress) {
|
||||
return res.json({
|
||||
code: 0,
|
||||
message: 'success',
|
||||
data: {
|
||||
newAchievements: []
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 获取所有启用的成就
|
||||
const achievements = await PinyinAchievement.find({ isActive: true });
|
||||
|
||||
const newAchievements = [];
|
||||
|
||||
for (const achievement of achievements) {
|
||||
// 检查是否已获得
|
||||
if (progress.achievements.some(a => a.code === achievement.code)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查条件
|
||||
const isAchieved = checkCondition(progress, achievement.condition);
|
||||
|
||||
if (isAchieved) {
|
||||
progress.achievements.push({
|
||||
code: achievement.code,
|
||||
obtainedAt: new Date()
|
||||
});
|
||||
|
||||
newAchievements.push({
|
||||
code: achievement.code,
|
||||
name: achievement.name,
|
||||
description: achievement.description,
|
||||
icon: achievement.icon,
|
||||
reward: achievement.reward
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (newAchievements.length > 0) {
|
||||
await progress.save();
|
||||
}
|
||||
|
||||
res.json({
|
||||
code: 0,
|
||||
message: 'success',
|
||||
data: {
|
||||
newAchievements
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('检查成就失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '检查成就失败',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建成就(管理员)
|
||||
* POST /api/pinyin/achievements
|
||||
*/
|
||||
exports.createAchievement = async (req, res) => {
|
||||
try {
|
||||
const achievementData = req.body;
|
||||
|
||||
// 检查code是否已存在
|
||||
const existing = await PinyinAchievement.findOne({ code: achievementData.code });
|
||||
if (existing) {
|
||||
return res.status(400).json({
|
||||
code: 400,
|
||||
message: '该成就代码已存在'
|
||||
});
|
||||
}
|
||||
|
||||
const achievement = new PinyinAchievement(achievementData);
|
||||
await achievement.save();
|
||||
|
||||
res.status(201).json({
|
||||
code: 0,
|
||||
message: '创建成功',
|
||||
data: achievement
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('创建成就失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '创建成就失败',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 更新成就(管理员)
|
||||
* PUT /api/pinyin/achievements/:id
|
||||
*/
|
||||
exports.updateAchievement = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const updateData = req.body;
|
||||
|
||||
// 不允许修改code
|
||||
delete updateData.code;
|
||||
|
||||
const achievement = await PinyinAchievement.findByIdAndUpdate(
|
||||
id,
|
||||
{ $set: updateData },
|
||||
{ new: true, runValidators: true }
|
||||
);
|
||||
|
||||
if (!achievement) {
|
||||
return res.status(404).json({
|
||||
code: 404,
|
||||
message: '成就不存在'
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
code: 0,
|
||||
message: '更新成功',
|
||||
data: achievement
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('更新成就失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '更新成就失败',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除成就(管理员)
|
||||
* DELETE /api/pinyin/achievements/:id
|
||||
*/
|
||||
exports.deleteAchievement = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
const achievement = await PinyinAchievement.findByIdAndDelete(id);
|
||||
|
||||
if (!achievement) {
|
||||
return res.status(404).json({
|
||||
code: 404,
|
||||
message: '成就不存在'
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
code: 0,
|
||||
message: '删除成功'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('删除成就失败:', error);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '删除成就失败',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 检查成就条件
|
||||
* @param {Object} progress - 用户进度
|
||||
* @param {Object} condition - 条件
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
function checkCondition(progress, condition) {
|
||||
switch (condition.type) {
|
||||
case 'explore_count':
|
||||
return progress.totalExplored >= condition.value;
|
||||
|
||||
case 'collect_count':
|
||||
return progress.totalStones >= condition.value;
|
||||
|
||||
case 'streak_days':
|
||||
return progress.streakDays >= condition.value;
|
||||
|
||||
case 'complete_symbol':
|
||||
return progress.isSymbolCompleted(condition.symbol);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user