stb/router/index.js
2024-11-07 14:21:20 +08:00

284 lines
7.7 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const db = require('../db/index')
const multer = require('multer')
const fs = require('fs')
const {
importQuestionsByFile
} = require('./stb')
const sanitizeInput = {
toPositiveInt: (value, defaultValue) => {
const num = parseInt(value)
return (num > 0) ? num : defaultValue
},
escapeSearch: (str) => {
if (!str) return ''
return str.replace(/[<>&"']/g, '')
}
}
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './uploads')
},
filename: function (req, file, cb) {
cb(null, Date.now() + '-' + file.originalname)
}
})
// 文件类型过滤
const fileFilter = (req, file, cb) => {
if (
file.mimetype === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' || // xlsx
file.mimetype === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' || // docx
file.mimetype === 'text/plain'
) {
cb(null, true)
} else {
cb(new Error('不支持的文件类型'), false)
}
}
const upload = multer({
storage: storage,
fileFilter: fileFilter
})
// 上传试卷
exports.uploadPaper = [
upload.single('file'),
async (req, res) => {
try {
if (!req.file) {
return res.json({
status: 1,
message: '请选择文件'
})
}
const filePath = req.file.path
await importQuestionsByFile(filePath)
fs.unlinkSync(filePath)
res.json({
status: 0,
message: '上传成功'
})
} catch (error) {
if (req.file && req.file.path) {
fs.unlinkSync(req.file.path)
}
res.json({
status: 1,
message: '上传失败',
error: error.message,
format: {
excel: "必须包含列:'题目', '选项A', '选项B', '选项C', '选项D', '答案'",
word: `格式示例:
题目1问题内容
A. 选项A内容
B. 选项B内容
C. 选项C内容
D. 选项D内容
答案A
题目2...`,
txt: `格式示:
<20><><EFBFBD>题内容
A. 选项A内容
B. 选项B内容
C. 选项C内容
D. 选项D内容
答案A
下一道题...`
}
})
}
}
]
// 获取试卷列表
exports.getList = async (req, res) => {
try {
const [papers] = await db.promise().query('SELECT * FROM paper');
const papersWithCount = papers.map(paper => ({
...paper,
topic_count: JSON.parse(paper.TopicsId || '[]').length
}));
res.json({ success: true, data: papersWithCount });
} catch (error) {
console.error('获取试卷列表失败:', error);
res.status(500).json({ success: false, message: '获取试卷列表失败' });
}
}
// 获取指定试卷的题目列表
exports.getPaperQuestions = async (req, res) => {
try {
const { paperId, page = 1, pageSize = 10 } = req.body;
if (!paperId) {
return res.status(400).json({ success: false, message: '无效的试卷ID' });
}
const sanitizedPaperId = sanitizeInput.toPositiveInt(paperId, 0);
const sanitizedPage = sanitizeInput.toPositiveInt(page, 1);
const sanitizedPageSize = sanitizeInput.toPositiveInt(pageSize, 10);
const limitedPageSize = Math.min(sanitizedPageSize, 100);
const offset = (sanitizedPage - 1) * limitedPageSize;
const [papers] = await db.promise().query('SELECT * FROM paper WHERE id = ?', [sanitizedPaperId]);
if (papers.length === 0) {
return res.status(404).json({ success: false, message: '试卷不存在' });
}
const topicIds = JSON.parse(papers[0].TopicsId || '[]');
const total = topicIds.length;
const pagedTopicIds = topicIds.slice(offset, offset + limitedPageSize);
if (pagedTopicIds.length === 0) {
return res.json({
success: true,
data: {
list: [],
pagination: {
current: sanitizedPage,
pageSize: limitedPageSize,
total
}
}
});
}
// 查询题目详情
const [topics] = await db.promise().query(
'SELECT * FROM topics WHERE id IN (?)',
[pagedTopicIds]
);
const orderedTopics = pagedTopicIds.map(id =>
topics.find(topic => topic.id === id)
).filter(Boolean);
res.json({
success: true,
data: {
list: orderedTopics,
pagination: {
current: sanitizedPage,
pageSize: limitedPageSize,
total
}
}
});
} catch (error) {
console.error('获取试卷题目失败:', error);
res.status(500).json({ success: false, message: '获取试卷题目失败' });
}
}
// 获取试卷详情
exports.getPaperDetail = async (req, res) => {
try {
console.log('Received body:', req.body);
if (!paperId) {
return res.status(400).json({ success: false, message: '无效的试卷ID' });
}
const sanitizedPaperId = sanitizeInput.toPositiveInt(paperId, 0);
const sanitizedPage = sanitizeInput.toPositiveInt(page, 1);
const sanitizedPageSize = sanitizeInput.toPositiveInt(pageSize, 10);
const limitedPageSize = Math.min(sanitizedPageSize, 100);
const offset = (sanitizedPage - 1) * limitedPageSize;
const [papers] = await db.promise().query('SELECT * FROM paper WHERE id = ?', [sanitizedPaperId]);
if (papers.length === 0) {
return res.status(404).json({ success: false, message: '试卷不存在' });
}
const topicIds = JSON.parse(papers[0].TopicsId || '[]');
const total = topicIds.length;
const pagedTopicIds = topicIds.slice(offset, offset + limitedPageSize);
let topics = [];
if (pagedTopicIds.length > 0) {
const [topicsResult] = await db.promise().query(
'SELECT * FROM topics WHERE id IN (?)',
[pagedTopicIds]
);
topics = pagedTopicIds.map(id =>
topicsResult.find(topic => topic.id === id)
).filter(Boolean);
}
res.json({
success: true,
data: {
...papers[0],
topics: {
list: topics,
pagination: {
current: sanitizedPage,
pageSize: limitedPageSize,
total
}
}
}
});
} catch (error) {
console.error('获取试卷详情失败:', error);
res.status(500).json({ success: false, message: '获取试卷详情失败' });
}
}
// 搜索题目
exports.searchTopics = async (req, res) => {
try {
let { keyword, page = 1, pageSize = 10 } = req.query;
keyword = sanitizeInput.escapeSearch(keyword);
if (!keyword) {
return res.status(400).json({ success: false, message: '请提供有效的搜索关键词' });
}
page = sanitizeInput.toPositiveInt(page, 1);
pageSize = Math.min(sanitizeInput.toPositiveInt(pageSize, 10), 100);
const offset = (page - 1) * pageSize;
const [countResult] = await db.promise().query(
'SELECT COUNT(*) as total FROM topics WHERE title LIKE ?',
[`%${keyword}%`]
);
const total = countResult[0].total;
const [topics] = await db.promise().query(
`SELECT t.*,
(SELECT title FROM paper WHERE JSON_CONTAINS(TopicsId, CAST(t.id AS JSON))) as paper_title
FROM topics t
WHERE t.title LIKE ?
LIMIT ?, ?`,
[`%${keyword}%`, offset, pageSize]
);
res.json({
success: true,
data: {
list: topics,
pagination: {
current: page,
pageSize,
total
}
}
});
} catch (error) {
console.error('搜索题目失败:', error);
res.status(500).json({ success: false, message: '搜索题目失败' });
}
}