feat(WEB): 견적 시스템 개선, 엑셀 다운로드, PDF 생성 기능 추가
견적 시스템: - QuoteRegistrationV2: 할인 모달, 거래명세서 모달, vatType 필드 추가 - DiscountModal: 할인율/할인금액 상호 계산 모달 - QuoteTransactionModal: 거래명세서 미리보기 모달 - LocationDetailPanel, LocationListPanel 개선 템플릿 기능: - UniversalListPage: 엑셀 다운로드 기능 추가 (전체/선택 다운로드) - DocumentViewer: PDF 생성 기능 개선 신규 API: - /api/pdf/generate: Puppeteer 기반 PDF 생성 엔드포인트 UI 개선: - 입력 컴포넌트 placeholder 스타일 개선 (opacity 50%) - 각종 리스트 컴포넌트 정렬/필터링 개선 패키지 추가: - html2canvas, jspdf, puppeteer, dom-to-image-more Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -17,8 +17,8 @@ import { Badge } from '@/components/ui/badge';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { TableRow, TableCell } from '@/components/ui/table';
|
||||
import { DeleteConfirmDialog } from '@/components/ui/confirm-dialog';
|
||||
import { Search, Plus, Edit, Trash2, Package, Download, FileDown, Upload } from 'lucide-react';
|
||||
import { downloadExcel, downloadSelectedExcel, downloadExcelTemplate, parseExcelFile, type ExcelColumn, type TemplateColumn } from '@/lib/utils/excel-download';
|
||||
import { Search, Plus, Edit, Trash2, Package, FileDown, Upload } from 'lucide-react';
|
||||
import { downloadExcelTemplate, parseExcelFile, type ExcelColumn, type TemplateColumn } from '@/lib/utils/excel-download';
|
||||
import { useItemList } from '@/hooks/useItemList';
|
||||
import { handleApiError } from '@/lib/api/error-handler';
|
||||
import { isNextRedirectError } from '@/lib/utils/redirect-error';
|
||||
@@ -253,34 +253,29 @@ export default function ItemListClient() {
|
||||
{ header: '활성상태', key: 'isActive', width: 10, transform: (v) => v ? '활성' : '비활성' },
|
||||
];
|
||||
|
||||
// 전체 엑셀 다운로드
|
||||
const handleExcelDownload = () => {
|
||||
if (items.length === 0) {
|
||||
alert('다운로드할 데이터가 없습니다.');
|
||||
return;
|
||||
}
|
||||
downloadExcel({
|
||||
data: items,
|
||||
columns: excelColumns,
|
||||
filename: '품목목록',
|
||||
sheetName: '품목',
|
||||
});
|
||||
};
|
||||
|
||||
// 선택 항목 엑셀 다운로드
|
||||
const handleSelectedExcelDownload = (selectedIds: string[]) => {
|
||||
if (selectedIds.length === 0) {
|
||||
alert('선택된 항목이 없습니다.');
|
||||
return;
|
||||
}
|
||||
downloadSelectedExcel({
|
||||
data: items,
|
||||
columns: excelColumns,
|
||||
selectedIds,
|
||||
idField: 'id',
|
||||
filename: '품목목록_선택',
|
||||
sheetName: '품목',
|
||||
});
|
||||
// API 응답을 ItemMaster 타입으로 변환 (엑셀 다운로드용)
|
||||
const mapItemResponse = (result: unknown): ItemMaster[] => {
|
||||
const data = result as { data?: { data?: Record<string, unknown>[] }; };
|
||||
const rawItems = data.data?.data ?? [];
|
||||
return rawItems.map((item: Record<string, unknown>) => ({
|
||||
id: String(item.id ?? item.item_id ?? ''),
|
||||
itemCode: (item.code ?? item.item_code ?? '') as string,
|
||||
itemName: (item.name ?? item.item_name ?? '') as string,
|
||||
itemType: (item.type_code ?? item.item_type ?? '') as ItemMaster['itemType'],
|
||||
partType: item.part_type as ItemMaster['partType'],
|
||||
unit: (item.unit ?? '') as string,
|
||||
specification: (item.specification ?? '') as string,
|
||||
isActive: item.is_active != null ? Boolean(item.is_active) : !item.deleted_at,
|
||||
category1: (item.category1 ?? '') as string,
|
||||
category2: (item.category2 ?? '') as string,
|
||||
category3: (item.category3 ?? '') as string,
|
||||
salesPrice: (item.sales_price ?? 0) as number,
|
||||
purchasePrice: (item.purchase_price ?? 0) as number,
|
||||
currentRevision: (item.current_revision ?? 0) as number,
|
||||
isFinal: Boolean(item.is_final ?? false),
|
||||
createdAt: (item.created_at ?? '') as string,
|
||||
updatedAt: (item.updated_at ?? '') as string,
|
||||
}));
|
||||
};
|
||||
|
||||
// 업로드용 템플릿 컬럼 정의
|
||||
@@ -416,55 +411,31 @@ export default function ItemListClient() {
|
||||
icon: Plus,
|
||||
},
|
||||
|
||||
// 헤더 액션 (엑셀 다운로드)
|
||||
headerActions: ({ selectedItems }) => (
|
||||
<div className="flex items-center gap-2">
|
||||
{/* 양식 다운로드 버튼 - 추후 활성화
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleTemplateDownload}
|
||||
className="gap-2"
|
||||
>
|
||||
<FileDown className="h-4 w-4" />
|
||||
양식 다운로드
|
||||
</Button>
|
||||
*/}
|
||||
{/* 양식 업로드 버튼 - 추후 활성화
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => fileInputRef.current?.click()}
|
||||
className="gap-2"
|
||||
>
|
||||
<Upload className="h-4 w-4" />
|
||||
양식 업로드
|
||||
</Button>
|
||||
*/}
|
||||
{/* 엑셀 데이터 다운로드 버튼 */}
|
||||
{selectedItems.size > 0 ? (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => handleSelectedExcelDownload(Array.from(selectedItems))}
|
||||
className="gap-2"
|
||||
>
|
||||
<Download className="h-4 w-4" />
|
||||
선택 다운로드 ({selectedItems.size})
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleExcelDownload}
|
||||
className="gap-2"
|
||||
>
|
||||
<Download className="h-4 w-4" />
|
||||
엑셀 다운로드
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
// 엑셀 다운로드 설정 (공통 기능)
|
||||
excelDownload: {
|
||||
columns: excelColumns,
|
||||
filename: '품목목록',
|
||||
sheetName: '품목',
|
||||
fetchAllUrl: '/api/proxy/items',
|
||||
fetchAllParams: ({ activeTab }): Record<string, string> => {
|
||||
// 현재 선택된 타입 필터 적용
|
||||
if (activeTab && activeTab !== 'all') {
|
||||
return { type: activeTab };
|
||||
}
|
||||
return { group_id: '1' }; // 품목관리 그룹
|
||||
},
|
||||
mapResponse: mapItemResponse,
|
||||
},
|
||||
|
||||
// 헤더 액션 (양식 다운로드/업로드 - 추후 활성화)
|
||||
// headerActions: () => (
|
||||
// <div className="flex items-center gap-2">
|
||||
// <Button variant="outline" size="sm" onClick={handleTemplateDownload} className="gap-2">
|
||||
// <FileDown className="h-4 w-4" />
|
||||
// 양식 다운로드
|
||||
// </Button>
|
||||
// </div>
|
||||
// ),
|
||||
|
||||
// API 액션 (일괄 삭제 포함)
|
||||
actions: {
|
||||
|
||||
Reference in New Issue
Block a user