feat(sn): CS 기준 UI 통일 및 지도 팝업 표준화

This commit is contained in:
2026-08-20 14:57:20 +09:00
parent c9e3ff0d91
commit 0cbbc3b934
167 changed files with 21191 additions and 14161 deletions
@@ -49,7 +49,9 @@ const unwrapData = <T>(response: T | { data?: T }): T =>
: (response as T);
/** Spring Page 응답이 비어 있거나 아직 미구현이어도 안전한 빈 Page로 정규화한다. */
const toPage = <T>(value: Partial<ExmnPage<T>> | null | undefined): ExmnPage<T> => ({
const toPage = <T>(
value: Partial<ExmnPage<T>> | null | undefined,
): ExmnPage<T> => ({
content: Array.isArray(value?.content) ? value.content : [],
totalElements: Number(value?.totalElements ?? 0),
number: Number(value?.number ?? 0),
@@ -66,25 +68,33 @@ const getBusinessReportFileName = async (
attachmentId: string,
): Promise<string | null> => {
try {
const response = await getRawJson(
const response = (await getRawJson(
`/attach-service/api/v1/atfl/attachments/${encodeURIComponent(attachmentCode)}`,
) as AttachmentMetadata[]
)) as
| AttachmentMetadata[]
| { data?: AttachmentMetadata[] | { content?: AttachmentMetadata[] } }
| { content?: AttachmentMetadata[] }
| null;
const payload = (
typeof response === "object"
&& response !== null
&& !Array.isArray(response)
&& "data" in response
) ? response.data : response;
let payload:
| AttachmentMetadata[]
| { content?: AttachmentMetadata[] }
| null
| undefined;
if (Array.isArray(response)) {
payload = response;
} else if (response && "data" in response) {
payload = response.data;
} else {
payload = response as { content?: AttachmentMetadata[] } | null;
}
const attachments = Array.isArray(payload)
? payload
: Array.isArray(payload?.content)
? payload.content
: [];
const attachment = attachments.find((item) => item.atflId === attachmentId)
?? attachments[0];
const attachment =
attachments.find((item) => item.atflId === attachmentId) ??
attachments[0];
return attachment?.orgnlFileNm?.trim() || null;
} catch {
return null;
@@ -109,15 +119,20 @@ export const getExmnBusinesses = async (
const page = toPage<ExmnBusiness>(
await getData(`${EXMN_BUSINESS_API_PATH}?${query}`),
);
const content = await Promise.all(page.content.map(async (business) => {
const attachmentCode = business.bizRptpAtchFileCd?.trim();
const attachmentId = business.bizRptpAtchFileId?.trim();
if (!attachmentCode || !attachmentId) return business;
return {
...business,
bizRptpFileName: await getBusinessReportFileName(attachmentCode, attachmentId),
};
}));
const content = await Promise.all(
page.content.map(async (business) => {
const attachmentCode = business.bizRptpAtchFileCd?.trim();
const attachmentId = business.bizRptpAtchFileId?.trim();
if (!attachmentCode || !attachmentId) return business;
return {
...business,
bizRptpFileName: await getBusinessReportFileName(
attachmentCode,
attachmentId,
),
};
}),
);
return { ...page, content };
};
@@ -126,11 +141,13 @@ export const getExmnSectionSummaries = async (
exmnBizId: string,
jobType: ExmnJobType,
): Promise<ExmnSectionSummaryRow[]> => {
type SectionSummaryPayload = ExmnSectionSummaryRow[] | Partial<ExmnPage<ExmnSectionSummaryRow>>;
type SectionSummaryPayload =
| ExmnSectionSummaryRow[]
| Partial<ExmnPage<ExmnSectionSummaryRow>>;
try {
const response = await getData(
const response = (await getData(
`${EXMN_BUSINESS_API_PATH}/${encodeURIComponent(exmnBizId)}/sections?jobType=${jobType}`,
) as SectionSummaryPayload | { data?: SectionSummaryPayload };
)) as SectionSummaryPayload | { data?: SectionSummaryPayload };
const payload = unwrapData<SectionSummaryPayload>(response);
if (Array.isArray(payload)) return payload;
return Array.isArray(payload?.content) ? payload.content : [];
@@ -174,8 +191,9 @@ export const getExmnFacilityDetails = async (params: {
if (params.defectType && params.defectType !== "ALL") {
query.set("defectType", params.defectType);
}
const response = await getData(`v1/exmnFacilities?${query}`) as
ExmnSurveyDetailRow[] | { data?: ExmnSurveyDetailRow[] };
const response = (await getData(`v1/exmnFacilities?${query}`)) as
| ExmnSurveyDetailRow[]
| { data?: ExmnSurveyDetailRow[] };
const payload = unwrapData<ExmnSurveyDetailRow[]>(response);
return Array.isArray(payload) ? payload : [];
};
@@ -234,8 +252,9 @@ export const getExmnPplUnitDetails = async (params: {
if (params.gisManagementNo?.trim()) {
query.set("gisManagementNo", params.gisManagementNo.trim());
}
const response = await getData(`v1/exmnFacilities/pplUnitSections?${query}`) as
ExmnPplUnitDetailPayload[] | { data?: ExmnPplUnitDetailPayload[] };
const response = (await getData(
`v1/exmnFacilities/pplUnitSections?${query}`,
)) as ExmnPplUnitDetailPayload[] | { data?: ExmnPplUnitDetailPayload[] };
const payload = unwrapData<ExmnPplUnitDetailPayload[]>(response);
if (!Array.isArray(payload)) return [];
return payload.map((row) => ({
@@ -245,14 +264,20 @@ export const getExmnPplUnitDetails = async (params: {
};
/** 선택한 조사사업의 처리분구·첨부를 포함한 상세정보를 조회한다. */
export const getExmnBusiness = async (exmnBizId: string): Promise<ExmnBusinessDetail> =>
getData(`${EXMN_BUSINESS_API_PATH}/${encodeURIComponent(exmnBizId)}`) as Promise<ExmnBusinessDetail>;
export const getExmnBusiness = async (
exmnBizId: string,
): Promise<ExmnBusinessDetail> =>
getData(
`${EXMN_BUSINESS_API_PATH}/${encodeURIComponent(exmnBizId)}`,
) as Promise<ExmnBusinessDetail>;
/** 조사사업과 선택 처리분구별 기본 요약행을 신규 저장한다. */
export const createExmnBusiness = async (
request: ExmnBusinessSaveRequest,
): Promise<ExmnBusinessDetail> =>
unwrapData<ExmnBusinessDetail>(await postRawJson(EXMN_BUSINESS_API_PATH, request));
unwrapData<ExmnBusinessDetail>(
await postRawJson(EXMN_BUSINESS_API_PATH, request),
);
/** 기존 조사사업 기본정보와 연결 처리분구를 같은 저장 계약으로 갱신한다. */
export const updateExmnBusiness = async (
@@ -269,22 +294,30 @@ export const createExmnTemplates = async (
exmnBizId: string,
trtdstIds: string[],
): Promise<ExmnTemplateResult> =>
unwrapData<ExmnTemplateResult>(await postRawJson(
`${EXMN_BUSINESS_API_PATH}/${encodeURIComponent(exmnBizId)}/templates`,
{ trtdstIds },
));
unwrapData<ExmnTemplateResult>(
await postRawJson(
`${EXMN_BUSINESS_API_PATH}/${encodeURIComponent(exmnBizId)}/templates`,
{ trtdstIds },
),
);
/** 생성된 조사사업 입력 양식 파일을 내려받는다. */
export const downloadExmnTemplates = async (exmnBizId: string): Promise<Blob> =>
getBlobData(`${EXMN_BUSINESS_API_PATH}/${encodeURIComponent(exmnBizId)}/templates/download`);
getBlobData(
`${EXMN_BUSINESS_API_PATH}/${encodeURIComponent(exmnBizId)}/templates/download`,
);
/** 하수관로·맨홀 현황조사 보고서 기준 XLSX를 내려받는다. */
export const downloadExmnReportTemplate = async (): Promise<Blob> =>
getBlobData(`${EXMN_BUSINESS_API_PATH}/templates/report/download`);
/** 사업보고서 첨부파일 ID로 기존 첨부서비스의 원본 파일을 내려받는다. */
export const downloadExmnBusinessReport = async (attachmentId: string): Promise<Blob> =>
getBlobData(`/attach-service/api/v1/download/${encodeURIComponent(attachmentId)}`);
export const downloadExmnBusinessReport = async (
attachmentId: string,
): Promise<Blob> =>
getBlobData(
`/attach-service/api/v1/download/${encodeURIComponent(attachmentId)}`,
);
/** 저장된 페이지 범위를 이용해 선택 관로의 조사보고서 구간만 PDF로 조회한다. */
export const downloadExmnPipeReport = async (
@@ -339,12 +372,17 @@ export const getPplSummaries = async (
exmnBizId: string,
params: { trtdstId?: string; page: number; size: number; sort?: string },
): Promise<ExmnPage<PplSummaryRow>> => {
const query = new URLSearchParams({ page: String(params.page), size: String(params.size) });
const query = new URLSearchParams({
page: String(params.page),
size: String(params.size),
});
if (params.trtdstId) query.set("trtdstId", params.trtdstId);
if (params.sort) query.set("sort", params.sort);
return toPage<PplSummaryRow>(await getData(
`${EXMN_BUSINESS_API_PATH}/${encodeURIComponent(exmnBizId)}/summaries/ppl?${query}`,
));
return toPage<PplSummaryRow>(
await getData(
`${EXMN_BUSINESS_API_PATH}/${encodeURIComponent(exmnBizId)}/summaries/ppl?${query}`,
),
);
};
/** 선택 사업의 PPL 시설을 처리분구·구간·GIS번호·등급으로 조회한다. */
@@ -359,10 +397,14 @@ export const getPplFacilities = async (
});
if (params.trtdstId) query.set("trtdstId", params.trtdstId);
if (params.sectionType) query.set("sectionType", params.sectionType);
if (params.gisManagementNo?.trim()) query.set("gisManagementNo", params.gisManagementNo.trim());
if (params.structuralGrade) query.set("structuralGrade", params.structuralGrade);
if (params.operationalGrade) query.set("operationalGrade", params.operationalGrade);
if (params.defectType && params.defectType !== "ALL") query.set("defectType", params.defectType);
if (params.gisManagementNo?.trim())
query.set("gisManagementNo", params.gisManagementNo.trim());
if (params.structuralGrade)
query.set("structuralGrade", params.structuralGrade);
if (params.operationalGrade)
query.set("operationalGrade", params.operationalGrade);
if (params.defectType && params.defectType !== "ALL")
query.set("defectType", params.defectType);
if (params.sort) query.set("sort", params.sort);
return toPage<PplFacility>(await getData(`v1/exmnFacilities?${query}`));
};
@@ -376,5 +418,7 @@ export const downloadPplExport = async (
if (trtdstId) query.set("trtdstId", trtdstId);
const queryString = query.toString();
const suffix = queryString ? `?${queryString}` : "";
return getBlobData(`${EXMN_BUSINESS_API_PATH}/${encodeURIComponent(exmnBizId)}/exports/ppl${suffix}`);
return getBlobData(
`${EXMN_BUSINESS_API_PATH}/${encodeURIComponent(exmnBizId)}/exports/ppl${suffix}`,
);
};