"use client"; import { useState, useCallback, useEffect } from "react"; import { DataGrid, type GridColumn } from "@/components/grid/data-grid"; import { SearchForm, SearchField } from "@/components/layout/search-form"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; import { SearchableSelect } from "@/components/ui/searchable-select"; import { FolderCell } from "@/components/ui/folder-cell"; import * as XLSX from "xlsx"; import Swal from "sweetalert2"; // 제품관리_PART 및 구조등록 (원본: partMng/structureList.jsp) export default function BomRegisterPage() { const [customerCd, setCustomerCd] = useState(""); const [projectName, setProjectName] = useState(""); const [unitCode, setUnitCode] = useState(""); const [searchUnitName, setSearchUnitName] = useState(""); const [searchWriter, setSearchWriter] = useState(""); const [deployFrom, setDeployFrom] = useState(""); const [deployTo, setDeployTo] = useState(""); const [status, setStatus] = useState(""); const [data, setData] = useState[]>([]); const [loading, setLoading] = useState(false); const [selectedRows, setSelectedRows] = useState[]>([]); const [customers, setCustomers] = useState<{ value: string; label: string }[]>([]); const [projects, setProjects] = useState<{ value: string; label: string }[]>([]); const [units, setUnits] = useState<{ value: string; label: string }[]>([]); const [users, setUsers] = useState<{ value: string; label: string }[]>([]); // 고객사 목록 (supply_mng) useEffect(() => { fetch("/api/common/supply-list", { method: "POST", headers: { "Content-Type": "application/json" }, body: "{}", }).then((r) => r.json()) .then((j) => setCustomers((j.RESULTLIST || []).map((r: Record) => ({ value: String(r.OBJID), label: String(r.SUPPLY_NAME || r.OBJID), })))) .catch(() => {}); }, []); useEffect(() => { fetch("/api/admin/users", { method: "POST", headers: { "Content-Type": "application/json" }, body: "{}" }) .then((r) => r.json()) .then((j) => setUsers((j.RESULTLIST || []).map((r: Record) => ({ value: String(r.USER_ID), label: String(r.USER_NAME || ""), })))) .catch(() => {}); }, []); // 고객사 변경 시 프로젝트 로드 useEffect(() => { setProjectName(""); setUnitCode(""); fetch("/api/common/project-list", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ customer_cd: customerCd }), }).then((r) => r.json()) .then((j) => setProjects((j.RESULTLIST || []).map((r: Record) => ({ value: String(r.OBJID), label: String(r.LABEL || r.PROJECT_NO || r.OBJID), })))) .catch(() => {}); }, [customerCd]); // 프로젝트 변경 시 유닛 로드 useEffect(() => { setUnitCode(""); if (!projectName) { setUnits([]); return; } fetch("/api/common/unit-list", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ contract_objid: projectName }), }).then((r) => r.json()) .then((j) => setUnits((j.RESULTLIST || []).map((r: Record) => ({ value: String(r.OBJID), label: String(r.UNIT_NAME || r.TASK_NAME), })))) .catch(() => {}); }, [projectName]); const openChangeDesignNote = (objIds: string) => { const w = 1000, h = 200; const left = (window.screen.width - w) / 2; const top = (window.screen.height - h) / 2; window.open( `/product/popup/change-design-note?objId=${encodeURIComponent(objIds)}`, "changeDesignNotePopUp", `width=${w},height=${h},left=${left},top=${top}`, ); }; const openStructureDetail = (objId: string) => { window.open( `/product/popup/set-structure?objId=${encodeURIComponent(objId)}`, "setStructurePopup", "width=1880,height=900,resizable=yes,scrollbars=yes", ); }; const columns: GridColumn[] = [ { title: "프로젝트번호", field: "PROJECT_NO", width: 120, hozAlign: "left" }, { title: "고객사", field: "CUSTOMER_NAME", width: 140, hozAlign: "left" }, { title: "고객사프로젝트명", field: "CUSTOMER_PROJECT_NAME", width: 200, hozAlign: "left" }, { title: "유닛명", field: "UNIT_NAME", width: 270, hozAlign: "left" }, { title: "E-BOM", field: "BOM_CNT", width: 80, hozAlign: "center", formatter: (cell) => , cellClick: (row) => openStructureDetail(String(row.OBJID)), }, { title: "등록자", field: "DEPT_USER_NAME", width: 120, hozAlign: "center" }, { title: "등록일", field: "REG_DATE", width: 100, hozAlign: "center" }, { title: "배포일", field: "DEPLOY_DATE", width: 100, hozAlign: "center" }, { title: "Version", field: "REVISION", width: 85, hozAlign: "center" }, { title: "배포사유", field: "NOTE", hozAlign: "left" }, { title: "상태", field: "STATUS_TITLE", width: 100, hozAlign: "center" }, ]; const fetchData = useCallback(async () => { setLoading(true); try { const res = await fetch("/api/product/bom", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ mode: "structure", customer_cd: customerCd, project_name: projectName, unit_code: unitCode, SEARCH_UNIT_NAME: searchUnitName, SEARCH_WRITER: searchWriter, SEARCH_DEPLOY_DATE_FROM: deployFrom, SEARCH_DEPLOY_DATE_TO: deployTo, status, }), }); if (res.ok) { const j = await res.json(); setData(j.RESULTLIST || []); } } finally { setLoading(false); } }, [customerCd, projectName, unitCode, searchUnitName, searchWriter, deployFrom, deployTo, status]); useEffect(() => { fetchData(); }, [fetchData]); const handleDeploy = async () => { if (selectedRows.length === 0) { Swal.fire("알림", "선택된 내용이 없습니다.", "warning"); return; } const isDeployed = selectedRows.some((r) => r.STATUS === "deploy"); if (isDeployed) { Swal.fire("알림", "배포완료건은 배포 할 수 없습니다.", "warning"); return; } // 동시배포 체크 (MULTI_MASTER_OBJID 동일해야 동시배포 가능) if (selectedRows.length > 1) { let prevMaster = ""; let onlyMulti = true; for (const r of selectedRows) { const master = String(r.MULTI_MASTER_OBJID || r.OBJID); if (!prevMaster || master === prevMaster) prevMaster = master; else { onlyMulti = false; break; } } if (!onlyMulti) { Swal.fire("알림", "한번에 한개의 배포만 가능합니다.(동시 프로젝트 등록중인 건만 동시배포 가능합니다.)", "warning"); return; } } const c = await Swal.fire({ title: "선택된 내용을 배포하시겠습니까?", icon: "warning", showCancelButton: true, confirmButtonText: "확인", cancelButtonText: "취소", }); if (!c.isConfirmed) return; openChangeDesignNote(selectedRows.map((r) => String(r.OBJID)).join(",")); }; const handleDelete = async () => { if (selectedRows.length === 0) { Swal.fire("알림", "선택된 내용이 없습니다.", "warning"); return; } const blocked = selectedRows.some((r) => r.STATUS === "deploy" || r.STATUS === "changeDesign"); if (blocked) { Swal.fire("알림", "배포완료/설계변경미배포 건은 삭제 할 수 없습니다.", "warning"); return; } const c = await Swal.fire({ title: "선택한 정보를 삭제하시겠습니까?", icon: "warning", showCancelButton: true, confirmButtonText: "확인", cancelButtonText: "취소", }); if (!c.isConfirmed) return; const res = await fetch("/api/product/bom/structure-delete", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ objIds: selectedRows.map((r) => String(r.OBJID)) }), }); const j = await res.json(); if (j.success) { await Swal.fire({ icon: "success", title: j.message, timer: 1200, showConfirmButton: false }); fetchData(); } else { Swal.fire("오류", j.message, "error"); } }; const handleExcelDownload = () => { if (data.length === 0) { Swal.fire("알림", "다운로드할 데이터가 없습니다.", "warning"); return; } const header = [ "프로젝트번호", "고객사", "고객사프로젝트명", "유닛명", "E-BOM", "등록자", "등록일", "배포일", "Version", "배포사유", "상태", ]; const body = data.map((r) => [ r.PROJECT_NO ?? "", r.CUSTOMER_NAME ?? "", r.CUSTOMER_PROJECT_NAME ?? "", r.UNIT_NAME ?? "", Number(r.BOM_CNT ?? 0), r.DEPT_USER_NAME ?? "", r.REG_DATE ?? "", r.DEPLOY_DATE ?? "", r.REVISION ?? "", r.NOTE ?? "", r.STATUS_TITLE ?? "", ]); const ws = XLSX.utils.aoa_to_sheet([header, ...body]); const wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, "PART 및 구조등록"); const today = new Date().toISOString().slice(0, 10); XLSX.writeFile(wb, `PART_및_구조등록_${today}.xlsx`); }; const handleSaveExcel = () => { if (selectedRows.length > 1) { Swal.fire("알림", "단건만 등록 가능합니다.", "warning"); return; } if (selectedRows.length === 1) { const r = selectedRows[0]; if (String(r.STATUS || "") !== "create") { Swal.fire("알림", "등록중인 건만 등록/추가 할 수 있습니다.", "warning"); return; } const qs = new URLSearchParams({ customer_cd: String(r.CUSTOMER_OBJID || ""), project_name: String(r.CONTRACT_OBJID || ""), unit_code: String(r.UNIT_CODE || ""), BOM_REPORT_OBJID: String(r.OBJID || ""), }).toString(); window.open(`/product/popup/bom-excel-import?${qs}`, "openBomReportExcelImportPopUp", "width=1920,height=860,resizable=yes,scrollbars=yes"); return; } if (!customerCd) { Swal.fire("알림", "고객사를 선택해 주세요.", "warning"); return; } if (!projectName) { Swal.fire("알림", "프로젝트를 선택해 주세요.", "warning"); return; } if (!unitCode) { Swal.fire("알림", "유닛명을 선택해 주세요.", "warning"); return; } const qs = new URLSearchParams({ customer_cd: customerCd, project_name: projectName, unit_code: unitCode, }).toString(); window.open(`/product/popup/bom-excel-import?${qs}`, "openBomReportExcelImportPopUp", "width=1920,height=860,resizable=yes,scrollbars=yes"); }; return (

제품관리_PART 및 구조등록

setSearchUnitName(e.target.value)} className="w-[140px]" />
setDeployFrom(e.target.value)} className="w-[140px]" /> ~ setDeployTo(e.target.value)} className="w-[140px]" />
); }