From d296d019e54190d2c74623236dd48bc3918858a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B6=85=E7=BA=A7=E8=80=81=E7=99=BD=E5=85=94?= Date: Fri, 21 Nov 2025 14:55:56 +0800 Subject: [PATCH] Enhance MessageEnter component by adding a map selection feature. Introduced a new button for map visibility and integrated SelectMap component for improved user interaction. --- .../InputMessage/InputMessage.tsx | 0 .../InputMessage/index.module.scss | 147 --- .../StepSendMessage/index.module.scss | 265 ------ .../components/StepSendMessage/index.tsx | 6 - Moncter/src/pages/pc/ckbox/weChat/api.ts | 0 .../components/ProfileModules/index.tsx | 0 .../MessageEnter/components/selectMap.tsx | 900 ++++++++++++++++++ .../components/MessageEnter/index.tsx | 31 +- 8 files changed, 928 insertions(+), 421 deletions(-) delete mode 100644 Moncter/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/InputMessage/InputMessage.tsx delete mode 100644 Moncter/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/InputMessage/index.module.scss delete mode 100644 Moncter/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/index.module.scss delete mode 100644 Moncter/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/index.tsx delete mode 100644 Moncter/src/pages/pc/ckbox/weChat/api.ts delete mode 100644 Moncter/src/pages/pc/ckbox/weChat/components/ChatWindow/components/ProfileCard/components/ProfileModules/index.tsx create mode 100644 Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/components/selectMap.tsx diff --git a/Moncter/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/InputMessage/InputMessage.tsx b/Moncter/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/InputMessage/InputMessage.tsx deleted file mode 100644 index e69de29b..00000000 diff --git a/Moncter/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/InputMessage/index.module.scss b/Moncter/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/InputMessage/index.module.scss deleted file mode 100644 index b8085ce9..00000000 --- a/Moncter/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/InputMessage/index.module.scss +++ /dev/null @@ -1,147 +0,0 @@ -.chatFooter { - background: #f7f7f7; - border-top: 1px solid #e1e1e1; - padding: 0; - height: auto; - border-radius: 8px; -} - -.inputContainer { - padding: 8px 12px; - display: flex; - flex-direction: column; - gap: 6px; -} - -.inputToolbar { - display: flex; - align-items: center; - padding: 4px 0; -} - -.leftTool { - display: flex; - gap: 4px; - align-items: center; -} - -.toolbarButton { - width: 28px; - height: 28px; - display: flex; - align-items: center; - justify-content: center; - border-radius: 4px; - color: #666; - font-size: 16px; - transition: all 0.15s; - border: none; - background: transparent; - - &:hover { - background: #e6e6e6; - color: #333; - } - - &:active { - background: #d9d9d9; - } -} - -.inputArea { - display: flex; - flex-direction: column; - padding: 4px 0; -} - -.inputWrapper { - border: 1px solid #d1d1d1; - border-radius: 4px; - background: #fff; - overflow: hidden; - - &:focus-within { - border-color: #07c160; - } -} - -.messageInput { - width: 100%; - border: none; - resize: none; - font-size: 13px; - line-height: 1.4; - padding: 8px 10px; - background: transparent; - - &:focus { - box-shadow: none; - outline: none; - } - - &::placeholder { - color: #b3b3b3; - } -} - -.sendButtonArea { - padding: 8px 10px; - display: flex; - justify-content: flex-end; - gap: 8px; -} - -.sendButton { - height: 32px; - border-radius: 4px; - font-weight: normal; - min-width: 60px; - font-size: 13px; - background: #07c160; - border-color: #07c160; - - &:hover { - background: #06ad56; - border-color: #06ad56; - } - - &:active { - background: #059748; - border-color: #059748; - } - - &:disabled { - background: #b3b3b3; - border-color: #b3b3b3; - opacity: 1; - } -} - -.hintButton { - border: none; - background: transparent; - color: #666; - font-size: 12px; - - &:hover { - color: #333; - } -} - -.inputHint { - font-size: 11px; - color: #999; - text-align: right; - margin-top: 2px; -} - -@media (max-width: 768px) { - .inputToolbar { - flex-wrap: wrap; - gap: 8px; - } - - .sendButtonArea { - justify-content: space-between; - } -} diff --git a/Moncter/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/index.module.scss b/Moncter/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/index.module.scss deleted file mode 100644 index fee50c0a..00000000 --- a/Moncter/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/index.module.scss +++ /dev/null @@ -1,265 +0,0 @@ -.stepContent { - .stepHeader { - margin-bottom: 20px; - - h3 { - font-size: 18px; - font-weight: 600; - color: #1a1a1a; - margin: 0 0 8px 0; - } - - p { - font-size: 14px; - color: #666; - margin: 0; - } - } -} - -.step3Content { - display: flex; - gap: 24px; - align-items: flex-start; - - .leftColumn { - flex: 1; - display: flex; - flex-direction: column; - gap: 20px; - } - - .rightColumn { - width: 400px; - flex: 1; - display: flex; - flex-direction: column; - gap: 20px; - } - - .messagePreview { - border: 2px dashed #52c41a; - border-radius: 8px; - padding: 20px; - background: #f6ffed; - - .previewTitle { - font-size: 14px; - color: #52c41a; - font-weight: 500; - margin-bottom: 12px; - } - - .messageBubble { - min-height: 60px; - padding: 12px; - background: #fff; - border-radius: 6px; - color: #666; - font-size: 14px; - line-height: 1.6; - - .currentEditingLabel { - font-size: 12px; - color: #999; - margin-bottom: 8px; - } - - .messageText { - color: #333; - white-space: pre-wrap; - word-break: break-word; - } - } - } - - .savedScriptGroups { - .scriptGroupTitle { - font-size: 14px; - font-weight: 500; - color: #333; - margin-bottom: 12px; - } - - .scriptGroupItem { - border: 1px solid #e8e8e8; - border-radius: 8px; - padding: 12px; - margin-bottom: 12px; - background: #fff; - - .scriptGroupHeader { - display: flex; - justify-content: space-between; - align-items: center; - - .scriptGroupLeft { - display: flex; - align-items: center; - gap: 8px; - flex: 1; - - :global(.ant-radio) { - margin-right: 4px; - } - - .scriptGroupName { - font-size: 14px; - font-weight: 500; - color: #333; - } - - .messageCount { - font-size: 12px; - color: #999; - margin-left: 8px; - } - } - - .scriptGroupActions { - display: flex; - gap: 4px; - - .actionButton { - padding: 4px; - color: #666; - - &:hover { - color: #1890ff; - } - } - } - } - - .scriptGroupContent { - margin-top: 8px; - padding-top: 8px; - border-top: 1px solid #f0f0f0; - font-size: 13px; - color: #666; - } - } - } - - .messageInputArea { - .messageInput { - margin-bottom: 12px; - } - - .attachmentButtons { - display: flex; - gap: 8px; - margin-bottom: 12px; - } - - .aiRewriteSection { - display: flex; - align-items: center; - margin-bottom: 8px; - } - - .messageHint { - font-size: 12px; - color: #999; - } - } - - .settingsPanel { - border: 1px solid #e8e8e8; - border-radius: 8px; - padding: 20px; - background: #fafafa; - - .settingsTitle { - font-size: 14px; - font-weight: 500; - color: #1a1a1a; - margin-bottom: 16px; - } - - .settingItem { - margin-bottom: 20px; - - &:last-child { - margin-bottom: 0; - } - - .settingLabel { - font-size: 14px; - font-weight: 500; - color: #1a1a1a; - margin-bottom: 12px; - } - - .settingControl { - display: flex; - align-items: center; - gap: 8px; - - span { - font-size: 14px; - color: #666; - min-width: 80px; - } - } - } - } - - .tagSection { - .settingLabel { - font-size: 14px; - font-weight: 500; - color: #1a1a1a; - margin-bottom: 12px; - } - } - - .pushPreview { - border: 1px solid #e8e8e8; - border-radius: 8px; - padding: 20px; - background: #f0f7ff; - - .previewTitle { - font-size: 14px; - font-weight: 500; - color: #1a1a1a; - margin-bottom: 12px; - } - - ul { - list-style: none; - padding: 0; - margin: 0; - - li { - font-size: 14px; - color: #666; - line-height: 1.8; - } - } - } -} - -@media (max-width: 1200px) { - .step3Content { - .rightColumn { - width: 350px; - } - } -} - -@media (max-width: 768px) { - .step3Content { - flex-direction: column; - - .leftColumn { - width: 100%; - } - - .rightColumn { - width: 100%; - } - } -} - diff --git a/Moncter/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/index.tsx b/Moncter/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/index.tsx deleted file mode 100644 index 082831d5..00000000 --- a/Moncter/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/index.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import ContentSelection from "@/components/ContentSelection"; -import { ContentItem } from "@/components/ContentSelection/data"; -import InputMessage from "./InputMessage/InputMessage"; -import styles from "./index.module.scss"; - -interface StepSendMessageProps { diff --git a/Moncter/src/pages/pc/ckbox/weChat/api.ts b/Moncter/src/pages/pc/ckbox/weChat/api.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/Moncter/src/pages/pc/ckbox/weChat/components/ChatWindow/components/ProfileCard/components/ProfileModules/index.tsx b/Moncter/src/pages/pc/ckbox/weChat/components/ChatWindow/components/ProfileCard/components/ProfileModules/index.tsx deleted file mode 100644 index e69de29b..00000000 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 new file mode 100644 index 00000000..7393c08c --- /dev/null +++ b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/components/selectMap.tsx @@ -0,0 +1,900 @@ +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 { useWebSocketStore } from "@/store/module/websocket/websocket"; + +declare const AMap: any; + +interface SelectMapProps { + visible: boolean; + onClose: () => void; + contract: ContractData | weChatGroup; + addMessage: (message: ChatRecord) => void; +} + +const SelectMap: React.FC = ({ + visible, + onClose, + contract, + addMessage, +}) => { + 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 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, + ); + } + }, 200); + } else { + handleModalChange(false); + } + }, [visible, handleModalChange]); + + return ( + +
+ + + + +
+ + {/* 显示点击位置的信息 */} + {selectedLocation && ( +
+
+ 位置信息: +
+
+ 地址: {selectedLocation.label || "加载中..."} +
+
+ 坐标: {selectedLocation.lat},{" "} + {selectedLocation.lng} +
+
+ )} + +
+ {mapLoading && ( +
+ +
+ )} +
{ + // 添加原生点击事件监听作为备用 + console.log("容器原生点击事件触发", e); + }} + >
+
+
+ ); +}; + +export default SelectMap; diff --git a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/index.tsx b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/index.tsx index 864ccb6e..9135624f 100644 --- a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/index.tsx +++ b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/index.tsx @@ -1,5 +1,15 @@ -import React, { useEffect, useState } from "react"; -import { Layout, Input, Button, Modal, message, Tooltip } from "antd"; +import React, { useEffect, useState, useRef } from "react"; +import { + Layout, + Input, + Button, + Modal, + message, + Tooltip, + AutoComplete, + Input as AntInput, + Spin, +} from "antd"; import { SendOutlined, FolderOutlined, @@ -8,6 +18,7 @@ import { CloseOutlined, MessageOutlined, ReloadOutlined, + EnvironmentOutlined, } from "@ant-design/icons"; import { ContractData, weChatGroup, ChatRecord } from "@/pages/pc/ckbox/data"; import { useWebSocketStore } from "@/store/module/websocket/websocket"; @@ -23,6 +34,7 @@ import { manualTriggerAi, } from "@/store/module/weChat/weChat"; import { useContactStore } from "@/store/module/weChat/contacts"; +import SelectMap from "./components/selectMap"; const { Footer } = Layout; const { TextArea } = Input; @@ -326,6 +338,8 @@ const MessageEnter: React.FC = ({ contract }) => { updateShowChatRecordModel(!showChatRecordModel); }; + const [mapVisible, setMapVisible] = useState(false); + return ( <> {/* 聊天输入 */} @@ -423,6 +437,12 @@ const MessageEnter: React.FC = ({ contract }) => { } className={styles.toolbarButton} /> +