业务功能·
微信小程序-接入电子健康卡
在数字化医疗的浪潮中,电子健康卡的接入成为提升医疗服务效率和便捷性的关键一环。对于前端开发者而言,实现电子健康卡的接入不仅需要对相关技术有深入理解,还需遵循严格的规范和流程。本文将介绍电子健康卡的接入方法。
流程介绍
实现思路
- 所有场景统一跳转到授权页面获取
wechatcode
- 所有回调页面统一处理
- 展示腾讯电子健康卡接口返回的h5页面
- 完善信息页面
- 人脸识别页面
- 验证成功页面
- 验证失败页面
- 结果处理页(中转页面,用于记录流程结束回调的参数,然后去触发互联网医院业务)
- 用卡上报场景统一处理
实现代码
电子健康卡相关工具方法
import { Emitter } from '../Emitter';
import { HEALTH_CARD_TYPE, genderEnum } from './constant';
import dayjs from 'dayjs';
import { reportHisData } from '@/apis/healthCard';
// 提示
const _toast = (title, complete) => {
uni.showToast({
title,
icon: 'none',
mask: true,
duration: 1500,
complete: () => {
// 延迟触发
setTimeout(() => {
complete && complete();
}, 1500);
},
});
};
// 加载
const _showLoading = (title = '加载中') => {
uni.showToast({
title,
duration: 1000 * 60 * 60 * 24,
icon: 'loading',
mask: true,
});
};
const _hideLoading = delayTime => {
// 延迟关闭
if (delayTime && typeof delayTime === 'number') {
setTimeout(() => {
uni.hideToast();
}, delayTime);
} else {
uni.hideToast();
}
};
// 日志
const _log = (...args) => {
console.log(...args);
};
class HealthCardUtil {
// 更新参数
patientId = '';
// 绑定参数
patientInfo = '';
// 授权验证
scene = '';
formPath = '';
verifyOrderId = '';
// 回调匹配的路由
matchRoute = '';
// 临时存储健康卡信息
healthCardInfo = null;
constructor() {
this.emitter = new Emitter();
this.showLoad = _showLoading;
this.hideLoad = _hideLoading;
this.toast = _toast;
this.log = _log;
}
create() {
this.recordFormPath();
uni.navigateTo({
url: `/patientPages/healthCard/auth/index?type=${HEALTH_CARD_TYPE.CREATE}`,
});
}
update(patientId) {
this.recordFormPath();
this.patientId = patientId;
uni.navigateTo({
url: `/patientPages/healthCard/auth/index?type=${HEALTH_CARD_TYPE.UPDATE}`,
});
}
// 验证
async verify({ scene, patientInfo, success, fail }) {
this.showLoad('跳转中');
const { healthCardId } = patientInfo;
// 非电子健康卡直接跳过
if (!healthCardId) {
success && success();
return;
}
this.patientInfo = patientInfo;
this.recordFormPath();
// 注册监听事件
this.onVerifySuccess(success);
this.onVerifyFail(fail);
this.scene = scene;
// 进行上报
await this.eventData({
qrCodeText: healthCardId,
scene,
});
setTimeout(() => {
this.hideLoad();
uni.navigateTo({
url: `/patientPages/healthCard/auth/index?type=${HEALTH_CARD_TYPE.SEARCH_VERIFY}`,
});
}, 500);
}
// 注册验证成功事件
onVerifySuccess(success) {
_log('【onVerifySuccess】', success);
// 防止重复注册
this.emitter.remove('verifySuccess');
this.emitter.once('verifySuccess', e => {
success && success(e);
});
}
emitVerifySuccess(e) {
this.emitter.emit('verifySuccess', e);
}
// 注册验证失败事件
onVerifyFail(fail) {
_log('【onVerifyFail】', fail);
// 防止重复注册
this.emitter.remove('verifyFail');
this.emitter.once('verifyFail', e => {
fail && fail(e);
});
}
emitVerifyFail(e) {
this.emitter.emit('verifyFail', e);
}
// 验证成功后
verifySuccess() {
this.toast('验证通过', () => {
// 返回来源路由
this.goBack(this.formPath, () => {
// 延迟触发
setTimeout(() => {
this.emitVerifySuccess();
}, 200);
});
});
}
// 验证失败后
verifyFail() {
this.toast('验证失败', () => {
this.goBack(this.formPath, () => {
// 延迟触发
setTimeout(() => {
this.emitVerifyFail();
}, 200);
});
});
}
// 记录来源路由
recordFormPath() {
// 来源路由
const curPages = getCurrentPages();
const curPage = curPages[curPages.length - 1];
this.formPath = curPage.route;
console.log('【formPath】', this.formPath);
}
// 匹配重定向的路径,返回到对应的页面
goBack(route = this.formPath, callback) {
// 返回到就诊人列表页
const curPages = getCurrentPages();
const pageLen = curPages.length;
let delta = 1;
while (delta <= pageLen - 1) {
if (curPages[pageLen - delta - 1].route === route) {
this.hideLoad();
uni.navigateBack({
delta: delta,
complete: () => {
if (callback) {
callback();
}
},
});
break;
}
delta++;
}
}
// 记录verifyOrderId,用于校验
recordVerifyOrderId(verifyOrderId) {
this.verifyOrderId = verifyOrderId;
}
// 健康卡信息转患者信息
transferInfoByHealthCard(healthCardInfo) {
try {
const {
name,
birthday,
idType,
idNumber,
gender,
address,
healthCardId,
patid,
phone1,
nation,
relation,
relationship,
isSelf,
} = healthCardInfo;
const genderInfo = genderEnum.find(it => it.name === gender);
let addressObj = null,
provinceInfo,
cityInfo,
districtInfo;
// 验证地址是否符合要求
const verifyResult = this.verifyAddress(address);
if (verifyResult) {
addressObj = JSON.parse(address);
provinceInfo = addressObj.city[0];
cityInfo = addressObj.city[1];
districtInfo = addressObj.city[2];
}
const _birthday =
birthday || idNumber.substr(6, 8).replace(/(.{4})(.{2})/, '$1-$2-');
const _sex = parseInt(idNumber.substr(16, 1)) % 2 == 1 ? 1 : 2;
return {
name,
birthday: new Date(_birthday).getTime(),
certType: Number(idType),
certId: idNumber,
sex: genderInfo ? genderInfo.value : _sex,
address: addressObj
? {
province: provinceInfo?.text,
provinceCode: provinceInfo?.value,
city: cityInfo?.text,
cityCode: cityInfo?.value,
district: districtInfo?.text,
districtCode: districtInfo?.value,
address: addressObj.address,
}
: null,
nationality: '中国',
nationalityCode: 'ZG',
healthCardId,
patid,
phone: phone1,
nation: nation || '汉族',
relation: relation || relationship || isSelf ? '0' : '',
};
} catch (err) {
this.toast('健康卡数据异常,请解绑后重新添加');
throw new Error('健康卡数据异常,请解绑后重新添加');
}
}
// 患者信息转健康卡信息
transferInfoByPatientInfo(patientInfo) {
const {
name,
birthday,
certType,
certId,
sex,
phone,
currentAddress,
relation,
} = patientInfo;
let city = [];
let address = '';
if (currentAddress && currentAddress.province) {
city = [
{ text: currentAddress.province, value: currentAddress.provinceCode },
{ text: currentAddress.city, value: currentAddress.cityCode },
{ text: currentAddress.district, value: currentAddress.districtCode },
];
address = currentAddress.address;
} else {
// 默认地址
city = [
{ text: '四川省', value: '510000' },
{ text: '泸州市', value: '510500' },
{ text: '江阳区', value: '510502' },
];
}
return {
...patientInfo,
name,
birthday: dayjs(new Date(birthday)).format('YYYY-MM-DD'),
idType: certType >= 10 ? String(certType) : '0' + String(certType),
idNumber: certId,
gender: sex,
phone,
city,
address,
relation,
};
}
// 用卡证件 10 就诊卡、11 电子健康卡
getCardType(healthCardId) {
return healthCardId ? '11' : '10';
}
// 根据名称匹配上报场景
getScene(title) {
const scene = {
change_patient: '0101087', // 基本信息
unbind: '01010871', // 解绑
medical_record: '010108', // 就医记录,
check_report: '0101081', // 检查报告
inspection_report: '0101082', // 检验报告
digital_image: '02010913', // 数字影像
queuing_up: '0101021', // 排队叫号
pay: '010105', // 缴费
outpatient_pay: '0101051', // 门诊缴费
outpatient_record: '0101052', // 门诊记录
appointment_register: '0101011', // 预约挂号
today_register: '0101012', // 当日挂号
};
return scene[title];
}
// 数据上报
eventData(param) {
return new Promise(resolve => {
_log('reportHisData 参数】', param);
const { scene, qrCodeText, department } = param;
if (!qrCodeText) {
resolve();
return;
}
const params = {
qrCodeText,
scene,
cardType: '11',
cardChannel: '0402',
time: dayjs().format('YYYY-MM-DD'),
};
if (department) {
params.department = department;
params.cardCostTypes = '0100';
}
reportHisData(params)
.then(res => {
_log('reportHisData 结果】', res);
resolve(res);
})
.catch(err => {
_log('reportHisData 结果】', err);
resolve();
});
});
}
/**
* 手机号脱敏处理
* @param {string} phone - 手机号字符串
* @returns {string} 脱敏后的手机号
*/
maskPhone(phone) {
if (!phone) return '--';
// 去除非数字字符
const cleanPhone = phone.replace(/\D/g, '');
// 验证是否为11位数字
if (!/^\d{11}$/.test(cleanPhone)) {
return phone; // 非标准手机号不做处理
}
// 格式化:(中间4位用*替换)
return cleanPhone.replace(/(\d{3})(\d{4})(\d{4})/, '$1****$3');
}
/**
* 身份证号脱敏处理
* @param {string} idCard - 身份证号字符串
* @returns {string} 脱敏后的身份证号
*/
maskIdCard(idCard) {
if (!idCard) return '--';
// 去除非数字和字母字符(支持15位和18位身份证号)
const cleanIdCard = idCard.replace(/[^\dXx]/g, '').toUpperCase();
// 验证15位或18位身份证号
const isValid15 = /^\d{15}$/.test(cleanIdCard);
const isValid18 = /^\d{17}[\dX]$/.test(cleanIdCard);
if (!isValid15 && !isValid18) {
return idCard; // 非标准身份证号不做处理
}
// 格式化:中间10位用*替换
if (isValid15) {
return cleanIdCard.replace(/(\d{1})(\d{10})(\d{4})/, '$1**********$3');
} else {
return cleanIdCard.replace(
/^(\d{4})(\d{10})(\d{3}[\dX])$/,
'$1**********$3',
);
}
}
// 验证地址是否正确
verifyAddress(address) {
if (!address) return false;
try {
const obj = JSON.parse(address);
// 验证数据结构
if (obj.city && obj.address) {
return true;
} else {
return false;
}
} catch (error) {
// 数据格式不正确
return false;
}
}
}
export default new HealthCardUtil();
电子健康卡业务逻辑相关代码
import { Emitter } from '@/utils/Emitter';
import {
registerHealthCardPreAuth,
registerHealthCardPreFill,
healthCardByHealthCode,
getRegInfoByCode,
getOrderInfoByOrderId,
registerRealPersonAuthOrder,
registerUniformVerifyOrder,
checkUniformVerifyResult,
getDynamicQrCode,
} from '@/apis/healthCard';
import { addHealthCard, updateHealthCard } from '@/apis/patient';
import healthCardUtil from '@/utils/healthCard/index';
import { cloneDeep } from 'lodash-es';
const plugin = requirePlugin('healthCardPlugins');
/* 绑卡回调地址 */
const BindSuccessRedirectUrl =
'mini:/patientPages/healthCard/redirectUrl/index?healthCode=${healthCode}';
const BindFailRedirectUrl =
'mini:/patientPages/healthCard/redirectUrl/index?regInfoCode=${regInfoCode}';
const BindUserFormPageUrl =
'mini:/patientPages/healthCard/useFrom/index?authCode=${authCode}';
// 人脸识别
const FaceRedirectUrl = '/patientPages/healthCard/faceUrl/index';
const VerifySuccessRedirectUrl =
'mini:/patientPages/healthCard/verifyUrl/index?registerOrderId=${registerOrderId}';
// 验证失败
const VerifyFailRedirectUrl = 'mini:/patientPages/healthCard/failUrl/index';
// 腾讯电子健康卡
class ElectronicHealthCard {
// 授权
authEmitter;
// 微信用户唯一标识,需通过uni.login获取
wechatCode = '';
// 建档地址
createURL = '';
// 升级地址
updateURL = '';
// 绑定验证地址
bindVerifyURL = '';
// 查询验证地址
searchVerifyURL = '';
// 结果
healthCode = '';
regInfoCode = '';
// 记录健康卡信息
healthCardInfo = {};
constructor() {
this.authEmitter = new Emitter();
}
loadWechatCode() {
return new Promise((resolve, reject) => {
plugin.login(
(isok, res) => {
healthCardUtil.log('【loadWechatCode 结果】 ', isok, res.result);
if (!isok && res.result.toLogin) {
reject(res);
} else {
// 用户在微信授权过,可直接获取登录信息,处理后续业务
resolve(res.result.wechatCode);
}
},
{
wechatCode: true,
// healthCode: true,
// ecardNo: '',
},
);
});
}
// 获取建档地址
beforeCreateCard({ wechatCode }) {
return new Promise((resolve, reject) => {
healthCardUtil.log('【beforeCreateCard】');
if (!wechatCode) {
healthCardUtil.toast('wechatCode 不存在');
return reject(new Error('wechatCode 不存在'));
}
// 入参
const params = {
wechatCode,
patientType: 0,
successRedirectUrl: BindSuccessRedirectUrl,
failRedirectUrl: BindFailRedirectUrl,
userFormPageUrl: BindUserFormPageUrl,
verifyFailRedirectUrl: VerifyFailRedirectUrl,
faceUrl: FaceRedirectUrl,
};
healthCardUtil.log('【registerHealthCardPreAuth 参数】', params);
registerHealthCardPreAuth(params)
.then(res => {
healthCardUtil.log('【registerHealthCardPreAuth 结果】', res);
if (res.data) {
this.createURL = res.data;
resolve && resolve(this.createURL);
} else {
healthCardUtil.toast('地址不存在');
reject(new Error('地址不存在'));
}
})
.catch(err => {
healthCardUtil.log('【registerHealthCardPreAuth 结果】', err);
reject(err);
});
});
}
// 获取升级地址
beforeUpdateCard({ wechatCode, patientId }) {
return new Promise((resolve, reject) => {
healthCardUtil.log('【beforeUpdateCard】');
if (!wechatCode) {
healthCardUtil.toast('wechatCode 不能为空');
return reject(new Error(`wechatCode 不能为空`));
}
if (!patientId) {
healthCardUtil.toast('patientId 不能为空');
return reject(new Error(`patientId 不能为空`));
}
// 入参
const params = {
wechatCode,
patientType: 1, // 老患者升级
successRedirectUrl: this.generatePatientURL(
BindSuccessRedirectUrl,
patientId,
),
failRedirectUrl: this.generatePatientURL(
BindFailRedirectUrl,
patientId,
),
userFormPageUrl: this.generatePatientURL(
BindUserFormPageUrl,
patientId,
),
verifyFailRedirectUrl: this.generatePatientURL(
VerifyFailRedirectUrl,
patientId,
),
faceUrl: this.generatePatientURL(FaceRedirectUrl, patientId),
};
healthCardUtil.log('【registerHealthCardPreAuth 参数】', params);
registerHealthCardPreAuth(params)
.then(res => {
healthCardUtil.log('【registerHealthCardPreAuth 结果】', res);
this.updateURL = res.data;
resolve(this.updateURL);
})
.catch(err => {
healthCardUtil.log('【registerHealthCardPreAuth 结果】', err);
reject(err);
});
});
}
// 填写建档信息
createCard({ param, authCode, code, patientId }) {
return new Promise((resolve, reject) => {
healthCardUtil.log('【createCard】');
// param 对应的参数请参考:https://open.tengmed.com/openAccess/docs/develop#113
const params = {
code,
businessDataBody: {
...param,
authCode,
successRedirectUrl: this.generatePatientURL(
BindSuccessRedirectUrl,
patientId,
),
failRedirectUrl: this.generatePatientURL(
BindFailRedirectUrl,
patientId,
),
verifyFailRedirectUrl: this.generatePatientURL(
VerifyFailRedirectUrl,
patientId,
),
faceUrl: this.generatePatientURL(FaceRedirectUrl, patientId),
},
};
healthCardUtil.log('【registerHealthCardPreFill 参数】', params);
registerHealthCardPreFill(params)
.then(res => {
healthCardUtil.log('【registerHealthCardPreFill 结果】', res);
this.bindVerifyURL = res.data;
resolve(this.bindVerifyURL);
})
.catch(err => {
healthCardUtil.log('【registerHealthCardPreFill 结果】', err);
reject(err);
});
});
}
// 获取验证地址
beforeGenerateOrderIdVerify(param) {
return new Promise((resolve, reject) => {
healthCardUtil.log('registerUniformVerifyOrder 参数】', param);
const params = {
...param,
verifySuccessRedirectUrl: VerifySuccessRedirectUrl,
verifyFailRedirectUrl: VerifyFailRedirectUrl,
faceUrl: FaceRedirectUrl,
};
registerUniformVerifyOrder(params)
.then(res => {
healthCardUtil.log('registerUniformVerifyOrder 结果】', res);
resolve(res);
})
.catch(err => {
healthCardUtil.log('registerUniformVerifyOrder 结果】', err);
reject(err);
});
});
}
checkVerify({ verifyOrderId, registerOrderId }) {
return new Promise((resolve, reject) => {
healthCardUtil.log('checkUniformVerifyResult 参数】', param);
const param = {
verifyOrderId,
verifyResult: registerOrderId,
};
checkUniformVerifyResult(param)
.then(res => {
healthCardUtil.log('checkUniformVerifyResult 结果】', res);
const { suc } = res.data;
if (suc) {
healthCardUtil.toast('验证成功');
resolve(suc);
} else {
healthCardUtil.toast('验证失败');
reject(new Error('验证失败'));
}
})
.catch(err => {
healthCardUtil.log('checkUniformVerifyResult 结果】', err);
healthCardUtil.toast('验证失败');
reject(err);
});
});
}
setHealthCode(healthCode) {
this.healthCode = healthCode;
}
clearHealthCode() {
this.healthCode = null;
}
setRegInfoCode(regInfoCode) {
this.regInfoCode = regInfoCode;
}
clearRegInfoCode() {
this.regInfoCode = null;
}
hasResult() {
return this.healthCode || this.regInfoCode;
}
// 通过healthCode获取健康卡信息
getInfoByHealthCode() {
return new Promise((resolve, reject) => {
if (!this.healthCode) {
healthCardUtil.toast('healthCode 不存在');
return reject(new Error('healthCode 不存在'));
}
const param = {
healthCode: this.healthCode,
};
healthCardUtil.log('【healthCardByHealthCode 参数】', param);
healthCardByHealthCode(param)
.then(res => {
healthCardUtil.log('【healthCardByHealthCode 结果】', res);
this.clearHealthCode();
resolve(res);
})
.catch(err => {
this.clearHealthCode();
healthCardUtil.log('【healthCardByHealthCode 结果】', err);
reject(err);
});
});
}
// 通过code获取健康卡信息
getInfoByCode() {
return new Promise((resolve, reject) => {
if (!this.regInfoCode) {
healthCardUtil.toast('regInfoCode 不存在');
return reject(new Error('regInfoCode 不存在'));
}
const param = {
code: this.regInfoCode,
};
healthCardUtil.log('getRegInfoByCode 参数】', param);
getRegInfoByCode(param)
.then(res => {
healthCardUtil.log('getRegInfoByCode 结果】', res);
this.clearRegInfoCode();
resolve(res);
})
.catch(err => {
this.clearRegInfoCode();
healthCardUtil.log('getRegInfoByCode 结果】', err);
reject(err);
});
});
}
// 获取健康卡信息
getInfo() {
if (this.healthCode) {
return this.getInfoByHealthCode();
} else if (this.regInfoCode) {
return this.getInfoByCode();
} else {
return new Promise(resolve => {
resolve('');
});
}
}
clearInfoCode() {
this.clearHealthCode();
this.clearRegInfoCode();
}
// 拼接患者id
generatePatientURL(defaultUrl, patientId) {
if (patientId) {
if (defaultUrl.indexOf('?') >= 0) {
return `${defaultUrl}&patientId=${patientId}`;
} else {
return `${defaultUrl}?patientId=${patientId}`;
}
}
return defaultUrl;
}
// 人脸识别-设备检测
checkIsSupportFacialRecognition() {
return new Promise(resolve => {
uni.checkIsSupportFacialRecognition({
checkAliveType: 2, // 优先屏幕闪烁,不支持则读数字
success: res => {
console.log(res, '设备检测');
const systemInfo = uni.getSystemInfoSync();
if (systemInfo.platform === 'android') {
const isSupport = res.errCode === 0;
resolve({
support: isSupport,
message: isSupport ? '支持' : '设备不支持',
});
} else {
resolve({
support: true,
message: '支持',
});
}
},
fail: err => {
console.log(err, '设备检测异常');
const { errCode } = err;
const messageEnum = {
10001: '不支持人脸采集:设备没有前置摄像头',
10002: '不支持人脸采集:没有下载到必要模型',
10003: '不支持人脸采集:后台控制不支持',
};
resolve({
support: false,
message: `${messageEnum[errCode] || '检测失败'}`,
details: err,
});
},
complete: () => {},
});
});
}
// 人脸识别
startFacialRecognitionVerify({ name, idCardNumber }) {
return new Promise(resolve => {
uni.startFacialRecognitionVerify({
name,
idCardNumber,
success: resolve,
fail: err => {
const { verifyResult } = err;
resolve({ errCode: -1, verifyResult });
},
});
});
}
// 人脸识别-校验
async verifyFlow({ orderId, verifyType }) {
return new Promise(async (resolve, reject) => {
try {
if (!orderId) {
healthCardUtil.toast('orderId 不能为空');
reject(new Error(`orderId 不能为空`));
return;
}
if (!verifyType) {
healthCardUtil.toast('verifyType 不能为空');
reject(new Error(`verifyType 不能为空`));
return;
}
// 检测设备
const supportResult = await this.checkIsSupportFacialRecognition();
if (!supportResult.support) {
healthCardUtil.toast(supportResult.message);
reject(new Error(supportResult.message));
return;
}
healthCardUtil.log('【getOrderInfoByOrderId 参数】', {
orderId,
verifyType,
});
// 1.获取用户信息
const healthCardInfoRes = await getOrderInfoByOrderId({
orderId,
verifyType,
});
healthCardUtil.log('【getOrderInfoByOrderId 结果】', healthCardInfoRes);
const { name, idCard, cardType } = healthCardInfoRes.data;
// 2.拉起人脸识别
const verifyRes = await this.startFacialRecognitionVerify({
name,
idCardNumber: idCard,
});
healthCardUtil.log('【人脸识别 结果】', verifyRes);
const { errCode } = verifyRes;
// 3.获取wechatCode
const wechatCode = await this.loadWechatCode();
const param = {
orderId,
verifyType,
result: errCode === 0 ? '01' : '-1',
name,
idCard,
cardType,
wechatCode,
};
healthCardUtil.log('【registerRealPersonAuthOrder 参数】', param);
// 4.人脸识别验证结果
const res = await registerRealPersonAuthOrder(param);
healthCardUtil.log('【registerRealPersonAuthOrder 结果】', res);
resolve(res.data);
} catch (err) {
healthCardUtil.log('【verifyFlow 结果】', err);
reject(err);
}
});
}
// 生成二维码
generateQrCode(healthCardInfo) {
return new Promise((resolve, reject) => {
const { idType, idNumber, healthCardId } = healthCardInfo;
const param = {
healthCardId,
idType,
idNumber,
codeType: 1, // 静态
};
healthCardUtil.log('getDynamicQrCode 参数】', param);
getDynamicQrCode(param)
.then(res => {
healthCardUtil.log('getDynamicQrCode 结果】', res);
const { qrCodeImg } = res.data;
if (qrCodeImg) {
resolve(qrCodeImg);
} else {
healthCardUtil.toast('二维码不存在');
reject(new Error('二维码不存在'));
}
})
.catch(err => {
healthCardUtil.log('getDynamicQrCode 结果】', err);
reject(err);
});
});
}
// 新增-根据健康卡建档
createByHealthCard(healthCardInfo) {
return new Promise(async (resolve, reject) => {
try {
const param = healthCardUtil.transferInfoByHealthCard(healthCardInfo);
// 校验地址,未通过去完善
if (!param.address) {
// 记录健康卡信息
this.healthCardInfo = healthCardInfo;
uni.navigateTo({
url: '/patientPages/patient/healthAddress/index',
});
return reject(new Error('地址不存在'));
}
const qrCode = await this.generateQrCode(healthCardInfo);
console.log('【二维码】', qrCode);
const params = {
...param,
type: 1, // 地址类型 1-就诊人现住址2-就诊人户籍住址3-物流配送地址
syncHis: 1,
qrCodeText: qrCode,
};
// 院内建档
console.log('【院内建档 参数】', params);
const resAdd = await addHealthCard(params);
console.log('【院内建档 结果】', resAdd);
resolve(resAdd);
} catch (error) {
reject(error);
}
});
}
// 更新-根据健康卡建档
updateByHealthCard(healthCardInfo, patientId) {
return new Promise(async (resolve, reject) => {
try {
if (!patientId) {
return reject(new Error('patientId 不存在'));
}
const param = healthCardUtil.transferInfoByHealthCard(healthCardInfo);
// 校验地址,未通过去完善
if (!param.address) {
// 记录健康卡信息
this.healthCardInfo = healthCardInfo;
uni.navigateTo({
url: `/patientPages/patient/healthAddress/index?patientId=${patientId}`,
});
return reject(new Error('地址不存在'));
}
const qrCode = await this.generateQrCode(healthCardInfo);
console.log('【二维码】', qrCode);
// 已建档更新
const { relation, phone, nation, address, healthCardId } = param;
// 更新建档
const params = {
platPatientId: patientId,
qrCodeText: qrCode,
nation,
phone,
address,
healthCardId,
type: 1,
syncHis: 1,
};
if (relation) {
params.relation = relation;
}
console.log('【更新建档 参数】', params);
const resUpdate = await updateHealthCard(params);
console.log('【更新建档 结果】', resUpdate);
resolve(resUpdate);
} catch (error) {
reject(error);
}
});
}
// 使用健康卡信息
getHealthCardInfo() {
const healthCardInfo = cloneDeep(this.healthCardInfo);
this.healthCardInfo = null;
return healthCardInfo;
}
}
export default new ElectronicHealthCard();
使用介绍
- 所有场景统一通过
utils/healthCard/index
方法触发
- HealthCardUtil.create: 新增场景
- HealthCardUtil.update: 老患者升级场景
- HealthCardUtil.verify: 查询场景
经过patientPages/healthCard/auth/index
页面授权获取wechatcode
- 所有回调页面统一处理
patientPages/healthCard/webview/index
展示腾讯电子健康卡接口返回的h5页面
<!-- 腾讯电子健康卡 -->
<template>
<web-view :src="pageUrl" />
</template>
<script setup>
import { onLoad } from "@dcloudio/uni-app";
import { ref } from "vue";
import healthCard from "../static/ElectronicHealthCard";
import healthCardUtil from "@/utils/healthCard/index";
import { HEALTH_CARD_TYPE } from "@/utils/healthCard/constant";
const pageUrl = ref("");
onLoad((options) => {
init(options);
});
async function init(options) {
console.log("【options】", options);
const { type, wechatCode } = options;
switch (type) {
// 建档
case HEALTH_CARD_TYPE.CREATE:
handleCreate(wechatCode);
break;
// 升级
case HEALTH_CARD_TYPE.UPDATE:
handleUpdate(wechatCode);
break;
// 绑定验证
case HEALTH_CARD_TYPE.BIND_VERIFY:
handleBind();
break;
// 查询验证
case HEALTH_CARD_TYPE.SEARCH_VERIFY:
handleSearchVerify(wechatCode);
break;
default:
break;
}
}
// 新增
const handleCreate = async (wechatCode) => {
try {
healthCardUtil.showLoad();
await healthCard.beforeCreateCard({ wechatCode });
pageUrl.value = healthCard.createURL;
healthCardUtil.hideLoad();
console.log("【pageUrl】", pageUrl.value);
} catch (err) {
healthCardUtil.hideLoad(1500);
}
};
// 升级
const handleUpdate = async (wechatCode) => {
try {
healthCardUtil.showLoad();
await healthCard.beforeUpdateCard({
wechatCode,
patientId: healthCardUtil.patientId,
});
pageUrl.value = healthCard.updateURL;
healthCardUtil.hideLoad();
console.log("【pageUrl】", pageUrl.value);
} catch (err) {
healthCardUtil.hideLoad(1500);
}
};
// 绑定
const handleBind = () => {
healthCardUtil.showLoad();
pageUrl.value = healthCard.bindVerifyURL;
healthCardUtil.hideLoad();
};
// 校验
const handleSearchVerify = async (wechatCode) => {
try {
healthCardUtil.showLoad();
const { name, idType, idNumber } = healthCardUtil.transferInfoByPatientInfo(
healthCardUtil.patientInfo
);
const { data } = await healthCard.beforeGenerateOrderIdVerify({
wechatCode,
name,
cardType: idType,
idCard: idNumber,
scene: healthCardUtil.scene,
useCardType: healthCardUtil.getCardType(
healthCardUtil.patientInfo.healthCardId
),
});
const { verifyUrl, verifyOrderId } = data;
// 记录校验数据
healthCardUtil.recordVerifyOrderId(verifyOrderId);
pageUrl.value = verifyUrl;
healthCardUtil.hideLoad();
console.log("【pageUrl】", pageUrl.value);
} catch (err) {
healthCardUtil.hideLoad(1500);
}
};
</script>
patientPages/healthCard/useFrom/index
完善信息页面patientPages/healthCard/faceUrl/index
人脸识别页面
<template>
<web-view :src="pageUrl" />
</template>
<script setup>
import { onLoad } from '@dcloudio/uni-app';
import { ref } from 'vue';
import healthCard from '../static/ElectronicHealthCard';
import healthCardUtil from '@/utils/healthCard/index';
const pageUrl = ref('');
const redirectURL = ref('');
onLoad(options => {
init(options);
});
async function init(options) {
try {
console.log('faceUrl【options】', options);
healthCardUtil.showLoad();
const { redirectUrl, orderId, verifyType } = options;
redirectURL.value = redirectUrl;
// 发起微信人脸识别
const verifyOrderId = await healthCard.verifyFlow({
orderId,
verifyType,
});
healthCardUtil.hideLoad();
console.log('faceUrl success', verifyOrderId);
pageUrl.value = `${decodeURIComponent(redirectUrl)}&verify_order_id=${
verifyOrderId || -1
}`;
console.log('pageUrl', pageUrl.value);
} catch (err) {
console.log('faceUrl fail', err);
pageUrl.value = `${decodeURIComponent(
redirectURL.value,
)}&verify_order_id=-1`;
console.log('pageUrl', pageUrl.value);
healthCardUtil.hideLoad(1500);
}
}
</script>
patientPages/healthCard/verifyUrl/index
验证成功页面
<template>
<view></view>
</template>
<script setup>
import { onLoad } from '@dcloudio/uni-app';
import healthCard from '../static/ElectronicHealthCard';
import healthCardUtil from '@/utils/healthCard/index';
onLoad(options => {
init(options);
});
async function init(options) {
console.log('redirectUrl【options】', options);
const { registerOrderId } = options;
if (registerOrderId) {
// 直接验证
uni.setNavigationBarTitle({ title: '授权验证中' });
healthCardUtil.showLoad('授权验证中');
const isVerify = await healthCard.checkVerify({
registerOrderId,
verifyOrderId: healthCardUtil.verifyOrderId,
});
if (isVerify) {
healthCardUtil.verifySuccess();
} else {
healthCardUtil.verifyFail();
}
}
}
</script>
patientPages/healthCard/failUrl/index
验证失败页面
<template>
<view></view>
</template>
<script setup>
import { onLoad } from '@dcloudio/uni-app';
import healthCardUtil from '@/utils/healthCard/index';
onLoad(options => {
init(options);
});
function init() {
healthCardUtil.showLoad('跳转中');
// 返回到起始页
healthCardUtil.goBack();
}
</script>
patientPages/healthCard/redirectUrl/index
结果处理页(中转页面,用于记录流程结束回调的参数,然后去触发互联网医院业务)
<template>
<view></view>
</template>
<script setup>
import { onLoad } from '@dcloudio/uni-app';
import healthCard from '../static/ElectronicHealthCard';
import healthCardUtil from '@/utils/healthCard/index';
onLoad(options => {
init(options);
});
async function init(options) {
console.log('redirectUrl【options】', options);
const { healthCode, regInfoCode } = options;
healthCardUtil.showLoad('跳转中');
// 记录参数
if (healthCode) {
healthCard.setHealthCode(healthCode);
} else if (regInfoCode) {
healthCard.setRegInfoCode(regInfoCode);
}
// 返回到起始页,根据记录的参数进行业务处理
healthCardUtil.goBack();
}
</script>
- 用卡上报场景统一使用
utils/healthCard/index
中的方法
eventData
上报数据getScene
获取(统一定义)上报场景