From c957c2ff8d9664d217e346f5f0c9d3fc4b3a072b Mon Sep 17 00:00:00 2001 From: rsone001 Date: Thu, 26 Feb 2026 15:13:56 +0900 Subject: [PATCH] =?UTF-8?q?st:=20feat:=20=EA=B7=B8=EB=A6=AC=EB=93=9C=20?= =?UTF-8?q?=ED=95=B4=EB=8D=94=20=EC=83=89=EC=83=81=20=ED=86=B5=EC=9D=BC,?= =?UTF-8?q?=20=ED=86=B5=EA=B3=84=EC=9E=85=EB=A0=A5=ED=98=84=ED=99=A9=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?&=20=EA=B2=80=EC=83=89=ED=8F=BC=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95(=ED=86=B5?= =?UTF-8?q?=EA=B3=84=EC=9E=85=EB=A0=A5=ED=98=84=ED=99=A9=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=EC=8B=9C=20=EB=8F=84=EB=A5=BC=20=EC=A0=9C=EC=99=B8?= =?UTF-8?q?=ED=95=9C=20=EC=8B=9C=EB=8A=94=20=ED=96=89=EC=A0=95=EA=B5=AC?= =?UTF-8?q?=EC=97=AD(sggNm)=EC=9D=84=20=EC=A1=B0=ED=9A=8C=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8F=84=EB=A1=9D)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/st/src/components/css/DataGrid.css | 35 ++++- apps/st/src/components/module/DataGrid.tsx | 3 + apps/st/src/components/module/SearchForm.tsx | 22 ++- apps/st/src/components/module/TabDataGrid.tsx | 3 +- .../input/SeweragePenetrationRateInp.tsx | 134 +++++++++--------- .../statistics/input/StatsInputStatusInp.tsx | 83 ++++++++--- .../statistics/input/SubmitDailog.tsx | 2 +- apps/st/src/components/type/DataGrid.type.ts | 5 +- .../st/src/components/type/SearchForm.type.ts | 2 + .../column/input/StatsInputStatusInpColumn.ts | 52 +++---- ...atistics-input-sew-supply-rate-service.ts} | 8 +- .../api/statistics-input-status-service.ts | 23 +++ .../api/statistics-management-service.ts | 13 -- .../statistics-input-status-interface.ts | 34 +++++ ...ics-sewage-supply-rate-input-interface.ts} | 3 +- 15 files changed, 289 insertions(+), 133 deletions(-) rename apps/st/src/entities/statistics/api/{statistics-input-service.ts => statistics-input-sew-supply-rate-service.ts} (84%) create mode 100644 apps/st/src/entities/statistics/api/statistics-input-status-service.ts create mode 100644 apps/st/src/entities/statistics/model/statistics-input-status-interface.ts rename apps/st/src/entities/statistics/model/{statistics-input-interface.ts => statistics-sewage-supply-rate-input-interface.ts} (98%) diff --git a/apps/st/src/components/css/DataGrid.css b/apps/st/src/components/css/DataGrid.css index 888d9fec1..cd21091f9 100644 --- a/apps/st/src/components/css/DataGrid.css +++ b/apps/st/src/components/css/DataGrid.css @@ -4,9 +4,24 @@ .rg-grid .rg-header .rg-table .rg-header-group-cell { @apply !bg-[#466995] !text-[#fff]; } - .rg-grid .rg-header .rg-table .rg-header-cell { + .rg-grid .rg-header .rg-table { @apply !bg-[#5987bf] !text-[#fff]; } + + /* 상태바·체크바 헤더 */ + .rg-grid .rg-head .rg-table tr:first-child td:first-child, + .rg-grid .rg-head .rg-table tr:first-child td:nth-child(2), + .rg-grid .rg-header .rg-table tr:first-child td:first-child, + .rg-grid .rg-header .rg-table tr:first-child td:nth-child(2) { + @apply !bg-[#5987bf] !text-[#fff]; + } + + .rg-grid .rg-header .rg-table tr td, + .rg-grid .rg-head .rg-table tr td { + border: none; + border-bottom: 1px solid #e5e7eb; + } + .rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell { @apply !bg-white; } @@ -40,6 +55,12 @@ .rg-grid .rg-header .rg-table .rg-header-cell { @apply !bg-[#62686d] !text-[#fff]; } + .rg-grid .rg-head .rg-table tr:first-child td:first-child, + .rg-grid .rg-head .rg-table tr:first-child td:nth-child(2), + .rg-grid .rg-header .rg-table tr:first-child td:first-child, + .rg-grid .rg-header .rg-table tr:first-child td:nth-child(2) { + @apply !bg-[#62686d] !text-[#fff]; + } .rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell { @apply !bg-[#545556] !text-[#fff]; } @@ -52,6 +73,12 @@ .rg-grid .rg-header .rg-table .rg-header-cell { @apply !bg-[#8d8d94] !text-[#fff]; } + .rg-grid .rg-head .rg-table tr:first-child td:first-child, + .rg-grid .rg-head .rg-table tr:first-child td:nth-child(2), + .rg-grid .rg-header .rg-table tr:first-child td:first-child, + .rg-grid .rg-header .rg-table tr:first-child td:nth-child(2) { + @apply !bg-[#8d8d94] !text-[#fff]; + } } [data-theme="green"] { @@ -61,5 +88,11 @@ .rg-grid .rg-header .rg-table .rg-header-cell { @apply !bg-[#6bafae] !text-[#fff]; } + .rg-grid .rg-head .rg-table tr:first-child td:first-child, + .rg-grid .rg-head .rg-table tr:first-child td:nth-child(2), + .rg-grid .rg-header .rg-table tr:first-child td:first-child, + .rg-grid .rg-header .rg-table tr:first-child td:nth-child(2) { + @apply !bg-[#6bafae] !text-[#fff]; + } } } diff --git a/apps/st/src/components/module/DataGrid.tsx b/apps/st/src/components/module/DataGrid.tsx index 8b614f4b7..539c55cdd 100644 --- a/apps/st/src/components/module/DataGrid.tsx +++ b/apps/st/src/components/module/DataGrid.tsx @@ -449,6 +449,7 @@ const DataGrid = ({ target: "local", fileName: `${menuName}.xlsx`, footer: "hidden", + allColumns: true, // 숨김(visible: false) 컬럼도 엑셀에 포함 done: () => { // 헤더 원복 columns.forEach((col) => { @@ -852,6 +853,7 @@ const DataGrid = ({ editable: col.editable, valueType: col.valueType, dataFormat: col.dataFormat, + ...(col.width != null && { width: col.width }), ...(col.styleName != null && { styleName: col.styleName, }), @@ -1146,6 +1148,7 @@ const DataGrid = ({ {...(column.valueType === ValueType.NUMBER && { numberFormat: column.dataFormat ? column.dataFormat : '#,##0.000' })} header={column.header} editable={column.editable} + {...(column.width != null && { width: column.width })} {...(baseStyleName != null && { styleName: baseStyleName })} {...(column.visible === false && { visible: false })} {...(cellTooltipCallback && { renderer: { showTooltip: true } })} diff --git a/apps/st/src/components/module/SearchForm.tsx b/apps/st/src/components/module/SearchForm.tsx index 91d823ed6..1b2899fd2 100644 --- a/apps/st/src/components/module/SearchForm.tsx +++ b/apps/st/src/components/module/SearchForm.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState, useEffect } from "react"; +import { useState, useEffect, useRef } from "react"; import useSWR from 'swr'; import { @@ -19,6 +19,7 @@ import { useAlertStore } from "@/shared/lib"; import { type SearchFormProps, type SearchFormValues, defaultSearchFormProps } from "../type/SearchForm.type"; import { statisticsAPi } from "@/entities/statistics/api/statistics-service"; import type { ApiResponse, SearchCondition, Sgg } from "@/entities/statistics/model/statistics-interface"; +import { doList } from "../util/column/input/DoList"; const getSidoListFetcher = async (): Promise> => { return statisticsAPi.getSidoList(); @@ -66,8 +67,13 @@ const SearchForm = (props: SearchFormProps = {}) => { bsnmCd: props.defaultValues?.bsnmCd || '', }); + // isStatusMenu면 bsnmCd가 doList에 있을 때만 시군구 조회. 선택 후 옵션 유지를 위해 마지막 목록 ref 사용 + const sggKey: [string, string] | null = + values.sido && values.sido !== "ALL" && (!mergedProps.isStatusMenu || doList.includes(values.bsnmCd ?? "")) + ? ["sgg-list", values.sido] + : null; const { data: sggList } = useSWR>( - values.sido && values.sido !== "ALL" ? ["sgg-list", values.sido] : null, + sggKey, getSggListFetcher, { revalidateOnFocus: false, @@ -87,7 +93,9 @@ const SearchForm = (props: SearchFormProps = {}) => { }, } ); - + const lastSggListRef = useRef([]); + if (sggList?.data) lastSggListRef.current = sggList.data; + const sggOptions = sggList?.data ?? (values.sido && values.sido !== "ALL" ? lastSggListRef.current : []); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); @@ -95,6 +103,7 @@ const SearchForm = (props: SearchFormProps = {}) => { }; const handleReset = () => { + lastSggListRef.current = []; const resetValues: SearchFormValues = { sido: '', gugun: '', @@ -109,7 +118,7 @@ const SearchForm = (props: SearchFormProps = {}) => { const handleSidoChange = (value: string) => { const selectedBsnm = sidoList?.data.sidoList.find((v) => v.sido === value)?.bsnmCd || ''; - + lastSggListRef.current = []; // 시도 변경 시 이전 시군구 목록 제거(조건 안 맞는 시도로 바꿀 때 옵션 안 남도록) setValues((prev) => ({ ...prev, sido: value, @@ -119,9 +128,10 @@ const SearchForm = (props: SearchFormProps = {}) => { }; const handleSggChange = (value: string) => { + const listForBsnm = sggList?.data ?? lastSggListRef.current; const selectedBsnm = value === 'ALL' ? (sidoList?.data.sidoList.find((v) => v.sido === values.sido)?.bsnmCd || '') - : (sggList?.data?.find((v) => v.gugun === value)?.bsnmCd || ''); + : (listForBsnm.find((v) => v.gugun === value)?.bsnmCd || ''); setValues((prev) => ({ ...prev, @@ -169,7 +179,7 @@ const SearchForm = (props: SearchFormProps = {}) => { 전체 - {sggList?.data?.map((sgg) => ( + {sggOptions?.map((sgg) => ( {sgg.gugun} diff --git a/apps/st/src/components/module/TabDataGrid.tsx b/apps/st/src/components/module/TabDataGrid.tsx index b188ce3fe..aa36287ee 100644 --- a/apps/st/src/components/module/TabDataGrid.tsx +++ b/apps/st/src/components/module/TabDataGrid.tsx @@ -419,6 +419,7 @@ const TabDataGrid = ({ columnInfo, isExcelImport = true, isExcelExport = true, r target: 'local', fileName: `${menuName}_${tabLabel}.xlsx`, footer: 'hidden', + allColumns: true, // 숨김(visible: false) 컬럼도 엑셀에 포함 done: () => { // 헤더 원복 columns.forEach((col) => { @@ -772,7 +773,7 @@ const TabDataGrid = ({ columnInfo, isExcelImport = true, isExcelExport = true, r return (
- + {columnInfo.map((info) => { const tabKey = info.tabKey; diff --git a/apps/st/src/components/statistics/input/SeweragePenetrationRateInp.tsx b/apps/st/src/components/statistics/input/SeweragePenetrationRateInp.tsx index cf7e52e27..d4eaa39d6 100644 --- a/apps/st/src/components/statistics/input/SeweragePenetrationRateInp.tsx +++ b/apps/st/src/components/statistics/input/SeweragePenetrationRateInp.tsx @@ -13,7 +13,7 @@ import SubmitDailog from "./SubmitDailog"; import { useAlertStore } from "@/shared/lib"; import { useAdminStore } from "@/store/admin-store"; -import { statisticsInputAPi } from "@/entities/statistics/api/statistics-input-service"; +import { StatisticsInputSewSupplyRateApi } from "@/entities/statistics/api/statistics-input-sew-supply-rate-service"; import type { SearchFormValues } from "@/components/type/SearchForm.type"; import type { SewerageSupplyRateItem, @@ -22,7 +22,7 @@ import type { SewerageSupplyRateVerificationResult, SewerageSupplyRateSaveRequest, SewerageSupplyRateStatusInfo, -} from "@/entities/statistics/model/statistics-input-interface"; +} from "@/entities/statistics/model/statistics-sewage-supply-rate-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"; @@ -101,7 +101,7 @@ const SeweragePenetrationRateInp = () => { const fetchSewerageSupplyRate = async (params: SewerageSupplyRateRequestParams, isEnterable: boolean) => { try { setIsLoading(true); - const response = await statisticsInputAPi.getSewerageSupplyRateList(params); + const response = await StatisticsInputSewSupplyRateApi.getSewerageSupplyRateList(params); if (response.status === 'success' && response.data) { const commonInfo = response.data.commonInfo; const statusInfo = response.data.statusInfo; @@ -126,7 +126,7 @@ const SeweragePenetrationRateInp = () => { totalPopl: commonInfo.sewerBzmnTotalPopl, poplSm: commonInfo.sewerBzmnPoplSm, frgnrPoplSm: commonInfo.sewerBzmnFrgnrPoplSm, - refArea: commonInfo.sewerBzmnArea, + refArea: commonInfo.sewerBzmnArea, } : null ); @@ -161,7 +161,7 @@ const SeweragePenetrationRateInp = () => { } try { - const response = await statisticsInputAPi.checkInputPeriod(values.year || ''); + const response = await StatisticsInputSewSupplyRateApi.checkInputPeriod(values.year || ''); if (response.status === 'success') { const checkEnterable = response.data; @@ -199,7 +199,8 @@ const SeweragePenetrationRateInp = () => { const submitFunc = async () => { const isError = rowData.filter((d) => d.verificationResult); if (isError.length > 0) { - alert('검증 오류 데이터가 있습니다.'); + alert(`데이터에 오류가 있습니다. + 수정 후 제출해주세요.`); return; } if (await confirm('제출 하시겠습니까?')) { @@ -276,7 +277,8 @@ const SeweragePenetrationRateInp = () => { locgCnfirmDept: submitInfo.locgCnfirmDept, locgCnfirmPh: submitInfo.locgCnfirmPh, }; - const response = await statisticsInputAPi.submitSewerageSupplyRate(requestData); + + const response = await StatisticsInputSewSupplyRateApi.submitSewerageSupplyRate(requestData); if (response.status === 'success') { await fetchSewerageSupplyRate(getSewerageSupplyRateParams(searchValues ?? {}), false); alert('제출되었습니다.'); @@ -294,15 +296,15 @@ const SeweragePenetrationRateInp = () => { try { if (await confirm('저장 하시겠습니까?')) { setIsLoading(true); - + const userInfo = await getUserInfo(); const currentData = getGridDataRef.current?.(); - + if (!currentData || currentData.length === 0) { alert('저장할 데이터가 없습니다.'); return; } - + // 컬럼 정의에서 dataFormat 추출 (소수점 자리수 맞추기 위해) const columnFormatMap = new Map(); SeweragePenetrationRateInpColumn.columns.forEach((col) => { @@ -316,10 +318,10 @@ const SeweragePenetrationRateInp = () => { 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; - + // #,##0.000 → 소수점 3자리, #,##0.0 → 소수점 1자리, #,##0 → 정수 const decimalPlaces = format.match(/\.(\d+)/)?.[1]?.length ?? 0; return decimalPlaces > 0 ? parseFloat(num.toFixed(decimalPlaces)) : Math.round(num); @@ -370,8 +372,12 @@ const SeweragePenetrationRateInp = () => { sewerBzmnFrgnrPoplSm: footerFromApi?.frgnrPoplSm // 행정참고자료 외국인 합계 }; - const response = await statisticsInputAPi.saveSewerageSupplyRate(requestData); - + if (isAdminInfo) { + requestData.superAdmin = 'superAdmin'; + } + + const response = await StatisticsInputSewSupplyRateApi.saveSewerageSupplyRate(requestData); + if (response.status === 'success') { fetchSewerageSupplyRate(getSewerageSupplyRateParams(searchValues ?? {}), true); alert('저장되었습니다.'); @@ -390,57 +396,57 @@ const SeweragePenetrationRateInp = () => { return ( <> -
- - {rowData.length > 0 && (isEnterable && (doList.includes(lastSearchedValues?.bsnmCd || '') ? Boolean(lastSearchedValues?.gugun && lastSearchedValues.gugun !== 'ALL') : true) || isAdminInfo) && ( -
-
- {isEnterable && (doList.includes(lastSearchedValues?.bsnmCd || '') ? Boolean(lastSearchedValues?.gugun && lastSearchedValues.gugun !== 'ALL') : true) && ( - <> - - getLastYearDataFunc(searchValues ?? {})} /> - - - )} - {(isEnterable && (doList.includes(lastSearchedValues?.bsnmCd || '') ? Boolean(lastSearchedValues?.gugun && lastSearchedValues.gugun !== 'ALL') : true) || isAdminInfo) && } +
+ + {rowData.length > 0 && (isEnterable && (doList.includes(lastSearchedValues?.bsnmCd || '') ? Boolean(lastSearchedValues?.gugun && lastSearchedValues.gugun !== 'ALL') : true) || isAdminInfo) && ( +
+
+ {isEnterable && (doList.includes(lastSearchedValues?.bsnmCd || '') ? Boolean(lastSearchedValues?.gugun && lastSearchedValues.gugun !== 'ALL') : true) && ( + <> + + getLastYearDataFunc(searchValues ?? {})} /> + + + )} + {(isEnterable && (doList.includes(lastSearchedValues?.bsnmCd || '') ? Boolean(lastSearchedValues?.gugun && lastSearchedValues.gugun !== 'ALL') : true) || isAdminInfo) && } +
-
- )} - {isLoading &&
-
- -
-
} - 0) && isEnterable && (doList.includes(lastSearchedValues?.bsnmCd || '') ? Boolean(lastSearchedValues?.gugun && lastSearchedValues.gugun !== 'ALL') : true)} - rowStartNum={3} - fixedColumns={1} - rowData={rowData} - setRowData={setRowData} - statusInfo={statusInfo} - getGridDataRef={getGridDataRef} - cellStyleCallback={({ row, fieldName }) => { - const verification = (row as GridRowWithVerification).verificationResult; - if (!verification) return; - const errors = verification[fieldName]; - if (Array.isArray(errors) && errors.length > 0) { - 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'); - } - }} - /> -
- - + )} + {isLoading &&
+
+ +
+
} + 0) && isEnterable && (doList.includes(lastSearchedValues?.bsnmCd || '') ? Boolean(lastSearchedValues?.gugun && lastSearchedValues.gugun !== 'ALL') : true)} + rowStartNum={3} + fixedColumns={1} + rowData={rowData} + setRowData={setRowData} + statusInfo={statusInfo} + getGridDataRef={getGridDataRef} + cellStyleCallback={({ row, fieldName }) => { + const verification = (row as GridRowWithVerification).verificationResult; + if (!verification) return; + const errors = verification[fieldName]; + if (Array.isArray(errors) && errors.length > 0) { + 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'); + } + }} + /> +
+ + ); }; diff --git a/apps/st/src/components/statistics/input/StatsInputStatusInp.tsx b/apps/st/src/components/statistics/input/StatsInputStatusInp.tsx index 46f8620c2..057ba5b88 100644 --- a/apps/st/src/components/statistics/input/StatsInputStatusInp.tsx +++ b/apps/st/src/components/statistics/input/StatsInputStatusInp.tsx @@ -1,14 +1,59 @@ import { useState } from "react"; import SearchForm from "@/components/module/SearchForm"; -import { DataGrid } from "@rsone/components"; +// import { DataGrid } from "@rsone/components"; +import DataGrid from "@/components/module/DataGrid"; import ApproveButton from "@/components/button/ApproveButton"; import RejectButton from "@/components/button/RejectButton"; +import { LoadingWithAnimation } from "@common/components"; import { StatsInputStatusInpColumn } from "@/components/util/column/input/StatsInputStatusInpColumn"; +import { StatisticsInputStatusApi } from "@/entities/statistics/api/statistics-input-status-service"; +import type { StatsInputStatusListRequestParams } from "@/entities/statistics/model/statistics-input-status-interface"; +import type { SearchFormValues } from "@/components/type/SearchForm.type"; +import { useAlertStore } from "@/shared/lib"; +import { toGridRows } from "@/components/util/grid/gridFunction"; // 하수도 통계 관리 > 00. 통계 입력 현황 const StatsInputStatusInp = () => { + const { setMessage: alert } = useAlertStore((state) => state); + const [rowData, setRowData] = useState[]>([]); + const [isLoading, setIsLoading] = useState(false); + + const handleSearch = async (values: SearchFormValues) => { + if (values.sido === '' || values.sido === 'ALL') { + alert('시도를 선택해주세요.'); + return; + } + + const searchParam: StatsInputStatusListRequestParams = { + ctpvNm: values.sido, + sewerBzmnCd: values.bsnmCd, + sggNm: values.gugun === 'ALL' ? '' : values.gugun, + statsYr: values.year, + }; + + try { + setIsLoading(true); + + const response = await StatisticsInputStatusApi.getStatisticsInputStatusList(searchParam); + + if (response.status === 'success' && response.data) { + setRowData(toGridRows(response.data)); + } else { + alert(response.message); + } + } catch { + alert('데이터 조회 중 오류가 발생했습니다.'); + setRowData([]); + } finally { + setIsLoading(false); + } + }; + + const handleReset = () => { + setRowData([]); + }; const rejectFunc = () => { // 보완 요청 로직 @@ -18,25 +63,31 @@ const StatsInputStatusInp = () => { // 승인 요청 로직 }; - const [rowData, setRowData] = useState[]>([]); - return ( <> - -
-
- - +
+ +
+
+ + +
+ {isLoading &&
+
+ +
+
} +
- ); }; diff --git a/apps/st/src/components/statistics/input/SubmitDailog.tsx b/apps/st/src/components/statistics/input/SubmitDailog.tsx index 14cfa06b0..6d0bbbd12 100644 --- a/apps/st/src/components/statistics/input/SubmitDailog.tsx +++ b/apps/st/src/components/statistics/input/SubmitDailog.tsx @@ -18,7 +18,7 @@ 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"; +import { type SewerageSupplyRateStatusInfo } from "@/entities/statistics/model/statistics-sewage-supply-rate-input-interface"; /** 숫자만 추출 후 하이픈 포맷 (010-1234-5678, 02-123-4567 등) */ function formatPhoneWithHyphen(value: string): string { diff --git a/apps/st/src/components/type/DataGrid.type.ts b/apps/st/src/components/type/DataGrid.type.ts index 0106251d5..d9bf1997c 100644 --- a/apps/st/src/components/type/DataGrid.type.ts +++ b/apps/st/src/components/type/DataGrid.type.ts @@ -1,6 +1,6 @@ import React from "react"; import { ValueType } from "realgrid"; -import { type SewerageSupplyRateStatusInfo } from "@/entities/statistics/model/statistics-input-interface"; +import { type SewerageSupplyRateStatusInfo } from "@/entities/statistics/model/statistics-sewage-supply-rate-input-interface"; // RealGrid 타입 정의 /** setColumns에 전달하는 컬럼 정보 (footer 배열/단일 객체 포함) */ @@ -11,6 +11,7 @@ export type RealGridColumnInfo = { editable?: boolean; valueType?: import("realgrid").ValueType; dataFormat?: string; + width?: number; styleName?: string; mergeRule?: { criteria: "value" | string }; sortable?: boolean; @@ -132,6 +133,8 @@ export type ColumnConfig = { editable?: boolean; // 셀 편집 가능 여부 /** 그리드에서 컬럼 숨김 (수식용 필드 등) */ visible?: boolean; + /** 컬럼 너비 (px). 지정 시 ... 생략 없이 텍스트 표시에 유리 */ + width?: number; /** 셀에 적용할 CSS 클래스명 (예: 'rg-cell-readonly', 'rg-cell-total') */ styleName?: string; mergeCells?: boolean; diff --git a/apps/st/src/components/type/SearchForm.type.ts b/apps/st/src/components/type/SearchForm.type.ts index b6fd4211d..f3668b56c 100644 --- a/apps/st/src/components/type/SearchForm.type.ts +++ b/apps/st/src/components/type/SearchForm.type.ts @@ -18,6 +18,7 @@ export type SearchFormProps = { onReset?: () => void; onValuesChange?: (values: SearchFormValues) => void; defaultValues?: SearchFormValues; + isStatusMenu?: boolean; }; export const defaultSearchFormProps: Required> = { @@ -27,4 +28,5 @@ export const defaultSearchFormProps: Required { const response = await axios.get ( `${ENDPOINT.ST_SERVICE.INPUT}/sewerage-supply-rate`, @@ -49,4 +49,4 @@ export class StatisticsInputAPiService implements StatisticsInputService { } } -export const statisticsInputAPi = new StatisticsInputAPiService(); \ No newline at end of file +export const StatisticsInputSewSupplyRateApi = new StatisticsInputSewSupplyRateApiService(); \ No newline at end of file diff --git a/apps/st/src/entities/statistics/api/statistics-input-status-service.ts b/apps/st/src/entities/statistics/api/statistics-input-status-service.ts new file mode 100644 index 000000000..5dd094e66 --- /dev/null +++ b/apps/st/src/entities/statistics/api/statistics-input-status-service.ts @@ -0,0 +1,23 @@ +import axios from "axios"; +import { ENDPOINT } from "@/shared/config"; + +import type { + StatisticsInputStatusService, + StatsInputStatusListRequestParams, + StatsInputStatusListApiResponse, +} from "../model/statistics-input-status-interface"; + +export class StatisticsInputStatusApiService implements StatisticsInputStatusService { + public async getStatisticsInputStatusList(param: StatsInputStatusListRequestParams): Promise { + const response = await axios.get ( + `${ENDPOINT.ST_SERVICE.INPUT}/stats-input-status`, + { + params: param + } + ); + + return response.data; + }; +} + +export const StatisticsInputStatusApi = new StatisticsInputStatusApiService(); \ No newline at end of file diff --git a/apps/st/src/entities/statistics/api/statistics-management-service.ts b/apps/st/src/entities/statistics/api/statistics-management-service.ts index f7a75da29..309a7b2f3 100644 --- a/apps/st/src/entities/statistics/api/statistics-management-service.ts +++ b/apps/st/src/entities/statistics/api/statistics-management-service.ts @@ -2,7 +2,6 @@ import axios from "axios"; import { ENDPOINT } from "@/shared/config"; -import { type CheckInputPeriodResponse } from "../model/statistics-input-interface"; import { type StatsInputStatusReviewApiResponse } from "../model/statistics-input-review-interface"; @@ -46,18 +45,6 @@ export class StatisticsManagementApiService { return response.data; } - /** - * 입력 기간 확인 (공통) - * @param year 연도 - */ - public async checkInputPeriod(year: string | number): Promise { - const response = await axios.get( - `${ENDPOINT.ST_SERVICE.INPUTCOMMON}/check-input-period`, - { params: { year } } - ); - return response.data; - } - /** * 01. 하수도 보급률 검토 목록 조회 * @param params (sido, gugun, yr, bsnmCd) diff --git a/apps/st/src/entities/statistics/model/statistics-input-status-interface.ts b/apps/st/src/entities/statistics/model/statistics-input-status-interface.ts new file mode 100644 index 000000000..47637923f --- /dev/null +++ b/apps/st/src/entities/statistics/model/statistics-input-status-interface.ts @@ -0,0 +1,34 @@ +import type { ApiResponse } from "./statistics-interface"; + +export interface StatsInputStatusListRequestParams { + ctpvNm?: string; + sggNm?: string; + sewerBzmnCd?: string; + statsYr?: string; + mode?: string; +} + +export interface StatsInputStatusList { + sido?: string; + gugun?: string; + menuCd?: string; + menuNm?: string; + locgStatusNm?: string; + inputRate?: number; + locgCharger?: string; + locgCttpc?: string; + locgDept?: string; + locgJob?: string; + locgCnfirmNm?: string; + locgCnfirmDept?: string; + locgCnfirmJob?: string; + returnOpinionSm?: string; +} + +export type StatsInputStatusListApiResponse = ApiResponse & { + message: string; +} + +export interface StatisticsInputStatusService { + getStatisticsInputStatusList(param: StatsInputStatusListRequestParams): Promise; +} diff --git a/apps/st/src/entities/statistics/model/statistics-input-interface.ts b/apps/st/src/entities/statistics/model/statistics-sewage-supply-rate-input-interface.ts similarity index 98% rename from apps/st/src/entities/statistics/model/statistics-input-interface.ts rename to apps/st/src/entities/statistics/model/statistics-sewage-supply-rate-input-interface.ts index 72b519acc..8ed9340ea 100644 --- a/apps/st/src/entities/statistics/model/statistics-input-interface.ts +++ b/apps/st/src/entities/statistics/model/statistics-sewage-supply-rate-input-interface.ts @@ -146,6 +146,7 @@ export interface SewerageSupplyRateSaveRequest { locgCnfirmJob?: string; locgCnfirmDept?: string; locgCnfirmPh?: string; + superAdmin?: string; } export interface SewerageSupplyRateSaveData { @@ -162,7 +163,7 @@ export interface CheckInputPeriodResponse { data: boolean; } -export interface StatisticsInputService { +export interface StatisticsInputSewSupplyRateService { getSewerageSupplyRateList(params: SewerageSupplyRateRequestParams): Promise; checkInputPeriod(params: string): Promise; saveSewerageSupplyRate(params: SewerageSupplyRateSaveRequest): Promise;