"use client"; // 구매관리 > 견적요청서관리 — wace salesMng/quotationRequestList.jsp 1:1 // 검색: 년도 / 프로젝트번호 / 견적요청서No / 공급업체 / 메일발송 / 작성자 / 제품구분 // 그리드: 13컬럼 (견적번호 / 요청번호 / 구매유형 / 프로젝트번호 / 주문유형 / 제품구분 / 품번 / 품명 / 공급업체 / 견적요청서(파일) / 메일발송 / 수신견적서 / 작성자) // 액션: 메일발송 / 삭제 / 조회 import React, { useCallback, useEffect, useMemo, useState } from "react"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; import { Mail, Trash2 } from "lucide-react"; import { toast } from "sonner"; import { DataGrid, DataGridColumn } from "@/components/common/DataGrid"; import { SmartSelect, SmartSelectOption } from "@/components/common/SmartSelect"; import { CompactFilterBar, CompactFilterField } from "@/components/common/CompactFilterBar"; import { PageHeader } from "@/components/common/PageHeader"; import { apiClient } from "@/lib/api/client"; import { purchaseApi, PurchaseListFilter, OptionItem, getYearOptions } from "@/lib/api/purchase"; import { exportToExcel } from "@/lib/utils/excelExport"; const PARENT_PRODUCT = "0000001"; const MAIL_SEND_OPTS: SmartSelectOption[] = [ { code: "N", label: "미발송" }, { code: "Y", label: "발송" }, ]; const EMPTY_FILTER: PurchaseListFilter = { year: String(new Date().getFullYear()), project_no: "", proposal_no: "", partner_objid: "", mail_send_yn: "", writer: "", product_cd: "", page: 1, page_size: 50, }; export default function QuoteRequestPage() { const [rows, setRows] = useState([]); const [total, setTotal] = useState(0); const [loading, setLoading] = useState(false); const [filter, setFilter] = useState(EMPTY_FILTER); const [checkedIds, setCheckedIds] = useState([]); const [productOpts, setProductOpts] = useState([]); const [supplierOpts, setSupplierOpts] = useState([]); const [userOpts, setUserOpts] = useState([]); const yearOpts = useMemo(() => getYearOptions(), []); const fetchList = useCallback(async (override?: Partial) => { setLoading(true); try { const f = { ...filter, ...override }; const res = await purchaseApi.listQuotationRequest(f); setRows(res.rows ?? []); setTotal(res.totalCount ?? 0); } catch (e: any) { toast.error(e?.response?.data?.message ?? e?.message ?? "조회 실패"); } finally { setLoading(false); } }, [filter]); useEffect(() => { let dead = false; (async () => { try { const [p, s, u] = await Promise.all([ apiClient.get(`/sales/codes/${PARENT_PRODUCT}`), purchaseApi.listVendors(), purchaseApi.listUsers(), ]); if (dead) return; setProductOpts(p.data?.data ?? []); setSupplierOpts(s); setUserOpts(u); } catch { /* skip */ } })(); fetchList(EMPTY_FILTER); return () => { dead = true; }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const gridRows = useMemo(() => rows.map((r, i) => ({ ...r, id: r.objid ?? `q_${i}` })), [rows]); const GRID_COLUMNS: DataGridColumn[] = useMemo(() => ([ { key: "quotation_request_no", label: "견적번호", width: "w-[140px]", align: "center" }, { key: "request_mng_no", label: "요청번호", width: "w-[140px]", align: "center" }, { key: "purchase_type_name", label: "구매유형", width: "w-[115px]", align: "center" }, { key: "project_number", label: "프로젝트번호", width: "w-[140px]", align: "center" }, { key: "order_type_name", label: "주문유형", width: "w-[115px]", align: "center" }, { key: "product_name_title", label: "제품구분", width: "w-[115px]", align: "center" }, { key: "part_no", label: "품번", width: "w-[150px]" }, { key: "part_name", label: "품명", minWidth: "min-w-[180px]" }, { key: "vendor_name", label: "공급업체", minWidth: "min-w-[150px]" }, { key: "quotation_file", label: "견적요청서", width: "w-[115px]", align: "center", renderType: "clip" }, { key: "mail_send_date_title", label: "메일발송", width: "w-[125px]", align: "center" }, { key: "attach_file_cnt", label: "수신견적서", width: "w-[115px]", align: "center" }, { key: "writer_name", label: "작성자", width: "w-[115px]", align: "center" }, ]), []); const summary = useMemo(() => [ { label: "전체 건수", value: total.toLocaleString(), suffix: "건" }, { label: "선택", value: checkedIds.length.toLocaleString(), suffix: "건" }, ], [total, checkedIds]); const handleSearch = () => { setFilter(f => ({ ...f, page: 1 })); fetchList({ page: 1 }); }; const handleReset = () => { setFilter(EMPTY_FILTER); fetchList(EMPTY_FILTER); }; return (
} /> 총 {total.toLocaleString()}건}> setFilter({ ...filter, year: v })} /> setFilter({ ...filter, project_no: e.target.value })} /> setFilter({ ...filter, proposal_no: e.target.value })} /> setFilter({ ...filter, partner_objid: v })} /> setFilter({ ...filter, mail_send_yn: v })} /> setFilter({ ...filter, writer: v })} /> setFilter({ ...filter, product_cd: v })} /> { setFilter(f => ({ ...f, page: p })); fetchList({ page: p }); }} onPageSizeChange={(n) => { setFilter(f => ({ ...f, page: 1, page_size: n })); fetchList({ page: 1, page_size: n }); }} showColumnSettings summaryStats={summary} onRefresh={() => fetchList()} onDownload={() => { if (gridRows.length === 0) { toast.info("내보낼 데이터가 없습니다."); return; } const exportRows = gridRows.map((r: any) => { const out: Record = {}; GRID_COLUMNS.forEach((c) => { out[c.label] = r[c.key] ?? ""; }); return out; }); exportToExcel(exportRows, "견적요청서관리.xlsx", "견적요청서"); }} showChart />
); }