行走红色苏州

main
lion 3 months ago
parent 913becb570
commit 84d894d7d1

@ -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 @@
<style lang="scss">
/*每个页面公共css */
@import "uview-ui/index.scss";
@import "uview-ui/index.scss";
@import "@/GAL/css/gal.css";
.uni-tabbar-bottom{
display: block!important;
.uni-tabbar-bottom{
display: block!important;
}
// #ifdef H5
.uni-tabbar-bottom{
display: none!important;
}
// #endif
.uni-tabbar {
box-shadow: 0px 0px 20rpx rgba(0, 0, 0, 0.3);
.uni-tabbar-border{
display: none;
.uni-tabbar-border{
display: none;
}
.uni-tabbar__item {
.uni-tabbar__bd {

@ -0,0 +1,177 @@
# H5端地图显示说明
## 当前状态
目前H5端使用的是**列表形式**显示点位,点击点位可以跳转到腾讯地图进行导航。
## uni-app map组件在H5端的支持情况
**✅ 可以直接使用!** uni-app的`<map>`组件在H5端是支持的但需要注意
1. **默认使用高德地图** - uni-app的map组件在H5端默认使用高德地图服务
2. **需要配置高德地图Key** - 必须在manifest.json中配置高德地图的Web端API Key
3. **功能限制** - 某些小程序特有的功能如cover-view在H5端不支持
## 如果要显示真正的地图,有以下方案:
### 方案一使用uni-app的map组件 + 高德地图(最简单)⭐推荐
#### 优点:
- 代码改动最小
- 与小程序端代码统一
- uni-app官方支持
#### 缺点:
- 需要使用高德地图(不是腾讯地图)
- 某些高级功能可能受限
#### 配置步骤:
1. **申请高德地图Web端API Key**
- 访问https://console.amap.com/dev
- 注册/登录账号
- 创建应用,选择"Web端 (JS API)"
- 获取API Key
- 配置域名白名单
2. **配置manifest.json**
```json
{
"h5": {
"sdkConfigs": {
"maps": {
"amap": {
"webKey": "你的高德地图Web端API Key"
}
}
}
}
}
```
3. **修改pages/home/home.vue**
- 移除H5端的条件编译`#ifndef H5`
- 让map组件在H5端也显示
- 注意cover-view在H5端不支持需要改为普通view
#### 示例代码:
```vue
<template>
<view class="maps">
<!-- 移除 #ifndef H5让map组件在H5端也显示 -->
<map
id="myMap"
:longitude="lng"
:latitude="lat"
:markers="markers"
:scale="scale"
show-location
@markertap="showDetail"
>
<!-- H5端不支持cover-view需要改为view -->
<!-- #ifndef H5 -->
<cover-view>...</cover-view>
<!-- #endif -->
<!-- #ifdef H5 -->
<view>...</view>
<!-- #endif -->
</map>
</view>
</template>
```
---
### 方案二使用腾讯地图Web SDK
#### 1. 获取腾讯地图Key
- 访问https://lbs.qq.com/
- 注册/登录账号
- 创建应用获取Key
- 配置域名白名单你的H5域名
#### 2. 配置manifest.json
`manifest.json``h5.sdkConfigs.maps.qqmap.key` 中填入你的Key
```json
{
"h5": {
"sdkConfigs": {
"maps": {
"qqmap": {
"key": "你的腾讯地图Key"
}
}
}
}
}
```
#### 3. 引入腾讯地图SDK
`pages/home/home.vue` 的H5端部分引入
```html
<!-- #ifdef H5 -->
<script src="https://map.qq.com/api/gljs?v=1.exp&key=你的Key"></script>
<!-- #endif -->
```
#### 4. 使用地图组件
可以使用 `<map>` 组件uni-app支持或直接使用腾讯地图Web API创建地图实例。
---
### 方案二使用iframe嵌入腾讯地图
#### 优点:
- 不需要Key使用URL scheme
- 实现简单
#### 缺点:
- 交互受限
- 无法自定义样式
#### 实现方式:
在H5端使用iframe嵌入腾讯地图URL类似当前的点位导航URL。
---
### 方案三使用其他地图SDK
#### 高德地图
- 访问https://lbs.amap.com/
- 获取Key
- 引入高德地图JS API
#### 百度地图
- 访问https://lbsyun.baidu.com/
- 获取Key
- 引入百度地图JS API
---
## 定位失败问题
### 错误:`getLocation:fail network error`
#### 常见原因:
1. **非HTTPS环境** - H5定位功能必须使用HTTPS协议
2. **用户拒绝授权** - 浏览器定位权限被拒绝
3. **网络问题** - 网络连接不稳定
4. **浏览器不支持** - 某些浏览器不支持定位API
#### 解决方案:
1. **确保使用HTTPS** - 部署到HTTPS域名
2. **引导用户授权** - 提示用户在浏览器设置中允许定位权限
3. **使用默认位置** - 定位失败时使用默认坐标(如苏州市中心)
4. **降级处理** - 定位失败时仍显示点位列表(不计算距离)
---
## 当前实现
目前H5端已经实现了
- ✅ 点位列表显示
- ✅ 点击跳转腾讯地图导航
- ✅ 定位失败时的降级处理
- ✅ 即使定位失败也能加载点位数据
如果需要显示真正的地图,请按照上述方案一进行配置。

@ -15,4 +15,8 @@ switch (mode) {
throw new Error('未配置环境');
console.log(`未配置环境`);
}
export { ROOTPATH }
// 微信配置
const WECHAT_APPID = 'wx3ff67f2e2b0c62ca' // 从manifest.json中获取的appid
export { ROOTPATH, WECHAT_APPID }

@ -1,5 +1,6 @@
import {
ROOTPATH as baseUrl
ROOTPATH as baseUrl,
WECHAT_APPID
} from "@/common/config.js"
// 这里的Vue为Vue对象(非创建出来的实例)vm为main.js中“Vue.use(httpInterceptor, app)”这一句的第二个参数,
@ -25,10 +26,14 @@ const install = (Vue, vm) => {
console.log('config-http', config)
config.data.activity_tag = 'walksz'
config.data.activity_list_id = 13
let walksz_lifeData = uni.getStorageSync('walksz_lifeData')
let vuex_token = walksz_lifeData.vuex_token;
if (vuex_token || vm.vuex_token) {
config.header['Authorization'] = `Bearer ${vuex_token || vm.vuex_token}`;
// 优先从storage获取token因为storage更新更及时
let walksz_lifeData = uni.getStorageSync('walksz_lifeData') || {}
let vuex_token = walksz_lifeData.vuex_token || vm.vuex_token || '';
if (vuex_token) {
config.header['Authorization'] = `Bearer ${vuex_token}`;
console.log('请求携带token:', vuex_token.substring(0, 20) + '...')
} else {
console.log('请求未携带token')
}
return config;
@ -46,21 +51,22 @@ const install = (Vue, vm) => {
success: function(res) {
if (res.confirm) {
uni.removeStorageSync('walksz_lifeData')
// #ifndef H5
uni.login({
provider: 'weixin',
success: (res) => {
let url = baseUrl +
'/api/mobile/user/wechat-login'
uni.request({
url: url,
data:{
code:res.code,
activity_tag : 'walksz',
activity_list_id : 13
url: url,
data:{
code:res.code,
activity_tag : 'walksz',
activity_list_id : 13
},
method: 'GET',
success: result => {
console.log("result",result)
success: result => {
console.log("result",result)
uni.setStorageSync("walksz_lifeData",{'vuex_token':result.data.token})
const currentPage =
@ -91,15 +97,71 @@ const install = (Vue, vm) => {
});
}
});
// #endif
// #ifdef H5
// H5端跳转到微信授权页面
const redirectUri = encodeURIComponent(window.location.href.split('?')[0])
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`
window.location.href = authUrl
// #endif
// login end
}
}
}) // showConfirm end
return
} else if (res.data?.errcode === 40002 || res.data?.errcode === 40003) {
// TOKEN鉴权失败清除token并重新登录
console.log('TOKEN鉴权失败清除token')
uni.removeStorageSync('walksz_lifeData')
vm.vuex_token = ''
// #ifndef H5
uni.showModal({
title: '登录已失效',
content: '请重新登录',
showCancel: false,
success: () => {
// 重新登录
uni.login({
provider: 'weixin',
success: (loginRes) => {
let url = baseUrl + '/api/mobile/user/wechat-login'
uni.request({
url: url,
data: {
code: loginRes.code,
activity_tag: 'walksz',
activity_list_id: 13
},
method: 'GET',
success: result => {
uni.setStorageSync("walksz_lifeData", {'vuex_token': result.data.token})
vm.vuex_token = result.data.token
// 重新加载当前页面
const currentPage = getCurrentPages()[getCurrentPages().length - 1]
const currentPagePath = "/" + currentPage.route
const currentPageOptions = currentPage.options
const queryString = Object.keys(currentPageOptions).map(key => `${key}=${currentPageOptions[key]}`).join('&')
uni.reLaunch({
url: `${currentPagePath}?${queryString}`
})
}
})
}
})
}
})
// #endif
// #ifdef H5
// H5端跳转到微信授权页面
const redirectUri = encodeURIComponent(window.location.href.split('?')[0])
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`
window.location.href = authUrl
// #endif
return false
} else {
uni.showToast({
icon: "none",
title: res?.data?.errmsg
title: res?.data?.errmsg || '请求失败'
})
}
return false;

@ -3,7 +3,7 @@
*
*/
import moment from 'moment';
import { lang } from 'moment';
import { lang } from 'moment';
const base64ToFile = (dataurl, filename = 'file') => {
let arr = dataurl.split(',')
@ -63,12 +63,12 @@ const isMobile = (phoneNumber) => {
const regex = /^1[3-9]\d{9}$/;
return regex.test(phoneNumber);
}
// 分享
const shareInfo = {
title:"打卡苏州市党史教育基地",
imageUrl:"/static/share.jpg"
}
// 分享
const shareInfo = {
title:"打卡苏州市党史教育基地",
imageUrl:"/static/share.jpg"
}
// 计算距离
const getDistance = (la1, lo1, la2, lo2) => { // 当前的纬度,当前的经度,接口拿到的纬度,接口拿到的经度
@ -90,11 +90,12 @@ const getDistance = (la1, lo1, la2, lo2) => { // 当前的纬度,当前的经
return distance.toFixed(2) + '公里'
}
}
// 打开导航
const toMapAPP = (lat,lng,name) => {
let that = this
const lat1 = parseFloat(lat)
// #ifndef H5
let that = this
const lat1 = parseFloat(lat)
const lng1 = parseFloat(lng)
// 获取用户是否开启 授权获取当前的地理位置、速度的权限。
uni.getSetting({
@ -149,8 +150,8 @@ const toMapAPP = (lat,lng,name) => {
console.log('有授权');
// 有权限则直接获取
uni.openLocation({
latitude: lat1, //到达的纬度
longitude: lng1, //到达的经度
latitude: lat1, //到达的纬度
longitude: lng1, //到达的经度
name: name, //到达的名字
scale: 12,
success() {
@ -160,7 +161,22 @@ const toMapAPP = (lat,lng,name) => {
}
}
})
// #endif
// #ifdef H5
// H5端使用腾讯地图URL导航
const lat1 = parseFloat(lat)
const lng1 = parseFloat(lng)
const nameEncoded = encodeURIComponent(name || '目的地')
// 使用腾讯地图路线规划URL
const url = `https://apis.map.qq.com/uri/v1/routeplan?type=drive&to=${lat1},${lng1}&tocoord=gcj02&toname=${nameEncoded}&referer=myapp`
// 在新窗口打开
if (typeof window !== 'undefined') {
window.open(url, '_blank')
} else {
// 如果window不存在使用uni API
plus && plus.runtime.openURL(url)
}
// #endif
}
export {
@ -171,7 +187,7 @@ export {
isOnlyChinese,
isNull,
isMobile,
getDistance,
toMapAPP,
getDistance,
toMapAPP,
shareInfo
}

@ -0,0 +1,134 @@
/*
* 微信JS-SDK工具
* 用于H5端的微信分享功能
*/
import { ROOTPATH, WECHAT_APPID } from '@/common/config.js'
let wx = null
// 动态加载微信JS-SDK
const loadWxSDK = () => {
return new Promise((resolve, reject) => {
// #ifdef H5
if (typeof window !== 'undefined' && !window.wx) {
const script = document.createElement('script')
script.src = 'https://res.wx.qq.com/open/js/jweixin-1.6.0.js'
script.onload = () => {
wx = window.wx
resolve(wx)
}
script.onerror = () => {
reject(new Error('加载微信JS-SDK失败'))
}
document.head.appendChild(script)
} else if (window.wx) {
wx = window.wx
resolve(wx)
} else {
reject(new Error('不支持的环境'))
}
// #endif
// #ifndef H5
resolve(null)
// #endif
})
}
// 获取微信JS-SDK签名
const getWxSignature = () => {
return new Promise((resolve, reject) => {
// #ifdef H5
const url = window.location.href.split('#')[0]
uni.request({
url: `${ROOTPATH}/api/mobile/user/wechat-share`,
method: 'GET',
data: {
url: url,
activity_tag: 'walksz',
activity_list_id: 13
},
success: (res) => {
if (res.data && res.data.signature) {
resolve(res.data)
} else {
reject(new Error('获取签名失败'))
}
},
fail: (err) => {
reject(err)
}
})
// #endif
// #ifndef H5
resolve(null)
// #endif
})
}
// 初始化微信JS-SDK
const initWxSDK = (shareConfig = {}) => {
return new Promise((resolve, reject) => {
// #ifdef H5
loadWxSDK().then(() => {
getWxSignature().then((signatureData) => {
const { signature, timestamp, nonceStr } = signatureData
wx.config({
debug: false,
appId: WECHAT_APPID,
timestamp: timestamp,
nonceStr: nonceStr,
signature: signature,
jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData']
})
wx.ready(() => {
// 分享到朋友
wx.updateAppMessageShareData({
title: shareConfig.title || '打卡苏州市党史教育基地',
desc: shareConfig.desc || '打卡苏州市党史教育基地',
link: shareConfig.link || window.location.href,
imgUrl: shareConfig.imgUrl || `${window.location.origin}/static/share.jpg`,
success: () => {
console.log('分享到朋友成功')
}
})
// 分享到朋友圈
wx.updateTimelineShareData({
title: shareConfig.title || '打卡苏州市党史教育基地',
link: shareConfig.link || window.location.href,
imgUrl: shareConfig.imgUrl || `${window.location.origin}/static/share.jpg`,
success: () => {
console.log('分享到朋友圈成功')
}
})
resolve(wx)
})
wx.error((res) => {
console.error('微信JS-SDK配置失败', res)
reject(res)
})
}).catch((err) => {
console.error('获取签名失败', err)
reject(err)
})
}).catch((err) => {
console.error('加载微信JS-SDK失败', err)
reject(err)
})
// #endif
// #ifndef H5
resolve(null)
// #endif
})
}
export {
loadWxSDK,
getWxSignature,
initWxSDK
}

@ -30,10 +30,10 @@
id: 0,
centerItem: false,
width: 71,
height: 58,
"text": "首页",
"pagePath": "/pages/home/home",
"iconPath": require("@/static/icon1.png"),
height: 58,
"text": "首页",
"pagePath": "/pages/home/home",
"iconPath": require("@/static/icon1.png"),
"selectedIconPath": require("@/static/icon1-cur.png")
},
{
@ -41,47 +41,58 @@
centerItem: false,
width: 72,
height: 65,
"text": "抗战",
"pagePath": "/pages/line/war",
"iconPath": require("@/static/icon5.png"),
"text": "抗战",
"pagePath": "/pages/line/war",
"iconPath": require("@/static/icon5.png"),
"selectedIconPath": require("@/static/icon5-cur.png")
},
{
id: 2,
centerItem: false,
width: 47,
height: 76,
"text": "书房",
"pagePath": "/pages/book/house",
"iconPath": require("@/static/icon6.png"),
"selectedIconPath": require("@/static/icon6-cur.png")
},
{
id: 3,
centerItem: false,
width: 54,
height: 60,
"text": "我的",
"pagePath": "/pages/me/me",
"iconPath": require("@/static/icon3.png"),
"selectedIconPath": require("@/static/icon3-cur.png")
},
{
id: 2,
centerItem: false,
width: 47,
height: 76,
"text": "书房",
"pagePath": "/pages/book/house",
"iconPath": require("@/static/icon6.png"),
"selectedIconPath": require("@/static/icon6-cur.png")
},
{
id: 3,
centerItem: false,
width: 54,
height: 60,
"text": "我的",
"pagePath": "/pages/me/me",
"iconPath": require("@/static/icon3.png"),
"selectedIconPath": require("@/static/icon3-cur.png")
}
]
};
},
mounted() {
this.currentItem = this.currentPage;
// #ifndef H5
// tabbar使tabbar
uni.hideTabBar();
// #endif
},
methods: {
changeItem(item) {
let _this = this;
let _this = this;
console.log(item.pagePath)
//_this.currentItem = item.id;
//_this.currentItem = item.id;
// #ifndef H5
uni.switchTab({
url: item.pagePath
});
// #endif
// #ifdef H5
// H5使uni.navigateTouni.reLaunch
uni.reLaunch({
url: item.pagePath
});
// #endif
}
}
};
@ -102,10 +113,10 @@
display: flex;
align-items: center;
padding: 10rpx 0;
color: #6E6E6E;
z-index: 9999;
background: #fff;
background: #fff;
color: #6E6E6E;
z-index: 9999;
background: #fff;
background: #fff;
border-top:10rpx solid #dbd0ba;
}
@ -131,15 +142,15 @@
.tabbar-container .tabbar-item .item-top {
/* width: 56rpx;
height: 44rpx; */
margin: 10rpx 0;
position: relative;
width: 120rpx;
margin: 10rpx 0;
position: relative;
width: 120rpx;
height: 61rpx;
}
.tabbar-container .tabbar-item .item-top image {
vertical-align: middle;
position: relative;
vertical-align: middle;
position: relative;
z-index:999999;
}
@ -151,22 +162,22 @@
.tabbar-container .center-item .item-bottom {
/* position: absolute;
bottom: 5rpx; */
}
.tabbar-container .center-item .item-top::before {
content:'';
width: 120rpx;
height: 80rpx;
position: absolute;
/* top: -50rpx;
left: calc(50% - 50rpx); */
top:5%;
left:50%;
transform: translate(-50%,-50%);
border-radius: 60rpx 60rpx 0 0;
box-shadow: 0 -6rpx 12rpx rgba(0, 0, 0, 0.1);
z-index:99999;
background-color: #fff;
/* background-color: #ffffff; */
}
.tabbar-container .center-item .item-top::before {
content:'';
width: 120rpx;
height: 80rpx;
position: absolute;
/* top: -50rpx;
left: calc(50% - 50rpx); */
top:5%;
left:50%;
transform: translate(-50%,-50%);
border-radius: 60rpx 60rpx 0 0;
box-shadow: 0 -6rpx 12rpx rgba(0, 0, 0, 0.1);
z-index:99999;
background-color: #fff;
/* background-color: #ffffff; */
}
</style>

@ -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"
}
}
}
}
}

@ -5,8 +5,8 @@
<u-image id="share-img" v-show="!isHidden" class="share-img" mode="scaleToFill" :width="133" :height="133"
:src="require('../static/cer-share.png')" @click="$u.throttle(share)"> mode=</u-image>
<div @click="back" :style="{'position':'absolute','left':'20rpx','top':backTop+'px','height':backHeight+'px','line-height':backHeight+'px'}">
<u-icon name="arrow-left" color="#fff" size="40"></u-icon>
<div @click="back" :style="{'position':'absolute','left':'20rpx','top':backTop+'px','height':backHeight+'px','line-height':backHeight+'px'}">
<u-icon name="arrow-left" color="#fff" size="40"></u-icon>
</div>
<div class="logo1">
<u-image :lazy-load="false" :show-loading="false" width="176" height="450"
@ -46,9 +46,9 @@
<view class="share-mask" @click="isHidden = false">
</view>
<view class="share-page">
<cover-view class="share-page__close" @click="isHidden = false">
x
<view class="share-page">
<cover-view class="share-page__close" @click="isHidden = false">
x
</cover-view>
<!-- <image :src="imgData" mode="widthFix"></image> -->
<canvas :style="{width:'90%',height:SCREEN_HEIGHT*0.7+'px',margin:'0 auto'}" canvas-id="firstCanvas" id="firstCanvas"></canvas>
@ -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;

@ -19,7 +19,7 @@
<view class="detail-image" v-if="info.image">
<image :src="info.image.url" mode="widthFix"></image>
</view>
<view class="detail-content-content">
<view class="detail-content-content">
<u-parse v-if='showContent' :html="info.content?info.content:' '"></u-parse>
<!-- <rich-text v-if='showContent' :nodes="info.content?info.content:' '"></rich-text> -->
</view>
@ -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');
}
}
}

@ -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

@ -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": "我的",

@ -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
}

@ -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()
},

File diff suppressed because it is too large Load Diff

@ -17,13 +17,13 @@
</view>
</view>
</view>
</view>
<view class="support">
<view>
<p>技术支持:江苏有线苏州分公司</p>
</view>
</view>
<view class="support">
<view>
<p>技术支持:江苏有线苏州分公司</p>
</view>
</view>
</view>
</view>
@ -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 @@
}
}
}
}

@ -61,9 +61,9 @@
</template>
<script>
import tabbar from '@/components/tabbar/tabbar.vue'
import {
shareInfo
import tabbar from '@/components/tabbar/tabbar.vue'
import {
shareInfo
} from '@/common/util.js'
export default {
components: {
@ -73,23 +73,28 @@
return {
navBarTop: 0,
listLine: [],
colorList: ['#dbd0ba','#ad6e46','#666d95','#6d7c4c'],
colorList: ['#dbd0ba','#ad6e46','#666d95','#6d7c4c'],
replaceImg:require('@/static/share.jpg')
}
},
onShareAppMessage() {
return shareInfo
},
onShareTimeline(){
return shareInfo
},
onShareAppMessage() {
return shareInfo
},
onShareTimeline(){
return shareInfo
},
onReady() {
},
onLoad() {
// #ifndef H5
const MenuButton = uni.getMenuButtonBoundingClientRect()
this.navBarTop = MenuButton.top //
// #endif
// #ifdef H5
this.navBarTop = 44 // H5
// #endif
// this.getUserLocation()
this.getLines()
},
@ -98,25 +103,25 @@
const res = await this.$u.api.baseFormIndex({
table_name: "circuits",
page: 1,
page_size: 999,
sort_name:'sort',
page_size: 999,
sort_name:'sort',
sort_type:'ASC'
// with_relations:['image']
})
res.data.map((item,index)=>{
item.color = this.colorList[index%this.colorList.length]
let orderMap = item.pointer_list.reduce((acc, val, idx) => {
acc[val] = idx;
return acc;
}, {});
item.pointer.sort((a, b) => {
// abarr+1
let indexA = orderMap[a.id] !== undefined ? orderMap[a.id] : item.pointer_list.length;
let indexB = orderMap[b.id] !== undefined ? orderMap[b.id] : item.pointer_list.length;
//
return indexA - indexB;
});
})
res.data.map((item,index)=>{
item.color = this.colorList[index%this.colorList.length]
let orderMap = item.pointer_list.reduce((acc, val, idx) => {
acc[val] = idx;
return acc;
}, {});
item.pointer.sort((a, b) => {
// abarr+1
let indexA = orderMap[a.id] !== undefined ? orderMap[a.id] : item.pointer_list.length;
let indexB = orderMap[b.id] !== undefined ? orderMap[b.id] : item.pointer_list.length;
//
return indexA - indexB;
});
})
this.listLine = res.data
},

@ -62,16 +62,16 @@
play-btn-position="center"></video>
<view class="closevideo" @click="playvideo=false,videoUrl=''">X</view>
</view>
</view>
<!-- 文章 -->
<view class="articleLine">
<block v-if="articleList.length>0">
<view class="articleLine-item" v-for="item in articleList" @click="goArticle(item.id)">
<view class="articleLine-item-dot"></view>
<view class="articleLine-item-title">{{item.title}}</view>
</view>
</block>
</view>
<!-- 文章 -->
<view class="articleLine">
<block v-if="articleList.length>0">
<view class="articleLine-item" v-for="item in articleList" @click="goArticle(item.id)">
<view class="articleLine-item-dot"></view>
<view class="articleLine-item-title">{{item.title}}</view>
</view>
</block>
</view>
<tabbar :currentPage="1"></tabbar>
@ -94,7 +94,7 @@
showMore: false,
videoList: [],
playvideo: false,
videoUrl: '',
videoUrl: '',
articleList:[]
}
@ -109,11 +109,16 @@
},
onLoad() {
// #ifndef H5
const MenuButton = uni.getMenuButtonBoundingClientRect()
this.navBarTop = MenuButton.top //
// #endif
// #ifdef H5
this.navBarTop = 44 // H5
// #endif
// this.getUserLocation()
this.getLines()
this.getVideos()
this.getVideos()
this.getArticles()
},
methods: {
@ -172,11 +177,11 @@
'filter[0][value]': 1,
})
this.articleList = res.data
},
goArticle(e) {
uni.navigateTo({
url: '/packages/detail/articleDetail?id=' + e,
});
},
goArticle(e) {
uni.navigateTo({
url: '/packages/detail/articleDetail?id=' + e,
});
},
}
}
@ -409,32 +414,32 @@
}
}
}
}
.articleLine {
position: relative;
z-index: 99;
padding: 60rpx 30rpx;
padding-top: 40rpx;
margin-top: 30rpx;
width: 100%;
&-item{
display: flex;
align-items: center;
color:#565656;
font-size: 28rpx;
border-bottom: 1rpx solid rgba(0,0,0,0.1);
padding:40rpx 0;
&-dot{
width:10rpx;
height:10rpx;
border-radius: 10rpx;
background-color: #565656;
}
&-title{
width:calc(100% - 10rpx);
padding-left:20rpx;
}
}
}
.articleLine {
position: relative;
z-index: 99;
padding: 60rpx 30rpx;
padding-top: 40rpx;
margin-top: 30rpx;
width: 100%;
&-item{
display: flex;
align-items: center;
color:#565656;
font-size: 28rpx;
border-bottom: 1rpx solid rgba(0,0,0,0.1);
padding:40rpx 0;
&-dot{
width:10rpx;
height:10rpx;
border-radius: 10rpx;
background-color: #565656;
}
&-title{
width:calc(100% - 10rpx);
padding-left:20rpx;
}
}
}
}
</style>

@ -57,7 +57,7 @@
</view>
</view>
<!-- 弹出头像 昵称 -->
<u-popup v-model="showform" class="login" mode="bottom" :mask-close-able="maskClose">
<u-popup v-model="showform" class="login" mode="bottom">
<view class="login-top">
<view class="">
<image src="../../static/me-icon0.png" mode=""></image>
@ -76,9 +76,16 @@
<view class="login-form">
<view>
<view style="border:none">
<!-- #ifndef H5 -->
<button plain open-type="chooseAvatar" @chooseavatar='onChooseAvatar' style="padding: 0;margin: 0;">
<image :src="imgurl" mode=""></image>
</button>
<!-- #endif -->
<!-- #ifdef H5 -->
<view class="avatar-upload-btn" @click="chooseImageH5">
<image :src="imgurl" mode=""></image>
</view>
<!-- #endif -->
</view>
<view>上传头像</view>
</view>
@ -155,8 +162,13 @@
return shareInfo
},
onLoad() {
// #ifndef H5
const MenuButton = uni.getMenuButtonBoundingClientRect()
this.navBarTop = MenuButton.top //
// #endif
// #ifdef H5
this.navBarTop = 44 // H5
// #endif
this.getConfig()
},
onShow() {
@ -164,25 +176,72 @@
this.getDone()
},
methods: {
// #ifndef H5
onChooseAvatar(e) {
console.log(e)
console.log(e);
let a = uni.uploadFile({
this.uploadAvatar(e.detail.avatarUrl)
},
// #endif
// #ifdef H5
chooseImageH5() {
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
console.log('H5选择图片:', res)
if (res.tempFilePaths && res.tempFilePaths.length > 0) {
this.uploadAvatar(res.tempFilePaths[0])
}
},
fail: (err) => {
console.error('H5选择图片失败:', err)
uni.showToast({
title: '选择图片失败',
icon: 'none'
})
}
})
},
// #endif
uploadAvatar(filePath) {
uni.showLoading({
title: '上传中...'
})
uni.uploadFile({
url: baseUrl + "/api/mobile/upload-file",
filePath: e.detail.avatarUrl,
filePath: filePath,
name: 'file',
formData: {
token: this.vuex_token
},
success: (res) => {
uni.hideLoading()
uni.showToast({
title: '上传成功',
duration: 1000
})
console.log("res", res)
this.imgurl = JSON.parse(res.data).url
this.form.headimgurl = this.imgurl
console.log("上传成功", res)
try {
const data = JSON.parse(res.data)
this.imgurl = data.url
this.form.headimgurl = this.imgurl
} catch (error) {
console.error('解析上传结果失败:', error)
uni.showToast({
title: '上传失败',
icon: 'none'
})
}
},
fail: (err) => {
uni.hideLoading()
console.error('上传失败:', err)
uni.showToast({
title: '上传失败',
icon: 'none'
})
}
})
},
@ -462,6 +521,31 @@
height: 100%;
}
}
// #ifdef H5
.avatar-upload-btn {
width: 100rpx;
height: 100rpx;
border-radius: 100rpx;
border: none;
background-color: #fff;
margin: 0 auto;
margin-bottom: 10rpx;
cursor: pointer;
overflow: hidden;
position: relative;
&:hover {
opacity: 0.8;
}
image {
width: 100%;
height: 100%;
display: block;
}
}
// #endif
}

Loading…
Cancel
Save