509 lines
17 KiB
JavaScript
509 lines
17 KiB
JavaScript
|
|
// 全局变量
|
|||
|
|
let isTaskRunning = false;
|
|||
|
|
let currentSection = 'home';
|
|||
|
|
let taskCheckInterval;
|
|||
|
|
const API_BASE_URL = 'http://localhost:8080/api'; // API基础地址
|
|||
|
|
|
|||
|
|
// DOM加载完成后初始化
|
|||
|
|
$(document).ready(function() {
|
|||
|
|
showSection('home');
|
|||
|
|
console.log('✅ 微信公众号文章爬虫系统已加载');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 显示指定区域
|
|||
|
|
function showSection(sectionName) {
|
|||
|
|
// 隐藏所有区域
|
|||
|
|
$('.section').hide();
|
|||
|
|
$('.feature-cards').hide();
|
|||
|
|
|
|||
|
|
if (sectionName === 'home') {
|
|||
|
|
$('.feature-cards').show();
|
|||
|
|
currentSection = 'home';
|
|||
|
|
} else {
|
|||
|
|
$('#section-' + sectionName).show();
|
|||
|
|
currentSection = sectionName;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 提取公众号主页相关函数
|
|||
|
|
function extractHomepage() {
|
|||
|
|
const articleUrl = $('#homepage-url').val().trim();
|
|||
|
|
|
|||
|
|
if (!articleUrl) {
|
|||
|
|
showResult('homepage', 'error', '请输入文章链接');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!articleUrl.includes('mp.weixin.qq.com')) {
|
|||
|
|
showResult('homepage', 'error', '请输入有效的微信公众号文章链接');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (isTaskRunning) {
|
|||
|
|
showResult('homepage', 'error', '有任务正在执行,请稍候...');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
isTaskRunning = true;
|
|||
|
|
showResult('homepage', 'loading', '正在提取公众号主页链接...');
|
|||
|
|
|
|||
|
|
// 调用后端API
|
|||
|
|
$.ajax({
|
|||
|
|
url: `${API_BASE_URL}/homepage/extract`,
|
|||
|
|
method: 'POST',
|
|||
|
|
contentType: 'application/json',
|
|||
|
|
data: JSON.stringify({ url: articleUrl }),
|
|||
|
|
success: function(response) {
|
|||
|
|
isTaskRunning = false;
|
|||
|
|
if (response.success && response.data && response.data.homepage) {
|
|||
|
|
const homepageUrl = response.data.homepage;
|
|||
|
|
const safeUrl = homepageUrl.replace(/'/g, "\\'");
|
|||
|
|
const resultHtml = `
|
|||
|
|
<div style="background: #f8f9fa; padding: 15px; border-radius: 8px; margin-top: 10px;">
|
|||
|
|
<h4 style="color: #28a745; margin-bottom: 10px;">✅ 提取成功</h4>
|
|||
|
|
<p><strong>公众号主页链接:</strong></p>
|
|||
|
|
<div style="background: white; padding: 10px; border: 1px solid #ddd; border-radius: 4px; word-break: break-all; font-family: monospace; font-size: 0.9em;">
|
|||
|
|
${homepageUrl}
|
|||
|
|
</div>
|
|||
|
|
<div style="margin-top: 15px;">
|
|||
|
|
<button class="btn btn-info" onclick="copyToClipboard('${safeUrl}')" style="margin-right: 10px;">📋 复制链接</button>
|
|||
|
|
<button class="btn btn-warning" onclick="openInNewTab('${safeUrl}')">🔗 打开主页</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
`;
|
|||
|
|
showResult('homepage', 'success', resultHtml);
|
|||
|
|
} else {
|
|||
|
|
showResult('homepage', 'error', response.message || '提取失败');
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
error: function(xhr, status, error) {
|
|||
|
|
isTaskRunning = false;
|
|||
|
|
let errorMsg = '请求失败:' + error;
|
|||
|
|
if (xhr.status === 0) {
|
|||
|
|
errorMsg = '无法连接到后端服务器,请确保 API 服务器已启动(运行 api_server.exe)';
|
|||
|
|
}
|
|||
|
|
showResult('homepage', 'error', errorMsg);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 生成模拟的公众号主页链接
|
|||
|
|
function generateMockHomepageUrl(articleUrl) {
|
|||
|
|
// 从文章链接中提取__biz参数来模拟真实的主页链接
|
|||
|
|
const bizMatch = articleUrl.match(/__biz=([^&]+)/);
|
|||
|
|
if (bizMatch) {
|
|||
|
|
const biz = bizMatch[1];
|
|||
|
|
return `https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=${biz}&scene=124`;
|
|||
|
|
}
|
|||
|
|
// 如果无法提取,返回示例链接
|
|||
|
|
return 'https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=MzI1NjEwMTM4OA==&scene=124';
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function loadExampleUrl() {
|
|||
|
|
const exampleUrl = 'https://mp.weixin.qq.com/s?__biz=MzI1NjEwMTM4OA==&mid=2651232405&idx=1&sn=7c8f5b2e3d4a1b9c8e7f6a5b4c3d2e1f&chksm=f1d7e8c4c6a061d2b9e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0&scene=27';
|
|||
|
|
|
|||
|
|
$('#homepage-url').val(exampleUrl);
|
|||
|
|
showResult('homepage', 'info', '已加载文章链接示例,点击"提取主页链接"开始处理');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 打开链接的辅助函数
|
|||
|
|
function openInNewTab(url) {
|
|||
|
|
window.open(url, '_blank');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 下载单篇文章
|
|||
|
|
function downloadSingleArticle() {
|
|||
|
|
alert('此功能需要后端命令行支持。\n\n请使用命令行程序:\n1. 运行 wechat-crawler.exe\n2. 选择对应功能进行下载');
|
|||
|
|
showResult('single', 'info', '请使用命令行程序执行下载功能');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取文章列表
|
|||
|
|
function getArticleList() {
|
|||
|
|
const accessToken = $('#access-token').val().trim();
|
|||
|
|
const pages = parseInt($('#pages').val()) || 0;
|
|||
|
|
|
|||
|
|
if (!accessToken) {
|
|||
|
|
showResult('list', 'error', '请输入Access Token URL');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (isTaskRunning) {
|
|||
|
|
showResult('list', 'error', '有任务正在执行,请稍候...');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
isTaskRunning = true;
|
|||
|
|
showResult('list', 'loading', '正在获取文章列表,请稍候...');
|
|||
|
|
|
|||
|
|
// 调用后端API(同步等待)
|
|||
|
|
$.ajax({
|
|||
|
|
url: `${API_BASE_URL}/article/list`,
|
|||
|
|
method: 'POST',
|
|||
|
|
contentType: 'application/json',
|
|||
|
|
data: JSON.stringify({ access_token: accessToken, pages: pages }),
|
|||
|
|
success: function(response) {
|
|||
|
|
isTaskRunning = false;
|
|||
|
|
if (response.success && response.data) {
|
|||
|
|
const data = response.data;
|
|||
|
|
const fileExt = data.filename.endsWith('.txt') ? 'TXT文件' : 'Excel文件';
|
|||
|
|
const resultHtml = `
|
|||
|
|
<div style="background: #f8f9fa; padding: 15px; border-radius: 8px; margin-top: 10px;">
|
|||
|
|
<h4 style="color: #28a745; margin-bottom: 10px;">✅ 获取成功</h4>
|
|||
|
|
<p><strong>公众号:</strong>${data.account}</p>
|
|||
|
|
<p><strong>文件:</strong>${data.filename}</p>
|
|||
|
|
<div style="margin-top: 15px;">
|
|||
|
|
<a href="${API_BASE_URL}${data.download}" class="btn btn-success" download>📥 下载${fileExt}</a>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
`;
|
|||
|
|
showResult('list', 'success', resultHtml);
|
|||
|
|
|
|||
|
|
// 自动触发下载
|
|||
|
|
window.location.href = `${API_BASE_URL}${data.download}`;
|
|||
|
|
} else {
|
|||
|
|
showResult('list', 'error', response.message || '获取失败');
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
error: function(xhr, status, error) {
|
|||
|
|
isTaskRunning = false;
|
|||
|
|
let errorMsg = '请求失败:' + error;
|
|||
|
|
if (xhr.status === 0) {
|
|||
|
|
errorMsg = '无法连接到后端服务器,请确保 API 服务器已启动';
|
|||
|
|
} else if (xhr.responseJSON && xhr.responseJSON.message) {
|
|||
|
|
errorMsg = xhr.responseJSON.message;
|
|||
|
|
}
|
|||
|
|
showResult('list', 'error', errorMsg);
|
|||
|
|
},
|
|||
|
|
timeout: 120000 // 2分钟超时
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 批量下载文章
|
|||
|
|
function batchDownload() {
|
|||
|
|
const officialAccount = $('#official-account').val().trim();
|
|||
|
|
const saveImage = $('#batch-save-image').is(':checked');
|
|||
|
|
const saveContent = $('#batch-save-content').is(':checked');
|
|||
|
|
|
|||
|
|
if (!officialAccount) {
|
|||
|
|
showResult('batch', 'error', '请输入公众号名称或文章链接');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (isTaskRunning) {
|
|||
|
|
showResult('batch', 'error', '有任务正在执行,请稍候...');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
isTaskRunning = true;
|
|||
|
|
showResult('batch', 'loading', '正在批量下载文章,请稍候...');
|
|||
|
|
|
|||
|
|
// 调用后端API(同步等待)
|
|||
|
|
$.ajax({
|
|||
|
|
url: `${API_BASE_URL}/article/batch`,
|
|||
|
|
method: 'POST',
|
|||
|
|
contentType: 'application/json',
|
|||
|
|
data: JSON.stringify({
|
|||
|
|
official_account: officialAccount,
|
|||
|
|
save_image: saveImage,
|
|||
|
|
save_content: saveContent
|
|||
|
|
}),
|
|||
|
|
success: function(response) {
|
|||
|
|
isTaskRunning = false;
|
|||
|
|
if (response.success && response.data) {
|
|||
|
|
const data = response.data;
|
|||
|
|
const resultHtml = `
|
|||
|
|
<div style="background: #f8f9fa; padding: 15px; border-radius: 8px; margin-top: 10px;">
|
|||
|
|
<h4 style="color: #28a745; margin-bottom: 10px;">✅ ${response.message}</h4>
|
|||
|
|
<p><strong>公众号:</strong>${data.account}</p>
|
|||
|
|
<p><strong>文章数量:</strong>${data.articleCount} 篇</p>
|
|||
|
|
<p><strong>保存路径:</strong>${data.path}</p>
|
|||
|
|
<div style="margin-top: 15px;">
|
|||
|
|
<button class="btn btn-info" onclick="loadDataList()">📊 查看数据列表</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
`;
|
|||
|
|
showResult('batch', 'success', resultHtml);
|
|||
|
|
} else {
|
|||
|
|
showResult('batch', 'error', response.message || '批量下载失败');
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
error: function(xhr, status, error) {
|
|||
|
|
isTaskRunning = false;
|
|||
|
|
let errorMsg = '请求失败:' + error;
|
|||
|
|
if (xhr.status === 0) {
|
|||
|
|
errorMsg = '无法连接到后端服务器,请确保 API 服务器已启动';
|
|||
|
|
} else if (xhr.responseJSON && xhr.responseJSON.message) {
|
|||
|
|
errorMsg = xhr.responseJSON.message;
|
|||
|
|
}
|
|||
|
|
showResult('batch', 'error', errorMsg);
|
|||
|
|
},
|
|||
|
|
timeout: 300000 // 5分钟超时
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 加载数据列表
|
|||
|
|
function loadDataList() {
|
|||
|
|
showResult('data', 'loading', '正在加载数据列表...');
|
|||
|
|
|
|||
|
|
// 调用后端API
|
|||
|
|
$.ajax({
|
|||
|
|
url: `${API_BASE_URL}/data/list`,
|
|||
|
|
method: 'GET',
|
|||
|
|
success: function(response) {
|
|||
|
|
if (response.success && response.data) {
|
|||
|
|
displayDataList(response.data);
|
|||
|
|
hideResult('data');
|
|||
|
|
} else {
|
|||
|
|
showResult('data', 'error', '加载失败');
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
error: function(xhr, status, error) {
|
|||
|
|
let errorMsg = '请求失败:' + error;
|
|||
|
|
if (xhr.status === 0) {
|
|||
|
|
errorMsg = '无法连接到后端服务器,请确保 API 服务器已启动';
|
|||
|
|
}
|
|||
|
|
showResult('data', 'error', errorMsg);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 显示数据列表
|
|||
|
|
function displayDataList(dataList) {
|
|||
|
|
let html = '';
|
|||
|
|
|
|||
|
|
if (!dataList || dataList.length === 0) {
|
|||
|
|
html = '<p class="text-center" style="padding: 20px; color: #666;">暂无数据,请先使用其他功能爬取文章</p>';
|
|||
|
|
} else {
|
|||
|
|
dataList.forEach(item => {
|
|||
|
|
const safeItemName = (item.name || '').replace(/'/g, "\\'");
|
|||
|
|
const safeItemPath = (item.path || '').replace(/'/g, "\\'").replace(/\\/g, '\\\\');
|
|||
|
|
html += `
|
|||
|
|
<div class="data-item">
|
|||
|
|
<h4><span class="status-indicator status-success"></span>${item.name || '未知'}</h4>
|
|||
|
|
<div class="data-item-info">
|
|||
|
|
<div class="data-item-stats">
|
|||
|
|
<div class="stat-item">
|
|||
|
|
<span>📊</span>
|
|||
|
|
<span>${item.articleCount || 0} 篇文章</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="stat-item">
|
|||
|
|
<span>📅</span>
|
|||
|
|
<span>${item.lastUpdate || '未知'}</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="stat-item">
|
|||
|
|
<span>📁</span>
|
|||
|
|
<span>${item.path || '未知'}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="data-item-actions">
|
|||
|
|
<button class="btn btn-info" onclick="viewArticles('${safeItemName}')">查看文章</button>
|
|||
|
|
<button class="btn btn-warning" onclick="alert('文件夹路径:${safeItemPath}')">查看路径</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
`;
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$('#data-list').html(html);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 查看文章列表
|
|||
|
|
function viewArticles(accountName) {
|
|||
|
|
alert(`查看 ${accountName} 的文章列表
|
|||
|
|
|
|||
|
|
这里将展示该公众号的所有文章,包括:
|
|||
|
|
- 文章标题
|
|||
|
|
- 发布时间
|
|||
|
|
- 文件大小
|
|||
|
|
- 下载状态等`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 打开文件夹
|
|||
|
|
function openFolder(path) {
|
|||
|
|
alert(`打开文件夹: ${path}\n\n在实际环境中,这里会调用系统命令打开文件资源管理器。`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 打开数据文件夹
|
|||
|
|
function openDataFolder() {
|
|||
|
|
alert('打开数据文件夹\n\n在实际环境中,这里会打开data目录。');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 任务管理函数
|
|||
|
|
function startTask(section, message) {
|
|||
|
|
isTaskRunning = true;
|
|||
|
|
showResult(section, 'loading', message);
|
|||
|
|
|
|||
|
|
// 显示进度条
|
|||
|
|
const resultDiv = $(`#${section}-result`);
|
|||
|
|
resultDiv.append(`
|
|||
|
|
<div class="progress-container">
|
|||
|
|
<div class="progress-bar">
|
|||
|
|
<div class="progress-fill"></div>
|
|||
|
|
</div>
|
|||
|
|
<div class="progress-text">0%</div>
|
|||
|
|
</div>
|
|||
|
|
`);
|
|||
|
|
|
|||
|
|
// 禁用相关按钮
|
|||
|
|
disableButtons();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function updateTaskProgress(percent, message) {
|
|||
|
|
const progressFill = $('.progress-fill');
|
|||
|
|
const progressText = $('.progress-text');
|
|||
|
|
|
|||
|
|
progressFill.css('width', percent + '%');
|
|||
|
|
progressText.text(Math.floor(percent) + '% - ' + message);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function endTask(section, type, message) {
|
|||
|
|
isTaskRunning = false;
|
|||
|
|
|
|||
|
|
// 移除进度条
|
|||
|
|
$('.progress-container').remove();
|
|||
|
|
|
|||
|
|
showResult(section, type, message);
|
|||
|
|
enableButtons();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function disableButtons() {
|
|||
|
|
$('.btn').prop('disabled', true).addClass('disabled');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function enableButtons() {
|
|||
|
|
$('.btn').prop('disabled', false).removeClass('disabled');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 结果显示函数
|
|||
|
|
function showResult(section, type, message) {
|
|||
|
|
const resultDiv = $(`#${section}-result`);
|
|||
|
|
resultDiv.removeClass('success error info loading')
|
|||
|
|
.addClass(type)
|
|||
|
|
.html(getResultIcon(type) + message)
|
|||
|
|
.show();
|
|||
|
|
|
|||
|
|
// 自动滚动到结果区域
|
|||
|
|
resultDiv[0].scrollIntoView({ behavior: 'smooth' });
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function hideResult(section) {
|
|||
|
|
$(`#${section}-result`).hide();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function getResultIcon(type) {
|
|||
|
|
switch (type) {
|
|||
|
|
case 'success': return '<span class="loading-spinner" style="display:none;"></span>✅ ';
|
|||
|
|
case 'error': return '<span class="loading-spinner" style="display:none;"></span>❌ ';
|
|||
|
|
case 'info': return '<span class="loading-spinner" style="display:none;"></span>ℹ️ ';
|
|||
|
|
case 'loading': return '<span class="loading-spinner"></span>';
|
|||
|
|
default: return '';
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 表单验证函数
|
|||
|
|
function validateUrl(url) {
|
|||
|
|
try {
|
|||
|
|
new URL(url);
|
|||
|
|
return true;
|
|||
|
|
} catch {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function validateInput(value, type) {
|
|||
|
|
switch (type) {
|
|||
|
|
case 'url':
|
|||
|
|
return validateUrl(value);
|
|||
|
|
case 'notEmpty':
|
|||
|
|
return value.trim().length > 0;
|
|||
|
|
case 'number':
|
|||
|
|
return !isNaN(value) && parseInt(value) > 0;
|
|||
|
|
default:
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 工具函数
|
|||
|
|
function formatFileSize(bytes) {
|
|||
|
|
if (bytes === 0) return '0 Bytes';
|
|||
|
|
const k = 1024;
|
|||
|
|
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
|||
|
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|||
|
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function formatDate(dateString) {
|
|||
|
|
const date = new Date(dateString);
|
|||
|
|
return date.getFullYear() + '-' +
|
|||
|
|
String(date.getMonth() + 1).padStart(2, '0') + '-' +
|
|||
|
|
String(date.getDate()).padStart(2, '0');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function copyToClipboard(text) {
|
|||
|
|
navigator.clipboard.writeText(text).then(() => {
|
|||
|
|
alert('已复制到剪贴板');
|
|||
|
|
}).catch(() => {
|
|||
|
|
alert('复制失败,请手动复制');
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 快捷键支持
|
|||
|
|
$(document).keydown(function(e) {
|
|||
|
|
// ESC键返回首页
|
|||
|
|
if (e.keyCode === 27 && currentSection !== 'home') {
|
|||
|
|
showSection('home');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Ctrl+Enter 执行当前页面的主要操作
|
|||
|
|
if (e.ctrlKey && e.keyCode === 13) {
|
|||
|
|
switch (currentSection) {
|
|||
|
|
case 'homepage':
|
|||
|
|
extractHomepage();
|
|||
|
|
break;
|
|||
|
|
case 'single':
|
|||
|
|
downloadSingleArticle();
|
|||
|
|
break;
|
|||
|
|
case 'list':
|
|||
|
|
getArticleList();
|
|||
|
|
break;
|
|||
|
|
case 'batch':
|
|||
|
|
batchDownload();
|
|||
|
|
break;
|
|||
|
|
case 'data':
|
|||
|
|
loadDataList();
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 页面可见性变化时的处理
|
|||
|
|
document.addEventListener('visibilitychange', function() {
|
|||
|
|
if (document.hidden) {
|
|||
|
|
console.log('页面已隐藏');
|
|||
|
|
} else {
|
|||
|
|
console.log('页面已显示');
|
|||
|
|
// 可以在这里刷新任务状态
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 错误处理
|
|||
|
|
window.onerror = function(message, source, lineno, colno, error) {
|
|||
|
|
console.error('页面错误:', message, '位置:', source + ':' + lineno);
|
|||
|
|
return false;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 控制台欢迎信息
|
|||
|
|
console.log(`
|
|||
|
|
🚀 微信公众号文章爬虫系统 Web界面
|
|||
|
|
====================================
|
|||
|
|
版本: 1.0.0
|
|||
|
|
开发者: AI Assistant
|
|||
|
|
更新时间: 2025-11-27
|
|||
|
|
====================================
|
|||
|
|
💡 提示:
|
|||
|
|
- 按 ESC 键返回首页
|
|||
|
|
- 按 Ctrl+Enter 执行当前操作
|
|||
|
|
- 所有操作都会显示详细进度
|
|||
|
|
====================================
|
|||
|
|
`);
|