diff --git a/app/Http/Controllers/ESign/EsignApiController.php b/app/Http/Controllers/ESign/EsignApiController.php
index 5a655805..212112ab 100644
--- a/app/Http/Controllers/ESign/EsignApiController.php
+++ b/app/Http/Controllers/ESign/EsignApiController.php
@@ -11,6 +11,7 @@
use App\Models\ESign\EsignSigner;
use App\Models\ESign\EsignSignField;
use App\Models\ESign\EsignAuditLog;
+use App\Models\Tenants\TenantSetting;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
@@ -20,6 +21,101 @@
class EsignApiController extends Controller
{
+ /**
+ * 법인도장 조회
+ */
+ public function getStamp(): JsonResponse
+ {
+ $tenantId = session('selected_tenant_id', 1);
+ $setting = TenantSetting::where('tenant_id', $tenantId)
+ ->where('setting_group', 'esign')
+ ->where('setting_key', 'company_stamp')
+ ->first();
+
+ if (!$setting || empty($setting->setting_value['image_path'])) {
+ return response()->json(['success' => true, 'data' => null]);
+ }
+
+ $path = $setting->setting_value['image_path'];
+ $exists = Storage::disk('local')->exists($path);
+
+ return response()->json([
+ 'success' => true,
+ 'data' => $exists ? [
+ 'image_path' => $path,
+ 'image_url' => '/storage/' . $path,
+ ] : null,
+ ]);
+ }
+
+ /**
+ * 법인도장 업로드
+ */
+ public function uploadStamp(Request $request): JsonResponse
+ {
+ $request->validate([
+ 'stamp_image' => 'required|image|max:5120',
+ ]);
+
+ $tenantId = session('selected_tenant_id', 1);
+ $file = $request->file('stamp_image');
+
+ $path = "esign/{$tenantId}/stamps/company_stamp.png";
+
+ // 기존 파일이 있으면 삭제
+ if (Storage::disk('local')->exists($path)) {
+ Storage::disk('local')->delete($path);
+ }
+
+ Storage::disk('local')->put($path, file_get_contents($file->getRealPath()));
+
+ TenantSetting::updateOrCreate(
+ [
+ 'tenant_id' => $tenantId,
+ 'setting_group' => 'esign',
+ 'setting_key' => 'company_stamp',
+ ],
+ [
+ 'setting_value' => ['image_path' => $path],
+ 'updated_by' => auth()->id(),
+ ]
+ );
+
+ return response()->json([
+ 'success' => true,
+ 'message' => '법인도장이 등록되었습니다.',
+ 'data' => [
+ 'image_path' => $path,
+ 'image_url' => '/storage/' . $path,
+ ],
+ ]);
+ }
+
+ /**
+ * 법인도장 삭제
+ */
+ public function deleteStamp(): JsonResponse
+ {
+ $tenantId = session('selected_tenant_id', 1);
+ $setting = TenantSetting::where('tenant_id', $tenantId)
+ ->where('setting_group', 'esign')
+ ->where('setting_key', 'company_stamp')
+ ->first();
+
+ if ($setting) {
+ $path = $setting->setting_value['image_path'] ?? null;
+ if ($path && Storage::disk('local')->exists($path)) {
+ Storage::disk('local')->delete($path);
+ }
+ $setting->delete();
+ }
+
+ return response()->json([
+ 'success' => true,
+ 'message' => '법인도장이 삭제되었습니다.',
+ ]);
+ }
+
/**
* 상태별 통계
*/
@@ -99,7 +195,6 @@ public function store(Request $request): JsonResponse
'metadata' => 'nullable|array',
'metadata.*' => 'nullable|string|max:500',
'file' => 'nullable|file|mimes:pdf,doc,docx|max:20480',
- 'creator_stamp_image' => 'nullable|string',
]);
$tenantId = session('selected_tenant_id', 1);
@@ -179,18 +274,22 @@ public function store(Request $request): JsonResponse
]);
}
- // 법인도장 이미지 처리
- if ($request->input('creator_stamp_image')) {
+ // 법인도장 자동 적용: tenant_settings에 등록된 도장이 있으면 creator signer에 설정
+ $stampSetting = TenantSetting::where('tenant_id', $tenantId)
+ ->where('setting_group', 'esign')
+ ->where('setting_key', 'company_stamp')
+ ->first();
+
+ if ($stampSetting && !empty($stampSetting->setting_value['image_path'])) {
$creatorSigner = EsignSigner::withoutGlobalScopes()
->where('contract_id', $contract->id)
->where('role', 'creator')
->first();
if ($creatorSigner) {
- $imageData = base64_decode($request->input('creator_stamp_image'));
- $imagePath = "esign/{$tenantId}/signatures/{$contract->id}_{$creatorSigner->id}_stamp.png";
- Storage::disk('local')->put($imagePath, $imageData);
- $creatorSigner->update(['signature_image_path' => $imagePath]);
+ $creatorSigner->update([
+ 'signature_image_path' => $stampSetting->setting_value['image_path'],
+ ]);
}
}
diff --git a/resources/views/esign/create.blade.php b/resources/views/esign/create.blade.php
index c1f6ea7b..18661c26 100644
--- a/resources/views/esign/create.blade.php
+++ b/resources/views/esign/create.blade.php
@@ -56,8 +56,7 @@ className="w-full border border-gray-300 rounded-md px-2.5 py-1.5 text-sm focus:
counterpart_name: '', counterpart_email: '', counterpart_phone: '',
});
const [file, setFile] = useState(null);
- const [stampImage, setStampImage] = useState(null);
- const [stampPreview, setStampPreview] = useState(null);
+ const [registeredStamp, setRegisteredStamp] = useState(null); // { image_path, image_url }
const [submitting, setSubmitting] = useState(false);
const [errors, setErrors] = useState({});
const [templates, setTemplates] = useState([]);
@@ -66,27 +65,12 @@ className="w-full border border-gray-300 rounded-md px-2.5 py-1.5 text-sm focus:
const [templateSearch, setTemplateSearch] = useState('');
const [metadata, setMetadata] = useState({});
const fileRef = useRef(null);
- const stampFileRef = useRef(null);
-
- const handleStampSelect = (e) => {
- const selected = e.target.files[0];
- if (!selected) return;
- const reader = new FileReader();
- reader.onload = () => {
- const base64 = reader.result.split(',')[1];
- setStampImage(base64);
- setStampPreview(reader.result);
- };
- reader.readAsDataURL(selected);
- };
-
- const removeStamp = () => {
- setStampImage(null);
- setStampPreview(null);
- if (stampFileRef.current) stampFileRef.current.value = '';
- };
useEffect(() => {
+ fetch('/esign/contracts/stamp', { headers: { 'Accept': 'application/json' } })
+ .then(r => r.json())
+ .then(json => { if (json.success) setRegisteredStamp(json.data); })
+ .catch(() => {});
fetch('/esign/contracts/templates', { headers: { 'Accept': 'application/json' } })
.then(r => r.json())
.then(json => { if (json.success) setTemplates(json.data); })
@@ -153,8 +137,6 @@ className="w-full border border-gray-300 rounded-md px-2.5 py-1.5 text-sm focus:
Object.entries(metadata).forEach(([k, v]) => { fd.append(`metadata[${k}]`, v || ''); });
}
- if (stampImage) fd.append('creator_stamp_image', stampImage);
-
try {
fd.append('_token', csrfToken);
fd.append('signers[0][name]', form.creator_name);
@@ -251,34 +233,28 @@ className="w-full border border-gray-300 rounded-md px-2.5 py-1.5 text-sm focus:
등록된 법인도장이 없습니다.
+ 대시보드에서 법인도장을 먼저 등록해 주세요등록된 법인도장은 새 계약 생성 시 자동으로 적용됩니다.
+ + {stamp ? ( +법인도장이 등록되어 있습니다.
+새 계약 생성 시 작성자 서명에 자동 적용됩니다.
+등록된 법인도장이 없습니다.
+ + +PNG, JPG 형식 (최대 5MB)
+