2026-09-04 10:40:02 +08:00

396 lines
9.3 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 v-if="logined" 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>
<re-login v-else height="80vh" />
<template v-if="logined" #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 useElder from "@/hooks/useElder";
import useUser from "@/hooks/useUser";
import { bindHisPatient, createSelfAuthRequest, getHisCustomer, getScannedCard } from "@/utils/api";
import { set } from "@/utils/cache";
import { toast } from "@/utils/widget";
import { themeBg, themeColor, themeSecondary } from "@/utils/theme-config";
import reLogin from "@/components/re-login.vue";
import ybPlugin from "@/utils/insurance-plugin";
import fullPage from "@/components/full-page.vue";
const {
logined,
getAuthCode,
userInfo,
storeId,
patientList: storePatientList,
loadPatientList,
} = useUser();
const titleMap = {
YB: "医保处方",
ZF: "自费处方",
};
const selectedPatientId = ref("");
const preferredCertNo = ref("");
const feeType = ref("");
const scanning = ref(false);
const patientList = computed(() => {
return storePatientList.value
.filter(patient => !patient.isTemporary)
.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 });
function scanCode() {
return new Promise((resolve, reject) => {
uni.scanCode({
onlyFromCamera: true,
scanType: ["qrCode"],
success: resolve,
fail: reject,
});
});
}
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 [Name, IDNum, CardNum, CardIDCode] = content.split('|');
if (!Name || !IDNum || !CardNum || !CardIDCode) {
toast("医保信息不完整,请重新读卡");
return;
}
if (userInfo.value.certNo === IDNum) {
toast("当前操作仅支持非本人医保码");
return;
}
set("current-scanned-card", {
Name: decodeURIComponent(Name),
IDNum,
CardNum,
CardIDCode
}, 300);
uni.navigateTo({
url: `/pages/member/detail?type=ybQrcode&feeType=${feeType.value}`,
});
} catch (error) {
console.log('eeeee: ', error)
}
scanning.value = false;
}
async function nextStep() {
if (!currentProfile.value) {
toast("请选择就诊人");
return;
}
let hisArchive = null;
if (feeType.value === 'YB') {
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.certNo);
}
set("current-his-archive", hisArchive);
uni.navigateTo({
url: `/pages/consult/disease-description?socialno=${currentProfile.value.certNo}&feeType=${feeType.value}`,
});
}
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(idCard) {
const { success, list, tmbxx, message } = await getHisCustomer(idCard);
const patients = Array.isArray(list) ? list : [];
const patient = patients.find(item => item.socialno === idCard);
if (!success || !patient) {
toast(message || "获取档案信息失败");
return Promise.reject(message || "获取档案信息失败");
}
patient.tmbxx = tmbxx;
return 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 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>