```
feat(readme): 对部分文本进行格式调整,包括金额数字空格分隔、API 参数说明优化、标题层级对齐等,提升可读性。 ```
This commit is contained in:
205
public/app.js
205
public/app.js
@@ -134,11 +134,11 @@ async function fetchDetails() {
|
||||
|
||||
listData = await dateRangeResponse.json();
|
||||
} else {
|
||||
// 普通模式 - 按数量抓取多页
|
||||
// 普通模式 - 按数量采集多页
|
||||
const url = document.getElementById('detailUrl').value;
|
||||
const limit = parseInt(document.getElementById('detailLimit').value);
|
||||
|
||||
// 抓取多页直到获得足够数量
|
||||
// 采集多页直到获得足够数量
|
||||
const allItems = [];
|
||||
let page = 1;
|
||||
const maxPagesToFetch = Math.ceil(limit / 10) + 1; // 假设每页约10条
|
||||
@@ -177,7 +177,7 @@ async function fetchDetails() {
|
||||
return;
|
||||
}
|
||||
|
||||
// 抓取详情
|
||||
// 采集详情
|
||||
const limit = useDetailDateRange ? listData.data.length : parseInt(document.getElementById('detailLimit').value);
|
||||
const detailResponse = await fetch(`${API_BASE}/details`, {
|
||||
method: 'POST',
|
||||
@@ -202,7 +202,7 @@ async function fetchDetails() {
|
||||
function displayDetails(items, container) {
|
||||
const html = `
|
||||
<div style="max-height: 380px; overflow-y: auto;">
|
||||
<h3 style="margin-bottom: 15px;">抓取了 ${items.length} 条详情</h3>
|
||||
<h3 style="margin-bottom: 15px;">采集了 ${items.length} 条详情</h3>
|
||||
${items.map((item, index) => `
|
||||
<div class="list-item">
|
||||
<h3>${index + 1}. ${item.title}</h3>
|
||||
@@ -212,7 +212,7 @@ function displayDetails(items, container) {
|
||||
${item.detail.budget ? `
|
||||
<span class="budget">${item.detail.budget.amount}${item.detail.budget.unit}</span>
|
||||
` : '<div class="meta">未找到预算信息</div>'}
|
||||
` : '<div class="error">抓取失败</div>'}
|
||||
` : '<div class="error">采集失败</div>'}
|
||||
<br><a href="${item.href}" target="_blank">查看原文 →</a>
|
||||
</div>
|
||||
`).join('')}
|
||||
@@ -271,6 +271,7 @@ async function generateReport() {
|
||||
currentReport = data.data;
|
||||
displayReport(data.data, results);
|
||||
exportBtn.style.display = 'inline-block';
|
||||
document.getElementById('sendEmailBtn').style.display = 'inline-block';
|
||||
} else {
|
||||
results.innerHTML = `<div class="error">错误: ${data.error}</div>`;
|
||||
}
|
||||
@@ -475,3 +476,197 @@ async function exportReport() {
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
// ========== 邮件功能 ==========
|
||||
|
||||
// 页面加载时加载邮件配置
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
loadEmailConfig();
|
||||
});
|
||||
|
||||
// 保存邮件配置到localStorage
|
||||
function saveEmailConfig() {
|
||||
const config = {
|
||||
smtpHost: document.getElementById('smtpHost').value,
|
||||
smtpPort: parseInt(document.getElementById('smtpPort').value) || 587,
|
||||
smtpUser: document.getElementById('smtpUser').value,
|
||||
smtpPass: document.getElementById('smtpPass').value,
|
||||
recipients: document.getElementById('recipients').value
|
||||
};
|
||||
|
||||
// 验证配置
|
||||
if (!config.smtpHost || !config.smtpUser || !config.smtpPass || !config.recipients) {
|
||||
showEmailStatus('请填写所有必填项', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// 保存到localStorage
|
||||
localStorage.setItem('emailConfig', JSON.stringify(config));
|
||||
showEmailStatus('邮件配置已保存', 'success');
|
||||
}
|
||||
|
||||
// 从localStorage加载邮件配置
|
||||
function loadEmailConfig() {
|
||||
const configStr = localStorage.getItem('emailConfig');
|
||||
if (configStr) {
|
||||
try {
|
||||
const config = JSON.parse(configStr);
|
||||
document.getElementById('smtpHost').value = config.smtpHost || '';
|
||||
document.getElementById('smtpPort').value = config.smtpPort || 587;
|
||||
document.getElementById('smtpUser').value = config.smtpUser || '';
|
||||
document.getElementById('smtpPass').value = config.smtpPass || '';
|
||||
document.getElementById('recipients').value = config.recipients || '';
|
||||
} catch (e) {
|
||||
console.error('加载邮件配置失败:', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 测试邮件配置
|
||||
async function testEmailConfig() {
|
||||
const config = {
|
||||
smtpHost: document.getElementById('smtpHost').value,
|
||||
smtpPort: parseInt(document.getElementById('smtpPort').value) || 587,
|
||||
smtpUser: document.getElementById('smtpUser').value,
|
||||
smtpPass: document.getElementById('smtpPass').value,
|
||||
recipients: document.getElementById('recipients').value
|
||||
};
|
||||
|
||||
// 验证配置
|
||||
if (!config.smtpHost || !config.smtpUser || !config.smtpPass || !config.recipients) {
|
||||
showEmailStatus('请填写所有必填项', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建测试报告
|
||||
const testReport = {
|
||||
summary: {
|
||||
total_count: 1,
|
||||
filtered_count: 1,
|
||||
threshold: '50万元',
|
||||
total_amount: '100.00万元',
|
||||
generated_at: new Date().toISOString()
|
||||
},
|
||||
projects: [{
|
||||
title: '这是一封测试邮件',
|
||||
date: new Date().toLocaleDateString('zh-CN'),
|
||||
publish_time: new Date().toLocaleString('zh-CN'),
|
||||
budget: {
|
||||
amount: 100,
|
||||
unit: '万元',
|
||||
text: '测试金额',
|
||||
originalUnit: '万元'
|
||||
},
|
||||
url: 'https://gjzx.nanjing.gov.cn'
|
||||
}]
|
||||
};
|
||||
|
||||
showEmailStatus('正在发送测试邮件...', 'info');
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/send-email`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
emailConfig: config,
|
||||
report: testReport
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
showEmailStatus('测试邮件发送成功!请检查收件箱', 'success');
|
||||
} else {
|
||||
showEmailStatus(`发送失败: ${data.error}`, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
showEmailStatus(`请求失败: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 发送报告到邮箱
|
||||
async function sendReportByEmail() {
|
||||
if (!currentReport) {
|
||||
alert('请先生成报告');
|
||||
return;
|
||||
}
|
||||
|
||||
// 从localStorage加载邮件配置
|
||||
const configStr = localStorage.getItem('emailConfig');
|
||||
if (!configStr) {
|
||||
alert('请先在"邮件配置"标签页配置邮件服务器');
|
||||
return;
|
||||
}
|
||||
|
||||
let emailConfig;
|
||||
try {
|
||||
emailConfig = JSON.parse(configStr);
|
||||
} catch (e) {
|
||||
alert('邮件配置格式错误,请重新配置');
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证配置
|
||||
if (!emailConfig.smtpHost || !emailConfig.smtpUser || !emailConfig.smtpPass || !emailConfig.recipients) {
|
||||
alert('邮件配置不完整,请在"邮件配置"标签页检查配置');
|
||||
return;
|
||||
}
|
||||
|
||||
const sendBtn = document.getElementById('sendEmailBtn');
|
||||
const originalText = sendBtn.textContent;
|
||||
sendBtn.disabled = true;
|
||||
sendBtn.textContent = '正在发送...';
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/send-email`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
emailConfig: emailConfig,
|
||||
report: currentReport
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
alert('报告已成功发送到邮箱!');
|
||||
} else {
|
||||
alert(`发送失败: ${data.error}`);
|
||||
}
|
||||
} catch (error) {
|
||||
alert(`请求失败: ${error.message}`);
|
||||
} finally {
|
||||
sendBtn.disabled = false;
|
||||
sendBtn.textContent = originalText;
|
||||
}
|
||||
}
|
||||
|
||||
// 显示邮件配置状态
|
||||
function showEmailStatus(message, type) {
|
||||
const statusDiv = document.getElementById('emailConfigStatus');
|
||||
const bgColors = {
|
||||
success: '#d4edda',
|
||||
error: '#f8d7da',
|
||||
info: '#d1ecf1'
|
||||
};
|
||||
const textColors = {
|
||||
success: '#155724',
|
||||
error: '#721c24',
|
||||
info: '#0c5460'
|
||||
};
|
||||
|
||||
statusDiv.innerHTML = `
|
||||
<div style="background: ${bgColors[type]}; color: ${textColors[type]}; padding: 15px; border-radius: 8px;">
|
||||
${message}
|
||||
</div>
|
||||
`;
|
||||
|
||||
// 3秒后自动隐藏成功消息
|
||||
if (type === 'success') {
|
||||
setTimeout(() => {
|
||||
statusDiv.innerHTML = '';
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user