From 4a26dae6b491fd14fe4fad7f64508dbd709405a6 Mon Sep 17 00:00:00 2001 From: bicochan Date: Thu, 16 Apr 2026 14:29:44 +0900 Subject: [PATCH] =?UTF-8?q?[st]=20feat:=20=ED=86=B5=EA=B3=84=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=EB=A6=AC=ED=8F=AC=ED=8A=B8=20=ED=99=94=EB=A9=B4=20?= =?UTF-8?q?=EB=A0=88=EC=9D=B4=EC=95=84=EC=9B=83=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../StatisticsVerificationReport.tsx | 361 ++++++++++++++++++ .../statistics-input-status-interface.ts | 11 +- .../statistics-verification-report-columns.ts | 71 ++++ .../statistics-verification-report-mock.ts | 288 ++++++++++++++ .../statistics-verification-report-types.ts | 49 +++ apps/st/src/shared/config/env.ts | 2 +- 6 files changed, 778 insertions(+), 4 deletions(-) create mode 100644 apps/st/src/components/statistics/verification/StatisticsVerificationReport.tsx create mode 100644 apps/st/src/entities/statistics/model/statistics-verification-report/statistics-verification-report-columns.ts create mode 100644 apps/st/src/entities/statistics/model/statistics-verification-report/statistics-verification-report-mock.ts create mode 100644 apps/st/src/entities/statistics/model/statistics-verification-report/statistics-verification-report-types.ts diff --git a/apps/st/src/components/statistics/verification/StatisticsVerificationReport.tsx b/apps/st/src/components/statistics/verification/StatisticsVerificationReport.tsx new file mode 100644 index 000000000..b9baaa018 --- /dev/null +++ b/apps/st/src/components/statistics/verification/StatisticsVerificationReport.tsx @@ -0,0 +1,361 @@ +"use client"; + +import { useEffect, useMemo, useState } from "react"; + +import { useAlertStore } from "@/shared/lib"; +import { + Button, + Label, + LoadingWithAnimation, + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@common/components"; + +import { + statisticsVerificationDetailColumnInfo, + statisticsVerificationSummaryColumnInfo, +} from "../../../entities/statistics/model/statistics-verification-report/statistics-verification-report-columns"; +import { + APPROVAL_STATUS_OPTIONS, + DEFAULT_FILTERS, + DEFAULT_SUB_FILTERS, + fetchStatisticsVerificationDetailMock, + fetchStatisticsVerificationSummaryMock, + getSigunguOptions, + getYearOptions, + SIDO_OPTIONS, + STATS_INDICATOR_OPTIONS, + STATUS_OPTIONS, +} from "../../../entities/statistics/model/statistics-verification-report/statistics-verification-report-mock"; +import type { + StatisticsVerificationDetailRow, + StatisticsVerificationFilterState, + StatisticsVerificationSubFilterState, + StatisticsVerificationSummaryRow, +} from "../../../entities/statistics/model/statistics-verification-report/statistics-verification-report-types"; + +import ApproveButton from "@/components/button/ApproveButton"; +import ReturnButton from "@/components/button/ReturnButton"; +import DataGrid from "@/components/module/DataGrid"; +import { toGridRows } from "@/components/util/grid/gridFunction"; + +function StatisticsVerificationReport() { + const { setMessage: alert } = useAlertStore((state) => state); + const yearOptions = useMemo(() => getYearOptions(), []); + const [filters, setFilters] = + useState(DEFAULT_FILTERS); + const [subFilters, setSubFilters] = + useState(DEFAULT_SUB_FILTERS); + const [summaryRows, setSummaryRows] = useState< + StatisticsVerificationSummaryRow[] + >([]); + const [detailRows, setDetailRows] = useState< + StatisticsVerificationDetailRow[] + >([]); + const [summaryGridRows, setSummaryGridRows] = useState< + Record[] + >([]); + const [detailGridRows, setDetailGridRows] = useState< + Record[] + >([]); + const [selectedSummaryRow, setSelectedSummaryRow] = + useState(null); + const [selectedDetailRow, setSelectedDetailRow] = + useState(null); + const [isLoading, setIsLoading] = useState(false); + + const sigunguOptions = useMemo( + () => getSigunguOptions(filters.sido), + [filters.sido], + ); + + useEffect(() => { + void handleSearch(filters, subFilters); + }, []); + + async function handleSearch( + nextFilters: StatisticsVerificationFilterState, + nextSubFilters: StatisticsVerificationSubFilterState, + summaryId?: number | null, + ) { + try { + setIsLoading(true); + const [summaryData, detailData] = await Promise.all([ + fetchStatisticsVerificationSummaryMock(nextFilters), + fetchStatisticsVerificationDetailMock( + nextFilters, + nextSubFilters, + summaryId, + ), + ]); + setSummaryRows(summaryData); + setDetailRows(detailData); + setSummaryGridRows(toGridRows(summaryData)); + setDetailGridRows(toGridRows(detailData)); + if (summaryData.length === 0) + alert("조회된 상단 목록 데이터가 없습니다."); + if (detailData.length === 0) + alert("조회된 상세 목록 데이터가 없습니다."); + } catch { + alert("통계검증리포트 조회 중 오류가 발생했습니다."); + } finally { + setIsLoading(false); + } + } + + function handleFilterChange< + K extends keyof StatisticsVerificationFilterState, + >(key: K, value: StatisticsVerificationFilterState[K]) { + if (key === "sido") { + setFilters((prev) => ({ ...prev, sido: value, sigungu: "ALL" })); + return; + } + setFilters((prev) => ({ ...prev, [key]: value })); + } + + function handleSubFilterChange< + K extends keyof StatisticsVerificationSubFilterState, + >(key: K, value: StatisticsVerificationSubFilterState[K]) { + setSubFilters((prev) => ({ ...prev, [key]: value })); + } + + function handleReset() { + setFilters(DEFAULT_FILTERS); + setSubFilters(DEFAULT_SUB_FILTERS); + setSelectedSummaryRow(null); + setSelectedDetailRow(null); + void handleSearch(DEFAULT_FILTERS, DEFAULT_SUB_FILTERS); + } + + function handleApprove() { + if (!selectedSummaryRow) { + alert("승인할 상단 목록 행을 먼저 선택해주세요."); + return; + } + alert( + `승인 API TBD: ${selectedSummaryRow.sido} ${selectedSummaryRow.sigungu} (${selectedSummaryRow.reportType})`, + ); + } + + function handleReject() { + if (!selectedDetailRow) { + alert("반려할 상세 항목 행을 먼저 선택해주세요."); + return; + } + alert( + `반려 API TBD: ${selectedDetailRow.sido} ${selectedDetailRow.sigungu} ${selectedDetailRow.detailItem}`, + ); + } + + function handleDownload() { + if (detailRows.length === 0) { + alert("다운로드할 상세 목록이 없습니다."); + return; + } + + const headers = [ + "시도", + "시군구", + "지표", + "세부항목", + "검증날짜", + "오류내역", + "입력값", + "비교값", + "상태", + "예외사유", + "반려의견", + "승인여부", + ]; + const rows = detailRows.map((row) => + [ + row.sido, + row.sigungu, + row.indicator, + row.detailItem, + row.verifyDate, + row.errorDetail, + String(row.inputValue), + String(row.compareValue), + row.status, + row.exceptionReason, + row.returnOpinion, + row.approvalYn, + ].join(","), + ); + const csv = [headers.join(","), ...rows].join("\n"); + const blob = new Blob([`\uFEFF${csv}`], { + type: "text/csv;charset=utf-8;", + }); + const url = URL.createObjectURL(blob); + const link = document.createElement("a"); + link.href = url; + link.download = "statistics-verification-report-detail.csv"; + link.click(); + URL.revokeObjectURL(url); + } + + function handleSummaryRowClick(row: Record) { + const summaryId = Number(row.summaryId); + const selected = summaryRows.find( + (item) => item.summaryId === summaryId, + ); + setSelectedSummaryRow(selected ?? null); + if (!summaryId) return; + void handleSearch(filters, subFilters, summaryId); + } + + function handleDetailRowClick(row: Record) { + const detailId = Number(row.detailId); + const selected = detailRows.find((item) => item.detailId === detailId); + setSelectedDetailRow(selected ?? null); + } + + return ( +
+
+
+ handleFilterChange("sido", value)} + options={SIDO_OPTIONS} + /> + + handleFilterChange("sigungu", value) + } + options={sigunguOptions} + /> + handleFilterChange("year", value)} + options={yearOptions} + /> + + handleFilterChange("statsIndicator", value) + } + options={STATS_INDICATOR_OPTIONS} + /> + +
+ + +
+
+
+ +
+
+ +
+
+ + + +
+
+
+ + handleSubFilterChange("status", value) + } + options={STATUS_OPTIONS} + /> + + handleSubFilterChange("approvalStatus", value) + } + options={APPROVAL_STATUS_OPTIONS} + /> +
+
+ + +
+
+
+ + + + {isLoading && ( +
+
+ +
+
+ )} +
+ ); +} + +interface FilterSelectProps { + label: string; + onChange: (value: string) => void; + options: Array<{ label: string; value: string }>; + value: string; +} + +function FilterSelect({ label, onChange, options, value }: FilterSelectProps) { + return ( +
+ + +
+ ); +} + +export { StatisticsVerificationReport }; +export default StatisticsVerificationReport; diff --git a/apps/st/src/entities/statistics/model/input/statistics-input-status-interface.ts b/apps/st/src/entities/statistics/model/input/statistics-input-status-interface.ts index ae721e462..ea6c281fe 100644 --- a/apps/st/src/entities/statistics/model/input/statistics-input-status-interface.ts +++ b/apps/st/src/entities/statistics/model/input/statistics-input-status-interface.ts @@ -6,6 +6,7 @@ export interface StatsInputStatusListRequestParams { sewerBzmnCd?: string; statsYr?: string; mode?: string; + statsCd?: string; } export interface StatsInputStatusList { @@ -25,10 +26,14 @@ export interface StatsInputStatusList { rjctOpnnCn?: string; } -export type StatsInputStatusListApiResponse = ApiResponse & { +export type StatsInputStatusListApiResponse = ApiResponse< + StatsInputStatusList[] +> & { message: string; -} +}; export interface StatisticsInputStatusService { - getStatisticsInputStatusList(param: StatsInputStatusListRequestParams): Promise; + getStatisticsInputStatusList( + param: StatsInputStatusListRequestParams, + ): Promise; } diff --git a/apps/st/src/entities/statistics/model/statistics-verification-report/statistics-verification-report-columns.ts b/apps/st/src/entities/statistics/model/statistics-verification-report/statistics-verification-report-columns.ts new file mode 100644 index 000000000..7ee24a013 --- /dev/null +++ b/apps/st/src/entities/statistics/model/statistics-verification-report/statistics-verification-report-columns.ts @@ -0,0 +1,71 @@ +import type { ColumnInfo } from "@/components/type/DataGrid.type"; + +const READ_ONLY_STYLE = "rg-cell-readonly"; + +export const statisticsVerificationSummaryColumnInfo: ColumnInfo = { + columns: [ + { name: "summaryId", fieldName: "summaryId", header: { text: "summaryId" }, visible: false }, + { name: "sido", fieldName: "sido", header: { text: "시도" }, styleName: READ_ONLY_STYLE }, + { name: "sigungu", fieldName: "sigungu", header: { text: "시군구" }, styleName: READ_ONLY_STYLE }, + { name: "reportType", fieldName: "reportType", header: { text: "구분" }, styleName: READ_ONLY_STYLE }, + { name: "progressStatus", fieldName: "progressStatus", header: { text: "진행상태" }, width: 120, styleName: READ_ONLY_STYLE }, + { name: "writerName", fieldName: "writerName", header: { text: "작성자" }, styleName: READ_ONLY_STYLE }, + { name: "writerContact", fieldName: "writerContact", header: { text: "작성자연락처" }, width: 130, styleName: READ_ONLY_STYLE }, + { name: "writerDept", fieldName: "writerDept", header: { text: "부서" }, styleName: READ_ONLY_STYLE }, + { name: "writerPosition", fieldName: "writerPosition", header: { text: "직급" }, styleName: READ_ONLY_STYLE }, + { name: "approverName", fieldName: "approverName", header: { text: "승인자" }, styleName: READ_ONLY_STYLE }, + { name: "approverDept", fieldName: "approverDept", header: { text: "부서" }, styleName: READ_ONLY_STYLE }, + { name: "approverPosition", fieldName: "approverPosition", header: { text: "직급" }, styleName: READ_ONLY_STYLE }, + { name: "returnReason", fieldName: "returnReason", header: { text: "반려사유" }, width: 220, styleName: READ_ONLY_STYLE }, + ], + columnLayout: [ + "summaryId", + "sido", + "sigungu", + "reportType", + "progressStatus", + "writerName", + "writerContact", + "writerDept", + "writerPosition", + "approverName", + "approverDept", + "approverPosition", + "returnReason", + ], +}; + +export const statisticsVerificationDetailColumnInfo: ColumnInfo = { + columns: [ + { name: "detailId", fieldName: "detailId", header: { text: "detailId" }, visible: false }, + { name: "summaryId", fieldName: "summaryId", header: { text: "summaryId" }, visible: false }, + { name: "sido", fieldName: "sido", header: { text: "시도" }, styleName: READ_ONLY_STYLE }, + { name: "sigungu", fieldName: "sigungu", header: { text: "시군구" }, styleName: READ_ONLY_STYLE }, + { name: "indicator", fieldName: "indicator", header: { text: "지표" }, width: 140, styleName: READ_ONLY_STYLE }, + { name: "detailItem", fieldName: "detailItem", header: { text: "세부항목" }, width: 180, styleName: READ_ONLY_STYLE }, + { name: "verifyDate", fieldName: "verifyDate", header: { text: "검증날짜" }, width: 110, styleName: READ_ONLY_STYLE }, + { name: "errorDetail", fieldName: "errorDetail", header: { text: "오류내역" }, width: 200, styleName: READ_ONLY_STYLE }, + { name: "inputValue", fieldName: "inputValue", header: { text: "입력값" }, width: 90, styleName: READ_ONLY_STYLE }, + { name: "compareValue", fieldName: "compareValue", header: { text: "비교값" }, width: 90, styleName: READ_ONLY_STYLE }, + { name: "status", fieldName: "status", header: { text: "상태" }, width: 90, styleName: READ_ONLY_STYLE }, + { name: "exceptionReason", fieldName: "exceptionReason", header: { text: "예외사유" }, width: 170, styleName: READ_ONLY_STYLE }, + { name: "returnOpinion", fieldName: "returnOpinion", header: { text: "반려의견" }, width: 170, styleName: READ_ONLY_STYLE }, + { name: "approvalYn", fieldName: "approvalYn", header: { text: "승인여부" }, width: 90, styleName: READ_ONLY_STYLE }, + ], + columnLayout: [ + "detailId", + "summaryId", + "sido", + "sigungu", + "indicator", + "detailItem", + "verifyDate", + "errorDetail", + "inputValue", + "compareValue", + "status", + "exceptionReason", + "returnOpinion", + "approvalYn", + ], +}; diff --git a/apps/st/src/entities/statistics/model/statistics-verification-report/statistics-verification-report-mock.ts b/apps/st/src/entities/statistics/model/statistics-verification-report/statistics-verification-report-mock.ts new file mode 100644 index 000000000..a56b16c49 --- /dev/null +++ b/apps/st/src/entities/statistics/model/statistics-verification-report/statistics-verification-report-mock.ts @@ -0,0 +1,288 @@ +import { fakerKO as faker } from "@faker-js/faker"; + +import type { + StatisticsVerificationDetailRow, + StatisticsVerificationFilterState, + StatisticsVerificationOption, + StatisticsVerificationSubFilterState, + StatisticsVerificationSummaryRow, +} from "./statistics-verification-report-types"; + +const NETWORK_DELAY_MS = 300; + +export const SIDO_OPTIONS: StatisticsVerificationOption[] = [ + { label: "전체", value: "ALL" }, + { label: "서울특별시", value: "SEOUL" }, + { label: "부산광역시", value: "BUSAN" }, + { label: "대구광역시", value: "DAEGU" }, + { label: "경기도", value: "GYEONGGI" }, +]; + +const SIGUNGU_OPTIONS_BY_SIDO: Record = + { + ALL: [{ label: "전체", value: "ALL" }], + SEOUL: [ + { label: "전체", value: "ALL" }, + { label: "중구", value: "SEOUL_JUNGGU" }, + { label: "강남구", value: "SEOUL_GANGNAM" }, + ], + BUSAN: [ + { label: "전체", value: "ALL" }, + { label: "해운대구", value: "BUSAN_HAEUNDAE" }, + { label: "수영구", value: "BUSAN_SUYEONG" }, + ], + DAEGU: [ + { label: "전체", value: "ALL" }, + { label: "중구", value: "DAEGU_JUNGGU" }, + { label: "달서구", value: "DAEGU_DALSEO" }, + ], + GYEONGGI: [ + { label: "전체", value: "ALL" }, + { label: "수원시", value: "GYEONGGI_SUWON" }, + { label: "성남시", value: "GYEONGGI_SEONGNAM" }, + ], + }; + +export const STATS_INDICATOR_OPTIONS: StatisticsVerificationOption[] = [ + { label: "통계항목", value: "ALL" }, + { label: "하수도 보급률", value: "SEWERAGE_SUPPLY" }, + { label: "관로 보급 현황", value: "PIPE_STATUS" }, + { label: "분류식 비율", value: "SEPARATED_RATIO" }, +]; + +export const STATUS_OPTIONS: StatisticsVerificationOption[] = [ + { label: "수정완료", value: "DONE" }, + { label: "검토중", value: "REVIEW" }, + { label: "오류", value: "ERROR" }, +]; + +export const APPROVAL_STATUS_OPTIONS: StatisticsVerificationOption[] = [ + { label: "전체", value: "ALL" }, + { label: "승인완료", value: "APPROVED" }, + { label: "반려", value: "REJECTED" }, + { label: "대기", value: "PENDING" }, +]; + +export const DEFAULT_FILTERS: StatisticsVerificationFilterState = { + sido: "ALL", + sigungu: "ALL", + year: "ALL", + statsIndicator: "ALL", +}; + +export const DEFAULT_SUB_FILTERS: StatisticsVerificationSubFilterState = { + status: "DONE", + approvalStatus: "ALL", +}; + +export function getYearOptions(): StatisticsVerificationOption[] { + const thisYear = new Date().getFullYear(); + return [ + { label: "전체", value: "ALL" }, + ...Array.from({ length: 5 }, (_, index) => { + const year = String(thisYear - index - 1); + return { label: year, value: year }; + }), + ]; +} + +export function getSigunguOptions( + sido: string, +): StatisticsVerificationOption[] { + return SIGUNGU_OPTIONS_BY_SIDO[sido] ?? []; +} + +export async function fetchStatisticsVerificationSummaryMock( + filters: StatisticsVerificationFilterState, +): Promise { + await wait(); + faker.seed(20260416); + + const rows = Array.from({ length: 12 }, (_, index) => { + const sido = pickSidoName(filters.sido); + const sigungu = pickSigunguName(filters.sido, filters.sigungu); + const progressStatus = faker.helpers.arrayElement([ + "승인대기", + "승인완료", + "반려", + ]); + return { + summaryId: index + 1, + sido, + sigungu, + reportType: faker.helpers.arrayElement([ + "정기보고", + "수정보고", + "보완보고", + ]), + progressStatus, + writerName: faker.person.lastName() + faker.person.firstName(), + writerContact: faker.phone.number({ style: "national" }), + writerDept: faker.helpers.arrayElement([ + "통계팀", + "하수행정과", + "정책기획과", + ]), + writerPosition: faker.helpers.arrayElement([ + "주무관", + "팀장", + "과장", + ]), + approverName: + progressStatus === "승인대기" + ? "-" + : faker.person.lastName() + faker.person.firstName(), + approverDept: + progressStatus === "승인대기" + ? "-" + : faker.helpers.arrayElement(["검증운영팀", "하수행정과"]), + approverPosition: + progressStatus === "승인대기" + ? "-" + : faker.helpers.arrayElement(["팀장", "과장"]), + returnReason: + progressStatus === "반려" + ? faker.helpers.arrayElement([ + "오류내역 확인 필요", + "예외사유 보강 필요", + "입력값 검증 재요청", + ]) + : "-", + }; + }); + + return rows.filter((row) => { + if (filters.sido !== "ALL" && row.sido !== pickSidoName(filters.sido)) + return false; + if (filters.sigungu !== "ALL") { + const currentSigungu = pickSigunguName( + filters.sido, + filters.sigungu, + ); + if (row.sigungu !== currentSigungu) return false; + } + return true; + }); +} + +export async function fetchStatisticsVerificationDetailMock( + filters: StatisticsVerificationFilterState, + subFilters: StatisticsVerificationSubFilterState, + selectedSummaryId?: number | null, +): Promise { + await wait(); + faker.seed(20260417); + + const rows = Array.from({ length: 24 }, (_, index) => { + const approvalYn = faker.helpers.arrayElement(["승인", "미승인"]); + const status = faker.helpers.arrayElement([ + "수정완료", + "검토중", + "오류", + ]); + const summaryId = faker.number.int({ min: 1, max: 12 }); + return { + detailId: index + 1, + summaryId, + sido: pickSidoName(filters.sido), + sigungu: pickSigunguName(filters.sido, filters.sigungu), + indicator: pickIndicator(filters.statsIndicator), + detailItem: faker.helpers.arrayElement([ + "처리구역면적", + "처리인구", + "분류식관거연장", + "하수관로보급률", + ]), + verifyDate: faker.date + .recent({ days: 20 }) + .toISOString() + .slice(0, 10), + errorDetail: faker.helpers.arrayElement([ + "전년 대비 편차 초과", + "입력값 누락", + "상호검증 불일치", + ]), + inputValue: faker.number.int({ min: 100, max: 5000 }), + compareValue: faker.number.int({ min: 100, max: 5000 }), + status, + exceptionReason: + status === "오류" + ? faker.lorem.sentence({ min: 1, max: 2 }) + : "-", + returnOpinion: + approvalYn === "미승인" + ? faker.helpers.arrayElement([ + "산식 재검토 필요", + "근거자료 보강 요청", + "담당자 확인 필요", + ]) + : "-", + approvalYn, + }; + }); + + return rows.filter((row) => { + if (selectedSummaryId && row.summaryId !== selectedSummaryId) + return false; + if (subFilters.status === "DONE" && row.status !== "수정완료") + return false; + if (subFilters.status === "REVIEW" && row.status !== "검토중") + return false; + if (subFilters.status === "ERROR" && row.status !== "오류") + return false; + if ( + subFilters.approvalStatus === "APPROVED" && + row.approvalYn !== "승인" + ) + return false; + if ( + subFilters.approvalStatus === "REJECTED" && + row.approvalYn !== "미승인" + ) + return false; + return true; + }); +} + +function wait() { + return new Promise((resolve) => setTimeout(resolve, NETWORK_DELAY_MS)); +} + +function pickSidoName(value: string): string { + if (value === "ALL") + return faker.helpers.arrayElement([ + "서울특별시", + "부산광역시", + "대구광역시", + "경기도", + ]); + + const matched = SIDO_OPTIONS.find((option) => option.value === value); + return matched?.label ?? "서울특별시"; +} + +function pickSigunguName(sido: string, sigungu: string): string { + if (sigungu !== "ALL") { + const options = getSigunguOptions(sido); + const matched = options.find((option) => option.value === sigungu); + if (matched) return matched.label; + } + + const options = getSigunguOptions(sido).filter( + (option) => option.value !== "ALL", + ); + if (options.length === 0) return "전체"; + return faker.helpers.arrayElement(options).label; +} + +function pickIndicator(indicator: string): string { + if (indicator === "ALL") + return faker.helpers.arrayElement( + STATS_INDICATOR_OPTIONS.filter((item) => item.value !== "ALL"), + ).label; + + const matched = STATS_INDICATOR_OPTIONS.find( + (option) => option.value === indicator, + ); + return matched?.label ?? "통계항목"; +} diff --git a/apps/st/src/entities/statistics/model/statistics-verification-report/statistics-verification-report-types.ts b/apps/st/src/entities/statistics/model/statistics-verification-report/statistics-verification-report-types.ts new file mode 100644 index 000000000..2cbcd04d9 --- /dev/null +++ b/apps/st/src/entities/statistics/model/statistics-verification-report/statistics-verification-report-types.ts @@ -0,0 +1,49 @@ +export interface StatisticsVerificationFilterState { + sido: string; + sigungu: string; + year: string; + statsIndicator: string; +} + +export interface StatisticsVerificationSubFilterState { + status: string; + approvalStatus: string; +} + +export interface StatisticsVerificationOption { + label: string; + value: string; +} + +export interface StatisticsVerificationSummaryRow { + summaryId: number; + sido: string; + sigungu: string; + reportType: string; + progressStatus: string; + writerName: string; + writerContact: string; + writerDept: string; + writerPosition: string; + approverName: string; + approverDept: string; + approverPosition: string; + returnReason: string; +} + +export interface StatisticsVerificationDetailRow { + detailId: number; + summaryId: number; + sido: string; + sigungu: string; + indicator: string; + detailItem: string; + verifyDate: string; + errorDetail: string; + inputValue: number; + compareValue: number; + status: string; + exceptionReason: string; + returnOpinion: string; + approvalYn: string; +} diff --git a/apps/st/src/shared/config/env.ts b/apps/st/src/shared/config/env.ts index 634bb7f15..6d1646631 100644 --- a/apps/st/src/shared/config/env.ts +++ b/apps/st/src/shared/config/env.ts @@ -13,4 +13,4 @@ export const REFRESH_TOKEN = export const AUTH_USER_ID = process.env.NEXT_PUBLIC_AUTH_USER_ID || "token-id"; export const ST_SERVICE_URL = process.env.NEXT_PUBLIC_ST_SERVICE_URL || "http://localhost:8080"; -export const COOKIE_DOMAIN = process.env.NEXT_PUBLIC_COOKIE_DOMAIN; \ No newline at end of file +export const COOKIE_DOMAIN = process.env.NEXT_PUBLIC_COOKIE_DOMAIN;