summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-07-09 12:19:05 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-07-09 12:19:05 +0000
commit6d654b1ba2c19e0bf1745b636908e3b00a0f02c7 (patch)
treef6d48c0d3a65b428a828acea5db65db8e7bf0db8 /lib
parent44794a8628997c0d979adb5bd6711cd848b3e397 (diff)
(대표님) 20250709 변경사항 (약 18시 30분까지)
Diffstat (limited to 'lib')
-rw-r--r--lib/admin-users/table/ausers-table-columns.tsx2
-rw-r--r--lib/b-rfq/attachment/attachment-columns.tsx8
-rw-r--r--lib/b-rfq/attachment/revision-dialog.tsx2
-rw-r--r--lib/b-rfq/final/final-rfq-detail-columns.tsx4
-rw-r--r--lib/b-rfq/initial/initial-rfq-detail-columns.tsx6
-rw-r--r--lib/b-rfq/service.ts37
-rw-r--r--lib/b-rfq/vendor-response/vendor-responses-table.tsx12
-rw-r--r--lib/basic-contract/status/basic-contract-columns.tsx2
-rw-r--r--lib/basic-contract/template/basic-contract-template-columns.tsx2
-rw-r--r--lib/bidding-projects/table/projects-table-columns.tsx2
-rw-r--r--lib/cbe/table/cbe-table-columns.tsx2
-rw-r--r--lib/cbe/table/comments-sheet.tsx2
-rw-r--r--lib/dashboard/dashboard-client.tsx6
-rw-r--r--lib/equip-class/table/equipClass-table-columns.tsx2
-rw-r--r--lib/esg-check-list/table/esg-evaluations-table-columns.tsx4
-rw-r--r--lib/evaluation-submit/table/evaluation-submissions-table-columns.tsx4
-rw-r--r--lib/form-list/table/formLists-table-columns.tsx2
-rw-r--r--lib/incoterms/table/incoterms-table-columns.tsx2
-rw-r--r--lib/items-tech/table/hull/offshore-hull-table-columns.tsx4
-rw-r--r--lib/items-tech/table/ship/items-ship-table-columns.tsx4
-rw-r--r--lib/items-tech/table/top/offshore-top-table-columns.tsx4
-rw-r--r--lib/items/table/items-table-columns.tsx2
-rw-r--r--lib/login-session/table/login-sessions-table-columns.tsx4
-rw-r--r--lib/page-visits/table/page-visits-table-columns.tsx2
-rw-r--r--lib/payment-terms/table/payment-terms-table-columns.tsx2
-rw-r--r--lib/po/service.ts2
-rw-r--r--lib/po/table/item-dialog.tsx2
-rw-r--r--lib/po/table/po-table-columns.tsx2
-rw-r--r--lib/poa/table/poa-table-columns.tsx2
-rw-r--r--lib/pq/pq-review-table-new/vendors-table-columns.tsx4
-rw-r--r--lib/pq/pq-review-table/vendors-table-columns.tsx4
-rw-r--r--lib/pq/table/pq-table-column.tsx4
-rw-r--r--lib/procurement-rfqs/services.ts4
-rw-r--r--lib/procurement-rfqs/table/detail-table/vendor-communication-drawer.tsx4
-rw-r--r--lib/procurement-rfqs/table/pr-item-dialog.tsx2
-rw-r--r--lib/project-avl/table/projectAVL-table-columns.tsx2
-rw-r--r--lib/project-gtc/table/project-gtc-table-columns.tsx4
-rw-r--r--lib/projects/table/projects-table-columns.tsx2
-rw-r--r--lib/qna/table/qna-table-columns.tsx4
-rw-r--r--lib/rfqs/cbe-table/cbe-table-columns.tsx2
-rw-r--r--lib/rfqs/cbe-table/comments-sheet.tsx2
-rw-r--r--lib/rfqs/cbe-table/invite-vendors-dialog.tsx6
-rw-r--r--lib/rfqs/table/attachment-rfq-sheet.tsx2
-rw-r--r--lib/rfqs/table/rfqs-table-columns.tsx2
-rw-r--r--lib/rfqs/tbe-table/comments-sheet.tsx2
-rw-r--r--lib/rfqs/tbe-table/file-dialog.tsx2
-rw-r--r--lib/rfqs/tbe-table/tbe-table-columns.tsx2
-rw-r--r--lib/rfqs/tbe-table/vendor-contact/vendor-contact-table-column.tsx4
-rw-r--r--lib/rfqs/validations.ts2
-rw-r--r--lib/roles/table/roles-table-columns.tsx2
-rw-r--r--lib/roles/userTable/assginedUsers-table-columns.tsx2
-rw-r--r--lib/sedp/sync-form copy.ts1037
-rw-r--r--lib/sedp/sync-form.ts503
-rw-r--r--lib/tag-numbering/table/tagNumbering-table-columns.tsx2
-rw-r--r--lib/tags/table/tag-table-column.tsx4
-rw-r--r--lib/tasks/table/tasks-table-columns.tsx2
-rw-r--r--lib/tbe/table/comments-sheet.tsx2
-rw-r--r--lib/tbe/table/file-dialog.tsx2
-rw-r--r--lib/tbe/table/tbe-table-columns.tsx2
-rw-r--r--lib/tech-project-avl/table/accepted-quotations-table-columns.tsx4
-rw-r--r--lib/tech-vendor-candidates/table/candidates-table-columns.tsx2
-rw-r--r--lib/tech-vendors/contacts-table/contact-table-columns.tsx4
-rw-r--r--lib/tech-vendors/table/tech-vendors-table-columns.tsx2
-rw-r--r--lib/techsales-rfq/service.ts2
-rw-r--r--lib/techsales-rfq/table/detail-table/quotation-history-dialog.tsx6
-rw-r--r--lib/techsales-rfq/table/detail-table/vendor-communication-drawer.tsx2
-rw-r--r--lib/techsales-rfq/table/rfq-table-column.tsx4
-rw-r--r--lib/techsales-rfq/table/tech-sales-quotation-attachments-sheet.tsx2
-rw-r--r--lib/techsales-rfq/table/tech-sales-rfq-attachments-sheet.tsx2
-rw-r--r--lib/users/access-control/users-table-columns.tsx2
-rw-r--r--lib/users/table/users-table-columns.tsx2
-rw-r--r--lib/vendor-candidates/table/candidates-table-columns.tsx2
-rw-r--r--lib/vendor-candidates/table/view-candidate_logs-dialog.tsx6
-rw-r--r--lib/vendor-evaluation-submit/table/evaluation-submissions-table-columns.tsx8
-rw-r--r--lib/vendor-type/table/vendorTypes-table-columns.tsx2
-rw-r--r--lib/vendor-users/table/ausers-table-columns.tsx2
-rw-r--r--lib/vendors/contacts-table/contact-table-columns.tsx4
-rw-r--r--lib/vendors/items-table/item-table-columns.tsx4
-rw-r--r--lib/vendors/materials-table/item-table-columns.tsx4
-rw-r--r--lib/vendors/rfq-history-table/rfq-history-table-columns.tsx2
-rw-r--r--lib/vendors/table/request-vendor-investigate-dialog.tsx4
-rw-r--r--lib/vendors/table/vendor-all-export.ts14
-rw-r--r--lib/vendors/table/vendors-table-columns.tsx4
-rw-r--r--lib/vendors/table/view-vendors_logs-dialog.tsx6
-rw-r--r--lib/welding/repository.ts2
-rw-r--r--lib/welding/table/ocr-table-columns.tsx40
86 files changed, 1537 insertions, 350 deletions
diff --git a/lib/admin-users/table/ausers-table-columns.tsx b/lib/admin-users/table/ausers-table-columns.tsx
index 38281c7e..41b78adb 100644
--- a/lib/admin-users/table/ausers-table-columns.tsx
+++ b/lib/admin-users/table/ausers-table-columns.tsx
@@ -173,7 +173,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<UserVie
if (cfg.id === "created_at") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
if (cfg.id === "roles") {
diff --git a/lib/b-rfq/attachment/attachment-columns.tsx b/lib/b-rfq/attachment/attachment-columns.tsx
index c611e06c..b726ebc8 100644
--- a/lib/b-rfq/attachment/attachment-columns.tsx
+++ b/lib/b-rfq/attachment/attachment-columns.tsx
@@ -156,13 +156,13 @@ export function getAttachmentColumns({
const updated = row.original.updatedAt as Date
return (
<div>
- <div>{formatDate(created)}</div>
+ <div>{formatDate(created, "KR")}</div>
<div className="text-xs text-muted-foreground">
{row.original.createdByName}
</div>
{updated && new Date(updated) > new Date(created) && (
<div className="text-xs text-blue-600">
- 수정: {formatDate(updated)}
+ 수정: {formatDate(updated, "KR")}
</div>
)}
</div>
@@ -252,10 +252,6 @@ export function getAttachmentColumns({
<MessageSquare className="mr-2 h-4 w-4" />
벤더 응답 보기
</DropdownMenuItem>
- <DropdownMenuItem>
- <Eye className="mr-2 h-4 w-4" />
- 미리보기
- </DropdownMenuItem>
<DropdownMenuItem
onClick={() => row.original.filePath && window.open(row.original.filePath, "_blank")}
>
diff --git a/lib/b-rfq/attachment/revision-dialog.tsx b/lib/b-rfq/attachment/revision-dialog.tsx
index b1fe1576..d26abedb 100644
--- a/lib/b-rfq/attachment/revision-dialog.tsx
+++ b/lib/b-rfq/attachment/revision-dialog.tsx
@@ -143,7 +143,7 @@ export function RevisionDialog({
</TableCell>
<TableCell>
- {formatDate(revision.createdAt)}
+ {formatDate(revision.createdAt, "KR")}
</TableCell>
<TableCell>
diff --git a/lib/b-rfq/final/final-rfq-detail-columns.tsx b/lib/b-rfq/final/final-rfq-detail-columns.tsx
index 832923eb..88d62765 100644
--- a/lib/b-rfq/final/final-rfq-detail-columns.tsx
+++ b/lib/b-rfq/final/final-rfq-detail-columns.tsx
@@ -351,7 +351,7 @@ export function getFinalRfqDetailColumns({
const deliveryDate = row.getValue("deliveryDate") as Date
return deliveryDate ? (
<div className="text-sm">
- {formatDate(deliveryDate)}
+ {formatDate(deliveryDate, "KR")}
</div>
) : (
<span className="text-muted-foreground">-</span>
@@ -487,7 +487,7 @@ export function getFinalRfqDetailColumns({
const updated = row.getValue("updatedAt") as Date
return updated ? (
<div className="text-sm">
- {formatDate(updated)}
+ {formatDate(updated, "KR")}
</div>
) : (
<span className="text-muted-foreground">-</span>
diff --git a/lib/b-rfq/initial/initial-rfq-detail-columns.tsx b/lib/b-rfq/initial/initial-rfq-detail-columns.tsx
index f2be425c..2d9c3a68 100644
--- a/lib/b-rfq/initial/initial-rfq-detail-columns.tsx
+++ b/lib/b-rfq/initial/initial-rfq-detail-columns.tsx
@@ -288,7 +288,7 @@ export function getInitialRfqDetailColumns({
const validDate = row.getValue("validDate") as Date
return validDate ? (
<div className="text-sm">
- {formatDate(validDate)}
+ {formatDate(validDate, "KR")}
</div>
) : (
<span className="text-muted-foreground">-</span>
@@ -307,7 +307,7 @@ export function getInitialRfqDetailColumns({
return dueDate ? (
<div className={`${isOverdue ? 'text-red-600' : ''}`}>
- <div className="font-medium">{formatDate(dueDate)}</div>
+ <div className="font-medium">{formatDate(dueDate, "KR")}</div>
{isOverdue && (
<div className="text-xs text-red-600">지연</div>
)}
@@ -384,7 +384,7 @@ export function getInitialRfqDetailColumns({
return (
<div className="space-y-1">
- <div className="text-sm">{formatDate(created)}</div>
+ <div className="text-sm">{formatDate(created, "KR")}</div>
{updated && new Date(updated) > new Date(created) && (
<div className="text-xs text-blue-600">
수정: {formatDate(updated, "KR")}
diff --git a/lib/b-rfq/service.ts b/lib/b-rfq/service.ts
index 4def634b..2ef57b34 100644
--- a/lib/b-rfq/service.ts
+++ b/lib/b-rfq/service.ts
@@ -498,7 +498,7 @@ export async function getVendorResponsesForAttachment(
rfqType: 'INITIAL' | 'FINAL' = 'INITIAL'
) {
try {
- // 1. 기본 벤더 응답 정보 가져오기
+ // 1. 기본 벤더 응답 정보 가져오기 (첨부파일 정보와 조인)
const responses = await db
.select({
id: vendorAttachmentResponses.id,
@@ -510,10 +510,16 @@ export async function getVendorResponsesForAttachment(
rfqType: vendorAttachmentResponses.rfqType,
rfqRecordId: vendorAttachmentResponses.rfqRecordId,
responseStatus: vendorAttachmentResponses.responseStatus,
- currentRevision: vendorAttachmentResponses.currentRevision,
+
+ // 첨부파일의 현재 리비전 (가장 중요!)
+ currentRevision: bRfqsAttachments.currentRevision,
+
+ // 벤더가 응답한 리비전
respondedRevision: vendorAttachmentResponses.respondedRevision,
+
responseComment: vendorAttachmentResponses.responseComment,
vendorComment: vendorAttachmentResponses.vendorComment,
+
// 새로 추가된 필드들
revisionRequestComment: vendorAttachmentResponses.revisionRequestComment,
revisionRequestedAt: vendorAttachmentResponses.revisionRequestedAt,
@@ -523,6 +529,7 @@ export async function getVendorResponsesForAttachment(
})
.from(vendorAttachmentResponses)
.leftJoin(vendors, eq(vendorAttachmentResponses.vendorId, vendors.id))
+ .leftJoin(bRfqsAttachments, eq(vendorAttachmentResponses.attachmentId, bRfqsAttachments.id))
.where(
and(
eq(vendorAttachmentResponses.attachmentId, attachmentId),
@@ -553,15 +560,23 @@ export async function getVendorResponsesForAttachment(
.orderBy(desc(vendorResponseAttachmentsB.uploadedAt));
}
- // 3. 응답에 파일 정보 병합
- const enhancedResponses = responses.map(response => ({
- ...response,
- files: responseFiles.filter(file => file.vendorResponseId === response.id),
- totalFiles: responseFiles.filter(file => file.vendorResponseId === response.id).length,
- latestFile: responseFiles
- .filter(file => file.vendorResponseId === response.id)
- .sort((a, b) => new Date(b.uploadedAt).getTime() - new Date(a.uploadedAt).getTime())[0] || null,
- }));
+ // 3. 응답에 파일 정보 병합 및 리비전 상태 체크
+ const enhancedResponses = responses.map(response => {
+ const files = responseFiles.filter(file => file.vendorResponseId === response.id);
+ const latestFile = files
+ .sort((a, b) => new Date(b.uploadedAt).getTime() - new Date(a.uploadedAt).getTime())[0] || null;
+
+ // 벤더가 최신 리비전에 응답했는지 체크
+ const isUpToDate = response.respondedRevision === response.currentRevision;
+
+ return {
+ ...response,
+ files,
+ totalFiles: files.length,
+ latestFile,
+ isUpToDate, // 최신 리비전 응답 여부
+ };
+ });
return enhancedResponses;
} catch (err) {
diff --git a/lib/b-rfq/vendor-response/vendor-responses-table.tsx b/lib/b-rfq/vendor-response/vendor-responses-table.tsx
index 251b1ad0..02a5fa59 100644
--- a/lib/b-rfq/vendor-response/vendor-responses-table.tsx
+++ b/lib/b-rfq/vendor-response/vendor-responses-table.tsx
@@ -52,20 +52,12 @@ export function VendorResponsesTable({ promises }: VendorResponsesTableProps) {
]
},
- {
- id: "rfqCode",
- label: "RFQ 번호",
- placeholder: "RFQ 번호 검색...",
- }
+
];
// 고급 필터 필드
const advancedFilterFields: DataTableAdvancedFilterField<VendorRfqResponseSummary>[] = [
- {
- id: "rfqCode",
- label: "RFQ 번호",
- type: "text",
- },
+
{
id: "overallStatus",
label: "전체 상태",
diff --git a/lib/basic-contract/status/basic-contract-columns.tsx b/lib/basic-contract/status/basic-contract-columns.tsx
index 54504be4..cc9d9bff 100644
--- a/lib/basic-contract/status/basic-contract-columns.tsx
+++ b/lib/basic-contract/status/basic-contract-columns.tsx
@@ -106,7 +106,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<BasicCo
// 날짜 형식 처리
if (cfg.id === "createdAt" || cfg.id === "updatedAt") {
const dateVal = cell.getValue() as Date
- return formatDateTime(dateVal)
+ return formatDateTime(dateVal, "KR")
}
// Status 컬럼에 Badge 적용 (확장)
diff --git a/lib/basic-contract/template/basic-contract-template-columns.tsx b/lib/basic-contract/template/basic-contract-template-columns.tsx
index b0486fe4..5f4433d1 100644
--- a/lib/basic-contract/template/basic-contract-template-columns.tsx
+++ b/lib/basic-contract/template/basic-contract-template-columns.tsx
@@ -186,7 +186,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<BasicCo
// 날짜 형식 처리
if (cfg.id === "createdAt" || cfg.id === "updatedAt") {
const dateVal = cell.getValue() as Date
- return formatDateTime(dateVal)
+ return formatDateTime(dateVal, "KR")
}
// Status 컬럼에 Badge 적용
diff --git a/lib/bidding-projects/table/projects-table-columns.tsx b/lib/bidding-projects/table/projects-table-columns.tsx
index b8f3b91b..f1e23be9 100644
--- a/lib/bidding-projects/table/projects-table-columns.tsx
+++ b/lib/bidding-projects/table/projects-table-columns.tsx
@@ -43,7 +43,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<Bidding
cell: ({ row, cell }) => {
if (cfg.id === "createdAt" || cfg.id === "updatedAt") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
return row.getValue(cfg.id) ?? ""
},
diff --git a/lib/cbe/table/cbe-table-columns.tsx b/lib/cbe/table/cbe-table-columns.tsx
index 2da62ea8..552a0249 100644
--- a/lib/cbe/table/cbe-table-columns.tsx
+++ b/lib/cbe/table/cbe-table-columns.tsx
@@ -158,7 +158,7 @@ export function getColumns({
if (cfg.id === "respondedAt") {
const dateVal = val as Date | undefined
if (!dateVal) return null
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
// 그 외 필드는 기본 값 표시
diff --git a/lib/cbe/table/comments-sheet.tsx b/lib/cbe/table/comments-sheet.tsx
index 2ac9049f..b4647e7a 100644
--- a/lib/cbe/table/comments-sheet.tsx
+++ b/lib/cbe/table/comments-sheet.tsx
@@ -176,7 +176,7 @@ export function CommentSheet({
</div>
)}
</TableCell>
- <TableCell> { c.createdAt ? formatDate(c.createdAt): "-"}</TableCell>
+ <TableCell> { c.createdAt ? formatDate(c.createdAt, "KR"): "-"}</TableCell>
<TableCell>
{c.commentedByEmail ?? "-"}
</TableCell>
diff --git a/lib/dashboard/dashboard-client.tsx b/lib/dashboard/dashboard-client.tsx
index cda1ed8e..398a18f2 100644
--- a/lib/dashboard/dashboard-client.tsx
+++ b/lib/dashboard/dashboard-client.tsx
@@ -68,14 +68,14 @@ export function DashboardClient({ initialData }: DashboardClientProps) {
<div className="flex items-center justify-between">
<div>
<h2 className="text-2xl font-bold tracking-tight">
- {getDomainDisplayName(domain)} Dashboard
+ {getDomainDisplayName(domain)} 대시보드
</h2>
- <p className="text-muted-foreground">
+ {/* <p className="text-muted-foreground">
{domain === "partners"
? "회사와 개인에게 할당된 일들을 보여줍니다."
: "팀과 개인에게 할당된 일들을 보여줍니다."
}
- </p>
+ </p> */}
</div>
<Button
onClick={handleRefresh}
diff --git a/lib/equip-class/table/equipClass-table-columns.tsx b/lib/equip-class/table/equipClass-table-columns.tsx
index d149c836..0dfbf06f 100644
--- a/lib/equip-class/table/equipClass-table-columns.tsx
+++ b/lib/equip-class/table/equipClass-table-columns.tsx
@@ -50,7 +50,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<Extende
if (cfg.id === "createdAt"||cfg.id === "updatedAt") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
return row.getValue(cfg.id) ?? ""
diff --git a/lib/esg-check-list/table/esg-evaluations-table-columns.tsx b/lib/esg-check-list/table/esg-evaluations-table-columns.tsx
index 399f9f4a..48139c75 100644
--- a/lib/esg-check-list/table/esg-evaluations-table-columns.tsx
+++ b/lib/esg-check-list/table/esg-evaluations-table-columns.tsx
@@ -206,7 +206,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<EsgEval
),
cell: ({ row }) => {
const date = row.getValue("createdAt") as Date
- return formatDate(date)
+ return formatDate(date, "KR")
},
},
{
@@ -216,7 +216,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<EsgEval
),
cell: ({ row }) => {
const date = row.getValue("updatedAt") as Date
- return formatDate(date)
+ return formatDate(date, "KR")
},
},
]
diff --git a/lib/evaluation-submit/table/evaluation-submissions-table-columns.tsx b/lib/evaluation-submit/table/evaluation-submissions-table-columns.tsx
index 1ec0284f..8d097aff 100644
--- a/lib/evaluation-submit/table/evaluation-submissions-table-columns.tsx
+++ b/lib/evaluation-submit/table/evaluation-submissions-table-columns.tsx
@@ -376,7 +376,7 @@ export function getColumns({ setRowAction, router }: GetColumnsProps): ColumnDef
),
cell: ({ row }) => {
const date = row.getValue("reviewerEvaluationCreatedAt") as Date;
- return formatDate(date);
+ return formatDate(date, "KR");
},
size: 140,
},
@@ -387,7 +387,7 @@ export function getColumns({ setRowAction, router }: GetColumnsProps): ColumnDef
),
cell: ({ row }) => {
const date = row.getValue("reviewerEvaluationUpdatedAt") as Date;
- return formatDate(date);
+ return formatDate(date, "KR");
},
size: 140,
},
diff --git a/lib/form-list/table/formLists-table-columns.tsx b/lib/form-list/table/formLists-table-columns.tsx
index 5b120796..b992feb3 100644
--- a/lib/form-list/table/formLists-table-columns.tsx
+++ b/lib/form-list/table/formLists-table-columns.tsx
@@ -91,7 +91,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<FormLis
if (cfg.id === "createdAt"||cfg.id === "updatedAt") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
return row.getValue(cfg.id) ?? ""
diff --git a/lib/incoterms/table/incoterms-table-columns.tsx b/lib/incoterms/table/incoterms-table-columns.tsx
index 91ce4482..3e25e1d3 100644
--- a/lib/incoterms/table/incoterms-table-columns.tsx
+++ b/lib/incoterms/table/incoterms-table-columns.tsx
@@ -159,7 +159,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<typeof
},
cell: ({ row }) => {
const dateVal = row.getValue("createdAt") as Date
- return formatDateTime(dateVal)
+ return formatDateTime(dateVal, "KR")
},
minSize: 80
}
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 efc6c583..19782c42 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),
+ cell: ({ row }) => formatDate(row.original.createdAt, "KR"),
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),
+ cell: ({ row }) => formatDate(row.original.updatedAt, "KR"),
enableSorting: true,
enableHiding: true,
meta: {
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 13ba2480..7018ae43 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),
+ cell: ({ row }) => formatDate(row.original.createdAt, "KR"),
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),
+ cell: ({ row }) => formatDate(row.original.updatedAt, "KR"),
enableSorting: true,
enableHiding: true,
meta: {
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 93f27492..c2df4b75 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),
+ cell: ({ row }) => formatDate(row.original.createdAt, "KR"),
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),
+ cell: ({ row }) => formatDate(row.original.updatedAt, "KR"),
enableSorting: true,
enableHiding: true,
meta: {
diff --git a/lib/items/table/items-table-columns.tsx b/lib/items/table/items-table-columns.tsx
index 8dd84c58..e321fe1a 100644
--- a/lib/items/table/items-table-columns.tsx
+++ b/lib/items/table/items-table-columns.tsx
@@ -138,7 +138,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<Item>[]
if (cfg.id === "createdAt"||cfg.id === "updatedAt") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
return row.getValue(cfg.id) ?? ""
diff --git a/lib/login-session/table/login-sessions-table-columns.tsx b/lib/login-session/table/login-sessions-table-columns.tsx
index 5d2389be..899678f3 100644
--- a/lib/login-session/table/login-sessions-table-columns.tsx
+++ b/lib/login-session/table/login-sessions-table-columns.tsx
@@ -89,7 +89,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<Extende
</div>
</TooltipTrigger>
<TooltipContent>
- {formatDate(date)}
+ {formatDate(date, "KR")}
</TooltipContent>
</Tooltip>
)
@@ -113,7 +113,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<Extende
</div>
</TooltipTrigger>
<TooltipContent>
- {formatDate(date)}
+ {formatDate(date, "KR")}
</TooltipContent>
</Tooltip>
)
diff --git a/lib/page-visits/table/page-visits-table-columns.tsx b/lib/page-visits/table/page-visits-table-columns.tsx
index e1d2fed4..86f2d9c3 100644
--- a/lib/page-visits/table/page-visits-table-columns.tsx
+++ b/lib/page-visits/table/page-visits-table-columns.tsx
@@ -125,7 +125,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<Extende
</div>
</TooltipTrigger>
<TooltipContent>
- {formatDate(date)}
+ {formatDate(date, "KR")}
</TooltipContent>
</Tooltip>
)
diff --git a/lib/payment-terms/table/payment-terms-table-columns.tsx b/lib/payment-terms/table/payment-terms-table-columns.tsx
index 08d30482..ecf20229 100644
--- a/lib/payment-terms/table/payment-terms-table-columns.tsx
+++ b/lib/payment-terms/table/payment-terms-table-columns.tsx
@@ -159,7 +159,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<typeof
},
cell: ({ row }) => {
const dateVal = row.getValue("createdAt") as Date
- return formatDateTime(dateVal)
+ return formatDateTime(dateVal, "KR")
},
minSize: 80
}
diff --git a/lib/po/service.ts b/lib/po/service.ts
index f62b57fa..99033854 100644
--- a/lib/po/service.ts
+++ b/lib/po/service.ts
@@ -289,7 +289,7 @@ export async function requestSignatures(
},
{
tabLabel: "remark",
- value: `결제 조건: ${contract.paymentTerms}
+ value: `지급 조건: ${contract.paymentTerms}
납품 조건: ${contract.deliveryTerms}
납품 기한: ${contract.deliveryDate}
납품 장소: ${contract.deliveryLocation}
diff --git a/lib/po/table/item-dialog.tsx b/lib/po/table/item-dialog.tsx
index a6690e75..ce4e4741 100644
--- a/lib/po/table/item-dialog.tsx
+++ b/lib/po/table/item-dialog.tsx
@@ -147,7 +147,7 @@ export function ItemsDialog({ open, onOpenChange, po }: ItemsDialogProps) {
<div className="mt-3 pt-2 border-t text-xs text-muted-foreground flex items-center">
<Clock className="mr-1 h-3 w-3" />
- Updated: {formatDate(item.updatedAt)}
+ Updated: {formatDate(item.updatedAt, "KR")}
</div>
</CardContent>
</Card>
diff --git a/lib/po/table/po-table-columns.tsx b/lib/po/table/po-table-columns.tsx
index 6834e543..7edd2435 100644
--- a/lib/po/table/po-table-columns.tsx
+++ b/lib/po/table/po-table-columns.tsx
@@ -250,7 +250,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<Contrac
// 날짜 포맷, 숫자 포맷 등 처리
if (cfg.type === "date") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
// ...
return row.getValue(cfg.id) ?? ""
diff --git a/lib/poa/table/poa-table-columns.tsx b/lib/poa/table/poa-table-columns.tsx
index b362e54c..7aad609e 100644
--- a/lib/poa/table/poa-table-columns.tsx
+++ b/lib/poa/table/poa-table-columns.tsx
@@ -112,7 +112,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<POADeta
const dateVal = value as Date;
return (
<div className="text-sm">
- {formatDate(dateVal)}
+ {formatDate(dateVal, "KR")}
</div>
);
}
diff --git a/lib/pq/pq-review-table-new/vendors-table-columns.tsx b/lib/pq/pq-review-table-new/vendors-table-columns.tsx
index 0491f1dc..6bfa8c7f 100644
--- a/lib/pq/pq-review-table-new/vendors-table-columns.tsx
+++ b/lib/pq/pq-review-table-new/vendors-table-columns.tsx
@@ -508,10 +508,10 @@ export function getColumns({ setRowAction, router }: GetColumnsProps): ColumnDef
),
cell: ({ row }) => {
if (row.original.approvedAt) {
- return <span className="text-green-600">{formatDate(row.original.approvedAt)}</span>
+ return <span className="text-green-600">{formatDate(row.original.approvedAt, "KR")}</span>
}
if (row.original.rejectedAt) {
- return <span className="text-red-600">{formatDate(row.original.rejectedAt)}</span>
+ return <span className="text-red-600">{formatDate(row.original.rejectedAt, "KR")}</span>
}
return "-"
},
diff --git a/lib/pq/pq-review-table/vendors-table-columns.tsx b/lib/pq/pq-review-table/vendors-table-columns.tsx
index 8673443f..dfa1c44f 100644
--- a/lib/pq/pq-review-table/vendors-table-columns.tsx
+++ b/lib/pq/pq-review-table/vendors-table-columns.tsx
@@ -160,12 +160,12 @@ export function getColumns({ setRowAction, router }: GetColumnsProps): ColumnDef
if (cfg.id === "createdAt") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
if (cfg.id === "updatedAt") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
diff --git a/lib/pq/table/pq-table-column.tsx b/lib/pq/table/pq-table-column.tsx
index 7efed645..b9317570 100644
--- a/lib/pq/table/pq-table-column.tsx
+++ b/lib/pq/table/pq-table-column.tsx
@@ -124,7 +124,7 @@ export function getColumns({
header: ({ column }) => (
<DataTableColumnHeaderSimple column={column} title="Created At" />
),
- cell: ({ cell }) => formatDateTime(cell.getValue() as Date),
+ cell: ({ cell }) => formatDateTime(cell.getValue() as Date, "KR"),
meta: {
excelHeader: "created At"
},
@@ -137,7 +137,7 @@ export function getColumns({
header: ({ column }) => (
<DataTableColumnHeaderSimple column={column} title="Updated At" />
),
- cell: ({ cell }) => formatDateTime(cell.getValue() as Date),
+ cell: ({ cell }) => formatDateTime(cell.getValue() as Date, "KR"),
meta: {
excelHeader: "updated At"
},
diff --git a/lib/procurement-rfqs/services.ts b/lib/procurement-rfqs/services.ts
index 3816605c..9cca4c73 100644
--- a/lib/procurement-rfqs/services.ts
+++ b/lib/procurement-rfqs/services.ts
@@ -940,8 +940,8 @@ export async function sendRfq(rfqId: number) {
projectCode: rfq.project?.code || '',
projectName: rfq.project?.name || '',
description: rfq.remark || '',
- dueDate: rfq.dueDate ? formatDate(rfq.dueDate) : 'N/A',
- deliveryDate: detail.deliveryDate ? formatDate(detail.deliveryDate) : 'N/A',
+ dueDate: rfq.dueDate ? formatDate(rfq.dueDate, "KR") : 'N/A',
+ deliveryDate: detail.deliveryDate ? formatDate(detail.deliveryDate, "KR") : 'N/A',
},
vendor: {
id: detail.vendor.id,
diff --git a/lib/procurement-rfqs/table/detail-table/vendor-communication-drawer.tsx b/lib/procurement-rfqs/table/detail-table/vendor-communication-drawer.tsx
index 34efdfc2..e43fc676 100644
--- a/lib/procurement-rfqs/table/detail-table/vendor-communication-drawer.tsx
+++ b/lib/procurement-rfqs/table/detail-table/vendor-communication-drawer.tsx
@@ -278,7 +278,7 @@ export function VendorCommunicationDrawer({
{selectedAttachment.fileName}
</DialogTitle>
<DialogDescription>
- {formatFileSize(selectedAttachment.fileSize)} • {formatDateTime(selectedAttachment.uploadedAt)}
+ {formatFileSize(selectedAttachment.fileSize)} • {formatDateTime(selectedAttachment.uploadedAt, "KR")}
</DialogDescription>
</DialogHeader>
@@ -417,7 +417,7 @@ export function VendorCommunicationDrawer({
)}
<div className="text-xs mt-1 opacity-70 flex items-center gap-1 justify-end">
- {formatDateTime(comment.createdAt)}
+ {formatDateTime(comment.createdAt, "KR")}
</div>
</div>
diff --git a/lib/procurement-rfqs/table/pr-item-dialog.tsx b/lib/procurement-rfqs/table/pr-item-dialog.tsx
index 4523295d..aada8438 100644
--- a/lib/procurement-rfqs/table/pr-item-dialog.tsx
+++ b/lib/procurement-rfqs/table/pr-item-dialog.tsx
@@ -217,7 +217,7 @@ export function PrDetailsDialog({
<TableCell>{item.materialDescription || "-"}</TableCell>
<TableCell className="whitespace-nowrap">{item.size || "-"}</TableCell>
<TableCell className="whitespace-nowrap">
- {item.deliveryDate ? formatDate(item.deliveryDate) : "-"}
+ {item.deliveryDate ? formatDate(item.deliveryDate, "KR") : "-"}
</TableCell>
<TableCell className="whitespace-nowrap">{item.quantity || "-"}</TableCell>
<TableCell className="whitespace-nowrap">{item.uom || "-"}</TableCell>
diff --git a/lib/project-avl/table/projectAVL-table-columns.tsx b/lib/project-avl/table/projectAVL-table-columns.tsx
index 916380e3..27e0ab42 100644
--- a/lib/project-avl/table/projectAVL-table-columns.tsx
+++ b/lib/project-avl/table/projectAVL-table-columns.tsx
@@ -64,7 +64,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<Project
if (cfg.id === "submitted_at"||cfg.id === "approved_at") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
return row.getValue(cfg.id) ?? ""
diff --git a/lib/project-gtc/table/project-gtc-table-columns.tsx b/lib/project-gtc/table/project-gtc-table-columns.tsx
index 141d5737..2605e365 100644
--- a/lib/project-gtc/table/project-gtc-table-columns.tsx
+++ b/lib/project-gtc/table/project-gtc-table-columns.tsx
@@ -273,7 +273,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<Project
return (
<div className="flex items-center">
<span>
- {formatDateTime(new Date(date))}
+ {formatDateTime(new Date(date), "KR")}
</span>
</div>
)
@@ -290,7 +290,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<Project
return (
<div className="flex items-center">
<span>
- {formatDate(new Date(date))}
+ {formatDate(new Date(date), "KR")}
</span>
</div>
)
diff --git a/lib/projects/table/projects-table-columns.tsx b/lib/projects/table/projects-table-columns.tsx
index 77899212..6926429a 100644
--- a/lib/projects/table/projects-table-columns.tsx
+++ b/lib/projects/table/projects-table-columns.tsx
@@ -50,7 +50,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<Project
if (cfg.id === "createdAt"||cfg.id === "updatedAt") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
return row.getValue(cfg.id) ?? ""
diff --git a/lib/qna/table/qna-table-columns.tsx b/lib/qna/table/qna-table-columns.tsx
index 01431e35..0aa30d88 100644
--- a/lib/qna/table/qna-table-columns.tsx
+++ b/lib/qna/table/qna-table-columns.tsx
@@ -242,7 +242,7 @@ export function getColumns({ setRowAction, router, currentUserId }: GetColumnsOp
),
cell: ({ row }) => (
<div className="text-sm">
- {formatDate(row.original.createdAt)}
+ {formatDate(row.original.createdAt, "KR")}
</div>
),
enableSorting: true,
@@ -262,7 +262,7 @@ export function getColumns({ setRowAction, router, currentUserId }: GetColumnsOp
return (
<div className="text-sm">
- {lastActivity ? formatDate(lastActivity) : "없음"}
+ {lastActivity ? formatDate(lastActivity, "KR") : "없음"}
</div>
)
},
diff --git a/lib/rfqs/cbe-table/cbe-table-columns.tsx b/lib/rfqs/cbe-table/cbe-table-columns.tsx
index bc16496f..aa244c75 100644
--- a/lib/rfqs/cbe-table/cbe-table-columns.tsx
+++ b/lib/rfqs/cbe-table/cbe-table-columns.tsx
@@ -157,7 +157,7 @@ export function getColumns({
if (cfg.id === "respondedAt" ) {
const dateVal = val as Date | undefined
if (!dateVal) return null
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
// 그 외 필드는 기본 값 표시
diff --git a/lib/rfqs/cbe-table/comments-sheet.tsx b/lib/rfqs/cbe-table/comments-sheet.tsx
index e91a0617..b040d734 100644
--- a/lib/rfqs/cbe-table/comments-sheet.tsx
+++ b/lib/rfqs/cbe-table/comments-sheet.tsx
@@ -167,7 +167,7 @@ export function CommentSheet({
</div>
)}
</TableCell>
- <TableCell> {c.createdAt ? formatDate(c.createdAt) : "-"}</TableCell>
+ <TableCell> {c.createdAt ? formatDate(c.createdAt, "KR") : "-"}</TableCell>
<TableCell>{c.commentedByEmail ?? "-"}</TableCell>
</TableRow>
))}
diff --git a/lib/rfqs/cbe-table/invite-vendors-dialog.tsx b/lib/rfqs/cbe-table/invite-vendors-dialog.tsx
index 18edbe80..8d69e765 100644
--- a/lib/rfqs/cbe-table/invite-vendors-dialog.tsx
+++ b/lib/rfqs/cbe-table/invite-vendors-dialog.tsx
@@ -50,7 +50,7 @@ import { createCbeEvaluation } from "../service"
// 컴포넌트 내부에서 사용할 폼 스키마 정의
const formSchema = z.object({
- paymentTerms: z.string().min(1, "결제 조건을 입력하세요"),
+ paymentTerms: z.string().min(1, "지급 조건을 입력하세요"),
incoterms: z.string().min(1, "Incoterms를 입력하세요"),
deliverySchedule: z.string().min(1, "배송 일정을 입력하세요"),
notes: z.string().optional(),
@@ -233,14 +233,14 @@ export function InviteVendorsDialog({
</div>
)}
- {/* 결제 조건 - 필수 필드 */}
+ {/* 지급 조건 - 필수 필드 */}
<FormField
control={form.control}
name="paymentTerms"
render={({ field }) => (
<FormItem>
<FormLabel>
- 결제 조건{RequiredLabel}
+ 지급 조건{RequiredLabel}
</FormLabel>
<FormControl>
<Input {...field} placeholder="예: Net 30" />
diff --git a/lib/rfqs/table/attachment-rfq-sheet.tsx b/lib/rfqs/table/attachment-rfq-sheet.tsx
index 57a170e1..75235b32 100644
--- a/lib/rfqs/table/attachment-rfq-sheet.tsx
+++ b/lib/rfqs/table/attachment-rfq-sheet.tsx
@@ -291,7 +291,7 @@ export function RfqAttachmentsSheet({
)}
{field.createdAt && (
<span className="text-xs text-muted-foreground">
- Created at {formatDate(field.createdAt)}
+ Created at {formatDate(field.createdAt, "KR")}
</span>
)}
</div>
diff --git a/lib/rfqs/table/rfqs-table-columns.tsx b/lib/rfqs/table/rfqs-table-columns.tsx
index 98df3bc8..5c09fcf0 100644
--- a/lib/rfqs/table/rfqs-table-columns.tsx
+++ b/lib/rfqs/table/rfqs-table-columns.tsx
@@ -278,7 +278,7 @@ export function getColumns({
if (cfg.id === "createdAt" || cfg.id === "updatedAt") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
return row.getValue(cfg.id) ?? ""
diff --git a/lib/rfqs/tbe-table/comments-sheet.tsx b/lib/rfqs/tbe-table/comments-sheet.tsx
index 6efd631f..b3cdbc60 100644
--- a/lib/rfqs/tbe-table/comments-sheet.tsx
+++ b/lib/rfqs/tbe-table/comments-sheet.tsx
@@ -165,7 +165,7 @@ export function CommentSheet({
</div>
)}
</TableCell>
- <TableCell> {c.createdAt ? formatDate(c.createdAt) : "-"}</TableCell>
+ <TableCell> {c.createdAt ? formatDate(c.createdAt, "KR") : "-"}</TableCell>
<TableCell>{c.commentedByEmail ?? "-"}</TableCell>
</TableRow>
))}
diff --git a/lib/rfqs/tbe-table/file-dialog.tsx b/lib/rfqs/tbe-table/file-dialog.tsx
index 772eb930..e19430a3 100644
--- a/lib/rfqs/tbe-table/file-dialog.tsx
+++ b/lib/rfqs/tbe-table/file-dialog.tsx
@@ -118,7 +118,7 @@ export function TBEFileDialog({
<FileListInfo className="flex-1 min-w-0">
<FileListName className="text-sm font-medium truncate">{file.fileName}</FileListName>
<FileListDescription className="text-xs text-muted-foreground">
- {file.uploadedAt ? formatDateTime(file.uploadedAt) : ""}
+ {file.uploadedAt ? formatDateTime(file.uploadedAt, "KR") : ""}
</FileListDescription>
</FileListInfo>
</div>
diff --git a/lib/rfqs/tbe-table/tbe-table-columns.tsx b/lib/rfqs/tbe-table/tbe-table-columns.tsx
index e8566831..0538d354 100644
--- a/lib/rfqs/tbe-table/tbe-table-columns.tsx
+++ b/lib/rfqs/tbe-table/tbe-table-columns.tsx
@@ -208,7 +208,7 @@ export function getColumns({
if (cfg.id === "tbeUpdated") {
const dateVal = val as Date | undefined
if (!dateVal) return null
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
// 그 외 필드는 기본 값 표시
diff --git a/lib/rfqs/tbe-table/vendor-contact/vendor-contact-table-column.tsx b/lib/rfqs/tbe-table/vendor-contact/vendor-contact-table-column.tsx
index fcd0c3fb..efc395b4 100644
--- a/lib/rfqs/tbe-table/vendor-contact/vendor-contact-table-column.tsx
+++ b/lib/rfqs/tbe-table/vendor-contact/vendor-contact-table-column.tsx
@@ -55,7 +55,7 @@ export function getColumns(): ColumnDef<VendorData>[] {
header: ({ column }) => (
<ClientDataTableColumnHeaderSimple column={column} title="Created At" />
),
- cell: ({ cell }) => formatDate(cell.getValue() as Date),
+ cell: ({ cell }) => formatDate(cell.getValue() as Date, "KR"),
},
// Updated At
@@ -64,7 +64,7 @@ export function getColumns(): ColumnDef<VendorData>[] {
header: ({ column }) => (
<ClientDataTableColumnHeaderSimple column={column} title="Updated At" />
),
- cell: ({ cell }) => formatDate(cell.getValue() as Date),
+ cell: ({ cell }) => formatDate(cell.getValue() as Date, "KR"),
},
]
} \ No newline at end of file
diff --git a/lib/rfqs/validations.ts b/lib/rfqs/validations.ts
index 7f39d0a6..8752f693 100644
--- a/lib/rfqs/validations.ts
+++ b/lib/rfqs/validations.ts
@@ -287,7 +287,7 @@ export type GetCBESchema = Awaited<ReturnType<typeof searchParamsCBECache.parse>
export const createCbeEvaluationSchema = z.object({
- paymentTerms: z.string().min(1, "결제 조건을 입력하세요"),
+ paymentTerms: z.string().min(1, "지급 조건을 입력하세요"),
incoterms: z.string().min(1, "Incoterms를 입력하세요"),
deliverySchedule: z.string().min(1, "배송 일정을 입력하세요"),
notes: z.string().optional(),
diff --git a/lib/roles/table/roles-table-columns.tsx b/lib/roles/table/roles-table-columns.tsx
index 3a491585..16249999 100644
--- a/lib/roles/table/roles-table-columns.tsx
+++ b/lib/roles/table/roles-table-columns.tsx
@@ -149,7 +149,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<RoleVie
if (cfg.id === "created_at") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
if (cfg.id === "domain") {
diff --git a/lib/roles/userTable/assginedUsers-table-columns.tsx b/lib/roles/userTable/assginedUsers-table-columns.tsx
index b317a465..950c6d7a 100644
--- a/lib/roles/userTable/assginedUsers-table-columns.tsx
+++ b/lib/roles/userTable/assginedUsers-table-columns.tsx
@@ -106,7 +106,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<UserVie
if (cfg.id === "created_at") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
if (cfg.id === "roles") {
diff --git a/lib/sedp/sync-form copy.ts b/lib/sedp/sync-form copy.ts
new file mode 100644
index 00000000..2cb677b7
--- /dev/null
+++ b/lib/sedp/sync-form copy.ts
@@ -0,0 +1,1037 @@
+// src/lib/cron/syncTagFormMappings.ts
+import db from "@/db/db";
+import { projects, tagTypes, tagClasses, tagTypeClassFormMappings, formMetas, forms, contractItems, items, contracts } from '@/db/schema';
+import { eq, and, inArray, ilike } from 'drizzle-orm';
+import { getSEDPToken } from "./sedp-token";
+
+// 환경 변수
+const SEDP_API_BASE_URL = process.env.SEDP_API_BASE_URL || 'http://sedpwebapi.ship.samsung.co.kr/api';
+
+// 인터페이스 정의
+interface TagTypeClassFormMapping {
+ projectId: number;
+ tagTypeLabel: string;
+ classLabel: string;
+ formCode: string;
+ formName: string;
+ remark: string | null;
+ ep: string;
+ createdAt: Date;
+ updatedAt: Date;
+}
+
+interface FormMeta {
+ projectId: number;
+ formCode: string;
+ formName: string;
+ columns: string; // JSON 문자열
+ createdAt: Date;
+ updatedAt: Date;
+}
+
+interface FormRecord {
+ contractItemId: number;
+ formCode: string;
+ formName: string;
+ eng: boolean;
+ createdAt: Date;
+ updatedAt: Date;
+}
+interface Register {
+ PROJ_NO: string;
+ TYPE_ID: string;
+ EP_ID: string;
+ DESC: string;
+ REMARK: string | null;
+ NEW_TAG_YN: boolean;
+ ALL_TAG_YN: boolean;
+ VND_YN: boolean;
+ SEQ: number;
+ CMPLX_YN: boolean;
+ CMPL_SETT: any | null;
+ MAP_ATT: any[];
+ MAP_CLS_ID: string[];
+ MAP_OPER: any | null;
+ LNK_ATT: LinkAttribute[];
+ JOIN_TABLS: any[];
+ DELETED: boolean;
+ CRTER_NO: string;
+ CRTE_DTM: string;
+ CHGER_NO: string | null;
+ CHGE_DTM: string | null;
+ _id: string;
+}
+
+interface LinkAttribute {
+ ATT_ID: string;
+ CPY_DESC: string;
+ JOIN_KEY_ATT_ID: string | null;
+ JOIN_VAL_ATT_ID: string | null;
+ KEY_YN: boolean;
+ EDIT_YN: boolean;
+ PUB_YN: boolean;
+ VND_YN: boolean;
+ DEF_VAL: string | null;
+ UOM_ID: string | null;
+}
+
+interface Attribute {
+ PROJ_NO: string;
+ ATT_ID: string;
+ DESC: string;
+ GROUP: string | null;
+ REMARK: string | null;
+ VAL_TYPE: string;
+ IGN_LIST_VAL: boolean;
+ CL_ID: string | null;
+ UOM_ID: string | null;
+ DEF_VAL: string | null;
+ MIN_VAL: number;
+ MAX_VAL: number;
+ ESS_YN: boolean;
+ SEQ: number;
+ FORMAT: string | null;
+ REG_EXPS: string | null;
+ ATTRIBUTES: any[];
+ DELETED: boolean;
+ CRTER_NO: string;
+ CRTE_DTM: string;
+ CHGER_NO: string | null;
+ CHGE_DTM: string | null;
+ _id: string;
+}
+
+interface CodeList {
+ PROJ_NO: string;
+ CL_ID: string;
+ DESC: string;
+ REMARK: string | null;
+ PRNT_CD_ID: string | null;
+ REG_TYPE_ID: string | null;
+ VAL_ATT_ID: string | null;
+ VALUES: CodeValue[];
+ LNK_ATT: any[];
+ DELETED: boolean;
+ CRTER_NO: string;
+ CRTE_DTM: string;
+ CHGER_NO: string | null;
+ CHGE_DTM: string | null;
+ _id: string;
+}
+
+interface CodeValue {
+ PRNT_VALUE: string | null;
+ VALUE: string;
+ DESC: string;
+ REMARK: string;
+ USE_YN: boolean;
+ SEQ: number;
+ ATTRIBUTES: any[];
+}
+
+interface UOM {
+ PROJ_NO: string;
+ UOM_ID: string;
+ DESC: string;
+ SYMBOL: string;
+ CONV_RATE: number;
+ DELETED: boolean;
+ CRTER_NO: string;
+ CRTE_DTM: string;
+ CHGER_NO: string | null;
+ CHGE_DTM: string | null;
+ _id: string;
+}
+
+interface Project {
+ id: number;
+ code: string;
+ name: string;
+ type?: string;
+ createdAt?: Date;
+ updatedAt?: Date;
+}
+
+interface SyncResult {
+ project: string;
+ success: boolean;
+ count?: number;
+ error?: string;
+}
+
+interface FormColumn {
+ key: string;
+ label: string;
+ type: string;
+ options?: string[];
+ uom?: string;
+ uomId?: string;
+ shi?: Boolean;
+}
+
+// 아이템 코드 추출 함수
+function extractItemCodes(remark: string | null): string[] {
+ if (!remark) return [];
+
+ // 검색용으로만 소문자로 변환
+ const remarkLower = remark.toLowerCase();
+
+ // 'vd_' 접두사 확인
+ const hasVD_ = remarkLower.includes("vd_");
+
+ if (!hasVD_) return [];
+
+ let vdPart = "";
+
+ // 'vd_'가 있으면 원본 문자열에서 추출 (소문자 버전이 아님)
+ if (hasVD_) {
+ const vdIndex = remarkLower.indexOf("vd_");
+ vdPart = remark.substring(vdIndex + 3); // 원본 문자열에서 추출
+ }
+
+ if (!vdPart) return [];
+
+ // 쉼표로 구분된 여러 itemCode 처리
+ return vdPart.split(",").map(code => code.trim());
+}
+
+async function getDefaulTAttributes(): Promise<string[]> {
+ try {
+ const apiKey = await getSEDPToken();
+
+ const response = await fetch(
+ `${SEDP_API_BASE_URL}/Dictionary/GetByKey`,
+ {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'accept': '*/*',
+ 'ApiKey': apiKey,
+ },
+ body: JSON.stringify({
+ Key: "DefaultAttributesToCompare",
+ })
+ }
+ );
+
+ if (!response.ok) {
+ if (response.status === 404) {
+ console.warn(`디폴트 속성 찾을 수 없음`);
+ return [];
+ }
+ throw new Error(`코드 리스트 요청 실패: ${response.status} ${response.statusText}`);
+ }
+
+ // 안전하게 JSON 파싱
+ try {
+ const data = await response.json();
+ // 데이터가 배열인지 확인하고 문자열 배열로 변환
+ if (Array.isArray(data)) {
+ return data as string[];
+ } else {
+ console.warn('응답이 배열 형식이 아닙니다');
+ return [];
+ }
+ } catch (parseError) {
+ console.error(`디폴트 속성 응답 파싱 실패:`, parseError);
+ // 응답 내용 로깅
+ try {
+ const text = await response.clone().text();
+ console.log(`응답 내용: ${text.substring(0, 200)}${text.length > 200 ? '...' : ''}`);
+ } catch (textError) {
+ console.error('응답 내용 로깅 실패:', textError);
+ }
+ return [];
+ }
+ } catch (error) {
+ console.error(`디폴트 어트리뷰트 가져오기 실패:`, error);
+ throw error;
+ }
+}
+
+// 레지스터 데이터 가져오기
+async function getRegisters(projectCode: string): Promise<Register[]> {
+ try {
+ // 토큰(API 키) 가져오기
+ const apiKey = await getSEDPToken();
+
+ const response = await fetch(
+ `${SEDP_API_BASE_URL}/Register/Get`,
+ {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'accept': '*/*',
+ 'ApiKey': apiKey,
+ 'ProjectNo': projectCode
+ },
+ body: JSON.stringify({
+ ProjectNo: projectCode,
+ ContainDeleted: false
+ })
+ }
+ );
+
+ if (!response.ok) {
+ throw new Error(`레지스터 요청 실패: ${response.status} ${response.statusText}`);
+ }
+
+ // 안전하게 JSON 파싱
+ let data;
+ try {
+ data = await response.json();
+ } catch (parseError) {
+ console.error(`프로젝트 ${projectCode}의 레지스터 응답 파싱 실패:`, parseError);
+ // 응답 내용 로깅
+ const text = await response.clone().text();
+ console.log(`응답 내용: ${text.substring(0, 200)}${text.length > 200 ? '...' : ''}`);
+ throw new Error(`레지스터 응답 파싱 실패: ${parseError instanceof Error ? parseError.message : String(parseError)}`);
+ }
+
+ // 결과를 배열로 변환 (단일 객체인 경우 배열로 래핑)
+ let registers: Register[] = Array.isArray(data) ? data : [data];
+
+ // MAP_CLS_ID가 비어있지 않고 REMARK가 vd, VD, vD, Vd 중 하나인 레지스터만 필터링
+ registers = registers.filter(register => {
+ // 삭제된 레지스터 제외
+ if (register.DELETED) return false;
+
+ // MAP_CLS_ID 배열이 존재하고 요소가 하나 이상 있는지 확인
+ const hasValidMapClsId = Array.isArray(register.MAP_CLS_ID) && register.MAP_CLS_ID.length > 0;
+
+ // REMARK가 'vd_' 또는 'vd' 포함 확인 (대소문자 구분 없이)
+ const remarkLower = register.REMARK && register.REMARK.toLowerCase();
+ const hasValidRemark = remarkLower && (remarkLower.includes('vd'));
+
+ // 두 조건 모두 충족해야 함
+ return hasValidMapClsId && hasValidRemark;
+ });
+
+ console.log(`프로젝트 ${projectCode}에서 ${registers.length}개의 유효한 레지스터를 가져왔습니다.`);
+ return registers;
+ } catch (error) {
+ console.error(`프로젝트 ${projectCode}의 레지스터 가져오기 실패:`, error);
+ throw error;
+ }
+}
+
+// 프로젝트의 모든 속성을 가져와 맵으로 반환
+async function getAttributes(projectCode: string): Promise<Map<string, Attribute>> {
+ try {
+ // 토큰(API 키) 가져오기
+ const apiKey = await getSEDPToken();
+
+ const response = await fetch(
+ `${SEDP_API_BASE_URL}/Attributes/Get`,
+ {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'accept': '*/*',
+ 'ApiKey': apiKey,
+ 'ProjectNo': projectCode
+ },
+ body: JSON.stringify({
+ ProjectNo: projectCode,
+ ContainDeleted: false
+ })
+ }
+ );
+
+ if (!response.ok) {
+ throw new Error(`속성 요청 실패: ${response.status} ${response.statusText}`);
+ }
+
+ // 안전하게 JSON 파싱
+ try {
+ const data = await response.json();
+
+ // 데이터가 배열인지 확인
+ const attributes: Attribute[] = Array.isArray(data) ? data : [data];
+
+ // ATT_ID로 효율적인 조회를 위한 맵 생성
+ const attributeMap = new Map<string, Attribute>();
+ for (const attribute of attributes) {
+ if (!attribute.DELETED) {
+ attributeMap.set(attribute.ATT_ID, attribute);
+ }
+ }
+
+ console.log(`프로젝트 ${projectCode}에서 ${attributeMap.size}개의 속성을 가져왔습니다`);
+ return attributeMap;
+
+ } catch (parseError) {
+ console.error(`프로젝트 ${projectCode}의 속성 응답 파싱 실패:`, parseError);
+ // 응답 내용 로깅
+ try {
+ const text = await response.clone().text();
+ console.log(`응답 내용: ${text.substring(0, 200)}${text.length > 200 ? '...' : ''}`);
+ } catch (textError) {
+ console.error('응답 내용 로깅 실패:', textError);
+ }
+ return new Map();
+ }
+ } catch (error) {
+ console.error(`프로젝트 ${projectCode}의 속성 가져오기 실패:`, error);
+ return new Map();
+ }
+}
+
+// 특정 속성 가져오기 (하위 호환성을 위해 유지)
+async function getAttributeById(projectCode: string, attributeId: string, register: string): Promise<Attribute | null> {
+ try {
+ // 토큰(API 키) 가져오기
+ const apiKey = await getSEDPToken();
+
+ const response = await fetch(
+ `${SEDP_API_BASE_URL}/Attributes/GetByID`,
+ {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'accept': '*/*',
+ 'ApiKey': apiKey,
+ 'ProjectNo': projectCode
+ },
+ body: JSON.stringify({
+ ProjectNo: projectCode,
+ ATT_ID: attributeId,
+ ContainDeleted: false
+ })
+ }
+ );
+
+ if (!response.ok) {
+ if (response.status === 404) {
+ console.warn(`속성 ID ${attributeId}를 찾을 수 없음`);
+ return null;
+ }
+ throw new Error(`속성 요청 실패: ${response.status} ${response.statusText}`);
+ }
+
+ // 안전하게 JSON 파싱
+ try {
+ const data = await response.json();
+ return data;
+ } catch (parseError) {
+ console.error(`속성 ID ${attributeId} ${register} ${projectCode} 응답 파싱 실패:`, parseError);
+ // 응답 내용 로깅
+ try {
+ const text = await response.clone().text();
+ console.log(`응답 내용: ${text.substring(0, 200)}${text.length > 200 ? '...' : ''}`);
+ } catch (textError) {
+ console.error('응답 내용 로깅 실패:', textError);
+ }
+ return null;
+ }
+ } catch (error) {
+ console.error(`속성 ID ${attributeId} 가져오기 실패:`, error);
+ return null;
+ }
+}
+
+// 프로젝트의 모든 코드 리스트를 가져와 맵으로 반환
+async function getCodeLists(projectCode: string): Promise<Map<string, CodeList>> {
+ try {
+ // 토큰(API 키) 가져오기
+ const apiKey = await getSEDPToken();
+
+ const response = await fetch(
+ `${SEDP_API_BASE_URL}/CodeList/Get`,
+ {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'accept': '*/*',
+ 'ApiKey': apiKey,
+ 'ProjectNo': projectCode
+ },
+ body: JSON.stringify({
+ ProjectNo: projectCode,
+ ContainDeleted: false
+ })
+ }
+ );
+
+ if (!response.ok) {
+ throw new Error(`코드 리스트 요청 실패: ${response.status} ${response.statusText}`);
+ }
+
+ // 안전하게 JSON 파싱
+ try {
+ const data = await response.json();
+
+ // 데이터가 배열인지 확인
+ const codeLists: CodeList[] = Array.isArray(data) ? data : [data];
+
+ // CL_ID로 효율적인 조회를 위한 맵 생성
+ const codeListMap = new Map<string, CodeList>();
+ for (const codeList of codeLists) {
+ if (!codeList.DELETED) {
+ codeListMap.set(codeList.CL_ID, codeList);
+ }
+ }
+
+ console.log(`프로젝트 ${projectCode}에서 ${codeListMap.size}개의 코드 리스트를 가져왔습니다`);
+ return codeListMap;
+
+ } catch (parseError) {
+ console.error(`프로젝트 ${projectCode}의 코드 리스트 응답 파싱 실패:`, parseError);
+ // 응답 내용 로깅
+ try {
+ const text = await response.clone().text();
+ console.log(`응답 내용: ${text.substring(0, 200)}${text.length > 200 ? '...' : ''}`);
+ } catch (textError) {
+ console.error('응답 내용 로깅 실패:', textError);
+ }
+ return new Map();
+ }
+ } catch (error) {
+ console.error(`프로젝트 ${projectCode}의 코드 리스트 가져오기 실패:`, error);
+ return new Map();
+ }
+}
+
+// 특정 코드 리스트 가져오기 (하위 호환성을 위해 유지)
+async function getCodeListById(projectCode: string, codeListId: string): Promise<CodeList | null> {
+ try {
+ // 토큰(API 키) 가져오기
+ const apiKey = await getSEDPToken();
+
+ const response = await fetch(
+ `${SEDP_API_BASE_URL}/CodeList/GetByID`,
+ {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'accept': '*/*',
+ 'ApiKey': apiKey,
+ 'ProjectNo': projectCode
+ },
+ body: JSON.stringify({
+ ProjectNo: projectCode,
+ CL_ID: codeListId,
+ ContainDeleted: false
+ })
+ }
+ );
+
+ if (!response.ok) {
+ if (response.status === 404) {
+ console.warn(`코드 리스트 ID ${codeListId}를 찾을 수 없음`);
+ return null;
+ }
+ throw new Error(`코드 리스트 요청 실패: ${response.status} ${response.statusText}`);
+ }
+
+ // 안전하게 JSON 파싱
+ try {
+ const data = await response.json();
+ return data;
+ } catch (parseError) {
+ console.error(`코드 리스트 ID ${codeListId} 응답 파싱 실패:`, parseError);
+ // 응답 내용 로깅
+ try {
+ const text = await response.clone().text();
+ console.log(`응답 내용: ${text.substring(0, 200)}${text.length > 200 ? '...' : ''}`);
+ } catch (textError) {
+ console.error('응답 내용 로깅 실패:', textError);
+ }
+ return null;
+ }
+ } catch (error) {
+ console.error(`코드 리스트 ID ${codeListId} 가져오기 실패:`, error);
+ return null;
+ }
+}
+
+// 프로젝트의 모든 UOM을 가져와 맵으로 반환
+async function getUOMs(projectCode: string): Promise<Map<string, UOM>> {
+ try {
+ // 토큰(API 키) 가져오기
+ const apiKey = await getSEDPToken();
+
+ const response = await fetch(
+ `${SEDP_API_BASE_URL}/UOM/Get`,
+ {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'accept': '*/*',
+ 'ApiKey': apiKey,
+ 'ProjectNo': projectCode
+ },
+ body: JSON.stringify({
+ ProjectNo: projectCode,
+ ContainDeleted: false
+ })
+ }
+ );
+
+ if (!response.ok) {
+ throw new Error(`UOM 요청 실패: ${response.status} ${response.statusText}`);
+ }
+
+ // 안전하게 JSON 파싱
+ try {
+ const data = await response.json();
+
+ // 데이터가 배열인지 확인
+ const uoms: UOM[] = Array.isArray(data) ? data : [data];
+
+ // UOM_ID로 효율적인 조회를 위한 맵 생성
+ const uomMap = new Map<string, UOM>();
+ for (const uom of uoms) {
+ if (!uom.DELETED) {
+ uomMap.set(uom.UOM_ID, uom);
+ }
+ }
+
+ console.log(`프로젝트 ${projectCode}에서 ${uomMap.size}개의 UOM을 가져왔습니다`);
+ return uomMap;
+
+ } catch (parseError) {
+ console.error(`프로젝트 ${projectCode}의 UOM 응답 파싱 실패:`, parseError);
+ // 응답 내용 로깅
+ try {
+ const text = await response.clone().text();
+ console.log(`응답 내용: ${text.substring(0, 200)}${text.length > 200 ? '...' : ''}`);
+ } catch (textError) {
+ console.error('응답 내용 로깅 실패:', textError);
+ }
+ return new Map();
+ }
+ } catch (error) {
+ console.error(`프로젝트 ${projectCode}의 UOM 가져오기 실패:`, error);
+ return new Map();
+ }
+}
+
+// UOM 가져오기 (하위 호환성을 위해 유지)
+async function getUomById(projectCode: string, uomId: string): Promise<UOM | null> {
+ try {
+ // 토큰(API 키) 가져오기
+ const apiKey = await getSEDPToken();
+
+ const response = await fetch(
+ `${SEDP_API_BASE_URL}/UOM/GetByID`,
+ {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'accept': '*/*',
+ 'ApiKey': apiKey,
+ 'ProjectNo': projectCode
+ },
+ body: JSON.stringify({
+ UOMID: uomId, // API 명세서에 따라 UOMID 사용
+ ProjectNo: projectCode,
+ ContainDeleted: false
+ })
+ }
+ );
+
+ if (!response.ok) {
+ if (response.status === 404) {
+ console.warn(`UOM ID ${uomId}를 찾을 수 없음`);
+ return null;
+ }
+ throw new Error(`UOM 요청 실패: ${response.status} ${response.statusText}`);
+ }
+
+ // 안전하게 JSON 파싱
+ try {
+ const data = await response.json();
+ return data;
+ } catch (parseError) {
+ console.error(`UOM ID ${uomId} 응답 파싱 실패:`, parseError);
+ // 응답 내용 로깅
+ try {
+ const text = await response.clone().text();
+ console.log(`응답 내용: ${text.substring(0, 200)}${text.length > 200 ? '...' : ''}`);
+ } catch (textError) {
+ console.error('응답 내용 로깅 실패:', textError);
+ }
+ return null;
+ }
+ } catch (error) {
+ console.error(`UOM ID ${uomId} 가져오기 실패:`, error);
+ return null;
+ }
+}
+
+// contractItemId 조회 함수
+async function getContractItemsByItemCodes(itemCodes: string[], projectId: number): Promise<Map<string, number>> {
+ try {
+ if (!itemCodes.length) return new Map();
+
+ // 먼저 itemCodes에 해당하는 item 레코드를 조회
+ const itemRecords = await db.select({
+ id: items.id,
+ itemCode: items.itemCode
+ })
+ .from(items)
+ .where(inArray(items.itemCode, itemCodes));
+
+ if (!itemRecords.length) {
+ console.log(`No items found for itemCodes: ${itemCodes.join(', ')}`);
+ return new Map();
+ }
+
+ // item ID 목록 추출
+ const itemIds = itemRecords.map(item => item.id);
+
+ // contracts와 join하여 projectId로 필터링하면서 contractItems 조회
+ const contractItemRecords = await db.select({
+ id: contractItems.id,
+ itemId: contractItems.itemId
+ })
+ .from(contractItems)
+ .innerJoin(contracts, eq(contractItems.contractId, contracts.id))
+ .where(
+ and(
+ inArray(contractItems.itemId, itemIds),
+ eq(contracts.projectId, projectId)
+ )
+ );
+
+ // itemCode와 contractItemId의 매핑 생성
+ const itemCodeToContractItemId = new Map<string, number>();
+
+ for (const item of itemRecords) {
+ // itemCode가 null이 아닌 경우에만 처리
+ if (item.itemCode) {
+ const matchedContractItems = contractItemRecords.filter(ci => ci.itemId === item.id);
+ if (matchedContractItems.length > 0) {
+ // 일치하는 첫 번째 contractItem 사용
+ itemCodeToContractItemId.set(item.itemCode, matchedContractItems[0].id);
+ }
+ }
+ }
+
+ return itemCodeToContractItemId;
+ } catch (error) {
+ console.error('ContractItems 조회 중 오류 발생:', error);
+ return new Map();
+ }
+}
+
+// 데이터베이스에 태그 타입 클래스 폼 매핑 및 폼 메타 저장
+async function saveFormMappingsAndMetas(
+ projectId: number,
+ projectCode: string,
+ registers: Register[]
+): Promise<number> {
+ try {
+ // 프로젝트의 태그 타입과 클래스 가져오기
+ const tagTypeRecords = await db.select()
+ .from(tagTypes)
+ .where(eq(tagTypes.projectId, projectId));
+
+ const tagClassRecords = await db.select()
+ .from(tagClasses)
+ .where(eq(tagClasses.projectId, projectId));
+
+ // 태그 타입과 클래스 매핑
+ const tagTypeMap = new Map(tagTypeRecords.map(type => [type.code, type]));
+ const tagClassMap = new Map(tagClassRecords.map(cls => [cls.code, cls]));
+
+ // 모든 속성, 코드 리스트, UOM을 한 번에 가져와 반복 API 호출 방지
+ const attributeMap = await getAttributes(projectCode);
+ const codeListMap = await getCodeLists(projectCode);
+ const uomMap = await getUOMs(projectCode);
+
+ // 기본 속성 가져오기
+ const defaultAttributes = await getDefaulTAttributes();
+
+ // 모든 register에서 itemCode를 추출하여 한 번에 조회
+ const allItemCodes: string[] = [];
+ registers.forEach(register => {
+ if (register.REMARK) {
+ const itemCodes = extractItemCodes(register.REMARK);
+ allItemCodes.push(...itemCodes);
+ }
+ });
+
+ // 중복 제거
+ const uniqueItemCodes = [...new Set(allItemCodes)];
+
+ // 모든 itemCode에 대한 contractItemId 조회
+ const itemCodeToContractItemId = await getContractItemsByItemCodes(uniqueItemCodes , projectId);
+
+ console.log(`${uniqueItemCodes.length}개의 고유 itemCode 중 ${itemCodeToContractItemId.size}개의 contractItem을 찾았습니다`);
+
+ // 저장할 데이터 준비
+ const mappingsToSave: TagTypeClassFormMapping[] = [];
+ const formMetasToSave: FormMeta[] = [];
+ const formsToSave: FormRecord[] = [];
+
+ // 폼이 있는 contractItemId 트래킹
+ const contractItemIdsWithForms = new Set<number>();
+
+ // 각 register 처리
+ for (const register of registers) {
+ // 삭제된 register 건너뛰기
+ if (register.DELETED) continue;
+
+ // REMARK에서 itemCodes 추출
+
+
+ // 폼 메타용 columns 구성
+ const columns: FormColumn[] = [];
+
+ for (const linkAtt of register.LNK_ATT) {
+ let attribute = null;
+
+ // 기본 속성인지 확인
+ if (defaultAttributes && defaultAttributes.includes(linkAtt.ATT_ID)) {
+ // 기본 속성에 대한 기본 attribute 객체 생성
+ attribute = {
+ DESC: linkAtt.ATT_ID,
+ VAL_TYPE: 'STRING'
+ };
+ } else {
+ // 맵에서 속성 조회
+ attribute = attributeMap.get(linkAtt.ATT_ID);
+
+ // 속성을 찾지 못한 경우 다음으로 넘어감
+ if (!attribute) continue;
+ }
+
+ // 컬럼 정보 생성
+ const column: FormColumn = {
+ key: linkAtt.ATT_ID,
+ label: attribute.DESC,
+ type: (attribute.VAL_TYPE === 'LIST' || attribute.VAL_TYPE === 'DYNAMICLIST')
+ ? 'LIST'
+ : (attribute.VAL_TYPE || 'STRING'),
+ shi: attribute.REMARK?.toLocaleLowerCase() === "shi"
+ };
+
+ // 리스트 타입에 대한 옵션 추가 (기본 속성이 아닌 경우)
+ if (!defaultAttributes.includes(linkAtt.ATT_ID) &&
+ (attribute.VAL_TYPE === 'LIST' || attribute.VAL_TYPE === 'DYNAMICLIST') &&
+ attribute.CL_ID) {
+
+ // 맵에서 코드 리스트 조회
+ const codeList = codeListMap.get(attribute.CL_ID);
+
+ if (codeList && codeList.VALUES) {
+ const options = [...new Set(
+ codeList.VALUES
+ .filter(value => value.USE_YN)
+ .map(value => value.VALUE)
+ )];
+
+ if (options.length > 0) {
+ column.options = options;
+ }
+ }
+ }
+
+ // UOM 정보 추가
+ if (linkAtt.UOM_ID) {
+ const uom = uomMap.get(linkAtt.UOM_ID);
+
+ if (uom) {
+ column.uom = uom.SYMBOL;
+ column.uomId = uom.UOM_ID;
+ }
+ }
+
+ columns.push(column);
+ }
+
+ // 컬럼이 없으면 건너뛰기
+ if (columns.length === 0) {
+ console.log(`폼 ${register.TYPE_ID} (${register.DESC})에 컬럼이 없어 건너뜁니다`);
+ continue;
+ }
+
+ // 폼 메타 데이터 준비
+ formMetasToSave.push({
+ projectId,
+ formCode: register.TYPE_ID,
+ formName: register.DESC,
+ columns: JSON.stringify(columns),
+ createdAt: new Date(),
+ updatedAt: new Date()
+ });
+
+ // 클래스 매핑 처리
+ for (const classId of register.MAP_CLS_ID) {
+ const tagClass = tagClassMap.get(classId);
+
+ if (!tagClass) {
+ console.warn(`프로젝트 ID ${projectId}에서 클래스 ID ${classId}를 찾을 수 없습니다`);
+ continue;
+ }
+
+ const tagTypeCode = tagClass.tagTypeCode;
+ const tagType = tagTypeMap.get(tagTypeCode);
+
+ if (!tagType) {
+ console.warn(`프로젝트 ID ${projectId}에서 태그 타입 ${tagTypeCode}를 찾을 수 없습니다`);
+ continue;
+ }
+
+ // 매핑 정보 저장
+ mappingsToSave.push({
+ projectId,
+ tagTypeLabel: tagType.description,
+ classLabel: tagClass.label,
+ formCode: register.TYPE_ID,
+ formName: register.DESC,
+ remark: register.REMARK,
+ ep: register.EP_ID,
+ createdAt: new Date(),
+ updatedAt: new Date()
+ });
+ }
+
+ const itemCodes = extractItemCodes(register.REMARK || '');
+ if (!itemCodes.length) {
+ console.log(`Register ${register.TYPE_ID} (${register.DESC})의 REMARK에 유효한 itemCode가 없습니다`);
+ continue;
+ }
+ // 폼 레코드 준비
+ for (const itemCode of itemCodes) {
+ const contractItemId = itemCodeToContractItemId.get(itemCode);
+
+ if (!contractItemId) {
+ console.warn(`itemCode: ${itemCode}에 대한 contractItemId를 찾을 수 없습니다`);
+ continue;
+ }
+
+ // 폼이 있는 contractItemId 추적
+ contractItemIdsWithForms.add(contractItemId);
+
+ formsToSave.push({
+ contractItemId,
+ formCode: register.TYPE_ID,
+ formName: register.DESC,
+ eng: true,
+ createdAt: new Date(),
+ updatedAt: new Date()
+ });
+ }
+ }
+
+ // 트랜잭션으로 모든 작업 처리
+ let totalSaved = 0;
+
+ await db.transaction(async (tx) => {
+ // 기존 데이터 삭제
+ await tx.delete(tagTypeClassFormMappings).where(eq(tagTypeClassFormMappings.projectId, projectId));
+ await tx.delete(formMetas).where(eq(formMetas.projectId, projectId));
+
+ // 해당 contractItemId에 대한 기존 폼 삭제
+ if (contractItemIdsWithForms.size > 0) {
+ await tx.delete(forms).where(inArray(forms.contractItemId, [...contractItemIdsWithForms]));
+ }
+
+ // 매핑 저장
+ if (mappingsToSave.length > 0) {
+ await tx.insert(tagTypeClassFormMappings).values(mappingsToSave);
+ totalSaved += mappingsToSave.length;
+ console.log(`프로젝트 ID ${projectId}에 대해 ${mappingsToSave.length}개의 태그 타입-클래스-폼 매핑을 저장했습니다`);
+ }
+
+ // 폼 메타 저장
+ if (formMetasToSave.length > 0) {
+ await tx.insert(formMetas).values(formMetasToSave);
+ totalSaved += formMetasToSave.length;
+ console.log(`프로젝트 ID ${projectId}에 대해 ${formMetasToSave.length}개의 폼 메타 레코드를 저장했습니다`);
+ }
+
+ // 폼 레코드 저장
+ if (formsToSave.length > 0) {
+ await tx.insert(forms).values(formsToSave);
+ totalSaved += formsToSave.length;
+ console.log(`프로젝트 ID ${projectId}에 대해 ${formsToSave.length}개의 폼 레코드를 저장했습니다`);
+ }
+ });
+
+ return totalSaved;
+ } catch (error) {
+ console.error(`폼 매핑 및 메타 저장 실패 (프로젝트 ID: ${projectId}):`, error);
+ throw error;
+ }
+}
+
+// 메인 동기화 함수
+export async function syncTagFormMappings() {
+ try {
+ console.log('태그 폼 매핑 동기화 시작:', new Date().toISOString());
+
+ // 모든 프로젝트 가져오기
+ const allProjects = await db.select().from(projects);
+
+ // 각 프로젝트에 대해 폼 매핑 동기화
+ const results = await Promise.allSettled(
+ allProjects.map(async (project: Project) => {
+ try {
+ // 레지스터 데이터 가져오기
+ const registers = await getRegisters(project.code);
+
+ // 데이터베이스에 저장
+ const count = await saveFormMappingsAndMetas(project.id, project.code, registers);
+ return {
+ project: project.code,
+ success: true,
+ count
+ } as SyncResult;
+ } catch (error) {
+ console.error(`프로젝트 ${project.code} 폼 매핑 동기화 실패:`, error);
+ return {
+ project: project.code,
+ success: false,
+ error: error instanceof Error ? error.message : String(error)
+ } as SyncResult;
+ }
+ })
+ );
+
+ // 결과 처리를 위한 배열 준비
+ const successfulResults: SyncResult[] = [];
+ const failedResults: SyncResult[] = [];
+
+ // 결과 분류
+ results.forEach((result) => {
+ if (result.status === 'fulfilled') {
+ if (result.value.success) {
+ successfulResults.push(result.value);
+ } else {
+ failedResults.push(result.value);
+ }
+ } else {
+ // 거부된 프로미스는 실패로 간주
+ failedResults.push({
+ project: 'unknown',
+ success: false,
+ error: result.reason?.toString() || 'Unknown error'
+ });
+ }
+ });
+
+ const successCount = successfulResults.length;
+ const failCount = failedResults.length;
+
+ // 이제 안전하게 count 속성에 접근 가능
+ const totalItems = successfulResults.reduce((sum, result) =>
+ sum + (result.count || 0), 0
+ );
+
+ console.log(`태그 폼 매핑 동기화 완료: ${successCount}개 프로젝트 성공 (총 ${totalItems}개 항목), ${failCount}개 프로젝트 실패`);
+
+ return {
+ success: successCount,
+ failed: failCount,
+ items: totalItems,
+ timestamp: new Date().toISOString()
+ };
+ } catch (error) {
+ console.error('태그 폼 매핑 동기화 중 오류 발생:', error);
+ throw error;
+ }
+} \ No newline at end of file
diff --git a/lib/sedp/sync-form.ts b/lib/sedp/sync-form.ts
index 2cb677b7..c293c98e 100644
--- a/lib/sedp/sync-form.ts
+++ b/lib/sedp/sync-form.ts
@@ -1,6 +1,6 @@
// src/lib/cron/syncTagFormMappings.ts
import db from "@/db/db";
-import { projects, tagTypes, tagClasses, tagTypeClassFormMappings, formMetas, forms, contractItems, items, contracts } from '@/db/schema';
+import { projects, tagTypes, tagClasses, tagTypeClassFormMappings, formMetas, forms, contractItems, items, contracts, templateItems } from '@/db/schema';
import { eq, and, inArray, ilike } from 'drizzle-orm';
import { getSEDPToken } from "./sedp-token";
@@ -37,6 +37,51 @@ interface FormRecord {
createdAt: Date;
updatedAt: Date;
}
+
+interface TemplateItem {
+ TMPL_ID: string;
+ NAME: string;
+ TMPL_TYPE: string;
+ SPR_LST_SETUP: {
+ ACT_SHEET: string;
+ HIDN_SHEETS: Array<string>;
+ CONTENT?: string;
+ DATA_SHEETS: Array<{
+ SHEET_NAME: string;
+ REG_TYPE_ID: string;
+ MAP_CELL_ATT: Array<{
+ ATT_ID: string;
+ IN: string;
+ }>;
+ }>;
+ };
+ GRD_LST_SETUP: {
+ REG_TYPE_ID: string;
+ SPR_ITM_IDS: Array<string>;
+ ATTS: Array<{
+ ATT_ID: string;
+ ALIAS: string;
+ HEAD_TEXT: string;
+ HIDN_YN: boolean;
+ SEQ:number;
+ DFLT_YN:boolean;
+ }>;
+ };
+ SPR_ITM_LST_SETUP: {
+ ACT_SHEET: string;
+ HIDN_SHEETS: Array<string>;
+ CONTENT?: string;
+ DATA_SHEETS: Array<{
+ SHEET_NAME: string;
+ REG_TYPE_ID: string;
+ MAP_CELL_ATT: Array<{
+ ATT_ID: string;
+ IN: string;
+ }>;
+ }>;
+ };
+}
+
interface Register {
PROJ_NO: string;
TYPE_ID: string;
@@ -75,6 +120,42 @@ interface LinkAttribute {
UOM_ID: string | null;
}
+interface newRegister {
+ PROJ_NO: string;
+ MAP_ID: string;
+ EP_ID: string;
+ CATEGORY: string;
+ BYPASS: boolean;
+ REG_TYPE_ID: string;
+ TOOL_ID: string;
+ TOOL_TYPE: string;
+ MAP_CLS: {
+ TOOL_ATT_NAME: string;
+ ITEMS: ClassItmes[];
+ };
+ MAP_ATT: MapAttribute[];
+ MAP_TMPLS: string[];
+ CRTER_NO: string;
+ CRTE_DTM: string;
+ CHGER_NO: string;
+ _id: string;
+}
+
+
+
+interface ClassItmes {
+ SEDP_OBJ_CLS_ID: string;
+ TOOL_VALS: string;
+ ISDEFALUT: boolean;
+}
+
+interface MapAttribute {
+ SEDP_ATT_ID: string;
+ TOOL_ATT_NAME: string;
+ KEY_YN: boolean;
+ INOUT: string | null;
+}
+
interface Attribute {
PROJ_NO: string;
ATT_ID: string;
@@ -167,6 +248,9 @@ interface FormColumn {
uom?: string;
uomId?: string;
shi?: Boolean;
+ hidden?: boolean;
+ seq?: number;
+ head?: string;
}
// 아이템 코드 추출 함수
@@ -249,6 +333,63 @@ async function getDefaulTAttributes(): Promise<string[]> {
}
}
+async function fetchTemplateFromSEDP(projectCode: string, formCode: string): Promise<TemplateItem[]> {
+ try {
+ // Get the token
+ const apiKey = await getSEDPToken();
+
+ // Make the API call
+ const response = await fetch(
+ `${SEDP_API_BASE_URL}/Template/GetByRegisterID`,
+ {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'accept': '*/*',
+ 'ApiKey': apiKey,
+ 'ProjectNo': projectCode
+ },
+ body: JSON.stringify({
+ WithContent: true,
+ ProjectNo: projectCode,
+ REG_TYPE_ID: formCode
+ })
+ }
+ );
+
+ if (!response.ok) {
+ if (response.status === 404) {
+ console.warn(`템플릿을 찾을 수 없음: ${formCode}`);
+ return [];
+ }
+ const errorText = await response.text();
+ throw new Error(`SEDP Template API request failed: ${response.status} ${response.statusText} - ${errorText}`);
+ }
+
+ // 안전하게 JSON 파싱
+ try {
+ const data = await response.json();
+ // 데이터가 배열인지 확인
+ const templates: TemplateItem[] = Array.isArray(data) ? data : [data];
+ return templates.filter(template => template && template.TMPL_ID);
+ } catch (parseError) {
+ console.error(`템플릿 응답 파싱 실패:`, parseError);
+ // 응답 내용 로깅
+ try {
+ const text = await response.clone().text();
+ console.log(`응답 내용: ${text.substring(0, 200)}${text.length > 200 ? '...' : ''}`);
+ } catch (textError) {
+ console.error('응답 내용 로깅 실패:', textError);
+ }
+ return [];
+ }
+ } catch (error: any) {
+ console.error('Error calling SEDP Template API:', error);
+ console.warn(`템플릿 가져오기 실패 (${formCode}): ${error.message || 'Unknown error'}`);
+ return [];
+ }
+}
+
// 레지스터 데이터 가져오기
async function getRegisters(projectCode: string): Promise<Register[]> {
try {
@@ -315,6 +456,55 @@ async function getRegisters(projectCode: string): Promise<Register[]> {
}
}
+async function getNewRegisters(projectCode: string): Promise<newRegister[]> {
+ try {
+ // 토큰(API 키) 가져오기
+ const apiKey = await getSEDPToken();
+
+ const response = await fetch(
+ `${SEDP_API_BASE_URL}/AdapterDataMapping/GetByToolID`,
+ {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'accept': '*/*',
+ 'ApiKey': apiKey,
+ 'ProjectNo': projectCode
+ },
+ body: JSON.stringify({
+ ProjectNo: projectCode,
+ "TOOL_ID": "eVCP"
+ })
+ }
+ );
+
+ if (!response.ok) {
+ throw new Error(`새 레지스터 요청 실패: ${response.status} ${response.statusText}`);
+ }
+
+ // 안전하게 JSON 파싱
+ let data;
+ try {
+ data = await response.json();
+ } catch (parseError) {
+ console.error(`프로젝트 ${projectCode}의 새 레지스터 응답 파싱 실패:`, parseError);
+ // 응답 내용 로깅
+ const text = await response.clone().text();
+ console.log(`응답 내용: ${text.substring(0, 200)}${text.length > 200 ? '...' : ''}`);
+ throw new Error(`새 레지스터 응답 파싱 실패: ${parseError instanceof Error ? parseError.message : String(parseError)}`);
+ }
+
+ // 결과를 배열로 변환 (단일 객체인 경우 배열로 래핑)
+ let registers: newRegister[] = Array.isArray(data) ? data : [data];
+
+ console.log(`프로젝트 ${projectCode}에서 ${registers.length}개의 새 레지스터를 가져왔습니다.`);
+ return registers;
+ } catch (error) {
+ console.error(`프로젝트 ${projectCode}의 새 레지스터 가져오기 실패:`, error);
+ throw error;
+ }
+}
+
// 프로젝트의 모든 속성을 가져와 맵으로 반환
async function getAttributes(projectCode: string): Promise<Map<string, Attribute>> {
try {
@@ -716,249 +906,167 @@ async function getContractItemsByItemCodes(itemCodes: string[], projectId: numbe
}
}
-// 데이터베이스에 태그 타입 클래스 폼 매핑 및 폼 메타 저장
-async function saveFormMappingsAndMetas(
+// UPDATED: saveFormMappingsAndMetas()
+// ------------------------------------
+// Primary loop is **newRegisters**‑first; legacy **registers** are consulted
+// only for supplemental details.
+//
+// 2025‑07‑09 fix: newRegister.MAP_CLS is a **single object**, not an array.
+// Updated class‑ID extraction accordingly.
+//
+export async function saveFormMappingsAndMetas(
projectId: number,
projectCode: string,
- registers: Register[]
+ registers: Register[], // legacy SEDP Register list (supplemental)
+ newRegisters: newRegister[] // AdapterDataMapping list (primary)
): Promise<number> {
try {
- // 프로젝트의 태그 타입과 클래스 가져오기
- const tagTypeRecords = await db.select()
- .from(tagTypes)
- .where(eq(tagTypes.projectId, projectId));
+ /* ------------------------------------------------------------------ */
+ /* 1. Prepare look‑up structures & common data */
+ /* ------------------------------------------------------------------ */
- const tagClassRecords = await db.select()
- .from(tagClasses)
- .where(eq(tagClasses.projectId, projectId));
+ const tagTypeRecords = await db.select().from(tagTypes).where(eq(tagTypes.projectId, projectId));
+ const tagClassRecords = await db.select().from(tagClasses).where(eq(tagClasses.projectId, projectId));
+ const tagTypeMap = new Map(tagTypeRecords.map(t => [t.code, t]));
+ const tagClassMap = new Map(tagClassRecords.map(c => [c.code, c]));
- // 태그 타입과 클래스 매핑
- const tagTypeMap = new Map(tagTypeRecords.map(type => [type.code, type]));
- const tagClassMap = new Map(tagClassRecords.map(cls => [cls.code, cls]));
+ const registerMap = new Map(registers.map(r => [r.TYPE_ID, r]));
- // 모든 속성, 코드 리스트, UOM을 한 번에 가져와 반복 API 호출 방지
const attributeMap = await getAttributes(projectCode);
- const codeListMap = await getCodeLists(projectCode);
- const uomMap = await getUOMs(projectCode);
-
- // 기본 속성 가져오기
+ const codeListMap = await getCodeLists(projectCode);
+ const uomMap = await getUOMs(projectCode);
const defaultAttributes = await getDefaulTAttributes();
- // 모든 register에서 itemCode를 추출하여 한 번에 조회
- const allItemCodes: string[] = [];
- registers.forEach(register => {
- if (register.REMARK) {
- const itemCodes = extractItemCodes(register.REMARK);
- allItemCodes.push(...itemCodes);
- }
- });
-
- // 중복 제거
- const uniqueItemCodes = [...new Set(allItemCodes)];
-
- // 모든 itemCode에 대한 contractItemId 조회
- const itemCodeToContractItemId = await getContractItemsByItemCodes(uniqueItemCodes , projectId);
-
- console.log(`${uniqueItemCodes.length}개의 고유 itemCode 중 ${itemCodeToContractItemId.size}개의 contractItem을 찾았습니다`);
+ /* ------------------------------------------------------------------ */
+ /* 2. Contract‑item look‑up (TOOL_TYPE) */
+ /* ------------------------------------------------------------------ */
+ const uniqueItemCodes = [...new Set(newRegisters.filter(nr => nr.TOOL_TYPE).map(nr => nr.TOOL_TYPE as string))];
+ const itemCodeToContractItemId = await getContractItemsByItemCodes(uniqueItemCodes, projectId);
- // 저장할 데이터 준비
+ /* ------------------------------------------------------------------ */
+ /* 3. Buffers for bulk insert */
+ /* ------------------------------------------------------------------ */
const mappingsToSave: TagTypeClassFormMapping[] = [];
const formMetasToSave: FormMeta[] = [];
const formsToSave: FormRecord[] = [];
-
- // 폼이 있는 contractItemId 트래킹
const contractItemIdsWithForms = new Set<number>();
+ const templateDataByFormCode: Map<string, TemplateItem[]> = new Map();
- // 각 register 처리
- for (const register of registers) {
- // 삭제된 register 건너뛰기
- if (register.DELETED) continue;
+ /* ------------------------------------------------------------------ */
+ /* 4. Iterate over newRegisters */
+ /* ------------------------------------------------------------------ */
+ for (const newReg of newRegisters) {
+ const formCode = newReg.REG_TYPE_ID;
+ const legacy = registerMap.get(formCode);
- // REMARK에서 itemCodes 추출
+ /* ---------- 4‑a. templates ------------------------------------ */
+ let templates: TemplateItem[] = [];
+ try {
+ const fetched = await fetchTemplateFromSEDP(projectCode, formCode);
+ templates = fetched.filter(t => (newReg.MAP_TMPLS?.length ? newReg.MAP_TMPLS.includes(t.TMPL_ID) : true));
+ if (templates.length) templateDataByFormCode.set(formCode, templates);
+ } catch (e) {
+ console.warn(`템플릿 가져오기 실패 (${formCode})`, e);
+ }
+ const templateAttrMap = new Map<string, { hidden: boolean; seq: number; head: string }>();
+ templates.forEach(t => t.GRD_LST_SETUP?.ATTS?.forEach(att => {
+ if (!templateAttrMap.has(att.ATT_ID)) templateAttrMap.set(att.ATT_ID, { hidden: att.HIDN_YN, seq: att.SEQ, head: att.HEAD_TEXT });
+ }));
- // 폼 메타용 columns 구성
+ /* ---------- 4‑b. columns -------------------------------------- */
const columns: FormColumn[] = [];
-
- for (const linkAtt of register.LNK_ATT) {
- let attribute = null;
-
- // 기본 속성인지 확인
- if (defaultAttributes && defaultAttributes.includes(linkAtt.ATT_ID)) {
- // 기본 속성에 대한 기본 attribute 객체 생성
- attribute = {
- DESC: linkAtt.ATT_ID,
- VAL_TYPE: 'STRING'
- };
- } else {
- // 맵에서 속성 조회
- attribute = attributeMap.get(linkAtt.ATT_ID);
-
- // 속성을 찾지 못한 경우 다음으로 넘어감
- if (!attribute) continue;
+ for (const mapAtt of newReg.MAP_ATT) {
+ const attId = mapAtt.SEDP_ATT_ID;
+ const attribute = defaultAttributes.includes(attId) ? { DESC: attId, VAL_TYPE: "STRING" } as Partial<Attribute> : attributeMap.get(attId);
+ if (!attribute) continue;
+
+ const tmplMeta = templateAttrMap.get(attId);
+ const isShi = mapAtt.INOUT === "OUT";
+
+ let uomSymbol: string | undefined; let uomId: string | undefined;
+ if (legacy?.LNK_ATT) {
+ const l = legacy.LNK_ATT.find(a => a.ATT_ID === attId);
+ if (l?.UOM_ID) { const u = uomMap.get(l.UOM_ID); if (u) { uomSymbol = u.SYMBOL; uomId = u.UOM_ID; } }
}
- // 컬럼 정보 생성
- const column: FormColumn = {
- key: linkAtt.ATT_ID,
- label: attribute.DESC,
- type: (attribute.VAL_TYPE === 'LIST' || attribute.VAL_TYPE === 'DYNAMICLIST')
- ? 'LIST'
- : (attribute.VAL_TYPE || 'STRING'),
- shi: attribute.REMARK?.toLocaleLowerCase() === "shi"
+ const col: FormColumn = {
+ key: attId,
+ label: attribute.DESC as string,
+ type: (attribute.VAL_TYPE === "LIST" || attribute.VAL_TYPE === "DYNAMICLIST") ? "LIST" : (attribute.VAL_TYPE || "STRING"),
+ shi: isShi,
+ hidden: tmplMeta?.hidden ?? false,
+ seq: tmplMeta?.seq ?? 0,
+ head: tmplMeta?.head ?? "",
+ ...(uomSymbol ? { uom: uomSymbol, uomId } : {})
};
- // 리스트 타입에 대한 옵션 추가 (기본 속성이 아닌 경우)
- if (!defaultAttributes.includes(linkAtt.ATT_ID) &&
- (attribute.VAL_TYPE === 'LIST' || attribute.VAL_TYPE === 'DYNAMICLIST') &&
- attribute.CL_ID) {
-
- // 맵에서 코드 리스트 조회
- const codeList = codeListMap.get(attribute.CL_ID);
-
- if (codeList && codeList.VALUES) {
- const options = [...new Set(
- codeList.VALUES
- .filter(value => value.USE_YN)
- .map(value => value.VALUE)
- )];
-
- if (options.length > 0) {
- column.options = options;
- }
- }
+ if (!defaultAttributes.includes(attId) && (attribute.VAL_TYPE === "LIST" || attribute.VAL_TYPE === "DYNAMICLIST") && attribute.CL_ID) {
+ const cl = codeListMap.get(attribute.CL_ID);
+ if (cl?.VALUES?.length) col.options = [...new Set(cl.VALUES.filter(v => v.USE_YN).map(v => v.VALUE))];
}
- // UOM 정보 추가
- if (linkAtt.UOM_ID) {
- const uom = uomMap.get(linkAtt.UOM_ID);
-
- if (uom) {
- column.uom = uom.SYMBOL;
- column.uomId = uom.UOM_ID;
- }
- }
-
- columns.push(column);
- }
-
- // 컬럼이 없으면 건너뛰기
- if (columns.length === 0) {
- console.log(`폼 ${register.TYPE_ID} (${register.DESC})에 컬럼이 없어 건너뜁니다`);
- continue;
+ columns.push(col);
}
+ if (!columns.length) { console.log(`폼 ${formCode} 건너뜀 (컬럼 없음)`); continue; }
+ columns.sort((a, b) => (a.seq ?? 999999) - (b.seq ?? 999999));
- // 폼 메타 데이터 준비
- formMetasToSave.push({
- projectId,
- formCode: register.TYPE_ID,
- formName: register.DESC,
- columns: JSON.stringify(columns),
- createdAt: new Date(),
- updatedAt: new Date()
- });
-
- // 클래스 매핑 처리
- for (const classId of register.MAP_CLS_ID) {
- const tagClass = tagClassMap.get(classId);
-
- if (!tagClass) {
- console.warn(`프로젝트 ID ${projectId}에서 클래스 ID ${classId}를 찾을 수 없습니다`);
- continue;
- }
-
- const tagTypeCode = tagClass.tagTypeCode;
- const tagType = tagTypeMap.get(tagTypeCode);
-
- if (!tagType) {
- console.warn(`프로젝트 ID ${projectId}에서 태그 타입 ${tagTypeCode}를 찾을 수 없습니다`);
- continue;
- }
+ formMetasToSave.push({ projectId, formCode, formName: legacy?.DESC || formCode, columns: JSON.stringify(columns), createdAt: new Date(), updatedAt: new Date() });
- // 매핑 정보 저장
- mappingsToSave.push({
- projectId,
- tagTypeLabel: tagType.description,
- classLabel: tagClass.label,
- formCode: register.TYPE_ID,
- formName: register.DESC,
- remark: register.REMARK,
- ep: register.EP_ID,
- createdAt: new Date(),
- updatedAt: new Date()
- });
+ /* ---------- 4‑c. class mappings -------------------------------- */
+ const classIds = new Set<string>();
+ if (newReg.MAP_CLS?.ITEMS?.length) {
+ newReg.MAP_CLS.ITEMS.forEach(it => classIds.add(it.SEDP_OBJ_CLS_ID));
}
- const itemCodes = extractItemCodes(register.REMARK || '');
- if (!itemCodes.length) {
- console.log(`Register ${register.TYPE_ID} (${register.DESC})의 REMARK에 유효한 itemCode가 없습니다`);
- continue;
- }
- // 폼 레코드 준비
- for (const itemCode of itemCodes) {
- const contractItemId = itemCodeToContractItemId.get(itemCode);
-
- if (!contractItemId) {
- console.warn(`itemCode: ${itemCode}에 대한 contractItemId를 찾을 수 없습니다`);
- continue;
- }
-
- // 폼이 있는 contractItemId 추적
- contractItemIdsWithForms.add(contractItemId);
+ classIds.forEach(classId => {
+ const cls = tagClassMap.get(classId);
+ if (!cls) { console.warn(`클래스 ${classId} 없음`); return; }
+ const tp = tagTypeMap.get(cls.tagTypeCode);
+ if (!tp) { console.warn(`태그 타입 ${cls.tagTypeCode} 없음`); return; }
+ mappingsToSave.push({ projectId, tagTypeLabel: tp.description, classLabel: cls.label, formCode, formName: legacy?.DESC || formCode, remark: newReg.TOOL_TYPE || null, ep: newReg.EP_ID || legacy?.EP_ID || "", createdAt: new Date(), updatedAt: new Date() });
+ });
- formsToSave.push({
- contractItemId,
- formCode: register.TYPE_ID,
- formName: register.DESC,
- eng: true,
- createdAt: new Date(),
- updatedAt: new Date()
- });
+ /* ---------- 4‑d. contractItem ↔ form --------------------------- */
+ if (newReg.TOOL_TYPE) {
+ const cId = itemCodeToContractItemId.get(newReg.TOOL_TYPE);
+ if (cId) { contractItemIdsWithForms.add(cId); formsToSave.push({ contractItemId: cId, formCode, formName: legacy?.DESC || formCode, eng: true, createdAt: new Date(), updatedAt: new Date() }); }
+ else console.warn(`itemCode ${newReg.TOOL_TYPE} 의 contractItemId 없음`);
}
}
- // 트랜잭션으로 모든 작업 처리
+ /* ------------------------------------------------------------------ */
+ /* 5. DB transaction */
+ /* ------------------------------------------------------------------ */
let totalSaved = 0;
-
- await db.transaction(async (tx) => {
- // 기존 데이터 삭제
+ await db.transaction(async tx => {
+ const old = await tx.select({ id: tagTypeClassFormMappings.id }).from(tagTypeClassFormMappings).where(eq(tagTypeClassFormMappings.projectId, projectId));
+ if (old.length) await tx.delete(templateItems).where(inArray(templateItems.formMappingId, old.map(o => o.id)));
await tx.delete(tagTypeClassFormMappings).where(eq(tagTypeClassFormMappings.projectId, projectId));
await tx.delete(formMetas).where(eq(formMetas.projectId, projectId));
+ if (contractItemIdsWithForms.size) await tx.delete(forms).where(inArray(forms.contractItemId, [...contractItemIdsWithForms]));
- // 해당 contractItemId에 대한 기존 폼 삭제
- if (contractItemIdsWithForms.size > 0) {
- await tx.delete(forms).where(inArray(forms.contractItemId, [...contractItemIdsWithForms]));
- }
-
- // 매핑 저장
- if (mappingsToSave.length > 0) {
- await tx.insert(tagTypeClassFormMappings).values(mappingsToSave);
- totalSaved += mappingsToSave.length;
- console.log(`프로젝트 ID ${projectId}에 대해 ${mappingsToSave.length}개의 태그 타입-클래스-폼 매핑을 저장했습니다`);
- }
+ const savedMappings = mappingsToSave.length ? await tx.insert(tagTypeClassFormMappings).values(mappingsToSave).returning({ id: tagTypeClassFormMappings.id, formCode: tagTypeClassFormMappings.formCode }) : [];
+ totalSaved += mappingsToSave.length;
- // 폼 메타 저장
- if (formMetasToSave.length > 0) {
- await tx.insert(formMetas).values(formMetasToSave);
- totalSaved += formMetasToSave.length;
- console.log(`프로젝트 ID ${projectId}에 대해 ${formMetasToSave.length}개의 폼 메타 레코드를 저장했습니다`);
+ if (savedMappings.length) {
+ const rows: any[] = [];
+ savedMappings.forEach(m => (templateDataByFormCode.get(m.formCode) || []).forEach(t => rows.push({ formMappingId: m.id, tmplId: t.TMPL_ID, name: t.NAME, tmplType: t.TMPL_TYPE, sprLstSetup: t.SPR_LST_SETUP, grdLstSetup: t.GRD_LST_SETUP, sprItmLstSetup: t.SPR_ITM_LST_SETUP, description: `Template for form ${m.formCode}`, isActive: true, createdAt: new Date(), updatedAt: new Date() })));
+ if (rows.length) { await tx.insert(templateItems).values(rows); totalSaved += rows.length; }
}
- // 폼 레코드 저장
- if (formsToSave.length > 0) {
- await tx.insert(forms).values(formsToSave);
- totalSaved += formsToSave.length;
- console.log(`프로젝트 ID ${projectId}에 대해 ${formsToSave.length}개의 폼 레코드를 저장했습니다`);
- }
+ if (formMetasToSave.length) { await tx.insert(formMetas).values(formMetasToSave); totalSaved += formMetasToSave.length; }
+ if (formsToSave.length) { await tx.insert(forms).values(formsToSave); totalSaved += formsToSave.length; }
});
return totalSaved;
- } catch (error) {
- console.error(`폼 매핑 및 메타 저장 실패 (프로젝트 ID: ${projectId}):`, error);
- throw error;
+ } catch (err) {
+ console.error(`폼 매핑 및 메타 저장 실패 (프로젝트 ID:${projectId})`, err);
+ throw err;
}
}
+
// 메인 동기화 함수
export async function syncTagFormMappings() {
try {
@@ -973,9 +1081,10 @@ export async function syncTagFormMappings() {
try {
// 레지스터 데이터 가져오기
const registers = await getRegisters(project.code);
+ const newRegisters = await getNewRegisters(project.code);
// 데이터베이스에 저장
- const count = await saveFormMappingsAndMetas(project.id, project.code, registers);
+ const count = await saveFormMappingsAndMetas(project.id, project.code, registers, newRegisters);
return {
project: project.code,
success: true,
diff --git a/lib/tag-numbering/table/tagNumbering-table-columns.tsx b/lib/tag-numbering/table/tagNumbering-table-columns.tsx
index 6e9b8191..1f3abfc4 100644
--- a/lib/tag-numbering/table/tagNumbering-table-columns.tsx
+++ b/lib/tag-numbering/table/tagNumbering-table-columns.tsx
@@ -90,7 +90,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<ViewTag
if (cfg.id === "createdAt"||cfg.id === "updatedAt") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
return row.getValue(cfg.id) ?? ""
diff --git a/lib/tags/table/tag-table-column.tsx b/lib/tags/table/tag-table-column.tsx
index 47746000..80c25464 100644
--- a/lib/tags/table/tag-table-column.tsx
+++ b/lib/tags/table/tag-table-column.tsx
@@ -100,7 +100,7 @@ export function getColumns({
header: ({ column }) => (
<DataTableColumnHeaderSimple column={column} title="Created At" />
),
- cell: ({ cell }) => formatDate(cell.getValue() as Date),
+ cell: ({ cell }) => formatDate(cell.getValue() as Date, "KR"),
meta: {
excelHeader: "created At"
},
@@ -113,7 +113,7 @@ export function getColumns({
header: ({ column }) => (
<DataTableColumnHeaderSimple column={column} title="Updated At" />
),
- cell: ({ cell }) => formatDate(cell.getValue() as Date),
+ cell: ({ cell }) => formatDate(cell.getValue() as Date, "KR"),
meta: {
excelHeader: "updated At"
},
diff --git a/lib/tasks/table/tasks-table-columns.tsx b/lib/tasks/table/tasks-table-columns.tsx
index 3737c2e5..7b0991dc 100644
--- a/lib/tasks/table/tasks-table-columns.tsx
+++ b/lib/tasks/table/tasks-table-columns.tsx
@@ -219,7 +219,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<Task>[]
if (cfg.id === "createdAt") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
// code etc...
diff --git a/lib/tbe/table/comments-sheet.tsx b/lib/tbe/table/comments-sheet.tsx
index 0952209d..35c29d39 100644
--- a/lib/tbe/table/comments-sheet.tsx
+++ b/lib/tbe/table/comments-sheet.tsx
@@ -178,7 +178,7 @@ export function CommentSheet({
</div>
)}
</TableCell>
- <TableCell> { c.createdAt ? formatDate(c.createdAt): "-"}</TableCell>
+ <TableCell> { c.createdAt ? formatDate(c.createdAt, "KR"): "-"}</TableCell>
<TableCell>
{c.commentedBy ?? "-"}
</TableCell>
diff --git a/lib/tbe/table/file-dialog.tsx b/lib/tbe/table/file-dialog.tsx
index b569f2b1..d22671da 100644
--- a/lib/tbe/table/file-dialog.tsx
+++ b/lib/tbe/table/file-dialog.tsx
@@ -118,7 +118,7 @@ export function TBEFileDialog({
<FileListInfo className="flex-1 min-w-0">
<FileListName className="text-sm font-medium truncate">{file.fileName}</FileListName>
<FileListDescription className="text-xs text-muted-foreground">
- {file.uploadedAt ? formatDateTime(file.uploadedAt) : ""}
+ {file.uploadedAt ? formatDateTime(file.uploadedAt, "KR") : ""}
</FileListDescription>
</FileListInfo>
</div>
diff --git a/lib/tbe/table/tbe-table-columns.tsx b/lib/tbe/table/tbe-table-columns.tsx
index 8f0de88c..f30cd0e0 100644
--- a/lib/tbe/table/tbe-table-columns.tsx
+++ b/lib/tbe/table/tbe-table-columns.tsx
@@ -215,7 +215,7 @@ export function getColumns({
if (cfg.id === "tbeUpdated") {
const dateVal = val as Date | undefined
if (!dateVal) return null
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
// 그 외 필드는 기본 값 표시
diff --git a/lib/tech-project-avl/table/accepted-quotations-table-columns.tsx b/lib/tech-project-avl/table/accepted-quotations-table-columns.tsx
index 68a61f0a..dae19395 100644
--- a/lib/tech-project-avl/table/accepted-quotations-table-columns.tsx
+++ b/lib/tech-project-avl/table/accepted-quotations-table-columns.tsx
@@ -293,7 +293,7 @@ export function getColumns(): ColumnDef<AcceptedQuotationItem>[] {
),
cell: ({ row }) => (
<div>
- {row.original.dueDate ? formatDate(row.original.dueDate) : "-"}
+ {row.original.dueDate ? formatDate(row.original.dueDate, "KR") : "-"}
</div>
),
enableSorting: true,
@@ -309,7 +309,7 @@ export function getColumns(): ColumnDef<AcceptedQuotationItem>[] {
),
cell: ({ row }) => (
<div>
- {row.original.acceptedAt ? formatDate(row.original.acceptedAt) : "-"}
+ {row.original.acceptedAt ? formatDate(row.original.acceptedAt, "KR") : "-"}
</div>
),
enableSorting: true,
diff --git a/lib/tech-vendor-candidates/table/candidates-table-columns.tsx b/lib/tech-vendor-candidates/table/candidates-table-columns.tsx
index 113927cf..aa6d0ef1 100644
--- a/lib/tech-vendor-candidates/table/candidates-table-columns.tsx
+++ b/lib/tech-vendor-candidates/table/candidates-table-columns.tsx
@@ -156,7 +156,7 @@ const actionsColumn: ColumnDef<VendorCandidatesWithVendorInfo> = {
if (cfg.id === "createdAt" ||cfg.id === "updatedAt" ) {
const dateVal = cell.getValue() as Date
- return formatDateTime(dateVal)
+ return formatDateTime(dateVal, "KR")
}
// code etc...
diff --git a/lib/tech-vendors/contacts-table/contact-table-columns.tsx b/lib/tech-vendors/contacts-table/contact-table-columns.tsx
index f80fae33..fece5013 100644
--- a/lib/tech-vendors/contacts-table/contact-table-columns.tsx
+++ b/lib/tech-vendors/contacts-table/contact-table-columns.tsx
@@ -146,12 +146,12 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<VendorC
if (cfg.id === "createdAt") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
if (cfg.id === "updatedAt") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
diff --git a/lib/tech-vendors/table/tech-vendors-table-columns.tsx b/lib/tech-vendors/table/tech-vendors-table-columns.tsx
index f690d266..69396c99 100644
--- a/lib/tech-vendors/table/tech-vendors-table-columns.tsx
+++ b/lib/tech-vendors/table/tech-vendors-table-columns.tsx
@@ -318,7 +318,7 @@ export function getColumns({ setRowAction, router, openItemsDialog }: GetColumns
// 날짜 컬럼 포맷팅
if (cfg.type === "date" && cell.getValue()) {
- return formatDate(cell.getValue() as Date);
+ return formatDate(cell.getValue() as Date, "KR");
}
return cell.getValue();
diff --git a/lib/techsales-rfq/service.ts b/lib/techsales-rfq/service.ts
index 14d7a45e..9689e855 100644
--- a/lib/techsales-rfq/service.ts
+++ b/lib/techsales-rfq/service.ts
@@ -634,7 +634,7 @@ export async function sendTechSalesRfqToVendors(input: {
projectCode: rfq.biddingProject?.pspid || '',
projectName: rfq.biddingProject?.projNm || '',
description: rfq.remark || '',
- dueDate: rfq.dueDate ? formatDate(rfq.dueDate) : 'N/A',
+ dueDate: rfq.dueDate ? formatDate(rfq.dueDate, "KR") : 'N/A',
materialCode: rfq.materialCode || '',
type: rfq.rfqType || 'SHIP',
},
diff --git a/lib/techsales-rfq/table/detail-table/quotation-history-dialog.tsx b/lib/techsales-rfq/table/detail-table/quotation-history-dialog.tsx
index 0195b10c..ce701e13 100644
--- a/lib/techsales-rfq/table/detail-table/quotation-history-dialog.tsx
+++ b/lib/techsales-rfq/table/detail-table/quotation-history-dialog.tsx
@@ -137,7 +137,7 @@ function QuotationCard({
<div>
<p className="text-sm font-medium text-muted-foreground">유효 기한</p>
<p className="text-sm">
- {data.validUntil ? formatDate(data.validUntil) : "미설정"}
+ {data.validUntil ? formatDate(data.validUntil, "KR") : "미설정"}
</p>
</div>
</div>
@@ -187,8 +187,8 @@ function QuotationCard({
<Clock className="size-3" />
<span>
{isCurrent
- ? `수정: ${data.updatedAt ? formatDate(data.updatedAt) : "N/A"}`
- : `변경: ${revisedAt ? formatDate(revisedAt) : "N/A"}`
+ ? `수정: ${data.updatedAt ? formatDate(data.updatedAt, "KR") : "N/A"}`
+ : `변경: ${revisedAt ? formatDate(revisedAt, "KR") : "N/A"}`
}
</span>
</div>
diff --git a/lib/techsales-rfq/table/detail-table/vendor-communication-drawer.tsx b/lib/techsales-rfq/table/detail-table/vendor-communication-drawer.tsx
index 4172ccd7..0312451d 100644
--- a/lib/techsales-rfq/table/detail-table/vendor-communication-drawer.tsx
+++ b/lib/techsales-rfq/table/detail-table/vendor-communication-drawer.tsx
@@ -351,7 +351,7 @@ export function VendorCommunicationDrawer({
{selectedAttachment.fileName}
</DialogTitle>
<DialogDescription>
- {formatFileSize(selectedAttachment.fileSize)} • {formatDateTime(selectedAttachment.uploadedAt)}
+ {formatFileSize(selectedAttachment.fileSize)} • {formatDateTime(selectedAttachment.uploadedAt, "KR")}
</DialogDescription>
</DialogHeader>
diff --git a/lib/techsales-rfq/table/rfq-table-column.tsx b/lib/techsales-rfq/table/rfq-table-column.tsx
index 3009e036..89054d0e 100644
--- a/lib/techsales-rfq/table/rfq-table-column.tsx
+++ b/lib/techsales-rfq/table/rfq-table-column.tsx
@@ -234,7 +234,7 @@ export function getColumns({
),
cell: ({ cell }) => {
const value = cell.getValue();
- return value ? formatDateTime(value as Date) : "";
+ return value ? formatDateTime(value as Date, "KR") : "";
},
meta: {
excelHeader: "등록일"
@@ -249,7 +249,7 @@ export function getColumns({
),
cell: ({ cell }) => {
const value = cell.getValue();
- return value ? formatDateTime(value as Date) : "";
+ return value ? formatDateTime(value as Date, "KR") : "";
},
meta: {
excelHeader: "수정일"
diff --git a/lib/techsales-rfq/table/tech-sales-quotation-attachments-sheet.tsx b/lib/techsales-rfq/table/tech-sales-quotation-attachments-sheet.tsx
index 21c61773..6d6bde5a 100644
--- a/lib/techsales-rfq/table/tech-sales-quotation-attachments-sheet.tsx
+++ b/lib/techsales-rfq/table/tech-sales-quotation-attachments-sheet.tsx
@@ -190,7 +190,7 @@ export function TechSalesQuotationAttachmentsSheet({
</Badge>
</div>
<p className="text-xs text-muted-foreground mt-1">
- {formatDate(attachment.createdAt)}
+ {formatDate(attachment.createdAt, "KR")}
</p>
{attachment.description && (
<p className="text-xs text-muted-foreground mt-1 break-words">
diff --git a/lib/techsales-rfq/table/tech-sales-rfq-attachments-sheet.tsx b/lib/techsales-rfq/table/tech-sales-rfq-attachments-sheet.tsx
index fa9be9e3..0593206a 100644
--- a/lib/techsales-rfq/table/tech-sales-rfq-attachments-sheet.tsx
+++ b/lib/techsales-rfq/table/tech-sales-rfq-attachments-sheet.tsx
@@ -379,7 +379,7 @@ export function TechSalesRfqAttachmentsSheet({
{existingFields.map((field, index) => {
const typeLabel = attachmentConfig.fileTypeLabel
const sizeText = field.fileSize ? prettyBytes(field.fileSize) : "알 수 없음"
- const dateText = field.createdAt ? formatDate(field.createdAt) : ""
+ const dateText = field.createdAt ? formatDate(field.createdAt, "KR") : ""
return (
<div key={field.id} className="flex items-start justify-between p-3 border rounded-md gap-3">
diff --git a/lib/users/access-control/users-table-columns.tsx b/lib/users/access-control/users-table-columns.tsx
index 7e510b96..f832085d 100644
--- a/lib/users/access-control/users-table-columns.tsx
+++ b/lib/users/access-control/users-table-columns.tsx
@@ -95,7 +95,7 @@ export function getColumns(): ColumnDef<User>[] {
if (cfg.id === "createdAt") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
if (cfg.id === "domain") {
diff --git a/lib/users/table/users-table-columns.tsx b/lib/users/table/users-table-columns.tsx
index c0eb9520..217fefcf 100644
--- a/lib/users/table/users-table-columns.tsx
+++ b/lib/users/table/users-table-columns.tsx
@@ -99,7 +99,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<UserVie
if (cfg.id === "created_at") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
if (cfg.id === "roles") {
diff --git a/lib/vendor-candidates/table/candidates-table-columns.tsx b/lib/vendor-candidates/table/candidates-table-columns.tsx
index 113927cf..aa6d0ef1 100644
--- a/lib/vendor-candidates/table/candidates-table-columns.tsx
+++ b/lib/vendor-candidates/table/candidates-table-columns.tsx
@@ -156,7 +156,7 @@ const actionsColumn: ColumnDef<VendorCandidatesWithVendorInfo> = {
if (cfg.id === "createdAt" ||cfg.id === "updatedAt" ) {
const dateVal = cell.getValue() as Date
- return formatDateTime(dateVal)
+ return formatDateTime(dateVal, "KR")
}
// code etc...
diff --git a/lib/vendor-candidates/table/view-candidate_logs-dialog.tsx b/lib/vendor-candidates/table/view-candidate_logs-dialog.tsx
index 8f0ea2eb..c429826a 100644
--- a/lib/vendor-candidates/table/view-candidate_logs-dialog.tsx
+++ b/lib/vendor-candidates/table/view-candidate_logs-dialog.tsx
@@ -105,7 +105,7 @@ export function ViewCandidateLogsDialog({
`"${log.comment?.replace(/"/g, '""') || ''}"`,
`"${log.userName || ''}"`,
`"${log.userEmail || ''}"`,
- `"${formatDateTime(log.createdAt)}"`
+ `"${formatDateTime(log.createdAt, "KR")}"`
].join(","))
].join("\n")
@@ -136,7 +136,7 @@ export function ViewCandidateLogsDialog({
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="sm:max-w-[700px]">
<DialogHeader>
- <DialogTitle>Audit Logs</DialogTitle>
+ <DialogTitle>협력업체 상태변경 히스토리</DialogTitle>
</DialogHeader>
{/* Filters and search */}
@@ -211,7 +211,7 @@ export function ViewCandidateLogsDialog({
<div className="flex justify-between items-start mb-2">
<Badge className="text-xs">{log.action}</Badge>
<div className="text-xs text-muted-foreground">
- {formatDateTime(log.createdAt)}
+ {formatDateTime(log.createdAt, "KR")}
</div>
</div>
diff --git a/lib/vendor-evaluation-submit/table/evaluation-submissions-table-columns.tsx b/lib/vendor-evaluation-submit/table/evaluation-submissions-table-columns.tsx
index aa6255bc..86355d54 100644
--- a/lib/vendor-evaluation-submit/table/evaluation-submissions-table-columns.tsx
+++ b/lib/vendor-evaluation-submit/table/evaluation-submissions-table-columns.tsx
@@ -212,7 +212,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<Evaluat
),
cell: ({ row }) => {
const date = row.getValue("submittedAt") as Date;
- return date ? formatDate(date) : (
+ return date ? formatDate(date, "KR") : (
<span className="text-muted-foreground">-</span>
);
},
@@ -234,7 +234,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<Evaluat
return (
<div className="space-y-1">
- <div className="text-sm">{formatDate(reviewedAt)}</div>
+ <div className="text-sm">{formatDate(reviewedAt, "KR")}</div>
{reviewedBy && (
<div className="text-xs text-muted-foreground">{reviewedBy}</div>
)}
@@ -436,7 +436,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<Evaluat
),
cell: ({ row }) => {
const date = row.getValue("createdAt") as Date;
- return formatDate(date);
+ return formatDate(date, "KR");
},
size: 140,
},
@@ -447,7 +447,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<Evaluat
),
cell: ({ row }) => {
const date = row.getValue("updatedAt") as Date;
- return formatDate(date);
+ return formatDate(date, "KR");
},
size: 140,
},
diff --git a/lib/vendor-type/table/vendorTypes-table-columns.tsx b/lib/vendor-type/table/vendorTypes-table-columns.tsx
index b5cfca71..a713ecc2 100644
--- a/lib/vendor-type/table/vendorTypes-table-columns.tsx
+++ b/lib/vendor-type/table/vendorTypes-table-columns.tsx
@@ -137,7 +137,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<VendorT
if (cfg.id === "createdAt"||cfg.id === "updatedAt") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
return row.getValue(cfg.id) ?? ""
diff --git a/lib/vendor-users/table/ausers-table-columns.tsx b/lib/vendor-users/table/ausers-table-columns.tsx
index 38281c7e..41b78adb 100644
--- a/lib/vendor-users/table/ausers-table-columns.tsx
+++ b/lib/vendor-users/table/ausers-table-columns.tsx
@@ -173,7 +173,7 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<UserVie
if (cfg.id === "created_at") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
if (cfg.id === "roles") {
diff --git a/lib/vendors/contacts-table/contact-table-columns.tsx b/lib/vendors/contacts-table/contact-table-columns.tsx
index f80fae33..fece5013 100644
--- a/lib/vendors/contacts-table/contact-table-columns.tsx
+++ b/lib/vendors/contacts-table/contact-table-columns.tsx
@@ -146,12 +146,12 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<VendorC
if (cfg.id === "createdAt") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
if (cfg.id === "updatedAt") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
diff --git a/lib/vendors/items-table/item-table-columns.tsx b/lib/vendors/items-table/item-table-columns.tsx
index 769722e4..61bd0325 100644
--- a/lib/vendors/items-table/item-table-columns.tsx
+++ b/lib/vendors/items-table/item-table-columns.tsx
@@ -146,12 +146,12 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<VendorI
if (cfg.id === "createdAt") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
if (cfg.id === "updatedAt") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
diff --git a/lib/vendors/materials-table/item-table-columns.tsx b/lib/vendors/materials-table/item-table-columns.tsx
index d2aa0f8f..6a37d404 100644
--- a/lib/vendors/materials-table/item-table-columns.tsx
+++ b/lib/vendors/materials-table/item-table-columns.tsx
@@ -146,12 +146,12 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<VendorM
if (cfg.id === "createdAt") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
if (cfg.id === "updatedAt") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
diff --git a/lib/vendors/rfq-history-table/rfq-history-table-columns.tsx b/lib/vendors/rfq-history-table/rfq-history-table-columns.tsx
index 7e22e96a..66ddee47 100644
--- a/lib/vendors/rfq-history-table/rfq-history-table-columns.tsx
+++ b/lib/vendors/rfq-history-table/rfq-history-table-columns.tsx
@@ -189,7 +189,7 @@ export function getColumns({ setRowAction, openItemsModal }: GetColumnsProps): C
if (cfg.id === "dueDate" || cfg.id === "createdAt") {
column.cell = ({ row }) => (
<div className="whitespace-nowrap">
- {formatDate(row.getValue(cfg.id))}
+ {formatDate(row.getValue(cfg.id), "KR")}
</div>
)
}
diff --git a/lib/vendors/table/request-vendor-investigate-dialog.tsx b/lib/vendors/table/request-vendor-investigate-dialog.tsx
index b3deafce..a0d84128 100644
--- a/lib/vendors/table/request-vendor-investigate-dialog.tsx
+++ b/lib/vendors/table/request-vendor-investigate-dialog.tsx
@@ -210,10 +210,10 @@ export function RequestVendorsInvestigateDialog({
<TableCell>
<Badge variant={status.variant as any}>{status.text}</Badge>
</TableCell>
- <TableCell>{formatDate(investigation.createdAt)}</TableCell>
+ <TableCell>{formatDate(investigation.createdAt, "KR")}</TableCell>
<TableCell>
{investigation.scheduledStartAt
- ? formatDate(investigation.scheduledStartAt)
+ ? formatDate(investigation.scheduledStartAt, "KR")
: "미정"}
</TableCell>
</TableRow>
diff --git a/lib/vendors/table/vendor-all-export.ts b/lib/vendors/table/vendor-all-export.ts
index cef801fd..31ab2b52 100644
--- a/lib/vendors/table/vendor-all-export.ts
+++ b/lib/vendors/table/vendor-all-export.ts
@@ -184,7 +184,7 @@ function createBasicInfoSheet(
representativeName: vendor.representativeName,
creditRating: vendor.creditRating,
cashFlowRating: vendor.cashFlowRating,
- createdAt: vendor.createdAt ? formatDate(vendor.createdAt) : "",
+ createdAt: vendor.createdAt ? formatDate(vendor.createdAt, "KR") : "",
});
});
}
@@ -280,7 +280,7 @@ function createItemsSheet(
itemCode: item.itemCode,
itemName: item.itemName,
description: item.description || "",
- createdAt: item.createdAt ? formatDate(item.createdAt) : "",
+ createdAt: item.createdAt ? formatDate(item.createdAt, "KR") : "",
});
});
} else {
@@ -335,8 +335,8 @@ function createRFQsSheet(
rfqNumber: rfq.rfqNumber,
title: rfq.title,
status: rfq.status,
- requestDate: rfq.requestDate ? formatDate(rfq.requestDate) : "",
- dueDate: rfq.dueDate ? formatDate(rfq.dueDate) : "",
+ requestDate: rfq.requestDate ? formatDate(rfq.requestDate, "KR") : "",
+ dueDate: rfq.dueDate ? formatDate(rfq.dueDate, "KR") : "",
description: rfq.description || "",
});
});
@@ -405,10 +405,10 @@ function createContractsSheet(
status: contract.status,
paymentTerms: contract.paymentTerms,
deliveryTerms: contract.deliveryTerms,
- deliveryDate: contract.deliveryDate ? formatDate(contract.deliveryDate) : "",
+ deliveryDate: contract.deliveryDate ? formatDate(contract.deliveryDate, "KR") : "",
deliveryLocation: contract.deliveryLocation,
- startDate: contract.startDate ? formatDate(contract.startDate) : "",
- endDate: contract.endDate ? formatDate(contract.endDate) : "",
+ startDate: contract.startDate ? formatDate(contract.startDate, "KR") : "",
+ endDate: contract.endDate ? formatDate(contract.endDate, "KR") : "",
currency: contract.currency,
totalAmount: contract.totalAmount ? formatAmount(contract.totalAmount) : "",
});
diff --git a/lib/vendors/table/vendors-table-columns.tsx b/lib/vendors/table/vendors-table-columns.tsx
index 21086918..0a5f066f 100644
--- a/lib/vendors/table/vendors-table-columns.tsx
+++ b/lib/vendors/table/vendors-table-columns.tsx
@@ -375,12 +375,12 @@ export function getColumns({ setRowAction, router, userId }: GetColumnsProps): C
if (cfg.id === "createdAt") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
if (cfg.id === "updatedAt") {
const dateVal = cell.getValue() as Date
- return formatDate(dateVal)
+ return formatDate(dateVal, "KR")
}
// code etc...
diff --git a/lib/vendors/table/view-vendors_logs-dialog.tsx b/lib/vendors/table/view-vendors_logs-dialog.tsx
index 7402ae55..521c52e9 100644
--- a/lib/vendors/table/view-vendors_logs-dialog.tsx
+++ b/lib/vendors/table/view-vendors_logs-dialog.tsx
@@ -104,7 +104,7 @@ export function ViewVendorLogsDialog({
`"${log.comment?.replace(/"/g, '""') || ''}"`,
`"${log.userName || ''}"`,
`"${log.userEmail || ''}"`,
- `"${formatDateTime(log.createdAt)}"`
+ `"${formatDateTime(log.createdAt, "KR")}"`
].join(","))
].join("\n")
@@ -135,7 +135,7 @@ export function ViewVendorLogsDialog({
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="sm:max-w-[700px]">
<DialogHeader>
- <DialogTitle>Audit Logs</DialogTitle>
+ <DialogTitle>협력업체 상태변경 히스토리</DialogTitle>
</DialogHeader>
{/* Filters and search */}
@@ -209,7 +209,7 @@ export function ViewVendorLogsDialog({
<div className="flex justify-between items-start mb-2">
<Badge className="text-xs">{log.action}</Badge>
<div className="text-xs text-muted-foreground">
- {formatDateTime(log.createdAt)}
+ {formatDateTime(log.createdAt, "KR")}
</div>
</div>
diff --git a/lib/welding/repository.ts b/lib/welding/repository.ts
index 1e96867b..e3351358 100644
--- a/lib/welding/repository.ts
+++ b/lib/welding/repository.ts
@@ -36,6 +36,8 @@ export async function selectOcrRows(
// ocrRows의 모든 필드
id: ocrRows.id,
tableId: ocrRows.tableId,
+ fileName: ocrRows.fileName,
+ inspectionDate: ocrRows.inspectionDate,
sessionId: ocrRows.sessionId,
rowIndex: ocrRows.rowIndex,
reportNo: ocrRows.reportNo,
diff --git a/lib/welding/table/ocr-table-columns.tsx b/lib/welding/table/ocr-table-columns.tsx
index 93ee1004..d4ca9f5f 100644
--- a/lib/welding/table/ocr-table-columns.tsx
+++ b/lib/welding/table/ocr-table-columns.tsx
@@ -51,7 +51,25 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<OcrRow>
enableSorting: false,
enableHiding: false,
},
-
+ {
+ accessorKey: "fileName",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="file Name" />
+ ),
+ cell: ({ getValue }) => {
+ const fileName = getValue() as string
+ return (
+ <div className="text-sm">
+ {/* <Badge variant="outline" className="font-mono text-xs"> */}
+ {fileName || "N/A"}
+ {/* </Badge> */}
+
+ </div>
+ )
+ },
+ enableSorting: true,
+ enableHiding: false,
+ },
// Report No 컬럼
{
accessorKey: "reportNo",
@@ -233,7 +251,25 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<OcrRow>
// },
// enableSorting: true,
// },
-
+ {
+ accessorKey: "inspectionDate",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="Inspection(Confirmed) Date" />
+ ),
+ cell: ({ getValue }) => {
+ const inspectionDate = getValue() as string
+ return (
+ <div className="text-sm">
+ {/* <Badge variant="outline" className="font-mono text-xs"> */}
+ {inspectionDate || "N/A"}
+ {/* </Badge> */}
+
+ </div>
+ )
+ },
+ enableSorting: true,
+ enableHiding: false,
+ },
{
accessorKey: "userName",