feat: 多班级版班级管理系统 v2.0
技术栈:Go (Gin + GORM) + PHP + MySQL 5.7 + Redis 主要功能: - 多班级完全隔离(class_id 贯穿全系统) - 后端从 Python FastAPI 重写为 Go Gin(端口 56789) - 超级管理员独立登录(env 配置路径,默认账密 admin/Admin123) - 科任老师/课代表新角色 - 课代表作业管理页面 - 排行榜分项排行(操行分/考勤/作业) - 角色加减分上下限由班主任配置 - 家长改密功能(可开关) - 班级角色按需开关 - 宿舍号格式:南0-000 - 周度/月度重置功能 - MySQL 5.7 兼容 - Nginx 反向代理部署 开发者: Canglan 版权归属: Sea Network Technology Studio 许可证: Apache License 2.0
This commit is contained in:
271
backend-go/internal/handler/class_handler.go
Normal file
271
backend-go/internal/handler/class_handler.go
Normal file
@@ -0,0 +1,271 @@
|
||||
// ===========================================
|
||||
// 多班级版班级管理系统 - 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"
|
||||
)
|
||||
|
||||
// ClassHandler 班级管理处理器
|
||||
type ClassHandler struct {
|
||||
classService *service.ClassService
|
||||
}
|
||||
|
||||
// NewClassHandler 创建班级管理处理器
|
||||
func NewClassHandler(classService *service.ClassService) *ClassHandler {
|
||||
return &ClassHandler{classService: classService}
|
||||
}
|
||||
|
||||
// ClassList 班级列表
|
||||
func (h *ClassHandler) ClassList(c *gin.Context) {
|
||||
includeDisabled := c.Query("include_disabled") == "true"
|
||||
result, err := h.classService.ListClasses(includeDisabled)
|
||||
if err != nil {
|
||||
response.InternalError(c, "获取班级列表失败")
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// ClassDetail 班级详情
|
||||
func (h *ClassHandler) ClassDetail(c *gin.Context) {
|
||||
classID, ok := parseID(c, "class_id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.classService.GetClassDetail(classID)
|
||||
if err != nil {
|
||||
response.NotFound(c, "班级不存在")
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// ClassCreate 创建班级
|
||||
func (h *ClassHandler) ClassCreate(c *gin.Context) {
|
||||
var req schema.ClassCreateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.classService.CreateClass(req.ClassName, req.Grade, req.Description)
|
||||
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, "班级创建成功")
|
||||
}
|
||||
|
||||
// ClassUpdate 更新班级
|
||||
func (h *ClassHandler) ClassUpdate(c *gin.Context) {
|
||||
classID, ok := parseID(c, "class_id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
var req schema.ClassUpdateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.classService.UpdateClass(classID, req.ClassName, req.Grade, req.Description, req.Status); err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.SuccessWithMessage(c, "更新成功")
|
||||
}
|
||||
|
||||
// ClassDelete 删除班级
|
||||
func (h *ClassHandler) ClassDelete(c *gin.Context) {
|
||||
classID, ok := parseID(c, "class_id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.classService.DeleteClass(classID); err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.SuccessWithMessage(c, "删除成功")
|
||||
}
|
||||
|
||||
// SwitchClass 切换班级上下文
|
||||
func (h *ClassHandler) SwitchClass(c *gin.Context) {
|
||||
var req schema.SwitchClassRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
userID := middleware.GetUserID(c)
|
||||
result, err := h.classService.SwitchClass(userID, req.ClassID)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "切换成功")
|
||||
}
|
||||
|
||||
// GetSettings 获取班级设置
|
||||
func (h *ClassHandler) GetSettings(c *gin.Context) {
|
||||
classID := middleware.GetClassID(c)
|
||||
result, err := h.classService.GetSettings(classID)
|
||||
if err != nil {
|
||||
response.InternalError(c, "获取设置失败")
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// allowedSettingKeys 允许通过 SaveSetting 端点写入的配置键白名单
|
||||
var allowedSettingKeys = map[string]bool{
|
||||
"initial_password": true,
|
||||
"initial_points": true,
|
||||
"deduction_attendance_absent": true,
|
||||
"deduction_attendance_late": true,
|
||||
"deduction_attendance_leave": true,
|
||||
"deduction_homework_not_submit": true,
|
||||
"deduction_homework_late": true,
|
||||
"reset_frequency": true,
|
||||
"reset_day_of_week": true,
|
||||
"reset_day_of_month": true,
|
||||
}
|
||||
|
||||
// SaveSetting 保存班级设置
|
||||
func (h *ClassHandler) SaveSetting(c *gin.Context) {
|
||||
classID := middleware.GetClassID(c)
|
||||
|
||||
var req schema.SettingRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
if !allowedSettingKeys[req.SettingKey] {
|
||||
response.BadRequest(c, "不允许的配置项: "+req.SettingKey)
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.classService.SaveSetting(classID, req.SettingKey, req.SettingValue); err != nil {
|
||||
response.InternalError(c, "保存设置失败")
|
||||
return
|
||||
}
|
||||
response.SuccessWithMessage(c, "保存成功")
|
||||
}
|
||||
|
||||
// GetPointLimits 获取角色加减分配置
|
||||
func (h *ClassHandler) GetPointLimits(c *gin.Context) {
|
||||
classID := middleware.GetClassID(c)
|
||||
result, err := h.classService.GetSettings(classID)
|
||||
if err != nil {
|
||||
response.InternalError(c, "获取配置失败")
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// allowedPointLimitKeys 允许的操行分限制配置键白名单(与 conduct_service 读取 key 一致)
|
||||
var allowedPointLimitKeys = map[string]bool{
|
||||
"point_limit_班长_max": true,
|
||||
"point_limit_班长_min": true,
|
||||
"point_limit_学习委员_max": true,
|
||||
"point_limit_学习委员_min": true,
|
||||
"point_limit_考勤委员_max": true,
|
||||
"point_limit_考勤委员_min": true,
|
||||
"point_limit_劳动委员_max": true,
|
||||
"point_limit_劳动委员_min": true,
|
||||
"point_limit_志愿委员_max": true,
|
||||
"point_limit_志愿委员_min": true,
|
||||
"point_limit_科任老师_max": true,
|
||||
"point_limit_科任老师_min": true,
|
||||
}
|
||||
|
||||
// SavePointLimits 保存角色加减分配置
|
||||
func (h *ClassHandler) SavePointLimits(c *gin.Context) {
|
||||
classID := middleware.GetClassID(c)
|
||||
|
||||
var req map[string]string
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
for key, value := range req {
|
||||
if !allowedPointLimitKeys[key] {
|
||||
response.BadRequest(c, "不允许的配置项: "+key)
|
||||
return
|
||||
}
|
||||
if err := h.classService.SaveSetting(classID, key, value); err != nil {
|
||||
response.InternalError(c, "保存配置失败")
|
||||
return
|
||||
}
|
||||
}
|
||||
response.SuccessWithMessage(c, "保存成功")
|
||||
}
|
||||
|
||||
// GetFeatures 获取功能开关
|
||||
func (h *ClassHandler) GetFeatures(c *gin.Context) {
|
||||
classID := middleware.GetClassID(c)
|
||||
result, err := h.classService.GetFeatures(classID)
|
||||
if err != nil {
|
||||
response.InternalError(c, "获取功能开关失败")
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// allowedFeatureKeys 允许的功能开关键白名单
|
||||
var allowedFeatureKeys = map[string]bool{
|
||||
"parent_account_enabled": true,
|
||||
"parent_password_change_enabled": true,
|
||||
"parent_view_attendance": true,
|
||||
"parent_view_ranking": true,
|
||||
"student_view_ranking": true,
|
||||
"homework_management": true,
|
||||
"attendance_management": true,
|
||||
"cadre_homework": true,
|
||||
}
|
||||
|
||||
// SaveFeature 保存功能开关
|
||||
func (h *ClassHandler) SaveFeature(c *gin.Context) {
|
||||
classID := middleware.GetClassID(c)
|
||||
|
||||
var req schema.FeatureToggleRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
if !allowedFeatureKeys[req.FeatureKey] {
|
||||
response.BadRequest(c, "不允许的功能开关: "+req.FeatureKey)
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.classService.SaveFeature(classID, req.FeatureKey, req.Enabled); err != nil {
|
||||
response.InternalError(c, "保存功能开关失败")
|
||||
return
|
||||
}
|
||||
response.SuccessWithMessage(c, "保存成功")
|
||||
}
|
||||
Reference in New Issue
Block a user