Files
Web_BLV_OA_Exam_Prod/api/controllers/adminUserController.ts

347 lines
9.5 KiB
TypeScript
Raw Normal View History

import { Request, Response } from 'express';
import { UserModel } from '../models/user';
import { QuizModel } from '../models/quiz';
import { UserGroupModel } from '../models/userGroup';
export class AdminUserController {
static async getUsers(req: Request, res: Response) {
try {
const page = parseInt(req.query.page as string) || 1;
const limit = parseInt(req.query.limit as string) || 10;
const keyword = req.query.keyword as string;
// TODO: Implement search in UserModel if needed, currently filtering in memory or ignored
// For now assuming findAll supports basic pagination.
// If keyword is needed, we should add findByKeyword to UserModel.
// But based on existing code, it seems it wasn't implemented there.
// Let's stick to what was there or improve if I see it.
// The previous code used findAll(limit, offset).
const result = await UserModel.findAll(limit, (page - 1) * limit);
// Filter by keyword if provided (naive implementation since DB doesn't support it yet via API)
let users = result.users;
if (keyword) {
users = users.filter(u => u.name.includes(keyword) || u.phone.includes(keyword));
}
// 获取每个用户的用户组信息
const usersWithGroups = await Promise.all(users.map(async (u) => {
const groups = await UserGroupModel.getUserGroups(u.id);
return {
...u,
password: u.password ?? '',
groups
};
}));
res.json({
success: true,
data: usersWithGroups,
pagination: {
page,
limit,
total: result.total,
pages: Math.ceil(result.total / limit)
}
});
} catch (error: any) {
res.status(500).json({
success: false,
message: error.message || '获取用户列表失败'
});
}
}
// 创建用户
static async createUser(req: Request, res: Response) {
try {
const { name, phone, password, groupIds } = req.body;
if (!name || !phone) {
return res.status(400).json({
success: false,
message: '姓名和手机号不能为空'
});
}
const errors = UserModel.validateUserData({ name, phone, password });
if (errors.length > 0) {
return res.status(400).json({
success: false,
message: '数据验证失败: ' + errors.join(', ')
});
}
const user = await UserModel.create({ name, phone, password });
// 自动加入"全体用户"组
const allUsersGroup = await UserGroupModel.getSystemGroup();
if (allUsersGroup) {
await UserGroupModel.addMember(allUsersGroup.id, user.id);
}
// 添加到指定用户组
if (groupIds && Array.isArray(groupIds)) {
await UserGroupModel.updateUserGroups(user.id, groupIds);
}
res.json({
success: true,
data: user
});
} catch (error: any) {
// 处理手机号已存在的错误
if (error.message === '手机号已存在' || error.code === 'SQLITE_CONSTRAINT_UNIQUE') {
return res.status(400).json({
success: false,
message: '手机号已存在'
});
}
res.status(500).json({
success: false,
message: error.message || '创建用户失败'
});
}
}
static async deleteUser(req: Request, res: Response) {
try {
const { userId } = req.body;
if (!userId) {
return res.status(400).json({
success: false,
message: 'userId不能为空'
});
}
const user = await UserModel.findById(userId);
if (!user) {
return res.status(404).json({
success: false,
message: '用户不存在'
});
}
await UserModel.delete(userId);
res.json({
success: true,
message: '删除成功'
});
} catch (error: any) {
res.status(500).json({
success: false,
message: error.message || '删除用户失败'
});
}
}
static async exportUsers(req: Request, res: Response) {
try {
const result = await UserModel.findAll(10000, 0);
const data = result.users.map((u) => ({
ID: u.id,
姓名: u.name,
手机号: u.phone,
密码: u.password ?? '',
注册时间: u.createdAt
}));
res.json({
success: true,
data
});
} catch (error: any) {
res.status(500).json({
success: false,
message: error.message || '导出用户失败'
});
}
}
// 更新用户信息
static async updateUser(req: Request, res: Response) {
try {
const { id } = req.params;
const { name, phone, password, groupIds } = req.body;
const user = await UserModel.findById(id);
if (!user) {
return res.status(404).json({
success: false,
message: '用户不存在'
});
}
// 准备更新数据
const updateData: Partial<{ name: string; phone: string; password: string }> = {};
if (name !== undefined) updateData.name = name;
if (phone !== undefined) updateData.phone = phone;
if (password !== undefined) updateData.password = password;
// 更新用户
const updatedUser = await UserModel.update(id, updateData);
// 更新用户组
if (groupIds && Array.isArray(groupIds)) {
await UserGroupModel.updateUserGroups(id, groupIds);
}
// 获取最新用户组信息
const groups = await UserGroupModel.getUserGroups(id);
res.json({
success: true,
data: {
...updatedUser,
groups
}
});
} catch (error: any) {
// 处理手机号已存在的错误
if (error.message === '手机号已存在') {
return res.status(400).json({
success: false,
message: '手机号已存在'
});
}
// 处理SQLITE_CONSTRAINT_UNIQUE错误
if (error.code === 'SQLITE_CONSTRAINT_UNIQUE') {
return res.status(400).json({
success: false,
message: '手机号已存在'
});
}
// 处理数据验证错误
if (error.message.includes('姓名长度必须在2-20个字符之间') ||
error.message.includes('手机号格式不正确')) {
return res.status(400).json({
success: false,
message: error.message
});
}
// 处理其他错误
res.status(500).json({
success: false,
message: error.message || '更新用户失败'
});
}
}
static async importUsers(req: Request, res: Response) {
try {
const file = (req as any).file;
if (!file) {
return res.status(400).json({
success: false,
message: '请上传Excel文件'
});
}
const XLSX = await import('xlsx');
const workbook = XLSX.read(file.buffer, { type: 'buffer' });
const sheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[sheetName];
const rows = XLSX.utils.sheet_to_json(worksheet) as any[];
const errors: string[] = [];
let imported = 0;
for (let i = 0; i < rows.length; i++) {
const row = rows[i];
try {
const name = row['姓名'] || row['name'];
const phone = row['手机号'] || row['phone'];
const password = row['密码'] || row['password'] || '';
if (!name || !phone) {
errors.push(`${i + 2}行:姓名或手机号缺失`);
continue;
}
await UserModel.create({ name, phone, password });
imported++;
} catch (error: any) {
if (error.message === '手机号已存在') {
errors.push(`${i + 2}行:手机号重复`);
} else {
errors.push(`${i + 2}行:${error.message}`);
}
}
}
res.json({
success: true,
data: {
imported,
total: rows.length,
errors
}
});
} catch (error: any) {
res.status(500).json({
success: false,
message: error.message || '导入用户失败'
});
}
}
static async getUserRecords(req: Request, res: Response) {
try {
const { userId } = req.params;
const page = parseInt(req.query.page as string) || 1;
const limit = parseInt(req.query.limit as string) || 10;
const result = await QuizModel.findRecordsByUserId(userId, limit, (page - 1) * limit);
res.json({
success: true,
data: result.records,
pagination: {
page,
limit,
total: result.total,
pages: Math.ceil(result.total / limit)
}
});
} catch (error: any) {
res.status(500).json({
success: false,
message: error.message || '获取用户答题记录失败'
});
}
}
static async getRecordDetail(req: Request, res: Response) {
try {
const { recordId } = req.params;
const record = await QuizModel.findRecordById(recordId);
if (!record) {
return res.status(404).json({
success: false,
message: '答题记录不存在'
});
}
const answers = await QuizModel.findAnswersByRecordId(recordId);
res.json({
success: true,
data: {
record,
answers
}
});
} catch (error: any) {
res.status(500).json({
success: false,
message: error.message || '获取答题记录详情失败'
});
}
}
}