summaryrefslogtreecommitdiff
path: root/lib/techsales-rfq/table/detail-table/rfq-detail-column.tsx
diff options
context:
space:
mode:
authorjoonhoekim <26rote@gmail.com>2025-06-24 01:51:59 +0000
committerjoonhoekim <26rote@gmail.com>2025-06-24 01:51:59 +0000
commit6824e097d768f724cf439b410ccfb1ab9685ac98 (patch)
tree1f297313637878e7a4ad6c89b84d5a2c3e9eb650 /lib/techsales-rfq/table/detail-table/rfq-detail-column.tsx
parentf4825dd3853188de4688fb4a56c0f4e847da314b (diff)
parent4e63d8427d26d0d1b366ddc53650e15f3481fc75 (diff)
(merge) 대표님/최겸 작업사항 머지
Diffstat (limited to 'lib/techsales-rfq/table/detail-table/rfq-detail-column.tsx')
-rw-r--r--lib/techsales-rfq/table/detail-table/rfq-detail-column.tsx101
1 files changed, 95 insertions, 6 deletions
diff --git a/lib/techsales-rfq/table/detail-table/rfq-detail-column.tsx b/lib/techsales-rfq/table/detail-table/rfq-detail-column.tsx
index 3e50a516..e921fcaa 100644
--- a/lib/techsales-rfq/table/detail-table/rfq-detail-column.tsx
+++ b/lib/techsales-rfq/table/detail-table/rfq-detail-column.tsx
@@ -5,7 +5,7 @@ import type { ColumnDef, Row } from "@tanstack/react-table";
import { formatDate } from "@/lib/utils"
import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header"
import { Checkbox } from "@/components/ui/checkbox";
-import { MessageCircle, MoreHorizontal, Trash2 } from "lucide-react";
+import { MessageCircle, MoreHorizontal, Trash2, Paperclip } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import {
@@ -38,6 +38,24 @@ export interface RfqDetailView {
createdAt: Date | null
updatedAt: Date | null
createdByName: string | null
+ quotationCode?: string | null
+ rfqCode?: string | null
+ quotationAttachments?: Array<{
+ id: number
+ revisionId: number
+ fileName: string
+ fileSize: number
+ filePath: string
+ description?: string | null
+ }>
+}
+
+// 견적서 정보 타입 (Sheet용)
+export interface QuotationInfo {
+ id: number
+ quotationCode: string | null
+ vendorName?: string
+ rfqCode?: string
}
interface GetColumnsProps<TData> {
@@ -45,11 +63,15 @@ interface GetColumnsProps<TData> {
React.SetStateAction<DataTableRowAction<TData> | null>
>;
unreadMessages?: Record<number, number>; // 읽지 않은 메시지 개수
+ onQuotationClick?: (quotationId: number) => void; // 견적 클릭 핸들러
+ openQuotationAttachmentsSheet?: (quotationId: number, quotationInfo: QuotationInfo) => void; // 견적서 첨부파일 sheet 열기
}
export function getRfqDetailColumns({
setRowAction,
- unreadMessages = {}
+ unreadMessages = {},
+ onQuotationClick,
+ openQuotationAttachmentsSheet
}: GetColumnsProps<RfqDetailView>): ColumnDef<RfqDetailView>[] {
return [
{
@@ -66,15 +88,15 @@ export function getRfqDetailColumns({
),
cell: ({ row }) => {
const status = row.original.status;
- const isDraft = status === "Draft";
+ const isSelectable = status ? !["Accepted", "Rejected"].includes(status) : true;
return (
<Checkbox
checked={row.getIsSelected()}
onCheckedChange={(value) => row.toggleSelected(!!value)}
- disabled={!isDraft}
+ disabled={!isSelectable}
aria-label="행 선택"
- className={!isDraft ? "opacity-50 cursor-not-allowed" : ""}
+ className={!isSelectable ? "opacity-50 cursor-not-allowed" : ""}
/>
);
},
@@ -163,15 +185,31 @@ export function getRfqDetailColumns({
cell: ({ row }) => {
const value = row.getValue("totalPrice") as string | number | null;
const currency = row.getValue("currency") as string | null;
+ const quotationId = row.original.id;
if (value === null || value === undefined) return "-";
// 숫자로 변환 시도
const numValue = typeof value === 'string' ? parseFloat(value) : value;
+ const displayValue = isNaN(numValue) ? value : numValue.toLocaleString();
+
+ // 견적값이 있고 클릭 핸들러가 있는 경우 클릭 가능한 버튼으로 표시
+ if (onQuotationClick && quotationId) {
+ return (
+ <Button
+ variant="link"
+ className="p-0 h-auto font-medium text-left justify-start hover:underline"
+ onClick={() => onQuotationClick(quotationId)}
+ title="견적 히스토리 보기"
+ >
+ {displayValue} {currency}
+ </Button>
+ );
+ }
return (
<div className="font-medium">
- {isNaN(numValue) ? value : numValue.toLocaleString()} {currency}
+ {displayValue} {currency}
</div>
);
},
@@ -182,6 +220,57 @@ export function getRfqDetailColumns({
size: 140,
},
{
+ accessorKey: "quotationAttachments",
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="첨부파일" />
+ ),
+ cell: ({ row }) => {
+ const attachments = row.original.quotationAttachments || [];
+ const attachmentCount = attachments.length;
+
+ if (attachmentCount === 0) {
+ return <div className="text-muted-foreground">-</div>;
+ }
+
+ return (
+ <Button
+ variant="ghost"
+ size="sm"
+ className="relative h-8 w-8 p-0 group"
+ onClick={() => {
+ // 견적서 첨부파일 sheet 열기
+ if (openQuotationAttachmentsSheet) {
+ const quotation = row.original;
+ openQuotationAttachmentsSheet(quotation.id, {
+ id: quotation.id,
+ quotationCode: quotation.quotationCode || null,
+ vendorName: quotation.vendorName || undefined,
+ rfqCode: quotation.rfqCode || undefined,
+ });
+ }
+ }}
+ title={
+ attachmentCount === 1
+ ? `${attachments[0].fileName} (${(attachments[0].fileSize / 1024 / 1024).toFixed(2)} MB)`
+ : `${attachmentCount}개의 첨부파일:\n${attachments.map(att => att.fileName).join('\n')}`
+ }
+ >
+ <Paperclip className="h-4 w-4 text-muted-foreground group-hover:text-primary transition-colors" />
+ {attachmentCount > 0 && (
+ <span className="pointer-events-none absolute -top-1 -right-1 inline-flex h-4 min-w-[1rem] items-center justify-center rounded-full bg-primary px-1 text-[0.625rem] font-medium leading-none text-primary-foreground">
+ {attachmentCount}
+ </span>
+ )}
+ </Button>
+ );
+ },
+ meta: {
+ excelHeader: "첨부파일"
+ },
+ enableResizing: false,
+ size: 80,
+ },
+ {
accessorKey: "currency",
header: ({ column }) => (
<DataTableColumnHeaderSimple column={column} title="통화" />