feat: PhotoWall 毕业照存储系统初始版本

后端: Go(Gin+GORM+MySQL+Redis)
- 17张业务表(yz_pw_前缀), 自动迁移
- JWT认证(3小时) + 盐+MD5密码 + 图形验证码
- 班级CRUD/加入(8人姓名验证/邀请码)/审核/30天自动清理
- 系统配置(16项)/菜单管理(动态路由)/数据统计
- 文件MD5去重/数据隔离/账号封禁/敏感词DFA检测

前端: Vue3+Vite+Element Plus+Less+ECharts+FontAwesome
- 动态路由(数据库菜单驱动)
- 蓝白配色, H5响应式
- 登录/注册/忘记密码/个人中心
- 班级创建向导/详情/加入/列表
- 管理后台: 审核/配置/菜单/统计/用户/敏感词

数据库: MySQL 10.31.100.3:3306/photowall
管理员: hero920103 / 920103
This commit is contained in:
hero920103
2026-09-03 05:55:23 +08:00
commit 57d9866dab
82 changed files with 12668 additions and 0 deletions
+55
View File
@@ -0,0 +1,55 @@
package jwt
import (
"errors"
"time"
"github.com/golang-jwt/jwt/v5"
)
type Claims struct {
UserID uint `json:"uid"`
Username string `json:"username"`
Role string `json:"role"`
jwt.RegisteredClaims
}
type Manager struct {
Secret []byte
ExpireHrs int
}
func New(secret string, expireHrs int) *Manager {
return &Manager{Secret: []byte(secret), ExpireHrs: expireHrs}
}
func (m *Manager) Generate(userID uint, username, role string) (string, error) {
claims := Claims{
UserID: userID,
Username: username,
Role: role,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(m.ExpireHrs) * time.Hour)),
IssuedAt: jwt.NewNumericDate(time.Now()),
},
}
t := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return t.SignedString(m.Secret)
}
func (m *Manager) Parse(tokenStr string) (*Claims, error) {
claims := &Claims{}
t, err := jwt.ParseWithClaims(tokenStr, claims, func(t *jwt.Token) (interface{}, error) {
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, errors.New("unexpected signing method")
}
return m.Secret, nil
})
if err != nil {
return nil, err
}
if !t.Valid {
return nil, errors.New("invalid token")
}
return claims, nil
}