diff --git a/README.md b/README.md index ad13b21..ea9a5fe 100644 --- a/README.md +++ b/README.md @@ -229,6 +229,7 @@ vscode中liveSassCompiler的配置: { "liveSassCompile.settings.includeItems": [ "/public/static/common/css/theme/*.scss", + "/public/static/plugs/lay-module/mapLocation/mapLocation.scss", "/public/static/plugs/lay-module/tableData/tableData.scss", "/public/static/plugs/lay-module/tagInput/tagInput.scss", "/public/static/plugs/lay-module/propertyInput/propertyInput.scss" diff --git a/public/static/plugs/mapLocation/mapLocation.css b/public/static/plugs/mapLocation/mapLocation.css new file mode 100644 index 0000000..e4f7ffc --- /dev/null +++ b/public/static/plugs/mapLocation/mapLocation.css @@ -0,0 +1,158 @@ +.ul-map-location .option { + display: flex; + justify-content: space-between; + align-items: flex-start; + padding-top: 10px; +} +.ul-map-location .search-container { + position: relative; +} +.ul-map-location .search-container .search-main { + display: flex; +} +.ul-map-location .search-container .search-main .search-prefix { + display: flex; + align-items: center; + justify-content: flex-end; + white-space: nowrap; +} +.ul-map-location .search-container .search-main .search-prefix .search-prefix-item { + display: flex; + align-items: center; + justify-content: center; + margin-right: 6px; +} +.ul-map-location .search-container .search-main .search-prefix .search-prefix-item .close { + margin-left: 3px; +} +.ul-map-location .search-container .search-main .location-input { + width: 240px; +} +.ul-map-location .search-container .search-main .on-search { + width: 68px; +} +.ul-map-location .search-container .search-body { + width: 292px; + padding: 8px; + position: absolute; + top: 100%; + right: 0; + z-index: 899999; + background: #fff; +} +.ul-map-location .search-container .search-body .search-result { + max-height: 300px; + overflow-y: auto; + background-color: #fff; + border: 1px solid #e6e6e6; + border-radius: 2px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12); +} +.ul-map-location .search-container .search-body .search-result .result-item { + padding: 5px 8px; + cursor: pointer; + border-bottom: 1px solid #f0f0f0; +} +.ul-map-location .search-container .search-body .search-result .result-item:hover { + background-color: #f2f2f2; +} +.ul-map-location .search-container .search-body .search-result .result-item .name { + font-size: 14px; + font-weight: bold; + color: #333; + margin-bottom: 3px; +} +.ul-map-location .search-container .search-body .search-result .result-item .address { + font-size: 12px; + color: #666; + margin-bottom: 3px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.ul-map-location .search-container .search-body .search-result .result-item .info { + display: flex; + justify-content: space-between; + font-size: 12px; +} +.ul-map-location .search-container .search-body .search-result .result-item .info .type { + color: #009688; + background-color: #f2f2f2; + padding: 0px 5px; + border-radius: 2px; +} +.ul-map-location .search-container .search-body .search-result .result-item .info .location { + color: #999; +} +.ul-map-location .search-container .search-body .search-result .no-result { + padding: 15px; + text-align: center; + color: #999; +} +.ul-map-location .search-container .search-body .search-result-option { + display: flex; + align-items: center; + justify-content: space-between; +} +.ul-map-location .search-container .search-body .search-result-option .item { + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.ul-map-location .search-container .search-body .search-result-option .item.disabled { + opacity: 0.5; + cursor: not-allowed; +} +.ul-map-location .search-container .search-body .search-statistics { + margin-top: 10px; +} +.ul-map-location .search-container .search-body .search-statistics .title { + font-size: 14px; + color: #333; + margin-bottom: 10px; +} +.ul-map-location .search-container .search-body .search-statistics .list { + display: flex; + flex-wrap: wrap; +} +.ul-map-location .search-container .search-body .search-statistics .list .item { + background-color: #f2f2f2; + padding: 0px 3px; + margin: 0 3px 3px 0; + border-radius: 2px; + font-size: 12px; + color: #666; + cursor: pointer; +} +.ul-map-location .search-container .search-body .search-statistics .list .item:hover { + background-color: #e6e6e6; +} +.ul-map-location .search-container .search-body .option-body { + text-align: center; + color: #999; + cursor: pointer; + margin-top: 6px; +} +.ul-map-location .location-message { + margin-top: 10px; + padding: 8px; + background-color: #f8f8f8; + border-radius: 2px; + font-size: 12px; + display: flex; + justify-content: space-between; + align-items: center; +} +.ul-map-location .location-message .location-me { + margin-left: 10px; +} +.ul-map-location .error-message { + margin-top: 10px; + padding: 8px; + background-color: #fff2f0; + border: 1px solid #ffccc7; + border-radius: 2px; + color: #f5222d; + font-size: 12px; +} \ No newline at end of file diff --git a/public/static/plugs/mapLocation/mapLocation.js b/public/static/plugs/mapLocation/mapLocation.js index df2e841..e5f9fbb 100644 --- a/public/static/plugs/mapLocation/mapLocation.js +++ b/public/static/plugs/mapLocation/mapLocation.js @@ -1,6 +1,15 @@ (function () { + const css = '/static/plugs/lay-module/mapLocation/mapLocation.css'; var mapLocation = function () { - $(function () { }); + $(function () { + var cssElement = document.createElement('link'); + + cssElement.setAttribute('rel', 'stylesheet'); + + cssElement.setAttribute('href', css); + + document.body.appendChild(cssElement); + }); }; mapLocation.prototype.render = function (elem, data) { @@ -8,7 +17,7 @@ defaultLocationLongitude: 116.407466, defaultLocationLatitude: 39.904989, defaultZoom: 16, - height: '40vw', + height: 'calc(95vh - 120px)', width: '100%', name: ua.randdomString(), location: null, @@ -16,7 +25,11 @@ locationLongitude: null }; + var options = $.extend(defaultOption, data); + var originalLocation = $(options.location).val(); + var originalLocationLatitude = $(options.locationLatitude).val(); + var originalLocationLongitude = $(options.locationLongitude).val(); if (!options.key) { console.log('请提供天地图API Key'); @@ -27,16 +40,55 @@ var mapId = options.name; var mapContainer = $(`
-
-
打开地图
-
取消
+
+
+
打开地图
+
关闭
+
重置
+
+
+
+
+ + + +
+ +
+ +
`); + $(elem).css('clear', 'both'); mapContainer.appendTo(elem); + var mapContent = $('#' + mapId); mapContent.css('height', options.height); mapContent.css('width', options.width); @@ -77,11 +129,12 @@ }); // 多图层切换有问题,需要换成不含form element的方式 - // L.control - // .layers(baseLayers, overlayLayers) - // .addTo(map); + L.control + .layers(baseLayers, overlayLayers) + .setPosition('bottomleft') + .addTo(map); + - map.on('click', function (e) { if (oldMarker) { oldMarker.removeFrom(map); @@ -90,7 +143,7 @@ marker.addTo(map); oldMarker = marker; - $.get('http://api.tianditu.gov.cn/geocoder', { + $.get('//api.tianditu.gov.cn/geocoder', { postStr: JSON.stringify({ lon: e.latlng.lng, lat: e.latlng.lat, @@ -127,7 +180,7 @@ mapContent.show(); initMap(); $(this).hide(); - mapContainer.find('.cancel').show(); + mapContainer.find('.if-open').show(); map.on('locationfound', function (e) { mapContainer.find('.location-message').html('您当前的位置:' + e.latlng.lat.toFixed(6) + ',' + e.latlng.lng.toFixed(6) + '
我的定位
'); @@ -154,12 +207,15 @@ map.locate(); } + if(oldMarker){ + oldMarker.removeFrom(map); + } if (options.locationLatitude && options.locationLongitude && $(options.locationLatitude).val() && $(options.locationLongitude).val()) { var lat = $(options.locationLatitude).val(); var lng = $(options.locationLongitude).val(); - var oldMarker = L.marker([lat,lng]); + oldMarker = L.marker([lat, lng]); oldMarker.addTo(map); - map.flyTo([lat,lng], options.defaultZoom); + map.flyTo([lat, lng], options.defaultZoom); } }); mapContainer.on('click', '.location-me', function () { @@ -169,8 +225,8 @@ // 绑定取消事件 mapContainer.find('.cancel').on('click', function () { mapContent.hide(); - $(this).hide(); - mapContainer.find('.init').show(); + $('.if-open').hide(); + mapContainer.find('.if-close').show(); mapContainer.find('.location-message').hide(); mapContainer.find('.error-message').hide(); // 如果需要销毁地图实例,可以在这里添加相关代码 @@ -180,8 +236,233 @@ // } }); + mapContainer.find('.reset').on('click',function(){ + console.log(options.location); + + if (options.location) { + $(options.location).val(originalLocation) + } + if (options.locationLatitude) { + $(options.locationLatitude).val(originalLocationLatitude) + } + if (options.locationLongitude) { + $(options.locationLongitude).val(originalLocationLongitude) + } + + if(oldMarker){ + oldMarker.removeFrom(map); + } + if($(options.locationLatitude).val() && $(options.locationLongitude).val()){ + var lat = $(options.locationLatitude).val(); + var lng = $(options.locationLongitude).val(); + oldMarker = L.marker([lat, lng]); + oldMarker.addTo(map); + map.flyTo([lat, lng], options.defaultZoom); + } + }) + // 初始状态下隐藏取消按钮 - mapContainer.find('.cancel').hide(); + mapContainer.find('.if-open').hide(); + + var searchLoading = false; + var page = 1; + function search(isInit) { + if (isInit) { + page = 1; + } + var keywords = mapContainer.find('.location-input').val(); + + if (keywords.length == 0) { + mapContainer.find('.search-body').hide(); + return; + } + + var provinceName = mapContainer.find('.province-name .main').text(); + var cityName = mapContainer.find('.city-name .main').text(); + provinceCode = mapContainer.find('.province-name').data('code'); + cityCode = mapContainer.find('.city-name').data('code'); + + + if (searchLoading) { + return; + } + searchLoading = true; + + // 更新上一页按钮状态 - 第一页时禁用上一页按钮 + mapContainer.find('.search-result-option .item[data-option="prev"]').toggleClass('disabled', page <= 1); + + var searchParams = { + keyWord: keywords, + mapBound: '-180,-90,180,90', + level: 8, + queryType: '1', + start: (page - 1) * 10, + count: 10, + show: 2, + }; + + // 按照区域搜索 + if (provinceName) { + delete searchParams.mapBound + searchParams.queryType = 12 + searchParams.specify = provinceCode; + } + + if (cityName) { + delete searchParams.mapBound + searchParams.queryType = 12 + searchParams.specify = cityCode; + } + + // 按照拼接关键字搜索 + // if (cityName) { + // searchParams.keyWord = cityName + searchParams.keyWord; + // } + // if (provinceName) { + // searchParams.keyWord = provinceName + searchParams.keyWord; + // } + + + $.get('//api.tianditu.gov.cn/v2/search', { + postStr: JSON.stringify(searchParams), + type: 'query', + tk: options.key + }, function (resSearch) { + searchLoading = false; + page++; + // 清空搜索结果容器 + var $searchResult = mapContainer.find('.search-result'); + $searchResult.empty(); + + // 检查是否有搜索结果 + if (resSearch && resSearch.pois && resSearch.pois.length > 0) { + // 遍历搜索结果并添加到容器中 + $.each(resSearch.pois, function (index, poi) { + var lonlatArr = poi.lonlat.split(','); + var resultItem = $(` +
+
${poi.name}
+
${poi.address}
+
+ ${poi.typeName || ''} + ${poi.province} ${poi.city} ${poi.county} +
+
+ `); + $searchResult.append(resultItem); + }); + + // 显示搜索结果区域 + $searchResult.show(); + mapContainer.find('.search-statistics').hide(); + + // 更新下一页按钮状态 + mapContainer.find('.search-result-option .item[data-option="next"]').toggleClass('disabled', resSearch.pois.length < 10); + } else { + // 没有搜索结果时显示提示 + $searchResult.html('
没有找到相关地点
'); + $searchResult.show(); + + // 禁用下一页按钮 + mapContainer.find('.search-result-option .item[data-option="next"]').addClass('disabled'); + } + // 更新统计数据 + if (resSearch && resSearch.statistics && resSearch.statistics.allAdmins) { + var $statisticsList = mapContainer.find('.search-statistics .list'); + $statisticsList.empty(); + + $.each(resSearch.statistics.allAdmins, function (index, admin) { + var isleaf = admin.isleaf ? '1' : '0'; + $statisticsList.append(`
${admin.adminName} ${admin.count}个
`); + }); + + // 如果没有搜索结果但有推荐地区,显示统计区域 + if (!resSearch.pois || resSearch.pois.length === 0) { + mapContainer.find('.search-statistics').show(); + } + } + mapContainer.find('.search-body').show(); + }); + } + + mapContainer.find('.location-input').on('input', function (e) { + search(true); + }); + mapContainer.find('.on-search').on('click', function (e) { + search(true); + }); + mapContainer.find('.option-body').on('click', function (e) { + mapContainer.find('.search-body').hide(); + }); + + mapContainer.on('click', '.search-statistics .item', function () { + if ($(this).data('isleaf') == '1') { + mapContainer.find('.city-name .main').text($(this).data('name')); + + mapContainer.find('.city-name').data('code', $(this).data('code')); + mapContainer.find('.city-name').show(); + } else { + mapContainer.find('.province-name .main').text($(this).data('name')); + mapContainer.find('.province-name').data('code', $(this).data('code')); + mapContainer.find('.province-name').show(); + } + search(true); + }); + + mapContainer.on('click', '.search-prefix-item .close', function () { + $(this).prev().text(''); + $(this).closest('.search-prefix-item').hide(); + search(true); + }); + + // 绑定搜索结果点击事件 + mapContainer.on('click', '.result-item', function () { + var lng = $(this).data('lng'); + var lat = $(this).data('lat'); + var latlng = L.latLng(lat, lng); + + // 移动地图到选中位置 + map.flyTo(latlng, 16); + + // 添加标记 + if (oldMarker) { + oldMarker.removeFrom(map); + } + var marker = L.marker(latlng); + marker.addTo(map); + oldMarker = marker; + + // 更新表单值 + var address = $(this).find('.address').text(); + if (options.location) { + $(options.location).val(address); + } + if (options.locationLatitude) { + $(options.locationLatitude).val(lat); + } + if (options.locationLongitude) { + $(options.locationLongitude).val(lng); + } + }); + + // 绑定分页按钮点击事件 + mapContainer.on('click', '.search-result-option .item', function () { + var option = $(this).data('option'); + + if (option === 'prev') { + if (page > 2) { // 当前页码大于2才能上一页 + page -= 2; // 因为search函数会自增page,所以这里减2 + search(); + } + } else if (option === 'next') { + // 如果当前结果数量等于10,说明可能有下一页 + var resultCount = mapContainer.find('.search-result .result-item').length; + if (resultCount === 10) { + search(); + } + } + }); + return elem; }; diff --git a/public/static/plugs/mapLocation/mapLocation.scss b/public/static/plugs/mapLocation/mapLocation.scss new file mode 100644 index 0000000..9981f52 --- /dev/null +++ b/public/static/plugs/mapLocation/mapLocation.scss @@ -0,0 +1,187 @@ +.ul-map-location { + .option { + display: flex; + justify-content: space-between; + align-items: flex-start; + padding-top: 10px; + } + + .search-container { + position: relative; + + .search-main { + display: flex; + + .search-prefix { + display: flex; + align-items: center; + justify-content: flex-end; + white-space: nowrap; + + .search-prefix-item { + display: flex; + align-items: center; + justify-content: center; + margin-right: 6px; + + .close { + margin-left: 3px; + } + } + } + + .location-input { + width: 240px; + } + + .on-search { + width: 68px; + } + } + + .search-body { + width: calc(308px - 16px); + padding: 8px; + position: absolute; + top: 100%; + right: 0; + z-index: 899999; + background: #fff; + + .search-result { + max-height: 300px; + overflow-y: auto; + background-color: #fff; + border: 1px solid #e6e6e6; + border-radius: 2px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12); + + .result-item { + padding: 5px 8px; + cursor: pointer; + border-bottom: 1px solid #f0f0f0; + + &:hover { + background-color: #f2f2f2; + } + + .name { + font-size: 14px; + font-weight: bold; + color: #333; + margin-bottom: 3px; + } + + .address { + font-size: 12px; + color: #666; + margin-bottom: 3px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .info { + display: flex; + justify-content: space-between; + font-size: 12px; + + .type { + color: #009688; + background-color: #f2f2f2; + padding: 0px 5px; + border-radius: 2px; + } + + .location { + color: #999; + } + } + } + + .no-result { + padding: 15px; + text-align: center; + color: #999; + } + } + + .search-result-option { + display: flex; + align-items: center; + justify-content: space-between; + + .item { + cursor: pointer; + user-select: none; + + &.disabled { + opacity: 0.5; + cursor: not-allowed; + } + } + } + + .search-statistics { + margin-top: 10px; + + .title { + font-size: 14px; + color: #333; + margin-bottom: 10px; + } + + .list { + display: flex; + flex-wrap: wrap; + + .item { + background-color: #f2f2f2; + padding: 0px 3px; + margin: 0 3px 3px 0; + border-radius: 2px; + font-size: 12px; + color: #666; + cursor: pointer; + + &:hover { + background-color: #e6e6e6; + } + } + } + } + + .option-body { + text-align: center; + color: #999; + cursor: pointer; + margin-top: 6px; + } + } + } + + .location-message { + margin-top: 10px; + padding: 8px; + background-color: #f8f8f8; + border-radius: 2px; + font-size: 12px; + display: flex; + justify-content: space-between; + align-items: center; + + .location-me { + margin-left: 10px; + } + } + + .error-message { + margin-top: 10px; + padding: 8px; + background-color: #fff2f0; + border: 1px solid #ffccc7; + border-radius: 2px; + color: #f5222d; + font-size: 12px; + } +}