summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-05-15 01:34:49 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-05-15 01:34:49 +0000
commited864fa46c7ce0aac2de4c5ba5d311ebfd7e6a88 (patch)
treeb04695b9c8a4d2b03ed1f44f318fa38d8c490364
parent9beaabc8d1e0ac3a5c54c8202d3c690577bdbd39 (diff)
(대표님) 벤더 문서 관련 개발사항
-rw-r--r--app/[lng]/partners/(partners)/vendor-data/form/[packageId]/[formId]/[projectId]/[contractId]/page.tsx (renamed from app/[lng]/partners/(partners)/vendor-data/form/[packageId]/[formId]/page.tsx)32
-rw-r--r--components/documents/StageList.tsx4
-rw-r--r--components/vendor-data/sidebar.tsx9
-rw-r--r--components/vendor-data/vendor-data-container.tsx8
-rw-r--r--db/schema/vendorDocu.ts3
-rw-r--r--lib/form-list/table/formLists-table-toolbar-actions.tsx4
-rw-r--r--lib/vendor-document-list/table/doc-table.tsx2
-rw-r--r--lib/vendor-document/table/doc-table-column.tsx13
-rw-r--r--lib/vendors/table/vendors-table-columns.tsx45
-rw-r--r--lib/vendors/validations.ts2
10 files changed, 93 insertions, 29 deletions
diff --git a/app/[lng]/partners/(partners)/vendor-data/form/[packageId]/[formId]/page.tsx b/app/[lng]/partners/(partners)/vendor-data/form/[packageId]/[formId]/[projectId]/[contractId]/page.tsx
index dc8df262..71a02ab3 100644
--- a/app/[lng]/partners/(partners)/vendor-data/form/[packageId]/[formId]/page.tsx
+++ b/app/[lng]/partners/(partners)/vendor-data/form/[packageId]/[formId]/[projectId]/[contractId]/page.tsx
@@ -1,11 +1,15 @@
import DynamicTable from "@/components/form-data/form-data-table";
-import { getFormData, getFormId } from "@/lib/forms/services";
+import { findContractItemId, getFormData, getFormId } from "@/lib/forms/services";
interface IndexPageProps {
params: {
lng: string;
packageId: string;
formId: string;
+ projectId: string;
+ contractId: string;
+
+
};
searchParams?: {
mode?: string;
@@ -20,19 +24,35 @@ export default async function FormPage({ params, searchParams }: IndexPageProps)
const resolvedSearchParams = await searchParams;
// 3) 구조 분해 할당
- const { lng, packageId, formId: formCode } = resolvedParams;
+ const { lng, packageId, formId: formCode, projectId,contractId } = resolvedParams;
// URL 쿼리 파라미터에서 mode 가져오기 (await 해서 사용)
const mode = resolvedSearchParams?.mode === "ENG" ? "ENG" : "IM"; // 기본값은 IM
// 4) 변환
- const packageIdAsNumber = Number(packageId);
+ let packageIdAsNumber = Number(packageId);
+ const contractIdAsNumber = Number(contractId);
+
+ // packageId가 0이면 contractId와 formCode로 실제 contractItemId 찾기
+ if (packageIdAsNumber === 0 && contractIdAsNumber > 0) {
+ console.log(`packageId가 0이므로 contractId ${contractIdAsNumber}와 formCode ${formCode}로 contractItemId 조회`);
+
+ const foundContractItemId = await findContractItemId(contractIdAsNumber, formCode);
+
+ if (foundContractItemId) {
+ console.log(`contractItemId ${foundContractItemId}를 찾았습니다. 이 값을 사용합니다.`);
+ packageIdAsNumber = foundContractItemId;
+ } else {
+ console.warn(`contractItemId를 찾을 수 없습니다. packageId는 계속 0으로 유지됩니다.`);
+ }
+ }
// 5) DB 조회
- const { columns, data, projectId } = await getFormData(formCode, packageIdAsNumber);
+ const { columns, data } = await getFormData(formCode, packageIdAsNumber);
+
// 6) formId 및 report temp file 조회
- const { formId } = await getFormId(packageId, formCode);
+ const { formId } = await getFormId(String(packageIdAsNumber), formCode);
// 7) 예외 처리
if (!columns) {
@@ -50,7 +70,7 @@ export default async function FormPage({ params, searchParams }: IndexPageProps)
formId={formId}
columnsJSON={columns}
dataJSON={data}
- projectId={projectId}
+ projectId={Number(projectId)}
mode={mode} // 모드 전달
/>
</div>
diff --git a/components/documents/StageList.tsx b/components/documents/StageList.tsx
index 8d82b741..64510dda 100644
--- a/components/documents/StageList.tsx
+++ b/components/documents/StageList.tsx
@@ -175,6 +175,8 @@ export default function StageList({ document }: StageListProps) {
<TableHead className="w-[100px]">Stage</TableHead>
<TableHead className="w-[100px]">Revision</TableHead>
<TableHead className="w-[150px]">첨부파일</TableHead>
+ <TableHead className="w-[150px]">등록자</TableHead>
+ <TableHead className="w-[150px]">Comment</TableHead>
<TableHead className="w-[150px]">생성일</TableHead>
<TableHead className="w-[120px]">계획일</TableHead>
<TableHead className="w-[120px]">실제일</TableHead>
@@ -232,6 +234,8 @@ export default function StageList({ document }: StageListProps) {
)}
</div>
</TableCell>
+ <TableCell>{ver.uploaderName}</TableCell>
+ <TableCell>{ver.comment}</TableCell>
<TableCell>{formatDate(ver.DocumentSubmitDate) ?? "-"}</TableCell>
<TableCell>{ver.planDate ?? "-"}</TableCell>
<TableCell>{ver.actualDate ?? "-"}</TableCell>
diff --git a/components/vendor-data/sidebar.tsx b/components/vendor-data/sidebar.tsx
index 2dff6bc1..3805d216 100644
--- a/components/vendor-data/sidebar.tsx
+++ b/components/vendor-data/sidebar.tsx
@@ -24,6 +24,8 @@ interface SidebarProps extends React.HTMLAttributes<HTMLDivElement> {
isCollapsed: boolean
packages: PackageData[]
selectedPackageId: number | null
+ selectedProjectId: number | null
+ selectedContractId: number | null
onSelectPackage: (itemId: number) => void
forms: FormInfo[]
selectedForm: string | null
@@ -37,6 +39,8 @@ export function Sidebar({
isCollapsed,
packages,
selectedPackageId,
+ selectedProjectId,
+ selectedContractId,
onSelectPackage,
forms,
selectedForm,
@@ -48,6 +52,7 @@ export function Sidebar({
const rawPathname = usePathname()
const pathname = rawPathname ?? ""
+
/**
* ---------------------------
* 1) URL에서 현재 패키지 / 폼 코드 추출
@@ -105,7 +110,7 @@ export function Sidebar({
if (mode === "ENG") {
// ENG 모드에서는 첫 번째 패키지 ID 또는 현재 URL에서 추출한 ID 사용
- packageId = currentItemId || (packages[0]?.itemId || 0);
+ packageId = 0;
} else {
// IM 모드에서는 반드시 선택된 패키지 ID 필요
if (selectedPackageId === null) return;
@@ -119,7 +124,7 @@ export function Sidebar({
// 예: /vendor-data/form/[packageId]/[formCode]
const baseSegments = segments.slice(0, segments.indexOf("vendor-data") + 1).join("/")
// 모드 정보를 쿼리 파라미터로 추가
- router.push(`/${baseSegments}/form/${packageId}/${form.formCode}?mode=${mode}`)
+ router.push(`/${baseSegments}/form/${packageId}/${form.formCode}/${selectedProjectId}/${selectedContractId}?mode=${mode}`)
}
return (
diff --git a/components/vendor-data/vendor-data-container.tsx b/components/vendor-data/vendor-data-container.tsx
index 77b36abf..fcecae43 100644
--- a/components/vendor-data/vendor-data-container.tsx
+++ b/components/vendor-data/vendor-data-container.tsx
@@ -274,6 +274,8 @@ export function VendorDataContainer({
isCollapsed={isCollapsed}
packages={currentContract?.packages || []}
selectedPackageId={selectedPackageId}
+ selectedProjectId={selectedProjectId}
+ selectedContractId={selectedContractId}
onSelectPackage={handleSelectPackage}
forms={formList}
selectedForm={
@@ -305,6 +307,8 @@ export function VendorDataContainer({
isCollapsed={isCollapsed}
packages={currentContract?.packages || []}
selectedPackageId={selectedPackageId}
+ selectedContractId={selectedContractId}
+ selectedProjectId={selectedProjectId}
onSelectPackage={handleSelectPackage}
forms={formList}
selectedForm={
@@ -324,6 +328,8 @@ export function VendorDataContainer({
isCollapsed={isCollapsed}
packages={currentContract?.packages || []}
selectedPackageId={selectedPackageId}
+ selectedContractId={selectedContractId}
+ selectedProjectId={selectedProjectId}
onSelectPackage={handleSelectPackage}
forms={formList}
selectedForm={
@@ -368,6 +374,8 @@ export function VendorDataContainer({
isCollapsed={isCollapsed}
packages={currentContract?.packages || []}
selectedPackageId={selectedPackageId}
+ selectedProjectId={selectedProjectId}
+ selectedContractId={selectedContractId}
onSelectPackage={handleSelectPackage}
forms={formList}
selectedForm={
diff --git a/db/schema/vendorDocu.ts b/db/schema/vendorDocu.ts
index 1e166e6b..8eb9cbc6 100644
--- a/db/schema/vendorDocu.ts
+++ b/db/schema/vendorDocu.ts
@@ -13,6 +13,7 @@ export const documents = pgTable(
// documentType: varchar("document_type", { length: 50 }).notNull(),
+ pic: varchar("pic", { length: 50 }),
// 어느 계약(Contract) 소속인지
contractId: integer("contract_id")
@@ -128,6 +129,7 @@ export const vendorDocumentsView = pgView("vendor_documents_view", {
id: integer("id").notNull(),
docNumber: varchar("doc_number", { length: 100 }).notNull(),
title: varchar("title", { length: 255 }).notNull(),
+ pic: varchar("pic", { length: 255 }).notNull(),
status: varchar("status", { length: 50 }).notNull(),
issuedDate: date("issued_date"),
@@ -152,6 +154,7 @@ export const vendorDocumentsView = pgView("vendor_documents_view", {
d.id,
d.doc_number,
d.title,
+ d.pic,
d.status,
d.issued_date,
diff --git a/lib/form-list/table/formLists-table-toolbar-actions.tsx b/lib/form-list/table/formLists-table-toolbar-actions.tsx
index cf874985..97db9a91 100644
--- a/lib/form-list/table/formLists-table-toolbar-actions.tsx
+++ b/lib/form-list/table/formLists-table-toolbar-actions.tsx
@@ -98,13 +98,13 @@ export function FormListsTableToolbarActions({ table }: ItemsTableToolbarActions
)
// 테이블 데이터 업데이트 - 전체 페이지 새로고침 대신 데이터만 갱신
- table.resetRowSelection()
+ // table.resetRowSelection()
// 여기서 테이블 데이터를 다시 불러오는 함수를 호출
// 예: refetchTableData()
// 또는 SWR/React Query 등을 사용하고 있다면 mutate() 호출
// 리로드가 꼭 필요하다면 아래 주석 해제
- // window.location.reload()
+ window.location.reload()
} else if (data.status === 'failed') {
// 에러 처리
if (pollingRef.current) {
diff --git a/lib/vendor-document-list/table/doc-table.tsx b/lib/vendor-document-list/table/doc-table.tsx
index f70ce365..db5dc409 100644
--- a/lib/vendor-document-list/table/doc-table.tsx
+++ b/lib/vendor-document-list/table/doc-table.tsx
@@ -31,8 +31,6 @@ export function DocumentsTable({
// 1) 데이터를 가져옴 (server component -> use(...) pattern)
const [{ data, pageCount }] = React.use(promises)
- console.log(data)
-
const [rowAction, setRowAction] = React.useState<DataTableRowAction<DocumentStagesView> | null>(null)
diff --git a/lib/vendor-document/table/doc-table-column.tsx b/lib/vendor-document/table/doc-table-column.tsx
index e53b03b9..20d43fff 100644
--- a/lib/vendor-document/table/doc-table-column.tsx
+++ b/lib/vendor-document/table/doc-table-column.tsx
@@ -76,6 +76,19 @@ export function getColumns({
size: 160,
},
{
+ accessorKey: "pic",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="SHI PIC" />
+ ),
+ cell: ({ row }) => <div>{row.getValue("pic")}</div>,
+ meta: {
+ excelHeader: "SHI PIC"
+ },
+ enableResizing: true,
+ minSize: 100,
+ size: 160,
+ },
+ {
accessorKey: "latestStageName",
header: ({ column }) => (
<DataTableColumnHeaderSimple column={column} title="Latest Stage Name" />
diff --git a/lib/vendors/table/vendors-table-columns.tsx b/lib/vendors/table/vendors-table-columns.tsx
index c768b587..21086918 100644
--- a/lib/vendors/table/vendors-table-columns.tsx
+++ b/lib/vendors/table/vendors-table-columns.tsx
@@ -51,9 +51,12 @@ type NextRouter = ReturnType<typeof useRouter>;
interface GetColumnsProps {
setRowAction: React.Dispatch<React.SetStateAction<DataTableRowAction<VendorWithType> | null>>;
router: NextRouter;
- userId: number;
+ userId: number;
}
+
+
+
/**
* tanstack table 컬럼 정의 (중첩 헤더 버전)
*/
@@ -110,13 +113,13 @@ export function getColumns({ setRowAction, router, userId }: GetColumnsProps): C
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-56">
- {(isApproved ||afterApproved) && (
- <DropdownMenuItem
- onSelect={() => setRowAction({ row, type: "update" })}
- >
- 레코드 편집
- </DropdownMenuItem>
- )}
+ {(isApproved || afterApproved) && (
+ <DropdownMenuItem
+ onSelect={() => setRowAction({ row, type: "update" })}
+ >
+ 레코드 편집
+ </DropdownMenuItem>
+ )}
<DropdownMenuItem
onSelect={() => {
@@ -130,10 +133,18 @@ export function getColumns({ setRowAction, router, userId }: GetColumnsProps): C
상세보기
</DropdownMenuItem>
<DropdownMenuItem
- onSelect={() => setRowAction({ row, type: "log" })}
- >
- 감사 로그 보기
- </DropdownMenuItem>
+ onSelect={() => {
+ // 새창으로 열기 위해 window.open() 사용
+ window.open(`/evcp/vendors/${row.original.id}/info`, '_blank');
+ }}
+ >
+ 상세보기(새창)
+ </DropdownMenuItem>
+ <DropdownMenuItem
+ onSelect={() => setRowAction({ row, type: "log" })}
+ >
+ 감사 로그 보기
+ </DropdownMenuItem>
<Separator />
<DropdownMenuSub>
@@ -409,10 +420,12 @@ export function getColumns({ setRowAction, router, userId }: GetColumnsProps): C
<DataTableColumnHeaderSimple column={column} title="" />
),
cell: ({ row }) => {
- // hasAttachments 및 attachmentsList 속성이 추가되었다고 가정
- const hasAttachments = (row.original as VendorWithAttachments).hasAttachments;
- const attachmentsList = (row.original as VendorWithAttachments).attachmentsList || [];
-
+ const vendor = row.original as unknown as VendorWithAttachments;
+
+ // 속성이 undefined일 수 있으므로 옵셔널 체이닝과 기본값 사용
+ const hasAttachments = vendor.hasAttachments ?? false;
+ const attachmentsList = vendor.attachmentsList ?? [];
+
if (hasAttachments) {
// 서버 액션을 사용하는 컴포넌트로 교체
return (
diff --git a/lib/vendors/validations.ts b/lib/vendors/validations.ts
index e01fa8b9..10ea3e78 100644
--- a/lib/vendors/validations.ts
+++ b/lib/vendors/validations.ts
@@ -172,7 +172,7 @@ export const createVendorSchema = z
.min(1, "국가 선택은 필수입니다.")
.max(100, "Max length 100"),
phone: z.string().max(50, "Max length 50").optional(),
- website: z.string().url("Invalid URL").max(255).optional(),
+ website: z.string().url("유효하지 않은 URL입니다. https:// 혹은 http:// 로 시작하는 주소를 입력해주세요.").max(255).optional(),
attachedFiles: z.any()
.refine(