修改企业微信推送
This commit is contained in:
+49
-109
@@ -13,7 +13,7 @@ const tableState = {
|
||||
const PERIOD_LS_PREFIX = "ba_period_";
|
||||
const PERIOD_TTL_MS = 4 * 60 * 60 * 1000;
|
||||
|
||||
let statsData = null;
|
||||
let wecomPreviewData = null;
|
||||
let currentView = "today";
|
||||
const SORT_KEYS = {
|
||||
rank: (r) => Number(r.rank) || 0,
|
||||
@@ -262,58 +262,25 @@ function downloadCsv(name, header, rows, periodStart) {
|
||||
a.click();
|
||||
}
|
||||
|
||||
function renderStatsTable() {
|
||||
const wrap = document.getElementById("stats-table-wrap");
|
||||
if (!wrap || !statsData) return;
|
||||
|
||||
const items = statsData.items || [];
|
||||
document.getElementById("stats-criteria").textContent = statsData.criteria || "";
|
||||
document.getElementById("stats-desc").textContent = statsData.message || "";
|
||||
const sum = statsData.summary;
|
||||
document.getElementById("stats-summary").textContent = statsData.ok
|
||||
? `符合条件 ${statsData.count} 个 · 三日交集 ${sum?.intersection ?? 0} 个`
|
||||
: "数据未就绪";
|
||||
|
||||
if (!statsData.ok) {
|
||||
wrap.innerHTML = `<p class="loading">${statsData.message || "请等待三个周期数据就绪"}</p>`;
|
||||
return;
|
||||
function updateStatsHeader(payload) {
|
||||
const criteria = document.getElementById("stats-criteria");
|
||||
const summary = document.getElementById("stats-summary");
|
||||
const desc = document.getElementById("stats-desc");
|
||||
if (!payload) return;
|
||||
if (criteria) {
|
||||
criteria.textContent = payload.ok
|
||||
? payload.period_label || "—"
|
||||
: "数据未就绪";
|
||||
}
|
||||
|
||||
if (!items.length) {
|
||||
wrap.innerHTML = '<p class="loading">暂无符合条件的合约</p>';
|
||||
return;
|
||||
if (summary) {
|
||||
summary.textContent = payload.ok
|
||||
? `共 ${payload.count} 个币种` +
|
||||
(payload.parts > 1 ? ` · 企微将分 ${payload.parts} 条发送` : "")
|
||||
: "";
|
||||
}
|
||||
if (desc && payload.message && !payload.ok) {
|
||||
desc.textContent = payload.message;
|
||||
}
|
||||
|
||||
wrap.innerHTML = `
|
||||
<table data-table="stats" class="stats-table">
|
||||
<thead><tr>
|
||||
<th>合约</th>
|
||||
<th>今日排名</th><th>今日涨跌</th><th>今日成交额</th>
|
||||
<th>昨日排名</th><th>昨日涨跌</th><th>昨日成交额</th>
|
||||
<th>前日排名</th><th>前日涨跌</th><th>前日成交额</th>
|
||||
<th>三日总成交额</th>
|
||||
</tr></thead>
|
||||
<tbody id="stats-body"></tbody>
|
||||
</table>`;
|
||||
|
||||
const body = document.getElementById("stats-body");
|
||||
body.innerHTML = items
|
||||
.map((row) => {
|
||||
const d = (p) => row[p] || {};
|
||||
const cell = (p, f) => {
|
||||
const x = d(p);
|
||||
const pct = x.price_change_pct ?? 0;
|
||||
return `<td class="${f === "pct" ? pctClass(pct) : ""}">${f === "pct" ? x.price_change_pct_fmt || "—" : f === "rank" ? x.rank ?? "—" : x.quote_volume_fmt || "—"}</td>`;
|
||||
};
|
||||
return `<tr class="row-highlight stats-row" data-symbol="${row.symbol}">
|
||||
<td><strong>${row.symbol}</strong></td>
|
||||
${cell("today", "rank")}${cell("today", "pct")}${cell("today", "vol")}
|
||||
${cell("yesterday", "rank")}${cell("yesterday", "pct")}${cell("yesterday", "vol")}
|
||||
${cell("daybefore", "rank")}${cell("daybefore", "pct")}${cell("daybefore", "vol")}
|
||||
<td class="stats-total-vol">${formatVol(row.total_quote_volume)}</td>
|
||||
</tr>`;
|
||||
})
|
||||
.join("");
|
||||
}
|
||||
|
||||
function escapeHtml(s) {
|
||||
@@ -324,59 +291,43 @@ function escapeHtml(s) {
|
||||
.replace(/\n/g, "<br>");
|
||||
}
|
||||
|
||||
function formatVol(v) {
|
||||
if (v >= 1e8) return (v / 1e8).toFixed(2) + "亿";
|
||||
if (v >= 1e4) return (v / 1e4).toFixed(2) + "万";
|
||||
return String(Math.round(v));
|
||||
}
|
||||
|
||||
function renderWecomDayRow(label, row) {
|
||||
if (!row?.rank) {
|
||||
return `<div class="wecom-day muted"><span class="wecom-day-label">${label}</span>—</div>`;
|
||||
}
|
||||
const pct = row.price_change_pct ?? 0;
|
||||
return `<div class="wecom-day">
|
||||
<span class="wecom-day-label">${label}</span>
|
||||
<span class="wecom-rank-num">#${row.rank}</span>
|
||||
<span class="wecom-vol">${row.quote_volume_fmt || row.quote_volume}</span>
|
||||
<span class="${pctClass(pct)}">${row.price_change_pct_fmt || pct.toFixed(2) + "%"}</span>
|
||||
<span class="wecom-fr">${row.funding_rate_fmt || "—"}</span>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function renderWecomPreview(payload) {
|
||||
const panel = document.getElementById("wecom-preview-panel");
|
||||
const cards = document.getElementById("wecom-preview-cards");
|
||||
const meta = document.getElementById("wecom-preview-meta");
|
||||
if (!panel || !cards) return;
|
||||
panel.classList.remove("hidden");
|
||||
if (!cards) return;
|
||||
wecomPreviewData = payload;
|
||||
updateStatsHeader(payload);
|
||||
if (!payload?.ok) {
|
||||
if (meta) meta.textContent = "未就绪";
|
||||
if (meta) meta.textContent = "";
|
||||
cards.innerHTML = `<p class="error">${escapeHtml(payload?.message || "无法生成预览")}</p>`;
|
||||
return;
|
||||
}
|
||||
if (meta) {
|
||||
const partsHint =
|
||||
payload.parts > 1 ? ` · 企微分 ${payload.parts} 条发送` : "";
|
||||
meta.textContent = `${payload.period_label || "—"} · ${payload.count} 个币种${partsHint}`;
|
||||
meta.textContent =
|
||||
`昨日周期 ${payload.period_label || "—"} · 昨/今/前 = 排名+涨跌幅` +
|
||||
(payload.parts > 1 ? ` · 超长将分 ${payload.parts} 条企微消息` : "");
|
||||
}
|
||||
if (!payload.items?.length) {
|
||||
cards.innerHTML = '<p class="loading">暂无三日交集币种</p>';
|
||||
return;
|
||||
}
|
||||
cards.innerHTML = payload.items
|
||||
.map(
|
||||
(it) => `
|
||||
.map((it) => {
|
||||
const line = (label, row) => {
|
||||
if (!row?.rank) return `${label}—`;
|
||||
const pct = row.price_change_pct ?? 0;
|
||||
const pctStr = row.price_change_pct_fmt || `${pct.toFixed(2)}%`;
|
||||
return `${label}<strong>#${row.rank}</strong><span class="${pctClass(pct)}">${pctStr}</span>`;
|
||||
};
|
||||
return `
|
||||
<article class="wecom-card">
|
||||
<header class="wecom-card-head">
|
||||
<span class="wecom-seq">${it.rank}</span>
|
||||
<strong class="wecom-symbol">${it.symbol}</strong>
|
||||
</header>
|
||||
${renderWecomDayRow("昨日", it.yesterday)}
|
||||
${renderWecomDayRow("今日", it.today)}
|
||||
${renderWecomDayRow("前日", it.daybefore)}
|
||||
</article>`
|
||||
)
|
||||
<p class="wecom-compact-line">${line("昨 ", it.yesterday)} ${line("今 ", it.today)} ${line("前 ", it.daybefore)}</p>
|
||||
</article>`;
|
||||
})
|
||||
.join("");
|
||||
}
|
||||
|
||||
@@ -417,35 +368,25 @@ async function testWecomPush() {
|
||||
}
|
||||
|
||||
async function loadStats() {
|
||||
document.getElementById("stats-table-wrap").innerHTML =
|
||||
'<p class="loading">统计中…</p>';
|
||||
try {
|
||||
const res = await fetch("/api/stats/three-day");
|
||||
statsData = await res.json();
|
||||
renderStatsTable();
|
||||
await loadWecomPreview();
|
||||
} catch (e) {
|
||||
document.getElementById("stats-table-wrap").innerHTML = `<p class="error">${e.message}</p>`;
|
||||
}
|
||||
await loadWecomPreview();
|
||||
}
|
||||
|
||||
function exportStatsCsv() {
|
||||
if (!statsData?.items?.length) return alert("暂无数据");
|
||||
const items = wecomPreviewData?.items;
|
||||
if (!items?.length) return alert("暂无数据");
|
||||
const header = [
|
||||
"合约",
|
||||
"今日排名", "今日涨跌%", "今日成交额",
|
||||
"昨日排名", "昨日涨跌%", "昨日成交额",
|
||||
"前日排名", "前日涨跌%", "前日成交额",
|
||||
"三日总成交额",
|
||||
"今日排名", "今日涨跌%",
|
||||
"昨日排名", "昨日涨跌%",
|
||||
"前日排名", "前日涨跌%",
|
||||
];
|
||||
const rows = statsData.items.map((r) => [
|
||||
const rows = items.map((r) => [
|
||||
r.symbol,
|
||||
r.today?.rank, r.today?.price_change_pct, r.today?.quote_volume,
|
||||
r.yesterday?.rank, r.yesterday?.price_change_pct, r.yesterday?.quote_volume,
|
||||
r.daybefore?.rank, r.daybefore?.price_change_pct, r.daybefore?.quote_volume,
|
||||
r.total_quote_volume,
|
||||
r.today?.rank, r.today?.price_change_pct,
|
||||
r.yesterday?.rank, r.yesterday?.price_change_pct,
|
||||
r.daybefore?.rank, r.daybefore?.price_change_pct,
|
||||
]);
|
||||
downloadCsv("binance-three-day-stats", header, rows, "stats");
|
||||
downloadCsv("binance-wecom-push", header, rows, wecomPreviewData?.period_label);
|
||||
}
|
||||
|
||||
function switchView(view) {
|
||||
@@ -458,7 +399,7 @@ function switchView(view) {
|
||||
});
|
||||
|
||||
if (view === "stats") {
|
||||
if (!statsData) loadStats();
|
||||
if (!wecomPreviewData) loadStats();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -492,11 +433,10 @@ document.getElementById("btn-refresh").addEventListener("click", async () => {
|
||||
});
|
||||
|
||||
document.getElementById("btn-reload-stats")?.addEventListener("click", () => {
|
||||
statsData = null;
|
||||
wecomPreviewData = null;
|
||||
loadStats();
|
||||
});
|
||||
document.getElementById("btn-export-stats")?.addEventListener("click", exportStatsCsv);
|
||||
document.getElementById("btn-push-preview")?.addEventListener("click", loadWecomPreview);
|
||||
document.getElementById("btn-push-test")?.addEventListener("click", testWecomPush);
|
||||
|
||||
loadPeriod("today");
|
||||
|
||||
Reference in New Issue
Block a user