You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

92 lines
2.7 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\URL;
class ApplicationFile extends Model
{
protected $fillable = [
'application_id',
'kind',
'disk',
'path',
'original_name',
'size',
'mime',
];
public function application(): BelongsTo
{
return $this->belongsTo(Application::class);
}
public function publicUrl(): string
{
$u = Storage::disk($this->disk)->url($this->path);
return preg_replace('#([^:])//+#', '$1/', $u) ?? $u;
}
/**
* 浏览器下载/「另存为」显示名:优先用户上传时的原始文件名,必要时按存储路径补全扩展名(避免无后缀时落到随机 storage 名)。
*/
public function clientDownloadName(): string
{
$raw = $this->original_name !== null && trim($this->original_name) !== ''
? basename(str_replace(['\\', '/'], '_', $this->original_name))
: '';
$storageExt = strtolower((string) pathinfo($this->path, PATHINFO_EXTENSION));
if ($raw !== '') {
$baseExt = strtolower((string) pathinfo($raw, PATHINFO_EXTENSION));
if ($storageExt !== '' && $baseExt === '') {
$raw .= '.'.$storageExt;
}
return $raw;
}
return $storageExt !== '' ? '附件.'.$storageExt : '附件';
}
/**
* PDF/图片在浏览器内联预览,其余类型用 attachment 以触发「保存为」时使用 clientDownloadName避免地址栏/标题仍显示 storage 随机名。
*/
public function preferredStreamDisposition(): string
{
$mime = strtolower((string) ($this->mime ?? ''));
if ($mime !== '') {
if (str_starts_with($mime, 'image/') || $mime === 'application/pdf') {
return 'inline';
}
return 'attachment';
}
$ext = strtolower((string) pathinfo($this->path, PATHINFO_EXTENSION));
if ($ext === 'pdf') {
return 'inline';
}
return 'attachment';
}
/**
* 选手端「预览」用 URL走 web 签名路由直出文件,不依赖 public/storage 符号链接(生产环境未 link 时 /storage/... 会 404
*/
public function participantPreviewSignedUrl(int $ttlSeconds = 172800): string
{
$u = URL::temporarySignedRoute(
'participant.application-file.download',
now()->addSeconds(max(60, $ttlSeconds)),
['file' => $this->id],
);
return preg_replace('#([^:])//+#', '$1/', $u) ?? $u;
}
}