Redesign biz compare: editable templates and pre/post result workbook.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-09-17 17:26:52 +08:00
parent 4811a25ac3
commit 14f5870e19
8 changed files with 1133 additions and 298 deletions

View file

@ -45,7 +45,7 @@ src/
| `/network/tasks/port-traffic` | 端口流量监控(设备管理) | `network` |
| `/network/tasks/port-traffic/wall` | 流量大屏列表(打开独立页签) | `network` |
| `/network/tasks/biz-state` | 业务状态监控(LLDP / VRF 关联采集) | `network` |
| `/network/tasks/biz-compare` | 业务状态比对(模板/映射/前后 diff) | `network` |
| `/network/tasks/biz-compare` | 业务状态比对(模板 + 任务 + pre/post 结果) | `network` |
| `/port-traffic/wall/:boardId` | 流量大屏专有页签(无网络侧栏) | `port-traffic-wall` |
| `/topology` | 拓扑管理(模式化编辑器:选择/平移/拖动/连线、框选、自动布局、拖放添加) | `topology` |
| `/webcrt` | WebCRT 终端 | `webcrt` |
@ -131,7 +131,8 @@ src/
- API:`/v1/biz-state/profiles`、`/discover`、`/tasks*`、`/batches*`、`/batches/{id}/export`、`/compare/*`
- **ParseProfile**:命令模板 + TextFSM + 回调 + schema;LLDP 与拓扑 **共享解析**(`lldp_shared`),业务流程写批次表,拓扑写 Fabric
- Phase1:LLDP 邻居快照;建任务默认启用对应厂商 LLDP profile;支持自定义只采不解析行
- Phase2:比对模板、端口映射、CompareJob(manual/auto)、`/network/tasks/biz-compare`
- Phase2:比对模板(可选 metric / key / 接口 / 比对字段)、端口映射、CompareJob 列表与详情、`pre/post` 结果表(高亮 + 筛选)、`/network/tasks/biz-compare`
- API 补充:`GET /v1/biz-state/compare/metrics`(模板字段目录)
- Phase3:VRF 发现→人选关联→带参采集(`*.route_vrf_summary`);`PUT …/items/{id}/bindings`
- 调度:`NETX_BIZ_STATE_SCHEDULER_ENABLED`(默认开),tick `NETX_BIZ_STATE_SCHEDULER_TICK_SEC`
- 前端:`/network/tasks/biz-state`(勾选监控项 / 发现 VRF / 批次 / 导出 zip)

View file

@ -229,14 +229,36 @@ const en = {
},
bizCompare: {
title: "Business compare",
templates: "Compare templates",
newTemplate: "New template",
editTemplate: "Edit template",
saveTemplate: "Save template",
templateSaved: "Template saved",
templateDeleted: "Template deleted",
confirmDeleteTemplate: "Delete this compare template?",
emptyTemplates: "No templates yet. Create one or use built-ins.",
templateHint:
"Field roles: Key aligns rows; interface fields use port mapping; compare fields show pre/post; ignore skips diff.",
keyFields: "Key",
ifaceFields: "Interface",
compareFields: "Compare",
ignoreFields: "Ignore",
field: "Field",
note: "Note",
keyRequired: "Select at least one key field",
noMetricFields: "No fields for this metric",
templateFilterPh: "Filter template / metric",
jobFilterPh: "Filter job / template / status",
mapping: "Port mapping",
newMapping: "New mapping…",
mapName: "Mapping name",
saveMapping: "Save mapping",
validateMapping: "Validate",
validateNeed: "Select mapping and before/after batches first",
mapHint: "before_if,after_if one pair per line",
mappingSaved: "Mapping saved",
createJob: "Create compare job",
defaultJobName: "Cutover compare",
jobName: "Name",
template: "Template",
mode: "Mode",
@ -251,10 +273,25 @@ const en = {
autoHint: "auto: new after-task batches trigger compare",
createCompare: "Create job",
runNow: "Run now",
saveJob: "Save config",
jobSaved: "Job config saved",
jobList: "Compare jobs",
detail: "Details",
edit: "Edit",
delete: "Delete",
tabConfig: "Config / batches",
tabResult: "Result",
runs: "Run history",
noRuns: "No runs yet — run a compare first",
result: "Result",
pickRun: "Pick a run or click Run now",
pickRun: "Pick a run below or click Run now",
resultEmpty: "No matching diff rows",
resultFilterPh: "Filter key / values…",
kindAll: "All kinds",
kindAdded: "Added only",
kindRemoved: "Removed only",
kindChanged: "Changed only",
kindUnchanged: "Unchanged only",
emptyJobs: "No compare jobs yet",
created: "Compare job created",
ran: "Compare finished",
@ -262,6 +299,7 @@ const en = {
colMode: "Mode",
colStatus: "Status",
colKind: "Kind",
colActions: "Actions",
colKey: "Key",
colChange: "Changes",
},

View file

@ -229,14 +229,35 @@ const zh = {
},
bizCompare: {
title: "业务状态比对",
templates: "比对模板",
newTemplate: "新建模板",
editTemplate: "编辑模板",
saveTemplate: "保存模板",
templateSaved: "模板已保存",
templateDeleted: "模板已删除",
confirmDeleteTemplate: "删除该比对模板?",
emptyTemplates: "暂无模板。可新建或使用系统默认。",
templateHint: "勾选字段角色:Key 用于对齐行;接口字段参与端口映射;比对字段左右对照;忽略字段不参与 diff。",
keyFields: "Key",
ifaceFields: "接口",
compareFields: "比对",
ignoreFields: "忽略",
field: "字段",
note: "备注",
keyRequired: "至少选择一个 Key 字段",
noMetricFields: "该 metric 无字段定义",
templateFilterPh: "筛选模板名 / metric",
jobFilterPh: "筛选任务名 / 模板 / 状态",
mapping: "端口映射",
newMapping: "新建映射…",
mapName: "映射名称",
saveMapping: "保存映射",
validateMapping: "校验映射",
validateNeed: "请先选择映射与前后批次",
mapHint: "before_if,after_if 每行一对",
mappingSaved: "映射已保存",
createJob: "建立比对任务",
defaultJobName: "割接比对",
jobName: "名称",
template: "模板",
mode: "模式",
@ -251,10 +272,25 @@ const zh = {
autoHint: "auto:操作后任务新批次到达会自动跑比对",
createCompare: "创建比对任务",
runNow: "立即比对",
jobList: "比对任务列表",
saveJob: "保存配置",
jobSaved: "任务配置已保存",
jobList: "比对任务",
detail: "详情",
edit: "编辑",
delete: "删除",
tabConfig: "配置 / 批次",
tabResult: "比对结果",
runs: "历史 Run",
noRuns: "尚无比对记录,请先执行比对",
result: "比对结果",
pickRun: "选择 Run 或点「立即比对」",
pickRun: "选择底部 Run 或点「立即比对」",
resultEmpty: "无匹配差异行",
resultFilterPh: "筛选 key / 字段值…",
kindAll: "全部类型",
kindAdded: "仅新增",
kindRemoved: "仅删除",
kindChanged: "仅变更",
kindUnchanged: "仅未变",
emptyJobs: "暂无比对任务",
created: "比对任务已创建",
ran: "比对完成",
@ -262,6 +298,7 @@ const zh = {
colMode: "模式",
colStatus: "状态",
colKind: "类型",
colActions: "操作",
colKey: "Key",
colChange: "变更",
},

View file

@ -9993,6 +9993,49 @@ html.login-page--paused .login-page__flare {
margin-bottom: 4px;
}
/* biz_state compare result workbook */
.bs-cmp-job-body {
min-height: min(64vh, 680px);
}
.bs-cmp-result-table {
flex: 1 1 auto;
min-height: 260px;
max-height: min(46vh, 520px);
}
.bs-cmp-diff-table .bs-cmp-pair-head {
text-align: center;
}
.bs-cmp-diff-table .bs-cmp-pre-head,
.bs-cmp-diff-table .bs-cmp-post-head {
font-size: 11px;
opacity: 0.8;
}
.bs-cmp-row--added {
background: rgba(34, 197, 94, 0.08);
}
.bs-cmp-row--removed {
background: rgba(239, 68, 68, 0.08);
}
.bs-cmp-row--changed {
background: rgba(245, 158, 11, 0.06);
}
.bs-cmp-cell--pre {
background: rgba(239, 68, 68, 0.14);
font-weight: 600;
}
.bs-cmp-cell--post {
background: rgba(34, 197, 94, 0.14);
font-weight: 600;
}
.nm-config-modal__body {
flex: 1 1 auto;
width: 100%;

File diff suppressed because it is too large Load diff

View file

@ -1841,9 +1841,33 @@ export const bizStateDownloadExport = async (batchId: string): Promise<void> =>
export const bizCompareListTemplates = () =>
apiGet<{ items: Record<string, unknown>[] }>("/v1/biz-state/compare/templates");
export const bizCompareListMetrics = () =>
apiGet<{
items: Array<{
metric_id: string;
fields: Array<{
name: string;
display_name: string;
dtype: string;
is_key: boolean;
is_interface: boolean;
role: string;
}>;
}>;
}>("/v1/biz-state/compare/metrics");
export const bizCompareCreateTemplate = (body: Record<string, unknown>) =>
apiPost<Record<string, unknown>>("/v1/biz-state/compare/templates", body);
export const bizCompareUpdateTemplate = (templateId: string, body: Record<string, unknown>) =>
apiPatch<Record<string, unknown>>(
`/v1/biz-state/compare/templates/${encodeURIComponent(templateId)}`,
body,
);
export const bizCompareDeleteTemplate = (templateId: string) =>
apiDelete<{ ok: boolean }>(`/v1/biz-state/compare/templates/${encodeURIComponent(templateId)}`);
export const bizCompareListMappings = () =>
apiGet<{ items: Record<string, unknown>[] }>("/v1/biz-state/compare/mappings");