调整支付

This commit is contained in:
ywyonui 2025-08-05 12:41:14 +08:00
parent 0cdce6446b
commit 50493a570a

View File

@ -13,7 +13,26 @@
</view>
<view class="scrollable-content">
<web-view :src="payUrl"></web-view>
<!-- H5环境下的处理 -->
<view v-if="isH5" class="h5-payment-container">
<view class="payment-info">
<view class="payment-title">支付信息</view>
<view class="payment-url">{{ payUrl }}</view>
</view>
<view class="payment-actions">
<button class="open-payment-btn" @click="openPaymentUrl">打开支付页面</button>
<button class="copy-url-btn" @click="copyPaymentUrl">复制支付链接</button>
</view>
<view class="payment-tips">
<text>提示</text>
<text>1. 点击"打开支付页面"按钮在新窗口打开支付</text>
<text>2. 支付完成后请返回此页面</text>
<text>3. 如无法打开请复制链接到浏览器中打开</text>
</view>
</view>
<!-- 非H5环境使用web-view -->
<web-view v-else :src="payUrl" @error="handleWebViewError" class="payment-webview"></web-view>
</view>
<!-- 底部支付区域 -->
@ -34,6 +53,228 @@ const { getCurXs, initWs, setWsCallback } = useUserStore();
const { getData } = useDataStore();
const payUrl = ref("");
const isH5 = ref(false);
let webViewObserver: any = null;
// H5
const checkPlatform = () => {
// #ifdef H5
isH5.value = true;
// #endif
};
// URL
const openPaymentUrl = () => {
if (payUrl.value) {
//
window.open(payUrl.value, '_blank');
}
};
// URL
const copyPaymentUrl = () => {
if (payUrl.value) {
// #ifdef H5
if (navigator.clipboard) {
navigator.clipboard.writeText(payUrl.value).then(() => {
uni.showToast({
title: '链接已复制',
icon: 'success'
});
}).catch(() => {
//
const textArea = document.createElement('textarea');
textArea.value = payUrl.value;
document.body.appendChild(textArea);
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);
uni.showToast({
title: '链接已复制',
icon: 'success'
});
});
} else {
//
const textArea = document.createElement('textarea');
textArea.value = payUrl.value;
document.body.appendChild(textArea);
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);
uni.showToast({
title: '链接已复制',
icon: 'success'
});
}
// #endif
}
};
// web-view
const handleWebViewError = (e: any) => {
console.error('web-view加载错误:', e);
uni.showModal({
title: '加载失败',
content: '支付页面加载失败,请检查网络连接或联系客服',
showCancel: false
});
};
// z-index
const fixZIndexConflicts = () => {
// #ifdef H5
const iframes = document.querySelectorAll('iframe');
iframes.forEach((iframe) => {
if (iframe.src && iframe.src.includes('payweb')) {
// iframez-index
(iframe as HTMLElement).style.zIndex = '999999';
// iframe
const allElements = document.querySelectorAll('*');
allElements.forEach((element) => {
const computedStyle = window.getComputedStyle(element);
const zIndex = parseInt(computedStyle.zIndex);
if (zIndex >= 999999 && element !== iframe) {
(element as HTMLElement).style.zIndex = '1';
console.log('修复z-index冲突:', element.tagName, element.className);
}
});
}
});
// #endif
};
// web-view
const fixWebViewStyle = () => {
// #ifdef H5
setTimeout(() => {
const iframes = document.querySelectorAll('iframe');
iframes.forEach((iframe) => {
if (iframe.src && iframe.src.includes('payweb')) {
// iframebody
const appElement = document.getElementById('app');
const countdownSection = document.querySelector('.countdown-section');
const paymentFooter = document.querySelector('.payment-footer');
if (appElement && countdownSection && paymentFooter) {
const appRect = appElement.getBoundingClientRect();
const countdownRect = countdownSection.getBoundingClientRect();
const footerRect = paymentFooter.getBoundingClientRect();
//
const safeAreaTop = parseInt(getComputedStyle(document.documentElement).getPropertyValue('--status-bar-height') || '0');
const safeAreaBottom = parseInt(getComputedStyle(document.documentElement).getPropertyValue('--window-bottom') || '0');
// iframe
const top = countdownRect.bottom + safeAreaTop;
const left = appRect.left;
const width = appRect.width;
const height = footerRect.top - countdownRect.bottom - safeAreaBottom;
// iframe
iframe.style.position = 'fixed';
iframe.style.top = `${top}px`;
iframe.style.left = `${left}px`;
iframe.style.width = `${width}px`;
iframe.style.height = `${Math.max(height, 100)}px`; //
iframe.style.border = 'none';
iframe.style.margin = '0';
iframe.style.padding = '0';
iframe.style.zIndex = '999999'; // 使z-index
iframe.style.backgroundColor = '#fff';
iframe.style.pointerEvents = 'auto';
// iframe
iframe.style.zIndex = '999999';
//
const potentialOverlays = document.querySelectorAll('.payment-footer, .countdown-section, .payment-page, [style*="z-index"]');
potentialOverlays.forEach((element) => {
const computedStyle = window.getComputedStyle(element);
const currentZIndex = parseInt(computedStyle.zIndex) || 0;
if (currentZIndex >= 999999) {
(element as HTMLElement).style.zIndex = '1';
console.log('降低元素z-index:', element.tagName, element.className);
}
});
// iframe
iframe.style.display = 'block';
iframe.style.visibility = 'visible';
iframe.style.opacity = '1';
console.log('已修复web-view样式定位到正确区域', {
top, left, width, height,
zIndex: iframe.style.zIndex,
display: iframe.style.display,
visibility: iframe.style.visibility
});
}
}
});
// z-index
fixZIndexConflicts();
}, 100);
// #endif
};
// DOMweb-view
const observeWebView = () => {
// #ifdef H5
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach((node) => {
if (node.nodeType === Node.ELEMENT_NODE) {
const element = node as Element;
if (element.tagName === 'IFRAME') {
setTimeout(() => {
fixWebViewStyle();
}, 50);
}
}
});
}
});
});
observer.observe(document.body, {
childList: true,
subtree: true
});
//
const handleResize = () => {
setTimeout(() => {
fixWebViewStyle();
}, 100);
};
// z-index
const checkZIndexConflicts = () => {
fixZIndexConflicts();
};
// 2z-index
const zIndexInterval = setInterval(checkZIndexConflicts, 2000);
window.addEventListener('resize', handleResize);
window.addEventListener('orientationchange', handleResize);
return {
observer,
cleanup: () => {
observer.disconnect();
window.removeEventListener('resize', handleResize);
window.removeEventListener('orientationchange', handleResize);
clearInterval(zIndexInterval);
}
};
// #endif
};
setWsCallback((type: string, res: any) => {
console.log('收到WebSocket消息:', type, res.data);
// data
@ -109,12 +350,25 @@ const cancelRegistration = () => {
};
onLoad(async (options: any) => {
//
checkPlatform();
if (options.payUrl) {
payUrl.value = decodeURIComponent(options.payUrl);
const res = await jzGetQkExpiredTime({ xsId: getCurXs.id} );
seconds = res.result;
initWs();
startCountdown();
// web-view
if (!isH5.value) {
setTimeout(() => {
fixWebViewStyle();
}, 500);
// DOM
webViewObserver = observeWebView();
}
} else {
uni.showToast({ title: '缺少支付地址', icon: 'none' })
setTimeout(() => {
@ -157,17 +411,41 @@ onBeforeUnmount(() => {
if (timer) {
clearInterval(timer);
}
// DOM
if (webViewObserver) {
if (webViewObserver.cleanup) {
webViewObserver.cleanup();
} else {
webViewObserver.disconnect();
}
}
});
</script>
<style lang="scss" scoped>
.payment-page {
min-height: 100%;
min-height: 100vh;
background-color: #f5f7fa;
display: flex;
flex-direction: column;
height: 100%;
height: 100vh;
overflow: hidden;
position: relative;
//
.countdown-section {
flex-shrink: 0;
}
.scrollable-content {
flex: 1;
min-height: 0;
}
.payment-footer {
flex-shrink: 0;
}
}
//
@ -176,11 +454,126 @@ onBeforeUnmount(() => {
position: relative;
}
// web-view
.payment-webview {
width: 100% !important;
height: 100% !important;
position: relative !important;
border: none !important;
margin: 0 !important;
padding: 0 !important;
z-index: 1;
flex: 1;
min-height: 0;
}
// web-view
.scrollable-content {
flex: 1;
position: relative;
overflow: hidden;
display: flex;
flex-direction: column;
min-height: 0;
// web-view
&:has(.payment-webview) {
.h5-payment-container {
display: none;
}
}
// web-view
.payment-webview {
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
}
}
// H5
.h5-payment-container {
padding: 20px;
background-color: #fff;
margin: 15px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.payment-info {
margin-bottom: 20px;
.payment-title {
font-size: 18px;
font-weight: bold;
color: #333;
margin-bottom: 10px;
}
.payment-url {
font-size: 14px;
color: #666;
word-break: break-all;
background-color: #f5f5f5;
padding: 10px;
border-radius: 4px;
border: 1px solid #ddd;
}
}
.payment-actions {
display: flex;
gap: 10px;
margin-bottom: 20px;
button {
flex: 1;
height: 44px;
border-radius: 22px;
font-size: 16px;
border: none;
cursor: pointer;
&.open-payment-btn {
background-color: #2879ff;
color: #fff;
}
&.copy-url-btn {
background-color: #fff;
color: #333;
border: 1px solid #ddd;
}
}
}
.payment-tips {
background-color: #fff7e6;
border: 1px solid #ffd591;
border-radius: 4px;
padding: 15px;
text {
display: block;
font-size: 14px;
color: #d46b08;
line-height: 1.5;
margin-bottom: 5px;
&:first-child {
font-weight: bold;
margin-bottom: 8px;
}
}
}
.countdown-section {
display: flex;
align-items: center;
padding: 15px;
background-color: #2879ff;
z-index: 1; // iframe
.countdown-icon {
margin-right: 10px;
@ -204,6 +597,82 @@ onBeforeUnmount(() => {
}
}
// H5
.h5-payment-container {
padding: 20px;
background-color: #fff;
margin: 15px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.payment-info {
margin-bottom: 20px;
.payment-title {
font-size: 18px;
font-weight: bold;
color: #333;
margin-bottom: 10px;
}
.payment-url {
font-size: 14px;
color: #666;
word-break: break-all;
background-color: #f5f5f5;
padding: 10px;
border-radius: 4px;
border: 1px solid #ddd;
}
}
.payment-actions {
display: flex;
gap: 10px;
margin-bottom: 20px;
button {
flex: 1;
height: 44px;
border-radius: 22px;
font-size: 16px;
border: none;
cursor: pointer;
&.open-payment-btn {
background-color: #2879ff;
color: #fff;
}
&.copy-url-btn {
background-color: #fff;
color: #333;
border: 1px solid #ddd;
}
}
}
.payment-tips {
background-color: #fff7e6;
border: 1px solid #ffd591;
border-radius: 4px;
padding: 15px;
text {
display: block;
font-size: 14px;
color: #d46b08;
line-height: 1.5;
margin-bottom: 5px;
&:first-child {
font-weight: bold;
margin-bottom: 8px;
}
}
}
.payment-footer {
position: sticky;
bottom: 0;
@ -212,6 +681,7 @@ onBeforeUnmount(() => {
background-color: #fff;
padding: 15px;
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
z-index: 1; // iframe
.total-amount {
display: flex;