90 lines
4.4 KiB
JavaScript
90 lines
4.4 KiB
JavaScript
/* AI 分析详情页:研报正文 + 数据源 */
|
||
const CODE_AID = parseInt(location.pathname.split('/').pop(), 10);
|
||
|
||
async function load() {
|
||
try {
|
||
const d = await api('/api/analyses/' + CODE_AID);
|
||
const a = d.analysis, stock = d.stock || {};
|
||
$('#aStock').textContent = a.stock_name || stock.name || '—';
|
||
$('#aCode').textContent = a.code;
|
||
$('#aIndustry').textContent = stock ? (stock.name + ' · ' + (stock.industry || '') + ' · ' + (stock.board || '')) : '';
|
||
$('#aTime').textContent = a.created_at;
|
||
$('#aFocus').textContent = a.focus || '整体投资价值';
|
||
$('#reportBox').innerHTML = mdRender(a.report);
|
||
renderSources(a.sources || {});
|
||
} catch (e) {
|
||
$('#reportBox').innerHTML = '<div class="empty">加载失败:' + escapeHtml(e.message) + '</div>';
|
||
}
|
||
}
|
||
|
||
function srcBlock(title, icon, inner, count) {
|
||
return `<details class="src-block" ${inner ? 'open' : ''}>
|
||
<summary>${icon} ${title} ${count !== undefined ? `<span class="src-count">${count}</span>` : ''}</summary>
|
||
<div class="src-body">${inner || '<div class="empty">无</div>'}</div>
|
||
</details>`;
|
||
}
|
||
|
||
function renderSources(s) {
|
||
let html = '';
|
||
|
||
// 1. RAG 相关资讯
|
||
const news = s.news || [];
|
||
html += srcBlock('RAG 相关资讯(向量检索命中)', '📰', news.map(n => `
|
||
<div class="src-news">
|
||
<div class="src-news-title">${escapeHtml(n.title)}</div>
|
||
<div class="src-news-meta">
|
||
<span>${n.date || '—'}</span>
|
||
<span class="tag tag-${n.sentiment > 0 ? '正' : n.sentiment < 0 ? '负' : '平'}">情感 ${Number(n.sentiment).toFixed(2)}</span>
|
||
<span style="color:var(--muted)">相似度 ${(1 - (n.distance || 0)).toFixed(3)}</span>
|
||
</div>
|
||
<div class="src-news-text">${escapeHtml(n.text)}</div>
|
||
</div>`).join(''), news.length);
|
||
|
||
// 2. 公司概况
|
||
html += srcBlock('公司概况(RAG 检索)', '🏢', s.profile ? `<p>${escapeHtml(s.profile)}</p>` : '', s.profile ? 1 : 0);
|
||
|
||
// 3. 技术指标
|
||
html += srcBlock('技术指标', '📈', s.indicators ? `<pre class="src-pre">${escapeHtml(s.indicators)}</pre>` : '', s.indicators ? 1 : 0);
|
||
|
||
// 4. 综合评分
|
||
if (s.score) {
|
||
const sc = s.score;
|
||
html += srcBlock('综合评分', '🎯', `
|
||
<div class="mini-stats" style="gap:14px">
|
||
<div class="mini-stat"><div class="ms-label">总分</div><div class="ms-value" style="color:${sc.total >= 68 ? '#f59e0b' : '#3b82f6'}">${sc.total}</div></div>
|
||
<div class="mini-stat"><div class="ms-label">评级</div><div class="ms-value"><span class="tag tag-${sc.rating}">${sc.rating}</span></div></div>
|
||
<div class="mini-stat"><div class="ms-label">趋势</div><div class="ms-value">${sc.trend}</div></div>
|
||
<div class="mini-stat"><div class="ms-label">动量</div><div class="ms-value">${sc.momentum}</div></div>
|
||
<div class="mini-stat"><div class="ms-label">技术</div><div class="ms-value">${sc.technical}</div></div>
|
||
<div class="mini-stat"><div class="ms-label">量能</div><div class="ms-value">${sc.volume}</div></div>
|
||
<div class="mini-stat"><div class="ms-label">消息</div><div class="ms-value">${sc.news}</div></div>
|
||
<div class="mini-stat"><div class="ms-label">机构</div><div class="ms-value">${sc.institutional}</div></div>
|
||
</div>`, 1);
|
||
}
|
||
|
||
// 5. 机构评级
|
||
const ratings = s.ratings || [];
|
||
html += srcBlock('机构评级', '🏦', ratings.length ? `<table>
|
||
<tr><th>机构</th><th>评级</th><th>目标价</th><th>日期</th></tr>
|
||
${ratings.map(r => `<tr><td>${escapeHtml(r.inst_name)}</td>
|
||
<td><span class="tag tag-${r.rating}">${r.rating}</span></td>
|
||
<td class="num">${r.target_price}</td><td>${r.rating_date}</td></tr>`).join('')}
|
||
</table>` : '', ratings.length);
|
||
|
||
// 6. 基金持仓
|
||
const holdings = s.holdings || [];
|
||
html += srcBlock('基金持仓', '💼', holdings.length ? `<table>
|
||
<tr><th>机构</th><th>季度</th><th>持仓市值</th><th>环比</th></tr>
|
||
${holdings.map(h => `<tr><td>${escapeHtml(h.inst_name)}</td><td>${h.quarter}</td>
|
||
<td class="num">${fmtNum(h.hold_value)}</td>
|
||
<td class="num ${pctClass(h.change_pct)}">${fmtPct(h.change_pct)}</td></tr>`).join('')}
|
||
</table>` : '', holdings.length);
|
||
|
||
// 7. 完整提示词
|
||
html += srcBlock('完整提示词(Prompt)', '🧠', s.prompt ? `<pre class="src-pre">${escapeHtml(s.prompt)}</pre>` : '', s.prompt ? 1 : 0);
|
||
|
||
$('#sourceBox').innerHTML = html;
|
||
}
|
||
|
||
load();
|