fix: 抢单池弹窗等 OSS 就绪再拼图,避免相对 URL 空白

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQueandCursor committed 2026-07-27 05:17:38 +08:00
1 parent 7eca128bb5
commit 0067a63093
5 files changed
+152 -42

No files matched your search

+6 -6
View File
@@ -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);
+102 -30
View File
@@ -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() {},
+6 -4
View File
@@ -25,15 +25,17 @@
<view wx:for="{{processedImages}}" wx:key="index" class="image-block">
<view wx:if="{{item.text}}" class="block-text">{{item.text}}</view>
<view class="image-padding">
<image
class="block-image"
src="{{item.url}}"
style="width:100%; height:{{item.height}}px; display:block;"
<image
class="block-image"
src="{{item.url}}"
mode="widthFix"
style="width:100%; {{item.height > 0 ? 'height:' + item.height + 'px;' : ''}} display:block;"
data-index="{{index}}"
data-url="{{item.url}}"
bindtap="onCustomPreview"
binderror="onImageError"
lazy-load="{{false}}"
show-menu-by-longpress="{{true}}"
/>
</view>
</view>
+36 -1
View File
@@ -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();
+2 -1
View File
@@ -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"
}
}