다국어 관리 페이지
This commit is contained in:
parent
6cac3dfa3f
commit
96c601a0cf
|
|
@ -665,7 +665,7 @@ export async function getLanguageList(
|
|||
}
|
||||
|
||||
/**
|
||||
* 다국어 키 목록 조회 (더미 데이터)
|
||||
* 다국어 키 목록 조회
|
||||
*/
|
||||
export async function getLangKeyList(
|
||||
req: AuthenticatedRequest,
|
||||
|
|
@ -677,59 +677,61 @@ export async function getLangKeyList(
|
|||
user: req.user,
|
||||
});
|
||||
|
||||
// 더미 데이터 반환
|
||||
const langKeys = [
|
||||
{
|
||||
keyId: 1,
|
||||
companyCode: "ILSHIN",
|
||||
menuName: "사용자 관리",
|
||||
langKey: "user.management.title",
|
||||
description: "사용자 관리 페이지 제목",
|
||||
isActive: "Y",
|
||||
createdDate: new Date().toISOString(),
|
||||
createdBy: "admin",
|
||||
updatedDate: new Date().toISOString(),
|
||||
updatedBy: "admin",
|
||||
},
|
||||
{
|
||||
keyId: 2,
|
||||
companyCode: "ILSHIN",
|
||||
menuName: "메뉴 관리",
|
||||
langKey: "menu.management.title",
|
||||
description: "메뉴 관리 페이지 제목",
|
||||
isActive: "Y",
|
||||
createdDate: new Date().toISOString(),
|
||||
createdBy: "admin",
|
||||
updatedDate: new Date().toISOString(),
|
||||
updatedBy: "admin",
|
||||
},
|
||||
{
|
||||
keyId: 3,
|
||||
companyCode: "HUTECH",
|
||||
menuName: "대시보드",
|
||||
langKey: "dashboard.title",
|
||||
description: "대시보드 페이지 제목",
|
||||
isActive: "Y",
|
||||
createdDate: new Date().toISOString(),
|
||||
createdBy: "admin",
|
||||
updatedDate: new Date().toISOString(),
|
||||
updatedBy: "admin",
|
||||
},
|
||||
];
|
||||
|
||||
// 프론트엔드에서 기대하는 응답 형식으로 변환
|
||||
const response: ApiResponse<any[]> = {
|
||||
success: true,
|
||||
message: "다국어 키 목록 조회 성공",
|
||||
data: langKeys,
|
||||
};
|
||||
|
||||
logger.info("다국어 키 목록 조회 성공", {
|
||||
totalCount: langKeys.length,
|
||||
response: response,
|
||||
// 실제 데이터베이스에서 데이터 조회
|
||||
const client = new Client({
|
||||
host: process.env.DB_HOST || "localhost",
|
||||
port: parseInt(process.env.DB_PORT || "5432"),
|
||||
database: process.env.DB_NAME || "ilshin",
|
||||
user: process.env.DB_USER || "postgres",
|
||||
password: process.env.DB_PASSWORD || "postgres",
|
||||
});
|
||||
|
||||
res.status(200).json(response);
|
||||
await client.connect();
|
||||
|
||||
try {
|
||||
const query = `
|
||||
SELECT
|
||||
key_id as "keyId",
|
||||
company_code as "companyCode",
|
||||
menu_name as "menuName",
|
||||
lang_key as "langKey",
|
||||
description,
|
||||
is_active as "isActive",
|
||||
created_date as "createdDate",
|
||||
created_by as "createdBy",
|
||||
updated_date as "updatedDate",
|
||||
updated_by as "updatedBy"
|
||||
FROM multi_lang_key_master
|
||||
ORDER BY company_code, menu_name, lang_key
|
||||
`;
|
||||
|
||||
const result = await client.query(query);
|
||||
const langKeys = result.rows.map((row) => ({
|
||||
...row,
|
||||
createdDate: row.createdDate
|
||||
? new Date(row.createdDate).toISOString()
|
||||
: undefined,
|
||||
updatedDate: row.updatedDate
|
||||
? new Date(row.updatedDate).toISOString()
|
||||
: undefined,
|
||||
}));
|
||||
|
||||
// 프론트엔드에서 기대하는 응답 형식으로 변환
|
||||
const response: ApiResponse<any[]> = {
|
||||
success: true,
|
||||
message: "다국어 키 목록 조회 성공",
|
||||
data: langKeys,
|
||||
};
|
||||
|
||||
logger.info("다국어 키 목록 조회 성공", {
|
||||
totalCount: langKeys.length,
|
||||
response: response,
|
||||
});
|
||||
|
||||
res.status(200).json(response);
|
||||
} finally {
|
||||
await client.end();
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error("다국어 키 목록 조회 실패:", error);
|
||||
res.status(500).json({
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -19,17 +19,6 @@ import {
|
|||
deleteCompany, // 회사 삭제
|
||||
getUserLocale,
|
||||
setUserLocale,
|
||||
getLanguageList,
|
||||
getLangKeyList,
|
||||
getLangTextList,
|
||||
saveLangTexts,
|
||||
saveLangKey,
|
||||
updateLangKey,
|
||||
deleteLangKey,
|
||||
toggleLangKeyStatus,
|
||||
saveLanguage,
|
||||
updateLanguage,
|
||||
toggleLanguageStatus,
|
||||
} from "../controllers/adminController";
|
||||
import { authenticateToken } from "../middleware/authMiddleware";
|
||||
|
||||
|
|
@ -67,17 +56,4 @@ router.delete("/companies/:companyCode", deleteCompany); // 회사 삭제
|
|||
router.get("/user-locale", getUserLocale);
|
||||
router.post("/user-locale", setUserLocale);
|
||||
|
||||
// 다국어 관리 API
|
||||
router.get("/multilang/languages", getLanguageList);
|
||||
router.get("/multilang/keys", getLangKeyList);
|
||||
router.get("/multilang/keys/:keyId/texts", getLangTextList);
|
||||
router.post("/multilang/keys/:keyId/texts", saveLangTexts);
|
||||
router.post("/multilang/keys", saveLangKey);
|
||||
router.put("/multilang/keys/:keyId", updateLangKey);
|
||||
router.delete("/multilang/keys/:keyId", deleteLangKey);
|
||||
router.put("/multilang/keys/:keyId/toggle", toggleLangKeyStatus);
|
||||
router.post("/multilang/languages", saveLanguage);
|
||||
router.put("/multilang/languages/:langCode", updateLanguage);
|
||||
router.put("/multilang/languages/:langCode/toggle", toggleLanguageStatus);
|
||||
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -1,23 +1,50 @@
|
|||
import { Router } from "express";
|
||||
import {
|
||||
getUserText,
|
||||
getBatchTranslations,
|
||||
clearCache,
|
||||
} from "../controllers/multilangController";
|
||||
import express from "express";
|
||||
import { authenticateToken } from "../middleware/authMiddleware";
|
||||
import {
|
||||
// 언어 관리 API
|
||||
getLanguages,
|
||||
createLanguage,
|
||||
updateLanguage,
|
||||
toggleLanguage,
|
||||
|
||||
const router = Router();
|
||||
// 다국어 키 관리 API
|
||||
getLangKeys,
|
||||
getLangTexts,
|
||||
createLangKey,
|
||||
updateLangKey,
|
||||
deleteLangKey,
|
||||
toggleLangKey,
|
||||
|
||||
// 모든 multilang 라우트에 인증 미들웨어 적용
|
||||
// 다국어 텍스트 관리 API
|
||||
saveLangTexts,
|
||||
getUserText,
|
||||
getLangText,
|
||||
getBatchTranslations,
|
||||
} from "../controllers/multilangController";
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// 모든 다국어 관리 라우트에 인증 미들웨어 적용
|
||||
router.use(authenticateToken);
|
||||
|
||||
// 다국어 텍스트 API
|
||||
router.get("/user-text/:companyCode/:menuCode/:langKey", getUserText);
|
||||
// 언어 관리 API
|
||||
router.get("/languages", getLanguages); // 언어 목록 조회
|
||||
router.post("/languages", createLanguage); // 언어 생성
|
||||
router.put("/languages/:langCode", updateLanguage); // 언어 수정
|
||||
router.put("/languages/:langCode/toggle", toggleLanguage); // 언어 상태 토글
|
||||
|
||||
// 다국어 텍스트 배치 조회 API (새로운 방식)
|
||||
router.post("/batch", getBatchTranslations);
|
||||
// 다국어 키 관리 API
|
||||
router.get("/keys", getLangKeys); // 다국어 키 목록 조회
|
||||
router.get("/keys/:keyId/texts", getLangTexts); // 특정 키의 다국어 텍스트 조회
|
||||
router.post("/keys", createLangKey); // 다국어 키 생성
|
||||
router.put("/keys/:keyId", updateLangKey); // 다국어 키 수정
|
||||
router.delete("/keys/:keyId", deleteLangKey); // 다국어 키 삭제
|
||||
router.put("/keys/:keyId/toggle", toggleLangKey); // 다국어 키 상태 토글
|
||||
|
||||
// 캐시 초기화 API (개발/테스트용)
|
||||
router.delete("/cache", clearCache);
|
||||
// 다국어 텍스트 관리 API
|
||||
router.post("/keys/:keyId/texts", saveLangTexts); // 다국어 텍스트 저장/수정
|
||||
router.get("/user-text/:companyCode/:menuCode/:langKey", getUserText); // 사용자별 다국어 텍스트 조회
|
||||
router.get("/text/:companyCode/:langKey/:langCode", getLangText); // 특정 키의 다국어 텍스트 조회
|
||||
router.post("/batch", getBatchTranslations); // 다국어 텍스트 배치 조회
|
||||
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,855 @@
|
|||
import { Client } from "pg";
|
||||
import { logger } from "../utils/logger";
|
||||
import {
|
||||
Language,
|
||||
LangKey,
|
||||
LangText,
|
||||
CreateLanguageRequest,
|
||||
UpdateLanguageRequest,
|
||||
CreateLangKeyRequest,
|
||||
UpdateLangKeyRequest,
|
||||
SaveLangTextsRequest,
|
||||
GetLangKeysParams,
|
||||
GetUserTextParams,
|
||||
BatchTranslationRequest,
|
||||
ApiResponse,
|
||||
} from "../types/multilang";
|
||||
|
||||
export class MultiLangService {
|
||||
private client: Client;
|
||||
|
||||
constructor(client: Client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
/**
|
||||
* 언어 목록 조회
|
||||
*/
|
||||
async getLanguages(): Promise<Language[]> {
|
||||
try {
|
||||
logger.info("언어 목록 조회 시작");
|
||||
|
||||
const query = `
|
||||
SELECT
|
||||
lang_code as "langCode",
|
||||
lang_name as "langName",
|
||||
lang_native as "langNative",
|
||||
is_active as "isActive",
|
||||
sort_order as "sortOrder",
|
||||
created_date as "createdDate",
|
||||
created_by as "createdBy",
|
||||
updated_date as "updatedDate",
|
||||
updated_by as "updatedBy"
|
||||
FROM language_master
|
||||
ORDER BY sort_order, lang_code
|
||||
`;
|
||||
|
||||
const result = await this.client.query(query);
|
||||
const languages = result.rows.map((row) => ({
|
||||
...row,
|
||||
createdDate: row.createdDate ? new Date(row.createdDate) : undefined,
|
||||
updatedDate: row.updatedDate ? new Date(row.updatedDate) : undefined,
|
||||
}));
|
||||
|
||||
logger.info(`언어 목록 조회 완료: ${languages.length}개`);
|
||||
return languages;
|
||||
} catch (error) {
|
||||
logger.error("언어 목록 조회 중 오류 발생:", error);
|
||||
throw new Error(
|
||||
`언어 목록 조회 실패: ${error instanceof Error ? error.message : "Unknown error"}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 언어 생성
|
||||
*/
|
||||
async createLanguage(languageData: CreateLanguageRequest): Promise<Language> {
|
||||
try {
|
||||
logger.info("언어 생성 시작", { languageData });
|
||||
|
||||
// 중복 체크
|
||||
const duplicateCheckQuery = `
|
||||
SELECT lang_code FROM language_master WHERE lang_code = $1
|
||||
`;
|
||||
const duplicateResult = await this.client.query(duplicateCheckQuery, [
|
||||
languageData.langCode,
|
||||
]);
|
||||
|
||||
if (duplicateResult.rows.length > 0) {
|
||||
throw new Error(
|
||||
`이미 존재하는 언어 코드입니다: ${languageData.langCode}`
|
||||
);
|
||||
}
|
||||
|
||||
// 언어 생성
|
||||
const insertQuery = `
|
||||
INSERT INTO language_master (
|
||||
lang_code, lang_name, lang_native, is_active, sort_order,
|
||||
created_date, created_by, updated_date, updated_by
|
||||
) VALUES ($1, $2, $3, $4, $5, now(), $6, now(), $7)
|
||||
RETURNING *
|
||||
`;
|
||||
|
||||
const insertValues = [
|
||||
languageData.langCode,
|
||||
languageData.langName,
|
||||
languageData.langNative,
|
||||
languageData.isActive || "Y",
|
||||
languageData.sortOrder || 0,
|
||||
languageData.createdBy || "system",
|
||||
languageData.updatedBy || "system",
|
||||
];
|
||||
|
||||
const result = await this.client.query(insertQuery, insertValues);
|
||||
const createdLanguage = result.rows[0];
|
||||
|
||||
logger.info("언어 생성 완료", { langCode: createdLanguage.lang_code });
|
||||
|
||||
return {
|
||||
langCode: createdLanguage.lang_code,
|
||||
langName: createdLanguage.lang_name,
|
||||
langNative: createdLanguage.lang_native,
|
||||
isActive: createdLanguage.is_active,
|
||||
sortOrder: createdLanguage.sort_order,
|
||||
createdDate: createdLanguage.created_date
|
||||
? new Date(createdLanguage.created_date)
|
||||
: undefined,
|
||||
createdBy: createdLanguage.created_by,
|
||||
updatedDate: createdLanguage.updated_date
|
||||
? new Date(createdLanguage.updated_date)
|
||||
: undefined,
|
||||
updatedBy: createdLanguage.updated_by,
|
||||
};
|
||||
} catch (error) {
|
||||
logger.error("언어 생성 중 오류 발생:", error);
|
||||
throw new Error(
|
||||
`언어 생성 실패: ${error instanceof Error ? error.message : "Unknown error"}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 언어 수정
|
||||
*/
|
||||
async updateLanguage(
|
||||
langCode: string,
|
||||
languageData: UpdateLanguageRequest
|
||||
): Promise<Language> {
|
||||
try {
|
||||
logger.info("언어 수정 시작", { langCode, languageData });
|
||||
|
||||
// 기존 언어 확인
|
||||
const checkQuery = `
|
||||
SELECT * FROM language_master WHERE lang_code = $1
|
||||
`;
|
||||
const checkResult = await this.client.query(checkQuery, [langCode]);
|
||||
|
||||
if (checkResult.rows.length === 0) {
|
||||
throw new Error(`언어를 찾을 수 없습니다: ${langCode}`);
|
||||
}
|
||||
|
||||
// 언어 수정
|
||||
const updateQuery = `
|
||||
UPDATE language_master
|
||||
SET
|
||||
lang_name = COALESCE($2, lang_name),
|
||||
lang_native = COALESCE($3, lang_native),
|
||||
is_active = COALESCE($4, is_active),
|
||||
sort_order = COALESCE($5, sort_order),
|
||||
updated_date = now(),
|
||||
updated_by = $6
|
||||
WHERE lang_code = $1
|
||||
RETURNING *
|
||||
`;
|
||||
|
||||
const updateValues = [
|
||||
langCode,
|
||||
languageData.langName,
|
||||
languageData.langNative,
|
||||
languageData.isActive,
|
||||
languageData.sortOrder,
|
||||
languageData.updatedBy || "system",
|
||||
];
|
||||
|
||||
const result = await this.client.query(updateQuery, updateValues);
|
||||
const updatedLanguage = result.rows[0];
|
||||
|
||||
logger.info("언어 수정 완료", { langCode });
|
||||
|
||||
return {
|
||||
langCode: updatedLanguage.lang_code,
|
||||
langName: updatedLanguage.lang_name,
|
||||
langNative: updatedLanguage.lang_native,
|
||||
isActive: updatedLanguage.is_active,
|
||||
sortOrder: updatedLanguage.sort_order,
|
||||
createdDate: updatedLanguage.created_date
|
||||
? new Date(updatedLanguage.created_date)
|
||||
: undefined,
|
||||
createdBy: updatedLanguage.created_by,
|
||||
updatedDate: updatedLanguage.updated_date
|
||||
? new Date(updatedLanguage.updated_date)
|
||||
: undefined,
|
||||
updatedBy: updatedLanguage.updated_by,
|
||||
};
|
||||
} catch (error) {
|
||||
logger.error("언어 수정 중 오류 발생:", error);
|
||||
throw new Error(
|
||||
`언어 수정 실패: ${error instanceof Error ? error.message : "Unknown error"}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 언어 상태 토글
|
||||
*/
|
||||
async toggleLanguage(langCode: string): Promise<string> {
|
||||
try {
|
||||
logger.info("언어 상태 토글 시작", { langCode });
|
||||
|
||||
// 현재 상태 조회
|
||||
const currentQuery = `
|
||||
SELECT is_active FROM language_master WHERE lang_code = $1
|
||||
`;
|
||||
const currentResult = await this.client.query(currentQuery, [langCode]);
|
||||
|
||||
if (currentResult.rows.length === 0) {
|
||||
throw new Error(`언어를 찾을 수 없습니다: ${langCode}`);
|
||||
}
|
||||
|
||||
const currentStatus = currentResult.rows[0].is_active;
|
||||
const newStatus = currentStatus === "Y" ? "N" : "Y";
|
||||
|
||||
// 상태 업데이트
|
||||
const updateQuery = `
|
||||
UPDATE language_master
|
||||
SET is_active = $2, updated_date = now(), updated_by = 'system'
|
||||
WHERE lang_code = $1
|
||||
`;
|
||||
|
||||
await this.client.query(updateQuery, [langCode, newStatus]);
|
||||
|
||||
const result = newStatus === "Y" ? "활성화" : "비활성화";
|
||||
logger.info("언어 상태 토글 완료", { langCode, result });
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
logger.error("언어 상태 토글 중 오류 발생:", error);
|
||||
throw new Error(
|
||||
`언어 상태 토글 실패: ${error instanceof Error ? error.message : "Unknown error"}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 다국어 키 목록 조회
|
||||
*/
|
||||
async getLangKeys(params: GetLangKeysParams): Promise<LangKey[]> {
|
||||
try {
|
||||
logger.info("다국어 키 목록 조회 시작", { params });
|
||||
|
||||
let query = `
|
||||
SELECT
|
||||
key_id as "keyId",
|
||||
company_code as "companyCode",
|
||||
menu_name as "menuName",
|
||||
lang_key as "langKey",
|
||||
description,
|
||||
is_active as "isActive",
|
||||
created_date as "createdDate",
|
||||
created_by as "createdBy",
|
||||
updated_date as "updatedDate",
|
||||
updated_by as "updatedBy"
|
||||
FROM multi_lang_key_master
|
||||
WHERE 1=1
|
||||
`;
|
||||
|
||||
const queryParams: any[] = [];
|
||||
let paramIndex = 1;
|
||||
|
||||
// 회사 코드 필터
|
||||
if (params.companyCode) {
|
||||
query += ` AND company_code = $${paramIndex}`;
|
||||
queryParams.push(params.companyCode);
|
||||
paramIndex++;
|
||||
}
|
||||
|
||||
// 메뉴 코드 필터
|
||||
if (params.menuCode) {
|
||||
query += ` AND menu_name = $${paramIndex}`;
|
||||
queryParams.push(params.menuCode);
|
||||
paramIndex++;
|
||||
}
|
||||
|
||||
// 검색 조건
|
||||
if (params.searchText) {
|
||||
query += ` AND (
|
||||
lang_key ILIKE $${paramIndex} OR
|
||||
description ILIKE $${paramIndex} OR
|
||||
menu_name ILIKE $${paramIndex}
|
||||
)`;
|
||||
queryParams.push(`%${params.searchText}%`);
|
||||
paramIndex++;
|
||||
}
|
||||
|
||||
// 정렬
|
||||
query += ` ORDER BY company_code, menu_name, lang_key`;
|
||||
|
||||
const result = await this.client.query(query, queryParams);
|
||||
const langKeys = result.rows.map((row) => ({
|
||||
...row,
|
||||
createdDate: row.createdDate ? new Date(row.createdDate) : undefined,
|
||||
updatedDate: row.updatedDate ? new Date(row.updatedDate) : undefined,
|
||||
}));
|
||||
|
||||
logger.info(`다국어 키 목록 조회 완료: ${langKeys.length}개`);
|
||||
return langKeys;
|
||||
} catch (error) {
|
||||
logger.error("다국어 키 목록 조회 중 오류 발생:", error);
|
||||
throw new Error(
|
||||
`다국어 키 목록 조회 실패: ${error instanceof Error ? error.message : "Unknown error"}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 특정 키의 다국어 텍스트 조회
|
||||
*/
|
||||
async getLangTexts(keyId: number): Promise<LangText[]> {
|
||||
try {
|
||||
logger.info("다국어 텍스트 조회 시작", { keyId });
|
||||
|
||||
const query = `
|
||||
SELECT
|
||||
text_id as "textId",
|
||||
key_id as "keyId",
|
||||
lang_code as "langCode",
|
||||
lang_text as "langText",
|
||||
is_active as "isActive",
|
||||
created_date as "createdDate",
|
||||
created_by as "createdBy",
|
||||
updated_date as "updatedDate",
|
||||
updated_by as "updatedBy"
|
||||
FROM multi_lang_text
|
||||
WHERE key_id = $1 AND is_active = 'Y'
|
||||
ORDER BY lang_code
|
||||
`;
|
||||
|
||||
const result = await this.client.query(query, [keyId]);
|
||||
const langTexts = result.rows.map((row) => ({
|
||||
...row,
|
||||
createdDate: row.createdDate ? new Date(row.createdDate) : undefined,
|
||||
updatedDate: row.updatedDate ? new Date(row.updatedDate) : undefined,
|
||||
}));
|
||||
|
||||
logger.info(`다국어 텍스트 조회 완료: ${langTexts.length}개`);
|
||||
return langTexts;
|
||||
} catch (error) {
|
||||
logger.error("다국어 텍스트 조회 중 오류 발생:", error);
|
||||
throw new Error(
|
||||
`다국어 텍스트 조회 실패: ${error instanceof Error ? error.message : "Unknown error"}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 다국어 키 생성
|
||||
*/
|
||||
async createLangKey(keyData: CreateLangKeyRequest): Promise<number> {
|
||||
try {
|
||||
logger.info("다국어 키 생성 시작", { keyData });
|
||||
|
||||
// 중복 체크
|
||||
const duplicateCheckQuery = `
|
||||
SELECT key_id FROM multi_lang_key_master
|
||||
WHERE company_code = $1 AND lang_key = $2
|
||||
`;
|
||||
const duplicateResult = await this.client.query(duplicateCheckQuery, [
|
||||
keyData.companyCode,
|
||||
keyData.langKey,
|
||||
]);
|
||||
|
||||
if (duplicateResult.rows.length > 0) {
|
||||
throw new Error(
|
||||
`동일한 회사에 이미 존재하는 언어키입니다: ${keyData.langKey}`
|
||||
);
|
||||
}
|
||||
|
||||
// 다국어 키 생성
|
||||
const insertQuery = `
|
||||
INSERT INTO multi_lang_key_master (
|
||||
company_code, menu_name, lang_key, description, is_active,
|
||||
created_date, created_by, updated_date, updated_by
|
||||
) VALUES ($1, $2, $3, $4, $5, now(), $6, now(), $7)
|
||||
RETURNING key_id
|
||||
`;
|
||||
|
||||
const insertValues = [
|
||||
keyData.companyCode,
|
||||
keyData.menuName || null,
|
||||
keyData.langKey,
|
||||
keyData.description || null,
|
||||
keyData.isActive || "Y",
|
||||
keyData.createdBy || "system",
|
||||
keyData.updatedBy || "system",
|
||||
];
|
||||
|
||||
const result = await this.client.query(insertQuery, insertValues);
|
||||
const keyId = result.rows[0].key_id;
|
||||
|
||||
logger.info("다국어 키 생성 완료", { keyId, langKey: keyData.langKey });
|
||||
|
||||
return keyId;
|
||||
} catch (error) {
|
||||
logger.error("다국어 키 생성 중 오류 발생:", error);
|
||||
throw new Error(
|
||||
`다국어 키 생성 실패: ${error instanceof Error ? error.message : "Unknown error"}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 다국어 키 수정
|
||||
*/
|
||||
async updateLangKey(
|
||||
keyId: number,
|
||||
keyData: UpdateLangKeyRequest
|
||||
): Promise<void> {
|
||||
try {
|
||||
logger.info("다국어 키 수정 시작", { keyId, keyData });
|
||||
|
||||
// 기존 키 확인
|
||||
const checkQuery = `
|
||||
SELECT key_id FROM multi_lang_key_master WHERE key_id = $1
|
||||
`;
|
||||
const checkResult = await this.client.query(checkQuery, [keyId]);
|
||||
|
||||
if (checkResult.rows.length === 0) {
|
||||
throw new Error(`다국어 키를 찾을 수 없습니다: ${keyId}`);
|
||||
}
|
||||
|
||||
// 중복 체크 (자신을 제외하고)
|
||||
if (keyData.companyCode && keyData.langKey) {
|
||||
const duplicateCheckQuery = `
|
||||
SELECT key_id FROM multi_lang_key_master
|
||||
WHERE company_code = $1 AND lang_key = $2 AND key_id != $3
|
||||
`;
|
||||
const duplicateResult = await this.client.query(duplicateCheckQuery, [
|
||||
keyData.companyCode,
|
||||
keyData.langKey,
|
||||
keyId,
|
||||
]);
|
||||
|
||||
if (duplicateResult.rows.length > 0) {
|
||||
throw new Error(
|
||||
`동일한 회사에 이미 존재하는 언어키입니다: ${keyData.langKey}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 다국어 키 수정
|
||||
const updateQuery = `
|
||||
UPDATE multi_lang_key_master
|
||||
SET
|
||||
company_code = COALESCE($2, company_code),
|
||||
menu_name = COALESCE($3, menu_name),
|
||||
lang_key = COALESCE($4, lang_key),
|
||||
description = COALESCE($5, description),
|
||||
updated_date = now(),
|
||||
updated_by = $6
|
||||
WHERE key_id = $1
|
||||
`;
|
||||
|
||||
const updateValues = [
|
||||
keyId,
|
||||
keyData.companyCode,
|
||||
keyData.menuName,
|
||||
keyData.langKey,
|
||||
keyData.description,
|
||||
keyData.updatedBy || "system",
|
||||
];
|
||||
|
||||
await this.client.query(updateQuery, updateValues);
|
||||
|
||||
logger.info("다국어 키 수정 완료", { keyId });
|
||||
} catch (error) {
|
||||
logger.error("다국어 키 수정 중 오류 발생:", error);
|
||||
throw new Error(
|
||||
`다국어 키 수정 실패: ${error instanceof Error ? error.message : "Unknown error"}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 다국어 키 삭제
|
||||
*/
|
||||
async deleteLangKey(keyId: number): Promise<void> {
|
||||
try {
|
||||
logger.info("다국어 키 삭제 시작", { keyId });
|
||||
|
||||
// 기존 키 확인
|
||||
const checkQuery = `
|
||||
SELECT key_id FROM multi_lang_key_master WHERE key_id = $1
|
||||
`;
|
||||
const checkResult = await this.client.query(checkQuery, [keyId]);
|
||||
|
||||
if (checkResult.rows.length === 0) {
|
||||
throw new Error(`다국어 키를 찾을 수 없습니다: ${keyId}`);
|
||||
}
|
||||
|
||||
// 트랜잭션 시작
|
||||
await this.client.query("BEGIN");
|
||||
|
||||
try {
|
||||
// 관련된 다국어 텍스트 삭제
|
||||
const deleteTextsQuery = `
|
||||
DELETE FROM multi_lang_text WHERE key_id = $1
|
||||
`;
|
||||
await this.client.query(deleteTextsQuery, [keyId]);
|
||||
|
||||
// 다국어 키 삭제
|
||||
const deleteKeyQuery = `
|
||||
DELETE FROM multi_lang_key_master WHERE key_id = $1
|
||||
`;
|
||||
await this.client.query(deleteKeyQuery, [keyId]);
|
||||
|
||||
// 트랜잭션 커밋
|
||||
await this.client.query("COMMIT");
|
||||
|
||||
logger.info("다국어 키 삭제 완료", { keyId });
|
||||
} catch (error) {
|
||||
// 트랜잭션 롤백
|
||||
await this.client.query("ROLLBACK");
|
||||
throw error;
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error("다국어 키 삭제 중 오류 발생:", error);
|
||||
throw new Error(
|
||||
`다국어 키 삭제 실패: ${error instanceof Error ? error.message : "Unknown error"}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 다국어 키 상태 토글
|
||||
*/
|
||||
async toggleLangKey(keyId: number): Promise<string> {
|
||||
try {
|
||||
logger.info("다국어 키 상태 토글 시작", { keyId });
|
||||
|
||||
// 현재 상태 조회
|
||||
const currentQuery = `
|
||||
SELECT is_active FROM multi_lang_key_master WHERE key_id = $1
|
||||
`;
|
||||
const currentResult = await this.client.query(currentQuery, [keyId]);
|
||||
|
||||
if (currentResult.rows.length === 0) {
|
||||
throw new Error(`다국어 키를 찾을 수 없습니다: ${keyId}`);
|
||||
}
|
||||
|
||||
const currentStatus = currentResult.rows[0].is_active;
|
||||
const newStatus = currentStatus === "Y" ? "N" : "Y";
|
||||
|
||||
// 상태 업데이트
|
||||
const updateQuery = `
|
||||
UPDATE multi_lang_key_master
|
||||
SET is_active = $2, updated_date = now(), updated_by = 'system'
|
||||
WHERE key_id = $1
|
||||
`;
|
||||
|
||||
await this.client.query(updateQuery, [keyId, newStatus]);
|
||||
|
||||
const result = newStatus === "Y" ? "활성화" : "비활성화";
|
||||
logger.info("다국어 키 상태 토글 완료", { keyId, result });
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
logger.error("다국어 키 상태 토글 중 오류 발생:", error);
|
||||
throw new Error(
|
||||
`다국어 키 상태 토글 실패: ${error instanceof Error ? error.message : "Unknown error"}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 다국어 텍스트 저장/수정
|
||||
*/
|
||||
async saveLangTexts(
|
||||
keyId: number,
|
||||
textData: SaveLangTextsRequest
|
||||
): Promise<void> {
|
||||
try {
|
||||
logger.info("다국어 텍스트 저장 시작", {
|
||||
keyId,
|
||||
textCount: textData.texts.length,
|
||||
});
|
||||
|
||||
// 기존 키 확인
|
||||
const checkQuery = `
|
||||
SELECT key_id FROM multi_lang_key_master WHERE key_id = $1
|
||||
`;
|
||||
const checkResult = await this.client.query(checkQuery, [keyId]);
|
||||
|
||||
if (checkResult.rows.length === 0) {
|
||||
throw new Error(`다국어 키를 찾을 수 없습니다: ${keyId}`);
|
||||
}
|
||||
|
||||
// 트랜잭션 시작
|
||||
await this.client.query("BEGIN");
|
||||
|
||||
try {
|
||||
// 기존 텍스트 삭제
|
||||
const deleteTextsQuery = `
|
||||
DELETE FROM multi_lang_text WHERE key_id = $1
|
||||
`;
|
||||
await this.client.query(deleteTextsQuery, [keyId]);
|
||||
|
||||
// 새로운 텍스트 삽입
|
||||
for (const text of textData.texts) {
|
||||
const insertTextQuery = `
|
||||
INSERT INTO multi_lang_text (
|
||||
key_id, lang_code, lang_text, is_active,
|
||||
created_date, created_by, updated_date, updated_by
|
||||
) VALUES ($1, $2, $3, $4, now(), $5, now(), $6)
|
||||
`;
|
||||
|
||||
const insertValues = [
|
||||
keyId,
|
||||
text.langCode,
|
||||
text.langText,
|
||||
text.isActive || "Y",
|
||||
text.createdBy || "system",
|
||||
text.updatedBy || "system",
|
||||
];
|
||||
|
||||
await this.client.query(insertTextQuery, insertValues);
|
||||
}
|
||||
|
||||
// 트랜잭션 커밋
|
||||
await this.client.query("COMMIT");
|
||||
|
||||
logger.info("다국어 텍스트 저장 완료", {
|
||||
keyId,
|
||||
savedCount: textData.texts.length,
|
||||
});
|
||||
} catch (error) {
|
||||
// 트랜잭션 롤백
|
||||
await this.client.query("ROLLBACK");
|
||||
throw error;
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error("다국어 텍스트 저장 중 오류 발생:", error);
|
||||
throw new Error(
|
||||
`다국어 텍스트 저장 실패: ${error instanceof Error ? error.message : "Unknown error"}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자별 다국어 텍스트 조회
|
||||
*/
|
||||
async getUserText(params: GetUserTextParams): Promise<string> {
|
||||
try {
|
||||
logger.info("사용자별 다국어 텍스트 조회 시작", { params });
|
||||
|
||||
const query = `
|
||||
SELECT t.lang_text as "langText"
|
||||
FROM multi_lang_key_master km
|
||||
JOIN multi_lang_text t ON km.key_id = t.key_id
|
||||
WHERE km.company_code = $1
|
||||
AND km.menu_name = $2
|
||||
AND km.lang_key = $3
|
||||
AND t.lang_code = $4
|
||||
AND km.is_active = 'Y'
|
||||
AND t.is_active = 'Y'
|
||||
LIMIT 1
|
||||
`;
|
||||
|
||||
const result = await this.client.query(query, [
|
||||
params.companyCode,
|
||||
params.menuCode,
|
||||
params.langKey,
|
||||
params.userLang,
|
||||
]);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
logger.warn("사용자별 다국어 텍스트를 찾을 수 없음", { params });
|
||||
return params.langKey; // 기본값으로 키 반환
|
||||
}
|
||||
|
||||
const langText = result.rows[0].langText;
|
||||
logger.info("사용자별 다국어 텍스트 조회 완료", { params, langText });
|
||||
|
||||
return langText;
|
||||
} catch (error) {
|
||||
logger.error("사용자별 다국어 텍스트 조회 중 오류 발생:", error);
|
||||
throw new Error(
|
||||
`사용자별 다국어 텍스트 조회 실패: ${error instanceof Error ? error.message : "Unknown error"}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 특정 키의 다국어 텍스트 조회
|
||||
*/
|
||||
async getLangText(
|
||||
companyCode: string,
|
||||
langKey: string,
|
||||
langCode: string
|
||||
): Promise<string> {
|
||||
try {
|
||||
logger.info("특정 키의 다국어 텍스트 조회 시작", {
|
||||
companyCode,
|
||||
langKey,
|
||||
langCode,
|
||||
});
|
||||
|
||||
const query = `
|
||||
SELECT t.lang_text as "langText"
|
||||
FROM multi_lang_text t
|
||||
JOIN multi_lang_key_master k ON t.key_id = k.key_id
|
||||
WHERE k.company_code = $1
|
||||
AND k.lang_key = $2
|
||||
AND t.lang_code = $3
|
||||
AND t.is_active = 'Y'
|
||||
AND k.is_active = 'Y'
|
||||
`;
|
||||
|
||||
const result = await this.client.query(query, [
|
||||
companyCode,
|
||||
langKey,
|
||||
langCode,
|
||||
]);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
logger.warn("특정 키의 다국어 텍스트를 찾을 수 없음", {
|
||||
companyCode,
|
||||
langKey,
|
||||
langCode,
|
||||
});
|
||||
return langKey; // 기본값으로 키 반환
|
||||
}
|
||||
|
||||
const langText = result.rows[0].langText;
|
||||
logger.info("특정 키의 다국어 텍스트 조회 완료", {
|
||||
companyCode,
|
||||
langKey,
|
||||
langCode,
|
||||
langText,
|
||||
});
|
||||
|
||||
return langText;
|
||||
} catch (error) {
|
||||
logger.error("특정 키의 다국어 텍스트 조회 중 오류 발생:", error);
|
||||
throw new Error(
|
||||
`특정 키의 다국어 텍스트 조회 실패: ${error instanceof Error ? error.message : "Unknown error"}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 배치 번역 조회
|
||||
*/
|
||||
async getBatchTranslations(
|
||||
params: BatchTranslationRequest
|
||||
): Promise<Record<string, string>> {
|
||||
try {
|
||||
logger.info("배치 번역 조회 시작", {
|
||||
companyCode: params.companyCode,
|
||||
menuCode: params.menuCode,
|
||||
userLang: params.userLang,
|
||||
keyCount: params.langKeys.length,
|
||||
});
|
||||
|
||||
if (params.langKeys.length === 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// 모든 키에 대한 마스터 정보를 한번에 조회
|
||||
const langKeyMastersQuery = `
|
||||
SELECT key_id, lang_key, company_code
|
||||
FROM multi_lang_key_master
|
||||
WHERE lang_key = ANY($1::varchar[])
|
||||
AND (company_code = $2::varchar OR company_code = '*')
|
||||
ORDER BY
|
||||
CASE WHEN company_code = $2::varchar THEN 1 ELSE 2 END,
|
||||
lang_key,
|
||||
company_code
|
||||
`;
|
||||
|
||||
const langKeyMasters = await this.client.query(langKeyMastersQuery, [
|
||||
params.langKeys,
|
||||
params.companyCode,
|
||||
]);
|
||||
|
||||
if (langKeyMasters.rows.length === 0) {
|
||||
logger.warn("배치 번역: 언어키 마스터를 찾을 수 없음", { params });
|
||||
return this.createDefaultTranslations(params.langKeys);
|
||||
}
|
||||
|
||||
// 찾은 키들의 ID 목록
|
||||
const keyIds = langKeyMasters.rows.map((row) => row.key_id);
|
||||
const foundKeys = langKeyMasters.rows.map((row) => row.lang_key);
|
||||
|
||||
// 누락된 키들 (기본값으로 설정)
|
||||
const missingKeys = params.langKeys.filter(
|
||||
(key) => !foundKeys.includes(key)
|
||||
);
|
||||
const result: Record<string, string> = {};
|
||||
|
||||
// 기본값으로 누락된 키들 설정
|
||||
missingKeys.forEach((key) => {
|
||||
result[key] = key;
|
||||
});
|
||||
|
||||
// 실제 번역 텍스트 조회
|
||||
if (keyIds.length > 0) {
|
||||
const textsQuery = `
|
||||
SELECT t.key_id, t.lang_text, km.lang_key
|
||||
FROM multi_lang_text t
|
||||
JOIN multi_lang_key_master km ON t.key_id = km.key_id
|
||||
WHERE t.key_id = ANY($1::int[])
|
||||
AND t.lang_code = $2
|
||||
AND t.is_active = 'Y'
|
||||
`;
|
||||
|
||||
const texts = await this.client.query(textsQuery, [
|
||||
keyIds,
|
||||
params.userLang,
|
||||
]);
|
||||
|
||||
// 결과 매핑
|
||||
texts.rows.forEach((row) => {
|
||||
result[row.lang_key] = row.lang_text;
|
||||
});
|
||||
}
|
||||
|
||||
logger.info("배치 번역 조회 완료", {
|
||||
totalKeys: params.langKeys.length,
|
||||
foundKeys: foundKeys.length,
|
||||
missingKeys: missingKeys.length,
|
||||
resultKeys: Object.keys(result).length,
|
||||
});
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
logger.error("배치 번역 조회 중 오류 발생:", error);
|
||||
throw new Error(
|
||||
`배치 번역 조회 실패: ${error instanceof Error ? error.message : "Unknown error"}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 기본 번역 생성 (키를 그대로 반환)
|
||||
*/
|
||||
private createDefaultTranslations(
|
||||
langKeys: string[]
|
||||
): Record<string, string> {
|
||||
const result: Record<string, string> = {};
|
||||
langKeys.forEach((key) => {
|
||||
result[key] = key;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
export interface Language {
|
||||
langCode: string;
|
||||
langName: string;
|
||||
langNative: string;
|
||||
isActive: string;
|
||||
sortOrder?: number;
|
||||
createdDate?: Date;
|
||||
createdBy?: string;
|
||||
updatedDate?: Date;
|
||||
updatedBy?: string;
|
||||
}
|
||||
|
||||
export interface LangKey {
|
||||
keyId?: number;
|
||||
companyCode: string;
|
||||
menuName?: string;
|
||||
langKey: string;
|
||||
description?: string;
|
||||
isActive: string;
|
||||
createdDate?: Date;
|
||||
createdBy?: string;
|
||||
updatedDate?: Date;
|
||||
updatedBy?: string;
|
||||
}
|
||||
|
||||
export interface LangText {
|
||||
textId?: number;
|
||||
keyId: number;
|
||||
langCode: string;
|
||||
langText: string;
|
||||
isActive: string;
|
||||
createdDate?: Date;
|
||||
createdBy?: string;
|
||||
updatedDate?: Date;
|
||||
updatedBy?: string;
|
||||
}
|
||||
|
||||
export interface LangKeyWithTexts extends LangKey {
|
||||
texts: LangText[];
|
||||
}
|
||||
|
||||
export interface CreateLanguageRequest {
|
||||
langCode: string;
|
||||
langName: string;
|
||||
langNative: string;
|
||||
isActive?: string;
|
||||
sortOrder?: number;
|
||||
createdBy?: string;
|
||||
updatedBy?: string;
|
||||
}
|
||||
|
||||
export interface UpdateLanguageRequest {
|
||||
langName?: string;
|
||||
langNative?: string;
|
||||
isActive?: string;
|
||||
sortOrder?: number;
|
||||
updatedBy?: string;
|
||||
}
|
||||
|
||||
export interface CreateLangKeyRequest {
|
||||
companyCode: string;
|
||||
menuName?: string;
|
||||
langKey: string;
|
||||
description?: string;
|
||||
isActive?: string;
|
||||
createdBy?: string;
|
||||
updatedBy?: string;
|
||||
}
|
||||
|
||||
export interface UpdateLangKeyRequest {
|
||||
companyCode?: string;
|
||||
menuName?: string;
|
||||
langKey?: string;
|
||||
description?: string;
|
||||
updatedBy?: string;
|
||||
}
|
||||
|
||||
export interface SaveLangTextsRequest {
|
||||
texts: Array<{
|
||||
langCode: string;
|
||||
langText: string;
|
||||
isActive?: string;
|
||||
createdBy?: string;
|
||||
updatedBy?: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
export interface GetLangKeysParams {
|
||||
companyCode?: string;
|
||||
menuCode?: string;
|
||||
keyType?: string;
|
||||
searchText?: string;
|
||||
page?: number;
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
export interface GetUserTextParams {
|
||||
companyCode: string;
|
||||
menuCode: string;
|
||||
langKey: string;
|
||||
userLang: string;
|
||||
}
|
||||
|
||||
export interface BatchTranslationRequest {
|
||||
companyCode: string;
|
||||
menuCode?: string;
|
||||
userLang: string;
|
||||
langKeys: string[];
|
||||
}
|
||||
|
||||
export interface TranslationCacheEntry {
|
||||
data: Record<string, string>;
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
export interface ApiResponse<T = any> {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
data?: T;
|
||||
error?: {
|
||||
code: string;
|
||||
details?: any;
|
||||
};
|
||||
pagination?: {
|
||||
page: number;
|
||||
limit: number;
|
||||
total: number;
|
||||
totalPages: number;
|
||||
};
|
||||
}
|
||||
|
|
@ -65,7 +65,7 @@ export default function MultiLangPage() {
|
|||
const fetchCompanies = async () => {
|
||||
try {
|
||||
console.log("회사 목록 조회 시작");
|
||||
const response = await apiClient.get("/api/admin/companies");
|
||||
const response = await apiClient.get("/admin/companies");
|
||||
console.log("회사 목록 응답 데이터:", response.data);
|
||||
|
||||
const data = response.data;
|
||||
|
|
@ -87,7 +87,7 @@ export default function MultiLangPage() {
|
|||
// 언어 목록 조회
|
||||
const fetchLanguages = async () => {
|
||||
try {
|
||||
const response = await apiClient.get("/api/admin/multilang/languages");
|
||||
const response = await apiClient.get("/multilang/languages");
|
||||
const data = response.data;
|
||||
if (data.success) {
|
||||
setLanguages(data.data);
|
||||
|
|
@ -100,7 +100,7 @@ export default function MultiLangPage() {
|
|||
// 다국어 키 목록 조회
|
||||
const fetchLangKeys = async () => {
|
||||
try {
|
||||
const response = await apiClient.get("/api/admin/multilang/keys");
|
||||
const response = await apiClient.get("/multilang/keys");
|
||||
const data = response.data;
|
||||
if (data.success) {
|
||||
console.log("✅ 전체 키 목록 로드:", data.data.length, "개");
|
||||
|
|
@ -147,7 +147,7 @@ export default function MultiLangPage() {
|
|||
const fetchLangTexts = async (keyId: number) => {
|
||||
try {
|
||||
console.log("다국어 텍스트 조회 시작: keyId =", keyId);
|
||||
const response = await apiClient.get(`/api/admin/multilang/keys/${keyId}/texts`);
|
||||
const response = await apiClient.get(`/multilang/keys/${keyId}/texts`);
|
||||
const data = response.data;
|
||||
console.log("다국어 텍스트 조회 응답:", data);
|
||||
if (data.success) {
|
||||
|
|
@ -203,7 +203,18 @@ export default function MultiLangPage() {
|
|||
if (!selectedKey) return;
|
||||
|
||||
try {
|
||||
const response = await apiClient.post(`/api/admin/multilang/keys/${selectedKey.keyId}/texts`, editingTexts);
|
||||
// 백엔드가 기대하는 형식으로 데이터 변환
|
||||
const requestData = {
|
||||
texts: editingTexts.map((text) => ({
|
||||
langCode: text.langCode,
|
||||
langText: text.langText,
|
||||
isActive: text.isActive || "Y",
|
||||
createdBy: user?.userId || "system",
|
||||
updatedBy: user?.userId || "system",
|
||||
})),
|
||||
};
|
||||
|
||||
const response = await apiClient.post(`/multilang/keys/${selectedKey.keyId}/texts`, requestData);
|
||||
const data = response.data;
|
||||
if (data.success) {
|
||||
alert("저장되었습니다.");
|
||||
|
|
@ -245,9 +256,9 @@ export default function MultiLangPage() {
|
|||
|
||||
let response;
|
||||
if (editingLanguage) {
|
||||
response = await apiClient.put(`/api/admin/multilang/languages/${editingLanguage.langCode}`, requestData);
|
||||
response = await apiClient.put(`/multilang/languages/${editingLanguage.langCode}`, requestData);
|
||||
} else {
|
||||
response = await apiClient.post("/api/admin/multilang/languages", requestData);
|
||||
response = await apiClient.post("/multilang/languages", requestData);
|
||||
}
|
||||
|
||||
const result = response.data;
|
||||
|
|
@ -282,17 +293,11 @@ export default function MultiLangPage() {
|
|||
|
||||
try {
|
||||
const deletePromises = Array.from(selectedLanguages).map((langCode) =>
|
||||
fetch(`${API_BASE_URL}/multilang/languages/${langCode}`, {
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}),
|
||||
apiClient.delete(`/admin/multilang/languages/${langCode}`),
|
||||
);
|
||||
|
||||
const responses = await Promise.all(deletePromises);
|
||||
const failedDeletes = responses.filter((response) => !response.ok);
|
||||
const failedDeletes = responses.filter((response) => !response.data.success);
|
||||
|
||||
if (failedDeletes.length === 0) {
|
||||
alert("선택된 언어가 삭제되었습니다.");
|
||||
|
|
@ -344,9 +349,9 @@ export default function MultiLangPage() {
|
|||
|
||||
let response;
|
||||
if (editingKey) {
|
||||
response = await apiClient.put(`/api/admin/multilang/keys/${editingKey.keyId}`, requestData);
|
||||
response = await apiClient.put(`/multilang/keys/${editingKey.keyId}`, requestData);
|
||||
} else {
|
||||
response = await apiClient.post("/api/admin/multilang/keys", requestData);
|
||||
response = await apiClient.post("/multilang/keys", requestData);
|
||||
}
|
||||
|
||||
const data = response.data;
|
||||
|
|
@ -383,7 +388,7 @@ export default function MultiLangPage() {
|
|||
// 키 상태 토글
|
||||
const handleToggleStatus = async (keyId: number) => {
|
||||
try {
|
||||
const response = await apiClient.put(`/api/admin/multilang/keys/${keyId}/toggle`);
|
||||
const response = await apiClient.put(`/multilang/keys/${keyId}/toggle`);
|
||||
const data = response.data;
|
||||
if (data.success) {
|
||||
alert(`키가 ${data.data}되었습니다.`);
|
||||
|
|
@ -400,7 +405,7 @@ export default function MultiLangPage() {
|
|||
// 언어 상태 토글
|
||||
const handleToggleLanguageStatus = async (langCode: string) => {
|
||||
try {
|
||||
const response = await apiClient.put(`/api/admin/multilang/languages/${langCode}/toggle`);
|
||||
const response = await apiClient.put(`/multilang/languages/${langCode}/toggle`);
|
||||
const data = response.data;
|
||||
if (data.success) {
|
||||
alert(`언어가 ${data.data}되었습니다.`);
|
||||
|
|
@ -440,9 +445,7 @@ export default function MultiLangPage() {
|
|||
}
|
||||
|
||||
try {
|
||||
const deletePromises = Array.from(selectedKeys).map((keyId) =>
|
||||
apiClient.delete(`/api/admin/multilang/keys/${keyId}`),
|
||||
);
|
||||
const deletePromises = Array.from(selectedKeys).map((keyId) => apiClient.delete(`/multilang/keys/${keyId}`));
|
||||
|
||||
const responses = await Promise.all(deletePromises);
|
||||
const allSuccess = responses.every((response) => response.data.success);
|
||||
|
|
@ -472,7 +475,7 @@ export default function MultiLangPage() {
|
|||
}
|
||||
|
||||
try {
|
||||
const response = await apiClient.delete(`/api/admin/multilang/keys/${keyId}`);
|
||||
const response = await apiClient.delete(`/multilang/keys/${keyId}`);
|
||||
const data = response.data;
|
||||
if (data.success) {
|
||||
alert("언어 키가 영구적으로 삭제되었습니다.");
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import axios, { AxiosResponse, AxiosError } from "axios";
|
||||
|
||||
// API 기본 URL 설정
|
||||
export const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || "http://localhost:8080";
|
||||
export const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || "http://localhost:8080/api";
|
||||
|
||||
// JWT 토큰 관리 유틸리티
|
||||
const TokenManager = {
|
||||
|
|
|
|||
Loading…
Reference in New Issue