From 45aa0f9c722e330aca413698985bfeca66c533d0 Mon Sep 17 00:00:00 2001 From: pro Date: Wed, 28 Jan 2026 16:31:10 +0900 Subject: [PATCH] =?UTF-8?q?fix:=EB=AA=85=ED=95=A8=20OCR=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=20=EC=A0=80=EC=9E=A5=20=EC=95=88=EB=90=98?= =?UTF-8?q?=EB=8D=98=20=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - TenantProspectController: business_card_image_data (Base64) validation 및 처리 추가 - TenantProspectService: saveBase64Image 메서드 추가로 Base64 이미지 저장 지원 - OCR로 인식한 명함 이미지가 DB에 정상 저장되도록 수정 Co-Authored-By: Claude Opus 4.5 --- .../Sales/TenantProspectController.php | 8 ++++- app/Services/Sales/TenantProspectService.php | 34 +++++++++++++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/app/Http/Controllers/Sales/TenantProspectController.php b/app/Http/Controllers/Sales/TenantProspectController.php index d44472a8..730babef 100644 --- a/app/Http/Controllers/Sales/TenantProspectController.php +++ b/app/Http/Controllers/Sales/TenantProspectController.php @@ -65,6 +65,7 @@ public function store(Request $request) 'contact_email' => 'nullable|email|max:100', 'address' => 'nullable|string|max:500', 'business_card' => 'nullable|image|max:5120', + 'business_card_image_data' => 'nullable|string', 'memo' => 'nullable|string|max:1000', ]); @@ -79,9 +80,14 @@ public function store(Request $request) // 등록자는 현재 로그인 사용자 $validated['registered_by'] = auth()->id(); + // Base64 이미지 데이터가 있으면 전달 + $businessCardBase64 = $validated['business_card_image_data'] ?? null; + unset($validated['business_card_image_data']); + $this->service->register( $validated, - $request->file('business_card') + $request->file('business_card'), + $businessCardBase64 ); return redirect()->route('sales.prospects.index') diff --git a/app/Services/Sales/TenantProspectService.php b/app/Services/Sales/TenantProspectService.php index 94f46c24..655fa5c5 100644 --- a/app/Services/Sales/TenantProspectService.php +++ b/app/Services/Sales/TenantProspectService.php @@ -14,17 +14,19 @@ class TenantProspectService /** * 명함 등록 (영업권 확보) */ - public function register(array $data, ?UploadedFile $businessCard = null): TenantProspect + public function register(array $data, ?UploadedFile $businessCard = null, ?string $businessCardBase64 = null): TenantProspect { - return DB::transaction(function () use ($data, $businessCard) { + return DB::transaction(function () use ($data, $businessCard, $businessCardBase64) { $now = now(); $expiresAt = $now->copy()->addMonths(TenantProspect::VALIDITY_MONTHS); $cooldownEndsAt = $expiresAt->copy()->addMonths(TenantProspect::COOLDOWN_MONTHS); - // 명함 이미지 저장 + // 명함 이미지 저장 (파일 업로드 또는 Base64) $businessCardPath = null; if ($businessCard) { $businessCardPath = $this->uploadBusinessCard($businessCard, $data['registered_by']); + } elseif ($businessCardBase64) { + $businessCardPath = $this->saveBase64Image($businessCardBase64, $data['registered_by']); } return TenantProspect::create([ @@ -265,6 +267,32 @@ private function uploadBusinessCard(UploadedFile $file, int $userId): string return $this->uploadAttachment($file, $userId); } + /** + * Base64 이미지 저장 + */ + private function saveBase64Image(string $base64Data, int $userId): ?string + { + // data:image/jpeg;base64,... 형식에서 데이터 추출 + if (preg_match('/^data:image\/(\w+);base64,/', $base64Data, $matches)) { + $extension = $matches[1]; + $base64Data = preg_replace('/^data:image\/\w+;base64,/', '', $base64Data); + } else { + $extension = 'jpg'; + } + + $imageData = base64_decode($base64Data); + if ($imageData === false) { + return null; + } + + $storedName = Str::uuid() . '.' . $extension; + $filePath = "prospects/{$userId}/{$storedName}"; + + Storage::disk('tenant')->put($filePath, $imageData); + + return $filePath; + } + /** * 명함 이미지 삭제 */