// =========================================== // 多班级版班级管理系统 - Go 后端 // // 开发者: Canglan // 联系方式: admin@sea-studio.top // 版权归属: Sea Network Technology Studio // 许可证: Apache License 2.0 // // 版权所有 © Sea Network Technology Studio // =========================================== package handler import ( "encoding/json" "io" "strconv" "github.com/gin-gonic/gin" "hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/middleware" "hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/schema" "hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/service" "hz-gitea.sea-studio.top/canglan/SharedClassManager/pkg/response" ) // AdminHandler 管理端处理器 type AdminHandler struct { adminService *service.AdminService conductService *service.ConductService attendanceSvc *service.AttendanceService rankingService *service.RankingService logService *service.LogService } // NewAdminHandler 创建管理端处理器 func NewAdminHandler( adminService *service.AdminService, conductService *service.ConductService, attendanceSvc *service.AttendanceService, rankingService *service.RankingService, logService *service.LogService, ) *AdminHandler { return &AdminHandler{ adminService: adminService, conductService: conductService, attendanceSvc: attendanceSvc, rankingService: rankingService, logService: logService, } } // ========== 学生管理 ========== // GetDormitories 获取宿舍号列表 func (h *AdminHandler) GetDormitories(c *gin.Context) { classID := middleware.GetClassID(c) if classID == 0 { response.BadRequest(c, "请先选择班级") return } dormitories, err := h.adminService.GetDormitories(classID) if err != nil { response.InternalError(c, "获取宿舍号列表失败") return } response.Success(c, gin.H{"dormitories": dormitories}, "操作成功") } // StudentList 获取学生列表 func (h *AdminHandler) StudentList(c *gin.Context) { classID := middleware.GetClassID(c) if classID == 0 { response.BadRequest(c, "请先选择班级") return } var query schema.StudentListQuery if err := c.ShouldBindQuery(&query); err != nil { response.BadRequest(c, "参数错误") return } result, err := h.adminService.GetStudents(classID, query.Page, query.PageSize, query.Search, query.DormitoryNumber) if err != nil { response.InternalError(c, "获取学生列表失败") return } response.Success(c, result, "操作成功") } // StudentImport 批量导入学生 func (h *AdminHandler) StudentImport(c *gin.Context) { classID := middleware.GetClassID(c) if classID == 0 { response.BadRequest(c, "请先选择班级") return } file, _, err := c.Request.FormFile("file") if err != nil { response.BadRequest(c, "请上传文件") return } defer file.Close() limitedReader := io.LimitReader(file, 5*1024*1024) content, err := io.ReadAll(limitedReader) if err != nil { response.BadRequest(c, "读取文件失败") return } var data struct { Students []map[string]interface{} `json:"students"` } if err := json.Unmarshal(content, &data); err != nil { response.BadRequest(c, "JSON格式错误") return } if len(data.Students) == 0 { response.BadRequest(c, "文件中没有学生数据") return } result, err := h.adminService.ImportStudents(data.Students, classID) if err != nil { response.InternalError(c, "导入失败") return } response.Success(c, result, "操作成功") } // StudentCreate 新增学生 func (h *AdminHandler) StudentCreate(c *gin.Context) { classID := middleware.GetClassID(c) if classID == 0 { response.BadRequest(c, "请先选择班级") return } var req schema.StudentCreateRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "参数错误") return } result, err := h.adminService.AddStudent(req.StudentNo, req.Name, req.ParentAccount, classID, req.DormitoryNumber) if err != nil { response.InternalError(c, err.Error()) return } if success, _ := result["success"].(bool); !success { msg, _ := result["message"].(string) if msg == "" { msg = "操作失败" } response.BadRequest(c, msg) return } response.Success(c, result, "学生添加成功") } // StudentUpdate 编辑学生 func (h *AdminHandler) StudentUpdate(c *gin.Context) { studentID, ok := parseID(c, "student_id") if !ok { return } classID := middleware.GetClassID(c) var req schema.StudentUpdateRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "参数错误") return } if err := h.adminService.UpdateStudent(studentID, req.Name, req.ParentAccount, req.DormitoryNumber, classID); err != nil { response.InternalError(c, err.Error()) return } response.SuccessWithMessage(c, "更新成功") } // StudentDelete 删除学生 func (h *AdminHandler) StudentDelete(c *gin.Context) { studentID, ok := parseID(c, "student_id") if !ok { return } classID := middleware.GetClassID(c) if err := h.adminService.DeleteStudent(studentID, classID); err != nil { response.InternalError(c, err.Error()) return } response.SuccessWithMessage(c, "删除成功") } // ResetStudentPassword 重置学生密码 func (h *AdminHandler) ResetStudentPassword(c *gin.Context) { studentID, ok := parseID(c, "student_id") if !ok { return } var req schema.ResetPasswordRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "参数错误") return } if err := h.adminService.ResetStudentPassword(studentID, req.NewPassword); err != nil { response.InternalError(c, err.Error()) return } response.SuccessWithMessage(c, "密码重置成功") } // ========== 操行分管理 ========== // AddConductPoints 批量加减分 func (h *AdminHandler) AddConductPoints(c *gin.Context) { var req schema.ConductAddRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "参数错误") return } classID := middleware.GetClassID(c) userID := middleware.GetUserID(c) realName := middleware.GetRealName(c) result, err := h.conductService.AddPoints( req.StudentIDs, req.PointsChange, req.Reason, userID, realName, classID, req.RelatedType, ) if err != nil { response.InternalError(c, err.Error()) return } if success, _ := result["success"].(bool); !success { msg, _ := result["message"].(string) if msg == "" { msg = "操作失败" } response.BadRequest(c, msg) return } response.Success(c, result, "操作成功") } // RevokeConductRecord 撤销记录 func (h *AdminHandler) RevokeConductRecord(c *gin.Context) { var req schema.RevokeRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "参数错误") return } userID := middleware.GetUserID(c) classID := middleware.GetClassID(c) result, err := h.conductService.RevokeRecord(req.RecordID, userID, classID) if err != nil { response.InternalError(c, err.Error()) return } if success, _ := result["success"].(bool); !success { msg, _ := result["message"].(string) if msg == "" { msg = "操作失败" } response.BadRequest(c, msg) return } response.SuccessWithMessage(c, "撤销成功") } // RestoreConductRecord 反撤销记录 func (h *AdminHandler) RestoreConductRecord(c *gin.Context) { var req schema.RevokeRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "参数错误") return } userID := middleware.GetUserID(c) classID := middleware.GetClassID(c) result, err := h.conductService.RestoreRecord(req.RecordID, userID, classID) if err != nil { response.InternalError(c, err.Error()) return } if success, _ := result["success"].(bool); !success { msg, _ := result["message"].(string) if msg == "" { msg = "操作失败" } response.BadRequest(c, msg) return } response.SuccessWithMessage(c, "反撤销成功") } // GetConductHistory 操行分历史 func (h *AdminHandler) GetConductHistory(c *gin.Context) { classID := middleware.GetClassID(c) var query schema.ConductHistoryQuery if err := c.ShouldBindQuery(&query); err != nil { response.BadRequest(c, "参数错误") return } result, err := h.conductService.GetHistory( classID, query.StudentID, query.Page, query.PageSize, query.StartDate, query.EndDate, query.RelatedType, query.ReasonPrefix, query.IsRevoked, query.ReasonSearch, ) if err != nil { response.InternalError(c, err.Error()) return } response.Success(c, result, "操作成功") } // BatchRevokeConductRecords 批量撤销 func (h *AdminHandler) BatchRevokeConductRecords(c *gin.Context) { var req schema.BatchRevokeRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "参数错误") return } userID := middleware.GetUserID(c) classID := middleware.GetClassID(c) successCount := 0 failCount := 0 var errors []map[string]interface{} for _, recordID := range req.RecordIDs { result, _ := h.conductService.RevokeRecord(recordID, userID, classID) if result != nil { if success, _ := result["success"].(bool); success { successCount++ } else { failCount++ msg, _ := result["message"].(string) errors = append(errors, map[string]interface{}{"record_id": recordID, "error": msg}) } } else { failCount++ errors = append(errors, map[string]interface{}{"record_id": recordID, "error": "撤销失败"}) } } response.Success(c, gin.H{ "success_count": successCount, "fail_count": failCount, "errors": errors, }, "批量撤销完成") } // BatchRestoreConductRecords 批量反撤销 func (h *AdminHandler) BatchRestoreConductRecords(c *gin.Context) { var req schema.BatchRevokeRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "参数错误") return } userID := middleware.GetUserID(c) classID := middleware.GetClassID(c) successCount := 0 failCount := 0 var errors []map[string]interface{} for _, recordID := range req.RecordIDs { result, _ := h.conductService.RestoreRecord(recordID, userID, classID) if result != nil { if success, _ := result["success"].(bool); success { successCount++ } else { failCount++ msg, _ := result["message"].(string) errors = append(errors, map[string]interface{}{"record_id": recordID, "error": msg}) } } else { failCount++ errors = append(errors, map[string]interface{}{"record_id": recordID, "error": "反撤销失败"}) } } response.Success(c, gin.H{ "success_count": successCount, "fail_count": failCount, "errors": errors, }, "批量反撤销完成") } // ========== 考勤管理 ========== // CreateAttendanceRecord 添加考勤 func (h *AdminHandler) CreateAttendanceRecord(c *gin.Context) { var req schema.AttendanceCreateRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "参数错误") return } userID := middleware.GetUserID(c) classID := middleware.GetClassID(c) result, err := h.attendanceSvc.CreateRecord( req.StudentID, req.Date, req.Slot, req.Status, &req.Reason, req.ApplyDeduction, req.CustomDeduction, userID, classID, ) if err != nil { response.InternalError(c, err.Error()) return } if success, _ := result["success"].(bool); !success { msg, _ := result["message"].(string) if msg == "" { msg = "操作失败" } response.BadRequest(c, msg) return } msg, _ := result["message"].(string) if msg == "" { msg = "操作成功" } response.SuccessWithMessage(c, msg) } // GetAttendanceRecords 获取考勤记录 func (h *AdminHandler) GetAttendanceRecords(c *gin.Context) { classID := middleware.GetClassID(c) var query schema.AttendanceQuery if err := c.ShouldBindQuery(&query); err != nil { response.BadRequest(c, "参数错误") return } result, err := h.attendanceSvc.GetRecords(classID, query.Date, query.StudentID, query.Slot) if err != nil { response.InternalError(c, err.Error()) return } response.Success(c, result, "操作成功") } // ========== 管理员管理 ========== // AdminList 管理员列表 func (h *AdminHandler) AdminList(c *gin.Context) { classID := middleware.GetClassID(c) result, err := h.adminService.GetAdmins(classID) if err != nil { response.InternalError(c, "获取管理员列表失败") return } response.Success(c, result, "操作成功") } // AdminCreate 添加管理员 func (h *AdminHandler) AdminCreate(c *gin.Context) { classID := middleware.GetClassID(c) if classID == 0 { response.BadRequest(c, "请先选择班级") return } var req schema.AdminCreateRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "参数错误") return } result, err := h.adminService.AddAdmin(req.Username, req.RealName, req.Password, req.RoleType, classID, req.SubjectID) if err != nil { response.InternalError(c, err.Error()) return } if success, _ := result["success"].(bool); !success { msg, _ := result["message"].(string) if msg == "" { msg = "操作失败" } response.BadRequest(c, msg) return } response.Success(c, result, "管理员添加成功") } // AdminUpdate 更新管理员 func (h *AdminHandler) AdminUpdate(c *gin.Context) { userID, ok := parseID(c, "user_id") if !ok { return } classID := middleware.GetClassID(c) var req schema.AdminUpdateRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "参数错误") return } if err := h.adminService.UpdateAdmin(userID, req.RealName, req.RoleType, classID, req.SubjectID); err != nil { response.InternalError(c, err.Error()) return } response.SuccessWithMessage(c, "更新成功") } // AdminDelete 删除管理员 func (h *AdminHandler) AdminDelete(c *gin.Context) { userID, ok := parseID(c, "user_id") if !ok { return } classID := middleware.GetClassID(c) if err := h.adminService.DeleteAdmin(userID, classID); err != nil { response.InternalError(c, err.Error()) return } response.SuccessWithMessage(c, "删除成功") } // AdminResetPassword 重置管理员密码 func (h *AdminHandler) AdminResetPassword(c *gin.Context) { userID, ok := parseID(c, "user_id") if !ok { return } var req schema.ResetPasswordRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "参数错误") return } if err := h.adminService.ResetAdminPassword(userID, req.NewPassword); err != nil { response.InternalError(c, err.Error()) return } response.SuccessWithMessage(c, "密码重置成功") } // UnlockAccount 解除登录锁定 func (h *AdminHandler) UnlockAccount(c *gin.Context) { var req schema.UnlockUserRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "参数错误") return } if err := h.adminService.UnlockAccount(req.Username, c.ClientIP()); err != nil { response.InternalError(c, "解锁失败") return } response.SuccessWithMessage(c, "解锁成功") } // GetRankings 分项排行榜 func (h *AdminHandler) GetRankings(c *gin.Context) { classID := middleware.GetClassID(c) if classID == 0 { response.BadRequest(c, "请先选择班级") return } rankType := c.DefaultQuery("type", "all") limit, _ := strconv.Atoi(c.DefaultQuery("limit", "50")) if limit <= 0 { limit = 50 } if limit > 500 { limit = 500 } result, err := h.rankingService.GetRankings(classID, rankType, limit) if err != nil { response.InternalError(c, err.Error()) return } response.Success(c, result, "操作成功") }