From 4f066b560e318aabcf4719895f082552e937fdd6 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 27 May 2026 18:11:26 +0800 Subject: [PATCH] gengx --- TUICallKit-Vue3/pages/Card/edit_card.vue | 15 +- TUICallKit-Vue3/tongji/pages/index.vue | 168 ++++++++++++++++++++--- 2 files changed, 163 insertions(+), 20 deletions(-) diff --git a/TUICallKit-Vue3/pages/Card/edit_card.vue b/TUICallKit-Vue3/pages/Card/edit_card.vue index daaddd2e..93c9a970 100644 --- a/TUICallKit-Vue3/pages/Card/edit_card.vue +++ b/TUICallKit-Vue3/pages/Card/edit_card.vue @@ -778,6 +778,7 @@ const showDatePicker = ref(false) const diagnosisId = ref(null) const patientId = ref(null) const isAddMode = ref(false) // 新建模式 +const returnUrl = ref('') // 保存成功后跳回(如日常记录页) // 表单数据 const formData = ref({ @@ -1023,6 +1024,13 @@ const loadCardDetail = async () => { const options = currentPage.options || {} diagnosisId.value = options.id isAddMode.value = options.add === '1' || options.add === 1 + if (options.returnUrl) { + try { + returnUrl.value = decodeURIComponent(String(options.returnUrl)) + } catch (e) { + returnUrl.value = String(options.returnUrl) + } + } const userData = uni.getStorageSync('userData') patientId.value = userData?.diagnosis?.patient_id @@ -1302,7 +1310,12 @@ const submitForm = async () => { } uni.showToast({ title: isAddMode.value ? '创建成功' : '保存成功', icon: 'success' }) setTimeout(() => { - uni.navigateBack() + const back = returnUrl.value + if (back && back.startsWith('/')) { + uni.redirectTo({ url: back }) + } else { + uni.navigateBack() + } }, 1500) } else { uni.showToast({ title: res.msg || '保存失败', icon: 'none' }) diff --git a/TUICallKit-Vue3/tongji/pages/index.vue b/TUICallKit-Vue3/tongji/pages/index.vue index 70cb1b4c..cc504e8d 100644 --- a/TUICallKit-Vue3/tongji/pages/index.vue +++ b/TUICallKit-Vue3/tongji/pages/index.vue @@ -212,7 +212,11 @@ - + + 正在登录… + + + @@ -1384,6 +1388,10 @@ const patientName = ref('') const age = ref(0) const gender = ref(0) +/** 登录 / 就诊卡门禁校验中(避免未登录时闪屏) */ +const authChecking = ref(false) +let gateRedirected = false + const loading = ref(false) const cardsLoading = ref(false) const cards = ref([]) @@ -1767,10 +1775,104 @@ function getDayBpTrend(date) { return makeTrend(cur, prev.systolic, 0) } +// ============ 登录 / 就诊卡门禁 ============ +/** 进行中的登录任务(避免与 App.onLaunch 重复发起 mnpLogin,并保证业务接口在其之后) */ +let authSessionPromise = null + +function hasAuthToken() { + return !!String(uni.getStorageSync('token') || '').trim() +} + +function clearAuthStorage() { + uni.removeStorageSync('token') + authSessionPromise = null +} + +function wxLoginGetCode() { + return new Promise((resolve, reject) => { + uni.login({ + provider: 'weixin', + success: (res) => { + if (res && res.code) resolve(res.code) + else reject(new Error('微信登录未返回 code')) + }, + fail: reject + }) + }) +} + +async function mnpLoginWithCode(code) { + const res = await proxy.apiUrl({ + url: '/api/login/mnpLogin', + method: 'POST', + data: { code } + }, false) + if (res && res.code === 1 && res.data && res.data.token) { + uni.setStorageSync('token', res.data.token) + uni.setStorageSync('userData', res.data) + return res.data + } + clearAuthStorage() + throw new Error(formatUserMessage(res?.msg, '登录失败')) +} + +async function doWxLogin() { + const code = await wxLoginGetCode() + await mnpLoginWithCode(code) + return hasAuthToken() +} + +/** 校验 token 有效;无效则清除并重新 mnpLogin(缺 token 时后端 code=0,不能当作已登录) */ +async function verifyOrLogin() { + if (!hasAuthToken()) { + return doWxLogin() + } + try { + const res = await proxy.apiUrl({ url: '/api/user/info', method: 'POST' }, false) + if (res && res.code === 1 && res.data) { + uni.setStorageSync('userData', res.data) + return true + } + } catch (e) { + /* 网络异常走重新登录 */ + } + clearAuthStorage() + try { + return await doWxLogin() + } catch (e2) { + return false + } +} + +/** 登录完成后再调业务接口;并发调用共享同一 Promise */ +async function ensureLoggedIn() { + if (authSessionPromise) { + return authSessionPromise + } + authSessionPromise = verifyOrLogin() + .then((ok) => { + if (!ok) authSessionPromise = null + return !!ok + }) + .catch(() => { + authSessionPromise = null + return false + }) + return authSessionPromise +} + +function redirectToCardEntry() { + if (gateRedirected) return + gateRedirected = true + const returnUrl = encodeURIComponent('/tongji/pages/index') + uni.redirectTo({ + url: `/pages/Card/edit_card?add=1&returnUrl=${returnUrl}` + }) +} + // ============ 就诊卡 ============ async function fetchCardList() { - const token = uni.getStorageSync('token') - if (!token) return + if (!hasAuthToken()) return [] cardsLoading.value = true try { const res = await proxy.apiUrl({ @@ -1793,7 +1895,7 @@ async function fetchCardList() { } async function applyCard(card) { - if (!card) return + if (!card || !hasAuthToken()) return diagnosisId.value = Number(card.id) || 0 patientId.value = Number(card.patient_id) || 0 patientName.value = card.patient_name || '' @@ -1822,7 +1924,7 @@ async function onSelectCard(card) { // ============ 接口请求 ============ async function fetchAll() { - if (!diagnosisId.value) return + if (!hasAuthToken() || !diagnosisId.value) return loading.value = true const { start, end } = currentRange.value try { @@ -3095,24 +3197,33 @@ async function bootstrap(options) { options = options || {} const inviteCode = String(options.invite_code || '').trim() if (options.from === 'share' && inviteCode) { + authChecking.value = false await bootstrapInviteViewer(inviteCode) return } isInviteViewer.value = false - const passedDiagnosisId = Number(options.diagnosis_id || options.id || 0) - diagnosisId.value = passedDiagnosisId - patientId.value = Number(options.patient_id || 0) - if (options.patient_name) patientName.value = decodeURIComponent(options.patient_name) - if (options.age) age.value = Number(options.age) || 0 - if (options.gender) gender.value = Number(options.gender) || 0 + gateRedirected = false + authChecking.value = true - const token = uni.getStorageSync('token') - if (!token) { - showUserToast('请先登录') + // 登录完成前不写 diagnosisId,避免模板/子流程提前打业务接口 + const passedDiagnosisId = Number(options.diagnosis_id || options.id || 0) + const passedPatientId = Number(options.patient_id || 0) + const passedPatientName = options.patient_name + ? decodeURIComponent(String(options.patient_name)) + : '' + const passedAge = Number(options.age) || 0 + const passedGender = Number(options.gender) || 0 + + const loggedIn = await ensureLoggedIn() + if (!loggedIn || !hasAuthToken()) { + authChecking.value = false + showUserToast('登录失败,请稍后重试') return } + readUserContext() + const list = await fetchCardList() if (Array.isArray(list) && list.length > 0) { @@ -3123,16 +3234,23 @@ async function bootstrap(options) { if (!target) target = list[0] await applyCard(target) } else { + if (passedDiagnosisId) diagnosisId.value = passedDiagnosisId + if (passedPatientId) patientId.value = passedPatientId + if (passedPatientName) patientName.value = passedPatientName + if (passedAge) age.value = passedAge + if (passedGender) gender.value = passedGender if (!diagnosisId.value || !patientId.value) { readUserContext() } if (!diagnosisId.value) { - showUserToast('暂无就诊卡,请先创建') + authChecking.value = false + redirectToCardEntry() return } } - fetchAll() + authChecking.value = false + await fetchAll() } onLoad((options) => { @@ -3152,6 +3270,7 @@ onShareAppMessage(() => { }) onShow(() => { + if (authChecking.value || gateRedirected) return if (!isInviteViewer.value && diagnosisId.value) { loadFamilyLikeSummary() } @@ -3162,7 +3281,7 @@ onPullDownRefresh(async () => { if (isInviteViewer.value) { const code = invitePreview.value.invite_code if (code) await bootstrapInviteViewer(code) - } else { + } else if (await ensureLoggedIn()) { await fetchAll() } uni.stopPullDownRefresh() @@ -3215,7 +3334,7 @@ function applyGamifyPayload(data) { } async function fetchGamifyState() { - if (!diagnosisId.value) return + if (!hasAuthToken() || !diagnosisId.value) return try { const res = await proxy.apiUrl({ url: '/api/tcm/dailyGetGamify', @@ -3725,7 +3844,7 @@ function closeWeeklyReport() { } async function loadFamilyLikeSummary() { - if (!diagnosisId.value || isInviteViewer.value) return + if (!hasAuthToken() || !diagnosisId.value || isInviteViewer.value) return const token = uni.getStorageSync('token') if (!token) return try { @@ -3846,6 +3965,17 @@ async function onFamilyLike() {