feat(repeat-screen-modal): 복수 외부 테이블 집계 지원 및 집계 설정 모달 UI 추가
- 여러 외부 테이블 데이터를 합산하여 집계 계산 지원 - 집계 설정 전용 모달(AggregationSettingsModal) 추가 - AggregationConfig에 hidden 속성 추가 (연산에만 사용, 표시 제외) - 채번 규칙 API 에러 처리 개선 (조용히 무시, 로그 최소화)
This commit is contained in:
parent
5e97a3a5e9
commit
ae6f022f88
|
|
@ -607,7 +607,9 @@ class NumberingRuleService {
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await pool.query(query, params);
|
const result = await pool.query(query, params);
|
||||||
if (result.rowCount === 0) return null;
|
if (result.rowCount === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const rule = result.rows[0];
|
const rule = result.rows[0];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -317,6 +317,11 @@ apiClient.interceptors.response.use(
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 채번 규칙 미리보기 API 실패는 조용하게 처리 (화면 로드 시 자주 발생)
|
||||||
|
if (url?.includes("/numbering-rules/") && url?.includes("/preview")) {
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
|
||||||
// 다른 에러들은 기존처럼 상세 로그 출력
|
// 다른 에러들은 기존처럼 상세 로그 출력
|
||||||
console.error("API 응답 오류:", {
|
console.error("API 응답 오류:", {
|
||||||
status: status,
|
status: status,
|
||||||
|
|
@ -324,7 +329,6 @@ apiClient.interceptors.response.use(
|
||||||
url: url,
|
url: url,
|
||||||
data: error.response?.data,
|
data: error.response?.data,
|
||||||
message: error.message,
|
message: error.message,
|
||||||
headers: error.config?.headers,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 401 에러 처리
|
// 401 에러 처리
|
||||||
|
|
|
||||||
|
|
@ -109,11 +109,24 @@ export async function deleteNumberingRule(ruleId: string): Promise<ApiResponse<v
|
||||||
export async function previewNumberingCode(
|
export async function previewNumberingCode(
|
||||||
ruleId: string
|
ruleId: string
|
||||||
): Promise<ApiResponse<{ generatedCode: string }>> {
|
): Promise<ApiResponse<{ generatedCode: string }>> {
|
||||||
|
// ruleId 유효성 검사
|
||||||
|
if (!ruleId || ruleId === "undefined" || ruleId === "null") {
|
||||||
|
return { success: false, error: "채번 규칙 ID가 설정되지 않았습니다" };
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await apiClient.post(`/numbering-rules/${ruleId}/preview`);
|
const response = await apiClient.post(`/numbering-rules/${ruleId}/preview`);
|
||||||
|
if (!response.data) {
|
||||||
|
return { success: false, error: "서버 응답이 비어있습니다" };
|
||||||
|
}
|
||||||
return response.data;
|
return response.data;
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
return { success: false, error: error.message || "코드 미리보기 실패" };
|
const errorMessage =
|
||||||
|
error.response?.data?.error ||
|
||||||
|
error.response?.data?.message ||
|
||||||
|
error.message ||
|
||||||
|
"코드 미리보기 실패";
|
||||||
|
return { success: false, error: errorMessage };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -590,18 +590,24 @@ export function RepeatScreenModalComponent({
|
||||||
|
|
||||||
if (!hasExternalAggregation) return;
|
if (!hasExternalAggregation) return;
|
||||||
|
|
||||||
// contentRows에서 외부 테이블 데이터 소스가 있는 table 타입 행 찾기
|
// contentRows에서 외부 테이블 데이터 소스가 있는 모든 table 타입 행 찾기
|
||||||
const tableRowWithExternalSource = contentRows.find(
|
const tableRowsWithExternalSource = contentRows.filter(
|
||||||
(row) => row.type === "table" && row.tableDataSource?.enabled
|
(row) => row.type === "table" && row.tableDataSource?.enabled
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!tableRowWithExternalSource) return;
|
if (tableRowsWithExternalSource.length === 0) return;
|
||||||
|
|
||||||
// 각 카드의 집계 재계산
|
// 각 카드의 집계 재계산
|
||||||
const updatedCards = groupedCardsData.map((card) => {
|
const updatedCards = groupedCardsData.map((card) => {
|
||||||
const key = `${card._cardId}-${tableRowWithExternalSource.id}`;
|
// 🆕 v3.11: 모든 외부 테이블 행의 데이터를 합침
|
||||||
// 🆕 v3.7: 삭제된 행은 집계에서 제외
|
const allExternalRows: any[] = [];
|
||||||
const externalRows = (extData[key] || []).filter((row) => !row._isDeleted);
|
for (const tableRow of tableRowsWithExternalSource) {
|
||||||
|
const key = `${card._cardId}-${tableRow.id}`;
|
||||||
|
// 🆕 v3.7: 삭제된 행은 집계에서 제외
|
||||||
|
const rows = (extData[key] || []).filter((row) => !row._isDeleted);
|
||||||
|
allExternalRows.push(...rows);
|
||||||
|
}
|
||||||
|
const externalRows = allExternalRows;
|
||||||
|
|
||||||
// 집계 재계산
|
// 집계 재계산
|
||||||
const newAggregations: Record<string, number> = {};
|
const newAggregations: Record<string, number> = {};
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -289,6 +289,9 @@ export interface AggregationConfig {
|
||||||
resultField: string; // 결과 필드명 (예: "total_balance_qty")
|
resultField: string; // 결과 필드명 (예: "total_balance_qty")
|
||||||
label: string; // 표시 라벨 (예: "총수주잔량")
|
label: string; // 표시 라벨 (예: "총수주잔량")
|
||||||
|
|
||||||
|
// === 🆕 v3.10: 숨김 설정 ===
|
||||||
|
hidden?: boolean; // 레이아웃에서 숨김 (연산에만 사용, 기본: false)
|
||||||
|
|
||||||
// === 🆕 v3.9: 저장 설정 ===
|
// === 🆕 v3.9: 저장 설정 ===
|
||||||
saveConfig?: AggregationSaveConfig; // 연관 테이블 저장 설정
|
saveConfig?: AggregationSaveConfig; // 연관 테이블 저장 설정
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -113,22 +113,20 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
||||||
// 채번 규칙은 비동기로 처리
|
// 채번 규칙은 비동기로 처리
|
||||||
if (testAutoGeneration.type === "numbering_rule") {
|
if (testAutoGeneration.type === "numbering_rule") {
|
||||||
const ruleId = testAutoGeneration.options?.numberingRuleId;
|
const ruleId = testAutoGeneration.options?.numberingRuleId;
|
||||||
if (ruleId) {
|
if (ruleId && ruleId !== "undefined" && ruleId !== "null") {
|
||||||
try {
|
try {
|
||||||
console.log("🚀 채번 규칙 API 호출 시작:", ruleId);
|
const { previewNumberingCode } = await import("@/lib/api/numberingRule");
|
||||||
const { generateNumberingCode } = await import("@/lib/api/numberingRule");
|
const response = await previewNumberingCode(ruleId);
|
||||||
const response = await generateNumberingCode(ruleId);
|
|
||||||
console.log("✅ 채번 규칙 API 응답:", response);
|
|
||||||
if (response.success && response.data) {
|
if (response.success && response.data) {
|
||||||
generatedValue = response.data.generatedCode;
|
generatedValue = response.data.generatedCode;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
// 실패 시 조용히 무시 (채번 규칙이 없어도 화면은 정상 로드)
|
||||||
console.error("❌ 채번 규칙 코드 생성 실패:", error);
|
} catch {
|
||||||
|
// 네트워크 에러 등 예외 상황은 조용히 무시
|
||||||
} finally {
|
} finally {
|
||||||
isGeneratingRef.current = false; // 생성 완료
|
isGeneratingRef.current = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.warn("⚠️ 채번 규칙 ID가 없습니다");
|
|
||||||
isGeneratingRef.current = false;
|
isGeneratingRef.current = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue