155 lines
6.6 KiB
JavaScript
155 lines
6.6 KiB
JavaScript
// src/js/tools/baiduHotTool.js
|
||
import BaseTool from '../baseTool.js';
|
||
|
||
class BaiduHotTool extends BaseTool {
|
||
constructor() {
|
||
super('baidu-hot', '百度热搜');
|
||
this.abortController = null;
|
||
// 定义分榜信息
|
||
this.boards = [
|
||
{ id: 'hot-search', name: '热搜榜' },
|
||
{ id: 'hot-meme', name: '热梗榜' },
|
||
{ id: 'finance', name: '财经榜' },
|
||
{ id: 'livelihood', name: '民生榜' },
|
||
];
|
||
}
|
||
|
||
render() {
|
||
return `
|
||
<div class="page-container" style="display: flex; flex-direction: column; height: 100%;">
|
||
<div class="section-header">
|
||
<button id="back-to-toolbox-btn" class="back-btn ripple"><i class="fas fa-arrow-left"></i> 返回工具箱</button>
|
||
<h1 style="flex-grow: 1; text-align: center;">${this.name}</h1>
|
||
</div>
|
||
<div class="sys-info-tabs baidu-hot-tabs" id="baidu-hot-tabs">
|
||
${this.boards.map(board => `
|
||
<button class="sys-info-tab" data-board-name="${board.name}">${board.name}</button>
|
||
`).join('')}
|
||
</div>
|
||
<div id="baidu-hot-results-container" class="content-area" style="padding: 0 20px 10px 10px; flex-grow: 1; overflow-y: auto;">
|
||
<div class="loading-container">
|
||
<img src="./assets/loading.gif" alt="加载中..." class="loading-gif">
|
||
<p class="loading-text">正在加载热搜...</p>
|
||
</div>
|
||
</div>
|
||
</div>`;
|
||
}
|
||
|
||
init() {
|
||
this._log('工具已初始化');
|
||
document.getElementById('back-to-toolbox-btn')?.addEventListener('click', () => {
|
||
window.mainPage.navigateTo('toolbox');
|
||
window.mainPage.updateActiveNavButton(document.getElementById('toolbox-btn'));
|
||
});
|
||
|
||
const tabs = document.querySelectorAll('#baidu-hot-tabs .sys-info-tab');
|
||
tabs.forEach(tab => {
|
||
tab.addEventListener('click', (e) => {
|
||
tabs.forEach(t => t.classList.remove('active'));
|
||
e.currentTarget.classList.add('active');
|
||
const boardName = e.currentTarget.dataset.boardName;
|
||
this._fetchAndRenderData(boardName);
|
||
});
|
||
});
|
||
|
||
// 默认加载第一个榜单
|
||
if (tabs.length > 0) {
|
||
tabs[0].click();
|
||
}
|
||
}
|
||
|
||
async _fetchAndRenderData(boardName) {
|
||
if (this.abortController) this.abortController.abort();
|
||
this.abortController = new AbortController();
|
||
|
||
const resultsContainer = document.getElementById('baidu-hot-results-container');
|
||
if (!resultsContainer) return;
|
||
|
||
resultsContainer.innerHTML = `
|
||
<div class="loading-container">
|
||
<img src="./assets/loading.gif" alt="加载中..." class="loading-gif">
|
||
<p class="loading-text">正在加载 ${boardName}...</p>
|
||
</div>`;
|
||
|
||
try {
|
||
const apiUrl = `https://api.suyanw.cn/api/bdrs.php?msg=${encodeURIComponent(boardName)}`;
|
||
const response = await fetch(apiUrl, { signal: this.abortController.signal });
|
||
if (!response.ok) throw new Error(`网络请求失败: ${response.status}`);
|
||
|
||
const blob = await response.blob();
|
||
await window.electronAPI.addTraffic(blob.size);
|
||
const textData = await blob.text();
|
||
|
||
this._log(`成功获取 ${boardName} 数据`);
|
||
this._renderList(textData);
|
||
} catch (error) {
|
||
if (error.name === 'AbortError') return;
|
||
const errorMessage = error.message.includes('API') ? error.message : `解析数据失败或网络异常`;
|
||
this._log(`获取 ${boardName} 失败: ${errorMessage}`);
|
||
resultsContainer.innerHTML = `<div class="loading-container"><p class="error-message"><i class="fas fa-exclamation-triangle"></i> 获取失败: ${errorMessage}</p></div>`;
|
||
}
|
||
}
|
||
|
||
_renderList(textData) {
|
||
const resultsContainer = document.getElementById('baidu-hot-results-container');
|
||
const lines = textData.split('\n').filter(line => line.trim() !== '' && !line.startsWith('----'));
|
||
|
||
if (lines.length === 0) {
|
||
throw new Error('API返回数据为空或格式无法解析');
|
||
}
|
||
|
||
// [修复] 改为使用 Flex 布局的 div 结构 (灵动岛风格),而非之前的 table
|
||
const itemsHtml = lines.map((line, index) => {
|
||
const match = line.match(/^(\d+):(.*)/);
|
||
if (!match) return '';
|
||
|
||
const rank = match[1];
|
||
const title = match[2].trim();
|
||
const searchUrl = `https://www.baidu.com/s?wd=${encodeURIComponent(title)}`;
|
||
|
||
let rankClass = '';
|
||
let iconClass = 'fa-fire';
|
||
let iconColor = 'var(--text-secondary)';
|
||
|
||
if (rank <= 3) {
|
||
rankClass = `rank-top-3 rank-${rank}`; // 复用 hotboardTool 的样式
|
||
iconClass = 'fa-fire-alt';
|
||
iconColor = 'var(--error-color)';
|
||
}
|
||
|
||
// 使用 island-card 样式 (在 style.css 中已定义)
|
||
return `
|
||
<div class="island-card ripple" style="height: auto; min-height: 60px; margin-bottom: 10px; padding: 15px;" data-link="${searchUrl}">
|
||
<div class="island-icon-box" style="width: 40px; height: 40px; border-radius: 10px; background: rgba(var(--bg-color-rgb), 0.5);">
|
||
<span class="hotboard-rank ${rankClass}" style="margin: 0; font-size: 16px;">${rank}</span>
|
||
</div>
|
||
|
||
<div class="island-content" style="flex-grow: 1; padding-left: 15px;">
|
||
<h3 class="island-title" style="margin: 0; white-space: normal;">${title}</h3>
|
||
</div>
|
||
|
||
<div class="island-action">
|
||
<i class="fas fa-chevron-right arrow-icon"></i>
|
||
</div>
|
||
</div>
|
||
`;
|
||
}).join('');
|
||
|
||
resultsContainer.innerHTML = `<div style="animation: contentFadeIn 0.5s;">${itemsHtml}</div>`;
|
||
|
||
resultsContainer.querySelectorAll('.island-card[data-link]').forEach(card => {
|
||
card.addEventListener('click', (e) => {
|
||
e.preventDefault();
|
||
window.electronAPI.openExternalLink(e.currentTarget.dataset.link);
|
||
});
|
||
});
|
||
}
|
||
|
||
destroy() {
|
||
if (this.abortController) this.abortController.abort();
|
||
this._log('工具已销毁');
|
||
super.destroy();
|
||
}
|
||
}
|
||
|
||
export default BaiduHotTool; |