카테고리 관리 ui 변경
This commit is contained in:
@@ -34,6 +34,7 @@
|
|||||||
SELECT CATEGORY_NO
|
SELECT CATEGORY_NO
|
||||||
, CATEGORY_DIV_CD
|
, CATEGORY_DIV_CD
|
||||||
, CATEGORY_NM
|
, CATEGORY_NM
|
||||||
|
, ORDER_NO
|
||||||
, DATE_FORMAT(REG_DATE, '%Y-%m-%d %H:%i') AS REG_DATE
|
, DATE_FORMAT(REG_DATE, '%Y-%m-%d %H:%i') AS REG_DATE
|
||||||
FROM madeu.HP_CATEGORY
|
FROM madeu.HP_CATEGORY
|
||||||
<where>
|
<where>
|
||||||
@@ -64,14 +65,18 @@
|
|||||||
</select>
|
</select>
|
||||||
|
|
||||||
<insert id="putCategoryManagement" parameterType="hashmap">
|
<insert id="putCategoryManagement" parameterType="hashmap">
|
||||||
<selectKey resultType="string" keyProperty="categoryNo" order="BEFORE">
|
<selectKey resultType="hashmap" keyProperty="categoryNo,orderNo" order="BEFORE">
|
||||||
SELECT NVL(MAX(CATEGORY_NO),0) + 1 FROM HP_CATEGORY WHERE CATEGORY_DIV_CD = #{categoryDivCd}
|
SELECT IFNULL(MAX(CATEGORY_NO),0) + 1 as categoryNo
|
||||||
|
, CASE WHEN #{orderNo} IS NULL OR #{orderNo} = '' OR #{orderNo} = 0 THEN IFNULL(MAX(ORDER_NO),0) + 1 ELSE #{orderNo} END as orderNo
|
||||||
|
FROM HP_CATEGORY
|
||||||
|
WHERE CATEGORY_DIV_CD = #{categoryDivCd}
|
||||||
</selectKey>
|
</selectKey>
|
||||||
/** CategoryManagementSql.putCategoryManagement **/
|
/** CategoryManagementSql.putCategoryManagement **/
|
||||||
INSERT INTO HP_CATEGORY(
|
INSERT INTO HP_CATEGORY(
|
||||||
CATEGORY_NO
|
CATEGORY_NO
|
||||||
, CATEGORY_DIV_CD
|
, CATEGORY_DIV_CD
|
||||||
, CATEGORY_NM
|
, CATEGORY_NM
|
||||||
|
, ORDER_NO
|
||||||
, USE_YN
|
, USE_YN
|
||||||
, REG_ID
|
, REG_ID
|
||||||
, REG_DATE
|
, REG_DATE
|
||||||
@@ -81,6 +86,7 @@
|
|||||||
#{categoryNo},
|
#{categoryNo},
|
||||||
#{categoryDivCd},
|
#{categoryDivCd},
|
||||||
#{categoryNm},
|
#{categoryNm},
|
||||||
|
#{orderNo},
|
||||||
'Y',
|
'Y',
|
||||||
#{regId},
|
#{regId},
|
||||||
NOW(),
|
NOW(),
|
||||||
@@ -93,6 +99,7 @@
|
|||||||
/** CategoryManagementSql.modCategoryManagement **/
|
/** CategoryManagementSql.modCategoryManagement **/
|
||||||
UPDATE HP_CATEGORY
|
UPDATE HP_CATEGORY
|
||||||
SET CATEGORY_NM = #{categoryNm}
|
SET CATEGORY_NM = #{categoryNm}
|
||||||
|
,ORDER_NO = #{orderNo}
|
||||||
,MOD_ID = #{modId}
|
,MOD_ID = #{modId}
|
||||||
,MOD_DATE = NOW()
|
,MOD_DATE = NOW()
|
||||||
WHERE CATEGORY_NO = #{categoryNo}
|
WHERE CATEGORY_NO = #{categoryNo}
|
||||||
|
|||||||
399
src/main/resources/static/css/web/categoryTree.css
Normal file
399
src/main/resources/static/css/web/categoryTree.css
Normal file
@@ -0,0 +1,399 @@
|
|||||||
|
/* ===================================================================
|
||||||
|
카테고리 트리 레이아웃 스타일
|
||||||
|
=================================================================== */
|
||||||
|
|
||||||
|
/* 트리 + 상세 패널 레이아웃 */
|
||||||
|
.category-tree-layout {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 140px);
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- 좌측 트리 패널 ---- */
|
||||||
|
.category-tree-panel {
|
||||||
|
width: 380px;
|
||||||
|
min-width: 300px;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #E9ECF0;
|
||||||
|
border-radius: 8px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-panel-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border-bottom: 1px solid #E9ECF0;
|
||||||
|
background: #fff;
|
||||||
|
/* 밝게 변경 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-panel-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-panel-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-sub-header {
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-bottom: 1px solid #E9ECF0;
|
||||||
|
justify-content: flex-start;
|
||||||
|
/* Changed to Left Align */
|
||||||
|
background: #fff;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-action-btn {
|
||||||
|
padding: 2px 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #666;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Button styles in Tree Header */
|
||||||
|
.tree-panel-actions,
|
||||||
|
.tree-sub-header {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-panel-actions .tree-action-btn,
|
||||||
|
.tree-panel-actions .put_btn,
|
||||||
|
.tree-panel-actions .delete_btn,
|
||||||
|
.tree-sub-header .tree-action-btn {
|
||||||
|
float: none !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 2px 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
height: 26px;
|
||||||
|
/* Unified height */
|
||||||
|
line-height: normal;
|
||||||
|
border-radius: 4px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-panel-actions .put_btn img,
|
||||||
|
.tree-panel-actions .delete_btn img {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
margin: 0;
|
||||||
|
position: static !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Specific colors */
|
||||||
|
.tree-panel-actions .put_btn {
|
||||||
|
background: #3985EA;
|
||||||
|
color: #fff;
|
||||||
|
border: 1px solid #3985EA;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-panel-actions .delete_btn {
|
||||||
|
background: #FF2222;
|
||||||
|
color: #fff;
|
||||||
|
border: 1px solid #FF2222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-panel-actions .tree-action-btn {
|
||||||
|
background: #fff;
|
||||||
|
color: #666;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.tree-action-btn:hover {
|
||||||
|
background: #3985EA;
|
||||||
|
/* Primary Blue */
|
||||||
|
color: #fff;
|
||||||
|
border-color: #3985EA;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-tree-container {
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
/* Changed from auto to hidden to prevent double scrollbars with Tabulator */
|
||||||
|
padding: 0;
|
||||||
|
/* Padding 제거 (Tabulator가 꽉 차게) */
|
||||||
|
}
|
||||||
|
|
||||||
|
#categoryTreeContainer {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Active Row Highlight */
|
||||||
|
.tabulator-row.row-active {
|
||||||
|
background-color: #e6f7ff !important;
|
||||||
|
/* Light Blue */
|
||||||
|
font-weight: bold;
|
||||||
|
color: #1890ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ---- 우측 상세 패널 ---- */
|
||||||
|
.category-detail-panel {
|
||||||
|
flex: 1;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #E9ECF0;
|
||||||
|
border-radius: 8px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-panel-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border-bottom: 1px solid #E9ECF0;
|
||||||
|
background: #fff;
|
||||||
|
/* 밝게 변경 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-panel-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-panel-content {
|
||||||
|
flex: 1;
|
||||||
|
padding: 20px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-empty-state {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100%;
|
||||||
|
color: #999;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 폼 스타일 */
|
||||||
|
.detail-form-group {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-form-group label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-form-input,
|
||||||
|
.detail-form-select {
|
||||||
|
width: 100%;
|
||||||
|
height: 38px;
|
||||||
|
padding: 0 12px;
|
||||||
|
border: 1px solid #E9ECF0;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333;
|
||||||
|
background: #fff;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-form-input:focus,
|
||||||
|
.detail-form-select:focus {
|
||||||
|
border-color: #3985EA;
|
||||||
|
outline: none;
|
||||||
|
box-shadow: 0 0 0 3px rgba(57, 133, 234, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-form-input[readonly] {
|
||||||
|
background: #f5f5f5;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-form-select {
|
||||||
|
appearance: none;
|
||||||
|
background: #fff url('/image/web/select_arrow.svg') no-repeat right 10px center;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-form-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-save-btn {
|
||||||
|
padding: 8px 24px;
|
||||||
|
background: #3985EA;
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-save-btn:hover {
|
||||||
|
background: #2c6fd1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-cancel-btn {
|
||||||
|
padding: 8px 24px;
|
||||||
|
background: #fff;
|
||||||
|
color: #666;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-cancel-btn:hover {
|
||||||
|
background: #f5f5f5;
|
||||||
|
border-color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 상세정보 표시 */
|
||||||
|
.detail-info-group {
|
||||||
|
margin-bottom: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-info-label {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #999;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-info-value {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333;
|
||||||
|
padding: 8px 12px;
|
||||||
|
background: #f8f9fb;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ===================================================================
|
||||||
|
Tabulator Custom Styling (Light Theme)
|
||||||
|
=================================================================== */
|
||||||
|
.tabulator {
|
||||||
|
border: none;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header */
|
||||||
|
.tabulator .tabulator-header {
|
||||||
|
background-color: #fff;
|
||||||
|
border-bottom: 1px solid #E9ECF0;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #494E53;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabulator .tabulator-header .tabulator-col {
|
||||||
|
background-color: #fff;
|
||||||
|
border-right: 1px solid #E9ECF0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabulator .tabulator-header .tabulator-col-content {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Rows */
|
||||||
|
.tabulator .tabulator-row {
|
||||||
|
background-color: #fff;
|
||||||
|
border-bottom: 1px solid #E9ECF0;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabulator .tabulator-row:nth-child(even) {
|
||||||
|
background-color: #fff;
|
||||||
|
/* Zebra striping 제거 혹은 연하게 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabulator .tabulator-row:hover {
|
||||||
|
background-color: rgba(57, 133, 234, 0.05) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabulator .tabulator-row.tabulator-selected {
|
||||||
|
background-color: rgba(57, 133, 234, 0.1) !important;
|
||||||
|
border-color: #3985EA;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabulator .tabulator-cell {
|
||||||
|
padding: 8px 10px;
|
||||||
|
border-right: 1px solid #E9ECF0;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Group Headers */
|
||||||
|
.tabulator .tabulator-group {
|
||||||
|
background-color: #f8f9fb !important;
|
||||||
|
border-bottom: 1px solid #E9ECF0;
|
||||||
|
border-top: 1px solid #E9ECF0;
|
||||||
|
color: #2c3e50;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 8px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabulator .tabulator-group:hover {
|
||||||
|
background-color: #f0f2f5 !important;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Checkbox (Row Selection) */
|
||||||
|
.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title input[type=checkbox],
|
||||||
|
.tabulator .tabulator-cell input[type=checkbox] {
|
||||||
|
accent-color: #3985EA;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ---- 반응형 ---- */
|
||||||
|
@media only screen and (max-width:1280px) {
|
||||||
|
.category-tree-panel {
|
||||||
|
width: 280px;
|
||||||
|
min-width: 240px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-tree-layout {
|
||||||
|
height: calc(100% - 120px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width:1080px) {
|
||||||
|
.category-tree-layout {
|
||||||
|
flex-direction: column;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-tree-panel {
|
||||||
|
width: 100%;
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-detail-panel {
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,34 +1,88 @@
|
|||||||
/* 페이징 관련 변수 */
|
/**
|
||||||
let webCategoryTotalCount = 0;
|
* CategoryManagement.js
|
||||||
let webCategoryTotalPages = 0;
|
* Tabulator library based implementation
|
||||||
|
*/
|
||||||
|
|
||||||
/*aggird*/
|
// Global Table Instance
|
||||||
let webCategoryAgGridData = [];
|
let categoryTable = null;
|
||||||
|
let categoryList = []; // Full flat list from server
|
||||||
|
|
||||||
/* 삭제할 항목들 */
|
// Category division map for labels
|
||||||
let delList = [];
|
const categoryDivMap = {
|
||||||
|
"01": "다이어트 시술",
|
||||||
|
"02": "다이어트 이벤트",
|
||||||
|
"03": "쁘띠 시술",
|
||||||
|
"04": "쁘띠 이벤트",
|
||||||
|
"05": "다이어트 전후사진",
|
||||||
|
"06": "쁘띠 전후사진"
|
||||||
|
};
|
||||||
|
|
||||||
/* 등록 버튼 이중 클릭 방지 플래그 */
|
// Initialize
|
||||||
let isInsertBtnDisabled = false;
|
$(function () {
|
||||||
|
fn_init();
|
||||||
|
fn_initEvent();
|
||||||
|
});
|
||||||
|
|
||||||
/****************************************************************************
|
function fn_init() {
|
||||||
* 카테고리 정보 리스트 조회
|
// Initial load
|
||||||
****************************************************************************/
|
fn_searchCategoryList();
|
||||||
function fn_selectListwebCategoryJson(){
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function fn_initEvent() {
|
||||||
|
// Expand/Collapse All (Groups)
|
||||||
|
$("#btnExpandAll").click(function () {
|
||||||
|
if (categoryTable) {
|
||||||
|
console.log("Expanding all groups...");
|
||||||
|
categoryTable.blockRedraw();
|
||||||
|
categoryTable.getGroups().forEach(group => group.show());
|
||||||
|
categoryTable.restoreRedraw();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#btnCollapseAll").click(function () {
|
||||||
|
if (categoryTable) {
|
||||||
|
console.log("Collapsing all groups...");
|
||||||
|
categoryTable.blockRedraw();
|
||||||
|
categoryTable.getGroups().forEach(group => group.hide());
|
||||||
|
categoryTable.restoreRedraw();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// CRUD Buttons (Top)
|
||||||
|
$("#btnInsertWebCategory").click(function () {
|
||||||
|
fn_showInsertForm();
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#btnDeleteWebCategory").click(function () {
|
||||||
|
fn_deleteCategory();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Form Buttons
|
||||||
|
$("#btnSaveCategory").click(fn_insertCategory);
|
||||||
|
$("#btnCancelInsert").click(fn_hideDetailPanel);
|
||||||
|
|
||||||
|
$("#btnUpdateCategory").click(fn_updateCategory);
|
||||||
|
$("#btnCancelEdit").click(fn_hideDetailPanel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch Data
|
||||||
|
*/
|
||||||
|
function fn_searchCategoryList() {
|
||||||
let formData = new FormData();
|
let formData = new FormData();
|
||||||
formData.append("menuClass", menuClass);
|
formData.append("menuClass", menuClass);
|
||||||
// gridSort에 categoryNm가 들어오면 CATEGORY_NM로 변환
|
|
||||||
let sortValue = webCategorySort;
|
// Server expects gridLimitStart/End for pagination, sending large range for All data
|
||||||
if (sortValue && sortValue.indexOf('categoryNm') !== -1) {
|
formData.append("gridLimitStart", 0);
|
||||||
sortValue = sortValue.replace(/categoryNm/g, 'CATEGORY_NM');
|
formData.append("gridLimitEnd", 100000);
|
||||||
}
|
|
||||||
formData.append("gridSort", sortValue);
|
// Search filters (Removed)
|
||||||
formData.append("gridLimitStart", webCategoryStart || 0);
|
formData.append("searchCategoryDivCd", "");
|
||||||
formData.append("gridLimitEnd", webCategoryLimit || 10);
|
formData.append("searchCategoryNm", "");
|
||||||
formData.append("categoryDivCd", categoryDivCd);
|
|
||||||
formData.append("categoryNm", categoryNm);
|
// Sort
|
||||||
formData.append("searchCategoryDivCd", $("#searchCategoryDivCd").val());
|
formData.append("gridSort", "CATEGORY_DIV_CD ASC, CATEGORY_NM ASC");
|
||||||
formData.append("searchCategoryNm", $("#searchCategoryNm").val());
|
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: encodeURI('/categoryManagement/getCategoryManagementList.do'),
|
url: encodeURI('/categoryManagement/getCategoryManagementList.do'),
|
||||||
@@ -37,513 +91,277 @@ function fn_selectListwebCategoryJson(){
|
|||||||
processData: false,
|
processData: false,
|
||||||
contentType: false,
|
contentType: false,
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
async: true,
|
|
||||||
success: function (data) {
|
success: function (data) {
|
||||||
if('0'==data.msgCode){
|
if (data.msgCode === '0' || data.success === 'true') {
|
||||||
// 페이징 처리
|
categoryList = data.rows || [];
|
||||||
webCategoryTotalCount = data.totalCount;
|
fn_renderTable(categoryList);
|
||||||
//$("#txt_noticeTotalCount").text(noticeTotalCount);
|
fn_hideDetailPanel();
|
||||||
|
} else {
|
||||||
webCategoryTotalPages = Math.ceil(webCategoryTotalCount/webCategoryLimit);
|
alert(data.msgDesc || "조회 중 오류가 발생했습니다.");
|
||||||
|
|
||||||
// 리스트 조회
|
|
||||||
webCategoryAgGridData = data.rows;
|
|
||||||
webCategoryGridOptions.api.setRowData(webCategoryAgGridData);
|
|
||||||
|
|
||||||
if(0<data.rows.length){
|
|
||||||
//페이징 처리
|
|
||||||
window.pagObj = $('#webCategoryPagination').twbsPagination({
|
|
||||||
startPage : ((webCategoryStart/webCategoryLimit)+1),
|
|
||||||
totalPages : (webCategoryTotalPages==0)?1:webCategoryTotalPages,
|
|
||||||
visiblePages : 10,
|
|
||||||
initiateStartPageClick: false,
|
|
||||||
prev : '<img src="/image/web/page_navigation_arrow.svg" alt="prev"/>',
|
|
||||||
next : '<img src="/image/web/page_navigation_arrow.svg" alt="next"/>',
|
|
||||||
first : '',
|
|
||||||
last : '',
|
|
||||||
onPageClick: function (Category, page) {
|
|
||||||
fn_webCategoryPagination(page);
|
|
||||||
}
|
|
||||||
}).on('page', function (Category, page) {
|
|
||||||
//console.info(page + ' (from Category listening)');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
modalEvent.danger("조회 오류", data.msgDesc);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error : function(xhr, status, error) {
|
error: function () {
|
||||||
modalEvent.danger("조회 오류", "조회 중 오류가 발생하였습니다. 잠시후 다시시도하십시오.");
|
alert("서버 통신 오류가 발생했습니다.");
|
||||||
},
|
|
||||||
beforeSend:function(){
|
|
||||||
// 로딩열기
|
|
||||||
webCategoryGridOptions.api.showLoadingOverlay();
|
|
||||||
},
|
|
||||||
complete:function(){
|
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
// Render Tabulator
|
||||||
* 검색하기
|
function fn_renderTable(list) {
|
||||||
****************************************************************************/
|
// Pre-process list to strip HTML tags for display if needed,
|
||||||
function fn_webCategorySearch(param){
|
// or we can use a formatter. Let's use a simple formatter.
|
||||||
if("A"!=param && "Y"!=selectUseYn){
|
|
||||||
modalEvent.warning("", "조회 권한이 없습니다.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn_webCategoryPaginReset();
|
categoryTable = new Tabulator("#categoryTreeContainer", {
|
||||||
|
data: list,
|
||||||
categoryDivCd = $("#searchCategoryDivCd").val();
|
layout: "fitColumns",
|
||||||
categoryNm = $("#searchCategoryNm").val();
|
selectableRows: false, // Updated: Only select via checkbox
|
||||||
|
groupBy: "categoryDivCd",
|
||||||
fn_selectListwebCategoryJson();
|
groupStartOpen: true, // Default to Expanded
|
||||||
}
|
groupHeader: function (value, count, data, group) {
|
||||||
|
// Custom Header: "Division Name (Count)"
|
||||||
|
let label = categoryDivMap[value] || value;
|
||||||
/****************************************************************************
|
return label + " (" + count + ")";
|
||||||
* 초기화하기
|
},
|
||||||
****************************************************************************/
|
columns: [
|
||||||
function fn_webCategoryReset(){
|
|
||||||
$("#searchCategoryDivCd").val("");
|
|
||||||
$("#searchCategoryNm").val("");
|
|
||||||
fn_webCategorySearch();
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* 페이징 처리
|
|
||||||
****************************************************************************/
|
|
||||||
function fn_webCategoryPagination(param){
|
|
||||||
webCategoryStart = (parseInt(param)-1)*webCategoryLimit;
|
|
||||||
|
|
||||||
fn_selectListwebCategoryJson();
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* 페이징 리셋
|
|
||||||
****************************************************************************/
|
|
||||||
function fn_webCategoryPaginReset(){
|
|
||||||
branchOfficeCd = '';
|
|
||||||
mbName = '';
|
|
||||||
mbHp = '';
|
|
||||||
opinionClassificationCd = '';
|
|
||||||
|
|
||||||
webCategoryStart = 0;
|
|
||||||
webCategoryLimit = 100;
|
|
||||||
webCategoryTotalCount = 0;
|
|
||||||
webCategoryTotalPages = 0;
|
|
||||||
|
|
||||||
//페이징 초기화
|
|
||||||
if($("#webCategoryPagination").data("twbs-pagination")){
|
|
||||||
$("#webCategoryPagination").twbsPagination("destroy");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* 검색 엔터 카테고리
|
|
||||||
****************************************************************************/
|
|
||||||
function fn_webCategoryEnter(e){
|
|
||||||
if(e.which){
|
|
||||||
// 파이어폭스
|
|
||||||
if(13 == e.which) {
|
|
||||||
//로그인 액션 스크립트
|
|
||||||
fn_webCategorySearch();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
// 윈도우, 사파리, 크롬
|
|
||||||
if(13 == Category.keyCode) {
|
|
||||||
//로그인 액션 스크립트
|
|
||||||
fn_webCategorySearch();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* 완료
|
|
||||||
****************************************************************************/
|
|
||||||
function fn_webCategoryOk(){
|
|
||||||
isInsertBtnDisabled = false;
|
|
||||||
$("#btnInsertWebCategory").prop('disabled', false);
|
|
||||||
fn_webCategoryReset();
|
|
||||||
}
|
|
||||||
// JavaScript
|
|
||||||
// Category division options
|
|
||||||
let categoryDivOptions = [
|
|
||||||
{ value: "01", label: "다이어트 시술" },
|
|
||||||
{ value: "02", label: "다이어트 이벤트" },
|
|
||||||
{ value: "03", label: "쁘띠 시술" },
|
|
||||||
{ value: "04", label: "쁘띠 이벤트" },
|
|
||||||
{ value: "05", label: "다이어트 전후사진" },
|
|
||||||
{ value: "06", label: "쁘띠 전후사진" }
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
let webCategoryColumnDefs = [
|
|
||||||
{field: "checkbox", headerName:"", minWidth:55, maxWidth:55, headerCheckboxSelection: true, checkboxSelection: true},
|
|
||||||
{
|
{
|
||||||
field: "categoryDivCd",
|
formatter: "rowSelection",
|
||||||
headerName: "카테고리구분",
|
titleFormatter: "rowSelection",
|
||||||
minWidth: 150,
|
headerSort: false,
|
||||||
maxWidth: 200,
|
width: 40,
|
||||||
cellStyle: {
|
hozAlign: "center",
|
||||||
display: 'flex',
|
headerHozAlign: "center",
|
||||||
alignItems: 'center',
|
cellClick: function (e, cell) {
|
||||||
justifyContent: 'center'
|
cell.getRow().toggleSelect();
|
||||||
},
|
|
||||||
cellRenderer: function(params) {
|
|
||||||
let found = categoryDivOptions.find(opt => opt.value === params.value);
|
|
||||||
return found ? found.label : params.value;
|
|
||||||
},
|
|
||||||
// Make editable only for new rows (regDate is empty)
|
|
||||||
editable: function(params) {
|
|
||||||
// 신규행(regDate 없음)이고 등록중 플래그가 있거나, 둘 중 하나라도 값이 없으면 false
|
|
||||||
if (!params.data.regDate) {
|
|
||||||
if (params.data._isRegistering) return false;
|
|
||||||
// 둘 중 하나라도 값이 없으면(입력 중)만 true, 둘 다 값이 있으면 false
|
|
||||||
if (!params.data.categoryDivCd || !params.data.categoryNm) return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// 다른 행: 그리드에 신규행이 있고, 그 신규행이 입력 중이거나 등록중이면 수정 불가
|
|
||||||
let rowData = [];
|
|
||||||
params.api.forEachNode(function(node) {
|
|
||||||
rowData.push(node.data);
|
|
||||||
});
|
|
||||||
let hasNewRowEditing = rowData.some(row => !row.regDate && (!row.categoryDivCd || !row.categoryNm || row._isRegistering));
|
|
||||||
if (hasNewRowEditing) return false;
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
cellEditor: 'agSelectCellEditor',
|
|
||||||
cellEditorParams: {
|
|
||||||
values: categoryDivOptions.map(opt => opt.label)
|
|
||||||
},
|
|
||||||
valueSetter: function(params) {
|
|
||||||
let found = categoryDivOptions.find(opt => opt.label === params.newValue);
|
|
||||||
if (found) {
|
|
||||||
params.data.categoryDivCd = found.value;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
title: "카테고리명",
|
||||||
field: "categoryNm",
|
field: "categoryNm",
|
||||||
headerName: "카테고리명",
|
headerSort: false,
|
||||||
minWidth: 200,
|
formatter: function (cell) {
|
||||||
maxWidth: 300,
|
// Strip HTML tags
|
||||||
cellStyle: {
|
let val = cell.getValue();
|
||||||
display: 'flex',
|
return val ? String(val).replace(/<[^>]*>?/gm, '') : '';
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center'
|
|
||||||
},
|
},
|
||||||
// 신규행이 등록중이거나 입력이 덜 된 경우 수정 불가
|
cellClick: function (e, cell) {
|
||||||
editable: function(params) {
|
// Handle Cell Click -> Edit
|
||||||
// 신규행: 입력(값이 없을 때)만 가능, 입력이 끝나면(둘 다 값이 있으면) 수정 불가, 등록중에도 수정 불가
|
const row = cell.getRow();
|
||||||
if (!params.data.regDate) {
|
const item = row.getData();
|
||||||
if (params.data._isRegistering) return false;
|
|
||||||
// 둘 중 하나라도 값이 없으면 true(입력 가능), 둘 다 값이 있으면 false(수정 불가)
|
// Highlight Row
|
||||||
if (!params.data.categoryDivCd || !params.data.categoryNm) return true;
|
if (categoryTable) {
|
||||||
return false;
|
const rows = categoryTable.getRows();
|
||||||
|
rows.forEach(r => r.getElement().classList.remove("row-active"));
|
||||||
|
row.getElement().classList.add("row-active");
|
||||||
}
|
}
|
||||||
// 신규행이 등록중이거나 입력 중이면 다른 행은 수정 불가
|
|
||||||
let rowData = [];
|
console.log("Name Cell Clicked:", item);
|
||||||
params.api.forEachNode(function(node) {
|
fn_showEditForm(item);
|
||||||
rowData.push(node.data);
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
// rowClick was causing issues with selection/edit overlap.
|
||||||
|
// Moved to specific cellClick handlers.
|
||||||
});
|
});
|
||||||
let hasNewRowEditing = rowData.some(row => !row.regDate && (!row.categoryDivCd || !row.categoryNm || row._isRegistering));
|
|
||||||
if (hasNewRowEditing) return false;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{ field: "regDate", headerName:"등록일", minWidth: 130, maxWidth: 150, editable: false,
|
|
||||||
cellStyle: {
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center'
|
|
||||||
},
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
// let the grid know which columns and what data to use
|
|
||||||
let webCategoryGridOptions = {
|
|
||||||
suppressRowTransform: true,
|
|
||||||
columnDefs: webCategoryColumnDefs,
|
|
||||||
defaultColDef: { // 리스트 기본 설정
|
|
||||||
flex: 1,
|
|
||||||
sortable: true, //정렬 여부
|
|
||||||
resizable: true, //리사이즈
|
|
||||||
cellStyle:{
|
|
||||||
textAlign:'left',
|
|
||||||
fontSize:'14px',
|
|
||||||
lineHeight:'16px',
|
|
||||||
whiteSpace:'normal',
|
|
||||||
padding:'0'
|
|
||||||
},
|
|
||||||
//suppressSizeToFit:true, //자동 맞춤
|
|
||||||
//enableRowGroup: true, // 그룹 묶음
|
|
||||||
enablePivot: true,
|
|
||||||
enableValue : true,
|
|
||||||
wrapText: true, // 텍스트 줄바꿈
|
|
||||||
autoHeight: true
|
|
||||||
},
|
|
||||||
//suppressMultiSort:true, //단일솔트 true가 단일, false가 다중 shift + sort 시
|
|
||||||
headerHeight : 41, // header 높이
|
|
||||||
//rowHeight : 41, // row 높이
|
|
||||||
rowData : webCategoryAgGridData,
|
|
||||||
suppressRowClickSelection : true, // 로우 클릭시 체크박스 선택 true no, false yes
|
|
||||||
localeText : {
|
|
||||||
noRowsToShow : '조회 결과가 없습니다.'
|
|
||||||
}, //데이터 없을 시 나오는 문구
|
|
||||||
rowSelection : 'multiple', // row 다중 선택
|
|
||||||
debug : false,
|
|
||||||
onSelectionChanged: function(Category){
|
|
||||||
delList = Category.api.getSelectedRows();
|
|
||||||
},
|
|
||||||
onSortChanged: function(Category){
|
|
||||||
//정렬
|
|
||||||
webCategorySort = ''; //기존 정렬 초기화
|
|
||||||
let columnArr = Category.columnApi.getColumnState();
|
|
||||||
if(0<columnArr.length){
|
|
||||||
//sort index 순으로 재정렬
|
|
||||||
columnArr.sort(function(a,b){
|
|
||||||
return a.sortIndex - b.sortIndex;
|
|
||||||
});
|
|
||||||
|
|
||||||
let nullCnt = 0;
|
/**
|
||||||
for(let i=0; i<columnArr.length; i++){
|
* Detail Panel: Hide All
|
||||||
let gridSortModel = columnArr[i].colId;
|
*/
|
||||||
let gridSort = columnArr[i].sort;
|
function fn_hideDetailPanel() {
|
||||||
|
$("#categoryInsertForm").hide();
|
||||||
|
$("#categoryEditForm").hide();
|
||||||
|
$("#categoryDetailContent").show(); // Default empty state
|
||||||
|
// Clear selection if desired
|
||||||
|
// if(categoryTable) categoryTable.deselectRow(); // Optional: keep selection
|
||||||
|
}
|
||||||
|
|
||||||
if(gridSort != null){
|
/**
|
||||||
webCategoryStart = 0;
|
* Detail Panel: Show Insert
|
||||||
webCategorySort += gridSortModel+' '+ gridSort + ',';
|
*/
|
||||||
|
function fn_showInsertForm(preSelectDivCd) {
|
||||||
|
if ("Y" !== insertUseYn) {
|
||||||
|
alert("등록 권한이 없습니다.");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else{
|
|
||||||
nullCnt++;
|
|
||||||
if(nullCnt == columnArr.length){
|
|
||||||
webCategorySort = '';
|
|
||||||
webCategoryDir = '';
|
|
||||||
webCategoryStart = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
webCategorySort = webCategorySort.substring(0,webCategorySort.lastIndexOf( ",")); //맨끝 콤마 지우기
|
|
||||||
|
|
||||||
fn_webCategorySearch();
|
$("#categoryDetailContent").hide();
|
||||||
},
|
$("#categoryEditForm").hide();
|
||||||
onCellValueChanged: function(event) {
|
$("#categoryInsertForm").show();
|
||||||
// 신규 row: regDate가 없을 때, 둘 다 값이 있어야 등록
|
|
||||||
if (!event.data.regDate) {
|
// Reset fields
|
||||||
if (event.data.categoryDivCd && event.data.categoryNm) {
|
$("#insertCategoryDivCd").val(preSelectDivCd || "");
|
||||||
// 등록중 플래그 설정
|
$("#insertCategoryNm").val("");
|
||||||
event.data._isRegistering = true;
|
// Order No is auto-generated (MAX+1) on server
|
||||||
event.api.refreshCells({ force: true }); // 색상 즉시 반영
|
|
||||||
let data = {
|
// Update Header
|
||||||
categoryDivCd: event.data.categoryDivCd,
|
$(".detail-panel-title").text("카테고리 등록");
|
||||||
categoryNm: event.data.categoryNm,
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detail Panel: Show Edit
|
||||||
|
*/
|
||||||
|
function fn_showEditForm(item) {
|
||||||
|
if (!item) return;
|
||||||
|
console.log("Show Edit Form for:", item);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$("#categoryDetailContent").hide();
|
||||||
|
$("#categoryInsertForm").hide();
|
||||||
|
$("#categoryEditForm").show();
|
||||||
|
|
||||||
|
// Fill fields
|
||||||
|
$("#editCategoryNo").val(item.categoryNo); // PK
|
||||||
|
$("#editCategoryDivCd").val(item.categoryDivCd); // PK part
|
||||||
|
|
||||||
|
$("#editCategoryDivNm").val(categoryDivMap[item.categoryDivCd] || item.categoryDivCd);
|
||||||
|
|
||||||
|
// Strip HTML for input value as well? usually we want the raw value if it is editable.
|
||||||
|
// Assuming edit is for clean text.
|
||||||
|
let cleanName = item.categoryNm ? String(item.categoryNm).replace(/<[^>]*>?/gm, '') : '';
|
||||||
|
$("#editCategoryNm").val(cleanName);
|
||||||
|
$("#editOrderNo").val(item.orderNo || "0"); // Set Order No
|
||||||
|
|
||||||
|
$("#editRegDate").val(item.regDate);
|
||||||
|
|
||||||
|
// Update Header
|
||||||
|
$(".detail-panel-title").text("카테고리 상세/수정");
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error displaying edit form:", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action: Insert
|
||||||
|
*/
|
||||||
|
function fn_insertCategory() {
|
||||||
|
const divCd = $("#insertCategoryDivCd").val();
|
||||||
|
const nm = $("#insertCategoryNm").val();
|
||||||
|
// Order No handled by backend (MAX+1)
|
||||||
|
|
||||||
|
if (!divCd) { alert("카테고리 구분을 선택해주세요."); return; }
|
||||||
|
if (!nm) { alert("카테고리명을 입력해주세요."); return; }
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
categoryDivCd: divCd,
|
||||||
|
categoryNm: nm,
|
||||||
|
orderNo: 0, // Default 0 to trigger backend logic
|
||||||
menuClass: menuClass
|
menuClass: menuClass
|
||||||
};
|
};
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: '/categoryManagement/putCategoryManagement.do',
|
url: '/categoryManagement/putCategoryManagement.do',
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
data: JSON.stringify(data),
|
data: JSON.stringify(data),
|
||||||
contentType: 'application/json',
|
contentType: 'application/json',
|
||||||
success: function (res) {
|
success: function (res) {
|
||||||
if (typeof res === 'string') {
|
let response = (typeof res === 'string') ? JSON.parse(res) : res;
|
||||||
try {
|
if (response.msgCode === '0') {
|
||||||
res = JSON.parse(res);
|
alert("등록되었습니다.");
|
||||||
} catch (e) {
|
fn_searchCategoryList(); // reload
|
||||||
modalEvent.danger('등록 오류', '서버 응답 파싱 오류');
|
|
||||||
event.data._isRegistering = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (res.msgCode === '0') {
|
|
||||||
modalEvent.success('등록 완료', '카테고리가 등록되었습니다.', function(){
|
|
||||||
fn_webCategoryOk();
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
modalEvent.danger('등록 오류', res.msgDesc);
|
alert(response.msgDesc);
|
||||||
}
|
}
|
||||||
event.data._isRegistering = false;
|
|
||||||
event.api.refreshCells({ force: true }); // 색상 즉시 반영
|
|
||||||
},
|
},
|
||||||
error: function () {
|
error: function () {
|
||||||
modalEvent.danger('등록 오류', '등록 중 오류가 발생하였습니다.');
|
alert("등록 중 오류가 발생했습니다.");
|
||||||
event.data._isRegistering = false;
|
|
||||||
event.api.refreshCells({ force: true }); // 색상 즉시 반영
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
}
|
||||||
// 둘 중 하나라도 없으면 등록/수정 불가, 아무 동작 안함
|
|
||||||
|
/**
|
||||||
|
* Action: Update
|
||||||
|
*/
|
||||||
|
function fn_updateCategory() {
|
||||||
|
if ("Y" !== updateUseYn) {
|
||||||
|
alert("수정 권한이 없습니다.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// 기존 row 수정: 둘 다 값이 있을 때만 수정
|
const no = $("#editCategoryNo").val();
|
||||||
if (event.data.categoryDivCd && event.data.categoryNm) {
|
const divCd = $("#editCategoryDivCd").val();
|
||||||
let updatedData = { ...event.oldData, ...event.data };
|
const nm = $("#editCategoryNm").val();
|
||||||
updatedData.menuClass = menuClass;
|
const orderNo = $("#editOrderNo").val() || 0;
|
||||||
|
|
||||||
|
if (!nm) { alert("카테고리명을 입력해주세요."); return; }
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
categoryNo: no,
|
||||||
|
categoryDivCd: divCd,
|
||||||
|
categoryNm: nm,
|
||||||
|
orderNo: orderNo,
|
||||||
|
menuClass: menuClass
|
||||||
|
};
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: '/categoryManagement/modCategoryManagement.do',
|
url: '/categoryManagement/modCategoryManagement.do',
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
data: JSON.stringify(updatedData),
|
data: JSON.stringify(data),
|
||||||
contentType: 'application/json',
|
contentType: 'application/json',
|
||||||
success: function (res) {
|
success: function (res) {
|
||||||
response = JSON.parse(res);
|
let response = (typeof res === 'string') ? JSON.parse(res) : res;
|
||||||
if (response.msgCode === '0') {
|
if (response.msgCode === '0') {
|
||||||
modalEvent.success('수정 완료', '수정이 성공적으로 반영되었습니다.');
|
alert("수정되었습니다.");
|
||||||
fn_selectListwebCategoryJson();
|
fn_searchCategoryList();
|
||||||
} else {
|
} else {
|
||||||
modalEvent.danger('수정 오류', response.msgDesc);
|
alert(response.msgDesc);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: function () {
|
error: function () {
|
||||||
modalEvent.danger('수정 오류', '수정 중 오류가 발생하였습니다.');
|
alert("수정 중 오류가 발생했습니다.");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
}
|
||||||
// 둘 중 하나라도 없으면 수정 불가, 아무 동작 안함
|
|
||||||
|
/**
|
||||||
|
* Action: Delete
|
||||||
|
*/
|
||||||
|
function fn_deleteCategory() {
|
||||||
|
if ("Y" !== deleteUseYn) {
|
||||||
|
alert("삭제 권한이 없습니다.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
},
|
|
||||||
getRowStyle: function(params) {
|
|
||||||
return null; // 색상은 CSS에서 처리
|
|
||||||
},
|
|
||||||
getRowClass: function(params) {
|
|
||||||
if (!params.data) return '';
|
|
||||||
if (!params.data.regDate && params.data._isRegistering) {
|
|
||||||
return 'registering-row';
|
|
||||||
}
|
|
||||||
if (!params.data.regDate) {
|
|
||||||
return 'new-row';
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// lookup the container we want the Grid to use
|
if (!categoryTable) return;
|
||||||
let webCategoryGridDiv = document.querySelector('#webCategoryGrid');
|
|
||||||
|
|
||||||
// create the grid passing in the div to use together with the columns & data we want to use
|
// Get Selected Data
|
||||||
new agGrid.Grid(webCategoryGridDiv, webCategoryGridOptions);
|
const selectedData = categoryTable.getSelectedData();
|
||||||
|
|
||||||
|
if (selectedData.length === 0) {
|
||||||
/****************************************************************************
|
alert("삭제할 카테고리를 선택해주세요.");
|
||||||
* 페이지 init
|
|
||||||
****************************************************************************/
|
|
||||||
function fn_pageInit(){
|
|
||||||
// 초기 페이징 처리
|
|
||||||
$("#searchCategoryDivCd").val(categoryDivCd);
|
|
||||||
$("#searchCategoryNm").val(categoryNm);
|
|
||||||
fn_webCategorySearch("A");
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* 페이지 Category
|
|
||||||
****************************************************************************/
|
|
||||||
function fn_pageCategory(){
|
|
||||||
$(document).on('keypress', '#searchCategoryDivCd', function(e) {
|
|
||||||
fn_webCategoryEnter(e);
|
|
||||||
});
|
|
||||||
$(document).on('keypress', '#searchCategoryNm', function(e) {
|
|
||||||
fn_webCategoryEnter(e);
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#btnSearchWebCategory").click(function () {
|
|
||||||
fn_webCategorySearch();
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#btnInsertWebCategory").click(function () {
|
|
||||||
if (isInsertBtnDisabled) return;
|
|
||||||
isInsertBtnDisabled = true;
|
|
||||||
$(this).prop('disabled', true);
|
|
||||||
fn_insertwebCategoryIntro();
|
|
||||||
// 등록 완료 또는 실패 시 다시 활성화 (fn_webCategoryOk에서 처리)
|
|
||||||
});
|
|
||||||
$("#btnDeleteWebCategory").click(function () {
|
|
||||||
fn_deleteWebCategory();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 카테고리 등록 모달 열기
|
|
||||||
function fn_insertwebCategoryIntro() {
|
|
||||||
if("Y"==insertUseYn){
|
|
||||||
// 그리드에 한 줄 추가
|
|
||||||
let newRow = {
|
|
||||||
categoryDivCd: '',
|
|
||||||
categoryNm: '',
|
|
||||||
regDate: ''
|
|
||||||
};
|
|
||||||
webCategoryGridOptions.api.applyTransaction({ add: [newRow], addIndex: 0 });
|
|
||||||
// 첫 번째 row, 카테고리구분 셀에 포커스
|
|
||||||
setTimeout(function() {
|
|
||||||
webCategoryGridOptions.api.startEditingCell({
|
|
||||||
rowIndex: 0,
|
|
||||||
colKey: 'categoryDivCd'
|
|
||||||
});
|
|
||||||
}, 100);
|
|
||||||
} else {
|
|
||||||
modalEvent.warning('', '등록 권한이 없습니다.');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 카테고리 삭제
|
|
||||||
function fn_deleteWebCategory() {
|
|
||||||
// 신규행이 등록중이거나 입력 중이면 삭제 불가
|
|
||||||
let rowData = [];
|
|
||||||
webCategoryGridOptions.api.forEachNode(function(node) {
|
|
||||||
rowData.push(node.data);
|
|
||||||
});
|
|
||||||
let hasNewRowEditing = rowData.some(row => !row.regDate && (!row.categoryDivCd || !row.categoryNm || row._isRegistering));
|
|
||||||
if (hasNewRowEditing) {
|
|
||||||
modalEvent.warning('', '신규 카테고리 등록이 완료되기 전에는 삭제할 수 없습니다.');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(!delList || delList.length === 0) {
|
|
||||||
modalEvent.warning('', '삭제할 카테고리를 선택하세요.');
|
// Map to required format
|
||||||
return;
|
const itemsToDelete = selectedData.map(item => ({
|
||||||
}
|
categoryNo: item.categoryNo,
|
||||||
modalEvent.info('삭제', '선택한 카테고리를 삭제하시겠습니까?', function(){
|
categoryDivCd: item.categoryDivCd
|
||||||
let data = {
|
}));
|
||||||
menuClass: menuClass,
|
|
||||||
delList: delList
|
if (confirm(itemsToDelete.length + "건의 카테고리를 삭제하시겠습니까?")) {
|
||||||
|
const data = {
|
||||||
|
delList: itemsToDelete,
|
||||||
|
menuClass: menuClass
|
||||||
};
|
};
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: '/categoryManagement/delCategoryManagement.do',
|
url: '/categoryManagement/delCategoryManagement.do',
|
||||||
data: JSON.stringify(data),
|
data: JSON.stringify(data),
|
||||||
dataType: 'json',
|
contentType: 'application/json',
|
||||||
contentType: 'application/json; charset=utf-8',
|
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
async: true,
|
|
||||||
success: function (res) {
|
success: function (res) {
|
||||||
if(res.msgCode === '0'){
|
let response = (typeof res === 'string') ? JSON.parse(res) : res;
|
||||||
modalEvent.success('삭제 완료', '카테고리가 삭제되었습니다.', function(){
|
if (response.msgCode === '0') {
|
||||||
fn_webCategoryOk();
|
alert("삭제되었습니다.");
|
||||||
});
|
fn_searchCategoryList();
|
||||||
} else {
|
} else {
|
||||||
modalEvent.danger('삭제 오류', res.msgDesc);
|
alert(response.msgDesc);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: function(xhr, status, error) {
|
error: function () {
|
||||||
modalEvent.danger('삭제 오류', '삭제 중 오류가 발생하였습니다. 잠시후 다시시도하십시오.');
|
alert("삭제 중 오류가 발생했습니다.");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
$(function(){
|
|
||||||
// 페이지 init
|
|
||||||
fn_pageInit();
|
|
||||||
|
|
||||||
// 페이지 Category
|
|
||||||
fn_pageCategory();
|
|
||||||
});
|
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||||
xmlns:th="http://www.thymeleaf.org"
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{/web/layout/homeLayout}">
|
||||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
|
||||||
layout:decorate="~{/web/layout/homeLayout}">
|
|
||||||
<th:block layout:fragment="layout_css">
|
<th:block layout:fragment="layout_css">
|
||||||
<link rel="stylesheet" href="/css/web/webCategorySelectList.css?v1.1">
|
<link rel="stylesheet" href="/css/web/webCategorySelectList.css?v2.0">
|
||||||
<link rel="stylesheet" href="/css/web/grid.css?v1.1">
|
<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.1">
|
||||||
</th:block>
|
</th:block>
|
||||||
<th:block layout:fragment="layout_top_script">
|
<th:block layout:fragment="layout_top_script">
|
||||||
<script src="/js/web/jquery.twbsPagination.js" type="text/javascript"></script>
|
<script src="/js/web/jquery.twbsPagination.js" type="text/javascript"></script>
|
||||||
@@ -22,15 +22,6 @@
|
|||||||
|
|
||||||
/* 검색 관련 변수 */
|
/* 검색 관련 변수 */
|
||||||
let categoryNm = "[[${param.categoryName}]]" == "" ? "" : "[[${param.categoryName}]]";
|
let categoryNm = "[[${param.categoryName}]]" == "" ? "" : "[[${param.categoryName}]]";
|
||||||
|
|
||||||
let webCategorySort = "[[${param.webCategorySort}]]";
|
|
||||||
let webCategoryDir = "[[${param.webCategoryDir}]]";
|
|
||||||
let webCategoryStart = "[[${param.webCategoryStart}]]"==""?0:"[[${param.webCategoryStart}]]";
|
|
||||||
let webCategoryLimit = "[[${param.webCategoryLimit}]]"==""?500:"[[${param.webCategoryLimit}]]";
|
|
||||||
|
|
||||||
let webCategorySearchStartDate = "[[${param.webCategorySearchStartDate}]]";
|
|
||||||
let webCategorySearchEndDate = "[[${param.webCategorySearchEndDate}]]";
|
|
||||||
let webCategorySearchDateType = "[[${param.webCategorySearchDateType}]]"==""?"A":"[[${param.webCategorySearchDateType}]]";
|
|
||||||
</script>
|
</script>
|
||||||
</th:block>
|
</th:block>
|
||||||
<th:block layout:fragment="layout_content">
|
<th:block layout:fragment="layout_content">
|
||||||
@@ -41,11 +32,54 @@
|
|||||||
<div class="filter_box">
|
<div class="filter_box">
|
||||||
<div class="form_box">
|
<div class="form_box">
|
||||||
|
|
||||||
<!-- 이름input -->
|
<!-- 검색 영역 삭제됨 -->
|
||||||
<div class="search_list">
|
<div class="search_list" style="display:none;"></div>
|
||||||
<div class="search_box">
|
|
||||||
<select id="searchCategoryDivCd" required>
|
<!-- Right Btn Box Removed as buttons moved to Tree Header -->
|
||||||
<option value="">전체</option>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 트리 + 상세 레이아웃 -->
|
||||||
|
<div class="category-tree-layout">
|
||||||
|
<!-- 좌측: 트리 영역 -->
|
||||||
|
<div class="category-tree-panel">
|
||||||
|
<div class="tree-panel-header">
|
||||||
|
<span class="tree-panel-title">카테고리 목록</span>
|
||||||
|
<div class="tree-panel-actions">
|
||||||
|
|
||||||
|
<button id="btnInsertWebCategory" class="put_btn">
|
||||||
|
<img src="/image/web/notice_btn_icon.svg" alt="추가">추가
|
||||||
|
</button>
|
||||||
|
<button id="btnDeleteWebCategory" class="delete_btn">
|
||||||
|
<img src="/image/web/delete_btn_icon.svg" alt="삭제">삭제
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Sub Header for Expand/Collapse -->
|
||||||
|
<div class="tree-sub-header">
|
||||||
|
<button id="btnExpandAll" class="tree-action-btn" title="모두 펼치기">▼ 펼치기</button>
|
||||||
|
<button id="btnCollapseAll" class="tree-action-btn" title="모두 접기">▶ 접기</button>
|
||||||
|
</div>
|
||||||
|
<div id="categoryTreeContainer" class="category-tree-container"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 우측: 상세/편집 영역 -->
|
||||||
|
<div class="category-detail-panel">
|
||||||
|
<div class="detail-panel-header">
|
||||||
|
<span class="detail-panel-title">카테고리 정보</span>
|
||||||
|
</div>
|
||||||
|
<div id="categoryDetailContent" class="detail-panel-content">
|
||||||
|
<div class="detail-empty-state">
|
||||||
|
<p>좌측 목록에서 카테고리를 선택하세요.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 등록 폼 (숨김 상태) -->
|
||||||
|
<div id="categoryInsertForm" class="detail-panel-content" style="display:none;">
|
||||||
|
<div class="detail-form-group">
|
||||||
|
<label>카테고리 구분</label>
|
||||||
|
<select id="insertCategoryDivCd" class="detail-form-select">
|
||||||
|
<option value="">선택</option>
|
||||||
<option value="01">다이어트 시술</option>
|
<option value="01">다이어트 시술</option>
|
||||||
<option value="02">다이어트 이벤트</option>
|
<option value="02">다이어트 이벤트</option>
|
||||||
<option value="03">쁘띠 시술</option>
|
<option value="03">쁘띠 시술</option>
|
||||||
@@ -54,38 +88,50 @@
|
|||||||
<option value="06">쁘띠 전후사진</option>
|
<option value="06">쁘띠 전후사진</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="search_box">
|
<div class="detail-form-group">
|
||||||
<input type="text" id="searchCategoryNm" required placeholder="카테고리명">
|
<label>카테고리명</label>
|
||||||
</div>
|
<input type="text" id="insertCategoryNm" class="detail-form-input" placeholder="카테고리명을 입력하세요">
|
||||||
<button id="btnSearchWebCategory" class="search_btn" data-toggle="modal" data-target=".work_closed_modal" style="transition: all 0.2s ease-in-out 0s;">조회</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="right_btn_box">
|
|
||||||
<button id="btnInsertWebCategory" class="put_btn">
|
|
||||||
<img src="/image/web/notice_btn_icon.svg" alt="등록">등록
|
|
||||||
</button>
|
|
||||||
<button id="btnDeleteWebCategory" class="delete_btn">
|
|
||||||
<img src="/image/web/delete_btn_icon.svg" alt="삭제">삭제
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="detail-form-actions">
|
||||||
|
<button id="btnSaveCategory" class="detail-save-btn">저장</button>
|
||||||
|
<button id="btnCancelInsert" class="detail-cancel-btn">취소</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="webCategoryGrid" class="table_box ag-theme-balham"></div>
|
<!-- 수정 폼 (숨김 상태) -->
|
||||||
|
<div id="categoryEditForm" class="detail-panel-content" style="display:none;">
|
||||||
<!-- 페이지게이션 -->
|
<div class="detail-form-group">
|
||||||
<div class="page_box">
|
<label>카테고리 구분</label>
|
||||||
<nav aria-label="Page navigation" class="navigation">
|
<input type="text" id="editCategoryDivNm" class="detail-form-input" readonly>
|
||||||
<ul class="pagination" id="webCategoryPagination"></ul>
|
<input type="hidden" id="editCategoryNo">
|
||||||
</nav>
|
<input type="hidden" id="editCategoryDivCd">
|
||||||
|
</div>
|
||||||
|
<div class="detail-form-group">
|
||||||
|
<label>카테고리명</label>
|
||||||
|
<input type="text" id="editCategoryNm" class="detail-form-input" placeholder="카테고리명을 입력하세요">
|
||||||
|
</div>
|
||||||
|
<div class="detail-form-group">
|
||||||
|
<label>정렬 순서</label>
|
||||||
|
<input type="number" id="editOrderNo" class="detail-form-input" placeholder="정렬 순서를 입력하세요">
|
||||||
|
</div>
|
||||||
|
<div class="detail-form-group">
|
||||||
|
<label>등록일</label>
|
||||||
|
<input type="text" id="editRegDate" class="detail-form-input" readonly>
|
||||||
|
</div>
|
||||||
|
<div class="detail-form-actions">
|
||||||
|
<button id="btnUpdateCategory" class="detail-save-btn">수정</button>
|
||||||
|
<button id="btnCancelEdit" class="detail-cancel-btn">취소</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form id="webCategorySelectListForm" method="POST" target="_blank"></form>
|
|
||||||
</th:block>
|
</th:block>
|
||||||
<th:block layout:fragment="layout_popup">
|
<th:block layout:fragment="layout_popup">
|
||||||
</th:block>
|
</th:block>
|
||||||
<th:block layout:fragment="layout_script">
|
<th:block layout:fragment="layout_script">
|
||||||
<script src="/js/web/ag-grid-community-29.3.5.min.js"></script>
|
<script src="https://unpkg.com/tabulator-tables@5.6.1/dist/js/tabulator.min.js"></script>
|
||||||
<script src="/js/web/categoryManagement/CategoryManagement.js"></script>
|
<script src="/js/web/categoryManagement/CategoryManagement.js?v2.0"></script>
|
||||||
</th:block>
|
</th:block>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
Reference in New Issue
Block a user