Merge remote-tracking branch 'origin/iipbs/st/dev'
Deploy Frontend / deploy (push) Successful in 3m54s
Deploy Frontend / deploy (push) Successful in 3m54s
This commit is contained in:
@@ -1115,7 +1115,7 @@ const PublicSewageFacilityInp = () => {
|
||||
if (!verification) return;
|
||||
const errors = verification[fieldName];
|
||||
if (Array.isArray(errors) && errors.length > 0) {
|
||||
const hasImr = errors.some((e) => e.vrfcCd === "IMR");
|
||||
const hasImr = errors.some((e) => e.vrfcCd === "IMR" || e.vrfcCd === "HB");
|
||||
return hasImr ? "rg-cell-verify-error-imr" : "rg-cell-verify-error";
|
||||
}
|
||||
}}
|
||||
@@ -1127,10 +1127,11 @@ const PublicSewageFacilityInp = () => {
|
||||
return errors
|
||||
.map((e) => {
|
||||
const prefix =
|
||||
e.vrfcCd === "IMR" ? "IMR검증 - " : "일반검증 - ";
|
||||
e.vrfcCd === "IMR" ? "IMR검증 - " : (e.vrfcCd === "NV" ? "일반검증 - " : "HB검증 - ");
|
||||
const comp = e.compVlCn ?? "";
|
||||
const now = e.nowVlCn ?? "";
|
||||
return `${prefix}${e.rsnExpln}(검증 기준값: ${comp} / 현재 입력값: ${now})`;
|
||||
return `${prefix}${e.rsnExpln}
|
||||
(검증 기준값: ${comp} / 현재 입력값: ${now})`;
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join("\n");
|
||||
|
||||
@@ -1978,7 +1978,7 @@ const SewagePipeInp = () => {
|
||||
if (!verification) return;
|
||||
const errors = verification[fieldName];
|
||||
if (Array.isArray(errors) && errors.length > 0) {
|
||||
const hasImr = errors.some((e) => e.vrfcCd === "IMR");
|
||||
const hasImr = errors.some((e) => e.vrfcCd === "IMR" || e.vrfcCd === "HB");
|
||||
return hasImr ? "rg-cell-verify-error-imr" : "rg-cell-verify-error";
|
||||
}
|
||||
}}
|
||||
@@ -1990,10 +1990,11 @@ const SewagePipeInp = () => {
|
||||
return errors
|
||||
.map((e) => {
|
||||
const prefix =
|
||||
e.vrfcCd === "IMR" ? "IMR검증 - " : "일반검증 - ";
|
||||
e.vrfcCd === "IMR" ? "IMR검증 - " : (e.vrfcCd === "NV" ? "일반검증 - " : "HB검증 - ");
|
||||
const comp = e.compVlCn ?? "";
|
||||
const now = e.nowVlCn ?? "";
|
||||
return `${prefix}${e.rsnExpln}(검증 기준값: ${comp} / 현재 입력값: ${now})`;
|
||||
return `${prefix}${e.rsnExpln}
|
||||
(검증 기준값: ${comp} / 현재 입력값: ${now})`;
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join("\n");
|
||||
|
||||
@@ -766,7 +766,7 @@ const SeweragePenetrationRateInp = () => {
|
||||
const errors = verification[fieldName];
|
||||
if (Array.isArray(errors) && errors.length > 0) {
|
||||
// IMR 검증은 노란색으로 구분
|
||||
const hasImr = errors.some((e) => e.vrfcCd === 'IMR');
|
||||
const hasImr = errors.some((e) => e.vrfcCd === 'IMR' || e.vrfcCd === 'HB');
|
||||
return hasImr ? 'rg-cell-verify-error-imr' : 'rg-cell-verify-error';
|
||||
}
|
||||
}}
|
||||
@@ -777,8 +777,9 @@ const SeweragePenetrationRateInp = () => {
|
||||
if (Array.isArray(errors) && errors.length > 0) {
|
||||
return errors
|
||||
.map((e) => {
|
||||
const prefix = e.vrfcCd === 'IMR' ? 'IMR검증 - ' : '일반검증 - ';
|
||||
return `${prefix}${e.rsnExpln}(검증 기준값: ${e.compVlCn} / 현재 입력값: ${e.nowVlCn})`;
|
||||
const prefix = e.vrfcCd === 'IMR' ? 'IMR검증 - ' : (e.vrfcCd === 'NM' ? '일반검증 - ' : 'HB검증 -');
|
||||
return `${prefix}${e.rsnExpln}
|
||||
(검증 기준값: ${e.compVlCn} / 현재 입력값: ${e.nowVlCn})`;
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join('\n');
|
||||
|
||||
@@ -4,13 +4,17 @@ import { RealGridReact } from "realgrid-react";
|
||||
import useSWR, { useSWRConfig } from "swr";
|
||||
|
||||
import { useAlertStore } from "@/shared/lib";
|
||||
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
||||
import { StatisticsInputStatusApi } from "@/entities/statistics/api/input/statistics-input-status-service";
|
||||
import {
|
||||
isInputPeriodCurrent,
|
||||
type CheckInputPeriodItem,
|
||||
} from "@/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface";
|
||||
import type { StatsInputStatusListRequestParams } from "@/entities/statistics/model/input/statistics-input-status-interface";
|
||||
import type { StatsInputStatusListApiResponse } from "@/entities/statistics/model/input/statistics-input-status-interface";
|
||||
import { LoadingWithAnimation } from "@common/components";
|
||||
|
||||
import ApproveButton from "@/components/button/ApproveButton";
|
||||
import RejectButton from "@/components/button/RejectButton";
|
||||
import DataGrid from "@/components/module/DataGrid";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||
@@ -37,6 +41,8 @@ const StatsInputStatusInp = () => {
|
||||
const [lastSearchedValues, setLastSearchedValues] =
|
||||
useState<SearchFormValues | null>(null);
|
||||
const [hasCompletedSearch, setHasCompletedSearch] = useState(false);
|
||||
const periodCheckListRef = useRef<CheckInputPeriodItem[]>([]);
|
||||
const inputPeriodCurrentRef = useRef(false);
|
||||
const gridRef = useRef<RealGridReact | null>(null);
|
||||
|
||||
const swrKey = searchParams
|
||||
@@ -72,21 +78,38 @@ const StatsInputStatusInp = () => {
|
||||
}
|
||||
}, [activeTabId]);
|
||||
|
||||
const handleSearch = (values: SearchFormValues) => {
|
||||
const handleSearch = async (values: SearchFormValues) => {
|
||||
if (values.sido === "" || values.sido === "ALL") {
|
||||
alert("시도를 선택해주세요.");
|
||||
return;
|
||||
}
|
||||
const params: StatsInputStatusListRequestParams = {
|
||||
ctpvNm: values.sido,
|
||||
sewerBzmnCd: values.bsnmCd,
|
||||
sggNm: values.gugun === "ALL" ? "" : values.gugun,
|
||||
statsYr: values.year ?? "",
|
||||
};
|
||||
setHasCompletedSearch(false);
|
||||
setLastSearchedValues(values);
|
||||
setSearchParams(params);
|
||||
mutate(["stats-input-status", params]);
|
||||
|
||||
try {
|
||||
const response = await statisticsInputSewSupplyRateApi.checkInputPeriod(values.year || "");
|
||||
|
||||
if (response.status !== "success") {
|
||||
alert(response.message ?? "입력기간 확인에 실패했습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
const periods = Array.isArray(response.data) ? response.data : [];
|
||||
periodCheckListRef.current = periods;
|
||||
const checkEnterable = isInputPeriodCurrent(periods);
|
||||
inputPeriodCurrentRef.current = checkEnterable;
|
||||
|
||||
const params: StatsInputStatusListRequestParams = {
|
||||
ctpvNm: values.sido,
|
||||
sewerBzmnCd: values.bsnmCd,
|
||||
sggNm: values.gugun === "ALL" ? "" : values.gugun,
|
||||
statsYr: values.year ?? "",
|
||||
};
|
||||
setHasCompletedSearch(false);
|
||||
setLastSearchedValues(values);
|
||||
setSearchParams(params);
|
||||
mutate(["stats-input-status", params]);
|
||||
} catch {
|
||||
alert("데이터 조회 중 오류가 발생했습니다.");
|
||||
}
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
@@ -94,10 +117,8 @@ const StatsInputStatusInp = () => {
|
||||
setRowData([]);
|
||||
setLastSearchedValues(null);
|
||||
setHasCompletedSearch(false);
|
||||
};
|
||||
|
||||
const rejectFunc = () => {
|
||||
// 보완 요청 로직
|
||||
periodCheckListRef.current = [];
|
||||
inputPeriodCurrentRef.current = false;
|
||||
};
|
||||
|
||||
const approveFunc = () => {
|
||||
@@ -125,7 +146,7 @@ const StatsInputStatusInp = () => {
|
||||
? Boolean(lastSearchedValues?.gugun && lastSearchedValues.gugun !== "ALL")
|
||||
: true;
|
||||
const showActionToolbarCard =
|
||||
hasCompletedSearch && rowData.length > 0 && gugunOkOrNotDoList;
|
||||
hasCompletedSearch && rowData.length > 0 && gugunOkOrNotDoList && inputPeriodCurrentRef.current;
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -134,7 +155,6 @@ const StatsInputStatusInp = () => {
|
||||
{showActionToolbarCard && (
|
||||
<div className="card !py-0">
|
||||
<div className="m-[0.6rem] flex items-center justify-end gap-[0.6rem]">
|
||||
<RejectButton rejectFunc={rejectFunc} />
|
||||
<ApproveButton approveFunc={approveFunc} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
import { useMemo, useState } from "react";
|
||||
|
||||
import { LoadingWithAnimation } from "@common/components";
|
||||
import { getUserInfo } from "../../../../../../packages/common/components/src/api";
|
||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||
import { useAlertStore } from "@/shared/lib";
|
||||
import { useAlertStore, useUserStore } from "@/shared/lib";
|
||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
||||
import type { PublicSewageFacilityReviewItem } from "@/entities/statistics/model/statistics-public-sewage-facility-review-interface";
|
||||
import type { StatsStatusInfo } from "@/entities/statistics/model/statistics-sewage-pipe-review-interface";
|
||||
import type { ReviewOpinionSaveRequest } from "@/entities/statistics/model/statistics-interface";
|
||||
import type {
|
||||
ReviewOpinionSaveRequest,
|
||||
ReviewerInfoRequest,
|
||||
} from "@/entities/statistics/model/statistics-interface";
|
||||
import DataGrid from "@/components/module/DataGrid";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import SubmitButton from "@/components/button/SumitButton";
|
||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||
import ReturnButton from "@/components/button/ReturnButton";
|
||||
import { ReturnReasonDialog } from "@/components/statistics/review/ReturnReasonDialog";
|
||||
import { ReviewSubmitDialog } from "@/components/statistics/review/ReviewSubmitDialog";
|
||||
import {
|
||||
ReviewOpinionDialog,
|
||||
type ReviewOpinionDialogContext,
|
||||
@@ -27,12 +29,13 @@ import { PublicSewageFacilityInfoList } from "@/components/util/column/review/Pu
|
||||
// 하수도 통계 관리 06.공공하수처리시설
|
||||
const PublicSewageFacilityRvw = () => {
|
||||
const { setMessage: alert } = useAlertStore((state) => state);
|
||||
const { confirm } = useConfirm();
|
||||
const userInfo = useUserStore((state) => state.userInfo);
|
||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [statsStatusInfo, setStatsStatusInfo] = useState<StatsStatusInfo>({});
|
||||
const [reviewOpinionOpen, setReviewOpinionOpen] = useState(false);
|
||||
const [returnDialogOpen, setReturnDialogOpen] = useState(false);
|
||||
const [submitDialogOpen, setSubmitDialogOpen] = useState(false);
|
||||
const [reviewOpinionContext, setReviewOpinionContext] =
|
||||
useState<ReviewOpinionDialogContext | null>(null);
|
||||
const [latestReviewOpinion, setLatestReviewOpinion] = useState("");
|
||||
@@ -67,6 +70,24 @@ const PublicSewageFacilityRvw = () => {
|
||||
const showActionBar =
|
||||
showReviewOpinionButton || showReturnButton || showSubmitButton;
|
||||
|
||||
const submitDialogContext = useMemo<ReviewerInfoRequest | null>(() => {
|
||||
if (reviewOpinionContext == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const instSeCd = userInfo?.instSeCd ?? "";
|
||||
if (!instSeCd) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
statsYr: reviewOpinionContext.statsYr,
|
||||
sewerBzmnCd: reviewOpinionContext.sewerBzmnCd,
|
||||
statsCd: reviewOpinionContext.statsCd,
|
||||
instSeCd,
|
||||
};
|
||||
}, [reviewOpinionContext, userInfo?.instSeCd]);
|
||||
|
||||
const handleReset = () => {
|
||||
setRowData([]);
|
||||
setStatsStatusInfo({});
|
||||
@@ -74,6 +95,7 @@ const PublicSewageFacilityRvw = () => {
|
||||
setLatestReviewOpinion("");
|
||||
setLatestProcessHistory("");
|
||||
setLastSearchValues(null);
|
||||
setSubmitDialogOpen(false);
|
||||
};
|
||||
|
||||
const handleSearch = async (values: SearchFormValues) => {
|
||||
@@ -134,37 +156,13 @@ const PublicSewageFacilityRvw = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const submitFunc = async () => {
|
||||
if (reviewOpinionContext == null) {
|
||||
const submitFunc = () => {
|
||||
if (submitDialogContext == null) {
|
||||
alert("조회 후 제출할 수 있습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(await confirm("제출 하시겠습니까?"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const userInfo = await getUserInfo();
|
||||
const response = await statisticsApi.submitReview({
|
||||
statsYr: reviewOpinionContext.statsYr,
|
||||
sewerBzmnCd: reviewOpinionContext.sewerBzmnCd,
|
||||
statsCd: reviewOpinionContext.statsCd,
|
||||
mdfrId: userInfo.userUnqId,
|
||||
});
|
||||
|
||||
if (response.status !== "success") {
|
||||
alert(response.message || "제출에 실패했습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
alert(response.message || "제출되었습니다.");
|
||||
if (lastSearchValues != null) {
|
||||
await handleSearch(lastSearchValues);
|
||||
}
|
||||
} catch {
|
||||
alert("제출 중 오류가 발생했습니다.");
|
||||
}
|
||||
setSubmitDialogOpen(true);
|
||||
};
|
||||
|
||||
const reviewOpinionFunc = async () => {
|
||||
@@ -261,6 +259,16 @@ const PublicSewageFacilityRvw = () => {
|
||||
initialProcessHistory={latestProcessHistory}
|
||||
onSave={saveReviewOpinion}
|
||||
/>
|
||||
<ReviewSubmitDialog
|
||||
open={submitDialogOpen}
|
||||
onOpenChange={setSubmitDialogOpen}
|
||||
context={submitDialogContext}
|
||||
onSubmitted={async () => {
|
||||
if (lastSearchValues != null) {
|
||||
await handleSearch(lastSearchValues);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<ReturnReasonDialog
|
||||
open={returnDialogOpen}
|
||||
onOpenChange={setReturnDialogOpen}
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
border-radius: 0.5rem !important;
|
||||
/* box-shadow: 0 0 10px -1px rgba(0, 0, 0, 0.06); */
|
||||
}
|
||||
|
||||
/* 헤더 스타일 */
|
||||
.rg-header,
|
||||
.rg-head,
|
||||
@@ -115,4 +114,4 @@
|
||||
.rg-cell-verify-error {
|
||||
background-color: #ffe6e6 !important;
|
||||
color: #c00 !important;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user