그리드 컨트롤 수정
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
package com.madeu.crm.settings.medicalcategory.ctrl;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@@ -182,4 +184,29 @@ public class MedicalCategoryController extends ManagerDraftAction {
|
||||
log.debug("MedicalCategoryController delMedicalCategory END");
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 진료유형 다건 삭제
|
||||
*/
|
||||
@PostMapping("/delMultiMedicalCategory.do")
|
||||
public HashMap<String, Object> delMultiMedicalCategory(@RequestBody Map<String, List<String>> body) {
|
||||
log.debug("MedicalCategoryController delMultiMedicalCategory START");
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
|
||||
try {
|
||||
List<String> pidList = body.get("pidList");
|
||||
if (pidList == null || pidList.isEmpty()) {
|
||||
map.put("msgCode", Constants.FAIL);
|
||||
map.put("msgDesc", "삭제할 항목이 선택되지 않았습니다.");
|
||||
return map;
|
||||
}
|
||||
map = medicalCategoryService.deleteMultiMedicalCategory(pidList);
|
||||
} catch (Exception e) {
|
||||
log.error("delMultiMedicalCategory : ", e);
|
||||
map.put("msgCode", Constants.FAIL);
|
||||
map.put("msgDesc", "서버 오류가 발생했습니다.");
|
||||
}
|
||||
log.debug("MedicalCategoryController delMultiMedicalCategory END");
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,4 +212,74 @@ public class MedicalCategoryService {
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 카테고리 다건 삭제 (논리 삭제 처리)
|
||||
* 하위 항목이 있는 카테고리는 건너뛰고, 나머지만 삭제 처리
|
||||
*
|
||||
* @param pidList 삭제 대상 pid 목록
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public HashMap<String, Object> deleteMultiMedicalCategory(List<String> pidList) throws Exception {
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
int successCount = 0;
|
||||
int skipCount = 0;
|
||||
List<String> skippedNames = new ArrayList<>();
|
||||
|
||||
try {
|
||||
for (String pidStr : pidList) {
|
||||
HashMap<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("pid", pidStr);
|
||||
|
||||
// 하위 카테고리 존재 여부 확인
|
||||
int childCount = medicalCategoryMapper.getChildCategoryCount(paramMap);
|
||||
if (childCount > 0) {
|
||||
// 하위 항목이 있으면 건너뜀
|
||||
Map<String, Object> info = medicalCategoryMapper.getMedicalCategory(paramMap);
|
||||
if (info != null && info.get("divi_name") != null) {
|
||||
skippedNames.add(String.valueOf(info.get("divi_name")));
|
||||
}
|
||||
skipCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 삭제 처리
|
||||
int result = medicalCategoryMapper.deleteMedicalCategory(paramMap);
|
||||
if (result > 0) {
|
||||
successCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (successCount > 0) {
|
||||
map.put("msgCode", Constants.OK);
|
||||
map.put("success", true);
|
||||
} else {
|
||||
map.put("msgCode", Constants.FAIL);
|
||||
}
|
||||
|
||||
// 결과 메시지 구성
|
||||
StringBuilder msg = new StringBuilder();
|
||||
if (successCount > 0) {
|
||||
msg.append(successCount + "건 삭제되었습니다.");
|
||||
}
|
||||
if (skipCount > 0) {
|
||||
if (msg.length() > 0)
|
||||
msg.append("\n");
|
||||
msg.append(skipCount + "건은 하위 항목이 존재하여 건너뛰었습니다.");
|
||||
if (!skippedNames.isEmpty()) {
|
||||
msg.append("\n(" + String.join(", ", skippedNames) + ")");
|
||||
}
|
||||
}
|
||||
if (successCount == 0 && skipCount == 0) {
|
||||
msg.append("삭제할 항목이 없습니다.");
|
||||
}
|
||||
map.put("msgDesc", msg.toString());
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("deleteMultiMedicalCategory Error: ", e);
|
||||
throw e;
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,47 +30,77 @@ $(document).ready(function () {
|
||||
}
|
||||
});
|
||||
|
||||
// 메뉴 [삭제] 클릭 이벤트
|
||||
// 메뉴 [삭제] 클릭 이벤트 - 멀티셀렉트 지원
|
||||
$(document).on('click', '#customContextMenu .delete', function () {
|
||||
var menu = $('#customContextMenu');
|
||||
var pid = menu.data('pid');
|
||||
var name = menu.data('name');
|
||||
menu.hide();
|
||||
|
||||
if (!pid) return;
|
||||
if (!confirm("'" + name + "' 항목을 삭제하시겠습니까?\n하위 항목이 있을 경우 삭제되지 않습니다.")) return;
|
||||
if (!window.currentContextRow) return;
|
||||
|
||||
var contextTable = window.currentContextRow.getTable();
|
||||
var contextData = window.currentContextRow.getData();
|
||||
var selectedRows = contextTable.getSelectedRows();
|
||||
|
||||
// 우클릭한 행이 선택된 행 목록에 포함되어 있는지 확인
|
||||
var isContextRowSelected = selectedRows.some(function (r) {
|
||||
return r.getData().pid === contextData.pid;
|
||||
});
|
||||
|
||||
var targetRows;
|
||||
if (isContextRowSelected && selectedRows.length > 1) {
|
||||
// 멀티 선택 상태에서 선택된 행 중 하나를 우클릭한 경우 → 전체 선택 삭제
|
||||
targetRows = selectedRows;
|
||||
} else {
|
||||
// 단일 행 또는 선택되지 않은 행을 우클릭한 경우 → 해당 행만 삭제
|
||||
targetRows = [window.currentContextRow];
|
||||
}
|
||||
|
||||
var pidList = targetRows.map(function (r) { return r.getData().pid; });
|
||||
var nameList = targetRows.map(function (r) { return r.getData().divi_name; });
|
||||
|
||||
var confirmMsg;
|
||||
if (pidList.length === 1) {
|
||||
confirmMsg = "'" + nameList[0] + "' 항목을 삭제하시겠습니까?\n하위 항목이 있을 경우 삭제되지 않습니다.";
|
||||
} else {
|
||||
confirmMsg = pidList.length + "개 항목을 삭제하시겠습니까?\n(" + nameList.join(', ') + ")\n하위 항목이 있는 경우 해당 항목은 건너뜁니다.";
|
||||
}
|
||||
|
||||
if (!confirm(confirmMsg)) return;
|
||||
|
||||
if (pidList.length === 1) {
|
||||
// 단건 삭제 - 기존 API 사용
|
||||
$.ajax({
|
||||
url: '/settings/medicalCategory/delMedicalCategory.do',
|
||||
type: 'POST',
|
||||
data: { pid: pid },
|
||||
data: { pid: pidList[0] },
|
||||
success: function (res) {
|
||||
alert(res.msgDesc);
|
||||
if (res.msgCode === '0' && window.currentContextRow) {
|
||||
var tableId = window.currentContextRow.getTable().element.id;
|
||||
var isSelected = window.currentContextRow.isSelected();
|
||||
|
||||
// 1. 그리드에서 행 삭제
|
||||
window.currentContextRow.delete();
|
||||
|
||||
// 2. 만약 선택된 행이었다면, 우측 하위 패널 초기화
|
||||
if (isSelected) {
|
||||
if (tableId === 'gridDepth2') {
|
||||
table3.setData([]);
|
||||
table4.setData([]);
|
||||
$("#btnArea3").empty();
|
||||
$("#btnArea4").empty();
|
||||
} else if (tableId === 'gridDepth3') {
|
||||
table4.setData([]);
|
||||
$("#btnArea4").empty();
|
||||
}
|
||||
}
|
||||
if (res.msgCode === '0') {
|
||||
loadData(true);
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
alert("삭제 중 오류가 발생했습니다.");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 멀티 삭제
|
||||
$.ajax({
|
||||
url: '/settings/medicalCategory/delMultiMedicalCategory.do',
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({ pidList: pidList }),
|
||||
success: function (res) {
|
||||
alert(res.msgDesc);
|
||||
if (res.msgCode === '0') {
|
||||
loadData(true);
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
alert("삭제 중 오류가 발생했습니다.");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -94,7 +124,7 @@ $(document).ready(function () {
|
||||
index: "pid",
|
||||
layout: "fitColumns",
|
||||
placeholder: "상위 항목을 선택하세요.",
|
||||
selectable: 1,
|
||||
selectable: true,
|
||||
height: "100%",
|
||||
columnDefaults: {
|
||||
headerTooltip: true,
|
||||
@@ -102,18 +132,17 @@ $(document).ready(function () {
|
||||
}
|
||||
};
|
||||
|
||||
// Depth 2 Grid - 순번, 명칭, 순서, 관리, 하위
|
||||
// Depth 2 Grid - 순번, 명칭, 순서, 하위
|
||||
table2 = new Tabulator("#gridDepth2", Object.assign({}, commonOpts, {
|
||||
columns: [
|
||||
{ title: "순번", formatter: "rownum", width: 38, hozAlign: "center", headerSort: false, cssClass: "col-sm" },
|
||||
{ title: "명칭", field: "divi_name", formatter: categoryNameFormatter, tooltip: true },
|
||||
{ title: "순서", field: "divi_sort", width: 38, hozAlign: "center", cssClass: "col-sm" },
|
||||
{ title: "관리", width: 50, hozAlign: "center", headerSort: false, formatter: editFormatter, cellClick: function (e, cell) { e.stopPropagation(); editCategory(cell.getRow().getData().pid); } },
|
||||
{ title: "하위", width: 50, hozAlign: "center", headerSort: false, formatter: function (c) { return addDescendantFormatter(c, 2); }, cellClick: function (e, cell) { e.stopPropagation(); var d = cell.getRow().getData(); addChildCategory(d.pid, 3, d.divi_name); } }
|
||||
]
|
||||
}));
|
||||
|
||||
// Depth 3 Grid - 순번, 명칭, 거래처, 담당자(연락처), 단가, 순서, 관리, 하위
|
||||
// Depth 3 Grid - 순번, 명칭, 거래처, 담당자(연락처), 단가, 순서, 하위
|
||||
table3 = new Tabulator("#gridDepth3", Object.assign({}, commonOpts, {
|
||||
columns: [
|
||||
{ title: "순번", formatter: "rownum", width: 38, hozAlign: "center", headerSort: false, cssClass: "col-sm" },
|
||||
@@ -122,24 +151,65 @@ $(document).ready(function () {
|
||||
{ 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: editFormatter, cellClick: function (e, cell) { e.stopPropagation(); editCategory(cell.getRow().getData().pid); } },
|
||||
{ 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); } }
|
||||
]
|
||||
}));
|
||||
|
||||
// Depth 4 Grid - 순번, 명칭, 순서, 관리 (하위 없음)
|
||||
// Depth 4 Grid - 순번, 명칭, 순서 (하위 없음)
|
||||
table4 = new Tabulator("#gridDepth4", Object.assign({}, commonOpts, {
|
||||
columns: [
|
||||
{ title: "순번", formatter: "rownum", width: 38, hozAlign: "center", headerSort: false, cssClass: "col-sm" },
|
||||
{ title: "명칭", field: "divi_name", formatter: categoryNameFormatter, tooltip: true },
|
||||
{ title: "순서", field: "divi_sort", width: 38, hozAlign: "center", cssClass: "col-sm" },
|
||||
{ title: "관리", width: 50, hozAlign: "center", headerSort: false, formatter: editFormatter, cellClick: function (e, cell) { e.stopPropagation(); editCategory(cell.getRow().getData().pid); } }
|
||||
{ title: "순서", field: "divi_sort", width: 38, hozAlign: "center", cssClass: "col-sm" }
|
||||
]
|
||||
}));
|
||||
|
||||
table2.on("rowClick", function (e, row) { clickRow(row, 2); });
|
||||
table3.on("rowClick", function (e, row) { clickRow(row, 3); });
|
||||
table4.on("rowClick", function (e, row) { clickRow(row, 4); });
|
||||
// Shift+Click 범위 선택을 위한 마지막 클릭 행 추적
|
||||
var lastClickedRow = {};
|
||||
|
||||
function handleRowClick(e, row, table, depth) {
|
||||
var tableId = table.element.id;
|
||||
|
||||
if (e.shiftKey && lastClickedRow[tableId]) {
|
||||
// Shift+Click: 범위 선택
|
||||
var allRows = table.getRows();
|
||||
var startIdx = allRows.indexOf(lastClickedRow[tableId]);
|
||||
var endIdx = allRows.indexOf(row);
|
||||
if (startIdx === -1) startIdx = 0;
|
||||
|
||||
var from = Math.min(startIdx, endIdx);
|
||||
var to = Math.max(startIdx, endIdx);
|
||||
|
||||
table.deselectRow();
|
||||
for (var i = from; i <= to; i++) {
|
||||
allRows[i].select();
|
||||
}
|
||||
} else if (e.ctrlKey || e.metaKey) {
|
||||
// Ctrl+Click: 토글 선택
|
||||
row.toggleSelect();
|
||||
} else {
|
||||
// 일반 클릭: 단일 선택
|
||||
table.deselectRow();
|
||||
row.select();
|
||||
}
|
||||
|
||||
lastClickedRow[tableId] = row;
|
||||
clickRow(row, depth);
|
||||
}
|
||||
|
||||
table2.on("rowClick", function (e, row) { handleRowClick(e, row, table2, 2); });
|
||||
table3.on("rowClick", function (e, row) { handleRowClick(e, row, table3, 3); });
|
||||
table4.on("rowClick", function (e, row) { handleRowClick(e, row, table4, 4); });
|
||||
|
||||
|
||||
function onCellDblClick(e, cell) {
|
||||
if (cell.getField() === "divi_name") {
|
||||
editCategory(cell.getRow().getData().pid);
|
||||
}
|
||||
}
|
||||
table2.on("cellDblClick", onCellDblClick);
|
||||
table3.on("cellDblClick", onCellDblClick);
|
||||
table4.on("cellDblClick", onCellDblClick);
|
||||
|
||||
table2.on("rowContext", onRowContextMenu);
|
||||
table3.on("rowContext", onRowContextMenu);
|
||||
@@ -195,8 +265,6 @@ $(document).ready(function () {
|
||||
var data = row.getData();
|
||||
var children = data._children || [];
|
||||
|
||||
row.getTable().deselectRow();
|
||||
row.select();
|
||||
|
||||
if (depth === 2) {
|
||||
table3.setData(children).then(function () {
|
||||
|
||||
Reference in New Issue
Block a user