This commit is contained in:
김보곤
2026-02-09 16:25:25 +09:00
3 changed files with 59 additions and 194 deletions

View File

@@ -1,88 +0,0 @@
APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost
APP_LOCALE=en
APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=en_US
APP_MAINTENANCE_DRIVER=file
# APP_MAINTENANCE_STORE=database
# PHP_CLI_SERVER_WORKERS=4
BCRYPT_ROUNDS=12
LOG_CHANNEL=stack
LOG_STACK=single
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
DB_CONNECTION=sqlite
# DB_HOST=127.0.0.1
# DB_PORT=3306
# DB_DATABASE=laravel
# DB_USERNAME=root
# DB_PASSWORD=
SESSION_DRIVER=database
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=null
BROADCAST_CONNECTION=log
FILESYSTEM_DISK=local
QUEUE_CONNECTION=database
CACHE_STORE=database
# CACHE_PREFIX=
MEMCACHED_HOST=127.0.0.1
REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=log
MAIL_SCHEME=null
MAIL_HOST=127.0.0.1
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
VITE_APP_NAME="${APP_NAME}"
# Google Gemini API (SAM AI 음성 어시스턴트)
GEMINI_API_KEY=
GEMINI_PROJECT_ID=
# FCM (Firebase Cloud Messaging)
FCM_PROJECT_ID=
FCM_SA_PATH=secrets/firebase-service-account.json
FCM_BATCH_CHUNK_SIZE=200
FCM_BATCH_DELAY_MS=100
FCM_LOGGING_ENABLED=true
FCM_LOG_CHANNEL=stack
# 바로빌 API (세금계산서 연동)
# @see https://dev.barobill.co.kr/
BAROBILL_CERT_KEY=
BAROBILL_CORP_NUM=
BAROBILL_TEST_MODE=true
# Google Cloud Storage (음성 녹음 백업)
GCS_BUCKET_NAME=
GCS_SERVICE_ACCOUNT_PATH=/var/www/sales/apikey/google_service_account.json
GCS_USE_DB_CONFIG=true

View File

@@ -12,7 +12,7 @@
class MidInspectionTemplateSeeder extends Seeder
{
private int $tenantId = 1;
private int $tenantId = 287;
public function run(): void
{
@@ -65,7 +65,11 @@ private function jointbarTemplate(): array
'title' => '조인트바 - 중간 검사 성적서',
'sections' => [
[
'title' => '조인트바 검사 항목',
'title' => '중간검사 기준서',
'items' => [],
],
[
'title' => '중간검사 DATA',
'items' => [
[
'category' => '겉모양',
@@ -162,7 +166,11 @@ private function slatTemplate(): array
'title' => '슬랫 - 중간 검사 성적서',
'sections' => [
[
'title' => '철재스라트 (EGI 1.55T) 검사 항목',
'title' => '중간검사 기준서',
'items' => [],
],
[
'title' => '중간검사 DATA',
'items' => [
[
'category' => '겉모양',
@@ -244,7 +252,11 @@ private function screenTemplate(): array
'title' => '스크린 - 중간 검사 성적서',
'sections' => [
[
'title' => '스크린 검사 항목',
'title' => '중간검사 기준서',
'items' => [],
],
[
'title' => '중간검사 DATA',
'items' => [
[
'category' => '겉모양',
@@ -334,100 +346,27 @@ private function bendingTemplate(): array
'title' => '절곡품 - 중간 검사 성적서',
'sections' => [
[
'title' => '가이드레일 검사',
'items' => [
[
'category' => '겉모양',
'item' => '절곡상태',
'standard' => '양호/불량',
'method' => '육안검사',
'frequency' => '전수',
],
[
'category' => '치수',
'item' => '길이',
'standard' => '도면치수 ± 4mm',
'method' => '계측검사',
'frequency' => '전수',
],
[
'category' => '치수',
'item' => '너비',
'standard' => '도면치수 ± 4mm',
'method' => '계측검사',
'frequency' => '전수',
],
[
'category' => '치수',
'item' => '간격 (POINT별)',
'standard' => '도면치수 ± 2mm (벽면형 4P, 측면형 6P)',
'method' => '계측검사',
'frequency' => '전수',
],
],
'title' => '중간검사 기준서',
'items' => [],
],
[
'title' => '하단마감재 검사',
'title' => '중간검사 DATA',
'items' => [
[
'category' => '겉모양',
'item' => '절곡상태',
'standard' => '양호/불량',
'method' => '육안검사',
'frequency' => '전수',
],
[
'category' => '치수',
'item' => '너비',
'standard' => '60mm 기준',
'method' => '계측검사',
'frequency' => '전수',
],
],
],
[
'title' => '케이스(셔터박스) 검사',
'items' => [
[
'category' => '겉모양',
'item' => '절곡상태',
'standard' => '양호/불량',
'method' => '육안검사',
'frequency' => '전수',
],
[
'category' => '치수',
'item' => '높이/하단/너비차/위치',
'standard' => '도면치수 기준 (양면/밑면/후면)',
'method' => '계측검사',
'frequency' => '전수',
],
],
],
[
'title' => '하단 L-BAR / 연기차단재 검사',
'items' => [
[
'category' => '치수',
'item' => 'L-BAR 너비',
'standard' => '17mm 기준',
'method' => '계측검사',
'frequency' => '전수',
],
[
'category' => '치수',
'item' => '연기차단재 (가이드레일용)',
'standard' => '너비 50mm, 간격 12mm',
'method' => '계측검사',
'frequency' => '전수',
],
[
'category' => '치수',
'item' => '연기차단재 (케이스용)',
'standard' => '너비 80mm, 간격 12mm',
'method' => '계측검사',
'frequency' => '전수',
],
// 가이드레일
['category' => '가이드레일/겉모양', 'item' => '절곡상태', 'standard' => '양호/불량', 'method' => '육안검사', 'frequency' => '전수'],
['category' => '가이드레일/치수', 'item' => '길이', 'standard' => '도면치수 ± 4mm', 'method' => '계측검사', 'frequency' => '전수'],
['category' => '가이드레일/치수', 'item' => '너비', 'standard' => '도면치수 ± 4mm', 'method' => '계측검사', 'frequency' => '전수'],
['category' => '가이드레일/치수', 'item' => '간격 (POINT별)', 'standard' => '도면치수 ± 2mm (벽면형 4P, 측면형 6P)', 'method' => '계측검사', 'frequency' => '전수'],
// 하단마감재
['category' => '하단마감재/겉모양', 'item' => '절곡상태', 'standard' => '양호/불량', 'method' => '육안검사', 'frequency' => '전수'],
['category' => '하단마감재/치수', 'item' => '너비', 'standard' => '60mm 기준', 'method' => '계측검사', 'frequency' => '전수'],
// 케이스(셔터박스)
['category' => '케이스/겉모양', 'item' => '절곡상태', 'standard' => '양호/불량', 'method' => '육안검사', 'frequency' => '전수'],
['category' => '케이스/치수', 'item' => '높이/하단/너비차/위치', 'standard' => '도면치수 기준 (양면/밑면/후면)', 'method' => '계측검사', 'frequency' => '전수'],
// 하단 L-BAR / 연기차단재
['category' => 'L-BAR·연기차단재/치수', 'item' => 'L-BAR 너비', 'standard' => '17mm 기준', 'method' => '계측검사', 'frequency' => '전수'],
['category' => 'L-BAR·연기차단재/치수', 'item' => '연기차단재 (가이드레일용)', 'standard' => '너비 50mm, 간격 12mm', 'method' => '계측검사', 'frequency' => '전수'],
['category' => 'L-BAR·연기차단재/치수', 'item' => '연기차단재 (케이스용)', 'standard' => '너비 80mm, 간격 12mm', 'method' => '계측검사', 'frequency' => '전수'],
],
],
],
@@ -491,11 +430,12 @@ private function createBasicFields(int $templateId): void
$fields = [
['label' => '품명', 'field_type' => 'text', 'sort_order' => 1],
['label' => '규격', 'field_type' => 'text', 'sort_order' => 2],
['label' => '로트크기', 'field_type' => 'text', 'sort_order' => 3],
['label' => '발주처', 'field_type' => 'text', 'sort_order' => 4],
['label' => '현장명', 'field_type' => 'text', 'sort_order' => 5],
['label' => '검사일자', 'field_type' => 'date', 'sort_order' => 6],
['label' => '검사자', 'field_type' => 'text', 'sort_order' => 7],
['label' => '수주 LOT NO', 'field_type' => 'text', 'sort_order' => 3],
['label' => '로트크기', 'field_type' => 'text', 'sort_order' => 4],
['label' => '발주처', 'field_type' => 'text', 'sort_order' => 5],
['label' => '현장명', 'field_type' => 'text', 'sort_order' => 6],
['label' => '검사자', 'field_type' => 'date', 'sort_order' => 7],
['label' => '검사자', 'field_type' => 'text', 'sort_order' => 8],
];
foreach ($fields as $field) {

View File

@@ -252,14 +252,26 @@ function buildDocumentPreviewHtml(data) {
}).join('');
};
// 섹션 이미지
const imagesHtml = sections.filter(s => s.image_path).map(s => `
<div class="mb-4 text-center">
<p class="text-xs font-medium text-gray-600 mb-1">${_previewEsc(s.title || '검사 기준')}</p>
<img src="/storage/${s.image_path}" alt="${_previewEsc(s.title)}" class="max-h-40 mx-auto border rounded">
// 섹션 이미지 섹션(items 없음)과 데이터 섹션(items 있음)으로 분리
const imageSections = sections.filter(s => (s.items || []).length === 0);
const dataSections = sections.filter(s => (s.items || []).length > 0);
// 이미지 섹션: ■ 타이틀 + 이미지 또는 플레이스홀더
const imageSectionsHtml = imageSections.map(s => `
<div class="mb-3">
<p class="text-sm font-bold mb-1">■ ${_previewEsc(s.title)}</p>
${s.image_path
? `<img src="/storage/${s.image_path}" alt="${_previewEsc(s.title)}" class="max-h-48 mx-auto border rounded">`
: `<div class="border border-dashed border-gray-300 rounded p-6 text-center text-gray-400 text-xs">이미지 미등록 (편집에서 업로드)</div>`
}
</div>
`).join('');
// 데이터 섹션 타이틀
const dataSectionTitle = dataSections.length > 0
? `<p class="text-sm font-bold mb-1 mt-3">■ ${_previewEsc(dataSections[0].title)}</p>`
: '';
return `
<div class="bg-white p-6" style="font-family: 'Malgun Gothic', sans-serif; font-size: 12px; max-width: 900px; margin: 0 auto;">
<div class="flex justify-between items-start mb-4">
@@ -273,8 +285,9 @@ function buildDocumentPreviewHtml(data) {
<div>${approvalHtml}</div>
</div>
${basicHtml}
${imagesHtml}
${imageSectionsHtml}
${columns.length > 0 ? `
${dataSectionTitle}
<table class="w-full border-collapse text-xs">
<thead>${renderHeaders()}</thead>
<tbody>${renderRows()}</tbody>