Procházet zdrojové kódy

feat(atl-map): 新增腾讯地图组件

HMY před 1 rokem
rodič
revize
264a25d047

+ 19 - 11
pages/mine/test/test.vue

@@ -17,9 +17,19 @@
 				<text class="time">{{ signOutTime ||'未打卡'}}</text>
 			</view>
 		</view>
-		<map id="myMap" class="map" :latitude="latitude" :longitude="longitude" :markers="covers">
-		</map>
+		<!-- <map id="myMap" class="map" :latitude="latitude" :longitude="longitude" :markers="covers"> -->
+		<!-- </map> -->
 		<!-- <map id="myMap" class="map" :longitude="longitude" :latitude="latitude" show-location></map> -->
+		<atl-map :mapKey="mapKey" :mapType="mapType">
+		            <template v-slot:content>
+		                <view style="position: absolute; bottom: 0; width: 100%; height: 24px; background-color: white">
+		                    <view style="display: flex; align-items: center; justify-content: center">
+		                        <image style="width: 24px; height: 24px" :src="imageSrc"></image>
+		                        <text>内容插槽</text>
+		                    </view>
+		                </view>
+		            </template>
+		        </atl-map>
 		<view class="footer">
 			<button type="primary" @click="signIn">上班签到</button>
 			<button type="default" @click="signOut">下班签退</button>
@@ -28,19 +38,17 @@
 </template>
 
 
-<script setup>
-	import {
-		onMounted,
-		reactive,
-		ref
-	} from 'vue';
+<script setup lang="ts">
+	import { onMounted, reactive, ref } from 'vue';
 
 	import goToWorkImg from "/static/images/mine/goToWork.png";
 	import afterWorkImg from "/static/images/mine/afterWork.png";
 	import locationImg from "/static/images/mine/location.png";
-import UniMap from '@/uni_modules/uni-map-common';
-
-
+	// const UniMap = require('@/uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common');
+    const disable=ref(true);
+	const show=ref(true);
+	const mapKey=ref('KJBBZ-5JCLZ-3NLXD-742CK-Y26UZ-X7BJN');
+	const mapType=ref('tmap');
 	const currentDate = ref('2023-04-01');
 	const currentDay = ref('星期三');
 	const clockInStatus = ref('');

+ 36 - 0
uni_modules/atl-map/changelog.md

@@ -0,0 +1,36 @@
+## 1.4.7(2024-09-20)
+fix: 修复点击poi点位,导致tap事件失效问题
+## 1.4.6(2024-09-01)
+update: 更新readme,添加地区经纬度生成小工具链接
+## 1.4.5(2024-03-08)
+fix: 修复top属性类型定于错误导致vue3编译异常情况
+ps: 感谢社区成员的提问以及解决方案 https://ask.dcloud.net.cn/question/187245
+## 1.4.4(2024-03-02)
+fix: 修复高德地图顶部操作栏层级问题
+## 1.4.3(2024-03-02)
+fix: 修复 自定义顶部栏时,地图顶部高度自适应问题
+## 1.4.2(2023-12-29)
+update: 更新readme  添加电子围栏demo
+## 1.4.1(2023-12-29)
+update: 更新文档
+## 1.4.0(2023-12-29)
+update: 更新地图电子围栏 添加案例
+## 1.3.1(2023-11-17)
+fix: 修复vue3微信小程序导入地图SDK报错问题
+update: 更新readme文档
+## 1.3.0(2023-11-12)
+update: 新增内容插槽,支持自定义内容,更新使用案例
+## 1.2.0(2023-11-05)
+update: 更新文档,新增pre-commit自动同步readme
+## 1.1.0(2023-10-31)
+update: 支持百度地图,代码优化,更新文档
+## 1.0.4(2023-10-28)
+update: 更新文档
+## 1.0.3(2023-10-28)
+fix: 修复文档图片预览问题
+## 1.0.2(2023-10-28)
+fix: 修复文档部分问题
+## 1.0.1(2023-10-28)
+fix: 修改插件名字,修复插件启动报错问题
+## 1.0.0(2023-10-28)
+feat: 完成微信小程序高德/腾讯地图插件封装,添加readme文档

+ 827 - 0
uni_modules/atl-map/components/amap/amap.vue

@@ -0,0 +1,827 @@
+<template>
+	<view class="map-content" :style="[
+			isCustomBar && {
+				height: customBarH + 'px',
+				paddingTop: statusBarH + 'px',
+				backgroundColor: 'transparent',
+				top: top + 'px',
+			},
+		]">
+		<view class="top">
+			<view class="cancel" @click="close">取消</view>
+			<view class="address-text">
+				{{ addressMap || '' }}
+			</view>
+			<view class="confirm" @click="submit"
+				:style="{ backgroundColor: disable ? 'rgba(0, 0, 0, 0.2)' : '#42b983' }">确定</view>
+		</view>
+		<map class="map" id="map" :latitude="lat" :longitude="long" scale="18" show-location :markers="markers"
+			@tap="getCurrentLocation" :polygons="isPolygons?polygons:[]" enable-poi @poitap="poitap">
+			<cover-view>
+				<slot name="content"></slot>
+			</cover-view>
+		</map>
+		<view class="search">
+			<view class="search-input">
+				<input placeholder="请输入关键词" v-model="searchValue" type="text" maxlength="64" @input="searchMap" />
+			</view>
+		</view>
+		<view class="bot-box">
+			<view class="poi-list">
+				<view class="poi-item" v-for="item in searchList" :key="item.id"
+					@click="getCurrentSingleLocation(item)">
+					<view v-if="searchList.length !== 0">
+						<view class="poi-name">
+							{{ item.name }}
+						</view>
+						<view class="poi-address">
+							<view class="address">{{ item.address }}</view>
+						</view>
+					</view>
+				</view>
+				<view class="empty" v-if="searchList.length == 0">暂无数据, 请更检查key是否有效或者更换关键词</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	// vue3 导入sdk不兼容 所以直接将sdk写入这个文件
+	function AMapWX(a) {
+		this.key = a.key
+		this.requestConfig = {
+			key: a.key,
+			s: "rsx",
+			platform: "WXJS",
+			appname: a.key,
+			sdkversion: "1.2.0",
+			logversion: "2.0"
+		}
+	}
+	AMapWX.prototype.getWxLocation = function(a, b) {
+		uni.getLocation({
+			type: "gcj02",
+			success: function(a) {
+				var c = a.longitude + "," + a.latitude;
+				uni.setStorage({
+					key: "userLocation",
+					data: c
+				}), b(c)
+			},
+			fail: function(c) {
+				uni.getStorage({
+					key: "userLocation",
+					success: function(a) {
+						a.data && b(a.data)
+					}
+				})
+			}
+		})
+	}
+	AMapWX.prototype.getRegeo = function(a) {
+		function c(c) {
+			var d = b.requestConfig;
+			uni.request({
+				url: "https://restapi.amap.com/v3/geocode/regeo",
+				data: {
+					key: b.key,
+					location: c,
+					extensions: "all",
+					s: d.s,
+					platform: d.platform,
+					appname: b.key,
+					sdkversion: d.sdkversion,
+					logversion: d.logversion
+				},
+				method: "GET",
+				header: {
+					"content-type": "application/json"
+				},
+				success: function(b) {
+					var d, e, f, g, h, i, j, k, l;
+					b.data.status && "1" == b.data.status ? (d = b.data.regeocode,
+						e = d.addressComponent, f = [], g = "", d && d.roads[
+							0] && d.roads[0].name && (g = d.roads[0].name + "附近"), h =
+						c.split(",")[0], i = c.split(",")[1], d.pois && d
+						.pois[0] && (g = d.pois[0].name + "附近", j = d.pois[0]
+							.location, j && (h = parseFloat(j.split(",")[0]), i =
+								parseFloat(j.split(",")[1]))), e.provice && f.push(e
+							.provice), e.city && f.push(e.city), e.district && f.push(
+							e.district), e.streetNumber && e.streetNumber.street && e
+						.streetNumber.number ? (f.push(e.streetNumber.street),
+							f.push(e.streetNumber.number)) : (k = "", d && d.roads[
+							0] && d.roads[0].name && (k = d.roads[0].name), f.push(
+							k)), f = f.join(""), l = [{
+							iconPath: a.iconPath,
+							width: a.iconWidth,
+							height: a.iconHeight,
+							name: f,
+							desc: g,
+							longitude: h,
+							latitude: i,
+							id: 0,
+							regeocodeData: d
+						}], a.success(l)) : a?.fail && a.fail({
+						errCode: b.data.infocode,
+						errMsg: b.data.info
+					})
+				},
+				fail: function(b) {
+					a.fail({
+						errCode: "0",
+						errMsg: b.errMsg || ""
+					})
+				}
+			})
+		}
+		var b = this;
+		a.location ? c(a.location) : b.getWxLocation(a, function(a) {
+			c(a)
+		})
+	}
+	AMapWX.prototype.getWeather = function(a) {
+		function d(d) {
+			var e = "base";
+			a.type && "forecast" == a.type && (e = "all"), uni.request({
+				url: "https://restapi.amap.com/v3/weather/weatherInfo",
+				data: {
+					key: b.key,
+					city: d,
+					extensions: e,
+					s: c.s,
+					platform: c.platform,
+					appname: b.key,
+					sdkversion: c.sdkversion,
+					logversion: c.logversion
+				},
+				method: "GET",
+				header: {
+					"content-type": "application/json"
+				},
+				success: function(b) {
+					function c(a) {
+						var b = {
+							city: {
+								text: "城市",
+								data: a.city
+							},
+							weather: {
+								text: "天气",
+								data: a.weather
+							},
+							temperature: {
+								text: "温度",
+								data: a.temperature
+							},
+							winddirection: {
+								text: "风向",
+								data: a.winddirection + "风"
+							},
+							windpower: {
+								text: "风力",
+								data: a.windpower + "级"
+							},
+							humidity: {
+								text: "湿度",
+								data: a.humidity + "%"
+							}
+						};
+						return b
+					}
+					var d, e;
+					b.data.status && "1" == b.data.status ? b.data.lives ? (d = b
+							.data.lives, d && d.length > 0 && (d = d[0], e = c(
+								d), e["liveData"] = d, a.success(e))) : b.data
+						.forecasts && b.data.forecasts[0] && a.success({
+							forecast: b.data.forecasts[0]
+						}) : a.fail({
+							errCode: b.data.infocode,
+							errMsg: b.data.info
+						})
+				},
+				fail: function(b) {
+					a.fail({
+						errCode: "0",
+						errMsg: b.errMsg || ""
+					})
+				}
+			})
+		}
+
+		function e(e) {
+			uni.request({
+				url: "https://restapi.amap.com/v3/geocode/regeo",
+				data: {
+					key: b.key,
+					location: e,
+					extensions: "all",
+					s: c.s,
+					platform: c.platform,
+					appname: b.key,
+					sdkversion: c.sdkversion,
+					logversion: c.logversion
+				},
+				method: "GET",
+				header: {
+					"content-type": "application/json"
+				},
+				success: function(b) {
+					var c, e;
+					b.data.status && "1" == b.data.status ? (e = b.data.regeocode, e
+						.addressComponent ? c = e.addressComponent.adcode :
+						e.aois && e.aois.length > 0 && (c = e.aois[0].adcode), d(c)
+					) : a.fail({
+						errCode: b.data.infocode,
+						errMsg: b.data.info
+					})
+				},
+				fail: function(b) {
+					a.fail({
+						errCode: "0",
+						errMsg: b.errMsg || ""
+					})
+				}
+			})
+		}
+		var b = this,
+			c = b.requestConfig;
+		a.city ? d(a.city) : b.getWxLocation(a, function(a) {
+			e(a)
+		})
+	}
+	AMapWX.prototype.getPoiAround = function(a) {
+		function d(d) {
+			var e = {
+				key: b.key,
+				location: d,
+				s: c.s,
+				platform: c.platform,
+				appname: b.key,
+				sdkversion: c.sdkversion,
+				logversion: c.logversion
+			};
+			a.querytypes && (e["types"] = a.querytypes), a.querykeywords && (e[
+				"keywords"] = a.querykeywords), uni.request({
+				url: "https://restapi.amap.com/v3/place/around",
+				data: e,
+				method: "GET",
+				header: {
+					"content-type": "application/json"
+				},
+				success: function(b) {
+					var c, d, e, f;
+					if (b.data.status && "1" == b.data.status) {
+						if (b = b.data, b && b.pois) {
+							for (c = [], d = 0; d < b.pois.length; d++) e = 0 == d ? a
+								.iconPathSelected : a.iconPath, c.push({
+									latitude: parseFloat(b.pois[d].location.split(",")[
+										1]),
+									longitude: parseFloat(b.pois[d].location.split(",")[
+										0]),
+									iconPath: e,
+									width: 22,
+									height: 32,
+									id: d,
+									name: b.pois[d].name,
+									address: b.pois[d].address
+								});
+							f = {
+								markers: c,
+								poisData: b.pois
+							}, a.success(f)
+						}
+					} else a.fail({
+						errCode: b.data.infocode,
+						errMsg: b.data.info
+					})
+				},
+				fail: function(b) {
+					a.fail({
+						errCode: "0",
+						errMsg: b.errMsg || ""
+					})
+				}
+			})
+		}
+		var b = this,
+			c = b.requestConfig;
+		a.location ? d(a.location) : b.getWxLocation(a, function(a) {
+			d(a)
+		})
+	}
+	AMapWX.prototype.getStaticmap = function(a) {
+		function f(b) {
+			c.push("location=" + b), a.zoom && c.push("zoom=" + a.zoom), a.size && c
+				.push("size=" + a.size), a.scale && c.push(
+					"scale=" + a.scale), a.markers && c.push("markers=" + a.markers), a
+				.labels && c.push("labels=" + a.labels), a.paths &&
+				c.push("paths=" + a.paths), a.traffic && c.push("traffic=" + a.traffic);
+			var e = d + c.join("&");
+			a.success({
+				url: e
+			})
+		}
+		var e, b = this,
+			c = [],
+			d = "https://restapi.amap.com/v3/staticmap?";
+		c.push("key=" + b.key), e = b.requestConfig, c.push("s=" + e.s), c.push(
+				"platform=" + e.platform), c.push("appname=" +
+				e.appname), c.push("sdkversion=" + e.sdkversion), c.push("logversion=" +
+				e.logversion), a.location ? f(a.location) :
+			b.getWxLocation(a, function(a) {
+				f(a)
+			})
+	}
+	AMapWX.prototype.getInputtips = function(a) {
+		var b = this,
+			c = b.requestConfig,
+			d = {
+				key: b.key,
+				s: c.s,
+				platform: c.platform,
+				appname: b.key,
+				sdkversion: c.sdkversion,
+				logversion: c.logversion
+			};
+		a.location && (d["location"] = a.location), a.keywords && (d["keywords"] = a
+				.keywords), a.type && (d["type"] = a.type),
+			a.city && (d["city"] = a.city), a.citylimit && (d["citylimit"] = a
+				.citylimit), uni.request({
+				url: "https://restapi.amap.com/v3/assistant/inputtips",
+				data: d,
+				method: "GET",
+				header: {
+					"content-type": "application/json"
+				},
+				success: function(b) {
+					b && b.data && b.data.tips && a.success({
+						tips: b.data.tips
+					})
+				},
+				fail: function(b) {
+					a.fail({
+						errCode: "0",
+						errMsg: b.errMsg || ""
+					})
+				}
+			})
+	}
+	AMapWX.prototype.getDrivingRoute = function(a) {
+		var b = this,
+			c = b.requestConfig,
+			d = {
+				key: b.key,
+				s: c.s,
+				platform: c.platform,
+				appname: b.key,
+				sdkversion: c.sdkversion,
+				logversion: c.logversion
+			};
+		a.origin && (d["origin"] = a.origin),
+			a.destination && (d["destination"] = a.destination),
+			a.strategy && (d["strategy"] = a.strategy),
+			a.waypoints && (d["waypoints"] = a.waypoints),
+			a.avoidpolygons && (d["avoidpolygons"] = a.avoidpolygons),
+			a.avoidroad && (d["avoidroad"] = a.avoidroad),
+			uni.request({
+				url: "https://restapi.amap.com/v3/direction/driving",
+				data: d,
+				method: "GET",
+				header: {
+					"content-type": "application/json"
+				},
+				success: function(b) {
+					b && b.data && b.data.route && a.success({
+						paths: b.data.route.paths,
+						taxi_cost: b.data.route.taxi_cost || ""
+					})
+				},
+				fail: function(b) {
+					a.fail({
+						errCode: "0",
+						errMsg: b.errMsg || ""
+					})
+				}
+			})
+	}
+	AMapWX.prototype.getWalkingRoute = function(a) {
+		var b = this,
+			c = b.requestConfig,
+			d = {
+				key: b.key,
+				s: c.s,
+				platform: c.platform,
+				appname: b.key,
+				sdkversion: c.sdkversion,
+				logversion: c.logversion
+			};
+		a.origin && (d["origin"] = a.origin), a.destination && (d["destination"] = a
+			.destination), uni.request({
+			url: "https://restapi.amap.com/v3/direction/walking",
+			data: d,
+			method: "GET",
+			header: {
+				"content-type": "application/json"
+			},
+			success: function(b) {
+				b && b.data && b.data.route && a.success({
+					paths: b.data.route.paths
+				})
+			},
+			fail: function(b) {
+				a.fail({
+					errCode: "0",
+					errMsg: b.errMsg || ""
+				})
+			}
+		})
+	}
+	AMapWX.prototype.getTransitRoute = function(a) {
+		var b = this,
+			c = b.requestConfig,
+			d = {
+				key: b.key,
+				s: c.s,
+				platform: c.platform,
+				appname: b.key,
+				sdkversion: c.sdkversion,
+				logversion: c.logversion
+			};
+		a.origin && (d["origin"] = a.origin), a.destination && (d["destination"] = a
+			.destination), a.strategy && (d[
+			"strategy"] = a.strategy), a.city && (d["city"] = a.city), a.cityd && (
+			d["cityd"] = a.cityd), uni.request({
+			url: "https://restapi.amap.com/v3/direction/transit/integrated",
+			data: d,
+			method: "GET",
+			header: {
+				"content-type": "application/json"
+			},
+			success: function(b) {
+				if (b && b.data && b.data.route) {
+					var c = b.data.route;
+					a.success({
+						distance: c.distance || "",
+						taxi_cost: c.taxi_cost || "",
+						transits: c.transits
+					})
+				}
+			},
+			fail: function(b) {
+				a.fail({
+					errCode: "0",
+					errMsg: b.errMsg || ""
+				})
+			}
+		})
+	}
+	AMapWX.prototype.getRidingRoute = function(a) {
+		var b = this,
+			c = b.requestConfig,
+			d = {
+				key: b.key,
+				s: c.s,
+				platform: c.platform,
+				appname: b.key,
+				sdkversion: c.sdkversion,
+				logversion: c.logversion
+			};
+		a.origin && (d["origin"] = a.origin), a.destination && (d["destination"] = a
+			.destination), uni.request({
+			url: "https://restapi.amap.com/v4/direction/bicycling",
+			data: d,
+			method: "GET",
+			header: {
+				"content-type": "application/json"
+			},
+			success: function(b) {
+				b && b.data && b.data.data && a.success({
+					paths: b.data.data.paths
+				})
+			},
+			fail: function(b) {
+				a.fail({
+					errCode: "0",
+					errMsg: b.errMsg || ""
+				})
+			}
+		})
+	}
+
+	export default {
+		name: 'amap',
+		props: {
+			longitude: {
+				type: String,
+				default: ''
+			},
+			latitude: {
+				type: String,
+				default: ''
+			},
+			mapKey: {
+				require: true,
+				type: String,
+				default: ''
+			},
+			marker: {
+				type: Object,
+				default: () => {}
+			},
+			disable: {
+				type: Boolean,
+				default: false
+			},
+			isPolygons: {
+				type: Boolean,
+				default: false
+			},
+			polygons: {
+				type: Array,
+				default: () => []
+			},
+			top: {
+				type: [String, Number],
+				default: 30
+			},
+			isCustomBar: {
+				type: Boolean,
+				default: false
+			}
+		},
+		data() {
+			return {
+				statusBarH: 0,
+				customBarH: 0,
+				addressMap: '',
+				searchValue: '',
+				markers: [],
+				amapPlugin: null,
+				key: this.$props?.mapKey, //高德地图key https://console.amap.com/dev/key/app 服务平台选择微信小程序
+				lat: this.$props?.latitude,
+				long: this.$props?.longitude,
+				regeocodeData: {},
+				searchList: []
+			};
+		},
+		created() {
+			this.init();
+			let self = this
+			uni.getSystemInfo({
+				success: function(e) {
+					self.statusBarH = e.statusBarHeight + 5
+					if (uni.getMenuButtonBoundingClientRect?.()) {
+						let custom = uni.getMenuButtonBoundingClientRect()
+						self.customBarH = custom.height + 5
+					} else {
+						self.customBarH = 30
+					}
+				},
+			})
+		},
+		methods: {
+			changeMarkers() {
+				this.markers[0] = {
+					...this.$props?.marker,
+					longitude: this.long,
+					latitude: this.lat
+				};
+			},
+			init() {
+				this.amapPlugin = new AMapWX({
+					key: this.key
+				});
+				const detail = {
+					longitude: this.$props?.longitude,
+					latitude: this.$props?.latitude
+				};
+
+				if (!detail.latitude || !detail.longitude) {
+					const _this = this;
+					uni.getLocation({
+						type: 'gcj02',
+						isHighAccuracy: true,
+						success: (data) => {
+							detail.latitude = data.latitude;
+							detail.longitude = data.longitude;
+							_this.getCurrentLocation({
+								detail
+							});
+						}
+					});
+				} else {
+					this.getCurrentLocation({
+						detail
+					});
+				}
+			},
+			poitap(e) {
+				this.getCurrentLocation(e)
+			},
+			//点击地图
+			getCurrentLocation(e) {
+				this.searchValue = '';
+				const {
+					latitude,
+					longitude
+				} = e.detail;
+				if (!latitude || !longitude) return;
+				this.getRegeo([longitude, latitude], (pois) => {
+					this.searchList = pois;
+				})
+			},
+			getInputtips() {
+				this.amapPlugin.getInputtips({
+					key: this.key,
+					keywords: this.searchValue,
+					location: this.long + ',' + this.lat,
+					success: (data) => {
+						this.searchList = data.tips.filter((i) => i?.id?.length && i?.location);
+					}
+				});
+			},
+			getRegeo(coordinate, fn) {
+				this.lat = coordinate[1];
+				this.long = coordinate[0];
+				this.changeMarkers();
+				this.amapPlugin.getRegeo({
+					location: this.long + ',' + this.lat,
+					success: (data) => {
+						const {
+							regeocodeData
+						} = data[0];
+						this.addressMap = regeocodeData.formatted_address;
+						this.regeocodeData = regeocodeData;
+						this.$emit('changeMarker', this.getConfirmData());
+						fn && fn(regeocodeData.pois);
+					}
+				});
+			},
+			//搜索关键字
+			searchMap() {
+				this.getInputtips();
+			},
+			getCurrentSingleLocation(data) {
+				let coordinate = data.location.split(',');
+				this.searchValue = data.name;
+				this.getRegeo(coordinate);
+			},
+			close() {
+				this.$emit('confirm');
+			},
+			getConfirmData() {
+				const {
+					pois,
+					addressComponent: {
+						province,
+						district,
+						township
+					}
+				} = this.regeocodeData;
+				const title = pois?.[0]?.name || province + district + township;
+				return {
+					...this.regeocodeData,
+					title,
+					latitude: this.lat,
+					longitude: this.long,
+					address: this.addressMap
+				}
+
+			},
+			submit(e) {
+				if (this.$props.disable) {
+					return;
+				}
+				if (!this.addressMap) {
+					return;
+				}
+				if (JSON.stringify(this.regeocodeData) != '{}') {
+					this.$emit('confirm', this.getConfirmData());
+				}
+			}
+		}
+	};
+</script>
+<style lang="scss" scoped>
+	.map-content {
+		position: fixed;
+		top: 0;
+		left: 0;
+		bottom: 0;
+		right: 0;
+		z-index: 99;
+		background-color: #fff;
+
+		.top {
+			position: absolute;
+			width: 100%;
+			height: 80rpx;
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			padding: 10rpx 40rpx;
+			box-sizing: border-box;
+			background-color: rgba(0, 0, 0, 0.2);
+			color: #fff;
+			z-index: 999;
+
+			.confirm {
+				height: 60rpx;
+				line-height: 60rpx;
+				padding: 0 20rpx;
+				border-radius: 10rpx;
+				background-color: #42b983;
+			}
+
+			.address-text {
+				width: 55vw;
+				text-align: center;
+				overflow: hidden;
+				word-wrap: break-word;
+				display: -webkit-box;
+				-webkit-line-clamp: 1;
+				-webkit-box-orient: vertical;
+			}
+		}
+
+		.map {
+			position: relative;
+			width: 100vw;
+			height: 50vh;
+
+			.position-icon {
+				position: absolute;
+				left: 50%;
+				top: 50%;
+				width: 50px;
+				height: 40px;
+				margin-top: -12px;
+				transform: translate(-50%, -50%);
+			}
+		}
+
+		.search {
+			padding: 10rpx 20rpx;
+			display: flex;
+			justify-content: center;
+			background-color: #fff;
+
+			input {
+				flex: 1;
+				width: calc(100vw - 80rpx);
+				padding: 0 20rpx;
+				height: 60rpx;
+				border: 1px solid #ccc;
+				border-radius: 10rpx;
+			}
+		}
+
+		.bot-box {
+
+			height: calc(50vh - 50px);
+			overflow: auto;
+			width: 100vw;
+			background-color: #fff;
+
+			.empty {
+				margin-top: 40rpx;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+			}
+
+			.poi-list {
+				// padding: 0 $uni-spacing-row-base;
+				box-sizing: border-box;
+
+				.poi-item {
+					margin: 20rpx 0;
+					padding: 10rpx;
+					// border: 1px solid $uni-border-color;
+					// border-radius: $uni-border-radius-base;
+
+					.poi-name {
+						font-size: 34rpx;
+						color: #333;
+					}
+
+					.poi-address {
+						.address {
+							width: 100%;
+							font-size: 26rpx;
+							overflow: hidden;
+							color: #999;
+							white-space: nowrap;
+							text-overflow: ellipsis;
+						}
+					}
+				}
+
+				.poi-item:active {
+					color: #fff;
+					border: 1px solid #42b983;
+				}
+			}
+		}
+	}
+</style>

+ 93 - 0
uni_modules/atl-map/components/atl-map/atl-map.vue

@@ -0,0 +1,93 @@
+<template>
+	<view>
+
+		<amap v-if="mapType === 'amap'" :disable="disable" :longitude="longitude" :latitude="latitude" :mapKey="mapKey"
+			:marker="marker" @confirm="confirm" @changeMarker="changeMarker" :polygons="polygons"
+			:isPolygons="isPolygons" :isCustomBar="isCustomBar" :top='top'>
+			<template v-slot:content>
+				<slot name="content"></slot>
+			</template>
+		</amap>
+		<tmap v-else :disable="disable" :longitude="longitude" :latitude="latitude" :mapKey="mapKey" :marker="marker"
+			@confirm="confirm" @changeMarker="changeMarker" :polygons="polygons" :isPolygons="isPolygons"
+			:isCustomBar="isCustomBar" :top='top'>
+			<template v-slot:content>
+				<slot name="content"></slot>
+			</template>
+		</tmap>
+	</view>
+</template>
+
+<script>
+	import amap from '../amap/amap.vue';
+	import tmap from '../tmap/tmap.vue';
+	// import bmap from '../bmap/bmap.vue';
+
+	export default {
+		name: 'atl-map',
+		props: {
+			longitude: {
+				type: String,
+				default: ''
+			},
+			latitude: {
+				type: String,
+				default: ''
+			},
+			mapKey: {
+				require: true,
+				type: String,
+				default: ''
+			},
+			marker: {
+				type: Object,
+				default: () => {}
+			},
+			mapType: {
+				type: String,
+				default: 'tmap'
+			},
+			disable: {
+				type: Boolean,
+				default: false
+			},
+			isPolygons: {
+				type: Boolean,
+				default: false
+			},
+			polygons: {
+				type: Array,
+				default: () => []
+			},
+			top: {
+				type: [String, Number],
+				default: 30
+			},
+			isCustomBar: {
+				type: Boolean,
+				default: false
+			}
+		},
+		components: {
+			amap,
+			tmap,
+			// bmap
+		},
+		data() {
+			return {};
+		},
+		created() {
+			// console.log(11, this.$props);
+		},
+		methods: {
+			confirm(e) {
+				this.$emit('confirm', e);
+			},
+			changeMarker(e) {
+				this.$emit('changeMarker', e);
+			}
+		}
+	};
+</script>
+
+<style lang="scss" scoped></style>

+ 814 - 0
uni_modules/atl-map/components/bmap/bmap.vue

@@ -0,0 +1,814 @@
+<template>
+	<view class="map-content" :style="[
+			isCustomBar && {
+				height: customBarH + 'px',
+				paddingTop: statusBarH + 'px',
+				backgroundColor: 'transparent',
+				top: top + 'px',
+			},
+		]">
+		<view class="top">
+			<view class="cancel" @click="close">取消</view>
+			<view class="address-text">
+				{{ addressMap || '' }}
+			</view>
+			<view class="confirm" @click="submit"
+				:style="{ backgroundColor: disable ? 'rgba(0, 0, 0, 0.2)' : '#42b983' }">确定</view>
+		</view>
+		<map class="map" id="map" :latitude="lat" :longitude="long" scale="18" show-location :markers="markers"
+			@tap="getCurrentLocation" :polygons="isPolygons?polygons:[]" enable-poi @poitap="poitap">
+			<cover-view>
+				<slot name="content"></slot>
+			</cover-view>
+		</map>
+		<view class="search">
+			<view class="search-input">
+				<input placeholder="请输入关键词" v-model="searchValue" type="text" maxlength="64" @input="searchMap" />
+			</view>
+		</view>
+		<view class="bot-box">
+			<view class="poi-list">
+				<view class="poi-item" v-for="item in searchList" :key="item.uid"
+					@click="getCurrentSingleLocation(item)">
+					<view v-if="searchList.length !== 0">
+						<view class="poi-name">
+							{{ item.name }}
+						</view>
+						<view class="poi-address">
+							<view class="address">{{ item.address || item.addr }}</view>
+						</view>
+					</view>
+				</view>
+				<view class="empty" v-if="searchList.length == 0">暂无数据, 请更检查key是否有效或者更换关键词</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	// import * as bmap from './bmap-wx.js';
+	class BMapWX {
+
+		/**
+		 * 百度地图微信小程序API类
+		 *
+		 * @constructor
+		 */
+		constructor(param) {
+			this.ak = param["ak"];
+		}
+
+		/**
+		 * 使用微信接口进行定位
+		 *
+		 * @param {string} type 坐标类型
+		 * @param {Function} success 成功执行
+		 * @param {Function} fail 失败执行
+		 * @param {Function} complete 完成后执行
+		 */
+		getWXLocation(type, success, fail, complete) {
+			type = type || 'gcj02',
+				success = success || function() {};
+			fail = fail || function() {};
+			complete = complete || function() {};
+			wx.getLocation({
+				type: type,
+				success: success,
+				fail: fail,
+				complete: complete
+			});
+		}
+
+		/**
+		 * POI周边检索
+		 *
+		 * @param {Object} param 检索配置
+		 * 参数对象结构可以参考
+		 * http://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-placeapi
+		 */
+		search(param) {
+			var that = this;
+			param = param || {};
+			let searchparam = {
+				query: param["query"] || '生活服务$美食&酒店',
+				scope: param["scope"] || 1,
+				filter: param["filter"] || '',
+				coord_type: param["coord_type"] || 2,
+				page_size: param["page_size"] || 10,
+				page_num: param["page_num"] || 0,
+				output: param["output"] || 'json',
+				ak: that.ak,
+				sn: param["sn"] || '',
+				timestamp: param["timestamp"] || '',
+				radius: param["radius"] || 2000,
+				ret_coordtype: 'gcj02ll'
+			};
+			let otherparam = {
+				iconPath: param["iconPath"],
+				iconTapPath: param["iconTapPath"],
+				width: param["width"],
+				height: param["height"],
+				alpha: param["alpha"] || 1,
+				success: param["success"] || function() {},
+				fail: param["fail"] || function() {}
+			};
+			let type = 'gcj02';
+			let locationsuccess = function(result) {
+				searchparam["location"] = result["latitude"] + ',' + result[
+					"longitude"];
+				wx.request({
+					url: 'https://api.map.baidu.com/place/v2/search',
+					data: searchparam,
+					header: {
+						"content-type": "application/json"
+					},
+					method: 'GET',
+					success(data) {
+						let res = data["data"];
+						if (res["status"] === 0) {
+							let poiArr = res["results"];
+							// outputRes 包含两个对象,
+							// originalData为百度接口返回的原始数据
+							// wxMarkerData为小程序规范的marker格式
+							let outputRes = {};
+							outputRes["originalData"] = res;
+							outputRes["wxMarkerData"] = [];
+							for (let i = 0; i < poiArr.length; i++) {
+								outputRes["wxMarkerData"][i] = {
+									id: i,
+									latitude: poiArr[i]["location"]["lat"],
+									longitude: poiArr[i]["location"]["lng"],
+									title: poiArr[i]["name"],
+									iconPath: otherparam["iconPath"],
+									iconTapPath: otherparam["iconTapPath"],
+									address: poiArr[i]["address"],
+									telephone: poiArr[i]["telephone"],
+									alpha: otherparam["alpha"],
+									width: otherparam["width"],
+									height: otherparam["height"]
+								}
+							}
+							otherparam.success(outputRes);
+						} else {
+							otherparam.fail({
+								errMsg: res["message"],
+								statusCode: res["status"]
+							});
+						}
+					},
+					fail(data) {
+						otherparam.fail(data);
+					}
+				});
+			}
+			let locationfail = function(result) {
+				otherparam.fail(result);
+			};
+			let locationcomplete = function(result) {};
+			if (!param["location"]) {
+				that.getWXLocation(type, locationsuccess, locationfail,
+					locationcomplete);
+			} else {
+				let longitude = param.location.split(',')[1];
+				let latitude = param.location.split(',')[0];
+				let errMsg = 'input location';
+				let res = {
+					errMsg: errMsg,
+					latitude: latitude,
+					longitude: longitude
+				};
+				locationsuccess(res);
+			}
+		}
+
+		/**
+		 * sug模糊检索
+		 *
+		 * @param {Object} param 检索配置
+		 * 参数对象结构可以参考
+		 * http://lbsyun.baidu.com/index.php?title=webapi/place-suggestion-api
+		 */
+		suggestion(param) {
+			var that = this;
+			param = param || {};
+			let suggestionparam = {
+				query: param["query"] || '',
+				region: param["region"] || '全国',
+				city_limit: param["city_limit"] || false,
+				output: param["output"] || 'json',
+				ak: that.ak,
+				sn: param["sn"] || '',
+				timestamp: param["timestamp"] || '',
+				ret_coordtype: 'gcj02ll'
+			};
+			let otherparam = {
+				success: param["success"] || function() {},
+				fail: param["fail"] || function() {}
+			};
+			wx.request({
+				url: 'https://api.map.baidu.com/place/v2/suggestion',
+				data: suggestionparam,
+				header: {
+					"content-type": "application/json"
+				},
+				method: 'GET',
+				success(data) {
+					let res = data["data"];
+					if (res["status"] === 0) {
+						otherparam.success(res);
+					} else {
+						otherparam.fail({
+							errMsg: res["message"],
+							statusCode: res["status"]
+						});
+					}
+				},
+				fail(data) {
+					otherparam.fail(data);
+				}
+			});
+		}
+
+		/**
+		 * rgc检索(逆地理编码:经纬度->地点描述)
+		 * 
+		 * @param {Object} param 检索配置
+		 * 参数对象结构可以参考
+		 * https://lbs.baidu.com/index.php?title=webapi/guide/webservice-geocoding-abroad
+		 * 
+		 */
+		regeocoding(param) {
+			var that = this;
+			param = param || {};
+			let regeocodingparam = {
+				coordtype: param["coordtype"] || 'gcj02ll',
+				ret_coordtype: 'gcj02ll',
+				radius: param["radius"] || 1000,
+				ak: that.ak,
+				sn: param["sn"] || '',
+				output: param["output"] || 'json',
+				callback: param["callback"] || function() {},
+				extensions_poi: param["extensions_poi"] || 1,
+				extensions_road: param["extensions_road"] || false,
+				extensions_town: param["extensions_town"] || false,
+				language: param["language"] || 'zh-CN',
+				language_auto: param["language_auto"] || 0
+			};
+			let otherparam = {
+				iconPath: param["iconPath"],
+				iconTapPath: param["iconTapPath"],
+				width: param["width"],
+				height: param["height"],
+				alpha: param["alpha"] || 1,
+				success: param["success"] || function() {},
+				fail: param["fail"] || function() {}
+			};
+			let type = 'gcj02';
+			let locationsuccess = function(result) {
+				regeocodingparam["location"] = result["latitude"] + ',' + result[
+					"longitude"];
+				wx.request({
+					url: 'https://api.map.baidu.com/reverse_geocoding/v3',
+					data: regeocodingparam,
+					header: {
+						"content-type": "application/json"
+					},
+					method: 'GET',
+					success(data) {
+						let res = data["data"];
+						if (res["status"] === 0) {
+							let poiObj = res["result"];
+							// outputRes 包含两个对象:
+							// originalData为百度接口返回的原始数据
+							// wxMarkerData为小程序规范的marker格式
+							let outputRes = {};
+							outputRes["originalData"] = res;
+							outputRes["wxMarkerData"] = [];
+							outputRes["wxMarkerData"][0] = {
+								id: 0,
+								latitude: result["latitude"],
+								longitude: result["longitude"],
+								address: poiObj["formatted_address"],
+								iconPath: otherparam["iconPath"],
+								iconTapPath: otherparam["iconTapPath"],
+								desc: poiObj["sematic_description"],
+								business: poiObj["business"],
+								alpha: otherparam["alpha"],
+								width: otherparam["width"],
+								height: otherparam["height"]
+							}
+							otherparam.success(outputRes);
+						} else {
+							otherparam.fail({
+								errMsg: res["message"],
+								statusCode: res["status"]
+							});
+						}
+					},
+					fail(data) {
+						otherparam.fail(data);
+					}
+				});
+			};
+			let locationfail = function(result) {
+				otherparam.fail(result);
+			}
+			let locationcomplete = function(result) {};
+			if (!param["location"]) {
+				that.getWXLocation(type, locationsuccess, locationfail,
+					locationcomplete);
+			} else {
+				let longitude = param.location.split(',')[1];
+				let latitude = param.location.split(',')[0];
+				let errMsg = 'input location';
+				let res = {
+					errMsg: errMsg,
+					latitude: latitude,
+					longitude: longitude
+				};
+				locationsuccess(res);
+			}
+		}
+
+		/**
+		 * gc检索(地理编码:地点->经纬度)
+		 *
+		 * @param {Object} param 检索配置
+		 * 参数对象结构可以参考
+		 * https://lbs.baidu.com/index.php?title=webapi/guide/webservice-geocoding
+		 * 
+		 */
+		geocoding(param) {
+			var that = this;
+			param = param || {};
+			let geocodingparam = {
+				address: param["address"] || '',
+				city: param["city"] || '',
+				ret_coordtype: param["coordtype"] || 'gcj02ll',
+				ak: that.ak,
+				sn: param["sn"] || '',
+				output: param["output"] || 'json',
+				callback: param["callback"] || function() {}
+			};
+			let otherparam = {
+				iconPath: param["iconPath"],
+				iconTapPath: param["iconTapPath"],
+				width: param["width"],
+				height: param["height"],
+				alpha: param["alpha"] || 1,
+				success: param["success"] || function() {},
+				fail: param["fail"] || function() {}
+			};
+			if (param["address"]) {
+				wx.request({
+					url: 'https://api.map.baidu.com/geocoding/v3',
+					data: geocodingparam,
+					header: {
+						"content-type": "application/json"
+					},
+					method: 'GET',
+					success(data) {
+						let res = data["data"];
+						if (res["status"] === 0) {
+							let poiObj = res["result"];
+							// outputRes 包含两个对象:
+							// originalData为百度接口返回的原始数据
+							// wxMarkerData为小程序规范的marker格式
+							let outputRes = res;
+							outputRes["originalData"] = res;
+							outputRes["wxMarkerData"] = [];
+							outputRes["wxMarkerData"][0] = {
+								id: 0,
+								latitude: poiObj["location"]["lat"],
+								longitude: poiObj["location"]["lng"],
+								iconPath: otherparam["iconPath"],
+								iconTapPath: otherparam["iconTapPath"],
+								alpha: otherparam["alpha"],
+								width: otherparam["width"],
+								height: otherparam["height"]
+							}
+							otherparam.success(outputRes);
+						} else {
+							otherparam.fail({
+								errMsg: res["message"],
+								statusCode: res["status"]
+							});
+						}
+					},
+					fail(data) {
+						otherparam.fail(data);
+					}
+				});
+			} else {
+				let errMsg = 'input address!';
+				let res = {
+					errMsg: errMsg
+				};
+				otherparam.fail(res);
+			}
+		}
+
+		/**
+		 * 天气检索
+		 *
+		 * @param {Object} param 检索配置
+		 */
+		weather(param) {
+			var that = this;
+			param = param || {};
+			let weatherparam = {
+				coord_type: param["coord_type"] || 'gcj02',
+				output: param["output"] || 'json',
+				ak: that.ak,
+				sn: param["sn"] || '',
+				timestamp: param["timestamp"] || ''
+			};
+			let otherparam = {
+				success: param["success"] || function() {},
+				fail: param["fail"] || function() {}
+			};
+			let type = 'gcj02';
+			let locationsuccess = function(result) {
+				weatherparam["location"] = result["longitude"] + ',' + result[
+					"latitude"];
+				wx.request({
+					url: 'https://api.map.baidu.com/telematics/v3/weather',
+					data: weatherparam,
+					header: {
+						"content-type": "application/json"
+					},
+					method: 'GET',
+					success(data) {
+						let res = data["data"];
+						if (res["error"] === 0 && res["status"] === 'success') {
+							let weatherArr = res["results"];
+							// outputRes 包含两个对象,
+							// originalData为百度接口返回的原始数据
+							// wxMarkerData为小程序规范的marker格式
+							let outputRes = {};
+							outputRes["originalData"] = res;
+							outputRes["currentWeather"] = [];
+							outputRes["currentWeather"][0] = {
+								currentCity: weatherArr[0]["currentCity"],
+								pm25: weatherArr[0]["pm25"],
+								date: weatherArr[0]["weather_data"][0]["date"],
+								temperature: weatherArr[0]["weather_data"][0][
+									"temperature"
+								],
+								weatherDesc: weatherArr[0]["weather_data"][0][
+									"weather"
+								],
+								wind: weatherArr[0]["weather_data"][0]["wind"]
+							};
+							otherparam.success(outputRes);
+						} else {
+							otherparam.fail({
+								errMsg: res["message"],
+								statusCode: res["status"]
+							});
+						}
+					},
+					fail(data) {
+						otherparam.fail(data);
+					}
+				});
+			}
+			let locationfail = function(result) {
+				otherparam.fail(result);
+			}
+			let locationcomplete = function(result) {}
+			if (!param["location"]) {
+				that.getWXLocation(type, locationsuccess, locationfail,
+					locationcomplete);
+			} else {
+				let longitude = param.location.split(',')[0];
+				let latitude = param.location.split(',')[1];
+				let errMsg = 'input location';
+				let res = {
+					errMsg: errMsg,
+					latitude: latitude,
+					longitude: longitude
+				};
+				locationsuccess(res);
+			}
+		}
+	}
+
+	export default {
+		name: 'bmap',
+		props: {
+			longitude: {
+				type: String,
+				default: ''
+			},
+			latitude: {
+				type: String,
+				default: ''
+			},
+			mapKey: {
+				require: true,
+				type: String,
+				default: ''
+			},
+			marker: {
+				type: Object,
+				default: () => {}
+			},
+			disable: {
+				type: Boolean,
+				default: false
+			},
+			isPolygons: {
+				type: Boolean,
+				default: false
+			},
+			polygons: {
+				type: Array,
+				default: () => []
+			},
+			top: {
+				type: [String, Number],
+				default: 30
+			},
+			isCustomBar: {
+				type: Boolean,
+				default: false
+			}
+		},
+		data() {
+			return {
+				statusBarH: 0,
+				customBarH: 0,
+				addressMap: '',
+				searchValue: '',
+				markers: [],
+				bmapPlugin: null,
+				key: this.$props?.mapKey,
+				lat: this.$props?.latitude,
+				long: this.$props?.longitude,
+				regeocodeData: {},
+				searchList: []
+			};
+		},
+		created() {
+			this.init();
+			let self = this
+			uni.getSystemInfo({
+				success: function(e) {
+					self.statusBarH = e.statusBarHeight + 5
+					if (uni.getMenuButtonBoundingClientRect?.()) {
+						let custom = uni.getMenuButtonBoundingClientRect()
+						self.customBarH = custom.height + 5
+					} else {
+						self.customBarH = 30
+					}
+				},
+			})
+		},
+		methods: {
+			changeMarkers() {
+				this.markers[0] = {
+					...this.$props?.marker,
+					longitude: this.long,
+					latitude: this.lat
+				};
+			},
+			init() {
+				this.bmapPlugin = new BMapWX({
+					ak: this.key
+				});
+				const detail = {
+					longitude: this.$props?.longitude,
+					latitude: this.$props?.latitude
+				};
+
+				if (!detail.latitude || !detail.longitude) {
+					const _this = this;
+					uni.getLocation({
+						type: 'gcj02',
+						isHighAccuracy: true,
+						success: (data) => {
+							detail.latitude = data.latitude;
+							detail.longitude = data.longitude;
+							_this.getCurrentLocation({
+								detail
+							});
+						}
+					});
+				} else {
+					this.getCurrentLocation({
+						detail
+					});
+				}
+			},
+			poitap(e) {
+				this.getCurrentLocation(e)
+			},
+			//点击地图
+			getCurrentLocation(e) {
+				this.searchValue = '';
+				const {
+					latitude,
+					longitude
+				} = e.detail;
+				if (!latitude || !longitude) return;
+
+				this.getRegeo([longitude, latitude], (pois) => {
+					this.searchList = pois;
+				});
+			},
+			getInputtips() {
+				this.bmapPlugin.suggestion({
+					query: this.searchValue,
+					success: (data) => {
+						this.searchList = data.result.filter((i) => i?.uid && i?.location);
+					}
+				});
+			},
+			getRegeo(coordinate, fn) {
+				this.long = coordinate[0];
+				this.lat = coordinate[1];
+				this.changeMarkers();
+				this.bmapPlugin.regeocoding({
+					location: this.lat + ',' + this.long,
+					success: (data) => {
+						const {
+							result
+						} = data.originalData;
+						this.addressMap = result.formatted_address;
+						this.regeocodeData = result;
+						this.$emit('changeMarker', this.getConfirmData());
+						fn && fn(result.pois);
+					},
+				});
+			},
+			//搜索关键字
+			searchMap() {
+				this.getInputtips();
+			},
+			getCurrentSingleLocation(data) {
+				const {
+					point,
+					location
+				} = data;
+				this.searchValue = data.name;
+				this.getRegeo([point?.x || location.lng, point?.y || location.lat]);
+			},
+			close() {
+				this.$emit('confirm');
+			},
+			getConfirmData() {
+				const {
+					pois,
+					addressComponent: {
+						province,
+						district,
+						township
+					}
+				} = this.regeocodeData;
+				const title = pois?.[0]?.name || province + district + township;
+				return {
+					...this.regeocodeData,
+					title,
+					latitude: this.lat,
+					longitude: this.long,
+					address: this.addressMap
+				}
+			},
+			submit(e) {
+				if (this.$props.disable) {
+					return;
+				}
+				if (!this.addressMap) {
+					return;
+				}
+				if (JSON.stringify(this.regeocodeData) != '{}') {
+					this.$emit('confirm', this.getConfirmData());
+				}
+			}
+		}
+	};
+</script>
+<style lang="scss" scoped>
+	.map-content {
+		position: fixed;
+		top: 0;
+		left: 0;
+		bottom: 0;
+		right: 0;
+		z-index: 99;
+		background-color: #fff;
+
+		.top {
+			position: absolute;
+			width: 100%;
+			height: 80rpx;
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			padding: 10rpx 40rpx;
+			box-sizing: border-box;
+			background-color: rgba(0, 0, 0, 0.2);
+			color: #fff;
+			z-index: 999;
+
+			.confirm {
+				height: 60rpx;
+				line-height: 60rpx;
+				padding: 0 20rpx;
+				border-radius: 10rpx;
+				background-color: #42b983;
+			}
+
+			.address-text {
+				width: 55vw;
+				text-align: center;
+				overflow: hidden;
+				word-wrap: break-word;
+				display: -webkit-box;
+				-webkit-line-clamp: 1;
+				-webkit-box-orient: vertical;
+			}
+		}
+
+		.map {
+			position: relative;
+			width: 100vw;
+			height: 50vh;
+
+			.position-icon {
+				position: absolute;
+				left: 50%;
+				top: 50%;
+				width: 50px;
+				height: 40px;
+				margin-top: -12px;
+				transform: translate(-50%, -50%);
+			}
+		}
+
+		.search {
+			padding: 10rpx 20rpx;
+			display: flex;
+			justify-content: center;
+			background-color: #fff;
+
+			input {
+				flex: 1;
+				width: calc(100vw - 80rpx);
+				padding: 0 20rpx;
+				height: 60rpx;
+				border: 1px solid #ccc;
+				border-radius: 10rpx;
+			}
+		}
+
+		.bot-box {
+
+			height: calc(50vh - 50px);
+			overflow: auto;
+			width: 100vw;
+			background-color: #fff;
+
+			.empty {
+				margin-top: 40rpx;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+			}
+
+			.poi-list {
+				padding: 0 $uni-spacing-row-base;
+				box-sizing: border-box;
+
+				.poi-item {
+					margin: 20rpx 0;
+					padding: 10rpx;
+					border: 1px solid $uni-border-color;
+					border-radius: $uni-border-radius-base;
+
+					.poi-name {
+						font-size: 34rpx;
+						color: #333;
+					}
+
+					.poi-address {
+						.address {
+							width: 100%;
+							font-size: 26rpx;
+							overflow: hidden;
+							color: #999;
+							white-space: nowrap;
+							text-overflow: ellipsis;
+						}
+					}
+				}
+
+				.poi-item:active {
+					color: #fff;
+					border: 1px solid #42b983;
+				}
+			}
+		}
+	}
+</style>

+ 1511 - 0
uni_modules/atl-map/components/tmap/tmap.vue

@@ -0,0 +1,1511 @@
+<template>
+	<view class="map-content" :style="[
+			isCustomBar && {
+				height: customBarH + 'px',
+				paddingTop: statusBarH + 'px',
+				backgroundColor: 'transparent',
+				top: top + 'px',
+			},
+		]">
+		<view class="top">
+			<view class="cancel" @click="closeMap">取消</view>
+			<view class="address-text">
+				{{ currentAd.title || '' }}
+			</view>
+			<view class="confirm" @click="submit"
+				:style="{ backgroundColor: disable ? 'rgba(0, 0, 0, 0.2)' : '#42b983' }">确定</view>
+		</view>
+		<map id="map" class="map" :longitude="long" :latitude="lat" show-location @tap="onTap" :markers="markers"
+			:polygons="isPolygons?polygons:[]" enable-poi @poitap="poitap">
+			<cover-view>
+				<slot name="content"></slot>
+			</cover-view>
+		</map>
+		<view class="search">
+			<view class="search-input">
+				<input placeholder="搜索附近" v-model="search" type="text" maxlength="64" @input="gosearch" />
+			</view>
+		</view>
+		<view class="bot-box">
+			<view class="poi-list">
+				<view class="poi-item" v-for="item in poiList" :key="item.id" @click="select(item)">
+					<view v-if="poiList.length !== 0">
+						<view class="poi-name">
+							{{ item.title }}
+						</view>
+						<view class="poi-address">
+							<view class="address">{{ item.address }}</view>
+						</view>
+					</view>
+				</view>
+				<view class="empty" v-if="poiList.length == 0">暂无数据, 请更检查key是否有效或者更换关键词</view>
+			</view>
+		</view>
+	</view>
+</template>
+<script>
+	// vue3 导入sdk不兼容 所以直接将sdk写入这个文件
+	var ERROR_CONF = {
+		KEY_ERR: 311,
+		KEY_ERR_MSG: 'key格式错误',
+		PARAM_ERR: 310,
+		PARAM_ERR_MSG: '请求参数信息有误',
+		SYSTEM_ERR: 600,
+		SYSTEM_ERR_MSG: '系统错误',
+		WX_ERR_CODE: 1000,
+		WX_OK_CODE: 200
+	};
+	var BASE_URL = 'https://apis.map.qq.com/ws/';
+	var URL_SEARCH = BASE_URL + 'place/v1/search';
+	var URL_SUGGESTION = BASE_URL + 'place/v1/suggestion';
+	var URL_GET_GEOCODER = BASE_URL + 'geocoder/v1/';
+	var URL_CITY_LIST = BASE_URL + 'district/v1/list';
+	var URL_AREA_LIST = BASE_URL + 'district/v1/getchildren';
+	var URL_DISTANCE = BASE_URL + 'distance/v1/';
+	var URL_DIRECTION = BASE_URL + 'direction/v1/';
+	var MODE = {
+		driving: 'driving',
+		transit: 'transit'
+	};
+	var EARTH_RADIUS = 6378136.49;
+	var Utils = {
+		/**
+		 * md5加密方法
+		 * 版权所有©2011 Sebastian Tschan,https://blueimp.net
+		 */
+		safeAdd(x, y) {
+			var lsw = (x & 0xffff) + (y & 0xffff);
+			var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
+			return (msw << 16) | (lsw & 0xffff);
+		},
+		bitRotateLeft(num, cnt) {
+			return (num << cnt) | (num >>> (32 - cnt));
+		},
+		md5cmn(q, a, b, x, s, t) {
+			return this.safeAdd(this.bitRotateLeft(this.safeAdd(this.safeAdd(a, q), this.safeAdd(x, t)), s), b);
+		},
+		md5ff(a, b, c, d, x, s, t) {
+			return this.md5cmn((b & c) | (~b & d), a, b, x, s, t);
+		},
+		md5gg(a, b, c, d, x, s, t) {
+			return this.md5cmn((b & d) | (c & ~d), a, b, x, s, t);
+		},
+		md5hh(a, b, c, d, x, s, t) {
+			return this.md5cmn(b ^ c ^ d, a, b, x, s, t);
+		},
+		md5ii(a, b, c, d, x, s, t) {
+			return this.md5cmn(c ^ (b | ~d), a, b, x, s, t);
+		},
+		binlMD5(x, len) {
+			/* append padding */
+			x[len >> 5] |= 0x80 << (len % 32);
+			x[((len + 64) >>> 9 << 4) + 14] = len;
+
+			var i;
+			var olda;
+			var oldb;
+			var oldc;
+			var oldd;
+			var a = 1732584193;
+			var b = -271733879;
+			var c = -1732584194;
+			var d = 271733878;
+
+			for (i = 0; i < x.length; i += 16) {
+				olda = a;
+				oldb = b;
+				oldc = c;
+				oldd = d;
+
+				a = this.md5ff(a, b, c, d, x[i], 7, -680876936);
+				d = this.md5ff(d, a, b, c, x[i + 1], 12, -389564586);
+				c = this.md5ff(c, d, a, b, x[i + 2], 17, 606105819);
+				b = this.md5ff(b, c, d, a, x[i + 3], 22, -1044525330);
+				a = this.md5ff(a, b, c, d, x[i + 4], 7, -176418897);
+				d = this.md5ff(d, a, b, c, x[i + 5], 12, 1200080426);
+				c = this.md5ff(c, d, a, b, x[i + 6], 17, -1473231341);
+				b = this.md5ff(b, c, d, a, x[i + 7], 22, -45705983);
+				a = this.md5ff(a, b, c, d, x[i + 8], 7, 1770035416);
+				d = this.md5ff(d, a, b, c, x[i + 9], 12, -1958414417);
+				c = this.md5ff(c, d, a, b, x[i + 10], 17, -42063);
+				b = this.md5ff(b, c, d, a, x[i + 11], 22, -1990404162);
+				a = this.md5ff(a, b, c, d, x[i + 12], 7, 1804603682);
+				d = this.md5ff(d, a, b, c, x[i + 13], 12, -40341101);
+				c = this.md5ff(c, d, a, b, x[i + 14], 17, -1502002290);
+				b = this.md5ff(b, c, d, a, x[i + 15], 22, 1236535329);
+
+				a = this.md5gg(a, b, c, d, x[i + 1], 5, -165796510);
+				d = this.md5gg(d, a, b, c, x[i + 6], 9, -1069501632);
+				c = this.md5gg(c, d, a, b, x[i + 11], 14, 643717713);
+				b = this.md5gg(b, c, d, a, x[i], 20, -373897302);
+				a = this.md5gg(a, b, c, d, x[i + 5], 5, -701558691);
+				d = this.md5gg(d, a, b, c, x[i + 10], 9, 38016083);
+				c = this.md5gg(c, d, a, b, x[i + 15], 14, -660478335);
+				b = this.md5gg(b, c, d, a, x[i + 4], 20, -405537848);
+				a = this.md5gg(a, b, c, d, x[i + 9], 5, 568446438);
+				d = this.md5gg(d, a, b, c, x[i + 14], 9, -1019803690);
+				c = this.md5gg(c, d, a, b, x[i + 3], 14, -187363961);
+				b = this.md5gg(b, c, d, a, x[i + 8], 20, 1163531501);
+				a = this.md5gg(a, b, c, d, x[i + 13], 5, -1444681467);
+				d = this.md5gg(d, a, b, c, x[i + 2], 9, -51403784);
+				c = this.md5gg(c, d, a, b, x[i + 7], 14, 1735328473);
+				b = this.md5gg(b, c, d, a, x[i + 12], 20, -1926607734);
+
+				a = this.md5hh(a, b, c, d, x[i + 5], 4, -378558);
+				d = this.md5hh(d, a, b, c, x[i + 8], 11, -2022574463);
+				c = this.md5hh(c, d, a, b, x[i + 11], 16, 1839030562);
+				b = this.md5hh(b, c, d, a, x[i + 14], 23, -35309556);
+				a = this.md5hh(a, b, c, d, x[i + 1], 4, -1530992060);
+				d = this.md5hh(d, a, b, c, x[i + 4], 11, 1272893353);
+				c = this.md5hh(c, d, a, b, x[i + 7], 16, -155497632);
+				b = this.md5hh(b, c, d, a, x[i + 10], 23, -1094730640);
+				a = this.md5hh(a, b, c, d, x[i + 13], 4, 681279174);
+				d = this.md5hh(d, a, b, c, x[i], 11, -358537222);
+				c = this.md5hh(c, d, a, b, x[i + 3], 16, -722521979);
+				b = this.md5hh(b, c, d, a, x[i + 6], 23, 76029189);
+				a = this.md5hh(a, b, c, d, x[i + 9], 4, -640364487);
+				d = this.md5hh(d, a, b, c, x[i + 12], 11, -421815835);
+				c = this.md5hh(c, d, a, b, x[i + 15], 16, 530742520);
+				b = this.md5hh(b, c, d, a, x[i + 2], 23, -995338651);
+
+				a = this.md5ii(a, b, c, d, x[i], 6, -198630844);
+				d = this.md5ii(d, a, b, c, x[i + 7], 10, 1126891415);
+				c = this.md5ii(c, d, a, b, x[i + 14], 15, -1416354905);
+				b = this.md5ii(b, c, d, a, x[i + 5], 21, -57434055);
+				a = this.md5ii(a, b, c, d, x[i + 12], 6, 1700485571);
+				d = this.md5ii(d, a, b, c, x[i + 3], 10, -1894986606);
+				c = this.md5ii(c, d, a, b, x[i + 10], 15, -1051523);
+				b = this.md5ii(b, c, d, a, x[i + 1], 21, -2054922799);
+				a = this.md5ii(a, b, c, d, x[i + 8], 6, 1873313359);
+				d = this.md5ii(d, a, b, c, x[i + 15], 10, -30611744);
+				c = this.md5ii(c, d, a, b, x[i + 6], 15, -1560198380);
+				b = this.md5ii(b, c, d, a, x[i + 13], 21, 1309151649);
+				a = this.md5ii(a, b, c, d, x[i + 4], 6, -145523070);
+				d = this.md5ii(d, a, b, c, x[i + 11], 10, -1120210379);
+				c = this.md5ii(c, d, a, b, x[i + 2], 15, 718787259);
+				b = this.md5ii(b, c, d, a, x[i + 9], 21, -343485551);
+
+				a = this.safeAdd(a, olda);
+				b = this.safeAdd(b, oldb);
+				c = this.safeAdd(c, oldc);
+				d = this.safeAdd(d, oldd);
+			}
+			return [a, b, c, d];
+		},
+		binl2rstr(input) {
+			var i;
+			var output = '';
+			var length32 = input.length * 32;
+			for (i = 0; i < length32; i += 8) {
+				output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xff);
+			}
+			return output;
+		},
+		rstr2binl(input) {
+			var i;
+			var output = [];
+			output[(input.length >> 2) - 1] = undefined;
+			for (i = 0; i < output.length; i += 1) {
+				output[i] = 0;
+			}
+			var length8 = input.length * 8;
+			for (i = 0; i < length8; i += 8) {
+				output[i >> 5] |= (input.charCodeAt(i / 8) & 0xff) << (i % 32);
+			}
+			return output;
+		},
+		rstrMD5(s) {
+			return this.binl2rstr(this.binlMD5(this.rstr2binl(s), s.length * 8));
+		},
+		rstrHMACMD5(key, data) {
+			var i;
+			var bkey = this.rstr2binl(key);
+			var ipad = [];
+			var opad = [];
+			var hash;
+			ipad[15] = opad[15] = undefined;
+			if (bkey.length > 16) {
+				bkey = this.binlMD5(bkey, key.length * 8);
+			}
+			for (i = 0; i < 16; i += 1) {
+				ipad[i] = bkey[i] ^ 0x36363636;
+				opad[i] = bkey[i] ^ 0x5c5c5c5c;
+			}
+			hash = this.binlMD5(ipad.concat(this.rstr2binl(data)), 512 + data.length * 8);
+			return this.binl2rstr(this.binlMD5(opad.concat(hash), 512 + 128));
+		},
+		rstr2hex(input) {
+			var hexTab = '0123456789abcdef';
+			var output = '';
+			var x;
+			var i;
+			for (i = 0; i < input.length; i += 1) {
+				x = input.charCodeAt(i);
+				output += hexTab.charAt((x >>> 4) & 0x0f) + hexTab.charAt(x & 0x0f);
+			}
+			return output;
+		},
+		str2rstrUTF8(input) {
+			return unescape(encodeURIComponent(input));
+		},
+		rawMD5(s) {
+			return this.rstrMD5(this.str2rstrUTF8(s));
+		},
+		hexMD5(s) {
+			return this.rstr2hex(this.rawMD5(s));
+		},
+		rawHMACMD5(k, d) {
+			return this.rstrHMACMD5(this.str2rstrUTF8(k), str2rstrUTF8(d));
+		},
+		hexHMACMD5(k, d) {
+			return this.rstr2hex(this.rawHMACMD5(k, d));
+		},
+
+		md5(string, key, raw) {
+			if (!key) {
+				if (!raw) {
+					return this.hexMD5(string);
+				}
+				return this.rawMD5(string);
+			}
+			if (!raw) {
+				return this.hexHMACMD5(key, string);
+			}
+			return this.rawHMACMD5(key, string);
+		},
+		/**
+		 * 得到md5加密后的sig参数
+		 * @param {Object} requestParam 接口参数
+		 * @param {String} sk签名字符串
+		 * @param {String} featrue 方法名
+		 * @return 返回加密后的sig参数
+		 */
+		getSig(requestParam, sk, feature, mode) {
+			var sig = null;
+			var requestArr = [];
+			Object.keys(requestParam).sort().forEach(function(key) {
+				requestArr.push(key + '=' + requestParam[key]);
+			});
+			if (feature == 'search') {
+				sig = '/ws/place/v1/search?' + requestArr.join('&') + sk;
+			}
+			if (feature == 'suggest') {
+				sig = '/ws/place/v1/suggestion?' + requestArr.join('&') + sk;
+			}
+			if (feature == 'reverseGeocoder') {
+				sig = '/ws/geocoder/v1/?' + requestArr.join('&') + sk;
+			}
+			if (feature == 'geocoder') {
+				sig = '/ws/geocoder/v1/?' + requestArr.join('&') + sk;
+			}
+			if (feature == 'getCityList') {
+				sig = '/ws/district/v1/list?' + requestArr.join('&') + sk;
+			}
+			if (feature == 'getDistrictByCityId') {
+				sig = '/ws/district/v1/getchildren?' + requestArr.join('&') + sk;
+			}
+			if (feature == 'calculateDistance') {
+				sig = '/ws/distance/v1/?' + requestArr.join('&') + sk;
+			}
+			if (feature == 'direction') {
+				sig = '/ws/direction/v1/' + mode + '?' + requestArr.join('&') + sk;
+			}
+			sig = this.md5(sig);
+			return sig;
+		},
+		/**
+		 * 得到终点query字符串
+		 * @param {Array|String} 检索数据
+		 */
+		location2query(data) {
+			if (typeof data == 'string') {
+				return data;
+			}
+			var query = '';
+			for (var i = 0; i < data.length; i++) {
+				var d = data[i];
+				if (!!query) {
+					query += ';';
+				}
+				if (d.location) {
+					query = query + d.location.lat + ',' + d.location.lng;
+				}
+				if (d.latitude && d.longitude) {
+					query = query + d.latitude + ',' + d.longitude;
+				}
+			}
+			return query;
+		},
+
+		/**
+		 * 计算角度
+		 */
+		rad(d) {
+			return d * Math.PI / 180.0;
+		},
+		/**
+		 * 处理终点location数组
+		 * @return 返回终点数组
+		 */
+		getEndLocation(location) {
+			var to = location.split(';');
+			var endLocation = [];
+			for (var i = 0; i < to.length; i++) {
+				endLocation.push({
+					lat: parseFloat(to[i].split(',')[0]),
+					lng: parseFloat(to[i].split(',')[1])
+				})
+			}
+			return endLocation;
+		},
+
+		/**
+		 * 计算两点间直线距离
+		 * @param a 表示纬度差
+		 * @param b 表示经度差
+		 * @return 返回的是距离,单位m
+		 */
+		getDistance(latFrom, lngFrom, latTo, lngTo) {
+			var radLatFrom = this.rad(latFrom);
+			var radLatTo = this.rad(latTo);
+			var a = radLatFrom - radLatTo;
+			var b = this.rad(lngFrom) - this.rad(lngTo);
+			var distance = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLatFrom) * Math.cos(
+				radLatTo) * Math.pow(Math.sin(b / 2), 2)));
+			distance = distance * EARTH_RADIUS;
+			distance = Math.round(distance * 10000) / 10000;
+			return parseFloat(distance.toFixed(0));
+		},
+		/**
+		 * 使用微信接口进行定位
+		 */
+		getWXLocation(success, fail, complete) {
+			wx.getLocation({
+				type: 'gcj02',
+				success: success,
+				fail: fail,
+				complete: complete
+			});
+		},
+
+		/**
+		 * 获取location参数
+		 */
+		getLocationParam(location) {
+			if (typeof location == 'string') {
+				var locationArr = location.split(',');
+				if (locationArr.length === 2) {
+					location = {
+						latitude: location.split(',')[0],
+						longitude: location.split(',')[1]
+					};
+				} else {
+					location = {};
+				}
+			}
+			return location;
+		},
+
+		/**
+		 * 回调函数默认处理
+		 */
+		polyfillParam(param) {
+			param.success = param.success || function() {};
+			param.fail = param.fail || function() {};
+			param.complete = param.complete || function() {};
+		},
+
+		/**
+		 * 验证param对应的key值是否为空
+		 * 
+		 * @param {Object} param 接口参数
+		 * @param {String} key 对应参数的key
+		 */
+		checkParamKeyEmpty(param, key) {
+			if (!param[key]) {
+				var errconf = this.buildErrorConfig(ERROR_CONF.PARAM_ERR, ERROR_CONF.PARAM_ERR_MSG + key + '参数格式有误');
+				param.fail(errconf);
+				param.complete(errconf);
+				return true;
+			}
+			return false;
+		},
+
+		/**
+		 * 验证参数中是否存在检索词keyword
+		 * 
+		 * @param {Object} param 接口参数
+		 */
+		checkKeyword(param) {
+			return !this.checkParamKeyEmpty(param, 'keyword');
+		},
+
+		/**
+		 * 验证location值
+		 * 
+		 * @param {Object} param 接口参数
+		 */
+		checkLocation(param) {
+			var location = this.getLocationParam(param.location);
+			if (!location || !location.latitude || !location.longitude) {
+				var errconf = this.buildErrorConfig(ERROR_CONF.PARAM_ERR, ERROR_CONF.PARAM_ERR_MSG +
+					' location参数格式有误');
+				param.fail(errconf);
+				param.complete(errconf);
+				return false;
+			}
+			return true;
+		},
+
+		/**
+		 * 构造错误数据结构
+		 * @param {Number} errCode 错误码
+		 * @param {Number} errMsg 错误描述
+		 */
+		buildErrorConfig(errCode, errMsg) {
+			return {
+				status: errCode,
+				message: errMsg
+			};
+		},
+
+		/**
+		 * 
+		 * 数据处理函数
+		 * 根据传入参数不同处理不同数据
+		 * @param {String} feature 功能名称
+		 * search 地点搜索
+		 * suggest关键词提示
+		 * reverseGeocoder逆地址解析
+		 * geocoder地址解析
+		 * getCityList获取城市列表:父集
+		 * getDistrictByCityId获取区县列表:子集
+		 * calculateDistance距离计算
+		 * @param {Object} param 接口参数
+		 * @param {Object} data 数据
+		 */
+		handleData(param, data, feature) {
+			if (feature == 'search') {
+				var searchResult = data.data;
+				var searchSimplify = [];
+				for (var i = 0; i < searchResult.length; i++) {
+					searchSimplify.push({
+						id: searchResult[i].id || null,
+						title: searchResult[i].title || null,
+						latitude: searchResult[i].location && searchResult[i].location.lat || null,
+						longitude: searchResult[i].location && searchResult[i].location.lng || null,
+						address: searchResult[i].address || null,
+						category: searchResult[i].category || null,
+						tel: searchResult[i].tel || null,
+						adcode: searchResult[i].ad_info && searchResult[i].ad_info.adcode || null,
+						city: searchResult[i].ad_info && searchResult[i].ad_info.city || null,
+						district: searchResult[i].ad_info && searchResult[i].ad_info.district || null,
+						province: searchResult[i].ad_info && searchResult[i].ad_info.province || null
+					})
+				}
+				param.success(data, {
+					searchResult: searchResult,
+					searchSimplify: searchSimplify
+				})
+			} else if (feature == 'suggest') {
+				var suggestResult = data.data;
+				var suggestSimplify = [];
+				for (var i = 0; i < suggestResult.length; i++) {
+					suggestSimplify.push({
+						adcode: suggestResult[i].adcode || null,
+						address: suggestResult[i].address || null,
+						category: suggestResult[i].category || null,
+						city: suggestResult[i].city || null,
+						district: suggestResult[i].district || null,
+						id: suggestResult[i].id || null,
+						latitude: suggestResult[i].location && suggestResult[i].location.lat || null,
+						longitude: suggestResult[i].location && suggestResult[i].location.lng || null,
+						province: suggestResult[i].province || null,
+						title: suggestResult[i].title || null,
+						type: suggestResult[i].type || null
+					})
+				}
+				param.success(data, {
+					suggestResult: suggestResult,
+					suggestSimplify: suggestSimplify
+				})
+			} else if (feature == 'reverseGeocoder') {
+				var reverseGeocoderResult = data.result;
+				var reverseGeocoderSimplify = {
+					address: reverseGeocoderResult.address || null,
+					latitude: reverseGeocoderResult.location && reverseGeocoderResult.location.lat || null,
+					longitude: reverseGeocoderResult.location && reverseGeocoderResult.location.lng || null,
+					adcode: reverseGeocoderResult.ad_info && reverseGeocoderResult.ad_info.adcode || null,
+					city: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component
+						.city || null,
+					district: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component
+						.district || null,
+					nation: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component
+						.nation || null,
+					province: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component
+						.province || null,
+					street: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component
+						.street || null,
+					street_number: reverseGeocoderResult.address_component && reverseGeocoderResult
+						.address_component.street_number || null,
+					recommend: reverseGeocoderResult.formatted_addresses && reverseGeocoderResult
+						.formatted_addresses.recommend || null,
+					rough: reverseGeocoderResult.formatted_addresses && reverseGeocoderResult.formatted_addresses
+						.rough || null
+				};
+				if (reverseGeocoderResult.pois) { //判断是否返回周边poi
+					var pois = reverseGeocoderResult.pois;
+					var poisSimplify = [];
+					for (var i = 0; i < pois.length; i++) {
+						poisSimplify.push({
+							id: pois[i].id || null,
+							title: pois[i].title || null,
+							latitude: pois[i].location && pois[i].location.lat || null,
+							longitude: pois[i].location && pois[i].location.lng || null,
+							address: pois[i].address || null,
+							category: pois[i].category || null,
+							adcode: pois[i].ad_info && pois[i].ad_info.adcode || null,
+							city: pois[i].ad_info && pois[i].ad_info.city || null,
+							district: pois[i].ad_info && pois[i].ad_info.district || null,
+							province: pois[i].ad_info && pois[i].ad_info.province || null
+						})
+					}
+					param.success(data, {
+						reverseGeocoderResult: reverseGeocoderResult,
+						reverseGeocoderSimplify: reverseGeocoderSimplify,
+						pois: pois,
+						poisSimplify: poisSimplify
+					})
+				} else {
+					param.success(data, {
+						reverseGeocoderResult: reverseGeocoderResult,
+						reverseGeocoderSimplify: reverseGeocoderSimplify
+					})
+				}
+			} else if (feature == 'geocoder') {
+				var geocoderResult = data.result;
+				var geocoderSimplify = {
+					title: geocoderResult.title || null,
+					latitude: geocoderResult.location && geocoderResult.location.lat || null,
+					longitude: geocoderResult.location && geocoderResult.location.lng || null,
+					adcode: geocoderResult.ad_info && geocoderResult.ad_info.adcode || null,
+					province: geocoderResult.address_components && geocoderResult.address_components.province ||
+						null,
+					city: geocoderResult.address_components && geocoderResult.address_components.city || null,
+					district: geocoderResult.address_components && geocoderResult.address_components.district ||
+						null,
+					street: geocoderResult.address_components && geocoderResult.address_components.street || null,
+					street_number: geocoderResult.address_components && geocoderResult.address_components
+						.street_number || null,
+					level: geocoderResult.level || null
+				};
+				param.success(data, {
+					geocoderResult: geocoderResult,
+					geocoderSimplify: geocoderSimplify
+				});
+			} else if (feature == 'getCityList') {
+				var provinceResult = data.result[0];
+				var cityResult = data.result[1];
+				var districtResult = data.result[2];
+				param.success(data, {
+					provinceResult: provinceResult,
+					cityResult: cityResult,
+					districtResult: districtResult
+				});
+			} else if (feature == 'getDistrictByCityId') {
+				var districtByCity = data.result[0];
+				param.success(data, districtByCity);
+			} else if (feature == 'calculateDistance') {
+				var calculateDistanceResult = data.result.elements;
+				var distance = [];
+				for (var i = 0; i < calculateDistanceResult.length; i++) {
+					distance.push(calculateDistanceResult[i].distance);
+				}
+				param.success(data, {
+					calculateDistanceResult: calculateDistanceResult,
+					distance: distance
+				});
+			} else if (feature == 'direction') {
+				var direction = data.result.routes;
+				param.success(data, direction);
+			} else {
+				param.success(data);
+			}
+		},
+
+		/**
+		 * 构造微信请求参数,公共属性处理
+		 * 
+		 * @param {Object} param 接口参数
+		 * @param {Object} param 配置项
+		 * @param {String} feature 方法名
+		 */
+		buildWxRequestConfig(param, options, feature) {
+			var that = this;
+			options.header = {
+				"content-type": "application/json"
+			};
+			options.method = 'GET';
+			options.success = function(res) {
+				var data = res.data;
+				if (data.status === 0) {
+					that.handleData(param, data, feature);
+				} else {
+					param.fail(data);
+				}
+			};
+			options.fail = function(res) {
+				res.statusCode = ERROR_CONF.WX_ERR_CODE;
+				param.fail(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE, res.errMsg));
+			};
+			options.complete = function(res) {
+				var statusCode = +res.statusCode;
+				switch (statusCode) {
+					case ERROR_CONF.WX_ERR_CODE: {
+						param.complete(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE, res.errMsg));
+						break;
+					}
+					case ERROR_CONF.WX_OK_CODE: {
+						var data = res.data;
+						if (data.status === 0) {
+							param.complete(data);
+						} else {
+							param.complete(that.buildErrorConfig(data.status, data.message));
+						}
+						break;
+					}
+					default: {
+						param.complete(that.buildErrorConfig(ERROR_CONF.SYSTEM_ERR, ERROR_CONF.SYSTEM_ERR_MSG));
+					}
+
+				}
+			};
+			return options;
+		},
+
+		/**
+		 * 处理用户参数是否传入坐标进行不同的处理
+		 */
+		locationProcess(param, locationsuccess, locationfail, locationcomplete) {
+			var that = this;
+			locationfail = locationfail || function(res) {
+				res.statusCode = ERROR_CONF.WX_ERR_CODE;
+				param.fail(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE, res.errMsg));
+			};
+			locationcomplete = locationcomplete || function(res) {
+				if (res.statusCode == ERROR_CONF.WX_ERR_CODE) {
+					param.complete(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE, res.errMsg));
+				}
+			};
+			if (!param.location) {
+				that.getWXLocation(locationsuccess, locationfail, locationcomplete);
+			} else if (that.checkLocation(param)) {
+				var location = Utils.getLocationParam(param.location);
+				locationsuccess(location);
+			}
+		}
+	};
+
+
+	class QQMapWX {
+
+		/**
+		 * 构造函数
+		 * 
+		 * @param {Object} options 接口参数,key 为必选参数
+		 */
+		constructor(options) {
+			if (!options.key) {
+				throw Error('key值不能为空');
+			}
+			this.key = options.key;
+		};
+
+		/**
+		 * POI周边检索
+		 *
+		 * @param {Object} options 接口参数对象
+		 * 
+		 * 参数对象结构可以参考
+		 * @see http://lbs.qq.com/webservice_v1/guide-search.html
+		 */
+		search(options) {
+			var that = this;
+			options = options || {};
+
+			Utils.polyfillParam(options);
+
+			if (!Utils.checkKeyword(options)) {
+				return;
+			}
+
+			var requestParam = {
+				keyword: options.keyword,
+				orderby: options.orderby || '_distance',
+				page_size: options.page_size || 10,
+				page_index: options.page_index || 1,
+				output: 'json',
+				key: that.key
+			};
+
+			if (options.address_format) {
+				requestParam.address_format = options.address_format;
+			}
+
+			if (options.filter) {
+				requestParam.filter = options.filter;
+			}
+
+			var distance = options.distance || "1000";
+			var auto_extend = options.auto_extend || 1;
+			var region = null;
+			var rectangle = null;
+
+			//判断城市限定参数
+			if (options.region) {
+				region = options.region;
+			}
+
+			//矩形限定坐标(暂时只支持字符串格式)
+			if (options.rectangle) {
+				rectangle = options.rectangle;
+			}
+
+			var locationsuccess = function(result) {
+				if (region && !rectangle) {
+					//城市限定参数拼接
+					requestParam.boundary = "region(" + region + "," + auto_extend + "," + result.latitude + "," +
+						result.longitude + ")";
+					if (options.sig) {
+						requestParam.sig = Utils.getSig(requestParam, options.sig, 'search');
+					}
+				} else if (rectangle && !region) {
+					//矩形搜索
+					requestParam.boundary = "rectangle(" + rectangle + ")";
+					if (options.sig) {
+						requestParam.sig = Utils.getSig(requestParam, options.sig, 'search');
+					}
+				} else {
+					requestParam.boundary = "nearby(" + result.latitude + "," + result.longitude + "," + distance +
+						"," + auto_extend + ")";
+					if (options.sig) {
+						requestParam.sig = Utils.getSig(requestParam, options.sig, 'search');
+					}
+				}
+				wx.request(Utils.buildWxRequestConfig(options, {
+					url: URL_SEARCH,
+					data: requestParam
+				}, 'search'));
+			};
+			Utils.locationProcess(options, locationsuccess);
+		};
+
+		/**
+		 * sug模糊检索
+		 *
+		 * @param {Object} options 接口参数对象
+		 * 
+		 * 参数对象结构可以参考
+		 * http://lbs.qq.com/webservice_v1/guide-suggestion.html
+		 */
+		getSuggestion(options) {
+			var that = this;
+			options = options || {};
+			Utils.polyfillParam(options);
+
+			if (!Utils.checkKeyword(options)) {
+				return;
+			}
+
+			var requestParam = {
+				keyword: options.keyword,
+				region: options.region || '全国',
+				region_fix: options.region_fix || 0,
+				policy: options.policy || 0,
+				page_size: options.page_size || 10, //控制显示条数
+				page_index: options.page_index || 1, //控制页数
+				get_subpois: options.get_subpois || 0, //返回子地点
+				output: 'json',
+				key: that.key
+			};
+			//长地址
+			if (options.address_format) {
+				requestParam.address_format = options.address_format;
+			}
+			//过滤
+			if (options.filter) {
+				requestParam.filter = options.filter;
+			}
+			//排序
+			if (options.location) {
+				var locationsuccess = function(result) {
+					requestParam.location = result.latitude + ',' + result.longitude;
+					if (options.sig) {
+						requestParam.sig = Utils.getSig(requestParam, options.sig, 'suggest');
+					}
+					wx.request(Utils.buildWxRequestConfig(options, {
+						url: URL_SUGGESTION,
+						data: requestParam
+					}, "suggest"));
+				};
+				Utils.locationProcess(options, locationsuccess);
+			} else {
+				if (options.sig) {
+					requestParam.sig = Utils.getSig(requestParam, options.sig, 'suggest');
+				}
+				wx.request(Utils.buildWxRequestConfig(options, {
+					url: URL_SUGGESTION,
+					data: requestParam
+				}, "suggest"));
+			}
+		};
+
+		/**
+		 * 逆地址解析
+		 *
+		 * @param {Object} options 接口参数对象
+		 * 
+		 * 请求参数结构可以参考
+		 * http://lbs.qq.com/webservice_v1/guide-gcoder.html
+		 */
+		reverseGeocoder(options) {
+			var that = this;
+			options = options || {};
+			Utils.polyfillParam(options);
+			var requestParam = {
+				coord_type: options.coord_type || 5,
+				get_poi: options.get_poi || 0,
+				output: 'json',
+				key: that.key
+			};
+			if (options.poi_options) {
+				requestParam.poi_options = options.poi_options
+			}
+
+			var locationsuccess = function(result) {
+				requestParam.location = result.latitude + ',' + result.longitude;
+				if (options.sig) {
+					requestParam.sig = Utils.getSig(requestParam, options.sig, 'reverseGeocoder');
+				}
+				wx.request(Utils.buildWxRequestConfig(options, {
+					url: URL_GET_GEOCODER,
+					data: requestParam
+				}, 'reverseGeocoder'));
+			};
+			Utils.locationProcess(options, locationsuccess);
+		};
+
+		/**
+		 * 地址解析
+		 *
+		 * @param {Object} options 接口参数对象
+		 * 
+		 * 请求参数结构可以参考
+		 * http://lbs.qq.com/webservice_v1/guide-geocoder.html
+		 */
+		geocoder(options) {
+			var that = this;
+			options = options || {};
+			Utils.polyfillParam(options);
+
+			if (Utils.checkParamKeyEmpty(options, 'address')) {
+				return;
+			}
+
+			var requestParam = {
+				address: options.address,
+				output: 'json',
+				key: that.key
+			};
+
+			//城市限定
+			if (options.region) {
+				requestParam.region = options.region;
+			}
+
+			if (options.sig) {
+				requestParam.sig = Utils.getSig(requestParam, options.sig, 'geocoder');
+			}
+
+			wx.request(Utils.buildWxRequestConfig(options, {
+				url: URL_GET_GEOCODER,
+				data: requestParam
+			}, 'geocoder'));
+		};
+
+
+		/**
+		 * 获取城市列表
+		 *
+		 * @param {Object} options 接口参数对象
+		 * 
+		 * 请求参数结构可以参考
+		 * http://lbs.qq.com/webservice_v1/guide-region.html
+		 */
+		getCityList(options) {
+			var that = this;
+			options = options || {};
+			Utils.polyfillParam(options);
+			var requestParam = {
+				output: 'json',
+				key: that.key
+			};
+
+			if (options.sig) {
+				requestParam.sig = Utils.getSig(requestParam, options.sig, 'getCityList');
+			}
+
+			wx.request(Utils.buildWxRequestConfig(options, {
+				url: URL_CITY_LIST,
+				data: requestParam
+			}, 'getCityList'));
+		};
+
+		/**
+		 * 获取对应城市ID的区县列表
+		 *
+		 * @param {Object} options 接口参数对象
+		 * 
+		 * 请求参数结构可以参考
+		 * http://lbs.qq.com/webservice_v1/guide-region.html
+		 */
+		getDistrictByCityId(options) {
+			var that = this;
+			options = options || {};
+			Utils.polyfillParam(options);
+
+			if (Utils.checkParamKeyEmpty(options, 'id')) {
+				return;
+			}
+
+			var requestParam = {
+				id: options.id || '',
+				output: 'json',
+				key: that.key
+			};
+
+			if (options.sig) {
+				requestParam.sig = Utils.getSig(requestParam, options.sig, 'getDistrictByCityId');
+			}
+
+			wx.request(Utils.buildWxRequestConfig(options, {
+				url: URL_AREA_LIST,
+				data: requestParam
+			}, 'getDistrictByCityId'));
+		};
+
+		/**
+		 * 用于单起点到多终点的路线距离(非直线距离)计算:
+		 * 支持两种距离计算方式:步行和驾车。
+		 * 起点到终点最大限制直线距离10公里。
+		 *
+		 * 新增直线距离计算。
+		 * 
+		 * @param {Object} options 接口参数对象
+		 * 
+		 * 请求参数结构可以参考
+		 * http://lbs.qq.com/webservice_v1/guide-distance.html
+		 */
+		calculateDistance(options) {
+			var that = this;
+			options = options || {};
+			Utils.polyfillParam(options);
+
+			if (Utils.checkParamKeyEmpty(options, 'to')) {
+				return;
+			}
+
+			var requestParam = {
+				mode: options.mode || 'walking',
+				to: Utils.location2query(options.to),
+				output: 'json',
+				key: that.key
+			};
+
+			if (options.from) {
+				options.location = options.from;
+			}
+
+			//计算直线距离
+			if (requestParam.mode == 'straight') {
+				var locationsuccess = function(result) {
+					var locationTo = Utils.getEndLocation(requestParam.to); //处理终点坐标
+					var data = {
+						message: "query ok",
+						result: {
+							elements: []
+						},
+						status: 0
+					};
+					for (var i = 0; i < locationTo.length; i++) {
+						data.result.elements.push({ //将坐标存入
+							distance: Utils.getDistance(result.latitude, result.longitude, locationTo[i]
+								.lat, locationTo[i].lng),
+							duration: 0,
+							from: {
+								lat: result.latitude,
+								lng: result.longitude
+							},
+							to: {
+								lat: locationTo[i].lat,
+								lng: locationTo[i].lng
+							}
+						});
+					}
+					var calculateResult = data.result.elements;
+					var distanceResult = [];
+					for (var i = 0; i < calculateResult.length; i++) {
+						distanceResult.push(calculateResult[i].distance);
+					}
+					return options.success(data, {
+						calculateResult: calculateResult,
+						distanceResult: distanceResult
+					});
+				};
+
+				Utils.locationProcess(options, locationsuccess);
+			} else {
+				var locationsuccess = function(result) {
+					requestParam.from = result.latitude + ',' + result.longitude;
+					if (options.sig) {
+						requestParam.sig = Utils.getSig(requestParam, options.sig, 'calculateDistance');
+					}
+					wx.request(Utils.buildWxRequestConfig(options, {
+						url: URL_DISTANCE,
+						data: requestParam
+					}, 'calculateDistance'));
+				};
+
+				Utils.locationProcess(options, locationsuccess);
+			}
+		};
+
+		/**
+		 * 路线规划:
+		 * 
+		 * @param {Object} options 接口参数对象
+		 * 
+		 * 请求参数结构可以参考
+		 * https://lbs.qq.com/webservice_v1/guide-road.html
+		 */
+		direction(options) {
+			var that = this;
+			options = options || {};
+			Utils.polyfillParam(options);
+
+			if (Utils.checkParamKeyEmpty(options, 'to')) {
+				return;
+			}
+
+			var requestParam = {
+				output: 'json',
+				key: that.key
+			};
+
+			//to格式处理
+			if (typeof options.to == 'string') {
+				requestParam.to = options.to;
+			} else {
+				requestParam.to = options.to.latitude + ',' + options.to.longitude;
+			}
+			//初始化局部请求域名
+			var SET_URL_DIRECTION = null;
+			//设置默认mode属性
+			options.mode = options.mode || MODE.driving;
+
+			//设置请求域名
+			SET_URL_DIRECTION = URL_DIRECTION + options.mode;
+
+			if (options.from) {
+				options.location = options.from;
+			}
+
+			if (options.mode == MODE.driving) {
+				if (options.from_poi) {
+					requestParam.from_poi = options.from_poi;
+				}
+				if (options.heading) {
+					requestParam.heading = options.heading;
+				}
+				if (options.speed) {
+					requestParam.speed = options.speed;
+				}
+				if (options.accuracy) {
+					requestParam.accuracy = options.accuracy;
+				}
+				if (options.road_type) {
+					requestParam.road_type = options.road_type;
+				}
+				if (options.to_poi) {
+					requestParam.to_poi = options.to_poi;
+				}
+				if (options.from_track) {
+					requestParam.from_track = options.from_track;
+				}
+				if (options.waypoints) {
+					requestParam.waypoints = options.waypoints;
+				}
+				if (options.policy) {
+					requestParam.policy = options.policy;
+				}
+				if (options.plate_number) {
+					requestParam.plate_number = options.plate_number;
+				}
+			}
+
+			if (options.mode == MODE.transit) {
+				if (options.departure_time) {
+					requestParam.departure_time = options.departure_time;
+				}
+				if (options.policy) {
+					requestParam.policy = options.policy;
+				}
+			}
+
+			var locationsuccess = function(result) {
+				requestParam.from = result.latitude + ',' + result.longitude;
+				if (options.sig) {
+					requestParam.sig = Utils.getSig(requestParam, options.sig, 'direction', options.mode);
+				}
+				wx.request(Utils.buildWxRequestConfig(options, {
+					url: SET_URL_DIRECTION,
+					data: requestParam
+				}, 'direction'));
+			};
+
+			Utils.locationProcess(options, locationsuccess);
+		}
+	};
+
+	// const QQMapWX = qMapWX
+	export default {
+		//父组件传递的信息 mapKeyk地图key marker点位配置 latitude经度 longitude纬度 confirm为回调方法回调中携带选择的地址参数
+		// 示例  <tmap @confirm="confirm" ></tmap>
+		// confirm(data){ data为选择的数据 }
+		name: 'tmap',
+		props: {
+			longitude: {
+				type: String,
+				default: ''
+			},
+			latitude: {
+				type: String,
+				default: ''
+			},
+			mapKey: {
+				require: true,
+				type: String,
+				default: ''
+			},
+			mapType: {
+				type: String,
+				default: 'tmap'
+			},
+			marker: {
+				type: Object,
+				default: () => {}
+			},
+			disable: {
+				type: Boolean,
+				default: false
+			},
+			isPolygons: {
+				type: Boolean,
+				default: false
+			},
+			polygons: {
+				type: Array,
+				default: () => []
+			},
+			top: {
+				type: [String, Number],
+				default: 30
+			},
+			isCustomBar: {
+				type: Boolean,
+				default: false
+			}
+		},
+		data() {
+			return {
+				statusBarH: 0,
+				customBarH: 0,
+				lat: this.$props?.latitude, //经度
+				long: this.$props?.longitude, //维度
+				key: this.$props?.mapKey,
+				search: '',
+				// qqmapsdk: {},
+				qqmapsdk: new QQMapWX({
+					key: this.$props?.mapKey
+				}),
+				poiList: [],
+				markers: [],
+				currentAd: {
+					title: '',
+				}, //选择的位址,
+			};
+		},
+		created() {
+			setTimeout(() => {
+				this.initData();
+			}, 100);
+			let self = this
+			uni.getSystemInfo({
+				success: function(e) {
+					self.statusBarH = e.statusBarHeight + 5
+					if (uni.getMenuButtonBoundingClientRect?.()) {
+						let custom = uni.getMenuButtonBoundingClientRect()
+						self.customBarH = custom.height + 5
+					} else {
+						self.customBarH = 30
+					}
+				},
+			})
+		},
+		methods: {
+			//初始化
+			initData() {
+				uni.getLocation({
+					type: 'gcj02',
+					isHighAccuracy: true,
+					success: (data) => {
+						this.long = this.$props?.longitude || data.longitude;
+						this.lat = this.$props?.latitude || data.latitude;
+						this.changeMarkers();
+						this.goSearchNearby();
+					}
+				});
+			},
+			poitap(e) {
+				this.onTap(e)
+			},
+			onTap(e) {
+				this.lat = e.detail.latitude;
+				this.long = e.detail.longitude;
+				this.changeMarkers();
+				this.search = '';
+				this.goSearchNearby();
+			},
+			changeMarkers() {
+				this.markers[0] = {
+					...this.$props?.marker,
+					longitude: this.long,
+					latitude: this.lat
+				};
+			},
+			//当前位址信息
+			goSearchNearby() {
+				let that = this;
+
+				that.qqmapsdk.reverseGeocoder({
+					location: {
+						latitude: that.lat,
+						longitude: that.long
+					},
+					get_poi: 1,
+					poi_options: 'policy=2;radius=3000;page_size=20;page_index=1',
+					success: (data) => {
+						that.poiList = data.result.pois;
+						that.currentAd = that.poiList[0];
+						that.$emit('changeMarker', {
+							...that.currentAd,
+							longitude: that.currentAd.location.lng,
+							latitude: that.currentAd.location.lat,
+						});
+					},
+					fail: (e) => {
+						uni.showToast({
+							title: e.message,
+							icon: 'none'
+						});
+					}
+				});
+			},
+			//搜索
+			gosearch() {
+				if (!this.search) {
+					uni.showToast({
+						title: '请输入搜索内容',
+						icon: 'none'
+					});
+					return;
+				}
+				let that = this;
+				that.qqmapsdk.getSuggestion({
+					keyword: that.search,
+					location: that.lat + ',' + that.long,
+					success: (data) => {
+						that.poiList = data.data;
+					},
+					fail: (e) => {
+						uni.showToast({
+							title: e.message,
+							icon: 'none'
+						});
+					}
+				});
+			},
+			//关闭地图
+			closeMap() {
+				this.$emit('confirm');
+			},
+			select(item) {
+				const {
+					lng: longitude,
+					lat: latitude
+				} = item?.location;
+				this.search = item.title;
+				if (this.currentAd.id == item.id) return;
+				this.currentAd = item;
+				this.lat = latitude;
+				this.long = longitude;
+				this.changeMarkers();
+				this.$emit('changeMarker', {
+					...this.currentAd,
+					longitude,
+					latitude,
+				});
+			},
+			//确定
+			submit() {
+				if (this.$props.disable) {
+					return;
+				}
+				const {
+					lng: longitude,
+					lat: latitude
+				} = this.currentAd?.location;
+
+				this.currentAd = {
+					...this.currentAd,
+					longitude,
+					latitude
+				};
+				this.$emit('confirm', this.currentAd);
+			},
+		}
+	};
+</script>
+<style lang="scss" scoped>
+	.map-content {
+		position: fixed;
+		top: 0;
+		left: 0;
+		bottom: 0;
+		right: 0;
+		z-index: 99;
+		background-color: #fff;
+
+		.top {
+			position: absolute;
+			width: 100%;
+			height: 80rpx;
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			padding: 10rpx 40rpx;
+			box-sizing: border-box;
+			background-color: rgba(0, 0, 0, 0.2);
+			color: #fff;
+			z-index: 999;
+
+			.confirm {
+				height: 60rpx;
+				line-height: 60rpx;
+				padding: 0 20rpx;
+				border-radius: 10rpx;
+				background-color: #42b983;
+			}
+
+			.address-text {
+				width: 55vw;
+				text-align: center;
+				overflow: hidden;
+				word-wrap: break-word;
+				display: -webkit-box;
+				-webkit-line-clamp: 1;
+				-webkit-box-orient: vertical;
+			}
+		}
+
+		.map {
+			position: relative;
+			width: 100vw;
+			height: 50vh;
+
+			.position-icon {
+				position: absolute;
+				left: 50%;
+				top: 50%;
+				width: 50px;
+				height: 40px;
+				margin-top: -12px;
+				transform: translate(-50%, -50%);
+			}
+		}
+
+		.search {
+			padding: 10rpx 20rpx;
+			display: flex;
+			justify-content: center;
+			background-color: #fff;
+
+			input {
+				flex: 1;
+				width: calc(100vw - 80rpx);
+				padding: 0 20rpx;
+				height: 60rpx;
+				border: 1px solid #ccc;
+				border-radius: 10rpx;
+			}
+		}
+
+		.bot-box {
+
+			height: calc(50vh - 50px);
+			overflow: auto;
+			width: 100vw;
+			background-color: #fff;
+
+			.empty {
+				margin-top: 40rpx;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+			}
+
+			.poi-list {
+				// padding: 0 $uni-spacing-row-base;
+				box-sizing: border-box;
+
+				.poi-item {
+					margin: 20rpx 0;
+					padding: 10rpx;
+					// border: 1px solid $uni-border-color;
+					// border-radius: $uni-border-radius-base;
+
+					.poi-name {
+						font-size: 34rpx;
+						color: #333;
+					}
+
+					.poi-address {
+						.address {
+							width: 100%;
+							font-size: 26rpx;
+							overflow: hidden;
+							color: #999;
+							white-space: nowrap;
+							text-overflow: ellipsis;
+						}
+					}
+				}
+
+				.poi-item:active {
+					color: #fff;
+					border: 1px solid #42b983;
+				}
+			}
+		}
+	}
+</style>

+ 85 - 0
uni_modules/atl-map/package.json

@@ -0,0 +1,85 @@
+{
+	"id": "atl-map",
+	"displayName": "atl-map微信小程序高德、腾讯、百度地图",
+	"version": "1.4.7",
+	"description": "简易好用的微信小程序地图定位,集成腾讯、高德、百度地图sdk,atl-map开箱即用。支持获取具体位置信息和经纬度,地图搜索,经纬度解析(逆地理编码:经纬度->地点描述),电子围栏(地图多边形)",
+	"keywords": [
+        "定位",
+        "微信小程序地图",
+        "高德/腾讯/百度地图"
+    ],
+	"repository": "https://github.com/13982720426/uniapp-plugin-atl-map.git",
+	"engines": {
+		"HBuilderX": "^3.6.3"
+	},
+	"dcloudext": {
+		"type": "component-vue",
+		"sale": {
+			"regular": {
+				"price": "0.00"
+			},
+			"sourcecode": {
+				"price": "0.00"
+			}
+		},
+		"contact": {
+			"qq": ""
+		},
+		"declaration": {
+			"ads": "无",
+			"data": "无",
+			"permissions": "mp-weixin:\n\"requiredPrivateInfos\": [\"getLocation\"],\n        \"permission\" : {\n            \"scope.userLocation\" : {\n                \"desc\" : \"开启定位\"\n            }\n        }"
+		},
+		"npmurl": ""
+	},
+	"uni_modules": {
+		"dependencies": [],
+		"encrypt": [],
+		"platforms": {
+			"cloud": {
+				"tcb": "y",
+                "aliyun": "y",
+                "alipay": "n"
+			},
+			"client": {
+				"Vue": {
+					"vue2": "y",
+					"vue3": "y"
+				},
+				"App": {
+					"app-vue": "u",
+					"app-nvue": "u",
+					"app-uvue": "u"
+				},
+				"H5-mobile": {
+					"Safari": "u",
+					"Android Browser": "u",
+					"微信浏览器(Android)": "u",
+					"QQ浏览器(Android)": "u"
+				},
+				"H5-pc": {
+					"Chrome": "u",
+					"IE": "u",
+					"Edge": "u",
+					"Firefox": "u",
+					"Safari": "u"
+				},
+				"小程序": {
+					"微信": "y",
+					"阿里": "u",
+					"百度": "u",
+					"字节跳动": "u",
+					"QQ": "u",
+					"钉钉": "u",
+					"快手": "u",
+					"飞书": "u",
+					"京东": "u"
+				},
+				"快应用": {
+					"华为": "u",
+					"联盟": "u"
+				}
+			}
+		}
+	}
+}

+ 364 - 0
uni_modules/atl-map/readme.md

@@ -0,0 +1,364 @@
+# atl-map 微信小程序高德、腾讯、百度地图
+
+简易好用的微信小程序地图定位,封装腾讯、高德、百度地图 sdk,atl-map 开箱即用。
+
+支持点击定位获取具体位置信息和经纬度,地图搜索,经纬度解析(逆地理编码:经纬度->地点描述),新增内容插槽支持自定义内容,电子围栏(地图多边形)
+
+[atl-map 插件下载](https://ext.dcloud.net.cn/plugin?name=atl-map)
+
+## 使用前准备
+
+在平台创建应用并申请 key
+
+### 申请高德、腾讯、百度地图 key
+
+- 高德地图测试 key 申请地址 `https://console.amap.com/dev/key/app` 服务平台选择微信小程序
+- 腾讯地图测试 key 申请地址 `https://lbs.qq.com/dev/console/application/mine` 启用产品选择微信小程序
+- 百度地图测试 key 申请地址 `https://lbs.baidu.com/apiconsole/key/create#/home` 应用类型选择微信小程序
+
+**<span style="color: red"> 重要!!! </span>**
+配置文件 `manifest.json` 微信小程序需要开启定位权限配置`requiredPrivateInfos`和`permission`
+
+```json
+"mp-weixin": {
+	"appid": "xxxx",
+	"usingComponents": true,
+	"requiredPrivateInfos": ["getLocation"],//开启定位权限
+	"permission": {
+		"scope.userLocation": {
+			"desc": "开启定位权限"
+		}
+	}
+}
+```
+
+## 基本使用
+
+### vue 模板
+
+```vue
+<template>
+	<view class="">
+		<view style="padding: 20px">
+			<view class="">地址:{{ title }}</view>
+			<view class="">详细地址:{{ address }}</view>
+			<view class="">经度:{{ longitude }}</view>
+			<view class="">纬度:{{ latitude }}</view>
+		</view>
+		<view style="width: 90vw; margin: 5vw">
+			<button @click="onClick">点击打开地图</button>
+		</view>
+		<atl-map :disable="disable" v-if="show" :longitude="longitude" :latitude="latitude" :marker="marker" :mapKey="mapKey" :mapType="mapType" @confirm="confirm">
+			<template v-slot:content>
+				<view style="position: absolute; bottom: 0; width: 100%; height: 24px; background-color: white">
+					<view style="display: flex; align-items: center; justify-content: center">
+						<image style="width: 24px; height: 24px" :src="imageSrc"></image>
+						<text>内容插槽</text>
+					</view>
+				</view>
+			</template>
+		</atl-map>
+	</view>
+</template>
+```
+
+### js 代码
+
+```javascript
+export default {
+	data() {
+		return {
+			disable: false,
+			show: false,
+			title: '',
+			address: '',
+			longitude: '',
+			latitude: '',
+			imageSrc: '/static/logo.png', //自定义图片
+			marker: {
+				id: 1,
+				height: 50,
+				width: 40
+				// iconPath: '/static/comm/position.png'
+			},
+			// mapKey: '42795f9a59358dea58a8bxxx',//高德地图测试key
+			mapKey: 'ZNJBZ-E6RHJ-EV3F2-DL73K-ARTTH-3EBRZ', //腾讯地图测试key
+			// mapKey: 'p5mGzPEt30bwv1yEkeQGsGP4Xrs9xxxx', //百度地图
+			mapType: 'tmap' // tmap bmap amap
+		};
+	},
+	onLoad() {},
+	methods: {
+		onClick() {
+			this.show = true;
+		},
+		confirm(e) {
+			if (e) {
+				this.longitude = e.longitude;
+				this.latitude = e.latitude;
+				this.title = e.title;
+				this.address = e.address;
+			}
+			this.show = false;
+		}
+	}
+};
+```
+
+## 电子围栏案例
+
+添加了电子围栏demo,因为使用第三方插件判断是否在范围内,**<span style="color: red"> 重要!!! </span>** 需要在项目中额外下载 @turf/boolean-point-in-polygon 插件 或者是自己写个方法判断是否在范围内
+
+`npm i @turf/boolean-point-in-polygon`
+
+如果启动报错 `@turf/helpers` 未找到,那请下载 `npm i @turf/helpers`
+
+地区经纬度生成 参考  [DataV.GeoAtlas地理小工具系列](https://datav.aliyun.com/portal/school/atlas/area_selector) 可以选择范围选择器或者边界生成器生成经纬度数据
+
+### vue 模板
+
+```vue
+<template>
+  <view class="">
+    <view style="padding:20px">
+      <view class="">地址:{{ title }}</view>
+      <view class="">详细地址:{{ address }}</view>
+      <view class="">经度:{{ longitude }}</view>
+      <view class="">纬度:{{ latitude }}</view>
+    </view>
+    <view style="width: 90vw; margin: 5vw">
+      <button @click="onClick">点击打开地图</button>
+    </view>
+    <atl-map
+      :disable="disable"
+      v-if="show"
+      :longitude="longitude"
+      :latitude="latitude"
+      :marker="marker"
+      :mapKey="mapKey"
+      :mapType="mapType"
+      @confirm="confirm"
+      @changeMarker="changeMarker"
+      :polygons="polygons"
+      :isPolygons="true"
+    >
+      <template v-slot:content>
+        <view
+          style="position: absolute; bottom: 0;width: 100%;height: 24px; background-color: white;"
+        >
+          <view
+            style="display: flex;align-items: center; justify-content: center;"
+          >
+            <image style="width: 24px; height: 24px;" :src="imageSrc"> </image>
+            <text> 内容插槽 </text>
+          </view>
+        </view>
+      </template>
+    </atl-map>
+  </view>
+</template>
+```
+
+### js 代码
+
+```javascript
+import booleanPointInPolygon from "@turf/boolean-point-in-polygon";
+import { point, polygon } from "@turf/helpers";
+export default {
+  data() {
+    return {
+      polygons: [
+        {
+          points: [
+            {
+              longitude: "106.57",
+              latitude: "29.52",
+            },
+            {
+              longitude: "106.57",
+              latitude: "29.53",
+            },
+            {
+              longitude: "106.55",
+              latitude: "29.53",
+            },
+            {
+              longitude: "106.55",
+              latitude: "29.52",
+            },
+            {
+              longitude: "106.57",
+              latitude: "29.52",
+            },
+          ],
+          strokeWidth: 1,
+          strokeColor: "#ff000066",
+          fillColor: "#ff000016",
+        },
+        {
+          points: [
+            {
+              longitude: "106.57",
+              latitude: "29.51",
+            },
+            {
+              longitude: "106.57",
+              latitude: "29.515",
+            },
+            {
+              longitude: "106.55",
+              latitude: "29.515",
+            },
+            {
+              longitude: "106.57",
+              latitude: "29.51",
+            },
+          ],
+          strokeWidth: 1,
+          strokeColor: "#ff000066",
+          fillColor: "#ff000016",
+        },
+      ],
+      disable: false,
+      show: false,
+      title: "",
+      address: "",
+      longitude: "",
+      latitude: "",
+      imageSrc: "/static/logo.png", //自定义图片
+      marker: {
+        id: 1,
+        height: 50,
+        width: 40,
+        // iconPath: '/static/comm/position.png'
+      },
+      // mapKey: '42795f9a59358dea58a8bxxx',//高德地图测试key
+      mapKey: "ZNJBZ-E6RHJ-EV3F2-DL73K-ARTTH-3EBRZ", //腾讯地图测试key
+      // mapKey: 'p5mGzPEt30bwv1yEkeQGsGP4Xrs9xxxx', //百度地图
+      mapType: "tmap", // tmap bmap amap
+    };
+  },
+  onLoad() {},
+  methods: {
+    changeMarker(e) {
+      const { latitude, longitude } = e;
+      const _polygons = this.polygons.map((polygon) => {
+        return polygon.points.map((i) => [
+          Number(i.longitude),
+          Number(i.latitude),
+        ]);
+      });
+      const _point = point([longitude, latitude]);
+      const _polygon = polygon(_polygons);
+      // 根据电子围栏判断否禁用
+      this.disable = booleanPointInPolygon(_point, _polygon);
+    },
+    onClick() {
+      this.show = true;
+    },
+    confirm(e) {
+      if (e) {
+        this.longitude = e.longitude;
+        this.latitude = e.latitude;
+        this.title = e.title;
+        this.address = e.address;
+      }
+      this.show = false;
+    },
+  },
+};
+```
+
+### 预览
+
+![预览图片1](https://raw.githubusercontent.com/13982720426/uniapp-plugin-atl-map/master/static/map1.png)
+![预览图片2](https://raw.githubusercontent.com/13982720426/uniapp-plugin-atl-map/master/static/map2.png)
+![预览图片3](https://raw.githubusercontent.com/13982720426/uniapp-plugin-atl-map/master/static/map3.png)
+
+## API
+
+### Props
+
+| 参数				| 说明																																																																																																								| 类型								| 默认值																																															|
+| ------------| -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------	| ----------				| -------------------------------------------------------------------------------------------------	|
+| mapKey			| <span style="color: red">`必填`</span>,地图 KEY																																																																																		| `String`					| 腾讯测试 key(每日限量)																																							|
+| mapType			| `非必填`,地图类型(腾讯:'tmap',高德:'amap',百度:'bmap')																																																																															| `String`					| tmap																																															|
+| longitude		| `非必填`,经度																																																																																																			| `String`					| 当前定位																																														|
+| latitude		| `非必填`,纬度																																																																																																			| `String`					| 当前定位																																														|
+| marker			| `非必填`,点位配置,只支持一个点位																																																																																									| `Object`					| [uniapp map 组件](https://uniapp.dcloud.net.cn/component/map.html#marker)默认值										|
+| disable			| `非必填`,确定按钮是否禁用																																																																																													| `Boolean`					| false																																															|
+| isPolygons	| `非必填`,是否显示多边形(电子围栏)																																																																																									| `Boolean`					| false																																															|
+| polygons		| `非必填`,多边形配置(具体配置请看案例或者官网说明)																																																																																		| `Array`						| `[]`,[uniapp map 组件](https://uniapp.dcloud.net.cn/component/map.html#marker) polygons 配置说明	|
+| isCustomBar	| `非必填`,是否自定义顶部(一般自定义顶部标题栏时使用)																																																																																	| `Boolean`					| false	(自定义顶部标题栏时留出[胶囊按钮](https://uniapp.dcloud.net.cn/api/ui/menuButton.html#getmenubuttonboundingclientrect)安全距离)																																														|
+| top					| `非必填`,地图距离顶部位置(一般自定义顶部标题栏时使用)																																																																																| `String`、`Number`	| 原生标题栏时,默认值:0,`"navigationStyle": "custom"`为自定义标题栏时,默认值:30											|
+| changeMarker| `非必填`,点位变化事件(可以通过 [turf](https://turfjs.fenxianglu.cn/category/booleans/booleanPointInPolygon.html#booleanpointinpolygon) 插件判断是否在电子围栏内,再配合 disable 属性使用,具体使用参考完整 demo)			| `Function`				| 返回值`{title,latitude,longitude,address,...高德/腾讯/百度地图其他参数}`														|
+| confirm			| `非必填`,点击确定事件																																																																																															| `Function`				| 返回值`{title,latitude,longitude,address,...高德/腾讯/百度地图其他参数}`														|
+
+### Solt
+
+| 名称		| 说明									| 其他																																																												|
+| -------	| -------------------	| --------------------------------------------------------------------------------------------------------------------------|
+| content	| 自定义 content 内容	| 使用的是 uniapp [cover-view 组件](https://uniapp.dcloud.net.cn/component/cover-view.html#cover-view)小程序注意事项请看官网		|
+
+## 注意事项
+
+1. [腾讯地图 key](https://lbs.qq.com/dev/console/application/mine) 每日限量测试,请自行申请
+2. 目前只支持微信小程序,其他平台请下载源码自行测试修改[github 地址](https://github.com/13982720426/uniapp-plugin-atl-map.git)
+3. 本项目使用 vue2 语法,vue3 也支持
+4. 微信小程序可能需要设置服务器域名,[登录小程序平台](https://mp.weixin.qq.com/wxamp/index/index) 服务器域名 -> request 合法域名(填入用到的平台域名 `https://api.map.baidu.com;https://apis.map.qq.com;https://restapi.amap.com;`
+5. 百度地图如果遇到接口返回 `APP Referer校验失败`,在[百度地图控制台](https://lbs.baidu.com/apiconsole/key/create#/home) 删除当前应用,重新创建应用并在 APP ID 填 `*` [参考链接](https://blog.csdn.net/m0_73504190/article/details/131420444)
+6. 如果点击地图没有查出数据,请查看微信开发者工具控制台网络(Network),是否有查询接口返回`{"status":200,"message":"APP不存在,AK有误请检查再重试"}、{"status":"0","info":"INVALID_USER_KEY","infocode":"10001"}、{"status": 311, "message": "key格式错误"}`等类似响应数据,多数是地图 key 的问题,更多状态码查看对应地图平台状态码说明文档
+7. 完整示例项目使用到了电子围栏,booleanPointInPolygon 等方法使用到了第三方插件,所以下载完整示例项目之后需要 `npm i`安装相应依赖,只下载插件非完整示例项目可以忽略
+
+## 优化
+
+开发初衷是为了能够支持各平台地图,满足需要不同地图的开发者,但是这会产生其他问题。一个项目一般情况下只用一个平台,没有用到的组件和 SDK 导致代码冗余,占用内存
+
+所以在设计的时候就将`<atl-map />`组件设计为一个入口组件,`<amap />`、`<tmap />`、`<bmap/>`为独立的子组件,可插拔。简而言之就是每个子组件可以单独使用,删除不用的组件可以减少体积。
+
+推荐选定自己使用的平台之后,删除其他不用的组件和 SDK。
+
+比如:只用腾讯地图,删除其他地图组件,在`uni_modules/atl-map/components` 下,删除 bmap、amap 文件夹,修改入口文件`atl-map.vue`,只用`tmap`组件
+
+```vue
+<template>
+  <view>
+    <tmap
+      v-else
+      :disable="disable"
+      :longitude="longitude"
+      :latitude="latitude"
+      :mapKey="mapKey"
+      :marker="marker"
+      @confirm="confirm"
+      @changeMarker="changeMarker"
+      :polygons="polygons"
+      :isPolygons="isPolygons"
+    >
+      <template v-slot:content>
+        <slot name="content"></slot>
+      </template>
+    </tmap>
+  </view>
+</template>
+```
+
+js 只引入和注册`tmap`组件
+
+```js
+<script>
+import tmap from '../tmap/tmap.vue';
+
+	...
+	components: {
+		tmap,
+	},
+	...
+<script />
+```
+
+这样就减少冗余代码,节省内存
+
+## 更新记录
+
+[查看日志](https://github.com/13982720426/uniapp-plugin-atl-map/blob/master/uni_modules/atl-map/changelog.md)