条件单拆成进行中与已结束两表,并展示开仓时间。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-10-06 16:20:33 +08:00
parent da1bae8751
commit 4ecabd414c
4 changed files with 2314 additions and 2265 deletions
+62 -25
View File
@@ -152,6 +152,17 @@
}); });
} }
function isActiveOrder(o) {
const st = String((o && o.status) || "");
return st === "armed" || st === "triggering" || st === "open";
}
function formatOpenTime(o) {
const raw = String((o && o.opened_at) || "").trim();
if (!raw) return "—";
return raw.replace("T", " ").slice(0, 19);
}
function renderPhoneOrderCard(o) { function renderPhoneOrderCard(o) {
const exit = orderExitText(o); const exit = orderExitText(o);
const meta = []; const meta = [];
@@ -176,6 +187,9 @@
escapeHtml(orderTriggerText(o)) + escapeHtml(orderTriggerText(o)) +
"</div>" + "</div>" +
(meta.length ? '<div class="hub-phone-cond-meta muted">' + escapeHtml(meta.join(" · ")) + "</div>" : "") + (meta.length ? '<div class="hub-phone-cond-meta muted">' + escapeHtml(meta.join(" · ")) + "</div>" : "") +
'<div class="hub-phone-cond-meta muted">开仓 ' +
escapeHtml(formatOpenTime(o)) +
"</div>" +
(o.message ? '<div class="hub-phone-cond-msg muted">' + escapeHtml(o.message) + "</div>" : "") + (o.message ? '<div class="hub-phone-cond-msg muted">' + escapeHtml(o.message) + "</div>" : "") +
(actions ? '<div class="hub-phone-cond-actions">' + actions + "</div>" : "") + (actions ? '<div class="hub-phone-cond-actions">' + actions + "</div>" : "") +
"</article>" "</article>"
@@ -274,29 +288,8 @@
renderCandidateGroup("", other, checkedIds); renderCandidateGroup("", other, checkedIds);
} }
async function loadOrders() { function renderDesktopRows(list) {
const box = document.getElementById("cond-list"); return list
if (!box) return;
const r = await fetch("/api/cond_orders");
const d = await r.json();
const list = d.orders || [];
if (!list.length) {
box.innerHTML = '<div class="cond-empty">暂无条件单</div>';
return;
}
if (isHubPhone()) {
box.innerHTML =
'<div class="hub-phone-cond-list">' +
list.map(renderPhoneOrderCard).join("") +
"</div>";
bindOrderActions(box);
return;
}
box.innerHTML =
'<div class="overview-table-wrap cond-table-wrap"><table class="overview-table"><thead><tr>' +
"<th>客户端</th><th>状态</th><th>标的</th><th>触发</th><th>偏离</th><th>到期h</th><th>出场</th><th>说明</th><th>操作</th>" +
"</tr></thead><tbody>" +
list
.map(function (o) { .map(function (o) {
return ( return (
"<tr>" + "<tr>" +
@@ -323,6 +316,9 @@
"<td>" + "<td>" +
escapeHtml(orderExitText(o) || "—") + escapeHtml(orderExitText(o) || "—") +
"</td>" + "</td>" +
'<td class="cond-td-time">' +
escapeHtml(formatOpenTime(o)) +
"</td>" +
'<td class="muted">' + '<td class="muted">' +
escapeHtml(o.message || "") + escapeHtml(o.message || "") +
"</td>" + "</td>" +
@@ -332,11 +328,52 @@
"</tr>" "</tr>"
); );
}) })
.join("") + .join("");
"</tbody></table></div>"; }
function renderDesktopTable(list, emptyText) {
if (!list.length) {
return '<div class="cond-empty">' + escapeHtml(emptyText) + "</div>";
}
return (
'<div class="overview-table-wrap cond-table-wrap"><table class="overview-table"><thead><tr>' +
"<th>客户端</th><th>状态</th><th>标的</th><th>触发</th><th>偏离</th><th>到期h</th><th>出场</th><th>开仓时间</th><th>说明</th><th>操作</th>" +
"</tr></thead><tbody>" +
renderDesktopRows(list) +
"</tbody></table></div>"
);
}
function renderPhoneList(list, emptyText) {
if (!list.length) {
return '<div class="cond-empty">' + escapeHtml(emptyText) + "</div>";
}
return '<div class="hub-phone-cond-list">' + list.map(renderPhoneOrderCard).join("") + "</div>";
}
function fillOrderBox(box, list, emptyText) {
if (!box) return;
box.innerHTML = isHubPhone() ? renderPhoneList(list, emptyText) : renderDesktopTable(list, emptyText);
bindOrderActions(box); bindOrderActions(box);
} }
async function loadOrders() {
const activeBox = document.getElementById("cond-list-active");
const doneBox = document.getElementById("cond-list-done");
if (!activeBox && !doneBox) return;
const r = await fetch("/api/cond_orders");
const d = await r.json();
const list = d.orders || [];
const active = [];
const done = [];
list.forEach(function (o) {
if (isActiveOrder(o)) active.push(o);
else done.push(o);
});
fillOrderBox(activeBox, active, "暂无进行中的条件单");
fillOrderBox(doneBox, done, "暂无已结束的条件单");
}
async function createOrder() { async function createOrder() {
const status = document.getElementById("cf-status"); const status = document.getElementById("cf-status");
const ids = Array.prototype.slice const ids = Array.prototype.slice
+5
View File
@@ -1562,6 +1562,11 @@ input.readonly {
.cond-st.st-open { color: var(--ok); background: rgba(52, 211, 153, 0.12); } .cond-st.st-open { color: var(--ok); background: rgba(52, 211, 153, 0.12); }
.cond-st.st-done { color: var(--muted); background: rgba(138, 160, 184, 0.12); } .cond-st.st-done { color: var(--muted); background: rgba(138, 160, 184, 0.12); }
.cond-table-wrap { margin-top: 0; } .cond-table-wrap { margin-top: 0; }
.cond-td-time {
white-space: nowrap;
font-variant-numeric: tabular-nums;
font-size: 0.82rem;
}
/* —— 数据统计 —— */ /* —— 数据统计 —— */
.stats-head { .stats-head {
+1 -1
View File
@@ -11,7 +11,7 @@
<link rel="icon" href="{{ url_for('static', filename='icons/favicon.ico') }}?v=2" sizes="any"> <link rel="icon" href="{{ url_for('static', filename='icons/favicon.ico') }}?v=2" sizes="any">
<link rel="apple-touch-icon" href="{{ url_for('static', filename='icons/apple-touch-icon.png') }}?v=2"> <link rel="apple-touch-icon" href="{{ url_for('static', filename='icons/apple-touch-icon.png') }}?v=2">
<link rel="manifest" href="/manifest.webmanifest"> <link rel="manifest" href="/manifest.webmanifest">
<link rel="stylesheet" href="{{ url_for('static', filename='hub.css') }}?v=43"> <link rel="stylesheet" href="{{ url_for('static', filename='hub.css') }}?v=44">
<script> <script>
(function () { (function () {
try { try {
+10 -3
View File
@@ -79,13 +79,20 @@
<section class="panel cond-card"> <section class="panel cond-card">
<div class="cond-card-head"> <div class="cond-card-head">
<h2>条件单历史</h2> <h2>进行中</h2>
</div> </div>
<div id="cond-list" class="muted">加载中…</div> <div id="cond-list-active" class="muted">加载中…</div>
</section>
<section class="panel cond-card">
<div class="cond-card-head">
<h2>已结束</h2>
</div>
<div id="cond-list-done" class="muted">加载中…</div>
</section> </section>
</div> </div>
{% endblock %} {% endblock %}
{% block scripts %} {% block scripts %}
<script src="{{ url_for('static', filename='cond_orders.js') }}?v=3"></script> <script src="{{ url_for('static', filename='cond_orders.js') }}?v=4"></script>
<script>HubCondOrders.boot();</script> <script>HubCondOrders.boot();</script>
{% endblock %} {% endblock %}