380 lines
13 KiB
TypeScript
380 lines
13 KiB
TypeScript
|
|
const familyNames = ['赵', '冯', '钱', '刘', '孙', '李', '周', '吴', '郑', '王', '陈', '杨', '黄', '张', '林', '何', '高', '马', '罗', '梁'];
|
||
|
|
const givenNames = ['玉岚', '艺莲', '若蓉', '思钰', '婷雅', '恩铭', '浩然', '子涵', '欣怡', '梓萱', '宇轩', '雨桐', '佳琪', '思远', '天乐', '晓峰', '文博', '嘉欣', '雅静', '明辉'];
|
||
|
|
const colleges = ['电气化学院', '管理学院', '设计学院', '信息工程学院', '艺术学院', '外国语学院'];
|
||
|
|
const deptMap: Record<string, string[]> = {
|
||
|
|
'电气化学院': ['电力工程系', '电气工程系', '自动化系'],
|
||
|
|
'管理学院': ['工商管理系', '会计系', '人力资源系'],
|
||
|
|
'设计学院': ['视觉传达设计系', '环境设计系'],
|
||
|
|
'信息工程学院': ['计算机系', '电子信息系'],
|
||
|
|
'艺术学院': ['音乐系', '美术系'],
|
||
|
|
'外国语学院': ['英语系', '日语系'],
|
||
|
|
};
|
||
|
|
const majorMap: Record<string, string[]> = {
|
||
|
|
'电力工程系': ['电气化', '电力工程'],
|
||
|
|
'电气工程系': ['电气工程', '智能电网'],
|
||
|
|
'自动化系': ['自动化', '机器人工程'],
|
||
|
|
'工商管理系': ['工商管理', '市场营销'],
|
||
|
|
'会计系': ['财务管理', '审计学'],
|
||
|
|
'人力资源系': ['人力资源管理'],
|
||
|
|
'视觉传达设计系': ['平面设计', '数字媒体设计'],
|
||
|
|
'环境设计系': ['室内设计', '景观设计'],
|
||
|
|
'计算机系': ['软件工程', '计算机科学与技术', '人工智能'],
|
||
|
|
'电子信息系': ['通信工程', '电子信息'],
|
||
|
|
'音乐系': ['声乐表演', '器乐演奏'],
|
||
|
|
'美术系': ['国画', '油画'],
|
||
|
|
'英语系': ['英语', '翻译'],
|
||
|
|
'日语系': ['日语'],
|
||
|
|
};
|
||
|
|
|
||
|
|
const statuses: Array<'normal' | 'disabled'> = ['normal', 'normal', 'normal', 'normal', 'disabled'];
|
||
|
|
const roles = ['学生'];
|
||
|
|
const grades = ['2023级', '2024级', '2025级'];
|
||
|
|
const classes = ['1班', '2班', '3班', '4班', '5班'];
|
||
|
|
|
||
|
|
// 年级管理数据
|
||
|
|
const gradeList: any[] = [
|
||
|
|
{ id: '1', name: '2025级', createTime: '2025.09.01 16:01:30', graduated: false },
|
||
|
|
{ id: '2', name: '2026级', createTime: '2025.09.01 16:01:30', graduated: false },
|
||
|
|
{ id: '3', name: '2024级', createTime: '2025.09.01 16:01:30', graduated: false },
|
||
|
|
{ id: '4', name: '2023级', createTime: '2025.09.01 16:01:30', graduated: false },
|
||
|
|
{ id: '5', name: '2022级', createTime: '2025.09.01 16:01:30', graduated: false },
|
||
|
|
{ id: '6', name: '2021级', createTime: '2025.09.01 16:01:30', graduated: false },
|
||
|
|
{ id: '7', name: '2020级', createTime: '2025.09.01 16:01:30', graduated: false },
|
||
|
|
{ id: '8', name: '2025级', createTime: '2025.09.01 16:01:30', graduated: false },
|
||
|
|
{ id: '9', name: '2025级', createTime: '2025.09.01 16:01:30', graduated: false },
|
||
|
|
{ id: '10', name: '2025级', createTime: '2025.09.01 16:01:30', graduated: false },
|
||
|
|
];
|
||
|
|
|
||
|
|
// 设置一条数据为已毕业状态,用于"还原"操作演示
|
||
|
|
gradeList[1].graduated = true;
|
||
|
|
|
||
|
|
function randomPick<T>(arr: T[]): T {
|
||
|
|
return arr[Math.floor(Math.random() * arr.length)];
|
||
|
|
}
|
||
|
|
|
||
|
|
function maskPhone(phone: string) {
|
||
|
|
return phone.substring(0, 3) + '****' + phone.substring(7);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 生成100条学生数据
|
||
|
|
const students: any[] = [];
|
||
|
|
for (let i = 0; i < 100; i++) {
|
||
|
|
const college = randomPick(colleges);
|
||
|
|
const depts = deptMap[college] || [];
|
||
|
|
const dept = randomPick(depts);
|
||
|
|
const majors = majorMap[dept] || [];
|
||
|
|
const major = randomPick(majors);
|
||
|
|
const status = randomPick(statuses);
|
||
|
|
const phone = `1${randomPick(['39', '56', '78', '38', '59'])}${String(Math.floor(Math.random() * 100000000)).padStart(8, '0')}`;
|
||
|
|
|
||
|
|
students.push({
|
||
|
|
id: String(i + 1),
|
||
|
|
name: randomPick(familyNames) + randomPick(givenNames),
|
||
|
|
studentNo: String(178000 + Math.floor(Math.random() * 1000)),
|
||
|
|
college,
|
||
|
|
dept,
|
||
|
|
major,
|
||
|
|
className: `${Math.ceil(Math.random() * 3)}班`,
|
||
|
|
grade: randomPick(grades),
|
||
|
|
phone,
|
||
|
|
maskedPhone: maskPhone(phone),
|
||
|
|
role: randomPick(roles),
|
||
|
|
updateDate: '2025.09.01',
|
||
|
|
status,
|
||
|
|
graduated: false,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// 生成100条已毕业学生数据
|
||
|
|
const graduatedStudents: any[] = [];
|
||
|
|
for (let i = 0; i < 100; i++) {
|
||
|
|
const college = randomPick(colleges);
|
||
|
|
const depts = deptMap[college] || [];
|
||
|
|
const dept = randomPick(depts);
|
||
|
|
const majors = majorMap[dept] || [];
|
||
|
|
const major = randomPick(majors);
|
||
|
|
const status = randomPick(statuses);
|
||
|
|
const phone = `1${randomPick(['39', '56', '78', '38', '59'])}${String(Math.floor(Math.random() * 100000000)).padStart(8, '0')}`;
|
||
|
|
|
||
|
|
graduatedStudents.push({
|
||
|
|
id: String(i + 2000),
|
||
|
|
name: randomPick(familyNames) + randomPick(givenNames),
|
||
|
|
studentNo: String(178000 + Math.floor(Math.random() * 1000)),
|
||
|
|
college,
|
||
|
|
dept,
|
||
|
|
major,
|
||
|
|
className: `${Math.ceil(Math.random() * 3)}班`,
|
||
|
|
grade: randomPick(grades),
|
||
|
|
phone,
|
||
|
|
maskedPhone: maskPhone(phone),
|
||
|
|
role: randomPick(roles),
|
||
|
|
updateDate: '2025.09.01',
|
||
|
|
status,
|
||
|
|
graduated: true,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
export default {
|
||
|
|
'GET /api/admin/student': (req: any, res: any) => {
|
||
|
|
const {
|
||
|
|
page = '1',
|
||
|
|
pageSize = '10',
|
||
|
|
graduated,
|
||
|
|
studentNo,
|
||
|
|
name,
|
||
|
|
college,
|
||
|
|
dept,
|
||
|
|
major,
|
||
|
|
className,
|
||
|
|
status,
|
||
|
|
} = req.query;
|
||
|
|
|
||
|
|
const source = graduated === 'true' ? graduatedStudents : students;
|
||
|
|
let filtered = [...source];
|
||
|
|
|
||
|
|
if (studentNo) {
|
||
|
|
filtered = filtered.filter((s) => s.studentNo.includes(studentNo));
|
||
|
|
}
|
||
|
|
if (name) {
|
||
|
|
filtered = filtered.filter((s) => s.name.includes(name));
|
||
|
|
}
|
||
|
|
if (college) {
|
||
|
|
filtered = filtered.filter((s) => s.college === college);
|
||
|
|
}
|
||
|
|
if (dept) {
|
||
|
|
filtered = filtered.filter((s) => s.dept === dept);
|
||
|
|
}
|
||
|
|
if (major) {
|
||
|
|
filtered = filtered.filter((s) => s.major === major);
|
||
|
|
}
|
||
|
|
if (className) {
|
||
|
|
filtered = filtered.filter((s) => s.className === className);
|
||
|
|
}
|
||
|
|
if (status) {
|
||
|
|
filtered = filtered.filter((s) => s.status === status);
|
||
|
|
}
|
||
|
|
|
||
|
|
const p = Number(page);
|
||
|
|
const ps = Number(pageSize);
|
||
|
|
const start = (p - 1) * ps;
|
||
|
|
const list = filtered.slice(start, start + ps);
|
||
|
|
|
||
|
|
res.json({
|
||
|
|
code: 0,
|
||
|
|
data: {
|
||
|
|
list,
|
||
|
|
total: filtered.length,
|
||
|
|
page: p,
|
||
|
|
pageSize: ps,
|
||
|
|
},
|
||
|
|
message: 'ok',
|
||
|
|
});
|
||
|
|
},
|
||
|
|
|
||
|
|
'POST /api/admin/student/toggle-status': (req: any, res: any) => {
|
||
|
|
const { id } = req.body;
|
||
|
|
const student = students.find((s) => s.id === id) || graduatedStudents.find((s) => s.id === id);
|
||
|
|
if (student) {
|
||
|
|
student.status = student.status === 'normal' ? 'disabled' : 'normal';
|
||
|
|
res.json({ code: 0, data: null, message: '操作成功' });
|
||
|
|
} else {
|
||
|
|
res.json({ code: 40000, data: null, message: '学生不存在' });
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
'POST /api/admin/student/delete': (req: any, res: any) => {
|
||
|
|
const { id } = req.body;
|
||
|
|
let idx = students.findIndex((s) => s.id === id);
|
||
|
|
if (idx > -1) {
|
||
|
|
students.splice(idx, 1);
|
||
|
|
res.json({ code: 0, data: null, message: '删除成功' });
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
idx = graduatedStudents.findIndex((s) => s.id === id);
|
||
|
|
if (idx > -1) {
|
||
|
|
graduatedStudents.splice(idx, 1);
|
||
|
|
res.json({ code: 0, data: null, message: '删除成功' });
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
res.json({ code: 40000, data: null, message: '学生不存在' });
|
||
|
|
},
|
||
|
|
|
||
|
|
'POST /api/admin/student/batch-delete': (req: any, res: any) => {
|
||
|
|
const { ids, graduated } = req.body;
|
||
|
|
if (!ids || !Array.isArray(ids) || ids.length === 0) {
|
||
|
|
res.json({ code: 40000, data: null, message: '请选择要删除的学生' });
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const source = graduated ? graduatedStudents : students;
|
||
|
|
let count = 0;
|
||
|
|
for (let i = source.length - 1; i >= 0; i--) {
|
||
|
|
if (ids.includes(source[i].id)) {
|
||
|
|
source.splice(i, 1);
|
||
|
|
count++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
res.json({ code: 0, data: { count }, message: `成功删除${count}名学生` });
|
||
|
|
},
|
||
|
|
|
||
|
|
'POST /api/admin/student/batch-import': (req: any, res: any) => {
|
||
|
|
// 模拟批量导入5名学生
|
||
|
|
const imported: any[] = [];
|
||
|
|
for (let i = 0; i < 5; i++) {
|
||
|
|
const college = randomPick(colleges);
|
||
|
|
const depts = deptMap[college] || [];
|
||
|
|
const dept = randomPick(depts);
|
||
|
|
const majors = majorMap[dept] || [];
|
||
|
|
const major = randomPick(majors);
|
||
|
|
const phone = `1${randomPick(['39', '56', '78', '38', '59'])}${String(Math.floor(Math.random() * 100000000)).padStart(8, '0')}`;
|
||
|
|
const newStudent = {
|
||
|
|
id: String(Date.now() + i),
|
||
|
|
name: randomPick(familyNames) + randomPick(givenNames),
|
||
|
|
studentNo: String(178000 + Math.floor(Math.random() * 1000)),
|
||
|
|
college,
|
||
|
|
dept,
|
||
|
|
major,
|
||
|
|
className: `${Math.ceil(Math.random() * 3)}班`,
|
||
|
|
grade: randomPick(grades),
|
||
|
|
phone,
|
||
|
|
maskedPhone: maskPhone(phone),
|
||
|
|
role: '学生',
|
||
|
|
updateDate: new Date().toISOString().slice(0, 10).replace(/-/g, '.'),
|
||
|
|
status: 'normal' as const,
|
||
|
|
graduated: false,
|
||
|
|
};
|
||
|
|
students.unshift(newStudent);
|
||
|
|
imported.push(newStudent);
|
||
|
|
}
|
||
|
|
res.json({ code: 0, data: { count: imported.length }, message: `成功导入${imported.length}名学生` });
|
||
|
|
},
|
||
|
|
|
||
|
|
'POST /api/admin/student/reset-password': (req: any, res: any) => {
|
||
|
|
const { id } = req.body;
|
||
|
|
const student = students.find((s) => s.id === id) || graduatedStudents.find((s) => s.id === id);
|
||
|
|
if (student) {
|
||
|
|
console.log(`[Mock] 重置学生 ${student.name} 密码`);
|
||
|
|
res.json({ code: 0, data: null, message: '密码已重置为 123456' });
|
||
|
|
} else {
|
||
|
|
res.json({ code: 40000, data: null, message: '学生不存在' });
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
'POST /api/admin/student/edit': (req: any, res: any) => {
|
||
|
|
const { id, name, studentNo, role, college, dept, major, className, grade, phone } = req.body;
|
||
|
|
const student = students.find((s) => s.id === id) || graduatedStudents.find((s) => s.id === id);
|
||
|
|
if (!student) {
|
||
|
|
res.json({ code: 40000, data: null, message: '学生不存在' });
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (!name || !studentNo || !role || !college || !dept || !major || !className || !grade) {
|
||
|
|
res.json({ code: 40000, data: null, message: '请填写完整信息' });
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
Object.assign(student, {
|
||
|
|
name, studentNo, role, college, dept, major, className, grade,
|
||
|
|
phone: phone || '',
|
||
|
|
maskedPhone: phone ? phone.substring(0, 3) + '****' + phone.substring(7) : '',
|
||
|
|
updateDate: new Date().toISOString().slice(0, 10).replace(/-/g, '.'),
|
||
|
|
});
|
||
|
|
res.json({ code: 0, data: student, message: '编辑成功' });
|
||
|
|
},
|
||
|
|
|
||
|
|
'POST /api/admin/student/add': (req: any, res: any) => {
|
||
|
|
const { name, studentNo, role, college, dept, major, className, grade, phone } = req.body;
|
||
|
|
if (!name || !studentNo || !role || !college || !dept || !major || !className || !grade) {
|
||
|
|
res.json({ code: 40000, data: null, message: '请填写完整信息' });
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const newStudent = {
|
||
|
|
id: String(students.length + 1000),
|
||
|
|
name,
|
||
|
|
studentNo,
|
||
|
|
college,
|
||
|
|
dept,
|
||
|
|
major,
|
||
|
|
className,
|
||
|
|
grade,
|
||
|
|
phone: phone || '',
|
||
|
|
maskedPhone: phone ? phone.substring(0, 3) + '****' + phone.substring(7) : '',
|
||
|
|
role,
|
||
|
|
updateDate: new Date().toISOString().slice(0, 10).replace(/-/g, '.'),
|
||
|
|
status: 'normal' as const,
|
||
|
|
};
|
||
|
|
students.unshift(newStudent);
|
||
|
|
res.json({ code: 0, data: newStudent, message: '新增成功' });
|
||
|
|
},
|
||
|
|
|
||
|
|
'GET /api/admin/student/colleges': (_req: any, res: any) => {
|
||
|
|
res.json({
|
||
|
|
code: 0,
|
||
|
|
data: {
|
||
|
|
colleges,
|
||
|
|
deptMap,
|
||
|
|
majorMap,
|
||
|
|
classes,
|
||
|
|
grades,
|
||
|
|
roles,
|
||
|
|
},
|
||
|
|
message: 'ok',
|
||
|
|
});
|
||
|
|
},
|
||
|
|
|
||
|
|
// 年级管理接口
|
||
|
|
'GET /api/admin/grade': (req: any, res: any) => {
|
||
|
|
const { page = '1', pageSize = '10', name } = req.query;
|
||
|
|
let filtered = [...gradeList];
|
||
|
|
if (name) {
|
||
|
|
filtered = filtered.filter((g: any) => g.name.includes(name));
|
||
|
|
}
|
||
|
|
const p = Number(page);
|
||
|
|
const ps = Number(pageSize);
|
||
|
|
const start = (p - 1) * ps;
|
||
|
|
const list = filtered.slice(start, start + ps);
|
||
|
|
res.json({ code: 0, data: { list, total: filtered.length, page: p, pageSize: ps }, message: 'ok' });
|
||
|
|
},
|
||
|
|
|
||
|
|
'POST /api/admin/grade/add': (req: any, res: any) => {
|
||
|
|
const { name } = req.body;
|
||
|
|
const newGrade = {
|
||
|
|
id: String(gradeList.length + 1),
|
||
|
|
name,
|
||
|
|
createTime: new Date().toISOString().replace('T', ' ').slice(0, 19),
|
||
|
|
};
|
||
|
|
gradeList.unshift(newGrade);
|
||
|
|
res.json({ code: 0, data: newGrade, message: '新增成功' });
|
||
|
|
},
|
||
|
|
|
||
|
|
'POST /api/admin/grade/edit': (req: any, res: any) => {
|
||
|
|
const { id, name } = req.body;
|
||
|
|
const item = gradeList.find((g: any) => g.id === id);
|
||
|
|
if (item) {
|
||
|
|
item.name = name;
|
||
|
|
res.json({ code: 0, data: item, message: '编辑成功' });
|
||
|
|
} else {
|
||
|
|
res.json({ code: 1, message: '未找到该年级' });
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
'POST /api/admin/grade/graduate': (req: any, res: any) => {
|
||
|
|
const { id } = req.body;
|
||
|
|
const idx = gradeList.findIndex((g: any) => g.id === id);
|
||
|
|
if (idx >= 0) {
|
||
|
|
gradeList[idx].graduated = true;
|
||
|
|
res.json({ code: 0, message: '转毕业成功' });
|
||
|
|
} else {
|
||
|
|
res.json({ code: 1, message: '未找到该年级' });
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
'POST /api/admin/grade/restore': (req: any, res: any) => {
|
||
|
|
const { id } = req.body;
|
||
|
|
const idx = gradeList.findIndex((g: any) => g.id === id);
|
||
|
|
if (idx >= 0) {
|
||
|
|
gradeList[idx].graduated = false;
|
||
|
|
res.json({ code: 0, message: '还原成功' });
|
||
|
|
} else {
|
||
|
|
res.json({ code: 1, message: '未找到该年级' });
|
||
|
|
}
|
||
|
|
},
|
||
|
|
};
|