v1.5.0: 舆情驱动自动化与持仓跟踪智能体合并为「 自动化」导航入口(双选项卡); 修复布尔设置存True/False导致读取失效的容错解析

This commit is contained in:
2026-08-19 23:37:04 +08:00
parent 99654de0fd
commit 978ab813eb
8 changed files with 309 additions and 149 deletions
+2 -79
View File
@@ -1,10 +1,10 @@
/* 系统设置页 */
/* 系统设置页:邮件通知 + 大模型接口(舆情/跟踪已移至 /automation */
let curSettings = null;
async function loadSettings() {
try {
curSettings = await api('/api/settings');
const mail = curSettings.mail, mono = curSettings.monitor, llm = curSettings.llm;
const mail = curSettings.mail, llm = curSettings.llm;
$('#emailEnabled').checked = !!mail.email_enabled;
$('#smtpHost').value = mail.smtp_host;
$('#smtpPort').value = mail.smtp_port;
@@ -16,42 +16,11 @@ async function loadSettings() {
$('#llmBaseUrl').value = llm.base_url;
$('#llmApiKey').value = llm.api_key;
$('#llmModel').value = llm.model;
$('#monitorEnabled').checked = !!mono.enabled;
$('#monitorInterval').value = mono.interval_min;
$('#monitorImportance').value = mono.importance_threshold;
$('#monitorSentiment').value = mono.sentiment_weight;
$('#monitorKeywords').value = (mono.keywords || []).join(',');
// 分类勾选
const cats = mono.categories || [];
$$('#monitorCats input').forEach(c => c.checked = cats.includes(c.value));
renderState(curSettings.state);
// 持仓跟踪
const tr = curSettings.tracking || {};
$('#trackingEnabled').checked = !!tr.enabled;
$('#trackingInterval').value = tr.interval_min;
$('#trackingImpact').value = tr.impact_threshold;
$('#trackingNotify').checked = !!tr.notify;
renderTrackingState(tr);
loadLog();
} catch (e) {
toast('设置加载失败');
}
}
function renderState(state) {
$('#monitorState').innerHTML = `
<div class="mini-stat"><div class="ms-label">已处理新闻水位</div><div class="ms-value num">#${state.last_news_id || 0}</div></div>
<div class="mini-stat"><div class="ms-label">上次扫描</div><div class="ms-value">${state.last_scan || '—'}</div></div>
<div class="mini-stat"><div class="ms-label">上次通知</div><div class="ms-value num">${state.last_sent_count || 0} 条</div></div>`;
}
function renderTrackingState(tr) {
$('#trackingState').innerHTML = `
<div class="mini-stat"><div class="ms-label">上次运行</div><div class="ms-value">${tr.last_run || '—'}</div></div>
<div class="mini-stat"><div class="ms-label">最近跟踪</div><div class="ms-value">${tr.last_stock || '—'}</div></div>
<div class="mini-stat"><div class="ms-label">最近告警影响度</div><div class="ms-value num">${tr.last_alert ? tr.last_alert + '/100' : '—'}</div></div>`;
}
function collectMail() {
return {
smtp_host: $('#smtpHost').value.trim(), smtp_port: $('#smtpPort').value,
@@ -61,18 +30,6 @@ function collectMail() {
};
}
function collectMonitor() {
const cats = $$('#monitorCats input:checked').map(c => c.value);
return {
monitor_enabled: $('#monitorEnabled').checked,
monitor_interval: $('#monitorInterval').value,
monitor_importance: $('#monitorImportance').value,
monitor_sentiment: $('#monitorSentiment').value,
monitor_categories: cats.join(','),
monitor_keywords: $('#monitorKeywords').value
};
}
async function save(which) {
try {
const body = {};
@@ -82,13 +39,6 @@ async function save(which) {
llm_api_key: $('#llmApiKey').value.trim(),
llm_model: $('#llmModel').value.trim()
};
if (which === 'monitor') body.monitor = collectMonitor();
if (which === 'tracking') body.tracking = {
tracking_enabled: $('#trackingEnabled').checked,
tracking_interval: $('#trackingInterval').value,
tracking_impact_threshold: $('#trackingImpact').value,
tracking_notify: $('#trackingNotify').checked
};
const r = await api('/api/settings', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) });
toast(r.msg || '已保存');
} catch (e) { toast('保存失败:' + e.message); }
@@ -116,31 +66,4 @@ async function testLlm() {
btn.disabled = false; btn.textContent = '🔌 测试连接';
}
async function scanNow() {
const btn = event.target; btn.disabled = true;
try {
const r = await api('/api/monitor/scan', { method: 'POST' });
toast(`扫描完成:检查 ${r.checked} 条,重要 ${r.important} 条,发送 ${r.sent}` + (r.error ? '' + r.error + '' : ''));
loadSettings();
} catch (e) { toast('扫描失败:' + e.message); }
btn.disabled = false;
}
async function loadLog() {
try {
const d = await api('/api/monitor/log');
const items = d.items || [];
if (!items.length) return;
$('#logTb').innerHTML = items.map(n => `
<tr>
<td style="color:var(--muted)">${n.sent_at}</td>
<td style="max-width:300px;white-space:normal">${escapeHtml(n.title)}</td>
<td><span class="cat-tag ${n.category}">${n.category}</span></td>
<td class="num ${pctClass(n.sentiment)}">${n.sentiment > 0 ? '利好' : n.sentiment < 0 ? '利空' : '中性'} (${Number(n.sentiment).toFixed(2)})</td>
<td class="num"><b>${n.importance}</b></td>
<td><span class="tag ${n.status === 'sent' ? 'tag-推荐' : n.status === 'skipped' ? 'tag-关注' : 'tag-负'}">${n.status}</span></td>
</tr>`).join('');
} catch (e) {}
}
loadSettings();