Files
tk-factory-services/tkpurchase/web/partner.html
Hyungi Ahn 281f5d35d1 feat: tkpurchase 시스템 Phase 1 - 협력업체 마스터 + 당일 방문 관리
신규 독립 시스템 tkpurchase (구매/방문 관리) 구축:
- 협력업체 CRUD + 소속 작업자 관리 (마스터 데이터 소유)
- 당일 방문 등록/체크인/체크아웃 + 일괄 마감
- 업체 자동완성, CSV 내보내기, 집계 통계
- 자정 자동 체크아웃 (node-cron)
- tkuser 협력업체 읽기 전용 탭 + 권한 그리드(tkpurchase-perms) 추가
- docker-compose에 tkpurchase-api/web 서비스 추가

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 15:45:37 +09:00

299 lines
18 KiB
HTML

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>협력업체 관리 - TK 구매관리</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link rel="stylesheet" href="/static/css/tkpurchase.css?v=20260312">
</head>
<body>
<!-- Header -->
<header class="bg-emerald-700 text-white sticky top-0 z-50">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between items-center h-14">
<div class="flex items-center gap-3">
<i class="fas fa-truck text-xl text-emerald-200"></i>
<h1 class="text-lg font-semibold">TK 구매관리</h1>
</div>
<div class="flex items-center gap-4">
<div id="headerUserName" class="text-sm font-medium hidden sm:block">-</div>
<div id="headerUserAvatar" class="w-8 h-8 bg-emerald-600 rounded-full flex items-center justify-center text-sm font-semibold">-</div>
<button onclick="doLogout()" class="text-emerald-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
</div>
</div>
</div>
</header>
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
<div class="flex gap-6">
<!-- Sidebar Nav -->
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-48 flex-shrink-0 pt-2"></nav>
<!-- Main -->
<div class="flex-1 min-w-0">
<div class="grid lg:grid-cols-5 gap-6">
<!-- 업체 목록 (좌측) -->
<div class="lg:col-span-2">
<div class="bg-white rounded-xl shadow-sm p-5">
<div class="flex items-center justify-between mb-4">
<h2 class="text-base font-semibold text-gray-800"><i class="fas fa-building text-emerald-500 mr-2"></i>협력업체</h2>
<button onclick="openAddPartner()" class="px-3 py-1.5 bg-emerald-600 text-white rounded-lg text-xs hover:bg-emerald-700">
<i class="fas fa-plus mr-1"></i>업체 등록
</button>
</div>
<!-- 필터 -->
<div class="flex gap-2 mb-3">
<input type="text" id="partnerSearch" class="input-field flex-1 px-3 py-1.5 rounded-lg text-sm" placeholder="업체명/사업자번호 검색">
<select id="partnerFilterActive" class="input-field px-2 py-1.5 rounded-lg text-sm">
<option value="true">활성</option>
<option value="">전체</option>
<option value="false">비활성</option>
</select>
</div>
<div id="partnerList" class="space-y-2 max-h-[70vh] overflow-y-auto">
<div class="text-gray-400 text-center py-8 text-sm">로딩 중...</div>
</div>
</div>
</div>
<!-- 업체 상세 (우측) -->
<div class="lg:col-span-3">
<div id="partnerDetail" class="hidden">
<div class="bg-white rounded-xl shadow-sm p-5 mb-4">
<h3 id="detailCompanyName" class="text-lg font-semibold text-gray-800 mb-3"></h3>
<div id="detailInfo"></div>
</div>
<!-- 작업자 목록 -->
<div class="bg-white rounded-xl shadow-sm p-5">
<div class="flex items-center justify-between mb-3">
<h3 class="text-base font-semibold text-gray-800"><i class="fas fa-users text-emerald-500 mr-2"></i>소속 작업자</h3>
<button onclick="openAddWorker()" class="px-3 py-1.5 bg-emerald-600 text-white rounded-lg text-xs hover:bg-emerald-700">
<i class="fas fa-user-plus mr-1"></i>작업자 등록
</button>
</div>
<div id="workerList" class="space-y-2"></div>
</div>
</div>
<div id="partnerEmpty" class="text-center text-gray-400 py-16">
<i class="fas fa-building text-4xl mb-3"></i>
<p>업체를 선택하면 상세 정보를 볼 수 있습니다</p>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 업체 등록 모달 -->
<div id="addPartnerModal" class="hidden modal-overlay" onclick="if(event.target===this)closeAddPartner()">
<div class="modal-content p-6">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-semibold">협력업체 등록</h3>
<button onclick="closeAddPartner()" class="text-gray-400 hover:text-gray-600"><i class="fas fa-times"></i></button>
</div>
<form id="addPartnerForm">
<div class="grid grid-cols-2 gap-3">
<div class="col-span-2">
<label class="block text-xs font-medium text-gray-600 mb-1">업체명 <span class="text-red-400">*</span></label>
<input type="text" id="newCompanyName" class="input-field w-full px-3 py-2 rounded-lg text-sm" required>
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">사업자번호</label>
<input type="text" id="newBusinessNumber" class="input-field w-full px-3 py-2 rounded-lg text-sm" placeholder="000-00-00000">
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">대표자</label>
<input type="text" id="newRepresentative" class="input-field w-full px-3 py-2 rounded-lg text-sm">
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">담당자명</label>
<input type="text" id="newContactName" class="input-field w-full px-3 py-2 rounded-lg text-sm">
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">담당자 연락처</label>
<input type="text" id="newContactPhone" class="input-field w-full px-3 py-2 rounded-lg text-sm">
</div>
<div class="col-span-2">
<label class="block text-xs font-medium text-gray-600 mb-1">주소</label>
<input type="text" id="newAddress" class="input-field w-full px-3 py-2 rounded-lg text-sm">
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">업종 (콤마 구분)</label>
<input type="text" id="newBusinessType" class="input-field w-full px-3 py-2 rounded-lg text-sm" placeholder="배관, 용접">
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">산재보험 관리번호</label>
<input type="text" id="newInsuranceNumber" class="input-field w-full px-3 py-2 rounded-lg text-sm">
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">산재보험 만료일</label>
<input type="date" id="newInsuranceExpiry" class="input-field w-full px-3 py-2 rounded-lg text-sm">
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">비고</label>
<input type="text" id="newPartnerNotes" class="input-field w-full px-3 py-2 rounded-lg text-sm">
</div>
</div>
<div class="flex justify-end mt-4 gap-2">
<button type="button" onclick="closeAddPartner()" class="px-4 py-2 border rounded-lg text-sm hover:bg-gray-50">취소</button>
<button type="submit" class="px-4 py-2 bg-emerald-600 text-white rounded-lg text-sm hover:bg-emerald-700">등록</button>
</div>
</form>
</div>
</div>
<!-- 업체 수정 모달 -->
<div id="editPartnerModal" class="hidden modal-overlay" onclick="if(event.target===this)closeEditPartner()">
<div class="modal-content p-6">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-semibold">협력업체 수정</h3>
<button onclick="closeEditPartner()" class="text-gray-400 hover:text-gray-600"><i class="fas fa-times"></i></button>
</div>
<form id="editPartnerForm">
<input type="hidden" id="editPartnerId">
<div class="grid grid-cols-2 gap-3">
<div class="col-span-2">
<label class="block text-xs font-medium text-gray-600 mb-1">업체명 <span class="text-red-400">*</span></label>
<input type="text" id="editCompanyName" class="input-field w-full px-3 py-2 rounded-lg text-sm" required>
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">사업자번호</label>
<input type="text" id="editBusinessNumber" class="input-field w-full px-3 py-2 rounded-lg text-sm">
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">대표자</label>
<input type="text" id="editRepresentative" class="input-field w-full px-3 py-2 rounded-lg text-sm">
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">담당자명</label>
<input type="text" id="editContactName" class="input-field w-full px-3 py-2 rounded-lg text-sm">
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">담당자 연락처</label>
<input type="text" id="editContactPhone" class="input-field w-full px-3 py-2 rounded-lg text-sm">
</div>
<div class="col-span-2">
<label class="block text-xs font-medium text-gray-600 mb-1">주소</label>
<input type="text" id="editAddress" class="input-field w-full px-3 py-2 rounded-lg text-sm">
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">업종 (콤마 구분)</label>
<input type="text" id="editBusinessType" class="input-field w-full px-3 py-2 rounded-lg text-sm">
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">산재보험 관리번호</label>
<input type="text" id="editInsuranceNumber" class="input-field w-full px-3 py-2 rounded-lg text-sm">
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">산재보험 만료일</label>
<input type="date" id="editInsuranceExpiry" class="input-field w-full px-3 py-2 rounded-lg text-sm">
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">비고</label>
<input type="text" id="editPartnerNotes" class="input-field w-full px-3 py-2 rounded-lg text-sm">
</div>
</div>
<div class="flex justify-end mt-4 gap-2">
<button type="button" onclick="closeEditPartner()" class="px-4 py-2 border rounded-lg text-sm hover:bg-gray-50">취소</button>
<button type="submit" class="px-4 py-2 bg-emerald-600 text-white rounded-lg text-sm hover:bg-emerald-700">저장</button>
</div>
</form>
</div>
</div>
<!-- 작업자 등록 모달 -->
<div id="addWorkerModal" class="hidden modal-overlay" onclick="if(event.target===this)closeAddWorker()">
<div class="modal-content p-6">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-semibold">작업자 등록</h3>
<button onclick="closeAddWorker()" class="text-gray-400 hover:text-gray-600"><i class="fas fa-times"></i></button>
</div>
<form id="addWorkerForm">
<div class="grid grid-cols-2 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="newWorkerName" class="input-field w-full px-3 py-2 rounded-lg text-sm" required>
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">직위</label>
<input type="text" id="newWorkerPosition" class="input-field w-full px-3 py-2 rounded-lg text-sm">
</div>
<div class="flex items-end pb-1">
<label class="flex items-center gap-2 cursor-pointer">
<input type="checkbox" id="newWorkerIsLeader" class="h-4 w-4 text-emerald-500 rounded">
<span class="text-sm">팀장급</span>
</label>
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">연락처</label>
<input type="text" id="newWorkerPhone" class="input-field w-full px-3 py-2 rounded-lg text-sm" placeholder="팀장급 필수">
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">안전교육 이수일</label>
<input type="date" id="newWorkerSafetyDate" class="input-field w-full px-3 py-2 rounded-lg text-sm">
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">비고</label>
<input type="text" id="newWorkerNotes" class="input-field w-full px-3 py-2 rounded-lg text-sm">
</div>
</div>
<div class="flex justify-end mt-4 gap-2">
<button type="button" onclick="closeAddWorker()" class="px-4 py-2 border rounded-lg text-sm hover:bg-gray-50">취소</button>
<button type="submit" class="px-4 py-2 bg-emerald-600 text-white rounded-lg text-sm hover:bg-emerald-700">등록</button>
</div>
</form>
</div>
</div>
<!-- 작업자 수정 모달 -->
<div id="editWorkerModal" class="hidden modal-overlay" onclick="if(event.target===this)closeEditWorker()">
<div class="modal-content p-6">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-semibold">작업자 수정</h3>
<button onclick="closeEditWorker()" class="text-gray-400 hover:text-gray-600"><i class="fas fa-times"></i></button>
</div>
<form id="editWorkerForm">
<div class="grid grid-cols-2 gap-3">
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">성명</label>
<input type="text" id="editWorkerName" class="input-field w-full px-3 py-2 rounded-lg text-sm" required>
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">직위</label>
<input type="text" id="editWorkerPosition" class="input-field w-full px-3 py-2 rounded-lg text-sm">
</div>
<div class="flex items-end pb-1">
<label class="flex items-center gap-2 cursor-pointer">
<input type="checkbox" id="editWorkerIsLeader" class="h-4 w-4 text-emerald-500 rounded">
<span class="text-sm">팀장급</span>
</label>
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">연락처</label>
<input type="text" id="editWorkerPhone" class="input-field w-full px-3 py-2 rounded-lg text-sm">
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">안전교육 이수일</label>
<input type="date" id="editWorkerSafetyDate" class="input-field w-full px-3 py-2 rounded-lg text-sm">
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">비고</label>
<input type="text" id="editWorkerNotes" class="input-field w-full px-3 py-2 rounded-lg text-sm">
</div>
</div>
<div class="flex justify-end mt-4 gap-2">
<button type="button" onclick="closeEditWorker()" class="px-4 py-2 border rounded-lg text-sm hover:bg-gray-50">취소</button>
<button type="submit" class="px-4 py-2 bg-emerald-600 text-white rounded-lg text-sm hover:bg-emerald-700">저장</button>
</div>
</form>
</div>
</div>
<script src="/static/js/tkpurchase-core.js?v=20260312"></script>
<script src="/static/js/tkpurchase-partner.js?v=20260312"></script>
<script>initPartnerPage();</script>
</body>
</html>