package service import ( "errors" "fmt" "seeyon-filesystem/config" "seeyon-filesystem/dto" "seeyon-filesystem/model" "seeyon-filesystem/repository" ) // FolderService 文件夹业务服务 type FolderService struct { folderRepo *repository.FolderRepository fileRepo *repository.FileRepository } // NewFolderService 创建文件夹服务实例 func NewFolderService() *FolderService { return &FolderService{ folderRepo: repository.NewFolderRepository(), fileRepo: repository.NewFileRepository(), } } // Create 创建文件夹 func (s *FolderService) Create(req *dto.CreateFolderRequest, ownerID uint64) (*dto.FolderVO, error) { // 构建物化路径 parentPath := "/" if req.ParentID > 0 { parent, err := s.folderRepo.FindByID(req.ParentID) if err != nil { return nil, errors.New("父文件夹不存在") } if parent.OwnerID != ownerID { return nil, errors.New("无权访问父文件夹") } parentPath = parent.Path } // 检查同名文件夹 existing, _ := s.folderRepo.FindByNameAndParent(req.Name, req.ParentID, ownerID) if existing != nil { return nil, errors.New("同名文件夹已存在") } folder := &model.Folder{ Name: req.Name, ParentID: req.ParentID, OwnerID: ownerID, Path: parentPath, // 先创建, 获取ID后再更新路径 Status: 1, } if err := s.folderRepo.Create(folder); err != nil { return nil, fmt.Errorf("创建文件夹失败: %w", err) } // 更新物化路径 folder.Path = fmt.Sprintf("%s%d/", parentPath, folder.ID) if err := s.folderRepo.Update(folder); err != nil { return nil, fmt.Errorf("更新文件夹路径失败: %w", err) } return s.toFolderVO(folder), nil } // GetByID 根据ID获取文件夹 func (s *FolderService) GetByID(id uint64, ownerID uint64) (*dto.FolderVO, error) { folder, err := s.folderRepo.FindByID(id) if err != nil { return nil, errors.New("文件夹不存在") } if folder.OwnerID != ownerID { return nil, errors.New("无权访问此文件夹") } return s.toFolderVO(folder), nil } // ListChildren 获取文件夹的子项(文件+文件夹, 基于权限) func (s *FolderService) ListChildren(folderID uint64, userID uint64) (*dto.FileListVO, error) { // 获取用户角色IDs roleIDs := s.getUserRoleIDs(userID) // 如果指定了文件夹ID, 验证访问权限 if folderID > 0 { folder, err := s.folderRepo.FindByID(folderID) if err != nil { return nil, errors.New("文件夹不存在") } if folder.OwnerID != userID { return nil, errors.New("无权访问此文件夹") } } // 查询子文件夹(暂时只查自己创建的) folders, err := s.folderRepo.ListByParent(folderID, userID) if err != nil { return nil, err } // 查询子文件(基于权限: 自己的 + 被授权的) files, err := s.fileRepo.ListByFolder(folderID, userID, roleIDs) if err != nil { return nil, err } // 组装响应 folderVOs := make([]dto.FolderVO, 0, len(folders)) for _, f := range folders { folderVOs = append(folderVOs, *s.toFolderVO(&f)) } fileVOs := make([]dto.FileVO, 0, len(files)) for _, f := range files { fileVOs = append(fileVOs, *s.toFileVO(&f)) } return &dto.FileListVO{ Folders: folderVOs, Files: fileVOs, }, nil } // Rename 重命名文件夹(乐观锁) func (s *FolderService) Rename(id uint64, newName string, ownerID uint64, version int) error { folder, err := s.folderRepo.FindByID(id) if err != nil { return errors.New("文件夹不存在") } if folder.OwnerID != ownerID { return errors.New("无权操作此文件夹") } // 乐观锁检查 if version > 0 && folder.Version != version { return fmt.Errorf("文件夹已被其他人修改, 当前版本: %d, 请刷新后重试", folder.Version) } newVersion := folder.Version + 1 result := config.DB.Model(&model.Folder{}). Where("id = ? AND version = ?", id, folder.Version). Updates(map[string]interface{}{ "name": newName, "version": newVersion, }) if result.RowsAffected == 0 { return fmt.Errorf("文件夹已被其他人修改, 请刷新后重试") } return result.Error } // Delete 删除文件夹(移入回收站) func (s *FolderService) Delete(id uint64, ownerID uint64) error { folder, err := s.folderRepo.FindByID(id) if err != nil { return errors.New("文件夹不存在") } if folder.OwnerID != ownerID { return errors.New("无权操作此文件夹") } return s.folderRepo.SoftDelete(id) } // toFolderVO 转换为视图对象 func (s *FolderService) toFolderVO(folder *model.Folder) *dto.FolderVO { return &dto.FolderVO{ ID: folder.ID, Name: folder.Name, ParentID: folder.ParentID, Path: folder.Path, Version: folder.Version, CreatedAt: folder.CreatedAt, UpdatedAt: folder.UpdatedAt, } } // getUserRoleIDs 获取用户的角色ID列表 func (s *FolderService) getUserRoleIDs(userID uint64) []uint64 { var userRoles []model.UserRole config.DB.Where("user_id = ?", userID).Find(&userRoles) roleIDs := make([]uint64, 0, len(userRoles)) for _, ur := range userRoles { roleIDs = append(roleIDs, ur.RoleID) } return roleIDs } // toFileVO 转换为视图对象 func (s *FolderService) toFileVO(file *model.File) *dto.FileVO { return &dto.FileVO{ ID: file.ID, Name: file.Name, Extension: file.Extension, FolderID: file.FolderID, Size: file.Size, MimeType: file.MimeType, IsFavorite: file.IsFavorite, DownloadCount: file.DownloadCount, CreatedAt: file.CreatedAt, UpdatedAt: file.UpdatedAt, } }