2025-12-18 19:07:21 +08:00
|
|
|
|
import { Request, Response } from 'express';
|
|
|
|
|
|
import { SystemConfigModel } from '../models';
|
2025-12-22 21:58:18 +08:00
|
|
|
|
import { query } from '../database';
|
2025-12-18 19:07:21 +08:00
|
|
|
|
|
2025-12-23 00:35:57 +08:00
|
|
|
|
const toPositiveInt = (value: unknown, defaultValue: number) => {
|
|
|
|
|
|
const n = Number(value);
|
|
|
|
|
|
if (!Number.isFinite(n) || n <= 0) return defaultValue;
|
|
|
|
|
|
return Math.floor(n);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-12-18 19:07:21 +08:00
|
|
|
|
export class AdminController {
|
|
|
|
|
|
// 管理员登录
|
|
|
|
|
|
static async login(req: Request, res: Response) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const { username, password } = req.body;
|
|
|
|
|
|
|
|
|
|
|
|
if (!username || !password) {
|
|
|
|
|
|
return res.status(400).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '用户名和密码不能为空'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-21 01:56:54 +08:00
|
|
|
|
// 直接验证用户名和密码,不依赖数据库
|
|
|
|
|
|
// 初始管理员账号:admin / admin123
|
|
|
|
|
|
const isValid = username === 'admin' && password === 'admin123';
|
2025-12-18 19:07:21 +08:00
|
|
|
|
if (!isValid) {
|
|
|
|
|
|
return res.status(401).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '用户名或密码错误'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-21 01:56:54 +08:00
|
|
|
|
// 直接返回成功,不生成真实的JWT token
|
2025-12-18 19:07:21 +08:00
|
|
|
|
res.json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
message: '登录成功',
|
|
|
|
|
|
data: {
|
|
|
|
|
|
username,
|
|
|
|
|
|
token: 'admin-token' // 简化处理
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
|
console.error('管理员登录失败:', error);
|
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: error.message || '登录失败'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取抽题配置
|
|
|
|
|
|
static async getQuizConfig(req: Request, res: Response) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const config = await SystemConfigModel.getQuizConfig();
|
|
|
|
|
|
|
|
|
|
|
|
res.json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
data: config
|
|
|
|
|
|
});
|
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
|
console.error('获取抽题配置失败:', error);
|
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: error.message || '获取抽题配置失败'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新抽题配置
|
|
|
|
|
|
static async updateQuizConfig(req: Request, res: Response) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const { singleRatio, multipleRatio, judgmentRatio, textRatio, totalScore } = req.body;
|
|
|
|
|
|
|
|
|
|
|
|
const config = {
|
|
|
|
|
|
singleRatio,
|
|
|
|
|
|
multipleRatio,
|
|
|
|
|
|
judgmentRatio,
|
|
|
|
|
|
textRatio,
|
|
|
|
|
|
totalScore
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
await SystemConfigModel.updateQuizConfig(config);
|
|
|
|
|
|
|
|
|
|
|
|
res.json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
message: '抽题配置更新成功'
|
|
|
|
|
|
});
|
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
|
console.error('更新抽题配置失败:', error);
|
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: error.message || '更新抽题配置失败'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取统计数据
|
|
|
|
|
|
static async getStatistics(req: Request, res: Response) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const { QuizModel } = await import('../models');
|
|
|
|
|
|
const statistics = await QuizModel.getStatistics();
|
|
|
|
|
|
|
|
|
|
|
|
res.json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
data: statistics
|
|
|
|
|
|
});
|
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
|
console.error('获取统计数据失败:', error);
|
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: error.message || '获取统计数据失败'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-19 00:58:58 +08:00
|
|
|
|
// 获取活跃任务统计数据
|
|
|
|
|
|
static async getActiveTasksStats(req: Request, res: Response) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const { ExamTaskModel } = await import('../models/examTask');
|
|
|
|
|
|
const stats = await ExamTaskModel.getActiveTasksWithStats();
|
|
|
|
|
|
|
|
|
|
|
|
res.json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
data: stats
|
|
|
|
|
|
});
|
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
|
console.error('获取活跃任务统计数据失败:', error);
|
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: error.message || '获取活跃任务统计数据失败'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-23 00:35:57 +08:00
|
|
|
|
static async getHistoryTaskStats(req: Request, res: Response) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const page = toPositiveInt(req.query.page, 1);
|
|
|
|
|
|
const limit = toPositiveInt(req.query.limit, 5);
|
|
|
|
|
|
|
|
|
|
|
|
const { ExamTaskModel } = await import('../models/examTask');
|
|
|
|
|
|
const result = await ExamTaskModel.getHistoryTasksWithStatsPaged(page, limit);
|
|
|
|
|
|
|
|
|
|
|
|
res.json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
data: result.data,
|
|
|
|
|
|
pagination: {
|
|
|
|
|
|
page,
|
|
|
|
|
|
limit,
|
|
|
|
|
|
total: result.total,
|
|
|
|
|
|
pages: Math.ceil(result.total / limit),
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
|
console.error('获取历史任务统计失败:', error);
|
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: error.message || '获取历史任务统计失败',
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static async getUpcomingTaskStats(req: Request, res: Response) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const page = toPositiveInt(req.query.page, 1);
|
|
|
|
|
|
const limit = toPositiveInt(req.query.limit, 5);
|
|
|
|
|
|
|
|
|
|
|
|
const { ExamTaskModel } = await import('../models/examTask');
|
|
|
|
|
|
const result = await ExamTaskModel.getUpcomingTasksWithStatsPaged(page, limit);
|
|
|
|
|
|
|
|
|
|
|
|
res.json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
data: result.data,
|
|
|
|
|
|
pagination: {
|
|
|
|
|
|
page,
|
|
|
|
|
|
limit,
|
|
|
|
|
|
total: result.total,
|
|
|
|
|
|
pages: Math.ceil(result.total / limit),
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
|
console.error('获取未开始任务统计失败:', error);
|
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: error.message || '获取未开始任务统计失败',
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-25 00:15:14 +08:00
|
|
|
|
static async getAllTaskStats(req: Request, res: Response) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const page = toPositiveInt(req.query.page, 1);
|
|
|
|
|
|
const limit = toPositiveInt(req.query.limit, 5);
|
|
|
|
|
|
|
|
|
|
|
|
const statusRaw = typeof req.query.status === 'string' ? req.query.status : undefined;
|
|
|
|
|
|
const status =
|
|
|
|
|
|
statusRaw === 'completed' || statusRaw === 'ongoing' || statusRaw === 'notStarted'
|
|
|
|
|
|
? statusRaw
|
|
|
|
|
|
: undefined;
|
|
|
|
|
|
|
|
|
|
|
|
const endAtStart = typeof req.query.endAtStart === 'string' ? req.query.endAtStart : undefined;
|
|
|
|
|
|
const endAtEnd = typeof req.query.endAtEnd === 'string' ? req.query.endAtEnd : undefined;
|
|
|
|
|
|
|
|
|
|
|
|
if (endAtStart && !Number.isFinite(Date.parse(endAtStart))) {
|
|
|
|
|
|
return res.status(400).json({ success: false, message: 'endAtStart 参数无效' });
|
|
|
|
|
|
}
|
|
|
|
|
|
if (endAtEnd && !Number.isFinite(Date.parse(endAtEnd))) {
|
|
|
|
|
|
return res.status(400).json({ success: false, message: 'endAtEnd 参数无效' });
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const { ExamTaskModel } = await import('../models/examTask');
|
|
|
|
|
|
const result = await ExamTaskModel.getAllTasksWithStatsPaged({
|
|
|
|
|
|
page,
|
|
|
|
|
|
limit,
|
|
|
|
|
|
status,
|
|
|
|
|
|
endAtStart,
|
|
|
|
|
|
endAtEnd,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
res.json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
data: result.data,
|
|
|
|
|
|
pagination: {
|
|
|
|
|
|
page,
|
|
|
|
|
|
limit,
|
|
|
|
|
|
total: result.total,
|
|
|
|
|
|
pages: Math.ceil(result.total / limit),
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
|
console.error('获取任务统计失败:', error);
|
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: error.message || '获取任务统计失败',
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-23 00:35:57 +08:00
|
|
|
|
static async getDashboardOverview(req: Request, res: Response) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const { QuizModel } = await import('../models');
|
|
|
|
|
|
const statistics = await QuizModel.getStatistics();
|
|
|
|
|
|
|
|
|
|
|
|
const now = new Date().toISOString();
|
|
|
|
|
|
|
|
|
|
|
|
const [categoryRows, activeSubjectRow, statusRow] = await Promise.all([
|
|
|
|
|
|
query(
|
|
|
|
|
|
`
|
|
|
|
|
|
SELECT
|
|
|
|
|
|
COALESCE(category, '未分类') as category,
|
|
|
|
|
|
COUNT(*) as count
|
|
|
|
|
|
FROM questions
|
|
|
|
|
|
GROUP BY COALESCE(category, '未分类')
|
|
|
|
|
|
ORDER BY count DESC
|
|
|
|
|
|
`,
|
|
|
|
|
|
),
|
|
|
|
|
|
query(
|
|
|
|
|
|
`
|
|
|
|
|
|
SELECT COUNT(DISTINCT subject_id) as total
|
|
|
|
|
|
FROM exam_tasks
|
|
|
|
|
|
WHERE start_at <= ? AND end_at >= ?
|
|
|
|
|
|
`,
|
|
|
|
|
|
[now, now],
|
|
|
|
|
|
).then((rows: any[]) => rows[0]),
|
|
|
|
|
|
query(
|
|
|
|
|
|
`
|
|
|
|
|
|
SELECT
|
|
|
|
|
|
SUM(CASE WHEN end_at < ? THEN 1 ELSE 0 END) as completed,
|
|
|
|
|
|
SUM(CASE WHEN start_at <= ? AND end_at >= ? THEN 1 ELSE 0 END) as ongoing,
|
|
|
|
|
|
SUM(CASE WHEN start_at > ? THEN 1 ELSE 0 END) as notStarted
|
|
|
|
|
|
FROM exam_tasks
|
|
|
|
|
|
`,
|
|
|
|
|
|
[now, now, now, now],
|
|
|
|
|
|
).then((rows: any[]) => rows[0]),
|
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
|
|
const questionCategoryStats = (categoryRows as any[]).map((r) => ({
|
|
|
|
|
|
category: r.category,
|
|
|
|
|
|
count: Number(r.count) || 0,
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
res.json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
data: {
|
|
|
|
|
|
totalUsers: statistics.totalUsers,
|
|
|
|
|
|
activeSubjectCount: Number(activeSubjectRow?.total) || 0,
|
|
|
|
|
|
questionCategoryStats,
|
|
|
|
|
|
taskStatusDistribution: {
|
|
|
|
|
|
completed: Number(statusRow?.completed) || 0,
|
|
|
|
|
|
ongoing: Number(statusRow?.ongoing) || 0,
|
|
|
|
|
|
notStarted: Number(statusRow?.notStarted) || 0,
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
|
console.error('获取仪表盘概览失败:', error);
|
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: error.message || '获取仪表盘概览失败',
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-22 21:58:18 +08:00
|
|
|
|
static async getUserStats(req: Request, res: Response) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const rows = await query(
|
|
|
|
|
|
`
|
|
|
|
|
|
SELECT
|
|
|
|
|
|
u.id as userId,
|
|
|
|
|
|
u.name as userName,
|
|
|
|
|
|
COUNT(qr.id) as totalRecords,
|
|
|
|
|
|
COALESCE(ROUND(AVG(qr.total_score), 2), 0) as averageScore,
|
|
|
|
|
|
COALESCE(MAX(qr.total_score), 0) as highestScore,
|
|
|
|
|
|
COALESCE(MIN(qr.total_score), 0) as lowestScore
|
|
|
|
|
|
FROM users u
|
|
|
|
|
|
LEFT JOIN quiz_records qr ON u.id = qr.user_id
|
|
|
|
|
|
GROUP BY u.id
|
|
|
|
|
|
ORDER BY totalRecords DESC, u.created_at DESC
|
|
|
|
|
|
`,
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
const data = (rows as any[]).map((row) => ({
|
|
|
|
|
|
userId: row.userId,
|
|
|
|
|
|
userName: row.userName,
|
|
|
|
|
|
totalRecords: Number(row.totalRecords) || 0,
|
|
|
|
|
|
averageScore: Number(row.averageScore) || 0,
|
|
|
|
|
|
highestScore: Number(row.highestScore) || 0,
|
|
|
|
|
|
lowestScore: Number(row.lowestScore) || 0,
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
res.json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
data,
|
|
|
|
|
|
});
|
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
|
console.error('获取用户统计失败:', error);
|
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: error.message || '获取用户统计失败',
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static async getSubjectStats(req: Request, res: Response) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const rows = await query(
|
|
|
|
|
|
`
|
|
|
|
|
|
SELECT
|
|
|
|
|
|
s.id as subjectId,
|
|
|
|
|
|
s.name as subjectName,
|
|
|
|
|
|
COUNT(qr.id) as totalRecords,
|
|
|
|
|
|
COALESCE(ROUND(AVG(qr.total_score), 2), 0) as averageScore,
|
|
|
|
|
|
COALESCE(ROUND(AVG(
|
|
|
|
|
|
CASE
|
|
|
|
|
|
WHEN qr.total_count > 0 THEN (qr.correct_count * 100.0 / qr.total_count)
|
|
|
|
|
|
ELSE 0
|
|
|
|
|
|
END
|
|
|
|
|
|
), 2), 0) as averageCorrectRate
|
|
|
|
|
|
FROM exam_subjects s
|
|
|
|
|
|
LEFT JOIN quiz_records qr ON s.id = qr.subject_id
|
|
|
|
|
|
GROUP BY s.id
|
|
|
|
|
|
ORDER BY totalRecords DESC, s.created_at DESC
|
|
|
|
|
|
`,
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
const data = (rows as any[]).map((row) => ({
|
|
|
|
|
|
subjectId: row.subjectId,
|
|
|
|
|
|
subjectName: row.subjectName,
|
|
|
|
|
|
totalRecords: Number(row.totalRecords) || 0,
|
|
|
|
|
|
averageScore: Number(row.averageScore) || 0,
|
|
|
|
|
|
averageCorrectRate: Number(row.averageCorrectRate) || 0,
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
res.json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
data,
|
|
|
|
|
|
});
|
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
|
console.error('获取科目统计失败:', error);
|
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: error.message || '获取科目统计失败',
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static async getTaskStats(req: Request, res: Response) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const rows = await query(
|
|
|
|
|
|
`
|
|
|
|
|
|
SELECT
|
|
|
|
|
|
t.id as taskId,
|
|
|
|
|
|
t.name as taskName,
|
|
|
|
|
|
COALESCE(rs.totalRecords, 0) as totalRecords,
|
|
|
|
|
|
COALESCE(rs.averageScore, 0) as averageScore,
|
|
|
|
|
|
COALESCE(us.totalUsers, 0) as totalUsers,
|
|
|
|
|
|
COALESCE(rs.completedUsers, 0) as completedUsers
|
|
|
|
|
|
FROM exam_tasks t
|
|
|
|
|
|
LEFT JOIN (
|
|
|
|
|
|
SELECT
|
|
|
|
|
|
task_id,
|
|
|
|
|
|
COUNT(*) as totalRecords,
|
|
|
|
|
|
ROUND(AVG(total_score), 2) as averageScore,
|
|
|
|
|
|
COUNT(DISTINCT user_id) as completedUsers
|
|
|
|
|
|
FROM quiz_records
|
|
|
|
|
|
WHERE task_id IS NOT NULL
|
|
|
|
|
|
GROUP BY task_id
|
|
|
|
|
|
) rs ON rs.task_id = t.id
|
|
|
|
|
|
LEFT JOIN (
|
|
|
|
|
|
SELECT
|
|
|
|
|
|
task_id,
|
|
|
|
|
|
COUNT(DISTINCT user_id) as totalUsers
|
|
|
|
|
|
FROM exam_task_users
|
|
|
|
|
|
GROUP BY task_id
|
|
|
|
|
|
) us ON us.task_id = t.id
|
|
|
|
|
|
ORDER BY t.created_at DESC
|
|
|
|
|
|
`,
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
const data = rows.map((row: any) => {
|
|
|
|
|
|
const totalUsers = Number(row.totalUsers) || 0;
|
|
|
|
|
|
const completedUsers = Number(row.completedUsers) || 0;
|
|
|
|
|
|
const completionRate = totalUsers > 0 ? (completedUsers / totalUsers) * 100 : 0;
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
taskId: row.taskId,
|
|
|
|
|
|
taskName: row.taskName,
|
|
|
|
|
|
totalRecords: Number(row.totalRecords) || 0,
|
|
|
|
|
|
averageScore: Number(row.averageScore) || 0,
|
|
|
|
|
|
completionRate,
|
|
|
|
|
|
};
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
res.json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
data,
|
|
|
|
|
|
});
|
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
|
console.error('获取任务统计失败:', error);
|
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: error.message || '获取任务统计失败',
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-18 19:07:21 +08:00
|
|
|
|
// 修改管理员密码
|
|
|
|
|
|
static async updatePassword(req: Request, res: Response) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const { username, oldPassword, newPassword } = req.body;
|
|
|
|
|
|
|
|
|
|
|
|
if (!username || !oldPassword || !newPassword) {
|
|
|
|
|
|
return res.status(400).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '参数不完整'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 验证旧密码
|
|
|
|
|
|
const isValid = await SystemConfigModel.validateAdminLogin(username, oldPassword);
|
|
|
|
|
|
if (!isValid) {
|
|
|
|
|
|
return res.status(401).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: '原密码错误'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新密码
|
|
|
|
|
|
await SystemConfigModel.updateAdminPassword(username, newPassword);
|
|
|
|
|
|
|
|
|
|
|
|
res.json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
message: '密码修改成功'
|
|
|
|
|
|
});
|
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
|
console.error('修改密码失败:', error);
|
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: error.message || '修改密码失败'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取所有配置(管理员用)
|
|
|
|
|
|
static async getAllConfigs(req: Request, res: Response) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const configs = await SystemConfigModel.getAllConfigs();
|
|
|
|
|
|
|
|
|
|
|
|
res.json({
|
|
|
|
|
|
success: true,
|
|
|
|
|
|
data: configs
|
|
|
|
|
|
});
|
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
|
console.error('获取配置失败:', error);
|
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
|
success: false,
|
|
|
|
|
|
message: error.message || '获取配置失败'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-22 21:58:18 +08:00
|
|
|
|
}
|