178 lines
4.9 KiB
TypeScript
178 lines
4.9 KiB
TypeScript
|
|
/**
|
||
|
|
* 테이블 이력 조회 API 클라이언트
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { apiClient } from "./client";
|
||
|
|
|
||
|
|
export interface TableHistoryRecord {
|
||
|
|
log_id: number;
|
||
|
|
operation_type: "INSERT" | "UPDATE" | "DELETE";
|
||
|
|
original_id: string;
|
||
|
|
changed_column: string;
|
||
|
|
old_value: string | null;
|
||
|
|
new_value: string | null;
|
||
|
|
changed_by: string;
|
||
|
|
changed_at: string;
|
||
|
|
ip_address: string | null;
|
||
|
|
user_agent: string | null;
|
||
|
|
full_row_before: Record<string, any> | null;
|
||
|
|
full_row_after: Record<string, any> | null;
|
||
|
|
}
|
||
|
|
|
||
|
|
export interface TableHistoryResponse {
|
||
|
|
success: boolean;
|
||
|
|
data?: {
|
||
|
|
records: TableHistoryRecord[];
|
||
|
|
pagination: {
|
||
|
|
total: number;
|
||
|
|
limit: number;
|
||
|
|
offset: number;
|
||
|
|
hasMore: boolean;
|
||
|
|
};
|
||
|
|
};
|
||
|
|
message?: string;
|
||
|
|
error?: string;
|
||
|
|
errorCode?: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
export interface TableHistoryTimelineEvent {
|
||
|
|
changed_at: string;
|
||
|
|
changed_by: string;
|
||
|
|
operation_type: "INSERT" | "UPDATE" | "DELETE";
|
||
|
|
ip_address: string | null;
|
||
|
|
changes: Array<{
|
||
|
|
column: string;
|
||
|
|
oldValue: string | null;
|
||
|
|
newValue: string | null;
|
||
|
|
}>;
|
||
|
|
full_row_before: Record<string, any> | null;
|
||
|
|
full_row_after: Record<string, any> | null;
|
||
|
|
}
|
||
|
|
|
||
|
|
export interface TableHistoryTimelineResponse {
|
||
|
|
success: boolean;
|
||
|
|
data?: TableHistoryTimelineEvent[];
|
||
|
|
message?: string;
|
||
|
|
error?: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
export interface TableHistorySummary {
|
||
|
|
operation_type: string;
|
||
|
|
count: number;
|
||
|
|
affected_records: number;
|
||
|
|
unique_users: number;
|
||
|
|
first_change: string;
|
||
|
|
last_change: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
export interface TableHistorySummaryResponse {
|
||
|
|
success: boolean;
|
||
|
|
data?: TableHistorySummary[];
|
||
|
|
message?: string;
|
||
|
|
error?: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
export interface TableHistoryCheckResponse {
|
||
|
|
success: boolean;
|
||
|
|
data?: {
|
||
|
|
tableName: string;
|
||
|
|
logTableName: string;
|
||
|
|
exists: boolean;
|
||
|
|
historyEnabled: boolean;
|
||
|
|
};
|
||
|
|
message?: string;
|
||
|
|
error?: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 레코드 변경 이력 조회 (recordId가 null이면 전체 테이블 이력)
|
||
|
|
*/
|
||
|
|
export async function getRecordHistory(
|
||
|
|
tableName: string,
|
||
|
|
recordId: string | number | null,
|
||
|
|
params?: {
|
||
|
|
limit?: number;
|
||
|
|
offset?: number;
|
||
|
|
operationType?: "INSERT" | "UPDATE" | "DELETE";
|
||
|
|
changedBy?: string;
|
||
|
|
startDate?: string;
|
||
|
|
endDate?: string;
|
||
|
|
},
|
||
|
|
): Promise<TableHistoryResponse> {
|
||
|
|
try {
|
||
|
|
const queryParams = new URLSearchParams();
|
||
|
|
if (params?.limit) queryParams.append("limit", params.limit.toString());
|
||
|
|
if (params?.offset) queryParams.append("offset", params.offset.toString());
|
||
|
|
if (params?.operationType) queryParams.append("operationType", params.operationType);
|
||
|
|
if (params?.changedBy) queryParams.append("changedBy", params.changedBy);
|
||
|
|
if (params?.startDate) queryParams.append("startDate", params.startDate);
|
||
|
|
if (params?.endDate) queryParams.append("endDate", params.endDate);
|
||
|
|
|
||
|
|
// recordId가 null이면 전체 테이블 이력 조회
|
||
|
|
const url = recordId
|
||
|
|
? `/table-history/${tableName}/${recordId}?${queryParams.toString()}`
|
||
|
|
: `/table-history/${tableName}/all?${queryParams.toString()}`;
|
||
|
|
|
||
|
|
const response = await apiClient.get(url);
|
||
|
|
return response.data;
|
||
|
|
} catch (error: any) {
|
||
|
|
console.error("❌ 레코드 이력 조회 실패:", error);
|
||
|
|
return {
|
||
|
|
success: false,
|
||
|
|
error: error.response?.data?.message || error.message || "이력 조회 중 오류가 발생했습니다.",
|
||
|
|
errorCode: error.response?.data?.errorCode,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 특정 레코드의 타임라인 조회 (그룹화된 이벤트)
|
||
|
|
*/
|
||
|
|
export async function getRecordTimeline(
|
||
|
|
tableName: string,
|
||
|
|
recordId: string | number,
|
||
|
|
): Promise<TableHistoryTimelineResponse> {
|
||
|
|
try {
|
||
|
|
const response = await apiClient.get(`/table-history/${tableName}/${recordId}/timeline`);
|
||
|
|
return response.data;
|
||
|
|
} catch (error: any) {
|
||
|
|
console.error("❌ 타임라인 조회 실패:", error);
|
||
|
|
return {
|
||
|
|
success: false,
|
||
|
|
error: error.response?.data?.message || error.message || "타임라인 조회 중 오류가 발생했습니다.",
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 테이블 전체 이력 요약
|
||
|
|
*/
|
||
|
|
export async function getTableHistorySummary(tableName: string): Promise<TableHistorySummaryResponse> {
|
||
|
|
try {
|
||
|
|
const response = await apiClient.get(`/table-history/${tableName}/summary`);
|
||
|
|
return response.data;
|
||
|
|
} catch (error: any) {
|
||
|
|
console.error("❌ 이력 요약 조회 실패:", error);
|
||
|
|
return {
|
||
|
|
success: false,
|
||
|
|
error: error.response?.data?.message || error.message || "이력 요약 조회 중 오류가 발생했습니다.",
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 이력 테이블 존재 여부 확인
|
||
|
|
*/
|
||
|
|
export async function checkHistoryTableExists(tableName: string): Promise<TableHistoryCheckResponse> {
|
||
|
|
try {
|
||
|
|
const response = await apiClient.get(`/table-history/${tableName}/check`);
|
||
|
|
return response.data;
|
||
|
|
} catch (error: any) {
|
||
|
|
console.error("❌ 이력 테이블 확인 실패:", error);
|
||
|
|
return {
|
||
|
|
success: false,
|
||
|
|
error: error.response?.data?.message || error.message || "이력 테이블 확인 중 오류가 발생했습니다.",
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|