tm-mapSelectedPoint.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. <template>
  2. <view class="tm-mapSelectedPoint" :class="[black_tmeme?'grey-darken-5':'']">
  3. <map :scale="mapscale" id="MapTm" ref="MapTm" @regionchange="moveMapChange" :markers="markers" :latitude="mapCenter.lat" :longitude="mapCenter.lng" :style="{width:`${width}rpx`,height:`400rpx`}"></map>
  4. <view class=" pa-32 ">
  5. <view class="tm-mapSelectedPoint-contr">
  6. <view class="pb-32"><text class=" text-size-n fulled text-overflow-1">当前:{{adress.adress||"获取失败,请移动地图选择"}}</text></view>
  7. <view class="flex-between pb-10">
  8. <tm-button @click="confirm" block height="80" style="width:60%">确认位置</tm-button>
  9. <view style="width:35%" class="flex-shrink">
  10. <tm-button :black="black_tmeme" :fllowTheme="fllowTheme" :theme="color_tmeme" @click="getLocation" text block height="80" icon="icon-position-fill">定位当前</tm-button>
  11. </view>
  12. </view>
  13. </view>
  14. <view v-if="adressList.length>0" class="grey-lighten-5 px-24 round-6 mt-32" :class="[black_tmeme?'bk grey-darken-4':'']">
  15. <scroll-view scroll-y :style="{height: scrollHeight+'px'}">
  16. <view @click="selecListitem(item)" v-for="(item,index) in adressList" :key="index" :class="[black_tmeme?'bk':'']" class="py-24 border-b-1 flex-between">
  17. <view class="mr-32">
  18. <view class="pb-12"> {{item.name}}</view>
  19. <view class="text-size-s text-grey">{{item.address}}</view>
  20. </view>
  21. <view class="flex-shrink">
  22. <tm-icons :black="black_tmeme" :fllowTheme="fllowTheme" :color="color_tmeme" size="40" v-if="activeId == item.id" name="icon-check-circle"></tm-icons>
  23. </view>
  24. </view>
  25. </scroll-view>
  26. </view>
  27. </view>
  28. </view>
  29. </template>
  30. <script>
  31. /**
  32. * 地图选点
  33. * @property {Boolean|String} black = [true|false] 默认null,是否开启暗黑模式
  34. * @property {String} color = [] 主题默认:primary,提供是请写主题色名称
  35. * @property {String} map-key = [] 地图key:默认为作者测试的,用户不要使用我的,否则会被限制,key作废。
  36. * @property {String} map-type = [] 地图类型:qq,qq,baidu,amp高德。
  37. * @property {Number} scale = [] 默认:14,地图绽放级别5-18
  38. * @property {Number} width = [] 默认:700,组件的宽度。
  39. * @property {Number} height = [] 默认:1200,组件的高度。
  40. * @property {Object} location = [] 默认:{latitude:39.908823,longitude:116.39747},默认的定位点,北京。
  41. * @property {Function} confirm 点击确认位置按钮时返回当前定位资料信息。
  42. * @property {Function} change 当移动地图时的位置信息,返回的结构同confirm
  43. */
  44. import tmButton from '@/tm-vuetify/components/tm-button/tm-button.vue';
  45. import tmIcons from '@/tm-vuetify/components/tm-icons/tm-icons.vue';
  46. export default {
  47. name:"tm-mapSelectedPoint",
  48. components:{tmButton,tmIcons},
  49. props:{
  50. width:{
  51. type:Number|String,
  52. default:700
  53. },
  54. height:{
  55. type:Number|String,
  56. default:1200
  57. },
  58. location:{
  59. type:Object,
  60. default:()=>{
  61. return {
  62. latitude:0,
  63. longitude:0
  64. }
  65. }
  66. },
  67. scale:{
  68. type:Number,
  69. default:14
  70. },
  71. // 是否开启暗黑模式
  72. black: {
  73. type: String | Boolean,
  74. default: null
  75. },
  76. color: {
  77. type: String | Array,
  78. default: 'primary'
  79. },
  80. // 跟随主题色的改变而改变。
  81. fllowTheme: {
  82. type: Boolean | String,
  83. default: true
  84. },
  85. mapKey:{
  86. type:String,
  87. default:'U3QBZ-3YIKI-YBEGX-5WURG-5ZQE6-ZGFME'
  88. },
  89. mapType:{
  90. type:String,
  91. default:'qq' //qq,baidu,amp
  92. }
  93. },
  94. watch: {
  95. location:{
  96. deep:true,
  97. async handler(newValue, oldValue) {
  98. this.moveMap(newValue.latitude,newValue.longitude)
  99. await this.moveMarkes(newValue.latitude,newValue.longitude)
  100. }
  101. }
  102. },
  103. data() {
  104. return {
  105. now_latitude:0,
  106. now_longitude:0,
  107. mapCenter:{
  108. lat:0,
  109. lng:0
  110. },
  111. markers:[],
  112. timeid:9566555566,
  113. adressList:[],
  114. adress:{
  115. adress:'',
  116. city:[]
  117. },
  118. scrollHeight:0,
  119. activeId:'',
  120. map:null,
  121. };
  122. },
  123. computed:{
  124. black_tmeme: function() {
  125. if (this.black !== null) return this.black;
  126. return this.$tm.vx.state().tmVuetify.black;
  127. },
  128. color_tmeme: function() {
  129. if (this.$tm.vx.state().tmVuetify.color !== null && this.$tm.vx.state().tmVuetify.color && this
  130. .fllowTheme) {
  131. return this.$tm.vx.state().tmVuetify.color;
  132. }
  133. return this.color;
  134. },
  135. mapscale:function(){
  136. return this.scale;
  137. }
  138. },
  139. created() {
  140. this.now_latitude = this.location.latitude;
  141. this.now_longitude = this.location.longitude;
  142. this.mapCenter = {
  143. lat:this.location.latitude,
  144. lng:this.location.longitude
  145. }
  146. },
  147. async mounted() {
  148. let t = this;
  149. this.map = uni.createMapContext("MapTm", this)
  150. let q = await this.$Querey('.tm-mapSelectedPoint-contr',this).catch(e=>{});
  151. let h = q[0].height||80;
  152. this.scrollHeight = uni.upx2px(this.height) - uni.upx2px(400) - h;
  153. // #ifdef MP
  154. uni.authorize({
  155. scope: 'scope.userLocation',
  156. success() {
  157. t.mapready();
  158. }
  159. })
  160. // #endif
  161. // #ifndef MP
  162. this.$nextTick(async function(){
  163. await uni.$tm.sleep(200)
  164. await this.mapready();
  165. })
  166. // #endif
  167. },
  168. methods: {
  169. moveMap(latitude,longitude){
  170. this.map.moveToLocation({
  171. latitude:latitude,
  172. longitude:longitude
  173. })
  174. },
  175. async mapready(){
  176. let t = this;
  177. // #ifndef H5
  178. uni.getSetting({
  179. success: async (res) => {
  180. if(!res.authSetting['scope.userLocation']){
  181. uni.showModal({
  182. title:"权限受限",
  183. content:"你禁止了位置受限,请打开设置,允许访问地址!否则功能无法使用。",
  184. cancelText:"我已允许",
  185. confirmText:"前往设置",
  186. success: async (rks) => {
  187. if(rks.cancel==true){
  188. await t.getLocation();
  189. return
  190. }
  191. uni.openSetting({})
  192. }
  193. })
  194. return;
  195. }
  196. if(t.mapCenter.lat !==0 && t.mapCenter.lng!==0){
  197. t.markers = [t.createMarker( t.mapCenter.lat ,t.mapCenter.lng)]
  198. await t.poiSidel_byTencentMap(t.mapCenter.lat ,t.mapCenter.lng)
  199. return;
  200. }
  201. await t.getLocation();
  202. },
  203. fail: (res) => {
  204. uni.$tm.toast("系统错误")
  205. }
  206. })
  207. // #endif
  208. // #ifdef H5
  209. if(t.mapCenter.lat !==0 && t.mapCenter.lng!==0){
  210. t.markers = [t.createMarker( t.mapCenter.lat ,t.mapCenter.lng)]
  211. await t.poiSidel_byTencentMap(t.mapCenter.lat ,t.mapCenter.lng)
  212. return;
  213. }
  214. await this.getLocation();
  215. // #endif
  216. },
  217. confirm(){
  218. this.$emit('confirm',{...this.adress,latitude:this.now_latitude,longitude:this.now_longitude})
  219. },
  220. async getLocation() {
  221. let t = this;
  222. //非h5通过GPS定位 。
  223. // #ifndef H5
  224. uni.getSetting({
  225. success: async (res) => {
  226. if(!res.authSetting['scope.userLocation']){
  227. uni.showModal({
  228. title:"权限受限",
  229. content:"你禁止了位置受限,请打开设置,允许访问地址!否则功能无法使用。",
  230. cancelText:"我已允许",
  231. confirmText:"前往设置",
  232. success: async (rks) => {
  233. if(rks.cancel==true){
  234. await t.getLocation();
  235. return
  236. }
  237. uni.openSetting({})
  238. }
  239. })
  240. return;
  241. }
  242. uni.getLocation({
  243. type: 'gcj02', //返回可以用于uni.openLocation的经纬度
  244. success:async function (res) {
  245. const latitude = res.latitude;
  246. const longitude = res.longitude;
  247. t.now_latitude = latitude;
  248. t.now_longitude = longitude;
  249. t.mapCenter = {
  250. lat:latitude,
  251. lng:longitude
  252. }
  253. t.moveMap(t.mapCenter.lat,t.mapCenter.lng)
  254. await t.moveMarkes(latitude,longitude)
  255. //缓存定位点。否则失败,间隔15s小于15秒。不允许调用。
  256. uni.setStorageSync('tmvue_map_selectePoint',{latitude:latitude,longitude:longitude})
  257. },
  258. fail: async (err) => {
  259. let p = uni.getStorageSync('tmvue_map_selectePoint');
  260. try{
  261. if(typeof p == 'object'){
  262. const latitude = p .latitude;
  263. const longitude = p .longitude;
  264. t.now_latitude = latitude;
  265. t.now_longitude = longitude;
  266. t.mapCenter = {
  267. lat:latitude,
  268. lng:longitude
  269. }
  270. t.moveMap(t.mapCenter.lat,t.mapCenter.lng)
  271. await t.moveMarkes(latitude,longitude)
  272. }
  273. }catch(e){
  274. uni.$tm.toast('请间隙至少15s调用,不可频繁定位。')
  275. }
  276. }
  277. });
  278. },
  279. fail: (res) => {
  280. uni.$tm.toast("系统错误")
  281. }
  282. })
  283. // #endif
  284. //h5通过ip定位
  285. // #ifdef H5
  286. uni.showLoading({
  287. mask:true,title:'...'
  288. })
  289. //没有获取到地址资料。通过Ip尝试定位 。
  290. let adressPoiObj = await uni.$tm.request.get("https://apis.map.qq.com/ws/location/v1/ip?key="+this.mapKey).catch(e=>{
  291. uni.hideLoading();
  292. uni.$tm.toast("地址解析错误")
  293. })
  294. if(adressPoiObj['status']==0){
  295. t.now_latitude = adressPoiObj.result.location.lat;
  296. t.now_longitude = adressPoiObj.result.location.lng;
  297. t.map.moveToLocation({
  298. latitude:t.now_latitude,
  299. longitude:t.now_longitude
  300. })
  301. t.moveMap(t.mapCenter.lat,t.mapCenter.lng)
  302. t.markers = [t.createMarker( adressPoiObj.result.location.lat,adressPoiObj.result.location.lng)]
  303. await t.poiSidel_byTencentMap(adressPoiObj.result.location.lat,adressPoiObj.result.location.lng)
  304. }
  305. // #endif
  306. },
  307. createMarker(latitude,longitude){
  308. let id = 636598;
  309. let label = {
  310. content:'',
  311. color:'#000000',
  312. fontSize:12,
  313. bgColor:'red',
  314. padding:5,
  315. textAlign:'center',
  316. }
  317. return {
  318. id:id,
  319. iconPath:'/static/posiimg.png',
  320. width:45,
  321. height:45,
  322. latitude:latitude,
  323. longitude:longitude,
  324. label:label,
  325. }
  326. },
  327. moveMapChange(e){
  328. var etype = ''
  329. // #ifdef APP-PLUS
  330. etype = 'end'
  331. // #endif
  332. // #ifdef MP-WEIXIN
  333. etype = e.type
  334. // #endif
  335. clearTimeout(this.timeid);
  336. if(etype ==='end'){
  337. let t = this;
  338. this.timeid = setTimeout(function() {
  339. t.map.getCenterLocation({
  340. success:async (res)=>{
  341. await t.moveMarkes(res.latitude,res.longitude)
  342. }
  343. })
  344. }, 350);
  345. }
  346. },
  347. async selecListitem(item){
  348. let t = this;
  349. this.$set(this.adress,'adress',item.address)
  350. await this.moveMarkes(item.location.latitude,item.location.longitude)
  351. this.activeId = item.id;
  352. },
  353. async moveMarkes(latitude,longitude,callback){
  354. let t = this;
  355. t.markers = []
  356. await uni.$tm.sleep(50)
  357. if(t.markers.length==0){
  358. t.markers = [t.createMarker( latitude,longitude)]
  359. }
  360. t.now_latitude = latitude;
  361. t.now_longitude = longitude;
  362. t.poiSidel_byTencentMap(latitude,longitude)
  363. },
  364. //mp腾讯地址获取当前地址资料。
  365. async poiSidel_byTencentMap(latitude,longitude){
  366. let t = this;
  367. uni.showLoading({
  368. mask:true,title:'...'
  369. })
  370. let lot=`location=${latitude},${longitude}&get_poi=1&key=${this.mapKey}`
  371. let adressPoiObj = await uni.$tm.request.get("https://apis.map.qq.com/ws/geocoder/v1/?"+lot).catch(e=>{
  372. uni.hideLoading();
  373. uni.$tm.toast("地址解析错误")
  374. })
  375. uni.hideLoading();
  376. if(adressPoiObj.status!==0){
  377. uni.$tm.toast(adressPoiObj.message)
  378. return;
  379. }
  380. let adress = adressPoiObj.result;
  381. this.$set(this.adress,'adress',adress.address)
  382. this.$set(this.adress,'city',[adress.address_component.province,adress.address_component.city,adress.address_component.district]);
  383. this.$emit('change',{...this.adress,latitude:this.now_latitude,longitude:this.now_longitude})
  384. let pos = adress.pois;
  385. if(pos.length==0) return;
  386. let list = [];
  387. for(let i=0;i<pos.length;i++){
  388. list.push({
  389. address:pos[i].address,
  390. name:pos[i].title,
  391. id:pos[i].id,
  392. location:{
  393. latitude:pos[i].location.lat,
  394. longitude:pos[i].location.lng
  395. }
  396. })
  397. }
  398. this.adressList = list;
  399. }
  400. },
  401. }
  402. </script>
  403. <style lang="scss">
  404. </style>