Merge branch 'iipbs/st/dev'
This commit is contained in:
@@ -32,6 +32,9 @@
|
||||
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-total {
|
||||
@apply !bg-[#e3eaf2];
|
||||
}
|
||||
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-selected-row {
|
||||
@apply !bg-[#dbeafe];
|
||||
}
|
||||
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-rowtype-biz-sum {
|
||||
@apply !bg-[#ffe9cf];
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import CompactDataGrid from "./CompactDataGrid";
|
||||
import type { SplitDataGridProps } from "../type/DataGrid.type";
|
||||
|
||||
import CompactDataGrid from "./CompactDataGrid";
|
||||
|
||||
const SplitDataGrid = ({
|
||||
leftColumnInfo,
|
||||
rightColumnInfo,
|
||||
@@ -11,6 +12,8 @@ const SplitDataGrid = ({
|
||||
rightRowData,
|
||||
setLeftRowData,
|
||||
setRightRowData,
|
||||
leftOnRowClick,
|
||||
leftCellStyleCallback,
|
||||
enableSort = false,
|
||||
}: SplitDataGridProps) => {
|
||||
return (
|
||||
@@ -18,10 +21,12 @@ const SplitDataGrid = ({
|
||||
<CompactDataGrid
|
||||
columnInfo={leftColumnInfo}
|
||||
fixedColumns={leftFixedColumns}
|
||||
showHeaderCheckbox={showHeaderCheckbox}
|
||||
showHeaderCheckbox={false}
|
||||
enableSort={enableSort}
|
||||
rowData={leftRowData}
|
||||
setRowData={setLeftRowData}
|
||||
onRowClick={leftOnRowClick}
|
||||
cellStyleCallback={leftCellStyleCallback}
|
||||
/>
|
||||
<CompactDataGrid
|
||||
columnInfo={rightColumnInfo}
|
||||
|
||||
@@ -1,33 +1,338 @@
|
||||
import { useState } from 'react';
|
||||
import { useRef, useState } from 'react';
|
||||
|
||||
import SearchForm from '@/components/module/SearchForm';
|
||||
import DataGrid from '@/components/module/DataGrid';
|
||||
import SplitDataGrid from '@/components/module/SplitDataGrid';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@common/components';
|
||||
import SubmitButton from '@/components/button/SumitButton';
|
||||
import { useConfirm } from '@frontend-opensource/use-react-hooks';
|
||||
|
||||
import { useAlertStore } from '@/shared/lib';
|
||||
import { statisticsInputSewSupplyRateApi } from '@/entities/statistics/api/input/statistics-input-sew-supply-rate-service';
|
||||
import { statisticsInputPublicSewageFacilityApiService } from '@/entities/statistics/api/input/statistics-public-sewage-facility-input-service';
|
||||
import { statisticsApi } from '@/entities/statistics/api/statistics-service';
|
||||
import type {
|
||||
PublicSewageFacilityRequestParams,
|
||||
PublicSewageFacilitySaveItem,
|
||||
PublicSewageFacilitySaveRequest,
|
||||
PublicSewageMappingTargetsRequestParams,
|
||||
} from '@/entities/statistics/model/input/statistics-public-sewage-facility-input-interface';
|
||||
import {
|
||||
type CheckInputPeriodItem,
|
||||
getVerificationPeriodActionBlockedMessage,
|
||||
isInputPeriodCurrent,
|
||||
} from '@/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface';
|
||||
import type { StatisticsInputSubmitInfoFormData } from '@/entities/statistics/model/statistics-input-submit-info-schema';
|
||||
import type { cancelSubmitRequest, ImrStatusResponse, SewerageStatusInfo } from '@/entities/statistics/model/statistics-interface';
|
||||
import { LoadingWithAnimation, Tabs, TabsContent, TabsList, TabsTrigger } from '@common/components';
|
||||
|
||||
import { getUserInfo } from '../../../../../../packages/common/components/src/api';
|
||||
|
||||
import SubmitDailog from './SubmitDailog';
|
||||
|
||||
import CancelSubmitButton from '@/components/button/CancelSubmitButton';
|
||||
import NotApplicableCheckButton from '@/components/button/NotApplicableCheckButton';
|
||||
import SaveButton from '@/components/button/SaveButton';
|
||||
import OperateDataButton from '@/components/button/OperateDataButton';
|
||||
import SubmitButton from '@/components/button/SumitButton';
|
||||
import UpdateOperateDataButton from '@/components/button/UpdateOperateDataButton';
|
||||
|
||||
import type { ColumnInfo, ColumnInfoList } from '@/components/type/DataGrid.type';
|
||||
import DataGrid from '@/components/module/DataGrid';
|
||||
import SearchForm from '@/components/module/SearchForm';
|
||||
import SplitDataGrid from '@/components/module/SplitDataGrid';
|
||||
import type { CellStyleCallbackParams, ColumnInfo, ColumnInfoList } from '@/components/type/DataGrid.type';
|
||||
import type { SearchFormValues } from '@/components/type/SearchForm.type';
|
||||
import { doList } from '@/components/util/column/input/DoList';
|
||||
import { PublicSewageFactInpColumnList } from '@/components/util/column/input/PublicSewageFactInpColumn/PublicSewageFactInpColumn';
|
||||
import { toGridRows } from '@/components/util/grid/gridFunction';
|
||||
import { useAdminStore } from '@/store/admin-store';
|
||||
|
||||
type TabToolbarSnapshot = {
|
||||
showSaveInToolbar: boolean;
|
||||
showEnterableToolbarButtons: boolean;
|
||||
showActionToolbarCard: boolean;
|
||||
};
|
||||
|
||||
function buildGugunOkForToolbar(values: SearchFormValues | null): boolean {
|
||||
return doList.includes(values?.bsnmCd || '')
|
||||
? Boolean(values?.gugun && values.gugun !== 'ALL')
|
||||
: true;
|
||||
}
|
||||
|
||||
const computeTabEnterable = (
|
||||
statusInfo: SewerageStatusInfo | null | undefined,
|
||||
periodEnterable: boolean,
|
||||
): boolean => {
|
||||
if (statusInfo?.laeSbmsnSttsCd) {
|
||||
if (['2', '3'].includes(statusInfo.laeSbmsnSttsCd)) {
|
||||
return false;
|
||||
}
|
||||
return periodEnterable;
|
||||
}
|
||||
return periodEnterable;
|
||||
};
|
||||
|
||||
function computeTabToolbarSnapshot(
|
||||
statusInfo: SewerageStatusInfo | null,
|
||||
hasRowData: boolean,
|
||||
treatAsSearched: boolean,
|
||||
searchContext: SearchFormValues | null,
|
||||
periodEnterable: boolean,
|
||||
isAdminInfo: boolean,
|
||||
): TabToolbarSnapshot {
|
||||
const gugunOk = buildGugunOkForToolbar(searchContext);
|
||||
const enterable = computeTabEnterable(statusInfo, periodEnterable);
|
||||
const showSaveInToolbar = (enterable || isAdminInfo) && gugunOk;
|
||||
const showEnterableToolbarButtons = enterable && gugunOk;
|
||||
const showActionToolbarCard =
|
||||
(hasRowData || treatAsSearched) &&
|
||||
(showSaveInToolbar ||
|
||||
(statusInfo?.laeSbmsnSttsCd === '2' &&
|
||||
(isAdminInfo || (enterable && gugunOk))));
|
||||
return { showSaveInToolbar, showEnterableToolbarButtons, showActionToolbarCard };
|
||||
}
|
||||
|
||||
const sleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms));
|
||||
|
||||
async function waitForImrJobCompleted(
|
||||
jobId: string,
|
||||
getStatus: (id: string) => Promise<ImrStatusResponse>,
|
||||
options?: {
|
||||
pollIntervalMs?: number;
|
||||
maxAttempts?: number;
|
||||
},
|
||||
): Promise<void> {
|
||||
const pollIntervalMs = options?.pollIntervalMs ?? 2000;
|
||||
const maxAttempts = options?.maxAttempts ?? 150;
|
||||
for (let i = 0; i < maxAttempts; i++) {
|
||||
const res = await getStatus(jobId);
|
||||
if (res.status === 'COMPLETED' && Number(res.job_prog) === 100) return;
|
||||
if (res.status === 'FAILED' || res.status === 'ERROR' || res.status === 'CANCELLED') {
|
||||
throw new Error(res.error_msg || `IMR 검증이 ${res.status} 상태로 종료되었습니다.`);
|
||||
}
|
||||
await sleep(pollIntervalMs);
|
||||
}
|
||||
throw new Error('IMR 검증 완료 대기 시간이 초과되었습니다.');
|
||||
}
|
||||
|
||||
// 하수도 통계 관리 > 06. 공공하수처리시설
|
||||
const PublicSewageFacilityInp = () => {
|
||||
|
||||
const { setMessage: alert } = useAlertStore((state) => state);
|
||||
const { confirm } = useConfirm();
|
||||
const { isAdminInfo } = useAdminStore();
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [hasSearched, setHasSearched] = useState(false);
|
||||
const [isNotApplicable, setIsNotApplicable] = useState(false);
|
||||
const [showIsNotApplicable, setShowIsNotApplicable] = useState(false);
|
||||
const [searchValues, setSearchValues] = useState<SearchFormValues | null>(null);
|
||||
const [lastSearchedValues, setLastSearchedValues] = useState<SearchFormValues | null>(null);
|
||||
const [tabStatusInfoMap, setTabStatusInfoMap] = useState<Map<string, SewerageStatusInfo | null>>(new Map());
|
||||
const [tabStatsCdMap, setTabStatsCdMap] = useState<Map<string, string>>(new Map());
|
||||
const [toolbarSnapshotByTab, setToolbarSnapshotByTab] = useState<Map<string, TabToolbarSnapshot>>(() => new Map());
|
||||
const [inputPeriodEnterable, setInputPeriodEnterable] = useState(true);
|
||||
const [periodCheckList, setPeriodCheckList] = useState<CheckInputPeriodItem[]>([]);
|
||||
const [showDailog, setShowDailog] = useState<boolean>(false);
|
||||
const [selectedMainFacilitySn, setSelectedMainFacilitySn] = useState<string | null>(null);
|
||||
|
||||
const periodEnterableRef = useRef(true);
|
||||
const searchDoneRef = useRef(false);
|
||||
|
||||
const submitFunc = () => {
|
||||
console.log('submit');
|
||||
// 제출 로직
|
||||
void (async () => {
|
||||
if (activeTab !== 'ST00060001') {
|
||||
alert('ST00060002 제출 API 연동 전입니다.');
|
||||
return;
|
||||
}
|
||||
if (!lastSearchedValues || !searchParamRef.current) {
|
||||
alert('먼저 조회를 진행해주세요.');
|
||||
return;
|
||||
}
|
||||
const currentData = rowDataMap.get('ST00060001') ?? [];
|
||||
if (!currentData || currentData.length === 0) {
|
||||
alert('제출할 데이터가 없습니다.');
|
||||
return;
|
||||
}
|
||||
const verificationBlocked = getVerificationPeriodActionBlockedMessage(periodCheckList);
|
||||
if (verificationBlocked) {
|
||||
alert(verificationBlocked);
|
||||
return;
|
||||
}
|
||||
if (await confirm('제출 하시겠습니까?')) {
|
||||
setShowDailog(true);
|
||||
}
|
||||
})();
|
||||
};
|
||||
|
||||
const buildFacilitySaveList = (currentData: Record<string, string | number>[]): PublicSewageFacilitySaveItem[] => {
|
||||
const toNumber = (v: unknown): number => {
|
||||
if (v === null || v === undefined) return 0;
|
||||
if (v === '') return 0;
|
||||
const num = typeof v === 'string' ? parseFloat(v.replace(/,/g, '')) : (v as number);
|
||||
return Number.isFinite(num) ? num : 0;
|
||||
};
|
||||
|
||||
const toNullableString = (v: unknown): string | null => {
|
||||
if (v === null || v === undefined) return null;
|
||||
const s = typeof v === 'string' ? v : String(v);
|
||||
return s.trim() === '' ? null : s;
|
||||
};
|
||||
|
||||
return currentData.map((d) => ({
|
||||
admdstCd: String(d.admdstCd ?? ''),
|
||||
admdstNm: String(d.admdstNm ?? ''),
|
||||
swtrmtFcltCd: String(d.swtrmtFcltCd ?? ''),
|
||||
swtrmtFcltNm: String(d.swtrmtFcltNm ?? ''),
|
||||
fcltSn: String(d.fcltSn ?? ''),
|
||||
fcltPstnCn: d.fcltPstnCn === '' ? null : toNullableString(d.fcltPstnCn),
|
||||
inflwSwagePhysQnt: toNumber(d.inflwSwagePhysQnt),
|
||||
inflwSwageBoilQnt: toNumber(d.inflwSwageBoilQnt),
|
||||
inflwSwageAltdQnt: toNumber(d.inflwSwageAltdQnt),
|
||||
prcsPhysCpct: toNumber(d.prcsPhysCpct),
|
||||
prcsBoilCpct: toNumber(d.prcsBoilCpct),
|
||||
prcsAltdCpct: toNumber(d.prcsAltdCpct),
|
||||
prxyCtrtCn: d.prxyCtrtCn === '' ? null : toNullableString(d.prxyCtrtCn),
|
||||
sftyAcdntEvntcsCnt: toNumber(d.sftyAcdntEvntcsCnt),
|
||||
rmrk: toNullableString(d.rmrk),
|
||||
}));
|
||||
};
|
||||
|
||||
const getNoApplicableForRequest = (): boolean => {
|
||||
const activeTabStatus = tabStatusInfoMap.get(activeTab) ?? null;
|
||||
const searchContextForToolbar = lastSearchedValues ?? searchValues;
|
||||
const gugunOk = buildGugunOkForToolbar(searchContextForToolbar);
|
||||
const enterable = computeTabEnterable(activeTabStatus, inputPeriodEnterable);
|
||||
const showEnterableToolbarButtons = enterable && gugunOk;
|
||||
const noApplicableVisible = showEnterableToolbarButtons && showIsNotApplicable;
|
||||
return noApplicableVisible ? Boolean(isNotApplicable) : false;
|
||||
};
|
||||
|
||||
const executeSubmit = async (submitInfo: StatisticsInputSubmitInfoFormData) => {
|
||||
const verificationBlocked = getVerificationPeriodActionBlockedMessage(periodCheckList);
|
||||
if (verificationBlocked) {
|
||||
alert(verificationBlocked);
|
||||
return;
|
||||
}
|
||||
if (activeTab !== 'ST00060001') {
|
||||
alert('ST00060002 제출 API 연동 전입니다.');
|
||||
return;
|
||||
}
|
||||
if (!lastSearchedValues || !searchParamRef.current) {
|
||||
alert('먼저 조회를 진행해주세요.');
|
||||
return;
|
||||
}
|
||||
const currentData = rowDataMap.get('ST00060001') ?? [];
|
||||
if (!currentData || currentData.length === 0) {
|
||||
alert('제출할 데이터가 없습니다.');
|
||||
return;
|
||||
}
|
||||
|
||||
const userInfo = await getUserInfo();
|
||||
const submitList = buildFacilitySaveList(currentData);
|
||||
const activeTabStatus = tabStatusInfoMap.get(activeTab) ?? null;
|
||||
const statsCdForTab = tabStatsCdMap.get(activeTab) ?? activeTab;
|
||||
const requestData = {
|
||||
statsYr: lastSearchedValues.year ?? '',
|
||||
ctpvNm: lastSearchedValues.sido ?? '',
|
||||
sggNm: lastSearchedValues.gugun === 'ALL' ? '' : lastSearchedValues.gugun ?? '',
|
||||
sewerBzmnCd: lastSearchedValues.bsnmCd ?? '',
|
||||
userId: userInfo.userUnqId,
|
||||
noApplicable: getNoApplicableForRequest(),
|
||||
laePicNm: submitInfo.laePicNm,
|
||||
laeKbrdrJbgdNm: submitInfo.laeKbrdrJbgdNm,
|
||||
laeKbrdrDeptNm: submitInfo.laeKbrdrDeptNm,
|
||||
laePicTelNo: submitInfo.laePicTelNo,
|
||||
laeIdfrNm: submitInfo.laeIdfrNm,
|
||||
laeIdfrJbgdNm: submitInfo.laeIdfrJbgdNm,
|
||||
laeIdfrDeptNm: submitInfo.laeIdfrDeptNm,
|
||||
laeIdfrTelNo: submitInfo.laeIdfrTelNo,
|
||||
submitList,
|
||||
};
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const response = await statisticsInputPublicSewageFacilityApiService.submitPublicSewageFacility(requestData);
|
||||
if (response.status === 'success') {
|
||||
if (response.data?.finalStatus === '5') {
|
||||
const imrParam = {
|
||||
user_id: userInfo.userUnqId,
|
||||
sewer_bzmn_cd: lastSearchedValues.bsnmCd ?? '',
|
||||
stats_cd: statsCdForTab,
|
||||
stats_yr: lastSearchedValues.year ?? '',
|
||||
lae_sbmsn_stts_cd: activeTabStatus?.laeSbmsnSttsCd === '4' ? '4' : '2',
|
||||
gen_verify_stts_cd: response.data?.nvpassed ? '1' : '2',
|
||||
};
|
||||
try {
|
||||
const imrResponse = await statisticsApi.callImrService(imrParam);
|
||||
if (imrResponse.job_id) {
|
||||
await waitForImrJobCompleted(
|
||||
imrResponse.job_id,
|
||||
(id) => statisticsApi.getImrStatus(id),
|
||||
);
|
||||
}
|
||||
alert('제출되었습니다.');
|
||||
} catch {
|
||||
alert('제출은 완료되었으나 IMR 검증 처리 중 오류가 발생했습니다.');
|
||||
}
|
||||
} else {
|
||||
alert(response.message || '제출 처리 결과를 확인해주세요.');
|
||||
}
|
||||
await loadPublicSewageFacilityActiveTabData(
|
||||
'ST00060001',
|
||||
searchParamRef.current,
|
||||
lastSearchedValues,
|
||||
);
|
||||
} else {
|
||||
alert(response.message || '데이터 제출 중 오류가 발생했습니다.');
|
||||
}
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const saveFunc = () => {
|
||||
console.log('save');
|
||||
// 저장 로직
|
||||
};
|
||||
void (async () => {
|
||||
if (activeTab !== 'ST00060001') {
|
||||
alert('ST00060002 저장 API 연동 전입니다.');
|
||||
return;
|
||||
}
|
||||
|
||||
const getOperateDataFunc = () => {
|
||||
console.log('get operate data');
|
||||
// 운영 데이터 가져오기
|
||||
if (!lastSearchedValues || !searchParamRef.current) {
|
||||
alert('먼저 조회를 진행해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
const currentData = rowDataMap.get('ST00060001') ?? [];
|
||||
if (!currentData || currentData.length === 0) {
|
||||
alert('저장할 데이터가 없습니다.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(await confirm("저장 하시겠습니까?"))) return;
|
||||
|
||||
const userInfo = await getUserInfo();
|
||||
const saveList = buildFacilitySaveList(currentData);
|
||||
|
||||
const param: PublicSewageFacilitySaveRequest = {
|
||||
statsYr: lastSearchedValues.year ?? '',
|
||||
ctpvNm: lastSearchedValues.sido ?? '',
|
||||
sggNm: lastSearchedValues.gugun === 'ALL' ? '' : lastSearchedValues.gugun ?? '',
|
||||
sewerBzmnCd: lastSearchedValues.bsnmCd ?? '',
|
||||
userId: userInfo.userUnqId,
|
||||
superAdmin: isAdminInfo ? 'superAdmin' : '',
|
||||
noApplicable: getNoApplicableForRequest(),
|
||||
saveList,
|
||||
};
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const response = await statisticsInputPublicSewageFacilityApiService.savePublicSewageFacility(param);
|
||||
if (response.status === 'success') {
|
||||
alert('저장되었습니다.');
|
||||
await loadPublicSewageFacilityActiveTabData(
|
||||
'ST00060001',
|
||||
searchParamRef.current,
|
||||
lastSearchedValues,
|
||||
);
|
||||
} else {
|
||||
alert(response.message || '데이터 저장 중 오류가 발생했습니다.');
|
||||
}
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
})();
|
||||
};
|
||||
|
||||
const updateOperateDataButtonFunc = () => {
|
||||
@@ -39,6 +344,276 @@ const PublicSewageFacilityInp = () => {
|
||||
const [activeTab, setActiveTab] = useState<string>(
|
||||
PublicSewageFactInpColumnList[0]?.tabKey ?? 'ST00060001',
|
||||
);
|
||||
const activeTabRef = useRef<string>(PublicSewageFactInpColumnList[0]?.tabKey ?? 'ST00060001');
|
||||
const firstTabKey = PublicSewageFactInpColumnList[0]?.tabKey ?? 'ST00060001';
|
||||
const searchParamRef = useRef<PublicSewageFacilityRequestParams | null>(null);
|
||||
|
||||
const commitToolbarSnapshotForLoadedTab = (
|
||||
tabKey: string,
|
||||
statusInfo: SewerageStatusInfo | null,
|
||||
hasRowData: boolean,
|
||||
searchContext: SearchFormValues | null,
|
||||
) => {
|
||||
setToolbarSnapshotByTab((prev) => {
|
||||
const next = new Map(prev);
|
||||
next.set(
|
||||
tabKey,
|
||||
computeTabToolbarSnapshot(
|
||||
statusInfo,
|
||||
hasRowData,
|
||||
searchDoneRef.current,
|
||||
searchContext,
|
||||
periodEnterableRef.current,
|
||||
isAdminInfo,
|
||||
),
|
||||
);
|
||||
return next;
|
||||
});
|
||||
};
|
||||
|
||||
const buildPublicSewageFacilityParams = (values: SearchFormValues): PublicSewageFacilityRequestParams => ({
|
||||
ctpvNm: values.sido,
|
||||
sggNm: values.gugun === 'ALL' ? '' : values.gugun,
|
||||
sewerBzmnCd: values.bsnmCd,
|
||||
fcltNm: values.fctName,
|
||||
statsYr: values.year,
|
||||
});
|
||||
|
||||
const tabRowDataExists = (tabKey: string): boolean => {
|
||||
if (tabKey === 'ST00060002') {
|
||||
const left = rowDataMap.get('MainFacility');
|
||||
const right = rowDataMap.get('MainFacilityTarget');
|
||||
return (left?.length ?? 0) > 0 || (right?.length ?? 0) > 0;
|
||||
}
|
||||
return (rowDataMap.get(tabKey)?.length ?? 0) > 0;
|
||||
};
|
||||
|
||||
const loadPublicSewageFacilityActiveTabData = async (
|
||||
tabKey: string,
|
||||
param: PublicSewageFacilityRequestParams,
|
||||
searchContext: SearchFormValues | null,
|
||||
): Promise<boolean> => {
|
||||
try {
|
||||
if (tabKey === 'ST00060001') {
|
||||
const response = await statisticsInputPublicSewageFacilityApiService.getPublicSewageFacility(param);
|
||||
if (response.status !== 'success') {
|
||||
alert(response.message || '데이터 조회 중 오류가 발생했습니다.');
|
||||
return false;
|
||||
}
|
||||
setSelectedMainFacilitySn(null);
|
||||
const statusInfo = response.data.statusInfo ?? null;
|
||||
const statsCd = response.data.commonInfo.statsCd || tabKey;
|
||||
const commonInfo = response.data.commonInfo;
|
||||
const list = response.data.publicSewageFacilityList ?? [];
|
||||
const convertedData = list.map((item) => ({
|
||||
ctpvNm: commonInfo.ctpvNm,
|
||||
...item,
|
||||
rmrk: item.rmrk ?? null,
|
||||
}));
|
||||
|
||||
if (list.length === 0) {
|
||||
setShowIsNotApplicable(true);
|
||||
} else {
|
||||
setShowIsNotApplicable(false);
|
||||
}
|
||||
|
||||
const gridRows = toGridRows(convertedData);
|
||||
setTabStatusInfoMap((prev) => {
|
||||
const next = new Map(prev);
|
||||
next.set(tabKey, statusInfo);
|
||||
return next;
|
||||
});
|
||||
setTabStatsCdMap((prev) => {
|
||||
const next = new Map(prev);
|
||||
next.set(tabKey, statsCd);
|
||||
return next;
|
||||
});
|
||||
setRowDataMap((prev) => {
|
||||
const next = new Map(prev);
|
||||
next.set('ST00060001', gridRows);
|
||||
return next;
|
||||
});
|
||||
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, gridRows.length > 0, searchContext);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (tabKey === 'ST00060002') {
|
||||
const response = await statisticsInputPublicSewageFacilityApiService.getPublicSewageMainFacility(param);
|
||||
if (response.status !== 'success') {
|
||||
alert(response.message || '데이터 조회 중 오류가 발생했습니다.');
|
||||
return false;
|
||||
}
|
||||
setSelectedMainFacilitySn(null);
|
||||
const statusInfo = response.data.statusInfo ?? null;
|
||||
const statsCd = response.data.commonInfo.statsCd || tabKey;
|
||||
const list = response.data.mainFacilityList ?? [];
|
||||
const leftRows = list.map((item) => ({
|
||||
swtrmtFcltNm: item.swtrmtFcltNm,
|
||||
fcltPstnCn: item.fcltPstnCn,
|
||||
prxyBzentyNmCn: item.prxyBzentyNmCn,
|
||||
cnsgnCstVl: item.cnsgnCstVl,
|
||||
prxyCtrtCn: item.prxyCtrtCn,
|
||||
wholNope: item.wholNope,
|
||||
isMainYn: item.isMainYn,
|
||||
admdstCd: item.admdstCd,
|
||||
fcltSn: item.fcltSn,
|
||||
swtrmtFcltCd: item.swtrmtFcltCd,
|
||||
sggNm: item.sggNm ?? '',
|
||||
admdstNm: item.admdstNm,
|
||||
}));
|
||||
const leftGridRows = toGridRows(leftRows);
|
||||
setTabStatusInfoMap((prev) => {
|
||||
const next = new Map(prev);
|
||||
next.set(tabKey, statusInfo);
|
||||
return next;
|
||||
});
|
||||
setTabStatsCdMap((prev) => {
|
||||
const next = new Map(prev);
|
||||
next.set(tabKey, statsCd);
|
||||
return next;
|
||||
});
|
||||
setRowDataMap((prev) => {
|
||||
const next = new Map(prev);
|
||||
next.set('MainFacility', leftGridRows);
|
||||
next.set('MainFacilityTarget', []);
|
||||
return next;
|
||||
});
|
||||
commitToolbarSnapshotForLoadedTab(tabKey, statusInfo, leftGridRows.length > 0, searchContext);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch {
|
||||
alert('데이터 조회 중 오류가 발생했습니다.');
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleSearch = async (values: SearchFormValues) => {
|
||||
if (!values.sido || values.sido === 'ALL') {
|
||||
alert('시도를 선택해주세요.');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const periodResponse = await statisticsInputSewSupplyRateApi.checkInputPeriod(values.year || '');
|
||||
if (periodResponse.status !== 'success') {
|
||||
alert(periodResponse.message);
|
||||
return;
|
||||
}
|
||||
const periods = Array.isArray(periodResponse.data) ? periodResponse.data : [];
|
||||
setPeriodCheckList(periods);
|
||||
const periodOk = isInputPeriodCurrent(periods);
|
||||
periodEnterableRef.current = periodOk;
|
||||
setInputPeriodEnterable(periodOk);
|
||||
|
||||
const yearChangedFromLastSearch =
|
||||
lastSearchedValues != null &&
|
||||
(lastSearchedValues.year ?? '') !== (values.year ?? '');
|
||||
|
||||
// 조회 시 이전 선택 로우 강조 초기화
|
||||
setSelectedMainFacilitySn(null);
|
||||
|
||||
if (yearChangedFromLastSearch) {
|
||||
setRowDataMap(new Map());
|
||||
setTabStatusInfoMap(new Map());
|
||||
setTabStatsCdMap(new Map());
|
||||
setToolbarSnapshotByTab(new Map());
|
||||
activeTabRef.current = firstTabKey;
|
||||
setActiveTab(firstTabKey);
|
||||
}
|
||||
|
||||
setLastSearchedValues(values);
|
||||
searchDoneRef.current = true;
|
||||
setHasSearched(true);
|
||||
|
||||
setIsLoading(true);
|
||||
const param = buildPublicSewageFacilityParams(values);
|
||||
searchParamRef.current = param;
|
||||
const tabKeyToLoad = yearChangedFromLastSearch ? firstTabKey : activeTabRef.current;
|
||||
await loadPublicSewageFacilityActiveTabData(tabKeyToLoad, param, values);
|
||||
} catch {
|
||||
alert('데이터 조회 중 오류가 발생했습니다.');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleActiveTabChange = async (tabKey: string) => {
|
||||
activeTabRef.current = tabKey;
|
||||
setActiveTab(tabKey);
|
||||
|
||||
if (!hasSearched || tabRowDataExists(tabKey) || !searchParamRef.current) return;
|
||||
try {
|
||||
setIsLoading(true);
|
||||
await loadPublicSewageFacilityActiveTabData(tabKey, searchParamRef.current, lastSearchedValues);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
setIsLoading(false);
|
||||
setHasSearched(false);
|
||||
setIsNotApplicable(false);
|
||||
setShowIsNotApplicable(false);
|
||||
|
||||
setRowDataMap(new Map());
|
||||
setTabStatusInfoMap(new Map());
|
||||
setTabStatsCdMap(new Map());
|
||||
setToolbarSnapshotByTab(new Map());
|
||||
|
||||
setInputPeriodEnterable(true);
|
||||
periodEnterableRef.current = true;
|
||||
setPeriodCheckList([]);
|
||||
|
||||
searchParamRef.current = null;
|
||||
searchDoneRef.current = false;
|
||||
|
||||
activeTabRef.current = firstTabKey;
|
||||
setActiveTab(firstTabKey);
|
||||
setLastSearchedValues(null);
|
||||
setSelectedMainFacilitySn(null);
|
||||
};
|
||||
|
||||
const cnacelSubmitFunc = async () => {
|
||||
try {
|
||||
if (await confirm('제출된 내용을 취소하시겠습니까?')) {
|
||||
const verificationBlocked = getVerificationPeriodActionBlockedMessage(periodCheckList);
|
||||
if (verificationBlocked) {
|
||||
alert(verificationBlocked);
|
||||
return;
|
||||
}
|
||||
|
||||
const userInfo = await getUserInfo();
|
||||
const statsCdForCancel = tabStatsCdMap.get(activeTab) ?? activeTab;
|
||||
const requestData: cancelSubmitRequest = {
|
||||
sewerBzmnCd: lastSearchedValues?.bsnmCd ?? '',
|
||||
ctpvNm: lastSearchedValues?.sido ?? '',
|
||||
sggNm: lastSearchedValues?.gugun ?? '',
|
||||
statsYr: lastSearchedValues?.year ?? '',
|
||||
mdfrId: userInfo.userUnqId,
|
||||
statsCd: statsCdForCancel,
|
||||
};
|
||||
|
||||
const response = await statisticsApi.cancelSubmit(requestData);
|
||||
|
||||
if (response.status === 'success') {
|
||||
if (searchParamRef.current) {
|
||||
await loadPublicSewageFacilityActiveTabData(
|
||||
activeTab,
|
||||
searchParamRef.current,
|
||||
lastSearchedValues,
|
||||
);
|
||||
}
|
||||
alert('제출 취소되었습니다.');
|
||||
} else {
|
||||
alert(response.message ?? '제출 취소 중 오류가 발생했습니다.');
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
alert('제출 취소 중 오류가 발생했습니다.');
|
||||
}
|
||||
};
|
||||
|
||||
const getGridColumnInfo = (
|
||||
tab: ColumnInfoList,
|
||||
@@ -47,25 +622,109 @@ const PublicSewageFacilityInp = () => {
|
||||
columnLayout: tab.columnLayout ?? [],
|
||||
});
|
||||
|
||||
const handleMainFacilityRowClick = async (rowData: Record<string, string | number>) => {
|
||||
if (!searchParamRef.current) {
|
||||
alert('먼저 조회를 진행해주세요.');
|
||||
return;
|
||||
}
|
||||
const fcltSn = String(rowData.fcltSn ?? '');
|
||||
if (!fcltSn) {
|
||||
alert('시설 일련번호가 없습니다.');
|
||||
return;
|
||||
}
|
||||
setSelectedMainFacilitySn(fcltSn);
|
||||
|
||||
const param: PublicSewageMappingTargetsRequestParams = {
|
||||
sewerBzmnCd: searchParamRef.current.sewerBzmnCd ?? '',
|
||||
ctpvNm: searchParamRef.current.ctpvNm ?? '',
|
||||
sggNm: searchParamRef.current.sggNm ?? '',
|
||||
statsYr: searchParamRef.current.statsYr ?? '',
|
||||
fcltSn,
|
||||
};
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const response = await statisticsInputPublicSewageFacilityApiService.getMappingTargets(param);
|
||||
if (response.status !== 'success') {
|
||||
alert(response.message || '매핑 대상 조회 중 오류가 발생했습니다.');
|
||||
return;
|
||||
}
|
||||
const mappedTargetRows = (response.data ?? []).map((item) => ({
|
||||
...item,
|
||||
__checked: item.mappedYn === 'Y' ? 'Y' : '',
|
||||
}));
|
||||
setRowDataMap((prev) => {
|
||||
const next = new Map(prev);
|
||||
next.set('MainFacilityTarget', toGridRows(mappedTargetRows));
|
||||
return next;
|
||||
});
|
||||
} catch {
|
||||
alert('매핑 대상 조회 중 오류가 발생했습니다.');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const leftMainFacilityCellStyleCallback = ({ row }: CellStyleCallbackParams) => {
|
||||
if (!selectedMainFacilitySn) return;
|
||||
return String(row.fcltSn ?? '') === selectedMainFacilitySn ? 'rg-cell-selected-row' : undefined;
|
||||
};
|
||||
|
||||
const searchContextForToolbar = lastSearchedValues ?? searchValues;
|
||||
const activeTabStatus = tabStatusInfoMap.get(activeTab) ?? null;
|
||||
const activeTabToolbar =
|
||||
toolbarSnapshotByTab.get(activeTab) ??
|
||||
computeTabToolbarSnapshot(
|
||||
activeTabStatus,
|
||||
tabRowDataExists(activeTab),
|
||||
hasSearched,
|
||||
searchContextForToolbar,
|
||||
inputPeriodEnterable,
|
||||
isAdminInfo,
|
||||
);
|
||||
const { showSaveInToolbar, showEnterableToolbarButtons, showActionToolbarCard } = activeTabToolbar;
|
||||
const isMainFacilityTab = activeTab === 'ST00060002';
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm fctName={true} />
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<UpdateOperateDataButton updateOperateDataButtonFunc={updateOperateDataButtonFunc} />
|
||||
<OperateDataButton getOperateDataFunc={getOperateDataFunc} />
|
||||
<SubmitButton submitFunc={submitFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
<div className="relative">
|
||||
<SearchForm
|
||||
fctName={true}
|
||||
onSubmit={handleSearch}
|
||||
onReset={handleReset}
|
||||
onValuesChange={setSearchValues}
|
||||
/>
|
||||
{showActionToolbarCard && (
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] mx-[0.6rem]">
|
||||
{showEnterableToolbarButtons && !isMainFacilityTab && (
|
||||
<>
|
||||
{showIsNotApplicable && <NotApplicableCheckButton isCheck={isNotApplicable} setIsCheck={setIsNotApplicable} />}
|
||||
<UpdateOperateDataButton updateOperateDataButtonFunc={updateOperateDataButtonFunc} />
|
||||
<SubmitButton submitFunc={submitFunc} />
|
||||
</>
|
||||
)}
|
||||
{!isMainFacilityTab && activeTabStatus?.laeSbmsnSttsCd === '2' && (
|
||||
<CancelSubmitButton cnacelSubmitFunc={cnacelSubmitFunc} />
|
||||
)}
|
||||
{showSaveInToolbar && <SaveButton saveFunc={saveFunc} />}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{isLoading && <div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
||||
<div className="relative size-[5rem]">
|
||||
<LoadingWithAnimation color="primary" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Tabs value={activeTab} onValueChange={setActiveTab}>
|
||||
<TabsList>
|
||||
{PublicSewageFactInpColumnList.map((tab) => (
|
||||
<TabsTrigger key={tab.tabKey} value={tab.tabKey}>
|
||||
{tab.tabLabel || tab.tabKey}
|
||||
</TabsTrigger>
|
||||
))}
|
||||
</TabsList>
|
||||
}
|
||||
<Tabs value={activeTab} onValueChange={(v) => void handleActiveTabChange(v)}>
|
||||
<TabsList>
|
||||
{PublicSewageFactInpColumnList.map((tab) => (
|
||||
<TabsTrigger key={tab.tabKey} value={tab.tabKey}>
|
||||
{tab.tabLabel || tab.tabKey}
|
||||
</TabsTrigger>
|
||||
))}
|
||||
</TabsList>
|
||||
|
||||
{PublicSewageFactInpColumnList.map((tab) => {
|
||||
if (tab.isSplitGrid && tab.left && tab.right) {
|
||||
@@ -78,10 +737,22 @@ const PublicSewageFacilityInp = () => {
|
||||
rightColumnInfo={getGridColumnInfo(tab.right)}
|
||||
leftFixedColumns={tab.left.fixedColumns}
|
||||
rightFixedColumns={tab.right.fixedColumns}
|
||||
showHeaderCheckbox={false}
|
||||
showHeaderCheckbox={true}
|
||||
enableSort={false}
|
||||
leftRowData={rowDataMap.get(leftKey) ?? []}
|
||||
rightRowData={rowDataMap.get(rightKey) ?? []}
|
||||
leftOnRowClick={
|
||||
tab.tabKey === 'ST00060002'
|
||||
? (row) => {
|
||||
void handleMainFacilityRowClick(row);
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
leftCellStyleCallback={
|
||||
tab.tabKey === 'ST00060002'
|
||||
? leftMainFacilityCellStyleCallback
|
||||
: undefined
|
||||
}
|
||||
setLeftRowData={(updater) => {
|
||||
setRowDataMap((prev) => {
|
||||
const next = new Map(prev);
|
||||
@@ -118,6 +789,7 @@ const PublicSewageFacilityInp = () => {
|
||||
columnInfo={gridColumnInfo}
|
||||
rowStartNum={tab.rowStartNum}
|
||||
fixedColumns={tab.fixedColumns}
|
||||
statusInfo={activeTabStatus}
|
||||
rowData={rowDataMap.get(tab.tabKey) ?? []}
|
||||
setRowData={(updater) => {
|
||||
setRowDataMap((prev) => {
|
||||
@@ -137,7 +809,16 @@ const PublicSewageFacilityInp = () => {
|
||||
</TabsContent>
|
||||
);
|
||||
})}
|
||||
</Tabs>
|
||||
</Tabs>
|
||||
</div>
|
||||
<SubmitDailog
|
||||
open={showDailog}
|
||||
onOpenChange={setShowDailog}
|
||||
statusInfo={activeTabStatus}
|
||||
onConfirm={executeSubmit}
|
||||
submitMode="normal"
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -28,13 +28,20 @@ import { doList } from "@/components/util/column/input/DoList";
|
||||
import { statisticsInputSewPipeApiService } from "@/entities/statistics/api/input/statistics-sewage-pipe-input-service";
|
||||
import type {
|
||||
SeweragePipeInputFactInstallStatusSaveRequest,
|
||||
SeweragePipeInputFactInstallStatusSubmitRequest,
|
||||
SeweragePipeInputManholeStatusItem,
|
||||
SeweragePipeInputManholeStatusSaveYearlyStatItem,
|
||||
SeweragePipeInputManholeStatusSaveRequest,
|
||||
SeweragePipeInputManholeStatusSubmitRequest,
|
||||
SeweragePipeInputPipeDiameterStatusSaveRequest,
|
||||
SeweragePipeInputPipeDiameterStatusSubmitRequest,
|
||||
SeweragePipeInputPipeTypeStatusItem,
|
||||
SeweragePipeInputPipeTypeStatusSaveRequest,
|
||||
SeweragePipeInputPipeTypeStatusSubmitRequest,
|
||||
SeweragePipeInputRegionalFactStatusSaveRequest,
|
||||
SeweragePipeInputRegionalFactStatusSaveItem,
|
||||
SeweragePipeInputRegionalFactStatusSubmitRequest,
|
||||
SeweragePipeInputSubmitResponse,
|
||||
SeweragePipeInputVerificationResult,
|
||||
SeweragePipeRequestParams,
|
||||
} from "@/entities/statistics/model/input/statistics-sewage-pipe-input-interface";
|
||||
@@ -903,6 +910,22 @@ const SewagePipeInp = () => {
|
||||
const userInfo = await getUserInfo();
|
||||
const statsCdForTab = tabStatsCdMap.get(tabKey) ?? statsCd;
|
||||
const statusForTab = tabStatusInfoMap.get(tabKey) ?? null;
|
||||
const submitBase = {
|
||||
statsYr: values.year ?? "",
|
||||
ctpvNm: values.sido ?? "",
|
||||
sggNm: values.gugun === "ALL" ? "" : (values.gugun ?? ""),
|
||||
sewerBzmnCd: values.bsnmCd ?? "",
|
||||
userId: userInfo.userUnqId,
|
||||
laePicNm: submitInfo.laePicNm,
|
||||
laeKbrdrJbgdNm: submitInfo.laeKbrdrJbgdNm,
|
||||
laeKbrdrDeptNm: submitInfo.laeKbrdrDeptNm,
|
||||
laePicTelNo: submitInfo.laePicTelNo,
|
||||
laeIdfrNm: submitInfo.laeIdfrNm,
|
||||
laeIdfrJbgdNm: submitInfo.laeIdfrJbgdNm,
|
||||
laeIdfrDeptNm: submitInfo.laeIdfrDeptNm,
|
||||
laeIdfrTelNo: submitInfo.laeIdfrTelNo,
|
||||
};
|
||||
let response: SeweragePipeInputSubmitResponse | null = null;
|
||||
|
||||
switch (tabKey) {
|
||||
case REGIONAL_FACT_TAB_KEY: {
|
||||
@@ -914,97 +937,294 @@ const SewagePipeInp = () => {
|
||||
|
||||
const submitList = buildRegionalFactSubmitListFromGrid(currentData);
|
||||
|
||||
const requestData = {
|
||||
statsYr: values.year ?? "",
|
||||
ctpvNm: values.sido ?? "",
|
||||
sggNm: values.gugun === "ALL" ? "" : (values.gugun ?? ""),
|
||||
sewerBzmnCd: values.bsnmCd ?? "",
|
||||
userId: userInfo.userUnqId,
|
||||
const requestData: SeweragePipeInputRegionalFactStatusSubmitRequest = {
|
||||
...submitBase,
|
||||
submitList,
|
||||
laePicNm: submitInfo.laePicNm,
|
||||
laeKbrdrJbgdNm: submitInfo.laeKbrdrJbgdNm,
|
||||
laeKbrdrDeptNm: submitInfo.laeKbrdrDeptNm,
|
||||
laePicTelNo: submitInfo.laePicTelNo,
|
||||
laeIdfrNm: submitInfo.laeIdfrNm,
|
||||
laeIdfrJbgdNm: submitInfo.laeIdfrJbgdNm,
|
||||
laeIdfrDeptNm: submitInfo.laeIdfrDeptNm,
|
||||
laeIdfrTelNo: submitInfo.laeIdfrTelNo,
|
||||
};
|
||||
|
||||
setGlobalProgressLabel("일반 검증 진행 중...");
|
||||
const response =
|
||||
response =
|
||||
await statisticsInputSewPipeApiService.submitRegionalFactStatus(requestData);
|
||||
if (response.status !== "success") {
|
||||
alert(response.message || "데이터 제출 중 오류가 발생했습니다.");
|
||||
break;
|
||||
}
|
||||
case "ST00020002": {
|
||||
const currentData = getFactInstallGridDataRef.current?.();
|
||||
if (!currentData || currentData.length === 0) {
|
||||
alert("제출할 데이터가 없습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
const finalStatus = response.data?.finalStatus;
|
||||
const nvpassed = response.data?.nvpassed;
|
||||
|
||||
if (finalStatus === "5") {
|
||||
setGlobalProgress(50);
|
||||
setGlobalProgressLabel("IMR 검증 진행 중...");
|
||||
const imrParam = {
|
||||
user_id: userInfo.userUnqId,
|
||||
sewer_bzmn_cd: values.bsnmCd ?? "",
|
||||
stats_cd: statsCdForTab,
|
||||
stats_yr: values.year ?? "",
|
||||
lae_sbmsn_stts_cd: statusForTab?.laeSbmsnSttsCd === "4" ? "4" : "2",
|
||||
gen_verify_stts_cd: nvpassed ? "1" : "2",
|
||||
};
|
||||
|
||||
try {
|
||||
const imrResponse = await statisticsApi.callImrService(imrParam);
|
||||
if (imrResponse.job_id) {
|
||||
await waitForImrJobCompleted(
|
||||
imrResponse.job_id,
|
||||
(id) => statisticsApi.getImrStatus(id),
|
||||
{
|
||||
onProgress: (jobProgress) => {
|
||||
setGlobalProgress(50 + Math.round(jobProgress / 2));
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
setGlobalProgress(100);
|
||||
await loadSewagePipeActiveTabData(
|
||||
tabKey,
|
||||
buildSewagePipeSearchParam(values),
|
||||
values,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
setVerificationResultDialogOpen(true);
|
||||
} catch (e) {
|
||||
await loadSewagePipeActiveTabData(
|
||||
tabKey,
|
||||
buildSewagePipeSearchParam(values),
|
||||
values,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
const msg =
|
||||
e instanceof Error && e.message
|
||||
? e.message
|
||||
: "IMR 검증 중 오류가 발생했습니다.\n관리자에게 문의하세요.";
|
||||
alert(msg);
|
||||
}
|
||||
} else {
|
||||
setGlobalProgress(100);
|
||||
await loadSewagePipeActiveTabData(
|
||||
tabKey,
|
||||
buildSewagePipeSearchParam(values),
|
||||
values,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
alert("제출되었습니다.");
|
||||
const columnFormatMap = new Map<string, string>();
|
||||
FactInstallStatusInpColumn.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 submitList = currentData.map((d) => ({
|
||||
admdstCd: String(d.admdstCd ?? ""),
|
||||
sggNm: String(d.sggNm ?? ""),
|
||||
admdstNm: String(d.admdstNm ?? ""),
|
||||
fcltSn: String(d.fcltSn ?? ""),
|
||||
swtrmtFcltCd: String(d.swtrmtFcltCd ?? ""),
|
||||
swtrmtFcltNm: String(d.swtrmtFcltNm ?? ""),
|
||||
prcsFcltCpct: formatNumber(d.prcsFcltCpct, "prcsFcltCpct"),
|
||||
prcsZoneArea: formatNumber(d.prcsZoneArea, "prcsZoneArea"),
|
||||
cbsysPrcsZoneArea: formatNumber(d.cbsysPrcsZoneArea, "cbsysPrcsZoneArea"),
|
||||
sprsysPrcsZoneArea: formatNumber(d.sprsysPrcsZoneArea, "sprsysPrcsZoneArea"),
|
||||
sprsysVartnRt: formatNumber(d.sprsysVartnRt, "sprsysVartnRt"),
|
||||
mltvEqpmCnt: formatNumber(d.mltvEqpmCnt, "mltvEqpmCnt"),
|
||||
cbsysMltvEqpmCnt: formatNumber(d.cbsysMltvEqpmCnt, "cbsysMltvEqpmCnt"),
|
||||
sprsysMltvEqpmCnt: formatNumber(d.sprsysMltvEqpmCnt, "sprsysMltvEqpmCnt"),
|
||||
sprsysMltvLnkgCnt: formatNumber(d.sprsysMltvLnkgCnt, "sprsysMltvLnkgCnt"),
|
||||
sprsysMltvYetLnkgCnt: formatNumber(d.sprsysMltvYetLnkgCnt, "sprsysMltvYetLnkgCnt"),
|
||||
wholFcltPrlg: formatNumber(d.wholFcltPrlg, "wholFcltPrlg"),
|
||||
wholIcptgAtlfcsPrlg: formatNumber(d.wholIcptgAtlfcsPrlg, "wholIcptgAtlfcsPrlg"),
|
||||
icptgPrlg: formatNumber(d.icptgPrlg, "icptgPrlg"),
|
||||
atlfcsPrlg: formatNumber(d.atlfcsPrlg, "atlfcsPrlg"),
|
||||
cbsysStofcbrCnt: formatNumber(d.cbsysStofcbrCnt, "cbsysStofcbrCnt"),
|
||||
sprsysStofcbrCnt: formatNumber(d.sprsysStofcbrCnt, "sprsysStofcbrCnt"),
|
||||
sprsysExlnOtflCnt: formatNumber(d.sprsysExlnOtflCnt, "sprsysExlnOtflCnt"),
|
||||
wholBrchlnPrlg: formatNumber(d.wholBrchlnPrlg, "wholBrchlnPrlg"),
|
||||
cbsysBrchlnPrlg: formatNumber(d.cbsysBrchlnPrlg, "cbsysBrchlnPrlg"),
|
||||
exlnBrchlnPrlg: formatNumber(d.exlnBrchlnPrlg, "exlnBrchlnPrlg"),
|
||||
drtwBrchlnPrlg: formatNumber(d.drtwBrchlnPrlg, "drtwBrchlnPrlg"),
|
||||
rmrk: String(d.rmrk ?? ""),
|
||||
}));
|
||||
const requestData: SeweragePipeInputFactInstallStatusSubmitRequest = {
|
||||
...submitBase,
|
||||
submitList,
|
||||
};
|
||||
setGlobalProgressLabel("일반 검증 진행 중...");
|
||||
response = await statisticsInputSewPipeApiService.submitFactInstallStatus(requestData);
|
||||
break;
|
||||
}
|
||||
case "ST00020003": {
|
||||
const currentData = getPipeTypeGridDataRef.current?.();
|
||||
if (!currentData || currentData.length === 0) {
|
||||
alert("제출할 데이터가 없습니다.");
|
||||
return;
|
||||
}
|
||||
const columnFormatMap = new Map<string, string>();
|
||||
PipeTypeStatusInpColumn.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 lastDataYear = getPipeTypeLastDataYear();
|
||||
const submitList = currentData.map((d) => {
|
||||
const yearlyStatList = [];
|
||||
for (let year = 1995; year <= lastDataYear; year++) {
|
||||
const wholKey = `y${year}PrlgWhol`;
|
||||
const lyngKey = `y${year}LyngPrlg`;
|
||||
const dmltnKey = `y${year}DmltnPrlg`;
|
||||
yearlyStatList.push({
|
||||
lyngYr: String(year),
|
||||
lyngPrlg: formatNumber(d[lyngKey] as string | number | undefined, lyngKey),
|
||||
dmltnPrlg: formatNumber(d[dmltnKey] as string | number | undefined, dmltnKey),
|
||||
prlgWhol: formatNumber(d[wholKey] as string | number | undefined, wholKey),
|
||||
});
|
||||
}
|
||||
return {
|
||||
admdstCd: String(d.admdstCd ?? ""),
|
||||
admdstNm: String(d.admdstNm ?? ""),
|
||||
pipeSeCd: String(d.pipeSeCd ?? ""),
|
||||
yearlyStatList,
|
||||
rmrk: String(d.rmrk ?? ""),
|
||||
lyngPrlgWhol: formatNumber(d.lyngPrlg, "lyngPrlg"),
|
||||
dmltnPrlgWhol: formatNumber(d.dmltnPrlg, "dmltnPrlg"),
|
||||
pipeByPrstWhol: formatNumber(d.pipeByPrstWhol, "pipeByPrstWhol"),
|
||||
};
|
||||
});
|
||||
const requestData: SeweragePipeInputPipeTypeStatusSubmitRequest = {
|
||||
...submitBase,
|
||||
submitList,
|
||||
};
|
||||
setGlobalProgressLabel("일반 검증 진행 중...");
|
||||
response = await statisticsInputSewPipeApiService.submitPipeTypeStatus(requestData);
|
||||
break;
|
||||
}
|
||||
case "ST00020004": {
|
||||
const currentData = getPipeDiameterGridDataRef.current?.();
|
||||
if (!currentData || currentData.length === 0) {
|
||||
alert("제출할 데이터가 없습니다.");
|
||||
return;
|
||||
}
|
||||
const columnFormatMap = new Map<string, string>();
|
||||
PipeDiameterStatusInpColumn.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 submitList = currentData.map((d) => ({
|
||||
pipeSeCd: String(d.pipeSeCd ?? ""),
|
||||
step1PdmtPrlg: formatNumber(d.step1PdmtPrlg, "step1PdmtPrlg"),
|
||||
step2PdmtPrlg: formatNumber(d.step2PdmtPrlg, "step2PdmtPrlg"),
|
||||
step3PdmtPrlg: formatNumber(d.step3PdmtPrlg, "step3PdmtPrlg"),
|
||||
step4PdmtPrlg: formatNumber(d.step4PdmtPrlg, "step4PdmtPrlg"),
|
||||
step5PdmtPrlg: formatNumber(d.step5PdmtPrlg, "step5PdmtPrlg"),
|
||||
sqrePdmtPrlg: formatNumber(d.sqrePdmtPrlg, "sqrePdmtPrlg"),
|
||||
etcPdmtPrlg: formatNumber(d.etcPdmtPrlg, "etcPdmtPrlg"),
|
||||
rmrk: String(d.rmrk ?? ""),
|
||||
pdmtByTsmWhol: formatNumber(d.pdmtByTsmWhol, "pdmtByTsmWhol"),
|
||||
admdstCd: String(d.admdstCd ?? ""),
|
||||
admdstNm: String(d.admdstNm ?? ""),
|
||||
}));
|
||||
const requestData: SeweragePipeInputPipeDiameterStatusSubmitRequest = {
|
||||
...submitBase,
|
||||
submitList,
|
||||
};
|
||||
setGlobalProgressLabel("일반 검증 진행 중...");
|
||||
response = await statisticsInputSewPipeApiService.submitPipeDiameterStatus(requestData);
|
||||
break;
|
||||
}
|
||||
case "ST00020005": {
|
||||
const currentData = getManholeGridDataRef.current?.();
|
||||
if (!currentData || currentData.length === 0) {
|
||||
alert("제출할 데이터가 없습니다.");
|
||||
return;
|
||||
}
|
||||
const columnFormatMap = new Map<string, string>();
|
||||
ManholeStatusInpColumn.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 minYy = 14;
|
||||
const maxYy = getManholeLastDataYear() % 100;
|
||||
const submitList = currentData.map((d) => {
|
||||
const yearlyStats: SeweragePipeInputManholeStatusSaveYearlyStatItem[] = [];
|
||||
for (let yy = minYy; yy <= maxYy; yy++) {
|
||||
const year = 2000 + yy;
|
||||
const wholKey = `yy${yy}WholMnhlCnt`;
|
||||
const step1Key = `yy${yy}Step1MnhlCnt`;
|
||||
const step2Key = `yy${yy}Step2MnhlCnt`;
|
||||
const step3Key = `yy${yy}Step3MnhlCnt`;
|
||||
const step4Key = `yy${yy}Step4MnhlCnt`;
|
||||
const step5Key = `yy${yy}Step5MnhlCnt`;
|
||||
yearlyStats.push({
|
||||
manhYr: String(year),
|
||||
wholMnhlCnt: formatNumber(d[wholKey] as string | number | undefined, wholKey),
|
||||
step1MnhlCnt: formatNumber(d[step1Key] as string | number | undefined, step1Key),
|
||||
step2MnhlCnt: formatNumber(d[step2Key] as string | number | undefined, step2Key),
|
||||
step3MnhlCnt: formatNumber(d[step3Key] as string | number | undefined, step3Key),
|
||||
step4MnhlCnt: formatNumber(d[step4Key] as string | number | undefined, step4Key),
|
||||
step5MnhlCnt: formatNumber(d[step5Key] as string | number | undefined, step5Key),
|
||||
});
|
||||
}
|
||||
return {
|
||||
emphsMngSeCd: String(d.emphsMngSeCd ?? ""),
|
||||
admdstCd: String(d.admdstCd ?? ""),
|
||||
admdstNm: String(d.admdstNm ?? ""),
|
||||
yearlyStats,
|
||||
rmrk: String(d.rmrk ?? ""),
|
||||
};
|
||||
});
|
||||
const requestData: SeweragePipeInputManholeStatusSubmitRequest = {
|
||||
...submitBase,
|
||||
submitList,
|
||||
};
|
||||
setGlobalProgressLabel("일반 검증 진행 중...");
|
||||
response = await statisticsInputSewPipeApiService.submitManholeStatus(requestData);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
alert("해당 탭 제출 API는 준비 중입니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!response || response.status !== "success") {
|
||||
alert(response?.message || "데이터 제출 중 오류가 발생했습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
const finalStatus = response.data?.finalStatus;
|
||||
const nvpassed = response.data?.nvpassed;
|
||||
|
||||
if (finalStatus === "5") {
|
||||
setGlobalProgress(50);
|
||||
setGlobalProgressLabel("IMR 검증 진행 중...");
|
||||
const imrParam = {
|
||||
user_id: userInfo.userUnqId,
|
||||
sewer_bzmn_cd: values.bsnmCd ?? "",
|
||||
stats_cd: statsCdForTab,
|
||||
stats_yr: values.year ?? "",
|
||||
lae_sbmsn_stts_cd: statusForTab?.laeSbmsnSttsCd === "4" ? "4" : "2",
|
||||
gen_verify_stts_cd: nvpassed ? "1" : "2",
|
||||
};
|
||||
|
||||
try {
|
||||
const imrResponse = await statisticsApi.callImrService(imrParam);
|
||||
if (imrResponse.job_id) {
|
||||
await waitForImrJobCompleted(
|
||||
imrResponse.job_id,
|
||||
(id) => statisticsApi.getImrStatus(id),
|
||||
{
|
||||
onProgress: (jobProgress) => {
|
||||
setGlobalProgress(50 + Math.round(jobProgress / 2));
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
setGlobalProgress(100);
|
||||
await loadSewagePipeActiveTabData(
|
||||
tabKey,
|
||||
buildSewagePipeSearchParam(values),
|
||||
values,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
setVerificationResultDialogOpen(true);
|
||||
} catch (e) {
|
||||
await loadSewagePipeActiveTabData(
|
||||
tabKey,
|
||||
buildSewagePipeSearchParam(values),
|
||||
values,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
const msg =
|
||||
e instanceof Error && e.message
|
||||
? e.message
|
||||
: "IMR 검증 중 오류가 발생했습니다.\n관리자에게 문의하세요.";
|
||||
alert(msg);
|
||||
}
|
||||
} else {
|
||||
setGlobalProgress(100);
|
||||
await loadSewagePipeActiveTabData(
|
||||
tabKey,
|
||||
buildSewagePipeSearchParam(values),
|
||||
values,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
alert("제출되었습니다.");
|
||||
}
|
||||
} catch {
|
||||
alert("데이터 제출 중 오류가 발생했습니다.");
|
||||
@@ -1537,7 +1757,7 @@ const SewagePipeInp = () => {
|
||||
/>
|
||||
{showEnterableToolbarButtons && (
|
||||
<>
|
||||
<LastYearDataButton getLastYearDataFunc={() => void getLastYearDataFunc()} />
|
||||
{activeTab !== 'ST00020002' && <LastYearDataButton getLastYearDataFunc={() => void getLastYearDataFunc()} />}
|
||||
<SubmitButton submitFunc={() => void submitFunc(false)} />
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -295,9 +295,9 @@ const SeweragePenetrationRateInp = () => {
|
||||
statsCd: statsCd,
|
||||
};
|
||||
|
||||
// if (isAdminInfo) {
|
||||
// params.superAdmin = 'superAdmin';
|
||||
// }
|
||||
if (isAdminInfo) {
|
||||
params.superAdmin = 'superAdmin';
|
||||
}
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
import { useMemo, useState } from "react";
|
||||
|
||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import {
|
||||
type ColumnDef,
|
||||
getCoreRowModel,
|
||||
type RowSelectionState,
|
||||
useReactTable,
|
||||
@@ -14,17 +12,21 @@ import {
|
||||
import { client } from "@/shared/api/client";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import { useAlertStore } from "@/shared/lib";
|
||||
import type { PageableList } from "@/shared/model";
|
||||
import {
|
||||
type AdstZoneResponseDto,
|
||||
type BusinessSendRequest,
|
||||
type BusinessSendResponse,
|
||||
type SelectedRecipient,
|
||||
type SewerStUserItem,
|
||||
useNtftalkTemplateList,
|
||||
useNtftalkTemplateVariables,
|
||||
userListColumns,
|
||||
useSewerStUserList,
|
||||
useStAnlsSidoCombo,
|
||||
useStAnlsSigunguCombo,
|
||||
} from "@/entities/statistics";
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
DataTable,
|
||||
Dialog,
|
||||
DialogClose,
|
||||
@@ -49,35 +51,6 @@ import {
|
||||
TableRow,
|
||||
} from "@common/components";
|
||||
|
||||
interface NtftalkTemplate {
|
||||
templateCode: string;
|
||||
templateName: string;
|
||||
templateContent: string;
|
||||
}
|
||||
|
||||
interface TemplateVariablesResponse {
|
||||
templateCode: string;
|
||||
variables: string[];
|
||||
count: number;
|
||||
}
|
||||
|
||||
interface BusinessSendRequest {
|
||||
templateCode: string;
|
||||
callback?: string;
|
||||
fixedRecipientNum?: string;
|
||||
recipients: Record<string, string>[];
|
||||
}
|
||||
|
||||
interface BusinessSendResponse {
|
||||
success: boolean;
|
||||
sentCount: number;
|
||||
message: string;
|
||||
}
|
||||
|
||||
interface SelectedRecipient extends SewerStUserItem {
|
||||
variableOverrides: Record<string, string>;
|
||||
}
|
||||
|
||||
type CommonVariableKey =
|
||||
| "userNm"
|
||||
| "sido"
|
||||
@@ -94,14 +67,6 @@ const GUBUN_OPTIONS = [
|
||||
{ value: "IDFR", label: "승인자" },
|
||||
{ value: "MCTPV", label: "검토자" },
|
||||
] as const;
|
||||
const DEFAULT_TEMPLATE_PARAMS = {
|
||||
sort: "createdAt,desc",
|
||||
senderKey: "",
|
||||
inspectionStatus: "APR",
|
||||
templateMessageType: "BA",
|
||||
page: 0,
|
||||
size: 10,
|
||||
};
|
||||
|
||||
function getDefaultStatsYear(): string {
|
||||
return String(new Date().getFullYear() - 1);
|
||||
@@ -161,38 +126,11 @@ function NtitlkSndng() {
|
||||
const [userListRowSelection, setUserListRowSelection] =
|
||||
useState<RowSelectionState>({});
|
||||
|
||||
const { data: templatePageData } = useQuery({
|
||||
queryKey: [
|
||||
ENDPOINT.NTFTALK_SERVICE.TEMP,
|
||||
"ntitlk-sndng",
|
||||
DEFAULT_TEMPLATE_PARAMS,
|
||||
],
|
||||
queryFn: async () => {
|
||||
const response = await client.get<PageableList<NtftalkTemplate>>(
|
||||
ENDPOINT.NTFTALK_SERVICE.TEMP,
|
||||
{ params: DEFAULT_TEMPLATE_PARAMS },
|
||||
);
|
||||
return response.data;
|
||||
},
|
||||
});
|
||||
|
||||
const { data: templatePageData } = useNtftalkTemplateList();
|
||||
const templates = templatePageData?.content ?? [];
|
||||
|
||||
const { data: templateVariablesData } = useQuery({
|
||||
queryKey: [
|
||||
ENDPOINT.NTFTALK_SERVICE.ATA_SEND,
|
||||
"template-variables",
|
||||
selectedTemplateCode,
|
||||
],
|
||||
queryFn: async () => {
|
||||
const response = await client.get<TemplateVariablesResponse>(
|
||||
`${ENDPOINT.NTFTALK_SERVICE.ATA_SEND}/template-variables/${selectedTemplateCode}`,
|
||||
);
|
||||
return response.data;
|
||||
},
|
||||
enabled: Boolean(selectedTemplateCode),
|
||||
});
|
||||
|
||||
const { data: templateVariablesData } =
|
||||
useNtftalkTemplateVariables(selectedTemplateCode);
|
||||
const variableNames = templateVariablesData?.variables ?? [];
|
||||
|
||||
const { data: sidoData } = useStAnlsSidoCombo();
|
||||
@@ -203,80 +141,6 @@ function NtitlkSndng() {
|
||||
const { data: userListResponse, isLoading: isUserListLoading } =
|
||||
useSewerStUserList(appliedParams);
|
||||
const userList = (userListResponse as unknown as SewerStUserItem[]) ?? [];
|
||||
const userListColumns = useMemo<ColumnDef<SewerStUserItem>[]>(
|
||||
() => [
|
||||
{
|
||||
id: "select",
|
||||
header: ({ table }) => (
|
||||
<div
|
||||
className="flex justify-center"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onKeyDown={(e) => e.stopPropagation()}
|
||||
role="presentation"
|
||||
>
|
||||
<Checkbox
|
||||
checked={
|
||||
table.getIsAllPageRowsSelected() ||
|
||||
(table.getIsSomePageRowsSelected() &&
|
||||
"indeterminate")
|
||||
}
|
||||
onCheckedChange={(value) =>
|
||||
table.toggleAllPageRowsSelected(!!value)
|
||||
}
|
||||
aria-label="전체 선택"
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
cell: ({ row }) => (
|
||||
<div
|
||||
className="flex justify-center"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onKeyDown={(e) => e.stopPropagation()}
|
||||
role="presentation"
|
||||
>
|
||||
<Checkbox
|
||||
checked={row.getIsSelected()}
|
||||
onCheckedChange={(value) =>
|
||||
row.toggleSelected(!!value)
|
||||
}
|
||||
aria-label="행 선택"
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
enableSorting: false,
|
||||
enableHiding: false,
|
||||
},
|
||||
{
|
||||
accessorKey: "userNm",
|
||||
header: "이름",
|
||||
},
|
||||
{
|
||||
accessorKey: "sido",
|
||||
header: "시도",
|
||||
},
|
||||
{
|
||||
accessorKey: "gugun",
|
||||
header: "시군구",
|
||||
},
|
||||
{
|
||||
accessorKey: "gubunNm",
|
||||
header: "구분",
|
||||
},
|
||||
{
|
||||
accessorKey: "deptNm",
|
||||
header: "소속",
|
||||
},
|
||||
{
|
||||
accessorKey: "jbgdNm",
|
||||
header: "직급",
|
||||
},
|
||||
{
|
||||
accessorKey: "telNo",
|
||||
header: "전화번호",
|
||||
},
|
||||
],
|
||||
[],
|
||||
);
|
||||
const userListTable = useReactTable({
|
||||
data: userList,
|
||||
columns: userListColumns,
|
||||
|
||||
@@ -11,16 +11,21 @@ import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||
import { SewagePipeColumnInfoListTot } from "@/components/util/column/total/SewagePipeTotColumn";
|
||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||
import type { SewagePipeTotalRequest } from "@/entities/statistics/model/statistics-total/statistics-sewage-pipe-total-interface";
|
||||
import CellColorInfo from "./CellColorInfo";
|
||||
|
||||
const firstTabKey = SewagePipeColumnInfoListTot[0]?.tabKey ?? "ST00020001";
|
||||
|
||||
function buildSewagePipeTotSearchParam(values: SearchFormValues): SewagePipeTotalRequest {
|
||||
const isSummaryEnabled = values.isSummary !== 'ALL';
|
||||
const summaryYearCnt = isSummaryEnabled ? Number(values.isSummary) : undefined;
|
||||
|
||||
return {
|
||||
ctpvNm: values.sido === "ALL" ? "" : values.sido,
|
||||
sggNm: values.gugun === "ALL" ? "" : values.gugun,
|
||||
sewerBzmnCd: values.bsnmCd,
|
||||
statsYr: values.year,
|
||||
rowDataYn: values.isDetail,
|
||||
...(isSummaryEnabled ? { summaryYearCnt } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -164,7 +169,7 @@ const SewagePipeTot = () => {
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<SearchForm isDetail={true} onSubmit={handleSearch} onReset={handleReset} sidoSelectText="전체" />
|
||||
<SearchForm isDetail={true} isSummary={true} onSubmit={handleSearch} onReset={handleReset} sidoSelectText="전체" />
|
||||
{isLoading && (
|
||||
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
||||
<div className="relative size-[5rem]">
|
||||
@@ -172,6 +177,7 @@ const SewagePipeTot = () => {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<CellColorInfo />
|
||||
<div className="flex flex-col gap-[0.6rem] mx-[0.6rem]">
|
||||
<Tabs
|
||||
value={activeTab}
|
||||
@@ -221,10 +227,11 @@ const SewagePipeTot = () => {
|
||||
fixedColumns={info.fixedColumns}
|
||||
enableSort={false}
|
||||
cellStyleCallback={({ row }) => {
|
||||
const rowType = String(row.rowType ?? "");
|
||||
if (rowType === "DETAIL") return undefined;
|
||||
if (rowType === "BIZ_SUM") return "rg-cell-rowtype-biz-sum";
|
||||
return "rg-cell-rowtype-other";
|
||||
const rowType = String(row.rowType ?? '');
|
||||
if (rowType === 'DETAIL') return undefined;
|
||||
if (rowType === 'BIZ_SUM') return 'rg-cell-rowtype-biz-sum';
|
||||
if (rowType === 'SUMMARY') return 'rg-cell-rowtype-summary';
|
||||
return 'rg-cell-rowtype-other';
|
||||
}}
|
||||
/>
|
||||
</TabsContent>
|
||||
|
||||
@@ -20,18 +20,18 @@ import { ENDPOINT } from "@/shared/config";
|
||||
import { useAlertStore } from "@/shared/lib";
|
||||
import type { ApiErrorResponse } from "@/shared/model";
|
||||
import { CodeSelect } from "@/entities/code";
|
||||
import type {
|
||||
AnalysisRequestPayload,
|
||||
AnalysisResponseDto,
|
||||
StAnlsMstResponse,
|
||||
StAnlsMstSearchParams,
|
||||
StAnlsOutlierListResponse,
|
||||
import {
|
||||
analysisApi,
|
||||
type AnalysisRequestPayload,
|
||||
type AnalysisResponseDto,
|
||||
type StAnlsMstResponse,
|
||||
type StAnlsMstSearchParams,
|
||||
type StAnlsOutlierListResponse,
|
||||
statisticsAnalysisMasterService,
|
||||
verificationHistoryColumns,
|
||||
type VerificationTargetCodeResponse,
|
||||
verificationTargetManagementApi,
|
||||
} from "@/entities/statistics";
|
||||
import { verificationHistoryColumns } from "@/entities/statistics";
|
||||
import { analysisApi } from "@/entities/statistics/api/analysis-api";
|
||||
import { stAnlsMstApi } from "@/entities/statistics/api/statistics-analysis-master-api";
|
||||
import { verificationTargetManagementApi } from "@/entities/statistics/api/verification-target-management-service";
|
||||
import type { VerificationTargetCodeResponse } from "@/entities/statistics/model/verification-target-management-interface";
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
@@ -102,7 +102,7 @@ function toNumber(value: string): number {
|
||||
return Number.isNaN(parsed) ? 0 : parsed;
|
||||
}
|
||||
|
||||
const HbStatisticsVerification = () => {
|
||||
export default function HbStatisticsVerification() {
|
||||
const { setMessage: alert } = useAlertStore((state) => state);
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
@@ -207,7 +207,9 @@ const HbStatisticsVerification = () => {
|
||||
params.verifyDtEnd = dayjs(to).format("YYYY-MM-DD");
|
||||
}
|
||||
|
||||
return stAnlsMstApi.getAnalysisHistoryList(params);
|
||||
return statisticsAnalysisMasterService.getAnalysisHistoryList(
|
||||
params,
|
||||
);
|
||||
},
|
||||
refetchInterval: (query) => {
|
||||
const data = query.state.data;
|
||||
@@ -248,9 +250,10 @@ const HbStatisticsVerification = () => {
|
||||
],
|
||||
queryFn: async () => {
|
||||
if (!outlierDialog.anlsSn) return [];
|
||||
const response = await stAnlsMstApi.getOutlierList(
|
||||
outlierDialog.anlsSn,
|
||||
);
|
||||
const response =
|
||||
await statisticsAnalysisMasterService.getOutlierList(
|
||||
outlierDialog.anlsSn,
|
||||
);
|
||||
return response;
|
||||
},
|
||||
enabled: outlierDialog.open && !!outlierDialog.anlsSn,
|
||||
@@ -771,6 +774,4 @@ const HbStatisticsVerification = () => {
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default HbStatisticsVerification;
|
||||
}
|
||||
|
||||
@@ -24,25 +24,21 @@ import dayjs from "dayjs";
|
||||
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import { CodeSelect } from "@/entities/code";
|
||||
import type {
|
||||
AdstZoneResponseDto,
|
||||
StAnlsMstResponse,
|
||||
StAnlsMstSearchParams,
|
||||
StAnlsRsltResponse,
|
||||
} from "@/entities/statistics";
|
||||
import {
|
||||
type AdstZoneResponseDto,
|
||||
IMR_DETAIL_VISIBLE_COLUMNS_BY_STATS_CD,
|
||||
IMR_DETAIL_VISIBLE_COLUMNS_DEFAULT,
|
||||
imrApi,
|
||||
imrDetailGridColumnInfo,
|
||||
imrVerificationHistoryColumns,
|
||||
} from "@/entities/statistics";
|
||||
import { imrApi } from "@/entities/statistics/api/imr-api";
|
||||
import {
|
||||
type StAnlsMstResponse,
|
||||
type StAnlsMstSearchParams,
|
||||
stAnlsRsltApi,
|
||||
type StAnlsRsltResponse,
|
||||
statisticsAnalysisMasterService,
|
||||
useStAnlsSidoCombo,
|
||||
useStAnlsSigunguCombo,
|
||||
} from "@/entities/statistics/api/queries";
|
||||
import { stAnlsMstApi } from "@/entities/statistics/api/statistics-analysis-master-api";
|
||||
import { stAnlsRsltApi } from "@/entities/statistics/api/statistics-analysis-result-api";
|
||||
} from "@/entities/statistics";
|
||||
import {
|
||||
Button,
|
||||
DataTable,
|
||||
@@ -144,7 +140,7 @@ const ImrVerificationHistory = () => {
|
||||
historyPagination,
|
||||
],
|
||||
queryFn: () =>
|
||||
stAnlsMstApi.getImrAnalysisMasterList({
|
||||
statisticsAnalysisMasterService.getImrAnalysisMasterList({
|
||||
...appliedSearchParams,
|
||||
page: historyPagination.pageIndex,
|
||||
size: historyPagination.pageSize,
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
import type { StAnlsDtlResponse } from "@/entities/statistics";
|
||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import type { AxiosError } from "axios";
|
||||
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import { useAlertStore, useMutationWrapper } from "@/shared/lib";
|
||||
import type { ApiErrorResponse } from "@/shared/model";
|
||||
import type {
|
||||
StAnlsDtlConfirmRequest,
|
||||
StAnlsDtlConfirmResponse,
|
||||
StAnlsDtlResponse,
|
||||
} from "@/entities/statistics";
|
||||
import { statisticsAnalysisDetailService } from "@/entities/statistics";
|
||||
import { Button } from "@common/components";
|
||||
|
||||
import Indicators from "./Indicators";
|
||||
@@ -38,6 +50,47 @@ const HbVerificationDetail: React.FC<HbVerificationDetailProps> = ({
|
||||
vrfcTrgtNm: string;
|
||||
} | null>(null);
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
const { setMessage: alert } = useAlertStore((state) => state);
|
||||
const { confirm } = useConfirm();
|
||||
|
||||
const confirmMutation = useMutationWrapper<
|
||||
StAnlsDtlConfirmResponse,
|
||||
AxiosError<ApiErrorResponse>,
|
||||
StAnlsDtlConfirmRequest
|
||||
>({
|
||||
mutationFn: (payload) =>
|
||||
statisticsAnalysisDetailService.confirmDetail(payload),
|
||||
onSuccess: async () => {
|
||||
setCheckedSns([]);
|
||||
|
||||
await Promise.all([
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: [
|
||||
ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_DTL,
|
||||
"list",
|
||||
anlsSn,
|
||||
],
|
||||
}),
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: [ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_MST],
|
||||
}),
|
||||
]);
|
||||
},
|
||||
});
|
||||
|
||||
const handleConfirmClick = async () => {
|
||||
if (checkedSns.length === 0) return;
|
||||
|
||||
if (!(await confirm("검증확정 처리하시겠습니까?"))) return;
|
||||
|
||||
const vrfcTrgtSnList = checkedSns
|
||||
.map((value) => Number(value))
|
||||
.filter((value) => !Number.isNaN(value));
|
||||
|
||||
confirmMutation.mutate({ anlsSn, vrfcTrgtSnList });
|
||||
};
|
||||
|
||||
const handleTargetSelect = (row: StAnlsDtlResponse) => {
|
||||
setSelectedVrfcTrgtSn(String(row.vrfcTrgtSn));
|
||||
setSelectedTargetInfo({
|
||||
@@ -70,7 +123,14 @@ const HbVerificationDetail: React.FC<HbVerificationDetailProps> = ({
|
||||
검증 상세
|
||||
</h2>
|
||||
</div>
|
||||
<Button disabled={checkedSns.length === 0}>검증확정</Button>
|
||||
<Button
|
||||
disabled={
|
||||
checkedSns.length === 0 || confirmMutation.isPending
|
||||
}
|
||||
onClick={handleConfirmClick}
|
||||
>
|
||||
검증확정
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-4">
|
||||
|
||||
@@ -6,7 +6,7 @@ import { getCoreRowModel, useReactTable } from "@tanstack/react-table";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import type { StAnlsDtlResponse } from "@/entities/statistics";
|
||||
import { getVerificationListColumns } from "@/entities/statistics";
|
||||
import { stAnlsDtlApi } from "@/entities/statistics/api/statistics-analysis-detail-api";
|
||||
import { statisticsAnalysisDetailService } from "@/entities/statistics/api/statistics-analysis-detail-service";
|
||||
import { DataTable } from "@common/components";
|
||||
|
||||
interface VerificationListProps {
|
||||
@@ -27,7 +27,11 @@ const VerificationList: React.FC<VerificationListProps> = ({
|
||||
const { data: detailData, isLoading } = useQuery({
|
||||
queryKey: [ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_DTL, "list", anlsSn],
|
||||
queryFn: () =>
|
||||
stAnlsDtlApi.getDetailList({ anlsSn, page: 0, size: 100 }),
|
||||
statisticsAnalysisDetailService.getDetailList({
|
||||
anlsSn,
|
||||
page: 0,
|
||||
size: 100,
|
||||
}),
|
||||
enabled: !!anlsSn,
|
||||
});
|
||||
|
||||
|
||||
+16
-18
@@ -1,6 +1,11 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { useConfirm } from '@frontend-opensource/use-react-hooks';
|
||||
|
||||
import { useAlertStore } from '@/shared/lib';
|
||||
import { NoData } from '@/shared/ui/no-data';
|
||||
import { generalverificationApiService } from '@/entities/statistics/api/general-verification-service';
|
||||
import type { VerifyDetailData, VerifyDetailResponseDto } from '@/entities/statistics/model/general-verification-interface';
|
||||
import {
|
||||
Button,
|
||||
Table,
|
||||
@@ -9,17 +14,13 @@ import {
|
||||
TableHead,
|
||||
TableRow,
|
||||
} from "@common/components";
|
||||
import FormulaComponents from './FormulaComponents';
|
||||
import { LoadingWithAnimation } from '@common/components';
|
||||
import FomulaDialog from './FomulaDialog';
|
||||
|
||||
import { useAlertStore } from '@/shared/lib';
|
||||
import { useConfirm } from '@frontend-opensource/use-react-hooks';
|
||||
|
||||
import { generalverificationApiService } from '@/entities/statistics/api/general-verification-service';
|
||||
import type { VerifyDetailData, VerifyDetailResponseDto } from '@/entities/statistics/model/general-verification-interface';
|
||||
import { getUserInfo } from '../../../../../../../packages/common/components/src/api';
|
||||
|
||||
import FomulaDialog from './FomulaDialog';
|
||||
import FormulaComponents from './FormulaComponents';
|
||||
|
||||
interface DetailComponentProps {
|
||||
selectedVrfcRow: number | null;
|
||||
}
|
||||
@@ -107,19 +108,16 @@ const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 여러 항목일 때 마지막이 단항 연산자면: 이전 항목들 연산자는 무조건 null
|
||||
// 여러 항목일 때 마지막이 단항 연산자면:
|
||||
// 이전 항목들의 연산자는 '?'일 때만 등록 허용 (자동 null 보정하지 않음)
|
||||
if (rows.length > 1 && lastIsUnary) {
|
||||
for (let i = 0; i < rows.length - 1; i++) {
|
||||
const prev = rows[i];
|
||||
if (prev) prev.cmprOpert = null;
|
||||
}
|
||||
setFormulaList((prev) => {
|
||||
if (prev.length <= 1) return prev;
|
||||
const next = prev.map((item, idx) =>
|
||||
idx < prev.length - 1 && item != null ? { ...item, cmprOpert: null } : item,
|
||||
const invalidUnaryPrevIdx = rows.slice(0, -1).findIndex((r) => r.cmprOpert !== '?');
|
||||
if (invalidUnaryPrevIdx !== -1) {
|
||||
alert(
|
||||
`마지막 항목이 단항 연산자(is_null, !is_null, floor)일 때는 이전 항목의 연산자를 '?'로 선택해야 합니다.\n(순번: ${invalidUnaryPrevIdx + 1})`,
|
||||
);
|
||||
return next;
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 마지막 항목의 연산자는 (단항 연산자 케이스 제외) 무조건 null 처리
|
||||
|
||||
@@ -365,6 +365,10 @@ export type SplitDataGridProps = {
|
||||
setRightRowData: React.Dispatch<
|
||||
React.SetStateAction<Record<string, string | number>[]>
|
||||
>;
|
||||
/** 좌측 분할 그리드 행 클릭 이벤트 */
|
||||
leftOnRowClick?: (rowData: Record<string, string | number>) => void;
|
||||
/** 좌측 분할 그리드 셀 스타일 콜백 */
|
||||
leftCellStyleCallback?: CellStyleCallback;
|
||||
/** 전체 정렬 기능 on/off (기본값: false) */
|
||||
enableSort?: boolean;
|
||||
};
|
||||
|
||||
+2
@@ -7,6 +7,7 @@ export const MainFacilityColumn = {
|
||||
{ name: 'prxyBzentyNmCn', fieldName: 'prxyBzentyNmCn', header: { text: '위탁업체명' }, editable: false },
|
||||
{ name: 'cnsgnCstVl', fieldName: 'cnsgnCstVl', header: { text: '위탁비용(백만원/년)' }, editable: false },
|
||||
{ name: 'prxyCtrtCn', fieldName: 'prxyCtrtCn', header: { text: '위탁계약기간' }, editable: false },
|
||||
{ name: 'wholNope', fieldName: 'wholNope', header: { text: '직원수(명)' }, editable: false },
|
||||
{ name: 'isMainYn', fieldName: 'isMainYn', header: { text: '중심처리시설여부' }, editable: false },
|
||||
|
||||
{ name: 'admdstCd', fieldName: 'admdstCd', header: { text: '행정구역코드' }, visible: false, editable: false, styleName: 'rg-cell-readonly' },
|
||||
@@ -21,6 +22,7 @@ export const MainFacilityColumn = {
|
||||
'prxyBzentyNmCn',
|
||||
'cnsgnCstVl',
|
||||
'prxyCtrtCn',
|
||||
'wholNope',
|
||||
'isMainYn',
|
||||
'admdstCd',
|
||||
'fcltSn',
|
||||
|
||||
+5
-3
@@ -1,6 +1,7 @@
|
||||
import { footerInt, footerDecimal1, footerDecimal3 } from "@/components/util/grid/footerSummary";
|
||||
import { ValueType } from "realgrid";
|
||||
|
||||
import { footerDecimal1, footerDecimal3,footerInt } from "@/components/util/grid/footerSummary";
|
||||
|
||||
/**
|
||||
* 하수도 통계 관리 > 06. 공공하수처리시설
|
||||
*/
|
||||
@@ -110,8 +111,9 @@ export const PublicSewageFactColumn = {
|
||||
{ name: 'intgPrcsFcltCn', fieldName: 'intgPrcsFcltCn', header: { text: '중심처리시설' }, editable: false, styleName: 'rg-cell-readonly' },
|
||||
{ name: 'wholNope', fieldName: 'wholNope', header: { text: '직원총수(명)' }, editable: false, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0', styleName: 'rg-cell-readonly' },
|
||||
{ name: 'sftyAcdntEvntcsCnt', fieldName: 'sftyAcdntEvntcsCnt', header: { text: '안전사고건수' }, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'rmk', fieldName: '비고', header: { text: '비고' } },
|
||||
{ name: 'rmrk', fieldName: 'rmrk', header: { text: '비고' } },
|
||||
{ name: 'admdstCd', fieldName: 'admdstCd', header: { text: '행정구역코드' }, visible: false, editable: false, styleName: 'rg-cell-readonly' },
|
||||
{ name: 'admdstNm', fieldName: 'admdstNm', header: { text: '행정구역명' }, visible: false, editable: false, styleName: 'rg-cell-readonly' },
|
||||
{ name: 'fcltSn', fieldName: 'fcltSn', header: { text: '처리시설일련번호' }, visible: false, editable: false, valueType: ValueType.TEXT, styleName: 'rg-cell-readonly' },
|
||||
{ name: 'swtrmtFcltCd', fieldName: 'swtrmtFcltCd', header: { text: '하수처리시설코드' }, visible: false, editable: false, styleName: 'rg-cell-readonly' },
|
||||
],
|
||||
@@ -208,7 +210,7 @@ export const PublicSewageFactColumn = {
|
||||
'intgPrcsFcltCn',
|
||||
'wholNope',
|
||||
'sftyAcdntEvntcsCnt',
|
||||
'rmk',
|
||||
'rmrk',
|
||||
'admdstCd',
|
||||
'fcltSn',
|
||||
'swtrmtFcltCd',
|
||||
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
import { stClient } from "@/shared/api/client";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
|
||||
import type {
|
||||
PublicSewageFacilityRequestParams,
|
||||
PublicSewageFacilityResponse,
|
||||
PublicSewageFacilitySaveRequest,
|
||||
PublicSewageFacilitySaveResponse,
|
||||
PublicSewageFacilitySubmitRequest,
|
||||
PublicSewageFacilitySubmitResponse,
|
||||
PublicSewageMainFacilityResponse,
|
||||
PublicSewageMappingTargetsRequestParams,
|
||||
PublicSewageMappingTargetsResponse,
|
||||
StatisticsInputPublicSewageFacilityService,
|
||||
} from "../../model/input/statistics-public-sewage-facility-input-interface";
|
||||
|
||||
export class StatisticsInputPublicSewageFacilityApiService implements StatisticsInputPublicSewageFacilityService {
|
||||
public async getPublicSewageFacility(param: PublicSewageFacilityRequestParams): Promise<PublicSewageFacilityResponse> {
|
||||
const response = await stClient.get<PublicSewageFacilityResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/public-sewage-facility/facility`,
|
||||
{ params: param },
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async getPublicSewageMainFacility(param: PublicSewageFacilityRequestParams): Promise<PublicSewageMainFacilityResponse> {
|
||||
const response = await stClient.get<PublicSewageMainFacilityResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/public-sewage-facility/main-facility`,
|
||||
{ params: param },
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async getMappingTargets(
|
||||
param: PublicSewageMappingTargetsRequestParams,
|
||||
): Promise<PublicSewageMappingTargetsResponse> {
|
||||
const response = await stClient.get<PublicSewageMappingTargetsResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/public-sewage-facility/main-facility/mapping-targets`,
|
||||
{ params: param },
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async savePublicSewageFacility(
|
||||
param: PublicSewageFacilitySaveRequest,
|
||||
): Promise<PublicSewageFacilitySaveResponse> {
|
||||
const response = await stClient.post<PublicSewageFacilitySaveResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/public-sewage-facility/facility/save`,
|
||||
param,
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async submitPublicSewageFacility(
|
||||
param: PublicSewageFacilitySubmitRequest,
|
||||
): Promise<PublicSewageFacilitySubmitResponse> {
|
||||
const response = await stClient.post<PublicSewageFacilitySubmitResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/public-sewage-facility/facility/submit`,
|
||||
param,
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
}
|
||||
|
||||
export const statisticsInputPublicSewageFacilityApiService = new StatisticsInputPublicSewageFacilityApiService();
|
||||
@@ -16,6 +16,8 @@ import type {
|
||||
SeweragePipeInputRegionalFactStatusSaveResponse,
|
||||
SeweragePipeInputRegionalFactStatusSubmitRequest,
|
||||
SeweragePipeInputRegionalFactStatusSubmitResponse,
|
||||
SeweragePipeInputFactInstallStatusSubmitRequest,
|
||||
SeweragePipeInputFactInstallStatusSubmitResponse,
|
||||
SeweragePipeInputRegionalResponse,
|
||||
SeweragePipeRequestParams,
|
||||
StatisticsInputSewPipeService,
|
||||
@@ -23,10 +25,14 @@ import type {
|
||||
SeweragePipeInputFactInstallStatusSaveResponse,
|
||||
SeweragePipeInputPipeTypeStatusSaveRequest,
|
||||
SeweragePipeInputPipeTypeStatusSaveResponse,
|
||||
SeweragePipeInputPipeTypeStatusSubmitRequest,
|
||||
SeweragePipeInputPipeDiameterStatusSaveRequest,
|
||||
SeweragePipeInputPipeDiameterStatusSaveResponse,
|
||||
SeweragePipeInputPipeDiameterStatusSubmitRequest,
|
||||
SeweragePipeInputManholeStatusSaveRequest,
|
||||
SeweragePipeInputManholeStatusSaveResponse,
|
||||
SeweragePipeInputManholeStatusSubmitRequest,
|
||||
SeweragePipeInputSubmitResponse,
|
||||
} from "../../model/input/statistics-sewage-pipe-input-interface";
|
||||
|
||||
export class StatisticsInputSewPipeApiService implements StatisticsInputSewPipeService {
|
||||
@@ -126,6 +132,14 @@ export class StatisticsInputSewPipeApiService implements StatisticsInputSewPipeS
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async submitFactInstallStatus(param: SeweragePipeInputFactInstallStatusSubmitRequest): Promise<SeweragePipeInputFactInstallStatusSubmitResponse> {
|
||||
const response = await stClient.post<SeweragePipeInputFactInstallStatusSubmitResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/sewage-pipe/facility-install-status/submit`,
|
||||
param,
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async savePipeTypeStatus(param: SeweragePipeInputPipeTypeStatusSaveRequest): Promise<SeweragePipeInputPipeTypeStatusSaveResponse> {
|
||||
const response = await stClient.post<SeweragePipeInputPipeTypeStatusSaveResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/sewage-pipe/pipe-type-status/save`,
|
||||
@@ -134,6 +148,14 @@ export class StatisticsInputSewPipeApiService implements StatisticsInputSewPipeS
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async submitPipeTypeStatus(param: SeweragePipeInputPipeTypeStatusSubmitRequest): Promise<SeweragePipeInputSubmitResponse> {
|
||||
const response = await stClient.post<SeweragePipeInputSubmitResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/sewage-pipe/pipe-type-status/submit`,
|
||||
param,
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async savePipeDiameterStatus(param: SeweragePipeInputPipeDiameterStatusSaveRequest): Promise<SeweragePipeInputPipeDiameterStatusSaveResponse> {
|
||||
const response = await stClient.post<SeweragePipeInputPipeDiameterStatusSaveResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/sewage-pipe/pipe-diameter-status/save`,
|
||||
@@ -142,6 +164,14 @@ export class StatisticsInputSewPipeApiService implements StatisticsInputSewPipeS
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async submitPipeDiameterStatus(param: SeweragePipeInputPipeDiameterStatusSubmitRequest): Promise<SeweragePipeInputSubmitResponse> {
|
||||
const response = await stClient.post<SeweragePipeInputSubmitResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/sewage-pipe/pipe-diameter-status/submit`,
|
||||
param,
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async saveManholeStatus(param: SeweragePipeInputManholeStatusSaveRequest): Promise<SeweragePipeInputManholeStatusSaveResponse> {
|
||||
const response = await stClient.post<SeweragePipeInputManholeStatusSaveResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/sewage-pipe/manhole-status/save`,
|
||||
@@ -149,6 +179,14 @@ export class StatisticsInputSewPipeApiService implements StatisticsInputSewPipeS
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async submitManholeStatus(param: SeweragePipeInputManholeStatusSubmitRequest): Promise<SeweragePipeInputSubmitResponse> {
|
||||
const response = await stClient.post<SeweragePipeInputSubmitResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUT}/sewage-pipe/manhole-status/submit`,
|
||||
param,
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
};
|
||||
|
||||
export const statisticsInputSewPipeApiService = new StatisticsInputSewPipeApiService();
|
||||
@@ -0,0 +1,43 @@
|
||||
import { client } from "@/shared/api/client";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import type { PageableList } from "@/shared/model";
|
||||
|
||||
import type {
|
||||
NtftalkTemplate,
|
||||
TemplateVariablesResponse,
|
||||
} from "../../model/notice-talk/notice-talk-sending-interface";
|
||||
|
||||
export const NTFTALK_TEMPLATE_LIST_PARAMS = {
|
||||
sort: "createdAt,desc",
|
||||
senderKey: "",
|
||||
inspectionStatus: "APR",
|
||||
templateMessageType: "BA",
|
||||
page: 0,
|
||||
size: 10,
|
||||
};
|
||||
|
||||
/**
|
||||
* 알림톡 발송 화면용 Ntftalk API
|
||||
*/
|
||||
export class NoticeTalkSendingApiService {
|
||||
async getTemplatePage(
|
||||
params: typeof NTFTALK_TEMPLATE_LIST_PARAMS = NTFTALK_TEMPLATE_LIST_PARAMS,
|
||||
): Promise<PageableList<NtftalkTemplate>> {
|
||||
const response = await client.get<PageableList<NtftalkTemplate>>(
|
||||
ENDPOINT.NTFTALK_SERVICE.TEMP,
|
||||
{ params },
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async getTemplateVariables(
|
||||
templateCode: string,
|
||||
): Promise<TemplateVariablesResponse> {
|
||||
const response = await client.get<TemplateVariablesResponse>(
|
||||
`${ENDPOINT.NTFTALK_SERVICE.ATA_SEND}/template-variables/${templateCode}`,
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
}
|
||||
|
||||
export const noticeTalkSendingApi = new NoticeTalkSendingApiService();
|
||||
@@ -0,0 +1,33 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
|
||||
import {
|
||||
noticeTalkSendingApi,
|
||||
NTFTALK_TEMPLATE_LIST_PARAMS,
|
||||
} from "./notice-talk-sending-service";
|
||||
|
||||
export function useNtftalkTemplateList() {
|
||||
return useQuery({
|
||||
queryKey: [
|
||||
ENDPOINT.NTFTALK_SERVICE.TEMP,
|
||||
"ntitlk-sndng",
|
||||
NTFTALK_TEMPLATE_LIST_PARAMS,
|
||||
],
|
||||
queryFn: () =>
|
||||
noticeTalkSendingApi.getTemplatePage(NTFTALK_TEMPLATE_LIST_PARAMS),
|
||||
});
|
||||
}
|
||||
|
||||
export function useNtftalkTemplateVariables(templateCode: string) {
|
||||
return useQuery({
|
||||
queryKey: [
|
||||
ENDPOINT.NTFTALK_SERVICE.ATA_SEND,
|
||||
"template-variables",
|
||||
templateCode,
|
||||
],
|
||||
queryFn: () =>
|
||||
noticeTalkSendingApi.getTemplateVariables(templateCode),
|
||||
enabled: Boolean(templateCode),
|
||||
});
|
||||
}
|
||||
@@ -1,18 +1,18 @@
|
||||
import { useInfiniteQuery, useQuery } from "@tanstack/react-query";
|
||||
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import { generalverificationApiService } from "@/entities/statistics/api/general-verification-service";
|
||||
import { StatisticsInputStatusApi } from "@/entities/statistics/api/input/statistics-input-status-service";
|
||||
import type { VerifyResultPageData } from "@/entities/statistics/model/general-verification-interface";
|
||||
|
||||
import type { VerifyResultPageData } from "../model/general-verification-interface";
|
||||
import type { SewerStUserSearchParams } from "../model/sewer-st-user-interface";
|
||||
import type {
|
||||
StatisticsVerificationFilterState,
|
||||
StatisticsVerificationSubFilterState,
|
||||
} from "@/entities/statistics/model/statistics-verification-report/statistics-verification-report-types";
|
||||
|
||||
import type { SewerStUserSearchParams } from "../model/sewer-st-user-interface";
|
||||
} from "../model/statistics-verification-report/statistics-verification-report-types";
|
||||
|
||||
import { StatisticsInputStatusApi } from "./input/statistics-input-status-service";
|
||||
import { generalverificationApiService } from "./general-verification-service";
|
||||
import { sewerStUserApi } from "./sewer-st-user-service";
|
||||
import { stAnlsMstApi } from "./statistics-analysis-master-api";
|
||||
import { statisticsAnalysisMasterService } from "./statistics-analysis-master-service";
|
||||
import { stAnlsRsltApi } from "./statistics-analysis-result-api";
|
||||
|
||||
const DETAIL_PAGE_SIZE = 100;
|
||||
@@ -20,14 +20,14 @@ const DETAIL_PAGE_SIZE = 100;
|
||||
export const useStAnlsSidoCombo = () => {
|
||||
return useQuery({
|
||||
queryKey: [ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_MST, "sido"],
|
||||
queryFn: () => stAnlsMstApi.getSidoCombo(),
|
||||
queryFn: () => statisticsAnalysisMasterService.getSidoCombo(),
|
||||
});
|
||||
};
|
||||
|
||||
export const useStAnlsSigunguCombo = (sidoCd: string) => {
|
||||
return useQuery({
|
||||
queryKey: [ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_MST, "sigungu", sidoCd],
|
||||
queryFn: () => stAnlsMstApi.getSigunguCombo(sidoCd),
|
||||
queryFn: () => statisticsAnalysisMasterService.getSigunguCombo(sidoCd),
|
||||
enabled: Boolean(sidoCd),
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import { client } from "@/shared/api";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
|
||||
import type {
|
||||
StAnlsDtlListApiResponse,
|
||||
StAnlsDtlResponse,
|
||||
StAnlsDtlSearchParams,
|
||||
} from "../model/statistics-analysis/statistics-analysis-detail-interface";
|
||||
|
||||
export class StAnlsDtlApiService {
|
||||
public async getDetailList(
|
||||
params: StAnlsDtlSearchParams,
|
||||
): Promise<StAnlsDtlListApiResponse> {
|
||||
const response = await client.get<StAnlsDtlListApiResponse>(
|
||||
`${ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_DTL}`,
|
||||
{
|
||||
params,
|
||||
},
|
||||
);
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async getDetail(
|
||||
anlsSn: number,
|
||||
vrfcTrgtSn: number,
|
||||
): Promise<StAnlsDtlResponse> {
|
||||
const response = await client.get<StAnlsDtlResponse>(
|
||||
`${ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_DTL}/${anlsSn}/${vrfcTrgtSn}`,
|
||||
);
|
||||
|
||||
return response.data;
|
||||
}
|
||||
}
|
||||
|
||||
export const stAnlsDtlApi = new StAnlsDtlApiService();
|
||||
@@ -0,0 +1,51 @@
|
||||
import { client } from "@/shared/api";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
|
||||
import type {
|
||||
StAnlsDtlConfirmRequest,
|
||||
StAnlsDtlConfirmResponse,
|
||||
StAnlsDtlListApiResponse,
|
||||
StAnlsDtlResponse,
|
||||
StAnlsDtlSearchParams,
|
||||
} from "../model/statistics-analysis/statistics-analysis-detail-interface";
|
||||
|
||||
async function getDetailList(
|
||||
params: StAnlsDtlSearchParams,
|
||||
): Promise<StAnlsDtlListApiResponse> {
|
||||
const response = await client.get<StAnlsDtlListApiResponse>(
|
||||
`${ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_DTL}`,
|
||||
{
|
||||
params,
|
||||
},
|
||||
);
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async function getDetail(
|
||||
anlsSn: number,
|
||||
vrfcTrgtSn: number,
|
||||
): Promise<StAnlsDtlResponse> {
|
||||
const response = await client.get<StAnlsDtlResponse>(
|
||||
`${ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_DTL}/${anlsSn}/${vrfcTrgtSn}`,
|
||||
);
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async function confirmDetail(
|
||||
request: StAnlsDtlConfirmRequest,
|
||||
): Promise<StAnlsDtlConfirmResponse> {
|
||||
const response = await client.post<StAnlsDtlConfirmResponse>(
|
||||
`${ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_DTL}/confirm`,
|
||||
request,
|
||||
);
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export const statisticsAnalysisDetailService = {
|
||||
getDetailList,
|
||||
getDetail,
|
||||
confirmDetail,
|
||||
};
|
||||
@@ -1,69 +0,0 @@
|
||||
import { client } from "@/shared/api";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
|
||||
import type {
|
||||
AdstZoneResponseDto,
|
||||
StAnlsMstImrListApiResponse,
|
||||
StAnlsMstListApiResponse,
|
||||
StAnlsMstSearchParams,
|
||||
StAnlsOutlierListResponse,
|
||||
} from "../model/statistics-analysis/statistics-analysis-master-interface";
|
||||
|
||||
export class StAnlsMstApiService {
|
||||
public async getAnalysisHistoryList(
|
||||
params: StAnlsMstSearchParams,
|
||||
): Promise<StAnlsMstListApiResponse> {
|
||||
const response = await client.get<StAnlsMstListApiResponse>(
|
||||
`${ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_MST}`,
|
||||
{
|
||||
params,
|
||||
},
|
||||
);
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async getImrAnalysisMasterList(
|
||||
params: StAnlsMstSearchParams,
|
||||
): Promise<StAnlsMstImrListApiResponse> {
|
||||
const response = await client.get<StAnlsMstImrListApiResponse>(
|
||||
`${ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_MST}/imr`,
|
||||
{
|
||||
params,
|
||||
},
|
||||
);
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async getOutlierList(
|
||||
anlsSn: number,
|
||||
): Promise<StAnlsOutlierListResponse[]> {
|
||||
const response = await client.get<StAnlsOutlierListResponse[]>(
|
||||
`${ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_MST}/outlierList/${anlsSn}`,
|
||||
);
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async getSidoCombo(): Promise<AdstZoneResponseDto[]> {
|
||||
const response = await client.get<AdstZoneResponseDto[]>(
|
||||
`${ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_MST}/sido`,
|
||||
);
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async getSigunguCombo(
|
||||
sidoCd: string,
|
||||
): Promise<AdstZoneResponseDto[]> {
|
||||
const response = await client.get<AdstZoneResponseDto[]>(
|
||||
`${ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_MST}/sigungu`,
|
||||
{ params: { sidoCd } },
|
||||
);
|
||||
|
||||
return response.data;
|
||||
}
|
||||
}
|
||||
|
||||
export const stAnlsMstApi = new StAnlsMstApiService();
|
||||
@@ -0,0 +1,71 @@
|
||||
import { client } from "@/shared/api";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
|
||||
import type {
|
||||
AdstZoneResponseDto,
|
||||
StAnlsMstImrListApiResponse,
|
||||
StAnlsMstListApiResponse,
|
||||
StAnlsMstSearchParams,
|
||||
StAnlsOutlierListResponse,
|
||||
} from "../model/statistics-analysis/statistics-analysis-master-interface";
|
||||
|
||||
async function getAnalysisHistoryList(
|
||||
params: StAnlsMstSearchParams,
|
||||
): Promise<StAnlsMstListApiResponse> {
|
||||
const response = await client.get<StAnlsMstListApiResponse>(
|
||||
`${ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_MST}`,
|
||||
{
|
||||
params,
|
||||
},
|
||||
);
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async function getImrAnalysisMasterList(
|
||||
params: StAnlsMstSearchParams,
|
||||
): Promise<StAnlsMstImrListApiResponse> {
|
||||
const response = await client.get<StAnlsMstImrListApiResponse>(
|
||||
`${ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_MST}/imr`,
|
||||
{
|
||||
params,
|
||||
},
|
||||
);
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async function getOutlierList(
|
||||
anlsSn: number,
|
||||
): Promise<StAnlsOutlierListResponse[]> {
|
||||
const response = await client.get<StAnlsOutlierListResponse[]>(
|
||||
`${ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_MST}/outlierList/${anlsSn}`,
|
||||
);
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async function getSidoCombo(): Promise<AdstZoneResponseDto[]> {
|
||||
const response = await client.get<AdstZoneResponseDto[]>(
|
||||
`${ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_MST}/sido`,
|
||||
);
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async function getSigunguCombo(sidoCd: string): Promise<AdstZoneResponseDto[]> {
|
||||
const response = await client.get<AdstZoneResponseDto[]>(
|
||||
`${ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_MST}/sigungu`,
|
||||
{ params: { sidoCd } },
|
||||
);
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export const statisticsAnalysisMasterService = {
|
||||
getAnalysisHistoryList,
|
||||
getImrAnalysisMasterList,
|
||||
getOutlierList,
|
||||
getSidoCombo,
|
||||
getSigunguCombo,
|
||||
};
|
||||
@@ -1,3 +1,4 @@
|
||||
export { analysisApi } from "./api/analysis-api";
|
||||
export {
|
||||
useDashboardEcptReqCount,
|
||||
useDashboardStatsSubmissionRate,
|
||||
@@ -8,6 +9,12 @@ export {
|
||||
export { dashboardApi } from "./api/dashboard/dashboard-service";
|
||||
export { useScheduleInfo } from "./api/dashboard/schedule-info-queries";
|
||||
export { scheduleInfoApi } from "./api/dashboard/schedule-info-service";
|
||||
export { imrApi } from "./api/imr-api";
|
||||
export { noticeTalkSendingApi } from "./api/notice-talk/notice-talk-sending-service";
|
||||
export {
|
||||
useNtftalkTemplateList,
|
||||
useNtftalkTemplateVariables,
|
||||
} from "./api/notice-talk/queries";
|
||||
export {
|
||||
useSewerStUserList,
|
||||
useStAnlsSidoCombo,
|
||||
@@ -16,7 +23,11 @@ export {
|
||||
useStatsVrfcRsltData,
|
||||
} from "./api/queries";
|
||||
export { sewerStUserApi } from "./api/sewer-st-user-service";
|
||||
export { statisticsAnalysisDetailService } from "./api/statistics-analysis-detail-service";
|
||||
export { statisticsAnalysisMasterService } from "./api/statistics-analysis-master-service";
|
||||
export { stAnlsRsltApi } from "./api/statistics-analysis-result-api";
|
||||
export { statisticsApprovalApi } from "./api/statistics-approval-service";
|
||||
export { verificationTargetManagementApi } from "./api/verification-target-management-service";
|
||||
export {
|
||||
type AnalysisHistoryListApiResponse,
|
||||
type AnalysisRequestPayload,
|
||||
@@ -64,12 +75,22 @@ export {
|
||||
} from "./model/imr/imr-interface";
|
||||
export { imrVerificationHistoryColumns } from "./model/imr/imr-verification-history-columns";
|
||||
export { type StatsInputStatusList } from "./model/input/statistics-input-status-interface";
|
||||
export { userListColumns } from "./model/notice-talk/notice-talk-sending-columns";
|
||||
export {
|
||||
type BusinessSendRequest,
|
||||
type BusinessSendResponse,
|
||||
type NtftalkTemplate,
|
||||
type SelectedRecipient,
|
||||
type TemplateVariablesResponse,
|
||||
} from "./model/notice-talk/notice-talk-sending-interface";
|
||||
export {
|
||||
type SewerStUserItem,
|
||||
type SewerStUserListResponse,
|
||||
type SewerStUserSearchParams,
|
||||
} from "./model/sewer-st-user-interface";
|
||||
export {
|
||||
type StAnlsDtlConfirmRequest,
|
||||
type StAnlsDtlConfirmResponse,
|
||||
type StAnlsDtlListApiResponse,
|
||||
type StAnlsDtlResponse,
|
||||
type StAnlsDtlSearchParams,
|
||||
@@ -121,3 +142,4 @@ export {
|
||||
type IMRArticleItem,
|
||||
type ValidationArticleItem,
|
||||
} from "./model/verification-article/verification-article-interface";
|
||||
export { type VerificationTargetCodeResponse } from "./model/verification-target-management-interface";
|
||||
|
||||
+254
@@ -0,0 +1,254 @@
|
||||
import type { SewerageStatusInfo } from "../statistics-interface";
|
||||
|
||||
export interface PublicSewageFacilityRequestParams {
|
||||
ctpvNm?: string;
|
||||
sggNm?: string;
|
||||
sewerBzmnCd?: string;
|
||||
fcltNm?: string;
|
||||
statsYr?: string;
|
||||
mode?: string;
|
||||
}
|
||||
|
||||
export interface PublicSewageFacilityVerifyResultItem {
|
||||
vrfcCd: string;
|
||||
rsnExpln: string;
|
||||
nowVlCn?: string;
|
||||
compVlCn?: string;
|
||||
}
|
||||
|
||||
/** 필드명 -> 검증 결과 배열 */
|
||||
export type PublicSewageFacilityVerificationResult = Record<
|
||||
string,
|
||||
PublicSewageFacilityVerifyResultItem[]
|
||||
>;
|
||||
|
||||
export interface PublicSewageFacilityCommonInfo {
|
||||
statsYr: string;
|
||||
ctpvNm: string;
|
||||
sewerBzmnCd: string;
|
||||
statsCd: string;
|
||||
verificationResult?: PublicSewageFacilityVerificationResult | null;
|
||||
}
|
||||
|
||||
export interface PublicSewageFacilityItem {
|
||||
admdstCd: string;
|
||||
sggNm: string;
|
||||
admdstNm: string;
|
||||
fcltSn: number;
|
||||
swtrmtFcltCd: string;
|
||||
swtrmtFcltNm: string;
|
||||
impdFcltPstnCn: string | null;
|
||||
prcsFcltCpct: number;
|
||||
prcsFcltPhysCpct: number;
|
||||
prcsFcltBoilCpct: number;
|
||||
prcsFcltAltdCpct: number;
|
||||
inflwSwageQnt: number;
|
||||
inflwSwagePhysQnt: number;
|
||||
inflwSwageBoilQnt: number;
|
||||
inflwSwageAltdQnt: number;
|
||||
prcsQnt: number;
|
||||
prcsPhysCpct: number;
|
||||
prcsBoilCpct: number;
|
||||
prcsAltdCpct: number;
|
||||
inflwBodVl: number;
|
||||
dschgBodVl: number;
|
||||
inflwTocQnt: number;
|
||||
dschgTocQnt: number;
|
||||
inflwSsQnt: number;
|
||||
dschgSsQnt: number;
|
||||
inflwTnVl: number;
|
||||
dschgTnVl: number;
|
||||
inflwTpVl: number;
|
||||
dschgTpVl: number;
|
||||
inflwGrssClfgVl: number;
|
||||
dschgGrssClfgVl: number;
|
||||
prcsRt: number;
|
||||
prcsLodQnt: number;
|
||||
prcsMthdExpln: string | null;
|
||||
wholHmnQnt: number;
|
||||
wholLvstQnt: number;
|
||||
wholEfntQnt: number;
|
||||
wholEtcQnt: number;
|
||||
telNo: string | null;
|
||||
cmptnStrtYmd: string | null;
|
||||
oprtngStrtYmd: string | null;
|
||||
wholBizVl: number;
|
||||
eflntDsnfMthdExpln: string | null;
|
||||
wtsysNm: string | null;
|
||||
trbtrNm: string | null;
|
||||
dtlUnitZoneCn: string | null;
|
||||
rgnSeNm: string | null;
|
||||
msirbCn: string | null;
|
||||
goalWqNo: string | null;
|
||||
engySrlneRt: number;
|
||||
engyItslfPrdctnQnt: number;
|
||||
anlEngyWholUseQnt: number;
|
||||
anlElpwrUseQnt: number;
|
||||
itslfEngyUseQnt: number;
|
||||
swtrmtEmsnQnt: number;
|
||||
operMnbdCn: string | null;
|
||||
prxyBzentyNmCn: string | null;
|
||||
cnsgnCstVl: number;
|
||||
prxyCtrtCn: string | null;
|
||||
intgPrcsFcltCn: string | null;
|
||||
wholNope: number;
|
||||
sftyAcdntEvntcsCnt: number;
|
||||
rmrk: string | null;
|
||||
verificationResult?: PublicSewageFacilityVerificationResult | null;
|
||||
}
|
||||
|
||||
export interface PublicSewageFacilityResponseData {
|
||||
statusInfo: SewerageStatusInfo;
|
||||
commonInfo: PublicSewageFacilityCommonInfo;
|
||||
publicSewageFacilityList: PublicSewageFacilityItem[];
|
||||
}
|
||||
|
||||
export interface PublicSewageFacilityResponse {
|
||||
status: string;
|
||||
message?: string;
|
||||
data: PublicSewageFacilityResponseData;
|
||||
}
|
||||
|
||||
/** ST00060002 지자체별 전체시설 목록 항목 */
|
||||
export interface PublicSewageMainFacilityItem {
|
||||
admdstCd: string;
|
||||
sggNm: string | null;
|
||||
admdstNm: string;
|
||||
isMainYn: string;
|
||||
fcltSn: string;
|
||||
swtrmtFcltCd: string;
|
||||
swtrmtFcltNm: string;
|
||||
fcltPstnCn: string | null;
|
||||
prxyBzentyNmCn: string | null;
|
||||
cnsgnCstVl: number;
|
||||
prxyCtrtCn: string | null;
|
||||
wholNope: number;
|
||||
}
|
||||
|
||||
/** ST00060002 조회 응답 data */
|
||||
export interface PublicSewageMainFacilityResponseData {
|
||||
statusInfo: SewerageStatusInfo;
|
||||
commonInfo: PublicSewageFacilityCommonInfo;
|
||||
mainFacilityList: PublicSewageMainFacilityItem[];
|
||||
}
|
||||
|
||||
/** ST00060002 조회 API 응답 */
|
||||
export interface PublicSewageMainFacilityResponse {
|
||||
status: string;
|
||||
message?: string;
|
||||
data: PublicSewageMainFacilityResponseData;
|
||||
}
|
||||
|
||||
/** ST00060002 메인시설 클릭 시 우측 매핑대상 조회 요청 */
|
||||
export interface PublicSewageMappingTargetsRequestParams {
|
||||
sewerBzmnCd: string;
|
||||
ctpvNm: string;
|
||||
sggNm: string;
|
||||
statsYr: string;
|
||||
fcltSn: string;
|
||||
}
|
||||
|
||||
/** ST00060002 메인시설 클릭 시 우측 매핑대상 조회 항목 */
|
||||
export interface PublicSewageMappingTargetItem {
|
||||
fcltSn: string;
|
||||
admdstNm: string;
|
||||
swtrmtFcltCd: string;
|
||||
swtrmtFcltNm: string;
|
||||
fcltPstnCn: string;
|
||||
mappedYn: string;
|
||||
mainFcltSn: string;
|
||||
isMainYn: string;
|
||||
}
|
||||
|
||||
/** ST00060002 메인시설 클릭 시 우측 매핑대상 조회 응답 */
|
||||
export interface PublicSewageMappingTargetsResponse {
|
||||
status: string;
|
||||
message?: string;
|
||||
data: PublicSewageMappingTargetItem[];
|
||||
}
|
||||
|
||||
/** ST00060001 공공하수처리시설 저장 — saveList 항목 */
|
||||
export interface PublicSewageFacilitySaveItem {
|
||||
admdstCd: string;
|
||||
admdstNm: string;
|
||||
swtrmtFcltCd: string;
|
||||
swtrmtFcltNm: string;
|
||||
fcltSn: string;
|
||||
fcltPstnCn: string | null;
|
||||
|
||||
inflwSwagePhysQnt: number;
|
||||
inflwSwageBoilQnt: number;
|
||||
inflwSwageAltdQnt: number;
|
||||
|
||||
prcsPhysCpct: number;
|
||||
prcsBoilCpct: number;
|
||||
prcsAltdCpct: number;
|
||||
|
||||
prxyCtrtCn: string | null;
|
||||
sftyAcdntEvntcsCnt: number;
|
||||
rmrk: string | null;
|
||||
}
|
||||
|
||||
/** ST00060001 공공하수처리시설 저장 API 요청 */
|
||||
export interface PublicSewageFacilitySaveRequest {
|
||||
statsYr: string;
|
||||
ctpvNm: string;
|
||||
sggNm: string;
|
||||
sewerBzmnCd: string;
|
||||
userId: string;
|
||||
superAdmin: string;
|
||||
|
||||
/**
|
||||
* 저장 요청에서 "해당없음" 처리 여부가 함께 전달되는 경우를 고려합니다.
|
||||
* (백엔드 스펙에 따라 필수 여부는 달라질 수 있어 optional로 둡니다.)
|
||||
*/
|
||||
noApplicable?: boolean;
|
||||
|
||||
saveList: PublicSewageFacilitySaveItem[];
|
||||
}
|
||||
|
||||
export interface PublicSewageFacilitySaveResponse {
|
||||
data?: string;
|
||||
message?: string;
|
||||
status: string;
|
||||
}
|
||||
|
||||
/** 공공하수처리시설 입력 제출 공통 본문 (`submitList` 제외) */
|
||||
export interface PublicSewageFacilitySubmitRequestBase {
|
||||
statsYr: string;
|
||||
ctpvNm: string;
|
||||
sggNm: string;
|
||||
sewerBzmnCd: string;
|
||||
userId: string;
|
||||
noApplicable?: boolean;
|
||||
laePicNm: string;
|
||||
laePicTelNo: string;
|
||||
laeKbrdrDeptNm: string;
|
||||
laeKbrdrJbgdNm: string;
|
||||
laeIdfrNm: string;
|
||||
laeIdfrTelNo: string;
|
||||
laeIdfrDeptNm: string;
|
||||
laeIdfrJbgdNm: string;
|
||||
}
|
||||
|
||||
/** ST00060001 공공하수처리시설 제출 API 요청 (`submitList` 행은 저장과 동일) */
|
||||
export interface PublicSewageFacilitySubmitRequest extends PublicSewageFacilitySubmitRequestBase {
|
||||
submitList: PublicSewageFacilitySaveItem[];
|
||||
}
|
||||
|
||||
export interface PublicSewageFacilitySubmitResponse {
|
||||
data: {
|
||||
finalStatus: string;
|
||||
nvpassed: boolean;
|
||||
}
|
||||
message?: string;
|
||||
status: string;
|
||||
}
|
||||
|
||||
export interface StatisticsInputPublicSewageFacilityService {
|
||||
getPublicSewageFacility(param: PublicSewageFacilityRequestParams): Promise<PublicSewageFacilityResponse>;
|
||||
getPublicSewageMainFacility(param: PublicSewageFacilityRequestParams): Promise<PublicSewageMainFacilityResponse>;
|
||||
getMappingTargets(param: PublicSewageMappingTargetsRequestParams): Promise<PublicSewageMappingTargetsResponse>;
|
||||
savePublicSewageFacility(param: PublicSewageFacilitySaveRequest): Promise<PublicSewageFacilitySaveResponse>;
|
||||
submitPublicSewageFacility(param: PublicSewageFacilitySubmitRequest): Promise<PublicSewageFacilitySubmitResponse>;
|
||||
}
|
||||
+49
-2
@@ -122,8 +122,8 @@ export interface SeweragePipeInputRegionalFactStatusSaveResponse {
|
||||
status: string;
|
||||
}
|
||||
|
||||
/** ST00020001 지역별 시설현황 제출 API 요청 (`submitList` 행은 저장과 동일) */
|
||||
export interface SeweragePipeInputRegionalFactStatusSubmitRequest {
|
||||
/** 하수관로 입력 제출 공통 본문 (`submitList` 제외) */
|
||||
export interface SeweragePipeInputSubmitRequestBase {
|
||||
statsYr: string;
|
||||
ctpvNm: string;
|
||||
sggNm: string;
|
||||
@@ -137,6 +137,10 @@ export interface SeweragePipeInputRegionalFactStatusSubmitRequest {
|
||||
laeIdfrTelNo: string;
|
||||
laeIdfrDeptNm: string;
|
||||
laeIdfrJbgdNm: string;
|
||||
}
|
||||
|
||||
/** ST00020001 지역별 시설현황 제출 API 요청 (`submitList` 행은 저장과 동일) */
|
||||
export interface SeweragePipeInputRegionalFactStatusSubmitRequest extends SeweragePipeInputSubmitRequestBase {
|
||||
submitList: SeweragePipeInputRegionalFactStatusSaveItem[];
|
||||
}
|
||||
|
||||
@@ -165,6 +169,30 @@ export interface SeweragePipeInputFactInstallStatusSaveResponse {
|
||||
status: string;
|
||||
}
|
||||
|
||||
/** ST00020002 시설별 설치현황 제출 API 요청 (`submitList` 행은 Tab2 저장과 동일) */
|
||||
export interface SeweragePipeInputFactInstallStatusSubmitRequest extends SeweragePipeInputSubmitRequestBase {
|
||||
submitList: SeweragePipeInputFactInstallStatusSaveItem[];
|
||||
}
|
||||
|
||||
export interface SeweragePipeInputFactInstallStatusSubmitResponse {
|
||||
data: {
|
||||
finalStatus: string;
|
||||
nvpassed: boolean;
|
||||
}
|
||||
message?: string;
|
||||
status: string;
|
||||
}
|
||||
|
||||
/** 하수관로 입력 제출 API 공통 응답 */
|
||||
export interface SeweragePipeInputSubmitResponse {
|
||||
data: {
|
||||
finalStatus: string;
|
||||
nvpassed: boolean;
|
||||
}
|
||||
message?: string;
|
||||
status: string;
|
||||
}
|
||||
|
||||
/** 시설별 설치 현황 — 목록 항목 */
|
||||
export interface SeweragePipeInputFactInstallStatusItem {
|
||||
admdstCd: string;
|
||||
@@ -283,6 +311,11 @@ export interface SeweragePipeInputPipeTypeStatusSaveResponse {
|
||||
status: string;
|
||||
}
|
||||
|
||||
/** ST00020003 관종별 현황 제출 API 요청 */
|
||||
export interface SeweragePipeInputPipeTypeStatusSubmitRequest extends SeweragePipeInputSubmitRequestBase {
|
||||
submitList: SeweragePipeInputPipeTypeStatusSaveItem[];
|
||||
}
|
||||
|
||||
/** 관경별 현황 — 목록 항목 */
|
||||
export interface SeweragePipeInputPipeDiameterStatusItem {
|
||||
admdstCd: string;
|
||||
@@ -350,6 +383,11 @@ export interface SeweragePipeInputPipeDiameterStatusSaveResponse {
|
||||
status: string;
|
||||
}
|
||||
|
||||
/** ST00020004 관경별 현황 제출 API 요청 */
|
||||
export interface SeweragePipeInputPipeDiameterStatusSubmitRequest extends SeweragePipeInputSubmitRequestBase {
|
||||
submitList: SeweragePipeInputPipeDiameterStatusSaveItem[];
|
||||
}
|
||||
|
||||
/** 맨홀 현황 — 연도별 통계 항목 */
|
||||
export interface SeweragePipeInputManholeYearlyStatItem {
|
||||
manhYr: string;
|
||||
@@ -443,6 +481,11 @@ export interface SeweragePipeInputManholeStatusSaveResponse {
|
||||
status: string;
|
||||
}
|
||||
|
||||
/** ST00020005 맨홀 현황 제출 API 요청 */
|
||||
export interface SeweragePipeInputManholeStatusSubmitRequest extends SeweragePipeInputSubmitRequestBase {
|
||||
submitList: SeweragePipeInputManholeStatusSaveItem[];
|
||||
}
|
||||
|
||||
/** 시설별 현황 관리 - 하수처리장별 연결 현황 목록 항목 */
|
||||
export interface SeweragePipeInputFacilityConnectionItem {
|
||||
fcltNm: string;
|
||||
@@ -571,7 +614,11 @@ export interface StatisticsInputSewPipeService {
|
||||
saveRegionalFactStatus(param: SeweragePipeInputRegionalFactStatusSaveRequest): Promise<SeweragePipeInputRegionalFactStatusSaveResponse>;
|
||||
submitRegionalFactStatus(param: SeweragePipeInputRegionalFactStatusSubmitRequest): Promise<SeweragePipeInputRegionalFactStatusSubmitResponse>;
|
||||
saveFactInstallStatus(param: SeweragePipeInputFactInstallStatusSaveRequest): Promise<SeweragePipeInputFactInstallStatusSaveResponse>;
|
||||
submitFactInstallStatus(param: SeweragePipeInputFactInstallStatusSubmitRequest): Promise<SeweragePipeInputFactInstallStatusSubmitResponse>;
|
||||
savePipeTypeStatus(param: SeweragePipeInputPipeTypeStatusSaveRequest): Promise<SeweragePipeInputPipeTypeStatusSaveResponse>;
|
||||
submitPipeTypeStatus(param: SeweragePipeInputPipeTypeStatusSubmitRequest): Promise<SeweragePipeInputSubmitResponse>;
|
||||
savePipeDiameterStatus(param: SeweragePipeInputPipeDiameterStatusSaveRequest): Promise<SeweragePipeInputPipeDiameterStatusSaveResponse>;
|
||||
submitPipeDiameterStatus(param: SeweragePipeInputPipeDiameterStatusSubmitRequest): Promise<SeweragePipeInputSubmitResponse>;
|
||||
saveManholeStatus(param: SeweragePipeInputManholeStatusSaveRequest): Promise<SeweragePipeInputManholeStatusSaveResponse>;
|
||||
submitManholeStatus(param: SeweragePipeInputManholeStatusSubmitRequest): Promise<SeweragePipeInputSubmitResponse>;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import type { ColumnDef } from "@tanstack/react-table";
|
||||
|
||||
import { Checkbox } from "@common/components";
|
||||
|
||||
import type { SewerStUserItem } from "../sewer-st-user-interface";
|
||||
|
||||
export const userListColumns: ColumnDef<SewerStUserItem>[] = [
|
||||
{
|
||||
id: "select",
|
||||
header: ({ table }) => (
|
||||
<div
|
||||
className="flex justify-center"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onKeyDown={(e) => e.stopPropagation()}
|
||||
role="presentation"
|
||||
>
|
||||
<Checkbox
|
||||
checked={
|
||||
table.getIsAllPageRowsSelected() ||
|
||||
(table.getIsSomePageRowsSelected() && "indeterminate")
|
||||
}
|
||||
onCheckedChange={(value) =>
|
||||
table.toggleAllPageRowsSelected(!!value)
|
||||
}
|
||||
aria-label="전체 선택"
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
cell: ({ row }) => (
|
||||
<div
|
||||
className="flex justify-center"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onKeyDown={(e) => e.stopPropagation()}
|
||||
role="presentation"
|
||||
>
|
||||
<Checkbox
|
||||
checked={row.getIsSelected()}
|
||||
onCheckedChange={(value) => row.toggleSelected(!!value)}
|
||||
aria-label="행 선택"
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
enableSorting: false,
|
||||
enableHiding: false,
|
||||
},
|
||||
{
|
||||
accessorKey: "userNm",
|
||||
header: "이름",
|
||||
},
|
||||
{
|
||||
accessorKey: "sido",
|
||||
header: "시도",
|
||||
},
|
||||
{
|
||||
accessorKey: "gugun",
|
||||
header: "시군구",
|
||||
},
|
||||
{
|
||||
accessorKey: "gubunNm",
|
||||
header: "구분",
|
||||
},
|
||||
{
|
||||
accessorKey: "deptNm",
|
||||
header: "소속",
|
||||
},
|
||||
{
|
||||
accessorKey: "jbgdNm",
|
||||
header: "직급",
|
||||
},
|
||||
{
|
||||
accessorKey: "telNo",
|
||||
header: "전화번호",
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,30 @@
|
||||
import type { SewerStUserItem } from "../sewer-st-user-interface";
|
||||
|
||||
export interface NtftalkTemplate {
|
||||
templateCode: string;
|
||||
templateName: string;
|
||||
templateContent: string;
|
||||
}
|
||||
|
||||
export interface TemplateVariablesResponse {
|
||||
templateCode: string;
|
||||
variables: string[];
|
||||
count: number;
|
||||
}
|
||||
|
||||
export interface BusinessSendRequest {
|
||||
templateCode: string;
|
||||
callback?: string;
|
||||
fixedRecipientNum?: string;
|
||||
recipients: Record<string, string>[];
|
||||
}
|
||||
|
||||
export interface BusinessSendResponse {
|
||||
success: boolean;
|
||||
sentCount: number;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface SelectedRecipient extends SewerStUserItem {
|
||||
variableOverrides: Record<string, string>;
|
||||
}
|
||||
+12
@@ -18,6 +18,8 @@ export interface StAnlsDtlResponse {
|
||||
nmlDataNocs: number; // 정상 데이터 건수
|
||||
exclDataNocs: number; // 제외 데이터 건수
|
||||
otlrDataNocs: number; // 이상치 데이터 건수
|
||||
cfmtnYn: string; // 확정여부 (Y/N)
|
||||
cfmtnDt: string | null; // 확정일자 (yyyy-MM-dd HH:mm:ss)
|
||||
statsCd: string; // 통계 코드
|
||||
statsNm: string; // 통계 항목 명
|
||||
vrfcTrgtNm: string; // 검증대상명
|
||||
@@ -30,3 +32,13 @@ export interface StAnlsDtlSearchParams extends PageableParams {
|
||||
}
|
||||
|
||||
export type StAnlsDtlListApiResponse = PageableList<StAnlsDtlResponse>;
|
||||
|
||||
export interface StAnlsDtlConfirmRequest {
|
||||
anlsSn: number; // 분석 일련번호
|
||||
vrfcTrgtSnList: number[]; // 검증 대상 일련번호 목록
|
||||
}
|
||||
|
||||
export interface StAnlsDtlConfirmResponse {
|
||||
anlsSn: number; // 분석 일련번호
|
||||
processedCount: number; // 처리된 검증 대상 건수
|
||||
}
|
||||
|
||||
+3
-2
@@ -45,13 +45,15 @@ export interface StAnlsMstResponseDto {
|
||||
/** 검증대상명 */
|
||||
vrfcTrgtNm: string;
|
||||
/** 분석진행비율 */
|
||||
anlsPrgrsRt: number;
|
||||
anlsPrgrsRt: number | null;
|
||||
/** 하수도사업자코드 */
|
||||
sewerBzmnCd: string;
|
||||
/** 통계코드 */
|
||||
statsCd: string;
|
||||
/** 검증방법코드 */
|
||||
vrfcMthdCd: string;
|
||||
/** 확정건수/총건수 (예: 3/10) */
|
||||
cfmtnYnCntTotalCnt: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,7 +134,6 @@ export interface StAnlsOutlierListResponseDto {
|
||||
outlierDataList: StAnlsOutlierDataResponseDto[];
|
||||
}
|
||||
|
||||
/** 기존 인터페이스 호환을 위한 별칭 (필요 시 유지) */
|
||||
export type StAnlsMstResponse = StAnlsMstResponseDto;
|
||||
export type StAnlsMstImrResponse = StAnlsMstImrResponseDto;
|
||||
export type StAnlsMstSearchParams = StAnlsMstSearchDto;
|
||||
|
||||
+6
@@ -77,6 +77,12 @@ export const verificationHistoryColumns = [
|
||||
<div className="px-2 py-4">{info.getValue() ?? "-"}</div>
|
||||
),
|
||||
}),
|
||||
columnHelper.accessor("cfmtnYnCntTotalCnt", {
|
||||
header: "확정건수/총",
|
||||
cell: (info) => (
|
||||
<div className="px-2 py-4">{info.getValue() ?? "-"}</div>
|
||||
),
|
||||
}),
|
||||
columnHelper.accessor("nmlDataNocs", {
|
||||
header: "정상건수",
|
||||
cell: (info) => (
|
||||
|
||||
+117
-87
@@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
|
||||
import type { ColumnDef } from "@tanstack/react-table";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
import { Checkbox } from "@common/components";
|
||||
|
||||
@@ -16,94 +17,123 @@ export const getVerificationListColumns = ({
|
||||
rowData,
|
||||
checkedSns,
|
||||
onCheck,
|
||||
}: GetVerificationListColumnsParams): ColumnDef<StAnlsDtlResponse>[] => [
|
||||
{
|
||||
id: "checkbox",
|
||||
header: () => {
|
||||
const isAllChecked =
|
||||
rowData.length > 0 && checkedSns.length === rowData.length;
|
||||
return (
|
||||
<div className="flex items-center justify-center">
|
||||
<Checkbox
|
||||
checked={isAllChecked}
|
||||
onCheckedChange={(value: boolean) => {
|
||||
if (value) {
|
||||
onCheck(
|
||||
rowData.map((r) => String(r.vrfcTrgtSn)),
|
||||
rowData,
|
||||
}: GetVerificationListColumnsParams): ColumnDef<StAnlsDtlResponse>[] => {
|
||||
const selectableRows = rowData.filter((r) => r.cfmtnYn !== "Y");
|
||||
|
||||
return [
|
||||
{
|
||||
id: "checkbox",
|
||||
header: () => {
|
||||
const isAllChecked =
|
||||
selectableRows.length > 0 &&
|
||||
checkedSns.length === selectableRows.length;
|
||||
return (
|
||||
<div className="flex items-center justify-center">
|
||||
<Checkbox
|
||||
checked={isAllChecked}
|
||||
disabled={selectableRows.length === 0}
|
||||
onCheckedChange={(value: boolean) => {
|
||||
if (value) {
|
||||
onCheck(
|
||||
selectableRows.map((r) =>
|
||||
String(r.vrfcTrgtSn),
|
||||
),
|
||||
selectableRows,
|
||||
);
|
||||
} else {
|
||||
onCheck([], []);
|
||||
}
|
||||
}}
|
||||
aria-label="Select all rows"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
cell: ({ row }) => {
|
||||
if (row.original.cfmtnYn === "Y") {
|
||||
return <div className="flex items-center justify-center" />;
|
||||
}
|
||||
const rowId = String(row.original.vrfcTrgtSn);
|
||||
const isChecked = checkedSns.includes(rowId);
|
||||
return (
|
||||
<div className="flex items-center justify-center">
|
||||
<Checkbox
|
||||
checked={isChecked}
|
||||
onCheckedChange={(value: boolean) => {
|
||||
const newCheckedSns = value
|
||||
? [...checkedSns, rowId]
|
||||
: checkedSns.filter((id) => id !== rowId);
|
||||
const newCheckedRows = selectableRows.filter(
|
||||
(r) =>
|
||||
newCheckedSns.includes(
|
||||
String(r.vrfcTrgtSn),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
onCheck([], []);
|
||||
onCheck(newCheckedSns, newCheckedRows);
|
||||
}}
|
||||
onClick={(e: React.MouseEvent) =>
|
||||
e.stopPropagation()
|
||||
}
|
||||
}}
|
||||
aria-label="Select all rows"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
aria-label={`Select row ${rowId}`}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
enableSorting: false,
|
||||
enableHiding: false,
|
||||
},
|
||||
cell: ({ row }) => {
|
||||
const rowId = String(row.original.vrfcTrgtSn);
|
||||
const isChecked = checkedSns.includes(rowId);
|
||||
return (
|
||||
<div className="flex items-center justify-center">
|
||||
<Checkbox
|
||||
checked={isChecked}
|
||||
onCheckedChange={(value: boolean) => {
|
||||
const newCheckedSns = value
|
||||
? [...checkedSns, rowId]
|
||||
: checkedSns.filter((id) => id !== rowId);
|
||||
const newCheckedRows = rowData.filter((r) =>
|
||||
newCheckedSns.includes(String(r.vrfcTrgtSn)),
|
||||
);
|
||||
onCheck(newCheckedSns, newCheckedRows);
|
||||
}}
|
||||
onClick={(e: React.MouseEvent) => e.stopPropagation()}
|
||||
aria-label={`Select row ${rowId}`}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
{
|
||||
header: "통계 년도",
|
||||
accessorKey: "statsYr",
|
||||
},
|
||||
enableSorting: false,
|
||||
enableHiding: false,
|
||||
},
|
||||
{
|
||||
header: "통계 년도",
|
||||
accessorKey: "statsYr",
|
||||
},
|
||||
{
|
||||
header: "통계 항목",
|
||||
accessorKey: "statsNm",
|
||||
},
|
||||
{
|
||||
header: "검증 항목",
|
||||
accessorKey: "vrfcTrgtNm",
|
||||
},
|
||||
{
|
||||
header: "μ",
|
||||
accessorKey: "ipcrCntVl",
|
||||
},
|
||||
{
|
||||
header: "Percentile",
|
||||
accessorKey: "pctlCrtrVl",
|
||||
},
|
||||
{
|
||||
header: "A",
|
||||
accessorKey: "scopAjmtCntVl",
|
||||
},
|
||||
{
|
||||
header: "C",
|
||||
accessorKey: "thrsCntVl",
|
||||
},
|
||||
{
|
||||
header: "정상건수",
|
||||
accessorKey: "nmlDataNocs",
|
||||
},
|
||||
{
|
||||
header: "제외건수",
|
||||
accessorKey: "exclDataNocs",
|
||||
},
|
||||
{
|
||||
header: "이상건수",
|
||||
accessorKey: "otlrDataNocs",
|
||||
},
|
||||
];
|
||||
{
|
||||
header: "통계 항목",
|
||||
accessorKey: "statsNm",
|
||||
},
|
||||
{
|
||||
header: "검증 항목",
|
||||
accessorKey: "vrfcTrgtNm",
|
||||
},
|
||||
{
|
||||
header: "확정일자",
|
||||
accessorKey: "cfmtnDt",
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<div className="text-center">
|
||||
{row.original.cfmtnDt
|
||||
? dayjs(row.original.cfmtnDt).format("YYYY-MM-DD")
|
||||
: "-"}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
header: "μ",
|
||||
accessorKey: "ipcrCntVl",
|
||||
},
|
||||
{
|
||||
header: "Percentile",
|
||||
accessorKey: "pctlCrtrVl",
|
||||
},
|
||||
{
|
||||
header: "A",
|
||||
accessorKey: "scopAjmtCntVl",
|
||||
},
|
||||
{
|
||||
header: "C",
|
||||
accessorKey: "thrsCntVl",
|
||||
},
|
||||
{
|
||||
header: "정상건수",
|
||||
accessorKey: "nmlDataNocs",
|
||||
},
|
||||
{
|
||||
header: "제외건수",
|
||||
accessorKey: "exclDataNocs",
|
||||
},
|
||||
{
|
||||
header: "이상건수",
|
||||
accessorKey: "otlrDataNocs",
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
@@ -1,29 +1,30 @@
|
||||
import { AxiosError } from "axios";
|
||||
import { useMutation, type UseMutationOptions } from "@tanstack/react-query";
|
||||
import { AxiosError } from "axios";
|
||||
|
||||
import { useAlertStore } from "./use-alert-store";
|
||||
|
||||
export const useMutationWrapper = <
|
||||
TData = unknown,
|
||||
TError = unknown,
|
||||
TVariables = void,
|
||||
TContext = unknown,
|
||||
TData = unknown,
|
||||
TError = unknown,
|
||||
TVariables = void,
|
||||
TContext = unknown,
|
||||
>(
|
||||
mutationOptions: UseMutationOptions<TData, TError, TVariables, TContext>,
|
||||
mutationOptions: UseMutationOptions<TData, TError, TVariables, TContext>,
|
||||
) => {
|
||||
const alert = useAlertStore((state) => state.setMessage);
|
||||
return useMutation({
|
||||
...mutationOptions,
|
||||
onError: (error) => {
|
||||
let errorMessage = "";
|
||||
const alert = useAlertStore((state) => state.setMessage);
|
||||
return useMutation({
|
||||
...mutationOptions,
|
||||
onError: (error) => {
|
||||
let errorMessage = "";
|
||||
|
||||
if (error instanceof AxiosError) {
|
||||
if (error.response?.data?.message)
|
||||
errorMessage += `${error.response.data.message}\n`;
|
||||
if (error.response?.data?.errors[0]?.message)
|
||||
errorMessage += `${error.response.data.errors[0].message}\n`;
|
||||
}
|
||||
if (error instanceof AxiosError) {
|
||||
if (error.response?.data?.message)
|
||||
errorMessage += `${error.response.data.message}\n`;
|
||||
if (error.response?.data?.errors[0]?.message)
|
||||
errorMessage += `${error.response.data.errors[0].message}\n`;
|
||||
}
|
||||
|
||||
alert(`${errorMessage}`);
|
||||
},
|
||||
});
|
||||
alert(`${errorMessage}`);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user