st: feat: 하수도보급률 입력 저장, 체출 로직 작업, 도-시 조회 시 버튼 조건 추가
This commit is contained in:
@@ -10,6 +10,7 @@ import type {
|
||||
FooterItemWithCallback,
|
||||
ColumnLayoutItem,
|
||||
CellStyleCallback,
|
||||
CellTooltipCallback,
|
||||
} from "../type/DataGrid.type";
|
||||
import { getComputedValueCallback } from "@/components/util/grid/computedFieldCallbacks";
|
||||
import JSZip from "jszip";
|
||||
@@ -311,6 +312,7 @@ const DataGrid = ({
|
||||
setRowData,
|
||||
getGridDataRef,
|
||||
cellStyleCallback,
|
||||
cellTooltipCallback,
|
||||
onRowClick,
|
||||
statusInfo,
|
||||
}: DataGridProps) => {
|
||||
@@ -321,8 +323,10 @@ const DataGrid = ({
|
||||
const originalRowsRef = useRef<Record<string, Record<string, string | number>[]>>({});
|
||||
const rowDataRef = useRef<Record<string, string | number>[]>(rowData);
|
||||
const cellStyleCallbackRef = useRef<CellStyleCallback | undefined>(cellStyleCallback);
|
||||
const cellTooltipCallbackRef = useRef<CellTooltipCallback | undefined>(cellTooltipCallback);
|
||||
rowDataRef.current = rowData;
|
||||
cellStyleCallbackRef.current = cellStyleCallback;
|
||||
cellTooltipCallbackRef.current = cellTooltipCallback;
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (!cellStyleCallback || !gridRef.current?.gridView) return;
|
||||
@@ -980,38 +984,38 @@ const DataGrid = ({
|
||||
getGridDataRef,
|
||||
]);
|
||||
|
||||
// 행 클릭 이벤트 설정
|
||||
// 행 클릭 이벤트 + 검증 오류 셀 클릭 시 showMessage (공식 문서 방식)
|
||||
useEffect(() => {
|
||||
if (!gridRef.current?.gridView || !onRowClick) return;
|
||||
const gridView = gridRef.current?.gridView;
|
||||
if (!gridView || (!onRowClick && !cellTooltipCallback)) return;
|
||||
|
||||
const gridView = gridRef.current.gridView;
|
||||
|
||||
// onCellClicked 이벤트 핸들러 설정
|
||||
gridView.onCellClicked = (grid, clickData) => {
|
||||
// 데이터 셀만 처리 (헤더, 푸터 등 제외)
|
||||
if (
|
||||
clickData.cellType === "data" &&
|
||||
clickData.itemIndex !== undefined
|
||||
) {
|
||||
try {
|
||||
// 행 전체 데이터 가져오기
|
||||
const row = rowData[clickData.itemIndex];
|
||||
|
||||
// 부모 컴포넌트로 데이터 전달
|
||||
onRowClick(row ?? {});
|
||||
} catch (error) {
|
||||
console.error("행 데이터 가져오기 오류:", error);
|
||||
if (clickData.cellType !== "data" || clickData.itemIndex === undefined) return;
|
||||
try {
|
||||
const row = rowDataRef.current[clickData.itemIndex];
|
||||
const cellIndex = (grid as { getCurrent?: () => { itemIndex: number; column?: string; fieldName?: string } }).getCurrent?.();
|
||||
// cellTooltipCallback 있으면 해당 셀 메시지로 showMessage (공식 문서: TooltipOptions + CellIndex)
|
||||
if (cellTooltipCallbackRef.current && row && cellIndex) {
|
||||
const fieldName = cellIndex.fieldName ?? cellIndex.column ?? "";
|
||||
const msg = cellTooltipCallbackRef.current({ row: row as Record<string, string | number>, fieldName });
|
||||
if (msg) {
|
||||
const colName = columns.find((c) => c.fieldName === fieldName || c.name === cellIndex.column)?.name ?? cellIndex.column ?? fieldName;
|
||||
(gridView as { showMessage?: (opts: { message: string; hideDuration?: number }, idx: { itemIndex: number; column: string }) => void }).showMessage?.(
|
||||
{ message: msg, hideDuration: 5000 },
|
||||
{ itemIndex: cellIndex.itemIndex, column: colName }
|
||||
);
|
||||
}
|
||||
}
|
||||
if (onRowClick) onRowClick((row ?? {}) as Record<string, string | number>);
|
||||
} catch (error) {
|
||||
console.error("행 데이터 가져오기 오류:", error);
|
||||
}
|
||||
};
|
||||
|
||||
// cleanup: 컴포넌트 언마운트 시 이벤트 핸들러 제거
|
||||
return () => {
|
||||
if (gridView.onCellClicked) {
|
||||
gridView.onCellClicked = undefined;
|
||||
}
|
||||
if (gridView.onCellClicked) gridView.onCellClicked = undefined;
|
||||
};
|
||||
}, [onRowClick]);
|
||||
}, [onRowClick, cellTooltipCallback, columns]);
|
||||
|
||||
return (
|
||||
<div className="mx-[0.6rem] flex flex-col gap-[0.6rem]">
|
||||
@@ -1034,7 +1038,11 @@ const DataGrid = ({
|
||||
statusInfo.locgStatus === '3' ? '승인' : '반려'
|
||||
}
|
||||
</span>
|
||||
<span>제출일: {statusInfo.locgDt ? statusInfo.locgDt : '미제출'}</span>
|
||||
<span>제출일: {statusInfo.locgDt
|
||||
? (statusInfo.locgDt.length === 8 && /^\d{8}$/.test(statusInfo.locgDt)
|
||||
? `${statusInfo.locgDt.slice(0, 4)}-${statusInfo.locgDt.slice(4, 6)}-${statusInfo.locgDt.slice(6, 8)}`
|
||||
: statusInfo.locgDt)
|
||||
: '미제출'}</span>
|
||||
<span>담당자: {statusInfo.locgCharger ? statusInfo.locgCharger : '-'}</span>
|
||||
<span>연락처: {statusInfo.locgCttpc ? statusInfo.locgCttpc : '-'}</span>
|
||||
</div>
|
||||
@@ -1083,10 +1091,26 @@ const DataGrid = ({
|
||||
setTimeout(() => {
|
||||
const gv = gridRef.current?.gridView;
|
||||
if (!gv?.columnByName) return;
|
||||
// 공식 문서: 데이터 영역 툴팁 = renderer.showTooltip + onShowTooltip (displayOptions는 Ellipsis용이라 사용 안 함)
|
||||
if (cellTooltipCallbackRef.current) {
|
||||
(gv as { onShowTooltip?: (grid: unknown, index: { itemIndex: number; column: string }, value: string) => string | undefined }).onShowTooltip = (_grid, index, value) => {
|
||||
const row = rowDataRef.current[index?.itemIndex];
|
||||
if (row == null) return value;
|
||||
const column = index.column;
|
||||
const col = columns.find((c) => c.name === column);
|
||||
const fieldName = col?.fieldName ?? column;
|
||||
const custom = cellTooltipCallbackRef.current?.({ row: row as Record<string, string | number>, fieldName });
|
||||
// verificationResult 등 메시지가 있을 때만 툴팁 표시 (없으면 undefined 반환 → 툴팁 안 띄움)
|
||||
return custom && custom.length > 0 ? custom : undefined;
|
||||
};
|
||||
}
|
||||
columns.forEach((column) => {
|
||||
const baseStyleName = column.styleName;
|
||||
const gridCol = gv.columnByName(column.name) as { styleCallback?: (g: unknown, dataCell: { itemIndex?: number; index?: { itemIndex?: number }; dataField?: string; fieldName?: string }) => string } | null;
|
||||
const gridCol = gv.columnByName(column.name) as { styleCallback?: (g: unknown, dataCell: { itemIndex?: number; index?: { itemIndex?: number }; dataField?: string; fieldName?: string }) => string; renderer?: { showTooltip?: boolean } } | null;
|
||||
if (gridCol) {
|
||||
if (cellTooltipCallbackRef.current) {
|
||||
(gv as { setColumnProperty?: (col: string, key: string, value: unknown) => void }).setColumnProperty?.(column.name, 'renderer', { showTooltip: true });
|
||||
}
|
||||
gridCol.styleCallback = (_g, dataCell) => {
|
||||
const itemIndex = dataCell?.index?.itemIndex ?? dataCell?.itemIndex ?? -1;
|
||||
const fieldName = dataCell?.dataField ?? dataCell?.fieldName ?? column.fieldName;
|
||||
@@ -1117,6 +1141,7 @@ const DataGrid = ({
|
||||
editable={column.editable}
|
||||
{...(baseStyleName != null && { styleName: baseStyleName })}
|
||||
{...(column.visible === false && { visible: false })}
|
||||
{...(cellTooltipCallback && { renderer: { showTooltip: true } })}
|
||||
footer={column.footer && !Array.isArray(column.footer) ? {
|
||||
text: column.footer.text,
|
||||
expression: column.footer.expression,
|
||||
|
||||
@@ -9,6 +9,7 @@ import LastYearDataButton from "@/components/button/LastYearDataButton";
|
||||
import SubmitExceptionButton from "@/components/button/SubmitExceptionButton";
|
||||
import { LoadingWithAnimation } from "@common/components";
|
||||
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
||||
import SubmitDailog from "./SubmitDailog";
|
||||
|
||||
import { useAlertStore } from "@/shared/lib";
|
||||
import { statisticsInputAPi } from "@/entities/statistics/api/statistics-input-service";
|
||||
@@ -21,11 +22,13 @@ import type {
|
||||
SewerageSupplyRateSaveRequest,
|
||||
SewerageSupplyRateStatusInfo,
|
||||
} from "@/entities/statistics/model/statistics-input-interface";
|
||||
import type { StatisticsInputSubmitInfoFormData } from "@/entities/statistics/model/statistics-input-submit-info-schema";
|
||||
import { SeweragePenetrationRateInpColumn } from "@/components/util/column/input/SeweragePenetrationRateInpColumn";
|
||||
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 { doList } from "@/components/util/column/input/DoList";
|
||||
|
||||
type GridRowWithVerification = Record<string, string | number> & {
|
||||
verificationResult?: SewerageSupplyRateVerificationResult;
|
||||
@@ -36,10 +39,10 @@ function getSewerageSupplyRateParams(
|
||||
overrides?: { yr?: string; demoYr?: string; mode?: string }
|
||||
): SewerageSupplyRateRequestParams {
|
||||
return {
|
||||
sido: values.sido,
|
||||
gugun: values.gugun === 'ALL' ? '' : values.gugun,
|
||||
bsnmCd: values.bsnmCd,
|
||||
yr: overrides?.yr ?? values.year,
|
||||
ctpvNm: values.sido,
|
||||
sggNm: values.gugun === 'ALL' ? '' : values.gugun,
|
||||
sewerBzmnCd: values.bsnmCd,
|
||||
statsYr: overrides?.yr ?? values.year,
|
||||
...(overrides?.mode && { mode: overrides.mode }),
|
||||
};
|
||||
}
|
||||
@@ -52,13 +55,15 @@ const SeweragePenetrationRateInp = () => {
|
||||
const [searchValues, setSearchValues] = useState<SearchFormValues | null>(null);
|
||||
const [isEnterable, setIsEnterable] = useState<boolean>(true);
|
||||
const [lastSearchedYear, setLastSearchedYear] = useState<string | null>(null);
|
||||
const [lastSearchedValues, setLastSearchedValues] = useState<SearchFormValues | null>(null);
|
||||
const [statusInfo, setStatusInfo] = useState<SewerageSupplyRateStatusInfo | null>(null);
|
||||
const [showDailog, setShowDailog] = useState<boolean>(false);
|
||||
const { confirm } = useConfirm();
|
||||
|
||||
const [footerFromApi, setFooterFromApi] = useState<{ totalPopl?: number; poplSm?: number; frgnrPoplSm?: number } | null>(null);
|
||||
const [footerFromApi, setFooterFromApi] = useState<{ totalPopl?: number; poplSm?: number; frgnrPoplSm?: number; refArea?: number } | null>(null);
|
||||
const getGridDataRef = useRef<(() => Record<string, string | number>[]) | null>(null);
|
||||
|
||||
const footerFieldNames = ['totalPopl', 'poplSm', 'frgnrPoplSm'] as const;
|
||||
const footerFieldNames = ['totalPopl', 'poplSm', 'frgnrPoplSm', 'refArea'] as const;
|
||||
const footerWithApiDefault = (fieldName: (typeof footerFieldNames)[number], numberFormat: string) => ({
|
||||
expression: 'sum' as const,
|
||||
numberFormat,
|
||||
@@ -76,6 +81,7 @@ const SeweragePenetrationRateInp = () => {
|
||||
if (col.fieldName === 'totalPopl') return { ...col, footer: footerWithApiDefault('totalPopl', '#,##0') };
|
||||
if (col.fieldName === 'poplSm') return { ...col, footer: footerWithApiDefault('poplSm', '#,##0') };
|
||||
if (col.fieldName === 'frgnrPoplSm') return { ...col, footer: footerWithApiDefault('frgnrPoplSm', '#,##0') };
|
||||
if (col.fieldName === 'refArea') return { ...col, footer: footerWithApiDefault('refArea', '#,##0.000') };
|
||||
return col;
|
||||
}),
|
||||
};
|
||||
@@ -85,20 +91,22 @@ const SeweragePenetrationRateInp = () => {
|
||||
setRowData([]);
|
||||
setStatusInfo(null);
|
||||
setLastSearchedYear(null);
|
||||
setLastSearchedValues(null);
|
||||
setFooterFromApi(null);
|
||||
};
|
||||
|
||||
const fetchSewerageSupplyRate = async (params: SewerageSupplyRateRequestParams) => {
|
||||
const fetchSewerageSupplyRate = async (params: SewerageSupplyRateRequestParams, isEnterable: boolean) => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const response = await statisticsInputAPi.getSewerageSupplyRateList(params);
|
||||
if (response.status === 'success' && response.data) {
|
||||
const commonInfo = response.data.commonInfo;
|
||||
const statusInfo = response.data.statusInfo;
|
||||
const convertedData: SewerageSupplyRateItem[] = response.data.sewerageSupplyRateList.map((d) => ({
|
||||
...d,
|
||||
sido: commonInfo.sido,
|
||||
speclCntrplnAr: d.speclCntrplnAr === '' || d.speclCntrplnAr === null ? '해당없음' : d.speclCntrplnAr,
|
||||
piplSupprt: commonInfo.piplSupprt,
|
||||
ctpvNm: commonInfo.ctpvNm,
|
||||
spcCtpnRgnCn: d.spcCtpnRgnCn === '' || d.spcCtpnRgnCn === null ? '해당없음' : d.spcCtpnRgnCn,
|
||||
swagePplPsplyRt: commonInfo.swagePplPsplyRt,
|
||||
}));
|
||||
setRowData(
|
||||
convertedData.map((d) => {
|
||||
@@ -109,16 +117,27 @@ const SeweragePenetrationRateInp = () => {
|
||||
);
|
||||
|
||||
setStatusInfo(response.data.statusInfo);
|
||||
|
||||
setFooterFromApi(
|
||||
commonInfo
|
||||
? {
|
||||
totalPopl: commonInfo.bsnmTotalPopl,
|
||||
poplSm: commonInfo.bsnmPoplSm,
|
||||
frgnrPoplSm: commonInfo.bsnmFrgnrPoplSm,
|
||||
totalPopl: commonInfo.sewerBzmnTotalPopl,
|
||||
poplSm: commonInfo.sewerBzmnPoplSm,
|
||||
frgnrPoplSm: commonInfo.sewerBzmnFrgnrPoplSm,
|
||||
refArea: commonInfo.sewerBzmnArea,
|
||||
}
|
||||
: null
|
||||
);
|
||||
|
||||
if (statusInfo && statusInfo.locgStatus) {
|
||||
if (['2', '3'].includes(statusInfo.locgStatus)) {
|
||||
setIsEnterable(false);
|
||||
} else {
|
||||
setIsEnterable(isEnterable);
|
||||
}
|
||||
} else {
|
||||
setIsEnterable(isEnterable);
|
||||
}
|
||||
|
||||
} else {
|
||||
alert(response.message);
|
||||
}
|
||||
@@ -142,10 +161,11 @@ const SeweragePenetrationRateInp = () => {
|
||||
const response = await statisticsInputAPi.checkInputPeriod(values.year || '');
|
||||
|
||||
if (response.status === 'success') {
|
||||
setIsEnterable(response.data);
|
||||
const checkEnterable = response.data;
|
||||
// setIsEnterable(response.data);
|
||||
setLastSearchedYear(values.year || null);
|
||||
|
||||
await fetchSewerageSupplyRate(getSewerageSupplyRateParams(values));
|
||||
await fetchSewerageSupplyRate(getSewerageSupplyRateParams(values), checkEnterable);
|
||||
setLastSearchedValues(values);
|
||||
} else {
|
||||
alert(response.message);
|
||||
}
|
||||
@@ -170,16 +190,101 @@ const SeweragePenetrationRateInp = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
await fetchSewerageSupplyRate(getSewerageSupplyRateParams(values, { mode: 'PRE' }));
|
||||
await fetchSewerageSupplyRate(getSewerageSupplyRateParams(values, { mode: 'PRE' }), true);
|
||||
};
|
||||
|
||||
const submitFunc = () => {
|
||||
const submitFunc = async () => {
|
||||
const isError = rowData.filter((d) => d.verificationResult);
|
||||
|
||||
if (isError.length > 0) {
|
||||
alert('검증 오류 데이터가 있습니다.');
|
||||
return;
|
||||
}
|
||||
if (await confirm('제출 하시겠습니까?')) {
|
||||
setShowDailog(true);
|
||||
}
|
||||
};
|
||||
|
||||
const executeSubmit = async (submitInfo: StatisticsInputSubmitInfoFormData) => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const userInfo = await getUserInfo();
|
||||
const currentData = getGridDataRef.current?.();
|
||||
if (!currentData || currentData.length === 0) {
|
||||
alert('제출할 데이터가 없습니다.');
|
||||
return;
|
||||
}
|
||||
const columnFormatMap = new Map<string, string>();
|
||||
SeweragePenetrationRateInpColumn.columns.forEach((col) => {
|
||||
if (col.fieldName && col.dataFormat) {
|
||||
columnFormatMap.set(col.fieldName, col.dataFormat);
|
||||
}
|
||||
});
|
||||
const formatNumber = (value: string | number | null | undefined, fieldName: string): number => {
|
||||
if (value === null || value === undefined || value === '') return 0;
|
||||
const num = typeof value === 'string' ? parseFloat(value.replace(/,/g, '')) : value;
|
||||
if (isNaN(num)) return 0;
|
||||
const format = columnFormatMap.get(fieldName);
|
||||
if (!format) return num;
|
||||
const decimalPlaces = format.match(/\.(\d+)/)?.[1]?.length ?? 0;
|
||||
return decimalPlaces > 0 ? parseFloat(num.toFixed(decimalPlaces)) : Math.round(num);
|
||||
};
|
||||
const convertedData: SewerageSupplyRateSaveItem[] = currentData.map((d) => ({
|
||||
sggNm: (d.sggNm as string) || null,
|
||||
admdstCd: d.admdstCd as string,
|
||||
admdstNm: d.admdstNm as string,
|
||||
trbtrNm: d.trbtrNm as string,
|
||||
spcCtpnRgnCn: d.spcCtpnRgnCn === '해당없음' ? null : (d.spcCtpnRgnCn as string | null),
|
||||
ts1SwtrmtPpltnCnt: formatNumber(d.ts1SwtrmtPpltnCnt, 'ts1SwtrmtPpltnCnt'),
|
||||
ts2SwtrmtPpltnCnt: formatNumber(d.ts2SwtrmtPpltnCnt, 'ts2SwtrmtPpltnCnt'),
|
||||
ts3SwtrmtPpltnCnt: formatNumber(d.ts3SwtrmtPpltnCnt, 'ts3SwtrmtPpltnCnt'),
|
||||
ts1WwtPrcsPpltnCnt: formatNumber(d.ts1WwtPrcsPpltnCnt, 'ts1WwtPrcsPpltnCnt'),
|
||||
ts2WwtPrcsPpltnCnt: formatNumber(d.ts2WwtPrcsPpltnCnt, 'ts2WwtPrcsPpltnCnt'),
|
||||
ts3WwtPrcsPpltnCnt: formatNumber(d.ts3WwtPrcsPpltnCnt, 'ts3WwtPrcsPpltnCnt'),
|
||||
yetCntnPpltnCnt: formatNumber(d.yetCntnPpltnCnt, 'yetCntnPpltnCnt'),
|
||||
staaArea: formatNumber(d.staaArea, 'staaArea'),
|
||||
unprcsPpltnCnt: formatNumber(d.unprcsPpltnCnt, 'unprcsPpltnCnt'),
|
||||
drtwPrcsPpltnCnt: formatNumber(d.drtwPrcsPpltnCnt, 'drtwPrcsPpltnCnt'),
|
||||
spctnkPpltnCnt: formatNumber(d.spctnkPpltnCnt, 'spctnkPpltnCnt'),
|
||||
staaExcpArea: formatNumber(d.staaExcpArea, 'staaExcpArea'),
|
||||
rmrk: (d.rmrk as string) ?? '',
|
||||
wholPpltnCnt: formatNumber(d.wholPpltnCnt, 'wholPpltnCnt'),
|
||||
wholArea: formatNumber(d.wholArea, 'wholArea'),
|
||||
wholSwtrmtPpltnCnt: formatNumber(d.wholSwtrmtPpltnCnt, 'wholSwtrmtPpltnCnt'),
|
||||
wholPblSwtrmtPpltnCnt: formatNumber(d.wholPblSwtrmtPpltnCnt, 'wholPblSwtrmtPpltnCnt'),
|
||||
wholWwtPrcsPpltnCnt: formatNumber(d.wholWwtPrcsPpltnCnt, 'wholWwtPrcsPpltnCnt'),
|
||||
wholStaaExcpPpltnCnt: formatNumber(d.wholStaaExcpPpltnCnt, 'wholStaaExcpPpltnCnt'),
|
||||
staaPsplyRt: formatNumber(d.staaPsplyRt, 'staaPsplyRt'),
|
||||
altdPrcsPsplyRt: formatNumber(d.altdPrcsPsplyRt, 'altdPrcsPsplyRt'),
|
||||
sewerInstlRt: formatNumber(d.sewerInstlRt, 'sewerInstlRt'),
|
||||
}));
|
||||
const requestData: SewerageSupplyRateSaveRequest = {
|
||||
sewerBzmnCd: searchValues?.bsnmCd ?? '',
|
||||
ctpvNm: searchValues?.sido ?? '',
|
||||
statsYr: searchValues?.year ?? '',
|
||||
userId: userInfo.userUnqId,
|
||||
submitList: convertedData,
|
||||
sewerBzmnFrgnrPoplSm: footerFromApi?.frgnrPoplSm,
|
||||
locgCharger: submitInfo.locgCharger,
|
||||
locgJob: submitInfo.locgJob,
|
||||
locgDept: submitInfo.locgDept,
|
||||
locgCttpc: submitInfo.locgCttpc,
|
||||
locgCnfirmNm: submitInfo.locgCnfirmNm,
|
||||
locgCnfirmJob: submitInfo.locgCnfirmJob,
|
||||
locgCnfirmDept: submitInfo.locgCnfirmDept,
|
||||
locgCnfirmPh: submitInfo.locgCnfirmPh,
|
||||
};
|
||||
const response = await statisticsInputAPi.submitSewerageSupplyRate(requestData);
|
||||
if (response.status === 'success') {
|
||||
await fetchSewerageSupplyRate(getSewerageSupplyRateParams(searchValues ?? {}), false);
|
||||
alert('제출되었습니다.');
|
||||
} else {
|
||||
alert('데이터 제출 중 오류가 발생했습니다.');
|
||||
}
|
||||
} catch {
|
||||
alert('데이터 제출 중 오류가 발생했습니다.');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const saveFunc = async () => {
|
||||
@@ -218,47 +323,54 @@ const SeweragePenetrationRateInp = () => {
|
||||
};
|
||||
|
||||
const convertedData: SewerageSupplyRateSaveItem[] = currentData.map((d) => ({
|
||||
gugun: (d.gugun as string) || null,
|
||||
adstCd: d.adstCd as string,
|
||||
adstDong: d.adstDong as string,
|
||||
bstrm: d.bstrm as string,
|
||||
speclCntrplnAr: d.speclCntrplnAr === '해당없음' ? null : (d.speclCntrplnAr as string | null),
|
||||
pblswrgPrmTrt: formatNumber(d.pblswrgPrmTrt, 'pblswrgPrmTrt'),
|
||||
pblswrgScdTrt: formatNumber(d.pblswrgScdTrt, 'pblswrgScdTrt'),
|
||||
pblswrgTertTrt: formatNumber(d.pblswrgTertTrt, 'pblswrgTertTrt'),
|
||||
wstrPrmTrt: formatNumber(d.wstrPrmTrt, 'wstrPrmTrt'),
|
||||
wstrScdTrt: formatNumber(d.wstrScdTrt, 'wstrScdTrt'),
|
||||
wstrTertTrt: formatNumber(d.wstrTertTrt, 'wstrTertTrt'),
|
||||
notConectPopltn: formatNumber(d.notConectPopltn, 'notConectPopltn'),
|
||||
swgeProcZoneInnerAr: formatNumber(d.swgeProcZoneInnerAr, 'swgeProcZoneInnerAr'),
|
||||
townUnprocPopltn: formatNumber(d.townUnprocPopltn, 'townUnprocPopltn'),
|
||||
townSwttPopltn: formatNumber(d.townSwttPopltn, 'townSwttPopltn'),
|
||||
townWrrtnPopltn: formatNumber(d.townWrrtnPopltn, 'townWrrtnPopltn'),
|
||||
swgeProcZoneOuterAr: formatNumber(d.swgeProcZoneOuterAr, 'swgeProcZoneOuterAr'),
|
||||
rmk: (d.rmk as string) ?? '',
|
||||
popltnSm: formatNumber(d.popltnSm, 'popltnSm'),
|
||||
arSm: formatNumber(d.arSm, 'arSm'),
|
||||
swgeProcZoneInnerSm: formatNumber(d.swgeProcZoneInnerSm, 'swgeProcZoneInnerSm'),
|
||||
pblswrgPopltnSm: formatNumber(d.pblswrgPopltnSm, 'pblswrgPopltnSm'),
|
||||
wstrPopltnSm: formatNumber(d.wstrPopltnSm, 'wstrPopltnSm'),
|
||||
swgeProcZoneOuterSm: formatNumber(d.swgeProcZoneOuterSm, 'swgeProcZoneOuterSm'),
|
||||
pblswrgPopltnSuprt: formatNumber(d.pblswrgPopltnSuprt, 'pblswrgPopltnSuprt'),
|
||||
adtrtPopltnSuprt: formatNumber(d.adtrtPopltnSuprt, 'adtrtPopltnSuprt'),
|
||||
swrgInstlrt: formatNumber(d.swrgInstlrt, 'swrgInstlrt'),
|
||||
// 행정구역
|
||||
sggNm: (d.sggNm as string) || null, // 시군구
|
||||
admdstCd: d.admdstCd as string, // 행정코드
|
||||
admdstNm: d.admdstNm as string, // 행정구역명
|
||||
trbtrNm: d.trbtrNm as string, // 지류
|
||||
spcCtpnRgnCn: d.spcCtpnRgnCn === '해당없음' ? null : (d.spcCtpnRgnCn as string | null), // 특별대책지역
|
||||
// 공공하수처리인구(명) - 물리적/생물학적/고도처리
|
||||
ts1SwtrmtPpltnCnt: formatNumber(d.ts1SwtrmtPpltnCnt, 'ts1SwtrmtPpltnCnt'), // 물리적처리
|
||||
ts2SwtrmtPpltnCnt: formatNumber(d.ts2SwtrmtPpltnCnt, 'ts2SwtrmtPpltnCnt'), // 생물학적처리
|
||||
ts3SwtrmtPpltnCnt: formatNumber(d.ts3SwtrmtPpltnCnt, 'ts3SwtrmtPpltnCnt'), // 고도처리
|
||||
// 폐수처리인구(명) - 물리적/생물학적/고도처리
|
||||
ts1WwtPrcsPpltnCnt: formatNumber(d.ts1WwtPrcsPpltnCnt, 'ts1WwtPrcsPpltnCnt'),
|
||||
ts2WwtPrcsPpltnCnt: formatNumber(d.ts2WwtPrcsPpltnCnt, 'ts2WwtPrcsPpltnCnt'),
|
||||
ts3WwtPrcsPpltnCnt: formatNumber(d.ts3WwtPrcsPpltnCnt, 'ts3WwtPrcsPpltnCnt'),
|
||||
yetCntnPpltnCnt: formatNumber(d.yetCntnPpltnCnt, 'yetCntnPpltnCnt'), // 미접속인구
|
||||
staaArea: formatNumber(d.staaArea, 'staaArea'), // 하수처리구역 내 면적(㎢)
|
||||
// 하수처리구역 외
|
||||
unprcsPpltnCnt: formatNumber(d.unprcsPpltnCnt, 'unprcsPpltnCnt'), // 미처리인구
|
||||
drtwPrcsPpltnCnt: formatNumber(d.drtwPrcsPpltnCnt, 'drtwPrcsPpltnCnt'), // 오수처리인구
|
||||
spctnkPpltnCnt: formatNumber(d.spctnkPpltnCnt, 'spctnkPpltnCnt'), // 정화조인구
|
||||
staaExcpArea: formatNumber(d.staaExcpArea, 'staaExcpArea'), // 하수처리구역 외 면적(㎢)
|
||||
rmrk: (d.rmrk as string) ?? '', // 비고
|
||||
// 합계·소계(계산필드 저장용)
|
||||
wholPpltnCnt: formatNumber(d.wholPpltnCnt, 'wholPpltnCnt'), // 총인구(명)
|
||||
wholArea: formatNumber(d.wholArea, 'wholArea'), // 총면적(㎢)
|
||||
wholSwtrmtPpltnCnt: formatNumber(d.wholSwtrmtPpltnCnt, 'wholSwtrmtPpltnCnt'), // 하수처리구역 내 합계
|
||||
wholPblSwtrmtPpltnCnt: formatNumber(d.wholPblSwtrmtPpltnCnt, 'wholPblSwtrmtPpltnCnt'), // 공공하수처리인구 소계
|
||||
wholWwtPrcsPpltnCnt: formatNumber(d.wholWwtPrcsPpltnCnt, 'wholWwtPrcsPpltnCnt'), // 폐수처리인구 소계
|
||||
wholStaaExcpPpltnCnt: formatNumber(d.wholStaaExcpPpltnCnt, 'wholStaaExcpPpltnCnt'), // 하수처리구역 외 합계
|
||||
// 보급률(%)
|
||||
staaPsplyRt: formatNumber(d.staaPsplyRt, 'staaPsplyRt'), // 공공하수처리구역 인구보급률
|
||||
altdPrcsPsplyRt: formatNumber(d.altdPrcsPsplyRt, 'altdPrcsPsplyRt'), // 고도처리 인구보급률
|
||||
sewerInstlRt: formatNumber(d.sewerInstlRt, 'sewerInstlRt'), // 하수도 설치율
|
||||
}));
|
||||
|
||||
const requestData: SewerageSupplyRateSaveRequest = {
|
||||
bsnmCd: searchValues?.bsnmCd ?? '',
|
||||
sido: searchValues?.sido ?? '',
|
||||
yr: searchValues?.year ?? '',
|
||||
userId: userInfo.userName,
|
||||
saveList: convertedData,
|
||||
}
|
||||
sewerBzmnCd: searchValues?.bsnmCd ?? '', // 하수도 사업자 코드
|
||||
ctpvNm: searchValues?.sido ?? '', // 시도
|
||||
statsYr: searchValues?.year ?? '', // 통계 연도
|
||||
userId: userInfo.userUnqId, // 사용자
|
||||
saveList: convertedData, // 저장 데이터
|
||||
sewerBzmnFrgnrPoplSm: footerFromApi?.frgnrPoplSm // 행정참고자료 외국인 합계
|
||||
};
|
||||
|
||||
const response = await statisticsInputAPi.saveSewerageSupplyRate(requestData);
|
||||
|
||||
if (response.status === 'success') {
|
||||
fetchSewerageSupplyRate(getSewerageSupplyRateParams(searchValues ?? {}));
|
||||
fetchSewerageSupplyRate(getSewerageSupplyRateParams(searchValues ?? {}), true);
|
||||
alert('저장되었습니다.');
|
||||
} else {
|
||||
alert('데이터 저장 중 오류가 발생했습니다.');
|
||||
@@ -277,12 +389,12 @@ const SeweragePenetrationRateInp = () => {
|
||||
<>
|
||||
<div className="relative">
|
||||
<SearchForm onSubmit={handleSearch} onReset={handleReset} onValuesChange={setSearchValues} />
|
||||
{rowData.length > 0 &&
|
||||
{rowData.length > 0 && isEnterable && (doList.includes(lastSearchedValues?.bsnmCd || '') ? Boolean(lastSearchedValues?.gugun && lastSearchedValues.gugun !== 'ALL') : true) &&
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] mx-[0.6rem]">
|
||||
{isEnterable && <SubmitExceptionButton SubmitExceptionFunc={SubmitExceptionFunc} />}
|
||||
{isEnterable && <LastYearDataButton getLastYearDataFunc={() => getLastYearDataFunc(searchValues ?? {})} />}
|
||||
{isEnterable && <SubmitButton submitFunc={submitFunc} />}
|
||||
<SubmitExceptionButton SubmitExceptionFunc={SubmitExceptionFunc} />
|
||||
<LastYearDataButton getLastYearDataFunc={() => getLastYearDataFunc(searchValues ?? {})} />
|
||||
<SubmitButton submitFunc={submitFunc} />
|
||||
{
|
||||
// 최고 관리자일땐 저장 가능하게
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
@@ -298,7 +410,7 @@ const SeweragePenetrationRateInp = () => {
|
||||
<DataGrid
|
||||
key={isEnterable ? 'enterable' : 'readonly'}
|
||||
columnInfo={columnInfo}
|
||||
isExcelImport={(rowData.length > 0) && isEnterable}
|
||||
isExcelImport={(rowData.length > 0) && isEnterable && (doList.includes(lastSearchedValues?.bsnmCd || '') ? Boolean(lastSearchedValues?.gugun && lastSearchedValues.gugun !== 'ALL') : true)}
|
||||
rowStartNum={3}
|
||||
fixedColumns={1}
|
||||
rowData={rowData}
|
||||
@@ -313,9 +425,18 @@ const SeweragePenetrationRateInp = () => {
|
||||
return 'rg-cell-verify-error';
|
||||
}
|
||||
}}
|
||||
cellTooltipCallback={({ row, fieldName }) => {
|
||||
const verification = (row as GridRowWithVerification).verificationResult;
|
||||
if (!verification) return;
|
||||
const errors = verification[fieldName];
|
||||
if (Array.isArray(errors) && errors.length > 0) {
|
||||
return errors.map((e) => e.rsnExpln).filter(Boolean).join('\n');
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<ConfirmDialog isOpen={false} />
|
||||
<SubmitDailog open={showDailog} onOpenChange={setShowDailog} statusInfo={statusInfo} onConfirm={executeSubmit} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
Input,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableRow,
|
||||
} from "@common/components";
|
||||
import { useEffect } from "react";
|
||||
import { useForm, Controller } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { statisticsInputSubmitInfoSchema, type StatisticsInputSubmitInfoFormData } from "@/entities/statistics/model/statistics-input-submit-info-schema";
|
||||
import { type SewerageSupplyRateStatusInfo } from "@/entities/statistics/model/statistics-input-interface";
|
||||
|
||||
/** 숫자만 추출 후 하이픈 포맷 (010-1234-5678, 02-123-4567 등) */
|
||||
function formatPhoneWithHyphen(value: string): string {
|
||||
const digits = value.replace(/\D/g, "");
|
||||
if (digits.length <= 3) return digits;
|
||||
if (digits.startsWith("010")) {
|
||||
if (digits.length <= 7) return `010-${digits.slice(3)}`;
|
||||
return `010-${digits.slice(3, 7)}-${digits.slice(7, 11)}`;
|
||||
}
|
||||
if (digits.startsWith("02")) {
|
||||
if (digits.length <= 5) return `02-${digits.slice(2)}`;
|
||||
if (digits.length <= 9) return `02-${digits.slice(2, 5)}-${digits.slice(5, 9)}`;
|
||||
return `02-${digits.slice(2, 6)}-${digits.slice(6, 10)}`;
|
||||
}
|
||||
if (digits.length <= 6) return `${digits.slice(0, 3)}-${digits.slice(3)}`;
|
||||
return `${digits.slice(0, 3)}-${digits.slice(3, 6)}-${digits.slice(6, 10)}`;
|
||||
}
|
||||
|
||||
const PHONE_FIELDS: (keyof StatisticsInputSubmitInfoFormData)[] = ["locgCttpc", "locgCnfirmPh"];
|
||||
|
||||
interface SubmitDialogProps {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
statusInfo: SewerageSupplyRateStatusInfo | null;
|
||||
/** 다이얼로그에서 저장 클릭 시 호출. 제출 정보를 넘기면 부모에서 requestData에 포함해 제출 API 호출 */
|
||||
onConfirm?: (data: StatisticsInputSubmitInfoFormData) => void | Promise<void>;
|
||||
}
|
||||
|
||||
const defaultValues: StatisticsInputSubmitInfoFormData = {
|
||||
locgCharger: "",
|
||||
locgJob: "",
|
||||
locgDept: "",
|
||||
locgCttpc: "",
|
||||
locgCnfirmNm: "",
|
||||
locgCnfirmJob: "",
|
||||
locgCnfirmDept: "",
|
||||
locgCnfirmPh: "",
|
||||
};
|
||||
|
||||
function statusInfoToFormData(info: SewerageSupplyRateStatusInfo): StatisticsInputSubmitInfoFormData {
|
||||
return {
|
||||
locgCharger: info.locgCharger ?? "",
|
||||
locgJob: info.locgJob ?? "",
|
||||
locgDept: info.locgDept ?? "",
|
||||
locgCttpc: info.locgCttpc ?? "",
|
||||
locgCnfirmNm: info.locgCnfirmNm ?? "",
|
||||
locgCnfirmJob: info.locgCnfirmJob ?? "",
|
||||
locgCnfirmDept: info.locgCnfirmDept ?? "",
|
||||
locgCnfirmPh: info.locgCnfirmPh ?? "",
|
||||
};
|
||||
}
|
||||
|
||||
const SubmitDailog = ({ open, onOpenChange, statusInfo, onConfirm }: SubmitDialogProps) => {
|
||||
const { control, handleSubmit, reset, formState: { errors } } = useForm<StatisticsInputSubmitInfoFormData>({
|
||||
resolver: zodResolver(statisticsInputSubmitInfoSchema),
|
||||
defaultValues,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
reset(statusInfo ? statusInfoToFormData(statusInfo) : defaultValues);
|
||||
}
|
||||
}, [open, statusInfo, reset]);
|
||||
|
||||
async function onSubmit(data: StatisticsInputSubmitInfoFormData) {
|
||||
await onConfirm?.(data);
|
||||
onOpenChange(false);
|
||||
reset(defaultValues);
|
||||
}
|
||||
|
||||
function handleCancel() {
|
||||
onOpenChange(false);
|
||||
reset(defaultValues);
|
||||
}
|
||||
|
||||
const rows: { name: keyof StatisticsInputSubmitInfoFormData; label: string; placeholder: string }[] = [
|
||||
{ name: "locgCharger", label: "작성자 명", placeholder: "작성자 명 입력" },
|
||||
{ name: "locgJob", label: "작성자 직제", placeholder: "작성자 직제 입력" },
|
||||
{ name: "locgDept", label: "작성자 부서", placeholder: "작성자 부서 입력" },
|
||||
{ name: "locgCttpc", label: "작성자 연락처", placeholder: "작성자 연락처 입력" },
|
||||
{ name: "locgCnfirmNm", label: "승인자명", placeholder: "승인자명 입력" },
|
||||
{ name: "locgCnfirmJob", label: "승인자 직제", placeholder: "승인자 직제 입력" },
|
||||
{ name: "locgCnfirmDept", label: "승인자 부서", placeholder: "승인자 부서 입력" },
|
||||
{ name: "locgCnfirmPh", label: "승인자 연락처", placeholder: "승인자 연락처" },
|
||||
];
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent className="max-w-[800px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>제출 정보</DialogTitle>
|
||||
</DialogHeader>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<Table variant="secondary">
|
||||
<TableBody>
|
||||
{rows.map(({ name, label, placeholder }) => (
|
||||
<TableRow key={name}>
|
||||
<TableHead className="w-[150px] bg-muted font-medium" data-required>
|
||||
{label}
|
||||
</TableHead>
|
||||
<TableCell>
|
||||
<Controller
|
||||
name={name}
|
||||
control={control}
|
||||
render={({ field }) => {
|
||||
const isPhone = PHONE_FIELDS.includes(name);
|
||||
return (
|
||||
<div className="space-y-1">
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
placeholder={placeholder}
|
||||
onChange={(e) => {
|
||||
const v = e.target.value;
|
||||
field.onChange(isPhone ? formatPhoneWithHyphen(v) : v);
|
||||
}}
|
||||
/>
|
||||
{errors[name]?.message && (
|
||||
<p className="text-sm text-destructive ml-1">
|
||||
{errors[name]?.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<DialogFooter className="mt-6">
|
||||
<Button type="button" color="gray" onClick={handleCancel}>
|
||||
취소
|
||||
</Button>
|
||||
<Button type="submit" color="green">
|
||||
저장
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default SubmitDailog;
|
||||
@@ -212,6 +212,10 @@ export type CellStyleCallbackParams = {
|
||||
|
||||
export type CellStyleCallback = (params: CellStyleCallbackParams) => string | undefined;
|
||||
|
||||
/** 셀 hover 시 툴팁 문구 (반환 시 해당 문구 표시, 검증 오류 메시지 등) */
|
||||
export type CellTooltipCallbackParams = { row: Record<string, string | number>; fieldName: string };
|
||||
export type CellTooltipCallback = (params: CellTooltipCallbackParams) => string | undefined;
|
||||
|
||||
export type DataGridProps = {
|
||||
columnInfo: ColumnInfo;
|
||||
rowStartNum?: number; // 헤더 행 개수 (1부터 시작, 예: 2면 1행과 2행까지 헤더로 간주)
|
||||
@@ -226,6 +230,8 @@ export type DataGridProps = {
|
||||
>;
|
||||
/** 셀 단위로 styleName을 동적으로 결정 (예: 검증 오류 셀) */
|
||||
cellStyleCallback?: CellStyleCallback;
|
||||
/** 셀 hover 시 툴팁 문구 (예: verificationResult의 rsnExpln) */
|
||||
cellTooltipCallback?: CellTooltipCallback;
|
||||
/** 저장 등 시점에 그리드 현재 데이터를 가져올 수 있도록 할당 (편집 반영된 값) */
|
||||
getGridDataRef?: {
|
||||
current: (() => Record<string, string | number>[]) | null;
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
export const doList = [
|
||||
"4100000000",
|
||||
"4200000000",
|
||||
"4300000000",
|
||||
"4400000000",
|
||||
"4500000000",
|
||||
"4600000000",
|
||||
"4700000000",
|
||||
"4800000000",
|
||||
];
|
||||
|
||||
export const needBsnmFrgnrPoplSmSidoList = [
|
||||
"3600000000",
|
||||
"4100000000",
|
||||
"4200000000",
|
||||
"4300000000",
|
||||
"4400000000",
|
||||
"4500000000",
|
||||
"4600000000",
|
||||
"4700000000",
|
||||
"4800000000",
|
||||
"5000000000",
|
||||
];
|
||||
@@ -7,13 +7,13 @@ import { ValueType } from "realgrid";
|
||||
export const SeweragePenetrationRateInpColumn = {
|
||||
columns: [
|
||||
// 행정구역
|
||||
{ name: 'sido', fieldName: 'sido', header: { text: '시도' }, footer: { text: '합계' }, editable: false, styleName: 'rg-cell-readonly' },
|
||||
{ name: 'gugun', fieldName: 'gugun', header: { text: '시군구' }, editable: false, styleName: 'rg-cell-readonly' },
|
||||
{ name: 'adstDong', fieldName: 'adstDong', header: { text: '행정구역명' }, editable: false, styleName: 'rg-cell-readonly' },
|
||||
{ name: 'ctpvNm', fieldName: 'ctpvNm', header: { text: '시도' }, footer: { text: '합계' }, editable: false, styleName: 'rg-cell-readonly' },
|
||||
{ name: 'sggNm', fieldName: 'sggNm', header: { text: '시군구' }, editable: false, styleName: 'rg-cell-readonly' },
|
||||
{ name: 'admdstNm', fieldName: 'admdstNm', header: { text: '행정구역명' }, editable: false, styleName: 'rg-cell-readonly' },
|
||||
|
||||
// 수계 및 권역
|
||||
{ name: 'rvbsn', fieldName: 'rvbsn', header: { text: '수계' }, editable: false, styleName: 'rg-cell-readonly' },
|
||||
{ name: 'bstrm', fieldName: 'bstrm', header: { text: '지류' } },
|
||||
{ name: 'trbtrNm', fieldName: 'trbtrNm', header: { text: '지류' } },
|
||||
|
||||
// 수계영향권별분류
|
||||
{ name: 'mdbsn', fieldName: 'mdbsn', header: { text: '세부단위유역' }, editable: false, styleName: 'rg-cell-readonly' },
|
||||
@@ -21,7 +21,7 @@ export const SeweragePenetrationRateInpColumn = {
|
||||
{ name: 'mdmbsn', fieldName: 'mdmbsn', header: { text: '소권역' }, editable: false, styleName: 'rg-cell-readonly' },
|
||||
|
||||
// 특별대책지역
|
||||
{ name: 'speclCntrplnAr', fieldName: 'speclCntrplnAr', header: { text: '특별대책지역' } },
|
||||
{ name: 'spcCtpnRgnCn', fieldName: 'spcCtpnRgnCn', header: { text: '특별대책지역' } },
|
||||
|
||||
// 행정참고자료인구
|
||||
{ name: 'totalPopl', fieldName: 'totalPopl', header: { text: '총인구' }, footer: footerInt, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0', styleName: 'rg-cell-readonly' },
|
||||
@@ -29,113 +29,113 @@ export const SeweragePenetrationRateInpColumn = {
|
||||
{ name: 'frgnrPoplSm', fieldName: 'frgnrPoplSm', header: { text: '외국인' }, footer: footerInt, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0', styleName: 'rg-cell-readonly' },
|
||||
|
||||
// 행정참고자료면적
|
||||
{ name: 'area', fieldName: 'area', header: { text: '행정참고자료면적(㎢)' }, footer: footerDecimal3, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.000', styleName: 'rg-cell-readonly' },
|
||||
{ name: 'refArea', fieldName: 'refArea', header: { text: '행정참고자료면적(㎢)' }, footer: footerDecimal3, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.000', styleName: 'rg-cell-readonly' },
|
||||
|
||||
// 총인구
|
||||
{
|
||||
name: 'popltnSm',
|
||||
fieldName: 'popltnSm',
|
||||
name: 'wholPpltnCnt',
|
||||
fieldName: 'wholPpltnCnt',
|
||||
header: { text: '총인구(명)' },
|
||||
footer: footerInt,
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0',
|
||||
computed: { fields: ['pblswrgPrmTrt', 'pblswrgScdTrt', 'pblswrgTertTrt', 'wstrPrmTrt', 'wstrScdTrt', 'wstrTertTrt', 'notConectPopltn', 'townUnprocPopltn', 'townSwttPopltn', 'townWrrtnPopltn'], type: 'sum' as const },
|
||||
computed: { fields: ['ts1SwtrmtPpltnCnt', 'ts2SwtrmtPpltnCnt', 'ts3SwtrmtPpltnCnt', 'ts1WwtPrcsPpltnCnt', 'ts2WwtPrcsPpltnCnt', 'ts3WwtPrcsPpltnCnt', 'yetCntnPpltnCnt', 'unprcsPpltnCnt', 'drtwPrcsPpltnCnt', 'spctnkPpltnCnt'], type: 'sum' as const },
|
||||
styleName: 'rg-cell-total',
|
||||
},
|
||||
|
||||
// 총면적
|
||||
{
|
||||
name: 'arSm',
|
||||
fieldName: 'arSm',
|
||||
name: 'wholArea',
|
||||
fieldName: 'wholArea',
|
||||
header: { text: '총면적(㎢)' },
|
||||
footer: footerDecimal3,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0.000',
|
||||
computed: { fields: ['swgeProcZoneInnerAr', 'swgeProcZoneOuterAr'], type: 'sum' as const },
|
||||
computed: { fields: ['staaArea', 'staaExcpArea'], type: 'sum' as const },
|
||||
styleName: 'rg-cell-total',
|
||||
},
|
||||
|
||||
// 하수처리구역 내 > 합계
|
||||
{
|
||||
name: 'swgeProcZoneInnerSm',
|
||||
fieldName: 'swgeProcZoneInnerSm',
|
||||
name: 'wholSwtrmtPpltnCnt',
|
||||
fieldName: 'wholSwtrmtPpltnCnt',
|
||||
header: { text: '합계' },
|
||||
footer: footerInt,
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0',
|
||||
computed: { fields: ['pblswrgPrmTrt', 'pblswrgScdTrt', 'pblswrgTertTrt', 'wstrPrmTrt', 'wstrScdTrt', 'wstrTertTrt', 'notConectPopltn'], type: 'sum' as const },
|
||||
computed: { fields: ['ts1SwtrmtPpltnCnt', 'ts2SwtrmtPpltnCnt', 'ts3SwtrmtPpltnCnt', 'ts1WwtPrcsPpltnCnt', 'ts2WwtPrcsPpltnCnt', 'ts3WwtPrcsPpltnCnt', 'yetCntnPpltnCnt'], type: 'sum' as const },
|
||||
styleName: 'rg-cell-total',
|
||||
},
|
||||
|
||||
// 하수처리구역 내 > 공공하수처리인구
|
||||
{
|
||||
name: 'pblswrgPopltnSm',
|
||||
fieldName: 'pblswrgPopltnSm',
|
||||
name: 'wholPblSwtrmtPpltnCnt',
|
||||
fieldName: 'wholPblSwtrmtPpltnCnt',
|
||||
header: { text: '소계' },
|
||||
footer: footerInt,
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0',
|
||||
computed: { fields: ['pblswrgPrmTrt', 'pblswrgScdTrt', 'pblswrgTertTrt'], type: 'sum' as const },
|
||||
computed: { fields: ['ts1SwtrmtPpltnCnt', 'ts2SwtrmtPpltnCnt', 'ts3SwtrmtPpltnCnt'], type: 'sum' as const },
|
||||
styleName: 'rg-cell-total',
|
||||
},
|
||||
{ name: 'pblswrgPrmTrt', fieldName: 'pblswrgPrmTrt', header: { text: '물리적처리' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'pblswrgScdTrt', fieldName: 'pblswrgScdTrt', header: { text: '생물학적처리' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'pblswrgTertTrt', fieldName: 'pblswrgTertTrt', header: { text: '고도처리' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'ts1SwtrmtPpltnCnt', fieldName: 'ts1SwtrmtPpltnCnt', header: { text: '물리적처리' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'ts2SwtrmtPpltnCnt', fieldName: 'ts2SwtrmtPpltnCnt', header: { text: '생물학적처리' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'ts3SwtrmtPpltnCnt', fieldName: 'ts3SwtrmtPpltnCnt', header: { text: '고도처리' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 하수처리구역 내 > 폐수처리인구
|
||||
{
|
||||
name: 'wstrPopltnSm',
|
||||
fieldName: 'wstrPopltnSm',
|
||||
name: 'wholWwtPrcsPpltnCnt',
|
||||
fieldName: 'wholWwtPrcsPpltnCnt',
|
||||
header: { text: '소계' },
|
||||
footer: footerInt,
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0',
|
||||
computed: { fields: ['wstrPrmTrt', 'wstrScdTrt', 'wstrTertTrt'], type: 'sum' as const },
|
||||
computed: { fields: ['ts1WwtPrcsPpltnCnt', 'ts2WwtPrcsPpltnCnt', 'ts3WwtPrcsPpltnCnt'], type: 'sum' as const },
|
||||
styleName: 'rg-cell-total',
|
||||
},
|
||||
{ name: 'wstrPrmTrt', fieldName: 'wstrPrmTrt', header: { text: '물리적처리' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'wstrScdTrt', fieldName: 'wstrScdTrt', header: { text: '생물학적처리' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'wstrTertTrt', fieldName: 'wstrTertTrt', header: { text: '고도처리' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'ts1WwtPrcsPpltnCnt', fieldName: 'ts1WwtPrcsPpltnCnt', header: { text: '물리적처리' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'ts2WwtPrcsPpltnCnt', fieldName: 'ts2WwtPrcsPpltnCnt', header: { text: '생물학적처리' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'ts3WwtPrcsPpltnCnt', fieldName: 'ts3WwtPrcsPpltnCnt', header: { text: '고도처리' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 하수처리구역 내 > 미접속인구
|
||||
{ name: 'notConectPopltn', fieldName: 'notConectPopltn', header: { text: '미접속인구' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'yetCntnPpltnCnt', fieldName: 'yetCntnPpltnCnt', header: { text: '미접속인구' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 하수처리구역 내 > 면적
|
||||
{ name: 'swgeProcZoneInnerAr', fieldName: 'swgeProcZoneInnerAr', header: { text: '면적(㎢)' }, footer: footerDecimal3, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
{ name: 'staaArea', fieldName: 'staaArea', header: { text: '면적(㎢)' }, footer: footerDecimal3, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
|
||||
// 하수처리구역 외
|
||||
{
|
||||
name: 'swgeProcZoneOuterSm',
|
||||
fieldName: 'swgeProcZoneOuterSm',
|
||||
name: 'wholStaaExcpPpltnCnt',
|
||||
fieldName: 'wholStaaExcpPpltnCnt',
|
||||
header: { text: '합계' },
|
||||
footer: footerInt,
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0',
|
||||
computed: { fields: ['townUnprocPopltn', 'townSwttPopltn', 'townWrrtnPopltn'], type: 'sum' as const },
|
||||
computed: { fields: ['unprcsPpltnCnt', 'drtwPrcsPpltnCnt', 'spctnkPpltnCnt'], type: 'sum' as const },
|
||||
styleName: 'rg-cell-total',
|
||||
},
|
||||
{ name: 'townUnprocPopltn', fieldName: 'townUnprocPopltn', header: { text: '미처리인구' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'townSwttPopltn', fieldName: 'townSwttPopltn', header: { text: '오수처리인구' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'townWrrtnPopltn', fieldName: 'townWrrtnPopltn', header: { text: '정화조인구' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'swgeProcZoneOuterAr', fieldName: 'swgeProcZoneOuterAr', header: { text: '면적(㎢)' }, footer: footerDecimal3, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
{ name: 'unprcsPpltnCnt', fieldName: 'unprcsPpltnCnt', header: { text: '미처리인구' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'drtwPrcsPpltnCnt', fieldName: 'drtwPrcsPpltnCnt', header: { text: '오수처리인구' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'spctnkPpltnCnt', fieldName: 'spctnkPpltnCnt', header: { text: '정화조인구' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'staaExcpArea', fieldName: 'staaExcpArea', header: { text: '면적(㎢)' }, footer: footerDecimal3, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
|
||||
// 공공하수처리구역 인구보급률 (하수처리구역 내 인구 / 전체 인구 * 100)
|
||||
{
|
||||
name: 'pblswrgPopltnSuprt',
|
||||
fieldName: 'pblswrgPopltnSuprt',
|
||||
name: 'staaPsplyRt',
|
||||
fieldName: 'staaPsplyRt',
|
||||
header: { text: '공공하수처리구역인구보급률(%)' },
|
||||
footer: footerAvgDecimal,
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0.0',
|
||||
computed: {
|
||||
numeratorFields: ['pblswrgPrmTrt', 'pblswrgScdTrt', 'pblswrgTertTrt', 'wstrPrmTrt', 'wstrScdTrt', 'wstrTertTrt', 'notConectPopltn'],
|
||||
denominatorFields: ['pblswrgPrmTrt', 'pblswrgScdTrt', 'pblswrgTertTrt', 'wstrPrmTrt', 'wstrScdTrt', 'wstrTertTrt', 'notConectPopltn', 'townUnprocPopltn', 'townSwttPopltn', 'townWrrtnPopltn'],
|
||||
numeratorFields: ['ts1SwtrmtPpltnCnt', 'ts2SwtrmtPpltnCnt', 'ts3SwtrmtPpltnCnt', 'ts1WwtPrcsPpltnCnt', 'ts2WwtPrcsPpltnCnt', 'ts3WwtPrcsPpltnCnt', 'yetCntnPpltnCnt'],
|
||||
denominatorFields: ['ts1SwtrmtPpltnCnt', 'ts2SwtrmtPpltnCnt', 'ts3SwtrmtPpltnCnt', 'ts1WwtPrcsPpltnCnt', 'ts2WwtPrcsPpltnCnt', 'ts3WwtPrcsPpltnCnt', 'yetCntnPpltnCnt', 'unprcsPpltnCnt', 'drtwPrcsPpltnCnt', 'spctnkPpltnCnt'],
|
||||
type: 'pblswrgPopltnSuprtRate' as const
|
||||
},
|
||||
styleName: 'rg-cell-total',
|
||||
@@ -143,16 +143,16 @@ export const SeweragePenetrationRateInpColumn = {
|
||||
|
||||
// 고도처리 인구보급률 (고도처리 인구 / 전체 인구 * 100)
|
||||
{
|
||||
name: 'adtrtPopltnSuprt',
|
||||
fieldName: 'adtrtPopltnSuprt',
|
||||
name: 'altdPrcsPsplyRt',
|
||||
fieldName: 'altdPrcsPsplyRt',
|
||||
header: { text: '고도처리인구보급률(%)' },
|
||||
footer: footerAvgDecimal,
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0.0',
|
||||
computed: {
|
||||
numeratorFields: ['pblswrgTertTrt', 'wstrTertTrt'],
|
||||
denominatorFields: ['pblswrgPrmTrt', 'pblswrgScdTrt', 'pblswrgTertTrt', 'wstrPrmTrt', 'wstrScdTrt', 'wstrTertTrt', 'notConectPopltn', 'townUnprocPopltn', 'townSwttPopltn', 'townWrrtnPopltn'],
|
||||
numeratorFields: ['ts3SwtrmtPpltnCnt', 'ts3WwtPrcsPpltnCnt'],
|
||||
denominatorFields: ['ts1SwtrmtPpltnCnt', 'ts2SwtrmtPpltnCnt', 'ts3SwtrmtPpltnCnt', 'ts1WwtPrcsPpltnCnt', 'ts2WwtPrcsPpltnCnt', 'ts3WwtPrcsPpltnCnt', 'yetCntnPpltnCnt', 'unprcsPpltnCnt', 'drtwPrcsPpltnCnt', 'spctnkPpltnCnt'],
|
||||
type: 'adtrtPopltnSuprtRate' as const
|
||||
},
|
||||
styleName: 'rg-cell-total',
|
||||
@@ -160,27 +160,27 @@ export const SeweragePenetrationRateInpColumn = {
|
||||
|
||||
// 하수도 설치율
|
||||
{
|
||||
name: 'swrgInstlrt',
|
||||
fieldName: 'swrgInstlrt',
|
||||
name: 'sewerInstlRt',
|
||||
fieldName: 'sewerInstlRt',
|
||||
header: { text: '하수도설치율(%)' },
|
||||
footer: footerAvgDecimal,
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0.0',
|
||||
computed: {
|
||||
numeratorFields: ['pblswrgPrmTrt', 'pblswrgScdTrt', 'pblswrgTertTrt', 'wstrPrmTrt', 'wstrScdTrt', 'wstrTertTrt', 'notConectPopltn', 'swgeProcZoneOuterSm'],
|
||||
denominatorFields: ['pblswrgPrmTrt', 'pblswrgScdTrt', 'pblswrgTertTrt', 'wstrPrmTrt', 'wstrScdTrt', 'wstrTertTrt', 'notConectPopltn'],
|
||||
thirdFields: ['piplSupprt'],
|
||||
numeratorFields: ['ts1SwtrmtPpltnCnt', 'ts2SwtrmtPpltnCnt', 'ts3SwtrmtPpltnCnt', 'ts1WwtPrcsPpltnCnt', 'ts2WwtPrcsPpltnCnt', 'ts3WwtPrcsPpltnCnt', 'yetCntnPpltnCnt', 'wholStaaExcpPpltnCnt'],
|
||||
denominatorFields: ['ts1SwtrmtPpltnCnt', 'ts2SwtrmtPpltnCnt', 'ts3SwtrmtPpltnCnt', 'ts1WwtPrcsPpltnCnt', 'ts2WwtPrcsPpltnCnt', 'ts3WwtPrcsPpltnCnt', 'yetCntnPpltnCnt'],
|
||||
thirdFields: ['swagePplPsplyRt'],
|
||||
type: 'swrgInstlrtRate' as const
|
||||
},
|
||||
styleName: 'rg-cell-total',
|
||||
},
|
||||
|
||||
// 비고
|
||||
{ name: 'rmk', fieldName: 'rmk', header: { text: '비고' } },
|
||||
{ name: 'rmrk', fieldName: 'rmrk', header: { text: '비고' } },
|
||||
|
||||
{ name: 'piplSupprt', fieldName: 'piplSupprt', header: { text: '하수관로보급률(%)' }, visible: false },
|
||||
{ name: 'adstCd', fieldName: 'adstCd', header: { text: '행정코드' }, visible: false },
|
||||
{ name: 'swagePplPsplyRt', fieldName: 'swagePplPsplyRt', header: { text: '하수관로보급률(%)' }, visible: false },
|
||||
{ name: 'admdstCd', fieldName: 'admdstCd', header: { text: '행정코드' }, visible: false },
|
||||
],
|
||||
|
||||
columnLayout: [
|
||||
@@ -189,49 +189,49 @@ export const SeweragePenetrationRateInpColumn = {
|
||||
hideChildHeaders: false,
|
||||
header: { text: '행정구역' },
|
||||
items: [
|
||||
{ column: 'sido', footerUserSpans: [{ colspan: 3 }] },
|
||||
'gugun',
|
||||
'adstDong',
|
||||
{ column: 'ctpvNm', footerUserSpans: [{ colspan: 3 }] },
|
||||
'sggNm',
|
||||
'admdstNm',
|
||||
],
|
||||
},
|
||||
'rvbsn',
|
||||
'bstrm',
|
||||
'trbtrNm',
|
||||
{
|
||||
name: 'groupB',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '수계영향권별분류' },
|
||||
items: ['mdbsn', 'lgbsn', 'mdmbsn'],
|
||||
},
|
||||
'speclCntrplnAr',
|
||||
'spcCtpnRgnCn',
|
||||
{
|
||||
name: 'groupC',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '행정참고자료인구' },
|
||||
items: ['totalPopl', 'poplSm', 'frgnrPoplSm'],
|
||||
},
|
||||
'area',
|
||||
'popltnSm',
|
||||
'arSm',
|
||||
'refArea',
|
||||
'wholPpltnCnt',
|
||||
'wholArea',
|
||||
{
|
||||
name: 'groupD',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '하수처리구역내' },
|
||||
items: [
|
||||
'swgeProcZoneInnerSm',
|
||||
'wholSwtrmtPpltnCnt',
|
||||
{
|
||||
name: 'pblswrgGroup',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '공공하수처리인구(명)' },
|
||||
items: ['pblswrgPopltnSm', 'pblswrgPrmTrt', 'pblswrgScdTrt', 'pblswrgTertTrt'],
|
||||
items: ['wholPblSwtrmtPpltnCnt', 'ts1SwtrmtPpltnCnt', 'ts2SwtrmtPpltnCnt', 'ts3SwtrmtPpltnCnt'],
|
||||
},
|
||||
{
|
||||
name: 'wstrGroup',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '폐수처리인구(명)' },
|
||||
items: ['wstrPopltnSm', 'wstrPrmTrt', 'wstrScdTrt', 'wstrTertTrt'],
|
||||
items: ['wholWwtPrcsPpltnCnt', 'ts1WwtPrcsPpltnCnt', 'ts2WwtPrcsPpltnCnt', 'ts3WwtPrcsPpltnCnt'],
|
||||
},
|
||||
'notConectPopltn',
|
||||
'swgeProcZoneInnerAr'
|
||||
'yetCntnPpltnCnt',
|
||||
'staaArea'
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -239,18 +239,18 @@ export const SeweragePenetrationRateInpColumn = {
|
||||
hideChildHeaders: false,
|
||||
header: { text: '하수처리구역외' },
|
||||
items: [
|
||||
'swgeProcZoneOuterSm',
|
||||
'townUnprocPopltn',
|
||||
'townSwttPopltn',
|
||||
'townWrrtnPopltn',
|
||||
'swgeProcZoneOuterAr'
|
||||
'wholStaaExcpPpltnCnt',
|
||||
'unprcsPpltnCnt',
|
||||
'drtwPrcsPpltnCnt',
|
||||
'spctnkPpltnCnt',
|
||||
'staaExcpArea'
|
||||
],
|
||||
},
|
||||
'pblswrgPopltnSuprt',
|
||||
'adtrtPopltnSuprt',
|
||||
'swrgInstlrt',
|
||||
'rmk',
|
||||
'piplSupprt',
|
||||
'adstCd',
|
||||
'staaPsplyRt',
|
||||
'altdPrcsPsplyRt',
|
||||
'sewerInstlRt',
|
||||
'rmrk',
|
||||
'swagePplPsplyRt',
|
||||
'admdstCd',
|
||||
]
|
||||
};
|
||||
@@ -38,6 +38,15 @@ export class StatisticsInputAPiService implements StatisticsInputService {
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async submitSewerageSupplyRate(params: SewerageSupplyRateSaveRequest): Promise<SewerageSupplyRateSaveApiResponse> {
|
||||
const response = await axios.post<SewerageSupplyRateSaveApiResponse> (
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/sewerage-supply-rate/submit`,
|
||||
params
|
||||
);
|
||||
|
||||
return response.data;
|
||||
}
|
||||
}
|
||||
|
||||
export const statisticsInputAPi = new StatisticsInputAPiService();
|
||||
@@ -2,120 +2,83 @@ import type { ApiResponse } from "./statistics-interface";
|
||||
|
||||
// 하수도 보급률 데이터 항목
|
||||
export interface SewerageSupplyRateStatusInfo {
|
||||
locgStatus: string;
|
||||
locgDt: string;
|
||||
locgCharger: string;
|
||||
locgCttpc: string;
|
||||
prvnStatus: string;
|
||||
dcsnStatus: string;
|
||||
locgStatus: string | null;
|
||||
locgDt: string | null;
|
||||
locgCharger: string | null;
|
||||
locgCttpc: string | null;
|
||||
locgJob: string | null;
|
||||
prvnStatus: string | null;
|
||||
dcsnStatus: string | null;
|
||||
wrterOpinionSm: string | null;
|
||||
chckerOpinionSm: string | null;
|
||||
returnOpinionSm: string | null;
|
||||
locgCnfirmDept: string | null;
|
||||
locgCnfirmJob: string | null;
|
||||
locgCnfirmNm: string | null;
|
||||
locgCnfirmPh: string | null;
|
||||
locgDept: string | null;
|
||||
}
|
||||
|
||||
export interface SewerageSupplyRateCommonInfo {
|
||||
bsnmArea: number;
|
||||
bsnmCd: string;
|
||||
bsnmFrgnrPoplSm: number;
|
||||
bsnmPoplSm: number;
|
||||
bsnmTotalPopl: number;
|
||||
sewerBzmnArea: number;
|
||||
sewerBzmnCd: string;
|
||||
sewerBzmnFrgnrPoplSm: number;
|
||||
sewerBzmnPoplSm: number;
|
||||
sewerBzmnTotalPopl: number;
|
||||
piplFcltyExtn: number;
|
||||
piplPlanExtn: number;
|
||||
piplSupprt: number;
|
||||
sido: string;
|
||||
yr: string;
|
||||
swagePplPsplyRt: number;
|
||||
ctpvNm: string;
|
||||
statsYr: string;
|
||||
}
|
||||
|
||||
/** 검증 결과 한 건 (필드별 메시지) */
|
||||
export interface VerificationResultItem {
|
||||
type: string;
|
||||
rsn: string;
|
||||
vrfcCd: string;
|
||||
rsnExpln: string;
|
||||
}
|
||||
|
||||
/** 필드명 → 검증 결과 배열. 예: { popltnSm: [{ type, rsn }], wstrPrmTrt: [...] } */
|
||||
export type SewerageSupplyRateVerificationResult = Record<string, VerificationResultItem[]>;
|
||||
|
||||
/** 하수도 보급률 목록 API 응답 한 행 (실제 응답 필드만) */
|
||||
export interface SewerageSupplyRateItem {
|
||||
sido: string;
|
||||
gugun: string;
|
||||
adstDong: string;
|
||||
rgnNm: string;
|
||||
adstCd: string;
|
||||
yr: string;
|
||||
bsnmCd: string;
|
||||
rvbsn: string;
|
||||
lgbsn: string;
|
||||
admdstCd: string;
|
||||
sggNm: string;
|
||||
admdstNm: string;
|
||||
rvbsn: string | null;
|
||||
trbtrNm: string;
|
||||
mdbsn: string;
|
||||
lgbsn: string;
|
||||
mdmbsn: string;
|
||||
spcCtpnRgnCn: string | null;
|
||||
totalPopl: number;
|
||||
poplSm: number;
|
||||
frgnrPoplSm: number;
|
||||
area: number;
|
||||
bsnmTotalPopl: number;
|
||||
bsnmPoplSm: number;
|
||||
bsnmFrgnrPoplSm: number;
|
||||
bsnmArea: number;
|
||||
piplPlanExtn: number;
|
||||
piplFcltyExtn: number;
|
||||
piplSupprt: number;
|
||||
wrssm: string | null;
|
||||
bstrm: string;
|
||||
speclCntrplnAr: string | null;
|
||||
popltnSm: number;
|
||||
arSm: number;
|
||||
swgeProcZoneInnerSm: number;
|
||||
pblswrgPopltnSm: number;
|
||||
pblswrgPrmTrt: number;
|
||||
pblswrgScdTrt: number;
|
||||
pblswrgTertTrt: number;
|
||||
wstrPopltnSm: number;
|
||||
wstrPrmTrt: number;
|
||||
wstrScdTrt: number;
|
||||
wstrTertTrt: number;
|
||||
swgeProcZoneInnerAr: number;
|
||||
swgeProcZoneOuterSm: number;
|
||||
townUnprocPopltn: number;
|
||||
townSwttPopltn: number;
|
||||
townWrrtnPopltn: number;
|
||||
uptownUnprPopltn: number;
|
||||
uptownSwttPopltn: number;
|
||||
uptownWrrtnPopltn: number;
|
||||
swgeProcZoneOuterAr: number;
|
||||
pblswrgPopltnSuprt: number;
|
||||
adtrtPopltnSuprt: number;
|
||||
swrgInstlrt: number;
|
||||
wrterOpinion: string | null;
|
||||
chckerOpinion: string | null;
|
||||
notConectPopltn: number;
|
||||
rmk: string;
|
||||
chkWrssm: string;
|
||||
chkBstrm: string;
|
||||
chkSpeclCntrplnAr: string;
|
||||
chkPopltnSm: string;
|
||||
chkArSm: string;
|
||||
chkSwgeProcZoneInnerSm: string;
|
||||
chkPblswrgPopltnSm: string;
|
||||
chkPblswrgPrmTrt: string;
|
||||
chkPblswrgScdTrt: string;
|
||||
chkPblswrgTertTrt: string;
|
||||
chkWstrPopltnSm: string;
|
||||
chkWstrPrmTrt: string;
|
||||
chkWstrScdTrt: string;
|
||||
chkWstrTertTrt: string;
|
||||
chkSwgeProcZoneInnerAr: string;
|
||||
chkSwgeProcZoneOuterSm: string;
|
||||
chkTownUnprocPopltn: string;
|
||||
chkTownSwttPopltn: string;
|
||||
chkTownWrrtnPopltn: string;
|
||||
chkUptownUnprPopltn: string;
|
||||
chkUptownSwttPopltn: string;
|
||||
chkUptownWrrtnPopltn: string;
|
||||
chkSwgeProcZoneOuterAr: string;
|
||||
chkPblswrgPopltnSuprt: string;
|
||||
chkAdtrtPopltnSuprt: string;
|
||||
chkSwrgInstlrt: string;
|
||||
chkNotConectPopltn: string;
|
||||
verificationResult?: SewerageSupplyRateVerificationResult;
|
||||
refArea: number;
|
||||
wholPpltnCnt: number;
|
||||
wholArea: number;
|
||||
wholSwtrmtPpltnCnt: number;
|
||||
wholPblSwtrmtPpltnCnt: number;
|
||||
ts1SwtrmtPpltnCnt: number;
|
||||
ts2SwtrmtPpltnCnt: number;
|
||||
ts3SwtrmtPpltnCnt: number;
|
||||
wholWwtPrcsPpltnCnt: number;
|
||||
ts1WwtPrcsPpltnCnt: number;
|
||||
ts2WwtPrcsPpltnCnt: number;
|
||||
ts3WwtPrcsPpltnCnt: number;
|
||||
yetCntnPpltnCnt: number;
|
||||
staaArea: number;
|
||||
wholStaaExcpPpltnCnt: number;
|
||||
unprcsPpltnCnt: number;
|
||||
drtwPrcsPpltnCnt: number;
|
||||
spctnkPpltnCnt: number;
|
||||
staaExcpArea: number;
|
||||
staaPsplyRt: number;
|
||||
altdPrcsPsplyRt: number;
|
||||
sewerInstlRt: number;
|
||||
rmrk: string | null;
|
||||
verificationResult?: SewerageSupplyRateVerificationResult | null;
|
||||
}
|
||||
|
||||
export interface SewerageSupplyRateResponseData {
|
||||
@@ -129,55 +92,63 @@ export type SewerageSupplyRateApiResponse = ApiResponse<SewerageSupplyRateRespon
|
||||
}
|
||||
|
||||
export interface SewerageSupplyRateRequestParams {
|
||||
sido?: string;
|
||||
gugun?: string;
|
||||
bsnmCd?: string;
|
||||
yr?: string;
|
||||
ctpvNm?: string;
|
||||
sggNm?: string;
|
||||
sewerBzmnCd?: string;
|
||||
statsYr?: string;
|
||||
mode?: string;
|
||||
}
|
||||
|
||||
/** 하수도 보급률 저장 API 요청 body (한 행) */
|
||||
export interface SewerageSupplyRateSaveItem {
|
||||
gugun: string | null;
|
||||
adstCd: string;
|
||||
adstDong: string;
|
||||
bstrm: string;
|
||||
speclCntrplnAr: string | null;
|
||||
pblswrgPrmTrt: number;
|
||||
pblswrgScdTrt: number;
|
||||
pblswrgTertTrt: number;
|
||||
wstrPrmTrt: number;
|
||||
wstrScdTrt: number;
|
||||
wstrTertTrt: number;
|
||||
notConectPopltn: number;
|
||||
swgeProcZoneInnerAr: number;
|
||||
townUnprocPopltn: number;
|
||||
townSwttPopltn: number;
|
||||
townWrrtnPopltn: number;
|
||||
swgeProcZoneOuterAr: number;
|
||||
rmk: string;
|
||||
popltnSm: number;
|
||||
arSm: number;
|
||||
swgeProcZoneInnerSm: number;
|
||||
pblswrgPopltnSm: number;
|
||||
wstrPopltnSm: number;
|
||||
swgeProcZoneOuterSm: number;
|
||||
pblswrgPopltnSuprt: number;
|
||||
adtrtPopltnSuprt: number;
|
||||
swrgInstlrt: number;
|
||||
sggNm: string | null;
|
||||
admdstCd: string;
|
||||
admdstNm: string;
|
||||
trbtrNm: string;
|
||||
spcCtpnRgnCn: string | null;
|
||||
ts1SwtrmtPpltnCnt: number;
|
||||
ts2SwtrmtPpltnCnt: number;
|
||||
ts3SwtrmtPpltnCnt: number;
|
||||
ts1WwtPrcsPpltnCnt: number;
|
||||
ts2WwtPrcsPpltnCnt: number;
|
||||
ts3WwtPrcsPpltnCnt: number;
|
||||
yetCntnPpltnCnt: number;
|
||||
staaArea: number;
|
||||
unprcsPpltnCnt: number;
|
||||
drtwPrcsPpltnCnt: number;
|
||||
spctnkPpltnCnt: number;
|
||||
staaExcpArea: number;
|
||||
rmrk: string;
|
||||
wholPpltnCnt: number;
|
||||
wholArea: number;
|
||||
wholSwtrmtPpltnCnt: number;
|
||||
wholPblSwtrmtPpltnCnt: number;
|
||||
wholWwtPrcsPpltnCnt: number;
|
||||
wholStaaExcpPpltnCnt: number;
|
||||
staaPsplyRt: number;
|
||||
altdPrcsPsplyRt: number;
|
||||
sewerInstlRt: number;
|
||||
}
|
||||
|
||||
export interface SewerageSupplyRateSaveRequest {
|
||||
yr: string;
|
||||
sido: string;
|
||||
bsnmCd: string;
|
||||
statsYr: string;
|
||||
ctpvNm: string;
|
||||
sewerBzmnCd: string;
|
||||
userId: string;
|
||||
saveList: SewerageSupplyRateSaveItem[];
|
||||
sewerBzmnFrgnrPoplSm?: number;
|
||||
saveList?: SewerageSupplyRateSaveItem[];
|
||||
submitList?: SewerageSupplyRateSaveItem[];
|
||||
locgCharger?: string;
|
||||
locgJob?: string;
|
||||
locgDept?: string;
|
||||
locgCttpc?: string;
|
||||
locgCnfirmNm?: string;
|
||||
locgCnfirmJob?: string;
|
||||
locgCnfirmDept?: string;
|
||||
locgCnfirmPh?: string;
|
||||
}
|
||||
|
||||
export interface SewerageSupplyRateSaveData {
|
||||
hasMismatch?: boolean;
|
||||
mismatchIdList?: string[];
|
||||
httpStatus?: number;
|
||||
code?: string;
|
||||
}
|
||||
@@ -195,4 +166,5 @@ export interface StatisticsInputService {
|
||||
getSewerageSupplyRateList(params: SewerageSupplyRateRequestParams): Promise<SewerageSupplyRateApiResponse>;
|
||||
checkInputPeriod(params: string): Promise<CheckInputPeriodResponse>;
|
||||
saveSewerageSupplyRate(params: SewerageSupplyRateSaveRequest): Promise<SewerageSupplyRateSaveApiResponse>;
|
||||
submitSewerageSupplyRate(params: SewerageSupplyRateSaveRequest): Promise<SewerageSupplyRateSaveApiResponse>;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const statisticsInputSubmitInfoSchema = z.object({
|
||||
// 작성자 명, 작성자 직제, 작성자 부서, 작성자 연락처, 승인자명, 승인자 직제, 승인자 부서, 승인자 연락처 (전부 필수)
|
||||
locgCharger: z.string().min(1, "작성자 명을 입력하세요"),
|
||||
locgJob: z.string().min(1, "작성자 직제를 입력하세요"),
|
||||
locgDept: z.string().min(1, "작성자 부서를 입력하세요"),
|
||||
locgCttpc: z.string().min(1, "작성자 연락처를 입력하세요"),
|
||||
locgCnfirmNm: z.string().min(1, "승인자명을 입력하세요"),
|
||||
locgCnfirmJob: z.string().min(1, "승인자 직제를 입력하세요"),
|
||||
locgCnfirmDept: z.string().min(1, "승인자 부서를 입력하세요"),
|
||||
locgCnfirmPh: z.string().min(1, "승인자 연락처를 입력하세요"),
|
||||
});
|
||||
|
||||
export type StatisticsInputSubmitInfoFormData = z.infer<
|
||||
typeof statisticsInputSubmitInfoSchema
|
||||
>;
|
||||
Reference in New Issue
Block a user