Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70db7662bb | ||
|
|
bb57ff72e7 | ||
|
|
9eef99a435 | ||
|
|
daff1610e3 | ||
|
|
5e3d263750 | ||
|
|
ced62ec0c4 |
@@ -1,17 +1,17 @@
|
|||||||
import "@/app/styles/base.css";
|
import "@/app/styles/base.css";
|
||||||
|
|
||||||
export const metadata = {
|
export const metadata = {
|
||||||
title: "유역하수도 통합 정보플랫폼",
|
title: "하수도플랫폼 통합관리시스템",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function AuthLayout({
|
export default function AuthLayout({
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<html lang="ko">
|
<html lang="ko">
|
||||||
<body>{children}</body>
|
<body>{children}</body>
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import type { Metadata } from "next";
|
|||||||
import { App } from "@/app";
|
import { App } from "@/app";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "유역하수도 통합 정보플랫폼",
|
title: "하수도플랫폼 통합관리시스템",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { cookies } from "next/headers";
|
||||||
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
|
import { COOKIE_DOMAIN, REFRESH_TOKEN } from "@/shared/config";
|
||||||
|
|
||||||
|
export async function POST() {
|
||||||
|
const cookieStore = await cookies();
|
||||||
|
cookieStore.delete({ name: REFRESH_TOKEN, domain: COOKIE_DOMAIN });
|
||||||
|
return NextResponse.json({ message: "Logged out" }, { status: 200 });
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
|
import "@/app/styles/base.css";
|
||||||
|
import "@/app/styles/components.css";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "하수도플랫폼 통합관리시스템",
|
||||||
|
description: "페이지가 존재하지 않습니다. 관리자에게 문의하여 주십시오.",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function GlobalNotFound() {
|
||||||
|
return (
|
||||||
|
<html lang="ko">
|
||||||
|
<body>
|
||||||
|
<main className="flex min-h-screen flex-col items-center justify-center bg-[#f0f4f8] px-4 py-16">
|
||||||
|
<div className="mb-16 text-center">
|
||||||
|
<h1 className="text-[3.2rem] font-bold leading-snug tracking-tight">
|
||||||
|
<span className="text-primary">하수도플랫폼 통합관리시스템</span>
|
||||||
|
에 오신 것을 환영합니다.
|
||||||
|
</h1>
|
||||||
|
<p className="mt-6 text-[2rem] text-[#666]">
|
||||||
|
오류가 발생하였습니다.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section className="card card-border flex w-full max-w-[72rem] flex-col items-center !rounded-2xl !py-16">
|
||||||
|
<Image
|
||||||
|
src="/images/magnifying-glass-with-warning.png"
|
||||||
|
alt=""
|
||||||
|
width={280}
|
||||||
|
height={280}
|
||||||
|
className="size-[28rem] object-contain"
|
||||||
|
/>
|
||||||
|
<p className="mt-4 text-[2.4rem] font-bold text-[#444]">
|
||||||
|
페이지가 존재하지 않습니다.
|
||||||
|
</p>
|
||||||
|
<p className="mt-2 text-[1.6rem] text-[#666]">
|
||||||
|
관리자에게 문의하여 주십시오
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ const nextConfig: NextConfig = {
|
|||||||
output: "standalone",
|
output: "standalone",
|
||||||
experimental: {
|
experimental: {
|
||||||
proxyTimeout: 600000,
|
proxyTimeout: 600000,
|
||||||
|
globalNotFound: true,
|
||||||
},
|
},
|
||||||
eslint: {
|
eslint: {
|
||||||
ignoreDuringBuilds: true,
|
ignoreDuringBuilds: true,
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 483 KiB After Width: | Height: | Size: 483 KiB |
@@ -92,6 +92,7 @@ async function silentRefresh(): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function logout(): Promise<void> {
|
async function logout(): Promise<void> {
|
||||||
|
await fetch("/api/auth/logout", { method: "POST" });
|
||||||
tokenManager.clearAuthToken();
|
tokenManager.clearAuthToken();
|
||||||
clearDeviceId();
|
clearDeviceId();
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import type { PageableList, PageableParams } from "@/shared/model";
|
import type { PageableList, PageableParams } from "@/shared/model";
|
||||||
|
|
||||||
export interface AuthorizationsParams extends PageableParams {
|
export interface AuthorizationsParams extends PageableParams {
|
||||||
keywordType?: string;
|
keywordType?: string;
|
||||||
keyword?: string;
|
keyword?: string;
|
||||||
authorizationName?: string;
|
authorizationName?: string;
|
||||||
|
urlPatternValue?: string;
|
||||||
httpMethodCode?: string;
|
httpMethodCode?: string;
|
||||||
useYn?: string;
|
useYn?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import { columns } from "../model/authorizations-table-columns";
|
|||||||
|
|
||||||
const DEFAULT_PARAMS = {
|
const DEFAULT_PARAMS = {
|
||||||
authorizationName: "",
|
authorizationName: "",
|
||||||
|
urlPatternValue: "",
|
||||||
httpMethodCode: "",
|
httpMethodCode: "",
|
||||||
sort: "regDt,desc",
|
sort: "regDt,desc",
|
||||||
page: 0,
|
page: 0,
|
||||||
@@ -36,6 +37,9 @@ function ModulePage() {
|
|||||||
const [authorizationName, setAuthorizationName] = useState(
|
const [authorizationName, setAuthorizationName] = useState(
|
||||||
params.authorizationName,
|
params.authorizationName,
|
||||||
);
|
);
|
||||||
|
const [urlPatternValue, setUrlPatternValue] = useState(
|
||||||
|
params.urlPatternValue,
|
||||||
|
);
|
||||||
const [httpMethodCode, setHttpMethodCode] = useState(params.httpMethodCode);
|
const [httpMethodCode, setHttpMethodCode] = useState(params.httpMethodCode);
|
||||||
|
|
||||||
const query = useQuery({
|
const query = useQuery({
|
||||||
@@ -43,6 +47,7 @@ function ModulePage() {
|
|||||||
queryFn: () =>
|
queryFn: () =>
|
||||||
AuthorizationsApi.getAuthorizationsList({
|
AuthorizationsApi.getAuthorizationsList({
|
||||||
authorizationName: params.authorizationName,
|
authorizationName: params.authorizationName,
|
||||||
|
urlPatternValue: params.urlPatternValue,
|
||||||
httpMethodCode: params.httpMethodCode,
|
httpMethodCode: params.httpMethodCode,
|
||||||
sort: params.sort,
|
sort: params.sort,
|
||||||
page: params.page,
|
page: params.page,
|
||||||
@@ -63,11 +68,12 @@ function ModulePage() {
|
|||||||
|
|
||||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setParams({ authorizationName, httpMethodCode, page: 0 });
|
setParams({ authorizationName, urlPatternValue, httpMethodCode, page: 0 });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
setAuthorizationName("");
|
setAuthorizationName("");
|
||||||
|
setUrlPatternValue("");
|
||||||
setHttpMethodCode("");
|
setHttpMethodCode("");
|
||||||
resetParams();
|
resetParams();
|
||||||
};
|
};
|
||||||
@@ -113,12 +119,23 @@ function ModulePage() {
|
|||||||
API명
|
API명
|
||||||
</Label>
|
</Label>
|
||||||
<Input
|
<Input
|
||||||
id="keyword"
|
id="authorizationName"
|
||||||
className="h-[3.2rem] w-[24rem] rounded-sm !text-[1.3rem]"
|
className="h-[3.2rem] w-[24rem] rounded-sm !text-[1.3rem]"
|
||||||
value={authorizationName}
|
value={authorizationName}
|
||||||
onChange={(e) => setAuthorizationName(e.target.value)}
|
onChange={(e) => setAuthorizationName(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Label htmlFor="urlPatternValue" className="text-label">
|
||||||
|
API URL
|
||||||
|
</Label>
|
||||||
|
<Input
|
||||||
|
id="urlPatternValue"
|
||||||
|
className="h-[3.2rem] w-[24rem] rounded-sm !text-[1.3rem]"
|
||||||
|
value={urlPatternValue}
|
||||||
|
onChange={(e) => setUrlPatternValue(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Button className="h-[3.2rem]" type="submit">
|
<Button className="h-[3.2rem]" type="submit">
|
||||||
조회
|
조회
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import dayjs from "dayjs";
|
|
||||||
import Image from "next/image";
|
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
import Image from "next/image";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
|
import { ENDPOINT } from "@/shared/config";
|
||||||
|
import { useAlertStore, useMenuStore, useMutationWrapper } from "@/shared/lib";
|
||||||
|
import { AttachmentApi } from "@/entities/attachment";
|
||||||
|
import { BoardApi } from "@/entities/board";
|
||||||
|
import { PostApi } from "@/entities/post";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Label,
|
Label,
|
||||||
@@ -12,14 +19,11 @@ import {
|
|||||||
RadioGroupItem,
|
RadioGroupItem,
|
||||||
Skeleton,
|
Skeleton,
|
||||||
} from "@common/components";
|
} from "@common/components";
|
||||||
import { AttachmentApi } from "@/entities/attachment";
|
|
||||||
import { PostApi } from "@/entities/post";
|
import { PostEvaluationApi } from "../api/post-evaluation-service";
|
||||||
import { BoardApi } from "@/entities/board";
|
|
||||||
import { ENDPOINT } from "@/shared/config";
|
|
||||||
import { useAlertStore, useMutationWrapper, useMenuStore } from "@/shared/lib";
|
|
||||||
import { PostAction } from "./post-action";
|
import { PostAction } from "./post-action";
|
||||||
import { PostComment } from "./post-comment";
|
import { PostComment } from "./post-comment";
|
||||||
import { PostEvaluationApi } from "../api/post-evaluation-service";
|
|
||||||
|
|
||||||
function Post({ bbsId, pstNo }: { bbsId: string; pstNo: string }) {
|
function Post({ bbsId, pstNo }: { bbsId: string; pstNo: string }) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -255,7 +259,9 @@ function Post({ bbsId, pstNo }: { bbsId: string; pstNo: string }) {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</PostAction>
|
</PostAction>
|
||||||
<PostComment bbsId={parseInt(bbsId)} pstNo={parseInt(pstNo)} />
|
{bbsInfo?.cmntUseYn === "Y" && (
|
||||||
|
<PostComment bbsId={parseInt(bbsId)} pstNo={parseInt(pstNo)} />
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import type { Config } from "tailwindcss";
|
import type { Config } from "tailwindcss";
|
||||||
import tailwindcssAnimate from "tailwindcss-animate";
|
import tailwindcssAnimate from "tailwindcss-animate";
|
||||||
|
|
||||||
import presetConfig from "../../tailwind.config.preset";
|
import presetConfig from "../../tailwind.config.preset";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
presets: [presetConfig],
|
presets: [presetConfig],
|
||||||
content: [
|
content: [
|
||||||
|
"./app/**/*.{js,ts,jsx,tsx}",
|
||||||
"./src/**/*.{js,ts,jsx,tsx}",
|
"./src/**/*.{js,ts,jsx,tsx}",
|
||||||
"../../packages/common/components/src/ui/**/*.{js,ts,jsx,tsx}",
|
"../../packages/common/components/src/ui/**/*.{js,ts,jsx,tsx}",
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import "@/app/styles/base.css";
|
import "@/app/styles/base.css";
|
||||||
|
|
||||||
export const metadata = {
|
export const metadata = {
|
||||||
title: "하수도통계 관리시스템",
|
title: "유역하수도 통합 정보플랫폼",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function AuthLayout({
|
export default function AuthLayout({
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ function WithBaseLayoutInner({ children }: { children: React.ReactNode }) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!getToken(CLAIM_NAME)) return;
|
if (!getToken(CLAIM_NAME)) return;
|
||||||
void statisticsApi.refreshAllCommonCodes().catch(() => {
|
void statisticsApi.refreshCommonCodes().catch(() => {
|
||||||
// 캐시 동기화 실패는 화면 진입을 막지 않음
|
// 캐시 동기화 실패는 화면 진입을 막지 않음
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
|
|
||||||
import { App } from "@/app";
|
import { App } from "@/app";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "하수도통계 관리시스템",
|
title: "유역하수도 통합 정보플랫폼",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
import { cookies } from "next/headers";
|
|
||||||
import { NextResponse } from "next/server";
|
|
||||||
|
|
||||||
import { COOKIE_DOMAIN, REFRESH_TOKEN } from "@/shared/config";
|
|
||||||
|
|
||||||
export async function POST() {
|
|
||||||
const cookieStore = await cookies();
|
|
||||||
cookieStore.delete({ name: REFRESH_TOKEN, domain: COOKIE_DOMAIN });
|
|
||||||
return NextResponse.json({ message: "Logged out" }, { status: 200 });
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
import type { Metadata } from "next";
|
|
||||||
import Image from "next/image";
|
|
||||||
|
|
||||||
import "@/app/styles/base.css";
|
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
|
||||||
title: "하수도통계 관리시스템",
|
|
||||||
description: "페이지가 존재하지 않습니다. 관리자에게 문의하여 주십시오.",
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function GlobalNotFound() {
|
|
||||||
return (
|
|
||||||
<html lang="ko">
|
|
||||||
<body>
|
|
||||||
<main className="flex min-h-screen flex-col items-center justify-center bg-[#f0f4f8] px-4 py-16">
|
|
||||||
<div className="mb-16 text-center">
|
|
||||||
<h1 className="text-[3.2rem] font-bold leading-snug tracking-tight">
|
|
||||||
<span className="text-primary">
|
|
||||||
하수도통계 관리시스템
|
|
||||||
</span>
|
|
||||||
에 오신 것을 환영합니다.
|
|
||||||
</h1>
|
|
||||||
<p className="mt-6 text-[2rem] text-[#666]">
|
|
||||||
오류가 발생하였습니다.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<section className="card card-border flex w-full max-w-[72rem] flex-col items-center !rounded-2xl !py-16">
|
|
||||||
<Image
|
|
||||||
src="/images/magnifying-glass-with-warning.png"
|
|
||||||
alt=""
|
|
||||||
width={280}
|
|
||||||
height={280}
|
|
||||||
className="size-[28rem] object-contain"
|
|
||||||
/>
|
|
||||||
<p className="mt-4 text-[2.4rem] font-bold text-[#444]">
|
|
||||||
페이지가 존재하지 않습니다.
|
|
||||||
</p>
|
|
||||||
<p className="mt-2 text-[1.6rem] text-[#666]">
|
|
||||||
관리자에게 문의하여 주십시오
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
</main>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -5,9 +5,6 @@ const subDomain =
|
|||||||
|
|
||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
output: "standalone",
|
output: "standalone",
|
||||||
experimental: {
|
|
||||||
globalNotFound: true,
|
|
||||||
},
|
|
||||||
async headers() {
|
async headers() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -41,7 +41,6 @@
|
|||||||
"chart.js": "^4.4.8",
|
"chart.js": "^4.4.8",
|
||||||
"chartjs-plugin-zoom": "^2.2.0",
|
"chartjs-plugin-zoom": "^2.2.0",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"decimal.js": "^10.6.0",
|
|
||||||
"js-cookie": "^3.0.5",
|
"js-cookie": "^3.0.5",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"lucide-react": "^0.474.0",
|
"lucide-react": "^0.474.0",
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
import { cookies } from "next/headers";
|
|
||||||
import Script from "next/script";
|
|
||||||
|
|
||||||
import "@fontsource-variable/noto-sans-kr";
|
|
||||||
|
|
||||||
import { AppProvider } from "./providers/app-provider";
|
|
||||||
|
|
||||||
import "./styles/base.css";
|
import "./styles/base.css";
|
||||||
import "./styles/components.css";
|
import "./styles/components.css";
|
||||||
|
import "@fontsource-variable/noto-sans-kr";
|
||||||
import "realgrid/dist/realgrid-style.css";
|
import "realgrid/dist/realgrid-style.css";
|
||||||
import "../components/css/DataGrid.css";
|
import "../components/css/DataGrid.css";
|
||||||
|
|
||||||
|
import { cookies } from "next/headers";
|
||||||
|
import { AppProvider } from "./providers/app-provider";
|
||||||
|
import Script from "next/script";
|
||||||
const App = async ({ children }: Readonly<{ children: React.ReactNode }>) => {
|
const App = async ({ children }: Readonly<{ children: React.ReactNode }>) => {
|
||||||
const theme = (await cookies()).get("site-theme-key");
|
const theme = (await cookies()).get("site-theme-key");
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,20 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { DndProvider } from "react-dnd";
|
import { DndProvider } from "react-dnd";
|
||||||
|
import { MultiBackend, getBackendOptions } from "@minoru/react-dnd-treeview";
|
||||||
import { ConfirmProvider } from "@frontend-opensource/use-react-hooks";
|
|
||||||
import { getBackendOptions,MultiBackend } from "@minoru/react-dnd-treeview";
|
|
||||||
import { AlertDialog as RsoneAlertDialog } from "@rsone/components";
|
|
||||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||||
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
|
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
|
||||||
|
import { ConfirmProvider } from "@frontend-opensource/use-react-hooks";
|
||||||
import { PromptProvider, StoreProvider } from "@/shared/providers";
|
|
||||||
import { AlertDialog } from "@/shared/ui/alert-dialog";
|
|
||||||
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
|
||||||
import { GlobalProgressOverlay } from "@/shared/ui/global-progress-overlay";
|
|
||||||
import { PromptDialog } from "@/shared/ui/prompt-dialog";
|
|
||||||
import { SelectPromptDialog } from "@/shared/ui/select-prompt-dialog";
|
|
||||||
import { Toaster } from "@/shared/ui/sonner";
|
|
||||||
import { AuthWrapper } from "@/entities/auth";
|
import { AuthWrapper } from "@/entities/auth";
|
||||||
import { MenuWrapper } from "@/entities/menu";
|
import { MenuWrapper } from "@/entities/menu";
|
||||||
|
import { Toaster } from "@/shared/ui/sonner";
|
||||||
|
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 { GlobalProgressOverlay } from "@/shared/ui/global-progress-overlay";
|
||||||
|
import { PromptProvider, StoreProvider } from "@/shared/providers";
|
||||||
|
import { AlertDialog as RsoneAlertDialog } from "@rsone/components";
|
||||||
|
|
||||||
const AppProvider = ({ children }: Readonly<{ children: React.ReactNode }>) => {
|
const AppProvider = ({ children }: Readonly<{ children: React.ReactNode }>) => {
|
||||||
const queryClient = new QueryClient();
|
const queryClient = new QueryClient();
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
|
||||||
|
|
||||||
import { Button } from "@common/components";
|
import { Button } from "@common/components";
|
||||||
|
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||||
|
|
||||||
interface LastYearDataButtonProps {
|
interface LastYearDataButtonProps {
|
||||||
getLastYearDataFunc: () => void;
|
getLastYearDataFunc: () => void;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
|
import { Checkbox, buttonVariants, cn } from "@common/components";
|
||||||
import type React from "react";
|
import type React from "react";
|
||||||
|
|
||||||
import { buttonVariants, Checkbox, cn } from "@common/components";
|
|
||||||
|
|
||||||
interface NotApplicableCheckButtonProp {
|
interface NotApplicableCheckButtonProp {
|
||||||
isCheck: boolean;
|
isCheck: boolean;
|
||||||
setIsCheck: React.Dispatch<React.SetStateAction<boolean>>;
|
setIsCheck: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
|
|||||||
@@ -2,17 +2,15 @@ import { Button } from "@common/components";
|
|||||||
|
|
||||||
interface SubmitButtonProps {
|
interface SubmitButtonProps {
|
||||||
submitFunc: () => void;
|
submitFunc: () => void;
|
||||||
/** 버튼 문구 (기본: 제출) */
|
|
||||||
text?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const SubmitButton = ({ submitFunc, text = "제출" }: SubmitButtonProps) => {
|
const SubmitButton = ({ submitFunc }: SubmitButtonProps) => {
|
||||||
return (
|
return (
|
||||||
<Button className="h-[3.2rem] min-w-[96px] px-4" onClick={submitFunc}>
|
<Button className="h-[3.2rem] w-[96px]" onClick={submitFunc}>
|
||||||
<i className="diveicon di-upload" />
|
<i className="diveicon di-upload" />
|
||||||
<span>{text}</span>
|
<span>제출</span>
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SubmitButton;
|
export default SubmitButton;
|
||||||
@@ -1,22 +1,5 @@
|
|||||||
@tailwind components;
|
@tailwind components;
|
||||||
|
|
||||||
/* RealGrid 기본은 white-space: nowrap → max-width만 주면 잘림. 너비 초과 시에만 줄바꿈 */
|
|
||||||
.rg-tooltip {
|
|
||||||
max-width: 60rem;
|
|
||||||
white-space: pre-line;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* RealGrid Excel export — applyDynamicStyles가 class background-color를 읽을 수 있도록 */
|
|
||||||
.rg-cell-rowtype-biz-sum {
|
|
||||||
background-color: #ffe9cf !important;
|
|
||||||
}
|
|
||||||
.rg-cell-rowtype-summary {
|
|
||||||
background-color: #feee85 !important;
|
|
||||||
}
|
|
||||||
.rg-cell-rowtype-other {
|
|
||||||
background-color: #fff7bf !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
@layer components {
|
@layer components {
|
||||||
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell {
|
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell {
|
||||||
@apply !bg-white;
|
@apply !bg-white;
|
||||||
@@ -25,15 +8,6 @@
|
|||||||
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-readonly {
|
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-readonly {
|
||||||
@apply !bg-[#f0f0f0] !text-[#666];
|
@apply !bg-[#f0f0f0] !text-[#666];
|
||||||
}
|
}
|
||||||
/* 고정 컬럼 — readonly와 동일한 화면 스타일 (엑셀 export 시 exportStyleName에서 제외) */
|
|
||||||
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-readonly,
|
|
||||||
.rg-grid .rg-body .rg-data-cell.rg-cell-readonly {
|
|
||||||
@apply !bg-[#f0f0f0] !text-[#666];
|
|
||||||
}
|
|
||||||
.rg-grid .rg-fixed-body .rg-table .rg-data-row td.rg-cell-readonly,
|
|
||||||
.rg-grid .rg-fixed-body .rg-data-row .rg-data-cell.rg-cell-readonly {
|
|
||||||
@apply !bg-[#f0f0f0] !text-[#666];
|
|
||||||
}
|
|
||||||
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-readonly.rg-cell-rowtype-curr {
|
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-readonly.rg-cell-rowtype-curr {
|
||||||
@apply !bg-white !text-[#333];
|
@apply !bg-white !text-[#333];
|
||||||
}
|
}
|
||||||
@@ -43,15 +17,6 @@
|
|||||||
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-verify-error-imr {
|
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-verify-error-imr {
|
||||||
@apply !bg-[#fff7bf] !text-[#b45309];
|
@apply !bg-[#fff7bf] !text-[#b45309];
|
||||||
}
|
}
|
||||||
/* 총계 footer 검증 오류 (commonInfo.verificationResult) */
|
|
||||||
.rg-grid .rg-footer .rg-table .rg-footer-cell.rg-cell-verify-error,
|
|
||||||
.rg-grid .rg-footers .rg-table .rg-footer-cell.rg-cell-verify-error {
|
|
||||||
@apply !bg-[#ffe6e6] !text-[#c00];
|
|
||||||
}
|
|
||||||
.rg-grid .rg-footer .rg-table .rg-footer-cell.rg-cell-verify-error-imr,
|
|
||||||
.rg-grid .rg-footers .rg-table .rg-footer-cell.rg-cell-verify-error-imr {
|
|
||||||
@apply !bg-[#fff7bf] !text-[#b45309];
|
|
||||||
}
|
|
||||||
/* 검증결과 내역: 처리여부(prcsYn 0·4 미처리 등) */
|
/* 검증결과 내역: 처리여부(prcsYn 0·4 미처리 등) */
|
||||||
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-vrf-prcs-bad {
|
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-vrf-prcs-bad {
|
||||||
@apply !font-semibold !text-[#dc2626];
|
@apply !font-semibold !text-[#dc2626];
|
||||||
@@ -434,13 +399,6 @@
|
|||||||
background-color: #ffe6e6 !important;
|
background-color: #ffe6e6 !important;
|
||||||
color: #c00 !important;
|
color: #c00 !important;
|
||||||
}
|
}
|
||||||
.rg-grid .rg-footer .rg-footer-cell.rg-cell-verify-error.rg-cell-verify-error,
|
|
||||||
.rg-grid .rg-footers .rg-footer-cell.rg-cell-verify-error.rg-cell-verify-error,
|
|
||||||
.rg-grid .rg-footer .rg-table .rg-footer-cell.rg-cell-verify-error.rg-cell-verify-error,
|
|
||||||
.rg-grid .rg-footers .rg-table .rg-footer-cell.rg-cell-verify-error.rg-cell-verify-error {
|
|
||||||
background-color: #ffe6e6 !important;
|
|
||||||
color: #c00 !important;
|
|
||||||
}
|
|
||||||
.rg-grid .rg-body .rg-data-cell.rg-cell-verify-error-imr.rg-cell-verify-error-imr,
|
.rg-grid .rg-body .rg-data-cell.rg-cell-verify-error-imr.rg-cell-verify-error-imr,
|
||||||
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-verify-error-imr.rg-cell-verify-error-imr,
|
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-verify-error-imr.rg-cell-verify-error-imr,
|
||||||
.rg-grid .rg-fixed-body .rg-data-cell.rg-cell-verify-error-imr.rg-cell-verify-error-imr,
|
.rg-grid .rg-fixed-body .rg-data-cell.rg-cell-verify-error-imr.rg-cell-verify-error-imr,
|
||||||
@@ -448,13 +406,6 @@
|
|||||||
background-color: #fff7bf !important;
|
background-color: #fff7bf !important;
|
||||||
color: #b45309 !important;
|
color: #b45309 !important;
|
||||||
}
|
}
|
||||||
.rg-grid .rg-footer .rg-footer-cell.rg-cell-verify-error-imr.rg-cell-verify-error-imr,
|
|
||||||
.rg-grid .rg-footers .rg-footer-cell.rg-cell-verify-error-imr.rg-cell-verify-error-imr,
|
|
||||||
.rg-grid .rg-footer .rg-table .rg-footer-cell.rg-cell-verify-error-imr.rg-cell-verify-error-imr,
|
|
||||||
.rg-grid .rg-footers .rg-table .rg-footer-cell.rg-cell-verify-error-imr.rg-cell-verify-error-imr {
|
|
||||||
background-color: #fff7bf !important;
|
|
||||||
color: #b45309 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* dark theme에서도 검증 오류 색을 유지하고 싶다면 동일 색 유지(가독성 우선) */
|
/* dark theme에서도 검증 오류 색을 유지하고 싶다면 동일 색 유지(가독성 우선) */
|
||||||
[data-theme="black"] .rg-grid .rg-body .rg-data-cell.rg-cell-verify-error.rg-cell-verify-error,
|
[data-theme="black"] .rg-grid .rg-body .rg-data-cell.rg-cell-verify-error.rg-cell-verify-error,
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
import { useEffect, useLayoutEffect,useRef } from "react"
|
import { useRef, useEffect, useLayoutEffect } from "react"
|
||||||
|
|
||||||
import { ValueType } from "realgrid"
|
import { ValueType } from "realgrid"
|
||||||
|
|
||||||
import RealGrid, { GridFitStyle } from "realgrid"
|
import RealGrid, { GridFitStyle } from "realgrid"
|
||||||
import { RealGridReact, RGDataColumn } from "realgrid-react"
|
import { RealGridReact, RGDataColumn } from "realgrid-react"
|
||||||
|
import type { DataGridProps, RealGridColumnInfo, GridViewWithSetColumns, FooterItemWithCallback, CellStyleCallback, CellStyleCallbackResult, CellStyleCallbackParams } from "../type/DataGrid.type"
|
||||||
import type { CellStyleCallback, CellStyleCallbackParams,CellStyleCallbackResult, DataGridProps, FooterItemWithCallback, GridViewWithSetColumns, RealGridColumnInfo } from "../type/DataGrid.type"
|
|
||||||
|
|
||||||
import { getComputedValueCallback } from "@/components/util/grid/computedFieldCallbacks"
|
import { getComputedValueCallback } from "@/components/util/grid/computedFieldCallbacks"
|
||||||
import { wrapWithFormatTruncate } from "@/components/util/grid/decimalNumber"
|
|
||||||
|
|
||||||
function mergeCellStyleCallbackResult(
|
function mergeCellStyleCallbackResult(
|
||||||
baseStyleName: string | undefined,
|
baseStyleName: string | undefined,
|
||||||
@@ -33,7 +30,7 @@ declare module "realgrid" {
|
|||||||
setOptions(options: {
|
setOptions(options: {
|
||||||
footer?: { visible?: boolean };
|
footer?: { visible?: boolean };
|
||||||
summaryMode?: 'aggregate' | 'statistical' | 'none';
|
summaryMode?: 'aggregate' | 'statistical' | 'none';
|
||||||
checkBar?: { visible?: boolean; checkableOnly?: boolean };
|
checkBar?: { visible?: boolean };
|
||||||
}): void;
|
}): void;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -50,11 +47,10 @@ type GridViewWithCheckApi = GridViewWithSetColumns & {
|
|||||||
checkItem?: (itemIndex: number, checked: boolean, exclusive?: boolean) => void;
|
checkItem?: (itemIndex: number, checked: boolean, exclusive?: boolean) => void;
|
||||||
checkRow?: (dataRow: number, checked: boolean, exclusive?: boolean) => void;
|
checkRow?: (dataRow: number, checked: boolean, exclusive?: boolean) => void;
|
||||||
checkAll?: (checked: boolean) => void;
|
checkAll?: (checked: boolean) => void;
|
||||||
setCheckable?: (itemIndex: number, checkable: boolean) => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** columnInfo → RealGrid DataField 배열 (computed → valueCallback 포함, setFields용) */
|
/** columnInfo → RealGrid DataField 배열 (computed → valueCallback 포함, setFields용) */
|
||||||
function buildFieldsFromColumns(columns: { fieldName: string; valueType?: ValueType; dataFormat?: string; computed?: import("../type/DataGrid.type").ComputedFieldConfig }[]) {
|
function buildFieldsFromColumns(columns: { fieldName: string; valueType?: ValueType; computed?: import("../type/DataGrid.type").ComputedFieldConfig }[]) {
|
||||||
return columns.map((col) => {
|
return columns.map((col) => {
|
||||||
const field: { fieldName: string; dataType: string; valueCallback?: (prod: unknown, dataRow: number, fieldName: string, fieldNames: string[], values: unknown[]) => number } = {
|
const field: { fieldName: string; dataType: string; valueCallback?: (prod: unknown, dataRow: number, fieldName: string, fieldNames: string[], values: unknown[]) => number } = {
|
||||||
fieldName: col.fieldName,
|
fieldName: col.fieldName,
|
||||||
@@ -70,7 +66,7 @@ function buildFieldsFromColumns(columns: { fieldName: string; valueType?: ValueT
|
|||||||
const hasSumOfMaxGroups = "groups" in col.computed && Array.isArray(col.computed.groups) && col.computed.groups.length > 0;
|
const hasSumOfMaxGroups = "groups" in col.computed && Array.isArray(col.computed.groups) && col.computed.groups.length > 0;
|
||||||
const hasSumPerTenThousand = col.computed.type === "sumPerTenThousand" && "numeratorFields" in col.computed && col.computed.numeratorFields.length > 0 && "denominatorField" in col.computed && Boolean(col.computed.denominatorField);
|
const hasSumPerTenThousand = col.computed.type === "sumPerTenThousand" && "numeratorFields" in col.computed && col.computed.numeratorFields.length > 0 && "denominatorField" in col.computed && Boolean(col.computed.denominatorField);
|
||||||
if (hasFields || hasNumeratorDenominator || hasMaxOfFieldAndSum || hasDifferenceOfSums || hasHalfSumOfSums || hasSumOfTwoHalfSumOfSums || hasSumOfMaxGroups || hasSumPerTenThousand) {
|
if (hasFields || hasNumeratorDenominator || hasMaxOfFieldAndSum || hasDifferenceOfSums || hasHalfSumOfSums || hasSumOfTwoHalfSumOfSums || hasSumOfMaxGroups || hasSumPerTenThousand) {
|
||||||
field.valueCallback = wrapWithFormatTruncate(getComputedValueCallback(col.computed), col.dataFormat);
|
field.valueCallback = getComputedValueCallback(col.computed) as (prod: unknown, dataRow: number, fieldName: string, fieldNames: string[], values: unknown[]) => number;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return field;
|
return field;
|
||||||
@@ -140,7 +136,6 @@ const CompactDataGrid = ({
|
|||||||
onRowClick,
|
onRowClick,
|
||||||
onItemChecked,
|
onItemChecked,
|
||||||
onItemAllChecked,
|
onItemAllChecked,
|
||||||
checkableCallback,
|
|
||||||
compactFullWidth = false,
|
compactFullWidth = false,
|
||||||
compactGridHeightClass = "h-[55vh]",
|
compactGridHeightClass = "h-[55vh]",
|
||||||
headerHeight = 60,
|
headerHeight = 60,
|
||||||
@@ -150,11 +145,9 @@ const CompactDataGrid = ({
|
|||||||
const columnsRef = useRef(columns);
|
const columnsRef = useRef(columns);
|
||||||
const rowDataRef = useRef<Record<string, string | number>[]>(rowData);
|
const rowDataRef = useRef<Record<string, string | number>[]>(rowData);
|
||||||
const cellStyleCallbackRef = useRef<CellStyleCallback | undefined>(cellStyleCallback);
|
const cellStyleCallbackRef = useRef<CellStyleCallback | undefined>(cellStyleCallback);
|
||||||
const checkableCallbackRef = useRef<DataGridProps["checkableCallback"]>(checkableCallback);
|
|
||||||
columnsRef.current = columns;
|
columnsRef.current = columns;
|
||||||
rowDataRef.current = rowData;
|
rowDataRef.current = rowData;
|
||||||
cellStyleCallbackRef.current = cellStyleCallback;
|
cellStyleCallbackRef.current = cellStyleCallback;
|
||||||
checkableCallbackRef.current = checkableCallback;
|
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
if (!cellStyleCallback || !gridRef.current?.gridView) return;
|
if (!cellStyleCallback || !gridRef.current?.gridView) return;
|
||||||
@@ -183,10 +176,8 @@ const CompactDataGrid = ({
|
|||||||
try {
|
try {
|
||||||
checkGrid.checkAll?.(false);
|
checkGrid.checkAll?.(false);
|
||||||
rowData.forEach((row, itemIndex) => {
|
rowData.forEach((row, itemIndex) => {
|
||||||
const checkable = checkableCallbackRef.current?.(row, itemIndex) ?? true;
|
|
||||||
checkGrid.setCheckable?.(itemIndex, checkable);
|
|
||||||
const checked = checkByRowFlag((row as Record<string, unknown>).__checked);
|
const checked = checkByRowFlag((row as Record<string, unknown>).__checked);
|
||||||
if (!checked || !checkable) return;
|
if (!checked) return;
|
||||||
if (checkGrid.checkItem) {
|
if (checkGrid.checkItem) {
|
||||||
checkGrid.checkItem(itemIndex, true, false);
|
checkGrid.checkItem(itemIndex, true, false);
|
||||||
return;
|
return;
|
||||||
@@ -283,7 +274,7 @@ const CompactDataGrid = ({
|
|||||||
|
|
||||||
// 헤더 체크박스 표시 여부 설정
|
// 헤더 체크박스 표시 여부 설정
|
||||||
gridView.setOptions({
|
gridView.setOptions({
|
||||||
checkBar: { visible: showHeaderCheckbox, checkableOnly: true },
|
checkBar: { visible: showHeaderCheckbox },
|
||||||
rowIndicator: { visible: false },
|
rowIndicator: { visible: false },
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -315,7 +306,6 @@ const CompactDataGrid = ({
|
|||||||
if (fixedColumns !== undefined && fixedColumns > 0) {
|
if (fixedColumns !== undefined && fixedColumns > 0) {
|
||||||
gridView.setFixedOptions({
|
gridView.setFixedOptions({
|
||||||
colCount: fixedColumns,
|
colCount: fixedColumns,
|
||||||
resizable: true,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,7 +496,6 @@ const CompactDataGrid = ({
|
|||||||
compactFullWidth,
|
compactFullWidth,
|
||||||
compactGridHeightClass,
|
compactGridHeightClass,
|
||||||
headerHeight,
|
headerHeight,
|
||||||
checkableCallback,
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 행 클릭 이벤트
|
// 행 클릭 이벤트
|
||||||
@@ -535,17 +524,6 @@ const CompactDataGrid = ({
|
|||||||
|
|
||||||
if (onItemChecked) {
|
if (onItemChecked) {
|
||||||
gridView.onItemChecked = (_grid, itemIndex, checked) => {
|
gridView.onItemChecked = (_grid, itemIndex, checked) => {
|
||||||
const row = rowDataRef.current[itemIndex];
|
|
||||||
if (
|
|
||||||
row &&
|
|
||||||
checkableCallbackRef.current &&
|
|
||||||
!checkableCallbackRef.current(row, itemIndex)
|
|
||||||
) {
|
|
||||||
if (checked) {
|
|
||||||
(_grid as GridViewWithCheckApi).checkItem?.(itemIndex, false, false);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
onItemChecked(itemIndex, checked);
|
onItemChecked(itemIndex, checked);
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,7 @@ import { type Dispatch, type MutableRefObject, type SetStateAction, useCallback,
|
|||||||
|
|
||||||
import { RealGridReact } from "realgrid-react";
|
import { RealGridReact } from "realgrid-react";
|
||||||
|
|
||||||
|
import { getUserInfo } from "../../../../../packages/common/components/src/api";
|
||||||
import { useAlertStore } from "@/shared/lib";
|
import { useAlertStore } from "@/shared/lib";
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
import type {
|
import type {
|
||||||
@@ -28,8 +29,6 @@ import {
|
|||||||
Textarea,
|
Textarea,
|
||||||
} from "@common/components";
|
} from "@common/components";
|
||||||
|
|
||||||
import { getUserInfo } from "../../../../../packages/common/components/src/api";
|
|
||||||
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
import { VerificationResultHistoryPagination } from "@/components/module/VerificationResultHistoryPagination";
|
import { VerificationResultHistoryPagination } from "@/components/module/VerificationResultHistoryPagination";
|
||||||
import type { CellStyleCallbackParams, ColumnInfo } from "@/components/type/DataGrid.type";
|
import type { CellStyleCallbackParams, ColumnInfo } from "@/components/type/DataGrid.type";
|
||||||
@@ -57,8 +56,8 @@ type ExceptionHistoryTabKey = "NV" | "IMR" | "HB";
|
|||||||
|
|
||||||
const exceptionHistoryTabs: { value: ExceptionHistoryTabKey; label: string }[] = [
|
const exceptionHistoryTabs: { value: ExceptionHistoryTabKey; label: string }[] = [
|
||||||
{ value: "NV", label: "일반검증 내역" },
|
{ value: "NV", label: "일반검증 내역" },
|
||||||
{ value: "IMR", label: "시계열 검증내역" },
|
{ value: "IMR", label: "I-MR 검증내역" },
|
||||||
{ value: "HB", label: "모집단 검증내역" },
|
{ value: "HB", label: "HB 검증내역" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const TITLE = "예외처리 내역 조회";
|
const TITLE = "예외처리 내역 조회";
|
||||||
@@ -275,7 +274,7 @@ export function ExceptionProcessingHistoryDialog({
|
|||||||
setImrPageCount(response?.data?.pageInfo?.totalPages ?? 1);
|
setImrPageCount(response?.data?.pageInfo?.totalPages ?? 1);
|
||||||
setImrPageIndex(pageIndex);
|
setImrPageIndex(pageIndex);
|
||||||
} catch {
|
} catch {
|
||||||
setErrorMessage("시계열 검증내역 조회 중 오류가 발생했습니다.");
|
setErrorMessage("I-MR 검증내역 조회 중 오류가 발생했습니다.");
|
||||||
} finally {
|
} finally {
|
||||||
setImrLoading(false);
|
setImrLoading(false);
|
||||||
}
|
}
|
||||||
@@ -294,7 +293,7 @@ export function ExceptionProcessingHistoryDialog({
|
|||||||
setHbPageCount(response?.data?.pageInfo?.totalPages ?? 1);
|
setHbPageCount(response?.data?.pageInfo?.totalPages ?? 1);
|
||||||
setHbPageIndex(pageIndex);
|
setHbPageIndex(pageIndex);
|
||||||
} catch {
|
} catch {
|
||||||
setErrorMessage("모집단 검증내역 조회 중 오류가 발생했습니다.");
|
setErrorMessage("HB 검증내역 조회 중 오류가 발생했습니다.");
|
||||||
} finally {
|
} finally {
|
||||||
setHbLoading(false);
|
setHbLoading(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
import { Button, Dialog, DialogContent, DialogHeader, DialogTitle } from "@common/components";
|
import { Button, Dialog, DialogContent, DialogHeader, DialogTitle } from "@common/components";
|
||||||
|
|
||||||
import type { SearchFormValues } from "../type/SearchForm.type";
|
|
||||||
|
|
||||||
import SidoSggFacilityNameSearchForm from "./SidoSggFacilityNameSearchForm";
|
import SidoSggFacilityNameSearchForm from "./SidoSggFacilityNameSearchForm";
|
||||||
|
import type { SearchFormValues } from "../type/SearchForm.type";
|
||||||
|
|
||||||
type GridTopActionButtonProps = {
|
type GridTopActionButtonProps = {
|
||||||
text: string;
|
text: string;
|
||||||
|
|||||||
@@ -5,11 +5,6 @@ import { useEffect, useState } from "react";
|
|||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
|
|
||||||
import { useAlertStore, useUserStore } from "@/shared/lib";
|
import { useAlertStore, useUserStore } from "@/shared/lib";
|
||||||
import {
|
|
||||||
fetchSearchCondition,
|
|
||||||
fetchSearchConditionInput,
|
|
||||||
SEARCH_CONDITION_SWR_KEY,
|
|
||||||
} from "@/shared/lib/use-search-condition-sido-list";
|
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
import type {
|
import type {
|
||||||
ApiResponse,
|
ApiResponse,
|
||||||
@@ -28,43 +23,28 @@ import {
|
|||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@common/components";
|
} from "@common/components";
|
||||||
|
|
||||||
import { doList, doNameList } from "@/components/util/column/input/DoList";
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
defaultSearchFormProps,
|
defaultSearchFormProps,
|
||||||
type SearchFormClsfCd,
|
type SearchFormClsfCd,
|
||||||
type SearchFormProps,
|
type SearchFormProps,
|
||||||
type SearchFormValues,
|
type SearchFormValues,
|
||||||
} from "../type/SearchForm.type";
|
} from "../type/SearchForm.type";
|
||||||
|
import { doList } from "../util/column/input/DoList";
|
||||||
|
|
||||||
function isDoListBsnm(bsnmCd: string | undefined): boolean {
|
const getSidoListFetcher = async (
|
||||||
return Boolean(bsnmCd && doList.includes(bsnmCd));
|
key: [string, string],
|
||||||
}
|
): Promise<ApiResponse<SearchCondition>> => {
|
||||||
|
return statisticsApi.getSidoList({ instSeCd: key[1] });
|
||||||
function isDoSido(sido?: { bsnmCd?: string; sido?: string }): boolean {
|
};
|
||||||
if (!sido) return false;
|
|
||||||
if (isDoListBsnm(sido.bsnmCd)) return true;
|
|
||||||
return Boolean(sido.sido && doNameList.includes(sido.sido));
|
|
||||||
}
|
|
||||||
|
|
||||||
function isAllGugunValue(gugun: string | undefined): boolean {
|
|
||||||
const value = (gugun ?? "").trim();
|
|
||||||
return !value || value === "ALL" || value === "전체";
|
|
||||||
}
|
|
||||||
|
|
||||||
function firstConcreteSgg(list: Sgg[] | undefined): Sgg | undefined {
|
|
||||||
return (list ?? []).find((sgg) => !isAllGugunValue(sgg.gugun));
|
|
||||||
}
|
|
||||||
|
|
||||||
const getSggListFetcher = async (
|
const getSggListFetcher = async (
|
||||||
key: [string, string, string, "Y" | "N"],
|
key: [string, string, string, string],
|
||||||
): Promise<ApiResponse<Sgg[]>> => {
|
): Promise<ApiResponse<Sgg[]>> => {
|
||||||
const [kind, sidoName, instSeCd, gugunSkipYn] = key;
|
const gugunSkipYn = doList.includes(key[3]) ? "N" : "Y";
|
||||||
const params = { instSeCd, gugunSkipYn };
|
return statisticsApi.getSggList(key[1], {
|
||||||
if (kind === "sgg-all") {
|
instSeCd: key[2],
|
||||||
return statisticsApi.getSggAllList(sidoName, params);
|
gugunSkipYn,
|
||||||
}
|
});
|
||||||
return statisticsApi.getSggList(sidoName, params);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function buildSearchFormValues(
|
function buildSearchFormValues(
|
||||||
@@ -79,15 +59,9 @@ function buildSearchFormValues(
|
|||||||
: "ALL";
|
: "ALL";
|
||||||
|
|
||||||
if (d?.sido) {
|
if (d?.sido) {
|
||||||
const sidoItem = sidoList?.data?.sidoList?.find(
|
|
||||||
(item) => item.sido === d.sido,
|
|
||||||
);
|
|
||||||
const gugun =
|
|
||||||
d.gugun ||
|
|
||||||
(sidoItem && !isDoSido(sidoItem) ? "ALL" : "");
|
|
||||||
return {
|
return {
|
||||||
sido: d.sido,
|
sido: d.sido,
|
||||||
gugun,
|
gugun: d.gugun || "",
|
||||||
year: d.year || defaultYear.toString(),
|
year: d.year || defaultYear.toString(),
|
||||||
order: d.order || "",
|
order: d.order || "",
|
||||||
fctName: d.fctName || "",
|
fctName: d.fctName || "",
|
||||||
@@ -99,28 +73,12 @@ function buildSearchFormValues(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.defaultRegionAll) {
|
|
||||||
return {
|
|
||||||
sido: "ALL",
|
|
||||||
gugun: "ALL",
|
|
||||||
year: d?.year || defaultYear.toString(),
|
|
||||||
order: d?.order || "",
|
|
||||||
fctName: d?.fctName || "",
|
|
||||||
bsnmCd: "",
|
|
||||||
isDetail: false,
|
|
||||||
isSummary: d?.isSummary || "",
|
|
||||||
clsfCd: initialClsfCd,
|
|
||||||
capacityGbn: d?.capacityGbn || "ALL",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const first = sidoList?.data?.sidoList?.[0];
|
const first = sidoList?.data?.sidoList?.[0];
|
||||||
const useFirstSido = (props.sido ?? defaultSearchFormProps.sido) && first;
|
const useFirstSido = (props.sido ?? defaultSearchFormProps.sido) && first;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
sido: useFirstSido ? first.sido : "",
|
sido: useFirstSido ? first.sido : "",
|
||||||
gugun:
|
gugun: "",
|
||||||
useFirstSido && first && !isDoSido(first) ? "ALL" : "",
|
|
||||||
year: d?.year || defaultYear.toString(),
|
year: d?.year || defaultYear.toString(),
|
||||||
order: d?.order || "",
|
order: d?.order || "",
|
||||||
fctName: d?.fctName || "",
|
fctName: d?.fctName || "",
|
||||||
@@ -144,12 +102,10 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
|||||||
|
|
||||||
const currentYear = new Date().getFullYear();
|
const currentYear = new Date().getFullYear();
|
||||||
const defaultYear = currentYear - 1;
|
const defaultYear = currentYear - 1;
|
||||||
const isInput = Boolean(props.isInput);
|
|
||||||
const sidoListKind = isInput ? "input" : "default";
|
|
||||||
|
|
||||||
const { data: sidoList } = useSWR<ApiResponse<SearchCondition>>(
|
const { data: sidoList } = useSWR<ApiResponse<SearchCondition>>(
|
||||||
SEARCH_CONDITION_SWR_KEY(instSeCd, sidoListKind),
|
["sido-list", instSeCd],
|
||||||
isInput ? fetchSearchConditionInput : fetchSearchCondition,
|
getSidoListFetcher,
|
||||||
{
|
{
|
||||||
revalidateOnFocus: false,
|
revalidateOnFocus: false,
|
||||||
revalidateOnReconnect: false,
|
revalidateOnReconnect: false,
|
||||||
@@ -176,7 +132,6 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
|||||||
|
|
||||||
// 최초 진입만 시도 API가 늦게 오는 경우
|
// 최초 진입만 시도 API가 늦게 오는 경우
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (props.defaultRegionAll) return;
|
|
||||||
if (props.defaultValues?.sido) return;
|
if (props.defaultValues?.sido) return;
|
||||||
const first = sidoList?.data?.sidoList?.[0];
|
const first = sidoList?.data?.sidoList?.[0];
|
||||||
if (!first || !mergedProps.sido) return;
|
if (!first || !mergedProps.sido) return;
|
||||||
@@ -184,33 +139,17 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
|||||||
prev.sido
|
prev.sido
|
||||||
? prev
|
? prev
|
||||||
: {
|
: {
|
||||||
...prev,
|
...prev,
|
||||||
sido: first.sido,
|
sido: first.sido,
|
||||||
gugun: isDoSido(first) ? "" : "ALL",
|
gugun: "",
|
||||||
bsnmCd: first.bsnmCd,
|
bsnmCd: first.bsnmCd,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}, [
|
}, [sidoList, props.defaultValues?.sido, mergedProps.sido]);
|
||||||
sidoList,
|
|
||||||
props.defaultValues?.sido,
|
|
||||||
props.defaultRegionAll,
|
|
||||||
mergedProps.sido,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const selectedSido = sidoList?.data?.sidoList?.find(
|
const sggKey: [string, string, string, string] | null =
|
||||||
(item) => item.sido === values.sido,
|
values.sido && values.sido !== "ALL"
|
||||||
);
|
? ["sgg-list", values.sido, instSeCd, values.bsnmCd || ""]
|
||||||
const gugunSkipYn = selectedSido?.gugunSkipYn ?? "Y";
|
|
||||||
const useSggAllList =
|
|
||||||
gugunSkipYn === "N" && !isDoListBsnm(selectedSido?.bsnmCd);
|
|
||||||
const sggKey: [string, string, string, "Y" | "N"] | null =
|
|
||||||
values.sido && values.sido !== "ALL" && sidoList?.data
|
|
||||||
? [
|
|
||||||
useSggAllList ? "sgg-all" : "sgg-list",
|
|
||||||
values.sido,
|
|
||||||
instSeCd,
|
|
||||||
gugunSkipYn,
|
|
||||||
]
|
|
||||||
: null;
|
: null;
|
||||||
const { data: sggList } = useSWR<ApiResponse<Sgg[]>>(
|
const { data: sggList } = useSWR<ApiResponse<Sgg[]>>(
|
||||||
sggKey,
|
sggKey,
|
||||||
@@ -224,60 +163,39 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
|||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
if (data.status !== "success") {
|
if (data.status !== "success") {
|
||||||
alert(`시군구 목록을 불러오는데 실패했습니다.
|
alert(`시군구 목록을 불러오는데 실패했습니다.
|
||||||
새로고침 후 다시 시도해주세요.`);
|
새로고침 후 다시 시도해주세요.`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onError: () => {
|
onError: () => {
|
||||||
alert(`시군구 목록을 불러오는데 실패했습니다.
|
alert(`시군구 목록을 불러오는데 실패했습니다.
|
||||||
새로고침 후 다시 시도해주세요.`);
|
새로고침 후 다시 시도해주세요.`);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
const sggOptions = sggList?.data ?? [];
|
const sggOptions = sggList?.data ?? [];
|
||||||
const isDoSelected = isDoSido(selectedSido);
|
|
||||||
const firstConcreteSggOption = firstConcreteSgg(sggOptions);
|
|
||||||
// 도: 빈 값일 때만 첫 시군구로 보이게. ALL은 사용자가 고른 전체 유지
|
|
||||||
const gugunSelectValue =
|
|
||||||
isDoSelected && !values.gugun
|
|
||||||
? (firstConcreteSggOption?.gugun ?? undefined)
|
|
||||||
: values.gugun || undefined;
|
|
||||||
|
|
||||||
// 도: 초기/시도 변경(빈 값)만 첫 시군구. 전체(ALL)는 유지. 그 외: 전체
|
// 시도 설정 후 시군구 목록이 오면 첫 번째 항목 자동 선택
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!mergedProps.gugun) return;
|
if (!mergedProps.gugun) return;
|
||||||
if (props.defaultRegionAll) return;
|
if (props.defaultValues?.gugun) return;
|
||||||
if (!values.sido || values.sido === "ALL") return;
|
if (!values.sido || values.sido === "ALL") return;
|
||||||
if (!selectedSido) return;
|
|
||||||
|
|
||||||
if (!isDoSelected) {
|
const firstSgg = sggList?.data?.[0];
|
||||||
setValues((prev) => {
|
if (!firstSgg) return;
|
||||||
if (prev.gugun) return prev;
|
|
||||||
return {
|
|
||||||
...prev,
|
|
||||||
gugun: "ALL",
|
|
||||||
bsnmCd: selectedSido.bsnmCd || prev.bsnmCd,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!firstConcreteSggOption) return;
|
|
||||||
|
|
||||||
setValues((prev) => {
|
setValues((prev) => {
|
||||||
if (prev.gugun) return prev;
|
if (prev.gugun) return prev;
|
||||||
return {
|
return {
|
||||||
...prev,
|
...prev,
|
||||||
gugun: firstConcreteSggOption.gugun,
|
gugun: firstSgg.gugun,
|
||||||
bsnmCd: firstConcreteSggOption.bsnmCd,
|
bsnmCd: firstSgg.bsnmCd,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}, [
|
}, [
|
||||||
firstConcreteSggOption,
|
sggList,
|
||||||
isDoSelected,
|
|
||||||
mergedProps.gugun,
|
|
||||||
props.defaultRegionAll,
|
|
||||||
selectedSido,
|
|
||||||
values.sido,
|
values.sido,
|
||||||
|
mergedProps.gugun,
|
||||||
|
props.defaultValues?.gugun,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||||
@@ -291,17 +209,12 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSidoChange = (value: string) => {
|
const handleSidoChange = (value: string) => {
|
||||||
const selected =
|
const selectedBsnm =
|
||||||
value === "ALL"
|
sidoList?.data?.sidoList?.find((v) => v.sido === value)?.bsnmCd || "";
|
||||||
? undefined
|
|
||||||
: sidoList?.data?.sidoList?.find((v) => v.sido === value);
|
|
||||||
const selectedBsnm = selected?.bsnmCd || "";
|
|
||||||
const gugunAll =
|
|
||||||
props.defaultRegionAll || value === "ALL" || !isDoSido(selected);
|
|
||||||
setValues((prev) => ({
|
setValues((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
sido: value,
|
sido: value,
|
||||||
gugun: gugunAll ? "ALL" : "",
|
gugun: "",
|
||||||
bsnmCd: selectedBsnm,
|
bsnmCd: selectedBsnm,
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
@@ -311,7 +224,7 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
|||||||
const selectedBsnm =
|
const selectedBsnm =
|
||||||
value === "ALL"
|
value === "ALL"
|
||||||
? sidoList?.data?.sidoList?.find((v) => v.sido === values.sido)
|
? sidoList?.data?.sidoList?.find((v) => v.sido === values.sido)
|
||||||
?.bsnmCd || ""
|
?.bsnmCd || ""
|
||||||
: listForBsnm.find((v) => v.gugun === value)?.bsnmCd || "";
|
: listForBsnm.find((v) => v.gugun === value)?.bsnmCd || "";
|
||||||
|
|
||||||
setValues((prev) => ({
|
setValues((prev) => ({
|
||||||
@@ -361,7 +274,7 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
|||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Label className="text-label">시군구</Label>
|
<Label className="text-label">시군구</Label>
|
||||||
<Select
|
<Select
|
||||||
value={gugunSelectValue}
|
value={values.gugun}
|
||||||
onValueChange={handleSggChange}
|
onValueChange={handleSggChange}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="w-[12rem]">
|
<SelectTrigger className="w-[12rem]">
|
||||||
@@ -464,23 +377,16 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
|||||||
<SelectValue placeholder="전체"></SelectValue>
|
<SelectValue placeholder="전체"></SelectValue>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="ALL">전체</SelectItem>
|
<SelectItem value='ALL'>전체</SelectItem>
|
||||||
<SelectItem value="500톤이상">
|
<SelectItem value='500톤이상'>500톤이상</SelectItem>
|
||||||
500톤이상
|
<SelectItem value='500톤미만'>500톤미만</SelectItem>
|
||||||
</SelectItem>
|
|
||||||
<SelectItem value="500톤미만">
|
|
||||||
500톤미만
|
|
||||||
</SelectItem>
|
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{mergedProps.isDetail && (
|
{mergedProps.isDetail && (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Label
|
<Label className="text-label cursor-pointer" htmlFor="isDetail">
|
||||||
className="cursor-pointer text-label"
|
|
||||||
htmlFor="isDetail"
|
|
||||||
>
|
|
||||||
세부 데이터 포함
|
세부 데이터 포함
|
||||||
</Label>
|
</Label>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
@@ -497,11 +403,7 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
|||||||
)}
|
)}
|
||||||
{mergedProps.isSummary && (
|
{mergedProps.isSummary && (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Label
|
<Label className="text-label cursor-pointer">
|
||||||
className="cursor-pointer text-label"
|
|
||||||
title="시·군·구 및 읍·면·동 변경에 따라 인구 및 관로 등 공표된 통계수치와 일부 상이할 수 있으니 유의 바랍니다."
|
|
||||||
>
|
|
||||||
<i className="diveicon di-exclamation-circle mr-1" />
|
|
||||||
요약표 포함
|
요약표 포함
|
||||||
</Label>
|
</Label>
|
||||||
<Select
|
<Select
|
||||||
@@ -514,17 +416,11 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
|||||||
<SelectValue placeholder="선택 안함"></SelectValue>
|
<SelectValue placeholder="선택 안함"></SelectValue>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="ALL">
|
<SelectItem value="ALL">선택 안함</SelectItem>
|
||||||
선택 안함
|
{[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((i) => (
|
||||||
</SelectItem>
|
<SelectItem value={i.toString()} key={i.toString()}>{`${i}개년`}</SelectItem>
|
||||||
{[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(
|
))
|
||||||
(i) => (
|
}
|
||||||
<SelectItem
|
|
||||||
value={i.toString()}
|
|
||||||
key={i.toString()}
|
|
||||||
>{`${i}개년`}</SelectItem>
|
|
||||||
),
|
|
||||||
)}
|
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
@@ -559,9 +455,7 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
|||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
<Button className="h-[3.2rem] w-[96px]" type="submit">
|
<Button className="h-[3.2rem] w-[96px]" type="submit">
|
||||||
{props.searchButtonText
|
{props.searchButtonText ? props.searchButtonText : '조회'}
|
||||||
? props.searchButtonText
|
|
||||||
: "조회"}
|
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,42 +1,41 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
import { ValueType } from "realgrid";
|
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
|
import { ValueType } from "realgrid";
|
||||||
|
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Input,
|
||||||
|
Label,
|
||||||
|
Select,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectValue,
|
||||||
|
LoadingWithAnimation,
|
||||||
|
} from "@common/components";
|
||||||
|
import CompactDataGrid from "./CompactDataGrid";
|
||||||
|
import SaveButton from "../button/SaveButton";
|
||||||
|
|
||||||
import { useAlertStore } from "@/shared/lib";
|
import { useAlertStore } from "@/shared/lib";
|
||||||
import { statisticsInputSewPipeApiService } from "@/entities/statistics/api/input/statistics-sewage-pipe-input-service";
|
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
import { isGugunRequiredSido } from "@/entities/statistics";
|
|
||||||
import type {
|
|
||||||
SeweragePipeFacilitiesListRequest,
|
|
||||||
SeweragePipeFacilityAdminAreaListRequest,
|
|
||||||
SeweragePipeFactConnectionSaveItem,
|
|
||||||
SeweragePipeFactConnectionSaveRequest,
|
|
||||||
} from "@/entities/statistics/model/input/statistics-sewage-pipe-input-interface";
|
|
||||||
import type {
|
import type {
|
||||||
ApiResponse,
|
ApiResponse,
|
||||||
SearchCondition,
|
SearchCondition,
|
||||||
Sgg,
|
Sgg,
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
} from "@/entities/statistics/model/statistics-interface";
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
Input,
|
|
||||||
Label,
|
|
||||||
LoadingWithAnimation,
|
|
||||||
Select,
|
|
||||||
SelectContent,
|
|
||||||
SelectItem,
|
|
||||||
SelectTrigger,
|
|
||||||
SelectValue,
|
|
||||||
} from "@common/components";
|
|
||||||
|
|
||||||
import { getUserInfo } from "../../../../../packages/common/components/src/api";
|
|
||||||
import type { ColumnInfo } from "../type/DataGrid.type";
|
import type { ColumnInfo } from "../type/DataGrid.type";
|
||||||
|
import type {
|
||||||
|
SeweragePipeFacilitiesListRequest,
|
||||||
|
SeweragePipeFacilityAdminAreaListRequest,
|
||||||
|
SeweragePipeFactConnectionSaveRequest,
|
||||||
|
SeweragePipeFactConnectionSaveItem,
|
||||||
|
} from "@/entities/statistics/model/input/statistics-sewage-pipe-input-interface";
|
||||||
|
import { statisticsInputSewPipeApiService } from "@/entities/statistics/api/input/statistics-sewage-pipe-input-service";
|
||||||
import type { SearchFormValues } from "../type/SearchForm.type";
|
import type { SearchFormValues } from "../type/SearchForm.type";
|
||||||
|
import { doNameList } from "../util/column/input/DoList";
|
||||||
import CompactDataGrid from "./CompactDataGrid";
|
import { getUserInfo } from "../../../../../packages/common/components/src/api";
|
||||||
|
|
||||||
/** 다이얼로그 좌측: 처리시설 정보 (순번 없음) */
|
/** 다이얼로그 좌측: 처리시설 정보 (순번 없음) */
|
||||||
const treatmentFacilityColumnInfo: ColumnInfo = {
|
const treatmentFacilityColumnInfo: ColumnInfo = {
|
||||||
@@ -115,9 +114,9 @@ const getSidoListFetcher = async (): Promise<ApiResponse<SearchCondition>> => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getSggAllListFetcher = async (
|
const getSggAllListFetcher = async (
|
||||||
key: [string, string, "Y" | "N"],
|
key: [string, string],
|
||||||
): Promise<ApiResponse<Sgg[]>> => {
|
): Promise<ApiResponse<Sgg[]>> => {
|
||||||
return statisticsApi.getSggList(key[1], { gugunSkipYn: key[2] });
|
return statisticsApi.getSggList(key[1]);
|
||||||
};
|
};
|
||||||
|
|
||||||
type SidoSggFacilityNameSearchFormProps = {
|
type SidoSggFacilityNameSearchFormProps = {
|
||||||
@@ -183,16 +182,9 @@ const SidoSggFacilityNameSearchForm = ({
|
|||||||
Record<string, string | number> | null
|
Record<string, string | number> | null
|
||||||
>(null);
|
>(null);
|
||||||
const didAutoFetchRef = useRef(false);
|
const didAutoFetchRef = useRef(false);
|
||||||
const isSavingConnectionRef = useRef(false);
|
|
||||||
|
|
||||||
const selectedSido = sidoList?.data?.sidoList?.find(
|
const sggKey: [string, string] | null =
|
||||||
(item) => item.sido === sido,
|
sido && sido !== "ALL" ? ["sgg-all", sido] : null;
|
||||||
);
|
|
||||||
const gugunSkipYn = selectedSido?.gugunSkipYn ?? "Y";
|
|
||||||
const sggKey: [string, string, "Y" | "N"] | null =
|
|
||||||
sido && sido !== "ALL" && sidoList?.data
|
|
||||||
? ["sgg-all", sido, gugunSkipYn]
|
|
||||||
: null;
|
|
||||||
const { data: sggList } = useSWR<ApiResponse<Sgg[]>>(
|
const { data: sggList } = useSWR<ApiResponse<Sgg[]>>(
|
||||||
sggKey,
|
sggKey,
|
||||||
getSggAllListFetcher,
|
getSggAllListFetcher,
|
||||||
@@ -305,11 +297,7 @@ const SidoSggFacilityNameSearchForm = ({
|
|||||||
swtrmtFcltCd,
|
swtrmtFcltCd,
|
||||||
sewerBzmnCd: initialSearchValues?.bsnmCd || '',
|
sewerBzmnCd: initialSearchValues?.bsnmCd || '',
|
||||||
ctpvNm: initialSidoValue || '',
|
ctpvNm: initialSidoValue || '',
|
||||||
...(isGugunRequiredSido(sidoList?.data?.sidoList, {
|
...(doNameList.includes(initialSidoValue) ? { sggNm: initialGugunValue } : {}),
|
||||||
sido: initialSidoValue,
|
|
||||||
})
|
|
||||||
? { sggNm: initialGugunValue }
|
|
||||||
: {}),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -341,213 +329,119 @@ const SidoSggFacilityNameSearchForm = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const canEditFactConnection = async (): Promise<boolean> => {
|
const handleSaveAdminRegions = async () => {
|
||||||
const statusCodeResponse = await statisticsApi.CheckStatusCode({
|
const statusCodeResponse = await statisticsApi.CheckStatusCode({
|
||||||
sewerBzmnCd: initialSearchValues?.bsnmCd?.trim() ?? "",
|
sewerBzmnCd: initialSearchValues?.bsnmCd?.trim() ?? "",
|
||||||
statsCd: "ST00020002",
|
statsCd: 'ST00020002',
|
||||||
statsYr: statsYr?.trim() ?? "",
|
statsYr: statsYr?.trim() ?? ''
|
||||||
});
|
});
|
||||||
|
|
||||||
if (statusCodeResponse.status === "success") {
|
if (statusCodeResponse.status === 'success') {
|
||||||
if (!["0", "1", "4"].includes(statusCodeResponse.data)) {
|
if (!['0', '1', '4'].includes(statusCodeResponse.data)) {
|
||||||
const codeName =
|
const codeName = statusCodeResponse.data === '2' ? '제출' : (statusCodeResponse.data === '3' ? '승인' : '검증중');
|
||||||
statusCodeResponse.data === "2"
|
alert(`시설별 설치 현황 데이터가 ${codeName} 상태일 때는 처리 시설 정보를 변경할 수 없습니다.`);
|
||||||
? "제출"
|
return;
|
||||||
: statusCodeResponse.data === "3"
|
}
|
||||||
? "승인"
|
} else {
|
||||||
: "검증중";
|
alert('오류가 발생했습니다.\n관리자에게 문의하세요')
|
||||||
alert(
|
|
||||||
`시설별 설치 현황 데이터가 ${codeName} 상태일 때는 처리 시설 정보를 변경할 수 없습니다.`,
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
alert("오류가 발생했습니다.\n관리자에게 문의하세요");
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const persistFactConnection = async (
|
|
||||||
saveList: SeweragePipeFactConnectionSaveItem[],
|
|
||||||
deleteList: string[],
|
|
||||||
): Promise<boolean> => {
|
|
||||||
if (!statsYr?.trim()) {
|
if (!statsYr?.trim()) {
|
||||||
alert("상단에서 통계연도로 조회한 뒤 이용해 주세요.");
|
alert("상단에서 통계연도로 조회한 뒤 이용해 주세요.");
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
if (!selectedFacilityRow) {
|
if (!selectedFacilityRow) {
|
||||||
alert("처리시설을 먼저 선택해주세요.");
|
alert("처리시설을 먼저 선택해주세요.");
|
||||||
return false;
|
return;
|
||||||
}
|
|
||||||
if (saveList.length === 0 && deleteList.length === 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!(await canEditFactConnection())) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
const hasChanged = adminRegionRows.some(
|
||||||
setIsLoading(true);
|
(row) =>
|
||||||
const userInfo = await getUserInfo();
|
(row.__checked === "1" && row.isConnection !== "1") ||
|
||||||
const request: SeweragePipeFactConnectionSaveRequest = {
|
(row.__checked !== "1" && row.isConnection === "1"),
|
||||||
ctpvNm: String(selectedFacilityRow.ctpvNm ?? ""),
|
);
|
||||||
sggNm: String(selectedFacilityRow.sggNm ?? ""),
|
|
||||||
fcltSn: String(selectedFacilityRow.fcltSn ?? ""),
|
|
||||||
statsYr: statsYr.trim(),
|
|
||||||
swtrmtFcltCd: String(selectedFacilityRow.fcltCd ?? ""),
|
|
||||||
swtrmtFcltNm: String(selectedFacilityRow.fcltNm ?? ""),
|
|
||||||
prcsFcltCpct: Number(selectedFacilityRow.fcltCpct ?? 0),
|
|
||||||
sewerBzmnCd: initialSearchValues?.bsnmCd?.trim() ?? "",
|
|
||||||
userId: userInfo.userUnqId,
|
|
||||||
saveList,
|
|
||||||
deleteList,
|
|
||||||
};
|
|
||||||
|
|
||||||
const response =
|
const saveList: SeweragePipeFactConnectionSaveItem[] = adminRegionRows
|
||||||
await statisticsInputSewPipeApiService.saveFactConnection(
|
.filter((row) => row.__checked === "1")
|
||||||
request,
|
.map((row) => ({
|
||||||
|
admdstCd: String(row.admdstCd ?? ""),
|
||||||
|
admdstNm: String(row.emdNm ?? ""),
|
||||||
|
}))
|
||||||
|
.filter((row) => row.admdstCd && row.admdstNm);
|
||||||
|
|
||||||
|
const deleteList = adminRegionRows
|
||||||
|
.filter((row) => row.__checked !== "1" && row.isConnection === "1")
|
||||||
|
.map((row) => String(row.admdstCd ?? ""))
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
if (!hasChanged) {
|
||||||
|
alert("변경된 연결 정보가 없습니다.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const run = async () => {
|
||||||
|
try {
|
||||||
|
setIsLoading(true);
|
||||||
|
const userInfo = await getUserInfo();
|
||||||
|
const request: SeweragePipeFactConnectionSaveRequest = {
|
||||||
|
ctpvNm: String(selectedFacilityRow.ctpvNm ?? ""),
|
||||||
|
sggNm: String(selectedFacilityRow.sggNm ?? ""),
|
||||||
|
fcltSn: String(selectedFacilityRow.fcltSn ?? ""),
|
||||||
|
statsYr: statsYr.trim(),
|
||||||
|
swtrmtFcltCd: String(selectedFacilityRow.fcltCd ?? ""),
|
||||||
|
swtrmtFcltNm: String(selectedFacilityRow.fcltNm ?? ""),
|
||||||
|
prcsFcltCpct: Number(selectedFacilityRow.fcltCpct ?? 0),
|
||||||
|
sewerBzmnCd: initialSearchValues?.bsnmCd?.trim() ?? "",
|
||||||
|
userId: userInfo.userUnqId,
|
||||||
|
saveList,
|
||||||
|
deleteList,
|
||||||
|
};
|
||||||
|
|
||||||
|
const response =
|
||||||
|
await statisticsInputSewPipeApiService.saveFactConnection(
|
||||||
|
request,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.status !== "success") {
|
||||||
|
alert(response.message ?? "연결관계 저장에 실패했습니다.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setAdminRegionRows((prev) =>
|
||||||
|
prev.map((row) => ({
|
||||||
|
...row,
|
||||||
|
isConnection: row.__checked === "1" ? "1" : "0",
|
||||||
|
})),
|
||||||
);
|
);
|
||||||
|
await onSaveSuccess?.();
|
||||||
if (response.status !== "success") {
|
alert("저장되었습니다.");
|
||||||
alert(response.message ?? "연결관계 저장에 실패했습니다.");
|
} catch {
|
||||||
return false;
|
alert("연결관계 저장 중 오류가 발생했습니다.");
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
await onSaveSuccess?.();
|
void run();
|
||||||
return true;
|
|
||||||
} catch {
|
|
||||||
alert("연결관계 저장 중 오류가 발생했습니다.");
|
|
||||||
return false;
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const syncConnectionFlags = (
|
const handleAdminRegionItemChecked = (
|
||||||
rows: Record<string, string | number>[],
|
|
||||||
): Record<string, string | number>[] =>
|
|
||||||
rows.map((row) => ({
|
|
||||||
...row,
|
|
||||||
isConnection: row.__checked === "1" ? "1" : "0",
|
|
||||||
}));
|
|
||||||
|
|
||||||
const revertCheckedToConnection = (
|
|
||||||
rows: Record<string, string | number>[],
|
|
||||||
): Record<string, string | number>[] =>
|
|
||||||
rows.map((row) => ({
|
|
||||||
...row,
|
|
||||||
__checked: row.isConnection === "1" ? "1" : "0",
|
|
||||||
}));
|
|
||||||
|
|
||||||
const handleAdminRegionItemChecked = async (
|
|
||||||
itemIndex: number,
|
itemIndex: number,
|
||||||
checked: boolean,
|
checked: boolean,
|
||||||
) => {
|
) => {
|
||||||
if (isSavingConnectionRef.current) {
|
|
||||||
// RealGrid가 이미 토글했을 수 있어 __checked 기준으로 재동기화
|
|
||||||
setAdminRegionRows((prev) => prev.map((row) => ({ ...row })));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const target = adminRegionRows[itemIndex];
|
|
||||||
if (!target) return;
|
|
||||||
|
|
||||||
const nextChecked = checked ? "1" : "0";
|
|
||||||
const prevChecked = target.isConnection === "1" ? "1" : "0";
|
|
||||||
|
|
||||||
setAdminRegionRows((prev) =>
|
setAdminRegionRows((prev) =>
|
||||||
prev.map((row, idx) =>
|
prev.map((row, idx) =>
|
||||||
idx === itemIndex
|
idx === itemIndex
|
||||||
? { ...row, __checked: nextChecked }
|
? { ...row, __checked: checked ? "1" : "0" }
|
||||||
: row,
|
: row,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
// 서버 상태와 동일하면 API 호출 없이 UI만 반영
|
|
||||||
if (nextChecked === prevChecked) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const saveList: SeweragePipeFactConnectionSaveItem[] =
|
|
||||||
checked
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
admdstCd: String(target.admdstCd ?? ""),
|
|
||||||
admdstNm: String(target.emdNm ?? ""),
|
|
||||||
},
|
|
||||||
].filter((row) => row.admdstCd && row.admdstNm)
|
|
||||||
: [];
|
|
||||||
const deleteList =
|
|
||||||
!checked && String(target.admdstCd ?? "")
|
|
||||||
? [String(target.admdstCd)]
|
|
||||||
: [];
|
|
||||||
|
|
||||||
if (saveList.length === 0 && deleteList.length === 0) {
|
|
||||||
setAdminRegionRows((prev) => revertCheckedToConnection(prev));
|
|
||||||
alert("행정구역 코드가 없어 저장할 수 없습니다.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
isSavingConnectionRef.current = true;
|
|
||||||
const ok = await persistFactConnection(saveList, deleteList);
|
|
||||||
isSavingConnectionRef.current = false;
|
|
||||||
|
|
||||||
if (!ok) {
|
|
||||||
setAdminRegionRows((prev) => revertCheckedToConnection(prev));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setAdminRegionRows((prev) => syncConnectionFlags(prev));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAdminRegionItemAllChecked = async (checked: boolean) => {
|
const handleAdminRegionItemAllChecked = (checked: boolean) => {
|
||||||
if (isSavingConnectionRef.current) {
|
|
||||||
setAdminRegionRows((prev) => prev.map((row) => ({ ...row })));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const snapshot = adminRegionRows;
|
|
||||||
if (snapshot.length === 0) return;
|
|
||||||
|
|
||||||
setAdminRegionRows((prev) =>
|
setAdminRegionRows((prev) =>
|
||||||
prev.map((row) => ({
|
prev.map((row) => ({ ...row, __checked: checked ? "1" : "0" })),
|
||||||
...row,
|
|
||||||
__checked: checked ? "1" : "0",
|
|
||||||
})),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const saveList: SeweragePipeFactConnectionSaveItem[] = checked
|
|
||||||
? snapshot
|
|
||||||
.filter((row) => row.isConnection !== "1")
|
|
||||||
.map((row) => ({
|
|
||||||
admdstCd: String(row.admdstCd ?? ""),
|
|
||||||
admdstNm: String(row.emdNm ?? ""),
|
|
||||||
}))
|
|
||||||
.filter((row) => row.admdstCd && row.admdstNm)
|
|
||||||
: [];
|
|
||||||
const deleteList = !checked
|
|
||||||
? snapshot
|
|
||||||
.filter((row) => row.isConnection === "1")
|
|
||||||
.map((row) => String(row.admdstCd ?? ""))
|
|
||||||
.filter(Boolean)
|
|
||||||
: [];
|
|
||||||
|
|
||||||
if (saveList.length === 0 && deleteList.length === 0) {
|
|
||||||
setAdminRegionRows((prev) => syncConnectionFlags(prev));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
isSavingConnectionRef.current = true;
|
|
||||||
const ok = await persistFactConnection(saveList, deleteList);
|
|
||||||
isSavingConnectionRef.current = false;
|
|
||||||
|
|
||||||
if (!ok) {
|
|
||||||
setAdminRegionRows((prev) => revertCheckedToConnection(prev));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setAdminRegionRows((prev) => syncConnectionFlags(prev));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -681,10 +575,8 @@ const SidoSggFacilityNameSearchForm = ({
|
|||||||
조회
|
조회
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="ml-auto">
|
||||||
<span className="text-lg text-gray-500 float-end">
|
<SaveButton saveFunc={handleSaveAdminRegions} />
|
||||||
* 체크 박스를 선택 / 해제 시 반영됩니다.
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ const SplitDataGrid = ({
|
|||||||
leftCellStyleCallback,
|
leftCellStyleCallback,
|
||||||
rightOnItemChecked,
|
rightOnItemChecked,
|
||||||
rightOnItemAllChecked,
|
rightOnItemAllChecked,
|
||||||
rightCheckableCallback,
|
|
||||||
enableSort = false,
|
enableSort = false,
|
||||||
}: SplitDataGridProps) => {
|
}: SplitDataGridProps) => {
|
||||||
return (
|
return (
|
||||||
@@ -40,7 +39,6 @@ const SplitDataGrid = ({
|
|||||||
setRowData={setRightRowData}
|
setRowData={setRightRowData}
|
||||||
onItemChecked={rightOnItemChecked}
|
onItemChecked={rightOnItemChecked}
|
||||||
onItemAllChecked={rightOnItemAllChecked}
|
onItemAllChecked={rightOnItemAllChecked}
|
||||||
checkableCallback={rightCheckableCallback}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -18,48 +18,32 @@ function mergeCellStyleCallbackResult(
|
|||||||
baseStyleName: string | undefined,
|
baseStyleName: string | undefined,
|
||||||
extra: CellStyleCallbackResult | undefined,
|
extra: CellStyleCallbackResult | undefined,
|
||||||
): CellStyleCallbackResult {
|
): CellStyleCallbackResult {
|
||||||
let styleName: string | undefined;
|
|
||||||
let extraObj: Extract<CellStyleCallbackResult, object> | undefined;
|
|
||||||
|
|
||||||
if (!extra) {
|
if (!extra) {
|
||||||
styleName = baseStyleName || undefined;
|
return baseStyleName ? { styleName: baseStyleName } : {};
|
||||||
} else if (typeof extra === "string") {
|
|
||||||
styleName = [extra, baseStyleName].filter(Boolean).join(" ") || undefined;
|
|
||||||
} else {
|
|
||||||
extraObj = extra;
|
|
||||||
styleName =
|
|
||||||
[extra.styleName, baseStyleName].filter(Boolean).join(" ") ||
|
|
||||||
undefined;
|
|
||||||
}
|
}
|
||||||
|
if (typeof extra === "string") {
|
||||||
if (!styleName && !extraObj) return {};
|
const styleName = [extra, baseStyleName].filter(Boolean).join(" ");
|
||||||
|
return styleName ? { styleName } : {};
|
||||||
const result: CellStyleCallbackResult = {
|
}
|
||||||
...extraObj,
|
const styleName = [extra.styleName, baseStyleName].filter(Boolean).join(" ");
|
||||||
|
return {
|
||||||
|
...extra,
|
||||||
...(styleName ? { styleName } : {}),
|
...(styleName ? { styleName } : {}),
|
||||||
};
|
};
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
import SplitDataGrid from "./SplitDataGrid";
|
import SplitDataGrid from "./SplitDataGrid";
|
||||||
|
|
||||||
import { getComputedValueCallback } from "@/components/util/grid/computedFieldCallbacks"
|
import { getComputedValueCallback } from "@/components/util/grid/computedFieldCallbacks"
|
||||||
import { wrapWithFormatTruncate } from "@/components/util/grid/decimalNumber"
|
|
||||||
import {
|
import {
|
||||||
buildExcelExportFileBaseName,
|
buildExcelExportFileBaseName,
|
||||||
buildFixedColumnNameSet,
|
|
||||||
getExcelImportColumnFieldNames,
|
getExcelImportColumnFieldNames,
|
||||||
getNonEditableColumnFieldNames,
|
getNonEditableColumnFieldNames,
|
||||||
hasAdmdstCdColumn,
|
hasAdmdstCdColumn,
|
||||||
isExcelImportAdmdstCdInvalid,
|
isExcelImportAdmdstCdInvalid,
|
||||||
mergeExcelImportWithExistingRows,
|
mergeExcelImportWithExistingRows,
|
||||||
prepareGridColumnsForExcelExport,
|
prepareGridColumnsForExcelExport,
|
||||||
releaseFixedOptionsForExcelExport,
|
|
||||||
resolveColumnStyleName,
|
|
||||||
restoreFixedOptionsAfterExcelExport,
|
|
||||||
restoreGridColumnsAfterExcelExport,
|
restoreGridColumnsAfterExcelExport,
|
||||||
shouldPrepareColumnsForExcelExport,
|
shouldPrepareColumnsForExcelExport,
|
||||||
disableAlternateRowStyle,
|
|
||||||
} from "@/components/util/gridExcelExport"
|
} from "@/components/util/gridExcelExport"
|
||||||
import { useTabStore } from "@/store/tab-store"
|
import { useTabStore } from "@/store/tab-store"
|
||||||
|
|
||||||
@@ -104,7 +88,7 @@ function safeGridViewRefresh(gv: { refresh?: () => void } | null | undefined) {
|
|||||||
try {
|
try {
|
||||||
gv.refresh();
|
gv.refresh();
|
||||||
} catch {
|
} catch {
|
||||||
console.error('refresh error');
|
/* noop */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,7 +237,7 @@ function sortRowsGroupPreserving(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** columnInfo → RealGrid DataField 배열 (computed → valueCallback 포함, setFields용) */
|
/** columnInfo → RealGrid DataField 배열 (computed → valueCallback 포함, setFields용) */
|
||||||
function buildFieldsFromColumns(columns: { fieldName: string; valueType?: ValueType; dataFormat?: string; computed?: import("../type/DataGrid.type").ComputedFieldConfig }[]) {
|
function buildFieldsFromColumns(columns: { fieldName: string; valueType?: ValueType; computed?: import("../type/DataGrid.type").ComputedFieldConfig }[]) {
|
||||||
return columns.map((col) => {
|
return columns.map((col) => {
|
||||||
const field: { fieldName: string; dataType: string; valueCallback?: (prod: unknown, dataRow: number, fieldName: string, fieldNames: string[], values: unknown[]) => number } = {
|
const field: { fieldName: string; dataType: string; valueCallback?: (prod: unknown, dataRow: number, fieldName: string, fieldNames: string[], values: unknown[]) => number } = {
|
||||||
fieldName: col.fieldName,
|
fieldName: col.fieldName,
|
||||||
@@ -269,7 +253,7 @@ function buildFieldsFromColumns(columns: { fieldName: string; valueType?: ValueT
|
|||||||
const hasSumOfMaxGroups = "groups" in col.computed && Array.isArray(col.computed.groups) && col.computed.groups.length > 0;
|
const hasSumOfMaxGroups = "groups" in col.computed && Array.isArray(col.computed.groups) && col.computed.groups.length > 0;
|
||||||
const hasSumPerTenThousand = col.computed.type === "sumPerTenThousand" && "numeratorFields" in col.computed && col.computed.numeratorFields.length > 0 && "denominatorField" in col.computed && Boolean(col.computed.denominatorField);
|
const hasSumPerTenThousand = col.computed.type === "sumPerTenThousand" && "numeratorFields" in col.computed && col.computed.numeratorFields.length > 0 && "denominatorField" in col.computed && Boolean(col.computed.denominatorField);
|
||||||
if (hasFields || hasNumeratorDenominator || hasMaxOfFieldAndSum || hasDifferenceOfSums || hasHalfSumOfSums || hasSumOfTwoHalfSumOfSums || hasSumOfMaxGroups || hasSumPerTenThousand) {
|
if (hasFields || hasNumeratorDenominator || hasMaxOfFieldAndSum || hasDifferenceOfSums || hasHalfSumOfSums || hasSumOfTwoHalfSumOfSums || hasSumOfMaxGroups || hasSumPerTenThousand) {
|
||||||
field.valueCallback = wrapWithFormatTruncate(getComputedValueCallback(col.computed), col.dataFormat);
|
field.valueCallback = getComputedValueCallback(col.computed) as (prod: unknown, dataRow: number, fieldName: string, fieldNames: string[], values: unknown[]) => number;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return field;
|
return field;
|
||||||
@@ -298,7 +282,7 @@ function createNumberComparer(dp: RealGridDataProviderComparer): (field: string
|
|||||||
const TabDataGrid = ({
|
const TabDataGrid = ({
|
||||||
columnInfo,
|
columnInfo,
|
||||||
isExcelImport = true,
|
isExcelImport = true,
|
||||||
excelImportSkipNonEditable = false,
|
excelImportSkipNonEditable = true,
|
||||||
excelImportSewerBzmnCd,
|
excelImportSewerBzmnCd,
|
||||||
excelExportSearchContext,
|
excelExportSearchContext,
|
||||||
isExcelExport = true,
|
isExcelExport = true,
|
||||||
@@ -329,23 +313,17 @@ const TabDataGrid = ({
|
|||||||
const cellStyleCallbackRef = useRef<CellStyleCallback | undefined>(undefined);
|
const cellStyleCallbackRef = useRef<CellStyleCallback | undefined>(undefined);
|
||||||
cellStyleCallbackRef.current = cellStyleCallback;
|
cellStyleCallbackRef.current = cellStyleCallback;
|
||||||
|
|
||||||
const attachCellStyleCallbacksForTab = useCallback((tabKey: string, columns: ColumnConfig[], columnLayout: ColumnLayoutItem[] | undefined, fixedCols: number | undefined, attempt = 0) => {
|
const attachCellStyleCallbacksForTab = useCallback((tabKey: string, columns: ColumnConfig[], attempt = 0) => {
|
||||||
|
if (!cellStyleCallbackRef.current) return;
|
||||||
const el = gridRefs.current.get(tabKey);
|
const el = gridRefs.current.get(tabKey);
|
||||||
const gv = el?.gridView;
|
const gv = el?.gridView;
|
||||||
if (!gv) return;
|
if (!gv) return;
|
||||||
|
|
||||||
const fixedColumnNameSet = buildFixedColumnNameSet(columns, columnLayout, fixedCols);
|
|
||||||
const hasUserCellStyleCallback = Boolean(cellStyleCallbackRef.current);
|
|
||||||
if (fixedColumnNameSet.size === 0 && !hasUserCellStyleCallback) return;
|
|
||||||
|
|
||||||
let attachedCount = 0;
|
let attachedCount = 0;
|
||||||
for (const column of columns) {
|
for (const column of columns) {
|
||||||
const isFixedColumn = fixedColumnNameSet.has(column.name);
|
|
||||||
if (!isFixedColumn && !hasUserCellStyleCallback) continue;
|
|
||||||
|
|
||||||
const gridCol = safeColumnByName(gv, column.name);
|
const gridCol = safeColumnByName(gv, column.name);
|
||||||
if (!gridCol) continue;
|
if (!gridCol) continue;
|
||||||
const baseStyleName = resolveColumnStyleName(column, fixedColumnNameSet);
|
const baseStyleName = column.styleName;
|
||||||
gridCol.styleCallback = (grid, dataCell) => {
|
gridCol.styleCallback = (grid, dataCell) => {
|
||||||
const dc = dataCell as {
|
const dc = dataCell as {
|
||||||
itemIndex?: number;
|
itemIndex?: number;
|
||||||
@@ -360,21 +338,19 @@ const TabDataGrid = ({
|
|||||||
return mergeCellStyleCallbackResult(baseStyleName, undefined);
|
return mergeCellStyleCallbackResult(baseStyleName, undefined);
|
||||||
}
|
}
|
||||||
const row = data[itemIndex] as Record<string, string | number>;
|
const row = data[itemIndex] as Record<string, string | number>;
|
||||||
const extra = hasUserCellStyleCallback
|
const extra = cellStyleCallbackRef.current?.({
|
||||||
? cellStyleCallbackRef.current?.({
|
rowIndex: itemIndex,
|
||||||
rowIndex: itemIndex,
|
fieldName,
|
||||||
fieldName,
|
row,
|
||||||
row,
|
grid: grid as CellStyleCallbackParams["grid"],
|
||||||
grid: grid as CellStyleCallbackParams["grid"],
|
});
|
||||||
})
|
|
||||||
: undefined;
|
|
||||||
return mergeCellStyleCallbackResult(baseStyleName, extra);
|
return mergeCellStyleCallbackResult(baseStyleName, extra);
|
||||||
};
|
};
|
||||||
attachedCount += 1;
|
attachedCount += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attachedCount === 0 && attempt < 20) {
|
if (attachedCount === 0 && attempt < 20) {
|
||||||
setTimeout(() => attachCellStyleCallbacksForTab(tabKey, columns, columnLayout, fixedCols, attempt + 1), 100);
|
setTimeout(() => attachCellStyleCallbacksForTab(tabKey, columns, attempt + 1), 100);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -483,14 +459,6 @@ const TabDataGrid = ({
|
|||||||
const excelExportVisibilitySnapshot = useExcelColumnVisibilityPrep
|
const excelExportVisibilitySnapshot = useExcelColumnVisibilityPrep
|
||||||
? prepareGridColumnsForExcelExport(gridView, columns)
|
? prepareGridColumnsForExcelExport(gridView, columns)
|
||||||
: undefined;
|
: undefined;
|
||||||
const savedFixedColCount = columnInfoItem.fixedColumns
|
|
||||||
? releaseFixedOptionsForExcelExport(
|
|
||||||
gridView,
|
|
||||||
columnInfoItem.fixedColumns,
|
|
||||||
)
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
disableAlternateRowStyle(gridView, true);
|
|
||||||
|
|
||||||
const exportBaseName = buildExcelExportFileBaseName(
|
const exportBaseName = buildExcelExportFileBaseName(
|
||||||
menuName,
|
menuName,
|
||||||
@@ -505,12 +473,6 @@ const TabDataGrid = ({
|
|||||||
footer: 'hidden',
|
footer: 'hidden',
|
||||||
allColumns: !useExcelColumnVisibilityPrep,
|
allColumns: !useExcelColumnVisibilityPrep,
|
||||||
done: () => {
|
done: () => {
|
||||||
if (savedFixedColCount !== undefined) {
|
|
||||||
restoreFixedOptionsAfterExcelExport(
|
|
||||||
gridView,
|
|
||||||
savedFixedColCount,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (excelExportVisibilitySnapshot) {
|
if (excelExportVisibilitySnapshot) {
|
||||||
restoreGridColumnsAfterExcelExport(gridView, excelExportVisibilitySnapshot);
|
restoreGridColumnsAfterExcelExport(gridView, excelExportVisibilitySnapshot);
|
||||||
}
|
}
|
||||||
@@ -1006,11 +968,6 @@ const TabDataGrid = ({
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const { columns, columnLayout } = info;
|
const { columns, columnLayout } = info;
|
||||||
const fixedColumnNameSet = buildFixedColumnNameSet(
|
|
||||||
columns,
|
|
||||||
columnLayout,
|
|
||||||
info.fixedColumns,
|
|
||||||
);
|
|
||||||
const currentRowData = rowDataMap.get(tabKey) || [];
|
const currentRowData = rowDataMap.get(tabKey) || [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -1117,7 +1074,6 @@ const TabDataGrid = ({
|
|||||||
gridView.setOptions({
|
gridView.setOptions({
|
||||||
summaryMode: "aggregate"
|
summaryMode: "aggregate"
|
||||||
});
|
});
|
||||||
disableAlternateRowStyle(gridView);
|
|
||||||
|
|
||||||
// footerUserSpans가 있는 경우 setColumnLayout으로 설정
|
// footerUserSpans가 있는 경우 setColumnLayout으로 설정
|
||||||
const checkFooterUserSpans = (layout: unknown[]): boolean => {
|
const checkFooterUserSpans = (layout: unknown[]): boolean => {
|
||||||
@@ -1233,27 +1189,9 @@ const TabDataGrid = ({
|
|||||||
if (currentInfo.fixedColumns !== undefined && currentInfo.fixedColumns > 0) {
|
if (currentInfo.fixedColumns !== undefined && currentInfo.fixedColumns > 0) {
|
||||||
gridView.setFixedOptions({
|
gridView.setFixedOptions({
|
||||||
colCount: currentInfo.fixedColumns,
|
colCount: currentInfo.fixedColumns,
|
||||||
resizable: true,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const tabFixedSet = buildFixedColumnNameSet(
|
|
||||||
columns,
|
|
||||||
currentInfo.columnLayout,
|
|
||||||
currentInfo.fixedColumns,
|
|
||||||
);
|
|
||||||
columns.forEach((col) => {
|
|
||||||
const styleName = resolveColumnStyleName(
|
|
||||||
col,
|
|
||||||
tabFixedSet,
|
|
||||||
);
|
|
||||||
gridView.setColumnProperty?.(
|
|
||||||
col.name,
|
|
||||||
"styleName",
|
|
||||||
styleName,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 각 탭별 ref 초기화
|
// 각 탭별 ref 초기화
|
||||||
if (!sortDirRefs.current.has(tabKey)) {
|
if (!sortDirRefs.current.has(tabKey)) {
|
||||||
sortDirRefs.current.set(tabKey, { current: {} });
|
sortDirRefs.current.set(tabKey, { current: {} });
|
||||||
@@ -1309,17 +1247,9 @@ const TabDataGrid = ({
|
|||||||
const onSortingHandler = createOnSortingHandler(columns, setRowData, sortDirRef, originalRowsRef, findGridElement);
|
const onSortingHandler = createOnSortingHandler(columns, setRowData, sortDirRef, originalRowsRef, findGridElement);
|
||||||
(gridView as { onSorting?: (g: unknown, f: unknown[], d: unknown[]) => boolean }).onSorting = enableSort ? onSortingHandler : () => false;
|
(gridView as { onSorting?: (g: unknown, f: unknown[], d: unknown[]) => boolean }).onSorting = enableSort ? onSortingHandler : () => false;
|
||||||
|
|
||||||
if (
|
if (cellStyleCallbackRef.current) {
|
||||||
cellStyleCallbackRef.current ||
|
|
||||||
tabFixedSet.size > 0
|
|
||||||
) {
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
attachCellStyleCallbacksForTab(
|
attachCellStyleCallbacksForTab(tabKey, columns);
|
||||||
tabKey,
|
|
||||||
columns,
|
|
||||||
currentInfo.columnLayout,
|
|
||||||
currentInfo.fixedColumns,
|
|
||||||
);
|
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
}, 150);
|
}, 150);
|
||||||
@@ -1332,16 +1262,7 @@ const TabDataGrid = ({
|
|||||||
layout={columnLayout}
|
layout={columnLayout}
|
||||||
rows={currentRowData}
|
rows={currentRowData}
|
||||||
>
|
>
|
||||||
{columns.map((column) => {
|
{columns.map((column) => (
|
||||||
const resolvedStyleName =
|
|
||||||
resolveColumnStyleName(
|
|
||||||
column,
|
|
||||||
fixedColumnNameSet,
|
|
||||||
) ||
|
|
||||||
(column.editable === false
|
|
||||||
? "rg-cell-readonly"
|
|
||||||
: undefined);
|
|
||||||
return (
|
|
||||||
<RGDataColumn
|
<RGDataColumn
|
||||||
key={column.name}
|
key={column.name}
|
||||||
name={column.name}
|
name={column.name}
|
||||||
@@ -1350,9 +1271,11 @@ const TabDataGrid = ({
|
|||||||
{...(column.valueType === ValueType.NUMBER && { numberFormat: column.dataFormat ? column.dataFormat : '#,##0.00' })}
|
{...(column.valueType === ValueType.NUMBER && { numberFormat: column.dataFormat ? column.dataFormat : '#,##0.00' })}
|
||||||
header={column.header}
|
header={column.header}
|
||||||
editable={column.editable}
|
editable={column.editable}
|
||||||
{...(resolvedStyleName != null
|
{...(column.styleName != null
|
||||||
? { styleName: resolvedStyleName }
|
? { styleName: column.styleName }
|
||||||
: {})}
|
: column.editable === false
|
||||||
|
? { styleName: 'rg-cell-readonly' as const }
|
||||||
|
: {})}
|
||||||
{...(column.visible === false && { visible: false })}
|
{...(column.visible === false && { visible: false })}
|
||||||
footer={column.footer && !Array.isArray(column.footer) ? {
|
footer={column.footer && !Array.isArray(column.footer) ? {
|
||||||
text: (column.footer as { text?: string }).text,
|
text: (column.footer as { text?: string }).text,
|
||||||
@@ -1362,8 +1285,7 @@ const TabDataGrid = ({
|
|||||||
mergeRule={column.mergeCells ? { criteria: column.mergeGroupField ? `values['${column.mergeGroupField}'] + value` : 'value' } : undefined}
|
mergeRule={column.mergeCells ? { criteria: column.mergeGroupField ? `values['${column.mergeGroupField}'] + value` : 'value' } : undefined}
|
||||||
sortable={enableSort && !column.sortdisable}
|
sortable={enableSort && !column.sortdisable}
|
||||||
/>
|
/>
|
||||||
);
|
))}
|
||||||
})}
|
|
||||||
</RealGridReact>
|
</RealGridReact>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -10,12 +10,7 @@ import {
|
|||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from "react";
|
||||||
|
|
||||||
import type { RealGridReact } from "realgrid-react";
|
import type { RealGridReact } from "realgrid-react";
|
||||||
|
|
||||||
import { useAlertStore } from "@/shared/lib";
|
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
|
||||||
import type { VerificationResultListRequest, VerificationResultReportItem } from "@/entities/statistics/model/statistics-interface";
|
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Dialog,
|
Dialog,
|
||||||
@@ -26,17 +21,17 @@ import {
|
|||||||
DialogTitle,
|
DialogTitle,
|
||||||
LoadingWithAnimation,
|
LoadingWithAnimation,
|
||||||
} from "@common/components";
|
} from "@common/components";
|
||||||
|
|
||||||
import { getUserInfo } from "../../../../../packages/common/components/src/api";
|
|
||||||
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
import { cellContentTooltip } from "@/components/module/verificationResultCellTooltip";
|
|
||||||
import { VerificationResultHistoryPagination } from "@/components/module/VerificationResultHistoryPagination";
|
import { VerificationResultHistoryPagination } from "@/components/module/VerificationResultHistoryPagination";
|
||||||
import type {
|
import type {
|
||||||
CellEditedCallbackParams,
|
CellEditedCallbackParams,
|
||||||
CellStyleCallbackParams,
|
CellStyleCallbackParams,
|
||||||
ColumnInfo,
|
ColumnInfo,
|
||||||
} from "@/components/type/DataGrid.type";
|
} from "@/components/type/DataGrid.type";
|
||||||
|
import { getUserInfo } from "../../../../../packages/common/components/src/api";
|
||||||
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
|
import type { VerificationResultListRequest, VerificationResultReportItem } from "@/entities/statistics/model/statistics-interface";
|
||||||
|
import { useAlertStore } from "@/shared/lib";
|
||||||
|
|
||||||
type VerificationResultGridRow = Record<string, string | number>;
|
type VerificationResultGridRow = Record<string, string | number>;
|
||||||
|
|
||||||
@@ -46,8 +41,8 @@ const VERIFICATION_METHOD_CODES: VerificationMethodCd[] = ["NV", "IMR", "HB"];
|
|||||||
|
|
||||||
const VRFC_MTHD_NAME_MAP: Record<VerificationMethodCd, string> = {
|
const VRFC_MTHD_NAME_MAP: Record<VerificationMethodCd, string> = {
|
||||||
NV: "일반",
|
NV: "일반",
|
||||||
IMR: "시계열",
|
IMR: "I-MR",
|
||||||
HB: "모집단",
|
HB: "HB",
|
||||||
};
|
};
|
||||||
|
|
||||||
export type VerificationExceptionSubmitItem = {
|
export type VerificationExceptionSubmitItem = {
|
||||||
@@ -68,7 +63,7 @@ function setRowCheckByItemIndex(
|
|||||||
try {
|
try {
|
||||||
gv?.checkItem?.(itemIndex, checked, false);
|
gv?.checkItem?.(itemIndex, checked, false);
|
||||||
} catch {
|
} catch {
|
||||||
console.error('RealGrid 체크 API error');
|
/* RealGrid 체크 API 미지원 등 */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +93,6 @@ const verificationSubmitResultColumnInfo: ColumnInfo = {
|
|||||||
{ name: "vrfcMthdCd", fieldName: "vrfcMthdCd", header: { text: "검증유형코드" }, editable: false, visible: false },
|
{ name: "vrfcMthdCd", fieldName: "vrfcMthdCd", header: { text: "검증유형코드" }, editable: false, visible: false },
|
||||||
{ name: "ctpvNm", fieldName: "ctpvNm", header: { text: "시도" }, editable: false },
|
{ name: "ctpvNm", fieldName: "ctpvNm", header: { text: "시도" }, editable: false },
|
||||||
{ name: "admdstNm", fieldName: "admdstNm", header: { text: "행정구역" }, editable: false },
|
{ name: "admdstNm", fieldName: "admdstNm", header: { text: "행정구역" }, editable: false },
|
||||||
{ name: "fcltNm", fieldName: "fcltNm", header: { text: "시설명" }, editable: false },
|
|
||||||
{ name: "vrfcTrgtNm", fieldName: "vrfcTrgtNm", header: { text: "검증대상" }, editable: false },
|
{ name: "vrfcTrgtNm", fieldName: "vrfcTrgtNm", header: { text: "검증대상" }, editable: false },
|
||||||
{ name: "rsnExpln", fieldName: "rsnExpln", header: { text: "사유" }, editable: false },
|
{ name: "rsnExpln", fieldName: "rsnExpln", header: { text: "사유" }, editable: false },
|
||||||
{ name: "nowVlCn", fieldName: "nowVlCn", header: { text: "입력값" }, editable: false },
|
{ name: "nowVlCn", fieldName: "nowVlCn", header: { text: "입력값" }, editable: false },
|
||||||
@@ -117,7 +111,6 @@ const verificationSubmitResultColumnInfo: ColumnInfo = {
|
|||||||
"vrfcMthdNm",
|
"vrfcMthdNm",
|
||||||
"ctpvNm",
|
"ctpvNm",
|
||||||
"admdstNm",
|
"admdstNm",
|
||||||
"fcltNm",
|
|
||||||
"vrfcTrgtNm",
|
"vrfcTrgtNm",
|
||||||
"rsnExpln",
|
"rsnExpln",
|
||||||
"nowVlCn",
|
"nowVlCn",
|
||||||
@@ -132,7 +125,7 @@ const verificationSubmitResultColumnInfo: ColumnInfo = {
|
|||||||
export interface VerificationResultDialogQueryContext {
|
export interface VerificationResultDialogQueryContext {
|
||||||
sewerBzmnCd: string;
|
sewerBzmnCd: string;
|
||||||
ctpvNm: string;
|
ctpvNm: string;
|
||||||
sggNm?: string;
|
sggNm: string;
|
||||||
statsYr: string;
|
statsYr: string;
|
||||||
statsCd: string;
|
statsCd: string;
|
||||||
}
|
}
|
||||||
@@ -208,7 +201,6 @@ export function VerificationResultDialog({
|
|||||||
vrfcMthdNm: VRFC_MTHD_NAME_MAP[vrfcMthdCd] ?? item.vrfcMthdNm,
|
vrfcMthdNm: VRFC_MTHD_NAME_MAP[vrfcMthdCd] ?? item.vrfcMthdNm,
|
||||||
ctpvNm: item.ctpvNm,
|
ctpvNm: item.ctpvNm,
|
||||||
admdstNm: item.admdstNm ?? item.sggNm ?? "-",
|
admdstNm: item.admdstNm ?? item.sggNm ?? "-",
|
||||||
fcltNm: item.fcltNm ?? "-",
|
|
||||||
vrfcTrgtNm: item.vrfcTrgtNm,
|
vrfcTrgtNm: item.vrfcTrgtNm,
|
||||||
rsnExpln: item.rsnExpln,
|
rsnExpln: item.rsnExpln,
|
||||||
nowVlCn: item.nowVlCn ?? "-",
|
nowVlCn: item.nowVlCn ?? "-",
|
||||||
@@ -421,7 +413,6 @@ export function VerificationResultDialog({
|
|||||||
getGridDataRef={getGridDataRef}
|
getGridDataRef={getGridDataRef}
|
||||||
onCellEdited={onPrcsOpnnExplnEdited}
|
onCellEdited={onPrcsOpnnExplnEdited}
|
||||||
cellStyleCallback={verificationMthdCellStyle}
|
cellStyleCallback={verificationMthdCellStyle}
|
||||||
cellTooltipCallback={cellContentTooltip}
|
|
||||||
onItemChecked={(itemIndex, checked) => {
|
onItemChecked={(itemIndex, checked) => {
|
||||||
setCheckedIndices((prev) => {
|
setCheckedIndices((prev) => {
|
||||||
const next = new Set(prev);
|
const next = new Set(prev);
|
||||||
|
|||||||
@@ -10,10 +10,9 @@ import {
|
|||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from "react";
|
||||||
|
|
||||||
import type { RealGridReact } from "realgrid-react";
|
import type { RealGridReact } from "realgrid-react";
|
||||||
|
|
||||||
import { useAlertStore } from "@/shared/lib";
|
import { getUserInfo } from "../../../../../packages/common/components/src/api";
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
import type { VerificationResultListRequest, VerificationResultReportItem } from "@/entities/statistics/model/statistics-interface";
|
import type { VerificationResultListRequest, VerificationResultReportItem } from "@/entities/statistics/model/statistics-interface";
|
||||||
import {
|
import {
|
||||||
@@ -31,20 +30,18 @@ import {
|
|||||||
TabsTrigger,
|
TabsTrigger,
|
||||||
} from "@common/components";
|
} from "@common/components";
|
||||||
|
|
||||||
import { getUserInfo } from "../../../../../packages/common/components/src/api";
|
|
||||||
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
import { cellContentTooltip } from "@/components/module/verificationResultCellTooltip";
|
|
||||||
import { VerificationResultHistoryPagination } from "@/components/module/VerificationResultHistoryPagination";
|
import { VerificationResultHistoryPagination } from "@/components/module/VerificationResultHistoryPagination";
|
||||||
import type { CellStyleCallbackParams, ColumnInfo } from "@/components/type/DataGrid.type";
|
import type { CellStyleCallbackParams, ColumnInfo } from "@/components/type/DataGrid.type";
|
||||||
|
import { useAlertStore } from "@/shared/lib";
|
||||||
|
|
||||||
type VerificationResultGridRow = Record<string, string | number>;
|
type VerificationResultGridRow = Record<string, string | number>;
|
||||||
type VerificationHistoryTabKey = "NV" | "IMR" | "HB";
|
type VerificationHistoryTabKey = "NV" | "IMR" | "HB";
|
||||||
|
|
||||||
const verificationHistoryTabs: { value: VerificationHistoryTabKey; label: string }[] = [
|
const verificationHistoryTabs: { value: VerificationHistoryTabKey; label: string }[] = [
|
||||||
{ value: "NV", label: "일반검증 내역" },
|
{ value: "NV", label: "일반검증 내역" },
|
||||||
{ value: "IMR", label: "시계열 검증내역" },
|
{ value: "IMR", label: "I-MR 검증내역" },
|
||||||
{ value: "HB", label: "모집단 검증내역" },
|
{ value: "HB", label: "HB 검증내역" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const PAGE_SIZE = 30;
|
const PAGE_SIZE = 30;
|
||||||
@@ -91,7 +88,7 @@ function uncheckGridRow(gridRef: MutableRefObject<RealGridReact | null>, itemInd
|
|||||||
try {
|
try {
|
||||||
(gridRef.current?.gridView as GridViewWithCheckApi | undefined)?.checkItem?.(itemIndex, false, false);
|
(gridRef.current?.gridView as GridViewWithCheckApi | undefined)?.checkItem?.(itemIndex, false, false);
|
||||||
} catch {
|
} catch {
|
||||||
console.error('RealGrid 체크 API error');
|
/* ignore */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +138,6 @@ const verificationResultColumnInfo: ColumnInfo = {
|
|||||||
columns: [
|
columns: [
|
||||||
{ name: "ctpvNm", fieldName: "ctpvNm", header: { text: "시도" }, editable: false },
|
{ name: "ctpvNm", fieldName: "ctpvNm", header: { text: "시도" }, editable: false },
|
||||||
{ name: "admdstNm", fieldName: "admdstNm", header: { text: "행정구역" }, editable: false },
|
{ name: "admdstNm", fieldName: "admdstNm", header: { text: "행정구역" }, editable: false },
|
||||||
{ name: "fcltNm", fieldName: "fcltNm", header: { text: "시설명" }, editable: false },
|
|
||||||
{ name: "vrfcTrgtNm", fieldName: "vrfcTrgtNm", header: { text: "검증대상" }, editable: false },
|
{ name: "vrfcTrgtNm", fieldName: "vrfcTrgtNm", header: { text: "검증대상" }, editable: false },
|
||||||
{ name: "rsnExpln", fieldName: "rsnExpln", header: { text: "사유" }, editable: false },
|
{ name: "rsnExpln", fieldName: "rsnExpln", header: { text: "사유" }, editable: false },
|
||||||
{ name: "nowVlCn", fieldName: "nowVlCn", header: { text: "입력값" }, editable: false },
|
{ name: "nowVlCn", fieldName: "nowVlCn", header: { text: "입력값" }, editable: false },
|
||||||
@@ -158,7 +154,6 @@ const verificationResultColumnInfo: ColumnInfo = {
|
|||||||
columnLayout: [
|
columnLayout: [
|
||||||
"ctpvNm",
|
"ctpvNm",
|
||||||
"admdstNm",
|
"admdstNm",
|
||||||
"fcltNm",
|
|
||||||
"vrfcTrgtNm",
|
"vrfcTrgtNm",
|
||||||
"rsnExpln",
|
"rsnExpln",
|
||||||
"nowVlCn",
|
"nowVlCn",
|
||||||
@@ -180,7 +175,7 @@ export interface VerificationResultHistoryDialogProps {
|
|||||||
queryContext?: {
|
queryContext?: {
|
||||||
sewerBzmnCd: string;
|
sewerBzmnCd: string;
|
||||||
ctpvNm: string;
|
ctpvNm: string;
|
||||||
sggNm?: string;
|
sggNm: string;
|
||||||
statsYr: string;
|
statsYr: string;
|
||||||
statsCd: string;
|
statsCd: string;
|
||||||
} | null;
|
} | null;
|
||||||
@@ -380,9 +375,8 @@ export function VerificationResultHistoryDialog({
|
|||||||
return {
|
return {
|
||||||
vrfcSn: item.vrfcSn,
|
vrfcSn: item.vrfcSn,
|
||||||
__checked: isChecked ? 1 : 0,
|
__checked: isChecked ? 1 : 0,
|
||||||
ctpvNm: item.ctpvNm ?? "-",
|
ctpvNm: item.ctpvNm,
|
||||||
admdstNm: item.admdstNm ?? item.sggNm ?? "-",
|
admdstNm: item.admdstNm ?? item.sggNm ?? "-",
|
||||||
fcltNm: item.fcltNm ?? "-",
|
|
||||||
vrfcTrgtNm: item.vrfcTrgtNm,
|
vrfcTrgtNm: item.vrfcTrgtNm,
|
||||||
rsnExpln: item.rsnExpln,
|
rsnExpln: item.rsnExpln,
|
||||||
nowVlCn: item.nowVlCn ?? "-",
|
nowVlCn: item.nowVlCn ?? "-",
|
||||||
@@ -506,7 +500,6 @@ export function VerificationResultHistoryDialog({
|
|||||||
enableSort={false}
|
enableSort={false}
|
||||||
getGridRef={gridRef}
|
getGridRef={gridRef}
|
||||||
cellStyleCallback={verificationPrcsYnNmCellStyle}
|
cellStyleCallback={verificationPrcsYnNmCellStyle}
|
||||||
cellTooltipCallback={cellContentTooltip}
|
|
||||||
onItemChecked={(itemIndex, checked) => {
|
onItemChecked={(itemIndex, checked) => {
|
||||||
const entry = entries[itemIndex];
|
const entry = entries[itemIndex];
|
||||||
if (!entry) return;
|
if (!entry) return;
|
||||||
@@ -565,7 +558,7 @@ export function VerificationResultHistoryDialog({
|
|||||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||||
<DialogContent className="max-w-[80%]" aria-describedby={undefined}>
|
<DialogContent className="max-w-[80%]" aria-describedby={undefined}>
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>{`${title} - ${queryContext?.statsYr} ${queryContext?.ctpvNm} ${queryContext?.sggNm ? queryContext?.sggNm : ''}`}</DialogTitle>
|
<DialogTitle>{`${title} - ${queryContext?.statsYr} ${queryContext?.ctpvNm} ${queryContext?.sggNm}`}</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<div className="max-h-[85vh] space-y-5 overflow-auto">
|
<div className="max-h-[85vh] space-y-5 overflow-auto">
|
||||||
{errorMessage && (
|
{errorMessage && (
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import {
|
|||||||
DoubleArrowLeftIcon,
|
DoubleArrowLeftIcon,
|
||||||
DoubleArrowRightIcon,
|
DoubleArrowRightIcon,
|
||||||
} from "@radix-ui/react-icons";
|
} from "@radix-ui/react-icons";
|
||||||
|
|
||||||
import { Button, cn } from "@common/components";
|
import { Button, cn } from "@common/components";
|
||||||
|
|
||||||
export type VerificationResultHistoryPaginationProps = {
|
export type VerificationResultHistoryPaginationProps = {
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
import type { CellTooltipCallbackParams } from "@/components/type/DataGrid.type";
|
|
||||||
|
|
||||||
/** RealGrid 셀 호버 시 title처럼 전체 내용 표시 */
|
|
||||||
export function cellContentTooltip({
|
|
||||||
row,
|
|
||||||
fieldName,
|
|
||||||
}: CellTooltipCallbackParams): string | undefined {
|
|
||||||
const value = row[fieldName];
|
|
||||||
if (value == null || value === "") return undefined;
|
|
||||||
return String(value);
|
|
||||||
}
|
|
||||||
@@ -1,48 +1,47 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
|
|
||||||
import { useTabStore as useGridTabStore } from "@rsone/components";
|
|
||||||
import {
|
import {
|
||||||
type InfiniteData,
|
type InfiniteData,
|
||||||
keepPreviousData,
|
keepPreviousData,
|
||||||
useInfiniteQuery,
|
useInfiniteQuery,
|
||||||
useQueryClient,
|
useQueryClient,
|
||||||
} from "@tanstack/react-query";
|
} from "@tanstack/react-query";
|
||||||
import dayjs from "dayjs";
|
import { useTabStore as useGridTabStore } from "@rsone/components";
|
||||||
|
|
||||||
import { useAlertStore, useMenuStore } from "@/shared/lib";
|
|
||||||
import {
|
|
||||||
findMenuItemByUrlPath,
|
|
||||||
resolveInputPageNavigationFromStatsCd,
|
|
||||||
} from "@/shared/lib/stats-cd-input-navigation";
|
|
||||||
import { CodeSelectWithAll } from "@/entities/code";
|
|
||||||
import { verificationInputReportApi } from "@/entities/statistics/api/verification-input-report-service";
|
import { verificationInputReportApi } from "@/entities/statistics/api/verification-input-report-service";
|
||||||
import type {
|
import type {
|
||||||
VerificationInputReportItem,
|
VerificationInputReportItem,
|
||||||
VerificationInputReportResponse,
|
VerificationInputReportResponse,
|
||||||
VerificationInputReportTypeCountingInfo,
|
VerificationInputReportTypeCountingInfo,
|
||||||
} from "@/entities/statistics/model/verification-input-report-interface";
|
} from "@/entities/statistics/model/verification-input-report-interface";
|
||||||
|
import { useAlertStore, useMenuStore } from "@/shared/lib";
|
||||||
|
import {
|
||||||
|
findMenuItemByUrlPath,
|
||||||
|
resolveInputPageNavigationFromStatsCd,
|
||||||
|
} from "@/shared/lib/stats-cd-input-navigation";
|
||||||
|
import { useStatisticsInputFocusStore } from "@/store/statistics-input-focus-store";
|
||||||
|
import { useTabStore } from "@/store/tab-store";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Badge,
|
Badge,
|
||||||
type BadgeProps,
|
type BadgeProps,
|
||||||
Label,
|
|
||||||
LoadingWithAnimation,
|
LoadingWithAnimation,
|
||||||
Tabs,
|
Tabs,
|
||||||
TabsContent,
|
TabsContent,
|
||||||
TabsList,
|
TabsList,
|
||||||
TabsTrigger,
|
TabsTrigger,
|
||||||
|
Label,
|
||||||
} from "@common/components";
|
} from "@common/components";
|
||||||
|
import { CodeSelectWithAll } from "@/entities/code";
|
||||||
import { useStatisticsInputFocusStore } from "@/store/statistics-input-focus-store";
|
|
||||||
import { useTabStore } from "@/store/tab-store";
|
|
||||||
|
|
||||||
type VerificationReportTabKey = "NV" | "IMR" | "HB";
|
type VerificationReportTabKey = "NV" | "IMR" | "HB";
|
||||||
|
|
||||||
const VERIFICATION_REPORT_TABS: { value: VerificationReportTabKey; label: string }[] = [
|
const VERIFICATION_REPORT_TABS: { value: VerificationReportTabKey; label: string }[] = [
|
||||||
{ value: "NV", label: "일반" },
|
{ value: "NV", label: "일반" },
|
||||||
{ value: "IMR", label: "시계열" },
|
{ value: "IMR", label: "I-MR" },
|
||||||
{ value: "HB", label: "모집단" },
|
{ value: "HB", label: "HB" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const TYPE_CODE_COLOR_MAP: Record<string, BadgeProps["color"]> = {
|
const TYPE_CODE_COLOR_MAP: Record<string, BadgeProps["color"]> = {
|
||||||
@@ -53,8 +52,8 @@ const TYPE_CODE_COLOR_MAP: Record<string, BadgeProps["color"]> = {
|
|||||||
|
|
||||||
const TYPE_CODE_NAME_MAP: Record<string, string> = {
|
const TYPE_CODE_NAME_MAP: Record<string, string> = {
|
||||||
NV: "일반",
|
NV: "일반",
|
||||||
IMR: "시계열",
|
IMR: "I-MR",
|
||||||
HB: "모집단",
|
HB: "HB",
|
||||||
};
|
};
|
||||||
|
|
||||||
const PAGE_SIZE = 100;
|
const PAGE_SIZE = 100;
|
||||||
|
|||||||
@@ -1,56 +1,20 @@
|
|||||||
import {
|
import {
|
||||||
type RefObject,
|
|
||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
useMemo,
|
useMemo,
|
||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
|
type RefObject,
|
||||||
} from "react";
|
} from "react";
|
||||||
|
|
||||||
import { flushSync } from "react-dom";
|
import { flushSync } from "react-dom";
|
||||||
|
|
||||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||||
|
|
||||||
import { ValueType } from "realgrid";
|
import { ValueType } from "realgrid";
|
||||||
import type { RealGridReact } from "realgrid-react";
|
import type { RealGridReact } from "realgrid-react";
|
||||||
|
|
||||||
import { useAlertStore, useGlobalProgressStore, useStatisticsInputToolbarGroupGate, useSearchConditionSidoList } from "@/shared/lib";
|
|
||||||
import { STATISTICS_INPUT_URL_PATH } from "@/shared/lib/stats-cd-input-navigation";
|
|
||||||
import { useStatisticsInputPendingNavigation } from "@/shared/lib/use-statistics-input-pending-navigation";
|
|
||||||
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
|
||||||
import { nullableTrimmedString } from "@/components/util/input/nullableString";
|
|
||||||
import { statisticsInputExcretaTreatmentFacilityApi } from "@/entities/statistics/api/input/statistics-input-excreta-treatment-facility-service";
|
|
||||||
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
|
||||||
import {
|
|
||||||
EXCRETA_TREATMENT_FACILITY_STATS_CD,
|
|
||||||
type ExcretaTreatmentFacilityItem,
|
|
||||||
type ExcretaTreatmentFacilityRequestParams,
|
|
||||||
type ExcretaTreatmentFacilitySaveItem,
|
|
||||||
type ExcretaTreatmentFacilityVerificationResult,
|
|
||||||
} from "@/entities/statistics/model/input/statistics-input-excreta-treatment-facility-interface";
|
|
||||||
import { isInputPeriodCurrent } from "@/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface";
|
|
||||||
import type { StatisticsInputSubmitInfoFormData } from "@/entities/statistics/model/statistics-input-submit-info-schema";
|
|
||||||
import type {
|
|
||||||
ApiResponse,
|
|
||||||
cancelSubmitRequest,
|
|
||||||
ImrStatusResponse,
|
|
||||||
SewerageStatusInfo,
|
|
||||||
Sgg,
|
|
||||||
Sido,
|
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
|
||||||
import {
|
|
||||||
filterBySelectedAdmdstCd,
|
|
||||||
isGugunOkForToolbar,
|
|
||||||
isSubmitOkForToolbar,
|
|
||||||
resolveNoApplicableForRequest,
|
|
||||||
toInputSearchRegion,
|
|
||||||
} from "@/entities/statistics";
|
|
||||||
|
|
||||||
import { LoadingWithAnimation } from "@common/components";
|
import { LoadingWithAnimation } from "@common/components";
|
||||||
|
|
||||||
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
|
||||||
|
|
||||||
import SubmitDailog from "./SubmitDailog";
|
|
||||||
|
|
||||||
import AddArticleButton from "@/components/button/AddArticleButton";
|
import AddArticleButton from "@/components/button/AddArticleButton";
|
||||||
import CancelSubmitButton from "@/components/button/CancelSubmitButton";
|
import CancelSubmitButton from "@/components/button/CancelSubmitButton";
|
||||||
import DeleteArticleButton from "@/components/button/DeleteArticleButton";
|
import DeleteArticleButton from "@/components/button/DeleteArticleButton";
|
||||||
@@ -60,24 +24,49 @@ import SaveButton from "@/components/button/SaveButton";
|
|||||||
import SubmitButton from "@/components/button/SumitButton";
|
import SubmitButton from "@/components/button/SumitButton";
|
||||||
import VerificationResultButton from "@/components/button/VerificationResultButton";
|
import VerificationResultButton from "@/components/button/VerificationResultButton";
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
|
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
||||||
import { openVerificationResultDialogIfNeeded } from "@/components/module/post-submit-verification-results";
|
import { openVerificationResultDialogIfNeeded } from "@/components/module/post-submit-verification-results";
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
||||||
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
||||||
|
import SubmitDailog from "./SubmitDailog";
|
||||||
|
import { ExcretaTreatFactInpColumn } from "@/components/util/column/input/ExcretaTreatFactInpColumn";
|
||||||
import type {
|
import type {
|
||||||
CellStyleCallbackParams,
|
CellStyleCallbackParams,
|
||||||
CellTooltipCallbackParams,
|
CellTooltipCallbackParams,
|
||||||
ColumnConfig,
|
ColumnConfig,
|
||||||
} from "@/components/type/DataGrid.type";
|
} from "@/components/type/DataGrid.type";
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
import { ExcretaTreatFactInpColumn } from "@/components/util/column/input/ExcretaTreatFactInpColumn";
|
import { doList } from "@/components/util/column/input/DoList";
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
import { formatCompactYmdForGrid, toCompactYmdOrNull } from "@/components/util/grid/ymdFormat";
|
|
||||||
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
|
||||||
import { isVerificationFailedFromCommonInfo } from "@/components/util/input/verification-failed-flag";
|
import { isVerificationFailedFromCommonInfo } from "@/components/util/input/verification-failed-flag";
|
||||||
import type { VerificationResultLikeMap } from "@/components/util/input/verification-result-display";
|
import { formatCompactYmdForGrid, toCompactYmdOrNull } from "@/components/util/grid/ymdFormat";
|
||||||
|
import { statisticsInputExcretaTreatmentFacilityApi } from "@/entities/statistics/api/input/statistics-input-excreta-treatment-facility-service";
|
||||||
|
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
||||||
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
|
import { isInputPeriodCurrent } from "@/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface";
|
||||||
|
import {
|
||||||
|
EXCRETA_TREATMENT_FACILITY_STATS_CD,
|
||||||
|
type ExcretaTreatmentFacilityItem,
|
||||||
|
type ExcretaTreatmentFacilityRequestParams,
|
||||||
|
type ExcretaTreatmentFacilitySaveItem,
|
||||||
|
type ExcretaTreatmentFacilityVerificationResult,
|
||||||
|
} from "@/entities/statistics/model/input/statistics-input-excreta-treatment-facility-interface";
|
||||||
|
import type { StatisticsInputSubmitInfoFormData } from "@/entities/statistics/model/statistics-input-submit-info-schema";
|
||||||
|
import type {
|
||||||
|
ApiResponse,
|
||||||
|
cancelSubmitRequest,
|
||||||
|
ImrStatusResponse,
|
||||||
|
Sgg,
|
||||||
|
SewerageStatusInfo,
|
||||||
|
} from "@/entities/statistics/model/statistics-interface";
|
||||||
|
import { useAlertStore, useGlobalProgressStore, useStatisticsInputToolbarGroupGate } from "@/shared/lib";
|
||||||
|
import { STATISTICS_INPUT_URL_PATH } from "@/shared/lib/stats-cd-input-navigation";
|
||||||
|
import { useStatisticsInputPendingNavigation } from "@/shared/lib/use-statistics-input-pending-navigation";
|
||||||
|
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
||||||
import { useAdminStore } from "@/store/admin-store";
|
import { useAdminStore } from "@/store/admin-store";
|
||||||
import { useTabStore } from "@/store/tab-store";
|
|
||||||
|
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
||||||
|
|
||||||
type GridRowWithVerification = Record<string, string | number> & {
|
type GridRowWithVerification = Record<string, string | number> & {
|
||||||
verificationResult?: ExcretaTreatmentFacilityVerificationResult;
|
verificationResult?: ExcretaTreatmentFacilityVerificationResult;
|
||||||
@@ -102,22 +91,10 @@ const computeTabEnterable = (
|
|||||||
return periodEnterable;
|
return periodEnterable;
|
||||||
};
|
};
|
||||||
|
|
||||||
const sidoListRef: { current: Sido[] } = { current: [] };
|
|
||||||
|
|
||||||
function buildGugunOkForToolbar(values: SearchFormValues | null): boolean {
|
function buildGugunOkForToolbar(values: SearchFormValues | null): boolean {
|
||||||
return isGugunOkForToolbar(sidoListRef.current, values);
|
return doList.includes(values?.bsnmCd || "")
|
||||||
}
|
? Boolean(values?.gugun && values.gugun !== "ALL")
|
||||||
|
: true;
|
||||||
function buildSubmitOkForToolbar(values: SearchFormValues | null): boolean {
|
|
||||||
return isSubmitOkForToolbar(sidoListRef.current, values);
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildNoApplicableForRequest(
|
|
||||||
values: SearchFormValues | null,
|
|
||||||
checked: boolean,
|
|
||||||
isSaveListEmpty: boolean,
|
|
||||||
): boolean {
|
|
||||||
return resolveNoApplicableForRequest(sidoListRef.current, values, checked, isSaveListEmpty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeTabToolbarSnapshot(
|
function computeTabToolbarSnapshot(
|
||||||
@@ -131,7 +108,7 @@ function computeTabToolbarSnapshot(
|
|||||||
const gugunOk = buildGugunOkForToolbar(searchContext);
|
const gugunOk = buildGugunOkForToolbar(searchContext);
|
||||||
const enterable = computeTabEnterable(statusInfo, periodEnterable);
|
const enterable = computeTabEnterable(statusInfo, periodEnterable);
|
||||||
const isSubmitted = statusInfo?.laeSbmsnSttsCd === "2";
|
const isSubmitted = statusInfo?.laeSbmsnSttsCd === "2";
|
||||||
const showSaveInToolbar = (enterable || isAdminInfo) && periodEnterable && gugunOk;
|
const showSaveInToolbar = (enterable || isAdminInfo) && gugunOk;
|
||||||
const showEnterableToolbarButtons = enterable && gugunOk;
|
const showEnterableToolbarButtons = enterable && gugunOk;
|
||||||
const showSubmittedInInputPeriodToolbar =
|
const showSubmittedInInputPeriodToolbar =
|
||||||
isSubmitted && periodEnterable && gugunOk;
|
isSubmitted && periodEnterable && gugunOk;
|
||||||
@@ -151,8 +128,9 @@ function buildExcretaTreatmentFacilitySearchParam(
|
|||||||
const fcltNm = values.fctName?.trim();
|
const fcltNm = values.fctName?.trim();
|
||||||
return {
|
return {
|
||||||
statsYr: values.year,
|
statsYr: values.year,
|
||||||
|
sewerBzmnCd: values.bsnmCd,
|
||||||
ctpvNm: values.sido,
|
ctpvNm: values.sido,
|
||||||
...toInputSearchRegion(sidoListRef.current, values),
|
sggNm: values.gugun === "ALL" ? "" : values.gugun,
|
||||||
...(fcltNm ? { fcltNm } : {}),
|
...(fcltNm ? { fcltNm } : {}),
|
||||||
...(overrides?.mode ? { mode: overrides.mode } : {}),
|
...(overrides?.mode ? { mode: overrides.mode } : {}),
|
||||||
};
|
};
|
||||||
@@ -213,6 +191,13 @@ function mapExcretaTreatmentFacilityListToGridRows(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function nullableTrimmedString(
|
||||||
|
value: string | number | null | undefined,
|
||||||
|
): string | null {
|
||||||
|
const s = String(value ?? "").trim();
|
||||||
|
return s === "" ? null : s;
|
||||||
|
}
|
||||||
|
|
||||||
function toGridNumber(value: string | number | null | undefined): number {
|
function toGridNumber(value: string | number | null | undefined): number {
|
||||||
const n = Number(value);
|
const n = Number(value);
|
||||||
return Number.isFinite(n) ? n : 0;
|
return Number.isFinite(n) ? n : 0;
|
||||||
@@ -225,9 +210,9 @@ function toApiYmd(value: string | number | Date | null | undefined): string | nu
|
|||||||
function resolveExcretaTreatmentFacilityAdmdst(
|
function resolveExcretaTreatmentFacilityAdmdst(
|
||||||
row: Record<string, string | number>,
|
row: Record<string, string | number>,
|
||||||
sggOptions: Sgg[],
|
sggOptions: Sgg[],
|
||||||
): { admdstCd: string | null; admdstNm: string | null } {
|
): { admdstCd: string; admdstNm: string } {
|
||||||
const existingCd = nullableTrimmedString(row.admdstCd);
|
const existingCd = String(row.admdstCd ?? "").trim();
|
||||||
const existingNm = nullableTrimmedString(row.admdstNm);
|
const existingNm = String(row.admdstNm ?? "").trim();
|
||||||
if (existingCd && existingNm) {
|
if (existingCd && existingNm) {
|
||||||
return { admdstCd: existingCd, admdstNm: existingNm };
|
return { admdstCd: existingCd, admdstNm: existingNm };
|
||||||
}
|
}
|
||||||
@@ -236,10 +221,7 @@ function resolveExcretaTreatmentFacilityAdmdst(
|
|||||||
if (matched) {
|
if (matched) {
|
||||||
return { admdstCd: matched.bsnmCd, admdstNm: matched.gugun };
|
return { admdstCd: matched.bsnmCd, admdstNm: matched.gugun };
|
||||||
}
|
}
|
||||||
return {
|
return { admdstCd: existingCd, admdstNm: existingNm || sggNm };
|
||||||
admdstCd: existingCd,
|
|
||||||
admdstNm: existingNm ?? nullableTrimmedString(sggNm),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 그리드 행 → ST00070001 저장/삭제 API 항목 */
|
/** 그리드 행 → ST00070001 저장/삭제 API 항목 */
|
||||||
@@ -254,18 +236,18 @@ function buildExcretaTreatmentFacilitySaveItem(
|
|||||||
return {
|
return {
|
||||||
admdstCd,
|
admdstCd,
|
||||||
admdstNm,
|
admdstNm,
|
||||||
fcltSn: nullableTrimmedString(row.fcltSn),
|
fcltSn: String(row.fcltSn ?? "").trim(),
|
||||||
fcltNm: nullableTrimmedString(row.fcltNm),
|
fcltNm: String(row.fcltNm ?? ""),
|
||||||
fcltPstnCn: nullableTrimmedString(row.fcltPstnCn),
|
fcltPstnCn: String(row.fcltPstnCn ?? ""),
|
||||||
telNo: nullableTrimmedString(row.telNo),
|
telNo: String(row.telNo ?? ""),
|
||||||
cmptnStrtYmd: toApiYmd(row.cmptnStrtYmd),
|
cmptnStrtYmd: toApiYmd(row.cmptnStrtYmd),
|
||||||
oprtngStrtYmd: toApiYmd(row.oprtngStrtYmd),
|
oprtngStrtYmd: toApiYmd(row.oprtngStrtYmd),
|
||||||
wholPjtcoAmt: toGridNumber(row.wholPjtcoAmt),
|
wholPjtcoAmt: toGridNumber(row.wholPjtcoAmt),
|
||||||
prcsFcltCpct: toGridNumber(row.prcsFcltCpct),
|
prcsFcltCpct: toGridNumber(row.prcsFcltCpct),
|
||||||
cpct: toGridNumber(row.cpct),
|
cpct: toGridNumber(row.cpct),
|
||||||
oprtngDayCnt: toGridNumber(row.oprtngDayCnt),
|
oprtngDayCnt: toGridNumber(row.oprtngDayCnt),
|
||||||
prcsMthdExpln: nullableTrimmedString(row.prcsMthdExpln),
|
prcsMthdExpln: String(row.prcsMthdExpln ?? ""),
|
||||||
linkTmplntCn: nullableTrimmedString(row.linkTmplntCn),
|
linkTmplntCn: String(row.linkTmplntCn ?? ""),
|
||||||
linkPrcsQnt: toGridNumber(row.linkPrcsQnt),
|
linkPrcsQnt: toGridNumber(row.linkPrcsQnt),
|
||||||
inflwBodWqVl: toGridNumber(row.inflwBodWqVl),
|
inflwBodWqVl: toGridNumber(row.inflwBodWqVl),
|
||||||
inflwTocWqVl: toGridNumber(row.inflwTocWqVl),
|
inflwTocWqVl: toGridNumber(row.inflwTocWqVl),
|
||||||
@@ -279,11 +261,11 @@ function buildExcretaTreatmentFacilitySaveItem(
|
|||||||
dschgTnWqVl: toGridNumber(row.dschgTnWqVl),
|
dschgTnWqVl: toGridNumber(row.dschgTnWqVl),
|
||||||
dschgTpWqVl: toGridNumber(row.dschgTpWqVl),
|
dschgTpWqVl: toGridNumber(row.dschgTpWqVl),
|
||||||
dschgClfgCnt: toGridNumber(row.dschgClfgCnt),
|
dschgClfgCnt: toGridNumber(row.dschgClfgCnt),
|
||||||
wtsysNm: nullableTrimmedString(row.wtsysNm),
|
wtsysNm: String(row.wtsysNm ?? ""),
|
||||||
trbtrNm: nullableTrimmedString(row.trbtrNm),
|
trbtrNm: String(row.trbtrNm ?? ""),
|
||||||
msirbCn: nullableTrimmedString(row.msirbCn),
|
msirbCn: String(row.msirbCn ?? ""),
|
||||||
ssirbCn: nullableTrimmedString(row.ssirbCn),
|
ssirbCn: String(row.ssirbCn ?? ""),
|
||||||
operMthdCdCn: nullableTrimmedString(row.operMthdCdCn),
|
operMthdCdCn: String(row.operMthdCdCn ?? ""),
|
||||||
wholNope: toGridNumber(row.wholNope),
|
wholNope: toGridNumber(row.wholNope),
|
||||||
sftyAcdntEvntcsCnt: toGridNumber(row.sftyAcdntEvntcsCnt),
|
sftyAcdntEvntcsCnt: toGridNumber(row.sftyAcdntEvntcsCnt),
|
||||||
rmrk: nullableTrimmedString(row.rmrk),
|
rmrk: nullableTrimmedString(row.rmrk),
|
||||||
@@ -308,11 +290,11 @@ async function waitForImrJobCompleted(
|
|||||||
options?.onProgress?.(Math.max(0, Math.min(100, Number(res.job_prog) || 0)));
|
options?.onProgress?.(Math.max(0, Math.min(100, Number(res.job_prog) || 0)));
|
||||||
if (res.status === "COMPLETED" && Number(res.job_prog) === 100) return;
|
if (res.status === "COMPLETED" && Number(res.job_prog) === 100) return;
|
||||||
if (res.status === "FAILED" || res.status === "ERROR" || res.status === "CANCELLED") {
|
if (res.status === "FAILED" || res.status === "ERROR" || res.status === "CANCELLED") {
|
||||||
throw new Error(res.error_msg || `시계열 검증이 ${res.status} 상태로 종료되었습니다.`);
|
throw new Error(res.error_msg || `IMR 검증이 ${res.status} 상태로 종료되었습니다.`);
|
||||||
}
|
}
|
||||||
await sleep(pollIntervalMs);
|
await sleep(pollIntervalMs);
|
||||||
}
|
}
|
||||||
throw new Error("시계열 검증 완료 대기 시간이 초과되었습니다.");
|
throw new Error("IMR 검증 완료 대기 시간이 초과되었습니다.");
|
||||||
}
|
}
|
||||||
|
|
||||||
function createEmptyExcretaTreatmentFacilityRow(
|
function createEmptyExcretaTreatmentFacilityRow(
|
||||||
@@ -334,8 +316,6 @@ const EXCRETA_TREATMENT_FACILITY_NAME_GUIDE_MESSAGE =
|
|||||||
|
|
||||||
// 하수도 통계 관리 > 07. 분뇨처리시설
|
// 하수도 통계 관리 > 07. 분뇨처리시설
|
||||||
const ExcretaTreatmentFacilityInp = () => {
|
const ExcretaTreatmentFacilityInp = () => {
|
||||||
const { sidoList } = useSearchConditionSidoList({ isInput: true });
|
|
||||||
sidoListRef.current = sidoList;
|
|
||||||
const { setMessage: alert } = useAlertStore((state) => state);
|
const { setMessage: alert } = useAlertStore((state) => state);
|
||||||
const { confirm } = useConfirm();
|
const { confirm } = useConfirm();
|
||||||
const { isAdminInfo } = useAdminStore();
|
const { isAdminInfo } = useAdminStore();
|
||||||
@@ -358,8 +338,6 @@ const ExcretaTreatmentFacilityInp = () => {
|
|||||||
const [statusInfo, setStatusInfo] = useState<SewerageStatusInfo | null>(null);
|
const [statusInfo, setStatusInfo] = useState<SewerageStatusInfo | null>(null);
|
||||||
const [statsCd, setStatsCd] = useState("");
|
const [statsCd, setStatsCd] = useState("");
|
||||||
const [isVerificationFailed, setIsVerificationFailed] = useState(false);
|
const [isVerificationFailed, setIsVerificationFailed] = useState(false);
|
||||||
const [footerVerificationResult, setFooterVerificationResult] =
|
|
||||||
useState<VerificationResultLikeMap | null>(null);
|
|
||||||
const [inputPeriodEnterable, setInputPeriodEnterable] = useState(true);
|
const [inputPeriodEnterable, setInputPeriodEnterable] = useState(true);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [sggOptions, setSggOptions] = useState<Sgg[]>([]);
|
const [sggOptions, setSggOptions] = useState<Sgg[]>([]);
|
||||||
@@ -378,10 +356,7 @@ const ExcretaTreatmentFacilityInp = () => {
|
|||||||
const sggOptionsSidoRef = useRef<string | null>(null);
|
const sggOptionsSidoRef = useRef<string | null>(null);
|
||||||
const [searchLoaded, setSearchLoaded] = useState(false);
|
const [searchLoaded, setSearchLoaded] = useState(false);
|
||||||
|
|
||||||
const activeTabId = useTabStore((s) => s.activeTabId);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeTabId !== STATISTICS_INPUT_URL_PATH.EXCRETA_TREATMENT_FACILITY) return;
|
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
void (async () => {
|
void (async () => {
|
||||||
try {
|
try {
|
||||||
@@ -407,7 +382,7 @@ const ExcretaTreatmentFacilityInp = () => {
|
|||||||
return () => {
|
return () => {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
};
|
};
|
||||||
}, [activeTabId]);
|
}, []);
|
||||||
|
|
||||||
const loadSggOptions = useCallback(async (sido: string): Promise<Sgg[]> => {
|
const loadSggOptions = useCallback(async (sido: string): Promise<Sgg[]> => {
|
||||||
if (!sido || sido === "ALL") {
|
if (!sido || sido === "ALL") {
|
||||||
@@ -427,7 +402,7 @@ const ExcretaTreatmentFacilityInp = () => {
|
|||||||
|
|
||||||
const columnInfo = useMemo(() => {
|
const columnInfo = useMemo(() => {
|
||||||
const enterable =
|
const enterable =
|
||||||
(computeTabEnterable(statusInfo, inputPeriodEnterable) || isAdminInfo) && inputPeriodEnterable;
|
computeTabEnterable(statusInfo, inputPeriodEnterable) || isAdminInfo;
|
||||||
const rawColumns = ExcretaTreatFactInpColumn.columns ?? [];
|
const rawColumns = ExcretaTreatFactInpColumn.columns ?? [];
|
||||||
const base = enterable
|
const base = enterable
|
||||||
? rawColumns
|
? rawColumns
|
||||||
@@ -455,7 +430,7 @@ const ExcretaTreatmentFacilityInp = () => {
|
|||||||
}, [statusInfo, inputPeriodEnterable, isAdminInfo, sggOptions, columnGuidesByEngCol]);
|
}, [statusInfo, inputPeriodEnterable, isAdminInfo, sggOptions, columnGuidesByEngCol]);
|
||||||
|
|
||||||
const canEditGrid =
|
const canEditGrid =
|
||||||
(computeTabEnterable(statusInfo, inputPeriodEnterable) || isAdminInfo) && inputPeriodEnterable;
|
computeTabEnterable(statusInfo, inputPeriodEnterable) || isAdminInfo;
|
||||||
|
|
||||||
const getCurrentRows = (): Record<string, string | number>[] =>
|
const getCurrentRows = (): Record<string, string | number>[] =>
|
||||||
gridGetRowsRef.current?.() ?? rowData;
|
gridGetRowsRef.current?.() ?? rowData;
|
||||||
@@ -491,18 +466,13 @@ const ExcretaTreatmentFacilityInp = () => {
|
|||||||
statusInfo: nextStatusInfo,
|
statusInfo: nextStatusInfo,
|
||||||
excretaTreatmentFacilityList,
|
excretaTreatmentFacilityList,
|
||||||
} = response.data;
|
} = response.data;
|
||||||
const list = filterBySelectedAdmdstCd(
|
const list = excretaTreatmentFacilityList ?? [];
|
||||||
excretaTreatmentFacilityList ?? [],
|
|
||||||
sidoListRef.current,
|
|
||||||
values,
|
|
||||||
);
|
|
||||||
const gridRows = mapExcretaTreatmentFacilityListToGridRows(list, commonInfo.ctpvNm);
|
const gridRows = mapExcretaTreatmentFacilityListToGridRows(list, commonInfo.ctpvNm);
|
||||||
|
|
||||||
setRowData(gridRows);
|
setRowData(gridRows);
|
||||||
setStatusInfo(nextStatusInfo);
|
setStatusInfo(nextStatusInfo);
|
||||||
setStatsCd(commonInfo.statsCd);
|
setStatsCd(commonInfo.statsCd);
|
||||||
setIsVerificationFailed(isVerificationFailedFromCommonInfo(commonInfo));
|
setIsVerificationFailed(isVerificationFailedFromCommonInfo(commonInfo));
|
||||||
setFooterVerificationResult(commonInfo.verificationResult ?? null);
|
|
||||||
if (overrides?.mode !== "PRE") {
|
if (overrides?.mode !== "PRE") {
|
||||||
setIsNotApplicable(gridRows.length === 0);
|
setIsNotApplicable(gridRows.length === 0);
|
||||||
} else if (gridRows.length > 0) {
|
} else if (gridRows.length > 0) {
|
||||||
@@ -562,7 +532,6 @@ const ExcretaTreatmentFacilityInp = () => {
|
|||||||
setStatusInfo(null);
|
setStatusInfo(null);
|
||||||
setStatsCd("");
|
setStatsCd("");
|
||||||
setIsVerificationFailed(false);
|
setIsVerificationFailed(false);
|
||||||
setFooterVerificationResult(null);
|
|
||||||
setIsNotApplicable(false);
|
setIsNotApplicable(false);
|
||||||
setInputPeriodEnterable(true);
|
setInputPeriodEnterable(true);
|
||||||
setSggOptions([]);
|
setSggOptions([]);
|
||||||
@@ -612,8 +581,12 @@ const ExcretaTreatmentFacilityInp = () => {
|
|||||||
|
|
||||||
const userInfo = await getUserInfo();
|
const userInfo = await getUserInfo();
|
||||||
const requestData: cancelSubmitRequest = {
|
const requestData: cancelSubmitRequest = {
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
mdfrId: userInfo.userUnqId,
|
mdfrId: userInfo.userUnqId,
|
||||||
statsCd: statsCd || EXCRETA_TREATMENT_FACILITY_STATS_CD,
|
statsCd: statsCd || EXCRETA_TREATMENT_FACILITY_STATS_CD,
|
||||||
@@ -649,7 +622,7 @@ const ExcretaTreatmentFacilityInp = () => {
|
|||||||
if (!(await confirm("저장 하시겠습니까?"))) return;
|
if (!(await confirm("저장 하시겠습니까?"))) return;
|
||||||
|
|
||||||
commitGrid();
|
commitGrid();
|
||||||
const noApplicable = buildNoApplicableForRequest(lastSearchedValues, isNotApplicable, getCurrentRows().length === 0);
|
const noApplicable = isNotApplicable;
|
||||||
const currentData = getCurrentRows();
|
const currentData = getCurrentRows();
|
||||||
const saveList = noApplicable
|
const saveList = noApplicable
|
||||||
? []
|
? []
|
||||||
@@ -660,7 +633,7 @@ const ExcretaTreatmentFacilityInp = () => {
|
|||||||
.filter((row) => String(row.fcltSn ?? "").trim() !== "")
|
.filter((row) => String(row.fcltSn ?? "").trim() !== "")
|
||||||
.map((row) => buildExcretaTreatmentFacilitySaveItem(row, sggOptions));
|
.map((row) => buildExcretaTreatmentFacilitySaveItem(row, sggOptions));
|
||||||
|
|
||||||
if (!noApplicable && saveList.length === 0 && buildSubmitOkForToolbar(lastSearchedValues)) {
|
if (!noApplicable && saveList.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -673,7 +646,11 @@ const ExcretaTreatmentFacilityInp = () => {
|
|||||||
{
|
{
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
userId: userInfo.userUnqId,
|
userId: userInfo.userUnqId,
|
||||||
...(isAdminInfo ? { superAdmin: "superAdmin" } : {}),
|
...(isAdminInfo ? { superAdmin: "superAdmin" } : {}),
|
||||||
noApplicable,
|
noApplicable,
|
||||||
@@ -709,9 +686,9 @@ const ExcretaTreatmentFacilityInp = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const noApplicable = buildNoApplicableForRequest(lastSearchedValues, isNotApplicable, getCurrentRows().length === 0);
|
const noApplicable = isNotApplicable;
|
||||||
const currentData = getCurrentRows();
|
const currentData = getCurrentRows();
|
||||||
if (!noApplicable && currentData.length === 0 && buildSubmitOkForToolbar(lastSearchedValues)) {
|
if (!noApplicable && currentData.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -736,7 +713,7 @@ const ExcretaTreatmentFacilityInp = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
commitGrid();
|
commitGrid();
|
||||||
const noApplicable = buildNoApplicableForRequest(lastSearchedValues, isNotApplicable, getCurrentRows().length === 0);
|
const noApplicable = isNotApplicable;
|
||||||
const currentData = getCurrentRows();
|
const currentData = getCurrentRows();
|
||||||
const submitList = noApplicable
|
const submitList = noApplicable
|
||||||
? []
|
? []
|
||||||
@@ -747,15 +724,19 @@ const ExcretaTreatmentFacilityInp = () => {
|
|||||||
.filter((row) => String(row.fcltSn ?? "").trim() !== "")
|
.filter((row) => String(row.fcltSn ?? "").trim() !== "")
|
||||||
.map((row) => buildExcretaTreatmentFacilitySaveItem(row, sggOptions));
|
.map((row) => buildExcretaTreatmentFacilitySaveItem(row, sggOptions));
|
||||||
|
|
||||||
if (!noApplicable && submitList.length === 0 && buildSubmitOkForToolbar(lastSearchedValues)) {
|
if (!noApplicable && submitList.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const statsCdForSubmit = statsCd || EXCRETA_TREATMENT_FACILITY_STATS_CD;
|
const statsCdForSubmit = statsCd || EXCRETA_TREATMENT_FACILITY_STATS_CD;
|
||||||
const verificationQuery = {
|
const verificationQuery = {
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
statsCd: statsCdForSubmit,
|
statsCd: statsCdForSubmit,
|
||||||
};
|
};
|
||||||
@@ -774,7 +755,11 @@ const ExcretaTreatmentFacilityInp = () => {
|
|||||||
{
|
{
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
userId: userInfo.userUnqId,
|
userId: userInfo.userUnqId,
|
||||||
laePicNm: submitInfo.laePicNm,
|
laePicNm: submitInfo.laePicNm,
|
||||||
laePicTelNo: submitInfo.laePicTelNo,
|
laePicTelNo: submitInfo.laePicTelNo,
|
||||||
@@ -801,16 +786,15 @@ const ExcretaTreatmentFacilityInp = () => {
|
|||||||
|
|
||||||
if (finalStatus === "5") {
|
if (finalStatus === "5") {
|
||||||
setGlobalProgress(50);
|
setGlobalProgress(50);
|
||||||
setGlobalProgressLabel("시계열 검증 진행 중...");
|
setGlobalProgressLabel("IMR 검증 진행 중...");
|
||||||
const imrParam = {
|
const imrParam = {
|
||||||
user_id: userInfo.userUnqId,
|
user_id: userInfo.userUnqId,
|
||||||
sewer_bzmn_cd: lastSearchedValues?.bsnmCd ?? "",
|
sewer_bzmn_cd: lastSearchedValues.bsnmCd ?? "",
|
||||||
stats_cd: statsCdForSubmit,
|
stats_cd: statsCdForSubmit,
|
||||||
stats_yr: lastSearchedValues.year ?? "",
|
stats_yr: lastSearchedValues.year ?? "",
|
||||||
lae_sbmsn_stts_cd:
|
lae_sbmsn_stts_cd:
|
||||||
statusInfo?.laeSbmsnSttsCd === "4" ? "4" : "2",
|
statusInfo?.laeSbmsnSttsCd === "4" ? "4" : "2",
|
||||||
gen_verify_stts_cd: nvpassed ? "1" : "2",
|
gen_verify_stts_cd: nvpassed ? "1" : "2",
|
||||||
hb_pass_yn: response.data?.isHbPassed,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -957,10 +941,10 @@ const ExcretaTreatmentFacilityInp = () => {
|
|||||||
.map((e) => {
|
.map((e) => {
|
||||||
const prefix =
|
const prefix =
|
||||||
e.vrfcCd === "IMR"
|
e.vrfcCd === "IMR"
|
||||||
? "시계열 검증 - "
|
? "IMR검증 - "
|
||||||
: e.vrfcCd === "NV"
|
: e.vrfcCd === "NV"
|
||||||
? "일반검증 - "
|
? "일반검증 - "
|
||||||
: "모집단 검증 -";
|
: "HB검증 -";
|
||||||
return `${prefix}${e.rsnExpln}
|
return `${prefix}${e.rsnExpln}
|
||||||
(검증 기준값: ${e.compVlCn} / 현재 입력값: ${e.nowVlCn})`;
|
(검증 기준값: ${e.compVlCn} / 현재 입력값: ${e.nowVlCn})`;
|
||||||
})
|
})
|
||||||
@@ -969,7 +953,7 @@ const ExcretaTreatmentFacilityInp = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const searchContextForToolbar = lastSearchedValues;
|
const searchContextForToolbar = lastSearchedValues ?? searchValues;
|
||||||
const toolbarSnapshot = computeTabToolbarSnapshot(
|
const toolbarSnapshot = computeTabToolbarSnapshot(
|
||||||
statusInfo,
|
statusInfo,
|
||||||
rowData.length > 0,
|
rowData.length > 0,
|
||||||
@@ -989,23 +973,23 @@ const ExcretaTreatmentFacilityInp = () => {
|
|||||||
hasSearched &&
|
hasSearched &&
|
||||||
toolbarGroupAllowed &&
|
toolbarGroupAllowed &&
|
||||||
(showSaveInToolbar || showEnterableToolbarButtons);
|
(showSaveInToolbar || showEnterableToolbarButtons);
|
||||||
const tabEnterableForGrid =
|
|
||||||
(computeTabEnterable(statusInfo, inputPeriodEnterable) || isAdminInfo) && inputPeriodEnterable;
|
|
||||||
const gugunOk = buildGugunOkForToolbar(searchContextForToolbar);
|
|
||||||
const submitOk = buildSubmitOkForToolbar(searchContextForToolbar);
|
|
||||||
const showNotApplicable =
|
const showNotApplicable =
|
||||||
searchLoaded &&
|
searchLoaded &&
|
||||||
hasSearched &&
|
hasSearched &&
|
||||||
rowData.length === 0 &&
|
rowData.length === 0 &&
|
||||||
computeTabEnterable(statusInfo, inputPeriodEnterable) &&
|
computeTabEnterable(statusInfo, inputPeriodEnterable);
|
||||||
submitOk;
|
|
||||||
|
const tabEnterableForGrid =
|
||||||
|
computeTabEnterable(statusInfo, inputPeriodEnterable) || isAdminInfo;
|
||||||
|
const gugunOk = buildGugunOkForToolbar(lastSearchedValues);
|
||||||
|
|
||||||
const verificationQueryContext = (() => {
|
const verificationQueryContext = (() => {
|
||||||
const ctx = lastSearchedValues ?? searchValues;
|
const ctx = lastSearchedValues ?? searchValues;
|
||||||
if (!ctx?.year || !ctx?.sido || !ctx?.bsnmCd || !statsCd) return null;
|
if (!ctx?.year || !ctx?.sido || !ctx?.bsnmCd || !statsCd) return null;
|
||||||
return {
|
return {
|
||||||
...toInputSearchRegion(sidoListRef.current, ctx),
|
sewerBzmnCd: ctx.bsnmCd,
|
||||||
ctpvNm: ctx.sido,
|
ctpvNm: ctx.sido,
|
||||||
|
sggNm: ctx.gugun === "ALL" ? "" : (ctx.gugun ?? ""),
|
||||||
statsYr: ctx.year,
|
statsYr: ctx.year,
|
||||||
statsCd,
|
statsCd,
|
||||||
};
|
};
|
||||||
@@ -1021,7 +1005,6 @@ const ExcretaTreatmentFacilityInp = () => {
|
|||||||
<>
|
<>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<SearchForm
|
<SearchForm
|
||||||
isInput
|
|
||||||
key={searchFormRemountKey}
|
key={searchFormRemountKey}
|
||||||
defaultValues={verificationSearchDefaults ?? undefined}
|
defaultValues={verificationSearchDefaults ?? undefined}
|
||||||
fctName={true}
|
fctName={true}
|
||||||
@@ -1030,7 +1013,7 @@ const ExcretaTreatmentFacilityInp = () => {
|
|||||||
onValuesChange={setSearchValues}
|
onValuesChange={setSearchValues}
|
||||||
/>
|
/>
|
||||||
{showActionToolbarCard && (
|
{showActionToolbarCard && (
|
||||||
<div className="card !py-0">
|
<div className="card !py-0">
|
||||||
<div className="m-[0.6rem] flex items-center justify-end gap-[0.6rem]">
|
<div className="m-[0.6rem] flex items-center justify-end gap-[0.6rem]">
|
||||||
<VerificationResultButton
|
<VerificationResultButton
|
||||||
VerificationResultButtonFunc={openVerificationHistoryDialog}
|
VerificationResultButtonFunc={openVerificationHistoryDialog}
|
||||||
@@ -1041,18 +1024,18 @@ const ExcretaTreatmentFacilityInp = () => {
|
|||||||
<LastYearDataButton
|
<LastYearDataButton
|
||||||
getLastYearDataFunc={() => void getLastYearDataFunc()}
|
getLastYearDataFunc={() => void getLastYearDataFunc()}
|
||||||
/>
|
/>
|
||||||
{submitOk && <SubmitButton submitFunc={submitFunc} />}
|
<SubmitButton submitFunc={submitFunc} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{statusInfo?.laeSbmsnSttsCd === "2" && submitOk && (
|
{statusInfo?.laeSbmsnSttsCd === "2" && (
|
||||||
<CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />
|
<CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />
|
||||||
)}
|
)}
|
||||||
{showSaveInToolbar && <SaveButton saveFunc={saveFunc} />}
|
{showSaveInToolbar && <SaveButton saveFunc={saveFunc} />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{showArticleToolbarCard && (
|
{showArticleToolbarCard && (
|
||||||
<div className="card !py-0">
|
<div className="card !py-0">
|
||||||
<div className="m-[0.6rem] flex items-center justify-end gap-[0.6rem]">
|
<div className="m-[0.6rem] flex items-center justify-end gap-[0.6rem]">
|
||||||
{showNotApplicable && (
|
{showNotApplicable && (
|
||||||
<NotApplicableCheckButton
|
<NotApplicableCheckButton
|
||||||
@@ -1060,10 +1043,10 @@ const ExcretaTreatmentFacilityInp = () => {
|
|||||||
setIsCheck={setIsNotApplicable}
|
setIsCheck={setIsNotApplicable}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<AddArticleButton addArticleFunc={addArticleFunc} />
|
<AddArticleButton addArticleFunc={addArticleFunc} />
|
||||||
<DeleteArticleButton deleteArticleFunc={deleteArticleFunc} />
|
<DeleteArticleButton deleteArticleFunc={deleteArticleFunc} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div className="absolute inset-0 z-50 flex items-center justify-center rounded-lg p-10 [data-theme='black']:bg-transparent">
|
<div className="absolute inset-0 z-50 flex items-center justify-center rounded-lg p-10 [data-theme='black']:bg-transparent">
|
||||||
@@ -1072,14 +1055,14 @@ const ExcretaTreatmentFacilityInp = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<DataGrid
|
<DataGrid
|
||||||
key={canEditGrid ? "enterable" : "readonly"}
|
key={canEditGrid ? "enterable" : "readonly"}
|
||||||
getGridRef={gridRef as RefObject<RealGridReact | null>}
|
getGridRef={gridRef as RefObject<RealGridReact | null>}
|
||||||
columnInfo={columnInfo}
|
columnInfo={columnInfo}
|
||||||
rowStartNum={ExcretaTreatFactInpColumn.rowStartNum}
|
rowStartNum={ExcretaTreatFactInpColumn.rowStartNum}
|
||||||
fixedColumns={ExcretaTreatFactInpColumn.fixedColumns}
|
fixedColumns={ExcretaTreatFactInpColumn.fixedColumns}
|
||||||
rowData={rowData}
|
rowData={rowData}
|
||||||
setRowData={setRowData}
|
setRowData={setRowData}
|
||||||
getGridDataRef={gridGetRowsRef}
|
getGridDataRef={gridGetRowsRef}
|
||||||
showHeaderCheckbox
|
showHeaderCheckbox
|
||||||
statusInfo={statusInfo}
|
statusInfo={statusInfo}
|
||||||
@@ -1089,7 +1072,6 @@ const ExcretaTreatmentFacilityInp = () => {
|
|||||||
excelImportSewerBzmnCd={(lastSearchedValues ?? searchValues)?.bsnmCd}
|
excelImportSewerBzmnCd={(lastSearchedValues ?? searchValues)?.bsnmCd}
|
||||||
excelExportSearchContext={toExcelExportSearchContextFromSearchForm(lastSearchedValues ?? searchValues)}
|
excelExportSearchContext={toExcelExportSearchContextFromSearchForm(lastSearchedValues ?? searchValues)}
|
||||||
cellStyleCallback={verificationCellStyle}
|
cellStyleCallback={verificationCellStyle}
|
||||||
footerVerificationResult={footerVerificationResult}
|
|
||||||
cellTooltipCallback={verificationCellTooltip}
|
cellTooltipCallback={verificationCellTooltip}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
import dayjs from "dayjs";
|
|
||||||
import { CalendarIcon } from "lucide-react";
|
import { CalendarIcon } from "lucide-react";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
import { useAlertStore } from "@/shared/lib";
|
import { useAlertStore } from "@/shared/lib";
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useEffect, useMemo, useRef, useState } from "react";
|
|||||||
|
|
||||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||||
|
|
||||||
import { useAlertStore, useGlobalProgressStore, useSearchConditionSidoList } from "@/shared/lib";
|
import { useAlertStore, useGlobalProgressStore } from "@/shared/lib";
|
||||||
import { STATISTICS_INPUT_URL_PATH } from "@/shared/lib/stats-cd-input-navigation";
|
import { STATISTICS_INPUT_URL_PATH } from "@/shared/lib/stats-cd-input-navigation";
|
||||||
import { useStatisticsInputPendingNavigation } from "@/shared/lib/use-statistics-input-pending-navigation";
|
import { useStatisticsInputPendingNavigation } from "@/shared/lib/use-statistics-input-pending-navigation";
|
||||||
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
||||||
@@ -10,20 +10,20 @@ import { statisticsInputPrivateSewageFacilityApi } from "@/entities/statistics/a
|
|||||||
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
import type {
|
import type {
|
||||||
PrivateSewageDesigStatusItem,
|
|
||||||
PrivateSewageDesigStatusSaveItem,
|
PrivateSewageDesigStatusSaveItem,
|
||||||
|
PrivateSewageFacilityVerificationResult,
|
||||||
|
PrivateSewageDesigStatusItem,
|
||||||
PrivateSewageDesigStatusSaveRequest,
|
PrivateSewageDesigStatusSaveRequest,
|
||||||
PrivateSewageDesigStatusSubmitRequest,
|
PrivateSewageDesigStatusSubmitRequest,
|
||||||
PrivateSewageFacilityVerificationResult,
|
|
||||||
SepticTankStatusItem,
|
|
||||||
SepticTankStatusSaveItem,
|
SepticTankStatusSaveItem,
|
||||||
SepticTankStatusSaveRequest,
|
SepticTankStatusSaveRequest,
|
||||||
SepticTankStatusSubmitRequest,
|
SepticTankStatusSubmitRequest,
|
||||||
SewageTreatFactStatusItem,
|
SewageTreatFactStatusItem,
|
||||||
SewageTreatFactStatusRequestParams,
|
|
||||||
SewageTreatFactStatusSaveItem,
|
SewageTreatFactStatusSaveItem,
|
||||||
SewageTreatFactStatusSaveRequest,
|
SewageTreatFactStatusSaveRequest,
|
||||||
SewageTreatFactStatusSubmitRequest,
|
SewageTreatFactStatusSubmitRequest,
|
||||||
|
SepticTankStatusItem,
|
||||||
|
SewageTreatFactStatusRequestParams,
|
||||||
} from "@/entities/statistics/model/input/statistics-input-private-sewage-facility-interface";
|
} from "@/entities/statistics/model/input/statistics-input-private-sewage-facility-interface";
|
||||||
import { isInputPeriodCurrent } from "@/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface";
|
import { isInputPeriodCurrent } from "@/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface";
|
||||||
import type { StatisticsInputSubmitInfoFormData } from "@/entities/statistics/model/statistics-input-submit-info-schema";
|
import type { StatisticsInputSubmitInfoFormData } from "@/entities/statistics/model/statistics-input-submit-info-schema";
|
||||||
@@ -31,15 +31,7 @@ import type {
|
|||||||
cancelSubmitRequest,
|
cancelSubmitRequest,
|
||||||
ImrStatusResponse,
|
ImrStatusResponse,
|
||||||
SewerageStatusInfo,
|
SewerageStatusInfo,
|
||||||
Sido,
|
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
} from "@/entities/statistics/model/statistics-interface";
|
||||||
import {
|
|
||||||
filterBySelectedAdmdstCd,
|
|
||||||
isGugunOkForToolbar,
|
|
||||||
isSubmitOkForToolbar,
|
|
||||||
toInputSearchRegion,
|
|
||||||
} from "@/entities/statistics";
|
|
||||||
|
|
||||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||||
|
|
||||||
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
||||||
@@ -47,31 +39,25 @@ import { getUserInfo } from "../../../../../../packages/common/components/src/ap
|
|||||||
import SubmitDailog from "./SubmitDailog";
|
import SubmitDailog from "./SubmitDailog";
|
||||||
|
|
||||||
import CancelSubmitButton from "@/components/button/CancelSubmitButton";
|
import CancelSubmitButton from "@/components/button/CancelSubmitButton";
|
||||||
import LastYearDataButton from "@/components/button/LastYearDataButton";
|
|
||||||
import SaveButton from "@/components/button/SaveButton";
|
|
||||||
import SubmitButton from "@/components/button/SumitButton";
|
import SubmitButton from "@/components/button/SumitButton";
|
||||||
|
import SaveButton from "@/components/button/SaveButton";
|
||||||
|
import LastYearDataButton from "@/components/button/LastYearDataButton";
|
||||||
import VerificationResultButton from "@/components/button/VerificationResultButton";
|
import VerificationResultButton from "@/components/button/VerificationResultButton";
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
import { openVerificationResultDialogIfNeeded } from "@/components/module/post-submit-verification-results";
|
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
|
import { openVerificationResultDialogIfNeeded } from "@/components/module/post-submit-verification-results";
|
||||||
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
||||||
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
||||||
import type { ColumnConfig, ColumnInfo } from "@/components/type/DataGrid.type";
|
import type { ColumnConfig, ColumnInfo } from "@/components/type/DataGrid.type";
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
|
import { doList } from "@/components/util/column/input/DoList";
|
||||||
import { PrivateSewageDesigStatusInpColumn } from "@/components/util/column/input/privateSewageFacility/PrivateSewageDesigStatusInpColumn";
|
import { PrivateSewageDesigStatusInpColumn } from "@/components/util/column/input/privateSewageFacility/PrivateSewageDesigStatusInpColumn";
|
||||||
import { SepticTankStatusInpColumn } from "@/components/util/column/input/privateSewageFacility/SepticTankStatusInpColumn";
|
import { SepticTankStatusInpColumn } from "@/components/util/column/input/privateSewageFacility/SepticTankStatusInpColumn";
|
||||||
import { SewageTreatFactStatusInpColumn } from "@/components/util/column/input/privateSewageFacility/SewageTreatFactStatusInpColumn";
|
import { SewageTreatFactStatusInpColumn } from "@/components/util/column/input/privateSewageFacility/SewageTreatFactStatusInpColumn";
|
||||||
import { fetchColumnGuidesRecord } from "@/components/util/grid/columnGuides";
|
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
import { patchVerificationFailedByTab } from "@/components/util/input/verification-failed-flag";
|
||||||
import {
|
|
||||||
patchFooterVerificationByTab,
|
|
||||||
patchVerificationFailedByTab,
|
|
||||||
} from "@/components/util/input/verification-failed-flag";
|
|
||||||
import type { VerificationResultLikeMap } from "@/components/util/input/verification-result-display";
|
|
||||||
import { nullableTrimmedString } from "@/components/util/input/nullableString";
|
|
||||||
import { useAdminStore } from "@/store/admin-store";
|
import { useAdminStore } from "@/store/admin-store";
|
||||||
import { useTabStore } from "@/store/tab-store";
|
|
||||||
|
|
||||||
const PrivateSewageFacilityInpTabList = [
|
const PrivateSewageFacilityInpTabList = [
|
||||||
SewageTreatFactStatusInpColumn,
|
SewageTreatFactStatusInpColumn,
|
||||||
@@ -88,6 +74,10 @@ const PRIVATE_SEWAGE_FACILITY_COLUMN_GUIDE_STATS_CD_BY_TAB_KEY: Record<string, s
|
|||||||
[PrivateSewageDesigStatusInpColumn.tabKey]: "ST00080003",
|
[PrivateSewageDesigStatusInpColumn.tabKey]: "ST00080003",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const PRIVATE_SEWAGE_FACILITY_COLUMN_GUIDE_STATS_CDS = Array.from(
|
||||||
|
new Set(Object.values(PRIVATE_SEWAGE_FACILITY_COLUMN_GUIDE_STATS_CD_BY_TAB_KEY)),
|
||||||
|
);
|
||||||
|
|
||||||
type GridRowWithVerification = Record<string, string | number> & {
|
type GridRowWithVerification = Record<string, string | number> & {
|
||||||
verificationResult?: PrivateSewageFacilityVerificationResult;
|
verificationResult?: PrivateSewageFacilityVerificationResult;
|
||||||
};
|
};
|
||||||
@@ -109,8 +99,9 @@ function buildPrivateSewageFacilitySearchParam(
|
|||||||
): SewageTreatFactStatusRequestParams {
|
): SewageTreatFactStatusRequestParams {
|
||||||
return {
|
return {
|
||||||
statsYr: values.year,
|
statsYr: values.year,
|
||||||
|
sewerBzmnCd: values.bsnmCd,
|
||||||
ctpvNm: values.sido,
|
ctpvNm: values.sido,
|
||||||
...toInputSearchRegion(sidoListRef.current, values),
|
sggNm: values.gugun === "ALL" ? "" : values.gugun,
|
||||||
...(overrides?.mode ? { mode: overrides.mode } : {}),
|
...(overrides?.mode ? { mode: overrides.mode } : {}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -128,14 +119,10 @@ const computeTabEnterable = (
|
|||||||
return periodEnterable;
|
return periodEnterable;
|
||||||
};
|
};
|
||||||
|
|
||||||
const sidoListRef: { current: Sido[] } = { current: [] };
|
|
||||||
|
|
||||||
function buildGugunOkForToolbar(values: SearchFormValues | null): boolean {
|
function buildGugunOkForToolbar(values: SearchFormValues | null): boolean {
|
||||||
return isGugunOkForToolbar(sidoListRef.current, values);
|
return doList.includes(values?.bsnmCd || "")
|
||||||
}
|
? Boolean(values?.gugun && values.gugun !== "ALL")
|
||||||
|
: true;
|
||||||
function buildSubmitOkForToolbar(values: SearchFormValues | null): boolean {
|
|
||||||
return isSubmitOkForToolbar(sidoListRef.current, values);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeTabToolbarSnapshot(
|
function computeTabToolbarSnapshot(
|
||||||
@@ -149,7 +136,7 @@ function computeTabToolbarSnapshot(
|
|||||||
const gugunOk = buildGugunOkForToolbar(searchContext);
|
const gugunOk = buildGugunOkForToolbar(searchContext);
|
||||||
const enterable = computeTabEnterable(statusInfo, periodEnterable);
|
const enterable = computeTabEnterable(statusInfo, periodEnterable);
|
||||||
const isSubmitted = statusInfo?.laeSbmsnSttsCd === "2";
|
const isSubmitted = statusInfo?.laeSbmsnSttsCd === "2";
|
||||||
const showSaveInToolbar = (enterable || isAdminInfo) && periodEnterable && gugunOk;
|
const showSaveInToolbar = (enterable || isAdminInfo) && gugunOk;
|
||||||
const showEnterableToolbarButtons = enterable && gugunOk;
|
const showEnterableToolbarButtons = enterable && gugunOk;
|
||||||
const showSubmittedInInputPeriodToolbar = isSubmitted && periodEnterable && gugunOk;
|
const showSubmittedInInputPeriodToolbar = isSubmitted && periodEnterable && gugunOk;
|
||||||
const showActionToolbarCard =
|
const showActionToolbarCard =
|
||||||
@@ -171,8 +158,8 @@ function tabRowDataExists(
|
|||||||
|
|
||||||
function mapRegionalListToGridRows<
|
function mapRegionalListToGridRows<
|
||||||
T extends { verificationResult?: PrivateSewageFacilityVerificationResult },
|
T extends { verificationResult?: PrivateSewageFacilityVerificationResult },
|
||||||
>(list: T[], ctpvNm: string, values?: SearchFormValues | null): GridRowWithVerification[] {
|
>(list: T[], ctpvNm: string): GridRowWithVerification[] {
|
||||||
return filterBySelectedAdmdstCd(list, sidoListRef.current, values).map((item) => {
|
return list.map((item) => {
|
||||||
const { verificationResult, ...rest } = item;
|
const { verificationResult, ...rest } = item;
|
||||||
const row = toGridRows([{ ctpvNm, ...rest }])[0] as GridRowWithVerification;
|
const row = toGridRows([{ ctpvNm, ...rest }])[0] as GridRowWithVerification;
|
||||||
if (verificationResult) row.verificationResult = verificationResult;
|
if (verificationResult) row.verificationResult = verificationResult;
|
||||||
@@ -180,6 +167,17 @@ function mapRegionalListToGridRows<
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeGridString(value: unknown): string {
|
||||||
|
if (value === null || value === undefined) return "";
|
||||||
|
return typeof value === "string" ? value : String(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeGridRmrk(value: unknown): string | null {
|
||||||
|
if (value === null || value === undefined) return null;
|
||||||
|
const s = typeof value === "string" ? value : String(value);
|
||||||
|
return s.trim() === "" ? null : s;
|
||||||
|
}
|
||||||
|
|
||||||
function buildColumnFormatNumber(
|
function buildColumnFormatNumber(
|
||||||
columns: { fieldName?: string; dataFormat?: string }[],
|
columns: { fieldName?: string; dataFormat?: string }[],
|
||||||
) {
|
) {
|
||||||
@@ -208,8 +206,8 @@ function buildSewageTreatFactStatusSaveList(
|
|||||||
const formatNumber = buildColumnFormatNumber(SewageTreatFactStatusInpColumn.columns);
|
const formatNumber = buildColumnFormatNumber(SewageTreatFactStatusInpColumn.columns);
|
||||||
|
|
||||||
return currentData.map((d) => ({
|
return currentData.map((d) => ({
|
||||||
admdstCd: nullableTrimmedString(d.admdstCd),
|
admdstCd: normalizeGridString(d.admdstCd),
|
||||||
admdstNm: nullableTrimmedString(d.admdstNm),
|
admdstNm: normalizeGridString(d.admdstNm),
|
||||||
step1StaaPrcsQnt: formatNumber(d.step1StaaPrcsQnt, "step1StaaPrcsQnt"),
|
step1StaaPrcsQnt: formatNumber(d.step1StaaPrcsQnt, "step1StaaPrcsQnt"),
|
||||||
step2StaaPrcsQnt: formatNumber(d.step2StaaPrcsQnt, "step2StaaPrcsQnt"),
|
step2StaaPrcsQnt: formatNumber(d.step2StaaPrcsQnt, "step2StaaPrcsQnt"),
|
||||||
step3StaaPrcsQnt: formatNumber(d.step3StaaPrcsQnt, "step3StaaPrcsQnt"),
|
step3StaaPrcsQnt: formatNumber(d.step3StaaPrcsQnt, "step3StaaPrcsQnt"),
|
||||||
@@ -224,7 +222,7 @@ function buildSewageTreatFactStatusSaveList(
|
|||||||
step5StaaExcpPrcsQnt: formatNumber(d.step5StaaExcpPrcsQnt, "step5StaaExcpPrcsQnt"),
|
step5StaaExcpPrcsQnt: formatNumber(d.step5StaaExcpPrcsQnt, "step5StaaExcpPrcsQnt"),
|
||||||
step6StaaExcpPrcsQnt: formatNumber(d.step6StaaExcpPrcsQnt, "step6StaaExcpPrcsQnt"),
|
step6StaaExcpPrcsQnt: formatNumber(d.step6StaaExcpPrcsQnt, "step6StaaExcpPrcsQnt"),
|
||||||
step7StaaExcpPrcsQnt: formatNumber(d.step7StaaExcpPrcsQnt, "step7StaaExcpPrcsQnt"),
|
step7StaaExcpPrcsQnt: formatNumber(d.step7StaaExcpPrcsQnt, "step7StaaExcpPrcsQnt"),
|
||||||
rmrk: nullableTrimmedString(d.rmrk),
|
rmrk: normalizeGridRmrk(d.rmrk),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,8 +232,8 @@ function buildSepticTankStatusSaveList(
|
|||||||
const formatNumber = buildColumnFormatNumber(SepticTankStatusInpColumn.columns);
|
const formatNumber = buildColumnFormatNumber(SepticTankStatusInpColumn.columns);
|
||||||
|
|
||||||
return currentData.map((d) => ({
|
return currentData.map((d) => ({
|
||||||
admdstCd: nullableTrimmedString(d.admdstCd),
|
admdstCd: normalizeGridString(d.admdstCd),
|
||||||
admdstNm: nullableTrimmedString(d.admdstNm),
|
admdstNm: normalizeGridString(d.admdstNm),
|
||||||
staaInsdSttkNprsflCnt: formatNumber(d.staaInsdSttkNprsflCnt, "staaInsdSttkNprsflCnt"),
|
staaInsdSttkNprsflCnt: formatNumber(d.staaInsdSttkNprsflCnt, "staaInsdSttkNprsflCnt"),
|
||||||
step1StaaInsdSttkFrcCnt: formatNumber(d.step1StaaInsdSttkFrcCnt, "step1StaaInsdSttkFrcCnt"),
|
step1StaaInsdSttkFrcCnt: formatNumber(d.step1StaaInsdSttkFrcCnt, "step1StaaInsdSttkFrcCnt"),
|
||||||
staaInsdSprktpFltrtbCnt: formatNumber(d.staaInsdSprktpFltrtbCnt, "staaInsdSprktpFltrtbCnt"),
|
staaInsdSprktpFltrtbCnt: formatNumber(d.staaInsdSprktpFltrtbCnt, "staaInsdSprktpFltrtbCnt"),
|
||||||
@@ -264,7 +262,7 @@ function buildSepticTankStatusSaveList(
|
|||||||
step6StaaExcpNope: formatNumber(d.step6StaaExcpNope, "step6StaaExcpNope"),
|
step6StaaExcpNope: formatNumber(d.step6StaaExcpNope, "step6StaaExcpNope"),
|
||||||
step7StaaExcpNope: formatNumber(d.step7StaaExcpNope, "step7StaaExcpNope"),
|
step7StaaExcpNope: formatNumber(d.step7StaaExcpNope, "step7StaaExcpNope"),
|
||||||
step8StaaExcpNope: formatNumber(d.step8StaaExcpNope, "step8StaaExcpNope"),
|
step8StaaExcpNope: formatNumber(d.step8StaaExcpNope, "step8StaaExcpNope"),
|
||||||
rmrk: nullableTrimmedString(d.rmrk),
|
rmrk: normalizeGridRmrk(d.rmrk),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,8 +272,8 @@ function buildPrivateSewageDesigStatusSaveList(
|
|||||||
const formatNumber = buildColumnFormatNumber(PrivateSewageDesigStatusInpColumn.columns);
|
const formatNumber = buildColumnFormatNumber(PrivateSewageDesigStatusInpColumn.columns);
|
||||||
|
|
||||||
return currentData.map((d) => ({
|
return currentData.map((d) => ({
|
||||||
admdstCd: nullableTrimmedString(d.admdstCd),
|
admdstCd: normalizeGridString(d.admdstCd),
|
||||||
admdstNm: nullableTrimmedString(d.admdstNm),
|
admdstNm: normalizeGridString(d.admdstNm),
|
||||||
indvSwagePbancRgnCnt: formatNumber(d.indvSwagePbancRgnCnt, "indvSwagePbancRgnCnt"),
|
indvSwagePbancRgnCnt: formatNumber(d.indvSwagePbancRgnCnt, "indvSwagePbancRgnCnt"),
|
||||||
indvSwageDsgnScpLen: formatNumber(d.indvSwageDsgnScpLen, "indvSwageDsgnScpLen"),
|
indvSwageDsgnScpLen: formatNumber(d.indvSwageDsgnScpLen, "indvSwageDsgnScpLen"),
|
||||||
spctnkGrssFcltCnt: formatNumber(d.spctnkGrssFcltCnt, "spctnkGrssFcltCnt"),
|
spctnkGrssFcltCnt: formatNumber(d.spctnkGrssFcltCnt, "spctnkGrssFcltCnt"),
|
||||||
@@ -285,7 +283,7 @@ function buildPrivateSewageDesigStatusSaveList(
|
|||||||
"drtwPrcsFcltGrssFcltCnt",
|
"drtwPrcsFcltGrssFcltCnt",
|
||||||
),
|
),
|
||||||
drtwPrcsFcltQnt: formatNumber(d.drtwPrcsFcltQnt, "drtwPrcsFcltQnt"),
|
drtwPrcsFcltQnt: formatNumber(d.drtwPrcsFcltQnt, "drtwPrcsFcltQnt"),
|
||||||
rmrk: nullableTrimmedString(d.rmrk),
|
rmrk: normalizeGridRmrk(d.rmrk),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,11 +305,11 @@ async function waitForImrJobCompleted(
|
|||||||
options?.onProgress?.(Math.max(0, Math.min(100, Number(res.job_prog) || 0)));
|
options?.onProgress?.(Math.max(0, Math.min(100, Number(res.job_prog) || 0)));
|
||||||
if (res.status === "COMPLETED" && Number(res.job_prog) === 100) return;
|
if (res.status === "COMPLETED" && Number(res.job_prog) === 100) return;
|
||||||
if (res.status === "FAILED" || res.status === "ERROR" || res.status === "CANCELLED") {
|
if (res.status === "FAILED" || res.status === "ERROR" || res.status === "CANCELLED") {
|
||||||
throw new Error(res.error_msg || `시계열 검증이 ${res.status} 상태로 종료되었습니다.`);
|
throw new Error(res.error_msg || `IMR 검증이 ${res.status} 상태로 종료되었습니다.`);
|
||||||
}
|
}
|
||||||
await sleep(pollIntervalMs);
|
await sleep(pollIntervalMs);
|
||||||
}
|
}
|
||||||
throw new Error("시계열 검증 완료 대기 시간이 초과되었습니다.");
|
throw new Error("IMR 검증 완료 대기 시간이 초과되었습니다.");
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolvePrivateSewageFacilityTab(tabKey: string) {
|
function resolvePrivateSewageFacilityTab(tabKey: string) {
|
||||||
@@ -324,8 +322,6 @@ function resolvePrivateSewageFacilityTab(tabKey: string) {
|
|||||||
|
|
||||||
// 하수도 통계 관리 > 08. 개인하수처리시설
|
// 하수도 통계 관리 > 08. 개인하수처리시설
|
||||||
const PrivateSewageFacilityInp = () => {
|
const PrivateSewageFacilityInp = () => {
|
||||||
const { sidoList } = useSearchConditionSidoList({ isInput: true });
|
|
||||||
sidoListRef.current = sidoList;
|
|
||||||
const { setMessage: alert } = useAlertStore((state) => state);
|
const { setMessage: alert } = useAlertStore((state) => state);
|
||||||
const { confirm } = useConfirm();
|
const { confirm } = useConfirm();
|
||||||
const { isAdminInfo } = useAdminStore();
|
const { isAdminInfo } = useAdminStore();
|
||||||
@@ -349,15 +345,9 @@ const PrivateSewageFacilityInp = () => {
|
|||||||
const [isVerificationFailedByTab, setIsVerificationFailedByTab] = useState<
|
const [isVerificationFailedByTab, setIsVerificationFailedByTab] = useState<
|
||||||
Map<string, boolean>
|
Map<string, boolean>
|
||||||
>(new Map());
|
>(new Map());
|
||||||
const [footerVerificationByTab, setFooterVerificationByTab] = useState<
|
const [toolbarSnapshotByTab, setToolbarSnapshotByTab] = useState<
|
||||||
Map<string, VerificationResultLikeMap | null>
|
|
||||||
>(new Map());
|
|
||||||
const [_toolbarSnapshotByTab, setToolbarSnapshotByTab] = useState<
|
|
||||||
Map<string, TabToolbarSnapshot>
|
Map<string, TabToolbarSnapshot>
|
||||||
>(new Map());
|
>(new Map());
|
||||||
const [searchContextByTab, setSearchContextByTab] = useState<Map<string, SearchFormValues>>(
|
|
||||||
() => new Map(),
|
|
||||||
);
|
|
||||||
const [verificationHistoryOpen, setVerificationHistoryOpen] = useState(false);
|
const [verificationHistoryOpen, setVerificationHistoryOpen] = useState(false);
|
||||||
const [verificationResultDialogOpen, setVerificationResultDialogOpen] = useState(false);
|
const [verificationResultDialogOpen, setVerificationResultDialogOpen] = useState(false);
|
||||||
const [showSubmitDialog, setShowSubmitDialog] = useState(false);
|
const [showSubmitDialog, setShowSubmitDialog] = useState(false);
|
||||||
@@ -372,30 +362,42 @@ const PrivateSewageFacilityInp = () => {
|
|||||||
const getGridDataRef = useRef<(() => Record<string, string | number>[]) | null>(null);
|
const getGridDataRef = useRef<(() => Record<string, string | number>[]) | null>(null);
|
||||||
activeTabRef.current = activeTab;
|
activeTabRef.current = activeTab;
|
||||||
|
|
||||||
const activeTabId = useTabStore((s) => s.activeTabId);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeTabId !== STATISTICS_INPUT_URL_PATH.PRIVATE_SEWAGE_FACILITY) return;
|
|
||||||
const tabKey = activeTab;
|
|
||||||
if (!tabKey) return;
|
|
||||||
if (Object.prototype.hasOwnProperty.call(columnGuidesByTab, tabKey)) return;
|
|
||||||
const statsCd =
|
|
||||||
PRIVATE_SEWAGE_FACILITY_COLUMN_GUIDE_STATS_CD_BY_TAB_KEY[tabKey] ?? tabKey;
|
|
||||||
|
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
void (async () => {
|
void (async () => {
|
||||||
const next = await fetchColumnGuidesRecord(statsCd);
|
const entries = await Promise.all(
|
||||||
|
PRIVATE_SEWAGE_FACILITY_COLUMN_GUIDE_STATS_CDS.map(async (statsCd) => {
|
||||||
|
try {
|
||||||
|
const res = await statisticsApi.getColumnGuides(statsCd);
|
||||||
|
if (res.status !== "success" || !Array.isArray(res.data)) {
|
||||||
|
return [statsCd, {}] as const;
|
||||||
|
}
|
||||||
|
const next: Record<string, string> = {};
|
||||||
|
for (const item of res.data) {
|
||||||
|
const key = item.engColNm?.trim();
|
||||||
|
const guide = item.columnGuide?.trim();
|
||||||
|
if (key && guide) next[key] = guide;
|
||||||
|
}
|
||||||
|
return [statsCd, next] as const;
|
||||||
|
} catch {
|
||||||
|
return [statsCd, {}] as const;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
if (cancelled) return;
|
if (cancelled) return;
|
||||||
setColumnGuidesByTab((prev) =>
|
const guidesByStatsCd = Object.fromEntries(entries);
|
||||||
Object.prototype.hasOwnProperty.call(prev, tabKey)
|
setColumnGuidesByTab(
|
||||||
? prev
|
Object.fromEntries(
|
||||||
: { ...prev, [tabKey]: next },
|
Object.entries(PRIVATE_SEWAGE_FACILITY_COLUMN_GUIDE_STATS_CD_BY_TAB_KEY).map(
|
||||||
|
([tabKey, statsCd]) => [tabKey, guidesByStatsCd[statsCd] ?? {}],
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
})();
|
})();
|
||||||
return () => {
|
return () => {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
};
|
};
|
||||||
}, [activeTabId, activeTab, columnGuidesByTab]);
|
}, []);
|
||||||
|
|
||||||
const commitToolbarSnapshotForLoadedTab = (
|
const commitToolbarSnapshotForLoadedTab = (
|
||||||
tabKey: string,
|
tabKey: string,
|
||||||
@@ -418,13 +420,6 @@ const PrivateSewageFacilityInp = () => {
|
|||||||
);
|
);
|
||||||
return next;
|
return next;
|
||||||
});
|
});
|
||||||
if (searchContext) {
|
|
||||||
setSearchContextByTab((prev) => {
|
|
||||||
const next = new Map(prev);
|
|
||||||
next.set(tabKey, searchContext);
|
|
||||||
return next;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const applyRowMap = (
|
const applyRowMap = (
|
||||||
@@ -467,7 +462,6 @@ const PrivateSewageFacilityInp = () => {
|
|||||||
const gridRows = mapRegionalListToGridRows(
|
const gridRows = mapRegionalListToGridRows(
|
||||||
(sewageTreatFactStatusList ?? []) as SewageTreatFactStatusItem[],
|
(sewageTreatFactStatusList ?? []) as SewageTreatFactStatusItem[],
|
||||||
commonInfo.ctpvNm,
|
commonInfo.ctpvNm,
|
||||||
searchContext,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
applyRowMap(mergeIntoExistingMap, (m) => {
|
applyRowMap(mergeIntoExistingMap, (m) => {
|
||||||
@@ -478,9 +472,6 @@ const PrivateSewageFacilityInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
||||||
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
||||||
return true;
|
return true;
|
||||||
@@ -499,7 +490,6 @@ const PrivateSewageFacilityInp = () => {
|
|||||||
const gridRows = mapRegionalListToGridRows(
|
const gridRows = mapRegionalListToGridRows(
|
||||||
(septicTankStatusList ?? []) as SepticTankStatusItem[],
|
(septicTankStatusList ?? []) as SepticTankStatusItem[],
|
||||||
commonInfo.ctpvNm,
|
commonInfo.ctpvNm,
|
||||||
searchContext,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
applyRowMap(mergeIntoExistingMap, (m) => {
|
applyRowMap(mergeIntoExistingMap, (m) => {
|
||||||
@@ -510,9 +500,6 @@ const PrivateSewageFacilityInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
||||||
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
||||||
return true;
|
return true;
|
||||||
@@ -531,7 +518,6 @@ const PrivateSewageFacilityInp = () => {
|
|||||||
const gridRows = mapRegionalListToGridRows(
|
const gridRows = mapRegionalListToGridRows(
|
||||||
(privateSewageDesigStatusList ?? []) as PrivateSewageDesigStatusItem[],
|
(privateSewageDesigStatusList ?? []) as PrivateSewageDesigStatusItem[],
|
||||||
commonInfo.ctpvNm,
|
commonInfo.ctpvNm,
|
||||||
searchContext,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
applyRowMap(mergeIntoExistingMap, (m) => {
|
applyRowMap(mergeIntoExistingMap, (m) => {
|
||||||
@@ -542,9 +528,6 @@ const PrivateSewageFacilityInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
||||||
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
||||||
return true;
|
return true;
|
||||||
@@ -562,9 +545,7 @@ const PrivateSewageFacilityInp = () => {
|
|||||||
setTabStatusInfoMap(new Map());
|
setTabStatusInfoMap(new Map());
|
||||||
setTabStatsCdMap(new Map());
|
setTabStatsCdMap(new Map());
|
||||||
setIsVerificationFailedByTab(new Map());
|
setIsVerificationFailedByTab(new Map());
|
||||||
setFooterVerificationByTab(new Map());
|
|
||||||
setToolbarSnapshotByTab(new Map());
|
setToolbarSnapshotByTab(new Map());
|
||||||
setSearchContextByTab(new Map());
|
|
||||||
setActiveTab(firstTabKey);
|
setActiveTab(firstTabKey);
|
||||||
activeTabRef.current = firstTabKey;
|
activeTabRef.current = firstTabKey;
|
||||||
setLastSearchedValues(null);
|
setLastSearchedValues(null);
|
||||||
@@ -606,9 +587,7 @@ const PrivateSewageFacilityInp = () => {
|
|||||||
setTabStatusInfoMap(new Map());
|
setTabStatusInfoMap(new Map());
|
||||||
setTabStatsCdMap(new Map());
|
setTabStatsCdMap(new Map());
|
||||||
setIsVerificationFailedByTab(new Map());
|
setIsVerificationFailedByTab(new Map());
|
||||||
setFooterVerificationByTab(new Map());
|
|
||||||
setToolbarSnapshotByTab(new Map());
|
setToolbarSnapshotByTab(new Map());
|
||||||
setSearchContextByTab(new Map());
|
|
||||||
activeTabRef.current = firstTabKey;
|
activeTabRef.current = firstTabKey;
|
||||||
setActiveTab(firstTabKey);
|
setActiveTab(firstTabKey);
|
||||||
}
|
}
|
||||||
@@ -718,8 +697,12 @@ const PrivateSewageFacilityInp = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const requestData: cancelSubmitRequest = {
|
const requestData: cancelSubmitRequest = {
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
mdfrId: userInfo.userUnqId,
|
mdfrId: userInfo.userUnqId,
|
||||||
statsCd: statsCdForTab,
|
statsCd: statsCdForTab,
|
||||||
@@ -802,7 +785,11 @@ const PrivateSewageFacilityInp = () => {
|
|||||||
const submitInfoBase = {
|
const submitInfoBase = {
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
laePicNm: submitInfo.laePicNm,
|
laePicNm: submitInfo.laePicNm,
|
||||||
laePicTelNo: submitInfo.laePicTelNo,
|
laePicTelNo: submitInfo.laePicTelNo,
|
||||||
laeKbrdrDeptNm: submitInfo.laeKbrdrDeptNm,
|
laeKbrdrDeptNm: submitInfo.laeKbrdrDeptNm,
|
||||||
@@ -814,8 +801,12 @@ const PrivateSewageFacilityInp = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const verificationQuery = {
|
const verificationQuery = {
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
statsCd: statsCdForTab,
|
statsCd: statsCdForTab,
|
||||||
};
|
};
|
||||||
@@ -835,7 +826,7 @@ const PrivateSewageFacilityInp = () => {
|
|||||||
const userInfo = await getUserInfo();
|
const userInfo = await getUserInfo();
|
||||||
setGlobalProgressLabel("일반 검증 진행 중...");
|
setGlobalProgressLabel("일반 검증 진행 중...");
|
||||||
|
|
||||||
let response: { status: string; message?: string; data?: { finalStatus?: string; nvpassed?: boolean; isHbPassed?: string } };
|
let response: { status: string; message?: string; data?: { finalStatus?: string; nvpassed?: boolean } };
|
||||||
|
|
||||||
if (isSewageTreatTab) {
|
if (isSewageTreatTab) {
|
||||||
const param: SewageTreatFactStatusSubmitRequest = {
|
const param: SewageTreatFactStatusSubmitRequest = {
|
||||||
@@ -880,15 +871,14 @@ const PrivateSewageFacilityInp = () => {
|
|||||||
|
|
||||||
if (finalStatus === "5") {
|
if (finalStatus === "5") {
|
||||||
setGlobalProgress(50);
|
setGlobalProgress(50);
|
||||||
setGlobalProgressLabel("시계열 검증 진행 중...");
|
setGlobalProgressLabel("IMR 검증 진행 중...");
|
||||||
const imrParam = {
|
const imrParam = {
|
||||||
user_id: userInfo.userUnqId,
|
user_id: userInfo.userUnqId,
|
||||||
sewer_bzmn_cd: lastSearchedValues?.bsnmCd ?? "",
|
sewer_bzmn_cd: lastSearchedValues.bsnmCd ?? "",
|
||||||
stats_cd: statsCdForTab,
|
stats_cd: statsCdForTab,
|
||||||
stats_yr: lastSearchedValues.year ?? "",
|
stats_yr: lastSearchedValues.year ?? "",
|
||||||
lae_sbmsn_stts_cd: activeTabStatus?.laeSbmsnSttsCd === "4" ? "4" : "2",
|
lae_sbmsn_stts_cd: activeTabStatus?.laeSbmsnSttsCd === "4" ? "4" : "2",
|
||||||
gen_verify_stts_cd: nvpassed ? "1" : "2",
|
gen_verify_stts_cd: nvpassed ? "1" : "2",
|
||||||
hb_pass_yn: response.data?.isHbPassed,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -972,7 +962,11 @@ const PrivateSewageFacilityInp = () => {
|
|||||||
const baseRequest = {
|
const baseRequest = {
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -1074,8 +1068,9 @@ const PrivateSewageFacilityInp = () => {
|
|||||||
const statsCd = tabStatsCdMap.get(activeTab);
|
const statsCd = tabStatsCdMap.get(activeTab);
|
||||||
if (!ctx?.year || !ctx?.sido || !ctx?.bsnmCd || !statsCd) return null;
|
if (!ctx?.year || !ctx?.sido || !ctx?.bsnmCd || !statsCd) return null;
|
||||||
return {
|
return {
|
||||||
...toInputSearchRegion(sidoListRef.current, ctx),
|
sewerBzmnCd: ctx.bsnmCd,
|
||||||
ctpvNm: ctx.sido,
|
ctpvNm: ctx.sido,
|
||||||
|
sggNm: ctx.gugun === "ALL" ? "" : (ctx.gugun ?? ""),
|
||||||
statsYr: ctx.year,
|
statsYr: ctx.year,
|
||||||
statsCd,
|
statsCd,
|
||||||
};
|
};
|
||||||
@@ -1086,10 +1081,10 @@ const PrivateSewageFacilityInp = () => {
|
|||||||
for (const tab of PrivateSewageFacilityInpTabList) {
|
for (const tab of PrivateSewageFacilityInpTabList) {
|
||||||
const tabKey = tab.tabKey;
|
const tabKey = tab.tabKey;
|
||||||
const canEdit =
|
const canEdit =
|
||||||
(computeTabEnterable(
|
computeTabEnterable(
|
||||||
tabStatusInfoMap.get(tabKey) ?? null,
|
tabStatusInfoMap.get(tabKey) ?? null,
|
||||||
inputPeriodEnterable,
|
inputPeriodEnterable,
|
||||||
) || isAdminInfo) && inputPeriodEnterable;
|
) || isAdminInfo;
|
||||||
const rawColumns = (tab.columns ?? []) as ColumnConfig[];
|
const rawColumns = (tab.columns ?? []) as ColumnConfig[];
|
||||||
const base = canEdit
|
const base = canEdit
|
||||||
? rawColumns
|
? rawColumns
|
||||||
@@ -1106,20 +1101,19 @@ const PrivateSewageFacilityInp = () => {
|
|||||||
return map;
|
return map;
|
||||||
}, [tabStatusInfoMap, inputPeriodEnterable, isAdminInfo, columnGuidesByTab]);
|
}, [tabStatusInfoMap, inputPeriodEnterable, isAdminInfo, columnGuidesByTab]);
|
||||||
|
|
||||||
const searchContextForToolbar = searchContextByTab.get(activeTab) ?? lastSearchedValues;
|
|
||||||
const activeTabStatus = tabStatusInfoMap.get(activeTab) ?? null;
|
const activeTabStatus = tabStatusInfoMap.get(activeTab) ?? null;
|
||||||
const activeTabToolbar =
|
const activeTabToolbar =
|
||||||
|
toolbarSnapshotByTab.get(activeTab) ??
|
||||||
computeTabToolbarSnapshot(
|
computeTabToolbarSnapshot(
|
||||||
activeTabStatus,
|
activeTabStatus,
|
||||||
tabRowDataExists(rowDataMap, activeTab),
|
tabRowDataExists(rowDataMap, activeTab),
|
||||||
hasSearched,
|
hasSearched,
|
||||||
searchContextForToolbar,
|
lastSearchedValues,
|
||||||
inputPeriodEnterable,
|
inputPeriodEnterable,
|
||||||
isAdminInfo,
|
isAdminInfo,
|
||||||
);
|
);
|
||||||
const { showSaveInToolbar, showEnterableToolbarButtons, showActionToolbarCard } =
|
const { showSaveInToolbar, showEnterableToolbarButtons, showActionToolbarCard } =
|
||||||
activeTabToolbar;
|
activeTabToolbar;
|
||||||
const submitOk = buildSubmitOkForToolbar(searchContextForToolbar);
|
|
||||||
|
|
||||||
const verificationCellStyle = ({
|
const verificationCellStyle = ({
|
||||||
fieldName,
|
fieldName,
|
||||||
@@ -1152,10 +1146,10 @@ const PrivateSewageFacilityInp = () => {
|
|||||||
.map((e) => {
|
.map((e) => {
|
||||||
const prefix =
|
const prefix =
|
||||||
e.vrfcCd === "IMR"
|
e.vrfcCd === "IMR"
|
||||||
? "시계열 검증 - "
|
? "IMR검증 - "
|
||||||
: e.vrfcCd === "NV"
|
: e.vrfcCd === "NV"
|
||||||
? "일반검증 - "
|
? "일반검증 - "
|
||||||
: "모집단 검증 - ";
|
: "HB검증 - ";
|
||||||
return `${prefix}${e.rsnExpln}(검증 기준값: ${e.compVlCn} / 현재 입력값: ${e.nowVlCn})`;
|
return `${prefix}${e.rsnExpln}(검증 기준값: ${e.compVlCn} / 현재 입력값: ${e.nowVlCn})`;
|
||||||
})
|
})
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
@@ -1178,7 +1172,6 @@ const PrivateSewageFacilityInp = () => {
|
|||||||
<>
|
<>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<SearchForm
|
<SearchForm
|
||||||
isInput
|
|
||||||
key={searchFormRemountKey}
|
key={searchFormRemountKey}
|
||||||
defaultValues={verificationSearchDefaults ?? undefined}
|
defaultValues={verificationSearchDefaults ?? undefined}
|
||||||
onSubmit={handleSearch}
|
onSubmit={handleSearch}
|
||||||
@@ -1199,10 +1192,10 @@ const PrivateSewageFacilityInp = () => {
|
|||||||
<LastYearDataButton
|
<LastYearDataButton
|
||||||
getLastYearDataFunc={() => void lastYearDataFunc()}
|
getLastYearDataFunc={() => void lastYearDataFunc()}
|
||||||
/>
|
/>
|
||||||
{submitOk && <SubmitButton submitFunc={submitFunc} />}
|
<SubmitButton submitFunc={submitFunc} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{activeTabStatus?.laeSbmsnSttsCd === "2" && submitOk && (
|
{activeTabStatus?.laeSbmsnSttsCd === "2" && (
|
||||||
<CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />
|
<CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />
|
||||||
)}
|
)}
|
||||||
{showSaveInToolbar && <SaveButton saveFunc={saveFunc} />}
|
{showSaveInToolbar && <SaveButton saveFunc={saveFunc} />}
|
||||||
@@ -1234,11 +1227,11 @@ const PrivateSewageFacilityInp = () => {
|
|||||||
const tabKey = info.tabKey;
|
const tabKey = info.tabKey;
|
||||||
const rowData = rowDataMap.get(tabKey) ?? [];
|
const rowData = rowDataMap.get(tabKey) ?? [];
|
||||||
const tabEnterableForGrid =
|
const tabEnterableForGrid =
|
||||||
(computeTabEnterable(
|
computeTabEnterable(
|
||||||
tabStatusInfoMap.get(tabKey) ?? null,
|
tabStatusInfoMap.get(tabKey) ?? null,
|
||||||
inputPeriodEnterable,
|
inputPeriodEnterable,
|
||||||
) || isAdminInfo) && inputPeriodEnterable;
|
) || isAdminInfo;
|
||||||
const gugunOk = buildGugunOkForToolbar(searchContextForToolbar);
|
const gugunOk = buildGugunOkForToolbar(lastSearchedValues);
|
||||||
const tabStatusInfo = tabStatusInfoMap.get(tabKey) ?? null;
|
const tabStatusInfo = tabStatusInfoMap.get(tabKey) ?? null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -1276,9 +1269,6 @@ const PrivateSewageFacilityInp = () => {
|
|||||||
excelExportSearchContext={toExcelExportSearchContextFromSearchForm(lastSearchedValues ?? searchValues)}
|
excelExportSearchContext={toExcelExportSearchContextFromSearchForm(lastSearchedValues ?? searchValues)}
|
||||||
isExcelExport
|
isExcelExport
|
||||||
cellStyleCallback={verificationCellStyle}
|
cellStyleCallback={verificationCellStyle}
|
||||||
footerVerificationResult={
|
|
||||||
footerVerificationByTab.get(tabKey) ?? null
|
|
||||||
}
|
|
||||||
cellTooltipCallback={verificationCellTooltip}
|
cellTooltipCallback={verificationCellTooltip}
|
||||||
getGridDataRef={
|
getGridDataRef={
|
||||||
activeTab === tabKey ? getGridDataRef : undefined
|
activeTab === tabKey ? getGridDataRef : undefined
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { type Dispatch, type SetStateAction,useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState, type Dispatch, type SetStateAction } from 'react';
|
||||||
|
|
||||||
import { useConfirm } from '@frontend-opensource/use-react-hooks';
|
import { useConfirm } from '@frontend-opensource/use-react-hooks';
|
||||||
|
|
||||||
import { useAlertStore, useGlobalProgressStore, useStatisticsInputToolbarGroupGate, useSearchConditionSidoList } from '@/shared/lib';
|
import { useAlertStore, useGlobalProgressStore, useStatisticsInputToolbarGroupGate } from '@/shared/lib';
|
||||||
import { STATISTICS_INPUT_URL_PATH } from '@/shared/lib/stats-cd-input-navigation';
|
import { STATISTICS_INPUT_URL_PATH } from '@/shared/lib/stats-cd-input-navigation';
|
||||||
import { useStatisticsInputPendingNavigation } from '@/shared/lib/use-statistics-input-pending-navigation';
|
import { useStatisticsInputPendingNavigation } from '@/shared/lib/use-statistics-input-pending-navigation';
|
||||||
import { statisticsInputSewSupplyRateApi } from '@/entities/statistics/api/input/statistics-input-sew-supply-rate-service';
|
import { statisticsInputSewSupplyRateApi } from '@/entities/statistics/api/input/statistics-input-sew-supply-rate-service';
|
||||||
@@ -23,9 +23,7 @@ import {
|
|||||||
type SewerageSupplyRateVerificationResult,
|
type SewerageSupplyRateVerificationResult,
|
||||||
} from '@/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface';
|
} from '@/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface';
|
||||||
import type { StatisticsInputSubmitInfoFormData } from '@/entities/statistics/model/statistics-input-submit-info-schema';
|
import type { StatisticsInputSubmitInfoFormData } from '@/entities/statistics/model/statistics-input-submit-info-schema';
|
||||||
import type { cancelSubmitRequest, ImrStatusResponse, SewerageStatusInfo, Sido } from '@/entities/statistics/model/statistics-interface';
|
import type { cancelSubmitRequest, ImrStatusResponse, SewerageStatusInfo } from '@/entities/statistics/model/statistics-interface';
|
||||||
import { filterBySelectedAdmdstCd, isGugunOkForToolbar, isSubmitOkForToolbar, resolveNoApplicableForRequest, toInputSearchRegion } from '@/entities/statistics';
|
|
||||||
|
|
||||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from '@common/components';
|
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from '@common/components';
|
||||||
|
|
||||||
import { getUserInfo } from '../../../../../../packages/common/components/src/api';
|
import { getUserInfo } from '../../../../../../packages/common/components/src/api';
|
||||||
@@ -40,22 +38,19 @@ import SubmitButton from '@/components/button/SumitButton';
|
|||||||
import UpdateOperateDataButton from '@/components/button/UpdateOperateDataButton';
|
import UpdateOperateDataButton from '@/components/button/UpdateOperateDataButton';
|
||||||
import VerificationResultButton from '@/components/button/VerificationResultButton';
|
import VerificationResultButton from '@/components/button/VerificationResultButton';
|
||||||
import DataGrid from '@/components/module/DataGrid';
|
import DataGrid from '@/components/module/DataGrid';
|
||||||
import { openVerificationResultDialogIfNeeded } from '@/components/module/post-submit-verification-results';
|
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
||||||
import SearchForm from '@/components/module/SearchForm';
|
import SearchForm from '@/components/module/SearchForm';
|
||||||
import SplitDataGrid from '@/components/module/SplitDataGrid';
|
import SplitDataGrid from '@/components/module/SplitDataGrid';
|
||||||
|
import { openVerificationResultDialogIfNeeded } from '@/components/module/post-submit-verification-results';
|
||||||
import { VerificationResultDialog } from '@/components/module/VerificationResultDialog';
|
import { VerificationResultDialog } from '@/components/module/VerificationResultDialog';
|
||||||
import { VerificationResultHistoryDialog } from '@/components/module/VerificationResultHistoryDialog';
|
import { VerificationResultHistoryDialog } from '@/components/module/VerificationResultHistoryDialog';
|
||||||
import type { CellStyleCallbackParams, ColumnInfo, ColumnInfoList } from '@/components/type/DataGrid.type';
|
import type { CellStyleCallbackParams, ColumnInfo, ColumnInfoList } from '@/components/type/DataGrid.type';
|
||||||
import type { SearchFormValues } from '@/components/type/SearchForm.type';
|
import type { SearchFormValues } from '@/components/type/SearchForm.type';
|
||||||
|
import { doList } from '@/components/util/column/input/DoList';
|
||||||
import { PublicSewageFactInpColumnList } from '@/components/util/column/input/PublicSewageFactInpColumn/PublicSewageFactInpColumn';
|
import { PublicSewageFactInpColumnList } from '@/components/util/column/input/PublicSewageFactInpColumn/PublicSewageFactInpColumn';
|
||||||
import { fetchColumnGuidesRecord } from '@/components/util/grid/columnGuides';
|
|
||||||
import { toGridRows } from '@/components/util/grid/gridFunction';
|
import { toGridRows } from '@/components/util/grid/gridFunction';
|
||||||
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
import { patchVerificationFailedByTab } from '@/components/util/input/verification-failed-flag';
|
||||||
import { patchFooterVerificationByTab,patchVerificationFailedByTab } from '@/components/util/input/verification-failed-flag';
|
|
||||||
import type { VerificationResultLikeMap } from '@/components/util/input/verification-result-display';
|
|
||||||
import { nullableTrimmedString } from '@/components/util/input/nullableString';
|
|
||||||
import { useAdminStore } from '@/store/admin-store';
|
import { useAdminStore } from '@/store/admin-store';
|
||||||
import { useTabStore } from '@/store/tab-store';
|
|
||||||
|
|
||||||
type GridRowWithVerification = Record<string, string | number> & {
|
type GridRowWithVerification = Record<string, string | number> & {
|
||||||
verificationResult?: SewerageSupplyRateVerificationResult;
|
verificationResult?: SewerageSupplyRateVerificationResult;
|
||||||
@@ -67,22 +62,10 @@ type TabToolbarSnapshot = {
|
|||||||
showActionToolbarCard: boolean;
|
showActionToolbarCard: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const sidoListRef: { current: Sido[] } = { current: [] };
|
|
||||||
|
|
||||||
function buildGugunOkForToolbar(values: SearchFormValues | null): boolean {
|
function buildGugunOkForToolbar(values: SearchFormValues | null): boolean {
|
||||||
return isGugunOkForToolbar(sidoListRef.current, values);
|
return doList.includes(values?.bsnmCd || '')
|
||||||
}
|
? Boolean(values?.gugun && values.gugun !== 'ALL')
|
||||||
|
: true;
|
||||||
function buildSubmitOkForToolbar(values: SearchFormValues | null): boolean {
|
|
||||||
return isSubmitOkForToolbar(sidoListRef.current, values);
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildNoApplicableForRequest(
|
|
||||||
values: SearchFormValues | null,
|
|
||||||
checked: boolean,
|
|
||||||
isSaveListEmpty: boolean,
|
|
||||||
): boolean {
|
|
||||||
return resolveNoApplicableForRequest(sidoListRef.current, values, checked, isSaveListEmpty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const computeTabEnterable = (
|
const computeTabEnterable = (
|
||||||
@@ -109,7 +92,7 @@ function computeTabToolbarSnapshot(
|
|||||||
const gugunOk = buildGugunOkForToolbar(searchContext);
|
const gugunOk = buildGugunOkForToolbar(searchContext);
|
||||||
const enterable = computeTabEnterable(statusInfo, periodEnterable);
|
const enterable = computeTabEnterable(statusInfo, periodEnterable);
|
||||||
const isSubmitted = statusInfo?.laeSbmsnSttsCd === '2';
|
const isSubmitted = statusInfo?.laeSbmsnSttsCd === '2';
|
||||||
const showSaveInToolbar = (enterable || isAdminInfo) && periodEnterable && gugunOk;
|
const showSaveInToolbar = (enterable || isAdminInfo) && gugunOk;
|
||||||
const showEnterableToolbarButtons = enterable && gugunOk;
|
const showEnterableToolbarButtons = enterable && gugunOk;
|
||||||
const showSubmittedInInputPeriodToolbar = isSubmitted && periodEnterable && gugunOk;
|
const showSubmittedInInputPeriodToolbar = isSubmitted && periodEnterable && gugunOk;
|
||||||
const showActionToolbarCard =
|
const showActionToolbarCard =
|
||||||
@@ -139,11 +122,11 @@ async function waitForImrJobCompleted(
|
|||||||
options?.onProgress?.(Math.max(0, Math.min(100, Number(res.job_prog) || 0)));
|
options?.onProgress?.(Math.max(0, Math.min(100, Number(res.job_prog) || 0)));
|
||||||
if (res.status === 'COMPLETED' && Number(res.job_prog) === 100) return;
|
if (res.status === 'COMPLETED' && Number(res.job_prog) === 100) return;
|
||||||
if (res.status === 'FAILED' || res.status === 'ERROR' || res.status === 'CANCELLED') {
|
if (res.status === 'FAILED' || res.status === 'ERROR' || res.status === 'CANCELLED') {
|
||||||
throw new Error(res.error_msg || `시계열 검증이 ${res.status} 상태로 종료되었습니다.`);
|
throw new Error(res.error_msg || `IMR 검증이 ${res.status} 상태로 종료되었습니다.`);
|
||||||
}
|
}
|
||||||
await sleep(pollIntervalMs);
|
await sleep(pollIntervalMs);
|
||||||
}
|
}
|
||||||
throw new Error('시계열 검증 완료 대기 시간이 초과되었습니다.');
|
throw new Error('IMR 검증 완료 대기 시간이 초과되었습니다.');
|
||||||
}
|
}
|
||||||
|
|
||||||
type MainFacilityMappingSaveDraft = {
|
type MainFacilityMappingSaveDraft = {
|
||||||
@@ -161,6 +144,10 @@ type MainFacilityMappingSaveDraft = {
|
|||||||
initialPrxyCtrtCn: string;
|
initialPrxyCtrtCn: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const PUBLIC_SEWAGE_FACILITY_COLUMN_GUIDE_TAB_KEYS = Array.from(
|
||||||
|
new Set(PublicSewageFactInpColumnList.map((tab) => tab.tabKey).filter(Boolean)),
|
||||||
|
);
|
||||||
|
|
||||||
/** 위탁계약기간: `yyyymmdd~yyyymmdd` (빈 값 허용). 하이픈 형식은 정규화 */
|
/** 위탁계약기간: `yyyymmdd~yyyymmdd` (빈 값 허용). 하이픈 형식은 정규화 */
|
||||||
function normalizePrxyCtrtCn(raw: unknown): string | null {
|
function normalizePrxyCtrtCn(raw: unknown): string | null {
|
||||||
if (raw === null || raw === undefined) return null;
|
if (raw === null || raw === undefined) return null;
|
||||||
@@ -173,10 +160,6 @@ function normalizePrxyCtrtCn(raw: unknown): string | null {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isMainFacilityRow(row: Record<string, string | number>): boolean {
|
|
||||||
return String(row.isMainYn ?? '').toUpperCase() === 'Y';
|
|
||||||
}
|
|
||||||
|
|
||||||
function isValidPrxyCtrtCn(value: string | null): boolean {
|
function isValidPrxyCtrtCn(value: string | null): boolean {
|
||||||
if (value === null) return true;
|
if (value === null) return true;
|
||||||
if (!/^\d{8}~\d{8}$/.test(value)) return false;
|
if (!/^\d{8}~\d{8}$/.test(value)) return false;
|
||||||
@@ -198,8 +181,6 @@ function validatePrxyCtrtCnInRows(rows: Record<string, string | number>[]): stri
|
|||||||
|
|
||||||
// 하수도 통계 관리 > 06. 공공하수처리시설
|
// 하수도 통계 관리 > 06. 공공하수처리시설
|
||||||
const PublicSewageFacilityInp = () => {
|
const PublicSewageFacilityInp = () => {
|
||||||
const { sidoList } = useSearchConditionSidoList({ isInput: true });
|
|
||||||
sidoListRef.current = sidoList;
|
|
||||||
const { setMessage: alert } = useAlertStore((state) => state);
|
const { setMessage: alert } = useAlertStore((state) => state);
|
||||||
const { confirm } = useConfirm();
|
const { confirm } = useConfirm();
|
||||||
const { isAdminInfo } = useAdminStore();
|
const { isAdminInfo } = useAdminStore();
|
||||||
@@ -222,15 +203,9 @@ const PublicSewageFacilityInp = () => {
|
|||||||
const [isVerificationFailedByTab, setIsVerificationFailedByTab] = useState<
|
const [isVerificationFailedByTab, setIsVerificationFailedByTab] = useState<
|
||||||
Map<string, boolean>
|
Map<string, boolean>
|
||||||
>(new Map());
|
>(new Map());
|
||||||
const [footerVerificationByTab, setFooterVerificationByTab] = useState<
|
|
||||||
Map<string, VerificationResultLikeMap | null>
|
|
||||||
>(new Map());
|
|
||||||
/** 탭키별 `engColNm -> columnGuide` 캐시 */
|
/** 탭키별 `engColNm -> columnGuide` 캐시 */
|
||||||
const [columnGuidesByTab, setColumnGuidesByTab] = useState<Record<string, Record<string, string>>>({});
|
const [columnGuidesByTab, setColumnGuidesByTab] = useState<Record<string, Record<string, string>>>({});
|
||||||
const [_toolbarSnapshotByTab, setToolbarSnapshotByTab] = useState<Map<string, TabToolbarSnapshot>>(() => new Map());
|
const [_toolbarSnapshotByTab, setToolbarSnapshotByTab] = useState<Map<string, TabToolbarSnapshot>>(() => new Map());
|
||||||
const [searchContextByTab, setSearchContextByTab] = useState<Map<string, SearchFormValues>>(
|
|
||||||
() => new Map(),
|
|
||||||
);
|
|
||||||
const [inputPeriodEnterable, setInputPeriodEnterable] = useState(true);
|
const [inputPeriodEnterable, setInputPeriodEnterable] = useState(true);
|
||||||
const [periodCheckList, setPeriodCheckList] = useState<CheckInputPeriodItem[]>([]);
|
const [periodCheckList, setPeriodCheckList] = useState<CheckInputPeriodItem[]>([]);
|
||||||
const [showDailog, setShowDailog] = useState<boolean>(false);
|
const [showDailog, setShowDailog] = useState<boolean>(false);
|
||||||
@@ -269,10 +244,10 @@ const PublicSewageFacilityInp = () => {
|
|||||||
alert('먼저 조회를 진행해주세요.');
|
alert('먼저 조회를 진행해주세요.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const treatAsNoApplicable = getNoApplicableForRequest();
|
const treatAsNoApplicable = getNoApplicableForRequest() || isNotApplicable;
|
||||||
const currentData =
|
const currentData =
|
||||||
st60001GridGetRowsRef.current?.() ?? rowDataMap.get('ST00060001') ?? [];
|
st60001GridGetRowsRef.current?.() ?? rowDataMap.get('ST00060001') ?? [];
|
||||||
if (!treatAsNoApplicable && (!currentData || currentData.length === 0) && buildSubmitOkForToolbar(searchContextByTab.get(activeTab) ?? lastSearchedValues)) {
|
if (!treatAsNoApplicable && (!currentData || currentData.length === 0)) {
|
||||||
alert('해당사항 없음을 체크해주세요.');
|
alert('해당사항 없음을 체크해주세요.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -300,13 +275,19 @@ const PublicSewageFacilityInp = () => {
|
|||||||
return Number.isFinite(num) ? num : 0;
|
return Number.isFinite(num) ? num : 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const toNullableString = (v: unknown): string | null => {
|
||||||
|
if (v === null || v === undefined) return null;
|
||||||
|
const s = typeof v === 'string' ? v : String(v);
|
||||||
|
return s.trim() === '' ? null : s;
|
||||||
|
};
|
||||||
|
|
||||||
return currentData.map((d) => ({
|
return currentData.map((d) => ({
|
||||||
admdstCd: nullableTrimmedString(d.admdstCd),
|
admdstCd: String(d.admdstCd ?? ''),
|
||||||
admdstNm: nullableTrimmedString(d.admdstNm),
|
admdstNm: String(d.admdstNm ?? ''),
|
||||||
swtrmtFcltCd: nullableTrimmedString(d.swtrmtFcltCd),
|
swtrmtFcltCd: String(d.swtrmtFcltCd ?? ''),
|
||||||
swtrmtFcltNm: nullableTrimmedString(d.swtrmtFcltNm),
|
swtrmtFcltNm: String(d.swtrmtFcltNm ?? ''),
|
||||||
fcltSn: nullableTrimmedString(d.fcltSn),
|
fcltSn: String(d.fcltSn ?? ''),
|
||||||
fcltPstnCn: nullableTrimmedString(d.fcltPstnCn),
|
fcltPstnCn: d.fcltPstnCn === '' ? null : toNullableString(d.fcltPstnCn),
|
||||||
inflwSwagePhysQnt: toNumber(d.inflwSwagePhysQnt),
|
inflwSwagePhysQnt: toNumber(d.inflwSwagePhysQnt),
|
||||||
inflwSwageBoilQnt: toNumber(d.inflwSwageBoilQnt),
|
inflwSwageBoilQnt: toNumber(d.inflwSwageBoilQnt),
|
||||||
inflwSwageAltdQnt: toNumber(d.inflwSwageAltdQnt),
|
inflwSwageAltdQnt: toNumber(d.inflwSwageAltdQnt),
|
||||||
@@ -315,19 +296,18 @@ const PublicSewageFacilityInp = () => {
|
|||||||
prcsAltdCpct: toNumber(d.prcsAltdCpct),
|
prcsAltdCpct: toNumber(d.prcsAltdCpct),
|
||||||
prxyCtrtCn: normalizePrxyCtrtCn(d.prxyCtrtCn),
|
prxyCtrtCn: normalizePrxyCtrtCn(d.prxyCtrtCn),
|
||||||
sftyAcdntEvntcsCnt: toNumber(d.sftyAcdntEvntcsCnt),
|
sftyAcdntEvntcsCnt: toNumber(d.sftyAcdntEvntcsCnt),
|
||||||
rmrk: nullableTrimmedString(d.rmrk),
|
rmrk: toNullableString(d.rmrk),
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
const getNoApplicableForRequest = (): boolean => {
|
const getNoApplicableForRequest = (): boolean => {
|
||||||
const searchContextForToolbar = searchContextByTab.get(activeTab) ?? lastSearchedValues;
|
const activeTabStatus = tabStatusInfoMap.get(activeTab) ?? null;
|
||||||
const currentData =
|
const searchContextForToolbar = lastSearchedValues ?? searchValues;
|
||||||
st60001GridGetRowsRef.current?.() ?? rowDataMap.get('ST00060001') ?? [];
|
const gugunOk = buildGugunOkForToolbar(searchContextForToolbar);
|
||||||
return buildNoApplicableForRequest(
|
const enterable = computeTabEnterable(activeTabStatus, inputPeriodEnterable);
|
||||||
searchContextForToolbar,
|
const showEnterableToolbarButtons = enterable && gugunOk;
|
||||||
Boolean(isNotApplicable),
|
const noApplicableVisible = showEnterableToolbarButtons && showIsNotApplicable;
|
||||||
buildFacilitySaveList(currentData).length === 0,
|
return noApplicableVisible ? Boolean(isNotApplicable) : false;
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const isCheckedRow = (row: Record<string, string | number>): boolean => {
|
const isCheckedRow = (row: Record<string, string | number>): boolean => {
|
||||||
@@ -335,28 +315,6 @@ const PublicSewageFacilityInp = () => {
|
|||||||
return v === 1 || v === '1' || v === 'Y' || v === 'y' || v === 'true';
|
return v === 1 || v === '1' || v === 'Y' || v === 'y' || v === 'true';
|
||||||
};
|
};
|
||||||
|
|
||||||
const isSelfMappingTarget = (
|
|
||||||
row: Record<string, string | number>,
|
|
||||||
mainFcltSn: string | null,
|
|
||||||
): boolean => Boolean(mainFcltSn) && String(row.fcltSn ?? '') === mainFcltSn;
|
|
||||||
|
|
||||||
const hasCheckedSelfMapping = (
|
|
||||||
rows: Record<string, string | number>[],
|
|
||||||
mainFcltSn: string | null,
|
|
||||||
): boolean => rows.some((r) => isSelfMappingTarget(r, mainFcltSn) && isCheckedRow(r));
|
|
||||||
|
|
||||||
/** 왼쪽에서 선택한 시설을 오른쪽에서 본인 체크하면 다른 시설은 해제 */
|
|
||||||
const applyExclusiveSelfMappingChecks = (
|
|
||||||
rows: Record<string, string | number>[],
|
|
||||||
mainFcltSn: string | null,
|
|
||||||
): Record<string, string | number>[] => {
|
|
||||||
if (!hasCheckedSelfMapping(rows, mainFcltSn)) return rows;
|
|
||||||
return rows.map((r) => ({
|
|
||||||
...r,
|
|
||||||
__checked: isSelfMappingTarget(r, mainFcltSn) ? 'Y' : '',
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
const executeSubmit = async (submitInfo: StatisticsInputSubmitInfoFormData) => {
|
const executeSubmit = async (submitInfo: StatisticsInputSubmitInfoFormData) => {
|
||||||
const verificationBlocked = getVerificationPeriodActionBlockedMessage(periodCheckList);
|
const verificationBlocked = getVerificationPeriodActionBlockedMessage(periodCheckList);
|
||||||
if (verificationBlocked) {
|
if (verificationBlocked) {
|
||||||
@@ -372,7 +330,7 @@ const PublicSewageFacilityInp = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const noApplicable = getNoApplicableForRequest();
|
const noApplicable = getNoApplicableForRequest();
|
||||||
const treatAsNoApplicable = noApplicable;
|
const treatAsNoApplicable = noApplicable || isNotApplicable;
|
||||||
const currentData =
|
const currentData =
|
||||||
st60001GridGetRowsRef.current?.() ?? rowDataMap.get('ST00060001') ?? [];
|
st60001GridGetRowsRef.current?.() ?? rowDataMap.get('ST00060001') ?? [];
|
||||||
|
|
||||||
@@ -383,7 +341,7 @@ const PublicSewageFacilityInp = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const submitList = treatAsNoApplicable ? [] : buildFacilitySaveList(currentData);
|
const submitList = treatAsNoApplicable ? [] : buildFacilitySaveList(currentData);
|
||||||
if (!treatAsNoApplicable && submitList.length === 0 && buildSubmitOkForToolbar(searchContextByTab.get(activeTab) ?? lastSearchedValues)) {
|
if (!treatAsNoApplicable && submitList.length === 0) {
|
||||||
alert('해당사항 없음을 체크해주세요.');
|
alert('해당사항 없음을 체크해주세요.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -396,7 +354,8 @@ const PublicSewageFacilityInp = () => {
|
|||||||
const requestData = {
|
const requestData = {
|
||||||
statsYr: lastSearchedValues.year ?? '',
|
statsYr: lastSearchedValues.year ?? '',
|
||||||
ctpvNm: lastSearchedValues.sido ?? '',
|
ctpvNm: lastSearchedValues.sido ?? '',
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sggNm: lastSearchedValues.gugun === 'ALL' ? '' : lastSearchedValues.gugun ?? '',
|
||||||
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? '',
|
||||||
userId: userInfo.userUnqId,
|
userId: userInfo.userUnqId,
|
||||||
noApplicable,
|
noApplicable,
|
||||||
laePicNm: submitInfo.laePicNm,
|
laePicNm: submitInfo.laePicNm,
|
||||||
@@ -426,15 +385,14 @@ const PublicSewageFacilityInp = () => {
|
|||||||
|
|
||||||
if (finalStatus === '5') {
|
if (finalStatus === '5') {
|
||||||
setGlobalProgress(50);
|
setGlobalProgress(50);
|
||||||
setGlobalProgressLabel('시계열 검증 진행 중...');
|
setGlobalProgressLabel('IMR 검증 진행 중...');
|
||||||
const imrParam = {
|
const imrParam = {
|
||||||
user_id: userInfo.userUnqId,
|
user_id: userInfo.userUnqId,
|
||||||
sewer_bzmn_cd: lastSearchedValues?.bsnmCd ?? '',
|
sewer_bzmn_cd: lastSearchedValues.bsnmCd ?? '',
|
||||||
stats_cd: statsCdForTab,
|
stats_cd: statsCdForTab,
|
||||||
stats_yr: lastSearchedValues.year ?? '',
|
stats_yr: lastSearchedValues.year ?? '',
|
||||||
lae_sbmsn_stts_cd: activeTabStatus?.laeSbmsnSttsCd === '4' ? '4' : '2',
|
lae_sbmsn_stts_cd: activeTabStatus?.laeSbmsnSttsCd === '4' ? '4' : '2',
|
||||||
gen_verify_stts_cd: nvpassed ? '1' : '2',
|
gen_verify_stts_cd: nvpassed ? '1' : '2',
|
||||||
hb_pass_yn: response.data?.isHbPassed,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -458,8 +416,9 @@ const PublicSewageFacilityInp = () => {
|
|||||||
);
|
);
|
||||||
await openVerificationResultDialogIfNeeded(
|
await openVerificationResultDialogIfNeeded(
|
||||||
{
|
{
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? '',
|
||||||
ctpvNm: lastSearchedValues.sido ?? '',
|
ctpvNm: lastSearchedValues.sido ?? '',
|
||||||
|
sggNm: lastSearchedValues.gugun === 'ALL' ? '' : (lastSearchedValues.gugun ?? ''),
|
||||||
statsYr: lastSearchedValues.year ?? '',
|
statsYr: lastSearchedValues.year ?? '',
|
||||||
statsCd: statsCdForTab,
|
statsCd: statsCdForTab,
|
||||||
},
|
},
|
||||||
@@ -474,8 +433,9 @@ const PublicSewageFacilityInp = () => {
|
|||||||
);
|
);
|
||||||
await openVerificationResultDialogIfNeeded(
|
await openVerificationResultDialogIfNeeded(
|
||||||
{
|
{
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? '',
|
||||||
ctpvNm: lastSearchedValues.sido ?? '',
|
ctpvNm: lastSearchedValues.sido ?? '',
|
||||||
|
sggNm: lastSearchedValues.gugun === 'ALL' ? '' : (lastSearchedValues.gugun ?? ''),
|
||||||
statsYr: lastSearchedValues.year ?? '',
|
statsYr: lastSearchedValues.year ?? '',
|
||||||
statsCd: statsCdForTab,
|
statsCd: statsCdForTab,
|
||||||
},
|
},
|
||||||
@@ -497,8 +457,9 @@ const PublicSewageFacilityInp = () => {
|
|||||||
);
|
);
|
||||||
await openVerificationResultDialogIfNeeded(
|
await openVerificationResultDialogIfNeeded(
|
||||||
{
|
{
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? '',
|
||||||
ctpvNm: lastSearchedValues.sido ?? '',
|
ctpvNm: lastSearchedValues.sido ?? '',
|
||||||
|
sggNm: lastSearchedValues.gugun === 'ALL' ? '' : (lastSearchedValues.gugun ?? ''),
|
||||||
statsYr: lastSearchedValues.year ?? '',
|
statsYr: lastSearchedValues.year ?? '',
|
||||||
statsCd: statsCdForTab,
|
statsCd: statsCdForTab,
|
||||||
},
|
},
|
||||||
@@ -528,7 +489,7 @@ const PublicSewageFacilityInp = () => {
|
|||||||
|
|
||||||
if (activeTab === 'ST00060002') {
|
if (activeTab === 'ST00060002') {
|
||||||
const statusCodeResponse = await statisticsApi.CheckStatusCode({
|
const statusCodeResponse = await statisticsApi.CheckStatusCode({
|
||||||
sewerBzmnCd: toInputSearchRegion(sidoListRef.current, lastSearchedValues).sewerBzmnCd,
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? '',
|
||||||
statsCd: 'ST00060001',
|
statsCd: 'ST00060001',
|
||||||
statsYr: lastSearchedValues.year ?? ''
|
statsYr: lastSearchedValues.year ?? ''
|
||||||
});
|
});
|
||||||
@@ -562,36 +523,19 @@ const PublicSewageFacilityInp = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkedRows = rightRows.filter((r) => isCheckedRow(r));
|
const saveList: PublicSewageMainFacilityMappingSaveItem[] = rightRows
|
||||||
const exclusiveSelf = hasCheckedSelfMapping(rightRows, selectedMainFacilitySn);
|
.filter((r) => isCheckedRow(r))
|
||||||
const saveList: PublicSewageMainFacilityMappingSaveItem[] = (
|
.map((r) => ({
|
||||||
exclusiveSelf
|
fcltSn: String(r.fcltSn ?? ''),
|
||||||
? checkedRows.filter((r) => isSelfMappingTarget(r, selectedMainFacilitySn))
|
admdstCd: String(r.admdstCd ?? ''),
|
||||||
: checkedRows
|
admdstNm: String(r.admdstNm ?? ''),
|
||||||
).map((r) => ({
|
swtrmtFcltCd: String(r.swtrmtFcltCd ?? ''),
|
||||||
fcltSn: nullableTrimmedString(r.fcltSn),
|
swtrmtFcltNm: String(r.swtrmtFcltNm ?? ''),
|
||||||
admdstCd: nullableTrimmedString(r.admdstCd),
|
isMainYn: String(r.isMainYn ?? ''),
|
||||||
admdstNm: nullableTrimmedString(r.admdstNm),
|
}));
|
||||||
swtrmtFcltCd: nullableTrimmedString(r.swtrmtFcltCd),
|
|
||||||
swtrmtFcltNm: nullableTrimmedString(r.swtrmtFcltNm),
|
|
||||||
isMainYn: nullableTrimmedString(r.isMainYn),
|
|
||||||
}));
|
|
||||||
|
|
||||||
const exclusiveDroppedSns = exclusiveSelf
|
|
||||||
? new Set(
|
|
||||||
checkedRows
|
|
||||||
.filter((r) => !isSelfMappingTarget(r, selectedMainFacilitySn))
|
|
||||||
.map((r) => String(r.fcltSn ?? ''))
|
|
||||||
.filter((sn) => sn !== ''),
|
|
||||||
)
|
|
||||||
: new Set<string>();
|
|
||||||
|
|
||||||
const deleteList = rightRows
|
const deleteList = rightRows
|
||||||
.filter((r) => {
|
.filter((r) => String(r.mappedYn ?? '') === 'Y' && !isCheckedRow(r))
|
||||||
const sn = String(r.fcltSn ?? '');
|
|
||||||
if (String(r.mappedYn ?? '') === 'Y' && !isCheckedRow(r)) return true;
|
|
||||||
return exclusiveDroppedSns.has(sn) && String(r.mappedYn ?? '') === 'Y';
|
|
||||||
})
|
|
||||||
.map((r) => String(r.fcltSn ?? ''))
|
.map((r) => String(r.fcltSn ?? ''))
|
||||||
.filter((sn) => sn !== '');
|
.filter((sn) => sn !== '');
|
||||||
|
|
||||||
@@ -605,7 +549,7 @@ const PublicSewageFacilityInp = () => {
|
|||||||
|
|
||||||
mainFacilityMappingSaveDraftRef.current = {
|
mainFacilityMappingSaveDraftRef.current = {
|
||||||
statsYr: lastSearchedValues.year ?? '',
|
statsYr: lastSearchedValues.year ?? '',
|
||||||
sewerBzmnCd: toInputSearchRegion(sidoListRef.current, lastSearchedValues).sewerBzmnCd,
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? '',
|
||||||
admdstCd: String(selectedMain.admdstCd ?? ''),
|
admdstCd: String(selectedMain.admdstCd ?? ''),
|
||||||
admdstNm: String(selectedMain.admdstNm ?? ''),
|
admdstNm: String(selectedMain.admdstNm ?? ''),
|
||||||
mainFcltSn: String(selectedMain.fcltSn ?? ''),
|
mainFcltSn: String(selectedMain.fcltSn ?? ''),
|
||||||
@@ -636,7 +580,7 @@ const PublicSewageFacilityInp = () => {
|
|||||||
|
|
||||||
if (activeTab === 'ST00060001') {
|
if (activeTab === 'ST00060001') {
|
||||||
const noApplicable = getNoApplicableForRequest();
|
const noApplicable = getNoApplicableForRequest();
|
||||||
const treatAsNoApplicable = noApplicable;
|
const treatAsNoApplicable = noApplicable || isNotApplicable;
|
||||||
const currentData =
|
const currentData =
|
||||||
st60001GridGetRowsRef.current?.() ?? rowDataMap.get('ST00060001') ?? [];
|
st60001GridGetRowsRef.current?.() ?? rowDataMap.get('ST00060001') ?? [];
|
||||||
const prxyCtrtCnError = validatePrxyCtrtCnInRows(currentData);
|
const prxyCtrtCnError = validatePrxyCtrtCnInRows(currentData);
|
||||||
@@ -645,7 +589,7 @@ const PublicSewageFacilityInp = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const saveList = treatAsNoApplicable ? [] : buildFacilitySaveList(currentData);
|
const saveList = treatAsNoApplicable ? [] : buildFacilitySaveList(currentData);
|
||||||
if (!treatAsNoApplicable && saveList.length === 0 && buildSubmitOkForToolbar(searchContextByTab.get(activeTab) ?? lastSearchedValues)) {
|
if (!treatAsNoApplicable && saveList.length === 0) {
|
||||||
alert('해당사항 없음을 체크해주세요.');
|
alert('해당사항 없음을 체크해주세요.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -656,7 +600,8 @@ const PublicSewageFacilityInp = () => {
|
|||||||
const param: PublicSewageFacilitySaveRequest = {
|
const param: PublicSewageFacilitySaveRequest = {
|
||||||
statsYr: lastSearchedValues.year ?? '',
|
statsYr: lastSearchedValues.year ?? '',
|
||||||
ctpvNm: lastSearchedValues.sido ?? '',
|
ctpvNm: lastSearchedValues.sido ?? '',
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sggNm: lastSearchedValues.gugun === 'ALL' ? '' : lastSearchedValues.gugun ?? '',
|
||||||
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? '',
|
||||||
userId: userInfo.userUnqId,
|
userId: userInfo.userUnqId,
|
||||||
...(isAdminInfo ? { superAdmin: 'superAdmin' } : {}),
|
...(isAdminInfo ? { superAdmin: 'superAdmin' } : {}),
|
||||||
noApplicable,
|
noApplicable,
|
||||||
@@ -699,28 +644,35 @@ const PublicSewageFacilityInp = () => {
|
|||||||
const firstTabKey = PublicSewageFactInpColumnList[0]?.tabKey ?? 'ST00060001';
|
const firstTabKey = PublicSewageFactInpColumnList[0]?.tabKey ?? 'ST00060001';
|
||||||
const searchParamRef = useRef<PublicSewageFacilityRequestParams | null>(null);
|
const searchParamRef = useRef<PublicSewageFacilityRequestParams | null>(null);
|
||||||
|
|
||||||
const activeTabId = useTabStore((s) => s.activeTabId);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeTabId !== STATISTICS_INPUT_URL_PATH.PUBLIC_SEWAGE_FACILITY) return;
|
|
||||||
const tabKey = activeTab;
|
|
||||||
if (!tabKey) return;
|
|
||||||
if (Object.prototype.hasOwnProperty.call(columnGuidesByTab, tabKey)) return;
|
|
||||||
|
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
void (async () => {
|
void (async () => {
|
||||||
const next = await fetchColumnGuidesRecord(tabKey);
|
const entries = await Promise.all(
|
||||||
if (cancelled) return;
|
PUBLIC_SEWAGE_FACILITY_COLUMN_GUIDE_TAB_KEYS.map(async (tabKey) => {
|
||||||
setColumnGuidesByTab((prev) =>
|
try {
|
||||||
Object.prototype.hasOwnProperty.call(prev, tabKey)
|
const res = await statisticsApi.getColumnGuides(tabKey);
|
||||||
? prev
|
if (res.status !== 'success' || !Array.isArray(res.data)) {
|
||||||
: { ...prev, [tabKey]: next },
|
return [tabKey, {}] as const;
|
||||||
|
}
|
||||||
|
const next: Record<string, string> = {};
|
||||||
|
for (const item of res.data) {
|
||||||
|
const key = item.engColNm?.trim();
|
||||||
|
const guide = item.columnGuide?.trim();
|
||||||
|
if (key && guide) next[key] = guide;
|
||||||
|
}
|
||||||
|
return [tabKey, next] as const;
|
||||||
|
} catch {
|
||||||
|
return [tabKey, {}] as const;
|
||||||
|
}
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
if (cancelled) return;
|
||||||
|
setColumnGuidesByTab(Object.fromEntries(entries));
|
||||||
})();
|
})();
|
||||||
return () => {
|
return () => {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
};
|
};
|
||||||
}, [activeTabId, activeTab, columnGuidesByTab]);
|
}, []);
|
||||||
|
|
||||||
const commitToolbarSnapshotForLoadedTab = (
|
const commitToolbarSnapshotForLoadedTab = (
|
||||||
tabKey: string,
|
tabKey: string,
|
||||||
@@ -743,18 +695,12 @@ const PublicSewageFacilityInp = () => {
|
|||||||
);
|
);
|
||||||
return next;
|
return next;
|
||||||
});
|
});
|
||||||
if (searchContext) {
|
|
||||||
setSearchContextByTab((prev) => {
|
|
||||||
const next = new Map(prev);
|
|
||||||
next.set(tabKey, searchContext);
|
|
||||||
return next;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const buildPublicSewageFacilityParams = (values: SearchFormValues): PublicSewageFacilityRequestParams => ({
|
const buildPublicSewageFacilityParams = (values: SearchFormValues): PublicSewageFacilityRequestParams => ({
|
||||||
ctpvNm: values.sido,
|
ctpvNm: values.sido,
|
||||||
...toInputSearchRegion(sidoListRef.current, values),
|
sggNm: values.gugun === 'ALL' ? '' : values.gugun,
|
||||||
|
sewerBzmnCd: values.bsnmCd,
|
||||||
fcltNm: values.fctName,
|
fcltNm: values.fctName,
|
||||||
statsYr: values.year,
|
statsYr: values.year,
|
||||||
});
|
});
|
||||||
@@ -784,11 +730,7 @@ const PublicSewageFacilityInp = () => {
|
|||||||
const statusInfo = response.data.statusInfo ?? null;
|
const statusInfo = response.data.statusInfo ?? null;
|
||||||
const statsCd = response.data.commonInfo.statsCd || tabKey;
|
const statsCd = response.data.commonInfo.statsCd || tabKey;
|
||||||
const commonInfo = response.data.commonInfo;
|
const commonInfo = response.data.commonInfo;
|
||||||
const list = filterBySelectedAdmdstCd(
|
const list = response.data.publicSewageFacilityList ?? [];
|
||||||
response.data.publicSewageFacilityList ?? [],
|
|
||||||
sidoListRef.current,
|
|
||||||
searchContext,
|
|
||||||
);
|
|
||||||
const convertedData = list.map((item) => ({
|
const convertedData = list.map((item) => ({
|
||||||
ctpvNm: commonInfo.ctpvNm,
|
ctpvNm: commonInfo.ctpvNm,
|
||||||
...item,
|
...item,
|
||||||
@@ -817,9 +759,6 @@ const PublicSewageFacilityInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
|
||||||
setRowDataMap((prev) => {
|
setRowDataMap((prev) => {
|
||||||
const next = new Map(prev);
|
const next = new Map(prev);
|
||||||
next.set('ST00060001', gridRows);
|
next.set('ST00060001', gridRows);
|
||||||
@@ -867,9 +806,6 @@ const PublicSewageFacilityInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, response.data.commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, response.data.commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, response.data.commonInfo),
|
|
||||||
);
|
|
||||||
setRowDataMap((prev) => {
|
setRowDataMap((prev) => {
|
||||||
const next = new Map(prev);
|
const next = new Map(prev);
|
||||||
next.set('MainFacility', leftGridRows);
|
next.set('MainFacility', leftGridRows);
|
||||||
@@ -901,7 +837,8 @@ const PublicSewageFacilityInp = () => {
|
|||||||
const request = {
|
const request = {
|
||||||
statsYr: lastSearchedValues.year ?? '',
|
statsYr: lastSearchedValues.year ?? '',
|
||||||
ctpvNm: lastSearchedValues.sido ?? '',
|
ctpvNm: lastSearchedValues.sido ?? '',
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sggNm: lastSearchedValues.gugun === 'ALL' ? '' : lastSearchedValues.gugun ?? '',
|
||||||
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? '',
|
||||||
userId: userInfo.userUnqId,
|
userId: userInfo.userUnqId,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1031,9 +968,7 @@ const PublicSewageFacilityInp = () => {
|
|||||||
setTabStatusInfoMap(new Map());
|
setTabStatusInfoMap(new Map());
|
||||||
setTabStatsCdMap(new Map());
|
setTabStatsCdMap(new Map());
|
||||||
setIsVerificationFailedByTab(new Map());
|
setIsVerificationFailedByTab(new Map());
|
||||||
setFooterVerificationByTab(new Map());
|
|
||||||
setToolbarSnapshotByTab(new Map());
|
setToolbarSnapshotByTab(new Map());
|
||||||
setSearchContextByTab(new Map());
|
|
||||||
activeTabRef.current = firstTabKey;
|
activeTabRef.current = firstTabKey;
|
||||||
setActiveTab(firstTabKey);
|
setActiveTab(firstTabKey);
|
||||||
}
|
}
|
||||||
@@ -1096,9 +1031,7 @@ const PublicSewageFacilityInp = () => {
|
|||||||
setTabStatusInfoMap(new Map());
|
setTabStatusInfoMap(new Map());
|
||||||
setTabStatsCdMap(new Map());
|
setTabStatsCdMap(new Map());
|
||||||
setIsVerificationFailedByTab(new Map());
|
setIsVerificationFailedByTab(new Map());
|
||||||
setFooterVerificationByTab(new Map());
|
|
||||||
setToolbarSnapshotByTab(new Map());
|
setToolbarSnapshotByTab(new Map());
|
||||||
setSearchContextByTab(new Map());
|
|
||||||
|
|
||||||
setInputPeriodEnterable(true);
|
setInputPeriodEnterable(true);
|
||||||
periodEnterableRef.current = true;
|
periodEnterableRef.current = true;
|
||||||
@@ -1125,8 +1058,9 @@ const PublicSewageFacilityInp = () => {
|
|||||||
const userInfo = await getUserInfo();
|
const userInfo = await getUserInfo();
|
||||||
const statsCdForCancel = tabStatsCdMap.get(activeTab) ?? activeTab;
|
const statsCdForCancel = tabStatsCdMap.get(activeTab) ?? activeTab;
|
||||||
const requestData: cancelSubmitRequest = {
|
const requestData: cancelSubmitRequest = {
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sewerBzmnCd: lastSearchedValues?.bsnmCd ?? '',
|
||||||
ctpvNm: lastSearchedValues?.sido ?? '',
|
ctpvNm: lastSearchedValues?.sido ?? '',
|
||||||
|
sggNm: lastSearchedValues?.gugun === 'ALL' ? '' : lastSearchedValues?.gugun ?? '',
|
||||||
statsYr: lastSearchedValues?.year ?? '',
|
statsYr: lastSearchedValues?.year ?? '',
|
||||||
mdfrId: userInfo.userUnqId,
|
mdfrId: userInfo.userUnqId,
|
||||||
statsCd: statsCdForCancel,
|
statsCd: statsCdForCancel,
|
||||||
@@ -1155,16 +1089,13 @@ const PublicSewageFacilityInp = () => {
|
|||||||
const getGridColumnInfo = (
|
const getGridColumnInfo = (
|
||||||
tab: ColumnInfoList,
|
tab: ColumnInfoList,
|
||||||
guideTabKey?: string,
|
guideTabKey?: string,
|
||||||
canEdit = true,
|
|
||||||
): ColumnInfo => ({
|
): ColumnInfo => ({
|
||||||
columns: (tab.columns ?? []).map((col) => {
|
columns: (tab.columns ?? []).map((col) => {
|
||||||
const guide = columnGuidesByTab[guideTabKey ?? tab.tabKey]?.[col.fieldName]?.trim();
|
const guide = columnGuidesByTab[guideTabKey ?? tab.tabKey]?.[col.fieldName]?.trim();
|
||||||
const withGuide = {
|
return {
|
||||||
...col,
|
...col,
|
||||||
tooltip: guide && guide.length > 0 ? guide : undefined,
|
tooltip: guide && guide.length > 0 ? guide : undefined,
|
||||||
};
|
};
|
||||||
if (canEdit) return withGuide;
|
|
||||||
return { ...withGuide, editable: false as const };
|
|
||||||
}),
|
}),
|
||||||
columnLayout: tab.columnLayout ?? [],
|
columnLayout: tab.columnLayout ?? [],
|
||||||
});
|
});
|
||||||
@@ -1184,9 +1115,7 @@ const PublicSewageFacilityInp = () => {
|
|||||||
const param: PublicSewageMappingTargetsRequestParams = {
|
const param: PublicSewageMappingTargetsRequestParams = {
|
||||||
sewerBzmnCd: searchParamRef.current.sewerBzmnCd ?? '',
|
sewerBzmnCd: searchParamRef.current.sewerBzmnCd ?? '',
|
||||||
ctpvNm: searchParamRef.current.ctpvNm ?? '',
|
ctpvNm: searchParamRef.current.ctpvNm ?? '',
|
||||||
...(searchParamRef.current.sggNm != null
|
sggNm: searchParamRef.current.sggNm ?? '',
|
||||||
? { sggNm: searchParamRef.current.sggNm }
|
|
||||||
: {}),
|
|
||||||
statsYr: searchParamRef.current.statsYr ?? '',
|
statsYr: searchParamRef.current.statsYr ?? '',
|
||||||
fcltSn,
|
fcltSn,
|
||||||
};
|
};
|
||||||
@@ -1202,13 +1131,10 @@ const PublicSewageFacilityInp = () => {
|
|||||||
if (rawList.length === 0) {
|
if (rawList.length === 0) {
|
||||||
alert('해당 시설은 중심처리시설의 위탁시설로 연결되어있습니다.');
|
alert('해당 시설은 중심처리시설의 위탁시설로 연결되어있습니다.');
|
||||||
}
|
}
|
||||||
const mappedTargetRows = applyExclusiveSelfMappingChecks(
|
const mappedTargetRows = rawList.map((item) => ({
|
||||||
rawList.map((item) => ({
|
...item,
|
||||||
...item,
|
__checked: item.mappedYn === 'Y' ? 'Y' : '',
|
||||||
__checked: item.mappedYn === 'Y' ? 'Y' : '',
|
}));
|
||||||
})),
|
|
||||||
fcltSn,
|
|
||||||
);
|
|
||||||
setRowDataMap((prev) => {
|
setRowDataMap((prev) => {
|
||||||
const next = new Map(prev);
|
const next = new Map(prev);
|
||||||
next.set('MainFacilityTarget', toGridRows(mappedTargetRows));
|
next.set('MainFacilityTarget', toGridRows(mappedTargetRows));
|
||||||
@@ -1226,9 +1152,8 @@ const PublicSewageFacilityInp = () => {
|
|||||||
return String(row.fcltSn ?? '') === selectedMainFacilitySn ? 'rg-cell-selected-row' : undefined;
|
return String(row.fcltSn ?? '') === selectedMainFacilitySn ? 'rg-cell-selected-row' : undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const searchContextForToolbar = searchContextByTab.get(activeTab) ?? lastSearchedValues;
|
const searchContextForToolbar = lastSearchedValues ?? searchValues;
|
||||||
const gugunOkOrNotDoList = buildGugunOkForToolbar(searchContextForToolbar);
|
const gugunOkOrNotDoList = buildGugunOkForToolbar(searchContextForToolbar);
|
||||||
const submitOk = buildSubmitOkForToolbar(searchContextForToolbar);
|
|
||||||
const activeTabStatus = tabStatusInfoMap.get(activeTab) ?? null;
|
const activeTabStatus = tabStatusInfoMap.get(activeTab) ?? null;
|
||||||
const activeTabToolbar = computeTabToolbarSnapshot(
|
const activeTabToolbar = computeTabToolbarSnapshot(
|
||||||
activeTabStatus,
|
activeTabStatus,
|
||||||
@@ -1248,7 +1173,7 @@ const PublicSewageFacilityInp = () => {
|
|||||||
isMainFacilityTab &&
|
isMainFacilityTab &&
|
||||||
tabRowDataExists('ST00060002') &&
|
tabRowDataExists('ST00060002') &&
|
||||||
gugunOkOrNotDoList &&
|
gugunOkOrNotDoList &&
|
||||||
inputPeriodEnterable;
|
(isAdminInfo || inputPeriodEnterable);
|
||||||
const showSaveInToolbar =
|
const showSaveInToolbar =
|
||||||
toolbarGroupAllowed && (baseShowSaveInToolbar || showMainFacilitySaveInToolbar);
|
toolbarGroupAllowed && (baseShowSaveInToolbar || showMainFacilitySaveInToolbar);
|
||||||
const showEnterableToolbarButtons =
|
const showEnterableToolbarButtons =
|
||||||
@@ -1273,8 +1198,9 @@ const PublicSewageFacilityInp = () => {
|
|||||||
const statsCd = tabStatsCdMap.get(activeTab) ?? activeTab;
|
const statsCd = tabStatsCdMap.get(activeTab) ?? activeTab;
|
||||||
if (!ctx?.year || !ctx?.sido || !ctx?.bsnmCd || !statsCd) return null;
|
if (!ctx?.year || !ctx?.sido || !ctx?.bsnmCd || !statsCd) return null;
|
||||||
return {
|
return {
|
||||||
...toInputSearchRegion(sidoListRef.current, ctx),
|
sewerBzmnCd: ctx.bsnmCd,
|
||||||
ctpvNm: ctx.sido,
|
ctpvNm: ctx.sido,
|
||||||
|
sggNm: ctx.gugun === 'ALL' ? '' : (ctx.gugun ?? ''),
|
||||||
statsYr: ctx.year,
|
statsYr: ctx.year,
|
||||||
statsCd,
|
statsCd,
|
||||||
};
|
};
|
||||||
@@ -1295,7 +1221,6 @@ const PublicSewageFacilityInp = () => {
|
|||||||
<>
|
<>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<SearchForm
|
<SearchForm
|
||||||
isInput
|
|
||||||
key={searchFormRemountKey}
|
key={searchFormRemountKey}
|
||||||
defaultValues={verificationSearchDefaults ?? undefined}
|
defaultValues={verificationSearchDefaults ?? undefined}
|
||||||
fctName={true}
|
fctName={true}
|
||||||
@@ -1316,12 +1241,12 @@ const PublicSewageFacilityInp = () => {
|
|||||||
)}
|
)}
|
||||||
{showEnterableToolbarButtons && !isMainFacilityTab && (
|
{showEnterableToolbarButtons && !isMainFacilityTab && (
|
||||||
<>
|
<>
|
||||||
{showIsNotApplicable && submitOk && <NotApplicableCheckButton isCheck={isNotApplicable} setIsCheck={setIsNotApplicable} />}
|
{showIsNotApplicable && <NotApplicableCheckButton isCheck={isNotApplicable} setIsCheck={setIsNotApplicable} />}
|
||||||
<UpdateOperateDataButton updateOperateDataButtonFunc={updateOperateDataButtonFunc} />
|
<UpdateOperateDataButton updateOperateDataButtonFunc={updateOperateDataButtonFunc} />
|
||||||
{submitOk && <SubmitButton submitFunc={submitFunc} />}
|
<SubmitButton submitFunc={submitFunc} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{!isMainFacilityTab && activeTabStatus?.laeSbmsnSttsCd === '2' && submitOk && (
|
{!isMainFacilityTab && activeTabStatus?.laeSbmsnSttsCd === '2' && (
|
||||||
<CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />
|
<CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />
|
||||||
)}
|
)}
|
||||||
{showSaveInToolbar && <SaveButton saveFunc={saveFunc} />}
|
{showSaveInToolbar && <SaveButton saveFunc={saveFunc} />}
|
||||||
@@ -1345,28 +1270,14 @@ const PublicSewageFacilityInp = () => {
|
|||||||
</TabsList>
|
</TabsList>
|
||||||
|
|
||||||
{PublicSewageFactInpColumnList.map((tab) => {
|
{PublicSewageFactInpColumnList.map((tab) => {
|
||||||
const tabStatus = tabStatusInfoMap.get(tab.tabKey) ?? null;
|
|
||||||
const tabEnterableForGrid =
|
|
||||||
(computeTabEnterable(tabStatus, inputPeriodEnterable) ||
|
|
||||||
isAdminInfo) &&
|
|
||||||
inputPeriodEnterable;
|
|
||||||
|
|
||||||
if (tab.isSplitGrid && tab.left && tab.right) {
|
if (tab.isSplitGrid && tab.left && tab.right) {
|
||||||
const leftKey = tab.left.tabKey ?? `${tab.tabKey}_left`;
|
const leftKey = tab.left.tabKey ?? `${tab.tabKey}_left`;
|
||||||
const rightKey = tab.right.tabKey ?? `${tab.tabKey}_right`;
|
const rightKey = tab.right.tabKey ?? `${tab.tabKey}_right`;
|
||||||
return (
|
return (
|
||||||
<TabsContent key={tab.tabKey} value={tab.tabKey}>
|
<TabsContent key={tab.tabKey} value={tab.tabKey}>
|
||||||
<SplitDataGrid
|
<SplitDataGrid
|
||||||
leftColumnInfo={getGridColumnInfo(
|
leftColumnInfo={getGridColumnInfo(tab.left, tab.tabKey)}
|
||||||
tab.left,
|
rightColumnInfo={getGridColumnInfo(tab.right, tab.tabKey)}
|
||||||
tab.tabKey,
|
|
||||||
tabEnterableForGrid,
|
|
||||||
)}
|
|
||||||
rightColumnInfo={getGridColumnInfo(
|
|
||||||
tab.right,
|
|
||||||
tab.tabKey,
|
|
||||||
tabEnterableForGrid,
|
|
||||||
)}
|
|
||||||
leftFixedColumns={tab.left.fixedColumns}
|
leftFixedColumns={tab.left.fixedColumns}
|
||||||
rightFixedColumns={tab.right.fixedColumns}
|
rightFixedColumns={tab.right.fixedColumns}
|
||||||
showHeaderCheckbox={true}
|
showHeaderCheckbox={true}
|
||||||
@@ -1392,25 +1303,11 @@ const PublicSewageFacilityInp = () => {
|
|||||||
const next = new Map(prev);
|
const next = new Map(prev);
|
||||||
const rows = [...(next.get('MainFacilityTarget') ?? [])];
|
const rows = [...(next.get('MainFacilityTarget') ?? [])];
|
||||||
if (!rows[itemIndex]) return prev;
|
if (!rows[itemIndex]) return prev;
|
||||||
const clicked = rows[itemIndex];
|
|
||||||
if (
|
|
||||||
checked &&
|
|
||||||
hasCheckedSelfMapping(rows, selectedMainFacilitySn) &&
|
|
||||||
!isSelfMappingTarget(clicked, selectedMainFacilitySn)
|
|
||||||
) {
|
|
||||||
return prev;
|
|
||||||
}
|
|
||||||
rows[itemIndex] = {
|
rows[itemIndex] = {
|
||||||
...clicked,
|
...rows[itemIndex],
|
||||||
__checked: checked ? 'Y' : '',
|
__checked: checked ? 'Y' : '',
|
||||||
};
|
};
|
||||||
next.set(
|
next.set('MainFacilityTarget', rows);
|
||||||
'MainFacilityTarget',
|
|
||||||
applyExclusiveSelfMappingChecks(
|
|
||||||
rows,
|
|
||||||
selectedMainFacilitySn,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return next;
|
return next;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1421,59 +1318,16 @@ const PublicSewageFacilityInp = () => {
|
|||||||
? (checked) => {
|
? (checked) => {
|
||||||
setRowDataMap((prev) => {
|
setRowDataMap((prev) => {
|
||||||
const next = new Map(prev);
|
const next = new Map(prev);
|
||||||
const rows = [...(next.get('MainFacilityTarget') ?? [])];
|
const rows = [...(next.get('MainFacilityTarget') ?? [])].map((r) => ({
|
||||||
if (
|
...r,
|
||||||
checked &&
|
__checked: checked ? 'Y' : '',
|
||||||
hasCheckedSelfMapping(rows, selectedMainFacilitySn)
|
}));
|
||||||
) {
|
next.set('MainFacilityTarget', rows);
|
||||||
next.set(
|
|
||||||
'MainFacilityTarget',
|
|
||||||
applyExclusiveSelfMappingChecks(
|
|
||||||
rows,
|
|
||||||
selectedMainFacilitySn,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
next.set(
|
|
||||||
'MainFacilityTarget',
|
|
||||||
rows.map((r) => ({
|
|
||||||
...r,
|
|
||||||
__checked:
|
|
||||||
checked &&
|
|
||||||
!isSelfMappingTarget(
|
|
||||||
r,
|
|
||||||
selectedMainFacilitySn,
|
|
||||||
)
|
|
||||||
? 'Y'
|
|
||||||
: '',
|
|
||||||
})),
|
|
||||||
);
|
|
||||||
return next;
|
return next;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
rightCheckableCallback={
|
|
||||||
tab.tabKey === 'ST00060002'
|
|
||||||
? (row) => {
|
|
||||||
const rows =
|
|
||||||
rowDataMap.get('MainFacilityTarget') ?? [];
|
|
||||||
if (
|
|
||||||
!hasCheckedSelfMapping(
|
|
||||||
rows,
|
|
||||||
selectedMainFacilitySn,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return isSelfMappingTarget(
|
|
||||||
row,
|
|
||||||
selectedMainFacilitySn,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
setLeftRowData={(updater) => {
|
setLeftRowData={(updater) => {
|
||||||
setRowDataMap((prev) => {
|
setRowDataMap((prev) => {
|
||||||
const next = new Map(prev);
|
const next = new Map(prev);
|
||||||
@@ -1503,10 +1357,11 @@ const PublicSewageFacilityInp = () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const gridColumnInfo = getGridColumnInfo(
|
const gridColumnInfo = getGridColumnInfo(tab);
|
||||||
tab,
|
const tabStatus = tabStatusInfoMap.get(tab.tabKey) ?? null;
|
||||||
undefined,
|
const tabEnterableForGrid = computeTabEnterable(
|
||||||
tabEnterableForGrid,
|
tabStatus,
|
||||||
|
inputPeriodEnterable,
|
||||||
);
|
);
|
||||||
const excelToolbarEnabledForTab =
|
const excelToolbarEnabledForTab =
|
||||||
tabRowDataExists(tab.tabKey) &&
|
tabRowDataExists(tab.tabKey) &&
|
||||||
@@ -1516,7 +1371,7 @@ const PublicSewageFacilityInp = () => {
|
|||||||
return (
|
return (
|
||||||
<TabsContent key={tab.tabKey} value={tab.tabKey}>
|
<TabsContent key={tab.tabKey} value={tab.tabKey}>
|
||||||
<DataGrid
|
<DataGrid
|
||||||
key={`${tab.tabKey}-${tabEnterableForGrid ? 'enterable' : 'readonly'}`}
|
key={tab.tabKey}
|
||||||
columnInfo={gridColumnInfo}
|
columnInfo={gridColumnInfo}
|
||||||
rowStartNum={tab.rowStartNum}
|
rowStartNum={tab.rowStartNum}
|
||||||
excelExportFileSuffix={tab.tabLabel || tab.tabKey}
|
excelExportFileSuffix={tab.tabLabel || tab.tabKey}
|
||||||
@@ -1545,29 +1400,14 @@ const PublicSewageFacilityInp = () => {
|
|||||||
showHeaderCheckbox={false}
|
showHeaderCheckbox={false}
|
||||||
enableSort={false}
|
enableSort={false}
|
||||||
cellStyleCallback={({ row, fieldName }) => {
|
cellStyleCallback={({ row, fieldName }) => {
|
||||||
const lockPrxyCtrtCn =
|
|
||||||
fieldName === 'prxyCtrtCn' && isMainFacilityRow(row);
|
|
||||||
const verification = (row as GridRowWithVerification).verificationResult;
|
const verification = (row as GridRowWithVerification).verificationResult;
|
||||||
let verifyStyle: string | undefined;
|
if (!verification) return;
|
||||||
if (verification) {
|
const errors = verification[fieldName];
|
||||||
const errors = verification[fieldName];
|
if (Array.isArray(errors) && errors.length > 0) {
|
||||||
if (Array.isArray(errors) && errors.length > 0) {
|
const hasImr = errors.some((e) => e.vrfcCd === "IMR" || e.vrfcCd === "HB");
|
||||||
const hasImr = errors.some((e) => e.vrfcCd === "IMR" || e.vrfcCd === "HB");
|
return hasImr ? "rg-cell-verify-error-imr" : "rg-cell-verify-error";
|
||||||
verifyStyle = hasImr ? "rg-cell-verify-error-imr" : "rg-cell-verify-error";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (lockPrxyCtrtCn) {
|
|
||||||
return {
|
|
||||||
editable: false,
|
|
||||||
readOnly: true,
|
|
||||||
styleName: [verifyStyle, 'rg-cell-readonly'].filter(Boolean).join(' ') || 'rg-cell-readonly',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return verifyStyle;
|
|
||||||
}}
|
}}
|
||||||
footerVerificationResult={
|
|
||||||
footerVerificationByTab.get(tab.tabKey) ?? null
|
|
||||||
}
|
|
||||||
cellTooltipCallback={({ row, fieldName }) => {
|
cellTooltipCallback={({ row, fieldName }) => {
|
||||||
const verification = (row as GridRowWithVerification).verificationResult;
|
const verification = (row as GridRowWithVerification).verificationResult;
|
||||||
if (!verification) return;
|
if (!verification) return;
|
||||||
@@ -1576,7 +1416,7 @@ const PublicSewageFacilityInp = () => {
|
|||||||
return errors
|
return errors
|
||||||
.map((e) => {
|
.map((e) => {
|
||||||
const prefix =
|
const prefix =
|
||||||
e.vrfcCd === "IMR" ? "시계열 검증 - " : (e.vrfcCd === "NV" ? "일반검증 - " : "모집단 검증 - ");
|
e.vrfcCd === "IMR" ? "IMR검증 - " : (e.vrfcCd === "NV" ? "일반검증 - " : "HB검증 - ");
|
||||||
const comp = e.compVlCn ?? "";
|
const comp = e.compVlCn ?? "";
|
||||||
const now = e.nowVlCn ?? "";
|
const now = e.nowVlCn ?? "";
|
||||||
return `${prefix}${e.rsnExpln}
|
return `${prefix}${e.rsnExpln}
|
||||||
|
|||||||
@@ -1,56 +1,20 @@
|
|||||||
import {
|
import {
|
||||||
type RefObject,
|
|
||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
useMemo,
|
useMemo,
|
||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
|
type RefObject,
|
||||||
} from "react";
|
} from "react";
|
||||||
|
|
||||||
import { flushSync } from "react-dom";
|
import { flushSync } from "react-dom";
|
||||||
|
|
||||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||||
|
|
||||||
import { ValueType } from "realgrid";
|
import { ValueType } from "realgrid";
|
||||||
import type { RealGridReact } from "realgrid-react";
|
import type { RealGridReact } from "realgrid-react";
|
||||||
|
|
||||||
import { useAlertStore, useGlobalProgressStore, useStatisticsInputToolbarGroupGate, useSearchConditionSidoList } from "@/shared/lib";
|
|
||||||
import { STATISTICS_INPUT_URL_PATH } from "@/shared/lib/stats-cd-input-navigation";
|
|
||||||
import { useStatisticsInputPendingNavigation } from "@/shared/lib/use-statistics-input-pending-navigation";
|
|
||||||
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
|
||||||
import { nullableTrimmedString } from "@/components/util/input/nullableString";
|
|
||||||
import { statisticsInputPumpingStationApi } from "@/entities/statistics/api/input/statistics-input-pumping-station-service";
|
|
||||||
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
|
||||||
import {
|
|
||||||
PUMPING_STATION_STATS_CD,
|
|
||||||
type PumpingStationItem,
|
|
||||||
type PumpingStationRequestParams,
|
|
||||||
type PumpingStationSaveItem,
|
|
||||||
type PumpingStationVerificationResult,
|
|
||||||
} from "@/entities/statistics/model/input/statistics-input-pumping-station-interface";
|
|
||||||
import { isInputPeriodCurrent } from "@/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface";
|
|
||||||
import type { StatisticsInputSubmitInfoFormData } from "@/entities/statistics/model/statistics-input-submit-info-schema";
|
|
||||||
import type {
|
|
||||||
ApiResponse,
|
|
||||||
cancelSubmitRequest,
|
|
||||||
ImrStatusResponse,
|
|
||||||
SewerageStatusInfo,
|
|
||||||
Sgg,
|
|
||||||
Sido,
|
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
|
||||||
import {
|
|
||||||
filterBySelectedAdmdstCd,
|
|
||||||
isGugunOkForToolbar,
|
|
||||||
isSubmitOkForToolbar,
|
|
||||||
resolveNoApplicableForRequest,
|
|
||||||
toInputSearchRegion,
|
|
||||||
} from "@/entities/statistics";
|
|
||||||
|
|
||||||
import { LoadingWithAnimation } from "@common/components";
|
import { LoadingWithAnimation } from "@common/components";
|
||||||
|
|
||||||
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
|
||||||
|
|
||||||
import SubmitDailog from "./SubmitDailog";
|
|
||||||
|
|
||||||
import AddArticleButton from "@/components/button/AddArticleButton";
|
import AddArticleButton from "@/components/button/AddArticleButton";
|
||||||
import CancelSubmitButton from "@/components/button/CancelSubmitButton";
|
import CancelSubmitButton from "@/components/button/CancelSubmitButton";
|
||||||
import DeleteArticleButton from "@/components/button/DeleteArticleButton";
|
import DeleteArticleButton from "@/components/button/DeleteArticleButton";
|
||||||
@@ -60,24 +24,49 @@ import SaveButton from "@/components/button/SaveButton";
|
|||||||
import SubmitButton from "@/components/button/SumitButton";
|
import SubmitButton from "@/components/button/SumitButton";
|
||||||
import VerificationResultButton from "@/components/button/VerificationResultButton";
|
import VerificationResultButton from "@/components/button/VerificationResultButton";
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
|
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
||||||
import { openVerificationResultDialogIfNeeded } from "@/components/module/post-submit-verification-results";
|
import { openVerificationResultDialogIfNeeded } from "@/components/module/post-submit-verification-results";
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
||||||
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
||||||
|
import { PumpingStationInpColumn } from "@/components/util/column/input/PumpingStationInpColumn";
|
||||||
|
import SubmitDailog from "./SubmitDailog";
|
||||||
import type {
|
import type {
|
||||||
CellStyleCallbackParams,
|
CellStyleCallbackParams,
|
||||||
CellTooltipCallbackParams,
|
CellTooltipCallbackParams,
|
||||||
ColumnConfig,
|
ColumnConfig,
|
||||||
} from "@/components/type/DataGrid.type";
|
} from "@/components/type/DataGrid.type";
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
import { PumpingStationInpColumn } from "@/components/util/column/input/PumpingStationInpColumn";
|
import { doList } from "@/components/util/column/input/DoList";
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
import { formatCompactYmdForGrid, toCompactYmdOrNull } from "@/components/util/grid/ymdFormat";
|
|
||||||
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
|
||||||
import { isVerificationFailedFromCommonInfo } from "@/components/util/input/verification-failed-flag";
|
import { isVerificationFailedFromCommonInfo } from "@/components/util/input/verification-failed-flag";
|
||||||
import type { VerificationResultLikeMap } from "@/components/util/input/verification-result-display";
|
import { formatCompactYmdForGrid, toCompactYmdOrNull } from "@/components/util/grid/ymdFormat";
|
||||||
|
import { statisticsInputPumpingStationApi } from "@/entities/statistics/api/input/statistics-input-pumping-station-service";
|
||||||
|
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
||||||
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
|
import { isInputPeriodCurrent } from "@/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface";
|
||||||
|
import {
|
||||||
|
PUMPING_STATION_STATS_CD,
|
||||||
|
type PumpingStationItem,
|
||||||
|
type PumpingStationRequestParams,
|
||||||
|
type PumpingStationSaveItem,
|
||||||
|
type PumpingStationVerificationResult,
|
||||||
|
} from "@/entities/statistics/model/input/statistics-input-pumping-station-interface";
|
||||||
|
import type {
|
||||||
|
ApiResponse,
|
||||||
|
cancelSubmitRequest,
|
||||||
|
ImrStatusResponse,
|
||||||
|
Sgg,
|
||||||
|
SewerageStatusInfo,
|
||||||
|
} from "@/entities/statistics/model/statistics-interface";
|
||||||
|
import { useAlertStore, useGlobalProgressStore, useStatisticsInputToolbarGroupGate } from "@/shared/lib";
|
||||||
|
import { STATISTICS_INPUT_URL_PATH } from "@/shared/lib/stats-cd-input-navigation";
|
||||||
|
import { useStatisticsInputPendingNavigation } from "@/shared/lib/use-statistics-input-pending-navigation";
|
||||||
|
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
||||||
import { useAdminStore } from "@/store/admin-store";
|
import { useAdminStore } from "@/store/admin-store";
|
||||||
import { useTabStore } from "@/store/tab-store";
|
|
||||||
|
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
||||||
|
import type { StatisticsInputSubmitInfoFormData } from "@/entities/statistics/model/statistics-input-submit-info-schema";
|
||||||
|
|
||||||
type GridRowWithVerification = Record<string, string | number> & {
|
type GridRowWithVerification = Record<string, string | number> & {
|
||||||
verificationResult?: PumpingStationVerificationResult;
|
verificationResult?: PumpingStationVerificationResult;
|
||||||
@@ -102,22 +91,10 @@ const computeTabEnterable = (
|
|||||||
return periodEnterable;
|
return periodEnterable;
|
||||||
};
|
};
|
||||||
|
|
||||||
const sidoListRef: { current: Sido[] } = { current: [] };
|
|
||||||
|
|
||||||
function buildGugunOkForToolbar(values: SearchFormValues | null): boolean {
|
function buildGugunOkForToolbar(values: SearchFormValues | null): boolean {
|
||||||
return isGugunOkForToolbar(sidoListRef.current, values);
|
return doList.includes(values?.bsnmCd || "")
|
||||||
}
|
? Boolean(values?.gugun && values.gugun !== "ALL")
|
||||||
|
: true;
|
||||||
function buildSubmitOkForToolbar(values: SearchFormValues | null): boolean {
|
|
||||||
return isSubmitOkForToolbar(sidoListRef.current, values);
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildNoApplicableForRequest(
|
|
||||||
values: SearchFormValues | null,
|
|
||||||
checked: boolean,
|
|
||||||
isSaveListEmpty: boolean,
|
|
||||||
): boolean {
|
|
||||||
return resolveNoApplicableForRequest(sidoListRef.current, values, checked, isSaveListEmpty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeTabToolbarSnapshot(
|
function computeTabToolbarSnapshot(
|
||||||
@@ -131,7 +108,7 @@ function computeTabToolbarSnapshot(
|
|||||||
const gugunOk = buildGugunOkForToolbar(searchContext);
|
const gugunOk = buildGugunOkForToolbar(searchContext);
|
||||||
const enterable = computeTabEnterable(statusInfo, periodEnterable);
|
const enterable = computeTabEnterable(statusInfo, periodEnterable);
|
||||||
const isSubmitted = statusInfo?.laeSbmsnSttsCd === "2";
|
const isSubmitted = statusInfo?.laeSbmsnSttsCd === "2";
|
||||||
const showSaveInToolbar = (enterable || isAdminInfo) && periodEnterable && gugunOk;
|
const showSaveInToolbar = (enterable || isAdminInfo) && gugunOk;
|
||||||
const showEnterableToolbarButtons = enterable && gugunOk;
|
const showEnterableToolbarButtons = enterable && gugunOk;
|
||||||
const showSubmittedInInputPeriodToolbar =
|
const showSubmittedInInputPeriodToolbar =
|
||||||
isSubmitted && periodEnterable && gugunOk;
|
isSubmitted && periodEnterable && gugunOk;
|
||||||
@@ -151,8 +128,9 @@ function buildPumpingStationSearchParam(
|
|||||||
const fcltNm = values.fctName?.trim();
|
const fcltNm = values.fctName?.trim();
|
||||||
return {
|
return {
|
||||||
statsYr: values.year,
|
statsYr: values.year,
|
||||||
|
sewerBzmnCd: values.bsnmCd,
|
||||||
ctpvNm: values.sido,
|
ctpvNm: values.sido,
|
||||||
...toInputSearchRegion(sidoListRef.current, values),
|
sggNm: values.gugun === "ALL" ? "" : values.gugun,
|
||||||
...(fcltNm ? { fcltNm } : {}),
|
...(fcltNm ? { fcltNm } : {}),
|
||||||
...(overrides?.mode ? { mode: overrides.mode } : {}),
|
...(overrides?.mode ? { mode: overrides.mode } : {}),
|
||||||
};
|
};
|
||||||
@@ -212,6 +190,13 @@ function mapPumpingStationListToGridRows(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function nullableTrimmedString(
|
||||||
|
value: string | number | null | undefined,
|
||||||
|
): string | null {
|
||||||
|
const s = String(value ?? "").trim();
|
||||||
|
return s === "" ? null : s;
|
||||||
|
}
|
||||||
|
|
||||||
function toGridNumber(value: string | number | null | undefined): number {
|
function toGridNumber(value: string | number | null | undefined): number {
|
||||||
const n = Number(value);
|
const n = Number(value);
|
||||||
return Number.isFinite(n) ? n : 0;
|
return Number.isFinite(n) ? n : 0;
|
||||||
@@ -220,9 +205,9 @@ function toGridNumber(value: string | number | null | undefined): number {
|
|||||||
function resolvePumpingStationAdmdst(
|
function resolvePumpingStationAdmdst(
|
||||||
row: Record<string, string | number>,
|
row: Record<string, string | number>,
|
||||||
sggOptions: Sgg[],
|
sggOptions: Sgg[],
|
||||||
): { admdstCd: string | null; admdstNm: string | null } {
|
): { admdstCd: string; admdstNm: string } {
|
||||||
const existingCd = nullableTrimmedString(row.admdstCd);
|
const existingCd = String(row.admdstCd ?? "").trim();
|
||||||
const existingNm = nullableTrimmedString(row.admdstNm);
|
const existingNm = String(row.admdstNm ?? "").trim();
|
||||||
if (existingCd && existingNm) {
|
if (existingCd && existingNm) {
|
||||||
return { admdstCd: existingCd, admdstNm: existingNm };
|
return { admdstCd: existingCd, admdstNm: existingNm };
|
||||||
}
|
}
|
||||||
@@ -231,10 +216,7 @@ function resolvePumpingStationAdmdst(
|
|||||||
if (matched) {
|
if (matched) {
|
||||||
return { admdstCd: matched.bsnmCd, admdstNm: matched.gugun };
|
return { admdstCd: matched.bsnmCd, admdstNm: matched.gugun };
|
||||||
}
|
}
|
||||||
return {
|
return { admdstCd: existingCd, admdstNm: existingNm || sggNm };
|
||||||
admdstCd: existingCd,
|
|
||||||
admdstNm: existingNm ?? nullableTrimmedString(sggNm),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 그리드 행 → ST00050001 저장/삭제 API 항목 */
|
/** 그리드 행 → ST00050001 저장/삭제 API 항목 */
|
||||||
@@ -243,14 +225,15 @@ function buildPumpingStationSaveItem(
|
|||||||
sggOptions: Sgg[] = [],
|
sggOptions: Sgg[] = [],
|
||||||
): PumpingStationSaveItem {
|
): PumpingStationSaveItem {
|
||||||
const { admdstCd, admdstNm } = resolvePumpingStationAdmdst(row, sggOptions);
|
const { admdstCd, admdstNm } = resolvePumpingStationAdmdst(row, sggOptions);
|
||||||
|
const fcltSn = String(row.fcltSn ?? "").trim();
|
||||||
return {
|
return {
|
||||||
admdstCd,
|
admdstCd,
|
||||||
admdstNm,
|
admdstNm,
|
||||||
fcltSn: nullableTrimmedString(row.fcltSn),
|
fcltSn: fcltSn,
|
||||||
swtrmtFcltNm: nullableTrimmedString(row.swtrmtFcltNm),
|
swtrmtFcltNm: String(row.swtrmtFcltNm ?? ""),
|
||||||
fcltNm: nullableTrimmedString(row.fcltNm),
|
fcltNm: String(row.fcltNm ?? ""),
|
||||||
pumpSeNm: nullableTrimmedString(row.pumpSeNm),
|
pumpSeNm: String(row.pumpSeNm ?? ""),
|
||||||
fcltPstnCn: nullableTrimmedString(row.fcltPstnCn),
|
fcltPstnCn: String(row.fcltPstnCn ?? ""),
|
||||||
oprtngStrtYmd: toCompactYmdOrNull(row.oprtngStrtYmd),
|
oprtngStrtYmd: toCompactYmdOrNull(row.oprtngStrtYmd),
|
||||||
planMltvArea: toGridNumber(row.planMltvArea),
|
planMltvArea: toGridNumber(row.planMltvArea),
|
||||||
sndyArea: toGridNumber(row.sndyArea),
|
sndyArea: toGridNumber(row.sndyArea),
|
||||||
@@ -302,11 +285,11 @@ async function waitForImrJobCompleted(
|
|||||||
options?.onProgress?.(Math.max(0, Math.min(100, Number(res.job_prog) || 0)));
|
options?.onProgress?.(Math.max(0, Math.min(100, Number(res.job_prog) || 0)));
|
||||||
if (res.status === "COMPLETED" && Number(res.job_prog) === 100) return;
|
if (res.status === "COMPLETED" && Number(res.job_prog) === 100) return;
|
||||||
if (res.status === "FAILED" || res.status === "ERROR" || res.status === "CANCELLED") {
|
if (res.status === "FAILED" || res.status === "ERROR" || res.status === "CANCELLED") {
|
||||||
throw new Error(res.error_msg || `시계열 검증이 ${res.status} 상태로 종료되었습니다.`);
|
throw new Error(res.error_msg || `IMR 검증이 ${res.status} 상태로 종료되었습니다.`);
|
||||||
}
|
}
|
||||||
await sleep(pollIntervalMs);
|
await sleep(pollIntervalMs);
|
||||||
}
|
}
|
||||||
throw new Error("시계열 검증 완료 대기 시간이 초과되었습니다.");
|
throw new Error("IMR 검증 완료 대기 시간이 초과되었습니다.");
|
||||||
}
|
}
|
||||||
|
|
||||||
function createEmptyPumpingStationRow(
|
function createEmptyPumpingStationRow(
|
||||||
@@ -328,8 +311,6 @@ const PUMPING_STATION_FACILITY_NAME_GUIDE_MESSAGE =
|
|||||||
|
|
||||||
// 하수도 통계 관리 > 05. 펌프장 (SewageReservoirPumpInp 단일 탭 패턴)
|
// 하수도 통계 관리 > 05. 펌프장 (SewageReservoirPumpInp 단일 탭 패턴)
|
||||||
const PumpingStationInp = () => {
|
const PumpingStationInp = () => {
|
||||||
const { sidoList } = useSearchConditionSidoList({ isInput: true });
|
|
||||||
sidoListRef.current = sidoList;
|
|
||||||
const { setMessage: alert } = useAlertStore((state) => state);
|
const { setMessage: alert } = useAlertStore((state) => state);
|
||||||
const { confirm } = useConfirm();
|
const { confirm } = useConfirm();
|
||||||
const { isAdminInfo } = useAdminStore();
|
const { isAdminInfo } = useAdminStore();
|
||||||
@@ -352,8 +333,6 @@ const PumpingStationInp = () => {
|
|||||||
const [statusInfo, setStatusInfo] = useState<SewerageStatusInfo | null>(null);
|
const [statusInfo, setStatusInfo] = useState<SewerageStatusInfo | null>(null);
|
||||||
const [statsCd, setStatsCd] = useState("");
|
const [statsCd, setStatsCd] = useState("");
|
||||||
const [isVerificationFailed, setIsVerificationFailed] = useState(false);
|
const [isVerificationFailed, setIsVerificationFailed] = useState(false);
|
||||||
const [footerVerificationResult, setFooterVerificationResult] =
|
|
||||||
useState<VerificationResultLikeMap | null>(null);
|
|
||||||
const [inputPeriodEnterable, setInputPeriodEnterable] = useState(true);
|
const [inputPeriodEnterable, setInputPeriodEnterable] = useState(true);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [sggOptions, setSggOptions] = useState<Sgg[]>([]);
|
const [sggOptions, setSggOptions] = useState<Sgg[]>([]);
|
||||||
@@ -374,10 +353,7 @@ const PumpingStationInp = () => {
|
|||||||
const sggOptionsSidoRef = useRef<string | null>(null);
|
const sggOptionsSidoRef = useRef<string | null>(null);
|
||||||
const [searchLoaded, setSearchLoaded] = useState(false);
|
const [searchLoaded, setSearchLoaded] = useState(false);
|
||||||
|
|
||||||
const activeTabId = useTabStore((s) => s.activeTabId);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeTabId !== STATISTICS_INPUT_URL_PATH.PUMPING_STATION) return;
|
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
void (async () => {
|
void (async () => {
|
||||||
try {
|
try {
|
||||||
@@ -401,7 +377,7 @@ const PumpingStationInp = () => {
|
|||||||
return () => {
|
return () => {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
};
|
};
|
||||||
}, [activeTabId]);
|
}, []);
|
||||||
|
|
||||||
const loadSggOptions = useCallback(async (sido: string): Promise<Sgg[]> => {
|
const loadSggOptions = useCallback(async (sido: string): Promise<Sgg[]> => {
|
||||||
if (!sido || sido === "ALL") {
|
if (!sido || sido === "ALL") {
|
||||||
@@ -421,7 +397,7 @@ const PumpingStationInp = () => {
|
|||||||
|
|
||||||
const columnInfo = useMemo(() => {
|
const columnInfo = useMemo(() => {
|
||||||
const enterable =
|
const enterable =
|
||||||
(computeTabEnterable(statusInfo, inputPeriodEnterable) || isAdminInfo) && inputPeriodEnterable;
|
computeTabEnterable(statusInfo, inputPeriodEnterable) || isAdminInfo;
|
||||||
const rawColumns = PumpingStationInpColumn.columns ?? [];
|
const rawColumns = PumpingStationInpColumn.columns ?? [];
|
||||||
const base = enterable
|
const base = enterable
|
||||||
? rawColumns
|
? rawColumns
|
||||||
@@ -449,7 +425,7 @@ const PumpingStationInp = () => {
|
|||||||
}, [statusInfo, inputPeriodEnterable, isAdminInfo, sggOptions, columnGuidesByEngCol]);
|
}, [statusInfo, inputPeriodEnterable, isAdminInfo, sggOptions, columnGuidesByEngCol]);
|
||||||
|
|
||||||
const canEditGrid =
|
const canEditGrid =
|
||||||
(computeTabEnterable(statusInfo, inputPeriodEnterable) || isAdminInfo) && inputPeriodEnterable;
|
computeTabEnterable(statusInfo, inputPeriodEnterable) || isAdminInfo;
|
||||||
|
|
||||||
const getCurrentRows = (): Record<string, string | number>[] =>
|
const getCurrentRows = (): Record<string, string | number>[] =>
|
||||||
gridGetRowsRef.current?.() ?? rowData;
|
gridGetRowsRef.current?.() ?? rowData;
|
||||||
@@ -481,11 +457,7 @@ const PumpingStationInp = () => {
|
|||||||
|
|
||||||
const { commonInfo, statusInfo: nextStatusInfo, pumpingStationList } =
|
const { commonInfo, statusInfo: nextStatusInfo, pumpingStationList } =
|
||||||
response.data;
|
response.data;
|
||||||
const list = filterBySelectedAdmdstCd(
|
const list = pumpingStationList ?? [];
|
||||||
pumpingStationList ?? [],
|
|
||||||
sidoListRef.current,
|
|
||||||
values,
|
|
||||||
);
|
|
||||||
const gridRows = mapPumpingStationListToGridRows(list, commonInfo.ctpvNm);
|
const gridRows = mapPumpingStationListToGridRows(list, commonInfo.ctpvNm);
|
||||||
|
|
||||||
setPumpingStationDeleteList([]);
|
setPumpingStationDeleteList([]);
|
||||||
@@ -493,7 +465,6 @@ const PumpingStationInp = () => {
|
|||||||
setStatusInfo(nextStatusInfo);
|
setStatusInfo(nextStatusInfo);
|
||||||
setStatsCd(commonInfo.statsCd);
|
setStatsCd(commonInfo.statsCd);
|
||||||
setIsVerificationFailed(isVerificationFailedFromCommonInfo(commonInfo));
|
setIsVerificationFailed(isVerificationFailedFromCommonInfo(commonInfo));
|
||||||
setFooterVerificationResult(commonInfo.verificationResult ?? null);
|
|
||||||
if (overrides?.mode !== "PRE") {
|
if (overrides?.mode !== "PRE") {
|
||||||
setIsNotApplicable(gridRows.length === 0);
|
setIsNotApplicable(gridRows.length === 0);
|
||||||
} else if (gridRows.length > 0) {
|
} else if (gridRows.length > 0) {
|
||||||
@@ -553,7 +524,6 @@ const PumpingStationInp = () => {
|
|||||||
setStatusInfo(null);
|
setStatusInfo(null);
|
||||||
setStatsCd("");
|
setStatsCd("");
|
||||||
setIsVerificationFailed(false);
|
setIsVerificationFailed(false);
|
||||||
setFooterVerificationResult(null);
|
|
||||||
setIsNotApplicable(false);
|
setIsNotApplicable(false);
|
||||||
setInputPeriodEnterable(true);
|
setInputPeriodEnterable(true);
|
||||||
setSggOptions([]);
|
setSggOptions([]);
|
||||||
@@ -603,8 +573,12 @@ const PumpingStationInp = () => {
|
|||||||
|
|
||||||
const userInfo = await getUserInfo();
|
const userInfo = await getUserInfo();
|
||||||
const requestData: cancelSubmitRequest = {
|
const requestData: cancelSubmitRequest = {
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
mdfrId: userInfo.userUnqId,
|
mdfrId: userInfo.userUnqId,
|
||||||
statsCd: statsCd || PUMPING_STATION_STATS_CD,
|
statsCd: statsCd || PUMPING_STATION_STATS_CD,
|
||||||
@@ -639,9 +613,9 @@ const PumpingStationInp = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const noApplicable = buildNoApplicableForRequest(lastSearchedValues, isNotApplicable, getCurrentRows().length === 0);
|
const noApplicable = isNotApplicable;
|
||||||
const currentData = getCurrentRows();
|
const currentData = getCurrentRows();
|
||||||
if (!noApplicable && currentData.length === 0 && buildSubmitOkForToolbar(lastSearchedValues)) {
|
if (!noApplicable && currentData.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -668,7 +642,7 @@ const PumpingStationInp = () => {
|
|||||||
if (!(await confirm("저장 하시겠습니까?"))) return;
|
if (!(await confirm("저장 하시겠습니까?"))) return;
|
||||||
|
|
||||||
commitGrid();
|
commitGrid();
|
||||||
const noApplicable = buildNoApplicableForRequest(lastSearchedValues, isNotApplicable, getCurrentRows().length === 0);
|
const noApplicable = isNotApplicable;
|
||||||
const currentData = getCurrentRows();
|
const currentData = getCurrentRows();
|
||||||
const saveList = noApplicable
|
const saveList = noApplicable
|
||||||
? []
|
? []
|
||||||
@@ -679,7 +653,7 @@ const PumpingStationInp = () => {
|
|||||||
.filter((row) => String(row.fcltSn ?? "").trim() !== "")
|
.filter((row) => String(row.fcltSn ?? "").trim() !== "")
|
||||||
.map((row) => buildPumpingStationSaveItem(row, sggOptions));
|
.map((row) => buildPumpingStationSaveItem(row, sggOptions));
|
||||||
|
|
||||||
if (!noApplicable && saveList.length === 0 && buildSubmitOkForToolbar(lastSearchedValues)) {
|
if (!noApplicable && saveList.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -690,7 +664,11 @@ const PumpingStationInp = () => {
|
|||||||
const response = await statisticsInputPumpingStationApi.savePumpingStationList({
|
const response = await statisticsInputPumpingStationApi.savePumpingStationList({
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
userId: userInfo.userUnqId,
|
userId: userInfo.userUnqId,
|
||||||
...(isAdminInfo ? { superAdmin: "superAdmin" } : {}),
|
...(isAdminInfo ? { superAdmin: "superAdmin" } : {}),
|
||||||
noApplicable,
|
noApplicable,
|
||||||
@@ -724,7 +702,7 @@ const PumpingStationInp = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
commitGrid();
|
commitGrid();
|
||||||
const noApplicable = buildNoApplicableForRequest(lastSearchedValues, isNotApplicable, getCurrentRows().length === 0);
|
const noApplicable = isNotApplicable;
|
||||||
const currentData = getCurrentRows();
|
const currentData = getCurrentRows();
|
||||||
const submitList = noApplicable
|
const submitList = noApplicable
|
||||||
? []
|
? []
|
||||||
@@ -733,15 +711,19 @@ const PumpingStationInp = () => {
|
|||||||
.filter((row) => String(row.fcltSn ?? "").trim() !== "")
|
.filter((row) => String(row.fcltSn ?? "").trim() !== "")
|
||||||
.map((row) => buildPumpingStationSaveItem(row, sggOptions));
|
.map((row) => buildPumpingStationSaveItem(row, sggOptions));
|
||||||
|
|
||||||
if (!noApplicable && submitList.length === 0 && buildSubmitOkForToolbar(lastSearchedValues)) {
|
if (!noApplicable && submitList.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const statsCdForSubmit = statsCd || PUMPING_STATION_STATS_CD;
|
const statsCdForSubmit = statsCd || PUMPING_STATION_STATS_CD;
|
||||||
const verificationQuery = {
|
const verificationQuery = {
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
statsCd: statsCdForSubmit,
|
statsCd: statsCdForSubmit,
|
||||||
};
|
};
|
||||||
@@ -758,7 +740,11 @@ const PumpingStationInp = () => {
|
|||||||
const response = await statisticsInputPumpingStationApi.submitPumpingStationList({
|
const response = await statisticsInputPumpingStationApi.submitPumpingStationList({
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
userId: userInfo.userUnqId,
|
userId: userInfo.userUnqId,
|
||||||
laePicNm: submitInfo.laePicNm,
|
laePicNm: submitInfo.laePicNm,
|
||||||
laePicTelNo: submitInfo.laePicTelNo,
|
laePicTelNo: submitInfo.laePicTelNo,
|
||||||
@@ -784,16 +770,15 @@ const PumpingStationInp = () => {
|
|||||||
|
|
||||||
if (finalStatus === "5") {
|
if (finalStatus === "5") {
|
||||||
setGlobalProgress(50);
|
setGlobalProgress(50);
|
||||||
setGlobalProgressLabel("시계열 검증 진행 중...");
|
setGlobalProgressLabel("IMR 검증 진행 중...");
|
||||||
const imrParam = {
|
const imrParam = {
|
||||||
user_id: userInfo.userUnqId,
|
user_id: userInfo.userUnqId,
|
||||||
sewer_bzmn_cd: lastSearchedValues?.bsnmCd ?? "",
|
sewer_bzmn_cd: lastSearchedValues.bsnmCd ?? "",
|
||||||
stats_cd: statsCdForSubmit,
|
stats_cd: statsCdForSubmit,
|
||||||
stats_yr: lastSearchedValues.year ?? "",
|
stats_yr: lastSearchedValues.year ?? "",
|
||||||
lae_sbmsn_stts_cd:
|
lae_sbmsn_stts_cd:
|
||||||
statusInfo?.laeSbmsnSttsCd === "4" ? "4" : "2",
|
statusInfo?.laeSbmsnSttsCd === "4" ? "4" : "2",
|
||||||
gen_verify_stts_cd: nvpassed ? "1" : "2",
|
gen_verify_stts_cd: nvpassed ? "1" : "2",
|
||||||
hb_pass_yn: response.data?.isHbPassed,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -940,10 +925,10 @@ const PumpingStationInp = () => {
|
|||||||
.map((e) => {
|
.map((e) => {
|
||||||
const prefix =
|
const prefix =
|
||||||
e.vrfcCd === "IMR"
|
e.vrfcCd === "IMR"
|
||||||
? "시계열 검증 - "
|
? "IMR검증 - "
|
||||||
: e.vrfcCd === "NV"
|
: e.vrfcCd === "NV"
|
||||||
? "일반검증 - "
|
? "일반검증 - "
|
||||||
: "모집단 검증 -";
|
: "HB검증 -";
|
||||||
return `${prefix}${e.rsnExpln}
|
return `${prefix}${e.rsnExpln}
|
||||||
(검증 기준값: ${e.compVlCn} / 현재 입력값: ${e.nowVlCn})`;
|
(검증 기준값: ${e.compVlCn} / 현재 입력값: ${e.nowVlCn})`;
|
||||||
})
|
})
|
||||||
@@ -952,7 +937,7 @@ const PumpingStationInp = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const searchContextForToolbar = lastSearchedValues;
|
const searchContextForToolbar = lastSearchedValues ?? searchValues;
|
||||||
const toolbarSnapshot = computeTabToolbarSnapshot(
|
const toolbarSnapshot = computeTabToolbarSnapshot(
|
||||||
statusInfo,
|
statusInfo,
|
||||||
rowData.length > 0,
|
rowData.length > 0,
|
||||||
@@ -972,23 +957,23 @@ const PumpingStationInp = () => {
|
|||||||
hasSearched &&
|
hasSearched &&
|
||||||
toolbarGroupAllowed &&
|
toolbarGroupAllowed &&
|
||||||
(showSaveInToolbar || showEnterableToolbarButtons);
|
(showSaveInToolbar || showEnterableToolbarButtons);
|
||||||
const tabEnterableForGrid =
|
|
||||||
(computeTabEnterable(statusInfo, inputPeriodEnterable) || isAdminInfo) && inputPeriodEnterable;
|
|
||||||
const gugunOk = buildGugunOkForToolbar(searchContextForToolbar);
|
|
||||||
const submitOk = buildSubmitOkForToolbar(searchContextForToolbar);
|
|
||||||
const showNotApplicable =
|
const showNotApplicable =
|
||||||
searchLoaded &&
|
searchLoaded &&
|
||||||
hasSearched &&
|
hasSearched &&
|
||||||
rowData.length === 0 &&
|
rowData.length === 0 &&
|
||||||
computeTabEnterable(statusInfo, inputPeriodEnterable) &&
|
computeTabEnterable(statusInfo, inputPeriodEnterable);
|
||||||
submitOk;
|
|
||||||
|
const tabEnterableForGrid =
|
||||||
|
computeTabEnterable(statusInfo, inputPeriodEnterable) || isAdminInfo;
|
||||||
|
const gugunOk = buildGugunOkForToolbar(lastSearchedValues);
|
||||||
|
|
||||||
const verificationQueryContext = (() => {
|
const verificationQueryContext = (() => {
|
||||||
const ctx = lastSearchedValues ?? searchValues;
|
const ctx = lastSearchedValues ?? searchValues;
|
||||||
if (!ctx?.year || !ctx?.sido || !ctx?.bsnmCd || !statsCd) return null;
|
if (!ctx?.year || !ctx?.sido || !ctx?.bsnmCd || !statsCd) return null;
|
||||||
return {
|
return {
|
||||||
...toInputSearchRegion(sidoListRef.current, ctx),
|
sewerBzmnCd: ctx.bsnmCd,
|
||||||
ctpvNm: ctx.sido,
|
ctpvNm: ctx.sido,
|
||||||
|
sggNm: ctx.gugun === "ALL" ? "" : (ctx.gugun ?? ""),
|
||||||
statsYr: ctx.year,
|
statsYr: ctx.year,
|
||||||
statsCd,
|
statsCd,
|
||||||
};
|
};
|
||||||
@@ -1004,7 +989,6 @@ const PumpingStationInp = () => {
|
|||||||
<>
|
<>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<SearchForm
|
<SearchForm
|
||||||
isInput
|
|
||||||
key={searchFormRemountKey}
|
key={searchFormRemountKey}
|
||||||
defaultValues={verificationSearchDefaults ?? undefined}
|
defaultValues={verificationSearchDefaults ?? undefined}
|
||||||
fctName={true}
|
fctName={true}
|
||||||
@@ -1024,10 +1008,10 @@ const PumpingStationInp = () => {
|
|||||||
<LastYearDataButton
|
<LastYearDataButton
|
||||||
getLastYearDataFunc={() => void getLastYearDataFunc()}
|
getLastYearDataFunc={() => void getLastYearDataFunc()}
|
||||||
/>
|
/>
|
||||||
{submitOk && <SubmitButton submitFunc={submitFunc} />}
|
<SubmitButton submitFunc={submitFunc} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{statusInfo?.laeSbmsnSttsCd === "2" && submitOk && (
|
{statusInfo?.laeSbmsnSttsCd === "2" && (
|
||||||
<CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />
|
<CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />
|
||||||
)}
|
)}
|
||||||
{showSaveInToolbar && <SaveButton saveFunc={saveFunc} />}
|
{showSaveInToolbar && <SaveButton saveFunc={saveFunc} />}
|
||||||
@@ -1072,7 +1056,6 @@ const PumpingStationInp = () => {
|
|||||||
excelImportSewerBzmnCd={(lastSearchedValues ?? searchValues)?.bsnmCd}
|
excelImportSewerBzmnCd={(lastSearchedValues ?? searchValues)?.bsnmCd}
|
||||||
excelExportSearchContext={toExcelExportSearchContextFromSearchForm(lastSearchedValues ?? searchValues)}
|
excelExportSearchContext={toExcelExportSearchContextFromSearchForm(lastSearchedValues ?? searchValues)}
|
||||||
cellStyleCallback={verificationCellStyle}
|
cellStyleCallback={verificationCellStyle}
|
||||||
footerVerificationResult={footerVerificationResult}
|
|
||||||
cellTooltipCallback={verificationCellTooltip}
|
cellTooltipCallback={verificationCellTooltip}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,17 +1,44 @@
|
|||||||
import { type Dispatch, type SetStateAction,useCallback, useEffect, useMemo, useRef, useState } from "react";
|
import { useCallback, useEffect, useMemo, useRef, useState, type Dispatch, type SetStateAction } from "react";
|
||||||
|
|
||||||
|
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||||
|
import { ValueType } from "realgrid";
|
||||||
|
import type { RealGridReact } from "realgrid-react";
|
||||||
import { flushSync } from "react-dom";
|
import { flushSync } from "react-dom";
|
||||||
|
|
||||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||||
import { ValueType } from "realgrid";
|
|
||||||
import type { RealGridReact } from "realgrid-react";
|
|
||||||
|
|
||||||
import { useAlertStore, useGlobalProgressStore, useStatisticsInputToolbarGroupGate, useSearchConditionSidoList } from "@/shared/lib";
|
import AddArticleButton from "@/components/button/AddArticleButton";
|
||||||
import { STATISTICS_INPUT_URL_PATH } from "@/shared/lib/stats-cd-input-navigation";
|
import CancelSubmitButton from "@/components/button/CancelSubmitButton";
|
||||||
import { useStatisticsInputPendingNavigation } from "@/shared/lib/use-statistics-input-pending-navigation";
|
import DeleteArticleButton from "@/components/button/DeleteArticleButton";
|
||||||
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
import LastYearDataButton from "@/components/button/LastYearDataButton";
|
||||||
import { nullableTrimmedString } from "@/components/util/input/nullableString";
|
import NotApplicableCheckButton from "@/components/button/NotApplicableCheckButton";
|
||||||
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
import SaveButton from "@/components/button/SaveButton";
|
||||||
|
import SubmitButton from "@/components/button/SumitButton";
|
||||||
|
import VerificationResultButton from "@/components/button/VerificationResultButton";
|
||||||
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
|
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
||||||
|
import { openVerificationResultDialogIfNeeded } from "@/components/module/post-submit-verification-results";
|
||||||
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
|
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
||||||
|
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
||||||
|
import type {
|
||||||
|
CellStyleCallback,
|
||||||
|
CellStyleCallbackParams,
|
||||||
|
CellStyleCallbackResult,
|
||||||
|
CellTooltipCallbackParams,
|
||||||
|
ColumnConfig,
|
||||||
|
ColumnInfo,
|
||||||
|
} from "@/components/type/DataGrid.type";
|
||||||
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
|
import { doList } from "@/components/util/column/input/DoList";
|
||||||
|
import { ExcretaRelatedIndustryInpColumn } from "@/components/util/column/input/sewageExcretaRelated/ExcretaRelatedIndustryInpColumn";
|
||||||
|
import { PrivateSewageTreatRelatedIndustryInpColumn } from "@/components/util/column/input/sewageExcretaRelated/PrivateSewageTreatRelatedIndustryInpColumn";
|
||||||
|
import { PublicInstitutionExcretaIndustryInpColumn } from "@/components/util/column/input/sewageExcretaRelated/PublicInstitutionExcretaIndustryInpColumn";
|
||||||
|
import { PublicInstitutionSewerIndustryInpColumn } from "@/components/util/column/input/sewageExcretaRelated/PublicInstitutionSewerIndustryInpColumn";
|
||||||
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
|
import { patchVerificationFailedByTab } from "@/components/util/input/verification-failed-flag";
|
||||||
import { statisticsInputSewageExcretaRelatedApi } from "@/entities/statistics/api/input/statistics-input-sewage-excreta-related-service";
|
import { statisticsInputSewageExcretaRelatedApi } from "@/entities/statistics/api/input/statistics-input-sewage-excreta-related-service";
|
||||||
|
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
import type {
|
import type {
|
||||||
ExcretaRelatedIndustrySaveItem,
|
ExcretaRelatedIndustrySaveItem,
|
||||||
@@ -27,70 +54,27 @@ import {
|
|||||||
SEWAGE_EXCRETA_PUBLIC_INSTITUTION_SEWER_STATS_CD,
|
SEWAGE_EXCRETA_PUBLIC_INSTITUTION_SEWER_STATS_CD,
|
||||||
} from "@/entities/statistics/model/input/statistics-input-sewage-excreta-related-interface";
|
} from "@/entities/statistics/model/input/statistics-input-sewage-excreta-related-interface";
|
||||||
import { isInputPeriodCurrent } from "@/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface";
|
import { isInputPeriodCurrent } from "@/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface";
|
||||||
import type { StatisticsInputSubmitInfoFormData } from "@/entities/statistics/model/statistics-input-submit-info-schema";
|
|
||||||
import type {
|
import type {
|
||||||
ApiResponse,
|
ApiResponse,
|
||||||
cancelSubmitRequest,
|
cancelSubmitRequest,
|
||||||
ImrStatusResponse,
|
ImrStatusResponse,
|
||||||
SewerageStatusInfo,
|
SewerageStatusInfo,
|
||||||
Sgg,
|
Sgg,
|
||||||
Sido,
|
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
} from "@/entities/statistics/model/statistics-interface";
|
||||||
import {
|
import type { StatisticsInputSubmitInfoFormData } from "@/entities/statistics/model/statistics-input-submit-info-schema";
|
||||||
filterBySelectedAdmdstCd,
|
import { useAlertStore, useGlobalProgressStore, useStatisticsInputToolbarGroupGate } from "@/shared/lib";
|
||||||
isGugunOkForToolbar,
|
import { STATISTICS_INPUT_URL_PATH } from "@/shared/lib/stats-cd-input-navigation";
|
||||||
isSubmitOkForToolbar,
|
import { useStatisticsInputPendingNavigation } from "@/shared/lib/use-statistics-input-pending-navigation";
|
||||||
resolveNoApplicableForRequest,
|
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
||||||
toInputSearchRegion,
|
import { useAdminStore } from "@/store/admin-store";
|
||||||
} from "@/entities/statistics";
|
|
||||||
|
|
||||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
|
||||||
|
|
||||||
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
||||||
|
|
||||||
import SubmitDailog from "./SubmitDailog";
|
import SubmitDailog from "./SubmitDailog";
|
||||||
|
|
||||||
import AddArticleButton from "@/components/button/AddArticleButton";
|
const SewageExcretaRelatedInpTabList = [
|
||||||
import CancelSubmitButton from "@/components/button/CancelSubmitButton";
|
PublicInstitutionSewerIndustryInpColumn,
|
||||||
import DeleteArticleButton from "@/components/button/DeleteArticleButton";
|
PublicInstitutionExcretaIndustryInpColumn,
|
||||||
import LastYearDataButton from "@/components/button/LastYearDataButton";
|
ExcretaRelatedIndustryInpColumn,
|
||||||
import NotApplicableCheckButton from "@/components/button/NotApplicableCheckButton";
|
|
||||||
import SaveButton from "@/components/button/SaveButton";
|
|
||||||
import SubmitButton from "@/components/button/SumitButton";
|
|
||||||
import VerificationResultButton from "@/components/button/VerificationResultButton";
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
|
||||||
import { openVerificationResultDialogIfNeeded } from "@/components/module/post-submit-verification-results";
|
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
|
||||||
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
|
||||||
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
|
||||||
import type {
|
|
||||||
CellStyleCallback,
|
|
||||||
CellStyleCallbackParams,
|
|
||||||
CellStyleCallbackResult,
|
|
||||||
CellTooltipCallbackParams,
|
|
||||||
ColumnConfig,
|
|
||||||
ColumnInfo,
|
|
||||||
} from "@/components/type/DataGrid.type";
|
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
|
||||||
import { ExcretaRelatedIndustryInpColumn } from "@/components/util/column/input/sewageExcretaRelated/ExcretaRelatedIndustryInpColumn";
|
|
||||||
import { PrivateSewageTreatRelatedIndustryInpColumn } from "@/components/util/column/input/sewageExcretaRelated/PrivateSewageTreatRelatedIndustryInpColumn";
|
|
||||||
import { PublicInstitutionExcretaIndustryInpColumn } from "@/components/util/column/input/sewageExcretaRelated/PublicInstitutionExcretaIndustryInpColumn";
|
|
||||||
import { PublicInstitutionSewerIndustryInpColumn } from "@/components/util/column/input/sewageExcretaRelated/PublicInstitutionSewerIndustryInpColumn";
|
|
||||||
import { fetchColumnGuidesRecord } from "@/components/util/grid/columnGuides";
|
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
|
||||||
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
|
||||||
import {
|
|
||||||
patchFooterVerificationByTab,
|
|
||||||
patchVerificationFailedByTab,
|
|
||||||
} from "@/components/util/input/verification-failed-flag";
|
|
||||||
import type { VerificationResultLikeMap } from "@/components/util/input/verification-result-display";
|
|
||||||
import { useAdminStore } from "@/store/admin-store";
|
|
||||||
import { useTabStore } from "@/store/tab-store";
|
|
||||||
|
|
||||||
const SewageExcretaRelatedInpTabList = [
|
|
||||||
PublicInstitutionSewerIndustryInpColumn,
|
|
||||||
PublicInstitutionExcretaIndustryInpColumn,
|
|
||||||
ExcretaRelatedIndustryInpColumn,
|
|
||||||
PrivateSewageTreatRelatedIndustryInpColumn,
|
PrivateSewageTreatRelatedIndustryInpColumn,
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
@@ -166,22 +150,10 @@ const computeTabEnterable = (
|
|||||||
return periodEnterable;
|
return periodEnterable;
|
||||||
};
|
};
|
||||||
|
|
||||||
const sidoListRef: { current: Sido[] } = { current: [] };
|
|
||||||
|
|
||||||
function buildGugunOkForToolbar(values: SearchFormValues | null): boolean {
|
function buildGugunOkForToolbar(values: SearchFormValues | null): boolean {
|
||||||
return isGugunOkForToolbar(sidoListRef.current, values);
|
return doList.includes(values?.bsnmCd || "")
|
||||||
}
|
? Boolean(values?.gugun && values.gugun !== "ALL")
|
||||||
|
: true;
|
||||||
function buildSubmitOkForToolbar(values: SearchFormValues | null): boolean {
|
|
||||||
return isSubmitOkForToolbar(sidoListRef.current, values);
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildNoApplicableForRequest(
|
|
||||||
values: SearchFormValues | null,
|
|
||||||
checked: boolean,
|
|
||||||
isSaveListEmpty: boolean,
|
|
||||||
): boolean {
|
|
||||||
return resolveNoApplicableForRequest(sidoListRef.current, values, checked, isSaveListEmpty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeTabToolbarSnapshot(
|
function computeTabToolbarSnapshot(
|
||||||
@@ -195,7 +167,7 @@ function computeTabToolbarSnapshot(
|
|||||||
const gugunOk = buildGugunOkForToolbar(searchContext);
|
const gugunOk = buildGugunOkForToolbar(searchContext);
|
||||||
const enterable = computeTabEnterable(statusInfo, periodEnterable);
|
const enterable = computeTabEnterable(statusInfo, periodEnterable);
|
||||||
const isSubmitted = statusInfo?.laeSbmsnSttsCd === "2";
|
const isSubmitted = statusInfo?.laeSbmsnSttsCd === "2";
|
||||||
const showSaveInToolbar = (enterable || isAdminInfo) && periodEnterable && gugunOk;
|
const showSaveInToolbar = (enterable || isAdminInfo) && gugunOk;
|
||||||
const showEnterableToolbarButtons = enterable && gugunOk;
|
const showEnterableToolbarButtons = enterable && gugunOk;
|
||||||
const showSubmittedInInputPeriodToolbar = isSubmitted && periodEnterable && gugunOk;
|
const showSubmittedInInputPeriodToolbar = isSubmitted && periodEnterable && gugunOk;
|
||||||
const showActionToolbarCard =
|
const showActionToolbarCard =
|
||||||
@@ -340,7 +312,7 @@ function buildSggNmColumn(
|
|||||||
function resolvePublicInstitutionAdmdst(
|
function resolvePublicInstitutionAdmdst(
|
||||||
row: Record<string, string | number>,
|
row: Record<string, string | number>,
|
||||||
sggOptions: Sgg[],
|
sggOptions: Sgg[],
|
||||||
): { admdstCd: string | null; admdstNm: string | null } {
|
): { admdstCd: string; admdstNm: string } {
|
||||||
const sggNm = String(row.sggNm ?? "").trim();
|
const sggNm = String(row.sggNm ?? "").trim();
|
||||||
if (sggNm) {
|
if (sggNm) {
|
||||||
const matched = sggOptions.find((s) => s.gugun === sggNm);
|
const matched = sggOptions.find((s) => s.gugun === sggNm);
|
||||||
@@ -348,12 +320,9 @@ function resolvePublicInstitutionAdmdst(
|
|||||||
return { admdstCd: matched.bsnmCd, admdstNm: matched.gugun };
|
return { admdstCd: matched.bsnmCd, admdstNm: matched.gugun };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const existingCd = nullableTrimmedString(row.admdstCd);
|
const existingCd = String(row.admdstCd ?? "").trim();
|
||||||
const existingNm = nullableTrimmedString(row.admdstNm);
|
const existingNm = String(row.admdstNm ?? "").trim();
|
||||||
return {
|
return { admdstCd: existingCd, admdstNm: existingNm || sggNm };
|
||||||
admdstCd: existingCd,
|
|
||||||
admdstNm: existingNm ?? nullableTrimmedString(sggNm),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function mergeGridRowsWithMapRows(
|
function mergeGridRowsWithMapRows(
|
||||||
@@ -393,6 +362,13 @@ function mergeGridRowsWithArticleMeta(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function nullableTrimmedString(
|
||||||
|
value: string | number | null | undefined,
|
||||||
|
): string | null {
|
||||||
|
const s = String(value ?? "").trim();
|
||||||
|
return s === "" ? null : s;
|
||||||
|
}
|
||||||
|
|
||||||
function toGridNumber(value: string | number | null | undefined): number {
|
function toGridNumber(value: string | number | null | undefined): number {
|
||||||
const n = Number(value);
|
const n = Number(value);
|
||||||
return Number.isFinite(n) ? n : 0;
|
return Number.isFinite(n) ? n : 0;
|
||||||
@@ -407,8 +383,8 @@ function buildPublicInstitutionIndustrySaveItem(
|
|||||||
return {
|
return {
|
||||||
admdstCd,
|
admdstCd,
|
||||||
admdstNm,
|
admdstNm,
|
||||||
ognzSn: nullableTrimmedString(row.ognzSn),
|
ognzSn: String(row.ognzSn ?? "").trim(),
|
||||||
ognzNm: nullableTrimmedString(row.ognzNm),
|
ognzNm: String(row.ognzNm ?? "").trim(),
|
||||||
pbadmsNope: toGridNumber(row.pbadmsNope),
|
pbadmsNope: toGridNumber(row.pbadmsNope),
|
||||||
engrkCnt: toGridNumber(row.engrkCnt),
|
engrkCnt: toGridNumber(row.engrkCnt),
|
||||||
mchnCnt: toGridNumber(row.mchnCnt),
|
mchnCnt: toGridNumber(row.mchnCnt),
|
||||||
@@ -426,8 +402,8 @@ function buildExcretaRelatedIndustrySaveItem(
|
|||||||
row: Record<string, string | number>,
|
row: Record<string, string | number>,
|
||||||
): ExcretaRelatedIndustrySaveItem {
|
): ExcretaRelatedIndustrySaveItem {
|
||||||
return {
|
return {
|
||||||
admdstCd: nullableTrimmedString(row.admdstCd),
|
admdstCd: String(row.admdstCd ?? "").trim(),
|
||||||
admdstNm: nullableTrimmedString(row.admdstNm),
|
admdstNm: String(row.admdstNm ?? "").trim(),
|
||||||
bzentyCnt: toGridNumber(row.bzentyCnt),
|
bzentyCnt: toGridNumber(row.bzentyCnt),
|
||||||
empNope: toGridNumber(row.empNope),
|
empNope: toGridNumber(row.empNope),
|
||||||
n3TonUdrCnt: toGridNumber(row.n3TonUdrCnt),
|
n3TonUdrCnt: toGridNumber(row.n3TonUdrCnt),
|
||||||
@@ -444,8 +420,8 @@ function buildPrivateSewageTreatRelatedIndustrySaveItem(
|
|||||||
row: Record<string, string | number>,
|
row: Record<string, string | number>,
|
||||||
): PrivateSewageTreatRelatedIndustrySaveItem {
|
): PrivateSewageTreatRelatedIndustrySaveItem {
|
||||||
return {
|
return {
|
||||||
admdstCd: nullableTrimmedString(row.admdstCd),
|
admdstCd: String(row.admdstCd ?? "").trim(),
|
||||||
admdstNm: nullableTrimmedString(row.admdstNm),
|
admdstNm: String(row.admdstNm ?? "").trim(),
|
||||||
designMdsrCnt: toGridNumber(row.designMdsrCnt),
|
designMdsrCnt: toGridNumber(row.designMdsrCnt),
|
||||||
designMdsrNope: toGridNumber(row.designMdsrNope),
|
designMdsrNope: toGridNumber(row.designMdsrNope),
|
||||||
mfbizCnt: toGridNumber(row.mfbizCnt),
|
mfbizCnt: toGridNumber(row.mfbizCnt),
|
||||||
@@ -545,10 +521,10 @@ function verificationCellTooltip({
|
|||||||
.map((e) => {
|
.map((e) => {
|
||||||
const prefix =
|
const prefix =
|
||||||
e.vrfcCd === "IMR"
|
e.vrfcCd === "IMR"
|
||||||
? "시계열 검증 - "
|
? "IMR검증 - "
|
||||||
: e.vrfcCd === "NV"
|
: e.vrfcCd === "NV"
|
||||||
? "일반검증 - "
|
? "일반검증 - "
|
||||||
: "모집단 검증 - ";
|
: "HB검증 - ";
|
||||||
return `${prefix}${e.rsnExpln}
|
return `${prefix}${e.rsnExpln}
|
||||||
(검증 기준값: ${e.compVlCn} / 현재 입력값: ${e.nowVlCn})`;
|
(검증 기준값: ${e.compVlCn} / 현재 입력값: ${e.nowVlCn})`;
|
||||||
})
|
})
|
||||||
@@ -563,8 +539,9 @@ function buildSewageExcretaRelatedSearchParam(
|
|||||||
): SewageExcretaRelatedRequestParams {
|
): SewageExcretaRelatedRequestParams {
|
||||||
return {
|
return {
|
||||||
statsYr: values.year,
|
statsYr: values.year,
|
||||||
|
sewerBzmnCd: values.bsnmCd,
|
||||||
ctpvNm: values.sido,
|
ctpvNm: values.sido,
|
||||||
...toInputSearchRegion(sidoListRef.current, values),
|
sggNm: values.gugun === "ALL" ? "" : values.gugun,
|
||||||
...(overrides?.mode ? { mode: overrides.mode } : {}),
|
...(overrides?.mode ? { mode: overrides.mode } : {}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -572,9 +549,8 @@ function buildSewageExcretaRelatedSearchParam(
|
|||||||
function mapListToGridRows<T extends { verificationResult?: SewageExcretaRelatedVerificationResult }>(
|
function mapListToGridRows<T extends { verificationResult?: SewageExcretaRelatedVerificationResult }>(
|
||||||
list: T[] | undefined,
|
list: T[] | undefined,
|
||||||
ctpvNm: string,
|
ctpvNm: string,
|
||||||
values?: SearchFormValues | null,
|
|
||||||
): GridRowWithVerification[] {
|
): GridRowWithVerification[] {
|
||||||
return filterBySelectedAdmdstCd(list, sidoListRef.current, values).map((item) => {
|
return (list ?? []).map((item) => {
|
||||||
const row = toGridRows([{ ctpvNm, ...item }])[0] as GridRowWithVerification;
|
const row = toGridRows([{ ctpvNm, ...item }])[0] as GridRowWithVerification;
|
||||||
if (item.verificationResult) {
|
if (item.verificationResult) {
|
||||||
row.verificationResult = item.verificationResult;
|
row.verificationResult = item.verificationResult;
|
||||||
@@ -601,17 +577,15 @@ async function waitForImrJobCompleted(
|
|||||||
options?.onProgress?.(Math.max(0, Math.min(100, Number(res.job_prog) || 0)));
|
options?.onProgress?.(Math.max(0, Math.min(100, Number(res.job_prog) || 0)));
|
||||||
if (res.status === "COMPLETED" && Number(res.job_prog) === 100) return;
|
if (res.status === "COMPLETED" && Number(res.job_prog) === 100) return;
|
||||||
if (res.status === "FAILED" || res.status === "ERROR" || res.status === "CANCELLED") {
|
if (res.status === "FAILED" || res.status === "ERROR" || res.status === "CANCELLED") {
|
||||||
throw new Error(res.error_msg || `시계열 검증이 ${res.status} 상태로 종료되었습니다.`);
|
throw new Error(res.error_msg || `IMR 검증이 ${res.status} 상태로 종료되었습니다.`);
|
||||||
}
|
}
|
||||||
await sleep(pollIntervalMs);
|
await sleep(pollIntervalMs);
|
||||||
}
|
}
|
||||||
throw new Error("시계열 검증 완료 대기 시간이 초과되었습니다.");
|
throw new Error("IMR 검증 완료 대기 시간이 초과되었습니다.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 하수도 통계 관리 > 12. 하수 및 분뇨관련산업
|
// 하수도 통계 관리 > 12. 하수 및 분뇨관련산업
|
||||||
const SewageExcretaRelatedInp = () => {
|
const SewageExcretaRelatedInp = () => {
|
||||||
const { sidoList } = useSearchConditionSidoList({ isInput: true });
|
|
||||||
sidoListRef.current = sidoList;
|
|
||||||
const { setMessage: alert } = useAlertStore((state) => state);
|
const { setMessage: alert } = useAlertStore((state) => state);
|
||||||
const { confirm } = useConfirm();
|
const { confirm } = useConfirm();
|
||||||
const isAdminInfo = useAdminStore((state) => state.isAdminInfo);
|
const isAdminInfo = useAdminStore((state) => state.isAdminInfo);
|
||||||
@@ -628,7 +602,7 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
const [tabStatusInfoMap, setTabStatusInfoMap] = useState<
|
const [tabStatusInfoMap, setTabStatusInfoMap] = useState<
|
||||||
Map<string, SewerageStatusInfo | null>
|
Map<string, SewerageStatusInfo | null>
|
||||||
>(new Map());
|
>(new Map());
|
||||||
const [_toolbarSnapshotByTab, setToolbarSnapshotByTab] = useState<
|
const [toolbarSnapshotByTab, setToolbarSnapshotByTab] = useState<
|
||||||
Map<string, TabToolbarSnapshot>
|
Map<string, TabToolbarSnapshot>
|
||||||
>(new Map());
|
>(new Map());
|
||||||
const [columnGuidesByTab, setColumnGuidesByTab] = useState<
|
const [columnGuidesByTab, setColumnGuidesByTab] = useState<
|
||||||
@@ -638,9 +612,6 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
const [lastSearchedValues, setLastSearchedValues] = useState<SearchFormValues | null>(
|
const [lastSearchedValues, setLastSearchedValues] = useState<SearchFormValues | null>(
|
||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
const [searchContextByTab, setSearchContextByTab] = useState<Map<string, SearchFormValues>>(
|
|
||||||
() => new Map(),
|
|
||||||
);
|
|
||||||
const [hasSearched, setHasSearched] = useState(false);
|
const [hasSearched, setHasSearched] = useState(false);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [inputPeriodEnterable, setInputPeriodEnterable] = useState(true);
|
const [inputPeriodEnterable, setInputPeriodEnterable] = useState(true);
|
||||||
@@ -649,9 +620,6 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
const [isVerificationFailedByTab, setIsVerificationFailedByTab] = useState<
|
const [isVerificationFailedByTab, setIsVerificationFailedByTab] = useState<
|
||||||
Map<string, boolean>
|
Map<string, boolean>
|
||||||
>(new Map());
|
>(new Map());
|
||||||
const [footerVerificationByTab, setFooterVerificationByTab] = useState<
|
|
||||||
Map<string, VerificationResultLikeMap | null>
|
|
||||||
>(new Map());
|
|
||||||
const [isNotApplicableByTab, setIsNotApplicableByTab] = useState<Map<string, boolean>>(
|
const [isNotApplicableByTab, setIsNotApplicableByTab] = useState<Map<string, boolean>>(
|
||||||
() => new Map(),
|
() => new Map(),
|
||||||
);
|
);
|
||||||
@@ -677,29 +645,36 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
const sggOptionsSidoRef = useRef<string | null>(null);
|
const sggOptionsSidoRef = useRef<string | null>(null);
|
||||||
activeTabRef.current = activeTab;
|
activeTabRef.current = activeTab;
|
||||||
|
|
||||||
const activeTabId = useTabStore((s) => s.activeTabId);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeTabId !== STATISTICS_INPUT_URL_PATH.SEWAGE_EXCRETA_RELATED) return;
|
|
||||||
const tabKey = activeTab;
|
|
||||||
if (!tabKey) return;
|
|
||||||
if (Object.prototype.hasOwnProperty.call(columnGuidesByTab, tabKey)) return;
|
|
||||||
const statsCd = tabKey;
|
|
||||||
|
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
void (async () => {
|
void (async () => {
|
||||||
const next = await fetchColumnGuidesRecord(statsCd);
|
const entries = await Promise.all(
|
||||||
if (cancelled) return;
|
SewageExcretaRelatedInpTabList.map(async (tab) => {
|
||||||
setColumnGuidesByTab((prev) =>
|
const tabKey = tab.tabKey;
|
||||||
Object.prototype.hasOwnProperty.call(prev, tabKey)
|
try {
|
||||||
? prev
|
const res = await statisticsApi.getColumnGuides(tabKey);
|
||||||
: { ...prev, [tabKey]: next },
|
if (res.status !== "success" || !Array.isArray(res.data)) {
|
||||||
|
return [tabKey, {}] as const;
|
||||||
|
}
|
||||||
|
const next: Record<string, string> = {};
|
||||||
|
for (const item of res.data) {
|
||||||
|
const key = item.engColNm?.trim();
|
||||||
|
const guide = item.columnGuide?.trim();
|
||||||
|
if (key && guide) next[key] = guide;
|
||||||
|
}
|
||||||
|
return [tabKey, next] as const;
|
||||||
|
} catch {
|
||||||
|
return [tabKey, {}] as const;
|
||||||
|
}
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
if (cancelled) return;
|
||||||
|
setColumnGuidesByTab(Object.fromEntries(entries));
|
||||||
})();
|
})();
|
||||||
return () => {
|
return () => {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
};
|
};
|
||||||
}, [activeTabId, activeTab, columnGuidesByTab]);
|
}, []);
|
||||||
|
|
||||||
const shouldShowNotApplicable = (
|
const shouldShowNotApplicable = (
|
||||||
tabKey: string,
|
tabKey: string,
|
||||||
@@ -764,13 +739,6 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
);
|
);
|
||||||
return next;
|
return next;
|
||||||
});
|
});
|
||||||
if (searchContext) {
|
|
||||||
setSearchContextByTab((prev) => {
|
|
||||||
const next = new Map(prev);
|
|
||||||
next.set(tabKey, searchContext);
|
|
||||||
return next;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const markTabLoaded = (tabKey: string) => {
|
const markTabLoaded = (tabKey: string) => {
|
||||||
@@ -886,7 +854,6 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
const gridRows = mapListToGridRows(
|
const gridRows = mapListToGridRows(
|
||||||
publicInstitutionSewerIndustryList,
|
publicInstitutionSewerIndustryList,
|
||||||
commonInfo.ctpvNm,
|
commonInfo.ctpvNm,
|
||||||
searchContext,
|
|
||||||
);
|
);
|
||||||
syncPublicInstitutionArticleTracking(
|
syncPublicInstitutionArticleTracking(
|
||||||
tabKey,
|
tabKey,
|
||||||
@@ -904,9 +871,6 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
||||||
commitToolbarSnapshotForLoadedTab(
|
commitToolbarSnapshotForLoadedTab(
|
||||||
tabKey,
|
tabKey,
|
||||||
@@ -933,7 +897,6 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
const gridRows = mapListToGridRows(
|
const gridRows = mapListToGridRows(
|
||||||
publicInstitutionExcretaIndustryList,
|
publicInstitutionExcretaIndustryList,
|
||||||
commonInfo.ctpvNm,
|
commonInfo.ctpvNm,
|
||||||
searchContext,
|
|
||||||
);
|
);
|
||||||
syncPublicInstitutionArticleTracking(
|
syncPublicInstitutionArticleTracking(
|
||||||
tabKey,
|
tabKey,
|
||||||
@@ -951,9 +914,6 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
||||||
commitToolbarSnapshotForLoadedTab(
|
commitToolbarSnapshotForLoadedTab(
|
||||||
tabKey,
|
tabKey,
|
||||||
@@ -976,7 +936,7 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const { commonInfo, statusInfo, excretaRelatedIndustryList } = response.data;
|
const { commonInfo, statusInfo, excretaRelatedIndustryList } = response.data;
|
||||||
const gridRows = mapListToGridRows(excretaRelatedIndustryList, commonInfo.ctpvNm, searchContext);
|
const gridRows = mapListToGridRows(excretaRelatedIndustryList, commonInfo.ctpvNm);
|
||||||
applyRowMap(mergeIntoExistingMap, (m) => {
|
applyRowMap(mergeIntoExistingMap, (m) => {
|
||||||
m.set(ExcretaRelatedIndustryInpColumn.tabKey, gridRows);
|
m.set(ExcretaRelatedIndustryInpColumn.tabKey, gridRows);
|
||||||
});
|
});
|
||||||
@@ -985,9 +945,6 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
||||||
commitToolbarSnapshotForLoadedTab(
|
commitToolbarSnapshotForLoadedTab(
|
||||||
tabKey,
|
tabKey,
|
||||||
@@ -1013,7 +970,6 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
const gridRows = mapListToGridRows(
|
const gridRows = mapListToGridRows(
|
||||||
privateSewageTreatRelatedIndustryList,
|
privateSewageTreatRelatedIndustryList,
|
||||||
commonInfo.ctpvNm,
|
commonInfo.ctpvNm,
|
||||||
searchContext,
|
|
||||||
);
|
);
|
||||||
applyRowMap(mergeIntoExistingMap, (m) => {
|
applyRowMap(mergeIntoExistingMap, (m) => {
|
||||||
m.set(PrivateSewageTreatRelatedIndustryInpColumn.tabKey, gridRows);
|
m.set(PrivateSewageTreatRelatedIndustryInpColumn.tabKey, gridRows);
|
||||||
@@ -1023,9 +979,6 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
||||||
commitToolbarSnapshotForLoadedTab(
|
commitToolbarSnapshotForLoadedTab(
|
||||||
tabKey,
|
tabKey,
|
||||||
@@ -1045,7 +998,6 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
setRowDataMap(new Map());
|
setRowDataMap(new Map());
|
||||||
setTabStatusInfoMap(new Map());
|
setTabStatusInfoMap(new Map());
|
||||||
setToolbarSnapshotByTab(new Map());
|
setToolbarSnapshotByTab(new Map());
|
||||||
setSearchContextByTab(new Map());
|
|
||||||
setActiveTab(firstTabKey);
|
setActiveTab(firstTabKey);
|
||||||
activeTabRef.current = firstTabKey;
|
activeTabRef.current = firstTabKey;
|
||||||
setLastSearchedValues(null);
|
setLastSearchedValues(null);
|
||||||
@@ -1058,7 +1010,6 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
setLoadedTabKeys(new Set());
|
setLoadedTabKeys(new Set());
|
||||||
setTabStatsCdMap(new Map());
|
setTabStatsCdMap(new Map());
|
||||||
setIsVerificationFailedByTab(new Map());
|
setIsVerificationFailedByTab(new Map());
|
||||||
setFooterVerificationByTab(new Map());
|
|
||||||
setIsNotApplicableByTab(new Map());
|
setIsNotApplicableByTab(new Map());
|
||||||
setDeleteListByTab(new Map());
|
setDeleteListByTab(new Map());
|
||||||
clearArticleOgnzSnTracking(
|
clearArticleOgnzSnTracking(
|
||||||
@@ -1109,9 +1060,7 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
setTabStatusInfoMap(new Map());
|
setTabStatusInfoMap(new Map());
|
||||||
setTabStatsCdMap(new Map());
|
setTabStatsCdMap(new Map());
|
||||||
setIsVerificationFailedByTab(new Map());
|
setIsVerificationFailedByTab(new Map());
|
||||||
setFooterVerificationByTab(new Map());
|
|
||||||
setToolbarSnapshotByTab(new Map());
|
setToolbarSnapshotByTab(new Map());
|
||||||
setSearchContextByTab(new Map());
|
|
||||||
setIsNotApplicableByTab(new Map());
|
setIsNotApplicableByTab(new Map());
|
||||||
setDeleteListByTab(new Map());
|
setDeleteListByTab(new Map());
|
||||||
clearArticleOgnzSnTracking(
|
clearArticleOgnzSnTracking(
|
||||||
@@ -1176,8 +1125,9 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
const statsCdForTab = tabStatsCdMap.get(tabKey) ?? tabKey;
|
const statsCdForTab = tabStatsCdMap.get(tabKey) ?? tabKey;
|
||||||
|
|
||||||
const requestData: cancelSubmitRequest = {
|
const requestData: cancelSubmitRequest = {
|
||||||
...toInputSearchRegion(sidoListRef.current, ctx),
|
sewerBzmnCd: ctx.bsnmCd ?? "",
|
||||||
ctpvNm: ctx.sido ?? "",
|
ctpvNm: ctx.sido ?? "",
|
||||||
|
sggNm: ctx.gugun === "ALL" ? "" : (ctx.gugun ?? ""),
|
||||||
statsYr: ctx.year ?? "",
|
statsYr: ctx.year ?? "",
|
||||||
mdfrId: userInfo.userUnqId,
|
mdfrId: userInfo.userUnqId,
|
||||||
statsCd: statsCdForTab,
|
statsCd: statsCdForTab,
|
||||||
@@ -1268,10 +1218,10 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
commitActiveGrid();
|
commitActiveGrid();
|
||||||
const noApplicable = buildNoApplicableForRequest(searchContextByTab.get(tabKey) ?? lastSearchedValues, isNotApplicableByTab.get(tabKey) ?? false, getTabGridRows(tabKey).length === 0);
|
const noApplicable = isNotApplicableByTab.get(tabKey) ?? false;
|
||||||
const currentData = getTabGridRows(tabKey);
|
const currentData = getTabGridRows(tabKey);
|
||||||
if (NOT_APPLICABLE_TAB_KEYS.has(tabKey)) {
|
if (NOT_APPLICABLE_TAB_KEYS.has(tabKey)) {
|
||||||
if (!noApplicable && currentData.length === 0 && buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)) {
|
if (!noApplicable && currentData.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1305,14 +1255,18 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
|
|
||||||
const isDistrictRowTab = DISTRICT_ROW_TAB_KEYS.has(tabKey);
|
const isDistrictRowTab = DISTRICT_ROW_TAB_KEYS.has(tabKey);
|
||||||
const isPublicInstitutionTab = ARTICLE_EDIT_TAB_KEYS.has(tabKey);
|
const isPublicInstitutionTab = ARTICLE_EDIT_TAB_KEYS.has(tabKey);
|
||||||
const noApplicable = buildNoApplicableForRequest(searchContextByTab.get(tabKey) ?? lastSearchedValues, isNotApplicableByTab.get(tabKey) ?? false, getTabGridRows(tabKey).length === 0);
|
const noApplicable = isNotApplicableByTab.get(tabKey) ?? false;
|
||||||
const currentData = getTabGridRows(tabKey);
|
const currentData = getTabGridRows(tabKey);
|
||||||
const mapRows = rowDataMap.get(tabKey) ?? [];
|
const mapRows = rowDataMap.get(tabKey) ?? [];
|
||||||
|
|
||||||
const searchContextBase = {
|
const searchContextBase = {
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
};
|
};
|
||||||
|
|
||||||
let submitList:
|
let submitList:
|
||||||
@@ -1373,7 +1327,7 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
)
|
)
|
||||||
.map((row) => buildPublicInstitutionIndustrySaveItem(row, list));
|
.map((row) => buildPublicInstitutionIndustrySaveItem(row, list));
|
||||||
|
|
||||||
if (!noApplicable && submitList.length === 0 && buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)) {
|
if (!noApplicable && submitList.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1477,16 +1431,15 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
|
|
||||||
if (finalStatus === "5") {
|
if (finalStatus === "5") {
|
||||||
setGlobalProgress(50);
|
setGlobalProgress(50);
|
||||||
setGlobalProgressLabel("시계열 검증 진행 중...");
|
setGlobalProgressLabel("IMR 검증 진행 중...");
|
||||||
const imrParam = {
|
const imrParam = {
|
||||||
user_id: userInfo.userUnqId,
|
user_id: userInfo.userUnqId,
|
||||||
sewer_bzmn_cd: lastSearchedValues?.bsnmCd ?? "",
|
sewer_bzmn_cd: lastSearchedValues.bsnmCd ?? "",
|
||||||
stats_cd: statsCdForTab,
|
stats_cd: statsCdForTab,
|
||||||
stats_yr: lastSearchedValues.year ?? "",
|
stats_yr: lastSearchedValues.year ?? "",
|
||||||
lae_sbmsn_stts_cd:
|
lae_sbmsn_stts_cd:
|
||||||
activeTabStatus?.laeSbmsnSttsCd === "4" ? "4" : "2",
|
activeTabStatus?.laeSbmsnSttsCd === "4" ? "4" : "2",
|
||||||
gen_verify_stts_cd: nvpassed ? "1" : "2",
|
gen_verify_stts_cd: nvpassed ? "1" : "2",
|
||||||
hb_pass_yn: response.data?.isHbPassed,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -1560,14 +1513,18 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
|
|
||||||
const isDistrictRowTab = DISTRICT_ROW_TAB_KEYS.has(tabKey);
|
const isDistrictRowTab = DISTRICT_ROW_TAB_KEYS.has(tabKey);
|
||||||
const isPublicInstitutionTab = ARTICLE_EDIT_TAB_KEYS.has(tabKey);
|
const isPublicInstitutionTab = ARTICLE_EDIT_TAB_KEYS.has(tabKey);
|
||||||
const noApplicable = buildNoApplicableForRequest(searchContextByTab.get(tabKey) ?? lastSearchedValues, isNotApplicableByTab.get(tabKey) ?? false, getTabGridRows(tabKey).length === 0);
|
const noApplicable = isNotApplicableByTab.get(tabKey) ?? false;
|
||||||
const currentData = getTabGridRows(tabKey);
|
const currentData = getTabGridRows(tabKey);
|
||||||
const mapRows = rowDataMap.get(tabKey) ?? [];
|
const mapRows = rowDataMap.get(tabKey) ?? [];
|
||||||
|
|
||||||
const baseSaveRequest = {
|
const baseSaveRequest = {
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
...(isPublicInstitutionTab && noApplicable
|
...(isPublicInstitutionTab && noApplicable
|
||||||
? { noApplicable: true as const }
|
? { noApplicable: true as const }
|
||||||
: {}),
|
: {}),
|
||||||
@@ -1650,7 +1607,7 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
)
|
)
|
||||||
.map((row) => buildPublicInstitutionIndustrySaveItem(row, list));
|
.map((row) => buildPublicInstitutionIndustrySaveItem(row, list));
|
||||||
|
|
||||||
if (!noApplicable && saveList.length === 0 && buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)) {
|
if (!noApplicable && saveList.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1741,8 +1698,8 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
newRow.__isNewArticle = 1;
|
newRow.__isNewArticle = 1;
|
||||||
if (sggNm) {
|
if (sggNm) {
|
||||||
const { admdstCd, admdstNm } = resolvePublicInstitutionAdmdst(newRow, list);
|
const { admdstCd, admdstNm } = resolvePublicInstitutionAdmdst(newRow, list);
|
||||||
newRow.admdstCd = admdstCd ?? "";
|
newRow.admdstCd = admdstCd;
|
||||||
newRow.admdstNm = admdstNm ?? "";
|
newRow.admdstNm = admdstNm;
|
||||||
}
|
}
|
||||||
|
|
||||||
flushSync(() => {
|
flushSync(() => {
|
||||||
@@ -1859,10 +1816,10 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
for (const tab of SewageExcretaRelatedInpTabList) {
|
for (const tab of SewageExcretaRelatedInpTabList) {
|
||||||
const tabKey = tab.tabKey;
|
const tabKey = tab.tabKey;
|
||||||
const canEdit =
|
const canEdit =
|
||||||
(computeTabEnterable(
|
computeTabEnterable(
|
||||||
tabStatusInfoMap.get(tabKey) ?? null,
|
tabStatusInfoMap.get(tabKey) ?? null,
|
||||||
inputPeriodEnterable,
|
inputPeriodEnterable,
|
||||||
) || isAdminInfo) && inputPeriodEnterable;
|
) || isAdminInfo;
|
||||||
const rawColumns = (tab.columns ?? []) as ColumnConfig[];
|
const rawColumns = (tab.columns ?? []) as ColumnConfig[];
|
||||||
const base = canEdit
|
const base = canEdit
|
||||||
? rawColumns
|
? rawColumns
|
||||||
@@ -1914,10 +1871,11 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
[publicInstitutionArticleCellStyleCallback],
|
[publicInstitutionArticleCellStyleCallback],
|
||||||
);
|
);
|
||||||
|
|
||||||
const searchContextForToolbar = searchContextByTab.get(activeTab) ?? lastSearchedValues;
|
const searchContextForToolbar = lastSearchedValues ?? searchValues;
|
||||||
const activeTabStatus = tabStatusInfoMap.get(activeTab) ?? null;
|
const activeTabStatus = tabStatusInfoMap.get(activeTab) ?? null;
|
||||||
const activeTabHasRowData = tabRowDataExists(rowDataMap, activeTab);
|
const activeTabHasRowData = tabRowDataExists(rowDataMap, activeTab);
|
||||||
const activeTabToolbar =
|
const activeTabToolbar =
|
||||||
|
toolbarSnapshotByTab.get(activeTab) ??
|
||||||
computeTabToolbarSnapshot(
|
computeTabToolbarSnapshot(
|
||||||
activeTabStatus,
|
activeTabStatus,
|
||||||
activeTabHasRowData,
|
activeTabHasRowData,
|
||||||
@@ -1935,13 +1893,10 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
(activeTabToolbar.showActionToolbarCard || (hasSearched && loadedTabKeys.has(activeTab)));
|
(activeTabToolbar.showActionToolbarCard || (hasSearched && loadedTabKeys.has(activeTab)));
|
||||||
const showArticleEditButtons =
|
const showArticleEditButtons =
|
||||||
ARTICLE_EDIT_TAB_KEYS.has(activeTab) && showEnterableToolbarButtons;
|
ARTICLE_EDIT_TAB_KEYS.has(activeTab) && showEnterableToolbarButtons;
|
||||||
const gugunOk = buildGugunOkForToolbar(searchContextForToolbar);
|
|
||||||
const submitOk = buildSubmitOkForToolbar(searchContextForToolbar);
|
|
||||||
const showNotApplicableForActiveTab =
|
const showNotApplicableForActiveTab =
|
||||||
NOT_APPLICABLE_TAB_KEYS.has(activeTab) &&
|
NOT_APPLICABLE_TAB_KEYS.has(activeTab) &&
|
||||||
loadedTabKeys.has(activeTab) &&
|
loadedTabKeys.has(activeTab) &&
|
||||||
shouldShowNotApplicable(activeTab, activeTabHasRowData, activeTabStatus) &&
|
shouldShowNotApplicable(activeTab, activeTabHasRowData, activeTabStatus);
|
||||||
submitOk;
|
|
||||||
const showSecondaryToolbarCard =
|
const showSecondaryToolbarCard =
|
||||||
hasSearched &&
|
hasSearched &&
|
||||||
toolbarGroupAllowed &&
|
toolbarGroupAllowed &&
|
||||||
@@ -1959,14 +1914,16 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
},
|
},
|
||||||
[isNotApplicableByTab, setIsNotApplicableForTab],
|
[isNotApplicableByTab, setIsNotApplicableForTab],
|
||||||
);
|
);
|
||||||
|
const gugunOk = buildGugunOkForToolbar(lastSearchedValues);
|
||||||
|
|
||||||
const verificationQueryContext = (() => {
|
const verificationQueryContext = (() => {
|
||||||
const ctx = lastSearchedValues ?? searchValues;
|
const ctx = lastSearchedValues ?? searchValues;
|
||||||
const statsCd = tabStatsCdMap.get(activeTab) ?? activeTab;
|
const statsCd = tabStatsCdMap.get(activeTab) ?? activeTab;
|
||||||
if (!ctx?.year || !ctx?.sido || !ctx?.bsnmCd || !statsCd) return null;
|
if (!ctx?.year || !ctx?.sido || !ctx?.bsnmCd || !statsCd) return null;
|
||||||
return {
|
return {
|
||||||
...toInputSearchRegion(sidoListRef.current, ctx),
|
sewerBzmnCd: ctx.bsnmCd,
|
||||||
ctpvNm: ctx.sido,
|
ctpvNm: ctx.sido,
|
||||||
|
sggNm: ctx.gugun === "ALL" ? "" : (ctx.gugun ?? ""),
|
||||||
statsYr: ctx.year,
|
statsYr: ctx.year,
|
||||||
statsCd,
|
statsCd,
|
||||||
};
|
};
|
||||||
@@ -1987,7 +1944,6 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
<>
|
<>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<SearchForm
|
<SearchForm
|
||||||
isInput
|
|
||||||
key={searchFormRemountKey}
|
key={searchFormRemountKey}
|
||||||
defaultValues={verificationSearchDefaults ?? undefined}
|
defaultValues={verificationSearchDefaults ?? undefined}
|
||||||
onSubmit={handleSearch}
|
onSubmit={handleSearch}
|
||||||
@@ -1995,8 +1951,8 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
onValuesChange={setSearchValues}
|
onValuesChange={setSearchValues}
|
||||||
/>
|
/>
|
||||||
{showActionToolbarCard && (
|
{showActionToolbarCard && (
|
||||||
<div className="card !py-0">
|
<div className="card !py-0">
|
||||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||||
<VerificationResultButton
|
<VerificationResultButton
|
||||||
VerificationResultButtonFunc={openVerificationHistoryDialog}
|
VerificationResultButtonFunc={openVerificationHistoryDialog}
|
||||||
isVerificationFailed={
|
isVerificationFailed={
|
||||||
@@ -2008,19 +1964,19 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
<LastYearDataButton
|
<LastYearDataButton
|
||||||
getLastYearDataFunc={() => void lastYearDataFunc()}
|
getLastYearDataFunc={() => void lastYearDataFunc()}
|
||||||
/>
|
/>
|
||||||
{submitOk && <SubmitButton submitFunc={submitFunc} />}
|
<SubmitButton submitFunc={submitFunc} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{activeTabStatus?.laeSbmsnSttsCd === "2" && submitOk && (
|
{activeTabStatus?.laeSbmsnSttsCd === "2" && (
|
||||||
<CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />
|
<CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />
|
||||||
)}
|
)}
|
||||||
{showSaveInToolbar && <SaveButton saveFunc={saveFunc} />}
|
{showSaveInToolbar && <SaveButton saveFunc={saveFunc} />}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
{showSecondaryToolbarCard && (
|
{showSecondaryToolbarCard && (
|
||||||
<div className="card !py-0">
|
<div className="card !py-0">
|
||||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||||
{showNotApplicableForActiveTab && (
|
{showNotApplicableForActiveTab && (
|
||||||
<NotApplicableCheckButton
|
<NotApplicableCheckButton
|
||||||
isCheck={isNotApplicableForActiveTab}
|
isCheck={isNotApplicableForActiveTab}
|
||||||
@@ -2030,11 +1986,11 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
{showArticleEditButtons && (
|
{showArticleEditButtons && (
|
||||||
<>
|
<>
|
||||||
<AddArticleButton addArticleFunc={() => void addArticleFunc()} />
|
<AddArticleButton addArticleFunc={() => void addArticleFunc()} />
|
||||||
<DeleteArticleButton deleteArticleFunc={deleteArticleFunc} />
|
<DeleteArticleButton deleteArticleFunc={deleteArticleFunc} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
||||||
@@ -2062,8 +2018,8 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
const rowData = rowDataMap.get(tabKey) ?? [];
|
const rowData = rowDataMap.get(tabKey) ?? [];
|
||||||
const tabStatusInfo = tabStatusInfoMap.get(tabKey) ?? null;
|
const tabStatusInfo = tabStatusInfoMap.get(tabKey) ?? null;
|
||||||
const tabEnterableForGrid =
|
const tabEnterableForGrid =
|
||||||
(computeTabEnterable(tabStatusInfo, inputPeriodEnterable) ||
|
computeTabEnterable(tabStatusInfo, inputPeriodEnterable) ||
|
||||||
isAdminInfo) && inputPeriodEnterable;
|
isAdminInfo;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TabsContent key={tabKey} value={tabKey}>
|
<TabsContent key={tabKey} value={tabKey}>
|
||||||
@@ -2104,9 +2060,6 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
}
|
}
|
||||||
getGridRef={activeTab === tabKey ? getGridRef : undefined}
|
getGridRef={activeTab === tabKey ? getGridRef : undefined}
|
||||||
cellStyleCallback={resolveGridCellStyleCallback(tabKey)}
|
cellStyleCallback={resolveGridCellStyleCallback(tabKey)}
|
||||||
footerVerificationResult={
|
|
||||||
footerVerificationByTab.get(tabKey) ?? null
|
|
||||||
}
|
|
||||||
cellTooltipCallback={verificationCellTooltip}
|
cellTooltipCallback={verificationCellTooltip}
|
||||||
/>
|
/>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
@@ -2154,7 +2107,7 @@ const SewageExcretaRelatedInp = () => {
|
|||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,56 +1,19 @@
|
|||||||
import {
|
import {
|
||||||
type Dispatch,
|
|
||||||
type SetStateAction,
|
|
||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
useMemo,
|
useMemo,
|
||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
|
type Dispatch,
|
||||||
|
type SetStateAction,
|
||||||
} from "react";
|
} from "react";
|
||||||
|
|
||||||
|
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||||
|
import { ValueType } from "realgrid";
|
||||||
|
import type { RealGridReact } from "realgrid-react";
|
||||||
import { flushSync } from "react-dom";
|
import { flushSync } from "react-dom";
|
||||||
|
|
||||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||||
import { ValueType } from "realgrid";
|
|
||||||
import type { RealGridReact } from "realgrid-react";
|
|
||||||
|
|
||||||
import { useAlertStore, useGlobalProgressStore, useStatisticsInputToolbarGroupGate, useSearchConditionSidoList } from "@/shared/lib";
|
|
||||||
import { STATISTICS_INPUT_URL_PATH } from "@/shared/lib/stats-cd-input-navigation";
|
|
||||||
import { useStatisticsInputPendingNavigation } from "@/shared/lib/use-statistics-input-pending-navigation";
|
|
||||||
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
|
||||||
import { nullableTrimmedString } from "@/components/util/input/nullableString";
|
|
||||||
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
|
||||||
import { statisticsInputSewageExcretaSlurgeApi } from "@/entities/statistics/api/input/statistics-input-sewage-excreta-slurge-service";
|
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
|
||||||
import type {
|
|
||||||
DigestorOperatingStatusSaveItem,
|
|
||||||
ExcretaSlurgeProcessingStatusSaveItem,
|
|
||||||
SewageExcretaSlurgeRequestParams,
|
|
||||||
SewageExcretaSlurgeVerificationResult,
|
|
||||||
SewageSlurgeProcessingFacStatusSaveItem,
|
|
||||||
SlurgeProcessingFacStatusSaveItem,
|
|
||||||
} from "@/entities/statistics/model/input/statistics-input-sewage-excreta-slurge-interface";
|
|
||||||
import {
|
|
||||||
SEWAGE_EXCRETA_DIGESTOR_OPERATING_STATS_CD,
|
|
||||||
SEWAGE_EXCRETA_EXCRETA_SLURGE_PROCESSING_STATS_CD,
|
|
||||||
SEWAGE_EXCRETA_SEWAGE_SLURGE_FAC_STATUS_STATS_CD,
|
|
||||||
SEWAGE_EXCRETA_SLURGE_PROCESSING_FAC_STATUS_STATS_CD,
|
|
||||||
} from "@/entities/statistics/model/input/statistics-input-sewage-excreta-slurge-interface";
|
|
||||||
import { isInputPeriodCurrent } from "@/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface";
|
|
||||||
import type { StatisticsInputSubmitInfoFormData } from "@/entities/statistics/model/statistics-input-submit-info-schema";
|
|
||||||
import type { ApiResponse, cancelSubmitRequest, ImrStatusResponse, SewerageStatusInfo, Sgg, Sido } from "@/entities/statistics/model/statistics-interface";
|
|
||||||
import {
|
|
||||||
filterBySelectedAdmdstCd,
|
|
||||||
isGugunOkForToolbar,
|
|
||||||
isSubmitOkForToolbar,
|
|
||||||
resolveNoApplicableForRequest,
|
|
||||||
toInputSearchRegion,
|
|
||||||
} from "@/entities/statistics";
|
|
||||||
|
|
||||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
|
||||||
|
|
||||||
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
|
||||||
|
|
||||||
import SubmitDailog from "./SubmitDailog";
|
|
||||||
|
|
||||||
import AddArticleButton from "@/components/button/AddArticleButton";
|
import AddArticleButton from "@/components/button/AddArticleButton";
|
||||||
import CancelSubmitButton from "@/components/button/CancelSubmitButton";
|
import CancelSubmitButton from "@/components/button/CancelSubmitButton";
|
||||||
@@ -61,10 +24,12 @@ import SaveButton from "@/components/button/SaveButton";
|
|||||||
import SubmitButton from "@/components/button/SumitButton";
|
import SubmitButton from "@/components/button/SumitButton";
|
||||||
import VerificationResultButton from "@/components/button/VerificationResultButton";
|
import VerificationResultButton from "@/components/button/VerificationResultButton";
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
|
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
||||||
import { openVerificationResultDialogIfNeeded } from "@/components/module/post-submit-verification-results";
|
import { openVerificationResultDialogIfNeeded } from "@/components/module/post-submit-verification-results";
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
||||||
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
||||||
|
import SubmitDailog from "./SubmitDailog";
|
||||||
import type {
|
import type {
|
||||||
CellEditedCallback,
|
CellEditedCallback,
|
||||||
CellStyleCallback,
|
CellStyleCallback,
|
||||||
@@ -76,23 +41,42 @@ import type {
|
|||||||
} from "@/components/type/DataGrid.type";
|
} from "@/components/type/DataGrid.type";
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
import {
|
import {
|
||||||
DIGESTOR_OPERATING_STATUS_EN_YN_FIELD,
|
|
||||||
DigestorOperatingStatusInpColumn,
|
DigestorOperatingStatusInpColumn,
|
||||||
|
DIGESTOR_OPERATING_STATUS_EN_YN_FIELD,
|
||||||
isDigestorOperatingRowDisabled,
|
isDigestorOperatingRowDisabled,
|
||||||
} from "@/components/util/column/input/sewageExcretaSlurge/DigestorOperatingStatusInpColumn";
|
} from "@/components/util/column/input/sewageExcretaSlurge/DigestorOperatingStatusInpColumn";
|
||||||
import { ExcretaSlurgeProcessingStatusInpColumn } from "@/components/util/column/input/sewageExcretaSlurge/ExcretaSlurgeProcessingStatusInpColumn";
|
import { ExcretaSlurgeProcessingStatusInpColumn } from "@/components/util/column/input/sewageExcretaSlurge/ExcretaSlurgeProcessingStatusInpColumn";
|
||||||
import { SewageSlurgeProcessingFacStatusInpColumn } from "@/components/util/column/input/sewageExcretaSlurge/SewageSlurgeProcessingFacStatusInpColumn";
|
import { SewageSlurgeProcessingFacStatusInpColumn } from "@/components/util/column/input/sewageExcretaSlurge/SewageSlurgeProcessingFacStatusInpColumn";
|
||||||
import { SlurgeProcessingFacStatusInpColumn } from "@/components/util/column/input/sewageExcretaSlurge/SlurgeProcessingFacStatusInpColumn";
|
import { SlurgeProcessingFacStatusInpColumn } from "@/components/util/column/input/sewageExcretaSlurge/SlurgeProcessingFacStatusInpColumn";
|
||||||
import { fetchColumnGuidesRecord } from "@/components/util/grid/columnGuides";
|
import { doList } from "@/components/util/column/input/DoList";
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
import { patchVerificationFailedByTab } from "@/components/util/input/verification-failed-flag";
|
||||||
|
import { statisticsInputSewageExcretaSlurgeApi } from "@/entities/statistics/api/input/statistics-input-sewage-excreta-slurge-service";
|
||||||
|
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
||||||
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
import {
|
import {
|
||||||
patchFooterVerificationByTab,
|
SEWAGE_EXCRETA_DIGESTOR_OPERATING_STATS_CD,
|
||||||
patchVerificationFailedByTab,
|
SEWAGE_EXCRETA_EXCRETA_SLURGE_PROCESSING_STATS_CD,
|
||||||
} from "@/components/util/input/verification-failed-flag";
|
SEWAGE_EXCRETA_SEWAGE_SLURGE_FAC_STATUS_STATS_CD,
|
||||||
import type { VerificationResultLikeMap } from "@/components/util/input/verification-result-display";
|
SEWAGE_EXCRETA_SLURGE_PROCESSING_FAC_STATUS_STATS_CD,
|
||||||
|
} from "@/entities/statistics/model/input/statistics-input-sewage-excreta-slurge-interface";
|
||||||
|
import type {
|
||||||
|
SewageExcretaSlurgeRequestParams,
|
||||||
|
DigestorOperatingStatusSaveItem,
|
||||||
|
ExcretaSlurgeProcessingStatusSaveItem,
|
||||||
|
SewageExcretaSlurgeVerificationResult,
|
||||||
|
SewageSlurgeProcessingFacStatusSaveItem,
|
||||||
|
SlurgeProcessingFacStatusSaveItem,
|
||||||
|
} from "@/entities/statistics/model/input/statistics-input-sewage-excreta-slurge-interface";
|
||||||
|
import { isInputPeriodCurrent } from "@/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface";
|
||||||
|
import type { ApiResponse, cancelSubmitRequest, ImrStatusResponse, SewerageStatusInfo, Sgg } from "@/entities/statistics/model/statistics-interface";
|
||||||
|
import type { StatisticsInputSubmitInfoFormData } from "@/entities/statistics/model/statistics-input-submit-info-schema";
|
||||||
|
import { useAlertStore, useGlobalProgressStore, useStatisticsInputToolbarGroupGate } from "@/shared/lib";
|
||||||
|
import { STATISTICS_INPUT_URL_PATH } from "@/shared/lib/stats-cd-input-navigation";
|
||||||
|
import { useStatisticsInputPendingNavigation } from "@/shared/lib/use-statistics-input-pending-navigation";
|
||||||
|
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
||||||
import { useAdminStore } from "@/store/admin-store";
|
import { useAdminStore } from "@/store/admin-store";
|
||||||
import { useTabStore } from "@/store/tab-store";
|
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
||||||
|
|
||||||
type GridRowWithVerification = Record<string, string | number> & {
|
type GridRowWithVerification = Record<string, string | number> & {
|
||||||
verificationResult?: SewageExcretaSlurgeVerificationResult;
|
verificationResult?: SewageExcretaSlurgeVerificationResult;
|
||||||
@@ -152,10 +136,10 @@ function verificationCellTooltip({
|
|||||||
.map((e) => {
|
.map((e) => {
|
||||||
const prefix =
|
const prefix =
|
||||||
e.vrfcCd === "IMR"
|
e.vrfcCd === "IMR"
|
||||||
? "시계열 검증 - "
|
? "IMR검증 - "
|
||||||
: e.vrfcCd === "NV"
|
: e.vrfcCd === "NV"
|
||||||
? "일반검증 - "
|
? "일반검증 - "
|
||||||
: "모집단 검증 - ";
|
: "HB검증 - ";
|
||||||
return `${prefix}${e.rsnExpln}
|
return `${prefix}${e.rsnExpln}
|
||||||
(검증 기준값: ${e.compVlCn} / 현재 입력값: ${e.nowVlCn})`;
|
(검증 기준값: ${e.compVlCn} / 현재 입력값: ${e.nowVlCn})`;
|
||||||
})
|
})
|
||||||
@@ -170,8 +154,9 @@ function buildSewageExcretaSlurgeSearchParam(
|
|||||||
): SewageExcretaSlurgeRequestParams {
|
): SewageExcretaSlurgeRequestParams {
|
||||||
return {
|
return {
|
||||||
statsYr: values.year,
|
statsYr: values.year,
|
||||||
|
sewerBzmnCd: values.bsnmCd,
|
||||||
ctpvNm: values.sido,
|
ctpvNm: values.sido,
|
||||||
...toInputSearchRegion(sidoListRef.current, values),
|
sggNm: values.gugun === "ALL" ? "" : values.gugun,
|
||||||
fcltNm: values.fctName?.trim() || undefined,
|
fcltNm: values.fctName?.trim() || undefined,
|
||||||
...(overrides?.mode ? { mode: overrides.mode } : {}),
|
...(overrides?.mode ? { mode: overrides.mode } : {}),
|
||||||
};
|
};
|
||||||
@@ -180,9 +165,8 @@ function buildSewageExcretaSlurgeSearchParam(
|
|||||||
function mapListToGridRows<T extends { verificationResult?: SewageExcretaSlurgeVerificationResult }>(
|
function mapListToGridRows<T extends { verificationResult?: SewageExcretaSlurgeVerificationResult }>(
|
||||||
list: T[] | undefined,
|
list: T[] | undefined,
|
||||||
ctpvNm: string,
|
ctpvNm: string,
|
||||||
values?: SearchFormValues | null,
|
|
||||||
): GridRowWithVerification[] {
|
): GridRowWithVerification[] {
|
||||||
return filterBySelectedAdmdstCd(list, sidoListRef.current, values).map((item) => {
|
return (list ?? []).map((item) => {
|
||||||
const row = toGridRows([{ ctpvNm, ...item }])[0] as GridRowWithVerification;
|
const row = toGridRows([{ ctpvNm, ...item }])[0] as GridRowWithVerification;
|
||||||
if (item.verificationResult) {
|
if (item.verificationResult) {
|
||||||
row.verificationResult = item.verificationResult;
|
row.verificationResult = item.verificationResult;
|
||||||
@@ -191,10 +175,10 @@ function mapListToGridRows<T extends { verificationResult?: SewageExcretaSlurgeV
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const SewageExcretaSlurgeInpTabList = [
|
const SewageExcretaSlurgeInpTabList = [
|
||||||
SlurgeProcessingFacStatusInpColumn,
|
SlurgeProcessingFacStatusInpColumn,
|
||||||
DigestorOperatingStatusInpColumn,
|
DigestorOperatingStatusInpColumn,
|
||||||
SewageSlurgeProcessingFacStatusInpColumn,
|
SewageSlurgeProcessingFacStatusInpColumn,
|
||||||
ExcretaSlurgeProcessingStatusInpColumn,
|
ExcretaSlurgeProcessingStatusInpColumn,
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
@@ -352,22 +336,10 @@ const computeTabEnterable = (
|
|||||||
return periodEnterable;
|
return periodEnterable;
|
||||||
};
|
};
|
||||||
|
|
||||||
const sidoListRef: { current: Sido[] } = { current: [] };
|
|
||||||
|
|
||||||
function buildGugunOkForToolbar(values: SearchFormValues | null): boolean {
|
function buildGugunOkForToolbar(values: SearchFormValues | null): boolean {
|
||||||
return isGugunOkForToolbar(sidoListRef.current, values);
|
return doList.includes(values?.bsnmCd || "")
|
||||||
}
|
? Boolean(values?.gugun && values.gugun !== "ALL")
|
||||||
|
: true;
|
||||||
function buildSubmitOkForToolbar(values: SearchFormValues | null): boolean {
|
|
||||||
return isSubmitOkForToolbar(sidoListRef.current, values);
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildNoApplicableForRequest(
|
|
||||||
values: SearchFormValues | null,
|
|
||||||
checked: boolean,
|
|
||||||
isSaveListEmpty: boolean,
|
|
||||||
): boolean {
|
|
||||||
return resolveNoApplicableForRequest(sidoListRef.current, values, checked, isSaveListEmpty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeTabToolbarSnapshot(
|
function computeTabToolbarSnapshot(
|
||||||
@@ -381,7 +353,7 @@ function computeTabToolbarSnapshot(
|
|||||||
const gugunOk = buildGugunOkForToolbar(searchContext);
|
const gugunOk = buildGugunOkForToolbar(searchContext);
|
||||||
const enterable = computeTabEnterable(statusInfo, periodEnterable);
|
const enterable = computeTabEnterable(statusInfo, periodEnterable);
|
||||||
const isSubmitted = statusInfo?.laeSbmsnSttsCd === "2";
|
const isSubmitted = statusInfo?.laeSbmsnSttsCd === "2";
|
||||||
const showSaveInToolbar = (enterable || isAdminInfo) && periodEnterable && gugunOk;
|
const showSaveInToolbar = (enterable || isAdminInfo) && gugunOk;
|
||||||
const showEnterableToolbarButtons = enterable && gugunOk;
|
const showEnterableToolbarButtons = enterable && gugunOk;
|
||||||
const showSubmittedInInputPeriodToolbar =
|
const showSubmittedInInputPeriodToolbar =
|
||||||
isSubmitted && periodEnterable && gugunOk;
|
isSubmitted && periodEnterable && gugunOk;
|
||||||
@@ -461,6 +433,13 @@ function mergeGridRowsWithMapRows(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function nullableTrimmedString(
|
||||||
|
value: string | number | null | undefined,
|
||||||
|
): string | null {
|
||||||
|
const s = String(value ?? "").trim();
|
||||||
|
return s === "" ? null : s;
|
||||||
|
}
|
||||||
|
|
||||||
function toGridNumber(value: string | number | null | undefined): number {
|
function toGridNumber(value: string | number | null | undefined): number {
|
||||||
const n = Number(value);
|
const n = Number(value);
|
||||||
return Number.isFinite(n) ? n : 0;
|
return Number.isFinite(n) ? n : 0;
|
||||||
@@ -469,7 +448,7 @@ function toGridNumber(value: string | number | null | undefined): number {
|
|||||||
function resolveSlurgeFacStatusAdmdst(
|
function resolveSlurgeFacStatusAdmdst(
|
||||||
row: Record<string, string | number>,
|
row: Record<string, string | number>,
|
||||||
sggOptions: Sgg[],
|
sggOptions: Sgg[],
|
||||||
): { admdstCd: string | null; admdstNm: string | null } {
|
): { admdstCd: string; admdstNm: string } {
|
||||||
const sggNm = String(row.sggNm ?? "").trim();
|
const sggNm = String(row.sggNm ?? "").trim();
|
||||||
if (sggNm) {
|
if (sggNm) {
|
||||||
const matched = sggOptions.find((s) => s.gugun === sggNm);
|
const matched = sggOptions.find((s) => s.gugun === sggNm);
|
||||||
@@ -477,15 +456,12 @@ function resolveSlurgeFacStatusAdmdst(
|
|||||||
return { admdstCd: matched.bsnmCd, admdstNm: matched.gugun };
|
return { admdstCd: matched.bsnmCd, admdstNm: matched.gugun };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const existingCd = nullableTrimmedString(row.admdstCd);
|
const existingCd = String(row.admdstCd ?? "").trim();
|
||||||
const existingNm = nullableTrimmedString(row.admdstNm);
|
const existingNm = String(row.admdstNm ?? "").trim();
|
||||||
if (existingCd || existingNm) {
|
if (existingCd || existingNm) {
|
||||||
return {
|
return { admdstCd: existingCd, admdstNm: existingNm || sggNm };
|
||||||
admdstCd: existingCd,
|
|
||||||
admdstNm: existingNm ?? nullableTrimmedString(sggNm),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
return { admdstCd: null, admdstNm: nullableTrimmedString(sggNm) };
|
return { admdstCd: "", admdstNm: sggNm };
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 그리드 행 → ST00110001 저장/삭제 API 항목 */
|
/** 그리드 행 → ST00110001 저장/삭제 API 항목 */
|
||||||
@@ -497,12 +473,12 @@ function buildSlurgeProcessingFacStatusSaveItem(
|
|||||||
return {
|
return {
|
||||||
admdstCd,
|
admdstCd,
|
||||||
admdstNm,
|
admdstNm,
|
||||||
swtrmtFcltCd: nullableTrimmedString(row.swtrmtFcltCd),
|
swtrmtFcltCd: String(row.swtrmtFcltCd ?? "").trim(),
|
||||||
swtrmtFcltNm: nullableTrimmedString(row.swtrmtFcltNm),
|
swtrmtFcltNm: String(row.swtrmtFcltNm ?? "").trim(),
|
||||||
fcltSn: nullableTrimmedString(row.fcltSn),
|
fcltSn: String(row.fcltSn ?? "").trim(),
|
||||||
itslfQnt: toGridNumber(row.itslfQnt),
|
itslfQnt: toGridNumber(row.itslfQnt),
|
||||||
otsdInflwQnt: toGridNumber(row.otsdInflwQnt),
|
otsdInflwQnt: toGridNumber(row.otsdInflwQnt),
|
||||||
transfTmplntNm: nullableTrimmedString(row.transfTmplntNm),
|
transfTmplntNm: String(row.transfTmplntNm ?? "").trim(),
|
||||||
transfPrcsQnt: toGridNumber(row.transfPrcsQnt),
|
transfPrcsQnt: toGridNumber(row.transfPrcsQnt),
|
||||||
srpFncRt: toGridNumber(row.srpFncRt),
|
srpFncRt: toGridNumber(row.srpFncRt),
|
||||||
itslfTs1RclmQnt: toGridNumber(row.itslfTs1RclmQnt),
|
itslfTs1RclmQnt: toGridNumber(row.itslfTs1RclmQnt),
|
||||||
@@ -510,32 +486,32 @@ function buildSlurgeProcessingFacStatusSaveItem(
|
|||||||
itslfTs1AltdQnt: toGridNumber(row.itslfTs1AltdQnt),
|
itslfTs1AltdQnt: toGridNumber(row.itslfTs1AltdQnt),
|
||||||
itslfTs1DryQnt: toGridNumber(row.itslfTs1DryQnt),
|
itslfTs1DryQnt: toGridNumber(row.itslfTs1DryQnt),
|
||||||
itslfTs1FuelQnt: toGridNumber(row.itslfTs1FuelQnt),
|
itslfTs1FuelQnt: toGridNumber(row.itslfTs1FuelQnt),
|
||||||
itslfTs1CmpstgQnt: toGridNumber(row.itslfTs1CmpstgQnt),
|
itslfTs2CmpstgQnt: toGridNumber(row.itslfTs2CmpstgQnt),
|
||||||
cmpsPrcsFcltBzentyNm: nullableTrimmedString(row.cmpsPrcsFcltBzentyNm),
|
cmpsPrcsFcltBzentyNm: String(row.cmpsPrcsFcltBzentyNm ?? "").trim(),
|
||||||
incnrPrcsLfvlm: toGridNumber(row.incnrPrcsLfvlm),
|
incnrPrcsLfvlm: toGridNumber(row.incnrPrcsLfvlm),
|
||||||
incnrPrcsPrdctRmtrlQnt: toGridNumber(row.incnrPrcsPrdctRmtrlQnt),
|
incnrPrcsPrdctRmtrlQnt: toGridNumber(row.incnrPrcsPrdctRmtrlQnt),
|
||||||
incnrPrcsFmlyrQnt: toGridNumber(row.incnrPrcsFmlyrQnt),
|
incnrPrcsFmlyrQnt: toGridNumber(row.incnrPrcsFmlyrQnt),
|
||||||
incnrPrcsFcltNm: nullableTrimmedString(row.incnrPrcsFcltNm),
|
incnrPrcsFcltNm: String(row.incnrPrcsFcltNm ?? "").trim(),
|
||||||
stbznPrcsLfvlm: toGridNumber(row.stbznPrcsLfvlm),
|
stbznPrcsLfvlm: toGridNumber(row.stbznPrcsLfvlm),
|
||||||
stbznPrcsFmlyrQnt: toGridNumber(row.stbznPrcsFmlyrQnt),
|
stbznPrcsFmlyrQnt: toGridNumber(row.stbznPrcsFmlyrQnt),
|
||||||
stbznPrcsFcltNm: nullableTrimmedString(row.stbznPrcsFcltNm),
|
stbznPrcsFcltNm: String(row.stbznPrcsFcltNm ?? "").trim(),
|
||||||
dryPrcsLfvlm: toGridNumber(row.dryPrcsLfvlm),
|
dryPrcsLfvlm: toGridNumber(row.dryPrcsLfvlm),
|
||||||
dryPrcsIncnrQnt: toGridNumber(row.dryPrcsIncnrQnt),
|
dryPrcsIncnrQnt: toGridNumber(row.dryPrcsIncnrQnt),
|
||||||
dryPrcsFuelQnt: toGridNumber(row.dryPrcsFuelQnt),
|
dryPrcsFuelQnt: toGridNumber(row.dryPrcsFuelQnt),
|
||||||
dryPrcsPrdctRmtrlQnt: toGridNumber(row.dryPrcsPrdctRmtrlQnt),
|
dryPrcsPrdctRmtrlQnt: toGridNumber(row.dryPrcsPrdctRmtrlQnt),
|
||||||
dryPrcsFmlyrQnt: toGridNumber(row.dryPrcsFmlyrQnt),
|
dryPrcsFmlyrQnt: toGridNumber(row.dryPrcsFmlyrQnt),
|
||||||
dryPrcsCmpstgQnt: toGridNumber(row.dryPrcsCmpstgQnt),
|
dryPrcsCmpstgQnt: toGridNumber(row.dryPrcsCmpstgQnt),
|
||||||
dryPrcsFcltNm: nullableTrimmedString(row.dryPrcsFcltNm),
|
dryPrcsFcltNm: String(row.dryPrcsFcltNm ?? "").trim(),
|
||||||
fuelPrcsIncnrQnt: toGridNumber(row.fuelPrcsIncnrQnt),
|
fuelPrcsIncnrQnt: toGridNumber(row.fuelPrcsIncnrQnt),
|
||||||
fuelPrcsFuelQnt: toGridNumber(row.fuelPrcsFuelQnt),
|
fuelPrcsFuelQnt: toGridNumber(row.fuelPrcsFuelQnt),
|
||||||
fuelPrcsFcltNm: nullableTrimmedString(row.fuelPrcsFcltNm),
|
fuelPrcsFcltNm: String(row.fuelPrcsFcltNm ?? "").trim(),
|
||||||
otsdCnsgnRclmQnt: toGridNumber(row.otsdCnsgnRclmQnt),
|
otsdCnsgnRclmQnt: toGridNumber(row.otsdCnsgnRclmQnt),
|
||||||
otsdCnsgnIncnrQnt: toGridNumber(row.otsdCnsgnIncnrQnt),
|
otsdCnsgnIncnrQnt: toGridNumber(row.otsdCnsgnIncnrQnt),
|
||||||
otsdCnsgnFuelPwplQnt: toGridNumber(row.otsdCnsgnFuelPwplQnt),
|
otsdCnsgnFuelPwplQnt: toGridNumber(row.otsdCnsgnFuelPwplQnt),
|
||||||
otsdCnsgnPrdctRmtrlQnt: toGridNumber(row.otsdCnsgnPrdctRmtrlQnt),
|
otsdCnsgnPrdctRmtrlQnt: toGridNumber(row.otsdCnsgnPrdctRmtrlQnt),
|
||||||
otsdCnsgnFmlyrQnt: toGridNumber(row.otsdCnsgnFmlyrQnt),
|
otsdCnsgnFmlyrQnt: toGridNumber(row.otsdCnsgnFmlyrQnt),
|
||||||
otsdCnsgnCmpstgQnt: toGridNumber(row.otsdCnsgnCmpstgQnt),
|
otsdCnsgnCmpstgQnt: toGridNumber(row.otsdCnsgnCmpstgQnt),
|
||||||
otsdCnsgnFcltNm: nullableTrimmedString(row.otsdCnsgnFcltNm),
|
otsdCnsgnFcltNm: String(row.otsdCnsgnFcltNm ?? "").trim(),
|
||||||
cparTs1Whol: toGridNumber(row.cparTs1Whol),
|
cparTs1Whol: toGridNumber(row.cparTs1Whol),
|
||||||
rmrk: nullableTrimmedString(row.rmrk),
|
rmrk: nullableTrimmedString(row.rmrk),
|
||||||
};
|
};
|
||||||
@@ -550,10 +526,10 @@ function buildDigestorOperatingStatusSaveItem(
|
|||||||
const base = {
|
const base = {
|
||||||
admdstCd,
|
admdstCd,
|
||||||
admdstNm,
|
admdstNm,
|
||||||
swtrmtFcltCd: nullableTrimmedString(row.swtrmtFcltCd),
|
swtrmtFcltCd: String(row.swtrmtFcltCd ?? "").trim(),
|
||||||
swtrmtFcltNm: nullableTrimmedString(row.swtrmtFcltNm),
|
swtrmtFcltNm: String(row.swtrmtFcltNm ?? "").trim(),
|
||||||
fcltSn: nullableTrimmedString(row.fcltSn),
|
fcltSn: String(row.fcltSn ?? "").trim(),
|
||||||
digstnEnYn: nullableTrimmedString(row.digstnEnYn),
|
digstnEnYn: String(row.digstnEnYn ?? "").trim(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isDigestorOperatingRowDisabled(row)) {
|
if (isDigestorOperatingRowDisabled(row)) {
|
||||||
@@ -601,9 +577,9 @@ function buildSewageSlurgeProcessingFacStatusSaveItem(
|
|||||||
return {
|
return {
|
||||||
admdstCd,
|
admdstCd,
|
||||||
admdstNm,
|
admdstNm,
|
||||||
fcltSn: nullableTrimmedString(row.fcltSn),
|
fcltSn: String(row.fcltSn ?? "").trim(),
|
||||||
fcltNm: nullableTrimmedString(row.fcltNm),
|
fcltNm: String(row.fcltNm ?? "").trim(),
|
||||||
prcsMthExpln: nullableTrimmedString(row.prcsMthExpln),
|
prcsMthExpln: String(row.prcsMthExpln ?? "").trim(),
|
||||||
fcltCpct: toGridNumber(row.fcltCpct),
|
fcltCpct: toGridNumber(row.fcltCpct),
|
||||||
anlPrcsQnt: toGridNumber(row.anlPrcsQnt),
|
anlPrcsQnt: toGridNumber(row.anlPrcsQnt),
|
||||||
dayAvgOprtngHr: toGridNumber(row.dayAvgOprtngHr),
|
dayAvgOprtngHr: toGridNumber(row.dayAvgOprtngHr),
|
||||||
@@ -621,9 +597,9 @@ function buildExcretaSlurgeProcessingStatusSaveItem(
|
|||||||
return {
|
return {
|
||||||
admdstCd,
|
admdstCd,
|
||||||
admdstNm,
|
admdstNm,
|
||||||
fcltSn: nullableTrimmedString(row.fcltSn),
|
fcltSn: String(row.fcltSn ?? "").trim(),
|
||||||
fcltNm: nullableTrimmedString(row.fcltNm),
|
fcltNm: String(row.fcltNm ?? "").trim(),
|
||||||
fcltPstnCn: nullableTrimmedString(row.fcltPstnCn),
|
fcltPstnCn: String(row.fcltPstnCn ?? "").trim(),
|
||||||
rcycQnt: toGridNumber(row.rcycQnt),
|
rcycQnt: toGridNumber(row.rcycQnt),
|
||||||
olandLfvlm: toGridNumber(row.olandLfvlm),
|
olandLfvlm: toGridNumber(row.olandLfvlm),
|
||||||
incnrQnt: toGridNumber(row.incnrQnt),
|
incnrQnt: toGridNumber(row.incnrQnt),
|
||||||
@@ -631,7 +607,7 @@ function buildExcretaSlurgeProcessingStatusSaveItem(
|
|||||||
fuelQnt: toGridNumber(row.fuelQnt),
|
fuelQnt: toGridNumber(row.fuelQnt),
|
||||||
etcQnt: toGridNumber(row.etcQnt),
|
etcQnt: toGridNumber(row.etcQnt),
|
||||||
nondspsQnt: toGridNumber(row.nondspsQnt),
|
nondspsQnt: toGridNumber(row.nondspsQnt),
|
||||||
swtrmtFcltNm: nullableTrimmedString(row.swtrmtFcltNm),
|
swtrmtFcltNm: String(row.swtrmtFcltNm ?? "").trim(),
|
||||||
rmrk: nullableTrimmedString(row.rmrk),
|
rmrk: nullableTrimmedString(row.rmrk),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -654,17 +630,15 @@ async function waitForImrJobCompleted(
|
|||||||
options?.onProgress?.(Math.max(0, Math.min(100, Number(res.job_prog) || 0)));
|
options?.onProgress?.(Math.max(0, Math.min(100, Number(res.job_prog) || 0)));
|
||||||
if (res.status === "COMPLETED" && Number(res.job_prog) === 100) return;
|
if (res.status === "COMPLETED" && Number(res.job_prog) === 100) return;
|
||||||
if (res.status === "FAILED" || res.status === "ERROR" || res.status === "CANCELLED") {
|
if (res.status === "FAILED" || res.status === "ERROR" || res.status === "CANCELLED") {
|
||||||
throw new Error(res.error_msg || `시계열 검증이 ${res.status} 상태로 종료되었습니다.`);
|
throw new Error(res.error_msg || `IMR 검증이 ${res.status} 상태로 종료되었습니다.`);
|
||||||
}
|
}
|
||||||
await sleep(pollIntervalMs);
|
await sleep(pollIntervalMs);
|
||||||
}
|
}
|
||||||
throw new Error("시계열 검증 완료 대기 시간이 초과되었습니다.");
|
throw new Error("IMR 검증 완료 대기 시간이 초과되었습니다.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 하수도 통계 관리 > 11. 하수 및 분뇨찌꺼기(슬러지)처리
|
// 하수도 통계 관리 > 11. 하수 및 분뇨찌꺼기(슬러지)처리
|
||||||
const SewageExcretaSlurgeInp = () => {
|
const SewageExcretaSlurgeInp = () => {
|
||||||
const { sidoList } = useSearchConditionSidoList({ isInput: true });
|
|
||||||
sidoListRef.current = sidoList;
|
|
||||||
const { isAdminInfo } = useAdminStore();
|
const { isAdminInfo } = useAdminStore();
|
||||||
const { confirm } = useConfirm();
|
const { confirm } = useConfirm();
|
||||||
const { setMessage: alert } = useAlertStore((state) => state);
|
const { setMessage: alert } = useAlertStore((state) => state);
|
||||||
@@ -693,15 +667,9 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
const [isVerificationFailedByTab, setIsVerificationFailedByTab] = useState<
|
const [isVerificationFailedByTab, setIsVerificationFailedByTab] = useState<
|
||||||
Map<string, boolean>
|
Map<string, boolean>
|
||||||
>(new Map());
|
>(new Map());
|
||||||
const [footerVerificationByTab, setFooterVerificationByTab] = useState<
|
|
||||||
Map<string, VerificationResultLikeMap | null>
|
|
||||||
>(new Map());
|
|
||||||
const [_toolbarSnapshotByTab, setToolbarSnapshotByTab] = useState<
|
const [_toolbarSnapshotByTab, setToolbarSnapshotByTab] = useState<
|
||||||
Map<string, TabToolbarSnapshot>
|
Map<string, TabToolbarSnapshot>
|
||||||
>(new Map());
|
>(new Map());
|
||||||
const [searchContextByTab, setSearchContextByTab] = useState<Map<string, SearchFormValues>>(
|
|
||||||
() => new Map(),
|
|
||||||
);
|
|
||||||
const [sggOptions, setSggOptions] = useState<Sgg[]>([]);
|
const [sggOptions, setSggOptions] = useState<Sgg[]>([]);
|
||||||
const [loadedTabKeys, setLoadedTabKeys] = useState<Set<string>>(() => new Set());
|
const [loadedTabKeys, setLoadedTabKeys] = useState<Set<string>>(() => new Set());
|
||||||
const [verificationHistoryOpen, setVerificationHistoryOpen] = useState(false);
|
const [verificationHistoryOpen, setVerificationHistoryOpen] = useState(false);
|
||||||
@@ -732,29 +700,36 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
const preYearArticleFcltSnRef = useRef<ArticleFcltSnSet>(new Set());
|
const preYearArticleFcltSnRef = useRef<ArticleFcltSnSet>(new Set());
|
||||||
activeTabRef.current = activeTab;
|
activeTabRef.current = activeTab;
|
||||||
|
|
||||||
const activeTabId = useTabStore((s) => s.activeTabId);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeTabId !== STATISTICS_INPUT_URL_PATH.SEWAGE_EXCRETA_SLURGE) return;
|
|
||||||
const tabKey = activeTab;
|
|
||||||
if (!tabKey) return;
|
|
||||||
if (Object.prototype.hasOwnProperty.call(columnGuidesByTab, tabKey)) return;
|
|
||||||
const statsCd = tabKey;
|
|
||||||
|
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
void (async () => {
|
void (async () => {
|
||||||
const next = await fetchColumnGuidesRecord(statsCd);
|
const entries = await Promise.all(
|
||||||
if (cancelled) return;
|
SewageExcretaSlurgeInpTabList.map(async (tab) => {
|
||||||
setColumnGuidesByTab((prev) =>
|
const tabKey = tab.tabKey;
|
||||||
Object.prototype.hasOwnProperty.call(prev, tabKey)
|
try {
|
||||||
? prev
|
const res = await statisticsApi.getColumnGuides(tabKey);
|
||||||
: { ...prev, [tabKey]: next },
|
if (res.status !== "success" || !Array.isArray(res.data)) {
|
||||||
|
return [tabKey, {}] as const;
|
||||||
|
}
|
||||||
|
const next: Record<string, string> = {};
|
||||||
|
for (const item of res.data) {
|
||||||
|
const key = item.engColNm?.trim();
|
||||||
|
const guide = item.columnGuide?.trim();
|
||||||
|
if (key && guide) next[key] = guide;
|
||||||
|
}
|
||||||
|
return [tabKey, next] as const;
|
||||||
|
} catch {
|
||||||
|
return [tabKey, {}] as const;
|
||||||
|
}
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
if (cancelled) return;
|
||||||
|
setColumnGuidesByTab(Object.fromEntries(entries));
|
||||||
})();
|
})();
|
||||||
return () => {
|
return () => {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
};
|
};
|
||||||
}, [activeTabId, activeTab, columnGuidesByTab]);
|
}, []);
|
||||||
|
|
||||||
const shouldShowNotApplicable = (
|
const shouldShowNotApplicable = (
|
||||||
hasRows: boolean,
|
hasRows: boolean,
|
||||||
@@ -814,13 +789,6 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
);
|
);
|
||||||
return next;
|
return next;
|
||||||
});
|
});
|
||||||
if (searchContext) {
|
|
||||||
setSearchContextByTab((prev) => {
|
|
||||||
const next = new Map(prev);
|
|
||||||
next.set(tabKey, searchContext);
|
|
||||||
return next;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getTabGridRows = (tabKey: string): Record<string, string | number>[] =>
|
const getTabGridRows = (tabKey: string): Record<string, string | number>[] =>
|
||||||
@@ -954,7 +922,7 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const { commonInfo, statusInfo, slurgeProcessingFacStatusList } = response.data;
|
const { commonInfo, statusInfo, slurgeProcessingFacStatusList } = response.data;
|
||||||
const gridRows = mapListToGridRows(slurgeProcessingFacStatusList, commonInfo.ctpvNm, searchContext);
|
const gridRows = mapListToGridRows(slurgeProcessingFacStatusList, commonInfo.ctpvNm);
|
||||||
syncSlurgeFacStatusArticleFcltSnTracking(gridRows, fromPreYear);
|
syncSlurgeFacStatusArticleFcltSnTracking(gridRows, fromPreYear);
|
||||||
applyRowMap(mergeIntoExistingMap, (m) => {
|
applyRowMap(mergeIntoExistingMap, (m) => {
|
||||||
m.set(SlurgeProcessingFacStatusInpColumn.tabKey, gridRows);
|
m.set(SlurgeProcessingFacStatusInpColumn.tabKey, gridRows);
|
||||||
@@ -964,9 +932,6 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
||||||
commitToolbarSnapshotForLoadedTab(
|
commitToolbarSnapshotForLoadedTab(
|
||||||
tabKey,
|
tabKey,
|
||||||
@@ -989,7 +954,7 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const { commonInfo, statusInfo, digestorOperatingStatusList } = response.data;
|
const { commonInfo, statusInfo, digestorOperatingStatusList } = response.data;
|
||||||
const gridRows = mapListToGridRows(digestorOperatingStatusList, commonInfo.ctpvNm, searchContext);
|
const gridRows = mapListToGridRows(digestorOperatingStatusList, commonInfo.ctpvNm);
|
||||||
if (!fromPreYear) {
|
if (!fromPreYear) {
|
||||||
publicSewageFacilitiesAvailableRef.current = gridRows.length > 0;
|
publicSewageFacilitiesAvailableRef.current = gridRows.length > 0;
|
||||||
if (gridRows.length === 0 && overrides?.alertIfDigestorEmpty) {
|
if (gridRows.length === 0 && overrides?.alertIfDigestorEmpty) {
|
||||||
@@ -1004,9 +969,6 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
||||||
commitToolbarSnapshotForLoadedTab(
|
commitToolbarSnapshotForLoadedTab(
|
||||||
tabKey,
|
tabKey,
|
||||||
@@ -1033,7 +995,6 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
const gridRows = mapListToGridRows(
|
const gridRows = mapListToGridRows(
|
||||||
sewageSlurgeProcessingFacStatusList,
|
sewageSlurgeProcessingFacStatusList,
|
||||||
commonInfo.ctpvNm,
|
commonInfo.ctpvNm,
|
||||||
searchContext,
|
|
||||||
);
|
);
|
||||||
applyRowMap(mergeIntoExistingMap, (m) => {
|
applyRowMap(mergeIntoExistingMap, (m) => {
|
||||||
m.set(SewageSlurgeProcessingFacStatusInpColumn.tabKey, gridRows);
|
m.set(SewageSlurgeProcessingFacStatusInpColumn.tabKey, gridRows);
|
||||||
@@ -1043,9 +1004,6 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
||||||
commitToolbarSnapshotForLoadedTab(
|
commitToolbarSnapshotForLoadedTab(
|
||||||
tabKey,
|
tabKey,
|
||||||
@@ -1071,7 +1029,6 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
const gridRows = mapListToGridRows(
|
const gridRows = mapListToGridRows(
|
||||||
excretaSlurgeProcessingStatusList,
|
excretaSlurgeProcessingStatusList,
|
||||||
commonInfo.ctpvNm,
|
commonInfo.ctpvNm,
|
||||||
searchContext,
|
|
||||||
);
|
);
|
||||||
if (!fromPreYear) {
|
if (!fromPreYear) {
|
||||||
excretaTreatmentFacilitiesAvailableRef.current = gridRows.length > 0;
|
excretaTreatmentFacilitiesAvailableRef.current = gridRows.length > 0;
|
||||||
@@ -1087,9 +1044,6 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
||||||
commitToolbarSnapshotForLoadedTab(
|
commitToolbarSnapshotForLoadedTab(
|
||||||
tabKey,
|
tabKey,
|
||||||
@@ -1111,9 +1065,7 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
setTabStatusInfoMap(new Map());
|
setTabStatusInfoMap(new Map());
|
||||||
setTabStatsCdMap(new Map());
|
setTabStatsCdMap(new Map());
|
||||||
setIsVerificationFailedByTab(new Map());
|
setIsVerificationFailedByTab(new Map());
|
||||||
setFooterVerificationByTab(new Map());
|
|
||||||
setToolbarSnapshotByTab(new Map());
|
setToolbarSnapshotByTab(new Map());
|
||||||
setSearchContextByTab(new Map());
|
|
||||||
setActiveTab(firstTabKey);
|
setActiveTab(firstTabKey);
|
||||||
activeTabRef.current = firstTabKey;
|
activeTabRef.current = firstTabKey;
|
||||||
setLastSearchedValues(null);
|
setLastSearchedValues(null);
|
||||||
@@ -1171,9 +1123,7 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
setTabStatusInfoMap(new Map());
|
setTabStatusInfoMap(new Map());
|
||||||
setTabStatsCdMap(new Map());
|
setTabStatsCdMap(new Map());
|
||||||
setIsVerificationFailedByTab(new Map());
|
setIsVerificationFailedByTab(new Map());
|
||||||
setFooterVerificationByTab(new Map());
|
|
||||||
setToolbarSnapshotByTab(new Map());
|
setToolbarSnapshotByTab(new Map());
|
||||||
setSearchContextByTab(new Map());
|
|
||||||
loadedTabKeysRef.current.clear();
|
loadedTabKeysRef.current.clear();
|
||||||
setLoadedTabKeys(new Set());
|
setLoadedTabKeys(new Set());
|
||||||
setDeleteListByTab(new Map());
|
setDeleteListByTab(new Map());
|
||||||
@@ -1282,9 +1232,9 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
commitActiveGrid();
|
commitActiveGrid();
|
||||||
const noApplicable = buildNoApplicableForRequest(searchContextByTab.get(tabKey) ?? lastSearchedValues, isNotApplicableByTab.get(tabKey) ?? false, getTabGridRows(tabKey).length === 0);
|
const noApplicable = isNotApplicableByTab.get(tabKey) ?? false;
|
||||||
const currentData = getTabGridRows(tabKey);
|
const currentData = getTabGridRows(tabKey);
|
||||||
if (!noApplicable && currentData.length === 0 && buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)) {
|
if (!noApplicable && currentData.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1312,7 +1262,7 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
|
|
||||||
commitActiveGrid();
|
commitActiveGrid();
|
||||||
|
|
||||||
const noApplicable = buildNoApplicableForRequest(searchContextByTab.get(tabKey) ?? lastSearchedValues, isNotApplicableByTab.get(tabKey) ?? false, getTabGridRows(tabKey).length === 0);
|
const noApplicable = isNotApplicableByTab.get(tabKey) ?? false;
|
||||||
const currentData = getTabGridRows(tabKey);
|
const currentData = getTabGridRows(tabKey);
|
||||||
const mapRows = rowDataMap.get(tabKey) ?? [];
|
const mapRows = rowDataMap.get(tabKey) ?? [];
|
||||||
|
|
||||||
@@ -1370,7 +1320,6 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
!noApplicable &&
|
!noApplicable &&
|
||||||
buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues) &&
|
|
||||||
((isSlurgeFacTab && slurgeSubmitList.length === 0) ||
|
((isSlurgeFacTab && slurgeSubmitList.length === 0) ||
|
||||||
(isDigestorTab && digestorSubmitList.length === 0) ||
|
(isDigestorTab && digestorSubmitList.length === 0) ||
|
||||||
(isSewageSlurgeFacTab && sewageSlurgeFacSubmitList.length === 0) ||
|
(isSewageSlurgeFacTab && sewageSlurgeFacSubmitList.length === 0) ||
|
||||||
@@ -1392,8 +1341,12 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
: SEWAGE_EXCRETA_SLURGE_PROCESSING_FAC_STATUS_STATS_CD);
|
: SEWAGE_EXCRETA_SLURGE_PROCESSING_FAC_STATUS_STATS_CD);
|
||||||
|
|
||||||
const verificationQuery = {
|
const verificationQuery = {
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
statsCd: statsCdForSubmit,
|
statsCd: statsCdForSubmit,
|
||||||
};
|
};
|
||||||
@@ -1422,7 +1375,11 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
const submitRequestBase = {
|
const submitRequestBase = {
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
userId: "",
|
userId: "",
|
||||||
laePicNm: submitInfo.laePicNm,
|
laePicNm: submitInfo.laePicNm,
|
||||||
laePicTelNo: submitInfo.laePicTelNo,
|
laePicTelNo: submitInfo.laePicTelNo,
|
||||||
@@ -1480,16 +1437,15 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
|
|
||||||
if (finalStatus === "5") {
|
if (finalStatus === "5") {
|
||||||
setGlobalProgress(50);
|
setGlobalProgress(50);
|
||||||
setGlobalProgressLabel("시계열 검증 진행 중...");
|
setGlobalProgressLabel("IMR 검증 진행 중...");
|
||||||
const imrParam = {
|
const imrParam = {
|
||||||
user_id: userInfo.userUnqId,
|
user_id: userInfo.userUnqId,
|
||||||
sewer_bzmn_cd: lastSearchedValues?.bsnmCd ?? "",
|
sewer_bzmn_cd: lastSearchedValues.bsnmCd ?? "",
|
||||||
stats_cd: statsCdForSubmit,
|
stats_cd: statsCdForSubmit,
|
||||||
stats_yr: lastSearchedValues.year ?? "",
|
stats_yr: lastSearchedValues.year ?? "",
|
||||||
lae_sbmsn_stts_cd:
|
lae_sbmsn_stts_cd:
|
||||||
activeTabStatus?.laeSbmsnSttsCd === "4" ? "4" : "2",
|
activeTabStatus?.laeSbmsnSttsCd === "4" ? "4" : "2",
|
||||||
gen_verify_stts_cd: nvpassed ? "1" : "2",
|
gen_verify_stts_cd: nvpassed ? "1" : "2",
|
||||||
hb_pass_yn: response.data?.isHbPassed,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -1561,8 +1517,12 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const requestData: cancelSubmitRequest = {
|
const requestData: cancelSubmitRequest = {
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
mdfrId: userInfo.userUnqId,
|
mdfrId: userInfo.userUnqId,
|
||||||
statsCd: statsCdForTab,
|
statsCd: statsCdForTab,
|
||||||
@@ -1610,7 +1570,7 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
|
|
||||||
commitActiveGrid();
|
commitActiveGrid();
|
||||||
|
|
||||||
const noApplicable = buildNoApplicableForRequest(searchContextByTab.get(tabKey) ?? lastSearchedValues, isNotApplicableByTab.get(tabKey) ?? false, getTabGridRows(tabKey).length === 0);
|
const noApplicable = isNotApplicableByTab.get(tabKey) ?? false;
|
||||||
const currentData = getTabGridRows(tabKey);
|
const currentData = getTabGridRows(tabKey);
|
||||||
const mapRows = rowDataMap.get(tabKey) ?? [];
|
const mapRows = rowDataMap.get(tabKey) ?? [];
|
||||||
|
|
||||||
@@ -1628,7 +1588,11 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
const baseSaveRequest = {
|
const baseSaveRequest = {
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
...(noApplicable ? { noApplicable: true } : {}),
|
...(noApplicable ? { noApplicable: true } : {}),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1659,7 +1623,7 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
.filter((row) => isPersistedArticleRowForTab(tabKey, row))
|
.filter((row) => isPersistedArticleRowForTab(tabKey, row))
|
||||||
.map((row) => buildSlurgeProcessingFacStatusSaveItem(row, list));
|
.map((row) => buildSlurgeProcessingFacStatusSaveItem(row, list));
|
||||||
|
|
||||||
if (!noApplicable && saveList.length === 0 && buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)) {
|
if (!noApplicable && saveList.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1686,7 +1650,7 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
buildDigestorOperatingStatusSaveItem(row, list),
|
buildDigestorOperatingStatusSaveItem(row, list),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!noApplicable && saveList.length === 0 && buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)) {
|
if (!noApplicable && saveList.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1712,7 +1676,7 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
.filter((row) => isPersistedArticleRowForTab(tabKey, row))
|
.filter((row) => isPersistedArticleRowForTab(tabKey, row))
|
||||||
.map((row) => buildSewageSlurgeProcessingFacStatusSaveItem(row, list));
|
.map((row) => buildSewageSlurgeProcessingFacStatusSaveItem(row, list));
|
||||||
|
|
||||||
if (!noApplicable && saveList.length === 0 && buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)) {
|
if (!noApplicable && saveList.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1739,7 +1703,7 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
buildExcretaSlurgeProcessingStatusSaveItem(row, list),
|
buildExcretaSlurgeProcessingStatusSaveItem(row, list),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!noApplicable && saveList.length === 0 && buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)) {
|
if (!noApplicable && saveList.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1917,10 +1881,10 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
for (const tab of SewageExcretaSlurgeInpTabList) {
|
for (const tab of SewageExcretaSlurgeInpTabList) {
|
||||||
const tabKey = tab.tabKey;
|
const tabKey = tab.tabKey;
|
||||||
const canEdit =
|
const canEdit =
|
||||||
(computeTabEnterable(
|
computeTabEnterable(
|
||||||
tabStatusInfoMap.get(tabKey) ?? null,
|
tabStatusInfoMap.get(tabKey) ?? null,
|
||||||
inputPeriodEnterable,
|
inputPeriodEnterable,
|
||||||
) || isAdminInfo) && inputPeriodEnterable;
|
) || isAdminInfo;
|
||||||
const rawColumns = (tab.columns ?? []) as ColumnConfig[];
|
const rawColumns = (tab.columns ?? []) as ColumnConfig[];
|
||||||
const base = canEdit
|
const base = canEdit
|
||||||
? rawColumns
|
? rawColumns
|
||||||
@@ -1934,7 +1898,7 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
col.fieldName === "sggNm"
|
col.fieldName === "sggNm"
|
||||||
) {
|
) {
|
||||||
next = buildSggNmColumn(col, canEdit, sggOptions);
|
next = buildSggNmColumn(col, canEdit, sggOptions);
|
||||||
} else if (col.fieldName === "sggNm") {
|
} else if (col.fieldName === "sggNm" || col.fieldName === "swtrmtFcltNm") {
|
||||||
next = { ...col, editable: false as const, styleName: "rg-cell-readonly" };
|
next = { ...col, editable: false as const, styleName: "rg-cell-readonly" };
|
||||||
}
|
}
|
||||||
const guide = columnGuidesByTab[tabKey]?.[col.fieldName]?.trim();
|
const guide = columnGuidesByTab[tabKey]?.[col.fieldName]?.trim();
|
||||||
@@ -1998,7 +1962,7 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
[digestorOperatingCellStyleCallback],
|
[digestorOperatingCellStyleCallback],
|
||||||
);
|
);
|
||||||
|
|
||||||
const searchContextForToolbar = searchContextByTab.get(activeTab) ?? lastSearchedValues;
|
const searchContextForToolbar = lastSearchedValues ?? searchValues;
|
||||||
const activeTabStatus = tabStatusInfoMap.get(activeTab) ?? null;
|
const activeTabStatus = tabStatusInfoMap.get(activeTab) ?? null;
|
||||||
const activeTabHasRowData = tabRowDataExists(rowDataMap, activeTab);
|
const activeTabHasRowData = tabRowDataExists(rowDataMap, activeTab);
|
||||||
const activeTabToolbar = computeTabToolbarSnapshot(
|
const activeTabToolbar = computeTabToolbarSnapshot(
|
||||||
@@ -2019,7 +1983,6 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
const showSaveInToolbar = baseShowSaveInToolbar && toolbarGroupAllowed;
|
const showSaveInToolbar = baseShowSaveInToolbar && toolbarGroupAllowed;
|
||||||
const showEnterableToolbarButtons =
|
const showEnterableToolbarButtons =
|
||||||
baseShowEnterableToolbarButtons && toolbarGroupAllowed;
|
baseShowEnterableToolbarButtons && toolbarGroupAllowed;
|
||||||
const submitOk = buildSubmitOkForToolbar(searchContextForToolbar);
|
|
||||||
const showActionToolbarCard =
|
const showActionToolbarCard =
|
||||||
toolbarGroupAllowed &&
|
toolbarGroupAllowed &&
|
||||||
(baseShowActionToolbarCard || (hasSearched && loadedTabKeys.has(activeTab)));
|
(baseShowActionToolbarCard || (hasSearched && loadedTabKeys.has(activeTab)));
|
||||||
@@ -2027,8 +1990,7 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
ARTICLE_EDIT_TAB_KEYS.has(activeTab) && showEnterableToolbarButtons;
|
ARTICLE_EDIT_TAB_KEYS.has(activeTab) && showEnterableToolbarButtons;
|
||||||
const showNotApplicableForActiveTab =
|
const showNotApplicableForActiveTab =
|
||||||
loadedTabKeys.has(activeTab) &&
|
loadedTabKeys.has(activeTab) &&
|
||||||
shouldShowNotApplicable(activeTabHasRowData, activeTabStatus) &&
|
shouldShowNotApplicable(activeTabHasRowData, activeTabStatus);
|
||||||
submitOk;
|
|
||||||
const showSecondaryToolbarCard =
|
const showSecondaryToolbarCard =
|
||||||
hasSearched &&
|
hasSearched &&
|
||||||
toolbarGroupAllowed &&
|
toolbarGroupAllowed &&
|
||||||
@@ -2062,8 +2024,9 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
const statsCd = tabStatsCdMap.get(activeTab);
|
const statsCd = tabStatsCdMap.get(activeTab);
|
||||||
if (!ctx?.year || !ctx?.sido || !ctx?.bsnmCd || !statsCd) return null;
|
if (!ctx?.year || !ctx?.sido || !ctx?.bsnmCd || !statsCd) return null;
|
||||||
return {
|
return {
|
||||||
...toInputSearchRegion(sidoListRef.current, ctx),
|
sewerBzmnCd: ctx.bsnmCd,
|
||||||
ctpvNm: ctx.sido,
|
ctpvNm: ctx.sido,
|
||||||
|
sggNm: ctx.gugun === "ALL" ? "" : (ctx.gugun ?? ""),
|
||||||
statsYr: ctx.year,
|
statsYr: ctx.year,
|
||||||
statsCd,
|
statsCd,
|
||||||
};
|
};
|
||||||
@@ -2084,7 +2047,6 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
<>
|
<>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<SearchForm
|
<SearchForm
|
||||||
isInput
|
|
||||||
key={searchFormRemountKey}
|
key={searchFormRemountKey}
|
||||||
defaultValues={verificationSearchDefaults ?? undefined}
|
defaultValues={verificationSearchDefaults ?? undefined}
|
||||||
fctName
|
fctName
|
||||||
@@ -2093,8 +2055,8 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
onValuesChange={setSearchValues}
|
onValuesChange={setSearchValues}
|
||||||
/>
|
/>
|
||||||
{showActionToolbarCard && (
|
{showActionToolbarCard && (
|
||||||
<div className="card !py-0">
|
<div className="card !py-0">
|
||||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||||
<VerificationResultButton
|
<VerificationResultButton
|
||||||
VerificationResultButtonFunc={openVerificationHistoryDialog}
|
VerificationResultButtonFunc={openVerificationHistoryDialog}
|
||||||
isVerificationFailed={
|
isVerificationFailed={
|
||||||
@@ -2106,19 +2068,19 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
<LastYearDataButton
|
<LastYearDataButton
|
||||||
getLastYearDataFunc={() => void lastYearDataFunc()}
|
getLastYearDataFunc={() => void lastYearDataFunc()}
|
||||||
/>
|
/>
|
||||||
{submitOk && <SubmitButton submitFunc={submitFunc} />}
|
<SubmitButton submitFunc={submitFunc} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{activeTabStatus?.laeSbmsnSttsCd === "2" && submitOk && (
|
{activeTabStatus?.laeSbmsnSttsCd === "2" && (
|
||||||
<CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />
|
<CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />
|
||||||
)}
|
)}
|
||||||
{showSaveInToolbar && <SaveButton saveFunc={saveFunc} />}
|
{showSaveInToolbar && <SaveButton saveFunc={saveFunc} />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{showSecondaryToolbarCard && (
|
{showSecondaryToolbarCard && (
|
||||||
<div className="card !py-0">
|
<div className="card !py-0">
|
||||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||||
{showNotApplicableForActiveTab && (
|
{showNotApplicableForActiveTab && (
|
||||||
<NotApplicableCheckButton
|
<NotApplicableCheckButton
|
||||||
isCheck={isNotApplicableForActiveTab}
|
isCheck={isNotApplicableForActiveTab}
|
||||||
@@ -2127,12 +2089,12 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
)}
|
)}
|
||||||
{showArticleEditButtons && (
|
{showArticleEditButtons && (
|
||||||
<>
|
<>
|
||||||
<AddArticleButton addArticleFunc={addArticleFunc} />
|
<AddArticleButton addArticleFunc={addArticleFunc} />
|
||||||
<DeleteArticleButton deleteArticleFunc={deleteArticleFunc} />
|
<DeleteArticleButton deleteArticleFunc={deleteArticleFunc} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
||||||
@@ -2197,9 +2159,6 @@ const SewageExcretaSlurgeInp = () => {
|
|||||||
activeTab === tabKey ? getGridRef : undefined
|
activeTab === tabKey ? getGridRef : undefined
|
||||||
}
|
}
|
||||||
cellStyleCallback={resolveGridCellStyleCallback(tabKey)}
|
cellStyleCallback={resolveGridCellStyleCallback(tabKey)}
|
||||||
footerVerificationResult={
|
|
||||||
footerVerificationByTab.get(tabKey) ?? null
|
|
||||||
}
|
|
||||||
cellTooltipCallback={verificationCellTooltip}
|
cellTooltipCallback={verificationCellTooltip}
|
||||||
onCellEdited={
|
onCellEdited={
|
||||||
tabKey === DigestorOperatingStatusInpColumn.tabKey
|
tabKey === DigestorOperatingStatusInpColumn.tabKey
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useEffect, useLayoutEffect,useMemo, useRef, useState } from "react";
|
|||||||
|
|
||||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||||
|
|
||||||
import { useAlertStore, useGlobalProgressStore, useStatisticsInputToolbarGroupGate, useSearchConditionSidoList } from "@/shared/lib";
|
import { useAlertStore, useGlobalProgressStore, useStatisticsInputToolbarGroupGate } from "@/shared/lib";
|
||||||
import {
|
import {
|
||||||
STATISTICS_INPUT_URL_PATH,
|
STATISTICS_INPUT_URL_PATH,
|
||||||
verificationSearchToFormValues,
|
verificationSearchToFormValues,
|
||||||
@@ -13,7 +13,9 @@ import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
|||||||
import type {
|
import type {
|
||||||
SeweragePipeInputFactInstallStatusSaveRequest,
|
SeweragePipeInputFactInstallStatusSaveRequest,
|
||||||
SeweragePipeInputFactInstallStatusSubmitRequest,
|
SeweragePipeInputFactInstallStatusSubmitRequest,
|
||||||
|
SeweragePipeInputManholeStatusItem,
|
||||||
SeweragePipeInputManholeStatusSaveRequest,
|
SeweragePipeInputManholeStatusSaveRequest,
|
||||||
|
SeweragePipeInputManholeStatusSaveYearlyStatItem,
|
||||||
SeweragePipeInputManholeStatusSubmitRequest,
|
SeweragePipeInputManholeStatusSubmitRequest,
|
||||||
SeweragePipeInputPipeDiameterStatusSaveRequest,
|
SeweragePipeInputPipeDiameterStatusSaveRequest,
|
||||||
SeweragePipeInputPipeDiameterStatusSubmitRequest,
|
SeweragePipeInputPipeDiameterStatusSubmitRequest,
|
||||||
@@ -38,15 +40,7 @@ import type {
|
|||||||
ImrStatusResponse,
|
ImrStatusResponse,
|
||||||
SewerageStatusInfo,
|
SewerageStatusInfo,
|
||||||
SubmitExceptionRequest,
|
SubmitExceptionRequest,
|
||||||
Sido,
|
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
} from "@/entities/statistics/model/statistics-interface";
|
||||||
import {
|
|
||||||
filterBySelectedAdmdstCd,
|
|
||||||
isGugunOkForToolbar,
|
|
||||||
isSubmitOkForToolbar,
|
|
||||||
toInputSearchRegion,
|
|
||||||
} from "@/entities/statistics";
|
|
||||||
|
|
||||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||||
|
|
||||||
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
||||||
@@ -59,29 +53,26 @@ import SaveButton from "@/components/button/SaveButton";
|
|||||||
import SubmitButton from "@/components/button/SumitButton";
|
import SubmitButton from "@/components/button/SumitButton";
|
||||||
import VerificationResultButton from "@/components/button/VerificationResultButton";
|
import VerificationResultButton from "@/components/button/VerificationResultButton";
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
|
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
||||||
import GridTopActionButton from "@/components/module/GridTopActionButton";
|
import GridTopActionButton from "@/components/module/GridTopActionButton";
|
||||||
import { openVerificationResultDialogIfNeeded } from "@/components/module/post-submit-verification-results";
|
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
import SplitDataGrid from "@/components/module/SplitDataGrid";
|
import SplitDataGrid from "@/components/module/SplitDataGrid";
|
||||||
|
import { openVerificationResultDialogIfNeeded } from "@/components/module/post-submit-verification-results";
|
||||||
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
||||||
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
||||||
import type { ColumnConfig, ColumnInfo, ColumnInfoList, ColumnLayoutItem } from "@/components/type/DataGrid.type";
|
import type { ColumnConfig, ColumnInfo, ColumnInfoList, ColumnLayoutItem } from "@/components/type/DataGrid.type";
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
|
import { doList } from "@/components/util/column/input/DoList";
|
||||||
import { FactInstallStatusInpColumn } from "@/components/util/column/input/sewagePipe/FactInstallStatusInpColumn";
|
import { FactInstallStatusInpColumn } from "@/components/util/column/input/sewagePipe/FactInstallStatusInpColumn";
|
||||||
import { ManholeStatusInpColumn } from "@/components/util/column/input/sewagePipe/ManholeStatusInpColumn";
|
import { ManholeStatusInpColumn } from "@/components/util/column/input/sewagePipe/ManholeStatusInpColumn";
|
||||||
import { PipeDiameterStatusInpColumn } from "@/components/util/column/input/sewagePipe/PipeDiameterStatusInpColumn";
|
import { PipeDiameterStatusInpColumn } from "@/components/util/column/input/sewagePipe/PipeDiameterStatusInpColumn";
|
||||||
import { PipeTypeStatusInpColumn } from "@/components/util/column/input/sewagePipe/PipeTypeStatusInpColumn";
|
import { PipeTypeStatusInpColumn } from "@/components/util/column/input/sewagePipe/PipeTypeStatusInpColumn";
|
||||||
import { RegionalFactStatusInpColumn } from "@/components/util/column/input/sewagePipe/RegionalFactStatusInpColumn";
|
import { RegionalFactStatusInpColumn } from "@/components/util/column/input/sewagePipe/RegionalFactStatusInpColumn";
|
||||||
import { SewagePipeInpColumnInfoList } from "@/components/util/column/input/sewagePipe/SewagePipeInpColumn";
|
import { SewagePipeInpColumnInfoList } from "@/components/util/column/input/sewagePipe/SewagePipeInpColumn";
|
||||||
import { fetchColumnGuidesRecord } from "@/components/util/grid/columnGuides";
|
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
|
||||||
import {
|
import {
|
||||||
patchFooterVerificationByTab,
|
|
||||||
patchVerificationFailedByTab,
|
patchVerificationFailedByTab,
|
||||||
} from "@/components/util/input/verification-failed-flag";
|
} from "@/components/util/input/verification-failed-flag";
|
||||||
import { nullableTrimmedString } from "@/components/util/input/nullableString";
|
|
||||||
import type { VerificationResultLikeMap } from "@/components/util/input/verification-result-display";
|
|
||||||
import { useAdminStore } from "@/store/admin-store";
|
import { useAdminStore } from "@/store/admin-store";
|
||||||
import { useStatisticsInputFocusStore } from "@/store/statistics-input-focus-store";
|
import { useStatisticsInputFocusStore } from "@/store/statistics-input-focus-store";
|
||||||
import { useTabStore } from "@/store/tab-store";
|
import { useTabStore } from "@/store/tab-store";
|
||||||
@@ -106,8 +97,9 @@ function buildSewagePipeSearchParam(
|
|||||||
): SeweragePipeRequestParams {
|
): SeweragePipeRequestParams {
|
||||||
return {
|
return {
|
||||||
statsYr: values.year,
|
statsYr: values.year,
|
||||||
|
sewerBzmnCd: values.bsnmCd,
|
||||||
ctpvNm: values.sido,
|
ctpvNm: values.sido,
|
||||||
...toInputSearchRegion(sidoListRef.current, values),
|
sggNm: values.gugun === "ALL" ? "" : values.gugun,
|
||||||
...(overrides?.mode ? { mode: overrides.mode } : {}),
|
...(overrides?.mode ? { mode: overrides.mode } : {}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -173,13 +165,12 @@ const applyPipeTypeStatusColumnLayout = (
|
|||||||
return walk(layout ?? []);
|
return walk(layout ?? []);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** ST00020003: 일반 사용자는 조회 연도 매설연장만, 관리자는 매설연장 컬럼 전체 편집 가능. 해당 연도 철거연장 컬럼 숨김 */
|
/** ST00020003: 입력기간 통과 시 조회 연도의 매설연장(y{year}LyngPrlg)만 편집 가능, 해당 연도 철거연장 컬럼 숨김 */
|
||||||
const applyPipeTypeStatusEditableColumns = (
|
const applyPipeTypeStatusEditableColumns = (
|
||||||
cols: ColumnConfig[] | undefined,
|
cols: ColumnConfig[] | undefined,
|
||||||
canEdit: boolean,
|
canEdit: boolean,
|
||||||
periodEnterable: boolean,
|
periodEnterable: boolean,
|
||||||
statsYr: string | null,
|
statsYr: string | null,
|
||||||
isAdmin: boolean,
|
|
||||||
): ColumnConfig[] => {
|
): ColumnConfig[] => {
|
||||||
const hideDmltnYear = shouldHidePipeTypeEditableYearDmltn(canEdit, periodEnterable, statsYr);
|
const hideDmltnYear = shouldHidePipeTypeEditableYearDmltn(canEdit, periodEnterable, statsYr);
|
||||||
|
|
||||||
@@ -204,12 +195,11 @@ const applyPipeTypeStatusEditableColumns = (
|
|||||||
if (fieldName === "lyngPrlg" || isYearLyngField) {
|
if (fieldName === "lyngPrlg" || isYearLyngField) {
|
||||||
const editableLyngField = periodEnterable ? resolvePipeTypeEditableLyngField(statsYr) : null;
|
const editableLyngField = periodEnterable ? resolvePipeTypeEditableLyngField(statsYr) : null;
|
||||||
const isTargetYear = editableLyngField !== null && fieldName === editableLyngField;
|
const isTargetYear = editableLyngField !== null && fieldName === editableLyngField;
|
||||||
if (isAdmin || isTargetYear) {
|
if (isTargetYear) {
|
||||||
const { styleName, ...rest } = col;
|
const { styleName: _readonlyStyle, ...rest } = col;
|
||||||
return {
|
return {
|
||||||
...rest,
|
...rest,
|
||||||
editable: true as const,
|
editable: true as const,
|
||||||
...(styleName && styleName !== "rg-cell-readonly" ? { styleName } : {}),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return { ...col, editable: false as const, styleName: col.styleName ?? "rg-cell-readonly" };
|
return { ...col, editable: false as const, styleName: col.styleName ?? "rg-cell-readonly" };
|
||||||
@@ -219,17 +209,10 @@ const applyPipeTypeStatusEditableColumns = (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 2-3 관종별: verificationResult.prlgWhol → 총계 계(pipeByPrstWhol) */
|
const getManholeLastDataYear = () => {
|
||||||
function remapPipeTypePrlgWholVerification(
|
const lastDataYear = new Date().getFullYear() - 1;
|
||||||
result?: SeweragePipeInputVerificationResult | null,
|
return Math.max(2014, lastDataYear);
|
||||||
): SeweragePipeInputVerificationResult | null | undefined {
|
};
|
||||||
if (!result) return result;
|
|
||||||
const fromAlias = result.prlgWhol;
|
|
||||||
if (!Array.isArray(fromAlias) || fromAlias.length === 0) return result;
|
|
||||||
const existing = result.pipeByPrstWhol;
|
|
||||||
if (Array.isArray(existing) && existing.length > 0) return result;
|
|
||||||
return { ...result, pipeByPrstWhol: fromAlias };
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 관종별 신 응답(yearlyStatList) -> 그리드 y{year}* 필드로 정규화 */
|
/** 관종별 신 응답(yearlyStatList) -> 그리드 y{year}* 필드로 정규화 */
|
||||||
function normalizePipeTypeStatusRow(
|
function normalizePipeTypeStatusRow(
|
||||||
@@ -241,7 +224,6 @@ function normalizePipeTypeStatusRow(
|
|||||||
yearlyStatList,
|
yearlyStatList,
|
||||||
lyngPrlgWhol,
|
lyngPrlgWhol,
|
||||||
dmltnPrlgWhol,
|
dmltnPrlgWhol,
|
||||||
verificationResult,
|
|
||||||
...rest
|
...rest
|
||||||
} = row;
|
} = row;
|
||||||
const yearFields: Record<string, number> = {};
|
const yearFields: Record<string, number> = {};
|
||||||
@@ -269,7 +251,43 @@ function normalizePipeTypeStatusRow(
|
|||||||
lyngPrlg: Number(row.lyngPrlg ?? lyngPrlgWhol ?? 0),
|
lyngPrlg: Number(row.lyngPrlg ?? lyngPrlgWhol ?? 0),
|
||||||
dmltnPrlg: Number(row.dmltnPrlg ?? dmltnPrlgWhol ?? 0),
|
dmltnPrlg: Number(row.dmltnPrlg ?? dmltnPrlgWhol ?? 0),
|
||||||
...yearFields,
|
...yearFields,
|
||||||
verificationResult: remapPipeTypePrlgWholVerification(verificationResult) ?? undefined,
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 맨홀 신 응답(yearlyStats) -> 그리드 yy{14..25}* 필드로 정규화 */
|
||||||
|
function normalizeManholeStatusRow(
|
||||||
|
row: SeweragePipeInputManholeStatusItem,
|
||||||
|
ctpvNm: string,
|
||||||
|
): Record<string, string | number | SeweragePipeInputVerificationResult | undefined> {
|
||||||
|
const maxYy = getManholeLastDataYear() % 100;
|
||||||
|
const { yearlyStats, ...rest } = row;
|
||||||
|
const yearFields: Record<string, number> = {};
|
||||||
|
for (let yy = 14; yy <= maxYy; yy++) {
|
||||||
|
yearFields[`yy${yy}WholMnhlCnt`] = 0;
|
||||||
|
yearFields[`yy${yy}Step1MnhlCnt`] = 0;
|
||||||
|
yearFields[`yy${yy}Step2MnhlCnt`] = 0;
|
||||||
|
yearFields[`yy${yy}Step3MnhlCnt`] = 0;
|
||||||
|
yearFields[`yy${yy}Step4MnhlCnt`] = 0;
|
||||||
|
yearFields[`yy${yy}Step5MnhlCnt`] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const y of yearlyStats ?? []) {
|
||||||
|
const year = Number(y.manhYr);
|
||||||
|
if (!Number.isFinite(year)) continue;
|
||||||
|
const yy = year % 100;
|
||||||
|
if (yy < 14 || yy > maxYy) continue;
|
||||||
|
yearFields[`yy${yy}WholMnhlCnt`] = Number(y.wholMnhlCnt ?? 0);
|
||||||
|
yearFields[`yy${yy}Step1MnhlCnt`] = Number(y.step1MnhlCnt ?? 0);
|
||||||
|
yearFields[`yy${yy}Step2MnhlCnt`] = Number(y.step2MnhlCnt ?? 0);
|
||||||
|
yearFields[`yy${yy}Step3MnhlCnt`] = Number(y.step3MnhlCnt ?? 0);
|
||||||
|
yearFields[`yy${yy}Step4MnhlCnt`] = Number(y.step4MnhlCnt ?? 0);
|
||||||
|
yearFields[`yy${yy}Step5MnhlCnt`] = Number(y.step5MnhlCnt ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
ctpvNm,
|
||||||
|
...rest,
|
||||||
|
...yearFields,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,6 +297,9 @@ type GridRowWithVerification = Record<string, string | number> & {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const REGIONAL_FACT_TAB_KEY = "ST00020001";
|
const REGIONAL_FACT_TAB_KEY = "ST00020001";
|
||||||
|
const SEWAGE_PIPE_COLUMN_GUIDE_TAB_KEYS = Array.from(
|
||||||
|
new Set(SewagePipeInpColumnInfoList.map((tab) => tab.tabKey).filter(Boolean)),
|
||||||
|
);
|
||||||
|
|
||||||
// function hasRegionalFactVerificationErrors(verification?: SeweragePipeInputVerificationResult | null): boolean {
|
// function hasRegionalFactVerificationErrors(verification?: SeweragePipeInputVerificationResult | null): boolean {
|
||||||
// if (!verification) return false;
|
// if (!verification) return false;
|
||||||
@@ -303,11 +324,11 @@ async function waitForImrJobCompleted(
|
|||||||
options?.onProgress?.(Math.max(0, Math.min(100, Number(res.job_prog) || 0)));
|
options?.onProgress?.(Math.max(0, Math.min(100, Number(res.job_prog) || 0)));
|
||||||
if (res.status === "COMPLETED" && Number(res.job_prog) === 100) return;
|
if (res.status === "COMPLETED" && Number(res.job_prog) === 100) return;
|
||||||
if (res.status === "FAILED" || res.status === "ERROR" || res.status === "CANCELLED") {
|
if (res.status === "FAILED" || res.status === "ERROR" || res.status === "CANCELLED") {
|
||||||
throw new Error(res.error_msg || `시계열 검증이 ${res.status} 상태로 종료되었습니다.`);
|
throw new Error(res.error_msg || `IMR 검증이 ${res.status} 상태로 종료되었습니다.`);
|
||||||
}
|
}
|
||||||
await sleep(pollIntervalMs);
|
await sleep(pollIntervalMs);
|
||||||
}
|
}
|
||||||
throw new Error("시계열 검증 완료 대기 시간이 초과되었습니다.");
|
throw new Error("IMR 검증 완료 대기 시간이 초과되었습니다.");
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildRegionalFactSubmitListFromGrid(
|
function buildRegionalFactSubmitListFromGrid(
|
||||||
@@ -329,10 +350,10 @@ function buildRegionalFactSubmitListFromGrid(
|
|||||||
return decimalPlaces > 0 ? parseFloat(num.toFixed(decimalPlaces)) : Math.round(num);
|
return decimalPlaces > 0 ? parseFloat(num.toFixed(decimalPlaces)) : Math.round(num);
|
||||||
};
|
};
|
||||||
return currentData.map((d) => ({
|
return currentData.map((d) => ({
|
||||||
admdstCd: nullableTrimmedString(d.admdstCd),
|
admdstCd: String(d.admdstCd ?? ""),
|
||||||
sggNm: nullableTrimmedString(d.sggNm),
|
sggNm: String(d.sggNm ?? ""),
|
||||||
admdstNm: nullableTrimmedString(d.admdstNm),
|
admdstNm: String(d.admdstNm ?? ""),
|
||||||
goalYr: nullableTrimmedString(d.goalYr),
|
goalYr: String(d.goalYr ?? ""),
|
||||||
wholPplMtncPlanPrlg: formatNumber(d.wholPplMtncPlanPrlg, "wholPplMtncPlanPrlg"),
|
wholPplMtncPlanPrlg: formatNumber(d.wholPplMtncPlanPrlg, "wholPplMtncPlanPrlg"),
|
||||||
wholPlanPrlg: formatNumber(d.wholPlanPrlg, "wholPlanPrlg"),
|
wholPlanPrlg: formatNumber(d.wholPlanPrlg, "wholPlanPrlg"),
|
||||||
wholFcltPrlg: formatNumber(d.wholFcltPrlg, "wholFcltPrlg"),
|
wholFcltPrlg: formatNumber(d.wholFcltPrlg, "wholFcltPrlg"),
|
||||||
@@ -368,7 +389,7 @@ function buildRegionalFactSubmitListFromGrid(
|
|||||||
exlnOtflCnt: formatNumber(d.exlnOtflCnt, "exlnOtflCnt"),
|
exlnOtflCnt: formatNumber(d.exlnOtflCnt, "exlnOtflCnt"),
|
||||||
sewerLdgrEdpPrlg: formatNumber(d.sewerLdgrEdpPrlg, "sewerLdgrEdpPrlg"),
|
sewerLdgrEdpPrlg: formatNumber(d.sewerLdgrEdpPrlg, "sewerLdgrEdpPrlg"),
|
||||||
sewerLdgrEdpRt: formatNumber(d.sewerLdgrEdpRt, "sewerLdgrEdpRt"),
|
sewerLdgrEdpRt: formatNumber(d.sewerLdgrEdpRt, "sewerLdgrEdpRt"),
|
||||||
rmrk: nullableTrimmedString(d.rmrk),
|
rmrk: (d.rmrk as string | null) ?? null,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,14 +416,10 @@ type TabToolbarSnapshot = {
|
|||||||
showActionToolbarCard: boolean;
|
showActionToolbarCard: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const sidoListRef: { current: Sido[] } = { current: [] };
|
|
||||||
|
|
||||||
function buildGugunOkForToolbar(values: SearchFormValues | null): boolean {
|
function buildGugunOkForToolbar(values: SearchFormValues | null): boolean {
|
||||||
return isGugunOkForToolbar(sidoListRef.current, values);
|
return doList.includes(values?.bsnmCd || "")
|
||||||
}
|
? Boolean(values?.gugun && values.gugun !== "ALL")
|
||||||
|
: true;
|
||||||
function buildSubmitOkForToolbar(values: SearchFormValues | null): boolean {
|
|
||||||
return isSubmitOkForToolbar(sidoListRef.current, values);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -420,7 +437,7 @@ function computeTabToolbarSnapshot(
|
|||||||
const gugunOk = buildGugunOkForToolbar(searchContext);
|
const gugunOk = buildGugunOkForToolbar(searchContext);
|
||||||
const enterable = computeTabEnterable(statusInfo, periodEnterable);
|
const enterable = computeTabEnterable(statusInfo, periodEnterable);
|
||||||
const isSubmitted = statusInfo?.laeSbmsnSttsCd === "2";
|
const isSubmitted = statusInfo?.laeSbmsnSttsCd === "2";
|
||||||
const showSaveInToolbar = (enterable || isAdminInfo) && periodEnterable && gugunOk;
|
const showSaveInToolbar = (enterable || isAdminInfo) && gugunOk;
|
||||||
const showEnterableToolbarButtons = enterable && gugunOk;
|
const showEnterableToolbarButtons = enterable && gugunOk;
|
||||||
const showSubmittedInInputPeriodToolbar = isSubmitted && periodEnterable && gugunOk;
|
const showSubmittedInInputPeriodToolbar = isSubmitted && periodEnterable && gugunOk;
|
||||||
const showActionToolbarCard =
|
const showActionToolbarCard =
|
||||||
@@ -434,8 +451,6 @@ function computeTabToolbarSnapshot(
|
|||||||
|
|
||||||
// 하수도 통계 관리 > 02. 하수관로
|
// 하수도 통계 관리 > 02. 하수관로
|
||||||
const SewagePipeInp = () => {
|
const SewagePipeInp = () => {
|
||||||
const { sidoList, isReady } = useSearchConditionSidoList({ isInput: true });
|
|
||||||
sidoListRef.current = sidoList;
|
|
||||||
const [rowDataMap, setRowDataMap] = useState<Map<string, Record<string, string | number>[]>>(new Map());
|
const [rowDataMap, setRowDataMap] = useState<Map<string, Record<string, string | number>[]>>(new Map());
|
||||||
const { setMessage: alert } = useAlertStore((state) => state);
|
const { setMessage: alert } = useAlertStore((state) => state);
|
||||||
const [activeTab, setActiveTab] = useState<string>(SewagePipeInpColumnInfoList[0]?.tabKey ?? "ST00020001");
|
const [activeTab, setActiveTab] = useState<string>(SewagePipeInpColumnInfoList[0]?.tabKey ?? "ST00020001");
|
||||||
@@ -452,9 +467,6 @@ const SewagePipeInp = () => {
|
|||||||
const [isVerificationFailedByTab, setIsVerificationFailedByTab] = useState<
|
const [isVerificationFailedByTab, setIsVerificationFailedByTab] = useState<
|
||||||
Map<string, boolean>
|
Map<string, boolean>
|
||||||
>(new Map());
|
>(new Map());
|
||||||
const [footerVerificationByTab, setFooterVerificationByTab] = useState<
|
|
||||||
Map<string, VerificationResultLikeMap | null>
|
|
||||||
>(new Map());
|
|
||||||
const [verificationHistoryOpen, setVerificationHistoryOpen] = useState(false);
|
const [verificationHistoryOpen, setVerificationHistoryOpen] = useState(false);
|
||||||
const [periodCheckList, setPeriodCheckList] = useState<CheckInputPeriodItem[]>([]);
|
const [periodCheckList, setPeriodCheckList] = useState<CheckInputPeriodItem[]>([]);
|
||||||
/** 탭키별 `engColNm -> columnGuide` 캐시 */
|
/** 탭키별 `engColNm -> columnGuide` 캐시 */
|
||||||
@@ -464,10 +476,7 @@ const SewagePipeInp = () => {
|
|||||||
/** checkInputPeriod — columnInfo useMemo가 입력기간 변경을 반영하도록 state로도 유지 */
|
/** checkInputPeriod — columnInfo useMemo가 입력기간 변경을 반영하도록 state로도 유지 */
|
||||||
const [inputPeriodEnterable, setInputPeriodEnterable] = useState(true);
|
const [inputPeriodEnterable, setInputPeriodEnterable] = useState(true);
|
||||||
/** 탭별 조회 시점의 상단 버튼 노출 조건(해당 탭을 다시 조회할 때만 그 탭 항목 갱신) */
|
/** 탭별 조회 시점의 상단 버튼 노출 조건(해당 탭을 다시 조회할 때만 그 탭 항목 갱신) */
|
||||||
const [_toolbarSnapshotByTab, setToolbarSnapshotByTab] = useState<Map<string, TabToolbarSnapshot>>(
|
const [toolbarSnapshotByTab, setToolbarSnapshotByTab] = useState<Map<string, TabToolbarSnapshot>>(
|
||||||
() => new Map(),
|
|
||||||
);
|
|
||||||
const [searchContextByTab, setSearchContextByTab] = useState<Map<string, SearchFormValues>>(
|
|
||||||
() => new Map(),
|
() => new Map(),
|
||||||
);
|
);
|
||||||
const { confirm } = useConfirm();
|
const { confirm } = useConfirm();
|
||||||
@@ -512,7 +521,6 @@ const SewagePipeInp = () => {
|
|||||||
const inputFocusNonce = useStatisticsInputFocusStore((s) => s.nonce);
|
const inputFocusNonce = useStatisticsInputFocusStore((s) => s.nonce);
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
if (activeTabId !== STATISTICS_INPUT_URL_PATH.SEWAGE_PIPE) return;
|
if (activeTabId !== STATISTICS_INPUT_URL_PATH.SEWAGE_PIPE) return;
|
||||||
if (!isReady) return;
|
|
||||||
const pending = useStatisticsInputFocusStore
|
const pending = useStatisticsInputFocusStore
|
||||||
.getState()
|
.getState()
|
||||||
.takePendingForUrl(STATISTICS_INPUT_URL_PATH.SEWAGE_PIPE);
|
.takePendingForUrl(STATISTICS_INPUT_URL_PATH.SEWAGE_PIPE);
|
||||||
@@ -521,33 +529,43 @@ const SewagePipeInp = () => {
|
|||||||
activeTabRef.current = tabKey;
|
activeTabRef.current = tabKey;
|
||||||
setActiveTab(tabKey);
|
setActiveTab(tabKey);
|
||||||
if (search) {
|
if (search) {
|
||||||
const values = verificationSearchToFormValues(search, sidoList);
|
const values = verificationSearchToFormValues(search);
|
||||||
setVerificationSearchDefaults(values);
|
setVerificationSearchDefaults(values);
|
||||||
postVerificationSearchRef.current = { values, tabKey };
|
postVerificationSearchRef.current = { values, tabKey };
|
||||||
setSearchFormRemountKey((k) => k + 1);
|
setSearchFormRemountKey((k) => k + 1);
|
||||||
}
|
}
|
||||||
}, [activeTabId, inputFocusNonce, isReady, sidoList]);
|
}, [activeTabId, inputFocusNonce]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeTabId !== STATISTICS_INPUT_URL_PATH.SEWAGE_PIPE) return;
|
if (activeTabId !== STATISTICS_INPUT_URL_PATH.SEWAGE_PIPE) return;
|
||||||
const tabKey = activeTab;
|
|
||||||
if (!tabKey) return;
|
|
||||||
if (Object.prototype.hasOwnProperty.call(columnGuidesByTab, tabKey)) return;
|
|
||||||
|
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
void (async () => {
|
void (async () => {
|
||||||
const next = await fetchColumnGuidesRecord(tabKey);
|
const entries = await Promise.all(
|
||||||
if (cancelled) return;
|
SEWAGE_PIPE_COLUMN_GUIDE_TAB_KEYS.map(async (tabKey) => {
|
||||||
setColumnGuidesByTab((prev) =>
|
try {
|
||||||
Object.prototype.hasOwnProperty.call(prev, tabKey)
|
const res = await statisticsApi.getColumnGuides(tabKey);
|
||||||
? prev
|
if (res.status !== "success" || !Array.isArray(res.data)) {
|
||||||
: { ...prev, [tabKey]: next },
|
return [tabKey, {}] as const;
|
||||||
|
}
|
||||||
|
const next: Record<string, string> = {};
|
||||||
|
for (const item of res.data) {
|
||||||
|
const key = item.engColNm?.trim();
|
||||||
|
const guide = item.columnGuide?.trim();
|
||||||
|
if (key && guide) next[key] = guide;
|
||||||
|
}
|
||||||
|
return [tabKey, next] as const;
|
||||||
|
} catch {
|
||||||
|
return [tabKey, {}] as const;
|
||||||
|
}
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
if (cancelled) return;
|
||||||
|
setColumnGuidesByTab(Object.fromEntries(entries));
|
||||||
})();
|
})();
|
||||||
return () => {
|
return () => {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
};
|
};
|
||||||
}, [activeTabId, activeTab, columnGuidesByTab]);
|
}, [activeTabId]);
|
||||||
|
|
||||||
const syncTopStatusIfStillOnTab = (loadedTabKey: string, nextStatsCd: string) => {
|
const syncTopStatusIfStillOnTab = (loadedTabKey: string, nextStatsCd: string) => {
|
||||||
if (loadedTabKey === activeTabRef.current) {
|
if (loadedTabKey === activeTabRef.current) {
|
||||||
@@ -560,13 +578,11 @@ const SewagePipeInp = () => {
|
|||||||
setTabStatusInfoMap(new Map());
|
setTabStatusInfoMap(new Map());
|
||||||
setTabStatsCdMap(new Map());
|
setTabStatsCdMap(new Map());
|
||||||
setIsVerificationFailedByTab(new Map());
|
setIsVerificationFailedByTab(new Map());
|
||||||
setFooterVerificationByTab(new Map());
|
|
||||||
setLastSearchedYear(null);
|
setLastSearchedYear(null);
|
||||||
setLastSearchedValues(null);
|
setLastSearchedValues(null);
|
||||||
setHasSearched(false);
|
setHasSearched(false);
|
||||||
setInputPeriodEnterable(true);
|
setInputPeriodEnterable(true);
|
||||||
setToolbarSnapshotByTab(new Map());
|
setToolbarSnapshotByTab(new Map());
|
||||||
setSearchContextByTab(new Map());
|
|
||||||
searchParamRef.current = null;
|
searchParamRef.current = null;
|
||||||
searchDoneRef.current = false;
|
searchDoneRef.current = false;
|
||||||
lazyTabLoggedRef.current.clear();
|
lazyTabLoggedRef.current.clear();
|
||||||
@@ -590,7 +606,7 @@ const SewagePipeInp = () => {
|
|||||||
});
|
});
|
||||||
return SewagePipeInpColumnInfoList.map((tab: ColumnInfoList) => {
|
return SewagePipeInpColumnInfoList.map((tab: ColumnInfoList) => {
|
||||||
const canEdit =
|
const canEdit =
|
||||||
(computeTabEnterable(tabStatusInfoMap.get(tab.tabKey) ?? null, inputPeriodEnterable) || isAdminInfo) && inputPeriodEnterable;
|
computeTabEnterable(tabStatusInfoMap.get(tab.tabKey) ?? null, inputPeriodEnterable) || isAdminInfo;
|
||||||
const applyEditable = (cols: ColumnConfig[] | undefined) =>
|
const applyEditable = (cols: ColumnConfig[] | undefined) =>
|
||||||
tab.tabKey === PIPE_TYPE_STATUS_TAB_KEY
|
tab.tabKey === PIPE_TYPE_STATUS_TAB_KEY
|
||||||
? applyPipeTypeStatusEditableColumns(
|
? applyPipeTypeStatusEditableColumns(
|
||||||
@@ -598,7 +614,6 @@ const SewagePipeInp = () => {
|
|||||||
canEdit,
|
canEdit,
|
||||||
inputPeriodEnterable,
|
inputPeriodEnterable,
|
||||||
lastSearchedYear,
|
lastSearchedYear,
|
||||||
isAdminInfo,
|
|
||||||
)
|
)
|
||||||
: (cols ?? []).map((col: ColumnConfig) =>
|
: (cols ?? []).map((col: ColumnConfig) =>
|
||||||
canEdit
|
canEdit
|
||||||
@@ -657,13 +672,6 @@ const SewagePipeInp = () => {
|
|||||||
);
|
);
|
||||||
return next;
|
return next;
|
||||||
});
|
});
|
||||||
if (searchContext) {
|
|
||||||
setSearchContextByTab((prev) => {
|
|
||||||
const next = new Map(prev);
|
|
||||||
next.set(tabKey, searchContext);
|
|
||||||
return next;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** mergeIntoExistingMap: true면 기존 맵에 병합(다른 탭 rowData·검색 후 다른 탭 캐시 유지). false면 맵 전체 교체 */
|
/** mergeIntoExistingMap: true면 기존 맵에 병합(다른 탭 rowData·검색 후 다른 탭 캐시 유지). false면 맵 전체 교체 */
|
||||||
@@ -677,7 +685,7 @@ const SewagePipeInp = () => {
|
|||||||
const searchConditionKey = JSON.stringify({
|
const searchConditionKey = JSON.stringify({
|
||||||
statsYr: searchParam.statsYr ?? "",
|
statsYr: searchParam.statsYr ?? "",
|
||||||
ctpvNm: searchParam.ctpvNm ?? "",
|
ctpvNm: searchParam.ctpvNm ?? "",
|
||||||
sggNm: values?.gugun === "ALL" ? "" : (values?.gugun ?? searchParam.sggNm ?? ""),
|
sggNm: searchParam.sggNm ?? "",
|
||||||
sewerBzmnCd: searchParam.sewerBzmnCd ?? "",
|
sewerBzmnCd: searchParam.sewerBzmnCd ?? "",
|
||||||
});
|
});
|
||||||
const applyRowMap = (apply: (m: Map<string, Record<string, string | number>[]>) => void) => {
|
const applyRowMap = (apply: (m: Map<string, Record<string, string | number>[]>) => void) => {
|
||||||
@@ -693,14 +701,12 @@ const SewagePipeInp = () => {
|
|||||||
setRowDataMap(next);
|
setRowDataMap(next);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const filterFetched = <T,>(list: readonly T[] | null | undefined) =>
|
|
||||||
filterBySelectedAdmdstCd(list, sidoListRef.current, values);
|
|
||||||
|
|
||||||
if (tabKey === 'ST00020001') {
|
if (tabKey === 'ST00020001') {
|
||||||
const response = await statisticsInputSewPipeApiService.getRegionalFactStatus(searchParam);
|
const response = await statisticsInputSewPipeApiService.getRegionalFactStatus(searchParam);
|
||||||
if (response.status === 'success') {
|
if (response.status === 'success') {
|
||||||
const commonInfo = response.data.commonInfo;
|
const commonInfo = response.data.commonInfo;
|
||||||
const convertedData = filterFetched(response.data.regionalFactStatusList).map((d) => ({
|
const convertedData = (response.data.regionalFactStatusList ?? []).map((d) => ({
|
||||||
ctpvNm: commonInfo.ctpvNm,
|
ctpvNm: commonInfo.ctpvNm,
|
||||||
...d,
|
...d,
|
||||||
}));
|
}));
|
||||||
@@ -709,9 +715,6 @@ const SewagePipeInp = () => {
|
|||||||
setTabStatsCdMap((prev) => new Map(prev).set(tabKey, commonInfo.statsCd));
|
setTabStatsCdMap((prev) => new Map(prev).set(tabKey, commonInfo.statsCd));
|
||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
);
|
||||||
syncTopStatusIfStillOnTab(tabKey, commonInfo.statsCd);
|
syncTopStatusIfStillOnTab(tabKey, commonInfo.statsCd);
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(values);
|
if (updateLastSearchedValues) setLastSearchedValues(values);
|
||||||
@@ -730,7 +733,7 @@ const SewagePipeInp = () => {
|
|||||||
const response = await statisticsInputSewPipeApiService.getFactInstallStatus(searchParam);
|
const response = await statisticsInputSewPipeApiService.getFactInstallStatus(searchParam);
|
||||||
if (response.status === 'success') {
|
if (response.status === 'success') {
|
||||||
const commonInfo = response.data.commonInfo;
|
const commonInfo = response.data.commonInfo;
|
||||||
const convertedData = filterFetched(response.data.factInstallStatusList).map((d) => ({
|
const convertedData = (response.data.factInstallStatusList ?? []).map((d) => ({
|
||||||
ctpvNm: commonInfo.ctpvNm,
|
ctpvNm: commonInfo.ctpvNm,
|
||||||
...d,
|
...d,
|
||||||
}));
|
}));
|
||||||
@@ -756,9 +759,6 @@ const SewagePipeInp = () => {
|
|||||||
setTabStatsCdMap((prev) => new Map(prev).set(tabKey, commonInfo.statsCd));
|
setTabStatsCdMap((prev) => new Map(prev).set(tabKey, commonInfo.statsCd));
|
||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
);
|
||||||
syncTopStatusIfStillOnTab(tabKey, commonInfo.statsCd);
|
syncTopStatusIfStillOnTab(tabKey, commonInfo.statsCd);
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(values);
|
if (updateLastSearchedValues) setLastSearchedValues(values);
|
||||||
@@ -777,7 +777,7 @@ const SewagePipeInp = () => {
|
|||||||
const response = await statisticsInputSewPipeApiService.getPipeTypeStatus(searchParam);
|
const response = await statisticsInputSewPipeApiService.getPipeTypeStatus(searchParam);
|
||||||
if (response.status === 'success') {
|
if (response.status === 'success') {
|
||||||
const commonInfo = response.data.commonInfo;
|
const commonInfo = response.data.commonInfo;
|
||||||
const convertedData = filterFetched(response.data.pipeTypeStatusList).map((d) =>
|
const convertedData = (response.data.pipeTypeStatusList ?? []).map((d) =>
|
||||||
normalizePipeTypeStatusRow(d, commonInfo.ctpvNm),
|
normalizePipeTypeStatusRow(d, commonInfo.ctpvNm),
|
||||||
);
|
);
|
||||||
applyRowMap((m) => m.set('ST00020003', toGridRows(convertedData)));
|
applyRowMap((m) => m.set('ST00020003', toGridRows(convertedData)));
|
||||||
@@ -785,13 +785,6 @@ const SewagePipeInp = () => {
|
|||||||
setTabStatsCdMap((prev) => new Map(prev).set(tabKey, commonInfo.statsCd));
|
setTabStatsCdMap((prev) => new Map(prev).set(tabKey, commonInfo.statsCd));
|
||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, {
|
|
||||||
verificationResult:
|
|
||||||
remapPipeTypePrlgWholVerification(commonInfo.verificationResult) ??
|
|
||||||
null,
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
syncTopStatusIfStillOnTab(tabKey, commonInfo.statsCd);
|
syncTopStatusIfStillOnTab(tabKey, commonInfo.statsCd);
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(values);
|
if (updateLastSearchedValues) setLastSearchedValues(values);
|
||||||
@@ -810,7 +803,7 @@ const SewagePipeInp = () => {
|
|||||||
const response = await statisticsInputSewPipeApiService.getPipeDiameterStatus(searchParam);
|
const response = await statisticsInputSewPipeApiService.getPipeDiameterStatus(searchParam);
|
||||||
if (response.status === 'success') {
|
if (response.status === 'success') {
|
||||||
const commonInfo = response.data.commonInfo;
|
const commonInfo = response.data.commonInfo;
|
||||||
const convertedData = filterFetched(response.data.pipeDiameterStatusList).map((d) => ({
|
const convertedData = (response.data.pipeDiameterStatusList ?? []).map((d) => ({
|
||||||
ctpvNm: commonInfo.ctpvNm,
|
ctpvNm: commonInfo.ctpvNm,
|
||||||
...d,
|
...d,
|
||||||
}));
|
}));
|
||||||
@@ -819,9 +812,6 @@ const SewagePipeInp = () => {
|
|||||||
setTabStatsCdMap((prev) => new Map(prev).set(tabKey, commonInfo.statsCd));
|
setTabStatsCdMap((prev) => new Map(prev).set(tabKey, commonInfo.statsCd));
|
||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
);
|
||||||
syncTopStatusIfStillOnTab(tabKey, commonInfo.statsCd);
|
syncTopStatusIfStillOnTab(tabKey, commonInfo.statsCd);
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(values);
|
if (updateLastSearchedValues) setLastSearchedValues(values);
|
||||||
@@ -840,18 +830,14 @@ const SewagePipeInp = () => {
|
|||||||
const response = await statisticsInputSewPipeApiService.getManholeStatus(searchParam);
|
const response = await statisticsInputSewPipeApiService.getManholeStatus(searchParam);
|
||||||
if (response.status === 'success') {
|
if (response.status === 'success') {
|
||||||
const commonInfo = response.data.commonInfo;
|
const commonInfo = response.data.commonInfo;
|
||||||
const convertedData = filterFetched(response.data.manholeStatusList).map((d) => ({
|
const convertedData = (response.data.manholeStatusList ?? []).map((d) =>
|
||||||
ctpvNm: commonInfo.ctpvNm,
|
normalizeManholeStatusRow(d, commonInfo.ctpvNm),
|
||||||
...d,
|
);
|
||||||
}));
|
|
||||||
applyRowMap((m) => m.set('ST00020005', toGridRows(convertedData)));
|
applyRowMap((m) => m.set('ST00020005', toGridRows(convertedData)));
|
||||||
setTabStatusInfoMap((prev) => new Map(prev).set(tabKey, response.data.statusInfo));
|
setTabStatusInfoMap((prev) => new Map(prev).set(tabKey, response.data.statusInfo));
|
||||||
setTabStatsCdMap((prev) => new Map(prev).set(tabKey, commonInfo.statsCd));
|
setTabStatsCdMap((prev) => new Map(prev).set(tabKey, commonInfo.statsCd));
|
||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
);
|
||||||
syncTopStatusIfStillOnTab(tabKey, commonInfo.statsCd);
|
syncTopStatusIfStillOnTab(tabKey, commonInfo.statsCd);
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(values);
|
if (updateLastSearchedValues) setLastSearchedValues(values);
|
||||||
@@ -870,10 +856,10 @@ const SewagePipeInp = () => {
|
|||||||
const response = await statisticsInputSewPipeApiService.getConnectionStatus(searchParam);
|
const response = await statisticsInputSewPipeApiService.getConnectionStatus(searchParam);
|
||||||
if (response.status === 'success') {
|
if (response.status === 'success') {
|
||||||
const commonInfo = response.data.commonInfo;
|
const commonInfo = response.data.commonInfo;
|
||||||
const facilityConvertedData = filterFetched(response.data.facilityConnectionList).map((d) => ({
|
const facilityConvertedData = (response.data.facilityConnectionList ?? []).map((d) => ({
|
||||||
...d,
|
...d,
|
||||||
}));
|
}));
|
||||||
const adminConvertedData = filterFetched(response.data.adminAreaConnectionList).map((d) => ({
|
const adminConvertedData = (response.data.adminAreaConnectionList ?? []).map((d) => ({
|
||||||
...d,
|
...d,
|
||||||
ctpvNm: d.ctpvNm || commonInfo.ctpvNm,
|
ctpvNm: d.ctpvNm || commonInfo.ctpvNm,
|
||||||
}));
|
}));
|
||||||
@@ -885,9 +871,6 @@ const SewagePipeInp = () => {
|
|||||||
setTabStatsCdMap((prev) => new Map(prev).set(tabKey, commonInfo.statsCd));
|
setTabStatsCdMap((prev) => new Map(prev).set(tabKey, commonInfo.statsCd));
|
||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
);
|
||||||
syncTopStatusIfStillOnTab(tabKey, commonInfo.statsCd);
|
syncTopStatusIfStillOnTab(tabKey, commonInfo.statsCd);
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(values);
|
if (updateLastSearchedValues) setLastSearchedValues(values);
|
||||||
@@ -941,10 +924,8 @@ const SewagePipeInp = () => {
|
|||||||
setTabStatusInfoMap(new Map());
|
setTabStatusInfoMap(new Map());
|
||||||
setTabStatsCdMap(new Map());
|
setTabStatsCdMap(new Map());
|
||||||
setIsVerificationFailedByTab(new Map());
|
setIsVerificationFailedByTab(new Map());
|
||||||
setFooterVerificationByTab(new Map());
|
|
||||||
setStatsCd("");
|
setStatsCd("");
|
||||||
setToolbarSnapshotByTab(new Map());
|
setToolbarSnapshotByTab(new Map());
|
||||||
setSearchContextByTab(new Map());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lazyTabLoggedRef.current.clear();
|
lazyTabLoggedRef.current.clear();
|
||||||
@@ -1106,8 +1087,9 @@ const SewagePipeInp = () => {
|
|||||||
|
|
||||||
const params: SubmitExceptionRequest = {
|
const params: SubmitExceptionRequest = {
|
||||||
...submitInfo,
|
...submitInfo,
|
||||||
...toInputSearchRegion(sidoListRef.current, searchValues),
|
sewerBzmnCd: searchValues?.bsnmCd ?? "",
|
||||||
ctpvNm: searchValues?.sido ?? "",
|
ctpvNm: searchValues?.sido ?? "",
|
||||||
|
sggNm: searchValues?.gugun === "ALL" ? "" : (searchValues?.gugun ?? ""),
|
||||||
statsYr: searchValues?.year ?? "",
|
statsYr: searchValues?.year ?? "",
|
||||||
userId: userInfo.userUnqId,
|
userId: userInfo.userUnqId,
|
||||||
statsCd: statsCdForTab,
|
statsCd: statsCdForTab,
|
||||||
@@ -1190,7 +1172,8 @@ const SewagePipeInp = () => {
|
|||||||
const submitBase = {
|
const submitBase = {
|
||||||
statsYr: values.year ?? "",
|
statsYr: values.year ?? "",
|
||||||
ctpvNm: values.sido ?? "",
|
ctpvNm: values.sido ?? "",
|
||||||
...toInputSearchRegion(sidoListRef.current, values),
|
sggNm: values.gugun === "ALL" ? "" : (values.gugun ?? ""),
|
||||||
|
sewerBzmnCd: values.bsnmCd ?? "",
|
||||||
userId: userInfo.userUnqId,
|
userId: userInfo.userUnqId,
|
||||||
laePicNm: submitInfo.laePicNm,
|
laePicNm: submitInfo.laePicNm,
|
||||||
laeKbrdrJbgdNm: submitInfo.laeKbrdrJbgdNm,
|
laeKbrdrJbgdNm: submitInfo.laeKbrdrJbgdNm,
|
||||||
@@ -1243,12 +1226,13 @@ const SewagePipeInp = () => {
|
|||||||
return decimalPlaces > 0 ? parseFloat(num.toFixed(decimalPlaces)) : Math.round(num);
|
return decimalPlaces > 0 ? parseFloat(num.toFixed(decimalPlaces)) : Math.round(num);
|
||||||
};
|
};
|
||||||
const submitList = currentData.map((d) => ({
|
const submitList = currentData.map((d) => ({
|
||||||
admdstCd: nullableTrimmedString(d.admdstCd),
|
admdstCd: String(d.admdstCd ?? ""),
|
||||||
sggNm: nullableTrimmedString(d.sggNm),
|
sggNm: String(d.sggNm ?? ""),
|
||||||
admdstNm: nullableTrimmedString(d.admdstNm),
|
admdstNm: String(d.admdstNm ?? ""),
|
||||||
fcltSn: nullableTrimmedString(d.fcltSn),
|
fcltSn: String(d.fcltSn ?? ""),
|
||||||
swtrmtFcltCd: nullableTrimmedString(d.swtrmtFcltCd),
|
swtrmtFcltCd: String(d.swtrmtFcltCd ?? ""),
|
||||||
swtrmtFcltNm: nullableTrimmedString(d.swtrmtFcltNm),
|
swtrmtFcltNm: String(d.swtrmtFcltNm ?? ""),
|
||||||
|
prcsFcltCpct: formatNumber(d.prcsFcltCpct, "prcsFcltCpct"),
|
||||||
prcsZoneArea: formatNumber(d.prcsZoneArea, "prcsZoneArea"),
|
prcsZoneArea: formatNumber(d.prcsZoneArea, "prcsZoneArea"),
|
||||||
cbsysPrcsZoneArea: formatNumber(d.cbsysPrcsZoneArea, "cbsysPrcsZoneArea"),
|
cbsysPrcsZoneArea: formatNumber(d.cbsysPrcsZoneArea, "cbsysPrcsZoneArea"),
|
||||||
sprsysPrcsZoneArea: formatNumber(d.sprsysPrcsZoneArea, "sprsysPrcsZoneArea"),
|
sprsysPrcsZoneArea: formatNumber(d.sprsysPrcsZoneArea, "sprsysPrcsZoneArea"),
|
||||||
@@ -1269,7 +1253,7 @@ const SewagePipeInp = () => {
|
|||||||
cbsysBrchlnPrlg: formatNumber(d.cbsysBrchlnPrlg, "cbsysBrchlnPrlg"),
|
cbsysBrchlnPrlg: formatNumber(d.cbsysBrchlnPrlg, "cbsysBrchlnPrlg"),
|
||||||
exlnBrchlnPrlg: formatNumber(d.exlnBrchlnPrlg, "exlnBrchlnPrlg"),
|
exlnBrchlnPrlg: formatNumber(d.exlnBrchlnPrlg, "exlnBrchlnPrlg"),
|
||||||
drtwBrchlnPrlg: formatNumber(d.drtwBrchlnPrlg, "drtwBrchlnPrlg"),
|
drtwBrchlnPrlg: formatNumber(d.drtwBrchlnPrlg, "drtwBrchlnPrlg"),
|
||||||
rmrk: nullableTrimmedString(d.rmrk),
|
rmrk: String(d.rmrk ?? ""),
|
||||||
}));
|
}));
|
||||||
const requestData: SeweragePipeInputFactInstallStatusSubmitRequest = {
|
const requestData: SeweragePipeInputFactInstallStatusSubmitRequest = {
|
||||||
...submitBase,
|
...submitBase,
|
||||||
@@ -1313,11 +1297,11 @@ const SewagePipeInp = () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
admdstCd: nullableTrimmedString(d.admdstCd),
|
admdstCd: String(d.admdstCd ?? ""),
|
||||||
admdstNm: nullableTrimmedString(d.admdstNm),
|
admdstNm: String(d.admdstNm ?? ""),
|
||||||
pipeSeCd: nullableTrimmedString(d.pipeSeCd),
|
pipeSeCd: String(d.pipeSeCd ?? ""),
|
||||||
yearlyStatList,
|
yearlyStatList,
|
||||||
rmrk: nullableTrimmedString(d.rmrk),
|
rmrk: String(d.rmrk ?? ""),
|
||||||
lyngPrlgWhol: formatNumber(d.lyngPrlg, "lyngPrlg"),
|
lyngPrlgWhol: formatNumber(d.lyngPrlg, "lyngPrlg"),
|
||||||
dmltnPrlgWhol: formatNumber(d.dmltnPrlg, "dmltnPrlg"),
|
dmltnPrlgWhol: formatNumber(d.dmltnPrlg, "dmltnPrlg"),
|
||||||
pipeByPrstWhol: formatNumber(d.pipeByPrstWhol, "pipeByPrstWhol"),
|
pipeByPrstWhol: formatNumber(d.pipeByPrstWhol, "pipeByPrstWhol"),
|
||||||
@@ -1351,7 +1335,7 @@ const SewagePipeInp = () => {
|
|||||||
return decimalPlaces > 0 ? parseFloat(num.toFixed(decimalPlaces)) : Math.round(num);
|
return decimalPlaces > 0 ? parseFloat(num.toFixed(decimalPlaces)) : Math.round(num);
|
||||||
};
|
};
|
||||||
const submitList = currentData.map((d) => ({
|
const submitList = currentData.map((d) => ({
|
||||||
pipeSeCd: nullableTrimmedString(d.pipeSeCd),
|
pipeSeCd: String(d.pipeSeCd ?? ""),
|
||||||
step1PdmtPrlg: formatNumber(d.step1PdmtPrlg, "step1PdmtPrlg"),
|
step1PdmtPrlg: formatNumber(d.step1PdmtPrlg, "step1PdmtPrlg"),
|
||||||
step2PdmtPrlg: formatNumber(d.step2PdmtPrlg, "step2PdmtPrlg"),
|
step2PdmtPrlg: formatNumber(d.step2PdmtPrlg, "step2PdmtPrlg"),
|
||||||
step3PdmtPrlg: formatNumber(d.step3PdmtPrlg, "step3PdmtPrlg"),
|
step3PdmtPrlg: formatNumber(d.step3PdmtPrlg, "step3PdmtPrlg"),
|
||||||
@@ -1359,10 +1343,10 @@ const SewagePipeInp = () => {
|
|||||||
step5PdmtPrlg: formatNumber(d.step5PdmtPrlg, "step5PdmtPrlg"),
|
step5PdmtPrlg: formatNumber(d.step5PdmtPrlg, "step5PdmtPrlg"),
|
||||||
sqrePdmtPrlg: formatNumber(d.sqrePdmtPrlg, "sqrePdmtPrlg"),
|
sqrePdmtPrlg: formatNumber(d.sqrePdmtPrlg, "sqrePdmtPrlg"),
|
||||||
etcPdmtPrlg: formatNumber(d.etcPdmtPrlg, "etcPdmtPrlg"),
|
etcPdmtPrlg: formatNumber(d.etcPdmtPrlg, "etcPdmtPrlg"),
|
||||||
rmrk: nullableTrimmedString(d.rmrk),
|
rmrk: String(d.rmrk ?? ""),
|
||||||
pdmtByTsmWhol: formatNumber(d.pdmtByTsmWhol, "pdmtByTsmWhol"),
|
pdmtByTsmWhol: formatNumber(d.pdmtByTsmWhol, "pdmtByTsmWhol"),
|
||||||
admdstCd: nullableTrimmedString(d.admdstCd),
|
admdstCd: String(d.admdstCd ?? ""),
|
||||||
admdstNm: nullableTrimmedString(d.admdstNm),
|
admdstNm: String(d.admdstNm ?? ""),
|
||||||
}));
|
}));
|
||||||
const requestData: SeweragePipeInputPipeDiameterStatusSubmitRequest = {
|
const requestData: SeweragePipeInputPipeDiameterStatusSubmitRequest = {
|
||||||
...submitBase,
|
...submitBase,
|
||||||
@@ -1391,17 +1375,36 @@ const SewagePipeInp = () => {
|
|||||||
const decimalPlaces = format.match(/\.(\d+)/)?.[1]?.length ?? 0;
|
const decimalPlaces = format.match(/\.(\d+)/)?.[1]?.length ?? 0;
|
||||||
return decimalPlaces > 0 ? parseFloat(num.toFixed(decimalPlaces)) : Math.round(num);
|
return decimalPlaces > 0 ? parseFloat(num.toFixed(decimalPlaces)) : Math.round(num);
|
||||||
};
|
};
|
||||||
const submitList = currentData.map((d) => ({
|
const minYy = 14;
|
||||||
admdstCd: nullableTrimmedString(d.admdstCd),
|
const maxYy = getManholeLastDataYear() % 100;
|
||||||
admdstNm: nullableTrimmedString(d.admdstNm),
|
const submitList = currentData.map((d) => {
|
||||||
emphsMngSeCd: nullableTrimmedString(d.emphsMngSeCd),
|
const yearlyStats: SeweragePipeInputManholeStatusSaveYearlyStatItem[] = [];
|
||||||
frlvlMnhlCnt: formatNumber(d.frlvlMnhlCnt, "frlvlMnhlCnt"),
|
for (let yy = minYy; yy <= maxYy; yy++) {
|
||||||
sclvlMnhlCnt: formatNumber(d.sclvlMnhlCnt, "sclvlMnhlCnt"),
|
const year = 2000 + yy;
|
||||||
thlvlMnhlCnt: formatNumber(d.thlvlMnhlCnt, "thlvlMnhlCnt"),
|
const wholKey = `yy${yy}WholMnhlCnt`;
|
||||||
folvlMnhlCnt: formatNumber(d.folvlMnhlCnt, "folvlMnhlCnt"),
|
const step1Key = `yy${yy}Step1MnhlCnt`;
|
||||||
filvlMnhlCnt: formatNumber(d.filvlMnhlCnt, "filvlMnhlCnt"),
|
const step2Key = `yy${yy}Step2MnhlCnt`;
|
||||||
rmrk: nullableTrimmedString(d.rmrk),
|
const step3Key = `yy${yy}Step3MnhlCnt`;
|
||||||
}));
|
const step4Key = `yy${yy}Step4MnhlCnt`;
|
||||||
|
const step5Key = `yy${yy}Step5MnhlCnt`;
|
||||||
|
yearlyStats.push({
|
||||||
|
manhYr: String(year),
|
||||||
|
wholMnhlCnt: formatNumber(d[wholKey] as string | number | undefined, wholKey),
|
||||||
|
step1MnhlCnt: formatNumber(d[step1Key] as string | number | undefined, step1Key),
|
||||||
|
step2MnhlCnt: formatNumber(d[step2Key] as string | number | undefined, step2Key),
|
||||||
|
step3MnhlCnt: formatNumber(d[step3Key] as string | number | undefined, step3Key),
|
||||||
|
step4MnhlCnt: formatNumber(d[step4Key] as string | number | undefined, step4Key),
|
||||||
|
step5MnhlCnt: formatNumber(d[step5Key] as string | number | undefined, step5Key),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
emphsMngSeCd: String(d.emphsMngSeCd ?? ""),
|
||||||
|
admdstCd: String(d.admdstCd ?? ""),
|
||||||
|
admdstNm: String(d.admdstNm ?? ""),
|
||||||
|
yearlyStats,
|
||||||
|
rmrk: String(d.rmrk ?? ""),
|
||||||
|
};
|
||||||
|
});
|
||||||
const requestData: SeweragePipeInputManholeStatusSubmitRequest = {
|
const requestData: SeweragePipeInputManholeStatusSubmitRequest = {
|
||||||
...submitBase,
|
...submitBase,
|
||||||
submitList,
|
submitList,
|
||||||
@@ -1425,15 +1428,14 @@ const SewagePipeInp = () => {
|
|||||||
|
|
||||||
if (finalStatus === "5") {
|
if (finalStatus === "5") {
|
||||||
setGlobalProgress(50);
|
setGlobalProgress(50);
|
||||||
setGlobalProgressLabel("시계열 검증 진행 중...");
|
setGlobalProgressLabel("IMR 검증 진행 중...");
|
||||||
const imrParam = {
|
const imrParam = {
|
||||||
user_id: userInfo.userUnqId,
|
user_id: userInfo.userUnqId,
|
||||||
sewer_bzmn_cd: values?.bsnmCd ?? '',
|
sewer_bzmn_cd: values.bsnmCd ?? "",
|
||||||
stats_cd: statsCdForTab,
|
stats_cd: statsCdForTab,
|
||||||
stats_yr: values.year ?? "",
|
stats_yr: values.year ?? "",
|
||||||
lae_sbmsn_stts_cd: statusForTab?.laeSbmsnSttsCd === "4" ? "4" : "2",
|
lae_sbmsn_stts_cd: statusForTab?.laeSbmsnSttsCd === "4" ? "4" : "2",
|
||||||
gen_verify_stts_cd: nvpassed ? "1" : "2",
|
gen_verify_stts_cd: nvpassed ? "1" : "2",
|
||||||
hb_pass_yn: response.data?.isHbPassed,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -1459,8 +1461,9 @@ const SewagePipeInp = () => {
|
|||||||
);
|
);
|
||||||
await openVerificationResultDialogIfNeeded(
|
await openVerificationResultDialogIfNeeded(
|
||||||
{
|
{
|
||||||
...toInputSearchRegion(sidoListRef.current, values),
|
sewerBzmnCd: values.bsnmCd ?? "",
|
||||||
ctpvNm: values.sido ?? "",
|
ctpvNm: values.sido ?? "",
|
||||||
|
sggNm: values.gugun === "ALL" ? "" : (values.gugun ?? ""),
|
||||||
statsYr: values.year ?? "",
|
statsYr: values.year ?? "",
|
||||||
statsCd: statsCdForTab,
|
statsCd: statsCdForTab,
|
||||||
},
|
},
|
||||||
@@ -1477,8 +1480,9 @@ const SewagePipeInp = () => {
|
|||||||
);
|
);
|
||||||
await openVerificationResultDialogIfNeeded(
|
await openVerificationResultDialogIfNeeded(
|
||||||
{
|
{
|
||||||
...toInputSearchRegion(sidoListRef.current, values),
|
sewerBzmnCd: values.bsnmCd ?? "",
|
||||||
ctpvNm: values.sido ?? "",
|
ctpvNm: values.sido ?? "",
|
||||||
|
sggNm: values.gugun === "ALL" ? "" : (values.gugun ?? ""),
|
||||||
statsYr: values.year ?? "",
|
statsYr: values.year ?? "",
|
||||||
statsCd: statsCdForTab,
|
statsCd: statsCdForTab,
|
||||||
},
|
},
|
||||||
@@ -1502,8 +1506,9 @@ const SewagePipeInp = () => {
|
|||||||
);
|
);
|
||||||
await openVerificationResultDialogIfNeeded(
|
await openVerificationResultDialogIfNeeded(
|
||||||
{
|
{
|
||||||
...toInputSearchRegion(sidoListRef.current, values),
|
sewerBzmnCd: values.bsnmCd ?? "",
|
||||||
ctpvNm: values.sido ?? "",
|
ctpvNm: values.sido ?? "",
|
||||||
|
sggNm: values.gugun === "ALL" ? "" : (values.gugun ?? ""),
|
||||||
statsYr: values.year ?? "",
|
statsYr: values.year ?? "",
|
||||||
statsCd: statsCdForTab,
|
statsCd: statsCdForTab,
|
||||||
},
|
},
|
||||||
@@ -1530,8 +1535,9 @@ const SewagePipeInp = () => {
|
|||||||
const userInfo = await getUserInfo();
|
const userInfo = await getUserInfo();
|
||||||
|
|
||||||
const requestData: cancelSubmitRequest = {
|
const requestData: cancelSubmitRequest = {
|
||||||
...toInputSearchRegion(sidoListRef.current, searchValues),
|
sewerBzmnCd: searchValues?.bsnmCd ?? '',
|
||||||
ctpvNm: searchValues?.sido ?? '',
|
ctpvNm: searchValues?.sido ?? '',
|
||||||
|
sggNm: searchValues?.gugun === "ALL" ? "" : (searchValues?.gugun ?? ""),
|
||||||
statsYr: searchValues?.year ?? '',
|
statsYr: searchValues?.year ?? '',
|
||||||
mdfrId: userInfo.userUnqId,
|
mdfrId: userInfo.userUnqId,
|
||||||
statsCd: tabStatsCdMap.get(activeTab) ?? statsCd,
|
statsCd: tabStatsCdMap.get(activeTab) ?? statsCd,
|
||||||
@@ -1616,10 +1622,10 @@ const SewagePipeInp = () => {
|
|||||||
const userInfo = await getUserInfo();
|
const userInfo = await getUserInfo();
|
||||||
|
|
||||||
const saveList = currentData.map((d) => ({
|
const saveList = currentData.map((d) => ({
|
||||||
admdstCd: nullableTrimmedString(d.admdstCd),
|
admdstCd: String(d.admdstCd ?? ""),
|
||||||
sggNm: nullableTrimmedString(d.sggNm),
|
sggNm: String(d.sggNm ?? ""),
|
||||||
admdstNm: nullableTrimmedString(d.admdstNm),
|
admdstNm: String(d.admdstNm ?? ""),
|
||||||
goalYr: nullableTrimmedString(d.goalYr),
|
goalYr: String(d.goalYr ?? ""),
|
||||||
wholPplMtncPlanPrlg: formatNumber(d.wholPplMtncPlanPrlg, "wholPplMtncPlanPrlg"),
|
wholPplMtncPlanPrlg: formatNumber(d.wholPplMtncPlanPrlg, "wholPplMtncPlanPrlg"),
|
||||||
wholPlanPrlg: formatNumber(d.wholPlanPrlg, "wholPlanPrlg"),
|
wholPlanPrlg: formatNumber(d.wholPlanPrlg, "wholPlanPrlg"),
|
||||||
wholFcltPrlg: formatNumber(d.wholFcltPrlg, "wholFcltPrlg"),
|
wholFcltPrlg: formatNumber(d.wholFcltPrlg, "wholFcltPrlg"),
|
||||||
@@ -1655,13 +1661,14 @@ const SewagePipeInp = () => {
|
|||||||
exlnOtflCnt: formatNumber(d.exlnOtflCnt, "exlnOtflCnt"),
|
exlnOtflCnt: formatNumber(d.exlnOtflCnt, "exlnOtflCnt"),
|
||||||
sewerLdgrEdpPrlg: formatNumber(d.sewerLdgrEdpPrlg, "sewerLdgrEdpPrlg"),
|
sewerLdgrEdpPrlg: formatNumber(d.sewerLdgrEdpPrlg, "sewerLdgrEdpPrlg"),
|
||||||
sewerLdgrEdpRt: formatNumber(d.sewerLdgrEdpRt, "sewerLdgrEdpRt"),
|
sewerLdgrEdpRt: formatNumber(d.sewerLdgrEdpRt, "sewerLdgrEdpRt"),
|
||||||
rmrk: nullableTrimmedString(d.rmrk),
|
rmrk: (d.rmrk as string | null) ?? null,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const param: SeweragePipeInputRegionalFactStatusSaveRequest = {
|
const param: SeweragePipeInputRegionalFactStatusSaveRequest = {
|
||||||
statsYr: values.year ?? "",
|
statsYr: values.year ?? "",
|
||||||
ctpvNm: values.sido ?? "",
|
ctpvNm: values.sido ?? "",
|
||||||
...toInputSearchRegion(sidoListRef.current, values),
|
sggNm: values.gugun === "ALL" ? "" : (values.gugun ?? ""),
|
||||||
|
sewerBzmnCd: values.bsnmCd ?? "",
|
||||||
userId: userInfo.userUnqId,
|
userId: userInfo.userUnqId,
|
||||||
...(isAdminInfo ? { superAdmin: "superAdmin" } : {}),
|
...(isAdminInfo ? { superAdmin: "superAdmin" } : {}),
|
||||||
saveList,
|
saveList,
|
||||||
@@ -1707,12 +1714,13 @@ const SewagePipeInp = () => {
|
|||||||
const userInfo = await getUserInfo();
|
const userInfo = await getUserInfo();
|
||||||
|
|
||||||
const saveList = currentData.map((d) => ({
|
const saveList = currentData.map((d) => ({
|
||||||
admdstCd: nullableTrimmedString(d.admdstCd),
|
admdstCd: String(d.admdstCd ?? ""),
|
||||||
sggNm: nullableTrimmedString(d.sggNm),
|
sggNm: String(d.sggNm ?? ""),
|
||||||
admdstNm: nullableTrimmedString(d.admdstNm),
|
admdstNm: String(d.admdstNm ?? ""),
|
||||||
fcltSn: nullableTrimmedString(d.fcltSn),
|
fcltSn: String(d.fcltSn ?? ""),
|
||||||
swtrmtFcltCd: nullableTrimmedString(d.swtrmtFcltCd),
|
swtrmtFcltCd: String(d.swtrmtFcltCd ?? ""),
|
||||||
swtrmtFcltNm: nullableTrimmedString(d.swtrmtFcltNm),
|
swtrmtFcltNm: String(d.swtrmtFcltNm ?? ""),
|
||||||
|
prcsFcltCpct: formatNumber(d.prcsFcltCpct, "prcsFcltCpct"),
|
||||||
prcsZoneArea: formatNumber(d.prcsZoneArea, "prcsZoneArea"),
|
prcsZoneArea: formatNumber(d.prcsZoneArea, "prcsZoneArea"),
|
||||||
cbsysPrcsZoneArea: formatNumber(d.cbsysPrcsZoneArea, "cbsysPrcsZoneArea"),
|
cbsysPrcsZoneArea: formatNumber(d.cbsysPrcsZoneArea, "cbsysPrcsZoneArea"),
|
||||||
sprsysPrcsZoneArea: formatNumber(d.sprsysPrcsZoneArea, "sprsysPrcsZoneArea"),
|
sprsysPrcsZoneArea: formatNumber(d.sprsysPrcsZoneArea, "sprsysPrcsZoneArea"),
|
||||||
@@ -1733,13 +1741,14 @@ const SewagePipeInp = () => {
|
|||||||
cbsysBrchlnPrlg: formatNumber(d.cbsysBrchlnPrlg, "cbsysBrchlnPrlg"),
|
cbsysBrchlnPrlg: formatNumber(d.cbsysBrchlnPrlg, "cbsysBrchlnPrlg"),
|
||||||
exlnBrchlnPrlg: formatNumber(d.exlnBrchlnPrlg, "exlnBrchlnPrlg"),
|
exlnBrchlnPrlg: formatNumber(d.exlnBrchlnPrlg, "exlnBrchlnPrlg"),
|
||||||
drtwBrchlnPrlg: formatNumber(d.drtwBrchlnPrlg, "drtwBrchlnPrlg"),
|
drtwBrchlnPrlg: formatNumber(d.drtwBrchlnPrlg, "drtwBrchlnPrlg"),
|
||||||
rmrk: nullableTrimmedString(d.rmrk),
|
rmrk: String(d.rmrk ?? ""),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const param: SeweragePipeInputFactInstallStatusSaveRequest = {
|
const param: SeweragePipeInputFactInstallStatusSaveRequest = {
|
||||||
statsYr: values.year ?? "",
|
statsYr: values.year ?? "",
|
||||||
ctpvNm: values.sido ?? "",
|
ctpvNm: values.sido ?? "",
|
||||||
...toInputSearchRegion(sidoListRef.current, values),
|
sggNm: values.gugun === "ALL" ? "" : (values.gugun ?? ""),
|
||||||
|
sewerBzmnCd: values.bsnmCd ?? "",
|
||||||
userId: userInfo.userUnqId,
|
userId: userInfo.userUnqId,
|
||||||
...(isAdminInfo ? { superAdmin: "superAdmin" } : {}),
|
...(isAdminInfo ? { superAdmin: "superAdmin" } : {}),
|
||||||
saveList,
|
saveList,
|
||||||
@@ -1807,11 +1816,11 @@ const SewagePipeInp = () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
admdstCd: nullableTrimmedString(d.admdstCd),
|
admdstCd: String(d.admdstCd ?? ""),
|
||||||
admdstNm: nullableTrimmedString(d.admdstNm),
|
admdstNm: String(d.admdstNm ?? ""),
|
||||||
pipeSeCd: nullableTrimmedString(d.pipeSeCd),
|
pipeSeCd: String(d.pipeSeCd ?? ""),
|
||||||
yearlyStatList,
|
yearlyStatList,
|
||||||
rmrk: nullableTrimmedString(d.rmrk),
|
rmrk: String(d.rmrk ?? ""),
|
||||||
lyngPrlgWhol: formatNumber(d.lyngPrlg, "lyngPrlg"),
|
lyngPrlgWhol: formatNumber(d.lyngPrlg, "lyngPrlg"),
|
||||||
dmltnPrlgWhol: formatNumber(d.dmltnPrlg, "dmltnPrlg"),
|
dmltnPrlgWhol: formatNumber(d.dmltnPrlg, "dmltnPrlg"),
|
||||||
pipeByPrstWhol: formatNumber(d.pipeByPrstWhol, "pipeByPrstWhol"),
|
pipeByPrstWhol: formatNumber(d.pipeByPrstWhol, "pipeByPrstWhol"),
|
||||||
@@ -1823,7 +1832,8 @@ const SewagePipeInp = () => {
|
|||||||
const param: SeweragePipeInputPipeTypeStatusSaveRequest = {
|
const param: SeweragePipeInputPipeTypeStatusSaveRequest = {
|
||||||
statsYr: values.year ?? "",
|
statsYr: values.year ?? "",
|
||||||
ctpvNm: values.sido ?? "",
|
ctpvNm: values.sido ?? "",
|
||||||
...toInputSearchRegion(sidoListRef.current, values),
|
sggNm: values.gugun === "ALL" ? "" : (values.gugun ?? ""),
|
||||||
|
sewerBzmnCd: values.bsnmCd ?? "",
|
||||||
userId: userInfo.userUnqId,
|
userId: userInfo.userUnqId,
|
||||||
...(isAdminInfo ? { superAdmin: "superAdmin" } : {}),
|
...(isAdminInfo ? { superAdmin: "superAdmin" } : {}),
|
||||||
saveList,
|
saveList,
|
||||||
@@ -1866,7 +1876,7 @@ const SewagePipeInp = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const saveList = currentData.map((d) => ({
|
const saveList = currentData.map((d) => ({
|
||||||
pipeSeCd: nullableTrimmedString(d.pipeSeCd),
|
pipeSeCd: String(d.pipeSeCd ?? ""),
|
||||||
step1PdmtPrlg: formatNumber(d.step1PdmtPrlg, "step1PdmtPrlg"),
|
step1PdmtPrlg: formatNumber(d.step1PdmtPrlg, "step1PdmtPrlg"),
|
||||||
step2PdmtPrlg: formatNumber(d.step2PdmtPrlg, "step2PdmtPrlg"),
|
step2PdmtPrlg: formatNumber(d.step2PdmtPrlg, "step2PdmtPrlg"),
|
||||||
step3PdmtPrlg: formatNumber(d.step3PdmtPrlg, "step3PdmtPrlg"),
|
step3PdmtPrlg: formatNumber(d.step3PdmtPrlg, "step3PdmtPrlg"),
|
||||||
@@ -1874,10 +1884,10 @@ const SewagePipeInp = () => {
|
|||||||
step5PdmtPrlg: formatNumber(d.step5PdmtPrlg, "step5PdmtPrlg"),
|
step5PdmtPrlg: formatNumber(d.step5PdmtPrlg, "step5PdmtPrlg"),
|
||||||
sqrePdmtPrlg: formatNumber(d.sqrePdmtPrlg, "sqrePdmtPrlg"),
|
sqrePdmtPrlg: formatNumber(d.sqrePdmtPrlg, "sqrePdmtPrlg"),
|
||||||
etcPdmtPrlg: formatNumber(d.etcPdmtPrlg, "etcPdmtPrlg"),
|
etcPdmtPrlg: formatNumber(d.etcPdmtPrlg, "etcPdmtPrlg"),
|
||||||
rmrk: nullableTrimmedString(d.rmrk),
|
rmrk: String(d.rmrk ?? ""),
|
||||||
pdmtByTsmWhol: formatNumber(d.pdmtByTsmWhol, "pdmtByTsmWhol"),
|
pdmtByTsmWhol: formatNumber(d.pdmtByTsmWhol, "pdmtByTsmWhol"),
|
||||||
admdstCd: nullableTrimmedString(d.admdstCd),
|
admdstCd: String(d.admdstCd ?? ""),
|
||||||
admdstNm: nullableTrimmedString(d.admdstNm),
|
admdstNm: String(d.admdstNm ?? ""),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const userInfo = await getUserInfo();
|
const userInfo = await getUserInfo();
|
||||||
@@ -1885,7 +1895,8 @@ const SewagePipeInp = () => {
|
|||||||
const param: SeweragePipeInputPipeDiameterStatusSaveRequest = {
|
const param: SeweragePipeInputPipeDiameterStatusSaveRequest = {
|
||||||
statsYr: values.year ?? "",
|
statsYr: values.year ?? "",
|
||||||
ctpvNm: values.sido ?? "",
|
ctpvNm: values.sido ?? "",
|
||||||
...toInputSearchRegion(sidoListRef.current, values),
|
sggNm: values.gugun === "ALL" ? "" : (values.gugun ?? ""),
|
||||||
|
sewerBzmnCd: values.bsnmCd ?? "",
|
||||||
userId: userInfo.userUnqId,
|
userId: userInfo.userUnqId,
|
||||||
...(isAdminInfo ? { superAdmin: "superAdmin" } : {}),
|
...(isAdminInfo ? { superAdmin: "superAdmin" } : {}),
|
||||||
saveList,
|
saveList,
|
||||||
@@ -1927,23 +1938,44 @@ const SewagePipeInp = () => {
|
|||||||
return decimalPlaces > 0 ? parseFloat(num.toFixed(decimalPlaces)) : Math.round(num);
|
return decimalPlaces > 0 ? parseFloat(num.toFixed(decimalPlaces)) : Math.round(num);
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveList = currentData.map((d) => ({
|
const minYy = 14;
|
||||||
admdstCd: nullableTrimmedString(d.admdstCd),
|
const maxYy = getManholeLastDataYear() % 100;
|
||||||
admdstNm: nullableTrimmedString(d.admdstNm),
|
|
||||||
emphsMngSeCd: nullableTrimmedString(d.emphsMngSeCd),
|
const saveList = currentData.map((d) => {
|
||||||
frlvlMnhlCnt: formatNumber(d.frlvlMnhlCnt, "frlvlMnhlCnt"),
|
const yearlyStats: SeweragePipeInputManholeStatusSaveYearlyStatItem[] = [];
|
||||||
sclvlMnhlCnt: formatNumber(d.sclvlMnhlCnt, "sclvlMnhlCnt"),
|
for (let yy = minYy; yy <= maxYy; yy++) {
|
||||||
thlvlMnhlCnt: formatNumber(d.thlvlMnhlCnt, "thlvlMnhlCnt"),
|
const year = 2000 + yy;
|
||||||
folvlMnhlCnt: formatNumber(d.folvlMnhlCnt, "folvlMnhlCnt"),
|
const wholKey = `yy${yy}WholMnhlCnt`;
|
||||||
filvlMnhlCnt: formatNumber(d.filvlMnhlCnt, "filvlMnhlCnt"),
|
const step1Key = `yy${yy}Step1MnhlCnt`;
|
||||||
rmrk: nullableTrimmedString(d.rmrk),
|
const step2Key = `yy${yy}Step2MnhlCnt`;
|
||||||
}));
|
const step3Key = `yy${yy}Step3MnhlCnt`;
|
||||||
|
const step4Key = `yy${yy}Step4MnhlCnt`;
|
||||||
|
const step5Key = `yy${yy}Step5MnhlCnt`;
|
||||||
|
yearlyStats.push({
|
||||||
|
manhYr: String(year),
|
||||||
|
wholMnhlCnt: formatNumber(d[wholKey] as string | number | undefined, wholKey),
|
||||||
|
step1MnhlCnt: formatNumber(d[step1Key] as string | number | undefined, step1Key),
|
||||||
|
step2MnhlCnt: formatNumber(d[step2Key] as string | number | undefined, step2Key),
|
||||||
|
step3MnhlCnt: formatNumber(d[step3Key] as string | number | undefined, step3Key),
|
||||||
|
step4MnhlCnt: formatNumber(d[step4Key] as string | number | undefined, step4Key),
|
||||||
|
step5MnhlCnt: formatNumber(d[step5Key] as string | number | undefined, step5Key),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
emphsMngSeCd: String(d.emphsMngSeCd ?? ""),
|
||||||
|
admdstCd: String(d.admdstCd ?? ""),
|
||||||
|
admdstNm: String(d.admdstNm ?? ""),
|
||||||
|
yearlyStats,
|
||||||
|
rmrk: String(d.rmrk ?? ""),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
const userInfo = await getUserInfo();
|
const userInfo = await getUserInfo();
|
||||||
const param: SeweragePipeInputManholeStatusSaveRequest = {
|
const param: SeweragePipeInputManholeStatusSaveRequest = {
|
||||||
statsYr: values.year ?? "",
|
statsYr: values.year ?? "",
|
||||||
ctpvNm: values.sido ?? "",
|
ctpvNm: values.sido ?? "",
|
||||||
...toInputSearchRegion(sidoListRef.current, values),
|
sggNm: values.gugun === "ALL" ? "" : (values.gugun ?? ""),
|
||||||
|
sewerBzmnCd: values.bsnmCd ?? "",
|
||||||
userId: userInfo.userUnqId,
|
userId: userInfo.userUnqId,
|
||||||
...(isAdminInfo ? { superAdmin: "superAdmin" } : {}),
|
...(isAdminInfo ? { superAdmin: "superAdmin" } : {}),
|
||||||
saveList,
|
saveList,
|
||||||
@@ -1972,12 +2004,12 @@ const SewagePipeInp = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const searchContextForToolbar = searchContextByTab.get(activeTab) ?? lastSearchedValues;
|
const gugunOkOrNotDoList = buildGugunOkForToolbar(lastSearchedValues);
|
||||||
const gugunOkOrNotDoList = buildGugunOkForToolbar(searchContextForToolbar);
|
|
||||||
const submitOk = buildSubmitOkForToolbar(searchContextForToolbar);
|
|
||||||
|
|
||||||
|
const searchContextForToolbar = lastSearchedValues ?? searchValues;
|
||||||
const activeTabStatus = tabStatusInfoMap.get(activeTab) ?? null;
|
const activeTabStatus = tabStatusInfoMap.get(activeTab) ?? null;
|
||||||
const activeTabToolbar =
|
const activeTabToolbar =
|
||||||
|
toolbarSnapshotByTab.get(activeTab) ??
|
||||||
computeTabToolbarSnapshot(
|
computeTabToolbarSnapshot(
|
||||||
activeTabStatus,
|
activeTabStatus,
|
||||||
tabRowDataExists(rowDataMap, activeTab),
|
tabRowDataExists(rowDataMap, activeTab),
|
||||||
@@ -2003,7 +2035,6 @@ const SewagePipeInp = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SearchForm
|
<SearchForm
|
||||||
isInput
|
|
||||||
key={searchFormRemountKey}
|
key={searchFormRemountKey}
|
||||||
defaultValues={verificationSearchDefaults ?? undefined}
|
defaultValues={verificationSearchDefaults ?? undefined}
|
||||||
onSubmit={handleSearch}
|
onSubmit={handleSearch}
|
||||||
@@ -2022,10 +2053,10 @@ const SewagePipeInp = () => {
|
|||||||
{showEnterableToolbarButtons && (
|
{showEnterableToolbarButtons && (
|
||||||
<>
|
<>
|
||||||
{activeTab !== 'ST00020002' && <LastYearDataButton getLastYearDataFunc={() => void getLastYearDataFunc()} />}
|
{activeTab !== 'ST00020002' && <LastYearDataButton getLastYearDataFunc={() => void getLastYearDataFunc()} />}
|
||||||
{submitOk && <SubmitButton submitFunc={() => void submitFunc(false)} />}
|
<SubmitButton submitFunc={() => void submitFunc(false)} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{activeTabStatus?.laeSbmsnSttsCd === "2" && submitOk && (
|
{activeTabStatus?.laeSbmsnSttsCd === "2" && (
|
||||||
<CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />
|
<CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />
|
||||||
)}
|
)}
|
||||||
{showSaveInToolbar && <SaveButton saveFunc={saveFunc} />}
|
{showSaveInToolbar && <SaveButton saveFunc={saveFunc} />}
|
||||||
@@ -2174,9 +2205,7 @@ const SewagePipeInp = () => {
|
|||||||
}}
|
}}
|
||||||
isExcelImport={excelToolbarEnabledForTab}
|
isExcelImport={excelToolbarEnabledForTab}
|
||||||
excelImportSkipNonEditable={
|
excelImportSkipNonEditable={
|
||||||
tabKey === PIPE_TYPE_STATUS_TAB_KEY
|
tabKey === PIPE_TYPE_STATUS_TAB_KEY ? !isAdminInfo : true
|
||||||
? !isAdminInfo
|
|
||||||
: false
|
|
||||||
}
|
}
|
||||||
excelImportSewerBzmnCd={(lastSearchedValues ?? searchValues)?.bsnmCd}
|
excelImportSewerBzmnCd={(lastSearchedValues ?? searchValues)?.bsnmCd}
|
||||||
excelExportSearchContext={toExcelExportSearchContextFromSearchForm(lastSearchedValues ?? searchValues)}
|
excelExportSearchContext={toExcelExportSearchContextFromSearchForm(lastSearchedValues ?? searchValues)}
|
||||||
@@ -2207,9 +2236,6 @@ const SewagePipeInp = () => {
|
|||||||
return hasImr ? "rg-cell-verify-error-imr" : "rg-cell-verify-error";
|
return hasImr ? "rg-cell-verify-error-imr" : "rg-cell-verify-error";
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
footerVerificationResult={
|
|
||||||
footerVerificationByTab.get(tabKey) ?? null
|
|
||||||
}
|
|
||||||
cellTooltipCallback={({ row, fieldName }) => {
|
cellTooltipCallback={({ row, fieldName }) => {
|
||||||
const verification = (row as GridRowWithVerification).verificationResult;
|
const verification = (row as GridRowWithVerification).verificationResult;
|
||||||
if (!verification) return;
|
if (!verification) return;
|
||||||
@@ -2218,7 +2244,7 @@ const SewagePipeInp = () => {
|
|||||||
return errors
|
return errors
|
||||||
.map((e) => {
|
.map((e) => {
|
||||||
const prefix =
|
const prefix =
|
||||||
e.vrfcCd === "IMR" ? "시계열 검증 - " : (e.vrfcCd === "NV" ? "일반검증 - " : "모집단 검증 - ");
|
e.vrfcCd === "IMR" ? "IMR검증 - " : (e.vrfcCd === "NV" ? "일반검증 - " : "HB검증 - ");
|
||||||
const comp = e.compVlCn ?? "";
|
const comp = e.compVlCn ?? "";
|
||||||
const now = e.nowVlCn ?? "";
|
const now = e.nowVlCn ?? "";
|
||||||
return `${prefix}${e.rsnExpln}
|
return `${prefix}${e.rsnExpln}
|
||||||
@@ -2243,8 +2269,9 @@ const SewagePipeInp = () => {
|
|||||||
searchValues?.bsnmCd &&
|
searchValues?.bsnmCd &&
|
||||||
(tabStatsCdMap.get(activeTab) ?? statsCd)
|
(tabStatsCdMap.get(activeTab) ?? statsCd)
|
||||||
? {
|
? {
|
||||||
...toInputSearchRegion(sidoListRef.current, searchValues),
|
sewerBzmnCd: searchValues.bsnmCd,
|
||||||
ctpvNm: searchValues.sido,
|
ctpvNm: searchValues.sido,
|
||||||
|
sggNm: searchValues.gugun === "ALL" ? "" : (searchValues.gugun ?? ""),
|
||||||
statsYr: searchValues.year,
|
statsYr: searchValues.year,
|
||||||
statsCd: tabStatsCdMap.get(activeTab) ?? statsCd,
|
statsCd: tabStatsCdMap.get(activeTab) ?? statsCd,
|
||||||
}
|
}
|
||||||
@@ -2278,8 +2305,9 @@ const SewagePipeInp = () => {
|
|||||||
searchValues?.bsnmCd &&
|
searchValues?.bsnmCd &&
|
||||||
(tabStatsCdMap.get(activeTab) ?? statsCd)
|
(tabStatsCdMap.get(activeTab) ?? statsCd)
|
||||||
? {
|
? {
|
||||||
...toInputSearchRegion(sidoListRef.current, searchValues),
|
sewerBzmnCd: searchValues.bsnmCd,
|
||||||
ctpvNm: searchValues.sido,
|
ctpvNm: searchValues.sido,
|
||||||
|
sggNm: searchValues.gugun === "ALL" ? "" : (searchValues.gugun ?? ""),
|
||||||
statsYr: searchValues.year,
|
statsYr: searchValues.year,
|
||||||
statsCd: tabStatsCdMap.get(activeTab) ?? statsCd,
|
statsCd: tabStatsCdMap.get(activeTab) ?? statsCd,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|||||||
|
|
||||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||||
|
|
||||||
import { useAlertStore, useGlobalProgressStore, useStatisticsInputToolbarGroupGate, useSearchConditionSidoList } from "@/shared/lib";
|
import { useAlertStore, useGlobalProgressStore, useStatisticsInputToolbarGroupGate } from "@/shared/lib";
|
||||||
|
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
||||||
import {
|
import {
|
||||||
STATISTICS_INPUT_URL_PATH,
|
STATISTICS_INPUT_URL_PATH,
|
||||||
verificationSearchToFormValues,
|
verificationSearchToFormValues,
|
||||||
} from "@/shared/lib/stats-cd-input-navigation";
|
} from "@/shared/lib/stats-cd-input-navigation";
|
||||||
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
|
||||||
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
||||||
import { sewagePipeMaintainApiService } from "@/entities/statistics/api/input/statistics-input-sewage-pipe-maintain-service";
|
import { sewagePipeMaintainApiService } from "@/entities/statistics/api/input/statistics-input-sewage-pipe-maintain-service";
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
@@ -27,15 +27,7 @@ import type {
|
|||||||
cancelSubmitRequest,
|
cancelSubmitRequest,
|
||||||
ImrStatusResponse,
|
ImrStatusResponse,
|
||||||
SewerageStatusInfo,
|
SewerageStatusInfo,
|
||||||
Sido,
|
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
} from "@/entities/statistics/model/statistics-interface";
|
||||||
import {
|
|
||||||
filterBySelectedAdmdstCd,
|
|
||||||
isGugunOkForToolbar,
|
|
||||||
isSubmitOkForToolbar,
|
|
||||||
toInputSearchRegion,
|
|
||||||
} from "@/entities/statistics";
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
LoadingWithAnimation,
|
LoadingWithAnimation,
|
||||||
Tabs,
|
Tabs,
|
||||||
@@ -54,23 +46,18 @@ import SaveButton from "@/components/button/SaveButton";
|
|||||||
import SubmitButton from "@/components/button/SumitButton";
|
import SubmitButton from "@/components/button/SumitButton";
|
||||||
import VerificationResultButton from "@/components/button/VerificationResultButton";
|
import VerificationResultButton from "@/components/button/VerificationResultButton";
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
import { openVerificationResultDialogIfNeeded } from "@/components/module/post-submit-verification-results";
|
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
|
import { openVerificationResultDialogIfNeeded } from "@/components/module/post-submit-verification-results";
|
||||||
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
||||||
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
||||||
import type { ColumnInfo } from "@/components/type/DataGrid.type";
|
import type { ColumnInfo } from "@/components/type/DataGrid.type";
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
|
import { doList } from "@/components/util/column/input/DoList";
|
||||||
import { PipeDredgingStatusInpColumn } from "@/components/util/column/input/sewagePipeMaintain/PipeDredgingStatusInpColumn";
|
import { PipeDredgingStatusInpColumn } from "@/components/util/column/input/sewagePipeMaintain/PipeDredgingStatusInpColumn";
|
||||||
import { RepairStatusInpColumn } from "@/components/util/column/input/sewagePipeMaintain/RepairStatusInpColumn";
|
import { RepairStatusInpColumn } from "@/components/util/column/input/sewagePipeMaintain/RepairStatusInpColumn";
|
||||||
import { fetchColumnGuidesRecord } from "@/components/util/grid/columnGuides";
|
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
import { patchVerificationFailedByTab } from "@/components/util/input/verification-failed-flag";
|
||||||
import {
|
|
||||||
patchFooterVerificationByTab,
|
|
||||||
patchVerificationFailedByTab,
|
|
||||||
} from "@/components/util/input/verification-failed-flag";
|
|
||||||
import type { VerificationResultLikeMap } from "@/components/util/input/verification-result-display";
|
|
||||||
import { nullableTrimmedString } from "@/components/util/input/nullableString";
|
|
||||||
import { useAdminStore } from "@/store/admin-store";
|
import { useAdminStore } from "@/store/admin-store";
|
||||||
import { useStatisticsInputFocusStore } from "@/store/statistics-input-focus-store";
|
import { useStatisticsInputFocusStore } from "@/store/statistics-input-focus-store";
|
||||||
import { useTabStore } from "@/store/tab-store";
|
import { useTabStore } from "@/store/tab-store";
|
||||||
@@ -81,8 +68,9 @@ function buildSewagePipeMaintainSearchParam(
|
|||||||
): SewagePipeMaintainRequestParams {
|
): SewagePipeMaintainRequestParams {
|
||||||
return {
|
return {
|
||||||
statsYr: values.year,
|
statsYr: values.year,
|
||||||
|
sewerBzmnCd: values.bsnmCd,
|
||||||
ctpvNm: values.sido,
|
ctpvNm: values.sido,
|
||||||
...toInputSearchRegion(sidoListRef.current, values),
|
sggNm: values.gugun === "ALL" ? "" : values.gugun,
|
||||||
...(overrides?.mode ? { mode: overrides.mode } : {}),
|
...(overrides?.mode ? { mode: overrides.mode } : {}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -94,6 +82,12 @@ const SewagePipeMaintainInpTabList = [
|
|||||||
|
|
||||||
const firstTabKey = RepairStatusInpColumn.tabKey;
|
const firstTabKey = RepairStatusInpColumn.tabKey;
|
||||||
|
|
||||||
|
const SEWAGE_PIPE_MAINTAIN_COLUMN_GUIDE_TAB_KEYS = Array.from(
|
||||||
|
new Set(
|
||||||
|
SewagePipeMaintainInpTabList.map((tab) => tab.tabKey).filter(Boolean),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
const toGridColumnInfo = (tab: (typeof SewagePipeMaintainInpTabList)[number]): ColumnInfo => ({
|
const toGridColumnInfo = (tab: (typeof SewagePipeMaintainInpTabList)[number]): ColumnInfo => ({
|
||||||
columns: tab.columns ?? [],
|
columns: tab.columns ?? [],
|
||||||
columnLayout: tab.columnLayout ?? [],
|
columnLayout: tab.columnLayout ?? [],
|
||||||
@@ -122,14 +116,10 @@ const computeTabEnterable = (
|
|||||||
return periodEnterable;
|
return periodEnterable;
|
||||||
};
|
};
|
||||||
|
|
||||||
const sidoListRef: { current: Sido[] } = { current: [] };
|
|
||||||
|
|
||||||
function buildGugunOkForToolbar(values: SearchFormValues | null): boolean {
|
function buildGugunOkForToolbar(values: SearchFormValues | null): boolean {
|
||||||
return isGugunOkForToolbar(sidoListRef.current, values);
|
return doList.includes(values?.bsnmCd || "")
|
||||||
}
|
? Boolean(values?.gugun && values.gugun !== "ALL")
|
||||||
|
: true;
|
||||||
function buildSubmitOkForToolbar(values: SearchFormValues | null): boolean {
|
|
||||||
return isSubmitOkForToolbar(sidoListRef.current, values);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeTabToolbarSnapshot(
|
function computeTabToolbarSnapshot(
|
||||||
@@ -143,7 +133,7 @@ function computeTabToolbarSnapshot(
|
|||||||
const gugunOk = buildGugunOkForToolbar(searchContext);
|
const gugunOk = buildGugunOkForToolbar(searchContext);
|
||||||
const enterable = computeTabEnterable(statusInfo, periodEnterable);
|
const enterable = computeTabEnterable(statusInfo, periodEnterable);
|
||||||
const isSubmitted = statusInfo?.laeSbmsnSttsCd === "2";
|
const isSubmitted = statusInfo?.laeSbmsnSttsCd === "2";
|
||||||
const showSaveInToolbar = (enterable || isAdminInfo) && periodEnterable && gugunOk;
|
const showSaveInToolbar = (enterable || isAdminInfo) && gugunOk;
|
||||||
const showEnterableToolbarButtons = enterable && gugunOk;
|
const showEnterableToolbarButtons = enterable && gugunOk;
|
||||||
const showSubmittedInInputPeriodToolbar =
|
const showSubmittedInInputPeriodToolbar =
|
||||||
isSubmitted && periodEnterable && gugunOk;
|
isSubmitted && periodEnterable && gugunOk;
|
||||||
@@ -164,6 +154,17 @@ function tabRowDataExists(
|
|||||||
return Array.isArray(rows) && rows.length > 0;
|
return Array.isArray(rows) && rows.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeGridString(value: unknown): string {
|
||||||
|
if (value === null || value === undefined) return "";
|
||||||
|
return typeof value === "string" ? value : String(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeGridRmrk(value: unknown): string | null {
|
||||||
|
if (value === null || value === undefined) return null;
|
||||||
|
const s = typeof value === "string" ? value : String(value);
|
||||||
|
return s.trim() === "" ? null : s;
|
||||||
|
}
|
||||||
|
|
||||||
const sleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms));
|
const sleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms));
|
||||||
|
|
||||||
async function waitForImrJobCompleted(
|
async function waitForImrJobCompleted(
|
||||||
@@ -182,11 +183,11 @@ async function waitForImrJobCompleted(
|
|||||||
options?.onProgress?.(Math.max(0, Math.min(100, Number(res.job_prog) || 0)));
|
options?.onProgress?.(Math.max(0, Math.min(100, Number(res.job_prog) || 0)));
|
||||||
if (res.status === "COMPLETED" && Number(res.job_prog) === 100) return;
|
if (res.status === "COMPLETED" && Number(res.job_prog) === 100) return;
|
||||||
if (res.status === "FAILED" || res.status === "ERROR" || res.status === "CANCELLED") {
|
if (res.status === "FAILED" || res.status === "ERROR" || res.status === "CANCELLED") {
|
||||||
throw new Error(res.error_msg || `시계열 검증이 ${res.status} 상태로 종료되었습니다.`);
|
throw new Error(res.error_msg || `IMR 검증이 ${res.status} 상태로 종료되었습니다.`);
|
||||||
}
|
}
|
||||||
await sleep(pollIntervalMs);
|
await sleep(pollIntervalMs);
|
||||||
}
|
}
|
||||||
throw new Error("시계열 검증 완료 대기 시간이 초과되었습니다.");
|
throw new Error("IMR 검증 완료 대기 시간이 초과되었습니다.");
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildColumnFormatNumber(
|
function buildColumnFormatNumber(
|
||||||
@@ -217,9 +218,9 @@ function buildRepairRowList(
|
|||||||
const formatNumber = buildColumnFormatNumber(RepairStatusInpColumn.columns);
|
const formatNumber = buildColumnFormatNumber(RepairStatusInpColumn.columns);
|
||||||
|
|
||||||
return currentData.map((d) => ({
|
return currentData.map((d) => ({
|
||||||
admdstCd: nullableTrimmedString(d.admdstCd),
|
admdstCd: normalizeGridString(d.admdstCd),
|
||||||
sggNm: nullableTrimmedString(d.sggNm),
|
sggNm: normalizeGridString(d.sggNm),
|
||||||
admdstNm: nullableTrimmedString(d.admdstNm),
|
admdstNm: normalizeGridString(d.admdstNm),
|
||||||
mendngWhol: formatNumber(d.mendngWhol, "mendngWhol"),
|
mendngWhol: formatNumber(d.mendngWhol, "mendngWhol"),
|
||||||
cbsysMendngPrlg: formatNumber(d.cbsysMendngPrlg, "cbsysMendngPrlg"),
|
cbsysMendngPrlg: formatNumber(d.cbsysMendngPrlg, "cbsysMendngPrlg"),
|
||||||
sprsysExlnPrlg: formatNumber(d.sprsysExlnPrlg, "sprsysExlnPrlg"),
|
sprsysExlnPrlg: formatNumber(d.sprsysExlnPrlg, "sprsysExlnPrlg"),
|
||||||
@@ -235,7 +236,7 @@ function buildRepairRowList(
|
|||||||
stofcbrCnt: formatNumber(d.stofcbrCnt, "stofcbrCnt"),
|
stofcbrCnt: formatNumber(d.stofcbrCnt, "stofcbrCnt"),
|
||||||
otflCnt: formatNumber(d.otflCnt, "otflCnt"),
|
otflCnt: formatNumber(d.otflCnt, "otflCnt"),
|
||||||
cctvExmnPrlg: formatNumber(d.cctvExmnPrlg, "cctvExmnPrlg"),
|
cctvExmnPrlg: formatNumber(d.cctvExmnPrlg, "cctvExmnPrlg"),
|
||||||
rmrk: nullableTrimmedString(d.rmrk),
|
rmrk: normalizeGridRmrk(d.rmrk),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,9 +246,9 @@ function buildDredgingRowList(
|
|||||||
const formatNumber = buildColumnFormatNumber(PipeDredgingStatusInpColumn.columns);
|
const formatNumber = buildColumnFormatNumber(PipeDredgingStatusInpColumn.columns);
|
||||||
|
|
||||||
return currentData.map((d) => ({
|
return currentData.map((d) => ({
|
||||||
admdstCd: nullableTrimmedString(d.admdstCd),
|
admdstCd: normalizeGridString(d.admdstCd),
|
||||||
sggNm: nullableTrimmedString(d.sggNm),
|
sggNm: normalizeGridString(d.sggNm),
|
||||||
admdstNm: nullableTrimmedString(d.admdstNm),
|
admdstNm: normalizeGridString(d.admdstNm),
|
||||||
wholFcltPrlg: formatNumber(d.wholFcltPrlg, "wholFcltPrlg"),
|
wholFcltPrlg: formatNumber(d.wholFcltPrlg, "wholFcltPrlg"),
|
||||||
wholSwagePpl: formatNumber(d.wholSwagePpl, "wholSwagePpl"),
|
wholSwagePpl: formatNumber(d.wholSwagePpl, "wholSwagePpl"),
|
||||||
cbsysPplPrlg: formatNumber(d.cbsysPplPrlg, "cbsysPplPrlg"),
|
cbsysPplPrlg: formatNumber(d.cbsysPplPrlg, "cbsysPplPrlg"),
|
||||||
@@ -267,14 +268,12 @@ function buildDredgingRowList(
|
|||||||
oceanEmsnQnt: formatNumber(d.oceanEmsnQnt, "oceanEmsnQnt"),
|
oceanEmsnQnt: formatNumber(d.oceanEmsnQnt, "oceanEmsnQnt"),
|
||||||
rcycQnt: formatNumber(d.rcycQnt, "rcycQnt"),
|
rcycQnt: formatNumber(d.rcycQnt, "rcycQnt"),
|
||||||
etcQnt: formatNumber(d.etcQnt, "etcQnt"),
|
etcQnt: formatNumber(d.etcQnt, "etcQnt"),
|
||||||
rmrk: nullableTrimmedString(d.rmrk),
|
rmrk: normalizeGridRmrk(d.rmrk),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 하수도 통계 관리 > 03. 하수관로 유지관리
|
// 하수도 통계 관리 > 03. 하수관로 유지관리
|
||||||
const SewagePipeMaintainInp = () => {
|
const SewagePipeMaintainInp = () => {
|
||||||
const { sidoList, isReady } = useSearchConditionSidoList({ isInput: true });
|
|
||||||
sidoListRef.current = sidoList;
|
|
||||||
const { setMessage: alert } = useAlertStore((state) => state);
|
const { setMessage: alert } = useAlertStore((state) => state);
|
||||||
const { isAdminInfo } = useAdminStore();
|
const { isAdminInfo } = useAdminStore();
|
||||||
const toolbarGroupAllowed = useStatisticsInputToolbarGroupGate();
|
const toolbarGroupAllowed = useStatisticsInputToolbarGroupGate();
|
||||||
@@ -297,15 +296,9 @@ const SewagePipeMaintainInp = () => {
|
|||||||
const [isVerificationFailedByTab, setIsVerificationFailedByTab] = useState<
|
const [isVerificationFailedByTab, setIsVerificationFailedByTab] = useState<
|
||||||
Map<string, boolean>
|
Map<string, boolean>
|
||||||
>(new Map());
|
>(new Map());
|
||||||
const [footerVerificationByTab, setFooterVerificationByTab] = useState<
|
const [toolbarSnapshotByTab, setToolbarSnapshotByTab] = useState<
|
||||||
Map<string, VerificationResultLikeMap | null>
|
|
||||||
>(new Map());
|
|
||||||
const [_toolbarSnapshotByTab, setToolbarSnapshotByTab] = useState<
|
|
||||||
Map<string, TabToolbarSnapshot>
|
Map<string, TabToolbarSnapshot>
|
||||||
>(new Map());
|
>(new Map());
|
||||||
const [searchContextByTab, setSearchContextByTab] = useState<Map<string, SearchFormValues>>(
|
|
||||||
() => new Map(),
|
|
||||||
);
|
|
||||||
const [verificationHistoryOpen, setVerificationHistoryOpen] = useState(false);
|
const [verificationHistoryOpen, setVerificationHistoryOpen] = useState(false);
|
||||||
const [verificationResultDialogOpen, setVerificationResultDialogOpen] = useState(false);
|
const [verificationResultDialogOpen, setVerificationResultDialogOpen] = useState(false);
|
||||||
const [showSubmitDialog, setShowSubmitDialog] = useState(false);
|
const [showSubmitDialog, setShowSubmitDialog] = useState(false);
|
||||||
@@ -335,7 +328,6 @@ const SewagePipeMaintainInp = () => {
|
|||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
if (activeTabId !== STATISTICS_INPUT_URL_PATH.SEWAGE_PIPE_MAINTAIN) return;
|
if (activeTabId !== STATISTICS_INPUT_URL_PATH.SEWAGE_PIPE_MAINTAIN) return;
|
||||||
if (!isReady) return;
|
|
||||||
const pending = useStatisticsInputFocusStore
|
const pending = useStatisticsInputFocusStore
|
||||||
.getState()
|
.getState()
|
||||||
.takePendingForUrl(STATISTICS_INPUT_URL_PATH.SEWAGE_PIPE_MAINTAIN);
|
.takePendingForUrl(STATISTICS_INPUT_URL_PATH.SEWAGE_PIPE_MAINTAIN);
|
||||||
@@ -343,34 +335,43 @@ const SewagePipeMaintainInp = () => {
|
|||||||
const { tabKey, search } = pending;
|
const { tabKey, search } = pending;
|
||||||
setActiveTab(tabKey);
|
setActiveTab(tabKey);
|
||||||
if (search) {
|
if (search) {
|
||||||
const values = verificationSearchToFormValues(search, sidoList);
|
const values = verificationSearchToFormValues(search);
|
||||||
setVerificationSearchDefaults(values);
|
setVerificationSearchDefaults(values);
|
||||||
postVerificationSearchRef.current = { values, tabKey };
|
postVerificationSearchRef.current = { values, tabKey };
|
||||||
setSearchFormRemountKey((k) => k + 1);
|
setSearchFormRemountKey((k) => k + 1);
|
||||||
}
|
}
|
||||||
}, [activeTabId, inputFocusNonce, isReady, sidoList]);
|
}, [activeTabId, inputFocusNonce]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeTabId !== STATISTICS_INPUT_URL_PATH.SEWAGE_PIPE_MAINTAIN) return;
|
if (activeTabId !== STATISTICS_INPUT_URL_PATH.SEWAGE_PIPE_MAINTAIN) return;
|
||||||
const tabKey = activeTab;
|
|
||||||
if (!tabKey) return;
|
|
||||||
if (Object.prototype.hasOwnProperty.call(columnGuidesByTab, tabKey)) return;
|
|
||||||
const statsCd = tabKey;
|
|
||||||
|
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
void (async () => {
|
void (async () => {
|
||||||
const next = await fetchColumnGuidesRecord(statsCd);
|
const entries = await Promise.all(
|
||||||
if (cancelled) return;
|
SEWAGE_PIPE_MAINTAIN_COLUMN_GUIDE_TAB_KEYS.map(async (tabKey) => {
|
||||||
setColumnGuidesByTab((prev) =>
|
try {
|
||||||
Object.prototype.hasOwnProperty.call(prev, tabKey)
|
const res = await statisticsApi.getColumnGuides(tabKey);
|
||||||
? prev
|
if (res.status !== "success" || !Array.isArray(res.data)) {
|
||||||
: { ...prev, [tabKey]: next },
|
return [tabKey, {}] as const;
|
||||||
|
}
|
||||||
|
const next: Record<string, string> = {};
|
||||||
|
for (const item of res.data) {
|
||||||
|
const key = item.engColNm?.trim();
|
||||||
|
const guide = item.columnGuide?.trim();
|
||||||
|
if (key && guide) next[key] = guide;
|
||||||
|
}
|
||||||
|
return [tabKey, next] as const;
|
||||||
|
} catch {
|
||||||
|
return [tabKey, {}] as const;
|
||||||
|
}
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
if (cancelled) return;
|
||||||
|
setColumnGuidesByTab(Object.fromEntries(entries));
|
||||||
})();
|
})();
|
||||||
return () => {
|
return () => {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
};
|
};
|
||||||
}, [activeTabId, activeTab, columnGuidesByTab]);
|
}, [activeTabId]);
|
||||||
|
|
||||||
const commitToolbarSnapshotForLoadedTab = (
|
const commitToolbarSnapshotForLoadedTab = (
|
||||||
tabKey: string,
|
tabKey: string,
|
||||||
@@ -393,13 +394,6 @@ const SewagePipeMaintainInp = () => {
|
|||||||
);
|
);
|
||||||
return next;
|
return next;
|
||||||
});
|
});
|
||||||
if (searchContext) {
|
|
||||||
setSearchContextByTab((prev) => {
|
|
||||||
const next = new Map(prev);
|
|
||||||
next.set(tabKey, searchContext);
|
|
||||||
return next;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const applyRowMap = (
|
const applyRowMap = (
|
||||||
@@ -441,11 +435,7 @@ const SewagePipeMaintainInp = () => {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const { commonInfo, statusInfo, repairStatusList } = response.data;
|
const { commonInfo, statusInfo, repairStatusList } = response.data;
|
||||||
const convertedData = filterBySelectedAdmdstCd(
|
const convertedData = (repairStatusList ?? []).map((d) => ({
|
||||||
repairStatusList ?? [],
|
|
||||||
sidoListRef.current,
|
|
||||||
searchContext,
|
|
||||||
).map((d) => ({
|
|
||||||
ctpvNm: commonInfo.ctpvNm,
|
ctpvNm: commonInfo.ctpvNm,
|
||||||
...d,
|
...d,
|
||||||
}));
|
}));
|
||||||
@@ -459,9 +449,6 @@ const SewagePipeMaintainInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
|
||||||
if (updateLastSearchedValues) {
|
if (updateLastSearchedValues) {
|
||||||
setLastSearchedValues(searchContext);
|
setLastSearchedValues(searchContext);
|
||||||
}
|
}
|
||||||
@@ -484,11 +471,7 @@ const SewagePipeMaintainInp = () => {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const { commonInfo, statusInfo, pipeDredgingStatusList } = response.data;
|
const { commonInfo, statusInfo, pipeDredgingStatusList } = response.data;
|
||||||
const convertedData = filterBySelectedAdmdstCd(
|
const convertedData = (pipeDredgingStatusList ?? []).map((d) => ({
|
||||||
pipeDredgingStatusList ?? [],
|
|
||||||
sidoListRef.current,
|
|
||||||
searchContext,
|
|
||||||
).map((d) => ({
|
|
||||||
ctpvNm: commonInfo.ctpvNm,
|
ctpvNm: commonInfo.ctpvNm,
|
||||||
...d,
|
...d,
|
||||||
}));
|
}));
|
||||||
@@ -502,9 +485,6 @@ const SewagePipeMaintainInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
|
||||||
if (updateLastSearchedValues) {
|
if (updateLastSearchedValues) {
|
||||||
setLastSearchedValues(searchContext);
|
setLastSearchedValues(searchContext);
|
||||||
}
|
}
|
||||||
@@ -612,7 +592,11 @@ const SewagePipeMaintainInp = () => {
|
|||||||
const submitInfoBase = {
|
const submitInfoBase = {
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
laePicNm: submitInfo.laePicNm,
|
laePicNm: submitInfo.laePicNm,
|
||||||
laeKbrdrJbgdNm: submitInfo.laeKbrdrJbgdNm,
|
laeKbrdrJbgdNm: submitInfo.laeKbrdrJbgdNm,
|
||||||
laeKbrdrDeptNm: submitInfo.laeKbrdrDeptNm,
|
laeKbrdrDeptNm: submitInfo.laeKbrdrDeptNm,
|
||||||
@@ -624,8 +608,12 @@ const SewagePipeMaintainInp = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const verificationQuery = {
|
const verificationQuery = {
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
statsCd: statsCdForTab,
|
statsCd: statsCdForTab,
|
||||||
};
|
};
|
||||||
@@ -667,15 +655,14 @@ const SewagePipeMaintainInp = () => {
|
|||||||
|
|
||||||
if (finalStatus === "5") {
|
if (finalStatus === "5") {
|
||||||
setGlobalProgress(50);
|
setGlobalProgress(50);
|
||||||
setGlobalProgressLabel("시계열 검증 진행 중...");
|
setGlobalProgressLabel("IMR 검증 진행 중...");
|
||||||
const imrParam = {
|
const imrParam = {
|
||||||
user_id: userInfo.userUnqId,
|
user_id: userInfo.userUnqId,
|
||||||
sewer_bzmn_cd: lastSearchedValues?.bsnmCd ?? "",
|
sewer_bzmn_cd: lastSearchedValues.bsnmCd ?? "",
|
||||||
stats_cd: statsCdForTab,
|
stats_cd: statsCdForTab,
|
||||||
stats_yr: lastSearchedValues.year ?? "",
|
stats_yr: lastSearchedValues.year ?? "",
|
||||||
lae_sbmsn_stts_cd: activeTabStatus?.laeSbmsnSttsCd === "4" ? "4" : "2",
|
lae_sbmsn_stts_cd: activeTabStatus?.laeSbmsnSttsCd === "4" ? "4" : "2",
|
||||||
gen_verify_stts_cd: nvpassed ? "1" : "2",
|
gen_verify_stts_cd: nvpassed ? "1" : "2",
|
||||||
hb_pass_yn: response.data?.isHbPassed,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -751,7 +738,11 @@ const SewagePipeMaintainInp = () => {
|
|||||||
const baseRequest = {
|
const baseRequest = {
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -853,8 +844,12 @@ const SewagePipeMaintainInp = () => {
|
|||||||
const statsCdForTab = tabStatsCdMap.get(tabKey) ?? tabKey;
|
const statsCdForTab = tabStatsCdMap.get(tabKey) ?? tabKey;
|
||||||
|
|
||||||
const requestData: cancelSubmitRequest = {
|
const requestData: cancelSubmitRequest = {
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
mdfrId: userInfo.userUnqId,
|
mdfrId: userInfo.userUnqId,
|
||||||
statsCd: statsCdForTab,
|
statsCd: statsCdForTab,
|
||||||
@@ -885,9 +880,7 @@ const SewagePipeMaintainInp = () => {
|
|||||||
setTabStatusInfoMap(new Map());
|
setTabStatusInfoMap(new Map());
|
||||||
setTabStatsCdMap(new Map());
|
setTabStatsCdMap(new Map());
|
||||||
setIsVerificationFailedByTab(new Map());
|
setIsVerificationFailedByTab(new Map());
|
||||||
setFooterVerificationByTab(new Map());
|
|
||||||
setToolbarSnapshotByTab(new Map());
|
setToolbarSnapshotByTab(new Map());
|
||||||
setSearchContextByTab(new Map());
|
|
||||||
setActiveTab(firstTabKey);
|
setActiveTab(firstTabKey);
|
||||||
setLastSearchedValues(null);
|
setLastSearchedValues(null);
|
||||||
setHasSearched(false);
|
setHasSearched(false);
|
||||||
@@ -932,9 +925,7 @@ const SewagePipeMaintainInp = () => {
|
|||||||
setTabStatusInfoMap(new Map());
|
setTabStatusInfoMap(new Map());
|
||||||
setTabStatsCdMap(new Map());
|
setTabStatsCdMap(new Map());
|
||||||
setIsVerificationFailedByTab(new Map());
|
setIsVerificationFailedByTab(new Map());
|
||||||
setFooterVerificationByTab(new Map());
|
|
||||||
setToolbarSnapshotByTab(new Map());
|
setToolbarSnapshotByTab(new Map());
|
||||||
setSearchContextByTab(new Map());
|
|
||||||
activeTabRef.current = firstTabKey;
|
activeTabRef.current = firstTabKey;
|
||||||
setActiveTab(firstTabKey);
|
setActiveTab(firstTabKey);
|
||||||
}
|
}
|
||||||
@@ -1009,10 +1000,10 @@ const SewagePipeMaintainInp = () => {
|
|||||||
for (const tab of SewagePipeMaintainInpTabList) {
|
for (const tab of SewagePipeMaintainInpTabList) {
|
||||||
const tabKey = tab.tabKey;
|
const tabKey = tab.tabKey;
|
||||||
const canEdit =
|
const canEdit =
|
||||||
(computeTabEnterable(
|
computeTabEnterable(
|
||||||
tabStatusInfoMap.get(tabKey) ?? null,
|
tabStatusInfoMap.get(tabKey) ?? null,
|
||||||
inputPeriodEnterable,
|
inputPeriodEnterable,
|
||||||
) || isAdminInfo) && inputPeriodEnterable;
|
) || isAdminInfo;
|
||||||
const rawColumns = tab.columns ?? [];
|
const rawColumns = tab.columns ?? [];
|
||||||
const base = canEdit
|
const base = canEdit
|
||||||
? rawColumns
|
? rawColumns
|
||||||
@@ -1030,9 +1021,10 @@ const SewagePipeMaintainInp = () => {
|
|||||||
return map;
|
return map;
|
||||||
}, [tabStatusInfoMap, inputPeriodEnterable, isAdminInfo, columnGuidesByTab]);
|
}, [tabStatusInfoMap, inputPeriodEnterable, isAdminInfo, columnGuidesByTab]);
|
||||||
|
|
||||||
const searchContextForToolbar = searchContextByTab.get(activeTab) ?? lastSearchedValues;
|
const searchContextForToolbar = lastSearchedValues ?? searchValues;
|
||||||
const activeTabStatus = tabStatusInfoMap.get(activeTab) ?? null;
|
const activeTabStatus = tabStatusInfoMap.get(activeTab) ?? null;
|
||||||
const activeTabToolbar =
|
const activeTabToolbar =
|
||||||
|
toolbarSnapshotByTab.get(activeTab) ??
|
||||||
computeTabToolbarSnapshot(
|
computeTabToolbarSnapshot(
|
||||||
activeTabStatus,
|
activeTabStatus,
|
||||||
tabRowDataExists(rowDataMap, activeTab),
|
tabRowDataExists(rowDataMap, activeTab),
|
||||||
@@ -1053,7 +1045,6 @@ const SewagePipeMaintainInp = () => {
|
|||||||
baseShowEnterableToolbarButtons && toolbarGroupAllowed;
|
baseShowEnterableToolbarButtons && toolbarGroupAllowed;
|
||||||
const showActionToolbarCard =
|
const showActionToolbarCard =
|
||||||
baseShowActionToolbarCard && toolbarGroupAllowed;
|
baseShowActionToolbarCard && toolbarGroupAllowed;
|
||||||
const submitOk = buildSubmitOkForToolbar(searchContextForToolbar);
|
|
||||||
|
|
||||||
const openVerificationHistoryDialog = () => {
|
const openVerificationHistoryDialog = () => {
|
||||||
const ctx = lastSearchedValues ?? searchValues;
|
const ctx = lastSearchedValues ?? searchValues;
|
||||||
@@ -1070,8 +1061,9 @@ const SewagePipeMaintainInp = () => {
|
|||||||
const statsCd = tabStatsCdMap.get(activeTab);
|
const statsCd = tabStatsCdMap.get(activeTab);
|
||||||
if (!ctx?.year || !ctx?.sido || !ctx?.bsnmCd || !statsCd) return null;
|
if (!ctx?.year || !ctx?.sido || !ctx?.bsnmCd || !statsCd) return null;
|
||||||
return {
|
return {
|
||||||
...toInputSearchRegion(sidoListRef.current, ctx),
|
sewerBzmnCd: ctx.bsnmCd,
|
||||||
ctpvNm: ctx.sido,
|
ctpvNm: ctx.sido,
|
||||||
|
sggNm: ctx.gugun === "ALL" ? "" : (ctx.gugun ?? ""),
|
||||||
statsYr: ctx.year,
|
statsYr: ctx.year,
|
||||||
statsCd,
|
statsCd,
|
||||||
};
|
};
|
||||||
@@ -1107,7 +1099,7 @@ const SewagePipeMaintainInp = () => {
|
|||||||
return errors
|
return errors
|
||||||
.map((e) => {
|
.map((e) => {
|
||||||
const prefix =
|
const prefix =
|
||||||
e.vrfcCd === "IMR" ? "시계열 검증 - " : e.vrfcCd === "NV" ? "일반검증 - " : "모집단 검증 - ";
|
e.vrfcCd === "IMR" ? "IMR검증 - " : e.vrfcCd === "NV" ? "일반검증 - " : "HB검증 - ";
|
||||||
return `${prefix}${e.rsnExpln}(검증 기준값: ${e.compVlCn} / 현재 입력값: ${e.nowVlCn})`;
|
return `${prefix}${e.rsnExpln}(검증 기준값: ${e.compVlCn} / 현재 입력값: ${e.nowVlCn})`;
|
||||||
})
|
})
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
@@ -1119,7 +1111,6 @@ const SewagePipeMaintainInp = () => {
|
|||||||
<>
|
<>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<SearchForm
|
<SearchForm
|
||||||
isInput
|
|
||||||
key={searchFormRemountKey}
|
key={searchFormRemountKey}
|
||||||
defaultValues={verificationSearchDefaults ?? undefined}
|
defaultValues={verificationSearchDefaults ?? undefined}
|
||||||
onSubmit={handleSearch}
|
onSubmit={handleSearch}
|
||||||
@@ -1140,10 +1131,10 @@ const SewagePipeMaintainInp = () => {
|
|||||||
<LastYearDataButton
|
<LastYearDataButton
|
||||||
getLastYearDataFunc={() => void getLastYearDataFunc()}
|
getLastYearDataFunc={() => void getLastYearDataFunc()}
|
||||||
/>
|
/>
|
||||||
{submitOk && <SubmitButton submitFunc={submitFunc} />}
|
<SubmitButton submitFunc={submitFunc} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{activeTabStatus?.laeSbmsnSttsCd === "2" && submitOk && (
|
{activeTabStatus?.laeSbmsnSttsCd === "2" && (
|
||||||
<CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />
|
<CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />
|
||||||
)}
|
)}
|
||||||
{showSaveInToolbar && <SaveButton saveFunc={saveFunc} />}
|
{showSaveInToolbar && <SaveButton saveFunc={saveFunc} />}
|
||||||
@@ -1175,11 +1166,11 @@ const SewagePipeMaintainInp = () => {
|
|||||||
const tabKey = info.tabKey;
|
const tabKey = info.tabKey;
|
||||||
const rowData = rowDataMap.get(tabKey) ?? [];
|
const rowData = rowDataMap.get(tabKey) ?? [];
|
||||||
const tabEnterableForGrid =
|
const tabEnterableForGrid =
|
||||||
(computeTabEnterable(
|
computeTabEnterable(
|
||||||
tabStatusInfoMap.get(tabKey) ?? null,
|
tabStatusInfoMap.get(tabKey) ?? null,
|
||||||
inputPeriodEnterable,
|
inputPeriodEnterable,
|
||||||
) || isAdminInfo) && inputPeriodEnterable;
|
) || isAdminInfo;
|
||||||
const gugunOk = buildGugunOkForToolbar(searchContextForToolbar);
|
const gugunOk = buildGugunOkForToolbar(lastSearchedValues);
|
||||||
const tabStatusInfo = tabStatusInfoMap.get(tabKey) ?? null;
|
const tabStatusInfo = tabStatusInfoMap.get(tabKey) ?? null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -1191,7 +1182,6 @@ const SewagePipeMaintainInp = () => {
|
|||||||
toGridColumnInfo(info)
|
toGridColumnInfo(info)
|
||||||
}
|
}
|
||||||
excelExportFileSuffix={info.tabLabel || tabKey}
|
excelExportFileSuffix={info.tabLabel || tabKey}
|
||||||
fixedColumns={info.fixedColumns}
|
|
||||||
rowData={rowData}
|
rowData={rowData}
|
||||||
setRowData={(updater) => {
|
setRowData={(updater) => {
|
||||||
setRowDataMap((prev) => {
|
setRowDataMap((prev) => {
|
||||||
@@ -1216,9 +1206,6 @@ const SewagePipeMaintainInp = () => {
|
|||||||
excelImportSewerBzmnCd={(lastSearchedValues ?? searchValues)?.bsnmCd}
|
excelImportSewerBzmnCd={(lastSearchedValues ?? searchValues)?.bsnmCd}
|
||||||
excelExportSearchContext={toExcelExportSearchContextFromSearchForm(lastSearchedValues ?? searchValues)}
|
excelExportSearchContext={toExcelExportSearchContextFromSearchForm(lastSearchedValues ?? searchValues)}
|
||||||
cellStyleCallback={verificationCellStyle}
|
cellStyleCallback={verificationCellStyle}
|
||||||
footerVerificationResult={
|
|
||||||
footerVerificationByTab.get(tabKey) ?? null
|
|
||||||
}
|
|
||||||
cellTooltipCallback={verificationCellTooltip}
|
cellTooltipCallback={verificationCellTooltip}
|
||||||
getGridDataRef={
|
getGridDataRef={
|
||||||
activeTab === tabKey ? getGridDataRef : undefined
|
activeTab === tabKey ? getGridDataRef : undefined
|
||||||
|
|||||||
@@ -1,59 +1,21 @@
|
|||||||
import {
|
import {
|
||||||
type Dispatch,
|
|
||||||
type SetStateAction,
|
|
||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
useMemo,
|
useMemo,
|
||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
|
type Dispatch,
|
||||||
|
type SetStateAction,
|
||||||
} from "react";
|
} from "react";
|
||||||
|
|
||||||
import { flushSync } from "react-dom";
|
import { flushSync } from "react-dom";
|
||||||
|
|
||||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||||
|
|
||||||
import { ValueType } from "realgrid";
|
import { ValueType } from "realgrid";
|
||||||
import type { RealGridReact } from "realgrid-react";
|
import type { RealGridReact } from "realgrid-react";
|
||||||
|
|
||||||
import { useAlertStore, useGlobalProgressStore, useStatisticsInputToolbarGroupGate, useSearchConditionSidoList } from "@/shared/lib";
|
|
||||||
import { STATISTICS_INPUT_URL_PATH } from "@/shared/lib/stats-cd-input-navigation";
|
|
||||||
import { useStatisticsInputPendingNavigation } from "@/shared/lib/use-statistics-input-pending-navigation";
|
|
||||||
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
|
||||||
import { nullableTrimmedString } from "@/components/util/input/nullableString";
|
|
||||||
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
|
||||||
import { statisticsInputSewageReservoirPumpApi } from "@/entities/statistics/api/input/statistics-input-sewage-reservoir-pump-service";
|
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
|
||||||
import {
|
|
||||||
type RainfallPumpStationItem,
|
|
||||||
type RainfallPumpStationSaveItem,
|
|
||||||
SEWAGE_RESERVOIR_STATS_CD,
|
|
||||||
type SewageReservoirItem,
|
|
||||||
type SewageReservoirRequestParams,
|
|
||||||
type SewageReservoirSaveItem,
|
|
||||||
type SewageReservoirVerificationResult,
|
|
||||||
} from "@/entities/statistics/model/input/statistics-input-sewage-reservoir-pump-interface";
|
|
||||||
import { isInputPeriodCurrent } from "@/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface";
|
|
||||||
import type { StatisticsInputSubmitInfoFormData } from "@/entities/statistics/model/statistics-input-submit-info-schema";
|
|
||||||
import type {
|
|
||||||
ApiResponse,
|
|
||||||
cancelSubmitRequest,
|
|
||||||
ImrStatusResponse,
|
|
||||||
SewerageStatusInfo,
|
|
||||||
Sgg,
|
|
||||||
Sido,
|
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
|
||||||
import {
|
|
||||||
filterBySelectedAdmdstCd,
|
|
||||||
isGugunOkForToolbar,
|
|
||||||
isSubmitOkForToolbar,
|
|
||||||
resolveNoApplicableForRequest,
|
|
||||||
toInputSearchRegion,
|
|
||||||
} from "@/entities/statistics";
|
|
||||||
|
|
||||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||||
|
|
||||||
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
|
||||||
|
|
||||||
import SubmitDailog from "./SubmitDailog";
|
|
||||||
|
|
||||||
import AddArticleButton from "@/components/button/AddArticleButton";
|
import AddArticleButton from "@/components/button/AddArticleButton";
|
||||||
import CancelSubmitButton from "@/components/button/CancelSubmitButton";
|
import CancelSubmitButton from "@/components/button/CancelSubmitButton";
|
||||||
import DeleteArticleButton from "@/components/button/DeleteArticleButton";
|
import DeleteArticleButton from "@/components/button/DeleteArticleButton";
|
||||||
@@ -63,10 +25,13 @@ import SaveButton from "@/components/button/SaveButton";
|
|||||||
import SubmitButton from "@/components/button/SumitButton";
|
import SubmitButton from "@/components/button/SumitButton";
|
||||||
import VerificationResultButton from "@/components/button/VerificationResultButton";
|
import VerificationResultButton from "@/components/button/VerificationResultButton";
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
|
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
||||||
import { openVerificationResultDialogIfNeeded } from "@/components/module/post-submit-verification-results";
|
import { openVerificationResultDialogIfNeeded } from "@/components/module/post-submit-verification-results";
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
||||||
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
||||||
|
import SubmitDailog from "./SubmitDailog";
|
||||||
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
import type {
|
import type {
|
||||||
CellStyleCallbackParams,
|
CellStyleCallbackParams,
|
||||||
CellTooltipCallbackParams,
|
CellTooltipCallbackParams,
|
||||||
@@ -74,24 +39,44 @@ import type {
|
|||||||
ColumnInfo,
|
ColumnInfo,
|
||||||
ColumnInfoList,
|
ColumnInfoList,
|
||||||
} from "@/components/type/DataGrid.type";
|
} from "@/components/type/DataGrid.type";
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
import { doList } from "@/components/util/column/input/DoList";
|
||||||
import { RainfallPumpStationInpColumn } from "@/components/util/column/input/sewageReservoirPump/RainfallPumpStationInpColumn";
|
import { RainfallPumpStationInpColumn } from "@/components/util/column/input/sewageReservoirPump/RainfallPumpStationInpColumn";
|
||||||
import { SewageReservoirInpColumn } from "@/components/util/column/input/sewageReservoirPump/SewageReservoirInpColumn";
|
import { SewageReservoirInpColumn } from "@/components/util/column/input/sewageReservoirPump/SewageReservoirInpColumn";
|
||||||
import { fetchColumnGuidesRecord } from "@/components/util/grid/columnGuides";
|
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
|
import { patchVerificationFailedByTab } from "@/components/util/input/verification-failed-flag";
|
||||||
import {
|
import {
|
||||||
formatCompactYmdForGrid,
|
formatCompactYmdForGrid,
|
||||||
normalizeOxYnValue,
|
normalizeOxYnValue,
|
||||||
toCompactYmdOrNull,
|
toCompactYmdOrNull,
|
||||||
} from "@/components/util/grid/ymdFormat";
|
} from "@/components/util/grid/ymdFormat";
|
||||||
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
import { statisticsInputSewageReservoirPumpApi } from "@/entities/statistics/api/input/statistics-input-sewage-reservoir-pump-service";
|
||||||
|
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
||||||
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
|
import { isInputPeriodCurrent } from "@/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface";
|
||||||
import {
|
import {
|
||||||
patchFooterVerificationByTab,
|
SEWAGE_RESERVOIR_STATS_CD,
|
||||||
patchVerificationFailedByTab,
|
type SewageReservoirItem,
|
||||||
} from "@/components/util/input/verification-failed-flag";
|
type SewageReservoirRequestParams,
|
||||||
import type { VerificationResultLikeMap } from "@/components/util/input/verification-result-display";
|
type SewageReservoirSaveItem,
|
||||||
|
type RainfallPumpStationItem,
|
||||||
|
type RainfallPumpStationSaveItem,
|
||||||
|
type SewageReservoirVerificationResult,
|
||||||
|
} from "@/entities/statistics/model/input/statistics-input-sewage-reservoir-pump-interface";
|
||||||
|
import type { StatisticsInputSubmitInfoFormData } from "@/entities/statistics/model/statistics-input-submit-info-schema";
|
||||||
|
import type {
|
||||||
|
ApiResponse,
|
||||||
|
cancelSubmitRequest,
|
||||||
|
ImrStatusResponse,
|
||||||
|
Sgg,
|
||||||
|
SewerageStatusInfo,
|
||||||
|
} from "@/entities/statistics/model/statistics-interface";
|
||||||
|
import { useAlertStore, useGlobalProgressStore, useStatisticsInputToolbarGroupGate } from "@/shared/lib";
|
||||||
|
import { STATISTICS_INPUT_URL_PATH } from "@/shared/lib/stats-cd-input-navigation";
|
||||||
|
import { useStatisticsInputPendingNavigation } from "@/shared/lib/use-statistics-input-pending-navigation";
|
||||||
|
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
||||||
import { useAdminStore } from "@/store/admin-store";
|
import { useAdminStore } from "@/store/admin-store";
|
||||||
import { useTabStore } from "@/store/tab-store";
|
|
||||||
|
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
||||||
|
|
||||||
const SewageReservoirPumpInpTabList = [
|
const SewageReservoirPumpInpTabList = [
|
||||||
SewageReservoirInpColumn,
|
SewageReservoirInpColumn,
|
||||||
@@ -107,6 +92,12 @@ const firstTabKey = SewageReservoirPumpInpTabList[0]?.tabKey ?? SEWAGE_RESERVOIR
|
|||||||
const rainfallPumpTabKey =
|
const rainfallPumpTabKey =
|
||||||
RainfallPumpStationInpColumn.tabKey ?? "rainfallPumpStationInp";
|
RainfallPumpStationInpColumn.tabKey ?? "rainfallPumpStationInp";
|
||||||
|
|
||||||
|
const SEWAGE_RESERVOIR_PUMP_COLUMN_GUIDE_TAB_KEYS = Array.from(
|
||||||
|
new Set(
|
||||||
|
SewageReservoirPumpInpTabList.map((tab) => tab.tabKey).filter(Boolean),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
const SEWAGE_RESERVOIR_FACILITY_NAME_GUIDE_MESSAGE =
|
const SEWAGE_RESERVOIR_FACILITY_NAME_GUIDE_MESSAGE =
|
||||||
"하수저류시설 등록시 하수저류시설명이 동일할 경우 같은 데이터로 분류됩니다.\n\n" +
|
"하수저류시설 등록시 하수저류시설명이 동일할 경우 같은 데이터로 분류됩니다.\n\n" +
|
||||||
"하수저류시설명이 동일 할 경우 구분을 위해 하수저류시설 1, 하수저류시설 2 형태로 구분하여 주시길 바랍니다.";
|
"하수저류시설명이 동일 할 경우 구분을 위해 하수저류시설 1, 하수저류시설 2 형태로 구분하여 주시길 바랍니다.";
|
||||||
@@ -134,22 +125,10 @@ const computeTabEnterable = (
|
|||||||
return periodEnterable;
|
return periodEnterable;
|
||||||
};
|
};
|
||||||
|
|
||||||
const sidoListRef: { current: Sido[] } = { current: [] };
|
|
||||||
|
|
||||||
function buildGugunOkForToolbar(values: SearchFormValues | null): boolean {
|
function buildGugunOkForToolbar(values: SearchFormValues | null): boolean {
|
||||||
return isGugunOkForToolbar(sidoListRef.current, values);
|
return doList.includes(values?.bsnmCd || "")
|
||||||
}
|
? Boolean(values?.gugun && values.gugun !== "ALL")
|
||||||
|
: true;
|
||||||
function buildSubmitOkForToolbar(values: SearchFormValues | null): boolean {
|
|
||||||
return isSubmitOkForToolbar(sidoListRef.current, values);
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildNoApplicableForRequest(
|
|
||||||
values: SearchFormValues | null,
|
|
||||||
checked: boolean,
|
|
||||||
isSaveListEmpty: boolean,
|
|
||||||
): boolean {
|
|
||||||
return resolveNoApplicableForRequest(sidoListRef.current, values, checked, isSaveListEmpty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeTabToolbarSnapshot(
|
function computeTabToolbarSnapshot(
|
||||||
@@ -163,7 +142,7 @@ function computeTabToolbarSnapshot(
|
|||||||
const gugunOk = buildGugunOkForToolbar(searchContext);
|
const gugunOk = buildGugunOkForToolbar(searchContext);
|
||||||
const enterable = computeTabEnterable(statusInfo, periodEnterable);
|
const enterable = computeTabEnterable(statusInfo, periodEnterable);
|
||||||
const isSubmitted = statusInfo?.laeSbmsnSttsCd === "2";
|
const isSubmitted = statusInfo?.laeSbmsnSttsCd === "2";
|
||||||
const showSaveInToolbar = (enterable || isAdminInfo) && periodEnterable && gugunOk;
|
const showSaveInToolbar = (enterable || isAdminInfo) && gugunOk;
|
||||||
const showEnterableToolbarButtons = enterable && gugunOk;
|
const showEnterableToolbarButtons = enterable && gugunOk;
|
||||||
const showSubmittedInInputPeriodToolbar =
|
const showSubmittedInInputPeriodToolbar =
|
||||||
isSubmitted && periodEnterable && gugunOk;
|
isSubmitted && periodEnterable && gugunOk;
|
||||||
@@ -191,8 +170,9 @@ function buildSewageReservoirSearchParam(
|
|||||||
const fcltNm = values.fctName?.trim();
|
const fcltNm = values.fctName?.trim();
|
||||||
return {
|
return {
|
||||||
statsYr: values.year,
|
statsYr: values.year,
|
||||||
|
sewerBzmnCd: values.bsnmCd,
|
||||||
ctpvNm: values.sido,
|
ctpvNm: values.sido,
|
||||||
...toInputSearchRegion(sidoListRef.current, values),
|
sggNm: values.gugun === "ALL" ? "" : values.gugun,
|
||||||
...(fcltNm ? { fcltNm } : {}),
|
...(fcltNm ? { fcltNm } : {}),
|
||||||
...(overrides?.mode ? { mode: overrides.mode } : {}),
|
...(overrides?.mode ? { mode: overrides.mode } : {}),
|
||||||
};
|
};
|
||||||
@@ -265,9 +245,8 @@ function buildSggNmColumn(
|
|||||||
function mapSewageReservoirListToGridRows(
|
function mapSewageReservoirListToGridRows(
|
||||||
list: SewageReservoirItem[],
|
list: SewageReservoirItem[],
|
||||||
ctpvNm: string,
|
ctpvNm: string,
|
||||||
values?: SearchFormValues | null,
|
|
||||||
): GridRowWithVerification[] {
|
): GridRowWithVerification[] {
|
||||||
return filterBySelectedAdmdstCd(list, sidoListRef.current, values).map((item) => {
|
return list.map((item) => {
|
||||||
const row = toGridRows([
|
const row = toGridRows([
|
||||||
{
|
{
|
||||||
...item,
|
...item,
|
||||||
@@ -285,6 +264,13 @@ function mapSewageReservoirListToGridRows(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function nullableTrimmedString(
|
||||||
|
value: string | number | null | undefined,
|
||||||
|
): string | null {
|
||||||
|
const s = String(value ?? "").trim();
|
||||||
|
return s === "" ? null : s;
|
||||||
|
}
|
||||||
|
|
||||||
function toGridNumber(value: string | number | null | undefined): number {
|
function toGridNumber(value: string | number | null | undefined): number {
|
||||||
const n = Number(value);
|
const n = Number(value);
|
||||||
return Number.isFinite(n) ? n : 0;
|
return Number.isFinite(n) ? n : 0;
|
||||||
@@ -304,13 +290,13 @@ function toPumpDmtrExpln(value: string | number | null | undefined): number {
|
|||||||
function resolveSewageReservoirAdmdst(
|
function resolveSewageReservoirAdmdst(
|
||||||
sggNm: string,
|
sggNm: string,
|
||||||
sggOptions: Sgg[],
|
sggOptions: Sgg[],
|
||||||
): { admdstCd: string | null; admdstNm: string | null } {
|
): { admdstCd: string; admdstNm: string } {
|
||||||
const trimmed = sggNm.trim();
|
const trimmed = sggNm.trim();
|
||||||
const matched = sggOptions.find((s) => s.gugun === trimmed);
|
const matched = sggOptions.find((s) => s.gugun === trimmed);
|
||||||
if (matched) {
|
if (matched) {
|
||||||
return { admdstCd: matched.bsnmCd, admdstNm: matched.gugun };
|
return { admdstCd: matched.bsnmCd, admdstNm: matched.gugun };
|
||||||
}
|
}
|
||||||
return { admdstCd: null, admdstNm: nullableTrimmedString(trimmed) };
|
return { admdstCd: "", admdstNm: trimmed };
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 그리드 행 → ST00040001 저장/삭제 API 항목 */
|
/** 그리드 행 → ST00040001 저장/삭제 API 항목 */
|
||||||
@@ -322,18 +308,19 @@ function buildSewageReservoirSaveItem(
|
|||||||
String(row.sggNm ?? ""),
|
String(row.sggNm ?? ""),
|
||||||
sggOptions,
|
sggOptions,
|
||||||
);
|
);
|
||||||
|
const fcltSn = String(row.fcltSn ?? "").trim();
|
||||||
return {
|
return {
|
||||||
admdstCd,
|
admdstCd,
|
||||||
admdstNm,
|
admdstNm,
|
||||||
// 항목 추가 직후 저장(신규) — 그리드 fcltSn 없음 → API에는 "1"
|
// 항목 추가 직후 저장(신규) — 그리드 fcltSn 없음 → API에는 "1"
|
||||||
fcltSn: nullableTrimmedString(row.fcltSn),
|
fcltSn: fcltSn,
|
||||||
fcltNm: nullableTrimmedString(row.fcltNm),
|
fcltNm: String(row.fcltNm ?? ""),
|
||||||
fcltPstnCn: nullableTrimmedString(row.fcltPstnCn),
|
fcltPstnCn: String(row.fcltPstnCn ?? ""),
|
||||||
oprtngStrtYmd: toCompactYmdOrNull(row.oprtngStrtYmd),
|
oprtngStrtYmd: toCompactYmdOrNull(row.oprtngStrtYmd),
|
||||||
planDesignFreqCnt: toGridNumber(row.planDesignFreqCnt),
|
planDesignFreqCnt: toGridNumber(row.planDesignFreqCnt),
|
||||||
fldngPrvtnYn: nullableTrimmedString(normalizeOxYnValue(row.fldngPrvtnYn)),
|
fldngPrvtnYn: normalizeOxYnValue(row.fldngPrvtnYn),
|
||||||
wqPlltnMtgtYn: nullableTrimmedString(normalizeOxYnValue(row.wqPlltnMtgtYn)),
|
wqPlltnMtgtYn: normalizeOxYnValue(row.wqPlltnMtgtYn),
|
||||||
rtlztnUsgYn: nullableTrimmedString(normalizeOxYnValue(row.rtlztnUsgYn)),
|
rtlztnUsgYn: normalizeOxYnValue(row.rtlztnUsgYn),
|
||||||
fcltStrctCn: nullableTrimmedString(row.fcltStrctCn),
|
fcltStrctCn: nullableTrimmedString(row.fcltStrctCn),
|
||||||
wtrStrgZoneArea: toGridNumber(row.wtrStrgZoneArea),
|
wtrStrgZoneArea: toGridNumber(row.wtrStrgZoneArea),
|
||||||
impdFcltCpct: toGridNumber(row.impdFcltCpct),
|
impdFcltCpct: toGridNumber(row.impdFcltCpct),
|
||||||
@@ -350,17 +337,17 @@ function buildSewageReservoirSaveItem(
|
|||||||
pumpFcltN3PerPpqty: toGridNumber(row.pumpFcltN3PerPpqty),
|
pumpFcltN3PerPpqty: toGridNumber(row.pumpFcltN3PerPpqty),
|
||||||
pumpFcltN3PumpCnt: toGridNumber(row.pumpFcltN3PumpCnt),
|
pumpFcltN3PumpCnt: toGridNumber(row.pumpFcltN3PumpCnt),
|
||||||
pumpFcltN3RsrvPumpCnt: toGridNumber(row.pumpFcltN3RsrvPumpCnt),
|
pumpFcltN3RsrvPumpCnt: toGridNumber(row.pumpFcltN3RsrvPumpCnt),
|
||||||
prcsgFcltYn: row.prcsgFcltYn ? (row.prcsgFcltYn === "무" ? "N" : "Y") : null,
|
prcsgFcltYn: String(row.prcsgFcltYn ? (row.prcsgFcltYn === '무' ? 'N' : 'Y') : ""),
|
||||||
ddrztnEqpmYn: row.ddrztnEqpmYn ? (row.prcsgFcltYn === "무" ? "N" : "Y") : null,
|
ddrztnEqpmYn: String(row.ddrztnEqpmYn ? (row.prcsgFcltYn === '무' ? 'N' : 'Y') : ""),
|
||||||
oslfEtgtYn: row.oslfEtgtYn ? (row.prcsgFcltYn === "무" ? "N" : "Y") : null,
|
oslfEtgtYn: String(row.oslfEtgtYn ? (row.prcsgFcltYn === '무' ? 'N' : 'Y') : ""),
|
||||||
mltvMthCn: nullableTrimmedString(row.mltvMthCn),
|
mltvMthCn: nullableTrimmedString(row.mltvMthCn),
|
||||||
impdMthCn: nullableTrimmedString(row.impdMthCn),
|
impdMthCn: nullableTrimmedString(row.impdMthCn),
|
||||||
impdPrcsMthdCn: nullableTrimmedString(row.impdPrcsMthdCn),
|
impdPrcsMthdCn: nullableTrimmedString(row.impdPrcsMthdCn),
|
||||||
dschgWtrsExpln: nullableTrimmedString(row.dschgWtrsExpln),
|
dschgWtrsExpln: String(row.dschgWtrsExpln ?? ""),
|
||||||
prcptnLastDspsQnt: toGridNumber(row.prcptnLastDspsQnt),
|
prcptnLastDspsQnt: toGridNumber(row.prcptnLastDspsQnt),
|
||||||
ctmnLastDspsQnt: toGridNumber(row.ctmnLastDspsQnt),
|
ctmnLastDspsQnt: toGridNumber(row.ctmnLastDspsQnt),
|
||||||
prcptnLastDspsMthdExpln: nullableTrimmedString(row.prcptnLastDspsMthdExpln),
|
prcptnLastDspsMthdExpln: String(row.prcptnLastDspsMthdExpln ?? ""),
|
||||||
ctmnLastDspsMthdExpln: nullableTrimmedString(row.ctmnLastDspsMthdExpln),
|
ctmnLastDspsMthdExpln: String(row.ctmnLastDspsMthdExpln ?? ""),
|
||||||
oprtngDayCnt: toGridNumber(row.oprtngDayCnt),
|
oprtngDayCnt: toGridNumber(row.oprtngDayCnt),
|
||||||
grssMltvQnt: toGridNumber(row.grssMltvQnt),
|
grssMltvQnt: toGridNumber(row.grssMltvQnt),
|
||||||
rmrk: nullableTrimmedString(row.rmrk),
|
rmrk: nullableTrimmedString(row.rmrk),
|
||||||
@@ -376,17 +363,18 @@ function buildRainfallPumpStationSaveItem(
|
|||||||
String(row.sggNm ?? ""),
|
String(row.sggNm ?? ""),
|
||||||
sggOptions,
|
sggOptions,
|
||||||
);
|
);
|
||||||
|
const fcltSn = String(row.fcltSn ?? "").trim();
|
||||||
return {
|
return {
|
||||||
admdstCd,
|
admdstCd,
|
||||||
admdstNm,
|
admdstNm,
|
||||||
fcltSn: nullableTrimmedString(row.fcltSn),
|
fcltSn: fcltSn,
|
||||||
fcltNm: nullableTrimmedString(row.fcltNm),
|
fcltNm: String(row.fcltNm ?? ""),
|
||||||
fcltPstnCn: nullableTrimmedString(row.fcltPstnCn),
|
fcltPstnCn: String(row.fcltPstnCn ?? ""),
|
||||||
fcltyKndCn: nullableTrimmedString(row.fcltyKndCn),
|
fcltyKndCn: String(row.fcltyKndCn ?? ""),
|
||||||
oprtngStrtYmd: toCompactYmdOrNull(row.oprtngStrtYmd),
|
oprtngStrtYmd: toCompactYmdOrNull(row.oprtngStrtYmd),
|
||||||
planDesignFreqCnt: toGridNumber(row.planDesignFreqCnt),
|
planDesignFreqCnt: toGridNumber(row.planDesignFreqCnt),
|
||||||
wtrStrgZoneArea: toGridNumber(row.wtrStrgZoneArea),
|
wtrStrgZoneArea: toGridNumber(row.wtrStrgZoneArea),
|
||||||
rsvrYn: row.rsvrYn ? (row.rsvrYn === "무" ? "N" : "Y") : null,
|
rsvrYn: String(row.rsvrYn ? (row.rsvrYn === "무" ? "N" : "Y") : ""),
|
||||||
rsvrImpndQnt: toGridNumber(row.rsvrImpndQnt),
|
rsvrImpndQnt: toGridNumber(row.rsvrImpndQnt),
|
||||||
abstnRgnImpdQnt: toGridNumber(row.abstnRgnImpdQnt),
|
abstnRgnImpdQnt: toGridNumber(row.abstnRgnImpdQnt),
|
||||||
grssPpqty: toGridNumber(row.grssPpqty),
|
grssPpqty: toGridNumber(row.grssPpqty),
|
||||||
@@ -402,14 +390,14 @@ function buildRainfallPumpStationSaveItem(
|
|||||||
pumpFcltN3PerPpqty: toGridNumber(row.pumpFcltN3PerPpqty),
|
pumpFcltN3PerPpqty: toGridNumber(row.pumpFcltN3PerPpqty),
|
||||||
pumpFcltN3PumpCnt: toGridNumber(row.pumpFcltN3PumpCnt),
|
pumpFcltN3PumpCnt: toGridNumber(row.pumpFcltN3PumpCnt),
|
||||||
pumpFcltN3RsrvPumpCnt: toGridNumber(row.pumpFcltN3RsrvPumpCnt),
|
pumpFcltN3RsrvPumpCnt: toGridNumber(row.pumpFcltN3RsrvPumpCnt),
|
||||||
prcsgFcltYn: row.prcsgFcltYn ? (row.prcsgFcltYn === "무" ? "N" : "Y") : null,
|
prcsgFcltYn: String(row.prcsgFcltYn ? (row.prcsgFcltYn === "무" ? "N" : "Y") : ""),
|
||||||
ddrztnEqpmYn: row.ddrztnEqpmYn ? (row.prcsgFcltYn === "무" ? "N" : "Y") : null,
|
ddrztnEqpmYn: String(row.ddrztnEqpmYn ? (row.prcsgFcltYn === "무" ? "N" : "Y") : ""),
|
||||||
oslfEtgtYn: row.oslfEtgtYn ? (row.prcsgFcltYn === "무" ? "N" : "Y") : null,
|
oslfEtgtYn: String(row.oslfEtgtYn ? (row.prcsgFcltYn === "무" ? "N" : "Y") : ""),
|
||||||
dschgWtrsExpln: nullableTrimmedString(row.dschgWtrsExpln),
|
dschgWtrsExpln: String(row.dschgWtrsExpln ?? ""),
|
||||||
prcptnLastDspsQnt: toGridNumber(row.prcptnLastDspsQnt),
|
prcptnLastDspsQnt: toGridNumber(row.prcptnLastDspsQnt),
|
||||||
ctmnLastDspsQnt: toGridNumber(row.ctmnLastDspsQnt),
|
ctmnLastDspsQnt: toGridNumber(row.ctmnLastDspsQnt),
|
||||||
prcptnLastDspsMthdExpln: nullableTrimmedString(row.prcptnLastDspsMthdExpln),
|
prcptnLastDspsMthdExpln: String(row.prcptnLastDspsMthdExpln ?? ""),
|
||||||
ctmnLastDspsMthdExpln: nullableTrimmedString(row.ctmnLastDspsMthdExpln),
|
ctmnLastDspsMthdExpln: String(row.ctmnLastDspsMthdExpln ?? ""),
|
||||||
oprtngDayCnt: toGridNumber(row.oprtngDayCnt),
|
oprtngDayCnt: toGridNumber(row.oprtngDayCnt),
|
||||||
grssMltvQnt: toGridNumber(row.grssMltvQnt),
|
grssMltvQnt: toGridNumber(row.grssMltvQnt),
|
||||||
rmrk: nullableTrimmedString(row.rmrk),
|
rmrk: nullableTrimmedString(row.rmrk),
|
||||||
@@ -419,9 +407,8 @@ function buildRainfallPumpStationSaveItem(
|
|||||||
function mapRainfallPumpStationListToGridRows(
|
function mapRainfallPumpStationListToGridRows(
|
||||||
list: RainfallPumpStationItem[],
|
list: RainfallPumpStationItem[],
|
||||||
ctpvNm: string,
|
ctpvNm: string,
|
||||||
values?: SearchFormValues | null,
|
|
||||||
): GridRowWithVerification[] {
|
): GridRowWithVerification[] {
|
||||||
return filterBySelectedAdmdstCd(list, sidoListRef.current, values).map((item) => {
|
return list.map((item) => {
|
||||||
const row = toGridRows([
|
const row = toGridRows([
|
||||||
{
|
{
|
||||||
...item,
|
...item,
|
||||||
@@ -459,17 +446,15 @@ async function waitForImrJobCompleted(
|
|||||||
options?.onProgress?.(Math.max(0, Math.min(100, Number(res.job_prog) || 0)));
|
options?.onProgress?.(Math.max(0, Math.min(100, Number(res.job_prog) || 0)));
|
||||||
if (res.status === "COMPLETED" && Number(res.job_prog) === 100) return;
|
if (res.status === "COMPLETED" && Number(res.job_prog) === 100) return;
|
||||||
if (res.status === "FAILED" || res.status === "ERROR" || res.status === "CANCELLED") {
|
if (res.status === "FAILED" || res.status === "ERROR" || res.status === "CANCELLED") {
|
||||||
throw new Error(res.error_msg || `시계열 검증이 ${res.status} 상태로 종료되었습니다.`);
|
throw new Error(res.error_msg || `IMR 검증이 ${res.status} 상태로 종료되었습니다.`);
|
||||||
}
|
}
|
||||||
await sleep(pollIntervalMs);
|
await sleep(pollIntervalMs);
|
||||||
}
|
}
|
||||||
throw new Error("시계열 검증 완료 대기 시간이 초과되었습니다.");
|
throw new Error("IMR 검증 완료 대기 시간이 초과되었습니다.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 하수도 통계 관리 > 04. 하수저류 시설 및 빗물 펌프장
|
// 하수도 통계 관리 > 04. 하수저류 시설 및 빗물 펌프장
|
||||||
const SewageReservoirPumpInp = () => {
|
const SewageReservoirPumpInp = () => {
|
||||||
const { sidoList } = useSearchConditionSidoList({ isInput: true });
|
|
||||||
sidoListRef.current = sidoList;
|
|
||||||
const { setMessage: alert } = useAlertStore((state) => state);
|
const { setMessage: alert } = useAlertStore((state) => state);
|
||||||
const { confirm } = useConfirm();
|
const { confirm } = useConfirm();
|
||||||
const { isAdminInfo } = useAdminStore();
|
const { isAdminInfo } = useAdminStore();
|
||||||
@@ -501,9 +486,9 @@ const SewageReservoirPumpInp = () => {
|
|||||||
alert("시군구를 선택해주세요.");
|
alert("시군구를 선택해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const noApplicable = buildNoApplicableForRequest(searchContextByTab.get(tabKey) ?? lastSearchedValues, isNotApplicableByTab.get(tabKey) ?? false, getCurrentRowsForTab(tabKey).length === 0);
|
const noApplicable = isNotApplicableByTab.get(tabKey) ?? false;
|
||||||
const currentData = getCurrentRowsForTab(tabKey);
|
const currentData = getCurrentRowsForTab(tabKey);
|
||||||
if (!noApplicable && currentData.length === 0 && buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)) {
|
if (!noApplicable && currentData.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -528,8 +513,12 @@ const SewageReservoirPumpInp = () => {
|
|||||||
const userInfo = await getUserInfo();
|
const userInfo = await getUserInfo();
|
||||||
|
|
||||||
const requestData: cancelSubmitRequest = {
|
const requestData: cancelSubmitRequest = {
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
mdfrId: userInfo.userUnqId,
|
mdfrId: userInfo.userUnqId,
|
||||||
statsCd: statsCdForTab,
|
statsCd: statsCdForTab,
|
||||||
@@ -682,7 +671,7 @@ const SewageReservoirPumpInp = () => {
|
|||||||
if (!(await confirm("저장 하시겠습니까?"))) return;
|
if (!(await confirm("저장 하시겠습니까?"))) return;
|
||||||
|
|
||||||
commitGridForTab(tabKey);
|
commitGridForTab(tabKey);
|
||||||
const noApplicable = buildNoApplicableForRequest(searchContextByTab.get(tabKey) ?? lastSearchedValues, isNotApplicableByTab.get(tabKey) ?? false, getCurrentRowsForTab(tabKey).length === 0);
|
const noApplicable = isNotApplicableByTab.get(tabKey) ?? false;
|
||||||
const currentData = getCurrentRowsForTab(tabKey);
|
const currentData = getCurrentRowsForTab(tabKey);
|
||||||
const isReservoirTab = tabKey === SEWAGE_RESERVOIR_STATS_CD;
|
const isReservoirTab = tabKey === SEWAGE_RESERVOIR_STATS_CD;
|
||||||
const saveList = noApplicable
|
const saveList = noApplicable
|
||||||
@@ -701,7 +690,7 @@ const SewageReservoirPumpInp = () => {
|
|||||||
: rainfallPumpStationDeleteList
|
: rainfallPumpStationDeleteList
|
||||||
.filter((row) => String(row.fcltSn ?? "").trim() !== "")
|
.filter((row) => String(row.fcltSn ?? "").trim() !== "")
|
||||||
.map((row) => buildRainfallPumpStationSaveItem(row, sggOptions));
|
.map((row) => buildRainfallPumpStationSaveItem(row, sggOptions));
|
||||||
if (!noApplicable && saveList.length === 0 && buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)) {
|
if (!noApplicable && saveList.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -709,7 +698,11 @@ const SewageReservoirPumpInp = () => {
|
|||||||
const requestBase = {
|
const requestBase = {
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
...(isAdminInfo ? { superAdmin: "superAdmin" } : {}),
|
...(isAdminInfo ? { superAdmin: "superAdmin" } : {}),
|
||||||
...(noApplicable ? { noApplicable: true } : {}),
|
...(noApplicable ? { noApplicable: true } : {}),
|
||||||
};
|
};
|
||||||
@@ -769,7 +762,7 @@ const SewageReservoirPumpInp = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
commitGridForTab(tabKey);
|
commitGridForTab(tabKey);
|
||||||
const noApplicable = buildNoApplicableForRequest(searchContextByTab.get(tabKey) ?? lastSearchedValues, isNotApplicableByTab.get(tabKey) ?? false, getCurrentRowsForTab(tabKey).length === 0);
|
const noApplicable = isNotApplicableByTab.get(tabKey) ?? false;
|
||||||
const currentData = getCurrentRowsForTab(tabKey);
|
const currentData = getCurrentRowsForTab(tabKey);
|
||||||
const isReservoirTab = tabKey === SEWAGE_RESERVOIR_STATS_CD;
|
const isReservoirTab = tabKey === SEWAGE_RESERVOIR_STATS_CD;
|
||||||
const submitList = noApplicable
|
const submitList = noApplicable
|
||||||
@@ -788,8 +781,12 @@ const SewageReservoirPumpInp = () => {
|
|||||||
const activeTabStatus = tabStatusInfoMap.get(tabKey) ?? null;
|
const activeTabStatus = tabStatusInfoMap.get(tabKey) ?? null;
|
||||||
const statsCdForTab = tabStatsCdMap.get(tabKey) ?? tabKey;
|
const statsCdForTab = tabStatsCdMap.get(tabKey) ?? tabKey;
|
||||||
const verificationQuery = {
|
const verificationQuery = {
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
statsCd: statsCdForTab,
|
statsCd: statsCdForTab,
|
||||||
};
|
};
|
||||||
@@ -803,7 +800,7 @@ const SewageReservoirPumpInp = () => {
|
|||||||
await loadActiveTabData(tabKey, lastSearchedValues, true, false);
|
await loadActiveTabData(tabKey, lastSearchedValues, true, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!noApplicable && submitList.length === 0 && buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)) {
|
if (!noApplicable && submitList.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -811,7 +808,11 @@ const SewageReservoirPumpInp = () => {
|
|||||||
const submitRequestBase = {
|
const submitRequestBase = {
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
...(noApplicable ? { noApplicable: true } : {}),
|
...(noApplicable ? { noApplicable: true } : {}),
|
||||||
laePicNm: submitInfo.laePicNm,
|
laePicNm: submitInfo.laePicNm,
|
||||||
laeKbrdrJbgdNm: submitInfo.laeKbrdrJbgdNm,
|
laeKbrdrJbgdNm: submitInfo.laeKbrdrJbgdNm,
|
||||||
@@ -851,16 +852,15 @@ const SewageReservoirPumpInp = () => {
|
|||||||
|
|
||||||
if (finalStatus === "5") {
|
if (finalStatus === "5") {
|
||||||
setGlobalProgress(50);
|
setGlobalProgress(50);
|
||||||
setGlobalProgressLabel("시계열 검증 진행 중...");
|
setGlobalProgressLabel("IMR 검증 진행 중...");
|
||||||
const imrParam = {
|
const imrParam = {
|
||||||
user_id: userInfo.userUnqId,
|
user_id: userInfo.userUnqId,
|
||||||
sewer_bzmn_cd: lastSearchedValues?.bsnmCd ?? "",
|
sewer_bzmn_cd: lastSearchedValues.bsnmCd ?? "",
|
||||||
stats_cd: statsCdForTab,
|
stats_cd: statsCdForTab,
|
||||||
stats_yr: lastSearchedValues.year ?? "",
|
stats_yr: lastSearchedValues.year ?? "",
|
||||||
lae_sbmsn_stts_cd:
|
lae_sbmsn_stts_cd:
|
||||||
activeTabStatus?.laeSbmsnSttsCd === "4" ? "4" : "2",
|
activeTabStatus?.laeSbmsnSttsCd === "4" ? "4" : "2",
|
||||||
gen_verify_stts_cd: nvpassed ? "1" : "2",
|
gen_verify_stts_cd: nvpassed ? "1" : "2",
|
||||||
hb_pass_yn: response.data?.isHbPassed,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -934,19 +934,13 @@ const SewageReservoirPumpInp = () => {
|
|||||||
const [tabStatusInfoMap, setTabStatusInfoMap] = useState<
|
const [tabStatusInfoMap, setTabStatusInfoMap] = useState<
|
||||||
Map<string, SewerageStatusInfo | null>
|
Map<string, SewerageStatusInfo | null>
|
||||||
>(new Map());
|
>(new Map());
|
||||||
const [_toolbarSnapshotByTab, setToolbarSnapshotByTab] = useState<
|
const [toolbarSnapshotByTab, setToolbarSnapshotByTab] = useState<
|
||||||
Map<string, TabToolbarSnapshot>
|
Map<string, TabToolbarSnapshot>
|
||||||
>(new Map());
|
>(new Map());
|
||||||
const [searchContextByTab, setSearchContextByTab] = useState<Map<string, SearchFormValues>>(
|
|
||||||
() => new Map(),
|
|
||||||
);
|
|
||||||
const [tabStatsCdMap, setTabStatsCdMap] = useState<Map<string, string>>(new Map());
|
const [tabStatsCdMap, setTabStatsCdMap] = useState<Map<string, string>>(new Map());
|
||||||
const [isVerificationFailedByTab, setIsVerificationFailedByTab] = useState<
|
const [isVerificationFailedByTab, setIsVerificationFailedByTab] = useState<
|
||||||
Map<string, boolean>
|
Map<string, boolean>
|
||||||
>(new Map());
|
>(new Map());
|
||||||
const [footerVerificationByTab, setFooterVerificationByTab] = useState<
|
|
||||||
Map<string, VerificationResultLikeMap | null>
|
|
||||||
>(new Map());
|
|
||||||
const [verificationHistoryOpen, setVerificationHistoryOpen] = useState(false);
|
const [verificationHistoryOpen, setVerificationHistoryOpen] = useState(false);
|
||||||
const [verificationResultDialogOpen, setVerificationResultDialogOpen] =
|
const [verificationResultDialogOpen, setVerificationResultDialogOpen] =
|
||||||
useState(false);
|
useState(false);
|
||||||
@@ -963,29 +957,35 @@ const SewageReservoirPumpInp = () => {
|
|||||||
useRef<(() => Record<string, string | number>[]) | null>(null);
|
useRef<(() => Record<string, string | number>[]) | null>(null);
|
||||||
const sggOptionsSidoRef = useRef<string | null>(null);
|
const sggOptionsSidoRef = useRef<string | null>(null);
|
||||||
|
|
||||||
const activeTabId = useTabStore((s) => s.activeTabId);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeTabId !== STATISTICS_INPUT_URL_PATH.SEWAGE_RESERVOIR_PUMP) return;
|
|
||||||
const tabKey = activeTab;
|
|
||||||
if (!tabKey) return;
|
|
||||||
if (Object.prototype.hasOwnProperty.call(columnGuidesByTab, tabKey)) return;
|
|
||||||
const statsCd = tabKey;
|
|
||||||
|
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
void (async () => {
|
void (async () => {
|
||||||
const next = await fetchColumnGuidesRecord(statsCd);
|
const entries = await Promise.all(
|
||||||
if (cancelled) return;
|
SEWAGE_RESERVOIR_PUMP_COLUMN_GUIDE_TAB_KEYS.map(async (tabKey) => {
|
||||||
setColumnGuidesByTab((prev) =>
|
try {
|
||||||
Object.prototype.hasOwnProperty.call(prev, tabKey)
|
const res = await statisticsApi.getColumnGuides(tabKey);
|
||||||
? prev
|
if (res.status !== "success" || !Array.isArray(res.data)) {
|
||||||
: { ...prev, [tabKey]: next },
|
return [tabKey, {}] as const;
|
||||||
|
}
|
||||||
|
const next: Record<string, string> = {};
|
||||||
|
for (const item of res.data) {
|
||||||
|
const key = item.engColNm?.trim();
|
||||||
|
const guide = item.columnGuide?.trim();
|
||||||
|
if (key && guide) next[key] = guide;
|
||||||
|
}
|
||||||
|
return [tabKey, next] as const;
|
||||||
|
} catch {
|
||||||
|
return [tabKey, {}] as const;
|
||||||
|
}
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
if (cancelled) return;
|
||||||
|
setColumnGuidesByTab(Object.fromEntries(entries));
|
||||||
})();
|
})();
|
||||||
return () => {
|
return () => {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
};
|
};
|
||||||
}, [activeTabId, activeTab, columnGuidesByTab]);
|
}, []);
|
||||||
|
|
||||||
const searchDoneRef = useRef(false);
|
const searchDoneRef = useRef(false);
|
||||||
const periodEnterableRef = useRef(true);
|
const periodEnterableRef = useRef(true);
|
||||||
@@ -1035,13 +1035,6 @@ const SewageReservoirPumpInp = () => {
|
|||||||
);
|
);
|
||||||
return next;
|
return next;
|
||||||
});
|
});
|
||||||
if (searchContext) {
|
|
||||||
setSearchContextByTab((prev) => {
|
|
||||||
const next = new Map(prev);
|
|
||||||
next.set(tabKey, searchContext);
|
|
||||||
return next;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const applyRowMap = (
|
const applyRowMap = (
|
||||||
@@ -1086,7 +1079,6 @@ const SewageReservoirPumpInp = () => {
|
|||||||
const gridRows = mapSewageReservoirListToGridRows(
|
const gridRows = mapSewageReservoirListToGridRows(
|
||||||
list,
|
list,
|
||||||
commonInfo.ctpvNm,
|
commonInfo.ctpvNm,
|
||||||
values,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
applyRowMap(mergeIntoExistingMap, (m) => {
|
applyRowMap(mergeIntoExistingMap, (m) => {
|
||||||
@@ -1097,9 +1089,6 @@ const SewageReservoirPumpInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
|
||||||
if (updateLastSearchedValues) {
|
if (updateLastSearchedValues) {
|
||||||
setLastSearchedValues(values);
|
setLastSearchedValues(values);
|
||||||
}
|
}
|
||||||
@@ -1135,7 +1124,6 @@ const SewageReservoirPumpInp = () => {
|
|||||||
const gridRows = mapRainfallPumpStationListToGridRows(
|
const gridRows = mapRainfallPumpStationListToGridRows(
|
||||||
list,
|
list,
|
||||||
commonInfo.ctpvNm,
|
commonInfo.ctpvNm,
|
||||||
values,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
applyRowMap(mergeIntoExistingMap, (m) => {
|
applyRowMap(mergeIntoExistingMap, (m) => {
|
||||||
@@ -1146,9 +1134,6 @@ const SewageReservoirPumpInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
|
||||||
if (updateLastSearchedValues) {
|
if (updateLastSearchedValues) {
|
||||||
setLastSearchedValues(values);
|
setLastSearchedValues(values);
|
||||||
}
|
}
|
||||||
@@ -1216,9 +1201,7 @@ const SewageReservoirPumpInp = () => {
|
|||||||
setTabStatusInfoMap(new Map());
|
setTabStatusInfoMap(new Map());
|
||||||
setTabStatsCdMap(new Map());
|
setTabStatsCdMap(new Map());
|
||||||
setIsVerificationFailedByTab(new Map());
|
setIsVerificationFailedByTab(new Map());
|
||||||
setFooterVerificationByTab(new Map());
|
|
||||||
setToolbarSnapshotByTab(new Map());
|
setToolbarSnapshotByTab(new Map());
|
||||||
setSearchContextByTab(new Map());
|
|
||||||
setLastSearchedValues(null);
|
setLastSearchedValues(null);
|
||||||
setSggOptions([]);
|
setSggOptions([]);
|
||||||
sggOptionsSidoRef.current = null;
|
sggOptionsSidoRef.current = null;
|
||||||
@@ -1268,9 +1251,7 @@ const SewageReservoirPumpInp = () => {
|
|||||||
setTabStatusInfoMap(new Map());
|
setTabStatusInfoMap(new Map());
|
||||||
setTabStatsCdMap(new Map());
|
setTabStatsCdMap(new Map());
|
||||||
setIsVerificationFailedByTab(new Map());
|
setIsVerificationFailedByTab(new Map());
|
||||||
setFooterVerificationByTab(new Map());
|
|
||||||
setToolbarSnapshotByTab(new Map());
|
setToolbarSnapshotByTab(new Map());
|
||||||
setSearchContextByTab(new Map());
|
|
||||||
loadedTabKeysRef.current.clear();
|
loadedTabKeysRef.current.clear();
|
||||||
setActiveTab(firstTabKey);
|
setActiveTab(firstTabKey);
|
||||||
}
|
}
|
||||||
@@ -1340,9 +1321,10 @@ const SewageReservoirPumpInp = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const searchContextForToolbar = searchContextByTab.get(activeTab) ?? lastSearchedValues;
|
const searchContextForToolbar = lastSearchedValues ?? searchValues;
|
||||||
const activeTabStatus = tabStatusInfoMap.get(activeTab) ?? null;
|
const activeTabStatus = tabStatusInfoMap.get(activeTab) ?? null;
|
||||||
const activeTabToolbar =
|
const activeTabToolbar =
|
||||||
|
toolbarSnapshotByTab.get(activeTab) ??
|
||||||
computeTabToolbarSnapshot(
|
computeTabToolbarSnapshot(
|
||||||
activeTabStatus,
|
activeTabStatus,
|
||||||
tabRowDataExists(rowDataMap, activeTab),
|
tabRowDataExists(rowDataMap, activeTab),
|
||||||
@@ -1363,7 +1345,6 @@ const SewageReservoirPumpInp = () => {
|
|||||||
baseShowEnterableToolbarButtons && toolbarGroupAllowed;
|
baseShowEnterableToolbarButtons && toolbarGroupAllowed;
|
||||||
const showActionToolbarCard =
|
const showActionToolbarCard =
|
||||||
baseShowActionToolbarCard && toolbarGroupAllowed;
|
baseShowActionToolbarCard && toolbarGroupAllowed;
|
||||||
const submitOk = buildSubmitOkForToolbar(searchContextForToolbar);
|
|
||||||
const isReservoirOrRainfallTab =
|
const isReservoirOrRainfallTab =
|
||||||
activeTab === SEWAGE_RESERVOIR_STATS_CD || activeTab === rainfallPumpTabKey;
|
activeTab === SEWAGE_RESERVOIR_STATS_CD || activeTab === rainfallPumpTabKey;
|
||||||
const showArticleToolbarCard =
|
const showArticleToolbarCard =
|
||||||
@@ -1378,8 +1359,7 @@ const SewageReservoirPumpInp = () => {
|
|||||||
activeTab,
|
activeTab,
|
||||||
tabRowDataExists(rowDataMap, activeTab),
|
tabRowDataExists(rowDataMap, activeTab),
|
||||||
tabStatusInfoMap.get(activeTab),
|
tabStatusInfoMap.get(activeTab),
|
||||||
) &&
|
);
|
||||||
submitOk;
|
|
||||||
const setIsNotApplicableForActiveTab: Dispatch<SetStateAction<boolean>> = useCallback(
|
const setIsNotApplicableForActiveTab: Dispatch<SetStateAction<boolean>> = useCallback(
|
||||||
(next) => {
|
(next) => {
|
||||||
const tabKey = activeTabRef.current;
|
const tabKey = activeTabRef.current;
|
||||||
@@ -1458,10 +1438,10 @@ const SewageReservoirPumpInp = () => {
|
|||||||
for (const tab of SewageReservoirPumpInpTabList) {
|
for (const tab of SewageReservoirPumpInpTabList) {
|
||||||
const tabKey = tab.tabKey ?? "";
|
const tabKey = tab.tabKey ?? "";
|
||||||
const canEdit =
|
const canEdit =
|
||||||
(computeTabEnterable(
|
computeTabEnterable(
|
||||||
tabStatusInfoMap.get(tabKey) ?? null,
|
tabStatusInfoMap.get(tabKey) ?? null,
|
||||||
inputPeriodEnterable,
|
inputPeriodEnterable,
|
||||||
) || isAdminInfo) && inputPeriodEnterable;
|
) || isAdminInfo;
|
||||||
const isReservoirTab = tabKey === SEWAGE_RESERVOIR_STATS_CD;
|
const isReservoirTab = tabKey === SEWAGE_RESERVOIR_STATS_CD;
|
||||||
const isRainfallPumpTab = tabKey === rainfallPumpTabKey;
|
const isRainfallPumpTab = tabKey === rainfallPumpTabKey;
|
||||||
const rawColumns = tab.columns ?? [];
|
const rawColumns = tab.columns ?? [];
|
||||||
@@ -1520,10 +1500,10 @@ const SewageReservoirPumpInp = () => {
|
|||||||
.map((e) => {
|
.map((e) => {
|
||||||
const prefix =
|
const prefix =
|
||||||
e.vrfcCd === "IMR"
|
e.vrfcCd === "IMR"
|
||||||
? "시계열 검증 - "
|
? "IMR검증 - "
|
||||||
: e.vrfcCd === "NV"
|
: e.vrfcCd === "NV"
|
||||||
? "일반검증 - "
|
? "일반검증 - "
|
||||||
: "모집단 검증 -";
|
: "HB검증 -";
|
||||||
return `${prefix}${e.rsnExpln}
|
return `${prefix}${e.rsnExpln}
|
||||||
(검증 기준값: ${e.compVlCn} / 현재 입력값: ${e.nowVlCn})`;
|
(검증 기준값: ${e.compVlCn} / 현재 입력값: ${e.nowVlCn})`;
|
||||||
})
|
})
|
||||||
@@ -1537,8 +1517,9 @@ const SewageReservoirPumpInp = () => {
|
|||||||
const statsCd = tabStatsCdMap.get(activeTab);
|
const statsCd = tabStatsCdMap.get(activeTab);
|
||||||
if (!ctx?.year || !ctx?.sido || !ctx?.bsnmCd || !statsCd) return null;
|
if (!ctx?.year || !ctx?.sido || !ctx?.bsnmCd || !statsCd) return null;
|
||||||
return {
|
return {
|
||||||
...toInputSearchRegion(sidoListRef.current, ctx),
|
sewerBzmnCd: ctx.bsnmCd,
|
||||||
ctpvNm: ctx.sido,
|
ctpvNm: ctx.sido,
|
||||||
|
sggNm: ctx.gugun === "ALL" ? "" : (ctx.gugun ?? ""),
|
||||||
statsYr: ctx.year,
|
statsYr: ctx.year,
|
||||||
statsCd,
|
statsCd,
|
||||||
};
|
};
|
||||||
@@ -1559,7 +1540,6 @@ const SewageReservoirPumpInp = () => {
|
|||||||
<>
|
<>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<SearchForm
|
<SearchForm
|
||||||
isInput
|
|
||||||
key={searchFormRemountKey}
|
key={searchFormRemountKey}
|
||||||
defaultValues={verificationSearchDefaults ?? undefined}
|
defaultValues={verificationSearchDefaults ?? undefined}
|
||||||
fctName={true}
|
fctName={true}
|
||||||
@@ -1581,10 +1561,10 @@ const SewageReservoirPumpInp = () => {
|
|||||||
<LastYearDataButton
|
<LastYearDataButton
|
||||||
getLastYearDataFunc={() => void getLastYearDataFunc()}
|
getLastYearDataFunc={() => void getLastYearDataFunc()}
|
||||||
/>
|
/>
|
||||||
{submitOk && <SubmitButton submitFunc={submitFunc} />}
|
<SubmitButton submitFunc={submitFunc} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{activeTabStatus?.laeSbmsnSttsCd === "2" && submitOk && (
|
{activeTabStatus?.laeSbmsnSttsCd === "2" && (
|
||||||
<CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />
|
<CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />
|
||||||
)}
|
)}
|
||||||
{showSaveInToolbar && <SaveButton saveFunc={saveFunc} />}
|
{showSaveInToolbar && <SaveButton saveFunc={saveFunc} />}
|
||||||
@@ -1626,11 +1606,11 @@ const SewageReservoirPumpInp = () => {
|
|||||||
{SewageReservoirPumpInpTabList.map((tab) => {
|
{SewageReservoirPumpInpTabList.map((tab) => {
|
||||||
const tabKey = tab.tabKey ?? "";
|
const tabKey = tab.tabKey ?? "";
|
||||||
const tabEnterableForGrid =
|
const tabEnterableForGrid =
|
||||||
(computeTabEnterable(
|
computeTabEnterable(
|
||||||
tabStatusInfoMap.get(tabKey) ?? null,
|
tabStatusInfoMap.get(tabKey) ?? null,
|
||||||
inputPeriodEnterable,
|
inputPeriodEnterable,
|
||||||
) || isAdminInfo) && inputPeriodEnterable;
|
) || isAdminInfo;
|
||||||
const gugunOk = buildGugunOkForToolbar(searchContextForToolbar);
|
const gugunOk = buildGugunOkForToolbar(lastSearchedValues);
|
||||||
const tabStatusInfo = tabStatusInfoMap.get(tabKey) ?? null;
|
const tabStatusInfo = tabStatusInfoMap.get(tabKey) ?? null;
|
||||||
const isReservoirTab = tabKey === SEWAGE_RESERVOIR_STATS_CD;
|
const isReservoirTab = tabKey === SEWAGE_RESERVOIR_STATS_CD;
|
||||||
return (
|
return (
|
||||||
@@ -1688,9 +1668,6 @@ const SewageReservoirPumpInp = () => {
|
|||||||
excelImportSewerBzmnCd={(lastSearchedValues ?? searchValues)?.bsnmCd}
|
excelImportSewerBzmnCd={(lastSearchedValues ?? searchValues)?.bsnmCd}
|
||||||
excelExportSearchContext={toExcelExportSearchContextFromSearchForm(lastSearchedValues ?? searchValues)}
|
excelExportSearchContext={toExcelExportSearchContextFromSearchForm(lastSearchedValues ?? searchValues)}
|
||||||
cellStyleCallback={verificationCellStyle}
|
cellStyleCallback={verificationCellStyle}
|
||||||
footerVerificationResult={
|
|
||||||
footerVerificationByTab.get(tabKey) ?? null
|
|
||||||
}
|
|
||||||
cellTooltipCallback={verificationCellTooltip}
|
cellTooltipCallback={verificationCellTooltip}
|
||||||
/>
|
/>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useEffect, useMemo, useRef, useState } from "react";
|
|||||||
|
|
||||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||||
|
|
||||||
import { useAlertStore, useGlobalProgressStore, useSearchConditionSidoList } from "@/shared/lib";
|
import { useAlertStore, useGlobalProgressStore } from "@/shared/lib";
|
||||||
import { STATISTICS_INPUT_URL_PATH } from "@/shared/lib/stats-cd-input-navigation";
|
import { STATISTICS_INPUT_URL_PATH } from "@/shared/lib/stats-cd-input-navigation";
|
||||||
import { useStatisticsInputPendingNavigation } from "@/shared/lib/use-statistics-input-pending-navigation";
|
import { useStatisticsInputPendingNavigation } from "@/shared/lib/use-statistics-input-pending-navigation";
|
||||||
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
||||||
@@ -35,15 +35,7 @@ import type {
|
|||||||
cancelSubmitRequest,
|
cancelSubmitRequest,
|
||||||
ImrStatusResponse,
|
ImrStatusResponse,
|
||||||
SewerageStatusInfo,
|
SewerageStatusInfo,
|
||||||
Sido,
|
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
} from "@/entities/statistics/model/statistics-interface";
|
||||||
import {
|
|
||||||
filterBySelectedAdmdstCd,
|
|
||||||
isGugunOkForToolbar,
|
|
||||||
isSubmitOkForToolbar,
|
|
||||||
toInputSearchRegion,
|
|
||||||
} from "@/entities/statistics";
|
|
||||||
|
|
||||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||||
|
|
||||||
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
||||||
@@ -56,27 +48,21 @@ import SaveButton from "@/components/button/SaveButton";
|
|||||||
import SubmitButton from "@/components/button/SumitButton";
|
import SubmitButton from "@/components/button/SumitButton";
|
||||||
import VerificationResultButton from "@/components/button/VerificationResultButton";
|
import VerificationResultButton from "@/components/button/VerificationResultButton";
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
|
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
||||||
import { openVerificationResultDialogIfNeeded } from "@/components/module/post-submit-verification-results";
|
import { openVerificationResultDialogIfNeeded } from "@/components/module/post-submit-verification-results";
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
||||||
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
||||||
import type { ColumnConfig, ColumnInfo } from "@/components/type/DataGrid.type";
|
import type { ColumnConfig, ColumnInfo } from "@/components/type/DataGrid.type";
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
|
import { doList } from "@/components/util/column/input/DoList";
|
||||||
import { CauserBurdenInpColumn } from "@/components/util/column/input/sewerageFinance/CauserBurdenInpColumn";
|
import { CauserBurdenInpColumn } from "@/components/util/column/input/sewerageFinance/CauserBurdenInpColumn";
|
||||||
import { SewerageChargeInpColumn } from "@/components/util/column/input/sewerageFinance/SewerageChargeInpColumn";
|
import { SewerageChargeInpColumn } from "@/components/util/column/input/sewerageFinance/SewerageChargeInpColumn";
|
||||||
import { SewerageFinanceSettleInpColumn } from "@/components/util/column/input/sewerageFinance/SewerageFinanceSettleInpColumn";
|
import { SewerageFinanceSettleInpColumn } from "@/components/util/column/input/sewerageFinance/SewerageFinanceSettleInpColumn";
|
||||||
import { SewerageUsageFeeInpColumn } from "@/components/util/column/input/sewerageFinance/SewerageUsageFeeInpColumn";
|
import { SewerageUsageFeeInpColumn } from "@/components/util/column/input/sewerageFinance/SewerageUsageFeeInpColumn";
|
||||||
import { fetchColumnGuidesRecord } from "@/components/util/grid/columnGuides";
|
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
import { patchVerificationFailedByTab } from "@/components/util/input/verification-failed-flag";
|
||||||
import {
|
|
||||||
patchFooterVerificationByTab,
|
|
||||||
patchVerificationFailedByTab,
|
|
||||||
} from "@/components/util/input/verification-failed-flag";
|
|
||||||
import type { VerificationResultLikeMap } from "@/components/util/input/verification-result-display";
|
|
||||||
import { nullableTrimmedString } from "@/components/util/input/nullableString";
|
|
||||||
import { useAdminStore } from "@/store/admin-store";
|
import { useAdminStore } from "@/store/admin-store";
|
||||||
import { useTabStore } from "@/store/tab-store";
|
|
||||||
|
|
||||||
const SewerageFinanceInpTabList = [
|
const SewerageFinanceInpTabList = [
|
||||||
SewerageFinanceSettleInpColumn,
|
SewerageFinanceSettleInpColumn,
|
||||||
@@ -87,6 +73,10 @@ const SewerageFinanceInpTabList = [
|
|||||||
|
|
||||||
const firstTabKey = SewerageFinanceSettleInpColumn.tabKey;
|
const firstTabKey = SewerageFinanceSettleInpColumn.tabKey;
|
||||||
|
|
||||||
|
const SEWERAGE_FINANCE_COLUMN_GUIDE_TAB_KEYS = Array.from(
|
||||||
|
new Set(SewerageFinanceInpTabList.map((tab) => tab.tabKey).filter(Boolean)),
|
||||||
|
);
|
||||||
|
|
||||||
type GridRowWithVerification = Record<string, string | number> & {
|
type GridRowWithVerification = Record<string, string | number> & {
|
||||||
verificationResult?: SewerageFinanceVerificationResult;
|
verificationResult?: SewerageFinanceVerificationResult;
|
||||||
};
|
};
|
||||||
@@ -108,8 +98,9 @@ function buildSewerageFinanceSearchParam(
|
|||||||
): SewerageFinanceRequestParams {
|
): SewerageFinanceRequestParams {
|
||||||
return {
|
return {
|
||||||
statsYr: values.year,
|
statsYr: values.year,
|
||||||
|
sewerBzmnCd: values.bsnmCd,
|
||||||
ctpvNm: values.sido,
|
ctpvNm: values.sido,
|
||||||
...toInputSearchRegion(sidoListRef.current, values),
|
sggNm: values.gugun === "ALL" ? "" : values.gugun,
|
||||||
...(overrides?.mode ? { mode: overrides.mode } : {}),
|
...(overrides?.mode ? { mode: overrides.mode } : {}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -127,14 +118,10 @@ const computeTabEnterable = (
|
|||||||
return periodEnterable;
|
return periodEnterable;
|
||||||
};
|
};
|
||||||
|
|
||||||
const sidoListRef: { current: Sido[] } = { current: [] };
|
|
||||||
|
|
||||||
function buildGugunOkForToolbar(values: SearchFormValues | null): boolean {
|
function buildGugunOkForToolbar(values: SearchFormValues | null): boolean {
|
||||||
return isGugunOkForToolbar(sidoListRef.current, values);
|
return doList.includes(values?.bsnmCd || "")
|
||||||
}
|
? Boolean(values?.gugun && values.gugun !== "ALL")
|
||||||
|
: true;
|
||||||
function buildSubmitOkForToolbar(values: SearchFormValues | null): boolean {
|
|
||||||
return isSubmitOkForToolbar(sidoListRef.current, values);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeTabToolbarSnapshot(
|
function computeTabToolbarSnapshot(
|
||||||
@@ -148,7 +135,7 @@ function computeTabToolbarSnapshot(
|
|||||||
const gugunOk = buildGugunOkForToolbar(searchContext);
|
const gugunOk = buildGugunOkForToolbar(searchContext);
|
||||||
const enterable = computeTabEnterable(statusInfo, periodEnterable);
|
const enterable = computeTabEnterable(statusInfo, periodEnterable);
|
||||||
const isSubmitted = statusInfo?.laeSbmsnSttsCd === "2";
|
const isSubmitted = statusInfo?.laeSbmsnSttsCd === "2";
|
||||||
const showSaveInToolbar = (enterable || isAdminInfo) && periodEnterable && gugunOk;
|
const showSaveInToolbar = (enterable || isAdminInfo) && gugunOk;
|
||||||
const showEnterableToolbarButtons = enterable && gugunOk;
|
const showEnterableToolbarButtons = enterable && gugunOk;
|
||||||
const showSubmittedInInputPeriodToolbar = isSubmitted && periodEnterable && gugunOk;
|
const showSubmittedInInputPeriodToolbar = isSubmitted && periodEnterable && gugunOk;
|
||||||
const showActionToolbarCard =
|
const showActionToolbarCard =
|
||||||
@@ -170,8 +157,8 @@ function tabRowDataExists(
|
|||||||
|
|
||||||
function mapRegionalListToGridRows<
|
function mapRegionalListToGridRows<
|
||||||
T extends { verificationResult?: SewerageFinanceVerificationResult },
|
T extends { verificationResult?: SewerageFinanceVerificationResult },
|
||||||
>(list: T[], ctpvNm: string, values?: SearchFormValues | null): GridRowWithVerification[] {
|
>(list: T[], ctpvNm: string): GridRowWithVerification[] {
|
||||||
return filterBySelectedAdmdstCd(list, sidoListRef.current, values).map((item) => {
|
return list.map((item) => {
|
||||||
const { verificationResult, ...rest } = item;
|
const { verificationResult, ...rest } = item;
|
||||||
const row = toGridRows([{ ctpvNm, ...rest }])[0] as GridRowWithVerification;
|
const row = toGridRows([{ ctpvNm, ...rest }])[0] as GridRowWithVerification;
|
||||||
if (verificationResult) row.verificationResult = verificationResult;
|
if (verificationResult) row.verificationResult = verificationResult;
|
||||||
@@ -179,6 +166,17 @@ function mapRegionalListToGridRows<
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeGridString(value: unknown): string {
|
||||||
|
if (value === null || value === undefined) return "";
|
||||||
|
return typeof value === "string" ? value : String(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeGridRmrk(value: unknown): string | null {
|
||||||
|
if (value === null || value === undefined) return null;
|
||||||
|
const s = typeof value === "string" ? value : String(value);
|
||||||
|
return s.trim() === "" ? null : s;
|
||||||
|
}
|
||||||
|
|
||||||
function buildColumnFormatNumber(columns: { fieldName?: string; dataFormat?: string }[]) {
|
function buildColumnFormatNumber(columns: { fieldName?: string; dataFormat?: string }[]) {
|
||||||
const columnFormatMap = new Map<string, string>();
|
const columnFormatMap = new Map<string, string>();
|
||||||
columns.forEach((col) => {
|
columns.forEach((col) => {
|
||||||
@@ -214,9 +212,9 @@ function buildSewerageFinanceSettleSaveList(
|
|||||||
const formatNumber = buildColumnFormatNumber(SewerageFinanceSettleInpColumn.columns);
|
const formatNumber = buildColumnFormatNumber(SewerageFinanceSettleInpColumn.columns);
|
||||||
|
|
||||||
return currentData.map((d) => ({
|
return currentData.map((d) => ({
|
||||||
admdstCd: nullableTrimmedString(d.admdstCd),
|
admdstCd: normalizeGridString(d.admdstCd),
|
||||||
sggNm: nullableTrimmedString(d.sggNm),
|
sggNm: normalizeGridString(d.sggNm),
|
||||||
admdstNm: nullableTrimmedString(d.admdstNm),
|
admdstNm: normalizeGridString(d.admdstNm),
|
||||||
cnterGovSprtAmt: formatNumber(d.cnterGovSprtAmt, "cnterGovSprtAmt"),
|
cnterGovSprtAmt: formatNumber(d.cnterGovSprtAmt, "cnterGovSprtAmt"),
|
||||||
mctpvLcexpAmt: formatNumber(d.mctpvLcexpAmt, "mctpvLcexpAmt"),
|
mctpvLcexpAmt: formatNumber(d.mctpvLcexpAmt, "mctpvLcexpAmt"),
|
||||||
wareaSggLclAmt: formatNumber(d.wareaSggLclAmt, "wareaSggLclAmt"),
|
wareaSggLclAmt: formatNumber(d.wareaSggLclAmt, "wareaSggLclAmt"),
|
||||||
@@ -240,7 +238,7 @@ function buildSewerageFinanceSettleSaveList(
|
|||||||
etcAcdntCrfwAmt: formatNumber(d.etcAcdntCrfwAmt, "etcAcdntCrfwAmt"),
|
etcAcdntCrfwAmt: formatNumber(d.etcAcdntCrfwAmt, "etcAcdntCrfwAmt"),
|
||||||
etcNrcpAmt: formatNumber(d.etcNrcpAmt, "etcNrcpAmt"),
|
etcNrcpAmt: formatNumber(d.etcNrcpAmt, "etcNrcpAmt"),
|
||||||
etcAmt: formatNumber(d.etcAmt, "etcAmt"),
|
etcAmt: formatNumber(d.etcAmt, "etcAmt"),
|
||||||
rmrk: nullableTrimmedString(d.rmrk),
|
rmrk: normalizeGridRmrk(d.rmrk),
|
||||||
fnnByWholPjtcoAmt: formatNumber(d.fnnByWholPjtcoAmt, "fnnByWholPjtcoAmt"),
|
fnnByWholPjtcoAmt: formatNumber(d.fnnByWholPjtcoAmt, "fnnByWholPjtcoAmt"),
|
||||||
usgByWholPjtcoAmt: formatNumber(d.usgByWholPjtcoAmt, "usgByWholPjtcoAmt"),
|
usgByWholPjtcoAmt: formatNumber(d.usgByWholPjtcoAmt, "usgByWholPjtcoAmt"),
|
||||||
tmplntWholAmt: formatNumber(d.tmplntWholAmt, "tmplntWholAmt"),
|
tmplntWholAmt: formatNumber(d.tmplntWholAmt, "tmplntWholAmt"),
|
||||||
@@ -256,13 +254,13 @@ function buildSewerageChargeSaveList(
|
|||||||
const formatNumber = buildColumnFormatNumber(SewerageChargeInpColumn.columns);
|
const formatNumber = buildColumnFormatNumber(SewerageChargeInpColumn.columns);
|
||||||
|
|
||||||
return currentData.map((d) => ({
|
return currentData.map((d) => ({
|
||||||
admdstCd: nullableTrimmedString(d.admdstCd),
|
admdstCd: normalizeGridString(d.admdstCd),
|
||||||
sggNm: nullableTrimmedString(d.sggNm),
|
sggNm: normalizeGridString(d.sggNm),
|
||||||
admdstNm: nullableTrimmedString(d.admdstNm),
|
admdstNm: normalizeGridString(d.admdstNm),
|
||||||
anlLevyQnt: formatNumber(d.anlLevyQnt, "anlLevyQnt"),
|
anlLevyQnt: formatNumber(d.anlLevyQnt, "anlLevyQnt"),
|
||||||
levyAmt: formatNumber(d.levyAmt, "levyAmt"),
|
levyAmt: formatNumber(d.levyAmt, "levyAmt"),
|
||||||
grssPrmcoAmt: formatNumber(d.grssPrmcoAmt, "grssPrmcoAmt"),
|
grssPrmcoAmt: formatNumber(d.grssPrmcoAmt, "grssPrmcoAmt"),
|
||||||
rmrk: nullableTrimmedString(d.rmrk),
|
rmrk: normalizeGridRmrk(d.rmrk),
|
||||||
avgUntprcAmt: formatNumber(d.avgUntprcAmt, "avgUntprcAmt"),
|
avgUntprcAmt: formatNumber(d.avgUntprcAmt, "avgUntprcAmt"),
|
||||||
grssUnitPrmcoAmt: formatNumber(d.grssUnitPrmcoAmt, "grssUnitPrmcoAmt"),
|
grssUnitPrmcoAmt: formatNumber(d.grssUnitPrmcoAmt, "grssUnitPrmcoAmt"),
|
||||||
rlztnRt: formatNumber(d.rlztnRt, "rlztnRt"),
|
rlztnRt: formatNumber(d.rlztnRt, "rlztnRt"),
|
||||||
@@ -275,9 +273,9 @@ function buildSewerageUsageFeeSaveList(
|
|||||||
const formatNumber = buildColumnFormatNumber(SewerageUsageFeeInpColumn.columns);
|
const formatNumber = buildColumnFormatNumber(SewerageUsageFeeInpColumn.columns);
|
||||||
|
|
||||||
return currentData.map((d) => ({
|
return currentData.map((d) => ({
|
||||||
admdstCd: nullableTrimmedString(d.admdstCd),
|
admdstCd: normalizeGridString(d.admdstCd),
|
||||||
sggNm: nullableTrimmedString(d.sggNm),
|
sggNm: normalizeGridString(d.sggNm),
|
||||||
admdstNm: nullableTrimmedString(d.admdstNm),
|
admdstNm: normalizeGridString(d.admdstNm),
|
||||||
hshusLevyAmt: formatNumber(d.hshusLevyAmt, "hshusLevyAmt"),
|
hshusLevyAmt: formatNumber(d.hshusLevyAmt, "hshusLevyAmt"),
|
||||||
hshusLevyQnt: formatNumber(d.hshusLevyQnt, "hshusLevyQnt"),
|
hshusLevyQnt: formatNumber(d.hshusLevyQnt, "hshusLevyQnt"),
|
||||||
hshusUntprcAmt: formatNumber(d.hshusUntprcAmt, "hshusUntprcAmt"),
|
hshusUntprcAmt: formatNumber(d.hshusUntprcAmt, "hshusUntprcAmt"),
|
||||||
@@ -299,7 +297,7 @@ function buildSewerageUsageFeeSaveList(
|
|||||||
etcLevyAmt: formatNumber(d.etcLevyAmt, "etcLevyAmt"),
|
etcLevyAmt: formatNumber(d.etcLevyAmt, "etcLevyAmt"),
|
||||||
etcLevyQnt: formatNumber(d.etcLevyQnt, "etcLevyQnt"),
|
etcLevyQnt: formatNumber(d.etcLevyQnt, "etcLevyQnt"),
|
||||||
etcLevyUntprcAmt: formatNumber(d.etcLevyUntprcAmt, "etcLevyUntprcAmt"),
|
etcLevyUntprcAmt: formatNumber(d.etcLevyUntprcAmt, "etcLevyUntprcAmt"),
|
||||||
rmrk: nullableTrimmedString(d.rmrk),
|
rmrk: normalizeGridRmrk(d.rmrk),
|
||||||
levyAmt: formatNumber(d.levyAmt, "levyAmt"),
|
levyAmt: formatNumber(d.levyAmt, "levyAmt"),
|
||||||
levyQnt: formatNumber(d.levyQnt, "levyQnt"),
|
levyQnt: formatNumber(d.levyQnt, "levyQnt"),
|
||||||
}));
|
}));
|
||||||
@@ -311,16 +309,16 @@ function buildCauserBurdenSaveList(
|
|||||||
const formatNumber = buildColumnFormatNumber(CauserBurdenInpColumn.columns);
|
const formatNumber = buildColumnFormatNumber(CauserBurdenInpColumn.columns);
|
||||||
|
|
||||||
return currentData.map((d) => ({
|
return currentData.map((d) => ({
|
||||||
admdstCd: nullableTrimmedString(d.admdstCd),
|
admdstCd: normalizeGridString(d.admdstCd),
|
||||||
sggNm: nullableTrimmedString(d.sggNm),
|
sggNm: normalizeGridString(d.sggNm),
|
||||||
admdstNm: nullableTrimmedString(d.admdstNm),
|
admdstNm: normalizeGridString(d.admdstNm),
|
||||||
levyEvntcsCnt: formatNumber(d.levyEvntcsCnt, "levyEvntcsCnt"),
|
levyEvntcsCnt: formatNumber(d.levyEvntcsCnt, "levyEvntcsCnt"),
|
||||||
levyAmt: formatNumber(d.levyAmt, "levyAmt"),
|
levyAmt: formatNumber(d.levyAmt, "levyAmt"),
|
||||||
mltvEqpmEvntcsCnt: formatNumber(d.mltvEqpmEvntcsCnt, "mltvEqpmEvntcsCnt"),
|
mltvEqpmEvntcsCnt: formatNumber(d.mltvEqpmEvntcsCnt, "mltvEqpmEvntcsCnt"),
|
||||||
mltvEqpmAmt: formatNumber(d.mltvEqpmAmt, "mltvEqpmAmt"),
|
mltvEqpmAmt: formatNumber(d.mltvEqpmAmt, "mltvEqpmAmt"),
|
||||||
othrCstrnOthrActrCnt: formatNumber(d.othrCstrnOthrActrCnt, "othrCstrnOthrActrCnt"),
|
othrCstrnOthrActrCnt: formatNumber(d.othrCstrnOthrActrCnt, "othrCstrnOthrActrCnt"),
|
||||||
othrCstrnOthrActrAmt: formatNumber(d.othrCstrnOthrActrAmt, "othrCstrnOthrActrAmt"),
|
othrCstrnOthrActrAmt: formatNumber(d.othrCstrnOthrActrAmt, "othrCstrnOthrActrAmt"),
|
||||||
rmrk: nullableTrimmedString(d.rmrk),
|
rmrk: normalizeGridRmrk(d.rmrk),
|
||||||
trgtByWholClctnAmt: formatNumber(d.trgtByWholClctnAmt, "trgtByWholClctnAmt"),
|
trgtByWholClctnAmt: formatNumber(d.trgtByWholClctnAmt, "trgtByWholClctnAmt"),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -343,17 +341,15 @@ async function waitForImrJobCompleted(
|
|||||||
options?.onProgress?.(Math.max(0, Math.min(100, Number(res.job_prog) || 0)));
|
options?.onProgress?.(Math.max(0, Math.min(100, Number(res.job_prog) || 0)));
|
||||||
if (res.status === "COMPLETED" && Number(res.job_prog) === 100) return;
|
if (res.status === "COMPLETED" && Number(res.job_prog) === 100) return;
|
||||||
if (res.status === "FAILED" || res.status === "ERROR" || res.status === "CANCELLED") {
|
if (res.status === "FAILED" || res.status === "ERROR" || res.status === "CANCELLED") {
|
||||||
throw new Error(res.error_msg || `시계열 검증이 ${res.status} 상태로 종료되었습니다.`);
|
throw new Error(res.error_msg || `IMR 검증이 ${res.status} 상태로 종료되었습니다.`);
|
||||||
}
|
}
|
||||||
await sleep(pollIntervalMs);
|
await sleep(pollIntervalMs);
|
||||||
}
|
}
|
||||||
throw new Error("시계열 검증 완료 대기 시간이 초과되었습니다.");
|
throw new Error("IMR 검증 완료 대기 시간이 초과되었습니다.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 하수도 통계 관리 > 09. 하수도재정
|
// 하수도 통계 관리 > 09. 하수도재정
|
||||||
const SewerageFinanceInp = () => {
|
const SewerageFinanceInp = () => {
|
||||||
const { sidoList } = useSearchConditionSidoList({ isInput: true });
|
|
||||||
sidoListRef.current = sidoList;
|
|
||||||
const { setMessage: alert } = useAlertStore((state) => state);
|
const { setMessage: alert } = useAlertStore((state) => state);
|
||||||
const { confirm } = useConfirm();
|
const { confirm } = useConfirm();
|
||||||
const { isAdminInfo } = useAdminStore();
|
const { isAdminInfo } = useAdminStore();
|
||||||
@@ -378,15 +374,9 @@ const SewerageFinanceInp = () => {
|
|||||||
const [isVerificationFailedByTab, setIsVerificationFailedByTab] = useState<
|
const [isVerificationFailedByTab, setIsVerificationFailedByTab] = useState<
|
||||||
Map<string, boolean>
|
Map<string, boolean>
|
||||||
>(new Map());
|
>(new Map());
|
||||||
const [footerVerificationByTab, setFooterVerificationByTab] = useState<
|
const [toolbarSnapshotByTab, setToolbarSnapshotByTab] = useState<
|
||||||
Map<string, VerificationResultLikeMap | null>
|
|
||||||
>(new Map());
|
|
||||||
const [_toolbarSnapshotByTab, setToolbarSnapshotByTab] = useState<
|
|
||||||
Map<string, TabToolbarSnapshot>
|
Map<string, TabToolbarSnapshot>
|
||||||
>(new Map());
|
>(new Map());
|
||||||
const [searchContextByTab, setSearchContextByTab] = useState<Map<string, SearchFormValues>>(
|
|
||||||
() => new Map(),
|
|
||||||
);
|
|
||||||
const [columnGuidesByTab, setColumnGuidesByTab] = useState<
|
const [columnGuidesByTab, setColumnGuidesByTab] = useState<
|
||||||
Record<string, Record<string, string>>
|
Record<string, Record<string, string>>
|
||||||
>({});
|
>({});
|
||||||
@@ -401,29 +391,35 @@ const SewerageFinanceInp = () => {
|
|||||||
const getGridDataRef = useRef<(() => Record<string, string | number>[]) | null>(null);
|
const getGridDataRef = useRef<(() => Record<string, string | number>[]) | null>(null);
|
||||||
activeTabRef.current = activeTab;
|
activeTabRef.current = activeTab;
|
||||||
|
|
||||||
const activeTabId = useTabStore((s) => s.activeTabId);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeTabId !== STATISTICS_INPUT_URL_PATH.SEWERAGE_FINANCE) return;
|
|
||||||
const tabKey = activeTab;
|
|
||||||
if (!tabKey) return;
|
|
||||||
if (Object.prototype.hasOwnProperty.call(columnGuidesByTab, tabKey)) return;
|
|
||||||
const statsCd = tabKey;
|
|
||||||
|
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
void (async () => {
|
void (async () => {
|
||||||
const next = await fetchColumnGuidesRecord(statsCd);
|
const entries = await Promise.all(
|
||||||
if (cancelled) return;
|
SEWERAGE_FINANCE_COLUMN_GUIDE_TAB_KEYS.map(async (tabKey) => {
|
||||||
setColumnGuidesByTab((prev) =>
|
try {
|
||||||
Object.prototype.hasOwnProperty.call(prev, tabKey)
|
const res = await statisticsApi.getColumnGuides(tabKey);
|
||||||
? prev
|
if (res.status !== "success" || !Array.isArray(res.data)) {
|
||||||
: { ...prev, [tabKey]: next },
|
return [tabKey, {}] as const;
|
||||||
|
}
|
||||||
|
const next: Record<string, string> = {};
|
||||||
|
for (const item of res.data) {
|
||||||
|
const key = item.engColNm?.trim();
|
||||||
|
const guide = item.columnGuide?.trim();
|
||||||
|
if (key && guide) next[key] = guide;
|
||||||
|
}
|
||||||
|
return [tabKey, next] as const;
|
||||||
|
} catch {
|
||||||
|
return [tabKey, {}] as const;
|
||||||
|
}
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
if (cancelled) return;
|
||||||
|
setColumnGuidesByTab(Object.fromEntries(entries));
|
||||||
})();
|
})();
|
||||||
return () => {
|
return () => {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
};
|
};
|
||||||
}, [activeTabId, activeTab, columnGuidesByTab]);
|
}, []);
|
||||||
|
|
||||||
const commitToolbarSnapshotForLoadedTab = (
|
const commitToolbarSnapshotForLoadedTab = (
|
||||||
tabKey: string,
|
tabKey: string,
|
||||||
@@ -446,13 +442,6 @@ const SewerageFinanceInp = () => {
|
|||||||
);
|
);
|
||||||
return next;
|
return next;
|
||||||
});
|
});
|
||||||
if (searchContext) {
|
|
||||||
setSearchContextByTab((prev) => {
|
|
||||||
const next = new Map(prev);
|
|
||||||
next.set(tabKey, searchContext);
|
|
||||||
return next;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const applyRowMap = (
|
const applyRowMap = (
|
||||||
@@ -493,7 +482,6 @@ const SewerageFinanceInp = () => {
|
|||||||
const gridRows = mapRegionalListToGridRows(
|
const gridRows = mapRegionalListToGridRows(
|
||||||
(sewerageFinanceSettleList ?? []) as SewerageFinanceSettleItem[],
|
(sewerageFinanceSettleList ?? []) as SewerageFinanceSettleItem[],
|
||||||
commonInfo.ctpvNm,
|
commonInfo.ctpvNm,
|
||||||
searchContext,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
applyRowMap(mergeIntoExistingMap, (m) => {
|
applyRowMap(mergeIntoExistingMap, (m) => {
|
||||||
@@ -504,9 +492,6 @@ const SewerageFinanceInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
||||||
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
||||||
return true;
|
return true;
|
||||||
@@ -523,7 +508,6 @@ const SewerageFinanceInp = () => {
|
|||||||
const gridRows = mapRegionalListToGridRows(
|
const gridRows = mapRegionalListToGridRows(
|
||||||
(sewerageChargeList ?? []) as SewerageChargeItem[],
|
(sewerageChargeList ?? []) as SewerageChargeItem[],
|
||||||
commonInfo.ctpvNm,
|
commonInfo.ctpvNm,
|
||||||
searchContext,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
applyRowMap(mergeIntoExistingMap, (m) => {
|
applyRowMap(mergeIntoExistingMap, (m) => {
|
||||||
@@ -534,9 +518,6 @@ const SewerageFinanceInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
||||||
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
||||||
return true;
|
return true;
|
||||||
@@ -553,7 +534,6 @@ const SewerageFinanceInp = () => {
|
|||||||
const gridRows = mapRegionalListToGridRows(
|
const gridRows = mapRegionalListToGridRows(
|
||||||
(sewerageUsageFeeList ?? []) as SewerageUsageFeeItem[],
|
(sewerageUsageFeeList ?? []) as SewerageUsageFeeItem[],
|
||||||
commonInfo.ctpvNm,
|
commonInfo.ctpvNm,
|
||||||
searchContext,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
applyRowMap(mergeIntoExistingMap, (m) => {
|
applyRowMap(mergeIntoExistingMap, (m) => {
|
||||||
@@ -564,9 +544,6 @@ const SewerageFinanceInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
||||||
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
||||||
return true;
|
return true;
|
||||||
@@ -583,7 +560,6 @@ const SewerageFinanceInp = () => {
|
|||||||
const gridRows = mapRegionalListToGridRows(
|
const gridRows = mapRegionalListToGridRows(
|
||||||
(causerBurdenList ?? []) as CauserBurdenItem[],
|
(causerBurdenList ?? []) as CauserBurdenItem[],
|
||||||
commonInfo.ctpvNm,
|
commonInfo.ctpvNm,
|
||||||
searchContext,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
applyRowMap(mergeIntoExistingMap, (m) => {
|
applyRowMap(mergeIntoExistingMap, (m) => {
|
||||||
@@ -594,9 +570,6 @@ const SewerageFinanceInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
||||||
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
||||||
return true;
|
return true;
|
||||||
@@ -614,9 +587,7 @@ const SewerageFinanceInp = () => {
|
|||||||
setTabStatusInfoMap(new Map());
|
setTabStatusInfoMap(new Map());
|
||||||
setTabStatsCdMap(new Map());
|
setTabStatsCdMap(new Map());
|
||||||
setIsVerificationFailedByTab(new Map());
|
setIsVerificationFailedByTab(new Map());
|
||||||
setFooterVerificationByTab(new Map());
|
|
||||||
setToolbarSnapshotByTab(new Map());
|
setToolbarSnapshotByTab(new Map());
|
||||||
setSearchContextByTab(new Map());
|
|
||||||
setActiveTab(firstTabKey);
|
setActiveTab(firstTabKey);
|
||||||
activeTabRef.current = firstTabKey;
|
activeTabRef.current = firstTabKey;
|
||||||
setLastSearchedValues(null);
|
setLastSearchedValues(null);
|
||||||
@@ -658,9 +629,7 @@ const SewerageFinanceInp = () => {
|
|||||||
setTabStatusInfoMap(new Map());
|
setTabStatusInfoMap(new Map());
|
||||||
setTabStatsCdMap(new Map());
|
setTabStatsCdMap(new Map());
|
||||||
setIsVerificationFailedByTab(new Map());
|
setIsVerificationFailedByTab(new Map());
|
||||||
setFooterVerificationByTab(new Map());
|
|
||||||
setToolbarSnapshotByTab(new Map());
|
setToolbarSnapshotByTab(new Map());
|
||||||
setSearchContextByTab(new Map());
|
|
||||||
activeTabRef.current = firstTabKey;
|
activeTabRef.current = firstTabKey;
|
||||||
setActiveTab(firstTabKey);
|
setActiveTab(firstTabKey);
|
||||||
}
|
}
|
||||||
@@ -770,8 +739,12 @@ const SewerageFinanceInp = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const requestData: cancelSubmitRequest = {
|
const requestData: cancelSubmitRequest = {
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
mdfrId: userInfo.userUnqId,
|
mdfrId: userInfo.userUnqId,
|
||||||
statsCd: statsCdForTab,
|
statsCd: statsCdForTab,
|
||||||
@@ -854,7 +827,11 @@ const SewerageFinanceInp = () => {
|
|||||||
const submitInfoBase = {
|
const submitInfoBase = {
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
laePicNm: submitInfo.laePicNm,
|
laePicNm: submitInfo.laePicNm,
|
||||||
laePicTelNo: submitInfo.laePicTelNo,
|
laePicTelNo: submitInfo.laePicTelNo,
|
||||||
laeKbrdrDeptNm: submitInfo.laeKbrdrDeptNm,
|
laeKbrdrDeptNm: submitInfo.laeKbrdrDeptNm,
|
||||||
@@ -866,8 +843,12 @@ const SewerageFinanceInp = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const verificationQuery = {
|
const verificationQuery = {
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
statsCd: statsCdForTab,
|
statsCd: statsCdForTab,
|
||||||
};
|
};
|
||||||
@@ -937,15 +918,14 @@ const SewerageFinanceInp = () => {
|
|||||||
|
|
||||||
if (finalStatus === "5") {
|
if (finalStatus === "5") {
|
||||||
setGlobalProgress(50);
|
setGlobalProgress(50);
|
||||||
setGlobalProgressLabel("시계열 검증 진행 중...");
|
setGlobalProgressLabel("IMR 검증 진행 중...");
|
||||||
const imrParam = {
|
const imrParam = {
|
||||||
user_id: userInfo.userUnqId,
|
user_id: userInfo.userUnqId,
|
||||||
sewer_bzmn_cd: lastSearchedValues?.bsnmCd ?? "",
|
sewer_bzmn_cd: lastSearchedValues.bsnmCd ?? "",
|
||||||
stats_cd: statsCdForTab,
|
stats_cd: statsCdForTab,
|
||||||
stats_yr: lastSearchedValues.year ?? "",
|
stats_yr: lastSearchedValues.year ?? "",
|
||||||
lae_sbmsn_stts_cd: activeTabStatus?.laeSbmsnSttsCd === "4" ? "4" : "2",
|
lae_sbmsn_stts_cd: activeTabStatus?.laeSbmsnSttsCd === "4" ? "4" : "2",
|
||||||
gen_verify_stts_cd: nvpassed ? "1" : "2",
|
gen_verify_stts_cd: nvpassed ? "1" : "2",
|
||||||
hb_pass_yn: response.data?.isHbPassed,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -1029,7 +1009,11 @@ const SewerageFinanceInp = () => {
|
|||||||
const baseRequest = {
|
const baseRequest = {
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -1150,8 +1134,9 @@ const SewerageFinanceInp = () => {
|
|||||||
const statsCd = tabStatsCdMap.get(activeTab);
|
const statsCd = tabStatsCdMap.get(activeTab);
|
||||||
if (!ctx?.year || !ctx?.sido || !ctx?.bsnmCd || !statsCd) return null;
|
if (!ctx?.year || !ctx?.sido || !ctx?.bsnmCd || !statsCd) return null;
|
||||||
return {
|
return {
|
||||||
...toInputSearchRegion(sidoListRef.current, ctx),
|
sewerBzmnCd: ctx.bsnmCd,
|
||||||
ctpvNm: ctx.sido,
|
ctpvNm: ctx.sido,
|
||||||
|
sggNm: ctx.gugun === "ALL" ? "" : (ctx.gugun ?? ""),
|
||||||
statsYr: ctx.year,
|
statsYr: ctx.year,
|
||||||
statsCd,
|
statsCd,
|
||||||
};
|
};
|
||||||
@@ -1162,10 +1147,10 @@ const SewerageFinanceInp = () => {
|
|||||||
for (const tab of SewerageFinanceInpTabList) {
|
for (const tab of SewerageFinanceInpTabList) {
|
||||||
const tabKey = tab.tabKey;
|
const tabKey = tab.tabKey;
|
||||||
const canEdit =
|
const canEdit =
|
||||||
(computeTabEnterable(
|
computeTabEnterable(
|
||||||
tabStatusInfoMap.get(tabKey) ?? null,
|
tabStatusInfoMap.get(tabKey) ?? null,
|
||||||
inputPeriodEnterable,
|
inputPeriodEnterable,
|
||||||
) || isAdminInfo) && inputPeriodEnterable;
|
) || isAdminInfo;
|
||||||
const rawColumns = (tab.columns ?? []) as ColumnConfig[];
|
const rawColumns = (tab.columns ?? []) as ColumnConfig[];
|
||||||
const base = canEdit
|
const base = canEdit
|
||||||
? rawColumns
|
? rawColumns
|
||||||
@@ -1182,20 +1167,19 @@ const SewerageFinanceInp = () => {
|
|||||||
return map;
|
return map;
|
||||||
}, [tabStatusInfoMap, inputPeriodEnterable, isAdminInfo, columnGuidesByTab]);
|
}, [tabStatusInfoMap, inputPeriodEnterable, isAdminInfo, columnGuidesByTab]);
|
||||||
|
|
||||||
const searchContextForToolbar = searchContextByTab.get(activeTab) ?? lastSearchedValues;
|
|
||||||
const activeTabStatus = tabStatusInfoMap.get(activeTab) ?? null;
|
const activeTabStatus = tabStatusInfoMap.get(activeTab) ?? null;
|
||||||
const activeTabToolbar =
|
const activeTabToolbar =
|
||||||
|
toolbarSnapshotByTab.get(activeTab) ??
|
||||||
computeTabToolbarSnapshot(
|
computeTabToolbarSnapshot(
|
||||||
activeTabStatus,
|
activeTabStatus,
|
||||||
tabRowDataExists(rowDataMap, activeTab),
|
tabRowDataExists(rowDataMap, activeTab),
|
||||||
hasSearched,
|
hasSearched,
|
||||||
searchContextForToolbar,
|
lastSearchedValues,
|
||||||
inputPeriodEnterable,
|
inputPeriodEnterable,
|
||||||
isAdminInfo,
|
isAdminInfo,
|
||||||
);
|
);
|
||||||
const { showSaveInToolbar, showEnterableToolbarButtons, showActionToolbarCard } =
|
const { showSaveInToolbar, showEnterableToolbarButtons, showActionToolbarCard } =
|
||||||
activeTabToolbar;
|
activeTabToolbar;
|
||||||
const submitOk = buildSubmitOkForToolbar(searchContextForToolbar);
|
|
||||||
|
|
||||||
const verificationCellStyle = ({
|
const verificationCellStyle = ({
|
||||||
fieldName,
|
fieldName,
|
||||||
@@ -1228,10 +1212,10 @@ const SewerageFinanceInp = () => {
|
|||||||
.map((e) => {
|
.map((e) => {
|
||||||
const prefix =
|
const prefix =
|
||||||
e.vrfcCd === "IMR"
|
e.vrfcCd === "IMR"
|
||||||
? "시계열 검증 - "
|
? "IMR검증 - "
|
||||||
: e.vrfcCd === "NV"
|
: e.vrfcCd === "NV"
|
||||||
? "일반검증 - "
|
? "일반검증 - "
|
||||||
: "모집단 검증 - ";
|
: "HB검증 - ";
|
||||||
return `${prefix}${e.rsnExpln}(검증 기준값: ${e.compVlCn} / 현재 입력값: ${e.nowVlCn})`;
|
return `${prefix}${e.rsnExpln}(검증 기준값: ${e.compVlCn} / 현재 입력값: ${e.nowVlCn})`;
|
||||||
})
|
})
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
@@ -1254,7 +1238,6 @@ const SewerageFinanceInp = () => {
|
|||||||
<>
|
<>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<SearchForm
|
<SearchForm
|
||||||
isInput
|
|
||||||
key={searchFormRemountKey}
|
key={searchFormRemountKey}
|
||||||
defaultValues={verificationSearchDefaults ?? undefined}
|
defaultValues={verificationSearchDefaults ?? undefined}
|
||||||
onSubmit={handleSearch}
|
onSubmit={handleSearch}
|
||||||
@@ -1262,8 +1245,8 @@ const SewerageFinanceInp = () => {
|
|||||||
onValuesChange={setSearchValues}
|
onValuesChange={setSearchValues}
|
||||||
/>
|
/>
|
||||||
{showActionToolbarCard && (
|
{showActionToolbarCard && (
|
||||||
<div className="card !py-0">
|
<div className="card !py-0">
|
||||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||||
<VerificationResultButton
|
<VerificationResultButton
|
||||||
VerificationResultButtonFunc={openVerificationHistoryDialog}
|
VerificationResultButtonFunc={openVerificationHistoryDialog}
|
||||||
isVerificationFailed={
|
isVerificationFailed={
|
||||||
@@ -1275,10 +1258,10 @@ const SewerageFinanceInp = () => {
|
|||||||
<LastYearDataButton
|
<LastYearDataButton
|
||||||
getLastYearDataFunc={() => void lastYearDataFunc()}
|
getLastYearDataFunc={() => void lastYearDataFunc()}
|
||||||
/>
|
/>
|
||||||
{submitOk && <SubmitButton submitFunc={submitFunc} />}
|
<SubmitButton submitFunc={submitFunc} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{activeTabStatus?.laeSbmsnSttsCd === "2" && submitOk && (
|
{activeTabStatus?.laeSbmsnSttsCd === "2" && (
|
||||||
<CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />
|
<CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />
|
||||||
)}
|
)}
|
||||||
{showSaveInToolbar && <SaveButton saveFunc={saveFunc} />}
|
{showSaveInToolbar && <SaveButton saveFunc={saveFunc} />}
|
||||||
@@ -1310,11 +1293,11 @@ const SewerageFinanceInp = () => {
|
|||||||
const tabKey = info.tabKey;
|
const tabKey = info.tabKey;
|
||||||
const rowData = rowDataMap.get(tabKey) ?? [];
|
const rowData = rowDataMap.get(tabKey) ?? [];
|
||||||
const tabEnterableForGrid =
|
const tabEnterableForGrid =
|
||||||
(computeTabEnterable(
|
computeTabEnterable(
|
||||||
tabStatusInfoMap.get(tabKey) ?? null,
|
tabStatusInfoMap.get(tabKey) ?? null,
|
||||||
inputPeriodEnterable,
|
inputPeriodEnterable,
|
||||||
) || isAdminInfo) && inputPeriodEnterable;
|
) || isAdminInfo;
|
||||||
const gugunOk = buildGugunOkForToolbar(searchContextForToolbar);
|
const gugunOk = buildGugunOkForToolbar(lastSearchedValues);
|
||||||
const tabStatusInfo = tabStatusInfoMap.get(tabKey) ?? null;
|
const tabStatusInfo = tabStatusInfoMap.get(tabKey) ?? null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -1352,9 +1335,6 @@ const SewerageFinanceInp = () => {
|
|||||||
excelExportSearchContext={toExcelExportSearchContextFromSearchForm(lastSearchedValues ?? searchValues)}
|
excelExportSearchContext={toExcelExportSearchContextFromSearchForm(lastSearchedValues ?? searchValues)}
|
||||||
isExcelExport
|
isExcelExport
|
||||||
cellStyleCallback={verificationCellStyle}
|
cellStyleCallback={verificationCellStyle}
|
||||||
footerVerificationResult={
|
|
||||||
footerVerificationByTab.get(tabKey) ?? null
|
|
||||||
}
|
|
||||||
cellTooltipCallback={verificationCellTooltip}
|
cellTooltipCallback={verificationCellTooltip}
|
||||||
getGridDataRef={
|
getGridDataRef={
|
||||||
activeTab === tabKey ? getGridDataRef : undefined
|
activeTab === tabKey ? getGridDataRef : undefined
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|||||||
|
|
||||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||||
|
|
||||||
import { useAlertStore, useGlobalProgressStore, useSearchConditionSidoList, useStatisticsInputToolbarGroupGate } from "@/shared/lib";
|
import { useAlertStore, useGlobalProgressStore, useStatisticsInputToolbarGroupGate } from "@/shared/lib";
|
||||||
import {
|
import {
|
||||||
STATISTICS_INPUT_URL_PATH,
|
STATISTICS_INPUT_URL_PATH,
|
||||||
verificationSearchToFormValues,
|
verificationSearchToFormValues,
|
||||||
@@ -25,15 +25,8 @@ import type {
|
|||||||
cancelSubmitRequest,
|
cancelSubmitRequest,
|
||||||
ImrStatusResponse,
|
ImrStatusResponse,
|
||||||
SewerageStatusInfo,
|
SewerageStatusInfo,
|
||||||
Sido,
|
|
||||||
SubmitExceptionRequest,
|
SubmitExceptionRequest,
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
} from "@/entities/statistics/model/statistics-interface";
|
||||||
import {
|
|
||||||
filterBySelectedAdmdstCd,
|
|
||||||
isGugunOkForToolbar,
|
|
||||||
isSubmitOkForToolbar,
|
|
||||||
toInputSearchRegion,
|
|
||||||
} from "@/entities/statistics";
|
|
||||||
import { LoadingWithAnimation } from "@common/components";
|
import { LoadingWithAnimation } from "@common/components";
|
||||||
|
|
||||||
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
||||||
@@ -47,18 +40,17 @@ import SubmitButton from "@/components/button/SumitButton";
|
|||||||
import VerificationResultButton from "@/components/button/VerificationResultButton";
|
import VerificationResultButton from "@/components/button/VerificationResultButton";
|
||||||
// import { DataGrid } from "@rsone/components";
|
// import { DataGrid } from "@rsone/components";
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
import { openVerificationResultDialogIfNeeded } from "@/components/module/post-submit-verification-results";
|
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
|
import { openVerificationResultDialogIfNeeded } from "@/components/module/post-submit-verification-results";
|
||||||
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
||||||
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
|
import { doList } from "@/components/util/column/input/DoList";
|
||||||
import { SeweragePenetrationRateInpColumn } from "@/components/util/column/input/SeweragePenetrationRateInpColumn";
|
import { SeweragePenetrationRateInpColumn } from "@/components/util/column/input/SeweragePenetrationRateInpColumn";
|
||||||
import { getFooterSummary } from "@/components/util/grid/footerSummary";
|
import { getFooterSummary } from "@/components/util/grid/footerSummary";
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
|
||||||
import { nullableTrimmedString } from "@/components/util/input/nullableString";
|
|
||||||
import { isVerificationFailedFromCommonInfo } from "@/components/util/input/verification-failed-flag";
|
import { isVerificationFailedFromCommonInfo } from "@/components/util/input/verification-failed-flag";
|
||||||
import type { VerificationResultLikeMap } from "@/components/util/input/verification-result-display";
|
|
||||||
import { useAdminStore } from "@/store/admin-store";
|
import { useAdminStore } from "@/store/admin-store";
|
||||||
import { useStatisticsInputFocusStore } from "@/store/statistics-input-focus-store";
|
import { useStatisticsInputFocusStore } from "@/store/statistics-input-focus-store";
|
||||||
import { useTabStore } from "@/store/tab-store";
|
import { useTabStore } from "@/store/tab-store";
|
||||||
@@ -68,28 +60,6 @@ type GridRowWithVerification = Record<string, string | number> & {
|
|||||||
verificationResult?: SewerageSupplyRateVerificationResult;
|
verificationResult?: SewerageSupplyRateVerificationResult;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** commonInfo 푸터 필드명 → 그리드 fieldName */
|
|
||||||
const FOOTER_VERIFY_FIELD_ALIASES: Record<string, string> = {
|
|
||||||
sewerBzmnWholPpltnCnt: "pbadmsWholPpltnCnt",
|
|
||||||
sewerBzmnDomplWholPpltnCnt: "domplWholPpltnCnt",
|
|
||||||
sewerBzmnFrgnrWholPpltnCnt: "frgnrWholPpltnCnt",
|
|
||||||
sewerBzmnArea: "refArea",
|
|
||||||
};
|
|
||||||
|
|
||||||
const remapCommonInfoVerificationToGridFields = (
|
|
||||||
result: SewerageSupplyRateVerificationResult | null | undefined,
|
|
||||||
): VerificationResultLikeMap | null => {
|
|
||||||
if (!result) return null;
|
|
||||||
const remapped: VerificationResultLikeMap = {};
|
|
||||||
for (const [key, errors] of Object.entries(result)) {
|
|
||||||
const gridField = FOOTER_VERIFY_FIELD_ALIASES[key] ?? key;
|
|
||||||
remapped[gridField] = errors;
|
|
||||||
// API 키로도 조회 가능하도록 유지
|
|
||||||
if (gridField !== key) remapped[key] = errors;
|
|
||||||
}
|
|
||||||
return remapped;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 컬럼 가이드 API 조회용 통계코드 (하수도 보급률) */
|
/** 컬럼 가이드 API 조회용 통계코드 (하수도 보급률) */
|
||||||
const SEWERAGE_PENETRATION_COLUMN_GUIDE_STATS_CD = "ST00010001";
|
const SEWERAGE_PENETRATION_COLUMN_GUIDE_STATS_CD = "ST00010001";
|
||||||
|
|
||||||
@@ -117,31 +87,36 @@ async function waitForImrJobCompleted(
|
|||||||
options?.onProgress?.(Math.max(0, Math.min(100, Number(res.job_prog) || 0)));
|
options?.onProgress?.(Math.max(0, Math.min(100, Number(res.job_prog) || 0)));
|
||||||
if (res.status === "COMPLETED" && Number(res.job_prog) === 100) return;
|
if (res.status === "COMPLETED" && Number(res.job_prog) === 100) return;
|
||||||
if (res.status === "FAILED" || res.status === "ERROR" || res.status === "CANCELLED") {
|
if (res.status === "FAILED" || res.status === "ERROR" || res.status === "CANCELLED") {
|
||||||
throw new Error(res.error_msg || `시계열 검증이 ${res.status} 상태로 종료되었습니다.`);
|
throw new Error(res.error_msg || `IMR 검증이 ${res.status} 상태로 종료되었습니다.`);
|
||||||
}
|
}
|
||||||
await sleep(pollIntervalMs);
|
await sleep(pollIntervalMs);
|
||||||
}
|
}
|
||||||
throw new Error("시계열 검증 완료 대기 시간이 초과되었습니다.");
|
throw new Error("IMR 검증 완료 대기 시간이 초과되었습니다.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const sidoListRef: { current: Sido[] } = { current: [] };
|
|
||||||
|
|
||||||
function getSewerageSupplyRateParams(
|
function getSewerageSupplyRateParams(
|
||||||
values: SearchFormValues,
|
values: SearchFormValues,
|
||||||
overrides?: { yr?: string; demoYr?: string; mode?: string }
|
overrides?: { yr?: string; demoYr?: string; mode?: string }
|
||||||
): SewerageSupplyRateRequestParams {
|
): SewerageSupplyRateRequestParams {
|
||||||
return {
|
return {
|
||||||
ctpvNm: values.sido,
|
ctpvNm: values.sido,
|
||||||
...toInputSearchRegion(sidoListRef.current, values),
|
sggNm: values.gugun === 'ALL' ? '' : values.gugun,
|
||||||
|
sewerBzmnCd: values.bsnmCd,
|
||||||
statsYr: overrides?.yr ?? values.year,
|
statsYr: overrides?.yr ?? values.year,
|
||||||
...(overrides?.mode && { mode: overrides.mode }),
|
...(overrides?.mode && { mode: overrides.mode }),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeGridString(value: unknown): string | null {
|
||||||
|
if (typeof value !== "string") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.trim() === "" ? null : value;
|
||||||
|
}
|
||||||
|
|
||||||
// 하수도 통계 관리 > 01. 하수도 보급률
|
// 하수도 통계 관리 > 01. 하수도 보급률
|
||||||
const SeweragePenetrationRateInp = () => {
|
const SeweragePenetrationRateInp = () => {
|
||||||
const { sidoList, isReady } = useSearchConditionSidoList({ isInput: true });
|
|
||||||
sidoListRef.current = sidoList;
|
|
||||||
const { setMessage: alert } = useAlertStore((state) => state);
|
const { setMessage: alert } = useAlertStore((state) => state);
|
||||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||||
@@ -162,8 +137,6 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
/** `engColNm` → `columnGuide` (헤더 hover) */
|
/** `engColNm` → `columnGuide` (헤더 hover) */
|
||||||
const [columnGuidesByEngCol, setColumnGuidesByEngCol] = useState<Record<string, string>>({});
|
const [columnGuidesByEngCol, setColumnGuidesByEngCol] = useState<Record<string, string>>({});
|
||||||
const [footerFromApi, setFooterFromApi] = useState<{ sewerBzmnWholPpltnCnt?: number; sewerBzmnDomplWholPpltnCnt?: number; sewerBzmnFrgnrWholPpltnCnt?: number; sewerBzmnArea?: number } | null>(null);
|
const [footerFromApi, setFooterFromApi] = useState<{ sewerBzmnWholPpltnCnt?: number; sewerBzmnDomplWholPpltnCnt?: number; sewerBzmnFrgnrWholPpltnCnt?: number; sewerBzmnArea?: number } | null>(null);
|
||||||
const [footerVerificationResult, setFooterVerificationResult] =
|
|
||||||
useState<VerificationResultLikeMap | null>(null);
|
|
||||||
const { confirm } = useConfirm();
|
const { confirm } = useConfirm();
|
||||||
const showGlobalProgress = useGlobalProgressStore((state) => state.show);
|
const showGlobalProgress = useGlobalProgressStore((state) => state.show);
|
||||||
const setGlobalProgress = useGlobalProgressStore((state) => state.setProgress);
|
const setGlobalProgress = useGlobalProgressStore((state) => state.setProgress);
|
||||||
@@ -183,16 +156,15 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
if (activeTabId !== STATISTICS_INPUT_URL_PATH.SEWERAGE_PENETRATION_RATE) {
|
if (activeTabId !== STATISTICS_INPUT_URL_PATH.SEWERAGE_PENETRATION_RATE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!isReady) return;
|
|
||||||
const pending = useStatisticsInputFocusStore
|
const pending = useStatisticsInputFocusStore
|
||||||
.getState()
|
.getState()
|
||||||
.takePendingForUrl(STATISTICS_INPUT_URL_PATH.SEWERAGE_PENETRATION_RATE);
|
.takePendingForUrl(STATISTICS_INPUT_URL_PATH.SEWERAGE_PENETRATION_RATE);
|
||||||
if (!pending?.search) return;
|
if (!pending?.search) return;
|
||||||
const values = verificationSearchToFormValues(pending.search, sidoList);
|
const values = verificationSearchToFormValues(pending.search);
|
||||||
setVerificationSearchDefaults(values);
|
setVerificationSearchDefaults(values);
|
||||||
postVerificationSearchRef.current = values;
|
postVerificationSearchRef.current = values;
|
||||||
setSearchFormRemountKey((k) => k + 1);
|
setSearchFormRemountKey((k) => k + 1);
|
||||||
}, [activeTabId, inputFocusNonce, isReady, sidoList]);
|
}, [activeTabId, inputFocusNonce]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeTabId !== STATISTICS_INPUT_URL_PATH.SEWERAGE_PENETRATION_RATE) {
|
if (activeTabId !== STATISTICS_INPUT_URL_PATH.SEWERAGE_PENETRATION_RATE) {
|
||||||
@@ -236,14 +208,11 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
(footerFromApi && footerFromApi[fieldName] != null ? footerFromApi[fieldName] : null) ?? getFooterSummary(grid, column),
|
(footerFromApi && footerFromApi[fieldName] != null ? footerFromApi[fieldName] : null) ?? getFooterSummary(grid, column),
|
||||||
});
|
});
|
||||||
|
|
||||||
// 관리자는 제출/승인 상태에서도 편집 가능. 단, 입력기간 외에는 불가.
|
// 최상위 관리자일땐 모든 상황에서 edit 가능하게 수정 필요.
|
||||||
|
|
||||||
const columnInfo = useMemo(() => {
|
const columnInfo = useMemo(() => {
|
||||||
const { columns, columnLayout } = SeweragePenetrationRateInpColumn;
|
const { columns, columnLayout } = SeweragePenetrationRateInpColumn;
|
||||||
const canEdit =
|
const base = (isEnterable || isAdminInfo) ? columns : columns.map((col) => ({ ...col, editable: false as const }));
|
||||||
(isEnterable || isAdminInfo) && isInputPeriodCurrent(periodCheckList);
|
|
||||||
const base = canEdit
|
|
||||||
? columns
|
|
||||||
: columns.map((col) => ({ ...col, editable: false as const }));
|
|
||||||
|
|
||||||
const withHeaderTooltips = base.map((col) => {
|
const withHeaderTooltips = base.map((col) => {
|
||||||
const guide = columnGuidesByEngCol[col.fieldName]?.trim();
|
const guide = columnGuidesByEngCol[col.fieldName]?.trim();
|
||||||
@@ -264,7 +233,7 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
return col;
|
return col;
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
}, [isEnterable, isAdminInfo, periodCheckList, footerFromApi, columnGuidesByEngCol]);
|
}, [isEnterable, isAdminInfo, footerFromApi, columnGuidesByEngCol]);
|
||||||
|
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
setRowData([]);
|
setRowData([]);
|
||||||
@@ -273,28 +242,19 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
setLastSearchedYear(null);
|
setLastSearchedYear(null);
|
||||||
setLastSearchedValues(null);
|
setLastSearchedValues(null);
|
||||||
setFooterFromApi(null);
|
setFooterFromApi(null);
|
||||||
setFooterVerificationResult(null);
|
|
||||||
setVerificationSearchDefaults(null);
|
setVerificationSearchDefaults(null);
|
||||||
setIsVerificationFailed(false);
|
setIsVerificationFailed(false);
|
||||||
setSearchFormRemountKey((k) => k + 1);
|
setSearchFormRemountKey((k) => k + 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchSewerageSupplyRate = async (
|
const fetchSewerageSupplyRate = async (params: SewerageSupplyRateRequestParams, isEnterable: boolean) => {
|
||||||
params: SewerageSupplyRateRequestParams,
|
|
||||||
isEnterable: boolean,
|
|
||||||
values?: SearchFormValues | null,
|
|
||||||
) => {
|
|
||||||
try {
|
try {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
const response = await statisticsInputSewSupplyRateApi.getSewerageSupplyRateList(params);
|
const response = await statisticsInputSewSupplyRateApi.getSewerageSupplyRateList(params);
|
||||||
if (response.status === 'success' && response.data) {
|
if (response.status === 'success' && response.data) {
|
||||||
const commonInfo = response.data.commonInfo;
|
const commonInfo = response.data.commonInfo;
|
||||||
const statusInfo = response.data.statusInfo;
|
const statusInfo = response.data.statusInfo;
|
||||||
const convertedData: SewerageSupplyRateItem[] = filterBySelectedAdmdstCd(
|
const convertedData: SewerageSupplyRateItem[] = response.data.sewerageSupplyRateList.map((d: SewerageSupplyRateItem) => ({
|
||||||
response.data.sewerageSupplyRateList,
|
|
||||||
sidoListRef.current,
|
|
||||||
values,
|
|
||||||
).map((d: SewerageSupplyRateItem) => ({
|
|
||||||
...d,
|
...d,
|
||||||
ctpvNm: commonInfo.ctpvNm,
|
ctpvNm: commonInfo.ctpvNm,
|
||||||
spcCtpnRgnCn: d.spcCtpnRgnCn === '' || d.spcCtpnRgnCn === null ? '해당없음' : d.spcCtpnRgnCn,
|
spcCtpnRgnCn: d.spcCtpnRgnCn === '' || d.spcCtpnRgnCn === null ? '해당없음' : d.spcCtpnRgnCn,
|
||||||
@@ -318,11 +278,6 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
}
|
}
|
||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
setFooterVerificationResult(
|
|
||||||
remapCommonInfoVerificationToGridFields(
|
|
||||||
commonInfo.verificationResult,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
setStatsCd(commonInfo.statsCd);
|
setStatsCd(commonInfo.statsCd);
|
||||||
setIsVerificationFailed(isVerificationFailedFromCommonInfo(commonInfo));
|
setIsVerificationFailed(isVerificationFailedFromCommonInfo(commonInfo));
|
||||||
if (statusInfo && statusInfo.laeSbmsnSttsCd) {
|
if (statusInfo && statusInfo.laeSbmsnSttsCd) {
|
||||||
@@ -344,7 +299,6 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
setRowData([]);
|
setRowData([]);
|
||||||
setStatusInfo(null);
|
setStatusInfo(null);
|
||||||
setFooterFromApi(null);
|
setFooterFromApi(null);
|
||||||
setFooterVerificationResult(null);
|
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
@@ -364,7 +318,7 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
setPeriodCheckList(periods);
|
setPeriodCheckList(periods);
|
||||||
const checkEnterable = isInputPeriodCurrent(periods);
|
const checkEnterable = isInputPeriodCurrent(periods);
|
||||||
setLastSearchedYear(values.year || null);
|
setLastSearchedYear(values.year || null);
|
||||||
await fetchSewerageSupplyRate(getSewerageSupplyRateParams(values), checkEnterable, values);
|
await fetchSewerageSupplyRate(getSewerageSupplyRateParams(values), checkEnterable);
|
||||||
setLastSearchedValues(values);
|
setLastSearchedValues(values);
|
||||||
} else {
|
} else {
|
||||||
alert(response.message);
|
alert(response.message);
|
||||||
@@ -392,8 +346,9 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
|
|
||||||
const params: SubmitExceptionRequest = {
|
const params: SubmitExceptionRequest = {
|
||||||
...submitInfo,
|
...submitInfo,
|
||||||
...toInputSearchRegion(sidoListRef.current, searchValues),
|
sewerBzmnCd: searchValues?.bsnmCd ?? '',
|
||||||
ctpvNm: searchValues?.sido ?? '',
|
ctpvNm: searchValues?.sido ?? '',
|
||||||
|
sggNm: searchValues?.gugun === "ALL" ? "" : (searchValues?.gugun ?? ''),
|
||||||
statsYr: searchValues?.year ?? '',
|
statsYr: searchValues?.year ?? '',
|
||||||
userId: userInfo.userUnqId,
|
userId: userInfo.userUnqId,
|
||||||
statsCd: statsCd,
|
statsCd: statsCd,
|
||||||
@@ -409,7 +364,7 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
const response = await statisticsApi.submitException(params);
|
const response = await statisticsApi.submitException(params);
|
||||||
|
|
||||||
if (response.status === 'success') {
|
if (response.status === 'success') {
|
||||||
await fetchSewerageSupplyRate(getSewerageSupplyRateParams(searchValues ?? {}), false, searchValues ?? {});
|
await fetchSewerageSupplyRate(getSewerageSupplyRateParams(searchValues ?? {}), false);
|
||||||
alert('제출되었습니다.');
|
alert('제출되었습니다.');
|
||||||
} else {
|
} else {
|
||||||
alert(response.message || '데이터 제출 중 오류가 발생했습니다.');
|
alert(response.message || '데이터 제출 중 오류가 발생했습니다.');
|
||||||
@@ -433,7 +388,7 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await fetchSewerageSupplyRate(getSewerageSupplyRateParams(values, { mode: 'PRE' }), true, values);
|
await fetchSewerageSupplyRate(getSewerageSupplyRateParams(values, { mode: 'PRE' }), true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const submitFunc = async (isException: boolean) => {
|
const submitFunc = async (isException: boolean) => {
|
||||||
@@ -498,12 +453,12 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const convertedData: SewerageSupplyRateSaveItem[] = currentData.map((d) => ({
|
const convertedData: SewerageSupplyRateSaveItem[] = currentData.map((d) => ({
|
||||||
sggNm: nullableTrimmedString(d.sggNm),
|
sggNm: normalizeGridString(d.sggNm),
|
||||||
admdstCd: nullableTrimmedString(d.admdstCd),
|
admdstCd: normalizeGridString(d.admdstCd),
|
||||||
admdstNm: nullableTrimmedString(d.admdstNm),
|
admdstNm: normalizeGridString(d.admdstNm),
|
||||||
trbtrNm: nullableTrimmedString(d.trbtrNm),
|
trbtrNm: normalizeGridString(d.trbtrNm),
|
||||||
spcCtpnRgnCn:
|
spcCtpnRgnCn:
|
||||||
d.spcCtpnRgnCn === '해당없음' ? null : nullableTrimmedString(d.spcCtpnRgnCn),
|
d.spcCtpnRgnCn === '해당없음' ? null : normalizeGridString(d.spcCtpnRgnCn),
|
||||||
ts1SwtrmtPpltnCnt: formatNumber(d.ts1SwtrmtPpltnCnt, 'ts1SwtrmtPpltnCnt'),
|
ts1SwtrmtPpltnCnt: formatNumber(d.ts1SwtrmtPpltnCnt, 'ts1SwtrmtPpltnCnt'),
|
||||||
ts2SwtrmtPpltnCnt: formatNumber(d.ts2SwtrmtPpltnCnt, 'ts2SwtrmtPpltnCnt'),
|
ts2SwtrmtPpltnCnt: formatNumber(d.ts2SwtrmtPpltnCnt, 'ts2SwtrmtPpltnCnt'),
|
||||||
ts3SwtrmtPpltnCnt: formatNumber(d.ts3SwtrmtPpltnCnt, 'ts3SwtrmtPpltnCnt'),
|
ts3SwtrmtPpltnCnt: formatNumber(d.ts3SwtrmtPpltnCnt, 'ts3SwtrmtPpltnCnt'),
|
||||||
@@ -516,7 +471,7 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
drtwPrcsPpltnCnt: formatNumber(d.drtwPrcsPpltnCnt, 'drtwPrcsPpltnCnt'),
|
drtwPrcsPpltnCnt: formatNumber(d.drtwPrcsPpltnCnt, 'drtwPrcsPpltnCnt'),
|
||||||
spctnkPpltnCnt: formatNumber(d.spctnkPpltnCnt, 'spctnkPpltnCnt'),
|
spctnkPpltnCnt: formatNumber(d.spctnkPpltnCnt, 'spctnkPpltnCnt'),
|
||||||
staaExcpArea: formatNumber(d.staaExcpArea, 'staaExcpArea'),
|
staaExcpArea: formatNumber(d.staaExcpArea, 'staaExcpArea'),
|
||||||
rmrk: nullableTrimmedString(d.rmrk),
|
rmrk: normalizeGridString(d.rmrk),
|
||||||
wholPpltnCnt: formatNumber(d.wholPpltnCnt, 'wholPpltnCnt'),
|
wholPpltnCnt: formatNumber(d.wholPpltnCnt, 'wholPpltnCnt'),
|
||||||
wholArea: formatNumber(d.wholArea, 'wholArea'),
|
wholArea: formatNumber(d.wholArea, 'wholArea'),
|
||||||
wholSwtrmtPpltnCnt: formatNumber(d.wholSwtrmtPpltnCnt, 'wholSwtrmtPpltnCnt'),
|
wholSwtrmtPpltnCnt: formatNumber(d.wholSwtrmtPpltnCnt, 'wholSwtrmtPpltnCnt'),
|
||||||
@@ -529,12 +484,13 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const requestData: SewerageSupplyRateSaveRequest = {
|
const requestData: SewerageSupplyRateSaveRequest = {
|
||||||
...toInputSearchRegion(sidoListRef.current, searchValues),
|
sewerBzmnCd: searchValues?.bsnmCd ?? '',
|
||||||
ctpvNm: searchValues?.sido ?? '',
|
ctpvNm: searchValues?.sido ?? '',
|
||||||
|
sggNm: searchValues?.gugun === "ALL" ? "" : (searchValues?.gugun ?? ''),
|
||||||
statsYr: searchValues?.year ?? '',
|
statsYr: searchValues?.year ?? '',
|
||||||
userId: userInfo.userUnqId,
|
userId: userInfo.userUnqId,
|
||||||
submitList: convertedData,
|
submitList: convertedData,
|
||||||
sewerBzmnArea: footerFromApi?.sewerBzmnArea,
|
sewerBzmnFrgnrWholPpltnCnt: footerFromApi?.sewerBzmnFrgnrWholPpltnCnt,
|
||||||
laePicNm: submitInfo.laePicNm,
|
laePicNm: submitInfo.laePicNm,
|
||||||
laeKbrdrJbgdNm: submitInfo.laeKbrdrJbgdNm,
|
laeKbrdrJbgdNm: submitInfo.laeKbrdrJbgdNm,
|
||||||
laeKbrdrDeptNm: submitInfo.laeKbrdrDeptNm,
|
laeKbrdrDeptNm: submitInfo.laeKbrdrDeptNm,
|
||||||
@@ -551,7 +507,7 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
setGlobalProgress(50);
|
setGlobalProgress(50);
|
||||||
|
|
||||||
if (response.data.finalStatus === '5') {
|
if (response.data.finalStatus === '5') {
|
||||||
setGlobalProgressLabel('시계열 검증 진행 중...');
|
setGlobalProgressLabel('IMR 검증 진행 중...');
|
||||||
const imrParam = {
|
const imrParam = {
|
||||||
user_id: userInfo.userUnqId,
|
user_id: userInfo.userUnqId,
|
||||||
sewer_bzmn_cd: searchValues?.bsnmCd ?? '',
|
sewer_bzmn_cd: searchValues?.bsnmCd ?? '',
|
||||||
@@ -559,7 +515,6 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
stats_yr: searchValues?.year ?? '',
|
stats_yr: searchValues?.year ?? '',
|
||||||
lae_sbmsn_stts_cd: (statusInfo?.laeSbmsnSttsCd === '4' ? '4' : '2'),
|
lae_sbmsn_stts_cd: (statusInfo?.laeSbmsnSttsCd === '4' ? '4' : '2'),
|
||||||
gen_verify_stts_cd: response.data.nvpassed ? '1' : '2',
|
gen_verify_stts_cd: response.data.nvpassed ? '1' : '2',
|
||||||
hb_pass_yn: response.data.isHbPassed,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -575,12 +530,13 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
setGlobalProgress(100);
|
setGlobalProgress(100);
|
||||||
await fetchSewerageSupplyRate(getSewerageSupplyRateParams(searchValues ?? {}), true, searchValues ?? {});
|
await fetchSewerageSupplyRate(getSewerageSupplyRateParams(searchValues ?? {}), true);
|
||||||
await openVerificationResultDialogIfNeeded(
|
await openVerificationResultDialogIfNeeded(
|
||||||
searchValues?.year && searchValues?.sido && searchValues?.bsnmCd && statsCd
|
searchValues?.year && searchValues?.sido && searchValues?.bsnmCd && statsCd
|
||||||
? {
|
? {
|
||||||
...toInputSearchRegion(sidoListRef.current, searchValues),
|
sewerBzmnCd: searchValues.bsnmCd,
|
||||||
ctpvNm: searchValues.sido,
|
ctpvNm: searchValues.sido,
|
||||||
|
sggNm: searchValues.gugun === "ALL" ? "" : (searchValues.gugun ?? ""),
|
||||||
statsYr: searchValues.year,
|
statsYr: searchValues.year,
|
||||||
statsCd,
|
statsCd,
|
||||||
}
|
}
|
||||||
@@ -589,13 +545,14 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
{ notify: alert },
|
{ notify: alert },
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
await fetchSewerageSupplyRate(getSewerageSupplyRateParams(searchValues ?? {}), true, searchValues ?? {});
|
await fetchSewerageSupplyRate(getSewerageSupplyRateParams(searchValues ?? {}), true);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
await openVerificationResultDialogIfNeeded(
|
await openVerificationResultDialogIfNeeded(
|
||||||
searchValues?.year && searchValues?.sido && searchValues?.bsnmCd && statsCd
|
searchValues?.year && searchValues?.sido && searchValues?.bsnmCd && statsCd
|
||||||
? {
|
? {
|
||||||
...toInputSearchRegion(sidoListRef.current, searchValues),
|
sewerBzmnCd: searchValues.bsnmCd,
|
||||||
ctpvNm: searchValues.sido,
|
ctpvNm: searchValues.sido,
|
||||||
|
sggNm: searchValues.gugun === "ALL" ? "" : (searchValues.gugun ?? ""),
|
||||||
statsYr: searchValues.year,
|
statsYr: searchValues.year,
|
||||||
statsCd,
|
statsCd,
|
||||||
}
|
}
|
||||||
@@ -612,12 +569,13 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setGlobalProgress(100);
|
setGlobalProgress(100);
|
||||||
await fetchSewerageSupplyRate(getSewerageSupplyRateParams(searchValues ?? {}), false, searchValues ?? {});
|
await fetchSewerageSupplyRate(getSewerageSupplyRateParams(searchValues ?? {}), false);
|
||||||
await openVerificationResultDialogIfNeeded(
|
await openVerificationResultDialogIfNeeded(
|
||||||
searchValues?.year && searchValues?.sido && searchValues?.bsnmCd && statsCd
|
searchValues?.year && searchValues?.sido && searchValues?.bsnmCd && statsCd
|
||||||
? {
|
? {
|
||||||
...toInputSearchRegion(sidoListRef.current, searchValues),
|
sewerBzmnCd: searchValues.bsnmCd,
|
||||||
ctpvNm: searchValues.sido,
|
ctpvNm: searchValues.sido,
|
||||||
|
sggNm: searchValues.gugun === "ALL" ? "" : (searchValues.gugun ?? ""),
|
||||||
statsYr: searchValues.year,
|
statsYr: searchValues.year,
|
||||||
statsCd,
|
statsCd,
|
||||||
}
|
}
|
||||||
@@ -678,14 +636,14 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
|
|
||||||
const convertedData: SewerageSupplyRateSaveItem[] = currentData.map((d) => ({
|
const convertedData: SewerageSupplyRateSaveItem[] = currentData.map((d) => ({
|
||||||
// 행정구역
|
// 행정구역
|
||||||
sggNm: nullableTrimmedString(d.sggNm), // 시군구
|
sggNm: normalizeGridString(d.sggNm), // 시군구
|
||||||
admdstCd: nullableTrimmedString(d.admdstCd), // 행정코드
|
admdstCd: normalizeGridString(d.admdstCd), // 행정코드
|
||||||
admdstNm: nullableTrimmedString(d.admdstNm), // 행정구역명
|
admdstNm: normalizeGridString(d.admdstNm), // 행정구역명
|
||||||
trbtrNm: nullableTrimmedString(d.trbtrNm), // 지류
|
trbtrNm: normalizeGridString(d.trbtrNm), // 지류
|
||||||
spcCtpnRgnCn:
|
spcCtpnRgnCn:
|
||||||
d.spcCtpnRgnCn === '해당없음'
|
d.spcCtpnRgnCn === '해당없음'
|
||||||
? null
|
? null
|
||||||
: nullableTrimmedString(d.spcCtpnRgnCn), // 특별대책지역
|
: normalizeGridString(d.spcCtpnRgnCn), // 특별대책지역
|
||||||
// 공공하수처리인구(명) - 물리적/생물학적/고도처리
|
// 공공하수처리인구(명) - 물리적/생물학적/고도처리
|
||||||
ts1SwtrmtPpltnCnt: formatNumber(d.ts1SwtrmtPpltnCnt, 'ts1SwtrmtPpltnCnt'), // 물리적처리
|
ts1SwtrmtPpltnCnt: formatNumber(d.ts1SwtrmtPpltnCnt, 'ts1SwtrmtPpltnCnt'), // 물리적처리
|
||||||
ts2SwtrmtPpltnCnt: formatNumber(d.ts2SwtrmtPpltnCnt, 'ts2SwtrmtPpltnCnt'), // 생물학적처리
|
ts2SwtrmtPpltnCnt: formatNumber(d.ts2SwtrmtPpltnCnt, 'ts2SwtrmtPpltnCnt'), // 생물학적처리
|
||||||
@@ -701,7 +659,7 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
drtwPrcsPpltnCnt: formatNumber(d.drtwPrcsPpltnCnt, 'drtwPrcsPpltnCnt'), // 오수처리인구
|
drtwPrcsPpltnCnt: formatNumber(d.drtwPrcsPpltnCnt, 'drtwPrcsPpltnCnt'), // 오수처리인구
|
||||||
spctnkPpltnCnt: formatNumber(d.spctnkPpltnCnt, 'spctnkPpltnCnt'), // 정화조인구
|
spctnkPpltnCnt: formatNumber(d.spctnkPpltnCnt, 'spctnkPpltnCnt'), // 정화조인구
|
||||||
staaExcpArea: formatNumber(d.staaExcpArea, 'staaExcpArea'), // 하수처리구역 외 면적(㎢)
|
staaExcpArea: formatNumber(d.staaExcpArea, 'staaExcpArea'), // 하수처리구역 외 면적(㎢)
|
||||||
rmrk: nullableTrimmedString(d.rmrk), // 비고
|
rmrk: normalizeGridString(d.rmrk), // 비고
|
||||||
// 합계·소계(계산필드 저장용)
|
// 합계·소계(계산필드 저장용)
|
||||||
wholPpltnCnt: formatNumber(d.wholPpltnCnt, 'wholPpltnCnt'), // 총인구(명)
|
wholPpltnCnt: formatNumber(d.wholPpltnCnt, 'wholPpltnCnt'), // 총인구(명)
|
||||||
wholArea: formatNumber(d.wholArea, 'wholArea'), // 총면적(㎢)
|
wholArea: formatNumber(d.wholArea, 'wholArea'), // 총면적(㎢)
|
||||||
@@ -716,12 +674,13 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const requestData: SewerageSupplyRateSaveRequest = {
|
const requestData: SewerageSupplyRateSaveRequest = {
|
||||||
...toInputSearchRegion(sidoListRef.current, searchValues),
|
sewerBzmnCd: searchValues?.bsnmCd ?? '', // 하수도 사업자 코드
|
||||||
ctpvNm: searchValues?.sido ?? '', // 시도
|
ctpvNm: searchValues?.sido ?? '', // 시도
|
||||||
|
sggNm: searchValues?.gugun === "ALL" ? "" : (searchValues?.gugun ?? ''),
|
||||||
statsYr: searchValues?.year ?? '', // 통계 연도
|
statsYr: searchValues?.year ?? '', // 통계 연도
|
||||||
userId: userInfo.userUnqId, // 사용자
|
userId: userInfo.userUnqId, // 사용자
|
||||||
saveList: convertedData, // 저장 데이터
|
saveList: convertedData, // 저장 데이터
|
||||||
sewerBzmnArea: footerFromApi?.sewerBzmnArea, // 행정참고자료면적
|
sewerBzmnFrgnrWholPpltnCnt: footerFromApi?.sewerBzmnFrgnrWholPpltnCnt // 행정참고자료 외국인 합계
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isAdminInfo) {
|
if (isAdminInfo) {
|
||||||
@@ -733,7 +692,7 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
if (response.status === 'success') {
|
if (response.status === 'success') {
|
||||||
setGlobalProgress(50);
|
setGlobalProgress(50);
|
||||||
setGlobalProgress(100);
|
setGlobalProgress(100);
|
||||||
await fetchSewerageSupplyRate(getSewerageSupplyRateParams(searchValues ?? {}), true, searchValues ?? {});
|
await fetchSewerageSupplyRate(getSewerageSupplyRateParams(searchValues ?? {}), true);
|
||||||
alert('저장되었습니다.');
|
alert('저장되었습니다.');
|
||||||
} else {
|
} else {
|
||||||
alert(response.message || '데이터 저장 중 오류가 발생했습니다.');
|
alert(response.message || '데이터 저장 중 오류가 발생했습니다.');
|
||||||
@@ -760,8 +719,9 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
const userInfo = await getUserInfo();
|
const userInfo = await getUserInfo();
|
||||||
|
|
||||||
const requestData: cancelSubmitRequest = {
|
const requestData: cancelSubmitRequest = {
|
||||||
...toInputSearchRegion(sidoListRef.current, searchValues),
|
sewerBzmnCd: searchValues?.bsnmCd ?? '',
|
||||||
ctpvNm: searchValues?.sido ?? '',
|
ctpvNm: searchValues?.sido ?? '',
|
||||||
|
sggNm: searchValues?.gugun === "ALL" ? "" : (searchValues?.gugun ?? ""),
|
||||||
statsYr: searchValues?.year ?? '',
|
statsYr: searchValues?.year ?? '',
|
||||||
mdfrId: userInfo.userUnqId,
|
mdfrId: userInfo.userUnqId,
|
||||||
statsCd: statsCd,
|
statsCd: statsCd,
|
||||||
@@ -770,7 +730,7 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
const response = await statisticsApi.cancelSubmit(requestData);
|
const response = await statisticsApi.cancelSubmit(requestData);
|
||||||
|
|
||||||
if (response.status === 'success') {
|
if (response.status === 'success') {
|
||||||
fetchSewerageSupplyRate(getSewerageSupplyRateParams(searchValues ?? {}), true, searchValues ?? {});
|
fetchSewerageSupplyRate(getSewerageSupplyRateParams(searchValues ?? {}), true);
|
||||||
alert('제출 취소되었습니다.');
|
alert('제출 취소되었습니다.');
|
||||||
} else {
|
} else {
|
||||||
alert(response.message ?? '제출 취소 중 오류가 발생했습니다.');
|
alert(response.message ?? '제출 취소 중 오류가 발생했습니다.');
|
||||||
@@ -789,14 +749,13 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
setVerificationHistoryOpen(true);
|
setVerificationHistoryOpen(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const toolbarSearchContext = lastSearchedValues;
|
const gugunOkOrNotDoList = doList.includes(lastSearchedValues?.bsnmCd || '')
|
||||||
const gugunOkOrNotDoList = isGugunOkForToolbar(sidoList, toolbarSearchContext);
|
? Boolean(lastSearchedValues?.gugun && lastSearchedValues.gugun !== 'ALL')
|
||||||
const submitOk = isSubmitOkForToolbar(sidoList, toolbarSearchContext);
|
: true;
|
||||||
|
|
||||||
const inputPeriodCurrent = isInputPeriodCurrent(periodCheckList);
|
const inputPeriodCurrent = isInputPeriodCurrent(periodCheckList);
|
||||||
const isSubmitted = statusInfo?.laeSbmsnSttsCd === '2';
|
const isSubmitted = statusInfo?.laeSbmsnSttsCd === '2';
|
||||||
const baseShowSaveInToolbar =
|
const baseShowSaveInToolbar = (isEnterable || isAdminInfo) && gugunOkOrNotDoList;
|
||||||
(isEnterable || isAdminInfo) && inputPeriodCurrent && gugunOkOrNotDoList;
|
|
||||||
const baseShowEnterableToolbarButtons = isEnterable && gugunOkOrNotDoList;
|
const baseShowEnterableToolbarButtons = isEnterable && gugunOkOrNotDoList;
|
||||||
const showSubmittedInInputPeriodToolbar =
|
const showSubmittedInInputPeriodToolbar =
|
||||||
isSubmitted && inputPeriodCurrent && gugunOkOrNotDoList;
|
isSubmitted && inputPeriodCurrent && gugunOkOrNotDoList;
|
||||||
@@ -814,7 +773,6 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
<>
|
<>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<SearchForm
|
<SearchForm
|
||||||
isInput
|
|
||||||
key={searchFormRemountKey}
|
key={searchFormRemountKey}
|
||||||
defaultValues={verificationSearchDefaults ?? undefined}
|
defaultValues={verificationSearchDefaults ?? undefined}
|
||||||
onSubmit={handleSearch}
|
onSubmit={handleSearch}
|
||||||
@@ -831,10 +789,10 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
{showEnterableToolbarButtons && (
|
{showEnterableToolbarButtons && (
|
||||||
<>
|
<>
|
||||||
<LastYearDataButton getLastYearDataFunc={() => getLastYearDataFunc(searchValues ?? {})} />
|
<LastYearDataButton getLastYearDataFunc={() => getLastYearDataFunc(searchValues ?? {})} />
|
||||||
{submitOk && <SubmitButton submitFunc={() => submitFunc(false)} />}
|
<SubmitButton submitFunc={() => submitFunc(false)} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{statusInfo?.laeSbmsnSttsCd === '2' && submitOk && <CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />}
|
{statusInfo?.laeSbmsnSttsCd === '2' && <CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />}
|
||||||
{showSaveInToolbar && <SaveButton saveFunc={saveFunc} />}
|
{showSaveInToolbar && <SaveButton saveFunc={saveFunc} />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -847,9 +805,9 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<DataGrid
|
<DataGrid
|
||||||
key={((isEnterable || isAdminInfo) && inputPeriodCurrent) ? 'enterable' : 'readonly'}
|
key={(isEnterable || isAdminInfo) ? 'enterable' : 'readonly'}
|
||||||
columnInfo={columnInfo}
|
columnInfo={columnInfo}
|
||||||
isExcelImport={(rowData.length > 0) && isEnterable && gugunOkOrNotDoList}
|
isExcelImport={(rowData.length > 0) && isEnterable && (doList.includes(lastSearchedValues?.bsnmCd || '') ? Boolean(lastSearchedValues?.gugun && lastSearchedValues.gugun !== 'ALL') : true)}
|
||||||
excelImportSewerBzmnCd={(lastSearchedValues ?? searchValues)?.bsnmCd}
|
excelImportSewerBzmnCd={(lastSearchedValues ?? searchValues)?.bsnmCd}
|
||||||
excelExportSearchContext={toExcelExportSearchContextFromSearchForm(lastSearchedValues ?? searchValues)}
|
excelExportSearchContext={toExcelExportSearchContextFromSearchForm(lastSearchedValues ?? searchValues)}
|
||||||
rowStartNum={3}
|
rowStartNum={3}
|
||||||
@@ -868,7 +826,6 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
return hasImr ? 'rg-cell-verify-error-imr' : 'rg-cell-verify-error';
|
return hasImr ? 'rg-cell-verify-error-imr' : 'rg-cell-verify-error';
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
footerVerificationResult={footerVerificationResult}
|
|
||||||
cellTooltipCallback={({ row, fieldName }) => {
|
cellTooltipCallback={({ row, fieldName }) => {
|
||||||
const verification = (row as GridRowWithVerification).verificationResult;
|
const verification = (row as GridRowWithVerification).verificationResult;
|
||||||
if (!verification) return;
|
if (!verification) return;
|
||||||
@@ -876,7 +833,7 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
if (Array.isArray(errors) && errors.length > 0) {
|
if (Array.isArray(errors) && errors.length > 0) {
|
||||||
return errors
|
return errors
|
||||||
.map((e) => {
|
.map((e) => {
|
||||||
const prefix = e.vrfcCd === 'IMR' ? '시계열 검증 - ' : (e.vrfcCd === 'NV' ? '일반검증 - ' : '모집단 검증 -');
|
const prefix = e.vrfcCd === 'IMR' ? 'IMR검증 - ' : (e.vrfcCd === 'NV' ? '일반검증 - ' : 'HB검증 -');
|
||||||
return `${prefix}${e.rsnExpln}
|
return `${prefix}${e.rsnExpln}
|
||||||
(검증 기준값: ${e.compVlCn} / 현재 입력값: ${e.nowVlCn})`;
|
(검증 기준값: ${e.compVlCn} / 현재 입력값: ${e.nowVlCn})`;
|
||||||
})
|
})
|
||||||
@@ -905,8 +862,9 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
queryContext={
|
queryContext={
|
||||||
searchValues?.year && searchValues?.sido && searchValues?.bsnmCd && statsCd
|
searchValues?.year && searchValues?.sido && searchValues?.bsnmCd && statsCd
|
||||||
? {
|
? {
|
||||||
...toInputSearchRegion(sidoListRef.current, searchValues),
|
sewerBzmnCd: searchValues.bsnmCd,
|
||||||
ctpvNm: searchValues.sido,
|
ctpvNm: searchValues.sido,
|
||||||
|
sggNm: searchValues.gugun === "ALL" ? "" : (searchValues.gugun ?? ""),
|
||||||
statsYr: searchValues.year,
|
statsYr: searchValues.year,
|
||||||
statsCd,
|
statsCd,
|
||||||
}
|
}
|
||||||
@@ -924,8 +882,12 @@ const SeweragePenetrationRateInp = () => {
|
|||||||
queryContext={
|
queryContext={
|
||||||
searchValues?.year && searchValues?.sido && searchValues?.bsnmCd && statsCd
|
searchValues?.year && searchValues?.sido && searchValues?.bsnmCd && statsCd
|
||||||
? {
|
? {
|
||||||
...toInputSearchRegion(sidoListRef.current, searchValues),
|
sewerBzmnCd: searchValues.bsnmCd,
|
||||||
ctpvNm: searchValues.sido,
|
ctpvNm: searchValues.sido,
|
||||||
|
sggNm:
|
||||||
|
searchValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (searchValues.gugun ?? ""),
|
||||||
statsYr: searchValues.year,
|
statsYr: searchValues.year,
|
||||||
statsCd,
|
statsCd,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,33 @@ import { useEffect, useMemo, useRef, useState } from "react";
|
|||||||
|
|
||||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||||
|
|
||||||
import { useAlertStore, useGlobalProgressStore, useStatisticsInputToolbarGroupGate, useSearchConditionSidoList } from "@/shared/lib";
|
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||||
import { STATISTICS_INPUT_URL_PATH } from "@/shared/lib/stats-cd-input-navigation";
|
|
||||||
import { useStatisticsInputPendingNavigation } from "@/shared/lib/use-statistics-input-pending-navigation";
|
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
||||||
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
|
||||||
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
import CancelSubmitButton from "@/components/button/CancelSubmitButton";
|
||||||
|
import LastYearDataButton from "@/components/button/LastYearDataButton";
|
||||||
|
import NotApplicableCheckButton from "@/components/button/NotApplicableCheckButton";
|
||||||
|
import SaveButton from "@/components/button/SaveButton";
|
||||||
|
import SubmitButton from "@/components/button/SumitButton";
|
||||||
|
import VerificationResultButton from "@/components/button/VerificationResultButton";
|
||||||
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
|
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
||||||
|
import { openVerificationResultDialogIfNeeded } from "@/components/module/post-submit-verification-results";
|
||||||
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
|
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
||||||
|
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
||||||
|
import type { ColumnConfig, ColumnInfo } from "@/components/type/DataGrid.type";
|
||||||
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
|
import { doList } from "@/components/util/column/input/DoList";
|
||||||
|
import { ComplaintInpColumn } from "@/components/util/column/input/sewerageServiceLevel/ComplaintInpColumn";
|
||||||
|
import { ResidentFriendlyFactInpColumn } from "@/components/util/column/input/sewerageServiceLevel/ResidentFriendlyFactInpColumn";
|
||||||
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
|
import { patchVerificationFailedByTab } from "@/components/util/input/verification-failed-flag";
|
||||||
import { statisticsInputSewerageServiceLevelApi } from "@/entities/statistics/api/input/statistics-input-sewerage-service-level-service";
|
import { statisticsInputSewerageServiceLevelApi } from "@/entities/statistics/api/input/statistics-input-sewerage-service-level-service";
|
||||||
|
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
|
import { isInputPeriodCurrent } from "@/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface";
|
||||||
import {
|
import {
|
||||||
SEWERAGE_SERVICE_LEVEL_COMPLAINT_STATS_CD,
|
SEWERAGE_SERVICE_LEVEL_COMPLAINT_STATS_CD,
|
||||||
SEWERAGE_SERVICE_LEVEL_RESIDENT_FRIENDLY_FACT_STATS_CD,
|
SEWERAGE_SERVICE_LEVEL_RESIDENT_FRIENDLY_FACT_STATS_CD,
|
||||||
@@ -19,55 +39,20 @@ import {
|
|||||||
type SewerageServiceLevelResidentFriendlyFactSaveItem,
|
type SewerageServiceLevelResidentFriendlyFactSaveItem,
|
||||||
type SewerageServiceLevelVerificationResult,
|
type SewerageServiceLevelVerificationResult,
|
||||||
} from "@/entities/statistics/model/input/statistics-input-sewerage-service-level-interface";
|
} from "@/entities/statistics/model/input/statistics-input-sewerage-service-level-interface";
|
||||||
import { isInputPeriodCurrent } from "@/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface";
|
|
||||||
import type { StatisticsInputSubmitInfoFormData } from "@/entities/statistics/model/statistics-input-submit-info-schema";
|
|
||||||
import type {
|
import type {
|
||||||
|
SewerageStatusInfo,
|
||||||
cancelSubmitRequest,
|
cancelSubmitRequest,
|
||||||
ImrStatusResponse,
|
ImrStatusResponse,
|
||||||
SewerageStatusInfo,
|
|
||||||
Sido,
|
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
} from "@/entities/statistics/model/statistics-interface";
|
||||||
import {
|
import type { StatisticsInputSubmitInfoFormData } from "@/entities/statistics/model/statistics-input-submit-info-schema";
|
||||||
filterBySelectedAdmdstCd,
|
import { useAlertStore, useGlobalProgressStore, useStatisticsInputToolbarGroupGate } from "@/shared/lib";
|
||||||
isGugunOkForToolbar,
|
import { STATISTICS_INPUT_URL_PATH } from "@/shared/lib/stats-cd-input-navigation";
|
||||||
isSubmitOkForToolbar,
|
import { useStatisticsInputPendingNavigation } from "@/shared/lib/use-statistics-input-pending-navigation";
|
||||||
resolveNoApplicableForRequest,
|
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
||||||
toInputSearchRegion,
|
import { useAdminStore } from "@/store/admin-store";
|
||||||
} from "@/entities/statistics";
|
|
||||||
|
|
||||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
|
||||||
|
|
||||||
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
|
||||||
|
|
||||||
import SubmitDailog from "./SubmitDailog";
|
import SubmitDailog from "./SubmitDailog";
|
||||||
|
|
||||||
import CancelSubmitButton from "@/components/button/CancelSubmitButton";
|
|
||||||
import LastYearDataButton from "@/components/button/LastYearDataButton";
|
|
||||||
import NotApplicableCheckButton from "@/components/button/NotApplicableCheckButton";
|
|
||||||
import SaveButton from "@/components/button/SaveButton";
|
|
||||||
import SubmitButton from "@/components/button/SumitButton";
|
|
||||||
import VerificationResultButton from "@/components/button/VerificationResultButton";
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
|
||||||
import { openVerificationResultDialogIfNeeded } from "@/components/module/post-submit-verification-results";
|
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
|
||||||
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
|
||||||
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
|
||||||
import type { ColumnConfig, ColumnInfo } from "@/components/type/DataGrid.type";
|
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
|
||||||
import { ComplaintInpColumn } from "@/components/util/column/input/sewerageServiceLevel/ComplaintInpColumn";
|
|
||||||
import { ResidentFriendlyFactInpColumn } from "@/components/util/column/input/sewerageServiceLevel/ResidentFriendlyFactInpColumn";
|
|
||||||
import { fetchColumnGuidesRecord } from "@/components/util/grid/columnGuides";
|
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
|
||||||
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
|
||||||
import {
|
|
||||||
patchFooterVerificationByTab,
|
|
||||||
patchVerificationFailedByTab,
|
|
||||||
} from "@/components/util/input/verification-failed-flag";
|
|
||||||
import type { VerificationResultLikeMap } from "@/components/util/input/verification-result-display";
|
|
||||||
import { nullableTrimmedString } from "@/components/util/input/nullableString";
|
|
||||||
import { useAdminStore } from "@/store/admin-store";
|
|
||||||
import { useTabStore } from "@/store/tab-store";
|
|
||||||
|
|
||||||
const SewerageServiceLevelInpTabList = [
|
const SewerageServiceLevelInpTabList = [
|
||||||
ComplaintInpColumn,
|
ComplaintInpColumn,
|
||||||
ResidentFriendlyFactInpColumn,
|
ResidentFriendlyFactInpColumn,
|
||||||
@@ -75,6 +60,11 @@ const SewerageServiceLevelInpTabList = [
|
|||||||
|
|
||||||
const firstTabKey = ComplaintInpColumn.tabKey;
|
const firstTabKey = ComplaintInpColumn.tabKey;
|
||||||
|
|
||||||
|
const SEWERAGE_SERVICE_LEVEL_COLUMN_GUIDE_STATS_CDS = [
|
||||||
|
SEWERAGE_SERVICE_LEVEL_COMPLAINT_STATS_CD,
|
||||||
|
SEWERAGE_SERVICE_LEVEL_RESIDENT_FRIENDLY_FACT_STATS_CD,
|
||||||
|
] as const;
|
||||||
|
|
||||||
const SEWERAGE_SERVICE_LEVEL_COLUMN_GUIDE_STATS_CD_BY_TAB_KEY: Record<string, string> = {
|
const SEWERAGE_SERVICE_LEVEL_COLUMN_GUIDE_STATS_CD_BY_TAB_KEY: Record<string, string> = {
|
||||||
[ComplaintInpColumn.tabKey]: SEWERAGE_SERVICE_LEVEL_COMPLAINT_STATS_CD,
|
[ComplaintInpColumn.tabKey]: SEWERAGE_SERVICE_LEVEL_COMPLAINT_STATS_CD,
|
||||||
[ResidentFriendlyFactInpColumn.tabKey]: SEWERAGE_SERVICE_LEVEL_RESIDENT_FRIENDLY_FACT_STATS_CD,
|
[ResidentFriendlyFactInpColumn.tabKey]: SEWERAGE_SERVICE_LEVEL_RESIDENT_FRIENDLY_FACT_STATS_CD,
|
||||||
@@ -128,22 +118,10 @@ const computeTabEnterable = (
|
|||||||
return periodEnterable;
|
return periodEnterable;
|
||||||
};
|
};
|
||||||
|
|
||||||
const sidoListRef: { current: Sido[] } = { current: [] };
|
|
||||||
|
|
||||||
function buildGugunOkForToolbar(values: SearchFormValues | null): boolean {
|
function buildGugunOkForToolbar(values: SearchFormValues | null): boolean {
|
||||||
return isGugunOkForToolbar(sidoListRef.current, values);
|
return doList.includes(values?.bsnmCd || "")
|
||||||
}
|
? Boolean(values?.gugun && values.gugun !== "ALL")
|
||||||
|
: true;
|
||||||
function buildSubmitOkForToolbar(values: SearchFormValues | null): boolean {
|
|
||||||
return isSubmitOkForToolbar(sidoListRef.current, values);
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildNoApplicableForRequest(
|
|
||||||
values: SearchFormValues | null,
|
|
||||||
checked: boolean,
|
|
||||||
isSaveListEmpty: boolean,
|
|
||||||
): boolean {
|
|
||||||
return resolveNoApplicableForRequest(sidoListRef.current, values, checked, isSaveListEmpty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeTabToolbarSnapshot(
|
function computeTabToolbarSnapshot(
|
||||||
@@ -157,7 +135,7 @@ function computeTabToolbarSnapshot(
|
|||||||
const gugunOk = buildGugunOkForToolbar(searchContext);
|
const gugunOk = buildGugunOkForToolbar(searchContext);
|
||||||
const enterable = computeTabEnterable(statusInfo, periodEnterable);
|
const enterable = computeTabEnterable(statusInfo, periodEnterable);
|
||||||
const isSubmitted = statusInfo?.laeSbmsnSttsCd === "2";
|
const isSubmitted = statusInfo?.laeSbmsnSttsCd === "2";
|
||||||
const showSaveInToolbar = (enterable || isAdminInfo) && periodEnterable && gugunOk;
|
const showSaveInToolbar = (enterable || isAdminInfo) && gugunOk;
|
||||||
const showEnterableToolbarButtons = enterable && gugunOk;
|
const showEnterableToolbarButtons = enterable && gugunOk;
|
||||||
const showSubmittedInInputPeriodToolbar = isSubmitted && periodEnterable && gugunOk;
|
const showSubmittedInInputPeriodToolbar = isSubmitted && periodEnterable && gugunOk;
|
||||||
const showActionToolbarCard =
|
const showActionToolbarCard =
|
||||||
@@ -175,16 +153,17 @@ function buildSewerageServiceLevelSearchParam(
|
|||||||
): SewerageServiceLevelComplaintRequestParams {
|
): SewerageServiceLevelComplaintRequestParams {
|
||||||
return {
|
return {
|
||||||
statsYr: values.year,
|
statsYr: values.year,
|
||||||
|
sewerBzmnCd: values.bsnmCd,
|
||||||
ctpvNm: values.sido,
|
ctpvNm: values.sido,
|
||||||
...toInputSearchRegion(sidoListRef.current, values),
|
sggNm: values.gugun === "ALL" ? "" : values.gugun,
|
||||||
...(overrides?.mode ? { mode: overrides.mode } : {}),
|
...(overrides?.mode ? { mode: overrides.mode } : {}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapServiceLevelListToGridRows<
|
function mapServiceLevelListToGridRows<
|
||||||
T extends { verificationResult?: SewerageServiceLevelVerificationResult },
|
T extends { verificationResult?: SewerageServiceLevelVerificationResult },
|
||||||
>(list: T[], ctpvNm: string, values?: SearchFormValues | null): GridRowWithVerification[] {
|
>(list: T[], ctpvNm: string): GridRowWithVerification[] {
|
||||||
return filterBySelectedAdmdstCd(list, sidoListRef.current, values).map((item) => {
|
return list.map((item) => {
|
||||||
const { verificationResult, ...rest } = item;
|
const { verificationResult, ...rest } = item;
|
||||||
const row = toGridRows([{ ctpvNm, ...rest }])[0] as GridRowWithVerification;
|
const row = toGridRows([{ ctpvNm, ...rest }])[0] as GridRowWithVerification;
|
||||||
if (verificationResult) row.verificationResult = verificationResult;
|
if (verificationResult) row.verificationResult = verificationResult;
|
||||||
@@ -192,6 +171,17 @@ function mapServiceLevelListToGridRows<
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeGridString(value: unknown): string {
|
||||||
|
if (value === null || value === undefined) return "";
|
||||||
|
return typeof value === "string" ? value : String(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeGridRmrk(value: unknown): string | null {
|
||||||
|
if (value === null || value === undefined) return null;
|
||||||
|
const s = typeof value === "string" ? value : String(value);
|
||||||
|
return s.trim() === "" ? null : s;
|
||||||
|
}
|
||||||
|
|
||||||
function buildColumnFormatNumber(
|
function buildColumnFormatNumber(
|
||||||
columns: { fieldName?: string; dataFormat?: string }[],
|
columns: { fieldName?: string; dataFormat?: string }[],
|
||||||
) {
|
) {
|
||||||
@@ -220,8 +210,8 @@ function buildComplaintSaveList(
|
|||||||
const formatNumber = buildColumnFormatNumber(ComplaintInpColumn.columns);
|
const formatNumber = buildColumnFormatNumber(ComplaintInpColumn.columns);
|
||||||
|
|
||||||
return currentData.map((d) => ({
|
return currentData.map((d) => ({
|
||||||
admdstCd: nullableTrimmedString(d.admdstCd),
|
admdstCd: normalizeGridString(d.admdstCd),
|
||||||
admdstNm: nullableTrimmedString(d.admdstNm),
|
admdstNm: normalizeGridString(d.admdstNm),
|
||||||
swtrmtPpltnCnt: formatNumber(d.swtrmtPpltnCnt, "swtrmtPpltnCnt"),
|
swtrmtPpltnCnt: formatNumber(d.swtrmtPpltnCnt, "swtrmtPpltnCnt"),
|
||||||
dschgWqCnt: formatNumber(d.dschgWqCnt, "dschgWqCnt"),
|
dschgWqCnt: formatNumber(d.dschgWqCnt, "dschgWqCnt"),
|
||||||
odorCnt: formatNumber(d.odorCnt, "odorCnt"),
|
odorCnt: formatNumber(d.odorCnt, "odorCnt"),
|
||||||
@@ -230,7 +220,7 @@ function buildComplaintSaveList(
|
|||||||
swagePplCnt: formatNumber(d.swagePplCnt, "swagePplCnt"),
|
swagePplCnt: formatNumber(d.swagePplCnt, "swagePplCnt"),
|
||||||
sewerCrgAmt: formatNumber(d.sewerCrgAmt, "sewerCrgAmt"),
|
sewerCrgAmt: formatNumber(d.sewerCrgAmt, "sewerCrgAmt"),
|
||||||
etcCnt: formatNumber(d.etcCnt, "etcCnt"),
|
etcCnt: formatNumber(d.etcCnt, "etcCnt"),
|
||||||
rmrk: nullableTrimmedString(d.rmrk),
|
rmrk: normalizeGridRmrk(d.rmrk),
|
||||||
whol: formatNumber(d.whol, "whol"),
|
whol: formatNumber(d.whol, "whol"),
|
||||||
crtrPpltnCvlcptEvntcsCnt: formatNumber(
|
crtrPpltnCvlcptEvntcsCnt: formatNumber(
|
||||||
d.crtrPpltnCvlcptEvntcsCnt,
|
d.crtrPpltnCvlcptEvntcsCnt,
|
||||||
@@ -245,11 +235,11 @@ function buildResidentFriendlyFactSaveList(
|
|||||||
const formatNumber = buildColumnFormatNumber(ResidentFriendlyFactInpColumn.columns);
|
const formatNumber = buildColumnFormatNumber(ResidentFriendlyFactInpColumn.columns);
|
||||||
|
|
||||||
return currentData.map((d) => ({
|
return currentData.map((d) => ({
|
||||||
admdstCd: nullableTrimmedString(d.admdstCd),
|
admdstCd: normalizeGridString(d.admdstCd),
|
||||||
admdstNm: nullableTrimmedString(d.admdstNm),
|
admdstNm: normalizeGridString(d.admdstNm),
|
||||||
swtrmtFcltCd: nullableTrimmedString(d.swtrmtFcltCd),
|
swtrmtFcltCd: normalizeGridString(d.swtrmtFcltCd),
|
||||||
swtrmtFcltNm: nullableTrimmedString(d.swtrmtFcltNm),
|
swtrmtFcltNm: normalizeGridString(d.swtrmtFcltNm),
|
||||||
fcltSn: nullableTrimmedString(d.fcltSn),
|
fcltSn: normalizeGridString(d.fcltSn),
|
||||||
tmplntArea: formatNumber(d.tmplntArea, "tmplntArea"),
|
tmplntArea: formatNumber(d.tmplntArea, "tmplntArea"),
|
||||||
brkFcltArea: formatNumber(d.brkFcltArea, "brkFcltArea"),
|
brkFcltArea: formatNumber(d.brkFcltArea, "brkFcltArea"),
|
||||||
childFrshpSpacArea: formatNumber(d.childFrshpSpacArea, "childFrshpSpacArea"),
|
childFrshpSpacArea: formatNumber(d.childFrshpSpacArea, "childFrshpSpacArea"),
|
||||||
@@ -259,7 +249,7 @@ function buildResidentFriendlyFactSaveList(
|
|||||||
eduMultiFcltArea: formatNumber(d.eduMultiFcltArea, "eduMultiFcltArea"),
|
eduMultiFcltArea: formatNumber(d.eduMultiFcltArea, "eduMultiFcltArea"),
|
||||||
wtlndMakeArea: formatNumber(d.wtlndMakeArea, "wtlndMakeArea"),
|
wtlndMakeArea: formatNumber(d.wtlndMakeArea, "wtlndMakeArea"),
|
||||||
etcCnt: formatNumber(d.etcCnt, "etcCnt"),
|
etcCnt: formatNumber(d.etcCnt, "etcCnt"),
|
||||||
rmrk: nullableTrimmedString(d.rmrk),
|
rmrk: normalizeGridRmrk(d.rmrk),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,17 +271,15 @@ async function waitForImrJobCompleted(
|
|||||||
options?.onProgress?.(Math.max(0, Math.min(100, Number(res.job_prog) || 0)));
|
options?.onProgress?.(Math.max(0, Math.min(100, Number(res.job_prog) || 0)));
|
||||||
if (res.status === "COMPLETED" && Number(res.job_prog) === 100) return;
|
if (res.status === "COMPLETED" && Number(res.job_prog) === 100) return;
|
||||||
if (res.status === "FAILED" || res.status === "ERROR" || res.status === "CANCELLED") {
|
if (res.status === "FAILED" || res.status === "ERROR" || res.status === "CANCELLED") {
|
||||||
throw new Error(res.error_msg || `시계열 검증이 ${res.status} 상태로 종료되었습니다.`);
|
throw new Error(res.error_msg || `IMR 검증이 ${res.status} 상태로 종료되었습니다.`);
|
||||||
}
|
}
|
||||||
await sleep(pollIntervalMs);
|
await sleep(pollIntervalMs);
|
||||||
}
|
}
|
||||||
throw new Error("시계열 검증 완료 대기 시간이 초과되었습니다.");
|
throw new Error("IMR 검증 완료 대기 시간이 초과되었습니다.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 하수도 통계 관리 > 13. 하수도 서비스 수준
|
// 하수도 통계 관리 > 13. 하수도 서비스 수준
|
||||||
const SewerageServiceLevelInp = () => {
|
const SewerageServiceLevelInp = () => {
|
||||||
const { sidoList } = useSearchConditionSidoList({ isInput: true });
|
|
||||||
sidoListRef.current = sidoList;
|
|
||||||
const { setMessage: alert } = useAlertStore((state) => state);
|
const { setMessage: alert } = useAlertStore((state) => state);
|
||||||
const { confirm } = useConfirm();
|
const { confirm } = useConfirm();
|
||||||
const { isAdminInfo } = useAdminStore();
|
const { isAdminInfo } = useAdminStore();
|
||||||
@@ -319,15 +307,9 @@ const SewerageServiceLevelInp = () => {
|
|||||||
const [isVerificationFailedByTab, setIsVerificationFailedByTab] = useState<
|
const [isVerificationFailedByTab, setIsVerificationFailedByTab] = useState<
|
||||||
Map<string, boolean>
|
Map<string, boolean>
|
||||||
>(new Map());
|
>(new Map());
|
||||||
const [footerVerificationByTab, setFooterVerificationByTab] = useState<
|
const [toolbarSnapshotByTab, setToolbarSnapshotByTab] = useState<
|
||||||
Map<string, VerificationResultLikeMap | null>
|
|
||||||
>(new Map());
|
|
||||||
const [_toolbarSnapshotByTab, setToolbarSnapshotByTab] = useState<
|
|
||||||
Map<string, TabToolbarSnapshot>
|
Map<string, TabToolbarSnapshot>
|
||||||
>(new Map());
|
>(new Map());
|
||||||
const [searchContextByTab, setSearchContextByTab] = useState<Map<string, SearchFormValues>>(
|
|
||||||
() => new Map(),
|
|
||||||
);
|
|
||||||
const [columnGuidesByTab, setColumnGuidesByTab] = useState<
|
const [columnGuidesByTab, setColumnGuidesByTab] = useState<
|
||||||
Record<string, Record<string, string>>
|
Record<string, Record<string, string>>
|
||||||
>({});
|
>({});
|
||||||
@@ -344,30 +326,42 @@ const SewerageServiceLevelInp = () => {
|
|||||||
const publicSewageFacilitiesAvailableRef = useRef(false);
|
const publicSewageFacilitiesAvailableRef = useRef(false);
|
||||||
activeTabRef.current = activeTab;
|
activeTabRef.current = activeTab;
|
||||||
|
|
||||||
const activeTabId = useTabStore((s) => s.activeTabId);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeTabId !== STATISTICS_INPUT_URL_PATH.SEWERAGE_SERVICE_LEVEL) return;
|
|
||||||
const tabKey = activeTab;
|
|
||||||
if (!tabKey) return;
|
|
||||||
if (Object.prototype.hasOwnProperty.call(columnGuidesByTab, tabKey)) return;
|
|
||||||
const statsCd =
|
|
||||||
SEWERAGE_SERVICE_LEVEL_COLUMN_GUIDE_STATS_CD_BY_TAB_KEY[tabKey] ?? tabKey;
|
|
||||||
|
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
void (async () => {
|
void (async () => {
|
||||||
const next = await fetchColumnGuidesRecord(statsCd);
|
const entries = await Promise.all(
|
||||||
|
SEWERAGE_SERVICE_LEVEL_COLUMN_GUIDE_STATS_CDS.map(async (statsCd) => {
|
||||||
|
try {
|
||||||
|
const res = await statisticsApi.getColumnGuides(statsCd);
|
||||||
|
if (res.status !== "success" || !Array.isArray(res.data)) {
|
||||||
|
return [statsCd, {}] as const;
|
||||||
|
}
|
||||||
|
const next: Record<string, string> = {};
|
||||||
|
for (const item of res.data) {
|
||||||
|
const key = item.engColNm?.trim();
|
||||||
|
const guide = item.columnGuide?.trim();
|
||||||
|
if (key && guide) next[key] = guide;
|
||||||
|
}
|
||||||
|
return [statsCd, next] as const;
|
||||||
|
} catch {
|
||||||
|
return [statsCd, {}] as const;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
if (cancelled) return;
|
if (cancelled) return;
|
||||||
setColumnGuidesByTab((prev) =>
|
const guidesByStatsCd = Object.fromEntries(entries);
|
||||||
Object.prototype.hasOwnProperty.call(prev, tabKey)
|
setColumnGuidesByTab(
|
||||||
? prev
|
Object.fromEntries(
|
||||||
: { ...prev, [tabKey]: next },
|
Object.entries(SEWERAGE_SERVICE_LEVEL_COLUMN_GUIDE_STATS_CD_BY_TAB_KEY).map(
|
||||||
|
([tabKey, statsCd]) => [tabKey, guidesByStatsCd[statsCd] ?? {}],
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
})();
|
})();
|
||||||
return () => {
|
return () => {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
};
|
};
|
||||||
}, [activeTabId, activeTab, columnGuidesByTab]);
|
}, []);
|
||||||
|
|
||||||
const commitToolbarSnapshotForLoadedTab = (
|
const commitToolbarSnapshotForLoadedTab = (
|
||||||
tabKey: string,
|
tabKey: string,
|
||||||
@@ -390,13 +384,6 @@ const SewerageServiceLevelInp = () => {
|
|||||||
);
|
);
|
||||||
return next;
|
return next;
|
||||||
});
|
});
|
||||||
if (searchContext) {
|
|
||||||
setSearchContextByTab((prev) => {
|
|
||||||
const next = new Map(prev);
|
|
||||||
next.set(tabKey, searchContext);
|
|
||||||
return next;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const applyRowMap = (
|
const applyRowMap = (
|
||||||
@@ -438,7 +425,6 @@ const SewerageServiceLevelInp = () => {
|
|||||||
const gridRows = mapServiceLevelListToGridRows(
|
const gridRows = mapServiceLevelListToGridRows(
|
||||||
(complaintList ?? []) as SewerageServiceLevelComplaintItem[],
|
(complaintList ?? []) as SewerageServiceLevelComplaintItem[],
|
||||||
commonInfo.ctpvNm,
|
commonInfo.ctpvNm,
|
||||||
searchContext,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
applyRowMap(mergeIntoExistingMap, (m) => {
|
applyRowMap(mergeIntoExistingMap, (m) => {
|
||||||
@@ -449,9 +435,6 @@ const SewerageServiceLevelInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
||||||
setSearchLoaded(true);
|
setSearchLoaded(true);
|
||||||
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
||||||
@@ -471,7 +454,6 @@ const SewerageServiceLevelInp = () => {
|
|||||||
const gridRows = mapServiceLevelListToGridRows(
|
const gridRows = mapServiceLevelListToGridRows(
|
||||||
(residentFriendlyFactList ?? []) as SewerageServiceLevelResidentFriendlyFactItem[],
|
(residentFriendlyFactList ?? []) as SewerageServiceLevelResidentFriendlyFactItem[],
|
||||||
commonInfo.ctpvNm,
|
commonInfo.ctpvNm,
|
||||||
searchContext,
|
|
||||||
);
|
);
|
||||||
if (!fromPreYear) {
|
if (!fromPreYear) {
|
||||||
publicSewageFacilitiesAvailableRef.current = gridRows.length > 0;
|
publicSewageFacilitiesAvailableRef.current = gridRows.length > 0;
|
||||||
@@ -488,9 +470,6 @@ const SewerageServiceLevelInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
||||||
setSearchLoaded(true);
|
setSearchLoaded(true);
|
||||||
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
||||||
@@ -514,9 +493,7 @@ const SewerageServiceLevelInp = () => {
|
|||||||
setTabStatusInfoMap(new Map());
|
setTabStatusInfoMap(new Map());
|
||||||
setTabStatsCdMap(new Map());
|
setTabStatsCdMap(new Map());
|
||||||
setIsVerificationFailedByTab(new Map());
|
setIsVerificationFailedByTab(new Map());
|
||||||
setFooterVerificationByTab(new Map());
|
|
||||||
setToolbarSnapshotByTab(new Map());
|
setToolbarSnapshotByTab(new Map());
|
||||||
setSearchContextByTab(new Map());
|
|
||||||
setActiveTab(firstTabKey);
|
setActiveTab(firstTabKey);
|
||||||
activeTabRef.current = firstTabKey;
|
activeTabRef.current = firstTabKey;
|
||||||
setLastSearchedValues(null);
|
setLastSearchedValues(null);
|
||||||
@@ -561,9 +538,7 @@ const SewerageServiceLevelInp = () => {
|
|||||||
setTabStatusInfoMap(new Map());
|
setTabStatusInfoMap(new Map());
|
||||||
setTabStatsCdMap(new Map());
|
setTabStatsCdMap(new Map());
|
||||||
setIsVerificationFailedByTab(new Map());
|
setIsVerificationFailedByTab(new Map());
|
||||||
setFooterVerificationByTab(new Map());
|
|
||||||
setToolbarSnapshotByTab(new Map());
|
setToolbarSnapshotByTab(new Map());
|
||||||
setSearchContextByTab(new Map());
|
|
||||||
setIsNotApplicable(false);
|
setIsNotApplicable(false);
|
||||||
activeTabRef.current = firstTabKey;
|
activeTabRef.current = firstTabKey;
|
||||||
setActiveTab(firstTabKey);
|
setActiveTab(firstTabKey);
|
||||||
@@ -682,19 +657,9 @@ const SewerageServiceLevelInp = () => {
|
|||||||
const tabKey = activeTabRef.current;
|
const tabKey = activeTabRef.current;
|
||||||
const isResidentTab = tabKey === ResidentFriendlyFactInpColumn.tabKey;
|
const isResidentTab = tabKey === ResidentFriendlyFactInpColumn.tabKey;
|
||||||
const latestRows = getTabGridRows(tabKey);
|
const latestRows = getTabGridRows(tabKey);
|
||||||
const noApplicable =
|
const noApplicable = isResidentTab && isNotApplicable;
|
||||||
isResidentTab &&
|
|
||||||
buildNoApplicableForRequest(
|
|
||||||
searchContextByTab.get(tabKey) ?? lastSearchedValues,
|
|
||||||
isNotApplicable,
|
|
||||||
latestRows.length === 0,
|
|
||||||
);
|
|
||||||
if (latestRows.length === 0) {
|
if (latestRows.length === 0) {
|
||||||
if (
|
if (isResidentTab && !noApplicable) {
|
||||||
isResidentTab &&
|
|
||||||
!noApplicable &&
|
|
||||||
buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)
|
|
||||||
) {
|
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -735,13 +700,7 @@ const SewerageServiceLevelInp = () => {
|
|||||||
return next;
|
return next;
|
||||||
});
|
});
|
||||||
|
|
||||||
const noApplicable =
|
const noApplicable = isResidentTab && isNotApplicable;
|
||||||
isResidentTab &&
|
|
||||||
buildNoApplicableForRequest(
|
|
||||||
searchContextByTab.get(tabKey) ?? lastSearchedValues,
|
|
||||||
isNotApplicable,
|
|
||||||
latestRows.length === 0,
|
|
||||||
);
|
|
||||||
const complaintSubmitList = buildComplaintSaveList(latestRows);
|
const complaintSubmitList = buildComplaintSaveList(latestRows);
|
||||||
const residentSubmitList = noApplicable
|
const residentSubmitList = noApplicable
|
||||||
? []
|
? []
|
||||||
@@ -751,12 +710,7 @@ const SewerageServiceLevelInp = () => {
|
|||||||
alert("제출할 데이터가 없습니다.");
|
alert("제출할 데이터가 없습니다.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (
|
if (isResidentTab && !noApplicable && residentSubmitList.length === 0) {
|
||||||
isResidentTab &&
|
|
||||||
!noApplicable &&
|
|
||||||
residentSubmitList.length === 0 &&
|
|
||||||
buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)
|
|
||||||
) {
|
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -771,7 +725,11 @@ const SewerageServiceLevelInp = () => {
|
|||||||
const submitInfoBase = {
|
const submitInfoBase = {
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
laePicNm: submitInfo.laePicNm,
|
laePicNm: submitInfo.laePicNm,
|
||||||
laePicTelNo: submitInfo.laePicTelNo,
|
laePicTelNo: submitInfo.laePicTelNo,
|
||||||
laeKbrdrDeptNm: submitInfo.laeKbrdrDeptNm,
|
laeKbrdrDeptNm: submitInfo.laeKbrdrDeptNm,
|
||||||
@@ -783,8 +741,12 @@ const SewerageServiceLevelInp = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const verificationQuery = {
|
const verificationQuery = {
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
statsCd: statsCdForTab,
|
statsCd: statsCdForTab,
|
||||||
};
|
};
|
||||||
@@ -829,15 +791,14 @@ const SewerageServiceLevelInp = () => {
|
|||||||
|
|
||||||
if (finalStatus === "5") {
|
if (finalStatus === "5") {
|
||||||
setGlobalProgress(50);
|
setGlobalProgress(50);
|
||||||
setGlobalProgressLabel("시계열 검증 진행 중...");
|
setGlobalProgressLabel("IMR 검증 진행 중...");
|
||||||
const imrParam = {
|
const imrParam = {
|
||||||
user_id: userInfo.userUnqId,
|
user_id: userInfo.userUnqId,
|
||||||
sewer_bzmn_cd: lastSearchedValues?.bsnmCd ?? "",
|
sewer_bzmn_cd: lastSearchedValues.bsnmCd ?? "",
|
||||||
stats_cd: statsCdForTab,
|
stats_cd: statsCdForTab,
|
||||||
stats_yr: lastSearchedValues.year ?? "",
|
stats_yr: lastSearchedValues.year ?? "",
|
||||||
lae_sbmsn_stts_cd: activeTabStatus?.laeSbmsnSttsCd === "4" ? "4" : "2",
|
lae_sbmsn_stts_cd: activeTabStatus?.laeSbmsnSttsCd === "4" ? "4" : "2",
|
||||||
gen_verify_stts_cd: nvpassed ? "1" : "2",
|
gen_verify_stts_cd: nvpassed ? "1" : "2",
|
||||||
hb_pass_yn: response.data?.isHbPassed,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -914,17 +875,15 @@ const SewerageServiceLevelInp = () => {
|
|||||||
return next;
|
return next;
|
||||||
});
|
});
|
||||||
|
|
||||||
const noApplicable =
|
const noApplicable = isResidentTab && isNotApplicable;
|
||||||
isResidentTab &&
|
|
||||||
buildNoApplicableForRequest(
|
|
||||||
searchContextByTab.get(tabKey) ?? lastSearchedValues,
|
|
||||||
isNotApplicable,
|
|
||||||
latestRows.length === 0,
|
|
||||||
);
|
|
||||||
const baseRequest = {
|
const baseRequest = {
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -954,11 +913,7 @@ const SewerageServiceLevelInp = () => {
|
|||||||
const saveList = noApplicable
|
const saveList = noApplicable
|
||||||
? []
|
? []
|
||||||
: buildResidentFriendlyFactSaveList(latestRows);
|
: buildResidentFriendlyFactSaveList(latestRows);
|
||||||
if (
|
if (!noApplicable && saveList.length === 0) {
|
||||||
!noApplicable &&
|
|
||||||
saveList.length === 0 &&
|
|
||||||
buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)
|
|
||||||
) {
|
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1018,8 +973,12 @@ const SewerageServiceLevelInp = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const requestData: cancelSubmitRequest = {
|
const requestData: cancelSubmitRequest = {
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
mdfrId: userInfo.userUnqId,
|
mdfrId: userInfo.userUnqId,
|
||||||
statsCd: statsCdForTab,
|
statsCd: statsCdForTab,
|
||||||
@@ -1057,10 +1016,10 @@ const SewerageServiceLevelInp = () => {
|
|||||||
for (const tab of SewerageServiceLevelInpTabList) {
|
for (const tab of SewerageServiceLevelInpTabList) {
|
||||||
const tabKey = tab.tabKey;
|
const tabKey = tab.tabKey;
|
||||||
const canEdit =
|
const canEdit =
|
||||||
(computeTabEnterable(
|
computeTabEnterable(
|
||||||
tabStatusInfoMap.get(tabKey) ?? null,
|
tabStatusInfoMap.get(tabKey) ?? null,
|
||||||
inputPeriodEnterable,
|
inputPeriodEnterable,
|
||||||
) || isAdminInfo) && inputPeriodEnterable;
|
) || isAdminInfo;
|
||||||
const rawColumns = (tab.columns ?? []) as ColumnConfig[];
|
const rawColumns = (tab.columns ?? []) as ColumnConfig[];
|
||||||
const base = canEdit
|
const base = canEdit
|
||||||
? rawColumns
|
? rawColumns
|
||||||
@@ -1077,15 +1036,15 @@ const SewerageServiceLevelInp = () => {
|
|||||||
return map;
|
return map;
|
||||||
}, [tabStatusInfoMap, inputPeriodEnterable, isAdminInfo, columnGuidesByTab]);
|
}, [tabStatusInfoMap, inputPeriodEnterable, isAdminInfo, columnGuidesByTab]);
|
||||||
|
|
||||||
const searchContextForToolbar = searchContextByTab.get(activeTab) ?? lastSearchedValues;
|
|
||||||
const activeTabStatus = tabStatusInfoMap.get(activeTab) ?? null;
|
const activeTabStatus = tabStatusInfoMap.get(activeTab) ?? null;
|
||||||
const activeTabRowData = rowDataMap.get(activeTab) ?? [];
|
const activeTabRowData = rowDataMap.get(activeTab) ?? [];
|
||||||
const activeTabToolbar =
|
const activeTabToolbar =
|
||||||
|
toolbarSnapshotByTab.get(activeTab) ??
|
||||||
computeTabToolbarSnapshot(
|
computeTabToolbarSnapshot(
|
||||||
activeTabStatus,
|
activeTabStatus,
|
||||||
tabRowDataExists(rowDataMap, activeTab),
|
tabRowDataExists(rowDataMap, activeTab),
|
||||||
hasSearched,
|
hasSearched,
|
||||||
searchContextForToolbar,
|
lastSearchedValues,
|
||||||
inputPeriodEnterable,
|
inputPeriodEnterable,
|
||||||
isAdminInfo,
|
isAdminInfo,
|
||||||
);
|
);
|
||||||
@@ -1096,14 +1055,12 @@ const SewerageServiceLevelInp = () => {
|
|||||||
activeTabToolbar.showEnterableToolbarButtons && toolbarGroupAllowed;
|
activeTabToolbar.showEnterableToolbarButtons && toolbarGroupAllowed;
|
||||||
const showActionToolbarCard =
|
const showActionToolbarCard =
|
||||||
activeTabToolbar.showActionToolbarCard && toolbarGroupAllowed;
|
activeTabToolbar.showActionToolbarCard && toolbarGroupAllowed;
|
||||||
const submitOk = buildSubmitOkForToolbar(searchContextForToolbar);
|
|
||||||
const showNotApplicableForResidentTab =
|
const showNotApplicableForResidentTab =
|
||||||
activeTab === ResidentFriendlyFactInpColumn.tabKey &&
|
activeTab === ResidentFriendlyFactInpColumn.tabKey &&
|
||||||
searchLoaded &&
|
searchLoaded &&
|
||||||
hasSearched &&
|
hasSearched &&
|
||||||
activeTabRowData.length === 0 &&
|
activeTabRowData.length === 0 &&
|
||||||
computeTabEnterable(activeTabStatus, inputPeriodEnterable) &&
|
computeTabEnterable(activeTabStatus, inputPeriodEnterable);
|
||||||
submitOk;
|
|
||||||
const showSecondaryToolbarCard =
|
const showSecondaryToolbarCard =
|
||||||
hasSearched &&
|
hasSearched &&
|
||||||
toolbarGroupAllowed &&
|
toolbarGroupAllowed &&
|
||||||
@@ -1114,8 +1071,9 @@ const SewerageServiceLevelInp = () => {
|
|||||||
const statsCd = tabStatsCdMap.get(activeTab);
|
const statsCd = tabStatsCdMap.get(activeTab);
|
||||||
if (!ctx?.year || !ctx?.sido || !ctx?.bsnmCd || !statsCd) return null;
|
if (!ctx?.year || !ctx?.sido || !ctx?.bsnmCd || !statsCd) return null;
|
||||||
return {
|
return {
|
||||||
...toInputSearchRegion(sidoListRef.current, ctx),
|
sewerBzmnCd: ctx.bsnmCd,
|
||||||
ctpvNm: ctx.sido,
|
ctpvNm: ctx.sido,
|
||||||
|
sggNm: ctx.gugun === "ALL" ? "" : (ctx.gugun ?? ""),
|
||||||
statsYr: ctx.year,
|
statsYr: ctx.year,
|
||||||
statsCd,
|
statsCd,
|
||||||
};
|
};
|
||||||
@@ -1152,10 +1110,10 @@ const SewerageServiceLevelInp = () => {
|
|||||||
.map((e) => {
|
.map((e) => {
|
||||||
const prefix =
|
const prefix =
|
||||||
e.vrfcCd === "IMR"
|
e.vrfcCd === "IMR"
|
||||||
? "시계열 검증 - "
|
? "IMR검증 - "
|
||||||
: e.vrfcCd === "NV"
|
: e.vrfcCd === "NV"
|
||||||
? "일반검증 - "
|
? "일반검증 - "
|
||||||
: "모집단 검증 - ";
|
: "HB검증 - ";
|
||||||
return `${prefix}${e.rsnExpln}(검증 기준값: ${e.compVlCn} / 현재 입력값: ${e.nowVlCn})`;
|
return `${prefix}${e.rsnExpln}(검증 기준값: ${e.compVlCn} / 현재 입력값: ${e.nowVlCn})`;
|
||||||
})
|
})
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
@@ -1178,7 +1136,6 @@ const SewerageServiceLevelInp = () => {
|
|||||||
<>
|
<>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<SearchForm
|
<SearchForm
|
||||||
isInput
|
|
||||||
key={searchFormRemountKey}
|
key={searchFormRemountKey}
|
||||||
defaultValues={verificationSearchDefaults ?? undefined}
|
defaultValues={verificationSearchDefaults ?? undefined}
|
||||||
onSubmit={handleSearch}
|
onSubmit={handleSearch}
|
||||||
@@ -1186,8 +1143,8 @@ const SewerageServiceLevelInp = () => {
|
|||||||
onValuesChange={setSearchValues}
|
onValuesChange={setSearchValues}
|
||||||
/>
|
/>
|
||||||
{showActionToolbarCard && (
|
{showActionToolbarCard && (
|
||||||
<div className="card !py-0">
|
<div className="card !py-0">
|
||||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||||
<VerificationResultButton
|
<VerificationResultButton
|
||||||
VerificationResultButtonFunc={openVerificationHistoryDialog}
|
VerificationResultButtonFunc={openVerificationHistoryDialog}
|
||||||
isVerificationFailed={
|
isVerificationFailed={
|
||||||
@@ -1199,19 +1156,19 @@ const SewerageServiceLevelInp = () => {
|
|||||||
<LastYearDataButton
|
<LastYearDataButton
|
||||||
getLastYearDataFunc={() => void getLastYearDataFunc()}
|
getLastYearDataFunc={() => void getLastYearDataFunc()}
|
||||||
/>
|
/>
|
||||||
{submitOk && <SubmitButton submitFunc={submitFunc} />}
|
<SubmitButton submitFunc={submitFunc} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{activeTabStatus?.laeSbmsnSttsCd === "2" && submitOk && (
|
{activeTabStatus?.laeSbmsnSttsCd === "2" && (
|
||||||
<CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />
|
<CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />
|
||||||
)}
|
)}
|
||||||
{showSaveInToolbar && <SaveButton saveFunc={saveFunc} />}
|
{showSaveInToolbar && <SaveButton saveFunc={saveFunc} />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{showSecondaryToolbarCard && (
|
{showSecondaryToolbarCard && (
|
||||||
<div className="card !py-0">
|
<div className="card !py-0">
|
||||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||||
{showNotApplicableForResidentTab && (
|
{showNotApplicableForResidentTab && (
|
||||||
<NotApplicableCheckButton
|
<NotApplicableCheckButton
|
||||||
isCheck={isNotApplicable}
|
isCheck={isNotApplicable}
|
||||||
@@ -1246,11 +1203,11 @@ const SewerageServiceLevelInp = () => {
|
|||||||
const tabKey = info.tabKey;
|
const tabKey = info.tabKey;
|
||||||
const rowData = rowDataMap.get(tabKey) ?? [];
|
const rowData = rowDataMap.get(tabKey) ?? [];
|
||||||
const tabEnterableForGrid =
|
const tabEnterableForGrid =
|
||||||
(computeTabEnterable(
|
computeTabEnterable(
|
||||||
tabStatusInfoMap.get(tabKey) ?? null,
|
tabStatusInfoMap.get(tabKey) ?? null,
|
||||||
inputPeriodEnterable,
|
inputPeriodEnterable,
|
||||||
) || isAdminInfo) && inputPeriodEnterable;
|
) || isAdminInfo;
|
||||||
const gugunOk = buildGugunOkForToolbar(searchContextForToolbar);
|
const gugunOk = buildGugunOkForToolbar(lastSearchedValues);
|
||||||
const tabStatusInfo = tabStatusInfoMap.get(tabKey) ?? null;
|
const tabStatusInfo = tabStatusInfoMap.get(tabKey) ?? null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -1288,9 +1245,6 @@ const SewerageServiceLevelInp = () => {
|
|||||||
excelExportSearchContext={toExcelExportSearchContextFromSearchForm(lastSearchedValues ?? searchValues)}
|
excelExportSearchContext={toExcelExportSearchContextFromSearchForm(lastSearchedValues ?? searchValues)}
|
||||||
isExcelExport
|
isExcelExport
|
||||||
cellStyleCallback={verificationCellStyle}
|
cellStyleCallback={verificationCellStyle}
|
||||||
footerVerificationResult={
|
|
||||||
footerVerificationByTab.get(tabKey) ?? null
|
|
||||||
}
|
|
||||||
cellTooltipCallback={verificationCellTooltip}
|
cellTooltipCallback={verificationCellTooltip}
|
||||||
getGridDataRef={
|
getGridDataRef={
|
||||||
activeTab === tabKey ? getGridDataRef : undefined
|
activeTab === tabKey ? getGridDataRef : undefined
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
import { useAlertStore } from "@/shared/lib";
|
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
|
||||||
import { LoadingWithAnimation } from "@common/components";
|
|
||||||
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
import type { ColumnConfig } from "@/components/type/DataGrid.type";
|
import type { ColumnConfig } from "@/components/type/DataGrid.type";
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
|
import { useAlertStore } from "@/shared/lib";
|
||||||
|
import { LoadingWithAnimation } from "@common/components";
|
||||||
|
|
||||||
const StatisticsReviewHistory = () => {
|
const StatisticsReviewHistory = () => {
|
||||||
const { setMessage: alert } = useAlertStore((state) => state);
|
const { setMessage: alert } = useAlertStore((state) => state);
|
||||||
@@ -70,7 +69,7 @@ const StatisticsReviewHistory = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<SearchForm isInput onSubmit={handleSearch} onReset={handleReset} />
|
<SearchForm onSubmit={handleSearch} onReset={handleReset} />
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
||||||
<div className="relative size-[5rem]">
|
<div className="relative size-[5rem]">
|
||||||
|
|||||||
@@ -4,33 +4,32 @@ import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
|||||||
import { RealGridReact } from "realgrid-react";
|
import { RealGridReact } from "realgrid-react";
|
||||||
import useSWR, { useSWRConfig } from "swr";
|
import useSWR, { useSWRConfig } from "swr";
|
||||||
|
|
||||||
import { useActiveTabRegAuthorityAllowed, useAlertStore, useSearchConditionSidoList } from "@/shared/lib";
|
import { useActiveTabRegAuthorityAllowed, useAlertStore } from "@/shared/lib";
|
||||||
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
||||||
import { StatisticsInputStatusApi } from "@/entities/statistics/api/input/statistics-input-status-service";
|
import { StatisticsInputStatusApi } from "@/entities/statistics/api/input/statistics-input-status-service";
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
|
import {
|
||||||
|
isInputPeriodCurrent,
|
||||||
|
type CheckInputPeriodItem,
|
||||||
|
} from "@/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface";
|
||||||
|
import type { StatsInputStatusApproveItem } from "@/entities/statistics/model/statistics-interface";
|
||||||
import type {
|
import type {
|
||||||
StatsInputStatusListApiResponse,
|
StatsInputStatusListApiResponse,
|
||||||
StatsInputStatusListRequestParams,
|
StatsInputStatusListRequestParams,
|
||||||
} from "@/entities/statistics/model/input/statistics-input-status-interface";
|
} from "@/entities/statistics/model/input/statistics-input-status-interface";
|
||||||
import {
|
|
||||||
type CheckInputPeriodItem,
|
|
||||||
isInputPeriodCurrent,
|
|
||||||
} from "@/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface";
|
|
||||||
import type { StatsInputStatusApproveItem } from "@/entities/statistics/model/statistics-interface";
|
|
||||||
import { isGugunOkForToolbar } from "@/entities/statistics";
|
|
||||||
import { LoadingWithAnimation } from "@common/components";
|
|
||||||
|
|
||||||
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
||||||
|
|
||||||
|
import { LoadingWithAnimation } from "@common/components";
|
||||||
import ApproveButton from "@/components/button/ApproveButton";
|
import ApproveButton from "@/components/button/ApproveButton";
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
|
import type { DataCellClickCallbackParams } from "@/components/type/DataGrid.type";
|
||||||
import {
|
import {
|
||||||
ExceptionProcessingHistoryDialog,
|
ExceptionProcessingHistoryDialog,
|
||||||
type ExceptionProcessingHistoryQueryContext,
|
type ExceptionProcessingHistoryQueryContext,
|
||||||
} from "@/components/module/ExceptionProcessingHistoryDialog";
|
} from "@/components/module/ExceptionProcessingHistoryDialog";
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
import type { DataCellClickCallbackParams } from "@/components/type/DataGrid.type";
|
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
|
import { doList } from "@/components/util/column/input/DoList";
|
||||||
import { StatsInputStatusInpColumn } from "@/components/util/column/input/StatsInputStatusInpColumn";
|
import { StatsInputStatusInpColumn } from "@/components/util/column/input/StatsInputStatusInpColumn";
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
import { useTabStore } from "@/store/tab-store";
|
import { useTabStore } from "@/store/tab-store";
|
||||||
@@ -44,7 +43,6 @@ const getStatsInputStatusFetcher = async (
|
|||||||
// 하수도 통계 관리 > 00. 통계 입력 현황
|
// 하수도 통계 관리 > 00. 통계 입력 현황
|
||||||
const StatsInputStatusInp = () => {
|
const StatsInputStatusInp = () => {
|
||||||
|
|
||||||
const { sidoList } = useSearchConditionSidoList();
|
|
||||||
const { setMessage: alert } = useAlertStore((state) => state);
|
const { setMessage: alert } = useAlertStore((state) => state);
|
||||||
const { confirm } = useConfirm();
|
const { confirm } = useConfirm();
|
||||||
const activeTabId = useTabStore((state) => state.activeTabId);
|
const activeTabId = useTabStore((state) => state.activeTabId);
|
||||||
@@ -255,7 +253,9 @@ const StatsInputStatusInp = () => {
|
|||||||
await mutate(["stats-input-status", searchParams]);
|
await mutate(["stats-input-status", searchParams]);
|
||||||
}, [mutate, searchParams]);
|
}, [mutate, searchParams]);
|
||||||
|
|
||||||
const gugunOkOrNotDoList = isGugunOkForToolbar(sidoList, lastSearchedValues);
|
const gugunOkOrNotDoList = doList.includes(lastSearchedValues?.bsnmCd || "")
|
||||||
|
? Boolean(lastSearchedValues?.gugun && lastSearchedValues.gugun !== "ALL")
|
||||||
|
: true;
|
||||||
|
|
||||||
const allRowsLaeSbmsnApproved = useMemo(
|
const allRowsLaeSbmsnApproved = useMemo(
|
||||||
() =>
|
() =>
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { Controller,useForm } from "react-hook-form";
|
import { useForm, Controller } from "react-hook-form";
|
||||||
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { statisticsInputSubmitInfoSchema, type StatisticsInputSubmitInfoFormData } from "@/entities/statistics/model/statistics-input-submit-info-schema";
|
||||||
import { type StatisticsInputSubmitInfoFormData,statisticsInputSubmitInfoSchema } from "@/entities/statistics/model/statistics-input-submit-info-schema";
|
|
||||||
import type { SewerageStatusInfo } from "@/entities/statistics/model/statistics-interface";
|
import type { SewerageStatusInfo } from "@/entities/statistics/model/statistics-interface";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Dialog,
|
Dialog,
|
||||||
@@ -15,12 +14,12 @@ import {
|
|||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
Input,
|
Input,
|
||||||
LoadingWithAnimation,
|
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
TableCell,
|
TableCell,
|
||||||
TableHead,
|
TableHead,
|
||||||
TableRow,
|
TableRow,
|
||||||
|
LoadingWithAnimation,
|
||||||
} from "@common/components";
|
} from "@common/components";
|
||||||
|
|
||||||
/** 숫자만 추출 후 하이픈 포맷 (010-1234-5678, 02-123-4567 등) */
|
/** 숫자만 추출 후 하이픈 포맷 (010-1234-5678, 02-123-4567 등) */
|
||||||
|
|||||||
@@ -1,68 +1,19 @@
|
|||||||
import {
|
import {
|
||||||
type Dispatch,
|
|
||||||
type SetStateAction,
|
|
||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
useMemo,
|
useMemo,
|
||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
|
type Dispatch,
|
||||||
|
type SetStateAction,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { flushSync } from "react-dom";
|
|
||||||
|
|
||||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||||
import { ValueType } from "realgrid";
|
|
||||||
import type { RealGridReact } from "realgrid-react";
|
|
||||||
|
|
||||||
import { useAlertStore, useGlobalProgressStore, useStatisticsInputToolbarGroupGate, useSearchConditionSidoList } from "@/shared/lib";
|
|
||||||
import { STATISTICS_INPUT_URL_PATH } from "@/shared/lib/stats-cd-input-navigation";
|
|
||||||
import { useStatisticsInputPendingNavigation } from "@/shared/lib/use-statistics-input-pending-navigation";
|
|
||||||
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
|
||||||
import { nullableTrimmedString } from "@/components/util/input/nullableString";
|
|
||||||
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
|
||||||
import { statisticsInputWaterReuseApi } from "@/entities/statistics/api/input/statistics-input-water-reuse-service";
|
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
|
||||||
import {
|
|
||||||
type PublicSewageTreatWaterReuseItem,
|
|
||||||
type PublicSewageTreatWaterReuseSaveItem,
|
|
||||||
type RainFallUtilFactStatusItem,
|
|
||||||
type RainFallUtilFactStatusSaveItem,
|
|
||||||
type RecycledWaterStatusItem,
|
|
||||||
type RecycledWaterStatusSaveItem,
|
|
||||||
type TreatWaterReuseBusinessApprStatusItem,
|
|
||||||
type TreatWaterReuseBusinessApprStatusSaveItem,
|
|
||||||
type TreatWaterReuseDesignConstStatusItem,
|
|
||||||
type TreatWaterReuseDesignConstStatusSaveItem,
|
|
||||||
WATER_REUSE_BUSINESS_APPR_STATS_CD,
|
|
||||||
WATER_REUSE_DESIGN_CONST_STATS_CD,
|
|
||||||
WATER_REUSE_PUBLIC_SEWAGE_TREAT_STATS_CD,
|
|
||||||
WATER_REUSE_RAINFALL_UTIL_FACT_STATS_CD,
|
|
||||||
WATER_REUSE_RECYCLED_WATER_STATS_CD,
|
|
||||||
type WaterReuseRequestParams,
|
|
||||||
type WaterReuseVerificationResult,
|
|
||||||
} from "@/entities/statistics/model/input/statistics-input-water-reuse-interface";
|
|
||||||
import { isInputPeriodCurrent } from "@/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface";
|
|
||||||
import type { StatisticsInputSubmitInfoFormData } from "@/entities/statistics/model/statistics-input-submit-info-schema";
|
|
||||||
import type {
|
|
||||||
ApiResponse,
|
|
||||||
cancelSubmitRequest,
|
|
||||||
ImrStatusResponse,
|
|
||||||
SewerageStatusInfo,
|
|
||||||
Sgg,
|
|
||||||
Sido,
|
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
|
||||||
import {
|
|
||||||
filterBySelectedAdmdstCd,
|
|
||||||
isGugunOkForToolbar,
|
|
||||||
isSubmitOkForToolbar,
|
|
||||||
resolveNoApplicableForRequest,
|
|
||||||
toInputSearchRegion,
|
|
||||||
} from "@/entities/statistics";
|
|
||||||
|
|
||||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||||
|
import { ValueType } from "realgrid";
|
||||||
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
import type { RealGridReact } from "realgrid-react";
|
||||||
|
import { flushSync } from "react-dom";
|
||||||
import SubmitDailog from "./SubmitDailog";
|
|
||||||
|
|
||||||
import AddArticleButton from "@/components/button/AddArticleButton";
|
import AddArticleButton from "@/components/button/AddArticleButton";
|
||||||
import CancelSubmitButton from "@/components/button/CancelSubmitButton";
|
import CancelSubmitButton from "@/components/button/CancelSubmitButton";
|
||||||
@@ -74,39 +25,83 @@ import SubmitButton from "@/components/button/SumitButton";
|
|||||||
import UpdateOperateDataButton from "@/components/button/UpdateOperateDataButton";
|
import UpdateOperateDataButton from "@/components/button/UpdateOperateDataButton";
|
||||||
import VerificationResultButton from "@/components/button/VerificationResultButton";
|
import VerificationResultButton from "@/components/button/VerificationResultButton";
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
|
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
||||||
import { openVerificationResultDialogIfNeeded } from "@/components/module/post-submit-verification-results";
|
import { openVerificationResultDialogIfNeeded } from "@/components/module/post-submit-verification-results";
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
||||||
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
||||||
import type { ColumnConfig, ColumnInfo } from "@/components/type/DataGrid.type";
|
import type { ColumnConfig, ColumnInfo } from "@/components/type/DataGrid.type";
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
|
import { doList } from "@/components/util/column/input/DoList";
|
||||||
import { PublicSewageTreatWaterReuseInpColumn } from "@/components/util/column/input/waterReuse/PublicSewageTreatWaterReuseInpColumn";
|
import { PublicSewageTreatWaterReuseInpColumn } from "@/components/util/column/input/waterReuse/PublicSewageTreatWaterReuseInpColumn";
|
||||||
import { RainFallUtilFactStatusInpColumn } from "@/components/util/column/input/waterReuse/RainFallUtilFactStatusInpColumn";
|
import { RainFallUtilFactStatusInpColumn } from "@/components/util/column/input/waterReuse/RainFallUtilFactStatusInpColumn";
|
||||||
import { RecycledWaterStatusInpColumn } from "@/components/util/column/input/waterReuse/RecycledWaterStatusInpColumn";
|
import { RecycledWaterStatusInpColumn } from "@/components/util/column/input/waterReuse/RecycledWaterStatusInpColumn";
|
||||||
import { TreatWaterReuseBusinessApprStatusInpColumn } from "@/components/util/column/input/waterReuse/TreatWaterReuseBusinessApprStatusInpColumn";
|
import { TreatWaterReuseBusinessApprStatusInpColumn } from "@/components/util/column/input/waterReuse/TreatWaterReuseBusinessApprStatusInpColumn";
|
||||||
import { TreatWaterReuseDesignConstStatusInpColumn } from "@/components/util/column/input/waterReuse/TreatWaterReuseDesignConstStatusInpColumn";
|
import { TreatWaterReuseDesignConstStatusInpColumn } from "@/components/util/column/input/waterReuse/TreatWaterReuseDesignConstStatusInpColumn";
|
||||||
import { fetchColumnGuidesRecord } from "@/components/util/grid/columnGuides";
|
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
import { formatCompactYmdForGrid, toCompactYmdOrNull } from "@/components/util/grid/ymdFormat";
|
|
||||||
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
|
||||||
import {
|
import {
|
||||||
patchFooterVerificationByTab,
|
|
||||||
patchVerificationFailedByTab,
|
patchVerificationFailedByTab,
|
||||||
} from "@/components/util/input/verification-failed-flag";
|
} from "@/components/util/input/verification-failed-flag";
|
||||||
import type { VerificationResultLikeMap } from "@/components/util/input/verification-result-display";
|
import { formatCompactYmdForGrid, toCompactYmdOrNull } from "@/components/util/grid/ymdFormat";
|
||||||
|
import { statisticsInputWaterReuseApi } from "@/entities/statistics/api/input/statistics-input-water-reuse-service";
|
||||||
|
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
||||||
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
|
import { isInputPeriodCurrent } from "@/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface";
|
||||||
|
import {
|
||||||
|
WATER_REUSE_BUSINESS_APPR_STATS_CD,
|
||||||
|
WATER_REUSE_DESIGN_CONST_STATS_CD,
|
||||||
|
WATER_REUSE_PUBLIC_SEWAGE_TREAT_STATS_CD,
|
||||||
|
WATER_REUSE_RAINFALL_UTIL_FACT_STATS_CD,
|
||||||
|
WATER_REUSE_RECYCLED_WATER_STATS_CD,
|
||||||
|
type PublicSewageTreatWaterReuseItem,
|
||||||
|
type PublicSewageTreatWaterReuseSaveItem,
|
||||||
|
type RainFallUtilFactStatusItem,
|
||||||
|
type RainFallUtilFactStatusSaveItem,
|
||||||
|
type RecycledWaterStatusItem,
|
||||||
|
type RecycledWaterStatusSaveItem,
|
||||||
|
type TreatWaterReuseBusinessApprStatusItem,
|
||||||
|
type TreatWaterReuseBusinessApprStatusSaveItem,
|
||||||
|
type TreatWaterReuseDesignConstStatusItem,
|
||||||
|
type TreatWaterReuseDesignConstStatusSaveItem,
|
||||||
|
type WaterReuseRequestParams,
|
||||||
|
type WaterReuseVerificationResult,
|
||||||
|
} from "@/entities/statistics/model/input/statistics-input-water-reuse-interface";
|
||||||
|
import type {
|
||||||
|
ApiResponse,
|
||||||
|
ImrStatusResponse,
|
||||||
|
Sgg,
|
||||||
|
SewerageStatusInfo,
|
||||||
|
cancelSubmitRequest,
|
||||||
|
} from "@/entities/statistics/model/statistics-interface";
|
||||||
|
import type { StatisticsInputSubmitInfoFormData } from "@/entities/statistics/model/statistics-input-submit-info-schema";
|
||||||
|
import { useAlertStore, useGlobalProgressStore, useStatisticsInputToolbarGroupGate } from "@/shared/lib";
|
||||||
|
import { STATISTICS_INPUT_URL_PATH } from "@/shared/lib/stats-cd-input-navigation";
|
||||||
|
import { useStatisticsInputPendingNavigation } from "@/shared/lib/use-statistics-input-pending-navigation";
|
||||||
|
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
||||||
import { useAdminStore } from "@/store/admin-store";
|
import { useAdminStore } from "@/store/admin-store";
|
||||||
import { useTabStore } from "@/store/tab-store";
|
|
||||||
|
|
||||||
const WaterReuseInpTabList = [
|
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
||||||
PublicSewageTreatWaterReuseInpColumn,
|
|
||||||
RecycledWaterStatusInpColumn,
|
import SubmitDailog from "./SubmitDailog";
|
||||||
RainFallUtilFactStatusInpColumn,
|
|
||||||
TreatWaterReuseDesignConstStatusInpColumn,
|
const WaterReuseInpTabList = [
|
||||||
|
PublicSewageTreatWaterReuseInpColumn,
|
||||||
|
RecycledWaterStatusInpColumn,
|
||||||
|
RainFallUtilFactStatusInpColumn,
|
||||||
|
TreatWaterReuseDesignConstStatusInpColumn,
|
||||||
TreatWaterReuseBusinessApprStatusInpColumn,
|
TreatWaterReuseBusinessApprStatusInpColumn,
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
const firstTabKey = PublicSewageTreatWaterReuseInpColumn.tabKey;
|
const firstTabKey = PublicSewageTreatWaterReuseInpColumn.tabKey;
|
||||||
|
|
||||||
|
const WATER_REUSE_COLUMN_GUIDE_STATS_CDS = [
|
||||||
|
WATER_REUSE_PUBLIC_SEWAGE_TREAT_STATS_CD,
|
||||||
|
WATER_REUSE_RECYCLED_WATER_STATS_CD,
|
||||||
|
WATER_REUSE_RAINFALL_UTIL_FACT_STATS_CD,
|
||||||
|
WATER_REUSE_DESIGN_CONST_STATS_CD,
|
||||||
|
WATER_REUSE_BUSINESS_APPR_STATS_CD,
|
||||||
|
] as const;
|
||||||
|
|
||||||
const WATER_REUSE_COLUMN_GUIDE_STATS_CD_BY_TAB_KEY: Record<string, string> = {
|
const WATER_REUSE_COLUMN_GUIDE_STATS_CD_BY_TAB_KEY: Record<string, string> = {
|
||||||
[PublicSewageTreatWaterReuseInpColumn.tabKey]: WATER_REUSE_PUBLIC_SEWAGE_TREAT_STATS_CD,
|
[PublicSewageTreatWaterReuseInpColumn.tabKey]: WATER_REUSE_PUBLIC_SEWAGE_TREAT_STATS_CD,
|
||||||
[RecycledWaterStatusInpColumn.tabKey]: WATER_REUSE_RECYCLED_WATER_STATS_CD,
|
[RecycledWaterStatusInpColumn.tabKey]: WATER_REUSE_RECYCLED_WATER_STATS_CD,
|
||||||
@@ -167,22 +162,10 @@ const computeTabEnterable = (
|
|||||||
return periodEnterable;
|
return periodEnterable;
|
||||||
};
|
};
|
||||||
|
|
||||||
const sidoListRef: { current: Sido[] } = { current: [] };
|
|
||||||
|
|
||||||
function buildGugunOkForToolbar(values: SearchFormValues | null): boolean {
|
function buildGugunOkForToolbar(values: SearchFormValues | null): boolean {
|
||||||
return isGugunOkForToolbar(sidoListRef.current, values);
|
return doList.includes(values?.bsnmCd || "")
|
||||||
}
|
? Boolean(values?.gugun && values.gugun !== "ALL")
|
||||||
|
: true;
|
||||||
function buildSubmitOkForToolbar(values: SearchFormValues | null): boolean {
|
|
||||||
return isSubmitOkForToolbar(sidoListRef.current, values);
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildNoApplicableForRequest(
|
|
||||||
values: SearchFormValues | null,
|
|
||||||
checked: boolean,
|
|
||||||
isSaveListEmpty: boolean,
|
|
||||||
): boolean {
|
|
||||||
return resolveNoApplicableForRequest(sidoListRef.current, values, checked, isSaveListEmpty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeTabToolbarSnapshot(
|
function computeTabToolbarSnapshot(
|
||||||
@@ -196,7 +179,7 @@ function computeTabToolbarSnapshot(
|
|||||||
const gugunOk = buildGugunOkForToolbar(searchContext);
|
const gugunOk = buildGugunOkForToolbar(searchContext);
|
||||||
const enterable = computeTabEnterable(statusInfo, periodEnterable);
|
const enterable = computeTabEnterable(statusInfo, periodEnterable);
|
||||||
const isSubmitted = statusInfo?.laeSbmsnSttsCd === "2";
|
const isSubmitted = statusInfo?.laeSbmsnSttsCd === "2";
|
||||||
const showSaveInToolbar = (enterable || isAdminInfo) && periodEnterable && gugunOk;
|
const showSaveInToolbar = (enterable || isAdminInfo) && gugunOk;
|
||||||
const showEnterableToolbarButtons = enterable && gugunOk;
|
const showEnterableToolbarButtons = enterable && gugunOk;
|
||||||
const showSubmittedInInputPeriodToolbar = isSubmitted && periodEnterable && gugunOk;
|
const showSubmittedInInputPeriodToolbar = isSubmitted && periodEnterable && gugunOk;
|
||||||
const showActionToolbarCard =
|
const showActionToolbarCard =
|
||||||
@@ -214,8 +197,9 @@ function buildWaterReuseSearchParam(
|
|||||||
): WaterReuseRequestParams {
|
): WaterReuseRequestParams {
|
||||||
return {
|
return {
|
||||||
statsYr: values.year,
|
statsYr: values.year,
|
||||||
|
sewerBzmnCd: values.bsnmCd,
|
||||||
ctpvNm: values.sido,
|
ctpvNm: values.sido,
|
||||||
...toInputSearchRegion(sidoListRef.current, values),
|
sggNm: values.gugun === "ALL" ? "" : values.gugun,
|
||||||
...(overrides?.mode ? { mode: overrides.mode } : {}),
|
...(overrides?.mode ? { mode: overrides.mode } : {}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -255,6 +239,13 @@ function buildSggNmColumn(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function nullableTrimmedString(
|
||||||
|
value: string | number | null | undefined,
|
||||||
|
): string | null {
|
||||||
|
const s = String(value ?? "").trim();
|
||||||
|
return s === "" ? null : s;
|
||||||
|
}
|
||||||
|
|
||||||
function toGridNumber(value: string | number | null | undefined): number {
|
function toGridNumber(value: string | number | null | undefined): number {
|
||||||
const n = Number(value);
|
const n = Number(value);
|
||||||
return Number.isFinite(n) ? n : 0;
|
return Number.isFinite(n) ? n : 0;
|
||||||
@@ -263,9 +254,9 @@ function toGridNumber(value: string | number | null | undefined): number {
|
|||||||
function resolveArticleAdmdst(
|
function resolveArticleAdmdst(
|
||||||
row: Record<string, string | number>,
|
row: Record<string, string | number>,
|
||||||
sggOptions: Sgg[],
|
sggOptions: Sgg[],
|
||||||
): { admdstCd: string | null; admdstNm: string | null } {
|
): { admdstCd: string; admdstNm: string } {
|
||||||
const existingCd = nullableTrimmedString(row.admdstCd);
|
const existingCd = String(row.admdstCd ?? "").trim();
|
||||||
const existingNm = nullableTrimmedString(row.admdstNm);
|
const existingNm = String(row.admdstNm ?? "").trim();
|
||||||
if (existingCd && existingNm) {
|
if (existingCd && existingNm) {
|
||||||
return { admdstCd: existingCd, admdstNm: existingNm };
|
return { admdstCd: existingCd, admdstNm: existingNm };
|
||||||
}
|
}
|
||||||
@@ -274,10 +265,7 @@ function resolveArticleAdmdst(
|
|||||||
if (matched) {
|
if (matched) {
|
||||||
return { admdstCd: matched.bsnmCd, admdstNm: matched.gugun };
|
return { admdstCd: matched.bsnmCd, admdstNm: matched.gugun };
|
||||||
}
|
}
|
||||||
return {
|
return { admdstCd: existingCd, admdstNm: existingNm || sggNm };
|
||||||
admdstCd: existingCd,
|
|
||||||
admdstNm: existingNm ?? nullableTrimmedString(sggNm),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getArticleRowSnField(tabKey: string): "fcltSn" | "bplcSn" | null {
|
function getArticleRowSnField(tabKey: string): "fcltSn" | "bplcSn" | null {
|
||||||
@@ -313,11 +301,11 @@ function buildRecycledWaterStatusSaveItem(
|
|||||||
return {
|
return {
|
||||||
admdstCd,
|
admdstCd,
|
||||||
admdstNm,
|
admdstNm,
|
||||||
fcltSn: nullableTrimmedString(row.fcltSn),
|
fcltSn: String(row.fcltSn ?? "").trim(),
|
||||||
fcltNm: nullableTrimmedString(row.fcltNm),
|
fcltNm: String(row.fcltNm ?? "").trim(),
|
||||||
bldgSeCn: nullableTrimmedString(row.bldgSeCn),
|
bldgSeCn: String(row.bldgSeCn ?? "").trim(),
|
||||||
fcltPstnCn: nullableTrimmedString(row.fcltPstnCn),
|
fcltPstnCn: String(row.fcltPstnCn ?? "").trim(),
|
||||||
lglTrgtYn: nullableTrimmedString(row.lglTrgtYn),
|
lglTrgtYn: String(row.lglTrgtYn ?? "").trim(),
|
||||||
cmptnStrtYmd: toCompactYmdOrNull(row.cmptnStrtYmd),
|
cmptnStrtYmd: toCompactYmdOrNull(row.cmptnStrtYmd),
|
||||||
oprtngStrtYmd: toCompactYmdOrNull(row.oprtngStrtYmd),
|
oprtngStrtYmd: toCompactYmdOrNull(row.oprtngStrtYmd),
|
||||||
archWholArea: toGridNumber(row.archWholArea),
|
archWholArea: toGridNumber(row.archWholArea),
|
||||||
@@ -325,7 +313,7 @@ function buildRecycledWaterStatusSaveItem(
|
|||||||
wtrUseQnt: toGridNumber(row.wtrUseQnt),
|
wtrUseQnt: toGridNumber(row.wtrUseQnt),
|
||||||
ruswtrUtztnQnt: toGridNumber(row.ruswtrUtztnQnt),
|
ruswtrUtztnQnt: toGridNumber(row.ruswtrUtztnQnt),
|
||||||
sbstCntUtztnQnt: toGridNumber(row.sbstCntUtztnQnt),
|
sbstCntUtztnQnt: toGridNumber(row.sbstCntUtztnQnt),
|
||||||
mnUsgCn: nullableTrimmedString(row.mnUsgCn),
|
mnUsgCn: String(row.mnUsgCn ?? "").trim(),
|
||||||
ruswtrOperAmt: toGridNumber(row.ruswtrOperAmt),
|
ruswtrOperAmt: toGridNumber(row.ruswtrOperAmt),
|
||||||
rmrk: nullableTrimmedString(row.rmrk),
|
rmrk: nullableTrimmedString(row.rmrk),
|
||||||
};
|
};
|
||||||
@@ -339,18 +327,18 @@ function buildRainFallUtilFactStatusSaveItem(
|
|||||||
return {
|
return {
|
||||||
admdstCd,
|
admdstCd,
|
||||||
admdstNm,
|
admdstNm,
|
||||||
fcltSn: nullableTrimmedString(row.fcltSn),
|
fcltSn: String(row.fcltSn ?? "").trim(),
|
||||||
fcltNm: nullableTrimmedString(row.fcltNm),
|
fcltNm: String(row.fcltNm ?? "").trim(),
|
||||||
bdstTypCn: nullableTrimmedString(row.bdstTypCn),
|
bdstTypCn: String(row.bdstTypCn ?? "").trim(),
|
||||||
fcltPstnCn: nullableTrimmedString(row.fcltPstnCn),
|
fcltPstnCn: String(row.fcltPstnCn ?? "").trim(),
|
||||||
lglTrgtYn: nullableTrimmedString(row.lglTrgtYn),
|
lglTrgtYn: String(row.lglTrgtYn ?? "").trim(),
|
||||||
cmptYmd: toCompactYmdOrNull(row.cmptYmd),
|
cmptYmd: toCompactYmdOrNull(row.cmptYmd),
|
||||||
instlAmt: toGridNumber(row.instlAmt),
|
instlAmt: toGridNumber(row.instlAmt),
|
||||||
rcptMynCn: nullableTrimmedString(row.rcptMynCn),
|
rcptMynCn: String(row.rcptMynCn ?? "").trim(),
|
||||||
filtrPrcsFcltYnExpln: nullableTrimmedString(row.filtrPrcsFcltYnExpln),
|
filtrPrcsFcltYnExpln: String(row.filtrPrcsFcltYnExpln ?? "").trim(),
|
||||||
impdCpct: toGridNumber(row.impdCpct),
|
impdCpct: toGridNumber(row.impdCpct),
|
||||||
anlUseQnt: toGridNumber(row.anlUseQnt),
|
anlUseQnt: toGridNumber(row.anlUseQnt),
|
||||||
exlnUtlzUsgExpln: nullableTrimmedString(row.exlnUtlzUsgExpln),
|
exlnUtlzUsgExpln: String(row.exlnUtlzUsgExpln ?? "").trim(),
|
||||||
anlOperAmt: toGridNumber(row.anlOperAmt),
|
anlOperAmt: toGridNumber(row.anlOperAmt),
|
||||||
rmrk: nullableTrimmedString(row.rmrk),
|
rmrk: nullableTrimmedString(row.rmrk),
|
||||||
};
|
};
|
||||||
@@ -364,10 +352,10 @@ function buildTreatWaterReuseDesignConstStatusSaveItem(
|
|||||||
return {
|
return {
|
||||||
admdstCd,
|
admdstCd,
|
||||||
admdstNm,
|
admdstNm,
|
||||||
bplcSn: nullableTrimmedString(row.bplcSn),
|
bplcSn: String(row.bplcSn ?? "").trim(),
|
||||||
bplcNm: nullableTrimmedString(row.bplcNm),
|
bplcNm: String(row.bplcNm ?? "").trim(),
|
||||||
rprsvNm: nullableTrimmedString(row.rprsvNm),
|
rprsvNm: String(row.rprsvNm ?? "").trim(),
|
||||||
bplcPstnCn: nullableTrimmedString(row.bplcPstnCn),
|
bplcPstnCn: String(row.bplcPstnCn ?? "").trim(),
|
||||||
coRegYmd: toCompactYmdOrNull(row.coRegYmd),
|
coRegYmd: toCompactYmdOrNull(row.coRegYmd),
|
||||||
rmrk: nullableTrimmedString(row.rmrk),
|
rmrk: nullableTrimmedString(row.rmrk),
|
||||||
};
|
};
|
||||||
@@ -381,10 +369,10 @@ function buildTreatWaterReuseBusinessApprStatusSaveItem(
|
|||||||
return {
|
return {
|
||||||
admdstCd,
|
admdstCd,
|
||||||
admdstNm,
|
admdstNm,
|
||||||
bplcSn: nullableTrimmedString(row.bplcSn),
|
bplcSn: String(row.bplcSn ?? "").trim(),
|
||||||
bplcNm: nullableTrimmedString(row.bplcNm),
|
bplcNm: String(row.bplcNm ?? "").trim(),
|
||||||
rprsvNm: nullableTrimmedString(row.rprsvNm),
|
rprsvNm: String(row.rprsvNm ?? "").trim(),
|
||||||
bplcPstnCn: nullableTrimmedString(row.bplcPstnCn),
|
bplcPstnCn: String(row.bplcPstnCn ?? "").trim(),
|
||||||
coRegYmd: toCompactYmdOrNull(row.coRegYmd),
|
coRegYmd: toCompactYmdOrNull(row.coRegYmd),
|
||||||
rmrk: nullableTrimmedString(row.rmrk),
|
rmrk: nullableTrimmedString(row.rmrk),
|
||||||
};
|
};
|
||||||
@@ -394,18 +382,18 @@ function buildPublicSewageTreatWaterReuseSaveItem(
|
|||||||
row: Record<string, string | number>,
|
row: Record<string, string | number>,
|
||||||
): PublicSewageTreatWaterReuseSaveItem {
|
): PublicSewageTreatWaterReuseSaveItem {
|
||||||
return {
|
return {
|
||||||
admdstCd: nullableTrimmedString(row.admdstCd),
|
admdstCd: String(row.admdstCd ?? "").trim(),
|
||||||
admdstNm: nullableTrimmedString(row.admdstNm ?? row.sggNm),
|
admdstNm: String(row.admdstNm ?? row.sggNm ?? "").trim(),
|
||||||
fcltSn: nullableTrimmedString(row.fcltSn),
|
fcltSn: String(row.fcltSn ?? "").trim(),
|
||||||
swtrmtFcltCd: nullableTrimmedString(row.swtrmtFcltCd),
|
swtrmtFcltCd: String(row.swtrmtFcltCd ?? "").trim(),
|
||||||
swtrmtFcltNm: nullableTrimmedString(row.swtrmtFcltNm),
|
swtrmtFcltNm: String(row.swtrmtFcltNm ?? "").trim(),
|
||||||
wholPrcsQnt: toGridNumber(row.wholPrcsQnt),
|
wholPrcsQnt: toGridNumber(row.wholPrcsQnt),
|
||||||
lglYn: nullableTrimmedString(row.lglYn),
|
lglYn: String(row.lglYn ?? "").trim(),
|
||||||
instlYn: nullableTrimmedString(row.instlYn),
|
instlYn: String(row.instlYn ?? "").trim(),
|
||||||
oprtngStrtYmd: toCompactYmdOrNull(row.oprtngStrtYmd),
|
oprtngStrtYmd: toCompactYmdOrNull(row.oprtngStrtYmd),
|
||||||
instlAprvYmd: toCompactYmdOrNull(row.instlAprvYmd),
|
instlAprvYmd: toCompactYmdOrNull(row.instlAprvYmd),
|
||||||
rprcsFcltCpct: toGridNumber(row.rprcsFcltCpct),
|
rprcsFcltCpct: toGridNumber(row.rprcsFcltCpct),
|
||||||
mtcnsNm: nullableTrimmedString(row.mtcnsNm),
|
mtcnsNm: String(row.mtcnsNm ?? "").trim(),
|
||||||
ruswtPplLen: toGridNumber(row.ruswtPplLen),
|
ruswtPplLen: toGridNumber(row.ruswtPplLen),
|
||||||
ruswtPumpLen: toGridNumber(row.ruswtPumpLen),
|
ruswtPumpLen: toGridNumber(row.ruswtPumpLen),
|
||||||
rmrk: nullableTrimmedString(row.rmrk),
|
rmrk: nullableTrimmedString(row.rmrk),
|
||||||
@@ -520,17 +508,15 @@ async function waitForImrJobCompleted(
|
|||||||
options?.onProgress?.(Math.max(0, Math.min(100, Number(res.job_prog) || 0)));
|
options?.onProgress?.(Math.max(0, Math.min(100, Number(res.job_prog) || 0)));
|
||||||
if (res.status === "COMPLETED" && Number(res.job_prog) === 100) return;
|
if (res.status === "COMPLETED" && Number(res.job_prog) === 100) return;
|
||||||
if (res.status === "FAILED" || res.status === "ERROR" || res.status === "CANCELLED") {
|
if (res.status === "FAILED" || res.status === "ERROR" || res.status === "CANCELLED") {
|
||||||
throw new Error(res.error_msg || `시계열 검증이 ${res.status} 상태로 종료되었습니다.`);
|
throw new Error(res.error_msg || `IMR 검증이 ${res.status} 상태로 종료되었습니다.`);
|
||||||
}
|
}
|
||||||
await sleep(pollIntervalMs);
|
await sleep(pollIntervalMs);
|
||||||
}
|
}
|
||||||
throw new Error("시계열 검증 완료 대기 시간이 초과되었습니다.");
|
throw new Error("IMR 검증 완료 대기 시간이 초과되었습니다.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 하수도 통계 관리 > 10. 물 재이용
|
// 하수도 통계 관리 > 10. 물 재이용
|
||||||
const WaterReuseInp = () => {
|
const WaterReuseInp = () => {
|
||||||
const { sidoList } = useSearchConditionSidoList({ isInput: true });
|
|
||||||
sidoListRef.current = sidoList;
|
|
||||||
const { setMessage: alert } = useAlertStore((state) => state);
|
const { setMessage: alert } = useAlertStore((state) => state);
|
||||||
const { confirm } = useConfirm();
|
const { confirm } = useConfirm();
|
||||||
const { isAdminInfo } = useAdminStore();
|
const { isAdminInfo } = useAdminStore();
|
||||||
@@ -559,15 +545,9 @@ const WaterReuseInp = () => {
|
|||||||
const [isVerificationFailedByTab, setIsVerificationFailedByTab] = useState<
|
const [isVerificationFailedByTab, setIsVerificationFailedByTab] = useState<
|
||||||
Map<string, boolean>
|
Map<string, boolean>
|
||||||
>(new Map());
|
>(new Map());
|
||||||
const [footerVerificationByTab, setFooterVerificationByTab] = useState<
|
const [toolbarSnapshotByTab, setToolbarSnapshotByTab] = useState<
|
||||||
Map<string, VerificationResultLikeMap | null>
|
|
||||||
>(new Map());
|
|
||||||
const [_toolbarSnapshotByTab, setToolbarSnapshotByTab] = useState<
|
|
||||||
Map<string, TabToolbarSnapshot>
|
Map<string, TabToolbarSnapshot>
|
||||||
>(new Map());
|
>(new Map());
|
||||||
const [searchContextByTab, setSearchContextByTab] = useState<Map<string, SearchFormValues>>(
|
|
||||||
() => new Map(),
|
|
||||||
);
|
|
||||||
const [columnGuidesByTab, setColumnGuidesByTab] = useState<
|
const [columnGuidesByTab, setColumnGuidesByTab] = useState<
|
||||||
Record<string, Record<string, string>>
|
Record<string, Record<string, string>>
|
||||||
>({});
|
>({});
|
||||||
@@ -589,29 +569,42 @@ const WaterReuseInp = () => {
|
|||||||
const loadedTabKeysRef = useRef<Set<string>>(new Set());
|
const loadedTabKeysRef = useRef<Set<string>>(new Set());
|
||||||
activeTabRef.current = activeTab;
|
activeTabRef.current = activeTab;
|
||||||
|
|
||||||
const activeTabId = useTabStore((s) => s.activeTabId);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeTabId !== STATISTICS_INPUT_URL_PATH.WATER_REUSE) return;
|
|
||||||
const tabKey = activeTab;
|
|
||||||
if (!tabKey) return;
|
|
||||||
if (Object.prototype.hasOwnProperty.call(columnGuidesByTab, tabKey)) return;
|
|
||||||
const statsCd = WATER_REUSE_COLUMN_GUIDE_STATS_CD_BY_TAB_KEY[tabKey] ?? tabKey;
|
|
||||||
|
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
void (async () => {
|
void (async () => {
|
||||||
const next = await fetchColumnGuidesRecord(statsCd);
|
const entries = await Promise.all(
|
||||||
|
WATER_REUSE_COLUMN_GUIDE_STATS_CDS.map(async (statsCd) => {
|
||||||
|
try {
|
||||||
|
const res = await statisticsApi.getColumnGuides(statsCd);
|
||||||
|
if (res.status !== "success" || !Array.isArray(res.data)) {
|
||||||
|
return [statsCd, {}] as const;
|
||||||
|
}
|
||||||
|
const next: Record<string, string> = {};
|
||||||
|
for (const item of res.data) {
|
||||||
|
const key = item.engColNm?.trim();
|
||||||
|
const guide = item.columnGuide?.trim();
|
||||||
|
if (key && guide) next[key] = guide;
|
||||||
|
}
|
||||||
|
return [statsCd, next] as const;
|
||||||
|
} catch {
|
||||||
|
return [statsCd, {}] as const;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
if (cancelled) return;
|
if (cancelled) return;
|
||||||
setColumnGuidesByTab((prev) =>
|
const guidesByStatsCd = Object.fromEntries(entries);
|
||||||
Object.prototype.hasOwnProperty.call(prev, tabKey)
|
setColumnGuidesByTab(
|
||||||
? prev
|
Object.fromEntries(
|
||||||
: { ...prev, [tabKey]: next },
|
Object.entries(WATER_REUSE_COLUMN_GUIDE_STATS_CD_BY_TAB_KEY).map(
|
||||||
|
([tabKey, statsCd]) => [tabKey, guidesByStatsCd[statsCd] ?? {}],
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
})();
|
})();
|
||||||
return () => {
|
return () => {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
};
|
};
|
||||||
}, [activeTabId, activeTab, columnGuidesByTab]);
|
}, []);
|
||||||
|
|
||||||
const loadSggOptions = useCallback(async (sido: string): Promise<Sgg[]> => {
|
const loadSggOptions = useCallback(async (sido: string): Promise<Sgg[]> => {
|
||||||
if (!sido || sido === "ALL") {
|
if (!sido || sido === "ALL") {
|
||||||
@@ -668,13 +661,6 @@ const WaterReuseInp = () => {
|
|||||||
);
|
);
|
||||||
return next;
|
return next;
|
||||||
});
|
});
|
||||||
if (searchContext) {
|
|
||||||
setSearchContextByTab((prev) => {
|
|
||||||
const next = new Map(prev);
|
|
||||||
next.set(tabKey, searchContext);
|
|
||||||
return next;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const applyRowMap = (
|
const applyRowMap = (
|
||||||
@@ -704,8 +690,6 @@ const WaterReuseInp = () => {
|
|||||||
): Promise<boolean> => {
|
): Promise<boolean> => {
|
||||||
const requestParam = overrides?.mode ? { ...param, mode: overrides.mode } : param;
|
const requestParam = overrides?.mode ? { ...param, mode: overrides.mode } : param;
|
||||||
const fromPreYear = overrides?.mode === "PRE";
|
const fromPreYear = overrides?.mode === "PRE";
|
||||||
const filterFetched = <T,>(list: T[] | undefined) =>
|
|
||||||
filterBySelectedAdmdstCd(list, sidoListRef.current, searchContext);
|
|
||||||
|
|
||||||
const applyNotApplicableForLoadedTab = (
|
const applyNotApplicableForLoadedTab = (
|
||||||
gridRows: readonly Record<string, string | number>[],
|
gridRows: readonly Record<string, string | number>[],
|
||||||
@@ -737,7 +721,7 @@ const WaterReuseInp = () => {
|
|||||||
}
|
}
|
||||||
const { commonInfo, statusInfo, publicSewageTreatWaterReuseList } = response.data;
|
const { commonInfo, statusInfo, publicSewageTreatWaterReuseList } = response.data;
|
||||||
const gridRows = mapPublicSewageTreatWaterReuseListToGridRows(
|
const gridRows = mapPublicSewageTreatWaterReuseListToGridRows(
|
||||||
filterFetched(publicSewageTreatWaterReuseList) as PublicSewageTreatWaterReuseItem[],
|
(publicSewageTreatWaterReuseList ?? []) as PublicSewageTreatWaterReuseItem[],
|
||||||
commonInfo.ctpvNm,
|
commonInfo.ctpvNm,
|
||||||
);
|
);
|
||||||
applyRowMap(mergeIntoExistingMap, (m) => {
|
applyRowMap(mergeIntoExistingMap, (m) => {
|
||||||
@@ -748,9 +732,6 @@ const WaterReuseInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
||||||
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
||||||
applyNotApplicableForLoadedTab(gridRows);
|
applyNotApplicableForLoadedTab(gridRows);
|
||||||
@@ -768,7 +749,7 @@ const WaterReuseInp = () => {
|
|||||||
}
|
}
|
||||||
const { commonInfo, statusInfo, recycledWaterList } = response.data;
|
const { commonInfo, statusInfo, recycledWaterList } = response.data;
|
||||||
const gridRows = mapRecycledWaterStatusListToGridRows(
|
const gridRows = mapRecycledWaterStatusListToGridRows(
|
||||||
filterFetched(recycledWaterList) as RecycledWaterStatusItem[],
|
(recycledWaterList ?? []) as RecycledWaterStatusItem[],
|
||||||
commonInfo.ctpvNm,
|
commonInfo.ctpvNm,
|
||||||
);
|
);
|
||||||
applyRowMap(mergeIntoExistingMap, (m) => {
|
applyRowMap(mergeIntoExistingMap, (m) => {
|
||||||
@@ -779,9 +760,6 @@ const WaterReuseInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
||||||
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
||||||
applyNotApplicableForLoadedTab(gridRows);
|
applyNotApplicableForLoadedTab(gridRows);
|
||||||
@@ -799,7 +777,7 @@ const WaterReuseInp = () => {
|
|||||||
}
|
}
|
||||||
const { commonInfo, statusInfo, rainFallUtilFactStatusList } = response.data;
|
const { commonInfo, statusInfo, rainFallUtilFactStatusList } = response.data;
|
||||||
const gridRows = mapRainFallUtilFactStatusListToGridRows(
|
const gridRows = mapRainFallUtilFactStatusListToGridRows(
|
||||||
filterFetched(rainFallUtilFactStatusList) as RainFallUtilFactStatusItem[],
|
(rainFallUtilFactStatusList ?? []) as RainFallUtilFactStatusItem[],
|
||||||
commonInfo.ctpvNm,
|
commonInfo.ctpvNm,
|
||||||
);
|
);
|
||||||
applyRowMap(mergeIntoExistingMap, (m) => {
|
applyRowMap(mergeIntoExistingMap, (m) => {
|
||||||
@@ -810,9 +788,6 @@ const WaterReuseInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
||||||
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
||||||
applyNotApplicableForLoadedTab(gridRows);
|
applyNotApplicableForLoadedTab(gridRows);
|
||||||
@@ -831,7 +806,8 @@ const WaterReuseInp = () => {
|
|||||||
}
|
}
|
||||||
const { commonInfo, statusInfo, treatWaterReuseDesignConstStatusList } = response.data;
|
const { commonInfo, statusInfo, treatWaterReuseDesignConstStatusList } = response.data;
|
||||||
const gridRows = mapTreatWaterReuseStatusListToGridRows(
|
const gridRows = mapTreatWaterReuseStatusListToGridRows(
|
||||||
filterFetched(treatWaterReuseDesignConstStatusList) as TreatWaterReuseDesignConstStatusItem[],
|
(treatWaterReuseDesignConstStatusList ??
|
||||||
|
[]) as TreatWaterReuseDesignConstStatusItem[],
|
||||||
commonInfo.ctpvNm,
|
commonInfo.ctpvNm,
|
||||||
);
|
);
|
||||||
applyRowMap(mergeIntoExistingMap, (m) => {
|
applyRowMap(mergeIntoExistingMap, (m) => {
|
||||||
@@ -842,9 +818,6 @@ const WaterReuseInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
||||||
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
||||||
applyNotApplicableForLoadedTab(gridRows);
|
applyNotApplicableForLoadedTab(gridRows);
|
||||||
@@ -864,7 +837,8 @@ const WaterReuseInp = () => {
|
|||||||
const { commonInfo, statusInfo, treatWaterReuseBusinessApprStatusList } =
|
const { commonInfo, statusInfo, treatWaterReuseBusinessApprStatusList } =
|
||||||
response.data;
|
response.data;
|
||||||
const gridRows = mapTreatWaterReuseStatusListToGridRows(
|
const gridRows = mapTreatWaterReuseStatusListToGridRows(
|
||||||
filterFetched(treatWaterReuseBusinessApprStatusList) as TreatWaterReuseBusinessApprStatusItem[],
|
(treatWaterReuseBusinessApprStatusList ??
|
||||||
|
[]) as TreatWaterReuseBusinessApprStatusItem[],
|
||||||
commonInfo.ctpvNm,
|
commonInfo.ctpvNm,
|
||||||
);
|
);
|
||||||
applyRowMap(mergeIntoExistingMap, (m) => {
|
applyRowMap(mergeIntoExistingMap, (m) => {
|
||||||
@@ -875,9 +849,6 @@ const WaterReuseInp = () => {
|
|||||||
setIsVerificationFailedByTab((prev) =>
|
setIsVerificationFailedByTab((prev) =>
|
||||||
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
patchVerificationFailedByTab(prev, tabKey, commonInfo),
|
||||||
);
|
);
|
||||||
setFooterVerificationByTab((prev) =>
|
|
||||||
patchFooterVerificationByTab(prev, tabKey, commonInfo),
|
|
||||||
);
|
|
||||||
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
if (updateLastSearchedValues) setLastSearchedValues(searchContext);
|
||||||
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
||||||
applyNotApplicableForLoadedTab(gridRows);
|
applyNotApplicableForLoadedTab(gridRows);
|
||||||
@@ -935,9 +906,7 @@ const WaterReuseInp = () => {
|
|||||||
setTabStatusInfoMap(new Map());
|
setTabStatusInfoMap(new Map());
|
||||||
setTabStatsCdMap(new Map());
|
setTabStatsCdMap(new Map());
|
||||||
setIsVerificationFailedByTab(new Map());
|
setIsVerificationFailedByTab(new Map());
|
||||||
setFooterVerificationByTab(new Map());
|
|
||||||
setToolbarSnapshotByTab(new Map());
|
setToolbarSnapshotByTab(new Map());
|
||||||
setSearchContextByTab(new Map());
|
|
||||||
setActiveTab(firstTabKey);
|
setActiveTab(firstTabKey);
|
||||||
activeTabRef.current = firstTabKey;
|
activeTabRef.current = firstTabKey;
|
||||||
setLastSearchedValues(null);
|
setLastSearchedValues(null);
|
||||||
@@ -984,9 +953,7 @@ const WaterReuseInp = () => {
|
|||||||
setTabStatusInfoMap(new Map());
|
setTabStatusInfoMap(new Map());
|
||||||
setTabStatsCdMap(new Map());
|
setTabStatsCdMap(new Map());
|
||||||
setIsVerificationFailedByTab(new Map());
|
setIsVerificationFailedByTab(new Map());
|
||||||
setFooterVerificationByTab(new Map());
|
|
||||||
setToolbarSnapshotByTab(new Map());
|
setToolbarSnapshotByTab(new Map());
|
||||||
setSearchContextByTab(new Map());
|
|
||||||
setDeleteListByTab(new Map());
|
setDeleteListByTab(new Map());
|
||||||
loadedTabKeysRef.current.clear();
|
loadedTabKeysRef.current.clear();
|
||||||
activeTabRef.current = firstTabKey;
|
activeTabRef.current = firstTabKey;
|
||||||
@@ -1109,9 +1076,9 @@ const WaterReuseInp = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const noApplicable = buildNoApplicableForRequest(searchContextByTab.get(tabKey) ?? lastSearchedValues, isNotApplicableByTab.get(tabKey) ?? false, getTabGridRows(tabKey).length === 0);
|
const noApplicable = isNotApplicableByTab.get(tabKey) ?? false;
|
||||||
const currentData = getTabGridRows(tabKey);
|
const currentData = getTabGridRows(tabKey);
|
||||||
if (!noApplicable && currentData.length === 0 && buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)) {
|
if (!noApplicable && currentData.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1144,7 +1111,11 @@ const WaterReuseInp = () => {
|
|||||||
const submitRequestBase = {
|
const submitRequestBase = {
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
laePicNm: submitInfo.laePicNm,
|
laePicNm: submitInfo.laePicNm,
|
||||||
laePicTelNo: submitInfo.laePicTelNo,
|
laePicTelNo: submitInfo.laePicTelNo,
|
||||||
laeKbrdrDeptNm: submitInfo.laeKbrdrDeptNm,
|
laeKbrdrDeptNm: submitInfo.laeKbrdrDeptNm,
|
||||||
@@ -1164,8 +1135,12 @@ const WaterReuseInp = () => {
|
|||||||
WATER_REUSE_COLUMN_GUIDE_STATS_CD_BY_TAB_KEY[tabKey] ??
|
WATER_REUSE_COLUMN_GUIDE_STATS_CD_BY_TAB_KEY[tabKey] ??
|
||||||
tabKey;
|
tabKey;
|
||||||
const verificationQuery = {
|
const verificationQuery = {
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
statsCd: statsCdForTab,
|
statsCd: statsCdForTab,
|
||||||
};
|
};
|
||||||
@@ -1195,16 +1170,16 @@ const WaterReuseInp = () => {
|
|||||||
let response: {
|
let response: {
|
||||||
status: string;
|
status: string;
|
||||||
message?: string;
|
message?: string;
|
||||||
data?: { finalStatus: string; nvpassed: boolean; isHbPassed?: string };
|
data?: { finalStatus: string; nvpassed: boolean };
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isPublicSewageTab) {
|
if (isPublicSewageTab) {
|
||||||
const noApplicable = buildNoApplicableForRequest(searchContextByTab.get(tabKey) ?? lastSearchedValues, isNotApplicableByTab.get(tabKey) ?? false, getTabGridRows(tabKey).length === 0);
|
const noApplicable = isNotApplicableByTab.get(tabKey) ?? false;
|
||||||
const currentData = getTabGridRows(tabKey);
|
const currentData = getTabGridRows(tabKey);
|
||||||
const submitList = noApplicable
|
const submitList = noApplicable
|
||||||
? []
|
? []
|
||||||
: currentData.map(buildPublicSewageTreatWaterReuseSaveItem);
|
: currentData.map(buildPublicSewageTreatWaterReuseSaveItem);
|
||||||
if (!noApplicable && submitList.length === 0 && buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)) {
|
if (!noApplicable && submitList.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1216,7 +1191,7 @@ const WaterReuseInp = () => {
|
|||||||
submitList,
|
submitList,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const noApplicable = buildNoApplicableForRequest(searchContextByTab.get(tabKey) ?? lastSearchedValues, isNotApplicableByTab.get(tabKey) ?? false, getTabGridRows(tabKey).length === 0);
|
const noApplicable = isNotApplicableByTab.get(tabKey) ?? false;
|
||||||
const currentData = getTabGridRows(tabKey);
|
const currentData = getTabGridRows(tabKey);
|
||||||
|
|
||||||
const sido = lastSearchedValues.sido ?? "";
|
const sido = lastSearchedValues.sido ?? "";
|
||||||
@@ -1247,7 +1222,7 @@ const WaterReuseInp = () => {
|
|||||||
.filter((row) => isPersistedArticleRow(tabKey, row))
|
.filter((row) => isPersistedArticleRow(tabKey, row))
|
||||||
.map((row) => buildRecycledWaterStatusSaveItem(row, list));
|
.map((row) => buildRecycledWaterStatusSaveItem(row, list));
|
||||||
|
|
||||||
if (!noApplicable && submitList.length === 0 && buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)) {
|
if (!noApplicable && submitList.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1267,7 +1242,7 @@ const WaterReuseInp = () => {
|
|||||||
.filter((row) => isPersistedArticleRow(tabKey, row))
|
.filter((row) => isPersistedArticleRow(tabKey, row))
|
||||||
.map((row) => buildRainFallUtilFactStatusSaveItem(row, list));
|
.map((row) => buildRainFallUtilFactStatusSaveItem(row, list));
|
||||||
|
|
||||||
if (!noApplicable && submitList.length === 0 && buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)) {
|
if (!noApplicable && submitList.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1289,7 +1264,7 @@ const WaterReuseInp = () => {
|
|||||||
buildTreatWaterReuseDesignConstStatusSaveItem(row, list),
|
buildTreatWaterReuseDesignConstStatusSaveItem(row, list),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!noApplicable && submitList.length === 0 && buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)) {
|
if (!noApplicable && submitList.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1314,7 +1289,7 @@ const WaterReuseInp = () => {
|
|||||||
buildTreatWaterReuseBusinessApprStatusSaveItem(row, list),
|
buildTreatWaterReuseBusinessApprStatusSaveItem(row, list),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!noApplicable && submitList.length === 0 && buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)) {
|
if (!noApplicable && submitList.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1343,16 +1318,15 @@ const WaterReuseInp = () => {
|
|||||||
|
|
||||||
if (finalStatus === "5") {
|
if (finalStatus === "5") {
|
||||||
setGlobalProgress(50);
|
setGlobalProgress(50);
|
||||||
setGlobalProgressLabel("시계열 검증 진행 중...");
|
setGlobalProgressLabel("IMR 검증 진행 중...");
|
||||||
const imrParam = {
|
const imrParam = {
|
||||||
user_id: userInfo.userUnqId,
|
user_id: userInfo.userUnqId,
|
||||||
sewer_bzmn_cd: lastSearchedValues?.bsnmCd ?? "",
|
sewer_bzmn_cd: lastSearchedValues.bsnmCd ?? "",
|
||||||
stats_cd: statsCdForTab,
|
stats_cd: statsCdForTab,
|
||||||
stats_yr: lastSearchedValues.year ?? "",
|
stats_yr: lastSearchedValues.year ?? "",
|
||||||
lae_sbmsn_stts_cd:
|
lae_sbmsn_stts_cd:
|
||||||
activeTabStatus?.laeSbmsnSttsCd === "4" ? "4" : "2",
|
activeTabStatus?.laeSbmsnSttsCd === "4" ? "4" : "2",
|
||||||
gen_verify_stts_cd: nvpassed ? "1" : "2",
|
gen_verify_stts_cd: nvpassed ? "1" : "2",
|
||||||
hb_pass_yn: response.data?.isHbPassed,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -1422,7 +1396,11 @@ const WaterReuseInp = () => {
|
|||||||
const requestBase = {
|
const requestBase = {
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
...(isAdminInfo ? { superAdmin: "superAdmin" } : {}),
|
...(isAdminInfo ? { superAdmin: "superAdmin" } : {}),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1440,12 +1418,12 @@ const WaterReuseInp = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (tabKey === PublicSewageTreatWaterReuseInpColumn.tabKey) {
|
if (tabKey === PublicSewageTreatWaterReuseInpColumn.tabKey) {
|
||||||
const noApplicable = buildNoApplicableForRequest(searchContextByTab.get(tabKey) ?? lastSearchedValues, isNotApplicableByTab.get(tabKey) ?? false, getTabGridRows(tabKey).length === 0);
|
const noApplicable = isNotApplicableByTab.get(tabKey) ?? false;
|
||||||
const currentData = getTabGridRows(tabKey);
|
const currentData = getTabGridRows(tabKey);
|
||||||
const saveList = noApplicable
|
const saveList = noApplicable
|
||||||
? []
|
? []
|
||||||
: currentData.map(buildPublicSewageTreatWaterReuseSaveItem);
|
: currentData.map(buildPublicSewageTreatWaterReuseSaveItem);
|
||||||
if (!noApplicable && saveList.length === 0 && buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)) {
|
if (!noApplicable && saveList.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1476,7 +1454,7 @@ const WaterReuseInp = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tabKey === RecycledWaterStatusInpColumn.tabKey) {
|
if (tabKey === RecycledWaterStatusInpColumn.tabKey) {
|
||||||
const noApplicable = buildNoApplicableForRequest(searchContextByTab.get(tabKey) ?? lastSearchedValues, isNotApplicableByTab.get(tabKey) ?? false, getTabGridRows(tabKey).length === 0);
|
const noApplicable = isNotApplicableByTab.get(tabKey) ?? false;
|
||||||
const currentData = getTabGridRows(tabKey);
|
const currentData = getTabGridRows(tabKey);
|
||||||
|
|
||||||
const sido = lastSearchedValues.sido ?? "";
|
const sido = lastSearchedValues.sido ?? "";
|
||||||
@@ -1499,7 +1477,7 @@ const WaterReuseInp = () => {
|
|||||||
.filter((row) => isPersistedArticleRow(tabKey, row))
|
.filter((row) => isPersistedArticleRow(tabKey, row))
|
||||||
.map((row) => buildRecycledWaterStatusSaveItem(row, list));
|
.map((row) => buildRecycledWaterStatusSaveItem(row, list));
|
||||||
|
|
||||||
if (!noApplicable && saveList.length === 0 && buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)) {
|
if (!noApplicable && saveList.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1536,7 +1514,7 @@ const WaterReuseInp = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tabKey === RainFallUtilFactStatusInpColumn.tabKey) {
|
if (tabKey === RainFallUtilFactStatusInpColumn.tabKey) {
|
||||||
const noApplicable = buildNoApplicableForRequest(searchContextByTab.get(tabKey) ?? lastSearchedValues, isNotApplicableByTab.get(tabKey) ?? false, getTabGridRows(tabKey).length === 0);
|
const noApplicable = isNotApplicableByTab.get(tabKey) ?? false;
|
||||||
const currentData = getTabGridRows(tabKey);
|
const currentData = getTabGridRows(tabKey);
|
||||||
|
|
||||||
const sido = lastSearchedValues.sido ?? "";
|
const sido = lastSearchedValues.sido ?? "";
|
||||||
@@ -1559,7 +1537,7 @@ const WaterReuseInp = () => {
|
|||||||
.filter((row) => isPersistedArticleRow(tabKey, row))
|
.filter((row) => isPersistedArticleRow(tabKey, row))
|
||||||
.map((row) => buildRainFallUtilFactStatusSaveItem(row, list));
|
.map((row) => buildRainFallUtilFactStatusSaveItem(row, list));
|
||||||
|
|
||||||
if (!noApplicable && saveList.length === 0 && buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)) {
|
if (!noApplicable && saveList.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1597,7 +1575,7 @@ const WaterReuseInp = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tabKey === TreatWaterReuseDesignConstStatusInpColumn.tabKey) {
|
if (tabKey === TreatWaterReuseDesignConstStatusInpColumn.tabKey) {
|
||||||
const noApplicable = buildNoApplicableForRequest(searchContextByTab.get(tabKey) ?? lastSearchedValues, isNotApplicableByTab.get(tabKey) ?? false, getTabGridRows(tabKey).length === 0);
|
const noApplicable = isNotApplicableByTab.get(tabKey) ?? false;
|
||||||
const currentData = getTabGridRows(tabKey);
|
const currentData = getTabGridRows(tabKey);
|
||||||
|
|
||||||
const sido = lastSearchedValues.sido ?? "";
|
const sido = lastSearchedValues.sido ?? "";
|
||||||
@@ -1622,7 +1600,7 @@ const WaterReuseInp = () => {
|
|||||||
buildTreatWaterReuseDesignConstStatusSaveItem(row, list),
|
buildTreatWaterReuseDesignConstStatusSaveItem(row, list),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!noApplicable && saveList.length === 0 && buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)) {
|
if (!noApplicable && saveList.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1662,7 +1640,7 @@ const WaterReuseInp = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tabKey === TreatWaterReuseBusinessApprStatusInpColumn.tabKey) {
|
if (tabKey === TreatWaterReuseBusinessApprStatusInpColumn.tabKey) {
|
||||||
const noApplicable = buildNoApplicableForRequest(searchContextByTab.get(tabKey) ?? lastSearchedValues, isNotApplicableByTab.get(tabKey) ?? false, getTabGridRows(tabKey).length === 0);
|
const noApplicable = isNotApplicableByTab.get(tabKey) ?? false;
|
||||||
const currentData = getTabGridRows(tabKey);
|
const currentData = getTabGridRows(tabKey);
|
||||||
|
|
||||||
const sido = lastSearchedValues.sido ?? "";
|
const sido = lastSearchedValues.sido ?? "";
|
||||||
@@ -1687,7 +1665,7 @@ const WaterReuseInp = () => {
|
|||||||
buildTreatWaterReuseBusinessApprStatusSaveItem(row, list),
|
buildTreatWaterReuseBusinessApprStatusSaveItem(row, list),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!noApplicable && saveList.length === 0 && buildSubmitOkForToolbar(searchContextByTab.get(tabKey) ?? lastSearchedValues)) {
|
if (!noApplicable && saveList.length === 0) {
|
||||||
alert("해당사항 없음을 체크해주세요.");
|
alert("해당사항 없음을 체크해주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1741,7 +1719,11 @@ const WaterReuseInp = () => {
|
|||||||
const request = {
|
const request = {
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
userId: userInfo.userUnqId,
|
userId: userInfo.userUnqId,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1899,8 +1881,12 @@ const WaterReuseInp = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const requestData: cancelSubmitRequest = {
|
const requestData: cancelSubmitRequest = {
|
||||||
...toInputSearchRegion(sidoListRef.current, lastSearchedValues),
|
sewerBzmnCd: lastSearchedValues.bsnmCd ?? "",
|
||||||
ctpvNm: lastSearchedValues.sido ?? "",
|
ctpvNm: lastSearchedValues.sido ?? "",
|
||||||
|
sggNm:
|
||||||
|
lastSearchedValues.gugun === "ALL"
|
||||||
|
? ""
|
||||||
|
: (lastSearchedValues.gugun ?? ""),
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
statsYr: lastSearchedValues.year ?? "",
|
||||||
mdfrId: userInfo.userUnqId,
|
mdfrId: userInfo.userUnqId,
|
||||||
statsCd: statsCdForTab,
|
statsCd: statsCdForTab,
|
||||||
@@ -1938,10 +1924,10 @@ const WaterReuseInp = () => {
|
|||||||
for (const tab of WaterReuseInpTabList) {
|
for (const tab of WaterReuseInpTabList) {
|
||||||
const tabKey = tab.tabKey;
|
const tabKey = tab.tabKey;
|
||||||
const canEdit =
|
const canEdit =
|
||||||
(computeTabEnterable(
|
computeTabEnterable(
|
||||||
tabStatusInfoMap.get(tabKey) ?? null,
|
tabStatusInfoMap.get(tabKey) ?? null,
|
||||||
inputPeriodEnterable,
|
inputPeriodEnterable,
|
||||||
) || isAdminInfo) && inputPeriodEnterable;
|
) || isAdminInfo;
|
||||||
const rawColumns = (tab.columns ?? []) as ColumnConfig[];
|
const rawColumns = (tab.columns ?? []) as ColumnConfig[];
|
||||||
const base = canEdit
|
const base = canEdit
|
||||||
? rawColumns
|
? rawColumns
|
||||||
@@ -1977,14 +1963,14 @@ const WaterReuseInp = () => {
|
|||||||
return map;
|
return map;
|
||||||
}, [tabStatusInfoMap, inputPeriodEnterable, isAdminInfo, columnGuidesByTab, sggOptions]);
|
}, [tabStatusInfoMap, inputPeriodEnterable, isAdminInfo, columnGuidesByTab, sggOptions]);
|
||||||
|
|
||||||
const searchContextForToolbar = searchContextByTab.get(activeTab) ?? lastSearchedValues;
|
|
||||||
const activeTabStatus = tabStatusInfoMap.get(activeTab) ?? null;
|
const activeTabStatus = tabStatusInfoMap.get(activeTab) ?? null;
|
||||||
const activeTabToolbar =
|
const activeTabToolbar =
|
||||||
|
toolbarSnapshotByTab.get(activeTab) ??
|
||||||
computeTabToolbarSnapshot(
|
computeTabToolbarSnapshot(
|
||||||
activeTabStatus,
|
activeTabStatus,
|
||||||
tabRowDataExists(rowDataMap, activeTab),
|
tabRowDataExists(rowDataMap, activeTab),
|
||||||
hasSearched,
|
hasSearched,
|
||||||
searchContextForToolbar,
|
lastSearchedValues,
|
||||||
inputPeriodEnterable,
|
inputPeriodEnterable,
|
||||||
isAdminInfo,
|
isAdminInfo,
|
||||||
);
|
);
|
||||||
@@ -1995,7 +1981,6 @@ const WaterReuseInp = () => {
|
|||||||
activeTabToolbar.showEnterableToolbarButtons && toolbarGroupAllowed;
|
activeTabToolbar.showEnterableToolbarButtons && toolbarGroupAllowed;
|
||||||
const showActionToolbarCard =
|
const showActionToolbarCard =
|
||||||
activeTabToolbar.showActionToolbarCard && toolbarGroupAllowed;
|
activeTabToolbar.showActionToolbarCard && toolbarGroupAllowed;
|
||||||
const submitOk = buildSubmitOkForToolbar(searchContextForToolbar);
|
|
||||||
const showSecondaryToolbarCard =
|
const showSecondaryToolbarCard =
|
||||||
hasSearched &&
|
hasSearched &&
|
||||||
toolbarGroupAllowed &&
|
toolbarGroupAllowed &&
|
||||||
@@ -2010,8 +1995,7 @@ const WaterReuseInp = () => {
|
|||||||
activeTab,
|
activeTab,
|
||||||
tabRowDataExists(rowDataMap, activeTab),
|
tabRowDataExists(rowDataMap, activeTab),
|
||||||
activeTabStatus,
|
activeTabStatus,
|
||||||
) &&
|
);
|
||||||
submitOk;
|
|
||||||
const setIsNotApplicableForActiveTab: Dispatch<SetStateAction<boolean>> = useCallback(
|
const setIsNotApplicableForActiveTab: Dispatch<SetStateAction<boolean>> = useCallback(
|
||||||
(next) => {
|
(next) => {
|
||||||
const tabKey = activeTabRef.current;
|
const tabKey = activeTabRef.current;
|
||||||
@@ -2030,8 +2014,9 @@ const WaterReuseInp = () => {
|
|||||||
const statsCd = tabStatsCdMap.get(activeTab);
|
const statsCd = tabStatsCdMap.get(activeTab);
|
||||||
if (!ctx?.year || !ctx?.sido || !ctx?.bsnmCd || !statsCd) return null;
|
if (!ctx?.year || !ctx?.sido || !ctx?.bsnmCd || !statsCd) return null;
|
||||||
return {
|
return {
|
||||||
...toInputSearchRegion(sidoListRef.current, ctx),
|
sewerBzmnCd: ctx.bsnmCd,
|
||||||
ctpvNm: ctx.sido,
|
ctpvNm: ctx.sido,
|
||||||
|
sggNm: ctx.gugun === "ALL" ? "" : (ctx.gugun ?? ""),
|
||||||
statsYr: ctx.year,
|
statsYr: ctx.year,
|
||||||
statsCd,
|
statsCd,
|
||||||
};
|
};
|
||||||
@@ -2068,10 +2053,10 @@ const WaterReuseInp = () => {
|
|||||||
.map((e) => {
|
.map((e) => {
|
||||||
const prefix =
|
const prefix =
|
||||||
e.vrfcCd === "IMR"
|
e.vrfcCd === "IMR"
|
||||||
? "시계열 검증 - "
|
? "IMR검증 - "
|
||||||
: e.vrfcCd === "NV"
|
: e.vrfcCd === "NV"
|
||||||
? "일반검증 - "
|
? "일반검증 - "
|
||||||
: "모집단 검증 - ";
|
: "HB검증 - ";
|
||||||
return `${prefix}${e.rsnExpln}(검증 기준값: ${e.compVlCn} / 현재 입력값: ${e.nowVlCn})`;
|
return `${prefix}${e.rsnExpln}(검증 기준값: ${e.compVlCn} / 현재 입력값: ${e.nowVlCn})`;
|
||||||
})
|
})
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
@@ -2094,7 +2079,6 @@ const WaterReuseInp = () => {
|
|||||||
<>
|
<>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<SearchForm
|
<SearchForm
|
||||||
isInput
|
|
||||||
key={searchFormRemountKey}
|
key={searchFormRemountKey}
|
||||||
defaultValues={verificationSearchDefaults ?? undefined}
|
defaultValues={verificationSearchDefaults ?? undefined}
|
||||||
onSubmit={handleSearch}
|
onSubmit={handleSearch}
|
||||||
@@ -2102,8 +2086,8 @@ const WaterReuseInp = () => {
|
|||||||
onValuesChange={setSearchValues}
|
onValuesChange={setSearchValues}
|
||||||
/>
|
/>
|
||||||
{showActionToolbarCard && (
|
{showActionToolbarCard && (
|
||||||
<div className="card !py-0">
|
<div className="card !py-0">
|
||||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||||
<VerificationResultButton
|
<VerificationResultButton
|
||||||
VerificationResultButtonFunc={openVerificationHistoryDialog}
|
VerificationResultButtonFunc={openVerificationHistoryDialog}
|
||||||
isVerificationFailed={
|
isVerificationFailed={
|
||||||
@@ -2115,19 +2099,19 @@ const WaterReuseInp = () => {
|
|||||||
<LastYearDataButton
|
<LastYearDataButton
|
||||||
getLastYearDataFunc={() => void getLastYearDataFunc()}
|
getLastYearDataFunc={() => void getLastYearDataFunc()}
|
||||||
/>
|
/>
|
||||||
{submitOk && <SubmitButton submitFunc={submitFunc} />}
|
<SubmitButton submitFunc={submitFunc} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{activeTabStatus?.laeSbmsnSttsCd === "2" && submitOk && (
|
{activeTabStatus?.laeSbmsnSttsCd === "2" && (
|
||||||
<CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />
|
<CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />
|
||||||
)}
|
)}
|
||||||
{showSaveInToolbar && <SaveButton saveFunc={saveFunc} />}
|
{showSaveInToolbar && <SaveButton saveFunc={saveFunc} />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{showSecondaryToolbarCard && (
|
{showSecondaryToolbarCard && (
|
||||||
<div className="card !py-0">
|
<div className="card !py-0">
|
||||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||||
{showNotApplicableForActiveTab && (
|
{showNotApplicableForActiveTab && (
|
||||||
<NotApplicableCheckButton
|
<NotApplicableCheckButton
|
||||||
isCheck={isNotApplicableForActiveTab}
|
isCheck={isNotApplicableForActiveTab}
|
||||||
@@ -2141,12 +2125,12 @@ const WaterReuseInp = () => {
|
|||||||
)}
|
)}
|
||||||
{isArticleEditTab && showEnterableToolbarButtons && (
|
{isArticleEditTab && showEnterableToolbarButtons && (
|
||||||
<>
|
<>
|
||||||
<AddArticleButton addArticleFunc={addArticleFunc} />
|
<AddArticleButton addArticleFunc={addArticleFunc} />
|
||||||
<DeleteArticleButton deleteArticleFunc={deleteArticleFunc} />
|
<DeleteArticleButton deleteArticleFunc={deleteArticleFunc} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
||||||
@@ -2173,11 +2157,11 @@ const WaterReuseInp = () => {
|
|||||||
const tabKey = info.tabKey;
|
const tabKey = info.tabKey;
|
||||||
const rowData = rowDataMap.get(tabKey) ?? [];
|
const rowData = rowDataMap.get(tabKey) ?? [];
|
||||||
const tabEnterableForGrid =
|
const tabEnterableForGrid =
|
||||||
(computeTabEnterable(
|
computeTabEnterable(
|
||||||
tabStatusInfoMap.get(tabKey) ?? null,
|
tabStatusInfoMap.get(tabKey) ?? null,
|
||||||
inputPeriodEnterable,
|
inputPeriodEnterable,
|
||||||
) || isAdminInfo) && inputPeriodEnterable;
|
) || isAdminInfo;
|
||||||
const gugunOk = buildGugunOkForToolbar(searchContextForToolbar);
|
const gugunOk = buildGugunOkForToolbar(lastSearchedValues);
|
||||||
const tabStatusInfo = tabStatusInfoMap.get(tabKey) ?? null;
|
const tabStatusInfo = tabStatusInfoMap.get(tabKey) ?? null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -2218,9 +2202,6 @@ const WaterReuseInp = () => {
|
|||||||
excelExportSearchContext={toExcelExportSearchContextFromSearchForm(lastSearchedValues ?? searchValues)}
|
excelExportSearchContext={toExcelExportSearchContextFromSearchForm(lastSearchedValues ?? searchValues)}
|
||||||
isExcelExport
|
isExcelExport
|
||||||
cellStyleCallback={verificationCellStyle}
|
cellStyleCallback={verificationCellStyle}
|
||||||
footerVerificationResult={
|
|
||||||
footerVerificationByTab.get(tabKey) ?? null
|
|
||||||
}
|
|
||||||
cellTooltipCallback={verificationCellTooltip}
|
cellTooltipCallback={verificationCellTooltip}
|
||||||
getGridDataRef={
|
getGridDataRef={
|
||||||
activeTab === tabKey ? getGridDataRef : undefined
|
activeTab === tabKey ? getGridDataRef : undefined
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import { Button } from "@common/components";
|
import { Button } from "@common/components";
|
||||||
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
|
import type { ColumnInfo } from "@/components/type/DataGrid.type";
|
||||||
|
import {
|
||||||
|
AdmdstRenewalReducedColumnConfig,
|
||||||
|
AdmdstRenewalAddedColumnConfig,
|
||||||
|
} from "@/components/util/column/management/AdmdstRenewalColumn";
|
||||||
|
|
||||||
|
import { UpperCodeSelectDialog } from "@/components/statistics/management/UpperCodeSelectDialog";
|
||||||
import type { useAdmdstRenewalTab } from "@/components/statistics/management/hooks/useAdmdstRenewalTab";
|
import type { useAdmdstRenewalTab } from "@/components/statistics/management/hooks/useAdmdstRenewalTab";
|
||||||
import { asGridRowData, asGridRowSetter, fromGridRow } from "@/components/statistics/management/lib/gridCast";
|
import { asGridRowData, asGridRowSetter, fromGridRow } from "@/components/statistics/management/lib/gridCast";
|
||||||
import type { AdmdstRenewalAddedItem } from "@/components/statistics/management/types/population-tab-types";
|
import type { AdmdstRenewalAddedItem } from "@/components/statistics/management/types/population-tab-types";
|
||||||
import { UpperCodeSelectDialog } from "@/components/statistics/management/UpperCodeSelectDialog";
|
|
||||||
import type { ColumnInfo } from "@/components/type/DataGrid.type";
|
|
||||||
import {
|
|
||||||
AdmdstRenewalAddedColumnConfig,
|
|
||||||
AdmdstRenewalReducedColumnConfig,
|
|
||||||
} from "@/components/util/column/management/AdmdstRenewalColumn";
|
|
||||||
|
|
||||||
const reducedColumnInfo: ColumnInfo = {
|
const reducedColumnInfo: ColumnInfo = {
|
||||||
columns: AdmdstRenewalReducedColumnConfig.columns ?? [],
|
columns: AdmdstRenewalReducedColumnConfig.columns ?? [],
|
||||||
|
|||||||
@@ -1,19 +1,17 @@
|
|||||||
import { useRef } from "react";
|
|
||||||
|
|
||||||
import type { RealGridReact } from "realgrid-react";
|
|
||||||
|
|
||||||
import type { DomesticPopulationItem } from "@/entities/statistics/model/ppltn/statistics-domestic-population-interface";
|
|
||||||
import { Button } from "@common/components";
|
import { Button } from "@common/components";
|
||||||
|
import type { RealGridReact } from "realgrid-react";
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
import type { usePopulationMappingTab } from "@/components/statistics/management/hooks/usePopulationMappingTab";
|
|
||||||
import { asGridRowData, asGridRowSetter, fromGridRow } from "@/components/statistics/management/lib/gridCast";
|
|
||||||
import { UpperCodeSelectDialog } from "@/components/statistics/management/UpperCodeSelectDialog";
|
|
||||||
import type { ColumnInfo, GridViewWithEditCommit } from "@/components/type/DataGrid.type";
|
import type { ColumnInfo, GridViewWithEditCommit } from "@/components/type/DataGrid.type";
|
||||||
import {
|
import {
|
||||||
DomesticPopulationLeftColumnConfig,
|
DomesticPopulationLeftColumnConfig,
|
||||||
DomesticPopulationRightColumnConfig,
|
DomesticPopulationRightColumnConfig,
|
||||||
} from "@/components/util/column/management/DomesticPopulationColumn";
|
} from "@/components/util/column/management/DomesticPopulationColumn";
|
||||||
|
import { useRef } from "react";
|
||||||
|
|
||||||
|
import { UpperCodeSelectDialog } from "@/components/statistics/management/UpperCodeSelectDialog";
|
||||||
|
import type { usePopulationMappingTab } from "@/components/statistics/management/hooks/usePopulationMappingTab";
|
||||||
|
import { asGridRowData, asGridRowSetter, fromGridRow } from "@/components/statistics/management/lib/gridCast";
|
||||||
|
import type { DomesticPopulationItem } from "@/entities/statistics/model/ppltn/statistics-domestic-population-interface";
|
||||||
|
|
||||||
|
|
||||||
const leftColumnInfo: ColumnInfo = {
|
const leftColumnInfo: ColumnInfo = {
|
||||||
@@ -98,7 +96,7 @@ const DomesticPopulationTab = ({ tab, statsYr, onFileButtonClick }: Props) => {
|
|||||||
enableSort={false}
|
enableSort={false}
|
||||||
getGridRef={rightGridRef} // ← 추가
|
getGridRef={rightGridRef} // ← 추가
|
||||||
onDataCellClick={({ row, fieldName }) => {
|
onDataCellClick={({ row, fieldName }) => {
|
||||||
if (fieldName === "sbstAdmdstCd") return;
|
if (fieldName === "mpinCd") return;
|
||||||
if (fieldName === "admdstCd") {
|
if (fieldName === "admdstCd") {
|
||||||
const gridView = rightGridRef.current?.gridView as
|
const gridView = rightGridRef.current?.gridView as
|
||||||
| GridViewWithEditCommit
|
| GridViewWithEditCommit
|
||||||
@@ -108,7 +106,7 @@ const DomesticPopulationTab = ({ tab, statsYr, onFileButtonClick }: Props) => {
|
|||||||
tab.setRightRowData((prev) =>
|
tab.setRightRowData((prev) =>
|
||||||
prev.map((r) =>
|
prev.map((r) =>
|
||||||
r.admdstCd === row.admdstCd
|
r.admdstCd === row.admdstCd
|
||||||
? { ...r, sbstAdmdstCd: String(row.admdstCd ?? "") }
|
? { ...r, mpinCd: String(row.admdstCd ?? "") }
|
||||||
: r,
|
: r,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -117,7 +115,7 @@ const DomesticPopulationTab = ({ tab, statsYr, onFileButtonClick }: Props) => {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onCellDblClick={({ row, fieldName }) => {
|
onCellDblClick={({ row, fieldName }) => {
|
||||||
if (fieldName !== "sbstAdmdstCd") return;
|
if (fieldName !== "mpinCd") return;
|
||||||
void tab.handleRightRowClick(fromGridRow<DomesticPopulationItem>(row), statsYr);
|
void tab.handleRightRowClick(fromGridRow<DomesticPopulationItem>(row), statsYr);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,20 +1,18 @@
|
|||||||
import { useRef } from "react";
|
|
||||||
|
|
||||||
import type { RealGridReact } from "realgrid-react";
|
|
||||||
|
|
||||||
import { Button } from "@common/components";
|
import { Button } from "@common/components";
|
||||||
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
import type { usePopulationMappingTab } from "@/components/statistics/management/hooks/usePopulationMappingTab";
|
|
||||||
import { asGridRowData, asGridRowSetter, fromGridRow } from "@/components/statistics/management/lib/gridCast";
|
|
||||||
import type { ForeignPopulationItem } from "@/components/statistics/management/types/population-tab-types";
|
|
||||||
import { UpperCodeSelectDialog } from "@/components/statistics/management/UpperCodeSelectDialog";
|
|
||||||
import type { ColumnInfo, GridViewWithEditCommit } from "@/components/type/DataGrid.type";
|
import type { ColumnInfo, GridViewWithEditCommit } from "@/components/type/DataGrid.type";
|
||||||
|
import { useRef } from "react";
|
||||||
|
import type { RealGridReact } from "realgrid-react";
|
||||||
import {
|
import {
|
||||||
ForeignPopulationLeftColumnConfig,
|
ForeignPopulationLeftColumnConfig,
|
||||||
ForeignPopulationRightColumnConfig,
|
ForeignPopulationRightColumnConfig,
|
||||||
} from "@/components/util/column/management/ForeignPopulationColumn";
|
} from "@/components/util/column/management/ForeignPopulationColumn";
|
||||||
|
|
||||||
|
import { UpperCodeSelectDialog } from "@/components/statistics/management/UpperCodeSelectDialog";
|
||||||
|
import type { usePopulationMappingTab } from "@/components/statistics/management/hooks/usePopulationMappingTab";
|
||||||
|
import { asGridRowData, asGridRowSetter, fromGridRow } from "@/components/statistics/management/lib/gridCast";
|
||||||
|
import type { ForeignPopulationItem } from "@/components/statistics/management/types/population-tab-types";
|
||||||
|
|
||||||
const leftColumnInfo: ColumnInfo = {
|
const leftColumnInfo: ColumnInfo = {
|
||||||
columns: ForeignPopulationLeftColumnConfig.columns ?? [],
|
columns: ForeignPopulationLeftColumnConfig.columns ?? [],
|
||||||
columnLayout: ForeignPopulationLeftColumnConfig.columnLayout ?? [],
|
columnLayout: ForeignPopulationLeftColumnConfig.columnLayout ?? [],
|
||||||
@@ -97,7 +95,7 @@ const ForeignPopulationTab = ({ tab, statsYr, onFileButtonClick }: Props) => {
|
|||||||
enableSort={false}
|
enableSort={false}
|
||||||
getGridRef={rightGridRef}
|
getGridRef={rightGridRef}
|
||||||
onDataCellClick={({ row, fieldName }) => {
|
onDataCellClick={({ row, fieldName }) => {
|
||||||
if (fieldName === "sbstAdmdstCd") return;
|
if (fieldName === "mpinCd") return;
|
||||||
if (fieldName === "admdstCd") {
|
if (fieldName === "admdstCd") {
|
||||||
const gridView = rightGridRef.current?.gridView as
|
const gridView = rightGridRef.current?.gridView as
|
||||||
| GridViewWithEditCommit
|
| GridViewWithEditCommit
|
||||||
@@ -107,7 +105,7 @@ const ForeignPopulationTab = ({ tab, statsYr, onFileButtonClick }: Props) => {
|
|||||||
tab.setRightRowData((prev) =>
|
tab.setRightRowData((prev) =>
|
||||||
prev.map((r) =>
|
prev.map((r) =>
|
||||||
r.admdstCd === row.admdstCd
|
r.admdstCd === row.admdstCd
|
||||||
? { ...r, sbstAdmdstCd: String(row.admdstCd ?? "") }
|
? { ...r, mpinCd: String(row.admdstCd ?? "") }
|
||||||
: r,
|
: r,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -116,7 +114,7 @@ const ForeignPopulationTab = ({ tab, statsYr, onFileButtonClick }: Props) => {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onCellDblClick={({ row, fieldName }) => {
|
onCellDblClick={({ row, fieldName }) => {
|
||||||
if (fieldName !== "sbstAdmdstCd") return;
|
if (fieldName !== "mpinCd") return;
|
||||||
void tab.handleRightRowClick(fromGridRow<ForeignPopulationItem>(row), statsYr);
|
void tab.handleRightRowClick(fromGridRow<ForeignPopulationItem>(row), statsYr);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -130,9 +130,9 @@ const getSidoListFetcher = async (): Promise<ApiResponse<SearchCondition>> => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getSggListFetcher = async (
|
const getSggListFetcher = async (
|
||||||
key: [string, string, "Y" | "N"],
|
key: [string, string],
|
||||||
): Promise<ApiResponse<Sgg[]>> => {
|
): Promise<ApiResponse<Sgg[]>> => {
|
||||||
return statisticsApi.getSggList(key[1], { gugunSkipYn: key[2] });
|
return statisticsApi.getSggList(key[1]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const LogHistory = () => {
|
const LogHistory = () => {
|
||||||
@@ -214,14 +214,8 @@ const LogHistory = () => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const selectedSido = sidoList?.data?.sidoList?.find(
|
const sggKey: [string, string] | null =
|
||||||
(item) => item.sido === sido,
|
sido && sido !== "ALL" ? ["log-history-sgg-list", sido] : null;
|
||||||
);
|
|
||||||
const gugunSkipYn = selectedSido?.gugunSkipYn ?? "Y";
|
|
||||||
const sggKey: [string, string, "Y" | "N"] | null =
|
|
||||||
sido && sido !== "ALL" && sidoList?.data
|
|
||||||
? ["log-history-sgg-list", sido, gugunSkipYn]
|
|
||||||
: null;
|
|
||||||
const { data: sggList } = useSWR<ApiResponse<Sgg[]>>(
|
const { data: sggList } = useSWR<ApiResponse<Sgg[]>>(
|
||||||
sggKey,
|
sggKey,
|
||||||
getSggListFetcher,
|
getSggListFetcher,
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
|
|
||||||
import { GridFitStyle } from "realgrid";
|
import { GridFitStyle } from "realgrid";
|
||||||
|
|
||||||
import { useAlertStore } from "@/shared/lib";
|
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
|
||||||
import { UserApi } from "@/entities/user";
|
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Dialog,
|
Dialog,
|
||||||
@@ -18,8 +14,6 @@ import {
|
|||||||
LoadingWithAnimation,
|
LoadingWithAnimation,
|
||||||
} from "@common/components";
|
} from "@common/components";
|
||||||
|
|
||||||
import { LogHistoryDetailsNestedDialog } from "./LogHistoryDetailsNestedDialog";
|
|
||||||
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
import type {
|
import type {
|
||||||
ColumnInfo,
|
ColumnInfo,
|
||||||
@@ -31,10 +25,15 @@ import {
|
|||||||
emptyLogHistoryDetailColumnInfo,
|
emptyLogHistoryDetailColumnInfo,
|
||||||
LOG_DETAIL_DETAILS_FIELD,
|
LOG_DETAIL_DETAILS_FIELD,
|
||||||
LOG_DETAIL_DETAILS_RAW_FIELD,
|
LOG_DETAIL_DETAILS_RAW_FIELD,
|
||||||
type LogDetailVerificationItem,
|
|
||||||
normalizeLogDetailList,
|
normalizeLogDetailList,
|
||||||
|
type LogDetailVerificationItem,
|
||||||
prepareLogDetailRowsForGrid,
|
prepareLogDetailRowsForGrid,
|
||||||
} from "@/components/util/column/management/LogHistoryDetailColumn";
|
} from "@/components/util/column/management/LogHistoryDetailColumn";
|
||||||
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
|
import { UserApi } from "@/entities/user";
|
||||||
|
import { useAlertStore } from "@/shared/lib";
|
||||||
|
|
||||||
|
import { LogHistoryDetailsNestedDialog } from "./LogHistoryDetailsNestedDialog";
|
||||||
|
|
||||||
export interface LogHistoryDetailDialogProps {
|
export interface LogHistoryDetailDialogProps {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import { GridFitStyle } from "realgrid";
|
|||||||
import { useAlertStore, useUserStore } from "@/shared/lib";
|
import { useAlertStore, useUserStore } from "@/shared/lib";
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
import type {
|
import type {
|
||||||
unSubmitDataRequest,
|
|
||||||
UnSubmitDataStatusItem,
|
UnSubmitDataStatusItem,
|
||||||
|
unSubmitDataRequest,
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
} from "@/entities/statistics/model/statistics-interface";
|
||||||
import { LoadingWithAnimation } from "@common/components";
|
import { LoadingWithAnimation } from "@common/components";
|
||||||
|
|
||||||
@@ -279,6 +279,7 @@ const NotEnteredStatus = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const params = buildUnSubmitDataRequest(values, userInfo);
|
const params = buildUnSubmitDataRequest(values, userInfo);
|
||||||
|
console.log(params);
|
||||||
if (!params.dtlInstCd) {
|
if (!params.dtlInstCd) {
|
||||||
alert("기관 정보를 확인할 수 없습니다.");
|
alert("기관 정보를 확인할 수 없습니다.");
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
import { Chart } from "react-chartjs-2";
|
import { Chart } from "react-chartjs-2";
|
||||||
|
|
||||||
import type { ChartOptions } from "chart.js";
|
|
||||||
import {
|
import {
|
||||||
|
Chart as ChartJS,
|
||||||
|
CategoryScale,
|
||||||
|
LinearScale,
|
||||||
BarController,
|
BarController,
|
||||||
BarElement,
|
BarElement,
|
||||||
CategoryScale,
|
|
||||||
Chart as ChartJS,
|
|
||||||
Legend,
|
|
||||||
LinearScale,
|
|
||||||
LineController,
|
LineController,
|
||||||
LineElement,
|
LineElement,
|
||||||
PointElement,
|
PointElement,
|
||||||
Title,
|
Title,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
|
Legend,
|
||||||
} from "chart.js";
|
} from "chart.js";
|
||||||
|
import type { ChartOptions } from "chart.js";
|
||||||
|
|
||||||
ChartJS.register(
|
ChartJS.register(
|
||||||
CategoryScale,
|
CategoryScale,
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
import type { usePopulationStatusTab } from "@/components/statistics/management/hooks/usePopulationStatusTab";
|
|
||||||
import { asGridRowData, asGridRowSetter } from "@/components/statistics/management/lib/gridCast";
|
|
||||||
import type { ColumnInfo } from "@/components/type/DataGrid.type";
|
import type { ColumnInfo } from "@/components/type/DataGrid.type";
|
||||||
import { PopulationStatusColumnConfig } from "@/components/util/column/management/PopulationStatusColumn";
|
import { PopulationStatusColumnConfig } from "@/components/util/column/management/PopulationStatusColumn";
|
||||||
|
|
||||||
|
import type { usePopulationStatusTab } from "@/components/statistics/management/hooks/usePopulationStatusTab";
|
||||||
|
import { asGridRowData, asGridRowSetter } from "@/components/statistics/management/lib/gridCast";
|
||||||
|
|
||||||
const columnInfo: ColumnInfo = {
|
const columnInfo: ColumnInfo = {
|
||||||
columns: PopulationStatusColumnConfig.columns ?? [],
|
columns: PopulationStatusColumnConfig.columns ?? [],
|
||||||
columnLayout: PopulationStatusColumnConfig.columnLayout ?? [],
|
columnLayout: PopulationStatusColumnConfig.columnLayout ?? [],
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import PopulationStatusChart from "./PopulationStatusChart";
|
import PopulationStatusChart from "./PopulationStatusChart";
|
||||||
|
|
||||||
import type { usePopulationVizTab } from "@/components/statistics/management/hooks/usePopulationVizTab";
|
import type { usePopulationVizTab } from "@/components/statistics/management/hooks/usePopulationVizTab";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useCallback, useEffect, useRef, useState } from "react";
|
import { useCallback, useRef, useState } from "react";
|
||||||
|
|
||||||
import { useAlertStore } from "@/shared/lib";
|
import { useAlertStore } from "@/shared/lib";
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
@@ -115,14 +115,6 @@ const StatisticsInputManagement = () => {
|
|||||||
setRowData([]);
|
setRowData([]);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const defaultYear = String(new Date().getFullYear() - 1);
|
|
||||||
void handleSearch({
|
|
||||||
year: defaultYear,
|
|
||||||
clsfCd: "ALL",
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleRegisterClick = () => {
|
const handleRegisterClick = () => {
|
||||||
const yr =
|
const yr =
|
||||||
searchFormValues?.year ?? lastSearchRef.current?.year ?? "";
|
searchFormValues?.year ?? lastSearchRef.current?.year ?? "";
|
||||||
|
|||||||
@@ -1,22 +1,23 @@
|
|||||||
import { useRef, useState } from "react";
|
import { useRef, useState } from "react";
|
||||||
|
|
||||||
|
import { Button, LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||||
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
import { statisticsPpltnApi } from "@/entities/statistics/api/statistics-ppltn-service";
|
import { statisticsPpltnApi } from "@/entities/statistics/api/statistics-ppltn-service";
|
||||||
import type { DomesticPopulationItem } from "@/entities/statistics/model/ppltn/statistics-domestic-population-interface";
|
import type { DomesticPopulationItem } from "@/entities/statistics/model/ppltn/statistics-domestic-population-interface";
|
||||||
import { Button, LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
|
||||||
|
|
||||||
import AdmdstRenewalTab from "./AdmdstRenewalTab";
|
import { usePopulationMappingTab } from "@/components/statistics/management/hooks/usePopulationMappingTab";
|
||||||
|
import { useAdmdstRenewalTab } from "@/components/statistics/management/hooks/useAdmdstRenewalTab";
|
||||||
|
import { usePopulationStatusTab } from "@/components/statistics/management/hooks/usePopulationStatusTab";
|
||||||
|
import { usePopulationVizTab } from "@/components/statistics/management/hooks/usePopulationVizTab";
|
||||||
|
|
||||||
import DomesticPopulationTab from "./DomesticPopulationTab";
|
import DomesticPopulationTab from "./DomesticPopulationTab";
|
||||||
import ForeignPopulationTab from "./ForeignPopulationTab";
|
import ForeignPopulationTab from "./ForeignPopulationTab";
|
||||||
|
import AdmdstRenewalTab from "./AdmdstRenewalTab";
|
||||||
import PopulationStatusTab from "./PopulationStatusTab";
|
import PopulationStatusTab from "./PopulationStatusTab";
|
||||||
import PopulationVizTab from "./PopulationVizTab";
|
import PopulationVizTab from "./PopulationVizTab";
|
||||||
|
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
|
||||||
import { useAdmdstRenewalTab } from "@/components/statistics/management/hooks/useAdmdstRenewalTab";
|
|
||||||
import { usePopulationMappingTab } from "@/components/statistics/management/hooks/usePopulationMappingTab";
|
|
||||||
import { usePopulationStatusTab } from "@/components/statistics/management/hooks/usePopulationStatusTab";
|
|
||||||
import { usePopulationVizTab } from "@/components/statistics/management/hooks/usePopulationVizTab";
|
|
||||||
import type { ForeignPopulationItem } from "@/components/statistics/management/types/population-tab-types";
|
import type { ForeignPopulationItem } from "@/components/statistics/management/types/population-tab-types";
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
|
||||||
|
|
||||||
const TAB_LIST = [
|
const TAB_LIST = [
|
||||||
{ key: "domestic", label: "행정인구등록" },
|
{ key: "domestic", label: "행정인구등록" },
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Dialog,
|
Dialog,
|
||||||
|
|||||||
@@ -2,8 +2,7 @@ import { useRef, useState } from "react";
|
|||||||
|
|
||||||
import { useAlertStore } from "@/shared/lib";
|
import { useAlertStore } from "@/shared/lib";
|
||||||
import { statisticsPpltnApi } from "@/entities/statistics/api/statistics-ppltn-service";
|
import { statisticsPpltnApi } from "@/entities/statistics/api/statistics-ppltn-service";
|
||||||
import type { UpperCodeCandidateItem } from "@/entities/statistics/model/ppltn/statistics-domestic-population-interface";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
|
|
||||||
// TODO: 원본 파일은 `../../../../../../packages/common/components/src/api` (6단계 상위) 였음.
|
// TODO: 원본 파일은 `../../../../../../packages/common/components/src/api` (6단계 상위) 였음.
|
||||||
// 이 훅 파일은 원본 컴포넌트보다 한 단계 더 깊은 폴더(hooks/)에 위치하므로
|
// 이 훅 파일은 원본 컴포넌트보다 한 단계 더 깊은 폴더(hooks/)에 위치하므로
|
||||||
// 실제 프로젝트에 옮길 때 상대경로 깊이를 다시 맞춰줘야 함 (혹은 @common/components에 getUserInfo가
|
// 실제 프로젝트에 옮길 때 상대경로 깊이를 다시 맞춰줘야 함 (혹은 @common/components에 getUserInfo가
|
||||||
@@ -11,14 +10,13 @@ import type { UpperCodeCandidateItem } from "@/entities/statistics/model/ppltn/s
|
|||||||
import { getUserInfo } from "../../../../../../../packages/common/components/src/api";
|
import { getUserInfo } from "../../../../../../../packages/common/components/src/api";
|
||||||
|
|
||||||
import { useAsyncAction } from "./useAsyncAction";
|
import { useAsyncAction } from "./useAsyncAction";
|
||||||
|
import type { UpperCodeCandidateItem } from "@/entities/statistics/model/ppltn/statistics-domestic-population-interface";
|
||||||
import type {
|
import type {
|
||||||
AdmdstRenewalAddedItem,
|
AdmdstRenewalAddedItem,
|
||||||
AdmdstRenewalAddedSaveItem,
|
AdmdstRenewalAddedSaveItem,
|
||||||
AdmdstRenewalReducedItem,
|
AdmdstRenewalReducedItem,
|
||||||
AdmdstRenewalReducedSaveItem,
|
AdmdstRenewalReducedSaveItem,
|
||||||
} from "@/components/statistics/management/types/population-tab-types";
|
} from "@/components/statistics/management/types/population-tab-types";
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
|
||||||
|
|
||||||
export function useAdmdstRenewalTab() {
|
export function useAdmdstRenewalTab() {
|
||||||
const { setMessage: alert } = useAlertStore((state) => state);
|
const { setMessage: alert } = useAlertStore((state) => state);
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
import { useRef, useState } from "react";
|
import { useRef, useState } from "react";
|
||||||
|
|
||||||
import * as XLSX from "xlsx";
|
import * as XLSX from "xlsx";
|
||||||
|
|
||||||
import { useAlertStore } from "@/shared/lib";
|
import { useAlertStore } from "@/shared/lib";
|
||||||
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
|
|
||||||
import { useAsyncAction } from "./useAsyncAction";
|
import { useAsyncAction } from "./useAsyncAction";
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
PopulationMappingApiConfig,
|
PopulationMappingApiConfig,
|
||||||
PopulationMappingRow,
|
PopulationMappingRow,
|
||||||
UpperCodeCandidateItem,
|
UpperCodeCandidateItem,
|
||||||
} from "@/components/statistics/management/types/population-tab-types";
|
} from "@/components/statistics/management/types/population-tab-types";
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
|
||||||
|
|
||||||
/* ── 엑셀 헤더 검증 (원본 컴포넌트의 validateExcelHeader를 그대로 이동) ── */
|
/* ── 엑셀 헤더 검증 (원본 컴포넌트의 validateExcelHeader를 그대로 이동) ── */
|
||||||
const validateExcelHeader = (file: File, requiredKeywords: string[]): Promise<boolean> => {
|
const validateExcelHeader = (file: File, requiredKeywords: string[]): Promise<boolean> => {
|
||||||
@@ -126,12 +124,12 @@ export function usePopulationMappingTab<TRow extends PopulationMappingRow>(
|
|||||||
|
|
||||||
await run(async () => {
|
await run(async () => {
|
||||||
const regList = rightRowData
|
const regList = rightRowData
|
||||||
.filter((row) => String(row.sbstAdmdstCd ?? "").trim() !== "")
|
.filter((row) => String(row.mpinCd ?? "").trim() !== "")
|
||||||
.map((row) => ({
|
.map((row) => ({
|
||||||
statsYr,
|
statsYr,
|
||||||
admdstCd: String(row.admdstCd ?? ""),
|
admdstCd: String(row.admdstCd ?? ""),
|
||||||
admdstNm: String(row.admdstNm ?? ""),
|
admdstNm: String(row.admdstNm ?? ""),
|
||||||
sbstAdmdstCd: String(row.sbstAdmdstCd ?? ""),
|
subAdmdstCd: String(row.mpinCd ?? ""),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const res = await config.saveFinal(statsYr, regList);
|
const res = await config.saveFinal(statsYr, regList);
|
||||||
@@ -167,7 +165,7 @@ const handleRightRowClick = async (rowData: TRow, statsYr: string) => {
|
|||||||
const rowIndex = selectedRowIndexRef.current;
|
const rowIndex = selectedRowIndexRef.current;
|
||||||
if (rowIndex === null) return;
|
if (rowIndex === null) return;
|
||||||
setRightRowData((prev) =>
|
setRightRowData((prev) =>
|
||||||
prev.map((row, idx) => (idx === rowIndex ? { ...row, sbstAdmdstCd: item["admdstCd"] ?? "" } : row)),
|
prev.map((row, idx) => (idx === rowIndex ? { ...row, mpinCd: item["admdstCd"] ?? "" } : row)),
|
||||||
);
|
);
|
||||||
selectedRowIndexRef.current = null;
|
selectedRowIndexRef.current = null;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,12 +2,10 @@ import { useState } from "react";
|
|||||||
|
|
||||||
import { useAlertStore } from "@/shared/lib";
|
import { useAlertStore } from "@/shared/lib";
|
||||||
import { statisticsPpltnApi } from "@/entities/statistics/api/statistics-ppltn-service";
|
import { statisticsPpltnApi } from "@/entities/statistics/api/statistics-ppltn-service";
|
||||||
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
import type { PopulationStatusItem } from "../types/population-tab-types";
|
|
||||||
|
|
||||||
import { useAsyncAction } from "./useAsyncAction";
|
import { useAsyncAction } from "./useAsyncAction";
|
||||||
|
import type { PopulationStatusItem } from "../types/population-tab-types";
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
|
||||||
|
|
||||||
export function usePopulationStatusTab() {
|
export function usePopulationStatusTab() {
|
||||||
const { setMessage: alert } = useAlertStore((state) => state);
|
const { setMessage: alert } = useAlertStore((state) => state);
|
||||||
|
|||||||
@@ -3,9 +3,8 @@ import { useState } from "react";
|
|||||||
import { useAlertStore } from "@/shared/lib";
|
import { useAlertStore } from "@/shared/lib";
|
||||||
import { statisticsPpltnApi } from "@/entities/statistics/api/statistics-ppltn-service";
|
import { statisticsPpltnApi } from "@/entities/statistics/api/statistics-ppltn-service";
|
||||||
|
|
||||||
import type { PopulationChartData } from "../PopulationStatusChart";
|
|
||||||
|
|
||||||
import { useAsyncAction } from "./useAsyncAction";
|
import { useAsyncAction } from "./useAsyncAction";
|
||||||
|
import type { PopulationChartData } from "../PopulationStatusChart";
|
||||||
|
|
||||||
export function usePopulationVizTab() {
|
export function usePopulationVizTab() {
|
||||||
const { setMessage: alert } = useAlertStore((state) => state);
|
const { setMessage: alert } = useAlertStore((state) => state);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { UpperCodeCandidateItem } from "@/entities/statistics/model/ppltn/statistics-domestic-population-interface";
|
|
||||||
import type { ApiResponse } from "@/entities/statistics/model/statistics-interface";
|
import type { ApiResponse } from "@/entities/statistics/model/statistics-interface";
|
||||||
|
import type { UpperCodeCandidateItem } from "@/entities/statistics/model/ppltn/statistics-domestic-population-interface";
|
||||||
|
|
||||||
/* ══════════════════════════════════════════════════
|
/* ══════════════════════════════════════════════════
|
||||||
외국인 인구 관련 타입
|
외국인 인구 관련 타입
|
||||||
@@ -14,7 +14,7 @@ export interface ForeignPopulationItem {
|
|||||||
frgnrMlPpltnCnt: number;
|
frgnrMlPpltnCnt: number;
|
||||||
frgnrFmlPpltnCnt: number;
|
frgnrFmlPpltnCnt: number;
|
||||||
/** 미매핑 리스트(우측) 전용 - 매핑 대상 행정구역코드(상위코드) */
|
/** 미매핑 리스트(우측) 전용 - 매핑 대상 행정구역코드(상위코드) */
|
||||||
sbstAdmdstCd: string;
|
mpinCd: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ForeignPopulationListResponse = ApiResponse<ForeignPopulationItem[]>;
|
export type ForeignPopulationListResponse = ApiResponse<ForeignPopulationItem[]>;
|
||||||
@@ -88,7 +88,7 @@ export interface PopulationMappingRegItem {
|
|||||||
statsYr: string;
|
statsYr: string;
|
||||||
admdstCd: string;
|
admdstCd: string;
|
||||||
admdstNm: string;
|
admdstNm: string;
|
||||||
sbstAdmdstCd: string;
|
subAdmdstCd: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 좌/우 그리드 행이 공통으로 가져야 하는 최소 필드 */
|
/** 좌/우 그리드 행이 공통으로 가져야 하는 최소 필드 */
|
||||||
@@ -96,7 +96,7 @@ export interface PopulationMappingRow {
|
|||||||
admdstCd: string;
|
admdstCd: string;
|
||||||
admdstNm: string;
|
admdstNm: string;
|
||||||
/** 우측(미매핑 리스트) 전용 필드. 좌측 데이터에는 존재하지 않을 수 있음 */
|
/** 우측(미매핑 리스트) 전용 필드. 좌측 데이터에는 존재하지 않을 수 있음 */
|
||||||
sbstAdmdstCd?: string;
|
mpinCd?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** usePopulationMappingTab에 주입하는 API/검증 설정 - 내국인/외국인 탭이 이 설정만 다르게 넘김 */
|
/** usePopulationMappingTab에 주입하는 API/검증 설정 - 내국인/외국인 탭이 이 설정만 다르게 넘김 */
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { useMemo, useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
|
|
||||||
|
import { LoadingWithAnimation } from "@common/components";
|
||||||
import { useAlertStore, useUserStore } from "@/shared/lib";
|
import { useAlertStore, useUserStore } from "@/shared/lib";
|
||||||
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
|
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
||||||
import type {
|
import type {
|
||||||
ExcretaTreatmentFacilityReviewItem,
|
ExcretaTreatmentFacilityReviewItem,
|
||||||
} from "@/entities/statistics/model/statistics-excreta-treatment-facility-review-interface";
|
} from "@/entities/statistics/model/statistics-excreta-treatment-facility-review-interface";
|
||||||
@@ -10,29 +11,28 @@ import {
|
|||||||
extractExcretaTreatmentFacilityReviewList,
|
extractExcretaTreatmentFacilityReviewList,
|
||||||
extractExcretaTreatmentFacilityReviewStatsStatusInfo,
|
extractExcretaTreatmentFacilityReviewStatsStatusInfo,
|
||||||
} from "@/entities/statistics/model/statistics-excreta-treatment-facility-review-interface";
|
} from "@/entities/statistics/model/statistics-excreta-treatment-facility-review-interface";
|
||||||
import type {
|
|
||||||
ReviewerInfoRequest,
|
|
||||||
ReviewOpinionSaveRequest,
|
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
|
||||||
import type { StatsStatusInfo } from "@/entities/statistics/model/statistics-sewage-pipe-review-interface";
|
import type { StatsStatusInfo } from "@/entities/statistics/model/statistics-sewage-pipe-review-interface";
|
||||||
import { LoadingWithAnimation } from "@common/components";
|
import type {
|
||||||
|
ReviewOpinionSaveRequest,
|
||||||
|
ReviewerInfoRequest,
|
||||||
|
} from "@/entities/statistics/model/statistics-interface";
|
||||||
|
|
||||||
|
import SubmitButton from "@/components/button/SumitButton";
|
||||||
import ReturnButton from "@/components/button/ReturnButton";
|
import ReturnButton from "@/components/button/ReturnButton";
|
||||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||||
import SubmitButton from "@/components/button/SumitButton";
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
import { ReturnReasonDialog } from "@/components/statistics/review/ReturnReasonDialog";
|
import { ReturnReasonDialog } from "@/components/statistics/review/ReturnReasonDialog";
|
||||||
import ReviewEmptyCurrLegend from "@/components/statistics/review/ReviewEmptyCurrLegend";
|
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
||||||
import {
|
import {
|
||||||
ReviewOpinionDialog,
|
ReviewOpinionDialog,
|
||||||
type ReviewOpinionDialogContext,
|
type ReviewOpinionDialogContext,
|
||||||
} from "@/components/statistics/review/ReviewOpinionDialog";
|
} from "@/components/statistics/review/ReviewOpinionDialog";
|
||||||
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
import { ExcretaTreatmentFacilityInfoList } from "@/components/util/column/review/ExcretaTreatmentFacilityRvwColumn";
|
import { ExcretaTreatmentFacilityInfoList } from "@/components/util/column/review/ExcretaTreatmentFacilityRvwColumn";
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
import { buildReviewCellStyleCallback } from "@/components/util/grid/reviewEmptyCurrCellStyle";
|
import { buildReviewCellStyleCallback } from "@/components/util/grid/reviewEmptyCurrCellStyle";
|
||||||
|
import ReviewEmptyCurrLegend from "@/components/statistics/review/ReviewEmptyCurrLegend";
|
||||||
|
|
||||||
const excretaTreatmentFacilityTab = ExcretaTreatmentFacilityInfoList[0];
|
const excretaTreatmentFacilityTab = ExcretaTreatmentFacilityInfoList[0];
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,6 @@ import { useMemo, useRef, useState } from "react";
|
|||||||
import { useAlertStore, useUserStore } from "@/shared/lib";
|
import { useAlertStore, useUserStore } from "@/shared/lib";
|
||||||
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
import type {
|
|
||||||
ReviewerInfoRequest,
|
|
||||||
ReviewOpinionSaveRequest,
|
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
|
||||||
import {
|
import {
|
||||||
extractPrivateSewageFacilityReviewList,
|
extractPrivateSewageFacilityReviewList,
|
||||||
extractPrivateSewageFacilityReviewStatsStatusInfo,
|
extractPrivateSewageFacilityReviewStatsStatusInfo,
|
||||||
@@ -14,25 +10,29 @@ import {
|
|||||||
type PrivateSewageFacilityReviewRequestParams,
|
type PrivateSewageFacilityReviewRequestParams,
|
||||||
} from "@/entities/statistics/model/statistics-private-sewage-facility-review-interface";
|
} from "@/entities/statistics/model/statistics-private-sewage-facility-review-interface";
|
||||||
import type { StatsStatusInfo } from "@/entities/statistics/model/statistics-sewage-pipe-review-interface";
|
import type { StatsStatusInfo } from "@/entities/statistics/model/statistics-sewage-pipe-review-interface";
|
||||||
|
import type {
|
||||||
|
ReviewerInfoRequest,
|
||||||
|
ReviewOpinionSaveRequest,
|
||||||
|
} from "@/entities/statistics/model/statistics-interface";
|
||||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||||
|
|
||||||
|
import SubmitButton from "@/components/button/SumitButton";
|
||||||
import ReturnButton from "@/components/button/ReturnButton";
|
import ReturnButton from "@/components/button/ReturnButton";
|
||||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||||
import SubmitButton from "@/components/button/SumitButton";
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
import { ReturnReasonDialog } from "@/components/statistics/review/ReturnReasonDialog";
|
import { ReturnReasonDialog } from "@/components/statistics/review/ReturnReasonDialog";
|
||||||
import ReviewEmptyCurrLegend from "@/components/statistics/review/ReviewEmptyCurrLegend";
|
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
||||||
import {
|
import {
|
||||||
ReviewOpinionDialog,
|
ReviewOpinionDialog,
|
||||||
type ReviewOpinionDialogContext,
|
type ReviewOpinionDialogContext,
|
||||||
} from "@/components/statistics/review/ReviewOpinionDialog";
|
} from "@/components/statistics/review/ReviewOpinionDialog";
|
||||||
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
|
||||||
import type { ColumnConfig, ColumnInfo, ColumnInfoList } from "@/components/type/DataGrid.type";
|
import type { ColumnConfig, ColumnInfo, ColumnInfoList } from "@/components/type/DataGrid.type";
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
import { PrivateSewageFacilityInfoListRvw } from "@/components/util/column/review/PrivateSewageFacilityColumn";
|
import { PrivateSewageFacilityInfoListRvw } from "@/components/util/column/review/PrivateSewageFacilityColumn";
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
import { buildReviewCellStyleCallbackByTab } from "@/components/util/grid/reviewEmptyCurrCellStyle";
|
import { buildReviewCellStyleCallbackByTab } from "@/components/util/grid/reviewEmptyCurrCellStyle";
|
||||||
|
import ReviewEmptyCurrLegend from "@/components/statistics/review/ReviewEmptyCurrLegend";
|
||||||
|
|
||||||
const firstTabKey = PrivateSewageFacilityInfoListRvw[0]?.tabKey ?? "ST00080001";
|
const firstTabKey = PrivateSewageFacilityInfoListRvw[0]?.tabKey ?? "ST00080001";
|
||||||
|
|
||||||
|
|||||||
@@ -1,32 +1,32 @@
|
|||||||
import { useMemo, useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
|
|
||||||
|
import { LoadingWithAnimation } from "@common/components";
|
||||||
import { useAlertStore, useUserStore } from "@/shared/lib";
|
import { useAlertStore, useUserStore } from "@/shared/lib";
|
||||||
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
import type {
|
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
||||||
ReviewerInfoRequest,
|
|
||||||
ReviewOpinionSaveRequest,
|
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
|
||||||
import type { PublicSewageFacilityReviewItem } from "@/entities/statistics/model/statistics-public-sewage-facility-review-interface";
|
import type { PublicSewageFacilityReviewItem } from "@/entities/statistics/model/statistics-public-sewage-facility-review-interface";
|
||||||
import type { StatsStatusInfo } from "@/entities/statistics/model/statistics-sewage-pipe-review-interface";
|
import type { StatsStatusInfo } from "@/entities/statistics/model/statistics-sewage-pipe-review-interface";
|
||||||
import { LoadingWithAnimation } from "@common/components";
|
import type {
|
||||||
|
ReviewOpinionSaveRequest,
|
||||||
import ReturnButton from "@/components/button/ReturnButton";
|
ReviewerInfoRequest,
|
||||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
} from "@/entities/statistics/model/statistics-interface";
|
||||||
import SubmitButton from "@/components/button/SumitButton";
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
|
import SubmitButton from "@/components/button/SumitButton";
|
||||||
|
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||||
|
import ReturnButton from "@/components/button/ReturnButton";
|
||||||
import { ReturnReasonDialog } from "@/components/statistics/review/ReturnReasonDialog";
|
import { ReturnReasonDialog } from "@/components/statistics/review/ReturnReasonDialog";
|
||||||
import ReviewEmptyCurrLegend from "@/components/statistics/review/ReviewEmptyCurrLegend";
|
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
||||||
import {
|
import {
|
||||||
ReviewOpinionDialog,
|
ReviewOpinionDialog,
|
||||||
type ReviewOpinionDialogContext,
|
type ReviewOpinionDialogContext,
|
||||||
} from "@/components/statistics/review/ReviewOpinionDialog";
|
} from "@/components/statistics/review/ReviewOpinionDialog";
|
||||||
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
import { PublicSewageFacilityInfoList } from "@/components/util/column/review/PublicSewageFacilityRvwColumn";
|
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
import { buildReviewCellStyleCallback } from "@/components/util/grid/reviewEmptyCurrCellStyle";
|
import { buildReviewCellStyleCallback } from "@/components/util/grid/reviewEmptyCurrCellStyle";
|
||||||
|
import ReviewEmptyCurrLegend from "@/components/statistics/review/ReviewEmptyCurrLegend";
|
||||||
|
|
||||||
|
import { PublicSewageFacilityInfoList } from "@/components/util/column/review/PublicSewageFacilityRvwColumn";
|
||||||
|
|
||||||
// 하수도 통계 관리 06.공공하수처리시설
|
// 하수도 통계 관리 06.공공하수처리시설
|
||||||
const PublicSewageFacilityRvw = () => {
|
const PublicSewageFacilityRvw = () => {
|
||||||
|
|||||||
@@ -1,36 +1,36 @@
|
|||||||
import { useMemo, useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
|
|
||||||
|
import { LoadingWithAnimation } from "@common/components";
|
||||||
import { useAlertStore, useUserStore } from "@/shared/lib";
|
import { useAlertStore, useUserStore } from "@/shared/lib";
|
||||||
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
import type {
|
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
||||||
ReviewerInfoRequest,
|
|
||||||
ReviewOpinionSaveRequest,
|
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
|
||||||
import {
|
import {
|
||||||
extractMediationPumpStationList,
|
extractMediationPumpStationList,
|
||||||
extractMediationPumpStationStatsStatusInfo,
|
extractMediationPumpStationStatsStatusInfo,
|
||||||
type MediationPumpStationItem,
|
type MediationPumpStationItem,
|
||||||
} from "@/entities/statistics/model/statistics-pumping-station-review-interface";
|
} from "@/entities/statistics/model/statistics-pumping-station-review-interface";
|
||||||
import type { StatsStatusInfo } from "@/entities/statistics/model/statistics-sewage-pipe-review-interface";
|
import type { StatsStatusInfo } from "@/entities/statistics/model/statistics-sewage-pipe-review-interface";
|
||||||
import { LoadingWithAnimation } from "@common/components";
|
import type {
|
||||||
|
ReviewOpinionSaveRequest,
|
||||||
|
ReviewerInfoRequest,
|
||||||
|
} from "@/entities/statistics/model/statistics-interface";
|
||||||
|
|
||||||
|
import SubmitButton from "@/components/button/SumitButton";
|
||||||
import ReturnButton from "@/components/button/ReturnButton";
|
import ReturnButton from "@/components/button/ReturnButton";
|
||||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||||
import SubmitButton from "@/components/button/SumitButton";
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
import { ReturnReasonDialog } from "@/components/statistics/review/ReturnReasonDialog";
|
import { ReturnReasonDialog } from "@/components/statistics/review/ReturnReasonDialog";
|
||||||
import ReviewEmptyCurrLegend from "@/components/statistics/review/ReviewEmptyCurrLegend";
|
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
||||||
import {
|
import {
|
||||||
ReviewOpinionDialog,
|
ReviewOpinionDialog,
|
||||||
type ReviewOpinionDialogContext,
|
type ReviewOpinionDialogContext,
|
||||||
} from "@/components/statistics/review/ReviewOpinionDialog";
|
} from "@/components/statistics/review/ReviewOpinionDialog";
|
||||||
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
import { PumpingStationInfoList } from "@/components/util/column/review/PumpingStationRvwColumn";
|
import { PumpingStationInfoList } from "@/components/util/column/review/PumpingStationRvwColumn";
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
import { buildReviewCellStyleCallback } from "@/components/util/grid/reviewEmptyCurrCellStyle";
|
import { buildReviewCellStyleCallback } from "@/components/util/grid/reviewEmptyCurrCellStyle";
|
||||||
|
import ReviewEmptyCurrLegend from "@/components/statistics/review/ReviewEmptyCurrLegend";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 하수도 통계 검토 05.중계펌프장
|
* 하수도 통계 검토 05.중계펌프장
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
||||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||||
|
|
||||||
import { useAlertStore } from "@/shared/lib";
|
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
|
||||||
import type { ReviewReturnSaveRequest } from "@/entities/statistics/model/statistics-interface";
|
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Dialog,
|
Dialog,
|
||||||
@@ -19,7 +16,9 @@ import {
|
|||||||
Textarea,
|
Textarea,
|
||||||
} from "@common/components";
|
} from "@common/components";
|
||||||
|
|
||||||
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
import type { ReviewReturnSaveRequest } from "@/entities/statistics/model/statistics-interface";
|
||||||
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
|
import { useAlertStore } from "@/shared/lib";
|
||||||
|
|
||||||
export type ReturnReasonDialogContext = Pick<
|
export type ReturnReasonDialogContext = Pick<
|
||||||
ReviewReturnSaveRequest,
|
ReviewReturnSaveRequest,
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
import { useAlertStore } from "@/shared/lib";
|
|
||||||
import type { ReviewOpinionSaveRequest } from "@/entities/statistics/model/statistics-interface";
|
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Dialog,
|
Dialog,
|
||||||
@@ -15,9 +13,11 @@ import {
|
|||||||
Label,
|
Label,
|
||||||
Textarea,
|
Textarea,
|
||||||
} from "@common/components";
|
} from "@common/components";
|
||||||
|
|
||||||
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
||||||
|
|
||||||
|
import type { ReviewOpinionSaveRequest } from "@/entities/statistics/model/statistics-interface";
|
||||||
|
import { useAlertStore } from "@/shared/lib";
|
||||||
|
|
||||||
export type ReviewOpinionDialogContext = Pick<
|
export type ReviewOpinionDialogContext = Pick<
|
||||||
ReviewOpinionSaveRequest,
|
ReviewOpinionSaveRequest,
|
||||||
"statsYr" | "sewerBzmnCd" | "statsCd"
|
"statsYr" | "sewerBzmnCd" | "statsCd"
|
||||||
@@ -103,7 +103,7 @@ export function ReviewOpinionDialog({
|
|||||||
resetForm();
|
resetForm();
|
||||||
onOpenChange(false);
|
onOpenChange(false);
|
||||||
} catch {
|
} catch {
|
||||||
console.error('검토 의견 저장 error');
|
/* 저장 실패 시 부모에서 alert 후 throw — 다이얼로그는 유지 */
|
||||||
} finally {
|
} finally {
|
||||||
setIsSaving(false);
|
setIsSaving(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,8 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
||||||
|
|
||||||
import { useAlertStore } from "@/shared/lib";
|
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
|
||||||
import type {
|
|
||||||
ReviewerInfoRequest,
|
|
||||||
ReviewerInfoResponse,
|
|
||||||
ReviewSubmitRequest,
|
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Dialog,
|
Dialog,
|
||||||
@@ -22,18 +16,19 @@ import {
|
|||||||
Textarea,
|
Textarea,
|
||||||
} from "@common/components";
|
} from "@common/components";
|
||||||
|
|
||||||
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
|
import type {
|
||||||
|
ReviewerInfoRequest,
|
||||||
|
ReviewerInfoResponse,
|
||||||
|
ReviewSubmitRequest,
|
||||||
|
} from "@/entities/statistics/model/statistics-interface";
|
||||||
|
import { useAlertStore } from "@/shared/lib";
|
||||||
|
|
||||||
export interface ReviewSubmitDialogProps {
|
export interface ReviewSubmitDialogProps {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
onOpenChange: (open: boolean) => void;
|
onOpenChange: (open: boolean) => void;
|
||||||
context: ReviewerInfoRequest | null;
|
context: ReviewerInfoRequest | null;
|
||||||
onSubmitted?: () => void | Promise<void>;
|
onSubmitted?: () => void | Promise<void>;
|
||||||
/**
|
|
||||||
* true면 검토의견·처리내역 UI를 숨기고
|
|
||||||
* submit body에 statsCd / splmntOpnnCn / wrterOpnnCn을 넣지 않음
|
|
||||||
*/
|
|
||||||
hideOpinionFields?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ReviewSubmitDialog({
|
export function ReviewSubmitDialog({
|
||||||
@@ -41,7 +36,6 @@ export function ReviewSubmitDialog({
|
|||||||
onOpenChange,
|
onOpenChange,
|
||||||
context,
|
context,
|
||||||
onSubmitted,
|
onSubmitted,
|
||||||
hideOpinionFields = false,
|
|
||||||
}: ReviewSubmitDialogProps) {
|
}: ReviewSubmitDialogProps) {
|
||||||
const { setMessage: alert } = useAlertStore((state) => state);
|
const { setMessage: alert } = useAlertStore((state) => state);
|
||||||
const [reviewerInfo, setReviewerInfo] =
|
const [reviewerInfo, setReviewerInfo] =
|
||||||
@@ -104,20 +98,14 @@ export function ReviewSubmitDialog({
|
|||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
|
|
||||||
const userInfo = await getUserInfo();
|
const userInfo = await getUserInfo();
|
||||||
const submitParam: ReviewSubmitRequest = hideOpinionFields
|
const submitParam: ReviewSubmitRequest = {
|
||||||
? {
|
statsYr: context.statsYr,
|
||||||
statsYr: context.statsYr,
|
sewerBzmnCd: context.sewerBzmnCd,
|
||||||
sewerBzmnCd: [context.sewerBzmnCd],
|
statsCd: context.statsCd,
|
||||||
mdfrId: userInfo.userUnqId,
|
mdfrId: userInfo.userUnqId,
|
||||||
}
|
splmntOpnnCn: reviewerInfo?.splmntOpnnCn ?? "",
|
||||||
: {
|
wrterOpnnCn: reviewerInfo?.wrterOpnnCn ?? "",
|
||||||
statsYr: context.statsYr,
|
};
|
||||||
sewerBzmnCd: context.sewerBzmnCd,
|
|
||||||
statsCd: context.statsCd,
|
|
||||||
mdfrId: userInfo.userUnqId,
|
|
||||||
splmntOpnnCn: reviewerInfo?.splmntOpnnCn ?? "",
|
|
||||||
wrterOpnnCn: reviewerInfo?.wrterOpnnCn ?? "",
|
|
||||||
};
|
|
||||||
|
|
||||||
const response = await statisticsApi.submitReview(submitParam);
|
const response = await statisticsApi.submitReview(submitParam);
|
||||||
if (response.status !== "success") {
|
if (response.status !== "success") {
|
||||||
@@ -165,26 +153,22 @@ export function ReviewSubmitDialog({
|
|||||||
<Label className="text-label">직책</Label>
|
<Label className="text-label">직책</Label>
|
||||||
<Input value={reviewerInfo?.cps ?? "-"} readOnly />
|
<Input value={reviewerInfo?.cps ?? "-"} readOnly />
|
||||||
</div>
|
</div>
|
||||||
{!hideOpinionFields && (
|
<div className="col-span-2 flex flex-col gap-2">
|
||||||
<>
|
<Label className="text-label">검토의견</Label>
|
||||||
<div className="col-span-2 flex flex-col gap-2">
|
<Textarea
|
||||||
<Label className="text-label">검토의견</Label>
|
value={reviewerInfo?.splmntOpnnCn ?? "-"}
|
||||||
<Textarea
|
readOnly
|
||||||
value={reviewerInfo?.splmntOpnnCn ?? "-"}
|
className="min-h-[10rem] p-2 resize-none !text-xl"
|
||||||
readOnly
|
/>
|
||||||
className="min-h-[10rem] p-2 resize-none !text-xl"
|
</div>
|
||||||
/>
|
<div className="col-span-2 flex flex-col gap-2">
|
||||||
</div>
|
<Label className="text-label">처리내역</Label>
|
||||||
<div className="col-span-2 flex flex-col gap-2">
|
<Textarea
|
||||||
<Label className="text-label">처리내역</Label>
|
value={reviewerInfo?.wrterOpnnCn ?? "-"}
|
||||||
<Textarea
|
readOnly
|
||||||
value={reviewerInfo?.wrterOpnnCn ?? "-"}
|
className="min-h-[10rem] p-2 resize-none !text-xl"
|
||||||
readOnly
|
/>
|
||||||
className="min-h-[10rem] p-2 resize-none !text-xl"
|
</div>
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -3,10 +3,6 @@ import { useMemo, useRef, useState } from "react";
|
|||||||
import { useAlertStore, useUserStore } from "@/shared/lib";
|
import { useAlertStore, useUserStore } from "@/shared/lib";
|
||||||
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
import type {
|
|
||||||
ReviewerInfoRequest,
|
|
||||||
ReviewOpinionSaveRequest,
|
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
|
||||||
import {
|
import {
|
||||||
extractSewageExcretaRelatedReviewList,
|
extractSewageExcretaRelatedReviewList,
|
||||||
extractSewageExcretaRelatedReviewStatsStatusInfo,
|
extractSewageExcretaRelatedReviewStatsStatusInfo,
|
||||||
@@ -14,25 +10,29 @@ import {
|
|||||||
type SewageExcretaRelatedReviewRequestParams,
|
type SewageExcretaRelatedReviewRequestParams,
|
||||||
} from "@/entities/statistics/model/statistics-sewage-excreta-related-review-interface";
|
} from "@/entities/statistics/model/statistics-sewage-excreta-related-review-interface";
|
||||||
import type { StatsStatusInfo } from "@/entities/statistics/model/statistics-sewage-pipe-review-interface";
|
import type { StatsStatusInfo } from "@/entities/statistics/model/statistics-sewage-pipe-review-interface";
|
||||||
|
import type {
|
||||||
|
ReviewerInfoRequest,
|
||||||
|
ReviewOpinionSaveRequest,
|
||||||
|
} from "@/entities/statistics/model/statistics-interface";
|
||||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||||
|
|
||||||
|
import SubmitButton from "@/components/button/SumitButton";
|
||||||
import ReturnButton from "@/components/button/ReturnButton";
|
import ReturnButton from "@/components/button/ReturnButton";
|
||||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||||
import SubmitButton from "@/components/button/SumitButton";
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
import { ReturnReasonDialog } from "@/components/statistics/review/ReturnReasonDialog";
|
import { ReturnReasonDialog } from "@/components/statistics/review/ReturnReasonDialog";
|
||||||
import ReviewEmptyCurrLegend from "@/components/statistics/review/ReviewEmptyCurrLegend";
|
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
||||||
import {
|
import {
|
||||||
ReviewOpinionDialog,
|
ReviewOpinionDialog,
|
||||||
type ReviewOpinionDialogContext,
|
type ReviewOpinionDialogContext,
|
||||||
} from "@/components/statistics/review/ReviewOpinionDialog";
|
} from "@/components/statistics/review/ReviewOpinionDialog";
|
||||||
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
|
||||||
import type { ColumnConfig, ColumnInfo, ColumnInfoList } from "@/components/type/DataGrid.type";
|
import type { ColumnConfig, ColumnInfo, ColumnInfoList } from "@/components/type/DataGrid.type";
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
import { SewageExcretaRelatedInfoListRvw } from "@/components/util/column/review/SewageExcretaRelatedRvwColumn";
|
import { SewageExcretaRelatedInfoListRvw } from "@/components/util/column/review/SewageExcretaRelatedRvwColumn";
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
import { buildReviewCellStyleCallbackByTab } from "@/components/util/grid/reviewEmptyCurrCellStyle";
|
import { buildReviewCellStyleCallbackByTab } from "@/components/util/grid/reviewEmptyCurrCellStyle";
|
||||||
|
import ReviewEmptyCurrLegend from "@/components/statistics/review/ReviewEmptyCurrLegend";
|
||||||
|
|
||||||
const firstTabKey = SewageExcretaRelatedInfoListRvw[0]?.tabKey ?? "ST00120001";
|
const firstTabKey = SewageExcretaRelatedInfoListRvw[0]?.tabKey ?? "ST00120001";
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,6 @@ import { useMemo, useRef, useState } from "react";
|
|||||||
import { useAlertStore, useUserStore } from "@/shared/lib";
|
import { useAlertStore, useUserStore } from "@/shared/lib";
|
||||||
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
import type {
|
|
||||||
ReviewerInfoRequest,
|
|
||||||
ReviewOpinionSaveRequest,
|
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
|
||||||
import {
|
import {
|
||||||
extractSewageExcretaSlurgeReviewList,
|
extractSewageExcretaSlurgeReviewList,
|
||||||
extractSewageExcretaSlurgeReviewStatsStatusInfo,
|
extractSewageExcretaSlurgeReviewStatsStatusInfo,
|
||||||
@@ -14,25 +10,29 @@ import {
|
|||||||
type SewageExcretaSlurgeReviewRequestParams,
|
type SewageExcretaSlurgeReviewRequestParams,
|
||||||
} from "@/entities/statistics/model/statistics-sewage-excreta-slurge-review-interface";
|
} from "@/entities/statistics/model/statistics-sewage-excreta-slurge-review-interface";
|
||||||
import type { StatsStatusInfo } from "@/entities/statistics/model/statistics-sewage-pipe-review-interface";
|
import type { StatsStatusInfo } from "@/entities/statistics/model/statistics-sewage-pipe-review-interface";
|
||||||
|
import type {
|
||||||
|
ReviewerInfoRequest,
|
||||||
|
ReviewOpinionSaveRequest,
|
||||||
|
} from "@/entities/statistics/model/statistics-interface";
|
||||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||||
|
|
||||||
|
import SubmitButton from "@/components/button/SumitButton";
|
||||||
import ReturnButton from "@/components/button/ReturnButton";
|
import ReturnButton from "@/components/button/ReturnButton";
|
||||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||||
import SubmitButton from "@/components/button/SumitButton";
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
import { ReturnReasonDialog } from "@/components/statistics/review/ReturnReasonDialog";
|
import { ReturnReasonDialog } from "@/components/statistics/review/ReturnReasonDialog";
|
||||||
import ReviewEmptyCurrLegend from "@/components/statistics/review/ReviewEmptyCurrLegend";
|
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
||||||
import {
|
import {
|
||||||
ReviewOpinionDialog,
|
ReviewOpinionDialog,
|
||||||
type ReviewOpinionDialogContext,
|
type ReviewOpinionDialogContext,
|
||||||
} from "@/components/statistics/review/ReviewOpinionDialog";
|
} from "@/components/statistics/review/ReviewOpinionDialog";
|
||||||
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
|
||||||
import type { ColumnConfig, ColumnInfo, ColumnInfoList } from "@/components/type/DataGrid.type";
|
import type { ColumnConfig, ColumnInfo, ColumnInfoList } from "@/components/type/DataGrid.type";
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
import { SewageExcretaSludgeInfoListRvw } from "@/components/util/column/review/SewageExcretaSlurgeRvwColumn";
|
import { SewageExcretaSludgeInfoListRvw } from "@/components/util/column/review/SewageExcretaSlurgeRvwColumn";
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
import { buildReviewCellStyleCallbackByTab } from "@/components/util/grid/reviewEmptyCurrCellStyle";
|
import { buildReviewCellStyleCallbackByTab } from "@/components/util/grid/reviewEmptyCurrCellStyle";
|
||||||
|
import ReviewEmptyCurrLegend from "@/components/statistics/review/ReviewEmptyCurrLegend";
|
||||||
|
|
||||||
const firstTabKey = SewageExcretaSludgeInfoListRvw[0]?.tabKey ?? "ST00110001";
|
const firstTabKey = SewageExcretaSludgeInfoListRvw[0]?.tabKey ?? "ST00110001";
|
||||||
|
|
||||||
|
|||||||
@@ -3,33 +3,33 @@ import { useMemo, useRef, useState } from "react";
|
|||||||
import { useAlertStore, useUserStore } from "@/shared/lib";
|
import { useAlertStore, useUserStore } from "@/shared/lib";
|
||||||
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
import type {
|
|
||||||
ReviewerInfoRequest,
|
|
||||||
ReviewOpinionSaveRequest,
|
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
|
||||||
import type {
|
import type {
|
||||||
SewerPipeMtcRequestParams,
|
SewerPipeMtcRequestParams,
|
||||||
StatsStatusInfo,
|
StatsStatusInfo,
|
||||||
} from "@/entities/statistics/model/statistics-sewage-pipe-mtc-review-interface";
|
} from "@/entities/statistics/model/statistics-sewage-pipe-mtc-review-interface";
|
||||||
|
import type {
|
||||||
|
ReviewerInfoRequest,
|
||||||
|
ReviewOpinionSaveRequest,
|
||||||
|
} from "@/entities/statistics/model/statistics-interface";
|
||||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||||
|
|
||||||
|
import SubmitButton from "@/components/button/SumitButton";
|
||||||
import ReturnButton from "@/components/button/ReturnButton";
|
import ReturnButton from "@/components/button/ReturnButton";
|
||||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||||
import SubmitButton from "@/components/button/SumitButton";
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
import { ReturnReasonDialog } from "@/components/statistics/review/ReturnReasonDialog";
|
import { ReturnReasonDialog } from "@/components/statistics/review/ReturnReasonDialog";
|
||||||
import ReviewEmptyCurrLegend from "@/components/statistics/review/ReviewEmptyCurrLegend";
|
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
||||||
import {
|
import {
|
||||||
ReviewOpinionDialog,
|
ReviewOpinionDialog,
|
||||||
type ReviewOpinionDialogContext,
|
type ReviewOpinionDialogContext,
|
||||||
} from "@/components/statistics/review/ReviewOpinionDialog";
|
} from "@/components/statistics/review/ReviewOpinionDialog";
|
||||||
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
|
||||||
import type { ColumnConfig, ColumnInfo, ColumnInfoList } from "@/components/type/DataGrid.type";
|
import type { ColumnConfig, ColumnInfo, ColumnInfoList } from "@/components/type/DataGrid.type";
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
import { SewagePipeMaintainColumnInfoList } from "@/components/util/column/review/SewagePipeMaintainRvwColumn";
|
import { SewagePipeMaintainColumnInfoList } from "@/components/util/column/review/SewagePipeMaintainRvwColumn";
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
import { buildReviewCellStyleCallbackByTab } from "@/components/util/grid/reviewEmptyCurrCellStyle";
|
import { buildReviewCellStyleCallbackByTab } from "@/components/util/grid/reviewEmptyCurrCellStyle";
|
||||||
|
import ReviewEmptyCurrLegend from "@/components/statistics/review/ReviewEmptyCurrLegend";
|
||||||
|
|
||||||
const firstTabKey = SewagePipeMaintainColumnInfoList[0]?.tabKey ?? "ST00030001";
|
const firstTabKey = SewagePipeMaintainColumnInfoList[0]?.tabKey ?? "ST00030001";
|
||||||
|
|
||||||
|
|||||||
@@ -3,28 +3,27 @@ import { useMemo, useRef, useState } from "react";
|
|||||||
import { useAlertStore, useUserStore } from "@/shared/lib";
|
import { useAlertStore, useUserStore } from "@/shared/lib";
|
||||||
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
import type {
|
|
||||||
ReviewerInfoRequest,
|
|
||||||
ReviewOpinionSaveRequest,
|
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
|
||||||
import type {
|
import type {
|
||||||
SewagePipeReviewRequestParams,
|
SewagePipeReviewRequestParams,
|
||||||
StatsStatusInfo,
|
StatsStatusInfo,
|
||||||
} from "@/entities/statistics/model/statistics-sewage-pipe-review-interface";
|
} from "@/entities/statistics/model/statistics-sewage-pipe-review-interface";
|
||||||
|
import type {
|
||||||
|
ReviewerInfoRequest,
|
||||||
|
ReviewOpinionSaveRequest,
|
||||||
|
} from "@/entities/statistics/model/statistics-interface";
|
||||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||||
|
|
||||||
|
import SubmitButton from "@/components/button/SumitButton";
|
||||||
import ReturnButton from "@/components/button/ReturnButton";
|
import ReturnButton from "@/components/button/ReturnButton";
|
||||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||||
import SubmitButton from "@/components/button/SumitButton";
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
import { ReturnReasonDialog } from "@/components/statistics/review/ReturnReasonDialog";
|
import { ReturnReasonDialog } from "@/components/statistics/review/ReturnReasonDialog";
|
||||||
import ReviewEmptyCurrLegend from "@/components/statistics/review/ReviewEmptyCurrLegend";
|
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
||||||
import {
|
import {
|
||||||
ReviewOpinionDialog,
|
ReviewOpinionDialog,
|
||||||
type ReviewOpinionDialogContext,
|
type ReviewOpinionDialogContext,
|
||||||
} from "@/components/statistics/review/ReviewOpinionDialog";
|
} from "@/components/statistics/review/ReviewOpinionDialog";
|
||||||
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
|
||||||
import type {
|
import type {
|
||||||
ColumnConfig,
|
ColumnConfig,
|
||||||
ColumnInfo,
|
ColumnInfo,
|
||||||
@@ -32,9 +31,10 @@ import type {
|
|||||||
ColumnLayoutItem,
|
ColumnLayoutItem,
|
||||||
} from "@/components/type/DataGrid.type";
|
} from "@/components/type/DataGrid.type";
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
import { getST00020003RvwConfig,SewagePipeColumnInfoListRvw } from "@/components/util/column/review/SewagePipeRvwColumn";
|
import { SewagePipeColumnInfoListRvw } from "@/components/util/column/review/SewagePipeRvwColumn";
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
|
||||||
import { buildReviewCellStyleCallbackByTab } from "@/components/util/grid/reviewEmptyCurrCellStyle";
|
import { buildReviewCellStyleCallbackByTab } from "@/components/util/grid/reviewEmptyCurrCellStyle";
|
||||||
|
import ReviewEmptyCurrLegend from "@/components/statistics/review/ReviewEmptyCurrLegend";
|
||||||
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
|
|
||||||
const firstTabKey = SewagePipeColumnInfoListRvw[0]?.tabKey ?? "ST00020001";
|
const firstTabKey = SewagePipeColumnInfoListRvw[0]?.tabKey ?? "ST00020001";
|
||||||
|
|
||||||
@@ -148,23 +148,15 @@ const SewagePipeRvw = () => {
|
|||||||
[tabStatsStatusInfoMap, activeTab],
|
[tabStatsStatusInfoMap, activeTab],
|
||||||
);
|
);
|
||||||
const columnInfo = useMemo<ColumnInfoList[]>(
|
const columnInfo = useMemo<ColumnInfoList[]>(
|
||||||
() => {
|
() =>
|
||||||
const statsYr = lastSearchValues?.year ?? new Date().getFullYear();
|
SewagePipeColumnInfoListRvw.map((tab) => ({
|
||||||
const st00020003Config = getST00020003RvwConfig(statsYr);
|
...tab,
|
||||||
return SewagePipeColumnInfoListRvw.map((tab) => {
|
columns: (tab.columns ?? []).map((col) => cloneColumnConfig(col)),
|
||||||
const source =
|
columnLayout: (tab.columnLayout ?? []).map((item) =>
|
||||||
tab.tabKey === "ST00020003" ? st00020003Config
|
cloneColumnLayoutItem(item),
|
||||||
: tab;
|
),
|
||||||
return {
|
})),
|
||||||
...source,
|
[],
|
||||||
columns: (source.columns ?? []).map((col) => cloneColumnConfig(col as Parameters<typeof cloneColumnConfig>[0])),
|
|
||||||
columnLayout: (source.columnLayout ?? []).map((item) =>
|
|
||||||
cloneColumnLayoutItem(item as ColumnLayoutItem),
|
|
||||||
),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[lastSearchValues?.year],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const reviewCellStyleCallbackByTab = useMemo(
|
const reviewCellStyleCallbackByTab = useMemo(
|
||||||
|
|||||||
@@ -3,31 +3,31 @@ import { useMemo, useRef, useState } from "react";
|
|||||||
import { useAlertStore, useUserStore } from "@/shared/lib";
|
import { useAlertStore, useUserStore } from "@/shared/lib";
|
||||||
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
|
import type { StatsStatusInfo } from "@/entities/statistics/model/statistics-sewage-pipe-review-interface";
|
||||||
import type { SewerReservoirRequestParams } from "@/entities/statistics/model/sewage-reservoir-pump-review-interface";
|
import type { SewerReservoirRequestParams } from "@/entities/statistics/model/sewage-reservoir-pump-review-interface";
|
||||||
import type {
|
import type {
|
||||||
ReviewerInfoRequest,
|
ReviewerInfoRequest,
|
||||||
ReviewOpinionSaveRequest,
|
ReviewOpinionSaveRequest,
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
} from "@/entities/statistics/model/statistics-interface";
|
||||||
import type { StatsStatusInfo } from "@/entities/statistics/model/statistics-sewage-pipe-review-interface";
|
|
||||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||||
|
|
||||||
|
import SubmitButton from "@/components/button/SumitButton";
|
||||||
import ReturnButton from "@/components/button/ReturnButton";
|
import ReturnButton from "@/components/button/ReturnButton";
|
||||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||||
import SubmitButton from "@/components/button/SumitButton";
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
import { ReturnReasonDialog } from "@/components/statistics/review/ReturnReasonDialog";
|
import { ReturnReasonDialog } from "@/components/statistics/review/ReturnReasonDialog";
|
||||||
import ReviewEmptyCurrLegend from "@/components/statistics/review/ReviewEmptyCurrLegend";
|
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
||||||
import {
|
import {
|
||||||
ReviewOpinionDialog,
|
ReviewOpinionDialog,
|
||||||
type ReviewOpinionDialogContext,
|
type ReviewOpinionDialogContext,
|
||||||
} from "@/components/statistics/review/ReviewOpinionDialog";
|
} from "@/components/statistics/review/ReviewOpinionDialog";
|
||||||
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
|
||||||
import type { ColumnConfig, ColumnInfo, ColumnInfoList } from "@/components/type/DataGrid.type";
|
import type { ColumnConfig, ColumnInfo, ColumnInfoList } from "@/components/type/DataGrid.type";
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
import { SewageReservoirPumpInfoListRvw } from "@/components/util/column/review/SewageReservoirPumpRvwColumn";
|
import { SewageReservoirPumpInfoListRvw } from "@/components/util/column/review/SewageReservoirPumpRvwColumn";
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
import { buildReviewCellStyleCallbackByTab } from "@/components/util/grid/reviewEmptyCurrCellStyle";
|
import { buildReviewCellStyleCallbackByTab } from "@/components/util/grid/reviewEmptyCurrCellStyle";
|
||||||
|
import ReviewEmptyCurrLegend from "@/components/statistics/review/ReviewEmptyCurrLegend";
|
||||||
|
|
||||||
const firstTabKey = SewageReservoirPumpInfoListRvw[0]?.tabKey ?? "ST00040001";
|
const firstTabKey = SewageReservoirPumpInfoListRvw[0]?.tabKey ?? "ST00040001";
|
||||||
|
|
||||||
|
|||||||
@@ -3,36 +3,36 @@ import { useMemo, useRef, useState } from "react";
|
|||||||
import { useAlertStore, useUserStore } from "@/shared/lib";
|
import { useAlertStore, useUserStore } from "@/shared/lib";
|
||||||
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
import type {
|
|
||||||
ReviewerInfoRequest,
|
|
||||||
ReviewOpinionSaveRequest,
|
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
|
||||||
import type { StatsStatusInfo } from "@/entities/statistics/model/statistics-sewage-pipe-review-interface";
|
|
||||||
import {
|
import {
|
||||||
extractSewerageFinanceReviewList,
|
extractSewerageFinanceReviewList,
|
||||||
extractSewerageFinanceReviewStatsStatusInfo,
|
extractSewerageFinanceReviewStatsStatusInfo,
|
||||||
mapSewerageFinanceReviewRows,
|
mapSewerageFinanceReviewRows,
|
||||||
type SewerageFinanceReviewRequestParams,
|
type SewerageFinanceReviewRequestParams,
|
||||||
} from "@/entities/statistics/model/statistics-sewerage-finance-review-interface";
|
} from "@/entities/statistics/model/statistics-sewerage-finance-review-interface";
|
||||||
|
import type { StatsStatusInfo } from "@/entities/statistics/model/statistics-sewage-pipe-review-interface";
|
||||||
|
import type {
|
||||||
|
ReviewerInfoRequest,
|
||||||
|
ReviewOpinionSaveRequest,
|
||||||
|
} from "@/entities/statistics/model/statistics-interface";
|
||||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||||
|
|
||||||
|
import SubmitButton from "@/components/button/SumitButton";
|
||||||
import ReturnButton from "@/components/button/ReturnButton";
|
import ReturnButton from "@/components/button/ReturnButton";
|
||||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||||
import SubmitButton from "@/components/button/SumitButton";
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
import { ReturnReasonDialog } from "@/components/statistics/review/ReturnReasonDialog";
|
import { ReturnReasonDialog } from "@/components/statistics/review/ReturnReasonDialog";
|
||||||
import ReviewEmptyCurrLegend from "@/components/statistics/review/ReviewEmptyCurrLegend";
|
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
||||||
import {
|
import {
|
||||||
ReviewOpinionDialog,
|
ReviewOpinionDialog,
|
||||||
type ReviewOpinionDialogContext,
|
type ReviewOpinionDialogContext,
|
||||||
} from "@/components/statistics/review/ReviewOpinionDialog";
|
} from "@/components/statistics/review/ReviewOpinionDialog";
|
||||||
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
|
||||||
import type { ColumnConfig, ColumnInfo, ColumnInfoList } from "@/components/type/DataGrid.type";
|
import type { ColumnConfig, ColumnInfo, ColumnInfoList } from "@/components/type/DataGrid.type";
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
import { SewerageFinanceInfoListRvw } from "@/components/util/column/review/SewerageFinanceRvwColumn";
|
import { SewerageFinanceInfoListRvw } from "@/components/util/column/review/SewerageFinanceRvwColumn";
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
import { buildReviewCellStyleCallbackByTab } from "@/components/util/grid/reviewEmptyCurrCellStyle";
|
import { buildReviewCellStyleCallbackByTab } from "@/components/util/grid/reviewEmptyCurrCellStyle";
|
||||||
|
import ReviewEmptyCurrLegend from "@/components/statistics/review/ReviewEmptyCurrLegend";
|
||||||
|
|
||||||
const firstTabKey = SewerageFinanceInfoListRvw[0]?.tabKey ?? "ST00090001";
|
const firstTabKey = SewerageFinanceInfoListRvw[0]?.tabKey ?? "ST00090001";
|
||||||
|
|
||||||
|
|||||||
@@ -1,31 +1,30 @@
|
|||||||
import { useMemo,useState } from "react";
|
import { useState, useMemo } from "react";
|
||||||
|
|
||||||
import { useAlertStore, useUserStore } from "@/shared/lib";
|
|
||||||
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
|
||||||
import type {
|
|
||||||
ReviewerInfoRequest,
|
|
||||||
ReviewOpinionSaveRequest,
|
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
|
||||||
import type { SewerageSupplyRateReviewItem, statsStatusInfo } from "@/entities/statistics/model/statistics-sewerage-penetration-review-interface";
|
|
||||||
import { LoadingWithAnimation } from "@common/components";
|
|
||||||
|
|
||||||
import ReturnButton from "@/components/button/ReturnButton";
|
|
||||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
|
||||||
import SubmitButton from "@/components/button/SumitButton";
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
|
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||||
|
import ReturnButton from "@/components/button/ReturnButton";
|
||||||
|
import SubmitButton from "@/components/button/SumitButton";
|
||||||
|
import { LoadingWithAnimation } from "@common/components";
|
||||||
import { ReturnReasonDialog } from "@/components/statistics/review/ReturnReasonDialog";
|
import { ReturnReasonDialog } from "@/components/statistics/review/ReturnReasonDialog";
|
||||||
|
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
||||||
|
|
||||||
|
import { useAlertStore, useUserStore } from "@/shared/lib";
|
||||||
|
import { SeweragePenetrationRateInfoList } from "@/components/util/column/review/SeweragePenetrationRateRvwColumn";
|
||||||
|
import type { SewerageSupplyRateReviewItem, statsStatusInfo } from "@/entities/statistics/model/statistics-sewerage-penetration-review-interface";
|
||||||
|
import type {
|
||||||
|
ReviewOpinionSaveRequest,
|
||||||
|
ReviewerInfoRequest,
|
||||||
|
} from "@/entities/statistics/model/statistics-interface";
|
||||||
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
|
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
||||||
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
|
import { buildReviewCellStyleCallback } from "@/components/util/grid/reviewEmptyCurrCellStyle";
|
||||||
import ReviewEmptyCurrLegend from "@/components/statistics/review/ReviewEmptyCurrLegend";
|
import ReviewEmptyCurrLegend from "@/components/statistics/review/ReviewEmptyCurrLegend";
|
||||||
import {
|
import {
|
||||||
ReviewOpinionDialog,
|
ReviewOpinionDialog,
|
||||||
type ReviewOpinionDialogContext,
|
type ReviewOpinionDialogContext,
|
||||||
} from "@/components/statistics/review/ReviewOpinionDialog";
|
} from "@/components/statistics/review/ReviewOpinionDialog";
|
||||||
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
|
||||||
import { SeweragePenetrationRateInfoList } from "@/components/util/column/review/SeweragePenetrationRateRvwColumn";
|
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
|
||||||
import { buildReviewCellStyleCallback } from "@/components/util/grid/reviewEmptyCurrCellStyle";
|
|
||||||
|
|
||||||
// 하수도 통계 검토 01.하수도 보급률
|
// 하수도 통계 검토 01.하수도 보급률
|
||||||
const SeweragePenetrationRateRvw = () => {
|
const SeweragePenetrationRateRvw = () => {
|
||||||
|
|||||||
@@ -3,31 +3,30 @@ import { useMemo, useRef, useState } from "react";
|
|||||||
import { useAlertStore, useUserStore } from "@/shared/lib";
|
import { useAlertStore, useUserStore } from "@/shared/lib";
|
||||||
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
import type {
|
|
||||||
ReviewerInfoRequest,
|
|
||||||
ReviewOpinionSaveRequest,
|
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
|
||||||
import type { StatsStatusInfo } from "@/entities/statistics/model/statistics-sewage-pipe-review-interface";
|
|
||||||
import {
|
import {
|
||||||
extractSewerageServiceLevelReviewList,
|
extractSewerageServiceLevelReviewList,
|
||||||
extractSewerageServiceLevelReviewStatsStatusInfo,
|
extractSewerageServiceLevelReviewStatsStatusInfo,
|
||||||
mapSewerageServiceLevelReviewRows,
|
mapSewerageServiceLevelReviewRows,
|
||||||
type SewerageServiceLevelReviewRequestParams,
|
type SewerageServiceLevelReviewRequestParams,
|
||||||
} from "@/entities/statistics/model/statistics-sewerage-service-level-review-interface";
|
} from "@/entities/statistics/model/statistics-sewerage-service-level-review-interface";
|
||||||
|
import type { StatsStatusInfo } from "@/entities/statistics/model/statistics-sewage-pipe-review-interface";
|
||||||
|
import type {
|
||||||
|
ReviewerInfoRequest,
|
||||||
|
ReviewOpinionSaveRequest,
|
||||||
|
} from "@/entities/statistics/model/statistics-interface";
|
||||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||||
|
|
||||||
|
import SubmitButton from "@/components/button/SumitButton";
|
||||||
import ReturnButton from "@/components/button/ReturnButton";
|
import ReturnButton from "@/components/button/ReturnButton";
|
||||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||||
import SubmitButton from "@/components/button/SumitButton";
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
import { ReturnReasonDialog } from "@/components/statistics/review/ReturnReasonDialog";
|
import { ReturnReasonDialog } from "@/components/statistics/review/ReturnReasonDialog";
|
||||||
import ReviewEmptyCurrLegend from "@/components/statistics/review/ReviewEmptyCurrLegend";
|
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
||||||
import {
|
import {
|
||||||
ReviewOpinionDialog,
|
ReviewOpinionDialog,
|
||||||
type ReviewOpinionDialogContext,
|
type ReviewOpinionDialogContext,
|
||||||
} from "@/components/statistics/review/ReviewOpinionDialog";
|
} from "@/components/statistics/review/ReviewOpinionDialog";
|
||||||
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
|
||||||
import type {
|
import type {
|
||||||
ColumnConfig,
|
ColumnConfig,
|
||||||
ColumnInfo,
|
ColumnInfo,
|
||||||
@@ -37,6 +36,7 @@ import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
|||||||
import { SewerageServiceLevelInfoListRvw } from "@/components/util/column/review/SewerageServiceLevelRvwColumn";
|
import { SewerageServiceLevelInfoListRvw } from "@/components/util/column/review/SewerageServiceLevelRvwColumn";
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
import { buildReviewCellStyleCallbackByTab } from "@/components/util/grid/reviewEmptyCurrCellStyle";
|
import { buildReviewCellStyleCallbackByTab } from "@/components/util/grid/reviewEmptyCurrCellStyle";
|
||||||
|
import ReviewEmptyCurrLegend from "@/components/statistics/review/ReviewEmptyCurrLegend";
|
||||||
|
|
||||||
const firstTabKey = SewerageServiceLevelInfoListRvw[0]?.tabKey ?? "ST00130001";
|
const firstTabKey = SewerageServiceLevelInfoListRvw[0]?.tabKey ?? "ST00130001";
|
||||||
|
|
||||||
|
|||||||
@@ -1,41 +1,35 @@
|
|||||||
import { useCallback, useMemo, useState } from "react";
|
import { useCallback, useMemo, useState } from "react";
|
||||||
|
|
||||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||||
import { createColumnHelper, getCoreRowModel, useReactTable } from "@tanstack/react-table";
|
import { createColumnHelper, getCoreRowModel, useReactTable } from "@tanstack/react-table";
|
||||||
|
|
||||||
import { useAlertStore, useSearchConditionSidoList, useUserStore } from "@/shared/lib";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
import type { DataCellClickCallbackParams } from "@/components/type/DataGrid.type";
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
import type {
|
import ApproveButton from "@/components/button/ApproveButton";
|
||||||
ReviewHistoryResponse,
|
import { doList } from "@/components/util/column/input/DoList";
|
||||||
StatsInputStatusReviewItem,
|
|
||||||
} from "@/entities/statistics/model/statistics-input-review-interface";
|
|
||||||
import type {
|
|
||||||
ReviewerInfoRequest,
|
|
||||||
StatsInputStatusApproveItem,
|
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
|
||||||
import { isGugunOkForToolbar } from "@/entities/statistics";
|
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
DataTable,
|
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogFooter,
|
DialogFooter,
|
||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
LoadingWithAnimation} from "@common/components";
|
LoadingWithAnimation,
|
||||||
|
DataTable
|
||||||
|
} from "@common/components";
|
||||||
|
|
||||||
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
import { useAlertStore } from "@/shared/lib";
|
||||||
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
import ApproveButton from "@/components/button/ApproveButton";
|
import type { StatsInputStatusApproveItem } from "@/entities/statistics/model/statistics-interface";
|
||||||
import SubmitButton from "@/components/button/SumitButton";
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
|
||||||
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
|
||||||
import type { DataCellClickCallbackParams } from "@/components/type/DataGrid.type";
|
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
|
||||||
import { StatsInputStatusInfoList } from "@/components/util/column/review/StatsInputStatusRvwColumn";
|
import { StatsInputStatusInfoList } from "@/components/util/column/review/StatsInputStatusRvwColumn";
|
||||||
|
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
||||||
|
import type {
|
||||||
|
ReviewHistoryResponse,
|
||||||
|
StatsInputStatusReviewItem,
|
||||||
|
} from "@/entities/statistics/model/statistics-input-review-interface";
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
|
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
||||||
|
|
||||||
type ReviewHistoryRow = ReviewHistoryResponse["data"][number];
|
type ReviewHistoryRow = ReviewHistoryResponse["data"][number];
|
||||||
|
|
||||||
@@ -60,9 +54,7 @@ const mapSewerageListToGridRows = (rawList: StatsInputStatusReviewItem[]) =>
|
|||||||
|
|
||||||
// 하수도 통계 검토 00. 통계 입력 현황
|
// 하수도 통계 검토 00. 통계 입력 현황
|
||||||
const StatsInputStatusRvw = () => {
|
const StatsInputStatusRvw = () => {
|
||||||
const { sidoList } = useSearchConditionSidoList();
|
|
||||||
const { setMessage: alert } = useAlertStore((state) => state);
|
const { setMessage: alert } = useAlertStore((state) => state);
|
||||||
const userInfo = useUserStore((state) => state.userInfo);
|
|
||||||
const { confirm } = useConfirm();
|
const { confirm } = useConfirm();
|
||||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||||
const [historyRowData, setHistoryRowData] = useState<ReviewHistoryRow[]>([]);
|
const [historyRowData, setHistoryRowData] = useState<ReviewHistoryRow[]>([]);
|
||||||
@@ -71,7 +63,6 @@ const StatsInputStatusRvw = () => {
|
|||||||
const [searchedYear, setSearchedYear] = useState<string>("");
|
const [searchedYear, setSearchedYear] = useState<string>("");
|
||||||
const [lastSearchedValues, setLastSearchedValues] = useState<SearchFormValues | null>(null);
|
const [lastSearchedValues, setLastSearchedValues] = useState<SearchFormValues | null>(null);
|
||||||
const [hasCompletedSearch, setHasCompletedSearch] = useState(false);
|
const [hasCompletedSearch, setHasCompletedSearch] = useState(false);
|
||||||
const [submitDialogOpen, setSubmitDialogOpen] = useState(false);
|
|
||||||
const [reviewHistoryOpen, setReviewHistoryOpen] = useState<boolean>(false);
|
const [reviewHistoryOpen, setReviewHistoryOpen] = useState<boolean>(false);
|
||||||
const [historySearchInfo, setHistorySearchInfo] = useState<{
|
const [historySearchInfo, setHistorySearchInfo] = useState<{
|
||||||
ctpvNm: string;
|
ctpvNm: string;
|
||||||
@@ -121,7 +112,6 @@ const StatsInputStatusRvw = () => {
|
|||||||
setLastSearchedValues(null);
|
setLastSearchedValues(null);
|
||||||
setHasCompletedSearch(false);
|
setHasCompletedSearch(false);
|
||||||
setIsApproveLoading(false);
|
setIsApproveLoading(false);
|
||||||
setSubmitDialogOpen(false);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSearch = async (values: SearchFormValues) => {
|
const handleSearch = async (values: SearchFormValues) => {
|
||||||
@@ -233,7 +223,9 @@ const StatsInputStatusRvw = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const gugunOkOrNotDoList = isGugunOkForToolbar(sidoList, lastSearchedValues);
|
const gugunOkOrNotDoList = doList.includes(lastSearchedValues?.bsnmCd || "")
|
||||||
|
? Boolean(lastSearchedValues?.gugun && lastSearchedValues.gugun !== "ALL")
|
||||||
|
: true;
|
||||||
|
|
||||||
const allSubmitStatusApproved = useMemo(
|
const allSubmitStatusApproved = useMemo(
|
||||||
() =>
|
() =>
|
||||||
@@ -250,74 +242,13 @@ const StatsInputStatusRvw = () => {
|
|||||||
[rowData],
|
[rowData],
|
||||||
);
|
);
|
||||||
|
|
||||||
/** 진행상태(prvn) 코드가 모두 제출완료(2) */
|
const showActionToolbarCard =
|
||||||
const allPrvnStatusSubmitted = useMemo(
|
|
||||||
() =>
|
|
||||||
rowData.length > 0 &&
|
|
||||||
rowData.every((row) => String(row.prvnStatusCd ?? "") === "2"),
|
|
||||||
[rowData],
|
|
||||||
);
|
|
||||||
|
|
||||||
const showSubmitButton =
|
|
||||||
hasCompletedSearch &&
|
|
||||||
rowData.length > 0 &&
|
|
||||||
gugunOkOrNotDoList &&
|
|
||||||
!allPrvnStatusApproved &&
|
|
||||||
!allPrvnStatusSubmitted;
|
|
||||||
|
|
||||||
const showApproveButton =
|
|
||||||
hasCompletedSearch &&
|
hasCompletedSearch &&
|
||||||
rowData.length > 0 &&
|
rowData.length > 0 &&
|
||||||
gugunOkOrNotDoList &&
|
gugunOkOrNotDoList &&
|
||||||
allSubmitStatusApproved &&
|
allSubmitStatusApproved &&
|
||||||
!allPrvnStatusApproved;
|
!allPrvnStatusApproved;
|
||||||
|
|
||||||
const showActionToolbarCard = showSubmitButton || showApproveButton;
|
|
||||||
|
|
||||||
const submitDialogContext = useMemo<ReviewerInfoRequest | null>(() => {
|
|
||||||
if (lastSearchedValues == null) return null;
|
|
||||||
|
|
||||||
const statsYr = lastSearchedValues.year ?? "";
|
|
||||||
const sewerBzmnCd = lastSearchedValues.bsnmCd ?? "";
|
|
||||||
const instSeCd = userInfo?.instSeCd ?? "";
|
|
||||||
|
|
||||||
if (!statsYr || !sewerBzmnCd || !instSeCd) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
statsYr,
|
|
||||||
sewerBzmnCd,
|
|
||||||
instSeCd,
|
|
||||||
};
|
|
||||||
}, [lastSearchedValues, userInfo?.instSeCd]);
|
|
||||||
|
|
||||||
const submitFunc = () => {
|
|
||||||
if (submitDialogContext == null) {
|
|
||||||
alert("조회 후 제출할 수 있습니다.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setSubmitDialogOpen(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const refreshListAfterSubmit = async () => {
|
|
||||||
if (!lastSearchedValues) return;
|
|
||||||
try {
|
|
||||||
const listResponse = await statisticsManagementApi.getStatsInputStatusList({
|
|
||||||
ctpvNm: lastSearchedValues.sido,
|
|
||||||
sggNm: lastSearchedValues.gugun === "ALL" ? "" : lastSearchedValues.gugun,
|
|
||||||
statsYr: lastSearchedValues.year ?? "",
|
|
||||||
sewerBzmnCd: lastSearchedValues.bsnmCd,
|
|
||||||
});
|
|
||||||
if (listResponse.status === "success" && listResponse.data) {
|
|
||||||
const rawList = listResponse.data.sewerageInputList ?? [];
|
|
||||||
setRowData(toGridRows(mapSewerageListToGridRows(rawList)));
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
/* 목록 갱신 실패는 별도 안내 없이 생략 */
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const openReviewHistoryForRow = useCallback(
|
const openReviewHistoryForRow = useCallback(
|
||||||
async (row: Record<string, string | number>) => {
|
async (row: Record<string, string | number>) => {
|
||||||
if (!searchedYear) {
|
if (!searchedYear) {
|
||||||
@@ -366,10 +297,7 @@ const StatsInputStatusRvw = () => {
|
|||||||
{showActionToolbarCard && (
|
{showActionToolbarCard && (
|
||||||
<div className="card !py-0">
|
<div className="card !py-0">
|
||||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||||
{showSubmitButton && (
|
<ApproveButton approveFunc={approveFunc} />
|
||||||
<SubmitButton submitFunc={submitFunc} text="일괄 제출" />
|
|
||||||
)}
|
|
||||||
{showApproveButton && <ApproveButton approveFunc={approveFunc} />}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -429,13 +357,6 @@ const StatsInputStatusRvw = () => {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<ReviewSubmitDialog
|
|
||||||
open={submitDialogOpen}
|
|
||||||
onOpenChange={setSubmitDialogOpen}
|
|
||||||
context={submitDialogContext}
|
|
||||||
hideOpinionFields
|
|
||||||
onSubmitted={() => void refreshListAfterSubmit()}
|
|
||||||
/>
|
|
||||||
<Dialog open={reviewHistoryOpen} onOpenChange={setReviewHistoryOpen}>
|
<Dialog open={reviewHistoryOpen} onOpenChange={setReviewHistoryOpen}>
|
||||||
<DialogContent
|
<DialogContent
|
||||||
className="flex max-h-[85vh] max-w-[48rem] flex-col gap-4"
|
className="flex max-h-[85vh] max-w-[48rem] flex-col gap-4"
|
||||||
|
|||||||
@@ -3,36 +3,36 @@ import { useMemo, useRef, useState } from "react";
|
|||||||
import { useAlertStore, useUserStore } from "@/shared/lib";
|
import { useAlertStore, useUserStore } from "@/shared/lib";
|
||||||
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
||||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||||
import type {
|
|
||||||
ReviewerInfoRequest,
|
|
||||||
ReviewOpinionSaveRequest,
|
|
||||||
} from "@/entities/statistics/model/statistics-interface";
|
|
||||||
import type { StatsStatusInfo } from "@/entities/statistics/model/statistics-sewage-pipe-review-interface";
|
|
||||||
import {
|
import {
|
||||||
extractWaterReuseReviewList,
|
extractWaterReuseReviewList,
|
||||||
extractWaterReuseReviewStatsStatusInfo,
|
extractWaterReuseReviewStatsStatusInfo,
|
||||||
mapWaterReuseReviewRows,
|
mapWaterReuseReviewRows,
|
||||||
type WaterReuseReviewRequestParams,
|
type WaterReuseReviewRequestParams,
|
||||||
} from "@/entities/statistics/model/statistics-water-reuse-review-interface";
|
} from "@/entities/statistics/model/statistics-water-reuse-review-interface";
|
||||||
|
import type { StatsStatusInfo } from "@/entities/statistics/model/statistics-sewage-pipe-review-interface";
|
||||||
|
import type {
|
||||||
|
ReviewerInfoRequest,
|
||||||
|
ReviewOpinionSaveRequest,
|
||||||
|
} from "@/entities/statistics/model/statistics-interface";
|
||||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||||
|
|
||||||
|
import SubmitButton from "@/components/button/SumitButton";
|
||||||
import ReturnButton from "@/components/button/ReturnButton";
|
import ReturnButton from "@/components/button/ReturnButton";
|
||||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||||
import SubmitButton from "@/components/button/SumitButton";
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
import { ReturnReasonDialog } from "@/components/statistics/review/ReturnReasonDialog";
|
import { ReturnReasonDialog } from "@/components/statistics/review/ReturnReasonDialog";
|
||||||
import ReviewEmptyCurrLegend from "@/components/statistics/review/ReviewEmptyCurrLegend";
|
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
||||||
import {
|
import {
|
||||||
ReviewOpinionDialog,
|
ReviewOpinionDialog,
|
||||||
type ReviewOpinionDialogContext,
|
type ReviewOpinionDialogContext,
|
||||||
} from "@/components/statistics/review/ReviewOpinionDialog";
|
} from "@/components/statistics/review/ReviewOpinionDialog";
|
||||||
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
|
||||||
import type { ColumnConfig, ColumnInfo, ColumnInfoList } from "@/components/type/DataGrid.type";
|
import type { ColumnConfig, ColumnInfo, ColumnInfoList } from "@/components/type/DataGrid.type";
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
import { WaterReuseInfoListRvw } from "@/components/util/column/review/WaterReuseRvwColumn";
|
import { WaterReuseInfoListRvw } from "@/components/util/column/review/WaterReuseRvwColumn";
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
import { buildReviewCellStyleCallbackByTab } from "@/components/util/grid/reviewEmptyCurrCellStyle";
|
import { buildReviewCellStyleCallbackByTab } from "@/components/util/grid/reviewEmptyCurrCellStyle";
|
||||||
|
import ReviewEmptyCurrLegend from "@/components/statistics/review/ReviewEmptyCurrLegend";
|
||||||
|
|
||||||
const firstTabKey = WaterReuseInfoListRvw[0]?.tabKey ?? "ST00100001";
|
const firstTabKey = WaterReuseInfoListRvw[0]?.tabKey ?? "ST00100001";
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +1,24 @@
|
|||||||
import { useRef, useState } from "react";
|
import { useRef, useState } from "react";
|
||||||
|
|
||||||
import { useAlertStore } from "@/shared/lib";
|
import { useAlertStore } from "@/shared/lib";
|
||||||
|
import { LoadingWithAnimation } from "@common/components";
|
||||||
|
|
||||||
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
|
import type { ColumnInfo } from "@/components/type/DataGrid.type";
|
||||||
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
|
|
||||||
|
// 분리된 분뇨처리시설용 컬럼 구성 임포트
|
||||||
|
import { ExcretaTreatmentStatusColumnConfig } from "@/components/util/column/total/SewerExcretaTreatmentStatusColumn";
|
||||||
|
|
||||||
// 집계표(TOTAL) API 및 인터페이스 명세 호출
|
// 집계표(TOTAL) API 및 인터페이스 명세 호출
|
||||||
import { statisticsTotalStatusApi } from "@/entities/statistics/api/statistics-total-service";
|
import { statisticsTotalStatusApi } from "@/entities/statistics/api/statistics-total-service";
|
||||||
import type {
|
import type {
|
||||||
ExcretaTreatmentMaintainTotalRequest
|
ExcretaTreatmentMaintainTotalRequest
|
||||||
} from "@/entities/statistics/model/statistics-total/statistics-excreta-treatment-total-interface";
|
} from "@/entities/statistics/model/statistics-total/statistics-excreta-treatment-total-interface";
|
||||||
import { LoadingWithAnimation } from "@common/components";
|
|
||||||
|
|
||||||
import CellColorInfo from "./CellColorInfo";
|
import CellColorInfo from "./CellColorInfo";
|
||||||
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
|
||||||
import type { ColumnInfo } from "@/components/type/DataGrid.type";
|
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
|
||||||
// 분리된 분뇨처리시설용 컬럼 구성 임포트
|
|
||||||
import { ExcretaTreatmentStatusColumnConfig } from "@/components/util/column/total/SewerExcretaTreatmentStatusColumn";
|
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
|
||||||
|
|
||||||
const ExcretaTreatmentFacilityTot = () => {
|
const ExcretaTreatmentFacilityTot = () => {
|
||||||
const { setMessage: alert } = useAlertStore((state) => state);
|
const { setMessage: alert } = useAlertStore((state) => state);
|
||||||
|
|
||||||
@@ -83,7 +84,7 @@ const ExcretaTreatmentFacilityTot = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<SearchForm isDetail={true} isSummary={true} onSubmit={handleSearch} onReset={handleReset} sidoSelectText="전체" defaultRegionAll />
|
<SearchForm isDetail={true} isSummary={true} onSubmit={handleSearch} onReset={handleReset} sidoSelectText="전체" />
|
||||||
|
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
||||||
@@ -104,7 +105,6 @@ const ExcretaTreatmentFacilityTot = () => {
|
|||||||
setRowData={setRowData} // 필수 프로퍼티 에러 해결
|
setRowData={setRowData} // 필수 프로퍼티 에러 해결
|
||||||
isExcelImport={false}
|
isExcelImport={false}
|
||||||
isExcelExport={true}
|
isExcelExport={true}
|
||||||
excelExportApplyStyles
|
|
||||||
showHeaderCheckbox={false}
|
showHeaderCheckbox={false}
|
||||||
fixedColumns={config.fixedColumns}
|
fixedColumns={config.fixedColumns}
|
||||||
enableSort={false}
|
enableSort={false}
|
||||||
|
|||||||
@@ -1,25 +1,26 @@
|
|||||||
import { useRef, useState } from "react";
|
import { useRef, useState } from "react";
|
||||||
|
|
||||||
import { useAlertStore } from "@/shared/lib";
|
import { useAlertStore } from "@/shared/lib";
|
||||||
|
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||||
|
|
||||||
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
|
import type { ColumnInfo } from "@/components/type/DataGrid.type";
|
||||||
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
|
|
||||||
|
// 분리된 개별 3개 컬럼 스펙 파일 로드
|
||||||
|
import { PrivateSewageTab1ColumnConfig } from "@/components/util/column/total/sewerPrivateSewageColumn/SewerPrivateSewageTab1Column";
|
||||||
|
import { PrivateSewageTab2ColumnConfig } from "@/components/util/column/total/sewerPrivateSewageColumn/SewerPrivateSewageTab2Column";
|
||||||
|
import { PrivateSewageTab3ColumnConfig } from "@/components/util/column/total/sewerPrivateSewageColumn/SewerPrivateSewageTab3Column";
|
||||||
|
|
||||||
// 통계 API 서비스 및 통합 DTO 명세 임포트
|
// 통계 API 서비스 및 통합 DTO 명세 임포트
|
||||||
import { statisticsTotalStatusApi } from "@/entities/statistics/api/statistics-total-service";
|
import { statisticsTotalStatusApi } from "@/entities/statistics/api/statistics-total-service";
|
||||||
import type {
|
import type {
|
||||||
PrivateSewageFacilitySummaryRequest
|
PrivateSewageFacilitySummaryRequest
|
||||||
} from "@/entities/statistics/model/statistics-total/statistics-private-sewage-total-interface";
|
} from "@/entities/statistics/model/statistics-total/statistics-private-sewage-total-interface";
|
||||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
|
||||||
|
|
||||||
import CellColorInfo from "./CellColorInfo";
|
import CellColorInfo from "./CellColorInfo";
|
||||||
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
|
||||||
import type { ColumnInfo } from "@/components/type/DataGrid.type";
|
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
|
||||||
// 분리된 개별 3개 컬럼 스펙 파일 로드
|
|
||||||
import { PrivateSewageTab1ColumnConfig } from "@/components/util/column/total/sewerPrivateSewageColumn/SewerPrivateSewageTab1Column";
|
|
||||||
import { PrivateSewageTab2ColumnConfig } from "@/components/util/column/total/sewerPrivateSewageColumn/SewerPrivateSewageTab2Column";
|
|
||||||
import { PrivateSewageTab3ColumnConfig } from "@/components/util/column/total/sewerPrivateSewageColumn/SewerPrivateSewageTab3Column";
|
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
|
||||||
|
|
||||||
const PrivateSewageColumnListTot = [
|
const PrivateSewageColumnListTot = [
|
||||||
PrivateSewageTab1ColumnConfig,
|
PrivateSewageTab1ColumnConfig,
|
||||||
PrivateSewageTab2ColumnConfig,
|
PrivateSewageTab2ColumnConfig,
|
||||||
@@ -131,7 +132,7 @@ const PrivateSewageFacilityTot = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<SearchForm isDetail={true} isSummary={true} onSubmit={handleSearch} onReset={handleReset} sidoSelectText="전체" defaultRegionAll />
|
<SearchForm isDetail={true} isSummary={true} onSubmit={handleSearch} onReset={handleReset} sidoSelectText="전체" />
|
||||||
|
|
||||||
{/* 하수관로 규칙과 100% 싱크 맞춘 중앙 정렬 소형 팝업 로딩 바 고정 */}
|
{/* 하수관로 규칙과 100% 싱크 맞춘 중앙 정렬 소형 팝업 로딩 바 고정 */}
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
@@ -183,7 +184,6 @@ const PrivateSewageFacilityTot = () => {
|
|||||||
}}
|
}}
|
||||||
isExcelImport={false}
|
isExcelImport={false}
|
||||||
isExcelExport={true}
|
isExcelExport={true}
|
||||||
excelExportApplyStyles
|
|
||||||
showHeaderCheckbox={false}
|
showHeaderCheckbox={false}
|
||||||
fixedColumns={info.fixedColumns}
|
fixedColumns={info.fixedColumns}
|
||||||
enableSort={false}
|
enableSort={false}
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
import { useAlertStore } from "@/shared/lib";
|
|
||||||
import { statisticsTotalStatusApi } from "@/entities/statistics/api/statistics-total-service";
|
|
||||||
import { LoadingWithAnimation } from "@common/components";
|
|
||||||
|
|
||||||
import CellColorInfo from "./CellColorInfo";
|
|
||||||
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
import { PublicSewageFacilityColumn } from "@/components/util/column/total/PublicSewageFacilityColumn";
|
import { PublicSewageFacilityColumn } from "@/components/util/column/total/PublicSewageFacilityColumn";
|
||||||
|
import { statisticsTotalStatusApi } from "@/entities/statistics/api/statistics-total-service";
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
|
import { useAlertStore } from "@/shared/lib";
|
||||||
|
|
||||||
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
|
import CellColorInfo from "./CellColorInfo";
|
||||||
|
import { LoadingWithAnimation } from "@common/components";
|
||||||
|
|
||||||
const PublicSewageFacilityTot = () => {
|
const PublicSewageFacilityTot = () => {
|
||||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||||
@@ -53,7 +52,7 @@ const PublicSewageFacilityTot = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SearchForm isDetail={true} capacityGbn={true} isSummary={true} onSubmit={handleSearch} sidoSelectText="전체" defaultRegionAll />
|
<SearchForm isDetail={true} capacityGbn={true} isSummary={true} onSubmit={handleSearch} sidoSelectText="전체" />
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
||||||
<div className="relative size-[5rem]">
|
<div className="relative size-[5rem]">
|
||||||
@@ -66,7 +65,6 @@ const PublicSewageFacilityTot = () => {
|
|||||||
columnInfo={PublicSewageFacilityColumn}
|
columnInfo={PublicSewageFacilityColumn}
|
||||||
rowStartNum={2}
|
rowStartNum={2}
|
||||||
isExcelImport={false}
|
isExcelImport={false}
|
||||||
excelExportApplyStyles
|
|
||||||
fixedColumns={2}
|
fixedColumns={2}
|
||||||
rowData={rowData}
|
rowData={rowData}
|
||||||
setRowData={setRowData}
|
setRowData={setRowData}
|
||||||
|
|||||||
@@ -1,23 +1,24 @@
|
|||||||
import { useRef, useState } from "react";
|
import { useRef, useState } from "react";
|
||||||
|
|
||||||
import { useAlertStore } from "@/shared/lib";
|
import { useAlertStore } from "@/shared/lib";
|
||||||
|
import { LoadingWithAnimation } from "@common/components";
|
||||||
|
|
||||||
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
|
import type { ColumnInfo } from "@/components/type/DataGrid.type";
|
||||||
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
|
|
||||||
|
// 분리된 중계펌프장용 컬럼 구성 임포트
|
||||||
|
import { MediationPumpStatusColumnConfig } from "@/components/util/column/total/SewerMediationPumpStatusColumn";
|
||||||
|
|
||||||
// 집계표(TOTAL) API 및 인터페이스 명세 호출
|
// 집계표(TOTAL) API 및 인터페이스 명세 호출
|
||||||
import { statisticsTotalStatusApi } from "@/entities/statistics/api/statistics-total-service";
|
import { statisticsTotalStatusApi } from "@/entities/statistics/api/statistics-total-service";
|
||||||
import type {
|
import type {
|
||||||
MediationPumpMaintainTotalRequest
|
MediationPumpMaintainTotalRequest
|
||||||
} from "@/entities/statistics/model/statistics-total/statistics-mediation-pump-total-interface";
|
} from "@/entities/statistics/model/statistics-total/statistics-mediation-pump-total-interface";
|
||||||
import { LoadingWithAnimation } from "@common/components";
|
|
||||||
|
|
||||||
import CellColorInfo from "./CellColorInfo";
|
import CellColorInfo from "./CellColorInfo";
|
||||||
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
|
||||||
import type { ColumnInfo } from "@/components/type/DataGrid.type";
|
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
|
||||||
// 분리된 중계펌프장용 컬럼 구성 임포트
|
|
||||||
import { MediationPumpStatusColumnConfig } from "@/components/util/column/total/SewerMediationPumpStatusColumn";
|
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
|
||||||
|
|
||||||
const PumpingStationTot = () => {
|
const PumpingStationTot = () => {
|
||||||
const { setMessage: alert } = useAlertStore((state) => state);
|
const { setMessage: alert } = useAlertStore((state) => state);
|
||||||
|
|
||||||
@@ -83,7 +84,7 @@ const PumpingStationTot = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<SearchForm isDetail={true} isSummary={true} onSubmit={handleSearch} onReset={handleReset} sidoSelectText="전체" defaultRegionAll />
|
<SearchForm isDetail={true} isSummary={true} onSubmit={handleSearch} onReset={handleReset} sidoSelectText="전체" />
|
||||||
|
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
||||||
@@ -104,7 +105,6 @@ const PumpingStationTot = () => {
|
|||||||
setRowData={setRowData}
|
setRowData={setRowData}
|
||||||
isExcelImport={false}
|
isExcelImport={false}
|
||||||
isExcelExport={true}
|
isExcelExport={true}
|
||||||
excelExportApplyStyles
|
|
||||||
showHeaderCheckbox={false}
|
showHeaderCheckbox={false}
|
||||||
fixedColumns={config.fixedColumns}
|
fixedColumns={config.fixedColumns}
|
||||||
enableSort={false}
|
enableSort={false}
|
||||||
|
|||||||
@@ -1,26 +1,25 @@
|
|||||||
import { useRef, useState } from "react";
|
import { useRef, useState } from "react";
|
||||||
|
|
||||||
import { useAlertStore } from "@/shared/lib";
|
import { useAlertStore } from "@/shared/lib";
|
||||||
import { statisticsTotalStatusApi } from "@/entities/statistics/api/statistics-total-service";
|
|
||||||
import type {
|
|
||||||
HumanWasteCollectionTab3Response,
|
|
||||||
IndividualSewageTab4Response,
|
|
||||||
PublicHumanWasteStaffTab2Response,
|
|
||||||
PublicSewageStaffTab1Response,
|
|
||||||
SewerageIndustry} from "@/entities/statistics/model/statistics-total/statistics-sewerage-industry-interface";
|
|
||||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||||
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
import CellColorInfo from "./CellColorInfo";
|
import CellColorInfo from "./CellColorInfo";
|
||||||
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
|
||||||
import { HumanWasteCollectionTab3ColumnConfig } from "@/components/util/column/total/sewageExcretaIndustry/HumanWasteCollectionTab3Column";
|
|
||||||
import { IndividualSewageTab4ColumnConfig } from "@/components/util/column/total/sewageExcretaIndustry/IndividualSewageTab4Column";
|
|
||||||
import { PublicHumanWasteStaffTab2ColumnConfig } from "@/components/util/column/total/sewageExcretaIndustry/PublicHumanWasteStaffTab2Column";
|
|
||||||
// 12. 하수 및 분뇨 관리 산업 탭 설정 (경로 확인 필수)
|
// 12. 하수 및 분뇨 관리 산업 탭 설정 (경로 확인 필수)
|
||||||
import { PublicSewageStaffTab1ColumnConfig } from "@/components/util/column/total/sewageExcretaIndustry/PublicSewageStaffTab1Column";
|
import { PublicSewageStaffTab1ColumnConfig } from "@/components/util/column/total/sewageExcretaIndustry/PublicSewageStaffTab1Column";
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { PublicHumanWasteStaffTab2ColumnConfig } from "@/components/util/column/total/sewageExcretaIndustry/PublicHumanWasteStaffTab2Column";
|
||||||
|
import { HumanWasteCollectionTab3ColumnConfig } from "@/components/util/column/total/sewageExcretaIndustry/HumanWasteCollectionTab3Column";
|
||||||
|
import { IndividualSewageTab4ColumnConfig } from "@/components/util/column/total/sewageExcretaIndustry/IndividualSewageTab4Column";
|
||||||
|
import { statisticsTotalStatusApi } from "@/entities/statistics/api/statistics-total-service";
|
||||||
|
import type {
|
||||||
|
SewerageIndustry,
|
||||||
|
PublicSewageStaffTab1Response,
|
||||||
|
PublicHumanWasteStaffTab2Response,
|
||||||
|
HumanWasteCollectionTab3Response,
|
||||||
|
IndividualSewageTab4Response
|
||||||
|
} from "@/entities/statistics/model/statistics-total/statistics-sewerage-industry-interface";
|
||||||
|
|
||||||
const SewageExcretaIndustryColumnListTot = [PublicSewageStaffTab1ColumnConfig,PublicHumanWasteStaffTab2ColumnConfig,HumanWasteCollectionTab3ColumnConfig,IndividualSewageTab4ColumnConfig].filter(Boolean);
|
const SewageExcretaIndustryColumnListTot = [PublicSewageStaffTab1ColumnConfig,PublicHumanWasteStaffTab2ColumnConfig,HumanWasteCollectionTab3ColumnConfig,IndividualSewageTab4ColumnConfig].filter(Boolean);
|
||||||
const firstTabKey = SewageExcretaIndustryColumnListTot[0]?.tabKey ?? "ST00120001";
|
const firstTabKey = SewageExcretaIndustryColumnListTot[0]?.tabKey ?? "ST00120001";
|
||||||
@@ -103,7 +102,7 @@ const SewageExcretaRelatedTot = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<SearchForm isDetail={true} isSummary={true} onSubmit={handleSearch} onReset={handleReset} sidoSelectText="전체" defaultRegionAll />
|
<SearchForm isDetail={true} isSummary={true} onSubmit={handleSearch} onReset={handleReset} sidoSelectText="전체" />
|
||||||
|
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
||||||
@@ -141,7 +140,6 @@ const SewageExcretaRelatedTot = () => {
|
|||||||
}}
|
}}
|
||||||
isExcelImport={false}
|
isExcelImport={false}
|
||||||
isExcelExport={true}
|
isExcelExport={true}
|
||||||
excelExportApplyStyles
|
|
||||||
showHeaderCheckbox={false}
|
showHeaderCheckbox={false}
|
||||||
fixedColumns={info.fixedColumns}
|
fixedColumns={info.fixedColumns}
|
||||||
enableSort={false}
|
enableSort={false}
|
||||||
|
|||||||
@@ -1,28 +1,30 @@
|
|||||||
import { useRef, useState } from "react";
|
import { useRef, useState } from "react";
|
||||||
|
|
||||||
import { useAlertStore } from "@/shared/lib";
|
import { useAlertStore } from "@/shared/lib";
|
||||||
|
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||||
|
|
||||||
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
|
|
||||||
|
// 4개 탭 컬럼 설정 임포트
|
||||||
|
import { SludgeProcessingTab1ColumnConfig } from "@/components/util/column/total/sludgeProcessing/SludgeProcessingTab1Column";
|
||||||
|
import { DigestionTankTab2ColumnConfig } from "@/components/util/column/total/sludgeProcessing/DigestionTankTab2Column";
|
||||||
|
import { SewageSludgeOperTab3ColumnConfig } from "@/components/util/column/total/sludgeProcessing/SewageSludgeOperTab3Column";
|
||||||
|
import { HumanWasteSludgeTab4ColumnConfig } from "@/components/util/column/total/sludgeProcessing/HumanWasteSludgeTab4Column";
|
||||||
|
|
||||||
// API 인스턴스 및 인터페이스 임포트 (타입 안전성 확보)
|
// API 인스턴스 및 인터페이스 임포트 (타입 안전성 확보)
|
||||||
import { statisticsTotalStatusApi } from "@/entities/statistics/api/statistics-total-service";
|
import { statisticsTotalStatusApi } from "@/entities/statistics/api/statistics-total-service";
|
||||||
import type {
|
import type {
|
||||||
DigestionTankOperTab2Response,
|
SludgeSummaryRequest,
|
||||||
HumanWasteSludgeTab4Response,
|
|
||||||
SewageSludgeOperTab3Response,
|
|
||||||
SludgeProcessingTab1Response,
|
SludgeProcessingTab1Response,
|
||||||
SludgeSummaryRequest} from "@/entities/statistics/model/statistics-total/statistics-sludge-total-interface";
|
DigestionTankOperTab2Response,
|
||||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
SewageSludgeOperTab3Response,
|
||||||
|
HumanWasteSludgeTab4Response
|
||||||
|
} from "@/entities/statistics/model/statistics-total/statistics-sludge-total-interface";
|
||||||
import CellColorInfo from "./CellColorInfo";
|
import CellColorInfo from "./CellColorInfo";
|
||||||
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
|
||||||
import { DigestionTankTab2ColumnConfig } from "@/components/util/column/total/sludgeProcessing/DigestionTankTab2Column";
|
|
||||||
import { HumanWasteSludgeTab4ColumnConfig } from "@/components/util/column/total/sludgeProcessing/HumanWasteSludgeTab4Column";
|
|
||||||
import { SewageSludgeOperTab3ColumnConfig } from "@/components/util/column/total/sludgeProcessing/SewageSludgeOperTab3Column";
|
|
||||||
// 4개 탭 컬럼 설정 임포트
|
|
||||||
import { SludgeProcessingTab1ColumnConfig } from "@/components/util/column/total/sludgeProcessing/SludgeProcessingTab1Column";
|
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
|
||||||
|
|
||||||
// 탭 순회 설정
|
// 탭 순회 설정
|
||||||
const SludgeColumnListTot = [
|
const SludgeColumnListTot = [
|
||||||
SludgeProcessingTab1ColumnConfig,
|
SludgeProcessingTab1ColumnConfig,
|
||||||
@@ -144,7 +146,7 @@ const loadGridData = async (tabKey: string, values: SearchFormValues): Promise<b
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<SearchForm isDetail={true} isSummary={true} onSubmit={handleSearch} onReset={handleReset} sidoSelectText="전체" defaultRegionAll />
|
<SearchForm isDetail={true} isSummary={true} onSubmit={handleSearch} onReset={handleReset} sidoSelectText="전체" />
|
||||||
|
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
||||||
@@ -186,7 +188,6 @@ const loadGridData = async (tabKey: string, values: SearchFormValues): Promise<b
|
|||||||
}}
|
}}
|
||||||
isExcelImport={false}
|
isExcelImport={false}
|
||||||
isExcelExport={true}
|
isExcelExport={true}
|
||||||
excelExportApplyStyles
|
|
||||||
showHeaderCheckbox={false}
|
showHeaderCheckbox={false}
|
||||||
fixedColumns={info.fixedColumns}
|
fixedColumns={info.fixedColumns}
|
||||||
enableSort={false}
|
enableSort={false}
|
||||||
|
|||||||
@@ -2,15 +2,15 @@ import { useRef, useState } from "react";
|
|||||||
|
|
||||||
import { useAlertStore } from "@/shared/lib";
|
import { useAlertStore } from "@/shared/lib";
|
||||||
import { statisticsTotalStatusApi } from "@/entities/statistics/api/statistics-total-service";
|
import { statisticsTotalStatusApi } from "@/entities/statistics/api/statistics-total-service";
|
||||||
import type { SewagePipeMaintainTotalRequest } from "@/entities/statistics/model/statistics-total/statistics-sewage-pipe-maintain-total-interface";
|
|
||||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||||
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
import type { ColumnInfo } from "@/components/type/DataGrid.type";
|
import type { ColumnInfo } from "@/components/type/DataGrid.type";
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
import { SewagePipeMaintainColumnListTot } from "@/components/util/column/total/sewagePipeMaintain/sewagePipeMaintainColumn";
|
import { SewagePipeMaintainColumnListTot } from "@/components/util/column/total/sewagePipeMaintain/sewagePipeMaintainColumn";
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
|
import type { SewagePipeMaintainTotalRequest } from "@/entities/statistics/model/statistics-total/statistics-sewage-pipe-maintain-total-interface";
|
||||||
|
|
||||||
const firstTabKey = SewagePipeMaintainColumnListTot[0]?.tabKey ?? "ST00030001";
|
const firstTabKey = SewagePipeMaintainColumnListTot[0]?.tabKey ?? "ST00030001";
|
||||||
|
|
||||||
@@ -133,7 +133,7 @@ const SewagePipeMaintainTot = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<SearchForm isDetail={true} isSummary={true} onSubmit={handleSearch} onReset={handleReset} sidoSelectText="전체" defaultRegionAll />
|
<SearchForm isDetail={true} isSummary={true} onSubmit={handleSearch} onReset={handleReset} sidoSelectText="전체" />
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
||||||
<div className="relative size-[5rem]">
|
<div className="relative size-[5rem]">
|
||||||
@@ -186,7 +186,6 @@ const SewagePipeMaintainTot = () => {
|
|||||||
}}
|
}}
|
||||||
isExcelImport={false}
|
isExcelImport={false}
|
||||||
isExcelExport
|
isExcelExport
|
||||||
excelExportApplyStyles
|
|
||||||
showHeaderCheckbox={false}
|
showHeaderCheckbox={false}
|
||||||
fixedColumns={info.fixedColumns}
|
fixedColumns={info.fixedColumns}
|
||||||
enableSort={false}
|
enableSort={false}
|
||||||
|
|||||||
@@ -2,17 +2,16 @@ import { useRef, useState } from "react";
|
|||||||
|
|
||||||
import { useAlertStore } from "@/shared/lib";
|
import { useAlertStore } from "@/shared/lib";
|
||||||
import { statisticsTotalStatusApi } from "@/entities/statistics/api/statistics-total-service";
|
import { statisticsTotalStatusApi } from "@/entities/statistics/api/statistics-total-service";
|
||||||
import type { SewagePipeTotalRequest } from "@/entities/statistics/model/statistics-total/statistics-sewage-pipe-total-interface";
|
|
||||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||||
|
|
||||||
import CellColorInfo from "./CellColorInfo";
|
|
||||||
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
import type { ColumnInfo } from "@/components/type/DataGrid.type";
|
import type { ColumnInfo } from "@/components/type/DataGrid.type";
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
import { getST00020003Config, SewagePipeColumnInfoListTot } from "@/components/util/column/total/SewagePipeTotColumn";
|
import { SewagePipeColumnInfoListTot, getST00020003Config } from "@/components/util/column/total/SewagePipeTotColumn";
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
|
import type { SewagePipeTotalRequest } from "@/entities/statistics/model/statistics-total/statistics-sewage-pipe-total-interface";
|
||||||
|
import CellColorInfo from "./CellColorInfo";
|
||||||
|
|
||||||
const firstTabKey = SewagePipeColumnInfoListTot[0]?.tabKey ?? "ST00020001";
|
const firstTabKey = SewagePipeColumnInfoListTot[0]?.tabKey ?? "ST00020001";
|
||||||
|
|
||||||
@@ -179,7 +178,7 @@ const SewagePipeTot = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<SearchForm isDetail={true} isSummary={true} onSubmit={handleSearch} onReset={handleReset} sidoSelectText="전체" defaultRegionAll />
|
<SearchForm isDetail={true} isSummary={true} onSubmit={handleSearch} onReset={handleReset} sidoSelectText="전체" />
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
||||||
<div className="relative size-[5rem]">
|
<div className="relative size-[5rem]">
|
||||||
@@ -205,10 +204,11 @@ const SewagePipeTot = () => {
|
|||||||
{columnInfo.map((info) => {
|
{columnInfo.map((info) => {
|
||||||
const tabKey = info.tabKey;
|
const tabKey = info.tabKey;
|
||||||
|
|
||||||
// ★ [동적 처리] ST00020003은 함수를 통해 컬럼 정보를 실시간으로 생성
|
// ★ [동적 처리] ST00020003인 경우 함수를 통해 컬럼 정보를 실시간으로 생성
|
||||||
const currentYear = lastSearchedValuesRef.current?.year || new Date().getFullYear();
|
const currentYear = lastSearchedValuesRef.current?.year || new Date().getFullYear();
|
||||||
const finalTabConfig =
|
const finalTabConfig = tabKey === "ST00020003"
|
||||||
tabKey === "ST00020003" ? getST00020003Config(currentYear) : info;
|
? getST00020003Config(currentYear)
|
||||||
|
: info;
|
||||||
|
|
||||||
if (!finalTabConfig.columns || !finalTabConfig.columnLayout) {
|
if (!finalTabConfig.columns || !finalTabConfig.columnLayout) {
|
||||||
return null;
|
return null;
|
||||||
@@ -239,7 +239,6 @@ const SewagePipeTot = () => {
|
|||||||
}}
|
}}
|
||||||
isExcelImport={false}
|
isExcelImport={false}
|
||||||
isExcelExport
|
isExcelExport
|
||||||
excelExportApplyStyles
|
|
||||||
showHeaderCheckbox={false}
|
showHeaderCheckbox={false}
|
||||||
fixedColumns={finalTabConfig.fixedColumns}
|
fixedColumns={finalTabConfig.fixedColumns}
|
||||||
enableSort={false}
|
enableSort={false}
|
||||||
|
|||||||
@@ -1,24 +1,25 @@
|
|||||||
import { useRef, useState } from "react";
|
import { useRef, useState } from "react";
|
||||||
|
|
||||||
import { useAlertStore } from "@/shared/lib";
|
import { useAlertStore } from "@/shared/lib";
|
||||||
|
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||||
|
|
||||||
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
|
import type { ColumnInfo } from "@/components/type/DataGrid.type";
|
||||||
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
|
|
||||||
|
// 분리된 개별 컬럼 구성 임포트 경로 유지
|
||||||
|
import { ReservoirStatusColumnConfig } from "@/components/util/column/total/sewerReservoir/SewerReservoirStatusColumn";
|
||||||
|
import { PumpStationStatusColumnConfig } from "@/components/util/column/total/sewerReservoir/SewerPumpStationStatusColumn";
|
||||||
|
|
||||||
// 수정 적용한 API 및 인터페이스 명세 호출 유지
|
// 수정 적용한 API 및 인터페이스 명세 호출 유지
|
||||||
import { statisticsTotalStatusApi } from "@/entities/statistics/api/statistics-total-service";
|
import { statisticsTotalStatusApi } from "@/entities/statistics/api/statistics-total-service";
|
||||||
import type {
|
import type {
|
||||||
SewerReservoirMaintainTotalRequest
|
SewerReservoirMaintainTotalRequest
|
||||||
} from "@/entities/statistics/model/statistics-total/statistics-sewage-reservoir-total-interface";
|
} from "@/entities/statistics/model/statistics-total/statistics-sewage-reservoir-total-interface";
|
||||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
|
||||||
|
|
||||||
import CellColorInfo from "./CellColorInfo";
|
import CellColorInfo from "./CellColorInfo";
|
||||||
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
|
||||||
import type { ColumnInfo } from "@/components/type/DataGrid.type";
|
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
|
||||||
import { PumpStationStatusColumnConfig } from "@/components/util/column/total/sewerReservoir/SewerPumpStationStatusColumn";
|
|
||||||
// 분리된 개별 컬럼 구성 임포트 경로 유지
|
|
||||||
import { ReservoirStatusColumnConfig } from "@/components/util/column/total/sewerReservoir/SewerReservoirStatusColumn";
|
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
|
||||||
|
|
||||||
const SewerReservoirColumnListTot = [
|
const SewerReservoirColumnListTot = [
|
||||||
ReservoirStatusColumnConfig,
|
ReservoirStatusColumnConfig,
|
||||||
PumpStationStatusColumnConfig
|
PumpStationStatusColumnConfig
|
||||||
@@ -117,7 +118,7 @@ const SewageReservoirPumpTot = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<SearchForm isDetail={true} isSummary={true} onSubmit={handleSearch} onReset={handleReset} sidoSelectText="전체" defaultRegionAll />
|
<SearchForm isDetail={true} isSummary={true} onSubmit={handleSearch} onReset={handleReset} sidoSelectText="전체" />
|
||||||
|
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
||||||
@@ -167,7 +168,6 @@ const SewageReservoirPumpTot = () => {
|
|||||||
}}
|
}}
|
||||||
isExcelImport={false}
|
isExcelImport={false}
|
||||||
isExcelExport={true}
|
isExcelExport={true}
|
||||||
excelExportApplyStyles
|
|
||||||
showHeaderCheckbox={false}
|
showHeaderCheckbox={false}
|
||||||
fixedColumns={info.fixedColumns}
|
fixedColumns={info.fixedColumns}
|
||||||
enableSort={false}
|
enableSort={false}
|
||||||
|
|||||||
@@ -199,7 +199,6 @@ const SewerageAggregateSummary = () => {
|
|||||||
<SearchForm
|
<SearchForm
|
||||||
isSummary={true}
|
isSummary={true}
|
||||||
sidoSelectText="전체"
|
sidoSelectText="전체"
|
||||||
defaultRegionAll
|
|
||||||
searchButtonText="내려받기"
|
searchButtonText="내려받기"
|
||||||
onSubmit={(values) => void handleDownload(values)}
|
onSubmit={(values) => void handleDownload(values)}
|
||||||
isReset={false}
|
isReset={false}
|
||||||
|
|||||||
@@ -1,26 +1,27 @@
|
|||||||
import { useRef, useState } from "react";
|
import { useRef, useState } from "react";
|
||||||
|
|
||||||
import { useAlertStore } from "@/shared/lib";
|
import { useAlertStore } from "@/shared/lib";
|
||||||
|
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||||
|
|
||||||
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
|
import type { ColumnInfo } from "@/components/type/DataGrid.type";
|
||||||
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
|
|
||||||
|
// 분리된 4개 개별 탭 컬럼 파일 바인딩
|
||||||
|
import { SewerageFinancialTab1ColumnConfig } from "@/components/util/column/total/sewerageFinancial/SewerageFinancialTab1Column";
|
||||||
|
import { SewerageFeeTab2ColumnConfig } from "@/components/util/column/total/sewerageFinancial/SewerageFeeTab2Column";
|
||||||
|
import { SewerageUsageFeeTab3ColumnConfig } from "@/components/util/column/total/sewerageFinancial/SewerageUsageFeeTab3Column";
|
||||||
|
import { SewerageOrgCauseTab4ColumnConfig } from "@/components/util/column/total/sewerageFinancial/SewerageOrgCauseTab4Column";
|
||||||
|
|
||||||
// API 인스턴스 및 인터페이스 호출
|
// API 인스턴스 및 인터페이스 호출
|
||||||
import { statisticsTotalStatusApi } from "@/entities/statistics/api/statistics-total-service";
|
import { statisticsTotalStatusApi } from "@/entities/statistics/api/statistics-total-service";
|
||||||
import type {
|
import type {
|
||||||
SewerageFinanceSummaryRequest
|
SewerageFinanceSummaryRequest
|
||||||
} from "@/entities/statistics/model/statistics-total/statistics-sewerage-finance-total-interface";
|
} from "@/entities/statistics/model/statistics-total/statistics-sewerage-finance-total-interface";
|
||||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
|
||||||
|
|
||||||
import CellColorInfo from "./CellColorInfo";
|
import CellColorInfo from "./CellColorInfo";
|
||||||
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
|
||||||
import type { ColumnInfo } from "@/components/type/DataGrid.type";
|
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
|
||||||
import { SewerageFeeTab2ColumnConfig } from "@/components/util/column/total/sewerageFinancial/SewerageFeeTab2Column";
|
|
||||||
// 분리된 4개 개별 탭 컬럼 파일 바인딩
|
|
||||||
import { SewerageFinancialTab1ColumnConfig } from "@/components/util/column/total/sewerageFinancial/SewerageFinancialTab1Column";
|
|
||||||
import { SewerageOrgCauseTab4ColumnConfig } from "@/components/util/column/total/sewerageFinancial/SewerageOrgCauseTab4Column";
|
|
||||||
import { SewerageUsageFeeTab3ColumnConfig } from "@/components/util/column/total/sewerageFinancial/SewerageUsageFeeTab3Column";
|
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
|
||||||
|
|
||||||
const SewerageFinanceColumnListTot = [
|
const SewerageFinanceColumnListTot = [
|
||||||
SewerageFinancialTab1ColumnConfig,
|
SewerageFinancialTab1ColumnConfig,
|
||||||
SewerageFeeTab2ColumnConfig,
|
SewerageFeeTab2ColumnConfig,
|
||||||
@@ -143,7 +144,7 @@ const SewerageFinanceTot = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<SearchForm isDetail={true} isSummary={true} onSubmit={handleSearch} onReset={handleReset} sidoSelectText="전체" defaultRegionAll />
|
<SearchForm isDetail={true} isSummary={true} onSubmit={handleSearch} onReset={handleReset} sidoSelectText="전체" />
|
||||||
|
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
||||||
@@ -194,7 +195,6 @@ const SewerageFinanceTot = () => {
|
|||||||
}}
|
}}
|
||||||
isExcelImport={false}
|
isExcelImport={false}
|
||||||
isExcelExport={true}
|
isExcelExport={true}
|
||||||
excelExportApplyStyles
|
|
||||||
showHeaderCheckbox={false}
|
showHeaderCheckbox={false}
|
||||||
fixedColumns={info.fixedColumns}
|
fixedColumns={info.fixedColumns}
|
||||||
enableSort={false}
|
enableSort={false}
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
import { useAlertStore } from "@/shared/lib";
|
|
||||||
import { statisticsTotalStatusApi } from "@/entities/statistics/api/statistics-total-service";
|
|
||||||
import { LoadingWithAnimation } from "@common/components";
|
|
||||||
|
|
||||||
import CellColorInfo from "./CellColorInfo";
|
|
||||||
|
|
||||||
import DataGrid from "@/components/module/DataGrid";
|
|
||||||
import SearchForm from "@/components/module/SearchForm";
|
|
||||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||||
import { SeweragePentrationRateTotColumn } from "@/components/util/column/total/SeweragePentrationRateTotColumn";
|
import { SeweragePentrationRateTotColumn } from "@/components/util/column/total/SeweragePentrationRateTotColumn";
|
||||||
|
import { statisticsTotalStatusApi } from "@/entities/statistics/api/statistics-total-service";
|
||||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||||
|
import { useAlertStore } from "@/shared/lib";
|
||||||
|
|
||||||
|
import SearchForm from "@/components/module/SearchForm";
|
||||||
|
import DataGrid from "@/components/module/DataGrid";
|
||||||
|
import CellColorInfo from "./CellColorInfo";
|
||||||
|
import { LoadingWithAnimation } from "@common/components";
|
||||||
|
|
||||||
const SeweragePenetrationRateTot = () => {
|
const SeweragePenetrationRateTot = () => {
|
||||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||||
@@ -52,7 +51,7 @@ const SeweragePenetrationRateTot = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SearchForm isDetail={true} isSummary={true} onSubmit={handleSearch} sidoSelectText="전체" defaultRegionAll />
|
<SearchForm isDetail={true} isSummary={true} onSubmit={handleSearch} sidoSelectText="전체" />
|
||||||
{isLoading && <div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
{isLoading && <div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
||||||
<div className="relative size-[5rem]">
|
<div className="relative size-[5rem]">
|
||||||
<LoadingWithAnimation color="primary" />
|
<LoadingWithAnimation color="primary" />
|
||||||
@@ -63,7 +62,6 @@ const SeweragePenetrationRateTot = () => {
|
|||||||
columnInfo={SeweragePentrationRateTotColumn}
|
columnInfo={SeweragePentrationRateTotColumn}
|
||||||
rowStartNum={2}
|
rowStartNum={2}
|
||||||
isExcelImport={false}
|
isExcelImport={false}
|
||||||
excelExportApplyStyles
|
|
||||||
fixedColumns={1}
|
fixedColumns={1}
|
||||||
rowData={rowData}
|
rowData={rowData}
|
||||||
setRowData={setRowData}
|
setRowData={setRowData}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user