Merge branch 'iipbs/st/dev' of https://www.onasys.co.kr:3000/ONAANDALL/frontend into iipbs/st/dev

This commit is contained in:
2026-03-11 12:51:37 +09:00
31 changed files with 2140 additions and 1797 deletions
@@ -1,31 +1,87 @@
import { useState } from "react";
import { useState, useMemo } from "react";
import SearchForm from "@/components/module/SearchForm";
import { TabDataGrid } from '@rsone/components';
import TabDataGrid from "@/components/module/TabDataGrid";
import SubmitButton from "@/components/button/SumitButton";
import SaveButton from "@/components/button/SaveButton";
import LastYearDataButton from "@/components/button/LastYearDataButton";
import SubmitExceptionButton from "@/components/button/SubmitExceptionButton";
import { RegionalFactStatusInpColumn } from "@/components/util/column/input/sewagePipe/RegionalFactStatusInpColumn";
import { FactInstallStatusInpColumn } from "@/components/util/column/input/sewagePipe/FactInstallStatusInpColumn";
import { PipeTypeStatusInpColumn } from "@/components/util/column/input/sewagePipe/PipeTypeStatusInpColumn";
import { PipeDiameterStatusInpColumn } from "@/components/util/column/input/sewagePipe/PipeDiameterStatusInpColumn";
import { ManholeStatusInpColumn } from "@/components/util/column/input/sewagePipe/ManholeStatusInpColumn";
import { ConnectionStatusInpColumn } from "@/components/util/column/input/sewagePipe/ConnectionStatusInpColumn";
import { SewagePipeInpColumnInfoList } from "@/components/util/column/input/sewagePipe/SewagePipeInpColumn";
import type { ColumnInfoList, ColumnConfig } from "@/components/type/DataGrid.type";
import type { SearchFormValues } from "@/components/type/SearchForm.type";
import { useAlertStore } from "@/shared/lib";
import { useAdminStore } from "@/store/admin-store";
// 하수도 통계 관리 > 02. 하수관로
// 하수도 통계 관리 > 02. 하수관로
const SewagePipeInp = () => {
// tab List
const SewagePipeInpTapList = [
RegionalFactStatusInpColumn,
FactInstallStatusInpColumn,
PipeTypeStatusInpColumn,
PipeDiameterStatusInpColumn,
ManholeStatusInpColumn,
ConnectionStatusInpColumn,
];
const [rowDataMap, setRowDataMap] = useState<Map<string, Record<string, string | number>[]>>(new Map());
const { setMessage: alert } = useAlertStore((state) => state);
const [isLoading, setIsLoading] = useState<boolean>(false);
const [activeTab, setActiveTab] = useState<string>(SewagePipeInpColumnInfoList[0]?.tabKey ?? "ST00020001");
const [isEnterable, setIsEnterable] = useState<boolean>(true);
const { isAdminInfo } = useAdminStore();
const columnInfo = useMemo(() => {
const canEdit = isEnterable || isAdminInfo;
return SewagePipeInpColumnInfoList.map((tab: ColumnInfoList) => {
const applyEditable = (cols: ColumnConfig[] | undefined) =>
(cols ?? []).map((col: ColumnConfig) =>
canEdit
? col
: { ...col, editable: false as const, styleName: col.styleName ?? "rg-cell-readonly" }
);
if (tab.left && tab.right) {
return {
...tab,
left: { ...tab.left, columns: applyEditable(tab.left.columns) },
right: { ...tab.right, columns: applyEditable(tab.right.columns) },
};
}
return {
...tab,
columns: applyEditable(tab.columns),
};
});
}, [isEnterable, isAdminInfo]);
const handleSearch = async (values: SearchFormValues) => {
if (!values.sido || values.sido === 'ALL') {
alert('시도를 선택해주세요.');
return;
}
setActiveTab('ST00020001');
setRowDataMap(new Map());
try {
setIsLoading(true);
// const searchParam: SewagePipeReviewRequestParams = {
// statsYr: values.year,
// sewerBzmnCd: values.bsnmCd,
// ctpvNm: values.sido,
// sggNm: values.gugun === 'ALL' ? '' : values.gugun
// };
// searchParamRef.current = searchParam;
// const response = await statisticsManagementApi.getSewagePipeReviewRegionalList(searchParam);
// if (response?.status === 'success' && response.data) {
// const newRowDataMap = new Map<string, Record<string, string | number>[]>();
// newRowDataMap.set('ST00020001', toGridRows(response.data as object[]));
// setRowDataMap(newRowDataMap);
// } else {
// alert(response?.message || "데이터가 없습니다.");
// }
} catch {
alert('데이터 조회 중 오류가 발생했습니다.');
} finally {
setIsLoading(false);
}
};
const SubmitExceptionFunc = () => {
console.log('submit exception');
@@ -47,7 +103,6 @@ const SewagePipeInp = () => {
// 저장 로직
};
const [rowDataMap, setRowDataMap] = useState<Map<string, Record<string, string | number>[]>>(new Map());
return (
<>
@@ -60,10 +115,12 @@ const SewagePipeInp = () => {
<SaveButton saveFunc={saveFunc} />
</div>
</div>
<TabDataGrid
columnInfo={SewagePipeInpTapList}
rowDataMap={rowDataMap}
setRowDataMap={setRowDataMap}
<TabDataGrid
columnInfo={columnInfo}
rowDataMap={rowDataMap}
setRowDataMap={setRowDataMap}
activeTab={activeTab}
onActiveTabChange={setActiveTab}
/>
</>
);
@@ -14,7 +14,13 @@ import SubmitDailog from "./SubmitDailog";
import { useAlertStore } from "@/shared/lib";
import { useAdminStore } from "@/store/admin-store";
import { StatisticsInputSewSupplyRateApi } from "@/entities/statistics/api/statistics-input-sew-supply-rate-service";
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/statistics-input-sew-supply-rate-service";
import { statisticsAPi } from "@/entities/statistics/api/statistics-service";
import { toGridRows } from "@/components/util/grid/gridFunction";
import { getFooterSummary } from "@/components/util/grid/footerSummary";
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
import { useConfirm } from "@frontend-opensource/use-react-hooks";
import type { SearchFormValues } from "@/components/type/SearchForm.type";
import type {
SewerageSupplyRateItem,
@@ -24,14 +30,12 @@ import type {
SewerageSupplyRateSaveRequest,
SewerageSupplyRateStatusInfo,
} from "@/entities/statistics/model/statistics-sewage-supply-rate-input-interface";
import type { cancelSubmitRequest } from "@/entities/statistics/model/statistics-interface";
import type { StatisticsInputSubmitInfoFormData } from "@/entities/statistics/model/statistics-input-submit-info-schema";
import { SeweragePenetrationRateInpColumn } from "@/components/util/column/input/SeweragePenetrationRateInpColumn";
import { 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;
};
@@ -60,11 +64,12 @@ const SeweragePenetrationRateInp = () => {
const [lastSearchedValues, setLastSearchedValues] = useState<SearchFormValues | null>(null);
const [statusInfo, setStatusInfo] = useState<SewerageSupplyRateStatusInfo | null>(null);
const [showDailog, setShowDailog] = useState<boolean>(false);
const [statsCd, setStatsCd] = useState<string>('');
const [footerFromApi, setFooterFromApi] = useState<{ sewerBzmnWholPpltnCnt?: number; sewerBzmnDomplWholPpltnCnt?: number; sewerBzmnFrgnrWholPpltnCnt?: number; sewerBzmnArea?: number } | null>(null);
const { confirm } = useConfirm();
const { isAdminInfo } = useAdminStore();
const [footerFromApi, setFooterFromApi] = useState<{ sewerBzmnWholPpltnCnt?: number; sewerBzmnDomplWholPpltnCnt?: number; sewerBzmnFrgnrWholPpltnCnt?: number; sewerBzmnArea?: number } | null>(null);
const getGridDataRef = useRef<(() => Record<string, string | number>[]) | null>(null);
const _footerFieldNames = ['sewerBzmnWholPpltnCnt', 'sewerBzmnDomplWholPpltnCnt', 'sewerBzmnFrgnrWholPpltnCnt', 'sewerBzmnArea'] as const;
@@ -103,7 +108,7 @@ const SeweragePenetrationRateInp = () => {
const fetchSewerageSupplyRate = async (params: SewerageSupplyRateRequestParams, isEnterable: boolean) => {
try {
setIsLoading(true);
const response = await StatisticsInputSewSupplyRateApi.getSewerageSupplyRateList(params);
const response = await statisticsInputSewSupplyRateApi.getSewerageSupplyRateList(params);
if (response.status === 'success' && response.data) {
const commonInfo = response.data.commonInfo;
const statusInfo = response.data.statusInfo;
@@ -121,7 +126,7 @@ const SeweragePenetrationRateInp = () => {
})
);
setStatusInfo(response.data.statusInfo);
setStatusInfo(statusInfo);
setFooterFromApi(
commonInfo
? {
@@ -132,7 +137,7 @@ const SeweragePenetrationRateInp = () => {
}
: null
);
setStatsCd(commonInfo.statsCd);
if (statusInfo && statusInfo.laeSbmsnSttsCd) {
if (['2', '3'].includes(statusInfo.laeSbmsnSttsCd)) {
setIsEnterable(false);
@@ -163,7 +168,7 @@ const SeweragePenetrationRateInp = () => {
}
try {
const response = await StatisticsInputSewSupplyRateApi.checkInputPeriod(values.year || '');
const response = await statisticsInputSewSupplyRateApi.checkInputPeriod(values.year || '');
if (response.status === 'success') {
const checkEnterable = response.data;
@@ -266,6 +271,7 @@ const SeweragePenetrationRateInp = () => {
const requestData: SewerageSupplyRateSaveRequest = {
sewerBzmnCd: searchValues?.bsnmCd ?? '',
ctpvNm: searchValues?.sido ?? '',
sggNm: searchValues?.gugun ?? '',
statsYr: searchValues?.year ?? '',
userId: userInfo.userUnqId,
submitList: convertedData,
@@ -280,7 +286,7 @@ const SeweragePenetrationRateInp = () => {
laeIdfrTelNo: submitInfo.laeIdfrTelNo,
};
const response = await StatisticsInputSewSupplyRateApi.submitSewerageSupplyRate(requestData);
const response = await statisticsInputSewSupplyRateApi.submitSewerageSupplyRate(requestData);
if (response.status === 'success') {
await fetchSewerageSupplyRate(getSewerageSupplyRateParams(searchValues ?? {}), false);
alert('제출되었습니다.');
@@ -368,6 +374,7 @@ const SeweragePenetrationRateInp = () => {
const requestData: SewerageSupplyRateSaveRequest = {
sewerBzmnCd: searchValues?.bsnmCd ?? '', // 하수도 사업자 코드
ctpvNm: searchValues?.sido ?? '', // 시도
sggNm: searchValues?.gugun ?? '',
statsYr: searchValues?.year ?? '', // 통계 연도
userId: userInfo.userUnqId, // 사용자
saveList: convertedData, // 저장 데이터
@@ -378,7 +385,7 @@ const SeweragePenetrationRateInp = () => {
requestData.superAdmin = 'superAdmin';
}
const response = await StatisticsInputSewSupplyRateApi.saveSewerageSupplyRate(requestData);
const response = await statisticsInputSewSupplyRateApi.saveSewerageSupplyRate(requestData);
if (response.status === 'success') {
fetchSewerageSupplyRate(getSewerageSupplyRateParams(searchValues ?? {}), true);
@@ -395,7 +402,36 @@ const SeweragePenetrationRateInp = () => {
setIsLoading(false);
}
};
console.log(footerFromApi);
const cnacelSubmitFunc = async () => {
try {
if (await confirm('제출된 내용을 취소하시겠습니까?')) {
const userInfo = await getUserInfo();
const requestData: cancelSubmitRequest = {
sewerBzmnCd: searchValues?.bsnmCd ?? '',
ctpvNm: searchValues?.sido ?? '',
sggNm: searchValues?.gugun ?? '',
statsYr: searchValues?.year ?? '',
userId: userInfo.userUnqId,
statsCd: statsCd,
};
const response = await statisticsAPi.cancelSubmit(requestData);
if (response.status === 'success') {
fetchSewerageSupplyRate(getSewerageSupplyRateParams(searchValues ?? {}), true);
alert('제출 취소되었습니다.');
} else {
alert(response.message ?? '제출 취소 중 오류가 발생했습니다.');
}
}
} catch {
alert('제출 취소 중 오류가 발생했습니다.');
}
};
return (
<>
<div className="relative">
@@ -411,7 +447,7 @@ const SeweragePenetrationRateInp = () => {
</>
)}
{statusInfo?.laeSbmsnSttsCd === '2' && <CancelSubmitButton cnacelSubmitFunc={() => console.log('test')} />}
{statusInfo?.laeSbmsnSttsCd === '2' && <CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />}
{(isEnterable && (doList.includes(lastSearchedValues?.bsnmCd || '') ? Boolean(lastSearchedValues?.gugun && lastSearchedValues.gugun !== 'ALL') : true) || isAdminInfo) && <SaveButton saveFunc={saveFunc} />}
</div>
</div>
@@ -1,7 +1,8 @@
import { useState } from "react";
import { useState, useEffect } from "react";
import useSWR, { useSWRConfig } from "swr";
import SearchForm from "@/components/module/SearchForm";
// import { DataGrid } from "@rsone/components";
import { useTabStore } from "@/store/tab-store";
import DataGrid from "@/components/module/DataGrid";
import ApproveButton from "@/components/button/ApproveButton";
import RejectButton from "@/components/button/RejectButton";
@@ -13,45 +14,63 @@ import type { StatsInputStatusListRequestParams } from "@/entities/statistics/mo
import type { SearchFormValues } from "@/components/type/SearchForm.type";
import { useAlertStore } from "@/shared/lib";
import { toGridRows } from "@/components/util/grid/gridFunction";
import type { StatsInputStatusListApiResponse } from "@/entities/statistics/model/statistics-input-status-interface";
const getStatsInputStatusFetcher = async (key: [string, StatsInputStatusListRequestParams]): Promise<StatsInputStatusListApiResponse> => {
return StatisticsInputStatusApi.getStatisticsInputStatusList(key[1]);
};
// 하수도 통계 관리 > 00. 통계 입력 현황
const StatsInputStatusInp = () => {
const { setMessage: alert } = useAlertStore((state) => state);
const activeTabId = useTabStore((state) => state.activeTabId);
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
const [isLoading, setIsLoading] = useState<boolean>(false);
const [searchParams, setSearchParams] = useState<StatsInputStatusListRequestParams | null>(null);
const handleSearch = async (values: SearchFormValues) => {
if (values.sido === '' || values.sido === 'ALL') {
alert('시도를 선택해주세요.');
const swrKey = searchParams ? (["stats-input-status", searchParams] as const) : null;
const { mutate } = useSWRConfig();
const { isLoading } = useSWR<StatsInputStatusListApiResponse>(
swrKey,
getStatsInputStatusFetcher,
{
revalidateOnFocus: true,
onSuccess: (data) => {
if (data.status === "success" && data.data) {
setRowData(toGridRows(data.data));
} else {
alert(data.message ?? "조회에 실패했습니다.");
}
},
onError: () => {
alert("데이터 조회 중 오류가 발생했습니다.");
setRowData([]);
},
},
);
useEffect(() => {
if (activeTabId === 'StatsInputStatusInp' && swrKey) {
mutate(swrKey);
}
}, [activeTabId]);
const handleSearch = (values: SearchFormValues) => {
if (values.sido === "" || values.sido === "ALL") {
alert("시도를 선택해주세요.");
return;
}
const searchParam: StatsInputStatusListRequestParams = {
const params: StatsInputStatusListRequestParams = {
ctpvNm: values.sido,
sewerBzmnCd: values.bsnmCd,
sggNm: values.gugun === 'ALL' ? '' : values.gugun,
sggNm: values.gugun === "ALL" ? "" : values.gugun,
statsYr: values.year,
};
try {
setIsLoading(true);
const response = await StatisticsInputStatusApi.getStatisticsInputStatusList(searchParam);
console.log(response)
if (response.status === 'success' && response.data) {
setRowData(toGridRows(response.data));
} else {
alert(response.message);
}
} catch {
alert('데이터 조회 중 오류가 발생했습니다.');
setRowData([]);
} finally {
setIsLoading(false);
}
setSearchParams(params);
mutate(["stats-input-status", params]);
};
const handleReset = () => {
setSearchParams(null);
setRowData([]);
};
@@ -155,7 +155,7 @@ const SubmitDailog = ({ open, onOpenChange, statusInfo, onConfirm }: SubmitDialo
취소
</Button>
<Button type="submit" color="green">
저장
제출
</Button>
</DialogFooter>
</form>
@@ -12,12 +12,15 @@ import { PumpingStationInfoList } from "@/components/util/column/review/PumpingS
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
import type { SearchFormValues } from "@/components/type/SearchForm.type";
import { toGridRows } from "@/components/util/grid/gridFunction";
import type { MediationPumpStationItem } from "@/entities/statistics/model/statistics-pumping-station-review-interface";
// 하수도 통계 검토 05.중계펌프장
/**
* 하수도 통계 검토 05.중계펌프장
*/
const PumpingStationRvw = () => {
const { setMessage: alert } = useAlertStore((state) => state);
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
const [isLoading, setIsLoading] = useState<boolean>(false);
const [isLoading, setIsLoading] = useState<boolean>(false);
const columnInfo = useMemo(() => {
const { columns, columnLayout, fixedColumns, rowStartNum } = PumpingStationInfoList;
@@ -27,7 +30,7 @@ const PumpingStationRvw = () => {
rowStartNum,
columns: columns.map((col) => ({
...col,
editable: false as const, // 검토 화면이므로 읽기 전용
editable: false as const,
styleName: col.styleName ?? ("rg-cell-readonly" as const),
})),
};
@@ -38,7 +41,7 @@ const PumpingStationRvw = () => {
};
const handleSearch = async (values: SearchFormValues) => {
if (values.sido === '' || values.sido === 'ALL') {
if (!values.sido || values.sido === 'ALL') {
alert('시도를 선택해주세요.');
return;
}
@@ -47,15 +50,22 @@ const PumpingStationRvw = () => {
setIsLoading(true);
const response = await statisticsManagementApi.getMediationPumpStationList({
sido: values.sido,
gugun: values.gugun === 'ALL' ? '' : values.gugun,
bsnmCd: values.bsnmCd,
yr: values.year,
bscFctNm: values.fctName, // 시설명 검색
ctpvNm: values.sido,
sggNm: values.gugun === 'ALL' ? '' : values.gugun,
sewerBzmnCd: values.bsnmCd,
statsYr: values.year,
pumpstNm: values.fctName,
});
if (response.status === 'success' && response.data) {
setRowData(toGridRows(response.data));
const rawList = response.data as MediationPumpStationItem[];
const convertedData = rawList.map(item => ({
...item,
rmrk: item.rmrk || ''
}));
setRowData(toGridRows(convertedData));
} else {
setRowData([]);
alert(response.message || "데이터가 없습니다.");
@@ -64,7 +74,7 @@ const PumpingStationRvw = () => {
console.error("중계펌프장 조회 중 에러 발생:", error);
alert('데이터 조회 중 오류가 발생했습니다.');
} finally {
setIsLoading(false);
setIsLoading(false);
}
};
@@ -74,9 +84,9 @@ const PumpingStationRvw = () => {
const returnFunc = () => console.log('returnFunc');
return (
<div className="relative">
<SearchForm onSubmit={handleSearch} onReset={handleReset} fctName={true} />
<div className="relative">
<SearchForm onSubmit={handleSearch} onReset={handleReset} />
<div className="card !py-0">
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
<ReviewOpinionButton reviewOpinionFunc={reviewOpinionFunc} />
@@ -101,7 +101,7 @@ const SewagePipeMaintainRvw = () => {
if (tabKey === 'ST00030001') {
response = await statisticsManagementApi.getSewerPipeMtcList(searchParamRef.current);
} else if (tabKey === 'ST00030002') {
// response = await statisticsManagementApi.getSewerPipeDrdgList(searchParamRef.current);
response = await statisticsManagementApi.getSewerPipeDrdgList(searchParamRef.current);
}
if (response?.status === 'success' && response.data) {
@@ -96,12 +96,11 @@ const SewagePipeRvw = () => {
if (tabKey === 'ST00020002') {
response = await statisticsManagementApi.getSewagePipeFacilityList(searchParamRef.current);
}else if(tabKey === 'ST00020003'){
response = await statisticsManagementApi.getSewagePipeTypeList(searchParamRef.current);
}else if(tabKey === 'ST00020004'){
response = await statisticsManagementApi.getSewagePipeDiamList(searchParamRef.current);
}
// }else if(tabKey === 'ST00020003'){
// response = await statisticsManagementApi.getSewagePipeTypeList(searchParamRef.current);
// }else if(tabKey === 'ST00020004'){
// response = await statisticsManagementApi.getSewagePipeDiamList(searchParamRef.current);
// }
if (response?.status === 'success' && response.data) {
@@ -13,11 +13,12 @@ import { SewageReservoirPumpInfoListRvw } from "@/components/util/column/review/
import type { ColumnInfoList, ColumnConfig } from "@/components/type/DataGrid.type";
import type { SearchFormValues } from "@/components/type/SearchForm.type";
import { toGridRows } from "@/components/util/grid/gridFunction";
import type { SewerReservoirRequestParams } from "@/entities/statistics/model/sewage-reservoir-pump-review-interface";
/**
* 하수도 통계 검토 04. 하수저류 시설 및 빗물 펌프장
* Tab A: 하수저류시설
* Tab B: 빗물펌프장
* Tab A: 하수저류시설 (ST00040001)
* Tab B: 빗물펌프장 (ST00040002)
*/
const SewageReservoirPumpRvw = () => {
const { setMessage: alert } = useAlertStore((state) => state);
@@ -25,7 +26,7 @@ const SewageReservoirPumpRvw = () => {
const [isLoading, setIsLoading] = useState<boolean>(false);
const [activeTab, setActiveTab] = useState<string>('ST00040001');
const searchParamRef = useRef<SearchFormValues | null>(null);
const searchParamRef = useRef<SewerReservoirRequestParams | null>(null);
const columnInfo = useMemo(() => {
return SewageReservoirPumpInfoListRvw.map((tab: ColumnInfoList) => ({
@@ -56,16 +57,15 @@ const SewageReservoirPumpRvw = () => {
try {
setIsLoading(true);
const searchParam = {
sido: values.sido,
gugun: values.gugun === 'ALL' ? '' : values.gugun,
bsnmCd: values.bsnmCd,
yr: values.year,
const searchParam: SewerReservoirRequestParams = {
statsYr: values.year,
sewerBzmnCd: values.bsnmCd,
ctpvNm: values.sido,
sggNm: values.gugun === 'ALL' ? '' : values.gugun,
};
searchParamRef.current = searchParam;
//하수저류시설 (Tab A)
const response = await statisticsManagementApi.getSewerReservoirList(searchParam);
if (response?.status === 'success' && response.data) {
@@ -85,15 +85,21 @@ const SewageReservoirPumpRvw = () => {
const handleActiveTabChange = async (tabKey: string) => {
setActiveTab(tabKey);
const existingAData = rowDataMap.get('ST00040001');
const activeTabData = rowDataMap.get(tabKey);
const hasAData = Array.isArray(existingAData) && existingAData.length > 0;
const hasActiveTabData = Array.isArray(activeTabData) && activeTabData.length > 0;
if (searchParamRef.current && !hasActiveTabData) {
if (hasAData && !hasActiveTabData && searchParamRef.current) {
try {
setIsLoading(true);
let response;
if (tabKey === 'ST00040002') {
if (tabKey === 'ST00040001') {
response = await statisticsManagementApi.getSewerReservoirList(searchParamRef.current);
} else if (tabKey === 'ST00040002') {
response = await statisticsManagementApi.getPumpStationList(searchParamRef.current);
}
@@ -116,19 +122,19 @@ const SewageReservoirPumpRvw = () => {
return (
<div className="relative">
<SearchForm onSubmit={handleSearch} onReset={handleReset}/>
<SearchForm onSubmit={handleSearch} onReset={handleReset} />
<div className="card !py-0">
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
<ReviewOpinionButton reviewOpinionFunc={() => { /* 검토의견 로직 */ }} />
<ApproveButton approveFunc={() => { /* 승인 로직 */ }} />
<ReturnButton returnFunc={() => { /* 반려 로직 */ }} />
<SaveButton saveFunc={() => { /* 저장 로직 */ }} />
<ReviewOpinionButton reviewOpinionFunc={() => { }} />
<ApproveButton approveFunc={() => { }} />
<ReturnButton returnFunc={() => { }} />
<SaveButton saveFunc={() => { }} />
</div>
</div>
{isLoading && (
<div className="absolute inset-0 z-50 rounded-lg flex justify-center items-center bg-white/50">
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
<div className="relative size-[5rem]">
<LoadingWithAnimation color="primary" />
</div>
@@ -1,79 +1,141 @@
"use client";
import { useState } from 'react';
import { useMemo, useState } from 'react';
import { CodeSelect } from '@/entities/code';
import {
Button,
Label,
Table,
TableBody,
TableCell,
TableHead,
TableRow,
// Table,
// TableBody,
// TableCell,
// TableHead,
// TableRow,
DataTable,
} from "@common/components";
import { getCoreRowModel, useReactTable } from "@tanstack/react-table";
// import { useDataTable } from "@/shared/lib";
import { GeneralVerificationColumn } from '@/components/util/column/management/GeneralVerificationColumn';
import type { GeneralverificationList } from '@/entities/statistics/model/general-verification-interface';
const GeneralVerificationManagement = () => {
const [statsCd, setStatsCd] = useState('');
// const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
// const [pagination, setPagination] = useState<PaginationState>({
// pageIndex: 0,
// pageSize: 100,
// });
// const { tableComponent } = useDataTable({
// tableOptions: {
// GeneralVerificationColumn,
// state: {
// pagination,
// rowSelection,
// },
// manualPagination: true,
// enableMultiRowSelection: true,
// getCoreRowModel: getCoreRowModel(),
// onPaginationChange: setPagination,
// onRowSelectionChange: setRowSelection,
// },
// // dataTableOptions: {
// // onRowClick: handleRowClick,
// // viewPagination: true,
// // },
// });
const mockData = useMemo<GeneralverificationList[]>(
() => [
{
vrfSn: 1,
tabNm: '하수도보급률',
vrfNm: '인구수 검증',
vrfClsCd: '시',
statsCd: 'ST000001',
useYn: 'Y',
rgtrId: '관리자',
regDt: '20260102',
},
{
vrfSn: 2,
tabNm: '하수도보급률',
vrfNm: '인구수 검증',
vrfClsCd: '시',
statsCd: 'ST000001',
useYn: 'Y',
rgtrId: '관리자',
regDt: '20260102',
},
{
vrfSn: 3,
tabNm: '하수도보급률',
vrfNm: '인구수 검증',
vrfClsCd: '시',
statsCd: 'ST000001',
useYn: 'Y',
rgtrId: '관리자',
regDt: '20260102',
},
{
vrfSn: 4,
tabNm: '하수도보급률',
vrfNm: '인구수 검증',
vrfClsCd: '시',
statsCd: 'ST000001',
useYn: 'Y',
rgtrId: '관리자',
regDt: '20260102',
},
],
[]
);
const table = useReactTable({
data: mockData,
columns: GeneralVerificationColumn,
getCoreRowModel: getCoreRowModel(),
});
const handleSearch = () => {
console.log(statsCd);
};
return (
<div className="relative">
<div className='h-full'>
<div className="card card-border">
<form>
<div className="flex items-center gap-8 p-2">
<div className="flex items-center gap-2">
<Label className="text-label">
통계항목
</Label>
<CodeSelect
upCd="STITEM"
value={statsCd}
onValueChange={setStatsCd}
placeholder="선택"
className="w-[16rem]"
/>
</div>
<div className="flex items-center gap-2 ml-auto">
<Button color="green" className="h-[3.2rem] w-[96px]" type="button">
초기화
</Button>
<Button className="h-[3.2rem] w-[96px]" type="submit">
조회
</Button>
</div>
<div className="flex items-center gap-8 p-2">
<div className="flex items-center gap-2">
<Label className="text-label">
통계항목
</Label>
<CodeSelect
upCd="STITEM"
value={statsCd}
onValueChange={setStatsCd}
placeholder="전체"
className="w-[16rem]"
/>
</div>
</form>
<div className="flex items-center gap-2 ml-auto">
<Button color="green" className="h-[3.2rem] w-[96px]" type="button">
초기화
</Button>
<Button className="h-[3.2rem] w-[96px]" type="button" onClick={handleSearch}>
조회
</Button>
</div>
</div>
</div>
<div className='card !mb-0 flex gap-5 !p-0'>
<div className='card !mb-0 flex gap-5 !p-0 h-[calc(100vh-40rem)]'>
<div className='card card-border w-1/2 !mx-0 flex flex-col'>
<Table variant="default">
<TableRow>
<TableHead>No</TableHead>
<TableHead>검증항목</TableHead>
<TableHead>등록자</TableHead>
<TableHead>등록일</TableHead>
<TableHead>사용여부</TableHead>
</TableRow>
<TableBody className='text-center'>
<TableRow>
<TableCell>
1
</TableCell>
<TableCell>
인구수검증
</TableCell>
<TableCell>
관리자
</TableCell>
<TableCell>
2026-02-09
</TableCell>
<TableCell>
Y
</TableCell>
</TableRow>
</TableBody>
</Table>
<div className="card-header">
<h3 className="text-2xl font-medium text-label">일반 검증 목록</h3>
</div>
<div className="card !m-4 h-full overflow-auto !p-0">
<DataTable table={table} />
</div>
</div>
<div className='w-1/2'>