From 84a147b6f245f48c6fa58fa832719fe0c5aa11f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9F=A5=E5=BE=AE?= Date: Wed, 8 Jul 2026 19:43:04 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=95=B0=E6=8D=AE=E6=B5=81=E5=9B=9B?= =?UTF-8?q?=E6=80=81=E5=88=86=E7=B1=BB(healthy/write=5Fonly/read=5Fonly/or?= =?UTF-8?q?phan)+=E5=83=B5=E5=B0=B8=E8=A1=A8=E6=B8=85=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/mofin_health.py | 17 ++++++++++++++--- static/mofin_health.html | 14 ++++++++++---- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/scripts/mofin_health.py b/scripts/mofin_health.py index 4191f791..3c718e97 100644 --- a/scripts/mofin_health.py +++ b/scripts/mofin_health.py @@ -394,7 +394,17 @@ def build_report(): has_output = len(readers) > 0 # 排除系统表 is_system = tname.startswith("sqlite_") or tname.startswith("_") - orphan = (not has_input or not has_output) and not is_system and cnt > 0 + if is_system: + continue + # 数据流状态:healthy / write_only / read_only / orphan + if has_input and has_output: + flow_status = "healthy" + elif has_input and not has_output: + flow_status = "write_only" + elif not has_input and has_output: + flow_status = "read_only" + else: + flow_status = "orphan" entities.append({ "name": tname, "desc": TABLES_DESC.get(tname, ""), @@ -403,8 +413,9 @@ def build_report(): "writers": writers[:10], "has_input": has_input, "has_output": has_output, - "orphan": orphan, - "warn": orphan or (cnt == 0 and tname not in ("capital_flow_cache","")), + "orphan": flow_status in ("orphan", "read_only", "write_only"), + "flow_status": flow_status, + "warn": flow_status != "healthy", }) # JSON文件 diff --git a/static/mofin_health.html b/static/mofin_health.html index 66774d2f..945cf982 100644 --- a/static/mofin_health.html +++ b/static/mofin_health.html @@ -236,7 +236,10 @@ function loadData() { `生成: ${d.generated_at}` + `功能: ✅${cnt.ok} ⚠️${cnt.warn} ❌${cnt.fail}` + `Cron: ✅${pipeOk} ❌${pipeErr} 共${d.pipelines.length}` + - `数据表: ${d.entities.length} | 孤立: ${d.entities.filter(e=>e.orphan).length}`; + `数据表: ${d.entities.length} | ` + + `孤立${d.entities.filter(e=>e.flow_status==='orphan').length} ` + + `写无读${d.entities.filter(e=>e.flow_status==='write_only').length} ` + + `读无写${d.entities.filter(e=>e.flow_status==='read_only').length}`; // Tab 0: 功能树 document.getElementById('panel0').innerHTML = renderFeatureTree(d.feature_tree); @@ -245,14 +248,17 @@ function loadData() { document.getElementById('panel1').innerHTML = renderPipelineTable(d.pipelines); // Tab 2: 数据实体 - let h2 = ''; + let h2 = '
表名作用行数写入方读取方状态
'; d.entities.forEach(e => { + const flowMap = {healthy:'✅ 正常', write_only:'✏️ 写无读', read_only:'📖 读无写', orphan:'🔴 孤立'}; + const flowColors = {healthy:'#3fb950', write_only:'#d29922', read_only:'#58a6ff', orphan:'#f85149'}; + const badge = flowMap[e.flow_status] || '?'; + const color = flowColors[e.flow_status] || '#8b949e'; const cls = e.orphan ? 'orphan' : ''; - const badge = e.orphan ? '🔴 孤立' : (!e.has_input||!e.has_output) ? '⚠️ 单向' : '✅'; h2 += ``; h2 += ``; h2 += ``; - h2 += ``; + h2 += ``; }); (d.json_files||[]).forEach(j => { h2 += ``;
表名作用行数写入方读取方数据流
${e.name}${e.desc||''}${e.rows}${(e.writers||[]).slice(0,4).join(', ')||''}${(e.readers||[]).slice(0,4).join(', ')||''}${badge}
${badge}
📄 ${j.name}${j.desc||'JSON文件'}${j.size_kb}KB