Merge remote-tracking branch 'origin/iipbs_cs' into iipbs_cs

# Conflicts:
#	apps/cs/next.config.ts
This commit is contained in:
2025-06-27 07:46:39 +09:00
215 changed files with 26267 additions and 2608 deletions
-1
View File
@@ -39,7 +39,6 @@
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@faker-js/faker": "^9.5.0",
"@types/js-cookie": "^3.0.6",
"@types/node": "^22.13.1",
"@types/webpack": "^5.28.5",
@@ -77,7 +77,7 @@ function PostPage({ bbsId }: { bbsId: string }) {
isLoading,
refetch,
} = useQuery({
queryKey: [ENDPOINT.BOARD_SERVICE.POSTS_USER, bbsId],
queryKey: [ENDPOINT.BOARD_SERVICE.POSTS_USER, bbsId, pagination],
queryFn: () =>
PostApi.getPostList(parseInt(bbsId), {
...postParams,
+1 -1
View File
@@ -4,7 +4,7 @@ const subDomain =
process.env.NEXT_PUBLIC_SUB_DOMAIN || "http://localhost:13000";
const nextConfig: NextConfig = {
output: 'standalone', // docker image shrink
output: "standalone",
async rewrites() {
return {
beforeFiles: [
+1 -1
View File
@@ -34,6 +34,7 @@
"js-cookie": "^3.0.5",
"lucide-react": "^0.474.0",
"next": "15.3.0",
"next-qrcode": "^2.5.1",
"react-chartjs-2": "^5.3.0",
"react-dnd": "^16.0.1",
"react-hook-form": "^7.54.2",
@@ -44,7 +45,6 @@
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@faker-js/faker": "^9.5.0",
"@types/js-cookie": "^3.0.6",
"@types/node": "^22.13.1",
"@types/webpack": "^5.28.5",
+3 -1
View File
@@ -7,10 +7,11 @@ import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import { ConfirmProvider } from "@frontend-opensource/use-react-hooks";
import { AuthWrapper } from "@/entities/auth";
import { MenuWrapper } from "@/entities/menu";
import { PromptProvider, StoreProvider } from "@/shared/providers";
import { AlertDialog } from "@/shared/ui/alert-dialog";
import { PromptDialog } from "@/shared/ui/prompt-dialog";
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
import { SelectPromptDialog } from "@/shared/ui/select-prompt-dialog";
import { PromptProvider, StoreProvider } from "@/shared/providers";
const AppProvider = ({ children }: Readonly<{ children: React.ReactNode }>) => {
const queryClient = new QueryClient();
@@ -31,6 +32,7 @@ const AppProvider = ({ children }: Readonly<{ children: React.ReactNode }>) => {
<AlertDialog />
<PromptDialog />
<ConfirmDialog />
<SelectPromptDialog />
</AuthWrapper>
</ConfirmProvider>
</PromptProvider>
@@ -0,0 +1,27 @@
import { client } from "@/shared/api";
import { ENDPOINT } from "@/shared/config";
import type {
LoginlogInfo,
LoginlogList,
LoginlogParams,
LoginlogService,
} from "../model/loginlog-interface";
export class LoginlogApiService implements LoginlogService {
public async getLoginlogList(params: LoginlogParams): Promise<LoginlogList> {
const response = await client.get<LoginlogList>(
`${ENDPOINT.USER_SERVICE.LOGINLOG}`,
{ params },
);
return response.data;
}
public async getLoginlogInfo(lgnSn: string): Promise<LoginlogInfo> {
const response = await client.get<LoginlogInfo>(
`${ENDPOINT.USER_SERVICE.LOGINLOG}/${lgnSn}`,
);
return response.data;
}
}
export const LoginlogApi = new LoginlogApiService();
+5
View File
@@ -0,0 +1,5 @@
export { LoginlogApiService } from "./api/loginlog-service";
export type {
Loginlog,
LoginlogParams,
} from "./model/loginlog-interface";
@@ -0,0 +1,37 @@
import type { PageableList, PageableParams } from "@/shared/model";
export interface LoginlogParams extends PageableParams {
lgnSn?: string;
userId?: string;
siteId?: string;
}
export interface Loginlog {
lgnSn: string;
lgnDt: string;
userId: string;
lgnIp: string;
lgnMethodCd: string;
errOcrnYn: string;
lgnErrCd: string;
siteId: string;
}
export interface LoginlogInfo {
lgnSn: string;
lgnDt: string;
userId: string;
lgnIp: string;
lgnMethodCd: string;
errOcrnYn: string;
lgnErrCd: string;
siteId: string;
}
export type LoginlogList = PageableList<Loginlog>;
export interface LoginlogService {
getLoginlogList: (params: LoginlogParams) => Promise<LoginlogList>;
getLoginlogInfo: (lgnSn: string) => Promise<LoginlogInfo>;
}
+1
View File
@@ -13,4 +13,5 @@ export {
type PostUpdateFormData,
type PostService,
} from "./model/post-interface";
export { deleteReasonMessages } from "./model/delete-reason-messages";
export { PostPageGuard } from "./lib/post-page-guard";
@@ -0,0 +1,11 @@
export const deleteReasonMessages = {
"저작권 침해":
"타인의 저작물을 허락 없이 게시하는 경우 저작권 침해로 간주되어 삭제될 수 있습니다.",
명예훼손: "타인의 명예를 훼손하는 내용의 게시물은 삭제될 수 있습니다.",
"개인정보 노출": "타인의 개인정보를 노출하는 게시물도 삭제될 수 있습니다.",
"불법 정보 유통":
"불법적인 상품이나 서비스를 판매하거나 홍보하는 게시물은 삭제될 수 있습니다.",
"욕설 및 비방":
"심한 욕설이나 비방, 모욕적인 내용이 포함된 게시물은 삭제될 수 있습니다.",
"광고성 정보": "지나치게 광고성이 짙은 게시물은 삭제될 수 있습니다.",
};
+13 -3
View File
@@ -21,20 +21,28 @@ import {
Skeleton,
} from "@common/components";
import { AttachmentApi } from "@/entities/attachment";
import { PostApi, type PostParams } from "@/entities/post";
import {
PostApi,
deleteReasonMessages,
type PostParams,
} from "@/entities/post";
import { AuthorityButton } from "@/entities/menu-authority";
import { ENDPOINT } from "@/shared/config";
import {
useAlertStore,
useMenuStore,
usePrompt,
useSelectPrompt,
useMutationWrapper,
} from "@/shared/lib";
const selectData = Object.entries(deleteReasonMessages).map(
([label, value]) => ({ label, value }),
);
function FaqPage({ bbsId }: { bbsId: string }) {
const router = useRouter();
const pathname = usePathname();
const { prompt } = usePrompt();
const { prompt } = useSelectPrompt(selectData);
const alert = useAlertStore((state) => state.setMessage);
const bbsInfo = useMenuStore((state) => state.bbsInfo);
@@ -75,11 +83,13 @@ function FaqPage({ bbsId }: { bbsId: string }) {
const handleDeletePost = async (pstNo: number) => {
const delRsn = await getPromptValue("삭제 사유를 입력해주세요.");
if (!delRsn) return;
deletePost({ pstNo, delRsn });
};
const onSelectedPostDelete = async () => {
const delRsn = await getPromptValue("삭제 사유를 입력해주세요.");
if (!delRsn) return;
await Promise.all(
selectedPostNumbers.map((pstNo) =>
PostApi.deletePost(parseInt(bbsId), pstNo, delRsn),
@@ -0,0 +1,49 @@
import dayjs from "dayjs";
import type { ColumnDef } from "@tanstack/react-table";
import type { Loginlog } from "@/entities/loginlog";
export const columns: ColumnDef<Loginlog>[] = [
{
id: "no",
header: "NO",
cell: ({ row, table }) => {
const totalRows = table.getRowCount();
const { pageIndex, pageSize } = table.getState().pagination;
return totalRows - (pageIndex * pageSize + row.index);
},
},
{
accessorKey: "lgnDt",
header: "등록일",
cell: ({ row }) => {
const date = dayjs(row.original.lgnDt);
return date.format("YYYY-MM-DD HH24:mi:ss");
},
},
{
accessorKey: "userId",
header: "사용자ID",
},
{
accessorKey: "로그인IP",
header: "remoteIp",
},
{
accessorKey: "lgnMthd",
header: "접속방식",
},
{
accessorKey: "오류여부",
header: "errOcrnYn",
},
{
accessorKey: "오류코드",
header: "lgnErrCd",
},
{
accessorKey: "사이트ID",
header: "siteId",
}
];
@@ -0,0 +1,92 @@
"use client";
import { useState } from "react";
import { keepPreviousData, useQuery } from "@tanstack/react-query";
import {
getCoreRowModel,
useReactTable,
type PaginationState,
} from "@tanstack/react-table";
import { Button, DataTable, Input, Label } from "@common/components";
import { LoginlogApi} from "../../../entities/loginlog/api/loginlog-service";
import { type LoginlogParams} from "../../../entities/loginlog/model/loginlog-interface";
import { ENDPOINT } from "@/shared/config";
import { columns } from "../model/table-columns";
type LoginlogPageProps = {
lgnSn?: string;
};
function LoginlogPage({ }: LoginlogPageProps) {
const [loginlogQuery, setLoginlogQuery] = useState<LoginlogParams>({
userId: "",
siteId: "",
});
const [pagination, setPagination] = useState<PaginationState>({
pageIndex: 0,
pageSize: 10,
});
const { data: loginlogList, refetch } = useQuery({
queryKey: [ENDPOINT.USER_SERVICE.LOGINLOG, , pagination],
queryFn: () =>
LoginlogApi.getLoginlogList({
...loginlogQuery,
page: pagination.pageIndex,
size: pagination.pageSize,
}),
placeholderData: keepPreviousData,
});
const table = useReactTable({
data: loginlogList?.content ?? [],
columns,
rowCount: loginlogList?.totalElements ?? 0,
state: { pagination },
manualPagination: true,
enableMultiRowSelection: false,
getCoreRowModel: getCoreRowModel(),
onPaginationChange: setPagination,
});
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
refetch();
};
return (
<div className="flex-1">
<div className="card card-border">
<form onSubmit={handleSubmit} className="flex items-center gap-2 p-2">
<Label htmlFor="" className="mr-2 text-label">
로그인로그
</Label>
<Input
className="h-[3.2rem] w-[20rem] rounded-sm !text-[1.3rem]"
value={loginlogQuery.userId}
onChange={(e) =>
setLoginlogQuery({
...loginlogQuery,
userId: e.target.value,
})
}
/>
<Button className="h-[3.2rem]" type="submit">
조회
</Button>
</form>
</div>
<div className="card card-border">
<div className="card-header">
<h3 className="text-2xl font-medium text-label">로그인로그 목록</h3>
</div>
<div className="card !m-4 h-[calc(100vh-35rem)] overflow-auto !p-0">
<DataTable table={table} viewPagination />
</div>
</div>
</div>
);
}
export { LoginlogPage };
+12 -1
View File
@@ -75,6 +75,9 @@ function MenuPage() {
queryClient.invalidateQueries({
queryKey: [ENDPOINT.CMS_SERVICE.MENUS, siteId],
});
queryClient.invalidateQueries({
queryKey: [ENDPOINT.CMS_SERVICE.MENU_ROLES],
});
},
});
@@ -91,6 +94,9 @@ function MenuPage() {
queryClient.invalidateQueries({
queryKey: [ENDPOINT.CMS_SERVICE.MENUS, siteId],
});
queryClient.invalidateQueries({
queryKey: [ENDPOINT.CMS_SERVICE.MENU_ROLES],
});
},
});
@@ -101,6 +107,9 @@ function MenuPage() {
queryClient.invalidateQueries({
queryKey: [ENDPOINT.CMS_SERVICE.MENUS, siteId],
});
queryClient.invalidateQueries({
queryKey: [ENDPOINT.CMS_SERVICE.MENU_ROLES],
});
},
});
@@ -118,8 +127,10 @@ function MenuPage() {
menuLnkgTypeCd: menuInfo?.menuLnkgTypeCd ?? MENU_TYPE.EMPTY,
iconNm: menuInfo?.iconName,
otptYn: menuInfo?.otptYn ?? "Y",
evlUseYn: menuInfo?.evlUseYn ?? "Y",
evlUseYn: menuInfo?.evlUseYn ?? "N",
qrcd: menuInfo?.qrcd ?? "N",
useYn: menuInfo?.useYn ?? "Y",
newWndwYn: menuInfo?.newWndwYn ?? "N",
},
});
@@ -0,0 +1,81 @@
import React, { useEffect, useRef, useState } from "react";
import { useQRCode } from "next-qrcode";
import {
Button,
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@common/components";
import { useClipboard } from "@frontend-opensource/use-react-hooks";
function QRCodeDialog({ url }: { url: string }) {
const { Canvas } = useQRCode();
const { copied: isCopied, copyText } = useClipboard();
const canvasRef = useRef<HTMLDivElement>(null);
const [originUrl, setOriginUrl] = useState("");
const qrCodeUrl = originUrl + url;
const handleDownload = () => {
const canvas = canvasRef.current?.querySelector("canvas");
if (!canvas) return;
const url = canvas.toDataURL("image/png");
const link = document.createElement("a");
link.href = url;
link.download = "qr-code.png";
link.click();
};
useEffect(() => {
if (typeof window === "undefined") return;
setOriginUrl(window.location.origin);
}, []);
return (
<Dialog>
<DialogTrigger asChild>
<Button disabled={!url}>QR 조회</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>QR 코드 스캔</DialogTitle>
</DialogHeader>
<div className="flex items-center justify-center p-4">
<div ref={canvasRef}>
<Canvas
text={url}
options={{
errorCorrectionLevel: "M",
margin: 1,
width: 200,
}}
/>
</div>
</div>
<div className="flex items-center justify-between rounded-sm bg-accent p-2 text-[1.3rem] text-accent-foreground">
<p className="break-all px-2">{qrCodeUrl}</p>
<Tooltip open={isCopied}>
<TooltipTrigger asChild>
<button
onClick={() => copyText(qrCodeUrl)}
className="size-10 shrink-0 rounded-sm hover:bg-[rgba(0,0,0,0.1)]"
>
<i className="diveicon di-clipboard" />
</button>
</TooltipTrigger>
<TooltipContent>
<span className="text-base">복사완료</span>
</TooltipContent>
</Tooltip>
</div>
<Button onClick={handleDownload}>QR 코드 다운로드</Button>
</DialogContent>
</Dialog>
);
}
export { QRCodeDialog };
+45 -24
View File
@@ -1,5 +1,5 @@
import dayjs from "dayjs";
import { type UseFormReturn } from "react-hook-form";
import type { UseFormReturn } from "react-hook-form";
import {
DatePicker,
IconFinder,
@@ -21,6 +21,7 @@ import type { MenuFormData, MenuType } from "../model/menu-interface";
import { OrganizationSearchDialog } from "./organization-search-dialog";
import { ContentSearchDialog } from "./content-search-dialog";
import { BoardSearchDialog } from "./board-search-dialog";
import { QRCodeDialog } from "./qrcode-dialog";
type TypeMenuFormProps = {
form: UseFormReturn<MenuFormData>;
@@ -33,6 +34,7 @@ function TypeMenuForm({ form, menuType }: TypeMenuFormProps) {
};
const handleContentSelect = (content: Contents) => {
form.setValue("urlPath", `/cntns/${content.contsSn}`);
form.setValue("menuLnkgSn", content.contsSn);
form.setValue("menuLnkgSnNm", content.contsTtl);
};
@@ -43,6 +45,10 @@ function TypeMenuForm({ form, menuType }: TypeMenuFormProps) {
};
const handleBoardSelect = (board: BoardPopup) => {
form.setValue(
"urlPath",
`/pst/${board.bbsTypeCd.toLowerCase()}/${board.bbsId}`,
);
form.setValue("menuLnkgSn", board.bbsId);
form.setValue("menuLnkgSnNm", board.bbsNm);
};
@@ -52,6 +58,14 @@ function TypeMenuForm({ form, menuType }: TypeMenuFormProps) {
form.setValue("menuPicDsgnYmd", dayjs(date).format("YYYYMMDD"));
};
const getUrlPathPlaceholder = () => {
if (menuType === "CONTENTS") return "콘텐츠 선택 시 자동으로 입력됩니다.";
if (menuType === "BOARD") return "게시판 선택 시 자동으로 입력됩니다.";
if (menuType === "INSIDE")
return "메뉴에 연결된 페이지의 경로를 입력하십시오.";
return "'http://' 또는 'https://'를 포함하여 입력하십시오.";
};
return (
<Table variant="secondary" className="-mt-[0.1rem]">
<colgroup>
@@ -91,7 +105,10 @@ function TypeMenuForm({ form, menuType }: TypeMenuFormProps) {
</TableCell>
</TableRow>
)}
{(menuType === "INSIDE" || menuType === "OUTSIDE") && (
{(menuType === "CONTENTS" ||
menuType === "BOARD" ||
menuType === "INSIDE" ||
menuType === "OUTSIDE") && (
<TableRow>
<TableHead>연결 URL</TableHead>
<TableCell className="border">
@@ -105,10 +122,9 @@ function TypeMenuForm({ form, menuType }: TypeMenuFormProps) {
{...field}
value={field.value ?? ""}
className="!text-[1.3rem]"
placeholder={
menuType === "INSIDE"
? "메뉴에 연결된 페이지의 경로를 입력하십시오."
: "'http://' 또는 'https://'를 포함하여 입력하십시오."
placeholder={getUrlPathPlaceholder()}
disabled={
menuType === "CONTENTS" || menuType === "BOARD"
}
/>
</FormControl>
@@ -293,25 +309,30 @@ function TypeMenuForm({ form, menuType }: TypeMenuFormProps) {
control={form.control}
name="qrcd"
render={({ field }) => (
<FormItem>
<FormControl>
<RadioGroup
value={field.value ?? ""}
onValueChange={field.onChange}
>
<div className="flex items-center space-x-4">
<div className="flex items-center space-x-2">
<RadioGroupItem value="Y" id="qrcdY" />
<Label htmlFor="qrcdY">사용</Label>
<div className="flex items-center gap-4">
<FormItem>
<FormControl>
<RadioGroup
value={field.value ?? ""}
onValueChange={field.onChange}
>
<div className="flex items-center space-x-4">
<div className="flex items-center space-x-2">
<RadioGroupItem value="Y" id="qrcdY" />
<Label htmlFor="qrcdY">사용</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="N" id="qrcdN" />
<Label htmlFor="qrcdN">사용안함</Label>
</div>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="N" id="qrcdN" />
<Label htmlFor="qrcdN">사용안함</Label>
</div>
</div>
</RadioGroup>
</FormControl>
</FormItem>
</RadioGroup>
</FormControl>
</FormItem>
{field.value === "Y" && (
<QRCodeDialog url={form.watch("urlPath") ?? ""} />
)}
</div>
)}
/>
</TableCell>
+7 -2
View File
@@ -23,13 +23,14 @@ import {
} from "@common/components";
import {
PostApi,
deleteReasonMessages,
type DeletePost,
type RecentPost,
type RecentPostParams,
} from "@/entities/post";
import { BoardApi } from "@/entities/board";
import { AuthorityButton } from "@/entities/menu-authority";
import { useAlertStore, usePrompt, useDataTable } from "@/shared/lib";
import { useAlertStore, useSelectPrompt, useDataTable } from "@/shared/lib";
import { ENDPOINT } from "@/shared/config";
import { columns } from "../model/table-columns";
import { MovePostDialog } from "./move-post-dialog";
@@ -39,9 +40,13 @@ type DateRange = {
to?: Date | undefined;
};
const selectData = Object.entries(deleteReasonMessages).map(
([label, value]) => ({ label, value }),
);
function RecentPage() {
const router = useRouter();
const { prompt } = usePrompt();
const { prompt } = useSelectPrompt(selectData);
const { confirm } = useConfirm();
const alert = useAlertStore((state) => state.setMessage);
const [dateRange, setDateRange] = useState<DateRange>();
+1 -1
View File
@@ -19,6 +19,7 @@ export const ENDPOINT = {
AUTHORIZATIONS: "/user-service/api/v1/authorizations",
ROLE_AUTHORIZATIONS: "/user-service/api/v1/role-authorizations",
ROLES: "/user-service/api/v1/roles",
LOGINLOG: "/user-service//api/v1/login-logs",
},
CMS_SERVICE: {
SITES: "/cms-service/api/v1/sites",
@@ -45,7 +46,6 @@ export const ENDPOINT = {
SURVEY_QUESTION: "/cms-service/api/v1/srvy-qitem",
SURVEY_ARTICLE: "/cms-service/api/v1/srvy-artcl",
ZIPS: "/cms-service/api/v1/zips",
LOGINLOG: "/cms-service/api/v1/loginlog",
GROUPS: "/cms-service/api/v1/groups",
GROUP_USERS: "/cms-service/api/v1/group-users",
MANAGER_IP: "/cms-service/api/v1/mgrip",
+1
View File
@@ -5,3 +5,4 @@ export { useDataTable } from "./use-data-table";
export { useMenuStore } from "./use-menu-store";
export { useUserStore } from "./use-user-store";
export { usePrompt } from "./use-prompt";
export { useSelectPrompt } from "./use-select-prompt";
@@ -0,0 +1,48 @@
import { useContext, useEffect } from "react";
import { PromptContext } from "../providers/prompt-provider";
type SelectData = {
label: string;
value: string;
};
export const useSelectPrompt = (data?: SelectData[]) => {
const {
selectData,
selectionGuide,
resolve,
setResolve,
setSelectData,
setSelectionGuide,
} = useContext(PromptContext);
const prompt = (message: string) => {
setSelectionGuide(message);
return new Promise<{ resolved: boolean; value?: string }>((resolve) => {
setResolve(() => resolve);
});
};
const onSubmit = (value: string) => {
resolve?.({ resolved: true, value });
setSelectionGuide("");
};
const onCancel = () => {
resolve?.({ resolved: false });
setSelectionGuide("");
};
useEffect(() => {
if (data) setSelectData(data);
}, [data]);
return {
selectData,
selectionGuide,
isOpen: !!selectionGuide,
prompt,
onSubmit,
onCancel,
};
};
@@ -1,7 +1,14 @@
import { createContext, useState } from "react";
type SelectData = {
label: string;
value: string;
};
interface PromptContext {
message?: string;
selectData?: SelectData[];
selectionGuide?: string;
resolve?: ({
resolved,
value,
@@ -10,18 +17,26 @@ interface PromptContext {
value?: string;
}) => void;
setMessage: (message: string) => void;
setSelectData: (selectData: SelectData[]) => void;
setSelectionGuide: (message: string) => void;
setResolve: (resolve: () => void) => void;
}
export const PromptContext = createContext<PromptContext>({
message: "",
selectData: [],
selectionGuide: "",
resolve() {},
setMessage() {},
setSelectData() {},
setSelectionGuide() {},
setResolve() {},
});
export const PromptProvider = ({ children }: { children: React.ReactNode }) => {
const [message, setMessage] = useState<string>();
const [selectData, setSelectData] = useState<SelectData[]>([]);
const [selectionGuide, setSelectionGuide] = useState<string>();
const [resolve, setResolve] =
useState<
({ resolved, value }: { resolved: boolean; value?: string }) => void
@@ -29,7 +44,16 @@ export const PromptProvider = ({ children }: { children: React.ReactNode }) => {
return (
<PromptContext.Provider
value={{ message, resolve, setMessage, setResolve }}
value={{
message,
selectData,
selectionGuide,
resolve,
setMessage,
setSelectData,
setSelectionGuide,
setResolve,
}}
>
{children}
</PromptContext.Provider>
+5 -1
View File
@@ -1,4 +1,4 @@
import { useState } from "react";
import { useEffect, useState } from "react";
import {
Button,
Dialog,
@@ -13,6 +13,10 @@ function PromptDialog() {
const { message, isOpen, onSubmit, onCancel } = usePrompt();
const [value, setValue] = useState("");
useEffect(() => {
if (isOpen) setValue("");
}, [isOpen]);
return (
<Dialog open={isOpen} onOpenChange={onCancel}>
<DialogContent aria-describedby={undefined}>
@@ -0,0 +1,68 @@
import { useEffect, useState } from "react";
import {
Button,
Dialog,
DialogContent,
DialogFooter,
DialogClose,
Select,
SelectTrigger,
SelectValue,
SelectContent,
SelectItem,
Textarea,
} from "@common/components";
import { useSelectPrompt } from "../lib/use-select-prompt";
function SelectPromptDialog() {
const { selectData, selectionGuide, isOpen, onSubmit, onCancel } =
useSelectPrompt();
const [value, setValue] = useState("");
useEffect(() => {
if (isOpen) setValue("");
}, [isOpen]);
return (
<Dialog open={isOpen} onOpenChange={onCancel}>
<DialogContent aria-describedby={undefined}>
<div className="flex flex-col gap-6 pb-4 pt-8">
<p className="whitespace-pre-line text-center text-[1.4rem] text-foreground">
{selectionGuide}
</p>
<div className="flex flex-col gap-2">
<Select onValueChange={setValue}>
<SelectTrigger>
<SelectValue placeholder="선택" />
</SelectTrigger>
<SelectContent>
{selectData?.map((data) => (
<SelectItem key={data.value} value={data.value}>
{data.label}
</SelectItem>
))}
</SelectContent>
</Select>
<Textarea
value={value}
className="!text-[1.3rem] !leading-6"
onChange={(e) => setValue(e.target.value)}
/>
</div>
</div>
<DialogFooter className="!justify-center">
<DialogClose asChild>
<Button onClick={() => onSubmit(value)}>확인</Button>
</DialogClose>
<DialogClose asChild>
<Button onClick={onCancel} color="white">
취소
</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
export { SelectPromptDialog };
+7 -2
View File
@@ -1,6 +1,7 @@
import { useRouter, usePathname } from "next/navigation";
import { Button } from "@common/components";
import { useMenuStore, usePrompt, useUserStore } from "@/shared/lib";
import { deleteReasonMessages } from "@/entities/post";
import { useMenuStore, useSelectPrompt, useUserStore } from "@/shared/lib";
type PostActionProps = {
bbsId: string;
@@ -9,10 +10,14 @@ type PostActionProps = {
handleDelete: (delRsn?: string) => Promise<void>;
};
const selectData = Object.entries(deleteReasonMessages).map(
([label, value]) => ({ label, value }),
);
function PostAction({ children, handleDelete }: PostActionProps) {
const router = useRouter();
const pathname = usePathname();
const { prompt } = usePrompt();
const { prompt } = useSelectPrompt(selectData);
const bbsInfo = useMenuStore((state) => state.bbsInfo);
const userInfo = useUserStore((state) => state.userInfo);
+7 -2
View File
@@ -25,19 +25,24 @@ import { AuthorityButton } from "@/entities/menu-authority";
import {
PostApi,
PostPageGuard,
deleteReasonMessages,
type Post,
type PostParams,
} from "@/entities/post";
import { ENDPOINT } from "@/shared/config";
import { useMenuStore, usePrompt } from "@/shared/lib";
import { useMenuStore, useSelectPrompt } from "@/shared/lib";
import { GridViewDataTable } from "@/shared/ui/grid-view-data-table";
import { columns as tableColumns } from "../model/post-table-columns";
import { createColumns as createGridViewColumns } from "../model/grid-view-table-columns";
const selectData = Object.entries(deleteReasonMessages).map(
([label, value]) => ({ label, value }),
);
function PostPage({ bbsId }: { bbsId: string }) {
const router = useRouter();
const pathname = usePathname();
const { prompt } = usePrompt();
const { prompt } = useSelectPrompt(selectData);
const bbsInfo = useMenuStore((state) => state.bbsInfo);
const thumbRefs = useRef<Map<number, string>>(new Map());
-5
View File
@@ -1,5 +0,0 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
+7 -67
View File
@@ -1,70 +1,10 @@
@import "../../../packages/common/components/src/base.css";
@import "@common/assets/styles/base.css";
@import "@common/assets/styles/diveicon.css";
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 0 0% 3.9%;
--card: 0 0% 100%;
--card-foreground: 0 0% 3.9%;
--popover: 0 0% 100%;
--popover-foreground: 0 0% 3.9%;
--primary: 0 0% 9%;
--primary-foreground: 0 0% 98%;
--secondary: 0 0% 96.1%;
--secondary-foreground: 0 0% 9%;
--muted: 0 0% 96.1%;
--muted-foreground: 0 0% 45.1%;
--accent: 0 0% 96.1%;
--accent-foreground: 0 0% 9%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 89.8%;
--input: 0 0% 89.8%;
--ring: 0 0% 3.9%;
--chart-1: 12 76% 61%;
--chart-2: 173 58% 39%;
--chart-3: 197 37% 24%;
--chart-4: 43 74% 66%;
--chart-5: 27 87% 67%;
--radius: 0.5rem
}
.dark {
--background: 0 0% 3.9%;
--foreground: 0 0% 98%;
--card: 0 0% 3.9%;
--card-foreground: 0 0% 98%;
--popover: 0 0% 3.9%;
--popover-foreground: 0 0% 98%;
--primary: 0 0% 98%;
--primary-foreground: 0 0% 9%;
--secondary: 0 0% 14.9%;
--secondary-foreground: 0 0% 98%;
--muted: 0 0% 14.9%;
--muted-foreground: 0 0% 63.9%;
--accent: 0 0% 14.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 14.9%;
--input: 0 0% 14.9%;
--ring: 0 0% 83.1%;
--chart-1: 220 70% 50%;
--chart-2: 160 60% 45%;
--chart-3: 30 80% 55%;
--chart-4: 280 65% 60%;
--chart-5: 340 75% 55%
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}
html,
body {
font-family: "Noto Sans KR", sans-serif;
font-size: 10px;
}
+4
View File
@@ -1,6 +1,8 @@
'use client'
import { BaseLayout } from "@common/components";
import "./globals.css";
import { StoreProvider } from "./store";
import { MainDiv } from "@common/business_components";
export default function RootLayout({
children,
@@ -12,7 +14,9 @@ export default function RootLayout({
<body>
<StoreProvider>
<BaseLayout>
<MainDiv>
{children}
</MainDiv>
</BaseLayout>
</StoreProvider>
</body>
+4
View File
@@ -0,0 +1,4 @@
export default function Loading() {
return <div>페이지 불러오는 중입니다...</div>;
}
+672
View File
@@ -0,0 +1,672 @@
"use client";
import { useWrStore } from "@/app/store";
import {
DmdCoReqSchema,
type DedMatUpdateType,
type DmdCoReqType,
type DmdMatTableType,
} from "@/app/store/matDmd/coMatRvw/type";
import { formH1Class, formTableName } from "@/components/lib/class/comClass";
import {
getCity,
getdmdMatFlag,
tableData,
yearOptions,
} from "@/components/lib/func/commom";
import {
ContentsDiv,
Form,
FormField,
FormUi,
ScrollArea,
SearchDiv,
SearchFormLeft,
SearchFormRight,
SearchInput,
SelectBox,
Title,
UiModal,
UiTable,
type SelectDataType,
} from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import { Button, Input, Label } from "@common/components/ui";
import { useEffect, useRef, useState } from "react";
import { useForm } from "react-hook-form";
import toast, { Toaster } from "react-hot-toast";
import { z } from "zod";
import moment from "moment";
import { usageProcData } from "@/app/store/matDmd/coMatRvw/headList";
import { zodResolver } from "@hookform/resolvers/zod";
import ConCostForm from "@/components/ui/form/coMat/conCostForm/conCostForm";
import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal";
export default function CoMatRvw() {
const { code, coRvw, coMatRvwInit, coMatRvwSearch, coMatRvwInqua } =
useWrStore((state) => state);
const { coMatRvwRes } = coRvw;
//init, sub, match
const initRef = useRef<boolean>(false);
const { coRvwHeadList } = coRvw;
const [pageNation, setPageNatiion] = useState<number>(1);
const [dmdCoNm, setDmdCoNm] = useState<string>("");
const [dmdMatData, setDmdMtaData] = useState<DmdMatTableType[]>([]);
const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>();
const [objSearch, setObjSearch] = useState<objSearchType>({
sgg: "",
city: "",
});
const [fromDate, setFromDate] = useState<string>(
String(new Date().getFullYear())
);
const [toDate, setToDate] = useState<string>(
String(new Date().getFullYear())
);
const [selectData, setSelectData] = useState<DmdCoReqType>(
{} as DmdCoReqType
);
const getSearch = (
startYear: number,
endYear: number,
sggCd: string,
dmdCoNm: string
) => {
if (dmdCoNm.length > 0) {
coMatRvwSearch(
pageNation,
13,
String(startYear),
String(endYear),
sggCd,
dmdCoNm
);
} else {
coMatRvwInqua(pageNation, 13, String(startYear), String(endYear), sggCd);
}
};
const form = useForm<z.infer<typeof DmdCoReqSchema>>({
resolver: zodResolver(DmdCoReqSchema),
});
const TableCellClick = (index: number) => {
console.log(coMatRvwRes);
if (coMatRvwRes && coMatRvwRes[index]) {
setSelectData(coMatRvwRes[index]);
}
};
useEffect(() => {
if (form?.getValues("useUsgCd")) {
form.setValue(
"demandCst.usgPrcsProcs",
usageProcData?.find(
(item) => item.usage === (form?.getValues("useUsgCd") as string)
)?.process ?? ""
);
}
}, [form.watch("useUsgCd")]);
useEffect(() => {
if (coMatRvwRes.length > 0) {
const data = coMatRvwRes?.map((item, index) => {
let flag = "";
flag = getdmdMatFlag(item?.demandMatching?.splyFcltFlg ??"");
return {
...item,
ctpvCd: item.demandCo?.ctpvCd,
sggCd: item.demandCo?.sggCd,
dmdCoNm: item.demandCo?.dmdCoNm,
daddr: item.demandCo?.daddr,
telno: item.demandCo?.telno,
regDt: moment(item?.demandCo?.regDt).format("YYYY-MM-DD"),
splyFcltFlg: flag,
};
});
setDmdMtaData(tableData(data, { code }));
}
}, [coMatRvwRes]);
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 getSgg = (val: string | number) => {
setObjSearch({ ...objSearch, sgg: String(val) });
};
useEffect(() => {
if (!initRef.current) {
coMatRvwInit(1, 13, fromDate, toDate);
initRef.current = true;
}
}, [coMatRvwInit, initRef, fromDate, toDate]);
useEffect(() => {
if (selectData) {
console.log(selectData);
form.reset(selectData);
}
}, [selectData, form]);
return (
<>
<ContentsDiv>
<div className="grid grid-cols-4 gap-4">
<div className="col-span-4">
<Title title={"수요매칭검토"} />
<SearchDiv>
<SearchFormLeft>
<div className="col-span-10 flex flex-row">
<SelectBox
className="col-span-2 w-1/3 h-full text-2xl"
label="시도"
selectClass={""}
selectArray={code.cityCd || []}
onSelectValue={getSelCity}
/>
<SelectBox
className="col-span-2 w-1/3 h-full text-2xl ml-4"
label="시군구"
selectClass={""}
selectArray={selectSgg || []}
onSelectValue={getSgg}
/>
<div className="col-span-7 w-full">
<div className="flex flex-row items-center">
<Label className="text-xl text-gray-600 mx-6">
하수 재이용년도
</Label>
<SelectBox
className="h-full w-32 text-2xl"
label=""
selectClass={""}
selectArray={yearOptions}
value={fromDate}
onSelectValue={(val: string | number) =>
setFromDate(String(val))
}
/>
<span className="mx-6">~</span>
<SelectBox
className="h-full w-32 text-2xl"
label=""
selectClass={""}
selectArray={yearOptions}
value={toDate}
onSelectValue={(val: string | number) =>
setToDate(String(val))
}
/>
<div className="col-span-2 ml-6">
<SearchInput
className={"text-2xl"}
label="회사명"
textValue={dmdCoNm}
setText={setDmdCoNm}
/>
</div>
</div>
</div>
</div>
</SearchFormLeft>
<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) => {
if (fromDate && toDate) {
const fromNum = Number(fromDate);
const toNum = Number(toDate);
if (fromNum > toNum) {
toast.error(
"시작년도가 종료년도 이후로 설정할 수 없습니다."
);
} else {
let con: string | number = "";
if (String(objSearch.city).length > 0) {
con = String(objSearch.city);
}
if (String(objSearch.sgg).length > 0 && String(objSearch.sgg) !== "0") {
con = String(objSearch.sgg);
}
getSearch(fromNum, toNum, con, dmdCoNm);
}
}
}}
>
조회
</Button>
</div>
</div>
</SearchFormRight>
</SearchDiv>
</div>
</div>
<div className="grid grid-cols-6 g ap-4">
<div className="col-span-6">
<ListDiv>
<UiTable
headName={"수요매칭검토현황"}
tableData={dmdMatData || []}
headlist={coRvwHeadList}
pageSize={20}
total={100000}
cellClick={(index: number | undefined, headId: string) => {
if (index !== undefined && index >= 0) {
TableCellClick(index);
}
}}
onPageChange={() => {}}
></UiTable>
</ListDiv>
<hr />
<ScrollArea className="h-[49vh]">
<ListDiv>
<h3 className="mt-4 ml-2 text-2xl font-medium text-label">
수요신청 상세현황
</h3>
<Form {...form}>
<div className="grid grid-cols-12 gap-4 ml-4 mr-4">
<div className="col-span-3 mt-4">
<FormField
control={form.control}
name="demandCo.regDt"
render={({ field }) => (
<FormUi label="요구시기">
<Input
placeholder=""
type="text"
onChange={(e) => {
field.onChange(String(e.target.value));
}}
value={
moment(field.value).format("YYYY-MM-DD") ?? ""
}
readOnly
/>
</FormUi>
)}
/>
</div>
<div className="col-span-3 mt-4">
<FormField
control={form.control}
name="dmndQty"
render={({ field }) => (
<FormUi label="요구수량(M3/d)">
<Input
placeholder=""
type="number"
step="0.1"
onChange={(e) => {
field.onChange(Number(e.target.value));
}}
value={field.value ?? 0}
readOnly
/>
</FormUi>
)}
/>
</div>
<div className="col-span-3 mt-4">
<FormField
control={form.control}
name="useUsgCd"
render={({ field }) => (
<FormUi label="사용용도">
<Input
placeholder=""
type="text"
step="0.1"
onChange={(e) => {
field.onChange(e.target.value);
}}
value={field.value ?? ""}
readOnly
/>
</FormUi>
)}
/>
</div>
<div className="col-span-3 mt-4">
<FormField
control={form.control}
name="wntUntprc"
render={({ field }) => (
<FormUi label="희망단가(원/m3)">
<Input
placeholder=""
type="number"
step="0.1"
onChange={(e) => {
field.onChange(Number(e.target.value));
}}
value={field.value ?? 0}
readOnly
/>
</FormUi>
)}
/>
</div>
<div className="col-span-12 w-full">
<h1 className={formH1Class}>요구수질</h1>
</div>
<div className="col-span-3 mt-4">
<FormField
control={form.control}
name="grssClfg"
render={({ field }) => (
<FormUi label="총대장균군수 (개/100ml)">
<Input
placeholder=""
type="number"
step="0.1"
onChange={(e) => {
field.onChange(Number(e.target.value));
}}
value={field.value ?? 0}
readOnly
/>
</FormUi>
)}
/>
</div>
<div className="col-span-3 mt-4">
<FormField
control={form.control}
name="combResdch"
render={({ field }) => (
<FormUi label="결합잔류염소(mg/L)">
<Input
placeholder=""
type="number"
step="0.1"
onChange={(e) => {
field.onChange(Number(e.target.value));
}}
value={field.value ?? 0}
readOnly
/>
</FormUi>
)}
/>
</div>
<div className="col-span-3 mt-4">
<FormField
control={form.control}
name="trbt"
render={({ field }) => (
<FormUi label="탁도(NTU)">
<Input
placeholder=""
type="number"
step="0.1"
onChange={(e) => {
field.onChange(Number(e.target.value));
}}
value={field.value ?? 0}
readOnly
/>
</FormUi>
)}
/>
</div>
<div className="col-span-3 mt-4">
<FormField
control={form.control}
name="blgcOxygDmndQnt"
render={({ field }) => (
<FormUi label="생물학적 산소요구량(BOD)(mg/L)">
<Input
placeholder=""
type="number"
step="0.1"
onChange={(e) => {
field.onChange(Number(e.target.value));
}}
value={field.value ?? 0}
readOnly
/>
</FormUi>
)}
/>
</div>
<div className="col-span-3 mt-4">
<FormField
control={form.control}
name="smll"
render={({ field }) => (
<FormUi label="냄새">
<Input
placeholder=""
type="number"
step="0.1"
onChange={(e) => {
field.onChange(Number(e.target.value));
}}
value={field.value ?? 0}
readOnly
/>
</FormUi>
)}
/>
</div>
<div className="col-span-3 mt-4">
<FormField
control={form.control}
name="crmty"
render={({ field }) => (
<FormUi label="색도(도)">
<Input
placeholder=""
type="number"
step="0.1"
onChange={(e) => {
field.onChange(Number(e.target.value));
}}
value={field.value ?? 0}
readOnly
/>
</FormUi>
)}
/>
</div>
<div className="col-span-3 mt-4">
<FormField
control={form.control}
name="tn"
render={({ field }) => (
<FormUi label="총질소 (T-N)(mg/L)">
<Input
placeholder=""
type="number"
step="0.1"
onChange={(e) => {
field.onChange(Number(e.target.value));
}}
value={field.value ?? 0}
readOnly
/>
</FormUi>
)}
/>
</div>
<div className="col-span-3 mt-4">
<FormField
control={form.control}
name="tph"
render={({ field }) => (
<FormUi label="총인(T-P)(mg/L)">
<Input
placeholder=""
type="number"
step="0.1"
onChange={(e) => {
field.onChange(Number(e.target.value));
}}
value={field.value ?? 0}
readOnly
/>
</FormUi>
)}
/>
</div>
<div className="col-span-3 mt-4">
<FormField
control={form.control}
name="ph"
render={({ field }) => (
<FormUi label="수소이온농도(pH)">
<Input
placeholder=""
type="number"
step="0.1"
onChange={(e) => {
field.onChange(Number(e.target.value));
}}
value={field.value ?? 0}
readOnly
/>
</FormUi>
)}
/>
</div>
<div className="col-span-3 mt-4">
<FormField
control={form.control}
name="clIonQnt"
render={({ field }) => (
<FormUi label="염화물(mgCL/L)">
<Input
placeholder=""
type="number"
step="0.1"
onChange={(e) => {
field.onChange(Number(e.target.value));
}}
value={field.value ?? 0}
readOnly
/>
</FormUi>
)}
/>
</div>
<div className="col-span-3 mt-4">
<FormField
control={form.control}
name="cdtnv"
render={({ field }) => (
<FormUi label="전기전도도(㎲/cm)">
<Input
placeholder=""
type="number"
onChange={(e) => {
field.onChange(Number(e.target.value));
}}
value={field.value ?? 0}
readOnly
/>
</FormUi>
)}
/>
</div>
<div className="col-span-3 mt-4">
<FormField
control={form.control}
name="rmrk"
render={({ field }) => (
<FormUi label="비고">
<Input
placeholder=""
type="text"
onChange={(e) => {
field.onChange(e.target.value);
}}
value={field.value ?? ""}
readOnly
/>
</FormUi>
)}
/>
</div>
<div className="col-span-12 w-full">
<h1 className={formH1Class}>공급처 후보지</h1>
</div>
<div className="col-span-4 mt-4">
<FormField
control={form.control}
name={`demandMatching.splyCndtList.${0}`}
render={({ field }) => (
<FormUi label="후보지1">
<Input
placeholder=""
type="text"
onChange={(e) => {
field.onChange(String(e.target.value));
}}
value={field.value ?? ""}
readOnly
/>
</FormUi>
)}
/>
</div>
<div className="col-span-4 mt-4">
<FormField
control={form.control}
name={`demandMatching.splyCndtList.${1}`}
render={({ field }) => (
<FormUi label="후보지2">
<Input
placeholder=""
type="text"
onChange={(e) => {
field.onChange(e.target.value);
}}
value={field.value ?? ""}
readOnly
/>
</FormUi>
)}
/>
</div>
<div className="col-span-4 mt-4">
<FormField
control={form.control}
name={`demandMatching.splyCndtList.${2}`}
render={({ field }) => (
<FormUi label="후보지3">
<Input
placeholder=""
type="text"
onChange={(e) => {
field.onChange(e.target.value);
}}
value={field.value ?? ""}
readOnly
/>
</FormUi>
)}
/>
</div>
</div>
</Form>
<ConCostForm form={form} type={"mat"} />
</ListDiv>
</ScrollArea>
</div>
</div>
</ContentsDiv>
<Toaster position="top-center" />
</>
);
}
@@ -0,0 +1,126 @@
"use client";
import { useWrStore } from "@/app/store";
import { ruseUtzType } from "@/app/store/matDmd/ruseCaseMng/headList";
import { getCity } from "@/components/lib/func/commom";
import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal";
import { ContentsDiv, SearchDiv, SearchFormLeft, SearchFormRight, SearchInput, SelectBox, Title, UiTable, type SelectDataType } from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import { Button } from "@common/components/ui";
import { useState } from "react";
export default function RuseCaseMng() {
const { code,ruseCase} = useWrStore((state) => state);
const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>()
const [objSearch, setObjSearch] = useState<objSearchType>({ sgg: "", city: "" });
const [selectUtz, setSelectUtz] = useState<string[] | []>()
const [searchTxt, setSearchTxt] = useState<string>()
const getSelCity = (val: string | number) => {
const cityValue = String(val);
const data = getCity(cityValue, code.sggCd);
setSelectSgg(data);
setObjSearch({ city: cityValue, sgg: '' });
};
const getSgg = (val: string | number) => {
setObjSearch({ ...objSearch, sgg: String(val) })
};
return (
<>
<ContentsDiv>
<div className="grid grid-cols-4 gap-4">
<div className="col-span-4">
<Title title={"물재이용사례 관리"} />
<SearchDiv>
<SearchFormLeft>
<div className="col-span-8 flex flex-row">
<SelectBox
className="col-span-2 w-1/3 h-full text-2xl"
label="시도"
selectClass={""}
selectArray={code.cityCd || []}
onSelectValue={getSelCity}
/>
<SelectBox
className="col-span-2 w-1/3 h-full text-2xl"
label="시군구"
selectClass={""}
selectArray={selectSgg || []}
onSelectValue={getSgg}
/>
<SelectBox
className="col-span-2 w-1/3 h-full text-2xl"
label="용도"
selectClass={""}
selectArray={ruseUtzType}
onSelectValue={(val) => {
if(val)
setSelectUtz([String(val)])}}
/>
<SearchInput
className={"text-2xl"}
label="수요처명"
textValue={""}
setText={(e) => {
setSearchTxt(e)
}}
/>
</div>
</SearchFormLeft>
<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>
<Button
size={"sm"}
onClick={(e) => { }}
>
엑셀등록
</Button>
<Button
size={"sm"}
onClick={(e) => { }}
>
다운로드
</Button>
<Button
size={"sm"}
onClick={(e) => { }}
>
양식받기
</Button>
</div>
</div>
</SearchFormRight>
</SearchDiv>
</div>
</div>
<div className="grid grid-cols-6 gap-4 ">
<div className="col-span-6">
<ListDiv className="overflow-x-auto">
<UiTable
headName={"물재이용사례 현황"}
tableData={[]}
children={undefined}
headlist={ruseCase.ruseHeadList}
pageSize={20}
total={100000}
cellClick={(index: number | undefined, headId: string) => {
}}
onPageChange={() => { }}
></UiTable>
</ListDiv>
</div>
</div>
</ContentsDiv>
</>
)
}
@@ -0,0 +1,338 @@
"use client";
import { useWrStore } from "@/app/store";
import {
DmdCoReqSchema,
type DmdCoReqType,
type RvwHistTableType,
} from "@/app/store/matDmd/coMatRvw/type";
import {
getCity,
getdmdMatFlag,
yearOptions,
} from "@/components/lib/func/commom";
import ConCostForm from "@/components/ui/form/coMat/conCostForm/conCostForm";
import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal";
import {
ContentsDiv,
SearchDiv,
SearchFormLeft,
SearchFormRight,
SearchInput,
SelectBox,
Title,
UiTable,
type SelectDataType,
} from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import { Button, DatePicker, Input, Label } from "@common/components/ui";
import { zodResolver } from "@hookform/resolvers/zod";
import moment from "moment";
import { useCallback, useEffect, useState } from "react";
import { set, useFieldArray, useForm } from "react-hook-form";
import { z } from "zod";
import { tableData } from "@/components/lib/func/commom";
import toast, { Toaster } from "react-hot-toast";
import { ToastFormUi } from "@/components/ui/toast/toastFromUi";
export default function RuseRvwHstry() {
const {
code,
ruseHist,
ruseRvwHistInit,
ruseRvwSearch,
ruseRvwInqua,
ruseRvwComplete,
} = useWrStore((state) => state);
const { rvwHistRes, ruseHistHeadList } = ruseHist;
const [pageNation, setPageNatiion] = useState<number>(1);
const [dmdCoNm, setDmdCoNm] = useState<string>("");
const [ruseUtztnFcltNm, setRuseUtztnFcltNm] = useState<string>("");
const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>();
const [objSearch, setObjSearch] = useState<objSearchType>({
sgg: "",
city: "",
});
const [fromDate, setFromDate] = useState<string>(
String(new Date().getFullYear())
);
const [toDate, setToDate] = useState<string>(
String(new Date().getFullYear())
);
const [rvwHistData, setRvwHistData] = useState<RvwHistTableType[]>();
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: "0" });
};
const getSgg = (val: string | number) => {
console.log(val);
setObjSearch({ ...objSearch, sgg: String(val) });
};
const getSearch = (
startYear: number,
endYear: number,
sggCd: string,
dmdCoNm: string,
ruseUtztnFcltNm: string
) => {
if (dmdCoNm || ruseUtztnFcltNm) {
ruseRvwSearch(
pageNation,
13,
String(startYear),
String(endYear),
sggCd,
dmdCoNm,
ruseUtztnFcltNm
);
} else {
ruseRvwInqua(pageNation, 13, String(startYear), String(endYear), sggCd);
}
};
const form = useForm<DmdCoReqType>({
resolver: zodResolver(DmdCoReqSchema),
mode: "onChange",
});
const TableCellClick = useCallback(
(index: number | undefined) => {
if (
index !== undefined &&
index >= 0 &&
rvwHistRes &&
rvwHistRes[index]
) {
form.reset(rvwHistRes[index]);
}
},
[rvwHistRes, form]
);
const confrirmToast = () => {
const completeData = rvwHistData
?.map((item) => {
form.clearErrors;
if (item?.completeYn) {
return Number(item.dmdInfoSn);
}
})
.filter((item) => item !== undefined);
if (form.formState.isDirty) {
toast((t) => (
<span className="flex flex-col items-center">
표준공사비 정보가 변경되었습니다. 검토 완료 진행시 입력한 정보는
초기화 됩니다.
<br />
진행하시겠습니까?
<button
onClick={() => {
toast.dismiss(t.id);
ruseRvwComplete(completeData as Number[]);
}}
>
확인
</button>
<button onClick={() => toast.dismiss(t.id)}>취소</button>
</span>
));
} else {
ruseRvwComplete(completeData as Number[]);
}
};
useEffect(() => {
if (!ruseHist.isInit) {
ruseRvwHistInit(
1,
13,
new Date().getFullYear().toString(),
new Date().getFullYear().toString()
);
}
}, [ruseHist.isInit]);
useEffect(() => {
if (rvwHistRes) {
const data = rvwHistRes?.map((item, index) => {
let flag = "";
flag = getdmdMatFlag(item.demandMatching?.splyFcltFlg ?? "");
return {
...item,
ctpvCd: item.demandCo?.ctpvCd,
sggCd: item.demandCo?.sggCd,
dmdCoNm: item.demandCo?.dmdCoNm,
daddr: item.demandCo?.daddr,
telno: item.demandCo?.telno,
regDt: item?.demandCo?.regDt
? moment(item?.demandCo?.regDt).format("YYYY-MM-DD")
: "없음",
rvwCmptnYmd: item?.rvwCmptnYmd
? moment(item?.rvwCmptnYmd).format("YYYY-MM-DD")
: "없음",
mtchnCmptnYmd: item?.mtchnCmptnYmd
? moment(item?.mtchnCmptnYmd).format("YYYY-MM-DD")
: "없음",
ruseUtztnFcltNm: item.ruseUtztnFcltNm,
dmndQty: item.dmndQty,
splyFcltFlg: flag,
completeYn: false,
} as unknown as RvwHistTableType;
});
setRvwHistData(tableData(data, { code }));
}
}, [rvwHistRes]);
useEffect(() => {
console.log("변경여부 ", form.formState.isDirty);
}, [form.formState]);
return (
<ContentsDiv>
<div className="grid grid-cols-4 gap-4">
<div className="col-span-4">
<Title title={"재이용검토이력"} />
<SearchDiv>
<SearchFormLeft>
<div className="col-span-10 flex flex-row">
<SelectBox
className="w-80 h-full text-2xl"
label="시도"
selectClass={""}
selectArray={code.cityCd || []}
onSelectValue={getSelCity}
>
{""}
</SelectBox>
<SelectBox
className="w-80 h-full text-2xl ml-4"
label="시군구"
selectClass={""}
selectArray={selectSgg || []}
onSelectValue={getSgg}
>
{""}
</SelectBox>
<div className="col-span-4 w-full">
<div className="flex flex-row items-center">
<Label className="text-xl text-gray-600 ml-4 mr-4">
수요신청년도
</Label>
<div className="flex flex-row mt-2">
<SelectBox
className="h-full w-32 text-2xl"
label=""
selectClass={""}
selectArray={yearOptions}
value={fromDate}
onSelectValue={(val: string | number) =>
setFromDate(String(val))
}
/>
<span className="mx-6">~</span>
<SelectBox
className="h-full w-32 text-2xl"
label=""
selectClass={""}
selectArray={yearOptions}
value={toDate}
onSelectValue={(val: string | number) =>
setToDate(String(val))
}
/>
<SearchInput
className={"text-2xl w-60 ml-4 "}
label="시설명"
textValue={ruseUtztnFcltNm}
setText={setRuseUtztnFcltNm}
/>
<SearchInput
className={"text-2xl w-60 ml-4 "}
label="회사명"
textValue={dmdCoNm}
setText={setDmdCoNm}
/>
</div>
</div>
</div>
</div>
</SearchFormLeft>
<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) => {
if (fromDate && toDate) {
const fromNum = Number(fromDate);
const toNum = Number(toDate);
if (fromNum > toNum) {
toast.error(
"시작년도가 종료년도 이후로 설정할 수 없습니다."
);
} else {
let con: string | number = "";
if (String(objSearch.city).length > 0) {
con = String(objSearch.city);
}
if (String(objSearch.sgg).length > 0 && objSearch.sgg !== "0") {
con = String(objSearch.sgg);
}
getSearch(
fromNum,
toNum,
con,
dmdCoNm,
ruseUtztnFcltNm
);
}
}
}}
>
조회
</Button>
<Button size={"sm"} onClick={confrirmToast}>
검토완료
</Button>
</div>
</div>
</SearchFormRight>
</SearchDiv>
</div>
</div>
<div className="grid grid-cols-6 gap-4 ">
<div className="col-span-6">
<ListDiv>
<UiTable
headName={"재이용검토현황"}
tableData={rvwHistData || []}
headlist={ruseHistHeadList}
pageSize={20}
total={100000}
cellClick={(index: number | undefined, headId: string) => {
TableCellClick(index);
}}
onPageChange={setPageNatiion}
></UiTable>
<hr />
<h3 className="mt-4 ml-2 text-2xl font-medium text-label">
수요신청 상세현황
</h3>
<ConCostForm form={form} type={"hist"} />
</ListDiv>
</div>
</div>
<Toaster position="top-center" />
</ContentsDiv>
);
}
+263
View File
@@ -0,0 +1,263 @@
"use client";
import { useWrStore } from "@/app/store";
import { btnClass } from "@/app/store/common/code";
import { fetchType, getFetch } from "@/components/lib/api";
import {
excelDownload,
getCity,
tableData
} from "@/components/lib/func/commom";
import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal";
import { ToastFormUi } from "@/components/ui/toast/toastFromUi";
import {
ContentsDiv,
SearchDiv,
SearchFormLeft,
SearchFormRight,
SearchInput,
SelectBox,
Title,
UiModal,
UiTable,
type SelectDataType,
} from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import SdmInsertForm from "@common/business_components/ui/sdmInsertForm";
import type { DemandCompType } from "@common/business_components/ui/sdmInsertForm/form";
import { Button } from "@common/components/ui";
import { useCallback, useEffect, useState } from "react";
import toast, { Toaster } from "react-hot-toast";
export default function CoSttn() {
const {
code,
coSttn,
coSttnInit,
coSttnSearch,
getDemandCompList,
regDemandCompany,
updateDemandCompany,
coSttnTxtSearch,
demandCompList,
dmdIsSucees
} = useWrStore((state) => state);
const [bdstTable, setBdstTable] = useState<DemandCompType[]>();
const [pageNation, setPageNation] = useState(1);
const { coSttnRes, coSttnResCount } = coSttn;
const [isDmdModal, setIsDmdModal] = useState<{
isMoal: boolean;
data: DemandCompType;
}>({ isMoal: false, data: {} as DemandCompType });
const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>();
const [objSearch, setObjSearch] = useState<objSearchType>({
sgg: "",
city: "",
});
const [seartchTxt, setSearchTxt] = useState<string>();
const [upadateData, setUpdateData] = useState<DemandCompType>();
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 getSgg = (val: string | number) => {
setObjSearch({ ...objSearch, sgg: String(val) });
};
useEffect(() => {
if (!coSttn.isInit) {
coSttnInit("1", "13", "0");
}
}, [coSttn.isInit, coSttnInit]);
useEffect(() => {
if (coSttnRes?.length > 0 && code.cityCd.length > 0) {
const data = tableData(coSttnRes, { code });
const chData = data.map((item: any) => ({
...item,
}));
// .filter((item: any) => item !== undefined);
setBdstTable(chData);
} else if (coSttnRes.length == 0) {
setBdstTable([]);
}
}, [coSttnRes, code]);
useEffect(() => {
if (coSttn.excelList.length > 0) {
if (coSttn.excelList.length === 0) return;
excelDownload(
coSttn.excelList,
"수요처 관리",
"sample_coSttn.xlsx",
"A1:F1",
2
);
}
}, [coSttn.excelList]);
useEffect(() => {
const con = (objSearch.sgg && objSearch.sgg !== "0") ? objSearch.sgg : objSearch.city ? objSearch.city : "0";
if(con){
coSttnSearch(String(pageNation), "13", String(con));
}
}, [coSttnSearch, objSearch.city, objSearch.sgg, pageNation]);
const excelClick = useCallback(() => {
const con = objSearch.sgg ? objSearch.sgg : objSearch.city;
if (con) coSttnSearch("1", "10000", String(con));
}, [coSttnSearch, objSearch.city, objSearch.sgg]);
const searchClick = () => {
const con = (objSearch.sgg && objSearch.sgg !== "0") ? objSearch.sgg : objSearch.city;
if (con) {
if (seartchTxt && seartchTxt?.length > 0) {
coSttnTxtSearch("1", "13", String(con), seartchTxt ?? "");
} else {
coSttnSearch("1", "13", String(con));
}
}
};
return (
<>
<ContentsDiv>
<div className="grid grid-cols-4 gap-4 ">
<div className="col-span-4">
<Title title={"수요처 관리"} />
<SearchDiv>
<SearchFormLeft>
<div className="col-span-10 flex flex-row">
<SelectBox
className="col-span-2 w-1/6 h-full text-2xl"
label="시도"
selectClass={""}
selectArray={code.cityCd || []}
onSelectValue={getSelCity}
/>
<SelectBox
className="col-span-2 w-1/6 h-full text-2xl"
label="시군구"
selectClass={""}
selectArray={selectSgg?selectSgg : [{text:"전체",val:"0"}]}
onSelectValue={getSgg}
/>
<SearchInput
className={"!text-3xl"}
label="회사명"
textValue={seartchTxt ?? ""}
setText={(e) => {
setSearchTxt(e);
}}
/>
</div>
</SearchFormLeft>
<SearchFormRight 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"} onClick={searchClick}>
조회
</Button>
<Button
size={"sm"}
className={btnClass}
onClick={() => {
setUpdateData(undefined);
setIsDmdModal({ ...isDmdModal, isMoal: true });
}}
>
등록
</Button>
<Button
size={"sm"}
className={btnClass}
onClick={() => {
/* 저장 로직 */
if (!upadateData) {
<ToastFormUi body={"수요처 변경을 원하는 행을 선택해주세요"} title={"수요처관리"}></ToastFormUi>;
}else{
setIsDmdModal({
...isDmdModal,
isMoal: true})
}
}}
>
저장
</Button>
<Button
size={"sm"}
className={`${btnClass} green`}
onClick={excelClick}
>
다운로드
</Button>
</div>
</SearchFormRight>
</SearchDiv>
</div>
</div>
<div className="grid grid-cols-6 gap-4 ">
<div className="col-span-6">
<ListDiv>
<UiTable
headName={[]}
tableData={bdstTable || []}
headlist={coSttn.coSttHeadList}
pageSize={bdstTable?.length ? Math.ceil(bdstTable.length / 13) : 0}
total={ coSttnResCount || 0 }
cellClick={(index: number | undefined, headId: string) => {
setUpdateData(coSttnRes[index as number]);
}}
onPageChange={setPageNation}
></UiTable>
</ListDiv>
</div>
</div>
<UiModal
bodyClass={"w-[40vw] max-w-none h-[90vh]"}
open={isDmdModal.isMoal}
onOpenChange={() => {
setIsDmdModal({ isMoal: false, data: {} as DemandCompType });
}}
body={
<SdmInsertForm
selectSidoData={code.cityCd}
selectSigunData={code.sggCd}
dataList={demandCompList}
rtnValue={(searchText: string, pageCnt: number) => {
getDemandCompList(searchText, pageCnt);
}}
rtnInputData={ async(data) => {
if(upadateData?.dmdInfoPk){
updateDemandCompany(data as DemandCompType)
}else{
const dmd= await getFetch(fetchType.WR,`/reuseFc/request/${data.dmdInfoPk}`)
if(dmd) {
toast.error(`사업자번호 ${dmd.dmdInfoPk}는 이미 등록되었습니다. 다시등록해주세요`)
return
}
regDemandCompany(data as DemandCompType);
}
if(dmdIsSucees ==='success'){
toast.success(`수요처 등록 및 수정 완료되었습니다..`)
setIsDmdModal({ isMoal: false, data: data as DemandCompType });
}else{
toast.error(`수요처 등록 및 수정 에러입니다.`)
}
}}
bodyClassNm={"w-full mx-auto bg-white rounded-lg shadow-md p-6"}
updateList={upadateData}
></SdmInsertForm>
}
></UiModal>
</ContentsDiv>
<Toaster position="top-center" />
</>
);
}
+132
View File
@@ -0,0 +1,132 @@
"use client";
import { useWrStore } from "@/app/store";
import { btnClass } from "@/app/store/common/code";
import type { customCoSttnBdst } from "@/app/store/matDmd/coSttn";
import { drgtHeadListExport } from "@/app/store/matDmd/drgtSttn/headList";
import { excelDownload, getCity } from "@/components/lib/func/commom";
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 ListDiv from "@common/business_components/ui/list_div";
import { Button, DatePicker, Label } from "@common/components/ui";
import { useCallback, useState } from "react";
export default function DrgtSttn() {
const { code, } = useWrStore((state) => state);
const [fromDate, setFromDate] = useState<Date>(new Date());
const [toDate, setToDate] = useState<Date>(new Date());
const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>();
const [objSearch, setObjSearch] = useState<objSearchType>({ sgg: "", city: "" });
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 getSgg = (val: string | number) => {
console.log(val);
setObjSearch({ ...objSearch, sgg: String(val) })
};
const excelClick = useCallback(() => {
excelDownload(
[[]],
"우리동네가뭄",
"sample_drgtSttn.xlsx",
"A1:H1"
);
}, []);
return (
<>
<ContentsDiv>
<div className="grid grid-cols-4 gap-4 ">
<div className="col-span-4">
<Title title={"우리동네가뭄"} />
<SearchDiv>
<SearchFormLeft>
<div className="col-span-10 flex flex-row">
<SelectBox
className="col-span-2 w-1/6 h-full text-2xl"
label="시도"
selectClass={""}
selectArray={code.cityCd || []}
onSelectValue={getSelCity}
/>
<SelectBox
className="col-span-2 w-1/6 h-full text-2xl"
label="시군구"
selectClass={""}
selectArray={selectSgg || []}
onSelectValue={getSgg}
/>
<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) }} />
<span>~</span>
<DatePicker mode={'single'}
selected={toDate}
onSelect={(date: Date | undefined) => { if (date) setToDate(date) }} />
</div>
</div>
</div>
</div>
</SearchFormLeft>
<SearchFormRight
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"}
onClick={(e) => { }}
>
조회
</Button>
<Button
size={"sm"}
className={btnClass}
onClick={() => { }}
>
상세보기
</Button>
<Button
size={"sm"}
className={`${btnClass} green`}
onClick={excelClick}
>
다운로드
</Button>
<Button
size={"sm"}
className={btnClass}
onClick={() => { }}
>
지도보기
</Button>
</div>
</SearchFormRight>
</SearchDiv>
</div>
</div>
<div className="grid grid-cols-6 gap-4 ">
<div className="col-span-6">
<ListDiv>
<UiTable
headName={[]}
tableData={[]}
headlist={drgtHeadListExport}
pageSize={20}
total={10000}
cellClick={(index: number | undefined, headId: string) => { }}
onPageChange={() => { }}
></UiTable>
</ListDiv>
</div>
</div>
</ContentsDiv>
</>
)
}
@@ -0,0 +1,293 @@
"use client";
import { useWrStore } from "@/app/store";
import { btnClass } from "@/app/store/common/code";
import { type customLdrmnt } from "@/app/store/matDmd/ldrmntCoSttn";
import { ldrmntHeadListExport, ldrmntNodeListExport } from "@/app/store/matDmd/ldrmntCoSttn/headList";
import {
excelDownload,
getCity,
getCityOrSgg,
tableData
} from "@/components/lib/func/commom";
import CoRegExcel from "@/components/ui/modal/coReg/coRegExcel/coRegExcelModal";
import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal";
import CoDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/coDatailModal";
import {
ContentsDiv,
downloadExcel,
SearchDiv,
SearchFormLeft,
SearchFormRight,
SearchInput,
SelectBox,
Title,
UiModal,
UiTable,
type ReturnType,
type SelectDataType
} from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import { Button } from "@common/components/ui";
import { useCallback, useEffect, useRef, useState } from "react";
export default function LdrmntCoSttn() {
const { code, ldrmnt, ldrmntInit, ldrmntSearch, } = useWrStore(
(state) => state
);
const { ldrmntRes, excelList } = ldrmnt;
const [detailModal, setDetailModal] = useState<{ isOpen: boolean, data: customLdrmnt | undefined }>({ data: undefined, isOpen: false })
const [pageNation, setPageNation] = useState(1);
const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>()
const [objSearch, setObjSearch] = useState<objSearchType>({ sgg: "", city: "" });
const [bdstTable, setBdstTable] = useState<customLdrmnt[]>();
const [searchTxt, setSearchTxt] = useState<string>();
const ref = useRef<ReturnType>({} as ReturnType);
const [excelData, setExcelData] = useState<any[]>();
const excelClick = useCallback(() => {
excelDownload(
[[]],
"잠재수요처 관리",
"sample_ldrmntCoSttn.xlsx",
"A1:AL1",
2
);
}, []);
const excelDownloadClick = () => {
downloadExcel({
data: excelData ?? [],
fileName: "잠재수요처 관리",
sheetNameArray: ["Sheet1"],
headerRange: "A1:F1"
})
}
const [isExcelOpen, setIsExcelOpen] = useState<{
isModal: boolean;
}>({ isModal: false });
const cellClick = (index: number | undefined, headId: string) => {
if (index !== undefined) {
setDetailModal({ isOpen: true, data: ldrmntRes[index] });
}
}
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 getSgg = (val: string | number) => {
setObjSearch({ ...objSearch, sgg: String(val) })
};
useEffect(() => {
if (!ldrmnt.isInit) {
ldrmntInit("0");
}
}, [ldrmnt.isInit, ldrmntInit]);
useEffect(() => {
const transData = Array.isArray(ldrmntRes) ? ldrmntRes : [ldrmntRes];
const data = tableData(transData, { code });
const tbData = Array.isArray(data)
? data.map((item: customLdrmnt) => ({
...item,
ctpvCd: item.fctryAddr.split(" ")[0] || "",
sggCd: item.fctryAddr.split(" ")[1] || ""
}))
: [];
setBdstTable(tbData);
}, [ldrmntRes, code]);
useEffect(() => {
const transData = Array.isArray(excelList) ? excelList : [excelList];
const exData = tableData(transData, { code });
const data = Array.isArray(exData)
? exData.map((item: customLdrmnt) => {
return {
"시도": item.fctryAddr.split(" ")[0] || "",
"시군구": item.fctryAddr.split(" ")[1] || "",
"회사명": item.dmdCoNm,
"공장주소": item.fctryAddr,
"공장관리번호": item.fctryMngNo,
"전화번호": item.telno
}
}) : [];
setExcelData(data)
}, [excelList])
useEffect(() => {
let cityTxt = '';
let sggTxt = '';
if (objSearch?.city.toString().length > 0) {
cityTxt = code.cityCd.find((item) => item.val === objSearch?.city)?.text ?? '';
}
if (objSearch?.sgg.toString().length > 1) {
sggTxt = code.sggCd.find((item) => item.val === objSearch?.sgg)?.text ?? '';
}
let cityNm = "";
if (sggTxt !== "0") {
cityNm = cityTxt + " " + sggTxt;
} else {
cityNm = cityTxt;
}
if (cityNm) {
if (cityTxt === '') cityNm = "0";
ldrmntSearch(pageNation, cityNm, searchTxt || "");
} else {
ldrmntSearch(pageNation, "", searchTxt || "");
}
}, [pageNation, objSearch, code, searchTxt, ldrmntSearch])
return (
<>
<ContentsDiv>
<div className="grid grid-cols-4 gap-4 ">
<div className="col-span-4">
<Title title={"잠재수요처 관리"} />
<SearchDiv>
<SearchFormLeft>
<div className="col-span-10 flex flex-row">
<SelectBox
className="col-span-2 w-1/6 h-full text-2xl"
label="시도"
selectClass={""}
selectArray={code.cityCd}
onSelectValue={getSelCity}
/>
<SelectBox
className="col-span-2 w-1/6 h-full text-2xl ml-4"
label="시군구"
selectClass={""}
selectArray={selectSgg || []}
onSelectValue={getSgg}
/>
<SearchInput
className={"text-2xl ml-4"}
label="회사명"
textValue={searchTxt || ""}
setText={(e) => {
setSearchTxt(e);
}}
/>
</div>
</SearchFormLeft>
<SearchFormRight
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"}
onClick={(e) => {
let cityTxt = ''
let sggTxt = ''
if (objSearch?.city.toString().length > 0) {
cityTxt = code.cityCd.find((item) => item.val === objSearch?.city)?.text ?? '';
}
if (objSearch?.sgg.toString().length > 1) {
sggTxt = code.sggCd.find((item) => item.val === objSearch?.sgg)?.text ?? '';
}
let cityNm = ""
if (sggTxt !== "0") {
cityNm = cityTxt + " " + sggTxt
} else {
cityNm = cityTxt
}
if (cityNm) {
if (cityTxt === '') cityNm = "0";
ldrmntSearch(pageNation, cityNm, searchTxt || "");
}
}}
>
조회
</Button>
<Button
size={"sm"}
className={btnClass}
onClick={() => {
setIsExcelOpen({ isModal: true });
}}
>
엑셀등록
</Button>
<Button
size={"sm"}
className={btnClass}
onClick={() => excelDownloadClick()}
>
다운로드
</Button>
<Button
size={"sm"}
className={`${btnClass} green`}
onClick={excelClick}
>
양식받기
</Button>
</div>
</SearchFormRight>
</SearchDiv>
</div>
</div>
<div className="grid grid-cols-6 gap-4 ">
<div className="col-span-6">
<div className="overflow-x-auto">
<ListDiv className="min-w-max">
<UiTable
headName={[]}
tableData={bdstTable || []}
headlist={ldrmntHeadListExport}
pageSize={20}
total={10000}
cellClick={(index: number | undefined, headId: string) => { cellClick(index ?? undefined, headId) }}
onPageChange={setPageNation}
/>
</ListDiv>
</div>
</div>
<UiModal
open={detailModal.isOpen}
onOpenChange={() => {
setDetailModal({ ...detailModal, isOpen: !detailModal.isOpen })
}}
bodyClass={"w-[40vw] max-w-none max-h-[calc(100%-70px)]"}
body={<CoDetailModal formObj={detailModal.data} />}
/>
<UiModal
open={isExcelOpen.isModal}
onOpenChange={() => {
setIsExcelOpen({ isModal: !isExcelOpen.isModal })
}}
bodyClass={"w-[40vw] max-w-none"}
body={<CoRegExcel />}
/>
</div>
</ContentsDiv>
</>
)
}
-84
View File
@@ -1,84 +0,0 @@
"use client";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import * as z from "zod";
import {
Form,
FormField,
FormUi,
ScrollArea,
SelectBox,
} from "@common/business_components/ui";
import { Button } from "@common/components/ui";
import { CoRegForm } from "@/components/ui/matDmd/coRegForm/component";
import toast, { Toaster } from "react-hot-toast";
import { ToastFormUi } from "@/components/toastFromUi";
const formSchema = z.object({
ctpv: z.string(),
sgg: z.string(),
coNm: z.string().min(1).max(20),
bznmNo: z.string().min(1).min(9).max(12),
addr: z.string().min(1).min(6).max(20),
telNo: z.string().min(8).max(12),
});
export default function MyForm() {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
coNm:'',
bznmNo:'',
addr:'',
telNo:'',
},
});
function onSubmit(values: z.infer<typeof formSchema>) {
try {
toast.dismiss();
ToastFormUi("수요신청 화면으로 이동하시겠습니까?", "수요처 등록 완료", "./dmdReg", "이동")
} catch (error) {
console.error("Form submission error", error);
toast.error("수요처 등록이 실패하였습니다.");
}
}
return (
<>
<div className="grid h-40 grid-cols-3 place-content-center">
<h1 className=" col-start-2 col-span-1 text-4xl underline">
수요처 정보입력
</h1>
</div>
<div className="grid grid-cols-5 gap-4 overflow-hidden">
<div className="col-span-1 "/>
<div className="col-span-3 ">
<div>
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="space-y-8 max-w-3xl mx-auto"
>
<CoRegForm>{form}</CoRegForm>
<Button type="submit">수요처등록</Button>
</form>
</Form>
</div>
</div>
<div className="col-span-1 " >
<Toaster position="top-center" />
</div>
</div>
</>
);
}
-106
View File
@@ -1,106 +0,0 @@
"use client";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import * as z from "zod";
import { Form } from "@common/business_components/ui";
import { Button } from "@common/components/ui";
import { DmdRegForm } from "@/components/ui/matDmd/dmdRegform/component";
import toast, { Toaster } from "react-hot-toast";
import { useRouter } from "next/navigation";
const formSchema = z.object({
dmdSel: z.string().min(1),
dmdTmng: z.coerce.date(),
dmdWq: z.string().min(1).optional(),
useUsgCd: z.string(),
wntUntprc: z.string().min(1),
grssClfg: z.string().min(1),
tn: z.string().min(1).optional(),
combResdch: z.string().min(1).optional(),
tp: z.string().min(1).optional(),
trbt: z.string().min(1).optional(),
ph: z.string().min(1).optional(),
bod: z.string().min(1).optional(),
clIonQnt: z.string().min(1).optional(),
smll: z.string().min(1).optional(),
cdtnv: z.string().min(1).optional(),
crmty: z.string().min(1).optional(),
rmrk: z.string().min(1).optional(),
sply1: z.string().min(1).optional(),
sply2: z.string().min(1).optional(),
sply3: z.string().min(1).optional(),
password: z.string().min(1),
});
export default function MyForm() {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
dmdSel:'',
dmdTmng: new Date(),
dmdWq: "",
useUsgCd: "",
wntUntprc: "",
grssClfg: "",
tn: "",
combResdch: "",
tp: "",
trbt: "",
ph: "",
bod: "",
clIonQnt: "",
smll: "",
cdtnv: "",
crmty: "",
rmrk: "",
sply1: "",
sply2: "",
sply3: "",
password: "",
},
});
const router = useRouter();
async function onSubmit(values: z.infer<typeof formSchema>) {
try {
toast.success("✅ 수요신청이 완료되었습니다.");
await new Promise((resolve) => setTimeout(resolve, 3000));
router.push("../../")
} catch (error) {
toast.error("수요신청을 다시입력해주시길 바랍니다.");
}
}
return (
<>
<div className="grid h-40 grid-cols-3 place-content-center">
<h1 className=" col-start-2 col-span-1 text-4xl underline">
수요 신청정보입력
</h1>
</div>
<div className="grid grid-cols-5 gap-4 overflow-hidden">
<div className="col-span-1 " />
<div className="col-span-3 max-h-[78vh] overflow-y-scroll ">
<div>
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="space-y-8 max-w-3xl mx-auto"
>
<DmdRegForm> {form}</DmdRegForm>
<Button type="submit"> 수요신청</Button>
</form>
</Form>
</div>
</div>
<div className="col-span-1 ">
<Toaster position="top-center" />
</div>
</div>
</>
);
}
+151 -18
View File
@@ -1,26 +1,159 @@
import Link from 'next/link';
import { Button } from '@common/components/ui';
"use client";
import { Button } from "@common/components/ui";
import { useRouter } from "next/navigation";
export default function Home() {
const router = useRouter();
return (
<>
<div className='flex'>
<Button className='place-self-auto'>
<Link href="reuseFaciltyManage/reuseFacilityInsert/publicReuseFaciltyInsert"> 하수재이용 시설 등록</Link>
</Button>
<Button className='place-self-auto'>
<Link href="reuseFaciltyManage/reuseFacilityInsert/rainReuseFaciltyInsert"> 빗물재이용 시설 등록</Link>
</Button>
<Button className='place-self-auto'>
<Link href="reuseFaciltyManage/reuseFacilityInsert/rswtReuseFacilityInsert"> 중수도시설 등록</Link>
</Button>
<div className="flex flex-col gap-8 p-6">
{/* 시설 등록 */}
<div>
<h2 className="text-xl font-semibold mb-4">시설 등록</h2>
<div className="grid grid-cols-12 gap-4">
<div className="col-span-2">
<Button className="w-full" onClick={() => {router.push('/ruseFcltMng/fcltReg/pbnstReg')}}>
하수재이용 시설 등록
</Button>
</div>
<div className="col-span-2">
<Button className="w-full" onClick={() => {router.push('/ruseFcltMng/fcltReg/rainReg')}}>
빗물재이용 시설 등록
</Button>
</div>
<div className="col-span-2">
<Button className="w-full" onClick={() => {router.push('/ruseFcltMng/fcltReg/rswtReg')}}>
중수도시설 등록
</Button>
</div>
<div className="col-span-2">
<Button className="w-full" onClick={() => {router.push('/ruseFcltMng/fcltReg/htdflReg')}}>
온배수시설 등록
</Button>
</div>
</div>
</div>
<Button className='place-self-auto'>
<Link href="matMng/matDmd/coReg">수요처 등록</Link>
</Button>
{/* 지도점검 결과 */}
<div>
<h2 className="text-xl font-semibold mb-4">지도점검 결과</h2>
<div className="grid grid-cols-12 gap-4">
<div className="col-span-2">
<Button className="w-full" onClick={() => {router.push('/ruseFcltMng/prfmncReg/pbnstPrfmncReg')}}>
하수재이용실적 등록
</Button>
</div>
<div className="col-span-2">
<Button className="w-full" onClick={() => {router.push('/ruseFcltMng/prfmncSttn/pbnstPrfmncSttn')}}>
하수재이용실적 현황
</Button>
</div>
<div className="col-span-2">
<Button className="w-full" onClick={() => {router.push('/ruseFcltMng/prfmncReg/chkgdnReg')}}>
지도점검 결과 등록
</Button>
</div>
<div className="col-span-2">
<Button className="w-full" onClick={() => {router.push('/ruseFcltMng/prfmncSttn/chkgdnSttn')}}>
지도점검 결과 현황
</Button>
</div>
</div>
</div>
{/* 시설 현황 */}
<div>
<h2 className="text-xl font-semibold mb-4">시설 현황</h2>
<div className="grid grid-cols-12 gap-4">
<div className="col-span-2">
<Button className="w-full" onClick={() => {router.push('/ruseFcltMng/fcltSttn/pbnstSttn')}}>
하수재이용시설현황
</Button>
</div>
<div className="col-span-2">
<Button className="w-full" onClick={() => {router.push('/ruseFcltMng/fcltSttn/rainSttn')}}>
빗물재이용시설현황
</Button>
</div>
<div className="col-span-2">
<Button className="w-full" onClick={() => {router.push('/ruseFcltMng/fcltSttn/rswtSttn')}}>
중수도이용시설현황
</Button>
</div>
<div className="col-span-2">
<Button className="w-full" onClick={() => {router.push('/ruseFcltMng/fcltSttn/htdflSttn')}}>
온배수현황
</Button>
</div>
</div>
</div>
{/* 수요처 관리 */}
<div>
<h2 className="text-xl font-semibold mb-4">수요처 관리</h2>
<div className="grid grid-cols-12 gap-4">
<div className="col-span-2">
<Button className="w-full" onClick={() => {router.push('/matMng/coMng/coSttn')}}>
수요처 관리
</Button>
</div>
<div className="col-span-2">
<Button className="w-full" onClick={() => {router.push('/matMng/coMng/ldrmntCoSttn')}}>
잠재수요처 관리
</Button>
</div>
<div className="col-span-2">
<Button className="w-full" onClick={() => {router.push('/matMng/coMng/drgtSttn')}}>
우리동네가뭄
</Button>
</div>
</div>
</div>
{/* 수요처 매칭 */}
<div>
<h2 className="text-xl font-semibold mb-4">수요처 매칭</h2>
<div className="grid grid-cols-12 gap-4">
<div className="col-span-2">
<Button className="w-full" onClick={() => {router.push('/matMng/coMat/coMatRvw')}}>
수요처 매칭 검토
</Button>
</div>
<div className="col-span-2">
<Button className="w-full" onClick={() => {router.push('/matMng/coMat/ruseRvwHstry')}}>
재이용검토이력
</Button>
</div>
<div className="col-span-2">
<Button className="w-full" onClick={() => {router.push('/matMng/coMat/ruseCaseMng')}}>
물재이용사례 관리
</Button>
</div>
</div>
</div>
{/* 통계*/}
<div>
<h2 className="text-xl font-semibold mb-4">통계 매칭</h2>
<div className="grid grid-cols-12 gap-4">
<div className="col-span-2">
<Button className="w-full" onClick={() => {router.push('/stats/rainStat')}}>
빗물재이용시설통계
</Button>
</div>
<div className="col-span-2">
<Button className="w-full" onClick={() => {router.push('/stats/rswtStat')}}>
중수도시설통계
</Button>
</div>
<div className="col-span-2">
<Button className="w-full" onClick={() => {router.push('/stats/matStat')}}>
물재이용사례 관리
</Button>
</div>
</div>
</div>
</div>
</>
</>
);
}
@@ -1,52 +0,0 @@
'use client'
import { ScrollArea, SearchDiv, SelectBox, UiTable } from '@common/business_components';
import { Button } from '@common/components';
import { PublicReuseFaciltyFormInsert } from '../../../../components/ui/publicReuseInsertForm';
import { useWrStore } from '../../../store';
export default function PublicReuseFaciltyInsert() {
const {pubFac} = useWrStore((state) => state);
const { pubFacHeadList, publicReuseFacilityData} = pubFac;
const searchDiv = '하수재이용시설 '
const selectBox = [{ text: '서울하수처리시설', val: "1_hasu" }, { text: '서울1하수처리시설', val: "2_hasu" }, { text: '서울2하수처리시설', val: "3_hasu" }]
const headName = () => {
return (
<h1 className="pl-3 text-xl">○공공 하수처리시설 등록</h1>
)
}
const onSelectValue = (val: string) => {
console.log(val)
}
return (
<>
<div className="grid grid-cols-2 gap-4 h-full">
<div className='col-span-4'>
<h1 className="pl-3 text-xl" > 하수재이용시설 등록</h1>
<div className="m-8">
<SearchDiv>
<div className='w-4/5 grid grid-cols-12 gap-1 mx-4'>
<SelectBox className='col-span-4' label={searchDiv} selectArray={selectBox} onSelectValue={onSelectValue} />
</div>
<div className='w-1/5 flex items-center justify-end'>
<Button className='mr-4 rounded-lg'>조회</Button>
<Button className='mr-4 rounded-lg'>신규추가</Button>
</div>
</SearchDiv>
</div>
</div>
<div className="col-span-1 pl-11">
<UiTable tableData={publicReuseFacilityData} headlist={pubFacHeadList} pageSize={100} total={10} headName={headName()} children={undefined}/>
</div>
<div className="col-span-1 pr-6 max-h-full overflow-y-scroll">
<ScrollArea>
<PublicReuseFaciltyFormInsert />
{/* <ScrollBar orientation="vertical"></ScrollBar> */}
</ScrollArea>
</div>
</div>
</>
)
}
@@ -1,67 +0,0 @@
'use client'
import { useWrStore } from "@/app/store";
import type { TableUpperProps } from "@/app/store/rainReuseFacilityInsert"
import { RainReuseFaciltyInsertForm } from "@/components/ui/rainReuseInsertForm";
import { ScrollArea, SearchDiv, SearchInput, UiTable } from "@common/business_components";
import { Button, TableHead, TableRow } from "@common/components";
export const headMakeColSpan = (upHeadList: TableUpperProps[]) => {
return (<>
<TableRow>{
upHeadList.map((head: TableUpperProps) =>
(!head.upSequnce ? <TableHead rowSpan={2} key={head.id}>{head.title}</TableHead> :
head.upName === 'upChangeRe' && head.upSequnce === 1 ? <TableHead key={head.id} rowSpan={1} colSpan={3}>{'중축 개축 증축 '}</TableHead> : null))}
</TableRow>
<TableRow>
{upHeadList.map((head: TableUpperProps) =>
(head.upName === 'upChangeRe' ? <TableHead key={head.id}>{head.title}</TableHead> : null))}
</TableRow>
</>)
}
export default function Home() {
const { rain } = useWrStore((state) => state);
const nodeList = headMakeColSpan(rain.upHeadList);
const headName = () => {
return (
<h1 className="pl-3 text-xl">○건축물 목록</h1>
)
}
return (
<>
<div className="grid grid-cols-2 gap-4 ">
<div className='col-span-2'>
<h1 className="pl-3 text-2xl" >빗물이용시설 등록 </h1>
<div className="m-8">
<SearchDiv >
<div className='w-4/5 grid grid-cols-12 gap-1 mx-4'>
<SearchInput className='col-span-3 my-7' label="건물명" />
</div>
<div className='w-1/5 flex items-center justify-end'>
<Button className='mr-4 rounded-lg'>조회</Button>
<Button className='mr-4 rounded-lg'>저장</Button>
<Button className='mr-4 rounded-lg'>신규등록</Button>
</div>
</SearchDiv>
</div>
</div>
<div className="colsapn-1 pl-11">
<UiTable tableData={rain.rainOfObject} headlist={rain.upHeadList} pageSize={100} total={10} headName={headName()}>
{nodeList}
</UiTable>
</div>
<div className="colsapn-1 pr-11 max-h-full ovreflow-y-scroll">
<ScrollArea>
<RainReuseFaciltyInsertForm></RainReuseFaciltyInsertForm>
</ScrollArea>
</div>
</div>
</>
);
}
@@ -1,69 +0,0 @@
'use client'
import { useWrStore } from "@/app/store";
import type { TableUpperProps } from "@/app/store/rainReuseFacilityInsert";
import { RswtrReuseFaciltyInsertForm } from "@/components/ui/rswtrReuseInsetForm";
import { ScrollArea, SearchDiv, SearchInput, UiTable } from "@common/business_components";
import { Button, TableHead, TableRow } from "@common/components";
const headMakeColSpan = (upHeadList: TableUpperProps[]) => {
return (<>
<TableRow>{
upHeadList.map((head: TableUpperProps) =>
(!head.upSequnce ? <TableHead rowSpan={2} key={head.id}>{head.title}</TableHead> :
head.upName === 'upChangeRe' && head.upSequnce === 1 ? <TableHead key={head.id} rowSpan={1} colSpan={3}>{'중축 개축 증축 '}</TableHead> : null))}
</TableRow>
<TableRow>
{upHeadList.map((head: TableUpperProps) =>
(head.upName === 'upChangeRe' ? <TableHead key={head.id}>{head.title}</TableHead> : null))}
</TableRow>
</>)
}
export default function Home() {
const {rswt} = useWrStore((state) => state);
const nodeList = headMakeColSpan(rswt.upHeadList);
const total = 100;
const headName = () => {
return (
<h1 className="pl-3 text-xl">○건축물 목록</h1>
)
}
return (
<>
<div className="grid grid-cols-2 gap-4 ">
<div className='col-span-2'>
<h1 className="pl-3 text-2xl" >중수도시설 등록 </h1>
<div className="m-8">
<SearchDiv >
<div className='w-4/5 grid grid-cols-6 gap-1 mx-4'>
<SearchInput className='col-span-1 my-7 text-2xl' label="건물명:" />
</div>
<div className='w-1/5 flex items-center justify-end'>
<Button className='mr-4 rounded-lg'>조회</Button>
<Button className='mr-4 rounded-lg'>저장</Button>
<Button className='mr-4 rounded-lg'>신규등록</Button>
</div>
</SearchDiv>
</div>
</div>
<div className="colsapn-1 pl-11">
<UiTable tableData={rswt.rswtOfObject} headlist={rswt.upHeadList} pageSize={100} total={10} headName={headName()}>
{nodeList}
</UiTable>
</div>
<div className="colsapn-1 pr-11 max-h-full ovreflow-y-scroll">
<ScrollArea>
<RswtrReuseFaciltyInsertForm></RswtrReuseFaciltyInsertForm>
</ScrollArea>
</div>
</div>
</>
);
}
@@ -0,0 +1,167 @@
"use client";
import { useWrStore } from "@/app/store";
import {
ContentsDiv,
ScrollArea,
SearchDiv,
SearchFormLeft,
SearchFormRight,
SearchInput,
Title,
UiModal,
UiTable,
} from "@common/business_components";
import { Button } from "@common/components";
import ListDiv from "@common/business_components/ui/list_div";
import { useEffect, useState } from "react";
import { tableData } from "@/components/lib/func/commom";
import HtdflRegForm from "@/components/ui/form/fcltReg/htdflReg/htdflRegForm";
import type { chgBuilding } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import BdstChgModal from "@/components/ui/modal/fcltReg/bdstChgModal/bdstChgModal";
import type { customHtdflBdst } from "@/app/store/ruseFcltMng/fcltReg/htdflReg";
import { BdstReg } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal";
export default function Home() {
const { code, htdfl, initHtdfl,getHtdflBdstData } = useWrStore((state) => state);
const [searchTxt, setSearchTxt] = useState("");
const [pageNation, setPageNation] = useState(1);
const [htdflForm, setHtdflForm] = useState<customHtdflBdst>();
const [bdstTable, setbdstTable] = useState<customHtdflBdst[]>();
const [issNewReg,setIsNewReg] = useState<boolean>( false);
const [bdstChgProps, setBdstChgProps] = useState<{
isOpen: boolean;
chgBuilding: chgBuilding[];
}>({ isOpen: false, chgBuilding: [] });
const { htdflRes } = htdfl;
useEffect(() => {
if (!htdfl.isInit) {
initHtdfl('0');
}
}, [htdfl.isInit, initHtdfl]);
useEffect(() => {
if (code.sggCd.length > 0) {
const htdflData = tableData(htdflRes, { code }).map(
(item: customHtdflBdst) => {
return {
...item,
bdstChgYn: item?.chgBuilding && item.chgBuilding.length > 0 && item.chgBuilding[0]?.bdstChgNm !== null ? 'Y' : 'N',
bdstUsgCd: item.reuseBuilding[0]?.bdstUsgCd
};
}
);
setbdstTable(htdflData);
}
}, [code, htdflRes]);
const cellClick: (val: number|undefined ,headId: string) => void = (
val
,headId) => {
if ((bdstTable ?? []).length > 0 && val !== undefined) {
{
setHtdflForm(htdflRes[val]);
}
}
if (headId === "bdstChgYn" && val !== undefined) {
if (
htdflRes[val]?.bdstInfoPk != null &&
htdflRes[val]?.chgBuilding?.length > 0
) {
bdstChgModal(htdflRes[val]?.chgBuilding as chgBuilding[]);
}
}
};
const bdstChgModal = (chgBuilding: chgBuilding[]) => {
setBdstChgProps({ isOpen: true, chgBuilding: chgBuilding });
};
useEffect(() => {
getHtdflBdstData(pageNation, "0");
}, [pageNation]);
return (
<>
<ContentsDiv>
<div className="grid grid-cols-2 gap-4 ">
<div className="col-span-2">
<Title title={"온배수시설 등록"} />
<SearchDiv>
<SearchFormLeft>
<SearchInput
className="col-span-3 my-7 !text-3xl"
label="건물명"
textValue={searchTxt || ""}
setText={(e) => {
setSearchTxt(e);
}}
/>
</SearchFormLeft>
<SearchFormRight>
<div className="flex flex-row space-x-2 items-center">
<Button size={"sm"} onClick={()=>{initHtdfl(searchTxt||"")}}>조회</Button>
<Button
size={"sm"}
onClick={() => setIsNewReg(!issNewReg)}
>
신규등록
</Button>
</div>
</SearchFormRight>
</SearchDiv>
</div>
</div>
<div className="grid grid-cols-6 gap-4 ">
<div className="col-span-4 h-full min-h-0">
<ListDiv className="min-h-0">
<UiTable
tableData={bdstTable || []}
headlist={htdfl.upHeadList}
pageSize={100}
total={10}
headName={"건축물 목록"}
cellClick={(val, headId) => { cellClick(val || undefined, headId); } }
onPageChange={setPageNation}
>
</UiTable>
</ListDiv>
</div>
<div className="col-span-2 max-h-full">
<ListDiv>
<ScrollArea className="h-[60vh]">
<HtdflRegForm
htdflForm={htdflForm ?? ({} as customHtdflBdst)}
isModal={false}
/>
</ScrollArea>
</ListDiv>
</div>
</div>
<UiModal
body={<BdstReg moType="HTB"></BdstReg>}
bodyClass="w-[68vw] max-w-none h-[90vh]"
open={issNewReg}
onOpenChange={(open) => {
setIsNewReg(open);
}}
/>
<UiModal
bodyClass={""}
open={bdstChgProps.isOpen}
body={<BdstChgModal chgBuilding={bdstChgProps.chgBuilding}></BdstChgModal>}
onOpenChange={(open) => {
setBdstChgProps({ ...bdstChgProps, isOpen: open });
}
}
/>
</ContentsDiv>
</>
);
}
@@ -0,0 +1,329 @@
"use client";
import {
ContentsDiv,
ScrollArea,
SearchDiv,
SearchFormLeft,
SearchInput,
Title,
UiModal,
UiTable,
} from "@common/business_components";
import { Button } from "@common/components";
import { useWrStore } from "../../../store";
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@common/components";
import { useCallback, useEffect, useState } from "react";
import ListDiv from "@common/business_components/ui/list_div";
import { tableData } from "@/components/lib/func/commom";
import type {
customPbnst,
fcBizType,
PbnstRegArrrayType,
pubHasuType,
} from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type";
import {
pbnstRegZod,
pbnstRegArrayZod,
fcBizSchema,
} from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type";
import { PbnstMngForm } from "@/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegForm";
import { PbnstBuseForm } from "@/components/ui/form/fcltReg/pbnstReg/buseReg/bugRegForm";
import { PbnstRegModal } from "@/components/ui/modal/fcltReg/pbnstRegModal/pbnstRegModal";
import toast, { Toaster } from "react-hot-toast";
import { writeRgtrAndMdfr } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg";
import { useFieldArray, useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
export default function PublicReuseFaciltyInsert() {
const {
code,
pbnst,
searchFclts,
pubHasuInit,
pbnstRegClick,
pbnstRuseFcltUpdate,
pubHasuSearch,
pbnstRuseBizUpdate,
} = useWrStore((state) => state);
const { pubFacHeadList, pbnstHasuRes, pbnstRes } = pbnst;
const [currentTab, setCurrentTab] = useState<string>("mng");
const [isRuseReg, setIsRuseReg] = useState<{
isModal: boolean;
data: pubHasuType;
}>({ isModal: false, data: {} as pubHasuType });
const [indexMng, setIndexMng] = useState<number>(0);
const [indexBiz, setIndexBiz] = useState<number>(0);
const [searchTxt, setSearchTxt] = useState<string>();
const [bdstTable, setbdstTable] = useState<pubHasuType[]>();
const [selectRow, setSelectRow] = useState<pubHasuType>();
const [pageNation, setPageNation] = useState<number>(1);
const form = useForm<{
items: z.infer<typeof pbnstRegZod>[];
}>({
resolver: zodResolver(z.object({ items: pbnstRegArrayZod })),
// defaultValues: { items: pbnstRegArrayZod.parse([]) },
mode: "onChange",
});
const {
fields: items,
append,
remove,
} = useFieldArray({
control: form.control,
name: `items`,
});
useEffect(() => {
if (!pbnst.isInit) {
pubHasuInit("1", "41");
}
}, [pbnst.isInit, pubHasuInit]);
const onSubmit = async (valuse: { items: PbnstRegArrrayType }) => {
const data = writeRgtrAndMdfr(valuse.items);
let bizs = [] as fcBizType[];
data.forEach((fclt) => {
bizs = [...bizs, ...fclt.fcBizs];
});
const pbnst =data.map((fclt) => {
return({
pbnstRuseFcltPk: fclt.pbnstRuseFcltPk,
fcltCpct: fclt.fcltCpct,
ruseCpct: fclt.ruseCpct,
splyExtraCpct: fclt.splyExtraCpct,
rgtr: fclt.rgtr,
mdfr: fclt.mdfr,
fcFiles: fclt.fcFiles,
fcOpers: fclt.fcOpers,
})
})
await pbnstRuseFcltUpdate(pbnst as customPbnst[]);
await pbnstRuseBizUpdate(bizs);
};
useEffect(() => {
if (code.sggCd.length) {
if (searchFclts) {
setbdstTable(tableData(searchFclts, { code }));
} else if (code.sggCd.length > 0 && pbnstHasuRes.length > 0) {
setbdstTable(tableData(pbnstHasuRes, { code }));
}
}
}, [code, pbnstHasuRes, searchFclts]);
const cellClick = (val: number | undefined) => {
if (val === undefined) return;
const selectRow = pbnstHasuRes?.[val];
setSelectRow(pbnstHasuRes?.[val]);
if (selectRow) {
pbnstRegClick(selectRow);
}
};
const handleTabChange = (value: string) => {
setCurrentTab(value);
};
useEffect(() => {
if (pbnst.pbnstRes&& pbnst.pbnstRes?.length>0) {
console.log("pbnst.pbnstRes", pbnstRes);
form.reset({ items: pbnstRegArrayZod.parse(pbnst.pbnstRes) });
}else{
console.log("pbnst.pbnstRes is null", pbnstRes);
form.reset({ items: [] });
}
}, [pbnst.pbnstRes]);
useEffect(() => {
if (indexMng) {
setIndexBiz(0);
}
}, [indexMng]);
useEffect(() => {
console.log("form errors:", form.formState.errors);
}, [form.formState.errors]);
const appendPbnstRuseFclt = useCallback(() => {
const selecTableRow = selectRow;
if (pbnstRes && pbnstRes.length > 0) {
const lastPbnst = pbnstRes[pbnstRes.length - 1];
if (lastPbnst && selecTableRow) {
append(
pbnstRegZod.parse({
pbnstRuseFcltPk:
String(selecTableRow.bscFctCd) + String(pbnstRes.length + 1),
ruseUtztnFcltNm: "",
fcBizs: [
fcBizSchema.parse({
pbnstRuseFcltFk:
String(lastPbnst.pbnstRuseFcltPk) +
String(pbnstRes.length + 1),
cycl: 1,
}),
] as fcBizType[],
})
);
setIsRuseReg({ ...isRuseReg, isModal: true });
}
} else {
if (selecTableRow) {
append(
pbnstRegZod.parse({
pbnstRuseFcltPk: String(selecTableRow.bscFctCd)+'1',
ruseUtztnFcltNm: "",
regDt: null,
mdfcnDt: null,
fcBizs: [fcBizSchema.parse({pbnstRuseFcltFk:String(selecTableRow.bscFctCd)+'1',cycl:1})] as fcBizType[],
})
)
setIsRuseReg({ ...isRuseReg, isModal: true });
}
}
}, [pbnstRegZod, pbnstRes, append, selectRow, form]);
useEffect(() => {
// console.log(" page getgetvaslue ", form.getValues());
}, [form.getValues()]);
useEffect(() =>{
pubHasuInit(String(pageNation), "41");
},[pageNation,pubHasuInit])
return (
<>
<ContentsDiv>
<div className="grid grid-cols-4 gap-4">
<div className="col-span-4">
<Title title={"하수재이용 시설 등록"} />
<SearchDiv>
<SearchFormLeft>
<SearchInput
className={"col-span-3 my-7 !text-3xl"}
label="건물명"
textValue={searchTxt || ""}
setText={(e) => {
setSearchTxt(e);
}}
/>
<div className="flex flex-row space-x-2 items-center">
<Button
className=""
size={"sm"}
onClick={(e) => {
searchTxt && searchTxt?.length > 0
? pubHasuSearch(String(pageNation), "41", searchTxt)
: pubHasuInit(String(pageNation), "41");
}}
>
조회
</Button>
<Button
size={"sm"}
className=""
onClick={() => {
// pbnstMngData([] as customPbnst[]);
if (!selectRow) {
toast.error(
"하수리시시설을 테이블을 선택하고 등록버튼을 눌러주세요"
);
return;
} else {
appendPbnstRuseFclt();
}
}}
>
신규등록
</Button>
</div>
</SearchFormLeft>
</SearchDiv>
</div>
</div>
<div className="grid grid-cols-6 gap-4 h-full">
<div className="col-span-4 h-full min-h-0">
<ListDiv className="min-h-0">
<ScrollArea className="h-[60vh]">
<UiTable
tableData={bdstTable || []}
headlist={pubFacHeadList}
pageSize={10}
total={100000}
headName={"공공 하수처리시설 등록"}
cellClick={cellClick}
onPageChange={setPageNation}
children={undefined}
/>
</ScrollArea>
</ListDiv>
</div>
<ListDiv className="col-span-2 pr-6 ">
<ScrollArea className="h-[60vh]">
<Tabs defaultValue="mng" onValueChange={handleTabChange}>
<TabsList className="">
<TabsTrigger className="!text-xl" value="mng">
시설정보
</TabsTrigger>
<TabsTrigger className="!text-xl" value="buse">
차수별정보
</TabsTrigger>
<Button
size={"sm"}
onClick={form.handleSubmit(onSubmit)}
className="!justify-end"
>
저장
</Button>
</TabsList>
<TabsContent className="max-h-full" value="mng">
<PbnstMngForm
formType="update"
form={form}
setIndexMng={(index: number) => {
console.log("setIndexMng", index);
setIndexMng(index);
}}
indexMng={indexMng}
/>
</TabsContent>
<TabsContent className="max-h-full" value="buse">
<PbnstBuseForm
formType="update"
form={form}
setIndexBiz={(index: number) => {
setIndexBiz(index);
}}
indexMng={indexMng}
indexBiz={indexBiz}
/>
</TabsContent>
</Tabs>
</ScrollArea>
</ListDiv>
<UiModal
body={
<PbnstRegModal
form={form}
data={isRuseReg.data || ({} as customPbnst)}
></PbnstRegModal>
}
bodyClass="w-[68vw] max-w-none h-[90vh]"
open={isRuseReg.isModal}
onOpenChange={(open) => {
remove(form.getValues("items").length - 1);
setIsRuseReg({ data: {} as pubHasuType, isModal: open });
}}
/>
</div>
<Toaster position="top-center" />
</ContentsDiv>
</>
);
}
@@ -0,0 +1,30 @@
import type { TableUpperProps } from "@/app/store/common/type/header";
import { TableRow, TableHead } from "@common/components/ui";
export const makeFcltRegHead = (upHeadList: TableUpperProps[]) => {
return (
<>
<TableRow>
{upHeadList.map((head: TableUpperProps) =>
!head.upSequnce ? (
<TableHead rowSpan={2} key={head.id}>
{head.title}
</TableHead>
) : head.upName === "upChangeRe" && head.upSequnce === 1 ? (
<TableHead key={head.id} rowSpan={1} colSpan={3}>
{"중축 개축 재축 "}
</TableHead>
) : null
)}
</TableRow>
<TableRow>
{upHeadList.map((head: TableUpperProps) =>
head.upName === "upChangeRe" ? (
<TableHead key={head.id}>{head.title}</TableHead>
) : null
)}
</TableRow>
</>
);
};
@@ -0,0 +1,181 @@
"use client";
import { useWrStore } from "@/app/store";
import {
type chgBuilding,
type customRainBdst,
} from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import { tableData } from "@/components/lib/func/commom";
import RainRegForm from "@/components/ui/form/fcltReg/rainReg/rainRegForm";
import BdstChgModal from "@/components/ui/modal/fcltReg/bdstChgModal/bdstChgModal";
import { BdstReg } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal";
import {
ContentsDiv,
ScrollArea,
SearchDiv,
SearchFormLeft,
SearchInput,
Title,
UiModal,
UiTable,
} from "@common/business_components";
import ListDiv from "@common/business_components/ui/list_div";
import { Button } from "@common/components";
import { useEffect, useState } from "react";
export default function Home() {
const { rain, code, initRain, rainSearch, getRainData } = useWrStore((state) => {
return state;
});
const { rainRes } = rain;
const [rainForm, setRainForm] = useState<customRainBdst>();
const [issNewReg, setIsNewReg] = useState<boolean>(false);
const [pageNation, setPageNation] = useState(1);
const [bdstTable, setbdstTable] = useState<customRainBdst[]>();
const [searchTxt, setSearchTxt] = useState<string>();
const [bdstChgProps, setBdstChgProps] = useState<{
isOpen: boolean;
chgBuilding: chgBuilding[];
}>({ isOpen: false, chgBuilding: [] });
useEffect(() => {
if (!rain.isInit) {
initRain('41');
}
}, [rain.isInit, initRain]);
useEffect(() => {
if (code.sggCd.length > 0) {
const rainData = tableData(rainRes, { code }).map(
(item: customRainBdst) => {
return {
...item,
bdstChgYn: item.chgBuilding.length > 0 ? "Y" : "N",
};
}
);
setbdstTable(rainData);
}
}, [code, rainRes]);
const cellClick: (val: number | undefined, headId: string) => void = (
val,
headId
) => {
if (val !== undefined) {
setRainForm(rainRes[val]);
}
if (headId === "bdstChgYn" && val !== undefined) {
if (
rainRes[val]?.bdstInfoPk != null &&
rainRes[val]?.chgBuilding.length > 0
) {
bdstChgModal(rainRes[val].chgBuilding);
}
}
};
const bdstChgModal = (chgBuilding: chgBuilding[]) => {
setBdstChgProps({ isOpen: true, chgBuilding: chgBuilding });
};
useEffect(() => {
console.log("getPageNation", pageNation);
getRainData(pageNation, "41");
}, [pageNation]);
return (
<>
<ContentsDiv>
<div className="grid grid-cols-4 gap-4">
<div className="col-span-4">
<Title title={"빗물이용시설 등록"} />
<SearchDiv>
<SearchFormLeft>
<SearchInput
className={"col-span-3 my-7 !text-3xl"}
label="건물명"
textValue={searchTxt || ""}
setText={(e) => {
setSearchTxt(e);
}}
/>
<div className="flex flex-row space-x-2 items-center">
<Button
className=""
size={"sm"}
onClick={(e) => {
rainSearch(searchTxt || "", pageNation, "41");
}}
>
조회
</Button>
<Button
size={"sm"}
className=""
onClick={() => setIsNewReg(!issNewReg)}
>
신규등록
</Button>
</div>
</SearchFormLeft>
{/* <SearchFormRight>
</SearchFormRight> */}
</SearchDiv>
</div>
</div>
<div className="grid grid-cols-6 gap-4">
<div className="col-span-4 h-full min-h-0">
<ListDiv className="min-h-0">
{/* <ScrollArea className="h-[60vh]"> */}
<UiTable
tableData={bdstTable || []}
headlist={rain.upHeadList}
pageSize={20}
total={10000}
headName={"건축물 목록"}
cellClick={(val, headId) => {
cellClick(val, headId);
}}
onPageChange={setPageNation}
>
</UiTable>
{/* </ScrollArea> */}
</ListDiv>
</div>
<div className="col-span-2 max-h-full">
<ListDiv className="">
<ScrollArea className="h-[60vh]">
<RainRegForm
rainForm={rainForm ?? ({} as customRainBdst)}
isModal={false}
></RainRegForm>
</ScrollArea>
</ListDiv>
</div>
</div>
<UiModal
body={<BdstReg moType="RNB"></BdstReg>}
bodyClass="w-[68vw] max-w-none h-[90vh]"
open={issNewReg}
onOpenChange={(open) => {
setIsNewReg(open);
}}
/>
<UiModal
bodyClass={""}
open={bdstChgProps.isOpen}
body={
<BdstChgModal chgBuilding={bdstChgProps.chgBuilding}></BdstChgModal>
}
onOpenChange={(open) => {
setBdstChgProps({ ...bdstChgProps, isOpen: open });
}}
/>
</ContentsDiv>
</>
);
}
@@ -0,0 +1,174 @@
"use client";
import { useWrStore } from "@/app/store";
import type { chgBuilding } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import type { customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg";
import { tableData } from "@/components/lib/func/commom";
import RswtrRegForm from "@/components/ui/form/fcltReg/rswtrReg/rswtrRegForm";
import BdstChgModal from "@/components/ui/modal/fcltReg/bdstChgModal/bdstChgModal";
import { BdstReg } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal";
import {
ContentsDiv,
ScrollArea,
SearchDiv,
SearchFormLeft,
SearchFormRight,
SearchInput,
Title,
UiModal,
UiTable,
} from "@common/business_components";
import ListDiv from "@common/business_components/ui/list_div";
import { Button } from "@common/components";
import { useEffect, useState } from "react";
export default function Home() {
const { code, rswt, initRswt, rswtBdstSearch, getRswtBdstData } = useWrStore(
(state) => state
);
const [rswtForm, setRswtForm] = useState<customRswtBdst>();
const [searchTxt, setSearchTxt] = useState<string>();
const [issNewReg, setIsNewReg] = useState<boolean>(false);
const [pageNation, setPageNation] = useState(1);
const [selectVal, setSelect] = useState<number>();
const [bdstTable, setbdstTable] = useState<customRswtBdst[]>();
const [bdstChgProps, setBdstChgProps] = useState<{
isOpen: boolean;
chgBuilding: chgBuilding[];
}>({ isOpen: false, chgBuilding: [] });
const { rswtRes } = rswt;
useEffect(() => {
if (!rswt.isInit) {
initRswt("41");
}
}, [rswt.isInit, initRswt]);
useEffect(() => {
if (code.sggCd.length > 0) {
const rswtData = tableData(rswtRes, { code }).map(
(item: customRswtBdst) => {
return {
...item,
bdstChgYn: item.chgBuilding[0]?.bdstChgNm != null ? "Y" : "N",
bdstUsgCd: item.reuseBuilding[0]?.bdstUsgCd,
};
}
);
setbdstTable(rswtData);
setRswtForm(rswtRes[selectVal ?? 0]);
}
}, [code, rswtRes, selectVal]);
const cellClick: (val: number | undefined, headId: string) => void = (
val,
headId
) => {
if ((bdstTable ?? []).length > 0 && val !== undefined) {
{
setSelect(val);
setRswtForm(rswtRes[val]);
}
}
if (headId === "bdstChgYn" && val !== undefined) {
if (
rswtRes[val]?.bdstInfoPk != null &&
rswtRes[val]?.chgBuilding?.length > 0
) {
bdstChgModal(rswtRes[val].chgBuilding);
}
}
};
const bdstChgModal = (chgBuilding: chgBuilding[]) => {
setBdstChgProps({ isOpen: true, chgBuilding: chgBuilding });
};
useEffect(() => {
getRswtBdstData(pageNation, "41");
}, [pageNation]);
return (
<>
<ContentsDiv>
<div className="grid grid-cols-4 gap-4">
<div className="col-span-4">
<Title title={"중수도시설 등록"} />
<SearchDiv>
<SearchFormLeft>
<SearchInput
className="col-span-3 my-7"
label="건물명"
textValue={searchTxt || ""}
setText={(e) => {
setSearchTxt(e);
}}
/>
</SearchFormLeft>
<SearchFormRight>
<div className="flex flex-row space-x-2">
<Button
size={"sm"}
className="mr-4 "
onClick={(e) => {
rswtBdstSearch(searchTxt || "", pageNation, "41");
}}
>
조회
</Button>
<Button
size={"sm"}
className="mr-4"
onClick={() => setIsNewReg(!issNewReg)}
>
신규등록
</Button>
</div>
</SearchFormRight>
</SearchDiv>
</div>
</div>
<div className="grid grid-cols-6 gap-4">
<div className="col-span-4 h-full min-h-0">
<ListDiv className="min-h-0">
<UiTable
tableData={bdstTable || []}
headlist={rswt.upHeadList}
pageSize={20}
total={10000}
headName={"건축물 목록"}
cellClick={cellClick}
onPageChange={setPageNation}
></UiTable>
</ListDiv>
</div>
<div className="col-span-2 max-h-full">
<ListDiv>
<ScrollArea className="h-[60vh]">
<RswtrRegForm
rswtForm={rswtForm ?? ({} as customRswtBdst)}
isModal={false}
/>
</ScrollArea>
</ListDiv>
</div>
</div>
<UiModal
body={<BdstReg moType="RST"></BdstReg>}
bodyClass="w-[68vw] max-w-none h-[90vh]"
open={issNewReg}
onOpenChange={(open) => {
setIsNewReg(open);
}}
/>
<UiModal
bodyClass={""}
open={bdstChgProps.isOpen}
body={
<BdstChgModal chgBuilding={bdstChgProps.chgBuilding}></BdstChgModal>
}
onOpenChange={(open) => {
setBdstChgProps({ ...bdstChgProps, isOpen: open });
}}
/>
</ContentsDiv>
</>
);
}
@@ -0,0 +1,193 @@
"use client";
import { useWrStore } from "@/app/store";
import { btnClass } from "@/app/store/common/code";
import type {
chgBuilding,
customRainBdst,
} from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import {
excelDownload,
getCityOrSgg,
tableData,
} from "@/components/lib/func/commom";
import HeadChModal from "@/components/ui/modal/sttn/headChModal/headChModal";
import SttnDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal";
import {
ContentsDiv,
SearchBaseForm,
Title,
UiModal,
UiTable,
type ReturnType,
} from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import { Button } from "@common/components/ui";
import { useCallback, useEffect, useRef, useState } from "react";
import { excelHtdflSttnParsing } from "@/app/store/ruseFcltMng/fcltSttn/htdflSttn/excel";
import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan";
export default function HtdflSttn() {
const { code, htdflSttn, htdflSttnSearch, initHtdfl } = useWrStore(
(state) => state
);
const { htdflSttnRes } = htdflSttn;
const ref = useRef<ReturnType>({} as ReturnType);
const [pageNation, setPageNation] = useState(1);
const [isChHead, setIsChHead] = useState(false);
const [bdstTable, setBdstTable] = useState<customRainBdst[]>();
const [detailModal, setDetailModal] = useState<{
isOpen: boolean;
data: customRainBdst | undefined;
}>({ data: undefined, isOpen: false });
const [bdstChgProps, setBdstChgProps] = useState<{
isOpen: boolean;
chBuilding: chgBuilding[];
}>({ isOpen: false, chBuilding: [] });
const codeData = getCityOrSgg(ref);
const excelClick = useCallback(() => {
if (codeData) htdflSttnSearch(1, "10000", codeData);
}, [htdflSttnSearch, codeData]);
useEffect(() => {
if (codeData != null) htdflSttnSearch(pageNation, "20", codeData);
}, [pageNation]);
const cellClick = (index: number | undefined, headId: string) => {
if (
headId !== "chBuildingYn" &&
index !== undefined &&
bdstTable !== undefined
) {
setDetailModal({ isOpen: true, data: bdstTable[index] });
}
};
useEffect(() => {
const excelDown = async () => {
if (htdflSttn.excelList.length > 0) {
if (htdflSttn.excelList.length === 0) return;
const excelData = await tableData(htdflSttn.excelList, { code });
const htdflExcel = excelHtdflSttnParsing(excelData, code.cityCd, code.sggCd);
excelDownload(
htdflExcel as [[]],
"온배수시설 현황",
"sample_htdflSttn.xlsx",
"A1:S3"
);
}
};
excelDown();
}, [htdflSttn.excelList, code]);
useEffect(() => {
if (!htdflSttn.isInit) {
initHtdfl(codeData ?? "0");
}
}, [htdflSttn.isInit, initHtdfl]);
useEffect(() => {
if (htdflSttnRes.length > 0 && code.cityCd.length > 0) {
const data = tableData(htdflSttnRes, { code });
const chData = data
.map((item: any) => ({
...item,
...item.reuseBuilding[0],
...item.reuseBuilding[0].htdflObj,
chBuildingYn: item.chgBuilding[0]?.bdstChgNm !== null ? "Y" : "N",
}))
.filter((item: any) => item.htdflObj !== undefined);
setBdstTable(chData);
}
}, [code, htdflSttnRes, htdflSttn.htdflSttHeadList]);
return (
<>
<ContentsDiv>
<div className="grid grid-cols-4 gap-4 ">
<div className="col-span-4">
<Title title={"온배수 시설 현황"} />
<SearchBaseForm
selectSidoData={code.cityCd}
selectSigunData={code.sggCd}
selectRegionData={code.rvbsnCd}
selectUnitWaterShedData={code.lgbsnCd}
selectMiddleRegionData={code.mdmbsnCd}
selectEnvPartData={code.lclgvrnmntCd}
rightChildren={<Button
className={btnClass}
onClick={() => {
setIsChHead(true);
} }
>
조회항목설정
</Button>}
leftChildren={undefined}
queryClick={function (returnType: ReturnType): void {
// '{partValue: 'A', sidoValue: '0', sigunValue: '0', regionValue: '0', unitWaterShedValue: '0', …}'
let con;
if (returnType.sigunValue != "0") {
con = returnType.sigunValue;
} else {
con = returnType.sidoValue;
}
htdflSttnSearch(pageNation, "20", con);
} }
excelClick={excelClick}
initClick={function (): void { } }
btnClass={btnClass}
ref={ref} isAdmin={false} />
</div>
</div>
<div className="grid grid-cols-6 gap-4 ">
<div className="col-span-6">
<ListDiv>
<UiTable
headName={[]}
tableData={bdstTable || []}
children={
<HeadMakeColSpan upHeadList={htdflSttn.htdflSttNodeList} />
}
headlist={htdflSttn.htdflSttHeadList}
pageSize={20}
total={100000}
cellClick={(index: number | undefined, headId: string) => {
cellClick(index ?? undefined, headId);
}}
onPageChange={setPageNation}
></UiTable>
</ListDiv>
</div>
</div>
<UiModal
open={isChHead}
onOpenChange={() => {
setIsChHead(!isChHead);
}}
bodyClass={""}
body={
<HeadChModal
type={"HTB"}
headList={htdflSttn.htdflSttHeadList.map((item) => ({
...item,
visible: item.visible ?? false,
}))}
/>
}
/>
<UiModal
open={detailModal.isOpen}
onOpenChange={() => {
setDetailModal({ ...detailModal, isOpen: !detailModal.isOpen });
}}
bodyClass={"w-[40vw] max-w-none max-h-[calc(100%-70px)]"}
body={<SttnDetailModal type={"HTB"} formObj={detailModal.data} />}
/>
</ContentsDiv>
</>
);
}
@@ -0,0 +1,223 @@
"use client";
import { useWrStore } from "@/app/store";
import { btnClass } from "@/app/store/common/code";
import {
ContentsDiv,
SearchBaseForm,
SearchInput,
SelectBox,
Title,
UiModal,
UiTable,
type ReturnType,
} from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import { Button, Label } from "@common/components/ui";
import HeadChModal from "@/components/ui/modal/sttn/headChModal/headChModal";
import { useCallback, useEffect, useRef, useState } from "react";
import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan";
import type { customPbnst } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type";
import { excelDownload, yearOptions } from "@/components/lib/func/commom";
import SearchInputText from "@/components/ui/searchInput/searchInput";
import type { WaterReuseFacility } from "@/app/store/ruseFcltMng/fcltSttn/pbnstSttn/type";
import { PbnstSttnModal } from "@/components/ui/modal/sttn/pbnstSttnModal/pbnstSttnModal";
export default function PbnstSttn() {
const {
code,
pbnstSttn,
pbnstSttnSearch,
pbnSttnInit,
getPbnStnDetail,
pbnNmSearch,
} = useWrStore((state) => state);
const ref = useRef<ReturnType>({} as ReturnType);
const [searchYear, setSearchYear] = useState<string>(
String(new Date().getFullYear())
);
const [isChHead, setIsChHead] = useState(false);
const [bdstTable, setBdstTable] = useState<WaterReuseFacility[]>();
const [pbnDetaileData, setPbnDetaileData] = useState<{
isModal: boolean;
data: customPbnst;
}>({ isModal: false, data: {} as customPbnst });
const [pbnRuseNm, setPbnRuseNm] = useState<string>("");
const excelClick = useCallback(() => {
pbnstSttnSearch("1", "10000", ref.current, "", searchYear);
}, [pbnstSttnSearch, searchYear, ref.current]);
const cellCLick = useCallback(
(index: number | undefined) => {
if (
index !== undefined &&
pbnstSttn.pbnstSttnRes &&
pbnstSttn.pbnstSttnRes[index]
) {
const pbnstRuseFcltPk = pbnstSttn.pbnstSttnRes[index].pbnstRuseFcltPk;
getPbnStnDetail(pbnstRuseFcltPk);
}
},
[getPbnStnDetail, pbnstSttn.pbnstSttnRes]
);
useEffect(() => {
if (pbnstSttn.excelList.length >= 0) {
excelDownload(
pbnstSttn.excelList,
"하수재이용시설 현황",
"sample_pbnstSttn.xlsx",
"A1:U2"
);
}
}, [pbnstSttn.excelList]);
useEffect(() => {
if (!pbnstSttn.isInit) {
pbnSttnInit("1", "13", ref.current, searchYear);
}
}, [pbnstSttn.isInit, pbnSttnInit, ref.current]);
useEffect(() => {
setBdstTable(pbnstSttn.pbnstSttnRes);
}, [pbnstSttn.pbnstSttnRes]);
// useEffect(() => {
// pbnstSttnSearch("1", "20", ref.current, pbnRuseNm, searchYear);
// }, [pageNation, ref.current, pbnRuseNm, searchYear, pbnstSttnSearch]);
// useEffect(() => {
// if (pbnRuseNm.length > 1)
// pbnNmSearch(String(pageNation), "23", ref.current, pbnRuseNm, searchYear);
// }, [pbnRuseNm,pageNation]);
useEffect(() => {
if (pbnstSttn.pbnstDetail.pbnstRuseFcltPk)
setPbnDetaileData({
isModal: true,
data: pbnstSttn.pbnstDetail,
});
}, [pbnstSttn.pbnstDetail]);
useEffect(() => {
console.log("pbnDetaileData.isModal ", pbnDetaileData.isModal);
}, [pbnDetaileData.isModal]);
return (
<>
<ContentsDiv>
<div className="grid grid-cols-2 gap-4 ">
<div className="col-span-2">
<Title title={"하수재이용 시설 현황"} />
<SearchBaseForm
selectSidoData={code.cityCd}
selectSigunData={code.sggCd}
selectRegionData={code.rvbsnCd}
selectUnitWaterShedData={code.lgbsnCd}
selectMiddleRegionData={code.mdmbsnCd}
selectEnvPartData={code.lclgvrnmntCd}
rightChildren={
<Button
className={btnClass}
onClick={() => {
setIsChHead(true);
}}
>
조회항목설정
</Button>
}
leftChildren={
<div className="col-span-3 flex items-center">
<SelectBox
className="w-48 h-full text-2xl"
label="연도"
selectClass={"w-full "}
selectArray={yearOptions}
value={searchYear}
onSelectValue={(val: string | number) =>
setSearchYear(String(val))
}
/>
<Label className="w-64 mt-2 mx-4 text-xl text-gray-600">
{"하수처리시설명 "}
</Label>
<SearchInput
className={"text-2xl w-full ㅍ"}
label=""
textValue={pbnRuseNm || ""}
setText={(e) => {
setPbnRuseNm(e || "");
}}
/>
</div>
}
queryClick={function (returnType: ReturnType): void {
pbnstSttnSearch("1", "20", returnType, pbnRuseNm, searchYear);
}}
excelClick={excelClick}
initClick={function (): void {}}
btnClass={btnClass}
ref={ref}
isAdmin={false}
/>
</div>
</div>
<div className="grid grid-cols-6 gap-4 ">
<div className="col-span-6">
<ListDiv>
<UiTable
headName={[]}
tableData={bdstTable || []}
children={
<HeadMakeColSpan upHeadList={pbnstSttn.pbnstSttNodeList} />
}
headlist={pbnstSttn.pbnstSttHeadList}
pageSize={20}
total={100000}
cellClick={(index: number | undefined, headId: string) => {
cellCLick(index);
}}
onPageChange={(page: number) => {
pbnstSttnSearch(
String(page),
String(13),
ref.current,
pbnRuseNm,
searchYear
);
}}
></UiTable>
</ListDiv>
</div>
</div>
<UiModal
open={isChHead}
onOpenChange={() => {
setIsChHead(!isChHead);
}}
bodyClass={""}
body={
<HeadChModal
type={"PBN"}
headList={pbnstSttn.pbnstSttHeadList.map((item) => ({
...item,
visible: item.visible ?? false,
}))}
/>
}
/>
<UiModal
body={
<PbnstSttnModal
data={pbnDetaileData.data || ({} as customPbnst)}
></PbnstSttnModal>
}
bodyClass="w-[68vw] max-w-none h-[90vh]"
open={pbnDetaileData.isModal}
onOpenChange={(open) => {
setPbnDetaileData({ data: {} as customPbnst, isModal: false });
}}
/>
</ContentsDiv>
</>
);
}
@@ -0,0 +1,216 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
"use client";
import { useWrStore } from "@/app/store";
import { btnClass } from "@/app/store/common/code";
import {
excelDownload,
getCityOrSgg,
tableData,
} from "@/components/lib/func/commom";
import HeadChModal from "@/components/ui/modal/sttn/headChModal/headChModal";
import {
ContentsDiv,
SearchBaseForm,
Title,
UiModal,
UiTable,
type ReturnType,
} from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import { Button } from "@common/components/ui";
import { useCallback, useEffect, useRef, useState } from "react";
import type {
chgBuilding,
customRainBdst,
} from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan";
import SttnDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal";
import BdstChgModal from "@/components/ui/modal/fcltReg/bdstChgModal/bdstChgModal";
export default function RainSttn() {
const { code, rainSttn, rainSttnSearch, rainSttnInit } = useWrStore(
(state) => state
);
const { rainSttnRes } = rainSttn;
const ref = useRef<ReturnType>({} as ReturnType);
const [pageNation, setPageNation] = useState(1);
const [isChHead, setIsChHead] = useState(false);
const [bdstTable, setBdstTable] = useState<customRainBdst[]>();
const [detailModal, setDetailModal] = useState<{
isOpen: boolean;
data: customRainBdst | undefined;
}>({ data: undefined, isOpen: false });
const [bdstChgProps, setBdstChgProps] = useState<{
isOpen: boolean;
chBuilding: chgBuilding[];
}>({ isOpen: false, chBuilding: [] });
const codeData = getCityOrSgg(ref);
const cellClick = (index: number | undefined, headId: string) => {
if (
headId !== "chBuildingYn" &&
index !== undefined &&
bdstTable !== undefined
) {
setDetailModal({ isOpen: true, data: bdstTable[index] });
} else if (
headId === "chBuildingYn" &&
index !== undefined &&
bdstTable !== undefined
) {
if (
bdstTable[index] &&
bdstTable[index]?.chgBuilding[0]?.bdstChgNm !== null
) {
setBdstChgProps({
isOpen: true,
chBuilding: bdstTable[index].chgBuilding,
});
}
}
};
useEffect(() => {
if (!rainSttn.isInit) {
rainSttnInit(codeData ?? "0");
}
}, [rainSttn.isInit, rainSttnInit]);
useEffect(() => {
if (rainSttnRes.length > 0 && code.cityCd.length > 0) {
const data = tableData(rainSttnRes, { code });
const chData = data
.map((item: any) => ({
...item,
...item.reuseBuilding[0],
...item.reuseBuilding[0].rainyObj,
chBuildingYn: item.chgBuilding[0]?.bdstChgNm !== null ? "Y" : "N",
}))
.filter((item: any) => item.rainyObj !== undefined);
setBdstTable(chData);
}
}, [code, rainSttnRes, rainSttn.rainSttHeadList]);
useEffect(() => {
if (codeData != null) rainSttnSearch(pageNation, "20", codeData, code.cityCd, code.sggCd);
}, [pageNation]);
useEffect(() => {
if (rainSttn.excelList.length > 0) {
if (rainSttn.excelList.length === 0) return;
excelDownload(
rainSttn.excelList,
"빗물재이용시설 현황",
"sample_rainSttn.xlsx",
"A1:W3"
);
}
}, [rainSttn.excelList]);
const excelClick = useCallback(() => {
if (codeData) rainSttnSearch(1, "10000", codeData, code.cityCd, code.sggCd);
}, [rainSttnSearch, codeData, code.cityCd, code.sggCd]);
return (
<>
<ContentsDiv>
<div className="grid grid-cols-4 gap-4 ">
<div className="col-span-4">
<Title title={"빗물재이용 시설 현황"} />
<SearchBaseForm
selectSidoData={code.cityCd}
selectSigunData={code.sggCd}
selectRegionData={code.rvbsnCd}
selectUnitWaterShedData={code.lgbsnCd}
selectMiddleRegionData={code.mdmbsnCd}
selectEnvPartData={code.lclgvrnmntCd}
rightChildren={
<Button
className={btnClass}
onClick={() => {
setIsChHead(true);
}}
>
조회항목설정
</Button>
}
leftChildren={undefined}
queryClick={function (returnType: ReturnType): void {
// '{partValue: 'A', sidoValue: '0', sigunValue: '0', regionValue: '0', unitWaterShedValue: '0', …}'
let con;
if (returnType.sigunValue != "0") {
con = returnType.sigunValue;
} else {
con = returnType.sidoValue;
}
rainSttnSearch(1, "20", con, code.cityCd, code.sggCd);
}}
excelClick={excelClick}
initClick={function (): void { }}
btnClass={btnClass}
ref={ref}
isAdmin={false}
/>
</div>
</div>
<div className="grid grid-cols-6 gap-4 ">
<div className="col-span-6">
<ListDiv>
<UiTable
headName={[]}
tableData={bdstTable || []}
children={
<HeadMakeColSpan upHeadList={rainSttn.rainSttNodeList} />
}
headlist={rainSttn.rainSttHeadList}
pageSize={20}
total={100000}
cellClick={(index: number | undefined, headId: string) => {
cellClick(index ?? undefined, headId);
}}
onPageChange={setPageNation}
></UiTable>
</ListDiv>
</div>
</div>
<UiModal
open={isChHead}
onOpenChange={() => {
setIsChHead(!isChHead);
}}
bodyClass={""}
body={
<HeadChModal
type={"RNB"}
headList={rainSttn.rainSttHeadList.map((item) => ({
...item,
visible: item.visible ?? false,
}))}
/>
}
/>
<UiModal
open={detailModal.isOpen}
onOpenChange={() => {
setDetailModal({ ...detailModal, isOpen: !detailModal.isOpen });
}}
bodyClass={"w-[40vw] max-w-none max-h-[calc(100%-70px)]"}
body={<SttnDetailModal type={"RNB"} formObj={detailModal.data} />}
/>
<UiModal
bodyClass={""}
open={bdstChgProps.isOpen}
body={
<BdstChgModal chgBuilding={bdstChgProps.chBuilding}></BdstChgModal>
}
onOpenChange={(open) => {
setBdstChgProps({ ...bdstChgProps, isOpen: open });
}}
/>
</ContentsDiv>
</>
);
}
@@ -0,0 +1,199 @@
"use client";
import { useWrStore } from "@/app/store";
import { btnClass } from "@/app/store/common/code";
import type { chgBuilding } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import type { customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg";
import {
excelDownload,
getCityOrSgg,
tableData,
} from "@/components/lib/func/commom";
import BdstChgModal from "@/components/ui/modal/fcltReg/bdstChgModal/bdstChgModal";
import HeadChModal from "@/components/ui/modal/sttn/headChModal/headChModal";
import SttnDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal";
import {
ContentsDiv,
SearchBaseForm,
Title,
UiModal,
UiTable,
type ReturnType,
} from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan";
import { Button } from "@common/components/ui";
import { useCallback, useEffect, useRef, useState } from "react";
export default function RswtSttn() {
const { code, rswtSttn, rswtSttnSearch, rswtSttnInit } = useWrStore(
(state) => state
);
const [pageNation, setPageNation] = useState(1);
const { rswtSttnRes } = rswtSttn;
const [isChHead, setIsChHead] = useState(false);
const ref = useRef<ReturnType>({} as ReturnType);
const [bdstTable, setBdstTable] = useState<customRswtBdst[]>();
const [detailModal, setDetailModal] = useState<{ isOpen: boolean, data: customRswtBdst | undefined }>({ data: undefined, isOpen: false })
const [bdstChgProps, setBdstChgProps] = useState<{
isOpen: boolean;
chBuilding: chgBuilding[];
}>({ isOpen: false, chBuilding: [] });
const codeCityOrSgg = getCityOrSgg(ref);
const cellClick = (index: number | undefined, headId: string) => {
if (headId !== 'chBuildingYn' && index !== undefined && bdstTable !== undefined) {
setDetailModal({ isOpen: true, data: bdstTable[index] })
} else if (headId === 'chBuildingYn' && index !== undefined && bdstTable !== undefined) {
if (
bdstTable[index] &&
bdstTable[index]?.chBuildingYn === 'Y'
) {
setBdstChgProps({ isOpen: true, chBuilding: bdstTable[index].chgBuilding });
}
}
}
useEffect(() => {
if (!rswtSttn.isInit) {
rswtSttnInit("0");
}
}, [rswtSttn.isInit, rswtSttnInit]);
useEffect(() => {
if (rswtSttnRes.length > 0 && code.cityCd.length > 0) {
const data = tableData(rswtSttnRes, { code });
const chData = data
.map((item: customRswtBdst) => ({
...item,
...item.reuseBuilding[0],
...item.reuseBuilding[0]?.rswtrObj,
chBuildingYn: item?.chgBuilding[0]?.bdstChgNm !== null && item?.chgBuilding.length > 0 ? 'Y' : 'N'
}))
.filter(
(item: customRswtBdst) =>
item.reuseBuilding[0]?.rswtrObj !== undefined
);
setBdstTable(chData);
}
}, [code, rswtSttnRes]);
useEffect(() => {
if (rswtSttn.excelList.length > 0) {
if (rswtSttn.excelList.length === 0) return;
excelDownload(
rswtSttn.excelList,
"중수도시설 현황",
"sample_rswtSttn.xlsx",
"A1:W3",
);
}
}, [rswtSttn.excelList]);
const excelClick = useCallback(
(returnType: ReturnType) => {
if (codeCityOrSgg)
rswtSttnSearch(1, "10000", codeCityOrSgg, code.cityCd, code.sggCd);
},
[rswtSttnSearch, code.cityCd, code.sggCd, codeCityOrSgg]
);
useEffect(() => {
if (codeCityOrSgg != null) rswtSttnSearch(pageNation, "20", codeCityOrSgg, code.cityCd, code.sggCd);
}, [pageNation]);
return (
<>
<ContentsDiv>
<div className="grid grid-cols-4 gap-4 ">
<div className="col-span-4">
<Title title={"중수도시설 현황"} />
<SearchBaseForm
selectSidoData={code.cityCd}
selectSigunData={code.sggCd}
selectRegionData={code.rvbsnCd}
selectUnitWaterShedData={code.lgbsnCd}
selectMiddleRegionData={code.mdmbsnCd}
selectEnvPartData={code.lclgvrnmntCd}
rightChildren={<Button
className={btnClass}
onClick={() => {
setIsChHead(true);
} }
>
조회항목설정
</Button>}
leftChildren={undefined}
queryClick={function (returnType: ReturnType): void {
// '{partValue: 'A', sidoValue: '0', sigunValue: '0', regionValue: '0', unitWaterShedValue: '0', …}'
if (codeCityOrSgg)
rswtSttnSearch(1, "20", codeCityOrSgg, code.cityCd, code.sggCd);
} }
excelClick={excelClick}
initClick={function (): void { } }
btnClass={btnClass}
ref={ref} isAdmin={false} />
</div>
</div>
<div className="grid grid-cols-6 gap-4 ">
<div className="col-span-6">
<ListDiv>
<UiTable
headName={[]}
tableData={bdstTable || []}
children={
<HeadMakeColSpan upHeadList={rswtSttn.rswtSttNodeList} />
}
headlist={rswtSttn.rswtSttHeadList}
pageSize={20}
total={10000}
cellClick={(index: number | undefined, headId: string) => { cellClick(index ?? undefined, headId) }}
onPageChange={setPageNation}
></UiTable>
</ListDiv>
</div>
</div>
<UiModal
open={isChHead}
onOpenChange={() => {
setIsChHead(!isChHead);
}}
bodyClass={""}
body={
<HeadChModal
headList={(rswtSttn.rswtSttHeadList || []).map((item) => ({
...item,
visible: item.visible ?? false,
}))}
type={"RST"}
/>
}
/>
<UiModal
open={detailModal.isOpen}
onOpenChange={() => {
setDetailModal({ ...detailModal, isOpen: !detailModal.isOpen });
}}
bodyClass={"w-[40vw] max-w-none max-h-[calc(100%-70px)]"}
body={<SttnDetailModal type={"RST"} formObj={detailModal.data} />}
/>
<UiModal
bodyClass={""}
open={bdstChgProps.isOpen}
body={
<BdstChgModal chgBuilding={bdstChgProps.chBuilding}></BdstChgModal>
}
onOpenChange={(open) => {
setBdstChgProps({ ...bdstChgProps, isOpen: open });
}}
/>
</ContentsDiv>
</>
);
}
@@ -0,0 +1,54 @@
import type { TableUpperProps } from "@/app/store/common/type/header";
import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList";
import { TableHead, TableRow } from "@common/components/ui";
export const headMakeprfmnc = (
upHeadList: TableUpperProps[],
makeHeadNm: chHeadType[]
) => {
return (
<>
<TableRow>
{upHeadList
.filter((data) => data.visible != false)
.map((head: TableUpperProps) =>
!head.upSequnce ? (
<TableHead
className={`border border-gray-600 px-2 py-1 `}
rowSpan={2}
key={head.id}
>
{head.title}
</TableHead>
) : head.upSequnce === 1 ? (
<TableHead
className={`border border-gray-600 px-2 py-1 `}
key={head.id}
rowSpan={1}
colSpan={
makeHeadNm.find((ch) => ch.headNm === head.upName)?.length
}
>
{makeHeadNm.find((ch) => ch.headNm === head.upName)?.text}
</TableHead>
) : null
)}
</TableRow>
<TableRow>
{upHeadList
.filter((data) => data.visible != false)
.map((head: TableUpperProps) =>
makeHeadNm.find((ch) => ch.headNm === head.upName) ? (
<TableHead
className={`border border-gray-600 px-2 py-1 `}
key={head.id}
>
{head.title}
</TableHead>
) : null
)}
</TableRow>
</>
);
};
@@ -0,0 +1,283 @@
"use client";
import { useWrStore } from "@/app/store";
import { type rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
import type {
rswtChkZodType,
rswtrChkDetailsZodType,
} from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn";
import {
excelArrayDownload,
excelDownload,
yearOptions,
} from "@/components/lib/func/commom";
import ChkgdExcel from "@/components/ui/modal/chkgd/chkgdExcel/chkgdExcel";
import ChkgdModal from "@/components/ui/modal/chkgd/chkgdModal/chkgdModal";
import RainChkgdTable from "@/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable";
import RswtChkgdTable from "@/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable";
import {
ContentsDiv,
SearchDiv,
SearchFormLeft,
SearchFormRight,
SearchInput,
SelectBox,
Title,
UiModal,
} from "@common/business_components/ui";
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 {
code,
rainChkgdn,
rswtChkgdn,
rainChkInit,
rainChkDetilUpdate,
rainChkDelete,
rainChkExcelDownload,
rainChkHeadChange,
isRainSttn,
rswtChkgdnInit,
rswtChkPolInit,
rswtChkDetilsUpdate,
rswtChkDelete,
rswtrChkExcelDownload,
rswtChkHeadChange,
} = useWrStore((state) => {
return state;
});
const [isRegExcel, setIsRegExcel] = useState(false);
const [updateRainDetail, setUpdateRainDetail] = useState<rainChkZodType[]>(
[]
);
const [updateRswtDetail, setUpdateRSwtDetail] = useState<
rswtrChkDetailsZodType[]
>([]);
const [deleteIdx, setDeleteIdx] = useState<number[]>([]);
const [selFcltDiv, setSelFcltDiv] = useState("RNB");
const [isModal, setIsModal] = useState({
open: false,
data: {},
});
const cellClick = () => {
if (searchYear) rainChkInit(searchYear, "0");
};
const [searchYear, setSearchYear] = useState<string>(
String(new Date().getFullYear())
);
useEffect(() => {
if (!rainChkgdn.isInit) {
rainChkInit(new Date().getFullYear().toString(), "0");
isRainSttn(false);
setIsModal({ data: {}, open: false });
setIsRegExcel(false);
}
if (!rswtChkgdn.isInit) {
rswtChkgdnInit(new Date().getFullYear().toString(), "0");
setIsModal({ data: {}, open: false });
setIsRegExcel(false);
}
}, [rainChkgdn.isInit, rainChkInit]);
useEffect(() => {
if (rswtChkgdn.excelList[0]&&rswtChkgdn.excelList[0]?.data.length > 1) {
excelArrayDownload(
"중수도시설 지도점검",
"sample_rs_chk.xlsx",
rswtChkgdn.excelList
);
}
}, [rswtChkgdn.excelList]);
useEffect(() => {
excelDownload(
rainChkgdn.excelList,
"빗물이용시설 지도점검",
"sample_rainy.xlsx",
"A1:AN1",
2
);
}, [rainChkgdn.excelList]);
const excelClick = useCallback(() => {
if (selFcltDiv === "RNB") {
rainChkExcelDownload(code.cityCd, code.sggCd);
} else {
rswtrChkExcelDownload(code.cityCd, code.sggCd);
}
}, [
rainChkExcelDownload,
rswtrChkExcelDownload,
code.cityCd,
code.sggCd,
selFcltDiv,
]);
const handleClick = useCallback(
(data: any) => {
if (data) setIsModal({ open: !isModal.open, data: data });
},
[isModal]
);
useEffect(() => {
rainChkgdn.isSttn = false;
rswtChkgdn.isSttn = false;
if (!rainChkgdn.isSttn && !rswtChkgdn.isSttn) {
rainChkHeadChange({ rainChkgdn }, true);
rswtChkHeadChange({ rswtChkgdn }, true);
}
}, [rainChkgdn.isSttn, rswtChkgdn.isSttn]);
const clickDelete = (data: number[], selFcltDiv: string) => {
if (data.length > 0) {
if (selFcltDiv === "RNB") {
rainChkDelete(data);
} else {
rswtChkDelete(data);
}
}
};
const chkUpdateTable = (selFcltDiv: string) => {
if (selFcltDiv === "RNB") {
rainChkDetilUpdate(updateRainDetail);
} else {
rswtChkDetilsUpdate(updateRswtDetail);
}
};
return (
<ContentsDiv>
<div className="grid grid-cols-4 gap-4 ">
<div className="col-span-4">
<Title title={"지도점검 결과 등록"} />
<SearchDiv>
<SearchFormLeft>
<div className="col-span-2 flex flex-row space-x-2">
<Label className="w-48 mt-2 text-xl text-gray-600">
{"지도점검년도"}
</Label>
<SelectBox
className="w-full h-full text-2xl"
label=""
selectClass={""}
selectArray={yearOptions}
value={searchYear}
onSelectValue={(val: string | number) =>
setSearchYear(String(val))
}
/>
</div>
<div className="col-span-2 flex flex-row space-x-2">
<Label className="w-28 mt-2 text-xl text-gray-600">
{"시설구분"}
</Label>
<SelectBox
className={"w-full h-full text-2xl"}
label={""}
selectClass={""}
selectArray={rainChkgdn.fcltDiv}
onSelectValue={(val: string | number) =>{
if(val === "RST") rswtChkPolInit();
setSelFcltDiv(String(val))
}
}
value={selFcltDiv ?? rainChkgdn.fcltDiv[0]?.val}
/>
</div>
</SearchFormLeft>
<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) => {
cellClick();
}}
>
조회
</Button>
<Button
size={"sm"}
onClick={() => {
clickDelete(deleteIdx, selFcltDiv);
}}
>
삭제
</Button>
<Button
size={"sm"}
onClick={() => {
chkUpdateTable(selFcltDiv);
}}
>
저장
</Button>
<Button
size={"sm"}
onClick={() => {
setIsRegExcel(!isRegExcel);
}}
>
결과등록
</Button>
<Button color="green" size={"sm"} onClick={excelClick}>
양식받기
</Button>
</div>
</div>
</SearchFormRight>
</SearchDiv>
</div>
</div>
<div className="grid grid-cols-6 gap-4 ">
<div className="col-span-6">
<ListDiv>
{selFcltDiv === "RNB" ? (
<RainChkgdTable
deleteData={setDeleteIdx}
detailUp={setUpdateRainDetail}
handleClick={handleClick}
rainChkData={rainChkgdn.rainChk}
/>
) : (
<RswtChkgdTable
detaiRswtlUpdate={setUpdateRSwtDetail}
deleteRswtData={setDeleteIdx}
handleRswtClick={handleClick}
rswtChkData={rswtChkgdn.rswtChkRes}
/>
)}
</ListDiv>
</div>
</div>
<UiModal
open={isModal.open}
onOpenChange={() => {
setIsModal({ open: !open, data: {} });
}}
bodyClass={"w-[80vw] max-w-none"}
body={<ChkgdModal type={selFcltDiv} obj={isModal.data} />}
></UiModal>
<UiModal
open={isRegExcel}
onOpenChange={setIsRegExcel}
bodyClass={"w-[30vw] max-w-none"}
body={<ChkgdExcel type={selFcltDiv}></ChkgdExcel>}
/>
<Toaster position="top-center" />
</ContentsDiv>
);
}
@@ -0,0 +1,279 @@
"use client";
import { useWrStore } from "@/app/store";
import type { pubHasuType } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type";
import { excelDownload, yearOptions } from "@/components/lib/func/commom";
import PbnPrfExcelModal from "@/components/ui/modal/chkgd/pbnPrfExcelModal/pbnPrfExcelModal";
import {
ContentsDiv,
Title,
SearchDiv,
SearchFormLeft,
SelectBox,
SearchInput,
SearchFormRight,
ScrollArea,
UiTable,
UiModal,
} from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import {
Button,
Label,
Table,
TableBody,
TableHeader,
} from "@common/components/ui";
import { useState, useEffect, useCallback } from "react";
import { set } from "react-hook-form";
import { Toaster } from "react-hot-toast";
import { headMakeprfmnc } from "../chkgdnReg/TableHead";
import { InputTableBody } from "@/components/lib/func/TableData";
import {
initValInUsage,
initValOutUsage,
subTotalObj,
totalObj,
type FcPrfType,
type PrfType,
} from "@/app/store/prfmncReg/pbnstPrfmncReg/type";
import { excelToPbnPrfData } from "@/app/store/prfmncReg/pbnstPrfmncReg/excel";
export default function prfmncPrfmncReg() {
const { code, prfmnc, prfmncHasuInit, prfmnRegData } = useWrStore(
(state) => state
);
const { pbnstPrfmncHeadList, monthHeadList, prfmncRes } = prfmnc;
const [bdstTable, setbdstTable] = useState<FcPrfType[]>();
const [searchTxt, setSearchTxt] = useState<string>();
const [isExcelOpen, setIsExcelOPen] = useState<{
isModal: boolean;
data: FcPrfType;
}>({ isModal: false, data: {} as FcPrfType });
const [inputData, setInputData] = useState<any[]>();
const [pbnstRuseFcltPk, setPbnstRuseFcltPk] = useState<string>();
const [pageNation , setPageNation] = useState<number>(1);
const [searchYear, setSearchYear] = useState<string>(
String(new Date().getFullYear())
);
const excelClick = useCallback(() => {
excelDownload(
[[]],
"하수재이용실적",
"sample_pbnstPrfmncReg.xlsx",
"A1:O1"
);
}, [prfmnc.excelList]);
const onSave = useCallback(() => {
if (pbnstRuseFcltPk) {
prfmnRegData(
excelToPbnPrfData(
inputData as unknown as JSON[],
searchYear,
pbnstRuseFcltPk
) as unknown as PrfType
);
prfmncHasuInit(String(pageNation), "41");
}
}, [inputData, searchYear, pbnstRuseFcltPk,prfmncHasuInit,pageNation]);
const cellClick = useCallback(
(index: number | undefined, headId: string) => {
if (index !== undefined) {
setIsExcelOPen({
isModal: false,
data: prfmncRes[index] || ({} as FcPrfType),
});
const inUsageData = structuredClone(initValInUsage);
const outUsageData = structuredClone(initValOutUsage);
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"
const monthKey = `${month}월`;
inUsageData.forEach((inData: any) => {
const usageKey = inData.usage;
const value = (prfItem as any)[usageKey] ?? 0;
inData[monthKey] = value;
inData.total += value;
if (inSubtotal && usageKey !== "subtotal") {
(inSubtotal as any)[monthKey] =
((inSubtotal as any)[monthKey] ?? 0) + value;
inSubtotal.total += value;
}
});
outUsageData.forEach((outData: any) => {
const usageKey = outData.usage;
const value = (prfItem as any)[usageKey] ?? 0;
outData[monthKey] = value;
outData.total += value;
if (usageKey !== "subtotal") {
(outSubtotal as any)[monthKey] =
((outSubtotal as any)[monthKey] ?? 0) + value;
outSubtotal.total += value;
}
});
});
inUsageData.push(inSubtotal);
outUsageData.push(outSubtotal);
const usageTotalObj: { [key: string]: any } = structuredClone(totalObj);
for (const key in usageTotalObj) {
if (["usage", "gubun", "edit"].includes(key)) continue;
const val =
(Number((inSubtotal as any)[key]) || 0) +
(Number((outSubtotal as any)[key]) || 0);
(usageTotalObj as any)[key] = val;
}
const tableData = [...inUsageData, ...outUsageData, usageTotalObj];
setPbnstRuseFcltPk(prfmncRes[index].pbnstRuseFcltPk);
setInputData(tableData);
} else {
setInputData([]);
}
}
},
[prfmncRes]
);
useEffect(() => {
if (!prfmnc.isInit) {
prfmncHasuInit('1', "41");
}
}, [prfmnc.isInit, prfmncHasuInit]);
useEffect(() => {
setbdstTable(prfmncRes);
}, [prfmncRes]);
return (
<>
<ContentsDiv>
<div className="grid grid-cols-4 gap-4">
<div className="col-span-4">
<Title title={"하수재이용 시설 등록"} />
<SearchDiv>
<SearchFormLeft>
<div className="col-span-2 flex flex-row space-x-2">
<Label className="w-48 mt-2 text-xl text-gray-600">
{"실적등록년도"}
</Label>
<SelectBox
className="w-full h-full text-2xl"
label=""
selectClass={""}
selectArray={yearOptions}
value={searchYear}
onSelectValue={(val: string | number) =>
setSearchYear(String(val))
}
/>
</div>
<div className="col-span-2 flex flex-row space-x-2">
<Label className="w-28 mt-2 text-xl text-gray-600">
{"시설명"}
</Label>
<SearchInput
className={"w-full text-2xl"}
label=""
textValue={searchTxt || ""}
setText={(e) => {
setSearchTxt(e);
}}
/>
</div>
</SearchFormLeft>
<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>
<Button
size={"sm"}
onClick={() => {
onSave();
}}
>
저장
</Button>
<Button
size={"sm"}
onClick={() => {
setIsExcelOPen({ ...isExcelOpen, isModal: true });
}}
>
파일등록
</Button>
<Button color="green" size={"sm"} onClick={excelClick}>
양식받기
</Button>
</div>
</div>
</SearchFormRight>
</SearchDiv>
</div>
</div>
<div className="grid grid-cols-12 gap-4 h-full">
<div className="col-span-4 h-full min-h-0">
<ListDiv className="min-h-0">
<ScrollArea className="h-[60vh]">
<UiTable
tableData={bdstTable || []}
headlist={pbnstPrfmncHeadList}
pageSize={10}
total={10000}
headName={"하수재이용시설 목록"}
cellClick={(index: number | undefined, headId: string) => {
cellClick(index, headId);
}}
onPageChange={setPageNation}
children={undefined}
/>
</ScrollArea>
</ListDiv>
</div>
<ListDiv className="col-span-8 pr-6 ">
<ScrollArea className="h-[60vh]">
<div className="card-header">
<h3 className="text-2xl font-medium text-label">
{"하수처리수재이용 실적(m3) 등록결과"}
</h3>
</div>
<Table variant="secondary">
<TableHeader className="font-bold">
{headMakeprfmnc(monthHeadList, [])}
</TableHeader>
<TableBody>
{InputTableBody(inputData ?? [], monthHeadList, setInputData)}
</TableBody>
</Table>
</ScrollArea>
</ListDiv>
</div>
</ContentsDiv>
<UiModal
bodyClass={""}
body={<PbnPrfExcelModal data={isExcelOpen.data}></PbnPrfExcelModal>}
open={isExcelOpen.isModal}
onOpenChange={() => {
setIsExcelOPen({ isModal: false, data: {} as FcPrfType });
}}
></UiModal>
<Toaster position="top-center" />
</>
);
}
@@ -0,0 +1,187 @@
"use client";
import { useWrStore } from "@/app/store";
import { type rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
import type { rswtChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn";
import {
excelArrayDownload,
excelDownload,
yearOptions,
} from "@/components/lib/func/commom";
import ChkgdExcel from "@/components/ui/modal/chkgd/chkgdExcel/chkgdExcel";
import ChkgdModal from "@/components/ui/modal/chkgd/chkgdModal/chkgdModal";
import RainChkgdTable from "@/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable";
import RswtChkgdTable from "@/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable";
import {
ContentsDiv,
SearchDiv,
SearchFormLeft,
SearchFormRight,
SearchInput,
SelectBox,
Title,
UiModal,
} from "@common/business_components/ui";
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";
//-----------------------
export default function Page() {
const {
code,
rainChkSttn,
rswtChkSttn,
rainChkSttnInit,
rainChkSttnSearch,
rswtChkSttnInit,
isRainSttn,
isRswtSttn
} = useWrStore((state) => {
return state;
});
const [selFcltDiv, setSelFcltDiv] = useState("RNB");
const [isModal, setIsModal] = useState({
open: false,
data: {},
});
const [searchYear, setSearchYear] = useState<string>(String(new Date().getFullYear()));
const cellClick = () => {
if (searchYear) rainChkSttnSearch(searchYear, "0");
};
useEffect(() => {
if (!rainChkSttn.isInit) {
isRainSttn(true)
rainChkSttnInit( "0");
setIsModal({ data: {}, open: false });
}
}, [rainChkSttn.isInit, rainChkSttnInit]);
useEffect(() => {
if (!rswtChkSttn.isInit) {
setIsModal({ data: {}, open: false });
rswtChkSttnInit( "0");
isRswtSttn(true)
}
},[rswtChkSttn.isInit, rswtChkSttnInit])
const handleClick = useCallback(
(data: any) => {
if (data) setIsModal({ open: !isModal.open, data: data });
},
[isModal]
);
const excelDown=() =>{
if(rainChkSttn.sttnExcelList && selFcltDiv === "RNB"){
excelDownload(
rainChkSttn.sttnExcelList,
"빗물이용시설 지도점검 현황",
"sample_rainChkSttn.xlsx",
"A1:Q2",
3
);
}else if(rswtChkSttn.sttnExcelList && selFcltDiv === "RST"){
excelDownload(
rswtChkSttn.sttnExcelList,
"중수도시설 지도점검 현황",
"sample_rswtChkSttn.xlsx",
"A1:X2",
3
);
}
}
return (
<ContentsDiv>
<div className="grid grid-cols-4 gap-4 ">
<div className="col-span-4">
<Title title={"지도점검 결과 현황"} />
<SearchDiv>
<SearchFormLeft>
<div className="col-span-2 flex flex-row space-x-2">
<Label className="w-48 mt-2 text-xl text-gray-600">{'지도점검년도'}</Label>
<SelectBox
className="w-full h-full text-2xl"
label=""
selectClass={""}
selectArray={yearOptions}
value={searchYear}
onSelectValue={(val: string | number) =>
setSearchYear(String(val))
}
/>
</div>
<div className="col-span-2 flex flex-row space-x-2">
<Label className="w-28 mt-2 text-xl text-gray-600">{'시설구분'}</Label>
<SelectBox
className={"w-full h-full text-2xl"}
label={""}
selectClass={""}
selectArray={rainChkSttn.fcltDiv}
onSelectValue={(val: string | number) =>
setSelFcltDiv(String(val))
}
value={selFcltDiv ?? rainChkSttn.fcltDiv[0]?.val}
/>
</div>
</SearchFormLeft>
<SearchFormRight>
<div className="space-y">
<div className="flex flex-row space-x-2">
<Button
size={"sm"}
onClick={(e) => {
cellClick();
}}
>
조회
</Button>
<Button color="green" size={"sm"} onClick={(e) =>{excelDown()}}>
다운로드
</Button>
</div>
</div>
</SearchFormRight>
</SearchDiv>
</div>
</div>
<div className="grid grid-cols-6 gap-4 ">
<div className="col-span-6">
<ListDiv>
{selFcltDiv === "RNB" ? (
<RainChkgdTable
deleteData={() => {}}
detailUp={() => {}}
handleClick={handleClick}
rainChkData={rainChkSttn.rainChkRes}
/>
) : (
<RswtChkgdTable
detaiRswtlUpdate={() => {}}
deleteRswtData={() => {}}
handleRswtClick={handleClick}
rswtChkData={rswtChkSttn.rswtChkRes}
/>
)}
</ListDiv>
</div>
</div>
<UiModal
open={isModal.open}
onOpenChange={() => {
setIsModal({ open: !open, data: {} });
}}
bodyClass={"w-[80vw] max-w-none"}
body={<ChkgdModal type={selFcltDiv} obj={isModal.data} />}
></UiModal>
<Toaster position="top-center" />
</ContentsDiv>
);
}
@@ -0,0 +1,650 @@
"use client";
import { useWrStore } from "@/app/store";
import { btnClass } from "@/app/store/common/code";
import { initValInUsage, initValOutUsage, subTotalObj, totalObj, type FcPrfType, type PrfType } from "@/app/store/prfmncReg/pbnstPrfmncReg/type";
import { excelPrfmncSttnParsing } from "@/app/store/prfmncSttn/pbnstPrfmncSttn/excel";
import { excelDownload, yearOptions } from "@/components/lib/func/commom";
import SearchInputText from "@/components/ui/searchInput/searchInput";
import { CHART_FORM, ContentsDiv, MainChart, ScrollArea, SearchBaseForm, SearchInput, SelectBox, Title, UiTable, type ChartConfig, type ReturnType } from "@common/business_components";
import ListDiv from "@common/business_components/ui/list_div";
import { Button, Label } from "@common/components/ui";
import { useCallback, useEffect, useRef, useState } from "react";
import toast, { Toaster } from "react-hot-toast";
export default function PbnstPrfmncSttn() {
const {
code,
tableHeadMaker,
pbnstPrfmncSttn,
pbnstPrfmncInit,
pbnstPrfmncSearch,
prfmnc,
pbnstSttn,
pbnNmSearch
} = useWrStore((state) => state);
const { monthHeadList } = prfmnc
const { pbnstPrfHeadList, prfmncRes, rawData, selectYearList } = pbnstPrfmncSttn;
const [isChHead, setIsChHead] = useState(false);
const [fromDate, setFromDate] = useState<string>(String(new Date().getFullYear()));
const [toDate, setToDate] = useState<string>(String(new Date().getFullYear()));
const [year, setYear] = useState<string>(String(new Date().getFullYear()));
const [bdstTable, setbdstTable] = useState<FcPrfType[]>();
const ref = useRef<ReturnType>({} as ReturnType);
const [swtrmtFcltNm, setSwtrmtFcltNm] = useState<string>();
const [pbnRuseNm, setPbnRuseNm] = useState<string>("");
const [searchYear, setSearchYear] = useState<string>(
String(new Date().getFullYear())
);
const [excelData, setExcelData] = useState<any[]>([]);
const excelClick = useCallback(() => {
excelDownload(
excelData,
"하수재이용실적 현황",
"sample_pbnstPrfmncSttn.xlsx",
"A1:N1",
2
);
}, [excelData]);
const [chartConfig, setChartConfig] = useState<ChartConfig>({});
const [chartData, setChartData] = useState<dnChartForm[]>([]);
const [dnInUsage, setDnInUsage] = useState<dnChartForm[]>([]);
const [dnInChartConfig, setDnInChartConfig] = useState<ChartConfig>({});
const [dnOutUsage, setDnOutUsage] = useState<dnChartForm[]>([]);
const [dnOutChartConfig, setDnOutChartConfig] = useState<ChartConfig>({});
const [barData, setBarData] = useState<barChartForm[]>([]);
const [barChartConfig, setBarChartConfig] = useState<ChartConfig>({});
const [prfData, setPrfData] = useState<any[]>();
const [lnInChartConfig, setLnInChartConfig] = useState<ChartConfig>({});
const [lnOutChartConfig, setLnOutChartConfig] = useState<ChartConfig>({});
const [inLineData, setInLineData] = useState<{
chartData1: lineChartDataProps[];
chartData2: lineChartDataProps[];
chartData3: lineChartDataProps[];
chartData4: lineChartDataProps[];
chartData5: lineChartDataProps[];
chartData6: lineChartDataProps[];
chartData7: lineChartDataProps[];
chartData8: lineChartDataProps[];
chartData9: lineChartDataProps[];
}>();
const [outLineData, setOutLineData] = useState<{
chartData1: lineChartDataProps[];
chartData2: lineChartDataProps[];
chartData3: lineChartDataProps[];
chartData4: lineChartDataProps[];
chartData5: lineChartDataProps[];
chartData6: lineChartDataProps[];
}>();
type dnChartForm = { label: string, val: number, fill?: string };
type barChartForm = { label: string, "장내용수": number, "장외용수": number };
type lineChartDataProps = { label: string, val: number, color: string };
const prfTableData = (prfList: PrfType[], year: string) => {
const inUsageData = structuredClone(initValInUsage);
const outUsageData = structuredClone(initValOutUsage);
const inSubtotal = structuredClone(subTotalObj);
const outSubtotal = structuredClone(subTotalObj);
const prfFilter = prfList?.filter((e) => e.ym.slice(0, 4) === year)
if (prfList && prfFilter.length > 0) {
prfList?.forEach((prfItem) => {
const month = Number(prfItem?.ym?.slice(4)); // "MM"
const monthKey = `${month}월`;
inUsageData.forEach((inData: any) => {
const usageKey = inData.usage;
const value = (prfItem as any)[usageKey] ?? 0;
inData[monthKey] = value;
inData.total += value;
if (inSubtotal && usageKey !== "subtotal") {
(inSubtotal as any)[monthKey] =
((inSubtotal as any)[monthKey] ?? 0) + value;
inSubtotal.total += value;
}
});
outUsageData.forEach((outData: any) => {
const usageKey = outData.usage;
const value = (prfItem as any)[usageKey] ?? 0;
outData[monthKey] = value;
outData.total += value;
if (usageKey !== "subtotal") {
(outSubtotal as any)[monthKey] =
((outSubtotal as any)[monthKey] ?? 0) + value;
outSubtotal.total += value;
}
});
});
inUsageData.push(inSubtotal);
outUsageData.push(outSubtotal);
const usageTotalObj: { [key: string]: any } = structuredClone(totalObj);
for (const key in usageTotalObj) {
if (["usage", "gubun", "edit"].includes(key)) continue;
const val =
(Number((inSubtotal as any)[key]) || 0) +
(Number((outSubtotal as any)[key]) || 0);
(usageTotalObj as any)[key] = val;
}
const tableData = [...inUsageData, ...outUsageData, usageTotalObj];
setPrfData(tableData);
setExcelData(excelPrfmncSttnParsing(prfData ?? []))
} else {
setPrfData([]);
}
}
const [chartId, setChartId] = useState<string>();
useEffect(() => {
// 누적 변수 초기화
let wshwtr = 0,
coolUswtr = 0,
cleanUswtr = 0,
drwtUswtr = 0,
dltnUswtr = 0,
ithlRswtr = 0,
ithlEtcUswtr = 0,
cleanToilUswtr = 0,
resn = 0;
let lndwtr = 0,
hydUswtr = 0,
ugwtChr = 0,
farmUswtr = 0,
rvrKeepUswtr = 0,
indstUswtr = 0;
let inUsageSum = 0,
outUsageSum = 0;
let inUsageArr: number[] = [],
outUsageArr: number[] = [];
// 라인차트용 데이터
const wshwtrData: lineChartDataProps[] = [],
coolUswtrData: lineChartDataProps[] = [],
cleanUswtrData: lineChartDataProps[] = [],
drwtUswtrData: lineChartDataProps[] = [],
dltnUswtrData: lineChartDataProps[] = [],
ithlRswtrData: lineChartDataProps[] = [],
ithlEtcUswtrData: lineChartDataProps[] = [],
cleanToilUswtrData: lineChartDataProps[] = [],
resnData: lineChartDataProps[] = [];
const lndwtrData: lineChartDataProps[] = [],
hydUswtrData: lineChartDataProps[] = [],
ugwtChrData: lineChartDataProps[] = [],
farmUswtrData: lineChartDataProps[] = [],
rvrKeepUswtrData: lineChartDataProps[] = [],
indstUswtrData: lineChartDataProps[] = [];
// 막대차트 데이터
const barData: barChartForm[] = [];
// 도넛차트 데이터
const dnData: dnChartForm[] = [];
const dnInData: dnChartForm[] = [];
const dnOutData: dnChartForm[] = [];
if (rawData) {
prfTableData([], year)
rawData.forEach((item) => {
// 실적 테이블 데이터
if (chartId){
if(item.prfList?.[0]?.ym.slice(0, 4) === year && item.prfList?.[0]?.pbnstRuseFcltFk === chartId){
prfTableData(item.prfList, year);
}
item.prfList.filter((e) => e.ym.slice(0, 4) === year && e.pbnstRuseFcltFk === chartId).forEach((element) => {
// 누적
wshwtr += element.wshwtr;
coolUswtr += element.coolUswtr;
cleanUswtr += element.cleanUswtr;
drwtUswtr += element.drwtUswtr;
dltnUswtr += element.dltnUswtr;
ithlRswtr += element.ithlRswtr;
ithlEtcUswtr += element.ithlEtcUswtr;
cleanToilUswtr += element.cleanToilUswtr;
resn += element.resn;
lndwtr += element.lndwtr;
hydUswtr += element.hydUswtr;
ugwtChr += element.ugwtChr;
farmUswtr += element.farmUswtr;
rvrKeepUswtr += element.rvrKeepUswtr;
indstUswtr += element.indstUswtr;
// 월별 합계
inUsageSum = element.wshwtr
+ element.coolUswtr
+ element.cleanUswtr
+ element.drwtUswtr
+ element.dltnUswtr
+ element.ithlRswtr
+ element.ithlEtcUswtr
+ element.cleanToilUswtr
+ element.resn;
outUsageSum = element.lndwtr
+ element.hydUswtr
+ element.ugwtChr
+ element.farmUswtr
+ element.rvrKeepUswtr
+ element.indstUswtr;
inUsageArr.push(inUsageSum);
outUsageArr.push(outUsageSum);
// 막대차트
const month = Number(element.ym.slice(4, 6));
barData.push({ label: `${month}월`, "장내용수": inUsageSum, "장외용수": outUsageSum });
// 라인차트
wshwtrData.push({ label: `${month}월`, val: element.wshwtr, color: "red" });
coolUswtrData.push({ label: `${month}월`, val: element.coolUswtr, color: "orange" });
cleanUswtrData.push({ label: `${month}월`, val: element.cleanUswtr, color: "yellow" });
drwtUswtrData.push({ label: `${month}월`, val: element.drwtUswtr, color: "pink" });
dltnUswtrData.push({ label: `${month}월`, val: element.dltnUswtr, color: "purple" });
ithlRswtrData.push({ label: `${month}월`, val: element.ithlRswtr, color: "green" });
ithlEtcUswtrData.push({ label: `${month}월`, val: element.ithlEtcUswtr, color: "blue" });
cleanToilUswtrData.push({ label: `${month}월`, val: element.cleanToilUswtr, color: "magenta" });
resnData.push({ label: `${month}월`, val: element.resn, color: "skyblue" });
lndwtrData.push({ label: `${month}월`, val: element.lndwtr, color: "red" });
hydUswtrData.push({ label: `${month}월`, val: element.hydUswtr, color: "orange" });
ugwtChrData.push({ label: `${month}월`, val: element.ugwtChr, color: "yellow" });
farmUswtrData.push({ label: `${month}월`, val: element.farmUswtr, color: "green" });
rvrKeepUswtrData.push({ label: `${month}월`, val: element.rvrKeepUswtr, color: "blue" });
indstUswtrData.push({ label: `${month}월`, val: element.indstUswtr, color: "purple" });
});
}
});
// 도넛차트 데이터
dnData.push({ label: "세척수", val: wshwtr, fill: "red" });
dnData.push({ label: "냉각수", val: coolUswtr, fill: "orange" });
dnData.push({ label: "청소수", val: cleanUswtr, fill: "yellow" });
dnData.push({ label: "식수대", val: drwtUswtr, fill: "green" });
dnData.push({ label: "희석용수", val: dltnUswtr, fill: "skyblue" });
dnData.push({ label: "중수도", val: ithlRswtr, fill: "blue" });
dnData.push({ label: "기타", val: ithlEtcUswtr, fill: "purple" });
dnData.push({ label: "청소화장실용수", val: cleanToilUswtr, fill: "red" });
dnData.push({ label: "세척살수용수", val: resn, fill: "orange" });
dnData.push({ label: "조경용수", val: lndwtr, fill: "yellow" });
dnData.push({ label: "친수용수", val: hydUswtr, fill: "green" });
dnData.push({ label: "지하수충전", val: ugwtChr, fill: "skyblue" });
dnData.push({ label: "농업용수", val: farmUswtr, fill: "blue" });
dnData.push({ label: "하천등유지용수", val: rvrKeepUswtr, fill: "purple" });
dnData.push({ label: "공업용수", val: indstUswtr, fill: "black" });
// 장내용수 도넛
dnInData.push({ label: "세척수", val: wshwtr, fill: "yellow" });
dnInData.push({ label: "냉각수", val: coolUswtr, fill: "green" });
dnInData.push({ label: "청소수", val: cleanUswtr, fill: "yellow" });
dnInData.push({ label: "식수대", val: drwtUswtr, fill: "green" });
dnInData.push({ label: "희석용수", val: dltnUswtr, fill: "yellow" });
dnInData.push({ label: "중수도", val: ithlRswtr, fill: "green" });
dnInData.push({ label: "기타", val: ithlEtcUswtr, fill: "yellow" });
dnInData.push({ label: "청소화장실용수", val: cleanToilUswtr, fill: "green" });
dnInData.push({ label: "세척살수용수", val: resn, fill: "yellow" });
// 장외용수 도넛
dnOutData.push({ label: "조경용수", val: lndwtr, fill: "yellow" });
dnOutData.push({ label: "친수용수", val: hydUswtr, fill: "black" });
dnOutData.push({ label: "지하수충전", val: ugwtChr, fill: "yellow" });
dnOutData.push({ label: "농업용수", val: farmUswtr, fill: "black" });
dnOutData.push({ label: "하천등유지용수", val: rvrKeepUswtr, fill: "yellow" });
dnOutData.push({ label: "공업용수", val: indstUswtr, fill: "black" });
// 라인차트 데이터
setInLineData({
chartData1: wshwtrData,
chartData2: coolUswtrData,
chartData3: cleanUswtrData,
chartData4: drwtUswtrData,
chartData5: dltnUswtrData,
chartData6: ithlRswtrData,
chartData7: ithlEtcUswtrData,
chartData8: cleanToilUswtrData,
chartData9: resnData
});
setOutLineData({
chartData1: lndwtrData,
chartData2: hydUswtrData,
chartData3: ugwtChrData,
chartData4: farmUswtrData,
chartData5: rvrKeepUswtrData,
chartData6: indstUswtrData,
});
setBarData(barData);
setChartData(dnData);
setDnInUsage(dnInData);
setDnOutUsage(dnOutData);
}
}, [rawData, year, chartId]);
useEffect(() => {
const newChartConfig = chartData.reduce((config, element) => {
config[element.label] = {
label: element.label,
fill: element.fill
};
return config;
}, {} as Record<string, { label: string; fill?: string }>) satisfies ChartConfig;
setChartConfig(newChartConfig);
}, [chartData]);
useEffect(() => {
const newChartConfig = dnInUsage.reduce((config, element) => {
config[element.label] = {
label: element.label,
fill: element.fill
};
return config;
}, {} as Record<string, { label: string; color: string; }>) satisfies ChartConfig;
setDnInChartConfig(newChartConfig);
}, [dnInUsage]);
useEffect(() => {
const newChartConfig = dnOutUsage.reduce((config, element) => {
config[element.label] = {
label: element.label,
fill: element.fill
};
return config;
}, {} as Record<string, { label: string; color: string; }>) satisfies ChartConfig;
setDnOutChartConfig(newChartConfig);
}, [dnOutUsage]);
useEffect(() => {
const newChartConfig = barData.reduce((config, element) => {
config[element.label] = {
label: element.label,
};
return config;
}, {} as Record<string, { label: string }>) satisfies ChartConfig;
setBarChartConfig(newChartConfig);
}, [barData]);
useEffect(() => {
if (inLineData?.chartData1) {
const newChartConfig = {
chartData1: {
label: '세척수',
color: "red",
},
chartData2: {
label: '냉각수',
color: "orange",
},
chartData3: {
label: '청소수',
color: "yellow",
},
chartData4: {
label: '식수대',
color: "pink",
},
chartData5: {
label: '희석용수',
color: "purple",
},
chartData6: {
label: '중수도',
color: "green",
},
chartData7: {
label: '기타',
color: "blue",
},
chartData8: {
label: '청소화장실용수',
color: "magenta",
},
chartData9: {
label: '세척살수용수',
color: "skyblue",
},
} satisfies ChartConfig;
setLnInChartConfig(newChartConfig);
}
}, [inLineData]);
useEffect(() => {
if (outLineData?.chartData1) {
const newChartConfig = {
chartData1: {
label: '조경용수',
color: "red",
},
chartData2: {
label: '친수용수',
color: "orange",
},
chartData3: {
label: '지하수충전',
color: "yellow",
},
chartData4: {
label: '농업용수',
color: "green",
},
chartData5: {
label: '하천등유지용수',
color: "blue",
},
chartData6: {
label: '공업용수',
color: "purple",
},
} satisfies ChartConfig;
setLnOutChartConfig(newChartConfig);
}
}, [outLineData]);
useEffect(() => {
const returnType: ReturnType = {
sidoValue: "0",
sigunValue: "0",
partValue: "A",
regionValue: "0",
unitWaterShedValue: "",
middleRegionValue: "",
envPartValue: "",
sidoText: "",
sigunText: ""
}
tableHeadMaker(Number(searchYear), Number(searchYear));
pbnstPrfmncSearch(returnType, "", searchYear, searchYear)
}, []);
useEffect(() => {
setbdstTable(prfmncRes);
if(prfmncRes?.[0]?.pbnstRuseFcltPk) setChartId(prfmncRes[0].pbnstRuseFcltPk)
}, [prfmncRes]);
useEffect(() => {
if (pbnRuseNm.length > 1)
pbnNmSearch("1", "23", ref.current, pbnRuseNm, searchYear);
}, [pbnRuseNm]);
const cellClick = (index: number | undefined, headId: string) => {
if (index !== undefined && headId !== undefined) {
setChartId(prfmncRes[index].pbnstRuseFcltPk)
}
}
return (
<>
<ContentsDiv>
<div className="grid grid-cols-4 gap-4 ">
<div className="col-span-4">
<Title title={"하수재이용실적 현황"} />
<SearchBaseForm
selectSidoData={code.cityCd}
selectSigunData={code.sggCd}
selectRegionData={code.rvbsnCd}
selectUnitWaterShedData={code.lgbsnCd}
selectMiddleRegionData={code.mdmbsnCd}
selectEnvPartData={code.lclgvrnmntCd}
rightChildren={<Button
className={btnClass}
onClick={() => {
setIsChHead(true);
}}
>
조회항목설정
</Button>}
leftChildren={<div className="col-span-5">
<div className="flex flex-row">
<div className="flex flex-row items-center">
<Label className="text-xl text-gray-600">하수 재이용년도</Label>
<SelectBox
className="h-full text-2xl"
label=""
selectClass={""}
selectArray={yearOptions}
value={fromDate}
onSelectValue={(val: string | number) => setFromDate(String(val))} />
<SelectBox
className="h-full text-2xl"
label=""
selectClass={""}
selectArray={yearOptions}
value={toDate}
onSelectValue={(val: string | number) => setToDate(String(val))} />
</div>
<SearchInputText
label={"하수처리시설"}
initValue={pbnRuseNm ?? ""}
setValue={(searchNm?: string) => {
setPbnRuseNm(searchNm || "");
}}
setRtnData={function (rtnData: any[]): void {
// setbdstTable(rtnData);
}}
searchList={pbnstSttn.pbnstSearchData || []}
></SearchInputText>
{/* <SelectBox
className="h-full text-2xl"
label="재이용시설명"
selectClass={""}
selectArray={[]}
value={""}
onSelectValue={() => { }} /> */}
</div>
</div>}
queryClick={function (returnType: ReturnType): void {
pbnstPrfmncSearch(returnType, pbnRuseNm ?? "", fromDate, toDate);
if (fromDate && toDate) {
const fromNum = Number(fromDate);
const toNum = Number(toDate);
if (fromNum > toNum) {
toast.error("시작년도가 종료년도 이후로 설정할 수 없습니다.");
} else {
if (toNum - fromNum > 5) {
toast.error("최대 5년까지 선택 가능합니다.");
} else {
tableHeadMaker(fromNum, toNum);
}
}
}
}}
excelClick={excelClick}
initClick={function (): void { }}
btnClass={btnClass}
ref={ref} isAdmin={false} />
</div>
</div>
<div className="grid grid-cols-6 gap-4 ">
<div className="col-span-6">
<ListDiv>
<UiTable
headName={[]}
tableData={bdstTable || []}
headlist={pbnstPrfHeadList}
pageSize={20}
total={10000}
cellClick={(index: number | undefined, headId: string) => {
cellClick(index ?? undefined, headId);
}}
onPageChange={() => { }
}
index={0}
/>
<hr />
<h3 className="mt-4 ml-2 text-2xl font-medium text-label">하수재이용실적 상세현황</h3>
<SelectBox
className="h-full w-1/12 text-2xl"
label=""
selectClass={""}
selectArray={selectYearList}
value={year}
onSelectValue={(val: string | number) => setYear(String(val))} />
<h1 className="">장내·외 용도별 하수재이용실적 현황(계)</h1>
<div className="flex">
<div className="w-1/3">
<MainChart chartConfig={chartConfig} chartData={chartData} chartTitle={"장내·외 용수 총 실적"} chartForm={CHART_FORM.DN} />
</div>
<div className="w-1/3">
<MainChart chartConfig={dnInChartConfig} chartData={dnInUsage} chartTitle={"장내용수 실적"} chartForm={CHART_FORM.DN} />
</div>
<div className="w-1/3">
<MainChart chartConfig={dnOutChartConfig} chartData={dnOutUsage} chartTitle={"장외용수 실적"} chartForm={CHART_FORM.DN} />
</div>
</div>
<h1 className="">장내·외 월별 하수재이용실적 현황</h1>
<div className="flex">
<div className="w-1/3">
<MainChart chartConfig={barChartConfig} chartData={barData} chartTitle={"월별 장내·외 용수 총 실적"} chartForm={CHART_FORM.DOUBLEBAR} />
</div>
<div className="w-1/3">
<MainChart chartConfig={lnInChartConfig} chartData={inLineData} chartTitle={"월별 장내 용수 실적"} chartForm={CHART_FORM.LINE} />
</div>
<div className="w-1/3">
<MainChart chartConfig={lnOutChartConfig} chartData={outLineData} chartTitle={"월별 장외 용수 총 실적"} chartForm={CHART_FORM.LINE} />
</div>
</div>
<h1 className="">하수재이용실적 현황</h1>
<ListDiv className="col-span-8 pr-6 ">
<ScrollArea className="h-[60vh]">
<div className="card-header">
<h3 className="text-2xl font-medium text-label">
{"하수처리수재이용 실적(m3) 등록결과"}
</h3>
</div>
<UiTable
headName={undefined}
tableData={prfData || []}
headlist={monthHeadList}
pageSize={0}
total={0}
cellClick={undefined}
onPageChange={function (page: number): void {
throw new Error("Function not implemented.");
}}>
</UiTable>
</ScrollArea>
</ListDiv>
</ListDiv>
</div>
</div>
</ContentsDiv>
<Toaster position="top-center" />
</>
)
}
+74
View File
@@ -0,0 +1,74 @@
'use client'
import { useWrStore } from "@/app/store";
import { yearOptions } from "@/components/lib/func/commom";
import { ContentsDiv, Title, SearchDiv, SearchFormLeft, SelectBox, UiTable } from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import { Button } from "@common/components/ui";
import { useState } from "react";
export default function MatStat(){
const { code, matStat } = useWrStore((state) => {
return state;
});
const [pageNation, setPageNation] = useState(1);
const [searchYear, setSearchYear] = useState<string>(
String(new Date().getFullYear())
);
return(
<>
<ContentsDiv>
<div className="grid grid-cols-4 gap-4">
<div className="col-span-4">
<Title title={"재이용 통계"} />
<SearchDiv>
<SearchFormLeft>
<SelectBox
className="w-full h-full text-2xl"
label="통계년도"
selectClass={""}
selectArray={yearOptions}
value={searchYear}
onSelectValue={(val: string | number) =>
setSearchYear(String(val))
}
/>
<div className="flex flex-row space-x-2 items-center">
<Button className="" size={"sm"} onClick={(e) => {}}>
조회
</Button>
<Button className="" size={"sm"} onClick={(e) => {}}>
다운로드
</Button>
<Button className="" size={"sm"} onClick={(e) => {}}>
전체통계다운로드
</Button>
</div>
</SearchFormLeft>
{/* <SearchFormRight>
</SearchFormRight> */}
</SearchDiv>
</div>
</div>
<div className="grid grid-cols-6 gap-4">
<div className="col-span-6 h-full min-h-0">
<ListDiv className="min-h-0">
{/* <ScrollArea className="h-[60vh]"> */}
<UiTable
tableData={[]}
headlist={matStat.matStatHeadList}
pageSize={20}
total={10000}
headName={"건축물 목록"}
cellClick={(val, headId) => {}}
onPageChange={setPageNation}
></UiTable>
{/* </ScrollArea> */}
</ListDiv>
</div>
</div>
</ContentsDiv>
</>
)
}
+275
View File
@@ -0,0 +1,275 @@
"use client";
import { useWrStore } from "@/app/store";
import type { RainStatProps } from "@/app/store/stats/rainStat";
import { excelDownload, tableData, yearOptions } from "@/components/lib/func/commom";
import { downloadExcel } from "@common/business_components";
import {
ContentsDiv,
ScrollArea,
SearchDiv,
SelectBox,
Title,
UiTable
} from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import { Button } from "@common/components/ui";
import { useEffect, useState } from "react";
export default function RainStat() {
const { code, rainStat, searchRainStatList } = useWrStore((state) => state);
const { rainStatList, excelList, rainDetailList } = rainStat;
const [searchYear, setSearchYear] = useState<string>(
String(new Date().getFullYear())
);
const [exData, setExData] = useState<Array<Record<string, string | number>>>();
const [bdstTable, setBdstTable] = useState<RainStatProps[]>();
useEffect(() => {
searchRainStatList(searchYear);
}, [code.cityCd, code.sggCd, searchRainStatList, searchYear])
const excelDetailDownLoad=() =>{
const sidoList = new Set<string>();
const sidoDataMap = new Map<string, (string | number)[]>(); // 시도별 데이터를 저장할 Map
const sidoDetailMap = new Map<string, (string | number)[][]>(); // 시도별 상세 데이터를 저장할 Map
// 먼저 시도별 상세 데이터를 그룹화
rainDetailList.forEach((item: RainStatProps[]) => {
const sidoVal = item.at(0)?.toString().trim();
const sigunVal = item.at(1)?.toString().trim();
let sidoText = '';
let sigunText = '';
const sido = code.cityCd.find((city) => city.val === sidoVal);
const sigun = code.sggCd.find((sgg) => sgg.val === sigunVal);
sidoText = sido?.text || '';
sigunText = sigun?.text || '';
// 시도, 시군구 코드를 텍스트로 변환하여 데이터에 할당
if (item.length > 0) {
item[0] = sidoText as unknown as RainStatProps;
}
if (item.length > 1) {
item[1] = sigunText as unknown as RainStatProps;
}
if (item.length > 2) {
item[2] = sidoText+' '+sigunText as unknown as RainStatProps;
}
// 시도별 상세 데이터 수집
if (sidoText) {
if (!sidoDetailMap.has(sidoText)) {
sidoDetailMap.set(sidoText, []);
}
sidoDetailMap.get(sidoText)!.push(item as unknown as (string | number)[]);
}
// 시도별 합계 데이터 수집
if (sidoText && !sidoList.has(sidoText)) {
sidoList.add(sidoText);
// 시도별 초기 데이터 구조 생성 (예: [시도명, 0, 0, 0, ...])
const initialData: (string | number)[] = [sidoText];
// 데이터의 나머지 컬럼들을 0으로 초기화 (실제 컬럼 수에 맞게 조정 필요)
for (let i = 1; i < item.length; i++) {
initialData.push(0);
}
sidoDataMap.set(sidoText, initialData);
}
});
// 시도별 합계 계산
rainDetailList.forEach((item: RainStatProps[]) => {
const sidoText = item[0]?.toString();
if (sidoText && sidoDataMap.has(sidoText)) {
const sidoData = sidoDataMap.get(sidoText)!;
// 각 컬럼의 값을 합계에 더하기 (1번 인덱스부터 시작)
for (let i = 1; i < item.length && i < sidoData.length; i++) {
if(i == 2){
sidoData[i] = '합계';
} else if(i == 3){
// 해당 시도의 데이터 개수를 계산
const sidoDataCount = rainDetailList.filter((data: unknown[]) =>
Array.isArray(data) && data.length > 0 && String(data[0]) === sidoText
).length;
sidoData[i] = sidoDataCount;
} else if( i == 4){
sidoData[i] = '';
} else if(i == 6){
// 법정 대상 건축물 개수 (인덱스 6이 'Y'인 경우)
const bumCnt = rainDetailList.filter((data: unknown[]) =>
Array.isArray(data) && data.length > 6 && String(data[0]) === sidoText
).filter((data: unknown[]) => String(data[6]) === '대상').length;
sidoData[i] = bumCnt;
} else if(i==8){
const value = Number(item[8]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
} else if(i==11){
const value = Number(item[11]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
} else if(i==12){
const value = Number(item[12]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
} else if(i==14){
const value = Number(item[14]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
}
else {
sidoData[i] = '';
}
}
}
});
// 시도별로 합계와 상세 데이터를 순서대로 배치
const summaryExcelData: (string | number)[][] = [];
// 시도별로 순회하면서 합계와 상세 데이터를 추가
Array.from(sidoList).forEach((sidoText) => {
const sidoSummary = sidoDataMap.get(sidoText);
const sidoDetails = sidoDetailMap.get(sidoText) || [];
if (sidoSummary) {
// 시도 합계 데이터 추가
summaryExcelData.push(sidoSummary);
// 해당 시도의 상세 데이터들 추가
sidoDetails.forEach(detail => {
summaryExcelData.push(detail);
});
}
});
const sidoSummaryList = Array.from(sidoDataMap.values());
const sidoTotalSummary = [['전체', '', '합계', 0, '', '', 0, '', '', 0, 0, 0, 0, 0, 0, '', 0]];
sidoSummaryList.forEach((item: (string | number)[]) => {
item.forEach((value: string | number, index: number) => {
if(typeof value === 'number') {
if (sidoTotalSummary[0] && index < sidoTotalSummary[0].length) {
sidoTotalSummary[0][index] = Number(sidoTotalSummary[0][index]) + Number(value);
}
}
});
});
// sidoSummaryList와 rainDetailList를 합쳐서 엑셀 데이터 생성
const excelData = [...sidoTotalSummary, ...sidoSummaryList, ...summaryExcelData];
excelDownload(
excelData as unknown as [][],
"빗물이용시설 통계",
"sample_rainStats.xlsx",
"A1:V3",
4
);
}
const excelClick = () => {
downloadExcel({
data: (exData as unknown as JSON[]) ?? [],
fileName: "재이용통계",
sheetNameArray: ["Sheet1"],
headerRange: "A1:M1"
})
}
useEffect(() => {
const transExcel = Array.isArray(excelList) ? excelList : [excelList];
const excelData = tableData(transExcel, { code });
const tbData = Array.isArray(excelData)
? excelData.map((item: RainStatProps) => {
return {
"시도": item.cityText,
"개소": item.tmp,
"설치비(백만원)": item.instlCst,
"저류조용량(m³/년)": item.dtfcltCpct,
"연간사용량(m³/년)": item.wtrUsqty,
"조경용수": item.lndwtr,
"청소화장실용수": item.cleanToilUswtr,
"세척살수용수": item.resn,
"농업용수": item.farmUswtr,
"공업용수": item.indstUswtr,
"친수용수": item.hydUswtr,
"기타": item.ithlEtcUswtr,
"연간운영비(백만원/년)": item.anlOperCst,
};
})
: [];
setExData(tbData);
}, [code, excelList])
useEffect(() => {
const transData = Array.isArray(rainStatList) ? rainStatList : [rainStatList];
const data = tableData(transData, { code });
const tbData = Array.isArray(data)
? data.map((item: RainStatProps) => {
return {
...item,
ctpvCd: item.cityText
};
})
: [];
setBdstTable(tbData);
}, [code, rainStatList]);
return (
<>
<ContentsDiv>
<div className="grid grid-cols-4 gap-4">
<div className="col-span-4">
<Title title={"빗물이용시설 통계"} />
<SearchDiv>
<div className="grid grid-cols-12 gap-5 m-4">
<div className="col-span-2">
<SelectBox
className="w-full h-full text-2xl"
label="통계년도"
selectClass={""}
selectArray={yearOptions}
value={searchYear}
onSelectValue={(val: string | number) =>
setSearchYear(String(val))
}
/>
</div>
<div className="flex flex-row space-x-2 items-center">
<Button className="" size={"sm"} onClick={() => { }}>
조회
</Button>
<Button className="" size={"sm"} onClick={() => excelClick()}>
다운로드
</Button>
<Button className="" size={"sm"} onClick={() => excelDetailDownLoad()}>
전체통계다운로드
</Button>
</div>
</div>
</SearchDiv>
{/* <SearchFormRight>
</SearchFormRight> */}
</div>
</div>
<div className="grid grid-cols-6 gap-4">
<div className="col-span-6 h-full min-h-0">
<ListDiv className="">
<ScrollArea className="h-[67vh]">
<UiTable
tableData={bdstTable || []}
headlist={rainStat.rainStatHeadList}
pageSize={10}
total={0}
headName={""}
cellClick={undefined}
onPageChange={() => {}}
></UiTable>
</ScrollArea>
</ListDiv>
</div>
</div>
</ContentsDiv>
</>
);
}
+289
View File
@@ -0,0 +1,289 @@
"use client";
import { useWrStore } from "@/app/store";
import type { RswtStatProps } from "@/app/store/stats/rswtStat";
import { excelDownload, tableData, yearOptions } from "@/components/lib/func/commom";
import {
ContentsDiv,
downloadExcel,
ScrollArea,
SearchDiv,
SelectBox,
Title,
UiTable
} from "@common/business_components/ui";
import ListDiv from "@common/business_components/ui/list_div";
import { Button } from "@common/components/ui";
import { useEffect, useState } from "react";
export default function RswtStat() {
const { code, rswtStat, searchRswtStatList } = useWrStore((state) => state);
const { rswtStatList, excelList, rswtDetailList } = rswtStat;
const [rswtTable, setRswtTable] = useState<RswtStatProps[]>();
const [searchYear, setSearchYear] = useState<string>(
String(new Date().getFullYear())
);
const [excelData, setExceData] = useState<Record<string, string | number>[]>();
useEffect(() => {
searchRswtStatList(searchYear)
}, [searchRswtStatList, searchYear])
const excelClick = () => {
downloadExcel({
data: (excelData as unknown as JSON[]) ?? [],
fileName: "중수도재이용통계",
sheetNameArray: ["Sheet1"],
headerRange: "A1:O1"
})
}
useEffect(() => {
const transData = Array.isArray(rswtStatList) ? rswtStatList : [rswtStatList];
const data = tableData(transData, { code });
const tbData = Array.isArray(data)
? data.map((item: RswtStatProps) => {
return {
...item,
ctpvCd: item.cityText
};
})
: [];
setRswtTable(tbData);
}, [code, rswtStatList])
useEffect(() => {
const transExcel = Array.isArray(excelList) ? excelList : [excelList];
const exData = tableData(transExcel, { code });
const tbData = Array.isArray(exData) ?
exData.map((item: RswtStatProps) => {
return {
"시도": item.cityText,
"개소": item.ctpvCnt,
"건축연면적(m³)": item.archArea,
"처리용량(m³)": item.filtrTrtmfctCpct,
"물사용량(m³/년)": item.wtrUsqty,
"중수도+대체수이용량(m³/년)": item.rswtAltSum,
"중수도이용량(m³/년)": item.rswtrUsqty,
"대체수이용량(m³/년)": item.altUswtrUtztnQnt,
"조경용수": item.lndwtr,
"청소화장실용수": item.cleanToilUswtr,
"농업용수": item.farmUswtr,
"공업용수": item.indstUswtr,
"친수용수": item.hydUswtr,
"기타": item.ithlEtcUswtr,
"연간운영비(백만원/년)": item.anlOperCst,
};
}) : [];
setExceData(tbData);
}, [code, excelList])
const excelDetailDownLoad=() =>{
const sidoList = new Set<string>();
const sidoDataMap = new Map<string, (string | number)[]>(); // 시도별 데이터를 저장할 Map
const sidoDetailMap = new Map<string, (string | number)[][]>(); // 시도별 상세 데이터를 저장할 Map
// 먼저 시도별 상세 데이터를 그룹화
rswtDetailList.forEach((item: RswtStatProps[]) => {
const sidoVal = item.at(0)?.toString().trim();
const sigunVal = item.at(1)?.toString().trim();
let sidoText = '';
let sigunText = '';
const sido = code.cityCd.find((city) => city.val === sidoVal);
const sigun = code.sggCd.find((sgg) => sgg.val === sigunVal);
sidoText = sido?.text || '';
sigunText = sigun?.text || '';
// 시도, 시군구 코드를 텍스트로 변환하여 데이터에 할당
if (item.length > 0) {
item[0] = sidoText as unknown as RswtStatProps;
}
if (item.length > 1) {
item[1] = sigunText as unknown as RswtStatProps;
}
if (item.length > 2) {
item[2] = sidoText+' '+sigunText as unknown as RswtStatProps;
}
// 시도별 상세 데이터 수집
if (sidoText) {
if (!sidoDetailMap.has(sidoText)) {
sidoDetailMap.set(sidoText, []);
}
sidoDetailMap.get(sidoText)!.push(item as unknown as (string | number)[]);
}
// 시도별 합계 데이터 수집
if (sidoText && !sidoList.has(sidoText)) {
sidoList.add(sidoText);
// 시도별 초기 데이터 구조 생성 (예: [시도명, 0, 0, 0, ...])
const initialData: (string | number)[] = [sidoText];
// 데이터의 나머지 컬럼들을 0으로 초기화 (실제 컬럼 수에 맞게 조정 필요)
for (let i = 1; i < item.length; i++) {
initialData.push(0);
}
sidoDataMap.set(sidoText, initialData);
}
});
// 시도별 합계 계산
rswtDetailList.forEach((item: RswtStatProps[]) => {
const sidoText = item[0]?.toString();
if (sidoText && sidoDataMap.has(sidoText)) {
const sidoData = sidoDataMap.get(sidoText)!;
// 각 컬럼의 값을 합계에 더하기 (1번 인덱스부터 시작)
for (let i = 1; i < item.length && i < sidoData.length; i++) {
if(i == 2){
sidoData[i] = '합계';
} else if(i == 3){
// 해당 시도의 데이터 개수를 계산
const sidoDataCount = rswtDetailList.filter((data: unknown[]) =>
Array.isArray(data) && data.length > 0 && String(data[0]) === sidoText
).length;
sidoData[i] = sidoDataCount;
} else if( i == 4){
sidoData[i] = '';
} else if(i == 6){
// 법정 대상 건축물 개수 (인덱스 6이 'Y'인 경우)
const bumCnt = rswtDetailList.filter((data: unknown[]) =>
Array.isArray(data) && data.length > 6 && String(data[0]) === sidoText
).filter((data: unknown[]) => String(data[6]) === '대상').length;
sidoData[i] = bumCnt;
} else if(i==9){
const value = Number(item[9]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
} else if(i==10){
const value = Number(item[10]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
} else if(i==11){
const value = Number(item[11]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
} else if(i==12){
const value = Number(item[12]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
}else if(i==13){
const value = Number(item[13]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
} else if(i==14){
const value = Number(item[14]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
} else if(i==16){
const value = Number(item[16]) || 0;
sidoData[i] = (Number(sidoData[i]) + value) as string | number;
} else {
sidoData[i] = '';
}
}
}
});
// 시도별로 합계와 상세 데이터를 순서대로 배치
const summaryExcelData: (string | number)[][] = [];
// 시도별로 순회하면서 합계와 상세 데이터를 추가
Array.from(sidoList).forEach((sidoText) => {
const sidoSummary = sidoDataMap.get(sidoText);
const sidoDetails = sidoDetailMap.get(sidoText) || [];
if (sidoSummary) {
// 시도 합계 데이터 추가
summaryExcelData.push(sidoSummary);
// 해당 시도의 상세 데이터들 추가
sidoDetails.forEach(detail => {
summaryExcelData.push(detail);
});
}
});
const sidoSummaryList = Array.from(sidoDataMap.values());
const sidoTotalSummary = [['전체', '', '합계', 0, '', '', 0, '', '', 0, 0, 0, 0, 0, 0, '', 0]];
sidoSummaryList.forEach((item: (string | number)[]) => {
item.forEach((value: string | number, index: number) => {
if(typeof value === 'number') {
if (sidoTotalSummary[0] && index < sidoTotalSummary[0].length) {
sidoTotalSummary[0][index] = Number(sidoTotalSummary[0][index]) + Number(value);
}
}
});
});
// sidoSummaryList와 rainDetailList를 합쳐서 엑셀 데이터 생성
const excelData = [...sidoTotalSummary,...sidoSummaryList, ...summaryExcelData];
excelDownload(
excelData as unknown as [][],
"중수도시설 통계",
"sample_rswtStats.xlsx",
"A1:Q3",
4
);
}
return (<>
<ContentsDiv>
<div className="grid grid-cols-4 gap-4">
<div className="col-span-4">
<Title title="중수도시설 통계" />
<SearchDiv>
<div className="grid grid-cols-12 gap-5 m-4">
<div className="col-span-2">
<SelectBox
className="w-full h-full text-2xl"
label="통계년도"
selectClass=""
selectArray={yearOptions}
value={searchYear}
onSelectValue={(val: string | number) => setSearchYear(String(val))}
/>
</div>
<div className="flex flex-row space-x-2 items-center">
<Button
className=""
size="sm"
onClick={() => {
searchRswtStatList(searchYear)
}}
>
조회
</Button>
<Button
className=""
size="sm"
onClick={() => excelClick()}
>
다운로드
</Button>
<Button
className=""
size="sm"
onClick={() => { excelDetailDownLoad() }}
>
전체통계다운로드
</Button>
</div>
</div>
</SearchDiv>
</div>
</div>
<div className="grid grid-cols-6 gap-4">
<div className="col-span-6 h-full min-h-0">
<ListDiv className="">
<ScrollArea className="h-[67vh]">
<UiTable
tableData={rswtTable || []}
headlist={rswtStat.rswtStatHeadList}
pageSize={10}
total={0}
headName=""
cellClick={undefined}
onPageChange={() => { }}
/>
</ScrollArea>
</ListDiv>
</div>
</div>
</ContentsDiv>
</>
);
}
+370
View File
@@ -0,0 +1,370 @@
import { getFetch } from "@/components/lib/api";
import type { EnvPartSelectDataType, SelectDataType } from "@common/business_components/ui";
export const btnClass = "p-4 m-2 text-white rounded-sm text-lg font-medium "
const yn: SelectDataType[] = [
{ val: 'Y', text: 'Y' },
{ val: 'N', text: 'N' },
]
//공통 건축물 용도
const bdstUsgCd: SelectDataType[] = [
{ val: '-1', text: "확인불가" },
{ val: '1', text: "운동장" },
{ val: '2', text: "체육관" },
{ val: '3', text: "공공업무시설" },
{ val: '4', text: "공공기관의청사" },
{ val: '5', text: "아파트" },
{ val: '6', text: "연립주택" },
{ val: '7', text: "다세대주택" },
{ val: '8', text: "기숙사" },
{ val: '9', text: "초등학교" },
{ val: '10', text: "중학교" },
{ val: '11', text: "고등학교" },
{ val: '12', text: "전문대학" },
{ val: '13', text: "대학및대학교" },
{ val: '14', text: "골프장" },
{ val: '15', text: "대규모점포" },
{ val: '16', text: "기타" },
];
//빗물 집수면 종류 용도
// const rainFcltCd = [
// { val: "1", text: "지붕" },
// { val: "2", text: "건물옥상" },
// { val: "3", text: "골프장 연못" },
// { val: "4", text: "운동장 바닥" },
// { val: "5", text: "운동장 지붕" },
// { val: "6", text: "주차장" },
// { val: "7", text: "태양광패널" },
// { val: "8", text: "연못" },
// { val: "9", text: "기타" },
// { val: "10", text: "확인불가" },
// ];
// 중수도 필수 원수종류
const rswtBdstType: SelectDataType[] = [
{ text: "숙박업", val: "17" },
{ text: "목욕장업", val: "18" },
{ text: "공장", val: "19" },
{ text: "발전시설", val: "20" },
{ text: "관광단지개발사업", val: "21" },
{ text: "도시개발사업", val: "22" },
{ text: "산업단지개발사업", val: "23" },
{ text: "택지개발사업", val: "24" },
{ text: "대규모점포(대형마트)", val: "25" },
{ text: "대규모점포(전문점)", val: "26" },
{ text: "대규모점포(백화점)", val: "27" },
{ text: "대규모점포(쇼핑센터)", val: "28" },
{ text: "대규모점포(복합쇼핑몰)", val: "29" },
{ text: "물류시설", val: "30" },
{ text: "운수시설(여객자동차터미널)", val: "31" },
{ text: "운수시설(철도시설)", val: "32" },
{ text: "운수시설(공항시설)", val: "33" },
{ text: "운수시설(항만시설)", val: "34" },
{ text: "업무시설(공공업무시설)", val: "35" },
{ text: "업무시설(금융업소)", val: "36" },
{ text: "업무시설(사무소)", val: "37" },
{ text: "업무시설(결혼상담소 등 소개업소)", val: "38" },
{ text: "업무시설(출판사)", val: "39" },
{ text: "업무시설(신문사)", val: "40" },
{ text: "업무시설(오피스텔)", val: "41" },
{ text: "교정시설", val: "42" },
{ text: "방송국", val: "43" },
{ text: "전신전화국", val: "44" },
{ text: "기타", val: "45" }
];
const orgwtKndCd = [
{ text: "오수(변기 오수 제외)", val: "1" },
{ text: "오수", val: "2" },
{ text: "폐수", val: "3" },
{ text: "오수 및 폐수", val: "4" },
{ text: "기타", val: "5" },
];
const chBuCd = [
{ val: "증축", text: "증축" },
{ val: "개축", text: "개축" },
{ val: "재축", text: "재축" },
]
const dmdUszCd = [
{ val: "조경용수", text: "조경용수" },
{ val: "청소화장실용수", text: "청소화장실용수" },
{ val: "농업용수", text: "농업용수" },
{ val: "공업용수", text: "공업용수" },
{ val: "친수용수", text: "친수용수" },
{ val: "기타", text: "기타" },
]
const ruseMngMtd = [
{ val: "자체운영", text: "자체운영" },
{ val: "공기업", text: "공기업" },
{ val: "민간(대행)", text: "민간(대행)" },
]
const pplQulity = [
{ val: "도복장강관", text: "도복장강관" },
{ val: "PE관", text: "PE관" },
{ val: "스테인레스관", text: "스테인레스관" },
{ val: "덕타일주철관", text: "덕타일주철관" },
{ val: "유리섬유복합관", text: "유리섬유복합관" },
{ val: "기타", text: "기타" },
]
const pplLenght = [
{ val: "D100", text: "D100" },
{ val: "D200", text: "D200" },
{ val: "D250", text: "D250" },
{ val: "D300", text: "D300" },
{ val: "D350", text: "D350" },
{ val: "D400", text: "D400" },
{ val: "D450", text: "D450" },
{ val: "D500", text: "D500" },
{ val: "D700", text: "D700" },
{ val: "D900", text: "D900" },
{ val: "D1000​", text: "D1000​" },
]
export const buildingType = {
RST:"RST",
RNB:"RNB",
HTB:"HTB"
}
const rainFcltCd = [
{ val: "지붕", text: "지붕" },
{ val: "건물옥상", text: "건물옥상" },
{ val: "골프장 연못", text: "골프장 연못" },
{ val: "운동장 바닥", text: "운동장 바닥" },
{ val: "운동장 지붕", text: "운동장 지붕" },
{ val: "주차장", text: "주차장" },
{ val: "태양광패널", text: "태양광패널" },
{ val: "연못", text: "연못" },
{ val: "기타", text: "기타" },
{ val: "확인불가", text: "확인불가" },
];
export type comCodeState = {
code: {
isInit: boolean;
chBuCd: SelectDataType[]
rainFcltCd: SelectDataType[];
bdstUsgCd: SelectDataType[];
cityCd: SelectDataType[];
sggCd: SelectDataType[];
rvbsnCd: SelectDataType[];
mdmbsnCd: SelectDataType[];
lgbsnCd: SelectDataType[];
lclgvrnmntCd: EnvPartSelectDataType[];
orgwtKndCd: SelectDataType[];
yn: SelectDataType[];
pplQulity: SelectDataType[];
pplLenght: SelectDataType[];
dmdUszCd:SelectDataType[]
buildingType: {
RST:string,
RNB:string,
HTB:string
}
ruseMngMtd:SelectDataType[]
};
};
export type comCodeType = comCodeState & comCodeActions;
export const getSggCd = async (set: any) => {
const sgg = await getFetch("common", "/addr/sgg");
/* const sggCd = sgg.map((item: any) => ({
val: item.adstDstrCd,
text: item.gugun,
})); */
const sggCd = [
{ text: "전체", val: '0' },
...sgg
.map((item: any) => ({
text: item.gugun || '',
val: String(item.adstDstrCd) || ''
}))
];
set((state: comCodeState) => ({
code: {
...state.code,
sggCd: sggCd,
},
}));
};
export const getCityCd = async (set: any) => {
const city = await getFetch("common", "/addr/city");
const cityCd = city.map((item: any) => ({
val: item.adstDstrCd,
text: item.sido,
}));
cityCd.unshift({ val: '0', text: '전체' })
set((state: comCodeState) => ({
code: {
...state.code,
cityCd: cityCd,
},
}));
};
// 권역 API 호출 함수 추가
export const getRegionCd = async (set: any) => {
try {
const rvbsn = await getFetch("common", "/addr/sarea");
const rvbsnCd = rvbsn.map((item: any) => ({
val: item.rvbsnCd,
text: item.rvbsn,
}));
rvbsnCd.unshift({ val: '0', text: '전체' })
set((state: comCodeState) => ({
code: {
...state.code,
rvbsnCd: rvbsnCd,
},
}));
} catch (error) {
console.error('권역 데이터를 가져오는데 실패했습니다:', error);
}
};
// 중권역 API 호출 함수 추가
export const getMiddleRegionCd = async (set: any) => {
try {
const mdmbsn = await getFetch("common", "/addr/midArea");
const mdmbsnCd = mdmbsn.map((item: any) => ({
val: item.rvbsnCd,
text: item.mdmbsn,
}));
mdmbsnCd.unshift({ val: '0', text: '전체' })
set((state: comCodeState) => ({
code: {
...state.code,
mdmbsnCd: mdmbsnCd,
},
}));
} catch (error) {
console.error('중권역 데이터를 가져오는데 실패했습니다:', error);
}
};
// 단위유역 API 호출 함수 추가
export const getUnitWaterShedCd = async (set: any) => {
try {
const lgbsn = await getFetch("common", "/addr/largeArea");
const lgbsnCd = lgbsn.map((item: any) => ({
val: item.rvbsnCd,
text: item.lgbsn,
}));
lgbsnCd.unshift({ val: '0', text: '전체' })
set((state: comCodeState) => ({
code: {
...state.code,
lgbsnCd: lgbsnCd,
},
}));
} catch (error) {
console.error('대영역 데이터를 가져오는데 실패했습니다:', error);
}
};
// 환경청 데이터
export const getEnvPartCd = async (set: any) => {
try {
const lclgvrnmnt = await getFetch('common', '/addr/govArea');
const lclgvrnmntCd = lclgvrnmnt.map((item: any) => ({
val: item.lclgvrnmntCd,
text: item.lclgvrnmntNm,
adstDliStrCd: item.adstDliStrCd || ''
}));
lclgvrnmntCd.unshift({ val: '0', text: '전체', adstDliStrCd: '' })
set((state: comCodeState) => ({
code: {
...state.code,
lclgvrnmntCd: lclgvrnmntCd,
},
}));
} catch (error) {
console.error('환경청 데이터를 가져오는데 실패했습니다:', error);
}
};
export const comCodeStateExport: comCodeState = {
code: {
isInit: false,
rainFcltCd: rainFcltCd,
bdstUsgCd: bdstUsgCd,
chBuCd: chBuCd,
orgwtKndCd: orgwtKndCd,
cityCd: [],
sggCd: [],
rvbsnCd: [],
mdmbsnCd: [],
lgbsnCd: [],
lclgvrnmntCd: [],
pplQulity:pplQulity,
pplLenght:pplLenght,
yn: yn,
dmdUszCd:dmdUszCd,
buildingType:buildingType,
ruseMngMtd:ruseMngMtd,
},
};
export type comCodeActions = {
codeInit: () => void;
};
export const codeActionExport: (set: any) => comCodeActions = (set: any) => {
return {
codeInit: async () => {
const sgg = await getFetch("common", "/addr/sgg");
const sggCd = sgg.map((item: any) => ({
val: item.adstDstrCd,
text: item.gugun,
}));
const city = await getFetch("common", "/addr/city");
const cityCd = city.map((item: any) => ({
val: item.adstDstrCd,
text: item.sido,
}));
return set((state: comCodeState) => ({
code: {
...state.code,
sggCd: sggCd,
cityCd: cityCd,
},
}));
},
divCityCd: async (cd: string) => {
set((state: comCodeState) => ({
code: {
...state.code,
sggCd: state.code.sggCd.filter((item) => { return item.val.toString().slice(0, 2) === cd }),
},
}));
},
};
};
@@ -0,0 +1,122 @@
import {
fetchType,
getFetch,
postFectch,
putFectch,
} from "@/components/lib/api";
import type { pubHasuType } from "../../ruseFcltMng/fcltReg/pbnstReg/type";
import type { DemandCompType } from "@common/business_components/ui/sdmInsertForm/form";
import type { conCostFeeType, rateFeeType } from "./type";
export type comFcltState = {
searchFclts: pubHasuType;
demandCompList: DemandCompType[];
dmdIsSucees: string;
checkDemand: DemandCompType;
constCostRes:conCostFeeType[],
rateFeeRes:rateFeeType[],
};
export type comFcltActions = {
getSwtrmtFcltNm: (searchNm: string) => void;
getDemandCompList: (searchNm: string, cnt: number) => void;
regDemandCompany: (data: DemandCompType) => void;
updateDemandCompany: (data: DemandCompType) => void;
getConstCostFee: (year: string) => void;
getRateFee: (year: string) => void;
};
export const searchActions: (set: any) => comFcltActions = (set: any) => {
return {
getSwtrmtFcltNm: async (searchNm: string) => {
const fcltNm = await getFetch(
"common",
`/prcsFclt/info/1/11/${searchNm}`
);
const searchFclts: pubHasuType[] = fcltNm.map((item: any) => ({
bscFctCd: item.bscFctCd,
sido: item.sido,
gugun: item.gugun,
bscFctNm: item.bscFctNm,
addr: item.addr,
fctCpc: item.fctCpc,
}));
set((state: comFcltState) => ({
...state,
searchFclts: searchFclts,
}));
},
getDemandCompList: async (searchNm: string, cnt: number) => {
const coList = await getFetch(
fetchType.WR,
`/reuseFc/request/${searchNm}/${cnt}`
);
console.log(coList);
set((state: comFcltState) => {
return (state.demandCompList = [...coList]);
});
},
regDemandCompany: async (data: DemandCompType) => {
try {
const response = await postFectch(
"/reuseFc/request",
data,
fetchType.WR
);
let message = "";
if (response.status === 200) {
message = "success";
} else {
message = "fail";
}
set((state: comFcltState) => {
state.dmdIsSucees = message;
return state;
});
} catch (err) {
console.log(err);
}
},
updateDemandCompany: async (data: DemandCompType) => {
try {
const response = await putFectch("/reuseFc/request", data);
let message = "";
if (response.status === 200) {
message = "success";
} else {
message = "fail";
}
set((state: comFcltState) => {
state.dmdIsSucees = message;
return state;
});
} catch (err) {
console.log(err);
}
},
getRateFee: async (year: string) => {
try {
const url = `/prcsFclt/CstRt/${year}`;
const rateFeeRes = await getFetch(fetchType.COMMON, url);
set((state: comFcltState) => {
return state.rateFeeRes = rateFeeRes;;
});
} catch (e) {
console.log(" error ", e);
}
},getConstCostFee: async (year: string) => {
try {
const url = `/prcsFclt/CstRuse/${year}`;
const constCost = await getFetch(fetchType.COMMON, url);
set((state: comFcltState) => {
return state.constCostRes = constCost;;
});
}catch (e) {
}
}
};
};
@@ -0,0 +1,32 @@
export type conCostFeeType= {
yr: string,
fctCpc: string,
fctCd: string,
stdCost: string
}
export type rateFeeType = {
yr: string,
incExpCd: string,
stdCost: number,
rt: number
}
export type ContCostMap = {
gubun: string;
"500": number;
"1000": number;
"2000": number;
"3000": number;
"5000": number;
"10000": number;
"20000": number;
"30000": number;
"50000": number;
"100000": number;
[key: string]: any;
};
+27
View File
@@ -0,0 +1,27 @@
export type CommonTableProps = {
id: string;
title: string;
upName?: string;
upSequnce?: number;
row?: number;
rowSpan?: number;
colSpan?: number;
visible?: boolean;
};
export type TableUpperProps = {
id: string;
title: string;
upName?: string;
upSequnce?: number;
edit?:boolean;
visible?:boolean;
rowSpan?: number;
colSpan?: number;
type?: string;
selectData ?:string; // type 이 seelct 일경우 selectarray 정하기 위해
row?:number;
mergeCell?:boolean // 셀을 합칠경우
readonly?:boolean
};
+3 -6
View File
@@ -1,4 +1,3 @@
'use client'
import { type ReactNode, createContext, useContext, useRef } from 'react'
import { useStore } from 'zustand'
@@ -15,13 +14,11 @@ export interface StoreProviderProps {
children: ReactNode
}
export const StoreProvider = ({
export const StoreProvider = ({
children,
}: StoreProviderProps) => {
const storeRef = useRef<StoreApi>(null)
if (!storeRef.current) {
storeRef.current = StoreZus()
}
const storeRef = useRef<StoreApi>(StoreZus())
return (
<StoreContext.Provider value={storeRef.current}>
{children}
@@ -0,0 +1,199 @@
import type { CommonTableProps, TableUpperProps } from "../../common/type/header";
export const coRvwHeadListExport: CommonTableProps[]= [
{
id: "cityText",
title: "시도",
visible: true,
},
{
id: "sggText",
title: "시군구",
visible: true,
},
{
id: "dmdCoNm",
title: "회사명",
visible: true,
},
{
id: "daddr",
title: "공장주소",
visible: true,
},
{
id: "telno",
title: "전화번호",
visible: true,
},
{
id: "regDt", //바꾸기
title: "신청일자",
visible: true,
},
{
id: "state", //바꾸기
title: "진행상태",
visible: true,
},
];
// id는 다확인해야함
export const coRvwNodeListExport: CommonTableProps[] = [
{
id: "ctpv",
title: "시도",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "sgg",
title: "시군구",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "coNm",
title: "회사명",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "addr",
title: "공장주소",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "telNo",
title: "전화번호",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "regDt", //바꾸기
title: "신청일자",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "state", //바꾸기
title: "진행상태",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
];
export const constCostHeadListExport: CommonTableProps[] = [
{
id: "gubun",
title: "구분",
visible: true,
},
{
id: "500",
title: "500",
visible: true,
},
{
id: "1000",
title: "1,000",
visible: true,
},
{
id: "2000",
title: "2,000",
visible: true,
},
{
id: "3000", //바꾸기
title: "3,000",
visible: true,
},
{
id: "5000", //바꾸기
title: "5,000",
visible: true,
},
{
id: "10000", //
title: "10,000",
visible: true,
},
{
id: "20000", //
title: "20,000",
visible: true,
},
{
id: "30000", //
title: "30,000",
visible: true,
},
{
id: "50000", //
title: "50,000",
visible: true,
},
{
id: "100000", //바꾸기
title: "100,000",
visible: true,
},
];
export const rateFeeHeadListExport: CommonTableProps[] = [
{
id: "gubun",
title: "공사비/구분",
visible: true,
},
{
id: "BD",
title: "기본조사설계비",
visible: true,
},
{
id: "WD",
title: "실시설계비",
visible: true,
},
{
id: "SE",
title: "공사감리비",
visible: true,
},
{
id: "CE",
title: "시설부대비",
visible: true,
},
];
export const usageProcData = [
{ usage: "청소", process: "총인처리시설+염소소독" },
{ usage: "화장실용수", process: "총인처리시설+염소소독" },
{ usage: "세척", process: "총인처리시설+UV소독" },
{ usage: "살수", process: "총인처리시설+UV소독" },
{ usage: "조경", process: "총인처리시설+UV소독" },
{ usage: "농업", process: "총인처리시설+UV소독" },
{ usage: "하천", process: "총인처리시설+UV소독" },
{ usage: "지하수", process: "전처리시설+RO" },
{ usage: "공업", process: "전처리시설+RO" },
];
+183
View File
@@ -0,0 +1,183 @@
import { constCostHeadListExport, coRvwHeadListExport, coRvwNodeListExport, rateFeeHeadListExport } from "./headList";
import type { CommonTableProps } from "../../common/type/header";
import type { DedMatUpdateType, DmdCoReqType } from "./type";
import { fetchType, getFetch, putFectch } from "@/components/lib/api";
import toast from "react-hot-toast/headless";
const coRvwHeadList = coRvwHeadListExport;
const coRvwNodeList = coRvwNodeListExport;
const rateFeeHeadList =rateFeeHeadListExport;
const constCostHeadList=constCostHeadListExport
export type coRvwState = {
coRvw: {
isInit: boolean;
coMatRvwRes: DmdCoReqType[];
coRvwHeadList: CommonTableProps[];
coRvwNodeList: CommonTableProps[];
rateFeeHeadList: CommonTableProps[];
constCostHeadList: CommonTableProps[];
};
};
export const coRvwStateExport: coRvwState = {
coRvw: {
isInit: false,
coMatRvwRes: [],
coRvwHeadList: coRvwHeadList,
coRvwNodeList: coRvwNodeList,
rateFeeHeadList:rateFeeHeadList,
constCostHeadList:constCostHeadList
},
};
export type coRvwType = coRvwState & coRvwActions;
type coRvwActions = {
coMatRvwInit: (
pageNo: number,
pageCnt: number,
startYear: string,
endYear: string,
) => void;
coMatRvwUpdate: (
splyCd: string,
dmdCd: string,
data: DedMatUpdateType
) => void;
coMatRvwSearch: (
pageNo: number,
pageCnt: number,
startYear: string,
endYear: string,
sggCd: string,
dmdCoNm: string,
) => void;
coMatRvwInqua: (
pageNo: number,
pageCnt: number,
startYear: string,
endYear: string,
sggCd: string
) => void;
};
const coMatInit = async (
pageNo: number,
pageCnt: number,
startYear: string,
endYear: string,
) => {
const url = `/reuseFc/request/infoList/sub/${pageNo}/${pageCnt}/${startYear}/${endYear}`;
const coMatRvwRes = await getFetch(fetchType.WR, url);
return coMatRvwRes;
};
export const coRvwActionsExport: (set: any) => coRvwActions = (set: any) => {
return {
coMatRvwInit: async (
pageNo: number,
pageCnt: number,
startYear: string,
endYear: string,
) => {
const coMatRvwRes = await coMatInit(pageNo, pageCnt, startYear, endYear);
return set((state: coRvwState) => ({
...state,
coRvw: {
...state.coRvw,
init: false,
coMatRvwRes: coMatRvwRes,
},
}));
},
coMatRvwUpdate: async (
splyCd: string,
dmdCd: string,
data: DedMatUpdateType
) => {
try {
const isUpdate = await putFectch(
`/reuseFc/request/cst/${splyCd}/${dmdCd}`,
data
);
const coMatRvwRes = coMatInit(
1,
10,
new Date().getFullYear().toString(),
new Date().getFullYear().toString(),
);
return set((state: coRvwState) => ({
...state,
coRvw: {
...state.coRvw,
init: false,
coMatRvwRes: coMatRvwRes,
},
}));
} catch (e) {
toast.error("매칭 검토 저장 오류입니다.");
}
},
coMatRvwSearch: async (
pageNo: number,
pageCnt: number,
startYear: string,
endYear: string,
sggCd: string,
dmdCoNm: string,
) => {
let url = `/reuseFc/request/infoList/sub/${pageNo}/${pageCnt}/${startYear}/${endYear}`;
if (sggCd.length > 0) {
url += `/${sggCd}`;
} else {
url += `/0`;
}
if (dmdCoNm?.length > 0) {
url += `/${dmdCoNm}`;
} else {
url += `/0`;
}
console.log(' url ', url)
const coMatRvwRes = await getFetch(fetchType.WR, url);
return set((state: coRvwState) => ({
...state,
coRvw: {
...state.coRvw,
coMatRvwRes: coMatRvwRes,
},
}));
},
coMatRvwInqua: async (
pageNo: number,
pageCnt: number,
startYear: string,
endYear: string,
sggCd: string
) => {
try {
let url = `/reuseFc/request/infoList/sub/${pageNo}/${pageCnt}/${startYear}/${endYear}`;
if (sggCd.length > 0) {
url += `/${sggCd}/0`;
}else if(sggCd ==='0'){
url += `/0/0`;
}
const coMatRvwRes = await getFetch(fetchType.WR, url);
return set((state: coRvwState) => ({
...state,
coRvw: {
...state.coRvw,
coMatRvwRes: coMatRvwRes,
},
}));
} catch (e) {
console.log(" error ", e);
}
}
};
};
+173
View File
@@ -0,0 +1,173 @@
import { z } from "zod";
const DemandInfoSchema = z.object({
dmdInfoSn: z.number(),
dmdInfoFk: z.string(),
dmndTmng: z.coerce.date(),
dmndQty: z.number(),
wntUntprc: z.number(),
grssClfg: z.number(),
combResdch: z.number(),
trbt: z.number(),
blgcOxygDmndQnt: z.number(),
smll: z.number(),
crmty: z.number().nullish(),
tn: z.number(),
tph: z.number(),
ph: z.number(),
clIonQnt: z.number(),
cdtnv: z.number(),
rmrk: z.string(),
useUsgCd: z.string(),
mtchnCmptnYmd: z.string().nullish(),
rvwCmptnYmd: z.string().nullish()
});
const DemandMatchingSchema = z.object({
dmdInfoFk: z.string().nullish(),
splyFcltFk: z.string().nullish(),
splyFcltFlg: z.string().nullish(),
pbnstRuseFcltBizFk: z.number().nullish(),
splyBgngDay: z.coerce.date().nullish(),
splyEndDay: z.coerce.date().nullish(),
splyCpct: z.number().nullish(),
splyFmYn: z.string().nullish(),
useUsgCd: z.string().nullish(),
dmdInfoSn: z.number().nullish(),
splyCndtList:z.array(z.string().nullish() ).nullish()
});
const DemandCoSchema = z.object({
dmdInfoPk: z.string(),
dmdCoNm: z.string(),
ctpvCd: z.string(),
sggCd: z.string(),
daddr: z.string(),
splyBgngDay: z.coerce.date(),
splyEndDay: z.coerce.date(),
splyCpct: z.number(),
splyFmYn: z.string().nullish(),
telno: z.string(),
useUsgCd: z.string().nullish(),
regDt: z.coerce.date().nullish(),
rgtr: z.string().nullish(),
mdfcnDt: z.coerce.date().nullish(),
mdfr: z.string().nullish(),
dmdAplyPswd: z.string(),
demandInfo: z.array(DemandInfoSchema.nullish()).nullish(), // 안쓰는 거임
demandMatchings: z.array(DemandMatchingSchema.nullish()).nullish()// 안쓰는 거임
});
const DemandCstSchema = z.object({
dmdInfoSn: z.number(),
usgPrcsProcs: z.string().nullish(),
cstrnCst: z.number(),
fcltSbsdCstrnCst: z.number(),
prcsFcltCpctCstrnCst: z.number()
});
export const DmdCoReqSchema = z.object({
cityText:z.string().nullish(),
sggText:z.string().nullish(),
dmdInfoSn: z.number(),
dmdInfoFk: z.string(),
dmndTmng: z.coerce.date(),
dmndQty: z.number(),
wntUntprc: z.number().nullish(),
grssClfg: z.number().nullish(),
combResdch: z.number().nullish(),
trbt: z.number().nullish(),
blgcOxygDmndQnt: z.number(),
smll: z.number().nullish(),
crmty: z.number().nullish(),
tn: z.number().nullish(),
tph: z.number().nullish(),
ph: z.number().nullish(),
clIonQnt: z.number().nullish(),
cdtnv: z.number(),
rmrk: z.string().nullish(),
useUsgCd: z.string().nullish(),
mtchnCmptnYmd: z.string().nullish(),
rvwCmptnYmd: z.string().nullish(),
demandCo: DemandCoSchema.nullish(),
demandMatching: DemandMatchingSchema.nullish(),
demandCst: DemandCstSchema,
ruseUtztnFcltNm:z.string().nullish(),
totalConstCost:z.number().nullish(),
});
export type DmdCoReqType = z.infer<typeof DmdCoReqSchema>;
export type DmdMatTableType = {
cityText:string,
sggText:string,
dmdCoNm:string,
daddr:string,
telno:string,
regDt:string,
splyFcltFlg:string
}
export type DedMatUpdateType =
{
dmdInfoSn: number;
usgPrcsProcs: string;
cstrnCst: number;
fcltSbsdCstrnCst: number;
prcsFcltCpctCstrnCst: number;
rgtr: string;
}
export type RvwHistTableType = {
cityText:string,
sggText:string,
dmdCoNm:string,
daddr:string,
telno:string,
regDt:string,
rvwCmptnYmd:string,
mtchnCmptnYmd:string,
ruseUtztnFcltNm:string,
dmndQty:string,
useUsgCd:string,
splyFcltFlg:string
completeYn:boolean
dmdInfoSn :string
}
export type RvwHistTableType = {
cityText:string,
sggText:string,
dmdCoNm:string,
daddr:string,
telno:string,
regDt:string,
rvwCmptnYmd:string,
mtchnCmptnYmd:string,
ruseUtztnFcltNm:string,
dmndQty:string,
useUsgCd:string,
splyFcltFlg:string
completeYn:boolean
dmdInfoSn :string
}
export type conCostFeeType= {
yr: string,
fctCpc: string,
fctCd: string,
stdCost: string
}
export type rateFeeType = {
yr: string,
incExpCd: string,
stdCost: number,
rt: number
}
+17
View File
@@ -0,0 +1,17 @@
import type { customCoSttnBdst } from ".";
export const excelCoSttnParsing = (data: customCoSttnBdst[]): string[][] => {
const excelExportData: string[][] = [];
data.forEach((item) => {
excelExportData.push([
String(item.ctpvCd),
String(item.sggCd),
item.dmdCoNm ?? "",
item.daddr ?? "",
String(item.dmdInfoPk ?? ""),
item.telno ?? ""
]);
});
return excelExportData;
};
@@ -0,0 +1,98 @@
import type { CommonTableProps } from "@/app/store/common/type/header";
import { z } from "zod";
export const sttnHeadListType = z.array(
z.object({
id: z.string(),
title: z.string(),
visible: z.boolean(),
})
);
export const coRegExcel = z.object({
file: z.any()
});
export const coSttHeadListExport: z.infer<typeof sttnHeadListType> = [
{
id: "cityText",
title: "시도",
visible: true,
},
{
id: "sggText",
title: "시군구",
visible: true,
},
{
id: "dmdCoNm",
title: "회사명",
visible: true,
},
{
id: "daddr",
title: "주소",
visible: true,
},
{
id: "dmdInfoPk",
title: "사업자번호",
visible: true,
},
{
id: "telno",
title: "전화번호",
visible: true,
},
];
export const coSttNodeListExport: CommonTableProps[] = [
{
id: "cityText",
title: "시도",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "sggText",
title: "시군구",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "dmdCoNm",
title: "회사명",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "daddr",
title: "주소",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "dmdInfoPk",
title: "사업자번호",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "telno",
title: "전화번호",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
];
+123
View File
@@ -0,0 +1,123 @@
import type { CommonTableProps } from "@/app/store/common/type/header";
import { fetchType, getFetch, getFetchWithCount } from "@/components/lib/api";
import { coSttHeadListExport, coSttNodeListExport } from "./headList";
import { excelCoSttnParsing } from "./excel";
import type { DemandCompType } from "@common/business_components/ui";
// 테이블 헤드 리스트
const coSttNodeList = coSttNodeListExport;
const coSttHeadList = coSttHeadListExport;
const coSttnRes: DemandCompType[] = [];
export type coSttnState = {
coSttn: {
coSttnRes: DemandCompType[];
coSttHeadList: CommonTableProps[];
coSttNodeList: CommonTableProps[];
excelList: [];
isInit: boolean;
coSttnResCount: number;
};
};
type coSttnActions = {
coSttnInit:(pageNo:string, pageCnt:string, con: string) => void;
coSttnSearch: (pageNo:string, pageCnt:string, con: string) => void;
coSttnTxtSearch:(pageNo:string, pageCnt:string, con: string,txt:string) => void;
};
export type coSttnType = coSttnState & coSttnActions;
export const coSttnStateExport: coSttnState = {
coSttn: {
coSttHeadList: coSttHeadList,
coSttNodeList: coSttNodeList,
coSttnRes: coSttnRes,
excelList: [],
isInit: false,
coSttnResCount: 0,
},
};
export const coSttnActionsExport: (set: any) => coSttnActions = (
set: any
) => {
return {
coSttnInit: async (pageNo:string, pageCnt:string, con: string) => {
try {
const coSttnRes = await getFetchWithCount(
fetchType.WR,
`/reuseFc/request/${pageNo}/${pageCnt}/${con}`
);
set((state: coSttnState) => {
return {
...state,
coSttn: {
...state.coSttn,
coSttnRes: coSttnRes.data,
isInit: false,
coSttnResCount: coSttnRes.count,
},
};
});
} catch (e) {
console.log(e)
}
},
coSttnSearch: async (pageNo:string, pageCnt:string, con: string) => {
try {
const coSttnRes = await getFetchWithCount(
fetchType.WR,
`/reuseFc/request/${pageNo}/${pageCnt}/${con}`
);
if (Number(pageCnt) >= 10000) {
const coExcel = excelCoSttnParsing(coSttnRes.data);
set((state: coSttnState) => {
return {
...state,
coSttn: {
...state.coSttn,
excelList: coExcel,
isInit: false,
},
};
});
} else
set((state: coSttnState) => {
return {
...state,
coSttn: {
...state.coSttn,
coSttnRes: coSttnRes.data,
isInit: false,
coSttnResCount : coSttnRes.count,
},
};
});
} catch (erTxt) {
console.log("error", erTxt);
}
},
coSttnTxtSearch: async (pageNo:string, pageCnt:string, con: string, txt: string) => {
try {
const coSttnRes = await getFetch(
fetchType.WR,
`/reuseFc/request/${pageNo}/${pageCnt}/${con}/${txt}`)
set((state: coSttnState) => {
return {
...state,
coSttn: {
...state.coSttn,
coSttnRes: coSttnRes,
isInit: false,
}}})
} catch (erTxt) {
console.log("error", erTxt);
}
}
}
}
@@ -0,0 +1,102 @@
import type { CommonTableProps } from "../../common/type/header";
export const drgtHeadListExport: CommonTableProps[] = [
{
id: "ctpvCd",
title: "시도",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "sggCd",
title: "시군구",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "haengjung",
title: "행정동",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "normal",
title: "정상(횟수)",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "attention",
title: "관심(횟수)",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "caution",
title: "주의(횟수)",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "warning",
title: "관심+주의(횟수)",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "ranking",
title: "가뭄순위",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
];
export const drgtDetailHeadListExport: CommonTableProps[] = [
{
id: "year",
title: "년",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "month",
title: "월",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},{
id: "day",
title: "일",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "state",
title: "가뭄상태",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
]
@@ -0,0 +1,27 @@
import type { CommonTableProps } from "../../common/type/header";
import { drgtHeadListExport } from "./headList";
const drgtHeadList = drgtHeadListExport;
export type drgtState = {
drgt:{
drgtHeadList: CommonTableProps[];
}
}
type drgtActions = {
};
export type drgtType = drgtState & drgtActions;
export const drgtStateExport: drgtState = {
drgt: {
drgtHeadList: drgtHeadList,
}
}
export const drgtActionsExport: (set: any) => drgtActions = (
set: any
) => {
return {};
};
+5 -5
View File
@@ -1,4 +1,4 @@
import type { selectArray } from "../rainReuseFacilityInsert";
import type { SelectDataType } from "@common/business_components/ui";
@@ -23,10 +23,10 @@ const selectSgg = [
export type matDmdState ={ dmd:{
isInit: boolean;
selectSido:selectArray[];
selectSgg:selectArray[];
selectUsg:selectArray[];
selectYN:selectArray[];
selectSido:SelectDataType[];
selectSgg:SelectDataType[];
selectUsg:SelectDataType[];
selectYN:SelectDataType[];
}}
type matDmdActions = {
decrementList: () => void
@@ -0,0 +1,75 @@
import { TEST_UUID } from "../../ruseFcltMng/fcltReg/rainReg";
type nameMap = {
[key: string]: string;
}
export const names: nameMap = {
"시도": "ctpvCd",
"시군구명": "sggCd",
"관리기관": "mngInst",
"회사명": "dmdCoNm",
"공장구분": "fctrySe",
"단지명": "cmpxNm",
"설립구분": "fndnSe",
"입주형태": "mvnShp",
"보유구분": "hldSe",
"최초승인일": "frstAprvYmd",
"최초등록일": "frstRegYmd",
"등록구분": "regSe",
"등록일": "regYmd",
"전화번호": "telno",
"남자종업원": "maleEmpCnt",
"여자종업원": "fmaleEmpCnt",
"외국인남자종업원": "frgnrMaleEmpCnt",
"외국인여자종업원": "frgnrFmaleEmpCnt",
"종업원합계": "totalEmpCnt",
"생산품": "prdctnItem",
"원자재": "splyMtrl",
"공장규모": "fctryScl",
"용도지역": "usgRgn",
"지목": "ldcg",
"용지면적": "usgRgnArea",
"제조시설면적": "mnftrFcltArea",
"부대시설면적": "sbsdFcltArea",
"건축면적": "archArea",
"지식산업센터명": "knwlIndstCntrNm",
"대표업종": "rprsTpbiz",
"업종명": "tpbizNm",
"업종코드": "tpbizCd",
"차수": "cycl",
"법인주소": "corpAddr",
"필지수": "esntlIdx",
"공장주소": "fctryAddr",
"공장주소_지번": "fctryLotnoAddr",
"공장관리번호": "fctryMngNo",
}
export const excelPbnstSttnParsing = (data: any[]): string[][] => {
const excelExportData: string[][] = [];
data.forEach((item) => {
excelExportData.push([
item.rvbsn,
String(item.lgbsn),
item.mdmbsn ?? "",
item.rgnNm ?? "",
String(item.sido ?? ""),
String(item.gugun ?? ""),
String(item.bscFctNm ?? ""),
String(item.efflWqltStndrdNm ?? ""),
String(item.fctCpc ?? ""),
String(item.tel ?? ""),
String(item.ruseUtztnFcltNm ?? ""),
String(item.fcltCpct ?? ""),
String(item.splyExtraCpct ?? ""),
String(item.ruseCpct ?? ""),
String(item.usageTotal ?? ""),
String(item.inUsage ?? ""),
String(item.outUsage ?? ""),
])
})
return excelExportData;
};
@@ -0,0 +1,404 @@
import { z } from "zod";
import type { CommonTableProps } from "../../common/type/header";
import { TEST_UUID } from "../../ruseFcltMng/fcltReg/rainReg";
export const ldrmntZod = z.object({
fctryMngSn: z.string().default(''),
ctpvCd: z.string().default(''),
sggCd: z.string().default(''),
mngInstNm: z.string().default('').nullish(),
dmdCoNm: z.string().default(''),
fctrySe: z.string().default(''),
cmpxNm: z.string().default(''),
fndnSe: z.string().default(''),
mvnShp: z.string().default(''),
hldSe: z.string().default(''),
frstAprvYmd: z.string().default(''),
frstRegYmd: z.string().default(''),
regSe: z.string().default(''),
regYmd: z.string().default(''),
telno: z.string().default(''),
maleEmpCnt: z.number().default(0),
fmaleEmpCnt: z.number().default(0),
frgnrMaleEmpCnt: z.number().default(0),
frgnrFmaleEmpCnt: z.number().default(0),
totalEmpCnt: z.number().default(0),
prdctnItem: z.string().default(''),
splyMtrl: z.string().default(''),
fctryScl: z.string().default(''),
usgRgn: z.string().default(''),
ldcg: z.string().default(''),
usgRgnArea: z.number().default(0),
mnftrFcltArea: z.number().default(0),
sbsdFcltArea: z.number().default(0),
archArea: z.number().default(0),
knwlIndstCntrNm: z.string().default(''),
rprsTpbiz: z.string().default(''),
tpbizNm: z.string().default(''),
tpbizCd: z.string().default(''),
cycl: z.number().default(0),
corpAddr: z.string().default(''),
esntlIdx: z.number().default(0),
fctryAddr: z.string().default(''),
fctryLotnoAddr: z.string().default(''),
fctryMngNo: z.string().default(''),
rgtr:z.string().default(TEST_UUID).nullish()
})
export const ldrmntHeadListExport: CommonTableProps[] = [
{
id: "ctpvCd",
title: "시도",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "sggCd",
title: "시군구",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "dmdCoNm",
title: "회사명",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "fctryAddr",
title: "공장주소",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "fctryMngNo",
title: "공장관리번호",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "telno",
title: "전화번호",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
]
export const ldrmntNodeListExport: CommonTableProps[] = [
{
id: "ctpvCd",
title: "시도",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "sggCd",
title: "시군구",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "mngInstNm",
title: "관리기관",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "dmdCoNm",
title: "회사명",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "fctrySe",
title: "공장구분",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "cmpxNm",
title: "단지명",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "fndnSe",
title: "설립구분",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "mvnShp",
title: "입주형태",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "hldSe",
title: "보유구분",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "frstAprvYmd",
title: "최초승인일",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "frstRegYmd",
title: "최초등록일",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "regSe",
title: "등록구분",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "regYmd",
title: "등록일",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "telno",
title: "전화번호",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "maleEmpCnt",
title: "남자종업원",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "fmaleEmpCnt",
title: "여자종업원",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "frgnrMaleEmpCnt",
title: "외국인남자종업원",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "frgnrFmaleEmpCnt",
title: "외국인여자종업원",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "totalEmpCnt",
title: "종업원합계",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "prdctnItem",
title: "생산품",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "splyMtrl",
title: "원자재",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "fctryScl",
title: "공장규모",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "usgRgn",
title: "용도지역",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "ldcg",
title: "지목",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "usgRgnArea",
title: "용지면적",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "mnftrFcltArea",
title: "제조시설면적",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "sbsdFcltArea",
title: "부대시설면적",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "archArea",
title: "건축면적",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "knwlIndstCntrNm",
title: "지식산업센터명",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "rprsTpbiz",
title: "대표업종",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "tpbizNm",
title: "업종명",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "tpbizCd",
title: "업종코드",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "cycl",
title: "차수",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "corpAddr",
title: "법인주소",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "esntlIdx",
title: "필지수",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "fctryAddr",
title: "공장주소",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "fctryLotnoAddr",
title: "공장주소_지번",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
{
id: "fctryMngNo",
title: "공장관리번호",
visible: true,
row: 1,
rowSpan: 1,
colSpan: 1,
},
];
@@ -0,0 +1,177 @@
import type { CommonTableProps } from "@/app/store/common/type/header";
import { deleteFectch, fetchType, getFetch, postFectch, putFectch } from "@/components/lib/api";
import { ToastFormUi } from "@/components/ui/toast/toastFromUi";
import { z } from "zod";
import { ldrmntHeadListExport, ldrmntNodeListExport, ldrmntZod } from "./headList";
import { TEST_UUID } from "../../ruseFcltMng/fcltReg/rainReg";
// 테이블 헤드 리스트
const ldrmntHeadList = ldrmntHeadListExport;
const ldrmntNodeList = ldrmntNodeListExport;
export type customLdrmnt = z.infer<typeof ldrmntZod>;
const ldrmntRes: customLdrmnt[] = [];
export type ldrmntState = {
ldrmnt: {
ldrmntHeadList: CommonTableProps[];
ldrmntNodeList: CommonTableProps[];
excelList: ExcelType[];
isInit: boolean;
ldrmntRes: customLdrmnt[];
};
};
type ExcelType = {
[key: string]: string | number | undefined;
};
const excelDownList: ExcelType[] = [];
type ldrmntActions = {
ldrmntRegData: (data: any[]) => void,
ldrmntInit: (con: string) => void
ldrmntSearch: (page: number, sggCd: string, coNm: string) => void;
ldrmntUpdate: (ldrmntRes: customLdrmnt) => void;
ldrmntDelete: () => void;
};
export type ldrmntType = ldrmntState & ldrmntActions;
export const ldrmntStateExport: ldrmntState = {
ldrmnt: {
ldrmntHeadList: ldrmntHeadList,
ldrmntNodeList: ldrmntNodeList,
excelList: [],
isInit: false,
ldrmntRes: ldrmntRes,
},
};
export const ldrmntActionsExport: (set: any) => ldrmntActions = (
set: any
) => {
return {
ldrmntInit: async (con: string) => {
try {
const ldrmntRes = await getFetch(
fetchType.WR,
`/reuseFc/request/temp/1/20/${con}`
);
set((state: ldrmntState) => {
return {
...state,
ldrmnt: {
...state.ldrmnt,
ldrmntRes: ldrmntRes,
isInit: false,
},
}
});
} catch (e) {
console.log(e)
}
},
ldrmntRegData: async (data) => {
try {
const response = await postFectch(
"/reuseFc/request/temp",
data,
fetchType.WR
);
console.log('response ', response)
if (response.status === 200) {
ToastFormUi({
body: "잠재수요처 등록이 완료되었습니다. ",
title: "잠재수요처 등록",
});
}
} catch (e) {
console.log(e)
ToastFormUi({
body: "잠재수요처 등록이 실패하였습니다. ",
title: "잠재수요처 등록",
});
}
},
ldrmntSearch: async (page: number, sggCd: string, coNm: string) => {
let searchUrl = "";
if (sggCd !== "") {
if (coNm !== "") {
searchUrl = `/reuseFc/request/temp/${page}/20/${sggCd}/${coNm}`;
} else {
searchUrl = `/reuseFc/request/temp/${page}/20/${sggCd}`;
}
}
try {
const ldrmntRes = await getFetch(
fetchType.WR,
searchUrl
);
ldrmntRes.forEach((item: customLdrmnt) => {
excelDownList.push({
ctpvCd: item.ctpvCd,
sggCd: item.sggCd,
dmdCoNm: item.dmdCoNm,
fctryAddr: item.fctryAddr,
fctryMngNo: item.fctryMngNo,
telno: item.telno,
})
})
set((state: ldrmntState) => {
return {
...state,
ldrmnt: {
...state.ldrmnt,
ldrmntRes: ldrmntRes,
excelList: excelDownList,
},
}
})
} catch (e) {
console.log(e)
}
},
ldrmntUpdate: async (ldrmntRes: customLdrmnt) => {
try {
ldrmntRes.rgtr = TEST_UUID;
const response = await putFectch(
`/reuseFc/request/temp`,
ldrmntRes
);
return set((state: ldrmntState) => ({
...state,
ldrmnt: {
...state.ldrmnt,
ldrmntRes: ldrmntRes,
},
}));
} catch (error) {
console.error("Error ldrmntUpdate:", error);
}
},
ldrmntDelete: async () => {
try {
const response = await deleteFectch(
`/reuseFc/request/temp`,
);
} catch (error) {
console.error("Error ldrmntDelete:", error);
}
},
}
}
@@ -0,0 +1,355 @@
import type { SelectDataType } from "@common/business_components/ui";
import type { TableUpperProps } from "../../common/type/header";
//★☆★☆ 여기서부터 수정하기 ★☆★☆
export const ruseCaseHeadListExport: TableUpperProps[] = [
{
id: "a",
title: "사업명",
visible: true,
row: 0,
rowSpan: 2,
},
{
id: "b",
title: "사업기간",
visible: true,
row: 0,
rowSpan: 2,
},
{
id: "c",
title: "공급처",
visible: true,
row: 0,
colSpan: 3,
},
{
id: "d",
title: "시설종류",
visible: true,
row: 1,
},
{
id: "e",
title: "공급처명",
visible: true,
row: 1,
},
{
id: "f",
title: "시설용량(m³/일)",
visible: true,
row: 1,
},
{
id: "g",
title: "수요처",
visible: true,
row: 0,
colSpan: 2,
},
{
id: "h",
title: "수요처명",
visible: true,
row: 1,
},
{
id: "i",
title: "주소",
visible: true,
row: 1,
},
{
id: "q",
title: "재이용시설",
visible: true,
row: 0,
colSpan: 5,
},
{
id: "q2",
title: "시설용량(m³/일)",
visible: true,
row: 1,
},
{
id: "q3",
title: "관로(km)",
visible: true,
row: 1,
},
{
id: "q4",
title: "용도",
visible: true,
row: 1,
},
{
id: "q5",
title: "공급량(m³/일)",
visible: true,
row: 1,
},
{
id: "q6",
title: "처리공법",
visible: true,
row: 1,
},
{
id: "k",
title: "보증수질",
visible: true,
row: 0,
colSpan: 13,
},
{
id: "k1",
title: "용도별",
visible: true,
row: 1,
},
{
id: "k2",
title: "총대장균군수​(개/100ml)",
visible: true,
row: 1,
},
{
id: "k3",
title: "결합잔류염소(mg/L)",
visible: true,
row: 1,
},
{
id: "k4",
title: "탁도(NTU)",
visible: true,
row: 1,
},
{
id: "k5",
title: "생물학적​산소요구량(BOD)(mg/L)​",
visible: true,
row: 1,
},
{
id: "k6",
title: "냄새​",
visible: true,
row: 1,
},
{
id: "k7",
title: "색도​",
visible: true,
row: 1,
},
{
id: "k8",
title: "총질소(T-N)(mg/L)​",
visible: true,
row: 1,
},
{
id: "k9",
title: "총인(T-P)(mg/L)",
visible: true,
row: 1,
},
{
id: "k10",
title: "수소이온농도(PH)​",
visible: true,
row: 1,
},
{
id: "k11",
title: "수소이온농도(PH)​",
visible: true,
row: 1,
},
{
id: "k12",
title: "전기전도도​(㎲/cm",
visible: true,
row: 1,
},
{
id: "k13",
title: "비고​",
visible: true,
row: 1,
},
{
id: "h",
title: "소요사업비(백만원)",
visible: true,
row: 0,
colSpan: 14,
},
{
id: "h1",
title: "총",
visible: true,
row: 1,
},
{
id: "h2",
title: "토목재이용시설",
visible: true,
row: 1,
},
{
id: "h3",
title: "토목관로",
visible: true,
row: 1,
},
{
id: "h4",
title: "건축",
visible: true,
row: 1,
},
{
id: "h5",
title: "기계",
visible: true,
row: 1,
},
{
id: "h6",
title: "전기・계측",
visible: true,
row: 1,
},
{
id: "h7",
title: "GIS・DB",
visible: true,
row: 1,
},
{
id: "h8",
title: "CCTV",
visible: true,
row: 1,
},
{
id: "h9",
title: "시공및준공",
visible: true,
row: 1,
},
{
id: "h10",
title: "페기물",
visible: true,
row: 1,
},
{
id: "h11",
title: "설계비",
visible: true,
row: 1,
},
{
id: "h12",
title: "감리비",
visible: true,
row: 1,
},
{
id: "h13",
title: "시설부대비",
visible: true,
row: 1,
},
{
id: "h14",
title: "기타",
visible: true,
row: 1,
},
{
id: "i",
title: "자원조달계획(백만원)",
visible: true,
row: 0,
colSpan: 4,
},
{
id: "i1",
title: "총",
visible: true,
row: 1,
},
{
id: "i2",
title: "국비",
visible: true,
row: 1,
},
{
id: "i3",
title: "지방비",
visible: true,
row: 1,
},
{
id: "i4",
title: "원인자부담",
visible: true,
row: 1,
},
{
id: "j",
title: "사업비정산(백만원)",
visible: true,
row: 0,
colSpan: 5,
},
{
id: "j1",
title: "총",
visible: true,
row: 1,
},
{
id: "j2",
title: "국비",
visible: true,
row: 1,
},
{
id: "j3",
title: "지방비",
visible: true,
row: 1,
},
{
id: "j4",
title: "원인자부담",
visible: true,
row: 1,
},
{
id: "j5",
title: "국고비율",
visible: true,
row: 1,
},
];
export const ruseUtzType: SelectDataType[] = [
{ text: "조경용수", val: "조경용수" },
{ text: "청소화장실용수", val: "청소화장실용수" },
{ text: "세척살수용수", val: "세척살수용수" },
{ text: "농업용수", val: "농업용수" },
{ text: "공업용수", val: "공업용수" },
{ text: "친수용수", val: "친수용수" },
{ text: "기타", val: "기타" },
];
@@ -0,0 +1,24 @@
import type { TableUpperProps } from "../../common/type/header";
import { ruseCaseHeadListExport } from "./headList";
export type ruseCaseState = {
ruseCase: {
ruseHeadList:TableUpperProps[];
};
};
type ruseCaseActions = {
};
export type ruseCaseType = ruseCaseState & ruseCaseActions;
export const ruseCaseStateExport: ruseCaseState = {
ruseCase: {
ruseHeadList:ruseCaseHeadListExport,
},
};
export const ruseCaseActionsExport: (set: any) => ruseCaseActions = (
set: any
) => {
return {
};
};
@@ -0,0 +1,71 @@
import type { TableUpperProps } from "../../common/type/header";
export const ruseHstryHeadListExport:TableUpperProps[]= [
{
id: "cityText",
title: "시도",
visible: true,
},
{
id: "sggText",
title: "시군구",
visible: true,
},
{
id: "dmdCoNm",
title: "회사명",
visible: true,
},
{
id: "daddr",
title: "공장주소",
visible: true,
},
{
id: "telno",
title: "전화번호",
visible: true,
},
{
id: "regDt", //바꾸기
title: "신청일자",
visible: true,
},
{
id: "rvwCmptnYmd", //바꾸기
title: "검토일자",
visible: true,
},
{
id: "mtchnCmptnYmd", //바꾸기
title: "매칭 완료일자",
visible: true,
},
{
id: "ruseUtztnFcltNm", //바꾸기
title: "공급처",
visible: true,
},
{
id: "dmndQty", //바꾸기
title: "요구수량(M3/d)",
visible: true,
},
{
id: "useUsgCd", //바꾸기
title: "사용용도",
visible: true,
},
{
id: "splyFcltFlg", //바꾸기
title: "진행상태",
visible: true,
},
{
id: "completeYn", //바꾸기
title: "매칭완료 여부",
visible: true,
},
];
@@ -0,0 +1,237 @@
import type { z } from "zod";
import type { sttnHeadListType } from "../coSttn/headList";
import type {
CommonTableProps,
TableUpperProps,
} from "../../common/type/header";
import { ruseHstryHeadListExport } from "./headList";
import { fetchType, getFetch, postFectch, putFectch } from "@/components/lib/api";
import type { DmdCoReqType } from "../coMatRvw/type";
import toast from "react-hot-toast";
import { TEST_UUID } from "../../ruseFcltMng/fcltReg/rainReg";
const ruseHistHeadList = ruseHstryHeadListExport;
export type ruseHstryState = {
ruseHist: {
isInit: boolean;
rvwHistRes: DmdCoReqType[];
ruseHistHeadList: TableUpperProps[];
};
};
export const ruseHstryStateExport: ruseHstryState = {
ruseHist: {
isInit: false,
rvwHistRes: [],
ruseHistHeadList: ruseHistHeadList,
},
};
export type ruseHstryType = ruseHstryState & ruseHstryActions;
//
export const addRgtrAndMdfrToDemandObj = (data: DmdCoReqType) => {
// 최상위 demand 객체
// demandCo가 있을 경우
if (data.demandCo) {
data.demandCo.rgtr = TEST_UUID;
data.demandCo.mdfr = TEST_UUID;
}
return data;
};
type ruseHstryActions = {
ruseRvwHistInit: (
pageNo: number,
pageCnt: number,
startYear: string,
endYear: string,
sggCd?: string
) => void;
ruseRvwCalUpdate: (data: DmdCoReqType) => void;
ruseRvwSearch: (
pageNo: number,
pageCnt: number,
startYear: string,
endYear: string,
sggCd: string,
dmdCoNm: string,
ruseUtztnFcltNm: string
) => void;
ruseRvwInqua: (
pageNo: number,
pageCnt: number,
startYear: string,
endYear: string,
sggCd: string
) => void;
ruseRvwComplete:( data: Number[]) => void;
};
const irvwHistInit = async (
pageNo: number,
pageCnt: number,
startYear: string,
endYear: string,
) => {
let url = `/reuseFc/request/infoList/matched/${pageNo}/${pageCnt}/${startYear}/${endYear}`;
// console.log("sggCd ", sggCd);
// if (sggCd) {
// url += `/${sggCd}`;
// }
const rvwHistRes = await getFetch(fetchType.WR, url);
return rvwHistRes;
};
export const ruseHstryActionsExport: (set: any) => ruseHstryActions = (
set: any
) => {
return {
ruseRvwHistInit: async (
pageNo: number,
pageCnt: number,
startYear: string,
endYear: string,
sggCd?: string
) => {
const rvwHistRes = await irvwHistInit(
pageNo,
pageCnt,
startYear,
endYear,
// sggCd
);
return set((state: ruseHstryState) => ({
...state,
ruseHist: {
...state.ruseHist,
init: false,
rvwHistRes: rvwHistRes,
},
}));
},
ruseRvwCalUpdate: async (data: DmdCoReqType) => {
try {
const updatedData = addRgtrAndMdfrToDemandObj(data);
const update = await putFectch(
`/reuseFc/request/cst`,
updatedData
);
if (update.status === 200) {
toast.success("매칭 계산 저장이 완료입니다.");
const rvwHistRes = await irvwHistInit(
1,
10,
new Date().getFullYear().toString(),
new Date().getFullYear().toString(),
);
return set((state: ruseHstryState) => ({
...state,
ruseHist: {
...state.ruseHist,
init: false,
rvwHistRes: rvwHistRes,
},
}));
}
} catch (e) {
toast.error("매칭 계산 저장이 오류입니다.");
console.log(e);
}
},
ruseRvwSearch: async (
pageNo: number,
pageCnt: number,
startYear: string,
endYear: string,
sggCd: string,
dmdCoNm: string,
ruseUtztnFcltNm: string
) => {
let url = `/reuseFc/request/infoList/matched/${pageNo}/${pageCnt}/${startYear}/${endYear}`;
if (sggCd.length > 0) {
url += `/${sggCd}`;
} else {
url += `/0`;
}
if (dmdCoNm?.length > 0) {
url += `/${dmdCoNm}`;
} else {
url += `/0`;
}
if (ruseUtztnFcltNm?.length > 0) {
url += `/${ruseUtztnFcltNm}`;
} else {
url += `/0`;
}
const rvwHistRes = await getFetch(fetchType.WR, url);
return set((state: ruseHstryState) => ({
...state,
ruseHist: {
...state.ruseHist,
rvwHistRes: rvwHistRes,
},
}));
},
ruseRvwInqua: async (
pageNo: number,
pageCnt: number,
startYear: string,
endYear: string,
sggCd: string
) => {
try {
let url = `/reuseFc/request/infoList/matched/${pageNo}/${pageCnt}/${startYear}/${endYear}`;
if (sggCd.length > 0) {
url += `/${sggCd}/0`;
}
const rvwHistRes = await getFetch(fetchType.WR, url);
return set((state: ruseHstryState) => ({
...state,
ruseHist: {
...state.ruseHist,
rvwHistRes: rvwHistRes,
},
}));
} catch (e) {
console.log(" error ", e);
}
},
ruseRvwComplete: async (data: Number[]) => {
try {
const complet = await postFectch(
`/reuseFc/request/completeCheck`,
data,
fetchType.WR
);
if (complet.status === 200) {
toast.success("완료 처리가 완료되었습니다.");
const rvwHistRes = await irvwHistInit(
1,
10,
new Date().getFullYear().toString(),
new Date().getFullYear().toString(),
);
}
} catch (e) {
console.log(" error ", e);
toast.error("완료 처리 중 오류가 발생했습니다.");
}
},
};
};
@@ -0,0 +1,137 @@
import type { SelectDataType } from "@common/business_components";
import type { rainChkZodType } from ".";
import { TEST_UUID } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import { buildingType } from "../../../common/code/index";
export const useTypes = [
"조경용수",
"청소화장실용수",
"세척살수용수",
"농업용수",
"공업용수",
"친수용수",
"기타",
];
export type Buildingtype = {
bdstInfoPk: number;
ctpvCd: 1;
sggCd: 1001;
daddr: "string3";
bdstNm: "string";
frstArchPrmsnDt: "2025-03-25";
archArea: 0;
regDt: "2025-04-16";
rgtr: null;
mdfcnDt: "2025-04-16";
mdfr: null;
};
export const buildingToExcelType = (
buildings: Buildingtype[],
sidoCode: SelectDataType[],
sggCdoe: SelectDataType[],
) => {
const excelData: string[][] = [];
buildings.forEach((building) => {
useTypes.forEach((useType) => {
excelData.push([
building.bdstInfoPk.toString(),
sidoCode.find((sido) => sido.val === building.ctpvCd.toString())
?.text || "",
sggCdoe.find((sido) => sido.val === building.sggCd.toString())
?.text || "",
building.daddr,
building.bdstNm,
"",
"",
"",
"",
useType,
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
]);
});
});
return excelData;
};
export const excelToRainChkData = (excelData: any, year: string) => {
const rainChkgdData: rainChkZodType[] = excelData.map((item: any) => {
if (item["점검일"] !== undefined) {
const checkYmd = item["점검일"].replace(/\./g, "")
let vltnDt = item["과태료 부과일(위반일)"]
if (vltnDt !== undefined) {
vltnDt = vltnDt ? vltnDt.replace(/\./g, "") : "";
}
const makeGuidDetail = Array.from({ length: 12 }, (_, i) => {
let month = `${i + 1}`;
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),
flg: "RNB",
};
});
return {
bdstRuseFcltFk: Number(item["NO"]),
chckYmd: checkYmd,
spwtPositn: item["유량측정방법"] ?? "",
rgtr: TEST_UUID,
oilqMeasMthd: item["운영관리형태"] ?? "",
anlOperCst: Number(item["연간운영비(원/년)"]) ?? 0,
operMngCd: item["유량측정방법"] ?? "",
guideDetails: makeGuidDetail,
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),
rgtr: TEST_UUID,
},
],
};
}
}).filter((el: any) => el !== undefined);
return rainChkgdData;
};
@@ -0,0 +1,223 @@
import type { TableUpperProps } from "@/app/store/common/type/header";
import { z } from "zod";
export const chkgdRegExcel = z.object({
bdstInfoPk: z.number().default(111111111),
chckYr: z
.string()
.default("")
.refine((year) => year.length === 0 || /^\d{4}$/.test(year), {
message: "4자리 연도만 입력하세요",
})
.refine(
(year) => {
if (year.length === 0) return true; // 빈 문자열은 통과
const numYear = Number(year);
return !isNaN(numYear) && numYear <= new Date().getFullYear();
},
{ message: "현재 년도보다 높은 수를 입력할 수 없습니다." }
),
file: z.instanceof(File).optional(),
});
export 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(),
chckYmd: z.string(),
cityText:z.string().nullish(),
sggText:z.string().nullish(),
prcsCpct: z.number().nullable(),
spwtPositn: z.string().nullable(),
regDt: z.string().nullable(),
rgtr: z.string().nullable(),
mdfcnDt: z.string().nullable(),
mdfr: z.string().nullable(),
flg: z.string().nullable(),
guideDetails: z.array(guideDetail),
building: z
.object({
bdstInfoPk: z.number(),
ctpvCd: z.number(),
sggCd: z.number(),
daddr: z.string().nullable(),
bdstNm: z.string(),
frstArchPrmsnDt: z.string().nullable(),
archArea: z.number(),
regDt: z.string().nullable(),
rgtr: z.string().nullable(),
mdfcnDt: z.string().nullable(),
mdfr: z.string().nullable(),
})
.nullable(),
rainyDetails: z.array(
z.object({
chkgdnFk: z.number().nullable(),
utztnUsgCd: z.string(),
ph: z.number().nullable(),
trbt: z.number().nullable(),
grssClfg: z.number().nullable(),
etc: z.string().nullable(),
vltnDt: z.string().nullable(),
vltnMttr: z.string().nullable(),
levyAmt: z.number().nullable(),
regDt: z.string().nullable(),
rgtr: z.string().nullable(),
mdfcnDt: z.string().nullable(),
mdfr: z.string().nullable(),
})
),
});
export type chHeadType = {
headNm: string;
text: string;
length: number;
rows?: number;
};
export type splRuseWaterType = {
utztnUsgCd: string;
splTotal: number;
spl01: number;
spl02: number;
spl03: number;
spl04: number;
spl05: number;
spl06: number;
spl07: number;
spl08: number;
spl09: number;
spl10: number;
spl11: number;
spl12: number;
ruseTotal: number;
ruse01: number;
ruse02: number;
ruse03: number;
ruse04: number;
ruse05: number;
ruse06: number;
ruse07: number;
ruse08: number;
ruse09: number;
ruse10: number;
ruse11: number;
ruse12: number;
};
export const rainHeadNmExport: chHeadType[] = [
{ headNm: "useQuilty", text: "이용수질(필요시)", length: 3 },
{ headNm: "feeHist", text: "과태료 부과내역", length: 3 },
{ headNm: "ruseWater", text: "연간보급수 이용량(m³)", length: 13 },
{ headNm: "detailQulity", text: "분기", length: 11 },
{ headNm: "splWater", text: "연간빗물 이용량(m³)", length: 13 },
];
export const rainChkgdnHeadListExport: TableUpperProps[] = [
{ id: "order", title: "순번", mergeCell: true },
{ id: "checkBox", title: "선택", mergeCell: true },
{ id: "cityText", title: "시도", mergeCell: true },
{ id: "sggText", title: "시군구", mergeCell: true },
{ id: "bdstNm", title: "시설명", mergeCell: true },
{ id: "operMngCd", title: "운영관리형태", mergeCell: true },
{ id: "oilqMeasMthd", title: "유량측정방법", mergeCell: true },
{ id: "anlOperCst", title: "연간운영비(원/년)", mergeCell: true },
{ id: "dtfcltCpct", title: "빗물저류조용량(m³)", mergeCell: true },
{ id: "chckYmd", title: "점검일", mergeCell: true },
{ id: "utztnUsgCd", title: "이용용도" },
{ id: "totalSplyUswtrUtztnQnt", title: "연간보급수이용량(m³)" },
{ id: "totalRuseFcltUtztnQnt", title: "연간빗물이용량(m³)" },
{
id: "ph",
title: "PH",
upName: "useQuilty",
upSequnce: 1,
type: "number",
edit: true,
},
{
id: "trbt",
title: "탁도",
upName: "useQuilty",
upSequnce: 2,
type: "number",
edit: true,
},
{
id: "grssClfg",
title: "총대장균군수",
upName: "useQuilty",
upSequnce: 3,
type: "number",
edit: true,
},
{
id: "vltnDt",
title: "부과일(위반일)",
upName: "feeHist",
upSequnce: 1,
type: "text",
edit: true,
},
{
id: "vltnMttr",
title: "위반사항",
upName: "feeHist",
upSequnce: 2,
type: "text",
edit: true,
},
{
id: "levyAmt",
title: "부과금액(천원)",
upName: "feeHist",
upSequnce: 3,
type: "number",
edit: true,
},
];
export const ruseHeadListExport: TableUpperProps[] = [
{ id: "utztnUsgCd", title: "이용용도" },
{ id: "ruseTotal", title: "계", upName: "ruseWater", upSequnce: 1 },
{ id: "ruse01", title: "1월", upName: "ruseWater", upSequnce: 2 , edit: true },
{ id: "ruse02", title: "2월", upName: "ruseWater", upSequnce: 3 , edit: true },
{ id: "ruse03", title: "3월", upName: "ruseWater", upSequnce: 4 , edit: true },
{ id: "ruse04", title: "4월", upName: "ruseWater", upSequnce: 5 , edit: true },
{ id: "ruse05", title: "5월", upName: "ruseWater", upSequnce: 6 , edit: true },
{ id: "ruse06", title: "6월", upName: "ruseWater", upSequnce: 7 , edit: true },
{ id: "ruse07", title: "7월", upName: "ruseWater", upSequnce: 8 , edit: true },
{ id: "ruse08", title: "8월", upName: "ruseWater", upSequnce: 9 , edit: true },
{ id: "ruse09", title: "9월", upName: "ruseWater", upSequnce: 10, edit: true },
{ id: "ruse10", title: "10월", upName: "ruseWater", upSequnce: 11 , edit: true },
{ id: "ruse11", title: "11월", upName: "ruseWater", upSequnce: 12 , edit: true },
{ id: "ruse12", title: "12월", upName: "ruseWater", upSequnce: 13 , edit: true },
];
export const splHeadListExport: TableUpperProps[] = [
{ id: "utztnUsgCd", title: "이용용도" },
{ id: "splTotal", title: "계", upName: "splWater", upSequnce: 1},
{ id: "spl01", title: "1월", upName: "splWater", upSequnce: 2, edit: true },
{ id: "spl02", title: "2월", upName: "splWater", upSequnce: 3, edit: true },
{ id: "spl03", title: "3월", upName: "splWater", upSequnce: 4, edit: true },
{ id: "spl04", title: "4월", upName: "splWater", upSequnce: 5, edit: true },
{ id: "spl05", title: "5월", upName: "splWater", upSequnce: 6, edit: true },
{ id: "spl06", title: "6월", upName: "splWater", upSequnce: 7, edit: true },
{ id: "spl07", title: "7월", upName: "splWater", upSequnce: 8, edit: true },
{ id: "spl08", title: "8월", upName: "splWater", upSequnce: 9, edit: true },
{ id: "spl09", title: "9월", upName: "splWater", upSequnce: 10, edit: true },
{ id: "spl10", title: "10월", upName: "splWater", upSequnce: 11, edit: true },
{ id: "spl11", title: "11월", upName: "splWater", upSequnce: 12, edit: true },
{ id: "spl12", title: "12월", upName: "splWater", upSequnce: 13, edit: true },
];
@@ -0,0 +1,271 @@
import { buildingType } from "@/app/store/common/code";
import {
TEST_UUID,
} from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import {
deleteFectch,
fetchType,
getFetch,
postFectch,
putFectch,
} from "@/components/lib/api";
import { ToastFormUi } from "@/components/ui/toast/toastFromUi";
import type { SelectDataType } from "@common/business_components/ui";
import { z } from "zod";
import { buildingToExcelType } from "./excel";
import {
rainChkgdnHeadListExport,
rainChkZod,
rainHeadNmExport,
ruseHeadListExport,
splHeadListExport,
type chHeadType,
} from "./headList";
import type { TableUpperProps } from "@/app/store/common/type/header";
export type rainChkZodType = z.infer<typeof rainChkZod>;
const fcltDiv = [
{ val: "RST", text: "중수도시설" },
{ val: "RNB", text: "빗물이용시설" },
];
const rainHeadNm = rainHeadNmExport;
const rainChkgdnHeadList = rainChkgdnHeadListExport;
const ruseHeadList = ruseHeadListExport;
const splHeadList = splHeadListExport;
const rainChk: rainChkZodType[] = [];
export type rainChkgdnState = {
rainChkgdn: {
rainChkgdnHeadList: TableUpperProps[];
rainChk: rainChkZodType[];
rainHeadNm: chHeadType[];
ruseHeadList: TableUpperProps[];
splHeadList: TableUpperProps[];
isInit: boolean;
isModalClose: boolean;
fcltDiv: SelectDataType[];
excelList: [];
isSttn: boolean;
};
};
type rainChkgdnActions = {
rainChkInit: (sggCd: string, searchTxt: string) => void;
rainChkDetilUpdate(rainChk: rainChkZodType[]): Promise<void>;
rainChkGuidUpdate(rainChk: rainChkZodType): Promise<void>;
rainChkExcelDownload(
sidoCode: SelectDataType[],
sggCode: SelectDataType[]
): Promise<void>;
rainChkExcelDataUPload(excelData: rainChkZodType[]): Promise<void>;
rainChkDelete(chkgdnPks: number[]): Promise<void>;
rainChkHeadChange: (rainChkgdn: rainChkgdnState, isEdit :boolean) => void;
};
export type rainChkgdnType = rainChkgdnState & rainChkgdnActions;
export const rainChkgdnStateExport: rainChkgdnState = {
rainChkgdn: {
rainChkgdnHeadList: rainChkgdnHeadList,
rainHeadNm: rainHeadNm,
rainChk: rainChk,
splHeadList: splHeadList,
ruseHeadList: ruseHeadList,
isInit: false,
isModalClose: false,
excelList: [],
fcltDiv: fcltDiv,
isSttn: false,
},
};
const makeMdfrChk = (data: rainChkZodType[], type: string, toDo: string) => {
const chData = data.map((item) => {
item.mdfr = TEST_UUID;
item.rgtr = TEST_UUID;
if (type === "rainyDetails") {
item.rainyDetails.forEach((item) => {
item.mdfr = TEST_UUID;
item.rgtr = TEST_UUID;
});
} else {
}
return item;
});
return chData;
};
const initFetch = async (txt: string | undefined, sgg: string | undefined) => {
const rainRes = await getFetch(
"wr",
`/reuseChk/rainy` + (txt ? `/${txt}` : "2024") + (sgg ? `/${sgg}` : "/0")
);
return rainRes;
};
export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = (
set: any
) => {
return {
rainChkExcelDownload: async (
sidoCode: SelectDataType[],
sggCode: SelectDataType[]
) => {
// 로그인한 아이디의 시도 or 시군구로 들어가야하는데 현재는 그냥 0으로 하드코딩
const data = await getFetch(
fetchType.WR,
`/reuseFc/buildingFlg/${buildingType.RNB}/41`
);
const excelList = buildingToExcelType(data, sidoCode, sggCode);
set((state: rainChkgdnState) => ({
rainChkgdn: {
...state.rainChkgdn,
excelList: excelList,
},
}));
},
rainChkExcelDataUPload: async (excelData: rainChkZodType[]) => {
try {
const res = await postFectch("/reuseChk/rainy", excelData);
if (res.ok) {
ToastFormUi({
body: "지도점검 등록이 완료되었습니다. ",
title: "지도점검 등록",
});
}
const rainChkRes = await initFetch("2024", "0");
return set((state: rainChkgdnState) => ({
...state,
rainChkgdn: {
...state.rainChkgdn,
rainChk: rainChkRes,
},
}));
} catch (error) {
console.log(error);
ToastFormUi({
body: "지도점검 등록이 실패되었습니다.",
title: "지도점검 등록",
});
}
},
rainChkInit: async (searchTxt: string, sggCd: string) => {
try {
const rainChkRes = await initFetch(searchTxt, sggCd);
return set((state: rainChkgdnState) => ({
...state,
rainChkgdn: {
...state.rainChkgdn,
rainChk: rainChkRes,
},
}));
} catch (error) {
console.log(error);
}
},
rainChkDetilUpdate: async (rainChk: rainChkZodType[]) => {
try {
const chData = await makeMdfrChk(rainChk, "rain", "rainDetil");
const res = await postFectch("/reuseChk/rainy", chData);
if (res.ok) {
ToastFormUi({
body: "지도점검 보급수 및 밋물이용량 수정이 완료되었습니다. ",
title: "지도점검 수정",
});
}
const rainChkRes = await initFetch("2024", "0");
return set((state: rainChkgdnState) => ({
...state,
rainChkgdn: {
...state.rainChkgdn,
rainChk: rainChkRes,
},
}));
} catch (error) {
console.log(error);
alert("수정에 실패하였습니다.");
}
},
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: "지도점검 수정",
});
}
const rainChkRes = await initFetch("2024", "0");
return set((state: rainChkgdnState) => ({
...state,
rainChkgdn: {
...state.rainChkgdn,
rainChk: rainChkRes,
},
}));
} catch (error) {
console.log(error);
}
},
rainChkDelete: async (chkgdnPks: number[]) => {
try {
const res = await deleteFectch(`/reuseChk/rainy`, chkgdnPks);
if (res) {
ToastFormUi({
body: "삭제가 완료되었습니다. ",
title: "지도점검 삭제",
});
}
const rainChkRes = await initFetch("2024", "0");
return set((state: rainChkgdnState) => ({
...state,
rainChkgdn: {
...state.rainChkgdn,
rainChk: rainChkRes,
},
}));
} catch (error) {
ToastFormUi({ body: "삭제를 실패했습니다.. ", title: "지도점검 삭제" });
}
},
rainChkHeadChange: async (rainChkgdn: rainChkgdnState , isEdit :boolean) => {
try {
const rainChkgdnHeadList = rainChkgdn.rainChkgdn.rainChkgdnHeadList;
const splHeadList = rainChkgdn.rainChkgdn.splHeadList;
const ruseHeadList = rainChkgdn.rainChkgdn.ruseHeadList;
rainChkgdnHeadList.forEach(( head) => {
if(head.edit!== undefined)
head.edit=isEdit;
});
splHeadList.forEach((head) => {
if(head.edit!== undefined)
head.edit=isEdit;
});
ruseHeadList.forEach((head) => {
if(head.edit!== undefined)
head.edit=isEdit;
});
return set((state: rainChkgdnState) => ({
...state,
rainChkgdn: {
...state.rainChkgdn,
rainChkgdnHeadList: rainChkgdnHeadList,
splHeadList:splHeadList,
ruseHeadList:ruseHeadList
},
}));
} catch (error) {
console.log(error);
}
},
};
};
@@ -0,0 +1,237 @@
import type { SelectDataType } from "@common/business_components/ui";
import { useTypes, type Buildingtype } from "../rainChkgdn/excel";
import { TEST_UUID } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import type { rswtChkZodType } from ".";
export const rswtMakeExcelSample = (
buildings: Buildingtype[],
sidoCode: SelectDataType[],
sggCdoe: SelectDataType[]
) => {
const excelSite = {
guideDetail: [] as string[][],
polutions: [] as string[][],
};
//첫번째 시트 데이터 이용량 현황 양식만들기
buildings.forEach((building) => {
useTypes.forEach((useType) => {
excelSite.guideDetail.push([
building.bdstInfoPk.toString(),
sidoCode.find((sido) => sido.val === building.ctpvCd.toString())
?.text || "",
sggCdoe.find((sido) => sido.val === building.sggCd.toString())?.text ||
"",
building.bdstNm,
building.daddr,
"",
"",
"",
"",
"",
"",
useType,
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
]);
});
});
//두번째 시트 양식 만들기 오염도
buildings.forEach((building) => {
useTypes.forEach((useType) => {
excelSite.polutions.push([
building.bdstInfoPk.toString(),
sidoCode.find((sido) => sido.val === building.ctpvCd.toString())
?.text || "",
sggCdoe.find((sido) => sido.val === building.sggCd.toString())?.text ||
"",
building.bdstNm,
building.daddr,
"",
"",
"",
"",
"",
useType,
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
]);
});
});
return excelSite;
};
export const excelToRswtGuideData = (excelData: any, year: string) => {
const rainChkgdData: rswtChkZodType[] = excelData
.map((item: any) => {
if (item["점검일"] !== undefined) {
const checkYmd = item["점검일"].replace(/\./g, "")
const makeGuidDetail = Array.from({ length: 12 }, (_, i) => {
let month = `${i + 1}`;
const splyData = item[`대체수_${month}월`];
const rswtData = item[`중수_${month}월`];
if (month.length < 2) month = "0" + month;
return {
ym: year + month,
chckYmd: checkYmd,
splyUswtrUtztnQnt: splyData !== "" ? splyData : 0,
ruseFcltUtztnQnt: rswtData !== "" ? rswtData : 0,
};
});
return {
bdstRuseFcltFk: Number(item["NO"]),
operMngCd: item["운영관리형태"],
anlOperCst: Number(item["연간운영비(원/년)"]) ?? 0,
prcsCpct: item["처리용량(m³)"],
spwtPositn: item["채수지점"],
chckYmd:checkYmd,
utztnUsgCd: item["이용용도"],
guideDetails: makeGuidDetail,
rgtr: TEST_UUID,
mdfr: TEST_UUID,
};
}
})
.filter((el: any) => el !== undefined);
return rainChkgdData;
};
export const excelToRswtPolution = (excelData: any, year: string) => {
const rainChkgdData: rswtChkZodType[] = excelData
.map((item: any) => {
if (item["점검일"] !== undefined) {
const checkYmd = item["점검일"].replace(/\./g, "")
let vltnDt = item["과태료 부과일(위반일)"]
if (vltnDt !== undefined) {
vltnDt = vltnDt .replace(/\./g, "")
}
const makePoluttion = Array.from({ length: 4 }, (_, i) => {
let quarter = `${i+1}`;
const grssClfgUswtr = item[`${quarter}분기_총대장균군수`];
const combResdch = item[`${quarter}분기_결합잔류염소`];
const trbt = item[`${quarter}분기_탁도`];
const bod = item[`${quarter}분기_BOD`];
const smll = item[`${quarter}분기_냄새`];
const crmty = item[`${quarter}분기_색도`];
const tph = item[`${quarter}분기_T-P`];
const tn = item[`${quarter}분기_T-N`];
const ph = item[`${quarter}분기_PH`];
const clIonQnt = item[`${quarter}분기_염화물`];
return {
node: quarter,
chckYmd: checkYmd,
grssClfgUswtr: grssClfgUswtr !== "" ? grssClfgUswtr : 0,
combResdch: combResdch !== "" ? combResdch : 0,
trbt: trbt !== "" ? trbt : 0,
bod: bod !== "" ? bod : 0,
smll: smll !== "" ? smll : 0,
crmty: crmty !== "" ? crmty : 0,
tph: tph !== "" ? tph : 0,
tn: tn !== "" ? tn : 0,
ph: ph !== "" ? ph : 0,
clIonQnt: clIonQnt !== "" ? clIonQnt : 0,
rgtr: TEST_UUID,
mdfr: TEST_UUID,
};
});
return {
bdstRuseFcltFk: Number(item["NO"]),
chckYmd: checkYmd,
utztnUsgCd: item["이용용도"],
operMngCd: item["운영관리형태"],
anlOperCst: Number(item["연간운영비(원/년)"]) ?? 0,
prcsCpct: item["처리용량(m³)"],
spwtPositn: item["채수지점"],
rswtrPollutions: makePoluttion,
rgtr: TEST_UUID,
mdfr: TEST_UUID,
rswtrDetails: [
{
utztnUsgCd: item["이용용도"],
vltnDt:vltnDt,
vltnMttr: item["위반사항"],
levyAmt: Number(item["과태료 부과금액(천원)"]) ?? 0,
rgtr: TEST_UUID,
mdfr: TEST_UUID,
},
],
};
}
})
.filter((el: any) => el !== undefined);
return rainChkgdData;
};
@@ -0,0 +1,231 @@
import { z } from "zod";
import { guideDetail, type chHeadType } from "../rainChkgdn/headList";
import type { TableUpperProps } from "@/app/store/common/type/header";
export type polutionType = {
chkgdnDtlFk: number;
utztnUsgCd: string;
node: number;
grssClfgUswtr: number;
combResdch: number;
trbt: number;
bod: number;
smll: number;
crmty: number;
tph: number;
tn: number;
ph: number;
clIonQnt: number;
edit?:boolean
};
const reuseBuildingZod = z.object({
bdstRuseFcltPk: z.number().nullish(),
bdstInfoFk: z.number().nullish(),
instlCmptnDt: z.string().nullable(), // Assuming it's a date string or null
instlCst: z.number(),
operMngCd: z.string().nullable(),
instlCstSprtYn: z.string().nullable(), // Assuming 'Y'/'N' or similar, or null
instlCstSprtAmt: z.number(),
grntchBdstCertYn: z.string().nullable(),
grntchBdstCertYr: z.string().nullable(), // Could be z.number().nullable() if it's strictly a year number
grntchBdstCertNo: z.string().nullable(),
grntchBdstCertGrd: z.string().nullable(),
crgRdctYn: z.string().nullable(),
crgRdctBss: z.string().nullable(),
crgRdctAmt: z.number(),
ruseFcltFlg: z.string().nullable(),
bdstUsgCd: z.number(),
lawTrgtYn: z.string().nullable(), // Assuming 'Y'/'N' or similar, or null
rgtr: z.string(), // Assuming this is a UUID
mdfr: z.string(), // Assuming this is a UUID
});
const buildingZod = z.object({
bdstInfoPk: z.number().nullable(),
ctpvCd: z.number(),
sggCd: z.number(),
daddr: z.string().nullable(),
bdstNm: z.string(),
frstArchPrmsnDt: z.string().nullable(), // Assuming it's a date string or null
archArea: z.number(),
rgtr: z.string(), // Assuming this is a UUID
mdfr: z.string(), // Assuming this is a UUID
});
export const rswtrPolutionsZode = z.object({
chkgdnDtlFk: z.string().nullish(),
utztnUsgCd: z.string().nullish(),
node: z.string().nullish(),
grssClfgUswtr: z.number(),
combResdch: z.number(),
trbt: z.number(),
bod: z.number(),
smll: z.number(),
crmty: z.number(),
tph: z.number(),
tn: z.number(),
ph: z.number(),
clIonQnt: z.number(),
regDt: z.string().nullish(),
rgtr: z.string().nullish(),
mdfcnDt: z.string().nullish(),
mdfr: z.string().nullish(),
edit:z.boolean().nullish()
});
export const rswtrDetailsZod = z.object({
chkgdnDtlPk: z.string().nullish(),
chkgdnFk: z.string().nullish(),
utztnUsgCd: z.string(),
vltnDt: z.string(),
vltnMttr: z.string(),
levyAmt: z.number(),
regDt: z.string().nullish(),
rgtr: z.string().nullish(),
mdfcnDt: z.string().nullish(),
mdfr: z.string().nullish(),
})
export const rswtChkgdZod = z.object({
chkgdnPk: z.number().nullish(),
bdstRuseFcltFk: z.number().nullish(),
chckYmd: z.string(),
prcsCpct: z.number(),
dtfcltCpct: z.number(),
spwtPositn: z.string(),
regDt: z.string().nullish(),
rgtr: z.string().nullish(),
mdfcnDt: z.string().nullish(),
mdfr: z.string().nullish(),
anlOperCst:z.number(),
oilqMeasMthd: z.string().nullish(),
utztnUsgCd: z.string(),
building: buildingZod,
guideDetails: z.array(guideDetail),
reuseBuilding: reuseBuildingZod,
rswtrDetails: z.array(
rswtrDetailsZod
),
rswtrPollutions: z.array(rswtrPolutionsZode),
});
export const rswtHeadNmExport: chHeadType[] = [
{ headNm: "useQuilty", text: "연간 평균 이용수질", length: 10 },
{ headNm: "feeHist", text: "과태료 부과내역", length: 3 },
];
export const rswtChkHeadListExport: TableUpperProps[] = [
{ id: "order", title: "순번", mergeCell: true },
{ id: "checkBox", title: "선택", mergeCell: true },
{ id: "cityText", title: "시도" ,mergeCell: true },
{ id: "sggText", title: "시군구",mergeCell: true },
{ id: "bdstNm", title: "시설명" ,mergeCell: true},
{ id: "operMngCd", title: "운영관리형태" ,mergeCell: true},
{ id: "anlOperCst", title: "연간운영비(원/년)" ,mergeCell: true},
{ id: "prcsCpct", title: "처리용량(m³)" ,mergeCell: true},
{ id: "spwtPositn", title: "채수지점" ,mergeCell: true},
{ id: "chckYmd", title: "점검일" ,mergeCell: true},
{ id: "utztnUsgCd", title: "이용용도" },
{ id: "splyUswtrUtztnQnt", title: "연간보급수이용량(m³)" ,type: "number"},
{ id: "ruseFcltUtztnQnt", title: "연간중수도이용량(m³)",type: "number"},
{
id: "grssClfgUswtr",
title: "총대장균군수",
upName: "useQuilty",
upSequnce: 1,
type: "number"
},
{
id: "combResdch",
title: "결합잔류염소",
upName: "useQuilty",
upSequnce: 2,
type: "number"
},
{ id: "trbt", title: "탁도", upName: "useQuilty", upSequnce: 3 ,type: "number"},
{ id: "bod", title: "BOD", upName: "useQuilty", upSequnce: 4 ,type: "number"},
{ id: "smll", title: "냄새", upName: "useQuilty", upSequnce: 5 ,type: "number"},
{ id: "crmty", title: "색도", upName: "useQuilty", upSequnce: 6 ,type: "number"},
{ id: "tn", title: "T-N", upName: "useQuilty", upSequnce: 7 ,type: "number"},
{ id: "tph", title: "T-P", upName: "useQuilty", upSequnce: 8 ,type: "number"},
{ id: "ph", title: "PH", upName: "useQuilty", upSequnce: 9,type: "number" },
{ id: "clIonQnt", title: "염화물", upName: "useQuilty", upSequnce: 10 ,type: "number"},
{
id: "vltnDt",
title: "부과일(위반일)",
upName: "feeHist",
upSequnce: 1,
type: "text",
edit:true
},
{
id: "vltnMttr",
title: "위반사항",
upName: "feeHist",
upSequnce: 2,
type: "text",
edit:true
},
{
id: "levyAmt",
title: "부과금액(천원)",
upName: "feeHist",
upSequnce: 3,
type: "number",
edit:true
}];
export const rswtDetailHeadListExport: TableUpperProps[] = [
{ id: "utztnUsgCd", title: "이용용도" },
{
id: "grssClfgUswtr",
title: "총대장균군수",
upName: "detailQulity",
upSequnce: 2,
edit: true,
},
{
id: "combResdch",
title: "결합잔류염소",
upName: "detailQulity",
upSequnce: 3,
edit: true,
},
{
id: "trbt",
title: "탁도",
upName: "detailQulity",
upSequnce: 4,
edit: true,
},
{ id: "bod", title: "BOD", upName: "detailQulity", upSequnce: 5, edit: true },
{
id: "smll",
title: "냄새",
upName: "detailQulity",
upSequnce: 6,
edit: true,
},
{
id: "crmty",
title: "색도",
upName: "detailQulity",
upSequnce: 7,
edit: true,
},
{ id: "tn", title: "T-N", upName: "detailQulity", upSequnce: 8, edit: true },
{ id: "tph", title: "T-P", upName: "detailQulity", upSequnce: 9, edit: true },
{ id: "ph", title: "PH", upName: "detailQulity", upSequnce: 10, edit: true },
{
id: "clIonQnt",
title: "염화물",
upName: "detailQulity",
upSequnce: 11,
edit: true,
},
];
@@ -0,0 +1,299 @@
import {
TEST_UUID,
} from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import type {
SelectDataType,
SheetParameter,
} from "@common/business_components";
import {
deleteFectch,
fetchType,
getFetch,
postFectch,
putFectch,
} from "@/components/lib/api";
import { buildingType } from "@/app/store/common/code";
import { rswtMakeExcelSample } from "./excel";
import {
rswtChkgdZod,
rswtChkHeadListExport,
rswtDetailHeadListExport,
rswtHeadNmExport,
rswtrDetailsZod,
} from "./headList";
import { z } from "zod";
import { ToastFormUi } from "@/components/ui/toast/toastFromUi";
import { type chHeadType } from "../rainChkgdn/headList";
import type { TableUpperProps } from "@/app/store/common/type/header";
const rswtChkHeadList = rswtChkHeadListExport;
const rswtDetailHeadList = rswtDetailHeadListExport;
const rswtHeadNm = rswtHeadNmExport;
export type rswtChkZodType = z.infer<typeof rswtChkgdZod>;
export type rswtrChkDetailsZodType = z.infer<typeof rswtrDetailsZod>;
export type rswtChkgdnState = {
rswtChkgdn: {
rswtChkHeadList: TableUpperProps[];
rswtDetailHeadList: TableUpperProps[];
rswtHeadNm: chHeadType[];
excelList: SheetParameter[];
rswtChkRes: rswtChkZodType[];
rswtChkPolGuide: rswtChkZodType[];
isInit: boolean;
isSttn:boolean
};
};
type rswtChkgdnActions = {
rswtChkgdnInit: (year: string, sggCd: string) => void;
rswtrChkExcelDownload(
sidoCode: SelectDataType[],
sggCode: SelectDataType[]
): Promise<void>;
rswtChkExceDataUpload: (excelData: rswtChkZodType[]) => void;
rswtChkDelete: (chkgdnPks: number[]) => void;
rswtChkDetilsUpdate: (rswtChkDetails: rswtrChkDetailsZodType[]) => void;
rswtChkPolAndGuide: (chkGdnPk: number) => void;
rswtChkPolInit: () => void;
rwstPolAndGuideUpdate: (rswtChk: rswtChkZodType[]) => void;
rswtChkHeadChange: (rswtChkgdn: rswtChkgdnState, isEdit: boolean) => void;
};
export type rswtChkgdnType = rswtChkgdnState & rswtChkgdnActions;
export const rswtChkgdnStateExport: rswtChkgdnState = {
rswtChkgdn: {
rswtChkHeadList: rswtChkHeadList,
rswtDetailHeadList: rswtDetailHeadList,
rswtHeadNm: rswtHeadNm,
excelList: [{
data: [[]], headerNum: 0, headerRange: "A1:V3",
sheetName: "",
startCol: '1'
}],
rswtChkRes: [],
rswtChkPolGuide: [],
isInit: false,
isSttn:false,
},
};
const initFetch = async (year: string | undefined, sgg: string | undefined) => {
const rswtChkRes = await getFetch(
"wr",
`/reuseChk/reuseWater/` +
(year ? `${year}` : "2024") +
(sgg ? `/${sgg}` : "/0")
);
return rswtChkRes;
};
const makeMdfrChk = (data: rswtChkZodType[] | rswtrChkDetailsZodType[]) => {
const chData = data.map((item) => {
item.mdfr = TEST_UUID;
item.rgtr = TEST_UUID;
if ("rswtrPollutions" in item) {
item?.rswtrPollutions.forEach((pollution) => {
pollution.mdfr = TEST_UUID;
pollution.rgtr = TEST_UUID;
});
}
return item;
});
return chData;
};
export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = (
set: any
) => {
return {
rswtrChkExcelDownload: async (
sidoCode: SelectDataType[],
sggCode: SelectDataType[]
) => {
const data = await getFetch(
fetchType.WR,
`/reuseFc/buildingFlg/${buildingType.RST}/41`
);
const excelList: any = [];
const exceldata = rswtMakeExcelSample(data, sidoCode, sggCode);
excelList.push({
data: exceldata.guideDetail,
headerNum: 0,
headerRange: "A1:AI1",
});
excelList.push({
data: exceldata.polutions,
headerNum: 0,
headerRange: "A1:AZ1",
});
return set((state: rswtChkgdnState) => ({
rswtChkgdn: {
...state.rswtChkgdn,
excelList: excelList,
},
}));
},
rswtChkgdnInit: async (year: string, sggCd: string) => {
try {
const rswtChkRes = await initFetch("2024", sggCd);
return set((state: rswtChkgdnState) => ({
...state,
rswtChkgdn: {
...state.rswtChkgdn,
rswtChkRes: rswtChkRes,
isInit: false,
},
}));
} catch (error) {
console.log(error);
}
},
rswtChkExceDataUpload: async (excelData: rswtChkZodType[]) => {
try {
const res = await postFectch("/reuseChk/reuseWater", excelData);
if (res.ok) {
ToastFormUi({
body: "지도점검 등록이 완료되었습니다.",
title: "지도점검 등록",
});
}
// const rainChkRes = await initFetch('2024', '0');
return set((state: rswtChkgdnState) => ({
...state,
rswtChkgdn: {
...state.rswtChkgdn,
},
}));
} catch (error) {
console.log(error);
}
},
rswtChkDetilsUpdate: async (rswtChk: rswtrChkDetailsZodType[]) => {
try {
const chData = await makeMdfrChk(rswtChk);
const res = await putFectch("/reuseChk/reuseWater", chData);
if (res.ok) {
ToastFormUi({
body: "지도점검 과태료 수정 수정이 완료되었습니다. ",
title: "지도점검 수정",
});
}
const rswtChkRes = await initFetch("2024", "0");
return set((state: rswtChkgdnState) => ({
...state,
rswtChkgdn: {
...state.rswtChkgdn,
rswtChkRes: rswtChkRes,
},
}));
} catch (error) {
console.log(error);
alert("수정에 실패하였습니다.");
}
},
rswtChkDelete: async (chkgdnPks: number[]) => {
try {
const res = await deleteFectch(`/reuseChk/reuseWater`, chkgdnPks);
if (res.ok) {
ToastFormUi({
body: "삭제가 완료되었습니다. ",
title: "지도점검 삭제",
});
}
const rswtChkRes = await initFetch("2024", "0");
return set((state: rswtChkgdnState) => ({
...state,
rswtChkgdn: {
...state.rswtChkgdn,
rswtChkRes: rswtChkRes,
},
}));
} catch (error) {
ToastFormUi({ body: "삭제를 실패했습니다.. ", title: "지도점검 삭제" });
}
},
rswtChkPolAndGuide: async (chkGdnPk: number) => {
try {
const rswtChkPolGuide = await getFetch(
"wr",
`/reuseChk/reuseWater/${chkGdnPk}`
);
return set((state: rswtChkgdnState) => ({
...state,
rswtChkgdn: {
...state.rswtChkgdn,
rswtChkPolGuide: rswtChkPolGuide,
},
}));
} catch (error) {}
},
rswtChkPolInit: () => {
try {
return set((state: rswtChkgdnState) => ({
...state,
rswtChkgdn: {
...state.rswtChkgdn,
rswtChkPolGuide: undefined,
},
}));
} catch (error) {}
},
rwstPolAndGuideUpdate: async (rswtChk: rswtChkZodType[]) => {
try {
const chData = await makeMdfrChk(rswtChk);
const res = await putFectch(
`/reuseChk/reuseWater/${rswtChk[0]?.chkgdnPk}`,
chData[0]
);
if (res.ok) {
ToastFormUi({
body: "지도점검 연간 수질 및 보급수/중수도 수정이 완료되었습니다. ",
title: "지도점검 수정",
});
}
const rswtChkRes = await initFetch("2024", "0");
return set((state: rswtChkgdnState) => ({
...state,
rswtChkgdn: {
...state.rswtChkgdn,
rswtChkRes: rswtChkRes,
},
}));
} catch (error) {
console.log(error);
ToastFormUi({
body: "지도점검 연간 수질 및 보급수/중수도 수정이 실패하였습니다.. ",
title: "지도점검 수정",
});
}
},
rswtChkHeadChange: async (rswtChkgdn: rswtChkgdnState, isEdit: boolean) => {
try {
const rswtChkHeadList = rswtChkgdn.rswtChkgdn.rswtChkHeadList;
const rswtDetailHeadList = rswtChkgdn.rswtChkgdn.rswtDetailHeadList;
rswtChkHeadList.forEach((head) => {
if (head.edit !== undefined) head.edit = isEdit;
});
rswtDetailHeadList.forEach((head) => {
if (head.edit !== undefined) head.edit = isEdit;
});
return set((state: rswtChkgdnState) => ({
...state,
rswtChkgdn: {
...state.rswtChkgdn,
rswtChkHeadList: rswtChkHeadList,
rswtDetailHeadList: rswtDetailHeadList,
},
}));
} catch (e) {}
},
};
};
@@ -0,0 +1,55 @@
import { TEST_UUID } from "../../ruseFcltMng/fcltReg/rainReg";
type NameMap = {
[key: string]: string;
};
const nameMap:NameMap = {
"세척수": "wshwtr",
"냉각수": "coolUswtr",
"청소수": "cleanUswtr",
"식수대": "drwtUswtr",
"희석용수": "dltnUswtr",
"중수도": "ithlRswtr",
"기타": "ithlEtcUswtr",
"청소화장실용수": "cleanToilUswtr",
"세척살수용수": "resn",
"조경용수": "lndwtr",
"친수용수": "hydUswtr",
"지하수충전": "ugwtChr",
"농업용수": "farmUswtr",
"하천등유지용수": "rvrKeepUswtr",
"공업용수": "indstUswtr"
};
export const excelToPbnPrfData = (excelData: JSON[], year: string,pbnstRuseFcltFk:string) => {
// 월별 데이터 하나로 병합
const merged = {} as any;
excelData.forEach((item: any) => {
const usageNm = item["용수명"]
const key = nameMap[usageNm as any];
if (!key) return;
for (let i = 1; i <= 12; i++) {
const month = i.toString().padStart(2, "0");
const ym = year + month;
if (!merged[ym]) merged[ym] = { ym };
merged[ym][key] = Number(item[`${i}월`] ?? 0);
}
});
const pbnPrfData = Object.values(merged);
const data = pbnPrfData.map((item) => {
return({
...(item as object),
pbnstRuseFcltFk:pbnstRuseFcltFk,
rgtr: TEST_UUID,
mdfr: TEST_UUID,
})
})
return data;
};
@@ -0,0 +1,38 @@
import { z } from "zod";
import type { TableUpperProps } from "../../common/type/header";
export const pbnPrfRegExcelZod = z.object({
ym: z.string().default(""),
bscFctNm: z.string().default(""),
pbnstRuseFcltFk:z.string(),
pbnstRuseFcltNm: z.string().default(""),
file: z.instanceof(File).optional(),
});
export const pbnstPrfmncHeadListExport: TableUpperProps[] = [
{ id: "sido", title: "시도" },
{ id: "gugun", title: "시군구" },
{ id: "bscFctNm", title: "시설명" },
{ id: "ruseUtztnFcltNm", title: "재이용시설명" },
{ id: "pbnstRuseFcltPk", title: "재이용시설코드" },
];
export const monthHeadListExport: TableUpperProps[] = [
{ 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 },
];
@@ -0,0 +1,111 @@
import { fetchType, getFetch, postFectch } from "@/components/lib/api";
import { pbnstPrfmncHeadListExport, monthHeadListExport } from "./headList";
import type { pubHasuType } from "../../ruseFcltMng/fcltReg/pbnstReg/type";
import type { FcPrfType, PrfType } from "./type";
import type { TableUpperProps } from "../../common/type/header";
import { ToastFormUi } from "@/components/ui/toast/toastFromUi";
import toast from "react-hot-toast";
const pbnstPrfmncHeadList = pbnstPrfmncHeadListExport;
const monthHeadList = monthHeadListExport;
export type pbnstPrfmncState = {
prfmnc: {
isInit: boolean;
pbnstPrfmncHeadList: TableUpperProps[];
monthHeadList: TableUpperProps[];
prfmncRes: FcPrfType[];
excelList: Number[];
};
};
export const pbnstPrfmncStateExport: pbnstPrfmncState = {
prfmnc: {
isInit: false,
pbnstPrfmncHeadList: pbnstPrfmncHeadList,
monthHeadList: monthHeadList,
prfmncRes: [],
excelList: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
},
};
export type pbnstPrfmncType = pbnstPrfmncState & pbnstPrfmncActions;
type pbnstPrfmncActions = {
prfmncHasuInit: (page: string, sggOrCity: string) => void;
prfmnRegData: (data: PrfType) => void;
};
const checkWrRegList = async () => {
const wrRegList = await getFetch("wr", `/reuseFc/pubDetailList`);
return wrRegList;
};
const hasuListFetch = async (page: string, sggOrCity: string) => {
const checkWrRegListRes = await checkWrRegList();
const rainRes = await postFectch(
`/prcsFclt/ruseInfo/${page ? page : 1}/10/A/${sggOrCity ? sggOrCity : "11"}/0/1/SW`,
checkWrRegListRes?.fcltCds,
fetchType.COMMON
);
const findData = rainRes.data.map((item: pubHasuType) => {
const data = checkWrRegListRes?.fcPrfList.find(
(fclt: FcPrfType) =>
fclt.pbnstRuseFcltPk.substring(0, 11) === item?.bscFctCd
);
if(data !==undefined){
return( {
sido: item.sido,
gugun: item.gugun,
bscFctNm: item.bscFctNm,
bscFctCd: item.bscFctCd,
ruseUtztnFcltNm: data.ruseUtztnFcltNm,
pbnstRuseFcltPk: data.pbnstRuseFcltPk,
prfList: data.prfList,
});
}
});
return findData;
};
export const pbnstPrfmncActionsExport: (set: any) => pbnstPrfmncActions = (
set: any
) => {
return {
prfmncHasuInit: async (page: string, sggOrCity: string) => {
try {
const prfmncRes = await hasuListFetch(page, sggOrCity);
console.log("prfmncRes", prfmncRes);
return set((state: pbnstPrfmncState) => ({
...state,
prfmnc: {
...state.prfmnc,
prfmncRes: prfmncRes,
isInit: false,
},
}));
} catch (errorHasu) {
console.log(errorHasu);
}
},
prfmnRegData: async (data: PrfType) => {
try {
const ressponse = await postFectch(
"/reuseFc/pubFcPrf",
data,
fetchType.WR
);
if (ressponse.status === 200) {
toast.success("하수재이용 시설 실적 등록이 완료되었습니다.");
}
} catch (e) {
console.log(e);
toast.error("하수재이용 시설 실적 등록이 실패하였습니다.");
}
},
};
};
@@ -0,0 +1,346 @@
import { z } from "zod";
import type { TableUpperProps } from "../../common/type/header";
import { fcOperSchema } from "../../ruseFcltMng/fcltReg/pbnstReg/type";
export const PrfSchema = z.object({
pbnstRuseFcltFk: z.string(),
ym: z.string(), // 예: "202310"
wshwtr: z.number(),
coolUswtr: z.number(),
cleanUswtr: z.number(),
drwtUswtr: z.number(),
dltnUswtr: z.number(),
ithlRswtr: z.number(),
ithlEtcUswtr: z.number(),
cleanToilUswtr: z.number(),
resn: z.number(),
lndwtr: z.number(),
hydUswtr: z.number(),
rvrKeepUswtr: z.number(),
farmUswtr: z.number(),
ugwtChr: z.number(),
indstUswtr: z.number(),
regDt: z.date().default(new Date()).nullish(),
rgtr: z.string().nullish(),
mdfcnDt: z.date().default(new Date()).nullish(),
mdfr: z.string().nullish(),
});
export const FcPrfSchema = z.object({
pbnstRuseFcltPk: z.string(),
ruseUtztnFcltNm: z.string(),
fcltCpct: z.number(),
ruseCpct: z.number(),
splyExtraCpct: z.number(),
regDt: z.date().default(new Date()),
rgtr: z.string(),
mdfcnDt: z.date().default(new Date()),
mdfr: z.string(),
prfList: z.array(PrfSchema),
operList:z.array(fcOperSchema),
bscFctNm: z.string().nullish(),
});
export type FcPrfType = z.infer<typeof FcPrfSchema>;
export type PrfType = z.infer<typeof PrfSchema>;
export const initValInUsage = [
{
usage: "wshwtr",
용수명: "세척수",
total: 0,
"1월": 0,
"2월": 0,
"3월": 0,
"4월": 0,
"5월": 0,
"6월": 0,
"7월": 0,
"8월": 0,
"9월": 0,
"10월": 0,
"11월": 0,
"12월": 0,
},
{
usage: "coolUswtr",
용수명: "냉각수",
total: 0,
"1월": 0,
"2월": 0,
"3월": 0,
"4월": 0,
"5월": 0,
"6월": 0,
"7월": 0,
"8월": 0,
"9월": 0,
"10월": 0,
"11월": 0,
"12월": 0,
},
{
usage: "cleanUswtr",
용수명: "청소수",
total: 0,
"1월": 0,
"2월": 0,
"3월": 0,
"4월": 0,
"5월": 0,
"6월": 0,
"7월": 0,
"8월": 0,
"9월": 0,
"10월": 0,
"11월": 0,
"12월": 0,
},
{
usage: "drwtUswtr",
용수명: "식수대",
total: 0,
"1월": 0,
"2월": 0,
"3월": 0,
"4월": 0,
"5월": 0,
"6월": 0,
"7월": 0,
"8월": 0,
"9월": 0,
"10월": 0,
"11월": 0,
"12월": 0,
},
{
usage: "dltnUswtr",
용수명: "희석용수",
total: 0,
"1월": 0,
"2월": 0,
"3월": 0,
"4월": 0,
"5월": 0,
"6월": 0,
"7월": 0,
"8월": 0,
"9월": 0,
"10월": 0,
"11월": 0,
"12월": 0,
},
{
usage: "ithlRswtr",
용수명: "중수도",
total: 0,
"1월": 0,
"2월": 0,
"3월": 0,
"4월": 0,
"5월": 0,
"6월": 0,
"7월": 0,
"8월": 0,
"9월": 0,
"10월": 0,
"11월": 0,
"12월": 0,
},
{
usage: "ithlEtcUswtr",
용수명: "기타",
total: 0,
"1월": 0,
"2월": 0,
"3월": 0,
"4월": 0,
"5월": 0,
"6월": 0,
"7월": 0,
"8월": 0,
"9월": 0,
"10월": 0,
"11월": 0,
"12월": 0,
},
];
export const initValOutUsage = [
{
usage: "resn",
용수명: "세척살수용수",
total: 0,
"1월": 0,
"2월": 0,
"3월": 0,
"4월": 0,
"5월": 0,
"6월": 0,
"7월": 0,
"8월": 0,
"9월": 0,
"10월": 0,
"11월": 0,
"12월": 0,
},
{
usage: "cleanToilUswtr",
용수명: "청소화장실용수",
total: 0,
"1월": 0,
"2월": 0,
"3월": 0,
"4월": 0,
"5월": 0,
"6월": 0,
"7월": 0,
"8월": 0,
"9월": 0,
"10월": 0,
"11월": 0,
"12월": 0,
},
{
usage: "lndwtr",
용수명: "조경용수",
total: 0,
"1월": 0,
"2월": 0,
"3월": 0,
"4월": 0,
"5월": 0,
"6월": 0,
"7월": 0,
"8월": 0,
"9월": 0,
"10월": 0,
"11월": 0,
"12월": 0,
},
{
usage: "hydUswtr",
용수명: "친수용수",
total: 0,
"1월": 0,
"2월": 0,
"3월": 0,
"4월": 0,
"5월": 0,
"6월": 0,
"7월": 0,
"8월": 0,
"9월": 0,
"10월": 0,
"11월": 0,
"12월": 0,
},
{
usage: "ugwtChr",
용수명: "지하수충전",
total: 0,
"1월": 0,
"2월": 0,
"3월": 0,
"4월": 0,
"5월": 0,
"6월": 0,
"7월": 0,
"8월": 0,
"9월": 0,
"10월": 0,
"11월": 0,
"12월": 0,
},
{
usage: "farmUswtr",
용수명: "농업용수",
total: 0,
"1월": 0,
"2월": 0,
"3월": 0,
"4월": 0,
"5월": 0,
"6월": 0,
"7월": 0,
"8월": 0,
"9월": 0,
"10월": 0,
"11월": 0,
"12월": 0,
},
{
usage: "rvrKeepUswtr",
용수명: "하천등유지용수",
total: 0,
"1월": 0,
"2월": 0,
"3월": 0,
"4월": 0,
"5월": 0,
"6월": 0,
"7월": 0,
"8월": 0,
"9월": 0,
"10월": 0,
"11월": 0,
"12월": 0,
},
{
usage: "indstUswtr",
용수명: "공업용수",
total: 0,
"1월": 0,
"2월": 0,
"3월": 0,
"4월": 0,
"5월": 0,
"6월": 0,
"7월": 0,
"8월": 0,
"9월": 0,
"10월": 0,
"11월": 0,
"12월": 0,
},
];
export const subTotalObj = {
usage: "subtotal",
용수명: "소계",
edit: false,
total: 0,
"1월": 0,
"2월": 0,
"3월": 0,
"4월": 0,
"5월": 0,
"6월": 0,
"7월": 0,
"8월": 0,
"9월": 0,
"10월": 0,
"11월": 0,
"12월": 0,
};
export const totalObj = {
usage: "total",
용수명: "총합계",
edit: false,
total: 0,
"1월": 0,
"2월": 0,
"3월": 0,
"4월": 0,
"5월": 0,
"6월": 0,
"7월": 0,
"8월": 0,
"9월": 0,
"10월": 0,
"11월": 0,
"12월": 0,
};
@@ -0,0 +1,41 @@
import type { rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn";
type rainSttnExcelType = {
bdstInfoPk: number;
ctpvCd: 1;
sggCd: 1001;
daddr: "string3";
bdstNm: "string";
frstArchPrmsnDt: "2025-03-25";
archArea: 0;
regDt: "2025-04-16";
rgtr: null;
mdfcnDt: "2025-04-16";
mdfr: null;
};
export const buildingExcelRainSttn = (excelList: any[]) => {
const excelData: string[][] = [];
excelList.forEach((item, index) => {
excelData.push([
String(item.cityText) ?? "",
String(item.sggText) ?? "",
String(item.bdstNm) ?? "",
item.operMngCd || String(item.operMngCd)===null? String(item.operMngCd) : "",
String(item.oilqMeasMthd) ?? "",
String(item.anlOperCst) ?? "",
String(item.dtfcltCpct) ?? "",
String(item.chckYmd) ?? "",
String(item.utztnUsgCd) ?? "",
String(item.totalSplyUswtrUtztnQnt) ?? "",
String(item.totalRuseFcltUtztnQnt) ?? "",
String(item.ph) ?? "",
String(item.trbt) ?? "",
String(item.grssClfg) ?? "",
String(item.vltnDt) ?? "",
String(item.vltnMttr) ?? "",
String(item.levyAmt) ?? "",
]);
});
return excelData;
};
@@ -0,0 +1,163 @@
import type { TableUpperProps } from "@/app/store/common/type/header";
export const rainChkgdnHeadSttnExport: TableUpperProps[] = [
{ id: 'order', title: "순번", mergeCell: true },
{ id: "cityText", title: "시도", mergeCell: true },
{ id: "sggText", title: "시군구", mergeCell: true },
{ id: "bdstNm", title: "시설명", mergeCell: true },
{ id: "operMngCd", title: "운영관리형태", mergeCell: true },
{ id: "oilqMeasMthd", title: "유량측정방법", mergeCell: true },
{ id: "anlOperCst", title: "연간운영비(원/년)", mergeCell: true },
{ id: "dtfcltCpct", title: "빗물저류조용량(m³)", mergeCell: true },
{ id: "chckYmd", title: "점검일", mergeCell: true },
{ id: "utztnUsgCd", title: "이용용도" },
{ id: "totalSplyUswtrUtztnQnt", title: "연간보급수이용량(m³)" },
{ id: "totalRuseFcltUtztnQnt", title: "연간빗물이용량(m³)" },
{
id: "ph",
title: "PH",
upName: "useQuilty",
upSequnce: 1,
type: "number",
},
{
id: "trbt",
title: "탁도",
upName: "useQuilty",
upSequnce: 2,
type: "number",
},
{
id: "grssClfg",
title: "총대장균군수",
upName: "useQuilty",
upSequnce: 3,
type: "number",
},
{
id: "vltnDt",
title: "부과일(위반일)",
upName: "feeHist",
upSequnce: 1,
type: "text",
},
{
id: "vltnMttr",
title: "위반사항",
upName: "feeHist",
upSequnce: 2,
type: "text",
},
{
id: "levyAmt",
title: "부과금액(천원)",
upName: "feeHist",
upSequnce: 3,
type: "number",
},
];
export const ruseSttnHeadListExport: TableUpperProps[] = [
{ id: "utztnUsgCd", title: "이용용도" },
{ id: "ruseTotal", title: "계", upName: "ruseWater", upSequnce: 1 },
{ id: "ruse01", title: "1월", upName: "ruseWater", upSequnce: 2 },
{ id: "ruse02", title: "2월", upName: "ruseWater", upSequnce: 3 },
{ id: "ruse03", title: "3월", upName: "ruseWater", upSequnce: 4 },
{ id: "ruse04", title: "4월", upName: "ruseWater", upSequnce: 5 },
{ id: "ruse05", title: "5월", upName: "ruseWater", upSequnce: 6 },
{ id: "ruse06", title: "6월", upName: "ruseWater", upSequnce: 7 },
{ id: "ruse07", title: "7월", upName: "ruseWater", upSequnce: 8 },
{ id: "ruse08", title: "8월", upName: "ruseWater", upSequnce: 9 },
{ id: "ruse09", title: "9월", upName: "ruseWater", upSequnce: 10 },
{ id: "ruse10", title: "10월", upName: "ruseWater", upSequnce: 11 },
{ id: "ruse11", title: "11월", upName: "ruseWater", upSequnce: 12 },
{ id: "ruse12", title: "12월", upName: "ruseWater", upSequnce: 13 },
];
export const splSttnHeadListExport: TableUpperProps[] = [
{ id: "utztnUsgCd", title: "이용용도" },
{ id: "splTotal", title: "계", upName: "splWater", upSequnce: 1 },
{ id: "spl01", title: "1월", upName: "splWater", upSequnce: 2 },
{ id: "spl02", title: "2월", upName: "splWater", upSequnce: 3 },
{ id: "spl03", title: "3월", upName: "splWater", upSequnce: 4 },
{ id: "spl04", title: "4월", upName: "splWater", upSequnce: 5 },
{ id: "spl05", title: "5월", upName: "splWater", upSequnce: 6 },
{ id: "spl06", title: "6월", upName: "splWater", upSequnce: 7 },
{ id: "spl07", title: "7월", upName: "splWater", upSequnce: 8 },
{ id: "spl08", title: "8월", upName: "splWater", upSequnce: 9 },
{ id: "spl09", title: "9월", upName: "splWater", upSequnce: 10 },
{
id: "spl10",
title: "10월",
upName: "splWater",
upSequnce: 11,
},
{
id: "spl11",
title: "11월",
upName: "splWater",
upSequnce: 12,
},
{
id: "spl12",
title: "12월",
upName: "splWater",
upSequnce: 13,
},
];
export const rswtDetailHeadListExport: TableUpperProps[] = [
{ id: "utztnUsgCd", title: "이용용도" },
{
id: "grssClfgUswtr",
title: "총대장균군수",
upName: "detailQulity",
upSequnce: 2,
},
{
id: "combResdch",
title: "결합잔류염소",
upName: "detailQulity",
upSequnce: 3,
},
{
id: "trbt",
title: "탁도",
upName: "detailQulity",
upSequnce: 4,
},
{
id: "bod",
title: "BOD",
upName: "detailQulity",
upSequnce: 5,
},
{
id: "smll",
title: "냄새",
upName: "detailQulity",
upSequnce: 6,
},
{
id: "crmty",
title: "색도",
upName: "detailQulity",
upSequnce: 7,
},
{ id: "tn", title: "T-N", upName: "detailQulity", upSequnce: 8},
{
id: "tph",
title: "T-P",
upName: "detailQulity",
upSequnce: 9,
},
{ id: "ph", title: "PH", upName: "detailQulity", upSequnce: 10 },
{
id: "clIonQnt",
title: "염화물",
upName: "detailQulity",
upSequnce: 11,
},
];
@@ -0,0 +1,129 @@
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";
const fcltDiv = [
{ val: "RST", text: "중수도시설" },
{ val: "RNB", text: "빗물이용시설" },
];
const rainChkgdnHeadList = rainChkgdnHeadSttnExport;
const ruseHeadList = ruseSttnHeadListExport;
const splHeadList = splSttnHeadListExport;
const rainHeadNm = rainHeadNmExport
const rainChk: rainChkZodType[] = [];
export type rainChkSttnState = {
rainChkSttn: {
rainChkRes: rainChkZodType[];
fcltDiv: SelectDataType[];
rainChkgdnHeadList: TableUpperProps[];
rainHeadNm:chHeadType[];
ruseHeadList: TableUpperProps[];
splHeadList: TableUpperProps[];
sttnExcelList:[]
isInit: boolean;
isSttn:boolean;
};
};
type rainChkSttnActions = {
rainChkSttnInit: ( sggCd: string) => void;
rainChkSttnSearch: (searchTxt: string, sggCd: string) => void;
isRainSttn:(isSttn:boolean) => void;
getRainSttnExcel:(excelList:rainChkZodType[]) => void;
};
export type rainChkSttnType = rainChkSttnState & rainChkSttnActions;
export const rainChkSttnStateExport: rainChkSttnState = {
rainChkSttn: {
rainChkRes: [],
fcltDiv: fcltDiv,
rainChkgdnHeadList: rainChkgdnHeadList,
ruseHeadList: ruseHeadList,
splHeadList: splHeadList,
rainHeadNm:rainHeadNm,
isInit: false,
sttnExcelList:[],
isSttn:false,
},
};
const initFetch = async (txt: string | undefined, sgg: string | undefined) => {
const rainRes = await getFetch(
"wr",
`/reuseChk/rainy/` + (txt ? `${txt}` : "2024") + (sgg ? `/${sgg}` : "/0")
);
return rainRes;
};
export const rainChkSttnActionsExport: (set: any) => rainChkSttnActions = (
set: any
) => {
return {
rainChkSttnInit: async ( sggCd: string) => {
try {
const rainChkRes = await initFetch(undefined, sggCd);
return set((state: rainChkSttnState) => ({
...state,
rainChkSttn: {
...state.rainChkSttn,
rainChkRes:rainChkRes
},
}));
} catch (error) {
console.log(error);
}
},
rainChkSttnSearch: async (searchTxt: string, sggCd: string) => {
try {
const rainChkRes = await initFetch(searchTxt, sggCd);
return set((state: rainChkSttnState) => ({
...state,
rainChkSttn: {
...state.rainChkSttn,
rainChkRes:rainChkRes
},
}));
} catch (error) {
console.log(error);
}
},isRainSttn :(isSttn:boolean) =>{
try {
return set((state: rainChkSttnState) => ({
...state,
rainChkSttn: {
...state.rainChkSttn,
isSttn:isSttn
},
}));
} catch (error) {
console.log(error);
}
},getRainSttnExcel: async (excelList:rainChkZodType[]) => {
try {
const excelData = buildingExcelRainSttn(excelList)
return set((state: rainChkSttnState) => ({
...state,
rainChkSttn: {
...state.rainChkSttn,
sttnExcelList:excelData
},
}));
} catch (error) {
console.log(error);
}
}
};
};
@@ -0,0 +1,34 @@
export const buildingExcelRswtSttn = (excelList: any[]) => {
const excelData: string[][] = [];
excelList.forEach((item, index) => {
excelData.push([
String(item.cityText) ?? "",
String(item.sggText) ?? "",
String(item.bdstNm) ?? "",
item.operMngCd===null ? "":item.operMngCd,
String(item.anlOperCst) ?? "",
String(item.prcsCpct) ?? "",
item.spwtPositn===null ? "":item.spwtPositn,
item.chckYmd ?? "",
String(item.utztnUsgCd) ?? "",
String(item.splyUswtrUtztnQnt) ?? "",
String(item.ruseFcltUtztnQnt) ?? "",
String(item.grssClfgUswtr) ?? "",
String(item.combResdch) ?? "",
String(item.trbt) ?? "",
String(item.bod) ?? "",
String(item.smll) ?? "",
String(item.tn) ?? "",
String(item.tph) ?? "",
String(item.ph) ?? "",
String(item.clIonQnt) ?? "",
String(item.vltnDt) ?? "",
String(item.vltnMttr) ?? "",
String(item.levyAmt) ?? "",
]);
});
return excelData;
};
@@ -0,0 +1,142 @@
import type { TableUpperProps } from "@/app/store/common/type/header";
export const rswtChkSttnHeadListExport: TableUpperProps[] = [
{ id: "order", title: "순번", rowSpan: true },
{ id: "cityText", title: "시도", rowSpan: true },
{ id: "sggText", title: "시군구", rowSpan: true },
{ id: "bdstNm", title: "시설명", rowSpan: true },
{ id: "operMngCd", title: "운영관리형태", rowSpan: true },
{ id: "anlOperCst", title: "연간운영비(원/년)", rowSpan: true },
{ id: "prcsCpct", title: "처리용량(m³)", rowSpan: true },
{ id: "spwtPositn", title: "채수지점", rowSpan: true },
{ id: "chckYmd", title: "점검일", rowSpan: true },
{ id: "utztnUsgCd", title: "이용용도" },
{ id: "splyUswtrUtztnQnt", title: "연간보급수이용량(m³)", type: "number" },
{ id: "ruseFcltUtztnQnt", title: "연간중수도이용량(m³)", type: "number" },
{
id: "grssClfgUswtr",
title: "총대장균군수",
upName: "useQuilty",
upSequnce: 1,
type: "number",
},
{
id: "combResdch",
title: "결합잔류염소",
upName: "useQuilty",
upSequnce: 2,
type: "number",
},
{
id: "trbt",
title: "탁도",
upName: "useQuilty",
upSequnce: 3,
type: "number",
},
{
id: "bod",
title: "BOD",
upName: "useQuilty",
upSequnce: 4,
type: "number",
},
{
id: "smll",
title: "냄새",
upName: "useQuilty",
upSequnce: 5,
type: "number",
},
{
id: "crmty",
title: "색도",
upName: "useQuilty",
upSequnce: 6,
type: "number",
},
{ id: "tn", title: "T-N", upName: "useQuilty", upSequnce: 7, type: "number" },
{
id: "tph",
title: "T-P",
upName: "useQuilty",
upSequnce: 8,
type: "number",
},
{ id: "ph", title: "PH", upName: "useQuilty", upSequnce: 9, type: "number" },
{
id: "clIonQnt",
title: "염화물",
upName: "useQuilty",
upSequnce: 10,
type: "number",
},
{
id: "vltnDt",
title: "부과일(위반일)",
upName: "feeHist",
upSequnce: 1,
type: "text",
},
{
id: "vltnMttr",
title: "위반사항",
upName: "feeHist",
upSequnce: 2,
type: "text",
},
{
id: "levyAmt",
title: "부과금액(천원)",
upName: "feeHist",
upSequnce: 3,
type: "number",
},
];
export const rswtDetailSttnHeadListExport: TableUpperProps[] = [
{ id: "utztnUsgCd", title: "이용용도" },
{
id: "grssClfgUswtr",
title: "총대장균군수",
upName: "detailQulity",
upSequnce: 2,
},
{
id: "combResdch",
title: "결합잔류염소",
upName: "detailQulity",
upSequnce: 3,
},
{
id: "trbt",
title: "탁도",
upName: "detailQulity",
upSequnce: 4,
},
{ id: "bod", title: "BOD", upName: "detailQulity", upSequnce: 5 },
{
id: "smll",
title: "냄새",
upName: "detailQulity",
upSequnce: 6,
},
{
id: "crmty",
title: "색도",
upName: "detailQulity",
upSequnce: 7,
},
{ id: "tn", title: "T-N", upName: "detailQulity", upSequnce: 8},
{ id: "tph", title: "T-P", upName: "detailQulity", upSequnce: 9 },
{ id: "ph", title: "PH", upName: "detailQulity", upSequnce: 10 },
{
id: "clIonQnt",
title: "염화물",
upName: "detailQulity",
upSequnce: 11,
},
];
@@ -0,0 +1,107 @@
import { rswtHeadNmExport } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList";
import { rswtChkSttnHeadListExport, rswtDetailSttnHeadListExport } from "./headList";
import type { TableUpperProps } from "@/app/store/common/type/header";
import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList";
import type { rswtChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn";
import { getFetch } from "@/components/lib/api";
import { buildingExcelRswtSttn } from "./excel";
const rswtChkHeadList = rswtChkSttnHeadListExport;
const rswtDetailHeadList = rswtDetailSttnHeadListExport;
const rswtHeadNm = rswtHeadNmExport;
export type rswtChkSttnState = {
rswtChkSttn: {
rswtChkSttnHeadList: TableUpperProps[];
rswtDetailSttnHeadList: TableUpperProps[];
rswtSttnHeadNm: chHeadType[];
sttnExcelList: [];
rswtChkRes: rswtChkZodType[];
isInit: boolean;
isSttn: boolean;
};
};
type rswtChkSttnActions = {
rswtChkSttnInit: ( sggCd: string) => void;
isRswtSttn: (isSttn:boolean) => void;
getRswtSttnExcel:(excelList:rswtChkZodType[]) => void;
};
export type rswtChkSttnType = rswtChkSttnState & rswtChkSttnActions;
export const rswtChkStateExport: rswtChkSttnState = {
rswtChkSttn: {
rswtChkSttnHeadList: rswtChkHeadList,
rswtDetailSttnHeadList: rswtDetailHeadList,
rswtSttnHeadNm: rswtHeadNm,
sttnExcelList: [],
rswtChkRes: [],
isInit: false,
isSttn:false,
},
};
const initFetch = async (year: string | undefined, sgg: string | undefined) => {
const rswtChkRes = await getFetch(
"wr",
`/reuseChk/reuseWater/` +
(year ? `${year}` : "2024") +
(sgg ? `/${sgg}` : "/0")
);
return rswtChkRes;
};
export const rswtChkSttnActionsExport: (set: any) => rswtChkSttnActions = (
set: any
) => {
return {
rswtChkSttnInit: async ( sggCd: string) => {
try {
const rswtChkRes = await initFetch("2024", sggCd);
return set((state: rswtChkSttnState) => ({
...state,
rswtChkSttn: {
...state.rswtChkSttn,
rswtChkRes: rswtChkRes,
isInit: false,
},
}));
} catch (error) {
console.log(error);
}
},isRswtSttn :(isSttn:boolean) =>{
try {
return set((state: rswtChkSttnState) => ({
...state,
rswtChkSttn: {
...state.rswtChkSttn,
isSttn:isSttn
},
}));
} catch (error) {
console.log(error);
}
},getRswtSttnExcel: async (excelList:rswtChkZodType []) => {
try {
const excelData = buildingExcelRswtSttn(excelList)
return set((state: rswtChkSttnState) => ({
...state,
rswtChkSttn: {
...state.rswtChkSttn,
sttnExcelList:excelData
},
}));
} catch (error) {
console.log(error);
}
}
};
};
@@ -0,0 +1,24 @@
export const excelPrfmncSttnParsing = (
data: any[]
): string[][] => {
const excelExportData: string[][] = [];
data.forEach((item) => {
excelExportData.push([
item.용수명,
item.total,
item["1월"],
item["2월"],
item["3월"],
item["4월"],
item["5월"],
item["6월"],
item["7월"],
item["8월"],
item["9월"],
item["10월"],
item["11월"],
item["12월"],
]);
});
return excelExportData;
};
@@ -0,0 +1,59 @@
import { z } from "zod";
import type { TableUpperProps } from "../../ruseFcltMng/fcltReg/rainReg";
export const pbnstPrfmncSttnHeadListExport: TableUpperProps[] = [
{
id: "number",
title: "No",
rowSpan: 2,
row: 0
},
{
id: "sido",
title: "시도",
rowSpan: 2,
row: 0
},
{
id: "gugun",
title: "시군구",
rowSpan: 2,
row: 0
},
{
id: "bscFctNm",
title: "시설명",
rowSpan: 2,
row: 0
},
{
id: "ruseUtztnFcltNm",
title: "재이용시설명",
rowSpan: 2,
row: 0
},
]
export const pbnstYearHeadListExport: TableUpperProps[] = [
{
title: "년도",
colSpan: 3,
row: 0
},
{
id: "total",
title: "계",
row: 1
},
{
id: "inUsage",
title: "장내용수",
row: 1
},
{
id: "outUsage",
title: "장외용수",
row: 1
},
]
@@ -0,0 +1,216 @@
import { fetchType, getFetch, postFectch } from "@/components/lib/api";
import type { TableUpperProps } from "../../common/type/header";
import { pbnstPrfmncSttnHeadListExport, pbnstYearHeadListExport } from "./headList";
import type { FcPrfType, PrfType } from "../../prfmncReg/pbnstPrfmncReg/type";
import type { pubHasuType, selectLabel } from "../../ruseFcltMng/fcltReg/pbnstReg/type";
import type { ReturnType } from "@common/business_components";
type pbnstPrfmncSttnActions = {
tableHeadMaker: (startYear: number, endYear: number) => void;
pbnstPrfmncInit: (page: string, sggOrCity: string) => void;
pbnstPrfmncSearch: (returnType: ReturnType, swtrmtFcltNm: string, fromDate: string, toDate: string) => void;
}
const pbnstPrfmncRes: PrfType[] = [];
const prfmncRes: FcPrfType[] = [];
export type pbnstPrfmncSttnState = {
pbnstPrfmncSttn: {
pbnstPrfHeadList: TableUpperProps[];
pbnstPrfmncRes: PrfType[];
prfmncRes: any[];
isInit: boolean;
rawData: any[];
selectYearList: selectLabel[]
}
}
export type pbnstPrfmncSttnType = pbnstPrfmncSttnState & pbnstPrfmncSttnActions;
export const pbnstPrfmncSttnExport: pbnstPrfmncSttnState = {
pbnstPrfmncSttn: {
pbnstPrfHeadList: [...pbnstPrfmncSttnHeadListExport],
pbnstPrfmncRes: pbnstPrfmncRes,
prfmncRes: prfmncRes,
isInit: false,
rawData: [],
selectYearList: []
}
}
const checkWrRegList = async () => {
const wrRegList = await getFetch("wr", `/reuseFc/pubDetailList`);
return wrRegList;
};
const hasuListFetch = async (page: string, sggOrCity: string) => {
const checkWrRegListRes = await checkWrRegList();
const rainRes = await postFectch(
`/prcsFclt/ruseInfo/${page ? page : 1}/10/A/${sggOrCity ? sggOrCity : "11"}/0/1/SW`,
checkWrRegListRes?.fcltCds,
fetchType.COMMON
);
const data = checkWrRegListRes.fcPrfList.map((item: FcPrfType) => {
const findData = rainRes.data.find(
(fclt: pubHasuType) =>
fclt.bscFctCd === item.pbnstRuseFcltPk.substring(0, 11)
);
return {
sido: findData?.sido,
gugun: findData?.gugun,
bscFctNm: findData?.bscFctNm,
ruseUtztnFcltNm: item.ruseUtztnFcltNm,
pbnstRuseFcltPk: item.pbnstRuseFcltPk,
};
});
return data;
}
export const pbnstPrfmncSttnActionsExport: (set: any) => pbnstPrfmncSttnActions = (
set: any
) => {
return {
tableHeadMaker: (startYear: number, endYear: number) => {
let yearHeader: TableUpperProps[] = [...pbnstPrfmncSttnHeadListExport];
const selectList = [] as unknown as selectLabel[]
for (let i = startYear; i <= endYear; i++) {
const yearHead = JSON.parse(JSON.stringify(pbnstYearHeadListExport));
if (yearHead) {
yearHead.forEach((item: { id?: string; }) => {
if (item.id) {
item.id = i + item.id;
}
})
if (yearHead[0])
yearHead[0].title = i + "년도"
}
yearHeader = [...yearHeader, ...yearHead]
selectList.push({ text: i + "년도", val: String(i) })
}
set((state: pbnstPrfmncSttnState) => {
return {
...state,
pbnstPrfmncSttn: {
...state.pbnstPrfmncSttn,
pbnstPrfHeadList: [...yearHeader],
selectYearList: selectList
},
};
});
},
pbnstPrfmncInit: async (page: string, sggOrCity: string) => {
try {
const prfmncRes = await hasuListFetch(page, sggOrCity);
return set((state: pbnstPrfmncSttnState) => ({
...state,
pbnstPrfmncSttn: {
...state.pbnstPrfmncSttn,
prfmncRes: prfmncRes,
isInit: true,
},
}));
} catch (e) {
console.log(e)
}
},
pbnstPrfmncSearch: async (returnType: ReturnType, swtrmtFcltNm: string, fromDate: string, toDate: string) => {
let searchUrl = "";
if (returnType.sigunValue !== "0") {
if (swtrmtFcltNm !== "") {
searchUrl = `/prcsFclt/info/1/20/${returnType.partValue}/${returnType.sigunValue}/0/1/SW${'/' + swtrmtFcltNm}`;
} else {
searchUrl = `/prcsFclt/info/1/20/${returnType.partValue}/${returnType.sigunValue}/0/1/SW`;
}
} else {
if (swtrmtFcltNm !== "") {
searchUrl = `/prcsFclt/info/1/20/${returnType.partValue}/${returnType.sidoValue}/0/1/SW${'/' + swtrmtFcltNm}`;
} else {
searchUrl = `/prcsFclt/info/1/20/${returnType.partValue}/${returnType.sidoValue}/0/1/SW`;
}
}
const pbnstRes = await getFetch(
fetchType.COMMON,
searchUrl
);
const bscFctCdList = pbnstRes.map((item: any) => {
return item.bscFctCd;
})
const res = await postFectch(
`/reuseFc/pubDetailList/${fromDate}/${toDate}`,
bscFctCdList,
`wr`,
)
let inUsageSum = 0;
let outUsageSum = 0;
let usageSum = 0;
let year = "";
const yearsData = []
res.data.forEach((item) => {
if (item.prfList.length === 0) {
const year = ""; // 연도 정보가 없으면 빈 문자열, 필요시 item에서 추출
const yearVal = { year: year, pbnstRuseFcltPk: item.pbnstRuseFcltPk ?? "", ruseUtztnFcltNm : item.ruseUtztnFcltNm ?? "" };
yearVal[year + "inUsage"] = 0;
yearVal[year + "outUsage"] = 0;
yearVal[year + "total"] = 0;
yearsData.push(yearVal);
}
item.prfList.forEach((acc) => {
year = acc.ym?.substring(0, 4) ?? "";
inUsageSum =
(acc.wshwtr ?? 0) +
(acc.coolUswtr ?? 0) +
(acc.cleanUswtr ?? 0) +
(acc.drwtUswtr ?? 0) +
(acc.dltnUswtr ?? 0) +
(acc.ithlRswtr ?? 0) +
(acc.ithlEtcUswtr ?? 0) +
(acc.cleanToilUswtr ?? 0) +
(acc.resn ?? 0);
outUsageSum =
(acc.lndwtr ?? 0) +
(acc.hydUswtr ?? 0) +
(acc.ugwtChr ?? 0) +
(acc.farmUswtr ?? 0) +
(acc.rvrKeepUswtr ?? 0) +
(acc.indstUswtr ?? 0);
const yearData = yearsData.find(
(yearItem) =>
yearItem.year === year &&
yearItem.pbnstRuseFcltPk == acc.pbnstRuseFcltPk
);
if (yearData) {
yearData[year + "inUsage"] += inUsageSum;
yearData[year + "outUsage"] += outUsageSum;
yearData[year + "total"] += (inUsageSum + outUsageSum);
} else {
const yearVal = { year: year, pbnstRuseFcltPk: acc.pbnstRuseFcltFk, ruseUtztnFcltNm : item.ruseUtztnFcltNm ?? "" };
yearVal[year + "inUsage"] = inUsageSum;
yearVal[year + "outUsage"] = outUsageSum;
yearVal[year + "total"] = inUsageSum + outUsageSum;
yearsData.push(yearVal);
}
});
});
const resData: any[] = []
pbnstRes.forEach((acc) => {
let data = yearsData.find((item) => item.pbnstRuseFcltPk.substring(0, 11) === acc.bscFctCd)
if (data) {
resData.push({ ...acc, ...data })
}
})
return set((state: pbnstPrfmncSttnState) => ({
...state,
pbnstPrfmncSttn: {
...state.pbnstPrfmncSttn,
prfmncRes: resData,
rawData: res.data
},
}));
}
}
}
@@ -1,178 +0,0 @@
import type { TableUpperProps } from "../rainReuseFacilityInsert";
export type TableProps = {
id: string;
title: string;
}
export type selectLabel={
text:string,
val:string
}
type publicReuseFacilityData = {
sido: string,
sigungo: string,
facilityName: string,
location: string,
locationgubun: string,
facilityCapacity: string,
yn?: string,
authoDay?: string,
area?: string,
reuse?: string,
register?: string
}
type pubMngFacData = {
mng: string,
subCo: string,
startDay: string,
endDay: string,
}
const selectLabel:selectLabel[]=[
{text:'test',val:'1'}
]
const pubFacHeadList:TableProps[] = [
{ id: "sido", title: "시도"},
{ id: "sigungo", title: "시군구"},
{ id: "facilityName", title: "시설명"},
{ id: "location", title: "위치"},
{ id: "locationgubun", title: "지역구분"},
{ id: "facilityCapacity", title: "시설용량"},
{ id: "yn", title: '재이용여부' },
{ id: "authoDay", title: '등록여부'}];
const pubMngUpHeadList:TableUpperProps[] = [
{ id: "mng", title: "운영방식"},
{ id: "subCo", title: "대행업체"},
{ id: "startDay", title: "시작일", upName:'upChangeRe' , upSequnce:1 },
{ id: "endDay", title: "종료일", upName:'upChangeRe' , upSequnce:2 },
];
const date = new Date()
const pubMngFacData:pubMngFacData[] = [
{ mng:"자체운영", subCo:"-",startDay: '2024-11-11' ,endDay:'2024-11-20'},
{ mng:"자체운영", subCo:"한국수자원공사",startDay: '2022-11-11' ,endDay:'2024-09-13'},
{ mng:"자체운영", subCo:"스타벅스",startDay: '2023-11-11' ,endDay:'2024-02-19'},
];
const publicReuseFacilityData:publicReuseFacilityData[] = [
{
sido: "서울",
sigungo: "강남구",
facilityName: "난지",
location: "경기도 고양시 덕양구 대차로 4가",
locationgubun: "500",
facilityCapacity: "800,000",
reuse: "Y",
register: "Y"
},
{
sido: "서울",
sigungo: "강남구",
facilityName: "난지",
location: "경기도 고양시 덕양구 대차로 4가",
locationgubun: "500",
facilityCapacity: "800,000",
reuse: "Y",
register: "Y"
},
{
sido: "서울",
sigungo: "강남구",
facilityName: "난지",
location: "경기도 고양시 덕양구 대차로 4가",
locationgubun: "500",
facilityCapacity: "800,000",
yn: "Y",
authoDay: "2012",
area:"123"
},
]
const erctUswtrCd:selectLabel[]=[
{text:'처리장연계',val:'1_erct'},
{text:'자체/연계',val:'2_erct'},
{text:'자체처리',val:'3_erct'},
]
const cyclCd :selectLabel[]= [
{ text: "1차", val: "1_cyc" },
{ text: "2차", val: "2_cyc" },
];
const seCd :selectLabel[] = [
{ text: "신규", val: "1_Se" },
{ text: "진행", val: "2_Se" },
];
const buseCd :selectLabel[]= [
{ text: "재정", val: "1_bus" },
{ text: "만루", val: "2_bus" },
];
const rprcsCd :selectLabel[] = [
{ text: "물리적처리", val: "1_rprc" },
{ text: "생물학적처리", val: "2_rprc" },
];
const buseMet :selectLabel[] = [
{ text: "재정", val: "1_busemet" },
{ text: "민간투자", val: "2_busemet" },
{ text: "자체", val: "3_busemet" },
];
const rprcLoCd :selectLabel[] = [
{ text: "내부", val: "1_rprc" },
{ text: "외부", val: "2_rprc" },
];
export type pubFacState = {pubFac:{
isInit: boolean;
pubFacHeadList: TableProps[];
pubMngUpHeadList:TableUpperProps[]
publicReuseFacilityData: publicReuseFacilityData[];
selectLabel:selectLabel[];
pubMngFacData:pubMngFacData[];
erctUswtrCd:selectLabel[];
cyclCd:selectLabel[];
seCd:selectLabel[];
buseCd :selectLabel[]
rprcsCd :selectLabel[]
buseMet :selectLabel[]
rprcLoCd:selectLabel[]
}}
type pubFacActions = {
decrementList: () => void
}
export type pubFacType = pubFacState & pubFacActions;
export const pubFacStateExport:pubFacState= {pubFac:{
isInit:false,
pubFacHeadList: pubFacHeadList,
pubMngUpHeadList:pubMngUpHeadList,
publicReuseFacilityData: publicReuseFacilityData,
selectLabel:selectLabel,
pubMngFacData:pubMngFacData,
erctUswtrCd:erctUswtrCd,
cyclCd:cyclCd,
seCd:seCd,
buseCd:buseCd,
rprcsCd:rprcsCd,
buseMet:buseMet,
rprcLoCd:rprcLoCd
}}
export const pubFacActionsExport:(set:any)=>pubFacActions=(set: any) => {
return {
decrementList:()=>set(
(state:pubFacState) => {
return (
{pubFac:{
pubFacheadList: state.pubFac.pubFacHeadList,
publicReuseFacilityUper:
state.pubFac.publicReuseFacilityData.slice(0, state.pubFac.publicReuseFacilityData.length - 1)
}})}
)
}
}
@@ -1,134 +0,0 @@
export type TableUpperProps = {
id: string;
title: string;
upName?: string;
upSequnce?: number;
}
export type rainFacOfType = {
sido: string,
sigungo: string,
facilityName: string,
location: string,
locationgubun: string,
firstConstructionPermission:string,
facilityCapacity: string,
buildingArea:string,
yn?: string,
permissionDay:string;
authoDay?: string,
area?: string,
reuse?: string,
register?: string,
legalTargetYn:string,
}
export const upHeadList:TableUpperProps[] = [
{ id: "sido", title: "시도"},
{ id: "sigungo", title: "시군구"},
{ id: "facilityName", title: "시설명"},
{ id: "location", title: "위치"},
{ id: "locationgubun", title: "지역구분"},
{ id: "facilityCapacity", title: "시설용량"},
{ id: "yn", title: '여부', upName:'upChangeRe' , upSequnce:1 },
{ id: "authoDay", title: '허가일',upName:'upChangeRe', upSequnce:2 },
{ id: "area", title: '면적' ,upName:'upChangeRe',upSequnce:3 }];
const rainOfObject:rainFacOfType[] = [
{
sido: "서울",
sigungo: "종로구",
facilityName: "그랑서울",
location: "종로 33",
locationgubun: "업무시설",
firstConstructionPermission : '2024-10-10',
buildingArea: "50",
facilityCapacity: "800,000",
reuse: "Y",
permissionDay:'2024-10-10',
register: "Y",
legalTargetYn:"Y"
},
{
sido: "서울",
sigungo: "종로구",
facilityName: "그랑서울",
location: "종로 33",
locationgubun: "업무시설",
firstConstructionPermission : '2024-10-10',
buildingArea: "50",
facilityCapacity: "800,000",
reuse: "Y",
permissionDay:'2024-10-10',
register: "Y",
legalTargetYn:"Y"
},
{
sido: "서울",
sigungo: "종로구",
facilityName: "그랑서울",
location: "종로 33",
locationgubun: "업무시설",
firstConstructionPermission : '2024-10-10',
buildingArea: "50",
facilityCapacity: "800,000",
reuse: "Y",
permissionDay:'2024-10-10',
register: "Y",
legalTargetYn:"Y"
},
]
export type selectArray ={
text:string,
val:string
}
export const selectClass ="w-full h-full text-2xl";
const selectHomeWater = [
{ text: '집수면', val: "1" },
{ text: "종류", val: "2" },
];
const selectYN= [
{ text: 'Y', val: "1" },
{ text: 'N', val: "2" },
];
export type rainFacState ={ rain:{
isInit: boolean;
upHeadList: TableUpperProps[];
rainOfObject: rainFacOfType[];
selectHomeWater:selectArray[];
selectYN:selectArray[];
}}
type rainFacSActions = {
decrementList: () => void
}
export type rainFacType = rainFacState & rainFacSActions;
export const rainFacStateExport:rainFacState= {rain:{
isInit:false,
upHeadList: upHeadList,
rainOfObject: rainOfObject,
selectHomeWater:selectHomeWater,
selectYN:selectYN
}}
export const rainFacActionsExport:(set:any)=>rainFacSActions=(set: any) => {
return {
decrementList:()=>set(
(state:rainFacState) => {
return (
{rain:{
upHeadList: state.rain.upHeadList,
rainOfObject:
state.rain.rainOfObject.slice(0, state.rain.rainOfObject.length - 1)
}})}
)
}
}

Some files were not shown because too many files have changed in this diff Show More