Revert "补充插件依赖拓扑与缺失依赖风险视图"

This reverts commit 369b74e834.
This commit is contained in:
Liu
2026-05-01 12:45:37 +08:00
parent 722bd4e134
commit f183283789
3 changed files with 0 additions and 266 deletions

View File

@@ -120,70 +120,6 @@
</el-col>
</el-row>
<el-row :gutter="16" class="insight-grid">
<el-col :xs="24" :md="12">
<el-card class="workspace-card" shadow="hover">
<div slot="header" class="workspace-header">
<div>
<h3>依赖核心插件</h3>
<p>优先保护被多个插件依赖的基础能力节点,避免单点异常扩散。</p>
</div>
</div>
<div class="rank-list">
<div v-if="topDependencyCorePlugins.length === 0" class="mobile-empty-state">暂无依赖关系数据</div>
<div v-for="(plugin, index) in topDependencyCorePlugins" :key="`core-${plugin.module_name}`" class="rank-item">
<div class="rank-item__index">{% raw %}{{ index + 1 }}{% endraw %}</div>
<div class="rank-item__content">
<div class="rank-item__title-row">
<div class="rank-item__title">{% raw %}{{ plugin.name }}{% endraw %}</div>
<el-tag :type="governanceTagType(plugin.governance_status)" size="mini">
{% raw %}{{ `${(plugin.dependency_summary || {}).dependent_count || 0} 个上游` }}{% endraw %}
</el-tag>
</div>
<div class="rank-item__summary">
{% raw %}{{ buildDependencyCoreSummary(plugin) }}{% endraw %}
</div>
<div class="rank-item__meta">
<span>执行:{% raw %}{{ executionLabel((plugin.execution_summary || {}).status) }}{% endraw %}</span>
<span>治理:{% raw %}{{ governanceLabel(plugin.governance_status) }}{% endraw %}</span>
</div>
</div>
</div>
</div>
</el-card>
</el-col>
<el-col :xs="24" :md="12">
<el-card class="workspace-card" shadow="hover">
<div slot="header" class="workspace-header">
<div>
<h3>缺失依赖风险</h3>
<p>快速查看声明了依赖但当前目标未加载的插件,优先处理运行链断裂问题。</p>
</div>
</div>
<div class="rank-list">
<div v-if="pluginsWithMissingDependencies.length === 0" class="mobile-empty-state">当前没有缺失依赖风险</div>
<div v-for="(plugin, index) in pluginsWithMissingDependencies" :key="`missing-${plugin.module_name}`" class="rank-item">
<div class="rank-item__index">{% raw %}{{ index + 1 }}{% endraw %}</div>
<div class="rank-item__content">
<div class="rank-item__title-row">
<div class="rank-item__title">{% raw %}{{ plugin.name }}{% endraw %}</div>
<el-tag type="warning" size="mini">
{% raw %}{{ `${(plugin.dependency_summary || {}).missing_count || 0} 个缺失` }}{% endraw %}
</el-tag>
</div>
<div class="rank-item__summary">
{% raw %}{{ buildMissingDependencySummary(plugin) }}{% endraw %}
</div>
<div class="rank-item__meta">
<span>模块:{% raw %}{{ plugin.module_name }}{% endraw %}</span>
</div>
</div>
</div>
</div>
</el-card>
</el-col>
</el-row>
<el-card class="workspace-card" shadow="hover">
<div slot="header" class="workspace-header">
<div>
@@ -322,9 +258,6 @@
<span>{% raw %}{{ governanceIssueSummary(plugin) }}{% endraw %}</span>
<span>{% raw %}{{ plugin.feature_key ? `Feature: ${plugin.feature_key}` : '未接入群级权限' }}{% endraw %}</span>
</div>
<div class="mobile-plugin-card__meta">
<span>依赖:{% raw %}{{ buildDependencySummaryText(plugin) }}{% endraw %}</span>
</div>
<div class="mobile-plugin-card__actions">
<el-button
size="mini"
@@ -389,55 +322,6 @@
</div>
<span v-else></span>
</el-descriptions-item>
<el-descriptions-item label="依赖关系" :span="2" v-if="selectedPlugin.dependency_summary">
<div class="config-overview-grid">
<div class="config-overview-item">
<span class="config-overview-label">声明依赖</span>
<span class="config-overview-value">{% raw %}{{ selectedPlugin.dependency_summary.declared_count || 0 }}{% endraw %}</span>
</div>
<div class="config-overview-item">
<span class="config-overview-label">已解析依赖</span>
<span class="config-overview-value">{% raw %}{{ selectedPlugin.dependency_summary.resolved_count || 0 }}{% endraw %}</span>
</div>
<div class="config-overview-item">
<span class="config-overview-label">缺失依赖</span>
<span class="config-overview-value">{% raw %}{{ selectedPlugin.dependency_summary.missing_count || 0 }}{% endraw %}</span>
</div>
<div class="config-overview-item">
<span class="config-overview-label">下游依赖</span>
<span class="config-overview-value">{% raw %}{{ selectedPlugin.dependency_summary.dependent_count || 0 }}{% endraw %}</span>
</div>
</div>
<div class="dependency-panels">
<div class="dependency-panel">
<div class="dependency-panel__title">已解析依赖</div>
<div v-if="selectedPlugin.resolved_dependencies && selectedPlugin.resolved_dependencies.length > 0" class="command-tags">
<el-tag v-for="dependency in selectedPlugin.resolved_dependencies" :key="`resolved-${dependency.module_name}`" size="mini" effect="plain">
{% raw %}{{ `${dependency.name} (${dependency.status_label || dependency.status || '未知'})` }}{% endraw %}
</el-tag>
</div>
<div v-else class="entity-subtitle"></div>
</div>
<div class="dependency-panel">
<div class="dependency-panel__title">缺失依赖</div>
<div v-if="selectedPlugin.missing_dependencies && selectedPlugin.missing_dependencies.length > 0" class="command-tags">
<el-tag v-for="dependency in selectedPlugin.missing_dependencies" :key="`missing-${dependency.name}`" size="mini" type="warning">
{% raw %}{{ dependency.name }}{% endraw %}
</el-tag>
</div>
<div v-else class="entity-subtitle"></div>
</div>
<div class="dependency-panel">
<div class="dependency-panel__title">下游依赖插件</div>
<div v-if="selectedPlugin.dependent_plugins && selectedPlugin.dependent_plugins.length > 0" class="command-tags">
<el-tag v-for="dependency in selectedPlugin.dependent_plugins" :key="`dependent-${dependency.module_name}`" size="mini" type="success" effect="plain">
{% raw %}{{ `${dependency.name} (${dependency.status_label || dependency.status || '未知'})` }}{% endraw %}
</el-tag>
</div>
<div v-else class="entity-subtitle"></div>
</div>
</div>
</el-descriptions-item>
<el-descriptions-item label="命令列表" :span="2" v-if="selectedPlugin.commands && selectedPlugin.commands.length > 0">
<div class="command-tags">
<el-tag v-for="cmd in selectedPlugin.commands" :key="cmd" size="mini" class="command-tag">
@@ -777,29 +661,6 @@
})
.slice(0, 5);
},
topDependencyCorePlugins() {
// 核心依赖插件优先按“被多少插件依赖”排序,
// 这样最容易形成单点影响的基础插件会排在前面。
return (this.plugins || [])
.filter(plugin => Number(((plugin.dependency_summary || {}).dependent_count) || 0) > 0)
.slice()
.sort((left, right) => {
return (
Number(((right.dependency_summary || {}).dependent_count) || 0) - Number(((left.dependency_summary || {}).dependent_count) || 0)
|| Number(((right.dependency_summary || {}).declared_count) || 0) - Number(((left.dependency_summary || {}).declared_count) || 0)
);
})
.slice(0, 5);
},
pluginsWithMissingDependencies() {
return (this.plugins || [])
.filter(plugin => Number(((plugin.dependency_summary || {}).missing_count) || 0) > 0)
.slice()
.sort((left, right) => {
return Number(((right.dependency_summary || {}).missing_count) || 0) - Number(((left.dependency_summary || {}).missing_count) || 0);
})
.slice(0, 5);
},
slowestPlugins() {
// 慢插件排行只看有执行样本的插件,避免未执行插件把榜单冲掉。
return (this.plugins || [])
@@ -913,33 +774,6 @@
if (!Number.isFinite(normalizedValue) || normalizedValue <= 0) return '-';
return `${normalizedValue.toFixed(2)} ms`;
},
buildDependencySummaryText(plugin) {
const dependencySummary = (plugin && plugin.dependency_summary) || {};
const declaredCount = Number(dependencySummary.declared_count || 0);
const missingCount = Number(dependencySummary.missing_count || 0);
const dependentCount = Number(dependencySummary.dependent_count || 0);
if (declaredCount <= 0 && dependentCount <= 0) {
return '无依赖关系';
}
if (missingCount > 0) {
return `声明 ${declaredCount} 个,缺失 ${missingCount}`;
}
if (dependentCount > 0) {
return `${dependentCount} 个插件依赖`;
}
return `已解析 ${declaredCount} 个依赖`;
},
buildDependencyCoreSummary(plugin) {
const dependencySummary = (plugin && plugin.dependency_summary) || {};
return `当前被 ${(dependencySummary.dependent_count || 0)} 个插件依赖,自身声明 ${(dependencySummary.declared_count || 0)} 个依赖。`;
},
buildMissingDependencySummary(plugin) {
const missingDependencies = ((plugin && plugin.missing_dependencies) || []).map(item => item.name).filter(Boolean);
if (!missingDependencies.length) {
return '当前没有缺失依赖。';
}
return `缺失依赖:${missingDependencies.join('、')}`;
},
loadPlugins() {
this.loading = true;
axios.get('/api/plugins')
@@ -1359,24 +1193,6 @@
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 10px;
}
.dependency-panels {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 12px;
margin-top: 12px;
}
.dependency-panel {
padding: 12px;
border-radius: 14px;
background: rgba(248,250,252,0.82);
border: 1px solid rgba(148,163,184,0.12);
}
.dependency-panel__title {
font-size: 13px;
font-weight: 700;
color: #334155;
margin-bottom: 8px;
}
.config-overview-item {
display: flex;
flex-direction: column;

View File

@@ -801,85 +801,6 @@ class PluginManager:
"execution_summary": execution_summary,
}
@staticmethod
def _normalize_snapshot_dependency_key(value: Any) -> str:
"""把依赖引用统一规整成可匹配的 key。"""
return str(value or "").strip().lower()
def _enrich_dependency_relationships(self, snapshots: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
"""为插件快照补齐依赖关系摘要。
设计目标:
1. 后台既要看“我依赖谁”,也要看“谁依赖我”;
2. 依赖声明有可能写插件名,也可能写模块名,因此这里做双 key 兼容;
3. 缺失依赖需要单独产出,便于页面上做风险聚合与高亮。
"""
normalized_snapshots = [dict(item or {}) for item in (snapshots or [])]
lookup_by_key: Dict[str, Dict[str, Any]] = {}
for snapshot in normalized_snapshots:
module_name = str(snapshot.get("module_name") or "").strip()
display_name = str(snapshot.get("name") or "").strip()
if module_name:
lookup_by_key[self._normalize_snapshot_dependency_key(module_name)] = snapshot
if display_name:
lookup_by_key[self._normalize_snapshot_dependency_key(display_name)] = snapshot
for snapshot in normalized_snapshots:
snapshot["resolved_dependencies"] = []
snapshot["missing_dependencies"] = []
snapshot["dependent_plugins"] = []
for snapshot in normalized_snapshots:
dependencies = list(snapshot.get("dependencies", []) or [])
resolved_dependencies = []
missing_dependencies = []
for dependency_name in dependencies:
normalized_key = self._normalize_snapshot_dependency_key(dependency_name)
target_snapshot = lookup_by_key.get(normalized_key)
if target_snapshot:
dependency_row = {
"name": str(target_snapshot.get("name") or "").strip(),
"module_name": str(target_snapshot.get("module_name") or "").strip(),
"status": str(target_snapshot.get("status") or "").strip(),
"status_label": str(target_snapshot.get("status_label") or "").strip(),
"governance_status": str(target_snapshot.get("governance_status") or "").strip(),
}
resolved_dependencies.append(dependency_row)
target_snapshot.setdefault("dependent_plugins", []).append(
{
"name": str(snapshot.get("name") or "").strip(),
"module_name": str(snapshot.get("module_name") or "").strip(),
"status": str(snapshot.get("status") or "").strip(),
"status_label": str(snapshot.get("status_label") or "").strip(),
"governance_status": str(snapshot.get("governance_status") or "").strip(),
}
)
else:
missing_dependencies.append(
{
"name": str(dependency_name or "").strip(),
}
)
snapshot["resolved_dependencies"] = resolved_dependencies
snapshot["missing_dependencies"] = missing_dependencies
snapshot["dependency_summary"] = {
"declared_count": len(dependencies),
"resolved_count": len(resolved_dependencies),
"missing_count": len(missing_dependencies),
"dependent_count": len(snapshot.get("dependent_plugins", []) or []),
"has_missing": len(missing_dependencies) > 0,
}
for snapshot in normalized_snapshots:
dependent_plugins = list(snapshot.get("dependent_plugins", []) or [])
dependent_plugins.sort(key=lambda item: (str(item.get("name") or ""), str(item.get("module_name") or "")))
snapshot["dependent_plugins"] = dependent_plugins
return normalized_snapshots
@staticmethod
def _status_to_label(status: str) -> str:
"""把运行态状态码转换成中文展示文案。"""
@@ -912,8 +833,6 @@ class PluginManager:
for module_name in sorted(discovered_module_names - loaded_module_names):
snapshots.append(self._build_unloaded_plugin_snapshot(module_name))
snapshots = self._enrich_dependency_relationships(snapshots)
snapshots.sort(
key=lambda item: (
0 if item.get("status") == "RUNNING" else 1,

View File

@@ -406,7 +406,6 @@
- 第一阶段已完成后台插件管理页已补充治理健康、能力类型、Feature Key、依赖与配置概览信息
- 第一阶段已完成:插件配置保存前已增加格式校验,避免坏配置直接写回线上文件
- 第二阶段已完成:插件管理页已补充执行表现摘要、最近错误信息与高风险/慢插件排行,便于快速定位运行异常插件
- 第二阶段已完成:插件快照已补充依赖拓扑摘要,后台可直接查看核心依赖插件、缺失依赖风险与上下游关系
- 后续可继续补充插件错误历史、性能排名、依赖图与熔断/隔离控制
建议内容: