연차변경원 진행중

This commit is contained in:
hehihoho3@gmail.com 2025-08-12 15:49:34 +09:00
parent e8e10c48c0
commit 05dc5b5d76
8 changed files with 233 additions and 41 deletions

View File

@ -5,6 +5,7 @@ import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
@ -18,6 +19,8 @@ public class LeaveChangeRequestVO {
private String userName;
private LocalDate originalLeaveDate;
private LocalDate requestedLeaveDate;
private BigDecimal originalLeaveDays; // 추가
private BigDecimal requestedLeaveDays; // 추가
private String requestReason;
private String requestStatus;
private String requestStatusName; // 추가

View File

@ -32,4 +32,6 @@ public class LeavePlanVO {
private String requestStatus; // 변경 상태
private String requestStatusName; // 변경 상태 코드 name
private String changeCount; // 변경 카운트
private BigDecimal originalLeaveDays; // 변경 일수
private BigDecimal requestedLeaveDays; // 변경 일수
}

View File

@ -27,7 +27,7 @@ public interface ItnLeaveService {
boolean rejectLeavePlan(Long planId, String approverId, String rejectReason);
boolean requestLeaveChange(LeaveChangeRequestVO leaveChangeRequestVO);
RestResponse requestLeaveChange(LeaveChangeRequestVO leaveChangeRequestVO);
LeaveChangeRequestVO getLeaveChangeRequestDetail(Long changeRequestId);

View File

@ -71,6 +71,8 @@ public class ItnLeaveServiceImpl implements ItnLeaveService {
LeaveChangeRequestVO leaveChangeRequestVO = itnLeaveMapper.selectItnLeaveChangeRequestById(changeRequestId);
if (leaveChangeRequestVO != null) {
leaveChangeRequestVO.setUserName(tCodeUtils.getUserName(leaveChangeRequestVO.getUniqId()));
log.info("originalLeaveDays: {}", leaveChangeRequestVO.getOriginalLeaveDays());
log.info("requestedLeaveDays: {}", leaveChangeRequestVO.getRequestedLeaveDays());
}
return leaveChangeRequestVO;
}
@ -79,6 +81,30 @@ public class ItnLeaveServiceImpl implements ItnLeaveService {
@Override
@Transactional
public boolean saveLeavePlan(LeavePlanVO leavePlanVO) {
// ==================== [검증 로직 시작] ====================
// 1. 사용자의 촉진 연차 목표치 조회 (itn_leave_status.promoted_leave)
LeaveStatusVO leaveStatus = itnLeaveMapper.selectLeaveStatusByUserIdAndYear(leavePlanVO.getUniqId(), leavePlanVO.getYear());
BigDecimal promotedLeaveGoal = leaveStatus.getPromotedLeave();
// 2. 현재 DB에 저장된 '승인' '대기' 상태의 모든 연차 계획 총합을 계산
List<LeavePlanVO> existingPlans = itnLeaveMapper.selectLeavePlansByUserIdAndYear(leavePlanVO.getUniqId(), leavePlanVO.getYear());
BigDecimal currentPledgedDays = existingPlans.stream()
.filter(p -> "10".equals(p.getStatus()) || "20".equals(p.getStatus())) // 10: 대기, 20: 승인
.map(LeavePlanVO::getLeaveDays)
.reduce(BigDecimal.ZERO, BigDecimal::add);
// 3. 이번에 새로 신청한 연차 일수
BigDecimal newRequestDays = leavePlanVO.getLeaveDays();
// 4. 예상 총합(기존 총합 + 신규 신청) 목표치를 초과하는지 검증
if (currentPledgedDays.add(newRequestDays).compareTo(promotedLeaveGoal) > 0) {
// 초과할 경우, 예외를 발생시켜 저장을 막고 사용자에게 에러 메시지 전달
throw new IllegalArgumentException("신청 가능한 촉진 연차 일수를 초과했습니다.");
}
// ==================== [검증 로직 종료] ====================
if (leavePlanVO.getPlanId() == null) {
// 신규 신청
leavePlanVO.setStatus(LEAVE_STATUS_PENDING); // 초기 상태는 PENDING
@ -173,18 +199,37 @@ public class ItnLeaveServiceImpl implements ItnLeaveService {
// 연차 변경 요청
@Override
@Transactional
public boolean requestLeaveChange(LeaveChangeRequestVO leaveChangeRequestVO) {
// 기존 연차 계획의 변경 요청 상태를 10으로 업데이트
// LeavePlanVO originalLeavePlan = itnLeaveMapper.selectLeavePlanById(leaveChangeRequestVO.getPlanId());
// if (originalLeavePlan == null) {
// return false; // 원본 연차 계획이 없음
// }
// leaveChangeRequestVO.setUniqId(originalLeavePlan.getUniqId());
public RestResponse requestLeaveChange(LeaveChangeRequestVO leaveChangeRequestVO) {
// ==================== [검증 로직 시작] ====================
// 1. 사용자의 촉진 연차 목표치 조회 (itn_leave_status.promoted_leave)
LeaveStatusVO leaveStatus = itnLeaveMapper.selectLeaveStatusByUserIdAndYear(leaveChangeRequestVO.getUniqId(), String.valueOf(leaveChangeRequestVO.getOriginalLeaveDate().getYear()));
BigDecimal promotedLeaveGoal = leaveStatus.getPromotedLeave();
// 연차 변경 요청 이력 저장
// 2. 현재 DB에 저장된 '승인' '대기' 상태의 모든 연차 계획 총합을 계산
List<LeavePlanVO> existingPlans = itnLeaveMapper.selectLeavePlansByUserIdAndYear(leaveChangeRequestVO.getUniqId(), String.valueOf(leaveChangeRequestVO.getOriginalLeaveDate().getYear()));
BigDecimal currentPledgedDays = existingPlans.stream()
.filter(p -> "10".equals(p.getStatus()) || "20".equals(p.getStatus())) // 10: 대기, 20: 승인
.map(LeavePlanVO::getLeaveDays)
.reduce(BigDecimal.ZERO, BigDecimal::add);
// 3. 이번 '변경'으로 인해 발생하는 연차 변동량 계산
// (: 1.0일 -> 0.5일 변경 -0.5 / 0.5일 -> 1.0일 변경 +0.5)
BigDecimal changeInDays = leaveChangeRequestVO.getRequestedLeaveDays().subtract(leaveChangeRequestVO.getOriginalLeaveDays());
// 4. 예상 총합(기존 총합 + 변동량) 목표치를 초과하는지 검증
if (currentPledgedDays.add(changeInDays).compareTo(promotedLeaveGoal) > 0) {
// 초과할 경우, 예외를 발생시켜 저장을 막음
return new RestResponse(HttpStatus.BAD_REQUEST, "변경 후 총 연차 일수가 촉진 연차 한도를 초과합니다.");
}
// ==================== [검증 로직 종료] ====================
// 5. 검증 통과 , 기존 로직 수행
leaveChangeRequestVO.setRequestStatus(LEAVE_CHANGE_REQUEST_STATUS_PENDING);
return itnLeaveMapper.insertLeaveChangeRequest(leaveChangeRequestVO) > 0;
itnLeaveMapper.insertLeaveChangeRequest(leaveChangeRequestVO);
return new RestResponse(HttpStatus.OK, "연차 변경 요청이 성공적으로 제출되었습니다.");
}
@ -202,11 +247,21 @@ public class ItnLeaveServiceImpl implements ItnLeaveService {
changeRequest.setApproverId(approverId);
itnLeaveMapper.updateLeaveChangeRequestStatus(changeRequest);
// 원본 연차 계획 업데이트 (날짜 변경)
// 원본 연차 계획 업데이트 (날짜 일수 변경)
LeavePlanVO originalLeavePlan = itnLeaveMapper.selectLeavePlanById(changeRequest.getPlanId());
if (originalLeavePlan != null) {
originalLeavePlan.setLeaveDate(changeRequest.getRequestedLeaveDate());
originalLeavePlan.setLeaveDays(changeRequest.getRequestedLeaveDays()); // 일수 변경 반영
itnLeaveMapper.updateLeavePlan(originalLeavePlan); // 기존 updateLeavePlan 사용
// 사용된 연차 재계산 업데이트 (used_leave는 고정값이므로 수정하지 않음)
// LeaveStatusVO leaveStatus = itnLeaveMapper.selectLeaveStatusByUserIdAndYear(originalLeavePlan.getUniqId(), originalLeavePlan.getYear());
// if (leaveStatus != null) {
// BigDecimal oldUsedLeave = leaveStatus.getUsedLeave();
// BigDecimal changedAmount = changeRequest.getOriginalLeaveDays().subtract(changeRequest.getRequestedLeaveDays());
// leaveStatus.setUsedLeave(oldUsedLeave.subtract(changedAmount));
// itnLeaveMapper.updateLeaveStatus(leaveStatus);
// }
}
return true;

View File

@ -89,12 +89,16 @@ public class ItnLeaveRestController {
public ResponseEntity<RestResponse> submitLeaveChangeRequest(@RequestBody LeaveChangeRequestVO leaveChangeRequestVO
, @AuthenticationPrincipal CustomUserDetails loginUser) {
leaveChangeRequestVO.setUniqId(loginUser.getUser().getUniqId());
boolean result = itnLeaveService.requestLeaveChange(leaveChangeRequestVO);
if (result) {
return ResponseEntity.ok().body(new RestResponse(HttpStatus.OK, "연차 변경 요청이 성공적으로 제출되었습니다."));
} else {
return ResponseEntity.badRequest().body(new RestResponse(HttpStatus.BAD_REQUEST, "연차 변경 요청 제출에 실패했습니다."));
}
// boolean result = itnLeaveService.requestLeaveChange(leaveChangeRequestVO);
return ResponseEntity.ok().body(itnLeaveService.requestLeaveChange(leaveChangeRequestVO));
// if (result) {
// return ResponseEntity.ok().body(new RestResponse(HttpStatus.OK, "연차 변경 요청이 성공적으로 제출되었습니다."));
// } else {
// return ResponseEntity.badRequest().body(new RestResponse(HttpStatus.BAD_REQUEST, "연차 변경 요청 제출에 실패했습니다."));
// }
}
// 연차 변경 요청 상세 조회

View File

@ -53,6 +53,8 @@
c.change_request_id,
c.original_leave_date,
c.requested_leave_date,
c.original_leave_days,
c.requested_leave_days,
c.request_reason,
c.request_status,
c.request_dt,
@ -143,6 +145,8 @@
UNIQ_ID,
ORIGINAL_LEAVE_DATE,
REQUESTED_LEAVE_DATE,
ORIGINAL_LEAVE_DAYS,
REQUESTED_LEAVE_DAYS,
REQUEST_REASON,
REQUEST_STATUS,
REQUEST_DT
@ -151,6 +155,8 @@
#{uniqId},
#{originalLeaveDate},
#{requestedLeaveDate},
#{originalLeaveDays},
#{requestedLeaveDays},
#{requestReason},
#{requestStatus},
NOW()
@ -167,6 +173,8 @@
T1.UNIQ_ID,
T1.ORIGINAL_LEAVE_DATE,
T1.REQUESTED_LEAVE_DATE,
T1.ORIGINAL_LEAVE_DAYS,
T1.REQUESTED_LEAVE_DAYS,
T1.REQUEST_REASON,
T1.REQUEST_STATUS,
(SELECT CODE_NAME FROM COMMON_CODE_DETAIL WHERE CODE_GROUP_ID = 'CHANGE_REQUEST_STATUS' AND CODE_ID = T1.REQUEST_STATUS) AS requestStatusName,
@ -195,6 +203,8 @@
T1.UNIQ_ID,
T1.ORIGINAL_LEAVE_DATE,
T1.REQUESTED_LEAVE_DATE,
T1.ORIGINAL_LEAVE_DAYS,
T1.REQUESTED_LEAVE_DAYS,
T1.REQUEST_REASON,
T1.REQUEST_STATUS,
(SELECT CODE_NAME FROM COMMON_CODE_DETAIL WHERE CODE_GROUP_ID = 'CHANGE_REQUEST_STATUS' AND CODE_ID = T1.REQUEST_STATUS) AS requestStatusName,
@ -211,11 +221,11 @@
SELECT
T1.CHANGE_REQUEST_ID,
T1.PLAN_ID,
ilp.YEAR ,
ilp.LEAVE_DAYS ,
T1.UNIQ_ID,
T1.ORIGINAL_LEAVE_DATE,
T1.REQUESTED_LEAVE_DATE,
T1.ORIGINAL_LEAVE_DAYS,
T1.REQUESTED_LEAVE_DAYS,
T1.REQUEST_REASON,
T1.REQUEST_STATUS,
(SELECT CODE_NAME FROM COMMON_CODE_DETAIL WHERE CODE_GROUP_ID = 'CHANGE_REQUEST_STATUS' AND CODE_ID = T1.REQUEST_STATUS) AS requestStatusName,
@ -224,8 +234,6 @@
T1.REQUEST_DT,
T1.APPROVAL_DT
FROM ITN_LEAVE_CHANGE_REQUEST T1
left join itn_leave_plan ilp
on T1.plan_id = ilp.PLAN_ID
WHERE T1.CHANGE_REQUEST_ID = #{changeRequestId}
</select>
@ -238,6 +246,8 @@
T1.UNIQ_ID,
T1.ORIGINAL_LEAVE_DATE,
T1.REQUESTED_LEAVE_DATE,
T1.ORIGINAL_LEAVE_DAYS,
T1.REQUESTED_LEAVE_DAYS,
T1.REQUEST_REASON,
T1.REQUEST_STATUS,
(SELECT CODE_NAME FROM COMMON_CODE_DETAIL WHERE CODE_GROUP_ID = 'CHANGE_REQUEST_STATUS' AND CODE_ID = T1.REQUEST_STATUS) AS requestStatusName,

View File

@ -53,6 +53,7 @@
<th>신청자</th>
<th>기존 연차 일자</th>
<th>요청 변경 일자</th>
<th>변경일수</th>
<th>요청 사유</th>
<th>요청 일시</th>
<th>상태</th>
@ -64,6 +65,10 @@
<td th:text="${@TCodeUtils.getUserName(changeRequest.uniqId)}"></td>
<td th:text="${changeRequest.originalLeaveDate}"></td>
<td th:text="${changeRequest.requestedLeaveDate}"></td>
<td>
<span th:if="${changeRequest.originalLeaveDays != null and changeRequest.requestedLeaveDays != null}"
th:text="|${changeRequest.originalLeaveDays} → ${changeRequest.requestedLeaveDays}|"></span>
</td>
<td th:text="${changeRequest.requestReason}"></td>
<td th:text="${#temporals.format(changeRequest.requestDt, 'yyyy-MM-dd HH:mm')}"></td>
<td th:text="${changeRequest.requestStatusName}"></td>
@ -179,6 +184,11 @@
$('#leaveChangeRequestDetailModal #detailChangeRequestUserId').val(data.userName);
$('#leaveChangeRequestDetailModal #detailOriginalLeaveDate').val(data.originalLeaveDate);
$('#leaveChangeRequestDetailModal #detailRequestedLeaveDate').val(data.requestedLeaveDate);
if (data.originalLeaveDays != null && data.requestedLeaveDays != null) {
$('#leaveChangeRequestDetailModal #detailLeaveDaysChange').val(`${data.originalLeaveDays} → ${data.requestedLeaveDays}`);
} else {
$('#leaveChangeRequestDetailModal #detailLeaveDaysChange').val('-');
}
$('#leaveChangeRequestDetailModal #detailRequestReason').val(data.requestReason);
$('#leaveChangeRequestDetailModal #detailChangeRequestRequestDt').val(data.requestDt);
$('#leaveChangeRequestDetailModal #changeRequestApprovalStatus').val('20'); // 기본값 설정 : 승인
@ -237,6 +247,10 @@
<label>요청 변경 일자</label>
<input type="text" class="form-control" id="detailRequestedLeaveDate" readonly>
</div>
<div class="form-group">
<label>변경 일수</label>
<input type="text" class="form-control" id="detailLeaveDaysChange" readonly>
</div>
<div class="form-group">
<label>요청 사유</label>
<textarea class="form-control" id="detailRequestReason" rows="3" readonly></textarea>

View File

@ -112,6 +112,56 @@
</table>
</div>
<!-- 촉진 연차 현황 요약 섹션 추가 -->
<div class="mb-4" th:with="
promotedLeaveVal=${leaveStatus != null ? leaveStatus.promotedLeave : T(java.math.BigDecimal).ZERO},
filteredLeavePlans=${leavePlans != null ? leavePlans.?[status == '10' or status == '20'] : T(java.util.Collections).emptyList()},
plannedTotal=${#aggregates.sum(filteredLeavePlans.![leaveDays != null ? leaveDays : T(java.math.BigDecimal).ZERO])},
remainingPlanDays=${T(java.util.Optional).ofNullable(promotedLeaveVal).orElse(T(java.math.BigDecimal).ZERO).subtract(T(java.util.Optional).ofNullable(plannedTotal).orElse(T(java.math.BigDecimal).ZERO))}">
<h5 class="mb-3"><i class="fas fa-chart-pie text-info mr-1"></i> 촉진 연차 현황</h5>
<table class="table table-bordered table-hover align-middle" style="width: 100%;">
<tbody>
<tr>
<th style="width: 200px; background-color: #f8f9fa;">촉진 연차 목표</th>
<td th:text="${leaveStatus.promotedLeave} + '일'">10.0일</td>
</tr>
<tr>
<th style="background-color: #f8f9fa;">현재 계획된 연차 총합</th>
<td th:text="${plannedTotal} + '일'">8.0일</td>
</tr>
<tr>
<th style="background-color: #f8f9fa;">추가 계획 가능 연차</th>
<td th:text="${remainingPlanDays} + '일'">2.0일</td>
</tr>
</tbody>
</table>
<!-- 디버깅 정보 (임시) -->
<div style="background-color: #f0f0f0; padding: 10px; margin-top: 20px; border-radius: 5px;">
<p><strong>디버깅 정보:</strong></p>
<p>촉진 연차 목표 (promotedLeave): <span th:text="${leaveStatus.promotedLeave}"></span></p>
<p>현재 계획된 연차 총합 (plannedTotal): <span th:text="${plannedTotal}"></span></p>
<p>추가 계획 가능 연차 (remainingPlanDays): <span th:text="${remainingPlanDays}"></span></p>
</div>
<!-- 사용자 안내 메시지 -->
<div>
<div th:if="${remainingPlanDays.compareTo(T(java.math.BigDecimal).ZERO) > 0}" class="alert alert-info mt-3" role="alert">
<i class="fas fa-info-circle mr-1"></i> 촉진 연차를 모두 사용하려면 <strong th:text="${remainingPlanDays}">2.0</strong>일의 연차를 더 신청해야 합니다.
</div>
<div th:if="${remainingPlanDays.compareTo(T(java.math.BigDecimal).ZERO) <= 0}" class="alert alert-success mt-3" role="alert">
<i class="fas fa-check-circle mr-1"></i> 촉진 연차 목표를 달성했거나 초과했습니다.
</div>
</div>
<!-- 추가된 버튼 -->
<div th:if="${remainingPlanDays.compareTo(T(java.math.BigDecimal).ZERO) > 0}" class="text-center mt-3">
<a th:href="@{/itn/leave/request}" class="btn btn-primary btn-lg">
<i class="fas fa-plus-circle mr-2"></i> 연차 사용 계획 신청하기
</a>
</div>
</div>
<!-- 연차 사용 계획 -->
<div>
<h5>📅 연차 사용 계획</h5>
@ -122,6 +172,7 @@
<th style="width: 200px;">일자</th>
<th style="width: 200px;">일수</th>
<th style="width: 200px;">변경 횟수</th>
<th style="width: 200px;">변경일수</th>
<th style="width: 200px;">요청 상태</th>
<th>반려 사유</th>
<th style="width: 100px;" class="text-center">관리</th>
@ -141,6 +192,10 @@
style="cursor: pointer;">
</a>
</td>
<td>
<span th:if="${plan.originalLeaveDays != null and plan.requestedLeaveDays != null}"
th:text="|${plan.originalLeaveDays} → ${plan.requestedLeaveDays}|"></span>
</td>
@ -158,7 +213,7 @@
<td th:text="${plan.rejectionReason}"></td>
<td>
<a href="#"
th:onclick="openLeaveChangeRequestModal([[${plan.planId}]], [[${plan.leaveDate}]])"
th:onclick="openLeaveChangeRequestModal([[${plan.planId}]], [[${plan.leaveDate}]], [[${plan.leaveDays}]])"
th:if="${plan.requestStatus != '10'} and ${plan.leaveDate > T(java.time.LocalDate).now()}"
class="btn btn-info btn-sm">
변경 요청
@ -172,6 +227,14 @@
</tr>
</th:block>
</tbody>
<tfoot>
<tr class="table-active font-weight-bold text-center">
<td>합계</td>
<td th:text="${#aggregates.sum(leavePlans.![leaveDays])}"></td>
<td th:text="${#aggregates.sum(leavePlans.![T(java.lang.Integer).parseInt(changeCount)])}"></td>
<td colspan="3"></td>
</tr>
</tfoot>
</table>
</div>
</div>
@ -220,7 +283,7 @@
$body.empty(); // 기존 내용 제거
if (historyList.length === 0) {
$body.append('<tr><td colspan="5">변경 이력이 없습니다.</td></tr>');
$body.append('<tr><td colspan="6">변경 이력이 없습니다.</td></tr>');
return;
}
@ -230,6 +293,9 @@
: item.requestStatus === '40' ? 'badge-success'
: 'badge-light';
const leaveDaysChangeHtml = (item.originalLeaveDays != null && item.requestedLeaveDays != null) ?
`<td>${item.originalLeaveDays} → ${item.requestedLeaveDays}</td>` : '<td>-</td>';
const row = `
<tr>
<td class="bg-secondary text-white font-monospace rounded px-2 py-1">
@ -237,6 +303,7 @@
</td>
<td>${item.originalLeaveDate}</td>
<td>${item.requestedLeaveDate}</td>
${leaveDaysChangeHtml}
<td>${item.requestReason}</td>
<td>
<span class="badge ${badgeClass} px-3 py-2">${item.requestStatusName}</span>
@ -254,11 +321,13 @@
});
}
window.openLeaveChangeRequestModal = function (planId, originalLeaveDate) {
window.openLeaveChangeRequestModal = function (planId, originalLeaveDate, originalLeaveDays) {
console.log(' openLeaveChangeRequestModal ');
$('#leaveChangeRequestModal #planId').val(planId);
$('#leaveChangeRequestModal #originalLeaveDate').val(originalLeaveDate);
$('#leaveChangeRequestModal #originalLeaveDays').val(originalLeaveDays);
$('#leaveChangeRequestModal #requestedLeaveDate').val('');
$('#leaveChangeRequestModal #requestedLeaveDays').val('1.0');
$('#leaveChangeRequestModal #requestReason').val('');
$('#leaveChangeRequestModal').modal('show');
}
@ -266,7 +335,9 @@
function submitLeaveChangeRequest() {
const planId = $('#leaveChangeRequestModal #planId').val();
const originalLeaveDate = $('#leaveChangeRequestModal #originalLeaveDate').val();
const originalLeaveDays = $('#leaveChangeRequestModal #originalLeaveDays').val();
const requestedLeaveDate = $('#leaveChangeRequestModal #requestedLeaveDate').val();
const requestedLeaveDays = $('#leaveChangeRequestModal #requestedLeaveDays').val();
const requestReason = $('#leaveChangeRequestModal #requestReason').val();
if (!requestedLeaveDate) {
@ -283,7 +354,9 @@
const data = {
planId: planId,
originalLeaveDate: originalLeaveDate,
originalLeaveDays: originalLeaveDays,
requestedLeaveDate: requestedLeaveDate,
requestedLeaveDays: requestedLeaveDays,
requestReason: requestReason
};
@ -295,9 +368,15 @@
contentType: 'application/json',
data: JSON.stringify(data),
success: function (response) {
fn_successAlert(response.msg);
$('#leaveChangeRequestModal').modal('hide');
location.reload();
if(response.status == 'BAD_REQUEST'){
fn_failedAlert(response.msg);
}else{
fn_successAlert(response.msg);
$('#leaveChangeRequestModal').modal('hide');
location.reload();
}
},
error: function (xhr, status, error) {
const errorResponse = JSON.parse(xhr.responseText);
@ -321,6 +400,7 @@
<div class="modal-body">
<form id="leaveChangeRequestForm">
<input type="hidden" id="planId" name="planId">
<input type="hidden" id="originalLeaveDays" name="originalLeaveDays">
<div class="form-group">
<label for="originalLeaveDate">기존 연차 일자</label>
<input type="text" class="form-control" id="originalLeaveDate" readonly>
@ -334,6 +414,13 @@
</div>
</div>
</div>
<div class="form-group">
<label for="requestedLeaveDays">변경 요청 일수</label>
<select class="form-control" id="requestedLeaveDays" name="requestedLeaveDays">
<option value="1.0">연차 (1.0일)</option>
<option value="0.5">반차 (0.5일)</option>
</select>
</div>
<div class="form-group">
<label for="requestReason">변경 요청 사유</label>
<textarea class="form-control" id="requestReason" name="requestReason" rows="3" required></textarea>
@ -351,7 +438,7 @@
<!-- 변경 이력 모달 -->
<!-- 변경 이력 모달 -->
<div class="modal fade" id="changeHistoryModal" tabindex="-1" role="dialog" aria-labelledby="changeHistoryModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-dialog modal-xl" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="changeHistoryModalLabel">변경 이력</h5>
@ -367,23 +454,40 @@
<th style="width: 20%;">변경 일시</th>
<th style="width: 15%;">기존 날짜</th>
<th style="width: 15%;">요청 날짜</th>
<th style="width: 10%;">변경일수</th>
<th style="width: 30%;">요청 사유</th>
<th style="width: 20%;">처리 상태</th>
<th style="width: 30%;">처리 상태</th>
</tr>
</thead>
<tbody id="changeHistoryBody">
<tr>
<td class="bg-secondary text-white font-monospace rounded px-2 py-1">
2025-07-15 09:32
</td>
<td>2025-07-22</td>
<td>2025-07-24</td>
<td>개인 일정 조정</td>
<td>
<span class="badge badge-secondary px-3 py-2">대기</span>
</td>
</tr>
<!-- 추가 row 가능 -->
<th:block th:if="${not #lists.isEmpty(historyList)}">
<tr th:each="item : ${historyList}">
<td class="bg-secondary text-white font-monospace rounded px-2 py-1">
<span th:text="${#temporals.format(item.requestDt, 'yyyy-MM-dd HH:mm')}"></span>
</td>
<td th:text="${item.originalLeaveDate}"></td>
<td th:text="${item.requestedLeaveDate}"></td>
<td>
<span th:if="${item.originalLeaveDays != null and item.requestedLeaveDays != null}"
th:text="|${item.originalLeaveDays} → ${item.requestedLeaveDays}|"></span>
<span th:unless="${item.originalLeaveDays != null and item.requestedLeaveDays != null}">-</span>
</td>
<td th:text="${item.requestReason}"></td>
<td>
<span th:class="'badge px-3 py-2 fs-6 ' +
(${item.requestStatus} == '20' ? 'badge-secondary' :
(${item.requestStatus} == '30' ? 'badge-warning' :
(${item.requestStatus} == '40' ? 'badge-success' : 'badge-light')))"
th:text="${item.requestStatusName}">
</span>
</td>
</tr>
</th:block>
<th:block th:if="${#lists.isEmpty(historyList)}">
<tr>
<td colspan="6">변경 이력이 없습니다.</td>
</tr>
</th:block>
</tbody>
</table>
</div>