feat: 多班级版班级管理系统 v2.0

技术栈:Go (Gin + GORM) + PHP + MySQL 5.7 + Redis

主要功能:
- 多班级完全隔离(class_id 贯穿全系统)
- 后端 Go Gin(端口 56789),Nginx 反代
- 超级管理员独立登录(env 配置,默认账密 admin/Admin123)
- bcrypt 密码加密(无 PASSWORD_SALT)
- 科任老师/课代表新角色
- 课代表作业管理页面
- 排行榜分项排行(操行分/考勤/作业)
- 角色加减分上下限由班主任配置
- 家长改密功能(可开关)
- 班级角色按需开关
- 宿舍号格式:南0-000
- 周度/月度重置功能
- MySQL 5.7 兼容
- 43 轮代码审查 + 全部修复

开发者: Canglan
版权归属: Sea Network Technology Studio
许可证: Apache License 2.0
This commit is contained in:
2026-06-22 10:21:52 +08:00
commit 16059ad3bf
135 changed files with 19933 additions and 0 deletions

View File

@@ -0,0 +1,206 @@
// ===========================================
// 多班级版班级管理系统 - Go 后端
//
// 开发者: Canglan
// 联系方式: admin@sea-studio.top
// 版权归属: Sea Network Technology Studio
// 许可证: Apache License 2.0
//
// 版权所有 © Sea Network Technology Studio
// ===========================================
package router
import (
"github.com/gin-gonic/gin"
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/config"
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/handler"
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/middleware"
"hz-gitea.sea-studio.top/canglan/SharedClassManager/pkg/response"
)
// Handlers 聚合所有 HTTP 处理器
type Handlers struct {
Auth *handler.AuthHandler
Admin *handler.AdminHandler
Student *handler.StudentHandler
Parent *handler.ParentHandler
Subject *handler.SubjectHandler
Semester *handler.SemesterHandler
Class *handler.ClassHandler
Config *handler.ConfigHandler
SuperAdmin *handler.SuperAdminHandler
Cadre *handler.CadreHandler
}
// SetupRouter 注册所有路由,返回 Gin 引擎
func SetupRouter(cfg *config.Config, h *Handlers) *gin.Engine {
if cfg.IsProduction() {
gin.SetMode(gin.ReleaseMode)
}
r := gin.New()
// ========== 全局中间件 ==========
// CORS 说明:生产环境通过 Nginx 反代实现同源策略API 与前端同域,无需额外 CORS 配置。
// 若需要直接访问 API绕过 Nginx需在此添加 CORS 中间件。
r.Use(middleware.AccessLog())
r.Use(gin.Recovery())
r.Use(middleware.Sanitize())
// ========== 公开路由组(不需要认证) ==========
public := r.Group("/api")
{
public.POST("/auth/login", h.Auth.Login)
}
// ========== 超级管理员独立登录(路径可配置) ==========
superAdminPath := "/api" + cfg.SuperAdminLoginPath
middleware.RegisterPublicPath(superAdminPath + "/login")
superAdmin := r.Group(superAdminPath)
{
superAdmin.POST("/login", h.SuperAdmin.Login)
}
// ========== 需认证的路由组 ==========
authRequired := r.Group("/api")
authRequired.Use(middleware.AuthRequired())
{
// 扣分规则(需认证)
authRequired.GET("/config/deduction-rules", h.Config.GetDeductionRules)
// 认证相关
authRequired.POST("/auth/logout", h.Auth.Logout)
authRequired.POST("/auth/change-password", h.Auth.ChangePassword)
authRequired.GET("/auth/me", h.Auth.GetUserInfo)
// 学生端
student := authRequired.Group("/student")
{
student.GET("/conduct/:student_id", h.Student.ConductHistory)
student.GET("/homework/:student_id", h.Student.Homework)
student.GET("/attendance/:student_id", h.Student.Attendance)
student.GET("/ranking", h.Student.Ranking)
student.GET("/my-info", h.Student.MyInfo)
student.GET("/semester-records", h.Student.SemesterRecords)
}
// 家长端
parent := authRequired.Group("/parent")
{
parent.GET("/child/conduct", h.Parent.Dashboard)
parent.GET("/child/attendance", h.Parent.Attendance)
parent.GET("/child/ranking", h.Parent.Ranking)
parent.GET("/child/history", h.Parent.History)
parent.POST("/password", h.Parent.ChangePassword)
}
// 管理端
admin := authRequired.Group("/admin")
admin.Use(middleware.RequireRole("admin", "super_admin"))
{
// 学生管理
admin.GET("/students/dormitories", h.Admin.GetDormitories)
admin.GET("/students", h.Admin.StudentList)
admin.POST("/students/import", h.Admin.StudentImport)
admin.POST("/students", h.Admin.StudentCreate)
admin.PUT("/students/:student_id", h.Admin.StudentUpdate)
admin.DELETE("/students/:student_id", h.Admin.StudentDelete)
admin.POST("/students/reset-password/:student_id", h.Admin.ResetStudentPassword)
// 操行分管理
admin.POST("/conduct/add", h.Admin.AddConductPoints)
admin.POST("/conduct/revoke", h.Admin.RevokeConductRecord)
admin.POST("/conduct/restore", h.Admin.RestoreConductRecord)
admin.GET("/conduct/history", h.Admin.GetConductHistory)
admin.POST("/conduct/batch-revoke", h.Admin.BatchRevokeConductRecords)
admin.POST("/conduct/batch-restore", h.Admin.BatchRestoreConductRecords)
// 考勤管理
admin.POST("/attendance", h.Admin.CreateAttendanceRecord)
admin.GET("/attendance/records", h.Admin.GetAttendanceRecords)
// 管理员管理
admin.POST("/add", h.Admin.AdminCreate)
admin.GET("/list", h.Admin.AdminList)
admin.PUT("/update/:user_id", h.Admin.AdminUpdate)
admin.DELETE("/delete/:user_id", h.Admin.AdminDelete)
admin.POST("/reset-password/:user_id", h.Admin.AdminResetPassword)
admin.POST("/unlock-user", h.Admin.UnlockAccount)
// 排行榜分项(新增)
admin.GET("/rankings", h.Admin.GetRankings)
}
// 科目管理
subject := authRequired.Group("/subject")
subject.Use(middleware.RequireRole("admin", "super_admin"))
{
subject.GET("/list", h.Subject.SubjectList)
subject.POST("/create", h.Subject.SubjectCreate)
subject.PUT("/update/:subject_id", h.Subject.SubjectUpdate)
subject.PUT("/toggle/:subject_id", h.Subject.SubjectToggle)
subject.DELETE("/delete/:subject_id", h.Subject.SubjectDelete)
}
// 学期管理
semester := authRequired.Group("/semester")
semester.Use(middleware.RequireRole("admin", "super_admin"))
{
semester.GET("/list", h.Semester.SemesterList)
semester.GET("/active", h.Semester.ActiveSemester)
semester.POST("/create", h.Semester.SemesterCreate)
semester.PUT("/activate/:semester_id", h.Semester.ActivateSemester)
semester.PUT("/update/:semester_id", h.Semester.SemesterUpdate)
semester.DELETE("/delete/:semester_id", h.Semester.SemesterDelete)
semester.POST("/:semester_id/associate", h.Semester.AssociateRecords)
semester.POST("/archive/:semester_id", h.Semester.ArchiveSemester)
semester.GET("/archive/:semester_id/records", h.Semester.GetArchiveData)
semester.POST("/period-reset", h.Semester.PeriodReset)
semester.GET("/period-archives", h.Semester.GetPeriodArchives)
}
// 班级管理
classGroup := authRequired.Group("/class")
classGroup.Use(middleware.RequireRole("admin", "super_admin"))
{
classGroup.GET("/list", h.Class.ClassList)
classGroup.GET("/:class_id", h.Class.ClassDetail)
classGroup.POST("/create", h.Class.ClassCreate)
classGroup.PUT("/update/:class_id", h.Class.ClassUpdate)
classGroup.DELETE("/delete/:class_id", h.Class.ClassDelete)
classGroup.POST("/switch", h.Class.SwitchClass)
classGroup.POST("/settings", h.Class.SaveSetting)
classGroup.GET("/settings", h.Class.GetSettings)
classGroup.GET("/point-limits", h.Class.GetPointLimits)
classGroup.POST("/point-limits", h.Class.SavePointLimits)
classGroup.GET("/features", h.Class.GetFeatures)
classGroup.POST("/features", h.Class.SaveFeature)
}
// 课代表路由(新增)
cadre := authRequired.Group("/cadre")
cadre.Use(middleware.RequireRole("课代表"))
{
cadre.GET("/homework", h.Cadre.HomeworkList)
cadre.POST("/homework", h.Cadre.HomeworkSubmit)
cadre.POST("/conduct/add", h.Cadre.AddConductPoints)
}
}
// ========== 系统路由 ==========
r.GET("/", func(c *gin.Context) {
response.Success(c, gin.H{
"app": cfg.AppName,
"version": "2.0",
"status": "running",
}, "服务运行中")
})
r.GET("/health", func(c *gin.Context) {
response.Success(c, gin.H{"status": "ok"}, "健康检查通过")
})
return r
}