Merge branch 'main' into feature/screen-management
This commit is contained in:
@@ -30,6 +30,29 @@ export const getCategoryColumns = async (req: AuthenticatedRequest, res: Respons
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 모든 테이블의 카테고리 컬럼 목록 조회 (Select 옵션 설정용)
|
||||
*/
|
||||
export const getAllCategoryColumns = async (req: AuthenticatedRequest, res: Response) => {
|
||||
try {
|
||||
const companyCode = req.user!.companyCode;
|
||||
|
||||
const columns = await tableCategoryValueService.getAllCategoryColumns(companyCode);
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
data: columns,
|
||||
});
|
||||
} catch (error: any) {
|
||||
logger.error(`전체 카테고리 컬럼 조회 실패: ${error.message}`);
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: "전체 카테고리 컬럼 조회 중 오류가 발생했습니다",
|
||||
error: error.message,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 카테고리 값 목록 조회 (메뉴 스코프 적용)
|
||||
*
|
||||
|
||||
@@ -878,7 +878,17 @@ export async function addTableData(
|
||||
const hasCompanyCodeColumn = await tableManagementService.hasColumn(tableName, "company_code");
|
||||
if (hasCompanyCodeColumn) {
|
||||
data.company_code = companyCode;
|
||||
logger.info(`🔒 멀티테넌시: company_code 자동 추가 - ${companyCode}`);
|
||||
logger.info(`멀티테넌시: company_code 자동 추가 - ${companyCode}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 🆕 writer 컬럼 자동 추가 (테이블에 writer 컬럼이 있고 값이 없는 경우)
|
||||
const userId = req.user?.userId;
|
||||
if (userId && !data.writer) {
|
||||
const hasWriterColumn = await tableManagementService.hasColumn(tableName, "writer");
|
||||
if (hasWriterColumn) {
|
||||
data.writer = userId;
|
||||
logger.info(`writer 자동 추가 - ${userId}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Router } from "express";
|
||||
import {
|
||||
getCategoryColumns,
|
||||
getAllCategoryColumns,
|
||||
getCategoryValues,
|
||||
addCategoryValue,
|
||||
updateCategoryValue,
|
||||
@@ -22,6 +23,10 @@ const router = Router();
|
||||
// 모든 라우트에 인증 미들웨어 적용
|
||||
router.use(authenticateToken);
|
||||
|
||||
// 모든 테이블의 카테고리 컬럼 목록 조회 (Select 옵션 설정용)
|
||||
// 주의: 더 구체적인 라우트보다 먼저 와야 함
|
||||
router.get("/all-columns", getAllCategoryColumns);
|
||||
|
||||
// 테이블의 카테고리 컬럼 목록 조회
|
||||
router.get("/:tableName/columns", getCategoryColumns);
|
||||
|
||||
|
||||
@@ -86,11 +86,12 @@ export class CommonCodeService {
|
||||
}
|
||||
|
||||
// 회사별 필터링 (최고 관리자가 아닌 경우)
|
||||
// company_code = '*'인 공통 데이터도 함께 조회
|
||||
if (userCompanyCode && userCompanyCode !== "*") {
|
||||
whereConditions.push(`company_code = $${paramIndex}`);
|
||||
whereConditions.push(`(company_code = $${paramIndex} OR company_code = '*')`);
|
||||
values.push(userCompanyCode);
|
||||
paramIndex++;
|
||||
logger.info(`회사별 코드 카테고리 필터링: ${userCompanyCode}`);
|
||||
logger.info(`회사별 코드 카테고리 필터링: ${userCompanyCode} (공통 데이터 포함)`);
|
||||
} else if (userCompanyCode === "*") {
|
||||
// 최고 관리자는 모든 데이터 조회 가능
|
||||
logger.info(`최고 관리자: 모든 코드 카테고리 조회`);
|
||||
@@ -116,7 +117,7 @@ export class CommonCodeService {
|
||||
|
||||
const offset = (page - 1) * size;
|
||||
|
||||
// 카테고리 조회
|
||||
// code_category 테이블에서만 조회 (comm_code 제거)
|
||||
const categories = await query<CodeCategory>(
|
||||
`SELECT * FROM code_category
|
||||
${whereClause}
|
||||
@@ -134,7 +135,7 @@ export class CommonCodeService {
|
||||
const total = parseInt(countResult?.count || "0");
|
||||
|
||||
logger.info(
|
||||
`카테고리 조회 완료: ${categories.length}개, 전체: ${total}개 (회사: ${userCompanyCode || "전체"})`
|
||||
`카테고리 조회 완료: code_category ${categories.length}개, 전체: ${total}개 (회사: ${userCompanyCode || "전체"})`
|
||||
);
|
||||
|
||||
return {
|
||||
@@ -224,7 +225,7 @@ export class CommonCodeService {
|
||||
paramIndex,
|
||||
});
|
||||
|
||||
// 코드 조회
|
||||
// code_info 테이블에서만 코드 조회 (comm_code fallback 제거)
|
||||
const codes = await query<CodeInfo>(
|
||||
`SELECT * FROM code_info
|
||||
${whereClause}
|
||||
@@ -242,20 +243,9 @@ export class CommonCodeService {
|
||||
const total = parseInt(countResult?.count || "0");
|
||||
|
||||
logger.info(
|
||||
`✅ [getCodes] 코드 조회 완료: ${categoryCode} - ${codes.length}개, 전체: ${total}개 (회사: ${userCompanyCode || "전체"}, menuObjid: ${menuObjid || "없음"})`
|
||||
`코드 조회 완료: ${categoryCode} - ${codes.length}개, 전체: ${total}개 (회사: ${userCompanyCode || "전체"}, menuObjid: ${menuObjid || "없음"})`
|
||||
);
|
||||
|
||||
logger.info(`📊 [getCodes] 조회된 코드 상세:`, {
|
||||
categoryCode,
|
||||
menuObjid,
|
||||
codes: codes.map((c) => ({
|
||||
code_value: c.code_value,
|
||||
code_name: c.code_name,
|
||||
menu_objid: c.menu_objid,
|
||||
company_code: c.company_code,
|
||||
})),
|
||||
});
|
||||
|
||||
return { data: codes, total };
|
||||
} catch (error) {
|
||||
logger.error(`코드 조회 중 오류 (${categoryCode}):`, error);
|
||||
|
||||
@@ -854,6 +854,11 @@ export class DynamicFormService {
|
||||
if (tableColumns.includes("updated_at")) {
|
||||
changedFields.updated_at = new Date();
|
||||
}
|
||||
// updated_date 컬럼도 지원 (sales_order_mng 등)
|
||||
if (tableColumns.includes("updated_date")) {
|
||||
changedFields.updated_date = new Date();
|
||||
console.log("📅 updated_date 자동 추가:", changedFields.updated_date);
|
||||
}
|
||||
|
||||
console.log("🎯 실제 업데이트할 필드들:", changedFields);
|
||||
|
||||
|
||||
@@ -79,6 +79,82 @@ class TableCategoryValueService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 모든 테이블의 카테고리 컬럼 목록 조회 (Select 옵션 설정용)
|
||||
* 테이블 선택 없이 등록된 모든 카테고리 컬럼을 조회합니다.
|
||||
*/
|
||||
async getAllCategoryColumns(
|
||||
companyCode: string
|
||||
): Promise<CategoryColumn[]> {
|
||||
try {
|
||||
logger.info("전체 카테고리 컬럼 목록 조회", { companyCode });
|
||||
|
||||
const pool = getPool();
|
||||
|
||||
let query: string;
|
||||
let params: any[];
|
||||
|
||||
if (companyCode === "*") {
|
||||
// 최고 관리자: 모든 카테고리 컬럼 조회 (중복 제거)
|
||||
query = `
|
||||
SELECT
|
||||
tc.table_name AS "tableName",
|
||||
tc.column_name AS "columnName",
|
||||
tc.column_name AS "columnLabel",
|
||||
COALESCE(cv_count.cnt, 0) AS "valueCount"
|
||||
FROM (
|
||||
SELECT DISTINCT table_name, column_name, MIN(display_order) as display_order
|
||||
FROM table_type_columns
|
||||
WHERE input_type = 'category'
|
||||
GROUP BY table_name, column_name
|
||||
) tc
|
||||
LEFT JOIN (
|
||||
SELECT table_name, column_name, COUNT(*) as cnt
|
||||
FROM table_column_category_values
|
||||
WHERE is_active = true
|
||||
GROUP BY table_name, column_name
|
||||
) cv_count ON tc.table_name = cv_count.table_name AND tc.column_name = cv_count.column_name
|
||||
ORDER BY tc.table_name, tc.display_order, tc.column_name
|
||||
`;
|
||||
params = [];
|
||||
} else {
|
||||
// 일반 회사: 자신의 카테고리 값만 카운트 (중복 제거)
|
||||
query = `
|
||||
SELECT
|
||||
tc.table_name AS "tableName",
|
||||
tc.column_name AS "columnName",
|
||||
tc.column_name AS "columnLabel",
|
||||
COALESCE(cv_count.cnt, 0) AS "valueCount"
|
||||
FROM (
|
||||
SELECT DISTINCT table_name, column_name, MIN(display_order) as display_order
|
||||
FROM table_type_columns
|
||||
WHERE input_type = 'category'
|
||||
GROUP BY table_name, column_name
|
||||
) tc
|
||||
LEFT JOIN (
|
||||
SELECT table_name, column_name, COUNT(*) as cnt
|
||||
FROM table_column_category_values
|
||||
WHERE is_active = true AND company_code = $1
|
||||
GROUP BY table_name, column_name
|
||||
) cv_count ON tc.table_name = cv_count.table_name AND tc.column_name = cv_count.column_name
|
||||
ORDER BY tc.table_name, tc.display_order, tc.column_name
|
||||
`;
|
||||
params = [companyCode];
|
||||
}
|
||||
|
||||
const result = await pool.query(query, params);
|
||||
|
||||
logger.info(`전체 카테고리 컬럼 ${result.rows.length}개 조회 완료`, {
|
||||
companyCode,
|
||||
});
|
||||
|
||||
return result.rows;
|
||||
} catch (error: any) {
|
||||
logger.error(`전체 카테고리 컬럼 조회 실패: ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 특정 컬럼의 카테고리 값 목록 조회 (메뉴 스코프)
|
||||
*
|
||||
|
||||
@@ -2289,6 +2289,13 @@ export class TableManagementService {
|
||||
|
||||
logger.info(`컬럼 타입 정보:`, Object.fromEntries(columnTypeMap));
|
||||
|
||||
// created_date 컬럼이 있고 값이 없으면 자동으로 현재 시간 추가
|
||||
const hasCreatedDate = columnTypeMap.has("created_date");
|
||||
if (hasCreatedDate && !data.created_date) {
|
||||
data.created_date = new Date().toISOString();
|
||||
logger.info(`created_date 자동 추가: ${data.created_date}`);
|
||||
}
|
||||
|
||||
// 컬럼명과 값을 분리하고 타입에 맞게 변환
|
||||
const columns = Object.keys(data);
|
||||
const values = Object.values(data).map((value, index) => {
|
||||
@@ -2394,6 +2401,13 @@ export class TableManagementService {
|
||||
logger.info(`컬럼 타입 정보:`, Object.fromEntries(columnTypeMap));
|
||||
logger.info(`PRIMARY KEY 컬럼들:`, primaryKeys);
|
||||
|
||||
// updated_date 컬럼이 있으면 자동으로 현재 시간 추가
|
||||
const hasUpdatedDate = columnTypeMap.has("updated_date");
|
||||
if (hasUpdatedDate && !updatedData.updated_date) {
|
||||
updatedData.updated_date = new Date().toISOString();
|
||||
logger.info(`updated_date 자동 추가: ${updatedData.updated_date}`);
|
||||
}
|
||||
|
||||
// SET 절 생성 (수정할 데이터) - 먼저 생성
|
||||
const setConditions: string[] = [];
|
||||
const setValues: any[] = [];
|
||||
|
||||
Reference in New Issue
Block a user