feat: archive entry type from review, prune stale trades on sync, manual delete
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -109,14 +109,25 @@
|
||||
return mins + "分钟";
|
||||
}
|
||||
|
||||
const ENTRY_TYPE_LABELS = {
|
||||
trend_pullback: "趋势回调",
|
||||
roll: "顺势加仓",
|
||||
trend: "趋势回调",
|
||||
};
|
||||
|
||||
function fmtEntryType(tr) {
|
||||
if (!tr) return "—";
|
||||
return (
|
||||
tr.entry_type ||
|
||||
tr.entry_reason ||
|
||||
tr.monitor_type ||
|
||||
"—"
|
||||
);
|
||||
const raw = String(
|
||||
tr.entry_type || tr.entry_reason || tr.reviewed_entry_reason || ""
|
||||
).trim();
|
||||
if (raw) {
|
||||
return ENTRY_TYPE_LABELS[raw] || raw;
|
||||
}
|
||||
const mt = String(tr.monitor_type || "").trim();
|
||||
if (mt && mt !== "下单监控") {
|
||||
return ENTRY_TYPE_LABELS[mt] || mt;
|
||||
}
|
||||
return "—";
|
||||
}
|
||||
|
||||
function reviewMark(tr) {
|
||||
@@ -551,7 +562,7 @@
|
||||
elTrades.innerHTML =
|
||||
'<table class="archive-trades-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><th>盈亏</th><th>标签</th><th>备注</th><th>操作</th>" +
|
||||
"</tr></thead><tbody>" +
|
||||
trades
|
||||
.map(function (t) {
|
||||
@@ -618,15 +629,30 @@
|
||||
'" value="' +
|
||||
String(t.note || "").replace(/"/g, """) +
|
||||
'" placeholder="备注" /></td>' +
|
||||
'<td><button type="button" class="archive-del-btn" data-id="' +
|
||||
tid +
|
||||
'" title="从档案移除(不影响实例复盘库)">删除</button></td>' +
|
||||
"</tr>"
|
||||
);
|
||||
})
|
||||
.join("") +
|
||||
"</tbody></table>";
|
||||
|
||||
elTrades.querySelectorAll(".archive-del-btn").forEach(function (btn) {
|
||||
btn.addEventListener("click", function (ev) {
|
||||
ev.stopPropagation();
|
||||
void deleteTrade(btn.getAttribute("data-id"));
|
||||
});
|
||||
});
|
||||
elTrades.querySelectorAll(".archive-trade-row").forEach(function (row) {
|
||||
row.addEventListener("click", function (ev) {
|
||||
if (ev.target.closest("select") || ev.target.closest("input")) return;
|
||||
if (
|
||||
ev.target.closest("select") ||
|
||||
ev.target.closest("input") ||
|
||||
ev.target.closest(".archive-del-btn")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
selectedTradeId = row.getAttribute("data-id");
|
||||
renderTrades();
|
||||
applyChartMarkers();
|
||||
@@ -650,6 +676,32 @@
|
||||
});
|
||||
}
|
||||
|
||||
async function deleteTrade(tradeId) {
|
||||
if (!selected || tradeId == null) return;
|
||||
if (!window.confirm("从币种档案移除该笔交易?(不影响交易所实例里的复盘记录)")) return;
|
||||
const r = await apiFetch(
|
||||
"/api/archive/trade/" + selected.exchange_key + "/" + tradeId,
|
||||
{ method: "DELETE" }
|
||||
);
|
||||
if (!r.ok) {
|
||||
const j = await r.json().catch(function () {
|
||||
return {};
|
||||
});
|
||||
setStatus(j.detail || j.msg || "删除失败");
|
||||
return;
|
||||
}
|
||||
if (String(selectedTradeId) === String(tradeId)) {
|
||||
selectedTradeId = null;
|
||||
}
|
||||
trades = trades.filter(function (t) {
|
||||
return String(t.trade_id || t.id) !== String(tradeId);
|
||||
});
|
||||
renderTrades();
|
||||
applyChartMarkers();
|
||||
await loadList();
|
||||
setStatus("已移除 1 笔档案记录");
|
||||
}
|
||||
|
||||
async function saveOverlay(tradeId, tag, note) {
|
||||
if (!selected) return;
|
||||
const body = { behavior_tag: tag || "", note: note != null ? note : undefined };
|
||||
@@ -742,7 +794,12 @@
|
||||
if (row.ok === false) {
|
||||
parts.push(label + " 失败: " + (row.msg || "未知错误"));
|
||||
} else {
|
||||
parts.push(label + " " + (row.trade_count != null ? row.trade_count : row.trades || 0) + " 笔");
|
||||
let line =
|
||||
label + " " + (row.trade_count != null ? row.trade_count : row.trades || 0) + " 笔";
|
||||
if (row.trades_removed > 0) {
|
||||
line += " 清" + row.trades_removed;
|
||||
}
|
||||
parts.push(line);
|
||||
}
|
||||
});
|
||||
return parts.join(" · ");
|
||||
|
||||
Reference in New Issue
Block a user