feat(HEL-566): 去掉主站行情管理入口并修好模型列表收起

主站行情管理并入数据中枢
- 数据中枢数据源配置页新增「主站行情任务」卡:交易时段后台刷新开关、
  手动后台刷新、历史区间回补(任务提交 + 轮询主站 job 记录亮灯),
  数据与调度仍归主站,控制台只经桥接代操作
- 新增桥接端点 /api/hub-admin/market/{refresh,backfill};回补改为
  market.backfill 后台任务(jobs.config.json 注册,锁独立,超时 30 分钟),
  桥接调用秒回,不再阻塞
- 主站桌面端删除顶栏「行情管理」按钮与整个行情管理对话框,清理随之
  失效的 CSS;移动端删除 system/admin 页与入口,管理员专区只留数据中枢
- Tushare Token / iFinD 凭证编辑沿用数据源页既有凭证区,无功能缺失

模型池收起修复
- 拉出模型清单后按钮切换为「收起列表」,收起只留一行摘要;再次点击
  重新拉取并展开;勾选添加完成后清单自动收起(原逻辑保留)
- 交互全部沿用 HEL-558 已确认样式的既有按钮与提示组件,未新增视觉

自测
- verify_baseline 通过;pytest 492 项通过;数据中枢 240 项通过
- verify_datahub_console 新增 [11b] 行情任务桥接端到端段;UI 自测新增
  行情任务卡开关往返、模型清单展开/收起/再展开/添加自动收起,日夜主题
  与 1030 窄屏复验通过
- Playwright e2e 102/103:唯一失败项在基线提交上同样失败(本机字体度量
  导致的头部溢出,与本卡无关)

Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
总工
2026-09-16 17:24:05 +08:00
co-authored by multica-agent
parent 44d6de3e2b
commit fa82b8621e
28 changed files with 563 additions and 551 deletions
+6 -142
View File
@@ -3132,7 +3132,6 @@
"system/profile": setupSystemPage,
"system/password": setupSystemPage,
"system/membership": setupSystemPage,
"system/admin": setupSystemPage,
};
const COMPLEX_LOADERS = {
@@ -3154,7 +3153,6 @@
"system/profile": loadSystem,
"system/password": loadSystem,
"system/membership": loadSystem,
"system/admin": loadSystem,
};
function isComplexPage(key) {
@@ -4928,14 +4926,6 @@
return String(key || state.key || "").indexOf("system/") === 0;
}
function systemForbiddenHtml() {
return '<div class="m-state m-motion-rise-in" data-system-page="forbidden">' +
'<span class="m-state-icon">' + icon("lock", 26) + "</span>" +
"<p>仅管理员可访问</p>" +
"<small>行情管理与数据中枢需要管理员权限。</small>" +
"</div>";
}
function systemFill(html) {
const scroll = document.getElementById("m-scroll");
if (scroll) scroll.innerHTML = html;
@@ -4975,26 +4965,17 @@
function loadSystem() {
const key = state.key;
if (key === "system/admin" && !global.MobileSession.isAdmin()) {
systemFill(systemForbiddenHtml());
return;
}
if (key === "system/password") {
renderSystemPassword();
return;
}
const seq = nextSeq();
const url = key === "system/admin" ? "/api/admin/settings" : "/api/account/status";
const url = "/api/account/status";
return global.MobileAPI.request(url).then(function (payload) {
if (seq !== state.seq || state.key !== key) return;
if (key === "system/admin") {
state.system.admin = payload || {};
renderSystemAdmin();
} else {
state.system.account = payload || {};
if (key === "system/profile") renderSystemProfile();
else renderSystemMembership();
}
state.system.account = payload || {};
if (key === "system/profile") renderSystemProfile();
else renderSystemMembership();
}).catch(function (error) {
if (seq !== state.seq || state.key !== key) return;
systemFill(errorHtml(error && error.message ? error.message : "加载失败"));
@@ -5078,9 +5059,6 @@
{ key: "system/password", icon: "lock", label: "修改密码", hint: "建议定期更换" },
{ key: "system/membership", icon: "gem", label: "会员状态", hint: "有效期与智能分析额度" }
];
const adminRows = [
{ key: "system/admin", icon: "sliders-horizontal", label: "行情管理", hint: "数据源状态 · 后台刷新 · 历史回补" }
];
const html =
'<div class="m-sys-home" data-system-page="home">' +
'<div class="m-card m-sys-profile-card"><span class="m-sys-avatar">' + escapeHtml(avatar) + "</span><div>" +
@@ -5093,7 +5071,7 @@
'<h3 class="m-sys-group-title">偏好</h3>' +
'<div class="m-card m-sys-list">' + systemThemeRowHtml() + "</div>" +
(global.MobileSession.isAdmin()
? '<h3 class="m-sys-group-title">管理员专区</h3><div class="m-card m-sys-list">' + adminRows.map(systemRowHtml).join("") + dataHubRowHtml() + "</div>"
? '<h3 class="m-sys-group-title">管理员专区</h3><div class="m-card m-sys-list">' + dataHubRowHtml() + "</div>"
: "") +
'<h3 class="m-sys-group-title">其他</h3>' +
'<div class="m-card m-sys-list">' +
@@ -5106,7 +5084,7 @@
'<span class="m-sys-row-body"><strong>退出登录</strong><small>退出后需要重新登录</small></span>' +
'<span class="m-sys-row-chevron">' + icon("chevron-right", 16) + "</span></button>" +
"</div>" +
'<p class="m-sys-foot">' + (global.MobileSession.isAdmin() ? "小白复盘 · 内网个人版" : "行情管理与数据中枢仅管理员可见") + "</p>" +
'<p class="m-sys-foot">' + (global.MobileSession.isAdmin() ? "小白复盘 · 内网个人版" : "数据中枢仅管理员可见") + "</p>" +
"</div>";
document.getElementById("m-view").innerHTML = html;
}
@@ -5196,55 +5174,6 @@
systemFill(html);
}
function statusDot(ok) {
return '<span class="m-sys-dot' + (ok ? " m-sys-dot--ok" : "") + '"></span>';
}
function datahubStatusText(hub) {
const enabled = number(hub.enabled_reads);
const total = number(hub.total_reads) || enabled;
const fallbacks = hub.fallback_labels || [];
if (fallbacks.length) return " 备用 " + fallbacks.join("、");
if (hub.configured) return " 主线路 " + enabled + "/" + total;
return " 未配置";
}
function renderSystemAdmin() {
const payload = state.system.admin || {};
const data = payload.data || {};
const ifind = data.ifind || {};
const marketHtml =
'<div class="m-sys-body" data-system-admin-panel="market">' +
'<div class="m-card m-sys-section"><strong>数据源状态</strong>' +
'<div class="m-sys-status-list">' +
'<div class="m-sys-status-item"><span>数据中枢</span><span>' + statusDot(data.configured) + (data.configured ? " 已连接" : " 未连接") + "</span></div>" +
'<div class="m-sys-status-item"><span>iFinD</span><span>' + statusDot(ifind.configured) + (ifind.configured ? " 已配置" : " 未配置") + "</span></div>" +
'<div class="m-sys-status-item"><span>行情快照</span><strong>' + number(data.snapshot_dates) + " 个交易日</strong></div>" +
'<div class="m-sys-status-item"><span>后台刷新</span><span>' + statusDot(data.background_refresh_enabled) + (data.background_refresh_enabled ? " 已启用" : " 已暂停") + "</span></div>" +
'<div class="m-sys-status-item"><span>数据中枢</span><span>' + statusDot(Boolean((data.datahub || {}).configured) && !((data.datahub || {}).fallback_count)) + datahubStatusText(data.datahub || {}) + "</span></div>" +
"</div></div>" +
'<div class="m-card m-sys-section"><strong>数据源密钥</strong>' +
formFieldHtml("行情来源凭据", '<input id="m-sys-token" type="text" value="请在数据中枢后台统一管理" disabled>', false) +
formFieldHtml("实时来源凭据", '<input id="m-sys-ifind" type="text" value="请在数据中枢后台统一管理" disabled>', false) +
'<button class="m-btn-primary" type="button" data-system-save-market>刷新状态</button></div>' +
'<div class="m-card m-sys-section"><strong>后台刷新</strong>' +
'<div class="m-sys-switch-row"><div><strong>交易时段自动刷新</strong><p class="m-sys-hint">开启后后台定时更新快照</p></div>' +
'<button class="m-theme-switch" type="button" data-system-toggle-refresh role="switch" aria-checked="' + (data.background_refresh_enabled ? "true" : "false") + '" aria-label="交易时段自动刷新"><span class="m-theme-switch-thumb"></span></button></div>' +
'<input id="m-sys-bg-refresh" type="checkbox"' + (data.background_refresh_enabled ? " checked" : "") + ' hidden>' +
'<button class="m-btn-outline" type="button" data-system-refresh>立即刷新一次</button>' +
'<p class="m-sys-hint">所有用户读取同一份快照,刷新不影响当前页面内容。</p></div>' +
'<div class="m-card m-sys-section"><strong>历史数据回补</strong>' +
formFieldHtml("开始日期", dateInputHtml("m-sys-backfill-start", ""), false) +
formFieldHtml("结束日期", dateInputHtml("m-sys-backfill-end", ""), false) +
'<button class="m-btn-outline" type="button" data-system-backfill>开始回补</button>' +
'<p class="m-sys-hint">回补用于补齐缺失的历史行情,开始前会再次确认;回补期间页面可正常使用。</p></div>' +
'<div class="m-card m-sys-section"><strong>模型池 · 会员 · 邀请码</strong>' +
'<p class="m-sys-hint">这些配置已统一在数据中枢管理。</p>' +
'<button class="m-btn-outline" type="button" data-system-datahub>打开数据中枢</button></div>' +
"</div>";
systemFill(marketHtml);
}
function dataHubConsoleUrl() {
if (global.XIAOBAI_DATAHUB_URL) return String(global.XIAOBAI_DATAHUB_URL);
// HEL-564: 固定内网地址,见 frontend/shared/admin.js 同名函数。
@@ -5373,67 +5302,6 @@
});
}
function saveSystemMarket() {
const button = document.querySelector("[data-system-save-market]");
if (button) button.disabled = true;
loadSystem().then(function () {
showToast("数据中枢状态已刷新");
}).catch(function (error) {
showToast(error && error.message ? error.message : "数据中枢状态读取失败");
}).then(function () {
if (button) button.disabled = false;
});
}
function toggleSystemRefresh() {
const enabled = !Boolean((state.system.admin && state.system.admin.data && state.system.admin.data.background_refresh_enabled));
global.MobileAPI.request("/api/admin/settings", "POST", {
background_refresh_enabled: enabled,
}).then(function () {
showToast(enabled ? "后台刷新已启用" : "后台刷新已暂停");
loadSystem();
}).catch(function (error) {
showToast(error && error.message ? error.message : "后台刷新设置失败");
});
}
function startSystemRefresh() {
const button = document.querySelector("[data-system-refresh]");
if (button) button.disabled = true;
global.MobileAPI.request("/api/admin/refresh", "POST", { trade_date: todayString() }).then(function (payload) {
showToast((payload && payload.message) || "后台刷新已提交");
}).catch(function (error) {
showToast(error && error.message ? error.message : "后台刷新启动失败");
}).then(function () {
if (button) button.disabled = false;
});
}
function startSystemBackfill() {
const startDate = (document.getElementById("m-sys-backfill-start") || {}).value;
const endDate = (document.getElementById("m-sys-backfill-end") || {}).value;
openConfirmSheet("开始历史回补?", "将按选定日期补齐缺失行情,回补期间页面仍可使用。", {
confirmLabel: "开始回补",
centered: true,
onConfirm: function () {
const button = document.querySelector("[data-system-backfill]");
if (button) button.disabled = true;
global.MobileAPI.request("/api/backfill", "POST", {
start_date: startDate,
end_date: endDate,
}).then(function (payload) {
const count = payload && payload.results ? payload.results.length : 0;
showToast("历史回补完成,共处理 " + count + " 个工作日");
loadSystem();
}).catch(function (error) {
showToast(error && error.message ? error.message : "回补失败");
}).then(function () {
if (button) button.disabled = false;
});
}
});
}
function bindEvents() {
window.addEventListener("hashchange", closeSheet);
@@ -5566,10 +5434,6 @@
if (event.target.closest("[data-system-save-password]")) { saveSystemPassword(); return; }
if (event.target.closest("[data-system-switch]")) { switchSystemAccount(); return; }
if (event.target.closest("[data-system-logout]")) { logoutSystemAccount(); return; }
if (event.target.closest("[data-system-save-market]")) { saveSystemMarket(); return; }
if (event.target.closest("[data-system-toggle-refresh]")) { toggleSystemRefresh(); return; }
if (event.target.closest("[data-system-refresh]")) { startSystemRefresh(); return; }
if (event.target.closest("[data-system-backfill]")) { startSystemBackfill(); return; }
if (event.target.closest("[data-system-datahub]")) { openDataHubConsole(); return; }
// 我的复盘:新增/编辑/删除/筛选/提交等操作