mirror of
https://github.com/kuaifan/dootask.git
synced 2025-12-11 18:42:54 +00:00
perf: 签到新增高德和腾讯地图
This commit is contained in:
parent
8c9c1c5afa
commit
4c075b4d11
@ -481,8 +481,13 @@ class SystemController extends AbstractController
|
||||
'face_remark',
|
||||
'face_retip',
|
||||
'locat_remark',
|
||||
'locat_map_type',
|
||||
'locat_bd_lbs_key',
|
||||
'locat_bd_lbs_point', // 格式:{"lng":116.404, "lat":39.915, "radius":500}
|
||||
'locat_amap_key',
|
||||
'locat_amap_point', // 格式:{"lng":116.404, "lat":39.915, "radius":500}
|
||||
'locat_tencent_key',
|
||||
'locat_tencent_point', // 格式:{"lng":116.404, "lat":39.915, "radius":500}
|
||||
'manual_remark',
|
||||
'modes',
|
||||
'key',
|
||||
@ -500,14 +505,25 @@ class SystemController extends AbstractController
|
||||
}
|
||||
if (is_array($all['modes'])) {
|
||||
if (in_array('locat', $all['modes'])) {
|
||||
if (empty($all['locat_bd_lbs_key'])) {
|
||||
return Base::retError('请填写百度地图AK');
|
||||
$mapTypes = [
|
||||
'baidu' => ['key' => 'locat_bd_lbs_key', 'point' => 'locat_bd_lbs_point', 'msg' => '请填写百度地图AK'],
|
||||
'amap' => ['key' => 'locat_amap_key', 'point' => 'locat_amap_point', 'msg' => '请填写高德地图Key'],
|
||||
'tencent' => ['key' => 'locat_tencent_key', 'point' => 'locat_tencent_point', 'msg' => '请填写腾讯地图Key'],
|
||||
];
|
||||
$type = $all['locat_map_type'];
|
||||
if (!isset($mapTypes[$type])) {
|
||||
return Base::retError('请选择地图类型');
|
||||
}
|
||||
if (!is_array($all['locat_bd_lbs_point'])) {
|
||||
$conf = $mapTypes[$type];
|
||||
if (empty($all[$conf['key']])) {
|
||||
return Base::retError($conf['msg']);
|
||||
}
|
||||
if (!is_array($all[$conf['point']])) {
|
||||
return Base::retError('请选择允许签到位置');
|
||||
}
|
||||
$all['locat_bd_lbs_point']['radius'] = intval($all['locat_bd_lbs_point']['radius']);
|
||||
if (empty($all['locat_bd_lbs_point']['lng']) || empty($all['locat_bd_lbs_point']['lat']) || empty($all['locat_bd_lbs_point']['radius'])) {
|
||||
$all[$conf['point']]['radius'] = intval($all[$conf['point']]['radius']);
|
||||
$point = $all[$conf['point']];
|
||||
if (empty($point['lng']) || empty($point['lat']) || empty($point['radius'])) {
|
||||
return Base::retError('请选择有效的签到位置');
|
||||
}
|
||||
}
|
||||
@ -539,7 +555,10 @@ class SystemController extends AbstractController
|
||||
$setting['face_remark'] = $setting['face_remark'] ?: Doo::translate('考勤机');
|
||||
$setting['face_retip'] = $setting['face_retip'] ?: 'open';
|
||||
$setting['locat_remark'] = $setting['locat_remark'] ?: Doo::translate('定位签到');
|
||||
$setting['locat_map_type'] = $setting['locat_map_type'] ?: 'baidu';
|
||||
$setting['locat_bd_lbs_point'] = is_array($setting['locat_bd_lbs_point']) ? $setting['locat_bd_lbs_point'] : ['radius' => 500];
|
||||
$setting['locat_amap_point'] = is_array($setting['locat_amap_point']) ? $setting['locat_amap_point'] : ['radius' => 500];
|
||||
$setting['locat_tencent_point'] = is_array($setting['locat_tencent_point']) ? $setting['locat_tencent_point'] : ['radius' => 500];
|
||||
$setting['manual_remark'] = $setting['manual_remark'] ?: Doo::translate('手动签到');
|
||||
$setting['time'] = $setting['time'] ? Base::json2array($setting['time']) : ['09:00', '18:00'];
|
||||
$setting['advance'] = intval($setting['advance']) ?: 120;
|
||||
|
||||
286
public/tools/map/select_amap.html
Normal file
286
public/tools/map/select_amap.html
Normal file
@ -0,0 +1,286 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title></title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#map-container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
<script>
|
||||
class AmapPickup {
|
||||
constructor(containerId) {
|
||||
this.containerId = containerId;
|
||||
this.map = null;
|
||||
this.circle = null;
|
||||
this.marker = null;
|
||||
this.centerPoint = null;
|
||||
this.isFirstClick = true;
|
||||
this.params = {
|
||||
theme: 'light', // 主题风格,light|dark
|
||||
key: null, // 高德地图 API Key
|
||||
point: null, // 初始坐标,如:116.404,39.915
|
||||
radius: 300, // 圆形半径
|
||||
zoom: 16, // 地图缩放级别
|
||||
}
|
||||
this.init();
|
||||
}
|
||||
|
||||
async init() {
|
||||
// 先初始化参数
|
||||
this.initParams();
|
||||
|
||||
// 如果没有 key,直接返回
|
||||
if (!this.params.key) {
|
||||
console.error('未提供高德地图 API Key');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 等待地图 JS 加载完成
|
||||
await this.loadMapScript();
|
||||
// 初始化地图
|
||||
this.initMap();
|
||||
} catch (error) {
|
||||
console.error('加载高德地图失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
initParams() {
|
||||
// 获取当前URL的查询参数
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
|
||||
// 遍历 params 对象的所有属性
|
||||
Object.keys(this.params).forEach(key => {
|
||||
// 从 URL 参数中获取值
|
||||
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";
|
||||
}
|
||||
|
||||
// 初始化地图
|
||||
initMap() {
|
||||
this.map = new AMap.Map(this.containerId, {
|
||||
zoom: this.params.zoom,
|
||||
center: this.params.point ? [this.params.point.lng, this.params.point.lat] : [116.404, 39.915],
|
||||
enableMapClick: true
|
||||
});
|
||||
|
||||
if (this.params.point) {
|
||||
this.centerPoint = [this.params.point.lng, this.params.point.lat];
|
||||
this.handleMapClick({lnglat: {lng: this.params.point.lng, lat: this.params.point.lat}});
|
||||
} else {
|
||||
this.centerPoint = [116.404, 39.915];
|
||||
}
|
||||
|
||||
this.bindEvents();
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
this.map.on('click', (e) => this.handleMapClick(e));
|
||||
|
||||
// 监听父页面消息
|
||||
window.addEventListener('message', (event) => {
|
||||
if (event.data.action === 'update_radius') {
|
||||
const newRadius = parseInt(event.data.radius);
|
||||
if (newRadius && newRadius >= 50 && newRadius <= 5000) {
|
||||
this.params.radius = newRadius;
|
||||
if (this.circle) {
|
||||
this.updateMarkerAndCircle();
|
||||
this.updateInfoPanel();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
handleMapClick(e) {
|
||||
this.centerPoint = [e.lnglat.lng, e.lnglat.lat];
|
||||
|
||||
if (this.isFirstClick) {
|
||||
this.createMarkerAndCircle();
|
||||
this.isFirstClick = false;
|
||||
} else {
|
||||
this.params.radius = this.circle.getRadius();
|
||||
this.updateMarkerAndCircle();
|
||||
}
|
||||
|
||||
this.updateInfoPanel();
|
||||
}
|
||||
|
||||
createMarkerAndCircle() {
|
||||
this.createMarker();
|
||||
this.createCircle();
|
||||
}
|
||||
|
||||
createMarker() {
|
||||
if (this.marker) {
|
||||
this.map.remove(this.marker);
|
||||
}
|
||||
this.marker = new AMap.Marker({
|
||||
position: this.centerPoint,
|
||||
map: this.map
|
||||
});
|
||||
}
|
||||
|
||||
createCircle() {
|
||||
if (this.circle) {
|
||||
this.map.remove(this.circle);
|
||||
}
|
||||
this.circle = new AMap.Circle({
|
||||
center: this.centerPoint,
|
||||
radius: this.params.radius,
|
||||
strokeColor: "#FF0000",
|
||||
strokeWeight: 2,
|
||||
strokeOpacity: 0.5,
|
||||
fillColor: "#FF0000",
|
||||
fillOpacity: 0.2,
|
||||
map: this.map
|
||||
});
|
||||
}
|
||||
|
||||
updateMarkerAndCircle() {
|
||||
if (this.marker) {
|
||||
this.map.remove(this.marker);
|
||||
}
|
||||
if (this.circle) {
|
||||
this.map.remove(this.circle);
|
||||
}
|
||||
|
||||
this.createMarker();
|
||||
this.createCircle();
|
||||
}
|
||||
|
||||
updateInfoPanel() {
|
||||
const currentRadius = this.circle ? this.circle.getRadius().toFixed(0) : this.params.radius.toString();
|
||||
const data = {
|
||||
longitude: this.centerPoint[0].toFixed(6),
|
||||
latitude: this.centerPoint[1].toFixed(6),
|
||||
radius: currentRadius
|
||||
}
|
||||
|
||||
// 发送消息给父页面
|
||||
window.parent.postMessage(Object.assign(data, {
|
||||
action: "amap_lbs_select_point",
|
||||
}), "*");
|
||||
}
|
||||
|
||||
// 获取当前选择的数据
|
||||
getData() {
|
||||
if (!this.circle) return null;
|
||||
|
||||
return {
|
||||
center: {
|
||||
lng: this.centerPoint[0],
|
||||
lat: this.centerPoint[1]
|
||||
},
|
||||
radius: this.circle.getRadius()
|
||||
};
|
||||
}
|
||||
|
||||
// 设置中心点和半径
|
||||
setData(lng, lat, radius) {
|
||||
this.centerPoint = [lng, lat];
|
||||
this.params.radius = radius || this.params.radius;
|
||||
|
||||
if (this.isFirstClick) {
|
||||
this.createMarkerAndCircle();
|
||||
this.isFirstClick = false;
|
||||
} else {
|
||||
this.updateMarkerAndCircle();
|
||||
}
|
||||
|
||||
this.updateInfoPanel();
|
||||
this.map.setCenter(this.centerPoint);
|
||||
}
|
||||
|
||||
loadMapScript() {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 如果已经加载过,直接返回
|
||||
if (window.AMap) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建script标签
|
||||
const script = document.createElement('script');
|
||||
script.type = 'text/javascript';
|
||||
script.src = `https://webapi.amap.com/maps?v=1.4.15&key=${this.params.key}&callback=initAmapMap`;
|
||||
|
||||
// 添加回调函数
|
||||
window.initAmapMap = () => {
|
||||
resolve();
|
||||
delete window.initAmapMap;
|
||||
};
|
||||
|
||||
// 处理加载错误
|
||||
script.onerror = () => {
|
||||
reject(new Error('高德地图脚本加载失败'));
|
||||
};
|
||||
|
||||
// 添加到页面
|
||||
document.body.appendChild(script);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载完成后初始化
|
||||
window.onload = function () {
|
||||
window.pickup = new AmapPickup("map-container");
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="map-container"></div>
|
||||
</body>
|
||||
</html>
|
||||
@ -29,6 +29,8 @@
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
<script>
|
||||
class Pickup {
|
||||
@ -133,6 +135,20 @@
|
||||
|
||||
bindEvents() {
|
||||
this.map.addEventListener("click", (e) => this.handleMapClick(e));
|
||||
|
||||
// 监听父页面消息
|
||||
window.addEventListener('message', (event) => {
|
||||
if (event.data.action === 'update_radius') {
|
||||
const newRadius = parseInt(event.data.radius);
|
||||
if (newRadius && newRadius >= 50 && newRadius <= 5000) {
|
||||
this.params.radius = newRadius;
|
||||
if (this.circle) {
|
||||
this.updateMarkerAndCircle();
|
||||
this.updateInfoPanel();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
handleMapClick(e) {
|
||||
@ -191,13 +207,16 @@
|
||||
}
|
||||
|
||||
updateInfoPanel() {
|
||||
const currentRadius = this.circle ? this.circle.getRadius().toFixed(0) : this.params.radius.toString();
|
||||
const data = {
|
||||
longitude: this.centerPoint.lng.toFixed(6),
|
||||
latitude: this.centerPoint.lat.toFixed(6),
|
||||
radius: this.circle ? this.circle.getRadius().toFixed(0) : '-'
|
||||
radius: currentRadius
|
||||
}
|
||||
|
||||
// 发送消息给父页面
|
||||
window.parent.postMessage(Object.assign(data, {
|
||||
action: "bd_lbs_select_point",
|
||||
action: "baidu_lbs_select_point",
|
||||
}), "*");
|
||||
}
|
||||
|
||||
297
public/tools/map/select_tencent.html
Normal file
297
public/tools/map/select_tencent.html
Normal file
@ -0,0 +1,297 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title></title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#map-container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
<script>
|
||||
class TencentPickup {
|
||||
constructor(containerId) {
|
||||
this.containerId = containerId;
|
||||
this.map = null;
|
||||
this.circle = null;
|
||||
this.marker = null;
|
||||
this.centerPoint = null;
|
||||
this.isFirstClick = true;
|
||||
this.params = {
|
||||
theme: 'light', // 主题风格,light|dark
|
||||
key: null, // 腾讯地图 API Key
|
||||
point: null, // 初始坐标,如:116.404,39.915
|
||||
radius: 300, // 圆形半径
|
||||
zoom: 16, // 地图缩放级别
|
||||
}
|
||||
this.init();
|
||||
}
|
||||
|
||||
async init() {
|
||||
// 先初始化参数
|
||||
this.initParams();
|
||||
|
||||
// 如果没有 key,直接返回
|
||||
if (!this.params.key) {
|
||||
console.error('未提供腾讯地图 API Key');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 等待地图 JS 加载完成
|
||||
await this.loadMapScript();
|
||||
// 初始化地图
|
||||
this.initMap();
|
||||
} catch (error) {
|
||||
console.error('加载腾讯地图失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
initParams() {
|
||||
// 获取当前URL的查询参数
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
|
||||
// 遍历 params 对象的所有属性
|
||||
Object.keys(this.params).forEach(key => {
|
||||
// 从 URL 参数中获取值
|
||||
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";
|
||||
}
|
||||
|
||||
// 初始化地图
|
||||
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(this.containerId, {
|
||||
center: center,
|
||||
zoom: this.params.zoom
|
||||
});
|
||||
|
||||
if (this.params.point) {
|
||||
this.centerPoint = center;
|
||||
this.handleMapClick({latLng: center});
|
||||
} else {
|
||||
this.centerPoint = center;
|
||||
}
|
||||
|
||||
this.bindEvents();
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
this.map.on('click', (e) => this.handleMapClick(e));
|
||||
|
||||
// 监听父页面消息
|
||||
window.addEventListener('message', (event) => {
|
||||
if (event.data.action === 'update_radius') {
|
||||
const newRadius = parseInt(event.data.radius);
|
||||
if (newRadius && newRadius >= 50 && newRadius <= 5000) {
|
||||
this.params.radius = newRadius;
|
||||
if (this.circle) {
|
||||
this.updateMarkerAndCircle();
|
||||
this.updateInfoPanel();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
handleMapClick(e) {
|
||||
this.centerPoint = e.latLng;
|
||||
|
||||
if (this.isFirstClick) {
|
||||
this.createMarkerAndCircle();
|
||||
this.isFirstClick = false;
|
||||
} else {
|
||||
this.updateMarkerAndCircle();
|
||||
}
|
||||
|
||||
this.updateInfoPanel();
|
||||
}
|
||||
|
||||
createMarkerAndCircle() {
|
||||
this.createMarker();
|
||||
this.createCircle();
|
||||
}
|
||||
|
||||
createMarker() {
|
||||
if (this.marker) {
|
||||
this.marker.setMap(null);
|
||||
}
|
||||
|
||||
// 使用MultiMarker,但不设置自定义样式,使用默认样式
|
||||
this.marker = new TMap.MultiMarker({
|
||||
map: this.map,
|
||||
geometries: [{
|
||||
id: 'marker1',
|
||||
position: this.centerPoint
|
||||
}]
|
||||
});
|
||||
}
|
||||
|
||||
createCircle() {
|
||||
if (this.circle) {
|
||||
this.circle.setMap(null);
|
||||
}
|
||||
|
||||
// 使用MultiCircle,但不设置自定义样式,使用默认样式
|
||||
this.circle = new TMap.MultiCircle({
|
||||
map: this.map,
|
||||
geometries: [{
|
||||
id: 'circle1',
|
||||
center: this.centerPoint,
|
||||
radius: this.params.radius
|
||||
}]
|
||||
});
|
||||
}
|
||||
|
||||
updateMarkerAndCircle() {
|
||||
if (this.marker) {
|
||||
this.marker.updateGeometries([{
|
||||
id: 'marker1',
|
||||
position: this.centerPoint
|
||||
}]);
|
||||
}
|
||||
|
||||
if (this.circle) {
|
||||
this.circle.updateGeometries([{
|
||||
id: 'circle1',
|
||||
center: this.centerPoint,
|
||||
radius: this.params.radius
|
||||
}]);
|
||||
}
|
||||
}
|
||||
|
||||
updateInfoPanel() {
|
||||
const data = {
|
||||
longitude: this.centerPoint.lng.toFixed(6),
|
||||
latitude: this.centerPoint.lat.toFixed(6),
|
||||
radius: this.params.radius.toString()
|
||||
}
|
||||
|
||||
// 发送消息给父页面
|
||||
window.parent.postMessage(Object.assign(data, {
|
||||
action: "tencent_lbs_select_point",
|
||||
}), "*");
|
||||
}
|
||||
|
||||
// 获取当前选择的数据
|
||||
getData() {
|
||||
if (!this.circle) return null;
|
||||
|
||||
return {
|
||||
center: {
|
||||
lng: this.centerPoint.lng,
|
||||
lat: this.centerPoint.lat
|
||||
},
|
||||
radius: this.params.radius
|
||||
};
|
||||
}
|
||||
|
||||
// 设置中心点和半径
|
||||
setData(lng, lat, radius) {
|
||||
this.centerPoint = new TMap.LatLng(lat, lng);
|
||||
this.params.radius = radius || this.params.radius;
|
||||
|
||||
if (this.isFirstClick) {
|
||||
this.createMarkerAndCircle();
|
||||
this.isFirstClick = false;
|
||||
} else {
|
||||
this.updateMarkerAndCircle();
|
||||
}
|
||||
|
||||
this.updateInfoPanel();
|
||||
this.map.setCenter(this.centerPoint);
|
||||
}
|
||||
|
||||
loadMapScript() {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 如果已经加载过,直接返回
|
||||
if (window.TMap) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建script标签
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载完成后初始化
|
||||
window.onload = function () {
|
||||
window.pickup = new TencentPickup("map-container");
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="map-container"></div>
|
||||
</body>
|
||||
</html>
|
||||
@ -125,20 +125,71 @@
|
||||
<FormItem :label="$L('签到备注')" prop="locat_remark">
|
||||
<Input :maxlength="30" v-model="formData.locat_remark"/>
|
||||
</FormItem>
|
||||
<FormItem :label="$L('百度地图AK')" prop="locat_bd_lbs_key">
|
||||
<Input :maxlength="100" v-model="formData.locat_bd_lbs_key"/>
|
||||
<div class="form-tip">{{$L('获取AK流程')}}: <a href="https://lbs.baidu.com/faq/search?id=299&title=677" target="_blank">https://lbs.baidu.com/faq/search?id=299&title=677</a></div>
|
||||
</FormItem>
|
||||
<FormItem :label="$L('允许签到位置')" prop="locat_bd_allow_point">
|
||||
<ETooltip v-if="formData.locat_bd_lbs_point.lng" :content="$L('点击修改')">
|
||||
<div class="form-tip">
|
||||
<a href="javascript:void(0)" @click="openBdSelect">
|
||||
{{ $L(`经度:${formData.locat_bd_lbs_point.lng},纬度:${formData.locat_bd_lbs_point.lat},半径:${formData.locat_bd_lbs_point.radius}米`) }}
|
||||
</a>
|
||||
</div>
|
||||
</ETooltip>
|
||||
<a v-else href="javascript:void(0)" @click="openBdSelect">{{$L('点击设置')}}</a>
|
||||
<FormItem :label="$L('地图类型')" prop="locat_map_type">
|
||||
<RadioGroup v-model="formData.locat_map_type">
|
||||
<Radio label="baidu">{{ $L('百度地图') }}</Radio>
|
||||
<Radio label="amap">{{ $L('高德地图') }}</Radio>
|
||||
<Radio label="tencent">{{ $L('腾讯地图') }}</Radio>
|
||||
</RadioGroup>
|
||||
<div class="form-tip">{{$L('仅支持移动端App')}}</div>
|
||||
</FormItem>
|
||||
|
||||
<!-- 百度地图配置 -->
|
||||
<template v-if="formData.locat_map_type === 'baidu'">
|
||||
<FormItem :label="$L('百度地图AK')" prop="locat_bd_lbs_key">
|
||||
<Input :maxlength="100" v-model="formData.locat_bd_lbs_key"/>
|
||||
<div class="form-tip">{{$L('获取AK流程')}}: <a href="https://lbs.baidu.com/faq/search?id=299&title=677" target="_blank">https://lbs.baidu.com/faq/search?id=299&title=677</a></div>
|
||||
</FormItem>
|
||||
<FormItem :label="$L('允许签到位置')" prop="locat_bd_lbs_point">
|
||||
<template v-if="formData.locat_bd_lbs_point.lng">
|
||||
<div class="form-tip">
|
||||
<a href="javascript:void(0)" @click="openMapSelect">
|
||||
{{ $L(`经度:${formData.locat_bd_lbs_point.lng},纬度:${formData.locat_bd_lbs_point.lat},半径:${formData.locat_bd_lbs_point.radius}米`) }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="form-tip" @click="openMapSelect">{{$L('点击修改允许签到位置')}}</div>
|
||||
</template>
|
||||
<a v-else href="javascript:void(0)" @click="openMapSelect">{{$L('点击设置')}}</a>
|
||||
</FormItem>
|
||||
</template>
|
||||
|
||||
<!-- 高德地图配置 -->
|
||||
<template v-if="formData.locat_map_type === 'amap'">
|
||||
<FormItem :label="$L('高德地图Key')" prop="locat_amap_key">
|
||||
<Input :maxlength="100" v-model="formData.locat_amap_key"/>
|
||||
<div class="form-tip">{{$L('获取Key流程')}}: <a href="https://lbs.amap.com/api/javascript-api/guide/abc/prepare" target="_blank">https://lbs.amap.com/api/javascript-api/guide/abc/prepare</a></div>
|
||||
</FormItem>
|
||||
<FormItem :label="$L('允许签到位置')" prop="locat_amap_point">
|
||||
<template v-if="formData.locat_amap_point.lng">
|
||||
<div class="form-tip">
|
||||
<a href="javascript:void(0)" @click="openMapSelect">
|
||||
{{ $L(`经度:${formData.locat_amap_point.lng},纬度:${formData.locat_amap_point.lat},半径:${formData.locat_amap_point.radius}米`) }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="form-tip" @click="openMapSelect">{{$L('点击修改允许签到位置')}}</div>
|
||||
</template>
|
||||
<a v-else href="javascript:void(0)" @click="openMapSelect">{{$L('点击设置')}}</a>
|
||||
</FormItem>
|
||||
</template>
|
||||
|
||||
<!-- 腾讯地图配置 -->
|
||||
<template v-if="formData.locat_map_type === 'tencent'">
|
||||
<FormItem :label="$L('腾讯地图Key')" prop="locat_tencent_key">
|
||||
<Input :maxlength="100" v-model="formData.locat_tencent_key"/>
|
||||
<div class="form-tip">{{$L('获取Key流程')}}: <a href="https://lbs.qq.com/dev/console/application/mine" target="_blank">https://lbs.qq.com/dev/console/application/mine</a></div>
|
||||
</FormItem>
|
||||
<FormItem :label="$L('允许签到位置')" prop="locat_tencent_point">
|
||||
<template v-if="formData.locat_tencent_point.lng">
|
||||
<div class="form-tip">
|
||||
<a href="javascript:void(0)" @click="openMapSelect">
|
||||
{{ $L(`经度:${formData.locat_tencent_point.lng},纬度:${formData.locat_tencent_point.lat},半径:${formData.locat_tencent_point.radius}米`) }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="form-tip" @click="openMapSelect">{{$L('点击修改允许签到位置')}}</div>
|
||||
</template>
|
||||
<a v-else href="javascript:void(0)" @click="openMapSelect">{{$L('点击设置')}}</a>
|
||||
</FormItem>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -171,38 +222,140 @@
|
||||
<TeamManagement v-if="allUserShow" checkin-mode/>
|
||||
</DrawerOverlay>
|
||||
|
||||
<!--百度选择签到位置-->
|
||||
<!--地图选择签到位置-->
|
||||
<Modal
|
||||
v-model="bdSelectShow"
|
||||
v-model="mapSelectShow"
|
||||
:title="$L('允许签到位置')"
|
||||
:mask-closable="false"
|
||||
width="800">
|
||||
:styles="{
|
||||
width: '90%',
|
||||
maxWidth: '1000px'
|
||||
}">
|
||||
<div>
|
||||
<div v-if="bdSelectPoint.radius" class="bd-select-point-tip">{{ $L(`签到半径${bdSelectPoint.radius}米`) }}</div>
|
||||
<div v-else class="bd-select-point-tip">{{ $L('请点击地图选择签到位置') }}</div>
|
||||
<IFrame v-if="bdSelectShow" class="bd-select-point-iframe" :src="bdSelectUrl" @on-message="onBdMessage"/>
|
||||
<div class="map-select-container">
|
||||
<div class="map-select-iframe-container">
|
||||
<IFrame v-if="mapSelectShow" ref="mapSelectIframe" class="map-select-point-iframe" :src="mapSelectUrl" @on-message="onMapMessage"/>
|
||||
</div>
|
||||
<div class="map-radius-control">
|
||||
<div class="radius-control-header">
|
||||
<h4>{{ $L('签到半径设置') }}</h4>
|
||||
</div>
|
||||
<div class="radius-control-body">
|
||||
<Input :value="mapSelectPoint.radius" @on-change="onRadiusChange" @on-blur="onRadiusBlur">
|
||||
<span slot="prepend">{{ $L('半径') }}</span>
|
||||
<span slot="append">{{ $L('米') }}</span>
|
||||
</Input>
|
||||
<div class="location-info">
|
||||
<div class="info-item">
|
||||
<span class="info-label">{{ $L('经度') }}:</span>
|
||||
<span class="info-value">{{ mapSelectPoint.lng || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">{{ $L('纬度') }}:</span>
|
||||
<span class="info-value">{{ mapSelectPoint.lat || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">{{ $L('半径') }}:</span>
|
||||
<span class="info-value">{{ mapSelectPoint.radius || '-' }} {{ $L('米') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="radius-control-tip">
|
||||
<template v-if="formData.locat_map_type === 'baidu'">
|
||||
{{ $L('点击地图选择中心位置,拖拽圆形边缘调整半径,或在上方输入框直接设置半径值') }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ $L('点击地图选择中心位置,在上方输入框中设置签到半径值') }}
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" class="adaption">
|
||||
<Button type="default" @click="bdSelectShow=false">{{$L('关闭')}}</Button>
|
||||
<Button type="primary" @click="onBdSelect">{{$L('确定')}}</Button>
|
||||
<Button type="default" @click="mapSelectShow=false">{{$L('关闭')}}</Button>
|
||||
<Button type="primary" @click="onMapSelect">{{$L('确定')}}</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
.bd-select-point-tip {
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
margin-bottom: 12px;
|
||||
margin-top: -12px;
|
||||
}
|
||||
.bd-select-point-iframe {
|
||||
width: 100%;
|
||||
.map-select-container {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
height: 500px;
|
||||
@media (max-width: 768px) {
|
||||
flex-direction: column;
|
||||
height: 700px;
|
||||
.map-radius-control {
|
||||
width: 100%;
|
||||
border-left: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.map-select-iframe-container {
|
||||
flex: 1;
|
||||
}
|
||||
.map-select-point-iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
border-radius: 12px;
|
||||
}
|
||||
.map-radius-control {
|
||||
width: 280px;
|
||||
border-left: 1px solid #e8e8e8;
|
||||
padding-left: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.radius-control-header {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.radius-control-header h4 {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
.radius-control-body {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.location-info {
|
||||
margin: 15px 0;
|
||||
padding: 12px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.info-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.info-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.info-label {
|
||||
color: #666;
|
||||
}
|
||||
.info-value {
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
.radius-control-tip {
|
||||
background: #f0f8ff;
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
border-left: 3px solid #007cff;
|
||||
font-size: 13px;
|
||||
color: #333;
|
||||
line-height: 1.4;
|
||||
margin-top: auto;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
import DrawerOverlay from "../../../../components/DrawerOverlay";
|
||||
@ -227,16 +380,22 @@ export default {
|
||||
face_retip: '',
|
||||
manual_remark: '',
|
||||
locat_remark: '',
|
||||
locat_bd_lbs_point: {},
|
||||
locat_map_type: 'baidu', // 地图类型
|
||||
locat_bd_lbs_key: '', // 百度地图AK
|
||||
locat_bd_lbs_point: {}, // 百度地图允许签到位置
|
||||
locat_amap_key: '', // 高德地图Key
|
||||
locat_amap_point: {}, // 高德地图允许签到位置
|
||||
locat_tencent_key: '', // 腾讯地图Key
|
||||
locat_tencent_point: {}, // 腾讯地图允许签到位置
|
||||
},
|
||||
ruleData: {},
|
||||
|
||||
allUserShow: false,
|
||||
exportShow: false,
|
||||
|
||||
bdSelectShow: false,
|
||||
bdSelectPoint: {},
|
||||
bdSelectUrl: '',
|
||||
mapSelectShow: false,
|
||||
mapSelectPoint: {},
|
||||
mapSelectUrl: '',
|
||||
}
|
||||
},
|
||||
|
||||
@ -291,37 +450,98 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
openBdSelect() {
|
||||
if (!this.formData.locat_bd_lbs_key) {
|
||||
$A.messageError('请先填写百度地图AK');
|
||||
return;
|
||||
openMapSelect() {
|
||||
const mapType = this.formData.locat_map_type;
|
||||
let mapKey = '';
|
||||
let currentPoint = {};
|
||||
|
||||
// 根据地图类型获取对应的key和point
|
||||
switch (mapType) {
|
||||
case 'baidu':
|
||||
mapKey = this.formData.locat_bd_lbs_key;
|
||||
currentPoint = this.formData.locat_bd_lbs_point;
|
||||
if (!mapKey) {
|
||||
$A.messageError('请先填写百度地图AK');
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 'amap':
|
||||
mapKey = this.formData.locat_amap_key;
|
||||
currentPoint = this.formData.locat_amap_point;
|
||||
if (!mapKey) {
|
||||
$A.messageError('请先填写高德地图Key');
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 'tencent':
|
||||
mapKey = this.formData.locat_tencent_key;
|
||||
currentPoint = this.formData.locat_tencent_point;
|
||||
if (!mapKey) {
|
||||
$A.messageError('请先填写腾讯地图Key');
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$A.messageError('请选择地图类型');
|
||||
return;
|
||||
}
|
||||
const url = $A.urlAddParams($A.mainUrl('tools/map/select.html'), {
|
||||
key: this.formData.locat_bd_lbs_key,
|
||||
point: this.formData.locat_bd_lbs_point.lng + ',' + this.formData.locat_bd_lbs_point.lat,
|
||||
radius: this.formData.locat_bd_lbs_point.radius,
|
||||
|
||||
const selectPage = `select_${mapType}.html`;
|
||||
const url = $A.urlAddParams($A.mainUrl(`tools/map/${selectPage}`), {
|
||||
key: mapKey,
|
||||
point: currentPoint.lng + ',' + currentPoint.lat,
|
||||
radius: currentPoint.radius,
|
||||
})
|
||||
|
||||
this.$store.dispatch('userUrl', url).then(newUrl => {
|
||||
this.bdSelectUrl = newUrl;
|
||||
this.bdSelectPoint = this.formData.locat_bd_lbs_point;
|
||||
this.bdSelectShow = true;
|
||||
this.mapSelectUrl = newUrl;
|
||||
this.mapSelectPoint = currentPoint;
|
||||
this.mapSelectShow = true;
|
||||
});
|
||||
},
|
||||
|
||||
onBdMessage(data) {
|
||||
if (data.action !== 'bd_lbs_select_point') {
|
||||
onMapMessage(data) {
|
||||
const expectedAction = `${this.formData.locat_map_type}_lbs_select_point`;
|
||||
if (data.action !== expectedAction) {
|
||||
return;
|
||||
}
|
||||
this.bdSelectPoint = {
|
||||
lng: data.longitude,
|
||||
lat: data.latitude,
|
||||
radius: data.radius,
|
||||
this.mapSelectPoint = {
|
||||
lng: parseFloat(data.longitude),
|
||||
lat: parseFloat(data.latitude),
|
||||
radius: parseInt(data.radius),
|
||||
}
|
||||
},
|
||||
|
||||
onBdSelect() {
|
||||
this.formData.locat_bd_lbs_point = this.bdSelectPoint;
|
||||
this.bdSelectShow = false;
|
||||
onRadiusChange({target}) {
|
||||
const value = parseInt(target.value);
|
||||
if (value && value >= 50 && value <= 5000) {
|
||||
this.mapSelectPoint.radius = value;
|
||||
const iframe = this.$refs.mapSelectIframe;
|
||||
iframe?.postMessage({
|
||||
action: 'update_radius',
|
||||
radius: value
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
onRadiusBlur({target}) {
|
||||
target.value = this.mapSelectPoint.radius;
|
||||
},
|
||||
|
||||
onMapSelect() {
|
||||
const mapType = this.formData.locat_map_type;
|
||||
switch (mapType) {
|
||||
case 'baidu':
|
||||
this.formData.locat_bd_lbs_point = this.mapSelectPoint;
|
||||
break;
|
||||
case 'amap':
|
||||
this.formData.locat_amap_point = this.mapSelectPoint;
|
||||
break;
|
||||
case 'tencent':
|
||||
this.formData.locat_tencent_point = this.mapSelectPoint;
|
||||
break;
|
||||
}
|
||||
this.mapSelectShow = false;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
286
resources/assets/statics/public/tools/map/select_amap.html
Normal file
286
resources/assets/statics/public/tools/map/select_amap.html
Normal file
@ -0,0 +1,286 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title></title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#map-container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
<script>
|
||||
class AmapPickup {
|
||||
constructor(containerId) {
|
||||
this.containerId = containerId;
|
||||
this.map = null;
|
||||
this.circle = null;
|
||||
this.marker = null;
|
||||
this.centerPoint = null;
|
||||
this.isFirstClick = true;
|
||||
this.params = {
|
||||
theme: 'light', // 主题风格,light|dark
|
||||
key: null, // 高德地图 API Key
|
||||
point: null, // 初始坐标,如:116.404,39.915
|
||||
radius: 300, // 圆形半径
|
||||
zoom: 16, // 地图缩放级别
|
||||
}
|
||||
this.init();
|
||||
}
|
||||
|
||||
async init() {
|
||||
// 先初始化参数
|
||||
this.initParams();
|
||||
|
||||
// 如果没有 key,直接返回
|
||||
if (!this.params.key) {
|
||||
console.error('未提供高德地图 API Key');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 等待地图 JS 加载完成
|
||||
await this.loadMapScript();
|
||||
// 初始化地图
|
||||
this.initMap();
|
||||
} catch (error) {
|
||||
console.error('加载高德地图失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
initParams() {
|
||||
// 获取当前URL的查询参数
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
|
||||
// 遍历 params 对象的所有属性
|
||||
Object.keys(this.params).forEach(key => {
|
||||
// 从 URL 参数中获取值
|
||||
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";
|
||||
}
|
||||
|
||||
// 初始化地图
|
||||
initMap() {
|
||||
this.map = new AMap.Map(this.containerId, {
|
||||
zoom: this.params.zoom,
|
||||
center: this.params.point ? [this.params.point.lng, this.params.point.lat] : [116.404, 39.915],
|
||||
enableMapClick: true
|
||||
});
|
||||
|
||||
if (this.params.point) {
|
||||
this.centerPoint = [this.params.point.lng, this.params.point.lat];
|
||||
this.handleMapClick({lnglat: {lng: this.params.point.lng, lat: this.params.point.lat}});
|
||||
} else {
|
||||
this.centerPoint = [116.404, 39.915];
|
||||
}
|
||||
|
||||
this.bindEvents();
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
this.map.on('click', (e) => this.handleMapClick(e));
|
||||
|
||||
// 监听父页面消息
|
||||
window.addEventListener('message', (event) => {
|
||||
if (event.data.action === 'update_radius') {
|
||||
const newRadius = parseInt(event.data.radius);
|
||||
if (newRadius && newRadius >= 50 && newRadius <= 5000) {
|
||||
this.params.radius = newRadius;
|
||||
if (this.circle) {
|
||||
this.updateMarkerAndCircle();
|
||||
this.updateInfoPanel();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
handleMapClick(e) {
|
||||
this.centerPoint = [e.lnglat.lng, e.lnglat.lat];
|
||||
|
||||
if (this.isFirstClick) {
|
||||
this.createMarkerAndCircle();
|
||||
this.isFirstClick = false;
|
||||
} else {
|
||||
this.params.radius = this.circle.getRadius();
|
||||
this.updateMarkerAndCircle();
|
||||
}
|
||||
|
||||
this.updateInfoPanel();
|
||||
}
|
||||
|
||||
createMarkerAndCircle() {
|
||||
this.createMarker();
|
||||
this.createCircle();
|
||||
}
|
||||
|
||||
createMarker() {
|
||||
if (this.marker) {
|
||||
this.map.remove(this.marker);
|
||||
}
|
||||
this.marker = new AMap.Marker({
|
||||
position: this.centerPoint,
|
||||
map: this.map
|
||||
});
|
||||
}
|
||||
|
||||
createCircle() {
|
||||
if (this.circle) {
|
||||
this.map.remove(this.circle);
|
||||
}
|
||||
this.circle = new AMap.Circle({
|
||||
center: this.centerPoint,
|
||||
radius: this.params.radius,
|
||||
strokeColor: "#FF0000",
|
||||
strokeWeight: 2,
|
||||
strokeOpacity: 0.5,
|
||||
fillColor: "#FF0000",
|
||||
fillOpacity: 0.2,
|
||||
map: this.map
|
||||
});
|
||||
}
|
||||
|
||||
updateMarkerAndCircle() {
|
||||
if (this.marker) {
|
||||
this.map.remove(this.marker);
|
||||
}
|
||||
if (this.circle) {
|
||||
this.map.remove(this.circle);
|
||||
}
|
||||
|
||||
this.createMarker();
|
||||
this.createCircle();
|
||||
}
|
||||
|
||||
updateInfoPanel() {
|
||||
const currentRadius = this.circle ? this.circle.getRadius().toFixed(0) : this.params.radius.toString();
|
||||
const data = {
|
||||
longitude: this.centerPoint[0].toFixed(6),
|
||||
latitude: this.centerPoint[1].toFixed(6),
|
||||
radius: currentRadius
|
||||
}
|
||||
|
||||
// 发送消息给父页面
|
||||
window.parent.postMessage(Object.assign(data, {
|
||||
action: "amap_lbs_select_point",
|
||||
}), "*");
|
||||
}
|
||||
|
||||
// 获取当前选择的数据
|
||||
getData() {
|
||||
if (!this.circle) return null;
|
||||
|
||||
return {
|
||||
center: {
|
||||
lng: this.centerPoint[0],
|
||||
lat: this.centerPoint[1]
|
||||
},
|
||||
radius: this.circle.getRadius()
|
||||
};
|
||||
}
|
||||
|
||||
// 设置中心点和半径
|
||||
setData(lng, lat, radius) {
|
||||
this.centerPoint = [lng, lat];
|
||||
this.params.radius = radius || this.params.radius;
|
||||
|
||||
if (this.isFirstClick) {
|
||||
this.createMarkerAndCircle();
|
||||
this.isFirstClick = false;
|
||||
} else {
|
||||
this.updateMarkerAndCircle();
|
||||
}
|
||||
|
||||
this.updateInfoPanel();
|
||||
this.map.setCenter(this.centerPoint);
|
||||
}
|
||||
|
||||
loadMapScript() {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 如果已经加载过,直接返回
|
||||
if (window.AMap) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建script标签
|
||||
const script = document.createElement('script');
|
||||
script.type = 'text/javascript';
|
||||
script.src = `https://webapi.amap.com/maps?v=1.4.15&key=${this.params.key}&callback=initAmapMap`;
|
||||
|
||||
// 添加回调函数
|
||||
window.initAmapMap = () => {
|
||||
resolve();
|
||||
delete window.initAmapMap;
|
||||
};
|
||||
|
||||
// 处理加载错误
|
||||
script.onerror = () => {
|
||||
reject(new Error('高德地图脚本加载失败'));
|
||||
};
|
||||
|
||||
// 添加到页面
|
||||
document.body.appendChild(script);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载完成后初始化
|
||||
window.onload = function () {
|
||||
window.pickup = new AmapPickup("map-container");
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="map-container"></div>
|
||||
</body>
|
||||
</html>
|
||||
@ -29,6 +29,8 @@
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
<script>
|
||||
class Pickup {
|
||||
@ -133,6 +135,20 @@
|
||||
|
||||
bindEvents() {
|
||||
this.map.addEventListener("click", (e) => this.handleMapClick(e));
|
||||
|
||||
// 监听父页面消息
|
||||
window.addEventListener('message', (event) => {
|
||||
if (event.data.action === 'update_radius') {
|
||||
const newRadius = parseInt(event.data.radius);
|
||||
if (newRadius && newRadius >= 50 && newRadius <= 5000) {
|
||||
this.params.radius = newRadius;
|
||||
if (this.circle) {
|
||||
this.updateMarkerAndCircle();
|
||||
this.updateInfoPanel();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
handleMapClick(e) {
|
||||
@ -191,13 +207,16 @@
|
||||
}
|
||||
|
||||
updateInfoPanel() {
|
||||
const currentRadius = this.circle ? this.circle.getRadius().toFixed(0) : this.params.radius.toString();
|
||||
const data = {
|
||||
longitude: this.centerPoint.lng.toFixed(6),
|
||||
latitude: this.centerPoint.lat.toFixed(6),
|
||||
radius: this.circle ? this.circle.getRadius().toFixed(0) : '-'
|
||||
radius: currentRadius
|
||||
}
|
||||
|
||||
// 发送消息给父页面
|
||||
window.parent.postMessage(Object.assign(data, {
|
||||
action: "bd_lbs_select_point",
|
||||
action: "baidu_lbs_select_point",
|
||||
}), "*");
|
||||
}
|
||||
|
||||
297
resources/assets/statics/public/tools/map/select_tencent.html
Normal file
297
resources/assets/statics/public/tools/map/select_tencent.html
Normal file
@ -0,0 +1,297 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title></title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#map-container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
<script>
|
||||
class TencentPickup {
|
||||
constructor(containerId) {
|
||||
this.containerId = containerId;
|
||||
this.map = null;
|
||||
this.circle = null;
|
||||
this.marker = null;
|
||||
this.centerPoint = null;
|
||||
this.isFirstClick = true;
|
||||
this.params = {
|
||||
theme: 'light', // 主题风格,light|dark
|
||||
key: null, // 腾讯地图 API Key
|
||||
point: null, // 初始坐标,如:116.404,39.915
|
||||
radius: 300, // 圆形半径
|
||||
zoom: 16, // 地图缩放级别
|
||||
}
|
||||
this.init();
|
||||
}
|
||||
|
||||
async init() {
|
||||
// 先初始化参数
|
||||
this.initParams();
|
||||
|
||||
// 如果没有 key,直接返回
|
||||
if (!this.params.key) {
|
||||
console.error('未提供腾讯地图 API Key');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 等待地图 JS 加载完成
|
||||
await this.loadMapScript();
|
||||
// 初始化地图
|
||||
this.initMap();
|
||||
} catch (error) {
|
||||
console.error('加载腾讯地图失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
initParams() {
|
||||
// 获取当前URL的查询参数
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
|
||||
// 遍历 params 对象的所有属性
|
||||
Object.keys(this.params).forEach(key => {
|
||||
// 从 URL 参数中获取值
|
||||
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";
|
||||
}
|
||||
|
||||
// 初始化地图
|
||||
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(this.containerId, {
|
||||
center: center,
|
||||
zoom: this.params.zoom
|
||||
});
|
||||
|
||||
if (this.params.point) {
|
||||
this.centerPoint = center;
|
||||
this.handleMapClick({latLng: center});
|
||||
} else {
|
||||
this.centerPoint = center;
|
||||
}
|
||||
|
||||
this.bindEvents();
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
this.map.on('click', (e) => this.handleMapClick(e));
|
||||
|
||||
// 监听父页面消息
|
||||
window.addEventListener('message', (event) => {
|
||||
if (event.data.action === 'update_radius') {
|
||||
const newRadius = parseInt(event.data.radius);
|
||||
if (newRadius && newRadius >= 50 && newRadius <= 5000) {
|
||||
this.params.radius = newRadius;
|
||||
if (this.circle) {
|
||||
this.updateMarkerAndCircle();
|
||||
this.updateInfoPanel();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
handleMapClick(e) {
|
||||
this.centerPoint = e.latLng;
|
||||
|
||||
if (this.isFirstClick) {
|
||||
this.createMarkerAndCircle();
|
||||
this.isFirstClick = false;
|
||||
} else {
|
||||
this.updateMarkerAndCircle();
|
||||
}
|
||||
|
||||
this.updateInfoPanel();
|
||||
}
|
||||
|
||||
createMarkerAndCircle() {
|
||||
this.createMarker();
|
||||
this.createCircle();
|
||||
}
|
||||
|
||||
createMarker() {
|
||||
if (this.marker) {
|
||||
this.marker.setMap(null);
|
||||
}
|
||||
|
||||
// 使用MultiMarker,但不设置自定义样式,使用默认样式
|
||||
this.marker = new TMap.MultiMarker({
|
||||
map: this.map,
|
||||
geometries: [{
|
||||
id: 'marker1',
|
||||
position: this.centerPoint
|
||||
}]
|
||||
});
|
||||
}
|
||||
|
||||
createCircle() {
|
||||
if (this.circle) {
|
||||
this.circle.setMap(null);
|
||||
}
|
||||
|
||||
// 使用MultiCircle,但不设置自定义样式,使用默认样式
|
||||
this.circle = new TMap.MultiCircle({
|
||||
map: this.map,
|
||||
geometries: [{
|
||||
id: 'circle1',
|
||||
center: this.centerPoint,
|
||||
radius: this.params.radius
|
||||
}]
|
||||
});
|
||||
}
|
||||
|
||||
updateMarkerAndCircle() {
|
||||
if (this.marker) {
|
||||
this.marker.updateGeometries([{
|
||||
id: 'marker1',
|
||||
position: this.centerPoint
|
||||
}]);
|
||||
}
|
||||
|
||||
if (this.circle) {
|
||||
this.circle.updateGeometries([{
|
||||
id: 'circle1',
|
||||
center: this.centerPoint,
|
||||
radius: this.params.radius
|
||||
}]);
|
||||
}
|
||||
}
|
||||
|
||||
updateInfoPanel() {
|
||||
const data = {
|
||||
longitude: this.centerPoint.lng.toFixed(6),
|
||||
latitude: this.centerPoint.lat.toFixed(6),
|
||||
radius: this.params.radius.toString()
|
||||
}
|
||||
|
||||
// 发送消息给父页面
|
||||
window.parent.postMessage(Object.assign(data, {
|
||||
action: "tencent_lbs_select_point",
|
||||
}), "*");
|
||||
}
|
||||
|
||||
// 获取当前选择的数据
|
||||
getData() {
|
||||
if (!this.circle) return null;
|
||||
|
||||
return {
|
||||
center: {
|
||||
lng: this.centerPoint.lng,
|
||||
lat: this.centerPoint.lat
|
||||
},
|
||||
radius: this.params.radius
|
||||
};
|
||||
}
|
||||
|
||||
// 设置中心点和半径
|
||||
setData(lng, lat, radius) {
|
||||
this.centerPoint = new TMap.LatLng(lat, lng);
|
||||
this.params.radius = radius || this.params.radius;
|
||||
|
||||
if (this.isFirstClick) {
|
||||
this.createMarkerAndCircle();
|
||||
this.isFirstClick = false;
|
||||
} else {
|
||||
this.updateMarkerAndCircle();
|
||||
}
|
||||
|
||||
this.updateInfoPanel();
|
||||
this.map.setCenter(this.centerPoint);
|
||||
}
|
||||
|
||||
loadMapScript() {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 如果已经加载过,直接返回
|
||||
if (window.TMap) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建script标签
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载完成后初始化
|
||||
window.onload = function () {
|
||||
window.pickup = new TencentPickup("map-container");
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="map-container"></div>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
x
Reference in New Issue
Block a user