no message

This commit is contained in:
kuaifan 2024-11-07 22:51:12 +08:00
parent a023c0b8bf
commit 4a9ed730c6
7 changed files with 633 additions and 7 deletions

View File

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="1" height="1" version="1.1" xmlns="http://www.w3.org/2000/svg">
</svg>

After

Width:  |  Height:  |  Size: 122 B

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title></title>
<!-- 百度地图API -->
<link rel="stylesheet" href="./style.css">
</head>
<body>
<div class="container">
<div class="search-box">
<div class="search-input-wrapper">
<svg class="search-icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path d="M950.784 899.584l-168.448-167.936c64.512-74.752 99.84-168.96 99.84-268.8 0-110.08-43.008-212.992-120.32-290.816S581.12 51.2 471.552 51.2c-110.08 0-212.992 43.008-290.816 120.32-77.824 77.824-120.832 181.248-120.832 291.328s43.008 212.992 120.32 290.816c77.824 77.824 181.248 120.32 290.816 120.32 90.624 0 177.152-29.184 248.32-82.944l169.984 169.984c8.192 8.192 19.456 12.8 30.72 12.8s22.016-4.096 30.72-12.8c16.896-16.896 16.896-44.544 0-61.44zM146.432 462.848C146.432 283.648 292.352 138.24 471.04 138.24c179.2 0 324.608 145.92 324.608 324.608 0 179.2-145.408 324.608-324.608 324.608s-324.608-145.92-324.608-324.608z" fill="#646A73"></path>
</svg>
<input type="text" id="search-input" placeholder="" enterkeyhint="search">
</div>
</div>
<div id="map-container"></div>
<div id="address-list" class="address-list">
<h3 id="address-label"></h3>
<ul id="poi-list"></ul>
</div>
<div class="loading">
<div class="loading-spinner"></div>
</div>
</div>
<script src="./main.js"></script>
</body>
</html>

409
public/tools/map/main.js vendored Normal file
View File

@ -0,0 +1,409 @@
class LocationPicker {
constructor() {
this.map = null;
this.marker = null;
this.geolocation = null;
this.localSearch = null;
this.currentPoint = null;
this.loadNum = 0;
this.config = {
theme: 'light', // 主题风格light|dark
key: null, // 百度地图 API Key
title: null, // 页面标题,如:选择打卡地点
label: null, // 搜索列表标签,如:附近的地点
placeholder: null, // 搜索框占位符,如:搜索附近的地点
point: null, // 初始坐标116.404,39.915
noresult: null, // 无搜索结果提示,如:附近没有找到地点
radius: 300, // 搜索半径单位300
zoom: 16, // 地图缩放级别
errtip: null, // 定位失败提示
errclose: false, // 定位失败是否关闭页面
channel: null, // 回传数据通道
selectclose: false, // 选择地点是否关闭页面
};
this.init();
}
async init() {
// 先初始化参数
this.initParams();
// 如果没有 key直接返回
if (!this.config.key) {
console.error('未提供百度地图 API Key');
return;
}
try {
// 等待地图 JS 加载完成
await this.loadBaiduMapScript();
// 初始化地图
this.initMap();
} catch (error) {
console.error('加载百度地图失败:', error);
}
}
initParams() {
// 获取当前URL的查询参数
const urlParams = new URLSearchParams(window.location.search);
// 遍历 config 对象的所有属性
Object.keys(this.config).forEach(key => {
// 从 URL 参数中获取值
const value = urlParams.get(key);
if (value !== null) {
// 根据参数类型进行转换
switch (key) {
case 'radius':
// 转换为数字
this.config[key] = parseInt(value) || 300;
break;
case 'point':
// 转换为坐标数组
const [lng, lat] = value.replace(/[|-]/, ',').split(',').map(parseFloat);
if (lng && lat) {
this.config[key] = {lng, lat};
}
break;
default:
// 字符串类型直接赋值
this.config[key] = value;
}
}
});
// 设置主题风格
document.documentElement.classList.add(`theme-${this.config.theme}`);
document.body.style.backgroundColor = "#ffffff";
// 设置标题
if (this.config.title) {
document.title = this.config.title;
}
// 设置搜索框占位符
if (this.config.placeholder) {
document.getElementById('search-input').placeholder = this.config.placeholder;
}
// 设置label
if (this.config.label) {
document.getElementById('address-label').innerText = this.config.label;
}
}
initMap() {
// 初始化地图
this.map = new BMap.Map('map-container');
// 创建定位控件
const locationControl = new BMap.GeolocationControl({
anchor: BMAP_ANCHOR_BOTTOM_RIGHT,
showAddressBar: false,
enableAutoLocation: false,
locationIcon: new BMap.Icon("empty.svg", new BMap.Size(0, 0))
});
// 监听定位事件
locationControl.addEventListener("locationSuccess", (e) => {
// 定位成功事件
this.updateCurrentPoint(e.point);
});
locationControl.addEventListener("locationError", (e) => {
// 定位失败事件
console.error('定位失败:', e.message);
this.locationError();
});
// 添加定位控件到地图
this.map.addControl(locationControl);
// 初始化本地搜索,移除地图渲染
this.localSearch = new BMap.LocalSearch(this.map, {
renderOptions: {
autoViewport: false // 关闭自动视野调整
}
});
// 设置地图中心点
if (this.config.point) {
const {lng, lat} = this.config.point;
this.config.point = new BMap.Point(lng, lat);
// 设置地图中心点和缩放级别
this.map.centerAndZoom(this.config.point, this.config.zoom);
// 创建圆形区域
const circle = new BMap.Circle(this.config.point, this.config.radius, {
fillColor: "#333333",
fillOpacity: 0.1,
strokeColor: "#333333",
strokeWeight: 1,
strokeOpacity: 0.3
});
this.map.addOverlay(circle);
}
// 绑定事件
this.bindEvents();
// 初始化时自动定位
this.getCurrentLocation();
}
bindEvents() {
const searchInput = document.getElementById('search-input');
// 监听回车键
searchInput.addEventListener('keyup', (e) => {
if (e.key === 'Enter') {
searchInput.blur();
}
});
// 监听失去焦点
searchInput.addEventListener('blur', () => {
this.searchAddress();
});
}
getCurrentLocation() {
this.loaderShow();
this.geolocation = new BMap.Geolocation();
this.geolocation.getCurrentPosition((result) => {
this.loaderHide();
if (result && result.point) {
this.updateCurrentPoint(result.point)
} else {
console.error('定位失败');
this.locationError();
}
}, {enableHighAccuracy: true});
}
updateCurrentPoint(point) {
this.currentPoint = point;
this.map.centerAndZoom(this.currentPoint, this.config.zoom);
this.updateMarker(this.currentPoint);
this.searchNearby();
}
updateMarker(point) {
if (this.marker) {
this.marker.setPosition(point);
} else {
this.marker = new BMap.Marker(point);
this.map.addOverlay(this.marker);
}
}
searchAddress() {
const keyword = document.getElementById('search-input').value;
this.searchNearby(keyword ? [keyword] : []);
}
searchNearby(keywords = [], retryCount = 0) {
// 当前位置未获取
if (this.currentPoint === null) {
return;
}
// 清除之前的搜索结果
this.localSearch.clearResults();
// 搜索附近的关键词
if (keywords.length === 0) {
keywords = ["写字楼", "公司", "银行", "餐馆", "商场", "超市", "学校", "医院", "公交站", "地铁站"]
}
// 定义一个随机数,用于判断定时器是否过期
this.searchRandom = Math.random();
// 设置搜索完成回调
this.loaderShow();
this.localSearch.setSearchCompleteCallback((results) => {
this.loaderHide();
if (this.localSearch.getStatus() !== BMAP_STATUS_SUCCESS) {
// 搜索失败
if (retryCount < 60) {
const tmpRand = this.searchRandom;
this.loaderShow();
setTimeout(() => {
this.loaderHide();
tmpRand === this.searchRandom && this.searchNearby(keywords, ++retryCount);
}, 1000)
return;
}
}
// 搜索结果
document.getElementById('address-list').style.display = 'block';
const array = [];
if (results instanceof Array) {
results.some(result => {
if (!result) {
return false;
}
for (let i = 0; i < result.getCurrentNumPois(); i++) {
const poi = result.getPoi(i);
poi._distance = this.config.point ? this.map.getDistance(this.config.point, poi.point) : null;
array.push(poi);
}
});
}
this.updatePoiList(array);
});
// 执行搜索
this.localSearch.searchNearby(keywords, this.currentPoint, this.config.radius);
}
updatePoiList(results) {
const poiList = document.getElementById('poi-list');
poiList.innerHTML = '';
// 如果没有搜索结果
if (results.length === 0 && this.config.noresult) {
poiList.innerHTML = '<li>' + this.config.noresult + '</li>';
return;
}
// 按距离排序(如果有距离信息)
results.sort((a, b) => {
if (a._distance && b._distance) {
return a._distance - b._distance;
}
return 0;
});
results = results.slice(0, 20);
// 创建列表项
results.forEach(poi => {
const li = document.createElement('li');
const distance = poi._distance ? `<div class="address-distance">${this.convertDistance(Math.round(poi._distance))}</div>` : '';
li.innerHTML = `
<div class="address-name">${poi.title}</div>
<div class="address-detail">${poi.address || ""}${distance}</div>
`;
li.addEventListener('click', () => {
const point = poi.point;
this.updateMarker(point);
this.map.setCenter(point);
//
if (typeof requireModuleJs === "function") {
const eeui = requireModuleJs("eeui");
eeui.setVariate("location::" + this.config.channel, JSON.stringify(poi))
}
if (this.config.selectclose) {
this.closePage();
}
});
poiList.appendChild(li);
});
// 列表更新后,重新将当前标记点居中显示
setTimeout(() => {
if (this.marker) {
this.map.setCenter(this.marker.getPosition());
}
}, 100); // 添加小延时确保DOM已更新
}
convertDistance(d) {
if (d > 1000) {
return (d / 1000).toFixed(1) + 'km';
}
return d.toFixed(0) + 'm';
}
locationError() {
if (this.config.errtip) {
alert(this.config.errtip);
}
if (this.config.errclose) {
this.closePage();
}
}
loaderShow() {
this.loadNum++;
this.loaderJudge();
}
loaderHide() {
setTimeout(() => {
this.loadNum--;
this.loaderJudge();
}, 100)
}
loaderJudge() {
if (this.loadNum > 0) {
document.querySelector('.loading').classList.add('show');
} else if (this.loadNum <= 0) {
document.querySelector('.loading').classList.remove('show');
}
}
closePage() {
try {
// 方法1: 如果是在 eeui 环境中
if (typeof requireModuleJs === "function") {
const eeui = requireModuleJs("eeui");
eeui.closePage();
}
// 方法2: 如果是从其他页面打开的,可以关闭当前窗口
window.close();
// 方法3: 如果是在 iOS WKWebView 中
try {
window.webkit.messageHandlers.closeWindow.postMessage(null);
} catch (e) {}
// 方法4: 如果是在 Android WebView 中
try {
window.android.closeWindow();
} catch (e) {}
// 方法5: 如果以上方法都失败,返回上一页
window.history.back();
} catch (e) {
console.error('关闭页面失败', e);
}
}
loadBaiduMapScript() {
return new Promise((resolve, reject) => {
// 如果已经加载过,直接返回
if (window.BMap) {
resolve();
return;
}
// 创建script标签
const script = document.createElement('script');
script.type = 'text/javascript';
script.src = `https://api.map.baidu.com/api?v=3.0&ak=${this.config.key}&callback=initBaiduMap`;
// 添加回调函数
window.initBaiduMap = () => {
resolve();
delete window.initBaiduMap;
};
// 处理加载错误
script.onerror = () => {
reject(new Error('百度地图脚本加载失败'));
};
// 添加到页面
document.body.appendChild(script);
});
}
}
// 初始化
document.addEventListener('DOMContentLoaded', () => {
new LocationPicker();
});

175
public/tools/map/style.css vendored Normal file
View File

@ -0,0 +1,175 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html.theme-dark {
-webkit-filter: invert(100%) hue-rotate(180deg) contrast(90%) !important;
filter: invert(100%) hue-rotate(180deg) contrast(90%) !important;
}
body {
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
font-size: 14px;
color: #303133;
}
.container {
display: flex;
flex-direction: column;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.search-box {
padding: 10px;
background: #fff;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
position: relative;
z-index: 100;
}
.search-input-wrapper {
position: relative;
display: flex;
align-items: center;
justify-content: center;
background-color: #EEF1F2;
border-radius: 6px;
height: 40px;
}
.search-icon {
margin: 0 10px 0 12px;
width: 20px;
height: 20px;
pointer-events: none;
}
#search-input {
flex: 1;
width: 0;
padding: 8px 8px 8px 0;
font-size: 15px;
border: 0;
background-color: transparent;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
outline: none;
-webkit-box-shadow: none;
box-shadow: none;
-webkit-tap-highlight-color: transparent;
-webkit-user-select: text;
}
#map-container {
flex: 1;
min-height: 240px;
}
.address-list {
display: none;
min-height: 300px;
overflow-y: auto;
background: #fff;
}
.address-list h3 {
font-size: 18px;
font-weight: bold;
padding: 12px 14px 10px;
position: sticky;
top: 0;
z-index: 1;
background-color: #ffffff;
}
#poi-list {
list-style: none;
}
#poi-list li {
padding: 10px 20px;
cursor: pointer;
position: relative;
}
#poi-list li::after {
content: "";
display: block;
height: 0;
clear: both;
}
#poi-list li::before {
content: "";
position: absolute;
left: 20px;
right: 0;
bottom: 0;
height: 1px;
background-color: #eee;
transform: scaleY(0.5);
}
#poi-list li:hover {
background: #f5f5f5;
}
.address-name {
font-size: 16px;
font-weight: 500;
margin-bottom: 5px;
line-height: 1.5;
}
.address-detail {
font-size: 13px;
color: #666;
line-height: 1.5;
}
.address-distance {
font-size: 13px;
color: #999;
float: right;
padding-left: 12px;
}
.loading {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 1000;
background: rgba(0, 0, 0, 0.6);
padding: 15px;
border-radius: 10px;
display: none;
}
.loading-spinner {
width: 30px;
height: 30px;
border: 2px solid transparent;
border-top-color: #fff;
border-left-color: #fff;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.loading.show {
display: block;
}

View File

@ -970,16 +970,14 @@ export default {
}, },
/** /**
* 获取定位App * 打开地图选位置App
* @param dispatch * @param dispatch
* @param objects * @param objects {{key: string, point: string}}
* @returns {Promise<unknown>} * @returns {Promise<unknown>}
*/ */
openAppMapPage({dispatch}, objects) { openAppMapPage({dispatch}, objects) {
return new Promise(resolve => { return new Promise(resolve => {
const params = { const params = {
// key: "xxxxxx",
// point: "116.404,39.925",
title: $A.L("签到地点"), title: $A.L("签到地点"),
label: $A.L("选择附近地点"), label: $A.L("选择附近地点"),
placeholder: $A.L("搜索地点"), placeholder: $A.L("搜索地点"),
@ -988,7 +986,7 @@ export default {
selectclose: "true", selectclose: "true",
channel: $A.randomString(6) channel: $A.randomString(6)
} }
const url = $A.urlAddParams($A.eeuiAppRewriteUrl('../public/tools/map/index.html'), Object.assign(params, objects)) const url = $A.urlAddParams($A.mainUrl("tools/map/index.html"), Object.assign(params, objects))
dispatch('openAppChildPage', { dispatch('openAppChildPage', {
pageType: 'app', pageType: 'app',
pageTitle: params.title, pageTitle: params.title,

View File

@ -7,6 +7,7 @@ class LocationPicker {
this.currentPoint = null; this.currentPoint = null;
this.loadNum = 0; this.loadNum = 0;
this.config = { this.config = {
theme: 'light', // 主题风格light|dark
key: null, // 百度地图 API Key key: null, // 百度地图 API Key
title: null, // 页面标题,如:选择打卡地点 title: null, // 页面标题,如:选择打卡地点
label: null, // 搜索列表标签,如:附近的地点 label: null, // 搜索列表标签,如:附近的地点
@ -20,8 +21,7 @@ class LocationPicker {
channel: null, // 回传数据通道 channel: null, // 回传数据通道
selectclose: false, // 选择地点是否关闭页面 selectclose: false, // 选择地点是否关闭页面
}; };
this.init().then(() => { this.init();
});
} }
async init() { async init() {
@ -73,6 +73,11 @@ class LocationPicker {
} }
}); });
// 设置主题风格
document.documentElement.classList.add(`theme-${this.config.theme}`);
document.body.style.backgroundColor = "#ffffff";
// 设置标题 // 设置标题
if (this.config.title) { if (this.config.title) {
document.title = this.config.title; document.title = this.config.title;

View File

@ -4,6 +4,11 @@
box-sizing: border-box; box-sizing: border-box;
} }
html.theme-dark {
-webkit-filter: invert(100%) hue-rotate(180deg) contrast(90%) !important;
filter: invert(100%) hue-rotate(180deg) contrast(90%) !important;
}
body { body {
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif; font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
font-size: 14px; font-size: 14px;