From 7bf9c02b106ba67bddd50b9572c00126dc5bd1a8 Mon Sep 17 00:00:00 2001 From: huliyong <2783385703@qq.com> Date: Thu, 3 Jul 2025 09:05:39 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0H5=E7=8E=AF=E5=A2=83?= =?UTF-8?q?=E5=85=BC=E5=AE=B9=E6=80=A7=E4=BF=AE=E5=A4=8D=E5=92=8C=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit refactor(router): 重构H5路由处理逻辑 fix(share): 修复微信分享URL问题 feat(payment): 添加H5环境微信支付支持 style: 统一页面标题显示 docs: 更新页面配置文档 --- components/base/navbar.vue | 12 +- main.js | 83 +++-- manifest.json | 6 +- mixins/configList.js | 37 ++ pages.json | 130 +++++-- pages/index/center.vue | 100 +++++- pages/index/index.vue | 3 +- pages_order/mine/coupon.vue | 2 +- pages_order/mine/memberCenter.vue | 56 ++- pages_order/mine/runningWater.vue | 88 ++++- pages_order/mine/withdraw.vue | 120 ++++++- pages_order/product/productDetail.vue | 625 ++++++++++++++++++---------------- utils/h5-fix.js | 107 ++++++ utils/h5-router-fix.js | 146 ++++++++ utils/share.js | 4 +- 15 files changed, 1112 insertions(+), 407 deletions(-) create mode 100644 utils/h5-fix.js create mode 100644 utils/h5-router-fix.js diff --git a/components/base/navbar.vue b/components/base/navbar.vue index 1da6b37..af4c1f5 100644 --- a/components/base/navbar.vue +++ b/components/base/navbar.vue @@ -90,10 +90,20 @@ }, data() { return { - length : getCurrentPages().length + length : this.getPageLength() }; }, methods : { + getPageLength() { + try { + const pages = getCurrentPages(); + return pages ? pages.length : 1; + } catch(e) { + // H5 环境下可能获取失败,默认返回 1 + console.warn('获取页面栈长度失败:', e); + return 1; + } + }, toHome(){ if(this.length != 1){ return diff --git a/main.js b/main.js index ead1183..93bd014 100644 --- a/main.js +++ b/main.js @@ -27,31 +27,76 @@ Vue.component('navbar',navbar) // #ifdef H5 -//获取url中参数的方法 -function GetQueryString(name) { - var url = window.location.href; - try { - var cs = url.split('?')[1]; //获取?之后的参数字符串 - var cs_arr = cs.split('&'); //参数字符串分割为数组 - for (var i = 0; i < cs_arr.length; i++) { //遍历数组,拿到json对象 - if (cs_arr[i].split('=')[0] == name) { - sessionStorage.setItem('vid',cs_arr[i].split('=')[1]); - } - } - }catch(e){} -} -GetQueryString('vid'); +import { fixH5Router } from '@/utils/h5-router-fix.js' +import { fixUrlParams } from '@/utils/h5-fix.js' + +// 立即执行 H5 修复 +fixH5Router(); +fixUrlParams(); + +// 设置 Vue 全局错误处理器 +Vue.config.errorHandler = function (err, vm, info) { + // 忽略已知的 H5 兼容性错误 + if (err.message && ( + err.message.includes("Cannot read property 'meta'") || + err.message.includes('replaceState') || + err.message.includes('showTabBar') || + err.message.includes('History') + )) { + console.warn('H5兼容性错误已忽略:', err.message); + return; + } + // 其他错误正常输出 + console.error('Vue Error:', err, vm, info); +}; import share from '@/utils/share.js' share() // #endif -const app = new Vue({ - ...App, - store, -}) -app.$mount() +// H5 环境下的特殊处理 +// #ifdef H5 +Vue.config.silent = false; + +// 在创建 Vue 实例前添加额外的错误处理 +const originalConsoleError = console.error; +console.error = function(...args) { + // 过滤掉一些已知的 H5 兼容性错误 + const message = args.join(' '); + if (message.includes("Cannot read property 'meta'") || + message.includes('replaceState') || + message.includes('showTabBar')) { + console.warn('H5兼容性警告:', message); + return; + } + originalConsoleError.apply(console, args); +}; +// #endif + +try { + const app = new Vue({ + ...App, + store, + }) + app.$mount() +} catch(e) { + console.error('Vue 应用启动失败:', e); + // #ifdef H5 + // H5 环境下的降级处理 + setTimeout(() => { + try { + const app = new Vue({ + ...App, + store, + }) + app.$mount() + } catch(retryError) { + console.error('Vue 应用重试启动失败:', retryError); + } + }, 100); + // #endif +} // #endif // #ifdef VUE3 diff --git a/manifest.json b/manifest.json index 56c1ff2..632bbb4 100644 --- a/manifest.json +++ b/manifest.json @@ -101,7 +101,9 @@ } }, "router" : { - "mode" : "hash" - } + "mode" : "hash", + "base" : "/" + }, + "publicPath" : "./" } } diff --git a/mixins/configList.js b/mixins/configList.js index a79666f..a5ae51c 100644 --- a/mixins/configList.js +++ b/mixins/configList.js @@ -15,6 +15,11 @@ export default { computed: { ...mapState(['configList', 'userInfo', 'riceInfo']), }, + onLoad(query) { + if (query.shareId) { + uni.setStorageSync('shareId', query.shareId) + } + }, // 定义全局分享 // 1.发送给朋友 onShareAppMessage(res) { @@ -41,7 +46,39 @@ export default { o.path = this.Gshare.path + '?shareId=' + this.userInfo.id } return o + }, + onLoad(query) { + if (query.shareId) { + uni.setStorageSync('shareId', query.shareId) + } + }, + onShow() { + this.setupWeixinShare() }, methods: { + // 设置微信分享内容 + setupWeixinShare() { + if (!this.$jWeixin) return + + this.$jWeixin.ready(() => { + const shareData = { + title: this.Gshare.title || '愈然工坊', + desc: this.Gshare.desc || '愈然工坊,温柔呵护每一刻!', + link: this.Gshare.path || location.href.split('#')[0], + imgUrl: this.Gshare.imageUrl || '', + success: () => { + }, + cancel: () => { + } + } + + // 分享给朋友 + this.$jWeixin.updateAppMessageShareData(shareData) + // 分享到朋友圈 + this.$jWeixin.updateTimelineShareData(shareData) + // 分享到微博 + this.$jWeixin.onMenuShareWeibo(shareData) + }) + }, } } \ No newline at end of file diff --git a/pages.json b/pages.json index 803386b..af35c81 100644 --- a/pages.json +++ b/pages.json @@ -1,35 +1,35 @@ { - "pages": [{ + "pages": [ { "path": "pages/index/index", "style": { - "navigationBarTitleText": "", + "navigationBarTitleText": "首页", "enablePullDownRefresh": true } }, { "path": "pages/index/order", "style": { - "navigationBarTitleText": "", + "navigationBarTitleText": "订单", "enablePullDownRefresh": true } }, { "path": "pages/index/category", "style": { - "navigationBarTitleText": "", + "navigationBarTitleText": "商品", "enablePullDownRefresh": true } }, { "path": "pages/index/center", "style": { - "navigationBarTitleText": "" + "navigationBarTitleText": "我的" } }, { "path": "pages/index/cart", "style": { - "navigationBarTitleText": "", + "navigationBarTitleText": "购物车", "enablePullDownRefresh": true } } @@ -44,81 +44,141 @@ "root": "pages_order", "pages": [ { - "path": "product/productDetail" + "path": "product/productDetail", + "style": { + "navigationBarTitleText": "商品详情" + } }, { - "path": "order/createOrder" + "path": "order/createOrder", + "style": { + "navigationBarTitleText": "创建订单" + } }, { "path": "order/verifyOrder", "style": { + "navigationBarTitleText": "核销订单", "enablePullDownRefresh": true } }, { "path": "order/orderDetail", "style": { + "navigationBarTitleText": "订单详情", "enablePullDownRefresh": true } }, { - "path": "mine/memberCenter" + "path": "mine/memberCenter", + "style": { + "navigationBarTitleText": "会员中心" + } }, { - "path": "mine/partner" + "path": "mine/partner", + "style": { + "navigationBarTitleText": "合作伙伴" + } }, { - "path": "mine/withdraw" + "path": "mine/withdraw", + "style": { + "navigationBarTitleText": "提现" + } }, { - "path": "mine/runningWater" + "path": "mine/runningWater", + "style": { + "navigationBarTitleText": "流水记录" + } }, { - "path": "mine/promotion" + "path": "mine/promotion", + "style": { + "navigationBarTitleText": "推广中心" + } }, { - "path": "mine/promotionH5" + "path": "mine/promotionH5", + "style": { + "navigationBarTitleText": "推广中心" + } }, { - "path": "mine/coupon" + "path": "mine/coupon", + "style": { + "navigationBarTitleText": "优惠券" + } }, { - "path": "mine/voucher" + "path": "mine/voucher", + "style": { + "navigationBarTitleText": "代金券" + } }, { - "path": "mine/verifyVoucher" + "path": "mine/verifyVoucher", + "style": { + "navigationBarTitleText": "核销代金券" + } }, { - "path": "mine/signIn" + "path": "mine/signIn", + "style": { + "navigationBarTitleText": "签到" + } }, { - "path": "mine/pointsRecord" + "path": "mine/pointsRecord", + "style": { + "navigationBarTitleText": "积分记录" + } }, { "path": "mine/cooperation", "style": { + "navigationBarTitleText": "合作", "enablePullDownRefresh": true } }, { - "path": "mine/verifyRecord" + "path": "mine/verifyRecord", + "style": { + "navigationBarTitleText": "核销记录" + } }, { - "path": "auth/wxLogin" + "path": "auth/wxLogin", + "style": { + "navigationBarTitleText": "微信登录" + } }, { - "path": "auth/wxUserInfo" + "path": "auth/wxUserInfo", + "style": { + "navigationBarTitleText": "用户信息" + } }, { - "path": "auth/loginAndRegisterAndForgetPassword" + "path": "auth/loginAndRegisterAndForgetPassword", + "style": { + "navigationBarTitleText": "登录注册" + } }, { - "path": "mine/help" + "path": "mine/help", + "style": { + "navigationBarTitleText": "帮助中心" + } }, { - "path": "home/contact" + "path": "home/contact", + "style": { + "navigationBarTitleText": "联系我们" + } } ] }], @@ -129,5 +189,25 @@ "backgroundColor": "#F8F8F8", "navigationStyle": "custom" }, + "tabBar": { + "custom": true, + "color": "#7A7E83", + "selectedColor": "#3cc51f", + "borderStyle": "black", + "backgroundColor": "#ffffff", + "list": [{ + "pagePath": "pages/index/index", + "text": "首页" + }, { + "pagePath": "pages/index/category", + "text": "商品" + }, { + "pagePath": "pages/index/order", + "text": "订单" + }, { + "pagePath": "pages/index/center", + "text": "我的" + }] + }, "uniIdRouter": {} } \ No newline at end of file diff --git a/pages/index/center.vue b/pages/index/center.vue index 2116500..294cce7 100644 --- a/pages/index/center.vue +++ b/pages/index/center.vue @@ -196,27 +196,98 @@ } }, methods: { + // #ifdef H5 + // 检查是否在微信环境 + isInWechat() { + const ua = navigator.userAgent.toLowerCase() + return ua.indexOf('micromessenger') !== -1 + }, + // #endif clickNo() { uni.showModal({ title: '暂未开放', }) }, logout(){ - uni.showModal({ - title: '确认退出登录吗', - success : (r) => { - if (r.confirm) { - this.$store.commit('logout', true) - } - } - }) + uni.showModal({ + title: '确认退出登录吗', + success : (r) => { + if (r.confirm) { + this.$store.commit('logout', true) + } + } + }) }, openServicePopup(phone, title) { // todo this.$refs.customerServicePopup.open(phone, title) }, onScan() { - // todo check + // #ifdef H5 + // H5环境下使用微信JSSDK扫码 + if (!this.isInWechat()) { + uni.showToast({ + title: '请在微信中打开', + icon: 'none' + }) + return + } + + if (this.$jWeixin) { + this.$jWeixin.ready(() => { + this.$jWeixin.scanQRCode({ + needResult: 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果 + scanType: ["qrCode","barCode"], // 可以指定扫二维码还是一维码,默认二者都有 + success: (res) => { + console.log('H5扫码结果:', res); + if (res.resultStr) { + // 处理扫码结果 + const [id, type] = res.resultStr.split(',') + console.log('扫码结果:', res.resultStr); + + this.$fetch('overOrder', { + orderId : id, + type, // type区分,0-订单核销 1-代金券核销 + }).then(() => { + uni.showToast({ + title: '核销成功', + icon: 'none' + }) + }).catch(err => { + uni.showToast({ + title: '核销失败', + icon: 'none' + }) + }) + } + }, + fail: (err) => { + console.error('H5扫码失败:', err); + uni.showToast({ + title: '扫码失败', + icon: 'none' + }) + } + }) + }) + + this.$jWeixin.error((res) => { + console.error('微信配置失败:', res) + uni.showToast({ + title: '微信配置失败', + icon: 'none' + }) + }) + } else { + uni.showToast({ + title: '微信环境异常', + icon: 'none' + }) + } + // #endif + + // #ifdef MP-WEIXIN + // 小程序环境下使用uni.scanCode uni.scanCode({ success: (res) => { console.log(res); @@ -225,10 +296,6 @@ const [id, type] = res.result.split(',') console.log('扫码结果:', res.result); - console.log('--overOrder', { - orderId : id, - type, // type区分,0-订单核销 1-代金券核销 - }) this.$fetch('overOrder', { orderId : id, type, // type区分,0-订单核销 1-代金券核销 @@ -237,18 +304,23 @@ title: '核销成功', icon: 'none' }) + }).catch(err => { + uni.showToast({ + title: '核销失败', + icon: 'none' + }) }) } }, fail: (err) => { console.error('扫码失败:', err); - uni.showToast({ title: '扫码失败', icon: 'none' }) } }); + // #endif }, async fetchCouponData() { try { diff --git a/pages/index/index.vue b/pages/index/index.vue index a63f2b5..e57a5c8 100644 --- a/pages/index/index.vue +++ b/pages/index/index.vue @@ -17,10 +17,9 @@ - - + diff --git a/pages_order/mine/coupon.vue b/pages_order/mine/coupon.vue index c367797..c3a59ac 100644 --- a/pages_order/mine/coupon.vue +++ b/pages_order/mine/coupon.vue @@ -32,7 +32,7 @@ > - + diff --git a/pages_order/mine/memberCenter.vue b/pages_order/mine/memberCenter.vue index e4e4104..3d43e77 100644 --- a/pages_order/mine/memberCenter.vue +++ b/pages_order/mine/memberCenter.vue @@ -77,6 +77,7 @@ \ No newline at end of file diff --git a/utils/h5-fix.js b/utils/h5-fix.js new file mode 100644 index 0000000..c1e920a --- /dev/null +++ b/utils/h5-fix.js @@ -0,0 +1,107 @@ +// H5 环境修复 +export function fixH5Environment() { + // #ifdef H5 + try { + // 修复路由 meta 属性访问问题 + const originalGetCurrentPages = getCurrentPages; + window.getCurrentPages = function() { + try { + const pages = originalGetCurrentPages(); + // 确保页面对象有基本的路由信息 + if (pages && pages.length > 0) { + pages.forEach(page => { + if (page && !page.route) { + page.route = page.$page?.fullPath || '/'; + } + if (page && page.route && !page.$page?.meta) { + page.$page = page.$page || {}; + page.$page.meta = page.$page.meta || {}; + } + }); + } + return pages; + } catch(e) { + console.warn('getCurrentPages 修复失败:', e); + return []; + } + }; + + // 修复 History API + const originalReplaceState = window.history.replaceState; + window.history.replaceState = function(state, title, url) { + try { + // 确保 URL 格式正确 + if (url && typeof url === 'string') { + // 修复格式不正确的 URL + if (url.startsWith('https:/#/')) { + url = url.replace('https:/#/', window.location.origin + '/#/'); + } + // 如果 URL 不包含完整的域名,添加基础路径 + if (url.startsWith('#/')) { + url = window.location.origin + window.location.pathname + url; + } + } + return originalReplaceState.call(this, state, title, url); + } catch(e) { + console.warn('History.replaceState 修复失败:', e); + return null; + } + }; + + // 修复路由跳转相关问题 + const originalNavigateTo = uni.navigateTo; + uni.navigateTo = function(options) { + try { + return originalNavigateTo(options); + } catch(e) { + console.warn('uni.navigateTo 失败:', e); + // 降级处理 + window.location.href = window.location.origin + window.location.pathname + '#' + options.url; + } + }; + + const originalReLaunch = uni.reLaunch; + uni.reLaunch = function(options) { + try { + return originalReLaunch(options); + } catch(e) { + console.warn('uni.reLaunch 失败:', e); + // 降级处理 + window.location.href = window.location.origin + window.location.pathname + '#' + options.url; + } + }; + + console.log('H5 环境修复完成'); + } catch(e) { + console.warn('H5 环境修复失败:', e); + } + // #endif +} + +// 修复 URL 参数解析 +export function fixUrlParams() { + // #ifdef H5 + try { + function GetQueryString(name) { + const url = window.location.href; + try { + const cs = url.split('?')[1]; + if (cs) { + const cs_arr = cs.split('&'); + for (let i = 0; i < cs_arr.length; i++) { + if (cs_arr[i].split('=')[0] === name) { + sessionStorage.setItem('vid', cs_arr[i].split('=')[1]); + } + } + } + } catch(e) { + console.warn('URL参数解析失败:', e); + } + } + + GetQueryString('vid'); + } catch(e) { + console.warn('URL参数修复失败:', e); + } + // #endif +} \ No newline at end of file diff --git a/utils/h5-router-fix.js b/utils/h5-router-fix.js new file mode 100644 index 0000000..b6049ca --- /dev/null +++ b/utils/h5-router-fix.js @@ -0,0 +1,146 @@ +// H5 路由和环境修复 +// #ifdef H5 + +// 存储原始方法 +let originalGetCurrentPages; +let originalHistoryReplaceState; +let isFixed = false; + +// 修复H5环境路由问题的主函数 +export function fixH5Router() { + if (isFixed) return; + + try { + // 1. 修复 getCurrentPages 方法 + if (typeof getCurrentPages === 'function') { + originalGetCurrentPages = getCurrentPages; + window.getCurrentPages = function() { + try { + const pages = originalGetCurrentPages(); + if (pages && Array.isArray(pages)) { + // 确保每个页面对象有必要的属性 + pages.forEach((page, index) => { + if (!page.route) { + page.route = page.$page?.fullPath || `page_${index}`; + } + if (!page.options) { + page.options = {}; + } + // 确保页面有 meta 属性 + if (page.$page && !page.$page.meta) { + page.$page.meta = {}; + } + }); + } + return pages || []; + } catch(e) { + console.warn('getCurrentPages 执行失败:', e); + return [{ + route: '/', + options: {}, + $page: { meta: {} } + }]; + } + }; + } + + // 2. 修复 History API + if (window.history && window.history.replaceState) { + originalHistoryReplaceState = window.history.replaceState; + window.history.replaceState = function(state, title, url) { + try { + // 修复 URL 格式问题 + if (url && typeof url === 'string') { + // 处理错误的 URL 格式 + if (url.includes('https:/#/')) { + url = url.replace(/https:\/+#\//, window.location.origin + '/#/'); + } + // 确保相对路径的正确性 + if (url.startsWith('#/')) { + url = window.location.origin + window.location.pathname + url; + } + // 处理双斜杠问题 + url = url.replace(/([^:]\/)\/+/g, '$1'); + } + return originalHistoryReplaceState.call(this, state, title, url); + } catch(e) { + console.warn('History.replaceState 修复执行失败:', e); + // 忽略错误,不执行原方法 + return null; + } + }; + } + + // 3. 添加全局错误处理 + const originalOnError = window.onerror; + window.onerror = function(message, source, lineno, colno, error) { + // 过滤已知的H5兼容性错误 + if (typeof message === 'string') { + if (message.includes("Cannot read property 'meta'") || + message.includes('replaceState') || + message.includes('showTabBar') || + message.includes('History')) { + console.warn('H5兼容性错误已忽略:', message); + return true; // 阻止默认错误处理 + } + } + + // 其他错误交给原处理器 + if (originalOnError) { + return originalOnError(message, source, lineno, colno, error); + } + return false; + }; + + // 4. 修复 URL 哈希处理 + if (window.location.hash === '' || window.location.hash === '#') { + window.location.hash = '#/'; + } + + // 5. 监听 hashchange 事件,确保路由正常 + window.addEventListener('hashchange', function(e) { + try { + const hash = window.location.hash; + if (!hash || hash === '#') { + window.location.hash = '#/'; + } + } catch(e) { + console.warn('hashchange 处理失败:', e); + } + }); + + isFixed = true; + console.log('H5 路由修复完成'); + + } catch(e) { + console.warn('H5 路由修复失败:', e); + } +} + +// 恢复原始方法(用于调试) +export function restoreH5Router() { + if (!isFixed) return; + + try { + if (originalGetCurrentPages) { + window.getCurrentPages = originalGetCurrentPages; + } + if (originalHistoryReplaceState) { + window.history.replaceState = originalHistoryReplaceState; + } + + isFixed = false; + console.log('H5 路由修复已恢复'); + } catch(e) { + console.warn('H5 路由恢复失败:', e); + } +} + +// 页面加载完成后自动执行修复 +if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', fixH5Router); +} else { + fixH5Router(); +} + +// #endif \ No newline at end of file diff --git a/utils/share.js b/utils/share.js index 79bf784..c229f0b 100644 --- a/utils/share.js +++ b/utils/share.js @@ -6,7 +6,9 @@ import Vue from 'vue' function share() { //微信分享 //获取签名 let data = { - url: Vue.prototype.$config.redirect + // location.href.split('#')[0]) + // url: Vue.prototype.$config.redirect + '/#/' + url: location.href.split('#')[0] } api('getVipShareSign', data, res => { if (res.code == 200) {