This commit is contained in:
@@ -141,6 +141,7 @@ const verificationResultColumnInfo: ColumnInfo = {
|
||||
columns: [
|
||||
{ name: "ctpvNm", fieldName: "ctpvNm", header: { text: "시도" }, editable: false },
|
||||
{ name: "admdstNm", fieldName: "admdstNm", header: { text: "행정구역" }, editable: false },
|
||||
{ name: "fcltNm", fieldName: "fcltNm", header: { text: "시설명" }, editable: false },
|
||||
{ name: "vrfcTrgtNm", fieldName: "vrfcTrgtNm", header: { text: "검증대상" }, editable: false },
|
||||
{ name: "rsnExpln", fieldName: "rsnExpln", header: { text: "사유" }, editable: false },
|
||||
{ name: "nowVlCn", fieldName: "nowVlCn", header: { text: "입력값" }, editable: false },
|
||||
@@ -157,6 +158,7 @@ const verificationResultColumnInfo: ColumnInfo = {
|
||||
columnLayout: [
|
||||
"ctpvNm",
|
||||
"admdstNm",
|
||||
"fcltNm",
|
||||
"vrfcTrgtNm",
|
||||
"rsnExpln",
|
||||
"nowVlCn",
|
||||
@@ -178,7 +180,7 @@ export interface VerificationResultHistoryDialogProps {
|
||||
queryContext?: {
|
||||
sewerBzmnCd: string;
|
||||
ctpvNm: string;
|
||||
sggNm: string;
|
||||
sggNm?: string;
|
||||
statsYr: string;
|
||||
statsCd: string;
|
||||
} | null;
|
||||
@@ -378,8 +380,9 @@ export function VerificationResultHistoryDialog({
|
||||
return {
|
||||
vrfcSn: item.vrfcSn,
|
||||
__checked: isChecked ? 1 : 0,
|
||||
ctpvNm: item.ctpvNm,
|
||||
ctpvNm: item.ctpvNm ?? "-",
|
||||
admdstNm: item.admdstNm ?? item.sggNm ?? "-",
|
||||
fcltNm: item.fcltNm ?? "-",
|
||||
vrfcTrgtNm: item.vrfcTrgtNm,
|
||||
rsnExpln: item.rsnExpln,
|
||||
nowVlCn: item.nowVlCn ?? "-",
|
||||
@@ -562,7 +565,7 @@ export function VerificationResultHistoryDialog({
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent className="max-w-[80%]" aria-describedby={undefined}>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{`${title} - ${queryContext?.statsYr} ${queryContext?.ctpvNm} ${queryContext?.sggNm}`}</DialogTitle>
|
||||
<DialogTitle>{`${title} - ${queryContext?.statsYr} ${queryContext?.ctpvNm} ${queryContext?.sggNm ? queryContext?.sggNm : ''}`}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="max-h-[85vh] space-y-5 overflow-auto">
|
||||
{errorMessage && (
|
||||
|
||||
+4
-1
@@ -632,6 +632,7 @@ const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => {
|
||||
kornArtopnEqtnCn: string;
|
||||
engArtopnEqtnCn: string;
|
||||
refStatsCd: string | null;
|
||||
refStatsNm: string | null;
|
||||
}) => {
|
||||
setRuleBlocks((prev) => {
|
||||
const i = prev.findIndex(
|
||||
@@ -650,11 +651,12 @@ const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => {
|
||||
kornArtopnEqtnCn: payload.kornArtopnEqtnCn,
|
||||
engArtopnEqtnCn: payload.engArtopnEqtnCn,
|
||||
refStatsCd: payload.refStatsCd,
|
||||
refStatsNm: payload.refStatsNm,
|
||||
}
|
||||
: {
|
||||
vrfcDtlSn: null,
|
||||
refStatsCd: payload.refStatsCd,
|
||||
refStatsNm: null,
|
||||
refStatsNm: payload.refStatsNm,
|
||||
kornArtopnEqtnCn: payload.kornArtopnEqtnCn,
|
||||
engArtopnEqtnCn: payload.engArtopnEqtnCn,
|
||||
cmprOpert: null,
|
||||
@@ -1034,6 +1036,7 @@ const DetailComponent = ({ selectedVrfcRow }: DetailComponentProps) => {
|
||||
);
|
||||
}
|
||||
}}
|
||||
vrfcClsfCd={detailInfo?.commonInfo.vrfcClsfCd}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
+62
-17
@@ -1,9 +1,12 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
import { useAlertStore } from "@/shared/lib";
|
||||
import { CodeSelect } from "@/entities/code";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import { CodeApi } from "@/entities/code";
|
||||
import { generalverificationApiService } from "@/entities/statistics/api/general-verification-service";
|
||||
import type { SelectedVerifyColumnListResponseData,VerifyColumnListResponseData, VerifyDetailResponseDto } from "@/entities/statistics/model/general-verification-interface";
|
||||
import type { SelectedVerifyColumnListResponseData, VerifyColumnListResponseData, VerifyDetailResponseDto } from "@/entities/statistics/model/general-verification-interface";
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
@@ -14,6 +17,11 @@ import {
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
Input,
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
Skeleton,
|
||||
Textarea,
|
||||
} from "@common/components";
|
||||
@@ -21,8 +29,10 @@ import {
|
||||
export interface FomulaDialogConfirmPayload {
|
||||
kornArtopnEqtnCn: string;
|
||||
engArtopnEqtnCn: string;
|
||||
/** 참조 통계코드 (선택 안 했으면 null) */
|
||||
/** 참조 통계코드 (수식에 참조 컬럼이 없으면 null) */
|
||||
refStatsCd: string | null;
|
||||
/** 참조 통계명 (수식에 참조 컬럼이 없으면 null) */
|
||||
refStatsNm: string | null;
|
||||
}
|
||||
|
||||
interface FomulaDialogProps {
|
||||
@@ -63,6 +73,11 @@ const FomulaDialog = ({ open, onOpenChange, data, trgtStatsCd, trgtStatsNm, allo
|
||||
const isUserDirectInputMode = allowLikeDirectInput && userDirectInput;
|
||||
|
||||
const { setMessage: alert } = useAlertStore((state) => state);
|
||||
const { data: statsItemCodes } = useQuery({
|
||||
queryKey: [ENDPOINT.CMS_SERVICE.CODE, "STITEM"],
|
||||
queryFn: () => CodeApi.getCode("STITEM"),
|
||||
enabled: open,
|
||||
});
|
||||
|
||||
/** 다이얼로그에서 쓰는 기호 → 제출용 value. 백엔드 규격에 맞게 수정 가능 */
|
||||
const OPERATOR_SYMBOL_TO_VALUE: Record<string, string> = {
|
||||
@@ -375,6 +390,7 @@ const FomulaDialog = ({ open, onOpenChange, data, trgtStatsCd, trgtStatsNm, allo
|
||||
|
||||
const handleChangeRefStatsCd = (next: string) => {
|
||||
if (!open) return;
|
||||
if (trgtStatsCd && next === trgtStatsCd) return;
|
||||
|
||||
// 현재 refStatsCdLocal에 해당하는 참조 컬럼이 수식에 포함돼 있으면 변경을 막고 안내만 표시
|
||||
const currentRefCols = refColList ?? [];
|
||||
@@ -404,6 +420,26 @@ const FomulaDialog = ({ open, onOpenChange, data, trgtStatsCd, trgtStatsNm, allo
|
||||
/** 참조 컬럼: 선택한 참조 통계로 조회한 목록이 있으면 사용, 없으면 getVerifyColumnList 결과 사용 */
|
||||
const refColList = selectedColumnInfo?.targetColumnInfo?.colList ?? columnInfo?.refColumnInfo?.colList ?? [];
|
||||
|
||||
const formulaUsesRefColumn = (): boolean => {
|
||||
const engSet = new Set(refColList.map((c) => c.engColNm).filter(Boolean));
|
||||
if (engSet.size === 0) return false;
|
||||
return formulaValueSegments.some((seg) => engSet.has(seg));
|
||||
};
|
||||
|
||||
const resolveRefStatsForConfirm = (isEmptyFormula: boolean): {
|
||||
refStatsCd: string | null;
|
||||
refStatsNm: string | null;
|
||||
} => {
|
||||
if (isEmptyFormula || !formulaUsesRefColumn() || !refStatsCdLocal) {
|
||||
return { refStatsCd: null, refStatsNm: null };
|
||||
}
|
||||
const refStatsNm =
|
||||
statsItemCodes?.find((item) => item.lwpoCd === refStatsCdLocal)?.lwpoCdNm
|
||||
?? data?.refStatsNm
|
||||
?? null;
|
||||
return { refStatsCd: refStatsCdLocal, refStatsNm };
|
||||
};
|
||||
|
||||
const handleOpenChange = (nextOpen: boolean) => {
|
||||
if (!nextOpen) {
|
||||
setFormulaDisplaySegments([]);
|
||||
@@ -528,11 +564,10 @@ const FomulaDialog = ({ open, onOpenChange, data, trgtStatsCd, trgtStatsNm, allo
|
||||
)}
|
||||
</div>
|
||||
<Textarea
|
||||
className={`w-full flex-1 resize-none !text-3xl p-4 !leading-loose font-bold ${
|
||||
isUserDirectInputMode
|
||||
className={`w-full flex-1 resize-none !text-3xl p-4 !leading-loose font-bold ${isUserDirectInputMode
|
||||
? "bg-white text-gray-900"
|
||||
: "bg-gray-100 text-gray-600"
|
||||
}`}
|
||||
}`}
|
||||
id="formulaDisplayInput"
|
||||
ref={formulaTextareaRef}
|
||||
value={formulaDisplaySegments.join('')}
|
||||
@@ -648,13 +683,25 @@ const FomulaDialog = ({ open, onOpenChange, data, trgtStatsCd, trgtStatsNm, allo
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex gap-2 justify-center items-center">
|
||||
<h3 className="font-bold text-title text-[14px]">참조 컬럼</h3>
|
||||
<CodeSelect
|
||||
upCd="STITEM"
|
||||
<Select
|
||||
value={refStatsCdLocal}
|
||||
onValueChange={handleChangeRefStatsCd}
|
||||
placeholder="선택"
|
||||
className="w-[16rem]"
|
||||
/>
|
||||
>
|
||||
<SelectTrigger className="w-[16rem]">
|
||||
<SelectValue placeholder="선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{statsItemCodes?.map((item) => (
|
||||
<SelectItem
|
||||
key={item.lwpoCd}
|
||||
value={item.lwpoCd}
|
||||
disabled={Boolean(trgtStatsCd) && item.lwpoCd === trgtStatsCd}
|
||||
>
|
||||
{item.lwpoCdNm}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
{(refColList?.length ?? 0) > 0 ?
|
||||
<Button
|
||||
@@ -717,14 +764,11 @@ const FomulaDialog = ({ open, onOpenChange, data, trgtStatsCd, trgtStatsNm, allo
|
||||
const raw = formulaDisplaySegments.join("");
|
||||
const wrapped = wrapWithBacktick(raw);
|
||||
const isEmptyFormula = raw.trim().length === 0;
|
||||
const refStats = resolveRefStatsForConfirm(isEmptyFormula);
|
||||
onConfirm?.({
|
||||
kornArtopnEqtnCn: isEmptyFormula ? raw : wrapped,
|
||||
engArtopnEqtnCn: isEmptyFormula ? raw : wrapped,
|
||||
refStatsCd: isEmptyFormula
|
||||
? null
|
||||
: refStatsCdLocal
|
||||
? refStatsCdLocal
|
||||
: null,
|
||||
...refStats,
|
||||
});
|
||||
onOpenChange?.(false);
|
||||
return;
|
||||
@@ -742,10 +786,11 @@ const FomulaDialog = ({ open, onOpenChange, data, trgtStatsCd, trgtStatsNm, allo
|
||||
const kornArtopnEqtnCn = formulaDisplaySegments.join('');
|
||||
const engArtopnEqtnCn = getFormulaValueForSubmit();
|
||||
const isEmptyFormula = kornArtopnEqtnCn.trim().length === 0;
|
||||
const refStats = resolveRefStatsForConfirm(isEmptyFormula);
|
||||
onConfirm?.({
|
||||
kornArtopnEqtnCn,
|
||||
engArtopnEqtnCn,
|
||||
refStatsCd: isEmptyFormula ? null : (refStatsCdLocal ? refStatsCdLocal : null),
|
||||
...refStats,
|
||||
});
|
||||
onOpenChange?.(false);
|
||||
}}
|
||||
|
||||
+13
-9
@@ -18,6 +18,7 @@ interface FormulaComponentsProps {
|
||||
data?: VerifyDetailResponseDto | null,
|
||||
index?: number,
|
||||
) => void;
|
||||
vrfcClsfCd?: string;
|
||||
}
|
||||
|
||||
const zoneClassName: Record<ClauseZone, string> = {
|
||||
@@ -43,6 +44,7 @@ const FormulaComponents = ({
|
||||
onDelete,
|
||||
onOperatorChange,
|
||||
handleFomulaDialog,
|
||||
vrfcClsfCd,
|
||||
}: FormulaComponentsProps) => {
|
||||
const cmprOpert = data?.cmprOpert;
|
||||
const displayFormula = data
|
||||
@@ -77,15 +79,17 @@ const FormulaComponents = ({
|
||||
onValueChange={onOperatorChange}
|
||||
/>
|
||||
</div>
|
||||
<label className="flex w-[96px] shrink-0 items-center justify-end gap-1.5 text-[#4b5563] cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="cursor-pointer accent-[#3a6df0]"
|
||||
checked={groupBy}
|
||||
onChange={(e) => onGroupByChange?.(e.target.checked)}
|
||||
/>
|
||||
group by
|
||||
</label>
|
||||
{vrfcClsfCd !== "TOTAL" &&
|
||||
<label className="flex w-[96px] shrink-0 items-center justify-end gap-1.5 text-[#4b5563] cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="cursor-pointer accent-[#3a6df0]"
|
||||
checked={groupBy}
|
||||
onChange={(e) => onGroupByChange?.(e.target.checked)}
|
||||
/>
|
||||
group by
|
||||
</label>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -58,6 +58,7 @@ import {
|
||||
export class StatisticsApiService implements StatisticsService {
|
||||
public async getSidoList(params?: {
|
||||
instSeCd?: string;
|
||||
isInput?: boolean;
|
||||
}): Promise<ApiResponse<SearchCondition>> {
|
||||
const response = await stClient.get<ApiResponse<SearchCondition>>(
|
||||
`${ENDPOINT.ST_SERVICE.COMMON}/search-condition`,
|
||||
@@ -66,6 +67,17 @@ export class StatisticsApiService implements StatisticsService {
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async getSidoListInput(params?: {
|
||||
instSeCd?: string;
|
||||
isInput?: boolean;
|
||||
}): Promise<ApiResponse<SearchCondition>> {
|
||||
const response = await stClient.get<ApiResponse<SearchCondition>>(
|
||||
`${ENDPOINT.ST_SERVICE.COMMON}/search-condition-input`,
|
||||
{ params },
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async getSggList(
|
||||
sidoName: string,
|
||||
params?: { instSeCd?: string; gugunSkipYn?: "Y" | "N" },
|
||||
|
||||
@@ -2,6 +2,8 @@ export interface Sido {
|
||||
adstDstrCd: string;
|
||||
sido: string;
|
||||
bsnmCd: string;
|
||||
/** Y: 시군구 생략(광역시 등), N: 시군구 필요(도) */
|
||||
gugunSkipYn: "Y" | "N";
|
||||
}
|
||||
|
||||
export interface SearchCondition {
|
||||
@@ -18,7 +20,7 @@ export interface Sgg {
|
||||
export interface cancelSubmitRequest {
|
||||
statsYr: string;
|
||||
ctpvNm: string;
|
||||
sggNm: string;
|
||||
sggNm?: string;
|
||||
sewerBzmnCd: string;
|
||||
statsCd: string;
|
||||
mdfrId: string;
|
||||
@@ -208,6 +210,7 @@ export interface VerificationResultReportItem {
|
||||
prcrId?: string | null;
|
||||
pbcpAprvYn?: string;
|
||||
mdfrId?: string | null;
|
||||
fcltNm?: string | null;
|
||||
}
|
||||
|
||||
export interface VerificationResultListPageInfo {
|
||||
@@ -233,7 +236,7 @@ export interface SubmitExceptionRequest {
|
||||
statsYr: string;
|
||||
statsCd: string;
|
||||
ctpvNm: string;
|
||||
sggNm: string;
|
||||
sggNm?: string;
|
||||
sewerBzmnCd: string;
|
||||
userId: string;
|
||||
superAdmin?: string;
|
||||
@@ -545,6 +548,7 @@ export interface unSubmitDataResponse {
|
||||
|
||||
export interface StatisticsService {
|
||||
getSidoList(params?: { instSeCd?: string }): Promise<ApiResponse<SearchCondition>>;
|
||||
getSidoListInput(params?: { instSeCd?: string }): Promise<ApiResponse<SearchCondition>>;
|
||||
getSggList(sidoName: string, params?: { instSeCd?: string; gugunSkipYn?: "Y" | "N" }): Promise<ApiResponse<Sgg[]>>;
|
||||
getSggAllList(sidoName: string, params?: { instSeCd?: string; gugunSkipYn?: "Y" | "N" }): Promise<ApiResponse<Sgg[]>>;
|
||||
getStatsInputPeriodList(params?: StatsInputPeriodListRequest): Promise<StatsInputPeriodListApiResponse>;
|
||||
|
||||
Reference in New Issue
Block a user