From 8af6e6738228684990b719254dcc3c1d689ed822 Mon Sep 17 00:00:00 2001 From: AnCha Date: Mon, 20 May 2024 00:18:08 +0900 Subject: [PATCH 1/9] =?UTF-8?q?Feat=20:=20=EC=B6=94=EA=B0=80=20=EC=A7=80?= =?UTF-8?q?=EB=8A=A5=ED=98=95=20=ED=83=90=EC=83=89=20api=20=EC=97=B0?= =?UTF-8?q?=EA=B2=B0=20=EB=B0=8F=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= =?UTF-8?q?=20#204?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reportIntelligent/IntelligentBasicInfo.js | 57 --------- .../reportIntelligent/IntelligentSearchBox.js | 102 ++++++++++++++-- .../IntelligentSearchOption.js | 115 ++++-------------- .../reportIntelligent/ReportIntelligent.js | 36 +++++- frontend/src/core/api/index.js | 26 ++++ 5 files changed, 173 insertions(+), 163 deletions(-) diff --git a/frontend/src/components/reportIntelligent/IntelligentBasicInfo.js b/frontend/src/components/reportIntelligent/IntelligentBasicInfo.js index 069b3529d4..495746aafc 100644 --- a/frontend/src/components/reportIntelligent/IntelligentBasicInfo.js +++ b/frontend/src/components/reportIntelligent/IntelligentBasicInfo.js @@ -26,63 +26,6 @@ export const IntelligentBasicInfo = ({ data }) => { }, [data]); return ( - // - //
- // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - - // - // - // 착장정보 - // - // - // - // - // - // - - // {/* - // - // 착장정보 - // - // */} - //
- //
diff --git a/frontend/src/components/reportIntelligent/IntelligentSearchBox.js b/frontend/src/components/reportIntelligent/IntelligentSearchBox.js index a887325ec3..2e90cb343d 100644 --- a/frontend/src/components/reportIntelligent/IntelligentSearchBox.js +++ b/frontend/src/components/reportIntelligent/IntelligentSearchBox.js @@ -1,14 +1,25 @@ +/*global kakao*/ import styled from "styled-components"; +import { useEffect, useRef, useState } from "react"; import { Input, Modal } from "antd"; import { SearchOutlined } from "@ant-design/icons"; import DaumPostcode from "react-daum-postcode"; -import { useState } from "react"; +import { Circle, Map, MapMarker } from "react-kakao-maps-sdk"; -//도로명 주소 검색 -export const IntelligentSeacrchBox = ({ title, form, name }) => { +// 지능형 탐색 - 도로명 주소 검색 +export const IntelligentSeacrchBox = ({ title, form, name, getLocation }) => { + const mapRef = useRef(); const [openPostcode, setOpenPostcode] = useState(false); const [location, setLocation] = useState(""); + const [markerPosition, setMarkerPosition] = useState({}); + useEffect(() => { + console.log("selectAddress", location); + if (location) { + handleGeocoder(); + } + }, [location]); + const handle = { // 버튼 클릭 이벤트 clickButton: () => { @@ -19,10 +30,35 @@ export const IntelligentSeacrchBox = ({ title, form, name }) => { selectAddress: (data) => { setLocation(data.address); form.setFieldsValue({ [name]: data.address }); // 주소 정보를 Form.Item에 직접 설정 + // setOpenPostcode(false); + }, + + // 선택 완료 이벤트 + clickOK: () => { + getLocation(markerPosition); setOpenPostcode(false); }, }; + const handleGeocoder = () => { + const geocoder = new kakao.maps.services.Geocoder(); + var callback = function (result, status) { + if (status === kakao.maps.services.Status.OK) { + console.log(result); + setMarkerPosition({ + lat: result[0].y, + lng: result[0].x, + }); + const map = mapRef.current; + if (map) { + map.setCenter(new kakao.maps.LatLng(result[0].y, result[0].x)); + map.setLevel(6); + } + } + }; + geocoder.addressSearch(location, callback); + }; + return ( @@ -33,16 +69,43 @@ export const IntelligentSeacrchBox = ({ title, form, name }) => { setOpenPostcode(false)} + onOk={handle.clickOK} onCancel={() => setOpenPostcode(false)}> - + + + + + + + + {markerPosition.lat && markerPosition.lng && ( + <> + + + + )} + + + ); @@ -89,3 +152,20 @@ const SearchIconWrapper = styled.div` padding: 0.9rem; border-left: 0.1rem solid #d9d9d9; `; + +const ModalContent = styled.div` + display: flex; + flex-direction: row; + width: 100%; + height: 100%; +`; + +const DaumPostcodeWrapper = styled.div` + width: 50%; + height: 100%; +`; + +const MapWrapper = styled.div` + width: 50%; + height: 100%; +`; diff --git a/frontend/src/components/reportIntelligent/IntelligentSearchOption.js b/frontend/src/components/reportIntelligent/IntelligentSearchOption.js index 43400fe793..722ee26bbd 100644 --- a/frontend/src/components/reportIntelligent/IntelligentSearchOption.js +++ b/frontend/src/components/reportIntelligent/IntelligentSearchOption.js @@ -23,95 +23,33 @@ const rangeConfig = { }, ], }; -const onFinish = (fieldsValue) => { - const values = { - ...fieldsValue, - }; - console.log("Received values of form: ", values); -}; -export const IntelligentSearchOption = ({ name }) => { - const [form] = Form.useForm(); +export const IntelligentSearchOption = ({ form, name, getLocation }) => { + // const [form] = Form.useForm(); return ( - // - // - // 탐색 시간대/위치 설정 - // - //
- // - // - //

시작일

- // - // - // - // - // - // - // - // - // - // - // - // - //

종료일

- // - // - // - // - // - // - // - // - // - // - // - //
- // - // - //

탐색 위치

- // - // - // - // - // - // - // - // - // - // - // 탐색시작 - // - // - // - // - //
- //
- //
{name}님의 지능형 탐색 - - - !d || d.isAfter(moment())} - disabledTime={(d) => !d || d.isAfter(moment())} - /> - - - - - - 시작하기 - - + {/* */} + + !d || d.isAfter(moment())} + disabledTime={(d) => !d || d.isAfter(moment())} + /> + + + + + + + 시작하기 + + + {/* */} ); }; @@ -128,15 +66,6 @@ const StIntelligentSearchOption = styled.div` //box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.1); `; -const FormItem = styled(Form.Item)` - margin-bottom: 0; -`; -const ButtonContainer = styled.div` - display: flex; - flex-direction: row; - justify-content: end; -`; - const ButtonWrapper = styled(Button)` margin-top: 2rem; margin-bottom: 0; diff --git a/frontend/src/components/reportIntelligent/ReportIntelligent.js b/frontend/src/components/reportIntelligent/ReportIntelligent.js index a5d6df69eb..1f37c721ef 100644 --- a/frontend/src/components/reportIntelligent/ReportIntelligent.js +++ b/frontend/src/components/reportIntelligent/ReportIntelligent.js @@ -1,16 +1,41 @@ import styled from "styled-components"; -import { IntelligentSearchOption } from "./IntelligentSearchOption"; +import { useState } from "react"; import { Col, Form, Row } from "antd"; +import { IntelligentSearchOption } from "./IntelligentSearchOption"; import { IntelligentBasicInfo } from "./IntelligentBasicInfo"; import { IntelligentMap } from "./IntelligentMap"; import { IntelligentSearchResult } from "./IntelligentSearchResult"; +import { postIntelligentSearch } from "../../core/api"; export const ReportIntelligent = ({ data }) => { + const [form] = Form.useForm(); + const [latlng, setLatlng] = useState({}); + + const getLocation = (latlng) => { + setLatlng(latlng); + console.log("latlng", latlng); + }; + + const onFinish = (fieldsValue) => { + const values = { + startTime: + fieldsValue["searchPeriod"][0].format("YYYY-MM-DD") + "T" + fieldsValue["searchPeriod"][0].format("HH:mm"), + endTime: + fieldsValue["searchPeriod"][1].format("YYYY-MM-DD") + "T" + fieldsValue["searchPeriod"][1].format("HH:mm"), + latitude: latlng["lat"], + longitude: latlng["lng"], + locationAddress: fieldsValue["searchLocation"], + }; + console.log("Received values of form: ", values); + // postIntelligentSearch(data.id, values); + }; return ( - + + + @@ -77,3 +102,10 @@ const ContainerRight = styled.div` width: 40%; height: 100%; `; + +const InputForm = styled(Form)` + width: 100%; + &.ant-form-vertical .ant-form-item-label { + padding: 0; + } +`; diff --git a/frontend/src/core/api/index.js b/frontend/src/core/api/index.js index b0b235ab9a..bb0ba6071f 100644 --- a/frontend/src/core/api/index.js +++ b/frontend/src/core/api/index.js @@ -169,6 +169,32 @@ export const getCCTVResult = async (id, step) => { return data; }; +/*실종자 리포트 - 지능형 탐색 추가 (Post) */ +export const postIntelligentSearch = async (id, values) => { + const data = axios + .post( + `${process.env.REACT_APP_API_ROOT}/api/missing-people/${id}/search`, + { + ...values, + }, + + { + headers: { "Content-Type": "application/json" }, + }, + ) + .then(function (response) { + console.log(response.data); + return response.data; + }) + .catch(function (e) { + // 실패 시 처리 + console.error(e); + console.log(e.response.data); + alert("탐색 실패. 재시도해주세요."); + }); + return data; +}; + /*의뢰인용 메인 - 실종자 정보 (Get) */ export const getGuardianMissingPerson = async () => { const data = axios From c9f59d0f5f4aad5067bf0abcca357f5676b88f72 Mon Sep 17 00:00:00 2001 From: AnCha Date: Mon, 20 May 2024 05:43:07 +0900 Subject: [PATCH 2/9] =?UTF-8?q?Chore=20:=20=ED=83=90=EC=83=89=20=EC=9D=B4?= =?UTF-8?q?=EB=A0=A5=20api=20=EC=97=B0=EA=B2=B0=20#204?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IntelligentReportList.js | 4 +- .../missingPersonReport/ReportList.js | 12 +- .../missingPersonReport/ReportMain.js | 3 +- .../reportIntelligent/IntelligentMap.js | 171 +++++++++++++++++- .../IntelligentResultView.js | 131 -------------- .../reportIntelligent/IntelligentSearchBox.js | 21 ++- .../IntelligentSearchOption.js | 19 +- .../IntelligentSearchResult.js | 135 +++++++++++++- .../reportIntelligent/ReportIntelligent.js | 52 +++++- frontend/src/core/api/index.js | 6 +- frontend/src/pages/MissingPersonReportPage.js | 48 ++--- 11 files changed, 404 insertions(+), 198 deletions(-) delete mode 100644 frontend/src/components/reportIntelligent/IntelligentResultView.js diff --git a/frontend/src/components/missingPersonReport/IntelligentReportList.js b/frontend/src/components/missingPersonReport/IntelligentReportList.js index 929815c5d1..d8669e0a4c 100644 --- a/frontend/src/components/missingPersonReport/IntelligentReportList.js +++ b/frontend/src/components/missingPersonReport/IntelligentReportList.js @@ -2,7 +2,7 @@ import { Button, Typography } from "antd"; import styled from "styled-components"; import { ReportList } from "./ReportList"; -export const IntelligentReportList = ({ history, onClick }) => { +export const IntelligentReportList = ({ history, onClick, handleClickList }) => { const MoveButton = ({ onClick }) => { return ( @@ -18,7 +18,7 @@ export const IntelligentReportList = ({ history, onClick }) => { {/* 지능형 탐색 */} - + ); }; diff --git a/frontend/src/components/missingPersonReport/ReportList.js b/frontend/src/components/missingPersonReport/ReportList.js index 95370f6132..51bb9f18ff 100644 --- a/frontend/src/components/missingPersonReport/ReportList.js +++ b/frontend/src/components/missingPersonReport/ReportList.js @@ -10,7 +10,7 @@ const data = [ "2024-03-14 10:03:12", ]; -export const ReportList = ({ history }) => { +export const ReportList = ({ history, handleClickList }) => { // const [data, setData] = useState([]); // useEffect(() => { // console.log("history data", listData); @@ -18,6 +18,7 @@ export const ReportList = ({ history }) => { // }, []); console.log("history", history); const ListItems = ({ item }) => { + console.log("item", item); return ( // // @@ -32,7 +33,10 @@ export const ReportList = ({ history }) => { // // // - + { + handleClickList(item.searchId); + }}>

{item.createdAt}

@@ -106,6 +110,10 @@ const ListItemContainer = styled.div` border-radius: 0.5rem; background-color: white; font-size: 1.4rem; + cursor: pointer; + &:hover { + background-color: #f5f5f5; + } @media all and (max-width: 1536px) { padding: 0.6rem 0.5rem; diff --git a/frontend/src/components/missingPersonReport/ReportMain.js b/frontend/src/components/missingPersonReport/ReportMain.js index ec3368fe7b..6c5176f2ef 100644 --- a/frontend/src/components/missingPersonReport/ReportMain.js +++ b/frontend/src/components/missingPersonReport/ReportMain.js @@ -15,6 +15,7 @@ export const ReportMain = ({ betweenData, secondData, onClick, + handleClickList, firstCCTVData, betweenCCTVData, secondCCTVData, @@ -42,7 +43,7 @@ export const ReportMain = ({ - + diff --git a/frontend/src/components/reportIntelligent/IntelligentMap.js b/frontend/src/components/reportIntelligent/IntelligentMap.js index 753558ecc7..bd2b7426f7 100644 --- a/frontend/src/components/reportIntelligent/IntelligentMap.js +++ b/frontend/src/components/reportIntelligent/IntelligentMap.js @@ -1,14 +1,179 @@ +/*global kakao*/ import styled from "styled-components"; -import { Map, MapMarker } from "react-kakao-maps-sdk"; -export const IntelligentMap = () => { +import { useEffect, useRef, useState } from "react"; +import { Circle, CustomOverlayMap, Map, MapMarker, useMap } from "react-kakao-maps-sdk"; +import { Divider, Tooltip } from "antd"; +import Icon, { CloseOutlined, PlusOutlined, MinusOutlined } from "@ant-design/icons"; +import CenterMarker from "../../assets/icons/centerMarker.svg"; +import ActivateRangeMarker from "../../assets/icons/rangeMarker_activate.svg"; +import DisabledRangeMarker from "../../assets/icons/rangeMarker_disabled.svg"; +import LocationMarker from "../../assets/icons/locationMarker.svg"; +import CCTVMarker from "../../assets/icons/cctvMarker_yy.svg"; + +export const IntelligentMap = ({ searchRange, location }) => { + const mapRef = useRef(); + const [showRange, setShowRange] = useState(false); + const [active, setActive] = useState(false); + /*position */ + const [rangePosition, setRangePosition] = useState({ + lat: 37.410826, + lng: 126.894317, + }); + + useEffect(() => { + if (searchRange && searchRange.lat && searchRange.lng) { + setRangePosition(searchRange); + setShowRange(true); + setActive(true); + handleCenter(); + } + }, [searchRange]); + + const handleCenter = () => { + const map = mapRef.current; + if (map) { + console.log("markerPosition", rangePosition); + map.setCenter(new kakao.maps.LatLng(rangePosition.lat, rangePosition.lng)); + map.setLevel(4); + } + console.log("handleCenter", rangePosition); + }; + + const handleLevel = (type) => { + const map = mapRef.current; + if (!map) return; + + if (type === "increase") { + map.setLevel(map.getLevel() + 1); + } else { + type === "decrease"; + map.setLevel(map.getLevel() - 1); + } + }; return ( - + + {showRange && rangePosition.lat && rangePosition.lng && ( + <> + + + + )} + {" "} + + {active ? ( + + { + setShowRange(!showRange); + }}> + {showRange ? : } + + + ) : ( + + {showRange ? : } + + )} + + handleLevel("decrease")}> + + {/* */} + + + handleLevel("increase")}> + {/* */} + + + + ); }; const StIntelligentMap = styled.div` + display: flex; + flex-direction: column; + flex: 1; + flex-grow: 1; + position: relative; width: 100%; height: 100%; `; +const OverlaySideContainer = styled.div` + display: flex; + flex-direction: column; + + position: absolute; + z-index: 1; + top: 10rem; + right: 1rem; +`; + +const OverlayTooltip = styled(Tooltip)``; + +const OverlayButtonStyle = ` + display: flex; + margin-bottom: 1rem; + border-radius: 0.4rem; + background-color: white; + box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.1);`; + +const SingleButton = styled.div` + ${OverlayButtonStyle} + + width: 3.5rem; + height: 3.5rem; + justify-content: center; +`; + +const GroupButton = styled.div` + ${OverlayButtonStyle} + + width: 3.5rem; + height: 7rem; + flex-direction: column; + justify-content: space-between; +`; + +const ButtonWrapper = styled.div` + display: flex; + flex-direction: row; + justify-content: center; + width: 100%; + height: 3.5rem; +`; + +const IconWrapper = styled(Icon)` + color: #555555; + &:focus { + color: rgba(0, 0, 0, 0.5); + } + &:active { + color: rgba(0, 0, 0, 0.5); + } +`; diff --git a/frontend/src/components/reportIntelligent/IntelligentResultView.js b/frontend/src/components/reportIntelligent/IntelligentResultView.js deleted file mode 100644 index 278c9497d8..0000000000 --- a/frontend/src/components/reportIntelligent/IntelligentResultView.js +++ /dev/null @@ -1,131 +0,0 @@ -import styled from "styled-components"; -import { useEffect, useState } from "react"; -import { Select, Pagination, Skeleton, List, Card, Col, Row, Form, Empty } from "antd"; -import { getSearchResultImg } from "../../core/api"; - -export const IntelligentResultView = ({ id }) => { - const [searchStart, setSearchStart] = useState(false); - const [data, setData] = useState([]); - const [dataCount, setDataCount] = useState(0); - - useEffect(() => { - console.log("useEffect", id); - if (id != null) fetchData(); - }, [id]); - - const fetchData = () => { - getSearchResultImg(1, id, "first").then((res) => { - console.log("IntelligentResultView", res.data); - setData(res.data.list); - setDataCount(res.data.count); - setSearchStart(true); - }); - }; - const onChangePage = (page) => { - getSearchResultImg(page, id, "first").then((res) => { - console.log("IntelligentResultView", res.data); - setData(res.data.list); - }); - }; - const Item = ({ item }) => { - return ( - - {item.imgUrl ? ( - - ) : ( - - )} -

{item.date}

-

{item.time}

-

정확도:{item.similarity}

-
- ); - }; - return ( - - - {searchStart ? ( - data.map((item, idx) => ) - ) : ( - - ; - - )} - - - {searchStart && ( - onChangePage(page)} - /> - )} - - - ); -}; -const StIntelligentResultView = styled.div` - display: flex; - flex-direction: column; - align-items: space-between; - - width: 100%; - height: 100%; - //bottom: 0; - padding: 0rem 2rem; - gap: 1.5rem; -`; - -const MiddleContainer = styled.div` - display: flex; - flex-direction: row; - justify-content: space-evenly; - align-content: space-between; - height: 90%; -`; -const BottomContainer = styled.div` - display: flex; - flex-direction: row; - justify-content: end; -`; - -const ItemContainer = styled.div` - display: flex; - flex-direction: column; - align-items: center; - margin-top: 0.9rem; - - p { - @media all and (max-width: 1537px) { - font-size: 1rem; - } - font-size: 1.3rem; - } -`; - -const ItemImage = styled.img` - width: 14.4rem; - height: 23.8rem; - @media all and (max-width: 1537px) { - width: 7.2rem; - height: 11.9rem; - } -`; - -const Paging = styled(Pagination)` - display: flex; - flex-direction: row; - justify-content: flex-end; - float: right; -`; - -const EmptyContainer = styled.div` - display: flex; - justify-content: center; - align-items: center; - - width: 100%; - height: 100%; -`; diff --git a/frontend/src/components/reportIntelligent/IntelligentSearchBox.js b/frontend/src/components/reportIntelligent/IntelligentSearchBox.js index 2e90cb343d..2810abab6a 100644 --- a/frontend/src/components/reportIntelligent/IntelligentSearchBox.js +++ b/frontend/src/components/reportIntelligent/IntelligentSearchBox.js @@ -7,18 +7,23 @@ import DaumPostcode from "react-daum-postcode"; import { Circle, Map, MapMarker } from "react-kakao-maps-sdk"; // 지능형 탐색 - 도로명 주소 검색 -export const IntelligentSeacrchBox = ({ title, form, name, getLocation }) => { +export const IntelligentSeacrchBox = ({ title, form, name, getLocation, location }) => { const mapRef = useRef(); const [openPostcode, setOpenPostcode] = useState(false); - - const [location, setLocation] = useState(""); + const [inputLocation, setInputLocation] = useState(location); const [markerPosition, setMarkerPosition] = useState({}); + + useEffect(() => { + console.log("location", location); + setInputLocation(location); + }, [location]); + useEffect(() => { - console.log("selectAddress", location); - if (location) { + console.log("selectAddress", inputLocation); + if (inputLocation) { handleGeocoder(); } - }, [location]); + }, [inputLocation]); const handle = { // 버튼 클릭 이벤트 @@ -28,7 +33,7 @@ export const IntelligentSeacrchBox = ({ title, form, name, getLocation }) => { // 주소 선택 이벤트 selectAddress: (data) => { - setLocation(data.address); + setInputLocation(data.address); form.setFieldsValue({ [name]: data.address }); // 주소 정보를 Form.Item에 직접 설정 // setOpenPostcode(false); }, @@ -62,7 +67,7 @@ export const IntelligentSeacrchBox = ({ title, form, name, getLocation }) => { return ( - + diff --git a/frontend/src/components/reportIntelligent/IntelligentSearchOption.js b/frontend/src/components/reportIntelligent/IntelligentSearchOption.js index 722ee26bbd..dfccad164b 100644 --- a/frontend/src/components/reportIntelligent/IntelligentSearchOption.js +++ b/frontend/src/components/reportIntelligent/IntelligentSearchOption.js @@ -3,6 +3,7 @@ import { Row, Col, Typography, Form, Button, DatePicker, TimePicker } from "antd import moment from "moment"; import { SeacrchBox } from "../common/SearchBox"; import { IntelligentSeacrchBox } from "./IntelligentSearchBox"; +import { useEffect, useState } from "react"; const { RangePicker } = DatePicker; const config = { @@ -24,8 +25,16 @@ const rangeConfig = { ], }; -export const IntelligentSearchOption = ({ form, name, getLocation }) => { +export const IntelligentSearchOption = ({ form, name, getLocation, location }) => { // const [form] = Form.useForm(); + // const [inputLocation, setInputLocation] = useState(location ?? ""); + console.log("IntelligentSearchOption", location); + // useEffect(() => { + // if (location) { + // console.log("IntelligentSearchOption", location); + // setInputLocation(location); + // } + // }, [location]); return ( @@ -42,7 +51,13 @@ export const IntelligentSearchOption = ({ form, name, getLocation }) => { /> - + diff --git a/frontend/src/components/reportIntelligent/IntelligentSearchResult.js b/frontend/src/components/reportIntelligent/IntelligentSearchResult.js index 3243423144..642ad0ceee 100644 --- a/frontend/src/components/reportIntelligent/IntelligentSearchResult.js +++ b/frontend/src/components/reportIntelligent/IntelligentSearchResult.js @@ -1,9 +1,45 @@ import styled from "styled-components"; -import { Typography, Select, Skeleton } from "antd"; +import { useEffect, useState } from "react"; +import { Typography, Select, Skeleton, Pagination, Empty } from "antd"; import { ResultView } from "../common/ResultView"; -import { IntelligentResultView } from "./IntelligentResultView"; +import { getSearchResultImg } from "../../core/api"; + +export const IntelligentSearchResult = ({ userId, resultData, resultId }) => { + const [searchStart, setSearchStart] = useState(false); + const [data, setData] = useState([]); + const [dataCount, setDataCount] = useState(0); + + useEffect(() => { + if (resultData && Object.keys(resultData).length > 0) { + console.log("resultData", resultData); + setData(resultData.list); + setDataCount(resultData.count); + setSearchStart(true); + } + }, [resultData]); + + const onChangePage = (page) => { + getSearchResultImg(page, userId, "first", resultId, 8).then((res) => { + console.log("IntelligentResultView", res.data); + setData(res.data.list); + }); + }; + + const Item = ({ item }) => { + return ( + + {item.imgUrl ? ( + + ) : ( + + )} +

{item.date}

+

{item.time}

+

정확도:{item.similarity}

+
+ ); + }; -export const IntelligentSearchResult = () => { return ( { ]} /> </TopContainer> */} - <IntelligentResultView /> + <ContentsContainer> + <ResultContainer> + {searchStart ? ( + data.map((item, idx) => <Item key={idx} item={item} />) + ) : ( + <EmptyContainer> + <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} /> + </EmptyContainer> + )} + </ResultContainer> + <BottomContainer> + {searchStart && ( + <Paging + size="small" + defaultCurrent={1} + defaultPageSize={8} + total={dataCount} + onChange={(page) => onChangePage(page)} + /> + )} + </BottomContainer> + </ContentsContainer> </StSearchResult> ); }; @@ -49,6 +106,7 @@ const StSearchResult = styled.div` background-color: white; border-radius: 1rem; `; + const Title = styled.p` margin-top: 1rem; margin-bottom: 1rem; @@ -69,3 +127,72 @@ const TopContainer = styled.div` flex-direction: row; justify-content: end; `; + +const ContentsContainer = styled.div` + display: flex; + flex-direction: column; + align-items: space-between; + + width: 100%; + height: 100%; + //bottom: 0; + padding: 1rem 0; +`; + +const ResultContainer = styled.div` + display: flex; + flex-direction: row; + justify-content: space-between; + align-content: space-between; + flex-wrap: wrap; + width: 100%; + height: 90%; + margin-bottom: 2rem; +`; +const BottomContainer = styled.div` + display: flex; + flex-direction: row; + justify-content: end; +`; + +const ItemContainer = styled.div` + display: flex; + flex-direction: column; + align-items: center; + margin-top: 0.9rem; + + p { + font-size: 1.3rem; + margin: 0.3rem 0; + @media all and (max-width: 1537px) { + font-size: 1rem; + } + } +`; + +const ItemImage = styled.img` + width: 14.4rem; + height: 23.8rem; + /* width: 12.96rem; + height: 21.42rem; */ + @media all and (max-width: 1537px) { + width: 7.2rem; + height: 11.9rem; + } +`; + +const Paging = styled(Pagination)` + display: flex; + flex-direction: row; + justify-content: flex-end; + float: right; +`; + +const EmptyContainer = styled.div` + display: flex; + justify-content: center; + align-items: center; + + width: 100%; + height: 100%; +`; diff --git a/frontend/src/components/reportIntelligent/ReportIntelligent.js b/frontend/src/components/reportIntelligent/ReportIntelligent.js index 1f37c721ef..0811278fdc 100644 --- a/frontend/src/components/reportIntelligent/ReportIntelligent.js +++ b/frontend/src/components/reportIntelligent/ReportIntelligent.js @@ -1,21 +1,58 @@ +/*global kakao*/ import styled from "styled-components"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { Col, Form, Row } from "antd"; import { IntelligentSearchOption } from "./IntelligentSearchOption"; import { IntelligentBasicInfo } from "./IntelligentBasicInfo"; import { IntelligentMap } from "./IntelligentMap"; import { IntelligentSearchResult } from "./IntelligentSearchResult"; import { postIntelligentSearch } from "../../core/api"; +import moment from "moment"; -export const ReportIntelligent = ({ data }) => { +export const ReportIntelligent = ({ data, clickData, clickId }) => { const [form] = Form.useForm(); const [latlng, setLatlng] = useState({}); + const [location, setLocation] = useState(""); + + useEffect(() => { + if (clickData && Object.keys(clickData).length > 0) { + console.log("clickData", clickData); + const start = moment(clickData.startTime, "YYYY-MM-DDTHH:mm:ss").format("YYYY-MM-DD HH:mm"); + const end = moment(clickData.endTime, "YYYY-MM-DDTHH:mm:ss").format("YYYY-MM-DD HH:mm"); + setLatlng({ lat: clickData.searchRange.latitude, lng: clickData.searchRange.longitude }); + + form.setFieldsValue({ + searchPeriod: [moment(start, "YYYY-MM-DD HH:mm"), moment(end, "YYYY-MM-DD HH:mm")], + searchLocation: location, + }); + } + }, [clickData]); + + useEffect(() => { + handleLocation(); + }, [latlng]); const getLocation = (latlng) => { setLatlng(latlng); console.log("latlng", latlng); }; + const handleLocation = () => { + const geocoder = new kakao.maps.services.Geocoder(); + var coord = new kakao.maps.LatLng(latlng.lat, latlng.lng); + + var callback = function (result, status) { + if (status === kakao.maps.services.Status.OK) { + console.log("handleLocation", result); + if (result[0].road_address) { + setLocation(result[0].road_address.address_name); + } + console.log("location", location); + } + }; + geocoder.coord2Address(coord.getLng(), coord.getLat(), callback); + }; + const onFinish = (fieldsValue) => { const values = { startTime: @@ -34,7 +71,12 @@ export const ReportIntelligent = ({ data }) => { <ContainerTop> <ContainerLeft> <InputForm form={form} onFinish={onFinish}> - <IntelligentSearchOption form={form} name={data.missingPeopleName} getLocation={getLocation} /> + <IntelligentSearchOption + form={form} + name={data.missingPeopleName} + getLocation={getLocation} + location={location} + /> </InputForm> </ContainerLeft> <ContainerRight> @@ -43,10 +85,10 @@ export const ReportIntelligent = ({ data }) => { </ContainerTop> <ContainerBottom> <ContainerLeft> - <IntelligentMap /> + <IntelligentMap searchRange={latlng} location={location} /> </ContainerLeft> <ContainerRight> - <IntelligentSearchResult /> + <IntelligentSearchResult userId={data.id} resultData={clickData} resultId={clickId} /> </ContainerRight> </ContainerBottom> </StReportIntelligent> diff --git a/frontend/src/core/api/index.js b/frontend/src/core/api/index.js index bb0ba6071f..6a150abeaf 100644 --- a/frontend/src/core/api/index.js +++ b/frontend/src/core/api/index.js @@ -110,13 +110,13 @@ export const getSearchHistoryList = async (id) => { return data; }; -/* 지능형 탐색결과 사진 가져오기 -1차,2차 탐색 (Get)*/ -export const getSearchResultImg = async (page, id, step, search_id) => { +/* 지능형 탐색결과 사진 가져오기 -1차,2차 탐색, 추가 탐색 (Get)*/ +export const getSearchResultImg = async (page, id, step, search_id, size) => { console.log("getSearchResultImg", id, step, search_id); const data = axios .get( - `${process.env.REACT_APP_API_ROOT}/api/missing-people/${id}/search-result?page=${page}&size=6${step ? `&step=${step}` : ""}${search_id ? `&search-id=${search_id}` : ""}`, + `${process.env.REACT_APP_API_ROOT}/api/missing-people/${id}/search-result?page=${page}&size=${size ? size : 6}${step ? `&step=${step}` : ""}${search_id ? `&search-id=${search_id}` : ""}`, { headers: { "Content-Type": "application/json" }, }, diff --git a/frontend/src/pages/MissingPersonReportPage.js b/frontend/src/pages/MissingPersonReportPage.js index bf02c0981c..3cccdf9389 100644 --- a/frontend/src/pages/MissingPersonReportPage.js +++ b/frontend/src/pages/MissingPersonReportPage.js @@ -32,6 +32,8 @@ function MissingPersonReportPage() { const [firstCCTVData, setFirstCCTVData] = useState([]); const [betweenCCTVData, setBetweenCCTVData] = useState([]); const [secondCCTVData, setSecondCCTVData] = useState([]); + const [clickData, setClickData] = useState([]); //클릭한 리스트 데이터 + const [clickId, setClickId] = useState(); //클릭한 리스트 아이디 const [loading, setLoading] = useState(false); const location = useLocation(); console.log("sssdfsadfsad location", location); @@ -121,17 +123,13 @@ function MissingPersonReportPage() { }); }; - /*지능형 탐색 시작하기 버튼 */ - const ReportStartBtn = () => { - return ( - <StReportStartBtn onClick={scrollToIntelligent}> - <ReportStartBtnLeft> - <ReconciliationOutlined style={{ fontSize: "2rem", color: "#1890FF" }} /> - <p>지능형 탐색</p> - </ReportStartBtnLeft> - <a> 시작하기</a> - </StReportStartBtn> - ); + const handleClickList = (id) => { + getSearchResultImg(1, userId, "", id, 8).then((res) => { + console.log("clickData", res.data); + setClickData(res.data); + setClickId(id); + }); + scrollToIntelligent(); }; return ( @@ -145,13 +143,14 @@ function MissingPersonReportPage() { betweenData={betweenData} secondData={secondData} onClick={scrollToIntelligent} + handleClickList={handleClickList} firstCCTVData={firstCCTVData} betweenCCTVData={betweenCCTVData} secondCCTVData={secondCCTVData} /> </StReport> <StReport> - <ReportIntelligent data={missingPerson} /> + <ReportIntelligent data={missingPerson} clickData={clickData} clickId={clickId} /> </StReport> </StMissingPersonReportPage> ); @@ -170,31 +169,6 @@ const StMissingPersonReportPage = styled.div` scroll-behavior: smooth; `; -const StReportStartBtn = styled.div` - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; - - width: 100%; - height: 5.2rem; - padding: 0rem 0.94rem; - border-radius: 0.3rem; - background-color: #f0f3ff; -`; - -const ReportStartBtnLeft = styled.div` - display: flex; - flex-direction: row; - align-items: center; - gap: 0.5rem; - - p { - font-size: 1.5rem; - font-weight: 600; - } -`; - const StReport = styled.div` height: 100vh; -ms-overflow-style: none; From 0f6712a7f71e173ce543f54b603262219cf2dde3 Mon Sep 17 00:00:00 2001 From: AnCha <tory912@gmail.com> Date: Mon, 20 May 2024 05:43:24 +0900 Subject: [PATCH 3/9] =?UTF-8?q?Chore=20:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=BD=94=EB=93=9C=20=EC=82=AD=EC=A0=9C=20#204?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/common/SearchBox.js | 4 +- .../missingPersonReport/BasicInfo.js | 88 +------------------ 2 files changed, 2 insertions(+), 90 deletions(-) diff --git a/frontend/src/components/common/SearchBox.js b/frontend/src/components/common/SearchBox.js index 81fc2264ee..6560dccafe 100644 --- a/frontend/src/components/common/SearchBox.js +++ b/frontend/src/components/common/SearchBox.js @@ -1,11 +1,9 @@ /*global kakao*/ import styled from "styled-components"; +import { useEffect, useRef, useState } from "react"; import { Input, Modal } from "antd"; import { SearchOutlined } from "@ant-design/icons"; import DaumPostcode from "react-daum-postcode"; -import { useEffect, useRef, useState } from "react"; -import { debounce } from "lodash"; - import { Circle, Map, MapMarker } from "react-kakao-maps-sdk"; //도로명 주소 검색 diff --git a/frontend/src/components/missingPersonReport/BasicInfo.js b/frontend/src/components/missingPersonReport/BasicInfo.js index f7991a5a62..a0085ab0c4 100644 --- a/frontend/src/components/missingPersonReport/BasicInfo.js +++ b/frontend/src/components/missingPersonReport/BasicInfo.js @@ -6,6 +6,7 @@ import { InputForm } from "../common/InputForm"; export const BasicInfo = ({ data }) => { const [form] = Form.useForm(); console.log("BasicInfo", data); + // 실종자 정보 적용 useEffect(() => { console.log("BasicInfo-useEffect", data); @@ -26,54 +27,9 @@ export const BasicInfo = ({ data }) => { }); }, [data]); - // 실종자 정보 적용 - // useEffect(() => { - // form.setFieldsValue({ - // name: "홍길동", - // birth: "1999.01.01", - // gender: "남성", - // missingTime: "2021.08.01 12:00" + "경", - // missingLocation: "서울시 강남구", - // guardianName: "김영희", - // relation: "부", - // guardianContact: "010-1234-5678", - // profileImage: - // "https://spring-server-image-storage.s3.ap-northeast-2.amazonaws.com/missingPeopleId=1/profile/001.PNG", - // }); - // }, []); - /* 실종자 정보 영역 */ const MissingPersonInfo = () => { return ( - // <InfoContainer> - // <Typography.Title level={5}>실종자 정보</Typography.Title> - // <MissingPersonForm form={form} layout="vertical"> - // <Row> - // <Col span={11}> - // {/* <Skeleton.Image active={false} style={{ width: "13rem", height: "16rem" }} /> */} - // {data.profileImage ? ( - // <img src={data.profileImage} alt="Profile" style={{ width: "13rem", height: "16rem" }} /> - // ) : ( - // <Skeleton.Image active={false} style={{ width: "13rem", height: "16rem" }} /> - // )} - // </Col> - // <Col span={13}> - // <InputForm label={"성명"} name={"name"} /> - // <Row> - // <Col span={16}> - // <InputForm label={"생년월일"} name={"birth"} /> - // </Col> - // <Col span={8}> - // <InputForm label={"성별"} name={"gender"} /> - // </Col> - // </Row> - // <InputForm label={"실종일시"} name={"missingTime"} /> - // <InputForm label={"실종장소"} name={"missingLocation"} /> - // </Col> - // </Row> - // </MissingPersonForm> - // </InfoContainer> - <InfoContainer> <Title>실종자 정보 @@ -111,22 +67,6 @@ export const BasicInfo = ({ data }) => { /* 보호자 정보 영역 */ const GuardianInfo = () => { return ( - // - // 보호자 정보 - // - // - // - // - // - // - // - // - // - // - // - // - // - // 보호자 정보 @@ -143,16 +83,6 @@ export const BasicInfo = ({ data }) => { /* 착장정보 영역 */ const WearingInfo = () => { return ( - // - // 착장 정보 - // - // - // - // {data.koQuery} - // - // - // - // 착장 정보 @@ -165,16 +95,6 @@ export const BasicInfo = ({ data }) => { /* 특이사항 영역 */ const DescInfo = () => { return ( - // - // 착장 정보 - // - // - // - // {data.koQuery} - // - // - // - // 특이사항 @@ -271,12 +191,6 @@ const StyledParagraph = styled.p` } `; -const PersonInfoContainer = styled.div` - display: flex; - flex-direction: row; - justify-content: space-between; -`; - const ImageContainer = styled.div` display: flex; width: 14rem; From c4ce4ce879b31fbe0a6436f625f64aecc1bbc56b Mon Sep 17 00:00:00 2001 From: AnCha Date: Mon, 20 May 2024 06:20:34 +0900 Subject: [PATCH 4/9] =?UTF-8?q?Chore=20:=20=EC=8B=A4=EC=A2=85=EC=9E=90=20?= =?UTF-8?q?=ED=83=90=EC=83=89=20=ED=98=84=ED=99=A9=20detail=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20#204?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/missingPersonReport/ReportMain.js | 3 ++- .../missingPersonReport/StepProgress.js | 15 ++++++++++----- frontend/src/pages/MissingPersonReportPage.js | 4 ++++ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/missingPersonReport/ReportMain.js b/frontend/src/components/missingPersonReport/ReportMain.js index 6c5176f2ef..c25be440ec 100644 --- a/frontend/src/components/missingPersonReport/ReportMain.js +++ b/frontend/src/components/missingPersonReport/ReportMain.js @@ -10,6 +10,7 @@ import { ReportResultImages } from "./ReportResultImages"; export const ReportMain = ({ data, step, + stepDetail, history, firstdata, betweenData, @@ -57,7 +58,7 @@ export const ReportMain = ({ betweenData={betweenCCTVData} secondData={secondCCTVData} /> - + diff --git a/frontend/src/components/missingPersonReport/StepProgress.js b/frontend/src/components/missingPersonReport/StepProgress.js index 0a5cd003a9..d8b74a9e3e 100644 --- a/frontend/src/components/missingPersonReport/StepProgress.js +++ b/frontend/src/components/missingPersonReport/StepProgress.js @@ -2,8 +2,9 @@ import styled from "styled-components"; import { useState, useEffect } from "react"; import { Steps, Typography } from "antd"; -export const StepProgress = ({ step }) => { +export const StepProgress = ({ step, stepDetail }) => { const [current, setCurrent] = useState(0); + const [detail, setDetail] = useState(""); const description = "This is a description."; const onChange = (value) => { console.log("onChange:", value); @@ -12,6 +13,9 @@ export const StepProgress = ({ step }) => { useEffect(() => { console.log("step", step); setCurrent(step); + if (step === 1 || step === 3) { + setDetail(stepDetail); + } }, [step]); return ( @@ -21,20 +25,21 @@ export const StepProgress = ({ step }) => { className="custom-steps" direction="vertical" current={current} - onChange={onChange} + // onChange={onChange} items={[ { title: "정보 등록", }, { title: "1차 탐색", + description: current === 1 ? detail : "", }, { title: "이미지 선별", - description, }, { title: "2차 탐색", + description: current === 3 ? detail : "", }, { title: "수색", @@ -90,7 +95,7 @@ const Step = styled(Steps)` font-size: 1.6rem; } &.ant-steps .ant-steps-item-description { - font-size: 1.4rem; + font-size: 1.2rem; } } @@ -107,7 +112,7 @@ const Step = styled(Steps)` font-size: 1.4rem; } &.ant-steps .ant-steps-item-description { - font-size: 1.2rem; + font-size: 1.1rem; } &.ant-steps.ant-steps-vertical > .ant-steps-item > .ant-steps-item-container > .ant-steps-item-tail { left: 1rem; diff --git a/frontend/src/pages/MissingPersonReportPage.js b/frontend/src/pages/MissingPersonReportPage.js index 3cccdf9389..e9a14960ec 100644 --- a/frontend/src/pages/MissingPersonReportPage.js +++ b/frontend/src/pages/MissingPersonReportPage.js @@ -25,6 +25,7 @@ import { ReportIntelligent } from "../components/reportIntelligent/ReportIntelli function MissingPersonReportPage() { const [missingPerson, setMissingPerson] = useState([]); const [step, setStep] = useState([]); + const [stepDetail, setStepDetail] = useState(""); //step별 상세정보 const [searchHistoryList, setSearchHistoryList] = useState([]); const [firstdata, setFirstdata] = useState([]); const [betweenData, setBetweenData] = useState([]); @@ -63,12 +64,14 @@ function MissingPersonReportPage() { switch (res.data.step) { case "FIRST": setStep(1); + setStepDetail(res.data.detail); break; case "BETWEEN": setStep(2); break; case "SECOND": setStep(3); + setStepDetail(res.data.detail); break; case "EXIT": setStep(4); @@ -138,6 +141,7 @@ function MissingPersonReportPage() { Date: Mon, 20 May 2024 14:25:39 +0900 Subject: [PATCH 5/9] =?UTF-8?q?Fix=20:=20getLocation=20=EC=97=90=EB=9F=AC?= =?UTF-8?q?=20=ED=95=B4=EA=B2=B0=20#204?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/common/SearchBox.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/common/SearchBox.js b/frontend/src/components/common/SearchBox.js index 6560dccafe..9b9261a427 100644 --- a/frontend/src/components/common/SearchBox.js +++ b/frontend/src/components/common/SearchBox.js @@ -7,7 +7,7 @@ import DaumPostcode from "react-daum-postcode"; import { Circle, Map, MapMarker } from "react-kakao-maps-sdk"; //도로명 주소 검색 -export const SeacrchBox = ({ title, form, name, getLocation }) => { +export const SeacrchBox = ({ title, form, name, getLocation, type }) => { const mapRef = useRef(); const [openPostcode, setOpenPostcode] = useState(false); @@ -36,7 +36,10 @@ export const SeacrchBox = ({ title, form, name, getLocation }) => { // 선택 완료 이벤트 clickOK: () => { - getLocation(markerPosition); + if (name === "searchLocation") { + getLocation(markerPosition); + } + setOpenPostcode(false); }, }; From 79ad997affcad8aa8591eadb671d66c036e76df7 Mon Sep 17 00:00:00 2001 From: AnCha Date: Wed, 22 May 2024 03:36:15 +0900 Subject: [PATCH 6/9] =?UTF-8?q?Feat=20:=20=ED=83=90=EC=83=89=20=EC=9D=B4?= =?UTF-8?q?=EB=A0=A5=20cctv=20=EC=9C=84=EC=B9=98=20=EB=A7=88=EC=BB=A4=20?= =?UTF-8?q?=ED=91=9C=EC=8B=9C=20#204?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reportIntelligent/IntelligentMap.js | 146 +++++++++++++++++- .../reportIntelligent/ReportIntelligent.js | 14 +- frontend/src/core/api/index.js | 11 +- 3 files changed, 161 insertions(+), 10 deletions(-) diff --git a/frontend/src/components/reportIntelligent/IntelligentMap.js b/frontend/src/components/reportIntelligent/IntelligentMap.js index bd2b7426f7..ea86a9b40f 100644 --- a/frontend/src/components/reportIntelligent/IntelligentMap.js +++ b/frontend/src/components/reportIntelligent/IntelligentMap.js @@ -2,7 +2,7 @@ import styled from "styled-components"; import { useEffect, useRef, useState } from "react"; import { Circle, CustomOverlayMap, Map, MapMarker, useMap } from "react-kakao-maps-sdk"; -import { Divider, Tooltip } from "antd"; +import { Button, Divider, List, Tooltip } from "antd"; import Icon, { CloseOutlined, PlusOutlined, MinusOutlined } from "@ant-design/icons"; import CenterMarker from "../../assets/icons/centerMarker.svg"; import ActivateRangeMarker from "../../assets/icons/rangeMarker_activate.svg"; @@ -10,7 +10,7 @@ import DisabledRangeMarker from "../../assets/icons/rangeMarker_disabled.svg"; import LocationMarker from "../../assets/icons/locationMarker.svg"; import CCTVMarker from "../../assets/icons/cctvMarker_yy.svg"; -export const IntelligentMap = ({ searchRange, location }) => { +export const IntelligentMap = ({ searchRange, location, cctvData }) => { const mapRef = useRef(); const [showRange, setShowRange] = useState(false); const [active, setActive] = useState(false); @@ -50,6 +50,66 @@ export const IntelligentMap = ({ searchRange, location }) => { map.setLevel(map.getLevel() - 1); } }; + + const Item = ({ item }) => { + return ( + + + + ); + }; + + const EventMarkerContainer = ({ position, images, markerStyle }) => { + const map = useMap(); + const [isVisible, setIsVisible] = useState(false); + + return ( + <> + { + map.panTo(marker.getPosition()); + setIsVisible(true); + }} + image={{ + src: markerStyle, // 마커이미지의 주소입니다 + size: { + width: 30, + height: 40, + }, // 마커이미지의 크기입니다 + }} + /> + {isVisible && ( + + + +

이미지 목록

+ +
+ 탐색 결과는 최신순으로 정렬됩니다. + + { + console.log(page); + }, + pageSize: 3, + size: "small", + position: "bottom", + }} + dataSource={images} + renderItem={(item) => } + /> +
+
+ )} + + ); + }; + return ( { /> )} - {" "} + {active && + cctvData && + cctvData.map( + (position) => ( + console.log("position", position), + ( + + ) + ), + )} + {active ? ( @@ -124,6 +199,71 @@ const StIntelligentMap = styled.div` width: 100%; height: 100%; `; + +const ContentsContainer = styled.div` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 37.3rem; + height: 30rem; + padding: 1rem; + background-color: white; + border-radius: 1rem; + + overflow-y: hidden; + cursor: pointer; +`; + +const TopContainer = styled.div` + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + width: 100%; + p { + font-size: 1.5rem; + } +`; +const ExplainText = styled.div` + display: flex; + justify-content: start; + width: 100%; + font-size: 1.2rem; + color: #8b8b8b; +`; + +const ImageList = styled(List)` + width: 100%; + height: 100%; +`; + +const ItemContainer = styled.div` + display: flex; + flex-direction: column; + align-items: center; + margin-top: 0.9rem; + + p { + @media all and (max-width: 1537px) { + font-size: 1rem; + } + font-size: 1.3rem; + } +`; + +const ItemImage = styled.img` + /* width: 14.4rem; + height: 23.8rem; */ + width: 11.52rem; + height: 19.04rem; + margin-right: 0.5rem; + @media all and (max-width: 1537px) { + width: 7.2rem; + height: 11.9rem; + } +`; + const OverlaySideContainer = styled.div` display: flex; flex-direction: column; diff --git a/frontend/src/components/reportIntelligent/ReportIntelligent.js b/frontend/src/components/reportIntelligent/ReportIntelligent.js index 0811278fdc..b5a3437f93 100644 --- a/frontend/src/components/reportIntelligent/ReportIntelligent.js +++ b/frontend/src/components/reportIntelligent/ReportIntelligent.js @@ -6,13 +6,14 @@ import { IntelligentSearchOption } from "./IntelligentSearchOption"; import { IntelligentBasicInfo } from "./IntelligentBasicInfo"; import { IntelligentMap } from "./IntelligentMap"; import { IntelligentSearchResult } from "./IntelligentSearchResult"; -import { postIntelligentSearch } from "../../core/api"; +import { getCCTVResult, postIntelligentSearch } from "../../core/api"; import moment from "moment"; export const ReportIntelligent = ({ data, clickData, clickId }) => { const [form] = Form.useForm(); const [latlng, setLatlng] = useState({}); const [location, setLocation] = useState(""); + const [cctvData, setCCTVData] = useState([]); useEffect(() => { if (clickData && Object.keys(clickData).length > 0) { @@ -20,7 +21,7 @@ export const ReportIntelligent = ({ data, clickData, clickId }) => { const start = moment(clickData.startTime, "YYYY-MM-DDTHH:mm:ss").format("YYYY-MM-DD HH:mm"); const end = moment(clickData.endTime, "YYYY-MM-DDTHH:mm:ss").format("YYYY-MM-DD HH:mm"); setLatlng({ lat: clickData.searchRange.latitude, lng: clickData.searchRange.longitude }); - + fetchCCTVData(); form.setFieldsValue({ searchPeriod: [moment(start, "YYYY-MM-DD HH:mm"), moment(end, "YYYY-MM-DD HH:mm")], searchLocation: location, @@ -32,6 +33,13 @@ export const ReportIntelligent = ({ data, clickData, clickId }) => { handleLocation(); }, [latlng]); + const fetchCCTVData = () => { + getCCTVResult(data.id, "", clickId).then((res) => { + console.log("firstCCTVData", res.data); + setCCTVData(res.data); + }); + }; + const getLocation = (latlng) => { setLatlng(latlng); console.log("latlng", latlng); @@ -85,7 +93,7 @@ export const ReportIntelligent = ({ data, clickData, clickId }) => {
- + diff --git a/frontend/src/core/api/index.js b/frontend/src/core/api/index.js index 6a150abeaf..81bf2da72c 100644 --- a/frontend/src/core/api/index.js +++ b/frontend/src/core/api/index.js @@ -152,11 +152,14 @@ export const getBetweenResultImg = async (page, id) => { }; /* 탐색 결과에 대한 cctv 위치 (Get)*/ -export const getCCTVResult = async (id, step) => { +export const getCCTVResult = async (id, step, search_id) => { const data = axios - .get(`${process.env.REACT_APP_API_ROOT}/api/missing-people/${id}/mapposition?step=${step}`, { - headers: { "Content-Type": "application/json" }, - }) + .get( + `${process.env.REACT_APP_API_ROOT}/api/missing-people/${id}/mapposition?${step ? `step=${step}` : `search-id=${search_id}`}`, + { + headers: { "Content-Type": "application/json" }, + }, + ) .then(function (response) { return response.data; }) From 25d25a1bd0ee3f6771e6fc909b26f69c83d8fb36 Mon Sep 17 00:00:00 2001 From: AnCha Date: Wed, 22 May 2024 03:56:14 +0900 Subject: [PATCH 7/9] =?UTF-8?q?Fix=20:=20=EC=A7=80=EB=8F=84=20=EB=B0=98?= =?UTF-8?q?=EA=B2=BD=20=ED=91=9C=EC=8B=9C=20=EC=95=88=EB=82=98=EC=98=A4?= =?UTF-8?q?=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0=20#204?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/reportIntelligent/IntelligentSearchBox.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/reportIntelligent/IntelligentSearchBox.js b/frontend/src/components/reportIntelligent/IntelligentSearchBox.js index 2810abab6a..35fe3b8dca 100644 --- a/frontend/src/components/reportIntelligent/IntelligentSearchBox.js +++ b/frontend/src/components/reportIntelligent/IntelligentSearchBox.js @@ -10,7 +10,7 @@ import { Circle, Map, MapMarker } from "react-kakao-maps-sdk"; export const IntelligentSeacrchBox = ({ title, form, name, getLocation, location }) => { const mapRef = useRef(); const [openPostcode, setOpenPostcode] = useState(false); - const [inputLocation, setInputLocation] = useState(location); + const [inputLocation, setInputLocation] = useState(""); const [markerPosition, setMarkerPosition] = useState({}); useEffect(() => { @@ -36,6 +36,7 @@ export const IntelligentSeacrchBox = ({ title, form, name, getLocation, location setInputLocation(data.address); form.setFieldsValue({ [name]: data.address }); // 주소 정보를 Form.Item에 직접 설정 // setOpenPostcode(false); + console.log("selectAddress", data.address); }, // 선택 완료 이벤트 @@ -46,6 +47,7 @@ export const IntelligentSeacrchBox = ({ title, form, name, getLocation, location }; const handleGeocoder = () => { + console.log("handleGeocoder"); const geocoder = new kakao.maps.services.Geocoder(); var callback = function (result, status) { if (status === kakao.maps.services.Status.OK) { @@ -61,7 +63,7 @@ export const IntelligentSeacrchBox = ({ title, form, name, getLocation, location } } }; - geocoder.addressSearch(location, callback); + geocoder.addressSearch(inputLocation, callback); }; return ( From 2943ccbb906c6175fa2a2d8ebb7f0261995cda9d Mon Sep 17 00:00:00 2001 From: AnCha Date: Wed, 22 May 2024 03:57:48 +0900 Subject: [PATCH 8/9] =?UTF-8?q?Chore=20:=20=EC=84=B1=EB=B3=84=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20#204?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/missingPersonList/CardView.js | 2 +- frontend/src/components/missingPersonReport/BasicInfo.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/missingPersonList/CardView.js b/frontend/src/components/missingPersonList/CardView.js index eec607e564..802fc4e674 100644 --- a/frontend/src/components/missingPersonList/CardView.js +++ b/frontend/src/components/missingPersonList/CardView.js @@ -17,7 +17,7 @@ export const CardView = ({ data }) => { form.setFieldsValue({ name: data.name, birth: data.birthdate, - gender: data.gender === "남성" ? "남" : "여", + gender: data.gender === "man" ? "남" : "여", missingTime: dateForm(data.missingAt), missingLocation: data.missingLocation, }); diff --git a/frontend/src/components/missingPersonReport/BasicInfo.js b/frontend/src/components/missingPersonReport/BasicInfo.js index a0085ab0c4..894fd5b4a9 100644 --- a/frontend/src/components/missingPersonReport/BasicInfo.js +++ b/frontend/src/components/missingPersonReport/BasicInfo.js @@ -13,7 +13,7 @@ export const BasicInfo = ({ data }) => { form.setFieldsValue({ name: data.missingPeopleName, birth: data.birthdate, - gender: data.gender, + gender: data.gender == "man" ? "남성" : "여성", missingTime: String(data.missingAt).split("T")[0] + " " + From 7fafaf80fc3489043bec08139f777d31be3a55cf Mon Sep 17 00:00:00 2001 From: AnCha Date: Wed, 22 May 2024 04:21:10 +0900 Subject: [PATCH 9/9] =?UTF-8?q?Feat=20:=20=ED=83=90=EC=83=89=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EC=8B=9C=20=EC=83=88=EB=A1=9C=EA=B3=A0=EC=B9=A8=20?= =?UTF-8?q?=EB=B0=8F=20=EB=A9=94=EC=84=B8=EC=A7=80=20#204?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reportIntelligent/ReportIntelligent.js | 73 ++++++++++++------- 1 file changed, 46 insertions(+), 27 deletions(-) diff --git a/frontend/src/components/reportIntelligent/ReportIntelligent.js b/frontend/src/components/reportIntelligent/ReportIntelligent.js index b5a3437f93..412a925a24 100644 --- a/frontend/src/components/reportIntelligent/ReportIntelligent.js +++ b/frontend/src/components/reportIntelligent/ReportIntelligent.js @@ -1,7 +1,7 @@ /*global kakao*/ import styled from "styled-components"; import { useEffect, useState } from "react"; -import { Col, Form, Row } from "antd"; +import { Col, Form, Row, message } from "antd"; import { IntelligentSearchOption } from "./IntelligentSearchOption"; import { IntelligentBasicInfo } from "./IntelligentBasicInfo"; import { IntelligentMap } from "./IntelligentMap"; @@ -11,6 +11,7 @@ import moment from "moment"; export const ReportIntelligent = ({ data, clickData, clickId }) => { const [form] = Form.useForm(); + const [messageApi, contextHolder] = message.useMessage(); const [latlng, setLatlng] = useState({}); const [location, setLocation] = useState(""); const [cctvData, setCCTVData] = useState([]); @@ -61,6 +62,14 @@ export const ReportIntelligent = ({ data, clickData, clickId }) => { geocoder.coord2Address(coord.getLng(), coord.getLat(), callback); }; + const success = () => { + messageApi.open({ + type: "success", + content: "탐색 결과는 지능형 탐색 이력에서 확인 가능합니다.", + duration: 10, + }); + }; + const onFinish = (fieldsValue) => { const values = { startTime: @@ -72,34 +81,44 @@ export const ReportIntelligent = ({ data, clickData, clickId }) => { locationAddress: fieldsValue["searchLocation"], }; console.log("Received values of form: ", values); - // postIntelligentSearch(data.id, values); + postIntelligentSearch(data.id, values).then((res) => { + if (res.success) { + success(); + setTimeout(() => { + window.location.reload(); + }, 2000); + } + }); }; return ( - - - - - - - - - - - - - - - - - - - - + <> + {contextHolder} + + + + + + + + + + + + + + + + + + + + + ); };