first
This commit is contained in:
141
server-api/app/support/AppraisalEvidenceService.php
Normal file
141
server-api/app/support/AppraisalEvidenceService.php
Normal file
@@ -0,0 +1,141 @@
|
||||
<?php
|
||||
|
||||
namespace app\support;
|
||||
|
||||
use support\Request;
|
||||
use function parse_url;
|
||||
use function str_starts_with;
|
||||
use function strtolower;
|
||||
|
||||
class AppraisalEvidenceService
|
||||
{
|
||||
private const IMAGE_EXTENSIONS = ['jpg', 'jpeg', 'png', 'webp', 'gif', 'bmp', 'heic'];
|
||||
private const VIDEO_EXTENSIONS = ['mp4', 'mov', 'm4v', 'webm', 'avi', 'mpeg', 'mpg'];
|
||||
private const PDF_EXTENSIONS = ['pdf'];
|
||||
|
||||
public function upload(Request $request, string $inputName = 'file'): array
|
||||
{
|
||||
$file = $request->file($inputName);
|
||||
if (!$file || !$file->isValid()) {
|
||||
throw new \RuntimeException('上传文件无效');
|
||||
}
|
||||
|
||||
$extension = strtolower($file->getUploadExtension() ?: '');
|
||||
$fileType = $this->detectFileType($extension);
|
||||
if ($fileType === 'file') {
|
||||
throw new \RuntimeException('仅支持上传图片、视频或 PDF 文件');
|
||||
}
|
||||
|
||||
$filename = sprintf('evidence_%s.%s', uniqid(), $extension ?: 'dat');
|
||||
$relativeDir = 'uploads/appraisal-evidence/' . date('Ymd');
|
||||
$relativePath = $relativeDir . '/' . $filename;
|
||||
$this->storage()->putUploadedFile($file, $relativePath);
|
||||
|
||||
$fileUrl = $this->storage()->publicUrl($request, $relativePath);
|
||||
|
||||
return [
|
||||
'file_id' => md5($relativePath),
|
||||
'file_url' => $fileUrl,
|
||||
'thumbnail_url' => $fileType === 'image' ? $fileUrl : '',
|
||||
'name' => $file->getUploadName(),
|
||||
'file_type' => $fileType,
|
||||
'mime_type' => $this->mimeType($fileType, $extension),
|
||||
];
|
||||
}
|
||||
|
||||
public function delete(string $fileUrl): void
|
||||
{
|
||||
$relativePath = $this->storage()->storagePath($fileUrl);
|
||||
if (!str_starts_with($relativePath, 'uploads/appraisal-evidence/')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->storage()->delete($relativePath);
|
||||
}
|
||||
|
||||
public function normalize(mixed $attachments, ?Request $request = null, bool $forStorage = false): array
|
||||
{
|
||||
if (is_string($attachments) && $attachments !== '') {
|
||||
$decoded = json_decode($attachments, true);
|
||||
$attachments = is_array($decoded) ? $decoded : [];
|
||||
}
|
||||
|
||||
if (!is_array($attachments)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$list = [];
|
||||
foreach ($attachments as $item) {
|
||||
if (!is_array($item)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$fileUrl = trim((string)($item['file_url'] ?? ''));
|
||||
if ($fileUrl === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = trim((string)($item['name'] ?? ''));
|
||||
$mimeType = trim((string)($item['mime_type'] ?? ''));
|
||||
$fileType = trim((string)($item['file_type'] ?? ''));
|
||||
|
||||
if ($fileType === '') {
|
||||
$path = parse_url('/' . $this->storage()->storagePath($fileUrl), PHP_URL_PATH) ?: '';
|
||||
$extension = strtolower(pathinfo($path, PATHINFO_EXTENSION));
|
||||
$fileType = $this->detectFileType($extension);
|
||||
if ($mimeType === '') {
|
||||
$mimeType = $this->mimeType($fileType, $extension);
|
||||
}
|
||||
}
|
||||
|
||||
$storedFileUrl = $this->storage()->storagePath($fileUrl);
|
||||
$storedThumbnailUrl = $this->storage()->storagePath(trim((string)($item['thumbnail_url'] ?? ($fileType === 'image' ? $fileUrl : ''))));
|
||||
|
||||
$list[] = [
|
||||
'file_id' => trim((string)($item['file_id'] ?? md5($storedFileUrl))),
|
||||
'file_url' => $forStorage
|
||||
? '/' . $storedFileUrl
|
||||
: ($request ? $this->storage()->normalizeUrl($fileUrl, $request) : $fileUrl),
|
||||
'thumbnail_url' => $forStorage
|
||||
? ($storedThumbnailUrl !== '' ? '/' . $storedThumbnailUrl : '')
|
||||
: ($request
|
||||
? $this->storage()->normalizeUrl(trim((string)($item['thumbnail_url'] ?? ($fileType === 'image' ? $fileUrl : ''))), $request)
|
||||
: trim((string)($item['thumbnail_url'] ?? ($fileType === 'image' ? $fileUrl : '')))),
|
||||
'name' => $name,
|
||||
'file_type' => $fileType ?: 'file',
|
||||
'mime_type' => $mimeType,
|
||||
];
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
public function detectFileType(string $extension): string
|
||||
{
|
||||
if (in_array($extension, self::IMAGE_EXTENSIONS, true)) {
|
||||
return 'image';
|
||||
}
|
||||
if (in_array($extension, self::VIDEO_EXTENSIONS, true)) {
|
||||
return 'video';
|
||||
}
|
||||
if (in_array($extension, self::PDF_EXTENSIONS, true)) {
|
||||
return 'pdf';
|
||||
}
|
||||
return 'file';
|
||||
}
|
||||
|
||||
private function mimeType(string $fileType, string $extension): string
|
||||
{
|
||||
return match ($fileType) {
|
||||
'image' => 'image/' . ($extension === 'jpg' ? 'jpeg' : ($extension ?: 'jpeg')),
|
||||
'video' => 'video/' . ($extension ?: 'mp4'),
|
||||
'pdf' => 'application/pdf',
|
||||
default => 'application/octet-stream',
|
||||
};
|
||||
}
|
||||
|
||||
private function storage(): FileStorageService
|
||||
{
|
||||
return new FileStorageService();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user