diff --git a/packages/common/business_components/src/ui/chart/BarChart.tsx b/packages/common/business_components/src/ui/chart/BarChart.tsx
index 79aa61c98..ec0647dff 100644
--- a/packages/common/business_components/src/ui/chart/BarChart.tsx
+++ b/packages/common/business_components/src/ui/chart/BarChart.tsx
@@ -19,6 +19,14 @@ const customStyles = {
} as CSSProperties,
};
+const fncNumberFormet = (value : string | number) => {
+ return String(value).includes('.')?
+ String(parseFloat(value.toString().replace(/,/g, ''))).split('.').map((part, index) =>
+ index === 0 ? part.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : part
+ ).join('.')
+ : String(value).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
+}
+
type BarChartProps = {
chartConfig: ChartConfig | undefined;
chartData: any[] | undefined;
@@ -51,7 +59,7 @@ const CustomTooltip = ({
{/* 색상 박스 추가 (범례 색상과 동일) */}
-
{` ${item.name} : ${item.value}`}
+
{` ${item.name} : ${fncNumberFormet(item.value)}`}
))}
diff --git a/packages/common/business_components/src/ui/map/lib/gis.layer.js b/packages/common/business_components/src/ui/map/lib/gis.layer.js
index f8fdb2a24..5f741e75f 100644
--- a/packages/common/business_components/src/ui/map/lib/gis.layer.js
+++ b/packages/common/business_components/src/ui/map/lib/gis.layer.js
@@ -688,6 +688,114 @@ GisOlLayer.prototype = {
});
return source;
+<<<<<<< HEAD
+=======
+ },
+ /**
+ * 여러 개의 검색 결과를 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>} extents [[minX,minY,maxX,maxY], ...]
+ * @returns {Array|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];
+>>>>>>> iipbs/common/main
}
};
diff --git a/packages/common/business_components/src/ui/table/index.tsx b/packages/common/business_components/src/ui/table/index.tsx
index fa7c9b7fe..dcf7f4aa4 100644
--- a/packages/common/business_components/src/ui/table/index.tsx
+++ b/packages/common/business_components/src/ui/table/index.tsx
@@ -30,6 +30,7 @@ type UiTableProps = {
boldArray?: number[];
resetSelection?: boolean;
index?: number;
+ headButton?: React.ReactNode | undefined;
};
type UiHeadProps = {
@@ -53,6 +54,7 @@ export function UiTable({
boldArray = [],
resetSelection = false,
index = -1,
+ headButton = undefined,
}: UiTableProps) {
const [cur, setCur] = useState(1);
const [idx, setIdx] = useState(index);
@@ -100,9 +102,16 @@ export function UiTable({
return (
<>
{headName ? (
-
-
{headName}
-
+ headButton ? (
+
+
{headName}
+ <>{headButton}>
+
+ ) : (
+
+
{headName}
+
+ )
) : (
<>>
)}