Files
cunkebao_v3/Appbuild/pages/index/index.vue
2025-07-31 17:41:43 +08:00

793 lines
22 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 class="container">
<!-- 全屏web-view容器 -->
<web-view :src="currentUrl" :style="webViewStyle" ref="webview" @message="handleMessage" @error="handleError"
@loading="handleLoading">
</web-view>
<!-- 加载状态 -->
<view v-if="loading" class="loading-container">
<view class="loading-spinner"></view>
<text class="loading-text">加载中...</text>
</view>
<!-- 错误状态 -->
<view v-if="error" class="error-container">
<text class="error-text">{{ error }}</text>
<button @click="reloadPage" class="reload-btn">重新加载</button>
<button @click="switchToFallback" class="fallback-btn">使用备用地址</button>
<button @click="clearTimeout" class="clear-btn">清除超时</button>
</view>
<!-- 调试信息仅在调试模式下显示 -->
<view v-if="config.appConfig.debug" class="debug-info">
<text>当前URL: {{ currentUrl }}</text>
<text>加载状态: {{ loading ? '加载中' : '已加载' }}</text>
<text>navBarHeight: {{ navBarHeight }}</text>
</view>
</view>
</template>
<script>
import config from '@/config.js';
export default {
data() {
return {
config: config,
currentUrl: '', // 初始化为空字符串
loading: false,
error: '',
loadingTimer: null,
messageQueue: []
}
},
onLoad() {
this.initApp();
},
onShow() {
this.resumeMessageQueue();
},
onHide() {
console.log('WebView页面隐藏');
},
onUnload() {
this.cleanup();
},
computed: {
navBarHeight() {
return (this.getSafeAreaHeight().navBarHeight || 44) + 'px'
},
webViewStyle() {
const safeArea = this.getSafeAreaHeight();
return {
position: 'absolute',
top: safeArea.navBarHeight + 'px',
left: '0px',
right: '0px',
bottom: '0px',
width: '100%',
height: `calc(100vh - ${safeArea.navBarHeight}px)`,
zIndex: 1
};
}
},
methods: {
// 获取初始URL
getInitialUrl() {
console.log('获取初始URLconfig:', this.config);
if (this.config && this.config.appConfig && this.config.appConfig.useTestPage) {
return this.config.webConfig.testUrl;
}
return this.config.webConfig.mainUrl;
},
// 初始化应用
initApp() {
console.log('UniApp: 开始初始化应用');
// 设置初始URL
this.currentUrl = this.getInitialUrl();
console.log('UniApp: 设置URL:', this.currentUrl);
this.setupLoadingTimeout();
this.initMessageHandler();
// 立即尝试注入桥接代码
console.log('UniApp: 立即注入桥接代码');
this.injectBridgeCode();
},
// 设置加载超时
setupLoadingTimeout() {
// 清除之前的定时器
if (this.loadingTimer) {
clearTimeout(this.loadingTimer);
}
// 检查是否启用超时检测
if (!this.config.appConfig.enableTimeout) {
console.log('超时检测已禁用');
return;
}
if (this.config.appConfig.loadingTimeout > 0) {
console.log('设置加载超时:', this.config.appConfig.loadingTimeout + 'ms');
this.loadingTimer = setTimeout(() => {
if (this.loading) {
console.warn('页面加载超时,当前状态:', this.loading);
this.handleTimeout();
}
}, this.config.appConfig.loadingTimeout);
}
},
// 处理加载超时
handleTimeout() {
console.warn('触发页面加载超时处理');
this.error = '页面加载超时,请检查网络连接';
this.loading = false;
// 清除定时器
if (this.loadingTimer) {
clearTimeout(this.loadingTimer);
this.loadingTimer = null;
}
},
// 初始化消息处理器
initMessageHandler() {
console.log('UniApp: 初始化消息处理器');
// 监听来自web-view的消息
window.addEventListener('message', (event) => {
console.log('UniApp: 收到window.message事件:', event.data);
this.handleIframeMessage(event);
});
},
// 设置WebView桥接
setupWebViewBridge() {
// 向web-view注入通信桥接代码
this.injectBridgeCode();
},
// 注入桥接代码
injectBridgeCode() {
console.log('UniApp: 开始注入桥接代码');
const bridgeCode = `
// UniApp WebView 桥接代码
console.log('开始注入UniApp桥接代码...');
// 检查是否已经存在桥接
if (window.uniAppBridge) {
console.log('UniApp桥接已存在跳过注入');
return;
}
window.uniAppBridge = {
// 发送消息到UniApp
postMessage: function(type, data) {
console.log('UniApp桥接发送消息:', type, data);
window.parent.postMessage({
type: type,
data: data,
timestamp: Date.now()
}, '*');
},
// 获取用户信息
getUserInfo: function() {
console.log('UniApp桥接: 请求用户信息');
this.postMessage('getUserInfo', {});
},
// 获取设备信息
getDeviceInfo: function() {
console.log('UniApp桥接: 请求设备信息');
this.postMessage('getDeviceInfo', {});
},
// 显示Toast
showToast: function(message, duration = 2000) {
console.log('UniApp桥接: 显示Toast', message, duration);
this.postMessage('toast', { message, duration });
},
// 显示Alert
showAlert: function(title, content) {
console.log('UniApp桥接: 显示Alert', title, content);
this.postMessage('alert', { title, content });
},
// 显示Confirm
showConfirm: function(title, content) {
console.log('UniApp桥接: 显示Confirm', title, content);
this.postMessage('confirm', { title, content });
},
// 分享
share: function(data) {
console.log('UniApp桥接: 分享', data);
this.postMessage('share', data);
},
// 支付
payment: function(data) {
console.log('UniApp桥接: 支付', data);
this.postMessage('payment', data);
},
// 页面导航
navigate: function(url) {
console.log('UniApp桥接: 导航', url);
this.postMessage('navigate', { url });
},
// 自定义消息
sendCustomMessage: function(type, data) {
console.log('UniApp桥接: 自定义消息', type, data);
this.postMessage(type, data);
},
// 页面准备就绪
notifyPageReady: function(data) {
console.log('UniApp桥接: 页面准备就绪', data);
this.postMessage('pageReady', data);
}
};
// 监听来自UniApp的消息
window.addEventListener('message', function(event) {
console.log('UniApp桥接收到消息:', event.data);
if (event.data && event.data.type) {
// 触发自定义事件
const customEvent = new CustomEvent('uniAppMessage', {
detail: event.data
});
window.dispatchEvent(customEvent);
}
});
console.log('UniApp桥接代码注入成功');
// 通知UniApp页面已加载完成
window.parent.postMessage({
type: 'pageLoaded',
data: { url: window.location.href },
timestamp: Date.now()
}, '*');
`;
// 立即尝试注入
console.log('UniApp: 立即注入桥接代码');
this.evalJS(bridgeCode);
// 延迟再次注入,确保注入成功
setTimeout(() => {
console.log('UniApp: 延迟500ms后再次注入');
this.evalJS(bridgeCode);
}, 500);
// 再次延迟注入,作为备用方案
setTimeout(() => {
console.log('UniApp: 延迟1000ms后备用注入');
this.evalJS(bridgeCode);
}, 1000);
},
// 执行JavaScript代码
evalJS(code) {
console.log('UniApp: 执行JavaScript代码');
console.log('UniApp: 当前平台:', uni.getSystemInfoSync().platform);
const webview = this.$refs.webview;
console.log('UniApp: webview引用:', webview);
// 检查是否在App环境下
// #ifdef APP-PLUS
if (webview && webview.evalJS) {
try {
webview.evalJS(code);
console.log('UniApp: JavaScript代码执行成功 (App环境)');
} catch (error) {
console.error('UniApp: JavaScript代码执行失败:', error);
}
} else {
console.warn('UniApp: webview或evalJS方法不存在 (App环境)');
// 尝试备用方案
this.tryAlternativeInjection(code);
}
// #endif
// #ifdef MP-WEIXIN || MP-ALIPAY || MP-BAIDU || MP-TOUTIAO
console.log('UniApp: 小程序环境,使用备用注入方案');
this.tryAlternativeInjection(code);
// #endif
// #ifdef H5
console.log('UniApp: H5环境使用备用注入方案');
this.tryAlternativeInjection(code);
// #endif
},
// 备用注入方案
tryAlternativeInjection(code) {
console.log('UniApp: 尝试备用注入方案');
try {
// 方案1: 直接通过postMessage发送代码
window.postMessage({
type: 'injectCode',
data: { code: code },
timestamp: Date.now()
}, '*');
console.log('UniApp: 备用方案1执行成功');
} catch (error) {
console.error('UniApp: 备用方案1失败:', error);
// 方案2: 通过web-view的message事件
try {
const webview = this.$refs.webview;
if (webview && webview.postMessage) {
webview.postMessage({
type: 'injectCode',
data: { code: code }
});
console.log('UniApp: 备用方案2执行成功');
} else {
console.error('UniApp: 备用方案2失败 - webview.postMessage不存在');
}
} catch (error2) {
console.error('UniApp: 备用方案2失败:', error2);
}
}
},
// 处理web-view组件的消息
handleMessage(event) {
console.log('收到web-view消息:', event.detail);
try {
const data = event.detail.data;
if (data && data.type) {
this.processMessage(data);
}
} catch (error) {
console.error('处理消息失败:', error);
}
},
// 处理iframe消息
handleIframeMessage(event) {
console.log('收到iframe消息:', event.data);
try {
if (event.data && event.data.type) {
// 处理页面加载完成消息
if (event.data.type === 'pageLoaded') {
console.log('收到页面加载完成消息:', event.data.data);
// 清除超时定时器
if (this.loadingTimer) {
clearTimeout(this.loadingTimer);
this.loadingTimer = null;
}
// 更新加载状态
this.loading = false;
this.processMessageQueue();
return;
}
this.processMessage(event.data);
}
} catch (error) {
console.error('处理iframe消息失败:', error);
}
},
// 处理消息
processMessage(data) {
console.log('UniApp处理消息:', data.type, data);
switch (data.type) {
case this.config.communication.messageTypes.GET_USER_INFO:
console.log('UniApp: 处理获取用户信息请求');
this.sendUserInfo();
break;
case this.config.communication.messageTypes.GET_DEVICE_INFO:
console.log('UniApp: 处理获取设备信息请求');
this.sendDeviceInfo();
break;
case this.config.communication.messageTypes.NAVIGATE:
console.log('UniApp: 处理导航请求');
this.handleNavigation(data);
break;
case this.config.communication.messageTypes.SHARE:
console.log('UniApp: 处理分享请求');
this.handleShare(data);
break;
case this.config.communication.messageTypes.PAYMENT:
console.log('UniApp: 处理支付请求');
this.handlePayment(data);
break;
case this.config.communication.messageTypes.TOAST:
console.log('UniApp: 处理Toast请求');
this.handleToast(data);
break;
case this.config.communication.messageTypes.ALERT:
console.log('UniApp: 处理Alert请求');
this.handleAlert(data);
break;
case this.config.communication.messageTypes.CONFIRM:
console.log('UniApp: 处理Confirm请求');
this.handleConfirm(data);
break;
case 'pageReady':
console.log('UniApp: 处理页面准备就绪消息');
// 可以在这里处理页面准备就绪的逻辑
break;
default:
console.log('UniApp: 未知消息类型:', data.type);
}
},
// 发送用户信息到iframe
sendUserInfo() {
console.log('UniApp: 发送用户信息');
const userInfo = {
type: 'userInfo',
data: this.config.userConfig.defaultUser
};
this.sendMessageToIframe(userInfo);
},
// 发送设备信息到iframe
sendDeviceInfo() {
console.log('UniApp: 发送设备信息');
const systemInfo = uni.getSystemInfoSync();
const deviceInfo = {
type: 'deviceInfo',
data: {
platform: systemInfo.platform,
model: systemInfo.model,
version: systemInfo.version,
appVersion: this.config.appConfig.version,
appName: this.config.appConfig.appName,
screenWidth: systemInfo.screenWidth,
screenHeight: systemInfo.screenHeight,
statusBarHeight: systemInfo.statusBarHeight
}
};
this.sendMessageToIframe(deviceInfo);
},
// 处理导航
handleNavigation(data) {
if (data.url) {
console.log('导航到:', data.url);
// 可以在这里处理页面跳转逻辑
}
},
// 处理分享
handleShare(data) {
console.log('UniApp: 处理分享请求', data);
uni.share({
provider: 'weixin',
scene: 'WXSceneSession',
type: 0,
href: data.url || this.currentUrl,
title: data.title || this.config.appConfig.appName,
summary: data.summary || '分享内容',
success: (res) => {
console.log('UniApp: 分享成功:', res);
this.sendToIframe('shareResult', { success: true });
},
fail: (err) => {
console.error('UniApp: 分享失败:', err);
this.sendToIframe('shareResult', { success: false, error: err });
}
});
},
// 处理支付
handlePayment(data) {
console.log('UniApp: 处理支付请求', data);
// 这里可以集成具体的支付功能
// 模拟支付成功
setTimeout(() => {
this.sendToIframe('paymentResult', {
success: true,
orderId: data.orderId || 'order123'
});
}, 1000);
},
// 处理Toast
handleToast(data) {
console.log('UniApp: 处理Toast请求', data);
uni.showToast({
title: data.message,
icon: 'none',
duration: data.duration || 2000
});
},
// 处理Alert
handleAlert(data) {
console.log('UniApp: 处理Alert请求', data);
uni.showModal({
title: data.title || '提示',
content: data.content,
showCancel: false
});
},
// 处理Confirm
handleConfirm(data) {
console.log('UniApp: 处理Confirm请求', data);
uni.showModal({
title: data.title || '确认',
content: data.content,
success: (res) => {
console.log('UniApp: Confirm结果:', res);
this.sendToIframe('confirmResult', {
confirmed: res.confirm
});
}
});
},
// 发送消息到iframe
sendMessageToIframe(message) {
this.messageQueue.push(message);
this.processMessageQueue();
},
// 处理消息队列
processMessageQueue() {
console.log('UniApp: 处理消息队列, 队列长度:', this.messageQueue.length, '加载状态:', this.loading);
if (this.messageQueue.length > 0 && !this.loading) {
const message = this.messageQueue.shift();
console.log('UniApp: 发送消息到iframe:', message);
this.evalJS(`
window.postMessage(${JSON.stringify(message)}, '*');
`);
}
},
// 恢复消息队列处理
resumeMessageQueue() {
this.processMessageQueue();
},
// 向iframe发送消息的通用方法
sendToIframe(type, data) {
const message = {
type: type,
data: data,
timestamp: Date.now()
};
this.sendMessageToIframe(message);
},
// 处理加载状态
handleLoading(event) {
console.log('WebView加载状态变化:', event.detail);
const newLoadingState = event.detail.loading;
console.log('加载状态从', this.loading, '变为', newLoadingState);
this.loading = newLoadingState;
if (!this.loading) {
// 页面加载完成
console.log('页面加载完成,清除超时定时器');
if (this.loadingTimer) {
clearTimeout(this.loadingTimer);
this.loadingTimer = null;
}
// 页面加载完成后立即注入桥接代码
this.injectBridgeCode();
this.processMessageQueue();
} else {
// 开始加载,设置超时
console.log('页面开始加载,设置超时检测');
this.setupLoadingTimeout();
}
},
// 处理错误
handleError(event) {
console.error('WebView错误:', event.detail);
this.error = '页面加载失败,请检查网络连接';
this.loading = false;
clearTimeout(this.loadingTimer);
},
// 重新加载页面
reloadPage() {
this.error = '';
this.loading = true;
this.setupLoadingTimeout();
const webview = this.$refs.webview;
if (webview) {
webview.reload();
}
},
// 切换到备用地址
switchToFallback() {
this.currentUrl = this.config.webConfig.fallbackUrl;
this.reloadPage();
},
// 清除超时
clearTimeout() {
console.log('手动清除超时');
if (this.loadingTimer) {
clearTimeout(this.loadingTimer);
this.loadingTimer = null;
}
this.error = '';
this.loading = false;
console.log('超时已清除');
},
// 获取安全区域高度
getSafeAreaHeight() {
try {
const systemInfo = uni.getSystemInfoSync();
console.log('UniApp: 系统信息:', systemInfo);
// 安全区域信息
const safeArea = systemInfo.safeArea || {};
const safeAreaInsets = systemInfo.safeAreaInsets || {};
console.log('UniApp: 安全区域:', safeArea);
console.log('UniApp: 安全区域边距:', safeAreaInsets);
// 状态栏高度
const statusBarHeight = systemInfo.statusBarHeight || 0;
console.log('UniApp: 状态栏高度:', statusBarHeight);
// 计算顶部安全区域高度
let topSafeAreaHeight = statusBarHeight;
// 如果有安全区域边距信息,优先使用它
if (safeAreaInsets.top !== undefined) {
topSafeAreaHeight = safeAreaInsets.top;
console.log('UniApp: 使用safeAreaInsets.top:', topSafeAreaHeight);
} else if (safeArea.top !== undefined) {
topSafeAreaHeight = safeArea.top;
console.log('UniApp: 使用safeArea.top:', topSafeAreaHeight);
} else {
// 根据平台和设备类型计算
topSafeAreaHeight = this.calculatePlatformSafeArea(statusBarHeight, systemInfo);
}
// 返回完整的安全区域信息
const safeAreaInfo = {
top: topSafeAreaHeight,
bottom: safeAreaInsets.bottom || safeArea.bottom || 0,
left: safeAreaInsets.left || safeArea.left || 0,
right: safeAreaInsets.right || safeArea.right || 0,
statusBarHeight: statusBarHeight,
navBarHeight: 44, // 导航栏高度通常是44px
platform: systemInfo.platform,
model: systemInfo.model,
system: systemInfo.system,
screenWidth: systemInfo.screenWidth,
screenHeight: systemInfo.screenHeight
};
return safeAreaInfo;
} catch (error) {
console.error('UniApp: 获取安全区域信息失败:', error);
// 返回默认值
return {
top: 44,
bottom: 0,
left: 0,
right: 0,
statusBarHeight: 44,
navBarHeight: 44,
platform: 'unknown',
model: 'unknown',
system: 'unknown',
screenWidth: 375,
screenHeight: 667
};
}
},
// 根据平台计算安全区域
calculatePlatformSafeArea(statusBarHeight, systemInfo) {
const platform = systemInfo.platform.toLowerCase();
const model = systemInfo.model || '';
const screenHeight = systemInfo.screenHeight;
const screenWidth = systemInfo.screenWidth;
console.log('UniApp: 平台信息:', { platform, model, screenHeight, screenWidth });
// iOS设备
if (platform === 'ios') {
// iPhone X及以后的设备刘海屏
if (screenHeight >= 812 || screenWidth >= 812) {
console.log('UniApp: 检测到iPhone X及以后设备');
return 44; // iPhone X状态栏高度
}
// 传统iPhone设备
else {
console.log('UniApp: 检测到传统iPhone设备');
return statusBarHeight || 20;
}
}
// Android设备
else if (platform === 'android') {
// 高分辨率设备可能是刘海屏
if (screenHeight >= 800 || screenWidth >= 800) {
console.log('UniApp: 检测到高分辨率Android设备');
return Math.max(statusBarHeight, 24); // 至少24px
}
// 传统Android设备
else {
console.log('UniApp: 检测到传统Android设备');
return statusBarHeight || 24;
}
}
// 其他平台
else {
console.log('UniApp: 其他平台设备');
return statusBarHeight || 20;
}
},
// 动态设置web-view高度
setWebViewHeight(height) {
console.log('设置web-view高度:', height);
if (this.$refs.webview) {
// 方法1: 通过style直接设置
this.$refs.webview.$el.style.height = height + 'px';
// 方法2: 通过class设置
this.$refs.webview.$el.className = 'webview custom-height';
// 方法3: 强制重新计算样式
this.$nextTick(() => {
this.$refs.webview.$el.style.setProperty('height', height + 'px', 'important');
});
}
},
// 设置web-view为全屏
setWebViewFullscreen() {
const safeArea = this.getSafeAreaHeight();
const fullHeight = uni.getSystemInfoSync().windowHeight;
console.log('设置web-view全屏高度:', fullHeight);
this.setWebViewHeight(fullHeight);
},
// 设置web-view为部分高度
setWebViewPartialHeight(percentage = 0.8) {
const safeArea = this.getSafeAreaHeight();
const windowHeight = uni.getSystemInfoSync().windowHeight;
const partialHeight = windowHeight * percentage;
console.log('设置web-view部分高度:', partialHeight, '百分比:', percentage);
this.setWebViewHeight(partialHeight);
},
// 清理资源
cleanup() {
if (this.loadingTimer) {
clearTimeout(this.loadingTimer);
}
}
}
}
</script>
<style>
@import url("index.css");
</style>