概要
项目需求是完成一个随手拍功能,拍照与上传图片功能简单,只写地图模块功能。
效果展示
文件目录结构
技术栈
- uniapp
- vue2
- 腾讯地图api
- qq地图转换经纬度
技术实现
1.index.vue文件代码
<template>
<view class="form">
<view class="top-bar">
<view class="top"></view>
<view class="title">
<view class="to-return" @click="toHome"></view>
随手拍
</view>
</view>
<view class="form-container">
<uni-forms ref="form" :modelValue="formData" validate-trigger="bind:confirm" label-position="top"
label-width="300rpx">
<uni-forms-item class="upload-item" label="上传图片">
<view class="picture">
<!-- <span style="color:red;">*</span> -->
<!-- <view>上传图片</view> -->
<view class="tips" @click="showModal = true"></view>
</view>
<!-- 弹窗和遮罩 -->
<view v-if="showModal" class="modal-wrapper">
<view class="modal">
<!-- 这里放置弹窗内容 -->
<view class="pic-title">说明</view>
<view class="pic-tips">
<view>支持扩展名:jpg/png</view>
<view>文件大小不得超过50MB</view>
<view>最多支持6张图片</view>
</view>
<button class="button" @click="showModal = false">关闭</button>
</view>
<view class="overlay"></view>
</view>
<uni-file-picker class="pic-pick" v-model="formData.picture" file-mediatype="image"
file-extname="png,jpg" limit="6" mode="grid" @select="select"
@delete="deleteFile"></uni-file-picker>
</uni-forms-item>
<uni-forms-item label="主题分类" name="themeType" required>
<view>
<picker style="height: 80rpx;" aria-placeholder="qing" @change="PickerJob"
v-model="formData.themeType" :range="JobList">
<view class="picker">
{{ formData.themeType ? JobList[formData.themeType] : "请选择主题分类"}}
</view>
</picker>
</view>
</uni-forms-item>
<uni-forms-item label="描述" name="describes" required>
<uni-easyinput type="textarea" maxlength="500" v-model="formData.describes" placeholder="请输入内容" />
<view style="text-align: right;">{{ formData.describes.length }}/500</view>
</uni-forms-item>
<view class="add-box">
<view>位置</view>
<view class="select" @click="openMap">
<img src="test.jpg" alt="">
重新选择
</view>
</view>
<map style="width: 100%; height: 262px;" :latitude="latitude" :longitude="longitude"
:markers="markers"></map>
<view class="add-box1">
<view>详细地址</view>
<view class="address">{{ formData.address }}</view>
</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>
</uni-forms>
<button style="background-color: #BC162C;margin-top: 20rpx;" type="primary"
@click="submit('form')">提交</button>
</view>
</view>
</template>
<script>
import {
create,
} from '@/api/suishoupai'
import config from '@/config'
import {
atlMap
} from './map/map.vue'
import {
getAccessToken
} from '@/utils/auth'
import {
getDictData
} from '@/api/evaluate/index.js'
var QQMapWX = require('@/utils/qqmap-wx-jssdk.js')
export default {
props: {
type: {
type: [String],
default: '0'
},
stationId: {
type: [String],
default: '0'
},
personId: {
type: [String],
default: '0'
}
},
computed: {
// resultCountry(){
// return this.countryName.join(",");
// }
},
components: {
atlMap
},
data() {
return {
show: false,
imageSrc: '/static/logo.png', //自定义图片
marker: {
id: 0,
latitude: 34.229121,
longitude: 108.899874,
width: 20,
height: 35
// iconPath: '/static/comm/position.png'
},
// mapKey: '42795f9a59358dea58a8bxxx',//高德地图测试key
mapKey: '', //腾讯地图测试key
mapType: 'tmap', // tmap bmap amap
showModal: false, // 控制是否显示弹窗
JobList: [],
JobListId: [],
modalName: null,
addressData: {
value: 0,
jobName: "",
},
dict1: {
dictType: 'theme_type'
},
webView: false,
barTitle: undefined,
id: 1, // 使用 marker点击事件 需要填写id
title: 'map',
latitude: 34.229121,
longitude: 108.899874,
markers: [],
options: ['分类1', '分类2', '分类3'], // 你的字典数据
selectedIndex: "", // 默认选中的索引
formData: {
themeType: "",
describes: '',
picture: null,
longitude: "",
latitude: "",
address: ""
},
rules: {
themeType: {
rules: [{
required: true,
errorMessage: '请选择主题分类'
}]
},
picture: {
rules: [{
required: true,
errorMessage: '请上传图片'
}]
},
describes: {
rules: [{
required: true,
errorMessage: '内容不能为空'
}]
},
},
fileList: [],
stationUsers: [],
multiArray: [
[],
[],
[]
],
multiIndex: [0, 0, 0],
area0: [],
area1: [],
area2: [],
ischeck: false,
stationList: [1, 23, 3],
station: undefined
}
},
onTabItemTap(e) {
// this.formData.picture = ''
this.$tab.reLaunch('/pages/carma/index')
},
onShow() {
// this.init()
// console.log(this.formData,this.formData.picture);
// if (this.fileList.length != 0) {
// this.formData.picture = ''
// }
// this.formData={
// themeType:"",
// describes: '',
// picture: null,
// longitude:"",
// latitude:"",
// address:""
// }
// this.hideTab()
},
onReady() {
// this.refreshPage();
// 使用this.$refs访问表单元素,并调用resetFields方法重置
// if (this.$refs.form) {
// this.$refs.form.resetFields();
// }
this.formData.latitude = this.latitude
this.formData.longitude = this.longitude
this.$refs.form.setRules(this.rules)
if (this.formData != {}) {
this.markers.push({
id: 0,
width: 20,
height: 35,
latitude: this.latitude,
longitude: this.longitude
})
this.getGeolocationName(this.latitude, this.longitude)
}
// console.log(this.formData.address,this.address);
// this.getLocation()
let p2 = this.getDict(this.dict1)
// console.log(p2);
Promise.all([p2]).then(result => {
// console.log(result,'22222222');
// this.getInfo()
})
},
onload() {
// uni.reLaunch();
// this.getLocation()
},
beforeUnmount() {
// console.log(11111)
// this.formData.picture = ''
},
mounted() {
this.init()
// console.log(this.type, this.stationId, this.personId);
if (this.type == '0') {
this.formData.affiliatedContactStationId = this.stationId
this.formData.messageRecipientId = this.personId
}
let params = {
type: 1,
localtionCode: 610400
}
// this.getList(params,0)
},
methods: {
refreshPage() {
// 刷新页面的操作
this.$tab.reLaunch('/pages/carma/index')
},
init() {
uni.getLocation({
type: 'gcj02',
geocode: true, // 是否需要解析地址信息
success: (res) => {
var latitude = res.latitude;
var longitude = res.longitude;
console.log("经度:" + longitude);
console.log("纬度:" + latitude);
this.longitude = longitude;
this.latitude = latitude;
this.getGeolocationName(this.latitude, this.longitude)
const index = this.markers.findIndex(marker => marker.id === 0);
// 更新该元素
if (index !== -1) {
this.markers[index] = {
...this.markers[index],
latitude: latitude,
longitude: longitude
};
}
},
fail: (err) => {
console.log("获取位置失败:" + err.errMsg);
}
});
},
resetForm() {
this.form = {
themeType: "",
describes: '',
picture: null,
};
},
toHome() {
// 跳转到 tabbar 中的其他页面
this.$tab.reLaunch('/pages/index')
this.showTab()
},
hideTab() {
//隐藏
uni.hideTabBar({
animation: true,
success() {
console.debug('隐藏成功')
}
})
},
showTab() {
//显示
uni.showTabBar({
animation: true,
success() {
console.debug('显示成功')
}
})
},
openMap() {
this.show = true;
},
confirm(e) {
if (e) {
this.longitude = e.longitude;
this.latitude = e.latitude;
this.formData.longitude = e.longitude;
this.formData.latitude = e.latitude;
this.title = e.title;
this.address = e.address;
this.formData.addressInfo = e.address
const index = this.markers.findIndex(marker => marker.id === 0);
// 更新该元素
if (index !== -1) {
this.markers[index] = {
...this.markers[index],
latitude: e.latitude,
longitude: e.longitude
};
}
this.formData.address = e.address
// console.log(e.latitude,e.longitude,'000000000');
// this.marker.latitude=e.latitude
// this.marker.longitude=e.longitude
}
this.show = false;
},
// getMapLocation(){
// uni.chooseLocation({
// success:(res)=> {
// // console.log(res);
// // this.getRegionFn(res);
// },
// fail:()=>{
// // 如果用uni.chooseLocation没有获取到地理位置,则需要获取当前的授权信息,判断是否有地理授权信息
// uni.getSetting({
// success: (res) => {
// console.log(res);
// var status = res.authSetting;
// if(!status['scope.userLocation']){
// // 如果授权信息中没有地理位置的授权,则需要弹窗提示用户需要授权地理信息
// uni.showModal({
// title:"是否授权当前位置",
// content:"需要获取您的地理位置,请确认授权,否则地图功能将无法使用",
// success:(tip)=>{
// if(tip.confirm){
// // 如果用户同意授权地理信息,则打开授权设置页面,判断用户的操作
// uni.openSetting({
// success:(data)=>{
// // 如果用户授权了地理信息在,则提示授权成功
// if(data.authSetting['scope.userLocation']===true){
// uni.showToast({
// title:"授权成功",
// icon:"success",
// duration:1000
// })
// // 授权成功后,然后再次chooseLocation获取信息
// uni.chooseLocation({
// success: (res) => {
// console.log("详细地址",res);
// // this.getRegionFn(res);
// }
// })
// }else{
// uni.showToast({
// title:"授权失败",
// icon:"none",
// duration:1000
// })
// }
// }
// })
// }
// }
// })
// }
// },
// fail: (res) => {
// uni.showToast({
// title:"调用授权窗口失败",
// icon:"none",
// duration:1000
// })
// }
// })
// }
// });
// },
PickerJob(e) {
// console.log(e)
this.formData.themeType = e.detail.value
this.addressData.value = e.detail.value
this.addressData.jobName = this.JobListId.filter(a => a.value == e.detail.value)[0].jobName
},
getDict(val) {
const parmas = {
pageNum: 1,
pageSize: 500,
...val
}
return new Promise((resolve, reject) => {
getDictData(parmas).then(res => {
// console.log(res,'09999999');
switch (parmas.dictType) {
// case 'performance_project':
// this.projectList = res.data.list
// resolve(this.projectList)
// break;
case 'theme_type':
this.JobListId = res.data.list;
this.JobList = res.data.list.map(a => a.label);
resolve(this.JobList)
break;
default:
break;
}
})
})
},
// 经纬度转换地址信息
async getGeolocationName(latitude, longitude) {
// console.log(latitude,longitude);
var qqmapsdk
// 实例化API核心类
qqmapsdk = new QQMapWX({
key: ''
});
qqmapsdk.reverseGeocoder({
location: {
latitude: latitude,
longitude: longitude
},
success: (res) => {
const address = res.result.address
this.formData.address = address
// console.log('reverseGeocoder', res)
},
fail: (err) => {
console.log('reverseGeocoder', err)
}
})
},
// 点击地图
// tap(e) {
// console.log(e)
// if (this.markers.length == 0) {
// this.markers.push({
// latitude: e.detail.latitude,
// longitude: e.detail.longitude
// })
// } else {
// this.markers[0].latitude = e.detail.latitude
// this.markers[0].longitude = e.detail.longitude
// }
// this.getGeolocationName(e.detail.latitude, e.detail.longitude)
// },
// 经纬度转换地址信息
// getGeolocationName(latitude, longitude) {
// console.log(latitude,longitude);
// var qqmapsdk
// // 实例化API核心类
// qqmapsdk = new QQMapWX({
// key: ''
// });
// qqmapsdk.reverseGeocoder({
// location: {
// latitude: latitude,
// longitude: longitude
// },
// success: (res) => {
// this.address=res.result.address
// console.log('reverseGeocoder', res)
// },
// fail: (err) => {
// console.log('reverseGeocoder', err)
// }
// })
// },
gotoMap() {
this.$tab.navigateTo(`/pagesC/carma/components/map/map`)
},
// 获取当前经纬度
getLocation() {
// 保存外部作用域的 this
let that = this;
// 获取用户是否开启授权获取当前地理位置的权限
uni.getSetting({
success(res) {
// 如果没有授权
if (!res.authSetting['scope.userLocation']) {
// 拉起授权窗口
uni.authorize({
scope: 'scope.userLocation',
success() {
// 用户同意授权
uni.getLocation({
type: 'gcj02',
success: (res) => {
// 更新外部作用域的经纬度信息
that.longitude = res.data.longitude;
that.latitude = res.data.latitude;
that.markers.push({
latitude: res.data.latitude,
longitude: res.data.longitude
})
// 调用获取地理位置名称并设置标记的方法
that.getGeolocationName(that.longitude, that
.latitude);
// 显示经纬度信息
uni.showToast({
title: '当前位置的经纬度:' + res.longitude +
',' + res.latitude,
icon: 'success',
mask: true
});
},
fail(error) {
console.log('失败', error);
}
});
},
fail(error) {
// 用户拒绝授权
console.log('拒绝授权', error);
// 可以在这里进行相关处理
}
});
} else {
// 用户已授权,直接获取位置信息
uni.getLocation({
type: 'gcj02',
success: (res) => {
// 更新外部作用域的经纬度信息
that.longitude = res.data.longitude;
that.latitude = res.data.latitude;
that.markers.push({
latitude: res.data.latitude,
longitude: res.data.longitude
})
// 调用获取地理位置名称并设置标记的方法
that.getGeolocationName(that.longitude, that.latitude);
// 可以在这里进行其他操作,比如显示经纬度信息
},
fail(error) {
console.log('失败', error);
}
});
}
}
});
},
handleSelect(event) {
this.selectedIndex = event.detail.value;
this.formData.themeType = this.selectedIndex
},
getListSui(params, val) {
// console.log(params)
getList().then(res => {
// console.log(res);
// console.log('stationList....',res)
// this.stationList = this.handleTree(res.data,'areaId')
// console.log('stationList',this.stationList)
})
},
onchange(e) {
// console.log(e,this.station)
this.formData.affiliatedContactStationId = e.detail.value[e.detail.value.length - 1].value
this.formData.affiliatedContactStationName = e.detail.value[e.detail.value.length - 1].text
let params = {
stationId: this.formData.affiliatedContactStationId
}
getStationUsers(params).then(res => {
// console.log(res)
this.stationUsers = res.data
})
},
onchangeUser(e) {
// console.log(e)
this.formData.messageRecipientId = e.detail.value[0].value
this.formData.messageRecipientName = e.detail.value[0].text
},
bindPickerChange(e) {
this.ischeck = true
// console.log(e)
if (this.multiArray[2][this.multiIndex[2]].id) {
this.formData.affiliatedContactStationId = this.multiArray[2][this.multiIndex[2]].id
this.formData.affiliatedContactStationName = this.multiArray[2][this.multiIndex[2]].locationName
} else if (this.multiArray[1][this.multiIndex[1]].id) {
this.formData.affiliatedContactStationId = this.multiArray[1][this.multiIndex[1]].id
this.formData.affiliatedContactStationName = this.multiArray[1][this.multiIndex[1]].locationName
} else if (this.multiArray[0][this.multiIndex[0]].id) {
this.formData.affiliatedContactStationId = this.multiArray[2][this.multiIndex[2]].id
this.formData.affiliatedContactStationName = this.multiArray[0][this.multiIndex[0]].locationName
}
let params = {
stationId: this.formData.affiliatedContactStationId
}
getStationUsers(params).then(res => {
// console.log(res)
this.stationUsers = res.data
})
},
bindChangeUser(e) {
// console.log(e)
// console.log(this.stationUsers[e.detail.value])
this.formData.messageRecipientId = this.stationUsers[e.detail.value].representativeId
this.formData.messageRecipientName = this.stationUsers[e.detail.value].representativeName
},
// bindColumnChange(e) {
// console.log(e)
// switch (e.detail.column) {
// case 0: //拖动第1列
// let params = {
// type:1,
// localtionCode:this.area0[e.detail.value].localtionCode
// }
// this.getList(params,1)
// break;
// case 1: //拖动第2列
// let params1 = {
// type:1,
// localtionCode:this.area1[e.detail.value].localtionCode
// }
// this.getList(params1,2)
// break;
// }
// // this.$forceUpdate();
// },
// 获取上传状态
select(e) {
// console.log('选择文件:', e)
const tempFilePaths = e.tempFilePaths;
tempFilePaths.forEach(item => {
uni.uploadFile({
url: config.baseUrl + config.baseApi + '/infra/file/uploadRandomClapping',
filePath: item,
name: 'file',
fileType: 'image',
header: {
'content-type': 'multipart/form-data',
'Tenant-Id': 1
},
success: (res) => {
res.data = JSON.parse(res.data)
// console.log(res.data);
let arr = {
extname: res.data.data.name,
id: res.data.data.id,
name: res.data.data.name,
url: res.data.data.url
}
this.fileList.push(arr)
// console.log(this.fileList)
}
});
})
},
deleteFile(e) {
// console.log(e)
this.fileList = this.fileList.filter(item => item.name != e.tempFile.name)
// console.log(this.fileList)
},
async submit(form) {
let validateStatus = await this.$refs[form].validate();
// console.log(validateStatus,'validateStatus')
if (!validateStatus) return;
this.$refs.form.validate().then(res => {
// console.log('success', res);
// console.log(this.formData)
// uni.showToast({
// title: `校验通过`
// })
if (this.fileList.length != 0) {
this.formData.picture = JSON.stringify(this.fileList.map(item => item.url))
}
// console.log(this.formData)
create(this.formData).then(res1 => {
// console.log(res1)
if (res1.code == 0) {
uni.showToast({
title: `提交成功`
})
this.$tab.navigateTo('/pagesD/submitOK/index')
// this.$tab.reLaunch(`/pages/index`)
// this.formData={}
// uni.navigateBack()
}
})
}).catch(err => {
console.log('err', err);
})
},
handleTree(data, areaId, parentId, children, rootId) {
areaId = areaId || 'areaId'
parentId = parentId || 'parentId'
children = children || 'children'
rootId = rootId || Math.min.apply(Math, data.map(item => {
return item[parentId]
})) || 0
//对源数据深度克隆
const cloneData = JSON.parse(JSON.stringify(data))
//循环所有项
const treeData = cloneData.filter(father => {
let branchArr = cloneData.filter(child => {
//返回每一项的子级数组
return father[areaId] == child[parentId]
});
branchArr.length > 0 ? father.children = branchArr : '';
//返回第一层
return father[parentId] == rootId;
});
return treeData != '' ? treeData : data;
}
}
}
</script>
<style lang="scss" scoped>
.form {
// background-color: #ffffff;
/* 根据需要添加样式 */
.top-bar {
position: fixed;
top: 0;
text-align: center;
width: 100%;
height: 88rpx;
font-family: PingFang SC, PingFang SC;
font-weight: 500;
font-style: normal;
text-transform: none;
color: #ffffff;
background-color: #BC162C;
z-index: 1;
.top {
height: 46rpx;
}
.title {
text-align: center;
height: 88rpx;
background-color: #BC162C;
position: relative;
line-height: 30rpx;
font-family: PingFang SC, PingFang SC;
font-weight: 500;
font-style: normal;
text-transform: none;
color: #ffffff;
.to-title {}
.to-return {
width: 36rpx;
height: 36rpx;
margin-top: 40rpx;
text-align: left;
color: white;
font-size: 34rpx;
margin-left: 10rpx;
background-image: url('/static/images/return.png');
background-size: cover;
position: relative;
top: 20%;
z-index: 3;
}
}
}
.form-container {
width: 94%;
margin: auto;
padding: 24rpx;
margin-top: 24rpx;
padding-top: 0rpx;
border-radius: 16rpx 16rpx 16rpx 16rpx;
background-color: #ffffff;
margin-top: 200rpx;
::v-deep {
.custom-file-picker {
// 隐藏增加按钮
.uni-file-picker__box-content.is-add {
display: none;
}
// 隐藏删除按钮
.uni-file-picker__box-content.is-delete {
display: none;
}
}
// 在你的组件中使用自定义样式类 custom-file-picker
.pic-pick {
@extend .custom-file-picker;
}
.uni-forms-item {
margin-bottom: 20rpx
/* 设置底部间距为 10rpx,可以根据需要自行调整 */
}
}
}
.add-box {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 30rpx;
margin-bottom: 30rpx;
font-size: 28rpx;
.address {
color: #898989;
}
&:nth-col {
margin-top: -20rpx;
}
.select {
width: 152rpx;
height: 48rpx;
display: flex;
align-items: center;
color: #BC162C;
img {
width: 28rpx;
height: 28rpx;
line-height: 48rpx;
}
}
}
.add-box1 {
margin-top: 20rpx;
.address {
color: #898989 !important;
}
}
.upload-item {
display: flex;
justify-content: space-between;
align-items: center;
}
.picture {
flex: 1;
width: 160rpx;
display: flex;
justify-content: space-between;
margin-bottom: 20rpx;
margin-top: -40rpx;
align-items: center;
.tips {
position: absolute;
left: 130rpx;
top: -60rpx;
width: 32rpx;
height: 32rpx;
background: url('test.jpg') 100% 100% no-repeat;
background-size: cover;
}
}
/* 弹窗样式 */
.modal-wrapper {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
z-index: 999;
/* 确保弹窗在最顶层 */
}
.modal {
width: 490rpx;
height: 320rpx;
background: #FFFFFF;
border-radius: 16rpx 16rpx 16rpx 16rpx;
padding: 20px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.5);
z-index: 888;
.pic-title {
width: 48rpx;
height: 24rpx;
font-family: PingFang SC, PingFang SC;
font-weight: 400;
font-size: 24rpx;
color: #BC162C;
line-height: 24rpx;
text-align: left;
font-style: normal;
text-transform: none;
margin-bottom: 24rpx;
}
.pic-tips {
width: 426rpx;
height: 108rpx;
font-family: PingFang SC, PingFang SC;
font-weight: 400;
font-size: 20rpx;
color: #BC162C;
line-height: 36rpx;
text-align: left;
font-style: normal;
text-transform: none;
margin-bottom: 34rpx;
}
.button {
line-height: 64rpx;
width: 426rpx;
height: 64rpx;
background: #FFE3E3;
border-radius: 8rpx 8rpx 8rpx 8rpx;
color: #BC162C;
}
}
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
/* 半透明黑色 */
z-index: 1;
/* 确保遮罩在弹窗下面 */
}
.picker {
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
cursor: pointer;
font-size: 14px;
/* 调整字体大小 */
}
.cu-form-group {
.title {
min-width: calc(4em + 15px);
}
}
/* 修改确定按钮的颜色 */
.picker ::after {
color: blue;
/* 蓝色 */
}
.greater-than {
width: 24rpx;
height: 24rpx;
line-height: 24rpx;
}
}
</style>
注*. mapKey: '', //这个自己注册一个腾讯地图的key
2.map.vue
<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:[]">
<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() {
// this.qqmapsdk = new QQMapWX({
// key: this.key
// });
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();
}
});
},
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: 250rpx;
display: flex;
justify-content: space-between;
align-items: flex-end;
padding: 10rpx 40rpx;
box-sizing: border-box;
background-color: rgba(0, 0, 0, 0.1);
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>