1214 lines
31 KiB
Go
1214 lines
31 KiB
Go
package service
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"strings"
|
||
"time"
|
||
|
||
"github.com/gogf/gf/v2/errors/gerror"
|
||
"github.com/gogf/gf/v2/frame/g"
|
||
"github.com/gogf/gf/v2/net/ghttp"
|
||
"github.com/gogf/gf/v2/os/gtime"
|
||
"github.com/gogf/gf/v2/util/gconv"
|
||
|
||
"nl-video-api/internal/dao"
|
||
"nl-video-api/internal/model/entity"
|
||
"nl-video-api/utility/response"
|
||
)
|
||
|
||
// AttachmentService 附件管理服务
|
||
type AttachmentService struct{}
|
||
|
||
// NewAttachmentService 创建附件管理服务实例
|
||
func NewAttachmentService() *AttachmentService {
|
||
return &AttachmentService{}
|
||
}
|
||
|
||
// 定义请求和响应结构体,避免循环导入
|
||
type AttachmentListReq struct {
|
||
Page int `json:"page"`
|
||
Size int `json:"size"`
|
||
Type string `json:"type"`
|
||
Category string `json:"category"`
|
||
Keyword string `json:"keyword"`
|
||
StartDate string `json:"start_date"`
|
||
EndDate string `json:"end_date"`
|
||
MinSize int64 `json:"min_size"`
|
||
MaxSize int64 `json:"max_size"`
|
||
UserId uint `json:"user_id"`
|
||
}
|
||
|
||
type AttachmentListRes struct {
|
||
List []AttachmentItem `json:"list"`
|
||
Total int `json:"total"`
|
||
Page int `json:"page"`
|
||
Size int `json:"size"`
|
||
}
|
||
|
||
type AttachmentItem struct {
|
||
Id uint `json:"id"`
|
||
Filename string `json:"filename"`
|
||
OriginalName string `json:"original_name"`
|
||
Url string `json:"url"`
|
||
Size int64 `json:"size"`
|
||
Type string `json:"type"`
|
||
Category string `json:"category"`
|
||
Description string `json:"description"`
|
||
UserId uint `json:"user_id"`
|
||
Username string `json:"username"`
|
||
CreatedAt int64 `json:"created_at"`
|
||
UpdatedAt int64 `json:"updated_at"`
|
||
}
|
||
|
||
type AttachmentDetailReq struct {
|
||
Id uint `json:"id"`
|
||
}
|
||
|
||
type AttachmentDetailRes struct {
|
||
Attachment AttachmentDetail `json:"attachment"`
|
||
}
|
||
|
||
type AttachmentDetail struct {
|
||
Id uint `json:"id"`
|
||
Filename string `json:"filename"`
|
||
OriginalName string `json:"original_name"`
|
||
Url string `json:"url"`
|
||
Size int64 `json:"size"`
|
||
Type string `json:"type"`
|
||
Category string `json:"category"`
|
||
Description string `json:"description"`
|
||
UserId uint `json:"user_id"`
|
||
Username string `json:"username"`
|
||
DownloadCount int `json:"download_count"`
|
||
CreatedAt int64 `json:"created_at"`
|
||
UpdatedAt int64 `json:"updated_at"`
|
||
}
|
||
|
||
type AttachmentUpdateReq struct {
|
||
Id uint `json:"id"`
|
||
Category string `json:"category"`
|
||
Description string `json:"description"`
|
||
}
|
||
|
||
type AttachmentDeleteReq struct {
|
||
Id uint `json:"id"`
|
||
}
|
||
|
||
type AttachmentBatchDeleteReq struct {
|
||
Ids []uint `json:"ids"`
|
||
}
|
||
|
||
type AttachmentDownloadReq struct {
|
||
Id uint `json:"id"`
|
||
}
|
||
|
||
type AttachmentDownloadRes struct {
|
||
Url string `json:"url"`
|
||
Filename string `json:"filename"`
|
||
}
|
||
|
||
type AttachmentCategoryListReq struct {
|
||
Type string `json:"type"`
|
||
}
|
||
|
||
type AttachmentCategoryListRes struct {
|
||
Categories []AttachmentCategoryItem `json:"categories"`
|
||
}
|
||
|
||
type AttachmentCategoryItem struct {
|
||
Category string `json:"category"`
|
||
Count int `json:"count"`
|
||
}
|
||
|
||
type AttachmentStatisticsReq struct {
|
||
StartDate string `json:"start_date"`
|
||
EndDate string `json:"end_date"`
|
||
Type string `json:"type"`
|
||
}
|
||
|
||
type AttachmentStatisticsRes struct {
|
||
TotalCount int `json:"total_count"`
|
||
TotalSize int64 `json:"total_size"`
|
||
TypeStats []AttachmentTypeStatItem `json:"type_stats"`
|
||
CategoryStats []AttachmentCategoryStatItem `json:"category_stats"`
|
||
UploadChart []AttachmentUploadChartItem `json:"upload_chart"`
|
||
SizeChart []AttachmentSizeChartItem `json:"size_chart"`
|
||
PopularFiles []AttachmentPopularItem `json:"popular_files"`
|
||
RecentUploads []AttachmentRecentItem `json:"recent_uploads"`
|
||
}
|
||
|
||
type AttachmentTypeStatItem struct {
|
||
Type string `json:"type"`
|
||
Count int `json:"count"`
|
||
Size int64 `json:"size"`
|
||
Percentage string `json:"percentage"`
|
||
}
|
||
|
||
type AttachmentCategoryStatItem struct {
|
||
Category string `json:"category"`
|
||
Count int `json:"count"`
|
||
Size int64 `json:"size"`
|
||
Percentage string `json:"percentage"`
|
||
}
|
||
|
||
type AttachmentUploadChartItem struct {
|
||
Date string `json:"date"`
|
||
Count int `json:"count"`
|
||
Size int64 `json:"size"`
|
||
}
|
||
|
||
type AttachmentSizeChartItem struct {
|
||
SizeRange string `json:"size_range"`
|
||
Count int `json:"count"`
|
||
}
|
||
|
||
type AttachmentPopularItem struct {
|
||
Id uint `json:"id"`
|
||
Filename string `json:"filename"`
|
||
Type string `json:"type"`
|
||
Size int64 `json:"size"`
|
||
DownloadCount int `json:"download_count"`
|
||
CreatedAt int64 `json:"created_at"`
|
||
}
|
||
|
||
type AttachmentRecentItem struct {
|
||
Id uint `json:"id"`
|
||
Filename string `json:"filename"`
|
||
OriginalName string `json:"original_name"`
|
||
Type string `json:"type"`
|
||
Size int64 `json:"size"`
|
||
UserId uint `json:"user_id"`
|
||
Username string `json:"username"`
|
||
CreatedAt int64 `json:"created_at"`
|
||
}
|
||
|
||
type AttachmentMoveReq struct {
|
||
Ids []uint `json:"ids"`
|
||
NewCategory string `json:"new_category"`
|
||
}
|
||
|
||
type AttachmentCopyReq struct {
|
||
Id uint `json:"id"`
|
||
NewCategory string `json:"new_category"`
|
||
Description string `json:"description"`
|
||
}
|
||
|
||
type AttachmentCopyRes struct {
|
||
Id uint `json:"id"`
|
||
Filename string `json:"filename"`
|
||
Url string `json:"url"`
|
||
}
|
||
|
||
type AttachmentRenameReq struct {
|
||
Id uint `json:"id"`
|
||
Filename string `json:"filename"`
|
||
}
|
||
|
||
type AttachmentSearchReq struct {
|
||
Query string `json:"query"`
|
||
Type string `json:"type"`
|
||
Category string `json:"category"`
|
||
Page int `json:"page"`
|
||
Size int `json:"size"`
|
||
}
|
||
|
||
type AttachmentSearchRes struct {
|
||
List []AttachmentItem `json:"list"`
|
||
Total int `json:"total"`
|
||
Page int `json:"page"`
|
||
Size int `json:"size"`
|
||
}
|
||
|
||
type AttachmentUserListReq struct {
|
||
Page int `json:"page"`
|
||
Size int `json:"size"`
|
||
Type string `json:"type"`
|
||
Category string `json:"category"`
|
||
Keyword string `json:"keyword"`
|
||
}
|
||
|
||
type AttachmentUserListRes struct {
|
||
List []AttachmentUserItem `json:"list"`
|
||
Total int `json:"total"`
|
||
Page int `json:"page"`
|
||
Size int `json:"size"`
|
||
}
|
||
|
||
type AttachmentUserItem struct {
|
||
Id uint `json:"id"`
|
||
Filename string `json:"filename"`
|
||
OriginalName string `json:"original_name"`
|
||
Url string `json:"url"`
|
||
Size int64 `json:"size"`
|
||
Type string `json:"type"`
|
||
Category string `json:"category"`
|
||
Description string `json:"description"`
|
||
CreatedAt int64 `json:"created_at"`
|
||
}
|
||
|
||
// Upload 上传附件
|
||
func (s *AttachmentService) Upload(r *ghttp.Request) {
|
||
// 获取请求参数
|
||
attachmentType := r.Get("type").String()
|
||
category := r.Get("category").String()
|
||
description := r.Get("description").String()
|
||
_ = description // 避免未使用变量错误
|
||
|
||
// 获取当前用户ID
|
||
userId := uint(1) // 临时设置,实际应该从请求中获取
|
||
if userId == 0 {
|
||
response.Error(r, response.CodeUnauthorized, "用户未登录")
|
||
return
|
||
}
|
||
|
||
// 这里应该处理文件上传逻辑
|
||
// 由于这是API结构设计,暂时模拟文件上传结果
|
||
filename := fmt.Sprintf("%s_%d.%s", attachmentType, time.Now().Unix(), "jpg")
|
||
url := fmt.Sprintf("/uploads/%s/%s", category, filename)
|
||
size := int64(1024 * 100) // 模拟文件大小
|
||
|
||
// 保存附件信息到数据库
|
||
data := &entity.Attachment{
|
||
Name: filename,
|
||
Path: url, // 使用URL作为路径
|
||
Url: url,
|
||
Size: size,
|
||
MimeType: attachmentType,
|
||
Extension: "jpg", // 从文件名提取扩展名
|
||
UserId: int(userId),
|
||
Status: 1, // 默认启用
|
||
CreatedAt: gtime.Now(),
|
||
UpdatedAt: gtime.Now(),
|
||
}
|
||
|
||
id, err := dao.Attachment.Ctx(r.Context()).Data(data).InsertAndGetId()
|
||
if err != nil {
|
||
response.Error(r, response.CodeInternalError, "保存附件信息失败")
|
||
return
|
||
}
|
||
|
||
response.Success(r, g.Map{
|
||
"id": uint(id),
|
||
"name": filename,
|
||
"url": url,
|
||
"size": size,
|
||
"type": attachmentType,
|
||
})
|
||
}
|
||
|
||
// List 获取附件列表
|
||
func (s *AttachmentService) List(ctx context.Context, req *AttachmentListReq) (*AttachmentListRes, error) {
|
||
// 设置默认值
|
||
if req.Page <= 0 {
|
||
req.Page = 1
|
||
}
|
||
if req.Size <= 0 {
|
||
req.Size = 10
|
||
}
|
||
|
||
// 构建查询条件
|
||
query := dao.Attachment.Ctx(ctx)
|
||
|
||
// 类型筛选
|
||
if req.Type != "" {
|
||
query = query.Where("mime_type", req.Type)
|
||
}
|
||
|
||
// 关键词搜索
|
||
if req.Keyword != "" {
|
||
keyword := "%" + req.Keyword + "%"
|
||
query = query.Where("name LIKE ?", keyword)
|
||
}
|
||
|
||
// 日期范围筛选
|
||
if req.StartDate != "" {
|
||
query = query.Where("created_at >= ?", req.StartDate+" 00:00:00")
|
||
}
|
||
if req.EndDate != "" {
|
||
query = query.Where("created_at <= ?", req.EndDate+" 23:59:59")
|
||
}
|
||
|
||
// 文件大小筛选
|
||
if req.MinSize > 0 {
|
||
query = query.Where("size >= ?", req.MinSize)
|
||
}
|
||
if req.MaxSize > 0 {
|
||
query = query.Where("size <= ?", req.MaxSize)
|
||
}
|
||
|
||
// 用户筛选
|
||
if req.UserId > 0 {
|
||
query = query.Where("user_id", req.UserId)
|
||
}
|
||
|
||
// 获取总数
|
||
total, err := query.Count()
|
||
if err != nil {
|
||
return nil, gerror.New("获取附件总数失败")
|
||
}
|
||
|
||
// 获取列表数据
|
||
var attachments []entity.Attachment
|
||
err = query.Order("id DESC").
|
||
Limit((req.Page-1)*req.Size, req.Size).
|
||
Scan(&attachments)
|
||
if err != nil {
|
||
return nil, gerror.New("获取附件列表失败")
|
||
}
|
||
|
||
// 获取用户信息
|
||
userIds := make([]int, 0, len(attachments))
|
||
for _, attachment := range attachments {
|
||
userIds = append(userIds, attachment.UserId)
|
||
}
|
||
|
||
userMap := make(map[int]string)
|
||
if len(userIds) > 0 {
|
||
var users []entity.NlUser
|
||
g.DB().Model("nl_user").WhereIn("id", userIds).Fields("id, username").Scan(&users)
|
||
for _, user := range users {
|
||
userMap[int(user.Id)] = user.Username
|
||
}
|
||
}
|
||
|
||
// 转换为响应格式
|
||
list := make([]AttachmentItem, 0, len(attachments))
|
||
for _, attachment := range attachments {
|
||
username := userMap[attachment.UserId]
|
||
list = append(list, AttachmentItem{
|
||
Id: attachment.Id,
|
||
Filename: attachment.Name,
|
||
OriginalName: attachment.Name, // 使用Name作为原始名称
|
||
Url: attachment.Url,
|
||
Size: attachment.Size,
|
||
Type: attachment.MimeType,
|
||
Category: "default", // 默认分类
|
||
Description: "", // 默认描述
|
||
UserId: uint(attachment.UserId),
|
||
Username: username,
|
||
CreatedAt: attachment.CreatedAt.Unix(),
|
||
UpdatedAt: attachment.UpdatedAt.Unix(),
|
||
})
|
||
}
|
||
|
||
return &AttachmentListRes{
|
||
List: list,
|
||
Total: total,
|
||
Page: req.Page,
|
||
Size: req.Size,
|
||
}, nil
|
||
}
|
||
|
||
// Detail 获取附件详情
|
||
func (s *AttachmentService) Detail(ctx context.Context, req *AttachmentDetailReq) (*AttachmentDetailRes, error) {
|
||
var attachment entity.Attachment
|
||
err := dao.Attachment.Ctx(ctx).Where("id", req.Id).Scan(&attachment)
|
||
if err != nil {
|
||
return nil, gerror.New("获取附件详情失败")
|
||
}
|
||
if attachment.Id == 0 {
|
||
return nil, gerror.New("附件不存在")
|
||
}
|
||
|
||
// 获取用户信息
|
||
var user entity.NlUser
|
||
g.DB().Model("nl_user").Where("id", attachment.UserId).Fields("username").Scan(&user)
|
||
|
||
return &AttachmentDetailRes{
|
||
Attachment: AttachmentDetail{
|
||
Id: attachment.Id,
|
||
Filename: attachment.Name,
|
||
OriginalName: attachment.Name,
|
||
Url: attachment.Url,
|
||
Size: attachment.Size,
|
||
Type: attachment.MimeType,
|
||
Category: "default",
|
||
Description: "",
|
||
UserId: uint(attachment.UserId),
|
||
Username: user.Username,
|
||
DownloadCount: 0, // 实体中没有此字段,设为0
|
||
CreatedAt: attachment.CreatedAt.Unix(),
|
||
UpdatedAt: attachment.UpdatedAt.Unix(),
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
// Update 更新附件
|
||
func (s *AttachmentService) Update(ctx context.Context, req *AttachmentUpdateReq) error {
|
||
// 检查附件是否存在
|
||
count, err := dao.Attachment.Ctx(ctx).Where("id", req.Id).Count()
|
||
if err != nil {
|
||
return gerror.New("检查附件失败")
|
||
}
|
||
if count == 0 {
|
||
return gerror.New("附件不存在")
|
||
}
|
||
|
||
// 更新附件信息(实体中没有category和description字段,只更新状态)
|
||
data := g.Map{
|
||
"status": 1, // 保持启用状态
|
||
"updated_at": gtime.Now(),
|
||
}
|
||
|
||
_, err = dao.Attachment.Ctx(ctx).Where("id", req.Id).Data(data).Update()
|
||
if err != nil {
|
||
return gerror.New("更新附件失败")
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// Delete 删除附件
|
||
func (s *AttachmentService) Delete(ctx context.Context, req *AttachmentDeleteReq) error {
|
||
// 获取附件信息
|
||
var attachment entity.Attachment
|
||
err := dao.Attachment.Ctx(ctx).Where("id", req.Id).Scan(&attachment)
|
||
if err != nil {
|
||
return gerror.New("获取附件信息失败")
|
||
}
|
||
if attachment.Id == 0 {
|
||
return gerror.New("附件不存在")
|
||
}
|
||
|
||
// 删除数据库记录
|
||
_, err = dao.Attachment.Ctx(ctx).Where("id", req.Id).Delete()
|
||
if err != nil {
|
||
return gerror.New("删除附件记录失败")
|
||
}
|
||
|
||
// 删除物理文件(这里应该根据实际存储方式处理)
|
||
// 例如:os.Remove(attachment.Url)
|
||
|
||
return nil
|
||
}
|
||
|
||
// BatchDelete 批量删除附件
|
||
func (s *AttachmentService) BatchDelete(ctx context.Context, req *AttachmentBatchDeleteReq) error {
|
||
if len(req.Ids) == 0 {
|
||
return gerror.New("请选择要删除的附件")
|
||
}
|
||
|
||
// 获取附件信息
|
||
var attachments []entity.Attachment
|
||
err := dao.Attachment.Ctx(ctx).WhereIn("id", req.Ids).Scan(&attachments)
|
||
if err != nil {
|
||
return gerror.New("获取附件信息失败")
|
||
}
|
||
|
||
// 删除数据库记录
|
||
_, err = dao.Attachment.Ctx(ctx).WhereIn("id", req.Ids).Delete()
|
||
if err != nil {
|
||
return gerror.New("批量删除附件记录失败")
|
||
}
|
||
|
||
// 删除物理文件
|
||
for _, attachment := range attachments {
|
||
// 这里应该根据实际存储方式处理
|
||
// 例如:os.Remove(attachment.Url)
|
||
_ = attachment // 避免未使用变量错误
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// Download 下载附件
|
||
func (s *AttachmentService) Download(ctx context.Context, req *AttachmentDownloadReq) (*AttachmentDownloadRes, error) {
|
||
// 获取附件信息
|
||
var attachment entity.Attachment
|
||
err := dao.Attachment.Ctx(ctx).Where("id", req.Id).Scan(&attachment)
|
||
if err != nil {
|
||
return nil, gerror.New("获取附件信息失败")
|
||
}
|
||
if attachment.Id == 0 {
|
||
return nil, gerror.New("附件不存在")
|
||
}
|
||
|
||
// 这里可以更新下载次数,但实体中没有download_count字段,所以跳过
|
||
|
||
return &AttachmentDownloadRes{
|
||
Url: attachment.Url,
|
||
Filename: attachment.Name,
|
||
}, nil
|
||
}
|
||
|
||
// GetCategoryList 获取附件分类列表
|
||
func (s *AttachmentService) GetCategoryList(ctx context.Context, req *AttachmentCategoryListReq) (*AttachmentCategoryListRes, error) {
|
||
query := dao.Attachment.Ctx(ctx).Fields("mime_type as category, COUNT(*) as count")
|
||
|
||
// 类型筛选
|
||
if req.Type != "" {
|
||
query = query.Where("mime_type", req.Type)
|
||
}
|
||
|
||
var categories []g.Map
|
||
err := query.Group("mime_type").Order("count DESC").Scan(&categories)
|
||
if err != nil {
|
||
return nil, gerror.New("获取分类列表失败")
|
||
}
|
||
|
||
// 转换为响应格式
|
||
list := make([]AttachmentCategoryItem, 0, len(categories))
|
||
for _, category := range categories {
|
||
list = append(list, AttachmentCategoryItem{
|
||
Category: gconv.String(category["category"]),
|
||
Count: gconv.Int(category["count"]),
|
||
})
|
||
}
|
||
|
||
return &AttachmentCategoryListRes{
|
||
Categories: list,
|
||
}, nil
|
||
}
|
||
|
||
// GetStatistics 获取附件统计
|
||
func (s *AttachmentService) GetStatistics(ctx context.Context, req *AttachmentStatisticsReq) (*AttachmentStatisticsRes, error) {
|
||
// 构建查询条件
|
||
query := dao.Attachment.Ctx(ctx)
|
||
if req.StartDate != "" {
|
||
query = query.Where("created_at >= ?", req.StartDate+" 00:00:00")
|
||
}
|
||
if req.EndDate != "" {
|
||
query = query.Where("created_at <= ?", req.EndDate+" 23:59:59")
|
||
}
|
||
if req.Type != "" {
|
||
query = query.Where("mime_type", req.Type)
|
||
}
|
||
|
||
// 获取基础统计
|
||
var totalCount int
|
||
var totalSize int64
|
||
query.Fields("COUNT(*) as total_count, COALESCE(SUM(size), 0) as total_size").
|
||
Scan(&g.Map{
|
||
"total_count": &totalCount,
|
||
"total_size": &totalSize,
|
||
})
|
||
|
||
// 获取类型统计
|
||
typeStats := make([]AttachmentTypeStatItem, 0)
|
||
var typeStatsData []g.Map
|
||
dao.Attachment.Ctx(ctx).Fields("mime_type as type, COUNT(*) as count, COALESCE(SUM(size), 0) as size").
|
||
Group("mime_type").Order("count DESC").Scan(&typeStatsData)
|
||
|
||
for _, stat := range typeStatsData {
|
||
count := gconv.Int(stat["count"])
|
||
size := gconv.Int64(stat["size"])
|
||
percentage := "0.00"
|
||
if totalCount > 0 {
|
||
percentage = fmt.Sprintf("%.2f", float64(count)/float64(totalCount)*100)
|
||
}
|
||
|
||
typeStats = append(typeStats, AttachmentTypeStatItem{
|
||
Type: gconv.String(stat["type"]),
|
||
Count: count,
|
||
Size: size,
|
||
Percentage: percentage,
|
||
})
|
||
}
|
||
|
||
// 获取分类统计(使用mime_type作为分类)
|
||
categoryStats := make([]AttachmentCategoryStatItem, 0)
|
||
var categoryStatsData []g.Map
|
||
dao.Attachment.Ctx(ctx).Fields("mime_type as category, COUNT(*) as count, COALESCE(SUM(size), 0) as size").
|
||
Group("mime_type").Order("count DESC").Limit(10).Scan(&categoryStatsData)
|
||
|
||
for _, stat := range categoryStatsData {
|
||
count := gconv.Int(stat["count"])
|
||
size := gconv.Int64(stat["size"])
|
||
percentage := "0.00"
|
||
if totalCount > 0 {
|
||
percentage = fmt.Sprintf("%.2f", float64(count)/float64(totalCount)*100)
|
||
}
|
||
|
||
categoryStats = append(categoryStats, AttachmentCategoryStatItem{
|
||
Category: gconv.String(stat["category"]),
|
||
Count: count,
|
||
Size: size,
|
||
Percentage: percentage,
|
||
})
|
||
}
|
||
|
||
// 获取上传图表数据(简化处理)
|
||
uploadChart := make([]AttachmentUploadChartItem, 0)
|
||
if req.StartDate != "" && req.EndDate != "" {
|
||
uploadChart = append(uploadChart, AttachmentUploadChartItem{
|
||
Date: req.StartDate,
|
||
Count: totalCount,
|
||
Size: totalSize,
|
||
})
|
||
}
|
||
|
||
// 获取大小图表数据
|
||
sizeChart := []AttachmentSizeChartItem{
|
||
{SizeRange: "0-1MB", Count: 0},
|
||
{SizeRange: "1-10MB", Count: 0},
|
||
{SizeRange: "10-100MB", Count: 0},
|
||
{SizeRange: "100MB+", Count: 0},
|
||
}
|
||
|
||
// 获取热门文件
|
||
popularFiles := make([]AttachmentPopularItem, 0)
|
||
var popularData []entity.Attachment
|
||
dao.Attachment.Ctx(ctx).Order("created_at DESC").Limit(10).Scan(&popularData)
|
||
|
||
for _, file := range popularData {
|
||
popularFiles = append(popularFiles, AttachmentPopularItem{
|
||
Id: file.Id,
|
||
Filename: file.Name,
|
||
Type: file.MimeType,
|
||
Size: file.Size,
|
||
DownloadCount: 0, // 实体中没有此字段
|
||
CreatedAt: file.CreatedAt.Unix(),
|
||
})
|
||
}
|
||
|
||
// 获取最近上传
|
||
recentUploads := make([]AttachmentRecentItem, 0)
|
||
var recentData []entity.Attachment
|
||
dao.Attachment.Ctx(ctx).Order("created_at DESC").Limit(10).Scan(&recentData)
|
||
|
||
// 获取用户信息
|
||
userIds := make([]int, 0, len(recentData))
|
||
for _, file := range recentData {
|
||
userIds = append(userIds, file.UserId)
|
||
}
|
||
|
||
userMap := make(map[int]string)
|
||
if len(userIds) > 0 {
|
||
var users []entity.NlUser
|
||
g.DB().Model("nl_user").WhereIn("id", userIds).Fields("id, username").Scan(&users)
|
||
for _, user := range users {
|
||
userMap[int(user.Id)] = user.Username
|
||
}
|
||
}
|
||
|
||
for _, file := range recentData {
|
||
username := userMap[file.UserId]
|
||
recentUploads = append(recentUploads, AttachmentRecentItem{
|
||
Id: file.Id,
|
||
Filename: file.Name,
|
||
OriginalName: file.Name,
|
||
Type: file.MimeType,
|
||
Size: file.Size,
|
||
UserId: uint(file.UserId),
|
||
Username: username,
|
||
CreatedAt: file.CreatedAt.Unix(),
|
||
})
|
||
}
|
||
|
||
return &AttachmentStatisticsRes{
|
||
TotalCount: totalCount,
|
||
TotalSize: totalSize,
|
||
TypeStats: typeStats,
|
||
CategoryStats: categoryStats,
|
||
UploadChart: uploadChart,
|
||
SizeChart: sizeChart,
|
||
PopularFiles: popularFiles,
|
||
RecentUploads: recentUploads,
|
||
}, nil
|
||
}
|
||
|
||
// Move 移动附件
|
||
func (s *AttachmentService) Move(ctx context.Context, req *AttachmentMoveReq) error {
|
||
if len(req.Ids) == 0 {
|
||
return gerror.New("请选择要移动的附件")
|
||
}
|
||
|
||
// 更新状态(实体中没有category字段,只能更新状态)
|
||
_, err := dao.Attachment.Ctx(ctx).WhereIn("id", req.Ids).Data(g.Map{
|
||
"status": 1,
|
||
"updated_at": gtime.Now(),
|
||
}).Update()
|
||
if err != nil {
|
||
return gerror.New("移动附件失败")
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// Copy 复制附件
|
||
func (s *AttachmentService) Copy(ctx context.Context, req *AttachmentCopyReq) (*AttachmentCopyRes, error) {
|
||
// 获取源附件信息
|
||
var sourceAttachment entity.Attachment
|
||
err := dao.Attachment.Ctx(ctx).Where("id", req.Id).Scan(&sourceAttachment)
|
||
if err != nil {
|
||
return nil, gerror.New("获取源附件信息失败")
|
||
}
|
||
if sourceAttachment.Id == 0 {
|
||
return nil, gerror.New("源附件不存在")
|
||
}
|
||
|
||
// 获取当前用户ID
|
||
userId := GetUserIdFromContext(ctx)
|
||
if userId == 0 {
|
||
return nil, gerror.New("用户未登录")
|
||
}
|
||
|
||
// 生成新文件名
|
||
newFilename := fmt.Sprintf("copy_%d_%s", time.Now().Unix(), sourceAttachment.Name)
|
||
newUrl := strings.Replace(sourceAttachment.Url, sourceAttachment.Name, newFilename, 1)
|
||
|
||
// 创建新附件记录
|
||
data := &entity.Attachment{
|
||
Name: newFilename,
|
||
Path: newUrl,
|
||
Url: newUrl,
|
||
Size: sourceAttachment.Size,
|
||
MimeType: sourceAttachment.MimeType,
|
||
Extension: sourceAttachment.Extension,
|
||
UserId: int(userId),
|
||
Status: 1,
|
||
CreatedAt: gtime.Now(),
|
||
UpdatedAt: gtime.Now(),
|
||
}
|
||
|
||
id, err := dao.Attachment.Ctx(ctx).Data(data).InsertAndGetId()
|
||
if err != nil {
|
||
return nil, gerror.New("复制附件失败")
|
||
}
|
||
|
||
// 这里应该复制物理文件
|
||
|
||
return &AttachmentCopyRes{
|
||
Id: uint(id),
|
||
Filename: newFilename,
|
||
Url: newUrl,
|
||
}, nil
|
||
}
|
||
|
||
// Rename 重命名附件
|
||
func (s *AttachmentService) Rename(ctx context.Context, req *AttachmentRenameReq) error {
|
||
// 检查附件是否存在
|
||
count, err := dao.Attachment.Ctx(ctx).Where("id", req.Id).Count()
|
||
if err != nil {
|
||
return gerror.New("检查附件失败")
|
||
}
|
||
if count == 0 {
|
||
return gerror.New("附件不存在")
|
||
}
|
||
|
||
// 更新文件名
|
||
_, err = dao.Attachment.Ctx(ctx).Where("id", req.Id).Data(g.Map{
|
||
"name": req.Filename,
|
||
"updated_at": gtime.Now(),
|
||
}).Update()
|
||
if err != nil {
|
||
return gerror.New("重命名附件失败")
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// Search 搜索附件
|
||
func (s *AttachmentService) Search(ctx context.Context, req *AttachmentSearchReq) (*AttachmentSearchRes, error) {
|
||
// 设置默认值
|
||
if req.Page <= 0 {
|
||
req.Page = 1
|
||
}
|
||
if req.Size <= 0 {
|
||
req.Size = 10
|
||
}
|
||
|
||
// 构建查询条件
|
||
query := dao.Attachment.Ctx(ctx)
|
||
|
||
// 关键词搜索
|
||
if req.Query != "" {
|
||
keyword := "%" + req.Query + "%"
|
||
query = query.Where("name LIKE ?", keyword)
|
||
}
|
||
|
||
// 类型筛选
|
||
if req.Type != "" {
|
||
query = query.Where("mime_type", req.Type)
|
||
}
|
||
|
||
// 获取总数
|
||
total, err := query.Count()
|
||
if err != nil {
|
||
return nil, gerror.New("获取搜索结果总数失败")
|
||
}
|
||
|
||
// 获取列表数据
|
||
var attachments []entity.Attachment
|
||
err = query.Order("id DESC").
|
||
Limit((req.Page-1)*req.Size, req.Size).
|
||
Scan(&attachments)
|
||
if err != nil {
|
||
return nil, gerror.New("获取搜索结果失败")
|
||
}
|
||
|
||
// 转换为响应格式
|
||
list := make([]AttachmentItem, 0, len(attachments))
|
||
for _, attachment := range attachments {
|
||
list = append(list, AttachmentItem{
|
||
Id: attachment.Id,
|
||
Filename: attachment.Name,
|
||
OriginalName: attachment.Name,
|
||
Url: attachment.Url,
|
||
Size: attachment.Size,
|
||
Type: attachment.MimeType,
|
||
Category: "default",
|
||
Description: "",
|
||
UserId: uint(attachment.UserId),
|
||
CreatedAt: attachment.CreatedAt.Unix(),
|
||
})
|
||
}
|
||
|
||
return &AttachmentSearchRes{
|
||
List: list,
|
||
Total: total,
|
||
Page: req.Page,
|
||
Size: req.Size,
|
||
}, nil
|
||
}
|
||
|
||
// UserList 用户获取附件列表
|
||
func (s *AttachmentService) UserList(ctx context.Context, req *AttachmentUserListReq) (*AttachmentUserListRes, error) {
|
||
// 设置默认值
|
||
if req.Page <= 0 {
|
||
req.Page = 1
|
||
}
|
||
if req.Size <= 0 {
|
||
req.Size = 10
|
||
}
|
||
|
||
// 获取当前用户ID
|
||
userId := GetUserIdFromContext(ctx)
|
||
if userId == 0 {
|
||
return nil, gerror.New("用户未登录")
|
||
}
|
||
|
||
// 构建查询条件
|
||
query := dao.Attachment.Ctx(ctx).Where("user_id", userId)
|
||
|
||
// 类型筛选
|
||
if req.Type != "" {
|
||
query = query.Where("mime_type", req.Type)
|
||
}
|
||
|
||
// 关键词搜索
|
||
if req.Keyword != "" {
|
||
keyword := "%" + req.Keyword + "%"
|
||
query = query.Where("name LIKE ?", keyword)
|
||
}
|
||
|
||
// 获取总数
|
||
total, err := query.Count()
|
||
if err != nil {
|
||
return nil, gerror.New("获取附件总数失败")
|
||
}
|
||
|
||
// 获取列表数据
|
||
var attachments []entity.Attachment
|
||
err = query.Order("id DESC").
|
||
Limit((req.Page-1)*req.Size, req.Size).
|
||
Scan(&attachments)
|
||
if err != nil {
|
||
return nil, gerror.New("获取附件列表失败")
|
||
}
|
||
|
||
// 转换为响应格式
|
||
list := make([]AttachmentUserItem, 0, len(attachments))
|
||
for _, attachment := range attachments {
|
||
list = append(list, AttachmentUserItem{
|
||
Id: attachment.Id,
|
||
Filename: attachment.Name,
|
||
OriginalName: attachment.Name,
|
||
Url: attachment.Url,
|
||
Size: attachment.Size,
|
||
Type: attachment.MimeType,
|
||
Category: "default",
|
||
Description: "",
|
||
CreatedAt: attachment.CreatedAt.Unix(),
|
||
})
|
||
}
|
||
|
||
return &AttachmentUserListRes{
|
||
List: list,
|
||
Total: total,
|
||
Page: req.Page,
|
||
Size: req.Size,
|
||
}, nil
|
||
}
|
||
|
||
// GetUserIdFromContext 从上下文获取用户ID
|
||
func GetUserIdFromContext(ctx context.Context) uint {
|
||
// 这里应该从JWT token或session中获取用户ID
|
||
// 临时返回固定值
|
||
return 1
|
||
}
|
||
|
||
// UserUpload 用户上传附件
|
||
func (s *AttachmentService) UserUpload(r *ghttp.Request) {
|
||
s.Upload(r)
|
||
}
|
||
|
||
// UserGetList 用户获取附件列表
|
||
func (s *AttachmentService) UserGetList(r *ghttp.Request) {
|
||
// 获取请求参数并转换为内部请求结构
|
||
req := &AttachmentUserListReq{
|
||
Page: r.Get("page", 1).Int(),
|
||
Size: r.Get("size", 10).Int(),
|
||
Type: r.Get("type").String(),
|
||
Category: r.Get("category").String(),
|
||
Keyword: r.Get("keyword").String(),
|
||
}
|
||
|
||
// 调用服务方法
|
||
res, err := s.UserList(r.Context(), req)
|
||
if err != nil {
|
||
response.Error(r, response.CodeInternalError, err.Error())
|
||
return
|
||
}
|
||
|
||
response.Success(r, res)
|
||
}
|
||
|
||
// UserGetDetail 用户获取附件详情
|
||
func (s *AttachmentService) UserGetDetail(r *ghttp.Request) {
|
||
req := &AttachmentDetailReq{
|
||
Id: uint(r.Get("id").Int()),
|
||
}
|
||
|
||
res, err := s.Detail(r.Context(), req)
|
||
if err != nil {
|
||
response.Error(r, response.CodeInternalError, err.Error())
|
||
return
|
||
}
|
||
|
||
response.Success(r, res)
|
||
}
|
||
|
||
// UserUpdate 用户更新附件
|
||
func (s *AttachmentService) UserUpdate(r *ghttp.Request) {
|
||
req := &AttachmentUpdateReq{
|
||
Id: uint(r.Get("id").Int()),
|
||
Category: r.Get("category").String(),
|
||
Description: r.Get("description").String(),
|
||
}
|
||
|
||
err := s.Update(r.Context(), req)
|
||
if err != nil {
|
||
response.Error(r, response.CodeInternalError, err.Error())
|
||
return
|
||
}
|
||
|
||
response.Success(r, "更新成功")
|
||
}
|
||
|
||
// UserDelete 用户删除附件
|
||
func (s *AttachmentService) UserDelete(r *ghttp.Request) {
|
||
req := &AttachmentDeleteReq{
|
||
Id: uint(r.Get("id").Int()),
|
||
}
|
||
|
||
err := s.Delete(r.Context(), req)
|
||
if err != nil {
|
||
response.Error(r, response.CodeInternalError, err.Error())
|
||
return
|
||
}
|
||
|
||
response.Success(r, "删除成功")
|
||
}
|
||
|
||
// UserDownload 用户下载附件
|
||
func (s *AttachmentService) UserDownload(r *ghttp.Request) {
|
||
req := &AttachmentDownloadReq{
|
||
Id: uint(r.Get("id").Int()),
|
||
}
|
||
|
||
res, err := s.Download(r.Context(), req)
|
||
if err != nil {
|
||
response.Error(r, response.CodeInternalError, err.Error())
|
||
return
|
||
}
|
||
|
||
response.Success(r, res)
|
||
}
|
||
|
||
// UserCopy 用户复制附件
|
||
func (s *AttachmentService) UserCopy(r *ghttp.Request) {
|
||
req := &AttachmentCopyReq{
|
||
Id: uint(r.Get("id").Int()),
|
||
NewCategory: r.Get("new_category").String(),
|
||
Description: r.Get("description").String(),
|
||
}
|
||
|
||
res, err := s.Copy(r.Context(), req)
|
||
if err != nil {
|
||
response.Error(r, response.CodeInternalError, err.Error())
|
||
return
|
||
}
|
||
|
||
response.Success(r, res)
|
||
}
|
||
|
||
// UserRename 用户重命名附件
|
||
func (s *AttachmentService) UserRename(r *ghttp.Request) {
|
||
req := &AttachmentRenameReq{
|
||
Id: uint(r.Get("id").Int()),
|
||
Filename: r.Get("filename").String(),
|
||
}
|
||
|
||
err := s.Rename(r.Context(), req)
|
||
if err != nil {
|
||
response.Error(r, response.CodeInternalError, err.Error())
|
||
return
|
||
}
|
||
|
||
response.Success(r, "重命名成功")
|
||
}
|
||
|
||
// UserSearch 用户搜索附件
|
||
func (s *AttachmentService) UserSearch(r *ghttp.Request) {
|
||
req := &AttachmentSearchReq{
|
||
Query: r.Get("query").String(),
|
||
Type: r.Get("type").String(),
|
||
Category: r.Get("category").String(),
|
||
Page: r.Get("page", 1).Int(),
|
||
Size: r.Get("size", 10).Int(),
|
||
}
|
||
|
||
res, err := s.Search(r.Context(), req)
|
||
if err != nil {
|
||
response.Error(r, response.CodeInternalError, err.Error())
|
||
return
|
||
}
|
||
|
||
response.Success(r, res)
|
||
}
|
||
|
||
// UserGetCategoryList 用户获取附件分类列表
|
||
func (s *AttachmentService) UserGetCategoryList(r *ghttp.Request) {
|
||
req := &AttachmentCategoryListReq{
|
||
Type: r.Get("type").String(),
|
||
}
|
||
|
||
res, err := s.GetCategoryList(r.Context(), req)
|
||
if err != nil {
|
||
response.Error(r, response.CodeInternalError, err.Error())
|
||
return
|
||
}
|
||
|
||
response.Success(r, res)
|
||
}
|
||
|
||
// AdminGetList 管理员获取附件列表
|
||
func (s *AttachmentService) AdminGetList(r *ghttp.Request) {
|
||
req := &AttachmentListReq{
|
||
Page: r.Get("page", 1).Int(),
|
||
Size: r.Get("size", 10).Int(),
|
||
Type: r.Get("type").String(),
|
||
Category: r.Get("category").String(),
|
||
Keyword: r.Get("keyword").String(),
|
||
StartDate: r.Get("start_date").String(),
|
||
EndDate: r.Get("end_date").String(),
|
||
MinSize: r.Get("min_size").Int64(),
|
||
MaxSize: r.Get("max_size").Int64(),
|
||
UserId: uint(r.Get("user_id").Int()),
|
||
}
|
||
|
||
res, err := s.List(r.Context(), req)
|
||
if err != nil {
|
||
response.Error(r, response.CodeInternalError, err.Error())
|
||
return
|
||
}
|
||
|
||
response.Success(r, res)
|
||
}
|
||
|
||
// AdminGetDetail 管理员获取附件详情
|
||
func (s *AttachmentService) AdminGetDetail(r *ghttp.Request) {
|
||
s.UserGetDetail(r)
|
||
}
|
||
|
||
// AdminUpdate 管理员更新附件
|
||
func (s *AttachmentService) AdminUpdate(r *ghttp.Request) {
|
||
s.UserUpdate(r)
|
||
}
|
||
|
||
// AdminDelete 管理员删除附件
|
||
func (s *AttachmentService) AdminDelete(r *ghttp.Request) {
|
||
s.UserDelete(r)
|
||
}
|
||
|
||
// AdminBatchDelete 管理员批量删除附件
|
||
func (s *AttachmentService) AdminBatchDelete(r *ghttp.Request) {
|
||
var ids []uint
|
||
r.Parse(&ids)
|
||
|
||
req := &AttachmentBatchDeleteReq{
|
||
Ids: ids,
|
||
}
|
||
|
||
err := s.BatchDelete(r.Context(), req)
|
||
if err != nil {
|
||
response.Error(r, response.CodeInternalError, err.Error())
|
||
return
|
||
}
|
||
|
||
response.Success(r, "批量删除成功")
|
||
}
|
||
|
||
// AdminDownload 管理员下载附件
|
||
func (s *AttachmentService) AdminDownload(r *ghttp.Request) {
|
||
s.UserDownload(r)
|
||
}
|
||
|
||
// AdminMove 管理员移动附件
|
||
func (s *AttachmentService) AdminMove(r *ghttp.Request) {
|
||
var ids []uint
|
||
r.Parse(&ids)
|
||
|
||
req := &AttachmentMoveReq{
|
||
Ids: ids,
|
||
NewCategory: r.Get("new_category").String(),
|
||
}
|
||
|
||
err := s.Move(r.Context(), req)
|
||
if err != nil {
|
||
response.Error(r, response.CodeInternalError, err.Error())
|
||
return
|
||
}
|
||
|
||
response.Success(r, "移动成功")
|
||
}
|
||
|
||
// AdminCopy 管理员复制附件
|
||
func (s *AttachmentService) AdminCopy(r *ghttp.Request) {
|
||
s.UserCopy(r)
|
||
}
|
||
|
||
// AdminRename 管理员重命名附件
|
||
func (s *AttachmentService) AdminRename(r *ghttp.Request) {
|
||
s.UserRename(r)
|
||
}
|
||
|
||
// AdminSearch 管理员搜索附件
|
||
func (s *AttachmentService) AdminSearch(r *ghttp.Request) {
|
||
s.UserSearch(r)
|
||
}
|
||
|
||
// AdminGetCategoryList 管理员获取附件分类列表
|
||
func (s *AttachmentService) AdminGetCategoryList(r *ghttp.Request) {
|
||
s.UserGetCategoryList(r)
|
||
}
|
||
|
||
// AdminGetStatistics 管理员获取附件统计
|
||
func (s *AttachmentService) AdminGetStatistics(r *ghttp.Request) {
|
||
req := &AttachmentStatisticsReq{
|
||
StartDate: r.Get("start_date").String(),
|
||
EndDate: r.Get("end_date").String(),
|
||
Type: r.Get("type").String(),
|
||
}
|
||
|
||
res, err := s.GetStatistics(r.Context(), req)
|
||
if err != nil {
|
||
response.Error(r, response.CodeInternalError, err.Error())
|
||
return
|
||
}
|
||
|
||
response.Success(r, res)
|
||
}
|