fix: 需求开发

This commit is contained in:
huxuejian 2026-07-31 16:21:41 +08:00
parent 875eccc803
commit 5e84eae788
9 changed files with 239 additions and 50 deletions

View File

@ -5,10 +5,10 @@ export default function useUser() {
const store = userStore();
const { drugStore, familyProfile, logined, myProfile, patientList, storeId, userInfo } = storeToRefs(store);
const { getAuthCode, getFamilyProfile, getStore, loadPatientList, login, loginout, getProfileData } = store;
const { getAuthCode, getFamilyProfile, getStore, loadPatientList, login, loginout, getProfileData, setTemporaryPatient } = store;
return {
drugStore, familyProfile, logined, myProfile, patientList, storeId, userInfo,
getAuthCode, getFamilyProfile, getStore, loadPatientList, login, loginout, getProfileData
getAuthCode, getFamilyProfile, getStore, loadPatientList, login, loginout, getProfileData, setTemporaryPatient
};
// const { userInfo, logined, maskName, maskMobile, maskCertNo, cards, card, idCardInfo, storeId, drugStore, getFamilyProfile, familyProfile } = storeToRefs(store);
// const { login, loginout, getAuthCode, getStore } = store;

View File

@ -22,7 +22,7 @@
"title": "【开发】支付宝",
"env": {
"UNI_PLATFORM": "mp-alipay",
"API_BASE_URL": "http://192.168.170.62:8080",
"API_BASE_URL": "http://192.168.31.146:8080",
"CORP_ID": "4G7H8J2K9L0M1N3P5Q6R7S8T9U",
"APP_ID": "2021004129669493",
"ORDER_SOURCE": "ALIPAY_MINI",

View File

@ -3,7 +3,8 @@
<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>
<button class="scan-button" :class="{ 'scan-button--elder': elderMode }" :disabled="scanning"
@click="scanInsuranceCode">{{ scanning ? "读取中..." : "扫医保码" }}</button>
</view>
<view class="patient-list">
@ -49,7 +50,7 @@ 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, getHisCustomer } from "@/utils/api";
import { bindHisPatient, getHisCustomer, getScannedCard } from "@/utils/api";
import { set } from "@/utils/cache";
import { toast } from "@/utils/widget";
@ -64,6 +65,7 @@ const {
myProfile,
familyProfile,
getProfileData,
storeId,
patientList: storePatientList,
loadPatientList,
} = useUser();
@ -76,11 +78,14 @@ const titleMap = {
const selectedPatientId = ref("");
const preferredCertNo = ref("");
const feeType = ref("");
const scanning = ref(false);
const patientList = computed(() => {
const list = [...storePatientList.value].sort((a, b) => {
return new Date(a.createTime).getTime() - new Date(b.createTime).getTime();
});
const list = 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;
});
@ -128,6 +133,49 @@ function selectDefaultPatient() {
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 id = typeof scanResult.result === "string" ? scanResult.result.trim() : "";
if (!/^[a-f\d]{24}$/i.test(id)) {
toast("医保二维码无效");
return;
}
const res = await getScannedCard({ id, storeId: storeId.value });
if (!res || !res.success || !res.data) {
toast((res && res.message) || "获取医保信息失败");
return;
}
if (!res.data.Name || !res.data.IDNum || !res.data.CardNum || !res.data.CardIDCode) {
toast("医保信息不完整,请重新读卡");
return;
}
set("current-scanned-card", res.data, 300);
uni.navigateTo({
url: `/pages/member/detail?type=ybQrcode&feeType=${feeType.value}`,
});
} catch (error) {
if (!error || !/cancel/i.test(error.errMsg || error.message || "")) {
toast(error.message || error.errMsg || error || "扫码失败");
}
} finally {
scanning.value = false;
}
}
async function nextStep() {
if (!currentProfile.value) {
toast("请选择就诊人");

View File

@ -56,6 +56,8 @@
</view>
</full-page>
<store-popup :drugStore="drugStore" :visible="visible" :elderMode="elderMode" @confirm="confirmStoreInfo()"
@close="visible = false" />
<confirm-popup title="提示" content="您是否半年内在医院就诊过?" cancelText="否" confirmText="是" :visible="confirmVisible"
@confirm="handleConfirmYes" @cancel="handleConfirmNo" @close="confirmVisible = false" />
</template>
@ -69,6 +71,7 @@ import ybPlugin from "@/utils/insurance-plugin";
import fullPage from "@/components/full-page.vue";
import confirmPopup from "./confirm-popup.vue";
import storePopup from "./store-popup.vue";
const mainMenuList = [
{
@ -106,13 +109,14 @@ const menuList = [
},
];
const { userInfo, logined, login, loginout, getAuthCode } = useUser();
const { userInfo, logined, login, loginout, getAuthCode, drugStore, getStore } = useUser();
const statusBarHeight = ref(20);
const count = ref({ rxUnpay: 0 });
const confirmVisible = ref(false);
const confirmResolve = ref(null);
const confirmReject = ref(null);
const feeType = ref("");
const visible = ref(false)
function goBack() {
uni.navigateBack();
@ -137,14 +141,19 @@ async function handleMainMenuClick(item) {
confirmVisible.value = true;
}
function handleConfirmYes() {
async function handleConfirmYes() {
confirmVisible.value = false;
confirmAuth();
await getStore();
visible.value = true
if (confirmResolve.value) {
confirmResolve.value();
cleanupConfirmPromise();
}
}
function confirmStoreInfo() {
visible.value = false
confirmAuth();
}
function handleConfirmNo() {
confirmVisible.value = false;

View File

@ -9,8 +9,7 @@
<template v-slot:body>
<view class="info-item">
<text class="item-label">姓名</text>
<input v-model="form.name" :maxlength="20" class="item-value" type="text"
placeholder="请输入姓名" />
<input v-model="form.name" :maxlength="20" class="item-value" type="text" placeholder="请输入姓名" />
</view>
<view class="info-item">
<text class="item-label">证件类型</text>
@ -57,15 +56,25 @@
import { computed, ref, watch } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import useUser from '@/hooks/useUser';
import { addHlwPatient, getHlwPatient, updateHlwPatient } from '@/utils/api';
import {
addHisCustomer,
addHlwPatient,
getHisCustomer,
getHlwPatient,
updateHlwPatient,
} from '@/utils/api';
import { get, remove, set } from '@/utils/cache';
import { isChinaId } from '@/utils/validator';
import { toast } from '@/utils/widget';
import reLogin from '@/components/re-login.vue';
const id = ref('');
const type = ref('');
const feeType = ref('');
const loading = ref(false);
const elderMode = ref(false);
const loadedPatientKey = ref('');
const scannedCard = ref(null);
const form = ref({
name: '',
certNo: '',
@ -73,8 +82,9 @@ const form = ref({
address: '',
});
const { userInfo, logined } = useUser();
const { userInfo, logined, setTemporaryPatient } = useUser();
const accountId = computed(() => userInfo.value && userInfo.value.userId ? userInfo.value.userId : '');
const isYbQrcode = computed(() => type.value === 'ybQrcode');
function validateForm() {
if (!form.value.name.trim()) {
@ -122,6 +132,11 @@ async function confirm() {
loading.value = true;
try {
if (isYbQrcode.value) {
await saveYbQrcodePatient();
return;
}
const payload = {
accountId: accountId.value,
name: form.value.name.trim(),
@ -150,6 +165,72 @@ async function confirm() {
}
}
async function saveYbQrcodePatient() {
if (!scannedCard.value) {
toast('医保扫码信息已失效,请重新扫码');
return;
}
const idCard = form.value.certNo.trim();
const res = await addHisCustomer({
idCard,
name: form.value.name.trim(),
mobile: form.value.mobile.trim(),
address: form.value.address.trim(),
mdtrt_cert_type: '03',
mdtrt_cert_no: scannedCard.value.CardNum,
card_sn: scannedCard.value.CardIDCode,
});
const patients = Array.isArray(res && res.list) ? res.list : [];
const hisArchive = patients.find(patient => patient.socialno === idCard) || patients[0] || null;
if (!res || !res.success || !hisArchive) {
toast((res && res.message) || '医保建档失败');
return;
}
hisArchive.socialno = hisArchive.socialno || idCard;
hisArchive.tmbxx = Array.isArray(res.tmbxx) ? res.tmbxx : [];
set('current-his-archive', hisArchive);
setTemporaryPatient({
name: form.value.name.trim(),
certNo: idCard,
mobile: form.value.mobile.trim(),
address: form.value.address.trim(),
});
uni.redirectTo({
url: `/pages/consult/disease-description?socialno=${idCard}&feeType=${feeType.value}`,
});
}
async function loadScannedCard() {
const card = get('current-scanned-card');
remove('current-scanned-card');
if (!card || !card.Name || !card.IDNum) {
toast('医保扫码信息已失效,请重新扫码');
uni.navigateBack();
return;
}
scannedCard.value = card;
form.value.name = card.Name;
form.value.certNo = card.IDNum;
loading.value = true;
try {
const res = await getHisCustomer(card.IDNum);
const patients = Array.isArray(res.list) ? res.list : [];
const patient = patients.find(item => item.socialno === card.IDNum);
if (patient) {
form.value.mobile = patient.tel || patient.mobile || '';
form.value.address = patient.address || '';
}
} catch (error) {
toast(error.message || error || '查询已有档案失败');
}
loading.value = false;
}
async function loadPatient() {
if (!id.value || !accountId.value) return;
const patientKey = `${accountId.value}:${id.value}`;
@ -178,12 +259,20 @@ async function loadPatient() {
onLoad(options => {
id.value = options.id || '';
uni.setNavigationBarTitle({ title: id.value ? '编辑就诊人' : '新增就诊人' });
type.value = options.type || '';
feeType.value = options.feeType || '';
uni.setNavigationBarTitle({
title: isYbQrcode.value ? '医保建档' : (id.value ? '编辑就诊人' : '新增就诊人'),
});
const savedElderMode = uni.getStorageSync('elderMode');
if (savedElderMode !== null && savedElderMode !== undefined) {
elderMode.value = savedElderMode;
}
if (isYbQrcode.value) {
loadScannedCard();
}
});
watch([id, accountId], loadPatient, { immediate: true });

View File

@ -72,8 +72,8 @@ import emptyData from "@/components/empty.vue";
const { elderVarStyle } = useElder();
const PrescriptionType = {
onlineMedicinePurchase: '在线配药', // 线 (线 )
storeMedicinePurchase: '在线复诊'
ZF: '自费处方', // 线 (线 )
YB: '医保处方'
}
const { userInfo } = useUser();
@ -120,7 +120,7 @@ async function getList() {
return {
...i,
time: dayjs(i.createTime).format('YYYY-MM-DD HH:mm'),
typeText: PrescriptionType[i.prescriptionType] || PrescriptionType.ONLINE_CONSULT,
typeText: PrescriptionType[i.feeType] || '',
name: i.name,
sex: i.sex,
age: i.age,

View File

@ -60,7 +60,7 @@
<view class="signatures">
<view class="signature-item" style="width: 33%">
<view>医生
<image v-if="data.doctorSignImg" class="signImage" :src="data.data"></image>
<image v-if="data.doctorSignImg" class="signImage" :src="data.doctorSignImg"></image>
<text v-else>{{ data.doctorName }}</text>
</view>
<view class="stamp">

View File

@ -26,25 +26,34 @@ export default defineStore("userStore", () => {
const userInfo = ref({}); // { avatar, certNo, mobile, userName, userId }
// his档案信息
const patients = ref([]); // 就诊人档案
const patientList = computed(() => patients.value.map(i => {
const { birthday, age, sex } = getInfoFromIdNo({ socialno: i.certNo });
const maskInfo = getMaskInfo({
name: i.name,
socialno: i.certNo,
tel: i.mobile,
});
return {
...i,
...maskInfo,
birthday,
age,
sex,
_id: i.id,
socialno: i.certNo,
tel: i.mobile,
isSelf: i.certNo === userInfo.value.certNo,
}
}))
const temporaryPatient = ref(null);
const patientList = computed(() => {
const source = temporaryPatient.value && temporaryPatient.value.certNo
? [
...patients.value.filter(i => i.certNo !== temporaryPatient.value.certNo),
temporaryPatient.value,
]
: patients.value;
return source.map(i => {
const { birthday, age, sex } = getInfoFromIdNo({ socialno: i.certNo });
const maskInfo = getMaskInfo({
name: i.name,
socialno: i.certNo,
tel: i.mobile,
});
return {
...i,
...maskInfo,
birthday,
age,
sex,
_id: i.id,
socialno: i.certNo,
tel: i.mobile,
isSelf: i.certNo === userInfo.value.certNo,
}
})
})
async function login() {
if (!userInfo.value.certNo) {
@ -100,6 +109,7 @@ export default defineStore("userStore", () => {
logined.value = false;
userInfo.value = {};
patients.value = [];
temporaryPatient.value = null;
uni.removeStorageSync("hasAuthed");
}
@ -224,6 +234,19 @@ export default defineStore("userStore", () => {
}
}
function setTemporaryPatient(patient) {
if (!patient || !patient.certNo) {
temporaryPatient.value = null;
return;
}
temporaryPatient.value = {
id: patient.id || `yb-qrcode-${patient.certNo}`,
createTime: patient.createTime || new Date().toISOString(),
...patient,
isTemporary: true,
};
}
watch(storeId, (n) => {
uni.setStorageSync("storeId", n);
});
@ -234,6 +257,7 @@ export default defineStore("userStore", () => {
storeId,
userInfo,
patients,
temporaryPatient,
launchOptions,
patientList,
@ -241,6 +265,7 @@ export default defineStore("userStore", () => {
getStore,
login,
loginout,
loadPatientList
loadPatientList,
setTemporaryPatient
};
});

View File

@ -31,6 +31,28 @@ export async function getHisCustomer(idCard) {
});
}
export async function getScannedCard({ id, storeId }) {
return await request({
url: "/getYoucanData/hlw",
data: {
type: "getScannedCard",
id,
storeId,
corpId: process.env.CORP_ID,
},
});
}
export async function addHisCustomer(data) {
return await request({
url: "/getYoucanData/hlw",
data: {
type: "addHisCustomer",
...data,
},
});
}
export async function bindHisPatient({
idCard,
name,
@ -38,16 +60,12 @@ export async function bindHisPatient({
address,
psnToken,
}) {
return await request({
url: "/getYoucanData/hlw",
data: {
type: "addHisCustomer",
idCard,
name,
mobile,
address,
psnToken,
},
return await addHisCustomer({
idCard,
name,
mobile,
address,
psnToken,
});
}