- User 模型增加 exp 字段,等级规则 Lv0-Lv6 - 新增签到记录(UserCheckIn)与任务记录(UserTask)模型,唯一索引防重 - 自动签到:AuthMiddleware 验证会话后,基于 Asia/Shanghai 自然日自动签到 +5 经验 - 手动签到:下拉菜单"签到"按钮兜底,已签到显示"今日已签到"并禁用 - 首次任务经验:上传头像/设置用户名/设置个性签名各 +10,审核通过与直接更新均触发 - 经验值变动后自动比对等级,升级时通过通知系统发送"恭喜提升至 LvX" - 下拉菜单重构:顶部头像+用户名+LvX 等级标签,菜单项增加左侧图标,优化布局样式 - 新增 API:POST /api/level/checkin、GET /api/level/info
44 lines
1.2 KiB
Go
44 lines
1.2 KiB
Go
package session
|
||
|
||
import (
|
||
"crypto/rand"
|
||
"encoding/hex"
|
||
"time"
|
||
)
|
||
|
||
// Session 服务端会话,替代 JWT 无状态令牌
|
||
type Session struct {
|
||
ID string // 会话唯一标识(64 位 hex)
|
||
UserID uint // 用户 ID
|
||
Email string // 邮箱
|
||
Username string // 用户名
|
||
Avatar string // 头像 URL
|
||
Role string // 角色
|
||
Exp int // 经验值(用于前端实时展示等级)
|
||
RememberMe bool // 是否持久化(决定 cookie maxAge)
|
||
IP string // 登录 IP
|
||
UserAgent string // 登录设备 User-Agent
|
||
Remark string // 用户备注(如"我的笔记本")
|
||
CreatedAt time.Time // 创建时间
|
||
LastAccess time.Time // 最后访问时间(滑动窗口)
|
||
}
|
||
|
||
// IsExpired 检查会话是否已过期
|
||
func (s *Session) IsExpired(idleTimeout time.Duration) bool {
|
||
return time.Since(s.LastAccess) > idleTimeout
|
||
}
|
||
|
||
// Touch 更新最后访问时间(续期)
|
||
func (s *Session) Touch() {
|
||
s.LastAccess = time.Now()
|
||
}
|
||
|
||
// NewID 生成 32 字节随机 hex 字符串作为会话 ID
|
||
func NewID() (string, error) {
|
||
b := make([]byte, 32)
|
||
if _, err := rand.Read(b); err != nil {
|
||
return "", err
|
||
}
|
||
return hex.EncodeToString(b), nil
|
||
}
|