Merge branch 'iipbs/sn/dev' of https://www.onasys.co.kr:3000/ONAANDALL/frontend into iipbs/sn/dev
This commit is contained in:
@@ -149,18 +149,7 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
setIsResetDetailSelection(true); // 선택 초기화
|
||||
setDetailBizId(0);
|
||||
// queryParams는 fetchFilteredData 내에서 매번 새로 생성되므로 별도 상태 초기화는 필요 없음
|
||||
}, [activeTab, basicType, workType, open]);
|
||||
|
||||
useEffect(() => {
|
||||
setActiveTab(TABS[0]?.val ?? "basic");
|
||||
setBasicType(BASIC_TYPES[0]?.val ?? "");
|
||||
setWorkType(WORK_TYPES[0]?.val ?? "");
|
||||
setTableCount(0);
|
||||
setTableData([]);
|
||||
setDetailTableCount(0);
|
||||
setDetailTableData([]);
|
||||
setDetailBizId(0);
|
||||
}, [open]);
|
||||
}, [activeTab, basicType, workType]);
|
||||
|
||||
// 페이지 변경 시마다 데이터 fetch
|
||||
useEffect(() => {
|
||||
@@ -490,14 +479,16 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
};
|
||||
|
||||
// 기본정보 테이블 cellClick 핸들러
|
||||
const handleBasicCellClick = (index?: number | undefined, headId?: String) => {
|
||||
const handleBasicCellClick = async (index?: number | undefined, headId?: String) => {
|
||||
if (typeof index === "number") {
|
||||
setIsLoading(true);
|
||||
|
||||
const row = tableData[index];
|
||||
const layerNm = row.lyrTypeNm;
|
||||
const fid = row.fid;
|
||||
const core = GisApp.Module.layer as any;
|
||||
core.showSearchResultsFromGeoJSON(layerNm, fid);
|
||||
await core.showSearchResultsFromGeoJSON(layerNm, fid);
|
||||
setIsLoading(false);
|
||||
onOpenChange(false); // SearchModal 닫기
|
||||
}
|
||||
};
|
||||
@@ -521,8 +512,7 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
RequestDTO.workTypes = JSON.parse(workType.replace(/'/g, '"'));
|
||||
|
||||
const res = await getData(`v1/bizInfo/fclts?${new URLSearchParams(RequestDTO).toString()}`);
|
||||
console.log('운영정보 cellClick 데이터1:', res);
|
||||
console.log('운영정보 cellClick 데이터2:', res.data);
|
||||
console.log('운영정보 cellClick 데이터:', res.data);
|
||||
|
||||
const mappedData = (res.data || []).map((item: any, detailIndex: number) => {
|
||||
const formattedItem = formatDisplayData(item);
|
||||
@@ -587,8 +577,22 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
const handleOperationResultCellClick = async (index?: number | undefined, headId?: String) => {
|
||||
if (typeof index === "number") {
|
||||
setIsLoading(true);
|
||||
|
||||
const row = detailTableData[index];
|
||||
const layerNm = row.lyrTypeNm;
|
||||
const fid = row.fid;
|
||||
const core = GisApp.Module.layer as any;
|
||||
await core.showSearchResultsFromGeoJSON(layerNm, fid);
|
||||
setIsLoading(false);
|
||||
onOpenChange(false); // SearchModal 닫기
|
||||
}
|
||||
};
|
||||
|
||||
// 기본정보 Excel 다운로드 핸들러
|
||||
const BasicExcelDownload = async () => {
|
||||
const basicExcelDownload = async () => {
|
||||
if (tableData.length === 0) {
|
||||
alert("다운로드 할 Excel 파일이 없습니다.\n조회 후 다시 시도해주세요.");
|
||||
return;
|
||||
@@ -804,7 +808,7 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
};
|
||||
|
||||
// 운영정보 Excel 다운로드 핸들러 추가
|
||||
const OperationExcelDownload = async () => {
|
||||
const operationExcelDownload = async () => {
|
||||
if (tableData.length === 0) {
|
||||
alert("다운로드 할 Excel 파일이 없습니다.\n조회 후 다시 시도해주세요.");
|
||||
return;
|
||||
@@ -898,7 +902,7 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
};
|
||||
|
||||
// 운영정보 Excel 다운로드 핸들러 추가
|
||||
const OperationResultExcelDownload = async () => {
|
||||
const operationResultExcelDownload = async () => {
|
||||
if (detailTableData.length === 0) {
|
||||
alert("다운로드 할 Excel 파일이 없습니다.\n조회 후 다시 시도해주세요.");
|
||||
return;
|
||||
@@ -1001,12 +1005,26 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
const viewMultipleFeature = async () => {
|
||||
if (!(tableData.length === 0)) {
|
||||
setIsLoading(true);
|
||||
|
||||
const row = tableData[0];
|
||||
const layerNm = row.lyrTypeNm;
|
||||
const fids = tableData.map((item) => item.fid);
|
||||
const core = GisApp.Module.layer as any;
|
||||
await core.showMultipleSearchResultsFromGeoJSON(layerNm, fids);
|
||||
setIsLoading(false);
|
||||
onOpenChange(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const renderBody = () => (
|
||||
<>
|
||||
{/* 탭 영역 */}
|
||||
<UITab
|
||||
defaultValue={TABS[0]?.val}
|
||||
defaultValue={activeTab}
|
||||
tabList={TABS.map((tab) => ({
|
||||
value: tab.val,
|
||||
label: tab.text
|
||||
@@ -1084,7 +1102,10 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
resetPageNo={isResetPage}
|
||||
resetSelection={isResetSelection}
|
||||
headButton={
|
||||
<Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-lg font-medium green" size="sm" onClick={BasicExcelDownload}>파일 다운로드</Button>
|
||||
<div className='flex'>
|
||||
<Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-lg font-medium primary" size="sm" onClick={viewMultipleFeature}>지도에서 보기</Button>
|
||||
<Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-lg font-medium green" size="sm" onClick={basicExcelDownload}>파일 다운로드</Button>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
@@ -1112,7 +1133,7 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
resetPageNo={isResetPage}
|
||||
resetSelection={isResetSelection}
|
||||
headButton={
|
||||
<Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-sm font-medium green" size="sm" onClick={OperationExcelDownload}>파일 다운로드</Button>
|
||||
<Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-sm font-medium green" size="sm" onClick={operationExcelDownload}>파일 다운로드</Button>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
@@ -1133,12 +1154,12 @@ const SearchModal: React.FC<SearchModalProps> = ({
|
||||
headlist={dynamicHeadlist2}
|
||||
pageSize={OPERATION_TABLE_SIZE}
|
||||
total={detailTableCount}
|
||||
cellClick={undefined}
|
||||
cellClick={handleOperationResultCellClick}
|
||||
onPageChange={setDetailCurPage}
|
||||
resetPageNo={isResetDetailPage}
|
||||
resetSelection={isResetDetailSelection}
|
||||
headButton={
|
||||
<Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-lg font-medium green" size="sm" onClick={OperationResultExcelDownload}>파일 다운로드</Button>
|
||||
<Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-lg font-medium green" size="sm" onClick={operationResultExcelDownload}>파일 다운로드</Button>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -688,6 +688,111 @@ GisOlLayer.prototype = {
|
||||
});
|
||||
|
||||
return source;
|
||||
},
|
||||
/**
|
||||
* 여러 개의 검색 결과를 GeoJSON으로 표시
|
||||
* @param {string} lyrTyNm 레이어 타입명
|
||||
* @param {Array|string} featureIds 피처 ID 배열 또는 단일 ID
|
||||
*/
|
||||
showMultipleSearchResultsFromGeoJSON: function (lyrTyNm, featureIds) {
|
||||
const layer = this.ensureSearchLayer();
|
||||
|
||||
const prev = layer.getSource();
|
||||
if (prev) prev.clear(true);
|
||||
|
||||
const layerCode = GisApp.layerCode;
|
||||
const matched = Object.values(layerCode).find(obj => obj.lyrTyNm === lyrTyNm);
|
||||
layer.set("gobjTy", matched.gobjTy);
|
||||
|
||||
const source = this.getMultiFeatureSourceFromGeoserver(lyrTyNm, featureIds);
|
||||
|
||||
const onLoadEnd = async () => {
|
||||
const feats = source.getFeatures();
|
||||
if (feats && feats.length > 0) {
|
||||
const select = GisApp.Module.select;
|
||||
await select.resetSelectedFeature();
|
||||
for (const feature of feats) select.selectMultiFeature(feature, true);
|
||||
const geometries = feats.map(f => f.getGeometry());
|
||||
if (geometries.length > 0) {
|
||||
const extent = this.combineExtents(geometries.map(g => g?.getExtent()));
|
||||
|
||||
let map = GisApp.Module.core.map;
|
||||
map.getView().fit(extent, {
|
||||
duration: 300,
|
||||
padding: [50, 50, 50, 50],
|
||||
maxZoom: 16
|
||||
});
|
||||
}
|
||||
} else {
|
||||
console.warn('[search-layer] GeoJSON에 피처가 없습니다.');
|
||||
}
|
||||
source.un('featuresloadend', onLoadEnd);
|
||||
source.un('featuresloaderror', onLoadError);
|
||||
};
|
||||
|
||||
const onLoadError = (e) => {
|
||||
console.error('[search-layer] GeoJSON 로드 실패:', e);
|
||||
source.un('featuresloadend', onLoadEnd);
|
||||
source.un('featuresloaderror', onLoadError);
|
||||
};
|
||||
|
||||
source.once('featuresloadend', onLoadEnd);
|
||||
source.once('featuresloaderror', onLoadError);
|
||||
|
||||
layer.setSource(source);
|
||||
|
||||
source.refresh();
|
||||
},
|
||||
/**
|
||||
* 피쳐 ID로 지오서버에서 검색해서 여러개 피처의 벡터소스를 리턴
|
||||
* @param {} lyrTyNm
|
||||
* @param {*} featureId
|
||||
* @returns
|
||||
*/
|
||||
getMultiFeatureSourceFromGeoserver: function (lyrTyNm, featureId) {
|
||||
|
||||
const typeName = this.storageNm + lyrTyNm;
|
||||
const srsName = GisApp.TO_PROJ;
|
||||
const baseUrl = GisApp.GEOSERVER_URL;
|
||||
|
||||
const ids = Array.isArray(featureId) ? featureId : [featureId];
|
||||
|
||||
const source = new VectorSource({
|
||||
format: new GeoJSON(),
|
||||
url: () => {
|
||||
const params = new URLSearchParams({
|
||||
SERVICE: 'WFS',
|
||||
VERSION: '1.1.0',
|
||||
REQUEST: 'GetFeature',
|
||||
TYPENAME: typeName,
|
||||
SRSNAME: srsName,
|
||||
OUTPUTFORMAT: 'application/json',
|
||||
FEATUREID: ids.join(','),
|
||||
});
|
||||
return `${baseUrl}?${params.toString()}`;
|
||||
},
|
||||
strategy: all,
|
||||
});
|
||||
|
||||
return source;
|
||||
},
|
||||
/**
|
||||
* 여러 extent 배열을 받아 결합된 extent를 반환
|
||||
* @param {Array<Array<number>>} extents [[minX,minY,maxX,maxY], ...]
|
||||
* @returns {Array<number>|null}
|
||||
*/
|
||||
combineExtents: function (extents) {
|
||||
if (!extents || extents.length === 0) return null;
|
||||
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
||||
for (const e of extents) {
|
||||
if (!e || e.length < 4) continue;
|
||||
minX = Math.min(minX, e[0]);
|
||||
minY = Math.min(minY, e[1]);
|
||||
maxX = Math.max(maxX, e[2]);
|
||||
maxY = Math.max(maxY, e[3]);
|
||||
}
|
||||
if (!isFinite(minX) || !isFinite(minY) || !isFinite(maxX) || !isFinite(maxY)) return null;
|
||||
return [minX, minY, maxX, maxY];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user