feat: 多班级版 v2.0 - Go后端重写 + 43轮代码审查

- 后端从 Python FastAPI 重写为 Go Gin(端口 56789)
- 多班级完全隔离
- 超级管理员独立登录
- 课代表作业管理、排行榜分项排行
- 角色加减分上下限可配置
- 家长改密功能(可开关)
- 周度/月度重置功能
- MySQL 5.7 兼容
- 43轮代码审查+全部修复
- Apache 2.0 许可证
This commit is contained in:
2026-06-22 10:06:10 +08:00
parent 4084afc53c
commit d6dec878bd
214 changed files with 12622 additions and 9725 deletions

View File

@@ -0,0 +1,230 @@
// ===========================================
// 多班级版班级管理系统 - Go 后端
//
// 开发者: Canglan
// 联系方式: admin@sea-studio.top
// 版权归属: Sea Network Technology Studio
// 许可证: Apache License 2.0
//
// 版权所有 © Sea Network Technology Studio
// ===========================================
package handler
import (
"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"
)
// SemesterHandler 学期管理处理器
type SemesterHandler struct {
semesterService *service.SemesterService
}
// NewSemesterHandler 创建学期管理处理器
func NewSemesterHandler(semesterService *service.SemesterService) *SemesterHandler {
return &SemesterHandler{semesterService: semesterService}
}
// SemesterList 学期列表
func (h *SemesterHandler) SemesterList(c *gin.Context) {
result, err := h.semesterService.ListSemesters()
if err != nil {
response.InternalError(c, "获取学期列表失败")
return
}
response.Success(c, result, "操作成功")
}
// ActiveSemester 当前学期
func (h *SemesterHandler) ActiveSemester(c *gin.Context) {
semester, err := h.semesterService.GetActiveSemester()
if err != nil {
response.Success(c, nil, "无活跃学期")
return
}
response.Success(c, semester, "操作成功")
}
// SemesterCreate 创建学期
func (h *SemesterHandler) SemesterCreate(c *gin.Context) {
var req schema.SemesterCreateRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "参数错误")
return
}
result, err := h.semesterService.CreateSemester(req.SemesterName, req.StartDate, req.EndDate)
if err != nil {
response.InternalError(c, err.Error())
return
}
if success, _ := result["success"].(bool); !success {
response.BadRequest(c, result["message"].(string))
return
}
response.Success(c, result, "操作成功")
}
// ActivateSemester 激活学期
func (h *SemesterHandler) ActivateSemester(c *gin.Context) {
semesterID, ok := parseID(c, "semester_id")
if !ok {
return
}
if err := h.semesterService.ActivateSemester(semesterID); err != nil {
response.BadRequest(c, err.Error())
return
}
response.SuccessWithMessage(c, "已设为当前学期")
}
// SemesterUpdate 编辑学期
func (h *SemesterHandler) SemesterUpdate(c *gin.Context) {
semesterID, ok := parseID(c, "semester_id")
if !ok {
return
}
var req schema.SemesterUpdateRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "参数错误")
return
}
if err := h.semesterService.UpdateSemester(semesterID, req.SemesterName, req.StartDate, req.EndDate); err != nil {
response.BadRequest(c, err.Error())
return
}
response.SuccessWithMessage(c, "更新成功")
}
// SemesterDelete 删除学期
func (h *SemesterHandler) SemesterDelete(c *gin.Context) {
semesterID, ok := parseID(c, "semester_id")
if !ok {
return
}
if err := h.semesterService.DeleteSemester(semesterID); err != nil {
response.BadRequest(c, err.Error())
return
}
response.SuccessWithMessage(c, "删除成功")
}
// AssociateRecords 关联记录
func (h *SemesterHandler) AssociateRecords(c *gin.Context) {
semesterID, ok := parseID(c, "semester_id")
if !ok {
return
}
result, err := h.semesterService.AssociateRecords(semesterID)
if err != nil {
response.InternalError(c, err.Error())
return
}
if success, _ := result["success"].(bool); !success {
response.BadRequest(c, result["message"].(string))
return
}
response.Success(c, result, "操作成功")
}
// ArchiveSemester 归档学期
func (h *SemesterHandler) ArchiveSemester(c *gin.Context) {
semesterID, ok := parseID(c, "semester_id")
if !ok {
return
}
classID := parseQueryParamInt(c, "class_id", 0)
resetScores := c.Query("reset_scores") == "true"
result, err := h.semesterService.ArchiveSemester(semesterID, classID, resetScores)
if err != nil {
response.InternalError(c, err.Error())
return
}
if success, _ := result["success"].(bool); !success {
response.BadRequest(c, result["message"].(string))
return
}
response.Success(c, result, "操作成功")
}
// GetArchiveData 归档数据
func (h *SemesterHandler) GetArchiveData(c *gin.Context) {
semesterID, ok := parseID(c, "semester_id")
if !ok {
return
}
classID := parseQueryParamInt(c, "class_id", 0)
page := parseQueryParamInt(c, "page", 1)
pageSize := parseQueryParamInt(c, "page_size", 20)
result, err := h.semesterService.GetArchiveRecords(semesterID, classID, page, pageSize)
if err != nil {
response.InternalError(c, err.Error())
return
}
response.Success(c, result, "操作成功")
}
// PeriodReset 手动触发周/月重置
func (h *SemesterHandler) PeriodReset(c *gin.Context) {
var req schema.PeriodResetRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "参数错误")
return
}
classID := middleware.GetClassID(c)
if classID == 0 {
response.BadRequest(c, "未指定班级")
return
}
userID := middleware.GetUserID(c)
realName := middleware.GetRealName(c)
ip := c.ClientIP()
if err := h.semesterService.PeriodReset(classID, req.Period, userID, realName, ip); err != nil {
response.InternalError(c, err.Error())
return
}
response.SuccessWithMessage(c, service.PeriodLabelCN(req.Period)+"重置成功")
}
// GetPeriodArchives 查看周期归档数据
func (h *SemesterHandler) GetPeriodArchives(c *gin.Context) {
var req schema.PeriodArchiveQuery
if err := c.ShouldBindQuery(&req); err != nil {
response.BadRequest(c, "参数错误")
return
}
classID := middleware.GetClassID(c)
if classID == 0 {
response.BadRequest(c, "未指定班级")
return
}
result, err := h.semesterService.GetPeriodArchives(classID, req.Period, req.Page, req.PageSize)
if err != nil {
response.InternalError(c, err.Error())
return
}
response.Success(c, result, "操作成功")
}