feat:增加调用腾讯位置服务api开关参数

This commit is contained in:
2026-11-06 00:33:29 +08:00
parent 8a4b1c7ae8
commit abc2f4d097
5 changed files with 57 additions and 16 deletions
@@ -13,6 +13,7 @@ import com.budwk.app.zhgh.activity.trainSignUp.models.TrainSignUpCourse;
import com.budwk.app.zhgh.activity.trainSignUp.models.TrainSignUpActivity; import com.budwk.app.zhgh.activity.trainSignUp.models.TrainSignUpActivity;
import com.budwk.app.zhgh.activity.trainSignUp.models.TrainSignUpUserCourse; import com.budwk.app.zhgh.activity.trainSignUp.models.TrainSignUpUserCourse;
import com.budwk.app.zhgh.activity.trainSignUp.service.TrainSignUpActivityService; import com.budwk.app.zhgh.activity.trainSignUp.service.TrainSignUpActivityService;
import com.budwk.app.zhgh.map.TencentLocationService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -29,6 +30,7 @@ import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Ok;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.util.Date; import java.util.Date;
@@ -65,10 +67,15 @@ public class TrainsignUpMineController {
public void h5Index() { public void h5Index() {
} }
/**
* 打开活动签到页,并按系统开关决定是否加载腾讯地图资源。
* @param request 用于向页面及公共布局传递本次签到定位开关
*/
@At("/scan") @At("/scan")
@SaCheckPermission("h5.trainSignUp.mine") @SaCheckPermission("h5.trainSignUp.mine")
@Ok("beetl:/platform/zhghh5/activity/trainSignUp/scan/index.html") @Ok("beetl:/platform/zhghh5/activity/trainSignUp/scan/index.html")
public void scan() { public void scan(HttpServletRequest request) {
request.setAttribute("activitySignTencentMapEnabled", TencentLocationService.isActivitySignEnabled());
} }
@At @At
@@ -244,6 +251,7 @@ public class TrainsignUpMineController {
} }
TrainSignUpActivity activity = dao.fetch(TrainSignUpActivity.class, course.getActivityId()); TrainSignUpActivity activity = dao.fetch(TrainSignUpActivity.class, course.getActivityId());
NutMap data = Lang.obj2nutmap(course); NutMap data = Lang.obj2nutmap(course);
data.put("tencentMapEnabled", TencentLocationService.isActivitySignEnabled());
data.put("signExtensionEnabled", activity != null && activity.getSignPointCount() != null data.put("signExtensionEnabled", activity != null && activity.getSignPointCount() != null
&& activity.getSignPointCount() > 0); && activity.getSignPointCount() > 0);
return Result.success(data); return Result.success(data);
@@ -19,6 +19,7 @@ import com.budwk.app.zhgh.activity.trainSignUp.service.TrainSignUpActivityServic
import com.budwk.app.zhgh.activity.trainSignUp.service.TrainSignUpActivityStatisticsService; import com.budwk.app.zhgh.activity.trainSignUp.service.TrainSignUpActivityStatisticsService;
import com.budwk.app.zhgh.welfare.model.WelfareProject; import com.budwk.app.zhgh.welfare.model.WelfareProject;
import com.budwk.app.zhgh.welfare.service.WelfareListService; import com.budwk.app.zhgh.welfare.service.WelfareListService;
import com.budwk.app.zhgh.map.TencentLocationService;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.nutz.aop.interceptor.async.Async; import org.nutz.aop.interceptor.async.Async;
@@ -854,6 +855,8 @@ public class TrainSignUpActivityServiceImpl extends BaseServiceImpl<TrainSignUpA
* 不与WGS84 transPosition混算;距离超出配置半径即拒绝签到。 * 不与WGS84 transPosition混算;距离超出配置半径即拒绝签到。
*/ */
private void requireScanCodeLocation(List<Double> coordinates, Double latitude, Double longitude, int radius) { private void requireScanCodeLocation(List<Double> coordinates, Double latitude, Double longitude, int radius) {
// 仅跳过定位与距离校验,调用方仍校验报名、课次时间并保留重复签到处理。
if (!TencentLocationService.isActivitySignEnabled()) return;
if (!validCoordinates(coordinates) || Math.abs(coordinates.get(0)) > 90 || Math.abs(coordinates.get(1)) > 180 if (!validCoordinates(coordinates) || Math.abs(coordinates.get(0)) > 90 || Math.abs(coordinates.get(1)) > 180
|| radius <= 0) { || radius <= 0) {
throw new IllegalArgumentException("当前点位未配置有效签到坐标"); throw new IllegalArgumentException("当前点位未配置有效签到坐标");
@@ -3,6 +3,7 @@ package com.budwk.app.zhgh.map;
import cn.hutool.crypto.digest.DigestUtil; import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.json.JSONObject; import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import com.budwk.app.web.commons.base.Globals;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.nutz.integration.jedis.RedisService; import org.nutz.integration.jedis.RedisService;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
@@ -100,6 +101,11 @@ public class TencentLocationService {
write(response, null, error(400, "定位回调参数不合法")); write(response, null, error(400, "定位回调参数不合法"));
return; return;
} }
// 关闭开关后,旧页面尚未完成的定位请求也不能继续调用腾讯接口。
if (!isActivitySignEnabled()) {
write(response, callback, error(403, "当前签到无需定位,请刷新页面直接签到"));
return;
}
String coordinate = request.getParameter(translate ? "locations" : "location"); String coordinate = request.getParameter(translate ? "locations" : "location");
String type = request.getParameter("type"); String type = request.getParameter("type");
if (!validCoordinate(coordinate) || (translate && (type == null || !type.matches("[1-6]")))) { if (!validCoordinate(coordinate) || (translate && (type == null || !type.matches("[1-6]")))) {
@@ -180,6 +186,16 @@ public class TencentLocationService {
} }
} }
/**
* 读取品牌活动签到定位开关,页面、签到校验和腾讯代理使用相同判断。
*
* @return 仅明确配置为 false 时关闭,参数缺失时保留原有定位校验
*/
public static boolean isActivitySignEnabled() {
String value = Globals.MyConfig.getString("AppActivitySignTencentMap");
return value == null || !"false".equalsIgnoreCase(value.trim());
}
private boolean validCoordinate(String value) { private boolean validCoordinate(String value) {
if (value == null || value.length() > 80) return false; if (value == null || value.length() > 80) return false;
String[] parts = value.split(",", -1); String[] parts = value.split(",", -1);
@@ -234,6 +250,10 @@ public class TencentLocationService {
private void send(Job job) { private void send(Job job) {
synchronized (job) { synchronized (job) {
if (job.done) return; if (job.done) return;
if (!isActivitySignEnabled()) {
finish(job, error(403, "当前签到无需定位,请刷新页面直接签到"), true);
return;
}
long remaining = REQUEST_TIMEOUT_MS - elapsedMillis(job.createdAt); long remaining = REQUEST_TIMEOUT_MS - elapsedMillis(job.createdAt);
if (closed || remaining <= 0) { if (closed || remaining <= 0) {
finish(job, error(504, "定位代理等待超时,请重新定位"), true); finish(job, error(504, "定位代理等待超时,请重新定位"), true);
@@ -77,7 +77,9 @@
src="https://webapi.amap.com/maps?v=2.0&key=57f0d098ba1b881ecc436c4cfd23bbbf&plugin=AMap.PolyEditor,AMap.Geolocation" src="https://webapi.amap.com/maps?v=2.0&key=57f0d098ba1b881ecc436c4cfd23bbbf&plugin=AMap.PolyEditor,AMap.Geolocation"
></script>--> ></script>-->
<!--# if (activitySignTencentMapEnabled!true) { #-->
<script src="https://map.qq.com/api/gljs?v=2.exp&key=NYNBZ-K62KI-DQJGU-U4NJ5-CSME7-ULFMU"></script> <script src="https://map.qq.com/api/gljs?v=2.exp&key=NYNBZ-K62KI-DQJGU-U4NJ5-CSME7-ULFMU"></script>
<!--# } #-->
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
Vue.config.devtools = true Vue.config.devtools = true
@@ -361,9 +361,9 @@ layout("/layouts/platform_h5.html"){
<div id="app" class="brand-train-sign-page" v-cloak> <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> <van-nav-bar title="活动签到" left-text="返回" left-arrow @click-left="onNavBack" fixed placeholder></van-nav-bar>
<div class="brand-train-sign-content"> <div class="brand-train-sign-content">
<div id="mapContainer" class="brand-train-sign-map"></div> <div v-if="tencentMapEnabled" id="mapContainer" class="brand-train-sign-map"></div>
<section class="brand-train-sign-details"> <section class="brand-train-sign-details">
<div class="brand-train-sign-location-tools"> <div v-if="tencentMapEnabled" class="brand-train-sign-location-tools">
<span class="brand-train-sign-location-status" role="status" <span class="brand-train-sign-location-status" role="status"
:class="{'brand-train-sign-map-warning': locationFailed || distance !== null && !isInRange, :class="{'brand-train-sign-map-warning': locationFailed || distance !== null && !isInRange,
'is-in-range': !locationFailed && !locating && isInRange}">{{locationMessage}}</span> 'is-in-range': !locationFailed && !locating && isInRange}">{{locationMessage}}</span>
@@ -377,8 +377,8 @@ layout("/layouts/platform_h5.html"){
<van-icon name="checked"></van-icon>当前点位已签到 <van-icon name="checked"></van-icon>当前点位已签到
</span> </span>
</div> </div>
<div class="brand-train-sign-text">签到范围:{{signRadius}} 米</div> <div v-if="tencentMapEnabled" class="brand-train-sign-text">签到范围:{{signRadius}} 米</div>
<div v-if="distance !== null" class="brand-train-sign-text">距签到地点约 {{Math.ceil(distance)}} 米</div> <div v-if="tencentMapEnabled && distance !== null" class="brand-train-sign-text">距签到地点约 {{Math.ceil(distance)}} 米</div>
<div v-if="extensionEnabled" class="brand-train-sign-progress"> <div v-if="extensionEnabled" class="brand-train-sign-progress">
<div class="brand-train-sign-progress-header"> <div class="brand-train-sign-progress-header">
<span class="brand-train-sign-progress-heading">活动签到进度</span> <span class="brand-train-sign-progress-heading">活动签到进度</span>
@@ -453,6 +453,7 @@ layout("/layouts/platform_h5.html"){
return { return {
ownerId: "train-sign-scan-" + Date.now(), courseId: GetQueryString("courseId"), row: {}, signData: {}, ownerId: "train-sign-scan-" + Date.now(), courseId: GetQueryString("courseId"), row: {}, signData: {},
extensionEnabled: false, legacyResult: {code: 1, msg: "正在获取签到信息"}, extensionEnabled: false, legacyResult: {code: 1, msg: "正在获取签到信息"},
tencentMapEnabled: ${activitySignTencentMapEnabled!true},
statusMessage: "请获取定位后完成签到", messageType: "", signLoading: false, formLoading: false, statusMessage: "请获取定位后完成签到", messageType: "", signLoading: false, formLoading: false,
pointPopup: false, formPopup: false, pointPopup: false, formPopup: false,
mapReady: false, mapLoading: false, locating: false, courseLoading: true, mapReady: false, mapLoading: false, locating: false, courseLoading: true,
@@ -477,7 +478,8 @@ layout("/layouts/platform_h5.html"){
if (this.messageType === "error") return this.statusMessage if (this.messageType === "error") return this.statusMessage
if (this.signData.isReachTarget && !this.currentPointSigned) return "已达标,可继续打卡其他点位。" if (this.signData.isReachTarget && !this.currentPointSigned) return "已达标,可继续打卡其他点位。"
if (this.signData.isReachTarget) return this.statusMessage if (this.signData.isReachTarget) return this.statusMessage
return this.currentPointSigned ? "请继续完成其他点位签到。" : "到达点位后,点击确认签到。" return this.currentPointSigned ? "请继续完成其他点位签到。"
: this.tencentMapEnabled ? "到达点位后,点击确认签到。" : "请点击确认签到。"
}, },
// 未打卡项优先,组内保留接口中的点位序号,不能改动原数组。 // 未打卡项优先,组内保留接口中的点位序号,不能改动原数组。
displaySignPoints() { displaySignPoints() {
@@ -496,9 +498,10 @@ layout("/layouts/platform_h5.html"){
return Number.isFinite(r) && r > 0 ? r : 0 return Number.isFinite(r) && r > 0 ? r : 0
}, },
signDisabled() { signDisabled() {
return this.courseLoading || this.mapLoading || this.locating || this.signLoading return this.courseLoading || this.mapLoading || this.locating || this.signLoading || !this.row.id
|| !this.mapReady || !this.currentPosition || this.distance === null || this.tencentMapEnabled && (!this.mapReady || !this.currentPosition || this.distance === null
|| this.distance > this.signRadius || this.extensionEnabled && this.signData.currentPointSigned === true || this.distance > this.signRadius)
|| this.extensionEnabled && this.signData.currentPointSigned === true
}, },
progressPercentage() { progressPercentage() {
if (!this.signData.signPointCount) return 0 if (!this.signData.signPointCount) return 0
@@ -570,7 +573,7 @@ layout("/layouts/platform_h5.html"){
}, },
/** 只初始化地图及定位预览,不提交签到。SDK失败可由重新加载按钮重试。 */ /** 只初始化地图及定位预览,不提交签到。SDK失败可由重新加载按钮重试。 */
initMap() { initMap() {
if (scanRuntime.destroyed || this.mapLoading) return Promise.resolve() if (!this.tencentMapEnabled || scanRuntime.destroyed || this.mapLoading) return Promise.resolve()
if (this.mapReady) return this.refreshPosition() if (this.mapReady) return this.refreshPosition()
if (!this.sitePosition || !this.signRadius) { if (!this.sitePosition || !this.signRadius) {
this.$set(this, "locationFailed", true) this.$set(this, "locationFailed", true)
@@ -712,7 +715,7 @@ layout("/layouts/platform_h5.html"){
}, },
/** 重新定位仅更新当前位置和距离;地图尚未就绪时重新加载SDK。 */ /** 重新定位仅更新当前位置和距离;地图尚未就绪时重新加载SDK。 */
refreshPosition() { refreshPosition() {
if (scanRuntime.destroyed || this.locating || this.signLoading) return Promise.resolve() if (!this.tencentMapEnabled || scanRuntime.destroyed || this.locating || this.signLoading) return Promise.resolve()
if (!this.mapReady) return this.initMap() if (!this.mapReady) return this.initMap()
return this.getUserLocation().catch(() => {}) return this.getUserLocation().catch(() => {})
}, },
@@ -740,10 +743,12 @@ layout("/layouts/platform_h5.html"){
return return
} }
this.$set(this, "row", resp.data) this.$set(this, "row", resp.data)
this.$set(this, "tencentMapEnabled", resp.data.tencentMapEnabled !== false)
this.$set(this, "extensionEnabled", resp.data.signExtensionEnabled === true) this.$set(this, "extensionEnabled", resp.data.signExtensionEnabled === true)
// 普通活动同样只预览,禁止进入页面就自动写入签到。 // 普通活动同样只预览,禁止进入页面就自动写入签到。
if (this.extensionEnabled) return this.loadSignData() if (this.extensionEnabled) return this.loadSignData()
this.$set(this, "legacyResult", {code: 1, msg: "到达点位后,请点击确认签到"}) this.$set(this, "legacyResult", {code: 1, msg: this.tencentMapEnabled
? "到达点位后,请点击确认签到" : "请点击确认签到"})
return this.initMap() return this.initMap()
}).catch(() => { }).catch(() => {
if (!scanRuntime.destroyed) this.$set(this, "locationMessage", "获取签到信息失败,请重新进入页面") if (!scanRuntime.destroyed) this.$set(this, "locationMessage", "获取签到信息失败,请重新进入页面")
@@ -768,13 +773,16 @@ layout("/layouts/platform_h5.html"){
onSign() { onSign() {
if (this.signDisabled || scanRuntime.destroyed) return if (this.signDisabled || scanRuntime.destroyed) return
this.$set(this, "signLoading", true) this.$set(this, "signLoading", true)
// 预览坐标不作为提交依据,点击后重新获取GCJ-02位置,并由后端再次校验范围。 // 开启定位时重新取位;关闭时只提交课次,由后端按同一系统开关处理签到。
return this.getUserLocation().then((coords) => { const location = this.tencentMapEnabled ? this.getUserLocation() : Promise.resolve(null)
return location.then((coords) => {
if (scanRuntime.destroyed) return null if (scanRuntime.destroyed) return null
if (this.distance > this.signRadius) throw new Error("尚未进入签到范围,请到达地点后重试") if (coords && this.distance > this.signRadius) throw new Error("尚未进入签到范围,请到达地点后重试")
const signStarted = performance.now() const signStarted = performance.now()
const requestId = scanRuntime.requestId const requestId = scanRuntime.requestId
return this.$axios.post("/platform/trainSignUp/mine/drivingScan", {courseId: this.courseId, lat: coords.lat, lng: coords.lng}) const payload = {courseId: this.courseId}
if (coords) { payload.lat = coords.lat; payload.lng = coords.lng }
return this.$axios.post("/platform/trainSignUp/mine/drivingScan", payload)
.then(resp => { .then(resp => {
console.info("签到阶段耗时", {stage: "sign", requestId: requestId, console.info("签到阶段耗时", {stage: "sign", requestId: requestId,
elapsedMs: Math.round(performance.now() - signStarted), code: resp.code}) elapsedMs: Math.round(performance.now() - signStarted), code: resp.code})