feat: Add public holiday batch processing and web interface for hospital information management.

This commit is contained in:
pjs
2026-02-16 01:24:22 +09:00
parent 6287526490
commit a41b072d99
12 changed files with 382 additions and 229 deletions

6
.gitignore vendored
View File

@@ -61,3 +61,9 @@ Thumbs.db
.settings/org.eclipse.jdt.core.prefs
.settings/org.eclipse.buildship.core.prefs
.classpath
# Wiki repo (별도 git 리포)
.wiki/
# Agent workflows
.agent/

View File

@@ -1,13 +1,13 @@
arguments=
arguments=--init-script C\:\\Users\\bd091\\AppData\\Roaming\\Antigravity\\User\\globalStorage\\redhat.java\\1.50.0\\config_win\\org.eclipse.osgi\\58\\0\\.cp\\gradle\\init\\init.gradle --init-script C\:\\Users\\bd091\\AppData\\Roaming\\Antigravity\\User\\globalStorage\\redhat.java\\1.50.0\\config_win\\org.eclipse.osgi\\58\\0\\.cp\\gradle\\protobuf\\init.gradle
auto.sync=false
build.scans.enabled=false
connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
connection.project.dir=
eclipse.preferences.version=1
gradle.user.home=
java.home=
java.home=C\:/Program Files/Java/jdk-21
jvm.arguments=
offline.mode=false
override.workspace.settings=false
show.console.view=false
show.executions.view=false
override.workspace.settings=true
show.console.view=true
show.executions.view=true

View File

@@ -50,7 +50,7 @@ public class InsertPublicHolidayBatchExcute {
* [임시 실행용] 서버 시작(또는 리로드) 시 배치를 즉시 1회 실행합니다.
* 실행이 완료된 후에는 다시 주석 처리하거나 삭제하세요.
*/
@EventListener(ContextRefreshedEvent.class)
// @EventListener(ContextRefreshedEvent.class)
public void forceRunBatch() {
log.info("============================================================================");
log.info("============== [FORCE START] Public Holiday Batch Execution ==============");

View File

@@ -360,4 +360,73 @@ public class WebHospitalController extends ManagerDraftAction {
log.debug("WebHospitalController deleteHospitalSchedule END");
return HttpUtil.makeHashToJsonModelAndView(map);
}
/**
* 병원 지정 휴일 개별 저장 (insert or update)
*/
@RequestMapping(value = "/webhospital/saveHospitalHoliday.do")
public ModelAndView saveHospitalHoliday(HttpSession session, HttpServletRequest request,
HttpServletResponse response) {
log.debug("WebHospitalController saveHospitalHoliday START");
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
HashMap<String, Object> map = new HashMap<String, Object>();
try {
if (!webCheckLogin(session)) {
return null;
} else {
paramMap.put("loginMemberId", String.valueOf(session.getAttribute("loginMemberId")));
paramMap.put("regId", String.valueOf(session.getAttribute("loginMemberId")));
paramMap.put("modId", String.valueOf(session.getAttribute("loginMemberId")));
map = webHospitalService.saveHospitalHoliday(paramMap);
}
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
if (Constants.OK != map.get("msgCode")) {
map.put("msgCode", Constants.FAIL);
map.put("success", false);
if (null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
map.put("msgDesc", "정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다.");
}
}
}
log.debug("WebHospitalController saveHospitalHoliday END");
return HttpUtil.makeHashToJsonModelAndView(map);
}
/**
* 병원 지정 휴일 선택 삭제 (체크된 row 일괄 삭제)
*/
@RequestMapping(value = "/webhospital/deleteHospitalHolidays.do")
public ModelAndView deleteHospitalHolidays(HttpSession session, HttpServletRequest request,
HttpServletResponse response) {
log.debug("WebHospitalController deleteHospitalHolidays START");
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
HashMap<String, Object> map = new HashMap<String, Object>();
try {
if (!webCheckLogin(session)) {
return null;
} else {
paramMap.put("loginMemberId", String.valueOf(session.getAttribute("loginMemberId")));
paramMap.put("modId", String.valueOf(session.getAttribute("loginMemberId")));
map = webHospitalService.deleteHospitalHolidays(paramMap);
}
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
if (Constants.OK != map.get("msgCode")) {
map.put("msgCode", Constants.FAIL);
map.put("success", false);
if (null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
map.put("msgDesc", "정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다.");
}
}
}
log.debug("WebHospitalController deleteHospitalHolidays END");
return HttpUtil.makeHashToJsonModelAndView(map);
}
}

View File

@@ -19,4 +19,8 @@ public interface WebHospitalService {
public HashMap<String, Object> saveHospitalSchedule(HashMap<String, Object> paramMap) throws Exception;
public HashMap<String, Object> deleteHospitalSchedule(HashMap<String, Object> paramMap) throws Exception;
public HashMap<String, Object> saveHospitalHoliday(HashMap<String, Object> paramMap) throws Exception;
public HashMap<String, Object> deleteHospitalHolidays(HashMap<String, Object> paramMap) throws Exception;
}

View File

@@ -8,10 +8,6 @@ import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.*;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@@ -715,39 +711,6 @@ public class WebHospitalServiceImpl implements WebHospitalService {
webHospitalSqlMapDAO.updateHospital(paramMap);
// 휴일정보 삭제
webHospitalHolidaySqlMapDAO.deleteHospitalHoliday(paramMap);
// 휴일정보 등록
JSONParser jsonParser = new JSONParser();
JSONObject jsonObject = (JSONObject) jsonParser.parse(String.valueOf(paramMap.get("holidayRows")));
JSONArray detailArray = (JSONArray) jsonObject.get("data");
for (int j = 0; j < detailArray.size(); j++) {
JSONObject detailObject = (JSONObject) detailArray.get(j);
String hospitalHolidayName = String.valueOf(detailObject.get("hospitalHolidayName"));
String locDate = String.valueOf(detailObject.get("locDate"));
String repeatYn = String.valueOf(detailObject.get("repeatYn"));
if ((null != hospitalHolidayName && !("").equals(hospitalHolidayName))
|| (null != locDate && !("").equals(locDate))
|| (null != repeatYn && !("").equals(repeatYn))) {
HashMap<String, Object> holidayParamMap = new HashMap<String, Object>();
String muHospitalHolidayId = ("HH").concat(String.valueOf(System.currentTimeMillis()));
holidayParamMap.put("muHospitalHolidayId", muHospitalHolidayId);
holidayParamMap.put("muHospitalId", paramMap.get("muHospitalId"));
holidayParamMap.put("hospitalHolidayName", hospitalHolidayName);
holidayParamMap.put("locDate", locDate);
holidayParamMap.put("repeatYn", repeatYn);
holidayParamMap.put("useYn", "Y");
holidayParamMap.put("regId", paramMap.get("regId"));
holidayParamMap.put("modId", paramMap.get("modId"));
holidayParamMap.put("tId", paramMap.get("tId"));
holidayParamMap.put("tDate", paramMap.get("tDate"));
webHospitalHolidaySqlMapDAO.insertHospitalHoliday(holidayParamMap);
}
}
map.put("msgCode", Constants.OK);
map.put("msgDesc", "수정되었습니다.");
}
@@ -826,4 +789,62 @@ public class WebHospitalServiceImpl implements WebHospitalService {
}
return map;
}
/**
* 병원 지정 휴일 개별 저장 (insert or update)
*/
@Override
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class })
public HashMap<String, Object> saveHospitalHoliday(HashMap<String, Object> paramMap) throws Exception {
log.debug("WebHospitalServiceImpl saveHospitalHoliday START");
HashMap<String, Object> map = new HashMap<>();
try {
String muHospitalHolidayId = String.valueOf(paramMap.get("muHospitalHolidayId"));
if (muHospitalHolidayId != null && !muHospitalHolidayId.isEmpty() && !"null".equals(muHospitalHolidayId)) {
// 기존 row 수정
webHospitalHolidaySqlMapDAO.updateHospitalHoliday(paramMap);
} else {
// 신규 row 등록
paramMap.put("muHospitalHolidayId", "HH");
webHospitalHolidaySqlMapDAO.insertHospitalHoliday(paramMap);
}
map.put("msgCode", Constants.OK);
map.put("msgDesc", "저장되었습니다.");
} catch (Exception e) {
e.printStackTrace();
throw e;
}
log.debug("WebHospitalServiceImpl saveHospitalHoliday END");
return map;
}
/**
* 병원 지정 휴일 선택 삭제 (체크된 row 일괄 삭제)
*/
@Override
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class })
public HashMap<String, Object> deleteHospitalHolidays(HashMap<String, Object> paramMap) throws Exception {
log.debug("WebHospitalServiceImpl deleteHospitalHolidays START");
HashMap<String, Object> map = new HashMap<>();
try {
String holidayIds = String.valueOf(paramMap.get("holidayIds"));
if (holidayIds != null && !holidayIds.isEmpty() && !"null".equals(holidayIds)) {
String[] ids = holidayIds.split(",");
for (String id : ids) {
HashMap<String, Object> delMap = new HashMap<>();
delMap.put("muHospitalId", paramMap.get("muHospitalId"));
delMap.put("muHospitalHolidayId", id.trim());
delMap.put("modId", paramMap.get("modId"));
webHospitalHolidaySqlMapDAO.deleteHospitalHoliday(delMap);
}
}
map.put("msgCode", Constants.OK);
map.put("msgDesc", "삭제되었습니다.");
} catch (Exception e) {
e.printStackTrace();
throw e;
}
log.debug("WebHospitalServiceImpl deleteHospitalHolidays END");
return map;
}
}

View File

@@ -81,6 +81,7 @@
,USE_YN = 'N'
WHERE USE_YN = 'Y'
AND MU_HOSPITAL_ID = #{muHospitalId}
AND MU_HOSPITAL_HOLIDAY_ID = #{muHospitalHolidayId}
</update>
</mapper>

View File

@@ -5,6 +5,7 @@
<select id="selectHospital" parameterType="hashmap" resultType="hashmap">
SELECT MH.MU_HOSPITAL_ID AS "muHospitalId"
,MH.HOSPITAL_NAME AS "hospitalName"
,MH.CENTER_DIV_CD AS "centerDivCd"
,MH.MON_OPEN_YN AS "monOpenYn"
,DATE_FORMAT(MH.MON_OPEN_START_TIME , '%H:%i') AS "monOpenStartTime"
,DATE_FORMAT(MH.MON_OPEN_END_TIME , '%H:%i') AS "monOpenEndTime"
@@ -49,6 +50,9 @@
),'') AS "memberName"
FROM MU_HOSPITAL AS MH
WHERE MH.USE_YN = 'Y'
<if test="centerDivCd != null and centerDivCd != ''">
AND MH.CENTER_DIV_CD = #{centerDivCd}
</if>
LIMIT 0, 1
</select>
@@ -71,21 +75,20 @@
,CASE
WHEN EXISTS (
SELECT 1
FROM MU_HOSPITAL_HOLIDAY MH
WHERE MH.USE_YN = 'Y'
FROM MU_HOSPITAL_HOLIDAY MHH
WHERE MHH.USE_YN = 'Y'
AND MHH.MU_HOSPITAL_ID = MH.MU_HOSPITAL_ID
AND (
(MH.REPEAT_YN = 'Y' AND DATE_FORMAT(MH.LOC_DATE, '%m-%d') = DATE_FORMAT(#{searchDate}, '%m-%d'))
(MHH.REPEAT_YN = 'Y' AND DATE_FORMAT(MHH.LOC_DATE, '%m-%d') = DATE_FORMAT(#{searchDate}, '%m-%d'))
OR
(MH.REPEAT_YN = 'N' AND MH.LOC_DATE = #{searchDate})
(MHH.REPEAT_YN = 'N' AND MHH.LOC_DATE = #{searchDate})
)) OR
EXISTS (
(MH.PUBLIC_HOLIDAY_USE_YN = 'Y' AND EXISTS (
SELECT 1
FROM MU_PUBLIC_HOLIDAY MPH
JOIN MU_HOSPITAL
ON PUBLIC_HOLIDAY_USE_YN='Y'
WHERE MPH.USE_YN = 'Y'
AND MPH.LOC_DATE = #{searchDate}
)
))
THEN 'Y'
ELSE 'N'
END AS "holidayYn"
@@ -147,6 +150,9 @@
AND MHS.SCHEDULE_DATE = #{searchDate}
AND MHS.USE_YN = 'Y'
WHERE MH.USE_YN = 'Y'
<if test="centerDivCd != null and centerDivCd != ''">
AND MH.CENTER_DIV_CD = #{centerDivCd}
</if>
LIMIT 0, 1
</select>
@@ -188,21 +194,20 @@
END AS OPEN_YN
,CASE
WHEN EXISTS(
SELECT 1
FROM MU_HOSPITAL_HOLIDAY AS MH
WHERE MH.USE_YN = 'Y'
AND ((MH.REPEAT_YN = 'Y' AND DATE_FORMAT(MH.LOC_DATE, '%m-%d') = DATE_FORMAT(TTD.RESULT_DATE, '%m-%d'))
OR
(MH.REPEAT_YN = 'N' AND MH.LOC_DATE = TTD.RESULT_DATE))
)
OR EXISTS(
SELECT 1
FROM MU_PUBLIC_HOLIDAY AS MPH
JOIN MU_HOSPITAL
ON PUBLIC_HOLIDAY_USE_YN='Y'
WHERE MPH.USE_YN = 'Y'
AND MPH.LOC_DATE = TTD.RESULT_DATE
SELECT 1
FROM MU_HOSPITAL_HOLIDAY AS MHH
WHERE MHH.USE_YN = 'Y'
AND MHH.MU_HOSPITAL_ID = MH.MU_HOSPITAL_ID
AND ((MHH.REPEAT_YN = 'Y' AND DATE_FORMAT(MHH.LOC_DATE, '%m-%d') = DATE_FORMAT(TTD.RESULT_DATE, '%m-%d'))
OR
(MHH.REPEAT_YN = 'N' AND MHH.LOC_DATE = TTD.RESULT_DATE))
)
OR (MH.PUBLIC_HOLIDAY_USE_YN = 'Y' AND EXISTS(
SELECT 1
FROM MU_PUBLIC_HOLIDAY AS MPH
WHERE MPH.USE_YN = 'Y'
AND MPH.LOC_DATE = TTD.RESULT_DATE
))
THEN 'Y'
ELSE 'N'
END AS HOLIDAY_YN
@@ -213,7 +218,10 @@
ORDER BY TTD.RESULT_DATE ASC
) AS TTD
LEFT JOIN MU_HOSPITAL AS MH
ON 1 = 1
ON MH.USE_YN = 'Y'
<if test="centerDivCd != null and centerDivCd != ''">
AND MH.CENTER_DIV_CD = #{centerDivCd}
</if>
) AS TTD
LEFT JOIN MU_HOSPITAL_SCHEDULE MHS
ON MHS.SCHEDULE_DATE = TTD.RESULT_DATE
@@ -387,4 +395,5 @@
WHERE USE_YN = 'Y'
AND MU_HOSPITAL_ID = #{muHospitalId}
</update>
</mapper>

View File

@@ -0,0 +1,38 @@
-- ================================================================
-- 센터구분(CENTER_DIV_CD) 컬럼 추가 및 쁘띠센터 행 생성 마이그레이션
-- ================================================================
-- 1. 센터구분 컬럼 추가
ALTER TABLE MU_HOSPITAL ADD COLUMN CENTER_DIV_CD VARCHAR(10) DEFAULT 'DIET' COMMENT '센터구분(DIET/PETIT)' AFTER HOSPITAL_NAME;
-- 2. 기존 행을 다이어트센터로 설정
UPDATE MU_HOSPITAL SET CENTER_DIV_CD = 'DIET' WHERE USE_YN = 'Y';
-- 3. 쁘띠센터 행 생성 (기존 다이어트 운영시간을 복사, 운영시간은 별도 설정 필요)
INSERT INTO MU_HOSPITAL (
MU_HOSPITAL_ID, HOSPITAL_NAME, CENTER_DIV_CD,
MON_OPEN_YN, MON_OPEN_START_TIME, MON_OPEN_END_TIME, MON_BREAK_START_TIME, MON_BREAK_END_TIME,
TUE_OPEN_YN, TUE_OPEN_START_TIME, TUE_OPEN_END_TIME, TUE_BREAK_START_TIME, TUE_BREAK_END_TIME,
WED_OPEN_YN, WED_OPEN_START_TIME, WED_OPEN_END_TIME, WED_BREAK_START_TIME, WED_BREAK_END_TIME,
THU_OPEN_YN, THU_OPEN_START_TIME, THU_OPEN_END_TIME, THU_BREAK_START_TIME, THU_BREAK_END_TIME,
FRI_OPEN_YN, FRI_OPEN_START_TIME, FRI_OPEN_END_TIME, FRI_BREAK_START_TIME, FRI_BREAK_END_TIME,
SAT_OPEN_YN, SAT_OPEN_START_TIME, SAT_OPEN_END_TIME, SAT_BREAK_START_TIME, SAT_BREAK_END_TIME,
SUN_OPEN_YN, SUN_OPEN_START_TIME, SUN_OPEN_END_TIME, SUN_BREAK_START_TIME, SUN_BREAK_END_TIME,
PUBLIC_HOLIDAY_USE_YN, MU_MEMBER_ID,
WRITE_DATE, WRITE_TIME, CUD_FLAG, USE_YN, REG_ID, REG_DATE, MOD_ID, MOD_DATE
)
SELECT
CONCAT(LEFT(MU_HOSPITAL_ID, 24), '2'), -- 새 ID 생성
HOSPITAL_NAME, 'PETIT',
MON_OPEN_YN, MON_OPEN_START_TIME, MON_OPEN_END_TIME, MON_BREAK_START_TIME, MON_BREAK_END_TIME,
TUE_OPEN_YN, TUE_OPEN_START_TIME, TUE_OPEN_END_TIME, TUE_BREAK_START_TIME, TUE_BREAK_END_TIME,
WED_OPEN_YN, WED_OPEN_START_TIME, WED_OPEN_END_TIME, WED_BREAK_START_TIME, WED_BREAK_END_TIME,
THU_OPEN_YN, THU_OPEN_START_TIME, THU_OPEN_END_TIME, THU_BREAK_START_TIME, THU_BREAK_END_TIME,
FRI_OPEN_YN, FRI_OPEN_START_TIME, FRI_OPEN_END_TIME, FRI_BREAK_START_TIME, FRI_BREAK_END_TIME,
SAT_OPEN_YN, SAT_OPEN_START_TIME, SAT_OPEN_END_TIME, SAT_BREAK_START_TIME, SAT_BREAK_END_TIME,
SUN_OPEN_YN, SUN_OPEN_START_TIME, SUN_OPEN_END_TIME, SUN_BREAK_START_TIME, SUN_BREAK_END_TIME,
PUBLIC_HOLIDAY_USE_YN, MU_MEMBER_ID,
CURDATE(), CURTIME(), 'C', 'Y', 'SYSTEM', NOW(), 'SYSTEM', NOW()
FROM MU_HOSPITAL
WHERE USE_YN = 'Y' AND CENTER_DIV_CD = 'DIET'
LIMIT 1;

View File

@@ -121,20 +121,21 @@
background: #fff;
border: solid 1px #E9ECF0;
border-radius: 5px;
padding: 50px;
padding: 20px 50px 50px 50px;
margin-top: 20px;
display: flex;
gap: 50px;
flex-wrap: wrap;
gap: 30px;
}
.project_wrap .content_section .hospital_wrap .center_box .info_box .info_left {
width: 50%;
min-width: 500px;
flex: 1 1 400px;
min-width: 0;
}
.project_wrap .content_section .hospital_wrap .center_box .info_box .info_right {
width: 50%;
min-width: 500px;
flex: 1 1 400px;
min-width: 0;
}
.project_wrap .content_section .hospital_wrap .center_box .info_box .info {
@@ -176,7 +177,7 @@
}
.project_wrap .content_section .hospital_wrap .center_box .info_box .form_box .time_box .time_list {
width: 700px;
width: 100%;
float: left;
}
@@ -233,7 +234,8 @@
}
.project_wrap .content_section .hospital_wrap .center_box .info_box .form_box .time_box .time_list li .day_box .day {
width: 70px;
width: 100%;
max-width: 70px;
line-height: 36px;
border-radius: 16px;
font-size: 14px;
@@ -470,7 +472,7 @@
}
.project_wrap .content_section .hospital_wrap .center_box .info_box .form_box .hospital_box .hospital_list {
width: 700px;
width: 100%;
float: left;
}
@@ -753,10 +755,14 @@
vertical-align: top;
}
.project_wrap .content_section .hospital_wrap .center_box .info_box .form_box .hospital_box .hospital_list li button:hover {
.project_wrap .content_section .hospital_wrap .center_box .info_box .form_box .hospital_box .hospital_list li button:not(.save_box button):hover {
background: none !important;
}
.project_wrap .content_section .hospital_wrap .center_box .info_box .form_box .hospital_box .hospital_list li .save_box button:hover {
background: #2d3748 !important;
}
.project_wrap .content_section .hospital_wrap .center_box .info_box .form_box .admset_box {
width: 100%;
background: #fff;

View File

@@ -5,6 +5,7 @@
function fn_selectHospitalJson(onlyOperatingHours) {
let formData = new FormData();
formData.append("menuClass", menuClass);
formData.append("centerDivCd", $("#currentCenterDivCd").val() || 'DIET');
$.ajax({
url: encodeURI('/webhospital/selectHospital.do'),
@@ -131,8 +132,12 @@ function fn_selectHospitalJson(onlyOperatingHours) {
// 휴일 상세 정보
fn_addRow2(hospitalRows.holidayRows);
// 달력 조회 (병원 ID 확보 후 실행)
fn_selectHospitalHolidayList();
// 달력: 이미 생성되어 있으면 이벤트만 재조회, 없으면 새로 생성
if (window.fcCalendar) {
window.fcCalendar.refetchEvents();
} else {
fn_selectHospitalHolidayList();
}
}
}
else {
@@ -177,10 +182,11 @@ function fn_addRow2(detailList) {
let repeatLabel = ('Y' == repeatYn) ? '반복' : '반복 안함';
addRowHtml += '<li style="display: flex !important; width: 100% !important; float: none !important; align-items: center; border-bottom: 1px solid #eee; padding: 10px 0;">';
addRowHtml += '<input type="hidden" name="muHospitalHolidayId" value="' + (detailList[i].muHospitalHolidayId || '') + '">';
// Checkbox
addRowHtml += ' <div class="check_box" style="width: 40px !important; display: flex; justify-content: center; align-items: center; float: none !important;">';
addRowHtml += ' <input type="checkbox" name="checkHolidayRow" value="">';
addRowHtml += ' <input type="checkbox" name="checkHolidayRow" value="' + (detailList[i].muHospitalHolidayId || '') + '">';
addRowHtml += ' </div>';
// Name
@@ -258,6 +264,7 @@ function fn_addRow(param) {
let addRowHtml = '';
addRowHtml += '<li style="display: flex !important; width: 100% !important; float: none !important; align-items: center; border-bottom: 1px solid #eee; padding: 10px 0;">';
addRowHtml += '<input type="hidden" name="muHospitalHolidayId" value="">';
// Checkbox
addRowHtml += ' <div class="check_box" style="width: 40px !important; display: flex; justify-content: center; align-items: center; float: none !important;">';
@@ -671,7 +678,6 @@ function fn_updateHospital() {
formData.append("sunBreakStartTime", sunBreakStartTime);
formData.append("sunBreakEndTime", sunBreakEndTime);
formData.append("publicHolidayUseYn", publicHolidayUseYn);
formData.append("holidayRows", JSON.stringify(detailArray));
$.ajax({
url: encodeURI('/webhospital/updateHospital.do'),
@@ -684,7 +690,7 @@ function fn_updateHospital() {
success: function (data) {
if ('0' == data.msgCode) {
modalEvent.success("수정 성공", data.msgDesc, function () {
fn_reload();
fn_selectHospitalJson(true);
});
}
else {
@@ -744,16 +750,38 @@ function fn_pageInit() {
// 탭 전환 시 캘린더 리사이즈 (풀캘린더 v6)
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
if (e.target.hash === '#schedule') {
if (window.calendar) {
window.calendar.render();
if (window.fcCalendar) {
window.fcCalendar.render();
}
}
});
// 기본 센터: 다이어트
$("#currentCenterDivCd").val('DIET');
// 병원 상세 조회
fn_selectHospitalJson();
}
/****************************************************************************
* 센터 전환
****************************************************************************/
function fn_switchCenter(centerDivCd) {
$("#currentCenterDivCd").val(centerDivCd);
fn_resetOperatingHoursForm();
fn_selectHospitalJson();
}
/****************************************************************************
* 운영시간 폼 초기화
****************************************************************************/
function fn_resetOperatingHoursForm() {
$('#checkMonOpenYn, #checkTueOpenYn, #checkWedOpenYn, #checkThuOpenYn, #checkFriOpenYn, #checkSatOpenYn, #checkSunOpenYn').prop('checked', false).trigger('change');
$('#checkPublicHolidayUseYn').prop('checked', false);
// 병원휴일 리스트 초기화
$('#hospitalHolidayList').empty();
}
/****************************************************************************
* 병원 휴일 정보 조회 (달력용)
@@ -822,7 +850,7 @@ function fn_selectHospitalHolidayList() {
}
});
calendar.render();
window.calendar = calendar; // 전역 변수로 저장
window.fcCalendar = calendar; // 전역 변수로 저장
}
/****************************************************************************
@@ -962,7 +990,7 @@ function fn_saveSchedule() {
success: function (data) {
if ('0' == data.msgCode) {
fn_closeSchedulePopup();
window.calendar.refetchEvents(); // 달력 갱신
window.fcCalendar.refetchEvents(); // 달력 갱신
} else {
modalEvent.danger("오류", data.msgDesc);
}
@@ -991,7 +1019,7 @@ function fn_deleteSchedule() {
success: function (data) {
if ('0' == data.msgCode) {
fn_closeSchedulePopup();
window.calendar.refetchEvents(); // 달력 갱신
window.fcCalendar.refetchEvents(); // 달력 갱신
} else {
modalEvent.danger("오류", data.msgDesc);
}
@@ -1089,27 +1117,7 @@ function fn_pageEvent() {
// [New] Row Remove Button (Checked items)
$("#btnRemoveRow").click(function () {
let checkedRows = $("#hospitalHolidayList input[name='checkHolidayRow']:checked");
if (checkedRows.length > 0) {
modalEvent.info("삭제", "선택한 " + checkedRows.length + "개의 항목을 삭제하시겠습니까?", function () {
checkedRows.each(function () {
$(this).closest('li').remove();
});
// If no rows left, add one empty row? Or just leave header?
// fn_addRow2 logic adds header if length > 0, else calls fn_addRow.
// If we deleted all data rows, we should check if any data row exists.
// Header is li.list_title_li. Data rows are just li.
if ($("#hospitalHolidayList li").not(".list_title_li").length == 0) {
$('#hospitalHolidayList').append('<li class="no_data" style="width: 100%; text-align: center; padding: 20px 0;">지정한 휴일이 없습니다.</li>');
}
// Trigger DB update immediately (skip confirmation)
fn_updateHospitalHoliday(true);
});
} else {
modalEvent.warning("알림", "삭제할 항목을 선택해주세요.");
}
fn_deleteCheckedHolidays();
});
// [New] Check All
@@ -1122,115 +1130,33 @@ function fn_pageEvent() {
* 병원 휴일 행별 저장
****************************************************************************/
function fn_saveHospitalHolidayRow(btn) {
// Simply call the bulk update function which gathers all rows and saves them.
// This satisfies the "Save" action while maintaining data integrity with the backend's "Delete All -> Insert All" logic.
fn_updateHospitalHoliday();
}
/****************************************************************************
* 병원 휴일 정보 수정
****************************************************************************/
function fn_updateHospitalHoliday() {
let $li = $(btn).closest('li');
let muHospitalId = $("#muHospitalId").val();
let muHospitalHolidayId = $li.find('input[name="muHospitalHolidayId"]').val();
let hospitalHolidayName = $li.find('input[name="hospitalHolidayName"]').val();
let locDate = $li.find('input[name="dateLocDate"]').val();
let repeatYn = $li.find('input[name="repeatYn"]').val();
// 법정공휴일 사용 여부
let publicHolidayUseYn = $("#checkPublicHolidayUseYn").is(":checked") ? "Y" : "N";
// 병원 지정 휴일 리스트
let detailArray = new Object();
let holidayLi = $("#hospitalHolidayList li");
let liLength = holidayLi.length;
let tempArray = new Array();
for (let i = 1; i < liLength; i++) {
// Skip 'no_data' row
if (holidayLi.eq(i).hasClass('no_data')) continue;
let hospitalHolidayName = holidayLi.eq(i).find('input[name="hospitalHolidayName"]').val();
// Skip empty names to prevent null insertion
if (!hospitalHolidayName || hospitalHolidayName.trim() === "") continue;
let locDate = holidayLi.eq(i).find('input[name="dateLocDate"]').val();
let repeatYn = holidayLi.eq(i).find('input[name="repeatYn"]').val();
let arr_sub = new Object();
arr_sub.hospitalHolidayName = hospitalHolidayName;
arr_sub.locDate = locDate;
arr_sub.repeatYn = repeatYn;
tempArray.push(arr_sub);
if (!hospitalHolidayName || hospitalHolidayName.trim() === "") {
modalEvent.danger("오류", "휴일명을 입력해주세요.");
return;
}
if (!locDate) {
modalEvent.danger("오류", "날짜를 선택해주세요.");
return;
}
detailArray.data = tempArray;
var updateFunc = function () {
modalEvent.info("저장", "해당 휴일을 저장하시겠습니까?", function () {
let formData = new FormData();
// 기존 병원 정보 수정 로직과 동일한 엔드포인트를 사용하되, 휴일 관련 데이터만 전송
// 단, 서버 로직상 다른 필드가 필수라면 기존 값을 가져오거나, 별도 API가 필요할 수 있음.
// 현재 updateHospital 로직은 전체 필드를 업데이트하는 것으로 보이므로,
// 안전하게는 전체 데이터를 보내거나, 휴일만 업데이트하는 별도 로직이 권장됨.
// 여기서는 사용자의 요청에 따라 '별도로 저장' 기능을 구현하므로,
// 기존 updateHospital을 호출하되 휴일 데이터 위주로 처리하거나,
// 혹은 updateHospital 수정이 필요할 수 있음.
// *중요*: 사용자가 '운영시간' 탭의 내용은 '저장' 버튼으로, '운영스케쥴' 탭의 내용은 '휴일 저장' 버튼으로 저장하길 원함.
// 하지만 백엔드(updateHospital)가 하나 통으로 되어 있다면,
// 여기서도 다른 필드 값들을 다 채워서 보내야 에러가 안 날 수 있음 (MyBatis Query 확인 필요).
// 앞서 본 쿼리상 updateHospital은 모든 칼럼을 업데이트함.
// 따라서 여기서도 화면에 있는 모든 입력값을 다 읽어서 보내는 것이 안전함. (부분 업데이트 쿼리가 없다면)
// 하지만 '운영시간' 탭의 데이터 변경사항이 '휴일 저장' 버튼 누를 때 같이 저장되어도 되는지?
// 사용자 의도는 "별도로 저장할 수 있게" 이므로,
// 이상적으로는 휴일만 업데이트하는 API가 있어야 함.
// 현재 API 구조상 updateHospital을 재사용한다면 모든 데이터를 다 보내야 함.
// 일단 전체 데이터를 다 수집해서 보내되, 성공 메시지 등은 분리 처리.
// --- 전체 데이터 수집 시작 (fn_updateHospital 내용 복사) ---
formData.append("menuClass", menuClass);
formData.append("muHospitalId", muHospitalId);
// 운영시간 데이터도 현재 화면 값 그대로 전송 (null 방지)
formData.append("monOpenYn", $("#checkMonOpenYn").is(":checked") ? "Y" : "N");
formData.append("monOpenStartTime", $("#monOpenStartTime").val());
formData.append("monOpenEndTime", $("#monOpenEndTime").val());
formData.append("monBreakStartTime", $("#monBreakStartTime").val());
formData.append("monBreakEndTime", $("#monBreakEndTime").val());
formData.append("tueOpenYn", $("#checkTueOpenYn").is(":checked") ? "Y" : "N");
formData.append("tueOpenStartTime", $("#tueOpenStartTime").val());
formData.append("tueOpenEndTime", $("#tueOpenEndTime").val());
formData.append("tueBreakStartTime", $("#tueBreakStartTime").val());
formData.append("tueBreakEndTime", $("#tueBreakEndTime").val());
formData.append("wedOpenYn", $("#checkWedOpenYn").is(":checked") ? "Y" : "N");
formData.append("wedOpenStartTime", $("#wedOpenStartTime").val());
formData.append("wedOpenEndTime", $("#wedOpenEndTime").val());
formData.append("wedBreakStartTime", $("#wedBreakStartTime").val());
formData.append("wedBreakEndTime", $("#wedBreakEndTime").val());
formData.append("thuOpenYn", $("#checkThuOpenYn").is(":checked") ? "Y" : "N");
formData.append("thuOpenStartTime", $("#thuOpenStartTime").val());
formData.append("thuOpenEndTime", $("#thuOpenEndTime").val());
formData.append("thuBreakStartTime", $("#thuBreakStartTime").val());
formData.append("thuBreakEndTime", $("#thuBreakEndTime").val());
formData.append("friOpenYn", $("#checkFriOpenYn").is(":checked") ? "Y" : "N");
formData.append("friOpenStartTime", $("#friOpenStartTime").val());
formData.append("friOpenEndTime", $("#friOpenEndTime").val());
formData.append("friBreakStartTime", $("#friBreakStartTime").val());
formData.append("friBreakEndTime", $("#friBreakEndTime").val());
formData.append("satOpenYn", $("#checkSatOpenYn").is(":checked") ? "Y" : "N");
formData.append("satOpenStartTime", $("#satOpenStartTime").val());
formData.append("satOpenEndTime", $("#satOpenEndTime").val());
formData.append("satBreakStartTime", $("#satBreakStartTime").val());
formData.append("satBreakEndTime", $("#satBreakEndTime").val());
formData.append("sunOpenYn", $("#checkSunOpenYn").is(":checked") ? "Y" : "N");
formData.append("sunOpenStartTime", $("#sunOpenStartTime").val());
formData.append("sunOpenEndTime", $("#sunOpenEndTime").val());
formData.append("sunBreakStartTime", $("#sunBreakStartTime").val());
formData.append("sunBreakEndTime", $("#sunBreakEndTime").val());
// 휴일 데이터
formData.append("publicHolidayUseYn", publicHolidayUseYn);
formData.append("holidayRows", JSON.stringify(detailArray));
formData.append("muHospitalHolidayId", muHospitalHolidayId || "");
formData.append("hospitalHolidayName", hospitalHolidayName);
formData.append("locDate", locDate);
formData.append("repeatYn", repeatYn || "N");
$.ajax({
url: encodeURI('/webhospital/updateHospital.do'),
url: encodeURI('/webhospital/saveHospitalHoliday.do'),
data: formData,
dataType: "json",
processData: false,
@@ -1238,29 +1164,93 @@ function fn_updateHospitalHoliday() {
type: 'POST',
success: function (data) {
if ('0' == data.msgCode) {
modalEvent.success("성공", "수정되었습니다.", function () {
modalEvent.success("성공", "저장되었습니다.", function () {
// 캘린더 리렌더링
if (window.calendar) {
window.calendar.refetchEvents();
if (window.fcCalendar) {
window.fcCalendar.refetchEvents();
}
// 페이지 리로드 대신 필요한 부분만 갱신하거나 유지
// location.reload();
// 휴일 목록 새로고침 (저장 후 ID가 변경될 수 있으므로)
fn_selectHospitalJson();
});
} else {
modalEvent.danger("오류", data.msgDesc);
}
},
error: function () {
modalEvent.danger("오류", "수정 중 오류가 발생했습니다.");
modalEvent.danger("오류", "저장 중 오류가 발생했습니다.");
}
});
};
});
}
if (typeof arguments[0] !== 'undefined' && arguments[0] === true) {
updateFunc();
} else {
modalEvent.info("수정", "병원 휴일 정보를 수정하시겠습니까?", updateFunc);
/****************************************************************************
* 병원 지정 휴일 선택 삭제 (체크된 row 삭제)
****************************************************************************/
function fn_deleteCheckedHolidays() {
let muHospitalId = $("#muHospitalId").val();
let checkedBoxes = $('input[name="checkHolidayRow"]:checked');
if (checkedBoxes.length === 0) {
modalEvent.danger("알림", "삭제할 휴일을 선택해주세요.");
return;
}
// 신규 row (ID가 없는 것)는 DOM에서 바로 제거, 기존 row는 서버에 삭제 요청
let idsToDelete = [];
let $newRows = $();
checkedBoxes.each(function () {
let holidayId = $(this).val();
if (holidayId && holidayId.trim() !== "") {
idsToDelete.push(holidayId.trim());
} else {
$newRows = $newRows.add($(this).closest('li'));
}
});
modalEvent.info("삭제", "선택한 휴일 " + checkedBoxes.length + "건을 삭제하시겠습니까?", function () {
// 신규 row는 DOM에서 즉시 제거
$newRows.remove();
if (idsToDelete.length > 0) {
// 기존 row는 서버에 삭제 요청
let formData = new FormData();
formData.append("menuClass", menuClass);
formData.append("muHospitalId", muHospitalId);
formData.append("holidayIds", idsToDelete.join(","));
$.ajax({
url: encodeURI('/webhospital/deleteHospitalHolidays.do'),
data: formData,
dataType: "json",
processData: false,
contentType: false,
type: 'POST',
success: function (data) {
if ('0' == data.msgCode) {
modalEvent.success("성공", "삭제되었습니다.", function () {
if (window.fcCalendar) {
window.fcCalendar.refetchEvents();
}
fn_selectHospitalJson();
});
} else {
modalEvent.danger("오류", data.msgDesc);
}
},
error: function () {
modalEvent.danger("오류", "삭제 중 오류가 발생했습니다.");
}
});
} else {
// 신규 row만 삭제한 경우
modalEvent.success("성공", "삭제되었습니다.");
// 남은 li가 헤더뿐이면 'no_data' 표시
if ($("#hospitalHolidayList li").not('.list_title_li').length === 0) {
$('#hospitalHolidayList').append('<li class="no_data" style="width: 100%; text-align: center; padding: 20px 0;">지정한 휴일이 없습니다.</li>');
}
}
});
}
$(function () {

View File

@@ -50,11 +50,11 @@
<!-- 탭 패널 추가 -->
<div class="tab_panel" role="tabpanel">
<!-- Nav tabs -->
<div class="nav_box">
<div class="nav_box" style="display: flex; align-items: center; justify-content: space-between;">
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active">
<a href="#schedule" aria-controls="schedule" role="tab" data-toggle="tab">
<p>병원 운영스케쥴</p>
<p>병원 캘린더</p>
</a>
</li>
<li role="presentation">
@@ -63,19 +63,28 @@
</a>
</li>
</ul>
<div style="display: flex; align-items: center; gap: 8px;">
<label for="currentCenterDivCd" style="font-size: 14px; font-weight: bold; white-space: nowrap;">센터
선택</label>
<select id="currentCenterDivCd" onchange="fn_switchCenter(this.value)"
style="width: 160px; height: 36px; border: 1px solid #ddd; border-radius: 5px; padding: 0 10px; font-size: 14px; cursor: pointer;">
<option value="DIET">다이어트센터</option>
<option value="PETIT">쁘띠센터</option>
</select>
</div>
</div>
<!-- Tab panes -->
<div class="tab-content">
<!-- 병원 운영스케쥴 탭 -->
<div role="tabpanel" class="tab-pane active" id="schedule">
<div class="info_box" style="display: flex; gap: 20px;">
<div class="info_box">
<!-- 좌측: 달력 & 법정공휴일 -->
<div class="info_left" style="width: 50%; min-width: auto;">
<div class="info_left">
<div class="form_box first">
<div class="hospital_box" style="margin-top: 0;">
<p class="title">병원 운영스케쥴</p>
<p class="title">병원 캘린더</p>
<!-- 달력 영역 -->
<div id='calendar' style="margin-bottom: 20px;"></div>
@@ -101,12 +110,12 @@
</div>
<!-- 우측: 병원지정 휴일 -->
<div class="info_right" style="width: 50%; min-width: auto;">
<div class="info_right">
<div class="form_box first">
<div class="hospital_box" style="margin-top: 0;">
<div class="hospital_title_box"
style="display: flex; justify-content: space-between; align-items: center;">
<p class="title" style="margin-bottom: 0; font-weight: bold; font-size: 16px;">
<p class="title" style="margin-bottom: 0; font-weight: bold;">
병원지정 휴일</p>
<div class="btn_group">
<button type="button" id="btnAddRow"
@@ -150,9 +159,9 @@
<!-- 운영시간 탭 -->
<div role="tabpanel" class="tab-pane" id="operatingHours">
<div class="info_box" style="display: flex; gap: 0;">
<div class="info_left"
style="width: 50%; min-width: auto; border-right: 1px solid #ddd; padding-right: 20px;">
<div class="info_box">
<div class="info_left">
<div class="form_box first">
<p class="title">운영시간</p>
@@ -658,7 +667,7 @@
</div>
</div>
<div class="info_right" style="width: 50%; min-width: auto; padding-left: 20px;">
<div class="info_right">
<div class="form_box first">
<div class="holiday_box" style="margin-top: 0; border-top: none; padding-top: 0;">
<p class="title" style="margin-bottom: 10px;">법정 공휴일</p>