package service import ( "errors" "sort" "seeyon-filesystem/config" "seeyon-filesystem/dto" "seeyon-filesystem/model" "seeyon-filesystem/utils" ) // StorageAssignService 存储策略分配服务 type StorageAssignService struct{} func NewStorageAssignService() *StorageAssignService { return &StorageAssignService{} } // UserStorageInfo 用户存储策略信息 type UserStorageInfo struct { PolicyID uint64 // 当前使用的策略ID(最高优先级) PolicyName string PolicyType string TotalQuota int64 // 总配额(所有策略叠加) UsedStorage int64 // 已用空间 UsedPercent float64 AccessMode string MaxFileSize int64 // 单文件大小上限(字节), 0=不限制 ChunkThreshold int64 // 分片上传阈值(字节) Assignments []model.StorageAssignment // 所有关联的分配规则 } // ResolvePolicyID 确定用户上传时应使用的存储策略 // 优先级: 用户专属 > 角色(按priority排序) > 系统默认 // 多角色时取优先级最高的策略 func (s *StorageAssignService) ResolvePolicyID(userID uint64) uint64 { assignments := s.getUserAssignments(userID) if len(assignments) == 0 { return uint64(config.AppConfig.Storage.DefaultPolicyID) } // 已按priority DESC排序, 取第一个 return assignments[0].PolicyID } // ResolveAccessMode 确定用户的访问模式 func (s *StorageAssignService) ResolveAccessMode(userID uint64) string { assignments := s.getUserAssignments(userID) for _, a := range assignments { if a.AccessMode != "" { return a.AccessMode } } return "" } // GetUserStorageInfo 获取用户完整的存储策略信息(含配额叠加) func (s *StorageAssignService) GetUserStorageInfo(userID uint64) (*UserStorageInfo, error) { assignments := s.getUserAssignments(userID) var user model.User config.DB.First(&user, userID) info := &UserStorageInfo{ UsedStorage: user.UsedStorage, Assignments: assignments, } if len(assignments) == 0 { // 使用默认策略 info.PolicyID = uint64(config.AppConfig.Storage.DefaultPolicyID) info.TotalQuota = user.StorageQuota } else { // 最高优先级策略 info.PolicyID = assignments[0].PolicyID info.AccessMode = assignments[0].AccessMode // 配额叠加: 所有策略的配额之和 var totalQuota int64 for _, a := range assignments { if a.StorageQuota > 0 { totalQuota += a.StorageQuota } } if totalQuota > 0 { info.TotalQuota = totalQuota } else { info.TotalQuota = user.StorageQuota } } // 获取策略详情 var policy model.StoragePolicy if config.DB.First(&policy, info.PolicyID).Error == nil { info.PolicyName = policy.Name info.PolicyType = policy.PolicyType } if info.TotalQuota > 0 { info.UsedPercent = float64(info.UsedStorage) / float64(info.TotalQuota) * 100 } // 根据角色确定文件大小限制 info.MaxFileSize, info.ChunkThreshold = s.getFileSizeLimit(userID) return info, nil } // getFileSizeLimit 根据用户角色返回单文件大小限制和分片阈值 // 返回: maxFileSize(字节), chunkThreshold(字节) func (s *StorageAssignService) getFileSizeLimit(userID uint64) (int64, int64) { // 获取用户角色 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) } // 检查角色名称确定限制 var roles []model.Role if len(roleIDs) > 0 { config.DB.Where("id IN ?", roleIDs).Find(&roles) } for _, r := range roles { switch r.Name { case "admin": return 0, 100 * 1024 * 1024 // 不限大小, 100MB分片 case "staff": return 500 * 1024 * 1024, 50 * 1024 * 1024 // 500MB上限, 50MB分片 case "user": return 100 * 1024 * 1024, 10 * 1024 * 1024 // 100MB上限, 10MB分片 case "guest": return 0, 0 // 不允许上传 } } // 默认 return 100 * 1024 * 1024, 10 * 1024 * 1024 } // getUserAssignments 获取用户的所有存储分配(去重+排序) func (s *StorageAssignService) getUserAssignments(userID uint64) []model.StorageAssignment { var all []model.StorageAssignment // 1. 用户专属分配 var userAssigns []model.StorageAssignment config.DB.Where("user_id = ? AND status = 1", userID).Find(&userAssigns) all = append(all, userAssigns...) // 2. 角色分配(用户所属的所有角色) var userRoles []model.UserRole config.DB.Where("user_id = ?", userID).Find(&userRoles) for _, ur := range userRoles { var roleAssigns []model.StorageAssignment config.DB.Where("group_id = ? AND status = 1", ur.RoleID).Find(&roleAssigns) all = append(all, roleAssigns...) } // 3. 系统默认 if len(all) == 0 { var defaultAssign model.StorageAssignment config.DB.Where("is_default = 1 AND status = 1").First(&defaultAssign) if defaultAssign.ID > 0 { all = append(all, defaultAssign) } } // 去重(按PolicyID) seen := make(map[uint64]bool) unique := make([]model.StorageAssignment, 0, len(all)) for _, a := range all { if !seen[a.PolicyID] { seen[a.PolicyID] = true unique = append(unique, a) } } // 按优先级降序排序 sort.Slice(unique, func(i, j int) bool { return unique[i].Priority > unique[j].Priority }) return unique } // ========== 管理接口 ========== // ListAssignments 获取所有分配规则 func (s *StorageAssignService) ListAssignments() ([]dto.StorageAssignmentVO, error) { var assignments []model.StorageAssignment if err := config.DB.Order("is_default DESC, priority DESC, group_id ASC").Find(&assignments).Error; err != nil { return nil, err } vos := make([]dto.StorageAssignmentVO, 0, len(assignments)) for _, a := range assignments { vo := dto.StorageAssignmentVO{ ID: a.ID, PolicyID: a.PolicyID, UserID: a.UserID, GroupID: a.GroupID, IsDefault: a.IsDefault, Priority: a.Priority, StorageQuota: a.StorageQuota, AccessMode: a.AccessMode, Status: a.Status, } var policy model.StoragePolicy if config.DB.First(&policy, a.PolicyID).Error == nil { vo.PolicyName = policy.Name } if a.UserID > 0 { var user model.User if config.DB.First(&user, a.UserID).Error == nil { vo.UserName = user.Nickname } } if a.GroupID > 0 { var role model.Role if config.DB.First(&role, a.GroupID).Error == nil { vo.RoleName = role.DisplayName } } vos = append(vos, vo) } return vos, nil } // SetDefault 设置系统默认存储策略 func (s *StorageAssignService) SetDefault(policyID uint64) error { // 先清除旧的默认 config.DB.Model(&model.StorageAssignment{}).Where("is_default = 1").Update("is_default", 0) // 查找或创建默认记录 var existing model.StorageAssignment err := config.DB.Where("is_default = 0 AND user_id = 0 AND group_id = 0").First(&existing).Error if err == nil { // 更新现有记录 existing.PolicyID = policyID existing.IsDefault = 1 return config.DB.Save(&existing).Error } // 创建新记录 return config.DB.Create(&model.StorageAssignment{ ID: utils.GenID(), PolicyID: policyID, IsDefault: 1, Status: 1, }).Error } // AssignToRole 为角色分配存储策略(支持多策略) func (s *StorageAssignService) AssignToRole(roleID, policyID uint64, quota int64, priority int, accessMode string) error { // 检查是否已存在相同分配 var existing model.StorageAssignment err := config.DB.Where("group_id = ? AND policy_id = ?", roleID, policyID).First(&existing).Error if err == nil { // 更新 existing.StorageQuota = quota existing.Priority = priority existing.AccessMode = accessMode return config.DB.Save(&existing).Error } return config.DB.Create(&model.StorageAssignment{ ID: utils.GenID(), GroupID: roleID, PolicyID: policyID, StorageQuota: quota, Priority: priority, AccessMode: accessMode, Status: 1, }).Error } // AssignToUser 为用户分配存储策略(覆盖角色策略) func (s *StorageAssignService) AssignToUser(userID, policyID uint64, quota int64, accessMode string) error { var existing model.StorageAssignment err := config.DB.Where("user_id = ?", userID).First(&existing).Error if err == nil { existing.PolicyID = policyID existing.StorageQuota = quota existing.AccessMode = accessMode return config.DB.Save(&existing).Error } return config.DB.Create(&model.StorageAssignment{ ID: utils.GenID(), UserID: userID, PolicyID: policyID, StorageQuota: quota, Priority: 100, // 用户专属最高优先级 AccessMode: accessMode, Status: 1, }).Error } // UpdateAssignment 更新分配规则 func (s *StorageAssignService) UpdateAssignment(id uint64, policyID uint64, priority *int, quota *int64, accessMode string) error { var assignment model.StorageAssignment if err := config.DB.First(&assignment, id).Error; err != nil { return errors.New("分配规则不存在") } updates := make(map[string]interface{}) if policyID > 0 { updates["policy_id"] = policyID } if priority != nil { updates["priority"] = *priority } if quota != nil { updates["storage_quota"] = *quota } if accessMode != "" { updates["access_mode"] = accessMode } if len(updates) == 0 { return errors.New("没有需要更新的字段") } return config.DB.Model(&model.StorageAssignment{}).Where("id = ?", id).Updates(updates).Error } // DeleteAssignment 删除分配规则 func (s *StorageAssignService) DeleteAssignment(id uint64) error { var assignment model.StorageAssignment if err := config.DB.First(&assignment, id).Error; err != nil { return errors.New("分配规则不存在") } if assignment.IsDefault == 1 { return errors.New("不能删除默认分配规则") } return config.DB.Delete(&model.StorageAssignment{}, id).Error }