Merge branch 'iipbs/st/dev'
This commit is contained in:
@@ -29,6 +29,13 @@
|
||||
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-verify-error-imr {
|
||||
@apply !bg-[#fff7bf] !text-[#b45309];
|
||||
}
|
||||
/* 검증결과 내역: 처리여부(prcsYn 0·4 미처리 등) */
|
||||
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-vrf-prcs-bad {
|
||||
@apply !font-semibold !text-[#dc2626];
|
||||
}
|
||||
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-vrf-prcs-ok {
|
||||
@apply !font-semibold !text-[#3372cf];
|
||||
}
|
||||
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-total {
|
||||
@apply !bg-[#e3eaf2];
|
||||
}
|
||||
@@ -95,6 +102,12 @@
|
||||
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell {
|
||||
@apply !bg-[#545556] !text-[#fff];
|
||||
}
|
||||
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-vrf-prcs-bad {
|
||||
@apply !text-[#f87171];
|
||||
}
|
||||
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-vrf-prcs-ok {
|
||||
@apply !text-[#3372cf];
|
||||
}
|
||||
}
|
||||
|
||||
[data-theme="red"] {
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
|
||||
import {
|
||||
defaultSearchFormProps,
|
||||
type SearchFormClsfCd,
|
||||
type SearchFormProps,
|
||||
type SearchFormValues,
|
||||
} from "../type/SearchForm.type";
|
||||
@@ -81,6 +82,12 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
||||
},
|
||||
);
|
||||
|
||||
const initialClsfCd: SearchFormClsfCd = (() => {
|
||||
const d = props.defaultValues?.clsfCd;
|
||||
if (d === "ALL" || d === "INPT" || d === "VRFC") return d;
|
||||
return "ALL";
|
||||
})();
|
||||
|
||||
const [values, setValues] = useState<SearchFormValues>({
|
||||
sido: props.defaultValues?.sido || "",
|
||||
gugun: props.defaultValues?.gugun || "",
|
||||
@@ -90,6 +97,7 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
||||
bsnmCd: props.defaultValues?.bsnmCd || "",
|
||||
isDetail: false,
|
||||
isSummary: props.defaultValues?.isSummary || "",
|
||||
clsfCd: initialClsfCd,
|
||||
});
|
||||
|
||||
const sggKey: [string, string, string, string] | null =
|
||||
@@ -134,6 +142,7 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
||||
bsnmCd: "",
|
||||
isDetail: false,
|
||||
isSummary: "",
|
||||
clsfCd: "ALL",
|
||||
};
|
||||
setValues(resetValues);
|
||||
props.onReset?.();
|
||||
@@ -250,6 +259,29 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
||||
</Select>
|
||||
</div>
|
||||
)}
|
||||
{mergedProps.clsf && (
|
||||
<div className="flex items-center gap-2">
|
||||
<Label className="text-label">분류</Label>
|
||||
<Select
|
||||
value={values.clsfCd ?? "ALL"}
|
||||
onValueChange={(value) =>
|
||||
setValues({
|
||||
...values,
|
||||
clsfCd: value as SearchFormClsfCd,
|
||||
})
|
||||
}
|
||||
>
|
||||
<SelectTrigger className="w-[10rem]">
|
||||
<SelectValue placeholder="선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="ALL">전체</SelectItem>
|
||||
<SelectItem value="INPT">입력</SelectItem>
|
||||
<SelectItem value="VRFC">검증</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
)}
|
||||
{mergedProps.fctName && (
|
||||
<div className="flex items-center gap-2">
|
||||
<Label
|
||||
|
||||
@@ -14,6 +14,8 @@ const SplitDataGrid = ({
|
||||
setRightRowData,
|
||||
leftOnRowClick,
|
||||
leftCellStyleCallback,
|
||||
rightOnItemChecked,
|
||||
rightOnItemAllChecked,
|
||||
enableSort = false,
|
||||
}: SplitDataGridProps) => {
|
||||
return (
|
||||
@@ -35,6 +37,8 @@ const SplitDataGrid = ({
|
||||
enableSort={enableSort}
|
||||
rowData={rightRowData}
|
||||
setRowData={setRightRowData}
|
||||
onItemChecked={rightOnItemChecked}
|
||||
onItemAllChecked={rightOnItemAllChecked}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { type Dispatch, type SetStateAction, useCallback, useEffect, useMemo, useState } from "react";
|
||||
|
||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||
import type { VerificationResultListRequest, VerificationResultReportItem } from "@/entities/statistics/model/statistics-interface";
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
@@ -11,20 +14,29 @@ import {
|
||||
DialogTitle,
|
||||
LoadingWithAnimation,
|
||||
} from "@common/components";
|
||||
|
||||
import DataGrid from "@/components/module/DataGrid";
|
||||
import { VerificationResultHistoryPagination } from "@/components/module/VerificationResultHistoryPagination";
|
||||
import type { ColumnInfo } from "@/components/type/DataGrid.type";
|
||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||
import type { VerificationResultListRequest, VerificationResultReportItem } from "@/entities/statistics/model/statistics-interface";
|
||||
import type { CellStyleCallbackParams, ColumnInfo } from "@/components/type/DataGrid.type";
|
||||
|
||||
type VerificationResultGridRow = Record<string, string | number>;
|
||||
|
||||
const PRCS_YN_LABEL: Record<string, string> = {
|
||||
"0": "미통과",
|
||||
"1": "통과",
|
||||
"2": "예외처리",
|
||||
"3": "반려",
|
||||
};
|
||||
function prcsYnCodeToNumber(raw: string | number | undefined): number | undefined {
|
||||
if (raw === undefined || raw === null) return undefined;
|
||||
if (typeof raw === "number" && Number.isFinite(raw)) return raw;
|
||||
const s = String(raw).trim();
|
||||
if (s === "") return undefined;
|
||||
const n = Number.parseInt(s, 10);
|
||||
return Number.isFinite(n) ? n : undefined;
|
||||
}
|
||||
|
||||
/** prcsYn 0·4 → 빨간색, 그 외 → 초록색 (처리여부 컬럼) */
|
||||
function verificationPrcsYnNmCellStyle({ fieldName, row }: CellStyleCallbackParams): string | undefined {
|
||||
if (fieldName !== "prcsYnNm") return undefined;
|
||||
const code = prcsYnCodeToNumber(row.prcsYn);
|
||||
if (code === 0 || code === 4) return "rg-cell-vrf-prcs-bad";
|
||||
return "rg-cell-vrf-prcs-ok";
|
||||
}
|
||||
|
||||
const verificationResultColumnInfo: ColumnInfo = {
|
||||
columns: [
|
||||
@@ -34,12 +46,13 @@ const verificationResultColumnInfo: ColumnInfo = {
|
||||
{ name: "rsnExpln", fieldName: "rsnExpln", header: { text: "사유" }, editable: false },
|
||||
{ name: "nowVlCn", fieldName: "nowVlCn", header: { text: "입력값" }, editable: false },
|
||||
{ name: "compVlCn", fieldName: "compVlCn", header: { text: "기준값" }, editable: false },
|
||||
{ name: "prcsYn", fieldName: "prcsYn", header: { text: "처리여부" }, editable: false },
|
||||
{ name: "prcsYnNm", fieldName: "prcsYnNm", header: { text: "처리여부" }, editable: false },
|
||||
{ name: "pbcpAprvYn", fieldName: "pbcpAprvYn", header: { text: "공단승인여부" }, editable: false },
|
||||
{ name: "regDt", fieldName: "regDt", header: { text: "등록일시" }, editable: false },
|
||||
{ name: "mdfcnDt", fieldName: "mdfcnDt", header: { text: "갱신일시" }, editable: false },
|
||||
{ name: "prcsYn", fieldName: "prcsYn", header: { text: "검증결과상태코드" }, editable: false, visible: false },
|
||||
],
|
||||
columnLayout: ["ctpvNm", "sggNm", "vrfcTrgtNm", "rsnExpln", "nowVlCn", "compVlCn", "prcsYn", "pbcpAprvYn", "regDt", "mdfcnDt"],
|
||||
columnLayout: ["ctpvNm", "sggNm", "vrfcTrgtNm", "rsnExpln", "nowVlCn", "compVlCn", "prcsYnNm", "pbcpAprvYn", "regDt", "mdfcnDt", "prcsYn"],
|
||||
};
|
||||
|
||||
export interface VerificationResultHistoryDialogProps {
|
||||
@@ -190,7 +203,8 @@ export function VerificationResultHistoryDialog({
|
||||
rsnExpln: item.rsnExpln,
|
||||
nowVlCn: item.nowVlCn ?? "-",
|
||||
compVlCn: item.compVlCn ?? "-",
|
||||
prcsYn: PRCS_YN_LABEL[item.prcsYn] ?? item.prcsYn,
|
||||
prcsYnNm: item.prcsYnNm ?? "-",
|
||||
prcsYn: item.prcsYn ?? "",
|
||||
pbcpAprvYn: item.pbcpAprvYn,
|
||||
regDt: (item.regDt ?? "").slice(0, 16),
|
||||
mdfcnDt: (item.mdfcnDt ?? "").slice(0, 16),
|
||||
@@ -224,6 +238,7 @@ export function VerificationResultHistoryDialog({
|
||||
isExcelExport={false}
|
||||
showHeaderCheckbox={false}
|
||||
enableSort={false}
|
||||
cellStyleCallback={verificationPrcsYnNmCellStyle}
|
||||
/>
|
||||
<VerificationResultHistoryPagination
|
||||
pageCount={Math.max(pageCount, 1)}
|
||||
|
||||
@@ -215,7 +215,7 @@ const VerificationSelectionReport = ({
|
||||
<div className="w-1/5 bg-container p-4 !pb-2 flex border-r border-border">
|
||||
<div className="card card-border flex-1 bg-background !px-0">
|
||||
<div className="border-b border-border flex justify-between">
|
||||
<h2 className="text-[2.4rem] font-semibold text-title p-4 ">검증 미통과 내역</h2>
|
||||
<h2 className="text-[2.4rem] font-semibold text-title p-4 ">이상치 선별 보고서</h2>
|
||||
<span
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
|
||||
@@ -0,0 +1,224 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { useAlertStore } from "@/shared/lib";
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
Input,
|
||||
Label,
|
||||
} from "@common/components";
|
||||
|
||||
export interface MainFacilityMappingSaveDialogValues {
|
||||
prxyBzentyNmCn: string;
|
||||
/** 위탁비용(백만원/년) */
|
||||
cnsgnCstVl: number;
|
||||
wholNope: number;
|
||||
/** YYYYMMDD~YYYYMMDD */
|
||||
prxyCtrtCn: string;
|
||||
}
|
||||
|
||||
export interface MainFacilityMappingSaveDialogProps {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
initialPrxyBzentyNmCn: string;
|
||||
/** 위탁비용(백만원/년) 초기값 */
|
||||
initialCnsgnCstVl: number;
|
||||
initialWholNope: number;
|
||||
/** 위탁계약기간 초기값 (YYYYMMDD~YYYYMMDD) */
|
||||
initialPrxyCtrtCn: string;
|
||||
onConfirm?: (values: MainFacilityMappingSaveDialogValues) => void | Promise<void>;
|
||||
}
|
||||
|
||||
function isValidYmd(ymd: string): boolean {
|
||||
if (!/^\d{8}$/.test(ymd)) return false;
|
||||
const y = Number(ymd.slice(0, 4));
|
||||
const m = Number(ymd.slice(4, 6));
|
||||
const d = Number(ymd.slice(6, 8));
|
||||
const dt = new Date(y, m - 1, d);
|
||||
return dt.getFullYear() === y && dt.getMonth() === m - 1 && dt.getDate() === d;
|
||||
}
|
||||
|
||||
function validatePrxyCtrtCn(value: string): string | null {
|
||||
const t = value.trim();
|
||||
if (!t) return "위탁계약기간을 입력해 주세요.";
|
||||
if (!/^\d{8}~\d{8}$/.test(t)) {
|
||||
return "위탁계약기간은 YYYYMMDD~YYYYMMDD 형식으로 입력해 주세요. (예: 20240101~20281231)";
|
||||
}
|
||||
const start = t.slice(0, 8);
|
||||
const end = t.slice(9, 17);
|
||||
if (!isValidYmd(start) || !isValidYmd(end)) {
|
||||
return "시작일 또는 종료일이 유효한 날짜가 아닙니다.";
|
||||
}
|
||||
if (start > end) {
|
||||
return "시작일이 종료일보다 늦을 수 없습니다.";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function MainFacilityMappingSaveDialog({
|
||||
open,
|
||||
onOpenChange,
|
||||
initialPrxyBzentyNmCn,
|
||||
initialCnsgnCstVl,
|
||||
initialWholNope,
|
||||
initialPrxyCtrtCn,
|
||||
onConfirm,
|
||||
}: MainFacilityMappingSaveDialogProps) {
|
||||
const { setMessage: alert } = useAlertStore((state) => state);
|
||||
const [prxyBzentyNmCn, setPrxyBzentyNmCn] = useState("");
|
||||
const [cnsgnCstInput, setCnsgnCstInput] = useState("");
|
||||
const [wholNopeInput, setWholNopeInput] = useState("");
|
||||
const [prxyCtrtCn, setPrxyCtrtCn] = useState("");
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
setPrxyBzentyNmCn(initialPrxyBzentyNmCn ?? "");
|
||||
const initCost = Number(initialCnsgnCstVl);
|
||||
setCnsgnCstInput(
|
||||
initialCnsgnCstVl === null ||
|
||||
initialCnsgnCstVl === undefined ||
|
||||
Number.isNaN(initCost)
|
||||
? ""
|
||||
: String(initCost),
|
||||
);
|
||||
setWholNopeInput(
|
||||
initialWholNope === null || initialWholNope === undefined || Number.isNaN(Number(initialWholNope))
|
||||
? ""
|
||||
: String(initialWholNope),
|
||||
);
|
||||
setPrxyCtrtCn((initialPrxyCtrtCn ?? "").trim());
|
||||
}
|
||||
}, [open, initialPrxyBzentyNmCn, initialCnsgnCstVl, initialWholNope, initialPrxyCtrtCn]);
|
||||
|
||||
const handleDialogOpenChange = (nextOpen: boolean) => {
|
||||
if (!nextOpen && !isSubmitting) {
|
||||
setPrxyBzentyNmCn("");
|
||||
setCnsgnCstInput("");
|
||||
setWholNopeInput("");
|
||||
setPrxyCtrtCn("");
|
||||
}
|
||||
onOpenChange(nextOpen);
|
||||
};
|
||||
|
||||
const handleConfirm = async () => {
|
||||
const trimmedCost = cnsgnCstInput.trim();
|
||||
const cnsgnCstVl = trimmedCost === "" ? 0 : Number.parseFloat(trimmedCost.replace(/,/g, ""));
|
||||
if (!Number.isFinite(cnsgnCstVl) || cnsgnCstVl < 0) {
|
||||
alert("위탁비용은 0 이상의 숫자로 입력해 주세요.");
|
||||
return;
|
||||
}
|
||||
const trimmedWhol = wholNopeInput.trim();
|
||||
const wholNope = trimmedWhol === "" ? 0 : Number.parseInt(trimmedWhol, 10);
|
||||
if (!Number.isFinite(wholNope) || wholNope < 0) {
|
||||
alert("전체 인원은 0 이상의 정수로 입력해 주세요.");
|
||||
return;
|
||||
}
|
||||
const prxyCtrtErr = validatePrxyCtrtCn(prxyCtrtCn);
|
||||
if (prxyCtrtErr) {
|
||||
alert(prxyCtrtErr);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
setIsSubmitting(true);
|
||||
await onConfirm?.({
|
||||
prxyBzentyNmCn: prxyBzentyNmCn.trim(),
|
||||
cnsgnCstVl,
|
||||
wholNope,
|
||||
prxyCtrtCn: prxyCtrtCn.trim(),
|
||||
});
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={handleDialogOpenChange}>
|
||||
<DialogContent className="max-w-[48rem]" aria-describedby={undefined}>
|
||||
<DialogHeader>
|
||||
<DialogTitle>저장 정보 입력</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="flex flex-col gap-4 py-2">
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label className="text-label">위탁업체명</Label>
|
||||
<Input
|
||||
value={prxyBzentyNmCn}
|
||||
onChange={(e) => setPrxyBzentyNmCn(e.target.value)}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="위탁사업자명을 입력하세요."
|
||||
disabled={isSubmitting}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label className="text-label">위탁비용(백만원/년)</Label>
|
||||
<Input
|
||||
type="text"
|
||||
inputMode="decimal"
|
||||
value={cnsgnCstInput}
|
||||
onChange={(e) => {
|
||||
const v = e.target.value.replace(/[^\d.]/g, "");
|
||||
const firstDot = v.indexOf(".");
|
||||
const next =
|
||||
firstDot === -1
|
||||
? v
|
||||
: v.slice(0, firstDot + 1) + v.slice(firstDot + 1).replace(/\./g, "");
|
||||
setCnsgnCstInput(next);
|
||||
}}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="0"
|
||||
disabled={isSubmitting}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label className="text-label">전체 인원</Label>
|
||||
<Input
|
||||
type="text"
|
||||
inputMode="numeric"
|
||||
value={wholNopeInput}
|
||||
onChange={(e) => {
|
||||
const v = e.target.value.replace(/\D/g, "");
|
||||
setWholNopeInput(v);
|
||||
}}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="0"
|
||||
disabled={isSubmitting}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label className="text-label">위탁계약기간</Label>
|
||||
<Input
|
||||
value={prxyCtrtCn}
|
||||
onChange={(e) => setPrxyCtrtCn(e.target.value)}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="YYYYMMDD~YYYYMMDD (예: 20240101~20281231)"
|
||||
autoComplete="off"
|
||||
disabled={isSubmitting}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<DialogClose asChild>
|
||||
<Button type="button" color="gray" disabled={isSubmitting}>
|
||||
취소
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<Button
|
||||
type="button"
|
||||
color="primary"
|
||||
disabled={isSubmitting}
|
||||
onClick={() => void handleConfirm()}
|
||||
>
|
||||
저장
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import { useRef, useState } from 'react';
|
||||
|
||||
import { useConfirm } from '@frontend-opensource/use-react-hooks';
|
||||
|
||||
import { useAlertStore } from '@/shared/lib';
|
||||
import { useAlertStore, useGlobalProgressStore } from '@/shared/lib';
|
||||
import { statisticsInputSewSupplyRateApi } from '@/entities/statistics/api/input/statistics-input-sew-supply-rate-service';
|
||||
import { statisticsInputPublicSewageFacilityApiService } from '@/entities/statistics/api/input/statistics-public-sewage-facility-input-service';
|
||||
import { statisticsApi } from '@/entities/statistics/api/statistics-service';
|
||||
@@ -10,6 +10,8 @@ import type {
|
||||
PublicSewageFacilityRequestParams,
|
||||
PublicSewageFacilitySaveItem,
|
||||
PublicSewageFacilitySaveRequest,
|
||||
PublicSewageMainFacilityMappingSaveItem,
|
||||
PublicSewageMainFacilityMappingSaveRequest,
|
||||
PublicSewageMappingTargetsRequestParams,
|
||||
} from '@/entities/statistics/model/input/statistics-public-sewage-facility-input-interface';
|
||||
import {
|
||||
@@ -23,6 +25,7 @@ import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from '
|
||||
|
||||
import { getUserInfo } from '../../../../../../packages/common/components/src/api';
|
||||
|
||||
import { MainFacilityMappingSaveDialog } from './MainFacilityMappingSaveDialog';
|
||||
import SubmitDailog from './SubmitDailog';
|
||||
|
||||
import CancelSubmitButton from '@/components/button/CancelSubmitButton';
|
||||
@@ -30,9 +33,12 @@ import NotApplicableCheckButton from '@/components/button/NotApplicableCheckButt
|
||||
import SaveButton from '@/components/button/SaveButton';
|
||||
import SubmitButton from '@/components/button/SumitButton';
|
||||
import UpdateOperateDataButton from '@/components/button/UpdateOperateDataButton';
|
||||
import VerificationResultButton from '@/components/button/VerificationResultButton';
|
||||
import DataGrid from '@/components/module/DataGrid';
|
||||
import SearchForm from '@/components/module/SearchForm';
|
||||
import SplitDataGrid from '@/components/module/SplitDataGrid';
|
||||
import { VerificationResultDialog } from '@/components/module/VerificationResultDialog';
|
||||
import { VerificationResultHistoryDialog } from '@/components/module/VerificationResultHistoryDialog';
|
||||
import type { CellStyleCallbackParams, ColumnInfo, ColumnInfoList } from '@/components/type/DataGrid.type';
|
||||
import type { SearchFormValues } from '@/components/type/SearchForm.type';
|
||||
import { doList } from '@/components/util/column/input/DoList';
|
||||
@@ -93,12 +99,14 @@ async function waitForImrJobCompleted(
|
||||
options?: {
|
||||
pollIntervalMs?: number;
|
||||
maxAttempts?: number;
|
||||
onProgress?: (jobProgress: number) => void;
|
||||
},
|
||||
): Promise<void> {
|
||||
const pollIntervalMs = options?.pollIntervalMs ?? 2000;
|
||||
const maxAttempts = options?.maxAttempts ?? 150;
|
||||
for (let i = 0; i < maxAttempts; i++) {
|
||||
const res = await getStatus(jobId);
|
||||
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 === 'FAILED' || res.status === 'ERROR' || res.status === 'CANCELLED') {
|
||||
throw new Error(res.error_msg || `IMR 검증이 ${res.status} 상태로 종료되었습니다.`);
|
||||
@@ -108,11 +116,31 @@ async function waitForImrJobCompleted(
|
||||
throw new Error('IMR 검증 완료 대기 시간이 초과되었습니다.');
|
||||
}
|
||||
|
||||
type MainFacilityMappingSaveDraft = {
|
||||
statsYr: string;
|
||||
sewerBzmnCd: string;
|
||||
admdstCd: string;
|
||||
admdstNm: string;
|
||||
mainFcltSn: string;
|
||||
mainFcltNm: string;
|
||||
initialCnsgnCstVl: number;
|
||||
saveList: PublicSewageMainFacilityMappingSaveItem[];
|
||||
deleteList: string[];
|
||||
initialPrxyBzentyNmCn: string;
|
||||
initialWholNope: number;
|
||||
initialPrxyCtrtCn: string;
|
||||
};
|
||||
|
||||
// 하수도 통계 관리 > 06. 공공하수처리시설
|
||||
const PublicSewageFacilityInp = () => {
|
||||
const { setMessage: alert } = useAlertStore((state) => state);
|
||||
const { confirm } = useConfirm();
|
||||
const { isAdminInfo } = useAdminStore();
|
||||
const showGlobalProgress = useGlobalProgressStore((state) => state.show);
|
||||
const setGlobalProgress = useGlobalProgressStore((state) => state.setProgress);
|
||||
const setGlobalProgressLabel = useGlobalProgressStore((state) => state.setLabel);
|
||||
const hideGlobalProgress = useGlobalProgressStore((state) => state.hide);
|
||||
const globalProgressVisible = useGlobalProgressStore((state) => state.visible);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [hasSearched, setHasSearched] = useState(false);
|
||||
const [isNotApplicable, setIsNotApplicable] = useState(false);
|
||||
@@ -126,9 +154,16 @@ const PublicSewageFacilityInp = () => {
|
||||
const [periodCheckList, setPeriodCheckList] = useState<CheckInputPeriodItem[]>([]);
|
||||
const [showDailog, setShowDailog] = useState<boolean>(false);
|
||||
const [selectedMainFacilitySn, setSelectedMainFacilitySn] = useState<string | null>(null);
|
||||
const mainFacilityMappingSaveDraftRef = useRef<MainFacilityMappingSaveDraft | null>(null);
|
||||
const [mainFacilityMappingSaveDialogOpen, setMainFacilityMappingSaveDialogOpen] = useState(false);
|
||||
const [mainFacilityMappingSaveDialogKey, setMainFacilityMappingSaveDialogKey] = useState(0);
|
||||
const [verificationResultDialogOpen, setVerificationResultDialogOpen] = useState(false);
|
||||
const [verificationHistoryOpen, setVerificationHistoryOpen] = useState(false);
|
||||
|
||||
const periodEnterableRef = useRef(true);
|
||||
const searchDoneRef = useRef(false);
|
||||
/** ST00060001만: RealGrid 편집값이 state에 없을 수 있어 저장/제출 시 그리드에서 직접 읽음 */
|
||||
const st60001GridGetRowsRef = useRef<(() => Record<string, string | number>[]) | null>(null);
|
||||
|
||||
const submitFunc = () => {
|
||||
void (async () => {
|
||||
@@ -140,7 +175,8 @@ const PublicSewageFacilityInp = () => {
|
||||
alert('먼저 조회를 진행해주세요.');
|
||||
return;
|
||||
}
|
||||
const currentData = rowDataMap.get('ST00060001') ?? [];
|
||||
const currentData =
|
||||
st60001GridGetRowsRef.current?.() ?? rowDataMap.get('ST00060001') ?? [];
|
||||
if (!currentData || currentData.length === 0) {
|
||||
alert('제출할 데이터가 없습니다.');
|
||||
return;
|
||||
@@ -199,6 +235,11 @@ const PublicSewageFacilityInp = () => {
|
||||
return noApplicableVisible ? Boolean(isNotApplicable) : false;
|
||||
};
|
||||
|
||||
const isCheckedRow = (row: Record<string, string | number>): boolean => {
|
||||
const v = row.__checked;
|
||||
return v === 1 || v === '1' || v === 'Y' || v === 'y' || v === 'true';
|
||||
};
|
||||
|
||||
const executeSubmit = async (submitInfo: StatisticsInputSubmitInfoFormData) => {
|
||||
const verificationBlocked = getVerificationPeriodActionBlockedMessage(periodCheckList);
|
||||
if (verificationBlocked) {
|
||||
@@ -213,125 +254,225 @@ const PublicSewageFacilityInp = () => {
|
||||
alert('먼저 조회를 진행해주세요.');
|
||||
return;
|
||||
}
|
||||
const currentData = rowDataMap.get('ST00060001') ?? [];
|
||||
const currentData =
|
||||
st60001GridGetRowsRef.current?.() ?? rowDataMap.get('ST00060001') ?? [];
|
||||
if (!currentData || currentData.length === 0) {
|
||||
alert('제출할 데이터가 없습니다.');
|
||||
return;
|
||||
}
|
||||
|
||||
const userInfo = await getUserInfo();
|
||||
const submitList = buildFacilitySaveList(currentData);
|
||||
const activeTabStatus = tabStatusInfoMap.get(activeTab) ?? null;
|
||||
const statsCdForTab = tabStatsCdMap.get(activeTab) ?? activeTab;
|
||||
const requestData = {
|
||||
statsYr: lastSearchedValues.year ?? '',
|
||||
ctpvNm: lastSearchedValues.sido ?? '',
|
||||
sggNm: lastSearchedValues.gugun === 'ALL' ? '' : lastSearchedValues.gugun ?? '',
|
||||
sewerBzmnCd: lastSearchedValues.bsnmCd ?? '',
|
||||
userId: userInfo.userUnqId,
|
||||
noApplicable: getNoApplicableForRequest(),
|
||||
laePicNm: submitInfo.laePicNm,
|
||||
laeKbrdrJbgdNm: submitInfo.laeKbrdrJbgdNm,
|
||||
laeKbrdrDeptNm: submitInfo.laeKbrdrDeptNm,
|
||||
laePicTelNo: submitInfo.laePicTelNo,
|
||||
laeIdfrNm: submitInfo.laeIdfrNm,
|
||||
laeIdfrJbgdNm: submitInfo.laeIdfrJbgdNm,
|
||||
laeIdfrDeptNm: submitInfo.laeIdfrDeptNm,
|
||||
laeIdfrTelNo: submitInfo.laeIdfrTelNo,
|
||||
submitList,
|
||||
};
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const response = await statisticsInputPublicSewageFacilityApiService.submitPublicSewageFacility(requestData);
|
||||
if (response.status === 'success') {
|
||||
if (response.data?.finalStatus === '5') {
|
||||
const imrParam = {
|
||||
user_id: userInfo.userUnqId,
|
||||
sewer_bzmn_cd: lastSearchedValues.bsnmCd ?? '',
|
||||
stats_cd: statsCdForTab,
|
||||
stats_yr: lastSearchedValues.year ?? '',
|
||||
lae_sbmsn_stts_cd: activeTabStatus?.laeSbmsnSttsCd === '4' ? '4' : '2',
|
||||
gen_verify_stts_cd: response.data?.nvpassed ? '1' : '2',
|
||||
};
|
||||
try {
|
||||
const imrResponse = await statisticsApi.callImrService(imrParam);
|
||||
if (imrResponse.job_id) {
|
||||
await waitForImrJobCompleted(
|
||||
imrResponse.job_id,
|
||||
(id) => statisticsApi.getImrStatus(id),
|
||||
);
|
||||
}
|
||||
alert('제출되었습니다.');
|
||||
} catch {
|
||||
alert('제출은 완료되었으나 IMR 검증 처리 중 오류가 발생했습니다.');
|
||||
}
|
||||
} else {
|
||||
alert(response.message || '제출 처리 결과를 확인해주세요.');
|
||||
}
|
||||
await loadPublicSewageFacilityActiveTabData(
|
||||
'ST00060001',
|
||||
searchParamRef.current,
|
||||
lastSearchedValues,
|
||||
);
|
||||
} else {
|
||||
alert(response.message || '데이터 제출 중 오류가 발생했습니다.');
|
||||
}
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const saveFunc = () => {
|
||||
void (async () => {
|
||||
if (activeTab !== 'ST00060001') {
|
||||
alert('ST00060002 저장 API 연동 전입니다.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!lastSearchedValues || !searchParamRef.current) {
|
||||
alert('먼저 조회를 진행해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
const currentData = rowDataMap.get('ST00060001') ?? [];
|
||||
if (!currentData || currentData.length === 0) {
|
||||
alert('저장할 데이터가 없습니다.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(await confirm("저장 하시겠습니까?"))) return;
|
||||
|
||||
showGlobalProgress({ label: '서버에 요청 중...', progress: 0 });
|
||||
const userInfo = await getUserInfo();
|
||||
const saveList = buildFacilitySaveList(currentData);
|
||||
|
||||
const param: PublicSewageFacilitySaveRequest = {
|
||||
const submitList = buildFacilitySaveList(currentData);
|
||||
const activeTabStatus = tabStatusInfoMap.get(activeTab) ?? null;
|
||||
const statsCdForTab = tabStatsCdMap.get(activeTab) ?? activeTab;
|
||||
const requestData = {
|
||||
statsYr: lastSearchedValues.year ?? '',
|
||||
ctpvNm: lastSearchedValues.sido ?? '',
|
||||
sggNm: lastSearchedValues.gugun === 'ALL' ? '' : lastSearchedValues.gugun ?? '',
|
||||
sewerBzmnCd: lastSearchedValues.bsnmCd ?? '',
|
||||
userId: userInfo.userUnqId,
|
||||
superAdmin: isAdminInfo ? 'superAdmin' : '',
|
||||
noApplicable: getNoApplicableForRequest(),
|
||||
saveList,
|
||||
laePicNm: submitInfo.laePicNm,
|
||||
laeKbrdrJbgdNm: submitInfo.laeKbrdrJbgdNm,
|
||||
laeKbrdrDeptNm: submitInfo.laeKbrdrDeptNm,
|
||||
laePicTelNo: submitInfo.laePicTelNo,
|
||||
laeIdfrNm: submitInfo.laeIdfrNm,
|
||||
laeIdfrJbgdNm: submitInfo.laeIdfrJbgdNm,
|
||||
laeIdfrDeptNm: submitInfo.laeIdfrDeptNm,
|
||||
laeIdfrTelNo: submitInfo.laeIdfrTelNo,
|
||||
submitList,
|
||||
};
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const response = await statisticsInputPublicSewageFacilityApiService.savePublicSewageFacility(param);
|
||||
if (response.status === 'success') {
|
||||
alert('저장되었습니다.');
|
||||
setGlobalProgressLabel('일반 검증 진행 중...');
|
||||
const response =
|
||||
await statisticsInputPublicSewageFacilityApiService.submitPublicSewageFacility(
|
||||
requestData,
|
||||
);
|
||||
|
||||
if (response.status !== 'success') {
|
||||
alert(response.message || '데이터 제출 중 오류가 발생했습니다.');
|
||||
return;
|
||||
}
|
||||
|
||||
const finalStatus = response.data?.finalStatus;
|
||||
const nvpassed = response.data?.nvpassed;
|
||||
|
||||
if (finalStatus === '5') {
|
||||
setGlobalProgress(50);
|
||||
setGlobalProgressLabel('IMR 검증 진행 중...');
|
||||
const imrParam = {
|
||||
user_id: userInfo.userUnqId,
|
||||
sewer_bzmn_cd: lastSearchedValues.bsnmCd ?? '',
|
||||
stats_cd: statsCdForTab,
|
||||
stats_yr: lastSearchedValues.year ?? '',
|
||||
lae_sbmsn_stts_cd: activeTabStatus?.laeSbmsnSttsCd === '4' ? '4' : '2',
|
||||
gen_verify_stts_cd: nvpassed ? '1' : '2',
|
||||
};
|
||||
|
||||
try {
|
||||
const imrResponse = await statisticsApi.callImrService(imrParam);
|
||||
if (imrResponse.job_id) {
|
||||
await waitForImrJobCompleted(
|
||||
imrResponse.job_id,
|
||||
(id) => statisticsApi.getImrStatus(id),
|
||||
{
|
||||
onProgress: (jobProgress) => {
|
||||
setGlobalProgress(50 + Math.round(jobProgress / 2));
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
setGlobalProgress(100);
|
||||
await loadPublicSewageFacilityActiveTabData(
|
||||
'ST00060001',
|
||||
searchParamRef.current,
|
||||
lastSearchedValues,
|
||||
);
|
||||
} else {
|
||||
alert(response.message || '데이터 저장 중 오류가 발생했습니다.');
|
||||
setVerificationResultDialogOpen(true);
|
||||
} catch (e) {
|
||||
await loadPublicSewageFacilityActiveTabData(
|
||||
'ST00060001',
|
||||
searchParamRef.current,
|
||||
lastSearchedValues,
|
||||
);
|
||||
setVerificationResultDialogOpen(true);
|
||||
const msg =
|
||||
e instanceof Error && e.message
|
||||
? e.message
|
||||
: 'IMR 검증 중 오류가 발생했습니다.\n관리자에게 문의하세요.';
|
||||
alert(msg);
|
||||
}
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
} else {
|
||||
setGlobalProgress(100);
|
||||
await loadPublicSewageFacilityActiveTabData(
|
||||
'ST00060001',
|
||||
searchParamRef.current,
|
||||
lastSearchedValues,
|
||||
);
|
||||
setVerificationResultDialogOpen(true);
|
||||
}
|
||||
} catch {
|
||||
alert('데이터 제출 중 오류가 발생했습니다.');
|
||||
} finally {
|
||||
hideGlobalProgress();
|
||||
}
|
||||
};
|
||||
|
||||
const saveFunc = () => {
|
||||
void (async () => {
|
||||
if (!lastSearchedValues || !searchParamRef.current) {
|
||||
alert('먼저 조회를 진행해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (activeTab === 'ST00060002') {
|
||||
if (!(await confirm('저장 하시겠습니까?'))) return;
|
||||
|
||||
const leftRows = rowDataMap.get('MainFacility') ?? [];
|
||||
const rightRows = rowDataMap.get('MainFacilityTarget') ?? [];
|
||||
if (!leftRows.length || !rightRows.length) {
|
||||
alert('저장할 데이터가 없습니다.');
|
||||
return;
|
||||
}
|
||||
if (!selectedMainFacilitySn) {
|
||||
alert('좌측에서 중심 처리 시설을 먼저 선택해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedMain = leftRows.find((r) => String(r.fcltSn ?? '') === selectedMainFacilitySn);
|
||||
if (!selectedMain) {
|
||||
alert('선택된 중심 처리 시설 정보를 찾을 수 없습니다.');
|
||||
return;
|
||||
}
|
||||
|
||||
const saveList: PublicSewageMainFacilityMappingSaveItem[] = rightRows
|
||||
.filter((r) => isCheckedRow(r))
|
||||
.map((r) => ({
|
||||
fcltSn: String(r.fcltSn ?? ''),
|
||||
admdstCd: String(r.admdstCd ?? ''),
|
||||
admdstNm: String(r.admdstNm ?? ''),
|
||||
swtrmtFcltCd: String(r.swtrmtFcltCd ?? ''),
|
||||
swtrmtFcltNm: String(r.swtrmtFcltNm ?? ''),
|
||||
isMainYn: String(r.isMainYn ?? ''),
|
||||
}));
|
||||
|
||||
const deleteList = rightRows
|
||||
.filter((r) => String(r.mappedYn ?? '') === 'Y' && !isCheckedRow(r))
|
||||
.map((r) => String(r.fcltSn ?? ''))
|
||||
.filter((sn) => sn !== '');
|
||||
|
||||
const wholNopeFromRow = Number(selectedMain.wholNope ?? 0);
|
||||
mainFacilityMappingSaveDraftRef.current = {
|
||||
statsYr: lastSearchedValues.year ?? '',
|
||||
sewerBzmnCd: lastSearchedValues.bsnmCd ?? '',
|
||||
admdstCd: String(selectedMain.admdstCd ?? ''),
|
||||
admdstNm: String(selectedMain.admdstNm ?? ''),
|
||||
mainFcltSn: String(selectedMain.fcltSn ?? ''),
|
||||
mainFcltNm: String(selectedMain.swtrmtFcltNm ?? ''),
|
||||
initialCnsgnCstVl: Number(selectedMain.cnsgnCstVl ?? 0),
|
||||
saveList,
|
||||
deleteList,
|
||||
initialPrxyBzentyNmCn: String(selectedMain.prxyBzentyNmCn ?? ''),
|
||||
initialWholNope: Number.isFinite(wholNopeFromRow) ? wholNopeFromRow : 0,
|
||||
initialPrxyCtrtCn: String(selectedMain.prxyCtrtCn ?? ''),
|
||||
};
|
||||
setMainFacilityMappingSaveDialogKey((k) => k + 1);
|
||||
setMainFacilityMappingSaveDialogOpen(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(await confirm('저장 하시겠습니까?'))) return;
|
||||
|
||||
if (activeTab === 'ST00060001') {
|
||||
try {
|
||||
showGlobalProgress({ label: '저장 진행 중...', progress: 0 });
|
||||
const userInfo = await getUserInfo();
|
||||
const currentData =
|
||||
st60001GridGetRowsRef.current?.() ?? rowDataMap.get('ST00060001') ?? [];
|
||||
if (!currentData || currentData.length === 0) {
|
||||
alert('저장할 데이터가 없습니다.');
|
||||
return;
|
||||
}
|
||||
|
||||
const saveList = buildFacilitySaveList(currentData);
|
||||
const param: PublicSewageFacilitySaveRequest = {
|
||||
statsYr: lastSearchedValues.year ?? '',
|
||||
ctpvNm: lastSearchedValues.sido ?? '',
|
||||
sggNm: lastSearchedValues.gugun === 'ALL' ? '' : lastSearchedValues.gugun ?? '',
|
||||
sewerBzmnCd: lastSearchedValues.bsnmCd ?? '',
|
||||
userId: userInfo.userUnqId,
|
||||
superAdmin: isAdminInfo ? 'superAdmin' : '',
|
||||
noApplicable: getNoApplicableForRequest(),
|
||||
saveList,
|
||||
};
|
||||
|
||||
const response =
|
||||
await statisticsInputPublicSewageFacilityApiService.savePublicSewageFacility(
|
||||
param,
|
||||
);
|
||||
if (response.status === 'success') {
|
||||
setGlobalProgress(50);
|
||||
await loadPublicSewageFacilityActiveTabData(
|
||||
'ST00060001',
|
||||
searchParamRef.current,
|
||||
lastSearchedValues,
|
||||
);
|
||||
setGlobalProgress(100);
|
||||
alert('저장되었습니다.');
|
||||
} else {
|
||||
alert(response.message || '데이터 저장 중 오류가 발생했습니다.');
|
||||
}
|
||||
} catch {
|
||||
alert('데이터 저장 중 오류가 발생했습니다.');
|
||||
} finally {
|
||||
hideGlobalProgress();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
alert('현재 탭 저장 API 연동 전입니다.');
|
||||
})();
|
||||
};
|
||||
|
||||
@@ -489,6 +630,59 @@ const PublicSewageFacilityInp = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleMainFacilityMappingSaveConfirm = async (input: {
|
||||
prxyBzentyNmCn: string;
|
||||
cnsgnCstVl: number;
|
||||
wholNope: number;
|
||||
prxyCtrtCn: string;
|
||||
}) => {
|
||||
const draft = mainFacilityMappingSaveDraftRef.current;
|
||||
if (!draft || !searchParamRef.current || !lastSearchedValues) {
|
||||
setMainFacilityMappingSaveDialogOpen(false);
|
||||
mainFacilityMappingSaveDraftRef.current = null;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
showGlobalProgress({ label: '저장 진행 중...', progress: 0 });
|
||||
const userInfo = await getUserInfo();
|
||||
const param: PublicSewageMainFacilityMappingSaveRequest = {
|
||||
statsYr: draft.statsYr,
|
||||
sewerBzmnCd: draft.sewerBzmnCd,
|
||||
admdstCd: draft.admdstCd,
|
||||
admdstNm: draft.admdstNm,
|
||||
mainFcltSn: draft.mainFcltSn,
|
||||
mainFcltNm: draft.mainFcltNm,
|
||||
prxyBzentyNmCn: input.prxyBzentyNmCn,
|
||||
cnsgnCstVl: input.cnsgnCstVl,
|
||||
wholNope: input.wholNope,
|
||||
prxyCtrtCn: input.prxyCtrtCn,
|
||||
userId: userInfo.userUnqId,
|
||||
saveList: draft.saveList,
|
||||
deleteList: draft.deleteList,
|
||||
};
|
||||
const response =
|
||||
await statisticsInputPublicSewageFacilityApiService.saveMainFacilityMapping(param);
|
||||
if (response.status === 'success') {
|
||||
setGlobalProgress(50);
|
||||
setMainFacilityMappingSaveDialogOpen(false);
|
||||
mainFacilityMappingSaveDraftRef.current = null;
|
||||
await loadPublicSewageFacilityActiveTabData(
|
||||
'ST00060002',
|
||||
searchParamRef.current,
|
||||
lastSearchedValues,
|
||||
);
|
||||
setGlobalProgress(100);
|
||||
alert('저장되었습니다.');
|
||||
} else {
|
||||
alert(response.message || '데이터 저장 중 오류가 발생했습니다.');
|
||||
}
|
||||
} catch {
|
||||
alert('데이터 저장 중 오류가 발생했습니다.');
|
||||
} finally {
|
||||
hideGlobalProgress();
|
||||
}
|
||||
};
|
||||
|
||||
const handleSearch = async (values: SearchFormValues) => {
|
||||
if (!values.sido || values.sido === 'ALL') {
|
||||
alert('시도를 선택해주세요.');
|
||||
@@ -685,6 +879,30 @@ const PublicSewageFacilityInp = () => {
|
||||
const { showSaveInToolbar, showEnterableToolbarButtons, showActionToolbarCard } = activeTabToolbar;
|
||||
const isMainFacilityTab = activeTab === 'ST00060002';
|
||||
|
||||
const openVerificationHistoryDialog = () => {
|
||||
const ctx = lastSearchedValues ?? searchValues;
|
||||
const activeTabStatsCd = tabStatsCdMap.get(activeTab) ?? activeTab;
|
||||
if (!ctx?.year || !ctx?.sido || !ctx?.bsnmCd || !activeTabStatsCd) {
|
||||
alert('먼저 조회를 진행해주세요.');
|
||||
return;
|
||||
}
|
||||
setVerificationHistoryOpen(true);
|
||||
};
|
||||
|
||||
const verificationQueryContext =
|
||||
(() => {
|
||||
const ctx = lastSearchedValues ?? searchValues;
|
||||
const statsCd = tabStatsCdMap.get(activeTab) ?? activeTab;
|
||||
if (!ctx?.year || !ctx?.sido || !ctx?.bsnmCd || !statsCd) return null;
|
||||
return {
|
||||
sewerBzmnCd: ctx.bsnmCd,
|
||||
ctpvNm: ctx.sido,
|
||||
sggNm: ctx.gugun === 'ALL' ? '' : (ctx.gugun ?? ''),
|
||||
statsYr: ctx.year,
|
||||
statsCd,
|
||||
};
|
||||
})();
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="relative">
|
||||
@@ -697,6 +915,9 @@ const PublicSewageFacilityInp = () => {
|
||||
{showActionToolbarCard && (
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] mx-[0.6rem]">
|
||||
<VerificationResultButton
|
||||
VerificationResultButtonFunc={openVerificationHistoryDialog}
|
||||
/>
|
||||
{showEnterableToolbarButtons && !isMainFacilityTab && (
|
||||
<>
|
||||
{showIsNotApplicable && <NotApplicableCheckButton isCheck={isNotApplicable} setIsCheck={setIsNotApplicable} />}
|
||||
@@ -711,12 +932,13 @@ const PublicSewageFacilityInp = () => {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{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]">
|
||||
<LoadingWithAnimation color="primary" />
|
||||
{isLoading && !globalProgressVisible && (
|
||||
<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]">
|
||||
<LoadingWithAnimation color="primary" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
<Tabs value={activeTab} onValueChange={(v) => void handleActiveTabChange(v)}>
|
||||
<TabsList>
|
||||
{PublicSewageFactInpColumnList.map((tab) => (
|
||||
@@ -753,6 +975,38 @@ const PublicSewageFacilityInp = () => {
|
||||
? leftMainFacilityCellStyleCallback
|
||||
: undefined
|
||||
}
|
||||
rightOnItemChecked={
|
||||
tab.tabKey === 'ST00060002'
|
||||
? (itemIndex, checked) => {
|
||||
setRowDataMap((prev) => {
|
||||
const next = new Map(prev);
|
||||
const rows = [...(next.get('MainFacilityTarget') ?? [])];
|
||||
if (!rows[itemIndex]) return prev;
|
||||
rows[itemIndex] = {
|
||||
...rows[itemIndex],
|
||||
__checked: checked ? 'Y' : '',
|
||||
};
|
||||
next.set('MainFacilityTarget', rows);
|
||||
return next;
|
||||
});
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
rightOnItemAllChecked={
|
||||
tab.tabKey === 'ST00060002'
|
||||
? (checked) => {
|
||||
setRowDataMap((prev) => {
|
||||
const next = new Map(prev);
|
||||
const rows = [...(next.get('MainFacilityTarget') ?? [])].map((r) => ({
|
||||
...r,
|
||||
__checked: checked ? 'Y' : '',
|
||||
}));
|
||||
next.set('MainFacilityTarget', rows);
|
||||
return next;
|
||||
});
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
setLeftRowData={(updater) => {
|
||||
setRowDataMap((prev) => {
|
||||
const next = new Map(prev);
|
||||
@@ -803,6 +1057,9 @@ const PublicSewageFacilityInp = () => {
|
||||
return next;
|
||||
});
|
||||
}}
|
||||
getGridDataRef={
|
||||
tab.tabKey === 'ST00060001' ? st60001GridGetRowsRef : undefined
|
||||
}
|
||||
showHeaderCheckbox={false}
|
||||
enableSort={false}
|
||||
/>
|
||||
@@ -811,6 +1068,11 @@ const PublicSewageFacilityInp = () => {
|
||||
})}
|
||||
</Tabs>
|
||||
</div>
|
||||
<VerificationResultHistoryDialog
|
||||
open={verificationHistoryOpen}
|
||||
onOpenChange={setVerificationHistoryOpen}
|
||||
queryContext={verificationQueryContext}
|
||||
/>
|
||||
<SubmitDailog
|
||||
open={showDailog}
|
||||
onOpenChange={setShowDailog}
|
||||
@@ -819,6 +1081,26 @@ const PublicSewageFacilityInp = () => {
|
||||
submitMode="normal"
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
<VerificationResultDialog
|
||||
open={verificationResultDialogOpen}
|
||||
onOpenChange={setVerificationResultDialogOpen}
|
||||
queryContext={verificationQueryContext}
|
||||
/>
|
||||
<MainFacilityMappingSaveDialog
|
||||
key={`main-facility-mapping-save-${mainFacilityMappingSaveDialogKey}`}
|
||||
open={mainFacilityMappingSaveDialogOpen}
|
||||
onOpenChange={(open) => {
|
||||
setMainFacilityMappingSaveDialogOpen(open);
|
||||
if (!open) {
|
||||
mainFacilityMappingSaveDraftRef.current = null;
|
||||
}
|
||||
}}
|
||||
initialPrxyBzentyNmCn={mainFacilityMappingSaveDraftRef.current?.initialPrxyBzentyNmCn ?? ''}
|
||||
initialCnsgnCstVl={mainFacilityMappingSaveDraftRef.current?.initialCnsgnCstVl ?? 0}
|
||||
initialWholNope={mainFacilityMappingSaveDraftRef.current?.initialWholNope ?? 0}
|
||||
initialPrxyCtrtCn={mainFacilityMappingSaveDraftRef.current?.initialPrxyCtrtCn ?? ''}
|
||||
onConfirm={handleMainFacilityMappingSaveConfirm}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,71 +1,74 @@
|
||||
import { useState, useMemo, useRef, useEffect, useLayoutEffect } from "react";
|
||||
import { useEffect, useLayoutEffect,useMemo, useRef, useState } from "react";
|
||||
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import DataGrid from "@/components/module/DataGrid";
|
||||
import SplitDataGrid from "@/components/module/SplitDataGrid";
|
||||
import GridTopActionButton from "@/components/module/GridTopActionButton";
|
||||
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 CancelSubmitButton from "@/components/button/CancelSubmitButton";
|
||||
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
||||
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
||||
import SubmitDailog from "./SubmitDailog";
|
||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||
|
||||
import { SewagePipeInpColumnInfoList } from "@/components/util/column/input/sewagePipe/SewagePipeInpColumn";
|
||||
import type { ColumnInfo, ColumnInfoList, ColumnConfig } from "@/components/type/DataGrid.type";
|
||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||
import { useAlertStore, useGlobalProgressStore } from "@/shared/lib";
|
||||
import {
|
||||
STATISTICS_INPUT_URL_PATH,
|
||||
verificationSearchToFormValues,
|
||||
} from "@/shared/lib/stats-cd-input-navigation";
|
||||
import { useAdminStore } from "@/store/admin-store";
|
||||
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||
import { doList } from "@/components/util/column/input/DoList";
|
||||
import { statisticsInputSewPipeApiService } from "@/entities/statistics/api/input/statistics-sewage-pipe-input-service";
|
||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||
import type {
|
||||
SeweragePipeInputFactInstallStatusSaveRequest,
|
||||
SeweragePipeInputFactInstallStatusSubmitRequest,
|
||||
SeweragePipeInputManholeStatusItem,
|
||||
SeweragePipeInputManholeStatusSaveYearlyStatItem,
|
||||
SeweragePipeInputManholeStatusSaveRequest,
|
||||
SeweragePipeInputManholeStatusSaveYearlyStatItem,
|
||||
SeweragePipeInputManholeStatusSubmitRequest,
|
||||
SeweragePipeInputPipeDiameterStatusSaveRequest,
|
||||
SeweragePipeInputPipeDiameterStatusSubmitRequest,
|
||||
SeweragePipeInputPipeTypeStatusItem,
|
||||
SeweragePipeInputPipeTypeStatusSaveRequest,
|
||||
SeweragePipeInputPipeTypeStatusSubmitRequest,
|
||||
SeweragePipeInputRegionalFactStatusSaveRequest,
|
||||
SeweragePipeInputRegionalFactStatusSaveItem,
|
||||
SeweragePipeInputRegionalFactStatusSaveRequest,
|
||||
SeweragePipeInputRegionalFactStatusSubmitRequest,
|
||||
SeweragePipeInputSubmitResponse,
|
||||
SeweragePipeInputVerificationResult,
|
||||
SeweragePipeRequestParams,
|
||||
} from "@/entities/statistics/model/input/statistics-sewage-pipe-input-interface";
|
||||
import {
|
||||
type CheckInputPeriodItem,
|
||||
getVerificationPeriodActionBlockedMessage,
|
||||
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 {
|
||||
cancelSubmitRequest,
|
||||
ImrStatusResponse,
|
||||
SewerageStatusInfo,
|
||||
SubmitExceptionRequest,
|
||||
} from "@/entities/statistics/model/statistics-interface";
|
||||
import type { StatisticsInputSubmitInfoFormData } from "@/entities/statistics/model/statistics-input-submit-info-schema";
|
||||
import {
|
||||
type CheckInputPeriodItem,
|
||||
getVerificationPeriodActionBlockedMessage,
|
||||
isInputPeriodCurrent,
|
||||
} from "@/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface";
|
||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||
|
||||
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
||||
|
||||
import SubmitDailog from "./SubmitDailog";
|
||||
|
||||
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 VerificationResultButton from "@/components/button/VerificationResultButton";
|
||||
import DataGrid from "@/components/module/DataGrid";
|
||||
import GridTopActionButton from "@/components/module/GridTopActionButton";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import SplitDataGrid from "@/components/module/SplitDataGrid";
|
||||
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
||||
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
||||
import type { ColumnConfig,ColumnInfo, ColumnInfoList } from "@/components/type/DataGrid.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 { ManholeStatusInpColumn } from "@/components/util/column/input/sewagePipe/ManholeStatusInpColumn";
|
||||
import { PipeDiameterStatusInpColumn } from "@/components/util/column/input/sewagePipe/PipeDiameterStatusInpColumn";
|
||||
import { PipeTypeStatusInpColumn } from "@/components/util/column/input/sewagePipe/PipeTypeStatusInpColumn";
|
||||
import { RegionalFactStatusInpColumn } from "@/components/util/column/input/sewagePipe/RegionalFactStatusInpColumn";
|
||||
import { SewagePipeInpColumnInfoList } from "@/components/util/column/input/sewagePipe/SewagePipeInpColumn";
|
||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||
import { useAdminStore } from "@/store/admin-store";
|
||||
import { useStatisticsInputFocusStore } from "@/store/statistics-input-focus-store";
|
||||
import { useTabStore } from "@/store/tab-store";
|
||||
|
||||
@@ -740,7 +743,7 @@ const SewagePipeInp = () => {
|
||||
if (!job) return;
|
||||
postVerificationSearchRef.current = null;
|
||||
void handleSearch(job.values, { forcedTabKey: job.tabKey });
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps -- 검색폼 remount 직후 1회 자동 조회
|
||||
|
||||
}, [searchFormRemountKey]);
|
||||
|
||||
const handleActiveTabChange = async (tabKey: string) => {
|
||||
@@ -1209,6 +1212,7 @@ const SewagePipeInp = () => {
|
||||
true,
|
||||
false,
|
||||
);
|
||||
setVerificationResultDialogOpen(true);
|
||||
const msg =
|
||||
e instanceof Error && e.message
|
||||
? e.message
|
||||
@@ -1224,7 +1228,7 @@ const SewagePipeInp = () => {
|
||||
true,
|
||||
false,
|
||||
);
|
||||
alert("제출되었습니다.");
|
||||
setVerificationResultDialogOpen(true);
|
||||
}
|
||||
} catch {
|
||||
alert("데이터 제출 중 오류가 발생했습니다.");
|
||||
|
||||
@@ -1,52 +1,54 @@
|
||||
import { useState, useMemo, useRef, useLayoutEffect, useEffect } from "react";
|
||||
import { useEffect,useLayoutEffect, useMemo, useRef, useState } from "react";
|
||||
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
// import { DataGrid } from "@rsone/components";
|
||||
import DataGrid from "@/components/module/DataGrid";
|
||||
import SubmitButton from "@/components/button/SumitButton";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import LastYearDataButton from "@/components/button/LastYearDataButton";
|
||||
import CancelSubmitButton from "@/components/button/CancelSubmitButton";
|
||||
import VerificationResultButton from "@/components/button/VerificationResultButton";
|
||||
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
||||
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
||||
import { LoadingWithAnimation } from "@common/components";
|
||||
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
||||
import SubmitDailog from "./SubmitDailog";
|
||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||
|
||||
import { useAlertStore, useGlobalProgressStore } from "@/shared/lib";
|
||||
import {
|
||||
STATISTICS_INPUT_URL_PATH,
|
||||
verificationSearchToFormValues,
|
||||
} from "@/shared/lib/stats-cd-input-navigation";
|
||||
import { useAdminStore } from "@/store/admin-store";
|
||||
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
||||
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||
import { getFooterSummary } from "@/components/util/grid/footerSummary";
|
||||
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||
|
||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||
import {
|
||||
type CheckInputPeriodItem,
|
||||
getVerificationPeriodActionBlockedMessage,
|
||||
isInputPeriodCurrent,
|
||||
type SewerageSupplyRateItem,
|
||||
type SewerageSupplyRateRequestParams,
|
||||
type SewerageSupplyRateSaveItem,
|
||||
type SewerageSupplyRateVerificationResult,
|
||||
type SewerageSupplyRateSaveRequest,
|
||||
getVerificationPeriodActionBlockedMessage,
|
||||
isInputPeriodCurrent,
|
||||
type SewerageSupplyRateVerificationResult,
|
||||
} 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 {
|
||||
cancelSubmitRequest,
|
||||
ImrStatusResponse,
|
||||
SewerageStatusInfo,
|
||||
SubmitExceptionRequest,
|
||||
} from "@/entities/statistics/model/statistics-interface";
|
||||
import type { StatisticsInputSubmitInfoFormData } from "@/entities/statistics/model/statistics-input-submit-info-schema";
|
||||
import { SeweragePenetrationRateInpColumn } from "@/components/util/column/input/SeweragePenetrationRateInpColumn";
|
||||
import { LoadingWithAnimation } from "@common/components";
|
||||
|
||||
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
||||
|
||||
import SubmitDailog from "./SubmitDailog";
|
||||
|
||||
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 VerificationResultButton from "@/components/button/VerificationResultButton";
|
||||
// import { DataGrid } from "@rsone/components";
|
||||
import DataGrid from "@/components/module/DataGrid";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import { VerificationResultDialog } from "@/components/module/VerificationResultDialog";
|
||||
import { VerificationResultHistoryDialog } from "@/components/module/VerificationResultHistoryDialog";
|
||||
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 { getFooterSummary } from "@/components/util/grid/footerSummary";
|
||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||
import { useAdminStore } from "@/store/admin-store";
|
||||
import { useStatisticsInputFocusStore } from "@/store/statistics-input-focus-store";
|
||||
import { useTabStore } from "@/store/tab-store";
|
||||
|
||||
@@ -274,7 +276,7 @@ const SeweragePenetrationRateInp = () => {
|
||||
if (!values) return;
|
||||
postVerificationSearchRef.current = null;
|
||||
void handleSearch(values);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps -- 검색폼 remount 직후 1회 자동 조회
|
||||
|
||||
}, [searchFormRemountKey]);
|
||||
|
||||
const SubmitExceptionFunc = async (submitInfo: StatisticsInputSubmitInfoFormData) => {
|
||||
@@ -475,6 +477,7 @@ const SeweragePenetrationRateInp = () => {
|
||||
} catch (e) {
|
||||
await fetchSewerageSupplyRate(getSewerageSupplyRateParams(searchValues ?? {}), true);
|
||||
setIsLoading(false);
|
||||
setVerificationResultDialogOpen(true);
|
||||
const msg =
|
||||
e instanceof Error && e.message
|
||||
? e.message
|
||||
@@ -485,7 +488,7 @@ const SeweragePenetrationRateInp = () => {
|
||||
} else {
|
||||
setGlobalProgress(100);
|
||||
await fetchSewerageSupplyRate(getSewerageSupplyRateParams(searchValues ?? {}), false);
|
||||
alert('제출되었습니다.');
|
||||
setVerificationResultDialogOpen(true);
|
||||
}
|
||||
} else {
|
||||
alert(response.message || '데이터 제출 중 오류가 발생했습니다.');
|
||||
|
||||
@@ -8,14 +8,15 @@ import {
|
||||
type RowSelectionState,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table";
|
||||
import type { AxiosError } from "axios";
|
||||
|
||||
import { client } from "@/shared/api/client";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import { useAlertStore } from "@/shared/lib";
|
||||
import { useAlertStore, useMutationWrapper } from "@/shared/lib";
|
||||
import type { ApiErrorResponse } from "@/shared/model";
|
||||
import {
|
||||
type AdstZoneResponseDto,
|
||||
type BusinessSendRequest,
|
||||
type BusinessSendResponse,
|
||||
noticeTalkSendingApi,
|
||||
type SelectedRecipient,
|
||||
type SewerStUserItem,
|
||||
useNtftalkTemplateList,
|
||||
@@ -122,10 +123,26 @@ function NtitlkSndng() {
|
||||
const [previewRecipient, setPreviewRecipient] =
|
||||
useState<SelectedRecipient | null>(null);
|
||||
const [isPreviewOpen, setIsPreviewOpen] = useState(false);
|
||||
const [isSending, setIsSending] = useState(false);
|
||||
const [userListRowSelection, setUserListRowSelection] =
|
||||
useState<RowSelectionState>({});
|
||||
|
||||
const sendMutation = useMutationWrapper<
|
||||
BusinessSendResponse,
|
||||
AxiosError<ApiErrorResponse>,
|
||||
BusinessSendRequest
|
||||
>({
|
||||
mutationFn: (payload) => noticeTalkSendingApi.sendBusiness(payload),
|
||||
onSuccess: (data) => {
|
||||
if (!data.success) {
|
||||
alert(data.message || "알림톡 발송 요청에 실패했습니다.");
|
||||
return;
|
||||
}
|
||||
alert(data.message || "알림톡 발송이 요청되었습니다.");
|
||||
setSelectedRecipients([]);
|
||||
setCommonVariableValues({});
|
||||
},
|
||||
});
|
||||
|
||||
const { data: templatePageData } = useNtftalkTemplateList();
|
||||
const templates = templatePageData?.content ?? [];
|
||||
|
||||
@@ -321,7 +338,7 @@ function NtitlkSndng() {
|
||||
}),
|
||||
);
|
||||
if (missingVariable) {
|
||||
alert("필수 변수값이 입력되지 않은 발송 대상이 있습니다.");
|
||||
alert("변수값이 입력되지 않은 발송 대상이 있습니다.");
|
||||
return;
|
||||
}
|
||||
if (
|
||||
@@ -331,34 +348,13 @@ function NtitlkSndng() {
|
||||
)
|
||||
return;
|
||||
|
||||
const payload: BusinessSendRequest = {
|
||||
sendMutation.mutate({
|
||||
templateCode: selectedTemplateCode,
|
||||
callback: "032-590-4000",
|
||||
recipients: selectedRecipients.map((recipient) =>
|
||||
getMergedVariables(recipient, commonVariableValues),
|
||||
),
|
||||
};
|
||||
|
||||
try {
|
||||
setIsSending(true);
|
||||
const response = await client.post<BusinessSendResponse>(
|
||||
`${ENDPOINT.NTFTALK_SERVICE.ATA_SEND}/business`,
|
||||
payload,
|
||||
);
|
||||
const data = response.data;
|
||||
if (!data.success) {
|
||||
alert(data.message || "알림톡 발송 요청에 실패했습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
alert(data.message || `알림톡 발송이 요청되었습니다.`);
|
||||
setSelectedRecipients([]);
|
||||
setCommonVariableValues({});
|
||||
} catch {
|
||||
alert("알림톡 발송 중 오류가 발생했습니다.");
|
||||
} finally {
|
||||
setIsSending(false);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -567,7 +563,8 @@ function NtitlkSndng() {
|
||||
color="green"
|
||||
onClick={handleSend}
|
||||
disabled={
|
||||
isSending || selectedRecipients.length === 0
|
||||
sendMutation.isPending ||
|
||||
selectedRecipients.length === 0
|
||||
}
|
||||
>
|
||||
발송
|
||||
|
||||
@@ -1,84 +1,230 @@
|
||||
import { useState } from "react";
|
||||
import { useRef, useState } from "react";
|
||||
|
||||
import { useAlertStore } from "@/shared/lib";
|
||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||
import type {
|
||||
StatsInputPeriodItem,
|
||||
StatsInputPeriodListRequest,
|
||||
} from "@/entities/statistics/model/statistics-interface";
|
||||
import { Button, LoadingWithAnimation } from "@common/components";
|
||||
|
||||
import {
|
||||
StatisticsInputPeriodDialog,
|
||||
type StatisticsInputPeriodDialogValues,
|
||||
} from "./StatisticsInputPeriodDialog";
|
||||
|
||||
import DataGrid from "@/components/module/DataGrid";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import type { ColumnConfig } from "@/components/type/DataGrid.type";
|
||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||
|
||||
function seTypeToDisplayLabel(seType: StatsInputPeriodItem["seType"]): string {
|
||||
if (seType === "INPT") return "입력";
|
||||
if (seType === "VRFC") return "검증";
|
||||
return seType;
|
||||
}
|
||||
|
||||
function rowSeTypeToCode(row: Record<string, string | number>): "INPT" | "VRFC" {
|
||||
const v = String(row.seType ?? "");
|
||||
if (v === "INPT" || v === "입력") return "INPT";
|
||||
if (v === "VRFC" || v === "검증") return "VRFC";
|
||||
return "INPT";
|
||||
}
|
||||
|
||||
/** API `YYYYMMDD` 등 → Date */
|
||||
function parseYmdToDate(ymd: unknown): Date | undefined {
|
||||
const s = String(ymd ?? "").replace(/\D/g, "");
|
||||
if (s.length !== 8) return undefined;
|
||||
const y = Number(s.slice(0, 4));
|
||||
const m = Number(s.slice(4, 6));
|
||||
const d = Number(s.slice(6, 8));
|
||||
if (!y || m < 1 || m > 12 || d < 1 || d > 31) return undefined;
|
||||
const dt = new Date(y, m - 1, d);
|
||||
if (dt.getFullYear() !== y || dt.getMonth() !== m - 1 || dt.getDate() !== d) {
|
||||
return undefined;
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
|
||||
const StatisticsInputManagement = () => {
|
||||
const { setMessage: alert } = useAlertStore((state) => state);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>(
|
||||
[],
|
||||
);
|
||||
const [periodDialogOpen, setPeriodDialogOpen] = useState(false);
|
||||
const [periodDialogMode, setPeriodDialogMode] = useState<"edit" | "create">("edit");
|
||||
const [createDefaultStatsYr, setCreateDefaultStatsYr] = useState("");
|
||||
const [periodDialogInitial, setPeriodDialogInitial] =
|
||||
useState<StatisticsInputPeriodDialogValues | null>(null);
|
||||
const [searchFormValues, setSearchFormValues] = useState<SearchFormValues | null>(null);
|
||||
const lastSearchRef = useRef<SearchFormValues | null>(null);
|
||||
|
||||
const handleSearch = async (values: SearchFormValues) => {
|
||||
if (!values.year) {
|
||||
alert("년도를 선택해주세요.");
|
||||
return;
|
||||
}
|
||||
lastSearchRef.current = values;
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const params: StatsInputPeriodListRequest = {
|
||||
statsYr: values.year,
|
||||
};
|
||||
if (values.clsfCd && values.clsfCd !== "ALL") {
|
||||
params.seType = values.clsfCd;
|
||||
}
|
||||
const res = await statisticsApi.getStatsInputPeriodList(params);
|
||||
if (res.status === "success" && Array.isArray(res.data)) {
|
||||
const rowsForGrid = res.data.map((row) => ({
|
||||
...row,
|
||||
seType: seTypeToDisplayLabel(row.seType),
|
||||
}));
|
||||
setRowData(toGridRows(rowsForGrid));
|
||||
} else {
|
||||
setRowData([]);
|
||||
alert(res.message || "데이터 조회에 실패했습니다.");
|
||||
}
|
||||
} catch {
|
||||
setRowData([]);
|
||||
alert("데이터 조회 중 오류가 발생했습니다.");
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
setRowData([]);
|
||||
};
|
||||
|
||||
const handleRegisterClick = () => {
|
||||
const yr =
|
||||
searchFormValues?.year ?? lastSearchRef.current?.year ?? "";
|
||||
if (!yr) {
|
||||
alert("검색 폼에서 년도를 선택해 주세요.");
|
||||
return;
|
||||
}
|
||||
setPeriodDialogMode("create");
|
||||
setCreateDefaultStatsYr(yr);
|
||||
setPeriodDialogInitial(null);
|
||||
setPeriodDialogOpen(true);
|
||||
};
|
||||
|
||||
const handleRowClick = (row: Record<string, string | number>) => {
|
||||
const seCdRaw = row.seCd;
|
||||
const seCdNum =
|
||||
typeof seCdRaw === "number"
|
||||
? seCdRaw
|
||||
: parseInt(String(seCdRaw ?? ""), 10);
|
||||
setPeriodDialogMode("edit");
|
||||
setPeriodDialogInitial({
|
||||
statsYr: String(row.statsYr ?? ""),
|
||||
seType: rowSeTypeToCode(row),
|
||||
seCd: Number.isFinite(seCdNum) ? seCdNum : 0,
|
||||
inptBgngYmd: parseYmdToDate(row.inptBgngYmd),
|
||||
inptEndYmd: parseYmdToDate(row.inptEndYmd),
|
||||
});
|
||||
setPeriodDialogOpen(true);
|
||||
};
|
||||
|
||||
const columns: ColumnConfig[] = [
|
||||
{
|
||||
name: "sido",
|
||||
fieldName: "시도",
|
||||
header: { text: "시도" },
|
||||
mergeCells: true,
|
||||
name: "statsYr",
|
||||
fieldName: "statsYr",
|
||||
header: { text: "연도" },
|
||||
editable: false,
|
||||
sortdisable: true,
|
||||
},
|
||||
{
|
||||
name: "sgg",
|
||||
fieldName: "시군구",
|
||||
header: { text: "시군구" },
|
||||
mergeCells: true,
|
||||
name: "seType",
|
||||
fieldName: "seType",
|
||||
header: { text: "분류" },
|
||||
editable: false,
|
||||
sortdisable: true,
|
||||
},
|
||||
{
|
||||
name: "구분",
|
||||
fieldName: "구분",
|
||||
name: "seCd",
|
||||
fieldName: "seCd",
|
||||
header: { text: "구분" },
|
||||
editable: false,
|
||||
sortdisable: true,
|
||||
},
|
||||
{
|
||||
name: "광역자치단체",
|
||||
fieldName: "광역자치단체",
|
||||
header: { text: "광역자치단체" },
|
||||
name: "inptBgngYmd",
|
||||
fieldName: "inptBgngYmd",
|
||||
header: { text: "시작일" },
|
||||
editable: false,
|
||||
sortdisable: true,
|
||||
},
|
||||
{
|
||||
name: "공단",
|
||||
fieldName: "공단",
|
||||
header: { text: "공단" },
|
||||
name: "inptEndYmd",
|
||||
fieldName: "inptEndYmd",
|
||||
header: { text: "종료일" },
|
||||
editable: false,
|
||||
sortdisable: true,
|
||||
},
|
||||
{
|
||||
name: "처리내역",
|
||||
fieldName: "처리내역",
|
||||
header: { text: "처리내역" },
|
||||
editable: false,
|
||||
sortdisable: true,
|
||||
},
|
||||
];
|
||||
|
||||
const columnLayout = [
|
||||
"sido",
|
||||
"sgg",
|
||||
"구분",
|
||||
{
|
||||
name: "groupA",
|
||||
hideChildHeaders: false,
|
||||
header: { text: "검토내역" },
|
||||
items: ["광역자치단체", "공단", "처리내역"],
|
||||
},
|
||||
"statsYr",
|
||||
"seType",
|
||||
"seCd",
|
||||
"inptBgngYmd",
|
||||
"inptEndYmd",
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm sido={false} />
|
||||
<div className="relative">
|
||||
<SearchForm
|
||||
sido={false}
|
||||
gugun={false}
|
||||
clsf
|
||||
onSubmit={handleSearch}
|
||||
onReset={handleReset}
|
||||
onValuesChange={setSearchFormValues}
|
||||
/>
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] mx-[0.6rem]">
|
||||
<Button
|
||||
color="primary"
|
||||
className="h-[3.2rem] w-[96px]"
|
||||
type="button"
|
||||
onClick={handleRegisterClick}
|
||||
>
|
||||
<span>등록</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<DataGrid
|
||||
columnInfo={{ columns, columnLayout }}
|
||||
rowData={rowData}
|
||||
enableSort={false}
|
||||
setRowData={setRowData}
|
||||
isExcelImport={false}
|
||||
isExcelExport={false}
|
||||
onRowClick={handleRowClick}
|
||||
/>
|
||||
</>
|
||||
<StatisticsInputPeriodDialog
|
||||
open={periodDialogOpen}
|
||||
mode={periodDialogMode}
|
||||
createDefaultStatsYr={createDefaultStatsYr}
|
||||
onOpenChange={(open) => {
|
||||
setPeriodDialogOpen(open);
|
||||
if (!open) {
|
||||
setPeriodDialogInitial(null);
|
||||
setPeriodDialogMode("edit");
|
||||
}
|
||||
}}
|
||||
initial={periodDialogInitial}
|
||||
onSaveSuccess={async () => {
|
||||
const v = lastSearchRef.current;
|
||||
if (v) await handleSearch(v);
|
||||
}}
|
||||
/>
|
||||
{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]">
|
||||
<LoadingWithAnimation color="primary" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,315 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||
|
||||
import { useAlertStore } from "@/shared/lib";
|
||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||
import type {
|
||||
StatsInputPeriodDeleteRequest,
|
||||
StatsInputPeriodSaveRequest,
|
||||
} from "@/entities/statistics/model/statistics-interface";
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
Input,
|
||||
InputDatePicker,
|
||||
Label,
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@common/components";
|
||||
|
||||
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
||||
|
||||
export type StatisticsInputPeriodDialogValues = {
|
||||
statsYr: string;
|
||||
seType: "INPT" | "VRFC";
|
||||
seCd: number;
|
||||
inptBgngYmd: Date | undefined;
|
||||
inptEndYmd: Date | undefined;
|
||||
};
|
||||
|
||||
export type StatisticsInputPeriodDialogMode = "edit" | "create";
|
||||
|
||||
function normalizeStatsYrInput(raw: string): string {
|
||||
return raw.replace(/\D/g, "").slice(0, 4);
|
||||
}
|
||||
|
||||
function formatDateToYmd(d: Date | undefined): string | null {
|
||||
if (!d || Number.isNaN(d.getTime())) return null;
|
||||
const y = d.getFullYear();
|
||||
const m = String(d.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(d.getDate()).padStart(2, "0");
|
||||
return `${y}${m}${day}`;
|
||||
}
|
||||
|
||||
export interface StatisticsInputPeriodDialogProps {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
/** 행 클릭(수정) 시에만 전달. 등록 모드에서는 null */
|
||||
initial: StatisticsInputPeriodDialogValues | null;
|
||||
mode: StatisticsInputPeriodDialogMode;
|
||||
/** mode가 create일 때 SearchForm의 연도 */
|
||||
createDefaultStatsYr?: string;
|
||||
/** 저장 성공 후 목록 재조회 등 */
|
||||
onSaveSuccess?: () => void | Promise<void>;
|
||||
}
|
||||
|
||||
export function StatisticsInputPeriodDialog({
|
||||
open,
|
||||
onOpenChange,
|
||||
initial,
|
||||
mode,
|
||||
createDefaultStatsYr,
|
||||
onSaveSuccess,
|
||||
}: StatisticsInputPeriodDialogProps) {
|
||||
const { setMessage: alert } = useAlertStore((state) => state);
|
||||
const { confirm } = useConfirm();
|
||||
const [statsYr, setStatsYr] = useState("");
|
||||
const [seType, setSeType] = useState<"INPT" | "VRFC" | null>(null);
|
||||
const [seCdInput, setSeCdInput] = useState("");
|
||||
const [inptBgngYmd, setInptBgngYmd] = useState<Date | undefined>(undefined);
|
||||
const [inptEndYmd, setInptEndYmd] = useState<Date | undefined>(undefined);
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
if (mode === "create") {
|
||||
setStatsYr(normalizeStatsYrInput(createDefaultStatsYr ?? ""));
|
||||
setSeType(null);
|
||||
setSeCdInput("0");
|
||||
setInptBgngYmd(undefined);
|
||||
setInptEndYmd(undefined);
|
||||
return;
|
||||
}
|
||||
if (!initial) return;
|
||||
setStatsYr(normalizeStatsYrInput(String(initial.statsYr ?? "")));
|
||||
setSeType(initial.seType);
|
||||
setSeCdInput(String(Number.isFinite(initial.seCd) ? initial.seCd : 0));
|
||||
setInptBgngYmd(initial.inptBgngYmd);
|
||||
setInptEndYmd(initial.inptEndYmd);
|
||||
}, [open, mode, initial, createDefaultStatsYr]);
|
||||
|
||||
const handleSave = async () => {
|
||||
const bgng = formatDateToYmd(inptBgngYmd);
|
||||
const end = formatDateToYmd(inptEndYmd);
|
||||
if (!bgng || !end) {
|
||||
alert("시작일과 종료일을 선택해주세요.");
|
||||
return;
|
||||
}
|
||||
if (bgng > end) {
|
||||
alert("시작일은 종료일보다 늦을 수 없습니다.");
|
||||
return;
|
||||
}
|
||||
if (seType === null) {
|
||||
alert("분류를 선택해주세요.");
|
||||
return;
|
||||
}
|
||||
const seCdParsed =
|
||||
mode === "create"
|
||||
? 0
|
||||
: (() => {
|
||||
const n = parseInt(seCdInput, 10);
|
||||
return Number.isFinite(n) && n >= 0 ? n : NaN;
|
||||
})();
|
||||
if (mode === "edit" && !Number.isFinite(seCdParsed)) {
|
||||
alert("구분 값이 올바르지 않습니다.");
|
||||
return;
|
||||
}
|
||||
const yr = normalizeStatsYrInput(statsYr.trim());
|
||||
if (mode === "create" && !/^\d{4}$/.test(yr)) {
|
||||
alert("연도는 숫자 4자리로 입력해 주세요.");
|
||||
return;
|
||||
}
|
||||
if (mode === "edit" && !yr) {
|
||||
alert("연도가 없습니다.");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
setIsSubmitting(true);
|
||||
const userInfo = await getUserInfo();
|
||||
const param: StatsInputPeriodSaveRequest = {
|
||||
statsYr: yr,
|
||||
seType,
|
||||
seCd: seCdParsed,
|
||||
inptBgngYmd: bgng,
|
||||
inptEndYmd: end,
|
||||
rgtrId: userInfo.userUnqId,
|
||||
};
|
||||
const res = await statisticsApi.saveStatsInputPeriod(param);
|
||||
if (res.status === "success") {
|
||||
alert(`${isCreate ? '등록 되었습니다.' : '수정 되었습니다.'}`);
|
||||
onOpenChange(false);
|
||||
await onSaveSuccess?.();
|
||||
} else {
|
||||
alert(res.message || "저장에 실패했습니다.");
|
||||
}
|
||||
} catch {
|
||||
alert("저장 중 오류가 발생했습니다.");
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDelete = async () => {
|
||||
if (mode === "create" || !initial) return;
|
||||
if (!(await confirm("삭제하시겠습니까?"))) return;
|
||||
|
||||
const bgng = formatDateToYmd(initial.inptBgngYmd);
|
||||
const end = formatDateToYmd(initial.inptEndYmd);
|
||||
if (!bgng || !end) {
|
||||
alert("삭제할 기간 정보가 없습니다.");
|
||||
return;
|
||||
}
|
||||
const yr = normalizeStatsYrInput(String(initial.statsYr ?? ""));
|
||||
if (!yr) {
|
||||
alert("연도가 없습니다.");
|
||||
return;
|
||||
}
|
||||
const seCd =
|
||||
Number.isFinite(initial.seCd) && initial.seCd >= 0 ? initial.seCd : 0;
|
||||
|
||||
try {
|
||||
setIsSubmitting(true);
|
||||
const userInfo = await getUserInfo();
|
||||
const param: StatsInputPeriodDeleteRequest = {
|
||||
statsYr: yr,
|
||||
seType: initial.seType,
|
||||
seCd,
|
||||
inptBgngYmd: bgng,
|
||||
inptEndYmd: end,
|
||||
rgtrId: userInfo.userUnqId,
|
||||
};
|
||||
const res = await statisticsApi.deleteStatsInputPeriod(param);
|
||||
if (res.status === "success") {
|
||||
alert("삭제되었습니다.");
|
||||
onOpenChange(false);
|
||||
await onSaveSuccess?.();
|
||||
} else {
|
||||
alert(res.message || "삭제에 실패했습니다.");
|
||||
}
|
||||
} catch {
|
||||
alert("삭제 중 오류가 발생했습니다.");
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
const isCreate = mode === "create";
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent className="max-w-[48rem]" aria-describedby={undefined}>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{isCreate ? "입력 기간 등록" : "입력 관리"}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="flex flex-col gap-4 py-2">
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label className="text-label">연도</Label>
|
||||
{isCreate ? (
|
||||
<Input
|
||||
type="text"
|
||||
inputMode="numeric"
|
||||
maxLength={4}
|
||||
autoComplete="off"
|
||||
value={statsYr}
|
||||
onChange={(e) =>
|
||||
setStatsYr(normalizeStatsYrInput(e.target.value))
|
||||
}
|
||||
placeholder="예: 2025"
|
||||
disabled={isSubmitting}
|
||||
className="!text-[1.3rem]"
|
||||
/>
|
||||
) : (
|
||||
<Input
|
||||
value={statsYr}
|
||||
readOnly
|
||||
disabled
|
||||
className="!text-[1.3rem]"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label className="text-label">분류</Label>
|
||||
<Select
|
||||
value={seType ?? undefined}
|
||||
onValueChange={(v) => setSeType(v as "INPT" | "VRFC")}
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
<SelectTrigger className="w-full">
|
||||
<SelectValue placeholder="선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="INPT">입력</SelectItem>
|
||||
<SelectItem value="VRFC">검증</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
{!isCreate && (
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label className="text-label">구분</Label>
|
||||
<Input
|
||||
type="number"
|
||||
inputMode="numeric"
|
||||
min={0}
|
||||
value={seCdInput}
|
||||
disabled
|
||||
className="!text-[1.3rem]"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label className="text-label">시작일</Label>
|
||||
<InputDatePicker
|
||||
value={inptBgngYmd}
|
||||
onChange={setInptBgngYmd}
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label className="text-label">종료일</Label>
|
||||
<InputDatePicker
|
||||
value={inptEndYmd}
|
||||
onChange={setInptEndYmd}
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<DialogClose asChild>
|
||||
<Button type="button" color="gray" disabled={isSubmitting}>
|
||||
닫기
|
||||
</Button>
|
||||
</DialogClose>
|
||||
{!isCreate && (
|
||||
<Button
|
||||
type="button"
|
||||
color="red"
|
||||
disabled={isSubmitting}
|
||||
onClick={() => void handleDelete()}
|
||||
>
|
||||
삭제
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
type="button"
|
||||
color="green"
|
||||
disabled={isSubmitting}
|
||||
onClick={() => void handleSave()}
|
||||
>
|
||||
{isCreate ? '등록' : '수정'}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
@@ -9,8 +9,8 @@ import ApproveButton from "@/components/button/ApproveButton";
|
||||
import ReturnButton from "@/components/button/ReturnButton";
|
||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import DataGrid from "@/components/module/DataGrid";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import type { ColumnConfig, ColumnInfo, ColumnInfoList } from "@/components/type/DataGrid.type";
|
||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||
import { SewagePipeMaintainColumnInfoList } from "@/components/util/column/review/SewagePipeMaintainRvwColumn";
|
||||
@@ -40,10 +40,12 @@ function getListDataByTab(tabKey: string, responseData: unknown): object[] {
|
||||
return [];
|
||||
}
|
||||
if (tabKey === "ST00030001") {
|
||||
return (((responseData as { mtcStatusList?: unknown[] }).mtcStatusList) ?? []) as object[];
|
||||
const list = (responseData as { sewerPipeMtcList?: unknown }).sewerPipeMtcList;
|
||||
return Array.isArray(list) ? (list as object[]) : [];
|
||||
}
|
||||
if (tabKey === "ST00030002") {
|
||||
return (((responseData as { drdgStatusList?: unknown[] }).drdgStatusList) ?? []) as object[];
|
||||
const list = (responseData as { sewerPipeDrdgList?: unknown }).sewerPipeDrdgList;
|
||||
return Array.isArray(list) ? (list as object[]) : [];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
import { useRef, useState } from "react";
|
||||
import { useMemo, useRef, useState } from "react";
|
||||
|
||||
import { useAlertStore } from "@/shared/lib";
|
||||
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
||||
import type { SewagePipeReviewRequestParams } from "@/entities/statistics/model/statistics-sewage-pipe-review-interface";
|
||||
import type {
|
||||
SewagePipeReviewRequestParams,
|
||||
StatsStatusInfo,
|
||||
} from "@/entities/statistics/model/statistics-sewage-pipe-review-interface";
|
||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components";
|
||||
|
||||
import ApproveButton from "@/components/button/ApproveButton";
|
||||
import SubmitButton from "@/components/button/SumitButton";
|
||||
import ReturnButton from "@/components/button/ReturnButton";
|
||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
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 { SewagePipeColumnInfoListRvw } from "@/components/util/column/review/SewagePipeRvwColumn";
|
||||
@@ -37,20 +39,73 @@ async function fetchSewagePipeReviewTab(
|
||||
return null;
|
||||
}
|
||||
|
||||
function extractReviewRowsFromResponseData(
|
||||
tabKey: string,
|
||||
data: unknown,
|
||||
): object[] {
|
||||
if (Array.isArray(data)) return data as object[];
|
||||
if (!data || typeof data !== "object") return [];
|
||||
|
||||
const d = data as Record<string, unknown>;
|
||||
switch (tabKey) {
|
||||
case "ST00020001":
|
||||
return Array.isArray(d.regionalStatusList) ? (d.regionalStatusList as object[]) : [];
|
||||
case "ST00020002":
|
||||
return Array.isArray(d.facilityStatusList) ? (d.facilityStatusList as object[]) : [];
|
||||
case "ST00020003":
|
||||
return Array.isArray(d.pipeTypeList) ? (d.pipeTypeList as object[]) : [];
|
||||
case "ST00020004":
|
||||
return Array.isArray(d.pipeDiamList) ? (d.pipeDiamList as object[]) : [];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function extractStatsStatusInfo(data: unknown): StatsStatusInfo | null {
|
||||
if (!data || typeof data !== "object") return null;
|
||||
const ssi = (data as { statsStatusInfo?: StatsStatusInfo }).statsStatusInfo;
|
||||
return ssi && typeof ssi === "object" ? ssi : null;
|
||||
}
|
||||
|
||||
// 하수도 통계 검토 02.하수관로
|
||||
const SewagePipeRvw = () => {
|
||||
const { setMessage: alert } = useAlertStore((state) => state);
|
||||
const [rowDataMap, setRowDataMap] = useState<Map<string, Record<string, string | number>[]>>(new Map());
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [activeTab, setActiveTab] = useState<string>(firstTabKey);
|
||||
/** 탭별 조회 응답의 statsStatusInfo — 활성 탭에 맞춰 버튼 노출 (SewagePipeInp의 tabStatusInfoMap과 동일 패턴) */
|
||||
const [tabStatsStatusInfoMap, setTabStatsStatusInfoMap] = useState<
|
||||
Map<string, StatsStatusInfo>
|
||||
>(new Map());
|
||||
|
||||
const searchParamRef = useRef<SewagePipeReviewRequestParams | null>(null);
|
||||
const searchDoneRef = useRef(false);
|
||||
const lazyTabLoggedRef = useRef<Set<string>>(new Set());
|
||||
|
||||
const { showReviewOpinionButton, showReturnButton, showSubmitButton } = useMemo(() => {
|
||||
const statsStatusInfo = tabStatsStatusInfoMap.get(activeTab) ?? {};
|
||||
const submit =
|
||||
statsStatusInfo.submitStatusCd != null
|
||||
? String(statsStatusInfo.submitStatusCd)
|
||||
: "";
|
||||
const prvn =
|
||||
statsStatusInfo.prvnStatusCd != null ? String(statsStatusInfo.prvnStatusCd) : "";
|
||||
const submitIs3 = submit === "3";
|
||||
const reviewSubmitVisible = submitIs3 && (prvn === "0" || prvn === "1");
|
||||
return {
|
||||
showReviewOpinionButton: reviewSubmitVisible,
|
||||
showSubmitButton: reviewSubmitVisible,
|
||||
showReturnButton: submitIs3 && prvn !== "3",
|
||||
};
|
||||
}, [tabStatsStatusInfoMap, activeTab]);
|
||||
|
||||
const showActionBar =
|
||||
showReviewOpinionButton || showReturnButton || showSubmitButton;
|
||||
|
||||
const handleReset = () => {
|
||||
setRowDataMap(new Map());
|
||||
setActiveTab(firstTabKey);
|
||||
setTabStatsStatusInfoMap(new Map());
|
||||
searchParamRef.current = null;
|
||||
searchDoneRef.current = false;
|
||||
lazyTabLoggedRef.current.clear();
|
||||
@@ -79,15 +134,24 @@ const SewagePipeRvw = () => {
|
||||
const response = await fetchSewagePipeReviewTab(activeTab, searchParam);
|
||||
|
||||
if (response?.status === "success" && response.data) {
|
||||
const ssi = extractStatsStatusInfo(response.data);
|
||||
setTabStatsStatusInfoMap((prev) => {
|
||||
const next = new Map(prev);
|
||||
next.set(activeTab, ssi ?? {});
|
||||
return next;
|
||||
});
|
||||
const rows = extractReviewRowsFromResponseData(activeTab, response.data);
|
||||
setRowDataMap((prev) => {
|
||||
const next = new Map(prev);
|
||||
next.set(activeTab, toGridRows(response.data as object[]));
|
||||
next.set(activeTab, toGridRows(rows));
|
||||
return next;
|
||||
});
|
||||
} else {
|
||||
setTabStatsStatusInfoMap(new Map());
|
||||
alert(response?.message || "데이터 조회 중 오류가 발생했습니다.");
|
||||
}
|
||||
} catch {
|
||||
setTabStatsStatusInfoMap(new Map());
|
||||
alert("데이터 조회 중 오류가 발생했습니다.");
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
@@ -118,9 +182,16 @@ const SewagePipeRvw = () => {
|
||||
lazyTabLoggedRef.current.add(tabKey);
|
||||
|
||||
if (response?.status === "success" && response.data) {
|
||||
const ssi = extractStatsStatusInfo(response.data);
|
||||
setTabStatsStatusInfoMap((prev) => {
|
||||
const next = new Map(prev);
|
||||
next.set(tabKey, ssi ?? {});
|
||||
return next;
|
||||
});
|
||||
const rows = extractReviewRowsFromResponseData(tabKey, response.data);
|
||||
setRowDataMap((prev) => {
|
||||
const next = new Map(prev);
|
||||
next.set(tabKey, toGridRows(response.data as object[]));
|
||||
next.set(tabKey, toGridRows(rows));
|
||||
return next;
|
||||
});
|
||||
} else {
|
||||
@@ -137,14 +208,19 @@ const SewagePipeRvw = () => {
|
||||
<div className="relative">
|
||||
<SearchForm onSubmit={handleSearch} onReset={handleReset} />
|
||||
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<ReviewOpinionButton reviewOpinionFunc={() => { }} />
|
||||
<ApproveButton approveFunc={() => { }} />
|
||||
<ReturnButton returnFunc={() => { }} />
|
||||
<SaveButton saveFunc={() => { }} />
|
||||
{showActionBar && (
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
{showReviewOpinionButton && (
|
||||
<ReviewOpinionButton reviewOpinionFunc={() => {}} />
|
||||
)}
|
||||
{showReturnButton && <ReturnButton returnFunc={() => {}} />}
|
||||
{showSubmitButton && (
|
||||
<SubmitButton submitFunc={() => {}} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{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]">
|
||||
|
||||
@@ -1,9 +1,79 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||
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 { 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 [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const { setMessage: alert } = useAlertStore((state) => state);
|
||||
|
||||
const handleSearch = async (values: SearchFormValues) => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
|
||||
const isSummaryEnabled = values.isSummary !== 'ALL';
|
||||
const summaryYearCnt = isSummaryEnabled ? Number(values.isSummary) : undefined;
|
||||
|
||||
const param = {
|
||||
ctpvNm: values.sido === 'ALL' ? '' : values.sido,
|
||||
sggNm: values.gugun === 'ALL' ? '' : values.gugun,
|
||||
sewerBzmnCd: values.bsnmCd,
|
||||
statsYr: values.year,
|
||||
rowDataYn: values.isDetail,
|
||||
summaryYn: isSummaryEnabled,
|
||||
...(isSummaryEnabled ? { summaryYearCnt } : {}),
|
||||
};
|
||||
|
||||
const response = await statisticsTotalStatusApi.getSewagePublicFacillityTotal(param);
|
||||
|
||||
if (response.status === 'success') {
|
||||
setRowData(toGridRows(response.data));
|
||||
} else {
|
||||
alert(response.message || '데이터 조회 중 오류가 발생했습니다.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
alert('데이터 조회 중 오류가 발생했습니다.');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm />
|
||||
<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">
|
||||
<div className="relative size-[5rem]">
|
||||
<LoadingWithAnimation color="primary" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<CellColorInfo />
|
||||
<DataGrid
|
||||
columnInfo={PublicSewageFacilityColumn}
|
||||
rowStartNum={2}
|
||||
isExcelImport={false}
|
||||
fixedColumns={2}
|
||||
rowData={rowData}
|
||||
setRowData={setRowData}
|
||||
cellStyleCallback={({ row }) => {
|
||||
const rowType = String(row.rowType ?? '');
|
||||
if (rowType === 'DETAIL') return undefined;
|
||||
if (rowType === 'BIZ_SUM') return 'rg-cell-rowtype-biz-sum';
|
||||
if (rowType === 'SUMMARY') return 'rg-cell-rowtype-summary';
|
||||
return 'rg-cell-rowtype-other';
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -25,6 +25,7 @@ function buildSewagePipeTotSearchParam(values: SearchFormValues): SewagePipeTota
|
||||
sewerBzmnCd: values.bsnmCd,
|
||||
statsYr: values.year,
|
||||
rowDataYn: values.isDetail,
|
||||
summaryYn: isSummaryEnabled,
|
||||
...(isSummaryEnabled ? { summaryYearCnt } : {}),
|
||||
};
|
||||
}
|
||||
@@ -106,6 +107,15 @@ const SewagePipeTot = () => {
|
||||
alert(response.message || "데이터 조회 중 오류가 발생했습니다.");
|
||||
return false;
|
||||
}
|
||||
if (tabKey === "ST00020005") {
|
||||
const response = await statisticsTotalStatusApi.getSewagePipePipeMnhleStatus(param);
|
||||
if (response.status === "success" && response.data) {
|
||||
applyRows(toGridRows(response.data as object[]));
|
||||
return true;
|
||||
}
|
||||
alert(response.message || "데이터 조회 중 오류가 발생했습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
@@ -120,7 +130,8 @@ const SewagePipeTot = () => {
|
||||
activeTab === "ST00020001" ||
|
||||
activeTab === "ST00020002" ||
|
||||
activeTab === "ST00020003" ||
|
||||
activeTab === "ST00020004"
|
||||
activeTab === "ST00020004" ||
|
||||
activeTab === "ST00020005"
|
||||
) {
|
||||
ok = await loadSewagePipeTotTabData(activeTab, values, true);
|
||||
}
|
||||
@@ -151,7 +162,8 @@ const SewagePipeTot = () => {
|
||||
tabKey === "ST00020001" ||
|
||||
tabKey === "ST00020002" ||
|
||||
tabKey === "ST00020003" ||
|
||||
tabKey === "ST00020004"
|
||||
tabKey === "ST00020004" ||
|
||||
tabKey === "ST00020005"
|
||||
) {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
|
||||
@@ -114,10 +114,10 @@ export default function HbStatisticsVerification() {
|
||||
|
||||
const [verifyType, setVerifyType] = useState<VerifyType>("ALL");
|
||||
const [formState, setFormState] = useState<VerificationFormState>({
|
||||
mu: "0",
|
||||
percentile: "0",
|
||||
a: "0",
|
||||
c: "0",
|
||||
mu: "",
|
||||
percentile: "",
|
||||
a: "",
|
||||
c: "",
|
||||
verificationYear: defaultYear,
|
||||
});
|
||||
const [selectedTargets, setSelectedTargets] = useState<string[]>([]);
|
||||
@@ -559,11 +559,14 @@ export default function HbStatisticsVerification() {
|
||||
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center gap-4">
|
||||
<Label className="w-32 text-label">
|
||||
μ
|
||||
<Label className="w-48 whitespace-nowrap text-label">
|
||||
중요도 계수(μ)
|
||||
</Label>
|
||||
<Input
|
||||
type="number"
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.1"
|
||||
value={formState.mu}
|
||||
onChange={(event) =>
|
||||
handleFormChange(
|
||||
@@ -572,15 +575,19 @@ export default function HbStatisticsVerification() {
|
||||
)
|
||||
}
|
||||
className="flex-1"
|
||||
placeholder="(0 ~ 1, 0.1 단위)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
<Label className="w-32 text-label">
|
||||
Percentile
|
||||
<Label className="w-48 text-label">
|
||||
백분위수 기준값(pct)
|
||||
</Label>
|
||||
<Input
|
||||
type="number"
|
||||
min="0"
|
||||
max="0.5"
|
||||
step="0.01"
|
||||
value={formState.percentile}
|
||||
onChange={(event) =>
|
||||
handleFormChange(
|
||||
@@ -589,15 +596,19 @@ export default function HbStatisticsVerification() {
|
||||
)
|
||||
}
|
||||
className="flex-1"
|
||||
placeholder="(0 ~ 0.5, 0.01 단위)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
<Label className="w-32 text-label">
|
||||
A
|
||||
<Label className="w-48 text-label">
|
||||
스케일 조정 계수(A)
|
||||
</Label>
|
||||
<Input
|
||||
type="number"
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.01"
|
||||
value={formState.a}
|
||||
onChange={(event) =>
|
||||
handleFormChange(
|
||||
@@ -606,15 +617,19 @@ export default function HbStatisticsVerification() {
|
||||
)
|
||||
}
|
||||
className="flex-1"
|
||||
placeholder="(0 ~ 1, 0.01 단위)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
<Label className="w-32 text-label">
|
||||
C
|
||||
<Label className="w-48 text-label">
|
||||
임계 계수(c)
|
||||
</Label>
|
||||
<Input
|
||||
type="number"
|
||||
min="0"
|
||||
max="100"
|
||||
step="1"
|
||||
value={formState.c}
|
||||
onChange={(event) =>
|
||||
handleFormChange(
|
||||
@@ -623,6 +638,7 @@ export default function HbStatisticsVerification() {
|
||||
)
|
||||
}
|
||||
className="flex-1"
|
||||
placeholder="(0 ~ 100, 1 단위)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,6 @@ import { useEffect, useState } from "react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Search } from "lucide-react";
|
||||
|
||||
import { CodeSelect } from "@/entities/code/ui/code-select";
|
||||
import { verificationTargetManagementApi } from "@/entities/statistics/api/verification-target-management-service";
|
||||
@@ -368,7 +367,7 @@ export function VerificationTargetDialog({
|
||||
type="number"
|
||||
min="0"
|
||||
max="0.5"
|
||||
step="0.1"
|
||||
step="0.01"
|
||||
value={
|
||||
field.value ??
|
||||
""
|
||||
@@ -385,7 +384,7 @@ export function VerificationTargetDialog({
|
||||
: null,
|
||||
)
|
||||
}
|
||||
placeholder="(0 ~ 0.5, 0.1 단위)"
|
||||
placeholder="(0 ~ 0.5, 0.01 단위)"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -369,6 +369,10 @@ export type SplitDataGridProps = {
|
||||
leftOnRowClick?: (rowData: Record<string, string | number>) => void;
|
||||
/** 좌측 분할 그리드 셀 스타일 콜백 */
|
||||
leftCellStyleCallback?: CellStyleCallback;
|
||||
/** 우측 분할 그리드 행 체크 변경 */
|
||||
rightOnItemChecked?: (itemIndex: number, checked: boolean) => void;
|
||||
/** 우측 분할 그리드 헤더 전체 체크 변경 */
|
||||
rightOnItemAllChecked?: (checked: boolean) => void;
|
||||
/** 전체 정렬 기능 on/off (기본값: false) */
|
||||
enableSort?: boolean;
|
||||
};
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/** 통계 분류: 전체 / 입력 / 검증 */
|
||||
export type SearchFormClsfCd = "ALL" | "INPT" | "VRFC";
|
||||
|
||||
export type SearchFormValues = {
|
||||
sido?: string;
|
||||
gugun?: string;
|
||||
@@ -7,6 +10,8 @@ export type SearchFormValues = {
|
||||
bsnmCd?: string;
|
||||
isDetail?: boolean;
|
||||
isSummary?: string;
|
||||
/** 분류: 전체(ALL), 입력(INPT), 검증(VRFC) */
|
||||
clsfCd?: SearchFormClsfCd;
|
||||
};
|
||||
|
||||
export type SearchFormProps = {
|
||||
@@ -16,6 +21,8 @@ export type SearchFormProps = {
|
||||
year?: boolean;
|
||||
order?: boolean;
|
||||
fctName?: boolean;
|
||||
/** 분류(입력/검증) 셀렉트 표시 */
|
||||
clsf?: boolean;
|
||||
userMenual?: boolean;
|
||||
isDetail?: boolean;
|
||||
isSummary?: boolean;
|
||||
@@ -33,6 +40,7 @@ export const defaultSearchFormProps: Required<
|
||||
year: true,
|
||||
order: false,
|
||||
fctName: false,
|
||||
clsf: false,
|
||||
userMenual: false,
|
||||
isDetail: false,
|
||||
isSummary: false,
|
||||
|
||||
+2
@@ -46,6 +46,7 @@ export const MainFacilityTargetColumn = {
|
||||
|
||||
{ name: 'fcltSn', fieldName: 'fcltSn', header: { text: '처리시설일련번호' }, visible: false, editable: false, valueType: ValueType.TEXT, styleName: 'rg-cell-readonly' },
|
||||
{ name: 'swtrmtFcltCd', fieldName: 'swtrmtFcltCd', header: { text: '하수처리시설코드' }, visible: false, editable: false, styleName: 'rg-cell-readonly' },
|
||||
{ name: 'admdstCd', fieldName: 'admdstCd', header: { text: '행정구역코드' }, visible: false, editable: false, styleName: 'rg-cell-readonly' },
|
||||
{ name: 'admdstNm', fieldName: 'admdstNm', header: { text: '행정구역명' }, visible: false, editable: false, styleName: 'rg-cell-readonly' },
|
||||
{ name: 'mainFcltSn', fieldName: 'mainFcltSn', header: { text: '연결된중심시설일련번호' }, visible: false, editable: false, styleName: 'rg-cell-readonly' },
|
||||
{ name: 'isMainYn', fieldName: 'isMainYn', header: { text: '중심처리시설여부' }, visible: false, editable: false, styleName: 'rg-cell-readonly' },
|
||||
@@ -56,6 +57,7 @@ export const MainFacilityTargetColumn = {
|
||||
'mappedYn',
|
||||
'fcltSn',
|
||||
'swtrmtFcltCd',
|
||||
'admdstCd',
|
||||
'admdstNm',
|
||||
'mainFcltSn',
|
||||
'isMainYn',
|
||||
|
||||
+3
-3
@@ -21,9 +21,9 @@ export const PublicSewageFactColumn = {
|
||||
{ name: 'prcsFcltCpct', fieldName: 'prcsFcltCpct', header: { text: '시설용량(500m³/일 이상/미만)' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0', styleName: 'rg-cell-total' },
|
||||
|
||||
// (m³/일)
|
||||
{ name: 'prcsFcltPhysCpct', fieldName: 'prcsFcltPhysCpct', header: { text: '물리적' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'prcsFcltBoilCpct', fieldName: 'prcsFcltBoilCpct', header: { text: '생물학적' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'prcsFcltAltdCpct', fieldName: 'prcsFcltAltdCpct', header: { text: '고도' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'prcsFcltPhysCpct', fieldName: 'prcsFcltPhysCpct', header: { text: '물리적' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'prcsFcltBoilCpct', fieldName: 'prcsFcltBoilCpct', header: { text: '생물학적' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'prcsFcltAltdCpct', fieldName: 'prcsFcltAltdCpct', header: { text: '고도' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
|
||||
// 유입하수량
|
||||
{ name: 'inflwSwageQnt', fieldName: 'inflwSwageQnt', header: { text: '유입하수량(500m³/일 이상/미만)' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0', styleName: 'rg-cell-readonly' },
|
||||
|
||||
@@ -0,0 +1,298 @@
|
||||
import { ValueType } from "realgrid";
|
||||
/**
|
||||
* 하수도 통계 관리 > 06. 공공하수처리시설
|
||||
* 단일 Tab
|
||||
*/
|
||||
export const PublicSewageFacilityColumn = {
|
||||
columns: [
|
||||
// 행정구역
|
||||
{ name: 'ctpvNm', fieldName: 'ctpvNm', header: { text: '시도' }, editable: false },
|
||||
{ name: 'sggNm', fieldName: 'sggNm', header: { text: '시군구' }, editable: false },
|
||||
{ name: 'admdstNm', fieldName: 'admdstNm', header: { text: '행정구역명' }, editable: false },
|
||||
|
||||
// 시설명 (500㎥/일 이상/미만)
|
||||
{ name: 'swtrmtFcltNm', fieldName: 'swtrmtFcltNm', header: { text: '시설명\n(500㎥/일\n이상/미만)' }, editable: false },
|
||||
|
||||
// 소재지
|
||||
{ name: 'fcltPstnCn', fieldName: 'fcltPstnCn', header: { text: '소재지' }, editable: false },
|
||||
|
||||
// 시설용량 (㎥/일)
|
||||
{
|
||||
name: 'prcsFcltCpct',
|
||||
fieldName: 'prcsFcltCpct',
|
||||
header: { text: ' 시설용량 500㎥/일\n이상/미만' },
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0',
|
||||
},
|
||||
{
|
||||
name: 'prcsFcltPhysCpct',
|
||||
fieldName: 'prcsFcltPhysCpct',
|
||||
header: { text: '물리적' },
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0.00',
|
||||
},
|
||||
{
|
||||
name: 'prcsFcltBoilCpct',
|
||||
fieldName: 'prcsFcltBoilCpct',
|
||||
header: { text: '생물학적' },
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0.00',
|
||||
},
|
||||
{
|
||||
name: 'prcsFcltAltdCpct',
|
||||
fieldName: 'prcsFcltAltdCpct',
|
||||
header: { text: '고도' },
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0.00',
|
||||
},
|
||||
|
||||
// 유입하수량 (㎥/일)
|
||||
{
|
||||
name: 'inflwSwageQnt',
|
||||
fieldName: 'inflwSwageQnt',
|
||||
header: { text: '유입하수량 500㎥/일\n이상/미만' },
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0.00',
|
||||
},
|
||||
{
|
||||
name: 'inflwSwagePhysQnt',
|
||||
fieldName: 'inflwSwagePhysQnt',
|
||||
header: { text: '물리적' },
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0.00',
|
||||
},
|
||||
{
|
||||
name: 'inflwSwageBoilQnt',
|
||||
fieldName: 'inflwSwageBoilQnt',
|
||||
header: { text: '생물학적' },
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0.00',
|
||||
},
|
||||
{
|
||||
name: 'inflwSwageAltdQnt',
|
||||
fieldName: 'inflwSwageAltdQnt',
|
||||
header: { text: '고도' },
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0.00',
|
||||
},
|
||||
|
||||
// 방류량 (㎥/일)
|
||||
{
|
||||
name: 'prcsQnt',
|
||||
fieldName: 'prcsQnt',
|
||||
header: { text: '방류량 500㎥/일\n이상/미만' },
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0.00',
|
||||
},
|
||||
{
|
||||
name: 'prcsPhysCpct',
|
||||
fieldName: 'prcsPhysCpct',
|
||||
header: { text: '물리적' },
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0.00',
|
||||
},
|
||||
{
|
||||
name: 'prcsBoilCpct',
|
||||
fieldName: 'prcsBoilCpct',
|
||||
header: { text: '생물학적' },
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0.00',
|
||||
},
|
||||
{
|
||||
name: 'prcsAltdCpct',
|
||||
fieldName: 'prcsAltdCpct',
|
||||
header: { text: '고도' },
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0.00',
|
||||
},
|
||||
|
||||
// 수질 정보 - 유입/방류 교차
|
||||
{ name: 'inflwBodVl', fieldName: 'inflwBodVl', header: { text: '유입\nBOD' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
{ name: 'dschgBodVl', fieldName: 'dschgBodVl', header: { text: '방류\nBOD' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
{ name: 'inflwTocQnt', fieldName: 'inflwTocQnt', header: { text: '유입\nTOC' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
{ name: 'dschgTocQnt', fieldName: 'dschgTocQnt', header: { text: '방류\nTOC' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
{ name: 'inflwSsQnt', fieldName: 'inflwSsQnt', header: { text: '유입\nSS' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
{ name: 'dschgSsQnt', fieldName: 'dschgSsQnt', header: { text: '방류\nSS' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
{ name: 'inflwTnVl', fieldName: 'inflwTnVl', header: { text: '유입\nT-N' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
{ name: 'dschgTnVl', fieldName: 'dschgTnVl', header: { text: '방류\nT-N' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
{ name: 'inflwTpVl', fieldName: 'inflwTpVl', header: { text: '유입\nT-P' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
{ name: 'dschgTpVl', fieldName: 'dschgTpVl', header: { text: '방류\nT-P' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
{ name: 'inflwGrssClfgVl', fieldName: 'inflwGrssClfgVl', header: { text: '유입\n총대장균군수' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
{ name: 'dschgGrssClfgVl', fieldName: 'dschgGrssClfgVl', header: { text: '방류\n총대장균군수' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
|
||||
// 처리 효율 및 방법
|
||||
{
|
||||
name: 'prcsRt',
|
||||
fieldName: 'prcsRt',
|
||||
header: { text: '처리\n효율(%)' },
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0.0',
|
||||
},
|
||||
{
|
||||
name: 'prcsLodQnt',
|
||||
fieldName: 'prcsLodQnt',
|
||||
header: { text: '처리부하량\n(kg BOD/D)' },
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0',
|
||||
},
|
||||
{ name: 'prcsMthdExpln', fieldName: 'prcsMthdExpln', header: { text: '처리\n방법' }, editable: false },
|
||||
|
||||
// 연계처리량 (㎥/일)
|
||||
{ name: 'wholHmnQnt', fieldName: 'wholHmnQnt', header: { text: '분뇨' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'wholLvstQnt', fieldName: 'wholLvstQnt', header: { text: '축산' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'wholEfntQnt', fieldName: 'wholEfntQnt', header: { text: '침출수' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'wholEtcQnt', fieldName: 'wholEtcQnt', header: { text: '기타' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 부가 정보
|
||||
{ name: 'telNo', fieldName: 'telNo', header: { text: '전화번호' }, editable: false },
|
||||
{ name: 'cmptnStrtYmd', fieldName: 'cmptnStrtYmd', header: { text: '준공일' }, editable: false },
|
||||
{ name: 'oprtngStrtYmd', fieldName: 'oprtngStrtYmd', header: { text: '가동개시일' }, editable: false },
|
||||
{ name: 'wholBizVl', fieldName: 'wholBizVl', header: { text: '사업비\n(백만원)' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.00' },
|
||||
{ name: 'eflntDsnfMthdExpln', fieldName: 'eflntDsnfMthdExpln', header: { text: '방류수\n소독방법' }, editable: false },
|
||||
|
||||
// 방류수역 정보
|
||||
{ name: 'wtsysNm', fieldName: 'wtsysNm', header: { text: '수계' }, editable: false },
|
||||
{ name: 'trbtrNm', fieldName: 'trbtrNm', header: { text: '지류' }, editable: false },
|
||||
{ name: 'dtlUnitZoneCn', fieldName: 'dtlUnitZoneCn', header: { text: '세부단위구역' }, editable: false },
|
||||
{ name: 'rgnSeNm', fieldName: 'rgnSeNm', header: { text: '지역구분' }, editable: false },
|
||||
|
||||
// 중권역
|
||||
{ name: 'msirbCn', fieldName: 'msirbCn', header: { text: '명칭' }, editable: false },
|
||||
{ name: 'goalWqNo', fieldName: 'goalWqNo', header: { text: '목표수질\n(BOD)' }, editable: false },
|
||||
|
||||
// 에너지
|
||||
{ name: 'engySrlneRt', fieldName: 'engySrlneRt', header: { text: '에너지\n자립율(%)' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'engyItslfPrdctnQnt', fieldName: 'engyItslfPrdctnQnt', header: { text: '에너지\n자체생산량\n(TOE)' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.00' },
|
||||
{ name: 'anlEngyWholUseQnt', fieldName: 'anlEngyWholUseQnt', header: { text: '계(TOE)' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.00' },
|
||||
{ name: 'anlElpwrUseQnt', fieldName: 'anlElpwrUseQnt', header: { text: '총전력사용량\n(kWh)' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.00' },
|
||||
{ name: 'itslfEngyUseQnt', fieldName: 'itslfEngyUseQnt', header: { text: '자체에너지\n사용량(TOE)' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.00' },
|
||||
{ name: 'swtrmtEmsnQnt', fieldName: 'swtrmtEmsnQnt', header: { text: '하수처리량당\nCO2배출량\n(㎏CO2/㎥)' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
|
||||
// 운영주체
|
||||
{ name: 'operMnbdCn', fieldName: 'operMnbdCn', header: { text: '운영주체\n(자체/공기업/\n민간대행)' }, editable: false },
|
||||
|
||||
// 위탁현황
|
||||
{ name: 'prxyBzentyNmCn', fieldName: 'prxyBzentyNmCn', header: { text: '위탁\n업체명' }, editable: false },
|
||||
{ name: 'cnsgnCstVl', fieldName: 'cnsgnCstVl', header: { text: '위탁비용\n(백만원/년)' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.00' },
|
||||
{ name: 'prxyCtrtCn', fieldName: 'prxyCtrtCn', header: { text: '위탁계약기간\n(yyyy-mm-dd\n~\nyyyy-mm-dd)' }, editable: false },
|
||||
{ name: 'intgPrcsFcltCn', fieldName: 'intgPrcsFcltCn', header: { text: '중심처리시설' }, editable: false },
|
||||
{ name: 'wholNope', fieldName: 'wholNope', header: { text: '직원총수\n(명)' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'sftyAcdntEvntcsCnt', fieldName: 'sftyAcdntEvntcsCnt', header: { text: '안전사고건수' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// hidden
|
||||
{ name: 'admdstCd', fieldName: 'admdstCd', header: { text: '행정구역코드' }, visible: false },
|
||||
{ name: 'rowType', fieldName: 'rowType', header: { text: '데이터구분' }, visible: false },
|
||||
{ name: 'statsYr', fieldName: 'statsYr', header: { text: '통계연도' }, visible: false },
|
||||
].map((col) => ({ ...col, editable: false })),
|
||||
|
||||
columnLayout: [
|
||||
{
|
||||
name: 'groupA',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '행정구역' },
|
||||
items: ['ctpvNm', 'sggNm', 'admdstNm'],
|
||||
},
|
||||
'swtrmtFcltNm',
|
||||
'fcltPstnCn',
|
||||
'prcsFcltCpct',
|
||||
{
|
||||
name: 'groupCapacity',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '(㎥/일)' },
|
||||
items: [ 'prcsFcltPhysCpct', 'prcsFcltBoilCpct', 'prcsFcltAltdCpct'],
|
||||
},
|
||||
'inflwSwageQnt',
|
||||
{
|
||||
name: 'groupInflw',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '(㎥/일)' },
|
||||
items: [ 'inflwSwagePhysQnt', 'inflwSwageBoilQnt', 'inflwSwageAltdQnt'],
|
||||
},
|
||||
'prcsQnt',
|
||||
{
|
||||
name: 'groupPrcs',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '(㎥/일)' },
|
||||
items: [ 'prcsPhysCpct', 'prcsBoilCpct', 'prcsAltdCpct'],
|
||||
},
|
||||
'inflwBodVl',
|
||||
'dschgBodVl',
|
||||
'inflwTocQnt',
|
||||
'dschgTocQnt',
|
||||
'inflwSsQnt',
|
||||
'dschgSsQnt',
|
||||
'inflwTnVl',
|
||||
'dschgTnVl',
|
||||
'inflwTpVl',
|
||||
'dschgTpVl',
|
||||
'inflwGrssClfgVl',
|
||||
'dschgGrssClfgVl',
|
||||
'prcsRt',
|
||||
'prcsLodQnt',
|
||||
'prcsMthdExpln',
|
||||
{
|
||||
name: 'groupLinkPrcs',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '연계처리량(㎥/일)\n(500㎥/일 이상/미만)' },
|
||||
items: ['wholHmnQnt', 'wholLvstQnt', 'wholEfntQnt', 'wholEtcQnt'],
|
||||
},
|
||||
'telNo',
|
||||
'cmptnStrtYmd',
|
||||
'oprtngStrtYmd',
|
||||
'wholBizVl',
|
||||
'eflntDsnfMthdExpln',
|
||||
{
|
||||
name: 'groupDschgWater',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '방류수역' },
|
||||
items: [
|
||||
'wtsysNm',
|
||||
'trbtrNm',
|
||||
'dtlUnitZoneCn',
|
||||
'rgnSeNm',
|
||||
{
|
||||
name: 'groupMsirbCn',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '중권역' },
|
||||
items: ['msirbCn', 'goalWqNo'],
|
||||
},
|
||||
],
|
||||
},
|
||||
'engySrlneRt',
|
||||
'engyItslfPrdctnQnt',
|
||||
{
|
||||
name: 'groupEngyUse',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '연간 총 에너지 사용량(TOE)' },
|
||||
items: ['anlEngyWholUseQnt', 'anlElpwrUseQnt', 'itslfEngyUseQnt'],
|
||||
},
|
||||
'swtrmtEmsnQnt',
|
||||
'operMnbdCn',
|
||||
{
|
||||
name: 'groupCnsgn',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '위탁현황' },
|
||||
items: ['prxyBzentyNmCn', 'cnsgnCstVl', 'prxyCtrtCn'],
|
||||
},
|
||||
'intgPrcsFcltCn',
|
||||
'wholNope',
|
||||
'sftyAcdntEvntcsCnt',
|
||||
'admdstCd',
|
||||
'rowType',
|
||||
'statsYr',
|
||||
],
|
||||
};
|
||||
@@ -706,7 +706,7 @@ const rawSewagePipeTotList = [
|
||||
tabKey: "ST00020004",
|
||||
tabLabel: "관경별 현황",
|
||||
rowStartNum: 2,
|
||||
fixedColumns: 3,
|
||||
fixedColumns: 1,
|
||||
columns: [
|
||||
{ name: "ctpvNm", fieldName: "ctpvNm", header: { text: "시도" }, editable: false },
|
||||
{ name: "sggNm", fieldName: "sggNm", header: { text: "시군구" }, editable: false },
|
||||
@@ -794,9 +794,238 @@ const rawSewagePipeTotList = [
|
||||
"etcPdmtPrlg",
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
tabKey: "ST00020005",
|
||||
tabLabel: "맨홀 현황",
|
||||
rowStartNum: 2,
|
||||
fixedColumns: 2,
|
||||
columns: [
|
||||
{ name: "ctpvNm", fieldName: "ctpvNm", header: { text: "시도" }, editable: false },
|
||||
{ name: "sggNm", fieldName: "sggNm", header: { text: "시군구" }, editable: false },
|
||||
{ name: "admdstNm", fieldName: "admdstNm", header: { text: "행정구역명" }, editable: false },
|
||||
{ name: "emphsMngSeNm", fieldName: "emphsMngSeNm", header: { text: "집중강우\n중점관리\n구역구분" }, editable: false },
|
||||
|
||||
{ name: "totWholMnhlCnt", fieldName: "totWholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "totStep1MnhlCnt", fieldName: "totStep1MnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "totStep2MnhlCnt", fieldName: "totStep2MnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "totStep3MnhlCnt", fieldName: "totStep3MnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "totStep4MnhlCnt", fieldName: "totStep4MnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "totStep5MnhlCnt", fieldName: "totStep5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2015년 이전 (yy14) ──────────────────────────────────
|
||||
{ name: "yy14WholMnhlCnt", fieldName: "yy14WholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy14Step1MnhlCnt", fieldName: "yy14Step1MnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy14Step2MnhlCnt", fieldName: "yy14Step2MnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy14Step3MnhlCnt", fieldName: "yy14Step3MnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy14Step4MnhlCnt", fieldName: "yy14Step4MnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy14Step5MnhlCnt", fieldName: "yy14Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2015년 (yy15) ───────────────────────────────────────
|
||||
{ name: "yy15WholMnhlCnt", fieldName: "yy15WholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy15Step1MnhlCnt", fieldName: "yy15Step1MnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy15Step2MnhlCnt", fieldName: "yy15Step2MnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy15Step3MnhlCnt", fieldName: "yy15Step3MnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy15Step4MnhlCnt", fieldName: "yy15Step4MnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy15Step5MnhlCnt", fieldName: "yy15Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2016년 (yy16) ───────────────────────────────────────
|
||||
{ name: "yy16WholMnhlCnt", fieldName: "yy16WholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy16Step1MnhlCnt", fieldName: "yy16Step1MnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy16Step2MnhlCnt", fieldName: "yy16Step2MnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy16Step3MnhlCnt", fieldName: "yy16Step3MnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy16Step4MnhlCnt", fieldName: "yy16Step4MnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy16Step5MnhlCnt", fieldName: "yy16Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2017년 (yy17) ───────────────────────────────────────
|
||||
{ name: "yy17WholMnhlCnt", fieldName: "yy17WholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy17Step1MnhlCnt", fieldName: "yy17Step1MnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy17Step2MnhlCnt", fieldName: "yy17Step2MnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy17Step3MnhlCnt", fieldName: "yy17Step3MnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy17Step4MnhlCnt", fieldName: "yy17Step4MnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy17Step5MnhlCnt", fieldName: "yy17Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2018년 (yy18) ───────────────────────────────────────
|
||||
{ name: "yy18WholMnhlCnt", fieldName: "yy18WholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy18Step1MnhlCnt", fieldName: "yy18Step1MnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy18Step2MnhlCnt", fieldName: "yy18Step2MnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy18Step3MnhlCnt", fieldName: "yy18Step3MnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy18Step4MnhlCnt", fieldName: "yy18Step4MnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy18Step5MnhlCnt", fieldName: "yy18Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2019년 (yy19) ───────────────────────────────────────
|
||||
{ name: "yy19WholMnhlCnt", fieldName: "yy19WholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy19Step1MnhlCnt", fieldName: "yy19Step1MnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy19Step2MnhlCnt", fieldName: "yy19Step2MnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy19Step3MnhlCnt", fieldName: "yy19Step3MnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy19Step4MnhlCnt", fieldName: "yy19Step4MnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy19Step5MnhlCnt", fieldName: "yy19Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2020년 (yy20) ───────────────────────────────────────
|
||||
{ name: "yy20WholMnhlCnt", fieldName: "yy20WholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy20Step1MnhlCnt", fieldName: "yy20Step1MnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy20Step2MnhlCnt", fieldName: "yy20Step2MnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy20Step3MnhlCnt", fieldName: "yy20Step3MnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy20Step4MnhlCnt", fieldName: "yy20Step4MnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy20Step5MnhlCnt", fieldName: "yy20Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2021년 (yy21) ───────────────────────────────────────
|
||||
{ name: "yy21WholMnhlCnt", fieldName: "yy21WholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy21Step1MnhlCnt", fieldName: "yy21Step1MnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy21Step2MnhlCnt", fieldName: "yy21Step2MnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy21Step3MnhlCnt", fieldName: "yy21Step3MnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy21Step4MnhlCnt", fieldName: "yy21Step4MnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy21Step5MnhlCnt", fieldName: "yy21Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2022년 (yy22) ───────────────────────────────────────
|
||||
{ name: "yy22WholMnhlCnt", fieldName: "yy22WholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy22Step1MnhlCnt", fieldName: "yy22Step1MnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy22Step2MnhlCnt", fieldName: "yy22Step2MnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy22Step3MnhlCnt", fieldName: "yy22Step3MnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy22Step4MnhlCnt", fieldName: "yy22Step4MnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy22Step5MnhlCnt", fieldName: "yy22Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2023년 (yy23) ───────────────────────────────────────
|
||||
{ name: "yy23WholMnhlCnt", fieldName: "yy23WholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy23Step1MnhlCnt", fieldName: "yy23Step1MnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy23Step2MnhlCnt", fieldName: "yy23Step2MnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy23Step3MnhlCnt", fieldName: "yy23Step3MnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy23Step4MnhlCnt", fieldName: "yy23Step4MnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy23Step5MnhlCnt", fieldName: "yy23Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2024년 (yy24) ───────────────────────────────────────
|
||||
{ name: "yy24WholMnhlCnt", fieldName: "yy24WholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy24Step1MnhlCnt", fieldName: "yy24Step1MnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy24Step2MnhlCnt", fieldName: "yy24Step2MnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy24Step3MnhlCnt", fieldName: "yy24Step3MnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy24Step4MnhlCnt", fieldName: "yy24Step4MnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy24Step5MnhlCnt", fieldName: "yy24Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
// ── 2025년 (yy25) ───────────────────────────────────────
|
||||
{ name: "yy25WholMnhlCnt", fieldName: "yy25WholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy25Step1MnhlCnt", fieldName: "yy25Step1MnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy25Step2MnhlCnt", fieldName: "yy25Step2MnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy25Step3MnhlCnt", fieldName: "yy25Step3MnhlCnt", header: { text: "콘크리트" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy25Step4MnhlCnt", fieldName: "yy25Step4MnhlCnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "yy25Step5MnhlCnt", fieldName: "yy25Step5MnhlCnt", header: { text: "추락방지시설\n설치맨홀(개)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
|
||||
{ name: "rmrk", fieldName: "rmrk", header: { text: "비고" }, editable: false },
|
||||
],
|
||||
columnLayout: [
|
||||
{ name: "addrGroup", header: { text: "행정구역" }, items: ["ctpvNm", "sggNm"] },
|
||||
"emphsMngSeNm",
|
||||
{
|
||||
name: "totGroup",
|
||||
header: { text: "연도별총계" },
|
||||
items: [
|
||||
{ name: "totMtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["totWholMnhlCnt", "totStep1MnhlCnt", "totStep2MnhlCnt", "totStep3MnhlCnt", "totStep4MnhlCnt"] },
|
||||
"totStep5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy14Group",
|
||||
header: { text: "2015년 이전" }, // ← _14Y
|
||||
items: [
|
||||
{ name: "yy14MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy14WholMnhlCnt", "yy14Step1MnhlCnt", "yy14Step2MnhlCnt", "yy14Step3MnhlCnt", "yy14Step4MnhlCnt"] },
|
||||
"yy14Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy15Group",
|
||||
header: { text: "2015년" }, // ← _15Y
|
||||
items: [
|
||||
{ name: "yy15MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy15WholMnhlCnt", "yy15Step1MnhlCnt", "yy15Step2MnhlCnt", "yy15Step3MnhlCnt", "yy15Step4MnhlCnt"] },
|
||||
"yy15Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy16Group",
|
||||
header: { text: "2016년" }, // ← _16Y
|
||||
items: [
|
||||
{ name: "yy16MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy16WholMnhlCnt", "yy16Step1MnhlCnt", "yy16Step2MnhlCnt", "yy16Step3MnhlCnt", "yy16Step4MnhlCnt"] },
|
||||
"yy16Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy17Group",
|
||||
header: { text: "2017년" },
|
||||
items: [
|
||||
{ name: "yy17MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy17WholMnhlCnt", "yy17Step1MnhlCnt", "yy17Step2MnhlCnt", "yy17Step3MnhlCnt", "yy17Step4MnhlCnt"] },
|
||||
"yy17Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy18Group",
|
||||
header: { text: "2018년" },
|
||||
items: [
|
||||
{ name: "yy18MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy18WholMnhlCnt", "yy18Step1MnhlCnt", "yy18Step2MnhlCnt", "yy18Step3MnhlCnt", "yy18Step4MnhlCnt"] },
|
||||
"yy18Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy19Group",
|
||||
header: { text: "2019년" },
|
||||
items: [
|
||||
{ name: "yy19MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy19WholMnhlCnt", "yy19Step1MnhlCnt", "yy19Step2MnhlCnt", "yy19Step3MnhlCnt", "yy19Step4MnhlCnt"] },
|
||||
"yy19Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy20Group",
|
||||
header: { text: "2020년" },
|
||||
items: [
|
||||
{ name: "yy20MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy20WholMnhlCnt", "yy20Step1MnhlCnt", "yy20Step2MnhlCnt", "yy20Step3MnhlCnt", "yy20Step4MnhlCnt"] },
|
||||
"yy20Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy21Group",
|
||||
header: { text: "2021년" },
|
||||
items: [
|
||||
{ name: "yy21MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy21WholMnhlCnt", "yy21Step1MnhlCnt", "yy21Step2MnhlCnt", "yy21Step3MnhlCnt", "yy21Step4MnhlCnt"] },
|
||||
"yy21Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy22Group",
|
||||
header: { text: "2022년" },
|
||||
items: [
|
||||
{ name: "yy22MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy22WholMnhlCnt", "yy22Step1MnhlCnt", "yy22Step2MnhlCnt", "yy22Step3MnhlCnt", "yy22Step4MnhlCnt"] },
|
||||
"yy22Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy23Group",
|
||||
header: { text: "2023년" },
|
||||
items: [
|
||||
{ name: "yy23MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy23WholMnhlCnt", "yy23Step1MnhlCnt", "yy23Step2MnhlCnt", "yy23Step3MnhlCnt", "yy23Step4MnhlCnt"] },
|
||||
"yy23Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy24Group",
|
||||
header: { text: "2024년" },
|
||||
items: [
|
||||
{ name: "yy24MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy24WholMnhlCnt", "yy24Step1MnhlCnt", "yy24Step2MnhlCnt", "yy24Step3MnhlCnt", "yy24Step4MnhlCnt"] },
|
||||
"yy24Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "yy25Group",
|
||||
header: { text: "2025년" },
|
||||
items: [
|
||||
{ name: "yy25MtrlGroup", header: { text: "맨홀뚜껑 재질(개)" }, items: ["yy25WholMnhlCnt", "yy25Step1MnhlCnt", "yy25Step2MnhlCnt", "yy25Step3MnhlCnt", "yy25Step4MnhlCnt"] },
|
||||
"yy25Step5MnhlCnt",
|
||||
],
|
||||
},
|
||||
"rmrk",
|
||||
],
|
||||
},
|
||||
|
||||
];
|
||||
|
||||
export const SewagePipeColumnInfoListTot = rawSewagePipeTotList.map((tab) => ({
|
||||
...tab,
|
||||
columns: tab.columns.map((col) => ({ ...col, editable: false as const })),
|
||||
}));
|
||||
|
||||
|
||||
+2
-2
@@ -28,7 +28,7 @@ export class StatisticsInputSewSupplyRateApiService implements StatisticsInputSe
|
||||
}
|
||||
|
||||
public async saveSewerageSupplyRate(params: SewerageSupplyRateSaveRequest): Promise<SewerageSupplyRateSaveResponse> {
|
||||
const response = await stClient.post<SewerageSupplyRateSaveResponse>(
|
||||
const response = await stClient.put<SewerageSupplyRateSaveResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/sewerage-supply-rate/save`,
|
||||
params,
|
||||
);
|
||||
@@ -36,7 +36,7 @@ export class StatisticsInputSewSupplyRateApiService implements StatisticsInputSe
|
||||
}
|
||||
|
||||
public async submitSewerageSupplyRate(params: SewerageSupplyRateSaveRequest): Promise<SewerageSupplyRateSubmitResponse> {
|
||||
const response = await stClient.post<SewerageSupplyRateSubmitResponse>(
|
||||
const response = await stClient.put<SewerageSupplyRateSubmitResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/sewerage-supply-rate/submit`,
|
||||
params,
|
||||
);
|
||||
|
||||
+14
-2
@@ -8,6 +8,8 @@ import type {
|
||||
PublicSewageFacilitySaveResponse,
|
||||
PublicSewageFacilitySubmitRequest,
|
||||
PublicSewageFacilitySubmitResponse,
|
||||
PublicSewageMainFacilityMappingSaveRequest,
|
||||
PublicSewageMainFacilityMappingSaveResponse,
|
||||
PublicSewageMainFacilityResponse,
|
||||
PublicSewageMappingTargetsRequestParams,
|
||||
PublicSewageMappingTargetsResponse,
|
||||
@@ -41,10 +43,20 @@ export class StatisticsInputPublicSewageFacilityApiService implements Statistics
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async saveMainFacilityMapping(
|
||||
param: PublicSewageMainFacilityMappingSaveRequest,
|
||||
): Promise<PublicSewageMainFacilityMappingSaveResponse> {
|
||||
const response = await stClient.put<PublicSewageMainFacilityMappingSaveResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/public-sewage-facility/main-facility/save`,
|
||||
param,
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async savePublicSewageFacility(
|
||||
param: PublicSewageFacilitySaveRequest,
|
||||
): Promise<PublicSewageFacilitySaveResponse> {
|
||||
const response = await stClient.post<PublicSewageFacilitySaveResponse>(
|
||||
const response = await stClient.put<PublicSewageFacilitySaveResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/public-sewage-facility/facility/save`,
|
||||
param,
|
||||
);
|
||||
@@ -54,7 +66,7 @@ export class StatisticsInputPublicSewageFacilityApiService implements Statistics
|
||||
public async submitPublicSewageFacility(
|
||||
param: PublicSewageFacilitySubmitRequest,
|
||||
): Promise<PublicSewageFacilitySubmitResponse> {
|
||||
const response = await stClient.post<PublicSewageFacilitySubmitResponse>(
|
||||
const response = await stClient.put<PublicSewageFacilitySubmitResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/public-sewage-facility/facility/submit`,
|
||||
param,
|
||||
);
|
||||
|
||||
@@ -101,7 +101,7 @@ export class StatisticsInputSewPipeApiService implements StatisticsInputSewPipeS
|
||||
}
|
||||
|
||||
public async saveFactConnection(param: SeweragePipeFactConnectionSaveRequest): Promise<SeweragePipeFactConnectionSaveResponse> {
|
||||
const response = await stClient.post<SeweragePipeFactConnectionSaveResponse>(
|
||||
const response = await stClient.put<SeweragePipeFactConnectionSaveResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/sewage-pipe/facility-connection-status/popup/save`,
|
||||
param,
|
||||
);
|
||||
@@ -109,7 +109,7 @@ export class StatisticsInputSewPipeApiService implements StatisticsInputSewPipeS
|
||||
}
|
||||
|
||||
public async saveRegionalFactStatus(param: SeweragePipeInputRegionalFactStatusSaveRequest): Promise<SeweragePipeInputRegionalFactStatusSaveResponse> {
|
||||
const response = await stClient.post<SeweragePipeInputRegionalFactStatusSaveResponse>(
|
||||
const response = await stClient.put<SeweragePipeInputRegionalFactStatusSaveResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/sewage-pipe/regional-facility-status/save`,
|
||||
param,
|
||||
);
|
||||
@@ -117,7 +117,7 @@ export class StatisticsInputSewPipeApiService implements StatisticsInputSewPipeS
|
||||
}
|
||||
|
||||
public async submitRegionalFactStatus(param: SeweragePipeInputRegionalFactStatusSubmitRequest): Promise<SeweragePipeInputRegionalFactStatusSubmitResponse> {
|
||||
const response = await stClient.post<SeweragePipeInputRegionalFactStatusSubmitResponse>(
|
||||
const response = await stClient.put<SeweragePipeInputRegionalFactStatusSubmitResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/sewage-pipe/regional-facility-status/submit`,
|
||||
param,
|
||||
);
|
||||
@@ -125,7 +125,7 @@ export class StatisticsInputSewPipeApiService implements StatisticsInputSewPipeS
|
||||
}
|
||||
|
||||
public async saveFactInstallStatus(param: SeweragePipeInputFactInstallStatusSaveRequest): Promise<SeweragePipeInputFactInstallStatusSaveResponse> {
|
||||
const response = await stClient.post<SeweragePipeInputFactInstallStatusSaveResponse>(
|
||||
const response = await stClient.put<SeweragePipeInputFactInstallStatusSaveResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/sewage-pipe/facility-install-status/save`,
|
||||
param,
|
||||
);
|
||||
@@ -133,7 +133,7 @@ export class StatisticsInputSewPipeApiService implements StatisticsInputSewPipeS
|
||||
}
|
||||
|
||||
public async submitFactInstallStatus(param: SeweragePipeInputFactInstallStatusSubmitRequest): Promise<SeweragePipeInputFactInstallStatusSubmitResponse> {
|
||||
const response = await stClient.post<SeweragePipeInputFactInstallStatusSubmitResponse>(
|
||||
const response = await stClient.put<SeweragePipeInputFactInstallStatusSubmitResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/sewage-pipe/facility-install-status/submit`,
|
||||
param,
|
||||
);
|
||||
@@ -141,7 +141,7 @@ export class StatisticsInputSewPipeApiService implements StatisticsInputSewPipeS
|
||||
}
|
||||
|
||||
public async savePipeTypeStatus(param: SeweragePipeInputPipeTypeStatusSaveRequest): Promise<SeweragePipeInputPipeTypeStatusSaveResponse> {
|
||||
const response = await stClient.post<SeweragePipeInputPipeTypeStatusSaveResponse>(
|
||||
const response = await stClient.put<SeweragePipeInputPipeTypeStatusSaveResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/sewage-pipe/pipe-type-status/save`,
|
||||
param,
|
||||
);
|
||||
@@ -149,7 +149,7 @@ export class StatisticsInputSewPipeApiService implements StatisticsInputSewPipeS
|
||||
}
|
||||
|
||||
public async submitPipeTypeStatus(param: SeweragePipeInputPipeTypeStatusSubmitRequest): Promise<SeweragePipeInputSubmitResponse> {
|
||||
const response = await stClient.post<SeweragePipeInputSubmitResponse>(
|
||||
const response = await stClient.put<SeweragePipeInputSubmitResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/sewage-pipe/pipe-type-status/submit`,
|
||||
param,
|
||||
);
|
||||
@@ -157,7 +157,7 @@ export class StatisticsInputSewPipeApiService implements StatisticsInputSewPipeS
|
||||
}
|
||||
|
||||
public async savePipeDiameterStatus(param: SeweragePipeInputPipeDiameterStatusSaveRequest): Promise<SeweragePipeInputPipeDiameterStatusSaveResponse> {
|
||||
const response = await stClient.post<SeweragePipeInputPipeDiameterStatusSaveResponse>(
|
||||
const response = await stClient.put<SeweragePipeInputPipeDiameterStatusSaveResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/sewage-pipe/pipe-diameter-status/save`,
|
||||
param,
|
||||
);
|
||||
@@ -165,7 +165,7 @@ export class StatisticsInputSewPipeApiService implements StatisticsInputSewPipeS
|
||||
}
|
||||
|
||||
public async submitPipeDiameterStatus(param: SeweragePipeInputPipeDiameterStatusSubmitRequest): Promise<SeweragePipeInputSubmitResponse> {
|
||||
const response = await stClient.post<SeweragePipeInputSubmitResponse>(
|
||||
const response = await stClient.put<SeweragePipeInputSubmitResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/sewage-pipe/pipe-diameter-status/submit`,
|
||||
param,
|
||||
);
|
||||
@@ -173,7 +173,7 @@ export class StatisticsInputSewPipeApiService implements StatisticsInputSewPipeS
|
||||
}
|
||||
|
||||
public async saveManholeStatus(param: SeweragePipeInputManholeStatusSaveRequest): Promise<SeweragePipeInputManholeStatusSaveResponse> {
|
||||
const response = await stClient.post<SeweragePipeInputManholeStatusSaveResponse>(
|
||||
const response = await stClient.put<SeweragePipeInputManholeStatusSaveResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/sewage-pipe/manhole-status/save`,
|
||||
param,
|
||||
);
|
||||
@@ -181,7 +181,7 @@ export class StatisticsInputSewPipeApiService implements StatisticsInputSewPipeS
|
||||
}
|
||||
|
||||
public async submitManholeStatus(param: SeweragePipeInputManholeStatusSubmitRequest): Promise<SeweragePipeInputSubmitResponse> {
|
||||
const response = await stClient.post<SeweragePipeInputSubmitResponse>(
|
||||
const response = await stClient.put<SeweragePipeInputSubmitResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/sewage-pipe/manhole-status/submit`,
|
||||
param,
|
||||
);
|
||||
|
||||
@@ -3,6 +3,8 @@ import { ENDPOINT } from "@/shared/config";
|
||||
import type { PageableList } from "@/shared/model";
|
||||
|
||||
import type {
|
||||
BusinessSendRequest,
|
||||
BusinessSendResponse,
|
||||
NtftalkTemplate,
|
||||
TemplateVariablesResponse,
|
||||
} from "../../model/notice-talk/notice-talk-sending-interface";
|
||||
@@ -38,6 +40,16 @@ export class NoticeTalkSendingApiService {
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async sendBusiness(
|
||||
payload: BusinessSendRequest,
|
||||
): Promise<BusinessSendResponse> {
|
||||
const response = await client.post<BusinessSendResponse>(
|
||||
`${ENDPOINT.NTFTALK_SERVICE.ATA_SEND}/business`,
|
||||
payload,
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
}
|
||||
|
||||
export const noticeTalkSendingApi = new NoticeTalkSendingApiService();
|
||||
|
||||
@@ -8,26 +8,32 @@ import {
|
||||
type getReviewOpinionDetailRequest,
|
||||
type getReviewOpinionDetailResponse,
|
||||
type ImrRequest,
|
||||
type ImrResponse,
|
||||
type ImrStatusResponse,
|
||||
type ReviewOpinionSaveRequest,
|
||||
type ReviewOpinionSaveResponse,
|
||||
type ReviewReturnSaveRequest,
|
||||
type ReviewReturnSaveResponse,
|
||||
type ReviewSubmitRequest,
|
||||
type ReviewSubmitResponse,
|
||||
type VerificationResultListRequest,
|
||||
type VerificationResultListResponse,
|
||||
type SearchCondition,
|
||||
type Sgg,
|
||||
type StatisticsLogDetailResponse,
|
||||
type StatisticsLogRequest,
|
||||
type StatisticsLogResponse,
|
||||
type StatisticsService,
|
||||
type StatsInputPeriodDeleteApiResponse,
|
||||
type StatsInputPeriodDeleteRequest,
|
||||
type StatsInputPeriodListApiResponse,
|
||||
type StatsInputPeriodListRequest,
|
||||
type StatsInputPeriodSaveApiResponse,
|
||||
type StatsInputPeriodSaveRequest,
|
||||
type SubmitExceptionRequest,
|
||||
type SubmitExceptionResponse,
|
||||
type ImrResponse,
|
||||
type ImrStatusResponse,
|
||||
type SubmitVerifyExceptionRequest,
|
||||
type SubmitVerifyExceptionResponse,
|
||||
type VerificationResultListRequest,
|
||||
type VerificationResultListResponse,
|
||||
} from "../model/statistics-interface";
|
||||
|
||||
export class StatisticsApiService implements StatisticsService {
|
||||
@@ -63,6 +69,39 @@ export class StatisticsApiService implements StatisticsService {
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/** 통계 입력 기간(연도·분류별) 목록 조회 — 경로는 백엔드 스펙에 맞게 수정 */
|
||||
public async getStatsInputPeriodList(
|
||||
params?: StatsInputPeriodListRequest,
|
||||
): Promise<StatsInputPeriodListApiResponse> {
|
||||
const response = await stClient.get<StatsInputPeriodListApiResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.DASHBOARD}/schedule-info/list`,
|
||||
{ params },
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/** 통계 입력 기간 저장 — 경로는 백엔드 스펙에 맞게 수정 */
|
||||
public async saveStatsInputPeriod(
|
||||
param: StatsInputPeriodSaveRequest,
|
||||
): Promise<StatsInputPeriodSaveApiResponse> {
|
||||
const response = await stClient.post<StatsInputPeriodSaveApiResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.DASHBOARD}/schedule-info`,
|
||||
param,
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/** 통계 입력 기간 삭제 — JSON body. HTTP 메서드·URL은 백엔드 스펙에 맞게 수정 */
|
||||
public async deleteStatsInputPeriod(
|
||||
param: StatsInputPeriodDeleteRequest,
|
||||
): Promise<StatsInputPeriodDeleteApiResponse> {
|
||||
const response = await stClient.delete<StatsInputPeriodDeleteApiResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.DASHBOARD}/schedule-info`,
|
||||
{ data: param },
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
// 입력 - 제출 취소
|
||||
public async cancelSubmit(
|
||||
param: cancelSubmitRequest,
|
||||
|
||||
@@ -11,6 +11,7 @@ import type {
|
||||
SewagePipeFactInstallStatusResponse,
|
||||
SewagePipePipeDiamStatusResponse,
|
||||
SewagePipePipeTypeFacilityStatusResponse,
|
||||
FcltyManholeSummaryResponse,
|
||||
SewagePipeTotalRequest,
|
||||
SewagePipeTotalResponse,
|
||||
} from "../model/statistics-total/statistics-sewage-pipe-total-interface";
|
||||
@@ -19,6 +20,10 @@ import type {
|
||||
SewerageServiceLevelRequest,
|
||||
SewerageServiceLevelResidentFriendlyFactResponse
|
||||
} from "../model/statistics-total/statistics-service-level-total-interface";
|
||||
import type {
|
||||
PublicSewageInquirySummaryResponse
|
||||
} from "../model/statistics-total/statistics-sewage-public-total-interface";
|
||||
|
||||
|
||||
export class StatisticsTotalApiService {
|
||||
public async getSewerageSupplyRateList(params: SewerageSupplyRateRequest): Promise<SewerageSupplyRateResponse> {
|
||||
@@ -84,6 +89,16 @@ export class StatisticsTotalApiService {
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
/** ST00020005 — 맨홀 시설현황(합계) */
|
||||
public async getSewagePipePipeMnhleStatus(
|
||||
params: SewagePipeTotalRequest,
|
||||
): Promise<FcltyManholeSummaryResponse> {
|
||||
const response = await stClient.get<FcltyManholeSummaryResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.TOTAL}/sewer-pipe/manhle-status`,
|
||||
{ params },
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/** ST00030001 — 하수관로 유지관리 > 개보수(합계) */
|
||||
public async getSewagePipeMaintainRepairTotal(
|
||||
@@ -106,6 +121,17 @@ export class StatisticsTotalApiService {
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/** ST00060001 —공공하수처리시설 */
|
||||
public async getSewagePublicFacillityTotal(
|
||||
params: SewagePipeMaintainTotalRequest,
|
||||
): Promise<PublicSewageInquirySummaryResponse> {
|
||||
const response = await stClient.get<PublicSewageInquirySummaryResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.TOTAL}/public-sewage`,
|
||||
{ params },
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
}
|
||||
|
||||
export const statisticsTotalStatusApi = new StatisticsTotalApiService();
|
||||
@@ -11,10 +11,18 @@ const IMR_VISIBLE_REGION_COLUMNS = [
|
||||
"cryrVl",
|
||||
] as const;
|
||||
|
||||
/** ST00020003, ST00020005: 시도·구군·행정구역·관종구분 */
|
||||
const IMR_VISIBLE_REGION_AND_PIPE_SE_COLUMNS = [
|
||||
/** ST00020003: 시도·구군·행정구역·관종구분·매설년도 */
|
||||
const IMR_VISIBLE_REGION_AND_PIPE_COLUMNS = [
|
||||
...IMR_VISIBLE_REGION_COLUMNS,
|
||||
"pipeSeNm",
|
||||
"lyngYr",
|
||||
] as const;
|
||||
|
||||
/** ST00020005: 시도·구군·행정구역·중점관리구역구분·맨홀기준년도 */
|
||||
const IMR_VISIBLE_REGION_AND_MANH_COLUMNS = [
|
||||
...IMR_VISIBLE_REGION_COLUMNS,
|
||||
"emphsMngSeNm",
|
||||
"manhYr",
|
||||
] as const;
|
||||
|
||||
/** ST00060001, ST00100001: 시도·구군·행정구역·시설코드·시설명·주소 */
|
||||
@@ -40,8 +48,8 @@ export const IMR_DETAIL_VISIBLE_COLUMNS_BY_STATS_CD: Record<
|
||||
string,
|
||||
readonly string[]
|
||||
> = {
|
||||
ST00020003: [...IMR_VISIBLE_REGION_AND_PIPE_SE_COLUMNS],
|
||||
ST00020005: [...IMR_VISIBLE_REGION_AND_PIPE_SE_COLUMNS],
|
||||
ST00020003: [...IMR_VISIBLE_REGION_AND_PIPE_COLUMNS],
|
||||
ST00020005: [...IMR_VISIBLE_REGION_AND_MANH_COLUMNS],
|
||||
ST00060001: [...IMR_VISIBLE_FACILITY_FULL_COLUMNS],
|
||||
ST00100001: [...IMR_VISIBLE_FACILITY_FULL_COLUMNS],
|
||||
ST00040001: [...IMR_VISIBLE_FACILITY_NAME_ADDR_COLUMNS],
|
||||
@@ -80,6 +88,18 @@ export const imrDetailGridColumnInfo: ColumnInfo = {
|
||||
header: { text: "행정구역" },
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
name: "emphsMngSeNm",
|
||||
fieldName: "emphsMngSeNm",
|
||||
header: { text: "중점관리구역구분" },
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
name: "manhYr",
|
||||
fieldName: "manhYr",
|
||||
header: { text: "맨홀기준년도" },
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
name: "admdstCd",
|
||||
fieldName: "admdstCd",
|
||||
@@ -105,6 +125,12 @@ export const imrDetailGridColumnInfo: ColumnInfo = {
|
||||
header: { text: "관종구분" },
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
name: "lyngYr",
|
||||
fieldName: "lyngYr",
|
||||
header: { text: "매설년도" },
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
name: "vrfcTrgtSn",
|
||||
fieldName: "vrfcTrgtSn",
|
||||
@@ -126,10 +152,13 @@ export const imrDetailGridColumnInfo: ColumnInfo = {
|
||||
"sido",
|
||||
"gugun",
|
||||
"adstDong",
|
||||
"emphsMngSeNm",
|
||||
"manhYr",
|
||||
"admdstCd",
|
||||
"fcltNm",
|
||||
"addr",
|
||||
"pipeSeNm",
|
||||
"lyngYr",
|
||||
"vrfcTrgtSn",
|
||||
"cryrVl",
|
||||
],
|
||||
|
||||
+36
@@ -151,6 +151,7 @@ export interface PublicSewageMappingTargetsRequestParams {
|
||||
/** ST00060002 메인시설 클릭 시 우측 매핑대상 조회 항목 */
|
||||
export interface PublicSewageMappingTargetItem {
|
||||
fcltSn: string;
|
||||
admdstCd?: string;
|
||||
admdstNm: string;
|
||||
swtrmtFcltCd: string;
|
||||
swtrmtFcltNm: string;
|
||||
@@ -167,6 +168,40 @@ export interface PublicSewageMappingTargetsResponse {
|
||||
data: PublicSewageMappingTargetItem[];
|
||||
}
|
||||
|
||||
/** ST00060002 중심처리시설 매핑 저장 — saveList 항목 */
|
||||
export interface PublicSewageMainFacilityMappingSaveItem {
|
||||
fcltSn: string;
|
||||
admdstCd: string;
|
||||
admdstNm: string;
|
||||
swtrmtFcltCd: string;
|
||||
swtrmtFcltNm: string;
|
||||
isMainYn: string;
|
||||
}
|
||||
|
||||
/** ST00060002 중심처리시설 매핑 저장 API 요청 */
|
||||
export interface PublicSewageMainFacilityMappingSaveRequest {
|
||||
statsYr: string;
|
||||
sewerBzmnCd: string;
|
||||
/** 좌측에서 선택한 중심 처리 시설의 행정구역 */
|
||||
admdstCd: string;
|
||||
admdstNm: string;
|
||||
mainFcltSn: string;
|
||||
mainFcltNm: string;
|
||||
prxyBzentyNmCn: string;
|
||||
cnsgnCstVl: number;
|
||||
wholNope: number;
|
||||
prxyCtrtCn: string;
|
||||
userId: string;
|
||||
saveList: PublicSewageMainFacilityMappingSaveItem[];
|
||||
deleteList: string[];
|
||||
}
|
||||
|
||||
export interface PublicSewageMainFacilityMappingSaveResponse {
|
||||
status: string;
|
||||
message?: string;
|
||||
data?: string;
|
||||
}
|
||||
|
||||
/** ST00060001 공공하수처리시설 저장 — saveList 항목 */
|
||||
export interface PublicSewageFacilitySaveItem {
|
||||
admdstCd: string;
|
||||
@@ -249,6 +284,7 @@ export interface StatisticsInputPublicSewageFacilityService {
|
||||
getPublicSewageFacility(param: PublicSewageFacilityRequestParams): Promise<PublicSewageFacilityResponse>;
|
||||
getPublicSewageMainFacility(param: PublicSewageFacilityRequestParams): Promise<PublicSewageMainFacilityResponse>;
|
||||
getMappingTargets(param: PublicSewageMappingTargetsRequestParams): Promise<PublicSewageMappingTargetsResponse>;
|
||||
saveMainFacilityMapping(param: PublicSewageMainFacilityMappingSaveRequest): Promise<PublicSewageMainFacilityMappingSaveResponse>;
|
||||
savePublicSewageFacility(param: PublicSewageFacilitySaveRequest): Promise<PublicSewageFacilitySaveResponse>;
|
||||
submitPublicSewageFacility(param: PublicSewageFacilitySubmitRequest): Promise<PublicSewageFacilitySubmitResponse>;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,46 @@ export interface ApiResponse<T> {
|
||||
message?: string;
|
||||
}
|
||||
|
||||
/** 통계 입력 관리 등 — 연도·구분·분류(입력/검증)별 입력 기간 한 행 */
|
||||
export interface StatsInputPeriodItem {
|
||||
statsYr: string;
|
||||
seCd: number;
|
||||
seType: "INPT" | "VRFC";
|
||||
inptBgngYmd: string;
|
||||
inptEndYmd: string;
|
||||
}
|
||||
|
||||
/** `data`가 `StatsInputPeriodItem[]` 인 조회 응답 */
|
||||
export type StatsInputPeriodListApiResponse = ApiResponse<StatsInputPeriodItem[]>;
|
||||
|
||||
/** 통계 입력 기간 목록 조회 요청 쿼리 */
|
||||
export interface StatsInputPeriodListRequest {
|
||||
statsYr?: string;
|
||||
/** 전체 / 입력 / 검증 (SearchForm `clsfCd`와 동일) */
|
||||
seType?: "ALL" | "INPT" | "VRFC";
|
||||
}
|
||||
|
||||
/** 통계 입력 기간 등록·수정 등 요청 본문 */
|
||||
export interface StatsInputPeriodSaveRequest {
|
||||
statsYr: string;
|
||||
seType: string;
|
||||
seCd: number;
|
||||
/** 시작일 (백엔드 형식 문자열, 예: YYYYMMDD) */
|
||||
inptBgngYmd: string;
|
||||
/** 종료일 (백엔드 형식 문자열, 예: YYYYMMDD) */
|
||||
inptEndYmd: string;
|
||||
rgtrId: string;
|
||||
}
|
||||
|
||||
/** 통계 입력 기간 저장 응답 */
|
||||
export type StatsInputPeriodSaveApiResponse = ApiResponse<unknown>;
|
||||
|
||||
/** 통계 입력 기간 삭제 요청 (필드 구성은 저장과 동일) */
|
||||
export type StatsInputPeriodDeleteRequest = StatsInputPeriodSaveRequest;
|
||||
|
||||
/** 통계 입력 기간 삭제 응답 */
|
||||
export type StatsInputPeriodDeleteApiResponse = ApiResponse<unknown>;
|
||||
|
||||
/** 하수 입력/보급률 등 조회 `data.statusInfo` 공통 (LAE 제출·담당자 정보) */
|
||||
export interface SewerageStatusInfo {
|
||||
laePicNm: string | null;
|
||||
@@ -116,6 +156,7 @@ export interface VerificationResultReportItem {
|
||||
nowVlCn: string;
|
||||
compVlCn: string | null;
|
||||
prcsYn: string;
|
||||
prcsYnNm: string;
|
||||
prcsOpnnExpln: string | null;
|
||||
prcrId: string | null;
|
||||
rjctOpnnCn: string | null;
|
||||
@@ -305,6 +346,11 @@ export interface StatisticsService {
|
||||
getSidoList(params?: { instSeCd?: string }): Promise<ApiResponse<SearchCondition>>;
|
||||
getSggList(sidoName: string, params?: { instSeCd?: string; gugunSkipYn?: "Y" | "N" }): Promise<ApiResponse<Sgg[]>>;
|
||||
getSggAllList(sidoName: string, params?: { instSeCd?: string; gugunSkipYn?: "Y" | "N" }): Promise<ApiResponse<Sgg[]>>;
|
||||
getStatsInputPeriodList(
|
||||
params?: StatsInputPeriodListRequest,
|
||||
): Promise<StatsInputPeriodListApiResponse>;
|
||||
saveStatsInputPeriod(param: StatsInputPeriodSaveRequest): Promise<StatsInputPeriodSaveApiResponse>;
|
||||
deleteStatsInputPeriod(param: StatsInputPeriodDeleteRequest): Promise<StatsInputPeriodDeleteApiResponse>;
|
||||
cancelSubmit(param: cancelSubmitRequest): Promise<cancelSubmitResponse>;
|
||||
callImrService(param: ImrRequest): Promise<ImrResponse>;
|
||||
submitException(param: SubmitExceptionRequest): Promise<SubmitExceptionResponse>;
|
||||
|
||||
+13
-2
@@ -32,7 +32,8 @@ export interface SewerPipeMtcItem {
|
||||
}
|
||||
|
||||
export interface SewerPipeMtcResponseData {
|
||||
mtcStatusList: SewerPipeMtcItem[];
|
||||
sewerPipeMtcList: SewerPipeMtcItem[];
|
||||
statsStatusInfo: StatsStatusInfo;
|
||||
}
|
||||
|
||||
export interface SewerPipeMtcRequestParams {
|
||||
@@ -96,7 +97,8 @@ export interface SewerPipeDrdgItem {
|
||||
|
||||
|
||||
export interface SewerPipeDrdgResponseData {
|
||||
drdgStatusList: SewerPipeDrdgItem[];
|
||||
sewerPipeDrdgList: SewerPipeDrdgItem[];
|
||||
statsStatusInfo: StatsStatusInfo;
|
||||
}
|
||||
|
||||
|
||||
@@ -104,4 +106,13 @@ export type SewerPipeDrdgApiResponse = ApiResponse<SewerPipeDrdgResponseData>;
|
||||
|
||||
export interface SewagePipeMtcService {
|
||||
getSewerPipeMtcDrdgItem(params: SewerPipeMtcRequestParams): Promise<SewerPipeDrdgApiResponse>;
|
||||
}
|
||||
|
||||
export interface StatsStatusInfo {
|
||||
statsCd?: string;
|
||||
submitStatusCd?: string;
|
||||
prvnStatusCd?: string;
|
||||
rjctOpnnCn?: string;
|
||||
splmntOpnnCn?: string;
|
||||
wrterOpnnCn?: string;
|
||||
}
|
||||
@@ -63,7 +63,8 @@ export interface SewagePipeReviewrRegionalItem {
|
||||
}
|
||||
|
||||
export interface SewagePipeReviewResponseData {
|
||||
sewagePipeList: SewagePipeReviewrRegionalItem[];
|
||||
regionalStatusList: SewagePipeReviewrRegionalItem[];
|
||||
statsStatusInfo: StatsStatusInfo;
|
||||
}
|
||||
|
||||
export interface SewagePipeReviewRequestParams {
|
||||
@@ -73,7 +74,7 @@ export interface SewagePipeReviewRequestParams {
|
||||
sewerBzmnCd?: string;
|
||||
}
|
||||
|
||||
export type SewagePipeReviewRegionalApiResponse = ApiResponse<SewagePipeReviewrRegionalItem[]> & {
|
||||
export type SewagePipeReviewRegionalApiResponse = ApiResponse<SewagePipeReviewResponseData> & {
|
||||
message: string;
|
||||
};
|
||||
|
||||
@@ -131,7 +132,12 @@ export interface SewagePipeReviewFacilityItem {
|
||||
}
|
||||
|
||||
|
||||
export type SewagePipeFacilityApiResponse = ApiResponse<SewagePipeReviewFacilityItem[]> & {
|
||||
export interface SewagePipeFacilityResponseData {
|
||||
facilityStatusList: SewagePipeReviewFacilityItem[];
|
||||
statsStatusInfo: StatsStatusInfo;
|
||||
}
|
||||
|
||||
export type SewagePipeFacilityApiResponse = ApiResponse<SewagePipeFacilityResponseData> & {
|
||||
message: string;
|
||||
};
|
||||
|
||||
@@ -165,10 +171,11 @@ export interface SewerPipeTypeItem {
|
||||
|
||||
|
||||
export interface SewerPipeTypeResponseData {
|
||||
pipeTypeStatusList: SewerPipeTypeItem[];
|
||||
pipeTypeList: SewerPipeTypeItem[];
|
||||
statsStatusInfo: StatsStatusInfo;
|
||||
}
|
||||
|
||||
export type SewerPipeTypeApiResponse = ApiResponse<SewerPipeTypeItem[]>;
|
||||
export type SewerPipeTypeApiResponse = ApiResponse<SewerPipeTypeResponseData>;
|
||||
|
||||
export interface SewagePipeTypeService {
|
||||
|
||||
@@ -225,9 +232,23 @@ export interface SewerPipeDiamItem {
|
||||
}
|
||||
|
||||
|
||||
export type SewerPipeDiamApiResponse = ApiResponse<SewerPipeDiamItem[]>;
|
||||
export interface SewerPipeDiamResponseData {
|
||||
pipeDiamList: SewerPipeDiamItem[];
|
||||
statsStatusInfo: StatsStatusInfo;
|
||||
}
|
||||
|
||||
export type SewerPipeDiamApiResponse = ApiResponse<SewerPipeDiamResponseData>;
|
||||
|
||||
|
||||
export interface SewagePipeDiamService {
|
||||
getSewagePipeDiamList(params: SewagePipeReviewRequestParams): Promise<SewerPipeDiamApiResponse>;
|
||||
}
|
||||
|
||||
export interface StatsStatusInfo {
|
||||
statsCd?: string;
|
||||
submitStatusCd?: string;
|
||||
prvnStatusCd?: string;
|
||||
rjctOpnnCn?: string;
|
||||
splmntOpnnCn?: string;
|
||||
wrterOpnnCn?: string;
|
||||
}
|
||||
+129
@@ -4,6 +4,8 @@ export interface SewagePipeTotalRequest {
|
||||
statsYr?: string;
|
||||
sewerBzmnCd?: string;
|
||||
rowDataYn?: boolean;
|
||||
summaryYn?: boolean;
|
||||
summaryYearCnt?: number;
|
||||
}
|
||||
|
||||
export interface SewagePipeTotalItem {
|
||||
@@ -234,3 +236,130 @@ export interface SewagePipePipeDiamStatusResponse {
|
||||
message?: string;
|
||||
data: SewagePipePipeDiamStatusItem[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 맨홀 현황 응답 아이템 인터페이스
|
||||
* DTO의 yy14(2014년 이전) ~ yy25(2024년) 필드를 모두 명시적으로 선언
|
||||
*/
|
||||
export interface FcltyManholeSummaryItem {
|
||||
/* --- 기본 정보 및 행 제어 --- */
|
||||
ctpvNm: string; // 시도명
|
||||
sggNm: string; // 시군구명
|
||||
admdstNm: string; // 행정구역명
|
||||
admdstCd: string; // 행정구역코드
|
||||
statsYr: string; // 통계연도
|
||||
rowType: string; // 데이터 구분 (OLD, CURR, SUMMARY 등)
|
||||
emphsMngSeCd: string; // 중점관리구역구분코드
|
||||
emphsMngSeNm: string; // 중점관리구역구분명
|
||||
|
||||
totWholMnhlCnt: number;
|
||||
totStep1MnhlCnt: number;
|
||||
totStep2MnhlCnt: number;
|
||||
totStep3MnhlCnt: number;
|
||||
totStep4MnhlCnt: number;
|
||||
totStep5MnhlCnt: number;
|
||||
/* --- yy14 (2014년 이전) --- */
|
||||
yy14WholMnhlCnt: number; // 합계
|
||||
yy14Step1MnhlCnt: number; // 1단계
|
||||
yy14Step2MnhlCnt: number; // 2단계
|
||||
yy14Step3MnhlCnt: number; // 3단계
|
||||
yy14Step4MnhlCnt: number; // 4단계
|
||||
yy14Step5MnhlCnt: number; // 5단계
|
||||
|
||||
/* --- yy15 (2014년) --- */
|
||||
yy15WholMnhlCnt: number;
|
||||
yy15Step1MnhlCnt: number;
|
||||
yy15Step2MnhlCnt: number;
|
||||
yy15Step3MnhlCnt: number;
|
||||
yy15Step4MnhlCnt: number;
|
||||
yy15Step5MnhlCnt: number;
|
||||
|
||||
/* --- yy16 (2015년) --- */
|
||||
yy16WholMnhlCnt: number;
|
||||
yy16Step1MnhlCnt: number;
|
||||
yy16Step2MnhlCnt: number;
|
||||
yy16Step3MnhlCnt: number;
|
||||
yy16Step4MnhlCnt: number;
|
||||
yy16Step5MnhlCnt: number;
|
||||
|
||||
/* --- yy17 (2016년) --- */
|
||||
yy17WholMnhlCnt: number;
|
||||
yy17Step1MnhlCnt: number;
|
||||
yy17Step2MnhlCnt: number;
|
||||
yy17Step3MnhlCnt: number;
|
||||
yy17Step4MnhlCnt: number;
|
||||
yy17Step5MnhlCnt: number;
|
||||
|
||||
/* --- yy18 (2017년) --- */
|
||||
yy18WholMnhlCnt: number;
|
||||
yy18Step1MnhlCnt: number;
|
||||
yy18Step2MnhlCnt: number;
|
||||
yy18Step3MnhlCnt: number;
|
||||
yy18Step4MnhlCnt: number;
|
||||
yy18Step5MnhlCnt: number;
|
||||
|
||||
/* --- yy19 (2018년) --- */
|
||||
yy19WholMnhlCnt: number;
|
||||
yy19Step1MnhlCnt: number;
|
||||
yy19Step2MnhlCnt: number;
|
||||
yy19Step3MnhlCnt: number;
|
||||
yy19Step4MnhlCnt: number;
|
||||
yy19Step5MnhlCnt: number;
|
||||
|
||||
/* --- yy20 (2019년) --- */
|
||||
yy20WholMnhlCnt: number;
|
||||
yy20Step1MnhlCnt: number;
|
||||
yy20Step2MnhlCnt: number;
|
||||
yy20Step3MnhlCnt: number;
|
||||
yy20Step4MnhlCnt: number;
|
||||
yy20Step5MnhlCnt: number;
|
||||
|
||||
/* --- yy21 (2020년) --- */
|
||||
yy21WholMnhlCnt: number;
|
||||
yy21Step1MnhlCnt: number;
|
||||
yy21Step2MnhlCnt: number;
|
||||
yy21Step3MnhlCnt: number;
|
||||
yy21Step4MnhlCnt: number;
|
||||
yy21Step5MnhlCnt: number;
|
||||
|
||||
/* --- yy22 (2021년) --- */
|
||||
yy22WholMnhlCnt: number;
|
||||
yy22Step1MnhlCnt: number;
|
||||
yy22Step2MnhlCnt: number;
|
||||
yy22Step3MnhlCnt: number;
|
||||
yy22Step4MnhlCnt: number;
|
||||
yy22Step5MnhlCnt: number;
|
||||
|
||||
/* --- yy23 (2022년) --- */
|
||||
yy23WholMnhlCnt: number;
|
||||
yy23Step1MnhlCnt: number;
|
||||
yy23Step2MnhlCnt: number;
|
||||
yy23Step3MnhlCnt: number;
|
||||
yy23Step4MnhlCnt: number;
|
||||
yy23Step5MnhlCnt: number;
|
||||
|
||||
/* --- yy24 (2023년) --- */
|
||||
yy24WholMnhlCnt: number;
|
||||
yy24Step1MnhlCnt: number;
|
||||
yy24Step2MnhlCnt: number;
|
||||
yy24Step3MnhlCnt: number;
|
||||
yy24Step4MnhlCnt: number;
|
||||
yy24Step5MnhlCnt: number;
|
||||
|
||||
/* --- yy25 (2024년) --- */
|
||||
yy25WholMnhlCnt: number;
|
||||
yy25Step1MnhlCnt: number;
|
||||
yy25Step2MnhlCnt: number;
|
||||
yy25Step3MnhlCnt: number;
|
||||
yy25Step4MnhlCnt: number;
|
||||
yy25Step5MnhlCnt: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 맨홀 현황 API 공통 응답 규격
|
||||
*/
|
||||
export interface FcltyManholeSummaryResponse {
|
||||
status: string; // success / error 등
|
||||
message?: string; // 오류 메시지 등
|
||||
data: FcltyManholeSummaryItem[]; // 실제 리스트 데이터
|
||||
}
|
||||
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
export interface PublicSewageInquirySummaryRequest {
|
||||
ctpvNm?: string;
|
||||
sggNm?: string;
|
||||
statsYr?: string;
|
||||
swtrmtFcltNm?: string;
|
||||
sewerBzmnCd?: string;
|
||||
rowDataYn?: boolean;
|
||||
capacityGbn?: string;
|
||||
summaryYn?: boolean;
|
||||
summaryYearCnt?: number;
|
||||
}
|
||||
|
||||
export interface PublicSewageInquirySummaryItem {
|
||||
// 기본 정보 및 행정구역
|
||||
ctpvNm: string;
|
||||
sggNm: string;
|
||||
statsYr: string;
|
||||
admdstCd: string;
|
||||
admdstNm: string;
|
||||
swtrmtFcltNm: string;
|
||||
rowType: string;
|
||||
fcltPstnCn: string;
|
||||
|
||||
// 시설 용량 (㎥/일)
|
||||
prcsFcltCpct: number;
|
||||
prcsFcltPhysCpct: number;
|
||||
prcsFcltBoilCpct: number;
|
||||
prcsFcltAltdCpct: number;
|
||||
|
||||
// 유입 및 처리량 (㎥/일)
|
||||
inflwSwageQnt: number;
|
||||
inflwSwagePhysQnt: number;
|
||||
inflwSwageBoilQnt: number;
|
||||
inflwSwageAltdQnt: number;
|
||||
|
||||
prcsQnt: number;
|
||||
prcsPhysCpct: number;
|
||||
prcsBoilCpct: number;
|
||||
prcsAltdCpct: number;
|
||||
|
||||
// 수질 정보 (유입/방류)
|
||||
inflwBodVl: number;
|
||||
dschgBodVl: number;
|
||||
inflwTocQnt: number;
|
||||
dschgTocQnt: number;
|
||||
inflwSsQnt: number;
|
||||
dschgSsQnt: number;
|
||||
inflwTnVl: number;
|
||||
dschgTnVl: number;
|
||||
inflwTpVl: number;
|
||||
dschgTpVl: number;
|
||||
inflwGrssClfgVl: number;
|
||||
dschgGrssClfgVl: number;
|
||||
|
||||
// 처리 효율 및 방법
|
||||
prcsRt: number;
|
||||
prcsLodQnt: number;
|
||||
prcsMthdExpln: string;
|
||||
|
||||
// 연계 처리량 (㎥/일)
|
||||
wholHmnQnt: number;
|
||||
wholLvstQnt: number;
|
||||
wholEfntQnt: number;
|
||||
wholEtcQnt: number;
|
||||
|
||||
// 부가 정보
|
||||
telNo: string;
|
||||
cmptnStrtYmd: string;
|
||||
oprtngStrtYmd: string;
|
||||
wholBizVl: number;
|
||||
eflntDsnfMthdExpln: string;
|
||||
|
||||
// 방류수역 정보
|
||||
wtsysNm: string;
|
||||
trbtrNm: string;
|
||||
dtlUnitZoneCn: string;
|
||||
rgnSeNm: string;
|
||||
msirbCn: string;
|
||||
goalWqNo: string;
|
||||
|
||||
// 에너지 및 위탁현황
|
||||
engySrlneRt: number;
|
||||
engyItslfPrdctnQnt: number;
|
||||
anlEngyWholUseQnt: number;
|
||||
anlElpwrUseQnt: number;
|
||||
itslfEngyUseQnt: number;
|
||||
swtrmtEmsnQnt: number;
|
||||
operMnbdCn: string;
|
||||
|
||||
// 위탁현황
|
||||
prxyBzentyNmCn: string;
|
||||
cnsgnCstVl: number;
|
||||
prxyCtrtCn: string;
|
||||
intgPrcsFcltCn: string;
|
||||
wholNope: number;
|
||||
sftyAcdntEvntcsCnt: number;
|
||||
}
|
||||
|
||||
export interface PublicSewageInquirySummaryResponse {
|
||||
status: string;
|
||||
message: string;
|
||||
data: PublicSewageInquirySummaryItem[];
|
||||
}
|
||||
+4
-4
@@ -34,7 +34,7 @@ export const hbArticleColumnInfo: ColumnInfo = {
|
||||
{
|
||||
name: "ipcrCntVl",
|
||||
fieldName: "ipcrCntVl",
|
||||
header: { text: "μ" },
|
||||
header: { text: "중요도 계수(μ)" },
|
||||
editable: false,
|
||||
sortdisable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
@@ -43,7 +43,7 @@ export const hbArticleColumnInfo: ColumnInfo = {
|
||||
{
|
||||
name: "pctlCrtrVl",
|
||||
fieldName: "pctlCrtrVl",
|
||||
header: { text: "Percentile" },
|
||||
header: { text: "백분위수 기준값(pct)" },
|
||||
editable: false,
|
||||
sortdisable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
@@ -52,7 +52,7 @@ export const hbArticleColumnInfo: ColumnInfo = {
|
||||
{
|
||||
name: "scopCntCntVl",
|
||||
fieldName: "scopCntCntVl",
|
||||
header: { text: "A" },
|
||||
header: { text: "스케일 조정 계수(A)" },
|
||||
editable: false,
|
||||
sortdisable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
@@ -61,7 +61,7 @@ export const hbArticleColumnInfo: ColumnInfo = {
|
||||
{
|
||||
name: "thrsCntVl",
|
||||
fieldName: "thrsCntVl",
|
||||
header: { text: "C" },
|
||||
header: { text: "임계 계수(c)" },
|
||||
editable: false,
|
||||
sortdisable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
|
||||
Reference in New Issue
Block a user