技术栈: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
225 lines
6.0 KiB
Go
225 lines
6.0 KiB
Go
// ===========================================
|
||
// 多班级版班级管理系统 - 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
|
||
}
|