yanlongqi 3b7133d9de 添加论述题权限控制系统和AI评分功能
本次更新实现了基于用户类型的论述题访问权限控制,并为论述题添加了专门的AI评分功能。

后端更新:
- 添加论述题权限验证:根据用户类型(ordinary-person/management-person)控制不同论述题的访问权限
- 新增 GradeEssay 方法:为论述题提供专门的AI评分,不依赖标准答案,基于保密法规进行专业评分
- 优化AI评分提示词:增加法规依据要求,返回参考答案、评分依据等更详细的评分信息
- 添加用户类型管理:新增 UpdateUserType API,支持用户更新个人类型
- 路由调整:将练习题相关API移至需要认证的路由组

前端更新:
- 论述题答题界面优化:不显示标准答案,展示AI评分的参考答案和评分依据
- 用户类型选择:登录/注册时支持选择用户类型
- 权限控制适配:根据用户类型显示对应的论述题列表

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 16:47:37 +08:00

247 lines
5.5 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.

package handlers
import (
"ankao/internal/database"
"ankao/internal/models"
"crypto/sha256"
"encoding/hex"
"fmt"
"net/http"
"time"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
// generateToken 生成简单的token实际项目应使用JWT
func generateToken(username string) string {
data := fmt.Sprintf("%s:%d", username, time.Now().Unix())
hash := sha256.Sum256([]byte(data))
return hex.EncodeToString(hash[:])
}
// Login 用户登录处理
func Login(c *gin.Context) {
var req models.LoginRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": "请求参数错误",
"error": err.Error(),
})
return
}
// 从数据库查找用户
var user models.User
db := database.GetDB()
result := db.Where("username = ?", req.Username).First(&user)
if result.Error != nil {
if result.Error == gorm.ErrRecordNotFound {
c.JSON(http.StatusUnauthorized, gin.H{
"success": false,
"message": "用户名或密码错误",
})
return
}
c.JSON(http.StatusInternalServerError, gin.H{
"success": false,
"message": "服务器错误",
"error": result.Error.Error(),
})
return
}
// 验证密码
if !user.CheckPassword(req.Password) {
c.JSON(http.StatusUnauthorized, gin.H{
"success": false,
"message": "用户名或密码错误",
})
return
}
// 生成token
token := generateToken(req.Username)
// 保存token到数据库
user.Token = token
if err := db.Save(&user).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"success": false,
"message": "token保存失败",
})
return
}
// 返回用户信息(不包含密码)
userInfo := models.UserInfoResponse{
Username: user.Username,
Avatar: user.Avatar,
Nickname: user.Nickname,
UserType: user.UserType, // 返回用户类型
}
// 检查用户类型是否为空,如果为空,标识需要补充
needUserType := user.UserType == ""
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "登录成功",
"data": models.LoginResponse{
Token: token,
User: userInfo,
},
"need_user_type": needUserType, // 添加标识,前端根据此标识显示补充弹窗
})
}
// Register 用户注册处理
func Register(c *gin.Context) {
var req models.RegisterRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": "请求参数错误",
"error": err.Error(),
})
return
}
db := database.GetDB()
// 检查用户名是否已存在
var existingUser models.User
result := db.Where("username = ?", req.Username).First(&existingUser)
if result.Error == nil {
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": "用户名已存在",
})
return
}
// 创建新用户
newUser := models.User{
Username: req.Username,
Nickname: req.Nickname,
UserType: req.UserType, // 保存用户类型
Avatar: "https://api.dicebear.com/7.x/avataaars/svg?seed=" + req.Username, // 使用用户名生成默认头像
}
// 如果没有提供昵称,使用用户名
if newUser.Nickname == "" {
newUser.Nickname = req.Username
}
// 加密密码
if err := newUser.HashPassword(req.Password); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"success": false,
"message": "密码加密失败",
"error": err.Error(),
})
return
}
// 生成token
token := generateToken(req.Username)
// 设置token
newUser.Token = token
// 保存到数据库
if err := db.Create(&newUser).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"success": false,
"message": "注册失败",
"error": err.Error(),
})
return
}
// 返回用户信息
userInfo := models.UserInfoResponse{
Username: newUser.Username,
Avatar: newUser.Avatar,
Nickname: newUser.Nickname,
UserType: newUser.UserType, // 返回用户类型
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "注册成功",
"data": models.LoginResponse{
Token: token,
User: userInfo,
},
})
}
// UpdateUserTypeRequest 更新用户类型请求
type UpdateUserTypeRequest struct {
UserType string `json:"user_type" binding:"required,oneof=ordinary-person management-person"`
}
// UpdateUserType 更新用户类型
func UpdateUserType(c *gin.Context) {
var req UpdateUserTypeRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": "请求参数错误,用户类型必须是 ordinary-person 或 management-person",
"error": err.Error(),
})
return
}
// 从上下文获取用户信息(由认证中间件设置)
username, exists := c.Get("username")
if !exists {
c.JSON(http.StatusUnauthorized, gin.H{
"success": false,
"message": "未授权访问",
})
return
}
db := database.GetDB()
var user models.User
if err := db.Where("username = ?", username).First(&user).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{
"success": false,
"message": "用户不存在",
})
return
}
// 更新用户类型
user.UserType = req.UserType
if err := db.Save(&user).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"success": false,
"message": "更新用户类型失败",
"error": err.Error(),
})
return
}
// 返回更新后的用户信息
userInfo := models.UserInfoResponse{
Username: user.Username,
Avatar: user.Avatar,
Nickname: user.Nickname,
UserType: user.UserType,
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "用户类型更新成功",
"data": userInfo,
})
}