This commit is contained in:
Harry
2026-04-25 10:09:16 +08:00
committed by GitHub
commit bf215c4b9f
15 changed files with 2482 additions and 0 deletions

314
server.js Normal file
View File

@@ -0,0 +1,314 @@
/**
* 点名系统后端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`);
});