diff options
Diffstat (limited to 'lib/items-tech')
16 files changed, 154 insertions, 120 deletions
diff --git a/lib/items-tech/table/add-items-dialog.tsx b/lib/items-tech/table/add-items-dialog.tsx index ee8ee8b8..1b0d00c7 100644 --- a/lib/items-tech/table/add-items-dialog.tsx +++ b/lib/items-tech/table/add-items-dialog.tsx @@ -4,7 +4,7 @@ import * as React from "react" import { useRouter } from "next/navigation"
import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
-import { Plus } from "lucide-react"
+import { Plus, Loader } from "lucide-react"
import * as z from "zod"
import { Button } from "@/components/ui/button"
@@ -44,6 +44,7 @@ const shipbuildingWorkTypes = [ { label: "선실", value: "선실" },
{ label: "배관", value: "배관" },
{ label: "철의", value: "철의" },
+ { label: "선체", value: "선체" },
] as const
// 해양 TOP 공종 유형 정의
@@ -60,12 +61,14 @@ const offshoreHullWorkTypes = [ { label: "HE", value: "HE" },
{ label: "HH", value: "HH" },
{ label: "HM", value: "HM" },
+ { label: "HO", value: "HO" },
+ { label: "HP", value: "HP" },
{ label: "NC", value: "NC" },
] as const
// 기본 아이템 스키마
const itemFormSchema = z.object({
- itemCode: z.string().min(1, "아이템 코드는 필수입니다"),
+ itemCode: z.string().optional(),
workType: z.string().min(1, "공종은 필수입니다"),
// 조선 및 해양 아이템 공통 필드
itemList: z.string().optional(),
@@ -83,6 +86,7 @@ interface AddItemDialogProps { export function AddItemDialog({ itemType }: AddItemDialogProps) {
const router = useRouter()
const [open, setOpen] = React.useState(false)
+ const [isAddPending, startAddTransition] = React.useTransition()
// 기본값 설정
const getDefaultValues = () => {
@@ -120,53 +124,55 @@ export function AddItemDialog({ itemType }: AddItemDialogProps) { })
const onSubmit = async (data: ItemFormValues) => {
- try {
- switch (itemType) {
- case 'shipbuilding':
- if (!data.shipTypes) {
- toast.error("선종은 필수입니다")
- return
- }
+ startAddTransition(async () => {
+ try {
+ switch (itemType) {
+ case 'shipbuilding':
+ if (!data.shipTypes) {
+ toast.error("선종은 필수입니다")
+ return
+ }
+
+ await createShipbuildingItem({
+ itemCode: data.itemCode || "",
+ workType: data.workType as "기장" | "전장" | "선실" | "배관" | "철의" | "선체",
+ shipTypes: data.shipTypes,
+ itemList: data.itemList || null,
+ });
+ break;
- await createShipbuildingItem({
- itemCode: data.itemCode,
- workType: data.workType,
- shipTypes: data.shipTypes,
- itemList: data.itemList || null,
- });
- break;
-
- case 'offshoreTop':
- await createOffshoreTopItem({
- itemCode: data.itemCode,
- workType: data.workType as "TM" | "TS" | "TE" | "TP",
- itemList: data.itemList || null,
- subItemList: data.subItemList || null
- });
- break;
-
- case 'offshoreHull':
- await createOffshoreHullItem({
- itemCode: data.itemCode,
- workType: data.workType as "HA" | "HE" | "HH" | "HM" | "NC",
- itemList: data.itemList || null,
- subItemList: data.subItemList || null
- });
- break;
+ case 'offshoreTop':
+ await createOffshoreTopItem({
+ itemCode: data.itemCode || "",
+ workType: data.workType as "TM" | "TS" | "TE" | "TP",
+ itemList: data.itemList || null,
+ subItemList: data.subItemList || null
+ });
+ break;
+
+ case 'offshoreHull':
+ await createOffshoreHullItem({
+ itemCode: data.itemCode || "",
+ workType: data.workType as "HA" | "HE" | "HH" | "HM" | "HO" | "HP" | "NC",
+ itemList: data.itemList || null,
+ subItemList: data.subItemList || null
+ });
+ break;
+
+ default:
+ toast.error("지원하지 않는 아이템 타입입니다");
+ return;
+ }
- default:
- toast.error("지원하지 않는 아이템 타입입니다");
- return;
+ toast.success("아이템이 성공적으로 추가되었습니다")
+ setOpen(false)
+ form.reset(getDefaultValues())
+ router.refresh()
+ } catch (error) {
+ toast.error("아이템 추가 중 오류가 발생했습니다")
+ console.error(error)
}
-
- toast.success("아이템이 성공적으로 추가되었습니다")
- setOpen(false)
- form.reset(getDefaultValues())
- router.refresh()
- } catch (error) {
- toast.error("아이템 추가 중 오류가 발생했습니다")
- console.error(error)
- }
+ })
}
const getItemTypeLabel = () => {
@@ -315,7 +321,15 @@ export function AddItemDialog({ itemType }: AddItemDialogProps) { <Button type="button" variant="outline" onClick={() => setOpen(false)}>
취소
</Button>
- <Button type="submit">추가</Button>
+ <Button type="submit" disabled={isAddPending}>
+ {isAddPending && (
+ <Loader
+ className="mr-2 size-4 animate-spin"
+ aria-hidden="true"
+ />
+ )}
+ 추가
+ </Button>
</div>
</form>
</Form>
diff --git a/lib/items-tech/table/hull/import-item-handler.tsx b/lib/items-tech/table/hull/import-item-handler.tsx index aa0c7992..8c8fc57d 100644 --- a/lib/items-tech/table/hull/import-item-handler.tsx +++ b/lib/items-tech/table/hull/import-item-handler.tsx @@ -4,11 +4,11 @@ import { z } from "zod" import { createOffshoreHullItem } from "../../service" // 해양 HULL 기능(공종) 유형 enum -const HULL_WORK_TYPES = ["HA", "HE", "HH", "HM", "NC"] as const; +const HULL_WORK_TYPES = ["HA", "HE", "HH", "HM", "HO", "HP", "NC"] as const; // 아이템 데이터 검증을 위한 Zod 스키마 const itemSchema = z.object({ - itemCode: z.string().min(1, "아이템 코드는 필수입니다"), + itemCode: z.string().optional(), workType: z.enum(HULL_WORK_TYPES, { required_error: "기능(공종)은 필수입니다", }), @@ -19,7 +19,7 @@ const itemSchema = z.object({ interface ProcessResult { successCount: number; errorCount: number; - errors?: Array<{ row: number; message: string }>; + errors: Array<{ row: number; message: string; itemCode?: string; workType?: string }>; } /** @@ -45,7 +45,7 @@ export async function processHullFileImport( // 데이터 행이 없으면 빈 결과 반환 if (dataRows.length === 0) { - return { successCount: 0, errorCount: 0 }; + return { successCount: 0, errorCount: 0, errors: [] }; } // 각 행에 대해 처리 @@ -89,7 +89,7 @@ export async function processHullFileImport( // 해양 HULL 아이템 생성 const result = await createOffshoreHullItem({ itemCode: cleanedRow.itemCode, - workType: cleanedRow.workType as "HA" | "HE" | "HH" | "HM" | "NC", + workType: cleanedRow.workType as "HA" | "HE" | "HH" | "HM" | "HO" | "HP" | "NC", itemList: cleanedRow.itemList, subItemList: cleanedRow.subItemList, }); diff --git a/lib/items-tech/table/hull/item-excel-template.tsx b/lib/items-tech/table/hull/item-excel-template.tsx index 13ec1973..79512b9b 100644 --- a/lib/items-tech/table/hull/item-excel-template.tsx +++ b/lib/items-tech/table/hull/item-excel-template.tsx @@ -1,9 +1,6 @@ import * as ExcelJS from 'exceljs'; import { saveAs } from "file-saver"; -// 해양 HULL 기능(공종) 유형 -const HULL_WORK_TYPES = ["HA", "HE", "HH", "HM", "NC"] as const; - /** * 해양 HULL 아이템 데이터 가져오기를 위한 Excel 템플릿 파일 생성 및 다운로드 */ @@ -79,13 +76,6 @@ export async function exportHullItemTemplate() { } }); - // 워크시트에 공종 유형 관련 메모 추가 - const infoRow = worksheet.addRow(['공종 유형 안내: ' + HULL_WORK_TYPES.join(', ')]); - infoRow.font = { bold: true, color: { argb: 'FF0000FF' } }; - worksheet.mergeCells(`A${infoRow.number}:F${infoRow.number}`); - - - // 워크시트 보호 (선택적) worksheet.protect('', { selectLockedCells: true, 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 19782c42..efc6c583 100644 --- a/lib/items-tech/table/hull/offshore-hull-table-columns.tsx +++ b/lib/items-tech/table/hull/offshore-hull-table-columns.tsx @@ -162,7 +162,7 @@ export function getOffshoreHullColumns({ setRowAction }: GetColumnsProps): Colum header: ({ column }) => (
<DataTableColumnHeaderSimple column={column} title="생성일" />
),
- cell: ({ row }) => formatDate(row.original.createdAt, "KR"),
+ cell: ({ row }) => formatDate(row.original.createdAt),
enableSorting: true,
enableHiding: true,
meta: {
@@ -174,7 +174,7 @@ export function getOffshoreHullColumns({ setRowAction }: GetColumnsProps): Colum header: ({ column }) => (
<DataTableColumnHeaderSimple column={column} title="수정일" />
),
- cell: ({ row }) => formatDate(row.original.updatedAt, "KR"),
+ cell: ({ row }) => formatDate(row.original.updatedAt),
enableSorting: true,
enableHiding: true,
meta: {
diff --git a/lib/items-tech/table/hull/offshore-hull-table-toolbar-actions.tsx b/lib/items-tech/table/hull/offshore-hull-table-toolbar-actions.tsx index ad6f86b2..642dfea7 100644 --- a/lib/items-tech/table/hull/offshore-hull-table-toolbar-actions.tsx +++ b/lib/items-tech/table/hull/offshore-hull-table-toolbar-actions.tsx @@ -70,12 +70,10 @@ export function OffshoreHullTableToolbarActions({ table }: OffshoreHullTableTool // 필요한 헤더 직접 정의 (필터링 문제 해결)
const headers = [
- { key: 'itemCode', header: '아이템 코드' },
- { key: 'itemName', header: '아이템 명' },
- { key: 'description', header: '설명' },
+ { key: 'itemCode', header: '자재 그룹' },
{ key: 'workType', header: '기능(공종)' },
- { key: 'itemList', header: '아이템 리스트' },
- { key: 'subItemList', header: '서브 아이템 리스트' },
+ { key: 'itemList', header: '자재명' },
+ { key: 'subItemList', header: '자재명(상세)' },
].filter(header => !excludeColumns.includes(header.key));
console.log("내보내기 헤더:", headers);
diff --git a/lib/items-tech/table/import-excel-button.tsx b/lib/items-tech/table/import-excel-button.tsx index 02736664..4565c365 100644 --- a/lib/items-tech/table/import-excel-button.tsx +++ b/lib/items-tech/table/import-excel-button.tsx @@ -84,7 +84,6 @@ export function ImportItemButton({ itemType, onSuccess }: ImportItemButtonProps) // 복호화 실패 시 원본 파일 사용 arrayBuffer = await file.arrayBuffer(); } - // ExcelJS 워크북 로드 const workbook = new ExcelJS.Workbook(); await workbook.xlsx.load(arrayBuffer); @@ -94,21 +93,21 @@ export function ImportItemButton({ itemType, onSuccess }: ImportItemButtonProps) if (!worksheet) { throw new Error("Excel 파일에 워크시트가 없습니다."); } - // 헤더 행 찾기 let headerRowIndex = 1; let headerRow: ExcelJS.Row | undefined; let headerValues: (string | null)[] = []; + worksheet.eachRow((row, rowNumber) => { const values = row.values as (string | null)[]; - if (!headerRow && values.some(v => v === "자재 그룹" || v === "itemCode" || v === "item_code")) { + if (!headerRow && values.some(v => v === "자재 그룹" || v === "자재 코드" || v === "itemCode" || v === "item_code")) { headerRowIndex = rowNumber; headerRow = row; headerValues = [...values]; } }); - + if (!headerRow) { throw new Error("Excel 파일에서 헤더 행을 찾을 수 없습니다."); } @@ -173,7 +172,7 @@ export function ImportItemButton({ itemType, onSuccess }: ImportItemButtonProps) }; // 선택된 타입에 따라 적절한 프로세스 함수 호출 - let result; + let result: { successCount: number; errorCount: number; errors?: Array<{ row: number; message: string; itemCode?: string; workType?: string }> }; if (itemType === "top") { result = await processTopFileImport(dataRows, updateProgress); } else if (itemType === "hull") { @@ -185,7 +184,12 @@ export function ImportItemButton({ itemType, onSuccess }: ImportItemButtonProps) toast.success(`${result.successCount}개의 ${ITEM_TYPE_NAMES[itemType]}이(가) 성공적으로 가져와졌습니다.`); if (result.errorCount > 0) { - toast.warning(`${result.errorCount}개의 항목은 처리할 수 없었습니다.`); + const errorDetails = result.errors?.map((error: { row: number; message: string; itemCode?: string; workType?: string }) => + `행 ${error.row}: ${error.itemCode || '알 수 없음'} (${error.workType || '알 수 없음'}) - ${error.message}` + ).join('\n') || '오류 정보를 가져올 수 없습니다.'; + + console.error('Import 오류 상세:', errorDetails); + toast.error(`${result.errorCount}개의 항목 처리 실패. 콘솔에서 상세 내용을 확인하세요.`); } // 상태 초기화 및 다이얼로그 닫기 diff --git a/lib/items-tech/table/ship/Items-ship-table.tsx b/lib/items-tech/table/ship/Items-ship-table.tsx index feab288a..cf41b3cf 100644 --- a/lib/items-tech/table/ship/Items-ship-table.tsx +++ b/lib/items-tech/table/ship/Items-ship-table.tsx @@ -90,6 +90,7 @@ export function ItemsShipTable({ promises }: ItemsTableProps) { { label: "선실", value: "선실" },
{ label: "배관", value: "배관" },
{ label: "철의", value: "철의" },
+ { label: "선체", value: "선체" },
],
},
{
diff --git a/lib/items-tech/table/ship/import-item-handler.tsx b/lib/items-tech/table/ship/import-item-handler.tsx index a47e451b..57546cc6 100644 --- a/lib/items-tech/table/ship/import-item-handler.tsx +++ b/lib/items-tech/table/ship/import-item-handler.tsx @@ -5,8 +5,8 @@ import { createShipbuildingImportItem } from "../../service" // 아이템 생성 // 아이템 데이터 검증을 위한 Zod 스키마 const itemSchema = z.object({ - itemCode: z.string().min(1, "아이템 코드는 필수입니다"), - workType: z.enum(["기장", "전장", "선실", "배관", "철의"], { + itemCode: z.string().optional(), + workType: z.enum(["기장", "전장", "선실", "배관", "철의", "선체"], { required_error: "기능(공종)은 필수입니다", }), shipTypes: z.string().nullable().optional(), @@ -16,7 +16,7 @@ const itemSchema = z.object({ interface ProcessResult { successCount: number; errorCount: number; - errors?: Array<{ row: number; message: string }>; + errors: Array<{ row: number; message: string; itemCode?: string; workType?: string }>; } /** @@ -42,7 +42,7 @@ export async function processFileImport( // 데이터 행이 없으면 빈 결과 반환 if (dataRows.length === 0) { - return { successCount: 0, errorCount: 0 }; + return { successCount: 0, errorCount: 0, errors: [] }; } // 각 행에 대해 처리 @@ -78,7 +78,12 @@ export async function processFileImport( err => `${err.path.join('.')}: ${err.message}` ).join(', '); - errors.push({ row: rowIndex, message: errorMessage }); + errors.push({ + row: rowIndex, + message: errorMessage, + itemCode: cleanedRow.itemCode, + workType: cleanedRow.workType + }); errorCount++; continue; } @@ -86,7 +91,7 @@ export async function processFileImport( // 아이템 생성 const result = await createShipbuildingImportItem({ itemCode: cleanedRow.itemCode, - workType: cleanedRow.workType as "기장" | "전장" | "선실" | "배관" | "철의", + workType: cleanedRow.workType as "기장" | "전장" | "선실" | "배관" | "철의" | "선체", shipTypes: cleanedRow.shipTypes, itemList: cleanedRow.itemList, }); @@ -96,16 +101,25 @@ export async function processFileImport( } else { errors.push({ row: rowIndex, - message: result.message || result.error || "알 수 없는 오류" + message: result.message || result.error || "알 수 없는 오류", + itemCode: cleanedRow.itemCode, + workType: cleanedRow.workType }); errorCount++; } } catch (error) { console.error(`${rowIndex}행 처리 오류:`, error); + + // cleanedRow가 정의되지 않은 경우를 처리 + const itemCode = row["자재 그룹"] || row["itemCode"] || ""; + const workType = row["기능(공종)"] || row["workType"] || ""; + errors.push({ row: rowIndex, - message: error instanceof Error ? error.message : "알 수 없는 오류" + message: error instanceof Error ? error.message : "알 수 없는 오류", + itemCode: typeof itemCode === 'string' ? itemCode.trim() : String(itemCode).trim(), + workType: typeof workType === 'string' ? workType.trim() : String(workType).trim() }); errorCount++; } @@ -120,6 +134,6 @@ export async function processFileImport( return { successCount, errorCount, - errors: errors.length > 0 ? errors : undefined + errors }; }
\ No newline at end of file diff --git a/lib/items-tech/table/ship/items-ship-table-columns.tsx b/lib/items-tech/table/ship/items-ship-table-columns.tsx index 7018ae43..13ba2480 100644 --- a/lib/items-tech/table/ship/items-ship-table-columns.tsx +++ b/lib/items-tech/table/ship/items-ship-table-columns.tsx @@ -165,7 +165,7 @@ export function getShipbuildingColumns({ setRowAction }: GetColumnsProps): Colum header: ({ column }) => (
<DataTableColumnHeaderSimple column={column} title="생성일" />
),
- cell: ({ row }) => formatDate(row.original.createdAt, "KR"),
+ cell: ({ row }) => formatDate(row.original.createdAt),
enableSorting: true,
enableHiding: true,
meta: {
@@ -177,7 +177,7 @@ export function getShipbuildingColumns({ setRowAction }: GetColumnsProps): Colum header: ({ column }) => (
<DataTableColumnHeaderSimple column={column} title="수정일" />
),
- cell: ({ row }) => formatDate(row.original.updatedAt, "KR"),
+ cell: ({ row }) => formatDate(row.original.updatedAt),
enableSorting: true,
enableHiding: true,
meta: {
diff --git a/lib/items-tech/table/ship/items-table-toolbar-actions.tsx b/lib/items-tech/table/ship/items-table-toolbar-actions.tsx index e58ba135..29995327 100644 --- a/lib/items-tech/table/ship/items-table-toolbar-actions.tsx +++ b/lib/items-tech/table/ship/items-table-toolbar-actions.tsx @@ -23,7 +23,7 @@ import { ImportItemButton } from "../import-excel-button" interface ShipbuildingItem { id: number; itemId: number; - workType: "기장" | "전장" | "선실" | "배관" | "철의"; + workType: "기장" | "전장" | "선실" | "배관" | "철의" | "선체"; shipTypes: string; itemCode: string; itemName: string; @@ -70,12 +70,11 @@ export function ItemsTableToolbarActions({ table }: ItemsTableToolbarActionsProp // 필요한 헤더 직접 정의 (필터링 문제 해결) const headers = [ - { key: 'itemCode', header: '아이템 코드' }, - { key: 'itemName', header: '아이템 명' }, - { key: 'description', header: '설명' }, + { key: 'itemCode', header: '자재 그룹' }, { key: 'workType', header: '기능(공종)' }, { key: 'shipTypes', header: '선종' }, - { key: 'itemList', header: '아이템 리스트' } + { key: 'itemList', header: '자재명' }, + { key: 'subItemList', header: '자재명(상세)' }, ].filter(header => !excludeColumns.includes(header.key)); console.log("내보내기 헤더:", headers); diff --git a/lib/items-tech/table/top/import-item-handler.tsx b/lib/items-tech/table/top/import-item-handler.tsx index 541ec4ef..0a163791 100644 --- a/lib/items-tech/table/top/import-item-handler.tsx +++ b/lib/items-tech/table/top/import-item-handler.tsx @@ -8,7 +8,7 @@ const TOP_WORK_TYPES = ["TM", "TS", "TE", "TP"] as const; // 아이템 데이터 검증을 위한 Zod 스키마 const itemSchema = z.object({ - itemCode: z.string().min(1, "아이템 코드는 필수입니다"), + itemCode: z.string().optional(), workType: z.enum(TOP_WORK_TYPES, { required_error: "기능(공종)은 필수입니다", }), @@ -19,7 +19,7 @@ const itemSchema = z.object({ interface ProcessResult { successCount: number; errorCount: number; - errors?: Array<{ row: number; message: string }>; + errors: Array<{ row: number; message: string; itemCode?: string; workType?: string }>; } /** @@ -45,7 +45,7 @@ export async function processTopFileImport( // 데이터 행이 없으면 빈 결과 반환 if (dataRows.length === 0) { - return { successCount: 0, errorCount: 0 }; + return { successCount: 0, errorCount: 0, errors: [] }; } // 각 행에 대해 처리 @@ -81,7 +81,12 @@ export async function processTopFileImport( err => `${err.path.join('.')}: ${err.message}` ).join(', '); - errors.push({ row: rowIndex, message: errorMessage }); + errors.push({ + row: rowIndex, + message: errorMessage, + itemCode: cleanedRow.itemCode, + workType: cleanedRow.workType + }); errorCount++; continue; } @@ -99,15 +104,24 @@ export async function processTopFileImport( } else { errors.push({ row: rowIndex, - message: result.message || result.error || "알 수 없는 오류" + message: result.message || result.error || "알 수 없는 오류", + itemCode: cleanedRow.itemCode, + workType: cleanedRow.workType }); errorCount++; } } catch (error) { console.error(`${rowIndex}행 처리 오류:`, error); + + // cleanedRow가 정의되지 않은 경우를 처리 + const itemCode = row["자재 그룹"] || row["itemCode"] || ""; + const workType = row["기능(공종)"] || row["workType"] || ""; + errors.push({ row: rowIndex, - message: error instanceof Error ? error.message : "알 수 없는 오류" + message: error instanceof Error ? error.message : "알 수 없는 오류", + itemCode: typeof itemCode === 'string' ? itemCode.trim() : String(itemCode).trim(), + workType: typeof workType === 'string' ? workType.trim() : String(workType).trim() }); errorCount++; } @@ -122,6 +136,6 @@ export async function processTopFileImport( return { successCount, errorCount, - errors: errors.length > 0 ? errors : undefined + errors }; } diff --git a/lib/items-tech/table/top/item-excel-template.tsx b/lib/items-tech/table/top/item-excel-template.tsx index f547d617..b67d91be 100644 --- a/lib/items-tech/table/top/item-excel-template.tsx +++ b/lib/items-tech/table/top/item-excel-template.tsx @@ -1,8 +1,6 @@ import * as ExcelJS from 'exceljs'; import { saveAs } from "file-saver"; -// 해양 TOP 기능(공종) 유형 -const TOP_WORK_TYPES = ["TM", "TS", "TE", "TP"] as const; /** * 해양 TOP 아이템 데이터 가져오기를 위한 Excel 템플릿 파일 생성 및 다운로드 @@ -81,11 +79,6 @@ export async function exportTopItemTemplate() { } }); - // 워크시트에 공종 유형 관련 메모 추가 - const infoRow = worksheet.addRow(['공종 유형 안내: ' + TOP_WORK_TYPES.join(', ')]); - infoRow.font = { bold: true, color: { argb: 'FF0000FF' } }; - worksheet.mergeCells(`A${infoRow.number}:F${infoRow.number}`); - // 워크시트 보호 (선택적) worksheet.protect('', { 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 c2df4b75..93f27492 100644 --- a/lib/items-tech/table/top/offshore-top-table-columns.tsx +++ b/lib/items-tech/table/top/offshore-top-table-columns.tsx @@ -162,7 +162,7 @@ export function getOffshoreTopColumns({ setRowAction }: GetColumnsProps): Column header: ({ column }) => (
<DataTableColumnHeaderSimple column={column} title="생성일" />
),
- cell: ({ row }) => formatDate(row.original.createdAt, "KR"),
+ cell: ({ row }) => formatDate(row.original.createdAt),
enableSorting: true,
enableHiding: true,
meta: {
@@ -174,7 +174,7 @@ export function getOffshoreTopColumns({ setRowAction }: GetColumnsProps): Column header: ({ column }) => (
<DataTableColumnHeaderSimple column={column} title="수정일" />
),
- cell: ({ row }) => formatDate(row.original.updatedAt, "KR"),
+ cell: ({ row }) => formatDate(row.original.updatedAt),
enableSorting: true,
enableHiding: true,
meta: {
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 f91adf96..bf10560f 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 @@ -70,12 +70,10 @@ export function OffshoreTopTableToolbarActions({ table }: OffshoreTopTableToolba // 필요한 헤더 직접 정의 (필터링 문제 해결)
const headers = [
- { key: 'itemCode', header: '아이템 코드' },
- { key: 'itemName', header: '아이템 명' },
- { key: 'description', header: '설명' },
+ { key: 'itemCode', header: '자재 그룹' },
{ key: 'workType', header: '기능(공종)' },
- { key: 'itemList', header: '아이템 리스트' },
- { key: 'subItemList', header: '서브 아이템 리스트' },
+ { key: 'itemList', header: '자재명' },
+ { key: 'subItemList', header: '자재명(상세)' },
].filter(header => !excludeColumns.includes(header.key));
console.log("내보내기 헤더:", headers);
diff --git a/lib/items-tech/table/update-items-sheet.tsx b/lib/items-tech/table/update-items-sheet.tsx index 16dfcb71..978e83d5 100644 --- a/lib/items-tech/table/update-items-sheet.tsx +++ b/lib/items-tech/table/update-items-sheet.tsx @@ -44,6 +44,7 @@ const shipbuildingWorkTypes = [ { value: "선실", label: "선실" },
{ value: "배관", label: "배관" },
{ value: "철의", label: "철의" },
+ { value: "선체", label: "선체" },
] as const
const offshoreTopWorkTypes = [
@@ -58,6 +59,8 @@ const offshoreHullWorkTypes = [ { value: "HE", label: "HE" },
{ value: "HH", label: "HH" },
{ value: "HM", label: "HM" },
+ { value: "HO", label: "HO" },
+ { value: "HP", label: "HP" },
{ value: "NC", label: "NC" },
] as const
@@ -65,7 +68,7 @@ const offshoreHullWorkTypes = [ type ShipbuildingItem = {
id: number
itemCode: string
- workType: "기장" | "전장" | "선실" | "배관" | "철의"
+ workType: "기장" | "전장" | "선실" | "배관" | "철의" | "선체"
shipTypes: string
itemList: string | null
}
@@ -81,7 +84,7 @@ type OffshoreTopItem = { type OffshoreHullItem = {
id: number
itemCode: string
- workType: "HA" | "HE" | "HH" | "HM" | "NC"
+ workType: "HA" | "HE" | "HH" | "HM" | "HO" | "HP" | "NC"
itemList: string | null
subItemList: string | null
}
diff --git a/lib/items-tech/validations.ts b/lib/items-tech/validations.ts index 653f0af8..95a34b58 100644 --- a/lib/items-tech/validations.ts +++ b/lib/items-tech/validations.ts @@ -24,6 +24,8 @@ export const shipbuildingSearchParamsCache = createSearchParamsCache({ itemList: parseAsString.withDefault(""),
filters: getFiltersStateParser().withDefault([]),
joinOperator: parseAsStringEnum(["and", "or"]).withDefault("and"),
+ shipFilters: getFiltersStateParser().withDefault([]),
+ shipJoinOperator: parseAsStringEnum(["and", "or"]).withDefault("and"),
search: parseAsString.withDefault(""),
})
@@ -42,6 +44,8 @@ export const offshoreTopSearchParamsCache = createSearchParamsCache({ subItemList: parseAsString.withDefault(""),
filters: getFiltersStateParser().withDefault([]),
joinOperator: parseAsStringEnum(["and", "or"]).withDefault("and"),
+ topFilters: getFiltersStateParser().withDefault([]),
+ topJoinOperator: parseAsStringEnum(["and", "or"]).withDefault("and"),
search: parseAsString.withDefault(""),
})
@@ -59,6 +63,8 @@ export const offshoreHullSearchParamsCache = createSearchParamsCache({ subItemList: parseAsString.withDefault(""),
filters: getFiltersStateParser().withDefault([]),
joinOperator: parseAsStringEnum(["and", "or"]).withDefault("and"),
+ hullFilters: getFiltersStateParser().withDefault([]),
+ hullJoinOperator: parseAsStringEnum(["and", "or"]).withDefault("and"),
search: parseAsString.withDefault(""),
})
@@ -66,7 +72,7 @@ export const offshoreHullSearchParamsCache = createSearchParamsCache({ // 조선 아이템 업데이트 스키마
export const updateShipbuildingItemSchema = z.object({
itemCode: z.string(),
- workType: z.string().optional(),
+ workType: z.enum(["기장", "전장", "선실", "배관", "철의", "선체"]).optional(),
shipTypes: z.string().optional(),
itemList: z.string().optional(),
})
@@ -80,7 +86,7 @@ export type UpdateShipbuildingItemSchema = z.infer<typeof updateShipbuildingItem // 조선 아이템 스키마
export const createShipbuildingItemSchema = z.object({
itemCode: z.string(),
- workType: z.string(),
+ workType: z.enum(["기장", "전장", "선실", "배관", "철의", "선체"]),
shipTypes: z.string(),
itemList: z.string().optional(),
})
@@ -90,7 +96,7 @@ export type CreateShipbuildingItemSchema = z.infer<typeof createShipbuildingItem // 조선 아이템 생성 데이터 타입
export interface ShipbuildingItemCreateData {
itemCode: string
- workType: string | null
+ workType: "기장" | "전장" | "선실" | "배관" | "철의" | "선체" | null
shipTypes: string | null
itemList?: string | null
}
@@ -109,7 +115,7 @@ export const createOffshoreTopItemSchema = z.object({ // 해양 HULL 아이템 스키마
export const createOffshoreHullItemSchema = z.object({
itemCode: z.string(),
- workType: z.enum(["HA", "HE", "HH", "HM", "NC"]),
+ workType: z.enum(["HA", "HE", "HH", "HM", "HO", "HP", "NC"]),
itemList: z.string().optional(),
subItemList: z.string().optional(),
})
@@ -128,7 +134,7 @@ export const updateOffshoreTopItemSchema = z.object({ // 해양 HULL 아이템 업데이트 스키마
export const updateOffshoreHullItemSchema = z.object({
itemCode: z.string(),
- workType: z.enum(["HA", "HE", "HH", "HM", "NC"]).optional(),
+ workType: z.enum(["HA", "HE", "HH", "HM", "HO", "HP", "NC"]).optional(),
itemList: z.string().optional(),
subItemList: z.string().optional(),
})
@@ -147,7 +153,7 @@ export interface OffshoreTopItemCreateData { // 해양 HULL 아이템 생성 데이터 타입
export interface OffshoreHullItemCreateData {
itemCode: string
- workType: "HA" | "HE" | "HH" | "HM" | "NC"
+ workType: "HA" | "HE" | "HH" | "HM" | "HO" | "HP" | "NC"
itemList?: string | null
subItemList?: string | null
}
|
