const { PinyinContent } = require('../../models/pinyin'); /** * 获取拼音内容列表 * GET /api/pinyin/contents */ exports.getContents = async (req, res) => { try { const { type, isFree, page = 1, limit = 20 } = req.query; // 构建查询条件 const query = { status: 'active' }; if (type) query.type = type; if (isFree !== undefined) query.isFree = isFree === 'true'; // 分页 const skip = (parseInt(page) - 1) * parseInt(limit); // 查询数据 const contents = await PinyinContent.find(query) .select('-__v') .sort({ order: 1, symbol: 1 }) .skip(skip) .limit(parseInt(limit)); // 获取总数 const total = await PinyinContent.countDocuments(query); res.json({ code: 0, message: 'success', data: { list: contents, total, page: parseInt(page), limit: parseInt(limit), totalPages: Math.ceil(total / parseInt(limit)) } }); } catch (error) { console.error('获取拼音内容列表失败:', error); res.status(500).json({ code: 500, message: '获取拼音内容列表失败', error: error.message }); } }; /** * 获取单个拼音详情 * GET /api/pinyin/contents/:symbol */ exports.getContentBySymbol = async (req, res) => { try { const { symbol } = req.params; const content = await PinyinContent.findOne({ symbol: symbol.toLowerCase(), status: 'active' }).select('-__v'); if (!content) { return res.status(404).json({ code: 404, message: '拼音内容不存在' }); } res.json({ code: 0, message: 'success', data: content }); } catch (error) { console.error('获取拼音详情失败:', error); res.status(500).json({ code: 500, message: '获取拼音详情失败', error: error.message }); } }; /** * 获取拼音音频 * GET /api/pinyin/contents/:symbol/audio */ exports.getContentAudio = async (req, res) => { try { const { symbol } = req.params; const content = await PinyinContent.findOne({ symbol: symbol.toLowerCase(), status: 'active' }).select('symbol audioUrl name'); if (!content) { return res.status(404).json({ code: 404, message: '拼音内容不存在' }); } res.json({ code: 0, message: 'success', data: { symbol: content.symbol, audioUrl: content.audioUrl, name: content.name } }); } catch (error) { console.error('获取拼音音频失败:', error); res.status(500).json({ code: 500, message: '获取拼音音频失败', error: error.message }); } }; /** * 创建拼音内容(管理员) * POST /api/pinyin/contents */ exports.createContent = async (req, res) => { try { const contentData = req.body; // 检查是否已存在 const existing = await PinyinContent.findOne({ symbol: contentData.symbol }); if (existing) { return res.status(400).json({ code: 400, message: '该拼音内容已存在' }); } const content = new PinyinContent(contentData); await content.save(); res.status(201).json({ code: 0, message: '创建成功', data: content }); } catch (error) { console.error('创建拼音内容失败:', error); res.status(500).json({ code: 500, message: '创建拼音内容失败', error: error.message }); } }; /** * 更新拼音内容(管理员) * PUT /api/pinyin/contents/:id */ exports.updateContent = async (req, res) => { try { const { id } = req.params; const updateData = req.body; // 不允许修改symbol delete updateData.symbol; const content = await PinyinContent.findByIdAndUpdate( id, { $set: updateData }, { new: true, runValidators: true } ); if (!content) { return res.status(404).json({ code: 404, message: '拼音内容不存在' }); } res.json({ code: 0, message: '更新成功', data: content }); } catch (error) { console.error('更新拼音内容失败:', error); res.status(500).json({ code: 500, message: '更新拼音内容失败', error: error.message }); } }; /** * 删除拼音内容(管理员) * DELETE /api/pinyin/contents/:id */ exports.deleteContent = async (req, res) => { try { const { id } = req.params; const content = await PinyinContent.findByIdAndDelete(id); if (!content) { 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 }); } }; /** * 上传拼音音频 * POST /api/pinyin/contents/:symbol/audio */ exports.uploadAudio = async (req, res) => { try { const { symbol } = req.params; if (!req.file) { return res.status(400).json({ code: 400, message: '请上传音频文件' }); } // 构建文件URL(假设使用静态文件服务) const audioUrl = `/uploads/audio/${req.file.filename}`; // 更新拼音内容的音频URL const content = await PinyinContent.findOneAndUpdate( { symbol: symbol.toLowerCase() }, { $set: { audioUrl } }, { new: true } ); if (!content) { return res.status(404).json({ code: 404, message: '拼音内容不存在' }); } res.json({ code: 0, message: '音频上传成功', data: { audioUrl } }); } catch (error) { console.error('上传音频失败:', error); res.status(500).json({ code: 500, message: '上传音频失败', error: error.message }); } }; /** * 上传口型图 * POST /api/pinyin/contents/:symbol/mouth-image */ exports.uploadMouthImage = async (req, res) => { try { const { symbol } = req.params; if (!req.file) { return res.status(400).json({ code: 400, message: '请上传图片文件' }); } // 构建文件URL const mouthImage = `/uploads/images/${req.file.filename}`; // 更新拼音内容的口型图URL const content = await PinyinContent.findOneAndUpdate( { symbol: symbol.toLowerCase() }, { $set: { mouthImage } }, { new: true } ); if (!content) { return res.status(404).json({ code: 404, message: '拼音内容不存在' }); } res.json({ code: 0, message: '口型图上传成功', data: { mouthImage } }); } catch (error) { console.error('上传口型图失败:', error); res.status(500).json({ code: 500, message: '上传口型图失败', error: error.message }); } }; /** * 批量更新音频URL(从外部TTS服务) * POST /api/pinyin/contents/batch-update-audio */ exports.batchUpdateAudio = async (req, res) => { try { const { audioBaseUrl } = req.body; if (!audioBaseUrl) { return res.status(400).json({ code: 400, message: '请提供音频基础URL' }); } // 获取所有拼音内容 const contents = await PinyinContent.find({}); // 批量更新音频URL const updatePromises = contents.map(content => { const audioUrl = `${audioBaseUrl}/${content.symbol}.mp3`; return PinyinContent.findByIdAndUpdate(content._id, { $set: { audioUrl } }); }); await Promise.all(updatePromises); res.json({ code: 0, message: `成功更新 ${contents.length} 个拼音的音频URL`, data: { updatedCount: contents.length } }); } catch (error) { console.error('批量更新音频失败:', error); res.status(500).json({ code: 500, message: '批量更新音频失败', error: error.message }); } };