From fe841e772abfc442ca30be7ac9cdf1c83ae8e3f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E7=90=A6?= Date: Tue, 4 Aug 2026 13:56:14 +0800 Subject: [PATCH] =?UTF-8?q?feat:=201.=20=E6=95=B0=E8=84=89api=E9=89=B4?= =?UTF-8?q?=E5=88=AB=E8=BA=AB=E4=BB=BD=E8=AF=81=E3=80=82=202.=20=E5=90=8E?= =?UTF-8?q?=E5=8F=B0+=E5=BE=AE=E4=BF=A1=E7=99=BB=E9=99=86=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/doctorAuth.js | 9 +- common/js/index.js | 99 +++++++++++-------- components/doctor-login/doctor-login.vue | 15 ++- .../components/PrescriptionDetailPopup.vue | 6 +- .../components/PrescriptionDetailPopup.vue | 6 +- 5 files changed, 86 insertions(+), 49 deletions(-) diff --git a/api/doctorAuth.js b/api/doctorAuth.js index 903b640..e40d258 100644 --- a/api/doctorAuth.js +++ b/api/doctorAuth.js @@ -29,10 +29,11 @@ export function sendDoctorWxCode(phone, password) { } export function doctorWxLogin(payload) { + // client_type=mobile:医生/药师/诊所管理员等统一按手机端会话管理 return req.request({ url: `${AUTH_PREFIX}/login`, method: 'POST', - data: payload, + data: { ...(payload || {}), client_type: 'mobile' }, header: { isToken: false }, }); } @@ -45,10 +46,11 @@ export function getDoctorWxSiblingAccounts() { } export function switchDoctorWxAccount(payload) { + // client_type=mobile:切换账号按手机端会话管理 return doctorAuthRequest({ url: '/switch-account', method: 'POST', - data: payload, + data: { ...(payload || {}), client_type: 'mobile' }, }); } @@ -61,10 +63,11 @@ export function getDoctorWxAuthConfig() { } export function doctorWxLoginByWechat(payload) { + // 微信登录同样标记为手机端会话 return req.request({ url: `${AUTH_PREFIX}/wx-login`, method: 'POST', - data: payload, + data: { ...(payload || {}), client_type: 'mobile' }, header: { isToken: false }, }); } diff --git a/common/js/index.js b/common/js/index.js index e4ccbf0..ac94352 100644 --- a/common/js/index.js +++ b/common/js/index.js @@ -88,6 +88,60 @@ const reqInterceptor = async (options) => { return options; } +/** + * 登录失效统一处理:弹窗提示并按 loginMode 清理 token 后跳转登录页 + * @param {string} tipMsg 提示文案 + * @param {*} response 原始响应 + * @param {object} conf 请求配置(供 _responseLog 使用) + */ +const handleAuthExpired = (tipMsg, response, conf) => { + // 防重复弹窗:并发 401 只提示一次 + if (!uni.__xkAuthModalShowing) { + uni.__xkAuthModalShowing = true + uni.showModal({ + title: '登录失效', + content: tipMsg, + showCancel: false, + confirmText: '重新登录', + success() { + const loginMode = uni.getStorageSync('loginMode') + if (loginMode === 'platform_admin') { + uni.removeStorageSync('platform_admin_token') + uni.removeStorageSync('platform_admin_user') + uni.removeStorageSync('loginMode') + } else if (loginMode === 'salesperson') { + uni.removeStorageSync('salesperson_token') + uni.removeStorageSync('salesperson_user') + uni.removeStorageSync('loginMode') + } else if (loginMode === 'clinic_salesperson') { + uni.removeStorageSync('clinic_salesperson_token') + uni.removeStorageSync('clinic_salesperson_user') + uni.removeStorageSync('loginMode') + } else if (loginMode === 'clinic_admin') { + uni.removeStorageSync('clinic_admin_token') + uni.removeStorageSync('clinic_admin_user') + uni.removeStorageSync('loginMode') + } else { + uni.removeStorageSync('token') + uni.removeStorageSync('loginInfo') + uni.removeStorageSync('identity') + } + uni.__xkAuthModalShowing = false + uni.reLaunch({ url: '/pages/login/index' }) + }, + fail() { + uni.__xkAuthModalShowing = false + } + }) + } + _responseLog(response, conf, "response 401") + return { + wakaryReqToReject: true, + msg: tipMsg, + res: response + } +} + /** * 响应拦截器 */ @@ -108,6 +162,11 @@ const resInterceptor = (response, conf = {}) => { if (res.result != null) { res.result = getRes(res.result) } + // Laravel notAuth 返回 HTTP 200 + 业务码 401,需与 HTTP 401 走同一套登录失效处理 + const bizCode = Number(res.code != null ? res.code : res.errcode) + if (bizCode === 401) { + return handleAuthExpired(res.msg || res.message || '账号需重新登录', response, conf) + } return res } else if (statusCode === 500) { uni.showToast({ @@ -125,45 +184,7 @@ const resInterceptor = (response, conf = {}) => { res: response } } else if (statusCode === 401) { - uni.showToast({ - icon: 'error', - title: response['msg'] || response['message'] || errorCode[statusCode] - }) - const loginMode = uni.getStorageSync('loginMode') - if (loginMode === 'platform_admin') { - uni.removeStorageSync('platform_admin_token') - uni.removeStorageSync('platform_admin_user') - uni.removeStorageSync('loginMode') - } else if (loginMode === 'salesperson') { - uni.removeStorageSync('salesperson_token') - uni.removeStorageSync('salesperson_user') - uni.removeStorageSync('loginMode') - } else if (loginMode === 'clinic_salesperson') { - uni.removeStorageSync('clinic_salesperson_token') - uni.removeStorageSync('clinic_salesperson_user') - uni.removeStorageSync('loginMode') - } else if (loginMode === 'clinic_admin') { - uni.removeStorageSync('clinic_admin_token') - uni.removeStorageSync('clinic_admin_user') - uni.removeStorageSync('loginMode') - } else { - uni.removeStorageSync('token') - uni.removeStorageSync('loginInfo') - uni.removeStorageSync('identity') - } - setTimeout(() => { - uni.reLaunch({ url: '/pages/login/index' }) - }, 1000) - _responseLog(response, conf, "response 401") - // 增加一个控制字段wakaryReqToReject 使 reject的内容更加可控 - return { - // 根据当前字段来判断是否reject - wakaryReqToReject: true, - // 下面可以配置其他返回信息,方便统一处理reject - // 以下内容作为reject的返回,根据需求处理,返回具体错误信息 - msg: response['msg'] || errorCode[statusCode], - res: response - } + return handleAuthExpired(response['msg'] || response['message'] || errorCode[statusCode] || '账号需重新登录', response, conf) } else { uni.showToast({ icon: 'error', diff --git a/components/doctor-login/doctor-login.vue b/components/doctor-login/doctor-login.vue index acfae87..f3d9961 100644 --- a/components/doctor-login/doctor-login.vue +++ b/components/doctor-login/doctor-login.vue @@ -169,12 +169,17 @@ export default { uni.showLoading({ title: '正在获取验证码' }); sendDoctorWxCode(this.form.mobile, this.form.password) .then((res) => { - if (res.code === 0) { - this.$refs.uCode.start(); - if (res.result && res.result.code) { - this.smsCode = res.result.code; - } + // HTTP 200 但业务 code 非 0 时 reject,统一走 catch 弹 toast + if (res.code !== 0) { + return Promise.reject(new Error(res.message || res.msg || '获取验证码失败')); } + this.$refs.uCode.start(); + if (res.result && res.result.code) { + this.smsCode = res.result.code; + } + }) + .catch((err) => { + this.$toast(err.message || err.msg || '获取验证码失败'); }) .finally(() => { uni.hideLoading(); diff --git a/subPackages/sub_business_shared/order/components/PrescriptionDetailPopup.vue b/subPackages/sub_business_shared/order/components/PrescriptionDetailPopup.vue index b3db48d..12ddd5e 100644 --- a/subPackages/sub_business_shared/order/components/PrescriptionDetailPopup.vue +++ b/subPackages/sub_business_shared/order/components/PrescriptionDetailPopup.vue @@ -126,7 +126,9 @@ 医师 - {{ view.doctorName }} + + + {{ view.doctorName }} 审核药师 @@ -214,6 +216,8 @@ export default { || (w.data.doctor_info && w.data.doctor_info.identity_info && w.data.doctor_info.identity_info.sign_image) || (w.data.doctorInfo && w.data.doctorInfo.identityInfo && w.data.doctorInfo.identityInfo.sign_image) || '' + // 透传二次签名标记,供医师签名区双图展示 + mapped.doctorSecondSign = w.data.doctor_second_sign mapped.pharmacistSignImage = w.data.Pharmacist_sign_image || (w.data.pharmacist_info && w.data.pharmacist_info.identity && w.data.pharmacist_info.identity.sign_image) diff --git a/subPackages/sub_clinic_admin/order/components/PrescriptionDetailPopup.vue b/subPackages/sub_clinic_admin/order/components/PrescriptionDetailPopup.vue index 79724e8..d5cee2a 100644 --- a/subPackages/sub_clinic_admin/order/components/PrescriptionDetailPopup.vue +++ b/subPackages/sub_clinic_admin/order/components/PrescriptionDetailPopup.vue @@ -118,7 +118,9 @@ 医师 - {{ view.doctorName }} + + + {{ view.doctorName }} 审核药师 @@ -203,6 +205,8 @@ export default { || (w.data.doctor_info && w.data.doctor_info.identity_info && w.data.doctor_info.identity_info.sign_image) || (w.data.doctorInfo && w.data.doctorInfo.identityInfo && w.data.doctorInfo.identityInfo.sign_image) || '' + // 透传二次签名标记,供医师签名区双图展示 + mapped.doctorSecondSign = w.data.doctor_second_sign mapped.pharmacistSignImage = w.data.Pharmacist_sign_image || (w.data.pharmacist_info && w.data.pharmacist_info.identity && w.data.pharmacist_info.identity.sign_image)