feat(盯盘): 筛选/排序控制条——信号多选chips+排序下拉(RR升降/涨跌升降)+RR下限过滤+重置
This commit is contained in:
+80
-2
@@ -94,6 +94,28 @@ body { background: #0f0f13; color: #e2e8f0; }
|
||||
<h2 class="text-lg font-semibold text-slate-200">👁️ 盯盘 · 全部策略</h2>
|
||||
<span class="text-xs text-slate-500"><span id="watchRefreshTime">—</span> <span id="watchCount" class="text-yellow-400 font-mono">0</span> 只</span>
|
||||
</div>
|
||||
<!-- 筛选/排序控制条 -->
|
||||
<div class="mb-3 p-2 rounded-lg bg-slate-800/40 border border-slate-700/50 text-xs space-y-2">
|
||||
<div class="flex flex-wrap items-center gap-1.5">
|
||||
<span class="text-slate-500 mr-1">信号:</span>
|
||||
<span id="watchSigChips"></span>
|
||||
<button onclick="watchSigAll(true)" class="px-1.5 py-0.5 rounded text-slate-400 hover:text-white border border-slate-600">全选</button>
|
||||
<button onclick="watchSigAll(false)" class="px-1.5 py-0.5 rounded text-slate-400 hover:text-white border border-slate-600">清空</button>
|
||||
</div>
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<span class="text-slate-500">排序:</span>
|
||||
<select id="watchSortMode" onchange="renderWatch()" class="bg-slate-900 border border-slate-600 rounded px-1.5 py-0.5 text-slate-300">
|
||||
<option value="default">默认(分组)</option>
|
||||
<option value="rr_desc">RR 从高到低</option>
|
||||
<option value="rr_asc">RR 从低到高</option>
|
||||
<option value="chg_desc">涨幅从高到低</option>
|
||||
<option value="chg_asc">跌幅从高到低</option>
|
||||
</select>
|
||||
<span class="text-slate-500 ml-2">RR ≥</span>
|
||||
<input id="watchMinRR" type="number" step="0.1" min="0" placeholder="0" onchange="renderWatch()" class="w-16 bg-slate-900 border border-slate-600 rounded px-1.5 py-0.5 text-slate-300">
|
||||
<button onclick="watchResetFilters()" class="px-2 py-0.5 rounded bg-slate-700 text-slate-300 hover:bg-slate-600 ml-1">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="watchContent" class="card overflow-hidden"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1368,18 +1390,74 @@ function fmtFullStrategy(s) {
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
// ── 盯盘筛选/排序状态 ──
|
||||
const WATCH_SIGNALS = ['买入','可买入','可加仓','卖出','止盈','关注','观望','持有','弱势持有','信号不充分'];
|
||||
let watchSigFilter = new Set(WATCH_SIGNALS); // 默认全选
|
||||
let watchChipsInit = false;
|
||||
|
||||
function watchRenderChips() {
|
||||
const host = document.getElementById('watchSigChips');
|
||||
if (!host) return;
|
||||
host.innerHTML = WATCH_SIGNALS.map(sig => {
|
||||
const on = watchSigFilter.has(sig);
|
||||
const cls = on
|
||||
? 'bg-amber-500/25 text-amber-300 border-amber-500/50'
|
||||
: 'bg-slate-800/50 text-slate-500 border-slate-700';
|
||||
return `<button onclick="watchToggleSig('${sig}')" class="px-1.5 py-0.5 rounded border ${cls} transition">${sig}</button>`;
|
||||
}).join('');
|
||||
}
|
||||
function watchToggleSig(sig) {
|
||||
if (watchSigFilter.has(sig)) watchSigFilter.delete(sig);
|
||||
else watchSigFilter.add(sig);
|
||||
watchRenderChips();
|
||||
renderWatch();
|
||||
}
|
||||
function watchSigAll(all) {
|
||||
watchSigFilter = all ? new Set(WATCH_SIGNALS) : new Set();
|
||||
watchRenderChips();
|
||||
renderWatch();
|
||||
}
|
||||
function watchResetFilters() {
|
||||
watchSigFilter = new Set(WATCH_SIGNALS);
|
||||
document.getElementById('watchSortMode').value = 'default';
|
||||
document.getElementById('watchMinRR').value = '';
|
||||
watchRenderChips();
|
||||
renderWatch();
|
||||
}
|
||||
|
||||
async function renderWatch() {
|
||||
const el = document.getElementById('watchContent');
|
||||
if (!el) return;
|
||||
try {
|
||||
if (watchTimer) clearInterval(watchTimer);
|
||||
if (!watchChipsInit) { watchRenderChips(); watchChipsInit = true; }
|
||||
const data = await fetchJSON('/api/watch');
|
||||
const stocks = data.stocks || [];
|
||||
let stocks = data.stocks || [];
|
||||
|
||||
// ── 筛选:信号多选 + RR下限 ──
|
||||
const minRR = parseFloat(document.getElementById('watchMinRR')?.value) || 0;
|
||||
stocks = stocks.filter(s => {
|
||||
const sig = s.timing_signal || '信号不充分';
|
||||
if (!watchSigFilter.has(sig)) return false;
|
||||
if (minRR > 0 && (s.rr_ratio || 0) < minRR) return false;
|
||||
return true;
|
||||
});
|
||||
|
||||
// ── 排序:默认=服务端分组序;覆盖模式按选定键全组内排序 ──
|
||||
const sortMode = document.getElementById('watchSortMode')?.value || 'default';
|
||||
const sorters = {
|
||||
rr_desc: (a, b) => (b.rr_ratio || 0) - (a.rr_ratio || 0),
|
||||
rr_asc: (a, b) => (a.rr_ratio || 0) - (b.rr_ratio || 0),
|
||||
chg_desc: (a, b) => (b.change_pct || 0) - (a.change_pct || 0),
|
||||
chg_asc: (a, b) => (a.change_pct || 0) - (b.change_pct || 0),
|
||||
};
|
||||
if (sorters[sortMode]) stocks = [...stocks].sort(sorters[sortMode]);
|
||||
|
||||
document.getElementById('watchCount').textContent = stocks.length;
|
||||
document.getElementById('watchRefreshTime').textContent = new Date().toLocaleTimeString();
|
||||
|
||||
if (stocks.length === 0) {
|
||||
el.innerHTML = '<div class="p-6 text-center text-slate-500 text-sm">暂无策略数据</div>';
|
||||
el.innerHTML = '<div class="p-6 text-center text-slate-500 text-sm">当前筛选条件下暂无个股(调整筛选或点重置)</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user