summaryrefslogtreecommitdiff
path: root/components/common/selectors/material/material-service.ts
diff options
context:
space:
mode:
authorjoonhoekim <26rote@gmail.com>2025-10-14 20:27:47 +0900
committerjoonhoekim <26rote@gmail.com>2025-10-14 20:27:47 +0900
commitf63cf682d6846210a04ce4a3eb8ebe9afd6d6dba (patch)
tree0a4717c11814c45e2b7d6531723700b1ae0a4974 /components/common/selectors/material/material-service.ts
parentd1cdcf9f35eca0552d1011e6d3c11a1d2d9abee4 (diff)
(김준회) 자재코드 선택기 구현 및 일반견적 생성시 반영
Diffstat (limited to 'components/common/selectors/material/material-service.ts')
-rw-r--r--components/common/selectors/material/material-service.ts155
1 files changed, 155 insertions, 0 deletions
diff --git a/components/common/selectors/material/material-service.ts b/components/common/selectors/material/material-service.ts
new file mode 100644
index 00000000..1f238ed7
--- /dev/null
+++ b/components/common/selectors/material/material-service.ts
@@ -0,0 +1,155 @@
+"use server";
+
+import { sql, SQL } from "drizzle-orm";
+import db from "@/db/db";
+import { MATERIAL_MASTER_PART_MATL } from "@/db/schema/MDG/mdg";
+
+export interface MaterialSearchItem {
+ materialCode: string; // 자재코드 (MATNR)
+ materialName: string; // 자재명 (ZZNAME)
+ displayText: string; // 애플리케이션 레벨에서 계산된 필드
+}
+
+export interface MaterialSearchResult {
+ success: boolean;
+ data: MaterialSearchItem[];
+ pagination: {
+ page: number;
+ perPage: number;
+ total: number;
+ pageCount: number;
+ hasNextPage: boolean;
+ hasPrevPage: boolean;
+ };
+}
+
+/**
+ * 자재 검색 함수 - MATERIAL_MASTER_PART_MATL 테이블에서 검색 (페이지네이션)
+ * 사용자는 자재코드를 직접 입력하여 검색함 (자재명이 아닌 자재코드만 검색 대상)
+ * 자재 레코드가 수억개 수준이므로 항상 페이지네이션 사용
+ */
+export async function searchMaterialsForSelector(
+ query: string,
+ page: number = 1,
+ perPage: number = 10
+): Promise<MaterialSearchResult> {
+ try {
+ const offset = (page - 1) * perPage;
+
+ // 검색 조건 - 자재코드(MATNR)로만 검색
+ let searchWhere: SQL<unknown> | undefined;
+ if (query.trim()) {
+ const searchPattern = `%${query.trim()}%`;
+ searchWhere = sql`${MATERIAL_MASTER_PART_MATL.MATNR} ILIKE ${searchPattern}`;
+ }
+
+ const { data, total } = await db.transaction(async (tx) => {
+ // 데이터 조회 - MATNR과 ZZNAME만 선택
+ const data = await tx
+ .select({
+ materialCode: MATERIAL_MASTER_PART_MATL.MATNR,
+ materialName: MATERIAL_MASTER_PART_MATL.ZZNAME,
+ })
+ .from(MATERIAL_MASTER_PART_MATL)
+ .where(searchWhere)
+ .orderBy(MATERIAL_MASTER_PART_MATL.MATNR)
+ .limit(perPage)
+ .offset(offset);
+
+ // 총 개수 조회
+ const countResult = await tx
+ .select({ count: sql<number>`count(*)` })
+ .from(MATERIAL_MASTER_PART_MATL)
+ .where(searchWhere);
+
+ const total = countResult[0]?.count || 0;
+
+ return {
+ data: data.map((row) => ({
+ materialCode: row.materialCode || '',
+ materialName: row.materialName || '',
+ displayText: `${row.materialCode || ''} - ${row.materialName || ''}`, // 애플리케이션 레벨에서 생성
+ })),
+ total,
+ };
+ });
+
+ const pageCount = Math.ceil(total / perPage);
+
+ return {
+ success: true,
+ data,
+ pagination: {
+ page,
+ perPage,
+ total,
+ pageCount,
+ hasNextPage: page < pageCount,
+ hasPrevPage: page > 1,
+ },
+ };
+ } catch (error) {
+ console.error("자재 검색 오류:", error);
+ return {
+ success: false,
+ data: [],
+ pagination: {
+ page: 1,
+ perPage: 10,
+ total: 0,
+ pageCount: 0,
+ hasNextPage: false,
+ hasPrevPage: false,
+ },
+ };
+ }
+}
+
+/**
+ * Dialog용 자재 목록 조회 함수 - 페이지네이션
+ * Dialog에서는 효율적인 사용자 경험을 위해 10개씩 페이지네이션하여 조회
+ * 자재 레코드가 수억개 수준이므로 무한 스크롤이나 전체 로드가 아닌 페이지네이션 사용
+ */
+export async function searchMaterialsForDialog(
+ query: string,
+ page: number = 1,
+ perPage: number = 10
+): Promise<{
+ success: boolean;
+ data: MaterialSearchItem[];
+ pagination: {
+ page: number;
+ perPage: number;
+ total: number;
+ pageCount: number;
+ hasNextPage: boolean;
+ hasPrevPage: boolean;
+ };
+ error?: string;
+}> {
+ try {
+ const result = await searchMaterialsForSelector(query, page, perPage);
+
+ return {
+ success: result.success,
+ data: result.data,
+ pagination: result.pagination,
+ error: result.success ? undefined : "검색 중 오류가 발생했습니다.",
+ };
+ } catch (error) {
+ console.error("Dialog용 자재 검색 오류:", error);
+ return {
+ success: false,
+ data: [],
+ pagination: {
+ page: 1,
+ perPage: 10,
+ total: 0,
+ pageCount: 0,
+ hasNextPage: false,
+ hasPrevPage: false,
+ },
+ error: "데이터를 불러오는데 실패했습니다.",
+ };
+ }
+} \ No newline at end of file