Merge commit '19621c17b43c3872c350fc0cf646a4dce9b1a215' into iipbs/wr/dev
iipbs_wr / build (push) Waiting to run

This commit is contained in:
leedj312
2025-06-30 20:19:10 +09:00
5 changed files with 370 additions and 135 deletions
+118 -22
View File
@@ -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<Date>(new Date());
const [toDate, setToDate] = useState<Date>(new Date());
const { code, drgt, drgtSearch, drgtModalSearch } = useWrStore((state) => state);
const { drgtRes, drgtMoRes } = drgt;
const [fromDate, setFromDate] = useState<string>();
const [toDate, setToDate] = useState<string>();
const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>();
const [objSearch, setObjSearch] = useState<objSearchType>({ sgg: "", city: "" });
const [tableData, setTableData] = useState<customDrgt[]>();
const [selectedSgg, setSelectedSgg] = useState<string>('');
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 (
<>
<ContentsDiv>
@@ -59,18 +106,41 @@ export default function DrgtSttn() {
selectClass={""}
selectArray={selectSgg || []}
onSelectValue={getSgg}
value={selectedSgg}
/>
<div className="col-span-5 w-auto">
<div className="flex flex-row items-center">
<Label className="text-xl text-gray-600">조회기간</Label>
<div className="flex flex-row w-1/4">
<DatePicker mode={'single'}
selected={fromDate}
onSelect={(date: Date | undefined) => { if (date) setFromDate(date) }} />
<DateMonthPicker
field={{
value: fromDate,
onChange: (date: string) => {
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);
}
}}
/>
<span>~</span>
<DatePicker mode={'single'}
selected={toDate}
onSelect={(date: Date | undefined) => { if (date) setToDate(date) }} />
<DateMonthPicker
field={{
value: toDate,
onChange: (date: string) => {
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);
}
}}
/>
</div>
</div>
</div>
@@ -81,7 +151,22 @@ export default function DrgtSttn() {
<div className="flex flex-row space-x-2">
<Button
size={"sm"}
onClick={(e) => { }}
onClick={(e) => {
let sidoText = '';
let sggText = '';
if (objSearch?.city.toString().length > 0) {
sidoText = code.cityCd.find((item) => item.val === objSearch?.city)?.text ?? '';
}
if (objSearch?.sgg.toString().length > 1) {
sggText = code.sggCd.find((item) => item.val === objSearch?.sgg)?.text ?? '';
}
if (sidoText === '세종특별자치시') {
sidoText = '세종시';
sggText = sidoText;
}
drgtSearch(fromDate ?? "", toDate ?? "", sidoText, sggText)
}}
>
조회
</Button>
@@ -116,16 +201,27 @@ export default function DrgtSttn() {
<ListDiv>
<UiTable
headName={[]}
tableData={[]}
tableData={drgtRes || []}
headlist={drgtHeadListExport}
pageSize={20}
total={10000}
cellClick={(index: number | undefined, headId: string) => { }}
cellClick={(index: number | undefined, headId: string) => {
cellClick(index ?? undefined, headId);
}}
onPageChange={() => { }}
></UiTable>
</ListDiv>
</div>
</div>
<UiModal
open={drgtModal.isOpen}
onOpenChange={() => {
setDrgtModal({ ...drgtModal, isOpen: !drgtModal.isOpen });
}}
bodyClass={"w-[50vw] max-w-none h-[80vh]"}
body={<DrgtDetailModal data={drgtModal.data} /*formObj={drgtModal.data}*/ />}
/>
<Toaster position="top-center" />
</ContentsDiv>
</>
)
+16 -17
View File
@@ -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,
+129 -9
View File
@@ -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<typeof drgtZod>;
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 {};
};
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)
}
},
}
}
@@ -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 (
<>
<ContentsDiv>
<div className="grid grid-cols-4 gap-4 ">
<div className="col-span-4">
<Title title={"우리동네가뭄 상세내용"} />
<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>
</>
)
}
@@ -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={"잠재수요처 등록"}></Title>
</div>
<div className="flex justify-between">
<h3 className="text-2xl font-bold text-gray-900 mt-1 ml-7">
{"잠재수요처 파일"}
</h3>
return (
<>
<div>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}>
<div>
<Title title={"잠재수요처 등록"}></Title>
</div>
<div className="flex justify-between">
<h3 className="text-2xl font-bold text-gray-900 mt-1 ml-7">
{"잠재수요처 파일"}
</h3>
<Button className="" type="submit" size={"sm"}>
저장
</Button>
</div>
<Button className="" type="submit" size={"sm"}>
저장
</Button>
</div>
<div>
<div>
<FormField
control={form.control}
name="file"
render={({ field }) => (
<FormUi label="">
<FileUpload
files={file ? [file] : []}
setFiles={(files: File[] | null) => {
console.log("files", files)
if (files && files?.length === 1) setFiles(files[0]);
}}
fileTypes=""
maxFiles={1}
></FileUpload>
</FormUi>
)}
/>
</div>
</form>
</Form>
</div>
</>
);
}
<FormField
control={form.control}
name="file"
render={({ field }) => (
<FormUi label="">
<FileUpload
files={file ? [file] : []}
setFiles={(files: File[] | null) => {
if (files && files?.length === 1) setFiles(files[0]);
}}
fileTypes=""
maxFiles={1}
></FileUpload>
</FormUi>
)}
/>
</div>
</form>
</Form>
</div>
</>
);
}