Files
stock-advisor/static/js/settings.js
T

147 lines
6.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 系统设置页 */
let curSettings = null;
async function loadSettings() {
try {
curSettings = await api('/api/settings');
const mail = curSettings.mail, mono = curSettings.monitor, llm = curSettings.llm;
$('#emailEnabled').checked = !!mail.email_enabled;
$('#smtpHost').value = mail.smtp_host;
$('#smtpPort').value = mail.smtp_port;
$('#smtpMode').value = mail.smtp_mode || 'plain';
$('#smtpUser').value = mail.smtp_user;
$('#smtpPass').value = mail.smtp_pass;
$('#senderName').value = mail.sender_name;
$('#emailTo').value = mail.email_to;
$('#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,
smtp_mode: $('#smtpMode').value, smtp_user: $('#smtpUser').value.trim(),
smtp_pass: $('#smtpPass').value, sender_name: $('#senderName').value.trim(),
email_to: $('#emailTo').value.trim(), email_enabled: $('#emailEnabled').checked
};
}
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 = {};
if (which === 'mail') body.mail = collectMail();
if (which === 'llm') body.llm = {
llm_base_url: $('#llmBaseUrl').value.trim(),
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); }
}
async function testEmail() {
const btn = event.target; btn.disabled = true; btn.textContent = '发送中…';
try {
await api('/api/settings', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ mail: collectMail() }) });
const r = await api('/api/settings/test-email', { method: 'POST' });
toast(r.msg || '发送成功');
} catch (e) { toast('发送失败:' + e.message); }
btn.disabled = false; btn.textContent = '📨 发送测试邮件';
}
async function testLlm() {
const btn = event.target; btn.disabled = true; btn.textContent = '测试中…';
try {
await api('/api/settings', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ llm: {
llm_base_url: $('#llmBaseUrl').value.trim(), llm_api_key: $('#llmApiKey').value.trim(), llm_model: $('#llmModel').value.trim()
} }) });
const r = await api('/api/settings/test-llm', { method: 'POST' });
toast(r.msg || '连接正常');
} catch (e) { toast('连接失败:' + e.message); }
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();