summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-07-03 01:59:36 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-07-03 01:59:36 +0000
commitde4c8a6a6b7c918a7a16fc34423d1143209c295f (patch)
tree9fbf0b93e5cbe9c3a8ca18c8bcd4dda5bf9640c5
parentdeb2d31dba913a3b831523f41b9bf2e286c53af1 (diff)
(최겸) 기술영업 벤더 공종 조회 기능 추가
-rw-r--r--config/techVendorColumnsConfig.ts9
-rw-r--r--db/schema/techVendors.ts13
-rw-r--r--lib/tech-vendors/items-table/add-item-dialog.tsx20
-rw-r--r--lib/tech-vendors/items-table/item-table-toolbar-actions.tsx2
-rw-r--r--lib/tech-vendors/service.ts88
-rw-r--r--lib/tech-vendors/table/tech-vendors-table-columns.tsx9
-rw-r--r--lib/tech-vendors/table/tech-vendors-table.tsx43
-rw-r--r--lib/tech-vendors/table/update-vendor-sheet.tsx21
-rw-r--r--lib/tech-vendors/utils.ts2
-rw-r--r--lib/tech-vendors/validations.ts18
10 files changed, 153 insertions, 72 deletions
diff --git a/config/techVendorColumnsConfig.ts b/config/techVendorColumnsConfig.ts
index c4b85b7b..f7fd4478 100644
--- a/config/techVendorColumnsConfig.ts
+++ b/config/techVendorColumnsConfig.ts
@@ -32,20 +32,23 @@ export const techVendorColumnsConfig: VendorColumnConfig[] = [
label: "업체 코드",
excelHeader: "업체 코드",
},
-
{
id: "vendorName",
label: "업체명",
excelHeader: "업체명",
},
-
{
id: "techVendorType",
label: "벤더 타입",
excelHeader: "벤더 타입",
type: "string",
},
-
+ {
+ id: "workTypes",
+ label: "Work Type",
+ excelHeader: "Work Type",
+ type: "string",
+ },
{
id: "taxId",
label: "세금 ID",
diff --git a/db/schema/techVendors.ts b/db/schema/techVendors.ts
index 9cb15ad8..113a5a1a 100644
--- a/db/schema/techVendors.ts
+++ b/db/schema/techVendors.ts
@@ -30,7 +30,8 @@ export const techVendors = pgTable("tech_vendors", {
enum: [
"ACTIVE",
"INACTIVE",
- "BLACKLISTED"
+ "BLACKLISTED",
+ "PENDING_REVIEW"
]
}).default("ACTIVE").notNull(),
// 대표자 정보
@@ -57,10 +58,7 @@ export const techVendorPossibleItems = pgTable("tech_vendor_possible_items", {
id: serial("id").primaryKey(),
vendorId: integer("vendor_id").notNull().references(() => techVendors.id),
// itemId: integer("item_id"), // 별도 item 테이블 연동시
- itemCode: varchar("item_code", { length: 100 })
- .notNull()
- .references(() => items.itemCode, { onDelete: "cascade" }),
- itemName: varchar("item_name", { length: 255 }).notNull(),
+ itemCode: varchar("item_code", { length: 100 }).notNull(),
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at").defaultNow().notNull(),
});
@@ -83,7 +81,6 @@ export const techVendorItemsView = pgView("tech_vendor_items_view").as((qb) => {
vendorItemId: techVendorPossibleItems.id,
vendorId: techVendorPossibleItems.vendorId,
itemCode: items.itemCode,
- itemName: items.itemName,
createdAt: techVendorPossibleItems.createdAt,
updatedAt: techVendorPossibleItems.updatedAt,
})
@@ -173,8 +170,7 @@ export const techVendorDetailView = pgView("tech_vendor_detail_view").as((qb) =>
(SELECT COALESCE(
json_agg(
json_build_object(
- 'itemCode', i.item_code,
- 'itemName', it.item_name
+ 'itemCode', i.item_code
)
),
'[]'::json
@@ -266,4 +262,5 @@ export type TechVendorCandidate = typeof techVendorCandidates.$inferSelect
export type TechVendorWithAttachments = TechVendor & {
hasAttachments?: boolean;
attachmentsList?: TechVendorAttach[];
+ workTypes?: string;
} \ No newline at end of file
diff --git a/lib/tech-vendors/items-table/add-item-dialog.tsx b/lib/tech-vendors/items-table/add-item-dialog.tsx
index e4d74204..21875295 100644
--- a/lib/tech-vendors/items-table/add-item-dialog.tsx
+++ b/lib/tech-vendors/items-table/add-item-dialog.tsx
@@ -79,8 +79,8 @@ export function AddItemDialog({ vendorId }: AddItemDialogProps) {
if (result.data) {
console.log(`[AddItemDialog] 사용 가능한 아이템 목록:`, result.data)
- setItems(result.data)
- setFilteredItems(result.data)
+ setItems(result.data as ItemDropdownOption[])
+ setFilteredItems(result.data as ItemDropdownOption[])
} else if (result.error) {
console.error("[AddItemDialog] 아이템 조회 실패:", result.error)
toast.error(result.error)
@@ -113,8 +113,8 @@ export function AddItemDialog({ vendorId }: AddItemDialogProps) {
const lowerSearch = searchTerm.toLowerCase()
const filtered = items.filter(item =>
item.itemCode.toLowerCase().includes(lowerSearch) ||
- item.itemName.toLowerCase().includes(lowerSearch) ||
- (item.description && item.description.toLowerCase().includes(lowerSearch))
+ item.itemList.toLowerCase().includes(lowerSearch) ||
+ (item.subItemList && item.subItemList.toLowerCase().includes(lowerSearch))
)
console.log(`[AddItemDialog] 필터링 결과: ${filtered.length}개 아이템`)
@@ -125,13 +125,13 @@ export function AddItemDialog({ vendorId }: AddItemDialogProps) {
console.log(`[AddItemDialog] 아이템 선택: ${item.itemCode}`)
form.setValue("itemCode", item.itemCode, { shouldValidate: true })
setSelectedItem({
- itemName: item.itemName,
- description: item.description || "",
+ itemName: item.itemList,
+ description: item.subItemList || "",
})
console.log(`[AddItemDialog] 선택된 아이템 정보:`, {
itemCode: item.itemCode,
- itemName: item.itemName,
- description: item.description || ""
+ itemName: item.itemList,
+ description: item.subItemList || ""
})
setCommandOpen(false)
}
@@ -241,7 +241,7 @@ export function AddItemDialog({ vendorId }: AddItemDialogProps) {
{filteredItems.map((item) => (
<CommandItem
key={item.itemCode}
- value={`${item.itemCode} ${item.itemName}`}
+ value={`${item.itemCode} ${item.itemList}`}
onSelect={() => handleSelectItem(item)}
>
<Check
@@ -253,7 +253,7 @@ export function AddItemDialog({ vendorId }: AddItemDialogProps) {
)}
/>
<span className="font-medium">{item.itemCode}</span>
- <span className="ml-2 text-gray-500 truncate">- {item.itemName}</span>
+ <span className="ml-2 text-gray-500 truncate">- {item.itemList}</span>
</CommandItem>
))}
</CommandGroup>
diff --git a/lib/tech-vendors/items-table/item-table-toolbar-actions.tsx b/lib/tech-vendors/items-table/item-table-toolbar-actions.tsx
index 68a20816..b327ff56 100644
--- a/lib/tech-vendors/items-table/item-table-toolbar-actions.tsx
+++ b/lib/tech-vendors/items-table/item-table-toolbar-actions.tsx
@@ -65,7 +65,7 @@ export function TechVendorItemsTableToolbarActions({ table, vendorId, vendorType
return (
<div className="flex items-center gap-2">
- <AddItemDialog vendorId={vendorId} vendorType={vendorType} />
+ {/* <AddItemDialog vendorId={vendorId} vendorType={vendorType} /> */}
{/** 3) Import 버튼 (파일 업로드) */}
<Button variant="outline" size="sm" className="gap-2" onClick={handleImportClick}>
diff --git a/lib/tech-vendors/service.ts b/lib/tech-vendors/service.ts
index 5fd5ef02..15e7331b 100644
--- a/lib/tech-vendors/service.ts
+++ b/lib/tech-vendors/service.ts
@@ -40,6 +40,7 @@ import fs from "fs/promises";
import { randomUUID } from "crypto";
import { sql } from "drizzle-orm";
import { users } from "@/db/schema/users";
+import { decryptWithServerAction } from "@/components/drm/drmUtils";
/* -----------------------------------------------------
1) 조회 관련
@@ -56,10 +57,14 @@ export async function getTechVendors(input: GetTechVendorsSchema) {
try {
const offset = (input.page - 1) * input.perPage;
- // 1) 고급 필터
+ // 1) 고급 필터 (workTypes와 techVendorType 제외 - 별도 처리)
+ const filteredFilters = input.filters.filter(
+ filter => filter.id !== "workTypes" && filter.id !== "techVendorType"
+ );
+
const advancedWhere = filterColumns({
table: techVendors,
- filters: input.filters,
+ filters: filteredFilters,
joinOperator: input.joinOperator,
});
@@ -108,8 +113,47 @@ export async function getTechVendors(input: GetTechVendorsSchema) {
: undefined
);
- // 실제 사용될 where (vendorType 필터링 추가)
- const where = and(finalWhere, vendorTypeWhere);
+ // TechVendorType 필터링 로직 추가 (고급 필터에서)
+ let techVendorTypeWhere;
+ const techVendorTypeFilters = input.filters.filter(filter => filter.id === "techVendorType");
+ if (techVendorTypeFilters.length > 0) {
+ const typeFilter = techVendorTypeFilters[0];
+ if (Array.isArray(typeFilter.value) && typeFilter.value.length > 0) {
+ // 각 타입에 대해 LIKE 조건으로 OR 연결
+ const typeConditions = typeFilter.value.map(type =>
+ ilike(techVendors.techVendorType, `%${type}%`)
+ );
+ techVendorTypeWhere = or(...typeConditions);
+ }
+ }
+
+ // WorkTypes 필터링 로직 추가
+ let workTypesWhere;
+ const workTypesFilters = input.filters.filter(filter => filter.id === "workTypes");
+ if (workTypesFilters.length > 0) {
+ const workTypeFilter = workTypesFilters[0];
+ if (Array.isArray(workTypeFilter.value) && workTypeFilter.value.length > 0) {
+ // workTypes에 해당하는 벤더 ID들을 서브쿼리로 찾음
+ const vendorIdsWithWorkTypes = db
+ .selectDistinct({ vendorId: techVendorPossibleItems.vendorId })
+ .from(techVendorPossibleItems)
+ .leftJoin(itemShipbuilding, eq(techVendorPossibleItems.itemCode, itemShipbuilding.itemCode))
+ .leftJoin(itemOffshoreTop, eq(techVendorPossibleItems.itemCode, itemOffshoreTop.itemCode))
+ .leftJoin(itemOffshoreHull, eq(techVendorPossibleItems.itemCode, itemOffshoreHull.itemCode))
+ .where(
+ or(
+ inArray(itemShipbuilding.workType, workTypeFilter.value),
+ inArray(itemOffshoreTop.workType, workTypeFilter.value),
+ inArray(itemOffshoreHull.workType, workTypeFilter.value)
+ )
+ );
+
+ workTypesWhere = inArray(techVendors.id, vendorIdsWithWorkTypes);
+ }
+ }
+
+ // 실제 사용될 where (vendorType, techVendorType, workTypes 필터링 추가)
+ const where = and(finalWhere, vendorTypeWhere, techVendorTypeWhere, workTypesWhere);
// 정렬
const orderBy =
@@ -160,6 +204,7 @@ export async function getTechVendorStatusCounts() {
async () => {
try {
const initial: Record<TechVendor["status"], number> = {
+ "PENDING_REVIEW": 0,
"ACTIVE": 0,
"INACTIVE": 0,
"BLACKLISTED": 0,
@@ -231,8 +276,10 @@ async function storeTechVendorFiles(
for (const file of files) {
// Convert file to buffer
- const ab = await file.arrayBuffer();
- const buffer = Buffer.from(ab);
+ // DRM 복호화 시도 및 버퍼 변환
+ const decryptedData = await decryptWithServerAction(file);
+ const buffer = Buffer.from(decryptedData);
+
// Generate a unique filename
const uniqueName = `${randomUUID()}-${file.name}`;
@@ -518,8 +565,7 @@ export async function getTechVendorItems(input: GetTechVendorItemsSchema, id: nu
if (input.search) {
const s = `%${input.search}%`;
globalWhere = or(
- ilike(techVendorItemsView.itemCode, s),
- ilike(techVendorItemsView.itemName, s)
+ ilike(techVendorItemsView.itemCode, s)
);
}
@@ -863,7 +909,7 @@ export async function getVendorItemsByType(vendorId: number, vendorType: string)
}
}
-export async function createTechVendorItem(input: CreateTechVendorItemSchema & { itemName: string }) {
+export async function createTechVendorItem(input: CreateTechVendorItemSchema) {
unstable_noStore();
try {
// DB에 이미 존재하는지 확인
@@ -889,7 +935,6 @@ export async function createTechVendorItem(input: CreateTechVendorItemSchema & {
.values({
vendorId: input.vendorId,
itemCode: input.itemCode,
- itemName: input.itemName || "기술영업",
})
.returning();
return newItem;
@@ -1009,14 +1054,12 @@ export async function exportTechVendorItems(vendorId: number) {
.select({
id: techVendorItemsView.vendorItemId,
vendorId: techVendorItemsView.vendorId,
- itemName: techVendorItemsView.itemName,
itemCode: techVendorItemsView.itemCode,
createdAt: techVendorItemsView.createdAt,
updatedAt: techVendorItemsView.updatedAt,
})
.from(techVendorItemsView)
.where(eq(techVendorItemsView.vendorId, vendorId))
- .orderBy(techVendorItemsView.itemName);
return items;
} catch (err) {
@@ -1308,27 +1351,6 @@ export async function importTechVendorsFromExcel(
}
}
- // // 3. 아이템 등록
- // if (vendor.items) {
- // console.log("아이템 등록 시도:", vendor.items);
- // const itemCodes = vendor.items.split(',').map(code => code.trim());
-
- // for (const itemCode of itemCodes) {
- // // 아이템 정보 조회
- // const [item] = await tx.select().from(items).where(eq(items.itemCode, itemCode));
- // if (item && item.itemCode && item.itemName) {
- // await tx.insert(techVendorPossibleItems).values({
- // vendorId: newVendor.id,
- // itemCode: item.itemCode,
- // itemName: item.itemName,
- // });
- // console.log("아이템 등록 성공:", itemCode);
- // } else {
- // console.log("아이템을 찾을 수 없음:", itemCode);
- // }
- // }
- // }
-
createdVendors.push(newVendor);
console.log("벤더 처리 완료:", vendor.vendorName);
} catch (error) {
diff --git a/lib/tech-vendors/table/tech-vendors-table-columns.tsx b/lib/tech-vendors/table/tech-vendors-table-columns.tsx
index 093b5547..22e89dd0 100644
--- a/lib/tech-vendors/table/tech-vendors-table-columns.tsx
+++ b/lib/tech-vendors/table/tech-vendors-table-columns.tsx
@@ -230,6 +230,12 @@ export function getColumns({ setRowAction, router }: GetColumnsProps): ColumnDef
className: "bg-slate-800 text-white border-slate-900",
iconColor: "text-white"
};
+ case "PENDING_REVIEW":
+ return {
+ variant: "default",
+ className: "bg-gray-100 text-gray-800 border-gray-300",
+ iconColor: "text-gray-600"
+ };
default:
return {
variant: "default",
@@ -244,7 +250,8 @@ export function getColumns({ setRowAction, router }: GetColumnsProps): ColumnDef
const statusMap: StatusDisplayMap = {
"ACTIVE": "활성 상태",
"INACTIVE": "비활성 상태",
- "BLACKLISTED": "거래 금지"
+ "BLACKLISTED": "거래 금지",
+ "PENDING_REVIEW": "비교 견적",
};
return statusMap[status] || status;
diff --git a/lib/tech-vendors/table/tech-vendors-table.tsx b/lib/tech-vendors/table/tech-vendors-table.tsx
index d6e6f99f..63ca8fcc 100644
--- a/lib/tech-vendors/table/tech-vendors-table.tsx
+++ b/lib/tech-vendors/table/tech-vendors-table.tsx
@@ -13,7 +13,7 @@ import { DataTable } from "@/components/data-table/data-table"
import { DataTableAdvancedToolbar } from "@/components/data-table/data-table-advanced-toolbar"
import { getColumns } from "./tech-vendors-table-columns"
import { getTechVendors, getTechVendorStatusCounts } from "../service"
-import { TechVendor, techVendors } from "@/db/schema/techVendors"
+import { TechVendor, techVendors, TechVendorWithAttachments } from "@/db/schema/techVendors"
import { TechVendorsTableToolbarActions } from "./tech-vendors-table-toolbar-actions"
import { UpdateVendorSheet } from "./update-vendor-sheet"
import { getVendorStatusIcon } from "../utils"
@@ -49,13 +49,14 @@ export function TechVendorsTable({ promises }: TechVendorsTableProps) {
const statusMap: Record<string, string> = {
"ACTIVE": "활성 상태",
"INACTIVE": "비활성 상태",
- "BLACKLISTED": "거래 금지"
+ "BLACKLISTED": "거래 금지",
+ "PENDING_REVIEW": "비교 견적",
};
return statusMap[status] || status;
};
- const filterFields: DataTableFilterField<TechVendor>[] = [
+ const filterFields: DataTableFilterField<TechVendorWithAttachments>[] = [
{
id: "status",
label: "상태",
@@ -69,7 +70,7 @@ export function TechVendorsTable({ promises }: TechVendorsTableProps) {
{ id: "vendorCode", label: "업체 코드" },
]
- const advancedFilterFields: DataTableAdvancedFilterField<TechVendor>[] = [
+ const advancedFilterFields: DataTableAdvancedFilterField<TechVendorWithAttachments>[] = [
{ id: "vendorName", label: "업체명", type: "text" },
{ id: "vendorCode", label: "업체코드", type: "text" },
{ id: "email", label: "이메일", type: "text" },
@@ -85,6 +86,40 @@ export function TechVendorsTable({ promises }: TechVendorsTableProps) {
icon: getVendorStatusIcon(status),
})),
},
+ {
+ id: "techVendorType",
+ label: "벤더 타입",
+ type: "multi-select",
+ options: [
+ { label: "조선", value: "조선" },
+ { label: "해양TOP", value: "해양TOP" },
+ { label: "해양HULL", value: "해양HULL" },
+ ],
+ },
+ {
+ id: "workTypes",
+ label: "Work Type",
+ type: "multi-select",
+ options: [
+ // 조선 workTypes
+ { label: "기장", value: "기장" },
+ { label: "전장", value: "전장" },
+ { label: "선실", value: "선실" },
+ { label: "배관", value: "배관" },
+ { label: "철의", value: "철의" },
+ // 해양TOP workTypes
+ { label: "TM", value: "TM" },
+ { label: "TS", value: "TS" },
+ { label: "TE", value: "TE" },
+ { label: "TP", value: "TP" },
+ // 해양HULL workTypes
+ { label: "HA", value: "HA" },
+ { label: "HE", value: "HE" },
+ { label: "HH", value: "HH" },
+ { label: "HM", value: "HM" },
+ { label: "NC", value: "NC" },
+ ],
+ },
{ id: "createdAt", label: "등록일", type: "date" },
{ id: "updatedAt", label: "수정일", type: "date" },
]
diff --git a/lib/tech-vendors/table/update-vendor-sheet.tsx b/lib/tech-vendors/table/update-vendor-sheet.tsx
index 774299f1..1d05b0c4 100644
--- a/lib/tech-vendors/table/update-vendor-sheet.tsx
+++ b/lib/tech-vendors/table/update-vendor-sheet.tsx
@@ -8,9 +8,6 @@ import {
Activity,
AlertCircle,
AlertTriangle,
- ClipboardList,
- FilePenLine,
- XCircle,
Circle as CircleIcon,
Building,
} from "lucide-react"
@@ -83,6 +80,12 @@ const getStatusConfig = (status: StatusType): StatusConfig => {
className: "text-slate-800",
label: "거래 금지"
};
+ case "PENDING_REVIEW":
+ return {
+ Icon: AlertTriangle,
+ className: "text-slate-800",
+ label: "비교 견적"
+ };
default:
return {
Icon: CircleIcon,
@@ -109,7 +112,7 @@ export function UpdateVendorSheet({ vendor, ...props }: UpdateVendorSheetProps)
phone: vendor?.phone ?? "",
email: vendor?.email ?? "",
website: vendor?.website ?? "",
- techVendorType: vendor?.techVendorType ? vendor.techVendorType.split(',').filter(Boolean) : [],
+ techVendorType: vendor?.techVendorType ? vendor.techVendorType.split(',').map(s => s.trim()).filter(Boolean) as ("조선" | "해양TOP" | "해양HULL")[] : [],
status: vendor?.status ?? "ACTIVE",
},
})
@@ -124,7 +127,7 @@ export function UpdateVendorSheet({ vendor, ...props }: UpdateVendorSheetProps)
phone: vendor?.phone ?? "",
email: vendor?.email ?? "",
website: vendor?.website ?? "",
- techVendorType: vendor?.techVendorType ? vendor.techVendorType.split(',').filter(Boolean) : [],
+ techVendorType: vendor?.techVendorType ? vendor.techVendorType.split(',').map(s => s.trim()).filter(Boolean) as ("조선" | "해양TOP" | "해양HULL")[] : [],
status: vendor?.status ?? "ACTIVE",
});
@@ -157,7 +160,7 @@ export function UpdateVendorSheet({ vendor, ...props }: UpdateVendorSheetProps)
userId: Number(session.user.id), // Add user ID from session
comment: statusComment, // Add comment for status changes
...data, // 모든 데이터 전달 - 서비스 함수에서 필요한 필드만 처리
- techVendorType: data.techVendorType ? data.techVendorType.join(',') : undefined,
+ techVendorType: Array.isArray(data.techVendorType) ? data.techVendorType.join(',') : undefined,
})
if (error) throw new Error(error)
@@ -165,7 +168,7 @@ export function UpdateVendorSheet({ vendor, ...props }: UpdateVendorSheetProps)
toast.success("업체 정보가 업데이트되었습니다!")
form.reset()
props.onOpenChange?.(false)
- } catch (err: any) {
+ } catch (err: unknown) {
toast.error(String(err))
}
})
@@ -312,11 +315,11 @@ export function UpdateVendorSheet({ vendor, ...props }: UpdateVendorSheetProps)
id={`update-${type}`}
checked={field.value?.includes(type as "조선" | "해양TOP" | "해양HULL")}
onChange={(e) => {
- const currentValue = field.value || [];
+ const currentValue = Array.isArray(field.value) ? field.value : [];
if (e.target.checked) {
field.onChange([...currentValue, type]);
} else {
- field.onChange(currentValue.filter((v) => v !== type));
+ field.onChange(currentValue.filter((v: string) => v !== type));
}
}}
className="w-4 h-4"
diff --git a/lib/tech-vendors/utils.ts b/lib/tech-vendors/utils.ts
index ac49c78a..693a6929 100644
--- a/lib/tech-vendors/utils.ts
+++ b/lib/tech-vendors/utils.ts
@@ -8,6 +8,8 @@ type StatusType = TechVendor["status"];
*/
export function getVendorStatusIcon(status: StatusType): LucideIcon {
switch (status) {
+ case "PENDING_REVIEW":
+ return Hourglass;
case "ACTIVE":
return CheckCircle2;
case "INACTIVE":
diff --git a/lib/tech-vendors/validations.ts b/lib/tech-vendors/validations.ts
index ee076945..fa0d9ae3 100644
--- a/lib/tech-vendors/validations.ts
+++ b/lib/tech-vendors/validations.ts
@@ -36,7 +36,7 @@ export const searchParamsCache = createSearchParamsCache({
// 기술영업 협력업체에 특화된 검색 필드
// -----------------------------------------------------------------
// 상태 (ACTIVE, INACTIVE, BLACKLISTED 등) 중에서 선택
- status: parseAsStringEnum(["ACTIVE", "INACTIVE", "BLACKLISTED", "PENDING_REVIEW", "IN_REVIEW", "REJECTED"]),
+ status: parseAsStringEnum(["ACTIVE", "INACTIVE", "BLACKLISTED", "PENDING_REVIEW"]),
// 협력업체명 검색
vendorName: parseAsString.withDefault(""),
@@ -46,8 +46,20 @@ export const searchParamsCache = createSearchParamsCache({
// 예) 코드 검색
vendorCode: parseAsString.withDefault(""),
+
// 벤더 타입 필터링 (다중 선택 가능)
vendorType: parseAsStringEnum(["ship", "top", "hull"]),
+
+ // workTypes 필터링 (다중 선택 가능)
+ workTypes: parseAsArrayOf(parseAsStringEnum([
+ // 조선 workTypes
+ "기장", "전장", "선실", "배관", "철의",
+ // 해양TOP workTypes
+ "TM", "TS", "TE", "TP",
+ // 해양HULL workTypes
+ "HA", "HE", "HH", "HM", "NC"
+ ])).withDefault([]),
+
// 필요하다면 이메일 검색 / 웹사이트 검색 등 추가 가능
email: parseAsString.withDefault(""),
website: parseAsString.withDefault(""),
@@ -239,12 +251,12 @@ export const updateTechVendorContactSchema = z.object({
export const createTechVendorItemSchema = z.object({
vendorId: z.number(),
itemCode: z.string().max(100, "Max length 100"),
- itemName: z.string().min(1, "Item name is required").max(255, "Max length 255"),
+ itemList: z.string().min(1, "Item list is required").max(255, "Max length 255"),
});
// 아이템 업데이트 스키마
export const updateTechVendorItemSchema = z.object({
- itemName: z.string().optional(),
+ itemList: z.string().optional(),
itemCode: z.string().max(100, "Max length 100"),
});