(() => {
@@ -356,6 +358,7 @@ const WaterReuseRvw = () => {
)}
+
void handleActiveTabChange(v)}
diff --git a/apps/st/src/components/statistics/verification/generalVerification/CopyDialog.tsx b/apps/st/src/components/statistics/verification/generalVerification/CopyDialog.tsx
index 556d3f54a..bb2f30974 100644
--- a/apps/st/src/components/statistics/verification/generalVerification/CopyDialog.tsx
+++ b/apps/st/src/components/statistics/verification/generalVerification/CopyDialog.tsx
@@ -63,11 +63,14 @@ const CopyDialog = ({
try {
setIsLoading(true);
const userInfo = await getUserInfo();
- const response = await generalverificationApiService.CopyVrfcData({
- vrfcSn: row?.vrfcSn ?? null,
- targetStatsCd: selectedCode ?? '',
- rgtrId: userInfo.userUnqId
- });
+ const response = await generalverificationApiService.CopyVrfcData(
+ {
+ vrfcSn: row?.vrfcSn ?? null,
+ targetStatsCd: selectedCode ?? '',
+ rgtrId: userInfo.userUnqId,
+ },
+ userInfo.userUnqId,
+ );
if (response.status === 'success') {
alert('복사되었습니다.');
diff --git a/apps/st/src/components/statistics/verification/generalVerification/RegistDialog.tsx b/apps/st/src/components/statistics/verification/generalVerification/RegistDialog.tsx
index 1aa0de71f..518f2da32 100644
--- a/apps/st/src/components/statistics/verification/generalVerification/RegistDialog.tsx
+++ b/apps/st/src/components/statistics/verification/generalVerification/RegistDialog.tsx
@@ -177,7 +177,12 @@ const RegistDialog = memo(
if (await confirm(deleteMsg)) {
try {
- const response = await generalverificationApiService.DeleteVrfcMaster(vrfcSn!);
+ const userInfo = await getUserInfo();
+ const response =
+ await generalverificationApiService.DeleteVrfcMaster(
+ vrfcSn!,
+ userInfo.userUnqId,
+ );
if (response.status === 'success') {
alert('삭제되었습니다.');
diff --git a/apps/st/src/components/util/MenuMatchList.ts b/apps/st/src/components/util/MenuMatchList.ts
index ded92e5a4..0ece5c741 100644
--- a/apps/st/src/components/util/MenuMatchList.ts
+++ b/apps/st/src/components/util/MenuMatchList.ts
@@ -1,8 +1,11 @@
/**
* statistics/input 화면과 탭(·분할 그리드) 키 매칭용 상수.
- * 각 컴포넌트에 실제로 쓰이는 `tabKey`를 모두 포함합니다.
+ * 각 컴포넌트에 실제로 쓰이는 `tabKey`·`statsCd`를 모두 포함합니다.
*/
+/** `SeweragePenetrationRateInp.tsx` — 단일 그리드 */
+export const SEWERAGE_PENETRATION_RATE_INP_TAB_KEYS = ["ST00010001"] as const;
+
/** `SewagePipeInp.tsx` — 메인 탭 + `ConnectionStatusInpColumn` 좌·우 그리드 서브 키 */
export const SEWAGE_PIPE_INP_TAB_KEYS = [
"ST00020001",
@@ -18,16 +21,108 @@ export const SEWAGE_PIPE_INP_TAB_KEYS = [
/** `SewagePipeMaintainInp.tsx` — 보수·준설 탭 */
export const SEWAGE_PIPE_MAINTAIN_INP_TAB_KEYS = ["ST00030001", "ST00030002"] as const;
-/** `SeweragePenetrationRateInp.tsx` — 단일 그리드(통계코드) */
-export const SEWERAGE_PENETRATION_RATE_INP_TAB_KEYS = ["ST00010001"] as const;
+/** `SewageReservoirPumpInp.tsx` */
+export const SEWAGE_RESERVOIR_PUMP_INP_TAB_KEYS = ["ST00040001", "ST00040002"] as const;
+/** `PumpingStationInp.tsx` */
+export const PUMPING_STATION_INP_TAB_KEYS = ["ST00050001"] as const;
+
+/** `PublicSewageFacilityInp.tsx` */
+export const PUBLIC_SEWAGE_FACILITY_INP_TAB_KEYS = ["ST00060001", "ST00060002"] as const;
+
+/** `ExcretaTreatmentFacilityInp.tsx` */
+export const EXCRETA_TREATMENT_FACILITY_INP_TAB_KEYS = ["ST00070001"] as const;
+
+/**
+ * `PrivateSewageFacilityInp.tsx`
+ * ST00080003은 tabKey(`privateSewageDesigStatusInp`)와 다름 — `INPUT_TAB_KEY_BY_STATS_CD` 참고
+ */
+export const PRIVATE_SEWAGE_FACILITY_INP_TAB_KEYS = [
+ "ST00080001",
+ "ST00080002",
+ "ST00080003",
+] as const;
+
+/** `SewerageFinanceInp.tsx` */
+export const SEWERAGE_FINANCE_INP_TAB_KEYS = [
+ "ST00090001",
+ "ST00090002",
+ "ST00090003",
+ "ST00090004",
+] as const;
+
+/** `WaterReuseInp.tsx` */
+export const WATER_REUSE_INP_TAB_KEYS = [
+ "ST00100001",
+ "ST00100002",
+ "ST00100003",
+ "ST00100004",
+ "ST00100005",
+] as const;
+
+/** `SewageExcretaSlurgeInp.tsx` */
+export const SEWAGE_EXCRETA_SLURGE_INP_TAB_KEYS = [
+ "ST00110001",
+ "ST00110002",
+ "ST00110003",
+ "ST00110004",
+] as const;
+
+/** `SewageExcretaRelatedInp.tsx` */
+export const SEWAGE_EXCRETA_RELATED_INP_TAB_KEYS = [
+ "ST00120001",
+ "ST00120002",
+ "ST00120003",
+ "ST00120004",
+] as const;
+
+/** `SewerageServiceLevelInp.tsx` */
+export const SEWERAGE_SERVICE_LEVEL_INP_TAB_KEYS = [
+ "ST00130001",
+ "ST00130002",
+] as const;
+
+/** statsCd와 입력 화면 activeTab(tabKey)이 다른 경우 */
+export const INPUT_TAB_KEY_BY_STATS_CD: Record = {
+ ST00080003: "privateSewageDesigStatusInp",
+};
+
+export type SeweragePenetrationRateInpTabKey =
+ (typeof SEWERAGE_PENETRATION_RATE_INP_TAB_KEYS)[number];
export type SewagePipeInpTabKey = (typeof SEWAGE_PIPE_INP_TAB_KEYS)[number];
-export type SewagePipeMaintainInpTabKey = (typeof SEWAGE_PIPE_MAINTAIN_INP_TAB_KEYS)[number];
-export type SeweragePenetrationRateInpTabKey = (typeof SEWERAGE_PENETRATION_RATE_INP_TAB_KEYS)[number];
+export type SewagePipeMaintainInpTabKey =
+ (typeof SEWAGE_PIPE_MAINTAIN_INP_TAB_KEYS)[number];
+export type SewageReservoirPumpInpTabKey =
+ (typeof SEWAGE_RESERVOIR_PUMP_INP_TAB_KEYS)[number];
+export type PumpingStationInpTabKey = (typeof PUMPING_STATION_INP_TAB_KEYS)[number];
+export type PublicSewageFacilityInpTabKey =
+ (typeof PUBLIC_SEWAGE_FACILITY_INP_TAB_KEYS)[number];
+export type ExcretaTreatmentFacilityInpTabKey =
+ (typeof EXCRETA_TREATMENT_FACILITY_INP_TAB_KEYS)[number];
+export type PrivateSewageFacilityInpTabKey =
+ (typeof PRIVATE_SEWAGE_FACILITY_INP_TAB_KEYS)[number];
+export type SewerageFinanceInpTabKey = (typeof SEWERAGE_FINANCE_INP_TAB_KEYS)[number];
+export type WaterReuseInpTabKey = (typeof WATER_REUSE_INP_TAB_KEYS)[number];
+export type SewageExcretaSlurgeInpTabKey =
+ (typeof SEWAGE_EXCRETA_SLURGE_INP_TAB_KEYS)[number];
+export type SewageExcretaRelatedInpTabKey =
+ (typeof SEWAGE_EXCRETA_RELATED_INP_TAB_KEYS)[number];
+export type SewerageServiceLevelInpTabKey =
+ (typeof SEWERAGE_SERVICE_LEVEL_INP_TAB_KEYS)[number];
/** 컴포넌트 파일명 기준 묶음 (메뉴·라우트 매칭 시 참고) */
export const STATISTICS_INPUT_TAB_KEYS_BY_SCREEN = {
+ SeweragePenetrationRateInp: SEWERAGE_PENETRATION_RATE_INP_TAB_KEYS,
SewagePipeInp: SEWAGE_PIPE_INP_TAB_KEYS,
SewagePipeMaintainInp: SEWAGE_PIPE_MAINTAIN_INP_TAB_KEYS,
- SeweragePenetrationRateInp: SEWERAGE_PENETRATION_RATE_INP_TAB_KEYS,
+ SewageReservoirPumpInp: SEWAGE_RESERVOIR_PUMP_INP_TAB_KEYS,
+ PumpingStationInp: PUMPING_STATION_INP_TAB_KEYS,
+ PublicSewageFacilityInp: PUBLIC_SEWAGE_FACILITY_INP_TAB_KEYS,
+ ExcretaTreatmentFacilityInp: EXCRETA_TREATMENT_FACILITY_INP_TAB_KEYS,
+ PrivateSewageFacilityInp: PRIVATE_SEWAGE_FACILITY_INP_TAB_KEYS,
+ SewerageFinanceInp: SEWERAGE_FINANCE_INP_TAB_KEYS,
+ WaterReuseInp: WATER_REUSE_INP_TAB_KEYS,
+ SewageExcretaSlurgeInp: SEWAGE_EXCRETA_SLURGE_INP_TAB_KEYS,
+ SewageExcretaRelatedInp: SEWAGE_EXCRETA_RELATED_INP_TAB_KEYS,
+ SewerageServiceLevelInp: SEWERAGE_SERVICE_LEVEL_INP_TAB_KEYS,
} as const;
diff --git a/apps/st/src/components/util/column/management/LogHistoryDetailColumn.ts b/apps/st/src/components/util/column/management/LogHistoryDetailColumn.ts
index e8c93a45d..220aa70e5 100644
--- a/apps/st/src/components/util/column/management/LogHistoryDetailColumn.ts
+++ b/apps/st/src/components/util/column/management/LogHistoryDetailColumn.ts
@@ -3,6 +3,28 @@ import { ValueType } from "realgrid";
import type { ColumnConfig, ColumnInfo } from "@/components/type/DataGrid.type";
import type { StatisticsLogDetailRow } from "@/entities/statistics/model/statistics-interface";
+export const LOG_DETAIL_DETAILS_FIELD = "details";
+export const LOG_DETAIL_DETAILS_RAW_FIELD = "__detailsRaw";
+
+export interface LogDetailVerificationColumn {
+ tblNm: string;
+ metaSn: number;
+ fieldNm: string;
+ engColNm: string;
+ dataScpCd: string;
+ kornColNm: string;
+}
+
+export interface LogDetailVerificationItem {
+ columns: LogDetailVerificationColumn[];
+ cmprOpert: string | null;
+ vrfcDtlSn: number;
+ refStatsCd: string | null;
+ eqtnCombSeq: number;
+ engArtopnEqtnCn: string;
+ kornArtopnEqtnCn: string;
+}
+
const COMMON_FIELD_ORDER = ["rmrk", "sggNm", "admdstCd", "admdstNm"] as const;
const FIELD_HEADER: Record = {
@@ -10,8 +32,71 @@ const FIELD_HEADER: Record = {
sggNm: "시군구",
admdstCd: "행정구역코드",
admdstNm: "행정구역명",
+ [LOG_DETAIL_DETAILS_FIELD]: "상세",
};
+function parseLogDetailsValue(
+ value: unknown,
+): LogDetailVerificationItem[] | null {
+ if (value == null || value === "") return null;
+ if (Array.isArray(value)) {
+ return value as LogDetailVerificationItem[];
+ }
+ if (typeof value === "string") {
+ try {
+ const parsed: unknown = JSON.parse(value);
+ return Array.isArray(parsed)
+ ? (parsed as LogDetailVerificationItem[])
+ : null;
+ } catch {
+ return null;
+ }
+ }
+ return null;
+}
+
+/** details JSON 배열을 그리드 버튼 셀 + 숨김 raw 필드로 변환 */
+export function prepareLogDetailRowsForGrid(
+ rows: StatisticsLogDetailRow[],
+): Record[] {
+ return rows.map((row) => {
+ const next: Record = {};
+
+ for (const [key, value] of Object.entries(row)) {
+ if (key === LOG_DETAIL_DETAILS_FIELD) {
+ const parsed = parseLogDetailsValue(value);
+ if (parsed && parsed.length > 0) {
+ next[LOG_DETAIL_DETAILS_RAW_FIELD] = JSON.stringify(parsed);
+ next[LOG_DETAIL_DETAILS_FIELD] = "상세보기";
+ } else {
+ next[LOG_DETAIL_DETAILS_RAW_FIELD] = "";
+ next[LOG_DETAIL_DETAILS_FIELD] =
+ value === null || value === undefined
+ ? ""
+ : typeof value === "object"
+ ? ""
+ : String(value);
+ }
+ continue;
+ }
+
+ next[key] =
+ value === null || value === undefined
+ ? ""
+ : (value as string | number);
+ }
+
+ if (
+ LOG_DETAIL_DETAILS_FIELD in row &&
+ !(LOG_DETAIL_DETAILS_RAW_FIELD in next)
+ ) {
+ next[LOG_DETAIL_DETAILS_RAW_FIELD] = "";
+ }
+
+ return next;
+ });
+}
+
function collectFieldNames(rows: StatisticsLogDetailRow[]): string[] {
const keys = new Set();
for (const row of rows) {
@@ -47,6 +132,16 @@ function buildColumns(rows: StatisticsLogDetailRow[]): ColumnConfig[] {
return fieldNames.map((fieldName) => {
const numeric = isNumericField(rows, fieldName);
+ if (fieldName === LOG_DETAIL_DETAILS_FIELD) {
+ return {
+ name: fieldName,
+ fieldName,
+ header: { text: FIELD_HEADER[fieldName] ?? fieldName },
+ editable: false,
+ width: 100,
+ styleName: "rg-cell-outline-action-btn",
+ };
+ }
return {
name: fieldName,
fieldName,
@@ -60,13 +155,33 @@ function buildColumns(rows: StatisticsLogDetailRow[]): ColumnConfig[] {
});
}
+function appendHiddenDetailsRawColumn(columns: ColumnConfig[]): ColumnConfig[] {
+ const hasDetails = columns.some(
+ (column) => column.fieldName === LOG_DETAIL_DETAILS_FIELD,
+ );
+ if (!hasDetails) return columns;
+
+ return [
+ ...columns,
+ {
+ name: LOG_DETAIL_DETAILS_RAW_FIELD,
+ fieldName: LOG_DETAIL_DETAILS_RAW_FIELD,
+ header: { text: "" },
+ editable: false,
+ visible: false,
+ },
+ ];
+}
+
export function buildLogHistoryDetailColumnInfo(
rows: StatisticsLogDetailRow[],
): ColumnInfo {
- const columns = buildColumns(rows);
+ const columns = appendHiddenDetailsRawColumn(buildColumns(rows));
return {
columns,
- columnLayout: columns.map((c) => c.fieldName),
+ columnLayout: columns
+ .filter((column) => column.visible !== false)
+ .map((column) => column.fieldName),
};
}
diff --git a/apps/st/src/components/util/column/review/PublicSewageFacilityRvwColumn.ts b/apps/st/src/components/util/column/review/PublicSewageFacilityRvwColumn.ts
index d02b5360b..b6952ff38 100644
--- a/apps/st/src/components/util/column/review/PublicSewageFacilityRvwColumn.ts
+++ b/apps/st/src/components/util/column/review/PublicSewageFacilityRvwColumn.ts
@@ -33,16 +33,19 @@ export const rawPublicSewageFacilityInfoList = {
name: 'ctpvNm',
fieldName: 'ctpvNm',
header: { text: '시도' },
+ mergeCells: true,
+ sortdisable: true,
footer: [
{ valueCallback: (grid: GridView) => getDivisionFooterLabel(grid, 0, true) },
{ valueCallback: (grid: GridView) => getDivisionFooterLabel(grid, 1, true) },
],
},
- { name: 'sggNm', fieldName: 'sggNm', header: { text: '시군구' } },
+ { name: 'sggNm', fieldName: 'sggNm', header: { text: '시군구' }, mergeCells: true, sortdisable: true },
{
name: 'displayYear',
fieldName: 'displayYear',
header: { text: '구분' },
+ sortdisable: true,
footer: [
{ valueCallback: (grid: GridView) => getDivisionFooterLabel(grid, 0, false) },
{ valueCallback: (grid: GridView) => getDivisionFooterLabel(grid, 1, false) },
diff --git a/apps/st/src/components/util/grid/gridFunction.ts b/apps/st/src/components/util/grid/gridFunction.ts
index ae19943d8..d6e36375a 100644
--- a/apps/st/src/components/util/grid/gridFunction.ts
+++ b/apps/st/src/components/util/grid/gridFunction.ts
@@ -61,6 +61,26 @@ export function buildReviewRowTypeCurrCellStyleCallbackByTab(
return map;
}
+/** 여러 cellStyleCallback 결과를 styleName으로 병합 */
+export function composeCellStyleCallbacks(
+ ...callbacks: CellStyleCallback[]
+): CellStyleCallback {
+ return (params) => {
+ const styleNames: string[] = [];
+ for (const cb of callbacks) {
+ const result = cb(params);
+ if (!result) continue;
+ if (typeof result === "string") {
+ styleNames.push(result);
+ } else if (result.styleName) {
+ styleNames.push(result.styleName);
+ }
+ }
+ const styleName = styleNames.join(" ").trim();
+ return styleName ? styleName : undefined;
+ };
+}
+
/**
* 객체 배열을 그리드 row 형식으로 변환 (null/undefined → "").
* 어떤 엔티티 타입이든 공통 사용 가능.
diff --git a/apps/st/src/components/util/grid/reviewEmptyCurrCellStyle.ts b/apps/st/src/components/util/grid/reviewEmptyCurrCellStyle.ts
new file mode 100644
index 000000000..65a125475
--- /dev/null
+++ b/apps/st/src/components/util/grid/reviewEmptyCurrCellStyle.ts
@@ -0,0 +1,183 @@
+import type { CellStyleCallback, ColumnConfig } from "@/components/type/DataGrid.type";
+import {
+ buildReviewRowTypeCurrCellStyleExcludeMergeCells,
+ composeCellStyleCallbacks,
+} from "@/components/util/grid/gridFunction";
+
+const DISPLAY_YEAR_FIELD = "displayYear";
+
+/** CURR 미입력 + OLD(전년) 데이터 있음 */
+export const REVIEW_CURR_EMPTY_WARN_STYLE = "rg-cell-review-curr-empty-warn";
+/** CURR 미입력 + OLD 행 없음 */
+export const REVIEW_CURR_EMPTY_NEW_STYLE = "rg-cell-review-curr-empty-new";
+
+function getColumnFieldNames(columns: readonly Pick[]): string[] {
+ return columns.map((col) => col.fieldName).filter(Boolean);
+}
+
+function getFieldNamesBeforeDivision(columns: readonly Pick[]): string[] {
+ const fields = getColumnFieldNames(columns);
+ const divisionIndex = fields.indexOf(DISPLAY_YEAR_FIELD);
+ if (divisionIndex <= 0) return [];
+ return fields.slice(0, divisionIndex);
+}
+
+function getFieldNamesAfterDivision(columns: readonly Pick[]): string[] {
+ const fields = getColumnFieldNames(columns);
+ const divisionIndex = fields.indexOf(DISPLAY_YEAR_FIELD);
+ if (divisionIndex < 0 || divisionIndex >= fields.length - 1) return [];
+ return fields.slice(divisionIndex + 1);
+}
+
+function getDivisionHighlightFieldNames(
+ columns: readonly Pick[],
+): Set {
+ const divisionColumn = columns.find((col) => col.fieldName === DISPLAY_YEAR_FIELD);
+ return new Set(
+ [DISPLAY_YEAR_FIELD, divisionColumn?.name, divisionColumn?.fieldName].filter(
+ Boolean,
+ ) as string[],
+ );
+}
+
+function buildRowGroupKey(
+ row: Record,
+ groupKeyFields: readonly string[],
+): string {
+ return groupKeyFields.map((field) => String(row[field] ?? "")).join("\0");
+}
+
+export function isEmptyOrZeroGridValue(value: string | number | undefined): boolean {
+ if (value === null || value === undefined || value === "") return true;
+ if (typeof value === "number") return value === 0;
+ const trimmed = String(value).trim();
+ if (trimmed === "") return true;
+ const numeric = Number(trimmed.replace(/,/g, ""));
+ return !Number.isNaN(numeric) && numeric === 0;
+}
+
+export function isRowEmptyOrZeroAfterDivision(
+ row: Record,
+ dataFieldNames: readonly string[],
+): boolean {
+ if (dataFieldNames.length === 0) return false;
+ return dataFieldNames.every((field) => isEmptyOrZeroGridValue(row[field]));
+}
+
+type EmptyCurrHighlight =
+ | typeof REVIEW_CURR_EMPTY_WARN_STYLE
+ | typeof REVIEW_CURR_EMPTY_NEW_STYLE;
+
+function buildOldRowByGroupKey(
+ rows: readonly Record[],
+ groupKeyFields: readonly string[],
+): Map> {
+ const map = new Map>();
+ for (const row of rows) {
+ if (String(row.rowType ?? "") !== "OLD") continue;
+ map.set(buildRowGroupKey(row, groupKeyFields), row);
+ }
+ return map;
+}
+
+function buildOldRowIndexByGroupKey(
+ rows: readonly Record[],
+ groupKeyFields: readonly string[],
+): Map {
+ const map = new Map();
+ rows.forEach((row, index) => {
+ if (String(row.rowType ?? "") !== "OLD") return;
+ map.set(buildRowGroupKey(row, groupKeyFields), index);
+ });
+ return map;
+}
+
+function resolveEmptyCurrHighlight(
+ currRow: Record,
+ oldRowByGroupKey: ReadonlyMap>,
+ groupKeyFields: readonly string[],
+ dataFieldNames: readonly string[],
+): EmptyCurrHighlight | undefined {
+ if (String(currRow.rowType ?? "") !== "CURR") return undefined;
+ if (!isRowEmptyOrZeroAfterDivision(currRow, dataFieldNames)) return undefined;
+
+ const groupKey = buildRowGroupKey(currRow, groupKeyFields);
+ const oldRow = oldRowByGroupKey.get(groupKey);
+
+ if (!oldRow) {
+ return REVIEW_CURR_EMPTY_NEW_STYLE;
+ }
+ if (isRowEmptyOrZeroAfterDivision(oldRow, dataFieldNames)) {
+ return undefined;
+ }
+ return REVIEW_CURR_EMPTY_WARN_STYLE;
+}
+
+/**
+ * 검토 그리드 — CURR 행의 구분 이후 값이 모두 비어있거나 0일 때
+ * 구분(displayYear): OLD 있음 → OLD·CURR 노란색, OLD 없음 → CURR 하늘색, 둘 다 없음 → 미적용
+ */
+export function buildReviewEmptyCurrCellStyleCallback(
+ columns: readonly Pick[],
+ rows: readonly Record[],
+): CellStyleCallback {
+ const groupKeyFields = getFieldNamesBeforeDivision(columns);
+ const dataFieldNames = getFieldNamesAfterDivision(columns);
+ const highlightFieldNames = getDivisionHighlightFieldNames(columns);
+ const oldRowByGroupKey = buildOldRowByGroupKey(rows, groupKeyFields);
+ const oldRowIndexByGroupKey = buildOldRowIndexByGroupKey(rows, groupKeyFields);
+
+ const highlightByRowIndex = new Map();
+ rows.forEach((row, index) => {
+ if (String(row.rowType ?? "") !== "CURR") return;
+
+ const highlight = resolveEmptyCurrHighlight(
+ row,
+ oldRowByGroupKey,
+ groupKeyFields,
+ dataFieldNames,
+ );
+ if (!highlight) return;
+
+ highlightByRowIndex.set(index, highlight);
+
+ if (highlight === REVIEW_CURR_EMPTY_WARN_STYLE) {
+ const oldIndex = oldRowIndexByGroupKey.get(buildRowGroupKey(row, groupKeyFields));
+ if (oldIndex !== undefined) {
+ highlightByRowIndex.set(oldIndex, highlight);
+ }
+ }
+ });
+
+ return ({ rowIndex, fieldName }) => {
+ if (highlightFieldNames.size === 0 || !highlightFieldNames.has(fieldName)) {
+ return undefined;
+ }
+ return highlightByRowIndex.get(rowIndex);
+ };
+}
+
+export function buildReviewCellStyleCallback(
+ columns: readonly Pick[],
+ rows: readonly Record[],
+): CellStyleCallback {
+ const base = buildReviewRowTypeCurrCellStyleExcludeMergeCells(columns);
+ const emptyCurr = buildReviewEmptyCurrCellStyleCallback(columns, rows);
+ return composeCellStyleCallbacks(base, emptyCurr);
+}
+
+export function buildReviewCellStyleCallbackByTab(
+ tabs: readonly {
+ tabKey: string;
+ columns?: readonly Pick[];
+ }[],
+ rowDataMap: ReadonlyMap[]>,
+): Map {
+ const map = new Map();
+ for (const tab of tabs) {
+ const columns = tab.columns ?? [];
+ const rows = rowDataMap.get(tab.tabKey) ?? [];
+ map.set(tab.tabKey, buildReviewCellStyleCallback(columns, rows));
+ }
+ return map;
+}
diff --git a/apps/st/src/components/util/input/verification-failed-flag.ts b/apps/st/src/components/util/input/verification-failed-flag.ts
new file mode 100644
index 000000000..22c81dad7
--- /dev/null
+++ b/apps/st/src/components/util/input/verification-failed-flag.ts
@@ -0,0 +1,17 @@
+import type { StatisticsInputCommonInfoBase } from "@/entities/statistics/model/statistics-interface";
+
+export function isVerificationFailedFromCommonInfo(
+ commonInfo: Pick | null | undefined,
+): boolean {
+ return commonInfo?.isVerificationFailed === true;
+}
+
+export function patchVerificationFailedByTab(
+ prev: Map,
+ tabKey: string,
+ commonInfo: Pick | null | undefined,
+): Map {
+ const next = new Map(prev);
+ next.set(tabKey, isVerificationFailedFromCommonInfo(commonInfo));
+ return next;
+}
diff --git a/apps/st/src/entities/statistics/api/general-verification-service.ts b/apps/st/src/entities/statistics/api/general-verification-service.ts
index 95c96b467..4e3f3a478 100644
--- a/apps/st/src/entities/statistics/api/general-verification-service.ts
+++ b/apps/st/src/entities/statistics/api/general-verification-service.ts
@@ -75,10 +75,16 @@ export class GeneralverificationApiService implements GeneralverificationService
}
public async DeleteVrfcMaster(
- param: number,
+ vrfcSn: number,
+ userUnqId: string,
): Promise {
const response = await stClient.delete(
- `${ENDPOINT.ST_SERVICE.INPUTVERIFY}/${param}`,
+ `${ENDPOINT.ST_SERVICE.INPUTVERIFY}/${vrfcSn}`,
+ {
+ headers: {
+ userId: userUnqId,
+ },
+ },
);
return response.data;
}
@@ -141,9 +147,16 @@ export class GeneralverificationApiService implements GeneralverificationService
public async CopyVrfcData(
param: CopyVerifyDataRequest,
+ userUnqId: string,
): Promise {
const response = await stClient.post(
`${ENDPOINT.ST_SERVICE.INPUTVERIFY}/${param.vrfcSn}/copy?targetStatsCd=${param.targetStatsCd}&rgtrId=${param.rgtrId}`,
+ undefined,
+ {
+ headers: {
+ userId: userUnqId,
+ },
+ },
);
return response.data;
}
diff --git a/apps/st/src/entities/statistics/api/statistics-management-service.ts b/apps/st/src/entities/statistics/api/statistics-management-service.ts
index d7d2f052f..93bed5573 100644
--- a/apps/st/src/entities/statistics/api/statistics-management-service.ts
+++ b/apps/st/src/entities/statistics/api/statistics-management-service.ts
@@ -258,7 +258,7 @@ export class StatisticsManagementApiService {
sggNm?: string;
statsYr?: string;
sewerBzmnCd?: string;
- pumpstNm?: string;
+ fcltNm?: string;
}
): Promise {
const response = await stClient.get(
diff --git a/apps/st/src/entities/statistics/api/statistics-service.ts b/apps/st/src/entities/statistics/api/statistics-service.ts
index 23a1bd394..557c47150 100644
--- a/apps/st/src/entities/statistics/api/statistics-service.ts
+++ b/apps/st/src/entities/statistics/api/statistics-service.ts
@@ -93,7 +93,7 @@ export class StatisticsApiService implements StatisticsService {
): Promise {
const response = await stClient.get(
`${ENDPOINT.ST_SERVICE.DASHBOARD}/schedule-info/list`,
- { params },
+ withAuthHeader({ params }),
);
return response.data;
}
@@ -101,7 +101,7 @@ export class StatisticsApiService implements StatisticsService {
public async getStatsInputPeriodDetail(params: StatsInputPeriodDetailRequest): Promise {
const response = await stClient.get(
`${ENDPOINT.ST_SERVICE.DASHBOARD}/schedule-info/detail`,
- { params },
+ withAuthHeader({ params }),
);
return response.data;
}
@@ -113,6 +113,7 @@ export class StatisticsApiService implements StatisticsService {
const response = await stClient.post(
`${ENDPOINT.ST_SERVICE.DASHBOARD}/schedule-info`,
param,
+ withAuthHeader(),
);
return response.data;
}
@@ -123,7 +124,7 @@ export class StatisticsApiService implements StatisticsService {
): Promise {
const response = await stClient.delete(
`${ENDPOINT.ST_SERVICE.DASHBOARD}/schedule-info`,
- { data: param },
+ withAuthHeader({ data: param }),
);
return response.data;
}
diff --git a/apps/st/src/entities/statistics/model/general-verification-interface.ts b/apps/st/src/entities/statistics/model/general-verification-interface.ts
index a3fcd66c0..07c0fbea3 100644
--- a/apps/st/src/entities/statistics/model/general-verification-interface.ts
+++ b/apps/st/src/entities/statistics/model/general-verification-interface.ts
@@ -275,7 +275,10 @@ export interface GeneralverificationService {
RegistVrfcMaster(
param: RegistVrfcMasterRequest,
): Promise;
- DeleteVrfcMaster(param: number): Promise;
+ DeleteVrfcMaster(
+ vrfcSn: number,
+ userUnqId: string,
+ ): Promise;
getVrfcOperators(): Promise;
getVrfcDetail(param: number): Promise;
getVerifyColumnList(
@@ -292,6 +295,7 @@ export interface GeneralverificationService {
): Promise;
CopyVrfcData(
param: CopyVerifyDataRequest,
+ userUnqId: string,
): Promise;
getVerifyResultList(
param: VerifyResultListRequest,
diff --git a/apps/st/src/entities/statistics/model/input/statistics-input-excreta-treatment-facility-interface.ts b/apps/st/src/entities/statistics/model/input/statistics-input-excreta-treatment-facility-interface.ts
index 07d5c3c00..82a721d35 100644
--- a/apps/st/src/entities/statistics/model/input/statistics-input-excreta-treatment-facility-interface.ts
+++ b/apps/st/src/entities/statistics/model/input/statistics-input-excreta-treatment-facility-interface.ts
@@ -1,4 +1,4 @@
-import type { ApiResponse, SewerageStatusInfo } from "../statistics-interface";
+import type { ApiResponse, SewerageStatusInfo, StatisticsInputCommonInfoBase } from "../statistics-interface";
/** 분뇨처리시설(ST00070001) — `ExcretaTreatFactInpColumn` */
export const EXCRETA_TREATMENT_FACILITY_STATS_CD = "ST00070001" as const;
@@ -18,7 +18,7 @@ export type ExcretaTreatmentFacilityVerificationResult = Record<
>;
/** 분뇨처리시설 조회 `data.commonInfo` */
-export interface ExcretaTreatmentFacilityCommonInfo {
+export interface ExcretaTreatmentFacilityCommonInfo extends StatisticsInputCommonInfoBase {
statsYr: string;
ctpvNm: string;
sewerBzmnCd: string;
diff --git a/apps/st/src/entities/statistics/model/input/statistics-input-private-sewage-facility-interface.ts b/apps/st/src/entities/statistics/model/input/statistics-input-private-sewage-facility-interface.ts
index 89179711b..b0285ac8d 100644
--- a/apps/st/src/entities/statistics/model/input/statistics-input-private-sewage-facility-interface.ts
+++ b/apps/st/src/entities/statistics/model/input/statistics-input-private-sewage-facility-interface.ts
@@ -1,4 +1,4 @@
-import type { ApiResponse, SewerageStatusInfo } from "../statistics-interface";
+import type { ApiResponse, SewerageStatusInfo, StatisticsInputCommonInfoBase } from "../statistics-interface";
/** 처리용량별 오수처리시설 현황(ST00080001) — `SewageTreatFactStatusInpColumn.tabKey` */
export const SEWAGE_TREAT_FACT_STATUS_STATS_CD = "ST00080001" as const;
@@ -18,7 +18,7 @@ export type PrivateSewageFacilityVerificationResult = Record<
>;
/** ST00080001 조회 `data.commonInfo` */
-export interface SewageTreatFactStatusCommonInfo {
+export interface SewageTreatFactStatusCommonInfo extends StatisticsInputCommonInfoBase {
statsYr: string;
ctpvNm: string;
sewerBzmnCd: string;
@@ -78,7 +78,7 @@ export interface SewageTreatFactStatusRequestParams {
export const SEPTIC_TANK_STATUS_STATS_CD = "ST00080002" as const;
/** ST00080002 조회 `data.commonInfo` */
-export interface SepticTankStatusCommonInfo {
+export interface SepticTankStatusCommonInfo extends StatisticsInputCommonInfoBase {
statsYr: string;
ctpvNm: string;
sewerBzmnCd: string;
@@ -156,7 +156,7 @@ export interface SepticTankStatusRequestParams {
export const PRIVATE_SEWAGE_DESIG_STATUS_STATS_CD = "ST00080003" as const;
/** ST00080003 조회 `data.commonInfo` */
-export interface PrivateSewageDesigStatusCommonInfo {
+export interface PrivateSewageDesigStatusCommonInfo extends StatisticsInputCommonInfoBase {
statsYr: string;
ctpvNm: string;
sewerBzmnCd: string;
diff --git a/apps/st/src/entities/statistics/model/input/statistics-input-pumping-station-interface.ts b/apps/st/src/entities/statistics/model/input/statistics-input-pumping-station-interface.ts
index 105eb1214..e9cfe9b99 100644
--- a/apps/st/src/entities/statistics/model/input/statistics-input-pumping-station-interface.ts
+++ b/apps/st/src/entities/statistics/model/input/statistics-input-pumping-station-interface.ts
@@ -1,4 +1,4 @@
-import type { ApiResponse, SewerageStatusInfo } from "../statistics-interface";
+import type { ApiResponse, SewerageStatusInfo, StatisticsInputCommonInfoBase } from "../statistics-interface";
/** 펌프장(ST00050001) — `PumpingStationInpColumn` tabKey */
export const PUMPING_STATION_STATS_CD = "ST00050001" as const;
@@ -18,7 +18,7 @@ export type PumpingStationVerificationResult = Record<
>;
/** 펌프장 조회 `data.commonInfo` */
-export interface PumpingStationCommonInfo {
+export interface PumpingStationCommonInfo extends StatisticsInputCommonInfoBase {
statsYr: string;
ctpvNm: string;
sewerBzmnCd: string;
diff --git a/apps/st/src/entities/statistics/model/input/statistics-input-sewage-excreta-related-interface.ts b/apps/st/src/entities/statistics/model/input/statistics-input-sewage-excreta-related-interface.ts
index f2db92d5a..fbfc464b3 100644
--- a/apps/st/src/entities/statistics/model/input/statistics-input-sewage-excreta-related-interface.ts
+++ b/apps/st/src/entities/statistics/model/input/statistics-input-sewage-excreta-related-interface.ts
@@ -1,4 +1,4 @@
-import type { ApiResponse, SewerageStatusInfo } from "../statistics-interface";
+import type { ApiResponse, SewerageStatusInfo, StatisticsInputCommonInfoBase } from "../statistics-interface";
/** 하수·분뇨관련산업 — 공공기관 하수분야(ST00120001) `PublicInstitutionSewerIndustryInpColumn.tabKey` */
export const SEWAGE_EXCRETA_PUBLIC_INSTITUTION_SEWER_STATS_CD = "ST00120001" as const;
@@ -18,7 +18,7 @@ export type SewageExcretaRelatedVerificationResult = Record<
>;
/** 조회 `data.commonInfo` */
-export interface SewageExcretaRelatedCommonInfo {
+export interface SewageExcretaRelatedCommonInfo extends StatisticsInputCommonInfoBase {
statsYr: string;
ctpvNm: string;
sewerBzmnCd: string;
diff --git a/apps/st/src/entities/statistics/model/input/statistics-input-sewage-excreta-slurge-interface.ts b/apps/st/src/entities/statistics/model/input/statistics-input-sewage-excreta-slurge-interface.ts
index 4c575fe84..1ad5e2294 100644
--- a/apps/st/src/entities/statistics/model/input/statistics-input-sewage-excreta-slurge-interface.ts
+++ b/apps/st/src/entities/statistics/model/input/statistics-input-sewage-excreta-slurge-interface.ts
@@ -1,4 +1,4 @@
-import type { ApiResponse, SewerageStatusInfo } from "../statistics-interface";
+import type { ApiResponse, SewerageStatusInfo, StatisticsInputCommonInfoBase } from "../statistics-interface";
/** 슬러지 처리 — 찌꺼기(슬러지)처리시설현황(ST00110001) `SlurgeProcessingFacStatusInpColumn.tabKey` */
export const SEWAGE_EXCRETA_SLURGE_PROCESSING_FAC_STATUS_STATS_CD = "ST00110001" as const;
@@ -27,7 +27,7 @@ export type SewageExcretaSlurgeVerificationResult = Record<
>;
/** 조회 `data.commonInfo` */
-export interface SewageExcretaSlurgeCommonInfo {
+export interface SewageExcretaSlurgeCommonInfo extends StatisticsInputCommonInfoBase {
statsYr: string;
ctpvNm: string;
sewerBzmnCd: string;
diff --git a/apps/st/src/entities/statistics/model/input/statistics-input-sewage-pipe-maintain-interface.ts b/apps/st/src/entities/statistics/model/input/statistics-input-sewage-pipe-maintain-interface.ts
index 36743925e..df35d2f76 100644
--- a/apps/st/src/entities/statistics/model/input/statistics-input-sewage-pipe-maintain-interface.ts
+++ b/apps/st/src/entities/statistics/model/input/statistics-input-sewage-pipe-maintain-interface.ts
@@ -1,4 +1,4 @@
-import type { ApiResponse, SewerageStatusInfo } from "../statistics-interface";
+import type { ApiResponse, SewerageStatusInfo, StatisticsInputCommonInfoBase } from "../statistics-interface";
export interface SewagePipeMaintainRepairVerificationResultItem {
vrfcCd: string;
@@ -13,7 +13,7 @@ export type SewagePipeMaintainRepairVerificationResult = Record<
SewagePipeMaintainRepairVerificationResultItem[]
>;
-export interface SewagePipeMaintainRepairCommonInfo {
+export interface SewagePipeMaintainRepairCommonInfo extends StatisticsInputCommonInfoBase {
statsYr: string;
ctpvNm: string;
sewerBzmnCd: string;
diff --git a/apps/st/src/entities/statistics/model/input/statistics-input-sewage-reservoir-pump-interface.ts b/apps/st/src/entities/statistics/model/input/statistics-input-sewage-reservoir-pump-interface.ts
index 4a5d0bd66..eb734afca 100644
--- a/apps/st/src/entities/statistics/model/input/statistics-input-sewage-reservoir-pump-interface.ts
+++ b/apps/st/src/entities/statistics/model/input/statistics-input-sewage-reservoir-pump-interface.ts
@@ -1,4 +1,4 @@
-import type { ApiResponse, SewerageStatusInfo } from "../statistics-interface";
+import type { ApiResponse, SewerageStatusInfo, StatisticsInputCommonInfoBase } from "../statistics-interface";
/** 하수저류시설 Tab1 — `SewageReservoirInpColumn.tabKey` */
export const SEWAGE_RESERVOIR_STATS_CD = "ST00040001" as const;
@@ -18,7 +18,7 @@ export type SewageReservoirVerificationResult = Record<
>;
/** 하수저류시설 조회 `data.commonInfo` */
-export interface SewageReservoirCommonInfo {
+export interface SewageReservoirCommonInfo extends StatisticsInputCommonInfoBase {
statsYr: string;
ctpvNm: string;
sewerBzmnCd: string;
@@ -86,7 +86,7 @@ export type SewageReservoirApiResponse = ApiResponse;
/** ST00090001 조회 `data.commonInfo` */
-export interface SewerageFinanceSettleCommonInfo {
+export interface SewerageFinanceSettleCommonInfo extends StatisticsInputCommonInfoBase {
statsYr: string;
ctpvNm: string;
sewerBzmnCd: string;
@@ -202,7 +202,7 @@ export interface SewerageFinanceSubmitResponse {
export const SEWERAGE_CHARGE_STATS_CD = "ST00090002" as const;
/** ST00090002 조회 `data.commonInfo` */
-export interface SewerageChargeCommonInfo {
+export interface SewerageChargeCommonInfo extends StatisticsInputCommonInfoBase {
statsYr: string;
ctpvNm: string;
sewerBzmnCd: string;
@@ -292,7 +292,7 @@ export type SewerageChargeSubmitItem = SewerageChargeSaveItem;
export const SEWERAGE_USAGE_FEE_STATS_CD = "ST00090003" as const;
/** ST00090003 조회 `data.commonInfo` */
-export interface SewerageUsageFeeCommonInfo {
+export interface SewerageUsageFeeCommonInfo extends StatisticsInputCommonInfoBase {
statsYr: string;
ctpvNm: string;
sewerBzmnCd: string;
@@ -416,7 +416,7 @@ export type SewerageUsageFeeSubmitItem = SewerageUsageFeeSaveItem;
export const CAUSER_BURDEN_STATS_CD = "ST00090004" as const;
/** ST00090004 조회 `data.commonInfo` */
-export interface CauserBurdenCommonInfo {
+export interface CauserBurdenCommonInfo extends StatisticsInputCommonInfoBase {
statsYr: string;
ctpvNm: string;
sewerBzmnCd: string;
diff --git a/apps/st/src/entities/statistics/model/input/statistics-input-sewerage-service-level-interface.ts b/apps/st/src/entities/statistics/model/input/statistics-input-sewerage-service-level-interface.ts
index f331aa558..b2e9f95df 100644
--- a/apps/st/src/entities/statistics/model/input/statistics-input-sewerage-service-level-interface.ts
+++ b/apps/st/src/entities/statistics/model/input/statistics-input-sewerage-service-level-interface.ts
@@ -1,4 +1,4 @@
-import type { ApiResponse, SewerageStatusInfo } from "../statistics-interface";
+import type { ApiResponse, SewerageStatusInfo, StatisticsInputCommonInfoBase } from "../statistics-interface";
/** 하수도 서비스 수준 — 민원(ST00130001) `ComplaintInpColumn.tabKey` */
export const SEWERAGE_SERVICE_LEVEL_COMPLAINT_STATS_CD = "ST00130001" as const;
@@ -18,7 +18,7 @@ export type SewerageServiceLevelVerificationResult = Record<
>;
/** ST00130001 조회 `data.commonInfo` */
-export interface SewerageServiceLevelComplaintCommonInfo {
+export interface SewerageServiceLevelComplaintCommonInfo extends StatisticsInputCommonInfoBase {
statsYr: string;
ctpvNm: string;
sewerBzmnCd: string;
@@ -72,7 +72,7 @@ export interface SewerageServiceLevelComplaintRequestParams {
export const SEWERAGE_SERVICE_LEVEL_RESIDENT_FRIENDLY_FACT_STATS_CD = "ST00130002" as const;
/** ST00130002 조회 `data.commonInfo` */
-export interface SewerageServiceLevelResidentFriendlyFactCommonInfo {
+export interface SewerageServiceLevelResidentFriendlyFactCommonInfo extends StatisticsInputCommonInfoBase {
statsYr: string;
ctpvNm: string;
sewerBzmnCd: string;
diff --git a/apps/st/src/entities/statistics/model/input/statistics-input-water-reuse-interface.ts b/apps/st/src/entities/statistics/model/input/statistics-input-water-reuse-interface.ts
index e157b9a68..b40a17da5 100644
--- a/apps/st/src/entities/statistics/model/input/statistics-input-water-reuse-interface.ts
+++ b/apps/st/src/entities/statistics/model/input/statistics-input-water-reuse-interface.ts
@@ -1,4 +1,4 @@
-import type { ApiResponse, SewerageStatusInfo } from "../statistics-interface";
+import type { ApiResponse, SewerageStatusInfo, StatisticsInputCommonInfoBase } from "../statistics-interface";
/** 물 재이용 — 공공하수처리수 재이용(ST00100001) `PublicSewageTreatWaterReuseInpColumn.tabKey` */
export const WATER_REUSE_PUBLIC_SEWAGE_TREAT_STATS_CD = "ST00100001" as const;
@@ -30,7 +30,7 @@ export type WaterReuseVerificationResult = Record<
>;
/** 조회 `data.commonInfo` */
-export interface WaterReuseCommonInfo {
+export interface WaterReuseCommonInfo extends StatisticsInputCommonInfoBase {
statsYr: string;
ctpvNm: string;
sewerBzmnCd: string;
diff --git a/apps/st/src/entities/statistics/model/input/statistics-public-sewage-facility-input-interface.ts b/apps/st/src/entities/statistics/model/input/statistics-public-sewage-facility-input-interface.ts
index a2570a9e2..7d685fdcb 100644
--- a/apps/st/src/entities/statistics/model/input/statistics-public-sewage-facility-input-interface.ts
+++ b/apps/st/src/entities/statistics/model/input/statistics-public-sewage-facility-input-interface.ts
@@ -1,4 +1,4 @@
-import type { SewerageStatusInfo } from "../statistics-interface";
+import type { SewerageStatusInfo, StatisticsInputCommonInfoBase } from "../statistics-interface";
export interface PublicSewageFacilityRequestParams {
ctpvNm?: string;
@@ -22,7 +22,7 @@ export type PublicSewageFacilityVerificationResult = Record<
PublicSewageFacilityVerifyResultItem[]
>;
-export interface PublicSewageFacilityCommonInfo {
+export interface PublicSewageFacilityCommonInfo extends StatisticsInputCommonInfoBase {
statsYr: string;
ctpvNm: string;
sewerBzmnCd: string;
diff --git a/apps/st/src/entities/statistics/model/input/statistics-sewage-pipe-input-interface.ts b/apps/st/src/entities/statistics/model/input/statistics-sewage-pipe-input-interface.ts
index 4076e5f4f..454eb4446 100644
--- a/apps/st/src/entities/statistics/model/input/statistics-sewage-pipe-input-interface.ts
+++ b/apps/st/src/entities/statistics/model/input/statistics-sewage-pipe-input-interface.ts
@@ -1,4 +1,4 @@
-import type { SewerageStatusInfo } from "../statistics-interface";
+import type { SewerageStatusInfo, StatisticsInputCommonInfoBase } from "../statistics-interface";
export interface SeweragePipeRequestParams {
ctpvNm?: string;
@@ -20,7 +20,7 @@ export interface VerifyResultItem {
/** 필드명 -> 검증 결과 배열 */
export type SeweragePipeInputVerificationResult = Record;
-export interface SeweragePipeInputCommonInfo {
+export interface SeweragePipeInputCommonInfo extends StatisticsInputCommonInfoBase {
statsYr: string;
ctpvNm: string;
sewerBzmnCd: string;
diff --git a/apps/st/src/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface.ts b/apps/st/src/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface.ts
index 5744197f8..d58f3c41e 100644
--- a/apps/st/src/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface.ts
+++ b/apps/st/src/entities/statistics/model/input/statistics-sewage-supply-rate-input-interface.ts
@@ -1,7 +1,7 @@
-import type { ApiResponse, SewerageStatusInfo } from "../statistics-interface";
+import type { ApiResponse, SewerageStatusInfo, StatisticsInputCommonInfoBase } from "../statistics-interface";
// 하수도 보급률 데이터 항목
-export interface SewerageSupplyRateCommonInfo {
+export interface SewerageSupplyRateCommonInfo extends StatisticsInputCommonInfoBase {
sewerBzmnArea: number;
sewerBzmnCd: string;
sewerBzmnFrgnrWholPpltnCnt: number;
diff --git a/apps/st/src/entities/statistics/model/statistics-excreta-treatment-facility-review-interface.ts b/apps/st/src/entities/statistics/model/statistics-excreta-treatment-facility-review-interface.ts
index b7981456d..ef4b618a8 100644
--- a/apps/st/src/entities/statistics/model/statistics-excreta-treatment-facility-review-interface.ts
+++ b/apps/st/src/entities/statistics/model/statistics-excreta-treatment-facility-review-interface.ts
@@ -44,7 +44,7 @@ export interface ExcretaTreatmentFacilityReviewItem {
}
export interface ExcretaTreatmentFacilityReviewResponseData {
- excretaTreatmentFacilityList: ExcretaTreatmentFacilityReviewItem[];
+ excretaTreatmentList: ExcretaTreatmentFacilityReviewItem[];
statsStatusInfo?: StatsStatusInfo;
}
@@ -65,7 +65,7 @@ export function extractExcretaTreatmentFacilityReviewList(
): ExcretaTreatmentFacilityReviewItem[] {
if (!data) return [];
if (Array.isArray(data)) return data;
- return data.excretaTreatmentFacilityList ?? [];
+ return data.excretaTreatmentList ?? [];
}
export function extractExcretaTreatmentFacilityReviewStatsStatusInfo(
diff --git a/apps/st/src/entities/statistics/model/statistics-interface.ts b/apps/st/src/entities/statistics/model/statistics-interface.ts
index d63262e54..f748a5c04 100644
--- a/apps/st/src/entities/statistics/model/statistics-interface.ts
+++ b/apps/st/src/entities/statistics/model/statistics-interface.ts
@@ -49,6 +49,7 @@ export type StatisticsColumnGuideListResponse = ApiResponse;
/** 통계 입력 기간 삭제 요청 */
export interface StatsInputPeriodDeleteRequest {
+ extSchdlId?: number;
statsYr: string;
seType: string;
seCd: number;
@@ -105,6 +109,11 @@ export interface StatsInputPeriodDeleteRequest {
/** 통계 입력 기간 삭제 응답 */
export type StatsInputPeriodDeleteApiResponse = ApiResponse;
+/** 입력 조회 `data.commonInfo` 공통 필드 */
+export interface StatisticsInputCommonInfoBase {
+ isVerificationFailed: boolean;
+}
+
/** 하수 입력/보급률 등 조회 `data.statusInfo` 공통 (LAE 제출·담당자 정보) */
export interface SewerageStatusInfo {
laePicNm: string | null;
diff --git a/apps/st/src/entities/statistics/model/statistics-pumping-station-review-interface.ts b/apps/st/src/entities/statistics/model/statistics-pumping-station-review-interface.ts
index 7ce2bc32a..4f4ad95d6 100644
--- a/apps/st/src/entities/statistics/model/statistics-pumping-station-review-interface.ts
+++ b/apps/st/src/entities/statistics/model/statistics-pumping-station-review-interface.ts
@@ -84,6 +84,6 @@ export interface MediationPumpStationService {
sewerBzmnCd?: string;
ctpvNm?: string;
sggNm?: string;
- pumpstNm?: string;
+ fcltNm?: string;
}): Promise;
}
diff --git a/apps/st/src/shared/lib/stats-cd-input-navigation.ts b/apps/st/src/shared/lib/stats-cd-input-navigation.ts
index 56b8c791d..891572ef9 100644
--- a/apps/st/src/shared/lib/stats-cd-input-navigation.ts
+++ b/apps/st/src/shared/lib/stats-cd-input-navigation.ts
@@ -3,9 +3,20 @@ import type { SearchFormValues } from "@/components/type/SearchForm.type";
import { doNameList } from "@/components/util/column/input/DoList";
import { menuMatchesStatisticsTabId } from "@/shared/lib/statistics-menu-url";
import {
+ EXCRETA_TREATMENT_FACILITY_INP_TAB_KEYS,
+ INPUT_TAB_KEY_BY_STATS_CD,
+ PRIVATE_SEWAGE_FACILITY_INP_TAB_KEYS,
+ PUBLIC_SEWAGE_FACILITY_INP_TAB_KEYS,
+ PUMPING_STATION_INP_TAB_KEYS,
+ SEWAGE_EXCRETA_RELATED_INP_TAB_KEYS,
+ SEWAGE_EXCRETA_SLURGE_INP_TAB_KEYS,
SEWAGE_PIPE_INP_TAB_KEYS,
SEWAGE_PIPE_MAINTAIN_INP_TAB_KEYS,
+ SEWAGE_RESERVOIR_PUMP_INP_TAB_KEYS,
+ SEWERAGE_FINANCE_INP_TAB_KEYS,
SEWERAGE_PENETRATION_RATE_INP_TAB_KEYS,
+ SEWERAGE_SERVICE_LEVEL_INP_TAB_KEYS,
+ WATER_REUSE_INP_TAB_KEYS,
} from "@/components/util/MenuMatchList";
/** 검증 결과에서 입력 화면 자동 조회에 사용하는 조건 */
@@ -35,15 +46,21 @@ export function verificationSearchToFormValues(
/** `statistics-page` 동적 import 경로의 파일명(확장자 제외)과 일치해야 함 */
export const STATISTICS_INPUT_URL_PATH = {
+ SEWERAGE_PENETRATION_RATE: "SeweragePenetrationRateInp",
SEWAGE_PIPE: "SewagePipeInp",
SEWAGE_PIPE_MAINTAIN: "SewagePipeMaintainInp",
- SEWERAGE_PENETRATION_RATE: "SeweragePenetrationRateInp",
+ SEWAGE_RESERVOIR_PUMP: "SewageReservoirPumpInp",
+ PUMPING_STATION: "PumpingStationInp",
PUBLIC_SEWAGE_FACILITY: "PublicSewageFacilityInp",
+ EXCRETA_TREATMENT_FACILITY: "ExcretaTreatmentFacilityInp",
+ PRIVATE_SEWAGE_FACILITY: "PrivateSewageFacilityInp",
+ SEWERAGE_FINANCE: "SewerageFinanceInp",
+ WATER_REUSE: "WaterReuseInp",
+ SEWAGE_EXCRETA_SLURGE: "SewageExcretaSlurgeInp",
+ SEWAGE_EXCRETA_RELATED: "SewageExcretaRelatedInp",
+ SEWERAGE_SERVICE_LEVEL: "SewerageServiceLevelInp",
} as const;
-/** `PublicSewageFacilityInp.tsx` — 공공하수처리시설 탭 */
-const PUBLIC_SEWAGE_FACILITY_INP_TAB_KEYS = ["ST00060001"] as const;
-
function normalizeSewagePipeTabKey(tabKey: string): string {
if (
tabKey === "adminAreaConnectionInp" ||
@@ -54,20 +71,66 @@ function normalizeSewagePipeTabKey(tabKey: string): string {
return tabKey;
}
+function resolveInputTabKey(urlPath: string, statsCd: string): string {
+ if (urlPath === STATISTICS_INPUT_URL_PATH.SEWAGE_PIPE) {
+ return normalizeSewagePipeTabKey(statsCd);
+ }
+ return INPUT_TAB_KEY_BY_STATS_CD[statsCd] ?? statsCd;
+}
+
const NAV_ROWS: { urlPath: string; tabKeys: readonly string[] }[] = [
- { urlPath: STATISTICS_INPUT_URL_PATH.SEWAGE_PIPE, tabKeys: SEWAGE_PIPE_INP_TAB_KEYS },
- {
- urlPath: STATISTICS_INPUT_URL_PATH.SEWAGE_PIPE_MAINTAIN,
- tabKeys: SEWAGE_PIPE_MAINTAIN_INP_TAB_KEYS,
- },
{
urlPath: STATISTICS_INPUT_URL_PATH.SEWERAGE_PENETRATION_RATE,
tabKeys: SEWERAGE_PENETRATION_RATE_INP_TAB_KEYS,
},
+ {
+ urlPath: STATISTICS_INPUT_URL_PATH.SEWAGE_PIPE,
+ tabKeys: SEWAGE_PIPE_INP_TAB_KEYS,
+ },
+ {
+ urlPath: STATISTICS_INPUT_URL_PATH.SEWAGE_PIPE_MAINTAIN,
+ tabKeys: SEWAGE_PIPE_MAINTAIN_INP_TAB_KEYS,
+ },
+ {
+ urlPath: STATISTICS_INPUT_URL_PATH.SEWAGE_RESERVOIR_PUMP,
+ tabKeys: SEWAGE_RESERVOIR_PUMP_INP_TAB_KEYS,
+ },
+ {
+ urlPath: STATISTICS_INPUT_URL_PATH.PUMPING_STATION,
+ tabKeys: PUMPING_STATION_INP_TAB_KEYS,
+ },
{
urlPath: STATISTICS_INPUT_URL_PATH.PUBLIC_SEWAGE_FACILITY,
tabKeys: PUBLIC_SEWAGE_FACILITY_INP_TAB_KEYS,
},
+ {
+ urlPath: STATISTICS_INPUT_URL_PATH.EXCRETA_TREATMENT_FACILITY,
+ tabKeys: EXCRETA_TREATMENT_FACILITY_INP_TAB_KEYS,
+ },
+ {
+ urlPath: STATISTICS_INPUT_URL_PATH.PRIVATE_SEWAGE_FACILITY,
+ tabKeys: PRIVATE_SEWAGE_FACILITY_INP_TAB_KEYS,
+ },
+ {
+ urlPath: STATISTICS_INPUT_URL_PATH.SEWERAGE_FINANCE,
+ tabKeys: SEWERAGE_FINANCE_INP_TAB_KEYS,
+ },
+ {
+ urlPath: STATISTICS_INPUT_URL_PATH.WATER_REUSE,
+ tabKeys: WATER_REUSE_INP_TAB_KEYS,
+ },
+ {
+ urlPath: STATISTICS_INPUT_URL_PATH.SEWAGE_EXCRETA_SLURGE,
+ tabKeys: SEWAGE_EXCRETA_SLURGE_INP_TAB_KEYS,
+ },
+ {
+ urlPath: STATISTICS_INPUT_URL_PATH.SEWAGE_EXCRETA_RELATED,
+ tabKeys: SEWAGE_EXCRETA_RELATED_INP_TAB_KEYS,
+ },
+ {
+ urlPath: STATISTICS_INPUT_URL_PATH.SEWERAGE_SERVICE_LEVEL,
+ tabKeys: SEWERAGE_SERVICE_LEVEL_INP_TAB_KEYS,
+ },
];
/**
@@ -83,11 +146,10 @@ export function resolveInputPageNavigationFromStatsCd(statsCd: string): {
for (const row of NAV_ROWS) {
if (row.tabKeys.includes(trimmed)) {
- const tabKey =
- row.urlPath === STATISTICS_INPUT_URL_PATH.SEWAGE_PIPE
- ? normalizeSewagePipeTabKey(trimmed)
- : trimmed;
- return { urlPath: row.urlPath, tabKey };
+ return {
+ urlPath: row.urlPath,
+ tabKey: resolveInputTabKey(row.urlPath, trimmed),
+ };
}
}
return null;
diff --git a/apps/st/src/shared/lib/use-statistics-input-pending-navigation.ts b/apps/st/src/shared/lib/use-statistics-input-pending-navigation.ts
new file mode 100644
index 000000000..9a901e558
--- /dev/null
+++ b/apps/st/src/shared/lib/use-statistics-input-pending-navigation.ts
@@ -0,0 +1,71 @@
+"use client";
+
+import { useEffect, useLayoutEffect, useRef, useState } from "react";
+
+import type { SearchFormValues } from "@/components/type/SearchForm.type";
+import {
+ verificationSearchToFormValues,
+ type StatisticsInputPendingSearch,
+} from "@/shared/lib/stats-cd-input-navigation";
+import { useStatisticsInputFocusStore } from "@/store/statistics-input-focus-store";
+import { useTabStore } from "@/store/tab-store";
+
+type PendingNavigation = {
+ tabKey: string;
+ search: StatisticsInputPendingSearch | null;
+};
+
+type UseStatisticsInputPendingNavigationOptions = {
+ urlPath: string;
+ onPending?: (pending: PendingNavigation) => void;
+ onAutoSearch?: (
+ values: SearchFormValues,
+ tabKey: string,
+ ) => void | Promise;
+};
+
+/** 이상치 선별 보고서 등에서 넘어온 입력 화면·탭·검색조건을 적용합니다. */
+export function useStatisticsInputPendingNavigation({
+ urlPath,
+ onPending,
+ onAutoSearch,
+}: UseStatisticsInputPendingNavigationOptions) {
+ const [verificationSearchDefaults, setVerificationSearchDefaults] =
+ useState(null);
+ const [searchFormRemountKey, setSearchFormRemountKey] = useState(0);
+ const autoSearchRef = useRef<{
+ values: SearchFormValues;
+ tabKey: string;
+ } | null>(null);
+ const handlersRef = useRef({ onPending, onAutoSearch });
+ handlersRef.current = { onPending, onAutoSearch };
+
+ const activeTabId = useTabStore((s) => s.activeTabId);
+ const inputFocusNonce = useStatisticsInputFocusStore((s) => s.nonce);
+
+ useLayoutEffect(() => {
+ if (activeTabId !== urlPath) return;
+ const pending = useStatisticsInputFocusStore
+ .getState()
+ .takePendingForUrl(urlPath);
+ if (!pending) return;
+
+ handlersRef.current.onPending?.(pending);
+
+ if (pending.search) {
+ const values = verificationSearchToFormValues(pending.search);
+ setVerificationSearchDefaults(values);
+ autoSearchRef.current = { values, tabKey: pending.tabKey };
+ setSearchFormRemountKey((k) => k + 1);
+ }
+ }, [activeTabId, inputFocusNonce, urlPath]);
+
+ useEffect(() => {
+ const job = autoSearchRef.current;
+ if (!job) return;
+ autoSearchRef.current = null;
+ void handlersRef.current.onAutoSearch?.(job.values, job.tabKey);
+ }, [searchFormRemountKey]);
+
+ return { verificationSearchDefaults, searchFormRemountKey };
+}