106 lines
5.1 KiB
PHP
106 lines
5.1 KiB
PHP
<?php
|
||
|
||
namespace App\Support;
|
||
|
||
use App\Models\Business\CourierAgreementSignature;
|
||
use Illuminate\Http\UploadedFile;
|
||
use Illuminate\Support\Facades\Storage;
|
||
use Illuminate\Validation\Rule;
|
||
use Intervention\Image\ImageManager;
|
||
use RuntimeException;
|
||
|
||
final class CourierAgreementCredentials
|
||
{
|
||
public const IMAGES = [
|
||
'license' => '营业执照', 'id_front' => '身份证人像面', 'id_back' => '身份证国徽面',
|
||
'bank_front' => '银行卡正面', 'bank_back' => '银行卡背面',
|
||
];
|
||
|
||
public static function definitions(string $type): array
|
||
{
|
||
$sheets = [
|
||
'identity' => ['name' => '身份证推送单', 'images' => ['id_front', 'id_back']],
|
||
'bank' => ['name' => '银行卡推送单', 'images' => ['bank_front', 'bank_back']],
|
||
];
|
||
return match ($type) {
|
||
'authorization' => $sheets,
|
||
'entity-change' => ['license' => ['name' => '营业执照盖章推送单', 'images' => ['license']]] + $sheets,
|
||
default => [],
|
||
};
|
||
}
|
||
|
||
public static function rules(string $type, bool $requested): array
|
||
{
|
||
$allowed = self::definitions($type);
|
||
$required = $requested ? array_merge(...array_column($allowed ?: [['images' => []]], 'images')) : [];
|
||
$rules = [
|
||
'credential_required' => ['nullable', 'boolean', Rule::prohibitedIf($allowed === [] && $requested)],
|
||
'credential_signer' => ['nullable', 'integer', 'in:0,1'],
|
||
'credential_images' => ['nullable', 'array:' . implode(',', array_keys(self::IMAGES))],
|
||
];
|
||
foreach (self::IMAGES as $key => $label) {
|
||
$active = in_array($key, $required, true);
|
||
$rules['credential_images.' . $key] = [Rule::requiredIf($active), Rule::prohibitedIf(! $active),
|
||
'nullable', 'image', 'mimes:jpg,jpeg,png', 'max:10240', 'dimensions:max_width=5000,max_height=5000'];
|
||
}
|
||
return $rules;
|
||
}
|
||
|
||
public function prepare(CourierAgreementSignature $signature, array $uploads): array
|
||
{
|
||
$definitions = self::definitions($signature->document_type);
|
||
if (! ($signature->payload['credential_required'] ?? false)) {
|
||
return [];
|
||
}
|
||
$disk = Storage::disk('uploads');
|
||
$base = "courier-agreements/{$signature->company_id}/{$signature->business_no}/credentials";
|
||
$result = [];
|
||
foreach ($definitions as $key => $definition) {
|
||
$pictures = [];
|
||
$originals = [];
|
||
foreach ($definition['images'] as $imageKey) {
|
||
$upload = $uploads[$imageKey] ?? null;
|
||
if (! $upload instanceof UploadedFile || ! $upload->isValid()) {
|
||
throw new RuntimeException('证件图片不完整,请重新上传。');
|
||
}
|
||
$extension = $upload->getMimeType() === 'image/png' ? 'png' : 'jpg';
|
||
$originalPath = "{$base}/{$imageKey}.{$extension}";
|
||
$original = file_get_contents($upload->getRealPath());
|
||
if (! $disk->put($originalPath, $original)) {
|
||
throw new RuntimeException('证件原始图片无法写入私有存储。');
|
||
}
|
||
$image = (new ImageManager(['driver' => 'gd']))->make($upload->getRealPath())->orientate();
|
||
$image->resize(2400, 2400, static function ($constraint): void {
|
||
$constraint->aspectRatio();
|
||
$constraint->upsize();
|
||
});
|
||
$maxHeight = $key === 'license' ? 470 : 180;
|
||
$scale = min(450 / $image->width(), $maxHeight / $image->height());
|
||
$pictures[] = ['label' => self::IMAGES[$imageKey],
|
||
'uri' => 'data:image/png;base64,' . base64_encode((string) $image->encode('png')),
|
||
'width' => round($image->width() * $scale, 2), 'height' => round($image->height() * $scale, 2)];
|
||
$originals[$imageKey] = ['path' => $originalPath, 'sha256' => hash('sha256', $original)];
|
||
$image->destroy();
|
||
}
|
||
$pdf = app('dompdf.wrapper');
|
||
$pdf->setPaper('a4', 'portrait');
|
||
$pdf->loadHTML(view('business.pdf.courier-credential', [
|
||
'title' => $definition['name'], 'pictures' => $pictures,
|
||
'stampOnly' => $key === 'license', 'signature' => $signature,
|
||
'fontPath' => str_replace('\\', '/', resource_path('fonts/DroidSansFallback.ttf')),
|
||
])->render(), 'UTF-8');
|
||
$bytes = $pdf->output();
|
||
if (! str_starts_with($bytes, '%PDF-') || $pdf->getDomPDF()->getCanvas()->get_page_count() !== 1) {
|
||
throw new RuntimeException('证件推送单必须为一页 PDF,请检查上传图片。');
|
||
}
|
||
$sourcePath = "{$base}/{$key}-source.pdf";
|
||
if (! $disk->put($sourcePath, $bytes)) {
|
||
throw new RuntimeException('证件推送单无法写入私有存储。');
|
||
}
|
||
$result[$key] = ['name' => $definition['name'], 'source_path' => $sourcePath,
|
||
'source_sha256' => hash('sha256', $bytes), 'originals' => $originals];
|
||
}
|
||
return $result;
|
||
}
|
||
}
|