Files
DDD1542 2348800e68
Build & Deploy to K8s / build-and-deploy (push) Successful in 9m22s
refactor(common-code): 마스터-디테일 재설계 — code_info(그룹) + code_detail(재귀 트리)
카테고리/캐스케이딩 시스템 (B/C/D) 전부 폐기:
- BE: mapper/Service/Controller 9세트 삭제 (cascading*, categoryTree, tableCategoryValue, categoryValueCascading, codeMerge)
- FE: 페이지 3 + API 8 + hooks 2 + 폐기 컴포넌트 6 삭제, 14곳 의존성 정리
- DB: 12 테이블 DROP, TABLE_TYPE_COLUMNS.CODE_CATEGORY → CODE_INFO rename

신설 commonCode 마스터-디테일:
- code_info: 1레벨 그룹 마스터
- code_detail: 2~∞ depth 재귀 트리 (parent_detail_id self-FK, depth 자동 계산)
- API: /api/common-codes/{info,detail}
- CodeCategoryFormModal/Panel → CodeInfoFormModal/Panel rename
- code_category 컬럼명 전부 code_info 로 치환 (mapper/Java/FE)
- 옛 commonCode API URL (/categories/...) → getCodeOptions 어댑터 + /detail?code_info=... 전환

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 16:50:50 +09:00

203 lines
6.9 KiB
TypeScript

import { apiClient } from "./client";
import type {
CodeInfo,
CodeDetail,
ApiResponse,
GetCodeInfoListQuery,
GetCodeDetailListQuery,
DuplicateCheckResult,
} from "@/types/commonCode";
/**
* 공통코드 API 클라이언트 (마스터-디테일 구조)
*
* code_info — 그룹 마스터
* code_detail — 트리 노드 (depth 2 시작, 무한 depth)
*
* 백엔드 계약 (BE Agent 가 만드는 것):
* /api/common-codes/info/...
* /api/common-codes/detail/...
*
* 응답 포맷:
* 목록: { success, data: [...], total: N, message }
* 단건/CRUD: { success, data: {...}, message }
*/
/* ───────────────────────── code_info (그룹 마스터) ───────────────────────── */
/** 그룹 목록 (페이징/검색) */
export async function getCodeInfoList(
params?: GetCodeInfoListQuery,
): Promise<ApiResponse<CodeInfo[]>> {
const search = new URLSearchParams();
if (params?.search) search.append("search", params.search);
if (params?.is_active !== undefined) search.append("is_active", params.is_active.toString());
if (params?.page !== undefined) search.append("page", params.page.toString());
if (params?.size !== undefined) search.append("size", params.size.toString());
const qs = search.toString();
const url = `/common-codes/info${qs ? `?${qs}` : ""}`;
const response = await apiClient.get(url);
return response.data;
}
/** 그룹 단건 */
export async function getCodeInfoInfo(codeInfo: string): Promise<ApiResponse<CodeInfo>> {
const response = await apiClient.get(`/common-codes/info/${encodeURIComponent(codeInfo)}`);
return response.data;
}
/** 그룹 생성 */
export async function createCodeInfo(data: Record<string, any>): Promise<ApiResponse<CodeInfo>> {
const response = await apiClient.post("/common-codes/info", data);
return response.data;
}
/** 그룹 수정 */
export async function updateCodeInfo(
codeInfo: string,
data: Record<string, any>,
): Promise<ApiResponse<CodeInfo>> {
const response = await apiClient.put(
`/common-codes/info/${encodeURIComponent(codeInfo)}`,
data,
);
return response.data;
}
/** 그룹 삭제 (CASCADE) */
export async function deleteCodeInfo(codeInfo: string): Promise<ApiResponse> {
const response = await apiClient.delete(`/common-codes/info/${encodeURIComponent(codeInfo)}`);
return response.data;
}
/** 그룹 중복 체크 */
export async function checkCodeInfoDuplicate(
field: "code_info" | "code_name" | "code_name_eng",
value: string,
excludeCode?: string,
): Promise<ApiResponse<DuplicateCheckResult>> {
const search = new URLSearchParams();
search.append("field", field);
search.append("value", value);
if (excludeCode) search.append("excludeCode", excludeCode);
const response = await apiClient.get(`/common-codes/info/check-duplicate?${search}`);
return response.data;
}
/* ───────────────────────── code_detail (디테일 트리) ───────────────────────── */
/** 그룹의 전체 디테일 트리 (depth+sort_order 평탄화 리스트) */
export async function getCodeDetailTree(
params: GetCodeDetailListQuery,
): Promise<ApiResponse<CodeDetail[]>> {
const search = new URLSearchParams();
search.append("code_info", params.code_info);
if (params.search) search.append("search", params.search);
if (params.is_active !== undefined) search.append("is_active", params.is_active.toString());
const response = await apiClient.get(`/common-codes/detail?${search}`);
return response.data;
}
/** 디테일 단건 */
export async function getCodeDetailInfo(
codeDetailId: number | string,
): Promise<ApiResponse<CodeDetail>> {
const response = await apiClient.get(`/common-codes/detail/${codeDetailId}`);
return response.data;
}
/** 디테일 생성 */
export async function createCodeDetail(
data: Record<string, any>,
): Promise<ApiResponse<CodeDetail>> {
const response = await apiClient.post("/common-codes/detail", data);
return response.data;
}
/** 디테일 수정 */
export async function updateCodeDetail(
codeDetailId: number | string,
data: Record<string, any>,
): Promise<ApiResponse<CodeDetail>> {
const response = await apiClient.put(`/common-codes/detail/${codeDetailId}`, data);
return response.data;
}
/** 디테일 삭제 (CASCADE) */
export async function deleteCodeDetail(codeDetailId: number | string): Promise<ApiResponse> {
const response = await apiClient.delete(`/common-codes/detail/${codeDetailId}`);
return response.data;
}
/** 디테일 중복 체크 (그룹 + 필드 단위) */
export async function checkCodeDetailDuplicate(
codeInfo: string,
field: "code_value" | "code_name" | "code_name_eng",
value: string,
excludeId?: number | string,
): Promise<ApiResponse<DuplicateCheckResult>> {
const search = new URLSearchParams();
search.append("code_info", codeInfo);
search.append("field", field);
search.append("value", value);
if (excludeId !== undefined && excludeId !== null && excludeId !== "") {
search.append("excludeId", String(excludeId));
}
const response = await apiClient.get(`/common-codes/detail/check-duplicate?${search}`);
return response.data;
}
/* ───────────────────────── compat: 화면관리/캐시에서 사용 ───────────────────────── */
/**
* 그룹의 활성 디테일 옵션 (label/value)
* 기존 `commonCodeApi.options.getOptions(categoryCode)` 의 대체.
*/
export async function getCodeOptions(
codeInfo: string,
): Promise<ApiResponse<Array<{ value: string; label: string; depth?: number; parent_detail_id?: number | null }>>> {
const tree = await getCodeDetailTree({ code_info: codeInfo, is_active: true });
const options = (tree.data || []).map((row) => ({
value: row.code_value,
label: row.code_name || row.code_value,
depth: row.depth,
parent_detail_id: row.parent_detail_id ?? null,
}));
return {
success: tree.success,
data: options,
message: tree.message,
total: options.length,
};
}
/**
* 호환 객체. 기존 코드가 `commonCodeApi.codes.getList(category, ...)` 등으로 부르고 있어
* 깨끗한 1안 마이그레이션 동안 임시로 노출. 새 코드는 위 함수들을 직접 import.
*
* NOTE: 사용처가 점진적으로 제거되면 이 객체도 삭제.
*/
export const commonCodeApi = {
info: {
getList: getCodeInfoList,
get: getCodeInfoInfo,
create: createCodeInfo,
update: updateCodeInfo,
delete: deleteCodeInfo,
checkDuplicate: checkCodeInfoDuplicate,
},
detail: {
getTree: getCodeDetailTree,
get: getCodeDetailInfo,
create: createCodeDetail,
update: updateCodeDetail,
delete: deleteCodeDetail,
checkDuplicate: checkCodeDetailDuplicate,
},
options: {
getOptions: getCodeOptions,
},
};