summaryrefslogtreecommitdiff
path: root/lib/rfq-last
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rfq-last')
-rw-r--r--lib/rfq-last/service.ts82
-rw-r--r--lib/rfq-last/table/rfq-table.tsx29
2 files changed, 95 insertions, 16 deletions
diff --git a/lib/rfq-last/service.ts b/lib/rfq-last/service.ts
index 2c1aa2ca..461a635a 100644
--- a/lib/rfq-last/service.ts
+++ b/lib/rfq-last/service.ts
@@ -3,7 +3,7 @@
import { revalidatePath, unstable_cache, unstable_noStore } from "next/cache";
import db from "@/db/db";
-import { avlVendorInfo, paymentTerms, incoterms, rfqLastVendorQuotationItems, rfqLastVendorAttachments, rfqLastVendorResponses, RfqsLastView, rfqLastAttachmentRevisions, rfqLastAttachments, rfqsLast, rfqsLastView, users, rfqPrItems, prItemsLastView, vendors, rfqLastDetails, rfqLastVendorResponseHistory, rfqLastDetailsView, vendorContacts, projects, basicContract, basicContractTemplates, rfqLastTbeSessions, rfqLastTbeDocumentReviews, templateDetailView, RfqStatus } from "@/db/schema";
+import { avlVendorInfo, paymentTerms, incoterms, rfqLastVendorQuotationItems, rfqLastVendorAttachments, rfqLastVendorResponses, RfqsLastView, rfqLastAttachmentRevisions, rfqLastAttachments, rfqsLast, rfqsLastView, users, rfqPrItems, prItemsLastView, vendors, rfqLastDetails, rfqLastVendorResponseHistory, rfqLastDetailsView, vendorContacts, projects, basicContract, basicContractTemplates, rfqLastTbeSessions, rfqLastTbeDocumentReviews, templateDetailView, RfqStatus, purchaseRequests } from "@/db/schema";
import { sql, and, desc, asc, like, ilike, or, eq, SQL, count, gte, lte, isNotNull, ne, inArray } from "drizzle-orm";
import { filterColumns } from "@/lib/filter-columns";
import { GetRfqLastAttachmentsSchema, GetRfqsSchema } from "./validations";
@@ -135,9 +135,25 @@ export async function getRfqs(input: GetRfqsSchema) {
console.log("총 데이터 수:", total);
- // 6. 정렬 및 페이징 처리
- const orderByColumns = input.sort.map((sort) => {
+ // 6. 정렬 및 페이징 처리 (NULL 값 처리 포함)
+ // classNo는 별도로 처리하므로 제외
+ const validSorts = input.sort.filter((sort) => sort.id !== 'classNo');
+
+ const orderByColumns = validSorts.map((sort) => {
const column = sort.id as keyof typeof rfqsLastView.$inferSelect;
+
+ // NULL 값이 있을 수 있는 컬럼들 (NULLS LAST 처리)
+ const nullableColumns = ['rfqTitle', 'majorItemMaterialDescription', 'itemCode', 'projectName', 'packageName'];
+
+ if (nullableColumns.includes(sort.id)) {
+ // NULL 값은 마지막에 정렬 (NULLS LAST)
+ // drizzle에서 컬럼을 직접 참조하여 SQL 템플릿 사용
+ const colRef = rfqsLastView[column];
+ return sort.desc
+ ? sql`${colRef} DESC NULLS LAST`
+ : sql`${colRef} ASC NULLS LAST`;
+ }
+
return sort.desc
? desc(rfqsLastView[column])
: asc(rfqsLastView[column]);
@@ -147,13 +163,59 @@ export async function getRfqs(input: GetRfqsSchema) {
orderByColumns.push(desc(rfqsLastView.createdAt));
}
- const rfqData = await db
- .select()
- .from(rfqsLastView)
- .where(finalWhere)
- .orderBy(...orderByColumns)
- .limit(input.perPage)
- .offset(offset);
+ // classNo 정렬이 있는 경우 서브쿼리로 purchaseRequests에서 classNo 가져오기
+ const hasClassNoSort = input.sort.some(s => s.id === 'classNo');
+
+ let rfqData;
+ try {
+ if (hasClassNoSort) {
+ // classNo 정렬이 있는 경우 서브쿼리로 첫 번째 purchaseRequests의 classNo 가져오기
+ const classNoOrderBy = input.sort
+ .filter(s => s.id === 'classNo')
+ .map(s => {
+ // 서브쿼리로 purchaseRequests에서 첫 번째 classNo 가져오기 (NULLS LAST 처리)
+ // 외부 쿼리의 rfqs_last_view.id를 참조하기 위해 correlation 사용
+ return s.desc
+ ? sql<string | null>`(SELECT class_no FROM purchase_requests WHERE rfq_id = rfqs_last_view.id ORDER BY id LIMIT 1) DESC NULLS LAST`
+ : sql<string | null>`(SELECT class_no FROM purchase_requests WHERE rfq_id = rfqs_last_view.id ORDER BY id LIMIT 1) ASC NULLS LAST`;
+ });
+
+ // classNo 정렬을 먼저 적용하고 나머지 정렬을 추가
+ const finalOrderBy = [...classNoOrderBy, ...orderByColumns];
+
+ console.log('=== classNo 정렬 실행 (서브쿼리) ===', {
+ hasClassNoSort,
+ classNoOrderByCount: classNoOrderBy.length,
+ finalOrderByCount: finalOrderBy.length
+ });
+
+ rfqData = await db
+ .select()
+ .from(rfqsLastView)
+ .where(finalWhere)
+ .orderBy(...finalOrderBy)
+ .limit(input.perPage)
+ .offset(offset);
+ } else {
+ rfqData = await db
+ .select()
+ .from(rfqsLastView)
+ .where(finalWhere)
+ .orderBy(...orderByColumns)
+ .limit(input.perPage)
+ .offset(offset);
+ }
+ } catch (orderError) {
+ console.error('정렬 오류:', orderError);
+ // 정렬 오류 발생 시 기본 정렬로 대체
+ rfqData = await db
+ .select()
+ .from(rfqsLastView)
+ .where(finalWhere)
+ .orderBy(desc(rfqsLastView.createdAt))
+ .limit(input.perPage)
+ .offset(offset);
+ }
const pageCount = Math.ceil(total / input.perPage);
diff --git a/lib/rfq-last/table/rfq-table.tsx b/lib/rfq-last/table/rfq-table.tsx
index 9f78f578..162dd343 100644
--- a/lib/rfq-last/table/rfq-table.tsx
+++ b/lib/rfq-last/table/rfq-table.tsx
@@ -215,6 +215,9 @@ export function RfqTable({
expandedRows: []
}), [getSearchParam, parseSearchParam]);
+ // 탭별로 독립적인 tableId 사용 (정렬 상태 분리)
+ const tableId = React.useMemo(() => `rfq-table-${rfqCategory}`, [rfqCategory]);
+
const {
presets,
activePresetId,
@@ -227,7 +230,7 @@ export function RfqTable({
setDefaultPreset,
renamePreset,
getCurrentSettings,
- } = useTablePresets<RfqsLastView>('rfq-table', initialSettings);
+ } = useTablePresets<RfqsLastView>(tableId, initialSettings);
// 컬럼 정의
const columns = React.useMemo(() => {
@@ -305,11 +308,25 @@ export function RfqTable({
const currentSettings = React.useMemo(() => getCurrentSettings(), [getCurrentSettings]);
- const initialState = React.useMemo(() => ({
- sorting: initialSettings.sort.filter((s: any) => columns.some((c: any) => ("accessorKey" in c ? c.accessorKey : c.id) === s.id)),
- columnVisibility: currentSettings.columnVisibility,
- columnPinning: currentSettings.pinnedColumns,
- }), [columns, currentSettings, initialSettings.sort]);
+ // 탭별로 독립적인 정렬 상태 관리
+ // rfqCategory가 변경되면 정렬 상태를 재계산하여 탭 간 정렬 충돌 방지
+ const initialState = React.useMemo(() => {
+ // 현재 탭의 컬럼에 존재하는 정렬만 유효한 것으로 필터링
+ const validSorting = initialSettings.sort.filter((s: any) =>
+ columns.some((c: any) => ("accessorKey" in c ? c.accessorKey : c.id) === s.id)
+ );
+
+ // 유효한 정렬이 없으면 기본 정렬 사용
+ const sorting = validSorting.length > 0
+ ? validSorting
+ : [{ id: "createdAt", desc: true }];
+
+ return {
+ sorting,
+ columnVisibility: currentSettings.columnVisibility,
+ columnPinning: currentSettings.pinnedColumns,
+ };
+ }, [columns, currentSettings, initialSettings.sort, rfqCategory]);
const { table } = useDataTable({
data: tableData.data,