yanlongqi 441eb215f6 将CSS迁移到Less并添加用户认证功能
主要变更:
- 将所有CSS文件迁移到Less预处理器
- 配置Vite支持Less编译
- 使用Less变量、嵌套和父选择器优化样式代码
- 添加用户注册和登录功能
- 实现用户认证中间件和保护路由
- 新增Profile和Login页面
- 添加底部导航栏组件TabBarLayout
- 更新CLAUDE.md为中文文档

技术改进:
- Less变量统一管理主题色和间距
- CSS嵌套提高代码可读性和可维护性
- 模块化样式组织更清晰

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 23:21:38 +08:00

191 lines
4.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.

package handlers
import (
"ankao/internal/models"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"net/http"
"os"
"time"
"github.com/gin-gonic/gin"
)
const usersFilePath = "users.json"
// loadUsers 从JSON文件加载用户数据
func loadUsers() (models.UserData, error) {
file, err := os.ReadFile(usersFilePath)
if err != nil {
return nil, fmt.Errorf("读取用户文件失败: %w", err)
}
var users models.UserData
if err := json.Unmarshal(file, &users); err != nil {
return nil, fmt.Errorf("解析用户数据失败: %w", err)
}
return users, nil
}
// saveUsers 保存用户数据到JSON文件
func saveUsers(users models.UserData) error {
data, err := json.MarshalIndent(users, "", " ")
if err != nil {
return fmt.Errorf("序列化用户数据失败: %w", err)
}
if err := os.WriteFile(usersFilePath, data, 0644); err != nil {
return fmt.Errorf("保存用户文件失败: %w", err)
}
return nil
}
// 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
}
// 加载用户数据
users, err := loadUsers()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"success": false,
"message": "服务器错误",
"error": err.Error(),
})
return
}
// 验证用户
user, exists := users[req.Username]
if !exists {
c.JSON(http.StatusUnauthorized, gin.H{
"success": false,
"message": "用户名或密码错误",
})
return
}
// 验证密码
if user.Password != req.Password {
c.JSON(http.StatusUnauthorized, gin.H{
"success": false,
"message": "用户名或密码错误",
})
return
}
// 生成token
token := generateToken(req.Username)
// 返回用户信息(不包含密码)
userInfo := models.UserInfoResponse{
Username: req.Username,
Avatar: user.Avatar,
Nickname: user.Nickname,
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "登录成功",
"data": models.LoginResponse{
Token: token,
User: userInfo,
},
})
}
// 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
}
// 加载现有用户数据
users, err := loadUsers()
if err != nil {
// 如果文件不存在,创建新的用户数据
users = make(models.UserData)
}
// 检查用户名是否已存在
if _, exists := users[req.Username]; exists {
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": "用户名已存在",
})
return
}
// 创建新用户
newUser := models.User{
Username: req.Username,
Password: req.Password, // 实际项目应该加密存储
Nickname: req.Nickname,
Avatar: "https://api.dicebear.com/7.x/avataaars/svg?seed=" + req.Username, // 使用用户名生成默认头像
}
// 如果没有提供昵称,使用用户名
if newUser.Nickname == "" {
newUser.Nickname = req.Username
}
// 添加新用户
users[req.Username] = newUser
// 保存用户数据
if err := saveUsers(users); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"success": false,
"message": "注册失败",
"error": err.Error(),
})
return
}
// 生成token
token := generateToken(req.Username)
// 返回用户信息
userInfo := models.UserInfoResponse{
Username: newUser.Username,
Avatar: newUser.Avatar,
Nickname: newUser.Nickname,
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "注册成功",
"data": models.LoginResponse{
Token: token,
User: userInfo,
},
})
}