- Added a new query parameter `deleteNumberingRules` to the `deleteScreenGroup` function, allowing users to specify if numbering rules should be deleted when a root screen group is removed. - Updated the `deleteScreenGroup` controller to handle the deletion of numbering rules conditionally based on the new parameter. - Enhanced the frontend `ScreenGroupTreeView` component to include a checkbox for users to confirm the deletion of numbering rules when deleting a root group, improving user control and clarity during deletion operations. - Implemented appropriate warnings and messages to inform users about the implications of deleting numbering rules, ensuring better user experience and data integrity awareness.
670 lines
21 KiB
TypeScript
670 lines
21 KiB
TypeScript
/**
|
|
* 화면 그룹 관리 API 클라이언트
|
|
* - 화면 그룹 (screen_groups)
|
|
* - 화면-그룹 연결 (screen_group_screens)
|
|
* - 필드 조인 (screen_field_joins)
|
|
* - 데이터 흐름 (screen_data_flows)
|
|
* - 화면-테이블 관계 (screen_table_relations)
|
|
*/
|
|
|
|
import { apiClient } from "./client";
|
|
|
|
// ============================================================
|
|
// 타입 정의
|
|
// ============================================================
|
|
|
|
export interface ScreenGroup {
|
|
id: number;
|
|
group_name: string;
|
|
group_code: string;
|
|
main_table_name?: string;
|
|
description?: string;
|
|
icon?: string;
|
|
display_order: number;
|
|
is_active: string;
|
|
company_code: string;
|
|
created_date?: string;
|
|
updated_date?: string;
|
|
writer?: string;
|
|
screen_count?: number;
|
|
screens?: ScreenGroupScreen[];
|
|
parent_group_id?: number | null; // 상위 그룹 ID
|
|
group_level?: number; // 그룹 레벨 (0: 대분류, 1: 중분류, 2: 소분류 ...)
|
|
hierarchy_path?: string; // 계층 경로
|
|
}
|
|
|
|
export interface ScreenGroupScreen {
|
|
id: number;
|
|
group_id: number;
|
|
screen_id: number;
|
|
screen_name?: string;
|
|
screen_role: string;
|
|
display_order: number;
|
|
is_default: string;
|
|
company_code: string;
|
|
}
|
|
|
|
export interface FieldJoin {
|
|
id: number;
|
|
screen_id: number;
|
|
layout_id?: number;
|
|
component_id?: string;
|
|
field_name?: string;
|
|
save_table: string;
|
|
save_column: string;
|
|
join_table: string;
|
|
join_column: string;
|
|
display_column: string;
|
|
join_type: string;
|
|
filter_condition?: string;
|
|
sort_column?: string;
|
|
sort_direction?: string;
|
|
is_active: string;
|
|
save_table_label?: string;
|
|
join_table_label?: string;
|
|
}
|
|
|
|
export interface DataFlow {
|
|
id: number;
|
|
group_id?: number;
|
|
source_screen_id: number;
|
|
source_action?: string;
|
|
target_screen_id: number;
|
|
target_action?: string;
|
|
data_mapping?: Record<string, any>;
|
|
flow_type: string;
|
|
flow_label?: string;
|
|
condition_expression?: string;
|
|
is_active: string;
|
|
source_screen_name?: string;
|
|
target_screen_name?: string;
|
|
group_name?: string;
|
|
}
|
|
|
|
export interface TableRelation {
|
|
id: number;
|
|
group_id?: number;
|
|
screen_id: number;
|
|
table_name: string;
|
|
relation_type: string;
|
|
crud_operations: string;
|
|
description?: string;
|
|
is_active: string;
|
|
screen_name?: string;
|
|
group_name?: string;
|
|
table_label?: string;
|
|
}
|
|
|
|
export interface ApiResponse<T> {
|
|
success: boolean;
|
|
data?: T;
|
|
message?: string;
|
|
error?: string;
|
|
total?: number;
|
|
page?: number;
|
|
size?: number;
|
|
totalPages?: number;
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// 화면 그룹 (screen_groups) API
|
|
// ============================================================
|
|
|
|
export async function getScreenGroups(params?: {
|
|
page?: number;
|
|
size?: number;
|
|
searchTerm?: string;
|
|
}): Promise<ApiResponse<ScreenGroup[]>> {
|
|
try {
|
|
const queryParams = new URLSearchParams();
|
|
if (params?.page) queryParams.append("page", params.page.toString());
|
|
if (params?.size) queryParams.append("size", params.size.toString());
|
|
if (params?.searchTerm) queryParams.append("searchTerm", params.searchTerm);
|
|
|
|
const response = await apiClient.get(`/screen-groups/groups?${queryParams.toString()}`);
|
|
return response.data;
|
|
} catch (error: any) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
export async function getScreenGroup(id: number): Promise<ApiResponse<ScreenGroup>> {
|
|
try {
|
|
const response = await apiClient.get(`/screen-groups/groups/${id}`);
|
|
return response.data;
|
|
} catch (error: any) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
export async function createScreenGroup(data: Partial<ScreenGroup>): Promise<ApiResponse<ScreenGroup>> {
|
|
try {
|
|
const response = await apiClient.post("/screen-groups/groups", data);
|
|
return response.data;
|
|
} catch (error: any) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
export async function updateScreenGroup(id: number, data: Partial<ScreenGroup>): Promise<ApiResponse<ScreenGroup>> {
|
|
try {
|
|
const response = await apiClient.put(`/screen-groups/groups/${id}`, data);
|
|
return response.data;
|
|
} catch (error: any) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
export async function deleteScreenGroup(id: number, options?: { deleteNumberingRules?: boolean }): Promise<ApiResponse<void>> {
|
|
try {
|
|
const params = new URLSearchParams();
|
|
if (options?.deleteNumberingRules) {
|
|
params.set("deleteNumberingRules", "true");
|
|
}
|
|
const queryString = params.toString();
|
|
const url = `/screen-groups/groups/${id}${queryString ? `?${queryString}` : ""}`;
|
|
const response = await apiClient.delete(url);
|
|
return response.data;
|
|
} catch (error: any) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// 화면-그룹 연결 (screen_group_screens) API
|
|
// ============================================================
|
|
|
|
export async function addScreenToGroup(data: {
|
|
group_id: number;
|
|
screen_id: number;
|
|
screen_role?: string;
|
|
display_order?: number;
|
|
is_default?: string;
|
|
target_company_code?: string; // 최고 관리자가 다른 회사로 복제할 때 사용
|
|
}): Promise<ApiResponse<ScreenGroupScreen>> {
|
|
try {
|
|
const response = await apiClient.post("/screen-groups/group-screens", data);
|
|
return response.data;
|
|
} catch (error: any) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
export async function updateScreenInGroup(id: number, data: {
|
|
screen_role?: string;
|
|
display_order?: number;
|
|
is_default?: string;
|
|
}): Promise<ApiResponse<ScreenGroupScreen>> {
|
|
try {
|
|
const response = await apiClient.put(`/screen-groups/group-screens/${id}`, data);
|
|
return response.data;
|
|
} catch (error: any) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
export async function removeScreenFromGroup(id: number): Promise<ApiResponse<void>> {
|
|
try {
|
|
const response = await apiClient.delete(`/screen-groups/group-screens/${id}`);
|
|
return response.data;
|
|
} catch (error: any) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// 필드 조인 (screen_field_joins) API
|
|
// ============================================================
|
|
|
|
export async function getFieldJoins(screenId?: number): Promise<ApiResponse<FieldJoin[]>> {
|
|
try {
|
|
const queryParams = screenId ? `?screen_id=${screenId}` : "";
|
|
const response = await apiClient.get(`/screen-groups/field-joins${queryParams}`);
|
|
return response.data;
|
|
} catch (error: any) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
export async function createFieldJoin(data: Partial<FieldJoin>): Promise<ApiResponse<FieldJoin>> {
|
|
try {
|
|
const response = await apiClient.post("/screen-groups/field-joins", data);
|
|
return response.data;
|
|
} catch (error: any) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
export async function updateFieldJoin(id: number, data: Partial<FieldJoin>): Promise<ApiResponse<FieldJoin>> {
|
|
try {
|
|
const response = await apiClient.put(`/screen-groups/field-joins/${id}`, data);
|
|
return response.data;
|
|
} catch (error: any) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
export async function deleteFieldJoin(id: number): Promise<ApiResponse<void>> {
|
|
try {
|
|
const response = await apiClient.delete(`/screen-groups/field-joins/${id}`);
|
|
return response.data;
|
|
} catch (error: any) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// 데이터 흐름 (screen_data_flows) API
|
|
// ============================================================
|
|
|
|
export async function getDataFlows(params?: { groupId?: number; sourceScreenId?: number }): Promise<ApiResponse<DataFlow[]>> {
|
|
try {
|
|
const queryParts: string[] = [];
|
|
if (params?.groupId) {
|
|
queryParts.push(`group_id=${params.groupId}`);
|
|
}
|
|
if (params?.sourceScreenId) {
|
|
queryParts.push(`source_screen_id=${params.sourceScreenId}`);
|
|
}
|
|
const queryString = queryParts.length > 0 ? `?${queryParts.join("&")}` : "";
|
|
const response = await apiClient.get(`/screen-groups/data-flows${queryString}`);
|
|
return response.data;
|
|
} catch (error: any) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
export async function createDataFlow(data: Partial<DataFlow>): Promise<ApiResponse<DataFlow>> {
|
|
try {
|
|
const response = await apiClient.post("/screen-groups/data-flows", data);
|
|
return response.data;
|
|
} catch (error: any) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
export async function updateDataFlow(id: number, data: Partial<DataFlow>): Promise<ApiResponse<DataFlow>> {
|
|
try {
|
|
const response = await apiClient.put(`/screen-groups/data-flows/${id}`, data);
|
|
return response.data;
|
|
} catch (error: any) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
export async function deleteDataFlow(id: number): Promise<ApiResponse<void>> {
|
|
try {
|
|
const response = await apiClient.delete(`/screen-groups/data-flows/${id}`);
|
|
return response.data;
|
|
} catch (error: any) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// 화면-테이블 관계 (screen_table_relations) API
|
|
// ============================================================
|
|
|
|
export async function getTableRelations(params?: {
|
|
screen_id?: number;
|
|
group_id?: number;
|
|
}): Promise<ApiResponse<TableRelation[]>> {
|
|
try {
|
|
const queryParams = new URLSearchParams();
|
|
if (params?.screen_id) queryParams.append("screen_id", params.screen_id.toString());
|
|
if (params?.group_id) queryParams.append("group_id", params.group_id.toString());
|
|
|
|
const response = await apiClient.get(`/screen-groups/table-relations?${queryParams.toString()}`);
|
|
return response.data;
|
|
} catch (error: any) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
export async function createTableRelation(data: Partial<TableRelation>): Promise<ApiResponse<TableRelation>> {
|
|
try {
|
|
const response = await apiClient.post("/screen-groups/table-relations", data);
|
|
return response.data;
|
|
} catch (error: any) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
export async function updateTableRelation(id: number, data: Partial<TableRelation>): Promise<ApiResponse<TableRelation>> {
|
|
try {
|
|
const response = await apiClient.put(`/screen-groups/table-relations/${id}`, data);
|
|
return response.data;
|
|
} catch (error: any) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
export async function deleteTableRelation(id: number): Promise<ApiResponse<void>> {
|
|
try {
|
|
const response = await apiClient.delete(`/screen-groups/table-relations/${id}`);
|
|
return response.data;
|
|
} catch (error: any) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// 화면 레이아웃 요약 (미리보기용) API
|
|
// ============================================================
|
|
|
|
// 레이아웃 아이템 (미니어처 렌더링용)
|
|
export interface LayoutItem {
|
|
x: number;
|
|
y: number;
|
|
width: number;
|
|
height: number;
|
|
componentKind: string; // 정확한 컴포넌트 종류 (table-list, button-primary 등)
|
|
widgetType: string; // 일반적인 위젯 타입 (button, text 등)
|
|
label?: string;
|
|
bindField?: string; // 바인딩된 필드명 (컬럼명)
|
|
usedColumns?: string[]; // 이 컴포넌트에서 사용하는 컬럼 목록
|
|
joinColumns?: string[]; // 이 컴포넌트에서 조인 컬럼 목록 (isEntityJoin=true)
|
|
}
|
|
|
|
export interface ScreenLayoutSummary {
|
|
screenId: number;
|
|
screenType: 'form' | 'grid' | 'dashboard' | 'action';
|
|
widgetCounts: Record<string, number>;
|
|
totalComponents: number;
|
|
// 미니어처 렌더링용 레이아웃 데이터
|
|
layoutItems: LayoutItem[];
|
|
canvasWidth: number;
|
|
canvasHeight: number;
|
|
}
|
|
|
|
// 단일 화면 레이아웃 요약 조회
|
|
export async function getScreenLayoutSummary(screenId: number): Promise<ApiResponse<ScreenLayoutSummary>> {
|
|
try {
|
|
const response = await apiClient.get(`/screen-groups/layout-summary/${screenId}`);
|
|
return response.data;
|
|
} catch (error: any) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
// 여러 화면 레이아웃 요약 일괄 조회
|
|
export async function getMultipleScreenLayoutSummary(
|
|
screenIds: number[]
|
|
): Promise<ApiResponse<Record<number, ScreenLayoutSummary>>> {
|
|
try {
|
|
const response = await apiClient.post("/screen-groups/layout-summary/batch", { screenIds });
|
|
return response.data;
|
|
} catch (error: any) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
// 필드 매핑 정보 타입
|
|
export interface FieldMappingInfo {
|
|
sourceTable?: string; // 연관 테이블명 (parentDataMapping에서 사용)
|
|
sourceField: string;
|
|
targetField: string;
|
|
sourceDisplayName?: string; // 메인 테이블 한글 컬럼명
|
|
targetDisplayName?: string; // 서브 테이블 한글 컬럼명
|
|
}
|
|
|
|
// 서브 테이블 정보 타입
|
|
export interface SubTableInfo {
|
|
tableName: string;
|
|
tableLabel?: string; // 테이블 한글명
|
|
componentType: string;
|
|
relationType: 'lookup' | 'source' | 'join' | 'reference' | 'parentMapping' | 'rightPanelRelation';
|
|
fieldMappings?: FieldMappingInfo[];
|
|
filterColumns?: string[]; // 필터링에 사용되는 컬럼 목록
|
|
// rightPanelRelation에서 추가 정보 (관계 유형 추론용)
|
|
originalRelationType?: 'join' | 'detail'; // 원본 relation.type
|
|
foreignKey?: string; // 디테일 테이블의 FK 컬럼
|
|
leftColumn?: string; // 마스터 테이블의 선택 기준 컬럼
|
|
// rightPanel.columns에서 외부 테이블 참조 정보
|
|
joinedTables?: string[]; // 참조하는 외부 테이블들 (예: ['customer_mng'])
|
|
joinColumns?: string[]; // 외부 테이블과 조인하는 FK 컬럼들 (예: ['customer_id'])
|
|
joinColumnRefs?: Array<{ // FK 컬럼 참조 정보 (어떤 테이블.컬럼에서 오는지)
|
|
column: string; // FK 컬럼명 (예: 'customer_id')
|
|
columnLabel: string; // FK 컬럼 한글명 (예: '거래처 ID')
|
|
refTable: string; // 참조 테이블 (예: 'customer_mng')
|
|
refTableLabel: string; // 참조 테이블 한글명 (예: '거래처 관리')
|
|
refColumn: string; // 참조 컬럼 (예: 'customer_code')
|
|
}>;
|
|
}
|
|
|
|
// 시각적 관계 유형 (시각화에서 사용)
|
|
export type VisualRelationType = 'filter' | 'hierarchy' | 'lookup' | 'mapping' | 'join';
|
|
|
|
// 관계 유형 추론 함수
|
|
export function inferVisualRelationType(subTable: SubTableInfo): VisualRelationType {
|
|
// 1. split-panel-layout의 rightPanel.relation
|
|
if (subTable.relationType === 'rightPanelRelation') {
|
|
// 원본 relation.type 기반 구분
|
|
if (subTable.originalRelationType === 'detail') {
|
|
return 'hierarchy'; // 부모-자식 계층 구조 (같은 테이블 자기 참조)
|
|
}
|
|
return 'filter'; // 마스터-디테일 필터링
|
|
}
|
|
|
|
// 2. selected-items-detail-input의 parentDataMapping
|
|
// parentDataMapping은 FK 관계를 정의하므로 조인으로 분류
|
|
if (subTable.relationType === 'parentMapping') {
|
|
return 'join'; // FK 조인 (sourceTable.sourceField → targetTable.targetField)
|
|
}
|
|
|
|
// 3. column_labels.reference_table
|
|
if (subTable.relationType === 'reference') {
|
|
return 'join'; // 실제 엔티티 조인 (LEFT JOIN 등)
|
|
}
|
|
|
|
// 4. autocomplete, entity-search
|
|
if (subTable.relationType === 'lookup') {
|
|
return 'lookup'; // 코드→명칭 변환
|
|
}
|
|
|
|
// 5. 기타 (source, join 등)
|
|
return 'join';
|
|
}
|
|
|
|
// 저장 테이블 정보 타입
|
|
export interface SaveTableInfo {
|
|
tableName: string;
|
|
saveType: 'save' | 'edit' | 'delete' | 'transferData';
|
|
componentType: string;
|
|
isMainTable: boolean;
|
|
mappingRules?: Array<{
|
|
sourceField: string;
|
|
targetField: string;
|
|
transform?: string;
|
|
}>;
|
|
}
|
|
|
|
export interface ScreenSubTablesData {
|
|
screenId: number;
|
|
screenName: string;
|
|
mainTable: string;
|
|
subTables: SubTableInfo[];
|
|
saveTables?: SaveTableInfo[]; // 저장 대상 테이블 목록
|
|
}
|
|
|
|
// 여러 화면의 서브 테이블 정보 조회 (메인 테이블 → 서브 테이블 관계)
|
|
export async function getScreenSubTables(
|
|
screenIds: number[]
|
|
): Promise<ApiResponse<Record<number, ScreenSubTablesData>>> {
|
|
try {
|
|
const response = await apiClient.post("/screen-groups/sub-tables/batch", { screenIds });
|
|
return response.data;
|
|
} catch (error: any) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// 메뉴-화면그룹 동기화 API
|
|
// ============================================================
|
|
|
|
export interface SyncDetail {
|
|
action: 'created' | 'linked' | 'skipped' | 'error';
|
|
sourceName: string;
|
|
sourceId: number | string;
|
|
targetId?: number | string;
|
|
reason?: string;
|
|
}
|
|
|
|
export interface SyncResult {
|
|
success: boolean;
|
|
created: number;
|
|
linked: number;
|
|
skipped: number;
|
|
errors: string[];
|
|
details: SyncDetail[];
|
|
}
|
|
|
|
export interface SyncStatus {
|
|
screenGroups: { total: number; linked: number; unlinked: number };
|
|
menuItems: { total: number; linked: number; unlinked: number };
|
|
potentialMatches: Array<{ menuName: string; groupName: string; similarity: string }>;
|
|
}
|
|
|
|
// 동기화 상태 조회
|
|
export async function getMenuScreenSyncStatus(
|
|
targetCompanyCode?: string
|
|
): Promise<ApiResponse<SyncStatus>> {
|
|
try {
|
|
const queryParams = targetCompanyCode ? `?targetCompanyCode=${targetCompanyCode}` : '';
|
|
const response = await apiClient.get(`/screen-groups/sync/status${queryParams}`);
|
|
return response.data;
|
|
} catch (error: any) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
// 화면관리 → 메뉴 동기화
|
|
export async function syncScreenGroupsToMenu(
|
|
targetCompanyCode?: string
|
|
): Promise<ApiResponse<SyncResult>> {
|
|
try {
|
|
const response = await apiClient.post("/screen-groups/sync/screen-to-menu", { targetCompanyCode });
|
|
return response.data;
|
|
} catch (error: any) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
// 메뉴 → 화면관리 동기화
|
|
export async function syncMenuToScreenGroups(
|
|
targetCompanyCode?: string
|
|
): Promise<ApiResponse<SyncResult>> {
|
|
try {
|
|
const response = await apiClient.post("/screen-groups/sync/menu-to-screen", { targetCompanyCode });
|
|
return response.data;
|
|
} catch (error: any) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
// 전체 동기화 결과 타입
|
|
export interface AllCompaniesSyncResult {
|
|
totalCompanies: number;
|
|
successCount: number;
|
|
failedCount: number;
|
|
totalCreated: number;
|
|
totalLinked: number;
|
|
details: Array<{
|
|
companyCode: string;
|
|
companyName: string;
|
|
direction: 'screens-to-menus' | 'menus-to-screens';
|
|
created: number;
|
|
linked: number;
|
|
skipped: number;
|
|
success: boolean;
|
|
error?: string;
|
|
}>;
|
|
}
|
|
|
|
// 전체 회사 동기화 (최고 관리자만)
|
|
export async function syncAllCompanies(): Promise<ApiResponse<AllCompaniesSyncResult>> {
|
|
try {
|
|
const response = await apiClient.post("/screen-groups/sync/all");
|
|
return response.data;
|
|
} catch (error: any) {
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|
|
|
|
// ============================================================
|
|
// [PoC] screen_groups 기반 메뉴 트리 조회
|
|
// 화면관리 → 메뉴관리 통합 테스트용
|
|
// ============================================================
|
|
|
|
export interface MenuTreeItem {
|
|
id: number;
|
|
objid: number | string;
|
|
name: string;
|
|
name_kor: string;
|
|
icon?: string;
|
|
url: string | null;
|
|
screen_id: number | null;
|
|
screen_code?: string;
|
|
screen_count: number;
|
|
parent_id: number | null;
|
|
level: number;
|
|
display_order: number;
|
|
is_active: boolean;
|
|
menu_objid: number | null;
|
|
children: MenuTreeItem[];
|
|
// menu_info 호환 필드
|
|
menu_name_kor: string;
|
|
menu_url: string | null;
|
|
parent_obj_id: string | null;
|
|
seq: number;
|
|
status: string;
|
|
}
|
|
|
|
export interface MenuTreeResult {
|
|
data: MenuTreeItem[];
|
|
stats: {
|
|
totalGroups: number;
|
|
groupsWithScreens: number;
|
|
groupsWithMenuObjid: number;
|
|
rootGroups: number;
|
|
};
|
|
flatList: Array<{
|
|
objid: string;
|
|
OBJID: string;
|
|
menu_name_kor: string;
|
|
MENU_NAME_KOR: string;
|
|
menu_url: string | null;
|
|
MENU_URL: string | null;
|
|
parent_obj_id: string;
|
|
PARENT_OBJ_ID: string;
|
|
seq: number;
|
|
SEQ: number;
|
|
status: string;
|
|
STATUS: string;
|
|
menu_type: number;
|
|
MENU_TYPE: number;
|
|
screen_group_id: number;
|
|
menu_objid: number | null;
|
|
}>;
|
|
}
|
|
|
|
// [PoC] screen_groups 기반 메뉴 트리 조회
|
|
export async function getMenuTreeFromScreenGroups(targetCompanyCode?: string): Promise<ApiResponse<MenuTreeResult>> {
|
|
try {
|
|
const params = targetCompanyCode ? { targetCompanyCode } : {};
|
|
const response = await apiClient.get("/screen-groups/menu-tree", { params });
|
|
return response.data;
|
|
} catch (error: any) {
|
|
console.error("[PoC] 메뉴 트리 조회 실패:", error);
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|