[ST] - fix: excel 가져오기 시 코드값이 숫자로 인식되어 저장이 이루어지지 않던 문제 수정

This commit is contained in:
2026-10-29 10:27:42 +09:00
parent 038b2d441e
commit b5f5938e51
3 changed files with 111 additions and 50 deletions
+13 -30
View File
@@ -33,6 +33,7 @@ import {
hasAdmdstCdColumn,
isExcelImportAdmdstCdInvalid,
mergeExcelImportWithExistingRows,
parseExcelImportCellValue,
prepareGridColumnsForExcelExport,
releaseFixedOptionsForExcelExport,
resolveColumnStyleName,
@@ -1346,6 +1347,11 @@ useEffect(() => {
columnLayout,
{ skipNonEditable: false },
);
const valueTypeByFieldName = new Map(
columns
.filter((c) => c.fieldName)
.map((c) => [c.fieldName as string, c.valueType]),
);
// 데이터 행 읽기
const dataRows: Record<string, string | number>[] = [];
@@ -1367,36 +1373,13 @@ useEffect(() => {
];
const fieldName = excelColumnFieldNames[colIndex];
const allFieldName = excelColumnFieldNamesAll[colIndex];
let cellValue: string | number = "";
if (
cell &&
cell.v !== undefined &&
cell.v !== null
) {
// 엑셀 셀 타입이 숫자이거나 값이 숫자인 경우 숫자로 변환
if (
cell.t === "n" ||
(typeof cell.v === "number" &&
!isNaN(cell.v))
) {
cellValue = cell.v as number;
} else {
const stringValue = String(cell.v);
// 문자열이지만 숫자로 변환 가능한 경우 숫자로 변환
const numericValue = Number(
stringValue.replace(/,/g, ""),
);
if (
!isNaN(numericValue) &&
stringValue.trim() !== ""
) {
cellValue = numericValue;
} else {
cellValue = stringValue;
}
}
}
const typeFieldName = fieldName || allFieldName;
const cellValue = parseExcelImportCellValue(
cell,
typeFieldName
? valueTypeByFieldName.get(typeFieldName)
: undefined,
);
if (allFieldName === "admdstCd" && cellValue !== "") {
rowAdmdstCd = cellValue;
+13 -17
View File
@@ -53,6 +53,7 @@ import {
hasAdmdstCdColumn,
isExcelImportAdmdstCdInvalid,
mergeExcelImportWithExistingRows,
parseExcelImportCellValue,
prepareGridColumnsForExcelExport,
releaseFixedOptionsForExcelExport,
resolveColumnStyleName,
@@ -611,6 +612,11 @@ const TabDataGrid = ({
columnLayout,
{ skipNonEditable: false },
);
const valueTypeByFieldName = new Map(
columns
.filter((c) => c.fieldName)
.map((c) => [c.fieldName as string, c.valueType]),
);
// 데이터 행 읽기
const dataRows: Record<string, string | number>[] = [];
@@ -625,23 +631,13 @@ const TabDataGrid = ({
const cell = worksheet[XLSX.utils.encode_cell({ r: row, c: col })];
const fieldName = excelColumnFieldNames[colIndex];
const allFieldName = excelColumnFieldNamesAll[colIndex];
let cellValue: string | number = '';
if (cell && cell.v !== undefined && cell.v !== null) {
// 엑셀 셀 타입이 숫자이거나 값이 숫자인 경우 숫자로 변환
if (cell.t === 'n' || (typeof cell.v === 'number' && !isNaN(cell.v))) {
cellValue = cell.v as number;
} else {
const stringValue = String(cell.v);
// 문자열이지만 숫자로 변환 가능한 경우 숫자로 변환
const numericValue = Number(stringValue.replace(/,/g, ''));
if (!isNaN(numericValue) && stringValue.trim() !== '') {
cellValue = numericValue;
} else {
cellValue = stringValue;
}
}
}
const typeFieldName = fieldName || allFieldName;
const cellValue = parseExcelImportCellValue(
cell,
typeFieldName
? valueTypeByFieldName.get(typeFieldName)
: undefined,
);
if (allFieldName === 'admdstCd' && cellValue !== '') {
rowAdmdstCd = cellValue;
+85 -3
View File
@@ -1,4 +1,4 @@
import type { GridView } from "realgrid";
import { type GridView, ValueType } from "realgrid";
import type {
ColumnConfig,
@@ -124,6 +124,82 @@ export function getNonEditableColumnFieldNames(
return fieldNames;
}
type ExcelImportCell = {
t?: string;
v?: unknown;
w?: string;
};
/** 엑셀 셀 → 그리드 값. NUMBER 컬럼만 숫자화하고, 코드(01)는 문자열로 유지 */
export function parseExcelImportCellValue(
cell: ExcelImportCell | undefined,
valueType?: ColumnConfig["valueType"],
): string | number {
if (!cell || cell.v === undefined || cell.v === null || cell.v === "") {
return "";
}
if (valueType === ValueType.NUMBER) {
if (typeof cell.v === "number" && !Number.isNaN(cell.v)) {
return cell.v;
}
const stringValue = String(cell.v);
const numericValue = Number(stringValue.replace(/,/g, ""));
if (!Number.isNaN(numericValue) && stringValue.trim() !== "") {
return numericValue;
}
return stringValue;
}
const formatted = typeof cell.w === "string" ? cell.w.trim() : "";
if (/^0\d+$/.test(formatted)) {
return formatted;
}
return String(cell.v);
}
function collectZeroPaddedCodeWidths(
rows: Record<string, string | number>[],
): Map<string, number> {
const widthByField = new Map<string, number>();
for (const row of rows) {
for (const [field, value] of Object.entries(row)) {
const s = String(value ?? "").trim();
if (!/^0\d+$/.test(s)) continue;
widthByField.set(field, Math.max(widthByField.get(field) ?? 0, s.length));
}
}
return widthByField;
}
function restoreImportedCodeLeadingZeros(
importedRow: Record<string, string | number>,
existingRow: Record<string, string | number> | undefined,
codeWidthByField: Map<string, number>,
): Record<string, string | number> {
const next: Record<string, string | number> = { ...importedRow };
for (const [field, value] of Object.entries(next)) {
if (value === "" || value == null) continue;
if (typeof value === "number" && !Number.isInteger(value)) continue;
const importedStr = String(value).trim();
if (!/^\d+$/.test(importedStr)) continue;
const existingStr =
existingRow != null ? String(existingRow[field] ?? "").trim() : "";
let width = codeWidthByField.get(field);
if (!width && /^0\d+$/.test(existingStr)) {
width = existingStr.length;
}
if (!width && field.endsWith("Cd") && importedStr.length <= 2) {
width = 2;
}
if (width && importedStr.length < width) {
next[field] = importedStr.padStart(width, "0");
}
}
return next;
}
/** 엑셀 import 결과를 기존 행과 병합 — preserveFieldNames는 기존 그리드 값 유지 */
export function mergeExcelImportWithExistingRows(
existingRows: Record<string, string | number>[],
@@ -134,14 +210,20 @@ export function mergeExcelImportWithExistingRows(
options?.preserveFieldNames && options.preserveFieldNames.length > 0
? new Set(options.preserveFieldNames)
: null;
const codeWidthByField = collectZeroPaddedCodeWidths(existingRows);
return importedRows.map((importedRow, index) => {
const existingRow = existingRows[index];
if (!existingRow) return { ...importedRow };
const normalizedImported = restoreImportedCodeLeadingZeros(
importedRow,
existingRow,
codeWidthByField,
);
if (!existingRow) return normalizedImported;
const merged: Record<string, string | number> = {
...existingRow,
...importedRow,
...normalizedImported,
};
if (preserveSet) {
for (const fieldName of preserveSet) {