324 lines
9.0 KiB
JavaScript
324 lines
9.0 KiB
JavaScript
// components/popup-notice/popup-notice.js
|
||
import PopupService from '../../services/popupService.js';
|
||
|
||
Component({
|
||
data: {
|
||
// 原有全屏弹窗数据
|
||
visible: false,
|
||
title: '',
|
||
images: [],
|
||
processedImages: [],
|
||
hasImages: false,
|
||
hasTextOnly: false,
|
||
textContent: '',
|
||
duration: 0,
|
||
remainingSeconds: 0,
|
||
muteChecked: false,
|
||
showMuteCheckbox: false,
|
||
isFullscreen: false,
|
||
timer: null,
|
||
|
||
// 悬浮窗相关数据
|
||
isMinimized: false,
|
||
floatX: 20,
|
||
floatY: 200,
|
||
savedRemainingSeconds: 0,
|
||
floatAvatarUrl: '',
|
||
|
||
// 🆕 自定义预览数据
|
||
showCustomPreview: false, // 是否显示自定义预览遮罩
|
||
previewUrls: [], // 当前预览的图片URL列表
|
||
currentPreviewIndex: 0, // 当前预览图片索引
|
||
},
|
||
|
||
lifetimes: {
|
||
detached() {
|
||
this.clearTimer();
|
||
}
|
||
},
|
||
|
||
methods: {
|
||
// ========== 原有所有方法(完全不变,一字不漏) ==========
|
||
async show(config, onCloseCallback) {
|
||
const { title, images, duration, showMuteCheckbox, serverTime } = config;
|
||
this.onCloseCallback = onCloseCallback;
|
||
|
||
let safeImages = JSON.parse(JSON.stringify(images || []));
|
||
const hasImages = safeImages.length > 0;
|
||
let hasTextOnly = false, textContent = '';
|
||
if (!hasImages) {
|
||
hasTextOnly = true;
|
||
textContent = config.text || '暂无内容';
|
||
}
|
||
|
||
this.setData({
|
||
visible: true,
|
||
isMinimized: false,
|
||
title: title || '',
|
||
images: safeImages,
|
||
hasImages,
|
||
hasTextOnly,
|
||
textContent,
|
||
duration: duration || 0,
|
||
remainingSeconds: duration || 0,
|
||
muteChecked: false,
|
||
showMuteCheckbox: showMuteCheckbox || false,
|
||
isFullscreen: false,
|
||
processedImages: [],
|
||
});
|
||
|
||
if (duration > 0) {
|
||
this.startCountdown();
|
||
}
|
||
|
||
if (hasImages) {
|
||
const processed = [];
|
||
const screenWidth = wx.getSystemInfoSync().windowWidth;
|
||
const containerWidth = screenWidth * 0.9;
|
||
const imageWidth = containerWidth - 60;
|
||
for (let i = 0; i < safeImages.length; i++) {
|
||
const img = safeImages[i];
|
||
const fullUrl = this.getFullImageUrl(img.url);
|
||
let imageHeight = 200;
|
||
try {
|
||
const res = await this.getImageInfoPromise(fullUrl);
|
||
const realHeight = (imageWidth * res.height) / res.width;
|
||
imageHeight = realHeight;
|
||
} catch (e) {
|
||
console.error('获取图片信息失败', fullUrl, e);
|
||
}
|
||
processed.push({
|
||
url: fullUrl,
|
||
text: img.text,
|
||
height: imageHeight,
|
||
});
|
||
}
|
||
this.setData({ processedImages: processed });
|
||
}
|
||
},
|
||
|
||
getImageInfoPromise(url) {
|
||
return new Promise((resolve, reject) => {
|
||
wx.getImageInfo({
|
||
src: url,
|
||
success: resolve,
|
||
fail: reject,
|
||
});
|
||
});
|
||
},
|
||
|
||
hide(muteToday = false) {
|
||
this.clearTimer();
|
||
this.setData({
|
||
visible: false,
|
||
isMinimized: false
|
||
});
|
||
if (this.onCloseCallback) {
|
||
this.onCloseCallback({ muteToday });
|
||
}
|
||
},
|
||
|
||
startCountdown() {
|
||
this.clearTimer();
|
||
this.timer = setInterval(() => {
|
||
let sec = this.data.remainingSeconds;
|
||
if (sec <= 1) {
|
||
this.clearTimer();
|
||
this.setData({ remainingSeconds: 0 });
|
||
} else {
|
||
this.setData({ remainingSeconds: sec - 1 });
|
||
}
|
||
}, 1000);
|
||
},
|
||
|
||
clearTimer() {
|
||
if (this.timer) {
|
||
clearInterval(this.timer);
|
||
this.timer = null;
|
||
}
|
||
},
|
||
|
||
onCloseTap() {
|
||
if (this.data.remainingSeconds > 0) {
|
||
wx.showToast({
|
||
title: `请阅读${this.data.remainingSeconds}秒后再关闭`,
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
if (this.data.showMuteCheckbox && this.data.muteChecked) {
|
||
wx.showModal({
|
||
title: '提示',
|
||
content: '今天将不再收到本页面的任何公告,确认吗?',
|
||
success: (res) => {
|
||
if (res.confirm) this.hide(true);
|
||
},
|
||
});
|
||
} else {
|
||
this.hide(false);
|
||
}
|
||
},
|
||
|
||
onMuteChange(e) {
|
||
this.setData({ muteChecked: e.detail.value.length > 0 });
|
||
},
|
||
|
||
// 🆕 替换原有的 onPreviewImage,改用自定义预览(不触发 onShow)
|
||
onCustomPreview(e) {
|
||
const index = e.currentTarget.dataset.index;
|
||
const urls = this.data.processedImages.map(img => img.url);
|
||
this.setData({
|
||
showCustomPreview: true,
|
||
previewUrls: urls,
|
||
currentPreviewIndex: index !== undefined ? index : 0
|
||
});
|
||
},
|
||
|
||
// 🆕 关闭自定义预览
|
||
onCloseCustomPreview() {
|
||
this.setData({
|
||
showCustomPreview: false,
|
||
previewUrls: [],
|
||
currentPreviewIndex: 0
|
||
});
|
||
},
|
||
|
||
// 🆕 swiper 切换事件
|
||
onPreviewSwiperChange(e) {
|
||
this.setData({
|
||
currentPreviewIndex: e.detail.current
|
||
});
|
||
},
|
||
|
||
// 保留原 onPreviewImage 方法以防外部调用,但不再使用
|
||
onPreviewImage(e) {
|
||
// 重定向到自定义预览
|
||
this.onCustomPreview(e);
|
||
},
|
||
|
||
onImageError(e) {
|
||
console.error('图片加载失败:', e.currentTarget.dataset.url);
|
||
},
|
||
|
||
toggleFullscreen() {
|
||
this.setData({ isFullscreen: !this.data.isFullscreen });
|
||
},
|
||
|
||
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;
|
||
},
|
||
|
||
preventMove() {},
|
||
|
||
onMinimize() {
|
||
const remaining = this.data.remainingSeconds;
|
||
this.clearTimer();
|
||
|
||
const app = getApp();
|
||
let avatarUrl = '';
|
||
if (app.globalData.morentouxiang) {
|
||
avatarUrl = app.globalData.morentouxiang;
|
||
} else {
|
||
avatarUrl = '/images/default-avatar.png';
|
||
}
|
||
|
||
if (avatarUrl && !avatarUrl.startsWith('http')) {
|
||
const ossBase = app.globalData.ossImageUrl || '';
|
||
avatarUrl = ossBase.replace(/\/+$/, '') + '/' + avatarUrl.replace(/^\/+/, '');
|
||
}
|
||
|
||
this.setData({
|
||
visible: false,
|
||
isMinimized: true,
|
||
savedRemainingSeconds: remaining,
|
||
floatX: 20,
|
||
floatY: 200,
|
||
floatAvatarUrl: avatarUrl
|
||
});
|
||
},
|
||
|
||
onFloatChange(e) {
|
||
this.setData({
|
||
floatX: e.detail.x,
|
||
floatY: e.detail.y
|
||
});
|
||
},
|
||
|
||
onFloatTap() {
|
||
this.setData({
|
||
visible: true,
|
||
isMinimized: false,
|
||
remainingSeconds: this.data.savedRemainingSeconds
|
||
});
|
||
|
||
if (this.data.duration > 0 && this.data.savedRemainingSeconds > 0) {
|
||
this.startCountdown();
|
||
}
|
||
},
|
||
|
||
onFloatAvatarError() {
|
||
this.setData({
|
||
floatAvatarUrl: '/images/avatar-placeholder.png'
|
||
});
|
||
},
|
||
|
||
cleanup() {
|
||
this.clearTimer();
|
||
this.setData({
|
||
visible: false,
|
||
isMinimized: false
|
||
});
|
||
PopupService.reset();
|
||
},
|
||
|
||
onFloatTouchStart(e) {
|
||
const touch = e.touches[0];
|
||
this.touchStartX = touch.clientX;
|
||
this.touchStartY = touch.clientY;
|
||
this.startFloatX = this.data.floatX;
|
||
this.startFloatY = this.data.floatY;
|
||
this.hasMoved = false;
|
||
return false;
|
||
},
|
||
|
||
onFloatTouchMove(e) {
|
||
const touch = e.touches[0];
|
||
const deltaX = touch.clientX - this.touchStartX;
|
||
const deltaY = touch.clientY - this.touchStartY;
|
||
|
||
if (Math.abs(deltaX) > 5 || Math.abs(deltaY) > 5) {
|
||
this.hasMoved = true;
|
||
}
|
||
|
||
let newX = this.startFloatX + deltaX;
|
||
let newY = this.startFloatY + deltaY;
|
||
|
||
const systemInfo = wx.getSystemInfoSync();
|
||
const screenWidth = systemInfo.windowWidth;
|
||
const screenHeight = systemInfo.windowHeight;
|
||
const estimatedSize = 60;
|
||
|
||
newX = Math.max(0, Math.min(newX, screenWidth - estimatedSize));
|
||
newY = Math.max(0, Math.min(newY, screenHeight - estimatedSize));
|
||
this.setData({ floatX: newX, floatY: newY });
|
||
|
||
return false;
|
||
},
|
||
|
||
onFloatTouchEnd(e) {
|
||
if (!this.hasMoved) {
|
||
this.onFloatTap();
|
||
}
|
||
return false;
|
||
},
|
||
|
||
// 🆕 阻止事件冒泡(用于预览遮罩内部点击不关闭)
|
||
stopPropagation() {}
|
||
}
|
||
}); |