- 기존 단일 품의서(purchase_request)를 5가지 전문 양식으로 분리 - pr_expense: 지출품의서 (항목/금액/비고) - pr_contract: 계약체결품의서 (계약상대방/기간/금액/조건) - pr_purchase: 구매품의서 (품목/수량/단가/납품정보) - pr_trip: 출장품의서 (일정표/경비내역) - pr_settlement: 비용정산품의서 (사용일자/항목/지급방법) - Alpine.js 단일 컴포넌트로 5종 동적 전환 - show/create/edit 모두 pr_ prefix 코드 자동 감지
375 lines
19 KiB
PHP
375 lines
19 KiB
PHP
{{--
|
|
품의서 5종 읽기전용 렌더링
|
|
Props:
|
|
$content (array) - approvals.content JSON (pr_type 포함)
|
|
--}}
|
|
@php
|
|
$prType = $content['pr_type'] ?? 'pr_purchase';
|
|
$prTypeLabels = [
|
|
'pr_expense' => '지출품의서',
|
|
'pr_contract' => '계약체결품의서',
|
|
'pr_purchase' => '구매품의서',
|
|
'pr_trip' => '출장품의서',
|
|
'pr_settlement' => '비용정산품의서',
|
|
];
|
|
@endphp
|
|
<div class="space-y-4">
|
|
|
|
{{-- 유형 뱃지 --}}
|
|
@php
|
|
$badgeClass = match($prType) {
|
|
'pr_expense' => 'bg-orange-50 text-orange-700 border-orange-200',
|
|
'pr_contract' => 'bg-purple-50 text-purple-700 border-purple-200',
|
|
'pr_purchase' => 'bg-blue-50 text-blue-700 border-blue-200',
|
|
'pr_trip' => 'bg-green-50 text-green-700 border-green-200',
|
|
'pr_settlement' => 'bg-teal-50 text-teal-700 border-teal-200',
|
|
default => 'bg-gray-50 text-gray-700 border-gray-200',
|
|
};
|
|
@endphp
|
|
<div class="px-3 py-1.5 rounded-lg text-sm font-medium border {{ $badgeClass }}" style="display: inline-block;">
|
|
{{ $prTypeLabels[$prType] ?? '품의서' }}
|
|
</div>
|
|
|
|
{{-- 기본 정보 --}}
|
|
<div class="grid gap-3" style="grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));">
|
|
<div>
|
|
<span class="text-xs text-gray-500">작성일자</span>
|
|
<div class="text-sm font-medium mt-0.5">{{ $content['write_date'] ?? '-' }}</div>
|
|
</div>
|
|
<div>
|
|
<span class="text-xs text-gray-500">요청부서</span>
|
|
<div class="text-sm font-medium mt-0.5">{{ $content['department'] ?? '-' }}</div>
|
|
</div>
|
|
<div>
|
|
<span class="text-xs text-gray-500">요청자</span>
|
|
<div class="text-sm font-medium mt-0.5">{{ $content['writer_name'] ?? '-' }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- ═══ 지출품의서 ═══ --}}
|
|
@if($prType === 'pr_expense')
|
|
<div class="grid gap-3" style="grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));">
|
|
@if(!empty($content['expense_category']))
|
|
<div>
|
|
<span class="text-xs text-gray-500">지출항목</span>
|
|
<div class="text-sm font-medium mt-0.5">{{ $content['expense_category'] }}</div>
|
|
</div>
|
|
@endif
|
|
@if(!empty($content['usage_date']))
|
|
<div>
|
|
<span class="text-xs text-gray-500">사용일자</span>
|
|
<div class="text-sm font-medium mt-0.5">{{ $content['usage_date'] }}</div>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
@if(!empty($content['purpose']))
|
|
<div class="p-3 bg-orange-50 border border-orange-200 rounded-lg">
|
|
<span class="text-xs font-medium text-orange-700">사용목적</span>
|
|
<div class="text-sm text-gray-800 mt-1 whitespace-pre-wrap">{{ $content['purpose'] }}</div>
|
|
</div>
|
|
@endif
|
|
|
|
@if(!empty($content['items']))
|
|
<div class="overflow-x-auto border border-gray-200 rounded-lg">
|
|
<table class="w-full text-sm">
|
|
<thead class="bg-gray-50">
|
|
<tr>
|
|
<th class="px-3 py-2 text-left text-xs font-medium text-gray-600">항목</th>
|
|
<th class="px-3 py-2 text-right text-xs font-medium text-gray-600">금액</th>
|
|
<th class="px-3 py-2 text-left text-xs font-medium text-gray-600">비고</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach($content['items'] as $item)
|
|
<tr class="border-t border-gray-100">
|
|
<td class="px-3 py-2 text-xs text-gray-700">{{ $item['description'] ?? '' }}</td>
|
|
<td class="px-3 py-2 text-xs text-gray-700 text-right font-medium whitespace-nowrap">{{ number_format($item['amount'] ?? 0) }}</td>
|
|
<td class="px-3 py-2 text-xs text-gray-700">{{ $item['remark'] ?? '' }}</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
<tfoot class="bg-gray-50 border-t border-gray-200">
|
|
<tr>
|
|
<td class="px-3 py-2 text-xs font-semibold text-gray-700 text-right">합계</td>
|
|
<td class="px-3 py-2 text-xs font-bold text-blue-700 text-right whitespace-nowrap">{{ number_format($content['total_amount'] ?? 0) }}</td>
|
|
<td></td>
|
|
</tr>
|
|
</tfoot>
|
|
</table>
|
|
</div>
|
|
@endif
|
|
@endif
|
|
|
|
{{-- ═══ 계약체결품의서 ═══ --}}
|
|
@if($prType === 'pr_contract')
|
|
<div class="grid gap-3" style="grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));">
|
|
<div>
|
|
<span class="text-xs text-gray-500">계약상대방</span>
|
|
<div class="text-sm font-medium mt-0.5">{{ $content['contract_party'] ?? '-' }}</div>
|
|
</div>
|
|
<div>
|
|
<span class="text-xs text-gray-500">계약금액</span>
|
|
<div class="text-sm font-medium mt-0.5">{{ number_format($content['contract_amount'] ?? 0) }}원</div>
|
|
</div>
|
|
@if(!empty($content['contract_start']) || !empty($content['contract_end']))
|
|
<div>
|
|
<span class="text-xs text-gray-500">계약기간</span>
|
|
<div class="text-sm font-medium mt-0.5">{{ $content['contract_start'] ?? '' }} ~ {{ $content['contract_end'] ?? '' }}</div>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
@if(!empty($content['contract_content']))
|
|
<div class="p-3 bg-purple-50 border border-purple-200 rounded-lg">
|
|
<span class="text-xs font-medium text-purple-700">계약내용</span>
|
|
<div class="text-sm text-gray-800 mt-1 whitespace-pre-wrap">{{ $content['contract_content'] }}</div>
|
|
</div>
|
|
@endif
|
|
|
|
@php
|
|
$contractSections = [
|
|
['key' => 'contract_scope', 'label' => '계약범위'],
|
|
['key' => 'delivery_service', 'label' => '납품/서비스 내용'],
|
|
['key' => 'payment_terms', 'label' => '대금지급조건'],
|
|
['key' => 'special_terms', 'label' => '기타 특약사항'],
|
|
];
|
|
@endphp
|
|
@foreach($contractSections as $sec)
|
|
@if(!empty($content[$sec['key']]))
|
|
<div>
|
|
<span class="text-xs text-gray-500">{{ $sec['label'] }}</span>
|
|
<div class="text-sm text-gray-700 mt-0.5 whitespace-pre-wrap">{{ $content[$sec['key']] }}</div>
|
|
</div>
|
|
@endif
|
|
@endforeach
|
|
@endif
|
|
|
|
{{-- ═══ 구매품의서 ═══ --}}
|
|
@if($prType === 'pr_purchase')
|
|
@if(!empty($content['purpose']))
|
|
<div class="p-3 bg-blue-50 border border-blue-200 rounded-lg">
|
|
<span class="text-xs font-medium text-blue-700">구매 목적</span>
|
|
<div class="text-sm text-gray-800 mt-1 whitespace-pre-wrap">{{ $content['purpose'] }}</div>
|
|
</div>
|
|
@endif
|
|
|
|
@if(!empty($content['items']))
|
|
<div class="overflow-x-auto border border-gray-200 rounded-lg">
|
|
<table class="w-full text-sm">
|
|
<thead class="bg-gray-50">
|
|
<tr>
|
|
<th class="px-3 py-2 text-left text-xs font-medium text-gray-600">품목</th>
|
|
<th class="px-3 py-2 text-right text-xs font-medium text-gray-600">수량</th>
|
|
<th class="px-3 py-2 text-right text-xs font-medium text-gray-600">단가</th>
|
|
<th class="px-3 py-2 text-right text-xs font-medium text-gray-600">금액</th>
|
|
<th class="px-3 py-2 text-left text-xs font-medium text-gray-600">비고</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach($content['items'] as $item)
|
|
<tr class="border-t border-gray-100">
|
|
<td class="px-3 py-2 text-xs text-gray-700">{{ $item['description'] ?? '' }}</td>
|
|
<td class="px-3 py-2 text-xs text-gray-700 text-right">{{ $item['quantity'] ?? '' }}</td>
|
|
<td class="px-3 py-2 text-xs text-gray-700 text-right whitespace-nowrap">{{ number_format($item['unit_price'] ?? 0) }}</td>
|
|
<td class="px-3 py-2 text-xs text-gray-700 text-right font-medium whitespace-nowrap">{{ number_format($item['amount'] ?? 0) }}</td>
|
|
<td class="px-3 py-2 text-xs text-gray-700">{{ $item['remark'] ?? '' }}</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
<tfoot class="bg-gray-50 border-t border-gray-200">
|
|
<tr>
|
|
<td class="px-3 py-2 text-xs font-semibold text-gray-700 text-right" colspan="3">합계</td>
|
|
<td class="px-3 py-2 text-xs font-bold text-blue-700 text-right whitespace-nowrap">{{ number_format($content['total_amount'] ?? 0) }}</td>
|
|
<td></td>
|
|
</tr>
|
|
</tfoot>
|
|
</table>
|
|
</div>
|
|
@endif
|
|
|
|
<div class="grid gap-3" style="grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));">
|
|
@if(!empty($content['vendor']))
|
|
<div>
|
|
<span class="text-xs text-gray-500">납품업체</span>
|
|
<div class="text-sm font-medium mt-0.5">{{ $content['vendor'] }}</div>
|
|
</div>
|
|
@endif
|
|
@if(!empty($content['delivery_date']))
|
|
<div>
|
|
<span class="text-xs text-gray-500">납품예정일</span>
|
|
<div class="text-sm font-medium mt-0.5">{{ $content['delivery_date'] }}</div>
|
|
</div>
|
|
@endif
|
|
@if(!empty($content['delivery_place']))
|
|
<div>
|
|
<span class="text-xs text-gray-500">납품장소</span>
|
|
<div class="text-sm font-medium mt-0.5">{{ $content['delivery_place'] }}</div>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
@endif
|
|
|
|
{{-- ═══ 출장품의서 ═══ --}}
|
|
@if($prType === 'pr_trip')
|
|
<div class="grid gap-3" style="grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));">
|
|
<div>
|
|
<span class="text-xs text-gray-500">출장자</span>
|
|
<div class="text-sm font-medium mt-0.5">{{ $content['traveler'] ?? '-' }}</div>
|
|
</div>
|
|
<div>
|
|
<span class="text-xs text-gray-500">출장지</span>
|
|
<div class="text-sm font-medium mt-0.5">{{ $content['destination'] ?? '-' }}</div>
|
|
</div>
|
|
@if(!empty($content['trip_start']) || !empty($content['trip_end']))
|
|
<div>
|
|
<span class="text-xs text-gray-500">출장기간</span>
|
|
<div class="text-sm font-medium mt-0.5">{{ $content['trip_start'] ?? '' }} ~ {{ $content['trip_end'] ?? '' }}</div>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
@if(!empty($content['purpose']))
|
|
<div class="p-3 bg-green-50 border border-green-200 rounded-lg">
|
|
<span class="text-xs font-medium text-green-700">업무내용</span>
|
|
<div class="text-sm text-gray-800 mt-1 whitespace-pre-wrap">{{ $content['purpose'] }}</div>
|
|
</div>
|
|
@endif
|
|
|
|
@if(!empty($content['schedules']))
|
|
<div class="overflow-x-auto border border-gray-200 rounded-lg">
|
|
<table class="w-full text-sm">
|
|
<thead class="bg-gray-50">
|
|
<tr>
|
|
<th class="px-3 py-2 text-left text-xs font-medium text-gray-600">일자</th>
|
|
<th class="px-3 py-2 text-left text-xs font-medium text-gray-600">행선지</th>
|
|
<th class="px-3 py-2 text-left text-xs font-medium text-gray-600">업무내용</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach($content['schedules'] as $sch)
|
|
<tr class="border-t border-gray-100">
|
|
<td class="px-3 py-2 text-xs text-gray-700 whitespace-nowrap">{{ $sch['date'] ?? '' }}</td>
|
|
<td class="px-3 py-2 text-xs text-gray-700">{{ $sch['destination'] ?? '' }}</td>
|
|
<td class="px-3 py-2 text-xs text-gray-700">{{ $sch['task'] ?? '' }}</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
@endif
|
|
|
|
@if(!empty($content['trip_expenses']))
|
|
@php $te = $content['trip_expenses']; @endphp
|
|
<div class="grid gap-3" style="grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));">
|
|
<div class="text-center p-2 bg-gray-50 rounded-lg">
|
|
<span class="text-xs text-gray-500">교통비</span>
|
|
<div class="text-sm font-medium mt-0.5">{{ number_format($te['transport'] ?? 0) }}</div>
|
|
</div>
|
|
<div class="text-center p-2 bg-gray-50 rounded-lg">
|
|
<span class="text-xs text-gray-500">숙박비</span>
|
|
<div class="text-sm font-medium mt-0.5">{{ number_format($te['accommodation'] ?? 0) }}</div>
|
|
</div>
|
|
<div class="text-center p-2 bg-gray-50 rounded-lg">
|
|
<span class="text-xs text-gray-500">식비</span>
|
|
<div class="text-sm font-medium mt-0.5">{{ number_format($te['meal'] ?? 0) }}</div>
|
|
</div>
|
|
<div class="text-center p-2 bg-gray-50 rounded-lg">
|
|
<span class="text-xs text-gray-500">기타</span>
|
|
<div class="text-sm font-medium mt-0.5">{{ number_format($te['other'] ?? 0) }}</div>
|
|
</div>
|
|
<div class="text-center p-2 bg-blue-50 border border-blue-200 rounded-lg">
|
|
<span class="text-xs text-blue-600 font-medium">합계</span>
|
|
<div class="text-sm font-bold text-blue-700 mt-0.5">{{ number_format($content['trip_expense_total'] ?? 0) }}</div>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
@endif
|
|
|
|
{{-- ═══ 비용정산품의서 ═══ --}}
|
|
@if($prType === 'pr_settlement')
|
|
@if(!empty($content['purpose']))
|
|
<div class="p-3 bg-teal-50 border border-teal-200 rounded-lg">
|
|
<span class="text-xs font-medium text-teal-700">정산 사유</span>
|
|
<div class="text-sm text-gray-800 mt-1 whitespace-pre-wrap">{{ $content['purpose'] }}</div>
|
|
</div>
|
|
@endif
|
|
|
|
@if(!empty($content['items']))
|
|
<div class="overflow-x-auto border border-gray-200 rounded-lg">
|
|
<table class="w-full text-sm">
|
|
<thead class="bg-gray-50">
|
|
<tr>
|
|
<th class="px-3 py-2 text-left text-xs font-medium text-gray-600">사용일자</th>
|
|
<th class="px-3 py-2 text-left text-xs font-medium text-gray-600">항목</th>
|
|
<th class="px-3 py-2 text-right text-xs font-medium text-gray-600">금액</th>
|
|
<th class="px-3 py-2 text-left text-xs font-medium text-gray-600">비고</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach($content['items'] as $item)
|
|
<tr class="border-t border-gray-100">
|
|
<td class="px-3 py-2 text-xs text-gray-700 whitespace-nowrap">{{ $item['date'] ?? '' }}</td>
|
|
<td class="px-3 py-2 text-xs text-gray-700">{{ $item['description'] ?? '' }}</td>
|
|
<td class="px-3 py-2 text-xs text-gray-700 text-right font-medium whitespace-nowrap">{{ number_format($item['amount'] ?? 0) }}</td>
|
|
<td class="px-3 py-2 text-xs text-gray-700">{{ $item['remark'] ?? '' }}</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
<tfoot class="bg-gray-50 border-t border-gray-200">
|
|
<tr>
|
|
<td class="px-3 py-2 text-xs font-semibold text-gray-700 text-right" colspan="2">합계</td>
|
|
<td class="px-3 py-2 text-xs font-bold text-blue-700 text-right whitespace-nowrap">{{ number_format($content['total_amount'] ?? 0) }}</td>
|
|
<td></td>
|
|
</tr>
|
|
</tfoot>
|
|
</table>
|
|
</div>
|
|
@endif
|
|
|
|
@if(!empty($content['payment_method']))
|
|
<div>
|
|
<span class="text-xs text-gray-500">지급방법</span>
|
|
<div class="text-sm font-medium mt-0.5">
|
|
@if($content['payment_method'] === 'corporate_card')
|
|
법인카드 사용
|
|
@elseif($content['payment_method'] === 'personal_advance')
|
|
개인 선지출 후 정산
|
|
@else
|
|
{{ $content['payment_method'] }}
|
|
@endif
|
|
</div>
|
|
</div>
|
|
@endif
|
|
@endif
|
|
|
|
{{-- 공통: 첨부서류 메모 --}}
|
|
@if(!empty($content['attachment_memo']))
|
|
<div>
|
|
<span class="text-xs text-gray-500">첨부서류</span>
|
|
<div class="text-sm text-gray-700 mt-0.5 whitespace-pre-wrap">{{ $content['attachment_memo'] }}</div>
|
|
</div>
|
|
@endif
|
|
|
|
{{-- 공통: 첨부파일 --}}
|
|
@if(!empty($approval->attachments))
|
|
<div>
|
|
<span class="text-xs text-gray-500">첨부파일</span>
|
|
<div class="mt-1 space-y-1">
|
|
@foreach($approval->attachments as $file)
|
|
<div class="flex items-center gap-2 text-sm">
|
|
<svg class="w-4 h-4 text-gray-400 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 13"/>
|
|
</svg>
|
|
<a href="{{ route('api.admin.approvals.download-file', $file['id']) }}" class="text-blue-600 hover:underline" target="_blank">
|
|
{{ $file['name'] ?? '파일' }}
|
|
</a>
|
|
<span class="text-xs text-gray-400">
|
|
{{ isset($file['size']) ? number_format($file['size'] / 1024, 1) . 'KB' : '' }}
|
|
</span>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
@endif
|
|
</div>
|