Files
xk-doctor-wx/common/js/index.js
李琦 31551437c2 1. 更新切换账号逻辑
2. 诊所管理员功能上线
2026-05-30 16:36:33 +08:00

275 lines
7.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Request from './request.js';
import errorCode from './errorCode.js';
import {Base64} from "js-base64";
import { getDoctorWxEnv } from '@/config/app-env.js';
const { legacyApiBase } = getDoctorWxEnv();
export const config = {
baseUrl: legacyApiBase
}
const arr = [
'mobile',
'express_mobile',
'doctor',
'accept_tel',
'patient_mobile',
'id_card',
'idcard',
'password'
]
// 敏感数据(解密后做脱敏;需与下方 switch 分支一致)
const sensitiveData = [
'id_card',
'idcard',
'mobile',
'express_mobile',
'patient_mobile'
]
/**
* 请求拦截器
* @param {*} options
*/
const reqInterceptor = async (options) => {
// 加密
if (options.data != null && options.type !== 'upload') {
options.data = getRes(options.data, false)
}
options.header = {
...options.header
}
const skipToken = options.header.isToken === false
const isClinicAdminReq = options.header._clinicAdmin === '1'
|| (options.url && String(options.url).indexOf('clinic-admin') !== -1)
const isDoctorWxAuthReq = options.url && String(options.url).indexOf('doctor-wx-auth') !== -1
// 内部控制位,不得作为 HTTP 头发出
delete options.header.isToken
delete options.header._clinicAdmin
const clinicToken = uni.getStorageSync('clinic_admin_token')
const doctorToken = uni.getStorageSync('token')
const loginMode = uni.getStorageSync('loginMode')
if (!skipToken) {
if (isDoctorWxAuthReq) {
if (loginMode === 'clinic_admin' && clinicToken) {
options.header['authorization'] = `Bearer ${clinicToken}`
} else if (doctorToken) {
options.header['authorization'] = `Bearer ${doctorToken}`
} else if (clinicToken) {
options.header['authorization'] = `Bearer ${clinicToken}`
}
} else if (isClinicAdminReq && clinicToken) {
options.header['authorization'] = `Bearer ${clinicToken}`
} else if (doctorToken) {
options.header['authorization'] = `Bearer ${doctorToken}`
}
}
return options;
}
/**
* 响应拦截器
*/
const resInterceptor = (response, conf = {}) => {
// 网络状态码
const statusCode = response.statusCode|| response.errcode;
// 响应拦截器
if (statusCode >= 200 && statusCode < 300) {
_responseLog(response, conf, "response 200-299")
// 解密Yii业务在 dataLaravel jok业务在 result
let res = response.data
if (res == null || typeof res !== 'object') {
return res
}
if (res.data != null) {
res.data = getRes(res.data)
}
if (res.result != null) {
res.result = getRes(res.result)
}
return res
} else if (statusCode === 500) {
uni.showToast({
icon: 'error',
title: response['msg'] || errorCode[statusCode]
})
_responseLog(response, conf, "response 500")
// 增加一个控制字段wakaryReqToReject 使 reject的内容更加可控
return {
// 根据当前字段来判断是否reject
wakaryReqToReject: true,
// 下面可以配置其他返回信息方便统一处理reject
// 以下内容作为reject的返回根据需求处理返回具体错误信息
msg: "服务器错误",
res: response
}
} else if (statusCode === 401) {
uni.showToast({
icon: 'error',
title: response['msg'] || response['message'] || errorCode[statusCode]
})
const isClinic = uni.getStorageSync('loginMode') === 'clinic_admin'
if (isClinic) {
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
}
} else {
uni.showToast({
icon: 'error',
title: response['msg'] || errorCode[statusCode]
})
_responseLog(response, conf, "response 300-499");
// 增加一个控制字段wakaryReqToReject 使 reject的内容更加可控
return {
// 根据当前字段来判断是否reject
wakaryReqToReject: true,
// 下面可以配置其他返回信息方便统一处理reject
// 以下内容作为reject的返回根据需求处理返回具体错误信息
msg: "response 300-499",
res: response
}
}
}
/**
* request log
*/
function _requestLog(req, describe = null) {
if (process.env.NODE_ENV === 'development') {}
}
/**
* response log
*/
function _responseLog(res, conf = {}, describe = null) {
let _statusCode = res.statusCode;
if (process.env.NODE_ENV === 'development') {}
if (_statusCode === 500) {
// save log to server
}
}
function getRes(obj, isDecode = true) {
if (obj == null || typeof obj !== 'object') {
return obj
}
try {
for (const key in obj) {
if (Array.isArray(obj[key])) {
obj[key] = getRes(obj[key])
} else if (typeof obj[key] === 'object' && obj[key] !== null) {
obj[key] = getRes(obj[key])
} else {
// 判断obj[key]是否在arr中
if (arr.indexOf(key) !== -1) {
let aseFile = ''
if (isDecode === true) {
aseFile = customBase64Decode(obj[key])
} else {
aseFile = customBase64Encode(obj[key])
}
const isGarbled = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\xFF]|[\u{E000}-\u{F8FF}]/u.test(
typeof aseFile === 'string' ? aseFile : ''
)
if (isGarbled) {
aseFile = obj[key]
}
if (isDecode === true) {
if (sensitiveData.indexOf(key) !== -1) {
// 数据脱敏,自动匹配姓名、手机号、身份证
switch (key) {
case 'express_name':
case 'express_region':
case 'accept_name':
case 'patient':
// 保留前两个字符,其余用星号代替
aseFile = aseFile.slice(0, 1).padEnd(aseFile.length, '*');
break;
case 'mobile':
case 'express_mobile':
// 保留前三位和后四位,中间用星号代替
aseFile = aseFile.slice(0, 3).padEnd(aseFile.length - 4, '*') + aseFile.slice(-4);
break;
case 'id_card':
case 'idcard':
// 保留前六位和后四位,中间用星号代替
aseFile = aseFile.slice(0, 6).padEnd(aseFile.length - 4, '*') + aseFile.slice(-4);
break;
default:
// 默认情况下,全部用星号代替
break;
}
}
}
obj[key] = aseFile
}
}
}
return obj
} catch (error) {
console.error('错误', error)
return obj
}
}
function customBase64Decode(data) {
// return data
try {
// 第一次Base64解码
const decodedFirst = Base64.decode(data)
// 截取从第30个字符开始往后的内容
const subStr = decodedFirst.slice(30)
// 第二次Base64解码
return Base64.decode(subStr) != ''? Base64.decode(subStr): data
} catch (error) {
console.error(`解码Base64字符串【${data}】时发生错误`, error)
return data
}
}
// 加密
function customBase64Encode(data) {
if (data == null || data === '') return data
// return data
try {
// 和加密方法差不多但是是要生成30个随机字符
let randomString = ''
for (let i = 0; i < 30; i++) {
const randomChar = String.fromCharCode(Math.floor(Math.random() * (126 - 32 + 1)) + 32)
randomString += randomChar
}
const encoded = Base64.encode(data)
return Base64.encode(randomString + encoded)
} catch (error) {
console.error(`加密字符串【${data}】时发生错误`, error)
return data
}
}
/**
* 请求方法封装
*/
export const req = new Request(config, reqInterceptor, resInterceptor)