2025-05-02 22:39:27 +08:00
|
|
|
|
// 广告位配置
|
|
|
|
|
|
const AD_POSITIONS = {
|
|
|
|
|
|
'home-banner-1': {
|
|
|
|
|
|
id: 'home-banner-1',
|
|
|
|
|
|
title: '首页顶部Banner广告位1',
|
2025-05-02 22:42:38 +08:00
|
|
|
|
image: 'https://www.zmt.wiki',
|
2025-05-02 22:39:27 +08:00
|
|
|
|
dimensions: '1200×200px',
|
|
|
|
|
|
prices: {
|
|
|
|
|
|
monthly: 250,
|
|
|
|
|
|
yearly: 500
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
'home-banner-2': {
|
|
|
|
|
|
id: 'home-banner-2',
|
|
|
|
|
|
title: '首页顶部Banner广告位2',
|
2025-05-02 22:42:38 +08:00
|
|
|
|
image: 'https://www.zmt.wiki',
|
2025-05-02 22:39:27 +08:00
|
|
|
|
dimensions: '1200×200px',
|
|
|
|
|
|
prices: {
|
|
|
|
|
|
monthly: 250,
|
|
|
|
|
|
yearly: 500
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
'home-sidebar': {
|
|
|
|
|
|
id: 'home-sidebar',
|
|
|
|
|
|
title: '首页侧边栏广告位',
|
2025-05-02 22:42:38 +08:00
|
|
|
|
image: 'https://www.zmt.wiki',
|
2025-05-02 22:39:27 +08:00
|
|
|
|
dimensions: '300×600px',
|
|
|
|
|
|
prices: {
|
|
|
|
|
|
yearly: 300
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
'category-top': {
|
|
|
|
|
|
id: 'category-top',
|
|
|
|
|
|
title: '分类页置顶广告位',
|
2025-05-02 22:42:38 +08:00
|
|
|
|
image: 'https://www.zmt.wiki',
|
2025-05-02 22:39:27 +08:00
|
|
|
|
dimensions: '800×150px',
|
|
|
|
|
|
prices: {
|
|
|
|
|
|
monthly: 100
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
'article-end': {
|
|
|
|
|
|
id: 'article-end',
|
|
|
|
|
|
title: '文末广告位',
|
2025-05-02 22:42:38 +08:00
|
|
|
|
image: 'https://www.zmt.wiki',
|
2025-05-02 22:39:27 +08:00
|
|
|
|
dimensions: '600×300px',
|
|
|
|
|
|
prices: {
|
|
|
|
|
|
yearly: 200
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
'url-top': {
|
|
|
|
|
|
id: 'url-top',
|
|
|
|
|
|
title: '网址置顶推荐',
|
2025-05-02 22:42:38 +08:00
|
|
|
|
image: 'https://www.zmt.wiki',
|
2025-05-02 22:39:27 +08:00
|
|
|
|
dimensions: '800×100px',
|
|
|
|
|
|
prices: {
|
|
|
|
|
|
monthly: 200,
|
|
|
|
|
|
yearly: 500
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 访问量数据(从API获取)
|
|
|
|
|
|
let visitData = {
|
|
|
|
|
|
today_uv: 0,
|
|
|
|
|
|
today_pv: 0,
|
|
|
|
|
|
yesterday_uv: 0,
|
|
|
|
|
|
yesterday_pv: 0,
|
|
|
|
|
|
last_month_pv: 0,
|
|
|
|
|
|
last_year_pv: 0
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 访问量价格系数配置
|
|
|
|
|
|
const VISIT_COEFFICIENTS = {
|
|
|
|
|
|
'low': { min: 0, max: 30000, coefficient: 0.8 }, // 低访问量,价格打8折
|
|
|
|
|
|
'medium': { min: 30001, max: 60000, coefficient: 1 }, // 中等访问量,原价
|
|
|
|
|
|
'high': { min: 60001, max: 100000, coefficient: 1.2 }, // 高访问量,价格上浮20%
|
|
|
|
|
|
'veryHigh': { min: 100001, max: Infinity, coefficient: 1.5 } // 极高访问量,价格上浮50%
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 广告位预订状态(实际项目中应该从数据库获取)
|
|
|
|
|
|
const BOOKED_STATUS = {
|
|
|
|
|
|
'home-banner-1': {
|
|
|
|
|
|
isBooked: false,
|
|
|
|
|
|
endDate: null
|
|
|
|
|
|
},
|
|
|
|
|
|
'home-banner-2': {
|
|
|
|
|
|
isBooked: false,
|
|
|
|
|
|
endDate: null
|
|
|
|
|
|
},
|
|
|
|
|
|
'home-sidebar': {
|
|
|
|
|
|
isBooked: true,
|
|
|
|
|
|
endDate: new Date('2026-12-31').toISOString()
|
|
|
|
|
|
},
|
|
|
|
|
|
'category-top': {
|
|
|
|
|
|
isBooked: false,
|
|
|
|
|
|
endDate: null
|
|
|
|
|
|
},
|
|
|
|
|
|
'article-end': {
|
|
|
|
|
|
isBooked: false,
|
|
|
|
|
|
endDate: null
|
|
|
|
|
|
},
|
|
|
|
|
|
'url-top': {
|
|
|
|
|
|
isBooked: false,
|
|
|
|
|
|
endDate: null
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 生成广告位HTML
|
|
|
|
|
|
function generateAdCardHtml(adId, adConfig) {
|
|
|
|
|
|
const status = BOOKED_STATUS[adId];
|
|
|
|
|
|
const isBooked = status.isBooked;
|
|
|
|
|
|
const endDate = status.endDate ? new Date(status.endDate) : null;
|
|
|
|
|
|
|
|
|
|
|
|
let statusHtml = '<span class="status-available">可预订</span>';
|
|
|
|
|
|
if (isBooked && endDate) {
|
|
|
|
|
|
const formattedDate = endDate.toLocaleDateString('zh-CN', {
|
|
|
|
|
|
year: 'numeric',
|
|
|
|
|
|
month: 'long',
|
|
|
|
|
|
day: 'numeric'
|
|
|
|
|
|
});
|
|
|
|
|
|
statusHtml = `
|
|
|
|
|
|
<span class="status-booked">
|
|
|
|
|
|
已预订
|
|
|
|
|
|
<span class="end-date">到期时间:${formattedDate}</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let priceHtml = '';
|
|
|
|
|
|
if (adConfig.prices.monthly) {
|
|
|
|
|
|
priceHtml += `<p>月付价格:<span id="${adId}-monthly">计算中...</span> 元/月</p>`;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (adConfig.prices.yearly) {
|
|
|
|
|
|
priceHtml += `<p>年付价格:<span id="${adId}-yearly">计算中...</span> 元/年</p>`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let bookingButtons = '';
|
|
|
|
|
|
if (!isBooked) {
|
|
|
|
|
|
if (adConfig.prices.monthly && adConfig.prices.yearly) {
|
|
|
|
|
|
bookingButtons = `
|
|
|
|
|
|
<div class="booking-options">
|
|
|
|
|
|
<button class="book-btn" onclick="bookAd('${adId}', 'monthly')">月付预订</button>
|
|
|
|
|
|
<button class="book-btn" onclick="bookAd('${adId}', 'yearly')">年付预订</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
`;
|
|
|
|
|
|
} else if (adConfig.prices.monthly) {
|
|
|
|
|
|
bookingButtons = `<button class="book-btn" onclick="bookAd('${adId}', 'monthly')">月付预订</button>`;
|
|
|
|
|
|
} else if (adConfig.prices.yearly) {
|
|
|
|
|
|
bookingButtons = `<button class="book-btn" onclick="bookAd('${adId}', 'yearly')">年付预订</button>`;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return `
|
|
|
|
|
|
<div class="ad-card" id="${adId}">
|
|
|
|
|
|
<h2>${adConfig.title}</h2>
|
|
|
|
|
|
<div class="ad-preview">
|
|
|
|
|
|
<a href="${adConfig.image}" target="_blank">
|
|
|
|
|
|
<img src="${adConfig.image}" alt="${adConfig.title}预览" class="preview-img">
|
|
|
|
|
|
<div class="preview-overlay">
|
|
|
|
|
|
<span class="preview-hint">点击查看大图</span>
|
|
|
|
|
|
<div class="ad-dimensions">尺寸:${adConfig.dimensions}</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="ad-stats">
|
|
|
|
|
|
${priceHtml}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="ad-status" id="${adId}-status">
|
|
|
|
|
|
${statusHtml}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
${bookingButtons}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化广告位
|
|
|
|
|
|
function initAdPositions() {
|
|
|
|
|
|
const adPositionsContainer = document.querySelector('.ad-positions');
|
|
|
|
|
|
if (!adPositionsContainer) return;
|
|
|
|
|
|
|
|
|
|
|
|
let html = '';
|
|
|
|
|
|
Object.entries(AD_POSITIONS).forEach(([adId, adConfig]) => {
|
|
|
|
|
|
html += generateAdCardHtml(adId, adConfig);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
adPositionsContainer.innerHTML = html;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取访问量数据
|
2025-08-17 14:49:06 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 获取访问量数据(带超时和重试机制)
|
|
|
|
|
|
* @param {number} timeout 超时时间(毫秒)
|
|
|
|
|
|
* @param {number} retries 重试次数
|
|
|
|
|
|
* @returns {Promise<boolean>} 是否成功获取数据
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function fetchVisitData(timeout = 10000, retries = 2) {
|
|
|
|
|
|
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
console.log(`正在获取访问量数据... (尝试 ${attempt + 1}/${retries + 1})`);
|
|
|
|
|
|
|
|
|
|
|
|
// 创建带超时的fetch请求
|
|
|
|
|
|
const controller = new AbortController();
|
|
|
|
|
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
|
|
|
|
|
|
|
|
|
|
const response = await fetch('info.php', {
|
|
|
|
|
|
signal: controller.signal,
|
|
|
|
|
|
cache: 'no-cache'
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
clearTimeout(timeoutId);
|
|
|
|
|
|
|
|
|
|
|
|
if (!response.ok) {
|
|
|
|
|
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const data = await response.json();
|
|
|
|
|
|
|
|
|
|
|
|
// 验证数据完整性
|
|
|
|
|
|
if (data && typeof data.last_month_pv === 'number') {
|
|
|
|
|
|
visitData = data;
|
|
|
|
|
|
console.log('访问量数据获取成功:', visitData);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
throw new Error('返回数据格式不正确');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.warn(`获取访问量数据失败 (尝试 ${attempt + 1}/${retries + 1}):`, error.message);
|
|
|
|
|
|
|
|
|
|
|
|
// 如果是最后一次尝试,记录错误但不抛出异常
|
|
|
|
|
|
if (attempt === retries) {
|
|
|
|
|
|
console.error('所有重试均失败,将使用基础价格');
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 等待一段时间后重试
|
|
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 1000 * (attempt + 1)));
|
2025-05-02 22:39:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-08-17 14:49:06 +08:00
|
|
|
|
return false;
|
2025-05-02 22:39:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 根据访问量获取价格系数
|
|
|
|
|
|
function getPriceCoefficient(monthlyPV) {
|
|
|
|
|
|
for (const [key, range] of Object.entries(VISIT_COEFFICIENTS)) {
|
|
|
|
|
|
if (monthlyPV >= range.min && monthlyPV <= range.max) {
|
|
|
|
|
|
return range.coefficient;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return 1; // 默认系数
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算实际价格
|
|
|
|
|
|
function calculateActualPrice(basePrice, monthlyPV) {
|
|
|
|
|
|
const coefficient = getPriceCoefficient(monthlyPV);
|
|
|
|
|
|
return Math.round(basePrice * coefficient);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-17 14:49:06 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 显示基础价格(不依赖API数据)
|
|
|
|
|
|
*/
|
|
|
|
|
|
function showBasePrices() {
|
|
|
|
|
|
console.log('显示基础价格...');
|
|
|
|
|
|
Object.entries(AD_POSITIONS).forEach(([adId, adConfig]) => {
|
|
|
|
|
|
const prices = adConfig.prices;
|
|
|
|
|
|
|
|
|
|
|
|
// 显示月付基础价格
|
|
|
|
|
|
if (prices.monthly) {
|
|
|
|
|
|
const monthlyElement = document.getElementById(`${adId}-monthly`);
|
|
|
|
|
|
if (monthlyElement) {
|
|
|
|
|
|
monthlyElement.textContent = prices.monthly.toLocaleString();
|
|
|
|
|
|
monthlyElement.classList.add('base-price');
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 显示年付基础价格
|
|
|
|
|
|
if (prices.yearly) {
|
|
|
|
|
|
const yearlyElement = document.getElementById(`${adId}-yearly`);
|
|
|
|
|
|
if (yearlyElement) {
|
|
|
|
|
|
yearlyElement.textContent = prices.yearly.toLocaleString();
|
|
|
|
|
|
yearlyElement.classList.add('base-price');
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 显示价格加载状态
|
|
|
|
|
|
*/
|
|
|
|
|
|
function showPriceLoading() {
|
|
|
|
|
|
console.log('显示价格加载状态...');
|
|
|
|
|
|
Object.entries(AD_POSITIONS).forEach(([adId, adConfig]) => {
|
|
|
|
|
|
const prices = adConfig.prices;
|
|
|
|
|
|
|
|
|
|
|
|
if (prices.monthly) {
|
|
|
|
|
|
const monthlyElement = document.getElementById(`${adId}-monthly`);
|
|
|
|
|
|
if (monthlyElement) {
|
|
|
|
|
|
monthlyElement.innerHTML = '<span class="loading-price">计算中...</span>';
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (prices.yearly) {
|
|
|
|
|
|
const yearlyElement = document.getElementById(`${adId}-yearly`);
|
|
|
|
|
|
if (yearlyElement) {
|
|
|
|
|
|
yearlyElement.innerHTML = '<span class="loading-price">计算中...</span>';
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 更新所有广告位的价格显示(实时价格)
|
|
|
|
|
|
*/
|
2025-05-02 22:39:27 +08:00
|
|
|
|
function updateAllAdPrices() {
|
2025-08-17 14:49:06 +08:00
|
|
|
|
console.log('开始更新实时价格...');
|
2025-05-02 22:39:27 +08:00
|
|
|
|
try {
|
|
|
|
|
|
Object.entries(AD_POSITIONS).forEach(([adId, adConfig]) => {
|
|
|
|
|
|
const prices = adConfig.prices;
|
|
|
|
|
|
|
|
|
|
|
|
// 更新月付价格显示
|
|
|
|
|
|
if (prices.monthly) {
|
|
|
|
|
|
const monthlyElement = document.getElementById(`${adId}-monthly`);
|
|
|
|
|
|
if (monthlyElement) {
|
|
|
|
|
|
const actualPrice = calculateActualPrice(prices.monthly, visitData.last_month_pv);
|
|
|
|
|
|
monthlyElement.textContent = actualPrice.toLocaleString();
|
2025-08-17 14:49:06 +08:00
|
|
|
|
monthlyElement.classList.remove('base-price', 'loading-price');
|
|
|
|
|
|
monthlyElement.classList.add('real-time-price');
|
2025-05-02 22:39:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新年付价格显示
|
|
|
|
|
|
if (prices.yearly) {
|
|
|
|
|
|
const yearlyElement = document.getElementById(`${adId}-yearly`);
|
|
|
|
|
|
if (yearlyElement) {
|
|
|
|
|
|
const actualPrice = calculateActualPrice(prices.yearly, visitData.last_month_pv);
|
|
|
|
|
|
yearlyElement.textContent = actualPrice.toLocaleString();
|
2025-08-17 14:49:06 +08:00
|
|
|
|
yearlyElement.classList.remove('base-price', 'loading-price');
|
|
|
|
|
|
yearlyElement.classList.add('real-time-price');
|
2025-05-02 22:39:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2025-08-17 14:49:06 +08:00
|
|
|
|
console.log('实时价格更新完成');
|
2025-05-02 22:39:27 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('更新价格时出错:', error);
|
2025-08-17 14:49:06 +08:00
|
|
|
|
// 如果更新失败,回退到基础价格
|
|
|
|
|
|
showBasePrices();
|
2025-05-02 22:39:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理广告预订
|
|
|
|
|
|
function bookAd(adPosition, paymentType) {
|
|
|
|
|
|
const status = BOOKED_STATUS[adPosition];
|
|
|
|
|
|
if (status.isBooked) {
|
|
|
|
|
|
alert('该广告位已被预订,请选择其他广告位或等待到期后再预订。');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const adConfig = AD_POSITIONS[adPosition];
|
|
|
|
|
|
const basePrice = adConfig.prices[paymentType];
|
|
|
|
|
|
|
|
|
|
|
|
if (!basePrice) {
|
|
|
|
|
|
alert('该广告位不支持此支付方式');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const actualPrice = calculateActualPrice(basePrice, visitData.last_month_pv);
|
|
|
|
|
|
const duration = paymentType === 'yearly' ? 365 : 30;
|
|
|
|
|
|
const confirmMessage = `您选择的广告位:${adConfig.title}\n支付方式:${paymentType === 'yearly' ? '年付' : '月付'}\n总价格:${actualPrice}元\n\n是否确认预订?`;
|
|
|
|
|
|
|
|
|
|
|
|
if (confirm(confirmMessage)) {
|
|
|
|
|
|
// 计算到期时间
|
|
|
|
|
|
const endDate = new Date();
|
|
|
|
|
|
endDate.setDate(endDate.getDate() + duration);
|
|
|
|
|
|
|
|
|
|
|
|
// 更新预订状态
|
|
|
|
|
|
BOOKED_STATUS[adPosition] = {
|
|
|
|
|
|
isBooked: true,
|
|
|
|
|
|
endDate: endDate.toISOString()
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 重新生成广告位卡片
|
|
|
|
|
|
const adCard = document.getElementById(adPosition);
|
|
|
|
|
|
if (adCard) {
|
|
|
|
|
|
adCard.outerHTML = generateAdCardHtml(adPosition, adConfig);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
alert('预订成功!我们的客服人员将尽快与您联系。');
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 图片预览功能
|
|
|
|
|
|
function initImagePreview() {
|
|
|
|
|
|
const modal = document.getElementById('previewModal');
|
|
|
|
|
|
const modalImg = modal.querySelector('.preview-modal-img');
|
|
|
|
|
|
const modalTitle = modal.querySelector('.preview-modal-title');
|
|
|
|
|
|
const modalDimensions = modal.querySelector('.preview-modal-dimensions');
|
|
|
|
|
|
const closeBtn = modal.querySelector('.preview-close');
|
|
|
|
|
|
|
|
|
|
|
|
// 确保模态框初始状态正确
|
|
|
|
|
|
modal.style.display = 'none';
|
|
|
|
|
|
|
|
|
|
|
|
// 点击预览图打开模态框
|
|
|
|
|
|
document.querySelectorAll('.preview-img').forEach(img => {
|
|
|
|
|
|
img.addEventListener('click', function() {
|
|
|
|
|
|
const card = this.closest('.ad-card');
|
|
|
|
|
|
const title = card.querySelector('h2').textContent;
|
|
|
|
|
|
const dimensions = card.querySelector('.ad-dimensions').textContent;
|
|
|
|
|
|
|
|
|
|
|
|
modalImg.src = this.src;
|
|
|
|
|
|
modalTitle.textContent = title;
|
|
|
|
|
|
modalDimensions.textContent = dimensions;
|
|
|
|
|
|
|
|
|
|
|
|
// 显示模态框
|
|
|
|
|
|
modal.style.display = 'flex';
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
modal.classList.add('show');
|
|
|
|
|
|
}, 10);
|
|
|
|
|
|
|
|
|
|
|
|
// 禁用滚动
|
|
|
|
|
|
document.body.style.overflow = 'hidden';
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 点击关闭按钮
|
|
|
|
|
|
closeBtn.addEventListener('click', function() {
|
|
|
|
|
|
modal.classList.remove('show');
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
modal.style.display = 'none';
|
|
|
|
|
|
document.body.style.overflow = '';
|
|
|
|
|
|
}, 300);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 点击模态框背景关闭
|
|
|
|
|
|
modal.addEventListener('click', function(e) {
|
|
|
|
|
|
if (e.target === modal) {
|
|
|
|
|
|
modal.classList.remove('show');
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
modal.style.display = 'none';
|
|
|
|
|
|
document.body.style.overflow = '';
|
|
|
|
|
|
}, 300);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 按ESC键关闭
|
|
|
|
|
|
document.addEventListener('keydown', function(e) {
|
|
|
|
|
|
if (e.key === 'Escape' && modal.classList.contains('show')) {
|
|
|
|
|
|
modal.classList.remove('show');
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
modal.style.display = 'none';
|
|
|
|
|
|
document.body.style.overflow = '';
|
|
|
|
|
|
}, 300);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理联系表单提交
|
|
|
|
|
|
document.querySelector('.contact-form').addEventListener('submit', function(e) {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
|
|
|
|
|
|
const formData = new FormData(this);
|
|
|
|
|
|
const data = Object.fromEntries(formData.entries());
|
|
|
|
|
|
|
|
|
|
|
|
// 这里可以添加表单验证逻辑
|
|
|
|
|
|
|
|
|
|
|
|
// 模拟表单提交
|
|
|
|
|
|
alert('感谢您的咨询!我们的客服人员将尽快与您联系。');
|
|
|
|
|
|
this.reset();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 确保页面完全加载后再执行
|
2025-08-17 14:49:06 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 页面初始化函数
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function initializePage() {
|
|
|
|
|
|
console.log('开始初始化页面...');
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 立即初始化广告位和显示基础价格
|
2025-05-02 22:39:27 +08:00
|
|
|
|
initAdPositions();
|
2025-08-17 14:49:06 +08:00
|
|
|
|
showBasePrices();
|
|
|
|
|
|
console.log('基础价格显示完成');
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 显示加载状态并异步获取实时数据
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
showPriceLoading();
|
|
|
|
|
|
|
|
|
|
|
|
// 异步获取访问量数据并更新价格
|
|
|
|
|
|
fetchVisitData(15000, 3).then(success => {
|
|
|
|
|
|
if (success) {
|
|
|
|
|
|
updateAllAdPrices();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 如果获取失败,回退到基础价格
|
|
|
|
|
|
console.log('API获取失败,显示基础价格');
|
|
|
|
|
|
showBasePrices();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}, 100); // 短暂延迟确保基础价格先显示
|
2025-05-02 22:39:27 +08:00
|
|
|
|
|
2025-08-17 14:49:06 +08:00
|
|
|
|
// 3. 设置定期更新(每5分钟)
|
2025-05-02 22:39:27 +08:00
|
|
|
|
setInterval(async () => {
|
2025-08-17 14:49:06 +08:00
|
|
|
|
console.log('定期更新访问量数据...');
|
|
|
|
|
|
const success = await fetchVisitData(10000, 1);
|
|
|
|
|
|
if (success) {
|
|
|
|
|
|
updateAllAdPrices();
|
|
|
|
|
|
}
|
2025-05-02 22:39:27 +08:00
|
|
|
|
}, 5 * 60 * 1000);
|
2025-08-17 14:49:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 使用DOMContentLoaded而不是window.onload,提前初始化
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
|
|
console.log('DOM加载完成,开始初始化...');
|
|
|
|
|
|
initializePage();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 保留window.onload作为备用(防止DOMContentLoaded未触发)
|
|
|
|
|
|
window.addEventListener('load', function() {
|
|
|
|
|
|
// 检查是否已经初始化过
|
|
|
|
|
|
if (!document.querySelector('.ad-positions').hasChildNodes()) {
|
|
|
|
|
|
console.log('备用初始化触发...');
|
|
|
|
|
|
initializePage();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|