2026-10-22 15:29:55 +08:00

403 lines
9.5 KiB
Vue
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.

<template>
<full-page :pageStyle="`background: ${themeBg};`">
<view class="container">
<view class="header">
<text class="title">选择就诊人</text>
<button class="scan-button rounded-sm" :disabled="scanning" @click="scanInsuranceCode">扫医保码</button>
</view>
<view class="patient-list">
<view v-for="patient in patientList" :key="patient.id" class="patient-card"
:class="{ 'patient-card--selected': selectedPatientId === patient.id }" @click="toggle(patient.id)">
<view class="patient-info">
<view class="name">
{{ patient.name }}
<text v-if="patient.isSelf" class="self-tag">(本人)</text>
</view>
<view class="details">
<text v-if="patient.sex">{{ patient.sex }}</text>
<text v-if="patient.age" class="age">{{ patient.age }}岁</text>
</view>
</view>
<uni-icons v-if="selectedPatientId === patient.id" type="checkbox-filled" :color="themeColor" :size="22" />
</view>
<view v-if="!patientList.length" class="empty-text">暂无就诊人</view>
</view>
</view>
<template #footer>
<view class="footer">
<view class="button-group">
<button class="action-button add-button rounded" @click="toAddPatient">
+新增就诊人
</button>
<button class="action-button next-button rounded" @click="nextStep">下一步</button>
</view>
<view class="manage-link" @click="toPatientManagement">
<text>最多添加10位就诊人,点击就诊人管理</text>
<uni-icons type="right" :color="themeSecondary" :size="16" />
</view>
</view>
</template>
</full-page>
</template>
<script setup>
import { computed, ref, watch } from "vue";
import { onLoad, onShow } from "@dcloudio/uni-app";
import useUser from "@/hooks/useUser";
import { bindHisPatient, createSelfAuthRequest, addHisCustomer } from "@/utils/api";
import { set } from "@/utils/cache";
import { toast } from "@/utils/widget";
import { themeBg, themeColor, themeSecondary } from "@/utils/theme-config";
import ybPlugin from "@/utils/insurance-plugin";
import fullPage from "@/components/full-page.vue";
const {
logined,
getAuthCode,
userInfo,
patientList,
loadPatientList,
} = useUser();
const titleMap = {
YB: "医保处方",
ZF: "自费处方",
};
const selectedPatientId = ref("");
const preferredCertNo = ref("");
const feeType = ref("");
const scanning = ref(false);
const currentProfile = computed(() => {
return patientList.value.find(patient => patient.id === selectedPatientId.value);
});
function scanCode() {
return new Promise((resolve, reject) => {
uni.scanCode({
onlyFromCamera: true,
scanType: ["qrCode"],
success: resolve,
fail: reject,
});
});
}
function selectDefaultPatient() {
const selectedExists = patientList.value.some(patient => patient.id === selectedPatientId.value);
if (selectedExists) return;
const preferred = patientList.value.find(patient => patient.certNo === preferredCertNo.value && preferredCertNo.value);
const self = patientList.value.find(patient => patient.isSelf);
selectedPatientId.value = (preferred || self || patientList.value[0] || {}).id || "";
}
function toAddPatient() {
uni.navigateTo({
url: `/pages/member/detail`,
});
}
function toggle(patientId) {
selectedPatientId.value = patientId;
}
function toPatientManagement() {
uni.navigateTo({ url: "/pages/member/list" });
}
async function bindInsurance(psnToken, idCard, name, mobile) {
const { success, list, tmbxx, message } = await bindHisPatient({ idCard, name, mobile, psnToken });
const patients = Array.isArray(list) ? list : [];
const patient = patients.find(item => item.socialno === idCard) || patients[0] || null;
if (!success || !patient) {
toast(message || "医保建档失败");
return Promise.reject(message || "医保建档失败");
}
if (patient.isyb !== "1") {
toast("医保建档失败");
return Promise.reject("医保建档失败");
}
patient.tmbxx = tmbxx;
return patient;
}
async function getHisArchive(profile) {
const params = {
name: profile.name,
idCard: profile.certNo,
mobile: profile.mobile,
birthday: profile.birthday,
sex: profile.sex,
address: profile.address
}
const { success, list, tmbxx, message } = await addHisCustomer(params);
const patient = Array.isArray(list) ? list[0] : null;
if (!success || !patient) {
toast(message || "获取档案信息失败");
return Promise.reject(message || "获取档案信息失败");
}
patient.tmbxx = tmbxx;
return patient;
}
async function nextStep() {
if (!currentProfile.value) {
toast("请选择就诊人");
return;
}
let hisArchive = null;
if (feeType.value === 'YB') {
if (!currentProfile.value.certNo) {
toast("就诊人未填写证件号,暂不支持医保处方");
return;
}
if (currentProfile.value.isSelf) {
const authCode = await getAuthCode("nhsamp");
const psnToken = await ybPlugin.getArchiveToken(authCode);
if (psnToken) {
hisArchive = await bindInsurance(psnToken, currentProfile.value.certNo, currentProfile.value.name, currentProfile.value.mobile);
} else {
return;
}
} else {
const { success, data, message } = await createSelfAuthRequest(
currentProfile.value.id,
userInfo.value.userId,
);
if (!success || !data || !data.id) {
toast(message || "创建授权请求失败");
return;
}
set("auth-hlw-patient", {
id: currentProfile.value.id,
name: currentProfile.value.name,
certNo: currentProfile.value.certNo,
feeType: feeType.value,
}, 10 * 60);
uni.navigateTo({ url: `/pages/consult/self-auth/auth-qrcode?id=${data.id}` });
return;
}
} else {
hisArchive = await getHisArchive(currentProfile.value);
}
const consultPatientProfile = {
patientId: hisArchive.patientId,
blhno: hisArchive.blhno,
name: hisArchive.name,
mobile: hisArchive.tel,
sex: hisArchive.sex == 1 ? '男' : '女',
age: parseInt(hisArchive.age) > 0 ? parseInt(hisArchive.age) : '',
address: hisArchive.address,
socialno: hisArchive.socialno,
tmbxx: Array.isArray(hisArchive.tmbxx) ? hisArchive.tmbxx : []
}
set("consult-patient-profile", consultPatientProfile);
uni.navigateTo({
url: `/pages/consult/disease-description?feeType=${feeType.value}`,
});
}
async function scanInsuranceCode() {
if (scanning.value) return;
scanning.value = true;
try {
const scanResult = await scanCode();
const content = scanResult && typeof scanResult.result === 'string' ? scanResult.result : '';
const [source, encodedName, IDNum, value1, value2] = content.split('|');
if (!['SC', 'EC'].includes(source) || !encodedName || !IDNum || !value1 || (source === 'SC' && !value2)) {
scanning.value = false;
toast("医保信息不完整,请重新读卡");
return;
}
if (userInfo.value.certNo === IDNum) {
scanning.value = false;
toast("当前操作仅支持非本人医保码");
return;
}
set("current-scanned-card", {
Source: source,
Name: decodeURIComponent(encodedName),
IDNum,
...(source === 'SC'
? { CardNum: value1, CardIDCode: value2 }
: { ECToken: value1 }),
}, 300);
uni.navigateTo({
url: `/pages/member/detail?type=ybQrcode&feeType=${feeType.value}`,
});
} catch (error) {
console.log('eeeee: ', error)
}
scanning.value = false;
}
onLoad(options => {
feeType.value = options.feeType;
preferredCertNo.value = options.socialno || "";
uni.setNavigationBarTitle({
title: titleMap[options.feeType] || "",
});
ybPlugin.init({
archiveTokenCallback: () => {
const certNo = currentProfile.value ? currentProfile.value.certNo : "";
uni.redirectTo({
url: `/pages/consult/index?socialno=${certNo}&feeType=${feeType.value}`,
});
},
});
});
onShow(async () => {
if (logined.value) {
await loadPatientList();
selectDefaultPatient();
}
});
watch(patientList, selectDefaultPatient, { immediate: true });
</script>
<style lang="scss" scoped>
.container {
min-height: 100%;
box-sizing: border-box;
padding: 0 16rpx 24rpx;
}
.header {
height: 104rpx;
padding: 0 34rpx 0 10rpx;
display: flex;
align-items: center;
justify-content: space-between;
}
.title {
font-size: 36rpx;
color: #333;
font-weight: bold;
}
.scan-button {
width: 164rpx;
height: 64rpx;
margin: 0;
padding: 0;
background: #0f9f8d;
color: #fff;
font-size: 26rpx;
line-height: 62rpx;
}
.scan-button::after,
.action-button::after {
border: none;
}
.patient-list {
background: #e8f8f5;
}
.patient-card {
min-height: 118rpx;
box-sizing: border-box;
padding: 18rpx 34rpx;
background: #fff;
display: flex;
align-items: center;
justify-content: space-between;
}
.patient-card+.patient-card {
margin-top: 8rpx;
}
.patient-card--selected {
background: #e8f8f5;
box-shadow: inset 4rpx 0 0 #0f9f8d;
}
.patient-info {
display: flex;
flex-direction: column;
}
.name {
font-size: 32rpx;
line-height: 40rpx;
font-weight: bold;
color: #333;
}
.self-tag {
color: #0f9f8d;
}
.details {
margin-top: 4rpx;
font-size: 28rpx;
line-height: 34rpx;
color: #9a9a9a;
}
.age {
margin-left: 10rpx;
}
.empty-text {
padding: 80rpx 0;
background: #fff;
text-align: center;
font-size: 26rpx;
color: #999;
}
.footer {
padding: 18rpx 24rpx 12rpx;
background: #fff;
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.06);
}
.button-group {
display: flex;
gap: 22rpx;
}
.action-button {
height: 88rpx;
margin: 0;
padding: 0;
font-size: 28rpx;
line-height: 88rpx;
}
.add-button {
width: 244rpx;
border: 2rpx solid #0f9f8d;
background: #fff;
color: #0f9f8d;
}
.next-button {
flex: 1;
background: #0f9f8d;
color: #fff;
}
.manage-link {
padding: 24rpx 0;
display: flex;
align-items: center;
justify-content: center;
font-size: 24rpx;
color: #344743;
}
</style>