엑셀 업로드 기능 개선
This commit is contained in:
parent
3d287bb883
commit
1995c3dca4
|
|
@ -3245,6 +3245,7 @@ export const resetUserPassword = async (
|
|||
|
||||
/**
|
||||
* 테이블 스키마 조회 (엑셀 업로드 컬럼 매핑용)
|
||||
* column_labels 테이블에서 라벨 정보도 함께 가져옴
|
||||
*/
|
||||
export async function getTableSchema(
|
||||
req: AuthenticatedRequest,
|
||||
|
|
@ -3264,20 +3265,25 @@ export async function getTableSchema(
|
|||
|
||||
logger.info("테이블 스키마 조회", { tableName, companyCode });
|
||||
|
||||
// information_schema에서 컬럼 정보 가져오기
|
||||
// information_schema와 column_labels를 JOIN하여 컬럼 정보와 라벨 정보 함께 가져오기
|
||||
const schemaQuery = `
|
||||
SELECT
|
||||
column_name,
|
||||
data_type,
|
||||
is_nullable,
|
||||
column_default,
|
||||
character_maximum_length,
|
||||
numeric_precision,
|
||||
numeric_scale
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = $1
|
||||
ORDER BY ordinal_position
|
||||
ic.column_name,
|
||||
ic.data_type,
|
||||
ic.is_nullable,
|
||||
ic.column_default,
|
||||
ic.character_maximum_length,
|
||||
ic.numeric_precision,
|
||||
ic.numeric_scale,
|
||||
cl.column_label,
|
||||
cl.display_order
|
||||
FROM information_schema.columns ic
|
||||
LEFT JOIN column_labels cl
|
||||
ON cl.table_name = ic.table_name
|
||||
AND cl.column_name = ic.column_name
|
||||
WHERE ic.table_schema = 'public'
|
||||
AND ic.table_name = $1
|
||||
ORDER BY COALESCE(cl.display_order, ic.ordinal_position), ic.ordinal_position
|
||||
`;
|
||||
|
||||
const columns = await query<any>(schemaQuery, [tableName]);
|
||||
|
|
@ -3290,9 +3296,10 @@ export async function getTableSchema(
|
|||
return;
|
||||
}
|
||||
|
||||
// 컬럼 정보를 간단한 형태로 변환
|
||||
// 컬럼 정보를 간단한 형태로 변환 (라벨 정보 포함)
|
||||
const columnList = columns.map((col: any) => ({
|
||||
name: col.column_name,
|
||||
label: col.column_label || col.column_name, // 라벨이 없으면 컬럼명 사용
|
||||
type: col.data_type,
|
||||
nullable: col.is_nullable === "YES",
|
||||
default: col.column_default,
|
||||
|
|
|
|||
|
|
@ -236,13 +236,23 @@ export const ExcelUploadModal: React.FC<ExcelUploadModalProps> = ({
|
|||
}
|
||||
};
|
||||
|
||||
// 자동 매핑
|
||||
// 자동 매핑 - 컬럼명과 라벨 모두 비교
|
||||
const handleAutoMapping = () => {
|
||||
const newMappings = excelColumns.map((excelCol) => {
|
||||
const matchedSystemCol = systemColumns.find(
|
||||
(sysCol) => sysCol.name.toLowerCase() === excelCol.toLowerCase()
|
||||
const normalizedExcelCol = excelCol.toLowerCase().trim();
|
||||
|
||||
// 1. 먼저 라벨로 매칭 시도
|
||||
let matchedSystemCol = systemColumns.find(
|
||||
(sysCol) => sysCol.label && sysCol.label.toLowerCase().trim() === normalizedExcelCol
|
||||
);
|
||||
|
||||
// 2. 라벨로 매칭되지 않으면 컬럼명으로 매칭 시도
|
||||
if (!matchedSystemCol) {
|
||||
matchedSystemCol = systemColumns.find(
|
||||
(sysCol) => sysCol.name.toLowerCase().trim() === normalizedExcelCol
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
excelColumn: excelCol,
|
||||
systemColumn: matchedSystemCol ? matchedSystemCol.name : null,
|
||||
|
|
@ -734,7 +744,14 @@ export const ExcelUploadModal: React.FC<ExcelUploadModalProps> = ({
|
|||
}
|
||||
>
|
||||
<SelectTrigger className="h-8 text-xs sm:h-10 sm:text-sm">
|
||||
<SelectValue placeholder="매핑 안함" />
|
||||
<SelectValue placeholder="매핑 안함">
|
||||
{mapping.systemColumn
|
||||
? (() => {
|
||||
const col = systemColumns.find(c => c.name === mapping.systemColumn);
|
||||
return col?.label || mapping.systemColumn;
|
||||
})()
|
||||
: "매핑 안함"}
|
||||
</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="none" className="text-xs sm:text-sm">
|
||||
|
|
@ -746,7 +763,7 @@ export const ExcelUploadModal: React.FC<ExcelUploadModalProps> = ({
|
|||
value={col.name}
|
||||
className="text-xs sm:text-sm"
|
||||
>
|
||||
{col.name} ({col.type})
|
||||
{col.label || col.name} ({col.type})
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { apiClient } from "./client";
|
|||
|
||||
export interface TableColumn {
|
||||
name: string;
|
||||
label: string; // 컬럼 라벨 (column_labels 테이블에서 가져옴)
|
||||
type: string;
|
||||
nullable: boolean;
|
||||
default: string | null;
|
||||
|
|
|
|||
Loading…
Reference in New Issue