diff --git a/Touchkebao/index.html b/Touchkebao/index.html index 92656ef9..d0dcd4e9 100644 --- a/Touchkebao/index.html +++ b/Touchkebao/index.html @@ -11,6 +11,10 @@ +
diff --git a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/components/selectMap.module.scss b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/components/selectMap.module.scss new file mode 100644 index 00000000..f0a77bb3 --- /dev/null +++ b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/components/selectMap.module.scss @@ -0,0 +1,111 @@ +.selectMapContainer { + display: flex; + flex-direction: column; + height: 600px; + gap: 16px; +} + +.searchArea { + flex-shrink: 0; + position: relative; +} + +.searchInput { + width: 100%; +} + +.searchResults { + position: absolute; + top: 100%; + left: 0; + right: 0; + z-index: 1000; + background: #fff; + border: 1px solid #e8e8e8; + border-radius: 4px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + margin-top: 4px; + max-height: 300px; + overflow-y: auto; + + :global(.ant-list-item) { + cursor: pointer; + padding: 12px 16px; + transition: background-color 0.2s; + + &:hover { + background-color: #f5f5f5; + } + } +} + +.mapArea { + flex: 1; + position: relative; + border: 1px solid #e8e8e8; + border-radius: 4px; + overflow: hidden; +} + +.mapContainer { + width: 100%; + height: 100%; + min-height: 400px; +} + +.loadingOverlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(255, 255, 255, 0.8); + display: flex; + align-items: center; + justify-content: center; + z-index: 100; +} + +.locationInfo { + flex-shrink: 0; + padding: 12px 16px; + background: #f5f5f5; + border-radius: 4px; + border: 1px solid #e8e8e8; +} + +.locationLabel { + display: flex; + align-items: center; + gap: 8px; + font-size: 14px; + font-weight: 500; + color: #1890ff; + margin-bottom: 8px; +} + +.locationText { + font-size: 14px; + color: #333; + margin-bottom: 4px; + word-break: break-all; +} + +.locationCoords { + font-size: 12px; + color: #999; + font-family: "Monaco", "Menlo", "Ubuntu Mono", monospace; +} + +.resultItem { + :global(.ant-list-item-meta-title) { + font-size: 14px; + color: #333; + margin-bottom: 4px; + } + + :global(.ant-list-item-meta-description) { + font-size: 12px; + color: #999; + } +} diff --git a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/components/selectMap.tsx b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/components/selectMap.tsx index 7393c08c..d2658da6 100644 --- a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/components/selectMap.tsx +++ b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/components/selectMap.tsx @@ -1,22 +1,45 @@ -import React, { useCallback, useEffect, useRef, useState } from "react"; -import { - AutoComplete, - Input as AntInput, - message, - Modal, - Spin, - Button, -} from "antd"; -import { ContractData, weChatGroup, ChatRecord } from "@/pages/pc/ckbox/data"; +import React, { useState, useEffect, useRef } from "react"; +import { Modal, Input, Button, List, message, Spin } from "antd"; +import { SearchOutlined, EnvironmentOutlined } from "@ant-design/icons"; import { useWebSocketStore } from "@/store/module/websocket/websocket"; +import styles from "./selectMap.module.scss"; -declare const AMap: any; +// 声明腾讯地图类型 +declare global { + interface Window { + qq: any; + } +} interface SelectMapProps { visible: boolean; onClose: () => void; - contract: ContractData | weChatGroup; - addMessage: (message: ChatRecord) => void; + contract?: any; + addMessage?: (message: any) => void; + onConfirm?: (locationXml: string) => void; +} + +interface SearchResult { + id: string; + title: string; + address: string; + location: { + lat: number; + lng: number; + }; + adcode?: string; + city?: string; + district?: string; +} + +interface LocationData { + x: string; // 经度 + y: string; // 纬度 + scale: string; // 缩放级别 + label: string; // 地址标签 + poiname: string; // POI名称 + maptype: string; // 地图类型 + poiid: string; // POI ID } const SelectMap: React.FC = ({ @@ -24,874 +47,360 @@ const SelectMap: React.FC = ({ onClose, contract, addMessage, + onConfirm, }) => { - const [selectedLocation, setSelectedLocation] = useState(null); - const mapRef = useRef(null); - const markersRef = useRef([]); // 使用数组保存所有标记点 - const geocoderRef = useRef(null); // 保存 Geocoder 实例 - const placeSearchRef = useRef(null); // 保存 PlaceSearch 实例 - const geolocationRef = useRef(null); // 保存 Geolocation 实例 - const pendingClickRef = useRef<{ - lat: number; - lng: number; - lnglat: any; - } | null>(null); // 保存待处理的点击坐标 - const [options, setOptions] = useState([]); - const [mapLoading, setMapLoading] = useState(true); - - const sendCommand = useWebSocketStore(state => state.sendCommand); - - // 清除所有标记点 - const clearAllMarkers = useCallback(() => { - if (markersRef.current && markersRef.current.length > 0) { - console.log(`清除 ${markersRef.current.length} 个标记点`); - markersRef.current.forEach(marker => { - if (marker) { - marker.setMap(null); - marker = null; - } - }); - markersRef.current = []; - } - }, []); - - const addMarker = useCallback( - (lnglat: any) => { - console.log("addMarker 调用,坐标:", lnglat); - - // 先清除所有现有的标记点 - clearAllMarkers(); - - // 创建红色图标,保持默认倒水滴形状 - const redIcon = new AMap.Icon({ - size: new AMap.Size(25, 34), // 默认标记点尺寸 - image: "https://webapi.amap.com/theme/v1.3/markers/n/mark_r.png", // 红色标记点图片 - imageOffset: new AMap.Pixel(0, 0), - imageSize: new AMap.Size(25, 34), - }); - - // 创建新的标记点 - const newMarker = new AMap.Marker({ - position: lnglat, - map: mapRef.current, - icon: redIcon, - }); - - // 将新标记点添加到数组中 - markersRef.current.push(newMarker); - - mapRef.current.setCenter(lnglat); - mapRef.current.setZoom(16); // 确保缩放到合适级别 - console.log("新 marker 已添加并居中"); - }, - [clearAllMarkers], + const [searchValue, setSearchValue] = useState(""); + const [searchResults, setSearchResults] = useState([]); + const [isSearching, setIsSearching] = useState(false); + const [selectedLocation, setSelectedLocation] = useState( + null, ); + const [map, setMap] = useState(null); + const [isReverseGeocoding, setIsReverseGeocoding] = useState(false); + const mapContainerRef = useRef(null); + const geocoderRef = useRef(null); + const searchServiceRef = useRef(null); + const markerRef = useRef(null); + const { sendCommand } = useWebSocketStore.getState(); - // 通用的地址获取函数 - const getAddressForLocation = useCallback( - (lat: number, lng: number, lnglat: any) => { - console.log("=== getAddressForLocation 调用 ==="); - console.log("坐标:", { lat, lng }); - console.log( - "Geocoder ref 状态:", - geocoderRef.current ? "存在" : "不存在", - ); - - // 检查 Geocoder 是否已初始化 - if (!geocoderRef.current) { - console.warn("Geocoder 未初始化,无法获取地址"); - return false; - } - - // 使用更精确的坐标进行查询 - // 高德地图 getAddress 支持 LngLat 对象或 [lng, lat] 数组 - let queryLnglat: any; - if (lnglat && typeof lnglat.getLat === "function") { - // 如果传入的是 LngLat 对象,直接使用 - queryLnglat = lnglat; - } else { - // 否则创建新的 LngLat 对象或使用数组格式 - try { - queryLnglat = new AMap.LngLat(lng, lat); - } catch (error) { - console.error("创建 LngLat 对象失败,使用数组格式:", error); - queryLnglat = [lng, lat]; - } - } - console.log("调用 geocoder.getAddress,坐标:", queryLnglat); - - try { - geocoderRef.current.getAddress( - queryLnglat, - (status: string, result: any) => { - console.log("=== Geocoder 回调触发(通用函数) ==="); - console.log("Status:", status); - console.log( - "Result:", - result ? JSON.stringify(result, null, 2) : "null", - ); - - if ( - status === "complete" && - result && - result.info === "OK" && - result.regeocode - ) { - const regeocode = result.regeocode; - const formattedAddress = regeocode.formattedAddress || ""; - const addressComponent = regeocode.addressComponent || {}; - - // 构建详细地址信息 - let addressLabel = formattedAddress; - let poiName = "点击位置"; - - // 优先级1: 如果有POI信息,优先使用POI名称 - if (regeocode.pois && regeocode.pois.length > 0) { - const poi = regeocode.pois[0]; - poiName = poi.name || poiName; - const poiAddress = poi.address || ""; - addressLabel = poiAddress - ? `${poiName} ${poiAddress}` - : `${poiName} ${formattedAddress}`; - } - // 优先级2: 如果有建筑物信息 - else if (regeocode.buildings && regeocode.buildings.length > 0) { - const building = regeocode.buildings[0]; - poiName = building.name || addressComponent.building || poiName; - addressLabel = `${poiName} ${formattedAddress}`; - } - // 优先级3: 如果有AOI(兴趣区域)信息 - else if (regeocode.aois && regeocode.aois.length > 0) { - const aoi = regeocode.aois[0]; - poiName = aoi.name || poiName; - addressLabel = `${poiName} ${formattedAddress}`; - } - // 优先级4: 使用地址组件构建详细地址 - else if (addressComponent.building) { - poiName = addressComponent.building; - addressLabel = `${poiName} ${formattedAddress}`; - } - // 优先级5: 组合地址组件 - else { - const parts = []; - if (addressComponent.province) - parts.push(addressComponent.province); - if (addressComponent.city) parts.push(addressComponent.city); - if (addressComponent.district) - parts.push(addressComponent.district); - if (addressComponent.township) - parts.push(addressComponent.township); - if (addressComponent.street) - parts.push(addressComponent.street); - if (addressComponent.streetNumber) - parts.push(addressComponent.streetNumber); - - if (parts.length > 0) { - const fullAddress = parts.join(""); - poiName = - addressComponent.street || - addressComponent.district || - "点击位置"; - addressLabel = fullAddress || formattedAddress; - } else { - addressLabel = - formattedAddress || `纬度: ${lat}, 经度: ${lng}`; - } - } - - setSelectedLocation({ - lat: lat, - lng: lng, - label: addressLabel, - poiname: poiName, - }); - - message.success("地址信息获取成功"); - } else { - console.warn("=== Geocoder 返回异常,尝试 PlaceSearch ==="); - console.warn("Status:", status); - console.warn("Result:", result); - // Geocoder 失败,使用 PlaceSearch 作为备用 - if (placeSearchRef.current) { - try { - const searchLnglat = lnglat || [lng, lat]; - placeSearchRef.current.searchNearBy( - "", - searchLnglat, - 1000, - (searchStatus: string, searchResult: any) => { - if ( - searchStatus === "complete" && - searchResult && - searchResult.info === "OK" && - searchResult.poiList?.pois?.length > 0 - ) { - const poi = searchResult.poiList.pois[0]; - const poiLabel = poi.address - ? `${poi.name} ${poi.address}` - : poi.name; - setSelectedLocation({ - lat: lat, - lng: lng, - label: poiLabel, - poiname: poi.name, - }); - message.success("通过附近搜索获取到地址信息"); - } else { - console.warn("PlaceSearch 返回异常:", { - status: searchStatus, - result: searchResult, - }); - const coordLabel = `纬度: ${lat}, 经度: ${lng}`; - setSelectedLocation({ - lat: lat, - lng: lng, - label: coordLabel, - poiname: "点击位置", - }); - message.warning("无法获取详细地址信息,但坐标已记录"); - } - }, - ); - } catch (placeSearchError) { - console.error( - "PlaceSearch.searchNearBy 调用异常:", - placeSearchError, - ); - const coordLabel = `纬度: ${lat}, 经度: ${lng}`; - setSelectedLocation({ - lat: lat, - lng: lng, - label: coordLabel, - poiname: "点击位置", - }); - message.warning("无法获取详细地址信息,但坐标已记录"); - } - } else { - const coordLabel = `纬度: ${lat}, 经度: ${lng}`; - setSelectedLocation({ - lat: lat, - lng: lng, - label: coordLabel, - poiname: "点击位置", - }); - message.warning("无法获取详细地址信息,但坐标已记录"); - } - } - }, - ); - } catch (error) { - console.error("=== Geocoder.getAddress 调用异常 ===", error); - // 如果 geocoder 调用失败,尝试使用 PlaceSearch - if (placeSearchRef.current) { - console.log("尝试使用 PlaceSearch 作为备用方案"); - try { - placeSearchRef.current.searchNearBy( - "", - lnglat || [lng, lat], - 1000, - (status: string, result: any) => { - if ( - status === "complete" && - result && - result.info === "OK" && - result.poiList?.pois?.length > 0 - ) { - const poi = result.poiList.pois[0]; - const poiLabel = poi.address - ? `${poi.name} ${poi.address}` - : poi.name; - setSelectedLocation({ - lat: lat, - lng: lng, - label: poiLabel, - poiname: poi.name, - }); - message.success("通过附近搜索获取到地址信息"); - } else { - const coordLabel = `纬度: ${lat}, 经度: ${lng}`; - setSelectedLocation({ - lat: lat, - lng: lng, - label: coordLabel, - poiname: "点击位置", - }); - message.warning("无法获取详细地址信息,但坐标已记录"); - } - }, - ); - } catch (placeSearchError) { - console.error("PlaceSearch 调用也失败:", placeSearchError); - const coordLabel = `纬度: ${lat}, 经度: ${lng}`; - setSelectedLocation({ - lat: lat, - lng: lng, - label: coordLabel, - poiname: "点击位置", - }); - message.warning("无法获取详细地址信息,但坐标已记录"); - } - } else { - const coordLabel = `纬度: ${lat}, 经度: ${lng}`; - setSelectedLocation({ - lat: lat, - lng: lng, - label: coordLabel, - poiname: "点击位置", - }); - message.warning("无法获取详细地址信息,但坐标已记录"); - } - return false; - } - - return true; - }, - [], - ); - - const initMap = useCallback(() => { - console.log("initMap 执行中"); - setMapLoading(true); - - // 确保容器存在 - const container = document.getElementById("amap-container"); - if (!container) { - console.error("地图容器不存在"); - setMapLoading(false); - return; - } - - // 确保容器样式正确 - container.style.pointerEvents = "auto"; - container.style.cursor = "crosshair"; - container.style.position = "relative"; - container.style.zIndex = "1"; - - const map = new AMap.Map("amap-container", { - zoom: 16, - center: [118.113653, 24.470164], // 默认中心 - viewMode: "2D", // 明确指定视图模式 - }); - mapRef.current = map; - - // 添加超时机制,防止 loading 一直显示 - const loadingTimeout = setTimeout(() => { - console.warn("地图加载超时,强制关闭 loading"); - setMapLoading(false); - }, 10000); // 10秒超时 - - // 立即加载插件,不等待地图 complete 事件 - console.log("=== 立即开始加载 AMap 插件(地图创建后) ==="); - AMap.plugin( - [ - "AMap.AutoComplete", - "AMap.PlaceSearch", - "AMap.Geocoder", - "AMap.Geolocation", - ], - error => { - if (error) { - console.error("=== AMap 插件加载失败 ===", error); - message.error("地图插件加载失败,部分功能可能不可用"); - clearTimeout(loadingTimeout); - setMapLoading(false); - return; - } - console.log("=== AMap 插件加载成功 ==="); - - // 立即创建 PlaceSearch 和 Geocoder 实例 - const placeSearch = new AMap.PlaceSearch({ - city: "全国", - map: map, - }); - placeSearchRef.current = placeSearch; - console.log("PlaceSearch 实例已创建"); - - const geocoder = new AMap.Geocoder({ - city: "全国", - radius: 1000, // 搜索半径,单位米 - extensions: "all", // 返回详细信息,包括POI、建筑物等 - }); - geocoderRef.current = geocoder; - console.log("Geocoder 实例已创建并保存到 ref,现在可以立即使用"); - - // 创建 Geolocation 实例用于获取当前位置 - const geolocation = new AMap.Geolocation({ - enableHighAccuracy: true, // 是否使用高精度定位,默认:true - timeout: 10000, // 超过10秒后停止定位,默认:无穷大 - maximumAge: 0, // 定位结果缓存0毫秒,默认:0 - convert: true, // 自动偏移坐标,偏移后的坐标为高德坐标,默认:true - showButton: false, // 显示定位按钮,默认:true - buttonPosition: "RB", // 定位按钮停靠位置,默认:'LB',左下角 - showMarker: false, // 定位成功后在定位到的位置显示点标记,默认:true - showCircle: false, // 定位成功后用圆圈表示定位精度范围,默认:true - panToLocation: false, // 定位成功后将定位到的位置作为地图中心点,默认:true - zoomToAccuracy: false, // 定位成功后调整地图视野范围使定位位置及精度范围视野内可见,默认:false - }); - geolocationRef.current = geolocation; - - // 获取当前位置 - console.log("=== 开始获取当前位置 ==="); - geolocation.getCurrentPosition((status: string, result: any) => { - console.log("=== 定位回调触发 ==="); - console.log("定位状态:", status); - console.log("定位结果:", result); - - if (status === "complete") { - const { position, formattedAddress, addressComponent } = result; - const lat = position.lat; - const lng = position.lng; - const lnglat = new AMap.LngLat(lng, lat); - - console.log("定位成功,当前位置:", { lat, lng }); - console.log("定位地址:", formattedAddress); - - // 将地图中心设置为当前位置 - map.setCenter(lnglat); - map.setZoom(16); - - // 添加当前位置标记 - addMarker(lnglat); - - // 设置选中位置信息 - let addressLabel = formattedAddress || `纬度: ${lat}, 经度: ${lng}`; - let poiName = "当前位置"; - - // 尝试从地址组件中获取更详细的信息 - if (addressComponent) { - const parts = []; - if (addressComponent.province) - parts.push(addressComponent.province); - if (addressComponent.city) parts.push(addressComponent.city); - if (addressComponent.district) - parts.push(addressComponent.district); - if (addressComponent.street) parts.push(addressComponent.street); - if (addressComponent.streetNumber) - parts.push(addressComponent.streetNumber); - - if (parts.length > 0) { - addressLabel = parts.join(""); - } - - poiName = - addressComponent.street || - addressComponent.district || - "当前位置"; - } - - setSelectedLocation({ - lat: lat, - lng: lng, - label: addressLabel, - poiname: poiName, - }); - - message.success("已获取当前位置"); - } else { - console.warn("定位失败:", result); - message.warning( - "无法获取当前位置,请手动点击地图选择位置。原因: " + - (result.message || "定位服务不可用"), - ); - // 定位失败时,使用默认中心点 - console.log("使用默认中心点"); - } - }); - - // 如果有待处理的点击坐标,立即处理它 - if (pendingClickRef.current) { - console.log("=== 检测到待处理的点击坐标,立即处理 ==="); - const { lat, lng, lnglat } = pendingClickRef.current; - console.log("待处理坐标:", { lat, lng }); - setTimeout(() => { - const success = getAddressForLocation(lat, lng, lnglat); - if (success) { - console.log("✓ 待处理的坐标已成功获取地址"); - pendingClickRef.current = null; // 清除待处理坐标 - } else { - console.warn("待处理的坐标获取地址失败"); - } - }, 100); - } - }, - ); - - // 立即绑定点击事件,插件可能已加载或正在加载 - console.log("立即绑定点击事件(插件可能已初始化)"); - map.on("click", (e: any) => { - console.log("=== 地图点击事件触发 ==="); - console.log("点击事件对象:", e); - console.log("点击位置对象:", e.lnglat); - console.log( - "Geocoder ref 状态:", - geocoderRef.current ? "已初始化" : "未初始化", - ); - - if (!e || !e.lnglat) { - console.error("点击事件无效,缺少 lnglat"); - return; - } - - const lnglat = e.lnglat; - const lat = lnglat.getLat(); - const lng = lnglat.getLng(); - console.log(`点击坐标 - 纬度: ${lat}, 经度: ${lng}`); - - // 立即添加标记和居中 - addMarker(lnglat); - - // 设置基本 selectedLocation(至少有坐标) - setSelectedLocation({ - lat: lat, - lng: lng, - label: "正在获取地址信息...", - poiname: "点击位置", - }); - - // 如果 Geocoder 已初始化,立即使用它 - if (geocoderRef.current) { - console.log("Geocoder 已初始化,立即获取地址"); - getAddressForLocation(lat, lng, lnglat); - } else { - console.log("Geocoder 未初始化,保存坐标待插件加载完成后处理"); - // 保存待处理的坐标 - pendingClickRef.current = { lat, lng, lnglat }; - } - }); - - // 等待地图完全加载后关闭 loading - map.on("complete", () => { - console.log("地图加载完成"); - // 清除超时定时器 - clearTimeout(loadingTimeout); - // 关闭 loading - setMapLoading(false); - console.log("地图加载完成,loading 已关闭"); - - // 确保地图容器可点击 - const mapContainer = map.getContainer(); - if (mapContainer) { - mapContainer.style.pointerEvents = "auto"; - mapContainer.style.cursor = "crosshair"; - console.log("地图容器指针事件已启用"); - } - }); - - // 如果地图加载失败,也设置加载完成 - map.on("error", (error: any) => { - console.error("地图加载错误:", error); - clearTimeout(loadingTimeout); - setMapLoading(false); - message.error("地图加载失败"); - }); - }, [addMarker, getAddressForLocation]); - - const handleSearch = value => { - if (value) { - AMap.plugin("AMap.AutoComplete", () => { - const auto = new AMap.AutoComplete({ city: "全国" }); - auto.search(value, (status, result) => { - if (status === "complete") { - setOptions( - result.tips.map(tip => ({ - value: tip.name, - data: tip, - })), - ); - } - }); - }); - } else { - setOptions([]); - } - }; - - const onSelect = (value, option) => { - const { district, address, name, location } = option.data; - const lnglat = location; - setSelectedLocation({ - lat: lnglat.lat, - lng: lnglat.lng, - label: `${name} ${address || district}`, - poiname: name, - }); - addMarker(lnglat); - mapRef.current.setCenter(lnglat); - }; - - const handleModalChange = useCallback( - (visible: boolean) => { - if (visible) { - console.log("模态打开:开始加载地图脚本"); - setMapLoading(true); - setSelectedLocation(null); - const script = document.createElement("script"); - script.src = - "https://webapi.amap.com/maps?v=1.4.15&key=79370028f5763e46742125ed2e900c76&plugin=AMap.PlaceSearch,AMap.AutoComplete,AMap.Geocoder,AMap.Geolocation"; - script.async = true; - script.onload = () => { - console.log("脚本加载成功:开始初始化地图"); - setTimeout(() => initMap(), 100); // 添加延迟确保 DOM 就绪 - }; - script.onerror = () => { - console.error("脚本加载失败"); - message.error("地图加载失败,请检查网络或API密钥"); - setMapLoading(false); - }; - document.body.appendChild(script); - } else { - console.log("模态关闭:清理地图和脚本"); - // 清除所有标记点 - clearAllMarkers(); - // 重置 ref - geocoderRef.current = null; - placeSearchRef.current = null; - geolocationRef.current = null; - // Cleanup on close - const scripts = document.querySelectorAll( - 'script[src*="webapi.amap.com"]', - ); - scripts.forEach(s => { - if (document.body.contains(s)) { - document.body.removeChild(s); - } - }); - if (mapRef.current) { - mapRef.current.destroy(); - mapRef.current = null; - } - setMapLoading(false); - setOptions([]); // 重置搜索选项 - } - }, - [initMap, clearAllMarkers], - ); - - // 手动获取当前位置 - const handleGetCurrentLocation = useCallback(() => { - if (!geolocationRef.current) { - message.warning("定位服务未初始化,请稍候再试"); - return; - } - - console.log("=== 手动触发获取当前位置 ==="); - message.loading({ content: "正在获取当前位置...", key: "location" }); - - geolocationRef.current.getCurrentPosition((status: string, result: any) => { - message.destroy("location"); - console.log("=== 手动定位回调触发 ==="); - console.log("定位状态:", status); - console.log("定位结果:", result); - - if (status === "complete" && result && result.position) { - const { position, formattedAddress, addressComponent } = result; - const lat = position.lat; - const lng = position.lng; - const lnglat = new AMap.LngLat(lng, lat); - - console.log("定位成功,当前位置:", { lat, lng }); - - // 将地图中心设置为当前位置 - if (mapRef.current) { - mapRef.current.setCenter(lnglat); - mapRef.current.setZoom(16); - } - - // 添加当前位置标记 - addMarker(lnglat); - - // 设置选中位置信息 - let addressLabel = formattedAddress || `纬度: ${lat}, 经度: ${lng}`; - let poiName = "当前位置"; - - // 尝试从地址组件中获取更详细的信息 - if (addressComponent) { - const parts = []; - if (addressComponent.province) parts.push(addressComponent.province); - if (addressComponent.city) parts.push(addressComponent.city); - if (addressComponent.district) parts.push(addressComponent.district); - if (addressComponent.street) parts.push(addressComponent.street); - if (addressComponent.streetNumber) - parts.push(addressComponent.streetNumber); - - if (parts.length > 0) { - addressLabel = parts.join(""); - } - - poiName = - addressComponent.street || addressComponent.district || "当前位置"; - } - - setSelectedLocation({ - lat: lat, - lng: lng, - label: addressLabel, - poiname: poiName, - }); - - message.success("已获取当前位置"); - } else { - console.warn("定位失败:", result); - message.error( - "获取当前位置失败: " + (result?.message || "定位服务不可用"), - ); - } - }); - }, [addMarker]); - - const handleSendLocation = () => { - if (!selectedLocation || !selectedLocation.lat || !selectedLocation.lng) { - message.warning("请选择有效位置"); - return; - } - - const { lat, lng, label, poiname } = selectedLocation; - const content = ``; - - const messageId = +Date.now(); - const params = { - wechatAccountId: contract.wechatAccountId, - wechatChatroomId: contract?.chatroomId ? contract.id : 0, - wechatFriendId: contract?.chatroomId ? 0 : contract.id, - msgSubType: 0, - msgType: 48, - content: content, - seq: messageId, - }; - - // 构造本地消息 - const localMessage: ChatRecord = { - id: messageId, - wechatAccountId: contract.wechatAccountId, - wechatFriendId: contract?.chatroomId ? 0 : contract.id, - wechatChatroomId: contract?.chatroomId ? contract.id : 0, - tenantId: 0, - accountId: 0, - synergyAccountId: 0, - content: content, - msgType: 48, - msgSubType: 0, - msgSvrId: "", - isSend: true, - createTime: new Date().toISOString(), - isDeleted: false, - deleteTime: "", - sendStatus: 1, - wechatTime: Date.now(), - origin: 0, - msgId: 0, - recalled: false, - seq: messageId, - }; - addMessage(localMessage); - - sendCommand("CmdSendMessage", params); - - onClose(); - setSelectedLocation(null); - }; - + // 初始化地图 useEffect(() => { - if (visible) { - handleModalChange(true); - // 确保容器在模态框打开后可以接收事件 - setTimeout(() => { - const container = document.getElementById("amap-container"); - if (container) { - container.style.pointerEvents = "auto"; - container.style.cursor = "crosshair"; - console.log( - "容器样式已设置,pointerEvents:", - container.style.pointerEvents, - ); + if (visible && mapContainerRef.current && window.qq && window.qq.maps) { + // 创建地图实例 + const center = new window.qq.maps.LatLng(39.908823, 116.39747); // 默认北京 + const mapInstance = new window.qq.maps.Map(mapContainerRef.current, { + center: center, + zoom: 13, + }); + + setMap(mapInstance); + + // 创建地理编码服务 + geocoderRef.current = new window.qq.maps.Geocoder({ + complete: (result: any) => { + setIsReverseGeocoding(false); + if (result && result.detail) { + const detail = result.detail; + const location = detail.location || detail.latLng; + if (location) { + setSelectedLocation({ + x: location.lng?.toString() || location.getLng().toString(), + y: location.lat?.toString() || location.getLat().toString(), + scale: "16", + label: + detail.address || detail.formatted_addresses?.recommend || "", + poiname: + detail.addressComponents?.street || detail.address || "", + maptype: "0", + poiid: detail.poiid || "", + }); + } + } + }, + error: () => { + setIsReverseGeocoding(false); + message.error("获取地址信息失败"); + }, + }); + + // 创建搜索服务 + searchServiceRef.current = new window.qq.maps.SearchService({ + complete: (result: any) => { + setIsSearching(false); + if (result && result.detail) { + const pois = result.detail.pois || []; + if (pois.length > 0) { + const searchResults = pois.map((poi: any) => { + const location = poi.location || poi.latLng; + return { + id: + poi.id || + `${location.lat || location.getLat()},${ + location.lng || location.getLng() + }`, + title: poi.title || poi.name || "", + address: poi.address || poi.ad_info?.adcode || "", + location: { + lat: location.lat || location.getLat(), + lng: location.lng || location.getLng(), + }, + adcode: poi.adcode || poi.ad_info?.adcode || "", + city: poi.city || poi.ad_info?.city || "", + district: poi.district || poi.ad_info?.district || "", + }; + }); + setSearchResults(searchResults); + } else { + setSearchResults([]); + message.info("未找到相关地址"); + } + } else { + setSearchResults([]); + message.info("未找到相关地址"); + } + }, + error: () => { + setIsSearching(false); + message.error("搜索失败,请重试"); + }, + }); + + // 地图点击事件 + window.qq.maps.event.addListener(mapInstance, "click", (event: any) => { + const lat = event.latLng.lat; + const lng = event.latLng.lng; + + // 更新标记点 + if (markerRef.current) { + markerRef.current.setMap(null); } - }, 200); - } else { - handleModalChange(false); + + const newMarker = new window.qq.maps.Marker({ + position: new window.qq.maps.LatLng(lat, lng), + map: mapInstance, + }); + + markerRef.current = newMarker; + + // 反向地理编码 + setIsReverseGeocoding(true); + geocoderRef.current.getAddress(new window.qq.maps.LatLng(lat, lng)); + }); + + return () => { + if (mapInstance) { + window.qq.maps.event.clearListeners(mapInstance, "click"); + } + }; } - }, [visible, handleModalChange]); + }, [visible]); + + // 搜索地址 + const handleSearch = () => { + if (!searchValue.trim()) { + message.warning("请输入搜索关键词"); + return; + } + + if (!searchServiceRef.current) { + message.error("搜索服务未初始化"); + return; + } + + setIsSearching(true); + searchServiceRef.current.search(searchValue); + }; + + // 选择搜索结果 + const handleSelectResult = (result: SearchResult) => { + if (!map) return; + + const lat = result.location.lat; + const lng = result.location.lng; + + // 移动地图中心 + map.setCenter(new window.qq.maps.LatLng(lat, lng)); + map.setZoom(16); + + // 更新标记点 + if (markerRef.current) { + markerRef.current.setMap(null); + } + + const newMarker = new window.qq.maps.Marker({ + position: new window.qq.maps.LatLng(lat, lng), + map: map, + }); + + markerRef.current = newMarker; + + // 设置选中的位置信息 + setSelectedLocation({ + x: lng.toString(), + y: lat.toString(), + scale: "16", + label: result.address || result.title, + poiname: result.title || "", + maptype: "0", + poiid: result.id || "", + }); + + // 清空搜索结果 + setSearchResults([]); + setSearchValue(""); + }; + + // 确认选择 + const handleConfirm = () => { + if (!selectedLocation) { + message.warning("请先选择位置"); + return; + } + + // 生成XML格式的位置信息 + const locationXml = ``; + + // 如果有onConfirm回调,调用它 + if (onConfirm) { + onConfirm(locationXml); + } + + // 如果有addMessage和contract,发送位置消息 + if (addMessage && contract) { + const messageId = +Date.now(); + const localMessage = { + id: messageId, + wechatAccountId: contract.wechatAccountId, + wechatFriendId: contract?.chatroomId ? 0 : contract.id, + wechatChatroomId: contract?.chatroomId ? contract.id : 0, + tenantId: 0, + accountId: 0, + synergyAccountId: 0, + content: locationXml, + msgType: 48, // 位置消息类型 + msgSubType: 0, + msgSvrId: "", + isSend: true, + createTime: new Date().toISOString(), + isDeleted: false, + deleteTime: "", + sendStatus: 1, + wechatTime: Date.now(), + origin: 0, + msgId: 0, + recalled: false, + seq: messageId, + }; + + addMessage(localMessage); + + // 发送消息到服务器 + sendCommand("CmdSendMessage", { + wechatAccountId: contract.wechatAccountId, + wechatChatroomId: contract?.chatroomId ? contract.id : 0, + wechatFriendId: contract?.chatroomId ? 0 : contract.id, + msgSubType: 0, + msgType: 48, + content: locationXml, + seq: messageId, + }); + } + + // 关闭弹窗并重置状态 + handleClose(); + }; + + // 关闭弹窗 + const handleClose = () => { + setSearchValue(""); + setSearchResults([]); + setSelectedLocation(null); + if (markerRef.current) { + markerRef.current.setMap(null); + markerRef.current = null; + } + setIsSearching(false); + setIsReverseGeocoding(false); + onClose(); + }; return ( -
- - - + open={visible} + onCancel={handleClose} + width={900} + centered + footer={[ + , -
+ {isReverseGeocoding ? "正在获取地址信息..." : "确认"} + , + ]} + > +
+ {/* 搜索区域 */} +
+ setSearchValue(e.target.value)} + onPressEnter={handleSearch} + prefix={} + suffix={ + + } + className={styles.searchInput} + /> - {/* 显示点击位置的信息 */} - {selectedLocation && ( -
-
- 位置信息: -
-
- 地址: {selectedLocation.label || "加载中..."} -
-
- 坐标: {selectedLocation.lat},{" "} - {selectedLocation.lng} -
+ {/* 搜索结果列表 */} + {searchResults.length > 0 && ( +
+ ( + handleSelectResult(item)} + > + } + title={item.title} + description={item.address} + /> + + )} + /> +
+ )}
- )} -
- {mapLoading && ( -
- + {/* 地图区域 */} +
+
+ {isReverseGeocoding && ( +
+ +
+ )} +
+ + {/* 选中位置信息 */} + {selectedLocation && ( +
+
+ 已选择位置 +
+
+ {selectedLocation.label || selectedLocation.poiname} +
+
+ 经度: {selectedLocation.x}, 纬度: {selectedLocation.y} +
)} -
{ - // 添加原生点击事件监听作为备用 - console.log("容器原生点击事件触发", e); - }} - >
);