Files
xk-doctor-wx/components/proxy-pay-qrcode-modal/proxy-pay-qrcode-modal.vue
李琦 62ffb6fd31 feat: 工作台常用入口可批量编辑,简报改为横幅,列表补下拉刷新
各角色工作台支持批量保存常用入口和业务员看板;AI 简报改成单行横幅避免锁死滑动;仓库/提现/对账等列表统一下拉刷新,并补代付码弹窗。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-18 08:53:16 +08:00

268 lines
6.0 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>
<view>
<!-- 页面级返回拦截:pageGuard 与 show 拆开,关弹窗后先离场再卸,避免锁死页面滑动 -->
<!-- #ifdef MP-WEIXIN -->
<page-container
v-if="pageGuard"
:show="show"
:overlay="false"
@leave="close"
@afterleave="releasePageGuard"
/>
<!-- #endif -->
<u-popup :value="show" mode="center" border-radius="24" :mask-close-able="true" @input="onPopupInput" @close="close">
<view class="ppay">
<view class="ppay__header">
<text class="ppay__title">患者代付码</text>
<text class="ppay__close" @click="close">关闭</text>
</view>
<view class="ppay__body">
<view v-if="loading" class="ppay__loading">
<u-loading mode="circle" size="40"></u-loading>
<text class="ppay__loading-text">代付码生成中...</text>
</view>
<block v-else-if="qrcode">
<!-- 后端返回完整 data:image/png;base64 数据,长按可转发给患者 -->
<image class="ppay__qrcode" :src="qrcode" mode="aspectFit" show-menu-by-longpress></image>
<view class="ppay__meta">
<view class="ppay__meta-row">
<text class="ppay__meta-label">订单号</text>
<text class="ppay__meta-value">{{ orderNo }}</text>
</view>
<view class="ppay__meta-row">
<text class="ppay__meta-label">待支付金额</text>
<text class="ppay__meta-value ppay__meta-value--price">¥{{ totalPayPrice }}</text>
</view>
</view>
<view class="ppay__tip">请让患者用微信「扫一扫」,进入小程序完成支付</view>
</block>
<view v-else class="ppay__error">
<text class="ppay__error-text">{{ errorText || '代付码生成失败' }}</text>
<view class="ppay__retry" @click="load">重试</view>
</view>
</view>
</view>
</u-popup>
</view>
</template>
<script>
/**
* 医生端「患者代付码」弹窗
*
* 用途:本次挂号处方存在待支付订单时,医生出示小程序码给患者扫码代付
* (复用 PC 接诊台同款后端 proxy-pay-qrcode,scene=ppay={orderId},患者端解析链路零改动)。
* 读值:xk-api 形态,拦截器已返回 body → code / result / message(unwrapXkApi)
*/
import { getProxyPayQrcodeApi } from '@/api/reception.js'
import { unwrapXkApi } from '@/utils/api-response.js'
export default {
name: 'ProxyPayQrcodeModal',
props: {
/** v-model 显隐 */
value: { type: Boolean, default: false },
/** 待支付订单ID(处方关联的商品订单) */
orderId: { type: [Number, String], default: 0 },
},
data() {
return {
loading: false,
qrcode: '',
orderNo: '',
totalPayPrice: '',
errorText: '',
pageGuard: false,
releaseTimer: null,
}
},
computed: {
show: {
get() { return this.value },
set(v) { this.$emit('input', v) },
},
},
watch: {
/** 每次打开都重新生成:订单可能已被支付/取消,后端会按最新状态校验 */
value(v) {
if (v) {
this.pageGuard = true
this.load()
} else {
this.scheduleReleaseGuard()
}
},
},
beforeDestroy() {
this.clearReleaseTimer()
},
methods: {
releasePageGuard() {
this.clearReleaseTimer()
this.pageGuard = false
},
scheduleReleaseGuard() {
this.clearReleaseTimer()
this.releaseTimer = setTimeout(() => {
this.pageGuard = false
this.releaseTimer = null
}, 350)
},
clearReleaseTimer() {
if (this.releaseTimer) {
clearTimeout(this.releaseTimer)
this.releaseTimer = null
}
},
close() {
this.show = false
},
onPopupInput(v) {
this.show = v
},
/** 请求代付码(xk-api,取值 code/result/message) */
async load() {
if (!this.orderId) {
this.qrcode = ''
this.errorText = '缺少订单信息'
return
}
this.loading = true
this.qrcode = ''
this.errorText = ''
try {
const res = await getProxyPayQrcodeApi({ order_id: this.orderId })
const { ok, payload, message } = unwrapXkApi(res)
if (ok && payload && payload.qrcode) {
this.qrcode = payload.qrcode
this.orderNo = payload.order_no || ''
this.totalPayPrice = payload.total_pay_price || ''
} else {
this.errorText = message || '代付码生成失败'
}
} catch (e) {
this.errorText = (e && e.message) || '代付码生成失败'
} finally {
this.loading = false
}
},
},
}
</script>
<style lang="scss" scoped>
.ppay {
width: 600rpx;
padding: 32rpx;
box-sizing: border-box;
&__header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 24rpx;
}
&__title {
font-size: 32rpx;
font-weight: bold;
color: #2a2e35;
}
&__close {
font-size: 26rpx;
color: #8a92a3;
padding: 8rpx;
}
&__body {
display: flex;
flex-direction: column;
align-items: center;
}
&__loading {
display: flex;
flex-direction: column;
align-items: center;
padding: 60rpx 0;
}
&__loading-text {
margin-top: 16rpx;
font-size: 26rpx;
color: #8a92a3;
}
&__qrcode {
width: 400rpx;
height: 400rpx;
}
/* 订单信息卡:1px 同色系边框 + 微光(规范禁止左侧竖色条强调) */
&__meta {
width: 100%;
margin-top: 24rpx;
padding: 20rpx 24rpx;
box-sizing: border-box;
border: 1px solid rgba(0, 168, 138, 0.3);
border-radius: 16rpx;
box-shadow: 0 0 6px rgba(0, 168, 138, 0.18);
}
&__meta-row {
display: flex;
align-items: center;
justify-content: space-between;
& + & {
margin-top: 12rpx;
}
}
&__meta-label {
font-size: 26rpx;
color: #8a92a3;
}
&__meta-value {
font-size: 26rpx;
color: #2a2e35;
&--price {
font-size: 30rpx;
font-weight: bold;
color: #fa3534;
}
}
&__tip {
margin-top: 20rpx;
font-size: 24rpx;
color: #8a92a3;
text-align: center;
}
&__error {
display: flex;
flex-direction: column;
align-items: center;
padding: 40rpx 0;
}
&__error-text {
font-size: 26rpx;
color: #fa3534;
}
&__retry {
margin-top: 24rpx;
padding: 12rpx 48rpx;
font-size: 26rpx;
color: #00a88a;
border: 1px solid rgba(0, 168, 138, 0.5);
border-radius: 999rpx;
}
}
</style>