迁移嘉兴学院的签到定位页面移植-1

This commit is contained in:
2026-11-04 14:58:21 +08:00
parent 0de8ee9232
commit 406ffe71af
2 changed files with 481 additions and 75 deletions
@@ -779,7 +779,10 @@ public class TrainSignUpActivityServiceImpl extends BaseServiceImpl<TrainSignUpA
Cnd.where("activityId", "=", activity.getId()).asc("orderNum"));
List<NutMap> signPoints = courses.stream().map(item -> NutMap.NEW().addv("courseId", item.getId())
.addv("courseName", item.getCourseName()).addv("courseLocation", item.getCourseLocation())
.addv("signed", attended.stream().anyMatch(record -> Objects.equals(record.getCourseId(), item.getId()))))
.addv("signed", attended.stream().anyMatch(record -> Objects.equals(record.getCourseId(), item.getId())))
// 同一课程可能有多个课次,展示该点位最早的有效签到时间,兼容历史空时间。
.addv("attendTime", attended.stream().filter(record -> Objects.equals(record.getCourseId(), item.getId()))
.map(TrainSignUpUserCourse::getAttendTime).filter(Objects::nonNull).min(Date::compareTo).orElse(null)))
.collect(Collectors.toList());
Map<String, Object> savedValues = new HashMap<>();
List<TrainSignUpUser> signUsers = dao().query(TrainSignUpUser.class,
@@ -1,82 +1,437 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style scoped>
.sign-page { min-height: 100vh; background: #f5f6f8; }
.sign-map { width: 100%; height: 42vh; background: #e8edf2; }
.sign-panel { padding: 18px 16px 28px; background: #fff; }
.sign-title { margin: 0 0 6px; font-size: 20px; font-weight: 600; text-align: center; }
.sign-location { color: #7d8490; font-size: 13px; text-align: center; }
.sign-progress { margin: 20px 0 8px; display: flex; align-items: center; justify-content: space-between; }
.sign-progress strong { color: #0878d1; font-size: 18px; }
.sign-message { min-height: 24px; margin: 16px 0; color: #606773; text-align: center; }
.sign-message.success { color: #07c160; }
.sign-message.error { color: #ee0a24; }
.sign-actions { display: grid; gap: 12px; }
.location-panel { padding: 12px 16px; background: #fff; }
.location-tools { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.location-message { color: #606773; font-size: 13px; overflow-wrap: anywhere; }
.point-list { max-height: 54vh; overflow-y: auto; }
.point-row { display: flex; justify-content: space-between; padding: 14px 16px; border-bottom: 1px solid #f0f1f3; }
.point-row small { display: block; margin-top: 4px; color: #969799; }
.point-state { color: #969799; }
.point-state.signed { color: #07c160; }
.form-popup { max-height: 62vh; overflow-y: auto; }
.popup-footer { padding: 12px 16px calc(12px + env(safe-area-inset-bottom)); }
.legacy-result { min-height: 52vh; padding-top: 36px; background: #fff; }
<style>
/* 沿用点位签到组件的纵向布局:地图伸展,信息和操作保留自身高度,小屏可滚动。 */
#app.brand-train-sign-page {
display: flex;
height: 100vh;
height: 100dvh;
width: 100%;
min-width: 0;
min-height: 0;
flex-direction: column;
overflow-x: hidden;
overflow-y: auto;
background: #f4f7fc;
}
.brand-train-sign-page > .van-nav-bar__placeholder {
flex-shrink: 0;
}
/* 仅本页沿用参考签到页的亮蓝主题,不改变其他业务页面的全局 Vant 配色。 */
.brand-train-sign-page .van-nav-bar__text,
.brand-train-sign-page .van-nav-bar .van-icon,
.brand-train-sign-page .van-tag--primary {
color: #1989fa;
}
.brand-train-sign-page .van-button--info {
border-color: #1989fa;
background: #1989fa;
}
.brand-train-sign-page .van-button--info.van-button--plain {
background: #fff;
color: #1989fa;
}
.brand-train-sign-content {
display: flex;
flex: 1 0 auto;
min-width: 0;
flex-direction: column;
}
.brand-train-sign-map {
/* 固定 SDK 容器定位,防止地图控件溢出到信息区和底部按钮。 */
position: relative !important;
z-index: 0;
flex: 1 0 240px;
width: 100%;
min-height: 240px;
overflow: hidden;
}
.brand-train-sign-details {
flex-shrink: 0;
min-width: 0;
max-width: 100%;
box-sizing: border-box;
padding: 16px;
background: #fff;
}
.brand-train-sign-title {
color: #263548;
font-size: 16px;
font-weight: 600;
line-height: 24px;
overflow-wrap: anywhere;
}
.brand-train-sign-title-row {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px 12px;
}
.brand-train-sign-signed {
color: #07c160;
font-size: 12px;
line-height: 20px;
}
.brand-train-sign-signed .van-icon {
margin-right: 4px;
vertical-align: middle;
}
.brand-train-sign-location-tools {
display: flex;
margin-bottom: 12px;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.brand-train-sign-location-tools .van-button {
flex-shrink: 0;
height: 32px;
padding: 0 2px;
border: 0;
background: transparent;
}
.brand-train-sign-location-status {
color: #78869a;
font-size: 12px;
line-height: 18px;
overflow-wrap: anywhere;
}
.brand-train-sign-location-status.is-in-range {
color: #263548;
}
.brand-train-sign-location-status.is-in-range::before {
display: inline-block;
width: 8px;
height: 8px;
margin-right: 6px;
border-radius: 50%;
background: #07c160;
content: '';
}
.brand-train-sign-text {
margin-top: 6px;
color: #78869a;
font-size: 13px;
line-height: 20px;
overflow-wrap: anywhere;
}
.brand-train-sign-text .van-icon {
margin-right: 4px;
vertical-align: middle;
}
.brand-train-sign-progress {
min-width: 0;
max-width: 100%;
box-sizing: border-box;
margin-top: 14px;
padding: 12px;
border-radius: 10px;
background: #f4f7fc;
color: #78869a;
font-size: 13px;
line-height: 20px;
}
.brand-train-sign-progress-header {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 4px 8px;
margin-bottom: 8px;
}
.brand-train-sign-progress-heading {
color: #263548;
font-size: 14px;
font-weight: 600;
}
.brand-train-sign-record-link {
display: inline-flex;
min-height: 32px;
margin-left: auto;
padding: 0;
align-items: center;
flex-shrink: 0;
border: 0;
background: transparent;
color: #1989fa;
font-size: 13px;
cursor: pointer;
}
.brand-train-sign-count {
margin: 0 3px;
color: #1989fa;
font-size: 22px;
font-weight: 600;
}
.brand-train-sign-progress-track {
/* 使用容器百分比宽度,避免旧组件缓存像素宽度后在屏幕尺寸变化时越出卡片。 */
width: 100%;
height: 8px;
margin-top: 10px;
overflow: hidden;
border-radius: 8px;
background: #dce3ee;
}
.brand-train-sign-progress-fill {
display: block;
height: 100%;
max-width: 100%;
border-radius: inherit;
background: #1989fa;
transition: width 0.25s ease;
}
.brand-train-sign-progress-message {
margin-top: 8px;
font-size: 12px;
line-height: 18px;
}
.brand-train-sign-map-warning {
color: #ee0a24;
}
.brand-train-sign-footer {
/* 状态留在信息区,底栏仅容纳操作;双按钮平分宽度,单按钮居中且不铺满屏幕。 */
position: sticky;
bottom: 0;
z-index: 3;
display: flex;
flex-shrink: 0;
justify-content: center;
gap: 12px;
padding: 12px 24px;
padding-bottom: calc(12px + env(safe-area-inset-bottom));
border-top: 1px solid #edf0f5;
background: #fff;
}
.brand-train-sign-footer .van-button {
flex: 1;
min-width: 0;
height: 40px;
padding: 0 8px;
border-radius: 8px;
font-size: 14px;
}
.brand-train-sign-footer .van-button:only-child {
flex: 0 1 180px;
}
.brand-train-sign-points-popup {
/* 从右侧滑入并覆盖整个视口;导航和底部提示保留高度,点位卡片区域独立滚动。 */
display: flex;
width: 100%;
height: 100%;
height: 100dvh;
flex-direction: column;
box-sizing: border-box;
overflow: hidden;
background: #f5f7fa;
}
.brand-train-sign-points-popup > .van-nav-bar {
flex-shrink: 0;
}
.brand-train-sign-points-list {
flex: 1;
min-height: 0;
padding: 16px;
overflow-y: auto;
overscroll-behavior: contain;
}
.brand-train-sign-point {
margin-bottom: 12px;
padding: 16px;
border: 1px solid #e9edf4;
border-radius: 12px;
background: #fff;
}
.brand-train-sign-point:last-child {
margin-bottom: 0;
}
.brand-train-sign-point .brand-train-sign-title {
font-size: 18px;
line-height: 28px;
}
.brand-train-sign-point .brand-train-sign-text {
margin-top: 10px;
}
.brand-train-sign-point-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 12px;
}
.brand-train-sign-point-header .brand-train-sign-title-row {
flex: 1;
min-width: 0;
gap: 4px 8px;
}
.brand-train-sign-point-status {
flex-shrink: 0;
padding: 4px 8px;
border-radius: 8px;
background: #fff7e9;
color: #d98a13;
font-size: 12px;
line-height: 20px;
white-space: nowrap;
}
.brand-train-sign-point-status.is-signed {
background: #e8fbf2;
color: #07c160;
}
.brand-train-sign-point-status .van-icon {
margin-right: 4px;
font-size: 14px;
vertical-align: middle;
}
.brand-train-sign-point-time {
margin-top: 12px;
padding-top: 12px;
border-top: 1px solid #edf0f5;
color: #78869a;
font-size: 12px;
line-height: 18px;
}
.brand-train-sign-point-time-value {
display: block;
margin-top: 4px;
color: #3b4b60;
font-size: 14px;
line-height: 20px;
overflow-wrap: anywhere;
}
.brand-train-sign-points-note {
flex-shrink: 0;
padding: 12px 16px;
padding-bottom: calc(12px + env(safe-area-inset-bottom));
border-top: 1px solid #edf0f5;
background: #fff;
color: #78869a;
font-size: 12px;
line-height: 18px;
text-align: center;
}
.form-popup { padding: 16px; overflow-y: auto; }
.popup-footer { padding: 12px 16px calc(12px + env(safe-area-inset-bottom)); background: #fff; }
</style>
<div id="app" class="sign-page">
<div id="app" class="brand-train-sign-page" v-cloak>
<van-nav-bar title="活动签到" left-text="返回" left-arrow @click-left="onNavBack" fixed placeholder></van-nav-bar>
<div id="mapContainer" class="sign-map"></div>
<div class="location-panel">
<div class="location-tools">
<span class="location-message" role="status">{{locationMessage}}</span>
<van-button size="small" plain type="info" icon="aim"
:loading="locating || mapLoading" :disabled="signLoading || courseLoading"
@click="refreshPosition">{{mapReady ? '重新定位' : '重新加载地图'}}</van-button>
</div>
<div v-if="distance !== null" class="location-message">
距签到地点约 {{Math.ceil(distance)}} 米,签到范围 {{signRadius}} 米
</div>
</div>
<template v-if="extensionEnabled">
<section class="sign-panel">
<h1 class="sign-title">{{signData.activityName || '活动签到'}}</h1>
<div class="sign-location">{{signData.courseName}}<span v-if="signData.courseLocation"> · {{signData.courseLocation}}</span></div>
<div class="sign-progress"><span>签到进度</span><strong>{{signData.signCount || 0}} / {{signData.signPointCount || 0}}</strong></div>
<van-progress :percentage="progressPercentage" color="#07c160" track-color="#e9edf1" stroke-width="8"></van-progress>
<div class="sign-message" :class="messageType">{{statusMessage}}</div>
<div class="sign-actions">
<van-button type="primary" block :loading="signLoading" :disabled="signDisabled" @click="onSign">
{{signData.currentPointSigned ? '当前点位已签到' : '立即签到'}}
</van-button>
<van-button plain type="info" block @click="openPopup('points')">查看全部签到点位</van-button>
<van-button v-if="signData.needDynamicForm" type="info" block @click="openPopup('form')">填写达标信息</van-button>
<van-button v-if="signData.needWelfareSelect" type="warning" block @click="goWelfare">选择礼物或福利</van-button>
<div class="brand-train-sign-content">
<div id="mapContainer" class="brand-train-sign-map"></div>
<section class="brand-train-sign-details">
<div class="brand-train-sign-location-tools">
<span class="brand-train-sign-location-status" role="status"
:class="{'brand-train-sign-map-warning': locationFailed || distance !== null && !isInRange,
'is-in-range': !locationFailed && !locating && isInRange}">{{locationMessage}}</span>
<van-button size="small" plain type="info" icon="aim"
:loading="locating || mapLoading" :disabled="signLoading || courseLoading"
@click="refreshPosition">{{mapReady ? '重新定位' : '重新加载地图'}}</van-button>
</div>
<div class="brand-train-sign-title-row">
<div class="brand-train-sign-title">{{signData.courseName || row.courseName || '活动签到'}}</div>
<span v-if="currentPointSigned" class="brand-train-sign-signed" role="status">
<van-icon name="checked"></van-icon>当前点位已签到
</span>
</div>
<div class="brand-train-sign-text">签到范围:{{signRadius}} 米</div>
<div v-if="distance !== null" class="brand-train-sign-text">距签到地点约 {{Math.ceil(distance)}} 米</div>
<div v-if="extensionEnabled" class="brand-train-sign-progress">
<div class="brand-train-sign-progress-header">
<span class="brand-train-sign-progress-heading">活动签到进度</span>
<van-tag v-if="signData.isReachTarget" plain type="success">活动已达标</van-tag>
<button type="button" class="brand-train-sign-record-link" @click="openPopup('points')">
点位打卡情况<van-icon name="arrow"></van-icon>
</button>
</div>
<div>已打卡 <strong class="brand-train-sign-count">{{signData.signCount || 0}}</strong> 个 / 达标需 {{signData.signPointCount || 0}} 个</div>
<div class="brand-train-sign-progress-track" role="progressbar" aria-label="活动签到进度"
aria-valuemin="0" aria-valuemax="100" :aria-valuenow="progressPercentage">
<span class="brand-train-sign-progress-fill" :style="{width: progressPercentage + '%'}"></span>
</div>
<div class="brand-train-sign-progress-message" role="status"
:class="{'brand-train-sign-map-warning': messageType === 'error'}">{{progressMessage}}</div>
</div>
<div v-else class="brand-train-sign-text">{{legacyResult.msg}}</div>
</section>
</template>
<div v-else class="weui-msg legacy-result">
<div class="weui-msg__icon-area">
<i v-if="legacyResult.code !== 0" class="weui-icon-warn weui-icon_msg"></i>
<i v-else class="weui-icon-success weui-icon_msg"></i>
<div v-if="showSignButton || showDynamicFormButton || signData.needWelfareSelect" class="brand-train-sign-footer">
<van-button v-if="showDynamicFormButton" :plain="showSignButton" type="info"
:disabled="signLoading || formLoading" @click="openPopup('form')">填写详细信息</van-button>
<van-button v-if="signData.needWelfareSelect" :plain="showSignButton" type="info"
:disabled="signLoading || formLoading" @click="goWelfare">去选择福利</van-button>
<van-button v-if="showSignButton" type="info" loading-text="签到中..."
:loading="signLoading" :disabled="signDisabled" @click="onSign">确认签到</van-button>
</div>
<div class="weui-msg__text-area"><div class="weui-msg__title">温馨提醒</div><div>{{legacyResult.msg || '正在获取签到信息'}}</div></div>
<div class="weui-msg__opr-area"><p class="weui-btn-area">
<van-button v-if="legacyResult.code !== 0" type="primary" block :loading="signLoading" :disabled="signDisabled" @click="onSign">确认签到</van-button>
<a v-else class="weui-btn weui-btn_primary">您已签到</a>
</p></div>
</div>
<van-popup :value="pointPopup" @input="visible => { if (!visible) closePopup('points') }" position="bottom" round :close-on-click-overlay="false" :style="{height: '62vh'}">
<van-nav-bar title="签到点位" left-text="关闭" left-arrow @click-left="closePopup('points')"></van-nav-bar>
<div class="point-list">
<div class="point-row" v-for="point in signData.signPoints" :key="point.courseId">
<div>{{point.courseName}}<small>{{point.courseLocation || '未填写地点'}}</small></div>
<span class="point-state" :class="{signed: point.signed}">{{point.signed ? '已签到' : '未签到'}}</span>
<van-popup :value="pointPopup" class="brand-train-sign-points-popup" position="right"
@input="visible => { if (!visible) closePopup('points') }" :close-on-click-overlay="false">
<van-nav-bar title="点位打卡情况" left-text="返回" left-arrow @click-left="closePopup('points')"></van-nav-bar>
<div ref="signPointsList" class="brand-train-sign-points-list">
<van-empty v-if="!displaySignPoints.length" description="暂无点位信息"></van-empty>
<div v-for="point in displaySignPoints" :key="point.courseId" class="brand-train-sign-point">
<div class="brand-train-sign-point-header">
<div class="brand-train-sign-title-row">
<div class="brand-train-sign-title">{{point.courseName || '点位名称未填写'}}</div>
<van-tag v-if="point.courseId === courseId" plain type="primary">当前点位</van-tag>
</div>
<span class="brand-train-sign-point-status" :class="{'is-signed': point.signed === true}">
<van-icon :name="point.signed === true ? 'checked' : 'clock-o'"></van-icon>{{point.signed === true ? '已打卡' : '未打卡'}}
</span>
</div>
<div class="brand-train-sign-text"><van-icon name="location-o"></van-icon>地点:{{point.courseLocation || '未填写地点名称'}}</div>
<div v-if="point.signed === true" class="brand-train-sign-point-time">
签到时间
<span class="brand-train-sign-point-time-value">{{formatAttendTime(point.attendTime)}}</span>
</div>
</div>
</div>
<div class="brand-train-sign-points-note">
{{signData.isReachTarget ? '活动已达标,仍可继续打卡其他点位' : '完成 ' + (signData.signPointCount || 0) + ' 个不同点位打卡即可达标'}}
</div>
</van-popup>
<van-popup :value="formPopup" @input="visible => { if (!visible) closePopup('form') }" position="bottom" round :close-on-click-overlay="false" :style="{height: '78vh'}">
<van-nav-bar title="填写签到信息" left-text="关闭" left-arrow @click-left="closePopup('form')"></van-nav-bar>
@@ -101,10 +456,34 @@ layout("/layouts/platform_h5.html"){
statusMessage: "请获取定位后完成签到", messageType: "", signLoading: false, formLoading: false,
pointPopup: false, formPopup: false,
mapReady: false, mapLoading: false, locating: false, courseLoading: true,
locationMessage: "正在加载签到地点", currentPosition: null, distance: null
locationMessage: "正在加载签到地点", locationFailed: false, currentPosition: null, distance: null
}
},
computed: {
currentPointSigned() {
return this.extensionEnabled ? this.signData.currentPointSigned === true : this.legacyResult.code === 0
},
showSignButton() {
return !this.courseLoading && !this.currentPointSigned
},
showDynamicFormButton() {
return this.signData.isReachTarget === true && this.signData.needDynamicForm === true
},
isInRange() {
return this.distance !== null && this.distance <= this.signRadius
},
// 达标与当前点位签到分别提示;错误优先,保留接口返回的处理失败原因。
progressMessage() {
if (this.messageType === "error") return this.statusMessage
if (this.signData.isReachTarget && !this.currentPointSigned) return "已达标,可继续打卡其他点位。"
if (this.signData.isReachTarget) return this.statusMessage
return this.currentPointSigned ? "请继续完成其他点位签到。" : "到达点位后,点击确认签到。"
},
// 未打卡项优先,组内保留接口中的点位序号,不能改动原数组。
displaySignPoints() {
const points = Array.isArray(this.signData.signPoints) ? this.signData.signPoints : []
return points.filter(point => point.signed !== true).concat(points.filter(point => point.signed === true))
},
// 本项目点位为GCJ-02[纬度,经度],不能使用参考工程的[经度,纬度]下标。
sitePosition() {
const p = this.row.courseLocationCoordinates
@@ -127,6 +506,11 @@ layout("/layouts/platform_h5.html"){
}
},
methods: {
/** attendTime为首次签到时间;返回可读时间,历史数据缺失时显示未记录。 */
formatAttendTime(attendTime) {
const time = attendTime ? this.$moment(attendTime) : null
return time && time.isValid() ? time.format("YYYY-MM-DD HH:mm:ss") : "未记录"
},
/**
* 复用布局中的腾讯地图Key;定位组件仅在扫码页按需加载。
* 返回SDK就绪Promise,失败时移除脚本,允许重试并处理页面销毁。
@@ -173,7 +557,7 @@ layout("/layouts/platform_h5.html"){
() => window.LBS && LBS.WebComponent && LBS.WebComponent.Geolocation)
]).then(() => key)
},
/** 地图标记使用静态文字区分地点与本人,同点位时标签分别显示在上方与下方。 */
/** 地图标记使用静态文字区分地点与本人,below决定标签显示在坐标下方或上方。 */
markerStyle(label, color, below) {
const y = below ? 12 : 36
const top = below ? 25 : 1
@@ -189,6 +573,7 @@ layout("/layouts/platform_h5.html"){
if (scanRuntime.destroyed || this.mapLoading) return Promise.resolve()
if (this.mapReady) return this.refreshPosition()
if (!this.sitePosition || !this.signRadius) {
this.$set(this, "locationFailed", true)
this.$set(this, "locationMessage", "当前点位未设置有效坐标或签到半径,请联系管理员")
return Promise.resolve()
}
@@ -202,7 +587,9 @@ layout("/layouts/platform_h5.html"){
scanRuntime.markers = new TMap.MultiMarker({
map: scanRuntime.map,
styles: {target: this.markerStyle("签到地点", "#ee0a24", false),
current: this.markerStyle("我的位置", "#1989fa", true)},
targetBelow: this.markerStyle("签到地点", "#ee0a24", true),
current: this.markerStyle("我的位置", "#1989fa", true),
currentAbove: this.markerStyle("我的位置", "#1989fa", false)},
geometries: [{id: "target", styleId: "target", position: center}]
})
scanRuntime.circle = new TMap.MultiCircle({map: scanRuntime.map,
@@ -213,6 +600,7 @@ layout("/layouts/platform_h5.html"){
}).catch(error => {
if (scanRuntime.destroyed) return
this.destroyMap()
this.$set(this, "locationFailed", true)
this.$set(this, "locationMessage", error.message || "地图加载失败,请重新加载")
}).finally(() => {
if (!scanRuntime.destroyed) this.$set(this, "mapLoading", false)
@@ -227,11 +615,20 @@ layout("/layouts/platform_h5.html"){
const a = Math.sin(dlat / 2) ** 2 + Math.cos(rad(site.lat)) * Math.cos(rad(coords.lat)) * Math.sin(dlng / 2) ** 2
return 6371000 * 2 * Math.atan2(Math.sqrt(Math.min(1, a)), Math.sqrt(Math.max(0, 1 - a)))
},
/** 同时展示签到圈和本人位置,不改变任何签到记录。 */
/** coords为GCJ-02 {lat,lng};更新两处标记并适配视野,不改变任何签到记录。 */
fitMap(coords) {
const p = this.sitePosition
const latPad = Math.max(this.signRadius / 111320, 0.0003)
const lngPad = latPad / Math.max(Math.cos(p.lat * Math.PI / 180), 0.000001)
// 北侧点的标签向上,南侧点向下,避免近距离签到时两个名称互相遮挡。
const currentAbove = coords.lat > p.lat
scanRuntime.markers.remove(["target", "current"])
scanRuntime.markers.add([
{id: "target", styleId: currentAbove ? "targetBelow" : "target", position: new TMap.LatLng(p.lat, p.lng)},
{id: "current", styleId: currentAbove ? "currentAbove" : "current", position: new TMap.LatLng(coords.lat, coords.lng)}
])
// 两点较远时也保留边距,避免本人位置和签到地点标签被地图边缘裁切。
const latPad = Math.max(this.signRadius / 111320, Math.abs(p.lat - coords.lat) * 0.2, 0.0003)
const lngPad = Math.max(latPad / Math.max(Math.cos(p.lat * Math.PI / 180), 0.000001),
Math.abs(p.lng - coords.lng) * 0.2)
scanRuntime.map.fitBounds(new TMap.LatLngBounds(
new TMap.LatLng(Math.max(-90, Math.min(p.lat, coords.lat) - latPad), Math.max(-180, Math.min(p.lng, coords.lng) - lngPad)),
new TMap.LatLng(Math.min(90, Math.max(p.lat, coords.lat) + latPad), Math.min(180, Math.max(p.lng, coords.lng) + lngPad))))
@@ -244,6 +641,7 @@ layout("/layouts/platform_h5.html"){
if (!this.mapReady || !scanRuntime.locator) return Promise.reject(new Error("定位组件尚未就绪"))
if (this.locating) return Promise.reject(new Error("正在定位,请稍候"))
this.$set(this, "locating", true)
this.$set(this, "locationFailed", false)
this.$set(this, "currentPosition", null)
this.$set(this, "distance", null)
this.$set(this, "locationMessage", "正在获取您的当前位置")
@@ -272,7 +670,6 @@ layout("/layouts/platform_h5.html"){
this.$set(this, "currentPosition", coords)
this.$set(this, "distance", distance)
this.$set(this, "locationMessage", distance <= this.signRadius ? "已进入签到范围" : "尚未进入签到范围")
scanRuntime.markers.add([{id: "current", styleId: "current", position: new TMap.LatLng(coords.lat, coords.lng)}])
this.fitMap(coords)
resolve(coords)
} catch (err) { reject(err) }
@@ -294,7 +691,10 @@ layout("/layouts/platform_h5.html"){
}, {timeout: 10000, highAccuracy: true, maximumAge: 0})
} catch (error) { finish(new Error("腾讯定位调用失败,请重新加载地图")) }
}).catch(error => {
if (!scanRuntime.destroyed) this.$set(this, "locationMessage", error.message)
if (!scanRuntime.destroyed) {
this.$set(this, "locationFailed", true)
this.$set(this, "locationMessage", error.message)
}
throw error
}).finally(() => {
if (!scanRuntime.destroyed) this.$set(this, "locating", false)
@@ -385,6 +785,9 @@ layout("/layouts/platform_h5.html"){
if (name === "points") this.$set(this, "pointPopup", true)
if (name === "form") this.$set(this, "formPopup", true)
window.mobilePopupHistory.open(this.ownerId, name)
if (name === "points") {
this.$nextTick(() => { if (this.$refs.signPointsList) this.$refs.signPointsList.scrollTop = 0 })
}
},
closePopup(name) { window.mobilePopupHistory.close(this.ownerId, name) },
closePopupFromHistory(name) {