diff --git a/Appbuild/pages/index/index.vue b/Appbuild/pages/index/index.vue index ceed4bc1..6be33682 100644 --- a/Appbuild/pages/index/index.vue +++ b/Appbuild/pages/index/index.vue @@ -38,20 +38,30 @@ export default { loading: false, error: '', loadingTimer: null, - messageQueue: [] + messageQueue: [], + // 返回键监听相关 + backButtonListener: null, + backButtonCount: 0, + backButtonTimer: null, + canExit: false, + lastBackTime: 0 } }, onLoad() { this.initApp(); + this.initBackButtonListener(); }, onShow() { this.resumeMessageQueue(); + this.resumeBackButtonListener(); }, onHide() { console.log('WebView页面隐藏'); + this.pauseBackButtonListener(); }, onUnload() { this.cleanup(); + this.removeBackButtonListener(); }, methods: { @@ -214,6 +224,41 @@ export default { notifyPageReady: function(data) { console.log('UniApp桥接: 页面准备就绪', data); this.postMessage('pageReady', data); + }, + + // 处理返回键 + handleBackButton: function(action) { + console.log('UniApp桥接: 处理返回键', action); + + switch(action) { + case 'showExitConfirm': + // 在 web-view 内显示退出确认 + if (confirm('确定要退出应用吗?')) { + this.postMessage('exitApp', {}); + } + break; + case 'exitApp': + // 通知 UniApp 退出应用 + this.postMessage('exitApp', {}); + break; + } + }, + + // 监听返回键事件 + listenBackButton: function() { + // 监听浏览器的后退事件 + window.addEventListener('popstate', (event) => { + console.log('UniApp桥接: 检测到 popstate 事件'); + this.postMessage('backButton', { action: 'popstate' }); + }); + + // 监听键盘事件 + document.addEventListener('keydown', (event) => { + if (event.key === 'Backspace' || event.keyCode === 8) { + console.log('UniApp桥接: 检测到返回键'); + this.postMessage('backButton', { action: 'keydown' }); + } + }); } }; @@ -237,6 +282,9 @@ export default { data: { url: window.location.href }, timestamp: Date.now() }, '*'); + + // 初始化返回键监听 + window.uniAppBridge.listenBackButton(); `; // 立即尝试注入 @@ -403,6 +451,14 @@ export default { console.log('UniApp: 处理页面准备就绪消息'); // 可以在这里处理页面准备就绪的逻辑 break; + case 'backButton': + console.log('UniApp: 处理返回键消息'); + this.handleBackButtonMessage(data); + break; + case 'exitApp': + console.log('UniApp: 处理退出应用消息'); + this.handleExitApp(); + break; default: console.log('UniApp: 未知消息类型:', data.type); } @@ -645,11 +701,211 @@ export default { this.setWebViewHeight(partialHeight); }, + // 初始化返回键监听 + initBackButtonListener() { + console.log('初始化返回键监听'); + + // 方法1: 使用 uni.addInterceptor 拦截返回事件 + // #ifdef APP-PLUS + try { + uni.addInterceptor('navigateBack', { + invoke(e) { + console.log('拦截到返回事件:', e); + return false; // 阻止默认返回行为 + } + }); + } catch (error) { + console.warn('addInterceptor 失败:', error); + } + // #endif + + // 方法2: 监听物理返回键 + this.setupPhysicalBackButton(); + + // 方法3: 监听 web-view 内的返回事件 + this.setupWebViewBackListener(); + }, + + // 设置物理返回键监听 + setupPhysicalBackButton() { + // #ifdef APP-PLUS + try { + // 监听安卓物理返回键 + plus.key.addEventListener('backbutton', (e) => { + console.log('检测到物理返回键事件:', e); + this.handleBackButton(); + }); + } catch (error) { + console.warn('物理返回键监听失败:', error); + } + // #endif + }, + + // 设置 web-view 内返回监听 + setupWebViewBackListener() { + // 监听 web-view 内的 popstate 事件 + window.addEventListener('popstate', (event) => { + console.log('检测到 popstate 事件:', event); + this.handleBackButton(); + }); + + // 监听 web-view 内的 beforeunload 事件 + window.addEventListener('beforeunload', (event) => { + console.log('检测到 beforeunload 事件:', event); + this.handleBackButton(); + }); + }, + + // 处理返回键事件 + handleBackButton() { + const now = Date.now(); + const timeDiff = now - this.lastBackTime; + + console.log('处理返回键事件, 时间差:', timeDiff, 'ms'); + + // 重置计数器 + if (timeDiff > 2000) { + this.backButtonCount = 0; + } + + this.backButtonCount++; + this.lastBackTime = now; + + // 第一次按返回键 + if (this.backButtonCount === 1) { + this.showExitConfirm(); + } + // 第二次按返回键,直接退出 + else if (this.backButtonCount >= 2) { + this.exitApp(); + } + }, + + // 显示退出确认 + showExitConfirm() { + console.log('显示退出确认'); + + // 方法1: 使用 uni.showModal + // #ifdef APP-PLUS + uni.showModal({ + title: '退出确认', + content: '确定要退出应用吗?', + confirmText: '退出', + cancelText: '取消', + success: (res) => { + if (res.confirm) { + this.exitApp(); + } + } + }); + // #endif + + // 方法2: 通过桥接发送消息到 web-view + this.sendBackButtonMessage('showExitConfirm'); + }, + + // 退出应用 + exitApp() { + console.log('退出应用'); + + // 方法1: 使用 plus.runtime.quit + // #ifdef APP-PLUS + try { + plus.runtime.quit(); + } catch (error) { + console.error('退出应用失败:', error); + } + // #endif + + // 方法2: 通过桥接发送退出消息 + this.sendBackButtonMessage('exitApp'); + }, + + // 发送返回键消息到 web-view + sendBackButtonMessage(action) { + if (this.$refs.webview) { + try { + // 通过 postMessage 发送消息 + this.$refs.webview.postMessage({ + type: 'backButton', + action: action, + timestamp: Date.now() + }); + } catch (error) { + console.error('发送返回键消息失败:', error); + } + } + }, + + // 处理返回键消息 + handleBackButtonMessage(data) { + console.log('处理返回键消息:', data); + + switch (data.action) { + case 'popstate': + case 'keydown': + this.handleBackButton(); + break; + default: + console.log('未知的返回键动作:', data.action); + } + }, + + // 处理退出应用 + handleExitApp() { + console.log('处理退出应用'); + + // #ifdef APP-PLUS + try { + plus.runtime.quit(); + } catch (error) { + console.error('退出应用失败:', error); + } + // #endif + }, + + // 恢复返回键监听 + resumeBackButtonListener() { + console.log('恢复返回键监听'); + this.backButtonCount = 0; + this.lastBackTime = 0; + }, + + // 暂停返回键监听 + pauseBackButtonListener() { + console.log('暂停返回键监听'); + this.backButtonCount = 0; + }, + + // 移除返回键监听 + removeBackButtonListener() { + console.log('移除返回键监听'); + + // #ifdef APP-PLUS + try { + // 移除物理返回键监听 + plus.key.removeEventListener('backbutton'); + + // 移除拦截器 + uni.removeInterceptor('navigateBack'); + } catch (error) { + console.warn('移除返回键监听失败:', error); + } + // #endif + + // 清除定时器 + if (this.backButtonTimer) { + clearTimeout(this.backButtonTimer); + this.backButtonTimer = null; + } + }, + // 清理资源 cleanup() { if (this.loadingTimer) { clearTimeout(this.loadingTimer); } + this.removeBackButtonListener(); } } } diff --git a/Appbuild/unpackage/dist/dev/app-plus/app-service.js b/Appbuild/unpackage/dist/dev/app-plus/app-service.js index ecf7b997..a4399776 100644 --- a/Appbuild/unpackage/dist/dev/app-plus/app-service.js +++ b/Appbuild/unpackage/dist/dev/app-plus/app-service.js @@ -116,25 +116,35 @@ if (uni.restoreGlobal) { loading: false, error: "", loadingTimer: null, - messageQueue: [] + messageQueue: [], + // 返回键监听相关 + backButtonListener: null, + backButtonCount: 0, + backButtonTimer: null, + canExit: false, + lastBackTime: 0 }; }, onLoad() { this.initApp(); + this.initBackButtonListener(); }, onShow() { this.resumeMessageQueue(); + this.resumeBackButtonListener(); }, onHide() { - formatAppLog("log", "at pages/index/index.vue:51", "WebView页面隐藏"); + formatAppLog("log", "at pages/index/index.vue:59", "WebView页面隐藏"); + this.pauseBackButtonListener(); }, onUnload() { this.cleanup(); + this.removeBackButtonListener(); }, methods: { // 获取初始URL getInitialUrl() { - formatAppLog("log", "at pages/index/index.vue:60", "获取初始URL,config:", this.config); + formatAppLog("log", "at pages/index/index.vue:70", "获取初始URL,config:", this.config); if (this.config && this.config.appConfig && this.config.appConfig.useTestPage) { return this.config.webConfig.testUrl; } @@ -142,12 +152,12 @@ if (uni.restoreGlobal) { }, // 初始化应用 initApp() { - formatAppLog("log", "at pages/index/index.vue:69", "UniApp: 开始初始化应用"); + formatAppLog("log", "at pages/index/index.vue:79", "UniApp: 开始初始化应用"); this.currentUrl = this.getInitialUrl(); - formatAppLog("log", "at pages/index/index.vue:72", "UniApp: 设置URL:", this.currentUrl); + formatAppLog("log", "at pages/index/index.vue:82", "UniApp: 设置URL:", this.currentUrl); this.setupLoadingTimeout(); this.initMessageHandler(); - formatAppLog("log", "at pages/index/index.vue:78", "UniApp: 立即注入桥接代码"); + formatAppLog("log", "at pages/index/index.vue:88", "UniApp: 立即注入桥接代码"); this.injectBridgeCode(); }, // 设置加载超时 @@ -156,14 +166,14 @@ if (uni.restoreGlobal) { clearTimeout(this.loadingTimer); } if (!this.config.appConfig.enableTimeout) { - formatAppLog("log", "at pages/index/index.vue:91", "超时检测已禁用"); + formatAppLog("log", "at pages/index/index.vue:101", "超时检测已禁用"); return; } if (this.config.appConfig.loadingTimeout > 0) { - formatAppLog("log", "at pages/index/index.vue:96", "设置加载超时:", this.config.appConfig.loadingTimeout + "ms"); + formatAppLog("log", "at pages/index/index.vue:106", "设置加载超时:", this.config.appConfig.loadingTimeout + "ms"); this.loadingTimer = setTimeout(() => { if (this.loading) { - formatAppLog("warn", "at pages/index/index.vue:99", "页面加载超时,当前状态:", this.loading); + formatAppLog("warn", "at pages/index/index.vue:109", "页面加载超时,当前状态:", this.loading); this.handleTimeout(); } }, this.config.appConfig.loadingTimeout); @@ -171,7 +181,7 @@ if (uni.restoreGlobal) { }, // 处理加载超时 handleTimeout() { - formatAppLog("warn", "at pages/index/index.vue:108", "触发页面加载超时处理"); + formatAppLog("warn", "at pages/index/index.vue:118", "触发页面加载超时处理"); this.error = "页面加载超时,请检查网络连接"; this.loading = false; if (this.loadingTimer) { @@ -181,9 +191,9 @@ if (uni.restoreGlobal) { }, // 初始化消息处理器 initMessageHandler() { - formatAppLog("log", "at pages/index/index.vue:120", "UniApp: 初始化消息处理器"); + formatAppLog("log", "at pages/index/index.vue:130", "UniApp: 初始化消息处理器"); window.addEventListener("message", (event) => { - formatAppLog("log", "at pages/index/index.vue:123", "UniApp: 收到window.message事件:", event.data); + formatAppLog("log", "at pages/index/index.vue:133", "UniApp: 收到window.message事件:", event.data); this.handleIframeMessage(event); }); }, @@ -193,21 +203,21 @@ if (uni.restoreGlobal) { }, // 注入桥接代码 injectBridgeCode() { - formatAppLog("log", "at pages/index/index.vue:136", "UniApp: 开始注入桥接代码"); + formatAppLog("log", "at pages/index/index.vue:146", "UniApp: 开始注入桥接代码"); const bridgeCode = ` // UniApp WebView 桥接代码 - __f__('log','at pages/index/index.vue:140','开始注入UniApp桥接代码...'); + __f__('log','at pages/index/index.vue:150','开始注入UniApp桥接代码...'); // 检查是否已经存在桥接 if (window.uniAppBridge) { - __f__('log','at pages/index/index.vue:144','UniApp桥接已存在,跳过注入'); + __f__('log','at pages/index/index.vue:154','UniApp桥接已存在,跳过注入'); return; } window.uniAppBridge = { // 发送消息到UniApp postMessage: function(type, data) { - __f__('log','at pages/index/index.vue:151','UniApp桥接发送消息:', type, data); + __f__('log','at pages/index/index.vue:161','UniApp桥接发送消息:', type, data); window.parent.postMessage({ type: type, data: data, @@ -217,68 +227,103 @@ if (uni.restoreGlobal) { // 获取用户信息 getUserInfo: function() { - __f__('log','at pages/index/index.vue:161','UniApp桥接: 请求用户信息'); + __f__('log','at pages/index/index.vue:171','UniApp桥接: 请求用户信息'); this.postMessage('getUserInfo', {}); }, // 获取设备信息 getDeviceInfo: function() { - __f__('log','at pages/index/index.vue:167','UniApp桥接: 请求设备信息'); + __f__('log','at pages/index/index.vue:177','UniApp桥接: 请求设备信息'); this.postMessage('getDeviceInfo', {}); }, // 显示Toast showToast: function(message, duration = 2000) { - __f__('log','at pages/index/index.vue:173','UniApp桥接: 显示Toast', message, duration); + __f__('log','at pages/index/index.vue:183','UniApp桥接: 显示Toast', message, duration); this.postMessage('toast', { message, duration }); }, // 显示Alert showAlert: function(title, content) { - __f__('log','at pages/index/index.vue:179','UniApp桥接: 显示Alert', title, content); + __f__('log','at pages/index/index.vue:189','UniApp桥接: 显示Alert', title, content); this.postMessage('alert', { title, content }); }, // 显示Confirm showConfirm: function(title, content) { - __f__('log','at pages/index/index.vue:185','UniApp桥接: 显示Confirm', title, content); + __f__('log','at pages/index/index.vue:195','UniApp桥接: 显示Confirm', title, content); this.postMessage('confirm', { title, content }); }, // 分享 share: function(data) { - __f__('log','at pages/index/index.vue:191','UniApp桥接: 分享', data); + __f__('log','at pages/index/index.vue:201','UniApp桥接: 分享', data); this.postMessage('share', data); }, // 支付 payment: function(data) { - __f__('log','at pages/index/index.vue:197','UniApp桥接: 支付', data); + __f__('log','at pages/index/index.vue:207','UniApp桥接: 支付', data); this.postMessage('payment', data); }, // 页面导航 navigate: function(url) { - __f__('log','at pages/index/index.vue:203','UniApp桥接: 导航', url); + __f__('log','at pages/index/index.vue:213','UniApp桥接: 导航', url); this.postMessage('navigate', { url }); }, // 自定义消息 sendCustomMessage: function(type, data) { - __f__('log','at pages/index/index.vue:209','UniApp桥接: 自定义消息', type, data); + __f__('log','at pages/index/index.vue:219','UniApp桥接: 自定义消息', type, data); this.postMessage(type, data); }, // 页面准备就绪 notifyPageReady: function(data) { - __f__('log','at pages/index/index.vue:215','UniApp桥接: 页面准备就绪', data); + __f__('log','at pages/index/index.vue:225','UniApp桥接: 页面准备就绪', data); this.postMessage('pageReady', data); + }, + + // 处理返回键 + handleBackButton: function(action) { + __f__('log','at pages/index/index.vue:231','UniApp桥接: 处理返回键', action); + + switch(action) { + case 'showExitConfirm': + // 在 web-view 内显示退出确认 + if (confirm('确定要退出应用吗?')) { + this.postMessage('exitApp', {}); + } + break; + case 'exitApp': + // 通知 UniApp 退出应用 + this.postMessage('exitApp', {}); + break; + } + }, + + // 监听返回键事件 + listenBackButton: function() { + // 监听浏览器的后退事件 + window.addEventListener('popstate', (event) => { + __f__('log','at pages/index/index.vue:251','UniApp桥接: 检测到 popstate 事件'); + this.postMessage('backButton', { action: 'popstate' }); + }); + + // 监听键盘事件 + document.addEventListener('keydown', (event) => { + if (event.key === 'Backspace' || event.keyCode === 8) { + __f__('log','at pages/index/index.vue:258','UniApp桥接: 检测到返回键'); + this.postMessage('backButton', { action: 'keydown' }); + } + }); } }; // 监听来自UniApp的消息 window.addEventListener('message', function(event) { - __f__('log','at pages/index/index.vue:222','UniApp桥接收到消息:', event.data); + __f__('log','at pages/index/index.vue:267','UniApp桥接收到消息:', event.data); if (event.data && event.data.type) { // 触发自定义事件 const customEvent = new CustomEvent('uniAppMessage', { @@ -288,7 +333,7 @@ if (uni.restoreGlobal) { } }); - __f__('log','at pages/index/index.vue:232','UniApp桥接代码注入成功'); + __f__('log','at pages/index/index.vue:277','UniApp桥接代码注入成功'); // 通知UniApp页面已加载完成 window.parent.postMessage({ @@ -296,48 +341,51 @@ if (uni.restoreGlobal) { data: { url: window.location.href }, timestamp: Date.now() }, '*'); + + // 初始化返回键监听 + window.uniAppBridge.listenBackButton(); `; - formatAppLog("log", "at pages/index/index.vue:243", "UniApp: 立即注入桥接代码"); + formatAppLog("log", "at pages/index/index.vue:291", "UniApp: 立即注入桥接代码"); this.evalJS(bridgeCode); setTimeout(() => { - formatAppLog("log", "at pages/index/index.vue:248", "UniApp: 延迟500ms后再次注入"); + formatAppLog("log", "at pages/index/index.vue:296", "UniApp: 延迟500ms后再次注入"); this.evalJS(bridgeCode); }, 500); setTimeout(() => { - formatAppLog("log", "at pages/index/index.vue:254", "UniApp: 延迟1000ms后备用注入"); + formatAppLog("log", "at pages/index/index.vue:302", "UniApp: 延迟1000ms后备用注入"); this.evalJS(bridgeCode); }, 1e3); }, // 执行JavaScript代码 evalJS(code) { - formatAppLog("log", "at pages/index/index.vue:261", "UniApp: 执行JavaScript代码"); - formatAppLog("log", "at pages/index/index.vue:262", "UniApp: 当前平台:", uni.getSystemInfoSync().platform); + formatAppLog("log", "at pages/index/index.vue:309", "UniApp: 执行JavaScript代码"); + formatAppLog("log", "at pages/index/index.vue:310", "UniApp: 当前平台:", uni.getSystemInfoSync().platform); const webview = this.$refs.webview; - formatAppLog("log", "at pages/index/index.vue:265", "UniApp: webview引用:", webview); + formatAppLog("log", "at pages/index/index.vue:313", "UniApp: webview引用:", webview); if (webview && webview.evalJS) { try { webview.evalJS(code); - formatAppLog("log", "at pages/index/index.vue:272", "UniApp: JavaScript代码执行成功 (App环境)"); + formatAppLog("log", "at pages/index/index.vue:320", "UniApp: JavaScript代码执行成功 (App环境)"); } catch (error) { - formatAppLog("error", "at pages/index/index.vue:274", "UniApp: JavaScript代码执行失败:", error); + formatAppLog("error", "at pages/index/index.vue:322", "UniApp: JavaScript代码执行失败:", error); } } else { - formatAppLog("warn", "at pages/index/index.vue:277", "UniApp: webview或evalJS方法不存在 (App环境)"); + formatAppLog("warn", "at pages/index/index.vue:325", "UniApp: webview或evalJS方法不存在 (App环境)"); this.tryAlternativeInjection(code); } }, // 备用注入方案 tryAlternativeInjection(code) { - formatAppLog("log", "at pages/index/index.vue:296", "UniApp: 尝试备用注入方案"); + formatAppLog("log", "at pages/index/index.vue:344", "UniApp: 尝试备用注入方案"); try { window.postMessage({ type: "injectCode", data: { code }, timestamp: Date.now() }, "*"); - formatAppLog("log", "at pages/index/index.vue:304", "UniApp: 备用方案1执行成功"); + formatAppLog("log", "at pages/index/index.vue:352", "UniApp: 备用方案1执行成功"); } catch (error) { - formatAppLog("error", "at pages/index/index.vue:306", "UniApp: 备用方案1失败:", error); + formatAppLog("error", "at pages/index/index.vue:354", "UniApp: 备用方案1失败:", error); try { const webview = this.$refs.webview; if (webview && webview.postMessage) { @@ -345,34 +393,34 @@ if (uni.restoreGlobal) { type: "injectCode", data: { code } }); - formatAppLog("log", "at pages/index/index.vue:316", "UniApp: 备用方案2执行成功"); + formatAppLog("log", "at pages/index/index.vue:364", "UniApp: 备用方案2执行成功"); } else { - formatAppLog("error", "at pages/index/index.vue:318", "UniApp: 备用方案2失败 - webview.postMessage不存在"); + formatAppLog("error", "at pages/index/index.vue:366", "UniApp: 备用方案2失败 - webview.postMessage不存在"); } } catch (error2) { - formatAppLog("error", "at pages/index/index.vue:321", "UniApp: 备用方案2失败:", error2); + formatAppLog("error", "at pages/index/index.vue:369", "UniApp: 备用方案2失败:", error2); } } }, // 处理web-view组件的消息 handleMessage(event) { - formatAppLog("log", "at pages/index/index.vue:328", "收到web-view消息:", event.detail); + formatAppLog("log", "at pages/index/index.vue:376", "收到web-view消息:", event.detail); try { const data = event.detail.data; if (data && data.type) { this.processMessage(data); } } catch (error) { - formatAppLog("error", "at pages/index/index.vue:335", "处理消息失败:", error); + formatAppLog("error", "at pages/index/index.vue:383", "处理消息失败:", error); } }, // 处理iframe消息 handleIframeMessage(event) { - formatAppLog("log", "at pages/index/index.vue:341", "收到iframe消息:", event.data); + formatAppLog("log", "at pages/index/index.vue:389", "收到iframe消息:", event.data); try { if (event.data && event.data.type) { if (event.data.type === "pageLoaded") { - formatAppLog("log", "at pages/index/index.vue:346", "收到页面加载完成消息:", event.data.data); + formatAppLog("log", "at pages/index/index.vue:394", "收到页面加载完成消息:", event.data.data); if (this.loadingTimer) { clearTimeout(this.loadingTimer); this.loadingTimer = null; @@ -384,55 +432,63 @@ if (uni.restoreGlobal) { this.processMessage(event.data); } } catch (error) { - formatAppLog("error", "at pages/index/index.vue:361", "处理iframe消息失败:", error); + formatAppLog("error", "at pages/index/index.vue:409", "处理iframe消息失败:", error); } }, // 处理消息 processMessage(data) { - formatAppLog("log", "at pages/index/index.vue:367", "UniApp处理消息:", data.type, data); + formatAppLog("log", "at pages/index/index.vue:415", "UniApp处理消息:", data.type, data); switch (data.type) { case this.config.communication.messageTypes.GET_USER_INFO: - formatAppLog("log", "at pages/index/index.vue:371", "UniApp: 处理获取用户信息请求"); + formatAppLog("log", "at pages/index/index.vue:419", "UniApp: 处理获取用户信息请求"); this.sendUserInfo(); break; case this.config.communication.messageTypes.GET_DEVICE_INFO: - formatAppLog("log", "at pages/index/index.vue:375", "UniApp: 处理获取设备信息请求"); + formatAppLog("log", "at pages/index/index.vue:423", "UniApp: 处理获取设备信息请求"); this.sendDeviceInfo(); break; case this.config.communication.messageTypes.NAVIGATE: - formatAppLog("log", "at pages/index/index.vue:379", "UniApp: 处理导航请求"); + formatAppLog("log", "at pages/index/index.vue:427", "UniApp: 处理导航请求"); this.handleNavigation(data); break; case this.config.communication.messageTypes.SHARE: - formatAppLog("log", "at pages/index/index.vue:383", "UniApp: 处理分享请求"); + formatAppLog("log", "at pages/index/index.vue:431", "UniApp: 处理分享请求"); this.handleShare(data); break; case this.config.communication.messageTypes.PAYMENT: - formatAppLog("log", "at pages/index/index.vue:387", "UniApp: 处理支付请求"); + formatAppLog("log", "at pages/index/index.vue:435", "UniApp: 处理支付请求"); this.handlePayment(data); break; case this.config.communication.messageTypes.TOAST: - formatAppLog("log", "at pages/index/index.vue:391", "UniApp: 处理Toast请求"); + formatAppLog("log", "at pages/index/index.vue:439", "UniApp: 处理Toast请求"); this.handleToast(data); break; case this.config.communication.messageTypes.ALERT: - formatAppLog("log", "at pages/index/index.vue:395", "UniApp: 处理Alert请求"); + formatAppLog("log", "at pages/index/index.vue:443", "UniApp: 处理Alert请求"); this.handleAlert(data); break; case this.config.communication.messageTypes.CONFIRM: - formatAppLog("log", "at pages/index/index.vue:399", "UniApp: 处理Confirm请求"); + formatAppLog("log", "at pages/index/index.vue:447", "UniApp: 处理Confirm请求"); this.handleConfirm(data); break; case "pageReady": - formatAppLog("log", "at pages/index/index.vue:403", "UniApp: 处理页面准备就绪消息"); + formatAppLog("log", "at pages/index/index.vue:451", "UniApp: 处理页面准备就绪消息"); + break; + case "backButton": + formatAppLog("log", "at pages/index/index.vue:455", "UniApp: 处理返回键消息"); + this.handleBackButtonMessage(data); + break; + case "exitApp": + formatAppLog("log", "at pages/index/index.vue:459", "UniApp: 处理退出应用消息"); + this.handleExitApp(); break; default: - formatAppLog("log", "at pages/index/index.vue:407", "UniApp: 未知消息类型:", data.type); + formatAppLog("log", "at pages/index/index.vue:463", "UniApp: 未知消息类型:", data.type); } }, // 发送用户信息到iframe sendUserInfo() { - formatAppLog("log", "at pages/index/index.vue:413", "UniApp: 发送用户信息"); + formatAppLog("log", "at pages/index/index.vue:469", "UniApp: 发送用户信息"); const userInfo = { type: "userInfo", data: this.config.userConfig.defaultUser @@ -441,7 +497,7 @@ if (uni.restoreGlobal) { }, // 发送设备信息到iframe sendDeviceInfo() { - formatAppLog("log", "at pages/index/index.vue:423", "UniApp: 发送设备信息"); + formatAppLog("log", "at pages/index/index.vue:479", "UniApp: 发送设备信息"); const systemInfo = uni.getSystemInfoSync(); const deviceInfo = { type: "deviceInfo", @@ -461,12 +517,12 @@ if (uni.restoreGlobal) { // 处理导航 handleNavigation(data) { if (data.url) { - formatAppLog("log", "at pages/index/index.vue:444", "导航到:", data.url); + formatAppLog("log", "at pages/index/index.vue:500", "导航到:", data.url); } }, // 处理分享 handleShare(data) { - formatAppLog("log", "at pages/index/index.vue:451", "UniApp: 处理分享请求", data); + formatAppLog("log", "at pages/index/index.vue:507", "UniApp: 处理分享请求", data); uni.share({ provider: "weixin", scene: "WXSceneSession", @@ -475,18 +531,18 @@ if (uni.restoreGlobal) { title: data.title || this.config.appConfig.appName, summary: data.summary || "分享内容", success: (res) => { - formatAppLog("log", "at pages/index/index.vue:460", "UniApp: 分享成功:", res); + formatAppLog("log", "at pages/index/index.vue:516", "UniApp: 分享成功:", res); this.sendToIframe("shareResult", { success: true }); }, fail: (err) => { - formatAppLog("error", "at pages/index/index.vue:464", "UniApp: 分享失败:", err); + formatAppLog("error", "at pages/index/index.vue:520", "UniApp: 分享失败:", err); this.sendToIframe("shareResult", { success: false, error: err }); } }); }, // 处理支付 handlePayment(data) { - formatAppLog("log", "at pages/index/index.vue:472", "UniApp: 处理支付请求", data); + formatAppLog("log", "at pages/index/index.vue:528", "UniApp: 处理支付请求", data); setTimeout(() => { this.sendToIframe("paymentResult", { success: true, @@ -496,7 +552,7 @@ if (uni.restoreGlobal) { }, // 处理Toast handleToast(data) { - formatAppLog("log", "at pages/index/index.vue:485", "UniApp: 处理Toast请求", data); + formatAppLog("log", "at pages/index/index.vue:541", "UniApp: 处理Toast请求", data); uni.showToast({ title: data.message, icon: "none", @@ -505,7 +561,7 @@ if (uni.restoreGlobal) { }, // 处理Alert handleAlert(data) { - formatAppLog("log", "at pages/index/index.vue:495", "UniApp: 处理Alert请求", data); + formatAppLog("log", "at pages/index/index.vue:551", "UniApp: 处理Alert请求", data); uni.showModal({ title: data.title || "提示", content: data.content, @@ -514,12 +570,12 @@ if (uni.restoreGlobal) { }, // 处理Confirm handleConfirm(data) { - formatAppLog("log", "at pages/index/index.vue:505", "UniApp: 处理Confirm请求", data); + formatAppLog("log", "at pages/index/index.vue:561", "UniApp: 处理Confirm请求", data); uni.showModal({ title: data.title || "确认", content: data.content, success: (res) => { - formatAppLog("log", "at pages/index/index.vue:510", "UniApp: Confirm结果:", res); + formatAppLog("log", "at pages/index/index.vue:566", "UniApp: Confirm结果:", res); this.sendToIframe("confirmResult", { confirmed: res.confirm }); @@ -533,10 +589,10 @@ if (uni.restoreGlobal) { }, // 处理消息队列 processMessageQueue() { - formatAppLog("log", "at pages/index/index.vue:526", "UniApp: 处理消息队列, 队列长度:", this.messageQueue.length, "加载状态:", this.loading); + formatAppLog("log", "at pages/index/index.vue:582", "UniApp: 处理消息队列, 队列长度:", this.messageQueue.length, "加载状态:", this.loading); if (this.messageQueue.length > 0 && !this.loading) { const message = this.messageQueue.shift(); - formatAppLog("log", "at pages/index/index.vue:529", "UniApp: 发送消息到iframe:", message); + formatAppLog("log", "at pages/index/index.vue:585", "UniApp: 发送消息到iframe:", message); this.evalJS(` window.postMessage(${JSON.stringify(message)}, '*'); `); @@ -557,12 +613,12 @@ if (uni.restoreGlobal) { }, // 处理加载状态 handleLoading(event) { - formatAppLog("log", "at pages/index/index.vue:553", "WebView加载状态变化:", event.detail); + formatAppLog("log", "at pages/index/index.vue:609", "WebView加载状态变化:", event.detail); const newLoadingState = event.detail.loading; - formatAppLog("log", "at pages/index/index.vue:555", "加载状态从", this.loading, "变为", newLoadingState); + formatAppLog("log", "at pages/index/index.vue:611", "加载状态从", this.loading, "变为", newLoadingState); this.loading = newLoadingState; if (!this.loading) { - formatAppLog("log", "at pages/index/index.vue:561", "页面加载完成,清除超时定时器"); + formatAppLog("log", "at pages/index/index.vue:617", "页面加载完成,清除超时定时器"); if (this.loadingTimer) { clearTimeout(this.loadingTimer); this.loadingTimer = null; @@ -570,13 +626,13 @@ if (uni.restoreGlobal) { this.injectBridgeCode(); this.processMessageQueue(); } else { - formatAppLog("log", "at pages/index/index.vue:573", "页面开始加载,设置超时检测"); + formatAppLog("log", "at pages/index/index.vue:629", "页面开始加载,设置超时检测"); this.setupLoadingTimeout(); } }, // 处理错误 handleError(event) { - formatAppLog("error", "at pages/index/index.vue:580", "WebView错误:", event.detail); + formatAppLog("error", "at pages/index/index.vue:636", "WebView错误:", event.detail); this.error = "页面加载失败,请检查网络连接"; this.loading = false; clearTimeout(this.loadingTimer); @@ -598,18 +654,18 @@ if (uni.restoreGlobal) { }, // 清除超时 clearTimeout() { - formatAppLog("log", "at pages/index/index.vue:606", "手动清除超时"); + formatAppLog("log", "at pages/index/index.vue:662", "手动清除超时"); if (this.loadingTimer) { clearTimeout(this.loadingTimer); this.loadingTimer = null; } this.error = ""; this.loading = false; - formatAppLog("log", "at pages/index/index.vue:613", "超时已清除"); + formatAppLog("log", "at pages/index/index.vue:669", "超时已清除"); }, // 动态设置web-view高度 setWebViewHeight(height) { - formatAppLog("log", "at pages/index/index.vue:618", "设置web-view高度:", height); + formatAppLog("log", "at pages/index/index.vue:674", "设置web-view高度:", height); if (this.$refs.webview) { this.$refs.webview.$el.style.height = height + "px"; this.$refs.webview.$el.className = "webview custom-height"; @@ -621,21 +677,162 @@ if (uni.restoreGlobal) { // 设置web-view为全屏 setWebViewFullscreen() { const fullHeight = uni.getSystemInfoSync().windowHeight; - formatAppLog("log", "at pages/index/index.vue:636", "设置web-view全屏,高度:", fullHeight); + formatAppLog("log", "at pages/index/index.vue:692", "设置web-view全屏,高度:", fullHeight); this.setWebViewHeight(fullHeight); }, // 设置web-view为部分高度 setWebViewPartialHeight(percentage = 0.8) { const windowHeight = uni.getSystemInfoSync().windowHeight; const partialHeight = windowHeight * percentage; - formatAppLog("log", "at pages/index/index.vue:644", "设置web-view部分高度:", partialHeight, "百分比:", percentage); + formatAppLog("log", "at pages/index/index.vue:700", "设置web-view部分高度:", partialHeight, "百分比:", percentage); this.setWebViewHeight(partialHeight); }, + // 初始化返回键监听 + initBackButtonListener() { + formatAppLog("log", "at pages/index/index.vue:706", "初始化返回键监听"); + try { + uni.addInterceptor("navigateBack", { + invoke(e) { + formatAppLog("log", "at pages/index/index.vue:713", "拦截到返回事件:", e); + return false; + } + }); + } catch (error) { + formatAppLog("warn", "at pages/index/index.vue:718", "addInterceptor 失败:", error); + } + this.setupPhysicalBackButton(); + this.setupWebViewBackListener(); + }, + // 设置物理返回键监听 + setupPhysicalBackButton() { + try { + plus.key.addEventListener("backbutton", (e) => { + formatAppLog("log", "at pages/index/index.vue:735", "检测到物理返回键事件:", e); + this.handleBackButton(); + }); + } catch (error) { + formatAppLog("warn", "at pages/index/index.vue:739", "物理返回键监听失败:", error); + } + }, + // 设置 web-view 内返回监听 + setupWebViewBackListener() { + window.addEventListener("popstate", (event) => { + formatAppLog("log", "at pages/index/index.vue:748", "检测到 popstate 事件:", event); + this.handleBackButton(); + }); + window.addEventListener("beforeunload", (event) => { + formatAppLog("log", "at pages/index/index.vue:754", "检测到 beforeunload 事件:", event); + this.handleBackButton(); + }); + }, + // 处理返回键事件 + handleBackButton() { + const now = Date.now(); + const timeDiff = now - this.lastBackTime; + formatAppLog("log", "at pages/index/index.vue:764", "处理返回键事件, 时间差:", timeDiff, "ms"); + if (timeDiff > 2e3) { + this.backButtonCount = 0; + } + this.backButtonCount++; + this.lastBackTime = now; + if (this.backButtonCount === 1) { + this.showExitConfirm(); + } else if (this.backButtonCount >= 2) { + this.exitApp(); + } + }, + // 显示退出确认 + showExitConfirm() { + formatAppLog("log", "at pages/index/index.vue:786", "显示退出确认"); + uni.showModal({ + title: "退出确认", + content: "确定要退出应用吗?", + confirmText: "退出", + cancelText: "取消", + success: (res) => { + if (res.confirm) { + this.exitApp(); + } + } + }); + this.sendBackButtonMessage("showExitConfirm"); + }, + // 退出应用 + exitApp() { + formatAppLog("log", "at pages/index/index.vue:809", "退出应用"); + try { + plus.runtime.quit(); + } catch (error) { + formatAppLog("error", "at pages/index/index.vue:816", "退出应用失败:", error); + } + this.sendBackButtonMessage("exitApp"); + }, + // 发送返回键消息到 web-view + sendBackButtonMessage(action) { + if (this.$refs.webview) { + try { + this.$refs.webview.postMessage({ + type: "backButton", + action, + timestamp: Date.now() + }); + } catch (error) { + formatAppLog("error", "at pages/index/index.vue:835", "发送返回键消息失败:", error); + } + } + }, + // 处理返回键消息 + handleBackButtonMessage(data) { + formatAppLog("log", "at pages/index/index.vue:842", "处理返回键消息:", data); + switch (data.action) { + case "popstate": + case "keydown": + this.handleBackButton(); + break; + default: + formatAppLog("log", "at pages/index/index.vue:850", "未知的返回键动作:", data.action); + } + }, + // 处理退出应用 + handleExitApp() { + formatAppLog("log", "at pages/index/index.vue:856", "处理退出应用"); + try { + plus.runtime.quit(); + } catch (error) { + formatAppLog("error", "at pages/index/index.vue:862", "退出应用失败:", error); + } + }, + // 恢复返回键监听 + resumeBackButtonListener() { + formatAppLog("log", "at pages/index/index.vue:869", "恢复返回键监听"); + this.backButtonCount = 0; + this.lastBackTime = 0; + }, + // 暂停返回键监听 + pauseBackButtonListener() { + formatAppLog("log", "at pages/index/index.vue:876", "暂停返回键监听"); + this.backButtonCount = 0; + }, + // 移除返回键监听 + removeBackButtonListener() { + formatAppLog("log", "at pages/index/index.vue:882", "移除返回键监听"); + try { + plus.key.removeEventListener("backbutton"); + uni.removeInterceptor("navigateBack"); + } catch (error) { + formatAppLog("warn", "at pages/index/index.vue:892", "移除返回键监听失败:", error); + } + if (this.backButtonTimer) { + clearTimeout(this.backButtonTimer); + this.backButtonTimer = null; + } + }, // 清理资源 cleanup() { if (this.loadingTimer) { clearTimeout(this.loadingTimer); } + this.removeBackButtonListener(); } } }; diff --git a/nkebao/src/pages/mobile/scenarios/list/index.module.scss b/nkebao/src/pages/mobile/scenarios/list/index.module.scss index 60c5c10a..b371a294 100644 --- a/nkebao/src/pages/mobile/scenarios/list/index.module.scss +++ b/nkebao/src/pages/mobile/scenarios/list/index.module.scss @@ -35,7 +35,10 @@ min-height: 100vh; padding: 0 0 60px 0; } - +.scene-page-content { + padding: 16px; + text-align: center; +} // 错误提示 .error-notice { margin-bottom: 12px; diff --git a/nkebao/src/pages/mobile/scenarios/list/index.tsx b/nkebao/src/pages/mobile/scenarios/list/index.tsx index 2613bdaf..07bf0547 100644 --- a/nkebao/src/pages/mobile/scenarios/list/index.tsx +++ b/nkebao/src/pages/mobile/scenarios/list/index.tsx @@ -65,7 +65,7 @@ const Scene: React.FC = () => { navigate("/scenarios/new"); }; - if (error && scenarios.length === 0) { + if (!(error && scenarios.length === 0)) { return (