feat(tksafety): 통합 출입신고 관리 시스템 구현

- DB 마이그레이션: request_type, visitor_name, department_id, check_in/out_time 컬럼 + status ENUM 확장
- 4소스 UNION 대시보드: 방문(외부/내부) + TBM + 협력업체 통합 조회
- 체크인/체크아웃 API + 내부 출입 신고(승인 불필요) 지원
- 통합 출입 현황판 페이지 신규 (entry-dashboard.html)
- 출입 신청/관리 페이지에 유형 필터 + 체크인/아웃 버튼 추가
- safety_entry_dashboard 권한 추가

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Hyungi Ahn
2026-03-13 14:24:13 +09:00
parent 5a062759c5
commit 6a20056e05
16 changed files with 810 additions and 57 deletions

View File

@@ -38,16 +38,40 @@
<h2 class="text-base font-semibold text-gray-800 mb-4"><i class="fas fa-file-signature text-blue-500 mr-2"></i>출입 신청</h2>
<form id="visitRequestForm">
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3">
<!-- 업체명 -->
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">업체명 <span class="text-red-400">*</span></label>
<input type="text" id="visitorCompany" class="input-field w-full px-3 py-2 rounded-lg text-sm" placeholder="방문 업체명" required>
<!-- 출입 유형 -->
<div class="sm:col-span-2 lg:col-span-3">
<label class="block text-xs font-medium text-gray-600 mb-1">출입 유형</label>
<div class="flex gap-4">
<label class="flex items-center gap-2 cursor-pointer">
<input type="radio" name="requestType" value="external" checked class="text-blue-600"> <span class="text-sm">외부 방문</span>
</label>
<label class="flex items-center gap-2 cursor-pointer">
<input type="radio" name="requestType" value="internal" class="text-blue-600"> <span class="text-sm">내부 출입</span>
</label>
</div>
</div>
<!-- 인원 -->
<div>
<!-- 업체명 (외부) -->
<div id="companyField">
<label class="block text-xs font-medium text-gray-600 mb-1">업체명 <span class="text-red-400">*</span></label>
<input type="text" id="visitorCompany" class="input-field w-full px-3 py-2 rounded-lg text-sm" placeholder="방문 업체명">
</div>
<!-- 방문자 이름 -->
<div id="visitorNameField">
<label class="block text-xs font-medium text-gray-600 mb-1">방문자 이름 <span id="visitorNameRequired" class="text-red-400 hidden">*</span></label>
<input type="text" id="visitorName" class="input-field w-full px-3 py-2 rounded-lg text-sm" placeholder="방문자 이름">
</div>
<!-- 인원 (외부만) -->
<div id="countField">
<label class="block text-xs font-medium text-gray-600 mb-1">방문 인원</label>
<input type="number" id="visitorCount" value="1" min="1" class="input-field w-full px-3 py-2 rounded-lg text-sm">
</div>
<!-- 부서 (내부만) -->
<div id="departmentField" class="hidden">
<label class="block text-xs font-medium text-gray-600 mb-1">부서</label>
<select id="departmentId" class="input-field w-full px-3 py-2 rounded-lg text-sm">
<option value="">선택 (선택사항)</option>
</select>
</div>
<!-- 작업장 분류 -->
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">작업장 분류 <span class="text-red-400">*</span></label>
@@ -100,8 +124,8 @@
<table class="visit-table">
<thead>
<tr>
<th>신청일</th>
<th>업체</th>
<th>유형</th>
<th>업체/이름</th>
<th class="text-center">인원</th>
<th>작업장</th>
<th>방문일</th>
@@ -121,8 +145,8 @@
</div>
</div>
<script src="/static/js/tksafety-core.js"></script>
<script src="/static/js/tksafety-visit-request.js"></script>
<script src="/static/js/tksafety-core.js?v=2"></script>
<script src="/static/js/tksafety-visit-request.js?v=2"></script>
<script>initVisitRequestPage();</script>
</body>
</html>