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:
230
backend-go/internal/repository/student_repo.go
Normal file
230
backend-go/internal/repository/student_repo.go
Normal file
@@ -0,0 +1,230 @@
|
||||
// ===========================================
|
||||
// 多班级版班级管理系统 - Go 后端
|
||||
//
|
||||
// 开发者: Canglan
|
||||
// 联系方式: admin@sea-studio.top
|
||||
// 版权归属: Sea Network Technology Studio
|
||||
// 许可证: Apache License 2.0
|
||||
//
|
||||
// 版权所有 © Sea Network Technology Studio
|
||||
// ===========================================
|
||||
|
||||
package repository
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"gorm.io/gorm"
|
||||
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/model"
|
||||
)
|
||||
|
||||
// StudentRepo 学生数据访问层
|
||||
type StudentRepo struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
// NewStudentRepo 创建学生 Repository
|
||||
func NewStudentRepo(db *gorm.DB) *StudentRepo {
|
||||
return &StudentRepo{db: db}
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取学生信息(含班级名称)
|
||||
func (r *StudentRepo) GetByID(studentID int) (*model.Student, error) {
|
||||
var student model.Student
|
||||
if err := r.db.Table("students s").
|
||||
Select("s.*, c.class_name").
|
||||
Joins("LEFT JOIN classes c ON s.class_id = c.class_id").
|
||||
Where("s.student_id = ?", studentID).
|
||||
First(&student).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &student, nil
|
||||
}
|
||||
|
||||
// GetByStudentNo 根据学号获取学生(可指定班级)
|
||||
func (r *StudentRepo) GetByStudentNo(studentNo string, classID int) (*model.Student, error) {
|
||||
var student model.Student
|
||||
query := r.db.Where("student_no = ?", studentNo)
|
||||
if classID > 0 {
|
||||
query = query.Where("class_id = ?", classID)
|
||||
}
|
||||
if err := query.First(&student).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &student, nil
|
||||
}
|
||||
|
||||
// GetAll 获取指定班级的学生列表
|
||||
func (r *StudentRepo) GetAll(classID int, includeDisabled bool) ([]model.Student, error) {
|
||||
var students []model.Student
|
||||
query := r.db.Where("class_id = ?", classID)
|
||||
if !includeDisabled {
|
||||
query = query.Where("status = 1")
|
||||
}
|
||||
if err := query.Order("student_no").Find(&students).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return students, nil
|
||||
}
|
||||
|
||||
// GetDormitoryList 获取班级内所有不重复的宿舍号列表
|
||||
func (r *StudentRepo) GetDormitoryList(classID int) ([]string, error) {
|
||||
var dormitories []string
|
||||
err := r.db.Model(&model.Student{}).
|
||||
Where("class_id = ? AND status = 1 AND dormitory_number IS NOT NULL AND dormitory_number != ''", classID).
|
||||
Distinct("dormitory_number").
|
||||
Order("dormitory_number").
|
||||
Pluck("dormitory_number", &dormitories).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dormitories, nil
|
||||
}
|
||||
|
||||
// Create 创建学生记录
|
||||
func (r *StudentRepo) Create(student *model.Student) (int, error) {
|
||||
if err := r.db.Create(student).Error; err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return student.StudentID, nil
|
||||
}
|
||||
|
||||
// Update 更新学生信息(仅更新非零值字段)
|
||||
func (r *StudentRepo) Update(studentID int, updates map[string]interface{}) error {
|
||||
if len(updates) == 0 {
|
||||
return nil
|
||||
}
|
||||
return r.db.Model(&model.Student{}).
|
||||
Where("student_id = ?", studentID).
|
||||
Updates(updates).Error
|
||||
}
|
||||
|
||||
// SoftDelete 软删除学生
|
||||
func (r *StudentRepo) SoftDelete(studentID int) error {
|
||||
return r.db.Model(&model.Student{}).
|
||||
Where("student_id = ?", studentID).
|
||||
Update("status", 0).Error
|
||||
}
|
||||
|
||||
// UpdateTotalPoints 更新学生总分(增量更新,下限保护为 0)
|
||||
func (r *StudentRepo) UpdateTotalPoints(studentID int, pointsChange int) error {
|
||||
return r.db.Model(&model.Student{}).
|
||||
Where("student_id = ?", studentID).
|
||||
Update("total_points", gorm.Expr("GREATEST(total_points + ?, 0)", pointsChange)).Error
|
||||
}
|
||||
|
||||
// GetRanking 获取班级内学生排行
|
||||
func (r *StudentRepo) GetRanking(classID int, limit int) ([]model.Student, error) {
|
||||
var students []model.Student
|
||||
if err := r.db.Where("status = 1 AND class_id = ?", classID).
|
||||
Order("total_points DESC, student_id ASC").
|
||||
Limit(limit).
|
||||
Find(&students).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return students, nil
|
||||
}
|
||||
|
||||
// GetTotalCount 获取班级内活跃学生总数
|
||||
func (r *StudentRepo) GetTotalCount(classID int) (int64, error) {
|
||||
var count int64
|
||||
if err := r.db.Model(&model.Student{}).
|
||||
Where("status = 1 AND class_id = ?", classID).
|
||||
Count(&count).Error; err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// ListByClass 分页获取班级学生列表(支持搜索和宿舍号过滤)
|
||||
func (r *StudentRepo) ListByClass(classID int, page, pageSize int, search, dormitoryNumber string) ([]model.Student, int64, error) {
|
||||
var students []model.Student
|
||||
var total int64
|
||||
|
||||
query := r.db.Model(&model.Student{}).Where("status = 1 AND class_id = ?", classID)
|
||||
|
||||
if search != "" {
|
||||
escaped := strings.NewReplacer("\\", "\\\\", "%", "\\%", "_", "\\_").Replace(search)
|
||||
searchPattern := fmt.Sprintf("%%%s%%", escaped)
|
||||
query = query.Where("student_no LIKE ? OR name LIKE ?", searchPattern, searchPattern)
|
||||
}
|
||||
|
||||
if dormitoryNumber != "" {
|
||||
query = query.Where("dormitory_number = ?", dormitoryNumber)
|
||||
}
|
||||
|
||||
// 获取总数
|
||||
if err := query.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
offset := (page - 1) * pageSize
|
||||
if err := query.Order("student_no").
|
||||
Limit(pageSize).
|
||||
Offset(offset).
|
||||
Find(&students).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return students, total, nil
|
||||
}
|
||||
|
||||
// BatchCreate 批量创建学生
|
||||
func (r *StudentRepo) BatchCreate(students []model.Student) error {
|
||||
return r.db.Create(&students).Error
|
||||
}
|
||||
|
||||
// GetStudentNosByClass 获取指定班级所有学生学号(用于批量导入去重)
|
||||
func (r *StudentRepo) GetStudentNosByClass(classID int) ([]string, error) {
|
||||
var studentNos []string
|
||||
if err := r.db.Model(&model.Student{}).
|
||||
Where("class_id = ?", classID).
|
||||
Pluck("student_no", &studentNos).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return studentNos, nil
|
||||
}
|
||||
|
||||
// ResetPoints 重置班级内所有学生的操行分为初始值
|
||||
func (r *StudentRepo) ResetPoints(classID int, initialPoints int) error {
|
||||
return r.db.Model(&model.Student{}).
|
||||
Where("class_id = ? AND status = 1", classID).
|
||||
Update("total_points", initialPoints).Error
|
||||
}
|
||||
|
||||
// GetByParentAccount 根据家长账号查找学生
|
||||
func (r *StudentRepo) GetByParentAccount(parentAccount string) (*model.Student, error) {
|
||||
var student model.Student
|
||||
if err := r.db.Where("parent_account = ? AND status = 1", parentAccount).First(&student).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &student, nil
|
||||
}
|
||||
|
||||
// GetRankByStudentID 使用密集排名(dense rank)计算学生排名:相同分数同名次,后续名次不跳过
|
||||
func (r *StudentRepo) GetRankByStudentID(classID, studentID int) (int, error) {
|
||||
var student model.Student
|
||||
if err := r.db.Select("total_points").Where("student_id = ?", studentID).First(&student).Error; err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var distinctHigherCount int64
|
||||
if err := r.db.Raw("SELECT COUNT(DISTINCT total_points) FROM students WHERE status = 1 AND class_id = ? AND total_points > ?",
|
||||
classID, student.TotalPoints).Scan(&distinctHigherCount).Error; err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(distinctHigherCount) + 1, nil
|
||||
}
|
||||
|
||||
// GetStudentsByClassID 获取班级内所有活跃学生(用于归档等批量操作)
|
||||
func (r *StudentRepo) GetStudentsByClassID(classID int) ([]model.Student, error) {
|
||||
var students []model.Student
|
||||
if err := r.db.Where("class_id = ? AND status = 1", classID).
|
||||
Order("total_points DESC, student_id ASC").
|
||||
Find(&students).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return students, nil
|
||||
}
|
||||
Reference in New Issue
Block a user