diff --git a/packages/common/business_components/src/ui/chart/DoubleBar.tsx b/packages/common/business_components/src/ui/chart/DoubleBar.tsx
index 9627485aa..be930f3af 100644
--- a/packages/common/business_components/src/ui/chart/DoubleBar.tsx
+++ b/packages/common/business_components/src/ui/chart/DoubleBar.tsx
@@ -83,7 +83,6 @@ export default function DoubleBarChart({chartConfig=undefined, chartData=[], cha
.map(key => item[key])
).flat());
};
- console.log(chartData);
const barMaxValue = getMaxValue(chartData, 'barVal');
return (
<>
diff --git a/packages/common/business_components/src/ui/chart/LineBarChart.tsx b/packages/common/business_components/src/ui/chart/LineBarChart.tsx
index 64a7d5bce..d81d6e2c8 100644
--- a/packages/common/business_components/src/ui/chart/LineBarChart.tsx
+++ b/packages/common/business_components/src/ui/chart/LineBarChart.tsx
@@ -94,6 +94,7 @@ export default function LineBarchart({
// 데이터의 최대값 계산
const getMaxValue = (data: any[], keyPrefix: string) => {
+ if (!data || data.length === 0) return 0;
return Math.max(...data.map(item =>
Object.keys(item)
.filter(key => key.includes(keyPrefix))
diff --git a/packages/common/business_components/src/ui/chart/LineBarChart2.tsx b/packages/common/business_components/src/ui/chart/LineBarChart2.tsx
new file mode 100644
index 000000000..ff8e6b5cb
--- /dev/null
+++ b/packages/common/business_components/src/ui/chart/LineBarChart2.tsx
@@ -0,0 +1,186 @@
+"use client"
+import type { CSSProperties } from "react";
+import { Bar, CartesianGrid, ComposedChart, Legend, Line, Tooltip, XAxis, YAxis } from "recharts";
+import {
+ ChartContainer,
+ type ChartConfig
+} from "./lib/chart";
+import type { ContentType } from "recharts/types/component/DefaultLegendContent";
+
+// 툴크 커스텀 css
+/** 차트 기본 스타일 */
+const customStyles = {
+ legendContainer: {
+ display: "flex",
+ justifyContent: "center",
+ gap: "20px",
+ fontSize: "9px",
+ fontWeight : "bold",
+ marginTop: "10px",
+ } as CSSProperties,
+};
+
+type LineBarChartProps = {
+ chartConfig: ChartConfig | undefined;
+ chartData: any[] | undefined;
+ chartTitle: string;
+ chartClassName?: string;
+ graphSize?: number;
+ yFieldText?: string | undefined;
+ yFieldText2?: string | undefined;
+ showLegend?: boolean;
+}
+
+type LegendEntry = {
+ value: string;
+ color: string;
+ type?: string;
+ payload?: unknown;
+};
+
+type LegendProps = {
+ payload?: LegendEntry[];
+};
+
+// 커스텀 툴팁
+const CustomTooltip = ({ active, payload, label }: { active?: boolean; payload?: Array<{ name: string; value: number; color: string }>; label?: string }) => {
+ if (active && payload && payload.length) {
+ return (
+
+
{label}
+ {payload.map((item, index) => (
+
+ {/* 색상 박스 추가 (범례 색상과 동일) */}
+
+
{` ${item.name} : ${item.value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}`}
+
+ ))}
+
+ );
+ }
+ return null;
+};
+
+// 커스텀 범례 (글씨 크기 키우기 + 스타일 추가)
+const CustomLegend = (props: LegendProps) => {
+ const { payload } = props;
+ if (!payload) return null;
+
+ return (
+
+ {payload.map((entry: LegendEntry, index: number) => (
+
+ ))}
+
+ );
+};
+
+export default function LineBarchart2({
+ chartConfig,
+ chartData,
+ chartTitle,
+ chartClassName = 'w-full h-full',
+ graphSize = 40,
+ yFieldText,
+ yFieldText2,
+ showLegend = true
+}: LineBarChartProps) {
+ if (!chartData || chartData.length === 0) {
+ return 데이터가 없습니다.
;
+ }
+
+ // 데이터의 최대값 계산
+ const getMaxValue = (data: any[], keyPrefix: string) => {
+ if (!data || data.length === 0) return 0;
+ return Math.max(...data.map(item =>
+ Object.keys(item)
+ .filter(key => key.includes(keyPrefix))
+ .map(key => item[key])
+ ).flat());
+ };
+
+ const lineMaxValue = getMaxValue(chartData, 'lineVal');
+ const barMaxValue = getMaxValue(chartData, 'barVal');
+ return (
+
+ {chartTitle && chartTitle !== "" && chartTitle !== "undefined" ? (
+
+ {chartTitle}
+
+ ) : null}
+
+
+
+
+
+ {/* 왼쪽 Y축: lineVal */}
+ {yFieldText && }
+ {/* 오른쪽 Y축: barVal */}
+ {yFieldText2 && }
+ } />
+ {showLegend && }
+ {/* 바 차트 (오른쪽 Y축 사용) */}
+ {Object.keys(chartData[0]).map((key, index) => {
+ const config = chartConfig?.[key];
+ if(key.includes("barVal")) {
+ return (
+
+ );
+ }
+ return null;
+ })}
+ {/* 라인 차트 (왼쪽 Y축 사용) */}
+ {Object.keys(chartData[0]).map((key, index) => {
+ const config = chartConfig?.[key];
+ if(key.includes("lineVal")) {
+ return (
+
+ );
+ }
+ return null;
+ })}
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/packages/common/business_components/src/ui/chart/index.tsx b/packages/common/business_components/src/ui/chart/index.tsx
index 6e0010f9a..ee308e378 100644
--- a/packages/common/business_components/src/ui/chart/index.tsx
+++ b/packages/common/business_components/src/ui/chart/index.tsx
@@ -2,6 +2,7 @@
import DoubleBarChart from './DoubleBar';
import DoughnutChart from './DoughnutChart';
import LineBarchart from './LineBarChart';
+import LineBarchart2 from './LineBarChart2';
import LineChart from './LineChart';
/**차트 FORM */
@@ -14,6 +15,8 @@ const CHART_FORM = {
DN :'daughnut',
/**LINE,BAR차트 */
LINEBAR : 'linebar',
+ /**LINE,BAR차트 */
+ LINEBAR2 : 'linebar2',
/**더블바 차트 형태*/
DOUBLEBAR : 'doublebar'
};
@@ -72,6 +75,10 @@ function MainChart(props: MainChartProps) {
return (
);
+ } else if (props.chartForm == CHART_FORM.LINEBAR2){
+ return (
+
+ );
} else if (props.chartForm == CHART_FORM.DOUBLEBAR){
return (
diff --git a/packages/common/business_components/src/ui/map/Gis.js b/packages/common/business_components/src/ui/map/Gis.js
index 6cb7938fe..9dd0dda76 100644
--- a/packages/common/business_components/src/ui/map/Gis.js
+++ b/packages/common/business_components/src/ui/map/Gis.js
@@ -16,6 +16,73 @@ import GisApp from './lib/gis.core';
export const GisContext = createContext({ gisCore: null, gisMap: null, treeData: null, checkedLayerIds: null });
export const useGisContext = () => useContext(GisContext);
+export const searchUpperPpls = async (fcltMngNo) => {
+ const BASE_URL = process.env.NEXT_PUBLIC_SEWERAGE_API_URL || '';
+
+ const res = await fetch(`${BASE_URL}/v1/fcltmhl/upperPpls/${fcltMngNo}`, {
+ method: "GET",
+ });
+
+ let data = null;
+ if (res.ok) {
+ try {
+ // 응답이 비어있는지 확인
+ const contentLength = res.headers.get('content-length');
+ if (contentLength === '0') alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
+
+ // 응답 텍스트를 먼저 가져와서 빈 문자열인지 확인
+ const text = await res.text();
+ if (!text || text.trim() === '') alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
+
+ // JSON 파싱 시도
+ data = JSON.parse(text);
+ } catch (error) {
+ console.error('JSON parsing error:', error);
+ alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
+ }
+ }
+
+ const select = GisApp.Module.select;
+
+ const gisMap = GisApp.Module.core?.map;
+
+ let foundFeature = null;
+
+ data.forEach(item => {
+ const pplMngNo = item.ppl_mng_no.trim();
+
+ gisMap.getLayers().getArray().filter(e => e.get("lyrTyNm") == 'tb_ms_swage_ppl').forEach(layer => {
+ const source = layer.getSource?.();
+ if (source?.getFeatures) {
+ const features = source.getFeatures();
+ for (const f of features) {
+ if (f.values_.fclt_mng_no.trim() === pplMngNo) {
+ foundFeature = f;
+ break;
+ }
+ }
+ }
+ });
+
+ if (foundFeature) select.selectMultiFeature(foundFeature, true);
+ });
+
+ if (!foundFeature) alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
+
+ let geometry = foundFeature?.getGeometry();
+ if (geometry) {
+ let extent = geometry.getExtent();
+
+ gisMap.getView().fit(extent, {
+ duration: 300,
+ padding: [50, 50, 50, 50],
+ maxZoom: 14,
+ constrainResolution: true,
+ nearest: true,
+ });
+ }
+};
+
function Gis({
isOpen,
@@ -94,7 +161,10 @@ function Gis({
featureId = data.bscFctCd;
} else if (layerName === '온배수시설') {
featureId = data.bdstRuseFcltSn;
- } else {
+ } else if(layerName == '수요처'){
+ featureId = data.dmdInfoId.replaceAll('-','')
+ }
+ else {
console.warn('해당 레이어에 대한 featureId 매핑 없음', layerNm);
featureId = data.fid || data.id || data.ftrIdn;
}
@@ -301,6 +371,7 @@ function Gis({
onFeatureSelect={handleFeatureSelect}
/>
)}
+ {/* */}
diff --git a/packages/common/business_components/src/ui/map/lib/gis.select.js b/packages/common/business_components/src/ui/map/lib/gis.select.js
index 21ab39609..d0209a6ed 100644
--- a/packages/common/business_components/src/ui/map/lib/gis.select.js
+++ b/packages/common/business_components/src/ui/map/lib/gis.select.js
@@ -429,6 +429,19 @@ GisOlSelect.prototype = {
auto: auto,
});
},
+ /**
+ * 피처 다중 셀렉트
+ */
+ selectMultiFeature: function (feature, auto) {
+ let me = this;
+ me.selectedFeatures.push(feature);
+ me.selectInteraction.dispatchEvent({
+ type: 'select',
+ selected: me.selectedFeatures,
+ deselected: [],
+ auto: auto,
+ });
+ },
};
export default GisOlSelect;
diff --git a/packages/common/business_components/src/ui/sdmInsertForm/form.tsx b/packages/common/business_components/src/ui/sdmInsertForm/form.tsx
index 786b07925..09dd10525 100644
--- a/packages/common/business_components/src/ui/sdmInsertForm/form.tsx
+++ b/packages/common/business_components/src/ui/sdmInsertForm/form.tsx
@@ -215,6 +215,8 @@ export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigun
useEffect(() => {
+ form.setValue('rgtr', '2d4b151d-1828-41e0-91d9-4cd28ea1cc7e');
+
if(updateList?.dmdInfoId){
form.reset(updateList)
if(updateList?.dmdInfoId.slice(10,14) !== '0000') {
@@ -322,7 +324,7 @@ export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigun
},
{
name: "bznmTotNo",
- label: "종사업자등록번호",
+ label: "",
component: (field) => (
(
-