lhj #343
|
|
@ -217,11 +217,14 @@ router.post("/:ruleId/allocate", authenticateToken, async (req: AuthenticatedReq
|
|||
const companyCode = req.user!.companyCode;
|
||||
const { ruleId } = req.params;
|
||||
|
||||
logger.info("코드 할당 요청", { ruleId, companyCode });
|
||||
|
||||
try {
|
||||
const allocatedCode = await numberingRuleService.allocateCode(ruleId, companyCode);
|
||||
logger.info("코드 할당 성공", { ruleId, allocatedCode });
|
||||
return res.json({ success: true, data: { generatedCode: allocatedCode } });
|
||||
} catch (error: any) {
|
||||
logger.error("코드 할당 실패", { error: error.message });
|
||||
logger.error("코드 할당 실패", { ruleId, companyCode, error: error.message });
|
||||
return res.status(500).json({ success: false, error: error.message });
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -761,10 +761,74 @@ export const EditModal: React.FC<EditModalProps> = ({ className }) => {
|
|||
// INSERT 모드
|
||||
console.log("[EditModal] INSERT 모드 - 새 데이터 생성:", formData);
|
||||
|
||||
// 🆕 채번 규칙 할당 처리 (저장 시점에 실제 순번 증가)
|
||||
const dataToSave = { ...formData };
|
||||
const fieldsWithNumbering: Record<string, string> = {};
|
||||
|
||||
// formData에서 채번 규칙이 설정된 필드 찾기
|
||||
for (const [key, value] of Object.entries(formData)) {
|
||||
if (key.endsWith("_numberingRuleId") && value) {
|
||||
const fieldName = key.replace("_numberingRuleId", "");
|
||||
fieldsWithNumbering[fieldName] = value as string;
|
||||
console.log(`🎯 [EditModal] 채번 규칙 발견: ${fieldName} → 규칙 ${value}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 채번 규칙이 있는 필드에 대해 allocateCode 호출
|
||||
if (Object.keys(fieldsWithNumbering).length > 0) {
|
||||
console.log("🎯 [EditModal] 채번 규칙 할당 시작");
|
||||
const { allocateNumberingCode } = await import("@/lib/api/numberingRule");
|
||||
|
||||
let hasAllocationFailure = false;
|
||||
const failedFields: string[] = [];
|
||||
|
||||
for (const [fieldName, ruleId] of Object.entries(fieldsWithNumbering)) {
|
||||
try {
|
||||
console.log(`🔄 [EditModal] ${fieldName} 필드에 대해 allocateCode 호출: ${ruleId}`);
|
||||
const allocateResult = await allocateNumberingCode(ruleId);
|
||||
|
||||
if (allocateResult.success && allocateResult.data?.generatedCode) {
|
||||
const newCode = allocateResult.data.generatedCode;
|
||||
console.log(`✅ [EditModal] ${fieldName} 새 코드 할당: ${dataToSave[fieldName]} → ${newCode}`);
|
||||
dataToSave[fieldName] = newCode;
|
||||
} else {
|
||||
console.warn(`⚠️ [EditModal] ${fieldName} 코드 할당 실패:`, allocateResult.error);
|
||||
if (!dataToSave[fieldName] || dataToSave[fieldName] === "") {
|
||||
hasAllocationFailure = true;
|
||||
failedFields.push(fieldName);
|
||||
}
|
||||
}
|
||||
} catch (allocateError) {
|
||||
console.error(`❌ [EditModal] ${fieldName} 코드 할당 오류:`, allocateError);
|
||||
if (!dataToSave[fieldName] || dataToSave[fieldName] === "") {
|
||||
hasAllocationFailure = true;
|
||||
failedFields.push(fieldName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 채번 규칙 할당 실패 시 저장 중단
|
||||
if (hasAllocationFailure) {
|
||||
const fieldNames = failedFields.join(", ");
|
||||
toast.error(`채번 규칙 할당에 실패했습니다 (${fieldNames}). 화면 설정에서 채번 규칙을 확인해주세요.`);
|
||||
console.error(`❌ [EditModal] 채번 규칙 할당 실패로 저장 중단. 실패 필드: ${fieldNames}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// _numberingRuleId 필드 제거 (실제 저장하지 않음)
|
||||
for (const key of Object.keys(dataToSave)) {
|
||||
if (key.endsWith("_numberingRuleId")) {
|
||||
delete dataToSave[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log("[EditModal] 최종 저장 데이터:", dataToSave);
|
||||
|
||||
const response = await dynamicFormApi.saveFormData({
|
||||
screenId: modalState.screenId!,
|
||||
tableName: screenData.screenInfo.tableName,
|
||||
data: formData,
|
||||
data: dataToSave,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
|
|
|
|||
|
|
@ -1,218 +1,23 @@
|
|||
"use client";
|
||||
|
||||
/**
|
||||
* PivotGrid 렌더러
|
||||
* 화면 관리 시스템에서 PivotGrid를 렌더링하는 컴포넌트
|
||||
*/
|
||||
|
||||
import React, { useState, useEffect, useMemo } from "react";
|
||||
import { ComponentRegistry } from "../../ComponentRegistry";
|
||||
import React from "react";
|
||||
import { AutoRegisteringComponentRenderer } from "../../AutoRegisteringComponentRenderer";
|
||||
import { createComponentDefinition } from "../../utils/createComponentDefinition";
|
||||
import { ComponentCategory } from "@/types/component";
|
||||
import { PivotGridComponent } from "./PivotGridComponent";
|
||||
import { PivotGridConfigPanel } from "./PivotGridConfigPanel";
|
||||
import {
|
||||
PivotGridComponentConfig,
|
||||
PivotFieldConfig,
|
||||
PivotCellData,
|
||||
} from "./types";
|
||||
import { apiClient } from "@/lib/api/client";
|
||||
|
||||
// ==================== 타입 ====================
|
||||
|
||||
interface PivotGridRendererProps {
|
||||
// 위젯 ID
|
||||
id?: string;
|
||||
|
||||
// 컴포넌트 설정
|
||||
config?: PivotGridComponentConfig;
|
||||
|
||||
// 외부 데이터 (formData 등에서 주입)
|
||||
data?: Record<string, any>[];
|
||||
|
||||
// 화면 관리 컨텍스트
|
||||
formData?: Record<string, any>;
|
||||
|
||||
// 이벤트 핸들러
|
||||
onCellClick?: (cellData: PivotCellData) => void;
|
||||
onDataLoad?: (data: Record<string, any>[]) => void;
|
||||
|
||||
// 제어관리 연동
|
||||
buttonControlOptions?: {
|
||||
buttonId?: string;
|
||||
actionType?: string;
|
||||
};
|
||||
|
||||
// 자동 필터 (멀티테넌시)
|
||||
autoFilter?: {
|
||||
companyCode?: string;
|
||||
};
|
||||
}
|
||||
|
||||
// ==================== 메인 컴포넌트 ====================
|
||||
|
||||
export const PivotGridRenderer: React.FC<PivotGridRendererProps> = ({
|
||||
id,
|
||||
config,
|
||||
data: externalData,
|
||||
formData,
|
||||
onCellClick,
|
||||
onDataLoad,
|
||||
buttonControlOptions,
|
||||
autoFilter,
|
||||
}) => {
|
||||
const [data, setData] = useState<Record<string, any>[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
// 데이터 로드
|
||||
useEffect(() => {
|
||||
const loadData = async () => {
|
||||
// 외부 데이터가 있으면 사용
|
||||
if (externalData && externalData.length > 0) {
|
||||
setData(externalData);
|
||||
onDataLoad?.(externalData);
|
||||
return;
|
||||
}
|
||||
|
||||
// 데이터 소스 설정 확인
|
||||
if (!config?.dataSource?.tableName) {
|
||||
setData([]);
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
// 테이블 데이터 조회
|
||||
const params: any = {
|
||||
tableName: config.dataSource.tableName,
|
||||
};
|
||||
|
||||
// 멀티테넌시 필터 적용
|
||||
if (autoFilter?.companyCode) {
|
||||
params.companyCode = autoFilter.companyCode;
|
||||
}
|
||||
|
||||
// 필터 조건 적용
|
||||
if (config.dataSource.filterConditions) {
|
||||
const filters: Record<string, any> = {};
|
||||
config.dataSource.filterConditions.forEach((cond) => {
|
||||
if (cond.valueFromField && formData) {
|
||||
filters[cond.field] = formData[cond.valueFromField];
|
||||
} else if (cond.value !== undefined) {
|
||||
filters[cond.field] = cond.value;
|
||||
}
|
||||
});
|
||||
params.filters = JSON.stringify(filters);
|
||||
}
|
||||
|
||||
const response = await apiClient.get(
|
||||
`/api/table-management/data/${config.dataSource.tableName}`,
|
||||
{ params }
|
||||
);
|
||||
|
||||
if (response.data.success) {
|
||||
const loadedData = response.data.data || [];
|
||||
setData(loadedData);
|
||||
onDataLoad?.(loadedData);
|
||||
} else {
|
||||
throw new Error(response.data.message || "데이터 로드 실패");
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error("PivotGrid 데이터 로드 실패:", err);
|
||||
setError(err.message || "데이터를 불러오는데 실패했습니다");
|
||||
setData([]);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
loadData();
|
||||
}, [
|
||||
config?.dataSource?.tableName,
|
||||
config?.dataSource?.filterConditions,
|
||||
externalData,
|
||||
formData,
|
||||
autoFilter?.companyCode,
|
||||
onDataLoad,
|
||||
]);
|
||||
|
||||
// 필드 설정에서 formData 값 적용
|
||||
const processedFields = useMemo<PivotFieldConfig[]>(() => {
|
||||
if (!config?.fields) return [];
|
||||
|
||||
return config.fields.map((field) => {
|
||||
// 필터 값에 formData 적용
|
||||
if (field.filterValues && formData) {
|
||||
return {
|
||||
...field,
|
||||
filterValues: field.filterValues.map((v) => {
|
||||
if (typeof v === "string" && v.startsWith("{{") && v.endsWith("}}")) {
|
||||
const key = v.slice(2, -2).trim();
|
||||
return formData[key] ?? v;
|
||||
}
|
||||
return v;
|
||||
}),
|
||||
};
|
||||
}
|
||||
return field;
|
||||
});
|
||||
}, [config?.fields, formData]);
|
||||
|
||||
// 로딩 상태
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="flex items-center justify-center p-8 text-muted-foreground">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="h-4 w-4 animate-spin rounded-full border-2 border-primary border-t-transparent" />
|
||||
<span className="text-sm">데이터 로딩 중...</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 에러 상태
|
||||
if (error) {
|
||||
return (
|
||||
<div className="flex items-center justify-center p-8 text-destructive">
|
||||
<div className="text-center">
|
||||
<p className="text-sm font-medium">데이터 로드 실패</p>
|
||||
<p className="text-xs mt-1">{error}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<PivotGridComponent
|
||||
id={id}
|
||||
title={config?.dataSource?.tableName}
|
||||
data={data}
|
||||
fields={processedFields}
|
||||
totals={config?.totals}
|
||||
style={config?.style}
|
||||
fieldChooser={config?.fieldChooser}
|
||||
chart={config?.chart}
|
||||
allowSortingBySummary={config?.allowSortingBySummary}
|
||||
allowFiltering={config?.allowFiltering}
|
||||
allowExpandAll={config?.allowExpandAll}
|
||||
wordWrapEnabled={config?.wordWrapEnabled}
|
||||
height={config?.height}
|
||||
maxHeight={config?.maxHeight}
|
||||
exportConfig={config?.exportConfig}
|
||||
onCellClick={onCellClick}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
// ==================== 컴포넌트 등록 ====================
|
||||
|
||||
ComponentRegistry.register({
|
||||
type: "pivot-grid",
|
||||
label: "피벗 그리드",
|
||||
category: "data",
|
||||
icon: "BarChart3",
|
||||
/**
|
||||
* PivotGrid 컴포넌트 정의
|
||||
*/
|
||||
const PivotGridDefinition = createComponentDefinition({
|
||||
id: "pivot-grid",
|
||||
name: "피벗 그리드",
|
||||
nameEng: "PivotGrid Component",
|
||||
description: "다차원 데이터 분석을 위한 피벗 테이블 컴포넌트",
|
||||
category: ComponentCategory.DISPLAY,
|
||||
webType: "text",
|
||||
component: PivotGridComponent,
|
||||
defaultConfig: {
|
||||
dataSource: {
|
||||
type: "table",
|
||||
|
|
@ -239,8 +44,41 @@ ComponentRegistry.register({
|
|||
},
|
||||
height: "400px",
|
||||
},
|
||||
Renderer: PivotGridRenderer,
|
||||
ConfigPanel: PivotGridConfigPanel,
|
||||
defaultSize: { width: 800, height: 500 },
|
||||
configPanel: PivotGridConfigPanel,
|
||||
icon: "BarChart3",
|
||||
tags: ["피벗", "분석", "집계", "그리드", "데이터"],
|
||||
version: "1.0.0",
|
||||
author: "개발팀",
|
||||
documentation: "",
|
||||
});
|
||||
|
||||
export default PivotGridRenderer;
|
||||
/**
|
||||
* PivotGrid 렌더러
|
||||
* 자동 등록 시스템을 사용하여 컴포넌트를 레지스트리에 등록
|
||||
*/
|
||||
export class PivotGridRenderer extends AutoRegisteringComponentRenderer {
|
||||
static componentDefinition = PivotGridDefinition;
|
||||
|
||||
render(): React.ReactElement {
|
||||
return (
|
||||
<PivotGridComponent
|
||||
{...this.props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 자동 등록 실행
|
||||
PivotGridRenderer.registerSelf();
|
||||
|
||||
// 강제 등록 (디버깅용)
|
||||
if (typeof window !== "undefined") {
|
||||
setTimeout(() => {
|
||||
try {
|
||||
PivotGridRenderer.registerSelf();
|
||||
} catch (error) {
|
||||
console.error("❌ PivotGrid 강제 등록 실패:", error);
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,12 +3,7 @@
|
|||
* 다차원 데이터 분석을 위한 피벗 테이블
|
||||
*/
|
||||
|
||||
// 메인 컴포넌트
|
||||
export { PivotGridComponent } from "./PivotGridComponent";
|
||||
export { PivotGridRenderer } from "./PivotGridRenderer";
|
||||
export { PivotGridConfigPanel } from "./PivotGridConfigPanel";
|
||||
|
||||
// 타입
|
||||
// 타입 내보내기
|
||||
export type {
|
||||
// 기본 타입
|
||||
PivotAreaType,
|
||||
|
|
@ -45,6 +40,10 @@ export type {
|
|||
PivotGridComponentConfig,
|
||||
} from "./types";
|
||||
|
||||
// 컴포넌트 내보내기
|
||||
export { PivotGridComponent } from "./PivotGridComponent";
|
||||
export { PivotGridConfigPanel } from "./PivotGridConfigPanel";
|
||||
|
||||
// 유틸리티
|
||||
export {
|
||||
aggregate,
|
||||
|
|
@ -60,4 +59,3 @@ export {
|
|||
} from "./utils/aggregation";
|
||||
|
||||
export { processPivotData, pathToKey, keyToPath } from "./utils/pivotEngine";
|
||||
|
||||
|
|
|
|||
|
|
@ -104,6 +104,20 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
|||
const currentFormValue = formData?.[component.columnName];
|
||||
const currentComponentValue = component.value;
|
||||
|
||||
// 🆕 채번 규칙이 설정되어 있으면 항상 _numberingRuleId를 formData에 설정
|
||||
// (값 생성 성공 여부와 관계없이, 저장 시점에 allocateCode를 호출하기 위함)
|
||||
if (testAutoGeneration.type === "numbering_rule" && testAutoGeneration.options?.numberingRuleId) {
|
||||
const ruleId = testAutoGeneration.options.numberingRuleId;
|
||||
if (ruleId && ruleId !== "undefined" && ruleId !== "null" && ruleId !== "") {
|
||||
const ruleIdKey = `${component.columnName}_numberingRuleId`;
|
||||
// formData에 아직 설정되지 않은 경우에만 설정
|
||||
if (isInteractive && onFormDataChange && !formData?.[ruleIdKey]) {
|
||||
onFormDataChange(ruleIdKey, ruleId);
|
||||
console.log("📝 채번 규칙 ID 사전 설정:", ruleIdKey, ruleId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 자동생성된 값이 없고, 현재 값도 없을 때만 생성
|
||||
if (!autoGeneratedValue && !currentFormValue && !currentComponentValue) {
|
||||
isGeneratingRef.current = true; // 생성 시작 플래그
|
||||
|
|
@ -144,13 +158,6 @@ export const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
|||
if (isInteractive && onFormDataChange && component.columnName) {
|
||||
console.log("📝 formData 업데이트:", component.columnName, generatedValue);
|
||||
onFormDataChange(component.columnName, generatedValue);
|
||||
|
||||
// 채번 규칙 ID도 함께 저장 (저장 시점에 실제 할당하기 위함)
|
||||
if (testAutoGeneration.type === "numbering_rule" && testAutoGeneration.options?.numberingRuleId) {
|
||||
const ruleIdKey = `${component.columnName}_numberingRuleId`;
|
||||
onFormDataChange(ruleIdKey, testAutoGeneration.options.numberingRuleId);
|
||||
console.log("📝 채번 규칙 ID 저장:", ruleIdKey, testAutoGeneration.options.numberingRuleId);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (!autoGeneratedValue && testAutoGeneration.type !== "none") {
|
||||
|
|
|
|||
|
|
@ -801,6 +801,9 @@ export class ButtonActionExecutor {
|
|||
console.log("🎯 채번 규칙 할당 시작 (allocateCode 호출)");
|
||||
const { allocateNumberingCode } = await import("@/lib/api/numberingRule");
|
||||
|
||||
let hasAllocationFailure = false;
|
||||
const failedFields: string[] = [];
|
||||
|
||||
for (const [fieldName, ruleId] of Object.entries(fieldsWithNumbering)) {
|
||||
try {
|
||||
console.log(`🔄 ${fieldName} 필드에 대해 allocateCode 호출: ${ruleId}`);
|
||||
|
|
@ -811,13 +814,31 @@ export class ButtonActionExecutor {
|
|||
console.log(`✅ ${fieldName} 새 코드 할당: ${formData[fieldName]} → ${newCode}`);
|
||||
formData[fieldName] = newCode;
|
||||
} else {
|
||||
console.warn(`⚠️ ${fieldName} 코드 할당 실패, 기존 값 유지:`, allocateResult.error);
|
||||
console.warn(`⚠️ ${fieldName} 코드 할당 실패:`, allocateResult.error);
|
||||
// 🆕 기존 값이 빈 문자열이면 실패로 표시
|
||||
if (!formData[fieldName] || formData[fieldName] === "") {
|
||||
hasAllocationFailure = true;
|
||||
failedFields.push(fieldName);
|
||||
}
|
||||
}
|
||||
} catch (allocateError) {
|
||||
console.error(`❌ ${fieldName} 코드 할당 오류:`, allocateError);
|
||||
// 오류 시 기존 값 유지
|
||||
// 🆕 기존 값이 빈 문자열이면 실패로 표시
|
||||
if (!formData[fieldName] || formData[fieldName] === "") {
|
||||
hasAllocationFailure = true;
|
||||
failedFields.push(fieldName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 🆕 채번 규칙 할당 실패 시 저장 중단
|
||||
if (hasAllocationFailure) {
|
||||
const fieldNames = failedFields.join(", ");
|
||||
toast.error(`채번 규칙 할당에 실패했습니다 (${fieldNames}). 화면 설정에서 채번 규칙을 확인해주세요.`);
|
||||
console.error(`❌ 채번 규칙 할당 실패로 저장 중단. 실패 필드: ${fieldNames}`);
|
||||
console.error("💡 해결 방법: 화면관리에서 해당 필드의 채번 규칙 설정을 확인하세요.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
console.log("✅ 채번 규칙 할당 완료");
|
||||
|
|
@ -3039,6 +3060,7 @@ export class ButtonActionExecutor {
|
|||
config: ButtonActionConfig,
|
||||
rowData: any,
|
||||
context: ButtonActionContext,
|
||||
isCreateMode: boolean = false, // 🆕 복사 모드에서 true로 전달
|
||||
): Promise<void> {
|
||||
const { groupByColumns = [] } = config;
|
||||
|
||||
|
|
@ -3112,10 +3134,11 @@ export class ButtonActionExecutor {
|
|||
const modalEvent = new CustomEvent("openEditModal", {
|
||||
detail: {
|
||||
screenId: config.targetScreenId,
|
||||
title: config.editModalTitle || "데이터 수정",
|
||||
title: isCreateMode ? (config.editModalTitle || "데이터 복사") : (config.editModalTitle || "데이터 수정"),
|
||||
description: description,
|
||||
modalSize: config.modalSize || "lg",
|
||||
editData: rowData,
|
||||
isCreateMode: isCreateMode, // 🆕 복사 모드에서 INSERT로 처리되도록
|
||||
groupByColumns: groupByColumns.length > 0 ? groupByColumns : undefined, // 🆕 그룹핑 컬럼 전달
|
||||
tableName: context.tableName, // 🆕 테이블명 전달
|
||||
buttonConfig: config, // 🆕 버튼 설정 전달 (제어로직 실행용)
|
||||
|
|
@ -3230,23 +3253,61 @@ export class ButtonActionExecutor {
|
|||
"code",
|
||||
];
|
||||
|
||||
// 🆕 화면 설정에서 채번 규칙 가져오기
|
||||
let screenNumberingRules: Record<string, string> = {};
|
||||
if (config.targetScreenId) {
|
||||
try {
|
||||
const { screenApi } = await import("@/lib/api/screen");
|
||||
const layout = await screenApi.getLayout(config.targetScreenId);
|
||||
|
||||
// 레이아웃에서 채번 규칙이 설정된 컴포넌트 찾기
|
||||
const findNumberingRules = (components: any[]): void => {
|
||||
for (const comp of components) {
|
||||
const compConfig = comp.componentConfig || {};
|
||||
// text-input 컴포넌트의 채번 규칙 확인
|
||||
if (compConfig.autoGeneration?.type === "numbering_rule" && compConfig.autoGeneration?.options?.numberingRuleId) {
|
||||
const columnName = compConfig.columnName || comp.columnName;
|
||||
if (columnName) {
|
||||
screenNumberingRules[columnName] = compConfig.autoGeneration.options.numberingRuleId;
|
||||
console.log(`📋 화면 설정에서 채번 규칙 발견: ${columnName} → ${compConfig.autoGeneration.options.numberingRuleId}`);
|
||||
}
|
||||
}
|
||||
// 중첩된 컴포넌트 확인
|
||||
if (comp.children && Array.isArray(comp.children)) {
|
||||
findNumberingRules(comp.children);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (layout?.components) {
|
||||
findNumberingRules(layout.components);
|
||||
}
|
||||
console.log("📋 화면 설정에서 찾은 채번 규칙:", screenNumberingRules);
|
||||
} catch (error) {
|
||||
console.warn("⚠️ 화면 레이아웃 조회 실패:", error);
|
||||
}
|
||||
}
|
||||
|
||||
// 품목코드 필드를 찾아서 무조건 공백으로 초기화
|
||||
let resetFieldName = "";
|
||||
for (const field of itemCodeFields) {
|
||||
if (copiedData[field] !== undefined) {
|
||||
const originalValue = copiedData[field];
|
||||
const ruleIdKey = `${field}_numberingRuleId`;
|
||||
const hasNumberingRule =
|
||||
rowData[ruleIdKey] !== undefined && rowData[ruleIdKey] !== null && rowData[ruleIdKey] !== "";
|
||||
|
||||
// 1순위: 원본 데이터에서 채번 규칙 ID 확인
|
||||
// 2순위: 화면 설정에서 채번 규칙 ID 확인
|
||||
const numberingRuleId = rowData[ruleIdKey] || screenNumberingRules[field];
|
||||
const hasNumberingRule = numberingRuleId !== undefined && numberingRuleId !== null && numberingRuleId !== "";
|
||||
|
||||
// 품목코드를 무조건 공백으로 초기화
|
||||
copiedData[field] = "";
|
||||
|
||||
// 채번 규칙 ID가 있으면 복사 (저장 시 자동 생성)
|
||||
if (hasNumberingRule) {
|
||||
copiedData[ruleIdKey] = rowData[ruleIdKey];
|
||||
copiedData[ruleIdKey] = numberingRuleId;
|
||||
console.log(`✅ 품목코드 초기화 (채번 규칙 있음): ${field} (기존값: ${originalValue})`);
|
||||
console.log(`📋 채번 규칙 ID 복사: ${ruleIdKey} = ${rowData[ruleIdKey]}`);
|
||||
console.log(`📋 채번 규칙 ID 설정: ${ruleIdKey} = ${numberingRuleId}`);
|
||||
} else {
|
||||
console.log(`✅ 품목코드 초기화 (수동 입력 필요): ${field} (기존값: ${originalValue})`);
|
||||
}
|
||||
|
|
@ -3303,9 +3364,9 @@ export class ButtonActionExecutor {
|
|||
|
||||
switch (editMode) {
|
||||
case "modal":
|
||||
// 모달로 복사 폼 열기 (편집 모달 재사용)
|
||||
console.log("📋 모달로 복사 폼 열기");
|
||||
await this.openEditModal(config, rowData, context);
|
||||
// 모달로 복사 폼 열기 (편집 모달 재사용, INSERT 모드로)
|
||||
console.log("📋 모달로 복사 폼 열기 (INSERT 모드)");
|
||||
await this.openEditModal(config, rowData, context, true); // 🆕 isCreateMode: true
|
||||
break;
|
||||
|
||||
case "navigate":
|
||||
|
|
@ -3316,8 +3377,8 @@ export class ButtonActionExecutor {
|
|||
|
||||
default:
|
||||
// 기본값: 모달
|
||||
console.log("📋 기본 모달로 복사 폼 열기");
|
||||
this.openEditModal(config, rowData, context);
|
||||
console.log("📋 기본 모달로 복사 폼 열기 (INSERT 모드)");
|
||||
this.openEditModal(config, rowData, context, true); // 🆕 isCreateMode: true
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error("❌ openCopyForm 실행 중 오류:", error);
|
||||
|
|
|
|||
Loading…
Reference in New Issue