Merge remote-tracking branch 'origin/main' into ksh

This commit is contained in:
SeongHyun Kim
2025-12-11 11:47:43 +09:00
134 changed files with 26318 additions and 4223 deletions

View File

@@ -0,0 +1,231 @@
/**
* 자동 입력 (Auto-Fill) API 클라이언트
*/
import { apiClient } from "./client";
// =====================================================
// 타입 정의
// =====================================================
export interface AutoFillMapping {
mappingId?: number;
sourceColumn: string;
targetField: string;
targetLabel?: string;
isEditable?: string;
isRequired?: string;
defaultValue?: string;
sortOrder?: number;
}
export interface AutoFillGroup {
groupId?: number;
groupCode: string;
groupName: string;
description?: string;
masterTable: string;
masterValueColumn: string;
masterLabelColumn?: string;
companyCode?: string;
isActive?: string;
createdDate?: string;
updatedDate?: string;
mappingCount?: number;
mappings?: AutoFillMapping[];
}
export interface AutoFillOption {
value: string;
label: string;
}
export interface AutoFillDataResponse {
data: Record<string, any>;
mappings: Array<{
targetField: string;
targetLabel: string;
value: any;
isEditable: boolean;
isRequired: boolean;
}>;
}
// =====================================================
// API 함수
// =====================================================
/**
* 자동 입력 그룹 목록 조회
*/
export async function getAutoFillGroups(isActive?: string): Promise<{
success: boolean;
data?: AutoFillGroup[];
error?: string;
}> {
try {
const params = new URLSearchParams();
if (isActive) params.append("isActive", isActive);
const response = await apiClient.get(`/cascading-auto-fill/groups?${params.toString()}`);
return response.data;
} catch (error: any) {
console.error("자동 입력 그룹 목록 조회 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
/**
* 자동 입력 그룹 상세 조회 (매핑 포함)
*/
export async function getAutoFillGroupDetail(groupCode: string): Promise<{
success: boolean;
data?: AutoFillGroup;
error?: string;
}> {
try {
const response = await apiClient.get(`/cascading-auto-fill/groups/${groupCode}`);
return response.data;
} catch (error: any) {
console.error("자동 입력 그룹 상세 조회 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
/**
* 자동 입력 그룹 생성
*/
export async function createAutoFillGroup(data: {
groupCode: string;
groupName: string;
description?: string;
masterTable: string;
masterValueColumn: string;
masterLabelColumn?: string;
mappings?: AutoFillMapping[];
}): Promise<{
success: boolean;
data?: AutoFillGroup;
message?: string;
error?: string;
}> {
try {
const response = await apiClient.post("/cascading-auto-fill/groups", data);
return response.data;
} catch (error: any) {
console.error("자동 입력 그룹 생성 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
/**
* 자동 입력 그룹 수정
*/
export async function updateAutoFillGroup(
groupCode: string,
data: Partial<AutoFillGroup> & { mappings?: AutoFillMapping[] }
): Promise<{
success: boolean;
data?: AutoFillGroup;
message?: string;
error?: string;
}> {
try {
const response = await apiClient.put(`/cascading-auto-fill/groups/${groupCode}`, data);
return response.data;
} catch (error: any) {
console.error("자동 입력 그룹 수정 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
/**
* 자동 입력 그룹 삭제
*/
export async function deleteAutoFillGroup(groupCode: string): Promise<{
success: boolean;
message?: string;
error?: string;
}> {
try {
const response = await apiClient.delete(`/cascading-auto-fill/groups/${groupCode}`);
return response.data;
} catch (error: any) {
console.error("자동 입력 그룹 삭제 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
/**
* 마스터 옵션 목록 조회
*/
export async function getAutoFillMasterOptions(groupCode: string): Promise<{
success: boolean;
data?: AutoFillOption[];
error?: string;
}> {
try {
const response = await apiClient.get(`/cascading-auto-fill/options/${groupCode}`);
return response.data;
} catch (error: any) {
console.error("마스터 옵션 목록 조회 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
/**
* 자동 입력 데이터 조회
* 마스터 값 선택 시 자동으로 입력할 데이터 조회
*/
export async function getAutoFillData(
groupCode: string,
masterValue: string
): Promise<{
success: boolean;
data?: Record<string, any>;
mappings?: AutoFillDataResponse["mappings"];
error?: string;
}> {
try {
const response = await apiClient.get(
`/cascading-auto-fill/data/${groupCode}?masterValue=${encodeURIComponent(masterValue)}`
);
return response.data;
} catch (error: any) {
console.error("자동 입력 데이터 조회 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
// 편의를 위한 네임스페이스 export
export const cascadingAutoFillApi = {
getGroups: getAutoFillGroups,
getGroupDetail: getAutoFillGroupDetail,
createGroup: createAutoFillGroup,
updateGroup: updateAutoFillGroup,
deleteGroup: deleteAutoFillGroup,
getMasterOptions: getAutoFillMasterOptions,
getData: getAutoFillData,
};

View File

@@ -0,0 +1,206 @@
/**
* 조건부 연쇄 (Conditional Cascading) API 클라이언트
*/
import { apiClient } from "./client";
// =====================================================
// 타입 정의
// =====================================================
export interface CascadingCondition {
conditionId?: number;
relationType: string; // "RELATION" | "HIERARCHY"
relationCode: string;
conditionName: string;
conditionField: string;
conditionOperator: string; // "EQ" | "NEQ" | "CONTAINS" | "IN" | "GT" | "LT" 등
conditionValue: string;
filterColumn: string;
filterValues: string; // 콤마로 구분된 값들
priority?: number;
companyCode?: string;
isActive?: string;
createdDate?: string;
updatedDate?: string;
}
// 연산자 목록
export const CONDITION_OPERATORS = [
{ value: "EQ", label: "같음 (=)" },
{ value: "NEQ", label: "같지 않음 (!=)" },
{ value: "CONTAINS", label: "포함" },
{ value: "NOT_CONTAINS", label: "포함하지 않음" },
{ value: "STARTS_WITH", label: "시작" },
{ value: "ENDS_WITH", label: "끝" },
{ value: "IN", label: "목록에 포함" },
{ value: "NOT_IN", label: "목록에 미포함" },
{ value: "GT", label: "보다 큼 (>)" },
{ value: "GTE", label: "보다 크거나 같음 (>=)" },
{ value: "LT", label: "보다 작음 (<)" },
{ value: "LTE", label: "보다 작거나 같음 (<=)" },
{ value: "IS_NULL", label: "비어있음" },
{ value: "IS_NOT_NULL", label: "비어있지 않음" },
];
// =====================================================
// API 함수
// =====================================================
/**
* 조건부 연쇄 규칙 목록 조회
*/
export async function getConditions(params?: {
isActive?: string;
relationCode?: string;
relationType?: string;
}): Promise<{
success: boolean;
data?: CascadingCondition[];
error?: string;
}> {
try {
const searchParams = new URLSearchParams();
if (params?.isActive) searchParams.append("isActive", params.isActive);
if (params?.relationCode) searchParams.append("relationCode", params.relationCode);
if (params?.relationType) searchParams.append("relationType", params.relationType);
const response = await apiClient.get(`/cascading-conditions?${searchParams.toString()}`);
return response.data;
} catch (error: any) {
console.error("조건부 연쇄 규칙 목록 조회 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
/**
* 조건부 연쇄 규칙 상세 조회
*/
export async function getConditionDetail(conditionId: number): Promise<{
success: boolean;
data?: CascadingCondition;
error?: string;
}> {
try {
const response = await apiClient.get(`/cascading-conditions/${conditionId}`);
return response.data;
} catch (error: any) {
console.error("조건부 연쇄 규칙 상세 조회 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
/**
* 조건부 연쇄 규칙 생성
*/
export async function createCondition(data: Omit<CascadingCondition, "conditionId">): Promise<{
success: boolean;
data?: CascadingCondition;
message?: string;
error?: string;
}> {
try {
const response = await apiClient.post("/cascading-conditions", data);
return response.data;
} catch (error: any) {
console.error("조건부 연쇄 규칙 생성 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
/**
* 조건부 연쇄 규칙 수정
*/
export async function updateCondition(
conditionId: number,
data: Partial<CascadingCondition>
): Promise<{
success: boolean;
data?: CascadingCondition;
message?: string;
error?: string;
}> {
try {
const response = await apiClient.put(`/cascading-conditions/${conditionId}`, data);
return response.data;
} catch (error: any) {
console.error("조건부 연쇄 규칙 수정 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
/**
* 조건부 연쇄 규칙 삭제
*/
export async function deleteCondition(conditionId: number): Promise<{
success: boolean;
message?: string;
error?: string;
}> {
try {
const response = await apiClient.delete(`/cascading-conditions/${conditionId}`);
return response.data;
} catch (error: any) {
console.error("조건부 연쇄 규칙 삭제 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
/**
* 조건에 따른 필터링된 옵션 조회
*/
export async function getFilteredOptions(
relationCode: string,
params: {
conditionFieldValue?: string;
parentValue?: string;
}
): Promise<{
success: boolean;
data?: Array<{ value: string; label: string }>;
appliedCondition?: { conditionId: number; conditionName: string } | null;
error?: string;
}> {
try {
const searchParams = new URLSearchParams();
if (params.conditionFieldValue) searchParams.append("conditionFieldValue", params.conditionFieldValue);
if (params.parentValue) searchParams.append("parentValue", params.parentValue);
const response = await apiClient.get(
`/cascading-conditions/filtered-options/${relationCode}?${searchParams.toString()}`
);
return response.data;
} catch (error: any) {
console.error("조건부 필터링 옵션 조회 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
// 편의를 위한 네임스페이스 export
export const cascadingConditionApi = {
getList: getConditions,
getDetail: getConditionDetail,
create: createCondition,
update: updateCondition,
delete: deleteCondition,
getFilteredOptions,
};

View File

@@ -0,0 +1,317 @@
/**
* 다단계 계층 (Hierarchy) API 클라이언트
*/
import { apiClient } from "./client";
// =====================================================
// 타입 정의
// =====================================================
export interface HierarchyLevel {
levelId?: number;
groupCode: string;
companyCode?: string;
levelOrder: number;
levelName: string;
levelCode?: string;
tableName: string;
valueColumn: string;
labelColumn: string;
parentKeyColumn?: string;
filterColumn?: string;
filterValue?: string;
orderColumn?: string;
orderDirection?: string;
placeholder?: string;
isRequired?: string;
isSearchable?: string;
isActive?: string;
createdDate?: string;
updatedDate?: string;
}
export interface HierarchyGroup {
groupId?: number;
groupCode: string;
groupName: string;
description?: string;
hierarchyType: "MULTI_TABLE" | "SELF_REFERENCE" | "BOM" | "TREE";
maxLevels?: number;
isFixedLevels?: string;
// Self-reference 설정
selfRefTable?: string;
selfRefIdColumn?: string;
selfRefParentColumn?: string;
selfRefValueColumn?: string;
selfRefLabelColumn?: string;
selfRefLevelColumn?: string;
selfRefOrderColumn?: string;
// BOM 설정
bomTable?: string;
bomParentColumn?: string;
bomChildColumn?: string;
bomItemTable?: string;
bomItemIdColumn?: string;
bomItemLabelColumn?: string;
bomQtyColumn?: string;
bomLevelColumn?: string;
// 메시지
emptyMessage?: string;
noOptionsMessage?: string;
loadingMessage?: string;
// 메타
companyCode?: string;
isActive?: string;
createdBy?: string;
createdDate?: string;
updatedBy?: string;
updatedDate?: string;
// 조회 시 포함
levels?: HierarchyLevel[];
levelCount?: number;
}
// 계층 타입
export const HIERARCHY_TYPES = [
{ value: "MULTI_TABLE", label: "다중 테이블 (국가>도시>구)" },
{ value: "SELF_REFERENCE", label: "자기 참조 (조직도)" },
{ value: "BOM", label: "BOM (부품 구조)" },
{ value: "TREE", label: "트리 (카테고리)" },
];
// =====================================================
// API 함수
// =====================================================
/**
* 계층 그룹 목록 조회
*/
export async function getHierarchyGroups(params?: {
isActive?: string;
hierarchyType?: string;
}): Promise<{
success: boolean;
data?: HierarchyGroup[];
error?: string;
}> {
try {
const searchParams = new URLSearchParams();
if (params?.isActive) searchParams.append("isActive", params.isActive);
if (params?.hierarchyType) searchParams.append("hierarchyType", params.hierarchyType);
const response = await apiClient.get(`/cascading-hierarchy?${searchParams.toString()}`);
return response.data;
} catch (error: any) {
console.error("계층 그룹 목록 조회 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
/**
* 계층 그룹 상세 조회 (레벨 포함)
*/
export async function getHierarchyGroupDetail(groupCode: string): Promise<{
success: boolean;
data?: HierarchyGroup;
error?: string;
}> {
try {
const response = await apiClient.get(`/cascading-hierarchy/${groupCode}`);
return response.data;
} catch (error: any) {
console.error("계층 그룹 상세 조회 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
/**
* 계층 그룹 생성
*/
export async function createHierarchyGroup(
data: Omit<HierarchyGroup, "groupId"> & { levels?: Partial<HierarchyLevel>[] }
): Promise<{
success: boolean;
data?: HierarchyGroup;
message?: string;
error?: string;
}> {
try {
const response = await apiClient.post("/cascading-hierarchy", data);
return response.data;
} catch (error: any) {
console.error("계층 그룹 생성 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
/**
* 계층 그룹 수정
*/
export async function updateHierarchyGroup(
groupCode: string,
data: Partial<HierarchyGroup>
): Promise<{
success: boolean;
data?: HierarchyGroup;
message?: string;
error?: string;
}> {
try {
const response = await apiClient.put(`/cascading-hierarchy/${groupCode}`, data);
return response.data;
} catch (error: any) {
console.error("계층 그룹 수정 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
/**
* 계층 그룹 삭제
*/
export async function deleteHierarchyGroup(groupCode: string): Promise<{
success: boolean;
message?: string;
error?: string;
}> {
try {
const response = await apiClient.delete(`/cascading-hierarchy/${groupCode}`);
return response.data;
} catch (error: any) {
console.error("계층 그룹 삭제 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
/**
* 레벨 추가
*/
export async function addLevel(
groupCode: string,
data: Partial<HierarchyLevel>
): Promise<{
success: boolean;
data?: HierarchyLevel;
message?: string;
error?: string;
}> {
try {
const response = await apiClient.post(`/cascading-hierarchy/${groupCode}/levels`, data);
return response.data;
} catch (error: any) {
console.error("레벨 추가 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
/**
* 레벨 수정
*/
export async function updateLevel(
levelId: number,
data: Partial<HierarchyLevel>
): Promise<{
success: boolean;
data?: HierarchyLevel;
message?: string;
error?: string;
}> {
try {
const response = await apiClient.put(`/cascading-hierarchy/levels/${levelId}`, data);
return response.data;
} catch (error: any) {
console.error("레벨 수정 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
/**
* 레벨 삭제
*/
export async function deleteLevel(levelId: number): Promise<{
success: boolean;
message?: string;
error?: string;
}> {
try {
const response = await apiClient.delete(`/cascading-hierarchy/levels/${levelId}`);
return response.data;
} catch (error: any) {
console.error("레벨 삭제 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
/**
* 특정 레벨의 옵션 조회
*/
export async function getLevelOptions(
groupCode: string,
levelOrder: number,
parentValue?: string
): Promise<{
success: boolean;
data?: Array<{ value: string; label: string }>;
levelInfo?: {
levelId: number;
levelName: string;
placeholder: string;
isRequired: string;
isSearchable: string;
};
error?: string;
}> {
try {
const params = new URLSearchParams();
if (parentValue) params.append("parentValue", parentValue);
const response = await apiClient.get(
`/cascading-hierarchy/${groupCode}/options/${levelOrder}?${params.toString()}`
);
return response.data;
} catch (error: any) {
console.error("레벨 옵션 조회 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
// 편의를 위한 네임스페이스 export
export const hierarchyApi = {
getGroups: getHierarchyGroups,
getDetail: getHierarchyGroupDetail,
createGroup: createHierarchyGroup,
updateGroup: updateHierarchyGroup,
deleteGroup: deleteHierarchyGroup,
addLevel,
updateLevel,
deleteLevel,
getLevelOptions,
};

View File

@@ -0,0 +1,215 @@
/**
* 상호 배제 (Mutual Exclusion) API 클라이언트
*/
import { apiClient } from "./client";
// =====================================================
// 타입 정의
// =====================================================
export interface MutualExclusion {
exclusionId?: number;
exclusionCode: string;
exclusionName: string;
fieldNames: string; // 콤마로 구분된 필드명 (예: "source_warehouse,target_warehouse")
sourceTable: string;
valueColumn: string;
labelColumn?: string;
exclusionType?: string; // "SAME_VALUE"
errorMessage?: string;
companyCode?: string;
isActive?: string;
createdDate?: string;
}
// 배제 타입 목록
export const EXCLUSION_TYPES = [
{ value: "SAME_VALUE", label: "동일 값 배제" },
{ value: "RELATED", label: "관련 값 배제 (예정)" },
];
// =====================================================
// API 함수
// =====================================================
/**
* 상호 배제 규칙 목록 조회
*/
export async function getExclusions(isActive?: string): Promise<{
success: boolean;
data?: MutualExclusion[];
error?: string;
}> {
try {
const params = new URLSearchParams();
if (isActive) params.append("isActive", isActive);
const response = await apiClient.get(`/cascading-exclusions?${params.toString()}`);
return response.data;
} catch (error: any) {
console.error("상호 배제 규칙 목록 조회 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
/**
* 상호 배제 규칙 상세 조회
*/
export async function getExclusionDetail(exclusionId: number): Promise<{
success: boolean;
data?: MutualExclusion;
error?: string;
}> {
try {
const response = await apiClient.get(`/cascading-exclusions/${exclusionId}`);
return response.data;
} catch (error: any) {
console.error("상호 배제 규칙 상세 조회 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
/**
* 상호 배제 규칙 생성
*/
export async function createExclusion(data: Omit<MutualExclusion, "exclusionId">): Promise<{
success: boolean;
data?: MutualExclusion;
message?: string;
error?: string;
}> {
try {
const response = await apiClient.post("/cascading-exclusions", data);
return response.data;
} catch (error: any) {
console.error("상호 배제 규칙 생성 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
/**
* 상호 배제 규칙 수정
*/
export async function updateExclusion(
exclusionId: number,
data: Partial<MutualExclusion>
): Promise<{
success: boolean;
data?: MutualExclusion;
message?: string;
error?: string;
}> {
try {
const response = await apiClient.put(`/cascading-exclusions/${exclusionId}`, data);
return response.data;
} catch (error: any) {
console.error("상호 배제 규칙 수정 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
/**
* 상호 배제 규칙 삭제
*/
export async function deleteExclusion(exclusionId: number): Promise<{
success: boolean;
message?: string;
error?: string;
}> {
try {
const response = await apiClient.delete(`/cascading-exclusions/${exclusionId}`);
return response.data;
} catch (error: any) {
console.error("상호 배제 규칙 삭제 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
/**
* 상호 배제 검증
*/
export async function validateExclusion(
exclusionCode: string,
fieldValues: Record<string, string>
): Promise<{
success: boolean;
data?: {
isValid: boolean;
errorMessage: string | null;
conflictingFields: string[];
};
error?: string;
}> {
try {
const response = await apiClient.post(`/cascading-exclusions/validate/${exclusionCode}`, {
fieldValues,
});
return response.data;
} catch (error: any) {
console.error("상호 배제 검증 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
/**
* 배제된 옵션 조회 (다른 필드에서 선택한 값 제외)
*/
export async function getExcludedOptions(
exclusionCode: string,
params: {
currentField?: string;
selectedValues?: string; // 콤마로 구분된 값들
}
): Promise<{
success: boolean;
data?: Array<{ value: string; label: string }>;
error?: string;
}> {
try {
const searchParams = new URLSearchParams();
if (params.currentField) searchParams.append("currentField", params.currentField);
if (params.selectedValues) searchParams.append("selectedValues", params.selectedValues);
const response = await apiClient.get(
`/cascading-exclusions/options/${exclusionCode}?${searchParams.toString()}`
);
return response.data;
} catch (error: any) {
console.error("배제된 옵션 조회 실패:", error);
return {
success: false,
error: error.response?.data?.message || error.message,
};
}
}
// 편의를 위한 네임스페이스 export
export const mutualExclusionApi = {
getList: getExclusions,
getDetail: getExclusionDetail,
create: createExclusion,
update: updateExclusion,
delete: deleteExclusion,
validate: validateExclusion,
getExcludedOptions,
};

View File

@@ -0,0 +1,161 @@
import { apiClient } from "./client";
export interface CascadingRelation {
relation_id: number;
relation_code: string;
relation_name: string;
description?: string;
parent_table: string;
parent_value_column: string;
parent_label_column?: string;
child_table: string;
child_filter_column: string;
child_value_column: string;
child_label_column: string;
child_order_column?: string;
child_order_direction?: string;
empty_parent_message?: string;
no_options_message?: string;
loading_message?: string;
clear_on_parent_change?: string;
company_code: string;
is_active?: string;
created_by?: string;
created_date?: string;
updated_by?: string;
updated_date?: string;
}
export interface CascadingRelationCreateInput {
relationCode: string;
relationName: string;
description?: string;
parentTable: string;
parentValueColumn: string;
parentLabelColumn?: string;
childTable: string;
childFilterColumn: string;
childValueColumn: string;
childLabelColumn: string;
childOrderColumn?: string;
childOrderDirection?: string;
emptyParentMessage?: string;
noOptionsMessage?: string;
loadingMessage?: string;
clearOnParentChange?: boolean;
}
export interface CascadingRelationUpdateInput extends Partial<CascadingRelationCreateInput> {
isActive?: boolean;
}
export interface CascadingOption {
value: string;
label: string;
}
/**
* 연쇄 관계 목록 조회
*/
export const getCascadingRelations = async (isActive?: string) => {
try {
const params = new URLSearchParams();
if (isActive !== undefined) {
params.append("isActive", isActive);
}
const response = await apiClient.get(`/cascading-relations?${params.toString()}`);
return response.data;
} catch (error: any) {
console.error("연쇄 관계 목록 조회 실패:", error);
return { success: false, error: error.message };
}
};
/**
* 연쇄 관계 상세 조회 (ID)
*/
export const getCascadingRelationById = async (id: number) => {
try {
const response = await apiClient.get(`/cascading-relations/${id}`);
return response.data;
} catch (error: any) {
console.error("연쇄 관계 상세 조회 실패:", error);
return { success: false, error: error.message };
}
};
/**
* 연쇄 관계 코드로 조회
*/
export const getCascadingRelationByCode = async (code: string) => {
try {
const response = await apiClient.get(`/cascading-relations/code/${code}`);
return response.data;
} catch (error: any) {
console.error("연쇄 관계 코드 조회 실패:", error);
return { success: false, error: error.message };
}
};
/**
* 연쇄 관계로 자식 옵션 조회
*/
export const getCascadingOptions = async (code: string, parentValue: string): Promise<{ success: boolean; data?: CascadingOption[]; error?: string }> => {
try {
const response = await apiClient.get(`/cascading-relations/options/${code}?parentValue=${encodeURIComponent(parentValue)}`);
return response.data;
} catch (error: any) {
console.error("연쇄 옵션 조회 실패:", error);
return { success: false, error: error.message };
}
};
/**
* 연쇄 관계 생성
*/
export const createCascadingRelation = async (data: CascadingRelationCreateInput) => {
try {
const response = await apiClient.post("/cascading-relations", data);
return response.data;
} catch (error: any) {
console.error("연쇄 관계 생성 실패:", error);
return { success: false, error: error.message };
}
};
/**
* 연쇄 관계 수정
*/
export const updateCascadingRelation = async (id: number, data: CascadingRelationUpdateInput) => {
try {
const response = await apiClient.put(`/cascading-relations/${id}`, data);
return response.data;
} catch (error: any) {
console.error("연쇄 관계 수정 실패:", error);
return { success: false, error: error.message };
}
};
/**
* 연쇄 관계 삭제
*/
export const deleteCascadingRelation = async (id: number) => {
try {
const response = await apiClient.delete(`/cascading-relations/${id}`);
return response.data;
} catch (error: any) {
console.error("연쇄 관계 삭제 실패:", error);
return { success: false, error: error.message };
}
};
export const cascadingRelationApi = {
getList: getCascadingRelations,
getById: getCascadingRelationById,
getByCode: getCascadingRelationByCode,
getOptions: getCascadingOptions,
create: createCascadingRelation,
update: updateCascadingRelation,
delete: deleteCascadingRelation,
};

View File

@@ -525,3 +525,37 @@ export async function getFlowAuditLogs(flowId: number, limit: number = 100): Pro
};
}
}
// ============================================
// 플로우 스텝 데이터 수정 API
// ============================================
/**
* 플로우 스텝 데이터 업데이트 (인라인 편집)
* @param flowId 플로우 정의 ID
* @param stepId 스텝 ID
* @param recordId 레코드의 primary key 값
* @param updateData 업데이트할 데이터
*/
export async function updateFlowStepData(
flowId: number,
stepId: number,
recordId: string | number,
updateData: Record<string, any>,
): Promise<ApiResponse<{ success: boolean }>> {
try {
const response = await fetch(`${API_BASE}/flow/${flowId}/step/${stepId}/data/${recordId}`, {
method: "PUT",
headers: getAuthHeaders(),
credentials: "include",
body: JSON.stringify(updateData),
});
return await response.json();
} catch (error: any) {
return {
success: false,
error: error.message,
};
}
}