refactor(WEB): DataTable 개선 및 회계 상세 컴포넌트 리팩토링

- DataTable 컴포넌트 기능 확장 및 코드 개선
- 회계 상세 컴포넌트(Bill/Deposit/Purchase/Sales/Withdrawal) 리팩토링
- 엑셀 다운로드 유틸리티 개선
- 대시보드 및 각종 리스트 페이지 업데이트
- dashboard_type2 페이지 추가
- 프론트엔드 개선 로드맵 문서 추가

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
유병철
2026-02-11 11:03:19 +09:00
parent 0db6302652
commit e14335b635
33 changed files with 1354 additions and 217 deletions

View File

@@ -22,7 +22,11 @@
* ```
*/
import * as XLSX from 'xlsx';
// xlsx는 ~400KB로 무거워서, 실제 사용 시점에 동적 로드
async function loadXLSX() {
const XLSX = await import('xlsx');
return XLSX;
}
/**
* 엑셀 컬럼 정의
@@ -84,19 +88,21 @@ function generateFilename(baseName: string, appendDate: boolean): string {
/**
* 데이터를 엑셀 파일로 다운로드
*/
export function downloadExcel<T extends Record<string, unknown>>({
export async function downloadExcel<T extends Record<string, unknown>>({
data,
columns,
filename = 'export',
sheetName = 'Sheet1',
appendDate = true,
}: ExcelDownloadOptions<T>): void {
}: ExcelDownloadOptions<T>): Promise<void> {
if (!data || data.length === 0) {
console.warn('[Excel] 다운로드할 데이터가 없습니다.');
return;
}
try {
const XLSX = await loadXLSX();
// 1. 헤더 행 생성
const headers = columns.map((col) => col.header);
@@ -162,7 +168,7 @@ export function downloadExcel<T extends Record<string, unknown>>({
/**
* 선택된 항목만 엑셀로 다운로드
*/
export function downloadSelectedExcel<T extends Record<string, unknown>>({
export async function downloadSelectedExcel<T extends Record<string, unknown>>({
data,
selectedIds,
idField = 'id',
@@ -170,7 +176,7 @@ export function downloadSelectedExcel<T extends Record<string, unknown>>({
}: ExcelDownloadOptions<T> & {
selectedIds: string[];
idField?: keyof T | string;
}): void {
}): Promise<void> {
const selectedData = data.filter((item) => {
const id = getNestedValue(item as Record<string, unknown>, idField as string);
return selectedIds.includes(String(id));
@@ -181,7 +187,7 @@ export function downloadSelectedExcel<T extends Record<string, unknown>>({
return;
}
downloadExcel({
await downloadExcel({
...options,
data: selectedData,
});
@@ -244,14 +250,15 @@ export interface TemplateDownloadOptions {
* });
* ```
*/
export function downloadExcelTemplate({
export async function downloadExcelTemplate({
columns,
filename = '업로드_양식',
sheetName = 'Sheet1',
includeSampleRow = true,
includeGuideRow = true,
}: TemplateDownloadOptions): void {
}: TemplateDownloadOptions): Promise<void> {
try {
const XLSX = await loadXLSX();
const wsData: (string | number | boolean)[][] = [];
// 1. 헤더 행 (필수 표시 포함)
@@ -384,6 +391,7 @@ export async function parseExcelFile<T = Record<string, unknown>>(
}
): Promise<ExcelParseResult<T>> {
const { columns, skipRows = 1, sheetIndex = 0 } = options;
const XLSX = await loadXLSX();
return new Promise((resolve) => {
const reader = new FileReader();