From a910819c1853081735356c7a2c5e05a2953602ab Mon Sep 17 00:00:00 2001
From: liujie <1793218484@qq.com>
Date: 星期一, 14 九月 2026 17:59:02 +0800
Subject: [PATCH] update
---
backend/src/main/java/com/tourguide/modules/order/service/MiniTourOrderCommandService.java | 12 ++++
mingdaojingjiang_guide_app/services/auth.js | 2
mingdaojingjiang_uniapp/mingdaojingjiang_uniapp/pages/order-pending-pay/index.vue | 10 +++
backend/src/main/java/com/tourguide/modules/user/service/GuideAccountService.java | 22 ++++---
mingdaojingjiang_guide_app/manifest.json | 1
mingdaojingjiang_guide_app/pages/workbench/index.vue | 71 +++++++++++++++++------
backend/src/main/java/com/tourguide/modules/user/service/GuideUserService.java | 12 ++-
7 files changed, 96 insertions(+), 34 deletions(-)
diff --git a/backend/src/main/java/com/tourguide/modules/order/service/MiniTourOrderCommandService.java b/backend/src/main/java/com/tourguide/modules/order/service/MiniTourOrderCommandService.java
index ed94927..1e292ec 100644
--- a/backend/src/main/java/com/tourguide/modules/order/service/MiniTourOrderCommandService.java
+++ b/backend/src/main/java/com/tourguide/modules/order/service/MiniTourOrderCommandService.java
@@ -166,6 +166,7 @@
int unpaidCancelMinutes = scenicSpot == null || scenicSpot.getUnpaidCancelMinutes() == null
|| scenicSpot.getUnpaidCancelMinutes() < 1
? DEFAULT_UNPAID_CANCEL_MINUTES : scenicSpot.getUnpaidCancelMinutes();
+ cancelExpiredUnpaidIfNeeded(order, unpaidCancelMinutes);
return TourOrderResponse.from(order)
.enrich(scenicSpot, meetingPoint, pricing, guide)
.withUnpaidCancelMinutes(unpaidCancelMinutes)
@@ -173,6 +174,17 @@
platformSettingsService.getSettings().getUnacceptedAutoRefundMinutes());
}
+ /** 读取订单时惰性取消已超时的未支付订单,避免等待定时任务扫描延迟。 */
+ private void cancelExpiredUnpaidIfNeeded(TourOrder order, int unpaidCancelMinutes) {
+ if (!OrderStatus.PENDING_PAYMENT.matches(order.getStatus())) return;
+ LocalDateTime baseTime = order.getPlacedAt() == null ? order.getCreatedAt() : order.getPlacedAt();
+ if (baseTime == null || baseTime.plusMinutes(unpaidCancelMinutes).isAfter(LocalDateTime.now())) return;
+ if (orderMapper.cancelUnpaid(order.getId()) > 0) {
+ order.setStatus(OrderStatus.CANCELLED.getCode());
+ order.setCancelledAt(LocalDateTime.now());
+ }
+ }
+
@Transactional
public TourOrderResponse cancel(Long visitorId, Long orderId) {
TourOrder order = orderMapper.selectForUpdate(orderId);
diff --git a/backend/src/main/java/com/tourguide/modules/user/service/GuideAccountService.java b/backend/src/main/java/com/tourguide/modules/user/service/GuideAccountService.java
index 4f55282..5271792 100644
--- a/backend/src/main/java/com/tourguide/modules/user/service/GuideAccountService.java
+++ b/backend/src/main/java/com/tourguide/modules/user/service/GuideAccountService.java
@@ -1,6 +1,7 @@
package com.tourguide.modules.user.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.tourguide.common.exception.BusinessException;
import com.tourguide.modules.order.domain.OrderStatus;
import com.tourguide.modules.order.entity.TourOrder;
@@ -57,16 +58,17 @@
if (idCardNo != null && !idCardNo.trim().isEmpty()) {
guideApplicationMapper.clearIdentityByIdCard(idCardNo);
}
- user.setUsername("deleted_" + UUID.randomUUID().toString().replace("-", "").substring(0, 24));
- user.setMobile(null);
- user.setCertificateNo(null);
- user.setIdCardNo(null);
- user.setIdCardFrontUrl(null);
- user.setIdCardBackUrl(null);
- user.setStatus(GuideUserService.STATUS_CANCELLED);
- user.setAutoDisableWhitelisted(0);
- user.setAutoDisabled(0);
- guideUserMapper.updateById(user);
+ guideUserMapper.update(null, new LambdaUpdateWrapper<GuideUser>()
+ .eq(GuideUser::getId, guideId)
+ .set(GuideUser::getUsername, "deleted_" + UUID.randomUUID().toString().replace("-", "").substring(0, 24))
+ .set(GuideUser::getMobile, null)
+ .set(GuideUser::getCertificateNo, null)
+ .set(GuideUser::getIdCardNo, null)
+ .set(GuideUser::getIdCardFrontUrl, null)
+ .set(GuideUser::getIdCardBackUrl, null)
+ .set(GuideUser::getStatus, GuideUserService.STATUS_CANCELLED)
+ .set(GuideUser::getAutoDisableWhitelisted, 0)
+ .set(GuideUser::getAutoDisabled, 0));
tokenSessionService.remove(payload);
}
}
diff --git a/backend/src/main/java/com/tourguide/modules/user/service/GuideUserService.java b/backend/src/main/java/com/tourguide/modules/user/service/GuideUserService.java
index 7ed8357..c68ba55 100644
--- a/backend/src/main/java/com/tourguide/modules/user/service/GuideUserService.java
+++ b/backend/src/main/java/com/tourguide/modules/user/service/GuideUserService.java
@@ -1,6 +1,7 @@
package com.tourguide.modules.user.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tourguide.common.api.PageResponse;
import com.tourguide.common.exception.BusinessException;
@@ -332,11 +333,12 @@
}
private void anonymizeCancelledGuide(GuideUser user) {
- user.setUsername("deleted_" + UUID.randomUUID().toString().replace("-", "").substring(0, 24));
- user.setMobile(null);
- user.setCertificateNo(null);
- user.setIdCardNo(null);
- userMapper.updateById(user);
+ userMapper.update(null, new LambdaUpdateWrapper<GuideUser>()
+ .eq(GuideUser::getId, user.getId())
+ .set(GuideUser::getUsername, "deleted_" + UUID.randomUUID().toString().replace("-", "").substring(0, 24))
+ .set(GuideUser::getMobile, null)
+ .set(GuideUser::getCertificateNo, null)
+ .set(GuideUser::getIdCardNo, null));
}
private void ensureUniqueGuideIdentity(GuideApplication application, GuideUser existingUser) {
diff --git a/mingdaojingjiang_guide_app/manifest.json b/mingdaojingjiang_guide_app/manifest.json
index 28bb7a3..7402aa1 100644
--- a/mingdaojingjiang_guide_app/manifest.json
+++ b/mingdaojingjiang_guide_app/manifest.json
@@ -39,6 +39,7 @@
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
+ "<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
diff --git a/mingdaojingjiang_guide_app/pages/workbench/index.vue b/mingdaojingjiang_guide_app/pages/workbench/index.vue
index 0dc2fe3..0a5eda8 100644
--- a/mingdaojingjiang_guide_app/pages/workbench/index.vue
+++ b/mingdaojingjiang_guide_app/pages/workbench/index.vue
@@ -143,7 +143,7 @@
<script>
import GuideDialog from '../../components/guide-dialog/guide-dialog.vue'
-import { getLoginState, isLoggedIn } from '../../services/auth'
+import { clearGuideLocalData, getLoginState, isLoggedIn } from '../../services/auth'
import {
getCurrentGuideReceivingSession,
getGuideProfile,
@@ -203,27 +203,54 @@
}
function dialPhone(phoneNumber) {
+ // App 端(5+):先申请拨号权限,再调用系统拨号界面
if (typeof plus !== 'undefined' && plus.device && typeof plus.device.dial === 'function') {
- plus.device.dial(phoneNumber, true)
+ const doDial = () => plus.device.dial(phoneNumber, true)
+ // Android 6.0+ 需运行时申请 CALL_PHONE 权限,iOS 直接拨号
+ if (typeof plus.android !== 'undefined' && typeof plus.android.requestPermissions === 'function') {
+ plus.android.requestPermissions(['android.permission.CALL_PHONE'], (result) => {
+ const denied = [
+ ...(result && result.deniedAlways ? result.deniedAlways : []),
+ ...(result && result.denied ? result.denied : [])
+ ]
+ if (denied.length > 0) {
+ showPhoneCallError()
+ return
+ }
+ doDial()
+ }, () => {
+ showPhoneCallError()
+ })
+ } else {
+ doDial()
+ }
return true
}
- if (typeof uni === 'undefined' || typeof uni.makePhoneCall !== 'function') {
- if (typeof window !== 'undefined' && window.location) {
- window.location.href = `tel:${phoneNumber}`
- return true
- }
- return false
+ // H5 端:用 <a href="tel:"> 触发,兼容微信 WebView
+ if (typeof window !== 'undefined' && typeof document !== 'undefined' && typeof document.createElement === 'function') {
+ const link = document.createElement('a')
+ link.setAttribute('href', `tel:${phoneNumber}`)
+ link.style.display = 'none'
+ document.body.appendChild(link)
+ link.click()
+ document.body.removeChild(link)
+ return true
}
- const result = uni.makePhoneCall({
- phoneNumber,
- fail: handlePhoneCallFailure
- })
- if (result && typeof result.catch === 'function') {
- result.catch(handlePhoneCallFailure)
+ // 小程序端:uni.makePhoneCall
+ if (typeof uni !== 'undefined' && typeof uni.makePhoneCall === 'function') {
+ const result = uni.makePhoneCall({
+ phoneNumber,
+ fail: handlePhoneCallFailure
+ })
+ if (result && typeof result.catch === 'function') {
+ result.catch(handlePhoneCallFailure)
+ }
+ return true
}
- return true
+
+ return false
}
function buildReceivingConfig(session, scenics = [], fallback = {}) {
@@ -594,13 +621,20 @@
}
this.countdownSeconds = Math.max(
0,
- Math.ceil((this.countdownFallbackEndAt - Date.now()) / 1000)
+ Math.min(
+ leadMinutes * 60,
+ Math.ceil((this.countdownFallbackEndAt - Date.now()) / 1000)
+ )
)
return
}
this.countdownFallbackEndAt = null
const endAt = serving ? startAt + durationMinutes * 60 * 1000 : startAt
- this.countdownSeconds = Math.max(0, Math.ceil((endAt - Date.now()) / 1000))
+ const maxSeconds = (serving ? durationMinutes : leadMinutes) * 60
+ this.countdownSeconds = Math.max(
+ 0,
+ Math.min(maxSeconds, Math.ceil((endAt - Date.now()) / 1000))
+ )
},
clearCountdown() {
if (this.countdownTimer) {
@@ -693,7 +727,8 @@
})
},
resubmit() {
- routeTo('/pages/register-phone/index')
+ clearGuideLocalData()
+ routeTo('/pages/login/index', 'reLaunch')
},
openPolicy() {
routeTo('/pages/agreements/index')
diff --git a/mingdaojingjiang_guide_app/services/auth.js b/mingdaojingjiang_guide_app/services/auth.js
index 64ab7f1..09b8331 100644
--- a/mingdaojingjiang_guide_app/services/auth.js
+++ b/mingdaojingjiang_guide_app/services/auth.js
@@ -100,7 +100,7 @@
})
}
-function clearGuideLocalData() {
+export function clearGuideLocalData() {
[
GUIDE_LOGIN_KEY,
GUIDE_ORDERS_KEY,
diff --git a/mingdaojingjiang_uniapp/mingdaojingjiang_uniapp/pages/order-pending-pay/index.vue b/mingdaojingjiang_uniapp/mingdaojingjiang_uniapp/pages/order-pending-pay/index.vue
index 1870da6..af7f590 100644
--- a/mingdaojingjiang_uniapp/mingdaojingjiang_uniapp/pages/order-pending-pay/index.vue
+++ b/mingdaojingjiang_uniapp/mingdaojingjiang_uniapp/pages/order-pending-pay/index.vue
@@ -224,6 +224,7 @@
function updateCountdown() {
if (!paymentDeadline.value) return
+ const previous = remainingSeconds.value
remainingSeconds.value = Math.max(
0,
Math.min(
@@ -231,6 +232,15 @@
Math.ceil((paymentDeadline.value - Date.now()) / 1000)
)
)
+ if (previous > 0 && remainingSeconds.value === 0) {
+ onCountdownExpired()
+ }
+}
+
+function onCountdownExpired() {
+ if (pageActive && order.value.id && !redirecting) {
+ refreshOrderStatus()
+ }
}
function parseServerTime(value) {
--
Gitblit v1.7.1