feat(WEB): 리스트 페이지 UI 레이아웃 표준화

- 공통 레이아웃 패턴 적용: [달력] → [프리셋] → [검색창] → [버튼들]
- beforeTableContent → headerActions + createButton 마이그레이션
- DateRangeSelector extraActions prop 활용하여 검색창 통합
- PricingListClient 테이블 행 클릭 → 상세 이동 기능 추가
- 회계 관련 페이지 (입금/출금/매입/매출/어음/카드/예상지출 등) 정리
- 건설 관련 페이지 검색 영역 정리
- 부모 메뉴 리다이렉트 컴포넌트 추가

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
유병철
2026-01-26 22:04:36 +09:00
parent ff93ab7fa2
commit 1f6b592b9f
65 changed files with 1974 additions and 503 deletions

View File

@@ -22,8 +22,10 @@ import {
Pencil,
Save,
Trash2,
Search,
} from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Checkbox } from '@/components/ui/checkbox';
import { Badge } from '@/components/ui/badge';
import { Switch } from '@/components/ui/switch';
@@ -85,6 +87,7 @@ export function PurchaseManagement() {
const [endDate, setEndDate] = useState('2025-12-31');
const [purchaseData, setPurchaseData] = useState<PurchaseRecord[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [searchQuery, setSearchQuery] = useState('');
// 통합 필터 상태 (filterConfig 기반)
const [filterValues, setFilterValues] = useState<Record<string, string | string[]>>({
@@ -295,7 +298,17 @@ export function PurchaseManagement() {
// 커스텀 필터 함수 (filterValues 파라미터 사용)
customFilterFn: (items, fv) => {
if (!items || items.length === 0) return items;
return items.filter((item) => {
// 검색어 필터
if (searchQuery) {
const search = searchQuery.toLowerCase();
const matchesSearch =
item.purchaseNo.toLowerCase().includes(search) ||
item.vendorName.toLowerCase().includes(search);
if (!matchesSearch) return false;
}
const vendorVal = fv.vendor as string;
const purchaseTypeVal = fv.purchaseType as string;
const issuanceVal = fv.issuance as string;
@@ -336,15 +349,45 @@ export function PurchaseManagement() {
return sorted;
},
// 검색창 (공통 컴포넌트에서 자동 생성)
hideSearch: true,
searchValue: searchQuery,
onSearchChange: setSearchQuery,
searchPlaceholder: '매입번호, 거래처명 검색...',
// 공통 헤더 옵션
dateRangeSelector: {
enabled: true,
showPresets: true,
startDate,
endDate,
onStartDateChange: setStartDate,
onEndDateChange: setEndDate,
},
// 헤더 액션: 계정과목명 Select + 저장 버튼
headerActions: ({ selectedItems }) => (
<div className="flex items-center gap-2">
<span className="text-sm font-medium text-gray-700 whitespace-nowrap"></span>
<Select value={selectedAccountSubject} onValueChange={setSelectedAccountSubject}>
<SelectTrigger className="w-[120px]">
<SelectValue placeholder="선택" />
</SelectTrigger>
<SelectContent>
{ACCOUNT_SUBJECT_SELECTOR_OPTIONS.map((option) => (
<SelectItem key={option.value} value={option.value}>
{option.label}
</SelectItem>
))}
</SelectContent>
</Select>
<Button onClick={() => handleSaveAccountSubject(selectedItems)} size="sm">
<Save className="h-4 w-4 mr-1" />
</Button>
</div>
),
// 통합 필터 시스템 (PC: 인라인, 모바일: 바텀시트 자동 분기)
filterConfig,
initialFilters: filterValues,
@@ -358,29 +401,6 @@ export function PurchaseManagement() {
{ label: '세금계산서 수취 미확인', value: `${stats.taxInvoicePendingCount}`, icon: Receipt, iconColor: 'text-red-500' },
],
// beforeTableContent: 계정과목명 Select + 저장 버튼 (테이블 밖에 위치)
beforeTableContent: ({ selectedItems }) => (
<div className="flex items-center gap-2">
<span className="text-sm font-medium text-gray-700"></span>
<Select value={selectedAccountSubject} onValueChange={setSelectedAccountSubject}>
<SelectTrigger className="w-[150px]">
<SelectValue placeholder="계정과목명 선택" />
</SelectTrigger>
<SelectContent>
{ACCOUNT_SUBJECT_SELECTOR_OPTIONS.map((option) => (
<SelectItem key={option.value} value={option.value}>
{option.label}
</SelectItem>
))}
</SelectContent>
</Select>
<Button onClick={() => handleSaveAccountSubject(selectedItems)} className="bg-blue-500 hover:bg-blue-600">
<Save className="h-4 w-4 mr-2" />
</Button>
</div>
),
// 테이블 하단 합계 행
tableFooter: (
<TableRow className="bg-muted/50 font-medium">
@@ -532,6 +552,7 @@ export function PurchaseManagement() {
filterValues,
selectedAccountSubject,
tableTotals,
searchQuery,
handleRowClick,
handleEdit,
handleTaxInvoiceToggle,