erp-backend/app/Models/File.php
2026-04-01 17:07:04 +08:00

248 lines
6.1 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Facades\Storage;
class File extends Model
{
use HasFactory;
protected $fillable = [
'user_id',
'original_name',
'storage_name',
'path',
'url',
'mime_type',
'size',
'extension',
'disk',
'module',
'purpose',
'description',
'status',
];
protected $casts = [
'size' => '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,
];
}
}