diff --git a/apps/wr/app/matMng/coMng/drgtSttn/page.tsx b/apps/wr/app/matMng/coMng/drgtSttn/page.tsx index 77bbe4a5a..d7c5170b2 100644 --- a/apps/wr/app/matMng/coMng/drgtSttn/page.tsx +++ b/apps/wr/app/matMng/coMng/drgtSttn/page.tsx @@ -1,32 +1,68 @@ "use client"; import { useWrStore } from "@/app/store"; import { btnClass } from "@/app/store/common/code"; -import type { customCoSttnBdst } from "@/app/store/matDmd/coSttn"; +import type { customDrgt } from "@/app/store/matDmd/drgtSttn"; import { drgtHeadListExport } from "@/app/store/matDmd/drgtSttn/headList"; import { excelDownload, getCity } from "@/components/lib/func/commom"; +import DrgtDetailModal from "@/components/ui/modal/coMat/drgtDetailModal"; import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; -import { ContentsDiv, SearchDiv, SearchFormLeft, SearchFormRight, SelectBox, Title, UiTable, type SelectDataType } from "@common/business_components/ui"; +import { ContentsDiv, DateMonthPicker, SearchDiv, SearchFormLeft, SearchFormRight, SelectBox, Title, UiModal, UiTable, type SelectDataType } from "@common/business_components/ui"; +import { MonthPicker } from "@common/business_components/ui/date_month_picker/mothPicker"; import ListDiv from "@common/business_components/ui/list_div"; import { Button, DatePicker, Label } from "@common/components/ui"; -import { useCallback, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; +import { toast, Toaster } from "react-hot-toast"; export default function DrgtSttn() { - const { code, } = useWrStore((state) => state); - const [fromDate, setFromDate] = useState(new Date()); - const [toDate, setToDate] = useState(new Date()); + const { code, drgt, drgtSearch, drgtModalSearch } = useWrStore((state) => state); + const { drgtRes, drgtMoRes } = drgt; + const [fromDate, setFromDate] = useState(); + const [toDate, setToDate] = useState(); const [selectSgg, setSelectSgg] = useState(); const [objSearch, setObjSearch] = useState({ sgg: "", city: "" }); + const [tableData, setTableData] = useState(); + const [selectedSgg, setSelectedSgg] = useState(''); + const [drgtModal, setDrgtModal] = useState<{ + isOpen: boolean; + data: customDrgt | undefined; + }>({ data: undefined, isOpen: false }); - const getSelCity = (val: string | number) => { - const cityValue = String(val); // Ensure val is treated as a string - const data = getCity(cityValue, code.sggCd); - setSelectSgg(data); - setObjSearch({ city: cityValue, sgg: '' }); + const cellClick = (index: number | undefined, headId: string) => { + if (fromDate && toDate) { + drgtModalSearch(fromDate, toDate, drgtRes[index].sggNm); + } else { + toast.error("조회기간을 선택해주세요."); + } + } + + useEffect(() => { + if (drgtMoRes && drgtMoRes.length > 0) { + setDrgtModal({ isOpen: true, data: drgtMoRes }); + } + }, [drgtMoRes]); + + const getCityVal = (val: string, sggCd: SelectDataType[]) => { + const data = sggCd + .filter((item) => String(item.val).substring(0, 2) === val) + .map((item) => ({ + val: item.val, + text: item.text, // 한국어 텍스트 + })); + return data; }; + const getSelCity = (val: string | number) => { + const cityValue = String(val); + const data = getCityVal(cityValue, code.sggCd); + setSelectSgg(data); + + const sggVal = data.length > 0 ? data[0].val : ''; + setSelectedSgg(sggVal); // 시군구 value 세팅 + setObjSearch({ city: cityValue, sgg: sggVal }); + }; const getSgg = (val: string | number) => { - console.log(val); - setObjSearch({ ...objSearch, sgg: String(val) }) + setSelectedSgg(String(val)); + setObjSearch({ ...objSearch, sgg: String(val) }); }; const excelClick = useCallback(() => { @@ -37,6 +73,17 @@ export default function DrgtSttn() { "A1:H1" ); }, []); + + useEffect(() => { + if (fromDate === undefined && toDate === undefined) { + const today = new Date(); + const year = today.getFullYear(); + const month = String(today.getMonth() + 1).padStart(2, '0'); + const formatted = `${year}${month}`; + setFromDate(formatted); + setToDate(formatted); + } + }, [fromDate, toDate]) return ( <> @@ -59,18 +106,41 @@ export default function DrgtSttn() { selectClass={""} selectArray={selectSgg || []} onSelectValue={getSgg} + value={selectedSgg} />
- { if (date) setFromDate(date) }} /> + { + const year = date.slice(0, 4); + let month = date.slice(4); + if (month.length < 2) { + month = month.padStart(2, "0"); + } + const formatted = `${year}${month}`; + setFromDate(formatted); + } + }} + /> ~ - { if (date) setToDate(date) }} /> + { + const year = date.slice(0, 4); + let month = date.slice(4); + if (month.length < 2) { + month = month.padStart(2, "0"); + } + const formatted = `${year}${month}`; + setToDate(formatted); + } + }} + />
@@ -81,7 +151,22 @@ export default function DrgtSttn() {
@@ -116,16 +201,27 @@ export default function DrgtSttn() { { }} + cellClick={(index: number | undefined, headId: string) => { + cellClick(index ?? undefined, headId); + }} onPageChange={() => { }} >
+ { + setDrgtModal({ ...drgtModal, isOpen: !drgtModal.isOpen }); + }} + bodyClass={"w-[50vw] max-w-none h-[80vh]"} + body={} + /> +
) diff --git a/apps/wr/app/store/matDmd/drgtSttn/headList.tsx b/apps/wr/app/store/matDmd/drgtSttn/headList.tsx index 40eae47e3..1741b7456 100644 --- a/apps/wr/app/store/matDmd/drgtSttn/headList.tsx +++ b/apps/wr/app/store/matDmd/drgtSttn/headList.tsx @@ -1,5 +1,19 @@ +import { z } from "zod"; import type { CommonTableProps } from "../../common/type/header"; +export const drgtZod = z.object({ + ctpvCd: z.string().default(''), + sggNm: z.string().default(''), + normal: z.string().default(''), + attention: z.string().default(''), + caution: z.string().default(''), + warning: z.string().default(''), + ranking: z.string().default(''), + year: z.string().default(''), + month: z.string().default(''), + drgtState: z.string().default('') +}) + export const drgtHeadListExport: CommonTableProps[] = [ { id: "ctpvCd", @@ -10,21 +24,13 @@ export const drgtHeadListExport: CommonTableProps[] = [ colSpan: 1, }, { - id: "sggCd", + id: "sggNm", title: "시군구", visible: true, row: 1, rowSpan: 1, colSpan: 1, }, - { - id: "haengjung", - title: "행정동", - visible: true, - row: 1, - rowSpan: 1, - colSpan: 1, - }, { id: "normal", title: "정상(횟수)", @@ -83,16 +89,9 @@ export const drgtDetailHeadListExport: CommonTableProps[] = [ row: 1, rowSpan: 1, colSpan: 1, - },{ - id: "day", - title: "일", - visible: true, - row: 1, - rowSpan: 1, - colSpan: 1, }, { - id: "state", + id: "drgtState", title: "가뭄상태", visible: true, row: 1, diff --git a/apps/wr/app/store/matDmd/drgtSttn/index.tsx b/apps/wr/app/store/matDmd/drgtSttn/index.tsx index edbbc2f28..698ba5984 100644 --- a/apps/wr/app/store/matDmd/drgtSttn/index.tsx +++ b/apps/wr/app/store/matDmd/drgtSttn/index.tsx @@ -1,27 +1,147 @@ +import { fetchType, getFetch } from "@/components/lib/api"; import type { CommonTableProps } from "../../common/type/header"; -import { drgtHeadListExport } from "./headList"; +import { drgtHeadListExport, drgtZod } from "./headList"; +import type { z } from "zod"; const drgtHeadList = drgtHeadListExport; +export type customDrgt = z.infer; + +const drgtRes: customDrgt[] = []; + export type drgtState = { - drgt:{ - drgtHeadList: CommonTableProps[]; - } + drgt: { + drgtHeadList: CommonTableProps[]; + drgtRes: customDrgt[]; + drgtMoRes: customDrgt[]; + } } type drgtActions = { + drgtSearch: (fromDate: string, toDate: string, sido: string, sgg: string) => void + drgtModalSearch: (fromDate: string, toDate: string, sgg: string) => void }; export type drgtType = drgtState & drgtActions; export const drgtStateExport: drgtState = { - drgt: { - drgtHeadList: drgtHeadList, - } + drgt: { + drgtHeadList: drgtHeadList, + drgtRes: drgtRes, + drgtMoRes: drgtRes, + } } export const drgtActionsExport: (set: any) => drgtActions = ( set: any ) => { - return {}; -}; \ No newline at end of file + return { + drgtSearch: async (fromDate: string, toDate: string, sido: string, sgg: string) => { + try { + let searchUrl = ""; + + if (sido === "" || sido === "전체") { + searchUrl = `/il/getDataCount/${fromDate}/${toDate}`; + } else { + searchUrl = `/il/getDataCount/${fromDate}/${toDate}/${sido}/${sgg}`; + } + + console.log("searchUrl", searchUrl); + + const drgtData = await getFetch( + fetchType.WR, + searchUrl + ); + + console.log("drgtRes", drgtData) + + //주의, 관심, 정상 추출 + const statusData = Array.from( + new Set(drgtData.map((e) => e.lvngMfgUswtrDrgtInfo)) + ); + + const statusMap = drgtData.reduce((acc: any, { sggNm, lvngMfgUswtrDrgtInfo: status, countDrgt }: { sggNm: string; lvngMfgUswtrDrgtInfo: string; countDrgt: number }) => { + if (!acc[sggNm]) { + acc[sggNm] = { sggNm, ...Object.fromEntries(statusData.map((e) => [e, 0])) }; + } + acc[sggNm][status] = Number(countDrgt); + return acc; + }, {}); + const data = Object.values(statusMap); + + const formatStatus = data.map((item) => { + const attention = item['관심'] || 0; + const caution = item['주의'] || 0; + return { + sggNm: item.sggNm, + normal: String(item['정상'] || 0), + caution: String(caution), + attention: String(attention), + warning: String(attention + caution), + }; + }); + + const ranking = Array.from( + new Set(formatStatus.map(e => Number(e.warning))) + ).sort((a, b) => b - a); + + const rankData = ranking.reduce((acc, val, idx) => { + acc[val] = idx + 1; + return acc; + }, {}); + + const drgtRes = formatStatus.map(item => ({ + ...item, + warning: String(item.warning), + ranking: rankData[Number(item.warning)], + })); + set((state: drgtState) => { + return { + ...state, + drgt: { + ...state.drgt, + drgtRes: drgtRes, + }, + } + }); + } catch (e) { + console.log(e) + } + }, + drgtModalSearch: async (fromDate: string, toDate: string, sgg: string) => { + try { + const drgtMoData = await getFetch( + fetchType.WR, + `/il/getData/${fromDate}/${toDate}/${sgg}/${sgg}` + ); + + console.log("drgtMoData", drgtMoData) + + const drgtMoRes = drgtMoData.map((item) => { + console.log("item", item) + const year = item.anlsYmd.slice(0, 4); + const month = item.anlsYmd.slice(4, 6); + const drgtState = item.lvngMfgUswtrDrgtInfo; + const sggNm = item.sggNm; + return { + year: year, + month: month, + drgtState: drgtState, + sggNm: sggNm + } + }); + set((state: drgtState) => { + return { + ...state, + drgt: { + ...state.drgt, + drgtMoRes: drgtMoRes, + }, + } + }); + } catch (e) { + console.log(e) + } + }, + } +} \ No newline at end of file diff --git a/apps/wr/components/ui/modal/coMat/drgtDetailModal.tsx b/apps/wr/components/ui/modal/coMat/drgtDetailModal.tsx index a6b05ca77..1be95fae6 100644 --- a/apps/wr/components/ui/modal/coMat/drgtDetailModal.tsx +++ b/apps/wr/components/ui/modal/coMat/drgtDetailModal.tsx @@ -1,48 +1,62 @@ "use client" import { btnClass } from "@/app/store/common/code" +import type { customDrgt } from "@/app/store/matDmd/drgtSttn" import { drgtDetailHeadListExport } from "@/app/store/matDmd/drgtSttn/headList" -import { ContentsDiv, Title, UiTable } from "@common/business_components/ui" +import { excelDownload } from "@/components/lib/func/commom" +import { Title, UiTable } from "@common/business_components/ui" import ListDiv from "@common/business_components/ui/list_div" import { Button } from "@common/components/ui" +import { useCallback, useEffect } from "react" + +export default function DrgtDetailModal({ + data, +}: { + data: customDrgt; +}) { + const excelClick = useCallback(() => { + excelDownload( + [[]], + "우리동네가뭄", + "sample_drgtSttn.xlsx", + "A1:H1" + ); + }, []); -export default function DrgtDetailModal() { return ( <> - -
-
- - <div className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2 "> - <div className="flex flex-row space-x-2"> - <Button - size={"sm"} - className={`${btnClass} green`} - onClick={() => { }} - > - 다운로드 - </Button> - </div> - <div className="grid grid-cols-6 gap-4 "> - <div className="col-span-6"> - <ListDiv> - <UiTable - headName={[]} - tableData={[]} - headlist={drgtDetailHeadListExport} - pageSize={10} - total={10000} - cellClick={(index: number | undefined, headId: string) => { }} - onPageChange={() => { }} - ></UiTable> - </ListDiv> - </div> - </div> + <div className="grid grid-cols-4 gap-4 h-full"> + <div className="col-span-4"> + <div className="flex items-center justify-between"> + <Title title={`우리동네가뭄 상세내용 - ${data[0].sggNm}`} /> + <div className="flex flex-row space-x-2"> + <Button + size={"sm"} + className={`${btnClass} green mt-12`} + onClick={excelClick} + > + 다운로드 + </Button> + </div> + </div> + <hr className="mt-2 mb-2" /> + <div className="grid grid-cols-6 gap-4 "> + <div className="col-span-6"> + <ListDiv> + <UiTable + headName={[]} + tableData={data} + headlist={drgtDetailHeadListExport} + pageSize={10} + total={10000} + cellClick={(index: number | undefined, headId: string) => { }} + onPageChange={() => { }} + ></UiTable> + </ListDiv> </div> </div> </div> - - </ContentsDiv> + </div> </> ) } \ No newline at end of file diff --git a/apps/wr/components/ui/modal/coReg/coRegExcel/coRegExcelModal.tsx b/apps/wr/components/ui/modal/coReg/coRegExcel/coRegExcelModal.tsx index 1fa8fa8f3..34d46043f 100644 --- a/apps/wr/components/ui/modal/coReg/coRegExcel/coRegExcelModal.tsx +++ b/apps/wr/components/ui/modal/coReg/coRegExcel/coRegExcelModal.tsx @@ -1,12 +1,12 @@ import { useWrStore } from "@/app/store"; import { coRegExcel } from "@/app/store/matDmd/coSttn/headList"; import type { customLdrmnt } from "@/app/store/matDmd/ldrmntCoSttn"; -import { excelToLdrmntData, names } from "@/app/store/matDmd/ldrmntCoSttn/excel"; +import { names } from "@/app/store/matDmd/ldrmntCoSttn/excel"; import { filePicked, FileUpload, FormUi, Title } from "@common/business_components/ui"; import { Form, FormField } from "@common/business_components/ui/form"; -import { Button, Input } from "@common/components/ui"; +import { Button } from "@common/components/ui"; import { zodResolver } from "@hookform/resolvers/zod"; -import { useEffect, useState } from "react"; +import { useState } from "react"; import { useForm } from "react-hook-form"; import type { z } from "zod"; @@ -26,34 +26,41 @@ export default function CoRegExcel() { ldrmntDelete(); if (file) { filePicked(file, 0).then((res) => { + //TODO:loading try { - console.log("res", res) let array: { [key: string]: string | number }[] = [] - if (Array.isArray(res)) - res.forEach((item, index) => { + let isError = false; + if (Array.isArray(res)){ + res.some((item, index) => { let object: { [key: string]: string | number } = {} - Object.keys(names).forEach((key) => { + Object.keys(names).some((key) => { if (item && names[key] !== undefined) { - if (key === "공장관리번호") + if (key === "공장관리번호") { item[key] = String(item[key]) - object[names[key] as string] = item[key]; + } else { + object[names[key] as string] = item[key]; + } } - + return false; }) + if(isError === true) + return true; array.push(object) if (index != 0 && index % 5000 == 0) { ldrmntRegData(array); - console.log("array", array) array = [] array.length = 0; - // throw new Error("error") } + return false; }) + } + if(isError === false) ldrmntRegData(array); - console.log("array끝", array) } catch (e) { console.log(e) + alert(e) + return true; } }); @@ -61,47 +68,46 @@ export default function CoRegExcel() { } - return ( - <> - <div> - <Form {...form}> - <form onSubmit={form.handleSubmit(onSubmit)}> - <div> - <Title title={"잠재수요처 등록"}> -
-
-

- {"잠재수요처 파일"} -

+ return ( + <> +
+
+ +
+ +
+
+

+ {"잠재수요처 파일"} +

- -
+ +
-
+
- ( - - { - console.log("files", files) - if (files && files?.length === 1) setFiles(files[0]); - }} - fileTypes="" - maxFiles={1} - > - - )} - /> -
- - -
- - ); - } + ( + + { + if (files && files?.length === 1) setFiles(files[0]); + }} + fileTypes="" + maxFiles={1} + > + + )} + /> +
+ + +
+ + ); +}