Files
SharedClassManager/backend-go/internal/repository/student_repo.go
canglan d6dec878bd feat: 多班级版 v2.0 - Go后端重写 + 43轮代码审查
- 后端从 Python FastAPI 重写为 Go Gin(端口 56789)
- 多班级完全隔离
- 超级管理员独立登录
- 课代表作业管理、排行榜分项排行
- 角色加减分上下限可配置
- 家长改密功能(可开关)
- 周度/月度重置功能
- MySQL 5.7 兼容
- 43轮代码审查+全部修复
- Apache 2.0 许可证
2026-06-22 10:06:10 +08:00

231 lines
7.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ===========================================
// 多班级版班级管理系统 - 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
}