feat(purchase): 생산소모품 구매 관리 시스템 구현
tkuser: 업체(공급업체) CRUD + 소모품 마스터 CRUD (사진 업로드 포함) tkfb: 구매신청 → 구매 처리 → 월간 분석/정산 전체 워크플로 설비(equipment) 분류 구매 시 자동 등록 + 실패 시 admin 알림 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
181
system1-factory/web/pages/purchase/request.html
Normal file
181
system1-factory/web/pages/purchase/request.html
Normal file
@@ -0,0 +1,181 @@
|
||||
<!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/tkfb.css">
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
<header class="bg-orange-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">
|
||||
<button id="mobileMenuBtn" class="lg:hidden text-orange-200 hover:text-white"><i class="fas fa-bars text-xl"></i></button>
|
||||
<i class="fas fa-industry text-xl text-orange-200"></i>
|
||||
<h1 class="text-lg font-semibold">TK 공장관리</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<span id="headerUserName" class="text-sm hidden sm:block">-</span>
|
||||
<div id="headerUserAvatar" class="w-8 h-8 bg-orange-600 rounded-full flex items-center justify-center text-sm font-bold">-</div>
|
||||
<button onclick="doLogout()" class="text-orange-200 hover:text-white" title="로그아웃"><i class="fas fa-sign-out-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="mobileOverlay" class="hidden fixed inset-0 bg-black/50 z-30 lg:hidden"></div>
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 fade-in">
|
||||
<div class="flex gap-6">
|
||||
<nav id="sideNav" class="hidden lg:flex flex-col gap-1 w-52 flex-shrink-0 pt-2 fixed lg:static z-40 bg-white lg:bg-transparent p-4 lg:p-0 rounded-lg lg:rounded-none shadow-lg lg:shadow-none top-14 left-0 bottom-0 overflow-y-auto"></nav>
|
||||
<div class="flex-1 min-w-0">
|
||||
|
||||
<div class="page-header">
|
||||
<div class="page-title-section">
|
||||
<h1 class="page-title">구매신청</h1>
|
||||
<p class="page-description">생산소모품 구매를 신청하고 처리 현황을 확인합니다</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 구매신청 폼 -->
|
||||
<div class="bg-white rounded-xl shadow-sm p-5 mb-6">
|
||||
<h2 class="text-base font-semibold text-gray-800 mb-4"><i class="fas fa-plus-circle text-orange-500 mr-2"></i>신규 구매신청</h2>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-4 gap-4 items-end">
|
||||
<div class="sm:col-span-2">
|
||||
<label class="block text-xs font-medium text-gray-600 mb-1">소모품 <span class="text-red-400">*</span></label>
|
||||
<select id="prItemSelect" class="w-full px-3 py-2 border rounded-lg text-sm focus:ring-2 focus:ring-orange-300" onchange="onItemSelect()">
|
||||
<option value="">소모품 선택</option>
|
||||
</select>
|
||||
<div id="prItemPreview" class="mt-2 hidden flex items-center gap-3 p-2 bg-gray-50 rounded-lg">
|
||||
<img id="prItemPhoto" class="w-12 h-12 rounded object-cover hidden">
|
||||
<div>
|
||||
<div id="prItemInfo" class="text-sm text-gray-700"></div>
|
||||
<div id="prItemPrice" class="text-xs text-gray-500"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-600 mb-1">수량 <span class="text-red-400">*</span></label>
|
||||
<input type="number" id="prQuantity" class="w-full px-3 py-2 border rounded-lg text-sm" min="1" value="1">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-600 mb-1">메모</label>
|
||||
<input type="text" id="prNotes" class="w-full px-3 py-2 border rounded-lg text-sm" placeholder="선택 사항">
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 flex justify-end">
|
||||
<button onclick="submitPurchaseRequest()" class="px-5 py-2 bg-orange-600 text-white rounded-lg text-sm hover:bg-orange-700">
|
||||
<i class="fas fa-paper-plane mr-1"></i>구매신청
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 필터 -->
|
||||
<div class="flex gap-3 mb-4 flex-wrap items-center">
|
||||
<select id="prFilterStatus" class="px-3 py-2 border rounded-lg text-sm" onchange="loadRequests()">
|
||||
<option value="">전체 상태</option>
|
||||
<option value="pending">대기</option>
|
||||
<option value="purchased">구매완료</option>
|
||||
<option value="hold">보류</option>
|
||||
</select>
|
||||
<select id="prFilterCategory" class="px-3 py-2 border rounded-lg text-sm" onchange="loadRequests()">
|
||||
<option value="">전체 분류</option>
|
||||
<option value="consumable">소모품</option>
|
||||
<option value="safety">안전용품</option>
|
||||
<option value="repair">수선비</option>
|
||||
<option value="equipment">설비</option>
|
||||
</select>
|
||||
<button onclick="loadRequests()" class="px-3 py-2 border rounded-lg text-sm text-gray-600 hover:bg-gray-100">
|
||||
<i class="fas fa-sync-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 신청 목록 -->
|
||||
<div class="bg-white rounded-xl shadow-sm overflow-hidden">
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full text-sm">
|
||||
<thead class="bg-gray-50 text-gray-600 text-xs uppercase">
|
||||
<tr>
|
||||
<th class="px-4 py-3 text-left">품목</th>
|
||||
<th class="px-4 py-3 text-left">분류</th>
|
||||
<th class="px-4 py-3 text-right">수량</th>
|
||||
<th class="px-4 py-3 text-left">신청자</th>
|
||||
<th class="px-4 py-3 text-left">신청일</th>
|
||||
<th class="px-4 py-3 text-center">상태</th>
|
||||
<th class="px-4 py-3 text-center">액션</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="prRequestList" class="divide-y">
|
||||
<tr><td colspan="7" class="px-4 py-8 text-center text-gray-400">데이터를 불러오는 중...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 구매 처리 모달 -->
|
||||
<div id="purchaseModal" class="hidden fixed inset-0 bg-black/40 z-50 flex items-center justify-center p-4" onclick="if(event.target===this)closePurchaseModal()">
|
||||
<div class="bg-white rounded-xl shadow-xl max-w-lg w-full p-6">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h3 class="text-lg font-semibold">구매 처리</h3>
|
||||
<button onclick="closePurchaseModal()" class="text-gray-400 hover:text-gray-600"><i class="fas fa-times"></i></button>
|
||||
</div>
|
||||
<div id="purchaseModalInfo" class="bg-gray-50 rounded-lg p-3 mb-4 text-sm"></div>
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-600 mb-1">업체</label>
|
||||
<select id="pmVendor" class="w-full px-3 py-2 border 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>
|
||||
<input type="date" id="pmDate" class="w-full px-3 py-2 border rounded-lg text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-600 mb-1">실구매 단가 <span class="text-red-400">*</span></label>
|
||||
<input type="number" id="pmUnitPrice" class="w-full px-3 py-2 border rounded-lg text-sm" min="0" oninput="showPriceDiff()">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-600 mb-1">수량</label>
|
||||
<input type="number" id="pmQuantity" class="w-full px-3 py-2 border rounded-lg text-sm" min="1" value="1">
|
||||
</div>
|
||||
<div class="col-span-2" id="pmPriceDiffArea" class="hidden">
|
||||
</div>
|
||||
<div class="col-span-2">
|
||||
<label class="block text-xs font-medium text-gray-600 mb-1">메모</label>
|
||||
<input type="text" id="pmNotes" class="w-full px-3 py-2 border rounded-lg text-sm">
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end mt-4 gap-2">
|
||||
<button type="button" onclick="closePurchaseModal()" class="px-4 py-2 border rounded-lg text-sm hover:bg-gray-50">취소</button>
|
||||
<button type="button" onclick="submitPurchase()" class="px-4 py-2 bg-orange-600 text-white rounded-lg text-sm hover:bg-orange-700">구매 완료</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 보류 모달 -->
|
||||
<div id="holdModal" class="hidden fixed inset-0 bg-black/40 z-50 flex items-center justify-center p-4" onclick="if(event.target===this)closeHoldModal()">
|
||||
<div class="bg-white rounded-xl shadow-xl max-w-md w-full p-6">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h3 class="text-lg font-semibold">보류 처리</h3>
|
||||
<button onclick="closeHoldModal()" class="text-gray-400 hover:text-gray-600"><i class="fas fa-times"></i></button>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-600 mb-1">보류 사유</label>
|
||||
<textarea id="holdReason" rows="3" class="w-full px-3 py-2 border rounded-lg text-sm" placeholder="보류 사유를 입력하세요"></textarea>
|
||||
</div>
|
||||
<div class="flex justify-end mt-4 gap-2">
|
||||
<button type="button" onclick="closeHoldModal()" class="px-4 py-2 border rounded-lg text-sm hover:bg-gray-50">취소</button>
|
||||
<button type="button" onclick="submitHold()" class="px-4 py-2 bg-gray-600 text-white rounded-lg text-sm hover:bg-gray-700">보류</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/static/js/tkfb-core.js?v=20260313"></script>
|
||||
<script src="/static/js/purchase-request.js?v=20260313"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user