diff options
Diffstat (limited to 'lib/items-tech/service.ts')
| -rw-r--r-- | lib/items-tech/service.ts | 966 |
1 files changed, 499 insertions, 467 deletions
diff --git a/lib/items-tech/service.ts b/lib/items-tech/service.ts index a14afa14..be65f5dd 100644 --- a/lib/items-tech/service.ts +++ b/lib/items-tech/service.ts @@ -9,17 +9,50 @@ import { unstable_cache } from "@/lib/unstable-cache"; import { getErrorMessage } from "@/lib/handle-error";
import { asc, desc, ilike, and, or, eq, count, inArray, sql } from "drizzle-orm";
-import { GetShipbuildingSchema, GetOffshoreTopSchema, GetOffshoreHullSchema, UpdateItemSchema, ShipbuildingItemCreateData, TypedItemCreateData, OffshoreTopItemCreateData, OffshoreHullItemCreateData } from "./validations";
-import { Item, items, itemShipbuilding, itemOffshoreTop, itemOffshoreHull, ItemOffshoreTop, ItemOffshoreHull } from "@/db/schema/items";
-import { findAllItems } from "./repository";
-import { findAllOffshoreItems } from "./repository";
+import { GetShipbuildingSchema, GetOffshoreTopSchema, GetOffshoreHullSchema, ShipbuildingItemCreateData, TypedItemCreateData, OffshoreTopItemCreateData, OffshoreHullItemCreateData } from "./validations";
+import { itemShipbuilding, itemOffshoreTop, itemOffshoreHull } from "@/db/schema/items";
+
+// 타입 정의 추가
+type WorkType = '기장' | '전장' | '선실' | '배관' | '철의';
+type OffshoreTopWorkType = 'TM' | 'TS' | 'TE' | 'TP';
+type OffshoreHullWorkType = 'HA' | 'HE' | 'HH' | 'HM' | 'NC';
+
+interface ShipbuildingItem {
+ id: number;
+ itemCode: string;
+ workType: WorkType;
+ itemList: string;
+ shipTypes: string;
+ createdAt: Date;
+ updatedAt: Date;
+}
+
+interface OffshoreTopTechItem {
+ id: number;
+ itemCode: string;
+ workType: OffshoreTopWorkType;
+ itemList: string;
+ subItemList?: string;
+ createdAt: Date;
+ updatedAt: Date;
+}
+
+interface OffshoreHullTechItem {
+ id: number;
+ itemCode: string;
+ workType: OffshoreHullWorkType;
+ itemList: string;
+ subItemList?: string;
+ createdAt: Date;
+ updatedAt: Date;
+}
/* -----------------------------------------------------
1) 조회 관련
----------------------------------------------------- */
/**
- * 복잡한 조건으로 Item 목록을 조회 (+ pagination) 하고,
+ * 복잡한 조건으로 조선 아이템 목록을 조회 (+ pagination) 하고,
* 총 개수에 따라 pageCount를 계산해서 리턴.
* Next.js의 unstable_cache를 사용해 일정 시간 캐시.
*/
@@ -31,27 +64,21 @@ export async function getShipbuildingItems(input: GetShipbuildingSchema) { // advancedTable 모드면 filterColumns()로 where 절 구성
const advancedWhere = filterColumns({
- table: items,
+ table: itemShipbuilding,
filters: input.filters.filter(filter => {
// enum 필드에 대한 isEmpty/isNotEmpty는 제외
return !((filter.id === 'workType' || filter.id === 'shipTypes') &&
(filter.operator === 'isEmpty' || filter.operator === 'isNotEmpty'))
}),
joinOperator: input.joinOperator,
- joinedTables: { itemShipbuilding },
- customColumnMapping: {
- workType: { table: itemShipbuilding, column: "workType" },
- shipTypes: { table: itemShipbuilding, column: "shipTypes" },
- itemList: { table: itemShipbuilding, column: "itemList" },
- },
});
let globalWhere;
if (input.search) {
const s = `%${input.search}%`;
globalWhere = or(
- ilike(items.itemCode, s),
- ilike(itemShipbuilding.itemList, s)
+ ilike(itemShipbuilding.itemCode, s),
+ ilike(itemShipbuilding.itemList, s),
);
}
@@ -75,27 +102,22 @@ export async function getShipbuildingItems(input: GetShipbuildingSchema) { const orderBy =
input.sort.length > 0
? input.sort.map((item) => {
- const column = item.id === "workType" || item.id === "shipTypes" || item.id === "itemList"
- ? itemShipbuilding[item.id]
- : items[item.id];
+ const column = itemShipbuilding[item.id];
return item.desc ? desc(column) : asc(column);
})
- : [desc(items.createdAt)];
+ : [desc(itemShipbuilding.createdAt)];
- // 조선 아이템 테이블과 기본 아이템 테이블 조인하여 조회
+ // 조선 아이템 테이블만 조회 (독립적)
const result = await db.select({
id: itemShipbuilding.id,
- itemCode: items.itemCode,
+ itemCode: itemShipbuilding.itemCode,
workType: itemShipbuilding.workType,
shipTypes: itemShipbuilding.shipTypes,
itemList: itemShipbuilding.itemList,
- itemName: items.itemName,
- description: items.description,
createdAt: itemShipbuilding.createdAt,
updatedAt: itemShipbuilding.updatedAt,
})
.from(itemShipbuilding)
- .innerJoin(items, eq(itemShipbuilding.itemCode, items.itemCode))
.where(where)
.orderBy(...orderBy)
.offset(offset)
@@ -106,7 +128,6 @@ export async function getShipbuildingItems(input: GetShipbuildingSchema) { count: count()
})
.from(itemShipbuilding)
- .innerJoin(items, eq(itemShipbuilding.itemCode, items.itemCode))
.where(where);
const pageCount = Math.ceil(Number(total) / input.perPage);
@@ -133,26 +154,20 @@ export async function getOffshoreTopItems(input: GetOffshoreTopSchema) { // advancedTable 모드면 filterColumns()로 where 절 구성
const advancedWhere = filterColumns({
- table: items,
+ table: itemOffshoreTop,
filters: input.filters.filter(filter => {
// enum 필드에 대한 isEmpty/isNotEmpty는 제외
return !((filter.id === 'workType') &&
(filter.operator === 'isEmpty' || filter.operator === 'isNotEmpty'))
}),
joinOperator: input.joinOperator,
- joinedTables: { itemOffshoreTop },
- customColumnMapping: {
- workType: { table: itemOffshoreTop, column: "workType" },
- itemList: { table: itemOffshoreTop, column: "itemList" },
- subItemList: { table: itemOffshoreTop, column: "subItemList" },
- },
});
let globalWhere;
if (input.search) {
const s = `%${input.search}%`;
globalWhere = or(
- ilike(items.itemCode, s),
+ ilike(itemOffshoreTop.itemCode, s),
ilike(itemOffshoreTop.itemList, s),
ilike(itemOffshoreTop.subItemList, s)
);
@@ -178,27 +193,22 @@ export async function getOffshoreTopItems(input: GetOffshoreTopSchema) { const orderBy =
input.sort.length > 0
? input.sort.map((item) => {
- const column = item.id === "workType" || item.id === "itemList" || item.id === "subItemList"
- ? itemOffshoreTop[item.id]
- : items[item.id];
+ const column = itemOffshoreTop[item.id];
return item.desc ? desc(column) : asc(column);
})
- : [desc(items.createdAt)];
+ : [desc(itemOffshoreTop.createdAt)];
- // 해양 TOP 아이템 테이블과 기본 아이템 테이블 조인하여 조회
+ // 해양 TOP 아이템 테이블만 조회 (독립적)
const result = await db.select({
id: itemOffshoreTop.id,
- itemCode: items.itemCode,
+ itemCode: itemOffshoreTop.itemCode,
workType: itemOffshoreTop.workType,
itemList: itemOffshoreTop.itemList,
subItemList: itemOffshoreTop.subItemList,
- itemName: items.itemName,
- description: items.description,
createdAt: itemOffshoreTop.createdAt,
updatedAt: itemOffshoreTop.updatedAt,
})
.from(itemOffshoreTop)
- .innerJoin(items, eq(itemOffshoreTop.itemCode, items.itemCode))
.where(where)
.orderBy(...orderBy)
.offset(offset)
@@ -209,7 +219,6 @@ export async function getOffshoreTopItems(input: GetOffshoreTopSchema) { count: count()
})
.from(itemOffshoreTop)
- .innerJoin(items, eq(itemOffshoreTop.itemCode, items.itemCode))
.where(where);
const pageCount = Math.ceil(Number(total) / input.perPage);
@@ -236,26 +245,20 @@ export async function getOffshoreHullItems(input: GetOffshoreHullSchema) { // advancedTable 모드면 filterColumns()로 where 절 구성
const advancedWhere = filterColumns({
- table: items,
+ table: itemOffshoreHull,
filters: input.filters.filter(filter => {
// enum 필드에 대한 isEmpty/isNotEmpty는 제외
return !((filter.id === 'workType') &&
(filter.operator === 'isEmpty' || filter.operator === 'isNotEmpty'))
}),
joinOperator: input.joinOperator,
- joinedTables: { itemOffshoreHull },
- customColumnMapping: {
- workType: { table: itemOffshoreHull, column: "workType" },
- itemList: { table: itemOffshoreHull, column: "itemList" },
- subItemList: { table: itemOffshoreHull, column: "subItemList" },
- },
});
let globalWhere;
if (input.search) {
const s = `%${input.search}%`;
globalWhere = or(
- ilike(items.itemCode, s),
+ ilike(itemOffshoreHull.itemCode, s),
ilike(itemOffshoreHull.itemList, s),
ilike(itemOffshoreHull.subItemList, s)
);
@@ -281,27 +284,22 @@ export async function getOffshoreHullItems(input: GetOffshoreHullSchema) { const orderBy =
input.sort.length > 0
? input.sort.map((item) => {
- const column = item.id === "workType" || item.id === "itemList" || item.id === "subItemList"
- ? itemOffshoreHull[item.id]
- : items[item.id];
+ const column = itemOffshoreHull[item.id];
return item.desc ? desc(column) : asc(column);
})
- : [desc(items.createdAt)];
+ : [desc(itemOffshoreHull.createdAt)];
- // 해양 HULL 아이템 테이블과 기본 아이템 테이블 조인하여 조회
+ // 해양 HULL 아이템 테이블만 조회 (독립적)
const result = await db.select({
id: itemOffshoreHull.id,
- itemCode: items.itemCode,
+ itemCode: itemOffshoreHull.itemCode,
workType: itemOffshoreHull.workType,
itemList: itemOffshoreHull.itemList,
subItemList: itemOffshoreHull.subItemList,
- itemName: items.itemName,
- description: items.description,
createdAt: itemOffshoreHull.createdAt,
updatedAt: itemOffshoreHull.updatedAt,
})
.from(itemOffshoreHull)
- .innerJoin(items, eq(itemOffshoreHull.itemCode, items.itemCode))
.where(where)
.orderBy(...orderBy)
.offset(offset)
@@ -312,7 +310,6 @@ export async function getOffshoreHullItems(input: GetOffshoreHullSchema) { count: count()
})
.from(itemOffshoreHull)
- .innerJoin(items, eq(itemOffshoreHull.itemCode, items.itemCode))
.where(where);
const pageCount = Math.ceil(Number(total) / input.perPage);
@@ -336,7 +333,7 @@ export async function getOffshoreHullItems(input: GetOffshoreHullSchema) { ----------------------------------------------------- */
/**
- * Item 생성 - 아이템 타입에 따라 해당 테이블에 데이터 삽입
+ * 조선 아이템 생성 - 독립적으로 생성
*/
export async function createShipbuildingItem(input: TypedItemCreateData) {
unstable_noStore()
@@ -351,60 +348,25 @@ export async function createShipbuildingItem(input: TypedItemCreateData) { }
}
- // itemName이 없으면 "기술영업"으로 설정
- if (!input.itemName) {
- input.itemName = "기술영업"
- }
-
- const result = await db.transaction(async (tx) => {
- // 1. itemCode로 직접 쿼리
- const existRows = await tx.select().from(items)
- .where(eq(items.itemCode, input.itemCode));
- const existingItem = existRows[0];
-
- let itemResult: any;
-
- if (existingItem) {
- // 기존 아이템이 있으면 업데이트하지 않고 그대로 사용
- itemResult = [existingItem]; // 배열 형태로 반환
- } else {
- // 없으면 새로 생성
- // 현재 가장 큰 ID 값 가져오기
- const maxIdResult = await tx.select({ maxId: sql`MAX(id)` }).from(items);
- const maxId = maxIdResult[0]?.maxId || 0;
- const newId = Number(maxId) + 1;
-
- // 새 ID로 아이템 생성
- itemResult = await tx.insert(items).values({
- id: newId,
- itemCode: input.itemCode,
- itemName: input.itemName,
- description: input.description,
- }).returning();
- }
-
- const shipData = input as ShipbuildingItemCreateData;
- const typeResult = await tx.insert(itemShipbuilding).values({
- itemCode: input.itemCode,
- workType: shipData.workType ? (shipData.workType as '기장' | '전장' | '선실' | '배관' | '철의') : '기장',
- shipTypes: shipData.shipTypes || '',
- itemList: shipData.itemList || null,
- createdAt: new Date(),
- updatedAt: new Date()
- }).returning();
-
- return { itemData: itemResult[0], shipbuildingData: typeResult[0] };
- })
+ const shipData = input as ShipbuildingItemCreateData;
+ const result = await db.insert(itemShipbuilding).values({
+ itemCode: input.itemCode,
+ workType: shipData.workType ? (shipData.workType as '기장' | '전장' | '선실' | '배관' | '철의') : '기장',
+ shipTypes: shipData.shipTypes || '',
+ itemList: shipData.itemList || null,
+ createdAt: new Date(),
+ updatedAt: new Date()
+ }).returning();
revalidateTag("items")
return {
success: true,
- data: result || null,
+ data: result[0] || null,
error: null
}
} catch (err) {
- console.error("아이템 생성/업데이트 오류:", err)
+ console.error("아이템 생성 오류:", err)
if (err instanceof Error && err.message.includes("unique constraint")) {
return {
@@ -430,16 +392,14 @@ export async function createShipbuildingItem(input: TypedItemCreateData) { */
export async function createShipbuildingImportItem(input: {
itemCode: string;
- itemName: string;
workType: '기장' | '전장' | '선실' | '배관' | '철의';
- description?: string | null;
itemList?: string | null;
- shipTypes: Record<string, boolean>;
+ subItemList?: string | null;
+ shipTypes?: string | null;
}) {
unstable_noStore();
try {
-
if (!input.itemCode) {
return {
success: false,
@@ -449,80 +409,46 @@ export async function createShipbuildingImportItem(input: { }
}
- // itemName이 없을 경우 "기술영업"으로 설정
- if (!input.itemName) {
- input.itemName = "기술영업";
- }
-
- const results = await db.transaction(async (tx) => {
- // 1. itemCode로 직접 쿼리
- const existRows = await tx.select().from(items)
- .where(eq(items.itemCode, input.itemCode));
- const existingItem = existRows[0];
-
- console.log('DB에서 직접 조회한 기존 아이템:', existingItem);
-
- let itemResult: any;
-
- if (existingItem) {
- console.log('기존 아이템 사용, itemCode:', input.itemCode);
- } else {
- // 없으면 새로 생성
- // 현재 가장 큰 ID 값 가져오기
- const maxIdResult = await tx.select({ maxId: sql`MAX(id)` }).from(items);
- const maxId = maxIdResult[0]?.maxId || 0;
- const newId = Number(maxId) + 1;
- console.log('새 아이템 생성을 위한 ID 계산:', { maxId, newId });
-
- // 새 ID로 아이템 생성
- const insertResult = await tx.insert(items).values({
- id: newId,
- itemCode: input.itemCode,
- itemName: input.itemName,
- description: input.description,
- }).returning();
-
- console.log('새 아이템 생성 완료, itemCode:', input.itemCode);
+ // 기존 아이템 확인
+ const existingItem = await db.select().from(itemShipbuilding)
+ .where(eq(itemShipbuilding.itemCode, input.itemCode));
+
+ if (existingItem.length > 0) {
+ return {
+ success: false,
+ message: "이미 존재하는 아이템 코드입니다",
+ data: null,
+ error: "중복 키 오류"
}
+ }
- const createdItems = [];
- for (const shipType of Object.keys(input.shipTypes)) {
- // 그대로 선종명 string으로 저장
- const existShip = await tx.select().from(itemShipbuilding)
- .where(
- and(
- eq(itemShipbuilding.itemCode, input.itemCode),
- eq(itemShipbuilding.shipTypes, shipType)
- )
- );
- if (!existShip[0]) {
- const shipbuildingResult = await tx.insert(itemShipbuilding).values({
- itemCode: input.itemCode,
- workType: input.workType,
- shipTypes: shipType,
- itemList: input.itemList || null,
- createdAt: new Date(),
- updatedAt: new Date()
- }).returning();
- createdItems.push({
- ...shipbuildingResult[0]
- });
- console.log('조선아이템 생성:', shipType, shipbuildingResult[0]);
- } else {
- console.log('이미 존재하는 조선아이템:', shipType);
- }
- }
- return createdItems;
- });
+ const result = await db.insert(itemShipbuilding).values({
+ itemCode: input.itemCode,
+ workType: input.workType,
+ shipTypes: input.shipTypes || '',
+ itemList: input.itemList || '',
+ createdAt: new Date(),
+ updatedAt: new Date()
+ }).returning();
revalidateTag("items");
return {
success: true,
- data: results,
+ data: result[0],
error: null
}
} catch (err) {
+ console.error("조선 아이템 생성 오류:", err);
+
+ if (err instanceof Error && err.message.includes("unique constraint")) {
+ return {
+ success: false,
+ message: "이미 존재하는 아이템 코드입니다",
+ data: null,
+ error: "중복 키 오류"
+ }
+ }
return {
success: false,
@@ -546,63 +472,24 @@ export async function createOffshoreTopItem(data: OffshoreTopItemCreateData) { }
}
- // itemName이 없으면 "기술영업"으로 설정
- if (!data.itemName) {
- data.itemName = "기술영업"
- }
-
- // 트랜잭션 내에서 처리
- const result = await db.transaction(async (tx) => {
- // 1. itemCode로 직접 쿼리
- const existRows = await tx.select().from(items)
- .where(eq(items.itemCode, data.itemCode));
- const existingItem = existRows[0];
-
- let itemResult: any;
-
- if (existingItem) {
- // 기존 아이템이 있으면 업데이트하지 않고 그대로 사용
- itemResult = [existingItem]; // 배열 형태로 반환
- } else {
- // 없으면 새로 생성
- // 현재 가장 큰 ID 값 가져오기
- const maxIdResult = await tx.select({ maxId: sql`MAX(id)` }).from(items);
- const maxId = maxIdResult[0]?.maxId || 0;
- const newId = Number(maxId) + 1;
-
- // 새 ID로 아이템 생성
- itemResult = await tx.insert(items).values({
- id: newId,
- itemCode: data.itemCode,
- itemName: data.itemName,
- description: data.description,
- }).returning();
- }
-
- const [offshoreTop] = await tx
- .insert(itemOffshoreTop)
- .values({
- itemCode: data.itemCode,
- workType: data.workType,
- itemList: data.itemList,
- subItemList: data.subItemList,
- createdAt: new Date(),
- updatedAt: new Date()
- })
- .returning();
-
- return { itemData: itemResult[0], offshoreTopData: offshoreTop };
- })
+ const result = await db.insert(itemOffshoreTop).values({
+ itemCode: data.itemCode,
+ workType: data.workType,
+ itemList: data.itemList,
+ subItemList: data.subItemList,
+ createdAt: new Date(),
+ updatedAt: new Date()
+ }).returning();
revalidateTag("items")
return {
success: true,
- data: result,
+ data: result[0],
error: null
}
} catch (err) {
- console.error("아이템 생성/업데이트 오류:", err)
+ console.error("아이템 생성 오류:", err)
if (err instanceof Error && err.message.includes("unique constraint")) {
return {
@@ -635,63 +522,24 @@ export async function createOffshoreHullItem(data: OffshoreHullItemCreateData) { }
}
- // itemName이 없으면 "기술영업"으로 설정
- if (!data.itemName) {
- data.itemName = "기술영업"
- }
-
- // 트랜잭션 내에서 처리
- const result = await db.transaction(async (tx) => {
- // 1. itemCode로 직접 쿼리
- const existRows = await tx.select().from(items)
- .where(eq(items.itemCode, data.itemCode));
- const existingItem = existRows[0];
-
- let itemResult: any;
-
- if (existingItem) {
- // 기존 아이템이 있으면 업데이트하지 않고 그대로 사용
- itemResult = [existingItem]; // 배열 형태로 반환
- } else {
- // 없으면 새로 생성
- // 현재 가장 큰 ID 값 가져오기
- const maxIdResult = await tx.select({ maxId: sql`MAX(id)` }).from(items);
- const maxId = maxIdResult[0]?.maxId || 0;
- const newId = Number(maxId) + 1;
-
- // 새 ID로 아이템 생성
- itemResult = await tx.insert(items).values({
- id: newId,
- itemCode: data.itemCode,
- itemName: data.itemName,
- description: data.description,
- }).returning();
- }
-
- const [offshoreHull] = await tx
- .insert(itemOffshoreHull)
- .values({
- itemCode: data.itemCode,
- workType: data.workType,
- itemList: data.itemList,
- subItemList: data.subItemList,
- createdAt: new Date(),
- updatedAt: new Date()
- })
- .returning();
-
- return { itemData: itemResult[0], offshoreHullData: offshoreHull };
- })
+ const result = await db.insert(itemOffshoreHull).values({
+ itemCode: data.itemCode,
+ workType: data.workType,
+ itemList: data.itemList,
+ subItemList: data.subItemList,
+ createdAt: new Date(),
+ updatedAt: new Date()
+ }).returning();
revalidateTag("items")
return {
success: true,
- data: result,
+ data: result[0],
error: null
}
} catch (err) {
- console.error("아이템 생성/업데이트 오류:", err)
+ console.error("아이템 생성 오류:", err)
if (err instanceof Error && err.message.includes("unique constraint")) {
return {
@@ -716,58 +564,41 @@ export async function createOffshoreHullItem(data: OffshoreHullItemCreateData) { ----------------------------------------------------- */
// 업데이트 타입 정의 인터페이스
-interface UpdateShipbuildingItemInput extends UpdateItemSchema {
+interface UpdateShipbuildingItemInput {
id: number;
workType?: string;
shipTypes?: string;
itemList?: string;
itemCode?: string;
- itemName?: string;
- description?: string;
}
/** 단건 업데이트 */
export async function modifyShipbuildingItem(input: UpdateShipbuildingItemInput) {
unstable_noStore();
try {
- const result = await db.transaction(async (tx) => {
- // 기존 아이템 조회
- const existingShipbuilding = await tx.query.itemShipbuilding.findFirst({
- where: eq(itemShipbuilding.id, input.id),
- with: {
- item: true
- }
- });
-
- if (!existingShipbuilding) {
- throw new Error("아이템을 찾을 수 없습니다.");
- }
-
- // 세부 아이템 테이블만 업데이트 (items 테이블은 변경하지 않음)
- const updateData: Record<string, unknown> = {};
-
- if (input.workType) updateData.workType = input.workType as '기장' | '전장' | '선실' | '배관' | '철의';
- if (input.shipTypes) updateData.shipTypes = input.shipTypes;
- if (input.itemList !== undefined) updateData.itemList = input.itemList;
-
- if (Object.keys(updateData).length > 0) {
- await tx.update(itemShipbuilding)
- .set(updateData)
- .where(eq(itemShipbuilding.id, input.id));
- }
-
- return {
- data: { id: input.id },
- error: null,
- success: true,
- message: "아이템이 성공적으로 업데이트되었습니다."
- };
- });
+ const updateData: Record<string, unknown> = {};
+
+ if (input.workType) updateData.workType = input.workType as '기장' | '전장' | '선실' | '배관' | '철의';
+ if (input.shipTypes) updateData.shipTypes = input.shipTypes;
+ if (input.itemList !== undefined) updateData.itemList = input.itemList;
+ if (input.itemCode) updateData.itemCode = input.itemCode;
+
+ if (Object.keys(updateData).length > 0) {
+ updateData.updatedAt = new Date();
+ await db.update(itemShipbuilding)
+ .set(updateData)
+ .where(eq(itemShipbuilding.id, input.id));
+ }
// 캐시 무효화
revalidateTag("items");
- return result;
+ return {
+ data: { id: input.id },
+ error: null,
+ success: true,
+ message: "아이템이 성공적으로 업데이트되었습니다."
+ };
} catch (err) {
return {
data: null,
@@ -779,58 +610,41 @@ export async function modifyShipbuildingItem(input: UpdateShipbuildingItemInput) }
// Offshore TOP 업데이트 타입 정의 인터페이스
-interface UpdateOffshoreTopItemInput extends UpdateItemSchema {
+interface UpdateOffshoreTopItemInput {
id: number;
workType?: string;
itemList?: string;
subItemList?: string;
itemCode?: string;
- itemName?: string;
- description?: string;
}
/** Offshore TOP 단건 업데이트 */
export async function modifyOffshoreTopItem(input: UpdateOffshoreTopItemInput) {
unstable_noStore();
try {
- const result = await db.transaction(async (tx) => {
- // 기존 아이템 조회
- const existingOffshoreTop = await tx.query.itemOffshoreTop.findFirst({
- where: eq(itemOffshoreTop.id, input.id),
- with: {
- item: true
- }
- });
-
- if (!existingOffshoreTop) {
- throw new Error("아이템을 찾을 수 없습니다.");
- }
-
- // 세부 아이템 테이블만 업데이트 (items 테이블은 변경하지 않음)
- const updateData: Record<string, unknown> = {};
-
- if (input.workType) updateData.workType = input.workType as 'TM' | 'TS' | 'TE' | 'TP';
- if (input.itemList !== undefined) updateData.itemList = input.itemList;
- if (input.subItemList !== undefined) updateData.subItemList = input.subItemList;
-
- if (Object.keys(updateData).length > 0) {
- await tx.update(itemOffshoreTop)
- .set(updateData)
- .where(eq(itemOffshoreTop.id, input.id));
- }
-
- return {
- data: { id: input.id },
- error: null,
- success: true,
- message: "아이템이 성공적으로 업데이트되었습니다."
- };
- });
+ const updateData: Record<string, unknown> = {};
+
+ if (input.workType) updateData.workType = input.workType as 'TM' | 'TS' | 'TE' | 'TP';
+ if (input.itemList !== undefined) updateData.itemList = input.itemList;
+ if (input.subItemList !== undefined) updateData.subItemList = input.subItemList;
+ if (input.itemCode) updateData.itemCode = input.itemCode;
+
+ if (Object.keys(updateData).length > 0) {
+ updateData.updatedAt = new Date();
+ await db.update(itemOffshoreTop)
+ .set(updateData)
+ .where(eq(itemOffshoreTop.id, input.id));
+ }
// 캐시 무효화
revalidateTag("items");
- return result;
+ return {
+ data: { id: input.id },
+ error: null,
+ success: true,
+ message: "아이템이 성공적으로 업데이트되었습니다."
+ };
} catch (err) {
return {
data: null,
@@ -842,58 +656,41 @@ export async function modifyOffshoreTopItem(input: UpdateOffshoreTopItemInput) { }
// Offshore HULL 업데이트 타입 정의 인터페이스
-interface UpdateOffshoreHullItemInput extends UpdateItemSchema {
+interface UpdateOffshoreHullItemInput {
id: number;
workType?: string;
itemList?: string;
subItemList?: string;
itemCode?: string;
- itemName?: string;
- description?: string;
}
/** Offshore HULL 단건 업데이트 */
export async function modifyOffshoreHullItem(input: UpdateOffshoreHullItemInput) {
unstable_noStore();
try {
- const result = await db.transaction(async (tx) => {
- // 기존 아이템 조회
- const existingOffshoreHull = await tx.query.itemOffshoreHull.findFirst({
- where: eq(itemOffshoreHull.id, input.id),
- with: {
- item: true
- }
- });
-
- if (!existingOffshoreHull) {
- throw new Error("아이템을 찾을 수 없습니다.");
- }
-
- // 세부 아이템 테이블만 업데이트 (items 테이블은 변경하지 않음)
- const updateData: Record<string, unknown> = {};
-
- if (input.workType) updateData.workType = input.workType as 'HA' | 'HE' | 'HH' | 'HM' | 'NC';
- if (input.itemList !== undefined) updateData.itemList = input.itemList;
- if (input.subItemList !== undefined) updateData.subItemList = input.subItemList;
-
- if (Object.keys(updateData).length > 0) {
- await tx.update(itemOffshoreHull)
- .set(updateData)
- .where(eq(itemOffshoreHull.id, input.id));
- }
-
- return {
- data: { id: input.id },
- error: null,
- success: true,
- message: "아이템이 성공적으로 업데이트되었습니다."
- };
- });
+ const updateData: Record<string, unknown> = {};
+
+ if (input.workType) updateData.workType = input.workType as 'HA' | 'HE' | 'HH' | 'HM' | 'NC';
+ if (input.itemList !== undefined) updateData.itemList = input.itemList;
+ if (input.subItemList !== undefined) updateData.subItemList = input.subItemList;
+ if (input.itemCode) updateData.itemCode = input.itemCode;
+
+ if (Object.keys(updateData).length > 0) {
+ updateData.updatedAt = new Date();
+ await db.update(itemOffshoreHull)
+ .set(updateData)
+ .where(eq(itemOffshoreHull.id, input.id));
+ }
// 캐시 무효화
revalidateTag("items");
- return result;
+ return {
+ data: { id: input.id },
+ error: null,
+ success: true,
+ message: "아이템이 성공적으로 업데이트되었습니다."
+ };
} catch (err) {
return {
data: null,
@@ -921,11 +718,8 @@ interface DeleteItemsInput { export async function removeShipbuildingItem(input: DeleteItemInput) {
unstable_noStore();
try {
- await db.transaction(async (tx) => {
- // 세부 아이템만 삭제 (아이템 테이블은 유지)
- await tx.delete(itemShipbuilding)
- .where(eq(itemShipbuilding.id, input.id));
- });
+ await db.delete(itemShipbuilding)
+ .where(eq(itemShipbuilding.id, input.id));
revalidateTag("items");
@@ -949,13 +743,10 @@ export async function removeShipbuildingItem(input: DeleteItemInput) { export async function removeShipbuildingItems(input: DeleteItemsInput) {
unstable_noStore();
try {
- await db.transaction(async (tx) => {
- if (input.ids.length > 0) {
- // 세부 아이템만 삭제 (아이템 테이블은 유지)
- await tx.delete(itemShipbuilding)
- .where(inArray(itemShipbuilding.id, input.ids));
- }
- });
+ if (input.ids.length > 0) {
+ await db.delete(itemShipbuilding)
+ .where(inArray(itemShipbuilding.id, input.ids));
+ }
revalidateTag("items");
@@ -969,11 +760,8 @@ export async function removeShipbuildingItems(input: DeleteItemsInput) { export async function removeOffshoreTopItem(input: DeleteItemInput) {
unstable_noStore();
try {
- await db.transaction(async (tx) => {
- // 세부 아이템만 삭제 (아이템 테이블은 유지)
- await tx.delete(itemOffshoreTop)
- .where(eq(itemOffshoreTop.id, input.id));
- });
+ await db.delete(itemOffshoreTop)
+ .where(eq(itemOffshoreTop.id, input.id));
revalidateTag("items");
@@ -997,13 +785,10 @@ export async function removeOffshoreTopItem(input: DeleteItemInput) { export async function removeOffshoreTopItems(input: DeleteItemsInput) {
unstable_noStore();
try {
- await db.transaction(async (tx) => {
- if (input.ids.length > 0) {
- // 세부 아이템만 삭제 (아이템 테이블은 유지)
- await tx.delete(itemOffshoreTop)
- .where(inArray(itemOffshoreTop.id, input.ids));
- }
- });
+ if (input.ids.length > 0) {
+ await db.delete(itemOffshoreTop)
+ .where(inArray(itemOffshoreTop.id, input.ids));
+ }
revalidateTag("items");
@@ -1017,11 +802,8 @@ export async function removeOffshoreTopItems(input: DeleteItemsInput) { export async function removeOffshoreHullItem(input: DeleteItemInput) {
unstable_noStore();
try {
- await db.transaction(async (tx) => {
- // 세부 아이템만 삭제 (아이템 테이블은 유지)
- await tx.delete(itemOffshoreHull)
- .where(eq(itemOffshoreHull.id, input.id));
- });
+ await db.delete(itemOffshoreHull)
+ .where(eq(itemOffshoreHull.id, input.id));
revalidateTag("items");
@@ -1045,13 +827,10 @@ export async function removeOffshoreHullItem(input: DeleteItemInput) { export async function removeOffshoreHullItems(input: DeleteItemsInput) {
unstable_noStore();
try {
- await db.transaction(async (tx) => {
- if (input.ids.length > 0) {
- // 세부 아이템만 삭제 (아이템 테이블은 유지)
- await tx.delete(itemOffshoreHull)
- .where(inArray(itemOffshoreHull.id, input.ids));
- }
- });
+ if (input.ids.length > 0) {
+ await db.delete(itemOffshoreHull)
+ .where(inArray(itemOffshoreHull.id, input.ids));
+ }
revalidateTag("items");
@@ -1061,50 +840,17 @@ export async function removeOffshoreHullItems(input: DeleteItemsInput) { }
}
-export async function getAllShipbuildingItems(): Promise<Item[]> {
- try {
- return await findAllItems();
- } catch (error) {
- console.error("Failed to get items:", error);
- throw new Error("Failed to get items");
- }
-}
-export async function getAllOffshoreItems(): Promise<(ItemOffshoreHull | ItemOffshoreTop)[]> {
- try {
- return await findAllOffshoreItems();
- } catch (err) {
- throw new Error("Failed to get items");
- }
-}
-
-
-// -----------------------------------------------------------
-// 기술영업을 위한 로직
-// -----------------------------------------------------------
-
-// 조선 공종 타입
-export type WorkType = '기장' | '전장' | '선실' | '배관' | '철의'
-
-// 조선 아이템 with 공종 정보
-export interface ShipbuildingItem {
- id: number
- itemCode: string
- workType: WorkType
- itemList: string | null // 실제 아이템명
- shipTypes: string
- createdAt: Date
- updatedAt: Date
-}
+/* -----------------------------------------------------
+ 5) 조회 관련 추가 함수들
+----------------------------------------------------- */
-// 공종별 아이템 조회
+// 조선 공종별 아이템 조회
export async function getShipbuildingItemsByWorkType(workType?: WorkType, shipType?: string) {
try {
const query = db
.select({
id: itemShipbuilding.id,
itemCode: itemShipbuilding.itemCode,
- itemName: items.itemName,
- description: items.description,
workType: itemShipbuilding.workType,
itemList: itemShipbuilding.itemList,
shipTypes: itemShipbuilding.shipTypes,
@@ -1112,7 +858,6 @@ export async function getShipbuildingItemsByWorkType(workType?: WorkType, shipTy updatedAt: itemShipbuilding.updatedAt,
})
.from(itemShipbuilding)
- .leftJoin(items, eq(itemShipbuilding.itemCode, items.itemCode))
const conditions = []
if (workType) {
@@ -1141,14 +886,80 @@ export async function getShipbuildingItemsByWorkType(workType?: WorkType, shipTy }
}
+// 해양 TOP 공종별 아이템 조회
+export async function getOffshoreTopItemsByWorkType(workType?: OffshoreTopWorkType) {
+ try {
+ const query = db
+ .select({
+ id: itemOffshoreTop.id,
+ itemCode: itemOffshoreTop.itemCode,
+ workType: itemOffshoreTop.workType,
+ itemList: itemOffshoreTop.itemList,
+ subItemList: itemOffshoreTop.subItemList,
+ createdAt: itemOffshoreTop.createdAt,
+ updatedAt: itemOffshoreTop.updatedAt,
+ })
+ .from(itemOffshoreTop)
+
+ if (workType) {
+ query.where(eq(itemOffshoreTop.workType, workType))
+ }
+
+ const result = await query
+
+ return {
+ data: result as OffshoreTopTechItem[],
+ error: null
+ }
+ } catch (error) {
+ console.error("해양 TOP 아이템 조회 오류:", error)
+ return {
+ data: null,
+ error: error instanceof Error ? error.message : "알 수 없는 오류"
+ }
+ }
+}
+
+// 해양 HULL 공종별 아이템 조회
+export async function getOffshoreHullItemsByWorkType(workType?: OffshoreHullWorkType) {
+ try {
+ const query = db
+ .select({
+ id: itemOffshoreHull.id,
+ itemCode: itemOffshoreHull.itemCode,
+ workType: itemOffshoreHull.workType,
+ itemList: itemOffshoreHull.itemList,
+ subItemList: itemOffshoreHull.subItemList,
+ createdAt: itemOffshoreHull.createdAt,
+ updatedAt: itemOffshoreHull.updatedAt,
+ })
+ .from(itemOffshoreHull)
+
+ if (workType) {
+ query.where(eq(itemOffshoreHull.workType, workType))
+ }
+
+ const result = await query
+
+ return {
+ data: result as OffshoreHullTechItem[],
+ error: null
+ }
+ } catch (error) {
+ console.error("해양 HULL 아이템 조회 오류:", error)
+ return {
+ data: null,
+ error: error instanceof Error ? error.message : "알 수 없는 오류"
+ }
+ }
+}
+
// 아이템 검색
export async function searchShipbuildingItems(searchQuery: string, workType?: WorkType, shipType?: string) {
try {
const searchConditions = [
ilike(itemShipbuilding.itemCode, `%${searchQuery}%`),
- ilike(items.itemName, `%${searchQuery}%`),
- ilike(items.description, `%${searchQuery}%`),
- ilike(itemShipbuilding.itemList, `%${searchQuery}%`)
+ ilike(itemShipbuilding.itemList, `%${searchQuery}%`),
]
let whereCondition = or(...searchConditions)
@@ -1172,8 +983,6 @@ export async function searchShipbuildingItems(searchQuery: string, workType?: Wo .select({
id: itemShipbuilding.id,
itemCode: itemShipbuilding.itemCode,
- itemName: items.itemName,
- description: items.description,
workType: itemShipbuilding.workType,
itemList: itemShipbuilding.itemList,
shipTypes: itemShipbuilding.shipTypes,
@@ -1181,7 +990,6 @@ export async function searchShipbuildingItems(searchQuery: string, workType?: Wo updatedAt: itemShipbuilding.updatedAt,
})
.from(itemShipbuilding)
- .leftJoin(items, eq(itemShipbuilding.itemCode, items.itemCode))
.where(whereCondition)
return {
@@ -1197,6 +1005,94 @@ export async function searchShipbuildingItems(searchQuery: string, workType?: Wo }
}
+// 해양 TOP 아이템 검색
+export async function searchOffshoreTopItems(searchQuery: string, workType?: OffshoreTopWorkType) {
+ try {
+ const searchConditions = [
+ ilike(itemOffshoreTop.itemCode, `%${searchQuery}%`),
+ ilike(itemOffshoreTop.itemList, `%${searchQuery}%`),
+ ilike(itemOffshoreTop.subItemList, `%${searchQuery}%`)
+ ]
+
+ let whereCondition = or(...searchConditions)
+
+ if (workType) {
+ whereCondition = and(
+ eq(itemOffshoreTop.workType, workType),
+ or(...searchConditions)
+ )
+ }
+
+ const result = await db
+ .select({
+ id: itemOffshoreTop.id,
+ itemCode: itemOffshoreTop.itemCode,
+ workType: itemOffshoreTop.workType,
+ itemList: itemOffshoreTop.itemList,
+ subItemList: itemOffshoreTop.subItemList,
+ createdAt: itemOffshoreTop.createdAt,
+ updatedAt: itemOffshoreTop.updatedAt,
+ })
+ .from(itemOffshoreTop)
+ .where(whereCondition)
+
+ return {
+ data: result as OffshoreTopTechItem[],
+ error: null
+ }
+ } catch (error) {
+ console.error("해양 TOP 아이템 검색 오류:", error)
+ return {
+ data: null,
+ error: error instanceof Error ? error.message : "알 수 없는 오류"
+ }
+ }
+}
+
+// 해양 HULL 아이템 검색
+export async function searchOffshoreHullItems(searchQuery: string, workType?: OffshoreHullWorkType) {
+ try {
+ const searchConditions = [
+ ilike(itemOffshoreHull.itemCode, `%${searchQuery}%`),
+ ilike(itemOffshoreHull.itemList, `%${searchQuery}%`),
+ ilike(itemOffshoreHull.subItemList, `%${searchQuery}%`)
+ ]
+
+ let whereCondition = or(...searchConditions)
+
+ if (workType) {
+ whereCondition = and(
+ eq(itemOffshoreHull.workType, workType),
+ or(...searchConditions)
+ )
+ }
+
+ const result = await db
+ .select({
+ id: itemOffshoreHull.id,
+ itemCode: itemOffshoreHull.itemCode,
+ workType: itemOffshoreHull.workType,
+ itemList: itemOffshoreHull.itemList,
+ subItemList: itemOffshoreHull.subItemList,
+ createdAt: itemOffshoreHull.createdAt,
+ updatedAt: itemOffshoreHull.updatedAt,
+ })
+ .from(itemOffshoreHull)
+ .where(whereCondition)
+
+ return {
+ data: result as OffshoreHullTechItem[],
+ error: null
+ }
+ } catch (error) {
+ console.error("해양 HULL 아이템 검색 오류:", error)
+ return {
+ data: null,
+ error: error instanceof Error ? error.message : "알 수 없는 오류"
+ }
+ }
+}
+
// 모든 공종 목록 조회
export async function getWorkTypes() {
return [
@@ -1208,6 +1104,27 @@ export async function getWorkTypes() { ]
}
+// 해양 TOP 공종 목록 조회
+export async function getOffshoreTopWorkTypes() {
+ return [
+ { code: 'TM' as OffshoreTopWorkType, name: 'TM', description: 'Topside Manufacturing' },
+ { code: 'TS' as OffshoreTopWorkType, name: 'TS', description: 'Topside Steel' },
+ { code: 'TE' as OffshoreTopWorkType, name: 'TE', description: 'Topside Equipment' },
+ { code: 'TP' as OffshoreTopWorkType, name: 'TP', description: 'Topside Piping' },
+ ]
+}
+
+// 해양 HULL 공종 목록 조회
+export async function getOffshoreHullWorkTypes() {
+ return [
+ { code: 'HA' as OffshoreHullWorkType, name: 'HA', description: 'Hull Assembly' },
+ { code: 'HE' as OffshoreHullWorkType, name: 'HE', description: 'Hull Equipment' },
+ { code: 'HH' as OffshoreHullWorkType, name: 'HH', description: 'Hull Heating' },
+ { code: 'HM' as OffshoreHullWorkType, name: 'HM', description: 'Hull Manufacturing' },
+ { code: 'NC' as OffshoreHullWorkType, name: 'NC', description: 'No Category' },
+ ]
+}
+
// 특정 아이템 코드들로 아이템 조회
export async function getShipbuildingItemsByCodes(itemCodes: string[]) {
try {
@@ -1215,8 +1132,6 @@ export async function getShipbuildingItemsByCodes(itemCodes: string[]) { .select({
id: itemShipbuilding.id,
itemCode: itemShipbuilding.itemCode,
- itemName: items.itemName,
- description: items.description,
workType: itemShipbuilding.workType,
itemList: itemShipbuilding.itemList,
shipTypes: itemShipbuilding.shipTypes,
@@ -1224,7 +1139,6 @@ export async function getShipbuildingItemsByCodes(itemCodes: string[]) { updatedAt: itemShipbuilding.updatedAt,
})
.from(itemShipbuilding)
- .leftJoin(items, eq(itemShipbuilding.itemCode, items.itemCode))
.where(
or(...itemCodes.map(code => eq(itemShipbuilding.itemCode, code)))
)
@@ -1242,6 +1156,68 @@ export async function getShipbuildingItemsByCodes(itemCodes: string[]) { }
}
+// 해양 TOP 아이템 코드별 조회
+export async function getOffshoreTopItemsByCodes(itemCodes: string[]) {
+ try {
+ const result = await db
+ .select({
+ id: itemOffshoreTop.id,
+ itemCode: itemOffshoreTop.itemCode,
+ workType: itemOffshoreTop.workType,
+ itemList: itemOffshoreTop.itemList,
+ subItemList: itemOffshoreTop.subItemList,
+ createdAt: itemOffshoreTop.createdAt,
+ updatedAt: itemOffshoreTop.updatedAt,
+ })
+ .from(itemOffshoreTop)
+ .where(
+ or(...itemCodes.map(code => eq(itemOffshoreTop.itemCode, code)))
+ )
+
+ return {
+ data: result as OffshoreTopTechItem[],
+ error: null
+ }
+ } catch (error) {
+ console.error("해양 TOP 아이템 코드별 조회 오류:", error)
+ return {
+ data: null,
+ error: error instanceof Error ? error.message : "알 수 없는 오류"
+ }
+ }
+}
+
+// 해양 HULL 아이템 코드별 조회
+export async function getOffshoreHullItemsByCodes(itemCodes: string[]) {
+ try {
+ const result = await db
+ .select({
+ id: itemOffshoreHull.id,
+ itemCode: itemOffshoreHull.itemCode,
+ workType: itemOffshoreHull.workType,
+ itemList: itemOffshoreHull.itemList,
+ subItemList: itemOffshoreHull.subItemList,
+ createdAt: itemOffshoreHull.createdAt,
+ updatedAt: itemOffshoreHull.updatedAt,
+ })
+ .from(itemOffshoreHull)
+ .where(
+ or(...itemCodes.map(code => eq(itemOffshoreHull.itemCode, code)))
+ )
+
+ return {
+ data: result as OffshoreHullTechItem[],
+ error: null
+ }
+ } catch (error) {
+ console.error("해양 HULL 아이템 코드별 조회 오류:", error)
+ return {
+ data: null,
+ error: error instanceof Error ? error.message : "알 수 없는 오류"
+ }
+ }
+}
+
// 전체 조선 아이템 조회 (캐싱용)
export async function getAllShipbuildingItemsForCache() {
try {
@@ -1270,6 +1246,62 @@ export async function getAllShipbuildingItemsForCache() { }
}
+// 전체 해양 TOP 아이템 조회 (캐싱용)
+export async function getAllOffshoreTopItemsForCache() {
+ try {
+ const result = await db
+ .select({
+ id: itemOffshoreTop.id,
+ itemCode: itemOffshoreTop.itemCode,
+ workType: itemOffshoreTop.workType,
+ itemList: itemOffshoreTop.itemList,
+ subItemList: itemOffshoreTop.subItemList,
+ createdAt: itemOffshoreTop.createdAt,
+ updatedAt: itemOffshoreTop.updatedAt,
+ })
+ .from(itemOffshoreTop)
+
+ return {
+ data: result as OffshoreTopTechItem[],
+ error: null
+ }
+ } catch (error) {
+ console.error("전체 해양 TOP 아이템 조회 오류:", error)
+ return {
+ data: null,
+ error: error instanceof Error ? error.message : "알 수 없는 오류"
+ }
+ }
+}
+
+// 전체 해양 HULL 아이템 조회 (캐싱용)
+export async function getAllOffshoreHullItemsForCache() {
+ try {
+ const result = await db
+ .select({
+ id: itemOffshoreHull.id,
+ itemCode: itemOffshoreHull.itemCode,
+ workType: itemOffshoreHull.workType,
+ itemList: itemOffshoreHull.itemList,
+ subItemList: itemOffshoreHull.subItemList,
+ createdAt: itemOffshoreHull.createdAt,
+ updatedAt: itemOffshoreHull.updatedAt,
+ })
+ .from(itemOffshoreHull)
+
+ return {
+ data: result as OffshoreHullTechItem[],
+ error: null
+ }
+ } catch (error) {
+ console.error("전체 해양 HULL 아이템 조회 오류:", error)
+ return {
+ data: null,
+ error: error instanceof Error ? error.message : "알 수 없는 오류"
+ }
+ }
+}
+
// 선종 목록 가져오기
export async function getShipTypes() {
try {
|
