diff --git a/packages/common/business_components/src/ui/chart/BarChart.tsx b/packages/common/business_components/src/ui/chart/BarChart.tsx index 02d3a7c60..ddd0ac272 100644 --- a/packages/common/business_components/src/ui/chart/BarChart.tsx +++ b/packages/common/business_components/src/ui/chart/BarChart.tsx @@ -74,17 +74,25 @@ const CustomLegend = (props: any) => { ); }; +// chartData의 모든 값 중 최대값 구하기 +const getGlobalMax = (data: Record[]) => { + if (!data || data.length === 0) return 0; + return Math.max( + ...data.flatMap(item => + Object.entries(item) + .filter(([key]) => key !== 'label') + .map(([, value]) => value as number) + ) + ); +}; + export default function Chart({chartConfig=undefined, chartData=[], chartTitle='차트', chartClassName='w-full h-full', graphSize=40, yFieldText='', showLegend=false} : BarChartProps) { const colors = ["#FF6B6B", "#4ECDC4", "#45B7D1", "#FED16A", "#FFEEAD", "#D4A5A5"]; - const getMaxValue = (data: any[], keyPrefix: string) => { - return Math.max(...data.map(item => - Object.keys(item) - .filter(key => key.includes(keyPrefix)) - .map(key => item[key]) - ).flat()); - }; - - const barMaxValue = getMaxValue(chartData, 'barVal'); + const globalMax = getGlobalMax(chartData); + const tickCount = 5; + // interval을 globalMax / tickCount로 계산 + const interval = globalMax / tickCount; + const ticks = Array.from({ length: tickCount + 1 }, (_, i) => Math.round(interval * i)); return ( <> {chartTitle && chartTitle !== "" && chartTitle !== "undefined" ? ( @@ -93,8 +101,8 @@ export default function Chart({chartConfig=undefined, chartData=[], chartTitle=' ): null}
- - + + }/> {chartData && chartData.length > 0 && ( diff --git a/packages/common/business_components/src/ui/date_picker_range/index.tsx b/packages/common/business_components/src/ui/date_picker_range/index.tsx new file mode 100644 index 000000000..70565230a --- /dev/null +++ b/packages/common/business_components/src/ui/date_picker_range/index.tsx @@ -0,0 +1,46 @@ +import "../date_picker/date-picker.css"; + +import { format } from "date-fns"; +import { CalendarIcon } from "lucide-react"; +import type { DayPickerSingleProps } from "react-day-picker"; + +import { cn } from "../../lib/utils"; +import { Button } from "@common/components/ui"; +import { Calendar } from "@common/components/ui"; +import { Popover, PopoverContent, PopoverTrigger } from "@common/components/ui"; + +type DatePickerRangeProps = { + placeholder?: string; + disabled?: boolean | ((date: Date) => boolean); +} & DayPickerSingleProps; + +export function DatePickerRange({ + className, + placeholder = "날짜 선택", + disabled, + ...props +}: DatePickerRangeProps) { + return ( + + + + + + + + + ); +} diff --git a/packages/common/business_components/src/ui/index.ts b/packages/common/business_components/src/ui/index.ts index fd1e6fe9e..eab3a7eab 100644 --- a/packages/common/business_components/src/ui/index.ts +++ b/packages/common/business_components/src/ui/index.ts @@ -21,4 +21,5 @@ export * from "./table_div"; export * from "./title"; export * from "./sdmInsertForm"; export * from "./popover_ui"; -export * from "./date_month_picker"; \ No newline at end of file +export * from "./date_month_picker"; +export * from "./date_picker_range" \ No newline at end of file diff --git a/packages/common/business_components/src/ui/map/Gis.js b/packages/common/business_components/src/ui/map/Gis.js index ef5c21d5b..3a7bec1b8 100644 --- a/packages/common/business_components/src/ui/map/Gis.js +++ b/packages/common/business_components/src/ui/map/Gis.js @@ -30,6 +30,7 @@ function Gis({ setIsOpen, setFeatureData, featureData, + imgVisble = false, searchView: SearchView, detailView: DetailView, onFeatureSelect, @@ -46,7 +47,7 @@ function Gis({ const gisCore = useMemo(() => new GisApp.core({ targetId: mapRef.current }), []); const mapInstanceRef = useRef(null); const checkedLayerIds = useRef([]); - + const layerNmRef = useRef('') // 팝업 데이터를 저장할 상태와 오버레이 참조를 저장할 ref 추가 // const [facilityInfoPopupData, setFacilityInfoPopupData] = useState([]); @@ -84,12 +85,32 @@ function Gis({ foundFeature = data; } else { // 아니면 featureId로 맵에서 Feature 인스턴스를 찾아서 사용 - const featureId = data.fid || data.ftrIdn || data.id; + let featureId + const layerName = layerNmRef.current + if (layerName === '하수재이용시설') { + featureId = data.searchPk; + } else if (layerName === '빗물이용시설'|| layerName == '중수도시설') { + featureId = data.bdstInfoPk; + } else if (layerName === '하수처리시설') { + featureId = data.bscFctCd; + } else if (layerName === '온배수시설' ) { + featureId = data.bdstRuseFcltPk; + } else { + console.warn('해당 레이어에 대한 featureId 매핑 없음', layerNm); + featureId = data.fid || data.id || data.ftrIdn; + } gisMap.getLayers().getArray().forEach(layer => { const source = layer.getSource?.(); - if (source?.getFeatureById) { - const feature = source.getFeatureById(String(featureId).trim()); - if (feature) foundFeature = feature; + if (source?.getFeatures) { + const allFeatures = source.getFeatures(); + for (const f of allFeatures) { + const id = String(f.getId()); + // console.log('id', id, featureId) + if (id && id.split('.')[1] === String(featureId)) { + foundFeature = f; + break; + } + } } }); } @@ -360,11 +381,13 @@ function Gis({ setVisible={setTabVisible} onCheckedChange={handleCheckedLayersChange} onLayerIconClick={(nodeNm) => { + layerNmRef.current = nodeNm setLayerNm(nodeNm); setIsOpen(true); const dummyFeature = { getProperties: () => ({}), // 최소 구조 }; onFeatureSelect(dummyFeature); }} + imageVisible={imgVisble} /> {/* */} @@ -375,6 +398,7 @@ function Gis({ featureData={featureData || { getProperties: () => ({}) }} seletectedLayerNm={layerNm} onClose={closePopup} // 닫기 콜백 전달 + onFeatureSelect={handleFeatureSelect} /> )} {/* SearchView가 존재할 때만 렌더링 */} diff --git a/packages/common/business_components/src/ui/map/GisTree.js b/packages/common/business_components/src/ui/map/GisTree.js index 5b30dc7f4..8a2db3ae2 100644 --- a/packages/common/business_components/src/ui/map/GisTree.js +++ b/packages/common/business_components/src/ui/map/GisTree.js @@ -10,7 +10,7 @@ import { DndProvider } from "react-dnd"; import { useGisContext } from './Gis'; import GisApp from './lib/gis.core'; -export default React.memo(function GisTree({ checkedNodes = [], setCheckedNodes = () => { }, visible, setVisible, onCheckedChange, onLayerIconClick }) { +export default React.memo(function GisTree({ checkedNodes = [], setCheckedNodes = () => { }, visible, setVisible, onCheckedChange, onLayerIconClick,imageVisible=false }) { const { gisCore, treeData } = useGisContext(); const [checked, setChecked] = useState([]); const [expanded, setExpanded] = useState([]); @@ -188,9 +188,9 @@ export default React.memo(function GisTree({ checkedNodes = [], setCheckedNodes image.src = canvas.toDataURL('image/png'); return image; }; - const handleLayerImgClick = (nodeNm) => { - console.log('click!', nodeNm) - onLayerIconClick(nodeNm) + const handleLayerImgClick = (nodeNm, nodeId) => { + if(!checked.includes(nodeId)) alert('시설을 선택해주세요') + else onLayerIconClick(nodeNm) } if (!treeData || treeData.length === 0) return null; @@ -224,7 +224,7 @@ export default React.memo(function GisTree({ checkedNodes = [], setCheckedNodes handleCheck(node.id)} className="cursor-pointer" /> {node.icon && {node.icon}} {node.text} - {depth > 0 && {handleLayerImgClick(node.text)}} alt={node.text}>} + {imageVisible ? depth > 0 && {handleLayerImgClick(node.text, node.id)}} alt={node.text}> : null}
)} sort={(a, b) => { diff --git a/packages/common/business_components/src/ui/sdmInsertForm/form.tsx b/packages/common/business_components/src/ui/sdmInsertForm/form.tsx index a42dea012..e58592837 100644 --- a/packages/common/business_components/src/ui/sdmInsertForm/form.tsx +++ b/packages/common/business_components/src/ui/sdmInsertForm/form.tsx @@ -234,6 +234,7 @@ export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigun }, [updateList,form]); useEffect(() => { + console.log( 'form.formState.errors ', form.formState.errors) },[form.formState.errors]) const formFields: Array<{ diff --git a/packages/common/business_components/src/ui/sdmInsertForm/index.tsx b/packages/common/business_components/src/ui/sdmInsertForm/index.tsx index c564b63dd..35c609f9e 100644 --- a/packages/common/business_components/src/ui/sdmInsertForm/index.tsx +++ b/packages/common/business_components/src/ui/sdmInsertForm/index.tsx @@ -42,12 +42,14 @@ const createFormSchema = (isBznmTotNoDisabled: boolean, isDuplicate: boolean ,up .min(8, "전화번호는 8자 이상 입력해주세요") .max(11, "전화번호는 11자 이내로 입력해주세요") .regex(/^[0-9]+$/, "전화번호는 숫자만 입력 가능합니다"), - rgtr: z.string().optional(), + rgtr: z.string().nullish(), dmdAplyPswd : updateList?.dmdInfoPk // 업데이트일경우 ? z.string().optional() // 패스워드는 선택 사항이며 길이 제한 없음 : z.string().optional() .refine((val) => !val || (val.length >= 8 && val.length <= 16), "패스워드는 8자 이상 16자 이내로 입력해주세요"), - dmdAplyPswdConfirm: z.string() + dmdAplyPswdConfirm: updateList?.dmdInfoPk // 업데이트일경우 + ? z.string().optional() // 패스워드는 선택 사항이며 길이 제한 없음 + :z.string() .min(1, "패스워드확인을 입력해주세요"), }).refine((data) => { // 패스워드 확인 검증 diff --git a/packages/common/business_components/src/ui/search_form_left/index.tsx b/packages/common/business_components/src/ui/search_form_left/index.tsx index 4f36c078c..a891ec207 100644 --- a/packages/common/business_components/src/ui/search_form_left/index.tsx +++ b/packages/common/business_components/src/ui/search_form_left/index.tsx @@ -301,7 +301,7 @@ function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], sel resetAllValues(); // 리셋 후 트리거를 false로 설정 if (setRtnPartValue) { - setRtnPartValue('0'); + setRtnPartValue('A'); } } }, [resetTrigger]); diff --git a/packages/common/components/src/ui/date-picker/index.tsx b/packages/common/components/src/ui/date-picker/index.tsx index 85c584e5f..ee5d37872 100644 --- a/packages/common/components/src/ui/date-picker/index.tsx +++ b/packages/common/components/src/ui/date-picker/index.tsx @@ -2,7 +2,7 @@ import "./date-picker.css"; import { format } from "date-fns"; import { CalendarIcon } from "lucide-react"; -import type { DayPicker } from "react-day-picker"; +import type { DayPickerSingleProps } from "react-day-picker"; import { cn } from "../../lib/utils"; import { Button } from "../button"; @@ -12,15 +12,12 @@ import { Popover, PopoverContent, PopoverTrigger } from "../popover"; type DatePickerProps = { placeholder?: string; disabled?: boolean; - selected?: Date; - zIndex?: number; // z-index prop 추가 -} & React.ComponentProps; +} & DayPickerSingleProps; export function DatePicker({ className, placeholder = "날짜 선택", disabled, - zIndex, // zIndex prop 받기 ...props }: DatePickerProps) { return ( @@ -39,11 +36,8 @@ export function DatePicker({ )} - - + + );