This commit is contained in:
Your Name
2026-05-27 18:11:26 +08:00
parent 13f58a5fdc
commit 4f066b560e
2 changed files with 163 additions and 20 deletions
+14 -1
View File
@@ -778,6 +778,7 @@ const showDatePicker = ref(false)
const diagnosisId = ref(null) const diagnosisId = ref(null)
const patientId = ref(null) const patientId = ref(null)
const isAddMode = ref(false) // 新建模式 const isAddMode = ref(false) // 新建模式
const returnUrl = ref('') // 保存成功后跳回(如日常记录页)
// 表单数据 // 表单数据
const formData = ref({ const formData = ref({
@@ -1023,6 +1024,13 @@ const loadCardDetail = async () => {
const options = currentPage.options || {} const options = currentPage.options || {}
diagnosisId.value = options.id diagnosisId.value = options.id
isAddMode.value = options.add === '1' || options.add === 1 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') const userData = uni.getStorageSync('userData')
patientId.value = userData?.diagnosis?.patient_id patientId.value = userData?.diagnosis?.patient_id
@@ -1302,7 +1310,12 @@ const submitForm = async () => {
} }
uni.showToast({ title: isAddMode.value ? '创建成功' : '保存成功', icon: 'success' }) uni.showToast({ title: isAddMode.value ? '创建成功' : '保存成功', icon: 'success' })
setTimeout(() => { setTimeout(() => {
uni.navigateBack() const back = returnUrl.value
if (back && back.startsWith('/')) {
uni.redirectTo({ url: back })
} else {
uni.navigateBack()
}
}, 1500) }, 1500)
} else { } else {
uni.showToast({ title: res.msg || '保存失败', icon: 'none' }) uni.showToast({ title: res.msg || '保存失败', icon: 'none' })
+149 -19
View File
@@ -212,7 +212,11 @@
</view> </view>
</view> </view>
<block v-if="!isInviteViewer"> <view v-if="authChecking && !isInviteViewer" class="page-gate-loading">
<text class="page-gate-loading-text">正在登录</text>
</view>
<block v-if="!isInviteViewer && !authChecking">
<!-- 顶部 Hero智能问候 + 今日状态--> <!-- 顶部 Hero智能问候 + 今日状态-->
<view class="hero"> <view class="hero">
<view class="hero-bg" /> <view class="hero-bg" />
@@ -1384,6 +1388,10 @@ const patientName = ref('')
const age = ref(0) const age = ref(0)
const gender = ref(0) const gender = ref(0)
/** 登录 / 就诊卡门禁校验中(避免未登录时闪屏) */
const authChecking = ref(false)
let gateRedirected = false
const loading = ref(false) const loading = ref(false)
const cardsLoading = ref(false) const cardsLoading = ref(false)
const cards = ref([]) const cards = ref([])
@@ -1767,10 +1775,104 @@ function getDayBpTrend(date) {
return makeTrend(cur, prev.systolic, 0) 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() { async function fetchCardList() {
const token = uni.getStorageSync('token') if (!hasAuthToken()) return []
if (!token) return
cardsLoading.value = true cardsLoading.value = true
try { try {
const res = await proxy.apiUrl({ const res = await proxy.apiUrl({
@@ -1793,7 +1895,7 @@ async function fetchCardList() {
} }
async function applyCard(card) { async function applyCard(card) {
if (!card) return if (!card || !hasAuthToken()) return
diagnosisId.value = Number(card.id) || 0 diagnosisId.value = Number(card.id) || 0
patientId.value = Number(card.patient_id) || 0 patientId.value = Number(card.patient_id) || 0
patientName.value = card.patient_name || '' patientName.value = card.patient_name || ''
@@ -1822,7 +1924,7 @@ async function onSelectCard(card) {
// ============ 接口请求 ============ // ============ 接口请求 ============
async function fetchAll() { async function fetchAll() {
if (!diagnosisId.value) return if (!hasAuthToken() || !diagnosisId.value) return
loading.value = true loading.value = true
const { start, end } = currentRange.value const { start, end } = currentRange.value
try { try {
@@ -3095,24 +3197,33 @@ async function bootstrap(options) {
options = options || {} options = options || {}
const inviteCode = String(options.invite_code || '').trim() const inviteCode = String(options.invite_code || '').trim()
if (options.from === 'share' && inviteCode) { if (options.from === 'share' && inviteCode) {
authChecking.value = false
await bootstrapInviteViewer(inviteCode) await bootstrapInviteViewer(inviteCode)
return return
} }
isInviteViewer.value = false isInviteViewer.value = false
const passedDiagnosisId = Number(options.diagnosis_id || options.id || 0) gateRedirected = false
diagnosisId.value = passedDiagnosisId authChecking.value = true
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
const token = uni.getStorageSync('token') // 登录完成前不写 diagnosisId,避免模板/子流程提前打业务接口
if (!token) { const passedDiagnosisId = Number(options.diagnosis_id || options.id || 0)
showUserToast('请先登录') 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 return
} }
readUserContext()
const list = await fetchCardList() const list = await fetchCardList()
if (Array.isArray(list) && list.length > 0) { if (Array.isArray(list) && list.length > 0) {
@@ -3123,16 +3234,23 @@ async function bootstrap(options) {
if (!target) target = list[0] if (!target) target = list[0]
await applyCard(target) await applyCard(target)
} else { } 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) { if (!diagnosisId.value || !patientId.value) {
readUserContext() readUserContext()
} }
if (!diagnosisId.value) { if (!diagnosisId.value) {
showUserToast('暂无就诊卡,请先创建') authChecking.value = false
redirectToCardEntry()
return return
} }
} }
fetchAll() authChecking.value = false
await fetchAll()
} }
onLoad((options) => { onLoad((options) => {
@@ -3152,6 +3270,7 @@ onShareAppMessage(() => {
}) })
onShow(() => { onShow(() => {
if (authChecking.value || gateRedirected) return
if (!isInviteViewer.value && diagnosisId.value) { if (!isInviteViewer.value && diagnosisId.value) {
loadFamilyLikeSummary() loadFamilyLikeSummary()
} }
@@ -3162,7 +3281,7 @@ onPullDownRefresh(async () => {
if (isInviteViewer.value) { if (isInviteViewer.value) {
const code = invitePreview.value.invite_code const code = invitePreview.value.invite_code
if (code) await bootstrapInviteViewer(code) if (code) await bootstrapInviteViewer(code)
} else { } else if (await ensureLoggedIn()) {
await fetchAll() await fetchAll()
} }
uni.stopPullDownRefresh() uni.stopPullDownRefresh()
@@ -3215,7 +3334,7 @@ function applyGamifyPayload(data) {
} }
async function fetchGamifyState() { async function fetchGamifyState() {
if (!diagnosisId.value) return if (!hasAuthToken() || !diagnosisId.value) return
try { try {
const res = await proxy.apiUrl({ const res = await proxy.apiUrl({
url: '/api/tcm/dailyGetGamify', url: '/api/tcm/dailyGetGamify',
@@ -3725,7 +3844,7 @@ function closeWeeklyReport() {
} }
async function loadFamilyLikeSummary() { async function loadFamilyLikeSummary() {
if (!diagnosisId.value || isInviteViewer.value) return if (!hasAuthToken() || !diagnosisId.value || isInviteViewer.value) return
const token = uni.getStorageSync('token') const token = uni.getStorageSync('token')
if (!token) return if (!token) return
try { try {
@@ -3846,6 +3965,17 @@ async function onFamilyLike() {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.page-gate-loading {
min-height: 60vh;
display: flex;
align-items: center;
justify-content: center;
padding: 80rpx 40rpx;
}
.page-gate-loading-text {
font-size: 28rpx;
color: #64748b;
}
.daily-page { .daily-page {
/* Premium UI Color System & Variables - Teal-Emerald Healing Redesign */ /* Premium UI Color System & Variables - Teal-Emerald Healing Redesign */
--primary: #0d9488; --primary: #0d9488;