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 4a82eff3c6
135 changed files with 19963 additions and 0 deletions

View File

@@ -0,0 +1,184 @@
// ===========================================
// 多班级版班级管理系统 - Go 后端
//
// 开发者: Canglan
// 联系方式: admin@sea-studio.top
// 版权归属: Sea Network Technology Studio
// 许可证: Apache License 2.0
//
// 版权所有 © Sea Network Technology Studio
// ===========================================
package repository
import (
"gorm.io/gorm"
"gorm.io/gorm/clause"
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/model"
)
// ClassRepo 班级数据访问层
type ClassRepo struct {
db *gorm.DB
}
// NewClassRepo 创建班级 Repository
func NewClassRepo(db *gorm.DB) *ClassRepo {
return &ClassRepo{db: db}
}
// GetDB 获取底层数据库连接
func (r *ClassRepo) GetDB() *gorm.DB {
return r.db
}
// GetByID 根据ID获取班级信息
func (r *ClassRepo) GetByID(classID int) (*model.Class, error) {
var class model.Class
if err := r.db.Where("class_id = ?", classID).First(&class).Error; err != nil {
return nil, err
}
return &class, nil
}
// GetAll 获取所有班级列表
func (r *ClassRepo) GetAll(includeDisabled bool) ([]model.Class, error) {
var classes []model.Class
query := r.db.Where("1 = 1")
if !includeDisabled {
query = query.Where("status = 1")
}
if err := query.Order("class_id").Find(&classes).Error; err != nil {
return nil, err
}
return classes, nil
}
// GetByName 根据班级名称获取班级
func (r *ClassRepo) GetByName(className string) (*model.Class, error) {
var class model.Class
if err := r.db.Where("class_name = ?", className).First(&class).Error; err != nil {
return nil, err
}
return &class, nil
}
// Create 创建班级
func (r *ClassRepo) Create(class *model.Class) (int, error) {
if err := r.db.Create(class).Error; err != nil {
return 0, err
}
return class.ClassID, nil
}
// Update 更新班级信息(仅更新非零值字段)
func (r *ClassRepo) Update(classID int, updates map[string]interface{}) error {
if len(updates) == 0 {
return nil
}
return r.db.Model(&model.Class{}).
Where("class_id = ?", classID).
Updates(updates).Error
}
// Delete 删除班级(硬删除,需先确认无学生)
func (r *ClassRepo) Delete(classID int) error {
return r.db.Where("class_id = ?", classID).Delete(&model.Class{}).Error
}
// GetStudentCount 获取班级活跃学生数量
func (r *ClassRepo) GetStudentCount(classID int) (int64, error) {
var count int64
if err := r.db.Model(&model.Student{}).
Where("class_id = ? AND status = 1", classID).
Count(&count).Error; err != nil {
return 0, err
}
return count, nil
}
// HasActiveStudents 检查班级是否有活跃学生
func (r *ClassRepo) HasActiveStudents(classID int) (bool, error) {
count, err := r.GetStudentCount(classID)
if err != nil {
return false, err
}
return count > 0, nil
}
// ========== 班级设置操作 ==========
// GetSettings 获取班级的所有设置
func (r *ClassRepo) GetSettings(classID int) ([]model.ClassSetting, error) {
var settings []model.ClassSetting
if err := r.db.Where("class_id = ?", classID).Find(&settings).Error; err != nil {
return nil, err
}
return settings, nil
}
// GetSetting 获取班级单个设置项
func (r *ClassRepo) GetSetting(classID int, key string) (*model.ClassSetting, error) {
var setting model.ClassSetting
if err := r.db.Where("class_id = ? AND setting_key = ?", classID, key).First(&setting).Error; err != nil {
return nil, err
}
return &setting, nil
}
// SaveSetting 保存班级设置项upsert
func (r *ClassRepo) SaveSetting(classID int, key, value string) error {
setting := model.ClassSetting{
ClassID: classID,
SettingKey: key,
SettingValue: value,
}
return r.db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "class_id"}, {Name: "setting_key"}},
DoUpdates: clause.AssignmentColumns([]string{"setting_value"}),
}).Create(&setting).Error
}
// BatchSaveSettings 批量保存班级设置项
func (r *ClassRepo) BatchSaveSettings(classID int, settings map[string]string) error {
for key, value := range settings {
if err := r.SaveSetting(classID, key, value); err != nil {
return err
}
}
return nil
}
// ========== 班级功能开关操作 ==========
// GetFeatures 获取班级的所有功能开关
func (r *ClassRepo) GetFeatures(classID int) ([]model.ClassFeature, error) {
var features []model.ClassFeature
if err := r.db.Where("class_id = ?", classID).Find(&features).Error; err != nil {
return nil, err
}
return features, nil
}
// GetFeature 获取班级单个功能开关
func (r *ClassRepo) GetFeature(classID int, featureKey string) (*model.ClassFeature, error) {
var feature model.ClassFeature
if err := r.db.Where("class_id = ? AND feature_key = ?", classID, featureKey).First(&feature).Error; err != nil {
return nil, err
}
return &feature, nil
}
// SaveFeature 保存班级功能开关upsert
func (r *ClassRepo) SaveFeature(classID int, featureKey string, enabled int8) error {
feature := model.ClassFeature{
ClassID: classID,
FeatureKey: featureKey,
Enabled: enabled,
}
return r.db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "class_id"}, {Name: "feature_key"}},
DoUpdates: clause.AssignmentColumns([]string{"enabled"}),
}).Create(&feature).Error
}