From 84d894d7d1c22370d9a55ecc27af016c9cf6e5b4 Mon Sep 17 00:00:00 2001
From: lion <120344285@qq.com>
Date: Tue, 30 Dec 2025 14:03:52 +0800
Subject: [PATCH] =?UTF-8?q?=20=E8=A1=8C=E8=B5=B0=E7=BA=A2=E8=89=B2?=
=?UTF-8?q?=E8=8B=8F=E5=B7=9E?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
App.vue | 45 +-
H5地图显示说明.md | 177 ++++
common/config.js | 6 +-
common/http.interceptor.js | 88 +-
common/util.js | 46 +-
common/wechat-jssdk.js | 134 +++
components/tabbar/tabbar.vue | 121 +--
manifest.json | 14 +-
packages/cer/cer.vue | 236 +++---
packages/detail/articleDetail.vue | 23 +-
packages/detail/detail.vue | 36 +-
pages.json | 88 +-
pages/book/house.vue | 44 +-
pages/book/index.vue | 6 +-
pages/home/home.vue | 1268 ++++++++++++++++++++++++++---
pages/index/index.vue | 65 +-
pages/line/line.vue | 59 +-
pages/line/war.vue | 91 ++-
pages/me/me.vue | 98 ++-
19 files changed, 2136 insertions(+), 509 deletions(-)
create mode 100644 H5地图显示说明.md
create mode 100644 common/wechat-jssdk.js
diff --git a/App.vue b/App.vue
index 2e953f3..64fbc5f 100644
--- a/App.vue
+++ b/App.vue
@@ -2,26 +2,26 @@
export default {
onLaunch: function() {
this.$nextTick(() => {
- // uni.login({
- // provider: 'weixin',
- // success: (res) => {
- // console.log(res.code);
- // this.$u.api.login({
- // code: res.code
- // }).then(res => {
- // this.$u.api.user().then(res=>{
- // this.$u.vuex('vuex_user', res)
- // })
- // })
- // }
+ // uni.login({
+ // provider: 'weixin',
+ // success: (res) => {
+ // console.log(res.code);
+ // this.$u.api.login({
+ // code: res.code
+ // }).then(res => {
+ // this.$u.api.user().then(res=>{
+ // this.$u.vuex('vuex_user', res)
+ // })
+ // })
+ // }
// });
})
- },
-
+ },
+
onShow: function() {
- console.log('App Show')
+ console.log('App Show')
},
onHide: function() {
@@ -32,15 +32,20 @@
\ No newline at end of file
diff --git a/manifest.json b/manifest.json
index 4f21729..6288d10 100644
--- a/manifest.json
+++ b/manifest.json
@@ -77,15 +77,23 @@
"vueVersion" : "2",
"h5" : {
"router" : {
- "base" : ""
+ "base" : "h5walksz",
+ "mode" : "hash"
},
"devServer" : {
"disableHostCheck" : true,
- "https" : false
+ "https" : false,
+ "port" : 8080
},
"title" : "行走红色苏州",
+ "template" : "",
+ "publicPath" : "/h5walksz/",
"sdkConfigs" : {
- "maps" : {}
+ "maps" : {
+ "qqmap" : {
+ "key" : "B4TBZ-G6OLU-NR6VC-GOUUX-6GTHH-BAFUZ"
+ }
+ }
}
}
}
diff --git a/packages/cer/cer.vue b/packages/cer/cer.vue
index c1141f1..2adf10a 100644
--- a/packages/cer/cer.vue
+++ b/packages/cer/cer.vue
@@ -5,8 +5,8 @@
mode=
-
-
+
+
-
-
- x
+
+
+ x
@@ -67,14 +67,14 @@
ROOTPATH
} from '@/common/config.js'
import {
- base64ToFile,
- toast,
+ base64ToFile,
+ toast,
shareInfo
- } from '@/common/util'
+ } from '@/common/util'
export default {
data() {
- return {
- SCREEN_WIDTH:0,
+ return {
+ SCREEN_WIDTH:0,
SCREEN_HEIGHT:0,
isShare: false,
isHidden: false,
@@ -82,112 +82,120 @@
//isShowModal: false,
userInfo: {},
myIndex: 0,
- navBarTop: 0,
- navBarRight: 0,
- backHeight:0,
+ navBarTop: 0,
+ navBarRight: 0,
+ backHeight:0,
backTop:0
};
- },
- onShareAppMessage() {
- return shareInfo
- },
- onShareTimeline() {
- return shareInfo
- },
- onShow() {
- this.userInfo = uni.getStorageSync('walksz_lifeData').vuex_user
- this.myIndex = this.userInfo.myIndex?this.userInfo.myIndex:'-'
- const MenuButton = uni.getMenuButtonBoundingClientRect()
- this.navBarTop = MenuButton.top + MenuButton.height //左侧文字与右侧胶囊对齐
- this.navBarRight = MenuButton.width
- this.backTop = MenuButton.top
- this.backHeight = MenuButton.height
- let sysInfo = uni.getSystemInfoSync();
- this.SCREEN_WIDTH = sysInfo.screenWidth
- this.SCREEN_HEIGHT = sysInfo.screenHeight;
},
- methods: {
- back(){
- uni.switchTab({
- url:'/pages/me/me'
- })
+ onShareAppMessage() {
+ return shareInfo
+ },
+ onShareTimeline() {
+ return shareInfo
+ },
+ onShow() {
+ this.userInfo = uni.getStorageSync('walksz_lifeData').vuex_user
+ this.myIndex = this.userInfo.myIndex?this.userInfo.myIndex:'-'
+ // #ifndef H5
+ const MenuButton = uni.getMenuButtonBoundingClientRect()
+ this.navBarTop = MenuButton.top + MenuButton.height //左侧文字与右侧胶囊对齐
+ this.navBarRight = MenuButton.width
+ this.backTop = MenuButton.top
+ this.backHeight = MenuButton.height
+ // #endif
+ // #ifdef H5
+ this.navBarTop = 88 // H5端固定导航栏高度
+ this.navBarRight = 0
+ this.backTop = 44
+ this.backHeight = 44
+ // #endif
+ let sysInfo = uni.getSystemInfoSync();
+ this.SCREEN_WIDTH = sysInfo.screenWidth
+ this.SCREEN_HEIGHT = sysInfo.screenHeight;
+ },
+ methods: {
+ back(){
+ uni.switchTab({
+ url:'/pages/me/me'
+ })
},
share() {
this.isHidden = true
uni.showLoading({
title: '图片生成中..'
- })
+ })
var ctx = uni.createCanvasContext('firstCanvas')
var w = this.SCREEN_WIDTH * 0.9;
- var h = this.SCREEN_HEIGHT * 0.7;
- console.log(w,h)
- var lw = 176 * .3
+ var h = this.SCREEN_HEIGHT * 0.7;
+ console.log(w,h)
+ var lw = 176 * .3
var lh = 450 * .3
ctx.drawImage('../static/cer-bg.jpg', 0, 0,w, h);
ctx.drawImage('../static/cer-logo.png', w-lw-20, 20, lw, lh);
- ctx.font = "13rpx bold";
- ctx.fillStyle = "#fff";
- var tleft = w*.13
- if(this.SCREEN_WIDTH<380){
- tleft = this.SCREEN_WIDTH<330?20:40
- console.log("tleft",tleft)
- ctx.fillText(this.userInfo.name+":", tleft, lh+40);
- ctx.fillText("传承红色基因,赓续红色血脉。", tleft+20, lh+60);
- ctx.fillText("您是第"+this.myIndex+"位完成“行走红色苏州——打卡",tleft+20, lh+80);
- ctx.fillText("苏州市党史教育基地”活动的学员。", tleft, lh+100);
- ctx.fillText("学好党史“必修课”,当好时代“答卷人”,", tleft+20, lh+120);
- ctx.fillText("快邀请您的好友一起参加活动吧!", tleft, lh+140);
- }else{
- ctx.fillText(this.userInfo.name+":", tleft, lh+40);
- ctx.fillText("传承红色基因,赓续红色血脉。", tleft+20, lh+60);
- ctx.fillText("您是第"+this.myIndex+"位完成“行走红色苏州——打卡苏州市",tleft+20, lh+80);
- ctx.fillText("党史教育基地”活动的学员。", tleft, lh+100);
- ctx.fillText("学好党史“必修课”,当好时代“答卷人”,快邀", tleft+20, lh+120);
- ctx.fillText("请您的好友一起参加活动吧!", tleft, lh+140);
+ ctx.font = "13rpx bold";
+ ctx.fillStyle = "#fff";
+ var tleft = w*.13
+ if(this.SCREEN_WIDTH<380){
+ tleft = this.SCREEN_WIDTH<330?20:40
+ console.log("tleft",tleft)
+ ctx.fillText(this.userInfo.name+":", tleft, lh+40);
+ ctx.fillText("传承红色基因,赓续红色血脉。", tleft+20, lh+60);
+ ctx.fillText("您是第"+this.myIndex+"位完成“行走红色苏州——打卡",tleft+20, lh+80);
+ ctx.fillText("苏州市党史教育基地”活动的学员。", tleft, lh+100);
+ ctx.fillText("学好党史“必修课”,当好时代“答卷人”,", tleft+20, lh+120);
+ ctx.fillText("快邀请您的好友一起参加活动吧!", tleft, lh+140);
+ }else{
+ ctx.fillText(this.userInfo.name+":", tleft, lh+40);
+ ctx.fillText("传承红色基因,赓续红色血脉。", tleft+20, lh+60);
+ ctx.fillText("您是第"+this.myIndex+"位完成“行走红色苏州——打卡苏州市",tleft+20, lh+80);
+ ctx.fillText("党史教育基地”活动的学员。", tleft, lh+100);
+ ctx.fillText("学好党史“必修课”,当好时代“答卷人”,快邀", tleft+20, lh+120);
+ ctx.fillText("请您的好友一起参加活动吧!", tleft, lh+140);
}
- ctx.draw()
- setTimeout(() => {
- uni.canvasToTempFilePath({
- canvasId: 'firstCanvas',
- fileType: 'jpg',
- success: (res) => {
- uni.hideLoading()
- this.imgData = res.tempFilePath;
- },
- })
+ ctx.draw()
+ setTimeout(() => {
+ uni.canvasToTempFilePath({
+ canvasId: 'firstCanvas',
+ fileType: 'jpg',
+ success: (res) => {
+ uni.hideLoading()
+ this.imgData = res.tempFilePath;
+ },
+ })
}, 100)
},
- save() {
+ save() {
let _this = this
-
- uni.saveImageToPhotosAlbum({
- filePath: _this.imgData,
- success: function() {
- _this.isHidden = false
- toast('保存成功')
- }
- });
- uni.uploadFile({
- url: `${ROOTPATH}/api/mobile/upload-file`,
- filePath: this.imgData,
- name: 'file',
- formData: {
- "file":this.imgData,
- 'token':this.vuex_token,
- 'active_tag':'walksz'
- },
- success: (res) => {
- console.log(res)
- // return
- const val = JSON.parse(res.data)
- this.$u.api.savePoster({
- upload_id: val.id,
- type: 1
- }).then(res => {
- }).catch(err => {
- })
- }
+
+ uni.saveImageToPhotosAlbum({
+ filePath: _this.imgData,
+ success: function() {
+ _this.isHidden = false
+ toast('保存成功')
+ }
+ });
+ uni.uploadFile({
+ url: `${ROOTPATH}/api/mobile/upload-file`,
+ filePath: this.imgData,
+ name: 'file',
+ formData: {
+ "file":this.imgData,
+ 'token':this.vuex_token,
+ 'active_tag':'walksz'
+ },
+ success: (res) => {
+ console.log(res)
+ // return
+ const val = JSON.parse(res.data)
+ this.$u.api.savePoster({
+ upload_id: val.id,
+ type: 1
+ }).then(res => {
+ }).catch(err => {
+ })
+ }
})
}
},
@@ -356,7 +364,7 @@
width: 60%;
margin: 400rpx auto;
text-align: center;
- line-height: 40px;
+ line-height: 40px;
white-space: pre-wrap;
}
@@ -366,7 +374,7 @@
right: 0;
top: 0;
width: 300rpx;
- height: 400rpx;
+ height: 400rpx;
z-index: 1000001;
}
}
@@ -401,7 +409,7 @@
top: 50%;
left: 50%;
right: 0;
- width:100%;
+ width:100%;
padding-top: 40rpx;
&>image {
width: 520rpx;
@@ -411,19 +419,19 @@
box-shadow: 0rpx 4rpx 20rpx 0rpx rgba(19, 1, 2, 0.71);
margin: auto;
}
- &__close{
- color: #fff;
- width: 80rpx;
- height: 80rpx;
- border-radius: 80rpx;
- line-height: 70rpx;
- text-align: center;
- border: 1px solid #fff;
- position: absolute;
- top: 0rpx;
- left: 0rpx;
- font-size: 50rpx;
- z-index: 10;
+ &__close{
+ color: #fff;
+ width: 80rpx;
+ height: 80rpx;
+ border-radius: 80rpx;
+ line-height: 70rpx;
+ text-align: center;
+ border: 1px solid #fff;
+ position: absolute;
+ top: 0rpx;
+ left: 0rpx;
+ font-size: 50rpx;
+ z-index: 10;
}
&__btn {
display: flex;
diff --git a/packages/detail/articleDetail.vue b/packages/detail/articleDetail.vue
index 85e05ef..ddab569 100644
--- a/packages/detail/articleDetail.vue
+++ b/packages/detail/articleDetail.vue
@@ -19,7 +19,7 @@
-
+
@@ -60,8 +60,13 @@
},
onLoad(option) {
+ // #ifndef H5
const MenuButton = uni.getMenuButtonBoundingClientRect()
this.navBarTop = MenuButton.top //左侧文字与右侧胶囊对齐
+ // #endif
+ // #ifdef H5
+ this.navBarTop = 44 // H5端固定导航栏高度
+ // #endif
this.getDetail(option.id)
},
methods: {
@@ -71,16 +76,16 @@
table_name: 'map_point_image_articles',
'with_relations[0]': 'image'
})
- this.info = res
- this.info.content = this.replaceStoragePath(res.content)
+ this.info = res
+ this.info.content = this.replaceStoragePath(res.content)
console.log(this.info.content)
this.showContent = true
- },
- replaceStoragePath(htmlStr) {
- // 正则匹配 src 属性中包含 ../storage 的部分(支持双引号或单引号)
- const regex = /src=["']\..\/storage/g;
- // 替换为目标路径(保持原有的引号)
- return htmlStr.replace(regex, 'src="https://h5.jscnsaas.cn/storage');
+ },
+ replaceStoragePath(htmlStr) {
+ // 正则匹配 src 属性中包含 ../storage 的部分(支持双引号或单引号)
+ const regex = /src=["']\..\/storage/g;
+ // 替换为目标路径(保持原有的引号)
+ return htmlStr.replace(regex, 'src="https://h5.jscnsaas.cn/storage');
}
}
}
diff --git a/packages/detail/detail.vue b/packages/detail/detail.vue
index 80fb93c..c90610e 100644
--- a/packages/detail/detail.vue
+++ b/packages/detail/detail.vue
@@ -203,7 +203,7 @@
playvideo: false,
playimg: false,
qrCode: '',
- showQrCode: false,
+ showQrCode: false,
hasQuestion:false
}
},
@@ -217,21 +217,26 @@
},
onLoad(option) {
+ // #ifndef H5
const MenuButton = uni.getMenuButtonBoundingClientRect()
this.navBarTop = MenuButton.top //左侧文字与右侧胶囊对齐
- this.getDetail(option.id)
+ // #endif
+ // #ifdef H5
+ this.navBarTop = 44 // H5端固定导航栏高度
+ // #endif
+ this.getDetail(option.id)
this.getQuestions(option.id)
},
methods: {
playFullScreen() {
let videoContext = uni.createVideoContext('videos', this)
videoContext.requestFullScreen()
- },
- async getQuestions(id) {
- const res = await this.$u.api.getQuestions({
- point_id: id
- })
- this.hasQuestion = res.questions.length>0?true:false
+ },
+ async getQuestions(id) {
+ const res = await this.$u.api.getQuestions({
+ point_id: id
+ })
+ this.hasQuestion = res.questions.length>0?true:false
},
async getDetail(id) {
const res = await this.$u.api.pointDetail({
@@ -257,6 +262,7 @@
let path = info.path ? info.path : ''
// 跳转到其他小程序
if (info.appid) {
+ // #ifndef H5
uni.navigateToMiniProgram({
appId: info.appid, // 目标小程序的 AppID
path: path, // 目标小程序的页面路径
@@ -272,6 +278,20 @@
console.log('跳转失败', err);
}
});
+ // #endif
+ // #ifdef H5
+ // H5端不支持跳转小程序,显示二维码或提示
+ if (info.qrcode) {
+ this.qrCode = info.qrcode.url
+ this.showQrCode = true
+ } else {
+ uni.showModal({
+ title: '提示',
+ content: '请在微信小程序中打开此功能',
+ showCancel: false
+ })
+ }
+ // #endif
} else {
if (!info.qrcode) {
return
diff --git a/pages.json b/pages.json
index 34637cb..c0288e8 100644
--- a/pages.json
+++ b/pages.json
@@ -41,44 +41,44 @@
"usingComponents": {
"map": "/uni_modules/@dcloudio/uni-map/components/uni-map/uni-map"
},
- "subPackages": [{
- "root": "packages",
- "pages":[{
- "path": "detail/detail",
- "style": {
- "navigationStyle": "custom"
- }
- },{
- "path": "detail/articleDetail",
- "style": {
- "navigationStyle": "custom"
- }
- },{
- "path": "vr/vr",
- "style": {
- "navigationStyle": "custom"
- }
- },{
- "path": "question/question",
- "style": {
- "navigationStyle": "custom"
- }
- },{
- "path": "cer/cer",
- "style": {
- "navigationStyle": "custom"
- }
- },{
- "path": "record/record",
- "style": {
- "navigationBarTitleText": "我的红色足迹"
- }
- },{
- "path": "search/search",
- "style": {
- "navigationBarTitleText": "搜索"
- }
- }]
+ "subPackages": [{
+ "root": "packages",
+ "pages":[{
+ "path": "detail/detail",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ },{
+ "path": "detail/articleDetail",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ },{
+ "path": "vr/vr",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ },{
+ "path": "question/question",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ },{
+ "path": "cer/cer",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ },{
+ "path": "record/record",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ },{
+ "path": "search/search",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ }]
}],
"preloadRule": {},
"globalStyle": {
@@ -104,12 +104,12 @@
"pagePath": "pages/line/war",
"iconPath": "/static/icon5.png",
"selectedIconPath": "/static/icon5-cur.png"
- },
- {
- "text": "书房",
- "pagePath": "pages/book/house",
- "iconPath": "/static/icon6.png",
- "selectedIconPath": "/static/icon6-cur.png"
+ },
+ {
+ "text": "书房",
+ "pagePath": "pages/book/house",
+ "iconPath": "/static/icon6.png",
+ "selectedIconPath": "/static/icon6-cur.png"
},
{
"text": "我的",
diff --git a/pages/book/house.vue b/pages/book/house.vue
index ab246b0..bb02af7 100644
--- a/pages/book/house.vue
+++ b/pages/book/house.vue
@@ -91,9 +91,13 @@
return shareInfo
},
onLoad() {
-
+ // #ifndef H5
const MenuButton = uni.getMenuButtonBoundingClientRect()
this.navBarTop = MenuButton.top //左侧文字与右侧胶囊对齐
+ // #endif
+ // #ifdef H5
+ this.navBarTop = 44 // H5端固定导航栏高度
+ // #endif
this.getBooks()
this.getVideos()
@@ -287,24 +291,51 @@
swiper {
height: calc(50vh - 200rpx) !important;
background-color: transparent !important;
+ // #ifdef H5
+ height: 400px !important;
+ background-color: transparent !important;
+ // #endif
image {
height: 85%;
}
}
-
+ ::v-deep uni-swiper{
+ height: calc(50vh - 200rpx) !important;
+ background-color: transparent !important;
+ }
::v-deep .u-swiper-wrap {
height: 100%;
+ // #ifdef H5
+ background-color: transparent !important;
+ // #endif
+ }
+
+ // #ifdef H5
+ ::v-deep .u-swiper {
+ background-color: transparent !important;
}
+
+ ::v-deep .u-swiper-item {
+ background-color: transparent !important;
+ }
+
+ ::v-deep .u-list-image-wrap {
+ background-color: transparent !important;
+ }
+ // #endif
::v-deep .u-swiper-indicator {
bottom: 150rpx !important;
+ // #ifdef H5
+ bottom: 75px !important;
+ // #endif
}
- ::v-deep .u-list-image-wrap {
- // background-color: #fff;
- }
+ // ::v-deep .u-list-image-wrap {
+ // background-color: #fff;
+ // }
.opacity0 swiper swiper-item:last-child {
opacity: 0;
@@ -329,6 +360,9 @@
white-space: break-spaces;
text-overflow: clip;
text-align: center;
+ // #ifdef H5
+ background-color: transparent !important;
+ // #endif
}
diff --git a/pages/book/index.vue b/pages/book/index.vue
index d00e547..ac775eb 100644
--- a/pages/book/index.vue
+++ b/pages/book/index.vue
@@ -52,9 +52,13 @@
return shareInfo
},
onLoad() {
-
+ // #ifndef H5
const MenuButton = uni.getMenuButtonBoundingClientRect()
this.navBarTop = MenuButton.top //左侧文字与右侧胶囊对齐
+ // #endif
+ // #ifdef H5
+ this.navBarTop = 44 // H5端固定导航栏高度
+ // #endif
this.getBooks()
},
diff --git a/pages/home/home.vue b/pages/home/home.vue
index d4702db..12f8b52 100644
--- a/pages/home/home.vue
+++ b/pages/home/home.vue
@@ -26,7 +26,8 @@
+
+
+
+
+
+
+
+
+
+
+ 距你 {{pointer.distance ? pointer.distance + ' 公里' : '-'}}
+
+
+
+ {{con.value}}
+
+
+
+
+
+
+
+
+ 开始前往
+
+
+
+
+
+
+
@@ -82,10 +117,10 @@
-
+
使用完整功能,需要获取您的定位,点击授权
-
+
@@ -121,7 +156,8 @@
import tabbar from '@/components/tabbar/tabbar.vue'
import myloading from '@/components/myloading.vue'
import {
- ROOTPATH as baseUrl
+ ROOTPATH as baseUrl,
+ WECHAT_APPID
} from "@/common/config.js"
import {
isNull,
@@ -130,6 +166,10 @@
getDistance,
toMapAPP
} from '@/common/util.js'
+ // #ifdef H5
+ // 微信分享SDK已移除,不再引入
+ // import { initWxSDK } from '@/common/wechat-jssdk.js'
+ // #endif
export default {
components: {
@@ -163,8 +203,13 @@
showLoad: false,
showNear: true,
showLabel:false,
- showLocationTip: false
-
+ showLocationTip: false,
+ // #ifdef H5
+ isLoading: true, // H5端加载状态,进入页面就显示地图容器
+ lastLocationTime: 0, // 上次定位时间,用于防抖
+ locationCacheTime: 300000, // 定位缓存时间5分钟(300000毫秒)
+ iconCache: {} // marker图标缓存,避免重复处理
+ // #endif
}
},
onShareAppMessage() {
@@ -175,8 +220,10 @@
},
onReady() {
this.initLocationAuth()
+ // 创建地图上下文(H5端和小程序端都支持)
this.mapContext = uni.createMapContext('myMap', this);
- // 获取当前地图层级
+ // #ifndef H5
+ // 获取当前地图层级(小程序端)
let _this = this
if (this.mapTimer) {
@@ -198,18 +245,78 @@
}, 1000)
}
-
+ // #endif
},
+ // #ifdef H5
+ mounted() {
+ // H5端微信分享已移除,不再初始化
+ // this.initWechatShare()
+ },
+ // #endif
onLoad(option) {
+ // #ifndef H5
const MenuButton = uni.getMenuButtonBoundingClientRect()
this.navBarTop = MenuButton.top //左侧文字与右侧胶囊对齐
+ // #endif
+ // #ifdef H5
+ this.navBarTop = 44 // H5端固定导航栏高度
+ console.log('H5端onLoad执行,vuex_token:', this.vuex_token)
+ // #endif
// this.getUserLocation()
+ // #ifndef H5
if (isNull(this.vuex_token)) {
this.getToken()
}
+ // #endif
+ // #ifdef H5
+ // H5端检查token和code
+ const urlParams = new URLSearchParams(window.location.search)
+ const code = urlParams.get('code')
+ console.log('H5端检查code:', code, 'token:', this.vuex_token)
+
+ if (code) {
+ // 有code,执行登录
+ this.getToken()
+ } else if (isNull(this.vuex_token)) {
+ // 没有code且没有token,检查是否在微信浏览器中
+ const isWechat = /MicroMessenger/i.test(navigator.userAgent)
+ console.log('是否在微信浏览器:', isWechat)
+ if (isWechat) {
+ // 在微信浏览器中,跳转授权
+ this.getToken()
+ } else {
+ // 不在微信浏览器中,提示用户
+ console.log('不在微信浏览器中,无法获取授权')
+ // 可以先加载不需要登录的数据
this.getArea()
this.getConfig()
-
+ // 尝试获取定位(可能失败,但不影响页面显示)
+ this.initLocationAuth()
+ // 即使没有token,也尝试加载点位数据(可能失败,但不影响页面显示)
+ this.getPointers()
+ }
+ } else {
+ // 有token,正常加载
+ console.log('H5端已有token,正常加载数据')
+ // H5端不显示定位提示
+ this.showLocationTip = false
+ this.getArea()
+ this.getConfig()
+ this.initLocationAuth()
+ // 有token时,initLocationAuth中会调用getPointers,但为了确保数据加载,这里也调用一次
+ // 如果定位成功,getPointers会被调用两次,但不会重复加载(因为pointers会被重置)
+ setTimeout(() => {
+ if (this.pointers.length === 0) {
+ console.log('延迟加载点位数据')
+ this.getPointers()
+ }
+ }, 1000)
+ }
+ // #endif
+ // #ifndef H5
+ this.getArea()
+ this.getConfig()
+ // #endif
},
onShow() {
let vuex_pointer = uni.getStorageSync('vuex_pointer') ? uni.getStorageSync('vuex_pointer') : null
@@ -217,25 +324,65 @@
let vuex_point_id = uni.getStorageSync('vuex_point_id') ? uni.getStorageSync('vuex_point_id') : ''
// 通过搜索获取的点位信息
if (vuex_pointer) {
+ // #ifndef H5
this.pointer = vuex_pointer
+ if (vuex_latlng && vuex_latlng.lat && vuex_latlng.lng) {
this.pointer.distance = getDistance(vuex_latlng.lat, vuex_latlng.lng, this.pointer.lat, this.pointer.lng)
+ }
this.showPointer = true
this.scale = 13
uni.removeStorageSync('vuex_pointer')
+ if (this.mapContext) {
this.mapContext.moveToLocation({
longitude: parseFloat(this.pointer.lng),
latitude: parseFloat(this.pointer.lat)
});
+ }
+ // #endif
+ // #ifdef H5
+ // H5端不显示弹窗,直接清除pointer,让用户从列表中查看
+ uni.removeStorageSync('vuex_pointer')
+ this.showPointer = false
+ this.pointer = null
+ // #endif
}
// 答题的点位解锁
if (vuex_point_id) {
+ // #ifndef H5
this.markers.map(item => {
if (item.id == vuex_point_id) {
item.has_answer = 1
uni.removeStorageSync("vuex_point_id")
}
})
+ // #endif
+ // #ifdef H5
+ this.pointers.map(item => {
+ if (item.id == vuex_point_id) {
+ item.has_answer = 1
+ uni.removeStorageSync("vuex_point_id")
+ }
+ })
+ // 更新markers中的has_answer
+ this.markers.map(item => {
+ if (item.id == vuex_point_id) {
+ item.has_answer = 1
+ }
+ })
+ // #endif
+ }
+ // #ifdef H5
+ // 返回页面时,如果markers为空,重新加载点位数据
+ if (this.markers.length === 0 && !isNull(this.vuex_token)) {
+ console.log('onShow: markers为空,重新加载点位数据')
+ this.getPointers()
}
+ // 如果有缓存的定位信息,使用缓存
+ if (vuex_latlng && vuex_latlng.lat && vuex_latlng.lng) {
+ this.lat = vuex_latlng.lat
+ this.lng = vuex_latlng.lng
+ }
+ // #endif
},
onHide() {
this.showTips = false
@@ -248,7 +395,83 @@
},
methods: {
+ // #ifdef H5
+ // 创建圆形marker图标(带缓存)
+ createRoundedMarkerIcon(imageUrl) {
+ return new Promise((resolve) => {
+ // 检查缓存
+ if (this.iconCache[imageUrl]) {
+ resolve(this.iconCache[imageUrl])
+ return
+ }
+
+ // 如果图片已经是base64或blob,直接返回并缓存
+ if (imageUrl.startsWith('data:') || imageUrl.startsWith('blob:')) {
+ this.iconCache[imageUrl] = imageUrl
+ resolve(imageUrl)
+ return
+ }
+
+ // 创建图片对象
+ const img = new Image()
+ img.crossOrigin = 'anonymous' // 允许跨域
+
+ img.onload = () => {
+ try {
+ // 创建canvas
+ const canvas = document.createElement('canvas')
+ const size = 40 // marker尺寸
+ canvas.width = size
+ canvas.height = size
+ const ctx = canvas.getContext('2d')
+
+ // 绘制圆形路径
+ ctx.beginPath()
+ ctx.arc(size / 2, size / 2, size / 2, 0, Math.PI * 2)
+ ctx.clip()
+
+ // 绘制图片(居中,填充圆形)
+ const scale = Math.max(size / img.width, size / img.height)
+ const x = (size - img.width * scale) / 2
+ const y = (size - img.height * scale) / 2
+ ctx.drawImage(img, x, y, img.width * scale, img.height * scale)
+
+ // 转换为base64
+ const base64 = canvas.toDataURL('image/png')
+ // 缓存结果
+ this.iconCache[imageUrl] = base64
+ resolve(base64)
+ } catch (error) {
+ console.error('创建圆形marker图标失败:', error)
+ // 缓存原图片,避免重复处理
+ this.iconCache[imageUrl] = imageUrl
+ resolve(imageUrl) // 失败时返回原图片
+ }
+ }
+
+ img.onerror = () => {
+ console.error('加载marker图片失败:', imageUrl)
+ // 缓存原图片,避免重复处理
+ this.iconCache[imageUrl] = imageUrl
+ resolve(imageUrl) // 失败时返回原图片
+ }
+
+ // 设置超时,避免长时间等待
+ setTimeout(() => {
+ if (!img.complete) {
+ console.warn('marker图片加载超时:', imageUrl)
+ // 缓存原图片
+ this.iconCache[imageUrl] = imageUrl
+ resolve(imageUrl) // 超时时返回原图片
+ }
+ }, 2000) // 减少超时时间到2秒
+
+ img.src = imageUrl
+ })
+ },
+ // #endif
initLocationAuth() {
+ // #ifndef H5
uni.getSetting({
success: (res) => {
const setting = res.authSetting || {}
@@ -276,29 +499,146 @@
this.showLocationTip = true
}
})
+ // #endif
+ // #ifdef H5
+ // H5端直接尝试获取定位,默认不显示提示
+ this.showLocationTip = false
+ // 先显示地图容器,然后尝试获取定位
+ this.isLoading = true
+ // 延迟一下再获取定位,确保页面先渲染
+ setTimeout(() => {
+ this.getUserLocation()
+ }, 100)
+ // #endif
},
// 我的位置
getUserLocation() {
+ console.log('getUserLocation执行')
+ // #ifdef H5
+ // H5端检查是否支持geolocation API
+ if (!navigator.geolocation) {
+ console.log('浏览器不支持定位功能')
+ this.showLocationTip = false
+ this.isLoading = false
+ // 即使不支持定位,也尝试加载点位数据
+ if (!isNull(this.vuex_token)) {
+ this.getPointers()
+ } else {
+ // 等待token后再加载
+ this.waitForToken(2000).then(() => {
+ if (!isNull(this.vuex_token)) {
+ this.getPointers()
+ }
+ })
+ }
+ return
+ }
+ // H5端定位防抖:检查是否有缓存的定位信息,且缓存时间未过期
+ const now = Date.now()
+ const cachedLocation = uni.getStorageSync('vuex_latlng')
+ if (cachedLocation && cachedLocation.lat && cachedLocation.lng) {
+ const cacheTime = cachedLocation.timestamp || 0
+ if (now - cacheTime < this.locationCacheTime) {
+ console.log('使用缓存的定位信息,避免频繁调用')
+ this.lat = cachedLocation.lat
+ this.lng = cachedLocation.lng
+ this.showLocationTip = false
+ this.isLoading = false
+ // 使用缓存定位后,如果有token则加载点位数据
+ if (!isNull(this.vuex_token)) {
+ this.getPointers()
+ } else {
+ this.getPointers()
+ }
+ return
+ }
+ }
+ // 防抖:如果距离上次定位时间太短,不重复调用
+ if (now - this.lastLocationTime < 2000) {
+ console.log('定位请求过于频繁,跳过本次请求')
+ return
+ }
+ this.lastLocationTime = now
+ // #endif
uni.getLocation({
type: 'gcj02',
+ // #ifdef H5
+ // H5端增加超时时间
+ timeout: 10000,
+ // #endif
success: (res) => {
+ console.log('获取定位成功:', res.latitude, res.longitude)
this.showLocationTip = false
- uni.removeStorageSync('vuex_latlng')
+ // #ifdef H5
+ this.isLoading = false
+ // #endif
this.lng = res.longitude
this.lat = res.latitude
+ // 保存定位信息,包含时间戳
uni.setStorageSync('vuex_latlng', {
lng: this.lng,
- lat: this.lat
+ lat: this.lat,
+ timestamp: Date.now()
})
+ // 获取定位后,如果有token则加载点位数据
+ if (!isNull(this.vuex_token)) {
this.getPointers()
+ } else {
+ // #ifdef H5
+ // H5端即使没有token,也可以先加载点位数据(不计算距离)
+ this.getPointers()
+ // #endif
+ }
},
fail: (err) => {
- console.log("err", err)
+ console.log("获取定位失败:", err)
+ // #ifdef H5
+ // H5端定位失败不显示提示,直接加载数据
+ this.showLocationTip = false
+ this.isLoading = false
+ const errMsg = err.errMsg || err.message || '未知错误'
+ console.log('定位失败原因:', errMsg)
+
+ // H5端定位失败常见原因和处理建议:
+ if (errMsg.includes('network error')) {
+ console.warn('定位失败:网络错误,可能原因:')
+ console.warn('1. 当前页面不是HTTPS协议(定位功能需要HTTPS)')
+ console.warn('2. 网络连接不稳定')
+ console.warn('3. 浏览器定位服务被禁用')
+ // 检查是否是HTTPS
+ if (window.location.protocol !== 'https:') {
+ console.error('⚠️ 当前页面不是HTTPS,定位功能无法使用!请使用HTTPS协议访问。')
+ }
+ } else if (errMsg.includes('permission') || errMsg.includes('denied')) {
+ console.warn('定位失败:用户拒绝了定位权限')
+ } else if (errMsg.includes('timeout')) {
+ console.warn('定位失败:定位超时')
+ }
+
+ // 即使定位失败,也尝试加载点位数据(不计算距离)
+ if (!isNull(this.vuex_token)) {
+ this.getPointers()
+ } else {
+ // 等待token后再加载
+ this.waitForToken(2000).then(() => {
+ if (!isNull(this.vuex_token)) {
+ this.getPointers()
+ }
+ })
+ }
+ // #endif
+ // #ifndef H5
this.showLocationTip = true
+ // 即使定位失败,如果有token也可以加载点位数据(不计算距离)
+ if (!isNull(this.vuex_token)) {
+ this.getPointers()
+ }
+ // #endif
}
})
},
retryLocationAuth() {
+ // #ifndef H5
// 根据当前授权状态选择 authorize 或直接打开设置
uni.getSetting({
success: (res) => {
@@ -337,8 +677,14 @@
}
}
})
+ // #endif
+ // #ifdef H5
+ // H5端直接尝试获取定位
+ this.getUserLocation()
+ // #endif
},
async getToken() {
+ // #ifndef H5
await uni.login({
provider: 'weixin',
success: (res) => {
@@ -346,10 +692,15 @@
code: res.code
}).then(res => {
this.$u.vuex('vuex_token', res.token)
+ // 等待token设置完成后再调用其他接口
+ this.$nextTick(() => {
this.$u.api.user().then(res => {
this.$u.vuex('vuex_user', res)
- })
+ }).then(() => {
+ // 用户信息获取完成后再加载点位数据
this.getPointers()
+ })
+ })
}).catch(err => {
console.log('login-error:', JSON.stringify(err))
})
@@ -358,12 +709,149 @@
console.log("errtoken", JSON.stringify(res))
}
});
+ // #endif
+ // #ifdef H5
+ // H5端使用微信网页授权
+ this.wechatH5Login()
+ // #endif
},
+ // #ifdef H5
+ // H5端微信网页授权登录
+ wechatH5Login() {
+ console.log('wechatH5Login执行')
+ // 检查URL中是否有code参数
+ const urlParams = new URLSearchParams(window.location.search)
+ const code = urlParams.get('code')
+ console.log('获取到的code:', code)
+
+ if (code) {
+ // 有code,调用登录接口
+ console.log('调用登录接口,code:', code)
+ this.$u.api.login({
+ code: code
+ }).then(res => {
+ console.log('登录成功,token:', res.token)
+ // 先设置token到vuex和storage
+ this.$u.vuex('vuex_token', res.token)
+ // 确保token立即同步到storage
+ const walksz_lifeData = uni.getStorageSync('walksz_lifeData') || {}
+ walksz_lifeData.vuex_token = res.token
+ uni.setStorageSync('walksz_lifeData', walksz_lifeData)
+ // 等待token同步完成
+ return new Promise((resolve) => {
+ // 使用nextTick确保vuex更新完成
+ this.$nextTick(() => {
+ // 再次确认token已设置
+ const token = this.vuex_token || uni.getStorageSync('walksz_lifeData')?.vuex_token
+ console.log('token设置完成,当前token:', token)
+ resolve(token)
+ })
+ })
+ }).then((token) => {
+ // token设置完成后,再调用需要token的接口
+ if (token) {
+ // 获取用户信息
+ return this.$u.api.user().then(res => {
+ this.$u.vuex('vuex_user', res)
+ return token
+ })
+ }
+ return token
+ }).then((token) => {
+ // 清除URL中的code参数
+ const newUrl = window.location.pathname + window.location.hash
+ window.history.replaceState({}, '', newUrl)
+ // token设置完成后,再加载需要token的数据
+ console.log('开始加载需要token的数据')
+ this.getArea()
+ this.getConfig()
+ this.initLocationAuth()
+ }).catch(err => {
+ console.log('login-error:', JSON.stringify(err))
+ // 登录失败,检查是否在微信浏览器中
+ const isWechat = /MicroMessenger/i.test(navigator.userAgent)
+ if (isWechat) {
+ // 重新授权
+ this.redirectToWechatAuth()
+ } else {
+ // 不在微信浏览器中,加载不需要登录的数据
+ this.getArea()
+ this.getConfig()
+ this.initLocationAuth()
+ }
+ })
+ } else {
+ // 没有code,检查是否在微信浏览器中
+ const isWechat = /MicroMessenger/i.test(navigator.userAgent)
+ console.log('没有code,是否在微信浏览器:', isWechat)
+ if (isWechat) {
+ // 在微信浏览器中,跳转到微信授权页面
+ this.redirectToWechatAuth()
+ } else {
+ // 不在微信浏览器中,加载不需要登录的数据
+ console.log('不在微信浏览器中,加载基础数据')
+ this.getArea()
+ this.getConfig()
+ this.initLocationAuth()
+ }
+ }
+ },
+ // H5端跳转到微信授权页面
+ redirectToWechatAuth() {
+ console.log('跳转到微信授权页面')
+ // 获取当前页面的完整URL(包括hash)
+ let currentUrl = window.location.href.split('?')[0]
+ // 如果有hash,保留hash
+ if (window.location.hash) {
+ currentUrl = currentUrl + window.location.hash
+ }
+ const redirectUri = encodeURIComponent(currentUrl)
+ const authUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${WECHAT_APPID}&redirect_uri=${redirectUri}&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect`
+ console.log('授权URL:', authUrl)
+ window.location.href = authUrl
+ },
+ // #endif
async getArea() {
+ // 检查token是否存在,如果不存在则等待
+ // #ifdef H5
+ if (isNull(this.vuex_token)) {
+ console.log('getArea等待token...')
+ // 等待token设置,最多等待2秒
+ await this.waitForToken(2000)
+ if (isNull(this.vuex_token)) {
+ console.log('getArea等待token超时,跳过')
+ return
+ }
+ }
+ // #endif
+ this.doGetArea()
+ },
+ // #ifdef H5
+ // 等待token设置的工具方法
+ waitForToken(timeout = 2000) {
+ return new Promise((resolve) => {
+ if (!isNull(this.vuex_token)) {
+ resolve()
+ return
+ }
+ const startTime = Date.now()
+ const checkToken = setInterval(() => {
+ if (!isNull(this.vuex_token)) {
+ clearInterval(checkToken)
+ resolve()
+ } else if (Date.now() - startTime > timeout) {
+ clearInterval(checkToken)
+ resolve()
+ }
+ }, 100)
+ })
+ },
+ // #endif
+ doGetArea() {
let that = this
let url = baseUrl + '/api/mobile/base-form/show'
url = url + '?filter[0][key]=number&filter[0][op]=eq&filter[0][value]=theme&with_relations[0]=detail'
- await uni.request({
+ uni.request({
url: url,
method: "GET",
data: {
@@ -378,7 +866,7 @@
that.listArea.sort((a, b) => a.sort - b.sort);
},
fail(err) {
- console.log(err)
+ console.log('getArea失败:', err)
}
})
},
@@ -392,64 +880,81 @@
this.scale = 11
this.markers = []
- // 根据区域id 遍历所有 重新生成markers
- if (this.theme_id == '') {
- // this.mapContext.moveToLocation({
- // longitude: this.lng,
- // latitude: this.lat,
- // });
- // this.getPointers()
- this.pointers.map((item, index) => {
- if (index < 10) {
- this.markers.push({
- id: item.id,
- latitude: parseFloat(item.lat),
- longitude: parseFloat(item.lng),
- iconPath: '/static/home-marker.png',
- truePath: item.logo ? item.logo.url : item.image.url,
- width: 0,
- height: 0,
- title: item.name,
- distance: item.distance ? parseInt(item.distance) : 0,
- has_answer: item.has_answer,
- customCallout: {
- anchorX: 70,
- anchorY: 30,
- display: 'ALWAYS'
- },
- })
+ // 根据区域id 重新获取数据并生成markers
+ // #ifndef H5
+ // 小程序端:如果pointers有数据,从现有数据中筛选;否则重新获取
+ if (this.pointers && this.pointers.length > 0) {
+ // 从现有pointers中筛选生成markers
+ if (this.theme_id == '') {
+ // 全部区域:取前10个
+ this.pointers.map((item, index) => {
+ if (index < 10) {
+ this.markers.push({
+ id: item.id,
+ latitude: parseFloat(item.lat),
+ longitude: parseFloat(item.lng),
+ iconPath: '/static/home-marker.png',
+ truePath: item.logo ? item.logo.url : item.image.url,
+ width: 0,
+ height: 0,
+ title: item.name,
+ distance: item.distance ? parseInt(item.distance) : 0,
+ has_answer: item.has_answer,
+ customCallout: {
+ anchorX: 70,
+ anchorY: 30,
+ display: 'ALWAYS'
+ },
+ })
+ }
+ })
+ } else {
+ // 特定区域:筛选theme_id匹配的
+ this.pointers.map((item, index) => {
+ if (this.theme_id && item.theme_id == this.theme_id) {
+ this.markers.push({
+ id: item.id,
+ latitude: parseFloat(item.lat),
+ longitude: parseFloat(item.lng),
+ iconPath: '/static/home-marker.png',
+ truePath: item.logo ? item.logo.url : (item.image?item.image.url:'/static/share.jpg'),
+ width: 0,
+ height: 0,
+ title: item.name,
+ distance: item.distance ? parseInt(item.distance) : 0,
+ has_answer: item.has_answer,
+ customCallout: {
+ anchorX: 70,
+ anchorY: 30,
+ display: 'ALWAYS'
+ },
+ })
+ }
+ })
+ // 移动到第一个marker位置
+ if (this.mapContext && this.markers.length > 0) {
+ this.mapContext.moveToLocation({
+ longitude: this.markers[0].longitude,
+ latitude: this.markers[0].latitude,
+ });
}
-
-
- })
+ }
} else {
- this.pointers.map((item, index) => {
- if (this.theme_id && item.theme_id == this.theme_id) {
- this.markers.push({
- id: item.id,
- latitude: parseFloat(item.lat),
- longitude: parseFloat(item.lng),
- iconPath: '/static/home-marker.png',
- truePath: item.logo ? item.logo.url : (item.image?item.image.url:'/static/share.jpg'),
- width: 0,
- height: 0,
- title: item.name,
- distance: item.distance ? parseInt(item.distance) : 0,
- has_answer: item.has_answer,
- customCallout: {
- anchorX: 70,
- anchorY: 30,
- display: 'ALWAYS'
- },
- })
- }
- })
- this.mapContext.moveToLocation({
- longitude: this.markers[0].longitude,
- latitude: this.markers[0].latitude,
- });
+ // pointers为空,重新获取数据
+ this.getPointers()
}
- // this.getPointers()
+ // #endif
+ // #ifdef H5
+ // H5端需要重新获取数据并生成markers
+ // 调用getPointers重新获取点位数据(会根据theme_id筛选)
+ this.getPointers()
+ // #endif
+ // #ifndef H5
+ // 小程序端如果pointers为空,也需要重新获取数据
+ if (!this.pointers || this.pointers.length === 0) {
+ this.getPointers()
+ }
+ // #endif
}
},
cancelArea() {
@@ -471,36 +976,173 @@
url: '/packages/search/search'
})
},
- getConfig() {
+ async getConfig() {
+ // 检查token是否存在,如果不存在则等待
+ // #ifdef H5
+ if (isNull(this.vuex_token)) {
+ console.log('getConfig等待token...')
+ await this.waitForToken(2000)
+ if (isNull(this.vuex_token)) {
+ console.log('getConfig等待token超时,跳过')
+ return
+ }
+ }
+ // #endif
+ this.doGetConfig()
+ },
+ doGetConfig() {
this.$u.api.getAppId().then((res) => {
res.config.map(item => {
if (item.key === 'tips') {
this.tips = item.value
}
})
-
+ }).catch(err => {
+ console.log('getConfig失败:', err)
})
},
getNears() {
- this.scale = 13
+ console.log('getNears执行,lat:', this.lat, 'lng:', this.lng)
this.showPointer = false
this.pointer = null
+ // #ifndef H5
+ this.scale = 13
+ if (this.mapContext) {
this.mapContext.moveToLocation({
longitude: this.lng,
latitude: this.lat
});
+ }
+ // #endif
+ // #ifdef H5
+ // H5端移动地图到当前位置
+ if (this.mapContext && this.lat && this.lng) {
+ this.mapContext.moveToLocation({
+ longitude: this.lng,
+ latitude: this.lat
+ });
+ } else if (this.lat && this.lng) {
+ // 如果mapContext不存在,直接设置scale和center
+ this.scale = 13
+ console.log('H5端移动到当前位置:', this.lat, this.lng)
+ } else {
+ console.warn('H5端没有定位信息,无法移动到当前位置')
+ }
+ // #endif
},
async getPointers() {
+ console.log('getPointers执行,lat:', this.lat, 'lng:', this.lng, 'theme_id:', this.theme_id, 'token:', this.vuex_token)
+ // #ifdef H5
+ // H5端检查token,如果不存在则等待
+ if (isNull(this.vuex_token)) {
+ console.log('getPointers等待token...')
+ await this.waitForToken(2000)
+ if (isNull(this.vuex_token)) {
+ console.log('getPointers等待token超时,跳过')
+ return
+ }
+ }
+ // #endif
+ this.doGetPointers()
+ },
+ async doGetPointers() {
+ console.log('doGetPointers执行,lat:', this.lat, 'lng:', this.lng, 'theme_id:', this.theme_id, 'token:', this.vuex_token)
+ // #ifdef H5
+ this.isLoading = true
+ // #endif
this.pointers = []
- this.markers = []
+ this.markers = [] // H5端也需要生成markers
+ try {
const res = await this.$u.api.getPoints({
theme_id: this.theme_id,
})
- this.pointers = res.points
+ console.log('获取点位数据成功,完整响应:', res)
+ console.log('点位数量:', res.points ? res.points.length : 0)
+ this.pointers = res.points || []
+ console.log('pointers数组:', this.pointers)
+ if (this.pointers.length === 0) {
+ console.warn('点位数据为空,请检查接口返回')
+ }
+ // #ifdef H5
+ // H5端先同步生成markers,然后异步更新圆形图标
+ const markerPromises = []
+ // #endif
this.pointers.map((item, index) => {
+ if (this.lat && this.lng) {
item.distance = getDistance(this.lat, this.lng, item.lat, item.lng)
- if (index < 10) {
- this.markers.push({
+ }
+ // H5端和小程序端都需要生成markers
+ if (index < 50) { // H5端可以显示更多点位
+ // #ifdef H5
+ // H5端marker格式(使用标准格式)
+ const truePath = item.logo ? item.logo.url : (item.image ? item.image.url : '/static/share.jpg')
+ // H5端iconPath可以使用网络图片URL
+ // 优先使用truePath(网络图片),如果没有则使用本地图片
+ let iconPath = truePath && truePath.startsWith('http') ? truePath : '/static/home-marker.png'
+ // 如果是本地路径,转换为完整URL
+ if (iconPath.startsWith('/') && !iconPath.startsWith('http')) {
+ iconPath = window.location.origin + '/h5walksz' + iconPath
+ }
+ // 先检查是否有圆形图标缓存,如果有就直接使用
+ const cachedRoundedIcon = this.iconCache && this.iconCache[iconPath]
+ // 先使用原图片创建marker,后续异步更新为圆形图片
+ const marker = {
+ id: item.id,
+ latitude: parseFloat(item.lat),
+ longitude: parseFloat(item.lng),
+ iconPath: cachedRoundedIcon || iconPath, // 如果有缓存就用圆形图标,否则用原图片
+ originalIconPath: iconPath, // 保存原始路径,用于后续处理
+ width: 40, // 增加marker尺寸,使图片更清晰
+ height: 40,
+ title: item.name,
+ truePath: truePath, // 保存图片路径,用于显示
+ has_answer: item.has_answer, // 保存答题状态
+ callout: {
+ content: item.name,
+ color: '#333',
+ fontSize: 12,
+ borderRadius: 8,
+ bgColor: '#fff',
+ padding: 8,
+ display: 'BYCLICK',
+ textAlign: 'center',
+ borderWidth: 1,
+ borderColor: '#e5e5e5'
+ }
+ }
+ this.markers.push(marker)
+ // 如果已经有缓存,就不需要再处理了
+ if (!cachedRoundedIcon) {
+ // 异步处理圆形图标
+ markerPromises.push(
+ this.createRoundedMarkerIcon(iconPath).then(roundedIconPath => {
+ if (!roundedIconPath || roundedIconPath === iconPath) return
+ const markerIndex = this.markers.findIndex(m => m.id === marker.id)
+ if (markerIndex !== -1) {
+ // 检查marker是否还存在(可能被重新生成了)
+ const currentMarker = this.markers[markerIndex]
+ if (currentMarker && currentMarker.id === marker.id) {
+ // 使用Vue.set确保响应式更新,并保留所有属性
+ const updatedMarker = {
+ ...currentMarker,
+ iconPath: roundedIconPath
+ }
+ this.$set(this.markers, markerIndex, updatedMarker)
+ console.log('H5端更新marker圆形图标:', marker.id, 'iconPath长度:', roundedIconPath.length)
+ } else {
+ console.warn('H5端marker已被更新,跳过圆形图标更新:', marker.id)
+ }
+ }
+ }).catch(err => {
+ console.warn('处理marker图标失败:', err)
+ })
+ )
+ }
+ console.log('H5端生成marker:', marker.id, 'iconPath:', marker.iconPath, 'truePath:', marker.truePath)
+ // #endif
+ // #ifndef H5
+ // 小程序端marker格式
+ const marker = {
id: item.id,
latitude: parseFloat(item.lat),
longitude: parseFloat(item.lng),
@@ -515,13 +1157,95 @@
anchorX: 70,
anchorY: 30,
display: 'ALWAYS'
- },
+ }
+ }
+ // #endif
+ this.markers.push(marker)
+ }
+ })
+ // #ifdef H5
+ // H5端等待所有圆形图标处理完成(不阻塞主流程)
+ if (markerPromises.length > 0) {
+ Promise.all(markerPromises).then(() => {
+ console.log('H5端所有marker圆形图标处理完成')
+ // 不强制更新,让每个marker的更新自己触发
+ }).catch(err => {
+ console.warn('H5端处理marker图标时出错:', err)
+ })
+ }
+ // #endif
+ console.log('生成的markers数量:', this.markers.length)
+ console.log('markers数据:', JSON.stringify(this.markers.slice(0, 3))) // 打印前3个marker用于调试
+ // #ifdef H5
+ console.log('H5端点位列表渲染,pointers长度:', this.pointers.length, 'markers长度:', this.markers.length)
+ // 确保地图有中心点和缩放级别
+ if (!this.lat || !this.lng) {
+ // 如果没有定位,使用第一个点位作为地图中心
+ if (this.markers.length > 0) {
+ this.lat = this.markers[0].latitude
+ this.lng = this.markers[0].longitude
+ console.log('H5端使用第一个点位作为地图中心:', this.lat, this.lng)
+ }
+ }
+ // 确保地图有缩放级别
+ if (!this.scale || this.scale < 10) {
+ this.scale = 13
+ console.log('H5端设置地图缩放级别:', this.scale)
+ }
+ // 强制更新markers(H5端可能需要等待地图加载完成)
+ this.$nextTick(() => {
+ console.log('H5端地图更新markers,当前markers数量:', this.markers.length)
+ // 延迟一下,确保地图已经渲染
+ setTimeout(() => {
+ // 强制触发Vue的响应式更新(保留圆形图标)
+ // 深拷贝markers,确保保留所有属性包括圆形图标和callout
+ const markers = this.markers.map(m => {
+ // 检查是否有圆形图标缓存,如果有就使用圆形图标
+ const originalPath = m.originalIconPath || m.iconPath
+ const cachedRoundedIcon = this.iconCache && this.iconCache[originalPath]
+ const newMarker = {
+ ...m,
+ // 优先使用圆形图标缓存,其次使用当前的iconPath
+ iconPath: cachedRoundedIcon || m.iconPath,
+ }
+ if (m.callout) {
+ newMarker.callout = {...m.callout}
+ }
+ return newMarker
+ })
+ this.markers = []
+ this.$nextTick(() => {
+ this.markers = markers
+ console.log('H5端强制更新markers完成,数量:', this.markers.length, '第一个iconPath类型:', typeof this.markers[0]?.iconPath)
+ // 移动地图到第一个marker位置,触发地图更新
+ if (this.mapContext && this.markers.length > 0) {
+ this.mapContext.moveToLocation({
+ longitude: this.markers[0].longitude,
+ latitude: this.markers[0].latitude,
+ success: () => {
+ console.log('H5端地图移动到第一个marker位置成功')
+ },
+ fail: (err) => {
+ console.error('H5端地图移动失败:', err)
+ }
})
}
})
+ }, 500)
+ })
+ this.isLoading = false
+ // #endif
+ } catch (err) {
+ console.error('获取点位数据失败:', err)
+ // #ifdef H5
+ console.error('H5端获取点位失败,错误详情:', JSON.stringify(err))
+ this.isLoading = false
+ // #endif
+ }
},
// 移动地图加载更多
pushMarkers(e) {
+ // #ifndef H5
let lengthM = this.markers.length //当前markers数量
// 加载完毕 或 区域选择 移动不加载
if (this.showLoad || this.theme_id) {
@@ -561,6 +1285,7 @@
}
})
}
+ // #endif
},
toDetail() {
@@ -576,18 +1301,67 @@
},
showDetail(e) {
- const arr = this.pointers.filter(item => item.id === e.markerId)
+ // 获取markerId,兼容小程序和H5
+ const markerId = e.markerId || e.detail?.markerId || e.detail?.marker?.id
+ console.log('showDetail触发,markerId:', markerId, 'event:', e)
+ const arr = this.pointers.filter(item => item.id == markerId)
if (arr.length > 0) {
this.pointer = arr[0]
+ if (this.lat && this.lng) {
this.pointer.distance = getDistance(this.lat, this.lng, this.pointer.lat, this.pointer.lng)
}
-
this.showPointer = true
-
+ }
},
toMap(e) {
+ if (!this.pointer) return
+ // #ifndef H5
toMapAPP(this.pointer.lat, this.pointer.lng, this.pointer.name)
+ // #endif
+ // #ifdef H5
+ // H5端打开腾讯地图URL
+ const address = this.pointer.config && this.pointer.config.length > 0 ?
+ this.pointer.config.find(c => c.key === 'address')?.value || '' : ''
+ const url = this.getMapUrl(this.pointer.lat, this.pointer.lng, this.pointer.name, address)
+ window.open(url, '_blank')
+ // #endif
+ },
+ // #ifdef H5
+ // H5端:选择点位
+ selectPointer(item) {
+ this.pointer = item
+ this.pointer.distance = getDistance(this.lat, this.lng, this.pointer.lat, this.pointer.lng)
+ this.showPointer = true
},
+ // H5端:打开腾讯地图URL
+ openMapUrl(item) {
+ const address = item.config && item.config.length > 0 ?
+ item.config.find(c => c.key === 'address')?.value || '' : ''
+ const url = this.getMapUrl(item.lat, item.lng, item.name, address)
+ window.open(url, '_blank')
+ },
+ // H5端:生成地图URL
+ getMapUrl(lat, lng, name, address) {
+ if (lat && lng) {
+ const marker = `coord:${lat},${lng};title:${encodeURIComponent(name || '位置')};addr:${encodeURIComponent(address || '')}`
+ return `https://apis.map.qq.com/uri/v1/marker?marker=${marker}&referer=myapp`
+ }
+ return 'https://apis.map.qq.com/uri/v1/marker?marker=coord:31.297241,120.580792;title:行走红色苏州;addr:苏州市姑苏区&referer=myapp'
+ },
+ // H5端:初始化微信分享(已移除,不再调用接口)
+ // initWechatShare() {
+ // // #ifdef H5
+ // initWxSDK({
+ // title: shareInfo.title,
+ // desc: shareInfo.title,
+ // link: window.location.href,
+ // imgUrl: `${window.location.origin}${shareInfo.imageUrl}`
+ // }).catch(err => {
+ // console.log('微信分享初始化失败', err)
+ // })
+ // // #endif
+ // },
+ // #endif
}
}
@@ -663,11 +1437,172 @@
}
.maps {
+ position: relative;
+ width: 100%;
+ height: 100vh;
#myMap {
width: 100%;
height: 100vh;
+ // #ifdef H5
+ // H5端确保地图容器有明确的尺寸
+ min-height: 500px;
+ position: relative;
+
+ // 尝试通过CSS为marker图标添加圆角(如果map组件支持)
+ ::v-deep .marker-icon,
+ ::v-deep .marker-icon {
+ border-radius: 100% !important;
+ overflow: hidden;
+ }
+ // #endif
}
+
+ // #ifdef H5
+ &-h5 {
+ width: 100%;
+ height: calc(100vh - 200rpx);
+ overflow-y: auto;
+ padding-top: 200rpx;
+ padding-bottom: 180rpx; // 为tabbar留出空间(135rpx + 45rpx安全距离)
+ margin-top: 0;
+ position: relative;
+
+ &-empty {
+ padding: 100rpx 30rpx;
+ text-align: center;
+ color: #999;
+ font-size: 28rpx;
+ }
+
+ &-loading {
+ padding: 100rpx 30rpx;
+ text-align: center;
+ color: #999;
+ font-size: 28rpx;
+ }
+
+ &-list {
+ padding: 0 30rpx;
+ }
+
+ &-item {
+ display: flex;
+ align-items: center;
+ background: #fff;
+ border-radius: 20rpx;
+ margin-bottom: 20rpx;
+ padding: 30rpx;
+ box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
+
+ &-img {
+ width: 140rpx;
+ height: 140rpx;
+ border-radius: 140rpx;
+ border: 4rpx solid #dbd0ba;
+ position: relative;
+ margin-right: 20rpx;
+ overflow: hidden;
+
+ image {
+ width: 100%;
+ height: 100%;
+ }
+
+ &-lock {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: rgba(0, 0, 0, 0.5);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ image {
+ width: 52rpx;
+ height: 68rpx;
+ }
+ }
+ }
+
+ &-info {
+ flex: 1;
+
+ &-title {
+ font-size: 36rpx;
+ color: #000;
+ margin-bottom: 10rpx;
+ font-weight: bold;
+ }
+
+ &-distance {
+ font-size: 28rpx;
+ color: #919191;
+ margin-bottom: 10rpx;
+ }
+
+ &-address {
+ font-size: 24rpx;
+ color: #999;
+ }
+ }
+
+ &-btn {
+ width: 58rpx;
+ height: 58rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ image {
+ width: 58rpx;
+ height: 60rpx;
+ }
+ }
+ }
+
+ &-tip {
+ position: fixed;
+ left: 50%;
+ bottom: 200rpx;
+ transform: translate(-50%, -50%);
+ width: 80%;
+ z-index: 99;
+ text-align: center;
+ background: rgba(0, 0, 0, 0.6);
+ color: #fff;
+ padding: 20rpx 30rpx;
+ border-radius: 40rpx;
+ }
+
+ &-near {
+ position: fixed;
+ right: 30rpx;
+ // #ifndef H5
+ bottom: 200rpx; // 在tabbar上方
+ // #endif
+ // #ifdef H5
+ bottom: 100px; // H5端使用px单位,在tabbar上方
+ // #endif
+ z-index: 9999; // 提高层级,确保在地图之上
+ cursor: pointer; // H5端添加鼠标指针样式
+ transition: bottom 0.3s ease-in-out; // 添加过渡动画
+
+ image {
+ width: 246rpx;
+ height: 132rpx;
+ pointer-events: auto; // 确保可以点击
+ }
+
+
+ }
+ &.maps-info-near-up {
+ bottom: 420rpx !important;
+ }
+ }
+ // #endif
&-info {
position: absolute;
@@ -675,53 +1610,139 @@
bottom: 160rpx;
width: 100%;
z-index: 99;
+
+ // #ifdef H5
+ position: fixed;
+ bottom: 180rpx; // H5端为tabbar留出空间
+ z-index: 9999; // H5端提高层级,确保在地图之上
+ pointer-events: none; // 容器不拦截事件,让子元素可以点击
+ // #endif
&-pointer {
background: #fff;
- border-radius: 20rpx;
- width: 85%;
+ border-radius: 20rpx 20rpx 0 0;
+ width: 100%;
margin: 0 auto;
- padding: 30rpx;
+ padding: 0;
font-size: 28rpx;
- box-shadow: -2px -3rpx 12px rgba(0, 0, 0, 0.1);
-
- &-title {
- color: #919191;
- padding-bottom: 20rpx;
-
- cover-view {
- margin-bottom: 10rpx;
- white-space: normal;
-
- &:first-child {
- font-size: 36rpx;
- color: #000;
+ box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.1);
+ // #ifdef H5
+ pointer-events: auto; // H5端确保可以点击
+ border-radius: 20px 20px 0 0;
+ box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
+ // #endif
+
+ &-header {
display: flex;
justify-content: space-between;
align-items: center;
- align-items: normal;
- white-space: normal;
- width: 97%;
- }
- }
-
-
+ padding: 30rpx 30rpx 20rpx;
+ // #ifdef H5
+ padding: 15px 15px 10px;
+ // #endif
+ }
+
+ &-title {
+ font-size: 36rpx;
+ font-weight: 600;
+ color: #1a1a1a;
+ flex: 1;
+ // #ifdef H5
+ font-size: 18px;
+ // #endif
+ }
+
+ &-close {
+ width: 40rpx;
+ height: 40rpx;
+ cursor: pointer;
+ // #ifdef H5
+ width: 20px;
+ height: 20px;
+ // #endif
+ }
+
+ &-content {
+ padding: 0 30rpx 20rpx;
+ // #ifdef H5
+ padding: 0 15px 10px;
+ // #endif
+ }
+
+ &-distance {
+ font-size: 26rpx;
+ color: #666;
+ margin-bottom: 12rpx;
+ // #ifdef H5
+ font-size: 13px;
+ margin-bottom: 6px;
+ // #endif
+ }
+
+ &-address {
+ font-size: 26rpx;
+ color: #999;
+ line-height: 1.5;
+ // #ifdef H5
+ font-size: 13px;
+ // #endif
+ }
+
+ &-divider {
+ width: 100%;
+ height: 1px;
+ background: #f0f0f0;
+ margin: 0;
}
&-btn {
display: flex;
- font-size: 28rpx;
- color: #c89a73;
justify-content: space-between;
align-items: center;
- padding-top: 20rpx;
- // border-top: 1px solid #e9e9e9;
-
- cover-view {
- cover-image {
- display: inline-block;
- vertical-align: middle;
+ padding: 24rpx 30rpx 30rpx;
+ // #ifdef H5
+ padding: 12px 15px 15px;
+ // #endif
+
+ &-nav {
+ display: flex;
+ align-items: center;
+ font-size: 28rpx;
+ color: #c89a73;
+ cursor: pointer;
+ transition: opacity 0.3s;
+ // #ifdef H5
+ font-size: 14px;
+ // #endif
+
+ &:active {
+ opacity: 0.7;
+ }
+ }
+
+ &-icon {
+ width: 29rpx;
+ height: 30rpx;
margin-right: 10rpx;
+ // #ifdef H5
+ width: 15px;
+ height: 15px;
+ margin-right: 5px;
+ // #endif
+ }
+
+ &-detail {
+ width: 201rpx;
+ height: 55rpx;
+ cursor: pointer;
+ transition: transform 0.2s;
+ // #ifdef H5
+ width: 100px;
+ height: 28px;
+ // #endif
+
+ &:active {
+ transform: scale(0.95);
}
}
}
@@ -731,13 +1752,32 @@
width: 90%;
margin: 0 auto;
text-align: right;
+ position: fixed;
+ right: 30rpx;
+ bottom: 200rpx;
+ z-index: 9999; // 提高层级
+ width: auto;
+ pointer-events: auto; // 确保可以点击
cover-image {
width: 246rpx;
height: 132rpx;
display: inline-block;
}
+
+ // #ifdef H5
+ cursor: pointer; // H5端添加鼠标指针样式
+ image {
+ width: 246rpx;
+ height: 132rpx;
+ display: inline-block;
+ pointer-events: auto; // 确保可以点击
+ }
+ // #endif
}
+ &.maps-info-near-up {
+ bottom: 420rpx
+ }
&-tip {
position: absolute;
diff --git a/pages/index/index.vue b/pages/index/index.vue
index f90f58d..8f56b39 100644
--- a/pages/index/index.vue
+++ b/pages/index/index.vue
@@ -17,13 +17,13 @@
-
+
-
-
-
- 技术支持:江苏有线苏州分公司
-
+
+
+
+ 技术支持:江苏有线苏州分公司
+
@@ -44,17 +44,22 @@
showBtn: true,
navBarBoxHeight: 0,
}
- },
- onShareAppMessage() {
- return shareInfo
- },
- onShareTimeline() {
- return shareInfo
+ },
+ onShareAppMessage() {
+ return shareInfo
+ },
+ onShareTimeline() {
+ return shareInfo
},
async onLoad() {
this.start();
+ // #ifndef H5
const MenuButton = uni.getMenuButtonBoundingClientRect()
this.navBarBoxHeight = MenuButton.top + MenuButton.height + 10
+ // #endif
+ // #ifdef H5
+ this.navBarBoxHeight = 88 // H5端固定导航栏高度
+ // #endif
},
beforeDestroy() {
// clearInterval(this.interval);
@@ -84,17 +89,17 @@
.wrap {
// height: 100vh;
width: 100vw;
- position: relative;
- // padding-bottom:200rpx;
+ position: relative;
+ // padding-bottom:200rpx;
height: 100vh;
}
.container {
background: #efe9df;
width: 100vw;
- position: relative;
- // padding-bottom:200rpx;
- min-height: 100vh;
+ position: relative;
+ // padding-bottom:200rpx;
+ min-height: 100vh;
padding-bottom:80rpx;
&-bg {
position: absolute;
@@ -103,22 +108,22 @@
width: 100%;
height: 100%;
}
- .support {
- position: absolute;
- bottom: 30rpx;
- width: 100%;
- font-size: 24rpx;
- color: #333;
- font-family: '宋体';
- opacity: 1;
- text-align: center;
- z-index: 9;
+ .support {
+ position: absolute;
+ bottom: 30rpx;
+ width: 100%;
+ font-size: 24rpx;
+ color: #333;
+ font-family: '宋体';
+ opacity: 1;
+ text-align: center;
+ z-index: 9;
}
.imgwrap {
position: relative;
z-index: 9;
- position: absolute;
- bottom: 60rpx;
+ position: absolute;
+ bottom: 60rpx;
width:100%;
&-map {
width: 745rpx;
@@ -169,7 +174,7 @@
}
- }
+ }
}
diff --git a/pages/line/line.vue b/pages/line/line.vue
index a45389f..47d338d 100644
--- a/pages/line/line.vue
+++ b/pages/line/line.vue
@@ -61,9 +61,9 @@