修复用户和文件管理,增加文件预览

This commit is contained in:
2025-11-03 16:18:30 +08:00
parent 2023fe4b97
commit 88d2f527f4
22 changed files with 4821 additions and 1095 deletions
+98 -44
View File
@@ -1,42 +1,46 @@
package models
import (
"strings"
"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"`
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"`
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"`
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"`
MD5 string `orm:"column(md5);size(32);null" json:"md5"`
// 分类信息
Category string `orm:"column(category);size(100)" json:"category"`
SubCategory string `orm:"column(sub_category);size(100);null" json:"sub_category"`
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"`
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"`
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"`
DeleteTime *time.Time `orm:"column(delete_time);type(datetime);null" json:"delete_time,omitempty"`
// 关联的用户信息(非数据库字段)
User *User `orm:"-" json:"user,omitempty"`
User *User `orm:"-" json:"user,omitempty"`
}
// TableName 设置表名
@@ -44,6 +48,31 @@ func (f *FileInfo) TableName() string {
return "yz_files"
}
// CanPreview 判断文件是否可以在线预览
func (f *FileInfo) CanPreview() bool {
previewableExts := map[string]bool{
// 图片格式
".jpg": true,
".jpeg": true,
".png": true,
".gif": true,
".bmp": true,
".webp": true,
".svg": true,
// 文档格式(仅支持 .docx,不支持旧的 .doc、Excel、PPT
".pdf": true,
".txt": true,
".docx": true,
// 视频格式
".mp4": true,
".webm": true,
// 音频格式
".mp3": true,
".wav": true,
}
return previewableExts[strings.ToLower(f.FileExt)]
}
// GetAllFiles 获取所有文件信息
func GetAllFiles() ([]*FileInfo, error) {
o := orm.NewOrm()
@@ -109,7 +138,7 @@ func UpdateFile(file *FileInfo) error {
return err
}
// DeleteFile 删除文件信息(软删除,设置状态为0)
// DeleteFile 删除文件信息(软删除,设置状态为0并记录删除时间
func DeleteFile(id int64) error {
o := orm.NewOrm()
file := &FileInfo{ID: id}
@@ -117,7 +146,9 @@ func DeleteFile(id int64) error {
return err
}
file.Status = 0
_, err := o.Update(file, "Status")
now := time.Now()
file.DeleteTime = &now
_, err := o.Update(file, "Status", "DeleteTime")
return err
}
@@ -131,50 +162,73 @@ func HardDeleteFile(id int64) error {
// 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,
"total_count": totalCount,
"total_size": totalSize,
"category_stats": categoryStats,
}, nil
}
// SearchFiles 搜索文件
// 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)
// 搜索原始文件名
qs = qs.Filter("original_name__icontains", keyword)
_, err := qs.OrderBy("-upload_time").All(&files)
return files, err
}
}
// GetFileByMD5 根据MD5获取文件信息(获取唯一的文件记录)
func GetFileByMD5(md5 string) (*FileInfo, error) {
o := orm.NewOrm()
var file FileInfo
err := o.QueryTable("yz_files").Filter("md5", md5).Filter("status", 1).OrderBy("upload_time").One(&file)
if err == orm.ErrNoRows {
return nil, nil
}
if err != nil {
return nil, err
}
return &file, nil
}
// GetFileByMD5AndTenant 根据MD5和租户ID获取文件信息
func GetFileByMD5AndTenant(md5 string, tenantID string) (*FileInfo, error) {
o := orm.NewOrm()
var file FileInfo
err := o.QueryTable("yz_files").Filter("md5", md5).Filter("tenant_id", tenantID).Filter("status", 1).OrderBy("upload_time").One(&file)
if err == orm.ErrNoRows {
return nil, nil
}
if err != nil {
return nil, err
}
return &file, nil
}
+35 -4
View File
@@ -24,6 +24,8 @@ type User struct {
Email string
Avatar string
Nickname string
Status int `orm:"column(status);default(1)" json:"status"`
Role int `orm:"column(role);default(0)" json:"role"`
DeleteTime *time.Time `orm:"column(delete_time);null;type(datetime)" json:"delete_time"`
LastLoginTime *time.Time `orm:"column(last_login_time);null;type(datetime)" json:"last_login_time"`
}
@@ -147,6 +149,20 @@ func GetAllUsers(tenantId int) []*User {
return users
}
// GetTenantUsers 获取指定租户下的所有用户(排除已删除的用户)
func GetTenantUsers(tenantId int) ([]*User, error) {
o := orm.NewOrm()
var users []*User
// 查询指定租户下未删除的用户
_, err := o.Raw("SELECT * FROM yz_users WHERE tenant_id = ? AND delete_time IS NULL ORDER BY id DESC", tenantId).QueryRows(&users)
if err != nil {
return nil, fmt.Errorf("查询租户用户失败: %v", err)
}
return users, nil
}
// GetUserInfo 根据用户ID或用户名获取用户
func GetUserInfo(userId int, username string, tenantId int) (*User, error) {
o := orm.NewOrm()
@@ -221,7 +237,7 @@ func ValidateUser(username, password string, tenantName string) (*User, error) {
}
// AddUser 向数据库添加新用户
func AddUser(username, password, email, nickname, avatar string, tenantId int) (*User, error) {
func AddUser(username, password, email, nickname, avatar string, tenantId, role int) (*User, error) {
// 1. 验证租户是否存在且有效
o := orm.NewOrm()
var tenantExists bool
@@ -258,11 +274,12 @@ func AddUser(username, password, email, nickname, avatar string, tenantId int) (
user := &User{
TenantId: tenantId,
Username: username,
Password: hashedPassword, // 存储加密后的密码
Salt: salt, // 存储盐值(用于后续验证)
Password: hashedPassword,
Salt: salt,
Email: email,
Nickname: nickname,
Avatar: avatar,
Role: role, // 设置角色ID
}
// 5. 插入数据库(使用之前定义的 o)
@@ -276,7 +293,7 @@ func AddUser(username, password, email, nickname, avatar string, tenantId int) (
}
// EditUser 更新用户信息
func EditUser(id int, username, email, nickname, avatar string) (*User, error) {
func EditUser(id int, username, email, nickname, avatar, status string, roleId int) (*User, error) {
// 根据ID查询用户
o := orm.NewOrm()
user := &User{}
@@ -307,6 +324,20 @@ func EditUser(id int, username, email, nickname, avatar string) (*User, error) {
user.Avatar = avatar
}
// 更新状态(将字符串转换为数字)
if status != "" {
if status == "active" {
user.Status = 1
} else if status == "inactive" {
user.Status = 0
}
}
// 更新角色ID
if roleId > 0 {
user.Role = roleId
}
// 执行数据库更新
_, err = o.Update(user)
if err != nil {