feat: [employee] 개인정보(주민번호, 급여이체, 부양가족)를 연봉정보 섹션으로 이동

- 주민등록번호, 급여이체정보, 부양가족을 특수 관리자 전용 섹션으로 이동
- 연봉 정보 → 개인정보 및 연봉정보로 문구 변경
- form="employeeForm" 속성으로 폼 외부 입력필드 연동
This commit is contained in:
김보곤
2026-03-16 21:53:30 +09:00
parent a70a3f5b8b
commit 48d9d72fa8
3 changed files with 532 additions and 534 deletions

View File

@@ -67,22 +67,12 @@ class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:rin
</div>
</div>
{{-- 주민등록번호 / 연락처 --}}
<div class="flex gap-4" style="flex-wrap: wrap;">
<div style="flex: 1 1 200px;">
<label for="resident_number" class="block text-sm font-medium text-gray-700 mb-1">주민등록번호</label>
<input type="text" name="resident_number" id="resident_number"
value="{{ $employee->resident_number }}"
placeholder="000000-0000000"
maxlength="14"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
</div>
<div style="flex: 1 1 200px;">
<label for="phone" class="block text-sm font-medium text-gray-700 mb-1">연락처</label>
<input type="text" name="phone" id="phone"
value="{{ $employee->user?->phone }}"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
</div>
{{-- 연락처 --}}
<div>
<label for="phone" class="block text-sm font-medium text-gray-700 mb-1">연락처</label>
<input type="text" name="phone" id="phone"
value="{{ $employee->user?->phone }}"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
</div>
{{-- 근무 정보 --}}
@@ -201,112 +191,6 @@ class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:rin
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
</div>
{{-- 급여이체정보 --}}
<div class="border-b border-gray-200 pb-4 mb-4 mt-8">
<h2 class="text-lg font-semibold text-gray-700">급여이체정보</h2>
</div>
@php $bankAccount = $employee->bank_account ?? []; @endphp
<div>
<label for="bank_account_bank_code" class="block text-sm font-medium text-gray-700 mb-1">이체은행</label>
<select name="bank_account[bank_code]" id="bank_account_bank_code"
onchange="this.form['bank_account[bank_name]'].value = this.options[this.selectedIndex].text !== '선택하세요' ? this.options[this.selectedIndex].text : ''"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<option value="">선택하세요</option>
@foreach(config('banks', []) as $code => $name)
<option value="{{ $code }}" {{ ($bankAccount['bank_code'] ?? '') === $code ? 'selected' : '' }}>{{ $name }}</option>
@endforeach
</select>
<input type="hidden" name="bank_account[bank_name]" value="{{ $bankAccount['bank_name'] ?? '' }}">
</div>
<div class="flex gap-4" style="flex-wrap: wrap;">
<div style="flex: 1 1 200px;">
<label for="bank_account_account_holder" class="block text-sm font-medium text-gray-700 mb-1">예금주</label>
<input type="text" name="bank_account[account_holder]" id="bank_account_account_holder"
value="{{ $bankAccount['account_holder'] ?? '' }}"
placeholder="예금주명"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
</div>
<div style="flex: 1 1 200px;">
<label for="bank_account_account_number" class="block text-sm font-medium text-gray-700 mb-1">계좌번호</label>
<input type="text" name="bank_account[account_number]" id="bank_account_account_number"
value="{{ $bankAccount['account_number'] ?? '' }}"
placeholder="숫자만 입력"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
</div>
</div>
{{-- 부양가족 정보 --}}
<div class="border-b border-gray-200 pb-4 mb-4 mt-8">
<h2 class="text-lg font-semibold text-gray-700">부양가족 정보</h2>
</div>
<div x-data="dependentsManager()">
{{-- 부양가족 전체 삭제 시에도 서버에 전달되도록 마커 --}}
<input type="hidden" name="dependents_submitted" value="1">
<template x-for="(dep, index) in dependents" :key="index">
<div class="border border-gray-200 rounded-lg p-4 mb-3 relative">
<button type="button" @click="removeDependent(index)"
class="absolute top-2 right-2 text-red-400 hover:text-red-600 transition-colors" title="삭제">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
<div class="text-xs font-medium text-gray-500 mb-2" x-text="'부양가족 ' + (index + 1)"></div>
<div class="flex gap-3 mb-2" style="flex-wrap: wrap;">
<div style="flex: 1 1 120px;">
<input type="text" :name="'dependents['+index+'][name]'" x-model="dep.name"
placeholder="이름" class="w-full px-2 py-1.5 border border-gray-300 rounded text-sm focus:ring-1 focus:ring-blue-500">
</div>
<div style="flex: 0 0 100px;">
<select :name="'dependents['+index+'][nationality]'" x-model="dep.nationality"
class="w-full px-2 py-1.5 border border-gray-300 rounded text-sm focus:ring-1 focus:ring-blue-500">
<option value="korean">내국인</option>
<option value="foreigner">외국인</option>
</select>
</div>
<div style="flex: 1 1 150px;">
<input type="text" :name="'dependents['+index+'][resident_number]'" x-model="dep.resident_number"
placeholder="주민등록번호" maxlength="14" class="w-full px-2 py-1.5 border border-gray-300 rounded text-sm focus:ring-1 focus:ring-blue-500">
</div>
</div>
<div class="flex gap-3 items-center" style="flex-wrap: wrap;">
<div style="flex: 0 0 100px;">
<select :name="'dependents['+index+'][relationship]'" x-model="dep.relationship"
class="w-full px-2 py-1.5 border border-gray-300 rounded text-sm focus:ring-1 focus:ring-blue-500">
<option value="">관계</option>
<option value="spouse">배우자</option>
<option value="child">자녀</option>
<option value="parent">부모</option>
<option value="sibling">형제자매</option>
<option value="grandparent">조부모</option>
<option value="other">기타</option>
</select>
</div>
<label class="inline-flex items-center gap-1 text-sm text-gray-600 cursor-pointer">
<input type="hidden" :name="'dependents['+index+'][is_disabled]'" value="0">
<input type="checkbox" :name="'dependents['+index+'][is_disabled]'" x-model="dep.is_disabled"
value="1" class="rounded border-gray-300 text-blue-600 focus:ring-blue-500">
장애인
</label>
<label class="inline-flex items-center gap-1 text-sm text-gray-600 cursor-pointer">
<input type="hidden" :name="'dependents['+index+'][is_dependent]'" value="0">
<input type="checkbox" :name="'dependents['+index+'][is_dependent]'" x-model="dep.is_dependent"
value="1" class="rounded border-gray-300 text-blue-600 focus:ring-blue-500">
피부양자적용
</label>
</div>
</div>
</template>
<button type="button" @click="addDependent()"
class="w-full py-2 border-2 border-dashed border-gray-300 rounded-lg text-sm text-gray-500 hover:border-blue-400 hover:text-blue-600 transition-colors">
+ 부양가족 추가
</button>
</div>
{{-- 버튼 --}}
<div class="flex justify-end gap-3 pt-4 border-t mt-6">
<a href="{{ route('hr.employees.show', $employee->id) }}"
@@ -372,9 +256,9 @@ class="text-red-400 hover:text-red-600 shrink-0 ml-2" title="삭제">
<div x-show="uploading" class="mt-3 text-sm text-blue-600">업로드 ...</div>
</div>
{{-- 연봉 정보 (특수 권한 사용자만 표시) --}}
{{-- 개인정보 연봉정보 (특수 권한 사용자만 표시) --}}
@if($canViewSalary)
@include('hr.employees.partials.salary-info')
@include('hr.employees.partials.salary-info', ['editMode' => true])
@endif
</div>
@@ -384,25 +268,6 @@ class="text-red-400 hover:text-red-600 shrink-0 ml-2" title="삭제">
@push('scripts')
<script>
function dependentsManager() {
return {
dependents: (@json($employee->dependents ?? [])).map(dep => ({
...dep,
is_disabled: !!(dep.is_disabled && dep.is_disabled !== '0' && dep.is_disabled !== 0),
is_dependent: !!(dep.is_dependent && dep.is_dependent !== '0' && dep.is_dependent !== 0),
})),
addDependent() {
this.dependents.push({
name: '', nationality: 'korean', resident_number: '',
relationship: '', is_disabled: false, is_dependent: false
});
},
removeDependent(index) {
this.dependents.splice(index, 1);
}
};
}
function fileUploader() {
return {
dragover: false,

View File

@@ -1,136 +1,525 @@
{{-- 연봉 정보 섹션 (특수 권한 사용자만 표시) --}}
<div class="bg-white rounded-lg shadow-sm overflow-hidden mt-6" x-data="salaryManager()">
{{-- 개인정보 연봉정보 섹션 (특수 권한 사용자만 표시) --}}
@php $isEditMode = $editMode ?? false; @endphp
<div class="bg-white rounded-lg shadow-sm overflow-hidden mt-6">
{{-- 헤더 --}}
<div class="px-6 py-4 border-b border-gray-200 bg-amber-50 flex items-center justify-between">
<div class="flex items-center gap-2">
<svg class="w-5 h-5 text-amber-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16.5 10.5V6.75a4.5 4.5 0 1 0-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 0 0 2.25-2.25v-6.75a2.25 2.25 0 0 0-2.25-2.25H6.75a2.25 2.25 0 0 0-2.25 2.25v6.75a2.25 2.25 0 0 0 2.25 2.25Z"/>
</svg>
<h3 class="text-lg font-semibold text-gray-800">연봉 정보</h3>
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-amber-100 text-amber-700">제한 열람</span>
</div>
<button type="button" @click="editing = !editing"
class="inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-lg transition-colors"
:class="editing ? 'bg-gray-200 text-gray-700 hover:bg-gray-300' : 'bg-blue-600 text-white hover:bg-blue-700'">
<template x-if="!editing">
<span class="flex items-center gap-1">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/>
</svg>
수정
</span>
</template>
<template x-if="editing">
<span>취소</span>
</template>
</button>
<div class="px-6 py-4 border-b border-gray-200 bg-amber-50 flex items-center gap-2">
<svg class="w-5 h-5 text-amber-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16.5 10.5V6.75a4.5 4.5 0 1 0-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 0 0 2.25-2.25v-6.75a2.25 2.25 0 0 0-2.25-2.25H6.75a2.25 2.25 0 0 0-2.25 2.25v6.75a2.25 2.25 0 0 0 2.25 2.25Z"/>
</svg>
<h3 class="text-lg font-semibold text-gray-800">개인정보 연봉정보</h3>
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-amber-100 text-amber-700">제한 열람</span>
</div>
{{-- ============================================================ --}}
{{-- 조회 모드 --}}
{{-- 개인정보 (주민번호, 급여이체정보, 부양가족) --}}
{{-- ============================================================ --}}
<div x-show="!editing">
{{-- 기본 연봉 정보 --}}
@if($isEditMode)
{{-- 편집 모드 --}}
<div class="p-6 space-y-6 border-b border-gray-200">
{{-- 주민등록번호 --}}
<div>
<label for="resident_number" class="block text-sm font-medium text-gray-700 mb-1">주민등록번호</label>
<input type="text" name="resident_number" id="resident_number" form="employeeForm"
value="{{ $employee->resident_number }}"
placeholder="000000-0000000"
maxlength="14"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
</div>
{{-- 급여이체정보 --}}
<div class="border-b border-gray-200 pb-4 mt-4">
<h2 class="text-base font-semibold text-gray-700">급여이체정보</h2>
</div>
@php $bankAccount = $employee->bank_account ?? []; @endphp
<div>
<label for="bank_account_bank_code" class="block text-sm font-medium text-gray-700 mb-1">이체은행</label>
<select name="bank_account[bank_code]" id="bank_account_bank_code" form="employeeForm"
onchange="document.querySelector('input[name=\'bank_account[bank_name]\'][form=\'employeeForm\']').value = this.options[this.selectedIndex].text !== '선택하세요' ? this.options[this.selectedIndex].text : ''"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<option value="">선택하세요</option>
@foreach(config('banks', []) as $code => $name)
<option value="{{ $code }}" {{ ($bankAccount['bank_code'] ?? '') === $code ? 'selected' : '' }}>{{ $name }}</option>
@endforeach
</select>
<input type="hidden" name="bank_account[bank_name]" form="employeeForm" value="{{ $bankAccount['bank_name'] ?? '' }}">
</div>
<div class="flex gap-4" style="flex-wrap: wrap;">
<div style="flex: 1 1 200px;">
<label for="bank_account_account_holder" class="block text-sm font-medium text-gray-700 mb-1">예금주</label>
<input type="text" name="bank_account[account_holder]" id="bank_account_account_holder" form="employeeForm"
value="{{ $bankAccount['account_holder'] ?? '' }}"
placeholder="예금주명"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
</div>
<div style="flex: 1 1 200px;">
<label for="bank_account_account_number" class="block text-sm font-medium text-gray-700 mb-1">계좌번호</label>
<input type="text" name="bank_account[account_number]" id="bank_account_account_number" form="employeeForm"
value="{{ $bankAccount['account_number'] ?? '' }}"
placeholder="숫자만 입력"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
</div>
</div>
{{-- 부양가족 정보 --}}
<div class="border-b border-gray-200 pb-4 mt-4">
<h2 class="text-base font-semibold text-gray-700">부양가족 정보</h2>
</div>
<div x-data="dependentsManager()">
<input type="hidden" name="dependents_submitted" value="1" form="employeeForm">
<template x-for="(dep, index) in dependents" :key="index">
<div class="border border-gray-200 rounded-lg p-4 mb-3 relative">
<button type="button" @click="removeDependent(index)"
class="absolute top-2 right-2 text-red-400 hover:text-red-600 transition-colors" title="삭제">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
<div class="text-xs font-medium text-gray-500 mb-2" x-text="'부양가족 ' + (index + 1)"></div>
<div class="flex gap-3 mb-2" style="flex-wrap: wrap;">
<div style="flex: 1 1 120px;">
<input type="text" :name="'dependents['+index+'][name]'" x-model="dep.name" form="employeeForm"
placeholder="이름" class="w-full px-2 py-1.5 border border-gray-300 rounded text-sm focus:ring-1 focus:ring-blue-500">
</div>
<div style="flex: 0 0 100px;">
<select :name="'dependents['+index+'][nationality]'" x-model="dep.nationality" form="employeeForm"
class="w-full px-2 py-1.5 border border-gray-300 rounded text-sm focus:ring-1 focus:ring-blue-500">
<option value="korean">내국인</option>
<option value="foreigner">외국인</option>
</select>
</div>
<div style="flex: 1 1 150px;">
<input type="text" :name="'dependents['+index+'][resident_number]'" x-model="dep.resident_number" form="employeeForm"
placeholder="주민등록번호" maxlength="14" class="w-full px-2 py-1.5 border border-gray-300 rounded text-sm focus:ring-1 focus:ring-blue-500">
</div>
</div>
<div class="flex gap-3 items-center" style="flex-wrap: wrap;">
<div style="flex: 0 0 100px;">
<select :name="'dependents['+index+'][relationship]'" x-model="dep.relationship" form="employeeForm"
class="w-full px-2 py-1.5 border border-gray-300 rounded text-sm focus:ring-1 focus:ring-blue-500">
<option value="">관계</option>
<option value="spouse">배우자</option>
<option value="child">자녀</option>
<option value="parent">부모</option>
<option value="sibling">형제자매</option>
<option value="grandparent">조부모</option>
<option value="other">기타</option>
</select>
</div>
<label class="inline-flex items-center gap-1 text-sm text-gray-600 cursor-pointer">
<input type="hidden" :name="'dependents['+index+'][is_disabled]'" value="0" form="employeeForm">
<input type="checkbox" :name="'dependents['+index+'][is_disabled]'" x-model="dep.is_disabled" form="employeeForm"
value="1" class="rounded border-gray-300 text-blue-600 focus:ring-blue-500">
장애인
</label>
<label class="inline-flex items-center gap-1 text-sm text-gray-600 cursor-pointer">
<input type="hidden" :name="'dependents['+index+'][is_dependent]'" value="0" form="employeeForm">
<input type="checkbox" :name="'dependents['+index+'][is_dependent]'" x-model="dep.is_dependent" form="employeeForm"
value="1" class="rounded border-gray-300 text-blue-600 focus:ring-blue-500">
피부양자적용
</label>
</div>
</div>
</template>
<button type="button" @click="addDependent()"
class="w-full py-2 border-2 border-dashed border-gray-300 rounded-lg text-sm text-gray-500 hover:border-blue-400 hover:text-blue-600 transition-colors">
+ 부양가족 추가
</button>
</div>
</div>
@else
{{-- 조회 모드 --}}
<div class="divide-y divide-gray-100">
<div class="px-6 py-3 flex" style="flex-wrap: wrap;">
<div class="shrink-0 text-sm font-medium text-gray-500" style="width: 140px;">연봉</div>
<div class="text-sm text-gray-900 font-semibold">
<template x-if="salaryData.annual_salary">
<span x-text="Number(salaryData.annual_salary).toLocaleString() + '원'"></span>
</template>
<template x-if="!salaryData.annual_salary">
<span class="text-gray-400 font-normal">미입력</span>
</template>
<div class="shrink-0 text-sm font-medium text-gray-500" style="width: 140px;">주민등록번호</div>
<div class="text-sm text-gray-900">
@if($employee->resident_number)
{{ Str::mask($employee->resident_number, '*', 8) }}
@else
-
@endif
</div>
</div>
{{-- 급여이체정보 --}}
<div class="px-6 py-4 bg-gray-50">
<span class="text-sm font-semibold text-gray-600">급여이체정보</span>
</div>
@php $bankAccount = $employee->bank_account ?? []; @endphp
<div class="px-6 py-3 flex" style="flex-wrap: wrap;">
<div class="shrink-0 text-sm font-medium text-gray-500" style="width: 140px;">적용일</div>
<div class="text-sm text-gray-900" x-text="salaryData.effective_date || '-'"></div>
<div class="shrink-0 text-sm font-medium text-gray-500" style="width: 140px;">이체은행</div>
<div class="text-sm text-gray-900">{{ $bankAccount['bank_name'] ?? '-' }}</div>
</div>
<div class="px-6 py-3 flex" style="flex-wrap: wrap;">
<div class="shrink-0 text-sm font-medium text-gray-500" style="width: 140px;">비고</div>
<div class="text-sm text-gray-900" x-text="salaryData.notes || '-'"></div>
<div class="shrink-0 text-sm font-medium text-gray-500" style="width: 140px;">예금주</div>
<div class="text-sm text-gray-900">{{ $bankAccount['account_holder'] ?? '-' }}</div>
</div>
<div class="px-6 py-3 flex" style="flex-wrap: wrap;">
<div class="shrink-0 text-sm font-medium text-gray-500" style="width: 140px;">계좌번호</div>
<div class="text-sm text-gray-900">{{ $bankAccount['account_number'] ?? '-' }}</div>
</div>
{{-- 부양가족 정보 --}}
<div class="px-6 py-4 bg-gray-50">
<span class="text-sm font-semibold text-gray-600">부양가족 정보</span>
</div>
@php $dependents = $employee->dependents ?? []; @endphp
@if(count($dependents) > 0)
<div class="px-6 py-3">
<div class="overflow-x-auto">
<table class="w-full text-sm">
<thead>
<tr class="border-b border-gray-200 text-gray-500">
<th class="text-left py-2 pr-3 font-medium">이름</th>
<th class="text-left py-2 pr-3 font-medium">/외국인</th>
<th class="text-left py-2 pr-3 font-medium">주민등록번호</th>
<th class="text-left py-2 pr-3 font-medium">관계</th>
<th class="text-left py-2 pr-3 font-medium">장애인</th>
<th class="text-left py-2 font-medium">피부양자</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-100">
@foreach($dependents as $dep)
<tr class="text-gray-900">
<td class="py-2 pr-3">{{ $dep['name'] ?? '-' }}</td>
<td class="py-2 pr-3">{{ ($dep['nationality'] ?? 'korean') === 'korean' ? '내국인' : '외국인' }}</td>
<td class="py-2 pr-3">
@if(!empty($dep['resident_number']))
{{ Str::mask($dep['resident_number'], '*', 8) }}
@else
-
@endif
</td>
<td class="py-2 pr-3">
@switch($dep['relationship'] ?? '')
@case('spouse') 배우자 @break
@case('child') 자녀 @break
@case('parent') 부모 @break
@case('sibling') 형제자매 @break
@case('grandparent') 조부모 @break
@case('other') 기타 @break
@default - @break
@endswitch
</td>
<td class="py-2 pr-3">{{ filter_var($dep['is_disabled'] ?? false, FILTER_VALIDATE_BOOLEAN) ? 'Y' : 'N' }}</td>
<td class="py-2">{{ filter_var($dep['is_dependent'] ?? false, FILTER_VALIDATE_BOOLEAN) ? 'Y' : 'N' }}</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
@else
<div class="px-6 py-3">
<p class="text-sm text-gray-400">등록된 부양가족이 없습니다.</p>
</div>
@endif
</div>
@endif
{{-- ============================================================ --}}
{{-- 연봉정보 --}}
{{-- ============================================================ --}}
<div x-data="salaryManager()">
{{-- 연봉 헤더 + 수정 버튼 --}}
<div class="px-6 py-4 border-t border-gray-200 bg-gray-50 flex items-center justify-between">
<span class="text-sm font-semibold text-gray-600">연봉정보</span>
<button type="button" @click="editing = !editing"
class="inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-lg transition-colors"
:class="editing ? 'bg-gray-200 text-gray-700 hover:bg-gray-300' : 'bg-blue-600 text-white hover:bg-blue-700'">
<template x-if="!editing">
<span class="flex items-center gap-1">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/>
</svg>
수정
</span>
</template>
<template x-if="editing">
<span>취소</span>
</template>
</button>
</div>
{{-- 조회 모드 --}}
<div x-show="!editing">
<div class="divide-y divide-gray-100">
<div class="px-6 py-3 flex" style="flex-wrap: wrap;">
<div class="shrink-0 text-sm font-medium text-gray-500" style="width: 140px;">연봉</div>
<div class="text-sm text-gray-900 font-semibold">
<template x-if="salaryData.annual_salary">
<span x-text="Number(salaryData.annual_salary).toLocaleString() + '원'"></span>
</template>
<template x-if="!salaryData.annual_salary">
<span class="text-gray-400 font-normal">미입력</span>
</template>
</div>
</div>
<div class="px-6 py-3 flex" style="flex-wrap: wrap;">
<div class="shrink-0 text-sm font-medium text-gray-500" style="width: 140px;">적용일</div>
<div class="text-sm text-gray-900" x-text="salaryData.effective_date || '-'"></div>
</div>
<div class="px-6 py-3 flex" style="flex-wrap: wrap;">
<div class="shrink-0 text-sm font-medium text-gray-500" style="width: 140px;">비고</div>
<div class="text-sm text-gray-900" x-text="salaryData.notes || '-'"></div>
</div>
</div>
{{-- 급여 산정 테이블 (저장된 데이터가 있을 ) --}}
<template x-if="salaryData.annual_salary && salaryData.fixed_overtime_hours != null">
<div class="border-t border-gray-200">
<div class="px-6 py-3 bg-blue-50">
<span class="text-sm font-semibold text-blue-700">급여 산정 내역</span>
</div>
<div class="px-6 pt-4">
<div class="overflow-x-auto">
<table class="w-full text-sm border border-gray-300">
<thead>
<tr class="bg-gray-100 text-gray-600">
<th class="border border-gray-300 px-3 py-2 text-center font-medium">총급여(연봉)</th>
<th class="border border-gray-300 px-3 py-2 text-center font-medium">기본급</th>
<th class="border border-gray-300 px-3 py-2 text-center font-medium">식대</th>
<th class="border border-gray-300 px-3 py-2 text-center font-medium">고정연장근로수당</th>
<th class="border border-gray-300 px-3 py-2 text-center font-medium bg-blue-50">합계()</th>
</tr>
</thead>
<tbody>
<tr class="text-gray-900">
<td class="border border-gray-300 px-3 py-2 text-right" x-text="Number(salaryData.annual_salary).toLocaleString()"></td>
<td class="border border-gray-300 px-3 py-2 text-right font-medium" x-text="Number(salaryData.base_salary || 0).toLocaleString()"></td>
<td class="border border-gray-300 px-3 py-2 text-right" x-text="Number(salaryData.meal_allowance || 200000).toLocaleString()"></td>
<td class="border border-gray-300 px-3 py-2 text-right font-medium" x-text="Number(salaryData.fixed_overtime_pay || 0).toLocaleString()"></td>
<td class="border border-gray-300 px-3 py-2 text-right font-bold bg-blue-50" x-text="Number(salaryData.monthly_salary || 0).toLocaleString()"></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="px-6 py-4">
<div class="overflow-x-auto">
<table class="w-full text-sm border border-gray-300">
<tbody>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700" style="width: 170px;">월급여</td>
<td class="border border-gray-300 px-3 py-2 text-right" style="width: 130px;" x-text="Number(salaryData.monthly_salary || 0).toLocaleString()"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs"></td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700">기본급</td>
<td class="border border-gray-300 px-3 py-2 text-right" x-text="Number(salaryData.base_salary || 0).toLocaleString()"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs"></td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700">식대</td>
<td class="border border-gray-300 px-3 py-2 text-right" x-text="Number(salaryData.meal_allowance || 200000).toLocaleString()"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs">고정값</td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700"> 근로시간</td>
<td class="border border-gray-300 px-3 py-2 text-right" x-text="salaryData.monthly_work_hours || 209"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs">고정값</td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700"> 고정연장근로시간</td>
<td class="border border-gray-300 px-3 py-2 text-right font-medium text-blue-700" x-text="salaryData.fixed_overtime_hours"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs">변동값</td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700">통상시급</td>
<td class="border border-gray-300 px-3 py-2 text-right" x-text="Number(salaryData.hourly_wage || 0).toLocaleString()"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs">(기본급+식대) / 209, 연차수당 계산시 적용시급</td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700">연장근로수당배수</td>
<td class="border border-gray-300 px-3 py-2 text-right" x-text="salaryData.overtime_multiplier || 1.5"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs"></td>
</tr>
<tr class="bg-amber-50">
<td class="border border-gray-300 px-3 py-2 font-semibold text-gray-800" style="background: rgb(254 243 199);">고정연장근로수당</td>
<td class="border border-gray-300 px-3 py-2 text-right font-bold" x-text="Number(salaryData.fixed_overtime_pay || 0).toLocaleString()"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs">통상시급 x 월고정연장근로시간 x 연장근로수당배수</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template>
</div>
{{-- 수정 모드 --}}
<div x-show="editing" class="p-6 space-y-4" x-cloak>
<div class="grid gap-4" style="grid-template-columns: repeat(3, 1fr);">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">연봉 ()</label>
<input type="text" inputmode="numeric"
:value="formatNumber(form.annual_salary)"
@input="form.annual_salary = parseNumber($event.target.value); $event.target.value = formatNumber(form.annual_salary)"
placeholder="예: 50,000,000"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">식대 ()</label>
<input type="text" inputmode="numeric"
:value="formatNumber(form.meal_allowance)"
@input="form.meal_allowance = parseNumber($event.target.value); $event.target.value = formatNumber(form.meal_allowance)"
placeholder="200,000"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<p class="text-xs text-gray-400 mt-1">비과세 한도: 200,000</p>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1"> 고정연장근로시간</label>
<input type="number" x-model.number="form.fixed_overtime_hours"
placeholder="예: 22"
min="0" max="52" step="1"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<p class="text-xs text-gray-400 mt-1">변동값 (사원별 상이)</p>
</div>
</div>
<div class="grid gap-4" style="grid-template-columns: 1fr 2fr;">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">적용일</label>
<input type="date" x-model="form.effective_date"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">비고</label>
<textarea x-model="form.notes" rows="1" maxlength="500" placeholder="메모 (선택)"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"></textarea>
</div>
</div>
{{-- 실시간 급여 산정 미리보기 --}}
<template x-if="form.annual_salary > 0">
<div class="border border-blue-200 rounded-lg overflow-hidden">
<div class="px-4 py-2 bg-blue-50 text-sm font-semibold text-blue-700">급여 산정 미리보기</div>
<div class="p-4 space-y-3">
<div class="overflow-x-auto">
<table class="w-full text-sm border border-gray-300">
<thead>
<tr class="bg-gray-100 text-gray-600">
<th class="border border-gray-300 px-3 py-2 text-center font-medium">총급여(연봉)</th>
<th class="border border-gray-300 px-3 py-2 text-center font-medium">기본급</th>
<th class="border border-gray-300 px-3 py-2 text-center font-medium">식대</th>
<th class="border border-gray-300 px-3 py-2 text-center font-medium">고정연장근로수당</th>
<th class="border border-gray-300 px-3 py-2 text-center font-medium bg-blue-50">합계()</th>
</tr>
</thead>
<tbody>
<tr class="text-gray-900">
<td class="border border-gray-300 px-3 py-2 text-right" x-text="formatNumber(form.annual_salary)"></td>
<td class="border border-gray-300 px-3 py-2 text-right font-medium" x-text="formatNumber(calcBaseSalary)"></td>
<td class="border border-gray-300 px-3 py-2 text-right" x-text="formatNumber(form.meal_allowance)"></td>
<td class="border border-gray-300 px-3 py-2 text-right font-medium" x-text="formatNumber(calcFixedOvertimePay)"></td>
<td class="border border-gray-300 px-3 py-2 text-right font-bold bg-blue-50" x-text="formatNumber(calcMonthlySalary)"></td>
</tr>
</tbody>
</table>
</div>
<div class="overflow-x-auto">
<table class="w-full text-sm border border-gray-300">
<tbody>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700" style="width: 170px;">월급여</td>
<td class="border border-gray-300 px-3 py-2 text-right" style="width: 130px;" x-text="formatNumber(calcMonthlySalary)"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs"></td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700">기본급</td>
<td class="border border-gray-300 px-3 py-2 text-right" x-text="formatNumber(calcBaseSalary)"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs"></td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700">식대</td>
<td class="border border-gray-300 px-3 py-2 text-right" x-text="formatNumber(form.meal_allowance)"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs">고정값</td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700"> 근로시간</td>
<td class="border border-gray-300 px-3 py-2 text-right">209</td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs">고정값</td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700"> 고정연장근로시간</td>
<td class="border border-gray-300 px-3 py-2 text-right font-medium text-blue-700" x-text="form.fixed_overtime_hours || 0"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs">변동값</td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700">통상시급</td>
<td class="border border-gray-300 px-3 py-2 text-right" x-text="formatNumber(calcHourlyWage)"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs">(기본급+식대) / 209, 연차수당 계산시 적용시급</td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700">연장근로수당배수</td>
<td class="border border-gray-300 px-3 py-2 text-right">1.5</td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs"></td>
</tr>
<tr class="bg-amber-50">
<td class="border border-gray-300 px-3 py-2 font-semibold text-gray-800" style="background: rgb(254 243 199);">고정연장근로수당</td>
<td class="border border-gray-300 px-3 py-2 text-right font-bold" x-text="formatNumber(calcFixedOvertimePay)"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs">통상시급 x 월고정연장근로시간 x 연장근로수당배수</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template>
<div class="flex justify-end gap-2 pt-2">
<button type="button" @click="editing = false"
class="px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors text-sm">
취소
</button>
<button type="button" @click="saveSalary()" :disabled="saving"
class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors text-sm disabled:opacity-50">
<span x-show="!saving">저장</span>
<span x-show="saving">저장 ...</span>
</button>
</div>
</div>
{{-- 급여 산정 테이블 (저장된 데이터가 있을 ) --}}
<template x-if="salaryData.annual_salary && salaryData.fixed_overtime_hours != null">
{{-- 연봉 변경 이력 --}}
<template x-if="salaryData.history && salaryData.history.length > 0">
<div class="border-t border-gray-200">
<div class="px-6 py-3 bg-blue-50">
<span class="text-sm font-semibold text-blue-700">급여 산정 내역</span>
<div class="px-6 py-3 bg-gray-50">
<span class="text-sm font-semibold text-gray-600">연봉 변경 이력</span>
</div>
{{-- 요약 테이블 --}}
<div class="px-6 pt-4">
<div class="px-6 py-3">
<div class="overflow-x-auto">
<table class="w-full text-sm border border-gray-300">
<table class="w-full text-sm">
<thead>
<tr class="bg-gray-100 text-gray-600">
<th class="border border-gray-300 px-3 py-2 text-center font-medium">총급여(연봉)</th>
<th class="border border-gray-300 px-3 py-2 text-center font-medium">기본급</th>
<th class="border border-gray-300 px-3 py-2 text-center font-medium">식대</th>
<th class="border border-gray-300 px-3 py-2 text-center font-medium">정연장근로수당</th>
<th class="border border-gray-300 px-3 py-2 text-center font-medium bg-blue-50">합계()</th>
<tr class="border-b border-gray-200 text-gray-500">
<th class="text-left py-2 pr-3 font-medium">연봉</th>
<th class="text-left py-2 pr-3 font-medium">고정OT시간</th>
<th class="text-left py-2 pr-3 font-medium">적용일</th>
<th class="text-left py-2 pr-3 font-medium"></th>
<th class="text-left py-2 pr-3 font-medium">기록일</th>
<th class="text-left py-2 pr-3 font-medium">기록자</th>
<th class="text-center py-2 font-medium" style="width: 60px;">삭제</th>
</tr>
</thead>
<tbody>
<tr class="text-gray-900">
<td class="border border-gray-300 px-3 py-2 text-right" x-text="Number(salaryData.annual_salary).toLocaleString()"></td>
<td class="border border-gray-300 px-3 py-2 text-right font-medium" x-text="Number(salaryData.base_salary || 0).toLocaleString()"></td>
<td class="border border-gray-300 px-3 py-2 text-right" x-text="Number(salaryData.meal_allowance || 200000).toLocaleString()"></td>
<td class="border border-gray-300 px-3 py-2 text-right font-medium" x-text="Number(salaryData.fixed_overtime_pay || 0).toLocaleString()"></td>
<td class="border border-gray-300 px-3 py-2 text-right font-bold bg-blue-50" x-text="Number(salaryData.monthly_salary || 0).toLocaleString()"></td>
</tr>
</tbody>
</table>
</div>
</div>
{{-- 상세 산정 내역 --}}
<div class="px-6 py-4">
<div class="overflow-x-auto">
<table class="w-full text-sm border border-gray-300">
<tbody>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700" style="width: 170px;">월급여</td>
<td class="border border-gray-300 px-3 py-2 text-right" style="width: 130px;" x-text="Number(salaryData.monthly_salary || 0).toLocaleString()"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs"></td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700">기본급</td>
<td class="border border-gray-300 px-3 py-2 text-right" x-text="Number(salaryData.base_salary || 0).toLocaleString()"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs"></td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700">식대</td>
<td class="border border-gray-300 px-3 py-2 text-right" x-text="Number(salaryData.meal_allowance || 200000).toLocaleString()"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs">고정값</td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700"> 근로시간</td>
<td class="border border-gray-300 px-3 py-2 text-right" x-text="salaryData.monthly_work_hours || 209"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs">고정값</td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700"> 고정연장근로시간</td>
<td class="border border-gray-300 px-3 py-2 text-right font-medium text-blue-700" x-text="salaryData.fixed_overtime_hours"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs">변동값</td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700">통상시급</td>
<td class="border border-gray-300 px-3 py-2 text-right" x-text="Number(salaryData.hourly_wage || 0).toLocaleString()"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs">(기본급+식대) / 209, 연차수당 계산시 적용시급</td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700">연장근로수당배수</td>
<td class="border border-gray-300 px-3 py-2 text-right" x-text="salaryData.overtime_multiplier || 1.5"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs"></td>
</tr>
<tr class="bg-amber-50">
<td class="border border-gray-300 px-3 py-2 font-semibold text-gray-800" style="background: rgb(254 243 199);">고정연장근로수당</td>
<td class="border border-gray-300 px-3 py-2 text-right font-bold" x-text="Number(salaryData.fixed_overtime_pay || 0).toLocaleString()"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs">통상시급 x 월고정연장근로시간 x 연장근로수당배수</td>
</tr>
<tbody class="divide-y divide-gray-100">
<template x-for="(item, idx) in [...salaryData.history].reverse()" :key="idx">
<tr class="text-gray-900">
<td class="py-2 pr-3 font-medium" x-text="item.annual_salary ? Number(item.annual_salary).toLocaleString() + '원' : '-'"></td>
<td class="py-2 pr-3" x-text="item.fixed_overtime_hours != null ? item.fixed_overtime_hours + 'h' : '-'"></td>
<td class="py-2 pr-3" x-text="item.effective_date || '-'"></td>
<td class="py-2 pr-3" x-text="item.notes || '-'"></td>
<td class="py-2 pr-3 text-gray-500" x-text="item.recorded_at || '-'"></td>
<td class="py-2 pr-3 text-gray-500" x-text="item.recorded_by || '-'"></td>
<td class="py-2 text-center">
<button type="button"
@click="deleteHistory(salaryData.history.length - 1 - idx)"
class="inline-flex items-center justify-center w-7 h-7 rounded text-red-400 hover:text-red-600 hover:bg-red-50 transition-colors"
title="이력 삭제">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
</svg>
</button>
</td>
</tr>
</template>
</tbody>
</table>
</div>
@@ -138,199 +527,31 @@ class="inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-lg
</div>
</template>
</div>
{{-- ============================================================ --}}
{{-- 수정 모드 --}}
{{-- ============================================================ --}}
<div x-show="editing" class="p-6 space-y-4" x-cloak>
{{-- 입력 필드 --}}
<div class="grid gap-4" style="grid-template-columns: repeat(3, 1fr);">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">연봉 ()</label>
<input type="text" inputmode="numeric"
:value="formatNumber(form.annual_salary)"
@input="form.annual_salary = parseNumber($event.target.value); $event.target.value = formatNumber(form.annual_salary)"
placeholder="예: 50,000,000"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">식대 ()</label>
<input type="text" inputmode="numeric"
:value="formatNumber(form.meal_allowance)"
@input="form.meal_allowance = parseNumber($event.target.value); $event.target.value = formatNumber(form.meal_allowance)"
placeholder="200,000"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<p class="text-xs text-gray-400 mt-1">비과세 한도: 200,000</p>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1"> 고정연장근로시간</label>
<input type="number" x-model.number="form.fixed_overtime_hours"
placeholder="예: 22"
min="0" max="52" step="1"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<p class="text-xs text-gray-400 mt-1">변동값 (사원별 상이)</p>
</div>
</div>
<div class="grid gap-4" style="grid-template-columns: 1fr 2fr;">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">적용일</label>
<input type="date" x-model="form.effective_date"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">비고</label>
<textarea x-model="form.notes" rows="1" maxlength="500" placeholder="메모 (선택)"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"></textarea>
</div>
</div>
{{-- 실시간 급여 산정 미리보기 --}}
<template x-if="form.annual_salary > 0">
<div class="border border-blue-200 rounded-lg overflow-hidden">
<div class="px-4 py-2 bg-blue-50 text-sm font-semibold text-blue-700">급여 산정 미리보기</div>
<div class="p-4 space-y-3">
{{-- 요약 테이블 --}}
<div class="overflow-x-auto">
<table class="w-full text-sm border border-gray-300">
<thead>
<tr class="bg-gray-100 text-gray-600">
<th class="border border-gray-300 px-3 py-2 text-center font-medium">총급여(연봉)</th>
<th class="border border-gray-300 px-3 py-2 text-center font-medium">기본급</th>
<th class="border border-gray-300 px-3 py-2 text-center font-medium">식대</th>
<th class="border border-gray-300 px-3 py-2 text-center font-medium">고정연장근로수당</th>
<th class="border border-gray-300 px-3 py-2 text-center font-medium bg-blue-50">합계()</th>
</tr>
</thead>
<tbody>
<tr class="text-gray-900">
<td class="border border-gray-300 px-3 py-2 text-right" x-text="formatNumber(form.annual_salary)"></td>
<td class="border border-gray-300 px-3 py-2 text-right font-medium" x-text="formatNumber(calcBaseSalary)"></td>
<td class="border border-gray-300 px-3 py-2 text-right" x-text="formatNumber(form.meal_allowance)"></td>
<td class="border border-gray-300 px-3 py-2 text-right font-medium" x-text="formatNumber(calcFixedOvertimePay)"></td>
<td class="border border-gray-300 px-3 py-2 text-right font-bold bg-blue-50" x-text="formatNumber(calcMonthlySalary)"></td>
</tr>
</tbody>
</table>
</div>
{{-- 상세 산정 내역 --}}
<div class="overflow-x-auto">
<table class="w-full text-sm border border-gray-300">
<tbody>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700" style="width: 170px;">월급여</td>
<td class="border border-gray-300 px-3 py-2 text-right" style="width: 130px;" x-text="formatNumber(calcMonthlySalary)"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs"></td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700">기본급</td>
<td class="border border-gray-300 px-3 py-2 text-right" x-text="formatNumber(calcBaseSalary)"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs"></td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700">식대</td>
<td class="border border-gray-300 px-3 py-2 text-right" x-text="formatNumber(form.meal_allowance)"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs">고정값</td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700"> 근로시간</td>
<td class="border border-gray-300 px-3 py-2 text-right">209</td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs">고정값</td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700"> 고정연장근로시간</td>
<td class="border border-gray-300 px-3 py-2 text-right font-medium text-blue-700" x-text="form.fixed_overtime_hours || 0"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs">변동값</td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700">통상시급</td>
<td class="border border-gray-300 px-3 py-2 text-right" x-text="formatNumber(calcHourlyWage)"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs">(기본급+식대) / 209, 연차수당 계산시 적용시급</td>
</tr>
<tr>
<td class="border border-gray-300 px-3 py-2 bg-gray-50 font-medium text-gray-700">연장근로수당배수</td>
<td class="border border-gray-300 px-3 py-2 text-right">1.5</td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs"></td>
</tr>
<tr class="bg-amber-50">
<td class="border border-gray-300 px-3 py-2 font-semibold text-gray-800" style="background: rgb(254 243 199);">고정연장근로수당</td>
<td class="border border-gray-300 px-3 py-2 text-right font-bold" x-text="formatNumber(calcFixedOvertimePay)"></td>
<td class="border border-gray-300 px-3 py-2 text-gray-500 text-xs">통상시급 x 월고정연장근로시간 x 연장근로수당배수</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template>
{{-- 버튼 --}}
<div class="flex justify-end gap-2 pt-2">
<button type="button" @click="editing = false"
class="px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors text-sm">
취소
</button>
<button type="button" @click="saveSalary()" :disabled="saving"
class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors text-sm disabled:opacity-50">
<span x-show="!saving">저장</span>
<span x-show="saving">저장 ...</span>
</button>
</div>
</div>
{{-- ============================================================ --}}
{{-- 연봉 변경 이력 --}}
{{-- ============================================================ --}}
<template x-if="salaryData.history && salaryData.history.length > 0">
<div class="border-t border-gray-200">
<div class="px-6 py-3 bg-gray-50">
<span class="text-sm font-semibold text-gray-600">연봉 변경 이력</span>
</div>
<div class="px-6 py-3">
<div class="overflow-x-auto">
<table class="w-full text-sm">
<thead>
<tr class="border-b border-gray-200 text-gray-500">
<th class="text-left py-2 pr-3 font-medium">연봉</th>
<th class="text-left py-2 pr-3 font-medium">고정OT시간</th>
<th class="text-left py-2 pr-3 font-medium">적용일</th>
<th class="text-left py-2 pr-3 font-medium">비고</th>
<th class="text-left py-2 pr-3 font-medium">기록일</th>
<th class="text-left py-2 pr-3 font-medium">기록자</th>
<th class="text-center py-2 font-medium" style="width: 60px;">삭제</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-100">
<template x-for="(item, idx) in [...salaryData.history].reverse()" :key="idx">
<tr class="text-gray-900">
<td class="py-2 pr-3 font-medium" x-text="item.annual_salary ? Number(item.annual_salary).toLocaleString() + '원' : '-'"></td>
<td class="py-2 pr-3" x-text="item.fixed_overtime_hours != null ? item.fixed_overtime_hours + 'h' : '-'"></td>
<td class="py-2 pr-3" x-text="item.effective_date || '-'"></td>
<td class="py-2 pr-3" x-text="item.notes || '-'"></td>
<td class="py-2 pr-3 text-gray-500" x-text="item.recorded_at || '-'"></td>
<td class="py-2 pr-3 text-gray-500" x-text="item.recorded_by || '-'"></td>
<td class="py-2 text-center">
<button type="button"
@click="deleteHistory(salaryData.history.length - 1 - idx)"
class="inline-flex items-center justify-center w-7 h-7 rounded text-red-400 hover:text-red-600 hover:bg-red-50 transition-colors"
title="이력 삭제">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
</svg>
</button>
</td>
</tr>
</template>
</tbody>
</table>
</div>
</div>
</div>
</template>
</div>
@push('scripts')
<script>
@if($isEditMode)
function dependentsManager() {
return {
dependents: (@json($employee->dependents ?? [])).map(dep => ({
...dep,
is_disabled: !!(dep.is_disabled && dep.is_disabled !== '0' && dep.is_disabled !== 0),
is_dependent: !!(dep.is_dependent && dep.is_dependent !== '0' && dep.is_dependent !== 0),
})),
addDependent() {
this.dependents.push({
name: '', nationality: 'korean', resident_number: '',
relationship: '', is_disabled: false, is_dependent: false
});
},
removeDependent(index) {
this.dependents.splice(index, 1);
}
};
}
@endif
function salaryManager() {
const MONTHLY_WORK_HOURS = 209;
const OVERTIME_MULTIPLIER = 1.5;
@@ -348,7 +569,6 @@ function salaryManager() {
notes: initialData.notes || '',
},
// === 계산 프로퍼티 (실시간 미리보기용) ===
get calcMonthlySalary() {
if (!this.form.annual_salary) return 0;
return Math.round(this.form.annual_salary / 12);
@@ -372,7 +592,6 @@ function salaryManager() {
return this.calcMonthlySalary - this.calcBaseSalary - (this.form.meal_allowance || 0);
},
// === 유틸리티 ===
formatNumber(val) {
if (!val && val !== 0) return '';
return Number(val).toLocaleString();
@@ -382,7 +601,6 @@ function salaryManager() {
return isNaN(num) ? '' : num;
},
// === API 호출 ===
async saveSalary() {
this.saving = true;
try {

View File

@@ -89,17 +89,6 @@ class="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 hover:bg-blue-700 te
<div class="shrink-0 text-sm font-medium text-gray-500" style="width: 140px;">연락처</div>
<div class="text-sm text-gray-900">{{ $employee->user?->phone ?? '-' }}</div>
</div>
<div class="px-6 py-3 flex" style="flex-wrap: wrap;">
<div class="shrink-0 text-sm font-medium text-gray-500" style="width: 140px;">주민등록번호</div>
<div class="text-sm text-gray-900">
@if($employee->resident_number)
{{ Str::mask($employee->resident_number, '*', 8) }}
@else
-
@endif
</div>
</div>
{{-- 근무 정보 --}}
<div class="px-6 py-4 bg-gray-50">
<span class="text-sm font-semibold text-gray-600">근무 정보</span>
@@ -161,80 +150,6 @@ class="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 hover:bg-blue-700 te
<div class="text-sm text-gray-900">{{ $employee->updated_at?->format('Y-m-d H:i') ?? '-' }}</div>
</div>
{{-- 급여이체정보 --}}
<div class="px-6 py-4 bg-gray-50">
<span class="text-sm font-semibold text-gray-600">급여이체정보</span>
</div>
@php $bankAccount = $employee->bank_account ?? []; @endphp
<div class="px-6 py-3 flex" style="flex-wrap: wrap;">
<div class="shrink-0 text-sm font-medium text-gray-500" style="width: 140px;">이체은행</div>
<div class="text-sm text-gray-900">{{ $bankAccount['bank_name'] ?? '-' }}</div>
</div>
<div class="px-6 py-3 flex" style="flex-wrap: wrap;">
<div class="shrink-0 text-sm font-medium text-gray-500" style="width: 140px;">예금주</div>
<div class="text-sm text-gray-900">{{ $bankAccount['account_holder'] ?? '-' }}</div>
</div>
<div class="px-6 py-3 flex" style="flex-wrap: wrap;">
<div class="shrink-0 text-sm font-medium text-gray-500" style="width: 140px;">계좌번호</div>
<div class="text-sm text-gray-900">{{ $bankAccount['account_number'] ?? '-' }}</div>
</div>
{{-- 부양가족 정보 --}}
<div class="px-6 py-4 bg-gray-50">
<span class="text-sm font-semibold text-gray-600">부양가족 정보</span>
</div>
@php $dependents = $employee->dependents ?? []; @endphp
@if(count($dependents) > 0)
<div class="px-6 py-3">
<div class="overflow-x-auto">
<table class="w-full text-sm">
<thead>
<tr class="border-b border-gray-200 text-gray-500">
<th class="text-left py-2 pr-3 font-medium">이름</th>
<th class="text-left py-2 pr-3 font-medium">/외국인</th>
<th class="text-left py-2 pr-3 font-medium">주민등록번호</th>
<th class="text-left py-2 pr-3 font-medium">관계</th>
<th class="text-left py-2 pr-3 font-medium">장애인</th>
<th class="text-left py-2 font-medium">피부양자</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-100">
@foreach($dependents as $dep)
<tr class="text-gray-900">
<td class="py-2 pr-3">{{ $dep['name'] ?? '-' }}</td>
<td class="py-2 pr-3">{{ ($dep['nationality'] ?? 'korean') === 'korean' ? '내국인' : '외국인' }}</td>
<td class="py-2 pr-3">
@if(!empty($dep['resident_number']))
{{ Str::mask($dep['resident_number'], '*', 8) }}
@else
-
@endif
</td>
<td class="py-2 pr-3">
@switch($dep['relationship'] ?? '')
@case('spouse') 배우자 @break
@case('child') 자녀 @break
@case('parent') 부모 @break
@case('sibling') 형제자매 @break
@case('grandparent') 조부모 @break
@case('other') 기타 @break
@default - @break
@endswitch
</td>
<td class="py-2 pr-3">{{ filter_var($dep['is_disabled'] ?? false, FILTER_VALIDATE_BOOLEAN) ? 'Y' : 'N' }}</td>
<td class="py-2">{{ filter_var($dep['is_dependent'] ?? false, FILTER_VALIDATE_BOOLEAN) ? 'Y' : 'N' }}</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
@else
<div class="px-6 py-3">
<p class="text-sm text-gray-400">등록된 부양가족이 없습니다.</p>
</div>
@endif
{{-- 첨부파일 --}}
<div class="px-6 py-4 bg-gray-50">
<span class="text-sm font-semibold text-gray-600">첨부파일</span>
@@ -262,9 +177,9 @@ class="text-sm text-blue-600 hover:text-blue-800">
</div>
</div>
{{-- 연봉 정보 (특수 권한 사용자만 표시) --}}
{{-- 개인정보 연봉정보 (특수 권한 사용자만 표시) --}}
@if($canViewSalary)
@include('hr.employees.partials.salary-info')
@include('hr.employees.partials.salary-info', ['editMode' => false])
@endif
</div>
@endsection