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:
602
backend-go/internal/handler/admin_handler.go
Normal file
602
backend-go/internal/handler/admin_handler.go
Normal file
@@ -0,0 +1,602 @@
|
||||
// ===========================================
|
||||
// 多班级版班级管理系统 - Go 后端
|
||||
//
|
||||
// 开发者: Canglan
|
||||
// 联系方式: admin@sea-studio.top
|
||||
// 版权归属: Sea Network Technology Studio
|
||||
// 许可证: Apache License 2.0
|
||||
//
|
||||
// 版权所有 © Sea Network Technology Studio
|
||||
// ===========================================
|
||||
|
||||
package handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/middleware"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/schema"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/service"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/pkg/response"
|
||||
)
|
||||
|
||||
// AdminHandler 管理端处理器
|
||||
type AdminHandler struct {
|
||||
adminService *service.AdminService
|
||||
conductService *service.ConductService
|
||||
attendanceSvc *service.AttendanceService
|
||||
rankingService *service.RankingService
|
||||
logService *service.LogService
|
||||
}
|
||||
|
||||
// NewAdminHandler 创建管理端处理器
|
||||
func NewAdminHandler(
|
||||
adminService *service.AdminService,
|
||||
conductService *service.ConductService,
|
||||
attendanceSvc *service.AttendanceService,
|
||||
rankingService *service.RankingService,
|
||||
logService *service.LogService,
|
||||
) *AdminHandler {
|
||||
return &AdminHandler{
|
||||
adminService: adminService,
|
||||
conductService: conductService,
|
||||
attendanceSvc: attendanceSvc,
|
||||
rankingService: rankingService,
|
||||
logService: logService,
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 学生管理 ==========
|
||||
|
||||
// GetDormitories 获取宿舍号列表
|
||||
func (h *AdminHandler) GetDormitories(c *gin.Context) {
|
||||
classID := middleware.GetClassID(c)
|
||||
if classID == 0 {
|
||||
response.BadRequest(c, "请先选择班级")
|
||||
return
|
||||
}
|
||||
dormitories, err := h.adminService.GetDormitories(classID)
|
||||
if err != nil {
|
||||
response.InternalError(c, "获取宿舍号列表失败")
|
||||
return
|
||||
}
|
||||
response.Success(c, gin.H{"dormitories": dormitories}, "操作成功")
|
||||
}
|
||||
|
||||
// StudentList 获取学生列表
|
||||
func (h *AdminHandler) StudentList(c *gin.Context) {
|
||||
classID := middleware.GetClassID(c)
|
||||
if classID == 0 {
|
||||
response.BadRequest(c, "请先选择班级")
|
||||
return
|
||||
}
|
||||
|
||||
var query schema.StudentListQuery
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.adminService.GetStudents(classID, query.Page, query.PageSize, query.Search, query.DormitoryNumber)
|
||||
if err != nil {
|
||||
response.InternalError(c, "获取学生列表失败")
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// StudentImport 批量导入学生
|
||||
func (h *AdminHandler) StudentImport(c *gin.Context) {
|
||||
classID := middleware.GetClassID(c)
|
||||
if classID == 0 {
|
||||
response.BadRequest(c, "请先选择班级")
|
||||
return
|
||||
}
|
||||
|
||||
file, _, err := c.Request.FormFile("file")
|
||||
if err != nil {
|
||||
response.BadRequest(c, "请上传文件")
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
limitedReader := io.LimitReader(file, 5*1024*1024)
|
||||
content, err := io.ReadAll(limitedReader)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "读取文件失败")
|
||||
return
|
||||
}
|
||||
|
||||
var data struct {
|
||||
Students []map[string]interface{} `json:"students"`
|
||||
}
|
||||
if err := json.Unmarshal(content, &data); err != nil {
|
||||
response.BadRequest(c, "JSON格式错误")
|
||||
return
|
||||
}
|
||||
if len(data.Students) == 0 {
|
||||
response.BadRequest(c, "文件中没有学生数据")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.adminService.ImportStudents(data.Students, classID)
|
||||
if err != nil {
|
||||
response.InternalError(c, "导入失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// StudentCreate 新增学生
|
||||
func (h *AdminHandler) StudentCreate(c *gin.Context) {
|
||||
classID := middleware.GetClassID(c)
|
||||
if classID == 0 {
|
||||
response.BadRequest(c, "请先选择班级")
|
||||
return
|
||||
}
|
||||
|
||||
var req schema.StudentCreateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.adminService.AddStudent(req.StudentNo, req.Name, req.ParentAccount, classID, req.DormitoryNumber)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if success, _ := result["success"].(bool); !success {
|
||||
msg, _ := result["message"].(string)
|
||||
if msg == "" {
|
||||
msg = "操作失败"
|
||||
}
|
||||
response.BadRequest(c, msg)
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, result, "学生添加成功")
|
||||
}
|
||||
|
||||
// StudentUpdate 编辑学生
|
||||
func (h *AdminHandler) StudentUpdate(c *gin.Context) {
|
||||
studentID, ok := parseID(c, "student_id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
classID := middleware.GetClassID(c)
|
||||
|
||||
var req schema.StudentUpdateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.adminService.UpdateStudent(studentID, req.Name, req.ParentAccount, req.DormitoryNumber, classID); err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.SuccessWithMessage(c, "更新成功")
|
||||
}
|
||||
|
||||
// StudentDelete 删除学生
|
||||
func (h *AdminHandler) StudentDelete(c *gin.Context) {
|
||||
studentID, ok := parseID(c, "student_id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
classID := middleware.GetClassID(c)
|
||||
|
||||
if err := h.adminService.DeleteStudent(studentID, classID); err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.SuccessWithMessage(c, "删除成功")
|
||||
}
|
||||
|
||||
// ResetStudentPassword 重置学生密码
|
||||
func (h *AdminHandler) ResetStudentPassword(c *gin.Context) {
|
||||
studentID, ok := parseID(c, "student_id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
var req schema.ResetPasswordRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.adminService.ResetStudentPassword(studentID, req.NewPassword); err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.SuccessWithMessage(c, "密码重置成功")
|
||||
}
|
||||
|
||||
// ========== 操行分管理 ==========
|
||||
|
||||
// AddConductPoints 批量加减分
|
||||
func (h *AdminHandler) AddConductPoints(c *gin.Context) {
|
||||
var req schema.ConductAddRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
classID := middleware.GetClassID(c)
|
||||
userID := middleware.GetUserID(c)
|
||||
realName := middleware.GetRealName(c)
|
||||
|
||||
result, err := h.conductService.AddPoints(
|
||||
req.StudentIDs, req.PointsChange, req.Reason,
|
||||
userID, realName, classID, req.RelatedType,
|
||||
)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if success, _ := result["success"].(bool); !success {
|
||||
msg, _ := result["message"].(string)
|
||||
if msg == "" {
|
||||
msg = "操作失败"
|
||||
}
|
||||
response.BadRequest(c, msg)
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// RevokeConductRecord 撤销记录
|
||||
func (h *AdminHandler) RevokeConductRecord(c *gin.Context) {
|
||||
var req schema.RevokeRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
userID := middleware.GetUserID(c)
|
||||
classID := middleware.GetClassID(c)
|
||||
result, err := h.conductService.RevokeRecord(req.RecordID, userID, classID)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if success, _ := result["success"].(bool); !success {
|
||||
msg, _ := result["message"].(string)
|
||||
if msg == "" {
|
||||
msg = "操作失败"
|
||||
}
|
||||
response.BadRequest(c, msg)
|
||||
return
|
||||
}
|
||||
response.SuccessWithMessage(c, "撤销成功")
|
||||
}
|
||||
|
||||
// RestoreConductRecord 反撤销记录
|
||||
func (h *AdminHandler) RestoreConductRecord(c *gin.Context) {
|
||||
var req schema.RevokeRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
userID := middleware.GetUserID(c)
|
||||
classID := middleware.GetClassID(c)
|
||||
result, err := h.conductService.RestoreRecord(req.RecordID, userID, classID)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if success, _ := result["success"].(bool); !success {
|
||||
msg, _ := result["message"].(string)
|
||||
if msg == "" {
|
||||
msg = "操作失败"
|
||||
}
|
||||
response.BadRequest(c, msg)
|
||||
return
|
||||
}
|
||||
response.SuccessWithMessage(c, "反撤销成功")
|
||||
}
|
||||
|
||||
// GetConductHistory 操行分历史
|
||||
func (h *AdminHandler) GetConductHistory(c *gin.Context) {
|
||||
classID := middleware.GetClassID(c)
|
||||
|
||||
var query schema.ConductHistoryQuery
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.conductService.GetHistory(
|
||||
classID, query.StudentID, query.Page, query.PageSize,
|
||||
query.StartDate, query.EndDate, query.RelatedType,
|
||||
query.ReasonPrefix, query.IsRevoked, query.ReasonSearch,
|
||||
)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// BatchRevokeConductRecords 批量撤销
|
||||
func (h *AdminHandler) BatchRevokeConductRecords(c *gin.Context) {
|
||||
var req schema.BatchRevokeRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
userID := middleware.GetUserID(c)
|
||||
classID := middleware.GetClassID(c)
|
||||
successCount := 0
|
||||
failCount := 0
|
||||
var errors []map[string]interface{}
|
||||
|
||||
for _, recordID := range req.RecordIDs {
|
||||
result, _ := h.conductService.RevokeRecord(recordID, userID, classID)
|
||||
if result != nil {
|
||||
if success, _ := result["success"].(bool); success {
|
||||
successCount++
|
||||
} else {
|
||||
failCount++
|
||||
msg, _ := result["message"].(string)
|
||||
errors = append(errors, map[string]interface{}{"record_id": recordID, "error": msg})
|
||||
}
|
||||
} else {
|
||||
failCount++
|
||||
errors = append(errors, map[string]interface{}{"record_id": recordID, "error": "撤销失败"})
|
||||
}
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{
|
||||
"success_count": successCount,
|
||||
"fail_count": failCount,
|
||||
"errors": errors,
|
||||
}, "批量撤销完成")
|
||||
}
|
||||
|
||||
// BatchRestoreConductRecords 批量反撤销
|
||||
func (h *AdminHandler) BatchRestoreConductRecords(c *gin.Context) {
|
||||
var req schema.BatchRevokeRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
userID := middleware.GetUserID(c)
|
||||
classID := middleware.GetClassID(c)
|
||||
successCount := 0
|
||||
failCount := 0
|
||||
var errors []map[string]interface{}
|
||||
|
||||
for _, recordID := range req.RecordIDs {
|
||||
result, _ := h.conductService.RestoreRecord(recordID, userID, classID)
|
||||
if result != nil {
|
||||
if success, _ := result["success"].(bool); success {
|
||||
successCount++
|
||||
} else {
|
||||
failCount++
|
||||
msg, _ := result["message"].(string)
|
||||
errors = append(errors, map[string]interface{}{"record_id": recordID, "error": msg})
|
||||
}
|
||||
} else {
|
||||
failCount++
|
||||
errors = append(errors, map[string]interface{}{"record_id": recordID, "error": "反撤销失败"})
|
||||
}
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{
|
||||
"success_count": successCount,
|
||||
"fail_count": failCount,
|
||||
"errors": errors,
|
||||
}, "批量反撤销完成")
|
||||
}
|
||||
|
||||
// ========== 考勤管理 ==========
|
||||
|
||||
// CreateAttendanceRecord 添加考勤
|
||||
func (h *AdminHandler) CreateAttendanceRecord(c *gin.Context) {
|
||||
var req schema.AttendanceCreateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
userID := middleware.GetUserID(c)
|
||||
classID := middleware.GetClassID(c)
|
||||
result, err := h.attendanceSvc.CreateRecord(
|
||||
req.StudentID, req.Date, req.Slot, req.Status,
|
||||
&req.Reason, req.ApplyDeduction, req.CustomDeduction, userID, classID,
|
||||
)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if success, _ := result["success"].(bool); !success {
|
||||
msg, _ := result["message"].(string)
|
||||
if msg == "" {
|
||||
msg = "操作失败"
|
||||
}
|
||||
response.BadRequest(c, msg)
|
||||
return
|
||||
}
|
||||
msg, _ := result["message"].(string)
|
||||
if msg == "" {
|
||||
msg = "操作成功"
|
||||
}
|
||||
response.SuccessWithMessage(c, msg)
|
||||
}
|
||||
|
||||
// GetAttendanceRecords 获取考勤记录
|
||||
func (h *AdminHandler) GetAttendanceRecords(c *gin.Context) {
|
||||
classID := middleware.GetClassID(c)
|
||||
|
||||
var query schema.AttendanceQuery
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.attendanceSvc.GetRecords(classID, query.Date, query.StudentID, query.Slot)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// ========== 管理员管理 ==========
|
||||
|
||||
// AdminList 管理员列表
|
||||
func (h *AdminHandler) AdminList(c *gin.Context) {
|
||||
classID := middleware.GetClassID(c)
|
||||
result, err := h.adminService.GetAdmins(classID)
|
||||
if err != nil {
|
||||
response.InternalError(c, "获取管理员列表失败")
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// AdminCreate 添加管理员
|
||||
func (h *AdminHandler) AdminCreate(c *gin.Context) {
|
||||
classID := middleware.GetClassID(c)
|
||||
if classID == 0 {
|
||||
response.BadRequest(c, "请先选择班级")
|
||||
return
|
||||
}
|
||||
|
||||
var req schema.AdminCreateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.adminService.AddAdmin(req.Username, req.RealName, req.Password, req.RoleType, classID, req.SubjectID)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if success, _ := result["success"].(bool); !success {
|
||||
msg, _ := result["message"].(string)
|
||||
if msg == "" {
|
||||
msg = "操作失败"
|
||||
}
|
||||
response.BadRequest(c, msg)
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "管理员添加成功")
|
||||
}
|
||||
|
||||
// AdminUpdate 更新管理员
|
||||
func (h *AdminHandler) AdminUpdate(c *gin.Context) {
|
||||
userID, ok := parseID(c, "user_id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
classID := middleware.GetClassID(c)
|
||||
var req schema.AdminUpdateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.adminService.UpdateAdmin(userID, req.RealName, req.RoleType, classID, req.SubjectID); err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.SuccessWithMessage(c, "更新成功")
|
||||
}
|
||||
|
||||
// AdminDelete 删除管理员
|
||||
func (h *AdminHandler) AdminDelete(c *gin.Context) {
|
||||
userID, ok := parseID(c, "user_id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
classID := middleware.GetClassID(c)
|
||||
if err := h.adminService.DeleteAdmin(userID, classID); err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.SuccessWithMessage(c, "删除成功")
|
||||
}
|
||||
|
||||
// AdminResetPassword 重置管理员密码
|
||||
func (h *AdminHandler) AdminResetPassword(c *gin.Context) {
|
||||
userID, ok := parseID(c, "user_id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
var req schema.ResetPasswordRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.adminService.ResetAdminPassword(userID, req.NewPassword); err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.SuccessWithMessage(c, "密码重置成功")
|
||||
}
|
||||
|
||||
// UnlockAccount 解除登录锁定
|
||||
func (h *AdminHandler) UnlockAccount(c *gin.Context) {
|
||||
var req schema.UnlockUserRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.adminService.UnlockAccount(req.Username, c.ClientIP()); err != nil {
|
||||
response.InternalError(c, "解锁失败")
|
||||
return
|
||||
}
|
||||
response.SuccessWithMessage(c, "解锁成功")
|
||||
}
|
||||
|
||||
|
||||
// GetRankings 分项排行榜
|
||||
func (h *AdminHandler) GetRankings(c *gin.Context) {
|
||||
classID := middleware.GetClassID(c)
|
||||
if classID == 0 {
|
||||
response.BadRequest(c, "请先选择班级")
|
||||
return
|
||||
}
|
||||
|
||||
rankType := c.DefaultQuery("type", "all")
|
||||
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "50"))
|
||||
if limit <= 0 {
|
||||
limit = 50
|
||||
}
|
||||
if limit > 500 {
|
||||
limit = 500
|
||||
}
|
||||
|
||||
result, err := h.rankingService.GetRankings(classID, rankType, limit)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
131
backend-go/internal/handler/auth_handler.go
Normal file
131
backend-go/internal/handler/auth_handler.go
Normal file
@@ -0,0 +1,131 @@
|
||||
// ===========================================
|
||||
// 多班级版班级管理系统 - Go 后端
|
||||
//
|
||||
// 开发者: Canglan
|
||||
// 联系方式: admin@sea-studio.top
|
||||
// 版权归属: Sea Network Technology Studio
|
||||
// 许可证: Apache License 2.0
|
||||
//
|
||||
// 版权所有 © Sea Network Technology Studio
|
||||
// ===========================================
|
||||
|
||||
package handler
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/middleware"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/schema"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/service"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/pkg/response"
|
||||
)
|
||||
|
||||
// AuthHandler 认证处理器
|
||||
type AuthHandler struct {
|
||||
authService *service.AuthService
|
||||
superAdminService *service.SuperAdminService
|
||||
}
|
||||
|
||||
// NewAuthHandler 创建认证处理器
|
||||
func NewAuthHandler(authService *service.AuthService, superAdminService *service.SuperAdminService) *AuthHandler {
|
||||
return &AuthHandler{authService: authService, superAdminService: superAdminService}
|
||||
}
|
||||
|
||||
// Login 用户登录
|
||||
func (h *AuthHandler) Login(c *gin.Context) {
|
||||
var req schema.LoginRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
ip := c.ClientIP()
|
||||
userAgent := c.GetHeader("User-Agent")
|
||||
|
||||
result := h.authService.Login(req.Username, req.Password, ip, userAgent)
|
||||
if !result.Success {
|
||||
response.Unauthorized(c, result.Message)
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, result, "登录成功")
|
||||
}
|
||||
|
||||
// Logout 用户登出
|
||||
func (h *AuthHandler) Logout(c *gin.Context) {
|
||||
userID := middleware.GetUserID(c)
|
||||
if err := h.authService.Logout(userID); err != nil {
|
||||
response.InternalError(c, "登出失败")
|
||||
return
|
||||
}
|
||||
response.SuccessWithMessage(c, "登出成功")
|
||||
}
|
||||
|
||||
// ChangePassword 修改密码(超级管理员操作 super_admins 表,普通用户操作 users 表)
|
||||
func (h *AuthHandler) ChangePassword(c *gin.Context) {
|
||||
var req schema.ChangePasswordRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
userID := middleware.GetUserID(c)
|
||||
userType := middleware.GetUserType(c)
|
||||
|
||||
// force 参数仅在用户确实需要强制改密时才允许使用
|
||||
if req.Force {
|
||||
if userType == "super_admin" {
|
||||
// 超级管理员的 need_change_password 由 super_admin_service 处理
|
||||
// force 改密时直接允许(登录时已验证 need_change_password 标记)
|
||||
} else {
|
||||
userInfo, err := h.authService.GetUserInfo(userID)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
needChange, _ := userInfo["need_change_password"].(bool)
|
||||
if !needChange {
|
||||
response.BadRequest(c, "当前状态不允许强制修改密码")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if userType == "super_admin" {
|
||||
if err := h.superAdminService.ChangePassword(userID, req.OldPassword, req.NewPassword, req.Force); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if err := h.authService.ChangePassword(userID, req.OldPassword, req.NewPassword, req.Force); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
response.SuccessWithMessage(c, "密码修改成功,请重新登录")
|
||||
}
|
||||
|
||||
// GetUserInfo 获取当前用户信息
|
||||
func (h *AuthHandler) GetUserInfo(c *gin.Context) {
|
||||
userID := middleware.GetUserID(c)
|
||||
userInfo, err := h.authService.GetUserInfo(userID)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, userInfo, "操作成功")
|
||||
}
|
||||
|
||||
// parseID 解析路径参数中的 ID
|
||||
func parseID(c *gin.Context, key string) (int, bool) {
|
||||
idStr := c.Param(key)
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "无效的ID参数")
|
||||
return 0, false
|
||||
}
|
||||
return id, true
|
||||
}
|
||||
143
backend-go/internal/handler/cadre_handler.go
Normal file
143
backend-go/internal/handler/cadre_handler.go
Normal file
@@ -0,0 +1,143 @@
|
||||
// ===========================================
|
||||
// 多班级版班级管理系统 - Go 后端
|
||||
//
|
||||
// 开发者: Canglan
|
||||
// 联系方式: admin@sea-studio.top
|
||||
// 版权归属: Sea Network Technology Studio
|
||||
// 许可证: Apache License 2.0
|
||||
//
|
||||
// 版权所有 © Sea Network Technology Studio
|
||||
// ===========================================
|
||||
|
||||
package handler
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/middleware"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/model"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/repository"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/schema"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/service"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/pkg/response"
|
||||
)
|
||||
|
||||
// CadreHandler 课代表处理器
|
||||
type CadreHandler struct {
|
||||
assignmentRepo *repository.AssignmentRepo
|
||||
conductService *service.ConductService
|
||||
adminRoleRepo *repository.AdminRoleRepo
|
||||
}
|
||||
|
||||
// NewCadreHandler 创建课代表处理器
|
||||
func NewCadreHandler(assignmentRepo *repository.AssignmentRepo, conductService *service.ConductService, adminRoleRepo *repository.AdminRoleRepo) *CadreHandler {
|
||||
return &CadreHandler{assignmentRepo: assignmentRepo, conductService: conductService, adminRoleRepo: adminRoleRepo}
|
||||
}
|
||||
|
||||
// HomeworkList 课代表查看作业列表
|
||||
func (h *CadreHandler) HomeworkList(c *gin.Context) {
|
||||
classID := middleware.GetClassID(c)
|
||||
|
||||
var query schema.CadreHomeworkQuery
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
subjectID := 0
|
||||
if query.SubjectID != nil {
|
||||
subjectID = *query.SubjectID
|
||||
}
|
||||
|
||||
assignments, total, err := h.assignmentRepo.GetAssignmentsByClass(classID, subjectID, query.Page, query.PageSize)
|
||||
if err != nil {
|
||||
response.InternalError(c, "获取作业列表失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Paginated(c, assignments, total, query.Page, query.PageSize)
|
||||
}
|
||||
|
||||
// HomeworkSubmit 课代表发布作业
|
||||
func (h *CadreHandler) HomeworkSubmit(c *gin.Context) {
|
||||
var req schema.CadreHomeworkSubmitRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
classID := middleware.GetClassID(c)
|
||||
userID := middleware.GetUserID(c)
|
||||
|
||||
// 从管理员角色中获取课代表关联的科目 ID
|
||||
adminRole, err := h.adminRoleRepo.GetByUserID(userID)
|
||||
if err != nil || adminRole == nil || adminRole.SubjectID == nil {
|
||||
response.BadRequest(c, "无法获取课代表关联的科目信息")
|
||||
return
|
||||
}
|
||||
|
||||
deadline, err := time.Parse("2006-01-02", req.Deadline)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "日期格式错误")
|
||||
return
|
||||
}
|
||||
|
||||
assignment := &model.Assignment{
|
||||
ClassID: classID,
|
||||
SubjectID: *adminRole.SubjectID,
|
||||
Title: req.Title,
|
||||
Description: &req.Description,
|
||||
Deadline: deadline,
|
||||
CreatedBy: userID,
|
||||
}
|
||||
|
||||
assignmentID, err := h.assignmentRepo.CreateAssignment(assignment)
|
||||
if err != nil {
|
||||
response.InternalError(c, "发布作业失败")
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{
|
||||
"assignment_id": assignmentID,
|
||||
}, "发布成功")
|
||||
}
|
||||
|
||||
// AddConductPoints 课代表登记缺交(仅允许作业相关的扣分操作)
|
||||
func (h *CadreHandler) AddConductPoints(c *gin.Context) {
|
||||
var req schema.ConductAddRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
// 课代表只允许扣分操作
|
||||
if req.PointsChange >= 0 {
|
||||
response.BadRequest(c, "课代表只能进行扣分操作")
|
||||
return
|
||||
}
|
||||
|
||||
classID := middleware.GetClassID(c)
|
||||
userID := middleware.GetUserID(c)
|
||||
realName := middleware.GetRealName(c)
|
||||
|
||||
result, err := h.conductService.CadreAddPoints(
|
||||
req.StudentIDs, req.PointsChange, req.Reason,
|
||||
userID, realName, classID, "homework",
|
||||
)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if success, _ := result["success"].(bool); !success {
|
||||
msg, _ := result["message"].(string)
|
||||
if msg == "" {
|
||||
msg = "操作失败"
|
||||
}
|
||||
response.BadRequest(c, msg)
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
271
backend-go/internal/handler/class_handler.go
Normal file
271
backend-go/internal/handler/class_handler.go
Normal file
@@ -0,0 +1,271 @@
|
||||
// ===========================================
|
||||
// 多班级版班级管理系统 - Go 后端
|
||||
//
|
||||
// 开发者: Canglan
|
||||
// 联系方式: admin@sea-studio.top
|
||||
// 版权归属: Sea Network Technology Studio
|
||||
// 许可证: Apache License 2.0
|
||||
//
|
||||
// 版权所有 © Sea Network Technology Studio
|
||||
// ===========================================
|
||||
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/middleware"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/schema"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/service"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/pkg/response"
|
||||
)
|
||||
|
||||
// ClassHandler 班级管理处理器
|
||||
type ClassHandler struct {
|
||||
classService *service.ClassService
|
||||
}
|
||||
|
||||
// NewClassHandler 创建班级管理处理器
|
||||
func NewClassHandler(classService *service.ClassService) *ClassHandler {
|
||||
return &ClassHandler{classService: classService}
|
||||
}
|
||||
|
||||
// ClassList 班级列表
|
||||
func (h *ClassHandler) ClassList(c *gin.Context) {
|
||||
includeDisabled := c.Query("include_disabled") == "true"
|
||||
result, err := h.classService.ListClasses(includeDisabled)
|
||||
if err != nil {
|
||||
response.InternalError(c, "获取班级列表失败")
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// ClassDetail 班级详情
|
||||
func (h *ClassHandler) ClassDetail(c *gin.Context) {
|
||||
classID, ok := parseID(c, "class_id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.classService.GetClassDetail(classID)
|
||||
if err != nil {
|
||||
response.NotFound(c, "班级不存在")
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// ClassCreate 创建班级
|
||||
func (h *ClassHandler) ClassCreate(c *gin.Context) {
|
||||
var req schema.ClassCreateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.classService.CreateClass(req.ClassName, req.Grade, req.Description)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if success, _ := result["success"].(bool); !success {
|
||||
response.BadRequest(c, result["message"].(string))
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "班级创建成功")
|
||||
}
|
||||
|
||||
// ClassUpdate 更新班级
|
||||
func (h *ClassHandler) ClassUpdate(c *gin.Context) {
|
||||
classID, ok := parseID(c, "class_id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
var req schema.ClassUpdateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.classService.UpdateClass(classID, req.ClassName, req.Grade, req.Description, req.Status); err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.SuccessWithMessage(c, "更新成功")
|
||||
}
|
||||
|
||||
// ClassDelete 删除班级
|
||||
func (h *ClassHandler) ClassDelete(c *gin.Context) {
|
||||
classID, ok := parseID(c, "class_id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.classService.DeleteClass(classID); err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.SuccessWithMessage(c, "删除成功")
|
||||
}
|
||||
|
||||
// SwitchClass 切换班级上下文
|
||||
func (h *ClassHandler) SwitchClass(c *gin.Context) {
|
||||
var req schema.SwitchClassRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
userID := middleware.GetUserID(c)
|
||||
result, err := h.classService.SwitchClass(userID, req.ClassID)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "切换成功")
|
||||
}
|
||||
|
||||
// GetSettings 获取班级设置
|
||||
func (h *ClassHandler) GetSettings(c *gin.Context) {
|
||||
classID := middleware.GetClassID(c)
|
||||
result, err := h.classService.GetSettings(classID)
|
||||
if err != nil {
|
||||
response.InternalError(c, "获取设置失败")
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// allowedSettingKeys 允许通过 SaveSetting 端点写入的配置键白名单
|
||||
var allowedSettingKeys = map[string]bool{
|
||||
"initial_password": true,
|
||||
"initial_points": true,
|
||||
"deduction_attendance_absent": true,
|
||||
"deduction_attendance_late": true,
|
||||
"deduction_attendance_leave": true,
|
||||
"deduction_homework_not_submit": true,
|
||||
"deduction_homework_late": true,
|
||||
"reset_frequency": true,
|
||||
"reset_day_of_week": true,
|
||||
"reset_day_of_month": true,
|
||||
}
|
||||
|
||||
// SaveSetting 保存班级设置
|
||||
func (h *ClassHandler) SaveSetting(c *gin.Context) {
|
||||
classID := middleware.GetClassID(c)
|
||||
|
||||
var req schema.SettingRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
if !allowedSettingKeys[req.SettingKey] {
|
||||
response.BadRequest(c, "不允许的配置项: "+req.SettingKey)
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.classService.SaveSetting(classID, req.SettingKey, req.SettingValue); err != nil {
|
||||
response.InternalError(c, "保存设置失败")
|
||||
return
|
||||
}
|
||||
response.SuccessWithMessage(c, "保存成功")
|
||||
}
|
||||
|
||||
// GetPointLimits 获取角色加减分配置
|
||||
func (h *ClassHandler) GetPointLimits(c *gin.Context) {
|
||||
classID := middleware.GetClassID(c)
|
||||
result, err := h.classService.GetSettings(classID)
|
||||
if err != nil {
|
||||
response.InternalError(c, "获取配置失败")
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// allowedPointLimitKeys 允许的操行分限制配置键白名单(与 conduct_service 读取 key 一致)
|
||||
var allowedPointLimitKeys = map[string]bool{
|
||||
"point_limit_班长_max": true,
|
||||
"point_limit_班长_min": true,
|
||||
"point_limit_学习委员_max": true,
|
||||
"point_limit_学习委员_min": true,
|
||||
"point_limit_考勤委员_max": true,
|
||||
"point_limit_考勤委员_min": true,
|
||||
"point_limit_劳动委员_max": true,
|
||||
"point_limit_劳动委员_min": true,
|
||||
"point_limit_志愿委员_max": true,
|
||||
"point_limit_志愿委员_min": true,
|
||||
"point_limit_科任老师_max": true,
|
||||
"point_limit_科任老师_min": true,
|
||||
}
|
||||
|
||||
// SavePointLimits 保存角色加减分配置
|
||||
func (h *ClassHandler) SavePointLimits(c *gin.Context) {
|
||||
classID := middleware.GetClassID(c)
|
||||
|
||||
var req map[string]string
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
for key, value := range req {
|
||||
if !allowedPointLimitKeys[key] {
|
||||
response.BadRequest(c, "不允许的配置项: "+key)
|
||||
return
|
||||
}
|
||||
if err := h.classService.SaveSetting(classID, key, value); err != nil {
|
||||
response.InternalError(c, "保存配置失败")
|
||||
return
|
||||
}
|
||||
}
|
||||
response.SuccessWithMessage(c, "保存成功")
|
||||
}
|
||||
|
||||
// GetFeatures 获取功能开关
|
||||
func (h *ClassHandler) GetFeatures(c *gin.Context) {
|
||||
classID := middleware.GetClassID(c)
|
||||
result, err := h.classService.GetFeatures(classID)
|
||||
if err != nil {
|
||||
response.InternalError(c, "获取功能开关失败")
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// allowedFeatureKeys 允许的功能开关键白名单
|
||||
var allowedFeatureKeys = map[string]bool{
|
||||
"parent_account_enabled": true,
|
||||
"parent_password_change_enabled": true,
|
||||
"parent_view_attendance": true,
|
||||
"parent_view_ranking": true,
|
||||
"student_view_ranking": true,
|
||||
"homework_management": true,
|
||||
"attendance_management": true,
|
||||
"cadre_homework": true,
|
||||
}
|
||||
|
||||
// SaveFeature 保存功能开关
|
||||
func (h *ClassHandler) SaveFeature(c *gin.Context) {
|
||||
classID := middleware.GetClassID(c)
|
||||
|
||||
var req schema.FeatureToggleRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
if !allowedFeatureKeys[req.FeatureKey] {
|
||||
response.BadRequest(c, "不允许的功能开关: "+req.FeatureKey)
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.classService.SaveFeature(classID, req.FeatureKey, req.Enabled); err != nil {
|
||||
response.InternalError(c, "保存功能开关失败")
|
||||
return
|
||||
}
|
||||
response.SuccessWithMessage(c, "保存成功")
|
||||
}
|
||||
44
backend-go/internal/handler/config_handler.go
Normal file
44
backend-go/internal/handler/config_handler.go
Normal file
@@ -0,0 +1,44 @@
|
||||
// ===========================================
|
||||
// 多班级版班级管理系统 - Go 后端
|
||||
//
|
||||
// 开发者: Canglan
|
||||
// 联系方式: admin@sea-studio.top
|
||||
// 版权归属: Sea Network Technology Studio
|
||||
// 许可证: Apache License 2.0
|
||||
//
|
||||
// 版权所有 © Sea Network Technology Studio
|
||||
// ===========================================
|
||||
|
||||
package handler
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/service"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/pkg/response"
|
||||
)
|
||||
|
||||
// ConfigHandler 配置处理器
|
||||
type ConfigHandler struct {
|
||||
configService *service.ConfigService
|
||||
}
|
||||
|
||||
// NewConfigHandler 创建配置处理器
|
||||
func NewConfigHandler(configService *service.ConfigService) *ConfigHandler {
|
||||
return &ConfigHandler{configService: configService}
|
||||
}
|
||||
|
||||
// GetDeductionRules 获取扣分规则(优先从 class_settings 读取班级级配置)
|
||||
func (h *ConfigHandler) GetDeductionRules(c *gin.Context) {
|
||||
classID := 0
|
||||
if classIDStr := c.Query("class_id"); classIDStr != "" {
|
||||
if id, err := strconv.Atoi(classIDStr); err == nil {
|
||||
classID = id
|
||||
}
|
||||
}
|
||||
|
||||
rules := h.configService.GetDeductionRules(classID)
|
||||
response.Success(c, rules, "操作成功")
|
||||
}
|
||||
20
backend-go/internal/handler/handler_utils.go
Normal file
20
backend-go/internal/handler/handler_utils.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// parseQueryParamInt 解析查询参数为 int
|
||||
func parseQueryParamInt(c *gin.Context, key string, defaultVal int) int {
|
||||
val := c.Query(key)
|
||||
if val == "" {
|
||||
return defaultVal
|
||||
}
|
||||
i, err := strconv.Atoi(val)
|
||||
if err != nil {
|
||||
return defaultVal
|
||||
}
|
||||
return i
|
||||
}
|
||||
115
backend-go/internal/handler/parent_handler.go
Normal file
115
backend-go/internal/handler/parent_handler.go
Normal file
@@ -0,0 +1,115 @@
|
||||
// ===========================================
|
||||
// 多班级版班级管理系统 - Go 后端
|
||||
//
|
||||
// 开发者: Canglan
|
||||
// 联系方式: admin@sea-studio.top
|
||||
// 版权归属: Sea Network Technology Studio
|
||||
// 许可证: Apache License 2.0
|
||||
//
|
||||
// 版权所有 © Sea Network Technology Studio
|
||||
// ===========================================
|
||||
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/middleware"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/schema"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/service"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/pkg/response"
|
||||
)
|
||||
|
||||
// ParentHandler 家长端处理器
|
||||
type ParentHandler struct {
|
||||
parentService *service.ParentService
|
||||
authService *service.AuthService
|
||||
classService *service.ClassService
|
||||
}
|
||||
|
||||
// NewParentHandler 创建家长端处理器
|
||||
func NewParentHandler(
|
||||
parentService *service.ParentService,
|
||||
authService *service.AuthService,
|
||||
classService *service.ClassService,
|
||||
) *ParentHandler {
|
||||
return &ParentHandler{
|
||||
parentService: parentService,
|
||||
authService: authService,
|
||||
classService: classService,
|
||||
}
|
||||
}
|
||||
|
||||
// Dashboard 子女操行分(家长仪表盘)
|
||||
func (h *ParentHandler) Dashboard(c *gin.Context) {
|
||||
userID := middleware.GetUserID(c)
|
||||
result, err := h.parentService.GetChildConduct(userID)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// History 子女历史记录
|
||||
func (h *ParentHandler) History(c *gin.Context) {
|
||||
var query schema.ParentHistoryQuery
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
userID := middleware.GetUserID(c)
|
||||
result, err := h.parentService.GetChildHistory(userID, query.Page, query.PageSize)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// Attendance 子女考勤
|
||||
func (h *ParentHandler) Attendance(c *gin.Context) {
|
||||
userID := middleware.GetUserID(c)
|
||||
result, err := h.parentService.GetChildAttendance(userID)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// Ranking 子女排名
|
||||
func (h *ParentHandler) Ranking(c *gin.Context) {
|
||||
userID := middleware.GetUserID(c)
|
||||
result, err := h.parentService.GetChildRanking(userID)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// ChangePassword 家长修改密码(受功能开关控制)
|
||||
func (h *ParentHandler) ChangePassword(c *gin.Context) {
|
||||
classID := middleware.GetClassID(c)
|
||||
|
||||
// 检查功能开关
|
||||
if !h.classService.IsFeatureEnabled(classID, "parent_password_change_enabled") {
|
||||
response.Forbidden(c, "该功能暂未开放")
|
||||
return
|
||||
}
|
||||
|
||||
var req schema.ChangePasswordRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
userID := middleware.GetUserID(c)
|
||||
if err := h.authService.ChangePassword(userID, req.OldPassword, req.NewPassword, false); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.SuccessWithMessage(c, "密码修改成功")
|
||||
}
|
||||
230
backend-go/internal/handler/semester_handler.go
Normal file
230
backend-go/internal/handler/semester_handler.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 handler
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/middleware"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/schema"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/service"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/pkg/response"
|
||||
)
|
||||
|
||||
// SemesterHandler 学期管理处理器
|
||||
type SemesterHandler struct {
|
||||
semesterService *service.SemesterService
|
||||
}
|
||||
|
||||
// NewSemesterHandler 创建学期管理处理器
|
||||
func NewSemesterHandler(semesterService *service.SemesterService) *SemesterHandler {
|
||||
return &SemesterHandler{semesterService: semesterService}
|
||||
}
|
||||
|
||||
// SemesterList 学期列表
|
||||
func (h *SemesterHandler) SemesterList(c *gin.Context) {
|
||||
result, err := h.semesterService.ListSemesters()
|
||||
if err != nil {
|
||||
response.InternalError(c, "获取学期列表失败")
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// ActiveSemester 当前学期
|
||||
func (h *SemesterHandler) ActiveSemester(c *gin.Context) {
|
||||
semester, err := h.semesterService.GetActiveSemester()
|
||||
if err != nil {
|
||||
response.Success(c, nil, "无活跃学期")
|
||||
return
|
||||
}
|
||||
response.Success(c, semester, "操作成功")
|
||||
}
|
||||
|
||||
// SemesterCreate 创建学期
|
||||
func (h *SemesterHandler) SemesterCreate(c *gin.Context) {
|
||||
var req schema.SemesterCreateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.semesterService.CreateSemester(req.SemesterName, req.StartDate, req.EndDate)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if success, _ := result["success"].(bool); !success {
|
||||
response.BadRequest(c, result["message"].(string))
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// ActivateSemester 激活学期
|
||||
func (h *SemesterHandler) ActivateSemester(c *gin.Context) {
|
||||
semesterID, ok := parseID(c, "semester_id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.semesterService.ActivateSemester(semesterID); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.SuccessWithMessage(c, "已设为当前学期")
|
||||
}
|
||||
|
||||
// SemesterUpdate 编辑学期
|
||||
func (h *SemesterHandler) SemesterUpdate(c *gin.Context) {
|
||||
semesterID, ok := parseID(c, "semester_id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
var req schema.SemesterUpdateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.semesterService.UpdateSemester(semesterID, req.SemesterName, req.StartDate, req.EndDate); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.SuccessWithMessage(c, "更新成功")
|
||||
}
|
||||
|
||||
// SemesterDelete 删除学期
|
||||
func (h *SemesterHandler) SemesterDelete(c *gin.Context) {
|
||||
semesterID, ok := parseID(c, "semester_id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.semesterService.DeleteSemester(semesterID); err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.SuccessWithMessage(c, "删除成功")
|
||||
}
|
||||
|
||||
// AssociateRecords 关联记录
|
||||
func (h *SemesterHandler) AssociateRecords(c *gin.Context) {
|
||||
semesterID, ok := parseID(c, "semester_id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.semesterService.AssociateRecords(semesterID)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if success, _ := result["success"].(bool); !success {
|
||||
response.BadRequest(c, result["message"].(string))
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// ArchiveSemester 归档学期
|
||||
func (h *SemesterHandler) ArchiveSemester(c *gin.Context) {
|
||||
semesterID, ok := parseID(c, "semester_id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
classID := parseQueryParamInt(c, "class_id", 0)
|
||||
resetScores := c.Query("reset_scores") == "true"
|
||||
|
||||
result, err := h.semesterService.ArchiveSemester(semesterID, classID, resetScores)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if success, _ := result["success"].(bool); !success {
|
||||
response.BadRequest(c, result["message"].(string))
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// GetArchiveData 归档数据
|
||||
func (h *SemesterHandler) GetArchiveData(c *gin.Context) {
|
||||
semesterID, ok := parseID(c, "semester_id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
classID := parseQueryParamInt(c, "class_id", 0)
|
||||
page := parseQueryParamInt(c, "page", 1)
|
||||
pageSize := parseQueryParamInt(c, "page_size", 20)
|
||||
|
||||
result, err := h.semesterService.GetArchiveRecords(semesterID, classID, page, pageSize)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// PeriodReset 手动触发周/月重置
|
||||
func (h *SemesterHandler) PeriodReset(c *gin.Context) {
|
||||
var req schema.PeriodResetRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
classID := middleware.GetClassID(c)
|
||||
if classID == 0 {
|
||||
response.BadRequest(c, "未指定班级")
|
||||
return
|
||||
}
|
||||
|
||||
userID := middleware.GetUserID(c)
|
||||
realName := middleware.GetRealName(c)
|
||||
ip := c.ClientIP()
|
||||
|
||||
if err := h.semesterService.PeriodReset(classID, req.Period, userID, realName, ip); err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.SuccessWithMessage(c, service.PeriodLabelCN(req.Period)+"重置成功")
|
||||
}
|
||||
|
||||
// GetPeriodArchives 查看周期归档数据
|
||||
func (h *SemesterHandler) GetPeriodArchives(c *gin.Context) {
|
||||
var req schema.PeriodArchiveQuery
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
classID := middleware.GetClassID(c)
|
||||
if classID == 0 {
|
||||
response.BadRequest(c, "未指定班级")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.semesterService.GetPeriodArchives(classID, req.Period, req.Page, req.PageSize)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
192
backend-go/internal/handler/student_handler.go
Normal file
192
backend-go/internal/handler/student_handler.go
Normal file
@@ -0,0 +1,192 @@
|
||||
// ===========================================
|
||||
// 多班级版班级管理系统 - Go 后端
|
||||
//
|
||||
// 开发者: Canglan
|
||||
// 联系方式: admin@sea-studio.top
|
||||
// 版权归属: Sea Network Technology Studio
|
||||
// 许可证: Apache License 2.0
|
||||
//
|
||||
// 版权所有 © Sea Network Technology Studio
|
||||
// ===========================================
|
||||
|
||||
package handler
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/middleware"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/repository"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/schema"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/service"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/pkg/response"
|
||||
)
|
||||
|
||||
// StudentHandler 学生端处理器
|
||||
type StudentHandler struct {
|
||||
studentService *service.StudentService
|
||||
classRepo *repository.ClassRepo
|
||||
}
|
||||
|
||||
// NewStudentHandler 创建学生端处理器
|
||||
func NewStudentHandler(studentService *service.StudentService, classRepo *repository.ClassRepo) *StudentHandler {
|
||||
return &StudentHandler{studentService: studentService, classRepo: classRepo}
|
||||
}
|
||||
|
||||
// Dashboard 学生个人信息(仪表盘)
|
||||
func (h *StudentHandler) Dashboard(c *gin.Context) {
|
||||
studentID := middleware.GetStudentID(c)
|
||||
if studentID == 0 {
|
||||
response.BadRequest(c, "非学生用户")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.studentService.GetStudentInfo(studentID)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// resolveStudentID 校验学生归属:学生只能查看自己的数据,家长只能查看关联子女,管理员可查看指定学生
|
||||
func (h *StudentHandler) resolveStudentID(c *gin.Context) (int, bool) {
|
||||
userType := middleware.GetUserType(c)
|
||||
if userType == "student" {
|
||||
// 学生只能查看自己的数据,忽略 URL 参数中的 student_id
|
||||
studentID := middleware.GetStudentID(c)
|
||||
if studentID == 0 {
|
||||
response.BadRequest(c, "非学生用户")
|
||||
return 0, false
|
||||
}
|
||||
return studentID, true
|
||||
}
|
||||
|
||||
requestedID, ok := parseID(c, "student_id")
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// 家长只能查看自己关联的子女数据
|
||||
if userType == "parent" {
|
||||
parentStudentID := middleware.GetStudentID(c)
|
||||
if parentStudentID == 0 || parentStudentID != requestedID {
|
||||
response.Forbidden(c, "无权访问该学生数据")
|
||||
return 0, false
|
||||
}
|
||||
return requestedID, true
|
||||
}
|
||||
|
||||
// 管理员/超级管理员允许查看(角色权限由路由中间件 RequireRole 控制)
|
||||
return requestedID, true
|
||||
}
|
||||
|
||||
// ConductHistory 学生操行分历史
|
||||
func (h *StudentHandler) ConductHistory(c *gin.Context) {
|
||||
studentID, ok := h.resolveStudentID(c)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
var query schema.StudentConductQuery
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.studentService.GetConductHistory(studentID, query.Limit, query.Offset)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// Homework 学生作业情况
|
||||
func (h *StudentHandler) Homework(c *gin.Context) {
|
||||
studentID, ok := h.resolveStudentID(c)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.studentService.GetHomeworkStatus(studentID)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// Attendance 学生考勤记录
|
||||
func (h *StudentHandler) Attendance(c *gin.Context) {
|
||||
studentID, ok := h.resolveStudentID(c)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
month := c.Query("month")
|
||||
result, err := h.studentService.GetAttendanceRecords(studentID, month)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// Ranking 操行分排行
|
||||
func (h *StudentHandler) Ranking(c *gin.Context) {
|
||||
classID := middleware.GetClassID(c)
|
||||
|
||||
// 检查班级功能开关:学生查看排行榜
|
||||
feature, err := h.classRepo.GetFeature(classID, "student_view_ranking")
|
||||
if err == nil && feature != nil && feature.Enabled == 0 {
|
||||
response.Forbidden(c, "该功能暂未开放")
|
||||
return
|
||||
}
|
||||
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "50"))
|
||||
if limit <= 0 {
|
||||
limit = 50
|
||||
}
|
||||
if limit > 500 {
|
||||
limit = 500
|
||||
}
|
||||
|
||||
result, err := h.studentService.GetRanking(classID, limit)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// MyInfo 学生个人信息
|
||||
func (h *StudentHandler) MyInfo(c *gin.Context) {
|
||||
studentID := middleware.GetStudentID(c)
|
||||
if studentID == 0 {
|
||||
response.BadRequest(c, "非学生用户")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.studentService.GetStudentInfo(studentID)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// SemesterRecords 学期归档记录
|
||||
func (h *StudentHandler) SemesterRecords(c *gin.Context) {
|
||||
studentID := middleware.GetStudentID(c)
|
||||
if studentID <= 0 {
|
||||
response.BadRequest(c, "非学生用户")
|
||||
return
|
||||
}
|
||||
result, err := h.studentService.GetSemesterRecords(studentID)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
152
backend-go/internal/handler/subject_handler.go
Normal file
152
backend-go/internal/handler/subject_handler.go
Normal file
@@ -0,0 +1,152 @@
|
||||
// ===========================================
|
||||
// 多班级版班级管理系统 - Go 后端
|
||||
//
|
||||
// 开发者: Canglan
|
||||
// 联系方式: admin@sea-studio.top
|
||||
// 版权归属: Sea Network Technology Studio
|
||||
// 许可证: Apache License 2.0
|
||||
//
|
||||
// 版权所有 © Sea Network Technology Studio
|
||||
// ===========================================
|
||||
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/schema"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/service"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/pkg/response"
|
||||
)
|
||||
|
||||
// SubjectHandler 科目管理处理器
|
||||
type SubjectHandler struct {
|
||||
subjectService *service.SubjectService
|
||||
}
|
||||
|
||||
// NewSubjectHandler 创建科目管理处理器
|
||||
func NewSubjectHandler(subjectService *service.SubjectService) *SubjectHandler {
|
||||
return &SubjectHandler{subjectService: subjectService}
|
||||
}
|
||||
|
||||
// SubjectList 科目列表
|
||||
func (h *SubjectHandler) SubjectList(c *gin.Context) {
|
||||
var isActive *bool
|
||||
if v := c.Query("is_active"); v == "true" {
|
||||
b := true
|
||||
isActive = &b
|
||||
} else if v == "false" {
|
||||
b := false
|
||||
isActive = &b
|
||||
}
|
||||
|
||||
result, err := h.subjectService.GetSubjects(isActive)
|
||||
if err != nil {
|
||||
response.InternalError(c, "获取科目列表失败")
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// SubjectCreate 创建科目
|
||||
func (h *SubjectHandler) SubjectCreate(c *gin.Context) {
|
||||
var req schema.SubjectCreateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.subjectService.CreateSubject(req.SubjectName, req.SubjectCode, req.SortOrder)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if success, _ := result["success"].(bool); !success {
|
||||
response.BadRequest(c, result["message"].(string))
|
||||
return
|
||||
}
|
||||
response.Success(c, result, "操作成功")
|
||||
}
|
||||
|
||||
// SubjectUpdate 更新科目
|
||||
func (h *SubjectHandler) SubjectUpdate(c *gin.Context) {
|
||||
subjectID, ok := parseID(c, "subject_id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
var req schema.SubjectUpdateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
updates := make(map[string]interface{})
|
||||
if req.SubjectName != nil {
|
||||
updates["subject_name"] = *req.SubjectName
|
||||
}
|
||||
if req.SubjectCode != nil {
|
||||
updates["subject_code"] = *req.SubjectCode
|
||||
}
|
||||
if req.IsActive != nil {
|
||||
updates["is_active"] = *req.IsActive
|
||||
}
|
||||
if req.SortOrder != nil {
|
||||
updates["sort_order"] = *req.SortOrder
|
||||
}
|
||||
|
||||
if err := h.subjectService.UpdateSubject(subjectID, updates); err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.SuccessWithMessage(c, "更新成功")
|
||||
}
|
||||
|
||||
// SubjectDelete 删除科目
|
||||
func (h *SubjectHandler) SubjectDelete(c *gin.Context) {
|
||||
subjectID, ok := parseID(c, "subject_id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.subjectService.DeleteSubject(subjectID); err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
response.SuccessWithMessage(c, "删除成功")
|
||||
}
|
||||
|
||||
// SubjectToggle 切换科目启用/禁用状态
|
||||
func (h *SubjectHandler) SubjectToggle(c *gin.Context) {
|
||||
subjectID, ok := parseID(c, "subject_id")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
IsActive bool `json:"is_active"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
var err error
|
||||
if req.IsActive {
|
||||
err = h.subjectService.EnableSubject(subjectID)
|
||||
} else {
|
||||
err = h.subjectService.DisableSubject(subjectID)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if req.IsActive {
|
||||
response.SuccessWithMessage(c, "科目已启用")
|
||||
} else {
|
||||
response.SuccessWithMessage(c, "科目已禁用")
|
||||
}
|
||||
}
|
||||
56
backend-go/internal/handler/super_admin_handler.go
Normal file
56
backend-go/internal/handler/super_admin_handler.go
Normal file
@@ -0,0 +1,56 @@
|
||||
// ===========================================
|
||||
// 多班级版班级管理系统 - Go 后端
|
||||
//
|
||||
// 开发者: Canglan
|
||||
// 联系方式: admin@sea-studio.top
|
||||
// 版权归属: Sea Network Technology Studio
|
||||
// 许可证: Apache License 2.0
|
||||
//
|
||||
// 版权所有 © Sea Network Technology Studio
|
||||
// ===========================================
|
||||
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/schema"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/internal/service"
|
||||
"hz-gitea.sea-studio.top/canglan/SharedClassManager/pkg/response"
|
||||
)
|
||||
|
||||
// SuperAdminHandler 超级管理员处理器
|
||||
type SuperAdminHandler struct {
|
||||
superAdminService *service.SuperAdminService
|
||||
}
|
||||
|
||||
// NewSuperAdminHandler 创建超级管理员处理器
|
||||
func NewSuperAdminHandler(superAdminService *service.SuperAdminService) *SuperAdminHandler {
|
||||
return &SuperAdminHandler{superAdminService: superAdminService}
|
||||
}
|
||||
|
||||
// Login 超级管理员登录
|
||||
func (h *SuperAdminHandler) Login(c *gin.Context) {
|
||||
var req schema.LoginRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
ip := c.ClientIP()
|
||||
userAgent := c.GetHeader("User-Agent")
|
||||
result, err := h.superAdminService.Login(req.Username, req.Password, ip, userAgent)
|
||||
if err != nil {
|
||||
response.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
success, ok := result["success"].(bool)
|
||||
if !ok || !success {
|
||||
msg, _ := result["message"].(string)
|
||||
response.Unauthorized(c, msg)
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, result, "登录成功")
|
||||
}
|
||||
Reference in New Issue
Block a user