Files
frontend/apps/sn/app/html/(map-layout)/aged-pipe/agedPipeUtils.ts
T

222 lines
7.3 KiB
TypeScript

"use client";
import type { SelectDataType } from "@common/business_components";
import { formatDisplayData } from "@/components/lib/utils/formatDisplayValue";
import {
MS_SWAGE_PPL_CODES,
MS_SWAGE_PPL_USE_CODES,
MsSwagePplCol,
} from "../map/components/common/table";
export type AgedPipeFilters = {
elapsedYears: number;
ctpvCd: string;
sggCd: string;
};
export type AgedPipeRow = {
fid: string;
lyrTypeNm: string;
rowNumber: number;
fcltMngNo: string;
instlYmd: string;
pdmtVl: string | number;
prlgVl: string | number;
usgCd: string;
mqltCd: string;
elapsedYears: number | string;
ctpvNm?: string;
sggNm?: string;
[key: string]: unknown;
};
type PipeSource = Record<string, unknown>;
const useMap = new Map(MS_SWAGE_PPL_USE_CODES.map((item) => [item.val.trim(), item.text]));
const materialMap = new Map(MS_SWAGE_PPL_CODES.map((item) => [item.val.trim(), item.text]));
export const AGED_PIPE_DEFAULT_FILTERS: AgedPipeFilters = {
elapsedYears: 20,
ctpvCd: "0",
sggCd: "0",
};
export const AGED_PIPE_LIST_HEADLIST = [
{ id: "rowNumber", title: "NO", widthPercent: 6 },
{ id: "fcltMngNo", title: "시설관리번호", widthPercent: 18 },
{ id: "instlYmd", title: "설치일자", widthPercent: 12 },
{ id: "pdmtVl", title: "관경(mm)", widthPercent: 10 },
{ id: "prlgVl", title: "연장(m)", widthPercent: 10 },
{ id: "usgCd", title: "용도", widthPercent: 14 },
{ id: "mqltCd", title: "재질", widthPercent: 18 },
{ id: "elapsedYears", title: "경과년도", widthPercent: 12, align: "right" },
];
export const AGED_PIPE_EXCEL_HEADER = {
rowNumber: "NO",
fcltMngNo: "시설관리번호",
instlYmd: "설치일자",
pdmtVl: "관경(mm)",
prlgVl: "연장(m)",
usgCd: "용도",
mqltCd: "재질",
elapsedYears: "경과년도",
};
export const AGED_PIPE_DETAIL_FIELDS = MsSwagePplCol;
const getToday = () => new Date();
const pad2 = (value: number) => String(value).padStart(2, "0");
export const getCutoffYmd = (elapsedYears: number) => {
const today = getToday();
const cutoff = new Date(today.getFullYear() - elapsedYears, today.getMonth(), today.getDate());
return `${cutoff.getFullYear()}${pad2(cutoff.getMonth() + 1)}${pad2(cutoff.getDate())}`;
};
const normalizeYmd = (value: unknown) => String(value ?? "").replace(/[^0-9]/g, "").slice(0, 8);
const getCodePrefix = (source: PipeSource) =>
String(source.pbadmsEmdCd ?? source.pbadms_emd_cd ?? "").trim();
const resolveRegionName = (
code: string,
directName: unknown,
options: SelectDataType[],
prefixLength: number,
) => {
if (String(directName ?? "").trim()) return String(directName);
const prefix = code.slice(0, prefixLength);
return options.find((item) => String(item.val).trim() === prefix)?.text ?? "";
};
export const getElapsedYears = (value: unknown) => {
const normalized = normalizeYmd(value);
if (normalized.length < 4) return null;
const year = Number(normalized.slice(0, 4));
const month = Number(normalized.slice(4, 6) || "1");
const day = Number(normalized.slice(6, 8) || "1");
if (!year) return null;
const today = getToday();
let elapsed = today.getFullYear() - year;
if (
today.getMonth() + 1 < month ||
(today.getMonth() + 1 === month && today.getDate() < day)
) {
elapsed -= 1;
}
return Math.max(elapsed, 0);
};
export const buildAgedPipeCqlFilters = (filters: AgedPipeFilters) => {
const cqlFilters: string[] = [];
cqlFilters.push(`instl_ymd <= '${getCutoffYmd(filters.elapsedYears)}'`);
if (filters.sggCd !== "0") {
cqlFilters.push(`pbadms_emd_cd LIKE '${filters.sggCd}%'`);
} else if (filters.ctpvCd !== "0") {
cqlFilters.push(`pbadms_emd_cd LIKE '${filters.ctpvCd}%'`);
}
return cqlFilters;
};
export const matchesAgedPipeFilters = (source: PipeSource, filters: AgedPipeFilters) => {
const instlYmd = normalizeYmd(source.instl_ymd ?? source.instlYmd);
if (!instlYmd || instlYmd > getCutoffYmd(filters.elapsedYears)) return false;
const regionCode = getCodePrefix(source);
if (filters.sggCd !== "0") return regionCode.startsWith(filters.sggCd);
if (filters.ctpvCd !== "0") return regionCode.startsWith(filters.ctpvCd);
return true;
};
export const toDisplayPipeRow = (
source: PipeSource,
index: number,
page: number,
ctpvOptions: SelectDataType[],
sggOptions: SelectDataType[],
): AgedPipeRow => {
const formatted = formatDisplayData(source) as PipeSource;
const codePrefix = getCodePrefix(source);
const instlYmd = formatted.instlYmd ?? source.instlYmd ?? formatted.instl_ymd ?? source.instl_ymd;
const trimmedUse = String(source.usgCd ?? source.usg_cd ?? "").trim();
const trimmedMaterial = String(source.mqltCd ?? source.mqlt_cd ?? "").trim();
const pdmtVl = formatted.pdmtVl ?? source.pdmtVl ?? source.pdmt_vl ?? "-";
const prlgVl = formatted.prlgVl ?? source.prlgVl ?? source.prlg_vl ?? "-";
return {
...source,
...formatted,
fid: String(source.fid ?? ""),
lyrTypeNm: String(source.lyrTypeNm ?? "tb_ms_swage_ppl"),
rowNumber: (page - 1) * 10 + index + 1,
fcltMngNo: String(formatted.fcltMngNo ?? source.fcltMngNo ?? source.fclt_mng_no ?? "-"),
instlYmd: String(instlYmd ?? "-"),
pdmtVl: typeof pdmtVl === "number" ? pdmtVl : String(pdmtVl),
prlgVl: typeof prlgVl === "number" ? prlgVl : String(prlgVl),
usgCd: useMap.get(trimmedUse) ?? String(formatted.usgCd ?? source.usgCd ?? source.usg_cd ?? "-"),
mqltCd:
materialMap.get(trimmedMaterial) ??
String(formatted.mqltCd ?? source.mqltCd ?? source.mqlt_cd ?? "-"),
elapsedYears: getElapsedYears(source.instlYmd ?? source.instl_ymd) ?? "-",
ctpvNm: resolveRegionName(
codePrefix,
formatted.ctpvNm ?? source.ctpvNm ?? source.ctpv_nm,
ctpvOptions,
2,
),
sggNm: resolveRegionName(
codePrefix,
formatted.sggNm ?? source.sggNm ?? source.sgg_nm,
sggOptions,
5,
),
};
};
export const getPipeDisplayValue = (source: PipeSource, key: string) => {
const formatted = formatDisplayData(source) as PipeSource;
const keyMap: Record<string, string[]> = {
fclt_mng_no: ["fclt_mng_no", "fcltMngNo"],
inst_mng_no: ["inst_mng_no", "instMngNo"],
instl_ymd: ["instl_ymd", "instlYmd"],
mapsht_no: ["mapsht_no", "mapshtNo"],
pdmt_vl: ["pdmt_vl", "pdmtVl"],
prlg_vl: ["prlg_vl", "prlgVl"],
usg_cd: ["usg_cd", "usgCd"],
mqlt_cd: ["mqlt_cd", "mqltCd"],
avg_grdn: ["avg_grdn", "avgGrdn"],
drtw_mltv_area: ["drtw_mltv_area", "drtwMltvArea"],
excln_mltv_area: ["excln_mltv_area", "exclnMltvArea"],
tmpt_dpth: ["tmpt_dpth", "tmptDpth"],
tmpt_mhl_mng_no: ["tmpt_mhl_mng_no", "tmptMhlMngNo"],
scend_dpth: ["scend_dpth", "scendDpth"],
scend_mhl_mng_no: ["scend_mhl_mng_no", "scendMhlMngNo"],
trfln_cnt: ["trfln_cnt", "trflnCnt"],
vrtc_len: ["vrtc_len", "vrtcLen"],
wdth_len: ["wdth_len", "wdthLen"],
};
const candidates = keyMap[key] ?? [key];
for (const candidate of candidates) {
const value = formatted[candidate] ?? source[candidate];
if (value !== undefined && value !== null && value !== "") {
if (candidate === "usg_cd" || candidate === "usgCd") {
return useMap.get(String(source.usg_cd ?? source.usgCd ?? "").trim()) ?? value;
}
if (candidate === "mqlt_cd" || candidate === "mqltCd") {
return materialMap.get(String(source.mqlt_cd ?? source.mqltCd ?? "").trim()) ?? value;
}
return value;
}
}
return "-";
};