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