perf: 添加定位签到

This commit is contained in:
kuaifan 2024-11-10 00:35:04 +08:00
parent 016bc41180
commit 74405f1a2a
10 changed files with 211 additions and 137 deletions

View File

@ -207,6 +207,9 @@ class UserBot extends AbstractModel
if (!in_array('locat', $setting['modes'])) {
return '暂未开放定位签到。';
}
if (empty($extra)) {
return '当前客户端版本低所需版本≥v0.39.75)。';
}
if ($extra['type'] === 'bd') {
// todo 判断距离
} else {

View File

@ -723,7 +723,6 @@ webhook地址最长仅支持255个字符。
请填写百度地图AK
请选择允许签到位置
请选择有效的签到位置
暂未开启签到功能。
暂未开放定位签到。
错误的定位签到。
获取地图快照失败

View File

@ -1764,13 +1764,6 @@ WiFi签到延迟时长为±1分钟。
以后再说
立即更新
签到地点
选择附近地点
搜索地点
附近没有找到地点
定位失败
签到地点
选择附近地点
搜索地点
附近没有找到地点
@ -1791,3 +1784,6 @@ WiFi签到延迟时长为±1分钟。
请先填写百度地图AK
你当前是负责人,确定要转为协助人员吗?
仅支持移动端App
暂未开放定位签到。
错误的定位签到。

View File

@ -25955,18 +25955,6 @@
"id": "Kata Bijak: (%T1)",
"ru": "Душеподъемная цитата: (%T1)"
},
{
"key": "签到地点",
"zh": "",
"zh-CHT": "簽到地點",
"en": "Check-in Location",
"ko": "출석 장소",
"ja": "チェックイン場所",
"de": "Eingetragener Ort",
"fr": "Lieu d'enregistrement",
"id": "Lokasi Check-in",
"ru": "Место регистрации"
},
{
"key": "选择附近地点",
"zh": "",
@ -26279,4 +26267,4 @@
"id": "Anda saat ini adalah orang yang bertanggung jawab. Apakah Anda yakin ingin beralih menjadi asisten?",
"ru": "Вы в данный момент являетесь ответственным лицом. Уверены, что хотите перейти в помощники?"
}
]
]

View File

@ -290,7 +290,9 @@ class BaiduMapPicker {
*/
initMap() {
// 初始化地图
this.map = new BMap.Map('map-container');
this.map = new BMap.Map('map-container', {
enableMapClick: false
});
// 初始化本地搜索,移除地图渲染
this.localSearch = new BMap.LocalSearch(this.map, {
@ -320,9 +322,7 @@ class BaiduMapPicker {
this.bindEvents();
// 初始化时自动定位
Loader.show();
this.getCurrentLocation().then((point) => {
Loader.hide();
if (point === null) {
this.locationError();
}
@ -348,10 +348,7 @@ class BaiduMapPicker {
// 地图定位点击事件
const mapLocation = document.getElementById('map-location');
mapLocation.addEventListener('click', () => {
Loader.show()
this.getCurrentLocation().then(() => {
Loader.hide()
});
this.getCurrentLocation();
});
}
@ -361,7 +358,9 @@ class BaiduMapPicker {
*/
getCurrentLocation() {
return new Promise(resolve => {
Loader.show()
App.getLocation().then(res => {
Loader.hide()
if (App.isJson(res) && res.longitude && res.latitude) {
const bd09_coord = CoordTransform.wgs84toBd09(res.longitude, res.latitude);
const point = new BMap.Point(bd09_coord[0], bd09_coord[1]);
@ -381,9 +380,13 @@ class BaiduMapPicker {
*/
updateCurrentPoint(point) {
this.currentPoint = point;
this.map.centerAndZoom(this.currentPoint, this.params.zoom);
if (Math.abs(this.map.getZoom() - this.params.zoom) > 1) {
this.map.centerAndZoom(this.currentPoint, this.params.zoom);
} else {
this.map.setCenter(this.currentPoint);
}
this.updateMarker(this.currentPoint);
this.searchNearby();
this.searchAddress();
}
/**
@ -403,95 +406,134 @@ class BaiduMapPicker {
* 搜索地址
*/
searchAddress() {
const keyword = document.getElementById('search-input').value;
this.searchNearby(keyword ? [keyword] : []);
const keyword = `${document.getElementById('search-input').value}`.trim();
if (keyword) {
this.searchKeyword(this.currentPoint, keyword);
} else {
this.searchLocation(this.currentPoint);
}
}
/**
* 搜索附近的地点
* @param keywords
* 通过关键词搜索附近的地点
* @param centerPoint
* @param keyword
* @param retryCount
*/
searchNearby(keywords = [], retryCount = 0) {
// 当前位置未获取
if (this.currentPoint === null) {
return;
}
searchKeyword(centerPoint, keyword, retryCount = 0) {
// 清除之前的搜索结果
this.localSearch.clearResults();
// 搜索附近的关键词
if (keywords.length === 0) {
keywords = ["写字楼", "公司", "银行", "餐馆", "商场", "超市", "学校", "医院", "公交站", "地铁站"]
}
// 定义一个随机数,用于判断定时器是否过期
this.searchRandom = Math.random();
// 设置搜索完成回调
Loader.show();
this.localSearch.setSearchCompleteCallback((results) => {
this.localSearch.setSearchCompleteCallback(result => {
Loader.hide();
if (this.localSearch.getStatus() !== BMAP_STATUS_SUCCESS) {
// 搜索失败
if (retryCount < 60) {
// 搜索失败10次重试
if (retryCount < 10) {
const tmpRand = this.searchRandom;
Loader.show();
setTimeout(() => {
Loader.hide();
tmpRand === this.searchRandom && this.searchNearby(keywords, ++retryCount);
}, 1000)
tmpRand === this.searchRandom && this.searchKeyword(centerPoint, keyword, ++retryCount);
}, 300)
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.params.point ? this.map.getDistance(this.params.point, poi.point) : null;
array.push(poi);
}
});
const pois = [];
for (let i = 0; i < result.getCurrentNumPois(); i++) {
const poi = result.getPoi(i);
if (!poi.point) {
continue;
}
poi.distance = this.params.point ? this.map.getDistance(this.params.point, poi.point) : null;
poi.distance_current = this.map.getDistance(centerPoint, poi.point);
pois.push(poi);
}
this.updatePoiList(array);
this.updatePoiList(pois);
});
// 执行搜索
this.localSearch.searchNearby(keywords, this.currentPoint, this.params.radius);
this.localSearch.searchNearby(keyword, centerPoint, this.params.radius);
}
/**
* 通过坐标搜索附近的地点
* @param point
*/
searchLocation(point) {
const geoc = new BMap.Geocoder();
Loader.show();
geoc.getLocation(point, (result) => {
Loader.hide();
const pois = [];
if (result) {
// 搜索结果
const surroundingPois = result.surroundingPois || [];
if (surroundingPois.length === 0) {
surroundingPois.push({
title: result.addressComponents.city + result.addressComponents.district,
address: result.address,
point: result.point,
});
}
surroundingPois.some(poi => {
if (!poi.point) {
return false;
}
poi.distance = this.params.point ? this.map.getDistance(this.params.point, poi.point) : null;
poi.distance_current = this.map.getDistance(point, poi.point);
pois.push(poi);
})
}
this.updatePoiList(pois)
}, {
poiRadius: this.params.radius,
numPois: 20,
});
}
/**
* 更新搜索结果列表
* @param results
* @param pois
*/
updatePoiList(results) {
updatePoiList(pois) {
const addressList = document.getElementById('address-list');
addressList.style.display = 'block';
const poiList = document.getElementById('poi-list');
poiList.innerHTML = '';
// 如果没有搜索结果
if (results.length === 0 && this.params.noresult) {
poiList.innerHTML = '<li>' + this.params.noresult + '</li>';
if (pois.length === 0) {
if (this.params.noresult) {
poiList.innerHTML = '<li><div class="address-noresult">' + this.params.noresult + '</div></li>';
}
return;
}
// 筛选距离小于搜索半径的结果(+100
pois = pois.filter(poi => {
return poi.title && poi.point && poi.distance_current < this.params.radius + 100;
});
// 按距离排序(如果有距离信息)
results.sort((a, b) => {
if (a.distance && b.distance) {
return a.distance - b.distance;
pois.sort((a, b) => {
if (a.distance_current && b.distance_current) {
return a.distance_current - b.distance_current;
}
return 0;
});
results = results.slice(0, 20);
// 只显示前20个结果
pois = pois.slice(0, 20);
// 创建列表项
results.forEach(poi => {
pois.forEach(poi => {
const li = document.createElement('li');
const distanceFormat = poi.distance ? `<div class="address-distance">${this.convertDistance(Math.round(poi.distance))}</div>` : '';
li.innerHTML = `

View File

@ -29,7 +29,6 @@ body {
.search-box {
padding: 10px;
background: #fff;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
position: relative;
z-index: 100;
}
@ -121,6 +120,7 @@ body {
#poi-list {
list-style: none;
padding-bottom: 10px;
}
#poi-list li {
@ -147,8 +147,8 @@ body {
transform: scaleY(0.5);
}
#poi-list li:hover {
background: #f5f5f5;
#poi-list li:last-child::before {
display: none;
}
.address-name {

View File

@ -76,7 +76,7 @@
</CheckboxGroup>
<div v-if="formData.modes.includes('face')" class="form-tip">{{$L('人脸签到')}}: {{$L('通过人脸识别机签到')}}</div>
<div v-if="formData.modes.includes('auto')" class="form-tip">{{$L('WiFi签到')}}: {{$L('详情看下文安装说明')}}</div>
<div v-if="formData.modes.includes('locat')" class="form-tip">{{$L('定位签到')}}: {{$L('通过在签到打卡机器人发送位置签到')}}</div>
<div v-if="formData.modes.includes('locat')" class="form-tip">{{$L('定位签到')}}: {{$L('通过在签到打卡机器人发送位置签到')}} ({{$L('仅支持移动端App')}})</div>
<div v-if="formData.modes.includes('manual')" class="form-tip">{{$L('手动签到')}}: {{$L('通过在签到打卡机器人发送指令签到')}}</div>
</FormItem>
</template>

View File

@ -978,7 +978,7 @@ export default {
openAppMapPage({dispatch}, objects) {
return new Promise(resolve => {
const params = {
title: $A.L("签到地点"),
title: $A.L("定位签到"),
label: $A.L("选择附近地点"),
placeholder: $A.L("搜索地点"),
noresult: $A.L("附近没有找到地点"),
@ -986,6 +986,7 @@ export default {
selectclose: "true",
channel: $A.randomString(6)
}
$A.eeuiAppSetVariate(`location::${params.channel}`, "");
const url = $A.urlAddParams($A.eeuiAppRewriteUrl('../public/tools/map/index.html'), Object.assign(params, objects || {}))
dispatch('openAppChildPage', {
pageType: 'app',
@ -997,9 +998,12 @@ export default {
url
},
callback: ({status}) => {
if (status === 'destroy') {
if (status === 'pause') {
const data = $A.jsonParse($A.eeuiAppGetVariate(`location::${params.channel}`));
resolve(data);
if (data.point) {
$A.eeuiAppSetVariate(`location::${params.channel}`, "");
resolve(data);
}
}
}
})

View File

@ -290,7 +290,9 @@ class BaiduMapPicker {
*/
initMap() {
// 初始化地图
this.map = new BMap.Map('map-container');
this.map = new BMap.Map('map-container', {
enableMapClick: false
});
// 初始化本地搜索,移除地图渲染
this.localSearch = new BMap.LocalSearch(this.map, {
@ -320,9 +322,7 @@ class BaiduMapPicker {
this.bindEvents();
// 初始化时自动定位
Loader.show();
this.getCurrentLocation().then((point) => {
Loader.hide();
if (point === null) {
this.locationError();
}
@ -348,10 +348,7 @@ class BaiduMapPicker {
// 地图定位点击事件
const mapLocation = document.getElementById('map-location');
mapLocation.addEventListener('click', () => {
Loader.show()
this.getCurrentLocation().then(() => {
Loader.hide()
});
this.getCurrentLocation();
});
}
@ -361,7 +358,9 @@ class BaiduMapPicker {
*/
getCurrentLocation() {
return new Promise(resolve => {
Loader.show()
App.getLocation().then(res => {
Loader.hide()
if (App.isJson(res) && res.longitude && res.latitude) {
const bd09_coord = CoordTransform.wgs84toBd09(res.longitude, res.latitude);
const point = new BMap.Point(bd09_coord[0], bd09_coord[1]);
@ -381,9 +380,13 @@ class BaiduMapPicker {
*/
updateCurrentPoint(point) {
this.currentPoint = point;
this.map.centerAndZoom(this.currentPoint, this.params.zoom);
if (Math.abs(this.map.getZoom() - this.params.zoom) > 1) {
this.map.centerAndZoom(this.currentPoint, this.params.zoom);
} else {
this.map.setCenter(this.currentPoint);
}
this.updateMarker(this.currentPoint);
this.searchNearby();
this.searchAddress();
}
/**
@ -403,95 +406,134 @@ class BaiduMapPicker {
* 搜索地址
*/
searchAddress() {
const keyword = document.getElementById('search-input').value;
this.searchNearby(keyword ? [keyword] : []);
const keyword = `${document.getElementById('search-input').value}`.trim();
if (keyword) {
this.searchKeyword(this.currentPoint, keyword);
} else {
this.searchLocation(this.currentPoint);
}
}
/**
* 搜索附近的地点
* @param keywords
* 通过关键词搜索附近的地点
* @param centerPoint
* @param keyword
* @param retryCount
*/
searchNearby(keywords = [], retryCount = 0) {
// 当前位置未获取
if (this.currentPoint === null) {
return;
}
searchKeyword(centerPoint, keyword, retryCount = 0) {
// 清除之前的搜索结果
this.localSearch.clearResults();
// 搜索附近的关键词
if (keywords.length === 0) {
keywords = ["写字楼", "公司", "银行", "餐馆", "商场", "超市", "学校", "医院", "公交站", "地铁站"]
}
// 定义一个随机数,用于判断定时器是否过期
this.searchRandom = Math.random();
// 设置搜索完成回调
Loader.show();
this.localSearch.setSearchCompleteCallback((results) => {
this.localSearch.setSearchCompleteCallback(result => {
Loader.hide();
if (this.localSearch.getStatus() !== BMAP_STATUS_SUCCESS) {
// 搜索失败
if (retryCount < 60) {
// 搜索失败10次重试
if (retryCount < 10) {
const tmpRand = this.searchRandom;
Loader.show();
setTimeout(() => {
Loader.hide();
tmpRand === this.searchRandom && this.searchNearby(keywords, ++retryCount);
}, 1000)
tmpRand === this.searchRandom && this.searchKeyword(centerPoint, keyword, ++retryCount);
}, 300)
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.params.point ? this.map.getDistance(this.params.point, poi.point) : null;
array.push(poi);
}
});
const pois = [];
for (let i = 0; i < result.getCurrentNumPois(); i++) {
const poi = result.getPoi(i);
if (!poi.point) {
continue;
}
poi.distance = this.params.point ? this.map.getDistance(this.params.point, poi.point) : null;
poi.distance_current = this.map.getDistance(centerPoint, poi.point);
pois.push(poi);
}
this.updatePoiList(array);
this.updatePoiList(pois);
});
// 执行搜索
this.localSearch.searchNearby(keywords, this.currentPoint, this.params.radius);
this.localSearch.searchNearby(keyword, centerPoint, this.params.radius);
}
/**
* 通过坐标搜索附近的地点
* @param point
*/
searchLocation(point) {
const geoc = new BMap.Geocoder();
Loader.show();
geoc.getLocation(point, (result) => {
Loader.hide();
const pois = [];
if (result) {
// 搜索结果
const surroundingPois = result.surroundingPois || [];
if (surroundingPois.length === 0) {
surroundingPois.push({
title: result.addressComponents.city + result.addressComponents.district,
address: result.address,
point: result.point,
});
}
surroundingPois.some(poi => {
if (!poi.point) {
return false;
}
poi.distance = this.params.point ? this.map.getDistance(this.params.point, poi.point) : null;
poi.distance_current = this.map.getDistance(point, poi.point);
pois.push(poi);
})
}
this.updatePoiList(pois)
}, {
poiRadius: this.params.radius,
numPois: 20,
});
}
/**
* 更新搜索结果列表
* @param results
* @param pois
*/
updatePoiList(results) {
updatePoiList(pois) {
const addressList = document.getElementById('address-list');
addressList.style.display = 'block';
const poiList = document.getElementById('poi-list');
poiList.innerHTML = '';
// 如果没有搜索结果
if (results.length === 0 && this.params.noresult) {
poiList.innerHTML = '<li>' + this.params.noresult + '</li>';
if (pois.length === 0) {
if (this.params.noresult) {
poiList.innerHTML = '<li><div class="address-noresult">' + this.params.noresult + '</div></li>';
}
return;
}
// 筛选距离小于搜索半径的结果(+100
pois = pois.filter(poi => {
return poi.title && poi.point && poi.distance_current < this.params.radius + 100;
});
// 按距离排序(如果有距离信息)
results.sort((a, b) => {
if (a.distance && b.distance) {
return a.distance - b.distance;
pois.sort((a, b) => {
if (a.distance_current && b.distance_current) {
return a.distance_current - b.distance_current;
}
return 0;
});
results = results.slice(0, 20);
// 只显示前20个结果
pois = pois.slice(0, 20);
// 创建列表项
results.forEach(poi => {
pois.forEach(poi => {
const li = document.createElement('li');
const distanceFormat = poi.distance ? `<div class="address-distance">${this.convertDistance(Math.round(poi.distance))}</div>` : '';
li.innerHTML = `

View File

@ -29,7 +29,6 @@ body {
.search-box {
padding: 10px;
background: #fff;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
position: relative;
z-index: 100;
}
@ -121,6 +120,7 @@ body {
#poi-list {
list-style: none;
padding-bottom: 10px;
}
#poi-list li {
@ -147,8 +147,8 @@ body {
transform: scaleY(0.5);
}
#poi-list li:hover {
background: #f5f5f5;
#poi-list li:last-child::before {
display: none;
}
.address-name {