feat(hub): mobile AI one-screen and dashboard monitor counts
Fix mobile AI to scroll only in the chat area. Dashboard cards show monitor item counts with expand-to-fullscreen and color-coded position floating P&L.
This commit is contained in:
@@ -90,33 +90,72 @@
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function renderRemarkLines(ac) {
|
||||
const lines = Array.isArray(ac && ac.remark_lines) ? ac.remark_lines : [];
|
||||
if (!lines.length) {
|
||||
const fallback = esc((ac && ac.remark) || "—");
|
||||
return `<div class="dash-ac-remark"><div class="dash-ac-remark-line">${fallback}</div></div>`;
|
||||
function renderMonitorCountChips(counts) {
|
||||
const mc = counts || {};
|
||||
const chips = [];
|
||||
const keys = Number(mc.keys) || 0;
|
||||
const orders = Number(mc.orders) || 0;
|
||||
const trends = Number(mc.trends) || 0;
|
||||
const rolls = Number(mc.rolls) || 0;
|
||||
if (keys > 0) chips.push(`<span class="dash-monitor-chip dash-monitor-key">关键位 ${keys}</span>`);
|
||||
if (orders > 0) {
|
||||
chips.push(`<span class="dash-monitor-chip dash-monitor-order">下单监控 ${orders}</span>`);
|
||||
}
|
||||
return `<div class="dash-ac-remark">${lines
|
||||
.map((ln) => {
|
||||
const kind = ln && ln.kind;
|
||||
const text = esc((ln && ln.text) || "");
|
||||
if (kind === "position" && ln.pnl != null && Number.isFinite(Number(ln.pnl))) {
|
||||
const pnl = Number(ln.pnl);
|
||||
return (
|
||||
`<div class="dash-ac-remark-line dash-ac-remark-pos">` +
|
||||
`${text} 浮<span class="${pnlClass(pnl)}">${pnlSigned(pnl, 2)}</span>` +
|
||||
`</div>`
|
||||
);
|
||||
}
|
||||
const cls =
|
||||
kind === "monitor"
|
||||
? "dash-ac-remark-line dash-ac-remark-mon"
|
||||
: kind === "issue"
|
||||
? "dash-ac-remark-line dash-ac-remark-issue"
|
||||
: "dash-ac-remark-line";
|
||||
return `<div class="${cls}">${text}</div>`;
|
||||
})
|
||||
.join("")}</div>`;
|
||||
if (trends > 0) chips.push(`<span class="dash-monitor-chip dash-monitor-trend">趋势回调 ${trends}</span>`);
|
||||
if (rolls > 0) chips.push(`<span class="dash-monitor-chip dash-monitor-roll">顺势加仓 ${rolls}</span>`);
|
||||
return chips;
|
||||
}
|
||||
|
||||
function renderAccountDetail(ac) {
|
||||
const counts = (ac && ac.monitor_counts) || {};
|
||||
const positions = Array.isArray(ac && ac.position_lines) ? ac.position_lines : [];
|
||||
const issues = Array.isArray(ac && ac.issues) ? ac.issues : [];
|
||||
const exId = ac && ac.id != null ? String(ac.id) : "";
|
||||
const chips = renderMonitorCountChips(counts);
|
||||
const expandBtn = exId
|
||||
? `<button type="button" class="dash-ac-expand-btn" data-dash-ex-id="${esc(exId)}" title="放大查看监控详情" aria-label="放大查看监控详情">` +
|
||||
`<svg viewBox="0 0 24 24" width="14" height="14" aria-hidden="true"><path fill="currentColor" d="M15 3h6v6h-2V6.41l-7.29 7.3-1.42-1.42 7.3-7.29H15V3zM3 9h2v10h10v2H3V9z"/></svg>` +
|
||||
`</button>`
|
||||
: "";
|
||||
const monitorRow =
|
||||
chips.length || expandBtn
|
||||
? `<div class="dash-ac-monitor-row">${chips.join("")}${expandBtn}</div>`
|
||||
: "";
|
||||
let posHtml = "";
|
||||
if (positions.length) {
|
||||
posHtml = positions
|
||||
.map((ln) => {
|
||||
const text = esc((ln && ln.text) || "");
|
||||
if (ln.pnl != null && Number.isFinite(Number(ln.pnl))) {
|
||||
const pnl = Number(ln.pnl);
|
||||
return (
|
||||
`<div class="dash-ac-remark-line dash-ac-remark-pos">` +
|
||||
`${text} 浮<span class="${pnlClass(pnl)}">${pnlSigned(pnl, 2)}</span>` +
|
||||
`</div>`
|
||||
);
|
||||
}
|
||||
return `<div class="dash-ac-remark-line dash-ac-remark-pos">${text}</div>`;
|
||||
})
|
||||
.join("");
|
||||
} else if (!chips.length && !issues.length) {
|
||||
posHtml = `<div class="dash-ac-remark-line dash-ac-remark-empty">无持仓</div>`;
|
||||
}
|
||||
const issueHtml = issues
|
||||
.map((text) => `<div class="dash-ac-remark-line dash-ac-remark-issue">${esc(text)}</div>`)
|
||||
.join("");
|
||||
return `<div class="dash-ac-remark">${monitorRow}<div class="dash-ac-positions">${posHtml}</div>${issueHtml}</div>`;
|
||||
}
|
||||
|
||||
function bindDashboardExpand() {
|
||||
if (!elAccounts) return;
|
||||
elAccounts.querySelectorAll(".dash-ac-expand-btn").forEach((btn) => {
|
||||
btn.addEventListener("click", (ev) => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
const id = btn.getAttribute("data-dash-ex-id");
|
||||
if (id && window.hubOpenMonitorExpand) window.hubOpenMonitorExpand(id);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function renderAccounts(accounts, threshold) {
|
||||
@@ -158,10 +197,11 @@
|
||||
<div class="dash-ac-metric"><span>浮盈亏</span><strong class="${pnlClass(floatPnl)}">${pnlSigned(floatPnl, 2)}</strong></div>
|
||||
</div>
|
||||
${lossBar}
|
||||
${renderRemarkLines(ac)}
|
||||
${renderAccountDetail(ac)}
|
||||
</article>`;
|
||||
})
|
||||
.join("");
|
||||
bindDashboardExpand();
|
||||
}
|
||||
|
||||
function renderTrades(trades, accounts) {
|
||||
|
||||
Reference in New Issue
Block a user