summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/dolce-v2/dialogs/add-and-modify-detail-drawing-dialog-v2.tsx131
-rw-r--r--lib/dolce-v2/sync-service.ts25
-rw-r--r--lib/dolce/table/detail-drawing-columns.tsx7
-rw-r--r--lib/dolce/utils/date-formatter.ts18
4 files changed, 44 insertions, 137 deletions
diff --git a/lib/dolce-v2/dialogs/add-and-modify-detail-drawing-dialog-v2.tsx b/lib/dolce-v2/dialogs/add-and-modify-detail-drawing-dialog-v2.tsx
index b8650b1a..7577d133 100644
--- a/lib/dolce-v2/dialogs/add-and-modify-detail-drawing-dialog-v2.tsx
+++ b/lib/dolce-v2/dialogs/add-and-modify-detail-drawing-dialog-v2.tsx
@@ -319,135 +319,8 @@ export function AddAndModifyDetailDrawingDialogV2({
};
const handleCancel = () => {
- // 유효성 검사
- if (!registerKind) {
- toast.error(t("addDetailDialog.selectRegisterKindError"));
- return;
- }
-
- if (drawingUsage !== "CMT") {
- if (!revision.trim()) {
- toast.error(t("addDetailDialog.selectRevisionError"));
- setRevisionError(t("addDetailDialog.revisionRequired"));
- return;
- }
-
- // Revision 형식 검증
- const revisionValidationError = validateRevision(revision);
- if (revisionValidationError) {
- toast.error(revisionValidationError);
- setRevisionError(revisionValidationError);
- return;
- }
- }
-
- // Add 모드일 때만 파일 필수
- if (mode === "add") {
- if (!drawing) return;
- if (!drawingUsage) {
- toast.error(t("addDetailDialog.selectDrawingUsageError"));
- return;
- }
- if (files.length === 0) {
- toast.error(t("addDetailDialog.selectFilesError"));
- return;
- }
- }
-
- // Edit 모드일 때는 detailDrawing 필수
- if (mode === "edit" && !detailDrawing) {
- toast.error(t("editDetailDialog.editError"));
- return;
- }
-
- try {
- setIsSubmitting(true);
-
- // FormData 구성
- const formData = new FormData();
- formData.append("userId", userId);
- formData.append("userNm", userName);
- formData.append("vendorCode", vendorCode);
- formData.append("email", userEmail);
-
- if (mode === "add" && drawing) {
- const uploadId = uuidv4();
-
- const dwgList = [
- {
- Mode: "ADD",
- Status: "Submitted",
- RegisterId: 0,
- ProjectNo: drawing.ProjectNo,
- Discipline: drawing.Discipline,
- DrawingKind: drawing.DrawingKind,
- DrawingNo: drawing.DrawingNo,
- DrawingName: drawing.DrawingName,
- RegisterGroupId: drawing.RegisterGroupId,
- RegisterSerialNo: 0,
- RegisterKind: registerKind,
- DrawingRevNo: drawingUsage === "CMT" ? null : revision,
- Category: "TS",
- Receiver: null,
- Manager: "",
- RegisterDesc: comment,
- UploadId: uploadId,
- RegCompanyCode: vendorCode,
- },
- ];
- formData.append("dwgList", JSON.stringify(dwgList));
-
- // 파일 추가
- formData.append("fileCount", String(files.length));
- files.forEach((file, index) => {
- formData.append(`file_${index}`, file);
- });
-
- } else if (mode === "edit" && detailDrawing) {
- const dwgList = [
- {
- Mode: "MOD",
- Status: detailDrawing.Status,
- RegisterId: detailDrawing.RegisterId,
- ProjectNo: detailDrawing.ProjectNo,
- Discipline: detailDrawing.Discipline,
- DrawingKind: detailDrawing.DrawingKind,
- DrawingNo: detailDrawing.DrawingNo,
- DrawingName: detailDrawing.DrawingName,
- RegisterGroupId: detailDrawing.RegisterGroupId,
- RegisterSerialNo: detailDrawing.RegisterSerialNo,
- RegisterKind: registerKind,
- DrawingRevNo: drawingUsage === "CMT" ? null : revision,
- Category: detailDrawing.Category,
- Receiver: detailDrawing.Receiver,
- Manager: detailDrawing.Manager,
- RegisterDesc: comment,
- UploadId: detailDrawing.UploadId,
- RegCompanyCode: detailDrawing.RegCompanyCode || vendorCode,
- },
- ];
- formData.append("dwgList", JSON.stringify(dwgList));
- formData.append("fileCount", "0"); // 수정 시에는 메타데이터만 수정 (파일 수정은 별도)
- }
-
- // Action 호출
- const result = await editDetailDwgReceiptV2(formData);
-
- if (result.success) {
- toast.success(mode === "add" ? t("addDetailDialog.addSuccess") : t("editDetailDialog.editSuccess"));
- resetForm();
- onComplete();
- onOpenChange(false);
- } else {
- throw new Error("Action failed");
- }
-
- } catch (error) {
- console.error("상세도면 처리 실패:", error);
- toast.error(mode === "add" ? t("addDetailDialog.addErrorMessage") : t("editDetailDialog.editErrorMessage"));
- } finally {
- setIsSubmitting(false);
- }
+ resetForm();
+ onOpenChange(false);
};
// DrawingUsage가 변경되면 RegisterKind 초기화
diff --git a/lib/dolce-v2/sync-service.ts b/lib/dolce-v2/sync-service.ts
index ea56b239..7f866955 100644
--- a/lib/dolce-v2/sync-service.ts
+++ b/lib/dolce-v2/sync-service.ts
@@ -1,6 +1,9 @@
"use server";
import fs from "fs/promises";
+import { createReadStream, createWriteStream } from "fs";
+import { Readable } from "stream";
+import { pipeline } from "stream/promises";
import path from "path";
import { v4 as uuidv4 } from "uuid";
import db from "@/db/db";
@@ -41,11 +44,15 @@ async function ensureUploadDir() {
async function saveFileToLocal(file: File): Promise<SavedFile> {
await ensureUploadDir();
- const buffer = Buffer.from(await file.arrayBuffer());
const uniqueName = `${uuidv4()}_${file.name}`;
const localPath = path.join(LOCAL_UPLOAD_DIR, uniqueName);
- await fs.writeFile(localPath, buffer);
+ // Stream: Web Stream (file.stream()) -> Node Writable Stream (fs.createWriteStream)
+ // Readable.fromWeb requires Node 18+
+ const readable = Readable.fromWeb(file.stream() as any);
+ const writable = createWriteStream(localPath);
+
+ await pipeline(readable, writable);
return {
originalName: file.name,
@@ -254,16 +261,20 @@ async function uploadLocalFiles(uploadId: string, userId: string, files: SavedFi
const file = files[i];
const fileId = uuidv4();
- // 로컬 파일 읽기
- const fileBuffer = await fs.readFile(file.localPath);
+ // 로컬 파일 읽기 (Stream)
+ const fileStream = createReadStream(file.localPath);
// 업로드 API 호출
const uploadUrl = `${DOLCE_API_URL}/PWPUploadService.ashx?UploadId=${uploadId}&FileId=${fileId}`;
const uploadResponse = await fetch(uploadUrl, {
method: "POST",
- headers: { "Content-Type": "application/octet-stream" },
- body: fileBuffer,
- });
+ headers: {
+ "Content-Type": "application/octet-stream",
+ "Content-Length": file.size.toString()
+ },
+ body: fileStream as any, // Node stream as body
+ duplex: "half", // Required for Node streams
+ } as RequestInit & { duplex?: string });
if (!uploadResponse.ok) throw new Error(`File upload failed: ${uploadResponse.status}`);
diff --git a/lib/dolce/table/detail-drawing-columns.tsx b/lib/dolce/table/detail-drawing-columns.tsx
index 30290817..215a0cff 100644
--- a/lib/dolce/table/detail-drawing-columns.tsx
+++ b/lib/dolce/table/detail-drawing-columns.tsx
@@ -104,7 +104,7 @@ export function createDetailDrawingColumns(
minSize: 180,
cell: ({ row }) => {
// 항상 RegisterKindENM 필드를 보여줌
- return <div>{row.getValue("RegisterKindENM")}</div>;
+ return <div>{row.getValue("RegisterKindENM") || row.original.RegisterKind}</div>;
},
},
{
@@ -114,6 +114,11 @@ export function createDetailDrawingColumns(
cell: ({ row }) => {
const userENM = row.original.CreateUserENM;
const userNM = row.getValue("CreateUserNM") as string;
+
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const localUserName = (row.original as any).userName;
+ if (localUserName) return <div>{localUserName}</div>;
+
return <div>{lng === "en" ? (userENM || userNM) : (userNM || userENM)}</div>;
},
},
diff --git a/lib/dolce/utils/date-formatter.ts b/lib/dolce/utils/date-formatter.ts
index 83e78b0d..ebf9653a 100644
--- a/lib/dolce/utils/date-formatter.ts
+++ b/lib/dolce/utils/date-formatter.ts
@@ -6,12 +6,30 @@
*/
import { formatSwpDate } from "@/lib/swp/utils";
+import { format, parseISO, isValid } from "date-fns";
/**
* SWP와 동일한 방식
+ * Postgres Date 타입(ISO String) 처리 추가
*/
export function formatDolceDateTime(dateStr: string | null): string {
if (!dateStr) return "-";
+
+ // ISO string check (e.g. "2023-11-27T10:20:30.000Z" or similar)
+ if (dateStr.includes("-") && (dateStr.includes("T") || dateStr.includes(":"))) {
+ try {
+ const date = parseISO(dateStr);
+ if (isValid(date)) {
+ // Requested format: YYYY-MM-DD AM/PM HH:mm:ss
+ // date-fns format: yyyy-MM-dd a hh:mm:ss
+ return format(date, "yyyy-MM-dd a hh:mm:ss");
+ }
+ } catch (e) {
+ // ignore parse error, fallback to default
+ console.error("Date parse error", e);
+ }
+ }
+
return formatSwpDate(dateStr);
}