smartswrtch-app/page_fenbao/statulist/nearby/index.vue
2025-01-18 18:01:08 +08:00

906 lines
25 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="page">
<u-navbar title="门店选择" :border-bottom="false" :background="bgc" title-color='#000' back-icon-color="#000"
title-size='44' height='40'></u-navbar>
<view class="serch">
<input type="text" v-model="keyword" @confirm="confirmss" placeholder="搜索门店"/>
<view class="dt" v-if="!dtlbflag" @click="btnlbtop">
<image src="https://api.ccttiot.com/smartmeter/img/static/u2uM05aGZDeVxrdrNmoh" mode=""></image>
地图
</view>
<view class="lb" v-else @click="btndttop">
<image src="https://api.ccttiot.com/smartmeter/img/static/ubAi251bnYEIdAkwJXcA" mode=""></image>
列表
</view>
</view>
<view class="dtxs">
<map class='map' id="map" :latitude="latitude" :longitude="longitude" @markertap="handleMarkerClick"
:show-location="true" :markers="covers" :scale="mapScale" @regionchange="regionchange"/>
<image class="picimg" v-if="iconflag"
src="https://api.ccttiot.com/smartmeter/img/static/uEAmNMMt65U10qwijrsJ" mode=""></image>
</view>
<!-- 0000000000000000000000000000000000000000000 -->
<!-- <view class="listbox" style="background: transparent;" > -->
<view class="list" v-if="listobj.name" @click="btnxqstore">
<view class="pic">
<image :src="listobj.picture.split(',')[0]" mode="aspectFill"></image>
</view>
<view class="cen">
<view class="cena" style="font-weight: 600;">
{{listobj.name}}
</view>
<view class="cenb">
<image src="https://api.ccttiot.com/smartmeter/img/static/uHK2aJHvzEm3nbOPwpdr" mode="aspectFit"></image>
{{listobj.address.length > 15 ? listobj.address.slice(0,13) + '...' :listobj.address}}
</view>
<view class="cenc">
营业时间:{{listobj.businessTimeStart}}-{{listobj.businessTimeEnd}}
</view>
<view class="" style=" display: flex;
align-items: center;
justify-content: space-between;
width: 100%;margin-top: 24rpx;">
<view class="juli">
距我{{listobj.distance}}
</view>
<view class="right">
<image src="https://api.ccttiot.com/smartmeter/img/static/u4Q5lajsFuAv7YEzBFib" mode="aspectFit"
@click.stop="mapFuns(item)"></image>
<image src="https://api.ccttiot.com/smartmeter/img/static/uPeCVStFHIF0rAhMKhlK" mode="aspectFit"
@click.stop="btntel(item)"></image>
</view>
</view>
</view>
</view>
<!-- </view> -->
<!-- 0000000000000000000000000000000000000000000 -->
<view class="listbox" v-if="!dtlbflag">
<view class="list" v-for="(item,index) in gxlist" :key="index">
<view class="pic" @click="btndts(item)">
<image :src="item.picture.split(',')[0]" mode="aspectFill"></image>
</view>
<view class="cen" @click="btndts(item)">
<view class="cena" style="font-weight: 600;">
{{item.name}}
</view>
<view class="cenb">
<image src="https://api.ccttiot.com/smartmeter/img/static/uHK2aJHvzEm3nbOPwpdr" mode="aspectFit"></image>
{{item.address.length > 15 ? item.address.slice(0,13) + '...' :item.address}}
</view>
<view class="cenc">
营业时间{{item.businessTimeStart}}-{{item.businessTimeEnd}}
</view>
<view class="" style=" display: flex;
align-items: center;
justify-content: space-between;
width: 100%;margin-top: 24rpx;">
<view class="juli">
距我{{item.distance}}
</view>
<view class="right">
<image src="https://api.ccttiot.com/smartmeter/img/static/u4Q5lajsFuAv7YEzBFib" mode="aspectFit"
@click.stop="mapFun(item)"></image>
<image src="https://api.ccttiot.com/smartmeter/img/static/uPeCVStFHIF0rAhMKhlK" mode="aspectFit"
@click.stop="btntel(item)"></image>
</view>
</view>
</view>
</view>
<view class="" v-if="gxlist.length == 0" style="width: 100%;height: 200rpx;margin: auto;margin-top: 230rpx;text-align: center;">
<image style="width: 200rpx;height: 200rpx;" src="https://api.ccttiot.com/smartmeter/img/static/uZFUpcz0YZZ4f4RjvGg2" mode="aspectFit"></image>
<view class="" style="font-size: 28rpx;color: #808080;margin-top: 30rpx;">该区域暂无店铺...</view>
</view>
</view>
<view class="saoma" @click="scanQRCode">
<view>
<image src="https://api.ccttiot.com/smartmeter/img/static/uBh15vzRx6gV0wRQj7gi" mode="aspectFit"></image>
扫一扫
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
latitude: '',
longitude: '',
covers: [],
index: 1,
isMch: false,
gxlist: [],
bgc: {
backgroundColor: " #fff",
},
mapScale: 15,
mapContext: null,
mapScaleInterval: null,
listmap: [],
iconflag: false,
dtlbflag:true,
listobj:{},
keyword:''
}
},
onLoad() {
},
onShow() {
this.getshanghu()
},
onReady() {
this.mapContext = uni.createMapContext('map', this)
this.mapScaleInterval = setInterval(this.updateMarkers, 1000)
},
// 分享到好友(会话)
onShareAppMessage: function () {
return {
title: '创想物联',
path: '/pages/shouye/index'
}
},
// 分享到朋友圈
onShareTimeline: function () {
return {
title: '创想物联',
query: '',
path: '/pages/shouye/index'
}
},
beforeDestroy() {
// 在组件卸载前清除定时器
if (this.mapScaleInterval) {
clearInterval(this.mapScaleInterval)
this.mapScaleInterval = null
}
},
methods: {
confirmss(){
this.covers = []
this.gxlist = []
this.$u.get("/app/store/listNearBy?center=" + this.jinweidu + '&radius=' + 20000 + '&keyword=' + this.keyword).then(
response => {
if (response.code == 200) {
this.listmap = response.data
let gxlist = response.data
gxlist.forEach(item => {
const distance = this.getDistance(this.latitude, this.longitude, item.lat, item.lng)
item.distance = distance
const shopCover = {
id: parseFloat(item.storeId),
latitude: item.lat,
longitude: item.lng,
width: 25,
height: 30,
iconPath: 'https://api.ccttiot.com/smartmeter/img/static/uZXgsJE6hXbRSwbKILB4',
distance: distance, // 可以在这里也添加距离到覆盖物对象中,但通常只需要在店铺对象中
label: {
content: item.name,
anchorX: (() => {
if (item.name.length <= 2) {
return -12
} else if (item.name.length <=
3) {
return -20
} else if (item.name.length <=
4) {
return -25
} else if (item.name.length <=
5) {
return -30
} else if (item.name.length <=
6) {
return -35
} else if (item.name.length <=
8) {
return -40
} else if (item.name.length <=
10) {
return -45
} else {
return -item.name.length *
5
}
})(),
fontWeight: 700,
color: '#8883F0',
textShadow: '2px 2px 0px white, -2px -2px 0px white, 2px -2px 0px white, -2px 2px 0px white',
borderRadius:5,
bgColor: '#fff'
}
}
this.covers.push(shopCover)
this.gxlist.push(item)
})
}
})
},
// 扫描二维码
scanQRCode() {
uni.scanCode({
onlyFromCamera: true,
scanType: ['qrCode'],
success: res => {
function getQueryParam(url, paramName) {
let regex = new RegExp(`[?&]${paramName}=([^&]*)`)
let results = regex.exec(url);
return results ? decodeURIComponent(results[1].replace(/\+/g, ' ')) : null
}
let sceneValue = res.result
let decodedValue = decodeURIComponent(sceneValue)
let id = getQueryParam(decodedValue, 's')
let that = this
let data = {
deviceNo: id
}
that.$u.get(`/app/device/isBind?deviceNo=${id}`).then(res => {
if (res.data == 2) {
that.$u.get(`/app/device/${id}/withSuitList`).then((res) => {
if (res.code == 200) {
uni.navigateTo({
url: '/page_components/fuwu/index?id=' + id
})
}
})
} else if (res.data == 1) {
console.log(1);
if(that.phonenumber == ''){
that.huoqutelflag = true
that.xuanzeflag = false
console.log(11);
}else{
console.log(12);
that.xuanzeflag = false
uni.showModal({
title: '提示',
content: '该设备未绑定,你需进行绑定吗?',
success: function(res) {
if (res.confirm) {
that.$u.put("/app/device/bind", data).then(res => {
if (res.code == 200) {
that.$u.get(`/app/device/${id}/bySn`).then((res) => {
if (res.code == 200) {
uni.navigateTo({
url: '/page_components/bindsz?id=' + res.data.deviceId
})
}
})
}
})
}
}
})
}
} else if (res.data == 0) {
uni.showModal({
title: '提示',
content: '该设备未录入,请先进行录入',
success: function(res) {
if (res.confirm) {
// uni.navigateTo({
// url: '/page_fenbao/zhuce?sn=' + id
// })
} else if (res.cancel) {
}
}
})
}
})
},
fail: err => {
console.error('扫描失败:', err)
uni.showToast({
title: '扫描失败',
icon: 'none'
})
}
})
},
// 点击列表显示地图
btnlbtop(){
this.dtlbflag = true
this.listobj = {}
},
// 点击地图显示列表
btndttop(){
this.dtlbflag = false
this.listobj = {}
},
// 点击拨打电话
btntel(item){
uni.makePhoneCall({
phoneNumber: this.listobj.contactMobile,
success: function(res) {
console.log('拨打电话成功', res)
},
fail: function(err) {
console.error('拨打电话失败', err)
uni.showToast({
title: '取消拨打电话',
icon: 'none'
})
}
})
},
// 查询拖动到指定为止的店铺
regionchange(e) {
this.iconflag = true
if (e.type == 'end') {
this.jinweidu = e.detail.centerLocation.longitude + ',' + e.detail.centerLocation.latitude
this.$u.get("/app/store/listNearBy?center=" + this.jinweidu + '&radius=' + 20000).then(res => {
if (res.code == 200) {
this.covers = []
this.listmap = res.data
this.gxlist = res.data
this.gxlist.forEach(item => {
// if (item.deviceCount !== null && item.deviceCount > 0) {
// 计算距离
const distance = this.getDistance(this.latitude, this.longitude, item.lat, item.lng)
// 将距离添加到店铺对象中
item.distance = distance
const shopCover = {
id: parseFloat(item.storeId),
latitude: item.lat,
longitude: item.lng,
width: 25,
height: 30,
iconPath: 'https://api.ccttiot.com/smartmeter/img/static/uZXgsJE6hXbRSwbKILB4',
distance: distance, // 可以在这里也添加距离到覆盖物对象中,但通常只需要在店铺对象中
// iconPath:item.picture
label: {
content: item.name,
anchorX: this.calculateAnchorX(item.name),
fontWeight: 700,
color: '#8883F0',
borderColor: '#fff',
borderRadius: 5,
bgColor: '#fff'
}
}
this.covers.push(shopCover)
// console.log(this.covers);
// }
})
}
})
this.iconflag = false
} else {
// this.iconflag = false
}
},
updateMarkers() {
this.mapContext.getScale({
success: (res) => {
this.covers = [] // 清空之前的覆盖物
if (res.scale <= 14) {
this.addMarkersWithoutLabels()
} else {
this.addMarkersWithLabels()
}
},
fail: (error) => {
console.error('获取地图缩放级别失败:', error)
// 额外的错误处理逻辑...
},
});
},
addMarkersWithoutLabels() {
this.listmap.forEach((item) => {
// if (item.deviceCount !== null && item.deviceCount > 0) {
const shopCover = {
id: parseFloat(item.storeId),
latitude: item.lat,
longitude: item.lng,
width: 25,
height: 30,
iconPath: 'https://api.ccttiot.com/smartmeter/img/static/uZXgsJE6hXbRSwbKILB4',
borderRadius:5,
bgColor: '#fff'
}
this.covers.push(shopCover)
// }
})
},
addMarkersWithLabels() {
this.listmap.forEach((item) => {
// if (item.deviceCount !== null && item.deviceCount > 0) {
const shopCover = {
id: parseFloat(item.storeId),
latitude: item.lat,
longitude: item.lng,
width: 25,
height: 30,
iconPath: 'https://api.ccttiot.com/smartmeter/img/static/uZXgsJE6hXbRSwbKILB4',
label: {
content: item.name,
anchorX: this.calculateAnchorX(item.name),
fontWeight: 700,
color: '#8883F0',
textShadow: '2px 2px 0px white, -2px -2px 0px white, 2px -2px 0px white, -2px 2px 0px white',
borderRadius:5,
bgColor: '#fff'
}
}
this.covers.push(shopCover)
// }
})
},
calculateAnchorX(name) {
let chineseLength = 0
let englishLength = 0
for (let i = 0; i < name.length; i++) {
const charCode = name.charCodeAt(i)
// 判断是否为中文字符(这里简化了判断,只考虑了基本的中文字符范围)
if (charCode >= 0x4e00 && charCode <= 0x9fa5) {
chineseLength++
} else if (/[a-zA-Z]/.test(name[i])) { // 判断是否为英文字符
englishLength = englishLength + 0.3 // 英文长度加1但视为两个中文字符长度
// console.log(englishLength)
}
}
const totalLength = chineseLength + englishLength * 2 // 总长度(以中文字符为单位)
return -totalLength * 6.5 // 假设每个中文字符对应的 anchorX 偏移是 -6.5
},
onControltap(control) {
this.setMapScale()
},
// 地图回正
async setMapScale(e, val) {
let mapContext = uni.createMapContext('map', this);
let setScale = () => {
return new Promise((resolve, reject) => {
mapContext.getScale({
success: r => {
this.mapScale = 15
resolve()
}
})
})
};
await setScale();
mapContext.moveToLocation({
success: (res) => {
const timer = setTimeout(() => {
this.mapScale = 15
clearTimeout(timer)
}, 500)
},
})
},
// 跳转导航
mapFun(item) {
uni.openLocation({
latitude: item.lat,
longitude: item.lng,
name: item.county,
address: item.address
})
},
mapFuns() {
uni.openLocation({
latitude: this.listobj.lat,
longitude: this.listobj.lng,
name: this.listobj.county,
address: this.listobj.address
})
},
getshanghu() {
this.$u.get("/app/user/userInfo").then((res) => {
if (res.code == 200) {
this.isMch = res.data.isMch
}
})
},
getMyLocation() {
uni.getLocation({
type: 'wgs84',
success: (res) => {
this.jinweidu = res.longitude + ',' + res.latitude
this.latitude = Number(res.latitude.toFixed(5)) - 0.005
this.longitude = Number(res.longitude.toFixed(5)) + 0.005
this.setMapScale()
// 请求附近的店铺
this.$u.get("/app/store/listNearBy?center=" + this.jinweidu + '&radius=' + 20000).then(
response => {
if (response.code == 200) {
this.listmap = response.data
let gxlist = response.data
gxlist.forEach(item => {
// if (item.deviceCount !== null && item.deviceCount > 0) {
// 计算距离
const distance = this.getDistance(this.latitude, this.longitude, item.lat, item.lng)
// 将距离添加到店铺对象中
item.distance = distance
// 创建店铺覆盖物对象
const shopCover = {
id: parseFloat(item.storeId),
latitude: item.lat,
longitude: item.lng,
width: 25,
height: 30,
iconPath: 'https://api.ccttiot.com/smartmeter/img/static/uZXgsJE6hXbRSwbKILB4',
distance: distance, // 可以在这里也添加距离到覆盖物对象中,但通常只需要在店铺对象中
label: {
content: item.name,
anchorX: (() => {
if (item.name.length <= 2) {
return -12
} else if (item.name.length <=
3) {
return -20
} else if (item.name.length <=
4) {
return -25
} else if (item.name.length <=
5) {
return -30
} else if (item.name.length <=
6) {
return -35
} else if (item.name.length <=
8) {
return -40
} else if (item.name.length <=
10) {
return -45
} else {
return -item.name.length *
5
}
})(),
fontWeight: 700,
color: '#8883F0',
textShadow: '2px 2px 0px white, -2px -2px 0px white, 2px -2px 0px white, -2px 2px 0px white',
borderRadius:5,
bgColor: '#fff'
}
}
this.covers.push(shopCover)
this.gxlist.push(item)
// }
})
}
}).catch(error => {
console.error('请求店铺列表失败:', error)
})
},
fail: (err) => {
console.error('获取位置失败:', err)
}
});
},
// 计算距离函数
getDistance(lat1, lon1, lat2, lon2) {
const R = 6371000; // 地球半径,单位:米
const phi1 = lat1 * Math.PI / 180; // 纬度转为弧度
const phi2 = lat2 * Math.PI / 180;
const deltaPhi = (lat2 - lat1) * Math.PI / 180;
const deltaLambda = (lon2 - lon1) * Math.PI / 180;
const a = Math.sin(deltaPhi / 2) * Math.sin(deltaPhi / 2) +
Math.cos(phi1) * Math.cos(phi2) *
Math.sin(deltaLambda / 2) * Math.sin(deltaLambda / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
const distance = R * c;
// 判断距离并格式化输出
if (distance > 1000) {
// 大于1000米转换为千米并保留一位小数
return (distance / 1000).toFixed(1) + 'Km';
} else {
// 小于等于1000米直接用米表示
return Math.floor(distance) + 'm';
}
},
handleMarkerClick(event) {
const markerId = event.markerId
// uni.navigateTo({
// url: '/page_user/mapditu/index?markerId=' + markerId
// })
this.$u.get("/app/store/" + markerId).then(res => {
if(res.code == 200){
const distance = this.getDistance(this.latitude, this.longitude, res.data.lat, res.data.lng)
this.listobj = { ...res.data, distance: distance }
}
})
},
btndts(item) {
const markerId = item.storeId
uni.navigateTo({
url: '/page_user/mapditu/index?markerId=' + markerId
})
},
// 点击进入详情
btnxqstore(){
uni.navigateTo({
url: '/page_user/mapditu/index?markerId=' + this.listobj.storeId
})
},
btntab(num) {
this.index = num
},
btndt(num) {
if (num == 1) {
uni.navigateTo({
url: '/page_user/mapditu/index'
})
} else if (num == 2) {
// console.log(111);
uni.switchTab({
url: '/pages/index/index'
})
}
}
},
mounted() {
this.getMyLocation()
}
}
</script>
<style lang="scss">
/deep/ .u-title {
padding-bottom: 2rpx;
}
/deep/ .u-icon__icon {
padding-bottom: 2rpx;
}
/deep/ .map {
width: 100%;
height: 100%;
}
.serch{
width: 100%;
height: 130rpx;
background: #FFFFFF;
padding: 0 18rpx;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: space-between;
input{
width: 630rpx;
height: 78rpx;
line-height: 78rpx;
box-sizing: border-box;
padding-left: 20rpx;
background-color: #F2F3F5;
}
view{
text-align: center;
font-size: 22rpx;
color: #3D3D3D;
width: 60rpx;
image{
width: 42rpx;
height: 42rpx;
}
}
}
page {
background: linear-gradient(180deg, #D9D8FF 0%, rgba(255, 255, 255, 0) 100%);
border-radius: 0rpx 0rpx 0rpx 0rpx;
}
.saoma {
width: 750rpx;
height: 166rpx;
background: #FFFFFF;
position: fixed;
left: 0;
bottom: 0;
padding-top: 22rpx;
border-radius: 54rpx 54rpx 0 0;
margin-top: 20rpx;
view {
text-align: center;
width: 676rpx;
height: 102rpx;
background: linear-gradient(270deg, #8883F0 0%, #8883F0 100%);
border-radius: 54rpx 54rpx 54rpx 54rpx;
font-weight: 500;
font-size: 40rpx;
color: #FFFFFF;
margin: auto;
line-height: 102rpx;
}
image {
width: 56rpx;
height: 56rpx;
vertical-align: middle;
margin-right: 10rpx;
margin-bottom: 10rpx;
}
}
.page {
width: 750rpx;
position: fixed;
top: 0;
left: 0;
.dtxs {
width: 100%;
height: 100vh;
position: fixed;
top: 0;
left: 0;
z-index: -1;
.picimg {
width: 120rpx;
height: 120rpx;
position: absolute;
left: 50%;
transform: translateX(-50%);
top: 50%;
}
}
.list {
display: flex;
margin-top: 10px;
border-bottom: 1px solid #eee;
padding: 16rpx 14rpx;
box-sizing: border-box;
background-color: #fff;
width: 690rpx;
margin: auto;
margin-top: 20rpx;
height: 250rpx;
border-radius: 12rpx;
.pic {
width: 210rpx;
height: 210rpx;
border-radius: 10rpx;
margin-right: 20rpx;
border-radius: 20rpx;
image {
width: 210rpx;
height: 210rpx;
border-radius: 20rpx;
}
}
.cen {
width: 488rpx;
.cena {
font-weight: 700 !important;
font-size: 28rpx;
color: #3D3D3D;
line-height: 38rpx;
}
.cenb {
font-weight: 400;
font-size: 26rpx;
color: #3D3D3D;
line-height: 32rpx;
margin-top: 14rpx;
padding-right: 30rpx;
box-sizing: border-box;
image {
display: inline-block;
width: 22rpx;
height: 22rpx;
margin-right: 6rpx;
}
}
.juli{
font-size: 24rpx;
padding: 6rpx 10rpx;
box-sizing: border-box;
border: 1px solid #4D48B5;
color: #4D48B5;
width: 160rpx;
text-align: center;
background: #EFEEFF;
border-radius: 10rpx;
}
.cenc {
font-weight: 400;
font-size: 26rpx;
color: #3D3D3D;
line-height: 32rpx;
margin-top: 14rpx;
text {
display: inline-block;
padding: 4rpx 18rpx;
box-sizing: border-box;
border-radius: 20rpx;
}
.bu {
margin-left: 32rpx;
background: #D9D8FF;
color: #4D48B5;
font-size: 20rpx;
}
}
}
.right {
image {
width: 48rpx;
height: 48rpx;
margin-right: 10rpx;
}
text {
display: block;
font-weight: 400;
font-size: 20rpx;
color: #808080;
line-height: 28rpx;
width: 100rpx;
}
}
}
.listbox {
background: #eee;
box-shadow: 0rpx 10rpx 64rpx 0rpx rgba(0, 0, 0, 0.08);
padding-left: 32rpx;
padding-right: 32rpx;
box-sizing: border-box;
height: 81vh;
overflow-y: scroll;
padding-bottom: 400rpx;
.moshi {
position: absolute;
bottom: 40vh;
left: 30rpx;
z-index: 99;
width: 100%;
image {
width: 230rpx;
// height: 80rpx !important;
}
.img {
height: 50rpx;
margin-bottom: 8rpx;
}
}
.title {
border-radius: 64rpx 64rpx 0 0;
display: flex;
justify-content: space-between;
font-weight: 500;
font-size: 36rpx;
color: #3D3D3D;
line-height: 160rpx;
padding: 0 76rpx;
width: 100%;
background-color: #fff;
position: fixed;
height: 160rpx;
top: 40vh;
left: 0;
padding-bottom: 20rpx;
}
}
}
.active {
border-bottom: 10rpx solid #D9D8FF;
border-radius: 7rpx;
padding-bottom: 10rpx;
font-weight: 700;
}
</style>