461 lines
12 KiB
TypeScript
461 lines
12 KiB
TypeScript
import type {
|
|
ExmnBusiness,
|
|
ExmnBusinessDetail,
|
|
ExmnImportValidationResult,
|
|
ExmnJobType,
|
|
ExmnSectionSummaryRow,
|
|
} from "./exmn-business-types";
|
|
import {
|
|
EXMN_DETAIL_SEVERITIES,
|
|
EXMN_DETAIL_TABLE_DEFINITIONS,
|
|
type ExmnPplUnitDetailRow,
|
|
type ExmnSeverityCounts,
|
|
type ExmnSurveyDetailRow,
|
|
} from "./exmn-detail-table";
|
|
import type { TrtdstSettingDto } from "./trtdst-types";
|
|
|
|
/** 백엔드 데이터가 준비되기 전 명시적 sample=Y 화면 검증에서만 사용하는 조사사업 목록이다. */
|
|
export const EXMN_SAMPLE_BUSINESSES: ExmnBusiness[] = [
|
|
{
|
|
exmnBizId: "SAMPLE-BIZ-001",
|
|
bizYr: "2026",
|
|
bizNm: "2026년 양평군 노후 하수관로 정밀조사사업",
|
|
bizCycl: 3,
|
|
ctpvNm: "경기도",
|
|
sggNm: "양평군",
|
|
trtdstCnt: 10,
|
|
prcisExmnPrlg: 18.42,
|
|
tpco: 1_250_000_000,
|
|
reportYn: "Y",
|
|
bizRptpAtchFileCd: "SAMPLE",
|
|
bizRptpAtchFileId: "SAMPLE-REPORT-001",
|
|
},
|
|
{
|
|
exmnBizId: "SAMPLE-BIZ-002",
|
|
bizYr: "2025",
|
|
bizNm: "2025년 이천시 하수관로 CCTV 조사사업",
|
|
bizCycl: 2,
|
|
ctpvNm: "경기도",
|
|
sggNm: "이천시",
|
|
trtdstCnt: 10,
|
|
prcisExmnPrlg: 12.75,
|
|
tpco: 890_000_000,
|
|
reportYn: "N",
|
|
},
|
|
{
|
|
exmnBizId: "SAMPLE-BIZ-003",
|
|
bizYr: "2024",
|
|
bizNm: "2024년 원주시 관로·맨홀 정밀조사사업",
|
|
bizCycl: 1,
|
|
ctpvNm: "강원특별자치도",
|
|
sggNm: "원주시",
|
|
trtdstCnt: 10,
|
|
prcisExmnPrlg: 15.1,
|
|
tpco: 1_030_000_000,
|
|
reportYn: "Y",
|
|
bizRptpAtchFileCd: "SAMPLE",
|
|
bizRptpAtchFileId: "SAMPLE-REPORT-003",
|
|
},
|
|
{
|
|
exmnBizId: "SAMPLE-BIZ-004",
|
|
bizYr: "2023",
|
|
bizNm: "2023년 청주시 하수관로 정밀조사사업",
|
|
bizCycl: 4,
|
|
ctpvNm: "충청북도",
|
|
sggNm: "청주시",
|
|
trtdstCnt: 10,
|
|
prcisExmnPrlg: 9.86,
|
|
tpco: 760_000_000,
|
|
reportYn: "N",
|
|
},
|
|
];
|
|
|
|
/** 사업등록 팝업의 체크박스·가나다순 정렬을 검증하는 활성 처리분구 샘플이다. */
|
|
export const EXMN_SAMPLE_TRTDST_SETTINGS: TrtdstSettingDto[] = [
|
|
"갈산처리분구",
|
|
"개군처리분구",
|
|
"공흥처리분구",
|
|
"국수처리분구",
|
|
"단월처리분구",
|
|
"덕평처리분구",
|
|
"문호처리분구",
|
|
"백안처리분구",
|
|
"서종처리분구",
|
|
"양근처리분구",
|
|
"양동처리분구",
|
|
"양서처리분구",
|
|
"오빈처리분구",
|
|
"용문처리분구",
|
|
"용천처리분구",
|
|
"지평처리분구",
|
|
"청운처리분구",
|
|
"회현처리분구",
|
|
"강상처리분구",
|
|
"강하처리분구",
|
|
"옥천처리분구",
|
|
].map((trtdstNm, index) => ({
|
|
trtdstId: `SAMPLE-TRTDST-${String(index + 1).padStart(2, "0")}`,
|
|
ctpvNm: "경기도",
|
|
sggNm: "양평군",
|
|
trtdstNm,
|
|
useYn: "Y",
|
|
}));
|
|
|
|
/** 선택 사업의 처리분구와 첨부 영역을 팝업에서 확인할 수 있도록 상세 샘플을 만든다. */
|
|
export const getExmnSampleBusinessDetail = (
|
|
exmnBizId: string,
|
|
fallbackBusiness?: ExmnBusiness,
|
|
): ExmnBusinessDetail => {
|
|
const business = EXMN_SAMPLE_BUSINESSES.find((item) => item.exmnBizId === exmnBizId)
|
|
?? fallbackBusiness
|
|
?? EXMN_SAMPLE_BUSINESSES[0];
|
|
const districts = EXMN_SAMPLE_TRTDST_SETTINGS.slice(0, business.trtdstCnt).map((item) => ({
|
|
trtdstId: item.trtdstId,
|
|
trtdstNm: item.trtdstNm,
|
|
pplExmnSheetNm: `${item.trtdstNm}_PPL`,
|
|
mnhlExmnSheetNm: `${item.trtdstNm}_MNHL`,
|
|
}));
|
|
|
|
return {
|
|
...business,
|
|
trtdstIds: districts.map((item) => item.trtdstId),
|
|
districts,
|
|
};
|
|
};
|
|
|
|
/** 결과등록 팝업의 데이터 검토·저장 활성 상태를 확인하는 정상 샘플 결과다. */
|
|
export const EXMN_SAMPLE_IMPORT_VALIDATION: ExmnImportValidationResult = {
|
|
valid: true,
|
|
fileHash: "SAMPLE-FILE-HASH-PREVIEW",
|
|
summary: {
|
|
pplCount: 24,
|
|
mnhlCount: 12,
|
|
},
|
|
errors: [],
|
|
};
|
|
|
|
/** 조사현황의 사업 행 선택과 관로·맨홀 탭 전환을 검증하는 처리분구 집계 샘플이다. */
|
|
export const getExmnSampleSectionSummaries = (
|
|
exmnBizId: string,
|
|
jobType: ExmnJobType,
|
|
): ExmnSectionSummaryRow[] => {
|
|
const business = EXMN_SAMPLE_BUSINESSES.find((item) => item.exmnBizId === exmnBizId)
|
|
?? EXMN_SAMPLE_BUSINESSES[0];
|
|
const districts = EXMN_SAMPLE_TRTDST_SETTINGS.slice(0, business.trtdstCnt);
|
|
|
|
return districts.map((district, index) => {
|
|
const scale = index + 1;
|
|
const pplStructural = 21 * scale;
|
|
const pplOperational = 7 * scale;
|
|
const pplEtc = 2 * scale;
|
|
const mnhlStructural = 5 * scale;
|
|
const mnhlOperational = 3 * scale;
|
|
const mnhlEtc = scale;
|
|
|
|
return {
|
|
trtdstId: district.trtdstId,
|
|
trtdstNm: district.trtdstNm,
|
|
trgtPrlg: Number((business.prcisExmnPrlg * 1000 / districts.length).toFixed(1)),
|
|
drvngDstnc: Number((business.prcisExmnPrlg * 930 / districts.length).toFixed(1)),
|
|
pplExmnWholAnmlyArtclCnt: jobType === "PPL" ? pplStructural + pplOperational + pplEtc : 0,
|
|
pplExmnStrctDfcCnt: jobType === "PPL" ? pplStructural : 0,
|
|
pplExmnOperDfcCnt: jobType === "PPL" ? pplOperational : 0,
|
|
pplExmnEtcCnt: jobType === "PPL" ? pplEtc : 0,
|
|
mnhlExmnWholAnmlyArtclCnt: jobType === "MNHL" ? mnhlStructural + mnhlOperational + mnhlEtc : 0,
|
|
mnhlExmnStrctDfcCnt: jobType === "MNHL" ? mnhlStructural : 0,
|
|
mnhlExmnOperDfcCnt: jobType === "MNHL" ? mnhlOperational : 0,
|
|
mnhlExmnEtcCnt: jobType === "MNHL" ? mnhlEtc : 0,
|
|
};
|
|
});
|
|
};
|
|
|
|
const EMPTY_SEVERITY_COUNTS: ExmnSeverityCounts = { L: 0, M: 0, S: 0 };
|
|
|
|
/** 열 코드와 행 순번으로 화면 확인용 희소 결함 건수를 일관되게 만든다. */
|
|
const buildSampleDefectCounts = (
|
|
jobType: ExmnJobType,
|
|
rowIndex: number,
|
|
): Record<string, ExmnSeverityCounts> => Object.fromEntries(
|
|
EXMN_DETAIL_TABLE_DEFINITIONS[jobType].defectColumns.map((column, columnIndex) => {
|
|
const counts = { ...EMPTY_SEVERITY_COUNTS };
|
|
EXMN_DETAIL_SEVERITIES.forEach((severity, severityIndex) => {
|
|
const seed = columnIndex + rowIndex * 3 + severityIndex;
|
|
if (seed % 11 === 0) {
|
|
counts[severity] = rowIndex + severityIndex + 1;
|
|
}
|
|
});
|
|
return [column.code, counts];
|
|
}),
|
|
);
|
|
|
|
/** 코드별 건수를 합산해 엑셀의 이상항목 합계 대·중·소 샘플을 만든다. */
|
|
const sumSampleDefects = (
|
|
defectCounts: Record<string, ExmnSeverityCounts>,
|
|
): ExmnSeverityCounts => EXMN_DETAIL_SEVERITIES.reduce(
|
|
(totals, severity) => {
|
|
totals[severity] = Object.values(defectCounts).reduce(
|
|
(sum, counts) => sum + counts[severity],
|
|
0,
|
|
);
|
|
return totals;
|
|
},
|
|
{ ...EMPTY_SEVERITY_COUNTS },
|
|
);
|
|
|
|
const SAMPLE_FACILITIES = [
|
|
{
|
|
reportNo: "118-0026",
|
|
pipeNo: "118-0026",
|
|
upstreamManhole: "118-0026M",
|
|
downstreamManhole: "118-0027M",
|
|
extensionM: 25.5,
|
|
drivingDistanceM: 25.5,
|
|
},
|
|
{
|
|
reportNo: "118-0027",
|
|
pipeNo: "118-0027",
|
|
upstreamManhole: "118-0027M",
|
|
downstreamManhole: "118-0028M",
|
|
extensionM: 27,
|
|
drivingDistanceM: 27,
|
|
},
|
|
{
|
|
reportNo: "118-0027-1",
|
|
pipeNo: "118-0027-1",
|
|
upstreamManhole: "118-0027-1M",
|
|
downstreamManhole: "118-0028M",
|
|
extensionM: 13.9,
|
|
drivingDistanceM: 13.9,
|
|
},
|
|
] as const;
|
|
|
|
/** 상세보기 WindowPopup에서 관로·맨홀 엑셀형 표를 확인하는 샘플 3행이다. */
|
|
export const getExmnSampleSurveyDetails = (
|
|
jobType: ExmnJobType,
|
|
): ExmnSurveyDetailRow[] => SAMPLE_FACILITIES.map((facility, rowIndex) => {
|
|
const defectCounts = buildSampleDefectCounts(jobType, rowIndex);
|
|
const anomalyTotals = sumSampleDefects(defectCounts);
|
|
return {
|
|
...facility,
|
|
drainageType: "합류",
|
|
pipeType: "HP",
|
|
specification: 600,
|
|
anomalyTotals,
|
|
defectCounts,
|
|
};
|
|
});
|
|
|
|
/** 엑셀 `본단위등급표`의 한 관로를 단위구간별 병합 표로 확인하는 샘플 원형이다. */
|
|
const EXMN_SAMPLE_PPL_UNIT_DETAIL_TEMPLATE: ExmnPplUnitDetailRow[] = [
|
|
{
|
|
pipeNo: "118-0026",
|
|
unitSeq: 1,
|
|
unitLengthM: 6,
|
|
defectPositionM: 0,
|
|
defectName: "(상태)조사시작(순주행)",
|
|
code: "IS",
|
|
recordType: "STATUS",
|
|
defectType: null,
|
|
severity: null,
|
|
occurrencePosition: "0/0",
|
|
infiltrationBonus: 0,
|
|
continuous: null,
|
|
structuralScore: null,
|
|
operationalScore: null,
|
|
surveyStopReason: null,
|
|
remark: null,
|
|
},
|
|
{
|
|
pipeNo: "118-0026",
|
|
unitSeq: 1,
|
|
unitLengthM: 6,
|
|
defectPositionM: 5.4,
|
|
defectName: "(관로)변형",
|
|
code: "DF",
|
|
recordType: "DEFECT",
|
|
defectType: "STRUCTURAL",
|
|
severity: "S",
|
|
occurrencePosition: "10/2",
|
|
infiltrationBonus: 0,
|
|
continuous: false,
|
|
structuralScore: 25,
|
|
operationalScore: null,
|
|
surveyStopReason: null,
|
|
remark: null,
|
|
},
|
|
{
|
|
pipeNo: "118-0026",
|
|
unitSeq: 1,
|
|
unitLengthM: 6,
|
|
defectPositionM: 6,
|
|
defectName: "(관로)이음부이탈",
|
|
code: "JS",
|
|
recordType: "DEFECT",
|
|
defectType: "STRUCTURAL",
|
|
severity: "L",
|
|
occurrencePosition: "4/6",
|
|
infiltrationBonus: 0,
|
|
continuous: null,
|
|
structuralScore: 35,
|
|
operationalScore: null,
|
|
surveyStopReason: null,
|
|
remark: null,
|
|
},
|
|
{
|
|
pipeNo: "118-0026",
|
|
unitSeq: 1,
|
|
unitLengthM: 6,
|
|
defectPositionM: 6,
|
|
defectName: "(상태)이음부(접합부)존재",
|
|
code: "JE",
|
|
recordType: "STATUS",
|
|
defectType: null,
|
|
severity: null,
|
|
occurrencePosition: "0/0",
|
|
infiltrationBonus: 0,
|
|
continuous: null,
|
|
structuralScore: null,
|
|
operationalScore: null,
|
|
surveyStopReason: null,
|
|
remark: null,
|
|
},
|
|
{
|
|
pipeNo: "118-0026",
|
|
unitSeq: 2,
|
|
unitLengthM: 6,
|
|
defectPositionM: 6,
|
|
defectName: "(상태)이음부(접합부)존재",
|
|
code: "JE",
|
|
recordType: "STATUS",
|
|
defectType: null,
|
|
severity: null,
|
|
occurrencePosition: "0/0",
|
|
infiltrationBonus: 0,
|
|
continuous: null,
|
|
structuralScore: null,
|
|
operationalScore: null,
|
|
surveyStopReason: null,
|
|
remark: null,
|
|
},
|
|
{
|
|
pipeNo: "118-0026",
|
|
unitSeq: 2,
|
|
unitLengthM: 6,
|
|
defectPositionM: 6,
|
|
defectName: "(관로)이음부이탈",
|
|
code: "JS",
|
|
recordType: "DEFECT",
|
|
defectType: "STRUCTURAL",
|
|
severity: "L",
|
|
occurrencePosition: "4/6",
|
|
infiltrationBonus: 0,
|
|
continuous: null,
|
|
structuralScore: 35,
|
|
operationalScore: null,
|
|
surveyStopReason: null,
|
|
remark: null,
|
|
},
|
|
{
|
|
pipeNo: "118-0026",
|
|
unitSeq: 2,
|
|
unitLengthM: 6,
|
|
defectPositionM: 7,
|
|
defectName: "(관로)균열원주",
|
|
code: "CC",
|
|
recordType: "DEFECT",
|
|
defectType: "STRUCTURAL",
|
|
severity: "L",
|
|
occurrencePosition: "11/12",
|
|
infiltrationBonus: 0,
|
|
continuous: null,
|
|
structuralScore: 40,
|
|
operationalScore: null,
|
|
surveyStopReason: null,
|
|
remark: null,
|
|
},
|
|
{
|
|
pipeNo: "118-0026",
|
|
unitSeq: 2,
|
|
unitLengthM: 6,
|
|
defectPositionM: 9.7,
|
|
defectName: "(관로)균열원주",
|
|
code: "CC",
|
|
recordType: "DEFECT",
|
|
defectType: "STRUCTURAL",
|
|
severity: "L",
|
|
occurrencePosition: "7/8",
|
|
infiltrationBonus: 0,
|
|
continuous: null,
|
|
structuralScore: 40,
|
|
operationalScore: null,
|
|
surveyStopReason: null,
|
|
remark: null,
|
|
},
|
|
{
|
|
pipeNo: "118-0026",
|
|
unitSeq: 2,
|
|
unitLengthM: 6,
|
|
defectPositionM: 11.6,
|
|
defectName: "(관로)변형",
|
|
code: "DF",
|
|
recordType: "DEFECT",
|
|
defectType: "STRUCTURAL",
|
|
severity: "S",
|
|
occurrencePosition: "10/12",
|
|
infiltrationBonus: 0,
|
|
continuous: false,
|
|
structuralScore: 25,
|
|
operationalScore: null,
|
|
surveyStopReason: null,
|
|
remark: null,
|
|
},
|
|
{
|
|
pipeNo: "118-0026",
|
|
unitSeq: 2,
|
|
unitLengthM: 6,
|
|
defectPositionM: 12,
|
|
defectName: "(관로)이음부이탈",
|
|
code: "JS",
|
|
recordType: "DEFECT",
|
|
defectType: "STRUCTURAL",
|
|
severity: "L",
|
|
occurrencePosition: "5/7",
|
|
infiltrationBonus: 0,
|
|
continuous: null,
|
|
structuralScore: 35,
|
|
operationalScore: null,
|
|
surveyStopReason: null,
|
|
remark: null,
|
|
},
|
|
{
|
|
pipeNo: "118-0026",
|
|
unitSeq: 2,
|
|
unitLengthM: 6,
|
|
defectPositionM: 12,
|
|
defectName: "(상태)이음부(접합부)존재",
|
|
code: "JE",
|
|
recordType: "STATUS",
|
|
defectType: null,
|
|
severity: null,
|
|
occurrencePosition: "0/0",
|
|
infiltrationBonus: 0,
|
|
continuous: null,
|
|
structuralScore: null,
|
|
operationalScore: null,
|
|
surveyStopReason: null,
|
|
remark: null,
|
|
},
|
|
];
|
|
|
|
/**
|
|
* 본단위구간 모드 최초 진입 시 처리분구의 관리번호 전체가 보이도록
|
|
* 관로 상세 샘플 3건에 동일한 단위구간 원형을 적용한다.
|
|
*/
|
|
export const EXMN_SAMPLE_PPL_UNIT_DETAILS: ExmnPplUnitDetailRow[] =
|
|
SAMPLE_FACILITIES.flatMap((facility) =>
|
|
EXMN_SAMPLE_PPL_UNIT_DETAIL_TEMPLATE.map((row) => ({
|
|
...row,
|
|
pipeNo: facility.pipeNo,
|
|
})),
|
|
);
|