From 8945be5ea89365f8a686a0e65b5a7d5b61c2ca20 Mon Sep 17 00:00:00 2001
From: joonhoekim <26rote@gmail.com>
Date: Fri, 3 Oct 2025 13:54:38 +0900
Subject: (김준회) 부서별 권한관리, swp 코멘트 기능, 벤더 po, shi-api 동기화
로직 수정
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../plant/document-comment-dialog.tsx | 183 +++++++++++++++++++++
.../plant/document-stage-toolbar.tsx | 2 +-
.../plant/document-stages-columns.tsx | 25 ++-
.../plant/document-stages-service.ts | 53 ++++++
.../plant/document-stages-table.tsx | 17 ++
.../plant/shi-buyer-system-api.ts | 3 +-
6 files changed, 277 insertions(+), 6 deletions(-)
create mode 100644 lib/vendor-document-list/plant/document-comment-dialog.tsx
(limited to 'lib/vendor-document-list')
diff --git a/lib/vendor-document-list/plant/document-comment-dialog.tsx b/lib/vendor-document-list/plant/document-comment-dialog.tsx
new file mode 100644
index 00000000..3dc3d321
--- /dev/null
+++ b/lib/vendor-document-list/plant/document-comment-dialog.tsx
@@ -0,0 +1,183 @@
+"use client"
+
+import React from "react"
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog"
+import { Button } from "@/components/ui/button"
+import { Textarea } from "@/components/ui/textarea"
+import { Label } from "@/components/ui/label"
+import { ScrollArea } from "@/components/ui/scroll-area"
+import { Loader2, MessageSquare } from "lucide-react"
+import { toast } from "sonner"
+import { useSession } from "next-auth/react"
+import { addDocumentComment } from "./document-stages-service"
+import { useRouter } from "next/navigation"
+import { cn } from "@/lib/utils"
+
+interface DocumentCommentDialogProps {
+ open: boolean
+ onOpenChange: (open: boolean) => void
+ documentId: number
+ docNumber: string
+ currentComment: string | null
+}
+
+export function DocumentCommentDialog({
+ open,
+ onOpenChange,
+ documentId,
+ docNumber,
+ currentComment,
+}: DocumentCommentDialogProps) {
+ const [newComment, setNewComment] = React.useState("")
+ const [isSubmitting, setIsSubmitting] = React.useState(false)
+ const { data: session } = useSession()
+ const router = useRouter()
+
+ // 기존 코멘트를 줄 단위로 파싱
+ const existingComments = React.useMemo(() => {
+ if (!currentComment) return []
+ return currentComment.split('\n').filter(line => line.trim() !== '')
+ }, [currentComment])
+
+ const handleSubmit = async () => {
+ if (!newComment.trim()) {
+ toast.error("코멘트 내용을 입력해주세요.")
+ return
+ }
+
+ if (!session?.user?.name || !session?.user?.email) {
+ toast.error("사용자 정보를 가져올 수 없습니다.")
+ return
+ }
+
+ setIsSubmitting(true)
+ try {
+ const result = await addDocumentComment({
+ documentId,
+ newComment: newComment.trim(),
+ userInfo: {
+ name: session.user.name,
+ email: session.user.email,
+ },
+ })
+
+ if (result.success) {
+ toast.success("코멘트가 추가되었습니다.")
+ setNewComment("")
+ onOpenChange(false)
+ router.refresh()
+ } else {
+ toast.error(result.error || "코멘트 추가 중 오류가 발생했습니다.")
+ }
+ } catch (error) {
+ console.error("Error adding comment:", error)
+ toast.error("코멘트 추가 중 오류가 발생했습니다.")
+ } finally {
+ setIsSubmitting(false)
+ }
+ }
+
+ const handleClose = () => {
+ if (!isSubmitting) {
+ setNewComment("")
+ onOpenChange(false)
+ }
+ }
+
+ return (
+
+ )
+}
+
+
diff --git a/lib/vendor-document-list/plant/document-stage-toolbar.tsx b/lib/vendor-document-list/plant/document-stage-toolbar.tsx
index f676e1fc..51767528 100644
--- a/lib/vendor-document-list/plant/document-stage-toolbar.tsx
+++ b/lib/vendor-document-list/plant/document-stage-toolbar.tsx
@@ -103,7 +103,7 @@ export function DocumentsTableToolbarActions({
{(() => {
const selectedRows = table.getFilteredSelectedRowModel().rows;
const deletableDocuments = selectedRows
- .map((row) => row.original)s
+ .map((row) => row.original)
.filter((doc) => !doc.buyerSystemStatus); // buyerSystemStatus가 null인 것만 필터링
return deletableDocuments.length > 0 ? (
diff --git a/lib/vendor-document-list/plant/document-stages-columns.tsx b/lib/vendor-document-list/plant/document-stages-columns.tsx
index af68ddb2..d5dfc895 100644
--- a/lib/vendor-document-list/plant/document-stages-columns.tsx
+++ b/lib/vendor-document-list/plant/document-stages-columns.tsx
@@ -380,14 +380,31 @@ export function getDocumentStagesColumns({
),
cell: ({ row }) => {
const doc = row.original
+ const hasComment = doc.buyerSystemComment && doc.buyerSystemComment.trim() !== ''
return (
-
- {doc.buyerSystemComment}
-
+
)
},
- size: 180,
+ size: 150,
enableResizing: true,
meta: {
excelHeader: "Document Comment"
diff --git a/lib/vendor-document-list/plant/document-stages-service.ts b/lib/vendor-document-list/plant/document-stages-service.ts
index 5f803104..cff448d5 100644
--- a/lib/vendor-document-list/plant/document-stages-service.ts
+++ b/lib/vendor-document-list/plant/document-stages-service.ts
@@ -1201,6 +1201,59 @@ export async function pullDocumentStatusFromSHI(
}
}
+// 문서 코멘트 추가
+export async function addDocumentComment(input: {
+ documentId: number
+ newComment: string
+ userInfo: {
+ name: string
+ email: string
+ }
+}) {
+ try {
+ // 1. 현재 문서 정보 조회
+ const document = await db.query.stageDocuments.findFirst({
+ where: eq(stageDocuments.id, input.documentId),
+ })
+
+ if (!document) {
+ return { success: false, error: "문서를 찾을 수 없습니다." }
+ }
+
+ // 2. 새 코멘트 포맷팅: [이름·이메일] 코멘트내용
+ const timestamp = new Date().toISOString().split('T')[0] // YYYY-MM-DD
+ const formattedComment = `[${input.userInfo.name}·${input.userInfo.email}] ${timestamp}: ${input.newComment}`
+
+ // 3. 기존 코멘트와 결합
+ const updatedComment = document.buyerSystemComment
+ ? `${document.buyerSystemComment}\n${formattedComment}`
+ : formattedComment
+
+ // 4. 문서 업데이트
+ await db
+ .update(stageDocuments)
+ .set({
+ buyerSystemComment: updatedComment,
+ updatedAt: new Date(),
+ })
+ .where(eq(stageDocuments.id, input.documentId))
+
+ // 5. 캐시 무효화
+ revalidatePath(`/partners/document-list-only/${document.contractId}`)
+
+ return {
+ success: true,
+ data: { comment: updatedComment }
+ }
+ } catch (error) {
+ console.error("코멘트 추가 실패:", error)
+ return {
+ success: false,
+ error: "코멘트 추가 중 오류가 발생했습니다."
+ }
+ }
+}
+
interface FileValidation {
projectId: number
diff --git a/lib/vendor-document-list/plant/document-stages-table.tsx b/lib/vendor-document-list/plant/document-stages-table.tsx
index 6cc112e3..63f0eae6 100644
--- a/lib/vendor-document-list/plant/document-stages-table.tsx
+++ b/lib/vendor-document-list/plant/document-stages-table.tsx
@@ -34,6 +34,7 @@ import { EditDocumentDialog } from "./document-stage-dialogs"
import { EditStageDialog } from "./document-stage-dialogs"
import { DocumentsTableToolbarActions } from "./document-stage-toolbar"
import { useSession } from "next-auth/react"
+import { DocumentCommentDialog } from "./document-comment-dialog"
interface DocumentStagesTableProps {
promises: Promise<[Awaited>]>
@@ -68,6 +69,7 @@ export function DocumentStagesTable({
const [editDocumentOpen, setEditDocumentOpen] = React.useState(false)
const [editStageOpen, setEditStageOpen] = React.useState(false)
const [excelImportOpen, setExcelImportOpen] = React.useState(false)
+ const [commentDialogOpen, setCommentDialogOpen] = React.useState(false)
// 선택된 항목들
const [selectedDocument, setSelectedDocument] = React.useState(null)
@@ -101,6 +103,9 @@ export function DocumentStagesTable({
}
setExpandedRows(newExpanded)
break
+ case "view_comment":
+ setCommentDialogOpen(true)
+ break
}
}
},
@@ -164,6 +169,7 @@ export function DocumentStagesTable({
setEditDocumentOpen(false)
setEditStageOpen(false)
setExcelImportOpen(false)
+ setCommentDialogOpen(false)
setSelectedDocument(null)
setSelectedStageId(null)
setRowAction(null)
@@ -413,6 +419,17 @@ export function DocumentStagesTable({
documents={rowAction?.row.original ? [rowAction?.row.original] : []}
onSuccess={() => rowAction?.row.toggleSelected(false)}
/>
+
+ {
+ if (!open) closeAllDialogs()
+ else setCommentDialogOpen(open)
+ }}
+ documentId={selectedDocument?.documentId || 0}
+ docNumber={selectedDocument?.docNumber || ''}
+ currentComment={selectedDocument?.buyerSystemComment || null}
+ />
)
}
\ No newline at end of file
diff --git a/lib/vendor-document-list/plant/shi-buyer-system-api.ts b/lib/vendor-document-list/plant/shi-buyer-system-api.ts
index b0462af8..9256eaf4 100644
--- a/lib/vendor-document-list/plant/shi-buyer-system-api.ts
+++ b/lib/vendor-document-list/plant/shi-buyer-system-api.ts
@@ -246,6 +246,7 @@ export class ShiBuyerSystemAPI {
vendorDocNumber: stageDocuments.vendorDocNumber,
title: stageDocuments.title,
status: stageDocuments.status,
+ buyerSystemComment: stageDocuments.buyerSystemComment, // 코멘트 필드 추가
projectCode: sql`(SELECT code FROM projects WHERE id = ${stageDocuments.projectId})`,
vendorCode: sql`(SELECT vendor_code FROM vendors WHERE id = ${stageDocuments.vendorId})`,
vendorName: sql`(SELECT vendor_name FROM vendors WHERE id = ${stageDocuments.vendorId})`,
@@ -300,7 +301,7 @@ export class ShiBuyerSystemAPI {
OWN_DOC_NO: doc.vendorDocNumber || doc.docNumber,
DSC: doc.title,
DOC_CLASS: 'B3',
- COMMENT: '',
+ COMMENT: doc.buyerSystemComment || '', // 실제 코멘트 전송
// 조민정 프로 요청으로 'ACTIVE' --> '생성요청' 값으로 변경 (251002,김준회)
STATUS: '생성요청',
CRTER: 'EVCP_SYSTEM',
--
cgit v1.2.3