/** * 点名系统后端API服务器 * 使用Node.js原生HTTP模块实现 */ const http = require('http'); const fs = require('fs'); const path = require('path'); const url = require('url'); // 数据存储(实际应用中应使用数据库) let rollCallLists = []; let rollCallRecords = []; // 从文件加载数据 function loadData() { try { const listsData = fs.readFileSync('data_lists.json', 'utf8'); rollCallLists = JSON.parse(listsData); } catch (e) { rollCallLists = []; } try { const recordsData = fs.readFileSync('data_records.json', 'utf8'); rollCallRecords = JSON.parse(recordsData); } catch (e) { rollCallRecords = []; } } // 保存数据到文件 function saveData() { fs.writeFileSync('data_lists.json', JSON.stringify(rollCallLists, null, 2)); fs.writeFileSync('data_records.json', JSON.stringify(rollCallRecords, null, 2)); } // 生成随机编号 function generateCode() { const length = Math.floor(Math.random() * 7) + 6; // 6-12位 let code = ''; for (let i = 0; i < length; i++) { code += Math.floor(Math.random() * 10); } return code; } // 创建HTTP服务器 const server = http.createServer((req, res) => { // 设置CORS头 res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); // 处理OPTIONS请求 if (req.method === 'OPTIONS') { res.writeHead(200); res.end(); return; } const parsedUrl = url.parse(req.url, true); const pathname = parsedUrl.pathname; // API路由 if (pathname.startsWith('/api/')) { handleAPI(req, res, pathname, parsedUrl.query); return; } // 静态文件服务 serveStatic(req, res, pathname); }); // 处理API请求 function handleAPI(req, res, pathname, query) { let body = ''; req.on('data', chunk => { body += chunk.toString(); }); req.on('end', () => { let data = {}; if (body) { try { data = JSON.parse(body); } catch (e) { sendError(res, '无效的JSON数据'); return; } } // 路由处理 switch (pathname) { case '/api/login': handleLogin(res, data); break; case '/api/create-list': handleCreateList(res, data); break; case '/api/get-lists': handleGetLists(res); break; case '/api/get-list': handleGetList(res, query); break; case '/api/update-list': handleUpdateList(res, data); break; case '/api/delete-list': handleDeleteList(res, data); break; case '/api/roll-call': handleRollCall(res, data); break; case '/api/get-records': handleGetRecords(res); break; default: sendError(res, '未知的API路径', 404); } }); } // 登录处理 function handleLogin(res, data) { const { username, password } = data; if (username === 'admin' && password === 'admin123') { sendSuccess(res, { token: 'admin-token-' + Date.now() }); } else { sendError(res, '用户名或密码错误', 401); } } // 创建点名名单 function handleCreateList(res, data) { const { name, members } = data; if (!name || !members || !Array.isArray(members)) { sendError(res, '参数错误'); return; } const newList = { id: Date.now(), name: name, code: generateCode(), members: members.map(memberName => ({ name: memberName, completed: false, timestamp: null })), createdAt: new Date().toLocaleString() }; rollCallLists.push(newList); saveData(); sendSuccess(res, newList); } // 获取所有名单 function handleGetLists(res) { sendSuccess(res, rollCallLists); } // 获取单个名单 function handleGetList(res, query) { const code = query.code; const list = rollCallLists.find(l => l.code === code); if (list) { sendSuccess(res, list); } else { sendError(res, '名单不存在', 404); } } // 更新名单 function handleUpdateList(res, data) { const { id, name, members } = data; const list = rollCallLists.find(l => l.id === id); if (!list) { sendError(res, '名单不存在', 404); return; } if (name) list.name = name; if (members && Array.isArray(members)) { list.members = members.map(memberName => { const existing = list.members.find(m => m.name === memberName); return existing || { name: memberName, completed: false, timestamp: null }; }); } saveData(); sendSuccess(res, list); } // 删除名单 function handleDeleteList(res, data) { const { id } = data; const index = rollCallLists.findIndex(l => l.id === id); if (index === -1) { sendError(res, '名单不存在', 404); return; } rollCallLists.splice(index, 1); saveData(); sendSuccess(res, { message: '删除成功' }); } // 点名 function handleRollCall(res, data) { const { code, name } = data; const list = rollCallLists.find(l => l.code === code); if (!list) { sendError(res, '名单不存在', 404); return; } const member = list.members.find(m => m.name === name); if (!member) { sendError(res, '成员不存在', 404); return; } if (member.completed) { sendError(res, '该成员已点名'); return; } member.completed = true; member.timestamp = new Date().toLocaleString(); // 添加记录 rollCallRecords.push({ name: name, listName: list.name, code: code, timestamp: member.timestamp }); saveData(); sendSuccess(res, { message: '点名成功', member: member }); } // 获取点名记录 function handleGetRecords(res) { sendSuccess(res, rollCallRecords); } // 静态文件服务 function serveStatic(req, res, pathname) { let filePath = pathname === '/' ? '/index.html' : pathname; filePath = path.join(__dirname, filePath); const extname = path.extname(filePath); const contentTypes = { '.html': 'text/html', '.js': 'text/javascript', '.css': 'text/css', '.json': 'application/json', '.png': 'image/png', '.jpg': 'image/jpeg', '.gif': 'image/gif' }; const contentType = contentTypes[extname] || 'text/plain'; fs.readFile(filePath, (err, content) => { if (err) { if (err.code === 'ENOENT') { res.writeHead(404); res.end('文件未找到'); } else { res.writeHead(500); res.end('服务器错误'); } } else { res.writeHead(200, { 'Content-Type': contentType }); res.end(content); } }); } // 发送成功响应 function sendSuccess(res, data) { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: true, data: data })); } // 发送错误响应 function sendError(res, message, code = 400) { res.writeHead(code, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: false, error: message })); } // 启动服务器 const PORT = 3000; loadData(); server.listen(PORT, () => { console.log(`点名系统服务器已启动`); console.log(`访问地址: http://localhost:${PORT}`); console.log(`后台管理: http://localhost:${PORT}/admin.html`); console.log(`用户点名: http://localhost:${PORT}/index.html`); });