Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
411e490b5d | ||
|
|
b5f5938e51 | ||
|
|
038b2d441e | ||
|
|
2ec58f1f5b | ||
|
|
3cf3617513 | ||
|
|
b611538180 | ||
|
|
1cffe06cf9 | ||
|
|
9a24e4aa23 | ||
|
|
3732c9380b | ||
|
|
9e15b23eda | ||
|
|
6f300918cd | ||
|
|
619878bc03 |
@@ -33,10 +33,10 @@
|
||||
├──────────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ [영역 B] 필수첨부파일 목록 │
|
||||
│ ┌────────────────────────────────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ 필수첨부파일아이디 | 문서구분 | 필수첨부파일명 | 필수첨부여부 | 필수파일검토내용 | 비고 | 관리 │ │
|
||||
│ │ 필수첨부파일아이디 | 문서구분 | 필수첨부파일명 | 필수첨부여부 | 비고 | 등록일시 | 수정일시 | 관리 │
|
||||
│ ├────────────────────────────────────────────────────────────────────────────────────────────────┤ │
|
||||
│ │ EAF-0001 | 설치인가 | 사업계획서 | 예 | 사업비 내역 검토 | 서명본 첨부 | [수정][삭제] │ │
|
||||
│ │ EAF-0002 | 기본계획 | 변경사유서 | 예 | 변경 전후 비교표 | — | [수정][삭제] │ │
|
||||
│ │ EAF-0001 | 설치인가 | 사업계획서 | 예 | 서명본 첨부 | 2026-04-22 10:10:00 | — | [수정][삭제] │ │
|
||||
│ │ EAF-0002 | 기본계획 | 변경사유서 | 예 | — | 2026-04-22 11:00:00 | — | [수정][삭제] │ │
|
||||
│ └────────────────────────────────────────────────────────────────────────────────────────────────┘ │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
@@ -47,9 +47,7 @@
|
||||
│ 필수첨부파일아이디(자동발급) [EAF-0004] │
|
||||
│ 문서구분 [설치인가 ▼] │
|
||||
│ 필수첨부파일명 [예: 사업계획서] │
|
||||
│ 양식파일 [파일 선택] │
|
||||
│ 필수첨부여부 [ ] 예 [ ] 아니오 │
|
||||
│ 필수파일검토내용 [검토내용을 입력하세요]│
|
||||
│ 비고 [비고를 입력하세요] │
|
||||
├──────────────────────────────────────────────────────┤
|
||||
│ [취소] [저장] │
|
||||
@@ -141,16 +139,16 @@ END
|
||||
|
||||
### 5-2. 그리드 컬럼
|
||||
|
||||
| 컬럼명 | Field | 타입 | 비고 |
|
||||
| ------------------ | -------------------- | ------ | ------------------------------------- |
|
||||
| 필수첨부파일아이디 | `esntlAtchFileId` | string | 예: `EAF-0001`, 클라이언트 생성/입력 |
|
||||
| 문서구분 | `docSeComCd` | string | 코드명 표시 — 공통코드 (TBD 상위코드) |
|
||||
| 필수첨부파일명 | `esntlAtchFileNm` | string | |
|
||||
| 필수첨부여부 | `esntlAtchYn` | string | `Y`→예, `N`→아니오 |
|
||||
| 필수파일검토내용 | `esntlAtchFileRvwCn` | string | 없으면 `—` 표시, 최대 2줄 clamp |
|
||||
| 비고 | `esntlAtchFileRmrk` | string | 없으면 `—` 표시 |
|
||||
| 양식 내려받기 | `atchFileGroupId` | string | 양식파일 다운로드 버튼 |
|
||||
| 관리 | — | — | 행별 **[수정] · [삭제]** |
|
||||
| 컬럼명 | Field | 타입 | 비고 |
|
||||
| ------------------ | ------------------- | ------ | ------------------------------------- |
|
||||
| 필수첨부파일아이디 | `esntlAtchFileId` | string | 예: `EAF-0001`, 클라이언트 생성/입력 |
|
||||
| 문서구분 | `docSeComCd` | string | 코드명 표시 — 공통코드 (TBD 상위코드) |
|
||||
| 필수첨부파일명 | `esntlAtchFileNm` | string | |
|
||||
| 필수첨부여부 | `esntlAtchYn` | string | `Y`→예, `N`→아니오 |
|
||||
| 비고 | `esntlAtchFileRmrk` | string | 없으면 `—` 표시 |
|
||||
| 등록일시 | `regDt` | string | `yyyy-MM-dd HH:mm:ss` |
|
||||
| 수정일시 | `mdfcnDt` | string | 미수정 시 빈 값 또는 `—` |
|
||||
| 관리 | — | — | 행별 **[수정] · [삭제]** |
|
||||
|
||||
- 행 클릭 시 별도 상세 화면 없음. 편집은 **[수정]** 버튼으로 다이얼로그 C를 연다.
|
||||
|
||||
@@ -169,15 +167,13 @@ END
|
||||
|
||||
### 6-1. 폼 필드
|
||||
|
||||
| 표시명 | 입력 유형 | 필수 | 기본값 | API 파라미터 매핑 | 비고 |
|
||||
| ------------------ | ------------------- | ---- | ------ | -------------------- | ---------------------------------- |
|
||||
| 필수첨부파일아이디 | (Readonly) | Y | — | `esntlAtchFileId` | 등록 시 미노출 |
|
||||
| 문서구분 | CodeSelect | Y | — | `docSeComCd` | 예: 설치인가, 기본계획 |
|
||||
| 필수첨부파일명 | Text | Y | — | `esntlAtchFileNm` | placeholder: "예: 사업계획서" |
|
||||
| 양식파일 | AttachmentFileField | N | — | `atchFileGroupId` | TUS 파일 업로드 |
|
||||
| 필수첨부여부 | RadioGroup | Y | Y | `esntlAtchYn` | Y/N, UI 표시: 예/아니오 |
|
||||
| 필수파일검토내용 | Textarea | N | — | `esntlAtchFileRvwCn` | placeholder: "검토내용을 입력하세요"|
|
||||
| 비고 | Textarea | N | — | `esntlAtchFileRmrk` | placeholder: "비고를 입력하세요" |
|
||||
| 표시명 | 입력 유형 | 필수 | 기본값 | API 파라미터 매핑 | 비고 |
|
||||
| ------------------ | ---------- | ---- | ------ | ------------------- | -------------------------------- |
|
||||
| 필수첨부파일아이디 | (Readonly) | Y | — | `esntlAtchFileId` | 등록 시 미노출 |
|
||||
| 문서구분 | CodeSelect | Y | — | `docSeComCd` | 예: 설치인가, 기본계획 |
|
||||
| 필수첨부파일명 | Text | Y | — | `esntlAtchFileNm` | placeholder: "예: 사업계획서" |
|
||||
| 필수첨부여부 | RadioGroup | Y | Y | `esntlAtchYn` | Y/N, UI 표시: 예/아니오 |
|
||||
| 비고 | Textarea | N | — | `esntlAtchFileRmrk` | placeholder: "비고를 입력하세요" |
|
||||
|
||||
### 6-2. 버튼
|
||||
|
||||
@@ -214,32 +210,28 @@ END
|
||||
|
||||
**응답 DTO**
|
||||
|
||||
| Field | 타입 | 설명 |
|
||||
| -------------------- | -------------------------- | -------------------------------- |
|
||||
| `esntlAtchFileId` | string | 필수첨부파일아이디 |
|
||||
| `docSeComCd` | string | 문서구분공통코드 |
|
||||
| `esntlAtchFileNm` | string | 필수첨부파일명 |
|
||||
| `esntlAtchYn` | string | 필수첨부여부 (Y/N) |
|
||||
| `esntlAtchFileRvwCn` | string? | 필수첨부파일검토내용 |
|
||||
| `esntlAtchFileRmrk` | string? | 필수첨부파일비고 |
|
||||
| `atchFileGroupId` | string? | 첨부파일그룹아이디 (양식파일) |
|
||||
| `atchFileList` | AtflMngClientResponseDto[]?| 첨부파일 목록 |
|
||||
| `rgtr` | string? | 등록자 UUID |
|
||||
| `rgtrNm` | string? | 등록자명 |
|
||||
| `mdfr` | string? | 수정자 UUID |
|
||||
| `regDt` | string? | 등록일시 (`yyyy-MM-dd HH:mm:ss`) |
|
||||
| `mdfcnDt` | string? | 수정일시 |
|
||||
| Field | 타입 | 설명 |
|
||||
| ------------------- | ------- | -------------------------------- |
|
||||
| `esntlAtchFileId` | string | 필수첨부파일아이디 |
|
||||
| `docSeComCd` | string | 문서구분공통코드 |
|
||||
| `esntlAtchFileNm` | string | 필수첨부파일명 |
|
||||
| `esntlAtchYn` | string | 필수첨부여부 (Y/N) |
|
||||
| `esntlAtchFileRmrk` | string? | 필수첨부파일비고 |
|
||||
| `rgtr` | string? | 등록자 UUID |
|
||||
| `rgtrNm` | string? | 등록자명 |
|
||||
| `mdfr` | string? | 수정자 UUID |
|
||||
| `regDt` | string? | 등록일시 (`yyyy-MM-dd HH:mm:ss`) |
|
||||
| `mdfcnDt` | string? | 수정일시 |
|
||||
|
||||
**저장 Request**
|
||||
|
||||
| Field | 필수 | 설명 |
|
||||
| -------------------- | ---- | -------------------- |
|
||||
| `docSeComCd` | Y | 문서구분 |
|
||||
| `esntlAtchFileNm` | N | 필수첨부파일명 |
|
||||
| `esntlAtchYn` | N | 필수첨부여부 |
|
||||
| `esntlAtchFileRvwCn` | N | 필수첨부파일검토내용 |
|
||||
| `esntlAtchFileRmrk` | N | 비고 |
|
||||
| `atchFileGroupId` | N | 첨부파일그룹아이디 |
|
||||
| Field | 필수 | 설명 |
|
||||
| ------------------- | ---- | ------------------ |
|
||||
| `esntlAtchFileId` | Y | 필수첨부파일아이디 |
|
||||
| `docSeComCd` | N | 문서구분 |
|
||||
| `esntlAtchFileNm` | N | 필수첨부파일명 |
|
||||
| `esntlAtchYn` | N | 필수첨부여부 |
|
||||
| `esntlAtchFileRmrk` | N | 비고 |
|
||||
|
||||
**검색 Query**
|
||||
|
||||
|
||||
@@ -19,8 +19,6 @@ export interface EsntlAtchFileMng {
|
||||
esntlAtchYn: "Y" | "N";
|
||||
/** 필수첨부파일비고 */
|
||||
esntlAtchFileRmrk?: string;
|
||||
/** 필수첨부파일검토내용 */
|
||||
esntlAtchFileRvwCn?: string;
|
||||
/** 첨부파일그룹아이디 (양식파일 그룹) */
|
||||
atchFileGroupId?: string;
|
||||
/** 첨부파일 목록 (양식파일) */
|
||||
@@ -79,8 +77,6 @@ export interface EsntlAtchFileMngSaveRequest {
|
||||
esntlAtchYn?: "Y" | "N";
|
||||
/** 필수첨부파일비고 */
|
||||
esntlAtchFileRmrk?: string;
|
||||
/** 필수첨부파일검토내용 */
|
||||
esntlAtchFileRvwCn?: string;
|
||||
/** 첨부파일그룹아이디 (양식파일 그룹) */
|
||||
atchFileGroupId?: string;
|
||||
}
|
||||
|
||||
@@ -51,19 +51,6 @@ export function createEsntlAtchFileColumns({
|
||||
meta: { align: "center" },
|
||||
cell: ({ getValue }) => formatYn(getValue()),
|
||||
}),
|
||||
columnHelper.accessor("esntlAtchFileRvwCn", {
|
||||
header: "필수파일검토내용",
|
||||
meta: { align: "left" },
|
||||
cell: ({ getValue }) => {
|
||||
const val = getValue();
|
||||
if (!val?.trim()) return "-";
|
||||
return (
|
||||
<span className="line-clamp-2 max-w-[20rem] text-left" title={val}>
|
||||
{val}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
}),
|
||||
columnHelper.accessor("esntlAtchFileRmrk", {
|
||||
header: "비고",
|
||||
meta: { align: "center" },
|
||||
|
||||
@@ -26,7 +26,6 @@ export interface EsntlAtchFileFormValues {
|
||||
docSeComCd: string;
|
||||
esntlAtchFileNm: string;
|
||||
esntlAtchYn: "Y" | "N";
|
||||
esntlAtchFileRvwCn: string;
|
||||
esntlAtchFileRmrk: string;
|
||||
atchFileGroupId: string;
|
||||
}
|
||||
@@ -69,7 +68,6 @@ function EsntlAtchFileFormDialog({
|
||||
docSeComCd: "",
|
||||
esntlAtchFileNm: "",
|
||||
esntlAtchYn: "Y",
|
||||
esntlAtchFileRvwCn: "",
|
||||
esntlAtchFileRmrk: "",
|
||||
atchFileGroupId: "",
|
||||
},
|
||||
@@ -117,7 +115,6 @@ function EsntlAtchFileFormDialog({
|
||||
docSeComCd: initial.docSeComCd ?? "",
|
||||
esntlAtchFileNm: initial.esntlAtchFileNm ?? "",
|
||||
esntlAtchYn: initial.esntlAtchYn ?? "Y",
|
||||
esntlAtchFileRvwCn: initial.esntlAtchFileRvwCn ?? "",
|
||||
esntlAtchFileRmrk: initial.esntlAtchFileRmrk ?? "",
|
||||
atchFileGroupId: initial.atchFileGroupId ?? "",
|
||||
});
|
||||
@@ -130,7 +127,6 @@ function EsntlAtchFileFormDialog({
|
||||
docSeComCd: "",
|
||||
esntlAtchFileNm: "",
|
||||
esntlAtchYn: "Y",
|
||||
esntlAtchFileRvwCn: "",
|
||||
esntlAtchFileRmrk: "",
|
||||
atchFileGroupId: "",
|
||||
});
|
||||
@@ -253,17 +249,6 @@ function EsntlAtchFileFormDialog({
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="esntlAtchFileRvwCn">필수파일검토내용</Label>
|
||||
<Textarea
|
||||
id="esntlAtchFileRvwCn"
|
||||
rows={3}
|
||||
placeholder="검토내용을 입력하세요"
|
||||
maxLength={4000}
|
||||
{...register("esntlAtchFileRvwCn")}
|
||||
className="!text-xl"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="esntlAtchFileRmrk">비고</Label>
|
||||
<Textarea
|
||||
|
||||
@@ -100,7 +100,7 @@ function EsntlAtchFileList({
|
||||
manualPagination: true,
|
||||
},
|
||||
dataTableOptions: {
|
||||
caption: "필수첨부파일 목록으로 필수첨부파일아이디, 문서구분, 필수첨부파일명, 필수첨부여부, 필수파일검토내용, 비고, 양식 내려받기, 관리 정보 제공",
|
||||
caption: "필수첨부파일 목록으로 필수첨부파일아이디, 문서구분, 필수첨부파일명, 필수첨부여부, 비고, 양식 내려받기, 관리 정보 제공",
|
||||
viewPagination: true,
|
||||
},
|
||||
});
|
||||
@@ -112,7 +112,6 @@ function EsntlAtchFileList({
|
||||
docSeComCd: values.docSeComCd,
|
||||
esntlAtchFileNm: values.esntlAtchFileNm,
|
||||
esntlAtchYn: values.esntlAtchYn,
|
||||
esntlAtchFileRvwCn: values.esntlAtchFileRvwCn || undefined,
|
||||
esntlAtchFileRmrk: values.esntlAtchFileRmrk || undefined,
|
||||
atchFileGroupId: values.atchFileGroupId || undefined,
|
||||
};
|
||||
|
||||
@@ -33,6 +33,7 @@ import {
|
||||
hasAdmdstCdColumn,
|
||||
isExcelImportAdmdstCdInvalid,
|
||||
mergeExcelImportWithExistingRows,
|
||||
parseExcelImportCellValue,
|
||||
prepareGridColumnsForExcelExport,
|
||||
releaseFixedOptionsForExcelExport,
|
||||
resolveColumnStyleName,
|
||||
@@ -289,14 +290,28 @@ type GridViewWithSetColumnProperty = {
|
||||
};
|
||||
|
||||
type GridViewWithEditOptions = {
|
||||
setEditOptions?: (options: { commitWhenLeave?: boolean }) => void;
|
||||
setEditOptions?: (options: {
|
||||
commitWhenLeave?: boolean;
|
||||
appendable?: boolean;
|
||||
insertable?: boolean;
|
||||
}) => void;
|
||||
setPasteOptions?: (options: { enableAppend?: boolean }) => void;
|
||||
};
|
||||
|
||||
/** 포커스가 그리드 밖으로 나갈 때 편집 중인 값을 자동 commit */
|
||||
function applyDefaultGridEditOptions(
|
||||
gridView: GridViewWithEditOptions | null | undefined,
|
||||
options?: { preventRowAppend?: boolean },
|
||||
) {
|
||||
gridView?.setEditOptions?.({ commitWhenLeave: true });
|
||||
gridView?.setEditOptions?.({
|
||||
commitWhenLeave: true,
|
||||
...(options?.preventRowAppend
|
||||
? { appendable: false, insertable: false }
|
||||
: {}),
|
||||
});
|
||||
if (options?.preventRowAppend) {
|
||||
gridView?.setPasteOptions?.({ enableAppend: false });
|
||||
}
|
||||
}
|
||||
|
||||
function isDateEditorColumn(column: {
|
||||
@@ -853,6 +868,7 @@ const DataGrid = ({
|
||||
gridHeight = 55, // vh 단위
|
||||
headerHeight = 60,
|
||||
fitStyle = GridFitStyle.EVEN,
|
||||
preventRowAppend = true,
|
||||
}: DataGridProps) => {
|
||||
const { columns, columnLayout } = columnInfo;
|
||||
const fixedColumnNameSet = useMemo(
|
||||
@@ -1331,6 +1347,11 @@ useEffect(() => {
|
||||
columnLayout,
|
||||
{ skipNonEditable: false },
|
||||
);
|
||||
const valueTypeByFieldName = new Map(
|
||||
columns
|
||||
.filter((c) => c.fieldName)
|
||||
.map((c) => [c.fieldName as string, c.valueType]),
|
||||
);
|
||||
|
||||
// 데이터 행 읽기
|
||||
const dataRows: Record<string, string | number>[] = [];
|
||||
@@ -1352,36 +1373,13 @@ useEffect(() => {
|
||||
];
|
||||
const fieldName = excelColumnFieldNames[colIndex];
|
||||
const allFieldName = excelColumnFieldNamesAll[colIndex];
|
||||
|
||||
let cellValue: string | number = "";
|
||||
if (
|
||||
cell &&
|
||||
cell.v !== undefined &&
|
||||
cell.v !== null
|
||||
) {
|
||||
// 엑셀 셀 타입이 숫자이거나 값이 숫자인 경우 숫자로 변환
|
||||
if (
|
||||
cell.t === "n" ||
|
||||
(typeof cell.v === "number" &&
|
||||
!isNaN(cell.v))
|
||||
) {
|
||||
cellValue = cell.v as number;
|
||||
} else {
|
||||
const stringValue = String(cell.v);
|
||||
// 문자열이지만 숫자로 변환 가능한 경우 숫자로 변환
|
||||
const numericValue = Number(
|
||||
stringValue.replace(/,/g, ""),
|
||||
);
|
||||
if (
|
||||
!isNaN(numericValue) &&
|
||||
stringValue.trim() !== ""
|
||||
) {
|
||||
cellValue = numericValue;
|
||||
} else {
|
||||
cellValue = stringValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
const typeFieldName = fieldName || allFieldName;
|
||||
const cellValue = parseExcelImportCellValue(
|
||||
cell,
|
||||
typeFieldName
|
||||
? valueTypeByFieldName.get(typeFieldName)
|
||||
: undefined,
|
||||
);
|
||||
|
||||
if (allFieldName === "admdstCd" && cellValue !== "") {
|
||||
rowAdmdstCd = cellValue;
|
||||
@@ -1467,7 +1465,9 @@ useEffect(() => {
|
||||
const scheduleFooterTask = (task: () => void, delayMs: number) => {
|
||||
footerTimerIds.push(setTimeout(task, delayMs));
|
||||
};
|
||||
applyDefaultGridEditOptions(gridView as GridViewWithEditOptions);
|
||||
applyDefaultGridEditOptions(gridView as GridViewWithEditOptions, {
|
||||
preventRowAppend,
|
||||
});
|
||||
|
||||
const columnsFieldsSig = columns.map((c) => c.fieldName).join("\u0001");
|
||||
if (columnsFieldsSig !== columnsFieldsSigRef.current) {
|
||||
@@ -1990,6 +1990,7 @@ useEffect(() => {
|
||||
fitStyle,
|
||||
enableSort,
|
||||
footerVerificationResult,
|
||||
preventRowAppend,
|
||||
]);
|
||||
|
||||
// 행·셀 클릭 이벤트 (검증 오류 툴팁은 hover만 — onShowTooltip / 빈 셀 오버레이)
|
||||
@@ -2527,6 +2528,7 @@ useEffect(() => {
|
||||
const gridView = gridRef.current?.gridView ?? grid;
|
||||
applyDefaultGridEditOptions(
|
||||
gridView as GridViewWithEditOptions,
|
||||
{ preventRowAppend },
|
||||
);
|
||||
if (!gridView?.columnByName) return;
|
||||
setTimeout(() => {
|
||||
|
||||
@@ -53,6 +53,7 @@ import {
|
||||
hasAdmdstCdColumn,
|
||||
isExcelImportAdmdstCdInvalid,
|
||||
mergeExcelImportWithExistingRows,
|
||||
parseExcelImportCellValue,
|
||||
prepareGridColumnsForExcelExport,
|
||||
releaseFixedOptionsForExcelExport,
|
||||
resolveColumnStyleName,
|
||||
@@ -611,6 +612,11 @@ const TabDataGrid = ({
|
||||
columnLayout,
|
||||
{ skipNonEditable: false },
|
||||
);
|
||||
const valueTypeByFieldName = new Map(
|
||||
columns
|
||||
.filter((c) => c.fieldName)
|
||||
.map((c) => [c.fieldName as string, c.valueType]),
|
||||
);
|
||||
|
||||
// 데이터 행 읽기
|
||||
const dataRows: Record<string, string | number>[] = [];
|
||||
@@ -625,23 +631,13 @@ const TabDataGrid = ({
|
||||
const cell = worksheet[XLSX.utils.encode_cell({ r: row, c: col })];
|
||||
const fieldName = excelColumnFieldNames[colIndex];
|
||||
const allFieldName = excelColumnFieldNamesAll[colIndex];
|
||||
|
||||
let cellValue: string | number = '';
|
||||
if (cell && cell.v !== undefined && cell.v !== null) {
|
||||
// 엑셀 셀 타입이 숫자이거나 값이 숫자인 경우 숫자로 변환
|
||||
if (cell.t === 'n' || (typeof cell.v === 'number' && !isNaN(cell.v))) {
|
||||
cellValue = cell.v as number;
|
||||
} else {
|
||||
const stringValue = String(cell.v);
|
||||
// 문자열이지만 숫자로 변환 가능한 경우 숫자로 변환
|
||||
const numericValue = Number(stringValue.replace(/,/g, ''));
|
||||
if (!isNaN(numericValue) && stringValue.trim() !== '') {
|
||||
cellValue = numericValue;
|
||||
} else {
|
||||
cellValue = stringValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
const typeFieldName = fieldName || allFieldName;
|
||||
const cellValue = parseExcelImportCellValue(
|
||||
cell,
|
||||
typeFieldName
|
||||
? valueTypeByFieldName.get(typeFieldName)
|
||||
: undefined,
|
||||
);
|
||||
|
||||
if (allFieldName === 'admdstCd' && cellValue !== '') {
|
||||
rowAdmdstCd = cellValue;
|
||||
|
||||
@@ -20,6 +20,7 @@ import { nullableTrimmedString } from "@/components/util/input/nullableString";
|
||||
import { statisticsInputExcretaTreatmentFacilityApi } from "@/entities/statistics/api/input/statistics-input-excreta-treatment-facility-service";
|
||||
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||
import { callImrServiceWithRollbackOnFailure } from "@/components/util/input/call-imr-with-rollback";
|
||||
import {
|
||||
EXCRETA_TREATMENT_FACILITY_STATS_CD,
|
||||
type ExcretaTreatmentFacilityItem,
|
||||
@@ -75,7 +76,11 @@ import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||
import { formatCompactYmdForGrid, toCompactYmdOrNull } from "@/components/util/grid/ymdFormat";
|
||||
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
||||
import { isVerificationFailedFromCommonInfo } from "@/components/util/input/verification-failed-flag";
|
||||
import type { VerificationResultLikeMap } from "@/components/util/input/verification-result-display";
|
||||
import {
|
||||
formatVerificationTooltip,
|
||||
normalizeVerificationResultMap,
|
||||
type VerificationResultLikeMap,
|
||||
} from "@/components/util/input/verification-result-display";
|
||||
import { useAdminStore } from "@/store/admin-store";
|
||||
import { useTabStore } from "@/store/tab-store";
|
||||
|
||||
@@ -207,7 +212,7 @@ function mapExcretaTreatmentFacilityListToGridRows(
|
||||
},
|
||||
])[0] as GridRowWithVerification;
|
||||
if (item.verificationResult) {
|
||||
row.verificationResult = item.verificationResult;
|
||||
row.verificationResult = normalizeVerificationResultMap(item.verificationResult);
|
||||
}
|
||||
return row;
|
||||
});
|
||||
@@ -502,7 +507,9 @@ const ExcretaTreatmentFacilityInp = () => {
|
||||
setStatusInfo(nextStatusInfo);
|
||||
setStatsCd(commonInfo.statsCd);
|
||||
setIsVerificationFailed(isVerificationFailedFromCommonInfo(commonInfo));
|
||||
setFooterVerificationResult(commonInfo.verificationResult ?? null);
|
||||
setFooterVerificationResult(
|
||||
normalizeVerificationResultMap(commonInfo.verificationResult) ?? null,
|
||||
);
|
||||
if (overrides?.mode !== "PRE") {
|
||||
setIsNotApplicable(gridRows.length === 0);
|
||||
} else if (gridRows.length > 0) {
|
||||
@@ -813,7 +820,13 @@ const ExcretaTreatmentFacilityInp = () => {
|
||||
};
|
||||
|
||||
try {
|
||||
const imrResponse = await statisticsApi.callImrService(imrParam);
|
||||
const imrResponse = await callImrServiceWithRollbackOnFailure(imrParam, {
|
||||
statsYr: lastSearchedValues.year ?? "",
|
||||
statsCd: statsCdForSubmit,
|
||||
sewerBzmnCd: lastSearchedValues?.bsnmCd ?? "",
|
||||
rollbackStatusCode: statusInfo?.lclgvSbmsnSttsCd ?? "",
|
||||
mdfrUuid: userInfo.userUnqId,
|
||||
});
|
||||
if (imrResponse.job_id) {
|
||||
await waitForImrJobCompleted(
|
||||
imrResponse.job_id,
|
||||
@@ -952,19 +965,7 @@ const ExcretaTreatmentFacilityInp = () => {
|
||||
if (!verification) return;
|
||||
const errors = verification[fieldName];
|
||||
if (Array.isArray(errors) && errors.length > 0) {
|
||||
return errors
|
||||
.map((e) => {
|
||||
const prefix =
|
||||
e.vrfcCd === "IMR"
|
||||
? "시계열 검증 - "
|
||||
: e.vrfcCd === "NV"
|
||||
? "일반검증 - "
|
||||
: "모집단 검증 -";
|
||||
return `${prefix}${e.rsnExpln}
|
||||
(검증 기준값: ${e.cmprCn} / 현재 입력값: ${e.nowCn})`;
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join("\n");
|
||||
return formatVerificationTooltip(errors);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
||||
import { statisticsInputPrivateSewageFacilityApi } from "@/entities/statistics/api/input/statistics-input-private-sewage-facility-service";
|
||||
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||
import { callImrServiceWithRollbackOnFailure } from "@/components/util/input/call-imr-with-rollback";
|
||||
import type {
|
||||
PrivateSewageDesigStatusItem,
|
||||
PrivateSewageDesigStatusSaveItem,
|
||||
@@ -68,7 +69,11 @@ import {
|
||||
patchFooterVerificationByTab,
|
||||
patchVerificationFailedByTab,
|
||||
} from "@/components/util/input/verification-failed-flag";
|
||||
import type { VerificationResultLikeMap } from "@/components/util/input/verification-result-display";
|
||||
import {
|
||||
formatVerificationTooltip,
|
||||
normalizeVerificationResultMap,
|
||||
type VerificationResultLikeMap,
|
||||
} from "@/components/util/input/verification-result-display";
|
||||
import { nullableTrimmedString } from "@/components/util/input/nullableString";
|
||||
import { useAdminStore } from "@/store/admin-store";
|
||||
import { useTabStore } from "@/store/tab-store";
|
||||
@@ -175,7 +180,9 @@ function mapRegionalListToGridRows<
|
||||
return filterBySelectedAdmdstCd(list, sidoListRef.current, values).map((item) => {
|
||||
const { verificationResult, ...rest } = item;
|
||||
const row = toGridRows([{ ctpvNm, ...rest }])[0] as GridRowWithVerification;
|
||||
if (verificationResult) row.verificationResult = verificationResult;
|
||||
if (verificationResult) {
|
||||
row.verificationResult = normalizeVerificationResultMap(verificationResult);
|
||||
}
|
||||
return row;
|
||||
});
|
||||
}
|
||||
@@ -888,7 +895,13 @@ const PrivateSewageFacilityInp = () => {
|
||||
};
|
||||
|
||||
try {
|
||||
const imrResponse = await statisticsApi.callImrService(imrParam);
|
||||
const imrResponse = await callImrServiceWithRollbackOnFailure(imrParam, {
|
||||
statsYr: lastSearchedValues.year ?? "",
|
||||
statsCd: statsCdForTab,
|
||||
sewerBzmnCd: lastSearchedValues?.bsnmCd ?? "",
|
||||
rollbackStatusCode: activeTabStatus?.lclgvSbmsnSttsCd ?? "",
|
||||
mdfrUuid: userInfo.userUnqId,
|
||||
});
|
||||
if (imrResponse.job_id) {
|
||||
await waitForImrJobCompleted(
|
||||
imrResponse.job_id,
|
||||
@@ -1144,18 +1157,7 @@ const PrivateSewageFacilityInp = () => {
|
||||
if (!verification) return;
|
||||
const errors = verification[fieldName];
|
||||
if (Array.isArray(errors) && errors.length > 0) {
|
||||
return errors
|
||||
.map((e) => {
|
||||
const prefix =
|
||||
e.vrfcCd === "IMR"
|
||||
? "시계열 검증 - "
|
||||
: e.vrfcCd === "NV"
|
||||
? "일반검증 - "
|
||||
: "모집단 검증 - ";
|
||||
return `${prefix}${e.rsnExpln}(검증 기준값: ${e.cmprCn} / 현재 입력값: ${e.nowCn})`;
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join("\n");
|
||||
return formatVerificationTooltip(errors);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import { useStatisticsInputPendingNavigation } from '@/shared/lib/use-statistics
|
||||
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 { callImrServiceWithRollbackOnFailure } from '@/components/util/input/call-imr-with-rollback';
|
||||
import type {
|
||||
PublicSewageFacilityRequestParams,
|
||||
PublicSewageFacilitySaveItem,
|
||||
@@ -52,7 +53,11 @@ import { fetchColumnGuidesRecord } from '@/components/util/grid/columnGuides';
|
||||
import { toGridRows } from '@/components/util/grid/gridFunction';
|
||||
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
||||
import { patchFooterVerificationByTab,patchVerificationFailedByTab } from '@/components/util/input/verification-failed-flag';
|
||||
import type { VerificationResultLikeMap } from '@/components/util/input/verification-result-display';
|
||||
import {
|
||||
formatVerificationTooltip,
|
||||
withNormalizedVerificationResult,
|
||||
type VerificationResultLikeMap,
|
||||
} from '@/components/util/input/verification-result-display';
|
||||
import { nullableTrimmedString } from '@/components/util/input/nullableString';
|
||||
import { useAdminStore } from '@/store/admin-store';
|
||||
import { useTabStore } from '@/store/tab-store';
|
||||
@@ -438,7 +443,13 @@ const PublicSewageFacilityInp = () => {
|
||||
};
|
||||
|
||||
try {
|
||||
const imrResponse = await statisticsApi.callImrService(imrParam);
|
||||
const imrResponse = await callImrServiceWithRollbackOnFailure(imrParam, {
|
||||
statsYr: lastSearchedValues.year ?? '',
|
||||
statsCd: statsCdForTab,
|
||||
sewerBzmnCd: lastSearchedValues?.bsnmCd ?? '',
|
||||
rollbackStatusCode: activeTabStatus?.lclgvSbmsnSttsCd ?? '',
|
||||
mdfrUuid: userInfo.userUnqId,
|
||||
});
|
||||
if (imrResponse.job_id) {
|
||||
await waitForImrJobCompleted(
|
||||
imrResponse.job_id,
|
||||
@@ -789,11 +800,13 @@ const PublicSewageFacilityInp = () => {
|
||||
sidoListRef.current,
|
||||
searchContext,
|
||||
);
|
||||
const convertedData = list.map((item) => ({
|
||||
ctpvNm: commonInfo.ctpvNm,
|
||||
...item,
|
||||
rmrk: item.rmrk ?? null,
|
||||
}));
|
||||
const convertedData = list.map((item) =>
|
||||
withNormalizedVerificationResult({
|
||||
ctpvNm: commonInfo.ctpvNm,
|
||||
...item,
|
||||
rmrk: item.rmrk ?? null,
|
||||
}),
|
||||
);
|
||||
|
||||
if (list.length === 0) {
|
||||
setShowIsNotApplicable(true);
|
||||
@@ -1575,17 +1588,7 @@ const PublicSewageFacilityInp = () => {
|
||||
if (!verification) return;
|
||||
const errors = verification[fieldName];
|
||||
if (Array.isArray(errors) && errors.length > 0) {
|
||||
return errors
|
||||
.map((e) => {
|
||||
const prefix =
|
||||
e.vrfcCd === "IMR" ? "시계열 검증 - " : (e.vrfcCd === "NV" ? "일반검증 - " : "모집단 검증 - ");
|
||||
const comp = e.cmprCn ?? "";
|
||||
const now = e.nowCn ?? "";
|
||||
return `${prefix}${e.rsnExpln}
|
||||
(검증 기준값: ${comp} / 현재 입력값: ${now})`;
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join("\n");
|
||||
return formatVerificationTooltip(errors);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -20,6 +20,7 @@ import { nullableTrimmedString } from "@/components/util/input/nullableString";
|
||||
import { statisticsInputPumpingStationApi } from "@/entities/statistics/api/input/statistics-input-pumping-station-service";
|
||||
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||
import { callImrServiceWithRollbackOnFailure } from "@/components/util/input/call-imr-with-rollback";
|
||||
import {
|
||||
PUMPING_STATION_STATS_CD,
|
||||
type PumpingStationItem,
|
||||
@@ -75,7 +76,11 @@ import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||
import { formatCompactYmdForGrid, toCompactYmdOrNull } from "@/components/util/grid/ymdFormat";
|
||||
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
||||
import { isVerificationFailedFromCommonInfo } from "@/components/util/input/verification-failed-flag";
|
||||
import type { VerificationResultLikeMap } from "@/components/util/input/verification-result-display";
|
||||
import {
|
||||
formatVerificationTooltip,
|
||||
normalizeVerificationResultMap,
|
||||
type VerificationResultLikeMap,
|
||||
} from "@/components/util/input/verification-result-display";
|
||||
import { useAdminStore } from "@/store/admin-store";
|
||||
import { useTabStore } from "@/store/tab-store";
|
||||
|
||||
@@ -206,7 +211,7 @@ function mapPumpingStationListToGridRows(
|
||||
},
|
||||
])[0] as GridRowWithVerification;
|
||||
if (item.verificationResult) {
|
||||
row.verificationResult = item.verificationResult;
|
||||
row.verificationResult = normalizeVerificationResultMap(item.verificationResult);
|
||||
}
|
||||
return row;
|
||||
});
|
||||
@@ -493,7 +498,9 @@ const PumpingStationInp = () => {
|
||||
setStatusInfo(nextStatusInfo);
|
||||
setStatsCd(commonInfo.statsCd);
|
||||
setIsVerificationFailed(isVerificationFailedFromCommonInfo(commonInfo));
|
||||
setFooterVerificationResult(commonInfo.verificationResult ?? null);
|
||||
setFooterVerificationResult(
|
||||
normalizeVerificationResultMap(commonInfo.verificationResult) ?? null,
|
||||
);
|
||||
if (overrides?.mode !== "PRE") {
|
||||
setIsNotApplicable(gridRows.length === 0);
|
||||
} else if (gridRows.length > 0) {
|
||||
@@ -796,7 +803,13 @@ const PumpingStationInp = () => {
|
||||
};
|
||||
|
||||
try {
|
||||
const imrResponse = await statisticsApi.callImrService(imrParam);
|
||||
const imrResponse = await callImrServiceWithRollbackOnFailure(imrParam, {
|
||||
statsYr: lastSearchedValues.year ?? "",
|
||||
statsCd: statsCdForSubmit,
|
||||
sewerBzmnCd: lastSearchedValues?.bsnmCd ?? "",
|
||||
rollbackStatusCode: statusInfo?.lclgvSbmsnSttsCd ?? "",
|
||||
mdfrUuid: userInfo.userUnqId,
|
||||
});
|
||||
if (imrResponse.job_id) {
|
||||
await waitForImrJobCompleted(
|
||||
imrResponse.job_id,
|
||||
@@ -935,19 +948,7 @@ const PumpingStationInp = () => {
|
||||
if (!verification) return;
|
||||
const errors = verification[fieldName];
|
||||
if (Array.isArray(errors) && errors.length > 0) {
|
||||
return errors
|
||||
.map((e) => {
|
||||
const prefix =
|
||||
e.vrfcCd === "IMR"
|
||||
? "시계열 검증 - "
|
||||
: e.vrfcCd === "NV"
|
||||
? "일반검증 - "
|
||||
: "모집단 검증 -";
|
||||
return `${prefix}${e.rsnExpln}
|
||||
(검증 기준값: ${e.cmprCn} / 현재 입력값: ${e.nowCn})`;
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join("\n");
|
||||
return formatVerificationTooltip(errors);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import { nullableTrimmedString } from "@/components/util/input/nullableString";
|
||||
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
||||
import { statisticsInputSewageExcretaRelatedApi } from "@/entities/statistics/api/input/statistics-input-sewage-excreta-related-service";
|
||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||
import { callImrServiceWithRollbackOnFailure } from "@/components/util/input/call-imr-with-rollback";
|
||||
import type {
|
||||
ExcretaRelatedIndustrySaveItem,
|
||||
PrivateSewageTreatRelatedIndustrySaveItem,
|
||||
@@ -84,7 +85,11 @@ import {
|
||||
patchFooterVerificationByTab,
|
||||
patchVerificationFailedByTab,
|
||||
} from "@/components/util/input/verification-failed-flag";
|
||||
import type { VerificationResultLikeMap } from "@/components/util/input/verification-result-display";
|
||||
import {
|
||||
formatVerificationTooltip,
|
||||
normalizeVerificationResultMap,
|
||||
type VerificationResultLikeMap,
|
||||
} from "@/components/util/input/verification-result-display";
|
||||
import { useAdminStore } from "@/store/admin-store";
|
||||
import { useTabStore } from "@/store/tab-store";
|
||||
|
||||
@@ -552,19 +557,7 @@ function verificationCellTooltip({
|
||||
if (!verification) return;
|
||||
const errors = verification[fieldName];
|
||||
if (Array.isArray(errors) && errors.length > 0) {
|
||||
return errors
|
||||
.map((e) => {
|
||||
const prefix =
|
||||
e.vrfcCd === "IMR"
|
||||
? "시계열 검증 - "
|
||||
: e.vrfcCd === "NV"
|
||||
? "일반검증 - "
|
||||
: "모집단 검증 - ";
|
||||
return `${prefix}${e.rsnExpln}
|
||||
(검증 기준값: ${e.cmprCn} / 현재 입력값: ${e.nowCn})`;
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join("\n");
|
||||
return formatVerificationTooltip(errors);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -588,7 +581,7 @@ function mapListToGridRows<T extends { verificationResult?: SewageExcretaRelated
|
||||
return filterBySelectedAdmdstCd(list, sidoListRef.current, values).map((item) => {
|
||||
const row = toGridRows([{ ctpvNm, ...item }])[0] as GridRowWithVerification;
|
||||
if (item.verificationResult) {
|
||||
row.verificationResult = item.verificationResult;
|
||||
row.verificationResult = normalizeVerificationResultMap(item.verificationResult);
|
||||
}
|
||||
return row;
|
||||
});
|
||||
@@ -1503,7 +1496,13 @@ const SewageExcretaRelatedInp = () => {
|
||||
};
|
||||
|
||||
try {
|
||||
const imrResponse = await statisticsApi.callImrService(imrParam);
|
||||
const imrResponse = await callImrServiceWithRollbackOnFailure(imrParam, {
|
||||
statsYr: lastSearchedValues.year ?? "",
|
||||
statsCd: statsCdForTab,
|
||||
sewerBzmnCd: lastSearchedValues?.bsnmCd ?? "",
|
||||
rollbackStatusCode: activeTabStatus?.lclgvSbmsnSttsCd ?? "",
|
||||
mdfrUuid: userInfo.userUnqId,
|
||||
});
|
||||
if (imrResponse.job_id) {
|
||||
await waitForImrJobCompleted(
|
||||
imrResponse.job_id,
|
||||
|
||||
@@ -21,6 +21,7 @@ import { nullableTrimmedString } from "@/components/util/input/nullableString";
|
||||
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
||||
import { statisticsInputSewageExcretaSlurgeApi } from "@/entities/statistics/api/input/statistics-input-sewage-excreta-slurge-service";
|
||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||
import { callImrServiceWithRollbackOnFailure } from "@/components/util/input/call-imr-with-rollback";
|
||||
import type {
|
||||
DigestorOperatingStatusSaveItem,
|
||||
ExcretaSlurgeProcessingStatusSaveItem,
|
||||
@@ -90,7 +91,11 @@ import {
|
||||
patchFooterVerificationByTab,
|
||||
patchVerificationFailedByTab,
|
||||
} from "@/components/util/input/verification-failed-flag";
|
||||
import type { VerificationResultLikeMap } from "@/components/util/input/verification-result-display";
|
||||
import {
|
||||
formatVerificationTooltip,
|
||||
normalizeVerificationResultMap,
|
||||
type VerificationResultLikeMap,
|
||||
} from "@/components/util/input/verification-result-display";
|
||||
import { useAdminStore } from "@/store/admin-store";
|
||||
import { useTabStore } from "@/store/tab-store";
|
||||
|
||||
@@ -148,19 +153,7 @@ function verificationCellTooltip({
|
||||
if (!verification) return;
|
||||
const errors = verification[fieldName];
|
||||
if (Array.isArray(errors) && errors.length > 0) {
|
||||
return errors
|
||||
.map((e) => {
|
||||
const prefix =
|
||||
e.vrfcCd === "IMR"
|
||||
? "시계열 검증 - "
|
||||
: e.vrfcCd === "NV"
|
||||
? "일반검증 - "
|
||||
: "모집단 검증 - ";
|
||||
return `${prefix}${e.rsnExpln}
|
||||
(검증 기준값: ${e.cmprCn} / 현재 입력값: ${e.nowCn})`;
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join("\n");
|
||||
return formatVerificationTooltip(errors);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,7 +178,7 @@ function mapListToGridRows<T extends { verificationResult?: SewageExcretaSlurgeV
|
||||
return filterBySelectedAdmdstCd(list, sidoListRef.current, values).map((item) => {
|
||||
const row = toGridRows([{ ctpvNm, ...item }])[0] as GridRowWithVerification;
|
||||
if (item.verificationResult) {
|
||||
row.verificationResult = item.verificationResult;
|
||||
row.verificationResult = normalizeVerificationResultMap(item.verificationResult);
|
||||
}
|
||||
return row;
|
||||
});
|
||||
@@ -627,7 +620,6 @@ function buildExcretaSlurgeProcessingStatusSaveItem(
|
||||
rcycQnt: toGridNumber(row.rcycQnt),
|
||||
olandLfvlm: toGridNumber(row.olandLfvlm),
|
||||
incnrQnt: toGridNumber(row.incnrQnt),
|
||||
oceanInputQnt: toGridNumber(row.oceanInputQnt),
|
||||
fuelQnt: toGridNumber(row.fuelQnt),
|
||||
etcQnt: toGridNumber(row.etcQnt),
|
||||
unprcsQnt: toGridNumber(row.unprcsQnt),
|
||||
@@ -1486,7 +1478,13 @@ const SewageExcretaSlurgeInp = () => {
|
||||
};
|
||||
|
||||
try {
|
||||
const imrResponse = await statisticsApi.callImrService(imrParam);
|
||||
const imrResponse = await callImrServiceWithRollbackOnFailure(imrParam, {
|
||||
statsYr: lastSearchedValues.year ?? "",
|
||||
statsCd: statsCdForSubmit,
|
||||
sewerBzmnCd: lastSearchedValues?.bsnmCd ?? "",
|
||||
rollbackStatusCode: activeTabStatus?.lclgvSbmsnSttsCd ?? "",
|
||||
mdfrUuid: userInfo.userUnqId,
|
||||
});
|
||||
if (imrResponse.job_id) {
|
||||
await waitForImrJobCompleted(
|
||||
imrResponse.job_id,
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
||||
import { statisticsInputSewPipeApiService } from "@/entities/statistics/api/input/statistics-sewage-pipe-input-service";
|
||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||
import { callImrServiceWithRollbackOnFailure } from "@/components/util/input/call-imr-with-rollback";
|
||||
import type {
|
||||
SeweragePipeInputFactInstallStatusSaveRequest,
|
||||
SeweragePipeInputFactInstallStatusSubmitRequest,
|
||||
@@ -82,7 +83,10 @@ import {
|
||||
} from "@/components/util/input/verification-failed-flag";
|
||||
import { nullableTrimmedString } from "@/components/util/input/nullableString";
|
||||
import {
|
||||
formatVerificationTooltip,
|
||||
getVerificationErrorsForField,
|
||||
normalizeVerificationResultMap,
|
||||
withNormalizedVerificationResult,
|
||||
type VerificationResultLikeMap,
|
||||
} from "@/components/util/input/verification-result-display";
|
||||
import { useAdminStore } from "@/store/admin-store";
|
||||
@@ -289,7 +293,10 @@ function normalizePipeTypeStatusRow(
|
||||
lyngPrlg: Number(lyngPrlgWhol ?? 0),
|
||||
dmltnPrlg: Number(dmltnPrlgWhol ?? 0),
|
||||
...yearFields,
|
||||
verificationResult: remapPipeTypePrlgWholVerification(verificationResult) ?? undefined,
|
||||
verificationResult:
|
||||
normalizeVerificationResultMap(
|
||||
remapPipeTypePrlgWholVerification(verificationResult),
|
||||
) ?? undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -719,10 +726,12 @@ const SewagePipeInp = () => {
|
||||
const response = await statisticsInputSewPipeApiService.getRegionalFactStatus(searchParam);
|
||||
if (response.status === 'success') {
|
||||
const commonInfo = response.data.commonInfo;
|
||||
const convertedData = filterFetched(response.data.regionalFactStatusList).map((d) => ({
|
||||
ctpvNm: commonInfo.ctpvNm,
|
||||
...d,
|
||||
}));
|
||||
const convertedData = filterFetched(response.data.regionalFactStatusList).map((d) =>
|
||||
withNormalizedVerificationResult({
|
||||
ctpvNm: commonInfo.ctpvNm,
|
||||
...d,
|
||||
}),
|
||||
);
|
||||
applyRowMap((m) => m.set('ST00020001', toGridRows(convertedData)));
|
||||
setTabStatusInfoMap((prev) => new Map(prev).set(tabKey, response.data.statusInfo));
|
||||
setTabStatsCdMap((prev) => new Map(prev).set(tabKey, commonInfo.statsCd));
|
||||
@@ -749,10 +758,12 @@ const SewagePipeInp = () => {
|
||||
const response = await statisticsInputSewPipeApiService.getFactInstallStatus(searchParam);
|
||||
if (response.status === 'success') {
|
||||
const commonInfo = response.data.commonInfo;
|
||||
const convertedData = filterFetched(response.data.factInstallStatusList).map((d) => ({
|
||||
ctpvNm: commonInfo.ctpvNm,
|
||||
...d,
|
||||
}));
|
||||
const convertedData = filterFetched(response.data.factInstallStatusList).map((d) =>
|
||||
withNormalizedVerificationResult({
|
||||
ctpvNm: commonInfo.ctpvNm,
|
||||
...d,
|
||||
}),
|
||||
);
|
||||
if (convertedData.length === 0) {
|
||||
const alreadyHandledForSameSearch =
|
||||
factInstallNoDataHandledKeyRef.current === searchConditionKey;
|
||||
@@ -829,10 +840,12 @@ const SewagePipeInp = () => {
|
||||
const response = await statisticsInputSewPipeApiService.getPipeDiameterStatus(searchParam);
|
||||
if (response.status === 'success') {
|
||||
const commonInfo = response.data.commonInfo;
|
||||
const convertedData = filterFetched(response.data.pipeDiameterStatusList).map((d) => ({
|
||||
ctpvNm: commonInfo.ctpvNm,
|
||||
...d,
|
||||
}));
|
||||
const convertedData = filterFetched(response.data.pipeDiameterStatusList).map((d) =>
|
||||
withNormalizedVerificationResult({
|
||||
ctpvNm: commonInfo.ctpvNm,
|
||||
...d,
|
||||
}),
|
||||
);
|
||||
applyRowMap((m) => m.set('ST00020004', toGridRows(convertedData)));
|
||||
setTabStatusInfoMap((prev) => new Map(prev).set(tabKey, response.data.statusInfo));
|
||||
setTabStatsCdMap((prev) => new Map(prev).set(tabKey, commonInfo.statsCd));
|
||||
@@ -859,10 +872,12 @@ const SewagePipeInp = () => {
|
||||
const response = await statisticsInputSewPipeApiService.getManholeStatus(searchParam);
|
||||
if (response.status === 'success') {
|
||||
const commonInfo = response.data.commonInfo;
|
||||
const convertedData = filterFetched(response.data.manholeStatusList).map((d) => ({
|
||||
ctpvNm: commonInfo.ctpvNm,
|
||||
...d,
|
||||
}));
|
||||
const convertedData = filterFetched(response.data.manholeStatusList).map((d) =>
|
||||
withNormalizedVerificationResult({
|
||||
ctpvNm: commonInfo.ctpvNm,
|
||||
...d,
|
||||
}),
|
||||
);
|
||||
applyRowMap((m) => m.set('ST00020005', toGridRows(convertedData)));
|
||||
setTabStatusInfoMap((prev) => new Map(prev).set(tabKey, response.data.statusInfo));
|
||||
setTabStatsCdMap((prev) => new Map(prev).set(tabKey, commonInfo.statsCd));
|
||||
@@ -889,13 +904,15 @@ const SewagePipeInp = () => {
|
||||
const response = await statisticsInputSewPipeApiService.getConnectionStatus(searchParam);
|
||||
if (response.status === 'success') {
|
||||
const commonInfo = response.data.commonInfo;
|
||||
const facilityConvertedData = filterFetched(response.data.facilityConnectionList).map((d) => ({
|
||||
...d,
|
||||
}));
|
||||
const adminConvertedData = filterFetched(response.data.adminAreaConnectionList).map((d) => ({
|
||||
...d,
|
||||
ctpvNm: d.ctpvNm || commonInfo.ctpvNm,
|
||||
}));
|
||||
const facilityConvertedData = filterFetched(response.data.facilityConnectionList).map((d) =>
|
||||
withNormalizedVerificationResult({ ...d }),
|
||||
);
|
||||
const adminConvertedData = filterFetched(response.data.adminAreaConnectionList).map((d) =>
|
||||
withNormalizedVerificationResult({
|
||||
...d,
|
||||
ctpvNm: d.ctpvNm || commonInfo.ctpvNm,
|
||||
}),
|
||||
);
|
||||
applyRowMap((m) => {
|
||||
m.set('treatmentPlantConnectionInp', toGridRows(facilityConvertedData));
|
||||
m.set('adminAreaConnectionInp', toGridRows(adminConvertedData));
|
||||
@@ -1338,7 +1355,6 @@ const SewagePipeInp = () => {
|
||||
rmrk: nullableTrimmedString(d.rmrk),
|
||||
lyngPrlgWhol: formatNumber(d.lyngPrlg, "lyngPrlg"),
|
||||
dmltnPrlgWhol: formatNumber(d.dmltnPrlg, "dmltnPrlg"),
|
||||
pipeByPrstWhol: formatNumber(d.pipeByPrstWhol, "pipeByPrstWhol"),
|
||||
};
|
||||
});
|
||||
const requestData: SeweragePipeInputPipeTypeStatusSubmitRequest = {
|
||||
@@ -1455,7 +1471,13 @@ const SewagePipeInp = () => {
|
||||
};
|
||||
|
||||
try {
|
||||
const imrResponse = await statisticsApi.callImrService(imrParam);
|
||||
const imrResponse = await callImrServiceWithRollbackOnFailure(imrParam, {
|
||||
statsYr: values.year ?? "",
|
||||
statsCd: statsCdForTab,
|
||||
sewerBzmnCd: values?.bsnmCd ?? "",
|
||||
rollbackStatusCode: statusForTab?.lclgvSbmsnSttsCd ?? "",
|
||||
mdfrUuid: userInfo.userUnqId,
|
||||
});
|
||||
if (imrResponse.job_id) {
|
||||
await waitForImrJobCompleted(
|
||||
imrResponse.job_id,
|
||||
@@ -1830,7 +1852,6 @@ const SewagePipeInp = () => {
|
||||
rmrk: nullableTrimmedString(d.rmrk),
|
||||
lyngPrlgWhol: formatNumber(d.lyngPrlg, "lyngPrlg"),
|
||||
dmltnPrlgWhol: formatNumber(d.dmltnPrlg, "dmltnPrlg"),
|
||||
pipeByPrstWhol: formatNumber(d.pipeByPrstWhol, "pipeByPrstWhol"),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -2237,17 +2258,7 @@ const SewagePipeInp = () => {
|
||||
tabKey,
|
||||
);
|
||||
if (Array.isArray(errors) && errors.length > 0) {
|
||||
return errors
|
||||
.map((e) => {
|
||||
const prefix =
|
||||
e.vrfcCd === "IMR" ? "시계열 검증 - " : (e.vrfcCd === "NV" ? "일반검증 - " : "모집단 검증 - ");
|
||||
const comp = e.cmprCn ?? "";
|
||||
const now = e.nowCn ?? "";
|
||||
return `${prefix}${e.rsnExpln}
|
||||
(검증 기준값: ${comp} / 현재 입력값: ${now})`;
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join("\n");
|
||||
return formatVerificationTooltip(errors);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -11,6 +11,7 @@ import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
||||
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
||||
import { sewagePipeMaintainApiService } from "@/entities/statistics/api/input/statistics-input-sewage-pipe-maintain-service";
|
||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||
import { callImrServiceWithRollbackOnFailure } from "@/components/util/input/call-imr-with-rollback";
|
||||
import type {
|
||||
SewagePipeMaintainDredgingSaveItem,
|
||||
SewagePipeMaintainDredgingSaveRequest,
|
||||
@@ -69,7 +70,11 @@ import {
|
||||
patchFooterVerificationByTab,
|
||||
patchVerificationFailedByTab,
|
||||
} from "@/components/util/input/verification-failed-flag";
|
||||
import type { VerificationResultLikeMap } from "@/components/util/input/verification-result-display";
|
||||
import {
|
||||
formatVerificationTooltip,
|
||||
withNormalizedVerificationResult,
|
||||
type VerificationResultLikeMap,
|
||||
} from "@/components/util/input/verification-result-display";
|
||||
import { nullableTrimmedString } from "@/components/util/input/nullableString";
|
||||
import { useAdminStore } from "@/store/admin-store";
|
||||
import { useStatisticsInputFocusStore } from "@/store/statistics-input-focus-store";
|
||||
@@ -444,10 +449,12 @@ const SewagePipeMaintainInp = () => {
|
||||
repairStatusList ?? [],
|
||||
sidoListRef.current,
|
||||
searchContext,
|
||||
).map((d) => ({
|
||||
ctpvNm: commonInfo.ctpvNm,
|
||||
...d,
|
||||
}));
|
||||
).map((d) =>
|
||||
withNormalizedVerificationResult({
|
||||
ctpvNm: commonInfo.ctpvNm,
|
||||
...d,
|
||||
}),
|
||||
);
|
||||
const gridRows = toGridRows(convertedData);
|
||||
|
||||
applyRowMap(mergeIntoExistingMap, (m) => {
|
||||
@@ -487,10 +494,12 @@ const SewagePipeMaintainInp = () => {
|
||||
pipeDredgingStatusList ?? [],
|
||||
sidoListRef.current,
|
||||
searchContext,
|
||||
).map((d) => ({
|
||||
ctpvNm: commonInfo.ctpvNm,
|
||||
...d,
|
||||
}));
|
||||
).map((d) =>
|
||||
withNormalizedVerificationResult({
|
||||
ctpvNm: commonInfo.ctpvNm,
|
||||
...d,
|
||||
}),
|
||||
);
|
||||
const gridRows = toGridRows(convertedData);
|
||||
|
||||
applyRowMap(mergeIntoExistingMap, (m) => {
|
||||
@@ -678,7 +687,13 @@ const SewagePipeMaintainInp = () => {
|
||||
};
|
||||
|
||||
try {
|
||||
const imrResponse = await statisticsApi.callImrService(imrParam);
|
||||
const imrResponse = await callImrServiceWithRollbackOnFailure(imrParam, {
|
||||
statsYr: lastSearchedValues.year ?? "",
|
||||
statsCd: statsCdForTab,
|
||||
sewerBzmnCd: lastSearchedValues?.bsnmCd ?? "",
|
||||
rollbackStatusCode: activeTabStatus?.lclgvSbmsnSttsCd ?? "",
|
||||
mdfrUuid: userInfo.userUnqId,
|
||||
});
|
||||
if (imrResponse.job_id) {
|
||||
await waitForImrJobCompleted(
|
||||
imrResponse.job_id,
|
||||
@@ -1103,14 +1118,7 @@ const SewagePipeMaintainInp = () => {
|
||||
if (!verification) return;
|
||||
const errors = verification[fieldName];
|
||||
if (Array.isArray(errors) && errors.length > 0) {
|
||||
return errors
|
||||
.map((e) => {
|
||||
const prefix =
|
||||
e.vrfcCd === "IMR" ? "시계열 검증 - " : e.vrfcCd === "NV" ? "일반검증 - " : "모집단 검증 - ";
|
||||
return `${prefix}${e.rsnExpln}(검증 기준값: ${e.cmprCn} / 현재 입력값: ${e.nowCn})`;
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join("\n");
|
||||
return formatVerificationTooltip(errors);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import { nullableTrimmedString } from "@/components/util/input/nullableString";
|
||||
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
||||
import { statisticsInputSewageReservoirPumpApi } from "@/entities/statistics/api/input/statistics-input-sewage-reservoir-pump-service";
|
||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||
import { callImrServiceWithRollbackOnFailure } from "@/components/util/input/call-imr-with-rollback";
|
||||
import {
|
||||
type RainfallPumpStationItem,
|
||||
type RainfallPumpStationSaveItem,
|
||||
@@ -89,7 +90,11 @@ import {
|
||||
patchFooterVerificationByTab,
|
||||
patchVerificationFailedByTab,
|
||||
} from "@/components/util/input/verification-failed-flag";
|
||||
import type { VerificationResultLikeMap } from "@/components/util/input/verification-result-display";
|
||||
import {
|
||||
formatVerificationTooltip,
|
||||
normalizeVerificationResultMap,
|
||||
type VerificationResultLikeMap,
|
||||
} from "@/components/util/input/verification-result-display";
|
||||
import { useAdminStore } from "@/store/admin-store";
|
||||
import { useTabStore } from "@/store/tab-store";
|
||||
|
||||
@@ -279,7 +284,7 @@ function mapSewageReservoirListToGridRows(
|
||||
},
|
||||
])[0] as GridRowWithVerification;
|
||||
if (item.verificationResult) {
|
||||
row.verificationResult = item.verificationResult;
|
||||
row.verificationResult = normalizeVerificationResultMap(item.verificationResult);
|
||||
}
|
||||
return row;
|
||||
});
|
||||
@@ -435,7 +440,7 @@ function mapRainfallPumpStationListToGridRows(
|
||||
])[0] as GridRowWithVerification;
|
||||
|
||||
if (item.verificationResult) {
|
||||
row.verificationResult = item.verificationResult;
|
||||
row.verificationResult = normalizeVerificationResultMap(item.verificationResult);
|
||||
}
|
||||
return row;
|
||||
});
|
||||
@@ -864,7 +869,13 @@ const SewageReservoirPumpInp = () => {
|
||||
};
|
||||
|
||||
try {
|
||||
const imrResponse = await statisticsApi.callImrService(imrParam);
|
||||
const imrResponse = await callImrServiceWithRollbackOnFailure(imrParam, {
|
||||
statsYr: lastSearchedValues.year ?? "",
|
||||
statsCd: statsCdForTab,
|
||||
sewerBzmnCd: lastSearchedValues?.bsnmCd ?? "",
|
||||
rollbackStatusCode: activeTabStatus?.lclgvSbmsnSttsCd ?? "",
|
||||
mdfrUuid: userInfo.userUnqId,
|
||||
});
|
||||
if (imrResponse.job_id) {
|
||||
await waitForImrJobCompleted(
|
||||
imrResponse.job_id,
|
||||
@@ -1516,19 +1527,7 @@ const SewageReservoirPumpInp = () => {
|
||||
if (!verification) return;
|
||||
const errors = verification[fieldName];
|
||||
if (Array.isArray(errors) && errors.length > 0) {
|
||||
return errors
|
||||
.map((e) => {
|
||||
const prefix =
|
||||
e.vrfcCd === "IMR"
|
||||
? "시계열 검증 - "
|
||||
: e.vrfcCd === "NV"
|
||||
? "일반검증 - "
|
||||
: "모집단 검증 -";
|
||||
return `${prefix}${e.rsnExpln}
|
||||
(검증 기준값: ${e.cmprCn} / 현재 입력값: ${e.nowCn})`;
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join("\n");
|
||||
return formatVerificationTooltip(errors);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import { useStatisticsInputPendingNavigation } from "@/shared/lib/use-statistics
|
||||
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
||||
import { statisticsInputSewerageFinanceApi } from "@/entities/statistics/api/input/statistics-input-sewerage-finance-service";
|
||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||
import { callImrServiceWithRollbackOnFailure } from "@/components/util/input/call-imr-with-rollback";
|
||||
import type {
|
||||
CauserBurdenItem,
|
||||
CauserBurdenSaveItem,
|
||||
@@ -73,7 +74,11 @@ import {
|
||||
patchFooterVerificationByTab,
|
||||
patchVerificationFailedByTab,
|
||||
} from "@/components/util/input/verification-failed-flag";
|
||||
import type { VerificationResultLikeMap } from "@/components/util/input/verification-result-display";
|
||||
import {
|
||||
formatVerificationTooltip,
|
||||
normalizeVerificationResultMap,
|
||||
type VerificationResultLikeMap,
|
||||
} from "@/components/util/input/verification-result-display";
|
||||
import { nullableTrimmedString } from "@/components/util/input/nullableString";
|
||||
import { useAdminStore } from "@/store/admin-store";
|
||||
import { useTabStore } from "@/store/tab-store";
|
||||
@@ -174,7 +179,9 @@ function mapRegionalListToGridRows<
|
||||
return filterBySelectedAdmdstCd(list, sidoListRef.current, values).map((item) => {
|
||||
const { verificationResult, ...rest } = item;
|
||||
const row = toGridRows([{ ctpvNm, ...rest }])[0] as GridRowWithVerification;
|
||||
if (verificationResult) row.verificationResult = verificationResult;
|
||||
if (verificationResult) {
|
||||
row.verificationResult = normalizeVerificationResultMap(verificationResult);
|
||||
}
|
||||
return row;
|
||||
});
|
||||
}
|
||||
@@ -940,7 +947,13 @@ const SewerageFinanceInp = () => {
|
||||
};
|
||||
|
||||
try {
|
||||
const imrResponse = await statisticsApi.callImrService(imrParam);
|
||||
const imrResponse = await callImrServiceWithRollbackOnFailure(imrParam, {
|
||||
statsYr: lastSearchedValues.year ?? "",
|
||||
statsCd: statsCdForTab,
|
||||
sewerBzmnCd: lastSearchedValues?.bsnmCd ?? "",
|
||||
rollbackStatusCode: activeTabStatus?.lclgvSbmsnSttsCd ?? "",
|
||||
mdfrUuid: userInfo.userUnqId,
|
||||
});
|
||||
if (imrResponse.job_id) {
|
||||
await waitForImrJobCompleted(
|
||||
imrResponse.job_id,
|
||||
@@ -1215,18 +1228,7 @@ const SewerageFinanceInp = () => {
|
||||
if (!verification) return;
|
||||
const errors = verification[fieldName];
|
||||
if (Array.isArray(errors) && errors.length > 0) {
|
||||
return errors
|
||||
.map((e) => {
|
||||
const prefix =
|
||||
e.vrfcCd === "IMR"
|
||||
? "시계열 검증 - "
|
||||
: e.vrfcCd === "NV"
|
||||
? "일반검증 - "
|
||||
: "모집단 검증 - ";
|
||||
return `${prefix}${e.rsnExpln}(검증 기준값: ${e.cmprCn} / 현재 입력값: ${e.nowCn})`;
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join("\n");
|
||||
return formatVerificationTooltip(errors);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
||||
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||
import { callImrServiceWithRollbackOnFailure } from "@/components/util/input/call-imr-with-rollback";
|
||||
import {
|
||||
type CheckInputPeriodItem,
|
||||
getVerificationPeriodActionBlockedMessage,
|
||||
@@ -58,7 +59,11 @@ import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||
import { toExcelExportSearchContextFromSearchForm } from "@/components/util/gridExcelExport";
|
||||
import { nullableTrimmedString } from "@/components/util/input/nullableString";
|
||||
import { isVerificationFailedFromCommonInfo } from "@/components/util/input/verification-failed-flag";
|
||||
import type { VerificationResultLikeMap } from "@/components/util/input/verification-result-display";
|
||||
import {
|
||||
formatVerificationTooltip,
|
||||
normalizeVerificationResultMap,
|
||||
type VerificationResultLikeMap,
|
||||
} from "@/components/util/input/verification-result-display";
|
||||
import { useAdminStore } from "@/store/admin-store";
|
||||
import { useStatisticsInputFocusStore } from "@/store/statistics-input-focus-store";
|
||||
import { useTabStore } from "@/store/tab-store";
|
||||
@@ -87,7 +92,7 @@ const remapCommonInfoVerificationToGridFields = (
|
||||
// API 키로도 조회 가능하도록 유지
|
||||
if (gridField !== key) remapped[key] = errors;
|
||||
}
|
||||
return remapped;
|
||||
return normalizeVerificationResultMap(remapped) ?? remapped;
|
||||
};
|
||||
|
||||
/** 컬럼 가이드 API 조회용 통계코드 (하수도 보급률) */
|
||||
@@ -302,7 +307,11 @@ const SeweragePenetrationRateInp = () => {
|
||||
setRowData(
|
||||
convertedData.map((d) => {
|
||||
const row = toGridRows([d])[0] as GridRowWithVerification;
|
||||
if (d.verificationResult) row.verificationResult = d.verificationResult;
|
||||
if (d.verificationResult) {
|
||||
row.verificationResult = normalizeVerificationResultMap(
|
||||
d.verificationResult,
|
||||
);
|
||||
}
|
||||
return row;
|
||||
})
|
||||
);
|
||||
@@ -558,7 +567,13 @@ const SeweragePenetrationRateInp = () => {
|
||||
};
|
||||
|
||||
try {
|
||||
const imrResponse = await statisticsApi.callImrService(imrParam);
|
||||
const imrResponse = await callImrServiceWithRollbackOnFailure(imrParam, {
|
||||
statsYr: searchValues?.year ?? "",
|
||||
statsCd,
|
||||
sewerBzmnCd: searchValues?.bsnmCd ?? "",
|
||||
rollbackStatusCode: statusInfo?.lclgvSbmsnSttsCd ?? "",
|
||||
mdfrUuid: userInfo.userUnqId,
|
||||
});
|
||||
if (imrResponse.job_id) {
|
||||
await waitForImrJobCompleted(imrResponse.job_id, (id) =>
|
||||
statisticsApi.getImrStatus(id),
|
||||
@@ -867,14 +882,7 @@ const SeweragePenetrationRateInp = () => {
|
||||
if (!verification) return;
|
||||
const errors = verification[fieldName];
|
||||
if (Array.isArray(errors) && errors.length > 0) {
|
||||
return errors
|
||||
.map((e) => {
|
||||
const prefix = e.vrfcCd === 'IMR' ? '시계열 검증 - ' : (e.vrfcCd === 'NV' ? '일반검증 - ' : '모집단 검증 -');
|
||||
return `${prefix}${e.rsnExpln}
|
||||
(검증 기준값: ${e.cmprCn} / 현재 입력값: ${e.nowCn})`;
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join('\n');
|
||||
return formatVerificationTooltip(errors);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -9,6 +9,7 @@ import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
||||
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
||||
import { statisticsInputSewerageServiceLevelApi } from "@/entities/statistics/api/input/statistics-input-sewerage-service-level-service";
|
||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||
import { callImrServiceWithRollbackOnFailure } from "@/components/util/input/call-imr-with-rollback";
|
||||
import {
|
||||
SEWERAGE_SERVICE_LEVEL_COMPLAINT_STATS_CD,
|
||||
SEWERAGE_SERVICE_LEVEL_RESIDENT_FRIENDLY_FACT_STATS_CD,
|
||||
@@ -63,7 +64,11 @@ import {
|
||||
patchFooterVerificationByTab,
|
||||
patchVerificationFailedByTab,
|
||||
} from "@/components/util/input/verification-failed-flag";
|
||||
import type { VerificationResultLikeMap } from "@/components/util/input/verification-result-display";
|
||||
import {
|
||||
formatVerificationTooltip,
|
||||
normalizeVerificationResultMap,
|
||||
type VerificationResultLikeMap,
|
||||
} from "@/components/util/input/verification-result-display";
|
||||
import { nullableTrimmedString } from "@/components/util/input/nullableString";
|
||||
import { useAdminStore } from "@/store/admin-store";
|
||||
import { useTabStore } from "@/store/tab-store";
|
||||
@@ -187,7 +192,9 @@ function mapServiceLevelListToGridRows<
|
||||
return filterBySelectedAdmdstCd(list, sidoListRef.current, values).map((item) => {
|
||||
const { verificationResult, ...rest } = item;
|
||||
const row = toGridRows([{ ctpvNm, ...rest }])[0] as GridRowWithVerification;
|
||||
if (verificationResult) row.verificationResult = verificationResult;
|
||||
if (verificationResult) {
|
||||
row.verificationResult = normalizeVerificationResultMap(verificationResult);
|
||||
}
|
||||
return row;
|
||||
});
|
||||
}
|
||||
@@ -839,7 +846,13 @@ const SewerageServiceLevelInp = () => {
|
||||
};
|
||||
|
||||
try {
|
||||
const imrResponse = await statisticsApi.callImrService(imrParam);
|
||||
const imrResponse = await callImrServiceWithRollbackOnFailure(imrParam, {
|
||||
statsYr: lastSearchedValues.year ?? "",
|
||||
statsCd: statsCdForTab,
|
||||
sewerBzmnCd: lastSearchedValues?.bsnmCd ?? "",
|
||||
rollbackStatusCode: activeTabStatus?.lclgvSbmsnSttsCd ?? "",
|
||||
mdfrUuid: userInfo.userUnqId,
|
||||
});
|
||||
if (imrResponse.job_id) {
|
||||
await waitForImrJobCompleted(
|
||||
imrResponse.job_id,
|
||||
@@ -1146,18 +1159,7 @@ const SewerageServiceLevelInp = () => {
|
||||
if (!verification) return;
|
||||
const errors = verification[fieldName];
|
||||
if (Array.isArray(errors) && errors.length > 0) {
|
||||
return errors
|
||||
.map((e) => {
|
||||
const prefix =
|
||||
e.vrfcCd === "IMR"
|
||||
? "시계열 검증 - "
|
||||
: e.vrfcCd === "NV"
|
||||
? "일반검증 - "
|
||||
: "모집단 검증 - ";
|
||||
return `${prefix}${e.rsnExpln}(검증 기준값: ${e.cmprCn} / 현재 입력값: ${e.nowCn})`;
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join("\n");
|
||||
return formatVerificationTooltip(errors);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@ const StatisticsReviewHistory = () => {
|
||||
{ name: "ctpvNm", fieldName: "ctpvNm", header: { text: "시도" }, editable: false },
|
||||
{ name: "sggNm", fieldName: "sggNm", header: { text: "시군구" }, editable: false },
|
||||
{ name: "menuNm", fieldName: "menuNm", header: { text: "통계항목" }, editable: false },
|
||||
{ name: "chckerOpinionSm", fieldName: "chckerOpinionSm", header: { text: "검토자의견" }, editable: false },
|
||||
{ name: "wrterOpinionSm", fieldName: "wrterOpinionSm", header: { text: "처리내역" }, editable: false },
|
||||
{ name: "splmntOpnnCn", fieldName: "splmntOpnnCn", header: { text: "검토자의견" }, editable: false },
|
||||
{ name: "rjctOpnnCn", fieldName: "rjctOpnnCn", header: { text: "반려의견" }, editable: false },
|
||||
];
|
||||
|
||||
const columnLayout = [
|
||||
@@ -29,8 +29,8 @@ const StatisticsReviewHistory = () => {
|
||||
"ctpvNm",
|
||||
"sggNm",
|
||||
"menuNm",
|
||||
"chckerOpinionSm",
|
||||
"wrterOpinionSm",
|
||||
"splmntOpnnCn",
|
||||
"rjctOpnnCn",
|
||||
];
|
||||
|
||||
const handleSearch = async (values: SearchFormValues) => {
|
||||
|
||||
@@ -21,6 +21,7 @@ import { nullableTrimmedString } from "@/components/util/input/nullableString";
|
||||
import { statisticsInputSewSupplyRateApi } from "@/entities/statistics/api/input/statistics-input-sew-supply-rate-service";
|
||||
import { statisticsInputWaterReuseApi } from "@/entities/statistics/api/input/statistics-input-water-reuse-service";
|
||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||
import { callImrServiceWithRollbackOnFailure } from "@/components/util/input/call-imr-with-rollback";
|
||||
import {
|
||||
type PublicSewageTreatWaterReuseItem,
|
||||
type PublicSewageTreatWaterReuseSaveItem,
|
||||
@@ -93,7 +94,11 @@ import {
|
||||
patchFooterVerificationByTab,
|
||||
patchVerificationFailedByTab,
|
||||
} from "@/components/util/input/verification-failed-flag";
|
||||
import type { VerificationResultLikeMap } from "@/components/util/input/verification-result-display";
|
||||
import {
|
||||
formatVerificationTooltip,
|
||||
normalizeVerificationResultMap,
|
||||
type VerificationResultLikeMap,
|
||||
} from "@/components/util/input/verification-result-display";
|
||||
import { useAdminStore } from "@/store/admin-store";
|
||||
import { useTabStore } from "@/store/tab-store";
|
||||
|
||||
@@ -443,7 +448,9 @@ function mapPublicSewageTreatWaterReuseListToGridRows(
|
||||
instlAprvYmd: formatCompactYmdForGrid(item.instlAprvYmd),
|
||||
},
|
||||
])[0] as GridRowWithVerification;
|
||||
if (verificationResult) row.verificationResult = verificationResult;
|
||||
if (verificationResult) {
|
||||
row.verificationResult = normalizeVerificationResultMap(verificationResult);
|
||||
}
|
||||
return row;
|
||||
});
|
||||
}
|
||||
@@ -462,7 +469,9 @@ function mapRecycledWaterStatusListToGridRows(
|
||||
oprtngStrtYmd: formatCompactYmdForGrid(item.oprtngStrtYmd),
|
||||
},
|
||||
])[0] as GridRowWithVerification;
|
||||
if (verificationResult) row.verificationResult = verificationResult;
|
||||
if (verificationResult) {
|
||||
row.verificationResult = normalizeVerificationResultMap(verificationResult);
|
||||
}
|
||||
return row;
|
||||
});
|
||||
}
|
||||
@@ -480,7 +489,9 @@ function mapRainFallUtilFactStatusListToGridRows(
|
||||
cmptnYmd: formatCompactYmdForGrid(item.cmptnYmd),
|
||||
},
|
||||
])[0] as GridRowWithVerification;
|
||||
if (verificationResult) row.verificationResult = verificationResult;
|
||||
if (verificationResult) {
|
||||
row.verificationResult = normalizeVerificationResultMap(verificationResult);
|
||||
}
|
||||
return row;
|
||||
});
|
||||
}
|
||||
@@ -497,7 +508,9 @@ function mapTreatWaterReuseStatusListToGridRows<
|
||||
coRegYmd: formatCompactYmdForGrid(item.coRegYmd),
|
||||
},
|
||||
])[0] as GridRowWithVerification;
|
||||
if (verificationResult) row.verificationResult = verificationResult;
|
||||
if (verificationResult) {
|
||||
row.verificationResult = normalizeVerificationResultMap(verificationResult);
|
||||
}
|
||||
return row;
|
||||
});
|
||||
}
|
||||
@@ -1355,7 +1368,13 @@ const WaterReuseInp = () => {
|
||||
};
|
||||
|
||||
try {
|
||||
const imrResponse = await statisticsApi.callImrService(imrParam);
|
||||
const imrResponse = await callImrServiceWithRollbackOnFailure(imrParam, {
|
||||
statsYr: lastSearchedValues.year ?? "",
|
||||
statsCd: statsCdForTab,
|
||||
sewerBzmnCd: lastSearchedValues?.bsnmCd ?? "",
|
||||
rollbackStatusCode: activeTabStatus?.lclgvSbmsnSttsCd ?? "",
|
||||
mdfrUuid: userInfo.userUnqId,
|
||||
});
|
||||
if (imrResponse.job_id) {
|
||||
await waitForImrJobCompleted(
|
||||
imrResponse.job_id,
|
||||
@@ -2063,18 +2082,7 @@ const WaterReuseInp = () => {
|
||||
if (!verification) return;
|
||||
const errors = verification[fieldName];
|
||||
if (Array.isArray(errors) && errors.length > 0) {
|
||||
return errors
|
||||
.map((e) => {
|
||||
const prefix =
|
||||
e.vrfcCd === "IMR"
|
||||
? "시계열 검증 - "
|
||||
: e.vrfcCd === "NV"
|
||||
? "일반검증 - "
|
||||
: "모집단 검증 - ";
|
||||
return `${prefix}${e.rsnExpln}(검증 기준값: ${e.cmprCn} / 현재 입력값: ${e.nowCn})`;
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join("\n");
|
||||
return formatVerificationTooltip(errors);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -49,7 +49,6 @@ const ExcretaTreatmentFacilityRvw = () => {
|
||||
const [reviewOpinionContext, setReviewOpinionContext] =
|
||||
useState<ReviewOpinionDialogContext | null>(null);
|
||||
const [latestReviewOpinion, setLatestReviewOpinion] = useState("");
|
||||
const [latestProcessHistory, setLatestProcessHistory] = useState("");
|
||||
const [lastSearchValues, setLastSearchValues] = useState<SearchFormValues | null>(null);
|
||||
|
||||
const columnInfo = useMemo(() => {
|
||||
@@ -116,7 +115,6 @@ const ExcretaTreatmentFacilityRvw = () => {
|
||||
setStatsStatusInfo({});
|
||||
setReviewOpinionContext(null);
|
||||
setLatestReviewOpinion("");
|
||||
setLatestProcessHistory("");
|
||||
setLastSearchValues(null);
|
||||
setReviewOpinionOpen(false);
|
||||
setReturnDialogOpen(false);
|
||||
@@ -170,14 +168,12 @@ const ExcretaTreatmentFacilityRvw = () => {
|
||||
statsCd: statsInfo.statsCd ?? "",
|
||||
});
|
||||
setLatestReviewOpinion(statsInfo.splmntOpnnCn ?? "");
|
||||
setLatestProcessHistory(statsInfo.splmntRsltCn ?? "");
|
||||
setRowData(toGridRows(convertedData as unknown as object[]));
|
||||
} else {
|
||||
setRowData([]);
|
||||
setStatsStatusInfo({});
|
||||
setReviewOpinionContext(null);
|
||||
setLatestReviewOpinion("");
|
||||
setLatestProcessHistory("");
|
||||
alert(response.message || "데이터가 없습니다.");
|
||||
}
|
||||
} catch {
|
||||
@@ -216,7 +212,6 @@ const ExcretaTreatmentFacilityRvw = () => {
|
||||
|
||||
const row = detailRes.data?.[0];
|
||||
setLatestReviewOpinion(row?.splmntOpnnCn ?? "");
|
||||
setLatestProcessHistory(row?.splmntRsltCn ?? "");
|
||||
setReviewOpinionOpen(true);
|
||||
} catch {
|
||||
alert("검토의견 조회 중 오류가 발생했습니다.");
|
||||
@@ -234,10 +229,8 @@ const ExcretaTreatmentFacilityRvw = () => {
|
||||
setStatsStatusInfo((prev) => ({
|
||||
...prev,
|
||||
splmntOpnnCn: param.splmntOpnnCn,
|
||||
splmntRsltCn: param.splmntRsltCn,
|
||||
}));
|
||||
setLatestReviewOpinion(param.splmntOpnnCn);
|
||||
setLatestProcessHistory(param.splmntRsltCn);
|
||||
} catch {
|
||||
alert("저장 중 오류가 발생했습니다.");
|
||||
}
|
||||
@@ -297,7 +290,6 @@ const ExcretaTreatmentFacilityRvw = () => {
|
||||
onOpenChange={setReviewOpinionOpen}
|
||||
context={reviewOpinionContext}
|
||||
initialReviewOpinion={latestReviewOpinion}
|
||||
initialProcessHistory={latestProcessHistory}
|
||||
onSave={saveReviewOpinion}
|
||||
/>
|
||||
<ReviewSubmitDialog
|
||||
|
||||
@@ -102,7 +102,6 @@ const PrivateSewageFacilityRvw = () => {
|
||||
}, [activeStatsStatusInfo.statsCd, lastSearchValues]);
|
||||
|
||||
const latestReviewOpinion = activeStatsStatusInfo.splmntOpnnCn ?? "";
|
||||
const latestProcessHistory = activeStatsStatusInfo.splmntRsltCn ?? "";
|
||||
|
||||
const submitDialogContext = useMemo<ReviewerInfoRequest | null>(() => {
|
||||
if (lastSearchValues == null) return null;
|
||||
@@ -284,7 +283,6 @@ const PrivateSewageFacilityRvw = () => {
|
||||
next.set(activeTab, {
|
||||
...(next.get(activeTab) ?? {}),
|
||||
splmntOpnnCn: row?.splmntOpnnCn ?? "",
|
||||
splmntRsltCn: row?.splmntRsltCn ?? "",
|
||||
});
|
||||
return next;
|
||||
});
|
||||
@@ -307,7 +305,6 @@ const PrivateSewageFacilityRvw = () => {
|
||||
next.set(activeTab, {
|
||||
...(next.get(activeTab) ?? {}),
|
||||
splmntOpnnCn: param.splmntOpnnCn,
|
||||
splmntRsltCn: param.splmntRsltCn,
|
||||
});
|
||||
return next;
|
||||
});
|
||||
@@ -411,7 +408,6 @@ const PrivateSewageFacilityRvw = () => {
|
||||
onOpenChange={setReviewOpinionOpen}
|
||||
context={reviewOpinionContext}
|
||||
initialReviewOpinion={latestReviewOpinion}
|
||||
initialProcessHistory={latestProcessHistory}
|
||||
onSave={saveReviewOpinion}
|
||||
/>
|
||||
<ReviewSubmitDialog
|
||||
|
||||
@@ -41,7 +41,6 @@ const PublicSewageFacilityRvw = () => {
|
||||
const [reviewOpinionContext, setReviewOpinionContext] =
|
||||
useState<ReviewOpinionDialogContext | null>(null);
|
||||
const [latestReviewOpinion, setLatestReviewOpinion] = useState("");
|
||||
const [latestProcessHistory, setLatestProcessHistory] = useState("");
|
||||
const [lastSearchValues, setLastSearchValues] = useState<SearchFormValues | null>(null);
|
||||
|
||||
const columnInfo = useMemo(() => {
|
||||
@@ -100,7 +99,6 @@ const PublicSewageFacilityRvw = () => {
|
||||
setStatsStatusInfo({});
|
||||
setReviewOpinionContext(null);
|
||||
setLatestReviewOpinion("");
|
||||
setLatestProcessHistory("");
|
||||
setLastSearchValues(null);
|
||||
setSubmitDialogOpen(false);
|
||||
};
|
||||
@@ -143,16 +141,12 @@ const PublicSewageFacilityRvw = () => {
|
||||
setLatestReviewOpinion(
|
||||
response.data.statsStatusInfo.splmntOpnnCn ?? "",
|
||||
);
|
||||
setLatestProcessHistory(
|
||||
response.data.statsStatusInfo.splmntRsltCn ?? "",
|
||||
);
|
||||
setRowData(toGridRows(convertedData as unknown as object[]));
|
||||
} else {
|
||||
setRowData([]);
|
||||
setStatsStatusInfo({});
|
||||
setReviewOpinionContext(null);
|
||||
setLatestReviewOpinion("");
|
||||
setLatestProcessHistory("");
|
||||
alert(response.message || "데이터가 없습니다.");
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -192,7 +186,6 @@ const PublicSewageFacilityRvw = () => {
|
||||
|
||||
const row = detailRes.data?.[0];
|
||||
setLatestReviewOpinion(row?.splmntOpnnCn ?? "");
|
||||
setLatestProcessHistory(row?.splmntRsltCn ?? "");
|
||||
setReviewOpinionOpen(true);
|
||||
} catch {
|
||||
alert("검토의견 조회 중 오류가 발생했습니다.");
|
||||
@@ -210,10 +203,8 @@ const PublicSewageFacilityRvw = () => {
|
||||
setStatsStatusInfo((prev) => ({
|
||||
...prev,
|
||||
splmntOpnnCn: param.splmntOpnnCn,
|
||||
splmntRsltCn: param.splmntRsltCn,
|
||||
}));
|
||||
setLatestReviewOpinion(param.splmntOpnnCn);
|
||||
setLatestProcessHistory(param.splmntRsltCn);
|
||||
} catch {
|
||||
alert("저장 중 오류가 발생했습니다.");
|
||||
}
|
||||
@@ -267,7 +258,6 @@ const PublicSewageFacilityRvw = () => {
|
||||
onOpenChange={setReviewOpinionOpen}
|
||||
context={reviewOpinionContext}
|
||||
initialReviewOpinion={latestReviewOpinion}
|
||||
initialProcessHistory={latestProcessHistory}
|
||||
onSave={saveReviewOpinion}
|
||||
/>
|
||||
<ReviewSubmitDialog
|
||||
|
||||
@@ -47,7 +47,6 @@ const PumpingStationRvw = () => {
|
||||
const [reviewOpinionContext, setReviewOpinionContext] =
|
||||
useState<ReviewOpinionDialogContext | null>(null);
|
||||
const [latestReviewOpinion, setLatestReviewOpinion] = useState("");
|
||||
const [latestProcessHistory, setLatestProcessHistory] = useState("");
|
||||
const [lastSearchValues, setLastSearchValues] = useState<SearchFormValues | null>(null);
|
||||
|
||||
const columnInfo = useMemo(() => {
|
||||
@@ -111,7 +110,6 @@ const PumpingStationRvw = () => {
|
||||
setStatsStatusInfo({});
|
||||
setReviewOpinionContext(null);
|
||||
setLatestReviewOpinion("");
|
||||
setLatestProcessHistory("");
|
||||
setLastSearchValues(null);
|
||||
setReviewOpinionOpen(false);
|
||||
setReturnDialogOpen(false);
|
||||
@@ -157,14 +155,12 @@ const PumpingStationRvw = () => {
|
||||
statsCd: statsInfo.statsCd ?? "",
|
||||
});
|
||||
setLatestReviewOpinion(statsInfo.splmntOpnnCn ?? "");
|
||||
setLatestProcessHistory(statsInfo.splmntRsltCn ?? "");
|
||||
setRowData(toGridRows(convertedData));
|
||||
} else {
|
||||
setRowData([]);
|
||||
setStatsStatusInfo({});
|
||||
setReviewOpinionContext(null);
|
||||
setLatestReviewOpinion("");
|
||||
setLatestProcessHistory("");
|
||||
alert(response.message || "데이터가 없습니다.");
|
||||
}
|
||||
} catch {
|
||||
@@ -203,7 +199,6 @@ const PumpingStationRvw = () => {
|
||||
|
||||
const row = detailRes.data?.[0];
|
||||
setLatestReviewOpinion(row?.splmntOpnnCn ?? "");
|
||||
setLatestProcessHistory(row?.splmntRsltCn ?? "");
|
||||
setReviewOpinionOpen(true);
|
||||
} catch {
|
||||
alert("검토의견 조회 중 오류가 발생했습니다.");
|
||||
@@ -221,10 +216,8 @@ const PumpingStationRvw = () => {
|
||||
setStatsStatusInfo((prev) => ({
|
||||
...prev,
|
||||
splmntOpnnCn: param.splmntOpnnCn,
|
||||
splmntRsltCn: param.splmntRsltCn,
|
||||
}));
|
||||
setLatestReviewOpinion(param.splmntOpnnCn);
|
||||
setLatestProcessHistory(param.splmntRsltCn);
|
||||
} catch {
|
||||
alert("저장 중 오류가 발생했습니다.");
|
||||
}
|
||||
@@ -284,7 +277,6 @@ const PumpingStationRvw = () => {
|
||||
onOpenChange={setReviewOpinionOpen}
|
||||
context={reviewOpinionContext}
|
||||
initialReviewOpinion={latestReviewOpinion}
|
||||
initialProcessHistory={latestProcessHistory}
|
||||
onSave={saveReviewOpinion}
|
||||
/>
|
||||
<ReviewSubmitDialog
|
||||
|
||||
@@ -30,8 +30,6 @@ export interface ReviewOpinionDialogProps {
|
||||
context: ReviewOpinionDialogContext | null;
|
||||
/** 다이얼로그 열릴 때 검토의견 초기값 */
|
||||
initialReviewOpinion?: string;
|
||||
/** 다이얼로그 열릴 때 처리내역 초기값 */
|
||||
initialProcessHistory?: string;
|
||||
/** 저장 시 생성된 param 전달 (API 호출 등) */
|
||||
onSave?: (param: ReviewOpinionSaveRequest) => void | Promise<void>;
|
||||
}
|
||||
@@ -41,18 +39,15 @@ export function ReviewOpinionDialog({
|
||||
onOpenChange,
|
||||
context,
|
||||
initialReviewOpinion = "",
|
||||
initialProcessHistory = "",
|
||||
onSave,
|
||||
}: ReviewOpinionDialogProps) {
|
||||
const { setMessage: alert } = useAlertStore((state) => state);
|
||||
const [reviewOpinion, setReviewOpinion] = useState("");
|
||||
const [processHistory, setProcessHistory] = useState("");
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const [reviewOpinionError, setReviewOpinionError] = useState(false);
|
||||
|
||||
const resetForm = () => {
|
||||
setReviewOpinion("");
|
||||
setProcessHistory("");
|
||||
setReviewOpinionError(false);
|
||||
};
|
||||
|
||||
@@ -64,8 +59,7 @@ export function ReviewOpinionDialog({
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
setReviewOpinion(initialReviewOpinion);
|
||||
setProcessHistory(initialProcessHistory);
|
||||
}, [open, initialReviewOpinion, initialProcessHistory]);
|
||||
}, [open, initialReviewOpinion]);
|
||||
|
||||
const handleSave = async () => {
|
||||
if (reviewOpinion.trim() === "") {
|
||||
@@ -96,7 +90,6 @@ export function ReviewOpinionDialog({
|
||||
sewerBzmnCd: context.sewerBzmnCd,
|
||||
statsCd: context.statsCd,
|
||||
splmntOpnnCn: reviewOpinion,
|
||||
splmntRsltCn: processHistory,
|
||||
mdfrUuid: userInfo.userUnqId,
|
||||
};
|
||||
await onSave?.(param);
|
||||
@@ -136,16 +129,6 @@ export function ReviewOpinionDialog({
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label className="text-label mb-2">처리내역</Label>
|
||||
<Textarea
|
||||
value={processHistory}
|
||||
onChange={(e) => setProcessHistory(e.target.value)}
|
||||
className="min-h-[10rem] resize-y !text-[1.3rem] !leading-6"
|
||||
placeholder="처리내역을 입력하세요."
|
||||
disabled={isSaving}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<DialogClose asChild>
|
||||
|
||||
@@ -30,8 +30,8 @@ export interface ReviewSubmitDialogProps {
|
||||
context: ReviewerInfoRequest | null;
|
||||
onSubmitted?: () => void | Promise<void>;
|
||||
/**
|
||||
* true면 검토의견·처리내역 UI를 숨기고
|
||||
* submit body에 statsCd / splmntOpnnCn / splmntRsltCn을 넣지 않음
|
||||
* true면 검토의견 UI를 숨기고
|
||||
* submit body에 statsCd / splmntOpnnCn을 넣지 않음
|
||||
*/
|
||||
hideOpinionFields?: boolean;
|
||||
}
|
||||
@@ -116,7 +116,6 @@ export function ReviewSubmitDialog({
|
||||
statsCd: context.statsCd,
|
||||
mdfrUuid: userInfo.userUnqId,
|
||||
splmntOpnnCn: reviewerInfo?.splmntOpnnCn ?? "",
|
||||
splmntRsltCn: reviewerInfo?.splmntRsltCn ?? "",
|
||||
};
|
||||
|
||||
const response = await statisticsApi.submitReview(submitParam);
|
||||
@@ -175,14 +174,6 @@ export function ReviewSubmitDialog({
|
||||
className="min-h-[10rem] p-2 resize-none !text-xl"
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-2 flex flex-col gap-2">
|
||||
<Label className="text-label">처리내역</Label>
|
||||
<Textarea
|
||||
value={reviewerInfo?.splmntRsltCn ?? "-"}
|
||||
readOnly
|
||||
className="min-h-[10rem] p-2 resize-none !text-xl"
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -105,7 +105,6 @@ const SewageExcretaRelatedRvw = () => {
|
||||
}, [activeStatsStatusInfo.statsCd, lastSearchValues]);
|
||||
|
||||
const latestReviewOpinion = activeStatsStatusInfo.splmntOpnnCn ?? "";
|
||||
const latestProcessHistory = activeStatsStatusInfo.splmntRsltCn ?? "";
|
||||
|
||||
const submitDialogContext = useMemo<ReviewerInfoRequest | null>(() => {
|
||||
if (lastSearchValues == null) return null;
|
||||
@@ -289,7 +288,6 @@ const SewageExcretaRelatedRvw = () => {
|
||||
next.set(activeTab, {
|
||||
...(next.get(activeTab) ?? {}),
|
||||
splmntOpnnCn: row?.splmntOpnnCn ?? "",
|
||||
splmntRsltCn: row?.splmntRsltCn ?? "",
|
||||
});
|
||||
return next;
|
||||
});
|
||||
@@ -312,7 +310,6 @@ const SewageExcretaRelatedRvw = () => {
|
||||
next.set(activeTab, {
|
||||
...(next.get(activeTab) ?? {}),
|
||||
splmntOpnnCn: param.splmntOpnnCn,
|
||||
splmntRsltCn: param.splmntRsltCn,
|
||||
});
|
||||
return next;
|
||||
});
|
||||
@@ -416,7 +413,6 @@ const SewageExcretaRelatedRvw = () => {
|
||||
onOpenChange={setReviewOpinionOpen}
|
||||
context={reviewOpinionContext}
|
||||
initialReviewOpinion={latestReviewOpinion}
|
||||
initialProcessHistory={latestProcessHistory}
|
||||
onSave={saveReviewOpinion}
|
||||
/>
|
||||
<ReviewSubmitDialog
|
||||
|
||||
@@ -105,7 +105,6 @@ const SewageExcretaSlurgeRvw = () => {
|
||||
}, [activeStatsStatusInfo.statsCd, lastSearchValues]);
|
||||
|
||||
const latestReviewOpinion = activeStatsStatusInfo.splmntOpnnCn ?? "";
|
||||
const latestProcessHistory = activeStatsStatusInfo.splmntRsltCn ?? "";
|
||||
|
||||
const submitDialogContext = useMemo<ReviewerInfoRequest | null>(() => {
|
||||
if (lastSearchValues == null) return null;
|
||||
@@ -290,7 +289,6 @@ const SewageExcretaSlurgeRvw = () => {
|
||||
next.set(activeTab, {
|
||||
...(next.get(activeTab) ?? {}),
|
||||
splmntOpnnCn: row?.splmntOpnnCn ?? "",
|
||||
splmntRsltCn: row?.splmntRsltCn ?? "",
|
||||
});
|
||||
return next;
|
||||
});
|
||||
@@ -313,7 +311,6 @@ const SewageExcretaSlurgeRvw = () => {
|
||||
next.set(activeTab, {
|
||||
...(next.get(activeTab) ?? {}),
|
||||
splmntOpnnCn: param.splmntOpnnCn,
|
||||
splmntRsltCn: param.splmntRsltCn,
|
||||
});
|
||||
return next;
|
||||
});
|
||||
@@ -417,7 +414,6 @@ const SewageExcretaSlurgeRvw = () => {
|
||||
onOpenChange={setReviewOpinionOpen}
|
||||
context={reviewOpinionContext}
|
||||
initialReviewOpinion={latestReviewOpinion}
|
||||
initialProcessHistory={latestProcessHistory}
|
||||
onSave={saveReviewOpinion}
|
||||
/>
|
||||
<ReviewSubmitDialog
|
||||
|
||||
@@ -120,7 +120,6 @@ const SewagePipeMaintainRvw = () => {
|
||||
}, [activeStatsStatusInfo.statsCd, lastSearchValues]);
|
||||
|
||||
const latestReviewOpinion = activeStatsStatusInfo.splmntOpnnCn ?? "";
|
||||
const latestProcessHistory = activeStatsStatusInfo.splmntRsltCn ?? "";
|
||||
|
||||
const submitDialogContext = useMemo<ReviewerInfoRequest | null>(() => {
|
||||
if (lastSearchValues == null) return null;
|
||||
@@ -302,7 +301,6 @@ const SewagePipeMaintainRvw = () => {
|
||||
next.set(activeTab, {
|
||||
...(next.get(activeTab) ?? {}),
|
||||
splmntOpnnCn: row?.splmntOpnnCn ?? "",
|
||||
splmntRsltCn: row?.splmntRsltCn ?? "",
|
||||
});
|
||||
return next;
|
||||
});
|
||||
@@ -325,7 +323,6 @@ const SewagePipeMaintainRvw = () => {
|
||||
next.set(activeTab, {
|
||||
...(next.get(activeTab) ?? {}),
|
||||
splmntOpnnCn: param.splmntOpnnCn,
|
||||
splmntRsltCn: param.splmntRsltCn,
|
||||
});
|
||||
return next;
|
||||
});
|
||||
@@ -429,7 +426,6 @@ const SewagePipeMaintainRvw = () => {
|
||||
onOpenChange={setReviewOpinionOpen}
|
||||
context={reviewOpinionContext}
|
||||
initialReviewOpinion={latestReviewOpinion}
|
||||
initialProcessHistory={latestProcessHistory}
|
||||
onSave={saveReviewOpinion}
|
||||
/>
|
||||
<ReviewSubmitDialog
|
||||
|
||||
@@ -181,7 +181,6 @@ const SewagePipeRvw = () => {
|
||||
};
|
||||
}, [activeStatsStatusInfo.statsCd, lastSearchValues]);
|
||||
const latestReviewOpinion = activeStatsStatusInfo.splmntOpnnCn ?? "";
|
||||
const latestProcessHistory = activeStatsStatusInfo.splmntRsltCn ?? "";
|
||||
const submitDialogContext = useMemo<ReviewerInfoRequest | null>(() => {
|
||||
if (lastSearchValues == null) return null;
|
||||
|
||||
@@ -362,7 +361,6 @@ const SewagePipeRvw = () => {
|
||||
next.set(activeTab, {
|
||||
...(next.get(activeTab) ?? {}),
|
||||
splmntOpnnCn: row?.splmntOpnnCn ?? "",
|
||||
splmntRsltCn: row?.splmntRsltCn ?? "",
|
||||
});
|
||||
return next;
|
||||
});
|
||||
@@ -385,7 +383,6 @@ const SewagePipeRvw = () => {
|
||||
next.set(activeTab, {
|
||||
...(next.get(activeTab) ?? {}),
|
||||
splmntOpnnCn: param.splmntOpnnCn,
|
||||
splmntRsltCn: param.splmntRsltCn,
|
||||
});
|
||||
return next;
|
||||
});
|
||||
@@ -488,7 +485,6 @@ const SewagePipeRvw = () => {
|
||||
onOpenChange={setReviewOpinionOpen}
|
||||
context={reviewOpinionContext}
|
||||
initialReviewOpinion={latestReviewOpinion}
|
||||
initialProcessHistory={latestProcessHistory}
|
||||
onSave={saveReviewOpinion}
|
||||
/>
|
||||
<ReviewSubmitDialog
|
||||
|
||||
@@ -126,7 +126,6 @@ const SewageReservoirPumpRvw = () => {
|
||||
}, [activeStatsCd, lastSearchValues]);
|
||||
|
||||
const latestReviewOpinion = activeStatsStatusInfo.splmntOpnnCn ?? "";
|
||||
const latestProcessHistory = activeStatsStatusInfo.splmntRsltCn ?? "";
|
||||
|
||||
const submitDialogContext = useMemo<ReviewerInfoRequest | null>(() => {
|
||||
if (lastSearchValues == null) return null;
|
||||
@@ -308,7 +307,6 @@ const SewageReservoirPumpRvw = () => {
|
||||
next.set(activeTab, {
|
||||
...(next.get(activeTab) ?? {}),
|
||||
splmntOpnnCn: row?.splmntOpnnCn ?? "",
|
||||
splmntRsltCn: row?.splmntRsltCn ?? "",
|
||||
});
|
||||
return next;
|
||||
});
|
||||
@@ -331,7 +329,6 @@ const SewageReservoirPumpRvw = () => {
|
||||
next.set(activeTab, {
|
||||
...(next.get(activeTab) ?? {}),
|
||||
splmntOpnnCn: param.splmntOpnnCn,
|
||||
splmntRsltCn: param.splmntRsltCn,
|
||||
});
|
||||
return next;
|
||||
});
|
||||
@@ -435,7 +432,6 @@ const SewageReservoirPumpRvw = () => {
|
||||
onOpenChange={setReviewOpinionOpen}
|
||||
context={reviewOpinionContext}
|
||||
initialReviewOpinion={latestReviewOpinion}
|
||||
initialProcessHistory={latestProcessHistory}
|
||||
onSave={saveReviewOpinion}
|
||||
/>
|
||||
<ReviewSubmitDialog
|
||||
|
||||
@@ -105,7 +105,6 @@ const SewerageFinanceRvw = () => {
|
||||
}, [activeStatsStatusInfo.statsCd, lastSearchValues]);
|
||||
|
||||
const latestReviewOpinion = activeStatsStatusInfo.splmntOpnnCn ?? "";
|
||||
const latestProcessHistory = activeStatsStatusInfo.splmntRsltCn ?? "";
|
||||
|
||||
const submitDialogContext = useMemo<ReviewerInfoRequest | null>(() => {
|
||||
if (lastSearchValues == null) return null;
|
||||
@@ -287,7 +286,6 @@ const SewerageFinanceRvw = () => {
|
||||
next.set(activeTab, {
|
||||
...(next.get(activeTab) ?? {}),
|
||||
splmntOpnnCn: row?.splmntOpnnCn ?? "",
|
||||
splmntRsltCn: row?.splmntRsltCn ?? "",
|
||||
});
|
||||
return next;
|
||||
});
|
||||
@@ -310,7 +308,6 @@ const SewerageFinanceRvw = () => {
|
||||
next.set(activeTab, {
|
||||
...(next.get(activeTab) ?? {}),
|
||||
splmntOpnnCn: param.splmntOpnnCn,
|
||||
splmntRsltCn: param.splmntRsltCn,
|
||||
});
|
||||
return next;
|
||||
});
|
||||
@@ -414,7 +411,6 @@ const SewerageFinanceRvw = () => {
|
||||
onOpenChange={setReviewOpinionOpen}
|
||||
context={reviewOpinionContext}
|
||||
initialReviewOpinion={latestReviewOpinion}
|
||||
initialProcessHistory={latestProcessHistory}
|
||||
onSave={saveReviewOpinion}
|
||||
/>
|
||||
<ReviewSubmitDialog
|
||||
|
||||
@@ -40,7 +40,6 @@ const SeweragePenetrationRateRvw = () => {
|
||||
const [reviewOpinionContext, setReviewOpinionContext] =
|
||||
useState<ReviewOpinionDialogContext | null>(null);
|
||||
const [latestReviewOpinion, setLatestReviewOpinion] = useState("");
|
||||
const [latestProcessHistory, setLatestProcessHistory] = useState("");
|
||||
const [lastSearchValues, setLastSearchValues] = useState<SearchFormValues | null>(null);
|
||||
|
||||
const columnInfo = useMemo(() => {
|
||||
@@ -100,7 +99,6 @@ const SeweragePenetrationRateRvw = () => {
|
||||
setStatsStatusInfo({});
|
||||
setReviewOpinionContext(null);
|
||||
setLatestReviewOpinion("");
|
||||
setLatestProcessHistory("");
|
||||
setLastSearchValues(null);
|
||||
};
|
||||
|
||||
@@ -139,15 +137,11 @@ const SeweragePenetrationRateRvw = () => {
|
||||
setLatestReviewOpinion(
|
||||
response.data.statsStatusInfo.splmntOpnnCn ?? "",
|
||||
);
|
||||
setLatestProcessHistory(
|
||||
response.data.statsStatusInfo.splmntRsltCn ?? "",
|
||||
);
|
||||
setRowData(toGridRows(convertedData));
|
||||
} else {
|
||||
setRowData([]);
|
||||
setReviewOpinionContext(null);
|
||||
setLatestReviewOpinion("");
|
||||
setLatestProcessHistory("");
|
||||
alert(response.message || "데이터가 없습니다.");
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -187,7 +181,6 @@ const SeweragePenetrationRateRvw = () => {
|
||||
|
||||
const row = detailRes.data?.[0];
|
||||
setLatestReviewOpinion(row?.splmntOpnnCn ?? "");
|
||||
setLatestProcessHistory(row?.splmntRsltCn ?? "");
|
||||
setReviewOpinionOpen(true);
|
||||
} catch {
|
||||
alert("검토의견 조회 중 오류가 발생했습니다.");
|
||||
@@ -205,10 +198,8 @@ const SeweragePenetrationRateRvw = () => {
|
||||
setStatsStatusInfo((prev) => ({
|
||||
...prev,
|
||||
splmntOpnnCn: param.splmntOpnnCn,
|
||||
splmntRsltCn: param.splmntRsltCn,
|
||||
}));
|
||||
setLatestReviewOpinion(param.splmntOpnnCn);
|
||||
setLatestProcessHistory(param.splmntRsltCn);
|
||||
} catch {
|
||||
alert("저장 중 오류가 발생했습니다.");
|
||||
}
|
||||
@@ -264,7 +255,6 @@ const SeweragePenetrationRateRvw = () => {
|
||||
onOpenChange={setReviewOpinionOpen}
|
||||
context={reviewOpinionContext}
|
||||
initialReviewOpinion={latestReviewOpinion}
|
||||
initialProcessHistory={latestProcessHistory}
|
||||
onSave={saveReviewOpinion}
|
||||
/>
|
||||
<ReviewSubmitDialog
|
||||
|
||||
@@ -103,7 +103,6 @@ const SewerageServiceLevelRvw = () => {
|
||||
}, [activeStatsStatusInfo.statsCd, lastSearchValues]);
|
||||
|
||||
const latestReviewOpinion = activeStatsStatusInfo.splmntOpnnCn ?? "";
|
||||
const latestProcessHistory = activeStatsStatusInfo.splmntRsltCn ?? "";
|
||||
|
||||
const submitDialogContext = useMemo<ReviewerInfoRequest | null>(() => {
|
||||
if (lastSearchValues == null) return null;
|
||||
@@ -288,7 +287,6 @@ const SewerageServiceLevelRvw = () => {
|
||||
next.set(activeTab, {
|
||||
...(next.get(activeTab) ?? {}),
|
||||
splmntOpnnCn: row?.splmntOpnnCn ?? "",
|
||||
splmntRsltCn: row?.splmntRsltCn ?? "",
|
||||
});
|
||||
return next;
|
||||
});
|
||||
@@ -311,7 +309,6 @@ const SewerageServiceLevelRvw = () => {
|
||||
next.set(activeTab, {
|
||||
...(next.get(activeTab) ?? {}),
|
||||
splmntOpnnCn: param.splmntOpnnCn,
|
||||
splmntRsltCn: param.splmntRsltCn,
|
||||
});
|
||||
return next;
|
||||
});
|
||||
@@ -415,7 +412,6 @@ const SewerageServiceLevelRvw = () => {
|
||||
onOpenChange={setReviewOpinionOpen}
|
||||
context={reviewOpinionContext}
|
||||
initialReviewOpinion={latestReviewOpinion}
|
||||
initialProcessHistory={latestProcessHistory}
|
||||
onSave={saveReviewOpinion}
|
||||
/>
|
||||
<ReviewSubmitDialog
|
||||
|
||||
@@ -39,22 +39,14 @@ import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||
|
||||
type ReviewHistoryRow = ReviewHistoryResponse["data"][number];
|
||||
|
||||
const checkPrvnStatusCd = (code: string) => {
|
||||
return (code === '0' || code === '1') ? '미작성' : (code === '2' ? '제출완료' : (code === '3' ? '승인완료' : '반려'));
|
||||
};
|
||||
|
||||
const checkSubmitStatusCd = (code: string) => {
|
||||
return code === '0' ? '미작성' : (code === '1' ? '작성중' : (code === '2' ? '제출완료' : (code === '3' ? '승인완료' : '보완요청')));
|
||||
};
|
||||
|
||||
const isStatsInputStatusRowApprovable = (row: Record<string, string | number>) =>
|
||||
String(row.submitStatusCd ?? "") === "3" && (String(row.prvnStatusCd ?? "") === "2" || String(row.prvnStatusCd ?? "") === "3");
|
||||
String(row.lclgvSbmsnSttsCd ?? "") === "3" &&
|
||||
(String(row.mctpvPicSbmsnSttsCd ?? "") === "2" ||
|
||||
String(row.mctpvPicSbmsnSttsCd ?? "") === "3");
|
||||
|
||||
const mapSewerageListToGridRows = (rawList: StatsInputStatusReviewItem[]) =>
|
||||
rawList.map((r) => ({
|
||||
...r,
|
||||
prvnStatusNm: checkPrvnStatusCd(r.prvnStatusCd || "0"),
|
||||
submitStatusNm: checkSubmitStatusCd(r.submitStatusCd || "0"),
|
||||
reviewHistory: "검토이력",
|
||||
}));
|
||||
|
||||
@@ -97,7 +89,7 @@ const StatsInputStatusRvw = () => {
|
||||
const reviewHistoryColumns = useMemo(() => {
|
||||
const col = createColumnHelper<ReviewHistoryRow>();
|
||||
return [
|
||||
col.accessor("logDt", {
|
||||
col.accessor("regDt", {
|
||||
header: "등록일",
|
||||
cell: (info) => info.getValue(),
|
||||
}),
|
||||
@@ -238,23 +230,23 @@ const StatsInputStatusRvw = () => {
|
||||
const allSubmitStatusApproved = useMemo(
|
||||
() =>
|
||||
rowData.length > 0 &&
|
||||
rowData.every((row) => String(row.submitStatusCd ?? "") === "3"),
|
||||
rowData.every((row) => String(row.lclgvSbmsnSttsCd ?? "") === "3"),
|
||||
[rowData],
|
||||
);
|
||||
|
||||
/** 진행상태(prvn) 코드가 모두 승인완료(3) */
|
||||
/** 진행상태(광역) 코드가 모두 승인완료(3) */
|
||||
const allPrvnStatusApproved = useMemo(
|
||||
() =>
|
||||
rowData.length > 0 &&
|
||||
rowData.every((row) => String(row.prvnStatusCd ?? "") === "3"),
|
||||
rowData.every((row) => String(row.mctpvPicSbmsnSttsCd ?? "") === "3"),
|
||||
[rowData],
|
||||
);
|
||||
|
||||
/** 진행상태(prvn) 코드가 모두 제출완료(2) */
|
||||
/** 진행상태(광역) 코드가 모두 제출완료(2) */
|
||||
const allPrvnStatusSubmitted = useMemo(
|
||||
() =>
|
||||
rowData.length > 0 &&
|
||||
rowData.every((row) => String(row.prvnStatusCd ?? "") === "2"),
|
||||
rowData.every((row) => String(row.mctpvPicSbmsnSttsCd ?? "") === "2"),
|
||||
[rowData],
|
||||
);
|
||||
|
||||
@@ -392,8 +384,8 @@ const StatsInputStatusRvw = () => {
|
||||
setRowData={setRowData}
|
||||
onDataCellClick={handleReviewHistoryCellClick}
|
||||
cellStyleCallback={({ row, fieldName }) => {
|
||||
if (fieldName === "submitStatusNm") {
|
||||
const statusCd = String(row.submitStatusCd ?? "");
|
||||
if (fieldName === "lclgvSbmsnSttsNm") {
|
||||
const statusCd = String(row.lclgvSbmsnSttsCd ?? "");
|
||||
|
||||
if (statusCd === "0" || statusCd === "1") {
|
||||
return "rg-cell-stats-status-pending";
|
||||
@@ -408,8 +400,8 @@ const StatsInputStatusRvw = () => {
|
||||
return "rg-cell-stats-status-rejected";
|
||||
}
|
||||
return undefined;
|
||||
} else if (fieldName === "prvnStatusNm") {
|
||||
const statusCd = String(row.prvnStatusCd ?? "");
|
||||
} else if (fieldName === "mctpvPicSbmsnSttsNm") {
|
||||
const statusCd = String(row.mctpvPicSbmsnSttsCd ?? "");
|
||||
|
||||
if (statusCd === "0" || statusCd === "1") {
|
||||
return "rg-cell-stats-status-pending";
|
||||
|
||||
@@ -108,7 +108,6 @@ const WaterReuseRvw = () => {
|
||||
}, [activeStatsStatusInfo.statsCd, lastSearchValues]);
|
||||
|
||||
const latestReviewOpinion = activeStatsStatusInfo.splmntOpnnCn ?? "";
|
||||
const latestProcessHistory = activeStatsStatusInfo.splmntRsltCn ?? "";
|
||||
|
||||
const submitDialogContext = useMemo<ReviewerInfoRequest | null>(() => {
|
||||
if (lastSearchValues == null) return null;
|
||||
@@ -291,7 +290,6 @@ const WaterReuseRvw = () => {
|
||||
next.set(activeTab, {
|
||||
...(next.get(activeTab) ?? {}),
|
||||
splmntOpnnCn: row?.splmntOpnnCn ?? "",
|
||||
splmntRsltCn: row?.splmntRsltCn ?? "",
|
||||
});
|
||||
return next;
|
||||
});
|
||||
@@ -314,7 +312,6 @@ const WaterReuseRvw = () => {
|
||||
next.set(activeTab, {
|
||||
...(next.get(activeTab) ?? {}),
|
||||
splmntOpnnCn: param.splmntOpnnCn,
|
||||
splmntRsltCn: param.splmntRsltCn,
|
||||
});
|
||||
return next;
|
||||
});
|
||||
@@ -418,7 +415,6 @@ const WaterReuseRvw = () => {
|
||||
onOpenChange={setReviewOpinionOpen}
|
||||
context={reviewOpinionContext}
|
||||
initialReviewOpinion={latestReviewOpinion}
|
||||
initialProcessHistory={latestProcessHistory}
|
||||
onSave={saveReviewOpinion}
|
||||
/>
|
||||
<ReviewSubmitDialog
|
||||
|
||||
+7
-4
@@ -554,17 +554,20 @@ const DetailComponent = ({
|
||||
const userInfo = await getUserInfo();
|
||||
let response;
|
||||
|
||||
const vrfcSn = detailInfo?.commonInfo.vrfcSn;
|
||||
if (vrfcSn == null) {
|
||||
alert("검증 일련번호가 없습니다.");
|
||||
return;
|
||||
}
|
||||
if (!hasPersistedDetails) {
|
||||
response =
|
||||
await generalverificationApiService.RegistVrfcDetail({
|
||||
vrfcSn: detailInfo?.commonInfo.vrfcSn ?? null,
|
||||
await generalverificationApiService.RegistVrfcDetail(vrfcSn, {
|
||||
detailList: rows,
|
||||
rgtrUuid: userInfo.userUnqId,
|
||||
});
|
||||
} else {
|
||||
response =
|
||||
await generalverificationApiService.UpdateVrfcDetail({
|
||||
vrfcSn: detailInfo?.commonInfo.vrfcSn ?? null,
|
||||
await generalverificationApiService.UpdateVrfcDetail(vrfcSn, {
|
||||
detailList: rows,
|
||||
mdfrUuid: userInfo.userUnqId,
|
||||
});
|
||||
|
||||
+14
-7
@@ -146,9 +146,15 @@ const RegistDialog = memo(
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpdateVrfcMaster = async (data: GeneralVerificationMasterSubmitFormData) => {
|
||||
const handleUpdateVrfcMaster = async (
|
||||
updateVrfcSn: number,
|
||||
body: UpdateVrfcMasterRequest,
|
||||
) => {
|
||||
try {
|
||||
const response = await generalverificationApiService.UpdateVrfcMaster(data as UpdateVrfcMasterRequest);
|
||||
const response = await generalverificationApiService.UpdateVrfcMaster(
|
||||
updateVrfcSn,
|
||||
body,
|
||||
);
|
||||
|
||||
if (response.status === 'success') {
|
||||
alert('수정되었습니다.');
|
||||
@@ -258,8 +264,11 @@ const RegistDialog = memo(
|
||||
if (await confirm(confirmMessage)) {
|
||||
const userInfo = await getUserInfo();
|
||||
if (isVrfcSn) {
|
||||
const updateData = {
|
||||
vrfcSn: data.vrfcSn,
|
||||
if (data.vrfcSn == null) {
|
||||
alert('수정 대상이 없습니다.');
|
||||
return;
|
||||
}
|
||||
await handleUpdateVrfcMaster(data.vrfcSn, {
|
||||
vrfcNm: data.vrfcNm,
|
||||
vrfcClsfCd: data.vrfcClsfCd,
|
||||
dcptDgt: data.dcptDgt,
|
||||
@@ -267,10 +276,8 @@ const RegistDialog = memo(
|
||||
...(data.dcptDgt === 0
|
||||
? {}
|
||||
: { dcptPrcsMthCd: data.dcptPrcsMthCd }),
|
||||
trgtStatsCd: data.trgtStatsCd,
|
||||
mdfrUuid: userInfo.userUnqId,
|
||||
};
|
||||
await handleUpdateVrfcMaster(updateData);
|
||||
});
|
||||
} else {
|
||||
const registData = {
|
||||
vrfcNm: data.vrfcNm,
|
||||
|
||||
@@ -481,6 +481,11 @@ export type DataGridProps = {
|
||||
headerHeight?: number;
|
||||
/** RealGrid `displayOptions.fitStyle` (기본 EVEN). 컬럼별 width 유지 시 NONE */
|
||||
fitStyle?: GridFitStyle;
|
||||
/**
|
||||
* true면 붙여넣기·편집으로 행을 추가하지 않음.
|
||||
* 검증 결과처럼 조회 행 수가 고정된 그리드에서 사용.
|
||||
*/
|
||||
preventRowAppend?: boolean;
|
||||
};
|
||||
|
||||
export type TabDataGridProps = {
|
||||
|
||||
@@ -8,6 +8,7 @@ export const doList = [
|
||||
"4600000000",
|
||||
"4700000000",
|
||||
"4800000000",
|
||||
"5000000000",
|
||||
];
|
||||
|
||||
export const needBsnmFrgnrPoplSmSidoList = [
|
||||
|
||||
-4
@@ -27,7 +27,6 @@ export const ExcretaSlurgeProcessingStatusInpColumn = {
|
||||
'rcycQnt',
|
||||
'olandLfvlm',
|
||||
'incnrQnt',
|
||||
'oceanInputQnt',
|
||||
'fuelQnt',
|
||||
'etcQnt',
|
||||
'unprcsQnt'
|
||||
@@ -51,7 +50,6 @@ export const ExcretaSlurgeProcessingStatusInpColumn = {
|
||||
'rcycQnt',
|
||||
'olandLfvlm',
|
||||
'incnrQnt',
|
||||
'oceanInputQnt',
|
||||
'fuelQnt',
|
||||
'etcQnt',
|
||||
],
|
||||
@@ -61,7 +59,6 @@ export const ExcretaSlurgeProcessingStatusInpColumn = {
|
||||
{ name: 'rcycQnt', fieldName: 'rcycQnt', header: { text: '재활용' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'olandLfvlm', fieldName: 'olandLfvlm', header: { text: '육상매립' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'incnrQnt', fieldName: 'incnrQnt', header: { text: '소각' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'oceanInputQnt', fieldName: 'oceanInputQnt', header: { text: '해양투기' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'fuelQnt', fieldName: 'fuelQnt', header: { text: '연료화' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'etcQnt', fieldName: 'etcQnt', header: { text: '기타' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
|
||||
@@ -100,7 +97,6 @@ export const ExcretaSlurgeProcessingStatusInpColumn = {
|
||||
'rcycQnt',
|
||||
'olandLfvlm',
|
||||
'incnrQnt',
|
||||
'oceanInputQnt',
|
||||
'fuelQnt',
|
||||
'etcQnt'
|
||||
]
|
||||
|
||||
@@ -49,6 +49,43 @@ export const ManholeStatusInpColumn = {
|
||||
styleName: "rg-cell-readonly",
|
||||
footer: { text: "합계" },
|
||||
},
|
||||
{
|
||||
name: "wholMnhlCntSum",
|
||||
fieldName: "wholMnhlCntSum",
|
||||
header: { text: "맨홀총계" },
|
||||
footer: footerInt,
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: "#,##0",
|
||||
styleName: "rg-cell-readonly",
|
||||
},
|
||||
{
|
||||
name: "frlvlMnhlCntSum",
|
||||
fieldName: "frlvlMnhlCntSum",
|
||||
header: { text: "주철계" },
|
||||
footer: footerInt,
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: "#,##0",
|
||||
styleName: "rg-cell-readonly",
|
||||
},
|
||||
{
|
||||
name: "thlvlMnhlCntSum",
|
||||
fieldName: "thlvlMnhlCntSum",
|
||||
header: { text: "콘크리트계" },
|
||||
footer: footerInt,
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: "#,##0",
|
||||
styleName: "rg-cell-readonly",
|
||||
},
|
||||
{
|
||||
name: "picNm",
|
||||
fieldName: "picNm",
|
||||
header: { text: "담당자명" },
|
||||
editable: false,
|
||||
styleName: "rg-cell-readonly",
|
||||
},
|
||||
{
|
||||
...intCol("wholMnhlCnt", "계", false),
|
||||
computed: {
|
||||
@@ -88,6 +125,12 @@ export const ManholeStatusInpColumn = {
|
||||
},
|
||||
"admdstNm",
|
||||
"emphsMngSeNm",
|
||||
{
|
||||
name: "adminRefGroup",
|
||||
hideChildHeaders: false,
|
||||
header: { text: "행정참고자료" },
|
||||
items: ["wholMnhlCntSum", "frlvlMnhlCntSum", "thlvlMnhlCntSum", "picNm"],
|
||||
},
|
||||
{
|
||||
name: "mtrlGroup",
|
||||
hideChildHeaders: false,
|
||||
|
||||
+2
@@ -75,6 +75,8 @@ export const PublicSewageTreatWaterReuseInpColumn = {
|
||||
name: 'lglYn',
|
||||
fieldName: 'lglYn',
|
||||
header: { text: '법적의무대상(대상/미대상)' },
|
||||
editable: false,
|
||||
styleName: 'rg-cell-readonly'
|
||||
},
|
||||
PUBLIC_SEWAGE_TREAT_WATER_REUSE_LGL_YN_VALUES,
|
||||
),
|
||||
|
||||
@@ -32,11 +32,11 @@ export const getGeneralVerificationColumns = (
|
||||
},
|
||||
{
|
||||
accessorKey: "vrfcClsfNm",
|
||||
header: "검증분류",
|
||||
header: "검증 분류",
|
||||
},
|
||||
{
|
||||
accessorKey: "useYn",
|
||||
header: "사용여부",
|
||||
header: "사용 여부",
|
||||
},
|
||||
{
|
||||
accessorKey: "regDt",
|
||||
|
||||
@@ -346,7 +346,6 @@ const rawSludgeList = [
|
||||
decimal1Col("rcycQnt", "재활용"),
|
||||
decimal1Col("olandLfvlm", "육상매립"),
|
||||
decimal1Col("incnrQnt", "소각"),
|
||||
decimal1Col("oceanInputQnt", "해양투기"),
|
||||
decimal1Col("fuelQnt", "연료화"),
|
||||
decimal1Col("etcQnt", "기타"),
|
||||
decimal1Col("unprcsQnt", "미처분량\n(이월량)(C)"),
|
||||
@@ -366,7 +365,6 @@ const rawSludgeList = [
|
||||
"rcycQnt",
|
||||
"olandLfvlm",
|
||||
"incnrQnt",
|
||||
"oceanInputQnt",
|
||||
"fuelQnt",
|
||||
"etcQnt",
|
||||
],
|
||||
|
||||
@@ -491,6 +491,10 @@ const rawList = [
|
||||
{ name: 'sggNm', fieldName: 'sggNm', header: { text: '시군구' }, mergeCells: true, sortdisable: true },
|
||||
{ name: 'admdstNm', fieldName: 'admdstNm', header: { text: '행정구역명' }, mergeCells: true, sortdisable: true },
|
||||
{ name: 'emphsMngSeNm', fieldName: 'emphsMngSeNm', header: { text: '집중강우\n중점관리\n구역구분' }, mergeCells: true },
|
||||
{ name: 'wholMnhlCntSum', fieldName: 'wholMnhlCntSum', header: { text: '맨홀총계' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'frlvlMnhlCntSum', fieldName: 'frlvlMnhlCntSum', header: { text: '주철계' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'thlvlMnhlCntSum', fieldName: 'thlvlMnhlCntSum', header: { text: '콘크리트계' }, footer: footerIntArrayByDivision, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'picNm', fieldName: 'picNm', header: { text: '담당자명' } },
|
||||
{
|
||||
name: 'displayYear',
|
||||
fieldName: 'displayYear',
|
||||
@@ -544,6 +548,12 @@ const rawList = [
|
||||
],
|
||||
},
|
||||
'emphsMngSeNm',
|
||||
{
|
||||
name: 'adminRefGroup',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '행정참고자료' },
|
||||
items: ['wholMnhlCntSum', 'frlvlMnhlCntSum', 'thlvlMnhlCntSum', 'picNm'],
|
||||
},
|
||||
'displayYear',
|
||||
{
|
||||
name: 'mtrlGroup',
|
||||
|
||||
@@ -17,12 +17,12 @@ const StatsInputStatusInfoColumnRaw = {
|
||||
styleName: 'rg-cell-outline-action-btn',
|
||||
},
|
||||
|
||||
{ name: 'chargerNm', fieldName: 'chargerNm', header: { text: '제출자' } },
|
||||
{ name: 'chargerCttpc', fieldName: 'chargerCttpc', header: { text: '연락처' } },
|
||||
{ name: 'submitStatusNm', fieldName: 'submitStatusNm', header: { text: '지자체진행상태' } },
|
||||
{ name: 'submitStatusCd', fieldName: 'submitStatusCd', header: { text: '지자체진행상태코드' }, visible: false },
|
||||
{ name: 'prvnStatusNm', fieldName: 'prvnStatusNm', header: { text: '진행상태' } },
|
||||
{ name: 'prvnStatusCd', fieldName: 'prvnStatusCd', header: { text: '진행상태코드' }, visible: false },
|
||||
{ name: 'lclgvPicNm', fieldName: 'lclgvPicNm', header: { text: '제출자' } },
|
||||
{ name: 'lclgvPicTelnoCn', fieldName: 'lclgvPicTelnoCn', header: { text: '연락처' } },
|
||||
{ name: 'lclgvSbmsnSttsNm', fieldName: 'lclgvSbmsnSttsNm', header: { text: '지자체진행상태' } },
|
||||
{ name: 'lclgvSbmsnSttsCd', fieldName: 'lclgvSbmsnSttsCd', header: { text: '지자체진행상태코드' }, visible: false },
|
||||
{ name: 'mctpvPicSbmsnSttsNm', fieldName: 'mctpvPicSbmsnSttsNm', header: { text: '진행상태' } },
|
||||
{ name: 'mctpvPicSbmsnSttsCd', fieldName: 'mctpvPicSbmsnSttsCd', header: { text: '진행상태코드' }, visible: false },
|
||||
],
|
||||
|
||||
columnLayout: [
|
||||
@@ -30,14 +30,14 @@ const StatsInputStatusInfoColumnRaw = {
|
||||
'sggNm',
|
||||
'tabNm',
|
||||
'reviewHistory',
|
||||
'chargerNm',
|
||||
'chargerCttpc',
|
||||
'submitStatusNm',
|
||||
'prvnStatusNm',
|
||||
'lclgvPicNm',
|
||||
'lclgvPicTelnoCn',
|
||||
'lclgvSbmsnSttsNm',
|
||||
'mctpvPicSbmsnSttsNm',
|
||||
'statsCd',
|
||||
'sewerBzmnCd',
|
||||
'submitStatusCd',
|
||||
'prvnStatusCd'
|
||||
'lclgvSbmsnSttsCd',
|
||||
'mctpvPicSbmsnSttsCd',
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
@@ -710,6 +710,10 @@ const rawSewagePipeTotList = [
|
||||
{ name: "sggNm", fieldName: "sggNm", header: { text: "시군구" }, editable: false },
|
||||
{ name: "admdstNm", fieldName: "admdstNm", header: { text: "행정구역명" }, editable: false },
|
||||
{ name: "emphsMngSeNm", fieldName: "emphsMngSeNm", header: { text: "집중강우\n중점관리\n구역구분" }, editable: false },
|
||||
{ name: "wholMnhlCntSum", fieldName: "wholMnhlCntSum", header: { text: "맨홀총계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "frlvlMnhlCntSum", fieldName: "frlvlMnhlCntSum", header: { text: "주철계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "thlvlMnhlCntSum", fieldName: "thlvlMnhlCntSum", header: { text: "콘크리트계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "picNm", fieldName: "picNm", header: { text: "담당자명" }, editable: false },
|
||||
{ name: "wholMnhlCnt", fieldName: "wholMnhlCnt", header: { text: "계" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "frlvlMnhlCnt", fieldName: "frlvlMnhlCnt", header: { text: "주철" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
{ name: "sclvlMnhlCnt", fieldName: "sclvlMnhlCnt", header: { text: "주철(조화)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0", editable: false },
|
||||
@@ -720,6 +724,11 @@ const rawSewagePipeTotList = [
|
||||
columnLayout: [
|
||||
{ name: "addrGroup", header: { text: "행정구역" }, items: ["ctpvNm", "sggNm", "admdstNm"] },
|
||||
"emphsMngSeNm",
|
||||
{
|
||||
name: "adminRefGroup",
|
||||
header: { text: "행정참고자료" },
|
||||
items: ["wholMnhlCntSum", "frlvlMnhlCntSum", "thlvlMnhlCntSum", "picNm"],
|
||||
},
|
||||
{
|
||||
name: "mtrlGroup",
|
||||
header: { text: "맨홀뚜껑 재질(개)" },
|
||||
|
||||
+1
-2
@@ -16,7 +16,6 @@ export const HumanWasteSludgeTab4ColumnConfig = {
|
||||
{ name: "rcycQnt", fieldName: "rcycQnt", header: { text: "재활용" }, valueType: ValueType.NUMBER, dataFormat: "#,##0.0", editable: false },
|
||||
{ name: "olandLfvlm", fieldName: "olandLfvlm", header: { text: "육상매립" }, valueType: ValueType.NUMBER, dataFormat: "#,##0.0", editable: false },
|
||||
{ name: "incnrQnt", fieldName: "incnrQnt", header: { text: "소각" }, valueType: ValueType.NUMBER, dataFormat: "#,##0.0", editable: false },
|
||||
{ name: "oceanInputQnt", fieldName: "oceanInputQnt", header: { text: "해양투기" }, valueType: ValueType.NUMBER, dataFormat: "#,##0.0", editable: false },
|
||||
{ name: "fuelQnt", fieldName: "fuelQnt", header: { text: "연료화" }, valueType: ValueType.NUMBER, dataFormat: "#,##0.0", editable: false },
|
||||
{ name: "etcQnt", fieldName: "etcQnt", header: { text: "기타" }, valueType: ValueType.NUMBER, dataFormat: "#,##0.0", editable: false },
|
||||
{ name: "unprcsQnt", fieldName: "unprcsQnt", header: { text: "미처분량\n(이월량)(C)" }, valueType: ValueType.NUMBER, dataFormat: "#,##0.0", editable: false },
|
||||
@@ -29,7 +28,7 @@ export const HumanWasteSludgeTab4ColumnConfig = {
|
||||
{
|
||||
name: "dspsGroup",
|
||||
header: { text: "처분량" },
|
||||
items: ["wholDspsQnt", "rcycQnt", "olandLfvlm", "incnrQnt", "oceanInputQnt", "fuelQnt", "etcQnt"]
|
||||
items: ["wholDspsQnt", "rcycQnt", "olandLfvlm", "incnrQnt", "fuelQnt", "etcQnt"]
|
||||
},
|
||||
"unprcsQnt",
|
||||
"swtrmtFcltNm"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { GridView } from "realgrid";
|
||||
import { type GridView, ValueType } from "realgrid";
|
||||
|
||||
import type {
|
||||
ColumnConfig,
|
||||
@@ -124,6 +124,82 @@ export function getNonEditableColumnFieldNames(
|
||||
return fieldNames;
|
||||
}
|
||||
|
||||
type ExcelImportCell = {
|
||||
t?: string;
|
||||
v?: unknown;
|
||||
w?: string;
|
||||
};
|
||||
|
||||
/** 엑셀 셀 → 그리드 값. NUMBER 컬럼만 숫자화하고, 코드(01)는 문자열로 유지 */
|
||||
export function parseExcelImportCellValue(
|
||||
cell: ExcelImportCell | undefined,
|
||||
valueType?: ColumnConfig["valueType"],
|
||||
): string | number {
|
||||
if (!cell || cell.v === undefined || cell.v === null || cell.v === "") {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (valueType === ValueType.NUMBER) {
|
||||
if (typeof cell.v === "number" && !Number.isNaN(cell.v)) {
|
||||
return cell.v;
|
||||
}
|
||||
const stringValue = String(cell.v);
|
||||
const numericValue = Number(stringValue.replace(/,/g, ""));
|
||||
if (!Number.isNaN(numericValue) && stringValue.trim() !== "") {
|
||||
return numericValue;
|
||||
}
|
||||
return stringValue;
|
||||
}
|
||||
|
||||
const formatted = typeof cell.w === "string" ? cell.w.trim() : "";
|
||||
if (/^0\d+$/.test(formatted)) {
|
||||
return formatted;
|
||||
}
|
||||
return String(cell.v);
|
||||
}
|
||||
|
||||
function collectZeroPaddedCodeWidths(
|
||||
rows: Record<string, string | number>[],
|
||||
): Map<string, number> {
|
||||
const widthByField = new Map<string, number>();
|
||||
for (const row of rows) {
|
||||
for (const [field, value] of Object.entries(row)) {
|
||||
const s = String(value ?? "").trim();
|
||||
if (!/^0\d+$/.test(s)) continue;
|
||||
widthByField.set(field, Math.max(widthByField.get(field) ?? 0, s.length));
|
||||
}
|
||||
}
|
||||
return widthByField;
|
||||
}
|
||||
|
||||
function restoreImportedCodeLeadingZeros(
|
||||
importedRow: Record<string, string | number>,
|
||||
existingRow: Record<string, string | number> | undefined,
|
||||
codeWidthByField: Map<string, number>,
|
||||
): Record<string, string | number> {
|
||||
const next: Record<string, string | number> = { ...importedRow };
|
||||
for (const [field, value] of Object.entries(next)) {
|
||||
if (value === "" || value == null) continue;
|
||||
if (typeof value === "number" && !Number.isInteger(value)) continue;
|
||||
const importedStr = String(value).trim();
|
||||
if (!/^\d+$/.test(importedStr)) continue;
|
||||
|
||||
const existingStr =
|
||||
existingRow != null ? String(existingRow[field] ?? "").trim() : "";
|
||||
let width = codeWidthByField.get(field);
|
||||
if (!width && /^0\d+$/.test(existingStr)) {
|
||||
width = existingStr.length;
|
||||
}
|
||||
if (!width && field.endsWith("Cd") && importedStr.length <= 2) {
|
||||
width = 2;
|
||||
}
|
||||
if (width && importedStr.length < width) {
|
||||
next[field] = importedStr.padStart(width, "0");
|
||||
}
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
/** 엑셀 import 결과를 기존 행과 병합 — preserveFieldNames는 기존 그리드 값 유지 */
|
||||
export function mergeExcelImportWithExistingRows(
|
||||
existingRows: Record<string, string | number>[],
|
||||
@@ -134,14 +210,20 @@ export function mergeExcelImportWithExistingRows(
|
||||
options?.preserveFieldNames && options.preserveFieldNames.length > 0
|
||||
? new Set(options.preserveFieldNames)
|
||||
: null;
|
||||
const codeWidthByField = collectZeroPaddedCodeWidths(existingRows);
|
||||
|
||||
return importedRows.map((importedRow, index) => {
|
||||
const existingRow = existingRows[index];
|
||||
if (!existingRow) return { ...importedRow };
|
||||
const normalizedImported = restoreImportedCodeLeadingZeros(
|
||||
importedRow,
|
||||
existingRow,
|
||||
codeWidthByField,
|
||||
);
|
||||
if (!existingRow) return normalizedImported;
|
||||
|
||||
const merged: Record<string, string | number> = {
|
||||
...existingRow,
|
||||
...importedRow,
|
||||
...normalizedImported,
|
||||
};
|
||||
if (preserveSet) {
|
||||
for (const fieldName of preserveSet) {
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { statisticsApi } from "@/entities/statistics/api/statistics-service";
|
||||
import type {
|
||||
ImrRequest,
|
||||
ImrResponse,
|
||||
rollbackStatusRequest,
|
||||
} from "@/entities/statistics/model/statistics-interface";
|
||||
|
||||
/** 제출 직후 IMR 요청이 실패하면 검증 이전 상태로 롤백 */
|
||||
export async function callImrServiceWithRollbackOnFailure(
|
||||
imrParam: ImrRequest,
|
||||
rollbackParam: rollbackStatusRequest,
|
||||
): Promise<ImrResponse> {
|
||||
try {
|
||||
return await statisticsApi.callImrService(imrParam);
|
||||
} catch (error) {
|
||||
try {
|
||||
await statisticsApi.rollbackStatus(rollbackParam);
|
||||
} catch {
|
||||
// 롤백 실패는 IMR 실패를 가리지 않음
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
import type { StatisticsInputCommonInfoBase } from "@/entities/statistics/model/statistics-interface";
|
||||
|
||||
import type { VerificationResultLikeMap } from "./verification-result-display";
|
||||
import {
|
||||
normalizeVerificationResultMap,
|
||||
type VerificationResultLikeMap,
|
||||
} from "./verification-result-display";
|
||||
|
||||
export function isVerificationFailedFromCommonInfo(
|
||||
commonInfo: Pick<StatisticsInputCommonInfoBase, "isVerificationFailed"> | null | undefined,
|
||||
@@ -28,6 +31,9 @@ export function patchFooterVerificationByTab(
|
||||
| undefined,
|
||||
): Map<string, VerificationResultLikeMap | null> {
|
||||
const next = new Map(prev);
|
||||
next.set(tabKey, commonInfo?.verificationResult ?? null);
|
||||
next.set(
|
||||
tabKey,
|
||||
normalizeVerificationResultMap(commonInfo?.verificationResult) ?? null,
|
||||
);
|
||||
return next;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,49 @@ export type VerificationResultLikeMap = Record<
|
||||
VerificationResultLikeItem[]
|
||||
>;
|
||||
|
||||
/** 입력 조회 verificationResult의 기준값/입력값이 null이면 "-" */
|
||||
export function displayVerificationCn(
|
||||
value: string | null | undefined,
|
||||
): string {
|
||||
if (value == null || String(value).trim() === "") return "-";
|
||||
return String(value);
|
||||
}
|
||||
|
||||
export function normalizeVerificationResultItem<T extends VerificationResultLikeItem>(
|
||||
item: T,
|
||||
): T {
|
||||
return {
|
||||
...item,
|
||||
nowCn: displayVerificationCn(item.nowCn ?? item.nowVlCn),
|
||||
cmprCn: displayVerificationCn(item.cmprCn ?? item.compVlCn),
|
||||
};
|
||||
}
|
||||
|
||||
export function normalizeVerificationResultMap<T extends VerificationResultLikeMap>(
|
||||
result: T | null | undefined,
|
||||
): T | undefined {
|
||||
if (!result || typeof result !== "object") return undefined;
|
||||
const next = {} as T;
|
||||
for (const [key, items] of Object.entries(result)) {
|
||||
(next as VerificationResultLikeMap)[key] = Array.isArray(items)
|
||||
? items.map((item) => normalizeVerificationResultItem(item))
|
||||
: [];
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
/** 조회 행/객체에 붙은 verificationResult의 cmprCn·nowCn null을 "-"로 바꿈 */
|
||||
export function withNormalizedVerificationResult<T extends object>(item: T): T {
|
||||
if (!("verificationResult" in item) || item.verificationResult == null) {
|
||||
return item;
|
||||
}
|
||||
const verificationResult = normalizeVerificationResultMap(
|
||||
item.verificationResult as VerificationResultLikeMap,
|
||||
);
|
||||
if (!verificationResult) return item;
|
||||
return { ...item, verificationResult };
|
||||
}
|
||||
|
||||
/** 검증 오류 배열 → RealGrid styleName */
|
||||
export function getVerificationStyleName(
|
||||
errors: VerificationResultLikeItem[] | null | undefined,
|
||||
@@ -37,8 +80,8 @@ export function formatVerificationTooltip(
|
||||
: e.vrfcCd === "NV"
|
||||
? "일반검증 - "
|
||||
: "모집단 검증 - ";
|
||||
const comp = e.cmprCn ?? e.compVlCn ?? "";
|
||||
const now = e.nowCn ?? e.nowVlCn ?? "";
|
||||
const comp = displayVerificationCn(e.cmprCn ?? e.compVlCn);
|
||||
const now = displayVerificationCn(e.nowCn ?? e.nowVlCn);
|
||||
return `${prefix}${e.rsnExpln}\n(검증 기준값: ${comp} / 현재 입력값: ${now})`;
|
||||
})
|
||||
.filter(Boolean)
|
||||
|
||||
@@ -56,10 +56,11 @@ export class GeneralverificationApiService implements GeneralverificationService
|
||||
}
|
||||
|
||||
public async UpdateVrfcMaster(
|
||||
vrfcSn: number,
|
||||
param: UpdateVrfcMasterRequest,
|
||||
): Promise<UpdateVrfcMasterResponse> {
|
||||
const response = await stClient.put<UpdateVrfcMasterResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUTVERIFY}/masters/${param.vrfcSn}`,
|
||||
`${ENDPOINT.ST_SERVICE.INPUTVERIFY}/masters/${vrfcSn}`,
|
||||
param,
|
||||
);
|
||||
return response.data;
|
||||
@@ -127,20 +128,22 @@ export class GeneralverificationApiService implements GeneralverificationService
|
||||
}
|
||||
|
||||
public async RegistVrfcDetail(
|
||||
vrfcSn: number,
|
||||
param: VerifyDetailRegistRequest,
|
||||
): Promise<RegistVrfcMasterResponse> {
|
||||
const response = await stClient.post<RegistVrfcMasterResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUTVERIFY}/${param.vrfcSn}/details`,
|
||||
`${ENDPOINT.ST_SERVICE.INPUTVERIFY}/${vrfcSn}/details`,
|
||||
param,
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async UpdateVrfcDetail(
|
||||
vrfcSn: number,
|
||||
param: VerifyDetailUpdateRequest,
|
||||
): Promise<RegistVrfcMasterResponse> {
|
||||
const response = await stClient.put<RegistVrfcMasterResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUTVERIFY}/${param.vrfcSn}/details`,
|
||||
`${ENDPOINT.ST_SERVICE.INPUTVERIFY}/${vrfcSn}/details`,
|
||||
param,
|
||||
);
|
||||
return response.data;
|
||||
|
||||
@@ -16,6 +16,8 @@ import {
|
||||
type ImrStatusResponse,
|
||||
type ReviewerInfoRequest,
|
||||
type ReviewerInfoResponse,
|
||||
type rollbackStatusRequest,
|
||||
type rollbackStatusResponse,
|
||||
type ReviewInputSaveRequest,
|
||||
type ReviewOpinionSaveRequest,
|
||||
type ReviewOpinionSaveResponse,
|
||||
@@ -156,6 +158,17 @@ export class StatisticsApiService implements StatisticsService {
|
||||
return response.data;
|
||||
}
|
||||
|
||||
// 입력 - 검증 이전 상태로 롤백
|
||||
public async rollbackStatus(
|
||||
param: rollbackStatusRequest,
|
||||
): Promise<rollbackStatusResponse> {
|
||||
const response = await stClient.put<rollbackStatusResponse>(
|
||||
`${ENDPOINT.ST_SERVICE.INPUTCOMMON}/rollback-status`,
|
||||
param,
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async callImrService(param: ImrRequest): Promise<ImrResponse> {
|
||||
const response = await client.post<ImrResponse>(
|
||||
`${ENDPOINT.STATVERIFY_SERVICE.IMR}`,
|
||||
|
||||
@@ -46,7 +46,6 @@ export interface CheckVerificationNameResponse {
|
||||
}
|
||||
|
||||
export interface UpdateVrfcMasterRequest {
|
||||
vrfcSn?: number | null;
|
||||
vrfcNm?: string | null;
|
||||
vrfcClsfCd?: string | null;
|
||||
dcptDgt?: number | null;
|
||||
@@ -184,13 +183,11 @@ export interface VerifyDetailRegistData {
|
||||
}
|
||||
|
||||
export interface VerifyDetailRegistRequest {
|
||||
vrfcSn: number | null;
|
||||
detailList: VerifyDetailRegistData[];
|
||||
rgtrUuid: string;
|
||||
}
|
||||
|
||||
export interface VerifyDetailUpdateRequest {
|
||||
vrfcSn: number | null;
|
||||
detailList: VerifyDetailRegistData[];
|
||||
mdfrUuid: string;
|
||||
}
|
||||
@@ -297,6 +294,7 @@ export interface GeneralverificationService {
|
||||
param: CheckVerificationNameRequest,
|
||||
): Promise<CheckVerificationNameResponse>;
|
||||
UpdateVrfcMaster(
|
||||
vrfcSn: number,
|
||||
param: UpdateVrfcMasterRequest,
|
||||
): Promise<UpdateVrfcMasterResponse>;
|
||||
RegistVrfcMaster(
|
||||
@@ -315,9 +313,11 @@ export interface GeneralverificationService {
|
||||
param: string,
|
||||
): Promise<VerifyColumnListResponse>;
|
||||
RegistVrfcDetail(
|
||||
vrfcSn: number,
|
||||
param: VerifyDetailRegistRequest,
|
||||
): Promise<RegistVrfcMasterResponse>;
|
||||
UpdateVrfcDetail(
|
||||
vrfcSn: number,
|
||||
param: VerifyDetailUpdateRequest,
|
||||
): Promise<RegistVrfcMasterResponse>;
|
||||
CopyVrfcData(
|
||||
|
||||
-1
@@ -437,7 +437,6 @@ export interface ExcretaSlurgeProcessingStatusItem {
|
||||
rcycQnt: number;
|
||||
olandLfvlm: number;
|
||||
incnrQnt: number;
|
||||
oceanInputQnt: number;
|
||||
fuelQnt: number;
|
||||
etcQnt: number;
|
||||
unprcsQnt: number;
|
||||
|
||||
@@ -81,7 +81,6 @@ export interface ReportStatusResponseDto {
|
||||
lastCfmtnPicTelnoCn?: string | null;
|
||||
lastCfmtnPicDeptNm?: string | null;
|
||||
lastCfmtnPicJbgdNm?: string | null;
|
||||
splmntRsltCn?: string | null;
|
||||
splmntOpnnCn?: string | null;
|
||||
rjctOpnnCn?: string | null;
|
||||
}
|
||||
|
||||
+4
-1
@@ -308,7 +308,6 @@ export interface SeweragePipeInputPipeTypeStatusSaveItem {
|
||||
rmrk: string | null;
|
||||
lyngPrlgWhol: number;
|
||||
dmltnPrlgWhol: number;
|
||||
pipeByPrstWhol: number;
|
||||
}
|
||||
|
||||
/** 관종별 현황 저장 API 요청 */
|
||||
@@ -420,6 +419,10 @@ export interface SeweragePipeInputManholeStatusItem {
|
||||
folvlMnhlCnt: number;
|
||||
filvlMnhlCnt: number;
|
||||
rmrk: string;
|
||||
wholMnhlCntSum: number;
|
||||
frlvlMnhlCntSum: number;
|
||||
thlvlMnhlCntSum: number;
|
||||
picNm: string | null;
|
||||
verificationResult?: SeweragePipeInputVerificationResult;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,12 +9,12 @@ export interface StatsInputStatusReviewItem {
|
||||
sewerBzmnCd?: string;
|
||||
tabNm?: string;
|
||||
statsCd?: string;
|
||||
submitStatusNm?: string;
|
||||
prvnStatusNm?: string;
|
||||
chargerNm?: string;
|
||||
chargerCttpc?: string;
|
||||
submitStatusCd?: string;
|
||||
prvnStatusCd?: string;
|
||||
lclgvPicNm?: string;
|
||||
lclgvPicTelnoCn?: string;
|
||||
lclgvSbmsnSttsCd?: string;
|
||||
lclgvSbmsnSttsNm?: string;
|
||||
mctpvPicSbmsnSttsCd?: string;
|
||||
mctpvPicSbmsnSttsNm?: string;
|
||||
}
|
||||
|
||||
export interface StatsInputStatusReviewResponseData {
|
||||
@@ -37,7 +37,7 @@ export interface ReviewHistoryResponse {
|
||||
status: string;
|
||||
message?: string;
|
||||
data: {
|
||||
logDt: string;
|
||||
regDt: string;
|
||||
historyContent: string;
|
||||
}[]
|
||||
}
|
||||
|
||||
@@ -31,6 +31,21 @@ export interface cancelSubmitResponse {
|
||||
message?: string;
|
||||
}
|
||||
|
||||
/** 검증 이전 상태로 롤백 요청 */
|
||||
export interface rollbackStatusRequest {
|
||||
statsYr: string;
|
||||
statsCd: string;
|
||||
sewerBzmnCd: string;
|
||||
rollbackStatusCode: string;
|
||||
mdfrUuid: string;
|
||||
}
|
||||
|
||||
/** 검증 이전 상태로 롤백 응답 */
|
||||
export interface rollbackStatusResponse {
|
||||
status: string;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export interface ApiResponse<T> {
|
||||
status: string;
|
||||
data?: T;
|
||||
@@ -327,7 +342,6 @@ export interface ReviewOpinionDetailItem {
|
||||
sewerBzmnCd: string;
|
||||
statsCd: string;
|
||||
splmntOpnnCn: string | null;
|
||||
splmntRsltCn: string | null;
|
||||
mdfrUuid: string | null;
|
||||
}
|
||||
|
||||
@@ -343,7 +357,6 @@ export interface ReviewOpinionSaveRequest {
|
||||
sewerBzmnCd: string;
|
||||
statsCd: string;
|
||||
splmntOpnnCn: string;
|
||||
splmntRsltCn: string;
|
||||
mdfrUuid: string;
|
||||
}
|
||||
|
||||
@@ -388,7 +401,6 @@ export interface ReviewSubmitRequest {
|
||||
/** 통계항목 단위 제출 시 사용 (통계 입력 현황 일괄 제출에는 미사용) */
|
||||
statsCd?: string;
|
||||
splmntOpnnCn?: string;
|
||||
splmntRsltCn?: string;
|
||||
}
|
||||
|
||||
export interface ReviewSubmitResponse {
|
||||
@@ -454,7 +466,6 @@ export interface ReviewerInfoResponse {
|
||||
dpmNm: string;
|
||||
cps: string;
|
||||
splmntOpnnCn: string;
|
||||
splmntRsltCn: string;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,9 +489,8 @@ export interface StatiscicsManagementReviewHistoryItem {
|
||||
ctpvNm: string;
|
||||
sggNm: string;
|
||||
menuNm: string;
|
||||
wrterOpinionSm: string | null;
|
||||
chckerOpinionSm: string | null;
|
||||
returnOpinionSm: string | null;
|
||||
splmntOpnnCn: string | null;
|
||||
rjctOpnnCn: string | null;
|
||||
}
|
||||
|
||||
export interface StatiscicsManagementReviewHistoryResponse {
|
||||
@@ -557,6 +567,7 @@ export interface StatisticsService {
|
||||
saveStatsInputPeriod(param: StatsInputPeriodSaveRequest): Promise<StatsInputPeriodSaveApiResponse>;
|
||||
deleteStatsInputPeriod(param: StatsInputPeriodDeleteRequest): Promise<StatsInputPeriodDeleteApiResponse>;
|
||||
cancelSubmit(param: cancelSubmitRequest): Promise<cancelSubmitResponse>;
|
||||
rollbackStatus(param: rollbackStatusRequest): Promise<rollbackStatusResponse>;
|
||||
callImrService(param: ImrRequest): Promise<ImrResponse>;
|
||||
submitException(param: SubmitExceptionRequest): Promise<SubmitExceptionResponse>;
|
||||
getLogList(param: StatisticsLogRequest): Promise<StatisticsLogResponse>;
|
||||
|
||||
-2
@@ -127,7 +127,6 @@ export interface HumanWasteSludgeReviewItem {
|
||||
rcycQnt: number | null;
|
||||
olandLfvlm: number | null;
|
||||
incnrQnt: number | null;
|
||||
oceanInputQnt: number | null;
|
||||
fuelQnt: number | null;
|
||||
etcQnt: number | null;
|
||||
unprcsQnt: number | null;
|
||||
@@ -218,7 +217,6 @@ export function mapSewageExcretaSlurgeReviewRows(list: unknown[]): object[] {
|
||||
rcycQnt: row.rcycQnt ?? 0,
|
||||
olandLfvlm: row.olandLfvlm ?? 0,
|
||||
incnrQnt: row.incnrQnt ?? 0,
|
||||
oceanInputQnt: row.oceanInputQnt ?? 0,
|
||||
fuelQnt: row.fuelQnt ?? 0,
|
||||
etcQnt: row.etcQnt ?? 0,
|
||||
unprcsQnt: row.unprcsQnt ?? 0,
|
||||
|
||||
@@ -108,5 +108,4 @@ export interface StatsStatusInfo {
|
||||
mctpvPicSbmsnSttsCd?: string;
|
||||
rjctOpnnCn?: string;
|
||||
splmntOpnnCn?: string;
|
||||
splmntRsltCn?: string;
|
||||
}
|
||||
@@ -247,6 +247,10 @@ export interface SewagePipeReviewManholeItem {
|
||||
folvlMnhlCnt: number;
|
||||
filvlMnhlCnt: number;
|
||||
rmrk: string | null;
|
||||
wholMnhlCntSum: number;
|
||||
frlvlMnhlCntSum: number;
|
||||
thlvlMnhlCntSum: number;
|
||||
picNm: string | null;
|
||||
}
|
||||
|
||||
export interface SewagePipeManholeResponseData {
|
||||
@@ -266,5 +270,4 @@ export interface StatsStatusInfo {
|
||||
mctpvPicSbmsnSttsCd?: string;
|
||||
rjctOpnnCn?: string;
|
||||
splmntOpnnCn?: string;
|
||||
splmntRsltCn?: string;
|
||||
}
|
||||
-1
@@ -59,7 +59,6 @@ export interface statsStatusInfo {
|
||||
mctpvPicSbmsnSttsCd?: string;
|
||||
rjctOpnnCn?: string;
|
||||
splmntOpnnCn?: string;
|
||||
splmntRsltCn?: string;
|
||||
}
|
||||
|
||||
export interface SewerageSupplyRateReviewResponseData {
|
||||
|
||||
+4
@@ -168,6 +168,10 @@ export interface FcltyManholeSummaryItem {
|
||||
thlvlMnhlCnt: number;
|
||||
folvlMnhlCnt: number;
|
||||
filvlMnhlCnt: number;
|
||||
wholMnhlCntSum: number;
|
||||
frlvlMnhlCntSum: number;
|
||||
thlvlMnhlCntSum: number;
|
||||
picNm: string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
-1
@@ -135,7 +135,6 @@ export interface HumanWasteSludgeStatusTotalItem {
|
||||
rcycQnt: number;
|
||||
olandLfvlm: number;
|
||||
incnrQnt: number;
|
||||
oceanInputQnt: number;
|
||||
fuelQnt: number;
|
||||
etcQnt: number;
|
||||
unprcsQnt: number;
|
||||
|
||||
@@ -16,8 +16,8 @@ interface VrfcReportPanelProps {
|
||||
|
||||
const TYPE_CODE_NAME_MAP: Record<string, string> = {
|
||||
NV: "일반",
|
||||
IMR: "시계열",
|
||||
HB: "모집단",
|
||||
IMR: "I-MR",
|
||||
HB: "HB",
|
||||
};
|
||||
|
||||
const TYPE_CODE_COLOR_MAP: Record<string, BadgeProps["color"]> = {
|
||||
@@ -73,8 +73,8 @@ export function VrfcReportPanel({ params }: VrfcReportPanelProps) {
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)}
|
||||
|
||||
{/* TBD: 테이블 컬럼 정의, 증감 표시 방법 */}
|
||||
<div className="max-h-[44rem] overflow-y-auto">
|
||||
{data.list.length === 0 ? (
|
||||
@@ -114,9 +114,9 @@ export function VrfcReportPanel({ params }: VrfcReportPanelProps) {
|
||||
<span>{item.admdstNm}</span>
|
||||
<span>
|
||||
{/* TBD: 증감 표시 방법 (nowCn - cmprCn 계산?) */}
|
||||
현재: {item.nowCn ?? "-"}{" "}
|
||||
/ 비교:
|
||||
{item.cmprCn ?? "-"}{" "}
|
||||
현재:{" "}{item.nowCn ?? "-"}
|
||||
/ 비교:{" "}
|
||||
{item.cmprCn ?? "-"}
|
||||
</span>
|
||||
</div>
|
||||
{/* TBD: 등급/점수/단계/업데이트 시각 필드 미제공 */}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
export const STATISTICS_ROUTE = "/statistics";
|
||||
export const STATISTICS_TAB_QUERY_KEY = "tab";
|
||||
/** 기본 화면(대시보드) 도움말 매칭용. URL에는 넣지 않음 */
|
||||
export const STATISTICS_DASHBOARD_TAB_ID = "Dashboard";
|
||||
|
||||
export function buildStatisticsTabUrl(tabId: string): string {
|
||||
return `${STATISTICS_ROUTE}?${STATISTICS_TAB_QUERY_KEY}=${encodeURIComponent(tabId)}`;
|
||||
|
||||
@@ -1,13 +1,20 @@
|
||||
import { PageTitle } from "@common/components";
|
||||
|
||||
import { findMenuItemByUrlPath } from "@/shared/lib/stats-cd-input-navigation";
|
||||
import { STATISTICS_DASHBOARD_TAB_ID } from "@/shared/lib/statistics-tab-url";
|
||||
|
||||
import { TabBar } from "./tab-bar";
|
||||
|
||||
import { useTabStore } from "@/store/tab-store";
|
||||
|
||||
function StatisticsPageLayout({ children }: { children: React.ReactNode }) {
|
||||
const { activeTabId, tabs } = useTabStore();
|
||||
const { activeTabId, tabs, menuList } = useTabStore();
|
||||
|
||||
const pageTitle = tabs.find((t) => t.id === activeTabId);
|
||||
const dashboardMenu =
|
||||
!pageTitle && menuList
|
||||
? findMenuItemByUrlPath(menuList, STATISTICS_DASHBOARD_TAB_ID)
|
||||
: null;
|
||||
|
||||
const menuPaths = pageTitle?.path?.split(">").map((path) => path.trim());
|
||||
|
||||
@@ -16,7 +23,7 @@ function StatisticsPageLayout({ children }: { children: React.ReactNode }) {
|
||||
<TabBar />
|
||||
<PageTitle
|
||||
title={pageTitle?.label ?? ""}
|
||||
menuCd={pageTitle?.menuItem?.menuCd}
|
||||
menuCd={pageTitle?.menuItem?.menuCd ?? dashboardMenu?.menuCd}
|
||||
menuPaths={menuPaths ?? []}
|
||||
/>
|
||||
{children}
|
||||
|
||||
Reference in New Issue
Block a user