From bf7cb7ec01d57256d9460f50c86cf9e0ed1252e5 Mon Sep 17 00:00:00 2001 From: wk Date: Thu, 5 Mar 2026 19:04:23 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=AE=A2=E5=8D=95=E5=8A=A0=E4=BA=8C?= =?UTF-8?q?=E7=BB=B4=E7=A0=81icon=E5=92=8C=E5=BC=B9=E7=AA=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App.vue | 26 ++- api/index.js | 13 +- api/service.js | 11 +- pages/detail/serviceDetail.vue | 2 +- pages/profile/profile.vue | 107 ++++++++--- pages/profileSub/serviceRecords.vue | 265 ++++++++++++++++++++++++++-- static/home/qr_code_icon.png | Bin 0 -> 3501 bytes 7 files changed, 364 insertions(+), 60 deletions(-) create mode 100644 static/home/qr_code_icon.png diff --git a/App.vue b/App.vue index 7609ea9..e58073c 100644 --- a/App.vue +++ b/App.vue @@ -102,38 +102,31 @@ }, 100) } }, - // 启动轮询支付状态 + // 启动轮询支付状态:回到小程序立马查一次,失败则每隔 3 秒再查,最多再查 3 次(共 4 次) startOrderStatusPolling(orderNumber) { - // 避免重复轮询 if (this._orderStatusTimer) { clearInterval(this._orderStatusTimer); this._orderStatusTimer = null; } let times = 0; - const maxTimes = 5; // 最多轮询 20 次,大约 1 分钟 + const maxTimes = 4; // 立即 1 次 + 最多再查 3 次 - this._orderStatusTimer = setInterval(async () => { + const doCheck = async () => { times++; try { const res = await updateLuOrderPayStatus({ orderNumber }); - // 约定:接口有返回数据即认为支付成功 if (res) { clearInterval(this._orderStatusTimer); this._orderStatusTimer = null; - // 成功后清理本地缓存的订单号 uni.removeStorageSync("lastOrderNumber"); - - uni.showToast({ - title: '支付成功', - icon: 'success' - }); - - // 跳转到服务记录页面,默认展示「待核销」tab + uni.showToast({ title: '支付成功', icon: 'success' }); uni.navigateTo({ url: '/pages/profileSub/serviceRecords?tab=pending_verification' }); - } else if (times >= maxTimes) { + return; + } + if (times >= maxTimes) { clearInterval(this._orderStatusTimer); this._orderStatusTimer = null; uni.showToast({ @@ -149,7 +142,10 @@ this._orderStatusTimer = null; } } - }, 3000); + }; + + doCheck(); // 回到小程序立马查一次 + this._orderStatusTimer = setInterval(doCheck, 3000); // 失败则每 3 秒再查,最多再查 3 次 } } } diff --git a/api/index.js b/api/index.js index 72dee5f..6dbefdf 100644 --- a/api/index.js +++ b/api/index.js @@ -4,8 +4,8 @@ */ // 基础URL配置(注意:末尾不要加斜杠) -// const BASE_URL = 'https://guangsh.manage.hschengtai.com' -const BASE_URL = 'http://192.168.5.134:48085' +const BASE_URL = 'https://guangsh.manage.hschengtai.com' +// const BASE_URL = 'http://192.168.5.134:48085' // 是否正在刷新token(防止并发刷新) let isRefreshing = false // 等待刷新完成的请求队列 @@ -366,12 +366,15 @@ export function request(options = {}) { uni.hideLoading() } - // 网络错误处理 + // 网络错误处理(真机/预览时域名未配置会报 domain 相关错误) let errorMsg = '网络请求失败' if (err.errMsg) { - if (err.errMsg.includes('timeout')) { + const em = err.errMsg + if (em.includes('timeout')) { errorMsg = '请求超时,请检查网络' - } else if (err.errMsg.includes('fail')) { + } else if (em.includes('domain') || em.includes('url not in')) { + errorMsg = '请在小程序后台配置服务器域名' + } else if (em.includes('fail')) { errorMsg = '网络连接失败,请检查网络设置' } } diff --git a/api/service.js b/api/service.js index 5175dae..eafd498 100644 --- a/api/service.js +++ b/api/service.js @@ -161,11 +161,16 @@ export function getMyOrderPage(params = {}){ }) } -// 删除订单 -export function deleteOrder(id){ +// 删除订单(id 为 Query 参数,拼在 URL 上) +export function deleteOrder(params = {}) { + const id = params.id + const url = id !== undefined && id !== '' + ? `/app-api/member/lu-order/delete?id=${encodeURIComponent(id)}` + : '/app-api/member/lu-order/delete' return request({ - url: '/app-api/member/lu-order/delete?id='+id, + url, method: 'DELETE', + data: {}, }) } diff --git a/pages/detail/serviceDetail.vue b/pages/detail/serviceDetail.vue index d8fac4a..5da61c3 100644 --- a/pages/detail/serviceDetail.vue +++ b/pages/detail/serviceDetail.vue @@ -61,7 +61,7 @@ {{ item.discount }}折 - {{ item.description }} + 现价¥ diff --git a/pages/profile/profile.vue b/pages/profile/profile.vue index d8fa8c9..1746854 100644 --- a/pages/profile/profile.vue +++ b/pages/profile/profile.vue @@ -7,11 +7,7 @@ - + @@ -128,6 +136,22 @@ export default { uploading: false, // 是否正在上传头像 }; }, + computed: { + avatarSrc() { + const v = this.userInfo.avatar; + return (v && typeof v === "string") ? v : "/static/tabbar/profile.png"; + }, + memberLevelIcon() { + const icon = this.userInfo.level && this.userInfo.level.icon; + return (icon && typeof icon === "string") ? icon : "/static/tabbar/profile.png"; + }, + userCardBgImage() { + const url = this.userInfo.level && this.userInfo.level.backgroundUrl; + return (url && typeof url === "string") + ? `url(${url})` + : "url(/static/profile/member-card-bg.png)"; + }, + }, onLoad() { this.getSystemInfo(); this.updateTime(); @@ -264,12 +288,10 @@ export default { // 选择头像(微信小程序使用 chooseAvatar,其他平台使用 chooseImage) handleChooseAvatar(e) { // #ifdef MP-WEIXIN - // 微信小程序新版本使用 chooseAvatar if (e.detail && e.detail.avatarUrl) { - const avatarUrl = e.detail.avatarUrl; - // 先显示本地预览 + const avatarUrl = typeof e.detail.avatarUrl === "string" ? e.detail.avatarUrl : String(e.detail.avatarUrl || ""); + if (!avatarUrl) return; this.userInfo.avatar = avatarUrl; - // 上传头像 this.uploadAvatar(avatarUrl); } // #endif @@ -282,22 +304,43 @@ export default { sourceType: ["album", "camera"], success: (res) => { const tempFilePath = res.tempFilePaths[0]; - // 先显示本地预览 this.userInfo.avatar = tempFilePath; - // 上传头像 this.uploadAvatar(tempFilePath); }, fail: (err) => { console.error("选择图片失败:", err); - uni.showToast({ - title: "选择图片失败", - icon: "none", - }); + uni.showToast({ title: "选择图片失败", icon: "none" }); }, }); // #endif }, + // 微信内:昵称输入框失焦时保存昵称(input type="nickname" 会弹出微信昵称选项) + handleNicknameBlur(e) { + const nickname = (e.detail && e.detail.value) ? String(e.detail.value).trim() : ""; + if (nickname) { + this.userInfo.nickname = nickname; + uni.setStorageSync("userInfo", this.userInfo); + this.updateUserNickname(nickname); + uni.showToast({ title: "昵称已更新", icon: "success" }); + } + }, + // 非微信环境点击昵称提示 + handleNicknameClickNonWeixin() { + uni.showToast({ + title: "请在微信中打开以修改昵称", + icon: "none", + }); + }, + // 同步昵称到后端(若后端有更新接口可在此调用) + async updateUserNickname(nickname) { + try { + // 若有更新用户信息接口可在此调用,例如:await updateUserInfo({ nickname }); + } catch (err) { + console.error("更新昵称失败:", err); + } + }, + // 上传头像 uploadAvatar(filePath) { if (this.uploading) { @@ -365,11 +408,10 @@ export default { fail: (err) => { uni.hideLoading(); console.error("上传头像失败:", err); - uni.showToast({ - title: "上传失败,请检查网络", - icon: "none", - }); - // 上传失败,恢复原头像 + const msg = (err && err.errMsg && err.errMsg.indexOf("ENOENT") !== -1) + ? "模拟器暂不支持更换头像,请使用真机预览" + : "上传失败,请检查网络"; + uni.showToast({ title: msg, icon: "none", duration: 2500 }); this.loadUserInfo(); }, complete: () => { @@ -501,6 +543,19 @@ export default { color: #333333; } + .nickname-input { + font-family: PingFang-SC, PingFang-SC; + font-weight: bold; + font-size: 32rpx; + color: #333333; + padding: 0; + margin: 0; + height: 44rpx; + line-height: 44rpx; + background: transparent; + width: 100%; + } + .user-id { font-family: PingFang-SC, PingFang-SC; font-weight: 500; diff --git a/pages/profileSub/serviceRecords.vue b/pages/profileSub/serviceRecords.vue index 68af6fa..a9306b0 100644 --- a/pages/profileSub/serviceRecords.vue +++ b/pages/profileSub/serviceRecords.vue @@ -90,20 +90,37 @@ mode="aspectFill" > - {{ goods.couponName || goods.name }} + {{ + goods.couponName || goods.name + }} - ¥{{ formatFen(goods.salePrice) }} + ¥{{ formatFen(goods.salePrice) }} ×{{ goods.num || goods.count || goods.quantity || goods.qty }} + + + @@ -111,7 +128,9 @@ 实付款: - ¥{{ formatFen(item.payableAmount) }} + ¥{{ formatFen(item.payableAmount) }} @@ -151,7 +170,7 @@ @@ -166,12 +185,44 @@ 上拉加载更多 + + + + + + + 核销码 + + {{ getQrUseStatusText(qrModalData.useStatus) }} + + × + + + + + + + 暂无券码 + + + @@ -717,6 +834,16 @@ export default { } } } + + .qr-code-icon-wrapper { + flex-shrink: 0; + padding: 12rpx; + margin-left: 8rpx; + } + .qr-code-icon { + width: 44rpx; + height: 44rpx; + } } } @@ -787,4 +914,122 @@ export default { } } } + +/* 券码二维码弹窗 */ +.qr-modal-mask { + position: fixed; + left: 0; + right: 0; + top: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + z-index: 900; +} +.qr-modal-wrap { + position: fixed; + left: 0; + right: 0; + top: 0; + bottom: 0; + z-index: 901; + display: flex; + align-items: center; + justify-content: center; + padding: 36rpx; + box-sizing: border-box; +} +.qr-modal { + width: 100%; + max-width: 720rpx; + background: #ffffff; + border-radius: 28rpx; + overflow: hidden; + box-shadow: 0 8rpx 40rpx rgba(0, 0, 0, 0.15); +} +.qr-modal-header { + position: relative; + padding: 40rpx 32rpx 28rpx; + border-bottom: 1rpx solid #f0f0f0; + display: flex; + align-items: center; + justify-content: center; + flex-wrap: wrap; + gap: 16rpx; +} +.qr-modal-title { + font-family: PingFang-SC, PingFang-SC; + font-weight: 600; + font-size: 36rpx; + color: #1a1819; +} +.qr-modal-status { + padding: 8rpx 20rpx; + border-radius: 24rpx; + font-family: PingFang-SC, PingFang-SC; + font-weight: 500; + font-size: 24rpx; + &.status-unused { + background: rgba(0, 66, 148, 0.1); + color: #004294; + } + &.status-used { + background: rgba(158, 158, 158, 0.15); + color: #9e9e9e; + } + &.status-refund { + background: rgba(76, 175, 80, 0.1); + color: #4caf50; + } + &.status-cancelled { + background: rgba(158, 158, 158, 0.15); + color: #9e9e9e; + } +} +.qr-modal-close { + position: absolute; + right: 20rpx; + top: 50%; + transform: translateY(-50%); + width: 56rpx; + height: 56rpx; + display: flex; + align-items: center; + justify-content: center; + font-size: 44rpx; + color: #999999; + line-height: 1; +} +.qr-modal-body { + padding: 48rpx 32rpx 56rpx; + display: flex; + flex-direction: column; + align-items: center; +} +.qr-code-box { + display: flex; + flex-direction: column; + align-items: center; +} +.qr-code-image { + width: 520rpx; + height: 520rpx; + background: #fff; + border: 2rpx solid #e8e8e8; + border-radius: 20rpx; + margin-bottom: 28rpx; +} +.qr-code-text { + font-family: PingFang-SC, PingFang-SC; + font-weight: 500; + font-size: 26rpx; + color: #333333; + word-break: break-all; + text-align: center; + padding: 0 20rpx; +} +.qr-code-empty { + font-family: PingFang-SC, PingFang-SC; + font-size: 28rpx; + color: #999999; +} diff --git a/static/home/qr_code_icon.png b/static/home/qr_code_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..0fa839c7de76a39c5d66e4d53f03ac2908031ea3 GIT binary patch literal 3501 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