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

103 lines
5.1 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.
/* 仪表盘 */
async function loadOverview() {
try {
const d = await api('/api/overview');
renderIndexes(d.indexes, d.stat);
renderTop(d.top);
renderHeat(d.heat);
renderNews(d.news);
renderWatch(d.watchlist);
} catch (e) {
$('#indexBox').innerHTML = '<div class="card"><div class="empty">加载失败:' + escapeHtml(e.message) + '</div></div>';
}
}
function renderIndexes(indexes, stat) {
const cards = indexes.map(ix => {
const cls = pctClass(ix.chg);
return `<div class="card">
<div class="kpi-label" style="color:var(--muted);font-size:12px">${ix.label}</div>
<div class="num" style="font-size:26px;font-weight:800;margin:6px 0">${Number(ix.value).toFixed(2)}</div>
<div class="num ${cls}" style="font-weight:600">${fmtPct(ix.chg)}</div>
</div>`;
}).join('');
const s = stat || {};
$('#indexBox').innerHTML = cards + `<div class="card">
<div class="card-title"><span class="bar"></span>市场情绪</div>
<div class="mini-stats">
<div class="mini-stat"><div class="ms-label">上涨</div><div class="ms-value up">${s.up || 0}</div></div>
<div class="mini-stat"><div class="ms-label">下跌</div><div class="ms-value down">${s.down || 0}</div></div>
<div class="mini-stat"><div class="ms-label">涨停</div><div class="ms-value" style="color:var(--up)">${s.limit_up || 0}</div></div>
<div class="mini-stat"><div class="ms-label">跌停</div><div class="ms-value" style="color:var(--down)">${s.limit_down || 0}</div></div>
<div class="mini-stat"><div class="ms-label">成交额</div><div class="ms-value">${fmtAmountYi(s.amount_yi)}</div></div>
</div>
<div style="margin-top:14px;color:var(--muted);font-size:12px">股票池 ${s.total || 0} 只 · 综合评分由 趋势/动量/技术/量能/消息/机构 六因子加权得出</div>
</div>`;
}
function renderTop(list) {
if (!list || !list.length) { $('#topRecBox').innerHTML = '<div class="empty">暂无数据</div>'; return; }
$('#topRecBox').innerHTML = `<table>
<tr><th>排名</th><th>股票</th><th>现价</th><th>今日</th><th>评分</th><th>评级</th><th>推荐理由</th></tr>
${list.map((it, i) => `<tr class="row-link" onclick="location.href='/stock/${it.code}'">
<td class="num">${i + 1}</td>
<td><b>${it.name}</b><div style="color:var(--muted);font-size:12px">${it.code} · ${it.industry}</div></td>
<td class="num">${it.close}</td>
<td class="num ${pctClass(it.change_pct)}">${fmtPct(it.change_pct)}</td>
<td class="num"><b style="color:${it.score.total >= 68 ? '#f59e0b' : '#3b82f6'}">${it.score.total}</b></td>
<td><span class="tag tag-${it.score.rating}">${it.score.rating}</span></td>
<td style="max-width:260px;white-space:normal;color:var(--text2)">${escapeHtml((it.reasons || []).join(''))}</td>
</tr>`).join('')}
</table>`;
}
function renderHeat(heat) {
if (!heat || !heat.length) { $('#heatBox').innerHTML = '<div class="empty">暂无数据</div>'; return; }
const max = Math.max(...heat.map(h => Math.abs(h.chg)), 0.01);
$('#heatBox').innerHTML = heat.map(h => {
const w = Math.min(100, Math.abs(h.chg) / max * 100);
const cls = pctClass(h.chg);
return `<div style="margin-bottom:12px">
<div class="between">
<span>${escapeHtml(h.industry)} <span style="color:var(--muted)">(${h.cnt})</span></span>
<span class="num ${cls}">${fmtPct(h.chg)}</span>
</div>
<div style="height:7px;background:#262d3a;border-radius:4px;margin-top:5px">
<div style="height:100%;width:${w}%;border-radius:4px;background:${h.chg >= 0 ? 'var(--up)' : 'var(--down)'}"></div>
</div>
</div>`;
}).join('');
}
function renderNews(news) {
if (!news || !news.length) { $('#newsBox').innerHTML = '<div class="empty">暂无数据</div>'; return; }
$('#newsBox').innerHTML = news.map(n => `
<div class="news-item" onclick="location.href='/news'">
<div class="news-title">${escapeHtml(n.title)}</div>
<div class="news-meta">
<span class="cat-tag ${n.category}">${n.category}</span>
<span class="tag tag-${n.sentiment > 0 ? '正' : n.sentiment < 0 ? '负' : '平'}">${n.sentiment > 0 ? '利好' : n.sentiment < 0 ? '利空' : '中性'}</span>
<span>${escapeHtml(n.source)}</span><span>${n.publish_date}</span>
</div>
</div>`).join('');
}
function renderWatch(list) {
if (!list || !list.length) {
$('#watchBox').innerHTML = `<div class="empty">暂无自选股<br><a href="/stocks">去股票池添加 →</a></div>`;
return;
}
$('#watchBox').innerHTML = `<table>
<tr><th>股票</th><th>现价</th><th>今日</th><th>评分</th><th>评级</th></tr>
${list.map(it => `<tr class="row-link" onclick="location.href='/stock/${it.code}'">
<td><b>${it.name}</b><div style="color:var(--muted);font-size:12px">${it.code}</div></td>
<td class="num">${it.close}</td>
<td class="num ${pctClass(it.change_pct)}">${fmtPct(it.change_pct)}</td>
<td class="num">${it.score}</td>
<td><span class="tag tag-${it.rating}">${it.rating}</span></td>
</tr>`).join('')}
</table>`;
}
loadOverview();