const express = require('express'); const router = express.Router(); const bcrypt = require('bcryptjs'); const jwt = require('jsonwebtoken'); const auth = require('../middleware/auth'); const { upload, getFileUrls } = require('../middleware/upload'); const { Admin, Activity, Registration, Expense, Photo, Sponsor, Prize } = require('../models'); const fs = require('fs'); const path = require('path'); // 管理员登录 router.post('/login', async (req, res) => { try { const { username, password } = req.body; const admin = await Admin.findOne({ where: { username } }); if (!admin || !bcrypt.compareSync(password, admin.password)) { return res.status(401).json({ error: '用户名或密码错误' }); } const token = jwt.sign({ id: admin.id }, process.env.JWT_SECRET, { expiresIn: '7d' }); res.json({ token, admin: { id: admin.id, username: admin.username, name: admin.name } }); } catch (error) { res.status(500).json({ error: error.message }); } }); // 创建活动 router.post('/activities', auth, async (req, res) => { try { const activity = await Activity.create(req.body); res.json(activity); } catch (error) { res.status(500).json({ error: error.message }); } }); // 编辑活动 router.put('/activities/:id', auth, async (req, res) => { try { await Activity.update(req.body, { where: { id: req.params.id } }); const activity = await Activity.findByPk(req.params.id); res.json(activity); } catch (error) { res.status(500).json({ error: error.message }); } }); // 审核报名 router.put('/registrations/:id', auth, async (req, res) => { try { const { status, peopleCount } = req.body; const updateData = {}; if (status) updateData.status = status; if (peopleCount !== undefined) updateData.peopleCount = peopleCount; await Registration.update(updateData, { where: { id: req.params.id } }); const registration = await Registration.findByPk(req.params.id); res.json(registration); } catch (error) { res.status(500).json({ error: error.message }); } }); // 签到/取消签到 router.put('/registrations/:id/checkin', auth, async (req, res) => { try { const registration = await Registration.findByPk(req.params.id); if (!registration) { return res.status(404).json({ error: '报名信息不存在' }); } const newStatus = !registration.checkInStatus; await Registration.update({ checkInStatus: newStatus, checkInTime: newStatus ? new Date() : null }, { where: { id: req.params.id } }); const updated = await Registration.findByPk(req.params.id); res.json(updated); } catch (error) { res.status(500).json({ error: error.message }); } }); // 获取所有报名(含待审核) router.get('/registrations', auth, async (req, res) => { try { const { activityId } = req.query; const where = activityId ? { activityId } : {}; const registrations = await Registration.findAll({ where, order: [['createdAt', 'DESC']] }); res.json(registrations); } catch (error) { res.status(500).json({ error: error.message }); } }); // 上传经费明细 router.post('/expenses', auth, upload.array('media', 5), async (req, res) => { try { const { activityId, item, amount, category, note } = req.body; let receipt = null; let media = []; if (req.files && req.files.length > 0) { const uploaded = getFileUrls(req.files); media = uploaded.map(file => ({ url: file.url, type: file.mimetype.startsWith('video/') ? 'video' : 'image' })); } const expense = await Expense.create({ activityId, item, amount, category, receipt, note, media }); res.json(expense); } catch (error) { res.status(500).json({ error: error.message }); } }); // 获取经费列表 router.get('/expenses', auth, async (req, res) => { try { const { activityId } = req.query; const where = activityId ? { activityId } : {}; const expenses = await Expense.findAll({ where }); res.json(expenses); } catch (error) { res.status(500).json({ error: error.message }); } }); // 更新经费 router.put('/expenses/:id', auth, upload.array('media', 5), async (req, res) => { try { const { item, amount, category, note, existingMedia } = req.body; const updateData = { item, amount, category, note }; // 处理现有媒体 let media = []; if (existingMedia) { try { media = JSON.parse(existingMedia); } catch (e) { media = []; } } // 处理新上传的媒体 if (req.files && req.files.length > 0) { const uploaded = getFileUrls(req.files); const newMedia = uploaded.map(file => ({ url: file.url, type: file.mimetype.startsWith('video/') ? 'video' : 'image' })); media = [...media, ...newMedia].slice(0, 5); // 限制最多5个 } updateData.media = media; await Expense.update(updateData, { where: { id: req.params.id } }); const expense = await Expense.findByPk(req.params.id); res.json(expense); } catch (error) { res.status(500).json({ error: error.message }); } }); // 删除经费 router.delete('/expenses/:id', auth, async (req, res) => { try { await Expense.destroy({ where: { id: req.params.id } }); res.json({ message: '删除成功' }); } catch (error) { res.status(500).json({ error: error.message }); } }); // 上传活动照片 router.post('/photos', auth, upload.array('photos', 10), async (req, res) => { try { const { activityId } = req.body; const uploaded = getFileUrls(req.files); const photos = uploaded.map(file => ({ activityId, url: file.url, type: /\.(mp4|mov|avi)$/i.test(file.filename) ? 'video' : 'image', status: 'approved' })); const created = await Photo.bulkCreate(photos); res.json(created); } catch (error) { res.status(500).json({ error: error.message }); } }); // 获取待审核照片 router.get('/photos/pending', auth, async (req, res) => { try { const photos = await Photo.findAll({ where: { status: 'pending' }, order: [['createdAt', 'DESC']] }); res.json(photos); } catch (error) { res.status(500).json({ error: error.message }); } }); // 审核照片 router.put('/photos/:id', auth, async (req, res) => { try { const { status } = req.body; await Photo.update({ status }, { where: { id: req.params.id } }); const photo = await Photo.findByPk(req.params.id); res.json(photo); } catch (error) { res.status(500).json({ error: error.message }); } }); // 删除照片 router.delete('/photos/:id', auth, async (req, res) => { try { const photo = await Photo.findByPk(req.params.id); if (!photo) { return res.status(404).json({ error: '照片不存在' }); } // 删除本地文件 const filename = photo.url.split('/').pop(); const filePath = path.join(__dirname, '../uploads', filename); if (fs.existsSync(filePath)) { fs.unlinkSync(filePath); } // 从数据库删除记录 await photo.destroy(); res.json({ message: '删除成功' }); } catch (error) { res.status(500).json({ error: error.message }); } }); // 添加赞助商 router.post('/sponsors', auth, upload.single('logo'), async (req, res) => { try { const { activityId, name, type, link, sortOrder } = req.body; let logo = null; if (req.file) { const [uploaded] = getFileUrls(req.file); logo = uploaded.url; } const sponsor = await Sponsor.create({ activityId, name, logo, type, link, sortOrder: sortOrder || 0 }); res.json(sponsor); } catch (error) { res.status(500).json({ error: error.message }); } }); // 更新赞助商 router.put('/sponsors/:id', auth, upload.single('logo'), async (req, res) => { try { const { name, type, link, sortOrder } = req.body; const updateData = { name, type, link }; if (sortOrder !== undefined) { updateData.sortOrder = sortOrder; } if (req.file) { const [uploaded] = getFileUrls(req.file); updateData.logo = uploaded.url; } await Sponsor.update(updateData, { where: { id: req.params.id } }); const sponsor = await Sponsor.findByPk(req.params.id); res.json(sponsor); } catch (error) { res.status(500).json({ error: error.message }); } }); // 删除赞助商 router.delete('/sponsors/:id', auth, async (req, res) => { try { await Sponsor.destroy({ where: { id: req.params.id } }); res.json({ message: '删除成功' }); } catch (error) { res.status(500).json({ error: error.message }); } }); // 添加奖品 router.post('/prizes', auth, upload.single('image'), async (req, res) => { try { const { activityId, name, level, description, quantity, sortOrder } = req.body; let image = null; if (req.file) { const [uploaded] = getFileUrls([req.file]); image = uploaded.url; } const prize = await Prize.create({ activityId, name, level, description, image, quantity: quantity || 1, sortOrder: sortOrder || 0 }); res.json(prize); } catch (error) { res.status(500).json({ error: error.message }); } }); // 更新奖品 router.put('/prizes/:id', auth, upload.single('image'), async (req, res) => { try { const { name, level, description, quantity, sortOrder } = req.body; const updateData = { name, level, description, quantity, sortOrder }; if (req.file) { const [uploaded] = getFileUrls([req.file]); updateData.image = uploaded.url; } await Prize.update(updateData, { where: { id: req.params.id } }); const prize = await Prize.findByPk(req.params.id); res.json(prize); } catch (error) { res.status(500).json({ error: error.message }); } }); // 删除奖品 router.delete('/prizes/:id', auth, async (req, res) => { try { await Prize.destroy({ where: { id: req.params.id } }); res.json({ message: '删除成功' }); } catch (error) { res.status(500).json({ error: error.message }); } }); module.exports = router;