224 lines
5.7 KiB
Vue
224 lines
5.7 KiB
Vue
<template>
|
||
<full-page :customScroll="true" pageStyle="background: #f5f5f5;">
|
||
<view class="auth-page">
|
||
<view class="title">医保本人授权</view>
|
||
<view class="description">请核对就诊人信息,并由就诊人本人完成医保授权</view>
|
||
|
||
<view v-if="patient" class="patient-card">
|
||
<view class="info-row">
|
||
<text class="label">姓名</text>
|
||
<text class="value">{{ patient.name || '--' }}</text>
|
||
</view>
|
||
<view class="info-row">
|
||
<text class="label">证件号</text>
|
||
<text class="value">{{ patient.certNo || '--' }}</text>
|
||
</view>
|
||
<view class="info-row">
|
||
<text class="label">年龄</text>
|
||
<text class="value">{{ patient.age === '' ? '--' : `${patient.age}岁` }}</text>
|
||
</view>
|
||
<view class="info-row">
|
||
<text class="label">性别</text>
|
||
<text class="value">{{ patient.sex || '--' }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<view v-else-if="errorMessage" class="state-card state-card--error">
|
||
<view>{{ errorMessage }}</view>
|
||
<view class="retry" @click="loadPatient">重新加载</view>
|
||
</view>
|
||
<view v-else class="state-card">正在加载就诊人信息...</view>
|
||
|
||
<view v-if="completed" class="success-card">
|
||
<view class="success-title">授权成功</view>
|
||
<view>医保建档已完成,请返回原手机继续操作</view>
|
||
</view>
|
||
</view>
|
||
|
||
<template v-if="patient && !completed" #footer>
|
||
<footer-button :text="submitting ? '授权处理中...' : '确认授权'" @onClick="authorize" />
|
||
</template>
|
||
</full-page>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref } from "vue";
|
||
import { onLoad } from "@dcloudio/uni-app";
|
||
import useUser from "@/hooks/useUser";
|
||
import ybPlugin from "@/utils/insurance-plugin";
|
||
import { getSelfAuthPatient, submitSelfAuth } from "@/utils/api";
|
||
import { get, remove, set } from "@/utils/cache";
|
||
import { toast } from "@/utils/widget";
|
||
|
||
import fullPage from "@/components/full-page.vue";
|
||
import footerButton from "@/components/footer-button.vue";
|
||
|
||
const AUTH_ID_PATTERN = /^[a-f\d]{24}$/i;
|
||
|
||
const { getAuthCode, login, logined } = useUser();
|
||
const authId = ref("");
|
||
const patient = ref(null);
|
||
const errorMessage = ref("");
|
||
const submitting = ref(false);
|
||
const completed = ref(false);
|
||
|
||
function parseId(value) {
|
||
const id = typeof value === "string" ? value.trim() : "";
|
||
if (!AUTH_ID_PATTERN.test(id)) return false;
|
||
authId.value = id;
|
||
return true;
|
||
}
|
||
|
||
async function ensureLogin() {
|
||
if (!logined.value) await login();
|
||
if (!logined.value) throw new Error("登录失败,请重新进入授权页面");
|
||
}
|
||
|
||
async function loadPatient(autoAuth = false) {
|
||
errorMessage.value = "";
|
||
patient.value = null;
|
||
if (!authId.value) {
|
||
errorMessage.value = "授权链接无效";
|
||
return;
|
||
}
|
||
try {
|
||
await ensureLogin();
|
||
const { success, data, message } = await getSelfAuthPatient(authId.value);
|
||
if (!success || !data) throw new Error(message || "获取就诊人信息失败");
|
||
patient.value = data;
|
||
completed.value = data.status === "success";
|
||
if (autoAuth) {
|
||
authorize()
|
||
}
|
||
} catch (error) {
|
||
errorMessage.value = error.message || error || "获取就诊人信息失败";
|
||
}
|
||
}
|
||
|
||
async function completeAuthorization(psnToken) {
|
||
if (completed.value || submitting.value) return;
|
||
if (typeof psnToken !== "string" || !psnToken.trim()) {
|
||
toast("获取医保授权信息失败");
|
||
return;
|
||
}
|
||
submitting.value = true;
|
||
try {
|
||
const { success, message } = await submitSelfAuth(authId.value, psnToken.trim());
|
||
if (!success) throw new Error(message || "医保建档失败");
|
||
completed.value = true;
|
||
remove("self-auth-action-id");
|
||
toast("授权并建档成功");
|
||
} catch (error) {
|
||
toast(error.message || error || "医保建档失败");
|
||
} finally {
|
||
submitting.value = false;
|
||
}
|
||
}
|
||
|
||
async function authorize() {
|
||
if (!patient.value || submitting.value || completed.value) return;
|
||
try {
|
||
const authCode = await getAuthCode("nhsamp");
|
||
const psnToken = await ybPlugin.getArchiveToken(authCode);
|
||
if (psnToken) await completeAuthorization(psnToken);
|
||
} catch (error) {
|
||
toast(error.message || error || "获取医保授权失败");
|
||
}
|
||
}
|
||
|
||
onLoad(async (options) => {
|
||
const optionId = options && typeof options.id === "string" ? options.id : "";
|
||
const targetId = optionId || get("self-auth-action-id", "");
|
||
if (!parseId(targetId)) {
|
||
errorMessage.value = "授权链接无效";
|
||
return;
|
||
}
|
||
set("self-auth-action-id", authId.value, 10 * 60);
|
||
ybPlugin.init({
|
||
archiveTokenCallback: () => {
|
||
uni.redirectTo({
|
||
url: `/pages/consult/self-auth/auth-action?id=${optionId}&type=afterAuth`,
|
||
})
|
||
},
|
||
});
|
||
await loadPatient(options.type === 'afterAuth');
|
||
});
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.auth-page {
|
||
padding: 48rpx 30rpx;
|
||
}
|
||
|
||
.title {
|
||
color: #333;
|
||
font-size: 40rpx;
|
||
font-weight: 600;
|
||
text-align: center;
|
||
}
|
||
|
||
.description {
|
||
margin: 20rpx 0 40rpx;
|
||
color: #888;
|
||
font-size: 28rpx;
|
||
text-align: center;
|
||
}
|
||
|
||
.patient-card,
|
||
.state-card,
|
||
.success-card {
|
||
padding: 12rpx 30rpx;
|
||
background: #fff;
|
||
border-radius: 16rpx;
|
||
}
|
||
|
||
.info-row {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
min-height: 92rpx;
|
||
border-bottom: 1rpx solid #eee;
|
||
}
|
||
|
||
.info-row:last-child {
|
||
border-bottom: 0;
|
||
}
|
||
|
||
.label {
|
||
color: #888;
|
||
}
|
||
|
||
.value {
|
||
color: #333;
|
||
}
|
||
|
||
.state-card {
|
||
padding: 50rpx 30rpx;
|
||
color: #888;
|
||
text-align: center;
|
||
}
|
||
|
||
.state-card--error {
|
||
color: #d9534f;
|
||
}
|
||
|
||
.retry {
|
||
margin-top: 28rpx;
|
||
color: #8b6538;
|
||
}
|
||
|
||
.success-card {
|
||
margin-top: 30rpx;
|
||
padding: 40rpx 30rpx;
|
||
color: #666;
|
||
text-align: center;
|
||
}
|
||
|
||
.success-title {
|
||
margin-bottom: 16rpx;
|
||
color: #2e9b58;
|
||
font-size: 36rpx;
|
||
font-weight: 600;
|
||
}
|
||
</style>
|