진료유형 설정(전체보기 탭) 수정

This commit is contained in:
2026-02-24 16:36:29 +09:00
parent 04de663693
commit befcd92f2b
6 changed files with 404 additions and 33 deletions

View File

@@ -209,4 +209,44 @@ public class MedicalCategoryController extends ManagerDraftAction {
log.debug("MedicalCategoryController delMultiMedicalCategory END");
return map;
}
/**
* 진료유형 인라인(부분) 수정
*/
@PostMapping("/updatePartialMedicalCategory.do")
public HashMap<String, Object> updatePartialMedicalCategory(@RequestBody HashMap<String, Object> paramMap,
HttpServletRequest request) {
log.debug("MedicalCategoryController updatePartialMedicalCategory START");
HashMap<String, Object> map = new HashMap<>();
try {
map = medicalCategoryService.updatePartialMedicalCategory(paramMap);
} catch (Exception e) {
log.error("updatePartialMedicalCategory : ", e);
map.put("msgCode", Constants.FAIL);
map.put("msgDesc", "서버 오류가 발생했습니다.");
}
log.debug("MedicalCategoryController updatePartialMedicalCategory END");
return map;
}
/**
* 진료유형 인라인(부분) 여러건 일괄 수정 (전체보기 저장)
*/
@PostMapping("/updateBatchMedicalCategory.do")
public HashMap<String, Object> updateBatchMedicalCategory(@RequestBody List<MedicalCategoryDTO> list,
HttpServletRequest request) {
log.debug("MedicalCategoryController updateBatchMedicalCategory START");
HashMap<String, Object> map = new HashMap<>();
try {
map = medicalCategoryService.updateBatchMedicalCategory(list);
} catch (Exception e) {
log.error("updateBatchMedicalCategory : ", e);
map.put("msgCode", Constants.FAIL);
map.put("msgDesc", "서버 오류가 발생했습니다.");
}
log.debug("MedicalCategoryController updateBatchMedicalCategory END");
return map;
}
}

View File

@@ -59,6 +59,14 @@ public interface MedicalCategoryMapper {
*/
int getChildCategoryCount(HashMap<String, Object> paramMap);
/**
* 카테고리 정보 부분 수정 (인라인 에디팅)
*
* @param paramMap
* @return
*/
int updatePartialMedicalCategory(HashMap<String, Object> paramMap);
/**
* 거래처 목록 조회 (Depth 3 매핑용)
*

View File

@@ -91,6 +91,36 @@ public class MedicalCategoryService {
return roots;
}
/**
* 카테고리 정보 부분 다건 일괄 수정 (전체보기 저장)
*
* @param list
* @return
* @throws Exception
*/
public HashMap<String, Object> updateBatchMedicalCategory(List<MedicalCategoryDTO> list) throws Exception {
HashMap<String, Object> map = new HashMap<>();
try {
int successCount = 0;
for (MedicalCategoryDTO dto : list) {
// dto의 빈 값은 쿼리의 <if> 조건을 통과하지 않아 업데이트 되지 않음
successCount += medicalCategoryMapper.updateMedicalCategory(dto);
}
if (successCount > 0) {
map.put("msgCode", Constants.OK);
map.put("success", true);
map.put("msgDesc", successCount + "건이 수정되었습니다.");
} else {
map.put("msgCode", Constants.FAIL);
map.put("msgDesc", "수정 사항이 없거나 실패했습니다.");
}
} catch (Exception e) {
log.error("updateBatchMedicalCategory Error: ", e);
throw e;
}
return map;
}
/**
* 특정 카테고리 상세 정보 조회
*/
@@ -282,4 +312,30 @@ public class MedicalCategoryService {
return map;
}
/**
* 카테고리 정보 부분 수정 (인라인 에디팅)
*
* @param paramMap
* @return
* @throws Exception
*/
public HashMap<String, Object> updatePartialMedicalCategory(HashMap<String, Object> paramMap) throws Exception {
HashMap<String, Object> map = new HashMap<>();
try {
int result = medicalCategoryMapper.updatePartialMedicalCategory(paramMap);
if (result > 0) {
map.put("msgCode", Constants.OK);
map.put("success", true);
map.put("msgDesc", "수정되었습니다.");
} else {
map.put("msgCode", Constants.FAIL);
map.put("msgDesc", "수정 실패했습니다.");
}
} catch (Exception e) {
log.error("updatePartialMedicalCategory Error: ", e);
throw e;
}
return map;
}
}

View File

@@ -248,7 +248,31 @@
WHERE pid = #{pid}
</update>
<!-- 7. 거래처 목록 조회 (Depth 3 전용) -->
<!-- 7. 정보 부분 수정 Update -->
<update id="updatePartialMedicalCategory" parameterType="java.util.HashMap">
UPDATE medical_divi_list
<set>
<if test='updateField == "divi_name"'>
divi_name = #{updateValue},
</if>
<if test='updateField == "kind_cost"'>
kind_cost = #{updateValue},
</if>
<if test='updateField == "kind_unit"'>
kind_unit = #{updateValue},
</if>
<if test='updateField == "list_use"'>
list_use = #{updateValue},
</if>
<if test='updateField == "tax_free"'>
tax_free = #{updateValue},
</if>
up_date = NOW()
</set>
WHERE pid = #{pid}
</update>
<!-- 8. 거래처 목록 조회 (Depth 3 전용) -->
<select id="getCustList" parameterType="java.util.HashMap" resultType="java.util.HashMap">
SELECT pid,
cust_name,

View File

@@ -125,7 +125,7 @@ $(document).ready(function () {
index: "pid",
layout: "fitColumns",
placeholder: "상위 항목을 선택하세요.",
selectable: true,
selectableRows: true,
height: "100%",
columnDefaults: {
headerTooltip: true,
@@ -149,9 +149,6 @@ $(document).ready(function () {
columns: [
{ title: "순번", formatter: "rownum", width: 38, hozAlign: "center", headerSort: false, cssClass: "col-sm" },
{ title: "명칭", field: "divi_name", formatter: categoryNameFormatter, tooltip: true },
// { title: "거래처", field: "cust_name", width: 90, hozAlign: "center", tooltip: true },
// { title: "담당자(연락처)", field: "cust_contact", width: 110, hozAlign: "center", tooltip: true },
// { title: "단가", field: "kind_cost", width: 80, hozAlign: "right", formatter: costFormatter },
{ title: "순서", field: "divi_sort", width: 38, hozAlign: "center", cssClass: "col-sm" },
{ title: "하위", width: 50, hozAlign: "center", headerSort: false, formatter: function (c) { return addDescendantFormatter(c, 3); }, cellClick: function (e, cell) { e.stopPropagation(); var d = cell.getRow().getData(); addChildCategory(d.pid, 4, d.divi_name); } }
],
@@ -329,6 +326,14 @@ $(document).ready(function () {
function buildNodeMap(nodes) {
nodes.forEach(node => {
nodeMap[node.pid] = node;
// 편집 모드 진입 시 입력창(Input)에 기존 값이 제대로 표시되게 하기 위해
// 공통 피쳐인 divi_name 값을 각 뎁스별 전용 열 필드에 복사해 둡니다.
if (node.divi_dept == 2) node.divi_name2 = node.divi_name;
else if (node.divi_dept == 3) node.divi_name3 = node.divi_name;
else if (node.divi_dept == 4) node.divi_name4 = node.divi_name;
else if (node.divi_dept == 5) node.divi_name5 = node.divi_name;
if (node._children && node._children.length > 0) {
buildNodeMap(node._children);
} else if (node._children && node._children.length === 0) {
@@ -599,43 +604,172 @@ $(document).ready(function () {
function initOverviewGrid(callback) {
tableOverview = new Tabulator("#gridOverview", {
editTriggerEvent: "dblclick",
dataTree: true,
dataTreeElementColumn: "divi_name",
dataTreeStartExpanded: true,
dataTreeChildIndent: 0,
layout: "fitColumns",
placeholder: "데이터를 불러오는 중...",
height: "100%",
columnDefaults: {
headerTooltip: true,
headerHozAlign: "center",
tooltip: true
tooltip: true,
headerSort: false
},
columns: [
{ title: "1depth", field: "divi_name", width: "15%", hozAlign: "left", formatter: overviewDepthFormatter(1) },
{ title: "2depth", field: "divi_name2", width: "12%", hozAlign: "left", formatter: overviewDepthFormatter(2) },
{ title: "3depth", field: "divi_name3", width: "18%", hozAlign: "left", formatter: overviewDepthFormatter(3) },
{ title: "4depth", field: "divi_name4", width: "12%", hozAlign: "left", formatter: overviewDepthFormatter(4) },
{ title: "단가", field: "kind_cost", width: "10%", formatter: costFormatter, hozAlign: "right" },
{ title: "단위", field: "kind_unit", width: "10%", hozAlign: "center" },
{ title: "사용여부", field: "list_use", width: "10%", formatter: ynFormatter, hozAlign: "center" },
{ title: "면세여부", field: "tax_free", width: "8%", formatter: ynFormatter, hozAlign: "center" }
{ title: "진료과목", field: "divi_name", width: "6%", hozAlign: "left", formatter: overviewDepthFormatter(1), editor: "input", editable: function (cell) { return cell.getRow().getData().divi_dept == 1; }, cellClick: handleTreeToggleClick },
{ title: "진료유형", field: "divi_name2", width: "16.25%", hozAlign: "left", formatter: overviewDepthFormatter(2), editor: "input", editable: function (cell) { return cell.getRow().getData().divi_dept == 2; }, cellClick: handleTreeToggleClick },
{ title: "제품/시술", field: "divi_name3", width: "17.75%", hozAlign: "left", formatter: overviewDepthFormatter(3), editor: "input", editable: function (cell) { return cell.getRow().getData().divi_dept == 3; }, cellClick: handleTreeToggleClick },
{ title: "용량/출력", field: "divi_name4", width: "14.75%", hozAlign: "left", formatter: overviewDepthFormatter(4), editor: "input", editable: function (cell) { return cell.getRow().getData().divi_dept == 4; }, cellClick: handleTreeToggleClick },
{ title: "부위", field: "divi_name5", width: "14.75%", hozAlign: "left", formatter: overviewDepthFormatter(5), editor: "input", editable: function (cell) { return cell.getRow().getData().divi_dept == 5; }, cellClick: handleTreeToggleClick },
{ title: "깊이", field: "divi_dept", width: "4%", hozAlign: "center", editor: "number", editorParams: { min: 1, max: 5, step: 1 } },
{ title: "단가", field: "kind_cost", width: "10%", formatter: costFormatter, hozAlign: "right", editor: "number" },
{ title: "할인가", field: "dc_cost", width: "10%", formatter: costFormatter, hozAlign: "right", editor: "number" },
{ title: "단위", field: "kind_unit", width: "8%", hozAlign: "center", editor: "input" },
{ title: "사용여부", field: "list_use", width: "6%", formatter: ynFormatter, hozAlign: "center", editor: "list", editorParams: { values: { "y": "Y", "n": "N" } } },
{ title: "면세여부", field: "tax_free", width: "6%", formatter: ynFormatter, hozAlign: "center", editor: "list", editorParams: { values: { "y": "Y", "n": "N" } } }
]
});
function handleTreeToggleClick(e, cell) {
if ($(e.target).closest('.custom-tree-toggle').length > 0 || $(e.target).closest('.tabulator-data-tree-control').length > 0) {
cell.getRow().treeToggle();
}
}
tableOverview.on("tableBuilt", function () {
if (typeof callback === 'function') callback();
});
// 인라인 편집 후 임시 저장 처리 (일괄 저장)
tableOverview.on("cellEdited", function (cell) {
var field = cell.getField();
var val = (cell.getValue() || "").toString().trim();
var oldVal = (cell.getOldValue() || "").toString().trim();
if (val === oldVal) return;
// 진료과목~부위 빈값 검증
if (field.startsWith("divi_name")) {
if (val === "") {
alert("항목명은 비워둘 수 없습니다.");
cell.restoreOldValue();
return;
}
}
// 수정 발생 시 저장/취소 버튼 활성화
$("#btnSaveOverview, #btnCancelOverview").show();
});
}
// 전체보기 일괄 저장 / 취소 이벤트 바인딩
$(document).on("click", "#btnSaveOverview", function () {
var editedCells = tableOverview.getEditedCells();
if (editedCells.length === 0) {
alert("수정된 항목이 없습니다.");
return;
}
var updateMap = {};
editedCells.forEach(function (cell) {
var data = cell.getRow().getData();
var pid = data.pid;
var field = cell.getField();
var val = (cell.getValue() || "").toString().trim();
if (!updateMap[pid]) {
updateMap[pid] = { pid: pid };
}
if (field.startsWith("divi_name")) {
updateMap[pid].diviName = val;
} else if (field === "divi_dept") {
updateMap[pid].diviDept = val;
} else if (field === "kind_cost") {
updateMap[pid].kindCost = parseFloat(val || 0);
} else if (field === "kind_sale_cost") {
updateMap[pid].kindSaleCost = parseFloat(val || 0);
} else if (field === "kind_unit") {
updateMap[pid].kindUnit = val;
} else if (field === "list_use") {
updateMap[pid].listUse = val;
} else if (field === "tax_free") {
updateMap[pid].taxFree = val;
}
});
var updateList = Object.values(updateMap);
if (!confirm("수정된 " + updateList.length + "건의 항목을 저장하시겠습니까?")) return;
$.ajax({
url: '/settings/medicalCategory/updateBatchMedicalCategory.do',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(updateList),
success: function (res) {
if (res.msgCode === '0') {
alert(res.msgDesc || "저장되었습니다.");
$("#btnSaveOverview, #btnCancelOverview").hide();
window.onChangeDepth1Overview();
} else {
alert(res.msgDesc);
}
},
error: function () {
alert("저장 중 오류가 발생했습니다.");
}
});
});
$(document).on("click", "#btnCancelOverview", function () {
if (confirm("수정 중인 내용을 취소하시겠습니까? (원래 데이터로 복귀합니다)")) {
$("#btnSaveOverview, #btnCancelOverview").hide();
window.loadData(true);
}
});
// 도움말 버튼 토글 (전체보기)
$(document).on("click", "#btnHelpOverview", function () {
$("#overviewGuideBox").slideToggle(200);
});
// 도움말 버튼 토글 (진료유형 관리)
$(document).on("click", "#btnHelpManage", function () {
$("#manageGuideBox").slideToggle(200);
});
$(document).on("click", "#btnExpandAll", function () {
if (tableOverview) {
tableOverview.getRows().forEach(function (row) {
row.treeExpand();
});
}
});
$(document).on("click", "#btnCollapseAll", function () {
if (tableOverview) {
tableOverview.getRows().forEach(function (row) {
row.treeCollapse();
});
}
});
function overviewDepthFormatter(targetDepth) {
return function (cell) {
var data = cell.getRow().getData();
if (parseInt(data.divi_dept, 10) !== targetDepth) return '';
var row = cell.getRow();
var nameStyle = data.list_use === 'y' ? 'font-weight:600;' : 'text-decoration:line-through; color:#aaa;';
var color = data.divi_color || '#333';
if (data.list_use !== 'y') color = '#aaa';
var html = '<span style="' + nameStyle + ' color:' + color + '">' + (data.divi_name || '') + '</span>';
var val = cell.getValue() || data.divi_name || '';
var html = '<span style="' + nameStyle + ' color:' + color + '">' + val + '</span>';
if (data.tax_free === 'y') {
html += ' <span style="color:#ff0000; font-size:11px; margin-left: 5px;">[면세]</span>';

View File

@@ -12,6 +12,7 @@
<link rel="stylesheet" href="/css/web/grid.css?v1.1">
<link rel="stylesheet" href="https://unpkg.com/tabulator-tables@5.6.1/dist/css/tabulator.min.css">
<link rel="stylesheet" href="/css/web/categoryTree.css?v1.2">
<link rel="stylesheet" href="/css/web/hospital_info.css?v1.1">
<style>
.project_wrap .content_section .hospital_wrap .center_box .tab_panel {
height: 100%;
@@ -23,6 +24,16 @@
overflow: hidden;
}
/* 탭 내 그리드 헤더 배경색 변경 및 고정 */
#gridOverview .tabulator-header {
background-color: #EDF5FF !important;
border-bottom: 1px solid #ddd !important;
}
#gridOverview .tabulator-header .tabulator-col {
background-color: #EDF5FF !important;
}
.project_wrap .content_section .hospital_wrap .center_box .tab_panel .tab-content .tab-pane {
height: 100%;
overflow: hidden;
@@ -32,6 +43,36 @@
.project_wrap .content_section .hospital_wrap .center_box .filter_box .form_box .select_box {
margin-left: 0 !important;
}
/* 그리드 폭이 좁아질 때 Tabulator 공식 트리 아이콘(SVG)이 찌그러지는 현상 방지 */
#gridOverview .tabulator-row .tabulator-cell .tabulator-data-tree-branch,
#gridOverview .tabulator-row .tabulator-cell .tabulator-data-tree-control {
flex-shrink: 0 !important;
/* 공간이 부족해도 아이콘 원형 유지 */
}
#gridOverview .tabulator-row .tabulator-cell .tabulator-data-tree-control svg {
width: 14px !important;
min-width: 14px !important;
height: 14px !important;
min-height: 14px !important;
flex-shrink: 0 !important;
display: block !important;
}
/* dataTreeChildIndent: 0 에 추가로, 모든 트리 컨트롤의 고정 마진 제거 및 1뎁스 여백 완전 밀착 */
#gridOverview .tabulator-row .tabulator-cell .tabulator-data-tree-control {
margin-right: 4px !important;
/* 기호와 텍스트 사이 간격만 유지 */
margin-left: 0 !important;
}
/* 1뎁스(진료과목)의 들여쓰기 공간 완전 제거 */
#gridOverview .tabulator-row .tabulator-cell[tabulator-field="divi_name"] .tabulator-data-tree-control,
#gridOverview .tabulator-row .tabulator-cell[tabulator-field="divi_name"] .tabulator-data-tree-branch {
margin-left: 0 !important;
padding-left: 0 !important;
}
</style>
</th:block>
@@ -66,21 +107,44 @@
<!-- ===== 탭1: 진료유형 관리 ===== -->
<div role="tabpanel" class="tab-pane active" id="tabManage">
<div class="filter_box">
<div class="form_box">
<div class="select_list first">
<div class="select_box dropdown" id="depth1SelectBox">
<button type="button" class="label dropdown-toggle" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">진료과목 전체</button>
<input type="hidden" id="depth1Select">
<ul class="select_option_list dropdown-menu" id="depth1OptionList"></ul>
<div class="form_box"
style="display: flex; align-items: center; justify-content: space-between;">
<div style="display: flex; align-items: center; gap: 10px;">
<div class="select_list first" style="margin: 0;">
<div class="select_box dropdown" id="depth1SelectBox">
<button type="button" class="label dropdown-toggle" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">진료과목 전체</button>
<input type="hidden" id="depth1Select">
<ul class="select_option_list dropdown-menu" id="depth1OptionList"></ul>
</div>
</div>
<div class="right_btn_box" style="margin: 0;">
<button class="put_btn" onclick="addChildCategory('0', '1', '최상위 항목')">
<img src="/image/web/notice_btn_icon.svg" alt="추가">추가
</button>
</div>
</div>
<button type="button" id="btnHelpManage" class="grid-link-btn grid-link-add"
style="border: 1px solid #ccc; padding: 2px 8px; border-radius: 3px; font-size: 13px; height: 32px; line-height: 26px; color: #555; background: #fff; font-weight: 600;">도움말</button>
</div>
<div class="right_btn_box">
<button class="put_btn" onclick="addChildCategory('0', '1', '최상위 항목')">
<img src="/image/web/notice_btn_icon.svg" alt="추가">추가
</button>
</div>
<!-- 진료유형 관리 사용 가이드 (기본 숨김) -->
<div id="manageGuideBox"
style="display: none; margin-top: 15px; padding: 15px; background-color: #f8f9fa; border: 1px solid #e0e0e0; border-radius: 5px; font-size: 13px; color: #333; line-height: 1.6;">
<h5
style="margin-top: 0; margin-bottom: 10px; font-size: 15px; font-weight: 600; color: #1a73e8;">
💡 진료유형 관리 탭 사용 가이드</h5>
<ul style="padding-left: 20px; margin-bottom: 0;">
<li><b>조회 및 이동:</b> 좌측 표에서 항목을 <b>클릭</b>하면 우측 표에 해당 항목의 하위 데이터가 로드됩니다.</li>
<li><b>항목 추가:</b> 각 패널 우측 상단이나 그리드 안의 <b>[추가/등록]</b> 버튼을 눌러 새 하위 항목을 손쉽게 생성할 수 있습니다.
</li>
<li><b>상세 수정:</b> 표 안의 데이터를 <b>더블클릭</b>하면 상세 정보를 수정할 수 있는 팝업창이 열립니다.
</li>
<li><b>항목 삭제 (우클릭):</b> 삭제할 항목 위에서 <b>마우스 우클릭</b>을 하면 [삭제] 메뉴가 나타납니다. 하위 항목이 딸려있으면 삭제되지
않으므로 주의하세요.</li>
<li><b>다중 선택 (Shift / Ctrl):</b> <b>Shift + 클릭</b>으로 여러 범위를 한 번에 연속 선택하거나, <b>Ctrl +
클릭</b>으로 띄엄띄엄 다중 선택한 뒤 <b>우클릭 삭제</b>할 수 있습니다.</li>
</ul>
</div>
</div>
@@ -96,7 +160,7 @@
</div>
<!-- Depth 3: 제품 -->
<div class="category-tree-panel" style="flex:20; width:auto; min-width:0;">
<div class="category-tree-panel" style="flex:30; width:auto; min-width:0;">
<div class="tree-panel-header">
<span class="tree-panel-title">제품/시술</span>
<div class="tree-panel-actions" id="btnArea3"></div>
@@ -114,7 +178,7 @@
</div>
<!-- Depth 5: 부위 -->
<div class="category-tree-panel" style="flex:25; width:auto; min-width:0;">
<div class="category-tree-panel" style="flex:15; width:auto; min-width:0;">
<div class="tree-panel-header">
<span class="tree-panel-title">부위</span>
<div class="tree-panel-actions" id="btnArea5"></div>
@@ -127,8 +191,9 @@
<!-- ===== 탭2: 전체보기 ===== -->
<div role="tabpanel" class="tab-pane" id="tabOverview">
<div class="filter_box">
<div class="form_box">
<div class="select_list first">
<div class="form_box"
style="display: flex; align-items: center; justify-content: space-between;">
<div class="select_list first" style="display: flex; align-items: center; gap: 10px;">
<div class="select_box dropdown" id="depth1SelectBoxOverview">
<button type="button" class="label dropdown-toggle" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">진료과목 전체</button>
@@ -136,10 +201,53 @@
<ul class="select_option_list dropdown-menu" id="depth1OptionListOverview"></ul>
</div>
</div>
<button type="button" id="btnHelpOverview" class="grid-link-btn grid-link-add"
style="border: 1px solid #ccc; padding: 2px 8px; border-radius: 3px; font-size: 13px; height: 32px; line-height: 26px; color: #555; background: #fff; font-weight: 600;">도움말</button>
</div>
<!-- 전체보기 사용 가이드 (기본 숨김) -->
<div id="overviewGuideBox"
style="display: none; margin-top: 15px; padding: 15px; background-color: #f8f9fa; border: 1px solid #e0e0e0; border-radius: 5px; font-size: 13px; color: #333; line-height: 1.6;">
<h5
style="margin-top: 0; margin-bottom: 10px; font-size: 15px; font-weight: 600; color: #1a73e8;">
💡 전체보기 탭 사용 가이드</h5>
<ul style="padding-left: 20px; margin-bottom: 0;">
<li><b>데이터 수정 (더블클릭):</b> 수정하고자 하는 항목(명칭, 단가, 할인가 등)의 셀 위에서 <b>더블클릭</b>하면 즉시 입력창이 표시되어
데이터를 수정할 수 있습니다.</li>
<li><b>트리 작동 (+/-버튼):</b> 좌측의 <b>+ / - 버튼</b>을 클릭하면 하위 진료유형, 제품/시술, 용량/출력, 부위가 단계별로
펼쳐지거나 접힙니다.</li>
<li><b>일괄 저장:</b> 항목을 하나라도 수정하면 표 우측 상단에 <b>[일괄저장]</b><b>[일괄취소]</b> 버튼이 나타납니다. 여러 항목을
연속해서 수정한 뒤 마지막에 한 번만 저장하시면 됩니다.</li>
<li><b>취소:</b> 저장 전 <b>[일괄취소]</b>를 누르면 모든 수정 내역이 원래 상태로 되돌아갑니다.</li>
</ul>
</div>
</div>
<div id="gridOverview" style="width:100%; height:calc(100vh - 270px);"></div>
<div class="form_box first"
style="margin-top: 20px; height: calc(100vh - 290px); display: flex; flex-direction: column;">
<div class="hospital_box"
style="margin-top: 0; padding: 15px; border: 1px solid #ddd; border-radius: 5px; height: 100%; display: flex; flex-direction: column; overflow: hidden; background-color: #fff;">
<div
style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; flex-shrink: 0; min-height: 26px;">
<div style="display: flex; align-items: center; gap: 8px;">
<span class="tree-panel-title" style="font-size: 17px; margin: 0;">전체 진료유형</span>
<button type="button" id="btnExpandAll" class="grid-link-btn grid-link-add"
style="border: 1px solid #ccc; padding: 2px 8px; border-radius: 3px; font-size: 12px; height: 24px; line-height: 18px; color: #555; background: #fff;">전체펼치기</button>
<button type="button" id="btnCollapseAll" class="grid-link-btn grid-link-edit"
style="border: 1px solid #ccc; padding: 2px 8px; border-radius: 3px; font-size: 12px; height: 24px; line-height: 18px; color: #555; background: #fff;">전체접기</button>
</div>
<div class="tree-panel-actions" style="min-height: 26px; display: flex;">
<button type="button" id="btnSaveOverview" class="put_btn"
style="display: none;"><img src="/image/web/check.svg" alt="일괄저장"
style="filter: brightness(0) invert(1);">일괄저장</button>
<button type="button" id="btnCancelOverview" class="delete_btn"
style="display: none;"><img src="/image/web/close.svg" alt="일괄취소"
style="filter: brightness(0) invert(1);">일괄취소</button>
</div>
</div>
<div id="gridOverview" style="width: 100%; flex-grow: 1; border: 1px solid #e0e0e0;"></div>
</div>
</div>
</div>
</div>
</div>
@@ -151,7 +259,8 @@
<th:block layout:fragment="layout_script">
<script src="https://unpkg.com/tabulator-tables@5.6.1/dist/js/tabulator.min.js"></script>
<script th:src="@{/js/web/settings/medicalcategory/medicalCategoryList.js(v=202602223)}"></script>
<script th:src="@{/js/web/settings/medicalcategory/medicalCategoryList.js(v=202602296)}"></script>
</th:block>
</html>