基本功能完成,下一步开始美化UI

This commit is contained in:
2025-12-19 16:02:38 +08:00
parent 465d4d7b4a
commit 6ac216d184
46 changed files with 2576 additions and 618 deletions

View File

@@ -1,18 +1,43 @@
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: result.users.map((u) => ({ ...u, password: u.password ?? '' })),
data: usersWithGroups,
pagination: {
page,
limit,
@@ -28,6 +53,58 @@ export class AdminUserController {
}
}
// 创建用户
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;
@@ -87,7 +164,7 @@ export class AdminUserController {
static async updateUser(req: Request, res: Response) {
try {
const { id } = req.params;
const { name, phone, password } = req.body;
const { name, phone, password, groupIds } = req.body;
const user = await UserModel.findById(id);
if (!user) {
@@ -106,9 +183,20 @@ export class AdminUserController {
// 更新用户
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
data: {
...updatedUser,
groups
}
});
} catch (error: any) {
// 处理手机号已存在的错误

View File

@@ -1,5 +1,6 @@
import { Request, Response } from 'express';
import { ExamTaskModel } from '../models/examTask';
import { UserGroupModel } from '../models/userGroup';
export class ExamTaskController {
static async getTasks(req: Request, res: Response) {
@@ -19,12 +20,29 @@ export class ExamTaskController {
static async createTask(req: Request, res: Response) {
try {
const { name, subjectId, startAt, endAt, userIds } = req.body;
const { name, subjectId, startAt, endAt, userIds = [], groupIds = [] } = req.body;
if (!name || !subjectId || !startAt || !endAt || !Array.isArray(userIds) || userIds.length === 0) {
if (!name || !subjectId || !startAt || !endAt) {
return res.status(400).json({
success: false,
message: '参数不完整或用户列表为空'
message: '参数不完整'
});
}
// 合并用户列表和用户组中的用户
const finalUserIds = new Set<string>(userIds);
if (Array.isArray(groupIds) && groupIds.length > 0) {
for (const groupId of groupIds) {
const members = await UserGroupModel.getMembers(groupId);
members.forEach(m => finalUserIds.add(m.id));
}
}
if (finalUserIds.size === 0) {
return res.status(400).json({
success: false,
message: '请至少选择一位用户或一个用户组'
});
}
@@ -33,7 +51,8 @@ export class ExamTaskController {
subjectId,
startAt,
endAt,
userIds
userIds: Array.from(finalUserIds),
selectionConfig: JSON.stringify({ userIds, groupIds })
});
res.json({
@@ -51,12 +70,29 @@ export class ExamTaskController {
static async updateTask(req: Request, res: Response) {
try {
const { id } = req.params;
const { name, subjectId, startAt, endAt, userIds } = req.body;
const { name, subjectId, startAt, endAt, userIds = [], groupIds = [] } = req.body;
if (!name || !subjectId || !startAt || !endAt || !Array.isArray(userIds) || userIds.length === 0) {
if (!name || !subjectId || !startAt || !endAt) {
return res.status(400).json({
success: false,
message: '参数不完整或用户列表为空'
message: '参数不完整'
});
}
// 合并用户列表和用户组中的用户
const finalUserIds = new Set<string>(userIds);
if (Array.isArray(groupIds) && groupIds.length > 0) {
for (const groupId of groupIds) {
const members = await UserGroupModel.getMembers(groupId);
members.forEach(m => finalUserIds.add(m.id));
}
}
if (finalUserIds.size === 0) {
return res.status(400).json({
success: false,
message: '请至少选择一位用户或一个用户组'
});
}
@@ -65,7 +101,8 @@ export class ExamTaskController {
subjectId,
startAt,
endAt,
userIds
userIds: Array.from(finalUserIds),
selectionConfig: JSON.stringify({ userIds, groupIds })
});
res.json({

View File

@@ -1,10 +1,11 @@
// 导出所有控制器
export { UserController } from './userController';
export { QuestionController } from './questionController';
export { QuizController } from './quizController';
export { AdminController } from './adminController';
export { BackupController } from './backupController';
export { QuestionCategoryController } from './questionCategoryController';
export { ExamSubjectController } from './examSubjectController';
export { ExamTaskController } from './examTaskController';
export { AdminUserController } from './adminUserController';
export * from './userController';
export * from './questionController';
export * from './quizController';
export * from './adminController';
export * from './questionCategoryController';
export * from './examSubjectController';
export * from './examTaskController';
export * from './adminUserController';
export * from './userQuizController';
export * from './backupController';
export * from './userGroupController';

View File

@@ -1,5 +1,6 @@
import { Request, Response } from 'express';
import { UserModel } from '../models/user';
import { UserGroupModel } from '../models/userGroup';
export class UserController {
static async createUser(req: Request, res: Response) {
@@ -24,6 +25,12 @@ export class UserController {
const user = await UserModel.create({ name, phone, password });
// 自动加入"全体用户"组
const allUsersGroup = await UserGroupModel.getSystemGroup();
if (allUsersGroup) {
await UserGroupModel.addMember(allUsersGroup.id, user.id);
}
res.json({
success: true,
data: user

View File

@@ -0,0 +1,64 @@
import { Request, Response } from 'express';
import { UserGroupModel } from '../models/userGroup';
export const userGroupController = {
// 获取所有用户组
getAll: async (req: Request, res: Response) => {
try {
const groups = await UserGroupModel.findAll();
res.json(groups);
} catch (error: any) {
res.status(500).json({ error: error.message });
}
},
// 创建用户组
create: async (req: Request, res: Response) => {
try {
const { name, description } = req.body;
if (!name) {
return res.status(400).json({ error: '用户组名称不能为空' });
}
const group = await UserGroupModel.create({ name, description });
res.status(201).json(group);
} catch (error: any) {
res.status(400).json({ error: error.message });
}
},
// 更新用户组
update: async (req: Request, res: Response) => {
try {
const { id } = req.params;
const { name, description } = req.body;
const group = await UserGroupModel.update(id, { name, description });
res.json(group);
} catch (error: any) {
res.status(400).json({ error: error.message });
}
},
// 删除用户组
delete: async (req: Request, res: Response) => {
try {
const { id } = req.params;
await UserGroupModel.delete(id);
res.json({ message: '用户组删除成功' });
} catch (error: any) {
res.status(400).json({ error: error.message });
}
},
// 获取用户组成员
getMembers: async (req: Request, res: Response) => {
try {
const { id } = req.params;
const members = await UserGroupModel.getMembers(id);
res.json(members);
} catch (error: any) {
res.status(500).json({ error: error.message });
}
}
};