From 18072d75a46a5ce5681768a7efce410a74f4996e Mon Sep 17 00:00:00 2001 From: ygx Date: Sat, 14 Mar 2026 18:55:23 +0800 Subject: [PATCH] feat --- package.json | 4 + pnpm-lock.yaml | 249 +++++- src/api/ops/netarchTopo.ts | 174 +++++ src/layout/default-layout.vue | 63 +- src/locale/en-US.ts | 5 + src/locale/zh-CN.ts | 5 + src/router/menu-data.ts | 33 +- src/router/routes/modules/ops.ts | 32 + src/router/typings.d.ts | 2 + src/store/modules/app/index.ts | 16 +- .../components/SubGroupFormDialog.vue | 155 ++++ .../components/TopologyFormDialog.vue | 125 +++ .../components/TopologyListDialog.vue | 338 ++++++++ .../netarch/topo-group/config/columns.ts | 88 +++ .../netarch/topo-group/config/filters.ts | 26 + .../netarch/topo-group/config/options.ts | 9 + .../ops/pages/netarch/topo-group/index.vue | 493 ++++++++++++ .../netarch/topo/components/AddNodeMenu.vue | 70 ++ .../netarch/topo/components/CustomNode.vue | 154 ++++ .../topo/components/DeleteConfirmDialog.vue | 40 + .../topo/components/EdgeActionDialog.vue | 53 ++ .../topo/components/EdgeEditDialog.vue | 87 +++ .../netarch/topo/components/EdgeStyleMenu.vue | 116 +++ .../netarch/topo/components/GroupPanel.vue | 257 ++++++ .../netarch/topo/components/GroupTreeItem.vue | 196 +++++ .../netarch/topo/components/LayoutMenu.vue | 50 ++ .../topo/components/NodeActionDialog.vue | 203 +++++ .../topo/components/NodeDetailDialog.vue | 193 +++++ .../topo/components/NodeEditDialog.vue | 151 ++++ .../pages/netarch/topo/components/Toolbar.vue | 147 ++++ .../pages/netarch/topo/components/index.ts | 12 + src/views/ops/pages/netarch/topo/config.ts | 17 + .../ops/pages/netarch/topo/hooks/index.ts | 3 + .../pages/netarch/topo/hooks/useEdgeStyles.ts | 46 ++ .../pages/netarch/topo/hooks/useTopoLayout.ts | 83 ++ .../netarch/topo/hooks/useTopoStorage.ts | 61 ++ src/views/ops/pages/netarch/topo/index.vue | 738 ++++++++++++++++++ .../netarch/topo/services/topoService.ts | 205 +++++ src/views/ops/pages/netarch/topo/types.ts | 40 + .../netarch/topo/utils/buildGroupTree.ts | 194 +++++ 40 files changed, 4886 insertions(+), 47 deletions(-) create mode 100644 src/api/ops/netarchTopo.ts create mode 100644 src/views/ops/pages/netarch/topo-group/components/SubGroupFormDialog.vue create mode 100644 src/views/ops/pages/netarch/topo-group/components/TopologyFormDialog.vue create mode 100644 src/views/ops/pages/netarch/topo-group/components/TopologyListDialog.vue create mode 100644 src/views/ops/pages/netarch/topo-group/config/columns.ts create mode 100644 src/views/ops/pages/netarch/topo-group/config/filters.ts create mode 100644 src/views/ops/pages/netarch/topo-group/config/options.ts create mode 100644 src/views/ops/pages/netarch/topo-group/index.vue create mode 100644 src/views/ops/pages/netarch/topo/components/AddNodeMenu.vue create mode 100644 src/views/ops/pages/netarch/topo/components/CustomNode.vue create mode 100644 src/views/ops/pages/netarch/topo/components/DeleteConfirmDialog.vue create mode 100644 src/views/ops/pages/netarch/topo/components/EdgeActionDialog.vue create mode 100644 src/views/ops/pages/netarch/topo/components/EdgeEditDialog.vue create mode 100644 src/views/ops/pages/netarch/topo/components/EdgeStyleMenu.vue create mode 100644 src/views/ops/pages/netarch/topo/components/GroupPanel.vue create mode 100644 src/views/ops/pages/netarch/topo/components/GroupTreeItem.vue create mode 100644 src/views/ops/pages/netarch/topo/components/LayoutMenu.vue create mode 100644 src/views/ops/pages/netarch/topo/components/NodeActionDialog.vue create mode 100644 src/views/ops/pages/netarch/topo/components/NodeDetailDialog.vue create mode 100644 src/views/ops/pages/netarch/topo/components/NodeEditDialog.vue create mode 100644 src/views/ops/pages/netarch/topo/components/Toolbar.vue create mode 100644 src/views/ops/pages/netarch/topo/components/index.ts create mode 100644 src/views/ops/pages/netarch/topo/config.ts create mode 100644 src/views/ops/pages/netarch/topo/hooks/index.ts create mode 100644 src/views/ops/pages/netarch/topo/hooks/useEdgeStyles.ts create mode 100644 src/views/ops/pages/netarch/topo/hooks/useTopoLayout.ts create mode 100644 src/views/ops/pages/netarch/topo/hooks/useTopoStorage.ts create mode 100644 src/views/ops/pages/netarch/topo/index.vue create mode 100644 src/views/ops/pages/netarch/topo/services/topoService.ts create mode 100644 src/views/ops/pages/netarch/topo/types.ts create mode 100644 src/views/ops/pages/netarch/topo/utils/buildGroupTree.ts diff --git a/package.json b/package.json index 023091c..de581cf 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,10 @@ "dependencies": { "@arco-design/web-vue": "^2.57.0", "@tabler/icons-vue": "^3.40.0", + "@vue-flow/background": "^1.3.2", + "@vue-flow/controls": "^1.1.3", + "@vue-flow/core": "^1.48.2", + "@vue-flow/minimap": "^1.5.4", "@vueuse/core": "^14.2.1", "axios": "^1.13.6", "dayjs": "^1.11.19", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 076afdc..6fc39cf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,9 +11,21 @@ importers: '@arco-design/web-vue': specifier: ^2.57.0 version: 2.57.0(vue@3.5.29(typescript@5.9.3)) - '@types/mockjs': - specifier: ^1.0.10 - version: 1.0.10 + '@tabler/icons-vue': + specifier: ^3.40.0 + version: 3.40.0(vue@3.5.29(typescript@5.9.3)) + '@vue-flow/background': + specifier: ^1.3.2 + version: 1.3.2(@vue-flow/core@1.48.2(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3)) + '@vue-flow/controls': + specifier: ^1.1.3 + version: 1.1.3(@vue-flow/core@1.48.2(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3)) + '@vue-flow/core': + specifier: ^1.48.2 + version: 1.48.2(vue@3.5.29(typescript@5.9.3)) + '@vue-flow/minimap': + specifier: ^1.5.4 + version: 1.5.4(@vue-flow/core@1.48.2(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3)) '@vueuse/core': specifier: ^14.2.1 version: 14.2.1(vue@3.5.29(typescript@5.9.3)) @@ -26,36 +38,27 @@ importers: echarts: specifier: ^6.0.0 version: 6.0.0 - install: - specifier: ^0.13.0 - version: 0.13.0 lodash: specifier: ^4.17.23 version: 4.17.23 mitt: specifier: ^3.0.1 version: 3.0.1 - mockjs: - specifier: ^1.1.0 - version: 1.1.0 nprogress: specifier: ^0.2.0 version: 0.2.0 pinia: specifier: ^3.0.4 version: 3.0.4(typescript@5.9.3)(vue@3.5.29(typescript@5.9.3)) - pnpm: - specifier: ^10.30.3 - version: 10.30.3 query-string: specifier: ^9.3.1 version: 9.3.1 sortablejs: specifier: ^1.15.7 version: 1.15.7 - typescript: - specifier: ^5.9.3 - version: 5.9.3 + uuid: + specifier: ^13.0.0 + version: 13.0.0 vue: specifier: ^3.5.29 version: 3.5.29(typescript@5.9.3) @@ -81,6 +84,9 @@ importers: '@types/lodash': specifier: ^4.17.24 version: 4.17.24 + '@types/mockjs': + specifier: ^1.0.10 + version: 1.0.10 '@types/nprogress': specifier: ^0.2.3 version: 0.2.3 @@ -141,6 +147,9 @@ importers: lint-staged: specifier: ^16.3.2 version: 16.3.2 + mockjs: + specifier: ^1.1.0 + version: 1.1.0 postcss-html: specifier: ^1.8.1 version: 1.8.1 @@ -171,6 +180,9 @@ importers: stylelint-order: specifier: ^7.0.1 version: 7.0.1(stylelint@17.4.0(typescript@5.9.3)) + typescript: + specifier: ^5.9.3 + version: 5.9.3 unplugin-vue-components: specifier: ^31.0.0 version: 31.0.0(vue@3.5.29(typescript@5.9.3)) @@ -856,6 +868,14 @@ packages: resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} engines: {node: '>=18'} + '@tabler/icons-vue@3.40.0': + resolution: {integrity: sha512-DyAOsnL6p3THhI8/74WvCFu86vlNI8U6DKtNHnYYjQpljtENLIy6i/bLiug3Lr04S71yKTWNxYyfd/8K8YFzQw==} + peerDependencies: + vue: '>=3.0.1' + + '@tabler/icons@3.40.0': + resolution: {integrity: sha512-V/Q4VgNPKubRTiLdmWjV/zscYcj5IIk+euicUtaVVqF6luSC9rDngYWgST5/yh3Mrg/mYUwRv1YVTk71Jp0twQ==} + '@trysound/sax@0.2.0': resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} @@ -916,6 +936,9 @@ packages: '@types/vfile@3.0.2': resolution: {integrity: sha512-b3nLFGaGkJ9rzOcuXRfHkZMdjsawuDD0ENL9fzTophtBg8FJHSGbH7daXkEpcwy3v7Xol3pAvsmlYyFhR4pqJw==} + '@types/web-bluetooth@0.0.20': + resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} + '@types/web-bluetooth@0.0.21': resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} @@ -1107,6 +1130,29 @@ packages: '@volar/typescript@2.4.28': resolution: {integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==} + '@vue-flow/background@1.3.2': + resolution: {integrity: sha512-eJPhDcLj1wEo45bBoqTXw1uhl0yK2RaQGnEINqvvBsAFKh/camHJd5NPmOdS1w+M9lggc9igUewxaEd3iCQX2w==} + peerDependencies: + '@vue-flow/core': ^1.23.0 + vue: ^3.3.0 + + '@vue-flow/controls@1.1.3': + resolution: {integrity: sha512-XCf+G+jCvaWURdFlZmOjifZGw3XMhN5hHlfMGkWh9xot+9nH9gdTZtn+ldIJKtarg3B21iyHU8JjKDhYcB6JMw==} + peerDependencies: + '@vue-flow/core': ^1.23.0 + vue: ^3.3.0 + + '@vue-flow/core@1.48.2': + resolution: {integrity: sha512-raxhgKWE+G/mcEvXJjGFUDYW9rAI3GOtiHR3ZkNpwBWuIaCC1EYiBmKGwJOoNzVFgwO7COgErnK7i08i287AFA==} + peerDependencies: + vue: ^3.3.0 + + '@vue-flow/minimap@1.5.4': + resolution: {integrity: sha512-l4C+XTAXnRxsRpUdN7cAVFBennC1sVRzq4bDSpVK+ag7tdMczAnhFYGgbLkUw3v3sY6gokyWwMl8CDonp8eB2g==} + peerDependencies: + '@vue-flow/core': ^1.23.0 + vue: ^3.3.0 + '@vue-macros/common@3.1.2': resolution: {integrity: sha512-h9t4ArDdniO9ekYHAD95t9AZcAbb19lEGK+26iAjUODOIJKmObDNBSe4+6ELQAA3vtYiFPPBtHh7+cQCKi3Dng==} engines: {node: '>=20.19.0'} @@ -1185,14 +1231,23 @@ packages: '@vue/shared@3.5.29': resolution: {integrity: sha512-w7SR0A5zyRByL9XUkCfdLs7t9XOHUyJ67qPGQjOou3p6GvBeBW+AVjUUmlxtZ4PIYaRvE+1LmK44O4uajlZwcg==} + '@vueuse/core@10.11.1': + resolution: {integrity: sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==} + '@vueuse/core@14.2.1': resolution: {integrity: sha512-3vwDzV+GDUNpdegRY6kzpLm4Igptq+GA0QkJ3W61Iv27YWwW/ufSlOfgQIpN6FZRMG0mkaz4gglJRtq5SeJyIQ==} peerDependencies: vue: ^3.5.0 + '@vueuse/metadata@10.11.1': + resolution: {integrity: sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==} + '@vueuse/metadata@14.2.1': resolution: {integrity: sha512-1ButlVtj5Sb/HDtIy1HFr1VqCP4G6Ypqt5MAo0lCgjokrk2mvQKsK2uuy0vqu/Ks+sHfuHo0B9Y9jn9xKdjZsw==} + '@vueuse/shared@10.11.1': + resolution: {integrity: sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==} + '@vueuse/shared@14.2.1': resolution: {integrity: sha512-shTJncjV9JTI4oVNyF1FQonetYAiTBd+Qj7cY89SWbXSkx7gyhrgtEdF2ZAVWS1S3SHlaROO6F2IesJxQEkZBw==} peerDependencies: @@ -1673,6 +1728,44 @@ packages: resolution: {integrity: sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==} engines: {node: '>=0.10.0'} + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + dargs@8.1.0: resolution: {integrity: sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==} engines: {node: '>=12'} @@ -2472,10 +2565,6 @@ packages: resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - install@0.13.0: - resolution: {integrity: sha512-zDml/jzr2PKU9I8J/xyZBQn8rPCAY//UOYNmR01XwNwyfhEWObo2SWfSl1+0tm1u6PhxLwDnfsT/6jB7OUxqFA==} - engines: {node: '>= 0.10'} - internal-slot@1.1.0: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} @@ -3280,11 +3369,6 @@ packages: pkg-types@2.3.0: resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} - pnpm@10.30.3: - resolution: {integrity: sha512-yWHR4KLY41TsqlFmuCJRZmi39Ey1vZUSLVkN2Bki9gb1RzttI+xKW+Bef80Y6EiNR9l4u+mBhy8RRdBumnQAFw==} - engines: {node: '>=18.12'} - hasBin: true - posix-character-classes@0.1.1: resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==} engines: {node: '>=0.10.0'} @@ -4155,6 +4239,10 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + uuid@13.0.0: + resolution: {integrity: sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==} + hasBin: true + validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} @@ -4227,6 +4315,17 @@ packages: vscode-uri@3.1.0: resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + vue-demi@0.14.10: + resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} + engines: {node: '>=12'} + hasBin: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + vue-echarts@8.0.1: resolution: {integrity: sha512-23rJTFLu1OUEGRWjJGmdGt8fP+8+ja1gVgzMYPIPaHWpXegcO1viIAaeu2H4QHESlVeHzUAHIxKXGrwjsyXAaA==} peerDependencies: @@ -5009,6 +5108,13 @@ snapshots: '@sindresorhus/merge-streams@4.0.0': {} + '@tabler/icons-vue@3.40.0(vue@3.5.29(typescript@5.9.3))': + dependencies: + '@tabler/icons': 3.40.0 + vue: 3.5.29(typescript@5.9.3) + + '@tabler/icons@3.40.0': {} + '@trysound/sax@0.2.0': {} '@tybys/wasm-util@0.10.1': @@ -5066,6 +5172,8 @@ snapshots: '@types/unist': 2.0.11 '@types/vfile-message': 2.0.0 + '@types/web-bluetooth@0.0.20': {} + '@types/web-bluetooth@0.0.21': {} '@typescript-eslint/eslint-plugin@8.56.1(@typescript-eslint/parser@8.56.1(eslint@8.57.0)(typescript@5.9.3))(eslint@8.57.0)(typescript@5.9.3)': @@ -5250,6 +5358,34 @@ snapshots: path-browserify: 1.0.1 vscode-uri: 3.1.0 + '@vue-flow/background@1.3.2(@vue-flow/core@1.48.2(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))': + dependencies: + '@vue-flow/core': 1.48.2(vue@3.5.29(typescript@5.9.3)) + vue: 3.5.29(typescript@5.9.3) + + '@vue-flow/controls@1.1.3(@vue-flow/core@1.48.2(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))': + dependencies: + '@vue-flow/core': 1.48.2(vue@3.5.29(typescript@5.9.3)) + vue: 3.5.29(typescript@5.9.3) + + '@vue-flow/core@1.48.2(vue@3.5.29(typescript@5.9.3))': + dependencies: + '@vueuse/core': 10.11.1(vue@3.5.29(typescript@5.9.3)) + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-zoom: 3.0.0 + vue: 3.5.29(typescript@5.9.3) + transitivePeerDependencies: + - '@vue/composition-api' + + '@vue-flow/minimap@1.5.4(@vue-flow/core@1.48.2(vue@3.5.29(typescript@5.9.3)))(vue@3.5.29(typescript@5.9.3))': + dependencies: + '@vue-flow/core': 1.48.2(vue@3.5.29(typescript@5.9.3)) + d3-selection: 3.0.0 + d3-zoom: 3.0.0 + vue: 3.5.29(typescript@5.9.3) + '@vue-macros/common@3.1.2(vue@3.5.29(typescript@5.9.3))': dependencies: '@vue/compiler-sfc': 3.5.29 @@ -5386,6 +5522,16 @@ snapshots: '@vue/shared@3.5.29': {} + '@vueuse/core@10.11.1(vue@3.5.29(typescript@5.9.3))': + dependencies: + '@types/web-bluetooth': 0.0.20 + '@vueuse/metadata': 10.11.1 + '@vueuse/shared': 10.11.1(vue@3.5.29(typescript@5.9.3)) + vue-demi: 0.14.10(vue@3.5.29(typescript@5.9.3)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + '@vueuse/core@14.2.1(vue@3.5.29(typescript@5.9.3))': dependencies: '@types/web-bluetooth': 0.0.21 @@ -5393,8 +5539,17 @@ snapshots: '@vueuse/shared': 14.2.1(vue@3.5.29(typescript@5.9.3)) vue: 3.5.29(typescript@5.9.3) + '@vueuse/metadata@10.11.1': {} + '@vueuse/metadata@14.2.1': {} + '@vueuse/shared@10.11.1(vue@3.5.29(typescript@5.9.3))': + dependencies: + vue-demi: 0.14.10(vue@3.5.29(typescript@5.9.3)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + '@vueuse/shared@14.2.1(vue@3.5.29(typescript@5.9.3))': dependencies: vue: 3.5.29(typescript@5.9.3) @@ -5904,6 +6059,42 @@ snapshots: dependencies: array-find-index: 1.0.2 + d3-color@3.1.0: {} + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-ease@3.0.1: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-selection@3.0.0: {} + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + dargs@8.1.0: {} data-view-buffer@1.0.2: @@ -6819,8 +7010,6 @@ snapshots: ini@4.1.1: {} - install@0.13.0: {} - internal-slot@1.1.0: dependencies: es-errors: 1.3.0 @@ -7605,8 +7794,6 @@ snapshots: exsolve: 1.0.8 pathe: 2.0.3 - pnpm@10.30.3: {} - posix-character-classes@0.1.1: {} possible-typed-array-names@1.1.0: {} @@ -8674,6 +8861,8 @@ snapshots: util-deprecate@1.0.2: {} + uuid@13.0.0: {} + validate-npm-package-license@3.0.4: dependencies: spdx-correct: 3.2.0 @@ -8736,6 +8925,10 @@ snapshots: vscode-uri@3.1.0: {} + vue-demi@0.14.10(vue@3.5.29(typescript@5.9.3)): + dependencies: + vue: 3.5.29(typescript@5.9.3) + vue-echarts@8.0.1(echarts@6.0.0)(vue@3.5.29(typescript@5.9.3)): dependencies: echarts: 6.0.0 diff --git a/src/api/ops/netarchTopo.ts b/src/api/ops/netarchTopo.ts new file mode 100644 index 0000000..3b48e6b --- /dev/null +++ b/src/api/ops/netarchTopo.ts @@ -0,0 +1,174 @@ +import { request } from '@/api/request' + +// ==================== 类型定义 ==================== + +/** 拓扑对象 */ +export interface Topology { + id: number + name: string + type: 'layer2' | 'layer3' | 'physical' + description?: string + group_id?: number + group_name?: string + node_data?: string + collector_id?: number + status?: 'pending' | 'discovering' | 'active' | 'error' + discovery_config?: string + last_discovery?: string + next_discovery?: string + node_count?: number + link_count?: number + enable?: boolean + created_at?: string + updated_at?: string +} + +/** 链路对象 */ +export interface Link { + id?: number + topology_id?: number + source: string + target: string + type?: 'physical' | 'virtual' + label?: string + bandwidth?: number + latency?: number + packet_loss?: number + status?: 'up' | 'down' | 'unknown' + in_traffic?: number + out_traffic?: number + metadata?: string + description?: string + created_at?: string + updated_at?: string +} + +/** 拓扑分组 */ +export interface TopologyGroup { + id: number + name: string + parent_id?: number + level?: number + path?: string + description?: string + sort?: number + enable?: boolean + topology_count?: number + total_link_count?: number + total_topology_count?: number + children?: TopologyGroup[] + created_at?: string + updated_at?: string +} + +/** 拓扑节点对象 */ +export interface TopologyNode { + id: string + topology_id: number + label: string + type: string + ip?: string + status?: string + alerts?: number + traffic?: string + description?: string + parentId?: string | null + level?: number + position?: { x: number; y: number } + created_at?: string + updated_at?: string +} + +// ==================== 分组管理接口 ==================== + +/** 获取分组列表 */ +export const fetchTopologyGroups = (data?: { + parent_id?: number; + page?: number; + size?: number; + keyword?: string; + enable?: boolean +}) => + request.get('/DC-Control/v1/topology-groups', { params: data }) + +/** 创建分组 */ +export const createTopologyGroup = (data: Partial) => + request.post('/DC-Control/v1/topology-groups', data) + +/** 更新分组 */ +export const updateTopologyGroup = (data: Partial & { id: number }) => + request.put(`/DC-Control/v1/topology-groups/${data.id}`, data) + +/** 删除分组 */ +export const deleteTopologyGroup = (id: number) => + request.delete(`/DC-Control/v1/topology-groups/${id}`) + +// ==================== 拓扑管理接口 ==================== + +/** 获取拓扑列表 */ +export const fetchTopologies = (data: { page: number; size: number; keyword?: string; group_id?: number }) => + request.get('/DC-Control/v1/topologies', { params: data }) + +/** 获取拓扑详情 */ +export const fetchTopologyDetail = (id: number) => + request.get(`/DC-Control/v1/topologies/${id}`) + +/** 创建拓扑 */ +export const createTopology = (data: Partial) => + request.post('/DC-Control/v1/topologies', data) + +/** 更新拓扑 */ +export const updateTopology = (data: Partial & { id: number }) => + request.put(`/DC-Control/v1/topologies/${data.id}`, data) + +/** 删除拓扑 */ +export const deleteTopology = (id: number) => + request.delete(`/DC-Control/v1/topologies/${id}`) + +/** 触发拓扑发现 */ +export const discoverTopology = (id: number) => + request.post(`/DC-Control/v1/topologies/${id}/discover`) + +/** 获取拓扑视图(包含拓扑和链路) */ +export const fetchTopologyView = (id: number) => + request.get(`/DC-Control/v1/topologies/${id}/view`) + +/** 获取拓扑图数据(用于前端可视化) */ +export const fetchTopologyGraph = (id: number) => + request.get(`/DC-Control/v1/topologies/${id}/graph`) + +// ==================== 节点管理接口 ==================== + +/** 创建节点 */ +export const createNode = (topologyId: number, data: Partial) => + request.post(`/DC-Control/v1/topologies/${topologyId}/nodes`, data) + +/** 更新节点 */ +export const updateNode = (topologyId: number, nodeId: string, data: Partial) => + request.put(`/DC-Control/v1/topologies/${topologyId}/nodes/${nodeId}`, data) + +/** 删除节点 */ +export const deleteNode = (topologyId: number, nodeId: string) => + request.delete(`/DC-Control/v1/topologies/${topologyId}/nodes/${nodeId}`) + +/** 批量更新节点位置 */ +export const updateNodesPositions = (topologyId: number, positions: Array<{ id: string; position: { x: number; y: number } }>) => + request.put(`/DC-Control/v1/topologies/${topologyId}/nodes/positions`, { positions }) + +// ==================== 链路管理接口 ==================== + +/** 获取链路列表 */ +export const fetchLinks = (topologyId: number) => + request.get(`/DC-Control/v1/topologies/${topologyId}/links`) + +/** 创建链路 */ +export const createLink = (topologyId: number, data: Partial) => + request.post(`/DC-Control/v1/topologies/${topologyId}/links`, data) + +/** 更新链路 */ +export const updateLink = (topologyId: number, linkId: number, data: Partial) => + request.put(`/DC-Control/v1/topologies/${topologyId}/links/${linkId}`, data) + +/** 删除链路 */ +export const deleteLink = (topologyId: number, linkId: string) => + request.delete(`/DC-Control/v1/topologies/${topologyId}/links/${linkId}`) diff --git a/src/layout/default-layout.vue b/src/layout/default-layout.vue index 8ff2405..d359552 100644 --- a/src/layout/default-layout.vue +++ b/src/layout/default-layout.vue @@ -43,7 +43,14 @@ - +
+ +
+