summaryrefslogtreecommitdiff
path: root/lib/items-tech
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-07-24 11:06:32 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-07-24 11:06:32 +0000
commit1dc24d48e52f2e490f5603ceb02842586ecae533 (patch)
tree8fca2c5b5b52cc10557b5ba6e55b937ae3c57cf6 /lib/items-tech
parented0d6fcc98f671280c2ccde797b50693da88152e (diff)
(대표님) 정기평가 피드백 반영, 설계 피드백 반영, (최겸) 기술영업 피드백 반영
Diffstat (limited to 'lib/items-tech')
-rw-r--r--lib/items-tech/service.ts42
-rw-r--r--lib/items-tech/table/add-items-dialog.tsx38
-rw-r--r--lib/items-tech/table/hull/offshore-hull-table-columns.tsx2
-rw-r--r--lib/items-tech/table/top/import-item-handler.tsx4
-rw-r--r--lib/items-tech/table/top/offshore-top-table-columns.tsx2
-rw-r--r--lib/items-tech/table/top/offshore-top-table-toolbar-actions.tsx2
-rw-r--r--lib/items-tech/table/top/offshore-top-table.tsx3
-rw-r--r--lib/items-tech/table/update-items-sheet.tsx56
-rw-r--r--lib/items-tech/validations.ts6
9 files changed, 113 insertions, 42 deletions
diff --git a/lib/items-tech/service.ts b/lib/items-tech/service.ts
index d93c5f96..e0896144 100644
--- a/lib/items-tech/service.ts
+++ b/lib/items-tech/service.ts
@@ -14,7 +14,7 @@ import { itemShipbuilding, itemOffshoreTop, itemOffshoreHull } from "@/db/schema
// 타입 정의 추가
export type ShipbuildingWorkType = '기장' | '전장' | '선실' | '배관' | '철의' | '선체';
-export type OffshoreTopWorkType = 'TM' | 'TS' | 'TE' | 'TP';
+export type OffshoreTopWorkType = 'TM' | 'TS' | 'TE' | 'TP' | 'TA';
export type OffshoreHullWorkType = 'HA' | 'HE' | 'HH' | 'HM' | 'HO' | 'HP' | 'NC';
export interface ShipbuildingItem {
@@ -415,6 +415,27 @@ export async function createShipbuildingItem(input: TypedItemCreateData) {
}
const shipData = input as ShipbuildingItemCreateData;
+
+ // 아이템코드 + 선종 조합으로 중복 체크
+ if (input.itemCode && shipData.shipTypes) {
+ const existingItem = await db.select().from(itemShipbuilding)
+ .where(
+ and(
+ eq(itemShipbuilding.itemCode, input.itemCode),
+ eq(itemShipbuilding.shipTypes, shipData.shipTypes)
+ )
+ );
+
+ if (existingItem.length > 0) {
+ return {
+ success: false,
+ message: "중복된 아이템코드 및 선종입니다",
+ data: null,
+ error: "중복 키 오류"
+ }
+ }
+ }
+
const result = await db.insert(itemShipbuilding).values({
itemCode: input.itemCode || "",
workType: shipData.workType ? (shipData.workType as '기장' | '전장' | '선실' | '배관' | '철의' | '선체') : '기장',
@@ -437,7 +458,7 @@ export async function createShipbuildingItem(input: TypedItemCreateData) {
if (err instanceof Error && err.message.includes("unique constraint")) {
return {
success: false,
- message: "이미 존재하는 아이템 코드입니다",
+ message: "중복된 아이템코드 및 선종입니다",
data: null,
error: "중복 키 오류"
}
@@ -488,7 +509,7 @@ export async function createShipbuildingImportItem(input: {
if (existingItem.length > 0) {
return {
success: false,
- message: "이미 존재하는 아이템 코드 및 선종입니다",
+ message: "중복된 아이템코드 및 선종입니다",
data: null,
error: "중복 키 오류"
}
@@ -517,7 +538,7 @@ export async function createShipbuildingImportItem(input: {
if (err instanceof Error && err.message.includes("unique constraint")) {
return {
success: false,
- message: "이미 존재하는 아이템 코드 및 선종입니다",
+ message: "중복된 아이템코드 및 선종입니다",
data: null,
error: "중복 키 오류"
}
@@ -557,7 +578,7 @@ export async function createOffshoreTopItem(data: OffshoreTopItemCreateData) {
if (existingItem.length > 0) {
return {
success: false,
- message: "이미 존재하는 아이템 코드입니다",
+ message: "중복된 아이템 코드입니다",
data: null,
error: "중복 키 오류"
};
@@ -586,7 +607,7 @@ export async function createOffshoreTopItem(data: OffshoreTopItemCreateData) {
if (err instanceof Error && err.message.includes("unique constraint")) {
return {
success: false,
- message: "이미 존재하는 아이템 코드입니다",
+ message: "중복된 아이템 코드입니다",
data: null,
error: "중복 키 오류"
};
@@ -626,7 +647,7 @@ export async function createOffshoreHullItem(data: OffshoreHullItemCreateData) {
if (existingItem.length > 0) {
return {
success: false,
- message: "이미 존재하는 아이템 코드입니다",
+ message: "중복된 아이템 코드입니다",
data: null,
error: "중복 키 오류"
};
@@ -655,7 +676,7 @@ export async function createOffshoreHullItem(data: OffshoreHullItemCreateData) {
if (err instanceof Error && err.message.includes("unique constraint")) {
return {
success: false,
- message: "이미 존재하는 아이템 코드입니다",
+ message: "중복된 아이템 코드입니다",
data: null,
error: "중복 키 오류"
};
@@ -735,7 +756,7 @@ export async function modifyOffshoreTopItem(input: UpdateOffshoreTopItemInput) {
try {
const updateData: Record<string, unknown> = {};
- if (input.workType) updateData.workType = input.workType as 'TM' | 'TS' | 'TE' | 'TP';
+ if (input.workType) updateData.workType = input.workType as 'TM' | 'TS' | 'TE' | 'TP' | 'TA';
if (input.itemList !== undefined) updateData.itemList = input.itemList;
if (input.subItemList !== undefined) updateData.subItemList = input.subItemList;
if (input.itemCode) updateData.itemCode = input.itemCode;
@@ -781,7 +802,7 @@ export async function modifyOffshoreHullItem(input: UpdateOffshoreHullItemInput)
try {
const updateData: Record<string, unknown> = {};
- if (input.workType) updateData.workType = input.workType as 'HA' | 'HE' | 'HH' | 'HM' | 'NC';
+ if (input.workType) updateData.workType = input.workType as 'HA' | 'HE' | 'HH' | 'HM' | 'HO' | 'HP' | 'NC';
if (input.itemList !== undefined) updateData.itemList = input.itemList;
if (input.subItemList !== undefined) updateData.subItemList = input.subItemList;
if (input.itemCode) updateData.itemCode = input.itemCode;
@@ -1222,6 +1243,7 @@ export async function getOffshoreTopWorkTypes() {
{ code: 'TS' as OffshoreTopWorkType, name: 'TS'},
{ code: 'TE' as OffshoreTopWorkType, name: 'TE'},
{ code: 'TP' as OffshoreTopWorkType, name: 'TP'},
+ { code: 'TA' as OffshoreTopWorkType, name: 'TA'},
]
}
diff --git a/lib/items-tech/table/add-items-dialog.tsx b/lib/items-tech/table/add-items-dialog.tsx
index 1b0d00c7..01a072da 100644
--- a/lib/items-tech/table/add-items-dialog.tsx
+++ b/lib/items-tech/table/add-items-dialog.tsx
@@ -53,6 +53,7 @@ const offshoreTopWorkTypes = [
{ label: "TS", value: "TS" },
{ label: "TE", value: "TE" },
{ label: "TP", value: "TP" },
+ { label: "TA", value: "TA" },
] as const
// 해양 HULL 공종 유형 정의
@@ -68,7 +69,7 @@ const offshoreHullWorkTypes = [
// 기본 아이템 스키마
const itemFormSchema = z.object({
- itemCode: z.string().optional(),
+ itemCode: z.string(),
workType: z.string().min(1, "공종은 필수입니다"),
// 조선 및 해양 아이템 공통 필드
itemList: z.string().optional(),
@@ -126,6 +127,8 @@ export function AddItemDialog({ itemType }: AddItemDialogProps) {
const onSubmit = async (data: ItemFormValues) => {
startAddTransition(async () => {
try {
+ let result;
+
switch (itemType) {
case 'shipbuilding':
if (!data.shipTypes) {
@@ -133,7 +136,7 @@ export function AddItemDialog({ itemType }: AddItemDialogProps) {
return
}
- await createShipbuildingItem({
+ result = await createShipbuildingItem({
itemCode: data.itemCode || "",
workType: data.workType as "기장" | "전장" | "선실" | "배관" | "철의" | "선체",
shipTypes: data.shipTypes,
@@ -142,16 +145,16 @@ export function AddItemDialog({ itemType }: AddItemDialogProps) {
break;
case 'offshoreTop':
- await createOffshoreTopItem({
+ result = await createOffshoreTopItem({
itemCode: data.itemCode || "",
- workType: data.workType as "TM" | "TS" | "TE" | "TP",
+ workType: data.workType as "TM" | "TS" | "TE" | "TP" | "TA",
itemList: data.itemList || null,
subItemList: data.subItemList || null
});
break;
case 'offshoreHull':
- await createOffshoreHullItem({
+ result = await createOffshoreHullItem({
itemCode: data.itemCode || "",
workType: data.workType as "HA" | "HE" | "HH" | "HM" | "HO" | "HP" | "NC",
itemList: data.itemList || null,
@@ -164,10 +167,15 @@ export function AddItemDialog({ itemType }: AddItemDialogProps) {
return;
}
- toast.success("아이템이 성공적으로 추가되었습니다")
- setOpen(false)
- form.reset(getDefaultValues())
- router.refresh()
+ // 결과 확인하여 성공/실패에 따라 다른 메시지 표시
+ if (result?.success) {
+ toast.success("아이템이 성공적으로 추가되었습니다")
+ setOpen(false)
+ form.reset(getDefaultValues())
+ router.refresh()
+ } else {
+ toast.error(result?.message || "아이템 추가에 실패했습니다")
+ }
} catch (error) {
toast.error("아이템 추가 중 오류가 발생했습니다")
console.error(error)
@@ -225,7 +233,9 @@ export function AddItemDialog({ itemType }: AddItemDialogProps) {
name="itemCode"
render={({ field }) => (
<FormItem>
- <FormLabel>아이템 코드</FormLabel>
+ <FormLabel>
+ 자재 그룹 <span style={{ color: 'red' }}>*</span>
+ </FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
@@ -238,7 +248,7 @@ export function AddItemDialog({ itemType }: AddItemDialogProps) {
name="workType"
render={({ field }) => (
<FormItem>
- <FormLabel>공종</FormLabel>
+ <FormLabel>공종 <span style={{ color: 'red' }}>*</span></FormLabel>
<Select onValueChange={field.onChange} defaultValue={field.value}>
<FormControl>
<SelectTrigger>
@@ -264,7 +274,7 @@ export function AddItemDialog({ itemType }: AddItemDialogProps) {
name="shipTypes"
render={({ field }) => (
<FormItem>
- <FormLabel>선종</FormLabel>
+ <FormLabel>선종 <span style={{ color: 'red' }}>*</span></FormLabel>
<FormControl>
<Input placeholder="선종을 입력하세요" {...field} />
</FormControl>
@@ -294,7 +304,7 @@ export function AddItemDialog({ itemType }: AddItemDialogProps) {
name="itemList"
render={({ field }) => (
<FormItem>
- <FormLabel>아이템 리스트</FormLabel>
+ <FormLabel>자재명</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
@@ -307,7 +317,7 @@ export function AddItemDialog({ itemType }: AddItemDialogProps) {
name="subItemList"
render={({ field }) => (
<FormItem>
- <FormLabel>서브 아이템 리스트</FormLabel>
+ <FormLabel>자재명(상세)</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
diff --git a/lib/items-tech/table/hull/offshore-hull-table-columns.tsx b/lib/items-tech/table/hull/offshore-hull-table-columns.tsx
index efc6c583..1ad9035c 100644
--- a/lib/items-tech/table/hull/offshore-hull-table-columns.tsx
+++ b/lib/items-tech/table/hull/offshore-hull-table-columns.tsx
@@ -22,7 +22,7 @@ import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-
interface OffshoreHullTableItem {
id: number;
itemId: number;
- workType: "HA" | "HE" | "HH" | "HM" | "NC";
+ workType: "HA" | "HE" | "HH" | "HM" | "HO" | "HP" | "NC";
itemList: string | null;
subItemList: string | null;
itemCode: string;
diff --git a/lib/items-tech/table/top/import-item-handler.tsx b/lib/items-tech/table/top/import-item-handler.tsx
index 4f34cff2..0197d826 100644
--- a/lib/items-tech/table/top/import-item-handler.tsx
+++ b/lib/items-tech/table/top/import-item-handler.tsx
@@ -4,7 +4,7 @@ import { z } from "zod"
import { createOffshoreTopItem } from "../../service"
// 해양 TOP 기능(공종) 유형 enum
-const TOP_WORK_TYPES = ["TM", "TS", "TE", "TP"] as const;
+const TOP_WORK_TYPES = ["TM", "TS", "TE", "TP", "TA"] as const;
// 아이템 데이터 검증을 위한 Zod 스키마
const itemSchema = z.object({
@@ -92,7 +92,7 @@ export async function processTopFileImport(
// 해양 TOP 아이템 생성
const result = await createOffshoreTopItem({
itemCode: cleanedRow.itemCode,
- workType: cleanedRow.workType as "TM" | "TS" | "TE" | "TP",
+ workType: cleanedRow.workType as "TM" | "TS" | "TE" | "TP" | "TA",
itemList: cleanedRow.itemList,
subItemList: cleanedRow.subItemList,
});
diff --git a/lib/items-tech/table/top/offshore-top-table-columns.tsx b/lib/items-tech/table/top/offshore-top-table-columns.tsx
index 93f27492..e1572e0c 100644
--- a/lib/items-tech/table/top/offshore-top-table-columns.tsx
+++ b/lib/items-tech/table/top/offshore-top-table-columns.tsx
@@ -22,7 +22,7 @@ import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-
interface OffshoreTopTableItem {
id: number;
itemId: number;
- workType: "TM" | "TS" | "TE" | "TP";
+ workType: "TM" | "TS" | "TE" | "TP" | "TA";
itemList: string | null;
subItemList: string | null;
itemCode: string;
diff --git a/lib/items-tech/table/top/offshore-top-table-toolbar-actions.tsx b/lib/items-tech/table/top/offshore-top-table-toolbar-actions.tsx
index bf10560f..c81feda0 100644
--- a/lib/items-tech/table/top/offshore-top-table-toolbar-actions.tsx
+++ b/lib/items-tech/table/top/offshore-top-table-toolbar-actions.tsx
@@ -23,7 +23,7 @@ import { ImportItemButton } from "../import-excel-button"
interface OffshoreTopItem {
id: number;
itemId: number;
- workType: "TM" | "TS" | "TE" | "TP";
+ workType: "TM" | "TS" | "TE" | "TP" | "TA";
itemList: string | null;
subItemList: string | null;
itemCode: string;
diff --git a/lib/items-tech/table/top/offshore-top-table.tsx b/lib/items-tech/table/top/offshore-top-table.tsx
index c038de13..dc76a06a 100644
--- a/lib/items-tech/table/top/offshore-top-table.tsx
+++ b/lib/items-tech/table/top/offshore-top-table.tsx
@@ -20,7 +20,7 @@ import { UpdateItemSheet } from "../update-items-sheet"
type OffshoreTopItem = {
id: number;
itemId: number;
- workType: "TM" | "TS" | "TE" | "TP";
+ workType: "TM" | "TS" | "TE" | "TP" | "TA";
itemList: string | null;
subItemList: string | null;
itemCode: string;
@@ -74,6 +74,7 @@ export function OffshoreTopTable({ promises }: OffshoreTopTableProps) {
{ label: "TS", value: "TS" },
{ label: "TE", value: "TE" },
{ label: "TP", value: "TP" },
+ { label: "TA", value: "TA" },
],
},
{
diff --git a/lib/items-tech/table/update-items-sheet.tsx b/lib/items-tech/table/update-items-sheet.tsx
index 978e83d5..91108ba0 100644
--- a/lib/items-tech/table/update-items-sheet.tsx
+++ b/lib/items-tech/table/update-items-sheet.tsx
@@ -52,6 +52,7 @@ const offshoreTopWorkTypes = [
{ value: "TS", label: "TS" },
{ value: "TE", label: "TE" },
{ value: "TP", label: "TP" },
+ { value: "TA", label: "TA" },
] as const
const offshoreHullWorkTypes = [
@@ -76,7 +77,7 @@ type ShipbuildingItem = {
type OffshoreTopItem = {
id: number
itemCode: string
- workType: "TM" | "TS" | "TE" | "TP"
+ workType: "TM" | "TS" | "TE" | "TP" | "TA"
itemList: string | null
subItemList: string | null
}
@@ -94,6 +95,7 @@ type UpdateItemSchema = {
workType?: string
shipTypes?: string
itemList?: string
+ subItemList?: string
}
interface UpdateItemSheetProps {
@@ -125,11 +127,16 @@ export function UpdateItemSheet({ item, itemType, open, onOpenChange }: UpdateIt
itemList: (item as ShipbuildingItem).itemList || "",
};
case 'offshoreTop':
+ const offshoreTopItem = item as OffshoreTopItem;
+ return {
+ itemList: offshoreTopItem.itemList || "",
+ subItemList: offshoreTopItem.subItemList || ""
+ };
case 'offshoreHull':
- const offshoreItem = item as OffshoreTopItem | OffshoreHullItem;
+ const offshoreHullItem = item as OffshoreHullItem;
return {
- itemList: offshoreItem.itemList || "",
- subItemList: offshoreItem.subItemList || ""
+ itemList: offshoreHullItem.itemList || "",
+ subItemList: offshoreHullItem.subItemList || ""
};
default:
return {};
@@ -224,7 +231,7 @@ export function UpdateItemSheet({ item, itemType, open, onOpenChange }: UpdateIt
<div className="mt-4">
<div className="grid gap-2">
<label className="text-sm font-medium leading-none">
- Material Group (수정 불가)
+ 자재 그룹 (수정 불가)
</label>
<Input value={item.itemCode} disabled readOnly />
</div>
@@ -235,7 +242,7 @@ export function UpdateItemSheet({ item, itemType, open, onOpenChange }: UpdateIt
name="workType"
render={({ field }) => (
<FormItem>
- <FormLabel>기능(공종)</FormLabel>
+ <FormLabel>기능(공종) <span style={{ color: 'red' }}>*</span></FormLabel>
<Select
onValueChange={field.onChange}
defaultValue={field.value}
@@ -266,7 +273,7 @@ export function UpdateItemSheet({ item, itemType, open, onOpenChange }: UpdateIt
name="shipTypes"
render={({ field }) => (
<FormItem>
- <FormLabel>선종</FormLabel>
+ <FormLabel>선종 <span style={{ color: 'red' }}>*</span></FormLabel>
<FormControl>
<Input placeholder="선종을 입력하세요" {...field} />
</FormControl>
@@ -281,14 +288,45 @@ export function UpdateItemSheet({ item, itemType, open, onOpenChange }: UpdateIt
name="itemList"
render={({ field }) => (
<FormItem>
- <FormLabel>아이템 리스트</FormLabel>
+ <FormLabel>자재명</FormLabel>
<FormControl>
- <Input placeholder="아이템 리스트를 입력하세요" {...field} />
+ <Input placeholder="자재명을 입력하세요" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
+ {itemType === 'offshoreHull' && (
+ <FormField
+ control={form.control}
+ name="subItemList"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>자재명(상세)</FormLabel>
+ <FormControl>
+ <Input placeholder="자재명(상세)을 입력하세요" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+ )}
+ {itemType === 'offshoreTop' && (
+ <FormField
+ control={form.control}
+ name="subItemList"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>자재명(상세)</FormLabel>
+ <FormControl>
+ <Input placeholder="자재명(상세)을 입력하세요" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+ )}
+
<SheetFooter>
<SheetClose asChild>
<Button variant="outline">취소</Button>
diff --git a/lib/items-tech/validations.ts b/lib/items-tech/validations.ts
index 95a34b58..ec662320 100644
--- a/lib/items-tech/validations.ts
+++ b/lib/items-tech/validations.ts
@@ -107,7 +107,7 @@ export type TypedItemCreateData = ShipbuildingItemCreateData
// 해양 TOP 아이템 스키마
export const createOffshoreTopItemSchema = z.object({
itemCode: z.string(),
- workType: z.enum(["TM", "TS", "TE", "TP"]),
+ workType: z.enum(["TM", "TS", "TE", "TP", "TA"]),
itemList: z.string().optional(),
subItemList: z.string().optional(),
})
@@ -126,7 +126,7 @@ export type CreateOffshoreHullItemSchema = z.infer<typeof createOffshoreHullItem
// 해양 TOP 아이템 업데이트 스키마
export const updateOffshoreTopItemSchema = z.object({
itemCode: z.string(),
- workType: z.enum(["TM", "TS", "TE", "TP"]).optional(),
+ workType: z.enum(["TM", "TS", "TE", "TP", "TA"]).optional(),
itemList: z.string().optional(),
subItemList: z.string().optional(),
})
@@ -145,7 +145,7 @@ export type UpdateOffshoreHullItemSchema = z.infer<typeof updateOffshoreHullItem
// 해양 TOP 아이템 생성 데이터 타입
export interface OffshoreTopItemCreateData {
itemCode: string
- workType: "TM" | "TS" | "TE" | "TP"
+ workType: "TM" | "TS" | "TE" | "TP" | "TA"
itemList?: string | null
subItemList?: string | null
}