Files
Web_BLV_OA_Exam_Prod/api/controllers/backupController.ts
XuJiacheng eb4504960e feat: 更新构建流程,添加 API 构建脚本和 SQL 文件复制脚本
- 修改 package.json,更新构建命令,添加 postbuild 脚本以复制 init.sql 文件。
- 新增 scripts/build-api.mjs,使用 esbuild 构建 API 代码。
- 新增 scripts/copy-init-sql.mjs,复制数据库初始化 SQL 文件到构建输出目录。
- 在 SubjectSelectionPage 组件中添加 totalScore 属性,增加历史最高分状态显示功能。
- 在 ExamSubjectPage 和 QuestionManagePage 中优化判断题答案处理逻辑。
- 在 OptionList 组件中将判断题选项文本从 'T' 和 'F' 改为 '对' 和 '错'。
- 在 QuizFooter 组件中调整样式,增加按钮和文本的可读性。
- 新增用户默认组测试用例,验证新用户创建后自动加入“全体用户”系统组。
- 新增 tsconfig.api.json,配置 API 相关 TypeScript 编译选项。
- 移除 vite.config.ts 中的 global 定义。
2025-12-30 20:33:14 +08:00

177 lines
5.0 KiB
TypeScript

import { Request, Response } from 'express';
import * as XLSX from 'xlsx';
import { UserModel, QuestionModel, QuizModel, UserGroupModel } from '../models';
export class BackupController {
// 导出用户数据
static async exportUsers(req: Request, res: Response) {
try {
const result = await UserModel.findAll(10000, 0);
const usersData = result.users.map(user => ({
ID: user.id,
姓名: user.name,
手机号: user.phone,
创建时间: user.createdAt
}));
res.json({
success: true,
data: usersData
});
} catch (error: any) {
res.status(500).json({
success: false,
message: error.message || '导出用户数据失败'
});
}
}
// 导出问题数据
static async exportQuestions(req: Request, res: Response) {
try {
const { type } = req.query;
const result = await QuestionModel.findAll({
type: type as string,
limit: 10000,
offset: 0
});
const questionsData = result.questions.map(question => ({
ID: question.id,
题目内容: question.content,
题型: question.type,
题目类别: question.category,
选项: question.options ? question.options.join('|') : '',
标准答案: Array.isArray(question.answer) ? question.answer.join(',') : question.answer,
分值: question.score,
创建时间: question.createdAt
}));
res.json({
success: true,
data: questionsData
});
} catch (error: any) {
res.status(500).json({
success: false,
message: error.message || '导出问题数据失败'
});
}
}
// 导出答题记录
static async exportRecords(req: Request, res: Response) {
try {
const result = await QuizModel.findAllRecords(10000, 0);
const recordsData = result.records.map((record: any) => ({
ID: record.id,
用户ID: record.userId,
用户名: record.userName,
手机号: record.userPhone,
总得分: record.totalScore,
正确题数: record.correctCount,
总题数: record.totalCount,
答题时间: record.createdAt
}));
res.json({
success: true,
data: recordsData
});
} catch (error: any) {
res.status(500).json({
success: false,
message: error.message || '导出答题记录失败'
});
}
}
// 导出答题答案
static async exportAnswers(req: Request, res: Response) {
try {
// 这里简化处理,实际应该分页获取所有答案
const answersData: any[] = [];
res.json({
success: true,
data: answersData
});
} catch (error: any) {
res.status(500).json({
success: false,
message: error.message || '导出答题答案失败'
});
}
}
// 数据恢复
static async restoreData(req: Request, res: Response) {
try {
const { users, questions, records, answers } = req.body;
// 数据验证
if (!users && !questions && !records && !answers) {
return res.status(400).json({
success: false,
message: '没有可恢复的数据'
});
}
let restoredCount = {
users: 0,
questions: 0,
records: 0,
answers: 0
};
// 恢复用户数据
if (users && users.length > 0) {
for (const user of users) {
try {
const createdUser = await UserModel.create({
name: user.姓名 || user.name,
phone: user.手机号 || user.phone
});
// 统一规则:恢复数据创建的用户也必须加入“全体用户”系统组
await UserGroupModel.updateUserGroups(createdUser.id, []);
restoredCount.users++;
} catch (error) {
console.log('用户已存在,跳过:', user. || user.phone);
}
}
}
// 恢复题目数据
if (questions && questions.length > 0) {
for (const question of questions) {
try {
await QuestionModel.create({
content: question.题目内容 || question.content,
type: question. || question.type,
category: question.题目类别 || question.category || '通用',
options: question.选项 ? (question. as string).split('|') : question.options,
answer: question.标准答案 || question.answer,
score: question.分值 || question.score
});
restoredCount.questions++;
} catch (error) {
console.log('题目创建失败,跳过:', error);
}
}
}
res.json({
success: true,
message: '数据恢复成功',
data: restoredCount
});
} catch (error: any) {
res.status(500).json({
success: false,
message: error.message || '数据恢复失败'
});
}
}
}