Skip to main content
Glama
admin.js11.8 kB
/** * 管理后台路由 - 系统配置和管理接口 * 提供系统管理、配置更新、监控等功能 */ import express from 'express'; import multer from 'multer'; import path from 'path'; import fs from 'fs/promises'; import { logger } from '../../utils/logger.js'; function createAdminRoutes(databaseManager, taskManager, configManager) { const router = express.Router(); const db = databaseManager; const config = configManager; // 文件上传配置 const upload = multer({ dest: 'temp/uploads/', limits: { fileSize: 10 * 1024 * 1024 }, // 10MB fileFilter: (req, file, cb) => { const allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'video/mp4']; if (allowedTypes.includes(file.mimetype)) { cb(null, true); } else { cb(new Error('不支持的文件类型')); } } }); /** * 获取系统配置 * GET /api/admin/config */ router.get('/config', async (req, res) => { try { const systemConfig = await config.getAll(); res.json({ success: true, data: systemConfig }); } catch (error) { logger.error('获取系统配置失败', error); res.status(500).json({ success: false, error: error.message }); } }); /** * 更新系统配置 * POST /api/admin/config */ router.post('/config', async (req, res) => { try { const updates = req.body; await config.update(updates); res.json({ success: true, message: '配置更新成功' }); } catch (error) { logger.error('更新系统配置失败', error); res.status(500).json({ success: false, error: error.message }); } }); /** * 批量导入代理 * POST /api/admin/proxies/import */ router.post('/proxies/import', async (req, res) => { try { const { proxies } = req.body; if (!Array.isArray(proxies)) { return res.status(400).json({ success: false, error: '代理数据格式错误' }); } const results = []; for (const proxy of proxies) { try { const [record, created] = await db.Proxy.findOrCreate({ where: { host: proxy.host, port: proxy.port }, defaults: proxy }); results.push({ proxy: `${proxy.host}:${proxy.port}`, created }); } catch (error) { results.push({ proxy: `${proxy.host}:${proxy.port}`, error: error.message }); } } res.json({ success: true, data: results }); } catch (error) { logger.error('导入代理失败', error); res.status(500).json({ success: false, error: error.message }); } }); /** * 批量导入指纹 * POST /api/admin/fingerprints/import */ router.post('/fingerprints/import', async (req, res) => { try { const { fingerprints } = req.body; if (!Array.isArray(fingerprints)) { return res.status(400).json({ success: false, error: '指纹数据格式错误' }); } const results = []; for (const fp of fingerprints) { try { const [record, created] = await db.Fingerprint.findOrCreate({ where: { fingerprint_id: fp.fingerprint_id }, defaults: fp }); results.push({ fingerprint_id: fp.fingerprint_id, created }); } catch (error) { results.push({ fingerprint_id: fp.fingerprint_id, error: error.message }); } } res.json({ success: true, data: results }); } catch (error) { logger.error('导入指纹失败', error); res.status(500).json({ success: false, error: error.message }); } }); /** * 创建新账号 * POST /api/admin/accounts */ router.post('/accounts', async (req, res) => { try { const { username, password, phone, email, nickname, proxy_id, fingerprint_id } = req.body; // 验证必填字段 if (!username) { return res.status(400).json({ success: false, error: '用户名不能为空' }); } // 检查用户名是否已存在 const existing = await db.Account.findOne({ where: { username } }); if (existing) { return res.status(400).json({ success: false, error: '用户名已存在' }); } const account = await db.Account.create({ username, password: password || null, phone, email, nickname, proxy_id, fingerprint_id, status: 'active', login_status: false }); res.json({ success: true, data: account }); } catch (error) { logger.error('创建账号失败', error); res.status(500).json({ success: false, error: error.message }); } }); /** * 更新账号信息 * PUT /api/admin/accounts/:id */ router.put('/accounts/:id', async (req, res) => { try { const { id } = req.params; const updates = req.body; const account = await db.Account.findByPk(id); if (!account) { return res.status(404).json({ success: false, error: '账号不存在' }); } // 不允许更新敏感字段 delete updates.cookies_encrypted; delete updates.session_data; await account.update(updates); res.json({ success: true, data: account }); } catch (error) { logger.error('更新账号失败', error); res.status(500).json({ success: false, error: error.message }); } }); /** * 删除账号 * DELETE /api/admin/accounts/:id */ router.delete('/accounts/:id', async (req, res) => { try { const { id } = req.params; const account = await db.Account.findByPk(id); if (!account) { return res.status(404).json({ success: false, error: '账号不存在' }); } await account.destroy(); res.json({ success: true, message: '账号删除成功' }); } catch (error) { logger.error('删除账号失败', error); res.status(500).json({ success: false, error: error.message }); } }); /** * 批量创建任务 * POST /api/admin/tasks/batch */ router.post('/tasks/batch', async (req, res) => { try { const { tasks } = req.body; if (!Array.isArray(tasks)) { return res.status(400).json({ success: false, error: '任务数据格式错误' }); } const results = []; for (const taskData of tasks) { try { const task = await taskManager.createTask(taskData); results.push({ task_id: task.id, success: true }); } catch (error) { results.push({ task_data: taskData, success: false, error: error.message }); } } res.json({ success: true, data: results }); } catch (error) { logger.error('批量创建任务失败', error); res.status(500).json({ success: false, error: error.message }); } }); /** * 取消任务 * DELETE /api/admin/tasks/:id */ router.delete('/tasks/:id', async (req, res) => { try { const { id } = req.params; const result = await taskManager.cancelTask(id); if (result.success) { res.json({ success: true, message: '任务取消成功' }); } else { res.status(400).json({ success: false, error: result.error }); } } catch (error) { logger.error('取消任务失败', error); res.status(500).json({ success: false, error: error.message }); } }); /** * 重新运行失败任务 * POST /api/admin/tasks/:id/retry */ router.post('/tasks/:id/retry', async (req, res) => { try { const { id } = req.params; const result = await taskManager.retryTask(id); if (result.success) { res.json({ success: true, message: '任务重试成功', data: result.task }); } else { res.status(400).json({ success: false, error: result.error }); } } catch (error) { logger.error('重试任务失败', error); res.status(500).json({ success: false, error: error.message }); } }); /** * 系统健康检查 * GET /api/admin/health */ router.get('/health', async (req, res) => { try { const health = { timestamp: new Date().toISOString(), database: await checkDatabaseHealth(), task_queue: await checkTaskQueueHealth(), memory: process.memoryUsage(), uptime: process.uptime(), version: require('../../../package.json').version }; res.json({ success: true, data: health }); } catch (error) { logger.error('健康检查失败', error); res.status(500).json({ success: false, error: error.message }); } }); /** * 获取系统日志 * GET /api/admin/logs */ router.get('/logs', async (req, res) => { try { const { level = 'info', limit = 100 } = req.query; const logFile = path.join(process.cwd(), 'logs', `${level}.log`); try { await fs.access(logFile); const content = await fs.readFile(logFile, 'utf8'); const lines = content.split('\n').filter(line => line.trim()).slice(-limit); res.json({ success: true, data: lines }); } catch (error) { res.json({ success: true, data: [] }); } } catch (error) { logger.error('获取日志失败', error); res.status(500).json({ success: false, error: error.message }); } }); /** * 清理系统日志 * DELETE /api/admin/logs */ router.delete('/logs', async (req, res) => { try { const { level } = req.query; const logDir = path.join(process.cwd(), 'logs'); if (level) { const logFile = path.join(logDir, `${level}.log`); await fs.writeFile(logFile, ''); } else { // 清理所有日志文件 const files = await fs.readdir(logDir); for (const file of files) { if (file.endsWith('.log')) { await fs.writeFile(path.join(logDir, file), ''); } } } res.json({ success: true, message: '日志清理成功' }); } catch (error) { logger.error('清理日志失败', error); res.status(500).json({ success: false, error: error.message }); } }); /** * 文件上传接口 * POST /api/admin/upload */ router.post('/upload', upload.single('file'), async (req, res) => { try { if (!req.file) { return res.status(400).json({ success: false, error: '未上传文件' }); } const { type = 'image' } = req.body; const uploadDir = path.join(process.cwd(), 'public', 'uploads', type); await fs.mkdir(uploadDir, { recursive: true }); const filename = `${Date.now()}-${req.file.originalname}`; const filePath = path.join(uploadDir, filename); await fs.rename(req.file.path, filePath); const url = `/uploads/${type}/${filename}`; res.json({ success: true, data: { url, filename, size: req.file.size } }); } catch (error) { logger.error('文件上传失败', error); res.status(500).json({ success: false, error: error.message }); } }); // 辅助函数 async function checkDatabaseHealth() { try { await db.sequelize.authenticate(); return { status: 'healthy', message: '数据库连接正常' }; } catch (error) { return { status: 'unhealthy', message: error.message }; } } async function checkTaskQueueHealth() { try { const stats = await taskManager.getTaskStats(); return { status: 'healthy', pending: stats.pending, running: stats.running, completed: stats.completed, failed: stats.failed }; } catch (error) { return { status: 'unhealthy', message: error.message }; } } return router; } export default createAdminRoutes;

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/billyangbc/xiaohongshu-mcp-nodejs'

If you have feedback or need assistance with the MCP directory API, please join our Discord server