175 lines
4.8 KiB
TypeScript
175 lines
4.8 KiB
TypeScript
import { Request, Response } from 'express';
|
|
import * as XLSX from 'xlsx';
|
|
import { UserModel, QuestionModel, QuizModel } 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 {
|
|
await UserModel.create({
|
|
name: user.姓名 || user.name,
|
|
phone: user.手机号 || user.phone
|
|
});
|
|
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 || '数据恢复失败'
|
|
});
|
|
}
|
|
}
|
|
}
|