From 0067a63093e25db8cfc90755f926bb53b13dfbd0 Mon Sep 17 00:00:00 2001 From: XingQue Date: Mon, 27 Jul 2026 05:17:38 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=8A=A2=E5=8D=95=E6=B1=A0=E5=BC=B9?= =?UTF-8?q?=E7=AA=97=E7=AD=89=20OSS=20=E5=B0=B1=E7=BB=AA=E5=86=8D=E6=8B=BC?= =?UTF-8?q?=E5=9B=BE=EF=BC=8C=E9=81=BF=E5=85=8D=E7=9B=B8=E5=AF=B9=20URL=20?= =?UTF-8?q?=E7=A9=BA=E7=99=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- app.js | 12 +- components/popup-notice/popup-notice.js | 132 +++++++++++++++++----- components/popup-notice/popup-notice.wxml | 10 +- pages/accept-order/accept-order.js | 37 +++++- pages/accept-order/accept-order.json | 3 +- 5 files changed, 152 insertions(+), 42 deletions(-) diff --git a/app.js b/app.js index 88696f9..5067b79 100644 --- a/app.js +++ b/app.js @@ -216,6 +216,12 @@ App({ refreshDashouMembership(this).catch(() => {}); } + // ③ 先应用本地缓存配置(必须在 reLaunch 抢单池之前,否则弹窗图片拼不出 OSS) + const cachedConfig = this.readConfigFromStorage(); + if (cachedConfig) { + this.applyDynamicConfig(cachedConfig); + } + // 纯打手端:未登录必进登录页;已认证进抢单池 const targetPage = isFighterOnly() ? resolveFighterOnlyLaunchUrl() @@ -226,12 +232,6 @@ App({ }, 0); } - // ③ 应用本地缓存配置 - const cachedConfig = this.readConfigFromStorage(); - if (cachedConfig) { - this.applyDynamicConfig(cachedConfig); - } - // ④ 初始化 this.initGoEasyWithConfig(); // 只有appkey有效时才真正初始化 ChatCore.initGlobalMessageSystem(this); diff --git a/components/popup-notice/popup-notice.js b/components/popup-notice/popup-notice.js index 0c1cfc3..59919a0 100644 --- a/components/popup-notice/popup-notice.js +++ b/components/popup-notice/popup-notice.js @@ -41,15 +41,24 @@ Component({ async show(config, onCloseCallback) { const { title, images, duration, showMuteCheckbox, serverTime } = config; this.onCloseCallback = onCloseCallback; - + this._showToken = (this._showToken || 0) + 1; + const token = this._showToken; + let safeImages = JSON.parse(JSON.stringify(images || [])); + // 兼容 url / image_url + safeImages = safeImages.map((img) => ({ + ...img, + url: img.url || img.image_url || '', + text: img.text || '', + })).filter((img) => !!img.url); + const hasImages = safeImages.length > 0; let hasTextOnly = false, textContent = ''; if (!hasImages) { hasTextOnly = true; textContent = config.text || '暂无内容'; } - + this.setData({ visible: true, isMinimized: false, @@ -65,34 +74,91 @@ Component({ isFullscreen: false, processedImages: [], }); - + if (duration > 0) { this.startCountdown(); } - - if (hasImages) { - const screenWidth = wx.getSystemInfoSync().windowWidth; - const containerWidth = Math.min(screenWidth * 0.86, 310); - const imageWidth = Math.max(containerWidth - 30, 200); - // 先立刻用默认高度展示,避免 getImageInfo 慢/失败时空白 - const processed = safeImages.map((img) => ({ - url: this.getFullImageUrl(img.url), - text: img.text, - height: 280, - })); - this.setData({ processedImages: processed }); - for (let i = 0; i < processed.length; i++) { - const fullUrl = processed[i].url; - try { - const res = await this.getImageInfoPromise(fullUrl); - const realHeight = (imageWidth * res.height) / res.width; - this.setData({ [`processedImages[${i}].height`]: realHeight }); - } catch (e) { - console.error('获取图片信息失败', fullUrl, e); - } + + if (!hasImages) return; + + // 等 OSS 域名就绪再拼接,避免相对路径导致整图空白 + await this.ensureOssBase(4000); + if (token !== this._showToken) return; + + const processed = safeImages.map((img) => ({ + url: this.getFullImageUrl(img.url), + text: img.text, + height: 0, + })); + console.log('[popup-notice] 图片URL:', processed.map((p) => p.url)); + this.setData({ processedImages: processed }); + + // 可选:量真实高度(失败也不影响 widthFix 展示) + const screenWidth = wx.getSystemInfoSync().windowWidth; + const containerWidth = Math.min(screenWidth * 0.86, 310); + const imageWidth = Math.max(containerWidth - 30, 200); + for (let i = 0; i < processed.length; i++) { + if (token !== this._showToken) return; + const fullUrl = processed[i].url; + if (!fullUrl || !/^https?:\/\//.test(fullUrl)) { + console.error('[popup-notice] OSS未就绪或URL非法', fullUrl); + continue; + } + try { + const res = await this.getImageInfoPromise(fullUrl); + const realHeight = (imageWidth * res.height) / res.width; + this.setData({ [`processedImages[${i}].height`]: realHeight }); + } catch (e) { + console.error('获取图片信息失败', fullUrl, e); } } }, + + /** 等待 / 回读本地缓存,确保能拼出完整 COS 地址 */ + ensureOssBase(timeoutMs = 3000) { + const app = getApp(); + const readOss = () => this.resolveOssBase(); + if (readOss()) return Promise.resolve(readOss()); + + return new Promise((resolve) => { + let done = false; + const finish = () => { + if (done) return; + done = true; + if (app.off) app.off('configApplied', onCfg); + clearInterval(timer); + clearTimeout(timerOut); + resolve(readOss()); + }; + const onCfg = () => finish(); + if (app.on) app.on('configApplied', onCfg); + const timer = setInterval(() => { + if (readOss()) finish(); + }, 100); + const timerOut = setTimeout(finish, timeoutMs); + // 主动再读一次缓存配置 + try { + if (typeof app.readConfigFromStorage === 'function') { + const cached = app.readConfigFromStorage(); + if (cached && app.applyDynamicConfig) app.applyDynamicConfig(cached); + } + } catch (e) {} + if (readOss()) finish(); + }); + }, + + resolveOssBase() { + const app = getApp(); + let base = (app.globalData && app.globalData.ossImageUrl) || ''; + if (!base && app && typeof app.readConfigFromStorage === 'function') { + try { + const cached = app.readConfigFromStorage(); + base = (cached && cached.cos && cached.cos.ossImageUrl) || ''; + if (base && app.globalData) app.globalData.ossImageUrl = base; + } catch (e) {} + } + return base || ''; + }, getImageInfoPromise(url) { return new Promise((resolve, reject) => { @@ -202,12 +268,18 @@ Component({ getFullImageUrl(relativeUrl) { if (!relativeUrl) return ''; - if (relativeUrl.startsWith('http')) return relativeUrl; - const app = getApp(); - let base = app.globalData.ossImageUrl || ''; - base = base.replace(/\/+$/, ''); - const clean = relativeUrl.replace(/^\/+/, ''); - return base ? base + '/' + clean : clean; + if (relativeUrl.startsWith('http://') || relativeUrl.startsWith('https://')) { + return relativeUrl; + } + // 后端 cos.ossImageUrl 带尾斜杠;相对路径不带前导 / + let base = this.resolveOssBase(); + if (!base) { + console.warn('[popup-notice] ossImageUrl 为空,无法拼接', relativeUrl); + return ''; + } + if (!base.endsWith('/')) base += '/'; + const clean = String(relativeUrl).replace(/^\/+/, ''); + return base + clean; }, preventMove() {}, diff --git a/components/popup-notice/popup-notice.wxml b/components/popup-notice/popup-notice.wxml index 5c20321..29645b7 100644 --- a/components/popup-notice/popup-notice.wxml +++ b/components/popup-notice/popup-notice.wxml @@ -25,15 +25,17 @@ {{item.text}} - diff --git a/pages/accept-order/accept-order.js b/pages/accept-order/accept-order.js index 77b20dc..0812f16 100644 --- a/pages/accept-order/accept-order.js +++ b/pages/accept-order/accept-order.js @@ -136,12 +136,42 @@ Page({ this._skipShowRefresh = true; }, - tryShowAcceptOrderPopup() { + async tryShowAcceptOrderPopup() { + if (app.globalData._acceptOrderPopupDone) return; + // 先确保 OSS 配置已加载,再拉弹窗(否则相对 URL 拼不出图) + await this.ensureOssReadyForPopup(4000); if (app.globalData._acceptOrderPopupDone) return; app.globalData._acceptOrderPopupDone = true; PopupService.checkAndShow(this, 'jiedan'); }, + ensureOssReadyForPopup(timeoutMs = 3000) { + const hasOss = () => !!(app.globalData && app.globalData.ossImageUrl); + if (hasOss()) return Promise.resolve(true); + try { + const cached = app.readConfigFromStorage && app.readConfigFromStorage(); + if (cached && app.applyDynamicConfig) { + app.applyDynamicConfig(cached); + } + } catch (e) {} + if (hasOss()) return Promise.resolve(true); + return new Promise((resolve) => { + let finished = false; + const done = () => { + if (finished) return; + finished = true; + if (app.off) app.off('configApplied', onCfg); + clearInterval(poll); + clearTimeout(to); + resolve(hasOss()); + }; + const onCfg = () => done(); + if (app.on) app.on('configApplied', onCfg); + const poll = setInterval(() => { if (hasOss()) done(); }, 100); + const to = setTimeout(done, timeoutMs); + }); + }, + persistPageCache(extra = {}) { const d = this.data; app.globalData._acceptOrderPageCache = { @@ -160,6 +190,11 @@ Page({ }, onHide: function () { + // 只释放 PopupService 锁,不强制关掉正在展示的弹窗内容(避免刚拼好 URL 就被清掉) + PopupService.reset(); + }, + + onUnload: function () { const popupComp = this.selectComponent('#popupNotice'); if (popupComp && popupComp.cleanup) { popupComp.cleanup(); diff --git a/pages/accept-order/accept-order.json b/pages/accept-order/accept-order.json index 8be2c01..f8cbf7f 100644 --- a/pages/accept-order/accept-order.json +++ b/pages/accept-order/accept-order.json @@ -9,6 +9,7 @@ "usingComponents": { "chenghao-tag": "/components/chenghao-tag/chenghao-tag", "global-notification": "/components/global-notification/global-notification", - "kefu-float": "/components/kefu-float/kefu-float" + "kefu-float": "/components/kefu-float/kefu-float", + "popup-notice": "/components/popup-notice/popup-notice" } }