303 lines
6.9 KiB
TypeScript
303 lines
6.9 KiB
TypeScript
import { PrismaClient } from "@prisma/client";
|
|
|
|
const prisma = new PrismaClient();
|
|
|
|
export interface ComponentStandardData {
|
|
component_code: string;
|
|
component_name: string;
|
|
component_name_eng?: string;
|
|
description?: string;
|
|
category: string;
|
|
icon_name?: string;
|
|
default_size?: any;
|
|
component_config: any;
|
|
preview_image?: string;
|
|
sort_order?: number;
|
|
is_active?: string;
|
|
is_public?: string;
|
|
company_code: string;
|
|
created_by?: string;
|
|
updated_by?: string;
|
|
}
|
|
|
|
export interface ComponentQueryParams {
|
|
category?: string;
|
|
active?: string;
|
|
is_public?: string;
|
|
company_code?: string;
|
|
search?: string;
|
|
sort?: string;
|
|
order?: "asc" | "desc";
|
|
limit?: number;
|
|
offset?: number;
|
|
}
|
|
|
|
class ComponentStandardService {
|
|
/**
|
|
* 컴포넌트 목록 조회
|
|
*/
|
|
async getComponents(params: ComponentQueryParams = {}) {
|
|
const {
|
|
category,
|
|
active = "Y",
|
|
is_public,
|
|
company_code,
|
|
search,
|
|
sort = "sort_order",
|
|
order = "asc",
|
|
limit,
|
|
offset = 0,
|
|
} = params;
|
|
|
|
const where: any = {};
|
|
|
|
// 활성화 상태 필터
|
|
if (active) {
|
|
where.is_active = active;
|
|
}
|
|
|
|
// 카테고리 필터
|
|
if (category && category !== "all") {
|
|
where.category = category;
|
|
}
|
|
|
|
// 공개 여부 필터
|
|
if (is_public) {
|
|
where.is_public = is_public;
|
|
}
|
|
|
|
// 회사별 필터 (공개 컴포넌트 + 해당 회사 컴포넌트)
|
|
if (company_code) {
|
|
where.OR = [{ is_public: "Y" }, { company_code }];
|
|
}
|
|
|
|
// 검색 조건
|
|
if (search) {
|
|
where.OR = [
|
|
...(where.OR || []),
|
|
{ component_name: { contains: search, mode: "insensitive" } },
|
|
{ component_name_eng: { contains: search, mode: "insensitive" } },
|
|
{ description: { contains: search, mode: "insensitive" } },
|
|
];
|
|
}
|
|
|
|
const orderBy: any = {};
|
|
orderBy[sort] = order;
|
|
|
|
const components = await prisma.component_standards.findMany({
|
|
where,
|
|
orderBy,
|
|
take: limit,
|
|
skip: offset,
|
|
});
|
|
|
|
const total = await prisma.component_standards.count({ where });
|
|
|
|
return {
|
|
components,
|
|
total,
|
|
limit,
|
|
offset,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 컴포넌트 상세 조회
|
|
*/
|
|
async getComponent(component_code: string) {
|
|
const component = await prisma.component_standards.findUnique({
|
|
where: { component_code },
|
|
});
|
|
|
|
if (!component) {
|
|
throw new Error(`컴포넌트를 찾을 수 없습니다: ${component_code}`);
|
|
}
|
|
|
|
return component;
|
|
}
|
|
|
|
/**
|
|
* 컴포넌트 생성
|
|
*/
|
|
async createComponent(data: ComponentStandardData) {
|
|
// 중복 코드 확인
|
|
const existing = await prisma.component_standards.findUnique({
|
|
where: { component_code: data.component_code },
|
|
});
|
|
|
|
if (existing) {
|
|
throw new Error(
|
|
`이미 존재하는 컴포넌트 코드입니다: ${data.component_code}`
|
|
);
|
|
}
|
|
|
|
const component = await prisma.component_standards.create({
|
|
data: {
|
|
...data,
|
|
created_date: new Date(),
|
|
updated_date: new Date(),
|
|
},
|
|
});
|
|
|
|
return component;
|
|
}
|
|
|
|
/**
|
|
* 컴포넌트 수정
|
|
*/
|
|
async updateComponent(
|
|
component_code: string,
|
|
data: Partial<ComponentStandardData>
|
|
) {
|
|
const existing = await this.getComponent(component_code);
|
|
|
|
const component = await prisma.component_standards.update({
|
|
where: { component_code },
|
|
data: {
|
|
...data,
|
|
updated_date: new Date(),
|
|
},
|
|
});
|
|
|
|
return component;
|
|
}
|
|
|
|
/**
|
|
* 컴포넌트 삭제
|
|
*/
|
|
async deleteComponent(component_code: string) {
|
|
const existing = await this.getComponent(component_code);
|
|
|
|
await prisma.component_standards.delete({
|
|
where: { component_code },
|
|
});
|
|
|
|
return { message: `컴포넌트가 삭제되었습니다: ${component_code}` };
|
|
}
|
|
|
|
/**
|
|
* 컴포넌트 정렬 순서 업데이트
|
|
*/
|
|
async updateSortOrder(
|
|
updates: Array<{ component_code: string; sort_order: number }>
|
|
) {
|
|
const transactions = updates.map(({ component_code, sort_order }) =>
|
|
prisma.component_standards.update({
|
|
where: { component_code },
|
|
data: { sort_order, updated_date: new Date() },
|
|
})
|
|
);
|
|
|
|
await prisma.$transaction(transactions);
|
|
|
|
return { message: "정렬 순서가 업데이트되었습니다." };
|
|
}
|
|
|
|
/**
|
|
* 컴포넌트 복제
|
|
*/
|
|
async duplicateComponent(
|
|
source_code: string,
|
|
new_code: string,
|
|
new_name: string
|
|
) {
|
|
const source = await this.getComponent(source_code);
|
|
|
|
// 새 코드 중복 확인
|
|
const existing = await prisma.component_standards.findUnique({
|
|
where: { component_code: new_code },
|
|
});
|
|
|
|
if (existing) {
|
|
throw new Error(`이미 존재하는 컴포넌트 코드입니다: ${new_code}`);
|
|
}
|
|
|
|
const component = await prisma.component_standards.create({
|
|
data: {
|
|
component_code: new_code,
|
|
component_name: new_name,
|
|
component_name_eng: source.component_name_eng,
|
|
description: source.description,
|
|
category: source.category,
|
|
icon_name: source.icon_name,
|
|
default_size: source.default_size as any,
|
|
component_config: source.component_config as any,
|
|
preview_image: source.preview_image,
|
|
sort_order: source.sort_order,
|
|
is_active: source.is_active,
|
|
is_public: source.is_public,
|
|
company_code: source.company_code,
|
|
created_date: new Date(),
|
|
created_by: source.created_by,
|
|
updated_date: new Date(),
|
|
updated_by: source.updated_by,
|
|
},
|
|
});
|
|
|
|
return component;
|
|
}
|
|
|
|
/**
|
|
* 카테고리 목록 조회
|
|
*/
|
|
async getCategories(company_code?: string) {
|
|
const where: any = {
|
|
is_active: "Y",
|
|
};
|
|
|
|
if (company_code) {
|
|
where.OR = [{ is_public: "Y" }, { company_code }];
|
|
}
|
|
|
|
const categories = await prisma.component_standards.findMany({
|
|
where,
|
|
select: { category: true },
|
|
distinct: ["category"],
|
|
});
|
|
|
|
return categories
|
|
.map((item) => item.category)
|
|
.filter((category) => category !== null);
|
|
}
|
|
|
|
/**
|
|
* 컴포넌트 통계
|
|
*/
|
|
async getStatistics(company_code?: string) {
|
|
const where: any = {
|
|
is_active: "Y",
|
|
};
|
|
|
|
if (company_code) {
|
|
where.OR = [{ is_public: "Y" }, { company_code }];
|
|
}
|
|
|
|
const total = await prisma.component_standards.count({ where });
|
|
|
|
const byCategory = await prisma.component_standards.groupBy({
|
|
by: ["category"],
|
|
where,
|
|
_count: { category: true },
|
|
});
|
|
|
|
const byStatus = await prisma.component_standards.groupBy({
|
|
by: ["is_active"],
|
|
_count: { is_active: true },
|
|
});
|
|
|
|
return {
|
|
total,
|
|
byCategory: byCategory.map((item) => ({
|
|
category: item.category,
|
|
count: item._count.category,
|
|
})),
|
|
byStatus: byStatus.map((item) => ({
|
|
status: item.is_active,
|
|
count: item._count.is_active,
|
|
})),
|
|
};
|
|
}
|
|
}
|
|
|
|
export default new ComponentStandardService();
|