diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-08-06 04:23:40 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-08-06 04:23:40 +0000 |
| commit | de2ac5a2860bc25180971e7a11f852d9d44675b7 (patch) | |
| tree | b931c363f2cb19e177a0a7b17190d5de2a82d709 /lib/techsales-rfq | |
| parent | 6c549b0f264e9be4d60af38f9efc05b189d6849f (diff) | |
(대표님) 정기평가, 법적검토, 정책, 가입관련 처리 및 관련 컴포넌트 추가, 메뉴 변경
Diffstat (limited to 'lib/techsales-rfq')
| -rw-r--r-- | lib/techsales-rfq/service.ts | 83 | ||||
| -rw-r--r-- | lib/techsales-rfq/table/detail-table/rfq-detail-column.tsx | 8 |
2 files changed, 64 insertions, 27 deletions
diff --git a/lib/techsales-rfq/service.ts b/lib/techsales-rfq/service.ts index 348d31ff..0d00a4e2 100644 --- a/lib/techsales-rfq/service.ts +++ b/lib/techsales-rfq/service.ts @@ -37,6 +37,14 @@ import { itemShipbuilding, itemOffshoreTop, itemOffshoreHull } from "@/db/schema import { techVendors, techVendorPossibleItems, techVendorContacts } from "@/db/schema/techVendors";
import { deleteFile, saveDRMFile, saveFile } from "@/lib/file-stroage";
import { decryptWithServerAction } from "@/components/drm/drmUtils";
+// RFQ 아이템 정보 타입
+interface RfqItemInfo {
+ itemCode: string;
+ workType: string;
+ itemList: string;
+ subItemList: string;
+ shipTypes: string;
+}
// 정렬 타입 정의
// 의도적으로 any 사용 - drizzle ORM의 orderBy 타입이 복잡함
@@ -3555,7 +3563,6 @@ export async function getAcceptedTechSalesVendorQuotations(input: { try {
const offset = (input.page - 1) * input.perPage;
- // 기본 WHERE 조건: status = 'Accepted'만 조회, rfqType이 'SHIP'이 아닌 것만
const baseConditions = [or(
eq(techSalesVendorQuotations.status, 'Submitted'),
eq(techSalesVendorQuotations.status, 'Accepted')
@@ -3664,11 +3671,16 @@ export async function getAcceptedTechSalesVendorQuotations(input: { vendorCode: sql<string | null>`vendors.vendor_code`,
vendorEmail: sql<string | null>`vendors.email`,
vendorCountry: sql<string | null>`vendors.country`,
+ vendorFlags: techSalesVendorQuotations.vendorFlags, // 벤더 플래그 (JSON)
// Project 정보
projNm: biddingProjects.projNm,
pspid: biddingProjects.pspid,
sector: biddingProjects.sector,
+ kunnrNm: biddingProjects.kunnrNm, // 선주명
+ ptype: biddingProjects.ptype, // 선종코드
+ ptypeNm: biddingProjects.ptypeNm, // 선종명
+ pjtType: biddingProjects.pjtType, // 프로젝트 타입
})
.from(techSalesVendorQuotations)
.leftJoin(techSalesRfqs, eq(techSalesVendorQuotations.rfqId, techSalesRfqs.id))
@@ -3758,36 +3770,61 @@ export async function getAcceptedTechSalesVendorQuotations(input: { });
}
- // 각 RFQ-벤더 조합에 대해 아이템별로 별도 행 생성
+ // 아이템별 벤더 순서로 데이터 확장
const expandedData: any[] = [];
+ // RFQ별로 아이템을 그룹화
+ const rfqItemsByRfq = new Map();
data.forEach(item => {
const rfqItems = rfqItemsMap.get(item.rfqId) || [];
+ if (!rfqItemsByRfq.has(item.rfqId)) {
+ rfqItemsByRfq.set(item.rfqId, []);
+ }
+ rfqItemsByRfq.get(item.rfqId).push({
+ ...item,
+ rfqItems: rfqItems,
+ vendorQuotation: item
+ });
+ });
+
+ // 각 RFQ의 아이템별로 벤더별 행 생성
+ rfqItemsByRfq.forEach((vendorQuotations) => {
+ const firstQuotation = vendorQuotations[0];
+ const rfqItems = firstQuotation.rfqItems;
if (rfqItems.length === 0) {
- // 아이템이 없는 경우 기본 행 하나만 추가
- expandedData.push({
- ...item,
- rfqItems: [],
- itemIndex: 0,
- totalItems: 0,
- isExpanded: false,
+ // 아이템이 없는 경우 각 벤더별로 행 생성
+ vendorQuotations.forEach((quotation) => {
+ expandedData.push({
+ ...quotation.vendorQuotation,
+ rfqItems: [],
+ itemIndex: 0,
+ totalItems: 0,
+ isExpanded: false,
+ itemCode: '',
+ workType: '',
+ itemList: '',
+ subItemList: '',
+ shipTypes: '',
+ });
});
} else {
- // 각 아이템별로 별도 행 생성
- rfqItems.forEach((rfqItem, index) => {
- expandedData.push({
- ...item,
- rfqItems: [rfqItem], // 단일 아이템만 포함
- itemIndex: index,
- totalItems: rfqItems.length,
- isExpanded: index === 0, // 첫 번째 아이템만 확장된 것으로 표시
- // 아이템 정보를 직접 포함
- itemCode: rfqItem.itemCode,
- workType: rfqItem.workType,
- itemList: rfqItem.itemList,
- subItemList: rfqItem.subItemList,
- shipTypes: rfqItem.shipTypes,
+ // 각 아이템별로 벤더별 행 생성
+ rfqItems.forEach((rfqItem: RfqItemInfo, itemIndex: number) => {
+ vendorQuotations.forEach((quotation: { vendorQuotation: any; rfqItems: RfqItemInfo[] }, vendorIndex: number) => {
+ expandedData.push({
+ ...quotation.vendorQuotation,
+ rfqItems: [rfqItem], // 단일 아이템만 포함
+ itemIndex: itemIndex,
+ totalItems: rfqItems.length,
+ isExpanded: vendorIndex === 0, // 첫 번째 벤더만 확장된 것으로 표시
+ // 아이템 정보를 직접 포함
+ itemCode: rfqItem.itemCode,
+ workType: rfqItem.workType,
+ itemList: rfqItem.itemList,
+ subItemList: rfqItem.subItemList,
+ shipTypes: rfqItem.shipTypes,
+ });
});
});
}
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 65f11d0e..ded0c116 100644 --- a/lib/techsales-rfq/table/detail-table/rfq-detail-column.tsx +++ b/lib/techsales-rfq/table/detail-table/rfq-detail-column.tsx @@ -212,7 +212,7 @@ export function getRfqDetailColumns({ {
id: "vendorFlags",
header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="벤더 구분자" />
+ <DataTableColumnHeaderSimple column={column} title="벤더 유형" />
),
cell: ({ row }) => {
const vendorFlags = row.original.vendorFlags;
@@ -224,16 +224,16 @@ export function getRfqDetailColumns({ const activeFlags = [];
if (vendorFlags.isCustomerPreferred) {
- activeFlags.push({ key: "isCustomerPreferred", label: "고객(선주) 선호 벤더", variant: "default" as const });
+ activeFlags.push({ key: "isCustomerPreferred", label: "고객(선주) 선호 벤더", variant: "outline" as const });
}
if (vendorFlags.isNewDiscovery) {
- activeFlags.push({ key: "isNewDiscovery", label: "신규 발굴 벤더", variant: "secondary" as const });
+ activeFlags.push({ key: "isNewDiscovery", label: "신규 발굴 벤더", variant: "outline" as const });
}
if (vendorFlags.isProjectApproved) {
activeFlags.push({ key: "isProjectApproved", label: "Project Approved Vendor", variant: "outline" as const });
}
if (vendorFlags.isShiProposal) {
- activeFlags.push({ key: "isShiProposal", label: "SHI Proposal Vendor", variant: "destructive" as const });
+ activeFlags.push({ key: "isShiProposal", label: "SHI Proposal Vendor", variant: "outline" as const });
}
if (activeFlags.length === 0) {
|
