feat: 상세정보 페이지 중분류 표시, 관리번호 표시 기능 추가

This commit is contained in:
swcho
2025-07-15 15:38:42 +09:00
parent 58a2b6c5c0
commit ae0384af83
2 changed files with 229 additions and 64 deletions
@@ -0,0 +1,155 @@
import { MS_SWAGE_PPL_USE_CODES, MS_SWAGE_PPL_CODES, MS_SWAGE_MHL_CODES, MS_SWAGE_MHL_USE_CODES, DRTW_SEWAGE_PUMP_USE_CODES } from './table';
interface CodeMapperProps {
layerName: string;
data: any;
}
/**
* 레이어별 코드 변환 함수
* @param layerName - 레이어 이름
* @param data - 변환할 데이터 객체
* @returns 변환된 데이터 객체
*/
export const codeMapper = ({ layerName, data }: CodeMapperProps): any => {
if (!data) return data;
const processedData = { ...data };
switch (layerName) {
case '하수관로':
// usg_cd 값 변환 (용도코드)
if (processedData.usg_cd) {
const usageCodeItem = MS_SWAGE_PPL_USE_CODES.find(
code => code.val === processedData.usg_cd.trim()
);
if (usageCodeItem) {
processedData.usg_cd = usageCodeItem.text;
}
}
// mqlt_cd 값 변환 (재질코드)
if (processedData.mqlt_cd) {
const materialCodeItem = MS_SWAGE_PPL_CODES.find(
code => code.val === processedData.mqlt_cd.trim()
);
if (materialCodeItem) {
processedData.mqlt_cd = materialCodeItem.text;
}
}
break;
case '하수맨홀':
// usg_cd 값 변환 (용도코드)
if (processedData.usg_cd) {
const usageCodeItem = MS_SWAGE_MHL_USE_CODES.find(
code => code.val === processedData.usg_cd.trim()
);
if (usageCodeItem) {
processedData.usg_cd = usageCodeItem.text;
}
}
// mqlt_cd 값 변환 (재질코드)
if (processedData.mqlt_cd) {
const materialCodeItem = MS_SWAGE_MHL_CODES.find(
code => code.val === processedData.mqlt_cd.trim()
);
if (materialCodeItem) {
processedData.mqlt_cd = materialCodeItem.text;
}
}
break;
case '하수펌프장':
// usg_cd 값 변환 (용도코드)
if (processedData.usg_cd) {
const usageCodeItem = DRTW_SEWAGE_PUMP_USE_CODES.find(
code => code.val === processedData.usg_cd.trim()
);
if (usageCodeItem) {
processedData.usg_cd = usageCodeItem.text;
}
}
break;
case '우수토실':
// prrtymngYn 값 변환 (중점여부)
if (processedData.prrtymngYn) {
if (processedData.prrtymngYn === 'Y') {
processedData.prrtymngYn = '중점우수토실';
} else if (processedData.prrtymngYn === 'N') {
processedData.prrtymngYn = '우수토실';
}
}
break;
case '중점우수토실':
if (processedData.manage_no) {
processedData.mqlt_cd = processedData.manage_no;
}
break;
default:
// 다른 레이어는 변환하지 않음
break;
}
return processedData;
};
/**
* 저장 시 코드 역변환 함수 (한글 → 코드)
* @param layerName - 레이어 이름
* @param data - 역변환할 데이터 객체
* @returns 역변환된 데이터 객체
*/
export const reverseCodeMapper = ({ layerName, data }: CodeMapperProps): any => {
if (!data) return data;
const processedData = { ...data };
switch (layerName) {
case '하수맨홀':
// mqlt_cd 값 역변환 (텍스트 → 코드)
if (processedData.mqlt_cd && typeof processedData.mqlt_cd === 'string') {
const materialCodeItem = MS_SWAGE_MHL_CODES.find(
code => code.text === processedData.mqlt_cd.trim()
);
if (materialCodeItem) {
processedData.mqlt_cd = materialCodeItem.val;
}
}
break;
case '우수토실':
// prrtymngYn 값 역변환 (텍스트 → Y/N)
if (processedData.prrtymngYn) {
if (processedData.prrtymngYn === '중점우수토실') {
processedData.prrtymngYn = 'Y';
} else if (processedData.prrtymngYn === '우수토실') {
processedData.prrtymngYn = 'N';
}
}
break;
case '하수펌프장':
// usg_cd 값 역변환 (텍스트 → 코드)
if (processedData.usg_cd && typeof processedData.usg_cd === 'string') {
const usageCodeItem = DRTW_SEWAGE_PUMP_USE_CODES.find(
code => code.text === processedData.usg_cd.trim()
);
if (usageCodeItem) {
processedData.usg_cd = usageCodeItem.val;
}
}
break;
default:
break;
}
return processedData;
};
// 기본 내보내기
export default { codeMapper, reverseCodeMapper };
@@ -11,18 +11,20 @@ import InfilChart from './components/popupComponent/chart/infilChart';
import RdiiChart from './components/popupComponent/chart/rdiiChart';
import { useInfilChartModalStore, useRdiiChartModalStore } from "./components/popupComponent/chartModalStore";
import { formatDisplayData } from '@/components/lib/utils/formatDisplayValue';
import { codeMapper } from "./components/common/codeMapper";
// TODO:
const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, featureData: any }) => {
const { gisMap } = useGisContext() as unknown as { checkedLayerIds: React.MutableRefObject<number[]>; treeData: { lyrSn: number }[] | null; gisCore: any; gisMap: any; };
const [layerNm, setLayerNm] = useState<string>(""); // 레이어 이름 상태
const [layerSpecificNm, setLayerSpecificNm] = useState<string>(""); // 레이어 이름 상태
const [tableData, setTableData] = useState<any>(null); // 피처 데이터
const [rainMeasureData, setRainMeasureData] = useState<any[]>([]); // 강우/측정 측정 정보
const [headlist, setHeadlist] = useState<{ id: string; title: string; }[]>([]); // 컬럼리스트 변경상태
const [headlist2, setHeadlist2] = useState<{ id: string; title: string; }[]>([]); // 컬럼리스트 변경상태
const [buttonChk, setButtonChk] = useState(true)
const [fetchData, setfetchData] = useState<any>(); // api 호출여부
const [fetchData, setFetchData] = useState<any>(); // api 호출여부
const contentRef = useRef<HTMLDivElement>(null);
const [isModalOpen, setIsModalOpen] = useState(false); // 모달 열기 상태
const [isMainSsc, setIsMainSsc] = useState(false); // 중점우수토실 여부
@@ -133,10 +135,47 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
// 🎯 기본 데이터 포맷팅
const formattedData = formatDisplayData(data);
setfetchData(formattedData);
setLayerSpecificNm(featureData.values_.fclt_mng_no);
setFetchData(formattedData);
setTableData(formattedData);
switch (selectedLayerName) {
case '하수관로':
setHeadlist(MsSwagePplCol)
setButtonChk(true)
// ✅ codeMapper 사용하여 API 결과도 변환
setTableData(codeMapper({
layerName: selectedLayerName,
data: { ...formattedData }
}));
// setFetchData(mappedData);
// setTableData(mappedData);
break;
case '하수맨홀':
setHeadlist(MsSwageMhlCol)
setButtonChk(true)
// ✅ codeMapper 사용하여 API 결과도 변환
setTableData(codeMapper({
layerName: selectedLayerName,
data: { ...formattedData }
}));
// setFetchData(mappedData);
// setTableData(mappedData);
break;
case '하수펌프장':
setHeadlist(ExclnSewagePumpCol)
setButtonChk(true)
setTableData(codeMapper({
layerName: selectedLayerName,
data: { ...formattedData }
}));
setLayerSpecificNm(tableData.mqlt_cd);
// setFetchData(mappedData);
// setTableData(mappedData);
break;
case '하수처리시설':
setHeadlist(SwtrmtFcltCol);
setButtonChk(false)
@@ -145,6 +184,11 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
setHeadlist(SwtrmtPrcsZoneCol)
setButtonChk(false)
break;
case '우수토실':
setHeadlist(stofcbrCol)
setButtonChk(true)
setIsMainSsc(false)
break;
case '중점우수토실':
setHeadlist(untrtSwgRainCol1)
setHeadlist2(untrtSwgRainCol2)
@@ -153,51 +197,34 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
// 🎯 processedData도 포맷팅하여 설정
const processedFormattedData = formatDisplayData(processedData);
setfetchData([processedFormattedData])
setFetchData([processedFormattedData])
setTableData(processedFormattedData);
// setIsLoading(false); // 기본 렌더링 완료
setTableData(codeMapper({
layerName: selectedLayerName,
data: { ...processedFormattedData }
}));
setLayerSpecificNm(tableData.mqlt_cd);
// 강우/측정 정보 데이터 호출
if (data?.chmbr_xcnts && data?.chmbr_ydnts) {
fetchRainMeasureData(data.chmbr_xcnts, data.chmbr_ydnts)
if (tableData?.chmbr_xcnts && tableData?.chmbr_ydnts) {
fetchRainMeasureData(tableData.chmbr_xcnts, tableData.chmbr_ydnts)
.then(response => {
console.log('additionalResponse', response);
setRainMeasureData(response || []);
})
.catch(error => {
console.error('추가 데이터 로딩 실패:', error);
setRainMeasureData(false);
setRainMeasureData([]);
});
}
break;
case '우수토실':
setHeadlist(stofcbrCol)
setButtonChk(true)
setIsMainSsc(false)
break;
case '하수관로':
setHeadlist(MsSwagePplCol)
setButtonChk(true)
break;
// case '오수펌프':
// setButtonChk(true)
// break;
// case '빗물펌프':
// setButtonChk(true)
// break;
case '하수펌프장':
setHeadlist(ExclnSewagePumpCol)
setButtonChk(true)
break;
case '하수맨홀':
setHeadlist(MsSwageMhlCol)
setButtonChk(true)
break;
default:
break;
}
// API 엔드포인트 선택
// 자체입력정보 API 엔드포인트 선택
let apiEndpoint = '';
const getFeatureId = featureId.toString().split('.').pop() || null;
if (selectedLayerName === '하수관로') apiEndpoint = `v1/fcltppl/${getFeatureId}`;
@@ -214,35 +241,13 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
if (result) {
console.log('API 데이터 로드 성공:', result);
// 하수맨홀인 경우 용도코드를 텍스트로 변환
if (selectedLayerName === '하수맨홀') {
const processedData = { ...result };
// ✅ codeMapper 사용하여 API 결과도 변환
const processedApiData = codeMapper({
layerName: selectedLayerName,
data: { ...result, ...tableData }
});
// mqlt_cd 값 변환 (재질코드)
if (processedData.mqlt_cd) {
const materialCodeItem = MS_SWAGE_MHL_CODES.find(
code => code.val === processedData.mqlt_cd.trim()
);
if (materialCodeItem) {
processedData.mqlt_cd = `${materialCodeItem.text}`;
}
}
setfetchData(processedData);
} // 🎯 우수토실인 경우 prrtymngYn 값 변환
else if (selectedLayerName === '우수토실' && data) {
const processedData = { ...result, ...data };
// prrtymngYn 값 변환
if (processedData.prrtymngYn === 'Y') processedData.prrtymngYn = '중점우수토실';
else if (processedData.prrtymngYn === 'N') processedData.prrtymngYn = '우수토실';
console.log('processedData', processedData);
setfetchData(processedData);
} else {
setfetchData(result);
}
setFetchData(processedApiData);
}
} catch (apiError) {
console.error('API 데이터 로딩 중 오류:', apiError);
@@ -256,7 +261,7 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
fetchData();
}, [featureId, processedData]);
// 🎯 추가 데이터 API 호출 함수 (독립적으로 실행)
// 🎯 추가 데이터 API 호출 함수
const fetchRainMeasureData = useCallback(async (chmbrXcnts: string, chmbrYdnts: string) => {
if (!chmbrXcnts || !chmbrYdnts) {
console.warn('추가 데이터 호출 실패: 필수 매개변수 누락', { chmbrXcnts, chmbrYdnts });
@@ -320,7 +325,7 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
})
.catch(error => {
console.error('추가 데이터 최종 로딩 실패:', error);
setRainMeasureData(false);
setRainMeasureData([]);
});
}
}
@@ -394,7 +399,7 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
if (result) {
alert('저장되었습니다');
setfetchData(result.data || result);
setFetchData(result.data || result);
} else {
alert('저장에 실패했습니다');
console.error('API 응답 오류:', result);
@@ -413,8 +418,13 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
<div id="popup" className="absolute top-0 right-0 w-[350px] h-[calc(100vh-10rem)] bg-white border-r border-gray-300 flex flex-col overflow-hidden transition-all duration-300 z-[50]">
<div className="card-header bg-primary flex items-center justify-between p-4">
<div className="flex items-center">
<h3 className="text-2xl font-medium text-white text-label whitespace-nowrap">{layerNm} 정보</h3>
{/* <div className="font-medium text-white text-label">(00구 00리 하수관로)</div> */}
<h3 className="text-2xl font-medium text-white text-label whitespace-nowrap mr-4">{layerNm}
{tableData?.usg_cd && (
<>
({tableData.usg_cd})
</>
)} 정보 <br />관리번호 : {layerSpecificNm}
</h3>
</div>
<div className="flex items-center space-x-3">
@@ -437,7 +447,7 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
)}
<Button
onClick={onClose}
className="text-white hover:text-gray-300 focus:outline-none ml-2"
className="text-white hover:text-gray-300 focus:outline-none"
>
✕
</Button>