Merge commit '4999cc72d66e82ce4ec6379801a6133fa38b9b24' into iipbs/wr/form_fuction
This commit is contained in:
@@ -3,18 +3,15 @@
|
||||
import { useWrStore } from "@/app/store";
|
||||
import {
|
||||
fcltDiv,
|
||||
type chHeadType,
|
||||
type rainChkZodType,
|
||||
type rainChkZodType
|
||||
} from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
|
||||
import type { TableUpperProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
|
||||
import { excelDownload } from "@/components/lib/func/commom";
|
||||
import ChkgdExcel from "@/components/ui/modal/chkgdExcel/chkgdExcel";
|
||||
import ChkgdModal from "@/components/ui/modal/chkgdModal/chkgdModal";
|
||||
import RainChkgdTable from "@/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable";
|
||||
import RainChkgdTableModal from "@/components/ui/table/chkgdTable/rainChkgd/rainChkgdTableModal";
|
||||
import RswtChkgdTable from "@/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable";
|
||||
import {
|
||||
ContentsDiv,
|
||||
filePickedBlob,
|
||||
SearchDiv,
|
||||
SearchFormLeft,
|
||||
SearchFormRight,
|
||||
@@ -37,7 +34,10 @@ export default function Page() {
|
||||
const [searchTxt, setSearchTxt] = useState<string>();
|
||||
const [updateRainDetail, setUpdateRainDetail] = useState<rainChkZodType[]>([]);
|
||||
const [selFcltDiv, setSelFcltDiv] = useState("RNB");
|
||||
|
||||
const [isModal, setIsModal] = useState({
|
||||
open: false,
|
||||
data: {},
|
||||
});
|
||||
const cellClick = () => {
|
||||
if(searchTxt)
|
||||
rainChkInit(searchTxt,'41')
|
||||
@@ -54,13 +54,15 @@ export default function Page() {
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
excelDownload(rainChkgdn.excelList ,'빗물이용시설 지도점검','sample_rainy.xlsx');
|
||||
excelDownload(rainChkgdn.excelList ,'빗물이용시설 지도점검','sample_rainy.xlsx', 'A1:AN1');
|
||||
}, [rainChkgdn.excelList]);
|
||||
|
||||
const excelClick= useCallback(()=>{
|
||||
rainChkExcelDownload(code.cityCd, code.sggCd);
|
||||
}, [excelDownload, code.cityCd, code.sggCd]);
|
||||
|
||||
}, [rainChkExcelDownload, code.cityCd, code.sggCd]);
|
||||
const handleClick = useCallback((data:any) => {
|
||||
if(data) setIsModal({ open: true, data: data });
|
||||
}, [isModal]);
|
||||
|
||||
return (
|
||||
<ContentsDiv>
|
||||
@@ -122,12 +124,12 @@ export default function Page() {
|
||||
<div className="grid grid-cols-6 gap-4 ">
|
||||
<div className="col-span-6">
|
||||
<ListDiv>
|
||||
{selFcltDiv === "RNB" ? <RainChkgdTable detailUp={setUpdateRainDetail} /> : <RswtChkgdTable />}
|
||||
{selFcltDiv === "RNB" ? <RainChkgdTable detailUp={setUpdateRainDetail} handleClick={handleClick} /> : <RswtChkgdTable />}
|
||||
</ListDiv>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<RainChkgdTableModal isModal={isModal} setIsModal={setIsModal}/>
|
||||
<UiModal
|
||||
open={isRegExcel}
|
||||
onOpenChange={setIsRegExcel}
|
||||
|
||||
@@ -9,6 +9,15 @@ import { buildingToExcelType, excelToRainChkData } from "./excel";
|
||||
import toast from "react-hot-toast";
|
||||
import { ToastFormUi } from "@/components/ui/toast/toastFromUi";
|
||||
|
||||
const guideDetail=z.object({
|
||||
chkgdnFk: z.number().nullable(),
|
||||
utztnUsgCd: z.string(),
|
||||
chckYmd: z.string(),
|
||||
ym: z.string(),
|
||||
splyUswtrUtztnQnt: z.number(),
|
||||
ruseFcltUtztnQnt: z.number(),
|
||||
flg: z.string(),
|
||||
})
|
||||
export const rainChkZod = z.object({
|
||||
chkgdnPk: z.number().nullable(),
|
||||
bdstRuseFcltFk: z.number(),
|
||||
@@ -21,15 +30,7 @@ export const rainChkZod = z.object({
|
||||
mdfr: z.string().nullable(),
|
||||
flg: z.string().nullable(),
|
||||
guideDetails: z.array(
|
||||
z.object({
|
||||
chkgdnFk: z.number().nullable(),
|
||||
utztnUsgCd: z.string(),
|
||||
chckYmd: z.string(),
|
||||
ym: z.string(),
|
||||
splyUswtrUtztnQnt: z.number(),
|
||||
ruseFcltUtztnQnt: z.number(),
|
||||
flg: z.string(),
|
||||
})
|
||||
guideDetail
|
||||
),
|
||||
building: z.object({
|
||||
bdstInfoPk: z.number(),
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
|
||||
const LOCAL_PORT = "3000";
|
||||
const DEV_PORT = "11080";
|
||||
const DEV_PORT_NEW="8882"
|
||||
const DEV_PORT_NEW="11082"
|
||||
|
||||
|
||||
export const LOCAL_URL_WR = `http://localhost:${LOCAL_PORT}/api/v1`;
|
||||
export const DEV_URL_WR = `http://con.mind-one.co.kr:${DEV_PORT}/api/v1`;
|
||||
|
||||
//export const DEV_URL_FO = `http://con.mind-one.co.kr:${DEV_PORT_FO}/api/v1`;
|
||||
export const DEV_URL_FO = `http://192.168.1.193:${DEV_PORT_NEW}/api/v1`;
|
||||
export const DEV_URL_FO = `http://con.mind-one.co.kr:${DEV_PORT_NEW}/api/v1`;
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Checkbox, Input, TableCell, TableRow } from "@common/components/ui";
|
||||
|
||||
export const rightTableData = (rainChk: rainChkZodType[]) => {
|
||||
// 1. chkgdnFk + utztnUsgCd 기준 누계 정보 만들기
|
||||
const maketotal = rainChk.map((item: any) => {
|
||||
const maketotal = rainChk.map((item: rainChkZodType) => {
|
||||
const selectTotal = item.guideDetails.reduce((acc: any, cur: any) => {
|
||||
const code = cur.utztnUsgCd;
|
||||
const fk = cur.chkgdnFk;
|
||||
@@ -23,6 +23,8 @@ export const rightTableData = (rainChk: rainChkZodType[]) => {
|
||||
|
||||
return selectTotal; // 모든 키: `${chkgdnFk}_${utztnUsgCd}` 형태
|
||||
});
|
||||
console.log("maketotal", maketotal);
|
||||
|
||||
|
||||
// 2. 누계 정보들을 하나의 객체로 합치기 (평탄화)
|
||||
const flatTotalMap = Object.assign({}, ...maketotal);
|
||||
@@ -30,8 +32,8 @@ export const rightTableData = (rainChk: rainChkZodType[]) => {
|
||||
// 3. rainyDetails에 누계 정보 주입
|
||||
|
||||
const updatedRainyDetails: any[] = [];
|
||||
rainChk.forEach((rd: any) => {
|
||||
const details = rd.rainyDetails.forEach((rainyItem: any) => {
|
||||
rainChk.forEach((rd: rainChkZodType) => {
|
||||
rd.rainyDetails.forEach((rainyItem: any) => {
|
||||
const key = `${rainyItem.chkgdnFk}_${rainyItem.utztnUsgCd}`;
|
||||
const totals = flatTotalMap[key] || {
|
||||
totalSplyUswtrUtztnQnt: 0,
|
||||
@@ -51,10 +53,6 @@ export const rightTableData = (rainChk: rainChkZodType[]) => {
|
||||
return updatedRainyDetails;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export const chRowspanTable = (
|
||||
makeTableData: any[],
|
||||
headList: TableUpperProps[],
|
||||
@@ -67,10 +65,7 @@ export const chRowspanTable = (
|
||||
selectedIds: number[],
|
||||
handleCellClick: (index: number, headId: string) => void
|
||||
) => {
|
||||
|
||||
|
||||
|
||||
|
||||
console.log('chRowspanTable', makeTableData);
|
||||
// rowspan된 셀 렌더링 여부 추적용
|
||||
const renderedMap = new Map<string, Set<number>>();
|
||||
return (
|
||||
|
||||
@@ -41,7 +41,6 @@ export const getCity = (val: string, sggCd: SelectDataType[]) => {
|
||||
returnData= { ...item, sggText: sggText, cityText: cityText};
|
||||
}
|
||||
|
||||
// console.log(" returnData ", returnData)
|
||||
return returnData;
|
||||
|
||||
});
|
||||
@@ -49,7 +48,7 @@ export const getCity = (val: string, sggCd: SelectDataType[]) => {
|
||||
|
||||
|
||||
|
||||
export const excelDownload =(excelList: [][], fileNm:string ,sampleFile:string ) =>{
|
||||
export const excelDownload =(excelList: [][], fileNm:string ,sampleFile:string, headerRange='A1:V3') =>{
|
||||
if (excelList.length === 0) return;
|
||||
fetch(`/${sampleFile}`, {})
|
||||
.then(async (response) => {
|
||||
@@ -59,7 +58,7 @@ export const getCity = (val: string, sggCd: SelectDataType[]) => {
|
||||
// 받은 파일 바인너리 처리
|
||||
const blobRet = await response.arrayBuffer()
|
||||
// 버퍼에 있는 엑셀데이터 전달 후 json으로 변환
|
||||
await filePickedBlob(blobRet, excelList,fileNm, 4)
|
||||
await filePickedBlob(blobRet, excelList,fileNm, 4,headerRange)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,41 +1,29 @@
|
||||
"use client";
|
||||
import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead";
|
||||
import { useWrStore } from "@/app/store";
|
||||
import type { rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
|
||||
import { tableData } from "@/components/lib/func/commom";
|
||||
import { UiModal } from "@common/business_components/ui";
|
||||
import {
|
||||
chRowspanTable,
|
||||
rightTableData
|
||||
} from "@/components/lib/func/TableData";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableHeader,
|
||||
} from "@common/components/ui";
|
||||
import { useEffect, useState } from "react";
|
||||
import ChkgdModal from "../../../modal/chkgdModal/chkgdModal";
|
||||
import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead";
|
||||
import {
|
||||
chRowspanTable,
|
||||
rightTableData,
|
||||
} from "@/components/lib/func/TableData";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
export default function RainChkgdTable({
|
||||
detailUp,
|
||||
detailUp, handleClick=() => {}
|
||||
}: {
|
||||
detailUp: (data: rainChkZodType[]) => void;
|
||||
handleClick?: (data:any) => void;
|
||||
}) {
|
||||
const { code, rainChkgdn } = useWrStore((state) => state);
|
||||
const [makeTableData, setMakeTableData] = useState<any[]>([]);
|
||||
const { rainChk } = rainChkgdn;
|
||||
const [selectedIds, setSelectedIds] = useState<number[]>([]);
|
||||
const [upRaintDetail, setUpRaintDetail] = useState<rainChkZodType[]>([]);
|
||||
const [isModal, setIsModal] = useState({ open: false, data: {} });
|
||||
|
||||
const handleCellClick = (index: number, headId: string) => {
|
||||
if (
|
||||
headId === "totalSplyUswtrUtztnQnt" ||
|
||||
headId === "totalRuseFcltUtztnQnt"
|
||||
) {
|
||||
setIsModal({ open: true, data: makeTableData[index] });
|
||||
}
|
||||
};
|
||||
|
||||
const toggleSelection = (pk: number, checked: boolean) => {
|
||||
setSelectedIds((prev) =>
|
||||
checked ? [...prev, pk] : prev.filter((item) => item !== pk)
|
||||
@@ -53,6 +41,15 @@ export default function RainChkgdTable({
|
||||
);
|
||||
};
|
||||
|
||||
const handleCellClick= useCallback((index: number, headId: string) => {
|
||||
if (
|
||||
headId === "totalSplyUswtrUtztnQnt" ||
|
||||
headId === "totalRuseFcltUtztnQnt"
|
||||
) {
|
||||
handleClick(makeTableData[index])
|
||||
}
|
||||
},[makeTableData, handleClick]);
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
@@ -65,8 +62,8 @@ export default function RainChkgdTable({
|
||||
rowspan: item.rainyDetails?.length,
|
||||
};
|
||||
});
|
||||
|
||||
setMakeTableData(rightTableData(rainChg));
|
||||
const tableTotalData = rightTableData(rainChg)
|
||||
setMakeTableData(tableTotalData);
|
||||
}, [rainChk, code]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -117,35 +114,24 @@ export default function RainChkgdTable({
|
||||
detailUp(upRaintDetail);
|
||||
}, [upRaintDetail]);
|
||||
return (
|
||||
<>
|
||||
<Table variant="secondary">
|
||||
<TableHeader className="font-bold">
|
||||
{headMakeprfmnc(
|
||||
rainChkgdn?.rainChkgdnHeadList,
|
||||
rainChkgdn?.rainHeadNm
|
||||
)}
|
||||
</TableHeader>
|
||||
<Table variant="secondary">
|
||||
<TableHeader className="font-bold">
|
||||
{headMakeprfmnc(
|
||||
rainChkgdn?.rainChkgdnHeadList,
|
||||
rainChkgdn?.rainHeadNm
|
||||
)}
|
||||
</TableHeader>
|
||||
|
||||
<TableBody>
|
||||
{chRowspanTable(
|
||||
makeTableData,
|
||||
rainChkgdn.rainChkgdnHeadList,
|
||||
handleChange,
|
||||
toggleSelection,
|
||||
selectedIds,
|
||||
handleCellClick
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
<UiModal
|
||||
open={isModal.open}
|
||||
onOpenChange={() => {
|
||||
setIsModal({ open: !open, data: {} });
|
||||
}}
|
||||
bodyClass={"w-[80vw] max-w-none"}
|
||||
body={<ChkgdModal type={"RNB"} obj={isModal.data} />}
|
||||
></UiModal>
|
||||
</>
|
||||
<TableBody>
|
||||
{chRowspanTable(
|
||||
makeTableData,
|
||||
rainChkgdn.rainChkgdnHeadList,
|
||||
handleChange,
|
||||
toggleSelection,
|
||||
selectedIds,
|
||||
handleCellClick
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import ChkgdModal from "@/components/ui/modal/chkgdModal/chkgdModal";
|
||||
import { UiModal } from "@common/business_components";
|
||||
|
||||
export default function RainChkgdTableModal({ isModal, setIsModal }: { isModal: { open: boolean; data: any }; setIsModal: (value: { open: boolean; data: any }) => void }) {
|
||||
return (<UiModal
|
||||
open={isModal.open}
|
||||
onOpenChange={() => {
|
||||
setIsModal({ open: !open, data: {} });
|
||||
}}
|
||||
bodyClass={"w-[80vw] max-w-none"}
|
||||
body={<ChkgdModal type={"RNB"} obj={isModal.data} />}
|
||||
></UiModal>)
|
||||
}
|
||||
@@ -43,6 +43,7 @@
|
||||
"sonner": "^2.0.1",
|
||||
"tailwind-merge": "^3.0.1",
|
||||
"xlsx": "^0.18.5",
|
||||
"xlsx-populate": "^1.21.0",
|
||||
"zod": "^3.24.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -58,6 +59,7 @@
|
||||
"@storybook/test": "^8.5.3",
|
||||
"@storybook/theming": "^8.5.5",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"@xlsx/xlsx-populate": "^0.0.8",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"eslint": "^9.17.0",
|
||||
"eslint-plugin-react-hooks": "^5.0.0",
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import * as XlsxPopulate from '@xlsx/xlsx-populate';
|
||||
export const excelStyle = async (data: ArrayBuffer, range: string = "A1:V3", fileNm:string) => {
|
||||
console.log("excelStyle", data, range, fileNm);
|
||||
const workbook = await XlsxPopulate.Workbook.fromData(data);
|
||||
const rangeCells = workbook.activeSheet(0)?.sheet(0)?.range(range);
|
||||
console.log(rangeCells);
|
||||
rangeCells?.style((styleQ)=>{
|
||||
console.log(styleQ);
|
||||
styleQ.fill({ type: "solid", color: {rgb:"9bc1e7"} });
|
||||
styleQ.borderEach( { style: "thin", color: { rgb: "FFFFFF" } } );
|
||||
styleQ.wrapText(true);
|
||||
// styleQ.fontColor({rgb:"FFFFFF"});
|
||||
styleQ.fontSize(15);
|
||||
styleQ.horizontalAlignment("center");
|
||||
styleQ.verticalAlignment("center");
|
||||
styleQ.bold(true);
|
||||
});
|
||||
const outputData = await workbook.output("array-buffer");
|
||||
const blob = new Blob([outputData], { type: "application/octet-stream" });
|
||||
const link = document.createElement("a");
|
||||
link.href = URL.createObjectURL(blob);
|
||||
link.download = fileNm+".xlsx";
|
||||
link.click();
|
||||
}
|
||||
+7
-8
@@ -1,18 +1,18 @@
|
||||
import * as XLSX from 'xlsx';
|
||||
import { excelStyle } from './excelStyle';
|
||||
|
||||
type ExcelDownloadProps = {
|
||||
data: JSON | JSON[];
|
||||
fileName: string;
|
||||
sheetNameArray: string[];
|
||||
headerRange: string;
|
||||
}
|
||||
|
||||
export const downloadExcel = ({ data, fileName = new Date().getTime().toString() + '.xlsx', sheetNameArray = ["Sheet1"] }: ExcelDownloadProps) => {
|
||||
export const downloadExcel = ({ data, fileName = new Date().getTime().toString() + '.xlsx', sheetNameArray = ["Sheet1"], headerRange='A1:V3'}: ExcelDownloadProps) => {
|
||||
const worksheet = XLSX.utils.json_to_sheet(Array.isArray(data) ? data : [data]);
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, sheetNameArray[0]);
|
||||
//let buffer = XLSX.write(workbook, { bookType: "xlsx", type: "buffer" });
|
||||
//XLSX.write(workbook, { bookType: "xlsx", type: "binary" });
|
||||
XLSX.writeFile(workbook, fileName + '.xlsx');
|
||||
excelStyle(XLSX.write(workbook, { bookType: "xlsx", type: "buffer" }), headerRange, fileName);
|
||||
};
|
||||
|
||||
|
||||
@@ -59,13 +59,12 @@ export const filePicked=(oFile: File, headerNum:number=0):Promise<JSON | undefin
|
||||
|
||||
|
||||
|
||||
export const filePickedBlob=(oFile: ArrayBuffer, data:[][],fileNm:string, headerNum:number=0):Promise<JSON | undefined> =>{
|
||||
// Create A File Reader HTML5
|
||||
export const filePickedBlob=(oFile: ArrayBuffer, data:[][],fileNm:string, headerNum:number=0, headerRange='A1:V3'):Promise<JSON | undefined> =>{ // Create A File Reader HTML5
|
||||
return new Promise<JSON | undefined>(() => {
|
||||
// Ready The Event For When A File Gets Selected
|
||||
const wb = XLSX.read(oFile, { type: 'binary' });
|
||||
// Loop Over Each Sheet
|
||||
wb.SheetNames.forEach(function (sheetName, index) {
|
||||
wb.SheetNames.forEach(async function (sheetName, index) {
|
||||
// Obtain The Current Row As CSV
|
||||
if(index==0){
|
||||
const sheet = wb.Sheets[sheetName];
|
||||
@@ -74,7 +73,7 @@ export const filePickedBlob=(oFile: ArrayBuffer, data:[][],fileNm:string, header
|
||||
// const sheet = XLSX.utils.json_to_sheet(data);
|
||||
XLSX.utils.sheet_add_aoa(sheet, data, { origin: 'A'+headerNum });
|
||||
// XLSX.utils.book_append_sheet(wb, sheet, 'test');
|
||||
XLSX.writeFile(wb, `${fileNm}.xlsx`);
|
||||
await excelStyle(XLSX.write(wb, { bookType: "xlsx", type: "buffer" }), headerRange, fileNm)
|
||||
} else {
|
||||
console.error(`Sheet "${sheetName}" is undefined.`);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
export * from "./chart";
|
||||
export * from "./date_picker";
|
||||
export * from "./dialog_ui";
|
||||
export * from "./excel_download";
|
||||
export * from "./excel";
|
||||
export * from "./file-upload";
|
||||
export * from "./form";
|
||||
export * from "./form_ui";
|
||||
@@ -19,3 +19,4 @@ export * from "./tab";
|
||||
export * from "./table";
|
||||
export * from "./table_div";
|
||||
export * from "./title";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user