diff --git a/Touchkebao/index.html b/Touchkebao/index.html index d0dcd4e9..f1c04fe6 100644 --- a/Touchkebao/index.html +++ b/Touchkebao/index.html @@ -13,7 +13,7 @@ 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 bc75ddc5..d09316ce 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 @@ -4,10 +4,11 @@ import { SearchOutlined, EnvironmentOutlined } from "@ant-design/icons"; import { useWebSocketStore } from "@/store/module/websocket/websocket"; import styles from "./selectMap.module.scss"; -// 声明腾讯地图类型 +// 声明腾讯地图类型(新版TMap API) declare global { interface Window { - qq: any; + TMap: any; + geolocationRef: any; // 全局IP定位服务引用 } } @@ -58,281 +59,454 @@ const SelectMap: React.FC = ({ const [map, setMap] = useState(null); const [isReverseGeocoding, setIsReverseGeocoding] = useState(false); const [isLocating, setIsLocating] = useState(false); + const [tmapLoaded, setTmapLoaded] = useState(false); const mapContainerRef = useRef(null); const geocoderRef = useRef(null); - const searchServiceRef = useRef(null); + const suggestServiceRef = useRef(null); const markerRef = useRef(null); const { sendCommand } = useWebSocketStore.getState(); + // 加载腾讯地图SDK + useEffect(() => { + // 检查TMap是否已经加载 + if (window.TMap) { + setTmapLoaded(true); + return; + } + + // 动态加载腾讯地图SDK(使用与index.html相同的密钥) + const script = document.createElement("script"); + script.src = + "https://map.qq.com/api/gljs?v=1.exp&libraries=service&key=7DZBZ-ZSRK3-QJN3W-O5VTV-4E2P6-7GFYX"; + script.async = true; + script.onload = () => { + console.log("腾讯地图SDK加载成功"); + setTmapLoaded(true); + }; + script.onerror = () => { + console.error("腾讯地图SDK加载失败"); + message.error("地图加载失败,请刷新页面重试"); + }; + document.head.appendChild(script); + + return () => { + // 清理script标签 + if (document.head.contains(script)) { + document.head.removeChild(script); + } + }; + }, []); + // 初始化地图 useEffect(() => { - 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, - }); + if (visible && mapContainerRef.current && tmapLoaded && window.TMap) { + console.log("开始初始化地图"); - setMap(mapInstance); - - // 创建地理编码服务 - geocoderRef.current = new window.qq.maps.Geocoder({ - complete: (result: any) => { - setIsReverseGeocoding(false); - try { - if (result && result.detail) { - const detail = result.detail; - const location = detail.location || detail.latLng; - if (location) { - const lat = - location.lat || (location.getLat ? location.getLat() : null); - const lng = - location.lng || (location.getLng ? location.getLng() : null); - - if (lat && lng) { - // 构建地址标签 - let addressLabel = ""; - if (detail.formatted_addresses) { - addressLabel = - detail.formatted_addresses.recommend || - detail.formatted_addresses.rough || - ""; - } - if (!addressLabel && detail.address) { - addressLabel = detail.address; - } - if (!addressLabel && detail.addressComponents) { - const addr = detail.addressComponents; - const parts = []; - if (addr.province) parts.push(addr.province); - if (addr.city) parts.push(addr.city); - if (addr.district) parts.push(addr.district); - if (addr.street) parts.push(addr.street); - if (addr.street_number) parts.push(addr.street_number); - addressLabel = parts.join(""); - } - if (!addressLabel) { - addressLabel = `${lat.toFixed(6)}, ${lng.toFixed(6)}`; - } - - setSelectedLocation({ - x: lng.toString(), - y: lat.toString(), - scale: "16", - label: addressLabel, - poiname: - detail.addressComponents?.street || detail.poiid || "", - maptype: "0", - poiid: detail.poiid || "", - }); - } else { - message.warning("无法解析位置信息"); - } - } else { - message.warning("未找到位置信息"); - } - } else { - message.warning("获取地址信息失败:返回数据为空"); - } - } catch (error) { - console.error("解析地址信息错误:", error); - message.error("解析地址信息失败"); - } - }, - error: (error: any) => { - setIsReverseGeocoding(false); - console.error("反向地理编码错误:", error); - 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); - } - - const newMarker = new window.qq.maps.Marker({ - position: new window.qq.maps.LatLng(lat, lng), - map: mapInstance, + try { + // 创建地图实例 + const center = new window.TMap.LatLng(39.908823, 116.39747); // 默认北京 + const mapInstance = new window.TMap.Map(mapContainerRef.current, { + center: center, + zoom: 13, + rotation: 0, + pitch: 0, }); - markerRef.current = newMarker; + setMap(mapInstance); - // 反向地理编码 - if (geocoderRef.current) { - setIsReverseGeocoding(true); - geocoderRef.current.getAddress(new window.qq.maps.LatLng(lat, lng)); - } - }); + // 创建地理编码服务(用于反向地理编码) + geocoderRef.current = new window.TMap.service.Geocoder(); - // 获取用户当前位置 - if (navigator.geolocation) { - setIsLocating(true); - navigator.geolocation.getCurrentPosition( - position => { - setIsLocating(false); - const userLat = position.coords.latitude; - const userLng = position.coords.longitude; + // 使用腾讯地图内置的定位服务 + window.geolocationRef = window.TMap.service.Geolocation; - // 移动地图中心到用户位置 - const userLocation = new window.qq.maps.LatLng(userLat, userLng); - mapInstance.setCenter(userLocation); - mapInstance.setZoom(16); + // 创建搜索建议服务 + suggestServiceRef.current = new window.TMap.service.Suggestion({ + pageSize: 10, + autoExtend: true, + }); - // 添加标记点 + // 地图点击事件处理函数 + const handleMapClick = (evt: any) => { + try { + const lat = evt.latLng.getLat(); + const lng = evt.latLng.getLng(); + + console.log("地图点击:", lat, lng); + + // 更新标记点 if (markerRef.current) { markerRef.current.setMap(null); + markerRef.current = null; } - const newMarker = new window.qq.maps.Marker({ - position: userLocation, + // 创建新标记 + const newMarker = new window.TMap.MultiMarker({ + id: "marker-layer", map: mapInstance, + geometries: [ + { + id: "selected-marker", + styleId: "marker", + position: new window.TMap.LatLng(lat, lng), + properties: { + title: "选中位置", + }, + }, + ], }); markerRef.current = newMarker; - // 获取用户位置的地址信息 - if (geocoderRef.current) { - setIsReverseGeocoding(true); - geocoderRef.current.getAddress(userLocation); - } - }, - error => { + // 设置基本位置信息(防止白屏) + setSelectedLocation({ + x: lng.toString(), + y: lat.toString(), + scale: "16", + label: `${lat.toFixed(6)}, ${lng.toFixed(6)}`, + poiname: "选中位置", + maptype: "0", + poiid: "", + }); + + // 反向地理编码获取地址 + setIsReverseGeocoding(true); + geocoderRef.current + .getAddress({ location: new window.TMap.LatLng(lat, lng) }) + .then((result: any) => { + setIsReverseGeocoding(false); + console.log("反向地理编码结果:", result); + + try { + if (result && result.result) { + const resultData = result.result; + const address = resultData.address || ""; + const addressComponent = resultData.address_component || {}; + const formattedAddresses = + resultData.formatted_addresses || {}; + + // 构建地址标签 + let addressLabel = + formattedAddresses.recommend || + formattedAddresses.rough || + address; + + if (!addressLabel) { + 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.street_number) + parts.push(addressComponent.street_number); + addressLabel = parts.join(""); + } + + if (!addressLabel) { + addressLabel = `${lat.toFixed(6)}, ${lng.toFixed(6)}`; + } + + setSelectedLocation({ + x: lng.toString(), + y: lat.toString(), + scale: "16", + label: addressLabel, + poiname: addressComponent.street || "未知位置", + maptype: "0", + poiid: resultData.poi_id || "", + }); + } else { + message.warning("获取详细地址信息失败,将使用坐标显示"); + } + } catch (error) { + console.error("解析地址信息错误:", error); + message.warning("解析地址信息失败,将使用坐标显示"); + } + }) + .catch((error: any) => { + setIsReverseGeocoding(false); + console.error("反向地理编码错误:", error); + message.warning("获取详细地址信息失败,将使用坐标显示"); + }); + } catch (error) { + console.error("地图点击处理错误:", error); + message.error("处理地图点击时出错,请重试"); + } + }; + + // 绑定地图点击事件 + mapInstance.on("click", handleMapClick); + + // 使用腾讯地图API初始化用户位置 + const initializeUserLocation = ( + lat: number, + lng: number, + isDefault: boolean = false, + ) => { + console.log(isDefault ? "使用默认位置:" : "用户位置:", lat, lng); + + // 移动地图中心到位置 + const userLocation = new window.TMap.LatLng(lat, lng); + mapInstance.setCenter(userLocation); + mapInstance.setZoom(16); + + // 添加标记点 + if (markerRef.current) { + markerRef.current.setMap(null); + markerRef.current = null; + } + + const newMarker = new window.TMap.MultiMarker({ + id: "marker-layer", + map: mapInstance, + geometries: [ + { + id: "user-location", + styleId: "marker", + position: userLocation, + properties: { + title: isDefault ? "默认位置" : "当前位置", + }, + }, + ], + }); + + markerRef.current = newMarker; + + // 使用腾讯地图服务获取该位置的地址信息 + setIsReverseGeocoding(true); + geocoderRef.current + .getAddress({ location: userLocation }) + .then((result: any) => { + setIsReverseGeocoding(false); + if (result && result.result) { + const resultData = result.result; + const formattedAddresses = resultData.formatted_addresses || {}; + const addressComponent = resultData.address_component || {}; + + const addressLabel = + formattedAddresses.recommend || + formattedAddresses.rough || + resultData.address || + `${lat.toFixed(6)}, ${lng.toFixed(6)}`; + + setSelectedLocation({ + x: lng.toString(), + y: lat.toString(), + scale: "16", + label: addressLabel, + poiname: + addressComponent.street || + (isDefault ? "默认位置" : "当前位置"), + maptype: "0", + poiid: resultData.poi_id || "", + }); + } + }) + .catch((error: any) => { + setIsReverseGeocoding(false); + console.error("获取地址信息失败:", error); + // 即使获取地址失败,也设置基本的位置信息 + setSelectedLocation({ + x: lng.toString(), + y: lat.toString(), + scale: "16", + label: `${lat.toFixed(6)}, ${lng.toFixed(6)}`, + poiname: isDefault ? "默认位置" : "当前位置", + maptype: "0", + poiid: "", + }); + }); + }; + + // 使用腾讯地图IP定位获取用户位置 + setIsLocating(true); + try { + if (window.geolocationRef) { + window.geolocationRef.getLocation({ + timeout: 10000, + convert: true, + success: function (result: any) { + setIsLocating(false); + if (result && result.location) { + const { lat, lng } = result.location; + message.info("已定位到您的大致位置"); + initializeUserLocation(lat, lng, false); + } else { + // IP定位失败:使用默认位置 + message.info("无法获取您的位置,已定位到北京"); + // 使用默认位置(北京市) + initializeUserLocation(39.908823, 116.39747, true); + } + }, + error: function () { + setIsLocating(false); + message.info("无法获取您的位置,已定位到北京"); + // 使用默认位置(北京市) + initializeUserLocation(39.908823, 116.39747, true); + }, + }); + } else { + // 地理编码服务未初始化:使用默认位置 setIsLocating(false); - console.error("获取位置失败:", error); - // 如果获取位置失败,使用默认位置(北京) - message.info("无法获取您的位置,已定位到默认位置"); - }, - { - enableHighAccuracy: true, - timeout: 10000, - maximumAge: 0, - }, - ); - } else { - message.info("您的浏览器不支持地理定位功能"); + message.info("无法获取您的位置,已定位到北京"); + // 使用默认位置(北京市) + initializeUserLocation(39.908823, 116.39747, true); + } + } catch (error) { + // 捕获任何可能的错误,防止白屏 + console.error("定位过程中发生错误:", error); + setIsLocating(false); + message.error("定位服务出现异常,已定位到北京"); + // 使用默认位置(北京市) + initializeUserLocation(39.908823, 116.39747, true); + } + + return () => { + // 清理地图事件监听 + if (mapInstance) { + mapInstance.off("click", handleMapClick); + } + }; + } catch (error) { + console.error("初始化地图时出错:", error); + message.error("地图加载失败,请刷新页面重试"); + setIsLocating(false); + } + } + }, [visible, tmapLoaded]); + + // 搜索地址(获取搜索建议) + const handleSearch = () => { + try { + if (!searchValue.trim()) { + message.warning("请输入搜索关键词"); + return; } - return () => { - if (mapInstance) { - window.qq.maps.event.clearListeners(mapInstance, "click"); - } - }; - } - }, [visible]); + if (!suggestServiceRef.current) { + message.error("搜索服务未初始化,请刷新页面重试"); + return; + } - // 搜索地址 - const handleSearch = () => { - if (!searchValue.trim()) { - message.warning("请输入搜索关键词"); - return; - } + setIsSearching(true); + suggestServiceRef.current + .getSuggestions({ + keyword: searchValue, + location: map ? map.getCenter() : undefined, + }) + .then((result: any) => { + setIsSearching(false); + console.log("搜索建议结果:", result); - if (!searchServiceRef.current) { - message.error("搜索服务未初始化"); - return; + if (result && result.data && result.data.length > 0) { + const searchResults = result.data.map((item: any) => ({ + id: item.id, + title: item.title || item.name || "", + address: item.address || "", + location: { + lat: item.location.lat, + lng: item.location.lng, + }, + adcode: item.adcode || "", + city: item.city || "", + district: item.district || "", + })); + setSearchResults(searchResults); + } else { + setSearchResults([]); + message.info("未找到相关地址"); + } + }) + .catch((error: any) => { + setIsSearching(false); + console.error("搜索失败:", error); + message.error("搜索失败,请重试"); + // 确保搜索状态被重置 + setSearchResults([]); + }); + } catch (error) { + setIsSearching(false); + console.error("搜索处理错误:", error); + message.error("搜索过程中出错,请重试"); + setSearchResults([]); } - - setIsSearching(true); - searchServiceRef.current.search(searchValue); }; // 选择搜索结果 const handleSelectResult = (result: SearchResult) => { - if (!map) return; + try { + if (!map) { + message.error("地图未初始化,请刷新页面重试"); + return; + } - const lat = result.location.lat; - const lng = result.location.lng; + const lat = result.location.lat; + const lng = result.location.lng; - // 移动地图中心 - map.setCenter(new window.qq.maps.LatLng(lat, lng)); - map.setZoom(16); + console.log("选择搜索结果:", result); - // 更新标记点 - if (markerRef.current) { - markerRef.current.setMap(null); + // 移动地图中心 + map.setCenter(new window.TMap.LatLng(lat, lng)); + map.setZoom(16); + + // 更新标记点 + if (markerRef.current) { + markerRef.current.setMap(null); + markerRef.current = null; + } + + const newMarker = new window.TMap.MultiMarker({ + id: "marker-layer", + map: map, + geometries: [ + { + id: "selected-poi", + styleId: "marker", + position: new window.TMap.LatLng(lat, lng), + properties: { + title: result.title, + }, + }, + ], + }); + + 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(""); + } catch (error) { + console.error("选择搜索结果错误:", error); + message.error("选择位置时出错,请重试"); } - - 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; - } + try { + if (!selectedLocation) { + message.warning("请先选择位置"); + return; + } - // 生成XML格式的位置信息 - const locationXml = ` = ({ maptype="${selectedLocation.maptype}" poiid="${selectedLocation.poiid}" />`; - // 如果有onConfirm回调,调用它 - if (onConfirm) { - onConfirm(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(); + } catch (error) { + console.error("确认位置时出错:", error); + message.error("发送位置信息时出错,请重试"); } - - // 如果有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(); }; // 关闭弹窗 diff --git a/Touchkebao/腾讯地图定位服务修复说明.md b/Touchkebao/腾讯地图定位服务修复说明.md new file mode 100644 index 00000000..601db72f --- /dev/null +++ b/Touchkebao/腾讯地图定位服务修复说明.md @@ -0,0 +1,73 @@ +# 腾讯地图定位服务修复说明 + +## 问题描述 + +在 `selectMap.tsx` 文件中使用腾讯地图定位服务时出现以下错误: + +``` +TypeError: window.TMap.service.Location is not a constructor + at selectMap.tsx:121:33 +``` + +## 原因分析 + +错误原因是尝试将 `TMap.service.Location` 作为构造函数使用,但在腾讯地图 GL API 中,定位服务不是通过构造函数方式创建的。 + +## 修复方法 + +### 1. 修改定位服务的初始化方式 + +将原来的代码: + +```typescript +// 创建IP定位服务 +window.geolocationRef = new window.TMap.service.Location({ + timeout: 10000, + convert: true, +}); +``` + +修改为: + +```typescript +// 使用腾讯地图内置的定位服务 +window.geolocationRef = window.TMap.service.Geolocation; +``` + +### 2. 修改定位服务的调用方式 + +在调用定位服务时,将配置参数直接传入 `getLocation` 方法: + +```typescript +window.geolocationRef.getLocation({ + timeout: 10000, + convert: true, + success: function (result: any) { + // 处理成功回调 + }, + error: function () { + // 处理错误回调 + }, +}); +``` + +## 技术说明 + +1. **腾讯地图 GL API 中的定位服务**: + - 正确的服务名称是 `TMap.service.Geolocation`,而非 `TMap.service.Location` + - 它是一个对象,不需要使用 `new` 关键字实例化 + - 配置参数应该直接传递给 `getLocation` 方法 + +2. **定位服务参数**: + - `timeout`:定位超时时间,单位毫秒 + - `convert`:是否将坐标转换为腾讯地图坐标系 + +3. **回调处理**: + - `success`:定位成功回调函数,返回位置信息 + - `error`:定位失败回调函数 + +## 注意事项 + +1. 确保腾讯地图 SDK 已正确加载 +2. 确保 API 密钥有定位服务的权限 +3. 定位精度可能受网络环境影响