diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-06-01 13:52:21 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-06-01 13:52:21 +0000 |
| commit | bac0228d21b7195065e9cddcc327ae33659c7bcc (patch) | |
| tree | 8f3016ae4533c8706d0c00a605d9b1d41968c2bc /lib/items | |
| parent | 2fdce8d7a57c792bba0ac36fa554dca9c9cc31e3 (diff) | |
(대표님) 20250601까지 작업사항
Diffstat (limited to 'lib/items')
| -rw-r--r-- | lib/items/service.ts | 9 | ||||
| -rw-r--r-- | lib/items/table/items-table-toolbar-actions.tsx | 63 | ||||
| -rw-r--r-- | lib/items/table/items-table.tsx | 189 |
3 files changed, 156 insertions, 105 deletions
diff --git a/lib/items/service.ts b/lib/items/service.ts index 35d2fa01..c841efad 100644 --- a/lib/items/service.ts +++ b/lib/items/service.ts @@ -45,12 +45,9 @@ export async function getItems(input: GetItemsSchema) { ilike(items.itemLevel, s), ilike(items.itemCode, s), ilike(items.itemName, s), + ilike(items.smCode, s), + ilike(items.packageCode, s), ilike(items.description, s), - ilike(items.parentItemCode, s), - ilike(items.unitOfMeasure, s), - ilike(items.steelType, s), - ilike(items.gradeMaterial, s), - ilike(items.baseUnitOfMeasure, s), ilike(items.changeDate, s) ); } @@ -75,6 +72,8 @@ export async function getItems(input: GetItemsSchema) { return { data, total }; }); + console.log(data) + const pageCount = Math.ceil(total / safePerPage); return { data, pageCount }; } catch (err) { diff --git a/lib/items/table/items-table-toolbar-actions.tsx b/lib/items/table/items-table-toolbar-actions.tsx index b3178ce1..7d8f7fb6 100644 --- a/lib/items/table/items-table-toolbar-actions.tsx +++ b/lib/items/table/items-table-toolbar-actions.tsx @@ -2,9 +2,10 @@ import * as React from "react" import { type Table } from "@tanstack/react-table" -import { Download, FileDown } from "lucide-react" +import { Download, FileDown, Database, Loader2 } from "lucide-react" import * as ExcelJS from 'exceljs' import { saveAs } from "file-saver" +import { toast } from "sonner" import { Button } from "@/components/ui/button" import { @@ -19,6 +20,9 @@ import { DeleteItemsDialog } from "./delete-items-dialog" import { AddItemDialog } from "./add-items-dialog" import { exportItemTemplate } from "./item-excel-template" import { ImportItemButton } from "./import-excel-button" +import { syncItemsFromCodeLists } from "@/lib/sedp/sync-package" + +// 동기화 함수 import (실제 경로로 수정 필요) interface ItemsTableToolbarActionsProps { table: Table<Item> @@ -26,12 +30,47 @@ interface ItemsTableToolbarActionsProps { export function ItemsTableToolbarActions({ table }: ItemsTableToolbarActionsProps) { const [refreshKey, setRefreshKey] = React.useState(0) + const [isSyncing, setIsSyncing] = React.useState(false) // 가져오기 성공 후 테이블 갱신 const handleImportSuccess = () => { setRefreshKey(prev => prev + 1) } + // 테이블 새로고침 함수 + const refreshTable = () => { + setRefreshKey(prev => prev + 1) + // 페이지 새로고침 또는 데이터 refetch 로직 + window.location.reload() + } + + // 전체 프로젝트 동기화 + const handleSyncAllProjects = async () => { + if (isSyncing) return + + setIsSyncing(true) + const loadingToast = toast.loading("모든 프로젝트의 아이템을 동기화하는 중...") + + try { + await syncItemsFromCodeLists() + toast.dismiss(loadingToast) + toast.success("모든 프로젝트의 아이템이 성공적으로 동기화되었습니다!") + + // 테이블 새로고침 + setTimeout(() => { + refreshTable() + }, 1000) + } catch (error) { + toast.dismiss(loadingToast) + toast.error("동기화 중 오류가 발생했습니다: " + (error as Error).message) + console.error("동기화 오류:", error) + } finally { + setIsSyncing(false) + } + } + + + // Excel 내보내기 함수 const exportTableToExcel = async ( table: Table<any>, @@ -125,10 +164,28 @@ export function ItemsTableToolbarActions({ table }: ItemsTableToolbarActionsProp ) : null} {/* 새 아이템 추가 다이얼로그 */} - <AddItemDialog /> + {/* <AddItemDialog /> */} {/* Import 버튼 */} - <ImportItemButton onSuccess={handleImportSuccess} /> + {/* <ImportItemButton onSuccess={handleImportSuccess} /> */} + + {/* 동기화 버튼 */} + <Button + variant="outline" + size="sm" + className="gap-2" + disabled={isSyncing} + onClick={handleSyncAllProjects} + > + {isSyncing ? ( + <Loader2 className="size-4 animate-spin" aria-hidden="true" /> + ) : ( + <Database className="size-4" aria-hidden="true" /> + )} + <span className="hidden sm:inline"> + {isSyncing ? "동기화 중..." : "동기화"} + </span> + </Button> {/* Export 드롭다운 메뉴 */} <DropdownMenu> diff --git a/lib/items/table/items-table.tsx b/lib/items/table/items-table.tsx index c05b4348..92f805eb 100644 --- a/lib/items/table/items-table.tsx +++ b/lib/items/table/items-table.tsx @@ -22,6 +22,7 @@ import { getColumns } from "./items-table-columns" import { ItemsTableToolbarActions } from "./items-table-toolbar-actions" import { UpdateItemSheet } from "./update-item-sheet" import { DeleteItemsDialog } from "./delete-items-dialog" +import { ViewModeToggle } from "@/components/data-table/view-mode-toggle" interface ItemsTableProps { promises?: Promise< @@ -71,7 +72,7 @@ export function ItemsTable({ promises }: ItemsTableProps) { id: "itemName", label: "자재그룹이름", type: "text", - }, + }, { id: "description", label: "상세", @@ -115,13 +116,13 @@ export function ItemsTable({ promises }: ItemsTableProps) { ] // 확장된 useDataTable 훅 사용 (pageSize 기반 자동 전환) - const { - table, - infiniteScroll, - isInfiniteMode, + const { + table, + infiniteScroll, + isInfiniteMode, effectivePageSize, handlePageSizeChange, - urlState + urlState } = useDataTable({ data, columns, @@ -154,98 +155,92 @@ export function ItemsTable({ promises }: ItemsTableProps) { } return ( - <div className="w-full space-y-2.5"> - - {/* <div className="flex items-center justify-between"> - <div className="flex items-center gap-2"> - <Button - variant="outline" - size="sm" - onClick={handleRefresh} - disabled={isInfiniteMode && infiniteScroll?.isLoading} - > - <RotateCcw className="h-4 w-4 mr-2" /> - 새로고침 - </Button> + <div className="w-full space-y-2.5 overflow-x-auto" style={{maxWidth:'100wv'}}> + + {/* 모드 토글 & 새로고침 */} + <div className="flex items-center justify-between"> + <ViewModeToggle + isInfiniteMode={isInfiniteMode} + onSwitch={handlePageSizeChange} // ← ViewModeToggle에 prop 추가 + /> </div> - </div> */} - - {/* 에러 상태 (무한 스크롤 모드) */} - {isInfiniteMode && infiniteScroll?.error && ( - <Alert variant="destructive"> - <AlertDescription> - 데이터를 불러오는 중 오류가 발생했습니다. - <Button - variant="link" - size="sm" - onClick={() => infiniteScroll.reset()} - className="ml-2 p-0 h-auto" - > - 다시 시도 - </Button> - </AlertDescription> - </Alert> - )} - - {/* 로딩 상태가 아닐 때만 테이블 렌더링 */} - {!(isInfiniteMode && infiniteScroll?.isLoading && infiniteScroll?.isEmpty) ? ( - <> - {/* 도구 모음 */} - <DataTableAdvancedToolbar - table={table} - filterFields={advancedFilterFields} - shallow={false} - > - <ItemsTableToolbarActions table={table} /> - </DataTableAdvancedToolbar> - - {/* 테이블 렌더링 */} - {isInfiniteMode ? ( - // 무한 스크롤 모드: InfiniteDataTable 사용 (자체 페이지네이션 없음) - <InfiniteDataTable - table={table} - hasNextPage={infiniteScroll?.hasNextPage || false} - isLoadingMore={infiniteScroll?.isLoadingMore || false} - onLoadMore={infiniteScroll?.loadMore} - totalCount={infiniteScroll?.totalCount} - isEmpty={infiniteScroll?.isEmpty || false} - compact={false} - autoSizeColumns={true} - /> - ) : ( - // 페이지네이션 모드: DataTable 사용 (내장 페이지네이션 활용) - <DataTable + + {/* 에러 상태 (무한 스크롤 모드) */} + {isInfiniteMode && infiniteScroll?.error && ( + <Alert variant="destructive"> + <AlertDescription> + 데이터를 불러오는 중 오류가 발생했습니다. + <Button + variant="link" + size="sm" + onClick={() => infiniteScroll.reset()} + className="ml-2 p-0 h-auto" + > + 다시 시도 + </Button> + </AlertDescription> + </Alert> + )} + + {/* 로딩 상태가 아닐 때만 테이블 렌더링 */} + {!(isInfiniteMode && infiniteScroll?.isLoading && infiniteScroll?.isEmpty) ? ( + <> + {/* 도구 모음 */} + <DataTableAdvancedToolbar table={table} - compact={false} - autoSizeColumns={true} - /> - )} - </> - ) : ( - /* 로딩 스켈레톤 (무한 스크롤 초기 로딩) */ - <div className="space-y-3"> - <div className="text-sm text-muted-foreground mb-4"> - 무한 스크롤 모드로 데이터를 로드하고 있습니다... + filterFields={advancedFilterFields} + shallow={false} + > + <ItemsTableToolbarActions table={table} /> + </DataTableAdvancedToolbar> + + {/* 테이블 렌더링 */} + {isInfiniteMode ? ( + // 무한 스크롤 모드: InfiniteDataTable 사용 (자체 페이지네이션 없음) + <InfiniteDataTable + table={table} + hasNextPage={infiniteScroll?.hasNextPage || false} + isLoadingMore={infiniteScroll?.isLoadingMore || false} + onLoadMore={infiniteScroll?.onLoadMore} + totalCount={infiniteScroll?.totalCount} + isEmpty={infiniteScroll?.isEmpty || false} + compact={false} + autoSizeColumns={true} + /> + ) : ( + // 페이지네이션 모드: DataTable 사용 (내장 페이지네이션 활용) + <DataTable + table={table} + compact={false} + autoSizeColumns={true} + /> + )} + </> + ) : ( + /* 로딩 스켈레톤 (무한 스크롤 초기 로딩) */ + <div className="space-y-3"> + <div className="text-sm text-muted-foreground mb-4"> + 무한 스크롤 모드로 데이터를 로드하고 있습니다... + </div> + {Array.from({ length: 10 }).map((_, i) => ( + <div key={i} className="h-12 w-full bg-muted animate-pulse rounded" /> + ))} </div> - {Array.from({ length: 10 }).map((_, i) => ( - <div key={i} className="h-12 w-full bg-muted animate-pulse rounded" /> - ))} - </div> - )} - - {/* 기존 다이얼로그들 */} - <UpdateItemSheet - open={rowAction?.type === "update"} - onOpenChange={() => setRowAction(null)} - item={rowAction?.row.original ?? null} - /> - <DeleteItemsDialog - open={rowAction?.type === "delete"} - onOpenChange={() => setRowAction(null)} - items={rowAction?.row.original ? [rowAction?.row.original] : []} - showTrigger={false} - onSuccess={() => rowAction?.row.toggleSelected(false)} - /> - </div> - ) + )} + + {/* 기존 다이얼로그들 */} + <UpdateItemSheet + open={rowAction?.type === "update"} + onOpenChange={() => setRowAction(null)} + item={rowAction?.row.original ?? null} + /> + <DeleteItemsDialog + open={rowAction?.type === "delete"} + onOpenChange={() => setRowAction(null)} + items={rowAction?.row.original ? [rowAction?.row.original] : []} + showTrigger={false} + onSuccess={() => rowAction?.row.toggleSelected(false)} + /> + </div> + ) }
\ No newline at end of file |
