diff --git a/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx b/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx index 53a7a31f3..88a0de300 100644 --- a/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx @@ -20,7 +20,6 @@ import { SearchDiv, SearchFormLeft, SearchFormRight, - SearchInput, SelectBox, Title, UiModal, @@ -29,7 +28,6 @@ import ListDiv from "@common/business_components/ui/list_div"; import { Button, Label } from "@common/components/ui"; import { useCallback, useEffect, useState } from "react"; import { Toaster } from "react-hot-toast"; -import { shallow } from "zustand/shallow"; export default function Page() { const { @@ -135,8 +133,8 @@ export default function Page() { ); useEffect(() => { - rainChkgdn.isSttn = false; - rswtChkgdn.isSttn = false; + //rainChkgdn.isSttn = false; + //rswtChkgdn.isSttn = false; if (!rainChkgdn.isSttn && !rswtChkgdn.isSttn) { rainChkHeadChange({ rainChkgdn }, true); rswtChkHeadChange({ rswtChkgdn }, true); diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx index 5754c02fc..58e8d6bf0 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx @@ -94,15 +94,15 @@ export const excelToRainChkData = (excelData: any, year: string) => { } const makeGuidDetail = Array.from({ length: 12 }, (_, i) => { let month = `${i + 1}`; - const splyData = item[`보급_${month}월`]; + const splyData = item[`대체_${month}월`]; const ruseData = item[`빗물_${month}월`]; if (month.length < 2) month = "0" + month; return { utztnUsgCd: item["이용용도"], ym: year + month, chckYmd: checkYmd, - splyUswtrUtztnQnt: Number(splyData ?? 0), - ruseFcltUtztnQnt: Number(ruseData ?? 0), + splyUswtrUtztnQnt: Number(splyData) || 0, + ruseFcltUtztnQnt: Number(ruseData) || 0, flg: "RNB", }; }); @@ -120,13 +120,13 @@ export const excelToRainChkData = (excelData: any, year: string) => { rainyDetails: [ { utztnUsgCd: item["이용용도"] ?? "", - ph: Number(item["PH"] ?? 0), - trbt: Number(item["탁도"] ?? 0), - grssClfg: Number(item["총대장균군수"] ?? 0), - etc: item["기타"] ?? "", // 필드 누락 방지 - vltnDt: vltnDt ?? "", - vltnMttr: item["위반사항"] ?? "", - levyAmt: Number(item["과태료부과금액(천원)"] ?? 0), + ph: Number(item["PH"] || 0), + trbt: Number(item["탁도"] || 0), + grssClfg: Number(item["총대장균군수"] || 0), + etc: item["기타"] || "", // 필드 누락 방지 + vltnDt: vltnDt || "-", + vltnMttr: item["위반사항"] || "-", + levyAmt: Number(item["과태료부과금액(천원)"] || 0), rgtr: TEST_UUID, }, ], diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx index 4af27a51c..4c7f2d514 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx @@ -1,7 +1,5 @@ import { buildingType } from "@/app/store/common/code"; -import { - TEST_UUID, -} from "@/app/store/ruseFcltMng/fcltReg/rainReg"; +import { TEST_UUID } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import { deleteFectch, fetchType, @@ -22,6 +20,7 @@ import { type chHeadType, } from "./headList"; import type { TableUpperProps } from "@/app/store/common/type/header"; +import toast from "react-hot-toast"; export type rainChkZodType = z.infer; const fcltDiv = [ @@ -52,7 +51,12 @@ export type rainChkgdnState = { }; type rainChkgdnActions = { - rainChkInit: (pageNo: string, cnt: string, sggCd: string, searchTxt: string) => void; + rainChkInit: ( + pageNo: string, + cnt: string, + sggCd: string, + searchTxt: string + ) => void; rainChkDetilUpdate(rainChk: rainChkZodType[]): Promise; rainChkGuidUpdate(rainChk: rainChkZodType): Promise; rainChkExcelDownload( @@ -98,11 +102,20 @@ const makeMdfrChk = (data: rainChkZodType[], type: string, toDo: string) => { return chData; }; -const initFetch = async (pageNo: string, cnt: string, txt: string | undefined, sgg: string | undefined) => { +const initFetch = async ( + pageNo: string, + cnt: string, + txt: string | undefined, + sgg: string | undefined +) => { const currentYear = new Date().getFullYear().toString(); const rainRes = await getFetch( "wr", - `/reuseChk/rainy` + (pageNo ? `/${pageNo}` : "/1") + (cnt ? `/${cnt}` : "/20") + (txt ? `/${txt}` : `/${currentYear}`) + (sgg ? `/${sgg}` : "/0") + `/reuseChk/rainy` + + (pageNo ? `/${pageNo}` : "/1") + + (cnt ? `/${cnt}` : "/20") + + (txt ? `/${txt}` : `/${currentYear}`) + + (sgg ? `/${sgg}` : "/0") ); return rainRes; }; @@ -131,32 +144,31 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( rainChkExcelDataUPload: async (excelData: rainChkZodType[]) => { try { const res = await postFectch("/reuseChk/rainy", excelData); - console.log("res", res); - console.log("res.ok", res.ok) - if (res.ok) { - ToastFormUi({ - body: "지도점검 등록이 완료되었습니다. ", - title: "지도점검 등록", - }); + if (res.status === 200) { + const currentYear = new Date().getFullYear().toString(); + const rainChkRes = await initFetch("1", "20", currentYear, "0"); + return set((state: rainChkgdnState) => ({ + ...state, + rainChkgdn: { + ...state.rainChkgdn, + rainChk: rainChkRes, + }, + })); + toast.success("지도점검 등록이 완료되었습니다."); + } else { + toast.error("지도점검 등록이 실패되었습니다."); } - const currentYear = new Date().getFullYear().toString(); - const rainChkRes = await initFetch("1", "20", currentYear, "0"); - return set((state: rainChkgdnState) => ({ - ...state, - rainChkgdn: { - ...state.rainChkgdn, - rainChk: rainChkRes, - }, - })); } catch (error) { console.log(error); - ToastFormUi({ - body: "지도점검 등록이 실패되었습니다.", - title: "지도점검 등록", - }); + toast.error("지도점검 등록이 실패되었습니다."); } }, - rainChkInit: async (pageNo: string, cnt: string, searchTxt: string, sggCd: string) => { + rainChkInit: async ( + pageNo: string, + cnt: string, + searchTxt: string, + sggCd: string + ) => { try { const rainChkRes = await initFetch(pageNo, cnt, searchTxt, sggCd); @@ -176,47 +188,49 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( const chData = await makeMdfrChk(rainChk, "rain", "rainDetil"); const res = await postFectch("/reuseChk/rainy", chData); - if (res.ok) { - ToastFormUi({ - body: "지도점검 보급수 및 밋물이용량 수정이 완료되었습니다. ", - title: "지도점검 수정", - }); + if (res.staus === 200) { + toast.success( + "지도점검 보급수 및 밋물이용량 수정이 완료되었습니다. " + ); + const currentYear = new Date().getFullYear().toString(); + const rainChkRes = await initFetch("1", "20", currentYear, "11"); + return set((state: rainChkgdnState) => ({ + ...state, + rainChkgdn: { + ...state.rainChkgdn, + rainChk: rainChkRes, + }, + })); + } else { + toast.error("지도점검 보급수 및 밋물이용량 수정 오류입니다."); } - const currentYear = new Date().getFullYear().toString(); - const rainChkRes = await initFetch(currentYear, "0"); - return set((state: rainChkgdnState) => ({ - ...state, - rainChkgdn: { - ...state.rainChkgdn, - rainChk: rainChkRes, - }, - })); } catch (error) { console.log(error); - alert("수정에 실패하였습니다."); + toast.error("지도점검 보급수 및 밋물이용량 수정 오류입니다."); } }, rainChkGuidUpdate: async (rainChk: rainChkZodType) => { try { //const chData = await makeMdfrChk(rainChk, "guideDetails", "rainDetil"); const res = await putFectch("/reuseChk/rainy", rainChk); - if (res.ok) { - ToastFormUi({ - body: "지도점검 수질 및 과태료 수정이 완료되었습니다. ", - title: "지도점검 수정", - }); + if (res.status === 200) { + toast.success("지도점검 수질 및 과태료 수정이 완료되었습니다. "); + + const currentYear = new Date().getFullYear().toString(); + const rainChkRes = await initFetch("1", "20", currentYear, "11"); + return set((state: rainChkgdnState) => ({ + ...state, + rainChkgdn: { + ...state.rainChkgdn, + rainChk: rainChkRes, + }, + })); + }else{ + toast.error("지도점검 수질 및 과태료 수정 오류입니다."); + } - const currentYear = new Date().getFullYear().toString(); - const rainChkRes = await initFetch(currentYear, "0"); - return set((state: rainChkgdnState) => ({ - ...state, - rainChkgdn: { - ...state.rainChkgdn, - rainChk: rainChkRes, - }, - })); } catch (error) { - console.log(error); + toast.error("지도점검 수질 및 과태료 수정 오류입니다."); } }, rainChkDelete: async (chkgdnPks: number[]) => { @@ -224,22 +238,23 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( const res = await deleteFectch(`/reuseChk/rainy`, chkgdnPks); if (res) { - ToastFormUi({ - body: "삭제가 완료되었습니다. ", - title: "지도점검 삭제", - }); + toast.success("삭제가 완료되었습니다. "); + + const currentYear = new Date().getFullYear().toString(); + const rainChkRes = await initFetch("1", "20", currentYear, "11"); + return set((state: rainChkgdnState) => ({ + ...state, + rainChkgdn: { + ...state.rainChkgdn, + rainChk: rainChkRes, + }, + })); + }else{ + toast.error("삭제시 오류가 발생하였습니다.. "); + } - const currentYear = new Date().getFullYear().toString(); - const rainChkRes = await initFetch(currentYear, "0"); - return set((state: rainChkgdnState) => ({ - ...state, - rainChkgdn: { - ...state.rainChkgdn, - rainChk: rainChkRes, - }, - })); } catch (error) { - ToastFormUi({ body: "삭제를 실패했습니다.. ", title: "지도점검 삭제" }); + toast.error("삭제시 오류가 발생하였습니다.. "); } }, rainChkHeadChange: async (rainChkgdn: rainChkgdnState, isEdit: boolean) => { @@ -249,16 +264,13 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( const ruseHeadList = rainChkgdn.rainChkgdn.ruseHeadList; rainChkgdnHeadList.forEach((head) => { - if (head.edit !== undefined) - head.edit = isEdit; + if (head.edit !== undefined) head.edit = isEdit; }); splHeadList.forEach((head) => { - if (head.edit !== undefined) - head.edit = isEdit; + if (head.edit !== undefined) head.edit = isEdit; }); ruseHeadList.forEach((head) => { - if (head.edit !== undefined) - head.edit = isEdit; + if (head.edit !== undefined) head.edit = isEdit; }); return set((state: rainChkgdnState) => ({ @@ -267,7 +279,7 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( ...state.rainChkgdn, rainChkgdnHeadList: rainChkgdnHeadList, splHeadList: splHeadList, - ruseHeadList: ruseHeadList + ruseHeadList: ruseHeadList, }, })); } catch (error) { diff --git a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/headList.tsx b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/headList.tsx index f112db0bd..8c90e0829 100644 --- a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/headList.tsx +++ b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/headList.tsx @@ -11,7 +11,7 @@ export const rainChkgdnHeadSttnExport: TableUpperProps[] = [ { id: "dtfcltCpct", title: "빗물저류조용량(m³)", mergeCell: true }, { id: "chckYmd", title: "점검일", mergeCell: true }, { id: "utztnUsgCd", title: "이용용도" }, - { id: "totalSplyUswtrUtztnQnt", title: "연간보급수이용량(m³)" }, + { id: "totalSplyUswtrUtztnQnt", title: "연간대체수이용량(m³)" }, { id: "totalRuseFcltUtztnQnt", title: "연간빗물이용량(m³)" }, { id: "ph", diff --git a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/index.tsx b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/index.tsx index ea3f58a40..2136dfebe 100644 --- a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/index.tsx +++ b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/index.tsx @@ -1,11 +1,10 @@ import type { rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; -import { type TableUpperProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import { getFetch } from "@/components/lib/api"; -import { ToastFormUi } from "@/components/ui/toast/toastFromUi"; import type { SelectDataType } from "@common/business_components/ui"; import { rainChkgdnHeadSttnExport, ruseSttnHeadListExport, splSttnHeadListExport } from "./headList"; import { rainHeadNmExport, type chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; import { buildingExcelRainSttn } from "./excel"; +import type { TableUpperProps } from "@/app/store/common/type/header"; const fcltDiv = [ { val: "RST", text: "중수도시설" }, diff --git a/apps/wr/components/lib/func/TableData.tsx b/apps/wr/components/lib/func/TableData.tsx index 9ac26827d..7a35e02c4 100644 --- a/apps/wr/components/lib/func/TableData.tsx +++ b/apps/wr/components/lib/func/TableData.tsx @@ -103,6 +103,7 @@ export const chRowspanTable = ( const key = head.id; const isMerged = head.mergeCell; const value = row[key]; + // 병합 대상이면 중복 렌더링 여부 판단 if (isMerged) { const renderedSet = renderedMap.get(key) ?? new Set(); @@ -152,7 +153,7 @@ export const chRowspanTable = ( onChange={(e) => { handleChange(rowIndex, head.id, e.target.value); }} - value={value ?? ""} + value={value || ""} disabled={!selectedIds.includes(row.chkgdnPk)} /> ) : ( diff --git a/apps/wr/components/ui/modal/chkgd/chkgdExcel/chkgdExcel.tsx b/apps/wr/components/ui/modal/chkgd/chkgdExcel/chkgdExcel.tsx index 15badc59d..8828420b8 100644 --- a/apps/wr/components/ui/modal/chkgd/chkgdExcel/chkgdExcel.tsx +++ b/apps/wr/components/ui/modal/chkgd/chkgdExcel/chkgdExcel.tsx @@ -1,7 +1,7 @@ import { useWrStore } from "@/app/store"; import { type rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; import { excelToRainChkData } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel"; -import { chkgdRegExcel } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; +import { chkgdRegExcel } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; import type { rswtChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn"; import { excelToRswtGuideData, @@ -18,24 +18,31 @@ import { SelectBox, Title, } from "@common/business_components/ui"; +import { Card } from "@common/business_components/ui/chart/lib/card"; import { Button, Input } from "@common/components/ui"; import { zodResolver } from "@hookform/resolvers/zod"; import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; +import toast from "react-hot-toast"; import type { z } from "zod"; export default function ChkgdExcel({ type }: { type: string }) { - const { - rswtChkgdn, - rainChkExcelDataUPload, - rswtChkExceDataUpload, - } = useWrStore((state) => { - return state; - }); - const [files, setFiles] = useState(null); + const { rswtChkgdn, rainChkExcelDataUPload, rswtChkExceDataUpload } = + useWrStore((state) => { + return state; + }); const [excelData, setExcelData] = useState< rswtChkZodType[] | rainChkZodType[] >(); + + const [file, setFile] = useState(null); + + const handleFileChange = (e: React.ChangeEvent) => { + const selectedFile = e.target.files?.[0]; + if (selectedFile) { + setFile(selectedFile); + } + }; const [excelRswtData, setExcelRswtData] = useState(); const currentYear = new Date().getFullYear(); @@ -49,7 +56,7 @@ export default function ChkgdExcel({ type }: { type: string }) { ); const defaultValues: z.infer = chkgdRegExcel.parse({ - chckYr: String(currentYear) + chckYr: String(currentYear), }); const form = useForm>({ @@ -58,14 +65,10 @@ export default function ChkgdExcel({ type }: { type: string }) { }); useEffect(() => { - if (files) { - const file = files[0]; + if (file) { if (form.getValues("chckYr").length < 1) { - ToastFormUi({ - body: "파일업로드 이전에 등록년도를 작성해주세요 ", - title: "지도점검 등록", - }); - setFiles(null); + toast.error("파일업로드 이전에 등록년도를 작성해주세요 "); + setFile(null); return; } if (file) @@ -87,7 +90,6 @@ export default function ChkgdExcel({ type }: { type: string }) { form.getValues("chckYr") ); - const keyGenerator = (item: rswtChkZodType) => `${item.bdstRuseFcltFk}|${item.chckYmd}|${item.utztnUsgCd}`; const totalData: rswtChkZodType[] = guideData.map((guide) => { @@ -98,12 +100,11 @@ export default function ChkgdExcel({ type }: { type: string }) { guide.utztnUsgCd === polution.utztnUsgCd ); - if (fusion) { return { ...guide, rswtrPollutions: fusion?.rswtrPollutions, - rswtrDetails:fusion?.rswtrDetails + rswtrDetails: fusion?.rswtrDetails, }; } else { return { @@ -118,19 +119,17 @@ export default function ChkgdExcel({ type }: { type: string }) { (item) => !guideKey.has(keyGenerator(item)) ); + const listTotalData: rswtChkZodType[] = [ + ...totalData, + ...onlypolution, + ]; - const listTotalData:rswtChkZodType[] =[ - ...totalData, - ...onlypolution - ] - - - setExcelRswtData(listTotalData); + setExcelRswtData(listTotalData); } }); } } - }, [files]); + }, [file]); function findMatchingItems( arrayA: T[], @@ -144,7 +143,6 @@ export default function ChkgdExcel({ type }: { type: string }) { (!condition || condition(item)) && bKeySet.has(keySelector(item)) ); } - const onSubmit = (values: z.infer) => { if (values.chckYr === "") { @@ -160,7 +158,6 @@ export default function ChkgdExcel({ type }: { type: string }) { }); return; } else { - rainChkExcelDataUPload(excelData as rainChkZodType[]); } } else if (type === "RST") { @@ -223,13 +220,13 @@ export default function ChkgdExcel({ type }: { type: string }) { name="file" render={({ field }) => ( - { - if (files) setFiles(files); - }} - fileTypes="xlsx" - > +
+ +
)} /> diff --git a/apps/wr/components/ui/modal/chkgd/chkgdModal/chkgdModal.tsx b/apps/wr/components/ui/modal/chkgd/chkgdModal/chkgdModal.tsx index 4e3d61008..965bc7275 100644 --- a/apps/wr/components/ui/modal/chkgd/chkgdModal/chkgdModal.tsx +++ b/apps/wr/components/ui/modal/chkgd/chkgdModal/chkgdModal.tsx @@ -39,7 +39,6 @@ export default function ChkgdModal({ type, obj }: { type: string; obj: any }) { "4": [] as z.infer[], }); - const { rainChk, ruseHeadList, splHeadList } = rainChkgdn; const [updateData, setUpdateData] = useState(); const initStats = (): z.infer => ({ @@ -97,7 +96,6 @@ export default function ChkgdModal({ type, obj }: { type: string; obj: any }) { target = { utztnUsgCd: code, ruseTotal: 0, splTotal: 0 }; acc.push(target); } - // 월별 값 누적 target[ruseMonthKey] = (target[ruseMonthKey] ?? 0) + ruseValue; target[splMonthKey] = (target[splMonthKey] ?? 0) + splValue; @@ -106,7 +104,18 @@ export default function ChkgdModal({ type, obj }: { type: string; obj: any }) { target.splTotal += splValue; return acc; }, []); - setGuidData(result); + + if (result) { + // '기타' 항목을 배열의 맨 뒤로 정렬합니다. + result.sort((a: splRuseWaterType, b: splRuseWaterType) => { + if (a.utztnUsgCd === "기타") return 1; // a를 b 뒤로 보냅니다. + if (b.utztnUsgCd === "기타") return -1; // b를 a 뒤로 보냅니다. + return 0; // 순서를 유지합니다. + }); + } + + console.log("result ", result); + setGuidData(result as splRuseWaterType[]); if (obj.rswtrPollutions) { const resultPolution: Record = { @@ -159,6 +168,14 @@ export default function ChkgdModal({ type, obj }: { type: string; obj: any }) { if (!resultPolution[nodeKey]) { resultPolution[nodeKey] = []; } + + // '기타' 항목을 배열의 맨 뒤로 정렬합니다. + resultPolution[nodeKey].sort((a: any, b: any) => { + if (a.utztnUsgCd === "기타") return 1; // a를 b 뒤로 보냅니다. + if (b.utztnUsgCd === "기타") return -1; // b를 a 뒤로 보냅니다. + return 0; // 순서를 유지합니다. + }); + resultPolution[nodeKey].push(average); }); diff --git a/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx b/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx index 5166b461f..720a73ab4 100644 --- a/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx +++ b/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx @@ -70,10 +70,15 @@ export default function RainChkgdTable({ }, [makeTableData, handleClick]); + useEffect(() =>{ + + + },[rainChkgdn.rainChk]) useEffect(() => { setSelectedIds([])// 셀렉트 초기화를 위한 작업 if (rainChkData) { + const rainChg = rainChkData.map((item: any) => { const bud = tableData([item.building], { code }); return { @@ -82,6 +87,7 @@ export default function RainChkgdTable({ rowspan: item.rainyDetails?.length, }; }); + setMakeTableData(rainChkTableData(rainChg)); } }, [rainChkData, code]); @@ -106,7 +112,6 @@ export default function RainChkgdTable({ ); if (findRain != undefined) { - console.log(findRain) return { ...rd, ph: Number(findRain.ph), diff --git a/apps/wr/public/sample_rainy.xlsx b/apps/wr/public/sample_rainy.xlsx index 73a52d89c..ec7577c51 100644 Binary files a/apps/wr/public/sample_rainy.xlsx and b/apps/wr/public/sample_rainy.xlsx differ