feat(tkuser): 연차/휴가 관리 프론트엔드 개편 (Sprint 001 Section B)
- workers 기반 → sso_users 기반 전환 (vacWorkers→vacUsers, /workers→/users) - 휴가 탭: 부서 필터, 이름 검색, balance_type 뱃지, 장기근속 제외 체크박스 - 배정 모달: balance_type/expires_at 필드 추가, 사용자 부서별 optgroup - 부서 탭: 팀장 표시/편집, 승인권한 CRUD - 연차 설정 탭/JS 신규: 기본연차·장기근속·이월연차 설정 UI - API 미완성 대응: 필드명 폴백(worker_id→user_id), 404 graceful degradation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -72,6 +72,9 @@
|
||||
<button class="tab-btn px-4 py-2 rounded-lg text-sm font-medium whitespace-nowrap" data-tab="vacations" onclick="switchTab('vacations', event)">
|
||||
<i class="fas fa-umbrella-beach mr-2"></i>휴가
|
||||
</button>
|
||||
<button class="tab-btn px-4 py-2 rounded-lg text-sm font-medium whitespace-nowrap" data-tab="vacationSettings" onclick="switchTab('vacationSettings', event)">
|
||||
<i class="fas fa-sliders mr-2"></i>연차 설정
|
||||
</button>
|
||||
<span class="tab-divider"></span>
|
||||
<!-- 거래/물품 -->
|
||||
<span class="tab-group-label">거래</span>
|
||||
@@ -513,6 +516,13 @@
|
||||
<div id="deptMembersPanel" class="hidden mt-4 border-t pt-4">
|
||||
<h3 class="text-sm font-semibold text-gray-700 mb-3"><i class="fas fa-users text-slate-400 mr-1.5"></i>소속 인원</h3>
|
||||
<div id="deptMembersList" class="space-y-2"></div>
|
||||
<div id="deptApprovalSection" class="hidden mt-4 border-t pt-4">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<h4 class="text-sm font-semibold text-gray-700"><i class="fas fa-user-check text-slate-400 mr-1.5"></i>승인권한</h4>
|
||||
<button onclick="openApprovalModal()" class="text-xs text-slate-500 hover:text-slate-700 px-1.5 py-0.5 rounded hover:bg-gray-100" title="승인권한 추가"><i class="fas fa-plus"></i></button>
|
||||
</div>
|
||||
<div id="deptApprovalList" class="space-y-2"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -732,7 +742,11 @@
|
||||
<div class="bg-white rounded-xl shadow-sm p-5 flex flex-col flex-1 overflow-hidden">
|
||||
<div class="flex items-center justify-between mb-4 flex-wrap gap-2">
|
||||
<h2 class="text-base font-semibold text-gray-800"><i class="fas fa-calendar-check text-slate-400 mr-2"></i>연차 배정</h2>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex items-center gap-2 flex-wrap">
|
||||
<select id="vacDeptFilter" class="input-field px-3 py-1.5 rounded-lg text-sm" onchange="filterVacBalances()">
|
||||
<option value="">전체 부서</option>
|
||||
</select>
|
||||
<input type="text" id="vacSearch" class="input-field px-3 py-1.5 rounded-lg text-sm w-36" placeholder="이름 검색" oninput="filterVacBalances()">
|
||||
<select id="vacYear" class="input-field px-3 py-1.5 rounded-lg text-sm" onchange="loadVacBalances()">
|
||||
</select>
|
||||
<button onclick="autoCalcVacation()" class="px-3 py-1.5 bg-emerald-600 text-white rounded-lg hover:bg-emerald-700 text-xs font-medium" title="입사일 기반 연차 자동 계산">
|
||||
@@ -751,6 +765,15 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ============ 연차 설정 탭 ============ -->
|
||||
<div id="tab-vacationSettings" class="hidden">
|
||||
<div class="max-w-3xl mx-auto space-y-6">
|
||||
<div id="vacSettingsContent">
|
||||
<div class="text-gray-400 text-center py-8"><i class="fas fa-spinner fa-spin text-2xl"></i><p class="mt-2 text-sm">로딩 중...</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 휴가 유형 모달 -->
|
||||
<div id="vacTypeModal" class="fixed inset-0 bg-black bg-opacity-50 hidden z-50 flex items-center justify-center p-4">
|
||||
<div class="bg-white rounded-xl max-w-sm w-full p-6">
|
||||
@@ -796,8 +819,8 @@
|
||||
</div>
|
||||
|
||||
<!-- 개별 배정 모달 -->
|
||||
<div id="vacBalanceModal" class="fixed inset-0 bg-black bg-opacity-50 hidden z-50 flex items-center justify-center p-4">
|
||||
<div class="bg-white rounded-xl max-w-sm w-full p-6">
|
||||
<div id="vacBalanceModal" class="modal-overlay fixed inset-0 bg-black bg-opacity-50 hidden z-50 flex items-center justify-center p-4">
|
||||
<div class="bg-white rounded-xl max-w-md w-full p-6">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h3 id="vacBalModalTitle" class="text-base font-semibold text-gray-900">연차 배정</h3>
|
||||
<button onclick="closeVacBalanceModal()" class="text-gray-400 hover:text-gray-600"><i class="fas fa-times"></i></button>
|
||||
@@ -805,8 +828,8 @@
|
||||
<form id="vacBalanceForm" class="space-y-3">
|
||||
<input type="hidden" id="vbEditId">
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-600 mb-1">작업자 <span class="text-red-400">*</span></label>
|
||||
<select id="vbWorker" class="input-field w-full px-3 py-1.5 rounded-lg text-sm" required>
|
||||
<label class="block text-xs font-medium text-gray-600 mb-1">사용자 <span class="text-red-400">*</span></label>
|
||||
<select id="vbUser" class="input-field w-full px-3 py-1.5 rounded-lg text-sm" required>
|
||||
<option value="">선택</option>
|
||||
</select>
|
||||
</div>
|
||||
@@ -816,6 +839,16 @@
|
||||
<option value="">선택</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-600 mb-1">배정 유형</label>
|
||||
<select id="vbBalanceType" class="input-field w-full px-3 py-1.5 rounded-lg text-sm" onchange="onBalanceTypeChange()">
|
||||
<option value="AUTO">기본연차</option>
|
||||
<option value="MANUAL">추가부여</option>
|
||||
<option value="CARRY_OVER">이월연차</option>
|
||||
<option value="LONG_SERVICE">장기근속</option>
|
||||
<option value="COMPANY_GRANT">회사부여</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-600 mb-1">배정 일수</label>
|
||||
@@ -826,6 +859,10 @@
|
||||
<input type="number" id="vbUsedDays" class="input-field w-full px-3 py-1.5 rounded-lg text-sm" value="0" step="0.5" min="0">
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-600 mb-1">만료일</label>
|
||||
<input type="date" id="vbExpiresAt" class="input-field w-full px-3 py-1.5 rounded-lg text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-600 mb-1">비고</label>
|
||||
<input type="text" id="vbNotes" class="input-field w-full px-3 py-1.5 rounded-lg text-sm" placeholder="메모">
|
||||
@@ -1159,6 +1196,12 @@
|
||||
<label class="block text-xs font-medium text-gray-600 mb-1">표시순서</label>
|
||||
<input type="number" id="editDeptOrder" class="input-field w-full px-3 py-1.5 rounded-lg text-sm" min="0">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-600 mb-1">팀장</label>
|
||||
<select id="editDeptLeader" class="input-field w-full px-3 py-1.5 rounded-lg text-sm">
|
||||
<option value="">미지정</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="flex gap-3 pt-3">
|
||||
<button type="button" onclick="closeDepartmentModal()" class="flex-1 px-4 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 text-sm">취소</button>
|
||||
<button type="submit" class="flex-1 px-4 py-2 bg-slate-700 text-white rounded-lg hover:bg-slate-800 text-sm font-medium"><i class="fas fa-save mr-1"></i>저장</button>
|
||||
@@ -1167,6 +1210,42 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 승인권한 추가 모달 -->
|
||||
<div id="approvalAuthorityModal" class="modal-overlay fixed inset-0 bg-black bg-opacity-50 hidden z-50 flex items-center justify-center p-4">
|
||||
<div class="bg-white rounded-xl max-w-sm w-full p-6">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h3 class="text-base font-semibold text-gray-900">승인권한 추가</h3>
|
||||
<button onclick="closeApprovalModal()" class="text-gray-400 hover:text-gray-600"><i class="fas fa-times"></i></button>
|
||||
</div>
|
||||
<form id="approvalAuthorityForm" class="space-y-3">
|
||||
<input type="hidden" id="approvalDeptId">
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-600 mb-1">승인 유형 <span class="text-red-400">*</span></label>
|
||||
<select id="approvalType" class="input-field w-full px-3 py-1.5 rounded-lg text-sm" required>
|
||||
<option value="">선택</option>
|
||||
<option value="VACATION">휴가</option>
|
||||
<option value="PURCHASE">구매</option>
|
||||
<option value="DOCUMENT">문서</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-600 mb-1">승인자 <span class="text-red-400">*</span></label>
|
||||
<select id="approvalUserId" class="input-field w-full px-3 py-1.5 rounded-lg text-sm" required>
|
||||
<option value="">선택</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-600 mb-1">순서</label>
|
||||
<input type="number" id="approvalOrder" class="input-field w-full px-3 py-1.5 rounded-lg text-sm" value="1" min="1">
|
||||
</div>
|
||||
<div class="flex gap-3 pt-2">
|
||||
<button type="button" onclick="closeApprovalModal()" class="flex-1 px-4 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 text-sm">취소</button>
|
||||
<button type="submit" class="flex-1 px-4 py-2 bg-slate-700 text-white rounded-lg hover:bg-slate-800 text-sm font-medium"><i class="fas fa-save mr-1"></i>저장</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 이슈 카테고리 수정 모달 -->
|
||||
<div id="editIssueCategoryModal" class="fixed inset-0 bg-black bg-opacity-50 hidden z-50 flex items-center justify-center p-4">
|
||||
<div class="bg-white rounded-xl max-w-md w-full p-6">
|
||||
@@ -2239,17 +2318,18 @@
|
||||
</div>
|
||||
|
||||
<!-- JS: Core (config, token, api, toast, helpers, init) -->
|
||||
<script src="/static/js/tkuser-core.js?v=2026031602"></script>
|
||||
<script src="/static/js/tkuser-core.js?v=2026032301"></script>
|
||||
<!-- JS: Tabs -->
|
||||
<script src="/static/js/tkuser-tabs.js?v=2026031602"></script>
|
||||
<script src="/static/js/tkuser-tabs.js?v=2026032301"></script>
|
||||
<!-- JS: Individual modules -->
|
||||
<script src="/static/js/tkuser-users.js?v=2026031601"></script>
|
||||
<script src="/static/js/tkuser-users.js?v=2026032301"></script>
|
||||
<script src="/static/js/tkuser-projects.js?v=2026031401"></script>
|
||||
<script src="/static/js/tkuser-departments.js?v=2026031401"></script>
|
||||
<script src="/static/js/tkuser-departments.js?v=2026032301"></script>
|
||||
<script src="/static/js/tkuser-issue-types.js?v=2026031401"></script>
|
||||
<script src="/static/js/tkuser-workplaces.js?v=2026031401"></script>
|
||||
<script src="/static/js/tkuser-tasks.js?v=2026031401"></script>
|
||||
<script src="/static/js/tkuser-vacations.js?v=2026031401"></script>
|
||||
<script src="/static/js/tkuser-vacations.js?v=2026032301"></script>
|
||||
<script src="/static/js/tkuser-vacation-settings.js?v=2026032301"></script>
|
||||
<script src="/static/js/tkuser-layout-map.js?v=2026031401"></script>
|
||||
<script src="/static/js/tkuser-partners.js?v=2026031601"></script>
|
||||
<script src="/static/js/tkuser-vendors.js?v=2026031401"></script>
|
||||
|
||||
Reference in New Issue
Block a user