feat: 增加地图搜索;增加地图表单字段重置;

This commit is contained in:
augushong
2025-05-07 15:36:40 +08:00
parent d2e4acef05
commit 7f4e1369cc
4 changed files with 643 additions and 16 deletions

View File

@@ -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"

View File

@@ -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;
}

View File

@@ -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 = $(`
<div class="ul-map-location">
<div class="option layui-btn-container">
<div class="layui-btn layui-btn-sm init">打开地图</div>
<div class="layui-btn layui-btn-sm cancel">取消</div>
<div class="option ">
<div class="layui-btn-container">
<div class="layui-btn layui-btn-sm if-close init">打开地图</div>
<div class="layui-btn layui-btn-sm if-open cancel">关闭</div>
<div class="layui-btn layui-btn-sm if-open reset">重置</div>
</div>
<div class="if-open search-container">
<div class=" search-main">
<div class="search-prefix">
<div class="search-prefix-item province-name" style="display:none">
<div class="main"></div>
<div class="close">
<i class="layui-icon layui-icon-close"></i>
</div>
</div>
<div class="search-prefix-item city-name" style="display:none">
<div class="main"></div>
<div class="close">
<i class="layui-icon layui-icon-close"></i>
</div>
</div>
<input type="text" class="layui-input location-input" placeholder="请输入搜索关键词" />
</div>
<div class="layui-btn on-search">搜索</div>
</div>
<div class="search-body" style="display:none">
<div class="search-result" style="display:none"></div>
<div class="search-result-option">
<div class="item" data-option="prev">上一页</div>
<div class="item" data-option="next">下一页</div>
</div>
<div class="search-statistics" style="display:none">
<div class="title">推荐的搜索地</div>
<div class="list">
</div>
</div>
<div class="option-body">关闭</div>
</div>
</div>
</div>
<div id="${mapId}"></div>
<div class="location-message" style="display: none;"></div>
<div class="error-message" style="display: none;"></div>
</div>
`);
$(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) + ' <div class="layui-btn layui-btn-xs location-me">我的定位</div>');
@@ -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 = $(`
<div class="result-item" data-lng="${lonlatArr[0]}" data-lat="${lonlatArr[1]}" data-name="${poi.name}">
<div class="name">${poi.name}</div>
<div class="address">${poi.address}</div>
<div class="info">
<span class="type">${poi.typeName || ''}</span>
<span class="location">${poi.province} ${poi.city} ${poi.county}</span>
</div>
</div>
`);
$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('<div class="no-result">没有找到相关地点</div>');
$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(`<div class="item" data-isleaf="${isleaf}" data-name="${admin.adminName}" data-code="${admin.adminCode}">${admin.adminName} ${admin.count}个</div>`);
});
// 如果没有搜索结果但有推荐地区,显示统计区域
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;
};

View File

@@ -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;
}
}