diff --git a/apps/as/app/(with-base-layout)/instl-sncn-old/[id]/modify/page.tsx b/apps/as/app/(with-base-layout)/instl-sncn-old/[id]/modify/page.tsx new file mode 100644 index 000000000..baf4de7af --- /dev/null +++ b/apps/as/app/(with-base-layout)/instl-sncn-old/[id]/modify/page.tsx @@ -0,0 +1,6 @@ +import { CnfmModifyPage } from "@/pages/instl-sncn-old"; + +export default async function InstlSncnModifyPage({ params }: { params: Promise<{ id: string }> }) { + const { id } = await params; + return ; +} diff --git a/apps/as/app/(with-base-layout)/instl-sncn-old/[id]/page.tsx b/apps/as/app/(with-base-layout)/instl-sncn-old/[id]/page.tsx new file mode 100644 index 000000000..92769d3ef --- /dev/null +++ b/apps/as/app/(with-base-layout)/instl-sncn-old/[id]/page.tsx @@ -0,0 +1,6 @@ +import { CnfmViewPage } from "@/pages/instl-sncn-old"; + +export default async function InstlSncnViewPage({ params }: { params: Promise<{ id: string }> }) { + const { id } = await params; + return ; +} diff --git a/apps/as/app/(with-base-layout)/instl-sncn-old/page.tsx b/apps/as/app/(with-base-layout)/instl-sncn-old/page.tsx new file mode 100644 index 000000000..6c1e37f16 --- /dev/null +++ b/apps/as/app/(with-base-layout)/instl-sncn-old/page.tsx @@ -0,0 +1,3 @@ +import { CnfmListPage } from "@/pages/instl-sncn-old"; + +export default CnfmListPage; diff --git a/apps/as/app/(with-base-layout)/instl-sncn-old/register/page.tsx b/apps/as/app/(with-base-layout)/instl-sncn-old/register/page.tsx new file mode 100644 index 000000000..82a838f8a --- /dev/null +++ b/apps/as/app/(with-base-layout)/instl-sncn-old/register/page.tsx @@ -0,0 +1,5 @@ +import { CnfmRegistPage } from "@/pages/instl-sncn-old"; + +export default function Page(props: any) { + return ; +} diff --git a/apps/as/app/(with-base-layout)/instl-sncn/[id]/edit/page.tsx b/apps/as/app/(with-base-layout)/instl-sncn/[id]/edit/page.tsx new file mode 100644 index 000000000..35d336bd3 --- /dev/null +++ b/apps/as/app/(with-base-layout)/instl-sncn/[id]/edit/page.tsx @@ -0,0 +1,10 @@ +import { InstlEditPage } from "@/pages/instl-sncn"; + +interface InstlSncnEditRouteProps { + params: Promise<{ id: string }>; +} + +export default async function Page({ params }: InstlSncnEditRouteProps) { + const { id } = await params; + return ; +} diff --git a/apps/as/app/(with-base-layout)/instl-sncn/[id]/modify/page.tsx b/apps/as/app/(with-base-layout)/instl-sncn/[id]/modify/page.tsx deleted file mode 100644 index e4718eceb..000000000 --- a/apps/as/app/(with-base-layout)/instl-sncn/[id]/modify/page.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { CnfmModifyPage } from "@/pages/instl-sncn"; - -export default async function InstlSncnModifyPage({ - params, -}: { - params: Promise<{ id: string }>; -}) { - const { id } = await params; - return ; -} diff --git a/apps/as/app/(with-base-layout)/instl-sncn/[id]/page.tsx b/apps/as/app/(with-base-layout)/instl-sncn/[id]/page.tsx index 3f25c4a3e..89cd7a329 100644 --- a/apps/as/app/(with-base-layout)/instl-sncn/[id]/page.tsx +++ b/apps/as/app/(with-base-layout)/instl-sncn/[id]/page.tsx @@ -1,10 +1,6 @@ -import { CnfmViewPage } from "@/pages/instl-sncn"; - -export default async function InstlSncnViewPage({ - params, -}: { - params: Promise<{ id: string }>; -}) { - const { id } = await params; - return ; -} +import { InstlViewPage } from "@/pages/instl-sncn"; + +export default async function InstlSncnDetailPage({ params }: { params: Promise<{ id: string }> }) { + const { id } = await params; + return ; +} diff --git a/apps/as/app/(with-base-layout)/instl-sncn/page.tsx b/apps/as/app/(with-base-layout)/instl-sncn/page.tsx index 7cd7bf82e..a3d6e05ac 100644 --- a/apps/as/app/(with-base-layout)/instl-sncn/page.tsx +++ b/apps/as/app/(with-base-layout)/instl-sncn/page.tsx @@ -1,3 +1,3 @@ -import { CnfmListPage } from "@/pages/instl-sncn"; - -export default CnfmListPage; +import { InstlListPage } from "@/pages/instl-sncn"; + +export default InstlListPage; diff --git a/apps/as/app/(with-base-layout)/instl-sncn/regist/page.tsx b/apps/as/app/(with-base-layout)/instl-sncn/regist/page.tsx new file mode 100644 index 000000000..b19f7abb6 --- /dev/null +++ b/apps/as/app/(with-base-layout)/instl-sncn/regist/page.tsx @@ -0,0 +1,3 @@ +import { InstlRegistPage } from "@/pages/instl-sncn"; + +export default InstlRegistPage; diff --git a/apps/as/app/(with-base-layout)/instl-sncn/register/page.tsx b/apps/as/app/(with-base-layout)/instl-sncn/register/page.tsx deleted file mode 100644 index ffe6a71a4..000000000 --- a/apps/as/app/(with-base-layout)/instl-sncn/register/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { CnfmRegistPage } from "@/pages/instl-sncn"; - -export default function Page(props: any) { - return ; -} diff --git a/apps/as/package.json b/apps/as/package.json index 5122cbbb5..ea9e0545a 100644 --- a/apps/as/package.json +++ b/apps/as/package.json @@ -24,6 +24,7 @@ "@tanstack/react-query-devtools": "^5.75.5", "@tanstack/react-table": "^8.21.2", "axios": "^1.8.1", + "class-variance-authority": "^0.7.1", "dayjs": "^1.11.13", "js-cookie": "^3.0.5", "lucide-react": "^0.474.0", diff --git a/apps/as/src/entities/acntg/api/acntg-service.ts b/apps/as/src/entities/acntg/api/acntg-service.ts index 957113dec..fd620009e 100644 --- a/apps/as/src/entities/acntg/api/acntg-service.ts +++ b/apps/as/src/entities/acntg/api/acntg-service.ts @@ -12,7 +12,7 @@ import { type AcntgSeMngTreeDto, } from "../model/acntg-interface"; -const BASE = ENDPOINT.AS_COMMON_SERVICE.ACNTG_SE; +const BASE = ENDPOINT.AS_SERVICE.ACNTG_SE; async function findAll(params: AcntgSeMngSearchDto): Promise> { const response = await client.get>(BASE, { params }); diff --git a/apps/as/src/entities/acntg/api/queries.ts b/apps/as/src/entities/acntg/api/queries.ts index c2bcc7f9f..db00d2317 100644 --- a/apps/as/src/entities/acntg/api/queries.ts +++ b/apps/as/src/entities/acntg/api/queries.ts @@ -10,7 +10,7 @@ import type { import { acntgSeMngService } from "./acntg-service"; -const acntgSeMngBaseKey = [ENDPOINT.AS_COMMON_SERVICE.ACNTG_SE] as const; +const acntgSeMngBaseKey = [ENDPOINT.AS_SERVICE.ACNTG_SE] as const; export function useAcntgSeMngPage(params: AcntgSeMngSearchDto) { return useQuery({ diff --git a/apps/as/src/entities/adstdstr/api/adstdstr-service.ts b/apps/as/src/entities/adstdstr/api/adstdstr-service.ts new file mode 100644 index 000000000..b4bb11fae --- /dev/null +++ b/apps/as/src/entities/adstdstr/api/adstdstr-service.ts @@ -0,0 +1,26 @@ +import { client } from "@/shared/api"; +import { ENDPOINT } from "@/shared/config"; + +import type { + CmCdAdstDstrComboResponseDto, + CmCdAdstDstrService, +} from "../model/adstdstr-interface"; + +const BASE = ENDPOINT.AS_SERVICE.ADSTDSTR; + +async function findSidoCombo(): Promise { + const response = await client.get(`${BASE}/sido`); + return response.data; +} + +async function findGugunCombo(sido: string): Promise { + const response = await client.get(`${BASE}/gugun`, { + params: { sido }, + }); + return response.data; +} + +export const cmCdAdstDstrService = { + findSidoCombo, + findGugunCombo, +} satisfies CmCdAdstDstrService; diff --git a/apps/as/src/entities/adstdstr/api/queries.ts b/apps/as/src/entities/adstdstr/api/queries.ts new file mode 100644 index 000000000..353e25cfe --- /dev/null +++ b/apps/as/src/entities/adstdstr/api/queries.ts @@ -0,0 +1,22 @@ +import { useQuery } from "@tanstack/react-query"; + +import { ENDPOINT } from "@/shared/config"; + +import { cmCdAdstDstrService } from "./adstdstr-service"; + +const cmCdAdstDstrBaseKey = [ENDPOINT.AS_SERVICE.ADSTDSTR] as const; + +export function useFindSidoCombo() { + return useQuery({ + queryKey: [...cmCdAdstDstrBaseKey, "findSidoCombo"], + queryFn: () => cmCdAdstDstrService.findSidoCombo(), + }); +} + +export function useFindGugunCombo(sido: string) { + return useQuery({ + queryKey: [...cmCdAdstDstrBaseKey, "findGugunCombo", sido], + queryFn: () => cmCdAdstDstrService.findGugunCombo(sido), + enabled: Boolean(sido), + }); +} diff --git a/apps/as/src/entities/adstdstr/index.ts b/apps/as/src/entities/adstdstr/index.ts new file mode 100644 index 000000000..da1dbd132 --- /dev/null +++ b/apps/as/src/entities/adstdstr/index.ts @@ -0,0 +1,6 @@ +export { cmCdAdstDstrService } from "./api/adstdstr-service"; +export { useFindGugunCombo, useFindSidoCombo } from "./api/queries"; +export type { + CmCdAdstDstrComboResponseDto, + CmCdAdstDstrService, +} from "./model/adstdstr-interface"; diff --git a/apps/as/src/entities/adstdstr/model/adstdstr-interface.ts b/apps/as/src/entities/adstdstr/model/adstdstr-interface.ts new file mode 100644 index 000000000..72cb673dc --- /dev/null +++ b/apps/as/src/entities/adstdstr/model/adstdstr-interface.ts @@ -0,0 +1,11 @@ +/** 백엔드 CmCdAdstDstrComboResponseDto */ +export interface CmCdAdstDstrComboResponseDto { + adstDstrCd: string; + adstDstrNm: string; +} + +/** Controller public 메서드명·시그니처와 동일 */ +export interface CmCdAdstDstrService { + findSidoCombo(): Promise; + findGugunCombo(sido: string): Promise; +} diff --git a/apps/as/src/entities/bns-if/api/bns-if-service.ts b/apps/as/src/entities/bns-if/api/bns-if-service.ts new file mode 100644 index 000000000..320a01efc --- /dev/null +++ b/apps/as/src/entities/bns-if/api/bns-if-service.ts @@ -0,0 +1,47 @@ +import { client } from "@/shared/api"; +import { ENDPOINT } from "@/shared/config"; + +import { buildBnsSearchDto } from "../lib/build-bns-search-dto"; +import type { + BnsDetailResponseWrapperDto, + BnsIfService, + BnsListResponseWrapperDto, + BnsSearchDto, + EmCodeListResponseDto, +} from "../model/bns-if-interface"; + +const BASE = ENDPOINT.AS_SERVICE.BNS_IF; + +async function getBnsList(params: BnsSearchDto): Promise { + const response = await client.get(`${BASE}/bns`, { + params: buildBnsSearchDto(params), + }); + return response.data; +} + +async function getBnsDetail( + gbn: string, + yr: string, + seqNo: string, +): Promise { + const response = await client.get(`${BASE}/bns/detail`, { + params: { gbn, yr, seqNo }, + }); + return response.data; +} + +async function getEmCodeList( + dpmCd?: string, + lclgvrnmntCd?: string, +): Promise { + const response = await client.get(`${BASE}/emCodeList`, { + params: { dpmCd, lclgvrnmntCd }, + }); + return response.data; +} + +export const bnsIfService = { + getBnsList, + getBnsDetail, + getEmCodeList, +} satisfies BnsIfService; diff --git a/apps/as/src/entities/bns-if/api/queries.ts b/apps/as/src/entities/bns-if/api/queries.ts new file mode 100644 index 000000000..7ab0b46a3 --- /dev/null +++ b/apps/as/src/entities/bns-if/api/queries.ts @@ -0,0 +1,33 @@ +import { keepPreviousData, useQuery } from "@tanstack/react-query"; + +import { ENDPOINT } from "@/shared/config"; + +import type { BnsSearchDto } from "../model/bns-if-interface"; + +import { bnsIfService } from "./bns-if-service"; + +const bnsIfBaseKey = [ENDPOINT.AS_SERVICE.BNS_IF] as const; + +export function useBnsList(params: BnsSearchDto, options?: { enabled?: boolean }) { + return useQuery({ + queryKey: [...bnsIfBaseKey, "getBnsList", params], + queryFn: () => bnsIfService.getBnsList(params), + enabled: options?.enabled, + placeholderData: keepPreviousData, + }); +} + +export function useBnsDetail(gbn: string, yr: string, seqNo: string) { + return useQuery({ + queryKey: [...bnsIfBaseKey, "getBnsDetail", gbn, yr, seqNo], + queryFn: () => bnsIfService.getBnsDetail(gbn, yr, seqNo), + enabled: Boolean(gbn && yr && seqNo), + }); +} + +export function useEmCodeList(dpmCd?: string, lclgvrnmntCd?: string) { + return useQuery({ + queryKey: [...bnsIfBaseKey, "getEmCodeList", dpmCd, lclgvrnmntCd], + queryFn: () => bnsIfService.getEmCodeList(dpmCd, lclgvrnmntCd), + }); +} diff --git a/apps/as/src/entities/bns-if/index.ts b/apps/as/src/entities/bns-if/index.ts new file mode 100644 index 000000000..430f4a611 --- /dev/null +++ b/apps/as/src/entities/bns-if/index.ts @@ -0,0 +1,13 @@ +export { bnsIfService } from "./api/bns-if-service"; +export { useBnsDetail, useBnsList, useEmCodeList } from "./api/queries"; +export { buildBnsSearchDto } from "./lib/build-bns-search-dto"; +export type { + BnsDetailResponseDto, + BnsDetailResponseWrapperDto, + BnsIfService, + BnsListResponseDto, + BnsListResponseWrapperDto, + BnsSearchDto, + EmCodeItemDto, + EmCodeListResponseDto, +} from "./model/bns-if-interface"; diff --git a/apps/as/src/entities/bns-if/lib/build-bns-search-dto.ts b/apps/as/src/entities/bns-if/lib/build-bns-search-dto.ts new file mode 100644 index 000000000..8e95b27dd --- /dev/null +++ b/apps/as/src/entities/bns-if/lib/build-bns-search-dto.ts @@ -0,0 +1,20 @@ +import type { BnsSearchDto } from "../model/bns-if-interface"; + +export function buildBnsSearchDto(input: { + cPage: number; + searchStartYear?: string; + searchSido?: string; + searchGugun?: string; +}): BnsSearchDto { + const dto: BnsSearchDto = { cPage: input.cPage }; + + const year = input.searchStartYear?.trim(); + const sido = input.searchSido?.trim(); + const gugun = input.searchGugun?.trim(); + + if (year) dto.searchStartYear = year; + if (sido) dto.searchSido = sido; + if (gugun) dto.searchGugun = gugun; + + return dto; +} diff --git a/apps/as/src/entities/bns-if/model/bns-if-interface.ts b/apps/as/src/entities/bns-if/model/bns-if-interface.ts new file mode 100644 index 000000000..e13ab8500 --- /dev/null +++ b/apps/as/src/entities/bns-if/model/bns-if-interface.ts @@ -0,0 +1,125 @@ +/** 백엔드 BnsSearchDto */ +export interface BnsSearchDto { + searchStartYear?: string; + cPage: number; + searchSido?: string; + searchGugun?: string; +} + +/** 백엔드 BnsListResponseWrapperDto */ +export interface BnsListResponseWrapperDto { + list: BnsListResponseDto[]; + cnt: number; +} + +/** 백엔드 BnsListResponseDto */ +export interface BnsListResponseDto { + cPage: number; + gbn: number; + chk: number; + seqNo: string; + rgnNm: string; + sido: string; + gugun: string; + bzCd: string; + bzNm: string; + yr: string; + strtYr: string; + edYr: string; + totBzamt: string; +} + +/** 백엔드 BnsDetailResponseWrapperDto */ +export interface BnsDetailResponseWrapperDto { + saup: unknown; + detail: BnsDetailResponseDto; +} + +/** 백엔드 BnsDetailResponseDto */ +export interface BnsDetailResponseDto { + cPage: number; + seqNo: string; + confBzCd: string; + chngDgr: string; + yr: string; + sido: string; + gugun: string; + rvbsnNm: string; + lgbsnNm: string; + mdmbsnNm: string; + lclgvrnmntNm: string; + accKdNm: string; + bzKdNm: string; + untBzNm: string; + dtlBzNm: string; + mevBzNm: string; + ddtlBzNm: string; + strtYr: string; + edYr: string; + aidRt: string; + bzStatus: string; + bzCd: string; + bzNm: string; + bzLoc: string; + efflWqltStndrdNm: string; + goalYear: string; + bssProm: string; + uppPlan: string; + techInsp: string; + bssCont: string; + rmk: string; + inflBscFctNm: string; + inflBscFctCd: string; + trtMtd: string; + swrExtns: string; + swrChng: string; + swrRnvt: string; + totFamNum: string; + pumpCnt: string; + rvWbsn: string; + rvText: string; + imprvExpctFlw: string; + imprvExpctWqlt: string; + trtplntPlEfflWqlt: string; + wqltAvg: string; + wqltHgh: string; + wqltLow: string; + stdCost: string; + bzEtc: string; + bscFctCd: string; + bscFctNm: string; + fctCpc: string; + fctCpcAfr: string; + trtDstrArea: string; + trtDstrAreaAfr: string; + swrTrtPopl: string; + swrTrtPoplAfr: string; + adstPopl: string; +} + +/** 백엔드 EmCodeItemDto */ +export interface EmCodeItemDto { + code: string; + data: string; + upCode: string; +} + +/** 백엔드 EmCodeListResponseDto */ +export interface EmCodeListResponseDto { + rvbsnList: EmCodeItemDto[]; + lgbsnList: EmCodeItemDto[]; + mdmbsnList: EmCodeItemDto[]; + accList: EmCodeItemDto[]; + bzList: EmCodeItemDto[]; + untList: EmCodeItemDto[]; + dtlList: EmCodeItemDto[]; + mevList: EmCodeItemDto[]; + ddtlList: EmCodeItemDto[]; +} + +/** Controller public 메서드명·시그니처와 동일 */ +export interface BnsIfService { + getBnsList(params: BnsSearchDto): Promise; + getBnsDetail(gbn: string, yr: string, seqNo: string): Promise; + getEmCodeList(dpmCd?: string, lclgvrnmntCd?: string): Promise; +} diff --git a/apps/as/src/entities/cklst/api/cklst-artcl-service.ts b/apps/as/src/entities/cklst/api/cklst-artcl-service.ts index dda8defd5..9561a659c 100644 --- a/apps/as/src/entities/cklst/api/cklst-artcl-service.ts +++ b/apps/as/src/entities/cklst/api/cklst-artcl-service.ts @@ -11,33 +11,25 @@ import type { CklstArtclUpdateRequest, } from "../model/cklst-artcl-interface"; +const BASE = ENDPOINT.AS_SERVICE.CKLST_ARTCL; + async function findPage(params: CklstArtclSearchParams): Promise> { - const response = await client.get>( - ENDPOINT.AS_CHECKLIST_SERVICE.CKLST_ARTCL, - { params }, - ); + const response = await client.get>(BASE, { params }); return response.data; } async function findByCklstSn(cklstSn: number): Promise { - const response = await client.get( - `${ENDPOINT.AS_CHECKLIST_SERVICE.CKLST_ARTCL}/by-cklst/${cklstSn}`, - ); + const response = await client.get(`${BASE}/by-cklst/${cklstSn}`); return response.data; } async function findById(cklstArtclSn: number, cklstSn: number): Promise { - const response = await client.get( - `${ENDPOINT.AS_CHECKLIST_SERVICE.CKLST_ARTCL}/${cklstArtclSn}/${cklstSn}`, - ); + const response = await client.get(`${BASE}/${cklstArtclSn}/${cklstSn}`); return response.data; } async function create(body: CklstArtclSaveRequest): Promise { - const response = await client.post( - ENDPOINT.AS_CHECKLIST_SERVICE.CKLST_ARTCL, - body, - ); + const response = await client.post(BASE, body); return response.data; } @@ -46,17 +38,12 @@ async function update( cklstSn: number, body: CklstArtclUpdateRequest, ): Promise { - const response = await client.put( - `${ENDPOINT.AS_CHECKLIST_SERVICE.CKLST_ARTCL}/${cklstArtclSn}/${cklstSn}`, - body, - ); + const response = await client.put(`${BASE}/${cklstArtclSn}/${cklstSn}`, body); return response.data; } async function remove(cklstArtclSn: number, cklstSn: number): Promise { - const response = await client.delete( - `${ENDPOINT.AS_CHECKLIST_SERVICE.CKLST_ARTCL}/${cklstArtclSn}/${cklstSn}`, - ); + const response = await client.delete(`${BASE}/${cklstArtclSn}/${cklstSn}`); return response.data; } diff --git a/apps/as/src/entities/cklst/api/cklst-mng-service.ts b/apps/as/src/entities/cklst/api/cklst-mng-service.ts index fdae4e8ff..8ad2e0556 100644 --- a/apps/as/src/entities/cklst/api/cklst-mng-service.ts +++ b/apps/as/src/entities/cklst/api/cklst-mng-service.ts @@ -11,40 +11,39 @@ import type { CklstTreeSearchParams, } from "../model/cklst-mng-interface"; +const BASE = ENDPOINT.AS_SERVICE.CKLST; + async function findPage(params: CklstMngSearchParams): Promise> { - const response = await client.get>(ENDPOINT.AS_CHECKLIST_SERVICE.CKLST, { + const response = await client.get>(BASE, { params, }); return response.data; } async function findById(cklstSn: number): Promise { - const response = await client.get(`${ENDPOINT.AS_CHECKLIST_SERVICE.CKLST}/${cklstSn}`); + const response = await client.get(`${BASE}/${cklstSn}`); return response.data; } async function findTree(params: CklstTreeSearchParams): Promise { - const response = await client.get(`${ENDPOINT.AS_CHECKLIST_SERVICE.CKLST}/list/tree`, { + const response = await client.get(`${BASE}/list/tree`, { params, }); return response.data; } async function create(body: CklstMngSaveRequest): Promise { - const response = await client.post(ENDPOINT.AS_CHECKLIST_SERVICE.CKLST, body); + const response = await client.post(BASE, body); return response.data; } async function update(cklstSn: number, body: CklstMngSaveRequest): Promise { - const response = await client.put( - `${ENDPOINT.AS_CHECKLIST_SERVICE.CKLST}/${cklstSn}`, - body, - ); + const response = await client.put(`${BASE}/${cklstSn}`, body); return response.data; } async function remove(cklstSn: number): Promise { - const response = await client.delete(`${ENDPOINT.AS_CHECKLIST_SERVICE.CKLST}/${cklstSn}`); + const response = await client.delete(`${BASE}/${cklstSn}`); return response.data; } diff --git a/apps/as/src/entities/cklst/api/cklst-rvw-service.ts b/apps/as/src/entities/cklst/api/cklst-rvw-service.ts index 0039bfbc1..e184d45aa 100644 --- a/apps/as/src/entities/cklst/api/cklst-rvw-service.ts +++ b/apps/as/src/entities/cklst/api/cklst-rvw-service.ts @@ -11,18 +11,15 @@ import type { CklstRvwUpdateRequest, } from "../model/cklst-rvw-interface"; +const BASE = ENDPOINT.AS_SERVICE.CKLST_RVW; + async function findPage(params: CklstRvwSearchParams): Promise> { - const response = await client.get>( - ENDPOINT.AS_CHECKLIST_SERVICE.CKLST_RVW, - { params }, - ); + const response = await client.get>(BASE, { params }); return response.data; } async function findByArtcl(cklstSn: number, cklstArtclSn: number): Promise { - const response = await client.get( - `${ENDPOINT.AS_CHECKLIST_SERVICE.CKLST_RVW}/by-artcl/${cklstSn}/${cklstArtclSn}`, - ); + const response = await client.get(`${BASE}/by-artcl/${cklstSn}/${cklstArtclSn}`); return response.data; } @@ -31,17 +28,12 @@ async function findById( cklstArtclSn: number, cklstSn: number, ): Promise { - const response = await client.get( - `${ENDPOINT.AS_CHECKLIST_SERVICE.CKLST_RVW}/${cklstRvwSn}/${cklstArtclSn}/${cklstSn}`, - ); + const response = await client.get(`${BASE}/${cklstRvwSn}/${cklstArtclSn}/${cklstSn}`); return response.data; } async function create(body: CklstRvwSaveRequest): Promise { - const response = await client.post( - ENDPOINT.AS_CHECKLIST_SERVICE.CKLST_RVW, - body, - ); + const response = await client.post(BASE, body); return response.data; } @@ -52,7 +44,7 @@ async function update( body: CklstRvwUpdateRequest, ): Promise { const response = await client.put( - `${ENDPOINT.AS_CHECKLIST_SERVICE.CKLST_RVW}/${cklstRvwSn}/${cklstArtclSn}/${cklstSn}`, + `${BASE}/${cklstRvwSn}/${cklstArtclSn}/${cklstSn}`, body, ); return response.data; @@ -64,7 +56,7 @@ async function remove( cklstSn: number, ): Promise { const response = await client.delete( - `${ENDPOINT.AS_CHECKLIST_SERVICE.CKLST_RVW}/${cklstRvwSn}/${cklstArtclSn}/${cklstSn}`, + `${BASE}/${cklstRvwSn}/${cklstArtclSn}/${cklstSn}`, ); return response.data; } diff --git a/apps/as/src/entities/cklst/api/queries.ts b/apps/as/src/entities/cklst/api/queries.ts index 33280c41a..afa3e02e3 100644 --- a/apps/as/src/entities/cklst/api/queries.ts +++ b/apps/as/src/entities/cklst/api/queries.ts @@ -18,9 +18,9 @@ import { cklstArtclService } from "./cklst-artcl-service"; import { cklstMngService } from "./cklst-mng-service"; import { cklstRvwService } from "./cklst-rvw-service"; -const cklstMngBaseKey = [ENDPOINT.AS_CHECKLIST_SERVICE.CKLST] as const; -const cklstArtclBaseKey = [ENDPOINT.AS_CHECKLIST_SERVICE.CKLST_ARTCL] as const; -const cklstRvwBaseKey = [ENDPOINT.AS_CHECKLIST_SERVICE.CKLST_RVW] as const; +const cklstMngBaseKey = [ENDPOINT.AS_SERVICE.CKLST] as const; +const cklstArtclBaseKey = [ENDPOINT.AS_SERVICE.CKLST_ARTCL] as const; +const cklstRvwBaseKey = [ENDPOINT.AS_SERVICE.CKLST_RVW] as const; export function useCklstMngPage(params: CklstMngSearchParams) { return useQuery({ diff --git a/apps/as/src/entities/cnstp/api/cnstp-service.ts b/apps/as/src/entities/cnstp/api/cnstp-service.ts index f39be006a..292ac7069 100644 --- a/apps/as/src/entities/cnstp/api/cnstp-service.ts +++ b/apps/as/src/entities/cnstp/api/cnstp-service.ts @@ -12,7 +12,7 @@ import { type CnstpSeMngTreeDto, } from "../model/cnstp-interface"; -const BASE = ENDPOINT.AS_COMMON_SERVICE.CNSTP_SE; +const BASE = ENDPOINT.AS_SERVICE.CNSTP_SE; async function findAll(params: CnstpSeMngSearchDto): Promise> { const response = await client.get>(BASE, { params }); diff --git a/apps/as/src/entities/cnstp/api/queries.ts b/apps/as/src/entities/cnstp/api/queries.ts index 2ebb44dea..a419af10c 100644 --- a/apps/as/src/entities/cnstp/api/queries.ts +++ b/apps/as/src/entities/cnstp/api/queries.ts @@ -10,7 +10,7 @@ import type { import { cnstpSeMngService } from "./cnstp-service"; -const cnstpSeMngBaseKey = [ENDPOINT.AS_COMMON_SERVICE.CNSTP_SE] as const; +const cnstpSeMngBaseKey = [ENDPOINT.AS_SERVICE.CNSTP_SE] as const; export function useCnstpSeMngPage(params: CnstpSeMngSearchDto) { return useQuery({ diff --git a/apps/as/src/entities/elapr/index.ts b/apps/as/src/entities/elapr/index.ts index caa639e51..ad35ae13b 100644 --- a/apps/as/src/entities/elapr/index.ts +++ b/apps/as/src/entities/elapr/index.ts @@ -1,4 +1,5 @@ export { elaprAplnService } from "./api/elapr-apln-service"; +export { ElaprDmndApi } from "./api/elapr-dmnd-service"; export { elaprTmpltService } from "./api/elapr-tmplt-service"; export { useCreateElaprTmplt, @@ -24,6 +25,7 @@ export { type ElaprAplnService, type ElaprAplnUpdateRequest, } from "./model/elapr-apln-interface"; +export type { ElaprDmndSaveRequest } from "./model/elapr-dmnd-interface"; export type { ElaprTmplt, ElaprTmpltSaveRequest, diff --git a/apps/as/src/entities/esntl/api/esntl-service.ts b/apps/as/src/entities/esntl/api/esntl-service.ts index 458940399..e8de77618 100644 --- a/apps/as/src/entities/esntl/api/esntl-service.ts +++ b/apps/as/src/entities/esntl/api/esntl-service.ts @@ -11,50 +11,41 @@ import type { EsntlAtchFileMngTreeSearchParams, } from "../model/esntl-interface"; +const BASE = ENDPOINT.AS_SERVICE.ESNTL_ATCH_FILE; + async function findTree( params: EsntlAtchFileMngTreeSearchParams, ): Promise { - const response = await client.get( - `${ENDPOINT.AS_COMMON_SERVICE.ESNTL_ATCH_FILE}/list/tree`, - { params }, - ); + const response = await client.get(`${BASE}/list/tree`, { + params, + }); return response.data; } async function findPage( params: EsntlAtchFileMngSearchParams, ): Promise> { - const response = await client.get>( - ENDPOINT.AS_COMMON_SERVICE.ESNTL_ATCH_FILE, - { params }, - ); + const response = await client.get>(BASE, { params }); return response.data; } async function findById(esntlAtchFileId: string): Promise { - const response = await client.get( - `${ENDPOINT.AS_COMMON_SERVICE.ESNTL_ATCH_FILE}/${esntlAtchFileId}`, - ); + const response = await client.get(`${BASE}/${esntlAtchFileId}`); return response.data; } async function create(body: EsntlAtchFileMngSaveRequest): Promise { - const response = await client.post(ENDPOINT.AS_COMMON_SERVICE.ESNTL_ATCH_FILE, body); + const response = await client.post(BASE, body); return response.data; } async function update(esntlAtchFileId: string, body: EsntlAtchFileMngSaveRequest): Promise { - const response = await client.put( - `${ENDPOINT.AS_COMMON_SERVICE.ESNTL_ATCH_FILE}/${esntlAtchFileId}`, - body, - ); + const response = await client.put(`${BASE}/${esntlAtchFileId}`, body); return response.data; } async function remove(esntlAtchFileId: string): Promise { - const response = await client.delete( - `${ENDPOINT.AS_COMMON_SERVICE.ESNTL_ATCH_FILE}/${esntlAtchFileId}`, - ); + const response = await client.delete(`${BASE}/${esntlAtchFileId}`); return response.data; } diff --git a/apps/as/src/entities/esntl/api/queries.ts b/apps/as/src/entities/esntl/api/queries.ts index 48e30fc68..dc7afb789 100644 --- a/apps/as/src/entities/esntl/api/queries.ts +++ b/apps/as/src/entities/esntl/api/queries.ts @@ -10,7 +10,7 @@ import type { import { esntlAtchFileMngService } from "./esntl-service"; -const esntlAtchFileMngBaseKey = [ENDPOINT.AS_COMMON_SERVICE.ESNTL_ATCH_FILE] as const; +const esntlAtchFileMngBaseKey = [ENDPOINT.AS_SERVICE.ESNTL_ATCH_FILE] as const; export function useEsntlAtchFileMngTree(params: EsntlAtchFileMngTreeSearchParams) { return useQuery({ diff --git a/apps/as/src/entities/instl-sncn/api/instl-sncn-service.ts b/apps/as/src/entities/instl-sncn/api/instl-sncn-service.ts index 208e0172d..b47de0782 100644 --- a/apps/as/src/entities/instl-sncn/api/instl-sncn-service.ts +++ b/apps/as/src/entities/instl-sncn/api/instl-sncn-service.ts @@ -1,41 +1,62 @@ import { client } from "@/shared/api"; import { ENDPOINT } from "@/shared/config"; +import type { PageResponse } from "@/shared/model"; + import type { + AdstZoneResponseDto, InstlSncnApplySaveRequestDto, - InstlSncnMng, + InstlSncnMngDetResponse, + InstlSncnMngResponseDto, InstlSncnMngSearchParams, InstlSncnMngService, - SpringPage, - InstlSncnMngDetResponse, } from "../model/instl-sncn-interface"; +async function getSidoCombo(): Promise { + const response = await client.get( + `${ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_MST}/sido`, + ); + + return response.data; +} + +async function getSigunguCombo(sidoCd: string): Promise { + const response = await client.get( + `${ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_MST}/sigungu`, + { params: { sidoCd } }, + ); + + return response.data; +} + +const BASE = ENDPOINT.AS_SERVICE.INSTL_SNCN; + export class InstlSncnApiService implements InstlSncnMngService { - public async getPage(params: InstlSncnMngSearchParams): Promise> { - const response = await client.get>(ENDPOINT.AS_INSTL_SERVICE.INSTL_SNCN, { + public async getPage( + params: InstlSncnMngSearchParams, + ): Promise> { + const response = await client.get>(BASE, { params, }); return response.data; } public async getById(id: string): Promise { - const response = await client.get(`${ENDPOINT.AS_INSTL_SERVICE.INSTL_SNCN}/${id}`); + const response = await client.get(`${BASE}/${id}`); return response.data; } public async saveApply(payload: InstlSncnApplySaveRequestDto): Promise { - const response = await client.post( - `${ENDPOINT.AS_INSTL_SERVICE.INSTL_SNCN}/save-apply`, - payload, - ); + const response = await client.post(`${BASE}/save-apply`, payload); return response.data; } - public async techReview(payload: InstlSncnApplySaveRequestDto): Promise { - const response = await client.post( - `${ENDPOINT.AS_INSTL_SERVICE.INSTL_SNCN}/tech-review`, - payload, - ); - return response.data; + public async techReview(id: string, payload: InstlSncnApplySaveRequestDto): Promise { + await client.post(`${BASE}/${id}/tech-review`, payload); } } export const InstlSncnApi = new InstlSncnApiService(); + +export const instlSncnRegionService = { + getSidoCombo, + getSigunguCombo, +}; diff --git a/apps/as/src/entities/instl-sncn/api/queries.ts b/apps/as/src/entities/instl-sncn/api/queries.ts new file mode 100644 index 000000000..46f56d231 --- /dev/null +++ b/apps/as/src/entities/instl-sncn/api/queries.ts @@ -0,0 +1,46 @@ +import { useQuery } from "@tanstack/react-query"; + +import { ENDPOINT } from "@/shared/config"; + +import type { InstlSncnMngSearchParams } from "../model/instl-sncn-interface"; + +import { InstlSncnApi, instlSncnRegionService } from "./instl-sncn-service"; + +export const instlSncnKeys = { + all: ["instl-sncn"] as const, + list: (params: InstlSncnMngSearchParams) => [...instlSncnKeys.all, "list", params] as const, + detail: (id: string) => [...instlSncnKeys.all, "detail", id] as const, + sidoCombo: () => [ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_MST, "sido"] as const, + sigunguCombo: (sidoCd: string) => + [ENDPOINT.STATVERIFY_SERVICE.ST_ANLS_MST, "sigungu", sidoCd] as const, +}; + +export function useInstlSncnList(params: InstlSncnMngSearchParams) { + return useQuery({ + queryKey: instlSncnKeys.list(params), + queryFn: () => InstlSncnApi.getPage(params), + }); +} + +export function useInstlSncnDetail(id: string) { + return useQuery({ + queryKey: instlSncnKeys.detail(id), + queryFn: () => InstlSncnApi.getById(id), + enabled: Boolean(id), + }); +} + +export function useInstlSncnSidoCombo() { + return useQuery({ + queryKey: instlSncnKeys.sidoCombo(), + queryFn: () => instlSncnRegionService.getSidoCombo(), + }); +} + +export function useInstlSncnSigunguCombo(sidoCd: string) { + return useQuery({ + queryKey: instlSncnKeys.sigunguCombo(sidoCd), + queryFn: () => instlSncnRegionService.getSigunguCombo(sidoCd), + enabled: Boolean(sidoCd), + }); +} diff --git a/apps/as/src/entities/instl-sncn/index.ts b/apps/as/src/entities/instl-sncn/index.ts index cd340d42d..146c16215 100644 --- a/apps/as/src/entities/instl-sncn/index.ts +++ b/apps/as/src/entities/instl-sncn/index.ts @@ -1,12 +1,28 @@ -export { InstlSncnApi } from "./api/instl-sncn-service"; +export { InstlSncnApi, instlSncnRegionService } from "./api/instl-sncn-service"; export { + instlSncnKeys, + useInstlSncnDetail, + useInstlSncnList, + useInstlSncnSidoCombo, + useInstlSncnSigunguCombo, +} from "./api/queries"; +export { + type AdstZoneResponseDto, + type AtflMngClientResponseDto, + type BizCstTreeDto, + type BizSclTreeDto, + type CklstRvwRsltTreeDto, + type ElaprDocPrgrsClientResponseDto, + type EsntlAtchFileMngTreeResponseDto, INSTL_SNCN_REGISTER_SELECTION_KEY, type InstlSncnApplySaveRequestDto, type InstlSncnBizCstSaveRequestDto, type InstlSncnBzScaleSaveDto, type InstlSncnCklstResultSaveDto, - type InstlSncnMng, + type InstlSncnMngDetResponse, + type InstlSncnMngResponseDto, + type InstlSncnMngSaveRequestDto, type InstlSncnMngSearchParams, - type SpringPage, - type ElaprDocPrgrsClientResponseDto, + type InstlSncnRvwOpnnResponseDto, + type ReviewStepCode, } from "./model/instl-sncn-interface"; diff --git a/apps/as/src/entities/instl-sncn/model/instl-sncn-interface.ts b/apps/as/src/entities/instl-sncn/model/instl-sncn-interface.ts index 81c769f98..433345b86 100644 --- a/apps/as/src/entities/instl-sncn/model/instl-sncn-interface.ts +++ b/apps/as/src/entities/instl-sncn/model/instl-sncn-interface.ts @@ -1,60 +1,100 @@ -export const INSTL_SNCN_REGISTER_SELECTION_KEY = "instlSncnRegisterSelection"; +import type { PageableParams, PageResponse } from "@/shared/model"; -export interface SpringPage { - content: T[]; - totalElements: number; - totalPages: number; - number: number; - size: number; - first: boolean; - last: boolean; - numberOfElements: number; +/** 행정구역(시도·시군구) 콤보 응답 DTO */ +export interface AdstZoneResponseDto { + /** 행정구역 코드 */ + adstCd: string; + /** 행정구역 명 */ + adstNm: string; } -export interface InstlSncnMngSearchParams { +export const INSTL_SNCN_REGISTER_SELECTION_KEY = "instlSncnRegisterSelection"; + +export interface InstlSncnMngSearchParams extends PageableParams { bizNm?: string; taskSeComCd?: string; sidoComCd?: string; sggComCd?: string; - page?: number; - size?: number; - sort?: string; } -export interface InstlSncnMng { - gugun: string; - sido: string; - instlSncnDocNo: string; - admdstCd: string; - sidoNm?: string; - sggNm?: string; - chrgrNm?: string; - instNm?: string; - envoSeComCd: string; +/** 설치인가관리 저장 요청 DTO */ +export interface InstlSncnMngSaveRequestDto { + /** 설치인가문서번호 */ + instlSncnDocNo?: string; + /** 행정구역코드 */ + admdstCd?: string; + /** 환경청구분공통코드 */ + envoSeComCd?: string; + /** 인가구분공통코드 */ sncnSeComCd: string; - envoSeCdNm: string; + /** 업무구분공통코드 */ taskSeComCd: string; - taskSeCdNm: string; - bgtBizCd: string; - bgtAplyYr: string; + /** 예산사업코드 */ + bgtBizCd?: string; + /** 예산신청연도 */ + bgtAplyYr?: string; + /** 사업명 */ bizNm: string; + /** 사업시작연도 */ bizBgngYr: string; + /** 사업종료연도 */ bizEndYr: string; + /** 사업내용 */ bizCn: string; - aplcntNm: string; - aplcntMblTelno: string; - aplcntOgdpNm: string; - aplcntEmlAddr: string; + /** 신청자명 */ + aplcntNm?: string; + /** 신청자휴대전화번호 */ + aplcntMblTelno?: string; + /** 신청자소속명 */ + aplcntOgdpNm?: string; + /** 신청자이메일주소 */ + aplcntEmlAddr?: string; + /** 설계자명 */ dsgnrNm: string; + /** 설계자전화번호 */ dsgnrTelno: string; + /** 설계자소속명 */ dsgnrOgdpNm: string; + /** 설계자이메일주소 */ dsgnrEmlAddr: string; - atchFileGroupId: string; - prgrsSttsComCd: string; + /** 첨부파일그룹아이디 */ + atchFileGroupId?: string; + /** 진행상태공통코드 */ + prgrsSttsComCd?: string; + /** 재이용시설구분공통코드 */ + rtlztnFcltSeComCd?: string; + /** 재이용용도구분공통코드 */ + rtlztnUsgSeComCd?: string; +} + +/** 설치인가관리 응답 DTO */ +export interface InstlSncnMngResponseDto extends InstlSncnMngSaveRequestDto { + /** 설치인가문서번호 (필수로 재정의) */ + instlSncnDocNo: string; + /** 환경청구분공통코드명 */ + envoSeCdNm: string; + /** 인가구분공통코드명 */ + sncnSeCdNm: string; + /** 업무구분공통코드명 */ + taskSeCdNm: string; + /** 진행상태공통코드명 */ prgrsSttsCdNm: string; + /** 재이용시설구분공통코드명 */ + rtlztnFcltSeComNm: string; + /** 재이용용도구분공통코드명 */ + rtlztnUsgSeComNm: string; + /** 등록일시 */ regDt: string; - mdfcnDt: string; + /** 등록자 UUID */ + rgtr: string; + /** 등록자명 */ rgtrNm: string; + /** 수정 일시 */ + mdfcnDt: string; + /** 시도 */ + sido: string; + /** 구군 */ + gugun: string; } /** 설치인가 신청 - 사업규모 저장 DTO(배열 원소) */ @@ -101,7 +141,7 @@ export interface InstlSncnEsntlAtchFileSaveDto { /** 설치인가 신청 - 통합 저장 요청 DTO */ export interface InstlSncnApplySaveRequestDto { - instlSncnMng: InstlSncnMng; + instlSncnMng: InstlSncnMngSaveRequestDto; bzScaleList: InstlSncnBzScaleSaveDto[]; bizCstList: InstlSncnBizCstSaveRequestDto[]; cklstResultList: InstlSncnCklstResultSaveDto[]; @@ -110,7 +150,155 @@ export interface InstlSncnApplySaveRequestDto { export type ReviewStepCode = "LOCAL" | "ENV" | "KECO"; +/** 공종 트리와 사업규모(수량) 조합 DTO */ +export interface BizSclTreeDto { + /** 들여쓰기 적용된 공종명(시각적) */ + indCnstpSeCdNm: string; + /** 공종 코드 */ + cnstpSeCd: string; + /** 공종 코드명 */ + cnstpSeCdNm: string; + /** 사용 여부(Y/N) */ + useYn: string; + /** 트리 레벨(깊이) */ + treeLevel: number; + /** 트리 경로 표시용 문자열 */ + treePath: string; + /** 기본계획수량 */ + bscPlanQty: number; + /** 예산반영수량 */ + bgtRfltQty: number; + /** 금회설계수량 */ + tstmDesignQty: number; +} +/** 회계구분 트리와 사업비용 조합 DTO */ +export interface BizCstTreeDto { + /** 들여쓰기 적용된 회계구분명(시각적) */ + indAcntgSeCdNm: string; + /** 회계구분 코드 */ + acntgSeCd: string; + /** 회계구분 코드명 */ + acntgSeCdNm: string; + /** 사용 여부(Y/N) */ + useYn: string; + /** 트리 레벨(깊이) */ + treeLevel: number; + /** 트리 경로 표시용 문자열 */ + treePath: string; + /** 기본계획금액 */ + bscPlanAmt: number; + /** 예산반영금액 */ + bgtRfltAmt: number; + /** 금회설계금액 */ + tstmDesignAmt: number; +} + +/** 점검표 검토결과 트리 DTO */ +export interface CklstRvwRsltTreeDto { + /** 점검표일련번호 */ + cklstSn: number; + /** 점검표명 */ + cklstNm: string; + /** 점검표항목일련번호 */ + cklstArtclSn: number; + /** 점검표항목명 */ + cklstArtclNm: string; + /** 검토일련번호 */ + cklstRvwSn: number; + /** 상위검토일련번호 */ + upCklstRvwSn: number | null; + /** 트리 레벨 */ + treeLevel: number; + /** 검토내용 */ + rvwCn: string; + /** 점검 사용 여부 */ + bchckUseYn: string; + /** 정렬순서 */ + sortSeq: number; + /** 업무구분코드 */ + taskSeComCd: string; + /** 검토단계공통코드 */ + rvwStpComCd: string; + /** 검토결과이상여부 */ + rvwRsltAnmlyYn: string; + /** 검토담당자 UUID */ + rvwPicUuid: string | null; + /** 담당자검토내용 */ + picRvwCn: string | null; + /** 검토일시 */ + rvwDt: string | null; +} + +/** 필수첨부파일관리 트리 조회 응답 DTO */ +export interface EsntlAtchFileMngTreeResponseDto { + /** 필수첨부파일아이디 */ + esntlAtchFileId: string; + /** 문서구분공통코드 */ + docSeComCd: string; + /** 필수첨부파일명 */ + esntlAtchFileNm: string; + /** 필수첨부여부 */ + esntlAtchYn: string; + /** 필수첨부파일비고 */ + esntlAtchFileRmrk: string | null; + /** 첨부파일 코드 */ + atflCd?: string; + /** 첨부파일 일련번호 */ + atflSn?: number; + /** 첨부파일 ID */ + atflId?: string; + /** 원본 파일명 */ + orgnlFileNm?: string; + /** 첨부파일 크기 */ + atflFlieSz?: number; + /** 첨부파일 타입 */ + atflType?: string; + /** 다운로드 횟수 */ + dwnldNocs?: number; + /** 등록일시 */ + regDt?: string; +} + +/** 첨부파일 응답 DTO (attach-service client) */ +export interface AtflMngClientResponseDto { + atflCd: string; + atflSn: number; + atflId: string; + physFileNm: string; + orgnlFileNm: string; + atflFlieSz: number; + atflType: string; + dwnldNocs: number; + delYn: string; + lnkgDmnId: string | null; + lnkgDmnNm: string | null; + regDt: string; +} + +/** 설치인가검토의견 응답 DTO */ +export interface InstlSncnRvwOpnnResponseDto { + /** 설치인가문서번호 */ + instlSncnDocNo: string; + /** 검토의견일련번호 */ + rvwOpnnSn: number; + /** 의견자구분공통코드 */ + opnrSeComCd: string; + /** 의견자구분공통코드명 */ + opnrSeCdNm: string | null; + /** 의견자명 */ + opnrNm: string; + /** 검토결과내용 */ + rvwRsltCn: string; + /** 검토결과이상여부 */ + rvwRsltAnmlyYn: string; + /** 첨부파일그룹아이디 */ + atchFileGroupId: string | null; + /** 첨부파일 상세 정보 */ + atchFileInfo?: AtflMngClientResponseDto; + /** 등록일시 */ + regDt: string; +} /** 전자결재 진행상태 (클라이언트 응답용) */ export interface ElaprDocPrgrsClientResponseDto { @@ -131,19 +319,21 @@ export interface ElaprDocPrgrsClientResponseDto { ognzNm?: string; } -// det 응답에 전자결재 진행상태 목록을 포함 +/** 설치인가관리 상세 응답 DTO */ export interface InstlSncnMngDetResponse { - detDto: InstlSncnMng; - bizSclList: any[]; - bizCstList: any[]; - cklstResultList?: any[]; - esntlFileList: any[]; - etcFileList: any[]; + detDto: InstlSncnMngResponseDto; + bizSclList: BizSclTreeDto[]; + bizCstList: BizCstTreeDto[]; + cklstResultList?: CklstRvwRsltTreeDto[]; + esntlFileList: EsntlAtchFileMngTreeResponseDto[]; + etcFileList: AtflMngClientResponseDto[]; + rvwList?: InstlSncnRvwOpnnResponseDto[]; elaprDocPrgrsList?: ElaprDocPrgrsClientResponseDto[] | null; } export interface InstlSncnMngService { - getPage: (params: InstlSncnMngSearchParams) => Promise>; + getPage: (params: InstlSncnMngSearchParams) => Promise>; getById: (id: string) => Promise; saveApply: (payload: InstlSncnApplySaveRequestDto) => Promise; + techReview: (id: string, payload: InstlSncnApplySaveRequestDto) => Promise; } diff --git a/apps/as/src/entities/rvw-mnpw/api/queries.ts b/apps/as/src/entities/rvw-mnpw/api/queries.ts index 6e075e4d5..7b38c6acf 100644 --- a/apps/as/src/entities/rvw-mnpw/api/queries.ts +++ b/apps/as/src/entities/rvw-mnpw/api/queries.ts @@ -3,6 +3,7 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { ENDPOINT } from "@/shared/config"; import type { + RvwMnpwMngPageSearchDto, RvwMnpwMngSaveRequestDto, RvwMnpwMngSearchDto, RvwMnpwMngUpdateRequestDto, @@ -10,9 +11,12 @@ import type { import { rvwMnpwMngService } from "./rvw-mnpw-service"; -const rvwMnpwMngBaseKey = [ENDPOINT.AS_COMMON_SERVICE.RVW_MNPW] as const; +const rvwMnpwMngBaseKey = [ENDPOINT.AS_SERVICE.RVW_MNPW] as const; -export function useRvwMnpwMngPage(params: RvwMnpwMngSearchDto, options?: { enabled?: boolean }) { +export function useRvwMnpwMngPage( + params: RvwMnpwMngPageSearchDto, + options?: { enabled?: boolean }, +) { return useQuery({ queryKey: [...rvwMnpwMngBaseKey, "findPage", params], queryFn: () => rvwMnpwMngService.findPage(params), @@ -20,6 +24,17 @@ export function useRvwMnpwMngPage(params: RvwMnpwMngSearchDto, options?: { enabl }); } +export function useRvwMnpwMngLoginUserList( + searchDto: RvwMnpwMngSearchDto, + options?: { enabled?: boolean }, +) { + return useQuery({ + queryKey: [...rvwMnpwMngBaseKey, "findRvwLoginUserList", searchDto], + queryFn: () => rvwMnpwMngService.findRvwLoginUserList(searchDto), + enabled: options?.enabled, + }); +} + export function useRvwMnpwMng( atrzSeComCd: string | null | undefined, ognzSn: number | null | undefined, diff --git a/apps/as/src/entities/rvw-mnpw/api/rvw-mnpw-service.ts b/apps/as/src/entities/rvw-mnpw/api/rvw-mnpw-service.ts index 4f756787f..2e99f3fba 100644 --- a/apps/as/src/entities/rvw-mnpw/api/rvw-mnpw-service.ts +++ b/apps/as/src/entities/rvw-mnpw/api/rvw-mnpw-service.ts @@ -3,6 +3,7 @@ import { ENDPOINT } from "@/shared/config"; import type { PageResponse } from "@/shared/model"; import type { + RvwMnpwMngPageSearchDto, RvwMnpwMngResponseDto, RvwMnpwMngSaveRequestDto, RvwMnpwMngSearchDto, @@ -10,14 +11,21 @@ import type { RvwMnpwMngUpdateRequestDto, } from "../model/rvw-mnpw-interface"; -const BASE = ENDPOINT.AS_COMMON_SERVICE.RVW_MNPW; +const BASE = ENDPOINT.AS_SERVICE.RVW_MNPW; -function pkPath(atrzSeComCd: string, ognzSn: number, userUuid: string): string { - return `${BASE}/${atrzSeComCd}/${ognzSn}/${userUuid}`; +async function findPage( + params: RvwMnpwMngPageSearchDto, +): Promise> { + const response = await client.get>(BASE, { params }); + return response.data; } -async function findPage(params: RvwMnpwMngSearchDto): Promise> { - const response = await client.get>(BASE, { params }); +async function findRvwLoginUserList( + searchDto: RvwMnpwMngSearchDto, +): Promise> { + const response = await client.get>(`${BASE}/loginuser/me`, { + params: searchDto, + }); return response.data; } @@ -26,41 +34,48 @@ async function findById( ognzSn: number, userUuid: string, ): Promise { - const response = await client.get(pkPath(atrzSeComCd, ognzSn, userUuid)); + const response = await client.get( + `${BASE}/${atrzSeComCd}/${ognzSn}/${userUuid}`, + ); return response.data; } -async function save(body: RvwMnpwMngSaveRequestDto): Promise { - const response = await client.post(BASE, body); +async function saveRvwMnpwMng(body: RvwMnpwMngSaveRequestDto): Promise { + const { atrzSeComCd, ognzSn, userUuid } = body; + const response = await client.post( + `${BASE}/${atrzSeComCd}/${ognzSn}/${userUuid}`, + body, + ); return response.data; } -async function update( +async function updateRvwMnpwMng( atrzSeComCd: string, ognzSn: number, userUuid: string, body: RvwMnpwMngUpdateRequestDto, ): Promise { const response = await client.put( - pkPath(atrzSeComCd, ognzSn, userUuid), + `${BASE}/${atrzSeComCd}/${ognzSn}/${userUuid}`, body, ); return response.data; } -async function deleteRvwMnpw( +async function deleteRvwMnpwMng( atrzSeComCd: string, ognzSn: number, userUuid: string, ): Promise { - const response = await client.delete(pkPath(atrzSeComCd, ognzSn, userUuid)); + const response = await client.delete(`${BASE}/${atrzSeComCd}/${ognzSn}/${userUuid}`); return response.data; } export const rvwMnpwMngService = { findPage, + findRvwLoginUserList, findById, - save, - update, - delete: deleteRvwMnpw, + save: saveRvwMnpwMng, + update: updateRvwMnpwMng, + delete: deleteRvwMnpwMng, } satisfies RvwMnpwMngService; diff --git a/apps/as/src/entities/rvw-mnpw/index.ts b/apps/as/src/entities/rvw-mnpw/index.ts index 14dd27dfc..380c50eb7 100644 --- a/apps/as/src/entities/rvw-mnpw/index.ts +++ b/apps/as/src/entities/rvw-mnpw/index.ts @@ -1,12 +1,14 @@ export { useDeleteRvwMnpwMng, useRvwMnpwMng, + useRvwMnpwMngLoginUserList, useRvwMnpwMngPage, useSaveRvwMnpwMng, useUpdateRvwMnpwMng, } from "./api/queries"; export { rvwMnpwMngService } from "./api/rvw-mnpw-service"; export type { + RvwMnpwMngPageSearchDto, RvwMnpwMngResponseDto, RvwMnpwMngSaveRequestDto, RvwMnpwMngSearchDto, diff --git a/apps/as/src/entities/rvw-mnpw/model/rvw-mnpw-interface.ts b/apps/as/src/entities/rvw-mnpw/model/rvw-mnpw-interface.ts index 92cbff071..4fee8df2e 100644 --- a/apps/as/src/entities/rvw-mnpw/model/rvw-mnpw-interface.ts +++ b/apps/as/src/entities/rvw-mnpw/model/rvw-mnpw-interface.ts @@ -14,13 +14,16 @@ export interface RvwMnpwMngResponseDto { regDt?: string; } -/** 백엔드 RvwMnpwMngSearchDto + Pageable */ -export interface RvwMnpwMngSearchDto extends PageableParams { +/** 백엔드 RvwMnpwMngSearchDto */ +export interface RvwMnpwMngSearchDto { atrzSeComCd?: string; ognzSn?: number; userUuid?: string; } +/** findPage — RvwMnpwMngSearchDto + Pageable */ +export type RvwMnpwMngPageSearchDto = RvwMnpwMngSearchDto & PageableParams; + /** 백엔드 RvwMnpwMngSaveRequestDto */ export interface RvwMnpwMngSaveRequestDto { atrzSeComCd: string; @@ -35,7 +38,10 @@ export interface RvwMnpwMngUpdateRequestDto { /** Controller public 메서드명·시그니처와 동일 */ export interface RvwMnpwMngService { - findPage(params: RvwMnpwMngSearchDto): Promise>; + findPage(params: RvwMnpwMngPageSearchDto): Promise>; + findRvwLoginUserList( + searchDto: RvwMnpwMngSearchDto, + ): Promise>; findById(atrzSeComCd: string, ognzSn: number, userUuid: string): Promise; save(body: RvwMnpwMngSaveRequestDto): Promise; update( diff --git a/apps/as/src/entities/tus/index.ts b/apps/as/src/entities/tus/index.ts new file mode 100644 index 000000000..5cf2e3fbf --- /dev/null +++ b/apps/as/src/entities/tus/index.ts @@ -0,0 +1 @@ +export { handleTusUpload, type TusUploadOptions } from "./lib/utils"; diff --git a/apps/as/src/entities/tus/lib/utils.ts b/apps/as/src/entities/tus/lib/utils.ts new file mode 100644 index 000000000..6bb40bfd7 --- /dev/null +++ b/apps/as/src/entities/tus/lib/utils.ts @@ -0,0 +1,61 @@ +import { Upload } from "tus-js-client"; + +import { ENDPOINT, PROXY_HOST } from "@/shared/config"; +import { AUTH_USER_ID, CLAIM_NAME } from "@/shared/config/env"; +import { getCookie } from "@/shared/lib"; + +interface TusUploadOptions { + metadata?: Record; + handleUploadStart?: (upload: Upload) => void; + handleProgress?: (percentage: number) => void; + handleSuccess?: (upload: Upload, atflCd: string, atflId: string) => void; + handleError?: (error: Error) => void; +} + +function handleTusUpload(file: File, options?: TusUploadOptions) { + let atflCd = ""; + let atflId = ""; + + const metadata = { + filename: file.name, + filetype: file.type, + ...options?.metadata, + }; + + const upload = new Upload(file, { + endpoint: `${PROXY_HOST}${ENDPOINT.ATTACH_SERVICE.TUS_UPLOAD}`, + chunkSize: 10 * 1024 * 1024, + headers: { + [CLAIM_NAME]: getCookie(CLAIM_NAME) ?? "", + [AUTH_USER_ID]: getCookie(AUTH_USER_ID) ?? "", + }, + metadata, + onError(error) { + console.error("TUS upload failed:", error); + options?.handleError?.(error); + }, + onProgress(bytesUploaded, bytesTotal) { + const percentage = (bytesUploaded / bytesTotal) * 100; + options?.handleProgress?.(percentage); + }, + onAfterResponse(_req, res) { + const fileInfo = res.getHeader("X-File-Info"); + if (!fileInfo) return; + + const parsed = JSON.parse(fileInfo) as { atflCd?: string; atflId?: string }; + atflCd = parsed.atflCd ?? ""; + atflId = parsed.atflId ?? ""; + }, + onSuccess() { + options?.handleSuccess?.(upload, atflCd, atflId); + }, + }); + + upload.start(); + options?.handleUploadStart?.(upload); + + return upload; +} + +export { handleTusUpload }; +export type { TusUploadOptions }; diff --git a/apps/as/src/pages/checklist-management/ui/cklst-mng-form-dialog.tsx b/apps/as/src/pages/checklist-management/ui/cklst-mng-form-dialog.tsx index 8ff919256..3efa22ba9 100644 --- a/apps/as/src/pages/checklist-management/ui/cklst-mng-form-dialog.tsx +++ b/apps/as/src/pages/checklist-management/ui/cklst-mng-form-dialog.tsx @@ -102,7 +102,7 @@ function CklstMngFormDialog({
setValue("docSeComCd", v)} placeholder="문서구분 선택" @@ -112,7 +112,7 @@ function CklstMngFormDialog({
setValue("taskSeComCd", v)} placeholder="업무구분 선택" diff --git a/apps/as/src/pages/instl-sncn-old/index.ts b/apps/as/src/pages/instl-sncn-old/index.ts new file mode 100644 index 000000000..570133ba4 --- /dev/null +++ b/apps/as/src/pages/instl-sncn-old/index.ts @@ -0,0 +1,4 @@ +export { CnfmListPage } from "./ui/cnfm-list-page"; +export { CnfmViewPage } from "./ui/cnfm-view-page"; +export { CnfmRegistPage } from "./ui/cnfm-regist-page"; +export { CnfmModifyPage } from "./ui/cnfm-modify-page"; diff --git a/apps/as/src/pages/instl-sncn/ui/cnfm-list-page.tsx b/apps/as/src/pages/instl-sncn-old/ui/cnfm-list-page.tsx similarity index 100% rename from apps/as/src/pages/instl-sncn/ui/cnfm-list-page.tsx rename to apps/as/src/pages/instl-sncn-old/ui/cnfm-list-page.tsx diff --git a/apps/as/src/pages/instl-sncn/ui/cnfm-modify-page.tsx b/apps/as/src/pages/instl-sncn-old/ui/cnfm-modify-page.tsx similarity index 100% rename from apps/as/src/pages/instl-sncn/ui/cnfm-modify-page.tsx rename to apps/as/src/pages/instl-sncn-old/ui/cnfm-modify-page.tsx diff --git a/apps/as/src/pages/instl-sncn/ui/cnfm-page.css b/apps/as/src/pages/instl-sncn-old/ui/cnfm-page.css similarity index 100% rename from apps/as/src/pages/instl-sncn/ui/cnfm-page.css rename to apps/as/src/pages/instl-sncn-old/ui/cnfm-page.css diff --git a/apps/as/src/pages/instl-sncn/ui/cnfm-regist-page.tsx b/apps/as/src/pages/instl-sncn-old/ui/cnfm-regist-page.tsx similarity index 90% rename from apps/as/src/pages/instl-sncn/ui/cnfm-regist-page.tsx rename to apps/as/src/pages/instl-sncn-old/ui/cnfm-regist-page.tsx index 8b736b028..0f178f101 100644 --- a/apps/as/src/pages/instl-sncn/ui/cnfm-regist-page.tsx +++ b/apps/as/src/pages/instl-sncn-old/ui/cnfm-regist-page.tsx @@ -10,7 +10,7 @@ import { type HttpResponse, Upload } from "tus-js-client"; import { AUTH_USER_ID, CLAIM_NAME, ENDPOINT, PROXY_HOST } from "@/shared/config"; import { getCookie, setCookie, useAlertStore, useUserStore } from "@/shared/lib"; -import { deleteAttachment } from "@/shared/lib/attach"; +import { deleteAttachment } from "@/shared/lib/attach"; import { formatFileSize } from "@/shared/lib/file-utils"; import type { AcntgSeMngTreeDto } from "@/entities/acntg"; import { acntgSeMngService } from "@/entities/acntg"; @@ -18,19 +18,17 @@ import type { CklstTreeNode } from "@/entities/cklst"; import { cklstMngService } from "@/entities/cklst"; import type { CnstpSeMngTreeDto } from "@/entities/cnstp"; import { cnstpSeMngService } from "@/entities/cnstp"; -import { - esntlAtchFileMngService, - type EsntlAtchFileMngTreeResponseDto, -} from "@/entities/esntl"; +import { esntlAtchFileMngService, type EsntlAtchFileMngTreeResponseDto } from "@/entities/esntl"; import { INSTL_SNCN_REGISTER_SELECTION_KEY, InstlSncnApi, type InstlSncnApplySaveRequestDto, type InstlSncnBizCstSaveRequestDto, type InstlSncnBzScaleSaveDto, - type InstlSncnMng, + type InstlSncnMngResponseDto, + InstlSncnMngSaveRequestDto, } from "@/entities/instl-sncn"; -import { EtcAttachments,NumCell, PrivacyConsent, ReadCell } from "@/widgets/cnfm"; +import { EtcAttachments, NumCell, PrivacyConsent, ReadCell } from "@/widgets/cnfm"; import { Button, Input } from "@common/components"; import "./cnfm-page.css"; @@ -128,7 +126,7 @@ const normalizeChecklistResultRows = (payload: any): any[] => { /* 메인 컴포넌트 */ /* ------------------------------------------------------------------ */ /** - * initialData 매핑 안내 + * initialData 매핑 안내 * - initialData 데이터는 cnfm-modify-page에서 서버로부터 받아온 상세 데이터를 그대로 전달받거나, cnfm-regist-page에서 수정 모드로 진입할 때 전달받을 수 있습니다. * - 이 컴포넌트는 수정 모드로 호출될 때 `initialData`를 받습니다. * - 서버 응답은 두 가지 형태 중 하나일 수 있습니다: @@ -184,7 +182,6 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { return visibleReviewStepCodes.includes(step) ? step : null; }, [isModifyMode, userInfo?.dtlInstCd, visibleReviewStepCodes]); const [selectedReviewStep, setSelectedReviewStep] = useState("LOCAL"); - useEffect(() => { if (visibleReviewStepCodes.length === 0) return; @@ -208,13 +205,15 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { const [taskSeComCdNm, setTaskSeComCdNm] = useState( () => (currentDet?.taskSeComCdNm as string) ?? "", ); - const [taskSeComCd, setTaskSeComCd] = useState(() => (currentDet?.taskSeComCd as string) ?? "RE"); + const [taskSeComCd, setTaskSeComCd] = useState( + () => (currentDet?.taskSeComCd as string) ?? "RE", + ); useEffect(() => { // do not override server-provided initialData (modify mode) if (currentDet) return; - const raw = sessionStorage.getItem(INSTL_SNCN_REGISTER_SELECTION_KEY); + const raw = sessionStorage.getItem(INSTL_SNCN_REGISTER_SELECTION_KEY); if (!raw) return; try { @@ -222,7 +221,7 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { taskSeComCdList?: string[]; taskSeComCdNmList?: string[]; }; - + setTaskSeComCd(parsed.taskSeComCdList?.join(",") || "RE"); setTaskSeComCdNm(parsed.taskSeComCdNmList?.join(",") || "재이용수"); } catch { @@ -262,13 +261,10 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { // selected task code for header filtering (null = none selected) const [selectedTaskCode, setSelectedTaskCode] = useState(null); - - - - - - const [requiredFiles, setRequiredFiles] = useState>({}); + const [requiredFiles, setRequiredFiles] = useState>( + {}, + ); const requiredFileInputRefs = useRef>({}); useEffect(() => { @@ -352,22 +348,22 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { upload.start(); }; - /* ── 기타 첨부파일 ── */ - type EtcFile = { - id: string; - name: string; - ext: string; - size: string; - uploader: string; - atflCd: string; - atflId: string; - }; - const [etcFiles, setEtcFiles] = useState([]); - const [etcNoticeOpen, setEtcNoticeOpen] = useState(true); - const [etcFileGroupId, setEtcFileGroupId] = useState(""); - const [etcUploading, setEtcUploading] = useState(false); - const etcFileGroupIdRef = useRef(""); - const initialMappedRef = useRef(false); + /* ── 기타 첨부파일 ── */ + type EtcFile = { + id: string; + name: string; + ext: string; + size: string; + uploader: string; + atflCd: string; + atflId: string; + }; + const [etcFiles, setEtcFiles] = useState([]); + const [etcNoticeOpen, setEtcNoticeOpen] = useState(true); + const [etcFileGroupId, setEtcFileGroupId] = useState(""); + const [etcUploading, setEtcUploading] = useState(false); + const etcFileGroupIdRef = useRef(""); + const initialMappedRef = useRef(false); // 초기 데이터가 주어지면 폼 상태로 매핑 (수정 모드에서 사용) useEffect(() => { @@ -382,7 +378,6 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { //const cklstResultList = initialData.cklstResultList ?? []; const esntlFileList = initialData.esntlFileList ?? []; const etcFileList = initialData.etcFileList ?? []; - // 기본 정보 및 설계자 정보 setBzNm(det.bizNm ?? ""); @@ -412,9 +407,12 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { .filter((f: any) => f && typeof f === "object") .map((f: any) => { const fileName = f.orgnlFileNm ?? f.physFileNm ?? ""; - const ext = fileName && typeof fileName === "string" && fileName.includes(".") ? fileName.split(".").pop() ?? "" : ""; + const ext = + fileName && typeof fileName === "string" && fileName.includes(".") + ? (fileName.split(".").pop() ?? "") + : ""; return { - id: f.atflId , + id: f.atflId, name: fileName, ext, size: f.atflFlieSz ?? 0, @@ -428,17 +426,18 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { // 수정모드시 기타첨부 그룹아이디 적용 (중복 매핑 방지) // - det.atchFileGroupId 또는 det.atflCd 우선, 없으면 etcFileList 첫 항목의 atflCd 사용 - const existingGroup = (det.atchFileGroupId ) || (Array.isArray(etcFileList) && etcFileList[0]?.atflCd) || ""; + const existingGroup = + det.atchFileGroupId || (Array.isArray(etcFileList) && etcFileList[0]?.atflCd) || ""; //console.log("etcFileGroupIdRef.current 초기화1:", existingGroup); if (existingGroup && etcFileGroupIdRef.current !== existingGroup) { etcFileGroupIdRef.current = existingGroup; setEtcFileGroupId((prev) => prev || existingGroup); } - // console.log("etcFileGroupIdRef.current 초기화:", etcFileGroupIdRef.current); + // console.log("etcFileGroupIdRef.current 초기화:", etcFileGroupIdRef.current); // 수정모드인 경우 서버가 전달한 업무구분(단일 혹은 콤마로 결합된 복수)을 상태로 복원 - setTaskSeComCd(det.taskSeComCd); - setTaskSeComCdNm(det.taskSeCdNm ); + setTaskSeComCd(det.taskSeComCd); + setTaskSeComCdNm(det.taskSeCdNm); // 매핑 완료 플래그 설정 — 이후 동일 컴포넌트 인스턴스에서 재매핑 방지 initialMappedRef.current = true; @@ -500,14 +499,14 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { }; } setAmtMap(map); - } + } } catch (err) { console.error("initialData 매핑 실패", err); } }, [initialData]); - /** 기타첨부파일 삭제 핸들러: 백엔드에 DELETE 요청을 보내 소프트삭제 처리 후 상태 갱신 */ - const handleDeleteEtcFile = async (fileId: string, atflId: string) => { + /** 기타첨부파일 삭제 핸들러: 백엔드에 DELETE 요청을 보내 소프트삭제 처리 후 상태 갱신 */ + const handleDeleteEtcFile = async (fileId: string, atflId: string) => { try { if (atflId) { await deleteAttachment(atflId); @@ -528,18 +527,21 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { }); }; - const handleRequiredFileChange = (key: RequiredAttachKey, e: React.ChangeEvent) => { + const handleRequiredFileChange = ( + key: RequiredAttachKey, + e: React.ChangeEvent, + ) => { const file = e.target.files?.[0]; if (!file) return; uploadRequiredFile(file, key); e.target.value = ""; }; - + const uploadEtcFile = (file: File): Promise => new Promise((resolve, reject) => { let uploadedAtflCd = ""; let uploadedAtflId = ""; - console.log("기타첨부파일 업로드 시작:", file.name ,etcFileGroupIdRef.current); + console.log("기타첨부파일 업로드 시작:", file.name, etcFileGroupIdRef.current); const upload = new Upload(file, { endpoint: `${PROXY_HOST}${ENDPOINT.ATTACH_SERVICE.TUS_UPLOAD}`, chunkSize: 10 * 1024 * 1024, @@ -569,7 +571,7 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { } }, onSuccess() { - const ext = file.name.includes(".") ? file.name.split(".").pop() ?? "" : ""; + const ext = file.name.includes(".") ? (file.name.split(".").pop() ?? "") : ""; resolve({ id: uploadedAtflId || `${Date.now()}_${Math.random()}`, name: file.name, @@ -666,7 +668,7 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { const cklstRows = useMemo(() => { // bchckUseYn 필터 제거: 부모가 있는 자식 노드(bchckUseYn=N)도 트리에 포함 // cklstTree 내의 피드 taskSeComCd 에 따라서 그룹핑 되도록 해줘 - + const useRows = selectedTaskCode ? cklstTree.filter((r) => (r as any).taskSeComCd === selectedTaskCode) : cklstTree; @@ -710,7 +712,7 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { const codes = Array.from( new Set((cklstTree ?? []).map((r) => (r as any).taskSeComCd).filter(Boolean)), ); - + if (codes.length === 0) { if (selectedTaskCode !== null) setSelectedTaskCode(null); return; @@ -791,7 +793,9 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { const el = cklstRowRefs.current[pendingInvalidKey]; if (el) { el.scrollIntoView({ behavior: "smooth", block: "center" }); - const firstRadio = el.querySelector(`input[name="chk_${pendingInvalidKey}"]`); + const firstRadio = el.querySelector( + `input[name="chk_${pendingInvalidKey}"]`, + ); firstRadio?.focus(); setPendingInvalidKey(null); } @@ -800,7 +804,7 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { // 수정 모드에서 서버의 체크리스트 결과값을 폼 상태로 반영 useEffect(() => { - if (!initialData || cklstRows.length === 0) return; + if (!initialData || cklstRows.length === 0) return; const results = normalizeChecklistResultRows(initialData); if (!Array.isArray(results) || results.length === 0) return; @@ -866,7 +870,6 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { return { total, completed, percent }; }, [cklstRows, checkResults, selectedReviewStep]); - const toCklstSaveDtoList = () => { const persistedStepCodeSet = new Set(); normalizeChecklistResultRows(initialData).forEach((r: any) => { @@ -877,9 +880,9 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { visibleReviewStepCodes.forEach((code) => persistedStepCodeSet.add(code)); // only persist rows that are enabled for checkbox (`bchckUseYn === "Y") - // only persist rows that are enabled for checkbox (`bchckUseYn === "Y") - // Use full cklstTree so items not currently visible (other task codes) are included - const relevantRows = (cklstTree ?? []).filter((row) => row.bchckUseYn === "Y"); + // only persist rows that are enabled for checkbox (`bchckUseYn === "Y") + // Use full cklstTree so items not currently visible (other task codes) are included + const relevantRows = (cklstTree ?? []).filter((row) => row.bchckUseYn === "Y"); // Ensure we generate DTOs grouped by all known task codes (TASK_CODE_LABELS keys) const allTaskCodes = Object.keys(TASK_CODE_LABELS); @@ -930,7 +933,9 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { const subtotalScale = (node: CnstpSeMngTreeDto, col: keyof BzScaleRow): number => cnstpTree - .filter((n) => cnstpLeafSet.has(n.cnstpSeCd) && n.treePath.split("|").includes(node.cnstpSeCd)) + .filter( + (n) => cnstpLeafSet.has(n.cnstpSeCd) && n.treePath.split("|").includes(node.cnstpSeCd), + ) .reduce((sum, n) => sum + num((bzScaleMap[n.cnstpSeCd] ?? emptyScale())[col]), 0); const scaleNodeVal = (node: CnstpSeMngTreeDto, col: keyof BzScaleRow): number => @@ -1046,7 +1051,6 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { /* ── 검증 ── */ function fnValidation(mode: "SAVE" | "PRESENTN") { - if (!bzNm.trim()) { alert("사업명을 입력하세요."); return false; @@ -1063,8 +1067,7 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { alert("개인정보 제공에 동의하셔야 제출이 가능합니다."); return false; } - - + if (!editableReviewStep) { alert("현재 사용자 권한/진행상태 조합에서 입력 가능한 체크리스트 단계가 없습니다."); return false; @@ -1100,14 +1103,18 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { visibleReviewStepCodes.some((step) => !checkResults[cklstKey(row, step)]), ); if (missingRow) { - const missingStep = visibleReviewStepCodes.find((step) => !checkResults[cklstKey(missingRow, step)])!; + const missingStep = visibleReviewStepCodes.find( + (step) => !checkResults[cklstKey(missingRow, step)], + )!; const invalidKey = cklstKey(missingRow, missingStep); console.warn("검토 결과 미선택 항목 발견:", invalidKey, missingRow, missingStep); const invalidRowEl = cklstRowRefs.current[invalidKey]; if (invalidRowEl) { invalidRowEl.scrollIntoView({ behavior: "smooth", block: "center" }); - const firstRadio = invalidRowEl.querySelector(`input[name="chk_${invalidKey}"]`); + const firstRadio = invalidRowEl.querySelector( + `input[name="chk_${invalidKey}"]`, + ); firstRadio?.focus(); } else { // row not visible: switch header filter to the missing row's task code, @@ -1125,18 +1132,14 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { return true; } - const toInstlSncnMngPayload = (prgrsSttsComCd: "SV" | "ST"| "ER"): InstlSncnMng => ({ + const toInstlSncnMngPayload = ( + prgrsSttsComCd: "SV" | "ST" | "ER", + ): InstlSncnMngSaveRequestDto => ({ instlSncnDocNo: docId ?? "", admdstCd: "", - sidoNm: "", - sggNm: "", - chrgrNm: "", - instNm: "", envoSeComCd: currentDet?.envoSeComCd ?? "", sncnSeComCd: sncnSeComCd || DEFAULT_SNCN_SE_COM_CD, - envoSeCdNm: "", taskSeComCd, - taskSeCdNm: taskSeComCdNm, bgtBizCd: "", bgtAplyYr: "", bizNm: bzNm, @@ -1153,12 +1156,6 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { dsgnrEmlAddr, atchFileGroupId: etcFileGroupId, prgrsSttsComCd, - prgrsSttsCdNm: "", - regDt: "", - mdfcnDt: "", - rgtrNm: "", - gugun: "", - sido: "" }); async function handleSave() { @@ -1188,15 +1185,15 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { async function handleSubmit() { if (!fnValidation("SAVE")) return; - const payload: InstlSncnApplySaveRequestDto = { + const payload: InstlSncnApplySaveRequestDto = { instlSncnMng: toInstlSncnMngPayload("SV"), // 저장 시 진행상태는 SV (임시저장) bzScaleList: toBzScaleSaveDtoList(), bizCstList: toBizCstSaveDtoList(), cklstResultList: toCklstSaveDtoList(), esntlAtchFileList: toEsntlAtchFileSaveDtoList(), - }; + }; - try { + try { const issuedDocNo = await InstlSncnApi.saveApply(payload); alert(`제출 되었습니다. 문서번호: ${issuedDocNo}`); } catch (error) { @@ -1264,7 +1261,7 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) {
- + * 사업기간 @@ -1286,7 +1283,7 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { - + * 사업내용 @@ -1299,22 +1296,24 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { - 구분 + 구분
{taskSeComCdNm}
- 신청 지자체 + 신청 지자체 {isModifyMode ? `${currentDet?.sido ?? "-"} ${currentDet?.gugun ?? "-"}` - : userInfo?.laeSeNm ?? "\u00A0"} + : (userInfo?.laeSeNm ?? "\u00A0")} - *사업구분 + + *사업구분 +
{[ @@ -1346,31 +1345,47 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { - - + + - + - + - - + + - - + + - + - - + +
신청자이름 + 신청자 + 이름 - {aplcntNm || userInfo?.userName || "\u00A0"} + + {aplcntNm || userInfo?.userName || "\u00A0"} + 전화번호전화번호 - {aplcntMblTelno || userInfo?.mphn || userInfo?.telno || "\u00A0"} + + {aplcntMblTelno || userInfo?.mphn || userInfo?.telno || "\u00A0"} +
부서부서 - {aplcntOgdpNm || userInfo?.instSeNm || "\u00A0"} + + {aplcntOgdpNm || userInfo?.instSeNm || "\u00A0"} + 이메일이메일 - {aplcntEmlAddr || userInfo?.email || "\u00A0"} + + {aplcntEmlAddr || userInfo?.email || "\u00A0"} +
설계자이름 + 설계자 + 이름 setDsgnrNm(e.target.value)} /> 전화번호전화번호 setDsgnrPsitn(e.target.value)} /> 이메일이메일

[ 개인정보 수집항목 ]

- * 필수항목 : 소속기관, 소속부서, 담당자, 직급, 사무실 번호, FAX 번호
- ․ 선택항목 : 휴대폰 번호, 이메일 주소
- ․ 기타항목 : IP Address, 쿠키, 시스템 접속 및 이용 기록
- ※ 시스템 이용과정에서 기타 항목의 정보들이 자동으로 생성되어 수집될 수 있습니다. + * 필수항목 : 소속기관, 소속부서, 담당자, 직급, 사무실 번호, FAX 번호 +
+ ․ 선택항목 : 휴대폰 번호, 이메일 주소 +
+ ․ 기타항목 : IP Address, 쿠키, 시스템 접속 및 이용 기록 +
※ 시스템 이용과정에서 기타 항목의 정보들이 자동으로 생성되어 수집될 수 있습니다.

[ 개인정보 이용목적 ]

- ․ 국가하수도정보시스템 웹서비스 이용에 따른 본인 확인 절차에 이용
- ․ 국가하수도정보시스템 사용에 필요한 권한 부여
- ․ 사용자별 맞춤 컨텐츠 (처리시설의 운영 데이터 조회, 수질현황 데이터 조회, 예산 편성 / 예산편성 등) 제공에 이용 + ․ 국가하수도정보시스템 웹서비스 이용에 따른 본인 확인 절차에 이용 +
+ ․ 국가하수도정보시스템 사용에 필요한 권한 부여 +
․ 사용자별 맞춤 컨텐츠 (처리시설의 운영 데이터 조회, 수질현황 데이터 조회, 예산 편성 + / 예산편성 등) 제공에 이용
● 개인정보의 보유 및 이용기간
- ․ 수집된 고객의 개인정보는 2년 동안 보유하며 그 이후에는 문서를 파쇄합니다.
- ․ 정보제공자가 개인정보 파쇄를 요청할 경우 즉시 파쇄합니다. + ․ 수집된 고객의 개인정보는 2년 동안 보유하며 그 이후에는 문서를 파쇄합니다. +
․ 정보제공자가 개인정보 파쇄를 요청할 경우 즉시 파쇄합니다.

● 개인정보 제공 거부에 따른 제한사항
- ․ 귀하는 개인정보 제공 동의를 거부할 권리가 있으나, 동의 거부 시 국가하수도정보시스템 이용 서비스에 제한이 있을 수 있습니다. + ․ 귀하는 개인정보 제공 동의를 거부할 권리가 있으나, 동의 거부 시 국가하수도정보시스템 이용 + 서비스에 제한이 있을 수 있습니다.
@@ -1613,25 +1633,27 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) {

체크리스트

-
- {Array.from(new Set((cklstTree ?? []).map((r) => (r as any).taskSeComCd).filter(Boolean))).map( - (code) => { - const name = TASK_CODE_LABELS[code] ?? code; - const active = selectedTaskCode === code; - return ( - - ); - }, - )} +
+ {Array.from( + new Set((cklstTree ?? []).map((r) => (r as any).taskSeComCd).filter(Boolean)), + ).map((code) => { + const name = TASK_CODE_LABELS[code] ?? code; + const active = selectedTaskCode === code; + return ( + + ); + })}
{`(${cklstStats.completed}/${cklstStats.total})`}
@@ -1663,8 +1685,9 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { )}
- 체크리스트 진행상황 [{selectedReviewStep}] — 총합: {cklstStats.total} · 완료: {" "} - {cklstStats.completed} · 진행률: {cklstStats.percent}% + 체크리스트 진행상황 [{selectedReviewStep}] — 총합: {cklstStats.total} · + 완료: {cklstStats.completed} · 진행률:{" "} + {cklstStats.percent}%
@@ -1729,7 +1752,7 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { cklstRows.map((row) => { const key = cklstKey(row, selectedReviewStep); const rvwPaddingLeft = `${Math.max(0, row.treeLevel - 1) * 16 + 8}px`; - //bchckUseYn 의 값이 "Y"인 항목은 라디오 박스가 보이고 없으면 안보이게 처리 + //bchckUseYn 의 값이 "Y"인 항목은 라디오 박스가 보이고 없으면 안보이게 처리 const showRadios = row.bchckUseYn === "Y"; return ( - @@ -1758,7 +1784,9 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { value="Y" checked={checkResults[key] === "Y"} disabled={editableReviewStep !== selectedReviewStep} - onChange={() => setCheckResults((prev) => ({ ...prev, [key]: "Y" }))} + onChange={() => + setCheckResults((prev) => ({ ...prev, [key]: "Y" })) + } /> @@ -1770,14 +1798,16 @@ function CnfmRegistPage({ initialData }: { initialData?: any } = {}) { value="N" checked={checkResults[key] === "N"} disabled={editableReviewStep !== selectedReviewStep} - onChange={() => setCheckResults((prev) => ({ ...prev, [key]: "N" }))} + onChange={() => + setCheckResults((prev) => ({ ...prev, [key]: "N" })) + } /> )} - - {showRadios && selectedReviewStep !== "LOCAL" ? ( + + {showRadios && selectedReviewStep !== "LOCAL" ? (
{row.cklstArtclNm} + {row.treeLevel > 1 ? "└ " : ""} {row.rvwCn}