diff --git a/backend/services/admin_service.py b/backend/services/admin_service.py index c9ce11b..8134ea4 100644 --- a/backend/services/admin_service.py +++ b/backend/services/admin_service.py @@ -72,62 +72,81 @@ class AdminService: operator_id: int, initial_points: int = 60 ) -> Dict[str, Any]: - """批量导入学生""" + """批量导入学生(优化版:预查重 + 批量操作)""" results = [] success_count = 0 + # 预查重:一次性获取所有已存在的学号和手机号 + existing_students = await StudentModel.get_all() + existing_student_nos = {s["student_no"] for s in existing_students} + + all_users = await execute_query("SELECT username FROM users WHERE status = 1") + existing_usernames = {u["username"] for u in all_users} + for student in students: - student_no = student.get("student_no", "").strip() - name = student.get("name", "").strip() - parent_phone = student.get("parent_phone", "").strip() - password = student.get("password", "").strip() - - if not student_no or not name: - results.append({"student_no": student_no, "success": False, "error": "学号或姓名不能为空"}) - continue - - if not security.validate_student_no(student_no): - results.append({"student_no": student_no, "success": False, "error": "学号格式错误"}) - continue - - if parent_phone and not security.validate_phone(parent_phone): - results.append({"student_no": student_no, "success": False, "error": "手机号格式错误"}) - continue - - existing = await StudentModel.get_by_student_no(student_no) - if existing: - results.append({"student_no": student_no, "success": False, "error": "学号已存在"}) - continue - - init_password = password if password else "123456" - - student_id = await StudentModel.create( - student_no=student_no, - name=name, - parent_phone=parent_phone if parent_phone else None, - initial_points=initial_points - ) - - await UserModel.create_student( - username=student_no, - password=init_password, - real_name=name, - student_id=student_id - ) - - if parent_phone: - parent_exists = await UserModel.get_by_username(parent_phone) - if not parent_exists: + try: + student_no = student.get("student_no", "").strip() + name = student.get("name", "").strip() + parent_phone = student.get("parent_phone", "").strip() + password = student.get("password", "").strip() + + if not student_no or not name: + results.append({"student_no": student_no, "success": False, "error": "学号或姓名不能为空"}) + continue + + if not security.validate_student_no(student_no): + results.append({"student_no": student_no, "success": False, "error": "学号格式错误"}) + continue + + if parent_phone and not security.validate_phone(parent_phone): + results.append({"student_no": student_no, "success": False, "error": "手机号格式错误"}) + continue + + if student_no in existing_student_nos: + results.append({"student_no": student_no, "success": False, "error": "学号已存在"}) + continue + + init_password = password if password else "123456" + + # 创建学生记录 + student_id = await StudentModel.create( + student_no=student_no, + name=name, + parent_phone=parent_phone if parent_phone else None, + initial_points=initial_points + ) + existing_student_nos.add(student_no) + + # 创建学生登录账号 + await UserModel.create_student( + username=student_no, + password=init_password, + real_name=name, + student_id=student_id + ) + existing_usernames.add(student_no) + + # 创建家长账号(如果手机号存在且未被注册) + if parent_phone and parent_phone not in existing_usernames: await UserModel.create_parent( username=parent_phone, password=init_password, real_name=f"{name}家长", student_id=student_id ) + existing_usernames.add(parent_phone) + + results.append({"student_no": student_no, "success": True, "student_id": student_id}) + success_count += 1 + logger.info(f"用户[{operator_id}] 导入学生: {student_no} - {name}") - results.append({"student_no": student_no, "success": True, "student_id": student_id}) - success_count += 1 - logger.info(f"用户[{operator_id}] 导入学生: {student_no} - {name}") + except Exception as e: + logger.error(f"导入学生失败: {student.get('student_no', '?')} - {str(e)}") + results.append({ + "student_no": student.get("student_no", ""), + "success": False, + "error": f"导入异常: {str(e)}" + }) return { "success": True, diff --git a/frontend/assets/js/admin.js b/frontend/assets/js/admin.js index 0c15697..449a55f 100644 --- a/frontend/assets/js/admin.js +++ b/frontend/assets/js/admin.js @@ -134,6 +134,18 @@ async function doImport() { showToast(result.message); closeModal('importModal'); loadStudents(); + + // 显示详细导入结果 + if (result.data && result.data.results) { + const failedList = result.data.results.filter(r => !r.success); + if (failedList.length > 0) { + let detail = '失败详情:\n'; + failedList.forEach(r => { + detail += `${r.student_no || '未知'}: ${r.error}\n`; + }); + alert(detail); + } + } } else { showToast(result.message, 'error'); }