diff --git a/apps/wr/app/ruseFcltMng/prfmncReg/pbnstPrfmncReg/page.tsx b/apps/wr/app/ruseFcltMng/prfmncReg/pbnstPrfmncReg/page.tsx index 6be50a8c5..10dd7ccb6 100644 --- a/apps/wr/app/ruseFcltMng/prfmncReg/pbnstPrfmncReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/prfmncReg/pbnstPrfmncReg/page.tsx @@ -25,7 +25,7 @@ import { } from "@common/components/ui"; import { useState, useEffect, useCallback } from "react"; import { set } from "react-hook-form"; -import { Toaster } from "react-hot-toast"; +import toast, { Toaster } from "react-hot-toast"; import { headMakeprfmnc } from "../chkgdnReg/TableHead"; import { InputTableBody } from "@/components/lib/func/TableData"; import { @@ -51,8 +51,8 @@ export default function prfmncPrfmncReg() { }>({ isModal: false, data: {} as FcPrfType }); const [inputData, setInputData] = useState(); const [pbnstRuseFcltPk, setPbnstRuseFcltPk] = useState(); - const [pageNation , setPageNation] = useState(1); - + const [pageNation, setPageNation] = useState(1); + const [cellNum, setCellNum] = useState(); const [searchYear, setSearchYear] = useState( String(new Date().getFullYear()) ); @@ -76,7 +76,7 @@ export default function prfmncPrfmncReg() { ); prfmncHasuInit(String(pageNation), "41"); } - }, [inputData, searchYear, pbnstRuseFcltPk,prfmncHasuInit,pageNation]); + }, [inputData, searchYear, pbnstRuseFcltPk, prfmncHasuInit, pageNation]); @@ -88,10 +88,16 @@ export default function prfmncPrfmncReg() { isModal: false, data: prfmncRes[index] || ({} as FcPrfType), }); - const inUsageData = structuredClone(initValInUsage); - const outUsageData = structuredClone(initValOutUsage); - const inSubtotal = structuredClone(subTotalObj); - const outSubtotal = structuredClone(subTotalObj); + const inUsageData = structuredClone(initValInUsage).map(row => ({ + ...row, + 구분: "장내용수", + })); + const outUsageData = structuredClone(initValOutUsage).map(row => ({ + ...row, + 구분: "장외용수", + })); + const inSubtotal = { ...structuredClone(subTotalObj), 구분: "장내용수" }; + const outSubtotal = { ...structuredClone(subTotalObj), 구분: "장외용수" }; if (prfmncRes[index]?.prfList) { prfmncRes[index].prfList?.forEach((prfItem) => { const month = Number(prfItem?.ym?.slice(4)); // "MM" @@ -127,7 +133,7 @@ export default function prfmncPrfmncReg() { }); inUsageData.push(inSubtotal); outUsageData.push(outSubtotal); - const usageTotalObj: { [key: string]: any } = structuredClone(totalObj); + const usageTotalObj: { [key: string]: any } = { ...structuredClone(totalObj), 구분: "총합계", 용수명: "" }; for (const key in usageTotalObj) { if (["usage", "gubun", "edit"].includes(key)) continue; const val = @@ -162,7 +168,7 @@ export default function prfmncPrfmncReg() {
- + <Title title={"하수재이용 실적 등록"} /> <SearchDiv> <SearchFormLeft> <div className="col-span-2 flex flex-row space-x-2"> @@ -197,7 +203,7 @@ export default function prfmncPrfmncReg() { <SearchFormRight className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2 "> <div className="space-y"> <div className="flex flex-row space-x-2"> - <Button size={"sm"} onClick={(e) => {}}> + <Button size={"sm"} onClick={(e) => { }}> 조회 </Button> <Button @@ -211,7 +217,12 @@ export default function prfmncPrfmncReg() { <Button size={"sm"} onClick={() => { - setIsExcelOPen({ ...isExcelOpen, isModal: true }); + if (cellNum === undefined) { + toast.error("하수처리재이용시설을 선택해주세요.") + return; + } else { + setIsExcelOPen({ ...isExcelOpen, isModal: true }); + } }} > 파일등록 @@ -238,6 +249,7 @@ export default function prfmncPrfmncReg() { headName={"하수재이용시설 목록"} cellClick={(index: number | undefined, headId: string) => { cellClick(index, headId); + setCellNum(index ?? 0); }} onPageChange={setPageNation} children={undefined} @@ -266,7 +278,7 @@ export default function prfmncPrfmncReg() { </div> </ContentsDiv> <UiModal - bodyClass={""} + bodyClass={"w-[30vw] max-w-none"} body={<PbnPrfExcelModal data={isExcelOpen.data}></PbnPrfExcelModal>} open={isExcelOpen.isModal} onOpenChange={() => { diff --git a/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/headList.tsx b/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/headList.tsx index 544f07516..abde1778f 100644 --- a/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/headList.tsx +++ b/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/headList.tsx @@ -4,7 +4,7 @@ import type { TableUpperProps } from "../../common/type/header"; export const pbnPrfRegExcelZod = z.object({ ym: z.string().default(""), bscFctNm: z.string().default(""), - pbnstRuseFcltFk:z.string(), + pbnstRuseFcltFk: z.string(), pbnstRuseFcltNm: z.string().default(""), file: z.instanceof(File).optional(), }); @@ -18,20 +18,21 @@ export const pbnstPrfmncHeadListExport: TableUpperProps[] = [ ]; export const monthHeadListExport: TableUpperProps[] = [ + { id: "구분", title: "구분", mergeCell: true }, { id: "용수명", title: "용수명" }, { id: "total", title: "계" }, - { id: "1월", title: "1월" ,edit: true }, - { id: "2월", title: "2월" ,edit: true }, - { id: "3월", title: "3월" ,edit: true }, - { id: "4월", title: "4월" ,edit: true }, - { id: "5월", title: "5월" ,edit: true }, - { id: "6월", title: "6월" ,edit: true }, - { id: "7월", title: "7월" ,edit: true }, - { id: "8월", title: "8월" ,edit: true }, - { id: "9월", title: "9월" ,edit: true }, - { id: "10월", title: "10월" ,edit: true }, - { id: "11월", title: "11월" ,edit: true }, - { id: "12월", title: "12월" ,edit: true }, + { id: "1월", title: "1월", edit: true }, + { id: "2월", title: "2월", edit: true }, + { id: "3월", title: "3월", edit: true }, + { id: "4월", title: "4월", edit: true }, + { id: "5월", title: "5월", edit: true }, + { id: "6월", title: "6월", edit: true }, + { id: "7월", title: "7월", edit: true }, + { id: "8월", title: "8월", edit: true }, + { id: "9월", title: "9월", edit: true }, + { id: "10월", title: "10월", edit: true }, + { id: "11월", title: "11월", edit: true }, + { id: "12월", title: "12월", edit: true }, ]; diff --git a/apps/wr/components/lib/func/TableData.tsx b/apps/wr/components/lib/func/TableData.tsx index dbb3aa7a6..39c8b7739 100644 --- a/apps/wr/components/lib/func/TableData.tsx +++ b/apps/wr/components/lib/func/TableData.tsx @@ -174,8 +174,6 @@ export const chRowspanTable = ( ); }; - - export const headVisibleChange = (headList: TableUpperProps[], isEdit: boolean) => { return headList.forEach((head) => { if (head.edit !== undefined) @@ -187,63 +185,124 @@ export const headVisibleChange = (headList: TableUpperProps[], isEdit: boolean) }); } - const handleChange = ( rowIndex: number, field: any, value: string | number, - setInputData: (data:any) => void + setInputData: (data: any) => void ) => { - if(Number(value) < 0 ||! Number(value)){ - value = 0; - }else{ + if (Number(value) < 0 || !Number(value)) { + value = 0; + } else { value = Number(value); } - setInputData((prevData:any) => - prevData?.map((row:any, index: number) => { - if (index === rowIndex) { - return { - ...row, - [field ]: value, - }; - } - return row; - }) - ); + setInputData((prevData: any) => + prevData?.map((row: any, index: number) => { + if (index === rowIndex) { + return { + ...row, + [field]: value, + }; + } + return row; + }) + ); }; ; +export const InputTableBody = ( + chgRes: any[] | [], + headList: TableUpperProps[], + setInputData: (data: any[]) => void +) => { + // mergeCell 처리용 + const getRowSpan = (data: any[], key: string, rowIndex: number) => { + if (rowIndex > 0 && data[rowIndex][key] === data[rowIndex - 1][key]) { + return 0; // 이전과 같으면 셀을 그리지 않음 + } + let span = 1; + for (let i = rowIndex + 1; i < data.length; i++) { + if (data[i][key] === data[rowIndex][key]) span++; + else break; + } + return span; + }; - -export const InputTableBody = (chgRes: any[] | [] ,headList:TableUpperProps[], setInputData: (data: any[]) => void) => { - return ( + return ( <> - {chgRes.map((data, dataIndex) => ( - <TableRow key={dataIndex + "row"}> - {headList.map((head, headIndex) => ( - <TableCell key={head.id + headIndex} className="w-36" > - {head.edit ===true && data.edit !==false? - <Input - className={`${head.id !== "utztnUsgCd" ? "text-right" : "text-center"} !text-xl h-10 w-full`} - onChange={(e) => - handleChange(dataIndex, head.id, e.target.value,setInputData) - } - value={data[head.id as keyof any] ?? ""} - /> : ( - <div - className={` - ${head.id !== "utztnUsgCd" ? "text-right" : "text-center"} - !text-xl w-full h-10 - `} + {chgRes.map((data, dataIndex) => { + // 소계/총합계 행 판별 + const isSubTotal = data["용수명"] === "소계"; + const isTotal = data["구분"] === 0; + + const bgClass = isTotal + ? "bg-[#d5e1eb] font-bold" + : isSubTotal + ? "bg-[#e6eef5] font-semibold" + : ""; + + return ( + <TableRow key={dataIndex + "row"}> + {headList.map((head, headIndex) => { + // 총합계 행이면 "구분"에서 colSpan=2로 병합 + if ( + data["구분"] === 0 && + head.id === "구분" + ) { + return ( + <TableCell + key={head.id + headIndex} + colSpan={2} + className="font-bold text-center bg-[#d5e1eb]" > - {data[head.id as keyof any] ?? ""} - </div> - ) + 총합계 + </TableCell> + ); + } + // 총합계(합계) 행이면 "용수명" 컬럼은 렌더링하지 않음 + if ( + data["구분"] === 0 && + head.id === "용수명" + ) { + return null; + } + // mergeCell 처리 + if (head.mergeCell) { + const rowSpan = getRowSpan(chgRes, head.id, dataIndex); + if (rowSpan === 0) return null; + return ( + <TableCell key={head.id + headIndex} rowSpan={rowSpan} className={`w-36 align-middle text-center whitespace-nowrap ${bgClass}`}> + {data[head.id as keyof any] ?? ""} + </TableCell> + ); } - </TableCell> - ))} - </TableRow> - ))} + // 기본 셀 + return head.edit === true && data.edit !== false ? ( + <TableCell key={head.id + headIndex} className={`w-36 ${bgClass}`}> + <Input + className={`${head.id !== "utztnUsgCd" ? "text-right" : "text-center"} !text-xl h-10 w-full`} + onChange={(e) => + handleChange(dataIndex, head.id, e.target.value, setInputData) + } + value={data[head.id as keyof any] ?? ""} + /> + </TableCell> + ) : ( + <TableCell key={head.id + headIndex} className={`w-36 ${bgClass}`}> + <div + className={` + ${head.id !== "utztnUsgCd" ? "text-right" : "text-center"} + !text-xl w-full h-10 + `} + > + {data[head.id as keyof any] ?? ""} + </div> + </TableCell> + ); + })} + </TableRow> + ); + })} </> ); -} \ No newline at end of file +}; \ No newline at end of file diff --git a/apps/wr/components/ui/modal/chkgd/pbnPrfExcelModal/pbnPrfExcelModal.tsx b/apps/wr/components/ui/modal/chkgd/pbnPrfExcelModal/pbnPrfExcelModal.tsx index 28dc882c3..fb6ba9b22 100644 --- a/apps/wr/components/ui/modal/chkgd/pbnPrfExcelModal/pbnPrfExcelModal.tsx +++ b/apps/wr/components/ui/modal/chkgd/pbnPrfExcelModal/pbnPrfExcelModal.tsx @@ -52,6 +52,7 @@ export default function PbnPrfExcelModal({ data }: { data: FcPrfType }) { useEffect(() => { if (files) { + console.log("이런") const file = files[0]; if (form.getValues("ym").length < 1) { ToastFormUi({ @@ -62,11 +63,12 @@ export default function PbnPrfExcelModal({ data }: { data: FcPrfType }) { return; } - if (file) + if (file) { filePicked(file, 0).then((res) => { if (res !== undefined) - setExcelData(excelToPbnPrfData(res as unknown as JSON[], form.getValues("ym"),form.getValues('pbnstRuseFcltFk') ) as PrfType[]) + setExcelData(excelToPbnPrfData(res as unknown as JSON[], form.getValues("ym"), form.getValues('pbnstRuseFcltFk')) as PrfType[]) }); + } } }, [files]); @@ -75,82 +77,85 @@ export default function PbnPrfExcelModal({ data }: { data: FcPrfType }) { <div> <Form {...form}> <form onSubmit={form.handleSubmit(onSubmit)}> - <div> + <div className="flex justify-between items-center"> <Title title={"하수재이용 실적등록"}> -
-
-

- {"점검정보 입력"} -

- -
+

+ {"점검정보 입력"} +

-
+
( field.onChange(val)} /> )} /> - - ( - - - - )} - /> - ( - - - - )} - /> - - ( - - { - if (files) setFiles(files); - }} - fileTypes="xlsx" - maxFiles={1} - > - - )} - /> +
+
+ ( + + + + )} + /> +
+
+ ( + + + + )} + /> +
+
+
+ ( + + { + if (files) setFiles(files); + }} + fileTypes="xlsx" + maxFiles={1} + > + + )} + /> +
diff --git a/apps/wr/public/sample_pbnstPrfmncReg.xlsx b/apps/wr/public/sample_pbnstPrfmncReg.xlsx index 67f0d559e..1f2ff81aa 100644 Binary files a/apps/wr/public/sample_pbnstPrfmncReg.xlsx and b/apps/wr/public/sample_pbnstPrfmncReg.xlsx differ