feat: 初始化义工时长管理系统
- 管理台:活动设置、时长登记、用户管理、数据导出(Excel/PNG) - 用户端:姓名查询个人义工时长与活动记录 - 技术栈:React + Vite + TailwindCSS / Node.js + Express + sql.js (SQLite) - 支持 Docker 部署,附带 Gitea Actions 自动部署工作流 - 响应式界面,兼容移动端与 PC 端 - 默认管理员账号:admin / admin123
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
import { Router } from 'express';
|
||||
import { getDb } from '../db';
|
||||
import { authMiddleware, AuthRequest } from '../middleware/auth';
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.post('/', authMiddleware, (req: AuthRequest, res) => {
|
||||
const { include_users, include_activities, include_hours, include_user_totals, include_user_activities } = req.body || {};
|
||||
const db = getDb();
|
||||
const result: any = {};
|
||||
|
||||
if (include_users) {
|
||||
result.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();
|
||||
}
|
||||
if (include_activities) {
|
||||
result.activities = db.prepareCompat(`
|
||||
SELECT a.*, GROUP_CONCAT(g.name) AS groups_name
|
||||
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();
|
||||
}
|
||||
if (include_hours) {
|
||||
result.hours = db.prepareCompat(`
|
||||
SELECT h.hours, h.remark, h.created_at,
|
||||
a.title AS activity_title, a.start_time, a.end_time,
|
||||
u.class, u.name, u.volunteer_no, g.name AS group_name
|
||||
FROM hours h
|
||||
JOIN activities a ON h.activity_id = a.id
|
||||
JOIN users u ON h.user_id = u.id
|
||||
LEFT JOIN work_groups g ON u.group_id = g.id
|
||||
ORDER BY a.start_time DESC, u.class, u.name
|
||||
`).all();
|
||||
}
|
||||
if (include_user_totals) {
|
||||
result.user_totals = db.prepareCompat(`
|
||||
SELECT u.id, u.class, u.name, u.volunteer_no, g.name AS group_name,
|
||||
COALESCE(SUM(h.hours), 0) AS total_hours,
|
||||
COUNT(DISTINCT h.activity_id) AS activity_count
|
||||
FROM users u
|
||||
LEFT JOIN work_groups g ON u.group_id = g.id
|
||||
LEFT JOIN hours h ON h.user_id = u.id
|
||||
GROUP BY u.id
|
||||
ORDER BY total_hours DESC, u.class, u.name
|
||||
`).all();
|
||||
}
|
||||
if (include_user_activities) {
|
||||
const 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() as any[];
|
||||
result.user_activities = users.map((u) => {
|
||||
const acts = db.prepareCompat(`
|
||||
SELECT a.title, a.start_time, a.end_time, h.hours, h.remark
|
||||
FROM hours h JOIN activities a ON h.activity_id = a.id
|
||||
WHERE h.user_id = ? ORDER BY a.start_time DESC
|
||||
`).all(u.id);
|
||||
return { ...u, activities: acts };
|
||||
});
|
||||
}
|
||||
res.json(result);
|
||||
});
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user