feat: system logs - email log + system log with admin UI
- db: email_logs (sent/failed) + system_logs (info/warn/error) tables, auto-migrated for existing installs - backend/logger.js: logEmail/logSystem with try/catch (never breaks flow) - mailer: log send result (SMTP unconfigured/sent/failed + error msg) - webhook: log blocked-internal, non-2xx response, send failure - server: error middleware records 500 errors to system_logs - routes/logs.js: GET /logs/emails + /logs/system (admin/owner, filters) - UI: 系统日志 page (owner/admin) with system/email tabs + filters - API docs updated
This commit is contained in:
37
backend/routes/logs.js
Normal file
37
backend/routes/logs.js
Normal file
@@ -0,0 +1,37 @@
|
||||
const express = require('express');
|
||||
const { query } = require('../db');
|
||||
const { authenticate, requireRole } = require('../middleware/auth');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// ---- 邮件日志(admin/owner 可查) ----
|
||||
router.get('/emails', authenticate, requireRole('owner', 'admin'), async (req, res) => {
|
||||
try {
|
||||
const { status, email, limit } = req.query;
|
||||
let q = 'SELECT * FROM email_logs WHERE 1=1';
|
||||
const p = [];
|
||||
if (status === 'sent' || status === 'failed') { q += ' AND status = ?'; p.push(status); }
|
||||
if (email) { q += ' AND to_email LIKE ?'; p.push(`%${email}%`); }
|
||||
q += ' ORDER BY id DESC LIMIT ?';
|
||||
p.push(Math.min(parseInt(limit) || 100, 500));
|
||||
const rows = await query(q, p);
|
||||
res.json(rows);
|
||||
} catch (e) { res.status(500).json({ error: e.message }); }
|
||||
});
|
||||
|
||||
// ---- 系统日志(admin/owner 可查) ----
|
||||
router.get('/system', authenticate, requireRole('owner', 'admin'), async (req, res) => {
|
||||
try {
|
||||
const { level, source, limit } = req.query;
|
||||
let q = 'SELECT * FROM system_logs WHERE 1=1';
|
||||
const p = [];
|
||||
if (['info', 'warn', 'error'].includes(level)) { q += ' AND level = ?'; p.push(level); }
|
||||
if (source) { q += ' AND source LIKE ?'; p.push(`%${source}%`); }
|
||||
q += ' ORDER BY id DESC LIMIT ?';
|
||||
p.push(Math.min(parseInt(limit) || 100, 500));
|
||||
const rows = await query(q, p);
|
||||
res.json(rows);
|
||||
} catch (e) { res.status(500).json({ error: e.message }); }
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user