refactor: Update references from table_column_category_values to category_values
- Changed all occurrences of `table_column_category_values` to `category_values` in the backend services and controllers to standardize the terminology. - Updated SQL queries to reflect the new table name, ensuring proper data retrieval and management. - Adjusted comments and documentation to clarify the purpose of the `category_values` table in the context of category management. These changes enhance code clarity and maintain consistency across the application.
This commit is contained in:
parent
13506912d9
commit
f6a02b5182
|
|
@ -818,13 +818,13 @@ export const getCategoryValueCascadingParentOptions = async (
|
|||
|
||||
const group = groupResult.rows[0];
|
||||
|
||||
// 부모 카테고리 값 조회 (table_column_category_values에서)
|
||||
// 부모 카테고리 값 조회 (category_values에서)
|
||||
let optionsQuery = `
|
||||
SELECT
|
||||
value_code as value,
|
||||
value_label as label,
|
||||
value_order as display_order
|
||||
FROM table_column_category_values
|
||||
FROM category_values
|
||||
WHERE table_name = $1
|
||||
AND column_name = $2
|
||||
AND is_active = true
|
||||
|
|
@ -916,13 +916,13 @@ export const getCategoryValueCascadingChildOptions = async (
|
|||
|
||||
const group = groupResult.rows[0];
|
||||
|
||||
// 자식 카테고리 값 조회 (table_column_category_values에서)
|
||||
// 자식 카테고리 값 조회 (category_values에서)
|
||||
let optionsQuery = `
|
||||
SELECT
|
||||
value_code as value,
|
||||
value_label as label,
|
||||
value_order as display_order
|
||||
FROM table_column_category_values
|
||||
FROM category_values
|
||||
WHERE table_name = $1
|
||||
AND column_name = $2
|
||||
AND is_active = true
|
||||
|
|
|
|||
|
|
@ -417,10 +417,10 @@ export class EntityJoinController {
|
|||
// 1. 현재 테이블의 Entity 조인 설정 조회
|
||||
const allJoinConfigs = await entityJoinService.detectEntityJoins(tableName, undefined, companyCode);
|
||||
|
||||
// 🆕 화면 디자이너용: table_column_category_values는 카테고리 드롭다운용이므로 제외
|
||||
// 🆕 화면 디자이너용: category_values는 카테고리 드롭다운용이므로 제외
|
||||
// 카테고리 값은 엔티티 조인 컬럼이 아니라 셀렉트박스 옵션으로 사용됨
|
||||
const joinConfigs = allJoinConfigs.filter(
|
||||
(config) => config.referenceTable !== "table_column_category_values"
|
||||
(config) => config.referenceTable !== "category_values"
|
||||
);
|
||||
|
||||
if (joinConfigs.length === 0) {
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ export class EntityJoinService {
|
|||
|
||||
if (column.input_type === "category") {
|
||||
// 카테고리 타입: reference 정보가 비어있어도 자동 설정
|
||||
referenceTable = referenceTable || "table_column_category_values";
|
||||
referenceTable = referenceTable || "category_values";
|
||||
referenceColumn = referenceColumn || "value_code";
|
||||
displayColumn = displayColumn || "value_label";
|
||||
|
||||
|
|
@ -308,7 +308,7 @@ export class EntityJoinService {
|
|||
const usedAliasesForColumns = new Set<string>();
|
||||
|
||||
// joinConfigs를 참조 테이블 + 소스 컬럼별로 중복 제거하여 별칭 생성
|
||||
// (table_column_category_values는 같은 테이블이라도 sourceColumn마다 별도 JOIN 필요)
|
||||
// (category_values는 같은 테이블이라도 sourceColumn마다 별도 JOIN 필요)
|
||||
const uniqueReferenceTableConfigs = joinConfigs.reduce((acc, config) => {
|
||||
if (
|
||||
!acc.some(
|
||||
|
|
@ -336,7 +336,7 @@ export class EntityJoinService {
|
|||
counter++;
|
||||
}
|
||||
usedAliasesForColumns.add(alias);
|
||||
// 같은 테이블이라도 sourceColumn이 다르면 별도 별칭 생성 (table_column_category_values 대응)
|
||||
// 같은 테이블이라도 sourceColumn이 다르면 별도 별칭 생성 (category_values 대응)
|
||||
const aliasKey = `${config.referenceTable}:${config.sourceColumn}`;
|
||||
aliasMap.set(aliasKey, alias);
|
||||
logger.info(
|
||||
|
|
@ -455,9 +455,10 @@ export class EntityJoinService {
|
|||
const aliasKey = `${config.referenceTable}:${config.sourceColumn}`;
|
||||
const alias = aliasMap.get(aliasKey);
|
||||
|
||||
// table_column_category_values는 특별한 조인 조건 필요 (회사별 필터링)
|
||||
if (config.referenceTable === "table_column_category_values") {
|
||||
return `LEFT JOIN ${config.referenceTable} ${alias} ON main."${config.sourceColumn}"::TEXT = ${alias}."${config.referenceColumn}"::TEXT AND ${alias}.table_name = '${tableName}' AND ${alias}.column_name = '${config.sourceColumn}' AND ${alias}.company_code = main.company_code AND ${alias}.is_active = true`;
|
||||
// category_values는 특별한 조인 조건 필요 (회사별 필터링)
|
||||
// is_active 필터 제거: 비활성화된 카테고리도 라벨로 표시되어야 함
|
||||
if (config.referenceTable === "category_values") {
|
||||
return `LEFT JOIN ${config.referenceTable} ${alias} ON main."${config.sourceColumn}"::TEXT = ${alias}."${config.referenceColumn}"::TEXT AND ${alias}.table_name = '${tableName}' AND ${alias}.column_name = '${config.sourceColumn}' AND ${alias}.company_code = main.company_code`;
|
||||
}
|
||||
|
||||
// user_info는 전역 테이블이므로 company_code 조건 없이 조인
|
||||
|
|
@ -528,10 +529,10 @@ export class EntityJoinService {
|
|||
return "join";
|
||||
}
|
||||
|
||||
// table_column_category_values는 특수 조인 조건이 필요하므로 캐시 불가
|
||||
if (config.referenceTable === "table_column_category_values") {
|
||||
// category_values는 특수 조인 조건이 필요하므로 캐시 불가
|
||||
if (config.referenceTable === "category_values") {
|
||||
logger.info(
|
||||
`🎯 table_column_category_values는 캐시 전략 불가: ${config.sourceColumn}`
|
||||
`🎯 category_values는 캐시 전략 불가: ${config.sourceColumn}`
|
||||
);
|
||||
return "join";
|
||||
}
|
||||
|
|
@ -723,10 +724,10 @@ export class EntityJoinService {
|
|||
const aliasKey = `${config.referenceTable}:${config.sourceColumn}`;
|
||||
const alias = aliasMap.get(aliasKey);
|
||||
|
||||
// table_column_category_values는 특별한 조인 조건 필요 (회사별 필터링만)
|
||||
if (config.referenceTable === "table_column_category_values") {
|
||||
// 멀티테넌시: 회사 데이터만 사용 (공통 데이터 제외)
|
||||
return `LEFT JOIN ${config.referenceTable} ${alias} ON main."${config.sourceColumn}"::TEXT = ${alias}."${config.referenceColumn}"::TEXT AND ${alias}.table_name = '${tableName}' AND ${alias}.column_name = '${config.sourceColumn}' AND ${alias}.company_code = main.company_code AND ${alias}.is_active = true`;
|
||||
// category_values는 특별한 조인 조건 필요 (회사별 필터링만)
|
||||
// is_active 필터 제거: 비활성화된 카테고리도 라벨로 표시되어야 함
|
||||
if (config.referenceTable === "category_values") {
|
||||
return `LEFT JOIN ${config.referenceTable} ${alias} ON main."${config.sourceColumn}"::TEXT = ${alias}."${config.referenceColumn}"::TEXT AND ${alias}.table_name = '${tableName}' AND ${alias}.column_name = '${config.sourceColumn}' AND ${alias}.company_code = main.company_code`;
|
||||
}
|
||||
|
||||
return `LEFT JOIN ${config.referenceTable} ${alias} ON main."${config.sourceColumn}"::TEXT = ${alias}."${config.referenceColumn}"::TEXT`;
|
||||
|
|
|
|||
|
|
@ -3098,7 +3098,7 @@ export class MenuCopyService {
|
|||
}
|
||||
|
||||
const allValuesResult = await client.query(
|
||||
`SELECT * FROM table_column_category_values
|
||||
`SELECT * FROM category_values
|
||||
WHERE company_code = $1
|
||||
AND (${columnConditions.join(" OR ")})
|
||||
ORDER BY depth NULLS FIRST, parent_value_id NULLS FIRST, value_order`,
|
||||
|
|
@ -3115,7 +3115,7 @@ export class MenuCopyService {
|
|||
// 5. 대상 회사에 이미 존재하는 값 한 번에 조회
|
||||
const existingValuesResult = await client.query(
|
||||
`SELECT value_id, table_name, column_name, value_code
|
||||
FROM table_column_category_values WHERE company_code = $1`,
|
||||
FROM category_values WHERE company_code = $1`,
|
||||
[targetCompanyCode]
|
||||
);
|
||||
const existingValueKeys = new Map(
|
||||
|
|
@ -3194,7 +3194,7 @@ export class MenuCopyService {
|
|||
});
|
||||
|
||||
const insertResult = await client.query(
|
||||
`INSERT INTO table_column_category_values (
|
||||
`INSERT INTO category_values (
|
||||
table_name, column_name, value_code, value_label, value_order,
|
||||
parent_value_id, depth, description, color, icon,
|
||||
is_active, is_default, created_at, created_by, company_code, menu_objid
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class TableCategoryValueService {
|
|||
tc.column_name AS "columnLabel",
|
||||
COUNT(cv.value_id) AS "valueCount"
|
||||
FROM table_type_columns tc
|
||||
LEFT JOIN table_column_category_values cv
|
||||
LEFT JOIN category_values cv
|
||||
ON tc.table_name = cv.table_name
|
||||
AND tc.column_name = cv.column_name
|
||||
AND cv.is_active = true
|
||||
|
|
@ -50,7 +50,7 @@ class TableCategoryValueService {
|
|||
tc.column_name AS "columnLabel",
|
||||
COUNT(cv.value_id) AS "valueCount"
|
||||
FROM table_type_columns tc
|
||||
LEFT JOIN table_column_category_values cv
|
||||
LEFT JOIN category_values cv
|
||||
ON tc.table_name = cv.table_name
|
||||
AND tc.column_name = cv.column_name
|
||||
AND cv.is_active = true
|
||||
|
|
@ -110,7 +110,7 @@ class TableCategoryValueService {
|
|||
) tc
|
||||
LEFT JOIN (
|
||||
SELECT table_name, column_name, COUNT(*) as cnt
|
||||
FROM table_column_category_values
|
||||
FROM 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
|
||||
|
|
@ -133,7 +133,7 @@ class TableCategoryValueService {
|
|||
) tc
|
||||
LEFT JOIN (
|
||||
SELECT table_name, column_name, COUNT(*) as cnt
|
||||
FROM table_column_category_values
|
||||
FROM 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
|
||||
|
|
@ -207,7 +207,7 @@ class TableCategoryValueService {
|
|||
is_active AS "isActive",
|
||||
is_default AS "isDefault",
|
||||
company_code AS "companyCode",
|
||||
NULL::numeric AS "menuObjid",
|
||||
menu_objid AS "menuObjid",
|
||||
created_at AS "createdAt",
|
||||
updated_at AS "updatedAt",
|
||||
created_by AS "createdBy",
|
||||
|
|
@ -289,7 +289,7 @@ class TableCategoryValueService {
|
|||
// 최고 관리자: 모든 회사에서 중복 체크
|
||||
duplicateQuery = `
|
||||
SELECT value_id
|
||||
FROM table_column_category_values
|
||||
FROM category_values
|
||||
WHERE table_name = $1
|
||||
AND column_name = $2
|
||||
AND value_code = $3
|
||||
|
|
@ -300,7 +300,7 @@ class TableCategoryValueService {
|
|||
// 일반 회사: 자신의 회사에서만 중복 체크
|
||||
duplicateQuery = `
|
||||
SELECT value_id
|
||||
FROM table_column_category_values
|
||||
FROM category_values
|
||||
WHERE table_name = $1
|
||||
AND column_name = $2
|
||||
AND value_code = $3
|
||||
|
|
@ -316,8 +316,41 @@ class TableCategoryValueService {
|
|||
throw new Error("이미 존재하는 코드입니다");
|
||||
}
|
||||
|
||||
// 라벨 중복 체크 (같은 테이블+컬럼+회사에서 동일한 라벨명 방지)
|
||||
let labelDupQuery: string;
|
||||
let labelDupParams: any[];
|
||||
|
||||
if (companyCode === "*") {
|
||||
labelDupQuery = `
|
||||
SELECT value_id
|
||||
FROM category_values
|
||||
WHERE table_name = $1
|
||||
AND column_name = $2
|
||||
AND value_label = $3
|
||||
AND is_active = true
|
||||
`;
|
||||
labelDupParams = [value.tableName, value.columnName, value.valueLabel];
|
||||
} else {
|
||||
labelDupQuery = `
|
||||
SELECT value_id
|
||||
FROM category_values
|
||||
WHERE table_name = $1
|
||||
AND column_name = $2
|
||||
AND value_label = $3
|
||||
AND company_code = $4
|
||||
AND is_active = true
|
||||
`;
|
||||
labelDupParams = [value.tableName, value.columnName, value.valueLabel, companyCode];
|
||||
}
|
||||
|
||||
const labelDupResult = await pool.query(labelDupQuery, labelDupParams);
|
||||
|
||||
if (labelDupResult.rows.length > 0) {
|
||||
throw new Error(`이미 동일한 이름의 카테고리 값이 존재합니다: "${value.valueLabel}"`);
|
||||
}
|
||||
|
||||
const insertQuery = `
|
||||
INSERT INTO table_column_category_values (
|
||||
INSERT INTO category_values (
|
||||
table_name, column_name, value_code, value_label, value_order,
|
||||
parent_value_id, depth, description, color, icon,
|
||||
is_active, is_default, company_code, menu_objid, created_by
|
||||
|
|
@ -425,6 +458,32 @@ class TableCategoryValueService {
|
|||
values.push(updates.isDefault);
|
||||
}
|
||||
|
||||
// 라벨 수정 시 중복 체크 (자기 자신 제외)
|
||||
if (updates.valueLabel !== undefined) {
|
||||
const currentRow = await pool.query(
|
||||
`SELECT table_name, column_name, company_code FROM category_values WHERE value_id = $1`,
|
||||
[valueId]
|
||||
);
|
||||
|
||||
if (currentRow.rows.length > 0) {
|
||||
const { table_name, column_name, company_code } = currentRow.rows[0];
|
||||
const labelDupResult = await pool.query(
|
||||
`SELECT value_id FROM category_values
|
||||
WHERE table_name = $1
|
||||
AND column_name = $2
|
||||
AND value_label = $3
|
||||
AND company_code = $4
|
||||
AND is_active = true
|
||||
AND value_id != $5`,
|
||||
[table_name, column_name, updates.valueLabel, company_code, valueId]
|
||||
);
|
||||
|
||||
if (labelDupResult.rows.length > 0) {
|
||||
throw new Error(`이미 동일한 이름의 카테고리 값이 존재합니다: "${updates.valueLabel}"`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setClauses.push(`updated_at = NOW()`);
|
||||
setClauses.push(`updated_by = $${paramIndex++}`);
|
||||
values.push(userId);
|
||||
|
|
@ -436,7 +495,7 @@ class TableCategoryValueService {
|
|||
// 최고 관리자: 모든 카테고리 값 수정 가능
|
||||
values.push(valueId);
|
||||
updateQuery = `
|
||||
UPDATE table_column_category_values
|
||||
UPDATE category_values
|
||||
SET ${setClauses.join(", ")}
|
||||
WHERE value_id = $${paramIndex++}
|
||||
RETURNING
|
||||
|
|
@ -459,7 +518,7 @@ class TableCategoryValueService {
|
|||
// 일반 회사: 자신의 카테고리 값만 수정 가능
|
||||
values.push(valueId, companyCode);
|
||||
updateQuery = `
|
||||
UPDATE table_column_category_values
|
||||
UPDATE category_values
|
||||
SET ${setClauses.join(", ")}
|
||||
WHERE value_id = $${paramIndex++}
|
||||
AND company_code = $${paramIndex++}
|
||||
|
|
@ -516,14 +575,14 @@ class TableCategoryValueService {
|
|||
if (companyCode === "*") {
|
||||
valueQuery = `
|
||||
SELECT table_name, column_name, value_code
|
||||
FROM table_column_category_values
|
||||
FROM category_values
|
||||
WHERE value_id = $1
|
||||
`;
|
||||
valueParams = [valueId];
|
||||
} else {
|
||||
valueQuery = `
|
||||
SELECT table_name, column_name, value_code
|
||||
FROM table_column_category_values
|
||||
FROM category_values
|
||||
WHERE value_id = $1
|
||||
AND company_code = $2
|
||||
`;
|
||||
|
|
@ -635,10 +694,10 @@ class TableCategoryValueService {
|
|||
if (companyCode === "*") {
|
||||
query = `
|
||||
WITH RECURSIVE category_tree AS (
|
||||
SELECT value_id FROM table_column_category_values WHERE parent_value_id = $1
|
||||
SELECT value_id FROM category_values WHERE parent_value_id = $1
|
||||
UNION ALL
|
||||
SELECT cv.value_id
|
||||
FROM table_column_category_values cv
|
||||
FROM category_values cv
|
||||
INNER JOIN category_tree ct ON cv.parent_value_id = ct.value_id
|
||||
)
|
||||
SELECT value_id FROM category_tree
|
||||
|
|
@ -647,11 +706,11 @@ class TableCategoryValueService {
|
|||
} else {
|
||||
query = `
|
||||
WITH RECURSIVE category_tree AS (
|
||||
SELECT value_id FROM table_column_category_values
|
||||
SELECT value_id FROM category_values
|
||||
WHERE parent_value_id = $1 AND company_code = $2
|
||||
UNION ALL
|
||||
SELECT cv.value_id
|
||||
FROM table_column_category_values cv
|
||||
FROM category_values cv
|
||||
INNER JOIN category_tree ct ON cv.parent_value_id = ct.value_id
|
||||
WHERE cv.company_code = $2
|
||||
)
|
||||
|
|
@ -697,10 +756,10 @@ class TableCategoryValueService {
|
|||
let labelParams: any[];
|
||||
|
||||
if (companyCode === "*") {
|
||||
labelQuery = `SELECT value_label FROM table_column_category_values WHERE value_id = $1`;
|
||||
labelQuery = `SELECT value_label FROM category_values WHERE value_id = $1`;
|
||||
labelParams = [id];
|
||||
} else {
|
||||
labelQuery = `SELECT value_label FROM table_column_category_values WHERE value_id = $1 AND company_code = $2`;
|
||||
labelQuery = `SELECT value_label FROM category_values WHERE value_id = $1 AND company_code = $2`;
|
||||
labelParams = [id, companyCode];
|
||||
}
|
||||
|
||||
|
|
@ -730,10 +789,10 @@ class TableCategoryValueService {
|
|||
let deleteParams: any[];
|
||||
|
||||
if (companyCode === "*") {
|
||||
deleteQuery = `DELETE FROM table_column_category_values WHERE value_id = $1`;
|
||||
deleteQuery = `DELETE FROM category_values WHERE value_id = $1`;
|
||||
deleteParams = [id];
|
||||
} else {
|
||||
deleteQuery = `DELETE FROM table_column_category_values WHERE value_id = $1 AND company_code = $2`;
|
||||
deleteQuery = `DELETE FROM category_values WHERE value_id = $1 AND company_code = $2`;
|
||||
deleteParams = [id, companyCode];
|
||||
}
|
||||
|
||||
|
|
@ -770,7 +829,7 @@ class TableCategoryValueService {
|
|||
if (companyCode === "*") {
|
||||
// 최고 관리자: 모든 카테고리 값 일괄 삭제 가능
|
||||
deleteQuery = `
|
||||
UPDATE table_column_category_values
|
||||
UPDATE category_values
|
||||
SET is_active = false, updated_at = NOW(), updated_by = $2
|
||||
WHERE value_id = ANY($1::int[])
|
||||
`;
|
||||
|
|
@ -778,7 +837,7 @@ class TableCategoryValueService {
|
|||
} else {
|
||||
// 일반 회사: 자신의 카테고리 값만 일괄 삭제 가능
|
||||
deleteQuery = `
|
||||
UPDATE table_column_category_values
|
||||
UPDATE category_values
|
||||
SET is_active = false, updated_at = NOW(), updated_by = $3
|
||||
WHERE value_id = ANY($1::int[])
|
||||
AND company_code = $2
|
||||
|
|
@ -819,7 +878,7 @@ class TableCategoryValueService {
|
|||
if (companyCode === "*") {
|
||||
// 최고 관리자: 모든 카테고리 값 순서 변경 가능
|
||||
updateQuery = `
|
||||
UPDATE table_column_category_values
|
||||
UPDATE category_values
|
||||
SET value_order = $1, updated_at = NOW()
|
||||
WHERE value_id = $2
|
||||
`;
|
||||
|
|
@ -827,7 +886,7 @@ class TableCategoryValueService {
|
|||
} else {
|
||||
// 일반 회사: 자신의 카테고리 값만 순서 변경 가능
|
||||
updateQuery = `
|
||||
UPDATE table_column_category_values
|
||||
UPDATE category_values
|
||||
SET value_order = $1, updated_at = NOW()
|
||||
WHERE value_id = $2
|
||||
AND company_code = $3
|
||||
|
|
@ -1379,48 +1438,23 @@ class TableCategoryValueService {
|
|||
let query: string;
|
||||
let params: any[];
|
||||
|
||||
// is_active 필터 제거: 비활성화된 카테고리도 라벨로 표시되어야 함
|
||||
if (companyCode === "*") {
|
||||
// 최고 관리자: 두 테이블 모두에서 조회 (UNION으로 병합)
|
||||
// 두 번째 쿼리용 플레이스홀더: $n+1 ~ $2n
|
||||
const placeholders2 = valueCodes.map((_, i) => `$${n + i + 1}`).join(", ");
|
||||
query = `
|
||||
SELECT value_code, value_label FROM (
|
||||
SELECT value_code, value_label
|
||||
FROM table_column_category_values
|
||||
WHERE value_code IN (${placeholders1})
|
||||
AND is_active = true
|
||||
UNION ALL
|
||||
SELECT value_code, value_label
|
||||
FROM category_values
|
||||
WHERE value_code IN (${placeholders2})
|
||||
AND is_active = true
|
||||
) combined
|
||||
SELECT DISTINCT value_code, value_label
|
||||
FROM category_values
|
||||
WHERE value_code IN (${placeholders1})
|
||||
`;
|
||||
params = [...valueCodes, ...valueCodes];
|
||||
params = [...valueCodes];
|
||||
} else {
|
||||
// 일반 회사: 두 테이블에서 자신의 카테고리 값 + 공통 카테고리 값 조회
|
||||
// 첫 번째: $1~$n (valueCodes), $n+1 (companyCode)
|
||||
// 두 번째: $n+2~$2n+1 (valueCodes), $2n+2 (companyCode)
|
||||
const companyIdx1 = n + 1;
|
||||
const placeholders2 = valueCodes.map((_, i) => `$${n + 1 + i + 1}`).join(", ");
|
||||
const companyIdx2 = 2 * n + 2;
|
||||
|
||||
const companyIdx = n + 1;
|
||||
query = `
|
||||
SELECT value_code, value_label FROM (
|
||||
SELECT value_code, value_label
|
||||
FROM table_column_category_values
|
||||
WHERE value_code IN (${placeholders1})
|
||||
AND is_active = true
|
||||
AND (company_code = $${companyIdx1} OR company_code = '*')
|
||||
UNION ALL
|
||||
SELECT value_code, value_label
|
||||
FROM category_values
|
||||
WHERE value_code IN (${placeholders2})
|
||||
AND is_active = true
|
||||
AND (company_code = $${companyIdx2} OR company_code = '*')
|
||||
) combined
|
||||
SELECT DISTINCT value_code, value_label
|
||||
FROM category_values
|
||||
WHERE value_code IN (${placeholders1})
|
||||
AND (company_code = $${companyIdx} OR company_code = '*')
|
||||
`;
|
||||
params = [...valueCodes, companyCode, ...valueCodes, companyCode];
|
||||
params = [...valueCodes, companyCode];
|
||||
}
|
||||
|
||||
const result = await pool.query(query, params);
|
||||
|
|
@ -1488,7 +1522,7 @@ class TableCategoryValueService {
|
|||
// 최고 관리자: 모든 카테고리 값 조회
|
||||
query = `
|
||||
SELECT value_code, value_label
|
||||
FROM table_column_category_values
|
||||
FROM category_values
|
||||
WHERE table_name = $1
|
||||
AND column_name = $2
|
||||
AND is_active = true
|
||||
|
|
@ -1498,7 +1532,7 @@ class TableCategoryValueService {
|
|||
// 일반 회사: 자신의 카테고리 값 + 공통 카테고리 값 조회
|
||||
query = `
|
||||
SELECT value_code, value_label
|
||||
FROM table_column_category_values
|
||||
FROM category_values
|
||||
WHERE table_name = $1
|
||||
AND column_name = $2
|
||||
AND is_active = true
|
||||
|
|
|
|||
|
|
@ -3505,7 +3505,7 @@ export class TableManagementService {
|
|||
const referenceTableColumns = new Map<string, string[]>();
|
||||
const uniqueRefTables = new Set(
|
||||
joinConfigs
|
||||
.filter((c) => c.referenceTable !== "table_column_category_values") // 카테고리는 제외
|
||||
.filter((c) => c.referenceTable !== "category_values") // 카테고리는 제외
|
||||
.map((c) => `${c.referenceTable}:${c.sourceColumn}`)
|
||||
);
|
||||
|
||||
|
|
@ -4310,8 +4310,8 @@ export class TableManagementService {
|
|||
];
|
||||
|
||||
for (const config of joinConfigs) {
|
||||
// table_column_category_values는 특수 조인 조건이 필요하므로 항상 DB 조인
|
||||
if (config.referenceTable === "table_column_category_values") {
|
||||
// category_values는 특수 조인 조건이 필요하므로 항상 DB 조인
|
||||
if (config.referenceTable === "category_values") {
|
||||
dbJoins.push(config);
|
||||
console.log(`🔗 DB 조인 (특수 조건): ${config.referenceTable}`);
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -378,7 +378,7 @@ export const InteractiveDataTable: React.FC<InteractiveDataTableProps> = ({
|
|||
for (const col of categoryColumns) {
|
||||
try {
|
||||
// menuObjid가 있으면 쿼리 파라미터로 전달 (메뉴별 카테고리 색상 적용)
|
||||
const queryParams = menuObjid ? `?menuObjid=${menuObjid}` : "";
|
||||
const queryParams = menuObjid ? `?menuObjid=${menuObjid}&includeInactive=true` : "?includeInactive=true";
|
||||
const response = await apiClient.get(
|
||||
`/table-categories/${component.tableName}/${col.columnName}/values${queryParams}`,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -796,7 +796,7 @@ export const RepeaterInput: React.FC<RepeaterInputProps> = ({
|
|||
|
||||
console.log(`📡 [RepeaterInput] 카테고리 매핑 로드: ${tableName}/${columnName}`);
|
||||
|
||||
const response = await apiClient.get(`/table-categories/${tableName}/${columnName}/values`);
|
||||
const response = await apiClient.get(`/table-categories/${tableName}/${columnName}/values?includeInactive=true`);
|
||||
|
||||
if (response.data.success && response.data.data && Array.isArray(response.data.data)) {
|
||||
const mapping: Record<string, { label: string; color: string }> = {};
|
||||
|
|
@ -838,7 +838,7 @@ export const RepeaterInput: React.FC<RepeaterInputProps> = ({
|
|||
try {
|
||||
console.log(`📡 [RepeaterInput] 조인 테이블 카테고리 매핑 로드: ${joinedTableName}/${columnName}`);
|
||||
|
||||
const response = await apiClient.get(`/table-categories/${joinedTableName}/${columnName}/values`);
|
||||
const response = await apiClient.get(`/table-categories/${joinedTableName}/${columnName}/values?includeInactive=true`);
|
||||
|
||||
if (response.data.success && response.data.data && Array.isArray(response.data.data)) {
|
||||
const mapping: Record<string, { label: string; color: string }> = {};
|
||||
|
|
|
|||
|
|
@ -367,7 +367,7 @@ export const CardDisplayComponent: React.FC<CardDisplayComponentProps> = ({
|
|||
|
||||
for (const columnName of categoryColumns) {
|
||||
try {
|
||||
const response = await apiClient.get(`/table-categories/${tableNameToUse}/${columnName}/values`);
|
||||
const response = await apiClient.get(`/table-categories/${tableNameToUse}/${columnName}/values?includeInactive=true`);
|
||||
|
||||
|
||||
if (response.data.success && response.data.data) {
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ export function RepeaterTable({
|
|||
continue;
|
||||
}
|
||||
|
||||
const response = await apiClient.get(`/table-categories/${tableName}/${columnName}/values`);
|
||||
const response = await apiClient.get(`/table-categories/${tableName}/${columnName}/values?includeInactive=true`);
|
||||
|
||||
if (response.data?.success && response.data.data) {
|
||||
const options = response.data.data.map((item: any) => ({
|
||||
|
|
|
|||
|
|
@ -1588,7 +1588,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
|||
for (const col of categoryColumns) {
|
||||
const columnName = col.columnName || col.column_name;
|
||||
try {
|
||||
const response = await apiClient.get(`/table-categories/${leftTableName}/${columnName}/values`);
|
||||
const response = await apiClient.get(`/table-categories/${leftTableName}/${columnName}/values?includeInactive=true`);
|
||||
|
||||
if (response.data.success && response.data.data) {
|
||||
const valueMap: Record<string, { label: string; color?: string }> = {};
|
||||
|
|
@ -1650,7 +1650,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
|||
for (const col of categoryColumns) {
|
||||
const columnName = col.columnName || col.column_name;
|
||||
try {
|
||||
const response = await apiClient.get(`/table-categories/${tableName}/${columnName}/values`);
|
||||
const response = await apiClient.get(`/table-categories/${tableName}/${columnName}/values?includeInactive=true`);
|
||||
|
||||
if (response.data.success && response.data.data) {
|
||||
const valueMap: Record<string, { label: string; color?: string }> = {};
|
||||
|
|
|
|||
|
|
@ -1298,7 +1298,8 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
targetColumn = parts[1];
|
||||
}
|
||||
|
||||
const response = await apiClient.get(`/table-categories/${targetTable}/${targetColumn}/values`);
|
||||
// 비활성화된 카테고리도 라벨로 표시하기 위해 includeInactive=true
|
||||
const response = await apiClient.get(`/table-categories/${targetTable}/${targetColumn}/values?includeInactive=true`);
|
||||
|
||||
if (response.data.success && response.data.data && Array.isArray(response.data.data)) {
|
||||
const mapping: Record<string, { label: string; color?: string }> = {};
|
||||
|
|
@ -1381,7 +1382,7 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
// inputType이 category인 경우 카테고리 매핑 로드
|
||||
if (inputTypeInfo?.inputType === "category" && !mappings[col.columnName]) {
|
||||
try {
|
||||
const response = await apiClient.get(`/table-categories/${joinedTable}/${col.actualColumn}/values`);
|
||||
const response = await apiClient.get(`/table-categories/${joinedTable}/${col.actualColumn}/values?includeInactive=true`);
|
||||
|
||||
if (response.data.success && response.data.data && Array.isArray(response.data.data)) {
|
||||
const mapping: Record<string, { label: string; color?: string }> = {};
|
||||
|
|
|
|||
|
|
@ -1362,7 +1362,7 @@ export function UniversalFormModalComponent({
|
|||
label: String(row[optionConfig.labelColumn || "name"]),
|
||||
}));
|
||||
} else if (optionConfig.type === "code" && optionConfig.categoryKey) {
|
||||
// 공통코드(카테고리 컬럼): table_column_category_values 테이블에서 조회
|
||||
// 공통코드(카테고리 컬럼): category_values 테이블에서 조회
|
||||
// categoryKey 형식: "tableName.columnName"
|
||||
const [categoryTable, categoryColumn] = optionConfig.categoryKey.split(".");
|
||||
if (categoryTable && categoryColumn) {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ import {
|
|||
import { apiClient } from "@/lib/api/client";
|
||||
import { getCascadingRelations, getCascadingRelationByCode, CascadingRelation } from "@/lib/api/cascadingRelation";
|
||||
|
||||
// 카테고리 컬럼 타입 (table_column_category_values 용)
|
||||
// 카테고리 컬럼 타입 (category_values 용)
|
||||
interface CategoryColumnOption {
|
||||
tableName: string;
|
||||
columnName: string;
|
||||
|
|
|
|||
|
|
@ -2526,7 +2526,7 @@ interface TableSectionSettingsModalProps {
|
|||
tables: { table_name: string; comment?: string }[];
|
||||
tableColumns: Record<string, { column_name: string; data_type: string; is_nullable: string; comment?: string; input_type?: string }[]>;
|
||||
onLoadTableColumns: (tableName: string) => void;
|
||||
// 카테고리 목록 (table_column_category_values에서 가져옴)
|
||||
// 카테고리 목록 (category_values에서 가져옴)
|
||||
categoryList?: { tableName: string; columnName: string; displayName?: string }[];
|
||||
onLoadCategoryList?: () => void;
|
||||
// 전체 섹션 목록 (다른 섹션 필드 참조용)
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ export interface SelectOptionConfig {
|
|||
labelColumn?: string; // 표시할 컬럼 (화면에 보여줄 텍스트)
|
||||
saveColumn?: string; // 저장할 컬럼 (실제로 DB에 저장할 값, 미지정 시 valueColumn 사용)
|
||||
filterCondition?: string;
|
||||
// 카테고리 컬럼 기반 옵션 (table_column_category_values 테이블)
|
||||
// 카테고리 컬럼 기반 옵션 (category_values 테이블)
|
||||
// 형식: "tableName.columnName" (예: "sales_order_mng.incoterms")
|
||||
categoryKey?: string;
|
||||
|
||||
|
|
|
|||
|
|
@ -540,7 +540,7 @@ export function BomItemEditorComponent({
|
|||
if (alreadyLoaded) continue;
|
||||
|
||||
try {
|
||||
const response = await apiClient.get(`/table-categories/${mainTableName}/${col.key}/values`);
|
||||
const response = await apiClient.get(`/table-categories/${mainTableName}/${col.key}/values?includeInactive=true`);
|
||||
if (response.data?.success && response.data.data) {
|
||||
const options = response.data.data.map((item: any) => ({
|
||||
value: item.valueCode || item.value_code,
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ export function BomTreeComponent({
|
|||
useEffect(() => {
|
||||
const loadLabels = async () => {
|
||||
try {
|
||||
const res = await apiClient.get(`/table-categories/${detailTable}/process_type/values`);
|
||||
const res = await apiClient.get(`/table-categories/${detailTable}/process_type/values?includeInactive=true`);
|
||||
const vals = res.data?.data || [];
|
||||
if (vals.length > 0) {
|
||||
const map: Record<string, string> = {};
|
||||
|
|
|
|||
|
|
@ -367,7 +367,7 @@ export const CardDisplayComponent: React.FC<CardDisplayComponentProps> = ({
|
|||
|
||||
for (const columnName of categoryColumns) {
|
||||
try {
|
||||
const response = await apiClient.get(`/table-categories/${tableNameToUse}/${columnName}/values`);
|
||||
const response = await apiClient.get(`/table-categories/${tableNameToUse}/${columnName}/values?includeInactive=true`);
|
||||
|
||||
|
||||
if (response.data.success && response.data.data) {
|
||||
|
|
|
|||
|
|
@ -1894,7 +1894,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
|||
for (const col of categoryColumns) {
|
||||
const columnName = col.columnName || col.column_name;
|
||||
try {
|
||||
const response = await apiClient.get(`/table-categories/${leftTableName}/${columnName}/values`);
|
||||
const response = await apiClient.get(`/table-categories/${leftTableName}/${columnName}/values?includeInactive=true`);
|
||||
|
||||
if (response.data.success && response.data.data) {
|
||||
const valueMap: Record<string, { label: string; color?: string }> = {};
|
||||
|
|
@ -1972,7 +1972,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
|||
for (const col of categoryColumns) {
|
||||
const columnName = col.columnName || col.column_name;
|
||||
try {
|
||||
const response = await apiClient.get(`/table-categories/${tableName}/${columnName}/values`);
|
||||
const response = await apiClient.get(`/table-categories/${tableName}/${columnName}/values?includeInactive=true`);
|
||||
|
||||
if (response.data.success && response.data.data) {
|
||||
const valueMap: Record<string, { label: string; color?: string }> = {};
|
||||
|
|
|
|||
|
|
@ -1441,7 +1441,8 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
targetColumn = parts[1];
|
||||
}
|
||||
|
||||
const response = await apiClient.get(`/table-categories/${targetTable}/${targetColumn}/values`);
|
||||
// 비활성화된 카테고리도 라벨로 표시하기 위해 includeInactive=true
|
||||
const response = await apiClient.get(`/table-categories/${targetTable}/${targetColumn}/values?includeInactive=true`);
|
||||
|
||||
if (response.data.success && response.data.data && Array.isArray(response.data.data)) {
|
||||
const mapping: Record<string, { label: string; color?: string }> = {};
|
||||
|
|
@ -1524,7 +1525,7 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
// inputType이 category인 경우 카테고리 매핑 로드
|
||||
if (inputTypeInfo?.inputType === "category" && !mappings[col.columnName]) {
|
||||
try {
|
||||
const response = await apiClient.get(`/table-categories/${joinedTable}/${col.actualColumn}/values`);
|
||||
const response = await apiClient.get(`/table-categories/${joinedTable}/${col.actualColumn}/values?includeInactive=true`);
|
||||
|
||||
if (response.data.success && response.data.data && Array.isArray(response.data.data)) {
|
||||
const mapping: Record<string, { label: string; color?: string }> = {};
|
||||
|
|
|
|||
Loading…
Reference in New Issue