[st] feat: 입력- 저장,제출 로직 수정(01,02) & 02-6tab 로직 수정, 집계- 로직 수정 및 요약표 포함 조건 추가

This commit is contained in:
2026-04-28 17:08:59 +09:00
parent d462c50684
commit 3b170b0992
31 changed files with 2267 additions and 486 deletions
@@ -25,6 +25,12 @@ interface RealGridDataProviderComparer {
getValue?(row: number, field: string | number): unknown;
}
type GridViewWithCheckApi = GridViewWithSetColumns & {
checkItem?: (itemIndex: number, checked: boolean, exclusive?: boolean) => void;
checkRow?: (dataRow: number, checked: boolean, exclusive?: boolean) => void;
checkAll?: (checked: boolean) => void;
};
/** columnInfo → RealGrid DataField 배열 (computed → valueCallback 포함, setFields용) */
function buildFieldsFromColumns(columns: { fieldName: string; valueType?: ValueType; computed?: import("../type/DataGrid.type").ComputedFieldConfig }[]) {
return columns.map((col) => {
@@ -72,6 +78,8 @@ const CompactDataGrid = ({
getGridDataRef,
cellStyleCallback,
onRowClick,
onItemChecked,
onItemAllChecked,
compactFullWidth = false,
compactGridHeightClass = "h-[65vh]",
}: DataGridProps) => {
@@ -96,6 +104,32 @@ const CompactDataGrid = ({
(dataProvider as { setRows: (r: unknown[]) => void }).setRows(rowData);
}
// __checked 플래그(1/true/Y) 기반으로 체크바 상태 동기화
if (showHeaderCheckbox) {
const checkGrid = gridView as GridViewWithCheckApi;
const checkByRowFlag = (value: unknown) =>
value === true ||
value === 1 ||
value === "1" ||
value === "Y" ||
value === "y" ||
value === "true";
try {
checkGrid.checkAll?.(false);
rowData.forEach((row, itemIndex) => {
const checked = checkByRowFlag((row as Record<string, unknown>).__checked);
if (!checked) return;
if (checkGrid.checkItem) {
checkGrid.checkItem(itemIndex, true, false);
return;
}
checkGrid.checkRow?.(itemIndex, true, false);
});
} catch (e) {
console.warn("check sync:", e);
}
}
// setDataComparer로 숫자 정렬 (setFields 미사용 → 데이터 유실·필드 중복 오류 없음)
const dp = dataProvider as RealGridDataProviderComparer;
if (typeof dp.setDataComparer === "function" && typeof dp.getValue === "function") {
@@ -337,6 +371,32 @@ const CompactDataGrid = ({
};
}, [onRowClick]);
useEffect(() => {
const gridView = gridRef.current?.gridView;
if (!gridView) return;
if (onItemChecked) {
gridView.onItemChecked = (_grid, itemIndex, checked) => {
onItemChecked(itemIndex, checked);
};
} else {
gridView.onItemChecked = undefined;
}
if (onItemAllChecked) {
gridView.onItemAllChecked = (_grid, checked) => {
onItemAllChecked(checked);
};
} else {
gridView.onItemAllChecked = undefined;
}
return () => {
if (gridView.onItemChecked) gridView.onItemChecked = undefined;
if (gridView.onItemAllChecked) gridView.onItemAllChecked = undefined;
};
}, [onItemChecked, onItemAllChecked]);
return (
<div className={`flex flex-col gap-[0.6rem] ${compactFullWidth ? "w-full min-w-0" : "w-1/2"}`}>
<div className={compactGridHeightClass}>
+81 -71
View File
@@ -580,10 +580,10 @@ const DataGrid = ({
) {
const cell =
worksheet[
XLSX.utils.encode_cell({
r: rowIndex,
c: col,
})
XLSX.utils.encode_cell({
r: rowIndex,
c: col,
})
];
if (
cell &&
@@ -659,7 +659,7 @@ const DataGrid = ({
const col = range.s.c + colIndex;
const cell =
worksheet[
XLSX.utils.encode_cell({ r: row, c: col })
XLSX.utils.encode_cell({ r: row, c: col })
];
const headerName =
headers[colIndex] || `Column${colIndex + 1}`;
@@ -783,13 +783,13 @@ const DataGrid = ({
onSorting?: (g: unknown, f: unknown[], d: unknown[]) => boolean;
}
).onSorting = enableSort
? createOnSortingHandler(
columns,
setRowData,
sortDirRef,
originalRowsRef,
)
: () => false;
? createOnSortingHandler(
columns,
setRowData,
sortDirRef,
originalRowsRef,
)
: () => false;
(gridView.displayOptions as DisplayOptions).fitStyle =
GridFitStyle.EVEN;
@@ -959,7 +959,7 @@ const DataGrid = ({
) {
(
column.footer[
index
index
] as FooterItemWithCallback
).valueCallback =
footerItem.valueCallback;
@@ -1012,11 +1012,11 @@ const DataGrid = ({
getGridDataRef.current = () => {
const gv = gridRef.current?.gridView as
| {
getDataSource?: () => {
getRowCount(): number;
getValue(r: number, f: string): unknown;
};
}
getDataSource?: () => {
getRowCount(): number;
getValue(r: number, f: string): unknown;
};
}
| undefined;
if (!gv?.getDataSource) return [];
const ds = gv.getDataSource();
@@ -1189,29 +1189,37 @@ const DataGrid = ({
style={{ display: "none" }}
onChange={handleFileChange}
/>
<div className="flex items-center justify-end gap-[0.6rem] px-[1.2rem]">
<div className={`flex items-center ${statusInfo ? 'justify-between' : 'justify-end'} gap-[0.6rem] pr-[1.2rem]`}>
{statusInfo && (
<div className="data-grid-status-bubble flex flex-wrap items-center gap-x-4 gap-y-1">
<span>
진행상황:{" "}
{statusInfo.laeSbmsnSttsCd === null ||
statusInfo.laeSbmsnSttsCd === "0"
statusInfo.laeSbmsnSttsCd === "0"
? "미작성"
: statusInfo.laeSbmsnSttsCd === "1"
? "작성중"
: statusInfo.laeSbmsnSttsCd === "2"
? "제출"
: statusInfo.laeSbmsnSttsCd === "3"
? "승인"
: statusInfo.laeSbmsnSttsCd === "4"
? "반려"
: "검증중"}
? <span className="animate-pulse">작성중</span>
: statusInfo.laeSbmsnSttsCd === "2"
? <span className="!text-[#2094fa]">제출</span>
: statusInfo.laeSbmsnSttsCd === "3"
? <span className="!text-[#1fd078]">승인</span>
: statusInfo.laeSbmsnSttsCd === "4"
? (
<span className="relative inline-flex !text-[#ff6c64] pr-3">
반려
<span className="absolute -right-0.5 -top-0.5 inline-flex size-[0.6125rem]">
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-[#ff6c64] opacity-75" />
<span className="relative inline-flex size-[0.6125rem] rounded-full bg-[#ff6c64]" />
</span>
</span>
)
: <span className="animate-pulse">검증중</span>}
</span>
<span>
제출일:{" "}
{statusInfo.laeSbmsnYmd
? statusInfo.laeSbmsnYmd.length === 8 &&
/^\d{8}$/.test(statusInfo.laeSbmsnYmd)
/^\d{8}$/.test(statusInfo.laeSbmsnYmd)
? `${statusInfo.laeSbmsnYmd.slice(0, 4)}-${statusInfo.laeSbmsnYmd.slice(4, 6)}-${statusInfo.laeSbmsnYmd.slice(6, 8)}`
: statusInfo.laeSbmsnYmd
: "미제출"}
@@ -1228,26 +1236,28 @@ const DataGrid = ({
</span>
</div>
)}
{isExcelImport && (
<Button
className="h-[3.2rem] w-[96px] bg-gradient-green px-6 hover:bg-gradient-green-hover"
type="button"
onClick={importExcel}
>
<i className="diveicon di-file-excel" />
<span>가져오기</span>
</Button>
)}
{isExcelExport && (
<Button
className="h-[3.2rem] w-[96px] bg-gradient-green px-6 hover:bg-gradient-green-hover"
type="button"
onClick={exportExcel}
>
<i className="diveicon di-file-excel" />
<span>내보내기</span>
</Button>
)}
<div className="flex items-center gap-[0.6rem]">
{isExcelImport && (
<Button
className="h-[3.2rem] w-[96px] bg-gradient-green px-6 hover:bg-gradient-green-hover"
type="button"
onClick={importExcel}
>
<i className="diveicon di-file-excel" />
<span>가져오기</span>
</Button>
)}
{isExcelExport && (
<Button
className="h-[3.2rem] w-[96px] bg-gradient-green px-6 hover:bg-gradient-green-hover"
type="button"
onClick={exportExcel}
>
<i className="diveicon di-file-excel" />
<span>내보내기</span>
</Button>
)}
</div>
</div>
<div style={{ height: `${gridHeight}vh` }}>
<RealGridReact
@@ -1266,24 +1276,24 @@ const DataGrid = ({
) => boolean;
}
).onSorting = enableSort
? createOnSortingHandler(
columns,
setRowData,
sortDirRef,
originalRowsRef,
)
: () => false;
? createOnSortingHandler(
columns,
setRowData,
sortDirRef,
originalRowsRef,
)
: () => false;
const dataProvider = gridRef.current
?.dataProvider as unknown as
| {
setFields?(f: unknown[]): void;
setRows?(
r: Record<string, string | number>[],
): void;
getJsonRow?(
r: number,
): Record<string, unknown>;
}
setFields?(f: unknown[]): void;
setRows?(
r: Record<string, string | number>[],
): void;
getJsonRow?(
r: number,
): Record<string, unknown>;
}
| undefined;
if (dataProvider?.setFields) {
dataProvider.setFields(
@@ -1436,14 +1446,14 @@ const DataGrid = ({
})}
footer={
column.footer &&
!Array.isArray(column.footer)
!Array.isArray(column.footer)
? {
text: column.footer.text,
expression:
column.footer.expression,
numberFormat:
column.footer.numberFormat,
}
text: column.footer.text,
expression:
column.footer.expression,
numberFormat:
column.footer.numberFormat,
}
: undefined
}
mergeRule={
@@ -4,15 +4,20 @@ import { useState } from "react";
import { Button, Dialog, DialogContent, DialogHeader, DialogTitle } from "@common/components";
import SidoSggFacilityNameSearchForm from "./SidoSggFacilityNameSearchForm";
import type { SearchFormValues } from "../type/SearchForm.type";
type GridTopActionButtonProps = {
text: string;
onClick?: (helpers: { openDialog: (title?: string) => void; closeDialog: () => void }) => void;
/** 상위 화면 검색 통계연도 — 시설 조회 다이얼로그에 전달 */
statsYr?: string;
/** 상위 화면 최근 검색조건 */
initialSearchValues?: Pick<SearchFormValues, "sido" | "gugun" | "bsnmCd"> | null;
/** 다이얼로그 저장 성공 후 부모 갱신 */
onSaveSuccess?: () => Promise<void> | void;
};
const GridTopActionButton = ({ text, onClick, statsYr }: GridTopActionButtonProps) => {
const GridTopActionButton = ({ text, onClick, statsYr, initialSearchValues, onSaveSuccess }: GridTopActionButtonProps) => {
const [isOpen, setIsOpen] = useState(false);
const [title, setTitle] = useState(text);
@@ -41,7 +46,11 @@ const GridTopActionButton = ({ text, onClick, statsYr }: GridTopActionButtonProp
<DialogHeader>
<DialogTitle>{title}</DialogTitle>
</DialogHeader>
<SidoSggFacilityNameSearchForm statsYr={statsYr} />
<SidoSggFacilityNameSearchForm
statsYr={statsYr}
initialSearchValues={initialSearchValues}
onSaveSuccess={onSaveSuccess}
/>
</DialogContent>
</Dialog>
</>
+29 -2
View File
@@ -89,6 +89,7 @@ const SearchForm = (props: SearchFormProps = {}) => {
fctName: props.defaultValues?.fctName || "",
bsnmCd: props.defaultValues?.bsnmCd || "",
isDetail: false,
isSummary: props.defaultValues?.isSummary || "",
});
const sggKey: [string, string, string, string] | null =
@@ -132,6 +133,7 @@ const SearchForm = (props: SearchFormProps = {}) => {
fctName: "",
bsnmCd: "",
isDetail: false,
isSummary: "",
};
setValues(resetValues);
props.onReset?.();
@@ -153,7 +155,7 @@ const SearchForm = (props: SearchFormProps = {}) => {
const selectedBsnm =
value === "ALL"
? sidoList?.data.sidoList.find((v) => v.sido === values.sido)
?.bsnmCd || ""
?.bsnmCd || ""
: listForBsnm.find((v) => v.gugun === value)?.bsnmCd || "";
setValues((prev) => ({
@@ -250,10 +252,11 @@ const SearchForm = (props: SearchFormProps = {}) => {
)}
{mergedProps.isDetail && (
<div className="flex items-center gap-2">
<Label className="text-label">
<Label className="text-label cursor-pointer" htmlFor="isDetail">
세부 데이터 포함
</Label>
<Checkbox
id="isDetail"
checked={values.isDetail}
onCheckedChange={(value) =>
setValues({
@@ -264,6 +267,30 @@ const SearchForm = (props: SearchFormProps = {}) => {
/>
</div>
)}
{mergedProps.isSummary && (
<div className="flex items-center gap-2">
<Label className="text-label cursor-pointer">
요약표 포함
</Label>
<Select
value={values.isSummary}
onValueChange={(value) =>
setValues({ ...values, isSummary: value })
}
>
<SelectTrigger className="w-[10rem]">
<SelectValue placeholder="선택 안함"></SelectValue>
</SelectTrigger>
<SelectContent>
<SelectItem value="ALL">선택 안함</SelectItem>
{[1,2,3,4,5,6,7,8,9,10].map((i) => (
<SelectItem value={i.toString()} key={i.toString()}>{`${i}개년`}</SelectItem>
))
}
</SelectContent>
</Select>
</div>
)}
{mergedProps.order && (
<div className="flex items-center gap-2">
<Label className="text-label">차수</Label>
@@ -1,6 +1,6 @@
"use client";
import { useState } from "react";
import { useEffect, useRef, useState } from "react";
import useSWR from "swr";
import { ValueType } from "realgrid";
@@ -29,8 +29,13 @@ import type { ColumnInfo } from "../type/DataGrid.type";
import type {
SeweragePipeFacilitiesListRequest,
SeweragePipeFacilityAdminAreaListRequest,
SeweragePipeFactConnectionSaveRequest,
SeweragePipeFactConnectionSaveItem,
} from "@/entities/statistics/model/input/statistics-sewage-pipe-input-interface";
import { statisticsInputSewPipeApiService } from "@/entities/statistics/api/input/statistics-sewage-pipe-input-service";
import type { SearchFormValues } from "../type/SearchForm.type";
import { doNameList } from "../util/column/input/DoList";
import { getUserInfo } from "../../../../../packages/common/components/src/api";
/** 다이얼로그 좌측: 처리시설 정보 (순번 없음) */
const treatmentFacilityColumnInfo: ColumnInfo = {
@@ -48,21 +53,35 @@ const treatmentFacilityColumnInfo: ColumnInfo = {
editable: false,
},
{
name: "fctNm",
fieldName: "fctNm",
name: "fcltNm",
fieldName: "fcltNm",
header: { text: "시설명" },
editable: false,
},
{
name: "fctCpc",
fieldName: "fctCpc",
name: "fcltCd",
fieldName: "fcltCd",
header: { text: "시설코드" },
editable: false,
visible: false,
},
{
name: "fcltSn",
fieldName: "fcltSn",
header: { text: "시설일련번호" },
editable: false,
visible: false,
},
{
name: "fcltCpct",
fieldName: "fcltCpct",
header: { text: "시설용량(m³/일)" },
valueType: ValueType.NUMBER,
dataFormat: "#,##0",
editable: false,
},
],
columnLayout: ["ctpvNm", "sggNm", "fctNm", "fctCpc"],
columnLayout: ["ctpvNm", "sggNm", "fcltNm", "fcltCpct", "fcltCd"],
};
/** 다이얼로그 우측: 행정구역 정보 (순번 없음, 헤더 체크박스는 showHeaderCheckbox) */
@@ -103,12 +122,26 @@ const getSggAllListFetcher = async (
type SidoSggFacilityNameSearchFormProps = {
/** 상위(SewagePipeInp 등) 검색 조건의 통계연도 — facilitiesList 등 API 필수값 */
statsYr?: string;
/** 상위(SewagePipeInp) 마지막 검색 조건 */
initialSearchValues?: Pick<SearchFormValues, "sido" | "gugun" | "bsnmCd"> | null;
/** 저장 성공 후 부모 탭 데이터 재조회 훅 */
onSaveSuccess?: () => Promise<void> | void;
};
const SidoSggFacilityNameSearchForm = ({
statsYr,
initialSearchValues,
onSaveSuccess,
}: SidoSggFacilityNameSearchFormProps) => {
const { setMessage: alert } = useAlertStore((state) => state);
const initialSidoValue =
initialSearchValues?.sido && initialSearchValues.sido !== "ALL"
? initialSearchValues.sido
: "ALL";
const initialGugunValue =
initialSearchValues?.gugun && initialSearchValues.gugun !== "ALL"
? initialSearchValues.gugun
: "ALL";
const { data: sidoList } = useSWR<ApiResponse<SearchCondition>>(
"sido-list",
@@ -134,9 +167,9 @@ const SidoSggFacilityNameSearchForm = ({
},
);
const [sido, setSido] = useState<string>("ALL");
const [gugun, setGugun] = useState<string>("ALL");
const [fctNm, setFctNm] = useState<string>("");
const [sido, setSido] = useState<string>(initialSidoValue);
const [gugun, setGugun] = useState<string>(initialGugunValue);
const [fcltNm, setFcltNm] = useState<string>("");
const [isLoading, setIsLoading] = useState<boolean>(false);
const [treatmentFacilityRows, setTreatmentFacilityRows] = useState<
@@ -145,6 +178,10 @@ const SidoSggFacilityNameSearchForm = ({
const [adminRegionRows, setAdminRegionRows] = useState<
Record<string, string | number>[]
>([]);
const [selectedFacilityRow, setSelectedFacilityRow] = useState<
Record<string, string | number> | null
>(null);
const didAutoFetchRef = useRef(false);
const sggKey: [string, string] | null =
sido && sido !== "ALL" ? ["sgg-all", sido] : null;
@@ -198,7 +235,7 @@ const SidoSggFacilityNameSearchForm = ({
alert("시도를 선택해주세요.");
return;
}
const trimmedFclty = fctNm.trim();
const trimmedFclty = fcltNm.trim();
const sewerBzmnCd = resolveSewerBzmnCd();
@@ -225,13 +262,15 @@ const SidoSggFacilityNameSearchForm = ({
list.map((item) => ({
ctpvNm: item.ctpvNm,
sggNm: item.sggNm,
fctNm: item.bscFctNm,
fctCpc: item.fctCpc,
bscFctCd: item.bscFctCd,
fcltNm: item.fcltNm,
fcltCpct: item.fcltCpct,
fcltCd: item.fcltCd,
fcltSn: item.fcltSn,
admdstCd: item.admdstCd,
statsYr: item.statsYr,
})),
);
setSelectedFacilityRow(null);
setAdminRegionRows([]);
} catch {
alert("처리시설 목록 조회 중 오류가 발생했습니다.");
@@ -247,7 +286,7 @@ const SidoSggFacilityNameSearchForm = ({
alert("상단에서 통계연도로 조회한 뒤 이용해 주세요.");
return;
}
const swtrmtFcltCd = String(row.bscFctCd ?? "").trim();
const swtrmtFcltCd = String(row.fcltCd ?? "").trim();
if (!swtrmtFcltCd) {
alert("처리시설 코드가 없습니다.");
return;
@@ -261,13 +300,14 @@ const SidoSggFacilityNameSearchForm = ({
const params: SeweragePipeFacilityAdminAreaListRequest = {
statsYr: statsYr.trim(),
swtrmtFcltCd,
sewerBzmnCd: String(row.admdstCd ?? "").trim(),
sewerBzmnCd: initialSearchValues?.bsnmCd || '',
ctpvNm,
sggNm,
...(doNameList.includes(ctpvNm) ? { sggNm } : {}),
};
try {
setIsLoading(true);
setSelectedFacilityRow(row);
const response =
await statisticsInputSewPipeApiService.getFacilityAdminAreaList(
params,
@@ -283,6 +323,8 @@ const SidoSggFacilityNameSearchForm = ({
sggNm: item.sggNm,
emdNm: item.admdstNm,
admdstCd: item.admdstCd,
isConnection: item.isConnection,
__checked: item.isConnection === "1" ? "1" : "0",
})),
);
} catch {
@@ -293,9 +335,172 @@ const SidoSggFacilityNameSearchForm = ({
};
const handleSaveAdminRegions = () => {
alert("저장 API 연동 예정입니다.");
if (!statsYr?.trim()) {
alert("상단에서 통계연도로 조회한 뒤 이용해 주세요.");
return;
}
if (!selectedFacilityRow) {
alert("처리시설을 먼저 선택해주세요.");
return;
}
const hasChanged = adminRegionRows.some(
(row) =>
(row.__checked === "1" && row.isConnection !== "1") ||
(row.__checked !== "1" && row.isConnection === "1"),
);
const saveList: SeweragePipeFactConnectionSaveItem[] = adminRegionRows
.filter((row) => row.__checked === "1")
.map((row) => ({
admdstCd: String(row.admdstCd ?? ""),
admdstNm: String(row.emdNm ?? ""),
}))
.filter((row) => row.admdstCd && row.admdstNm);
const deleteList = adminRegionRows
.filter((row) => row.__checked !== "1" && row.isConnection === "1")
.map((row) => String(row.admdstCd ?? ""))
.filter(Boolean);
if (!hasChanged) {
alert("변경된 연결 정보가 없습니다.");
return;
}
const run = async () => {
try {
setIsLoading(true);
const userInfo = await getUserInfo();
const request: SeweragePipeFactConnectionSaveRequest = {
ctpvNm: String(selectedFacilityRow.ctpvNm ?? ""),
sggNm: String(selectedFacilityRow.sggNm ?? ""),
fcltSn: String(selectedFacilityRow.fcltSn ?? ""),
statsYr: statsYr.trim(),
swtrmtFcltCd: String(selectedFacilityRow.fcltCd ?? ""),
swtrmtFcltNm: String(selectedFacilityRow.fcltNm ?? ""),
prcsFcltCpct: Number(selectedFacilityRow.fcltCpct ?? 0),
sewerBzmnCd: initialSearchValues?.bsnmCd?.trim() ?? "",
userId: userInfo.userUnqId,
saveList,
deleteList,
};
const response =
await statisticsInputSewPipeApiService.saveFactConnection(
request,
);
if (response.status !== "success") {
alert(response.message ?? "연결관계 저장에 실패했습니다.");
return;
}
setAdminRegionRows((prev) =>
prev.map((row) => ({
...row,
isConnection: row.__checked === "1" ? "1" : "0",
})),
);
await onSaveSuccess?.();
alert("저장되었습니다.");
} catch {
alert("연결관계 저장 중 오류가 발생했습니다.");
} finally {
setIsLoading(false);
}
};
void run();
};
const handleAdminRegionItemChecked = (
itemIndex: number,
checked: boolean,
) => {
setAdminRegionRows((prev) =>
prev.map((row, idx) =>
idx === itemIndex
? { ...row, __checked: checked ? "1" : "0" }
: row,
),
);
};
const handleAdminRegionItemAllChecked = (checked: boolean) => {
setAdminRegionRows((prev) =>
prev.map((row) => ({ ...row, __checked: checked ? "1" : "0" })),
);
};
useEffect(() => {
if (!initialSearchValues?.sido || initialSearchValues.sido === "ALL") return;
setSido(initialSearchValues.sido);
setGugun(
initialSearchValues.gugun && initialSearchValues.gugun !== "ALL"
? initialSearchValues.gugun
: "ALL",
);
}, [initialSearchValues?.sido, initialSearchValues?.gugun]);
useEffect(() => {
if (didAutoFetchRef.current) return;
if (!statsYr?.trim()) return;
if (!initialSearchValues?.sido || initialSearchValues.sido === "ALL") return;
const nextSido = initialSearchValues.sido;
const nextGugun =
initialSearchValues.gugun && initialSearchValues.gugun !== "ALL"
? initialSearchValues.gugun
: "ALL";
didAutoFetchRef.current = true;
setSido(nextSido);
setGugun(nextGugun);
const params: SeweragePipeFacilitiesListRequest = {
statsYr: statsYr.trim(),
...(initialSearchValues.bsnmCd?.trim()
? { sewerBzmnCd: initialSearchValues.bsnmCd.trim() }
: {}),
ctpvNm: nextSido,
...(nextGugun !== "ALL" ? { sggNm: nextGugun } : {}),
};
const run = async () => {
try {
setIsLoading(true);
const response =
await statisticsInputSewPipeApiService.getFacilitiesList(params);
if (response.status !== "success") {
alert(response.message ?? "처리시설 목록 조회에 실패했습니다.");
return;
}
const list = response.data ?? [];
setTreatmentFacilityRows(
list.map((item) => ({
ctpvNm: item.ctpvNm,
sggNm: item.sggNm,
fcltNm: item.fcltNm,
fcltCpct: item.fcltCpct,
fcltCd: item.fcltCd,
fcltSn: item.fcltSn,
admdstCd: item.admdstCd,
statsYr: item.statsYr,
})),
);
setSelectedFacilityRow(null);
setAdminRegionRows([]);
} catch {
alert("처리시설 목록 조회 중 오류가 발생했습니다.");
} finally {
setIsLoading(false);
}
};
void run();
}, [statsYr, initialSearchValues, alert]);
return (
<div className="flex flex-col gap-4 pt-2">
<form onSubmit={handleSubmit} className="flex flex-col gap-4">
@@ -346,8 +551,8 @@ const SidoSggFacilityNameSearchForm = ({
<Label className="shrink-0 text-label">시설명</Label>
<Input
className="min-w-[12rem] flex-1"
value={fctNm}
onChange={(e) => setFctNm(e.target.value)}
value={fcltNm}
onChange={(e) => setFcltNm(e.target.value)}
placeholder="시설명 입력"
/>
</div>
@@ -396,6 +601,8 @@ const SidoSggFacilityNameSearchForm = ({
rowData={adminRegionRows}
setRowData={setAdminRegionRows}
showHeaderCheckbox
onItemChecked={handleAdminRegionItemChecked}
onItemAllChecked={handleAdminRegionItemAllChecked}
compactFullWidth
// compactGridHeightClass="h-[min(40vh,28rem)] min-h-[16rem]"
/>