import { Router, Request, Response } from 'express'; import { getDb } from '../db'; import { authMiddleware, AuthRequest } from '../middleware/auth'; const router = Router(); router.get('/', (req: Request, res: Response) => { const db = getDb(); const list = db.prepareCompat(` SELECT a.*, GROUP_CONCAT(g.name) AS groups_name, GROUP_CONCAT(g.id) AS groups_id FROM activities a LEFT JOIN activity_groups ag ON a.id = ag.activity_id LEFT JOIN work_groups g ON ag.group_id = g.id GROUP BY a.id ORDER BY a.start_time DESC `).all().map((item: any) => ({ ...item, groups: (item.groups_id ? String(item.groups_id).split(',').map(Number) : []), groups_name_list: (item.groups_name ? String(item.groups_name).split(',') : []), })); res.json(list); }); router.get('/:id', (req: Request, res: Response) => { const id = Number(req.params.id); const db = getDb(); const act = db.prepareCompat('SELECT * FROM activities WHERE id = ?').get(id) as any; if (!act) return res.status(404).json({ error: '活动不存在' }); const groups = db.prepareCompat(` SELECT g.id, g.name FROM activity_groups ag JOIN work_groups g ON ag.group_id = g.id WHERE ag.activity_id = ? `).all(id); res.json({ ...act, groups: groups.map((g: any) => g.id), groups_name_list: groups.map((g: any) => g.name) }); }); router.post('/', authMiddleware, (req: AuthRequest, res: Response) => { const { title, content, start_time, end_time, groups } = req.body || {}; if (!title || !String(title).trim()) return res.status(400).json({ error: '活动标题不能为空' }); if (!start_time || !end_time) return res.status(400).json({ error: '活动时间不能为空' }); const db = getDb(); try { db.execCompat('BEGIN'); const info = db.prepareCompat('INSERT INTO activities (title, content, start_time, end_time) VALUES (?,?,?,?)') .run(String(title).trim(), content || '', start_time, end_time); const activityId = Number(info.lastInsertRowid); const insertAG = db.prepareCompat('INSERT OR IGNORE INTO activity_groups (activity_id, group_id) VALUES (?,?)'); if (Array.isArray(groups)) { for (const gid of groups) insertAG.run(activityId, Number(gid)); } db.execCompat('COMMIT'); db.save(); res.json({ id: activityId }); } catch (e: any) { try { db.execCompat('ROLLBACK'); } catch {} res.status(500).json({ error: e.message }); } }); router.put('/:id', authMiddleware, (req: AuthRequest, res: Response) => { const id = Number(req.params.id); const { title, content, start_time, end_time, groups } = req.body || {}; if (!title || !String(title).trim()) return res.status(400).json({ error: '活动标题不能为空' }); if (!start_time || !end_time) return res.status(400).json({ error: '活动时间不能为空' }); const db = getDb(); try { db.execCompat('BEGIN'); db.prepareCompat('UPDATE activities SET title=?, content=?, start_time=?, end_time=? WHERE id=?') .run(String(title).trim(), content || '', start_time, end_time, id); db.prepareCompat('DELETE FROM activity_groups WHERE activity_id = ?').run(id); const insertAG = db.prepareCompat('INSERT OR IGNORE INTO activity_groups (activity_id, group_id) VALUES (?,?)'); if (Array.isArray(groups)) { for (const gid of groups) insertAG.run(id, Number(gid)); } db.execCompat('COMMIT'); db.save(); res.json({ ok: true }); } catch (e: any) { try { db.execCompat('ROLLBACK'); } catch {} res.status(500).json({ error: e.message }); } }); router.delete('/:id', authMiddleware, (req: AuthRequest, res: Response) => { const id = Number(req.params.id); const db = getDb(); db.prepareCompat('DELETE FROM activities WHERE id = ?').run(id); db.save(); res.json({ ok: true }); }); router.get('/:id/participants', (req: Request, res: Response) => { const id = Number(req.params.id); const db = getDb(); const act = db.prepareCompat('SELECT * FROM activities WHERE id = ?').get(id); if (!act) return res.status(404).json({ error: '活动不存在' }); const groupIds = db.prepareCompat('SELECT group_id FROM activity_groups WHERE activity_id = ?').all(id).map((r: any) => r.group_id); let users: any[]; if (groupIds.length === 0) { users = db.prepareCompat(` SELECT u.id, u.class, u.name, u.volunteer_no, g.name AS group_name FROM users u LEFT JOIN work_groups g ON u.group_id = g.id ORDER BY u.class, u.name `).all(); } else { const ph = groupIds.map(() => '?').join(','); users = db.prepareCompat(` SELECT u.id, u.class, u.name, u.volunteer_no, g.name AS group_name FROM users u LEFT JOIN work_groups g ON u.group_id = g.id WHERE u.group_id IN (${ph}) OR u.group_id IS NULL ORDER BY u.class, u.name `).all(...groupIds); } const hoursRows = db.prepareCompat('SELECT * FROM hours WHERE activity_id = ?').all(id); const hoursMap: Record = {}; for (const h of hoursRows) hoursMap[(h as any).user_id] = h; const list = users.map((u: any) => ({ ...u, hours: hoursMap[u.id]?.hours ?? 0, remark: hoursMap[u.id]?.remark ?? '', hours_id: hoursMap[u.id]?.id ?? null, })); res.json({ activity: act, list }); }); export default router;