diff options
Diffstat (limited to 'components/form-data/import-excel-form.tsx')
| -rw-r--r-- | components/form-data/import-excel-form.tsx | 117 |
1 files changed, 99 insertions, 18 deletions
diff --git a/components/form-data/import-excel-form.tsx b/components/form-data/import-excel-form.tsx index d425a909..f32e44d8 100644 --- a/components/form-data/import-excel-form.tsx +++ b/components/form-data/import-excel-form.tsx @@ -1,17 +1,18 @@ -// lib/excelUtils.ts (continued) import ExcelJS from "exceljs"; import { saveAs } from "file-saver"; import { toast } from "sonner"; import { DataTableColumnJSON } from "./form-data-table-columns"; import { updateFormDataInDB } from "@/lib/forms/services"; import { decryptWithServerAction } from "../drm/drmUtils"; -// Assuming the previous types are defined above + +// Enhanced options interface with editableFieldsMap export interface ImportExcelOptions { file: File; tableData: GenericData[]; columnsJSON: DataTableColumnJSON[]; - formCode?: string; // Optional - provide to enable direct DB save - contractItemId?: number; // Optional - provide to enable direct DB save + formCode?: string; + contractItemId?: number; + editableFieldsMap?: Map<string, string[]>; // 새로 추가 onPendingChange?: (isPending: boolean) => void; onDataUpdate?: (updater: ((prev: GenericData[]) => GenericData[]) | GenericData[]) => void; } @@ -21,6 +22,7 @@ export interface ImportExcelResult { importedCount?: number; error?: any; message?: string; + skippedFields?: { tagNo: string, fields: string[] }[]; // 건너뛴 필드 정보 } export interface ExportExcelOptions { @@ -30,7 +32,6 @@ export interface ExportExcelOptions { onPendingChange?: (isPending: boolean) => void; } -// For typing consistency interface GenericData { [key: string]: any; } @@ -41,6 +42,7 @@ export async function importExcelData({ columnsJSON, formCode, contractItemId, + editableFieldsMap = new Map(), // 기본값으로 빈 Map onPendingChange, onDataUpdate }: ImportExcelOptions): Promise<ImportExcelResult> { @@ -59,7 +61,6 @@ export async function importExcelData({ }); const workbook = new ExcelJS.Workbook(); - // const arrayBuffer = await file.arrayBuffer(); const arrayBuffer = await decryptWithServerAction(file); await workbook.xlsx.load(arrayBuffer); @@ -127,6 +128,7 @@ export async function importExcelData({ const importedData: GenericData[] = []; const lastRowNumber = worksheet.lastRow?.number || 1; let errorCount = 0; + const skippedFieldsLog: { tagNo: string, fields: string[] }[] = []; // 건너뛴 필드 로그 // Process each data row for (let rowNum = 2; rowNum <= lastRowNumber; rowNum++) { @@ -135,21 +137,51 @@ export async function importExcelData({ if (!rowValues || rowValues.length <= 1) continue; // Skip empty rows let errorMessage = ""; + let warningMessage = ""; const rowObj: Record<string, any> = {}; + const skippedFields: string[] = []; // 현재 행에서 건너뛴 필드들 - // Get the TAG_NO first to identify existing data + // Get the TAG_NO first to identify existing data and editable fields const tagNoColIndex = keyToIndexMap.get("TAG_NO"); const tagNo = tagNoColIndex ? String(rowValues[tagNoColIndex] ?? "").trim() : ""; const existingRowData = existingDataMap.get(tagNo); + + // Get editable fields for this specific TAG + const editableFields = editableFieldsMap.has(tagNo) ? editableFieldsMap.get(tagNo)! : []; // Process each column columnsJSON.forEach((col) => { const colIndex = keyToIndexMap.get(col.key); if (colIndex === undefined) return; - // Check if this column should be ignored (col.shi === true) + // Determine if this field is editable + let isFieldEditable = true; + let skipReason = ""; + + // 1. Check if this is a SHI-only field if (col.shi === true) { - // Use existing value instead of Excel value + isFieldEditable = false; + skipReason = "SHI-only field"; + } + // 2. Check if this field is editable based on TAG class attributes + else if (col.key !== "TAG_NO" && col.key !== "TAG_DESC") { + // For non-basic fields, check if they're in the editable list + if (tagNo && editableFieldsMap.has(tagNo)) { + if (!editableFields.includes(col.key)) { + isFieldEditable = false; + skipReason = "Not editable for this TAG class"; + } + } else if (tagNo) { + // If TAG exists but no editable fields info, treat as not editable + isFieldEditable = false; + skipReason = "No editable fields info for this TAG"; + } + } + // 3. TAG_NO and TAG_DESC are always considered basic fields + // (They should be editable, but you might want to add specific logic here) + + // If field is not editable, use existing value or default + if (!isFieldEditable) { if (existingRowData && existingRowData[col.key] !== undefined) { rowObj[col.key] = existingRowData[col.key]; } else { @@ -165,9 +197,13 @@ export async function importExcelData({ break; } } + + // Log skipped field + skippedFields.push(`${col.label} (${skipReason})`); return; // Skip processing Excel value for this column } + // Process Excel value for editable fields const cellValue = rowValues[colIndex] ?? ""; let stringVal = String(cellValue).trim(); @@ -212,6 +248,15 @@ export async function importExcelData({ } }); + // Log skipped fields for this TAG + if (skippedFields.length > 0) { + skippedFieldsLog.push({ + tagNo: tagNo, + fields: skippedFields + }); + warningMessage += `Skipped ${skippedFields.length} non-editable fields. `; + } + // Validate TAG_NO const tagNum = rowObj["TAG_NO"]; if (!tagNum) { @@ -225,10 +270,23 @@ export async function importExcelData({ row.getCell(lastColIndex).value = errorMessage.trim(); errorCount++; } else { + // Add warning message to Excel if there are skipped fields + if (warningMessage) { + row.getCell(lastColIndex).value = `WARNING: ${warningMessage.trim()}`; + } importedData.push(rowObj); } } + // Show summary of skipped fields + if (skippedFieldsLog.length > 0) { + const totalSkippedFields = skippedFieldsLog.reduce((sum, log) => sum + log.fields.length, 0); + console.log("Skipped fields summary:", skippedFieldsLog); + toast.info( + `${totalSkippedFields} non-editable fields were skipped across ${skippedFieldsLog.length} rows. Check console for details.` + ); + } + // If there are validation errors, download error report and exit if (errorCount > 0) { const outBuffer = await workbook.xlsx.writeBuffer(); @@ -236,7 +294,11 @@ export async function importExcelData({ toast.error( `There are ${errorCount} error row(s). Please check downloaded file.` ); - return { success: false, error: "Data validation errors" }; + return { + success: false, + error: "Data validation errors", + skippedFields: skippedFieldsLog + }; } // If we reached here, all data is valid @@ -310,13 +372,15 @@ export async function importExcelData({ return { success: true, importedCount: successCount, - message: `Partially successful: ${successCount} rows updated, ${errorCount} errors` + message: `Partially successful: ${successCount} rows updated, ${errorCount} errors`, + skippedFields: skippedFieldsLog }; } else { return { success: false, error: "All updates failed", - message: errors.join("\n") + message: errors.join("\n"), + skippedFields: skippedFieldsLog }; } } @@ -326,16 +390,25 @@ export async function importExcelData({ onDataUpdate(() => mergedData); } - toast.success(`Successfully updated ${successCount} rows`); + const successMessage = skippedFieldsLog.length > 0 + ? `Successfully updated ${successCount} rows (some non-editable fields were preserved)` + : `Successfully updated ${successCount} rows`; + + toast.success(successMessage); return { success: true, importedCount: successCount, - message: "All data imported and saved to database" + message: "All data imported and saved to database", + skippedFields: skippedFieldsLog }; } catch (saveError) { console.error("Failed to save imported data:", saveError); toast.error("Failed to save imported data to database"); - return { success: false, error: saveError }; + return { + success: false, + error: saveError, + skippedFields: skippedFieldsLog + }; } } else { // Fall back to just updating local state if DB parameters aren't provided @@ -343,8 +416,16 @@ export async function importExcelData({ onDataUpdate(() => mergedData); } - toast.success(`Imported ${importedData.length} rows successfully (local only)`); - return { success: true, importedCount: importedData.length }; + const successMessage = skippedFieldsLog.length > 0 + ? `Imported ${importedData.length} rows successfully (some fields preserved)` + : `Imported ${importedData.length} rows successfully`; + + toast.success(`${successMessage} (local only)`); + return { + success: true, + importedCount: importedData.length, + skippedFields: skippedFieldsLog + }; } } catch (err) { @@ -354,4 +435,4 @@ export async function importExcelData({ } finally { if (onPendingChange) onPendingChange(false); } -}
\ No newline at end of file +} |
