diff options
Diffstat (limited to 'lib/projects')
| -rw-r--r-- | lib/projects/dialog/project-detail-dialog.tsx | 431 | ||||
| -rw-r--r-- | lib/projects/table/projects-table-columns.tsx | 29 | ||||
| -rw-r--r-- | lib/projects/table/projects-table.tsx | 25 |
3 files changed, 481 insertions, 4 deletions
diff --git a/lib/projects/dialog/project-detail-dialog.tsx b/lib/projects/dialog/project-detail-dialog.tsx new file mode 100644 index 00000000..2ecb37a5 --- /dev/null +++ b/lib/projects/dialog/project-detail-dialog.tsx @@ -0,0 +1,431 @@ +"use client" + +import * as React from "react" +import { type Project } from "@/db/schema/projects" + +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog" +import { + Table, + TableBody, + TableCell, + TableRow, +} from "@/components/ui/table" +import { Badge } from "@/components/ui/badge" +import { formatDate } from "@/lib/utils" + +interface ProjectDetailDialogProps { + project: Project + open: boolean + onOpenChange: (open: boolean) => void +} + +export function ProjectDetailDialog({ + project, + open, + onOpenChange, +}: ProjectDetailDialogProps) { + const formatValue = (value: string | null | undefined) => { + return value || "-" + } + + return ( + <Dialog open={open} onOpenChange={onOpenChange}> + <DialogContent className="max-w-6xl h-[90vh] flex flex-col"> + <DialogHeader className="flex-shrink-0"> + <DialogTitle className="flex items-center gap-2"> + 프로젝트 상세 정보 + <Badge variant="outline">{project.code}</Badge> + </DialogTitle> + <DialogDescription> + 프로젝트코드: {project.code} | {project.name} + </DialogDescription> + </DialogHeader> + + <div className="flex-1 overflow-y-auto min-h-0"> + <div className="space-y-6 p-4"> + <h3 className="text-lg font-semibold mb-3">프로젝트 전체 정보</h3> + <Table> + <TableBody> + {/* 기본 프로젝트 정보 */} + <TableRow> + <TableCell className="font-medium w-1/4">프로젝트 코드</TableCell> + <TableCell>{formatValue(project.code)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">프로젝트명</TableCell> + <TableCell>{formatValue(project.name)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">프로젝트 타입</TableCell> + <TableCell> + <Badge variant={project.type === "ship" ? "default" : "secondary"}> + {project.type === "ship" ? "조선" : "해양"} + </Badge> + </TableCell> + </TableRow> + + {/* 선주 및 기본 정보 */} + <TableRow> + <TableCell className="font-medium">선주명</TableCell> + <TableCell>{formatValue(project.OWN_NM)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">선주약어</TableCell> + <TableCell>{formatValue(project.OWN_AB)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">선주1</TableCell> + <TableCell>{formatValue(project.OWN_1)}</TableCell> + </TableRow> + + {/* 선급 정보 */} + <TableRow> + <TableCell className="font-medium">선급1</TableCell> + <TableCell>{formatValue(project.CLS_1)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">선급2</TableCell> + <TableCell>{formatValue(project.CLS_2)}</TableCell> + </TableRow> + + {/* 선박 정보 */} + <TableRow> + <TableCell className="font-medium">선종</TableCell> + <TableCell>{formatValue(project.SKND)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">선형</TableCell> + <TableCell>{formatValue(project.SHTYPE)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">선형코드</TableCell> + <TableCell>{formatValue(project.SHTYPE_CD)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">선형군</TableCell> + <TableCell>{formatValue(project.SHTYPE_GRP)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">선형단위</TableCell> + <TableCell>{formatValue(project.SHTYPE_UOM)}</TableCell> + </TableRow> + + {/* 도크 및 건조 정보 */} + <TableRow> + <TableCell className="font-medium">도크</TableCell> + <TableCell>{formatValue(project.DOCK_CD)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">기준호선</TableCell> + <TableCell>{formatValue(project.MSHIP_NO)}</TableCell> + </TableRow> + + {/* 계약 정보 */} + <TableRow> + <TableCell className="font-medium">계약일자</TableCell> + <TableCell>{formatValue(project.CNRT_DT)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">계약인도일자</TableCell> + <TableCell>{formatValue(project.CNRT_DL_DT)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">실인도일자</TableCell> + <TableCell>{formatValue(project.RL_DL_DT)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">선표인도일자</TableCell> + <TableCell>{formatValue(project.BP_DL_DT)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">Sail Away Date</TableCell> + <TableCell>{formatValue(project.SA_DT)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">고객발주번호</TableCell> + <TableCell>{formatValue(project.CSTM_PO_NO)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">계약존속여부</TableCell> + <TableCell>{formatValue(project.CNRT_CNTN_YN)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">계약유보여부</TableCell> + <TableCell>{formatValue(project.CNRT_RESV_YN)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">전체 계약 대수</TableCell> + <TableCell>{formatValue(project.TOT_CNRT_CNT)}</TableCell> + </TableRow> + + {/* 프로젝트 상태 */} + <TableRow> + <TableCell className="font-medium">진행상태</TableCell> + <TableCell>{formatValue(project.PRGS_STAT)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">공사진행여부</TableCell> + <TableCell>{formatValue(project.PROJ_PRGS_YN)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">시작일자</TableCell> + <TableCell>{formatValue(project.STDT)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">인터페이스 진행단계</TableCell> + <TableCell>{formatValue(project.IF_STAT)}</TableCell> + </TableRow> + + {/* 기술 정보 */} + <TableRow> + <TableCell className="font-medium">IMO 번호</TableCell> + <TableCell>{formatValue(project.IMO_NO)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">국적</TableCell> + <TableCell>{formatValue(project.NTTP)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">Main engine type code</TableCell> + <TableCell>{formatValue(project.MN_ENGN_TP_CD)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">관청명</TableCell> + <TableCell>{formatValue(project.GOV)}</TableCell> + </TableRow> + + {/* 조직 정보 */} + <TableRow> + <TableCell className="font-medium">사업부</TableCell> + <TableCell>{formatValue(project.BIZCLS)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">사업장코드</TableCell> + <TableCell>{formatValue(project.BIZLOC_CD)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">사업영역</TableCell> + <TableCell>{formatValue(project.BIZ_DMN)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">영업그룹</TableCell> + <TableCell>{formatValue(project.SALE_GRP)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">영업조직</TableCell> + <TableCell>{formatValue(project.SALE_ORG_CD)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">손익센터</TableCell> + <TableCell>{formatValue(project.PRCTR)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">설계담당자</TableCell> + <TableCell>{formatValue(project.DSN_CHRGR)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">회사코드</TableCell> + <TableCell>{formatValue(project.CO_CD)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">플랜트 코드</TableCell> + <TableCell>{formatValue(project.PLNT_CD)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">관리회계영역</TableCell> + <TableCell>{formatValue(project.MNG_ACOT_DMN)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">품질사업부</TableCell> + <TableCell>{formatValue(project.QM_CLS)}</TableCell> + </TableRow> + + {/* 프로젝트 세부 정보 */} + <TableRow> + <TableCell className="font-medium">프로젝트 세부타입</TableCell> + <TableCell>{formatValue(project.PROJ_DTL_TP)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">프로젝트 기타타입</TableCell> + <TableCell>{formatValue(project.PROJ_ETC_TP)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">프로젝트구분</TableCell> + <TableCell>{formatValue(project.PROJ_GB)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">프로젝트 프로파일</TableCell> + <TableCell>{formatValue(project.PROJ_PROF)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">프로젝트범위</TableCell> + <TableCell>{formatValue(project.PROJ_SCP)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">프로젝트 WBS타입</TableCell> + <TableCell>{formatValue(project.PROJ_WBS_TP)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">원본 TYPE</TableCell> + <TableCell>{formatValue(project.TYPE)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">(중국)프로젝트타입</TableCell> + <TableCell>{formatValue(project.CHN_PROJ_TP)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">(풍력)프로젝트타입</TableCell> + <TableCell>{formatValue(project.WP_PROJ_TP)}</TableCell> + </TableRow> + + {/* 시리즈 정보 */} + <TableRow> + <TableCell className="font-medium">시리즈여부</TableCell> + <TableCell>{formatValue(project.SERS_YN)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">시리즈첫공사번호</TableCell> + <TableCell>{formatValue(project.SERS_NO)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">시리즈번호</TableCell> + <TableCell>{formatValue(project.REF_NO)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">세대수/시리즈</TableCell> + <TableCell>{formatValue(project.GENT_CNT)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">연관프로젝트</TableCell> + <TableCell>{formatValue(project.RLTD_PROJ)}</TableCell> + </TableRow> + + {/* 제품 정보 */} + <TableRow> + <TableCell className="font-medium">제품 Level 4</TableCell> + <TableCell>{formatValue(project.PDT_LVL_4)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">전기전자 제품군</TableCell> + <TableCell>{formatValue(project.DIGT_PDT_GRP)}</TableCell> + </TableRow> + + {/* 프로젝트 관리 정보 */} + <TableRow> + <TableCell className="font-medium">프로젝트 생성요청일</TableCell> + <TableCell>{formatValue(project.PROJ_CRTE_REQ_DT)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">프로젝트 생성요청자</TableCell> + <TableCell>{formatValue(project.PROJ_CRTE_REQ_EMPNO)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">모프로젝트 인도계획일</TableCell> + <TableCell>{formatValue(project.PROJ_DL_PLN_DT)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">모프로젝트 인도실적일</TableCell> + <TableCell>{formatValue(project.PROJ_DL_RT_DT)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">프로포절 프로젝트</TableCell> + <TableCell>{formatValue(project.PRO_PROJ_NO)}</TableCell> + </TableRow> + + {/* 안건 정보 */} + <TableRow> + <TableCell className="font-medium">안건번호</TableCell> + <TableCell>{formatValue(project.INQY_NO)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">안건순번</TableCell> + <TableCell>{formatValue(project.INQY_SEQ)}</TableCell> + </TableRow> + + {/* 보증 정보 */} + <TableRow> + <TableCell className="font-medium">A/S 보증기간</TableCell> + <TableCell>{formatValue(project.AS_GRNT_PRD)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">Project Warranty Start Date</TableCell> + <TableCell>{formatValue(project.GRNT_STDT)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">주문주 보증기간</TableCell> + <TableCell>{formatValue(project.ORDR_GRNT_PRD)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">주문주 보증종료일</TableCell> + <TableCell>{formatValue(project.ORDR_GRNT_FN_DT)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">최종수요자 보증종료일</TableCell> + <TableCell>{formatValue(project.FIN_GRNT_FN_DT)}</TableCell> + </TableRow> + + {/* 기타 정보 */} + <TableRow> + <TableCell className="font-medium">MC YN</TableCell> + <TableCell>{formatValue(project.NEW_MC_YN)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">사내외 구분</TableCell> + <TableCell>{formatValue(project.IO_GB)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">유통경로</TableCell> + <TableCell>{formatValue(project.DIST_PATH)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">인도전선명</TableCell> + <TableCell>{formatValue(project.DL_BF_PROJ_NM)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">인도고객 ID</TableCell> + <TableCell>{formatValue(project.DL_CSTM_CD)}</TableCell> + </TableRow> + + {/* 시스템 정보 */} + <TableRow> + <TableCell className="font-medium">시스템회계마감일자</TableCell> + <TableCell>{formatValue(project.SYS_ACOT_CLSD_DT)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">Source System</TableCell> + <TableCell>{formatValue(project.SRC_SYS_ID)}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">삭제 여부</TableCell> + <TableCell> + {project.DEL_YN ? ( + <Badge variant="destructive">삭제됨</Badge> + ) : ( + <Badge variant="secondary">활성</Badge> + )} + </TableCell> + </TableRow> + + {/* 생성/수정 정보 */} + <TableRow> + <TableCell className="font-medium">생성일시</TableCell> + <TableCell>{formatDate(project.createdAt, "KR")}</TableCell> + </TableRow> + <TableRow> + <TableCell className="font-medium">수정일시</TableCell> + <TableCell>{formatDate(project.updatedAt, "KR")}</TableCell> + </TableRow> + </TableBody> + </Table> + </div> + </div> + </DialogContent> + </Dialog> + ) +} diff --git a/lib/projects/table/projects-table-columns.tsx b/lib/projects/table/projects-table-columns.tsx index 6926429a..95eeae85 100644 --- a/lib/projects/table/projects-table-columns.tsx +++ b/lib/projects/table/projects-table-columns.tsx @@ -3,8 +3,10 @@ import * as React from "react" import { type DataTableRowAction } from "@/types/table" import { type ColumnDef } from "@tanstack/react-table" +import { Eye } from "lucide-react" import { formatDate } from "@/lib/utils" +import { Button } from "@/components/ui/button" import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header" import { Project } from "@/db/schema" @@ -12,13 +14,35 @@ import { projectsColumnsConfig } from "@/config/projectsColumnsConfig" interface GetColumnsProps { setRowAction: React.Dispatch<React.SetStateAction<DataTableRowAction<Project> | null>> + onDetailClick: (project: Project) => void } /** * tanstack table 컬럼 정의 (중첩 헤더 버전) */ -export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<Project>[] { +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export function getColumns({ setRowAction, onDetailClick }: GetColumnsProps): ColumnDef<Project>[] { + // 상세보기 버튼 컬럼 + const detailColumn: ColumnDef<Project> = { + id: "action", + header: "상세보기", + size: 100, + cell: ({ row }) => { + const project = row.original + return ( + <Button + variant="ghost" + size="sm" + onClick={() => onDetailClick(project)} + className="h-8 w-8 p-0" + > + <Eye className="h-4 w-4" /> + <span className="sr-only">상세보기</span> + </Button> + ) + }, + } // ---------------------------------------------------------------- // 3) 일반 컬럼들을 "그룹"별로 묶어 중첩 columns 생성 @@ -82,9 +106,10 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<Project }) // ---------------------------------------------------------------- - // 4) 최종 컬럼 배열: select, nestedColumns, actions + // 4) 최종 컬럼 배열: detailColumn, nestedColumns // ---------------------------------------------------------------- return [ + detailColumn, ...nestedColumns, ] }
\ No newline at end of file diff --git a/lib/projects/table/projects-table.tsx b/lib/projects/table/projects-table.tsx index 3da54b7c..462e8638 100644 --- a/lib/projects/table/projects-table.tsx +++ b/lib/projects/table/projects-table.tsx @@ -16,6 +16,7 @@ import { getColumns } from "./projects-table-columns" import { getProjectLists } from "../service" import { Project } from "@/db/schema" import { ProjectTableToolbarActions } from "./projects-table-toolbar-actions" +import { ProjectDetailDialog } from "@/lib/projects/dialog/project-detail-dialog" interface ItemsTableProps { promises: Promise< @@ -26,17 +27,28 @@ interface ItemsTableProps { } export function ProjectsTable({ promises }: ItemsTableProps) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars const { featureFlags } = useFeatureFlags() const [{ data, pageCount }] = React.use(promises) + // eslint-disable-next-line @typescript-eslint/no-unused-vars const [rowAction, setRowAction] = React.useState<DataTableRowAction<Project> | null>(null) + // 상세보기 다이얼로그 상태 관리 + const [selectedProject, setSelectedProject] = React.useState<Project | null>(null) + const [dialogOpen, setDialogOpen] = React.useState(false) + + const handleDetailClick = React.useCallback((project: Project) => { + setSelectedProject(project) + setDialogOpen(true) + }, []) + const columns = React.useMemo( - () => getColumns({ setRowAction }), - [setRowAction] + () => getColumns({ setRowAction, onDetailClick: handleDetailClick }), + [setRowAction, handleDetailClick] ) /** @@ -123,6 +135,15 @@ export function ProjectsTable({ promises }: ItemsTableProps) { <ProjectTableToolbarActions table={table} /> </DataTableAdvancedToolbar> </DataTable> + + {/* 프로젝트 상세보기 다이얼로그 */} + {selectedProject && ( + <ProjectDetailDialog + project={selectedProject} + open={dialogOpen} + onOpenChange={setDialogOpen} + /> + )} </> ) } |
