Refine business monitoring UI and protect asynchronous navigation

This commit is contained in:
oliver 2026-10-11 00:30:30 +08:00
parent 5403c7d939
commit 8c15975d3e
14 changed files with 866 additions and 148 deletions

View file

@ -174,6 +174,20 @@ const en = {
},
bizState: {
title: "Business monitor",
loadedTasks: "Loaded tasks",
loadedBatches: "Recent batches · {{n}} loaded (up to 200)",
collectErrors: "Recent collection errors",
retry: "Retry",
taskLoading: "Loading task configuration…",
tasksLoadError: "Could not load tasks",
taskLoadError: "Could not load task configuration",
batchLoadError: "Could not load batch",
sheetLoadError: "Could not load structured data",
statusQueued: "Queued",
batchSuccess: "Collected",
batchPartial: "Partially completed",
batchFailed: "Collection failed",
batchCancelled: "Cancelled",
create: "Create task",
createHint: "Pick any valid NE (managed / UME); search supported",
createModeDevice: "Pick device",
@ -225,6 +239,7 @@ const en = {
statusCollecting: "Collecting",
detail: "Details",
interval: "Interval",
intervalUnit: "Interval unit",
intervalUnitDays: "days",
intervalUnitHours: "hours",
intervalUnitSeconds: "seconds",

View file

@ -174,6 +174,20 @@ const zh = {
},
bizState: {
title: "业务监控",
loadedTasks: "已载入任务",
loadedBatches: "最近批次 · 已载入 {{n}} 条(最多 200)",
collectErrors: "最近采集异常",
retry: "重试",
taskLoading: "正在读取任务配置…",
tasksLoadError: "任务列表读取失败",
taskLoadError: "任务配置读取失败",
batchLoadError: "批次读取失败",
sheetLoadError: "结构化数据读取失败",
statusQueued: "排队中",
batchSuccess: "采集成功",
batchPartial: "部分完成",
batchFailed: "采集失败",
batchCancelled: "已取消",
create: "创建任务",
createHint: "从托管 / UME 等有效网元中选择(支持查找)",
createModeDevice: "选择设备",
@ -225,6 +239,7 @@ const zh = {
statusCollecting: "采集中",
detail: "详情",
interval: "采集周期",
intervalUnit: "周期单位",
intervalUnitDays: "天",
intervalUnitHours: "小时",
intervalUnitSeconds: "秒",

View file

@ -12444,6 +12444,145 @@ html.login-page--paused .login-page__flare {
.bs-cmp-job-modal .is-indeterminate { animation: none; }
}
/* Business monitoring uses the same compact operations surfaces as comparison. */
.bs-monitor-workspace,
.bs-monitor-modal {
--mon-line: #2b3748;
--mon-muted: #9aa9bc;
--mon-accent: #6ba9ec;
}
.panel.bs-monitor-workspace,
.bs-monitor-modal .modal__dialog {
border-color: var(--mon-line);
border-radius: 6px;
background: #0c1521;
}
.bs-monitor-workspace .button,
.bs-monitor-modal .button,
.bs-monitor-workspace .input,
.bs-monitor-modal .input,
.bs-monitor-modal .ui-field__select {
border-radius: 4px;
box-shadow: none;
}
.bs-monitor-workspace .pt-list-kpis {
gap: 0;
border: 1px solid var(--mon-line);
border-radius: 4px;
overflow: hidden;
background: #111c2a;
}
.bs-monitor-workspace .pt-list-kpi {
border: 0;
border-right: 1px solid var(--mon-line);
border-radius: 0;
background: transparent;
}
.bs-monitor-workspace .pt-list-kpi:last-child { border-right: 0; }
.bs-monitor-workspace .pt-list-kpi__value { font-family: ui-monospace, Consolas, monospace; }
.bs-monitor-workspace .pt-list-kpi__label { font-size: 11px; color: var(--mon-muted); }
.bs-monitor-workspace .filter-inline,
.bs-monitor-modal .filter-inline {
flex-wrap: wrap;
border-radius: 4px;
}
.bs-monitor-workspace > .pt-list > .pt-list-table-wrap,
.bs-monitor-modal .pt-list-table-wrap {
border-color: var(--mon-line);
border-radius: 4px;
min-width: 0;
}
.bs-monitor-workspace > .pt-list > .pt-list-table-wrap .pt-list-table { min-width: 1120px; }
.bs-monitor-batches .pt-list-table { min-width: 1100px; }
.bs-monitor-workspace .pt-list-table th,
.bs-monitor-modal .pt-list-table th { background: #162232; font-size: 11px; }
.bs-monitor-workspace .pt-list-table td,
.bs-monitor-modal .pt-list-table td { border-bottom-color: var(--mon-line); }
.bs-monitor-workspace .pt-list-table td { font-size: 12px; }
.bs-monitor-workspace .pt-list-task-name + .muted { font-size: 11px; }
.bs-monitor-heading { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.bs-monitor-id { color: var(--mon-muted); font: 10px/1.4 ui-monospace, Consolas, monospace; }
.bs-monitor-heading > span:last-child { font-size: 16px; overflow-wrap: anywhere; }
.bs-monitor-task-content { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.bs-monitor-task-content[hidden] { display: none; }
.bs-monitor-task-content[inert] { opacity: 0.5; }
.bs-monitor-task .bs-schedule-row {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
align-items: start;
gap: 12px;
padding: 14px;
border: 1px solid var(--mon-line);
border-radius: 4px;
background: #111c2a;
}
.bs-monitor-task .bs-schedule-row > .muted { grid-column: 1 / -1; font-size: 11px; line-height: 1.6; }
.bs-monitor-task .config-sync-policy-field { min-width: 0; flex-wrap: wrap; }
.bs-monitor-task .config-sync-policy-field .input { min-width: 0; width: 100%; }
.bs-monitor-task .config-sync-policy-field > select { min-width: 0; border-radius: 4px; }
.bs-monitor-task .bs-monitor-interval-field { display: grid; grid-template-columns: minmax(0, 1fr) auto; }
.bs-monitor-task .bs-monitor-interval-field > span { grid-column: 1 / -1; }
.bs-monitor-modal .modal__footer { min-width: 0; max-width: 100%; flex-wrap: wrap; }
.bs-monitor-task .bs-monitor-task-tabs { gap: 0; margin: 0; border-bottom: 1px solid var(--mon-line); }
.bs-monitor-task-tabs .button { border: 0; border-radius: 0; border-bottom: 2px solid transparent; background: transparent; color: var(--mon-muted); }
.bs-monitor-task .bs-monitor-task-tabs .button.is-active { border-bottom-color: var(--mon-accent); color: #edf5ff; background: rgba(107,169,236,0.08); outline: none; box-shadow: none; }
.bs-monitor-task-tabs .button:focus-visible { outline: 2px solid var(--mon-accent); outline-offset: -2px; }
.bs-monitor-history-count { flex: 1 1 240px; font-size: 11px; }
.bs-monitor-batches > .btn-row { padding: 10px; }
.bs-monitor-workspace .bs-monitor-delete,
.bs-monitor-modal .bs-monitor-delete { color: #fca5a5; }
.bs-monitor-loading { padding: 16px; color: var(--mon-muted); font-size: 12px; }
.bs-monitor-error {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 8px;
padding: 10px;
border: 1px solid #7f4343;
border-radius: 4px;
color: #fecaca;
background: rgba(127,67,67,0.1);
font-size: 12px;
overflow-wrap: anywhere;
}
.bs-monitor-modal .bs-workbook-meta,
.bs-monitor-modal .bs-sheet-cmd-bar,
.bs-monitor-modal .bs-sheet-cmd-row,
.bs-monitor-modal .bs-sheet-tab { border-radius: 4px; background-image: none; }
.bs-monitor-modal .bs-sheet-tabs { min-width: 0; flex-wrap: nowrap; overflow-x: auto; }
.bs-monitor-modal .bs-sheet-tab { flex: 0 0 auto; }
.bs-monitor-modal .bs-sheet-filter { gap: 8px; }
.bs-monitor-modal .bs-sheet-filter .input { flex: 1 1 200px; min-width: 0; }
.bs-monitor-modal .bs-sheet-filter .ui-field { min-width: 0; max-width: 100%; }
.bs-monitor-modal .bs-sheet-filter .ui-field__select { max-width: 100%; }
.bs-monitor-modal .bs-sheet-count { margin-left: auto; }
@media (max-width: 800px) {
.bs-monitor-workspace .pt-list-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.bs-monitor-workspace .pt-list-kpi:nth-child(2) { border-right: 0; }
.bs-monitor-workspace .pt-list-kpi:nth-child(-n+2) { border-bottom: 1px solid var(--mon-line); }
.bs-monitor-task .bs-schedule-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 600px) {
.bs-monitor-task .bs-schedule-row { grid-template-columns: minmax(0, 1fr); }
.bs-monitor-modal .bs-sheet-filter > .input { flex-basis: 100%; }
}
/* Native :fullscreen + CSS immersive fallback (class only when FS API blocked) */
.bs-cmp-board.is-fullscreen,
.bs-cmp-board:fullscreen {

File diff suppressed because it is too large Load diff

View file

@ -1944,6 +1944,9 @@ export const bizStatePurgeTask = (taskId: string) =>
export const bizStateGetBatch = (batchId: string) =>
apiGet<Record<string, unknown>>(`/v1/biz-state/batches/${encodeURIComponent(batchId)}`);
export const bizStateGetTaskProgress = (taskId: string) =>
apiGet<Record<string, unknown>>(`/v1/biz-state/tasks/${encodeURIComponent(taskId)}/progress`);
export const bizStateListBatchMetricRows = (params: {
batchId: string;
metricId: string;