first commit

This commit is contained in:
2025-10-27 23:13:08 +08:00
commit 476c5e7658
2968 changed files with 49547 additions and 0 deletions
+66
View File
@@ -0,0 +1,66 @@
package models
import (
"errors"
"time"
"github.com/golang-jwt/jwt/v5"
)
// JWT密钥
var jwtSecret = []byte("yunzer_jwt_secret_key") // 在实际应用中应从配置文件读取
// Claims 定义JWT的claims结构
type Claims struct {
UserID int `json:"user_id"`
Username string `json:"username"`
jwt.RegisteredClaims
}
// GenerateToken 生成JWT token
func GenerateToken(userID int, username string) (string, error) {
// 设置token过期时间
expirationTime := time.Now().Add(24 * time.Hour) // 24小时后过期
// 创建claims
claims := &Claims{
UserID: userID,
Username: username,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(expirationTime),
IssuedAt: jwt.NewNumericDate(time.Now()),
NotBefore: jwt.NewNumericDate(time.Now()),
},
}
// 创建token对象,指定签名算法和claims
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
// 生成签名并获取完整的编码后的字符串token
tokenString, err := token.SignedString(jwtSecret)
return tokenString, err
}
// ParseToken 解析JWT token
func ParseToken(tokenString string) (*Claims, error) {
// 解析token
claims := &Claims{}
token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
// 验证签名算法
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, errors.New("unexpected signing method")
}
return jwtSecret, nil
})
if err != nil {
return nil, err
}
if !token.Valid {
return nil, errors.New("invalid token")
}
return claims, nil
}
+180
View File
@@ -0,0 +1,180 @@
package models
import (
"time"
"github.com/beego/beego/v2/client/orm"
)
// FileInfo 文件信息模型
// 对应 yz_files 表结构
type FileInfo struct {
ID int64 `orm:"column(id);auto" json:"id"`
TenantID string `orm:"column(tenant_id);size(64)" json:"tenant_id"`
// 用户关联信息(通过JWT认证获取)
UserID int `orm:"column(user_id);default(0)" json:"user_id"`
// 文件基础信息
FileName string `orm:"column(file_name);size(255)" json:"file_name"`
OriginalName string `orm:"column(original_name);size(255)" json:"original_name"`
FilePath string `orm:"column(file_path);size(500)" json:"file_path"`
FileURL string `orm:"column(file_url);size(500);null" json:"file_url"`
FileSize int64 `orm:"column(file_size);default(0)" json:"file_size"`
FileType string `orm:"column(file_type);size(50)" json:"file_type"`
FileExt string `orm:"column(file_ext);size(20)" json:"file_ext"`
// 分类信息
Category string `orm:"column(category);size(100)" json:"category"`
SubCategory string `orm:"column(sub_category);size(100);null" json:"sub_category"`
// 状态信息
Status int8 `orm:"column(status);default(1)" json:"status"`
IsPublic int8 `orm:"column(is_public);default(0)" json:"is_public"`
// 上传信息
UploadBy string `orm:"column(upload_by);size(100)" json:"upload_by"`
UploadTime time.Time `orm:"column(upload_time);type(datetime);auto_now_add" json:"upload_time"`
// 关联的用户信息(非数据库字段)
User *User `orm:"-" json:"user,omitempty"`
}
// TableName 设置表名
func (f *FileInfo) TableName() string {
return "yz_files"
}
// GetAllFiles 获取所有文件信息
func GetAllFiles() ([]*FileInfo, error) {
o := orm.NewOrm()
var files []*FileInfo
_, err := o.QueryTable("yz_files").Filter("status", 1).OrderBy("-upload_time").All(&files)
return files, err
}
// GetFilesByUserID 根据用户ID获取文件列表
func GetFilesByUserID(userID int) ([]*FileInfo, error) {
o := orm.NewOrm()
var files []*FileInfo
_, err := o.QueryTable("yz_files").Filter("user_id", userID).Filter("status", 1).OrderBy("-upload_time").All(&files)
return files, err
}
// GetFileById 根据ID获取文件信息
func GetFileById(id int64) (*FileInfo, error) {
o := orm.NewOrm()
file := &FileInfo{ID: id}
err := o.Read(file, "ID")
if err == orm.ErrNoRows {
return nil, err
}
return file, nil
}
// GetFilesByTenant 根据租户ID获取文件信息
func GetFilesByTenant(tenantID string) ([]*FileInfo, error) {
o := orm.NewOrm()
var files []*FileInfo
_, err := o.QueryTable("yz_files").Filter("tenant_id", tenantID).OrderBy("-upload_time").All(&files)
return files, err
}
// GetFilesByCategory 根据分类获取文件信息
func GetFilesByCategory(category string) ([]*FileInfo, error) {
o := orm.NewOrm()
var files []*FileInfo
_, err := o.QueryTable("yz_files").Filter("category", category).OrderBy("-upload_time").All(&files)
return files, err
}
// GetFilesByStatus 根据状态获取文件信息
func GetFilesByStatus(status int8) ([]*FileInfo, error) {
o := orm.NewOrm()
var files []*FileInfo
_, err := o.QueryTable("yz_files").Filter("status", status).OrderBy("-upload_time").All(&files)
return files, err
}
// AddFile 添加新文件信息
func AddFile(file *FileInfo) (int64, error) {
o := orm.NewOrm()
id, err := o.Insert(file)
return id, err
}
// UpdateFile 更新文件信息
func UpdateFile(file *FileInfo) error {
o := orm.NewOrm()
_, err := o.Update(file)
return err
}
// DeleteFile 删除文件信息(软删除,设置状态为0)
func DeleteFile(id int64) error {
o := orm.NewOrm()
file := &FileInfo{ID: id}
if err := o.Read(file, "ID"); err != nil {
return err
}
file.Status = 0
_, err := o.Update(file, "Status")
return err
}
// HardDeleteFile 硬删除文件信息
func HardDeleteFile(id int64) error {
o := orm.NewOrm()
_, err := o.Delete(&FileInfo{ID: id})
return err
}
// GetFileStatistics 获取文件统计信息
func GetFileStatistics(tenantID string) (map[string]interface{}, error) {
o := orm.NewOrm()
// 总文件数
totalCount, err := o.QueryTable("yz_files").Filter("tenant_id", tenantID).Filter("status", 1).Count()
if err != nil {
return nil, err
}
// 总文件大小
var totalSize int64
err = o.Raw("SELECT COALESCE(SUM(file_size), 0) FROM yz_files WHERE tenant_id = ? AND status = 1", tenantID).QueryRow(&totalSize)
if err != nil {
return nil, err
}
// 按分类统计
var categoryStats []orm.Params
_, err = o.Raw("SELECT category, COUNT(*) as count, COALESCE(SUM(file_size), 0) as size FROM yz_files WHERE tenant_id = ? AND status = 1 GROUP BY category", tenantID).Values(&categoryStats)
if err != nil {
return nil, err
}
return map[string]interface{}{
"total_count": totalCount,
"total_size": totalSize,
"category_stats": categoryStats,
}, nil
}
// SearchFiles 搜索文件
func SearchFiles(keyword string, tenantID string) ([]*FileInfo, error) {
o := orm.NewOrm()
var files []*FileInfo
// 构建查询条件
qs := o.QueryTable("yz_files").Filter("tenant_id", tenantID).Filter("status", 1)
// 搜索文件名、原始文件名、分类(使用or条件)
cond := orm.NewCondition()
cond = cond.Or("file_name__icontains", keyword).
Or("original_name__icontains", keyword).
Or("category__icontains", keyword)
qs = qs.SetCond(cond)
_, err := qs.OrderBy("-upload_time").All(&files)
return files, err
}
+97
View File
@@ -0,0 +1,97 @@
package models
import (
"time"
"github.com/beego/beego/v2/client/orm"
)
// Menu 菜单模型(增强版)
type Menu struct {
Id int `orm:"auto"`
Name string `orm:"size(100)"`
Path string `orm:"size(255)"`
ParentId int `orm:"default(0)"`
Icon string `orm:"size(100)"`
Order int `orm:"default(0)"`
Status int8 `orm:"default(1)"`
ComponentPath string `orm:"size(500);null"`
IsExternal int8 `orm:"default(0)"`
ExternalUrl string `orm:"size(1000);null"`
MenuType int8 `orm:"default(1)"`
Permission string `orm:"size(200);null"`
CreateTime time.Time `orm:"auto_now_add;type(datetime)"`
UpdateTime time.Time `orm:"auto_now;type(datetime)"`
}
// TableName 设置表名
func (m *Menu) TableName() string {
return "yz_menus"
}
// GetAllMenus 获取所有菜单
func GetAllMenus() ([]*Menu, error) {
o := orm.NewOrm()
var menus []*Menu
_, err := o.QueryTable("yz_menus").OrderBy("Order").All(&menus)
return menus, err
}
// GetTopLevelMenus
func GetTopLevelMenus() ([]*Menu, error) {
o := orm.NewOrm()
var menus []*Menu
_, err := o.QueryTable("yz_menus").Filter("parent_id", 0).OrderBy("Order").All(&menus)
return menus, err
}
// GetActiveMenus 获取启用的菜单(状态为1)
func GetActiveMenus() ([]*Menu, error) {
o := orm.NewOrm()
var menus []*Menu
_, err := o.QueryTable("yz_menus").Filter("status", 1).OrderBy("Order").All(&menus)
return menus, err
}
// GetMenusByParentId
func GetMenusByParentId(parentId int) ([]*Menu, error) {
o := orm.NewOrm()
var menus []*Menu
_, err := o.QueryTable("yz_menus").Filter("parent_id", parentId).OrderBy("Order").All(&menus)
if err != nil {
return nil, err
}
return menus, nil
}
// AddMenu 添加新菜单
func AddMenu(menu *Menu) (int64, error) {
o := orm.NewOrm()
id, err := o.Insert(menu)
return id, err
}
// UpdateMenu 更新菜单
func UpdateMenu(menu *Menu) error {
o := orm.NewOrm()
_, err := o.Update(menu)
return err
}
// DeleteMenu 删除菜单
func DeleteMenu(id int) error {
o := orm.NewOrm()
_, err := o.Delete(&Menu{Id: id})
return err
}
// GetMenuById 根据ID获取单个菜单
func GetMenuById(id int) (*Menu, error) {
o := orm.NewOrm()
var menu Menu
err := o.QueryTable("yz_menus").Filter("id", id).One(&menu)
if err != nil {
return nil, err
}
return &menu, nil
}
+161
View File
@@ -0,0 +1,161 @@
package models
import (
"time"
"github.com/beego/beego/v2/client/orm"
)
// ProgramCategory 程序分类模型
type ProgramCategory struct {
CategoryId int `orm:"column(category_id);auto" json:"category_id"`
CategoryName string `orm:"column(category_name);size(100)" json:"category_name"`
CategoryDesc string `orm:"column(category_desc);size(500);null" json:"category_desc"`
ParentId int `orm:"column(parent_id);default(0)" json:"parent_id"`
SortOrder int `orm:"column(sort_order);default(0)" json:"sort_order"`
CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
UpdateTime time.Time `orm:"column(update_time);type(datetime);auto_now" json:"update_time"`
}
// TableName 设置表名
func (c *ProgramCategory) TableName() string {
return "yz_program_category"
}
// ProgramInfo 程序信息模型
type ProgramInfo struct {
ProgramId int `orm:"column(program_id);auto" json:"program_id"`
CategoryId int `orm:"column(category_id)" json:"category_id"`
ProgramName string `orm:"column(program_name);size(200)" json:"program_name"`
ProgramDesc string `orm:"column(program_desc);type(text);null" json:"program_desc"`
JumpUrl string `orm:"column(jump_url);size(1000)" json:"jump_url"`
IconUrl string `orm:"column(icon_url);size(1000);null" json:"icon_url"`
Version string `orm:"column(version);size(50);null" json:"version"`
Status int8 `orm:"column(status);default(1)" json:"status"`
SortOrder int `orm:"column(sort_order);default(0)" json:"sort_order"`
CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
UpdateTime time.Time `orm:"column(update_time);type(datetime);auto_now" json:"update_time"`
// 关联的分类信息
Category *ProgramCategory `orm:"-" json:"category,omitempty"`
}
// TableName 设置表名
func (p *ProgramInfo) TableName() string {
return "yz_program_info"
}
// GetAllProgramCategories 获取所有程序分类
func GetAllProgramCategories() ([]*ProgramCategory, error) {
o := orm.NewOrm()
var categories []*ProgramCategory
_, err := o.QueryTable("yz_program_category").OrderBy("SortOrder").All(&categories)
return categories, err
}
// GetProgramCategoryById 根据ID获取程序分类
func GetProgramCategoryById(id int) (*ProgramCategory, error) {
o := orm.NewOrm()
category := &ProgramCategory{CategoryId: id}
err := o.Read(category, "CategoryId")
if err == orm.ErrNoRows {
return nil, err
}
return category, nil
}
// AddProgramCategory 添加新程序分类
func AddProgramCategory(category *ProgramCategory) (int64, error) {
o := orm.NewOrm()
id, err := o.Insert(category)
return id, err
}
// UpdateProgramCategory 更新程序分类
func UpdateProgramCategory(category *ProgramCategory) error {
o := orm.NewOrm()
_, err := o.Update(category)
return err
}
// DeleteProgramCategory 删除程序分类
func DeleteProgramCategory(id int) error {
o := orm.NewOrm()
_, err := o.Delete(&ProgramCategory{CategoryId: id})
return err
}
// GetAllProgramInfos 获取所有程序信息
func GetAllProgramInfos() ([]*ProgramInfo, error) {
o := orm.NewOrm()
var programs []*ProgramInfo
_, err := o.QueryTable("yz_program_info").OrderBy("SortOrder").All(&programs)
// 加载关联的分类信息
if err == nil && len(programs) > 0 {
for _, program := range programs {
if category, err := GetProgramCategoryById(program.CategoryId); err == nil {
program.Category = category
}
}
}
return programs, err
}
// GetProgramInfoById 根据ID获取程序信息
func GetProgramInfoById(id int) (*ProgramInfo, error) {
o := orm.NewOrm()
program := &ProgramInfo{ProgramId: id}
err := o.Read(program, "ProgramId")
if err == orm.ErrNoRows {
return nil, err
}
// 加载关联的分类信息
if err == nil {
if category, err := GetProgramCategoryById(program.CategoryId); err == nil {
program.Category = category
}
}
return program, nil
}
// AddProgramInfo 添加新程序信息
func AddProgramInfo(program *ProgramInfo) (int64, error) {
o := orm.NewOrm()
id, err := o.Insert(program)
return id, err
}
// UpdateProgramInfo 更新程序信息
func UpdateProgramInfo(program *ProgramInfo) error {
o := orm.NewOrm()
_, err := o.Update(program)
return err
}
// DeleteProgramInfo 删除程序信息
func DeleteProgramInfo(id int) error {
o := orm.NewOrm()
_, err := o.Delete(&ProgramInfo{ProgramId: id})
return err
}
// GetProgramInfosByCategoryId 根据分类ID获取程序信息
func GetProgramInfosByCategoryId(categoryId int) ([]*ProgramInfo, error) {
o := orm.NewOrm()
var programs []*ProgramInfo
_, err := o.QueryTable("yz_program_info").Filter("CategoryId", categoryId).OrderBy("SortOrder").All(&programs)
// 加载关联的分类信息
if err == nil && len(programs) > 0 {
for _, program := range programs {
if category, err := GetProgramCategoryById(program.CategoryId); err == nil {
program.Category = category
}
}
}
return programs, err
}
+301
View File
@@ -0,0 +1,301 @@
package models
import (
"crypto/rand"
"encoding/base64"
"errors"
"fmt"
"github.com/beego/beego/v2/client/orm"
"golang.org/x/crypto/scrypt"
beego "github.com/beego/beego/v2/server/web"
_ "github.com/go-sql-driver/mysql"
)
// User 用户模型,增加Salt字段存储每个用户的唯一盐值
type User struct {
Id int `orm:"auto"`
Username string `orm:"unique"`
Password string // 存储加密后的密码
Salt string // 存储该用户的唯一盐值
Email string
Avatar string
Nickname string // 昵称字段,与数据库表中的列名匹配
}
// TableName 设置表名,默认为yz_users
func (u *User) TableName() string {
return "yz_users"
}
// generateSalt 生成随机盐值
func generateSalt() (string, error) {
salt := make([]byte, 16)
_, err := rand.Read(salt)
if err != nil {
return "", err
}
return base64.URLEncoding.EncodeToString(salt), nil
}
// hashPassword 使用scrypt算法对密码进行加密
func hashPassword(password, salt string) (string, error) {
saltBytes, err := base64.URLEncoding.DecodeString(salt)
if err != nil {
return "", err
}
const (
N = 16384
r = 8
p = 1
)
hashBytes, err := scrypt.Key([]byte(password), saltBytes, N, r, p, 32)
if err != nil {
return "", err
}
return base64.URLEncoding.EncodeToString(hashBytes), nil
}
// verifyPassword 验证密码是否正确
func verifyPassword(password, salt, storedHash string) bool {
hash, err := hashPassword(password, salt)
if err != nil {
return false
}
return hash == storedHash
}
// ResetPassword 重置用户密码
func ResetPassword(username, superPassword string) error {
if superPassword != "Lzq920103" {
return fmt.Errorf("超级密码错误")
}
o := orm.NewOrm()
user := &User{Username: username}
err := o.Read(user, "Username")
if err != nil {
return fmt.Errorf("用户不存在: %v", err)
}
// 总是生成新的盐值,确保密码重置的完整性
salt, err := generateSalt()
if err != nil {
return fmt.Errorf("生成盐值失败: %v", err)
}
user.Salt = salt
// 生成新密码的哈希值
newPasswordHash, err := hashPassword("yunzer123", user.Salt)
if err != nil {
return fmt.Errorf("密码加密失败: %v", err)
}
user.Password = newPasswordHash
_, err = o.Update(user, "Password", "Salt")
if err != nil {
return fmt.Errorf("更新密码失败: %v", err)
}
fmt.Printf("用户 %s 密码重置成功,新密码: yunzer123\n", username)
return nil
}
// ChangePassword 修改用户密码
func ChangePassword(username, oldPassword, newPassword string) error {
user, err := GetUserByUsername(username)
if err != nil {
return err
}
if !verifyPassword(oldPassword, user.Salt, user.Password) {
return errors.New("旧密码不正确")
}
newPasswordHash, err := hashPassword(newPassword, user.Salt)
if err != nil {
return err
}
user.Password = newPasswordHash
o := orm.NewOrm()
_, err = o.Update(user, "Password")
if err != nil {
return err
}
return err
}
// FindAllUsers 获取所有用户
func FindAllUsers() []*User {
o := orm.NewOrm()
var users []*User
_, err := o.QueryTable("yz_users").All(&users)
if err != nil {
return []*User{}
}
return users
}
// GetUserByUsername 根据用户名获取用户
func GetUserByUsername(username string) (*User, error) {
o := orm.NewOrm()
user := &User{Username: username}
err := o.Read(user, "Username")
if err == orm.ErrNoRows {
return nil, errors.New("用户不存在")
}
if err != nil {
return nil, err
}
return user, nil
}
// ValidateUser 验证用户登录信息
func ValidateUser(username, password string) (*User, error) {
user, err := GetUserByUsername(username)
if err != nil {
return nil, err
}
if verifyPassword(password, user.Salt, user.Password) {
return user, nil
}
return nil, errors.New("密码不正确")
}
// AddUser 向数据库添加新用户(模型层核心方法)
func AddUser(username, password, email, nickname, avatar string) (*User, error) {
// 1. 检查用户是否已存在(避免用户名重复)
existingUser, err := GetUserByUsername(username)
if err == nil && existingUser != nil {
return nil, fmt.Errorf("用户名已存在")
}
if err != nil && err.Error() != "用户不存在" { // 排除"用户不存在"的正常错误
return nil, fmt.Errorf("查询用户失败: %v", err)
}
// 2. 生成盐值(每个用户唯一)
salt, err := generateSalt()
if err != nil {
return nil, fmt.Errorf("生成盐值失败: %v", err)
}
// 3. 加密密码(结合盐值)
hashedPassword, err := hashPassword(password, salt)
if err != nil {
return nil, fmt.Errorf("密码加密失败: %v", err)
}
// 4. 构建用户对象
user := &User{
Username: username,
Password: hashedPassword, // 存储加密后的密码
Salt: salt, // 存储盐值(用于后续验证)
Email: email,
Nickname: nickname,
Avatar: avatar,
}
// 5. 插入数据库
o := orm.NewOrm()
_, err = o.Insert(user)
if err != nil {
return nil, fmt.Errorf("数据库插入失败: %v", err)
}
// 6. 返回新创建的用户对象
return user, nil
}
// UpdateUser 更新用户信息(模型层方法)
func UpdateUser(id int, username, email, nickname, avatar string) (*User, error) {
// 1. 根据ID查询用户是否存在
o := orm.NewOrm()
user := &User{Id: id}
err := o.Read(user)
if err != nil {
return nil, fmt.Errorf("用户不存在: %v", err)
}
// 2. 仅更新非空字段(避免覆盖原有值)
if username != "" {
// 若更新用户名,需检查新用户名是否已被占用
existingUser, _ := GetUserByUsername(username)
if existingUser != nil && existingUser.Id != id {
return nil, fmt.Errorf("用户名已被占用")
}
user.Username = username
}
if email != "" {
user.Email = email
}
if nickname != "" {
user.Nickname = nickname
}
if avatar != "" {
user.Avatar = avatar
}
// 3. 执行数据库更新
_, err = o.Update(user)
if err != nil {
return nil, fmt.Errorf("数据库更新失败: %v", err)
}
return user, nil
}
// DeleteUser 根据ID删除用户(模型层方法)
func DeleteUser(id int) error {
o := orm.NewOrm()
// 先查询用户是否存在
user := &User{Id: id}
err := o.Read(user)
if err != nil {
return fmt.Errorf("用户不存在: %v", err)
}
// 执行删除操作
_, err = o.Delete(user)
if err != nil {
return fmt.Errorf("数据库删除失败: %v", err)
}
return nil
}
// Init 初始化数据库
func Init() {
orm.RegisterModel(new(User))
orm.RegisterModel(new(Menu))
orm.RegisterModel(new(ProgramCategory))
orm.RegisterModel(new(ProgramInfo))
orm.RegisterModel(new(FileInfo))
ormConfig, err := beego.AppConfig.String("orm")
if err != nil {
panic("无法获取orm配置: " + err.Error())
}
if ormConfig == "mysql" {
user, err1 := beego.AppConfig.String("mysqluser")
pass, err2 := beego.AppConfig.String("mysqlpass")
urls, err3 := beego.AppConfig.String("mysqlurls")
db, err4 := beego.AppConfig.String("mysqldb")
if err1 != nil || err2 != nil || err3 != nil || err4 != nil {
panic("数据库配置错误")
}
// 构建连接字符串
dsn := user + ":" + pass + "@tcp(" + urls + ")/" + db + "?charset=utf8mb4&parseTime=True&loc=Local"
fmt.Println("数据库连接字符串:", dsn)
// 注册数据库
err = orm.RegisterDataBase("default", "mysql", dsn)
if err != nil {
panic("数据库连接失败: " + err.Error())
}
// 测试连接
// 注意:Beego v2 中不需要显式调用 Using,默认使用 "default"
fmt.Println("数据库连接成功!")
}
}