컴포넌트 리뉴얼 1.0

This commit is contained in:
kjs
2025-12-19 15:44:38 +09:00
parent 2487c79a61
commit 91d00aa784
61 changed files with 11678 additions and 175 deletions

View File

@@ -3,6 +3,101 @@ import { AuthenticatedRequest } from "../types/auth";
import { getPool } from "../database/db";
import { logger } from "../utils/logger";
/**
* 엔티티 옵션 조회 API (UnifiedSelect용)
* GET /api/entity/:tableName/options
*
* Query Params:
* - value: 값 컬럼 (기본: id)
* - label: 표시 컬럼 (기본: name)
*/
export async function getEntityOptions(req: AuthenticatedRequest, res: Response) {
try {
const { tableName } = req.params;
const { value = "id", label = "name" } = req.query;
// tableName 유효성 검증
if (!tableName || tableName === "undefined" || tableName === "null") {
logger.warn("엔티티 옵션 조회 실패: 테이블명이 없음", { tableName });
return res.status(400).json({
success: false,
message: "테이블명이 지정되지 않았습니다.",
});
}
const companyCode = req.user!.companyCode;
const pool = getPool();
// 테이블의 실제 컬럼 목록 조회
const columnsResult = await pool.query(
`SELECT column_name FROM information_schema.columns
WHERE table_schema = 'public' AND table_name = $1`,
[tableName]
);
const existingColumns = new Set(columnsResult.rows.map((r: any) => r.column_name));
// 요청된 컬럼 검증
const valueColumn = existingColumns.has(value as string) ? value : "id";
const labelColumn = existingColumns.has(label as string) ? label : "name";
// 둘 다 없으면 에러
if (!existingColumns.has(valueColumn as string)) {
return res.status(400).json({
success: false,
message: `테이블 "${tableName}"에 값 컬럼 "${value}"이 존재하지 않습니다.`,
});
}
// label 컬럼이 없으면 value 컬럼을 label로도 사용
const effectiveLabelColumn = existingColumns.has(labelColumn as string) ? labelColumn : valueColumn;
// WHERE 조건 (멀티테넌시)
const whereConditions: string[] = [];
const params: any[] = [];
let paramIndex = 1;
if (companyCode !== "*" && existingColumns.has("company_code")) {
whereConditions.push(`company_code = $${paramIndex}`);
params.push(companyCode);
paramIndex++;
}
const whereClause = whereConditions.length > 0
? `WHERE ${whereConditions.join(" AND ")}`
: "";
// 쿼리 실행 (최대 500개)
const query = `
SELECT ${valueColumn} as value, ${effectiveLabelColumn} as label
FROM ${tableName}
${whereClause}
ORDER BY ${effectiveLabelColumn} ASC
LIMIT 500
`;
const result = await pool.query(query, params);
logger.info("엔티티 옵션 조회 성공", {
tableName,
valueColumn,
labelColumn: effectiveLabelColumn,
companyCode,
rowCount: result.rowCount,
});
res.json({
success: true,
data: result.rows,
});
} catch (error: any) {
logger.error("엔티티 옵션 조회 오류", {
error: error.message,
stack: error.stack,
});
res.status(500).json({ success: false, message: error.message });
}
}
/**
* 엔티티 검색 API
* GET /api/entity-search/:tableName