summaryrefslogtreecommitdiff
path: root/components/form-data/spreadJS-dialog.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'components/form-data/spreadJS-dialog.tsx')
-rw-r--r--components/form-data/spreadJS-dialog.tsx725
1 files changed, 381 insertions, 344 deletions
diff --git a/components/form-data/spreadJS-dialog.tsx b/components/form-data/spreadJS-dialog.tsx
index d001463e..91d5672c 100644
--- a/components/form-data/spreadJS-dialog.tsx
+++ b/components/form-data/spreadJS-dialog.tsx
@@ -107,9 +107,9 @@ interface LoadingProgressProps {
const LoadingProgress: React.FC<LoadingProgressProps> = ({ phase, progress, total, isVisible }) => {
const percentage = total > 0 ? Math.round((progress / total) * 100) : 0;
-
+
if (!isVisible) return null;
-
+
return (
<div className="absolute inset-0 bg-white/90 flex items-center justify-center z-50">
<div className="bg-white rounded-lg shadow-lg border p-6 min-w-[300px]">
@@ -117,11 +117,11 @@ const LoadingProgress: React.FC<LoadingProgressProps> = ({ phase, progress, tota
<Loader className="h-5 w-5 animate-spin text-blue-600" />
<span className="font-medium text-gray-900">Loading Template</span>
</div>
-
+
<div className="space-y-2">
<div className="text-sm text-gray-600">{phase}</div>
<div className="w-full bg-gray-200 rounded-full h-2">
- <div
+ <div
className="bg-blue-600 h-2 rounded-full transition-all duration-300 ease-out"
style={{ width: `${percentage}%` }}
/>
@@ -161,7 +161,7 @@ export function TemplateViewDialog({
const [validationErrors, setValidationErrors] = React.useState<ValidationError[]>([]);
const [selectedTemplateId, setSelectedTemplateId] = React.useState<string>("");
const [availableTemplates, setAvailableTemplates] = React.useState<TemplateItem[]>([]);
-
+
// ๐Ÿ†• ๋กœ๋”ฉ ์ƒํƒœ ์ถ”๊ฐ€
const [loadingProgress, setLoadingProgress] = React.useState<{
phase: string;
@@ -244,102 +244,102 @@ export function TemplateViewDialog({
}
return editableFieldsMap.get(selectedRow.TAG_NO) || [];
}
-
+
// SPREAD_LIST๋‚˜ GRD_LIST์˜ ๊ฒฝ์šฐ ์ „์—ญ editableFields๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ
return [];
}, [templateType, selectedRow?.TAG_NO, editableFieldsMap]);
-
-const isFieldEditable = React.useCallback((attId: string, rowData?: GenericData) => {
- const columnConfig = columnsJSON.find(col => col.key === attId);
- if (columnConfig?.shi === "OUT" || columnConfig?.shi === null) {
- return false;
- }
-
- if (attId === "TAG_NO" || attId === "TAG_DESC" || attId === "status") {
- return false;
- }
- if (templateType === 'SPREAD_LIST' || templateType === 'GRD_LIST') {
- // ๊ฐ ํ–‰์˜ TAG_NO๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํŽธ์ง‘ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ํŒ๋‹จ
- if (!rowData?.TAG_NO || !editableFieldsMap.has(rowData.TAG_NO)) {
+ const isFieldEditable = React.useCallback((attId: string, rowData?: GenericData) => {
+ const columnConfig = columnsJSON.find(col => col.key === attId);
+ if (columnConfig?.shi === "OUT" || columnConfig?.shi === null) {
return false;
}
-
- const rowEditableFields = editableFieldsMap.get(rowData.TAG_NO) || [];
- if (!rowEditableFields.includes(attId)) {
+
+ if (attId === "TAG_NO" || attId === "TAG_DESC" || attId === "status") {
return false;
}
-
- if (rowData && (rowData.shi === "OUT" || rowData.shi === null)) {
- return false;
+
+ if (templateType === 'SPREAD_LIST' || templateType === 'GRD_LIST') {
+ // ๊ฐ ํ–‰์˜ TAG_NO๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํŽธ์ง‘ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ํŒ๋‹จ
+ if (!rowData?.TAG_NO || !editableFieldsMap.has(rowData.TAG_NO)) {
+ return false;
+ }
+
+ const rowEditableFields = editableFieldsMap.get(rowData.TAG_NO) || [];
+ if (!rowEditableFields.includes(attId)) {
+ return false;
+ }
+
+ if (rowData && (rowData.shi === "OUT" || rowData.shi === null)) {
+ return false;
+ }
+ return true;
}
+
+ // SPREAD_ITEM์˜ ๊ฒฝ์šฐ ๊ธฐ์กด ๋กœ์ง ์œ ์ง€
+ if (templateType === 'SPREAD_ITEM') {
+ return editableFields.includes(attId);
+ }
+
return true;
- }
+ }, [templateType, columnsJSON, editableFieldsMap]); // editableFields ์˜์กด์„ฑ ์ œ๊ฑฐ
- // SPREAD_ITEM์˜ ๊ฒฝ์šฐ ๊ธฐ์กด ๋กœ์ง ์œ ์ง€
- if (templateType === 'SPREAD_ITEM') {
- return editableFields.includes(attId);
- }
+ const editableFieldsCount = React.useMemo(() => {
+ if (templateType === 'SPREAD_ITEM') {
+ // SPREAD_ITEM์˜ ๊ฒฝ์šฐ ๊ธฐ์กด ๋กœ์ง ์œ ์ง€
+ return cellMappings.filter(m => m.isEditable).length;
+ }
- return true;
-}, [templateType, columnsJSON, editableFieldsMap]); // editableFields ์˜์กด์„ฑ ์ œ๊ฑฐ
+ if (templateType === 'SPREAD_LIST' || templateType === 'GRD_LIST') {
+ // ๊ฐ ํ–‰๋ณ„๋กœ ํŽธ์ง‘ ๊ฐ€๋Šฅํ•œ ํ•„๋“œ ์ˆ˜๋ฅผ ๊ณ„์‚ฐ
+ let totalEditableCount = 0;
-const editableFieldsCount = React.useMemo(() => {
- if (templateType === 'SPREAD_ITEM') {
- // SPREAD_ITEM์˜ ๊ฒฝ์šฐ ๊ธฐ์กด ๋กœ์ง ์œ ์ง€
- return cellMappings.filter(m => m.isEditable).length;
- }
-
- if (templateType === 'SPREAD_LIST' || templateType === 'GRD_LIST') {
- // ๊ฐ ํ–‰๋ณ„๋กœ ํŽธ์ง‘ ๊ฐ€๋Šฅํ•œ ํ•„๋“œ ์ˆ˜๋ฅผ ๊ณ„์‚ฐ
- let totalEditableCount = 0;
-
- tableData.forEach((rowData, rowIndex) => {
- cellMappings.forEach(mapping => {
- if (mapping.dataRowIndex === rowIndex) {
- if (isFieldEditable(mapping.attId, rowData)) {
- totalEditableCount++;
+ tableData.forEach((rowData, rowIndex) => {
+ cellMappings.forEach(mapping => {
+ if (mapping.dataRowIndex === rowIndex) {
+ if (isFieldEditable(mapping.attId, rowData)) {
+ totalEditableCount++;
+ }
}
- }
+ });
});
- });
-
- return totalEditableCount;
- }
-
- return cellMappings.filter(m => m.isEditable).length;
-}, [cellMappings, templateType, tableData, isFieldEditable]);
+
+ return totalEditableCount;
+ }
+
+ return cellMappings.filter(m => m.isEditable).length;
+ }, [cellMappings, templateType, tableData, isFieldEditable]);
// ๐Ÿš€ ๋ฐฐ์น˜ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜๋“ค
const setBatchValues = React.useCallback((
- activeSheet: any,
- valuesToSet: Array<{row: number, col: number, value: any}>
+ activeSheet: any,
+ valuesToSet: Array<{ row: number, col: number, value: any }>
) => {
console.log(`๐Ÿš€ Setting ${valuesToSet.length} values in batch`);
-
- const columnGroups = new Map<number, Array<{row: number, value: any}>>();
-
- valuesToSet.forEach(({row, col, value}) => {
+
+ const columnGroups = new Map<number, Array<{ row: number, value: any }>>();
+
+ valuesToSet.forEach(({ row, col, value }) => {
if (!columnGroups.has(col)) {
columnGroups.set(col, []);
}
- columnGroups.get(col)!.push({row, value});
+ columnGroups.get(col)!.push({ row, value });
});
-
+
columnGroups.forEach((values, col) => {
values.sort((a, b) => a.row - b.row);
-
+
let start = 0;
while (start < values.length) {
let end = start;
while (end + 1 < values.length && values[end + 1].row === values[end].row + 1) {
end++;
}
-
+
const rangeValues = values.slice(start, end + 1).map(v => v.value);
const startRow = values[start].row;
-
+
try {
if (rangeValues.length === 1) {
activeSheet.setValue(startRow, col, rangeValues[0]);
@@ -356,7 +356,7 @@ const editableFieldsCount = React.useMemo(() => {
}
}
}
-
+
start = end + 1;
}
});
@@ -365,7 +365,7 @@ const editableFieldsCount = React.useMemo(() => {
const createCellStyle = React.useCallback((activeSheet: any, row: number, col: number, isEditable: boolean) => {
// ๊ธฐ์กด ์Šคํƒ€์ผ ๊ฐ€์ ธ์˜ค๊ธฐ (์—†์œผ๋ฉด ์ƒˆ๋กœ ์ƒ์„ฑ)
const existingStyle = activeSheet.getStyle(row, col) || new GC.Spread.Sheets.Style();
-
+
// backColor๋งŒ ์ˆ˜์ •
if (isEditable) {
existingStyle.backColor = "#bbf7d0";
@@ -374,25 +374,25 @@ const editableFieldsCount = React.useMemo(() => {
// ์ฝ๊ธฐ ์ „์šฉ์ผ ๋•Œ๋งŒ ํ…์ŠคํŠธ ์ƒ‰์ƒ ๋ณ€๊ฒฝ (์„ ํƒ์‚ฌํ•ญ)
existingStyle.foreColor = "#4b5563";
}
-
+
return existingStyle;
}, []);
const setBatchStyles = React.useCallback((
- activeSheet: any,
- stylesToSet: Array<{row: number, col: number, isEditable: boolean}>
+ activeSheet: any,
+ stylesToSet: Array<{ row: number, col: number, isEditable: boolean }>
) => {
console.log(`๐ŸŽจ Setting ${stylesToSet.length} styles in batch`);
-
+
// ๐Ÿ”ง ๊ฐœ๋ณ„ ์…€๋ณ„๋กœ ์Šคํƒ€์ผ๊ณผ ์ž ๊ธˆ ์ƒํƒœ ์„ค์ • (ํŽธ์ง‘ ๊ถŒํ•œ ๋ณด์žฅ)
- stylesToSet.forEach(({row, col, isEditable}) => {
+ stylesToSet.forEach(({ row, col, isEditable }) => {
try {
const cell = activeSheet.getCell(row, col);
const style = createCellStyle(activeSheet, row, col, isEditable);
-
+
activeSheet.setStyle(row, col, style);
cell.locked(!isEditable); // ํŽธ์ง‘ ๊ฐ€๋Šฅํ•˜๋ฉด ์ž ๊ธˆ ํ•ด์ œ
-
+
// ๐Ÿ†• ํŽธ์ง‘ ๊ฐ€๋Šฅํ•œ ์…€์— ๊ธฐ๋ณธ ํ…์ŠคํŠธ ์—๋””ํ„ฐ ์„ค์ •
if (isEditable) {
const textCellType = new GC.Spread.Sheets.CellTypes.Text();
@@ -511,7 +511,7 @@ const editableFieldsCount = React.useMemo(() => {
for (let i = 0; i < rowCount; i++) {
try {
const targetRow = cellPos.row + i;
-
+
// ๐Ÿ”ง ๊ฐ ์…€๋งˆ๋‹ค ์ƒˆ๋กœ์šด ComboBox ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
const comboBoxCellType = new GC.Spread.Sheets.CellTypes.ComboBox();
comboBoxCellType.items(safeOptions);
@@ -525,7 +525,7 @@ const editableFieldsCount = React.useMemo(() => {
// ComboBox์™€ Validator ์ ์šฉ
activeSheet.setCellType(targetRow, cellPos.col, comboBoxCellType);
activeSheet.setDataValidator(targetRow, cellPos.col, cellValidator);
-
+
// ๐Ÿš€ ์ค‘์š”: ์…€ ์ž ๊ธˆ ํ•ด์ œ ๋ฐ ํŽธ์ง‘ ๊ฐ€๋Šฅ ์„ค์ •
const cell = activeSheet.getCell(targetRow, cellPos.col);
cell.locked(false);
@@ -546,7 +546,7 @@ const editableFieldsCount = React.useMemo(() => {
const getSafeActiveSheet = React.useCallback((spread: any, functionName: string = 'unknown') => {
if (!spread) return null;
-
+
try {
let activeSheet = spread.getActiveSheet();
if (!activeSheet) {
@@ -568,7 +568,7 @@ const editableFieldsCount = React.useMemo(() => {
const ensureRowCapacity = React.useCallback((activeSheet: any, requiredRowCount: number) => {
try {
if (!activeSheet) return false;
-
+
const currentRowCount = activeSheet.getRowCount();
if (requiredRowCount > currentRowCount) {
const newRowCount = requiredRowCount + 10;
@@ -584,7 +584,7 @@ const editableFieldsCount = React.useMemo(() => {
const ensureColumnCapacity = React.useCallback((activeSheet: any, requiredColumnCount: number) => {
try {
if (!activeSheet) return false;
-
+
const currentColumnCount = activeSheet.getColumnCount();
if (requiredColumnCount > currentColumnCount) {
const newColumnCount = requiredColumnCount + 10;
@@ -606,206 +606,206 @@ const editableFieldsCount = React.useMemo(() => {
}, []);
// ๐Ÿš€ ์ตœ์ ํ™”๋œ GRD_LIST ์ƒ์„ฑ
- // ๐Ÿš€ ์ตœ์ ํ™”๋œ GRD_LIST ์ƒ์„ฑ (TAG_DESC ์ปฌ๋Ÿผ ํ‹€๊ณ ์ • ํฌํ•จ)
-const createGrdListTableOptimized = React.useCallback((activeSheet: any, template: TemplateItem) => {
- console.log('๐Ÿš€ Creating optimized GRD_LIST table with TAG_DESC freeze');
-
- const visibleColumns = columnsJSON
- .filter(col => col.hidden !== true)
- .sort((a, b) => (a.seq ?? 999999) - (b.seq ?? 999999));
-
- if (visibleColumns.length === 0) return [];
-
- const startCol = 1;
- const dataStartRow = 1;
- const mappings: CellMapping[] = [];
-
- ensureColumnCapacity(activeSheet, startCol + visibleColumns.length);
- ensureRowCapacity(activeSheet, dataStartRow + tableData.length);
-
- // ๐ŸงŠ TAG_DESC ์ปฌ๋Ÿผ ์œ„์น˜ ์ฐพ๊ธฐ (ํ‹€๊ณ ์ •์šฉ)
- const tagDescColumnIndex = visibleColumns.findIndex(col => col.key === 'TAG_DESC');
- let freezeColumnCount = 0;
-
- if (tagDescColumnIndex !== -1) {
- // TAG_DESC ์ปฌ๋Ÿผ๊นŒ์ง€ ํฌํ•จํ•ด์„œ ๊ณ ์ • (startCol + tagDescColumnIndex + 1)
- freezeColumnCount = startCol + tagDescColumnIndex + 1;
- console.log(`๐ŸงŠ TAG_DESC found at column index ${tagDescColumnIndex}, freezing ${freezeColumnCount} columns`);
- } else {
- // TAG_DESC๊ฐ€ ์—†์œผ๋ฉด TAG_NO๊นŒ์ง€๋งŒ ๊ณ ์ • (์ผ๋ฐ˜์ ์œผ๋กœ ์ฒซ ๋ฒˆ์งธ ์ปฌ๋Ÿผ)
- const tagNoColumnIndex = visibleColumns.findIndex(col => col.key === 'TAG_NO');
- if (tagNoColumnIndex !== -1) {
- freezeColumnCount = startCol + tagNoColumnIndex + 1;
- console.log(`๐ŸงŠ TAG_NO found at column index ${tagNoColumnIndex}, freezing ${freezeColumnCount} columns`);
+ // ๐Ÿš€ ์ตœ์ ํ™”๋œ GRD_LIST ์ƒ์„ฑ (TAG_DESC ์ปฌ๋Ÿผ ํ‹€๊ณ ์ • ํฌํ•จ)
+ const createGrdListTableOptimized = React.useCallback((activeSheet: any, template: TemplateItem) => {
+ console.log('๐Ÿš€ Creating optimized GRD_LIST table with TAG_DESC freeze');
+
+ const visibleColumns = columnsJSON
+ .filter(col => col.hidden !== true)
+ .sort((a, b) => (a.seq ?? 999999) - (b.seq ?? 999999));
+
+ if (visibleColumns.length === 0) return [];
+
+ const startCol = 1;
+ const dataStartRow = 1;
+ const mappings: CellMapping[] = [];
+
+ ensureColumnCapacity(activeSheet, startCol + visibleColumns.length);
+ ensureRowCapacity(activeSheet, dataStartRow + tableData.length);
+
+ // ๐ŸงŠ TAG_DESC ์ปฌ๋Ÿผ ์œ„์น˜ ์ฐพ๊ธฐ (ํ‹€๊ณ ์ •์šฉ)
+ const tagDescColumnIndex = visibleColumns.findIndex(col => col.key === 'TAG_DESC');
+ let freezeColumnCount = 0;
+
+ if (tagDescColumnIndex !== -1) {
+ // TAG_DESC ์ปฌ๋Ÿผ๊นŒ์ง€ ํฌํ•จํ•ด์„œ ๊ณ ์ • (startCol + tagDescColumnIndex + 1)
+ freezeColumnCount = startCol + tagDescColumnIndex + 1;
+ console.log(`๐ŸงŠ TAG_DESC found at column index ${tagDescColumnIndex}, freezing ${freezeColumnCount} columns`);
+ } else {
+ // TAG_DESC๊ฐ€ ์—†์œผ๋ฉด TAG_NO๊นŒ์ง€๋งŒ ๊ณ ์ • (์ผ๋ฐ˜์ ์œผ๋กœ ์ฒซ ๋ฒˆ์งธ ์ปฌ๋Ÿผ)
+ const tagNoColumnIndex = visibleColumns.findIndex(col => col.key === 'TAG_NO');
+ if (tagNoColumnIndex !== -1) {
+ freezeColumnCount = startCol + tagNoColumnIndex + 1;
+ console.log(`๐ŸงŠ TAG_NO found at column index ${tagNoColumnIndex}, freezing ${freezeColumnCount} columns`);
+ }
}
- }
- // ํ—ค๋” ์ƒ์„ฑ
- const headerStyle = new GC.Spread.Sheets.Style();
- headerStyle.backColor = "#3b82f6";
- headerStyle.foreColor = "#ffffff";
- headerStyle.font = "bold 12px Arial";
- headerStyle.hAlign = GC.Spread.Sheets.HorizontalAlign.center;
-
- visibleColumns.forEach((column, colIndex) => {
- const targetCol = startCol + colIndex;
- const cell = activeSheet.getCell(0, targetCol);
- cell.value(column.label);
- cell.locked(true);
- activeSheet.setStyle(0, targetCol, headerStyle);
- });
+ // ํ—ค๋” ์ƒ์„ฑ
+ const headerStyle = new GC.Spread.Sheets.Style();
+ headerStyle.backColor = "#3b82f6";
+ headerStyle.foreColor = "#ffffff";
+ headerStyle.font = "bold 12px Arial";
+ headerStyle.hAlign = GC.Spread.Sheets.HorizontalAlign.center;
- // ๐Ÿš€ ๋ฐ์ดํ„ฐ ๋ฐฐ์น˜ ์ฒ˜๋ฆฌ ์ค€๋น„
- const allValues: Array<{row: number, col: number, value: any}> = [];
- const allStyles: Array<{row: number, col: number, isEditable: boolean}> = [];
-
- // ๐Ÿ”ง ํŽธ์ง‘ ๊ฐ€๋Šฅํ•œ ์…€ ์ •๋ณด ์ˆ˜์ง‘ (๋“œ๋กญ๋‹ค์šด์šฉ)
- const dropdownConfigs: Array<{
- startRow: number;
- col: number;
- rowCount: number;
- options: string[];
- editableRows: number[]; // ํŽธ์ง‘ ๊ฐ€๋Šฅํ•œ ํ–‰๋งŒ ์ถ”์ 
- }> = [];
-
- visibleColumns.forEach((column, colIndex) => {
- const targetCol = startCol + colIndex;
-
- // ๋“œ๋กญ๋‹ค์šด ์„ค์ •์„ ์œ„ํ•œ ํŽธ์ง‘ ๊ฐ€๋Šฅํ•œ ํ–‰ ์ฐพ๊ธฐ
- if (column.type === "LIST" && column.options) {
- const editableRows: number[] = [];
- tableData.forEach((rowData, rowIndex) => {
- if (isFieldEditable(column.key, rowData)) { // rowData ์ „๋‹ฌ
- editableRows.push(dataStartRow + rowIndex);
+ visibleColumns.forEach((column, colIndex) => {
+ const targetCol = startCol + colIndex;
+ const cell = activeSheet.getCell(0, targetCol);
+ cell.value(column.label);
+ cell.locked(true);
+ activeSheet.setStyle(0, targetCol, headerStyle);
+ });
+
+ // ๐Ÿš€ ๋ฐ์ดํ„ฐ ๋ฐฐ์น˜ ์ฒ˜๋ฆฌ ์ค€๋น„
+ const allValues: Array<{ row: number, col: number, value: any }> = [];
+ const allStyles: Array<{ row: number, col: number, isEditable: boolean }> = [];
+
+ // ๐Ÿ”ง ํŽธ์ง‘ ๊ฐ€๋Šฅํ•œ ์…€ ์ •๋ณด ์ˆ˜์ง‘ (๋“œ๋กญ๋‹ค์šด์šฉ)
+ const dropdownConfigs: Array<{
+ startRow: number;
+ col: number;
+ rowCount: number;
+ options: string[];
+ editableRows: number[]; // ํŽธ์ง‘ ๊ฐ€๋Šฅํ•œ ํ–‰๋งŒ ์ถ”์ 
+ }> = [];
+
+ visibleColumns.forEach((column, colIndex) => {
+ const targetCol = startCol + colIndex;
+
+ // ๋“œ๋กญ๋‹ค์šด ์„ค์ •์„ ์œ„ํ•œ ํŽธ์ง‘ ๊ฐ€๋Šฅํ•œ ํ–‰ ์ฐพ๊ธฐ
+ if (column.type === "LIST" && column.options) {
+ const editableRows: number[] = [];
+ tableData.forEach((rowData, rowIndex) => {
+ if (isFieldEditable(column.key, rowData)) { // rowData ์ „๋‹ฌ
+ editableRows.push(dataStartRow + rowIndex);
+ }
+ });
+
+ if (editableRows.length > 0) {
+ dropdownConfigs.push({
+ startRow: dataStartRow,
+ col: targetCol,
+ rowCount: tableData.length,
+ options: column.options,
+ editableRows: editableRows
+ });
}
- });
-
- if (editableRows.length > 0) {
- dropdownConfigs.push({
- startRow: dataStartRow,
+ }
+
+ tableData.forEach((rowData, rowIndex) => {
+ const targetRow = dataStartRow + rowIndex;
+ const cellEditable = isFieldEditable(column.key, rowData); // rowData ์ „๋‹ฌ
+ const value = rowData[column.key];
+
+ mappings.push({
+ attId: column.key,
+ cellAddress: getCellAddress(targetRow, targetCol),
+ isEditable: cellEditable,
+ dataRowIndex: rowIndex
+ });
+
+ allValues.push({
+ row: targetRow,
col: targetCol,
- rowCount: tableData.length,
- options: column.options,
- editableRows: editableRows
+ value: value ?? null
+ });
+
+ allStyles.push({
+ row: targetRow,
+ col: targetCol,
+ isEditable: cellEditable
});
- }
- }
-
- tableData.forEach((rowData, rowIndex) => {
- const targetRow = dataStartRow + rowIndex;
- const cellEditable = isFieldEditable(column.key, rowData); // rowData ์ „๋‹ฌ
- const value = rowData[column.key];
-
- mappings.push({
- attId: column.key,
- cellAddress: getCellAddress(targetRow, targetCol),
- isEditable: cellEditable,
- dataRowIndex: rowIndex
- });
-
- allValues.push({
- row: targetRow,
- col: targetCol,
- value: value ?? null
- });
-
- allStyles.push({
- row: targetRow,
- col: targetCol,
- isEditable: cellEditable
});
});
- });
- // ๐Ÿš€ ๋ฐฐ์น˜๋กœ ๊ฐ’๊ณผ ์Šคํƒ€์ผ ์„ค์ •
- setBatchValues(activeSheet, allValues);
- setBatchStyles(activeSheet, allStyles);
+ // ๐Ÿš€ ๋ฐฐ์น˜๋กœ ๊ฐ’๊ณผ ์Šคํƒ€์ผ ์„ค์ •
+ setBatchValues(activeSheet, allValues);
+ setBatchStyles(activeSheet, allStyles);
- // ๐ŸŽฏ ๊ฐœ์„ ๋œ ๋“œ๋กญ๋‹ค์šด ์„ค์ • (ํŽธ์ง‘ ๊ฐ€๋Šฅํ•œ ์…€์—๋งŒ)
- dropdownConfigs.forEach(({ col, options, editableRows }) => {
- try {
- console.log(`๐ŸŽฏ Setting dropdown for column ${col}, editable rows: ${editableRows.length}`);
-
- const safeOptions = options
- .filter(opt => opt !== null && opt !== undefined && opt !== '')
- .map(opt => String(opt).trim())
- .filter(opt => opt.length > 0)
- .slice(0, 20);
+ // ๐ŸŽฏ ๊ฐœ์„ ๋œ ๋“œ๋กญ๋‹ค์šด ์„ค์ • (ํŽธ์ง‘ ๊ฐ€๋Šฅํ•œ ์…€์—๋งŒ)
+ dropdownConfigs.forEach(({ col, options, editableRows }) => {
+ try {
+ console.log(`๐ŸŽฏ Setting dropdown for column ${col}, editable rows: ${editableRows.length}`);
- if (safeOptions.length === 0) return;
+ const safeOptions = options
+ .filter(opt => opt !== null && opt !== undefined && opt !== '')
+ .map(opt => String(opt).trim())
+ .filter(opt => opt.length > 0)
+ .slice(0, 20);
- // ํŽธ์ง‘ ๊ฐ€๋Šฅํ•œ ํ–‰์—๋งŒ ๋“œ๋กญ๋‹ค์šด ์ ์šฉ
- editableRows.forEach(targetRow => {
- try {
- const comboBoxCellType = new GC.Spread.Sheets.CellTypes.ComboBox();
- comboBoxCellType.items(safeOptions);
- comboBoxCellType.editorValueType(GC.Spread.Sheets.CellTypes.EditorValueType.text);
+ if (safeOptions.length === 0) return;
- const cellValidator = GC.Spread.Sheets.DataValidation.createListValidator(safeOptions.join(','));
- cellValidator.showInputMessage(false);
- cellValidator.showErrorMessage(false);
+ // ํŽธ์ง‘ ๊ฐ€๋Šฅํ•œ ํ–‰์—๋งŒ ๋“œ๋กญ๋‹ค์šด ์ ์šฉ
+ editableRows.forEach(targetRow => {
+ try {
+ const comboBoxCellType = new GC.Spread.Sheets.CellTypes.ComboBox();
+ comboBoxCellType.items(safeOptions);
+ comboBoxCellType.editorValueType(GC.Spread.Sheets.CellTypes.EditorValueType.text);
- activeSheet.setCellType(targetRow, col, comboBoxCellType);
- activeSheet.setDataValidator(targetRow, col, cellValidator);
-
- // ๐Ÿš€ ํŽธ์ง‘ ๊ถŒํ•œ ๋ช…์‹œ์  ์„ค์ •
- const cell = activeSheet.getCell(targetRow, col);
- cell.locked(false);
+ const cellValidator = GC.Spread.Sheets.DataValidation.createListValidator(safeOptions.join(','));
+ cellValidator.showInputMessage(false);
+ cellValidator.showErrorMessage(false);
- console.log(`โœ… Dropdown applied to editable cell [${targetRow}, ${col}]`);
- } catch (cellError) {
- console.warn(`โš ๏ธ Failed to apply dropdown to [${targetRow}, ${col}]:`, cellError);
- }
- });
- } catch (error) {
- console.error(`โŒ Dropdown config failed for column ${col}:`, error);
- }
- });
+ activeSheet.setCellType(targetRow, col, comboBoxCellType);
+ activeSheet.setDataValidator(targetRow, col, cellValidator);
- // ๐ŸงŠ ํ‹€๊ณ ์ • ์„ค์ •
- if (freezeColumnCount > 0) {
- try {
- activeSheet.frozenColumnCount(freezeColumnCount);
- activeSheet.frozenRowCount(1); // ํ—ค๋” ํ–‰๋„ ๊ณ ์ •
-
- console.log(`๐ŸงŠ Freeze applied: ${freezeColumnCount} columns, 1 row (header)`);
-
- // ๐ŸŽจ ๊ณ ์ •๋œ ์ปฌ๋Ÿผ์— ํŠน๋ณ„ํ•œ ์Šคํƒ€์ผ ์ถ”๊ฐ€ (์„ ํƒ์‚ฌํ•ญ)
- for (let col = 0; col < freezeColumnCount; col++) {
- for (let row = 0; row <= tableData.length; row++) {
- try {
- const currentStyle = activeSheet.getStyle(row, col) || new GC.Spread.Sheets.Style();
-
- if (row === 0) {
- // ํ—ค๋”๋Š” ๊ธฐ์กด ์Šคํƒ€์ผ ์œ ์ง€
- continue;
- } else {
- // ๋ฐ์ดํ„ฐ ์…€์— ๊ณ ์ • ๊ตฌ๋ถ„์„  ์ถ”๊ฐ€
- if (col === freezeColumnCount - 1) {
- currentStyle.borderRight = new GC.Spread.Sheets.LineBorder("#2563eb", GC.Spread.Sheets.LineStyle.medium);
- activeSheet.setStyle(row, col, currentStyle);
+ // ๐Ÿš€ ํŽธ์ง‘ ๊ถŒํ•œ ๋ช…์‹œ์  ์„ค์ •
+ const cell = activeSheet.getCell(targetRow, col);
+ cell.locked(false);
+
+ console.log(`โœ… Dropdown applied to editable cell [${targetRow}, ${col}]`);
+ } catch (cellError) {
+ console.warn(`โš ๏ธ Failed to apply dropdown to [${targetRow}, ${col}]:`, cellError);
+ }
+ });
+ } catch (error) {
+ console.error(`โŒ Dropdown config failed for column ${col}:`, error);
+ }
+ });
+
+ // ๐ŸงŠ ํ‹€๊ณ ์ • ์„ค์ •
+ if (freezeColumnCount > 0) {
+ try {
+ activeSheet.frozenColumnCount(freezeColumnCount);
+ activeSheet.frozenRowCount(1); // ํ—ค๋” ํ–‰๋„ ๊ณ ์ •
+
+ console.log(`๐ŸงŠ Freeze applied: ${freezeColumnCount} columns, 1 row (header)`);
+
+ // ๐ŸŽจ ๊ณ ์ •๋œ ์ปฌ๋Ÿผ์— ํŠน๋ณ„ํ•œ ์Šคํƒ€์ผ ์ถ”๊ฐ€ (์„ ํƒ์‚ฌํ•ญ)
+ for (let col = 0; col < freezeColumnCount; col++) {
+ for (let row = 0; row <= tableData.length; row++) {
+ try {
+ const currentStyle = activeSheet.getStyle(row, col) || new GC.Spread.Sheets.Style();
+
+ if (row === 0) {
+ // ํ—ค๋”๋Š” ๊ธฐ์กด ์Šคํƒ€์ผ ์œ ์ง€
+ continue;
+ } else {
+ // ๋ฐ์ดํ„ฐ ์…€์— ๊ณ ์ • ๊ตฌ๋ถ„์„  ์ถ”๊ฐ€
+ if (col === freezeColumnCount - 1) {
+ currentStyle.borderRight = new GC.Spread.Sheets.LineBorder("#2563eb", GC.Spread.Sheets.LineStyle.medium);
+ activeSheet.setStyle(row, col, currentStyle);
+ }
}
+ } catch (styleError) {
+ console.warn(`โš ๏ธ Failed to apply freeze border style to [${row}, ${col}]:`, styleError);
}
- } catch (styleError) {
- console.warn(`โš ๏ธ Failed to apply freeze border style to [${row}, ${col}]:`, styleError);
}
}
+ } catch (freezeError) {
+ console.error('โŒ Failed to apply freeze:', freezeError);
}
- } catch (freezeError) {
- console.error('โŒ Failed to apply freeze:', freezeError);
}
- }
- setOptimalColumnWidths(activeSheet, visibleColumns, startCol, tableData);
-
- console.log(`โœ… Optimized GRD_LIST created with freeze:`);
- console.log(` - Total mappings: ${mappings.length}`);
- console.log(` - Editable cells: ${mappings.filter(m => m.isEditable).length}`);
- console.log(` - Dropdown configs: ${dropdownConfigs.length}`);
- console.log(` - Frozen columns: ${freezeColumnCount}`);
-
- return mappings;
-}, [tableData, columnsJSON, isFieldEditable, setBatchValues, setBatchStyles, ensureColumnCapacity, ensureRowCapacity, getCellAddress, setOptimalColumnWidths]);
+ setOptimalColumnWidths(activeSheet, visibleColumns, startCol, tableData);
+
+ console.log(`โœ… Optimized GRD_LIST created with freeze:`);
+ console.log(` - Total mappings: ${mappings.length}`);
+ console.log(` - Editable cells: ${mappings.filter(m => m.isEditable).length}`);
+ console.log(` - Dropdown configs: ${dropdownConfigs.length}`);
+ console.log(` - Frozen columns: ${freezeColumnCount}`);
+
+ return mappings;
+ }, [tableData, columnsJSON, isFieldEditable, setBatchValues, setBatchStyles, ensureColumnCapacity, ensureRowCapacity, getCellAddress, setOptimalColumnWidths]);
const setupSheetProtectionAndEvents = React.useCallback((activeSheet: any, mappings: CellMapping[]) => {
console.log(`๐Ÿ›ก๏ธ Setting up protection and events for ${mappings.length} mappings`);
@@ -817,22 +817,22 @@ const createGrdListTableOptimized = React.useCallback((activeSheet: any, templat
mappings.forEach((mapping) => {
const cellPos = parseCellAddress(mapping.cellAddress);
if (!cellPos) return;
-
+
try {
const cell = activeSheet.getCell(cellPos.row, cellPos.col);
const columnConfig = columnsJSON.find(col => col.key === mapping.attId);
-
+
if (mapping.isEditable) {
// ๐Ÿš€ ํŽธ์ง‘ ๊ฐ€๋Šฅํ•œ ์…€ ์„ค์ • ๊ฐ•ํ™”
cell.locked(false);
-
+
if (columnConfig?.type === "LIST" && columnConfig.options) {
// LIST ํƒ€์ž…: ์ƒˆ ComboBox ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
const comboBox = new GC.Spread.Sheets.CellTypes.ComboBox();
comboBox.items(columnConfig.options);
comboBox.editorValueType(GC.Spread.Sheets.CellTypes.EditorValueType.text);
activeSheet.setCellType(cellPos.row, cellPos.col, comboBox);
-
+
// DataValidation๋„ ์ถ”๊ฐ€
const validator = GC.Spread.Sheets.DataValidation.createListValidator(columnConfig.options.join(','));
activeSheet.setDataValidator(cellPos.row, cellPos.col, validator);
@@ -840,7 +840,7 @@ const createGrdListTableOptimized = React.useCallback((activeSheet: any, templat
// NUMBER ํƒ€์ž…: ์ˆซ์ž ์ž…๋ ฅ ํ—ˆ์šฉ
const textCellType = new GC.Spread.Sheets.CellTypes.Text();
activeSheet.setCellType(cellPos.row, cellPos.col, textCellType);
-
+
// ์ˆซ์ž validation ์ถ”๊ฐ€ (์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ์—†์ด)
const numberValidator = GC.Spread.Sheets.DataValidation.createNumberValidator(
GC.Spread.Sheets.ConditionalFormatting.ComparisonOperators.between,
@@ -854,11 +854,11 @@ const createGrdListTableOptimized = React.useCallback((activeSheet: any, templat
const textCellType = new GC.Spread.Sheets.CellTypes.Text();
activeSheet.setCellType(cellPos.row, cellPos.col, textCellType);
}
-
+
// ํŽธ์ง‘ ๊ฐ€๋Šฅ ์Šคํƒ€์ผ ์žฌ์ ์šฉ
const editableStyle = createCellStyle(activeSheet, cellPos.row, cellPos.col, true);
activeSheet.setStyle(cellPos.row, cellPos.col, editableStyle);
-
+
console.log(`๐Ÿ”“ Cell [${cellPos.row}, ${cellPos.col}] ${mapping.attId} set as EDITABLE`);
} else {
// ์ฝ๊ธฐ ์ „์šฉ ์…€
@@ -930,7 +930,7 @@ const createGrdListTableOptimized = React.useCallback((activeSheet: any, templat
const dataRowIndex = exactMapping.dataRowIndex;
if (dataRowIndex >= 0 && dataRowIndex < tableData.length) {
const rowData = tableData[dataRowIndex];
- if (rowData?.shi === "OUT" || rowData?.shi === null ) {
+ if (rowData?.shi === "OUT" || rowData?.shi === null) {
console.log(`๐Ÿšซ Row ${dataRowIndex} is in SHI mode`);
toast.warning(`Row ${dataRowIndex + 1}: ${exactMapping.attId} field is read-only (SHI mode)`);
info.cancel = true;
@@ -998,7 +998,7 @@ const createGrdListTableOptimized = React.useCallback((activeSheet: any, templat
console.log('๐Ÿš€ Starting optimized spread initialization...');
setIsInitializing(true);
updateProgress('Initializing...', 0, 100);
-
+
setCurrentSpread(spread);
setHasChanges(false);
setValidationErrors([]);
@@ -1007,7 +1007,7 @@ const createGrdListTableOptimized = React.useCallback((activeSheet: any, templat
spread.suspendPaint();
spread.suspendEvent();
spread.suspendCalcService();
-
+
updateProgress('Setting up workspace...', 10, 100);
try {
@@ -1021,19 +1021,19 @@ const createGrdListTableOptimized = React.useCallback((activeSheet: any, templat
if (templateType === 'GRD_LIST') {
updateProgress('Creating dynamic table...', 20, 100);
-
+
spread.clearSheets();
spread.addSheet(0);
const sheet = spread.getSheet(0);
sheet.name('Data');
spread.setActiveSheet('Data');
-
+
updateProgress('Processing table data...', 50, 100);
mappings = createGrdListTableOptimized(sheet, workingTemplate);
-
+
} else {
updateProgress('Loading template structure...', 20, 100);
-
+
let contentJson = workingTemplate.SPR_LST_SETUP?.CONTENT || workingTemplate.SPR_ITM_LST_SETUP?.CONTENT;
let dataSheets = workingTemplate.SPR_LST_SETUP?.DATA_SHEETS || workingTemplate.SPR_ITM_LST_SETUP?.DATA_SHEETS;
@@ -1042,10 +1042,10 @@ const createGrdListTableOptimized = React.useCallback((activeSheet: any, templat
}
const jsonData = typeof contentJson === 'string' ? JSON.parse(contentJson) : contentJson;
-
+
updateProgress('Loading template layout...', 40, 100);
spread.fromJSON(jsonData);
-
+
activeSheet = getSafeActiveSheet(spread, 'after-fromJSON');
if (!activeSheet) {
throw new Error('ActiveSheet became null after loading template');
@@ -1058,15 +1058,24 @@ const createGrdListTableOptimized = React.useCallback((activeSheet: any, templat
const activeSheetName = workingTemplate.SPR_LST_SETUP?.ACT_SHEET;
- const matchingDataSheets = dataSheets.filter(ds =>
- ds.SHEET_NAME === activeSheetName
- );
- if (activeSheetName && spread.getSheetFromName(activeSheetName)) {
- spread.setActiveSheet(activeSheetName);
- }
+ // ๐Ÿ”ง ๊ฐ DATA_SHEET๋ณ„๋กœ ์ฒ˜๋ฆฌ
+ dataSheets.forEach(dataSheet => {
+ const sheetName = dataSheet.SHEET_NAME;
+
+ // ํ•ด๋‹น ์‹œํŠธ๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธ
+ const targetSheet = spread.getSheetFromName(sheetName);
+ if (!targetSheet) {
+ console.warn(`โš ๏ธ Sheet '${sheetName}' not found in template`);
+ return;
+ }
+
+ console.log(`๐Ÿ“‹ Processing sheet: ${sheetName}`);
+
+ // ํ•ด๋‹น ์‹œํŠธ๋กœ ์ „ํ™˜
+ spread.setActiveSheet(sheetName);
+ const currentSheet = spread.getActiveSheet();
- matchingDataSheets.forEach(dataSheet => {
if (dataSheet.MAP_CELL_ATT && dataSheet.MAP_CELL_ATT.length > 0) {
dataSheet.MAP_CELL_ATT.forEach((mapping: any) => {
const { ATT_ID, IN } = mapping;
@@ -1076,11 +1085,11 @@ const createGrdListTableOptimized = React.useCallback((activeSheet: any, templat
if (!cellPos) return;
const requiredRows = cellPos.row + tableData.length;
- if (!ensureRowCapacity(activeSheet, requiredRows)) return;
+ if (!ensureRowCapacity(currentSheet, requiredRows)) return;
// ๐Ÿš€ ๋ฐฐ์น˜ ๋ฐ์ดํ„ฐ ์ค€๋น„
- const valuesToSet: Array<{row: number, col: number, value: any}> = [];
- const stylesToSet: Array<{row: number, col: number, isEditable: boolean}> = [];
+ const valuesToSet: Array<{ row: number, col: number, value: any }> = [];
+ const stylesToSet: Array<{ row: number, col: number, isEditable: boolean }> = [];
tableData.forEach((rowData, index) => {
const targetRow = cellPos.row + index;
@@ -1108,67 +1117,95 @@ const createGrdListTableOptimized = React.useCallback((activeSheet: any, templat
});
// ๐Ÿš€ ๋ฐฐ์น˜ ์ฒ˜๋ฆฌ
- setBatchValues(activeSheet, valuesToSet);
- setBatchStyles(activeSheet, stylesToSet);
+ setBatchValues(currentSheet, valuesToSet);
+ setBatchStyles(currentSheet, stylesToSet);
// ๋“œ๋กญ๋‹ค์šด ์„ค์ •
const columnConfig = columnsJSON.find(col => col.key === ATT_ID);
if (columnConfig?.type === "LIST" && columnConfig.options) {
const hasEditableRows = tableData.some((rowData) => isFieldEditable(ATT_ID, rowData));
if (hasEditableRows) {
- setupOptimizedListValidation(activeSheet, cellPos, columnConfig.options, tableData.length);
+ setupOptimizedListValidation(currentSheet, cellPos, columnConfig.options, tableData.length);
}
}
});
}
});
-
+
+ // ๐Ÿ”ง ๋งˆ์ง€๋ง‰์— activeSheetName์œผ๋กœ ๋‹ค์‹œ ์ „ํ™˜
+ if (activeSheetName && spread.getSheetFromName(activeSheetName)) {
+ spread.setActiveSheet(activeSheetName);
+ activeSheet = spread.getActiveSheet();
+ }
+
} else if (templateType === 'SPREAD_ITEM' && selectedRow) {
updateProgress('Setting up form fields...', 60, 100);
- const activeSheetName = workingTemplate.SPR_ITM_LST_SETUP?.ACT_SHEET;
+ const activeSheetName = workingTemplate.SPR_ITM_LST_SETUP?.ACT_SHEET;
- const matchingDataSheets = dataSheets.filter(ds =>
- ds.SHEET_NAME === activeSheetName
- );
-
- if (activeSheetName && spread.getSheetFromName(activeSheetName)) {
- spread.setActiveSheet(activeSheetName);
+ if (activeSheetName && spread.getSheetFromName(activeSheetName)) {
+ spread.setActiveSheet(activeSheetName);
+ }
+
+ dataSheets.forEach(dataSheet => {
+
+ const sheetName = dataSheet.SHEET_NAME;
+ // ํ•ด๋‹น ์‹œํŠธ๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธ
+ const targetSheet = spread.getSheetFromName(sheetName);
+ if (!targetSheet) {
+ console.warn(`โš ๏ธ Sheet '${sheetName}' not found in template`);
+ return;
}
- matchingDataSheets.forEach(dataSheet => {
+ console.log(`๐Ÿ“‹ Processing sheet: ${sheetName}`);
+
+ // ํ•ด๋‹น ์‹œํŠธ๋กœ ์ „ํ™˜
+ spread.setActiveSheet(sheetName);
+ const currentSheet = spread.getActiveSheet();
+
+
dataSheet.MAP_CELL_ATT?.forEach((mapping: any) => {
const { ATT_ID, IN } = mapping;
const cellPos = parseCellAddress(IN);
+
+
if (cellPos) {
const isEditable = isFieldEditable(ATT_ID);
const value = selectedRow[ATT_ID];
-
+
mappings.push({
attId: ATT_ID,
cellAddress: IN,
isEditable: isEditable,
dataRowIndex: 0
});
-
- const cell = activeSheet.getCell(cellPos.row, cellPos.col);
+
+ const cell = currentSheet.getCell(cellPos.row, cellPos.col);
cell.value(value ?? null);
-
- const style = createCellStyle(activeSheet, cellPos.row, cellPos.col, isEditable);
- activeSheet.setStyle(cellPos.row, cellPos.col, style);
-
+
+ const style = createCellStyle(currentSheet, cellPos.row, cellPos.col, isEditable);
+ currentSheet.setStyle(cellPos.row, cellPos.col, style);
+
const columnConfig = columnsJSON.find(col => col.key === ATT_ID);
if (columnConfig?.type === "LIST" && columnConfig.options && isEditable) {
- setupOptimizedListValidation(activeSheet, cellPos, columnConfig.options, 1);
+ setupOptimizedListValidation(currentSheet, cellPos, columnConfig.options, 1);
}
}
});
+
+ // ๐Ÿ”ง ๋งˆ์ง€๋ง‰์— activeSheetName์œผ๋กœ ๋‹ค์‹œ ์ „ํ™˜
+ if (activeSheetName && spread.getSheetFromName(activeSheetName)) {
+ spread.setActiveSheet(activeSheetName);
+ activeSheet = spread.getActiveSheet();
+ }
+
+
});
}
}
updateProgress('Configuring interactions...', 90, 100);
setCellMappings(mappings);
-
+
const finalActiveSheet = getSafeActiveSheet(spread, 'setupEvents');
if (finalActiveSheet) {
setupSheetProtectionAndEvents(finalActiveSheet, mappings);
@@ -1201,20 +1238,20 @@ const createGrdListTableOptimized = React.useCallback((activeSheet: any, templat
toast.info("No changes to save");
return;
}
-
+
const errors = validateAllData();
if (errors.length > 0) {
toast.error(`Cannot save: ${errors.length} validation errors found. Please fix them first.`);
return;
}
-
+
try {
setIsPending(true);
const activeSheet = currentSpread.getActiveSheet();
-
+
if (templateType === 'SPREAD_ITEM' && selectedRow) {
const dataToSave = { ...selectedRow };
-
+
cellMappings.forEach(mapping => {
if (mapping.isEditable) {
const cellPos = parseCellAddress(mapping.cellAddress);
@@ -1224,59 +1261,59 @@ const createGrdListTableOptimized = React.useCallback((activeSheet: any, templat
}
}
});
-
+
dataToSave.TAG_NO = selectedRow.TAG_NO;
-
+
const { success, message } = await updateFormDataInDB(
formCode,
contractItemId,
dataToSave
);
-
+
if (!success) {
toast.error(message);
return;
}
-
+
toast.success("Changes saved successfully!");
onUpdateSuccess?.(dataToSave);
-
+
} else if ((templateType === 'SPREAD_LIST' || templateType === 'GRD_LIST') && tableData.length > 0) {
console.log('๐Ÿ” Starting batch save process...');
-
+
const updatedRows: GenericData[] = [];
let saveCount = 0;
let checkedCount = 0;
-
+
for (let i = 0; i < tableData.length; i++) {
const originalRow = tableData[i];
const dataToSave = { ...originalRow };
let hasRowChanges = false;
-
+
console.log(`๐Ÿ” Processing row ${i} (TAG_NO: ${originalRow.TAG_NO})`);
-
+
cellMappings.forEach(mapping => {
if (mapping.dataRowIndex === i && mapping.isEditable) {
checkedCount++;
-
+
// ๐Ÿ”ง isFieldEditable๊ณผ ๋™์ผํ•œ ๋กœ์ง ์‚ฌ์šฉ
const rowData = tableData[i];
const fieldEditable = isFieldEditable(mapping.attId, rowData);
-
+
console.log(` ๐Ÿ“ Field ${mapping.attId}: fieldEditable=${fieldEditable}, mapping.isEditable=${mapping.isEditable}`);
-
+
if (fieldEditable) {
const cellPos = parseCellAddress(mapping.cellAddress);
if (cellPos) {
const cellValue = activeSheet.getValue(cellPos.row, cellPos.col);
const originalValue = originalRow[mapping.attId];
-
+
// ๐Ÿ”ง ๊ฐœ์„ ๋œ ๊ฐ’ ๋น„๊ต (ํƒ€์ž… ๋ณ€ํ™˜ ๋ฐ null/undefined ์ฒ˜๋ฆฌ)
const normalizedCellValue = cellValue === null || cellValue === undefined ? "" : String(cellValue).trim();
const normalizedOriginalValue = originalValue === null || originalValue === undefined ? "" : String(originalValue).trim();
-
+
console.log(` ๐Ÿ” ${mapping.attId}: "${normalizedOriginalValue}" -> "${normalizedCellValue}"`);
-
+
if (normalizedCellValue !== normalizedOriginalValue) {
dataToSave[mapping.attId] = cellValue;
hasRowChanges = true;
@@ -1286,18 +1323,18 @@ const createGrdListTableOptimized = React.useCallback((activeSheet: any, templat
}
}
});
-
+
if (hasRowChanges) {
console.log(`๐Ÿ’พ Saving row ${i} with changes`);
dataToSave.TAG_NO = originalRow.TAG_NO;
-
+
try {
const { success, message } = await updateFormDataInDB(
formCode,
contractItemId,
dataToSave
);
-
+
if (success) {
updatedRows.push(dataToSave);
saveCount++;
@@ -1317,9 +1354,9 @@ const createGrdListTableOptimized = React.useCallback((activeSheet: any, templat
console.log(`โ„น๏ธ No changes in row ${i}`);
}
}
-
+
console.log(`๐Ÿ“Š Save summary: ${saveCount} saved, ${checkedCount} fields checked`);
-
+
if (saveCount > 0) {
toast.success(`${saveCount} rows saved successfully!`);
onUpdateSuccess?.(updatedRows);
@@ -1328,10 +1365,10 @@ const createGrdListTableOptimized = React.useCallback((activeSheet: any, templat
toast.warning("No actual changes were found to save. Please check if the values were properly edited.");
}
}
-
+
setHasChanges(false);
setValidationErrors([]);
-
+
} catch (error) {
console.error("Error saving changes:", error);
toast.error("An unexpected error occurred while saving");
@@ -1339,16 +1376,16 @@ const createGrdListTableOptimized = React.useCallback((activeSheet: any, templat
setIsPending(false);
}
}, [
- currentSpread,
- hasChanges,
- templateType,
- selectedRow,
- tableData,
- formCode,
- contractItemId,
- onUpdateSuccess,
- cellMappings,
- columnsJSON,
+ currentSpread,
+ hasChanges,
+ templateType,
+ selectedRow,
+ tableData,
+ formCode,
+ contractItemId,
+ onUpdateSuccess,
+ cellMappings,
+ columnsJSON,
validateAllData,
isFieldEditable // ๐Ÿ”ง ์˜์กด์„ฑ ์ถ”๊ฐ€
]);
@@ -1357,11 +1394,11 @@ const createGrdListTableOptimized = React.useCallback((activeSheet: any, templat
const isDataValid = templateType === 'SPREAD_ITEM' ? !!selectedRow : tableData.length > 0;
const dataCount = templateType === 'SPREAD_ITEM' ? 1 : tableData.length;
-
+
return (
<Dialog open={isOpen} onOpenChange={onClose}>
<DialogContent
- className="w-[90vw] max-w-[1400px] h-[85vh] flex flex-col fixed top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%] z-50"
+ className="w-[95vw] max-w-[95vw] h-[90vh] flex flex-col fixed top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%] z-50"
>
<DialogHeader className="flex-shrink-0">
<DialogTitle>SEDP Template - {formCode}</DialogTitle>
@@ -1439,13 +1476,13 @@ const createGrdListTableOptimized = React.useCallback((activeSheet: any, templat
<div className="flex-1 overflow-hidden relative">
{/* ๐Ÿ†• ๋กœ๋”ฉ ํ”„๋กœ๊ทธ๋ ˆ์Šค ์˜ค๋ฒ„๋ ˆ์ด */}
- <LoadingProgress
+ <LoadingProgress
phase={loadingProgress?.phase || ''}
progress={loadingProgress?.progress || 0}
total={loadingProgress?.total || 100}
isVisible={isInitializing && !!loadingProgress}
/>
-
+
{selectedTemplate && isClient && isDataValid ? (
<SpreadSheets
key={`${templateType}-${selectedTemplate.TMPL_ID}-${selectedTemplateId}`}