第一版提交,答题功能OK,题库管理待完善

This commit is contained in:
2025-12-18 19:07:21 +08:00
parent e5600535be
commit ba252b2f56
93 changed files with 20431 additions and 1 deletions

135
api/server.ts Normal file
View File

@@ -0,0 +1,135 @@
import express from 'express';
import cors from 'cors';
import path from 'path';
import { initDatabase } from './database';
import {
UserController,
QuestionController,
QuizController,
AdminController,
BackupController,
QuestionCategoryController,
ExamSubjectController,
ExamTaskController,
AdminUserController
} from './controllers';
import {
upload,
errorHandler,
adminAuth,
requestLogger,
responseFormatter
} from './middlewares';
const app = express();
const PORT = process.env.PORT || 3000;
// 中间件
app.use(cors());
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true, limit: '10mb' }));
app.use(requestLogger);
app.use(responseFormatter);
// API路由
const apiRouter = express.Router();
// 用户相关
apiRouter.post('/users', UserController.createUser);
apiRouter.get('/users/:id', UserController.getUser);
apiRouter.post('/users/validate', UserController.validateUserInfo);
// 题库管理
apiRouter.get('/questions', QuestionController.getQuestions);
apiRouter.get('/questions/:id', QuestionController.getQuestion);
apiRouter.post('/questions', adminAuth, QuestionController.createQuestion);
apiRouter.put('/questions/:id', adminAuth, QuestionController.updateQuestion);
apiRouter.delete('/questions/:id', adminAuth, QuestionController.deleteQuestion);
apiRouter.post('/questions/import', adminAuth, upload.single('file'), QuestionController.importQuestions);
apiRouter.get('/questions/export', adminAuth, QuestionController.exportQuestions);
// 为了兼容前端可能的错误请求,添加一个不包含 /api 前缀的路由
app.get('/questions/export', adminAuth, QuestionController.exportQuestions);
// 题目类别
apiRouter.get('/question-categories', QuestionCategoryController.getCategories);
apiRouter.post('/admin/question-categories', adminAuth, QuestionCategoryController.createCategory);
apiRouter.put('/admin/question-categories/:id', adminAuth, QuestionCategoryController.updateCategory);
apiRouter.delete('/admin/question-categories/:id', adminAuth, QuestionCategoryController.deleteCategory);
// 考试科目
apiRouter.get('/exam-subjects', ExamSubjectController.getSubjects);
apiRouter.get('/admin/subjects', adminAuth, ExamSubjectController.getSubjects);
apiRouter.post('/admin/subjects', adminAuth, ExamSubjectController.createSubject);
apiRouter.put('/admin/subjects/:id', adminAuth, ExamSubjectController.updateSubject);
apiRouter.delete('/admin/subjects/:id', adminAuth, ExamSubjectController.deleteSubject);
// 考试任务
apiRouter.get('/exam-tasks', ExamTaskController.getTasks);
apiRouter.get('/exam-tasks/user/:userId', ExamTaskController.getUserTasks);
apiRouter.post('/admin/tasks', adminAuth, ExamTaskController.createTask);
apiRouter.put('/admin/tasks/:id', adminAuth, ExamTaskController.updateTask);
apiRouter.delete('/admin/tasks/:id', adminAuth, ExamTaskController.deleteTask);
apiRouter.get('/admin/tasks/:id/report', adminAuth, ExamTaskController.getTaskReport);
// 用户管理
apiRouter.get('/admin/users', adminAuth, AdminUserController.getUsers);
apiRouter.delete('/admin/users', adminAuth, AdminUserController.deleteUser);
apiRouter.get('/admin/users/export', adminAuth, AdminUserController.exportUsers);
apiRouter.post('/admin/users/import', adminAuth, upload.single('file'), AdminUserController.importUsers);
apiRouter.get('/admin/users/:userId/records', adminAuth, AdminUserController.getUserRecords);
apiRouter.get('/admin/quiz/records/detail/:recordId', adminAuth, AdminUserController.getRecordDetail);
// 答题相关
apiRouter.post('/quiz/generate', QuizController.generateQuiz);
apiRouter.post('/quiz/submit', QuizController.submitQuiz);
apiRouter.get('/quiz/records/:userId', QuizController.getUserRecords);
apiRouter.get('/quiz/records/detail/:recordId', QuizController.getRecordDetail);
apiRouter.get('/quiz/records', adminAuth, QuizController.getAllRecords);
// 管理员相关
apiRouter.post('/admin/login', AdminController.login);
apiRouter.get('/admin/config', adminAuth, AdminController.getQuizConfig);
apiRouter.put('/admin/config', adminAuth, AdminController.updateQuizConfig);
apiRouter.get('/admin/statistics', adminAuth, AdminController.getStatistics);
apiRouter.put('/admin/password', adminAuth, AdminController.updatePassword);
apiRouter.get('/admin/configs', adminAuth, AdminController.getAllConfigs);
// 数据备份和恢复
apiRouter.get('/admin/export/users', adminAuth, BackupController.exportUsers);
apiRouter.get('/admin/export/questions', adminAuth, BackupController.exportQuestions);
apiRouter.get('/admin/export/records', adminAuth, BackupController.exportRecords);
apiRouter.get('/admin/export/answers', adminAuth, BackupController.exportAnswers);
apiRouter.post('/admin/restore', adminAuth, BackupController.restoreData);
// 应用API路由
app.use('/api', apiRouter);
// 静态文件服务
app.use(express.static(path.join(process.cwd(), 'dist')));
// 前端路由SPA支持
app.get('*', (req, res) => {
res.sendFile(path.join(process.cwd(), 'dist', 'index.html'));
});
// 错误处理
app.use(errorHandler);
// 启动服务器
async function startServer() {
try {
await initDatabase();
console.log('数据库初始化完成');
app.listen(PORT, () => {
console.log(`服务器运行在端口 ${PORT}`);
console.log(`API文档: http://localhost:${PORT}/api`);
});
} catch (error) {
console.error('启动服务器失败:', error);
process.exit(1);
}
}
startServer();