382 lines
13 KiB
JavaScript
382 lines
13 KiB
JavaScript
|
|
// 检查jQuery是否加载
|
|||
|
|
if (typeof jQuery === 'undefined') {
|
|||
|
|
console.error('jQuery未加载,请检查网络连接');
|
|||
|
|
alert('jQuery加载失败,请刷新页面或检查网络连接');
|
|||
|
|
} else {
|
|||
|
|
$(document).ready(function() {
|
|||
|
|
let currentFilename = null;
|
|||
|
|
let progressInterval = null;
|
|||
|
|
let currentStep = 0;
|
|||
|
|
const steps = [
|
|||
|
|
{ name: '解析URL', percent: 5 },
|
|||
|
|
{ name: '启动浏览器', percent: 15 },
|
|||
|
|
{ name: '加载页面', percent: 30 },
|
|||
|
|
{ name: '滚动获取文章', percent: 70 },
|
|||
|
|
{ name: '提取数据', percent: 85 },
|
|||
|
|
{ name: '生成Excel文件', percent: 95 }
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
// 登出按钮点击事件
|
|||
|
|
$('#logoutBtn').click(function() {
|
|||
|
|
if (confirm('确定要登出吗?')) {
|
|||
|
|
$.ajax({
|
|||
|
|
url: '/api/logout',
|
|||
|
|
type: 'POST',
|
|||
|
|
success: function(response) {
|
|||
|
|
if (response.success) {
|
|||
|
|
window.location.href = '/login';
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
error: function() {
|
|||
|
|
window.location.href = '/login';
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 加载队列统计信息并更新徽章
|
|||
|
|
function updateQueueBadge() {
|
|||
|
|
$.ajax({
|
|||
|
|
url: '/api/queue/stats',
|
|||
|
|
type: 'GET',
|
|||
|
|
success: function(response) {
|
|||
|
|
if (response.success && response.stats) {
|
|||
|
|
const pending = response.stats.pending || 0;
|
|||
|
|
const processing = response.stats.processing || 0;
|
|||
|
|
const total = pending + processing;
|
|||
|
|
|
|||
|
|
if (total > 0) {
|
|||
|
|
$('#queueBadge').text(total).show();
|
|||
|
|
} else {
|
|||
|
|
$('#queueBadge').hide();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
error: function() {
|
|||
|
|
// 忽略错误,不显示徽章
|
|||
|
|
$('#queueBadge').hide();
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 初始加载徽章
|
|||
|
|
updateQueueBadge();
|
|||
|
|
|
|||
|
|
// 每10秒更新一次徽章
|
|||
|
|
setInterval(updateQueueBadge, 10000);
|
|||
|
|
|
|||
|
|
// 导出按钮点击事件
|
|||
|
|
$('#exportBtn').click(function() {
|
|||
|
|
const url = $('#authorUrl').val().trim();
|
|||
|
|
const cookies = $('#cookieInput').val().trim();
|
|||
|
|
const months = parseFloat($('#monthsSelect').val()); // 改为parseFloat支持小数
|
|||
|
|
const articlesOnly = $('#articlesOnlyCheckbox').is(':checked'); // 获取是否只爬取文章
|
|||
|
|
|
|||
|
|
// 验证URL
|
|||
|
|
if (!url) {
|
|||
|
|
showError('请输入百家号作者主页地址');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!url.includes('baijiahao.baidu.com') || !url.includes('app_id=')) {
|
|||
|
|
showError('URL格式不正确,请输入完整的百家号作者主页地址');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 开始导出(始终使用默认代理)
|
|||
|
|
startExport(url, cookies, months, articlesOnly, true, '');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 下载按钮点击事件
|
|||
|
|
$('#downloadBtn').click(function() {
|
|||
|
|
if (currentFilename) {
|
|||
|
|
window.location.href = `/api/download/${currentFilename}`;
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 输入框回车事件
|
|||
|
|
$('#authorUrl').keypress(function(e) {
|
|||
|
|
if (e.which === 13) {
|
|||
|
|
$('#exportBtn').click();
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 开始导出
|
|||
|
|
function startExport(url, cookies, months, articlesOnly, useProxy, proxyApiUrl) {
|
|||
|
|
// 隐藏结果框和文章列表
|
|||
|
|
$('#resultBox').hide();
|
|||
|
|
$('#downloadBtn').hide();
|
|||
|
|
$('#articlePreview').hide();
|
|||
|
|
|
|||
|
|
// 显示加载框
|
|||
|
|
$('#loadingBox').show();
|
|||
|
|
$('#progressDetails').show();
|
|||
|
|
updateProgress('开始初始化...', 0);
|
|||
|
|
|
|||
|
|
// 启动进度模拟
|
|||
|
|
startProgressSimulation();
|
|||
|
|
|
|||
|
|
// 禁用按钮
|
|||
|
|
$('#exportBtn').prop('disabled', true);
|
|||
|
|
|
|||
|
|
// 构建请求数据(始终启用代理)
|
|||
|
|
const requestData = {
|
|||
|
|
url: url,
|
|||
|
|
cookies: cookies || '',
|
|||
|
|
months: months, // 直接使用months,不要用 || 6 因为0.33是有效值
|
|||
|
|
use_proxy: useProxy, // 始终启用代理
|
|||
|
|
proxy_api_url: proxyApiUrl || '',
|
|||
|
|
articles_only: articlesOnly // 仅爬取文章
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 发送请求
|
|||
|
|
$.ajax({
|
|||
|
|
url: '/api/export',
|
|||
|
|
type: 'POST',
|
|||
|
|
contentType: 'application/json',
|
|||
|
|
data: JSON.stringify(requestData),
|
|||
|
|
success: function(response) {
|
|||
|
|
if (response.success) {
|
|||
|
|
currentFilename = response.filename;
|
|||
|
|
completeAllSteps();
|
|||
|
|
|
|||
|
|
// 显示文章列表
|
|||
|
|
if (response.articles && response.articles.length > 0) {
|
|||
|
|
displayArticles(response.articles, response.count);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
setTimeout(function() {
|
|||
|
|
showSuccess(`导出成功!共获取到 ${response.count} 篇文章`);
|
|||
|
|
$('#downloadBtn').show();
|
|||
|
|
}, 500);
|
|||
|
|
} else {
|
|||
|
|
stopProgressSimulation();
|
|||
|
|
showError(response.message || '导出失败');
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
error: function(xhr, status, error) {
|
|||
|
|
stopProgressSimulation();
|
|||
|
|
|
|||
|
|
// 检查是否需要登录
|
|||
|
|
if (xhr.status === 401 || (xhr.responseJSON && xhr.responseJSON.need_login)) {
|
|||
|
|
alert('登录已过期,请重新登录');
|
|||
|
|
window.location.href = '/login';
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
let errorMessage = '导出失败,请检查网络连接或稍后重试';
|
|||
|
|
|
|||
|
|
if (xhr.responseJSON && xhr.responseJSON.message) {
|
|||
|
|
errorMessage = xhr.responseJSON.message;
|
|||
|
|
} else if (xhr.status === 0) {
|
|||
|
|
errorMessage = '无法连接到服务器,请确保后端服务已启动';
|
|||
|
|
} else if (xhr.status === 500) {
|
|||
|
|
errorMessage = '服务器内部错误,请稍后重试';
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
showError(errorMessage);
|
|||
|
|
},
|
|||
|
|
complete: function() {
|
|||
|
|
// 隐藏加载框
|
|||
|
|
$('#loadingBox').hide();
|
|||
|
|
$('#progressDetails').hide();
|
|||
|
|
|
|||
|
|
// 启用按钮
|
|||
|
|
$('#exportBtn').prop('disabled', false);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 更新进度显示
|
|||
|
|
function updateProgress(message, percent) {
|
|||
|
|
$('#progressMessage').text(message);
|
|||
|
|
$('#progressBar').css('width', percent + '%');
|
|||
|
|
$('#progressPercent').text(Math.round(percent) + '%');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 启动进度模拟
|
|||
|
|
function startProgressSimulation() {
|
|||
|
|
currentStep = 0;
|
|||
|
|
$('.step-item').removeClass('active completed');
|
|||
|
|
|
|||
|
|
progressInterval = setInterval(function() {
|
|||
|
|
if (currentStep < steps.length) {
|
|||
|
|
// 标记当前步骤为活跃
|
|||
|
|
$('.step-item').eq(currentStep).addClass('active');
|
|||
|
|
|
|||
|
|
// 更新进度
|
|||
|
|
updateProgress(steps[currentStep].name + '...', steps[currentStep].percent);
|
|||
|
|
|
|||
|
|
// 模拟步骤完成
|
|||
|
|
setTimeout(function() {
|
|||
|
|
let step = currentStep;
|
|||
|
|
$('.step-item').eq(step).removeClass('active').addClass('completed');
|
|||
|
|
}, 1000);
|
|||
|
|
|
|||
|
|
currentStep++;
|
|||
|
|
}
|
|||
|
|
}, 2000); // 每2秒一个步骤
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 停止进度模拟
|
|||
|
|
function stopProgressSimulation() {
|
|||
|
|
if (progressInterval) {
|
|||
|
|
clearInterval(progressInterval);
|
|||
|
|
progressInterval = null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 完成所有步骤
|
|||
|
|
function completeAllSteps() {
|
|||
|
|
stopProgressSimulation();
|
|||
|
|
$('.step-item').removeClass('active').addClass('completed');
|
|||
|
|
updateProgress('导出完成!', 100);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 显示文章列表
|
|||
|
|
function displayArticles(articles, totalCount) {
|
|||
|
|
$('#articleCount').text(totalCount + '篇');
|
|||
|
|
$('#articleList').empty();
|
|||
|
|
|
|||
|
|
if (articles.length === 0) {
|
|||
|
|
$('#articleList').html(`
|
|||
|
|
<div class="article-empty">
|
|||
|
|
<i class="bi bi-inbox"></i>
|
|||
|
|
<p>暂无文章数据</p>
|
|||
|
|
</div>
|
|||
|
|
`);
|
|||
|
|
} else {
|
|||
|
|
articles.forEach(function(article, index) {
|
|||
|
|
const articleHtml = `
|
|||
|
|
<div class="article-item">
|
|||
|
|
<div class="article-item-header">
|
|||
|
|
<div class="article-number">${index + 1}</div>
|
|||
|
|
<div class="article-title">${escapeHtml(article['标题'] || '未知标题')}</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="article-meta">
|
|||
|
|
<div class="article-time">
|
|||
|
|
<i class="bi bi-clock"></i>
|
|||
|
|
${escapeHtml(article['发布时间'] || '未知')}
|
|||
|
|
</div>
|
|||
|
|
<div class="article-badge">
|
|||
|
|
<i class="bi bi-check-circle-fill"></i>
|
|||
|
|
已提取
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
`;
|
|||
|
|
$('#articleList').append(articleHtml);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 如果总数大于显示数,显示提示
|
|||
|
|
if (totalCount > articles.length) {
|
|||
|
|
$('#articleList').append(`
|
|||
|
|
<div class="article-item" style="text-align: center; color: var(--text-secondary);">
|
|||
|
|
<i class="bi bi-three-dots"></i>
|
|||
|
|
还有 ${totalCount - articles.length} 篇文章未显示,请下载Excel查看完整列表
|
|||
|
|
</div>
|
|||
|
|
`);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$('#articlePreview').fadeIn();
|
|||
|
|
|
|||
|
|
// 滚动到文章列表
|
|||
|
|
setTimeout(function() {
|
|||
|
|
$('html, body').animate({
|
|||
|
|
scrollTop: $('#articlePreview').offset().top - 20
|
|||
|
|
}, 500);
|
|||
|
|
}, 300);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// HTML转义
|
|||
|
|
function escapeHtml(text) {
|
|||
|
|
const map = {
|
|||
|
|
'&': '&',
|
|||
|
|
'<': '<',
|
|||
|
|
'>': '>',
|
|||
|
|
'"': '"',
|
|||
|
|
"'": '''
|
|||
|
|
};
|
|||
|
|
return text.replace(/[&<>"']/g, function(m) { return map[m]; });
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 显示成功消息
|
|||
|
|
function showSuccess(message) {
|
|||
|
|
$('#resultMessage')
|
|||
|
|
.removeClass('error')
|
|||
|
|
.addClass('success')
|
|||
|
|
.html(`✅ ${message}`);
|
|||
|
|
$('#resultBox').fadeIn();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 显示错误消息
|
|||
|
|
function showError(message) {
|
|||
|
|
$('#resultMessage')
|
|||
|
|
.removeClass('success')
|
|||
|
|
.addClass('error')
|
|||
|
|
.html(`❌ ${message}`);
|
|||
|
|
$('#resultBox').fadeIn();
|
|||
|
|
$('#downloadBtn').hide();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 添加输入框焦点效果
|
|||
|
|
$('#authorUrl').focus(function() {
|
|||
|
|
$(this).parent().addClass('focused');
|
|||
|
|
}).blur(function() {
|
|||
|
|
$(this).parent().removeClass('focused');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 添加到队列按钮点击事件
|
|||
|
|
$('#addToQueueBtn').click(function() {
|
|||
|
|
const url = $('#authorUrl').val().trim();
|
|||
|
|
const months = parseFloat($('#monthsSelect').val());
|
|||
|
|
const articlesOnly = $('#articlesOnlyCheckbox').is(':checked'); // 获取是否只爬取文章
|
|||
|
|
|
|||
|
|
// 验证URL
|
|||
|
|
if (!url) {
|
|||
|
|
showError('请输入百家号作者主页地址');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!url.includes('baijiahao.baidu.com') || !url.includes('app_id=')) {
|
|||
|
|
showError('URL格式不正确,请输入完整的百家号作者主页地址');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 添加到队列(始终启用默认代理)
|
|||
|
|
$.ajax({
|
|||
|
|
url: '/api/queue/add',
|
|||
|
|
type: 'POST',
|
|||
|
|
contentType: 'application/json',
|
|||
|
|
data: JSON.stringify({
|
|||
|
|
url: url,
|
|||
|
|
months: months,
|
|||
|
|
use_proxy: true, // 始终启用代理
|
|||
|
|
proxy_api_url: '', // 使用默认代理API
|
|||
|
|
articles_only: articlesOnly // 仅爬取文章
|
|||
|
|
}),
|
|||
|
|
success: function(response) {
|
|||
|
|
if (response.success) {
|
|||
|
|
showSuccess('任务已添加到队列,系统将后台处理');
|
|||
|
|
// 3秒后跳转到队列页面
|
|||
|
|
setTimeout(function() {
|
|||
|
|
window.location.href = '/queue';
|
|||
|
|
}, 3000);
|
|||
|
|
} else {
|
|||
|
|
showError(response.message || '添加任务失败');
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
error: function(xhr) {
|
|||
|
|
if (xhr.status === 401) {
|
|||
|
|
alert('登录已过期,请重新登录');
|
|||
|
|
window.location.href = '/login';
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
showError('添加任务失败,请稍后重试');
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
}
|