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:
224
backend-go/internal/service/class_service.go
Normal file
224
backend-go/internal/service/class_service.go
Normal file
@@ -0,0 +1,224 @@
|
||||
// ===========================================
|
||||
// 多班级版班级管理系统 - Go 后端
|
||||
//
|
||||
// 开发者: Canglan
|
||||
// 联系方式: admin@sea-studio.top
|
||||
// 版权归属: Sea Network Technology Studio
|
||||
// 许可证: Apache License 2.0
|
||||
//
|
||||
// 版权所有 © Sea Network Technology Studio
|
||||
// ===========================================
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/config"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/model"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/repository"
|
||||
appJwt "hz-gitea.sea-studio.top/canglan/SharedClassManager/pkg/jwt"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/pkg/database"
|
||||
)
|
||||
|
||||
// ClassService 班级服务
|
||||
type ClassService struct {
|
||||
classRepo *repository.ClassRepo
|
||||
userRepo *repository.UserRepo
|
||||
adminRoleRepo *repository.AdminRoleRepo
|
||||
}
|
||||
|
||||
// NewClassService 创建班级服务
|
||||
func NewClassService(
|
||||
classRepo *repository.ClassRepo,
|
||||
userRepo *repository.UserRepo,
|
||||
adminRoleRepo *repository.AdminRoleRepo,
|
||||
) *ClassService {
|
||||
return &ClassService{
|
||||
classRepo: classRepo,
|
||||
userRepo: userRepo,
|
||||
adminRoleRepo: adminRoleRepo,
|
||||
}
|
||||
}
|
||||
|
||||
// ListClasses 获取班级列表
|
||||
func (s *ClassService) ListClasses(includeDisabled bool) (map[string]interface{}, error) {
|
||||
classes, err := s.classRepo.GetAll(includeDisabled)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := range classes {
|
||||
count, _ := s.classRepo.GetStudentCount(classes[i].ClassID)
|
||||
classes[i].StudentCount = count
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
"classes": classes,
|
||||
"total": len(classes),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetClassDetail 获取班级详情
|
||||
func (s *ClassService) GetClassDetail(classID int) (map[string]interface{}, error) {
|
||||
cls, err := s.classRepo.GetByID(classID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cls.StudentCount, _ = s.classRepo.GetStudentCount(classID)
|
||||
return map[string]interface{}{"class": cls}, nil
|
||||
}
|
||||
|
||||
// CreateClass 创建班级
|
||||
func (s *ClassService) CreateClass(className string, grade, description *string) (map[string]interface{}, error) {
|
||||
existing, _ := s.classRepo.GetByName(className)
|
||||
if existing != nil {
|
||||
return map[string]interface{}{"success": false, "message": "班级名称已存在"}, nil
|
||||
}
|
||||
|
||||
cls := &model.Class{
|
||||
ClassName: className,
|
||||
Grade: grade,
|
||||
Description: description,
|
||||
Status: 1,
|
||||
}
|
||||
classID, err := s.classRepo.Create(cls)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
"success": true,
|
||||
"class_id": classID,
|
||||
"message": "班级创建成功",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateClass 更新班级
|
||||
func (s *ClassService) UpdateClass(classID int, className, grade, description *string, status *int8) error {
|
||||
existing, err := s.classRepo.GetByID(classID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("班级不存在")
|
||||
}
|
||||
|
||||
updates := make(map[string]interface{})
|
||||
if className != nil && *className != existing.ClassName {
|
||||
nameExists, _ := s.classRepo.GetByName(*className)
|
||||
if nameExists != nil {
|
||||
return fmt.Errorf("班级名称已存在")
|
||||
}
|
||||
updates["class_name"] = *className
|
||||
}
|
||||
if grade != nil {
|
||||
updates["grade"] = *grade
|
||||
}
|
||||
if description != nil {
|
||||
updates["description"] = *description
|
||||
}
|
||||
if status != nil {
|
||||
updates["status"] = *status
|
||||
}
|
||||
|
||||
return s.classRepo.Update(classID, updates)
|
||||
}
|
||||
|
||||
// DeleteClass 删除班级
|
||||
func (s *ClassService) DeleteClass(classID int) error {
|
||||
hasStudents, _ := s.classRepo.HasActiveStudents(classID)
|
||||
if hasStudents {
|
||||
return fmt.Errorf("该班级下还有学生,无法删除")
|
||||
}
|
||||
return s.classRepo.Delete(classID)
|
||||
}
|
||||
|
||||
// SwitchClass 切换班级上下文(超级管理员)
|
||||
func (s *ClassService) SwitchClass(userID int, classID int) (map[string]interface{}, error) {
|
||||
cfg := config.AppConfig
|
||||
cls, err := s.classRepo.GetByID(classID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("班级不存在")
|
||||
}
|
||||
|
||||
user, err := s.userRepo.GetByUserID(userID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("用户不存在")
|
||||
}
|
||||
|
||||
// 查询目标班级中该用户的角色
|
||||
var role string
|
||||
if user.UserType == "super_admin" {
|
||||
role = "系统管理员"
|
||||
} else {
|
||||
adminRole, _ := s.adminRoleRepo.GetByUserIDAndClass(userID, classID)
|
||||
if adminRole != nil {
|
||||
role = adminRole.RoleType
|
||||
}
|
||||
}
|
||||
|
||||
// 生成新 Token,更新 class_id
|
||||
token, err := appJwt.CreateToken(
|
||||
user.UserID, user.Username, user.UserType,
|
||||
user.StudentID, role, user.RealName, &classID,
|
||||
user.NeedChangePassword == 1,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("生成令牌失败")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
_ = database.SetUserToken(ctx, userID, token, cfg.JWTIdleTimeoutMinutes)
|
||||
|
||||
return map[string]interface{}{
|
||||
"token": token,
|
||||
"class_id": classID,
|
||||
"class_name": cls.ClassName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetSettings 获取班级设置
|
||||
func (s *ClassService) GetSettings(classID int) (map[string]interface{}, error) {
|
||||
settings, err := s.classRepo.GetSettings(classID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make(map[string]string)
|
||||
for _, setting := range settings {
|
||||
result[setting.SettingKey] = setting.SettingValue
|
||||
}
|
||||
return map[string]interface{}{"settings": result}, nil
|
||||
}
|
||||
|
||||
// SaveSetting 保存班级设置
|
||||
func (s *ClassService) SaveSetting(classID int, key, value string) error {
|
||||
return s.classRepo.SaveSetting(classID, key, value)
|
||||
}
|
||||
|
||||
// GetFeatures 获取班级功能开关
|
||||
func (s *ClassService) GetFeatures(classID int) (map[string]interface{}, error) {
|
||||
features, err := s.classRepo.GetFeatures(classID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make(map[string]int8)
|
||||
for _, f := range features {
|
||||
result[f.FeatureKey] = f.Enabled
|
||||
}
|
||||
return map[string]interface{}{"features": result}, nil
|
||||
}
|
||||
|
||||
// SaveFeature 保存班级功能开关
|
||||
func (s *ClassService) SaveFeature(classID int, featureKey string, enabled int8) error {
|
||||
return s.classRepo.SaveFeature(classID, featureKey, enabled)
|
||||
}
|
||||
|
||||
// IsFeatureEnabled 检查功能开关是否启用
|
||||
func (s *ClassService) IsFeatureEnabled(classID int, featureKey string) bool {
|
||||
feature, err := s.classRepo.GetFeature(classID, featureKey)
|
||||
if err != nil || feature == nil {
|
||||
return true // 默认启用
|
||||
}
|
||||
return feature.Enabled == 1
|
||||
}
|
||||
Reference in New Issue
Block a user