修复bug
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { onLaunch,onShow,onHide } from '@dcloudio/uni-app'
|
import { onLaunch,onShow,onHide } from '@dcloudio/uni-app'
|
||||||
import { isPublicPath } from '@/common/checkLogin.js'
|
import { isPublicPath, requireLogin } from '@/common/checkLogin.js'
|
||||||
|
|
||||||
let cidRetryTimer = null
|
let cidRetryTimer = null
|
||||||
let cidRetryCount = 0
|
let cidRetryCount = 0
|
||||||
@@ -27,10 +27,8 @@
|
|||||||
invoke(args) {
|
invoke(args) {
|
||||||
const t = uni.getStorageSync('token')
|
const t = uni.getStorageSync('token')
|
||||||
if (!t && !isPublicPath(args.url)) {
|
if (!t && !isPublicPath(args.url)) {
|
||||||
uni.showToast({ title: '请先登录', icon: 'none' })
|
// 使用 requireLogin 统一处理,自带防重复锁
|
||||||
setTimeout(() => {
|
requireLogin({ message: '请先登录', redirect: true })
|
||||||
uni.navigateTo({ url: '/pageSubPack/loginSub/login?mode=pwd' })
|
|
||||||
}, 1000)
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,10 @@
|
|||||||
* if (!requireLogin()) return
|
* if (!requireLogin()) return
|
||||||
*
|
*
|
||||||
* 页面级调用即可,全局 navigateTo 拦截器(App.vue onLaunch 中注册)作为兜底。
|
* 页面级调用即可,全局 navigateTo 拦截器(App.vue onLaunch 中注册)作为兜底。
|
||||||
|
*
|
||||||
|
* 防重复机制:
|
||||||
|
* _loginPending — requireLogin 立即设置,阻止在 setTimeout 等待期内重复调度
|
||||||
|
* _loginNavigating — navigateToLogin 设置,阻止实际跳转重复
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** 无需登录即可访问的页面路径白名单(全局拦截器使用) */
|
/** 无需登录即可访问的页面路径白名单(全局拦截器使用) */
|
||||||
@@ -18,6 +22,73 @@ export const PUBLIC_PATHS = [
|
|||||||
'/pages/navigation/navigation'
|
'/pages/navigation/navigation'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
// ==================== 登录页跳转防重复锁 ====================
|
||||||
|
// 使用 getApp().globalData 存储,避免模块被分包/异步 chunk 多次实例化导致锁失效
|
||||||
|
|
||||||
|
function getLock() {
|
||||||
|
const app = getApp()
|
||||||
|
if (!app.globalData) app.globalData = {}
|
||||||
|
return app.globalData
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断当前是否已在登录页
|
||||||
|
*/
|
||||||
|
function isOnLoginPage() {
|
||||||
|
const pages = getCurrentPages()
|
||||||
|
if (!pages || pages.length === 0) return false
|
||||||
|
const route = pages[pages.length - 1].route || ''
|
||||||
|
return route.includes('loginSub/login')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跳转到登录页(统一入口,带防重复锁)
|
||||||
|
* 所有需要跳转登录页的地方都应调用此函数,不要直接调用 uni.navigateTo / uni.reLaunch
|
||||||
|
*
|
||||||
|
* @param {object} [options]
|
||||||
|
* @param {string} [options.method='navigateTo'] - 跳转方式:'navigateTo' | 'reLaunch' | 'redirectTo'
|
||||||
|
* @param {string} [options.url='/pageSubPack/loginSub/login?mode=pwd'] - 目标 url
|
||||||
|
*/
|
||||||
|
export function navigateToLogin(options = {}) {
|
||||||
|
const {
|
||||||
|
method = 'navigateTo',
|
||||||
|
url = '/pageSubPack/loginSub/login?mode=pwd'
|
||||||
|
} = options
|
||||||
|
|
||||||
|
// 已经在登录页,跳过
|
||||||
|
if (isOnLoginPage()) return
|
||||||
|
|
||||||
|
const lock = getLock()
|
||||||
|
|
||||||
|
// reLaunch 优先级最高,强制放行(用于 token 过期、退出登录等场景)
|
||||||
|
if (method !== 'reLaunch' && lock._loginNavigating) return
|
||||||
|
|
||||||
|
lock._loginNavigating = true
|
||||||
|
|
||||||
|
const navFn = uni[method]
|
||||||
|
if (!navFn) {
|
||||||
|
lock._loginNavigating = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
navFn({
|
||||||
|
url,
|
||||||
|
fail() {
|
||||||
|
// 跳转失败时重置锁,允许后续重试
|
||||||
|
lock._loginNavigating = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置登录跳转锁(登录页 onLoad 时调用)
|
||||||
|
*/
|
||||||
|
export function resetLoginLock() {
|
||||||
|
const lock = getLock()
|
||||||
|
lock._loginPending = false
|
||||||
|
lock._loginNavigating = false
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断指定路径是否为公开页面(无需登录)
|
* 判断指定路径是否为公开页面(无需登录)
|
||||||
* @param {string} url - navigateTo 的目标 url
|
* @param {string} url - navigateTo 的目标 url
|
||||||
@@ -40,15 +111,21 @@ export function isPublicPath(url) {
|
|||||||
export function requireLogin(options = {}) {
|
export function requireLogin(options = {}) {
|
||||||
const {
|
const {
|
||||||
message = '请先登录',
|
message = '请先登录',
|
||||||
redirect = true
|
redirect = true
|
||||||
} = options
|
} = options
|
||||||
const token = uni.getStorageSync('token')
|
const token = uni.getStorageSync('token')
|
||||||
if (token) return true
|
if (token) return true
|
||||||
|
|
||||||
uni.showToast({ title: message, icon: 'none' })
|
uni.showToast({ title: message, icon: 'none' })
|
||||||
if (redirect) {
|
if (redirect) {
|
||||||
|
// 立即加锁,防止在 setTimeout 等待期内重复调度
|
||||||
|
const lock = getLock()
|
||||||
|
if (lock._loginPending) return false
|
||||||
|
lock._loginPending = true
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
uni.navigateTo({ url: '/pageSubPack/loginSub/login?mode=pwd' })
|
lock._loginPending = false
|
||||||
|
navigateToLogin({ method: 'navigateTo' })
|
||||||
}, 1000)
|
}, 1000)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { navigateToLogin } from '@/common/checkLogin.js'
|
||||||
|
|
||||||
let baseUrl = '';
|
let baseUrl = '';
|
||||||
if (process.env.NODE_ENV === 'development') {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
baseUrl = 'http://192.168.1.222:8080'; // 开发环境
|
baseUrl = 'http://192.168.1.222:8080'; // 开发环境
|
||||||
@@ -42,7 +44,7 @@ export default function request(url, data = {}, method = "GET") {
|
|||||||
if (resData.code === 401) {
|
if (resData.code === 401) {
|
||||||
if (token) {
|
if (token) {
|
||||||
uni.clearStorageSync('token');
|
uni.clearStorageSync('token');
|
||||||
uni.reLaunch({ url: '/pageSubPack/loginSub/login?mode=pwd' });
|
navigateToLogin({ method: 'reLaunch' });
|
||||||
}
|
}
|
||||||
reject({ msg: '登录过期', code: 401 });
|
reject({ msg: '登录过期', code: 401 });
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ import { ref, computed, onUnmounted } from 'vue';
|
|||||||
import { onLoad } from '@dcloudio/uni-app'
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
import { getLoginBySms, getLoginPassword, getSendCode } from '../api/api.js'
|
import { getLoginBySms, getLoginPassword, getSendCode } from '../api/api.js'
|
||||||
import PrivacyPopup from '@/components/privacy-popup/privacy-popup.vue'
|
import PrivacyPopup from '@/components/privacy-popup/privacy-popup.vue'
|
||||||
|
import { resetLoginLock } from '@/common/checkLogin.js'
|
||||||
|
|
||||||
// ========== 模式切换 ==========
|
// ========== 模式切换 ==========
|
||||||
// 'sms' = 手机验证码登录, 'pwd' = 账号密码登录
|
// 'sms' = 手机验证码登录, 'pwd' = 账号密码登录
|
||||||
@@ -113,6 +114,8 @@ const pendingAction = ref('')
|
|||||||
|
|
||||||
// ========== onLoad: 读取 mode 参数 ==========
|
// ========== onLoad: 读取 mode 参数 ==========
|
||||||
onLoad((options) => {
|
onLoad((options) => {
|
||||||
|
// 重置登录跳转锁,允许下次未登录时再次跳转
|
||||||
|
resetLoginLock()
|
||||||
if (options && options.mode === 'sms') {
|
if (options && options.mode === 'sms') {
|
||||||
loginMode.value = 'sms'
|
loginMode.value = 'sms'
|
||||||
} else if (options && options.mode === 'pwd') {
|
} else if (options && options.mode === 'pwd') {
|
||||||
|
|||||||
@@ -83,6 +83,7 @@
|
|||||||
|
|
||||||
const id = ref(undefined)
|
const id = ref(undefined)
|
||||||
const type = ref('')
|
const type = ref('')
|
||||||
|
const isSubmitting = ref(false)
|
||||||
const formData = ref({
|
const formData = ref({
|
||||||
// carNum: uni.getStorageSync('carNum'),
|
// carNum: uni.getStorageSync('carNum'),
|
||||||
// carBrand: uni.getStorageSync('carBrand'),
|
// carBrand: uni.getStorageSync('carBrand'),
|
||||||
@@ -202,14 +203,25 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 车牌号正则:省份简称 + 城市代码字母 + 5位(蓝牌)或6位(新能源绿牌)字母数字
|
||||||
|
const CAR_NUM_REGEX = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤川青藏琼宁][A-Z][A-Z0-9]{5,6}$/
|
||||||
|
|
||||||
const saveCar = async () => {
|
const saveCar = async () => {
|
||||||
|
if (isSubmitting.value) return
|
||||||
if (!formData.value.carNum) {
|
if (!formData.value.carNum) {
|
||||||
return uni.showToast({
|
return uni.showToast({
|
||||||
title: "请输入车牌号",
|
title: "请输入车牌号",
|
||||||
icon: "none"
|
icon: "none"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if (!CAR_NUM_REGEX.test(formData.value.carNum)) {
|
||||||
|
return uni.showToast({
|
||||||
|
title: "请输入正确的车牌号",
|
||||||
|
icon: "none"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
isSubmitting.value = true
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: '提交中...',
|
title: '提交中...',
|
||||||
mask: true
|
mask: true
|
||||||
@@ -232,6 +244,7 @@
|
|||||||
|
|
||||||
submitCarData(carImageUrl)
|
submitCarData(carImageUrl)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
isSubmitting.value = false
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: err.msg || '网络异常',
|
title: err.msg || '网络异常',
|
||||||
@@ -260,6 +273,7 @@
|
|||||||
params.id = id.value
|
params.id = id.value
|
||||||
putCar(params).then(res => {
|
putCar(params).then(res => {
|
||||||
console.log(res);
|
console.log(res);
|
||||||
|
isSubmitting.value = false
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
@@ -274,9 +288,10 @@
|
|||||||
uni.removeStorageSync("carImageUrl")
|
uni.removeStorageSync("carImageUrl")
|
||||||
uni.removeStorageSync("carBrandId")
|
uni.removeStorageSync("carBrandId")
|
||||||
uni.removeStorageSync("checkType")
|
uni.removeStorageSync("checkType")
|
||||||
uni.redirectTo({ url: "/pageSubPack/my/myCarIndex" })
|
uni.navigateBack()
|
||||||
}, 1500)
|
}, 1500)
|
||||||
} else {
|
} else {
|
||||||
|
isSubmitting.value = false
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: res.msg || '提交失败',
|
title: res.msg || '提交失败',
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
@@ -285,6 +300,7 @@
|
|||||||
})
|
})
|
||||||
}else{
|
}else{
|
||||||
postCar(params).then(res => {
|
postCar(params).then(res => {
|
||||||
|
isSubmitting.value = false
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
@@ -299,9 +315,10 @@
|
|||||||
uni.removeStorageSync("carImageUrl")
|
uni.removeStorageSync("carImageUrl")
|
||||||
uni.removeStorageSync("carBrandId")
|
uni.removeStorageSync("carBrandId")
|
||||||
uni.removeStorageSync("checkType")
|
uni.removeStorageSync("checkType")
|
||||||
uni.redirectTo({ url: "/pageSubPack/my/myCarIndex" })
|
uni.navigateBack()
|
||||||
}, 1500)
|
}, 1500)
|
||||||
} else {
|
} else {
|
||||||
|
isSubmitting.value = false
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: res.msg || '提交失败',
|
title: res.msg || '提交失败',
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
@@ -467,4 +484,4 @@
|
|||||||
color: #999 !important;
|
color: #999 !important;
|
||||||
font-size: 28rpx !important;
|
font-size: 28rpx !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -63,6 +63,7 @@
|
|||||||
|
|
||||||
const statusBarHeight = ref(20)
|
const statusBarHeight = ref(20)
|
||||||
const currentStatus = ref('')
|
const currentStatus = ref('')
|
||||||
|
const isDeleting = ref(false)
|
||||||
const id = ref(undefined)
|
const id = ref(undefined)
|
||||||
const form = ref({
|
const form = ref({
|
||||||
plateNo: '',
|
plateNo: '',
|
||||||
@@ -110,11 +111,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onDelete = () => {
|
const onDelete = () => {
|
||||||
|
if (isDeleting.value) return
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: "确认删除",
|
title: "确认删除",
|
||||||
content: "确认删除此车辆信息吗?",
|
content: "确认删除此车辆信息吗?",
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
if (res.confirm) {
|
if (res.confirm) {
|
||||||
|
isDeleting.value = true
|
||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: '删除中...',
|
title: '删除中...',
|
||||||
mask: true
|
mask: true
|
||||||
@@ -122,6 +125,7 @@
|
|||||||
deleteCar({
|
deleteCar({
|
||||||
carId: id.value
|
carId: id.value
|
||||||
}).then(deleteRes => {
|
}).then(deleteRes => {
|
||||||
|
isDeleting.value = false
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
if (deleteRes.code === 200) {
|
if (deleteRes.code === 200) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
@@ -129,7 +133,7 @@
|
|||||||
icon: 'success'
|
icon: 'success'
|
||||||
})
|
})
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
uni.redirectTo({ url: "/pageSubPack/my/myCarIndex" })
|
uni.navigateBack()
|
||||||
}, 1500)
|
}, 1500)
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
|
|||||||
@@ -40,6 +40,9 @@
|
|||||||
import {
|
import {
|
||||||
getMyCarList
|
getMyCarList
|
||||||
} from '@/pageSubPack/api/apiSub.js'
|
} from '@/pageSubPack/api/apiSub.js'
|
||||||
|
import {
|
||||||
|
onShow
|
||||||
|
} from '@dcloudio/uni-app'
|
||||||
const statusBarHeight = ref(20)
|
const statusBarHeight = ref(20)
|
||||||
const defaultCarImg = "http://47.104.199.163:9090/images/propertyImgs/defaultCarImg.png"
|
const defaultCarImg = "http://47.104.199.163:9090/images/propertyImgs/defaultCarImg.png"
|
||||||
const carList = ref([])
|
const carList = ref([])
|
||||||
@@ -61,9 +64,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 页面加载时请求第一页
|
// 页面加载时请求第一页
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList()
|
getList()
|
||||||
})
|
})
|
||||||
|
// 从子页面返回时刷新列表(如新增/编辑/删除车辆后)
|
||||||
|
onShow(() => {
|
||||||
|
pageNum.value = 1
|
||||||
|
noMoreData.value = false
|
||||||
|
loadingMore.value = false
|
||||||
|
carList.value = []
|
||||||
|
getList()
|
||||||
|
})
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
// 防重复请求
|
// 防重复请求
|
||||||
if (loadingMore.value || noMoreData.value) return
|
if (loadingMore.value || noMoreData.value) return
|
||||||
@@ -268,4 +279,4 @@
|
|||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 46px;
|
height: 46px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user