feat: 实现前端卡密管理界面

- 卡密列表展示与分页功能

- 单个/批量创建卡密

- 卡密删除与批量删除

- 卡密导出功能 (file-saver)

- 启用/禁用状态切换

- 状态判断 (有效/已使用/已失效)

- Toast 通知系统 (vue-sonner)

- 登录页面错误提示优化

- 后端登录错误消息中文化
This commit is contained in:
sar
2026-01-13 21:34:56 +08:00
parent 42c423bd32
commit 8d60704eda
143 changed files with 6646 additions and 91 deletions

View File

@@ -0,0 +1,66 @@
package auth
import (
"errors"
"os"
"time"
"github.com/golang-jwt/jwt/v5"
)
var jwtSecret = []byte(getJWTSecret())
// Claims JWT 声明
type Claims struct {
UserID int `json:"user_id"`
Username string `json:"username"`
IsSuperAdmin bool `json:"is_super_admin"`
jwt.RegisteredClaims
}
// GenerateToken 生成 JWT Token
func GenerateToken(userID int, username string, isSuperAdmin bool) (string, error) {
expireHours := 24 // Token 有效期 24 小时
claims := &Claims{
UserID: userID,
Username: username,
IsSuperAdmin: isSuperAdmin,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(expireHours) * time.Hour)),
IssuedAt: jwt.NewNumericDate(time.Now()),
NotBefore: jwt.NewNumericDate(time.Now()),
Issuer: "gpt-manager",
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(jwtSecret)
}
// ParseToken 解析 JWT Token
func ParseToken(tokenString string) (*Claims, error) {
token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, errors.New("invalid signing method")
}
return jwtSecret, nil
})
if err != nil {
return nil, err
}
if claims, ok := token.Claims.(*Claims); ok && token.Valid {
return claims, nil
}
return nil, errors.New("invalid token")
}
func getJWTSecret() string {
if secret := os.Getenv("JWT_SECRET"); secret != "" {
return secret
}
return "your-default-secret-key-change-in-production"
}