'integer', ]; /** * 关联用户 */ public function user(): BelongsTo { return $this->belongsTo(User::class); } /** * 获取文件完整路径 */ public function getFullPathAttribute(): string { return $this->path . '/' . $this->storage_name; } /** * 获取文件大小(可读格式) */ public function getSizeFormattedAttribute(): string { $size = $this->size; $units = ['B', 'KB', 'MB', 'GB', 'TB']; for ($i = 0; $size >= 1024 && $i < 4; $i++) { $size /= 1024; } return round($size, 2) . ' ' . $units[$i]; } /** * 获取文件图标 */ public function getIconAttribute(): string { $extension = strtolower($this->extension); $icons = [ // 图片 'jpg' => 'image', 'jpeg' => 'image', 'png' => 'image', 'gif' => 'image', 'bmp' => 'image', 'svg' => 'image', 'webp' => 'image', // 文档 'pdf' => 'picture_as_pdf', 'doc' => 'description', 'docx' => 'description', 'xls' => 'table_chart', 'xlsx' => 'table_chart', 'ppt' => 'slideshow', 'pptx' => 'slideshow', // 文本 'txt' => 'text_fields', 'md' => 'text_fields', 'json' => 'code', 'xml' => 'code', 'html' => 'code', // 压缩文件 'zip' => 'folder_zip', 'rar' => 'folder_zip', '7z' => 'folder_zip', 'tar' => 'folder_zip', 'gz' => 'folder_zip', // 其他 'csv' => 'table_rows', ]; return $icons[$extension] ?? 'insert_drive_file'; } /** * 检查文件是否存在 */ public function exists(): bool { return Storage::disk($this->disk)->exists($this->getFullPathAttribute()); } /** * 获取文件内容 */ public function getContent(): string { return Storage::disk($this->disk)->get($this->getFullPathAttribute()); } /** * 删除物理文件 */ public function deletePhysicalFile(): bool { if ($this->exists()) { return Storage::disk($this->disk)->delete($this->getFullPathAttribute()); } return false; } /** * 获取文件URL */ public function getUrl(): string { if ($this->url) { return $this->url; } return Storage::disk($this->disk)->url($this->getFullPathAttribute()); } /** * 获取缩略图URL(如果是图片) */ public function getThumbnailUrl($width = 200, $height = 200): ?string { if (strpos($this->mime_type, 'image/') === 0) { // 这里可以集成图片处理库生成缩略图 // 暂时返回原图URL return $this->getUrl(); } return null; } /** * 获取文件统计 */ public static function getStatistics($userId = null) { $query = self::query(); if ($userId) { $query->where('user_id', $userId); } $total = $query->count(); $totalSize = $query->sum('size'); $byModule = $query->selectRaw('module, COUNT(*) as count, SUM(size) as size') ->groupBy('module') ->orderBy('count', 'desc') ->get(); $byType = $query->selectRaw('mime_type, COUNT(*) as count') ->groupBy('mime_type') ->orderBy('count', 'desc') ->limit(10) ->get(); return [ 'total' => $total, 'total_size' => $totalSize, 'total_size_formatted' => self::formatSize($totalSize), 'by_module' => $byModule, 'by_type' => $byType, ]; } /** * 格式化文件大小 */ private static function formatSize($bytes): string { $units = ['B', 'KB', 'MB', 'GB', 'TB']; for ($i = 0; $bytes >= 1024 && $i < 4; $i++) { $bytes /= 1024; } return round($bytes, 2) . ' ' . $units[$i]; } /** * 根据模块获取文件 */ public static function getByModule($module, $purpose = null, $limit = 20) { $query = self::where('module', $module)->where('status', 'active'); if ($purpose) { $query->where('purpose', $purpose); } return $query->orderBy('created_at', 'desc')->limit($limit)->get(); } /** * 清理过期文件 */ public static function cleanupExpired($days = 30) { $expiredDate = now()->subDays($days); $files = self::where('created_at', '<', $expiredDate) ->where('status', '!=', 'permanent') ->get(); $deletedCount = 0; $failedFiles = []; foreach ($files as $file) { try { // 删除物理文件 $file->deletePhysicalFile(); // 删除数据库记录 $file->delete(); $deletedCount++; } catch (\Exception $e) { $failedFiles[] = [ 'id' => $file->id, 'name' => $file->original_name, 'error' => $e->getMessage(), ]; } } return [ 'deleted_count' => $deletedCount, 'failed_files' => $failedFiles, ]; } }