最新版公众号前端
This commit is contained in:
805
src/views/JiaoFei_detail copy.vue
Normal file
805
src/views/JiaoFei_detail copy.vue
Normal file
@@ -0,0 +1,805 @@
|
||||
<template>
|
||||
<div class="home">
|
||||
<nav-bar url="/Member_wdzd"></nav-bar>
|
||||
<div class="bj"></div>
|
||||
<div class="app-container">
|
||||
<!-- 缴费信息 -->
|
||||
<div class="left-label">
|
||||
<div class="label-color"></div>
|
||||
<div class="label-text">缴费信息</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="cell">
|
||||
<div class="cell_title">缴费金额</div>
|
||||
<div class="cell_value">¥{{ parseFloat(params.BillMoney).toFixed(2) }}</div>
|
||||
</div>
|
||||
<div class="cell">
|
||||
<div class="cell_title">缴费单号</div>
|
||||
<div class="cell_value">{{ params.SerialFlowNo }}</div>
|
||||
</div>
|
||||
<div class="cell">
|
||||
<div class="cell_title">开单时间</div>
|
||||
<div class="cell_value">{{ params.BillTime }}</div>
|
||||
</div>
|
||||
<div class="cell">
|
||||
<div class="cell_title">执行科室</div>
|
||||
<div class="cell_value">{{ params.DoDepartName }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 缴费项目 -->
|
||||
<div class="left-label">
|
||||
<div class="label-color"></div>
|
||||
<div class="label-text">缴费项目</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div v-for="item in payDetail" class="cell">
|
||||
<div class="cell_title">{{ item.COSTNAME }}</div>
|
||||
<div class="cell_value">¥{{ item.AMOUNT }}×{{ item.COSTSUM }} {{ item.UNIT }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 选择支付方式 -->
|
||||
<div class="left-label">
|
||||
<div class="label-color"></div>
|
||||
<div class="label-text">支付方式</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<!-- 微信支付选项 -->
|
||||
<div v-if="provider == 'wxpay'" class="cell">
|
||||
<label class="pay-item-label">
|
||||
<div class="pay_type_list">
|
||||
<div>
|
||||
<img class="medical-insurance-image"
|
||||
src="https://hnwjyy.oss-cn-shanghai.aliyuncs.com/%E5%8C%BB%E4%BF%9D%E6%B7%B7%E5%90%88%E6%94%AF%E4%BB%98%402x.png" />
|
||||
</div>
|
||||
<div>医保支付</div>
|
||||
</div>
|
||||
<input type="radio" name="payType" value="微信医保支付" v-model="radiovalue1" />
|
||||
</label>
|
||||
</div>
|
||||
<div v-if="provider == 'wxpay'" class="cell">
|
||||
<label class="pay-item-label">
|
||||
<div class="pay_type_list">
|
||||
<div>
|
||||
<img class="pay-image"
|
||||
src="https://open.weixin.qq.com/zh_CN/htmledition/res/assets/res-design-download/icon64_appwx_logo.png" />
|
||||
</div>
|
||||
<div>微信支付</div>
|
||||
</div>
|
||||
<input type="radio" name="payType" value="微信支付" v-model="radiovalue1" />
|
||||
</label>
|
||||
</div>
|
||||
<!-- 支付宝支付选项 -->
|
||||
<!-- <div v-if="provider=='alipay'" class="cell">
|
||||
<div class="pay_type_list">
|
||||
<div><img class="pay-image" src="../../static/icon/alipay.svg" /></div>
|
||||
<div>支付宝支付</div>
|
||||
</div>
|
||||
<input type="radio" name="payType" value="支付宝支付" v-model="radiovalue1" />
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
<button class="btn" @click="generateOrder" :disabled="isPaying">
|
||||
{{ isPaying ? '支付处理中...' : '支付' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
preCheck, apiUnifiedOrder,
|
||||
apiopDjcx, apiopLBQuery,
|
||||
apiOpWxQuery, getPayAuthCode,
|
||||
prePay, getAccessToken
|
||||
} from "@/request/api.js";
|
||||
import { Dialog, Toast } from "vant";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
PatientId: '',
|
||||
SerialFlowNo: '',
|
||||
payDetail: [],
|
||||
provider: 'wxpay', // 支付方式 wxpay 或 alipay
|
||||
radiovalue1: '', // 选择的支付方式
|
||||
isPaying: false, // 添加防止重复支付的状态
|
||||
returnUrl: 'https://nxwj.btlsoln.com/nxwj-gzh/#/JiaoFei_detail', // 回调地址
|
||||
params: {
|
||||
FlowNo: '',
|
||||
BillMoney: '',
|
||||
BillTime: '',
|
||||
BillType: '1',
|
||||
DiagnosisCode: '',
|
||||
DiagnosisName: '',
|
||||
DoDepartName: '',
|
||||
DoDepartCode: '',
|
||||
DoctorName: '',
|
||||
SerialFlowNo: '',
|
||||
SerialNo: '',
|
||||
SetDepartName: '',
|
||||
SetDepartCode: '',
|
||||
DoctorCode: '',
|
||||
BillName: '',
|
||||
PatientId: '',
|
||||
},
|
||||
globalData: {// 医保授权相关
|
||||
scene: 0,
|
||||
ghid: '', // 单据id
|
||||
jzrid: '',//病人id,就诊卡Id
|
||||
authCode: '',
|
||||
payAuthCode: '',
|
||||
userCardNo: '',
|
||||
userName: '',
|
||||
cityId: '',
|
||||
hosp_out_trade_no: '',
|
||||
userLongitudeLatitude: {},
|
||||
// 医保授权支付相关
|
||||
orderInfo: {},
|
||||
// 医保支付金额相关
|
||||
ybPayInfo: {},
|
||||
},
|
||||
accessToken: '',
|
||||
};
|
||||
},
|
||||
|
||||
// 修改后的 mounted
|
||||
mounted() {
|
||||
// 优先从路由query获取(授权回调后参数在query中)
|
||||
this.PatientId = this.$route.query.PatientId || this.$route.params.PatientId || sessionStorage.getItem('cachedPatientId') || '';
|
||||
this.SerialFlowNo = this.$route.query.SerialFlowNo || this.$route.params.SerialFlowNo || sessionStorage.getItem('cachedSerialFlowNo') || '';
|
||||
|
||||
// 重新缓存参数(确保后续使用)
|
||||
if (this.PatientId) sessionStorage.setItem('cachedPatientId', this.PatientId);
|
||||
if (this.SerialFlowNo) sessionStorage.setItem('cachedSerialFlowNo', this.SerialFlowNo);
|
||||
|
||||
// 处理授权回调
|
||||
let authCode = this.$route.query.authCode;
|
||||
let retCode = this.$route.query.retCode;
|
||||
if (retCode === '0' && authCode) {
|
||||
this.radiovalue1='微信医保支付';
|
||||
this.getPayAuth(authCode);
|
||||
// 不return,允许后续执行getData()(或在getPayAuth中调用)
|
||||
}
|
||||
|
||||
// 确保数据加载(如果参数存在)
|
||||
if (this.PatientId && this.SerialFlowNo) {
|
||||
this.getData();
|
||||
} else {
|
||||
Toast('订单信息丢失,请重新选择订单');
|
||||
setTimeout(() => this.$router.push('/Member_wdzd'), 1500);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
methods: {
|
||||
getToken() {
|
||||
getAccessToken().then(res => {
|
||||
console.log(res)
|
||||
this.accessToken = res.data.accessToken
|
||||
}).catch(err => {
|
||||
Toast(err.message)
|
||||
})
|
||||
},
|
||||
getData() {
|
||||
let formdata = {
|
||||
PatientId: this.PatientId,
|
||||
QueryType: "0",
|
||||
OrderNo: this.SerialFlowNo,
|
||||
};
|
||||
let queryData = {
|
||||
FlowNo: this.SerialFlowNo,
|
||||
PatientId: this.PatientId,
|
||||
InsuranceType: '0'
|
||||
};
|
||||
|
||||
// 并行执行两个异步请求
|
||||
Promise.all([
|
||||
apiopDjcx(formdata),
|
||||
apiopLBQuery(queryData)
|
||||
]).then(([djcxRes, lbQueryRes]) => {
|
||||
// 处理 apiopDjcx 的响应
|
||||
console.log(djcxRes.data);
|
||||
let jsonObj = this.$x2js.xml2js(djcxRes.data);
|
||||
console.log(jsonObj);
|
||||
let jsonObj2 = jsonObj.Envelope.Body.MOP_OutpBillstoPayQueryResponse.request.request;
|
||||
|
||||
if (jsonObj2.returnresult.returncode === "1") {
|
||||
// 设置参数
|
||||
this.params.BillMoney = jsonObj2.data.BillMoney;
|
||||
this.params.BillName = jsonObj2.data.BillName;
|
||||
this.params.BillTime = jsonObj2.data.BillTime;
|
||||
this.params.BillType = jsonObj2.data.BillType;
|
||||
this.params.DiagnosisCode = jsonObj2.data.DiagnosisCode;
|
||||
this.params.DiagnosisName = jsonObj2.data.DiagnosisName;
|
||||
this.params.DoDepartName = jsonObj2.data.DoDepartName;
|
||||
this.params.DoDepartCode = jsonObj2.data.DoDepartCode;
|
||||
this.params.DoctorName = jsonObj2.data.DoctorName;
|
||||
this.params.DoctorCode = jsonObj2.data.DoctorCode;
|
||||
this.params.FlowNo = jsonObj2.data.FlowNo;
|
||||
this.params.SerialFlowNo = jsonObj2.data.SerialFlowNo;
|
||||
this.params.SerialNo = jsonObj2.data.SerialNo;
|
||||
this.params.SetDepartName = jsonObj2.data.SetDepartName;
|
||||
this.params.SetDepartCode = jsonObj2.data.SetDepartCode;
|
||||
this.params.PatientId = this.PatientId;
|
||||
} else {
|
||||
Toast("获取缴费信息失败");
|
||||
}
|
||||
|
||||
// 处理 apiopLBQuery 的响应
|
||||
console.log(lbQueryRes);
|
||||
let lbJsonObj = this.$x2js.xml2js(lbQueryRes.data);
|
||||
console.log(lbJsonObj);
|
||||
let lbJsonObj2 = this.$x2js.xml2js(
|
||||
lbJsonObj.Envelope.Body.MOP_OutpBillsDetailQueryResponse.MOP_OutpBillsDetailQueryResult
|
||||
);
|
||||
console.log(lbJsonObj2);
|
||||
|
||||
if (Array.isArray(lbJsonObj2.response.data.data_row)) {
|
||||
this.payDetail = lbJsonObj2.response.data.data_row;
|
||||
} else {
|
||||
this.payDetail = lbJsonObj2.response.data;
|
||||
}
|
||||
}).catch(err => {
|
||||
Toast(err.message);
|
||||
});
|
||||
},
|
||||
generateOrder() {
|
||||
// 防止重复点击
|
||||
if (this.isPaying) {
|
||||
return;
|
||||
}
|
||||
if (!this.radiovalue1) {
|
||||
Toast('请选择支付方式');
|
||||
return;
|
||||
}
|
||||
// 设置支付状态为进行中
|
||||
this.isPaying = true;
|
||||
|
||||
// 根据选择的支付方式执行不同逻辑
|
||||
if (this.radiovalue1 === '微信医保支付') {
|
||||
|
||||
//判断单价小数位是否只有2位,不是统一错误
|
||||
console.log(this.payDetail);
|
||||
if (Array.isArray(this.payDetail)) {
|
||||
this.payDetail.forEach(item => {
|
||||
const amountStr = item.AMOUNT.toString();
|
||||
if (amountStr.includes('.')) {
|
||||
const parts = amountStr.split('.');
|
||||
const decimalPart = parts[1];
|
||||
// 检查小数位数是否超过2位且末尾非0
|
||||
if (decimalPart.length > 2 && !decimalPart.endsWith('0')) {
|
||||
Toast("单价有误,暂不支持医保结账,请到门诊缴费");
|
||||
this.isPaying = false;
|
||||
return;
|
||||
}
|
||||
// 如果超过2位但末尾是0,需要进一步检查去除末尾0后是否超过2位
|
||||
if (decimalPart.length > 2) {
|
||||
const trimmedDecimal = decimalPart.replace(/0+$/, ''); // 去除末尾的0
|
||||
if (trimmedDecimal.length > 2) {
|
||||
Toast("单价有误,暂不支持医保结账,请到门诊缴费");
|
||||
this.isPaying = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// console.log("不是数组");
|
||||
const amountStr = this.payDetail.data_row.AMOUNT.toString();
|
||||
if (amountStr.includes('.')) {
|
||||
const parts = amountStr.split('.');
|
||||
const decimalPart = parts[1];
|
||||
// 检查小数位数是否超过2位且末尾非0
|
||||
if (decimalPart.length > 2 && !decimalPart.endsWith('0')) {
|
||||
Toast("单价有误,暂不支持医保结账,请到门诊缴费");
|
||||
this.isPaying = false;
|
||||
return;
|
||||
}
|
||||
// 如果超过2位但末尾是0,需要进一步检查去除末尾0后是否超过2位
|
||||
if (decimalPart.length > 2) {
|
||||
const trimmedDecimal = decimalPart.replace(/0+$/, ''); // 去除末尾的0
|
||||
if (trimmedDecimal.length > 2) {
|
||||
Toast("单价有误,暂不支持医保结账,请到门诊缴费");
|
||||
this.isPaying = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 只有特定患者可以使用医保支付
|
||||
if (this.PatientId == "90131735" || this.PatientId == "90120780") {
|
||||
this.handleMedicalInsurancePay();
|
||||
} else {
|
||||
Toast("如需医保支付,请携带身份证、医保卡等到线下缴费处操作。");
|
||||
this.isPaying = false;
|
||||
return;
|
||||
}
|
||||
} else if (this.radiovalue1 === '微信支付') {
|
||||
this.handleWechatPay();
|
||||
}
|
||||
},
|
||||
handleMedicalInsurancePay() {
|
||||
preCheck().then(res => {
|
||||
if (res.code === 200) {
|
||||
// 生成带参数的returnUrl(关键!)
|
||||
const returnUrlWithParams = `${this.returnUrl}?PatientId=${this.PatientId}&SerialFlowNo=${this.SerialFlowNo}`;
|
||||
const encodedReturnUrl = encodeURIComponent(returnUrlWithParams);
|
||||
|
||||
let authUrl = res.data;
|
||||
if (authUrl.includes('?')) {
|
||||
authUrl += '&redirectUrl=' + encodedReturnUrl;
|
||||
} else {
|
||||
authUrl += '?redirectUrl=' + encodedReturnUrl;
|
||||
}
|
||||
|
||||
window.location.href = authUrl; // 跳转授权页
|
||||
}
|
||||
});
|
||||
},
|
||||
getPayAuth(code) {
|
||||
const loadingToast = Toast.loading({
|
||||
message: '加载中...',
|
||||
forbidClick: true, // 禁止点击背景
|
||||
duration: 0 // 不自动关闭
|
||||
});
|
||||
let params = {
|
||||
// openid: localStorage.getItem("openid"),
|
||||
qrcode: code,
|
||||
}
|
||||
console.log(params);
|
||||
getPayAuthCode(params).then((res) => {
|
||||
console.log("授权流程完毕,授权结果!!!")
|
||||
console.log(res)
|
||||
if (res.code == 200) {
|
||||
// 解析 内层 JSON 字符串
|
||||
let responseData;
|
||||
try {
|
||||
responseData = typeof res.data.json === 'string' ? JSON.parse(res.data.json) : res.data.json;
|
||||
} catch (e) {
|
||||
console.error("JSON解析错误", e);
|
||||
Toast.fail("数据解析异常,请稍后重试");
|
||||
loadingToast.clear(); // 解析错误时关闭加载
|
||||
this.isPaying = false;
|
||||
return;
|
||||
}
|
||||
if (responseData.user_card_no == res.data.IdNo) {
|
||||
|
||||
if (responseData.code === 0) {
|
||||
// Toast.success("获取payAuthNo用户信息成功,正在发起支付");
|
||||
// TODO :发起支付
|
||||
// console.log("用户信息:", responseData);
|
||||
// {
|
||||
// "code": 0,
|
||||
// "message": "success",
|
||||
// "user_name": "张林",
|
||||
// "user_card_no": "370911198701055636",
|
||||
// "pay_auth_no": "AUTH640100202510131615020070042",
|
||||
// "user_longitude_latitude": {
|
||||
// "longitude": "116.993209",
|
||||
// "latitude": "35.978569"
|
||||
// },
|
||||
// "city_id": "640199",
|
||||
// "family_pay_auth_no": null
|
||||
// }
|
||||
this.globalData.payAuthCode = responseData.pay_auth_no
|
||||
this.globalData.userCardNo = responseData.user_card_no
|
||||
this.globalData.userName = responseData.user_name
|
||||
this.globalData.cityId = responseData.city_id
|
||||
this.globalData.userLongitudeLatitude = responseData.user_longitude_latitude
|
||||
this.globalData.ghid = sessionStorage.getItem('cachedSerialFlowNo') || this.SerialFlowNo;
|
||||
this.globalData.jzrid = sessionStorage.getItem('cachedPatientId') || this.PatientId;
|
||||
let YbInfo = {
|
||||
"payAuthNo": responseData.pay_auth_no,
|
||||
"userLongitudeLatitude": responseData.user_longitude_latitude,
|
||||
"userCardNo": responseData.user_card_no,
|
||||
"userName": responseData.user_name,
|
||||
"jlid": "YBJF" + sessionStorage.getItem('cachedSerialFlowNo') || this.SerialFlowNo,
|
||||
"kdsj": this.params.BillTime,
|
||||
"ysje": this.params.BillMoney,
|
||||
"jzrid": sessionStorage.getItem('cachedPatientId') || this.PatientId
|
||||
}
|
||||
sessionStorage.setItem('YbInfo', JSON.stringify(YbInfo));
|
||||
// 授权完毕、开始预结算下单
|
||||
let req = {
|
||||
"userCardNo": this.globalData.userCardNo,
|
||||
"userName": this.globalData.userName,
|
||||
"orderTitle": "门诊缴费",
|
||||
"openid": res.data.openid,
|
||||
"ghid": this.globalData.ghid,
|
||||
"FlowNo":this.params.FlowNo,
|
||||
"payAuthNo": this.globalData.payAuthCode,
|
||||
"jzrid": this.globalData.jzrid,
|
||||
"userLongitudeLatitude": this.globalData.userLongitudeLatitude,
|
||||
"accessToken": res.data.accessToken
|
||||
}
|
||||
|
||||
this.retryPrePayWithDelay(req, 1) // 1次重试
|
||||
.then(res => {
|
||||
console.log(res);
|
||||
if (res.code == 200) {
|
||||
loadingToast.clear();
|
||||
let data = encodeURIComponent(JSON.stringify(res.data));
|
||||
this.$router.push(`/yborder?data=${data}`);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
Toast.fail('支付请求失败');
|
||||
// 错误时也清除loading提示
|
||||
loadingToast.clear();
|
||||
})
|
||||
.finally(() => {
|
||||
this.isPaying = false;
|
||||
// 移除此行,避免重复清除loadingToast
|
||||
});
|
||||
|
||||
} else if (responseData.code < 0) {
|
||||
Toast.fail("系统繁忙,请稍后重试");
|
||||
this.getData();
|
||||
loadingToast.clear(); // 异常时关闭
|
||||
this.isPaying = false;
|
||||
} else if (responseData.code > 0) {
|
||||
Toast.fail(responseData.message);
|
||||
this.radiovalue1 = ''; // 重置支付方式选择
|
||||
this.getData();
|
||||
loadingToast.clear(); // 异常时关闭
|
||||
this.isPaying = false; // 重新启用支付按钮
|
||||
}
|
||||
|
||||
} else {
|
||||
Toast.fail("不是本人医保,不予办理");
|
||||
this.getData();
|
||||
loadingToast.clear(); // 异常时关闭
|
||||
this.isPaying = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
Toast.fail(res.message || "授权失败");
|
||||
this.getData();
|
||||
loadingToast.clear(); // 异常时关闭
|
||||
this.isPaying = false;
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.error("getPayAuthCode error", err);
|
||||
Toast.fail("获取用户信息异常,请稍后重试");
|
||||
this.getData();
|
||||
loadingToast.clear(); // 异常时关闭
|
||||
this.isPaying = false;
|
||||
});
|
||||
|
||||
},
|
||||
retryPrePayWithDelay(requestData, retries) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const doRequest = (attempt) => {
|
||||
prePay(requestData)
|
||||
.then(response => {
|
||||
resolve(response);
|
||||
})
|
||||
.catch(error => {
|
||||
if (attempt < retries) {
|
||||
console.warn(`prePay请求失败,正在进行第${attempt}次重试`);
|
||||
setTimeout(() => doRequest(attempt + 1), 1000); // 1秒后重试
|
||||
} else {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
};
|
||||
doRequest(0);
|
||||
});
|
||||
},
|
||||
// 清除 URL 中的 code
|
||||
clearCodeFromUrl() {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
urlParams.delete('code');
|
||||
const newSearch = urlParams.toString() ? '?' + urlParams.toString() : '';
|
||||
const cleanUrl = window.location.origin + window.location.pathname + window.location.hash.split('?')[0] + newSearch;
|
||||
window.history.replaceState(null, '', cleanUrl);
|
||||
},
|
||||
handleWechatPay() {
|
||||
console.log("this.params", this.params);
|
||||
apiUnifiedOrder(this.params).then((ref) => {
|
||||
if (ref.code === 200) {
|
||||
//调用微信支付
|
||||
try {
|
||||
|
||||
const data = ref.data;
|
||||
|
||||
// 兼容不同字段名
|
||||
let payParams = {
|
||||
appId: data.appid || data.appId,
|
||||
timeStamp: data.timeStamp || data.timestamp,
|
||||
nonceStr: data.nonce_str || data.nonceStr,
|
||||
package: data.package || `prepay_id=${data.prepay_id || data.prepayId}`,
|
||||
signType: 'MD5',
|
||||
paySign: data.paySign
|
||||
};
|
||||
|
||||
console.log('支付参数:', payParams);
|
||||
|
||||
// 查询参数
|
||||
let queryParams = {
|
||||
outTradeNo: data.outTradeNo
|
||||
};
|
||||
console.log('订单号:', queryParams.outTradeNo);
|
||||
|
||||
// 验证必要参数
|
||||
const requiredParams = ['appId', 'timeStamp', 'nonceStr', 'package', 'paySign'];
|
||||
for (let param of requiredParams) {
|
||||
if (!payParams[param]) {
|
||||
Toast(`缺少支付参数: ${param}`);
|
||||
this.loading = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof WeixinJSBridge == "undefined") {
|
||||
Toast("请在微信中打开页面进行支付");
|
||||
this.loading = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// 调起微信支付
|
||||
WeixinJSBridge.invoke('getBrandWCPayRequest', payParams, (res) => {
|
||||
console.log('微信支付返回:', res);
|
||||
console.log("订单号:", queryParams.outTradeNo);
|
||||
|
||||
if (res.err_msg && res.err_msg.indexOf('ok') > -1) {
|
||||
// ✅ 支付成功,启动轮询
|
||||
this.startPaymentPolling(queryParams); // 调用组件方法
|
||||
} else if (res.err_msg && res.err_msg.indexOf('cancel') > -1) {
|
||||
Toast("用户取消支付");
|
||||
} else {
|
||||
Toast("支付失败: " + (res.err_msg || '未知错误'));
|
||||
}
|
||||
|
||||
this.loading = false;
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('支付调用异常:', error);
|
||||
Toast("支付调用失败");
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
}).catch((err) => {
|
||||
Toast("通讯异常,请稍后重试");
|
||||
});
|
||||
},
|
||||
// 独立方法:启动轮询查询支付结果
|
||||
startPaymentPolling(queryParams) {
|
||||
// 防止重复启动
|
||||
if (this.pollTimer) {
|
||||
clearInterval(this.pollTimer);
|
||||
this.pollTimer = null;
|
||||
}
|
||||
|
||||
const toast = Toast.loading({
|
||||
forbidClick: true,
|
||||
message: '正在查询支付结果...',
|
||||
loadingType: 'circular',
|
||||
duration: 0
|
||||
});
|
||||
|
||||
let pollCount = 0;
|
||||
const maxPollCount = 15; // 最多 30 秒(15次 × 2秒)
|
||||
|
||||
this.pollTimer = setInterval(() => {
|
||||
pollCount++;
|
||||
console.log(`第 ${pollCount} 次轮询查询支付状态...`);
|
||||
|
||||
apiOpWxQuery(queryParams)
|
||||
.then((res) => {
|
||||
console.log('查询响应:', res);
|
||||
|
||||
if (res.code === 200) {
|
||||
const data = res.data;
|
||||
const state = data.trade_state;
|
||||
|
||||
if (state === 'SUCCESS') {
|
||||
// ✅ 支付成功
|
||||
clearInterval(this.pollTimer);
|
||||
this.pollTimer = null;
|
||||
toast.clear();
|
||||
Toast.success("支付成功");
|
||||
// 设置支付状态为完成
|
||||
this.isPaying = false;
|
||||
// 清理缓存
|
||||
sessionStorage.removeItem('cachedPatientId');
|
||||
sessionStorage.removeItem('cachedSerialFlowNo');
|
||||
|
||||
// 先跳转再刷新
|
||||
this.$router.replace({ path: "/Member_wdzd" });
|
||||
|
||||
// 确保路由跳转完成后刷新页面
|
||||
this.$nextTick(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
sessionStorage.removeItem("yuyue");
|
||||
} else if (state === 'NOTPAY') {
|
||||
// 继续等待
|
||||
console.log('用户尚未支付');
|
||||
} else {
|
||||
// 其他失败状态
|
||||
clearInterval(this.pollTimer);
|
||||
this.pollTimer = null;
|
||||
toast.clear();
|
||||
Toast.fail("支付失败:" + (data.trade_state_desc || state));
|
||||
}
|
||||
} else {
|
||||
console.warn('查询接口异常:', res);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('查询请求失败:', error);
|
||||
})
|
||||
.finally(() => {
|
||||
if (pollCount >= maxPollCount) {
|
||||
if (this.pollTimer) {
|
||||
clearInterval(this.pollTimer);
|
||||
this.pollTimer = null;
|
||||
}
|
||||
toast.clear();
|
||||
Toast.fail("支付超时,请稍后查看订单状态");
|
||||
}
|
||||
});
|
||||
}, 2000);
|
||||
|
||||
// 总超时兜底(30秒)
|
||||
setTimeout(() => {
|
||||
if (this.pollTimer) {
|
||||
clearInterval(this.pollTimer);
|
||||
this.pollTimer = null;
|
||||
}
|
||||
if (toast) {
|
||||
toast.clear();
|
||||
}
|
||||
}, maxPollCount * 2000);
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped lang="scss">
|
||||
/* 全局样式 */
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Helvetica, sans-serif;
|
||||
background-color: #f5f5f5;
|
||||
color: #333;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.app-container {
|
||||
padding-bottom: 100px;
|
||||
}
|
||||
|
||||
/* 背景层 */
|
||||
.bj {
|
||||
background: #f5f5f5;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
/* 标题样式 */
|
||||
.left-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 15px 15px 10px;
|
||||
font-size: 0.45rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.label-color {
|
||||
width: 4px;
|
||||
height: 16px;
|
||||
background-color: #166bcc;
|
||||
margin-right: 8px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
/* 卡片样式 */
|
||||
.card {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
margin: 0 12px 15px;
|
||||
padding: 12px 15px;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
/* 单元格样式 */
|
||||
.cell {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 12px 0;
|
||||
border-bottom: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
.cell:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.cell_title {
|
||||
font-size: 0.35rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.cell_value {
|
||||
font-size: 0.35rem;
|
||||
color: #333;
|
||||
text-align: right;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 支付方式样式 */
|
||||
.pay_type_list {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 统一图片容器宽度,确保图片和文字都左对齐 */
|
||||
.pay_type_list>div:first-child {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
width: 1.8rem;
|
||||
/* 调整为适应1.2rem图片的容器宽度 */
|
||||
margin-right: 0.3rem;
|
||||
}
|
||||
|
||||
.pay_type_list>div:last-child {
|
||||
font-size: 0.4rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 进一步放大图片(扩大0.5倍,即原来的1.5倍) */
|
||||
.pay-image {
|
||||
width: 0.9rem;
|
||||
height: 0.9rem;
|
||||
}
|
||||
|
||||
.medical-insurance-image {
|
||||
width: 1.2rem;
|
||||
height: 1.2rem;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.pay-item-label {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 按钮样式 */
|
||||
.btn {
|
||||
position: fixed;
|
||||
// bottom: 30px;
|
||||
margin-top: 1rem;
|
||||
left: 5%;
|
||||
width: 90%;
|
||||
height: 1rem;
|
||||
background-color: #166bcc;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
font-size: 0.4rem;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user