From 35e58f90bcd9daa6006b0cf88285bf2b71b67f88 Mon Sep 17 00:00:00 2001 From: kuaifan Date: Mon, 28 Jul 2025 08:46:54 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E7=AD=BE=E5=88=B0=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E9=AB=98=E5=BE=B7=E5=92=8C=E8=85=BE=E8=AE=AF=E5=9C=B0=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Http/Controllers/Api/DialogController.php | 6 +- public/tools/map/main.js | 850 +++++++++++++++++- public/tools/map/style.css | 4 +- resources/assets/js/store/actions.js | 32 - .../assets/statics/public/tools/map/main.js | 850 +++++++++++++++++- .../assets/statics/public/tools/map/style.css | 4 +- 6 files changed, 1702 insertions(+), 44 deletions(-) diff --git a/app/Http/Controllers/Api/DialogController.php b/app/Http/Controllers/Api/DialogController.php index 71771d5c2..4df5d7f31 100755 --- a/app/Http/Controllers/Api/DialogController.php +++ b/app/Http/Controllers/Api/DialogController.php @@ -1690,7 +1690,9 @@ class DialogController extends AbstractController * * @apiParam {Number} dialog_id 对话ID * @apiParam {String} type 位置类型 - * - bd: 百度地图 + * - baidu: 百度地图 + * - amap: 高德地图 + * - tencent: 腾讯地图 * @apiParam {Number} lng 经度 * @apiParam {Number} lat 纬度 * @apiParam {String} title 位置名称 @@ -1725,7 +1727,7 @@ class DialogController extends AbstractController // WebSocketDialog::checkDialog($dialog_id); // - if ($type == 'bd') { + if (in_array($type, ['baidu', 'amap', 'tencent'])) { $msgData = [ 'type' => $type, 'lng' => $lng, diff --git a/public/tools/map/main.js b/public/tools/map/main.js index 83accb62c..9b22de711 100644 --- a/public/tools/map/main.js +++ b/public/tools/map/main.js @@ -500,6 +500,27 @@ class BaiduMapPicker { }); } + /** + * 生成百度地图缩略图 + * @param point + * @returns {string} + */ + generateThumb(point) { + if (!point || !this.params.key) return null; + + const params = new URLSearchParams({ + ak: this.params.key, + center: `${point.lng},${point.lat}`, + markers: `${point.lng},${point.lat}`, + width: 800, + height: 480, + zoom: 17, + copyright: 1, + }); + + return `https://api.map.baidu.com/staticimage/v2?${params.toString()}`; + } + /** * 更新搜索结果列表 * @param pois @@ -547,8 +568,9 @@ class BaiduMapPicker { const point = poi.point; this.updateMarker(point); this.map.setCenter(point); - // - App.setVariate("location::" + this.params.channel, JSON.stringify(poi)); + App.setVariate("location::" + this.params.channel, JSON.stringify(Object.assign(poi, { + thumb: this.generateThumb(poi.point) + }))); if (this.params.selectclose) { App.closePage(); } @@ -632,8 +654,830 @@ class BaiduMapPicker { } } +// 高德地图选点类 +class AmapPicker { + constructor() { + this.map = null; + this.marker = null; + this.placeSearch = null; + this.currentPoint = null; + this.params = { + theme: 'light', + key: null, + title: null, + label: null, + placeholder: null, + point: null, + noresult: null, + radius: 300, + zoom: 16, + errtip: null, + channel: null, + selectclose: false, + }; + this.init(); + } + + async init() { + this.initParams(); + if (!this.params.key) { + console.error('未提供高德地图 API Key'); + return; + } + + try { + await this.loadMapScript(); + this.initMap(); + } catch (error) { + console.error('加载高德地图失败:', error); + } + } + + initParams() { + const urlParams = new URLSearchParams(window.location.search); + Object.keys(this.params).forEach(key => { + const value = urlParams.get(key); + if (value !== null) { + switch (key) { + case 'radius': + this.params[key] = parseInt(value) || 300; + break; + case 'point': + const [lng, lat] = value.replace(/[|-]/, ',').split(',').map(parseFloat); + if (lng && lat) { + this.params[key] = {lng, lat}; + } + break; + default: + this.params[key] = value; + } + } + }); + + if (!['dark', 'light'].includes(this.params.theme)) { + this.params.theme = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; + } + document.documentElement.classList.add(`theme-${this.params.theme}`); + document.body.style.backgroundColor = "#ffffff"; + + if (this.params.title) document.title = this.params.title; + if (this.params.placeholder) document.getElementById('search-input').placeholder = this.params.placeholder; + if (this.params.label) document.getElementById('address-label').innerText = this.params.label; + } + + initMap() { + this.map = new AMap.Map('map-container', { + zoom: this.params.zoom, + center: this.params.point ? [this.params.point.lng, this.params.point.lat] : [116.404, 39.915], + keyboardEnable: false + }); + + // 设置签到范围圆形 + if (this.params.point) { + const circle = new AMap.Circle({ + center: [this.params.point.lng, this.params.point.lat], + radius: this.params.radius, + strokeColor: '#333333', + strokeWeight: 1, + strokeOpacity: 0.3, + fillColor: '#333333', + fillOpacity: 0.1, + map: this.map + }); + } + + this.bindEvents(); + this.getCurrentLocation().catch(error => { + this.locationError(error); + }).finally(() => { + document.getElementById('map-location').style.display = 'block'; + }); + } + + bindEvents() { + const searchInput = document.getElementById('search-input'); + searchInput.addEventListener('keyup', (e) => { + if (e.key === 'Enter') searchInput.blur(); + }); + searchInput.addEventListener('blur', () => this.searchAddress()); + + document.getElementById('map-location').addEventListener('click', () => { + this.getCurrentLocation().catch(error => this.locationError(error)); + }); + } + + getCurrentLocation() { + return new Promise((resolve, reject) => { + Loader.show(); + App.getLocation().then(res => { + Loader.hide(); + if (!App.isJson(res) || res.status !== 'success') { + reject(res.error || "unknown error"); + return; + } + // WGS84坐标转换为GCJ02坐标系(高德地图使用的坐标系) + const gcj02_coord = CoordTransform.wgs84ToGcj02(res.longitude, res.latitude); + const point = [gcj02_coord[0], gcj02_coord[1]]; + this.updateCurrentPoint(point); + resolve(point); + }); + }); + } + + updateCurrentPoint(point) { + this.currentPoint = point; + this.map.setCenter(point); + this.map.setZoom(this.params.zoom); + this.updateMarker(point); + this.searchAddress(); + } + + updateMarker(point) { + if (this.marker) { + this.marker.setPosition(point); + } else { + this.marker = new AMap.Marker({ + position: point, + map: this.map + }); + } + } + + searchAddress() { + const keyword = document.getElementById('search-input').value.trim(); + if (keyword) { + this.searchKeyword(keyword); + } else { + this.searchLocation(); + } + } + + searchKeyword(keyword) { + if (!keyword || !this.currentPoint) return; + + Loader.show(); + // 使用Web服务API进行搜索,避免密钥平台不匹配问题 + const searchUrl = `https://restapi.amap.com/v3/place/around?key=${this.params.key}&location=${this.currentPoint[0]},${this.currentPoint[1]}&keywords=${encodeURIComponent(keyword)}&radius=${this.params.radius}&offset=20&page=1&extensions=all`; + + fetch(searchUrl) + .then(response => response.json()) + .then(data => { + Loader.hide(); + console.log('高德地图Web服务搜索结果:', data); + if (data.status === '1' && data.pois) { + // 转换数据格式以匹配原有的处理逻辑 + const pois = data.pois.map(poi => ({ + name: poi.name, + address: poi.address, + location: { + lng: parseFloat(poi.location.split(',')[0]), + lat: parseFloat(poi.location.split(',')[1]) + } + })); + this.updatePoiList(pois); + } else { + console.log('高德地图Web服务搜索失败:', data); + this.updatePoiList([]); + } + }) + .catch(error => { + Loader.hide(); + console.error('高德地图Web服务搜索错误:', error); + this.updatePoiList([]); + }); + } + + searchLocation() { + if (!this.currentPoint) return; + + Loader.show(); + // 使用Web服务API获取附近POI,避免密钥平台不匹配问题 + const geocodeUrl = `https://restapi.amap.com/v3/geocode/regeo?key=${this.params.key}&location=${this.currentPoint[0]},${this.currentPoint[1]}&radius=${this.params.radius}&extensions=all&batch=false&roadlevel=0`; + + fetch(geocodeUrl) + .then(response => response.json()) + .then(data => { + Loader.hide(); + console.log('高德地图Web服务逆地理编码结果:', data); + if (data.status === '1' && data.regeocode && data.regeocode.pois) { + // 转换数据格式以匹配原有的处理逻辑 + const pois = data.regeocode.pois.map(poi => ({ + name: poi.name, + address: poi.address, + location: { + lng: parseFloat(poi.location.split(',')[0]), + lat: parseFloat(poi.location.split(',')[1]) + } + })); + this.updatePoiList(pois); + } else { + console.log('高德地图Web服务逆地理编码失败:', data); + // 如果没有POI数据,尝试使用周边搜索 + this.searchNearbyPlaces(); + } + }) + .catch(error => { + Loader.hide(); + console.error('高德地图Web服务逆地理编码错误:', error); + // 网络错误时尝试周边搜索 + this.searchNearbyPlaces(); + }); + } + + // 周边地点搜索的备用方法 + searchNearbyPlaces() { + if (!this.currentPoint) return; + + Loader.show(); + // 搜索常见的POI类型 + const keywords = ['餐厅|商店|银行|医院|学校|酒店|超市|加油站']; + const searchUrl = `https://restapi.amap.com/v3/place/around?key=${this.params.key}&location=${this.currentPoint[0]},${this.currentPoint[1]}&keywords=${keywords}&radius=${this.params.radius}&offset=20&page=1&extensions=all`; + + fetch(searchUrl) + .then(response => response.json()) + .then(data => { + Loader.hide(); + console.log('高德地图周边搜索结果:', data); + if (data.status === '1' && data.pois) { + const pois = data.pois.map(poi => ({ + name: poi.name, + address: poi.address, + location: { + lng: parseFloat(poi.location.split(',')[0]), + lat: parseFloat(poi.location.split(',')[1]) + } + })); + this.updatePoiList(pois); + } else { + console.log('高德地图周边搜索也失败:', data); + this.updatePoiList([]); + } + }) + .catch(error => { + Loader.hide(); + console.error('高德地图周边搜索错误:', error); + this.updatePoiList([]); + }); + } + + /** + * 生成高德地图缩略图 + * @param point + * @returns {string} + */ + generateThumb(point) { + if (!point || !this.params.key) return null; + + const params = new URLSearchParams({ + key: this.params.key, + location: `${point.lng},${point.lat}`, + zoom: 17, + size: '800*480', + markers: `mid,,A:${point.lng},${point.lat}`, + }); + + return `https://restapi.amap.com/v3/staticmap?${params.toString()}`; + } + + updatePoiList(pois) { + const addressList = document.getElementById('address-list'); + addressList.style.display = 'flex'; + + const poiList = document.getElementById('poi-list'); + poiList.innerHTML = ''; + + console.log('高德地图POI列表:', pois); + + if (pois.length === 0) { + if (this.params.noresult) { + poiList.innerHTML = '
  • ' + this.params.noresult + '
  • '; + } + return; + } + + // 计算距离并过滤 + const filteredPois = pois.filter(poi => { + // 确保POI有位置信息 + if (!poi.location) { + console.log('POI缺少位置信息:', poi); + return false; + } + + // 计算到签到中心点的距离 + if (this.params.point) { + poi.distance = this.calculateDistance( + this.params.point.lat, this.params.point.lng, + poi.location.lat, poi.location.lng + ); + } else { + poi.distance = null; + } + + // 计算到当前位置的距离 + poi.distance_current = this.calculateDistance( + this.currentPoint[1], this.currentPoint[0], + poi.location.lat, poi.location.lng + ); + + return poi.distance_current < this.params.radius + 100; + }).sort((a, b) => a.distance_current - b.distance_current).slice(0, 20); + + console.log('过滤后的POI列表:', filteredPois); + + filteredPois.forEach(poi => { + const li = document.createElement('li'); + const distanceFormat = poi.distance ? `
    ${this.convertDistance(Math.round(poi.distance))}
    ` : ''; + li.innerHTML = ` +
    ${poi.name || poi.title}
    +
    ${poi.address || ""}${distanceFormat}
    + `; + li.addEventListener('click', () => { + const point = [poi.location.lng, poi.location.lat]; + this.updateMarker(point); + this.map.setCenter(point); + App.setVariate("location::" + this.params.channel, JSON.stringify({ + title: poi.name || poi.title, + address: poi.address || "", + point: {lng: poi.location.lng, lat: poi.location.lat}, + distance: poi.distance, + thumb: this.generateThumb(poi.location) + })); + if (this.params.selectclose) { + App.closePage(); + } + }); + poiList.appendChild(li); + }); + } + + // 简单的距离计算方法(当AMap.GeometryUtil不可用时使用) + calculateDistance(lat1, lng1, lat2, lng2) { + const R = 6371000; // 地球半径(米) + const dLat = (lat2 - lat1) * Math.PI / 180; + const dLng = (lng2 - lng1) * Math.PI / 180; + const a = Math.sin(dLat/2) * Math.sin(dLat/2) + + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * + Math.sin(dLng/2) * Math.sin(dLng/2); + const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); + return R * c; + } + + convertDistance(d) { + if (d > 1000) { + return (d / 1000).toFixed(1) + 'km'; + } + return d.toString() + 'm'; + } + + locationError(error) { + if (this.params.errtip) { + alert(this.params.errtip + ':' + error); + } else { + alert(error); + } + } + + loadMapScript() { + return new Promise((resolve, reject) => { + if (window.AMap) { + resolve(); + return; + } + + const script = document.createElement('script'); + script.type = 'text/javascript'; + // 只加载基础地图API,POI搜索使用Web服务API + script.src = `https://webapi.amap.com/maps?v=1.4.15&key=${this.params.key}&callback=initAmapMap`; + + window.initAmapMap = () => { + console.log('高德地图加载完成'); + resolve(); + delete window.initAmapMap; + }; + + script.onerror = () => { + reject(new Error('高德地图脚本加载失败')); + }; + + document.body.appendChild(script); + }); + } +} + +// 腾讯地图选点类 +class TencentMapPicker { + constructor() { + this.map = null; + this.marker = null; + this.currentPoint = null; + this.params = { + theme: 'light', + key: null, + title: null, + label: null, + placeholder: null, + point: null, + noresult: null, + radius: 300, + zoom: 16, + errtip: null, + channel: null, + selectclose: false, + }; + this.init(); + } + + async init() { + this.initParams(); + if (!this.params.key) { + console.error('未提供腾讯地图 API Key'); + return; + } + + try { + await this.loadMapScript(); + this.initMap(); + } catch (error) { + console.error('加载腾讯地图失败:', error); + } + } + + initParams() { + const urlParams = new URLSearchParams(window.location.search); + Object.keys(this.params).forEach(key => { + const value = urlParams.get(key); + if (value !== null) { + switch (key) { + case 'radius': + this.params[key] = parseInt(value) || 300; + break; + case 'point': + const [lng, lat] = value.replace(/[|-]/, ',').split(',').map(parseFloat); + if (lng && lat) { + this.params[key] = {lng, lat}; + } + break; + default: + this.params[key] = value; + } + } + }); + + if (!['dark', 'light'].includes(this.params.theme)) { + this.params.theme = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; + } + document.documentElement.classList.add(`theme-${this.params.theme}`); + document.body.style.backgroundColor = "#ffffff"; + + if (this.params.title) document.title = this.params.title; + if (this.params.placeholder) document.getElementById('search-input').placeholder = this.params.placeholder; + if (this.params.label) document.getElementById('address-label').innerText = this.params.label; + } + + initMap() { + const center = this.params.point ? + new TMap.LatLng(this.params.point.lat, this.params.point.lng) : + new TMap.LatLng(39.915, 116.404); + + this.map = new TMap.Map('map-container', { + center: center, + zoom: this.params.zoom, + disableKeyboard: true, + showControl: false, + showScale: false, + showZoom: false + }); + + // 设置签到范围圆形 + if (this.params.point) { + const circle = new TMap.MultiCircle({ + map: this.map, + geometries: [{ + id: 'circle1', + center: new TMap.LatLng(this.params.point.lat, this.params.point.lng), + radius: this.params.radius + }] + }); + } + + this.bindEvents(); + this.getCurrentLocation().catch(error => { + this.locationError(error); + }).finally(() => { + document.getElementById('map-location').style.display = 'block'; + }); + } + + bindEvents() { + const searchInput = document.getElementById('search-input'); + searchInput.addEventListener('keyup', (e) => { + if (e.key === 'Enter') searchInput.blur(); + }); + searchInput.addEventListener('blur', () => this.searchAddress()); + + document.getElementById('map-location').addEventListener('click', () => { + this.getCurrentLocation().catch(error => this.locationError(error)); + }); + } + + getCurrentLocation() { + return new Promise((resolve, reject) => { + Loader.show(); + App.getLocation().then(res => { + Loader.hide(); + if (!App.isJson(res) || res.status !== 'success') { + reject(res.error || "unknown error"); + return; + } + // WGS84坐标转换为GCJ02坐标系(腾讯地图使用的坐标系) + const gcj02_coord = CoordTransform.wgs84ToGcj02(res.longitude, res.latitude); + const point = new TMap.LatLng(gcj02_coord[1], gcj02_coord[0]); + this.updateCurrentPoint(point); + resolve(point); + }); + }); + } + + updateCurrentPoint(point) { + this.currentPoint = point; + this.map.setCenter(point); + this.map.setZoom(this.params.zoom); + this.updateMarker(point); + this.searchAddress(); + } + + updateMarker(point) { + if (this.marker) { + this.marker.updateGeometries([{ + id: 'marker1', + position: point + }]); + } else { + this.marker = new TMap.MultiMarker({ + map: this.map, + geometries: [{ + id: 'marker1', + position: point + }] + }); + } + } + + searchAddress() { + const keyword = document.getElementById('search-input').value.trim(); + if (keyword) { + this.searchKeyword(keyword); + } else { + this.searchLocation(); + } + } + + searchKeyword(keyword) { + if (!this.currentPoint || !keyword) { + this.updatePoiList([]); + return; + } + + Loader.show(); + // 使用JSONP方式调用腾讯地图Web服务API,避免跨域 + this.searchWithJsonp(`https://apis.map.qq.com/ws/place/v1/search?boundary=nearby(${this.currentPoint.lat},${this.currentPoint.lng},${this.params.radius})&keyword=${encodeURIComponent(keyword)}&page_size=20&page_index=1&orderby=_distance&key=${this.params.key}&output=jsonp&callback=tencentSearchCallback`); + } + + searchLocation() { + if (!this.currentPoint) return; + + Loader.show(); + // 使用JSONP方式调用腾讯地图逆地理编码API + this.searchWithJsonp(`https://apis.map.qq.com/ws/geocoder/v1/?location=${this.currentPoint.lat},${this.currentPoint.lng}&key=${this.params.key}&get_poi=1&poi_options=radius=${this.params.radius};page_size=20&output=jsonp&callback=tencentGeocodeCallback`); + } + + searchWithJsonp(url) { + // 生成唯一的回调函数名 + const callbackId = 'tencentCallback_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9); + const isSearchApi = url.includes('/place/v1/search'); + const actualCallback = isSearchApi ? 'tencentSearchCallback' : 'tencentGeocodeCallback'; + + // 替换URL中的回调函数名 + const actualUrl = url.replace(/callback=[^&]+/, `callback=${actualCallback}`); + + // 保存this引用 + const self = this; + + // 设置全局回调函数 + if (isSearchApi) { + window.tencentSearchCallback = (data) => { + Loader.hide(); + console.log('腾讯地图JSONP搜索结果:', data); + if (data.status === 0 && data.data) { + const pois = data.data.map(item => ({ + title: item.title, + address: item.address, + point: {lng: item.location.lng, lat: item.location.lat}, + distance: self.params.point ? self.calculateDistance( + self.params.point.lat, self.params.point.lng, + item.location.lat, item.location.lng + ) : null + })); + self.updatePoiList(pois); + } else { + console.log('腾讯地图JSONP搜索失败:', data); + self.updatePoiList([]); + } + // 清理全局回调函数 + setTimeout(() => { + delete window.tencentSearchCallback; + }, 100); + }; + } else { + window.tencentGeocodeCallback = (data) => { + Loader.hide(); + console.log('腾讯地图JSONP逆地理编码结果:', data); + if (data.status === 0 && data.result) { + const pois = []; + + // 只添加附近POI,不添加当前位置 + if (data.result.pois) { + data.result.pois.forEach(poi => { + pois.push({ + title: poi.title, + address: poi.address, + point: {lng: poi.location.lng, lat: poi.location.lat}, + distance: self.params.point ? self.calculateDistance( + self.params.point.lat, self.params.point.lng, + poi.location.lat, poi.location.lng + ) : null + }); + }); + } + + self.updatePoiList(pois); + } else { + console.log('腾讯地图JSONP逆地理编码失败:', data); + self.updatePoiList([]); + } + // 清理全局回调函数 + setTimeout(() => { + delete window.tencentGeocodeCallback; + }, 100); + }; + } + + // 创建script标签进行JSONP调用 + const script = document.createElement('script'); + script.src = actualUrl; + script.onerror = () => { + Loader.hide(); + console.error('腾讯地图JSONP调用失败'); + self.updatePoiList([]); + // 清理 + document.body.removeChild(script); + if (isSearchApi) { + delete window.tencentSearchCallback; + } else { + delete window.tencentGeocodeCallback; + } + }; + + script.onload = () => { + // 移除script标签 + setTimeout(() => { + if (document.body.contains(script)) { + document.body.removeChild(script); + } + }, 100); + }; + + document.body.appendChild(script); + } + + calculateDistance(lat1, lng1, lat2, lng2) { + const R = 6371000; // 地球半径(米) + const dLat = (lat2 - lat1) * Math.PI / 180; + const dLng = (lng2 - lng1) * Math.PI / 180; + const a = Math.sin(dLat/2) * Math.sin(dLat/2) + + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * + Math.sin(dLng/2) * Math.sin(dLng/2); + const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); + return R * c; + } + + /** + * 生成腾讯地图缩略图 + * @param point + * @returns {string} + */ + generateThumb(point) { + if (!point || !this.params.key) return null; + + const params = new URLSearchParams({ + key: this.params.key, + center: `${point.lat},${point.lng}`, + zoom: 18, + size: '800*480', + maptype: 'roadmap', + markers: `size:large|color:0xFF0000|label:A|${point.lat},${point.lng}`, + }); + + return `https://apis.map.qq.com/ws/staticmap/v2/?${params.toString()}`; + } + + updatePoiList(pois) { + const addressList = document.getElementById('address-list'); + addressList.style.display = 'flex'; + + const poiList = document.getElementById('poi-list'); + poiList.innerHTML = ''; + + if (pois.length === 0) { + if (this.params.noresult) { + poiList.innerHTML = '
  • ' + this.params.noresult + '
  • '; + } + return; + } + + pois.forEach(poi => { + const li = document.createElement('li'); + const distanceFormat = poi.distance ? `
    ${this.convertDistance(Math.round(poi.distance))}
    ` : ''; + li.innerHTML = ` +
    ${poi.title}
    +
    ${poi.address || ""}${distanceFormat}
    + `; + li.addEventListener('click', () => { + const point = new TMap.LatLng(poi.point.lat, poi.point.lng); + this.updateMarker(point); + this.map.setCenter(point); + App.setVariate("location::" + this.params.channel, JSON.stringify(Object.assign(poi, { + thumb: this.generateThumb(poi.point) + }))); + if (this.params.selectclose) { + App.closePage(); + } + }); + poiList.appendChild(li); + }); + } + + convertDistance(d) { + if (d > 1000) { + return (d / 1000).toFixed(1) + 'km'; + } + return d.toString() + 'm'; + } + + locationError(error) { + if (this.params.errtip) { + alert(this.params.errtip + ':' + error); + } else { + alert(error); + } + } + + loadMapScript() { + return new Promise((resolve, reject) => { + if (window.TMap) { + resolve(); + return; + } + + // 只加载GL版本用于地图显示,POI搜索使用JSONP调用Web服务API + const script = document.createElement('script'); + script.type = 'text/javascript'; + script.src = `https://map.qq.com/api/gljs?v=1.exp&key=${this.params.key}&callback=initTencentMap`; + + window.initTencentMap = () => { + resolve(); + delete window.initTencentMap; + }; + + script.onerror = () => { + reject(new Error('腾讯地图脚本加载失败')); + }; + + document.body.appendChild(script); + }); + } +} + +// 地图工厂类 +class MapFactory { + static createMap() { + const urlParams = new URLSearchParams(window.location.search); + const mapType = urlParams.get('type') || 'baidu'; + + switch (mapType) { + case 'amap': + return new AmapPicker(); + case 'tencent': + return new TencentMapPicker(); + case 'baidu': + default: + return new BaiduMapPicker(); + } + } +} + // 初始化 document.addEventListener('DOMContentLoaded', () => { new App(); - new BaiduMapPicker(); + MapFactory.createMap(); }); diff --git a/public/tools/map/style.css b/public/tools/map/style.css index 1887a3597..fcbc8db89 100644 --- a/public/tools/map/style.css +++ b/public/tools/map/style.css @@ -73,11 +73,11 @@ body { position: relative; display: flex; flex: 1; + min-height: 240px; } #map-container { flex: 1; - min-height: 240px; } #map-location { @@ -85,7 +85,7 @@ body { position: absolute; bottom: 16px; right: 16px; - z-index: 100; + z-index: 9999; background: #fff; border-radius: 4px; cursor: pointer; diff --git a/resources/assets/js/store/actions.js b/resources/assets/js/store/actions.js index 7374ff03b..fc2883e95 100644 --- a/resources/assets/js/store/actions.js +++ b/resources/assets/js/store/actions.js @@ -1296,38 +1296,6 @@ export default { $A.modalError(`你选择的位置「${data.title}」不在签到范围内`) return } - data.thumb = null; - if (objects.type === 'baidu') { - data.thumb = $A.urlAddParams('https://api.map.baidu.com/staticimage/v2', { - ak: objects.key, - center: `${data.point.lng},${data.point.lat}`, - markers: `${data.point.lng},${data.point.lat}`, - width: 800, - height: 480, - zoom: 19, - copyright: 1, - }) - } else if (objects.type === 'amap') { - data.thumb = $A.urlAddParams('https://restapi.amap.com/v3/staticmap', { - key: objects.key, - center: `${data.point.lng},${data.point.lat}`, - markers: `${data.point.lng},${data.point.lat}`, - width: 800, - height: 480, - zoom: 19, - copyright: 1, - }) - } else if (objects.type === 'tencent') { - data.thumb = $A.urlAddParams('https://apis.map.qq.com/ws/staticmap/v2', { - key: objects.key, - center: `${data.point.lng},${data.point.lat}`, - markers: `${data.point.lng},${data.point.lat}`, - width: 800, - height: 480, - zoom: 19, - copyright: 1, - }) - } resolve(data); } } diff --git a/resources/assets/statics/public/tools/map/main.js b/resources/assets/statics/public/tools/map/main.js index 83accb62c..9b22de711 100644 --- a/resources/assets/statics/public/tools/map/main.js +++ b/resources/assets/statics/public/tools/map/main.js @@ -500,6 +500,27 @@ class BaiduMapPicker { }); } + /** + * 生成百度地图缩略图 + * @param point + * @returns {string} + */ + generateThumb(point) { + if (!point || !this.params.key) return null; + + const params = new URLSearchParams({ + ak: this.params.key, + center: `${point.lng},${point.lat}`, + markers: `${point.lng},${point.lat}`, + width: 800, + height: 480, + zoom: 17, + copyright: 1, + }); + + return `https://api.map.baidu.com/staticimage/v2?${params.toString()}`; + } + /** * 更新搜索结果列表 * @param pois @@ -547,8 +568,9 @@ class BaiduMapPicker { const point = poi.point; this.updateMarker(point); this.map.setCenter(point); - // - App.setVariate("location::" + this.params.channel, JSON.stringify(poi)); + App.setVariate("location::" + this.params.channel, JSON.stringify(Object.assign(poi, { + thumb: this.generateThumb(poi.point) + }))); if (this.params.selectclose) { App.closePage(); } @@ -632,8 +654,830 @@ class BaiduMapPicker { } } +// 高德地图选点类 +class AmapPicker { + constructor() { + this.map = null; + this.marker = null; + this.placeSearch = null; + this.currentPoint = null; + this.params = { + theme: 'light', + key: null, + title: null, + label: null, + placeholder: null, + point: null, + noresult: null, + radius: 300, + zoom: 16, + errtip: null, + channel: null, + selectclose: false, + }; + this.init(); + } + + async init() { + this.initParams(); + if (!this.params.key) { + console.error('未提供高德地图 API Key'); + return; + } + + try { + await this.loadMapScript(); + this.initMap(); + } catch (error) { + console.error('加载高德地图失败:', error); + } + } + + initParams() { + const urlParams = new URLSearchParams(window.location.search); + Object.keys(this.params).forEach(key => { + const value = urlParams.get(key); + if (value !== null) { + switch (key) { + case 'radius': + this.params[key] = parseInt(value) || 300; + break; + case 'point': + const [lng, lat] = value.replace(/[|-]/, ',').split(',').map(parseFloat); + if (lng && lat) { + this.params[key] = {lng, lat}; + } + break; + default: + this.params[key] = value; + } + } + }); + + if (!['dark', 'light'].includes(this.params.theme)) { + this.params.theme = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; + } + document.documentElement.classList.add(`theme-${this.params.theme}`); + document.body.style.backgroundColor = "#ffffff"; + + if (this.params.title) document.title = this.params.title; + if (this.params.placeholder) document.getElementById('search-input').placeholder = this.params.placeholder; + if (this.params.label) document.getElementById('address-label').innerText = this.params.label; + } + + initMap() { + this.map = new AMap.Map('map-container', { + zoom: this.params.zoom, + center: this.params.point ? [this.params.point.lng, this.params.point.lat] : [116.404, 39.915], + keyboardEnable: false + }); + + // 设置签到范围圆形 + if (this.params.point) { + const circle = new AMap.Circle({ + center: [this.params.point.lng, this.params.point.lat], + radius: this.params.radius, + strokeColor: '#333333', + strokeWeight: 1, + strokeOpacity: 0.3, + fillColor: '#333333', + fillOpacity: 0.1, + map: this.map + }); + } + + this.bindEvents(); + this.getCurrentLocation().catch(error => { + this.locationError(error); + }).finally(() => { + document.getElementById('map-location').style.display = 'block'; + }); + } + + bindEvents() { + const searchInput = document.getElementById('search-input'); + searchInput.addEventListener('keyup', (e) => { + if (e.key === 'Enter') searchInput.blur(); + }); + searchInput.addEventListener('blur', () => this.searchAddress()); + + document.getElementById('map-location').addEventListener('click', () => { + this.getCurrentLocation().catch(error => this.locationError(error)); + }); + } + + getCurrentLocation() { + return new Promise((resolve, reject) => { + Loader.show(); + App.getLocation().then(res => { + Loader.hide(); + if (!App.isJson(res) || res.status !== 'success') { + reject(res.error || "unknown error"); + return; + } + // WGS84坐标转换为GCJ02坐标系(高德地图使用的坐标系) + const gcj02_coord = CoordTransform.wgs84ToGcj02(res.longitude, res.latitude); + const point = [gcj02_coord[0], gcj02_coord[1]]; + this.updateCurrentPoint(point); + resolve(point); + }); + }); + } + + updateCurrentPoint(point) { + this.currentPoint = point; + this.map.setCenter(point); + this.map.setZoom(this.params.zoom); + this.updateMarker(point); + this.searchAddress(); + } + + updateMarker(point) { + if (this.marker) { + this.marker.setPosition(point); + } else { + this.marker = new AMap.Marker({ + position: point, + map: this.map + }); + } + } + + searchAddress() { + const keyword = document.getElementById('search-input').value.trim(); + if (keyword) { + this.searchKeyword(keyword); + } else { + this.searchLocation(); + } + } + + searchKeyword(keyword) { + if (!keyword || !this.currentPoint) return; + + Loader.show(); + // 使用Web服务API进行搜索,避免密钥平台不匹配问题 + const searchUrl = `https://restapi.amap.com/v3/place/around?key=${this.params.key}&location=${this.currentPoint[0]},${this.currentPoint[1]}&keywords=${encodeURIComponent(keyword)}&radius=${this.params.radius}&offset=20&page=1&extensions=all`; + + fetch(searchUrl) + .then(response => response.json()) + .then(data => { + Loader.hide(); + console.log('高德地图Web服务搜索结果:', data); + if (data.status === '1' && data.pois) { + // 转换数据格式以匹配原有的处理逻辑 + const pois = data.pois.map(poi => ({ + name: poi.name, + address: poi.address, + location: { + lng: parseFloat(poi.location.split(',')[0]), + lat: parseFloat(poi.location.split(',')[1]) + } + })); + this.updatePoiList(pois); + } else { + console.log('高德地图Web服务搜索失败:', data); + this.updatePoiList([]); + } + }) + .catch(error => { + Loader.hide(); + console.error('高德地图Web服务搜索错误:', error); + this.updatePoiList([]); + }); + } + + searchLocation() { + if (!this.currentPoint) return; + + Loader.show(); + // 使用Web服务API获取附近POI,避免密钥平台不匹配问题 + const geocodeUrl = `https://restapi.amap.com/v3/geocode/regeo?key=${this.params.key}&location=${this.currentPoint[0]},${this.currentPoint[1]}&radius=${this.params.radius}&extensions=all&batch=false&roadlevel=0`; + + fetch(geocodeUrl) + .then(response => response.json()) + .then(data => { + Loader.hide(); + console.log('高德地图Web服务逆地理编码结果:', data); + if (data.status === '1' && data.regeocode && data.regeocode.pois) { + // 转换数据格式以匹配原有的处理逻辑 + const pois = data.regeocode.pois.map(poi => ({ + name: poi.name, + address: poi.address, + location: { + lng: parseFloat(poi.location.split(',')[0]), + lat: parseFloat(poi.location.split(',')[1]) + } + })); + this.updatePoiList(pois); + } else { + console.log('高德地图Web服务逆地理编码失败:', data); + // 如果没有POI数据,尝试使用周边搜索 + this.searchNearbyPlaces(); + } + }) + .catch(error => { + Loader.hide(); + console.error('高德地图Web服务逆地理编码错误:', error); + // 网络错误时尝试周边搜索 + this.searchNearbyPlaces(); + }); + } + + // 周边地点搜索的备用方法 + searchNearbyPlaces() { + if (!this.currentPoint) return; + + Loader.show(); + // 搜索常见的POI类型 + const keywords = ['餐厅|商店|银行|医院|学校|酒店|超市|加油站']; + const searchUrl = `https://restapi.amap.com/v3/place/around?key=${this.params.key}&location=${this.currentPoint[0]},${this.currentPoint[1]}&keywords=${keywords}&radius=${this.params.radius}&offset=20&page=1&extensions=all`; + + fetch(searchUrl) + .then(response => response.json()) + .then(data => { + Loader.hide(); + console.log('高德地图周边搜索结果:', data); + if (data.status === '1' && data.pois) { + const pois = data.pois.map(poi => ({ + name: poi.name, + address: poi.address, + location: { + lng: parseFloat(poi.location.split(',')[0]), + lat: parseFloat(poi.location.split(',')[1]) + } + })); + this.updatePoiList(pois); + } else { + console.log('高德地图周边搜索也失败:', data); + this.updatePoiList([]); + } + }) + .catch(error => { + Loader.hide(); + console.error('高德地图周边搜索错误:', error); + this.updatePoiList([]); + }); + } + + /** + * 生成高德地图缩略图 + * @param point + * @returns {string} + */ + generateThumb(point) { + if (!point || !this.params.key) return null; + + const params = new URLSearchParams({ + key: this.params.key, + location: `${point.lng},${point.lat}`, + zoom: 17, + size: '800*480', + markers: `mid,,A:${point.lng},${point.lat}`, + }); + + return `https://restapi.amap.com/v3/staticmap?${params.toString()}`; + } + + updatePoiList(pois) { + const addressList = document.getElementById('address-list'); + addressList.style.display = 'flex'; + + const poiList = document.getElementById('poi-list'); + poiList.innerHTML = ''; + + console.log('高德地图POI列表:', pois); + + if (pois.length === 0) { + if (this.params.noresult) { + poiList.innerHTML = '
  • ' + this.params.noresult + '
  • '; + } + return; + } + + // 计算距离并过滤 + const filteredPois = pois.filter(poi => { + // 确保POI有位置信息 + if (!poi.location) { + console.log('POI缺少位置信息:', poi); + return false; + } + + // 计算到签到中心点的距离 + if (this.params.point) { + poi.distance = this.calculateDistance( + this.params.point.lat, this.params.point.lng, + poi.location.lat, poi.location.lng + ); + } else { + poi.distance = null; + } + + // 计算到当前位置的距离 + poi.distance_current = this.calculateDistance( + this.currentPoint[1], this.currentPoint[0], + poi.location.lat, poi.location.lng + ); + + return poi.distance_current < this.params.radius + 100; + }).sort((a, b) => a.distance_current - b.distance_current).slice(0, 20); + + console.log('过滤后的POI列表:', filteredPois); + + filteredPois.forEach(poi => { + const li = document.createElement('li'); + const distanceFormat = poi.distance ? `
    ${this.convertDistance(Math.round(poi.distance))}
    ` : ''; + li.innerHTML = ` +
    ${poi.name || poi.title}
    +
    ${poi.address || ""}${distanceFormat}
    + `; + li.addEventListener('click', () => { + const point = [poi.location.lng, poi.location.lat]; + this.updateMarker(point); + this.map.setCenter(point); + App.setVariate("location::" + this.params.channel, JSON.stringify({ + title: poi.name || poi.title, + address: poi.address || "", + point: {lng: poi.location.lng, lat: poi.location.lat}, + distance: poi.distance, + thumb: this.generateThumb(poi.location) + })); + if (this.params.selectclose) { + App.closePage(); + } + }); + poiList.appendChild(li); + }); + } + + // 简单的距离计算方法(当AMap.GeometryUtil不可用时使用) + calculateDistance(lat1, lng1, lat2, lng2) { + const R = 6371000; // 地球半径(米) + const dLat = (lat2 - lat1) * Math.PI / 180; + const dLng = (lng2 - lng1) * Math.PI / 180; + const a = Math.sin(dLat/2) * Math.sin(dLat/2) + + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * + Math.sin(dLng/2) * Math.sin(dLng/2); + const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); + return R * c; + } + + convertDistance(d) { + if (d > 1000) { + return (d / 1000).toFixed(1) + 'km'; + } + return d.toString() + 'm'; + } + + locationError(error) { + if (this.params.errtip) { + alert(this.params.errtip + ':' + error); + } else { + alert(error); + } + } + + loadMapScript() { + return new Promise((resolve, reject) => { + if (window.AMap) { + resolve(); + return; + } + + const script = document.createElement('script'); + script.type = 'text/javascript'; + // 只加载基础地图API,POI搜索使用Web服务API + script.src = `https://webapi.amap.com/maps?v=1.4.15&key=${this.params.key}&callback=initAmapMap`; + + window.initAmapMap = () => { + console.log('高德地图加载完成'); + resolve(); + delete window.initAmapMap; + }; + + script.onerror = () => { + reject(new Error('高德地图脚本加载失败')); + }; + + document.body.appendChild(script); + }); + } +} + +// 腾讯地图选点类 +class TencentMapPicker { + constructor() { + this.map = null; + this.marker = null; + this.currentPoint = null; + this.params = { + theme: 'light', + key: null, + title: null, + label: null, + placeholder: null, + point: null, + noresult: null, + radius: 300, + zoom: 16, + errtip: null, + channel: null, + selectclose: false, + }; + this.init(); + } + + async init() { + this.initParams(); + if (!this.params.key) { + console.error('未提供腾讯地图 API Key'); + return; + } + + try { + await this.loadMapScript(); + this.initMap(); + } catch (error) { + console.error('加载腾讯地图失败:', error); + } + } + + initParams() { + const urlParams = new URLSearchParams(window.location.search); + Object.keys(this.params).forEach(key => { + const value = urlParams.get(key); + if (value !== null) { + switch (key) { + case 'radius': + this.params[key] = parseInt(value) || 300; + break; + case 'point': + const [lng, lat] = value.replace(/[|-]/, ',').split(',').map(parseFloat); + if (lng && lat) { + this.params[key] = {lng, lat}; + } + break; + default: + this.params[key] = value; + } + } + }); + + if (!['dark', 'light'].includes(this.params.theme)) { + this.params.theme = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; + } + document.documentElement.classList.add(`theme-${this.params.theme}`); + document.body.style.backgroundColor = "#ffffff"; + + if (this.params.title) document.title = this.params.title; + if (this.params.placeholder) document.getElementById('search-input').placeholder = this.params.placeholder; + if (this.params.label) document.getElementById('address-label').innerText = this.params.label; + } + + initMap() { + const center = this.params.point ? + new TMap.LatLng(this.params.point.lat, this.params.point.lng) : + new TMap.LatLng(39.915, 116.404); + + this.map = new TMap.Map('map-container', { + center: center, + zoom: this.params.zoom, + disableKeyboard: true, + showControl: false, + showScale: false, + showZoom: false + }); + + // 设置签到范围圆形 + if (this.params.point) { + const circle = new TMap.MultiCircle({ + map: this.map, + geometries: [{ + id: 'circle1', + center: new TMap.LatLng(this.params.point.lat, this.params.point.lng), + radius: this.params.radius + }] + }); + } + + this.bindEvents(); + this.getCurrentLocation().catch(error => { + this.locationError(error); + }).finally(() => { + document.getElementById('map-location').style.display = 'block'; + }); + } + + bindEvents() { + const searchInput = document.getElementById('search-input'); + searchInput.addEventListener('keyup', (e) => { + if (e.key === 'Enter') searchInput.blur(); + }); + searchInput.addEventListener('blur', () => this.searchAddress()); + + document.getElementById('map-location').addEventListener('click', () => { + this.getCurrentLocation().catch(error => this.locationError(error)); + }); + } + + getCurrentLocation() { + return new Promise((resolve, reject) => { + Loader.show(); + App.getLocation().then(res => { + Loader.hide(); + if (!App.isJson(res) || res.status !== 'success') { + reject(res.error || "unknown error"); + return; + } + // WGS84坐标转换为GCJ02坐标系(腾讯地图使用的坐标系) + const gcj02_coord = CoordTransform.wgs84ToGcj02(res.longitude, res.latitude); + const point = new TMap.LatLng(gcj02_coord[1], gcj02_coord[0]); + this.updateCurrentPoint(point); + resolve(point); + }); + }); + } + + updateCurrentPoint(point) { + this.currentPoint = point; + this.map.setCenter(point); + this.map.setZoom(this.params.zoom); + this.updateMarker(point); + this.searchAddress(); + } + + updateMarker(point) { + if (this.marker) { + this.marker.updateGeometries([{ + id: 'marker1', + position: point + }]); + } else { + this.marker = new TMap.MultiMarker({ + map: this.map, + geometries: [{ + id: 'marker1', + position: point + }] + }); + } + } + + searchAddress() { + const keyword = document.getElementById('search-input').value.trim(); + if (keyword) { + this.searchKeyword(keyword); + } else { + this.searchLocation(); + } + } + + searchKeyword(keyword) { + if (!this.currentPoint || !keyword) { + this.updatePoiList([]); + return; + } + + Loader.show(); + // 使用JSONP方式调用腾讯地图Web服务API,避免跨域 + this.searchWithJsonp(`https://apis.map.qq.com/ws/place/v1/search?boundary=nearby(${this.currentPoint.lat},${this.currentPoint.lng},${this.params.radius})&keyword=${encodeURIComponent(keyword)}&page_size=20&page_index=1&orderby=_distance&key=${this.params.key}&output=jsonp&callback=tencentSearchCallback`); + } + + searchLocation() { + if (!this.currentPoint) return; + + Loader.show(); + // 使用JSONP方式调用腾讯地图逆地理编码API + this.searchWithJsonp(`https://apis.map.qq.com/ws/geocoder/v1/?location=${this.currentPoint.lat},${this.currentPoint.lng}&key=${this.params.key}&get_poi=1&poi_options=radius=${this.params.radius};page_size=20&output=jsonp&callback=tencentGeocodeCallback`); + } + + searchWithJsonp(url) { + // 生成唯一的回调函数名 + const callbackId = 'tencentCallback_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9); + const isSearchApi = url.includes('/place/v1/search'); + const actualCallback = isSearchApi ? 'tencentSearchCallback' : 'tencentGeocodeCallback'; + + // 替换URL中的回调函数名 + const actualUrl = url.replace(/callback=[^&]+/, `callback=${actualCallback}`); + + // 保存this引用 + const self = this; + + // 设置全局回调函数 + if (isSearchApi) { + window.tencentSearchCallback = (data) => { + Loader.hide(); + console.log('腾讯地图JSONP搜索结果:', data); + if (data.status === 0 && data.data) { + const pois = data.data.map(item => ({ + title: item.title, + address: item.address, + point: {lng: item.location.lng, lat: item.location.lat}, + distance: self.params.point ? self.calculateDistance( + self.params.point.lat, self.params.point.lng, + item.location.lat, item.location.lng + ) : null + })); + self.updatePoiList(pois); + } else { + console.log('腾讯地图JSONP搜索失败:', data); + self.updatePoiList([]); + } + // 清理全局回调函数 + setTimeout(() => { + delete window.tencentSearchCallback; + }, 100); + }; + } else { + window.tencentGeocodeCallback = (data) => { + Loader.hide(); + console.log('腾讯地图JSONP逆地理编码结果:', data); + if (data.status === 0 && data.result) { + const pois = []; + + // 只添加附近POI,不添加当前位置 + if (data.result.pois) { + data.result.pois.forEach(poi => { + pois.push({ + title: poi.title, + address: poi.address, + point: {lng: poi.location.lng, lat: poi.location.lat}, + distance: self.params.point ? self.calculateDistance( + self.params.point.lat, self.params.point.lng, + poi.location.lat, poi.location.lng + ) : null + }); + }); + } + + self.updatePoiList(pois); + } else { + console.log('腾讯地图JSONP逆地理编码失败:', data); + self.updatePoiList([]); + } + // 清理全局回调函数 + setTimeout(() => { + delete window.tencentGeocodeCallback; + }, 100); + }; + } + + // 创建script标签进行JSONP调用 + const script = document.createElement('script'); + script.src = actualUrl; + script.onerror = () => { + Loader.hide(); + console.error('腾讯地图JSONP调用失败'); + self.updatePoiList([]); + // 清理 + document.body.removeChild(script); + if (isSearchApi) { + delete window.tencentSearchCallback; + } else { + delete window.tencentGeocodeCallback; + } + }; + + script.onload = () => { + // 移除script标签 + setTimeout(() => { + if (document.body.contains(script)) { + document.body.removeChild(script); + } + }, 100); + }; + + document.body.appendChild(script); + } + + calculateDistance(lat1, lng1, lat2, lng2) { + const R = 6371000; // 地球半径(米) + const dLat = (lat2 - lat1) * Math.PI / 180; + const dLng = (lng2 - lng1) * Math.PI / 180; + const a = Math.sin(dLat/2) * Math.sin(dLat/2) + + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * + Math.sin(dLng/2) * Math.sin(dLng/2); + const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); + return R * c; + } + + /** + * 生成腾讯地图缩略图 + * @param point + * @returns {string} + */ + generateThumb(point) { + if (!point || !this.params.key) return null; + + const params = new URLSearchParams({ + key: this.params.key, + center: `${point.lat},${point.lng}`, + zoom: 18, + size: '800*480', + maptype: 'roadmap', + markers: `size:large|color:0xFF0000|label:A|${point.lat},${point.lng}`, + }); + + return `https://apis.map.qq.com/ws/staticmap/v2/?${params.toString()}`; + } + + updatePoiList(pois) { + const addressList = document.getElementById('address-list'); + addressList.style.display = 'flex'; + + const poiList = document.getElementById('poi-list'); + poiList.innerHTML = ''; + + if (pois.length === 0) { + if (this.params.noresult) { + poiList.innerHTML = '
  • ' + this.params.noresult + '
  • '; + } + return; + } + + pois.forEach(poi => { + const li = document.createElement('li'); + const distanceFormat = poi.distance ? `
    ${this.convertDistance(Math.round(poi.distance))}
    ` : ''; + li.innerHTML = ` +
    ${poi.title}
    +
    ${poi.address || ""}${distanceFormat}
    + `; + li.addEventListener('click', () => { + const point = new TMap.LatLng(poi.point.lat, poi.point.lng); + this.updateMarker(point); + this.map.setCenter(point); + App.setVariate("location::" + this.params.channel, JSON.stringify(Object.assign(poi, { + thumb: this.generateThumb(poi.point) + }))); + if (this.params.selectclose) { + App.closePage(); + } + }); + poiList.appendChild(li); + }); + } + + convertDistance(d) { + if (d > 1000) { + return (d / 1000).toFixed(1) + 'km'; + } + return d.toString() + 'm'; + } + + locationError(error) { + if (this.params.errtip) { + alert(this.params.errtip + ':' + error); + } else { + alert(error); + } + } + + loadMapScript() { + return new Promise((resolve, reject) => { + if (window.TMap) { + resolve(); + return; + } + + // 只加载GL版本用于地图显示,POI搜索使用JSONP调用Web服务API + const script = document.createElement('script'); + script.type = 'text/javascript'; + script.src = `https://map.qq.com/api/gljs?v=1.exp&key=${this.params.key}&callback=initTencentMap`; + + window.initTencentMap = () => { + resolve(); + delete window.initTencentMap; + }; + + script.onerror = () => { + reject(new Error('腾讯地图脚本加载失败')); + }; + + document.body.appendChild(script); + }); + } +} + +// 地图工厂类 +class MapFactory { + static createMap() { + const urlParams = new URLSearchParams(window.location.search); + const mapType = urlParams.get('type') || 'baidu'; + + switch (mapType) { + case 'amap': + return new AmapPicker(); + case 'tencent': + return new TencentMapPicker(); + case 'baidu': + default: + return new BaiduMapPicker(); + } + } +} + // 初始化 document.addEventListener('DOMContentLoaded', () => { new App(); - new BaiduMapPicker(); + MapFactory.createMap(); }); diff --git a/resources/assets/statics/public/tools/map/style.css b/resources/assets/statics/public/tools/map/style.css index 1887a3597..fcbc8db89 100644 --- a/resources/assets/statics/public/tools/map/style.css +++ b/resources/assets/statics/public/tools/map/style.css @@ -73,11 +73,11 @@ body { position: relative; display: flex; flex: 1; + min-height: 240px; } #map-container { flex: 1; - min-height: 240px; } #map-location { @@ -85,7 +85,7 @@ body { position: absolute; bottom: 16px; right: 16px; - z-index: 100; + z-index: 9999; background: #fff; border-radius: 4px; cursor: pointer;