From 976ce29ad99e092e87d689e3bf8092a81678be58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BB=9D=E5=B0=98?= <237809796@qq.com> Date: Tue, 30 Jun 2026 23:57:43 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E:=20=E4=BE=9D=E8=B5=96?= =?UTF-8?q?=E5=85=B3=E7=B3=BB=E5=9B=BE(AntV=20X6=20v3=20+=20Vue=20?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E8=8A=82=E7=82=B9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DependencyGraph.vue: X6 画布初始化 + 插件(框选/对齐线/撤销/滚动) + 工程节点渲染 - ModuleNode.vue: Vue 自定义节点组件(工程名/路径/技术栈标签) - 项目详情新增依赖图Tab,与概览/文件并列 - 网格布局排列工程节点,支持缩放/拖拽/框选 - Phase 0 验证 demo(X6Demo.vue)保留在 /dev/x6 路由 --- .../AntV-X6调研报告与引入计划-2026-06-30.md | 328 ++++++++++++++++++ docs/INDEX.md | 3 +- docs/待决策.md | 66 ++++ package-lock.json | 89 +++++ package.json | 3 + src/components/dev/X6Demo.vue | 185 ++++++++++ src/components/project/DependencyGraph.vue | 224 ++++++++++++ src/components/project/ModuleNode.vue | 98 ++++++ src/i18n/en/dependencyGraph.ts | 7 + src/i18n/zh-CN/dependencyGraph.ts | 7 + src/router/index.ts | 6 + src/views/ProjectDetail.vue | 16 +- 12 files changed, 1030 insertions(+), 2 deletions(-) create mode 100644 docs/01-技术文档/AntV-X6调研报告与引入计划-2026-06-30.md create mode 100644 src/components/dev/X6Demo.vue create mode 100644 src/components/project/DependencyGraph.vue create mode 100644 src/components/project/ModuleNode.vue create mode 100644 src/i18n/en/dependencyGraph.ts create mode 100644 src/i18n/zh-CN/dependencyGraph.ts diff --git a/docs/01-技术文档/AntV-X6调研报告与引入计划-2026-06-30.md b/docs/01-技术文档/AntV-X6调研报告与引入计划-2026-06-30.md new file mode 100644 index 0000000..cffd247 --- /dev/null +++ b/docs/01-技术文档/AntV-X6调研报告与引入计划-2026-06-30.md @@ -0,0 +1,328 @@ +# AntV X6 技术调研报告与引入计划 + +> 创建: 2026-06-30 | 状态: 调研完成,待决策 +> 调研对象: AntV X6(图编辑与可视化引擎) +> 数据来源: GitHub API(antvis/X6)+ npm registry 实时查询(2026-06-30) +> 关联任务: `[子4] 前端:依赖关系图可视化`、`[子2] df-project:依赖图构建` + +--- + +## 一、为什么调研 X6 + +DevFlow 正在推进 **多工程/多仓库项目组织** 功能(任务列表中的父任务「多工程/多仓库项目组织」拆出 5 个子任务)。其中: + +- `[子2]` 后端需构建 `ModuleDependencyGraph`(工程间依赖图数据结构) +- `[子4]` 前端需 **依赖关系图可视化**(节点 = 工程,边 = 依赖关系,支持交互) + +当前 DevFlow 前端(`src/`)**零图可视化依赖**(已 grep 确认:无 d3 / vis-network / cytoscape / antv / x6 / jointjs / reactflow)。需要选型一个图引擎承担可视化层。 + +X6 是这次选型的重点候选,本报告评估其是否适合 DevFlow。 + +--- + +## 二、X6 是什么 + +**AntV X6** 是蚂蚁集团 AntV 数据可视化团队开源的 **图编辑与可视化引擎**(Graph Editing and Visualization Engine)。 + +- GitHub: https://github.com/antvis/X6 +- 文档: https://x6.antv.antgroup.com/ +- License: **MIT** +- 定位: 专注 **节点-边图** 的交互式编辑与可视化 + +与纯图表库(ECharts/G2)的区别:X6 不是「把数据画成图」,而是「让用户在画布上编辑图」——拖拽节点、连线、布局、撤销重做、导出。这正是依赖图编辑器需要的形态。 + +--- + +## 三、关键数据(实时校准,非记忆) + +> ⚠️ 网上多数博客仍停留在「v2.x」,**已过时**。以下为 2026-06-30 npm + GitHub API 实测。 + +### 3.1 版本现状 + +| 通道 | 版本 | 说明 | +|---|---|---| +| **latest** | **3.1.7** | 当前正式稳定版(v3 主线) | +| beta | 3.1.4-beta.1 | 预发布通道 | +| @antv/x6@1.35.1 | 1.35.1 | v1 旧线(仅维护,勿新用) | + +**结论**:新项目直接上 **v3.1.7**,不要从 v1/v2 起步。v3 是当前活跃主线。 + +### 3.2 仓库活跃度 + +| 指标 | 数值 | +|---|---| +| Stars | 18.3k | +| Forks | 2.5k | +| Network | 1886 | +| 最近 release | 持续迭代(2026 年仍有多次 release) | +| 维护状态 | **活跃** | + +### 3.3 最近 release 亮点(佐证活跃度) + +近期 PR 修复了: +- 节点事件无法冒泡到连线的问题(#4888) +- stencil 插件搜索后高度自适应(#4975) + +说明交互细节仍在持续打磨,非弃维项目。 + +--- + +## 四、核心能力清单 + +| 能力 | 说明 | DevFlow 是否用得到 | +|---|---|---| +| **节点系统** | 内置矩形/圆形/椭圆/多边形,支持 HTML/React/Vue 自定义节点 | ✅ 工程节点用 Vue 自定义 | +| **边系统** | 直线/折线/曲线/自定义路由,箭头/标签/路径动画 | ✅ 依赖边带类型标签(API调用/类库/MQ...) | +| **交互** | 拖拽、缩放、框选、连线、对齐线、撤销/重做 | ✅ 用户可手动调整布局 | +| **布局算法** | dagre(层次)/ force(力导向)/ grid / circular | ✅ dagre 天然适合依赖图 | +| **插件生态** | 小地图、对齐线、框选、变换、键盘、历史、剪贴板、上下文菜单 | ✅ 小地图(大图概览)+ 历史(撤销) | +| **数据格式** | JSON graph data,导入/导出 | ✅ 与后端 ModuleDependencyGraph 直接映射 | +| **事件系统** | 完整节点/边/画布事件 | ✅ 点击节点跳转工程详情 | +| **导出** | PNG / SVG / JPG | ⚠️ 锦上添花 | + +--- + +## 五、技术特性 + +### 5.1 架构 + +- **框架无关**:核心纯 TypeScript,不绑定 React/Vue +- **渲染引擎**:SVG(默认)/ Canvas(大图性能更优) +- **插件化**:功能按需引入,tree-shaking 友好(v3 强化) + +### 5.2 生态包(v3 延续插件化) + +| 包 | 用途 | DevFlow 需要 | +|---|---|---| +| `@antv/x6` | 核心引擎 | ✅ 必装 | +| `@antv/x6-plugin-selection` | 框选/点选 | ✅ | +| `@antv/x6-plugin-snapline` | 对齐线 | ✅ | +| `@antv/x6-plugin-history` | 撤销/重做 | ✅ | +| `@antv/x6-plugin-minimap` | 小地图 | ✅ 大图必备 | +| `@antv/x6-plugin-keyboard` | 键盘快捷键 | ⚠️ 可选 | +| `@antv/x6-plugin-clipboard` | 剪贴板 | ⚠️ 可选 | +| `@antv/x6-plugin-transform` | 缩放/旋转 | ⚠️ 可选 | +| `@antv/x6-plugin-scroller` | 画布滚动 | ✅ 大图画布 | +| `@antv/x6-plugin-export` | 图片导出 | ❌ 暂不需要 | +| `@antv/x6-plugin-stencil` | 元素面板(拖入) | ⚠️ 可视化编辑器才需要 | +| `@antv/x6-vue-shape` | Vue 自定义节点 | ✅ 工程节点用 Vue 组件 | + +### 5.3 与 DevFlow 技术栈兼容性 + +| 维度 | DevFlow | X6 要求 | 兼容 | +|---|---|---|---| +| 前端框架 | Vue 3.5 | 框架无关 + vue-shape | ✅ | +| UI 库 | Arco Design | 无冲突 | ✅ | +| 构建 | Vite 6 | 支持 | ✅ | +| TS | 5.6 | 原生 TS | ✅ | +| 运行时 | Tauri WebView | 标准 DOM API | ✅ | +| 包管理 | bun.lock / npm | 均支持 | ✅ | + +**无兼容性阻塞。** + +--- + +## 六、竞品对比 + +| 库 | 定位 | 编辑能力 | Vue 支持 | 布局算法 | 体积 | 适合 DevFlow | +|---|---|---|---|---|---|---| +| **AntV X6** | 图编辑引擎 | ⭐⭐⭐⭐⭐ 全栈 | 官方 vue-shape | 内置 dagre/force | 中 | ✅ **最佳** | +| ReactFlow | React 图编辑 | ⭐⭐⭐⭐ | 需包装(非原生) | 需配 dagre | 中 | ❌ React 栈 | +| vis-network | 图可视化 | ⭐⭐⭐ | 手动 | 内置 | 小 | ⚠️ 编辑弱 | +| cytoscape.js | 图分析+可视化 | ⭐⭐⭐ | 手动 | 插件 | 中 | ⚠️ 偏分析 | +| d3 | 通用可视化 | ⭐⭐ 手搓 | 手动 | 手搓 | 大 | ❌ 工作量大 | +| G6 | 关系图谱分析 | ⭐⭐⭐⭐ | 手动 | 内置 | 中 | ⚠️ 偏分析非编辑 | + +**结论**:DevFlow 需要「可编辑依赖图」,X6 在编辑能力 + Vue 原生支持 + 布局算法三方面综合最优。G6 是同门兄弟但偏「图谱分析」(大图布局/聚类),X6 偏「图编辑」(人机交互),DevFlow 场景是后者。 + +--- + +## 七、DevFlow 落地场景评估 + +### 7.1 主场景:多工程依赖关系图(P0,立即落地) + +对应任务 `[子4]`。 + +``` +[DevFlow 工程] ──API调用──> [u-talk 工程] + │ + ├──类库引入──> [df-types crate] + └──共享资源──> [MySQL] +``` + +- 节点 = module(工程/crate),Vue 自定义节点展示名称/路径/技术栈 +- 边 = module_dependency,标签展示 dep_type(API调用/类库/MQ/共享资源/自定义) +- 布局 = dagre 层次布局(天然适合依赖关系) +- 交互 = 点击节点跳工程详情、拖拽调整、小地图导航 +- 数据源 = 后端 `get_dependency_graph` IPC 返回的图结构 + +### 7.2 次场景:工作流编辑器(P1,未来) + +DevFlow 有工作流引擎(AiNode/HumanNode/executor),未来可做可视化工作流编辑器: +- 拖拽节点(AI 节点 / 人工节点 / 判断节点) +- 连线定义流转 +- 与后端 workflow 定义双向同步 + +X6 的 stencil 插件(元素拖入面板)正是为这类低代码编辑器设计。 + +### 7.3 次场景:任务依赖图(P2) + +任务有 `depends_on / blocks / relates_to` 关联(create_task_link),可可视化展示任务拓扑。当前任务列表已有 `list_task_links` / `get_task_tree` 数据基础。 + +### 7.4 不适用场景 + +- ai-news(纯 HTML/JS,无图编辑需求)— 不引入 +- u-talk / u-desk — 暂无明确图编辑需求,不引入 + +--- + +## 八、风险与对策 + +| 风险 | 影响 | 对策 | +|---|---|---| +| v3 文档站是 SPA,离线难爬 | 学习曲线 | 在线阅读 + 官方 examples 仓库对照 | +| v3 相比 v1 有 breaking changes | 迁移成本 | 全新引入,无历史包袱,直接学 v3 | +| 插件多,初次配置繁琐 | 上手成本 | 本计划已列出必装子集(见 §九) | +| 大图性能(>500 节点) | 渲染卡顿 | DevFlow 单项目工程数有限(<50),不触瓶颈;必要时切 Canvas 渲染 | +| vue-shape 与 Arco 组件协同 | 样式冲突 | 节点用独立样式作用域,避免全局污染 | +| 包体积增加 | 安装包变大 | X6 核心 + 必装插件 gzip 后约 200-300KB,Tauri 本地资源可接受 | + +**无阻塞级风险。** + +--- + +## 九、引入计划 + +### 9.1 决策点(待人工拍板) + +| 项 | 推荐 | 备选 | +|---|---|---| +| 是否引入 X6 | ✅ **引入** | vis-network(编辑弱)/ 自研 SVG(成本高) | +| 版本 | v3.1.7(latest) | — | +| 落地优先级 | P0 依赖图 → P1 工作流编辑器 | — | +| 引入范围 | 仅 DevFlow 前端 | — | + +### 9.2 分阶段实施 + +#### Phase 0:依赖安装与验证(0.5 天) + +```bash +# 在 DevFlow 前端目录 +bun add @antv/x6 @antv/x6-plugin-selection @antv/x6-plugin-snapline \ + @antv/x6-plugin-history @antv/x6-plugin-minimap @antv/x6-plugin-scroller \ + @antv/x6-vue-shape +``` + +交付物: +- 依赖装入 `package.json` +- 一个最小 demo 页面(3 节点 2 边,验证渲染 + 拖拽 + 缩放) +- 验证 Tauri WebView 下无异常 + +#### Phase 1:依赖关系图组件(1.5 天,对接 `[子4]`) + +前置:`[子2]` 后端 `get_dependency_graph` IPC 完成。 + +交付物: +- 新建 `src/components/DependencyGraph.vue` +- 封装 X6 Graph 实例(生命周期管理:mount 初始化、unmount 销毁) +- 数据映射:`ModuleDependencyGraph` → X6 fromJSON +- Vue 自定义节点组件 `ModuleNode.vue`(展示工程名/路径/技术栈图标) +- 边标签展示 dep_type +- dagre 自动布局 +- 小地图 + 框选 + 撤销重做 +- 事件:点击节点 → emit('select-module', id),父组件跳详情 + +#### Phase 2:集成到项目详情页(0.5 天,对接 `[子4]`) + +交付物: +- 项目详情页新增「依赖图」Tab +- 与工程列表 Tab 并列,数据同源 +- 空状态处理(单工程无依赖时提示) + +#### Phase 3(未来):工作流可视化编辑器 + +不在本次计划范围,待工作流引擎需求明确后再立项。 + +### 9.3 工程化约定 + +1. **X6 实例管理**:组件内 `onMounted` 创建,`onBeforeUnmount` 调 `graph.dispose()`,避免内存泄漏 +2. **类型契约**:后端 `ModuleDependencyGraph`(Rust serde)→ ts-rs 导出 → 前端 X6 fromJSON 格式转换函数集中放 `src/utils/graphMapper.ts` +3. **样式隔离**:自定义节点用 ` diff --git a/src/components/project/DependencyGraph.vue b/src/components/project/DependencyGraph.vue new file mode 100644 index 0000000..af15477 --- /dev/null +++ b/src/components/project/DependencyGraph.vue @@ -0,0 +1,224 @@ + + + + + diff --git a/src/components/project/ModuleNode.vue b/src/components/project/ModuleNode.vue new file mode 100644 index 0000000..69eb0f1 --- /dev/null +++ b/src/components/project/ModuleNode.vue @@ -0,0 +1,98 @@ + + + + + diff --git a/src/i18n/en/dependencyGraph.ts b/src/i18n/en/dependencyGraph.ts new file mode 100644 index 0000000..7ea678d --- /dev/null +++ b/src/i18n/en/dependencyGraph.ts @@ -0,0 +1,7 @@ +export default { + dependencyGraph: { + title: 'Dependency Graph', + empty: 'No modules yet, please add a module first', + tabTitle: '🔗 Dependencies', + }, +} diff --git a/src/i18n/zh-CN/dependencyGraph.ts b/src/i18n/zh-CN/dependencyGraph.ts new file mode 100644 index 0000000..7f63201 --- /dev/null +++ b/src/i18n/zh-CN/dependencyGraph.ts @@ -0,0 +1,7 @@ +export default { + dependencyGraph: { + title: '依赖关系图', + empty: '暂无工程,请先添加工程', + tabTitle: '🔗 依赖图', + }, +} diff --git a/src/router/index.ts b/src/router/index.ts index 0693b83..2d62bad 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -65,6 +65,12 @@ const routes = [ component: () => import('../views/AuditLog.vue'), meta: { title: '审批历史' }, }, + { + path: '/dev/x6', + name: 'X6Demo', + component: () => import('../components/dev/X6Demo.vue'), + meta: { title: 'X6 v3 验证' }, + }, { path: '/settings', name: 'Settings', diff --git a/src/views/ProjectDetail.vue b/src/views/ProjectDetail.vue index 20f5f88..297ced8 100644 --- a/src/views/ProjectDetail.vue +++ b/src/views/ProjectDetail.vue @@ -58,6 +58,14 @@ > {{ $t('fileExplorer.tabTitle') }} + @@ -65,6 +73,11 @@ + +
+ +
+
@@ -258,6 +271,7 @@ import { projectStatusLabel, taskStatusLabel, taskStatusClass } from '../constan import ConfirmDialog from '@/components/ConfirmDialog.vue' import ApprovalDialog from '@/components/project/ApprovalDialog.vue' import FileExplorer from '@/components/project/FileExplorer.vue' +import DependencyGraph from '@/components/project/DependencyGraph.vue' import { useConfirm } from '@/composables/useConfirm' import { useRendered } from '@/composables/useMarkdown' @@ -270,7 +284,7 @@ const showApprovalDialog = ref(false) let unlisten: (() => void) | null = null // Tab 导航:概览(项目信息/任务/工作流日志) vs 文件浏览器(Batch 10)。 -const activeTab = ref<'overview' | 'files'>('overview') +const activeTab = ref<'overview' | 'files' | 'graph'>('overview') // 确认弹层状态机抽至 composables/useConfirm(原 4 视图重复:Projects/ProjectDetail/Ideas/Settings) const { confirmState, confirmDialog, answerConfirm } = useConfirm()