388 lines
8.8 KiB
Vue
Raw Normal View History

2026-07-27 11:26:39 +08:00
<template>
<full-page pageStyle="background: #f5f6f7;">
<view v-if="logined" class="container" :class="{ 'container--elder': elderMode }">
<view class="header" :class="{ 'header--elder': elderMode }">
<text class="title" :class="{ 'title--elder': elderMode }">选择就诊人</text>
<button class="scan-button" :class="{ 'scan-button--elder': elderMode }">扫医保码</button>
</view>
<view class="patient-list">
<view v-for="patient in patientList" :key="patient.id" class="patient-card"
:class="{ 'patient-card--elder': elderMode }" @click="toggle(patient.id)">
<view class="patient-info">
<view class="name" :class="{ 'name--elder': elderMode }">
{{ patient.name }}
<text v-if="patient.isSelf" class="self-tag">本人</text>
</view>
<view class="details" :class="{ 'details--elder': elderMode }">
<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="#3375f6"
:size="elderMode ? 34 : 22" />
</view>
<view v-if="!patientList.length" class="empty-text">暂无就诊人</view>
</view>
</view>
<re-login v-else height="80vh" />
<template v-if="logined" #footer>
<view class="footer">
<view class="button-group" :class="{ 'button-group--elder': elderMode }">
<button class="action-button add-button" @click="toAddPatient">+ 新增就诊人</button>
<button class="action-button next-button" @click="nextStep">下一步</button>
</view>
<view class="manage-link" :class="{ 'manage-link--elder': elderMode }" @click="toPatientManagement">
<text>最多添加10位就诊人点击就诊人管理</text>
<uni-icons type="right" color="#8b8b8b" :size="elderMode ? 24 : 16" />
</view>
</view>
</template>
</full-page>
</template>
<script setup>
import { computed, ref, watch } from "vue";
import { onLoad, onShow } from "@dcloudio/uni-app";
import useElder from "@/hooks/useElder";
import useUser from "@/hooks/useUser";
import { bindHisPatient, sm4Encrypt } from "@/utils/api";
import { toast } from "@/utils/widget";
import reLogin from "@/components/re-login.vue";
import ybPlugin from "@/utils/insurance-plugin";
import fullPage from "@/components/full-page.vue";
const { elderMode } = useElder();
const {
logined,
getAuthCode,
myProfile,
familyProfile,
getProfileData,
patientList: storePatientList,
loadPatientList,
} = useUser();
const titleMap = {
YB: "医保处方",
ZF: "自费处方",
};
const selectedPatientId = ref("");
const preferredCertNo = ref("");
const feeType = ref("");
const patientList = computed(() => {
const list = [...storePatientList.value].sort((a, b) => {
return new Date(a.createTime).getTime() - new Date(b.createTime).getTime();
});
return feeType.value === "YB" ? list.filter(patient => patient.isSelf) : list;
});
const currentProfile = computed(() => {
return patientList.value.find(patient => patient.id === selectedPatientId.value);
});
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(logined, value => {
if (value) loadPatientList();
});
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);
const self = patientList.value.find(patient => patient.isSelf);
selectedPatientId.value = (preferred || self || patientList.value[0] || {}).id || "";
}
watch(patientList, selectDefaultPatient, { immediate: true });
async function nextStep() {
if (!currentProfile.value) {
toast("请选择就诊人");
return;
}
if (feeType.value === 'YB' && false) {
// 医保暂只支持支本人, 进行医保授权操作
const self = currentProfile.value.isSelf;
const authCode = await getAuthCode("nhsamp");
let archiveParams = [authCode];
if (!self) {
const encrypted = await getEncryptedPatientInfo(currentProfile.value);
archiveParams = [authCode, encrypted.anotherIdNo, encrypted.anotherName];
}
const psnToken = await ybPlugin.getArchiveToken(...archiveParams);
if (!psnToken) return;
try {
await bindInsurance(
psnToken,
currentProfile.value.certNo,
currentProfile.value.name,
currentProfile.value.mobile,
);
uni.navigateTo({
url: `/pages/consult/disease-description?socialno=${currentProfile.value.certNo}&type=${type.value}&authDrugRecord=${authDrugRecord.value}`,
});
} catch (error) {
toast(error.message || error);
}
}
uni.navigateTo({
url: `/pages/consult/disease-description?socialno=${currentProfile.value.certNo}&feeType=${feeType.value}`,
});
}
async function getEncryptedPatientInfo(patient) {
const res = await sm4Encrypt({ textGroup: [patient.certNo, patient.name] });
if (!res || !res.success || !Array.isArray(res.textGroup) || res.textGroup.length < 2) {
return Promise.reject((res && res.message) || "获取就诊人加密信息失败");
}
return {
anotherIdNo: res.textGroup[0],
anotherName: res.textGroup[1],
};
}
async function bindInsurance(psnToken, idCard, name, mobile) {
const { success, list, 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) {
return Promise.reject(message || "医保建档失败");
}
if (patient.isyb !== "1") {
return Promise.reject("当前用户为非医保用户");
}
if (myProfile.value && myProfile.value.socialno === patient.socialno) {
myProfile.value = getProfileData(patient);
return;
}
const index = familyProfile.value.findIndex(item => item.socialno === patient.socialno);
if (index >= 0) familyProfile.value[index] = getProfileData(patient);
}
function toggle(patientId) {
selectedPatientId.value = patientId;
}
function toAddPatient() {
uni.navigateTo({
url: `/pages/member/detail`,
});
}
function toPatientManagement() {
uni.navigateTo({ url: "/pages/member/list" });
}
</script>
<style lang="scss" scoped>
.container {
min-height: 100%;
box-sizing: border-box;
padding: 0 16rpx 24rpx;
}
.header {
height: 104rpx;
padding: 0 34rpx;
display: flex;
align-items: center;
justify-content: space-between;
}
.title {
font-size: 28rpx;
color: #222;
}
.scan-button {
width: 164rpx;
height: 64rpx;
margin: 0;
padding: 0;
border-radius: 4rpx;
background: #3375f6;
color: #fff;
font-size: 26rpx;
line-height: 64rpx;
}
.scan-button::after,
.action-button::after {
border: none;
}
.patient-list {
background: #eceeef;
}
.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-info {
display: flex;
flex-direction: column;
}
.name {
font-size: 28rpx;
line-height: 40rpx;
color: #333;
}
.self-tag {
color: #116f38;
}
.details {
margin-top: 4rpx;
font-size: 24rpx;
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: 72rpx;
margin: 0;
padding: 0;
border-radius: 4rpx;
font-size: 28rpx;
line-height: 70rpx;
}
.add-button {
width: 244rpx;
border: 2rpx solid #3375f6;
background: #fff;
color: #3375f6;
}
.next-button {
flex: 1;
background: #3375f6;
color: #fff;
}
.manage-link {
min-height: 50rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 23rpx;
color: #8b8b8b;
}
.container--elder {
padding: 0 24rpx 32rpx;
}
.header--elder {
height: 128rpx;
}
.title--elder {
font-size: 38rpx;
}
.scan-button--elder {
width: 196rpx;
height: 80rpx;
font-size: 34rpx;
line-height: 80rpx;
}
.patient-card--elder {
min-height: 156rpx;
padding: 24rpx 40rpx;
}
.name--elder {
font-size: 38rpx;
line-height: 52rpx;
}
.details--elder {
font-size: 32rpx;
line-height: 44rpx;
}
.button-group--elder .action-button {
height: 92rpx;
font-size: 36rpx;
line-height: 90rpx;
}
.manage-link--elder {
min-height: 68rpx;
font-size: 30rpx;
}
</style>