更新
This commit is contained in:
@@ -374,6 +374,53 @@
|
||||
<text>数据仅供参考,请遵医嘱</text>
|
||||
</view>
|
||||
|
||||
<!-- 无就诊卡:授权手机号后可录入 -->
|
||||
<view v-if="phoneGateVisible" class="input-modal-mask" @click="closePhoneGate">
|
||||
<view class="input-modal phone-gate-modal" @click.stop>
|
||||
<view class="input-modal-grip" />
|
||||
<view class="input-modal-head">
|
||||
<view class="input-modal-title-wrap">
|
||||
<text class="input-modal-title">授权手机号</text>
|
||||
<text class="input-modal-sub">绑定手机号后即可记录血糖,无需先填写就诊卡</text>
|
||||
</view>
|
||||
<view class="input-modal-close" @click="closePhoneGate">
|
||||
<text class="input-modal-close-icon">×</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="phone-gate-body">
|
||||
<text class="phone-gate-tip">微信仅提供手机号,请选择性别以便写入就诊档案。</text>
|
||||
<view class="phone-gate-gender">
|
||||
<text class="phone-gate-gender-label">性别</text>
|
||||
<view class="phone-gate-gender-row">
|
||||
<view
|
||||
class="phone-gate-gender-opt"
|
||||
:class="{ active: phoneGateSex === 1 }"
|
||||
@click="phoneGateSex = 1"
|
||||
>
|
||||
<text>男</text>
|
||||
</view>
|
||||
<view
|
||||
class="phone-gate-gender-opt"
|
||||
:class="{ active: phoneGateSex === 2 }"
|
||||
@click="phoneGateSex = 2"
|
||||
>
|
||||
<text>女</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<button
|
||||
class="phone-gate-btn"
|
||||
open-type="getPhoneNumber"
|
||||
:loading="phoneBinding"
|
||||
:disabled="phoneBinding || !phoneGateSex"
|
||||
@getphonenumber="onPhoneGateAuthorize"
|
||||
>
|
||||
微信授权手机号
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 录入今日数据弹层 -->
|
||||
<view v-if="inputForm.visible" class="input-modal-mask" @click="closeInputForm">
|
||||
<view class="input-modal" @click.stop>
|
||||
@@ -528,7 +575,11 @@ const gender = ref(0)
|
||||
|
||||
/** 登录 / 就诊卡门禁校验中(避免未登录时闪屏) */
|
||||
const authChecking = ref(false)
|
||||
let gateRedirected = false
|
||||
|
||||
const userMobile = ref('')
|
||||
const phoneGateVisible = ref(false)
|
||||
const phoneGateSex = ref(0)
|
||||
const phoneBinding = ref(false)
|
||||
|
||||
const loading = ref(false)
|
||||
const cardsLoading = ref(false)
|
||||
@@ -1020,15 +1071,6 @@ async function ensureLoggedIn() {
|
||||
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() {
|
||||
if (!hasAuthToken()) return []
|
||||
@@ -1062,6 +1104,145 @@ async function applyCard(card) {
|
||||
gender.value = Number(card.gender) || 0
|
||||
}
|
||||
|
||||
function readUserMobile() {
|
||||
try {
|
||||
const userData = uni.getStorageSync('userData') || {}
|
||||
userMobile.value = String(userData.mobile || userData.phone || '').trim()
|
||||
} catch (e) {
|
||||
userMobile.value = ''
|
||||
}
|
||||
return userMobile.value
|
||||
}
|
||||
|
||||
function syncPhoneGateSexFromUser() {
|
||||
try {
|
||||
const userData = uni.getStorageSync('userData') || {}
|
||||
const sex = Number(userData.sex)
|
||||
phoneGateSex.value = sex === 1 || sex === 2 ? sex : 0
|
||||
} catch (e) {
|
||||
phoneGateSex.value = 0
|
||||
}
|
||||
}
|
||||
|
||||
function openPhoneGate() {
|
||||
syncPhoneGateSexFromUser()
|
||||
phoneGateVisible.value = true
|
||||
}
|
||||
|
||||
async function refreshUserMobile() {
|
||||
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)
|
||||
userMobile.value = String(res.data.mobile || res.data.phone || '').trim()
|
||||
}
|
||||
} catch (e) {
|
||||
/* 静默 */
|
||||
}
|
||||
return userMobile.value
|
||||
}
|
||||
|
||||
async function ensureDailyContextByPhone(sex) {
|
||||
if (diagnosisId.value) return true
|
||||
|
||||
const payload = {}
|
||||
const sexVal = sex ?? phoneGateSex.value
|
||||
if (sexVal === 1 || sexVal === 2) {
|
||||
payload.sex = sexVal
|
||||
}
|
||||
|
||||
const res = await proxy.apiUrl({
|
||||
url: '/api/tcm/dailyEnsurePhoneContext',
|
||||
method: 'POST',
|
||||
data: payload
|
||||
}, false)
|
||||
|
||||
if (res && res.code === 1 && res.data && res.data.diagnosis_id) {
|
||||
await applyCard({
|
||||
id: res.data.diagnosis_id,
|
||||
patient_id: res.data.patient_id,
|
||||
patient_name: res.data.patient_name || '',
|
||||
age: res.data.age || 0,
|
||||
gender: res.data.gender || 0
|
||||
})
|
||||
if (res.data.created) {
|
||||
await fetchCardList()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if (res && res.data && res.data.need_mobile) {
|
||||
return 'need_mobile'
|
||||
}
|
||||
|
||||
showUserToast(formatUserMessage(res?.msg, '无法开始录入'))
|
||||
return false
|
||||
}
|
||||
|
||||
async function ensureCanRecordGlucose() {
|
||||
if (diagnosisId.value) return true
|
||||
|
||||
readUserMobile()
|
||||
if (!userMobile.value) {
|
||||
openPhoneGate()
|
||||
return false
|
||||
}
|
||||
|
||||
const ok = await ensureDailyContextByPhone()
|
||||
if (ok === 'need_mobile') {
|
||||
openPhoneGate()
|
||||
return false
|
||||
}
|
||||
return !!ok
|
||||
}
|
||||
|
||||
function closePhoneGate() {
|
||||
if (phoneBinding.value) return
|
||||
phoneGateVisible.value = false
|
||||
}
|
||||
|
||||
async function onPhoneGateAuthorize(e) {
|
||||
const detail = e?.detail || {}
|
||||
if (detail.errMsg && !String(detail.errMsg).includes('ok')) {
|
||||
showUserToast('需要授权手机号后才能录入血糖')
|
||||
return
|
||||
}
|
||||
const code = detail.code
|
||||
if (!code) {
|
||||
showUserToast('获取手机号失败,请重试')
|
||||
return
|
||||
}
|
||||
if (phoneGateSex.value !== 1 && phoneGateSex.value !== 2) {
|
||||
showUserToast('请先选择性别')
|
||||
return
|
||||
}
|
||||
|
||||
phoneBinding.value = true
|
||||
try {
|
||||
const res = await proxy.apiUrl({
|
||||
url: '/api/user/getMobileByMnp',
|
||||
method: 'POST',
|
||||
data: { code, sex: phoneGateSex.value }
|
||||
}, false)
|
||||
if (!res || res.code !== 1) {
|
||||
showUserToast(formatUserMessage(res?.msg, '绑定手机号失败'))
|
||||
return
|
||||
}
|
||||
await refreshUserMobile()
|
||||
phoneGateVisible.value = false
|
||||
const ok = await ensureDailyContextByPhone(phoneGateSex.value)
|
||||
if (ok === true) {
|
||||
await openInputForm(true)
|
||||
} else if (ok === 'need_mobile') {
|
||||
openPhoneGate()
|
||||
}
|
||||
} catch (err) {
|
||||
showUserToast('网络异常,请稍后再试')
|
||||
} finally {
|
||||
phoneBinding.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function onSelectCard(card) {
|
||||
if (!card || Number(card.id) === Number(diagnosisId.value)) return
|
||||
bloodRecords.value = []
|
||||
@@ -1150,10 +1331,10 @@ function onRefresh() {
|
||||
fetchAll()
|
||||
}
|
||||
|
||||
function goMorePage() {
|
||||
async function goMorePage() {
|
||||
if (!diagnosisId.value) {
|
||||
showUserToast('请先选择就诊卡')
|
||||
return
|
||||
const ok = await ensureCanRecordGlucose()
|
||||
if (!ok || !diagnosisId.value) return
|
||||
}
|
||||
uni.navigateTo({ url: '/tongji/pages/more' })
|
||||
}
|
||||
@@ -1384,16 +1565,20 @@ function onInputField(field, e) {
|
||||
inputForm.value[field] = val
|
||||
}
|
||||
|
||||
async function openInputForm() {
|
||||
if (!diagnosisId.value) {
|
||||
showUserToast('请先选择就诊卡')
|
||||
return
|
||||
}
|
||||
async function openInputForm(skipEnsure = false) {
|
||||
const token = uni.getStorageSync('token')
|
||||
if (!token) {
|
||||
showUserToast('请先登录后再录入')
|
||||
return
|
||||
}
|
||||
if (!skipEnsure) {
|
||||
const can = await ensureCanRecordGlucose()
|
||||
if (!can) return
|
||||
}
|
||||
if (!diagnosisId.value) {
|
||||
showUserToast('请先授权手机号')
|
||||
return
|
||||
}
|
||||
// 微信小程序 canvas 是原生组件、z-index 无法被弹层覆盖,
|
||||
// 这里通过 v-if 卸载它;下次显示时 selectorQuery 拿到的会是新节点,
|
||||
// 因此先清空缓存的 ctx / node,避免下次 ensureCanvas 复用旧引用。
|
||||
@@ -1434,7 +1619,7 @@ function closeInputForm() {
|
||||
}
|
||||
|
||||
/** 任一录入弹层打开时需卸载 canvas(小程序原生组件会盖住普通 view)*/
|
||||
const recordOverlayOpen = computed(() => inputForm.value.visible)
|
||||
const recordOverlayOpen = computed(() => inputForm.value.visible || phoneGateVisible.value)
|
||||
|
||||
async function submitInputForm() {
|
||||
if (inputForm.value.submitting || inputForm.value.loading) return
|
||||
@@ -2153,7 +2338,6 @@ async function bootstrap(options) {
|
||||
}
|
||||
|
||||
isInviteViewer.value = false
|
||||
gateRedirected = false
|
||||
authChecking.value = true
|
||||
|
||||
// 登录完成前不写 diagnosisId,避免模板/子流程提前打业务接口
|
||||
@@ -2192,15 +2376,16 @@ async function bootstrap(options) {
|
||||
if (!diagnosisId.value || !patientId.value) {
|
||||
readUserContext()
|
||||
}
|
||||
if (!diagnosisId.value) {
|
||||
authChecking.value = false
|
||||
redirectToCardEntry()
|
||||
return
|
||||
readUserMobile()
|
||||
if (!diagnosisId.value && userMobile.value) {
|
||||
await ensureDailyContextByPhone()
|
||||
}
|
||||
}
|
||||
|
||||
authChecking.value = false
|
||||
await fetchAll()
|
||||
if (diagnosisId.value) {
|
||||
await fetchAll()
|
||||
}
|
||||
}
|
||||
|
||||
onLoad((options) => {
|
||||
@@ -2208,7 +2393,7 @@ onLoad((options) => {
|
||||
})
|
||||
|
||||
onShow(() => {
|
||||
if (authChecking.value || gateRedirected) return
|
||||
if (authChecking.value) return
|
||||
nextTick(() => scheduleChartRedraw())
|
||||
})
|
||||
|
||||
@@ -4110,6 +4295,62 @@ async function onFamilyLike() {
|
||||
line-height: 1;
|
||||
font-weight: 700;
|
||||
}
|
||||
.phone-gate-body {
|
||||
padding: 32rpx;
|
||||
}
|
||||
.phone-gate-tip {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
color: var(--primary-container);
|
||||
line-height: 1.6;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
.phone-gate-gender {
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
.phone-gate-gender-label {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
color: var(--primary);
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
.phone-gate-gender-row {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
}
|
||||
.phone-gate-gender-opt {
|
||||
flex: 1;
|
||||
min-height: 88rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 20rpx;
|
||||
background: #ffffff;
|
||||
border: 2rpx solid rgba(32, 78, 43, 0.25);
|
||||
color: var(--primary-container);
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
.phone-gate-gender-opt.active {
|
||||
border-color: var(--primary);
|
||||
color: var(--primary);
|
||||
box-shadow: inset 0 0 0 1rpx var(--primary);
|
||||
}
|
||||
.phone-gate-btn {
|
||||
width: 100%;
|
||||
min-height: 96rpx;
|
||||
line-height: 96rpx;
|
||||
border-radius: 20rpx;
|
||||
background: #ffffff;
|
||||
color: var(--primary);
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
border: 2rpx solid var(--primary);
|
||||
}
|
||||
.phone-gate-btn::after {
|
||||
border: none;
|
||||
}
|
||||
.input-modal-loading {
|
||||
min-height: 520rpx;
|
||||
padding: 120rpx 0;
|
||||
|
||||
Reference in New Issue
Block a user