diff --git a/src/views/monitor/topology-build/components/GraphEditModal.vue b/src/views/monitor/topology-build/components/GraphEditModal.vue
new file mode 100644
index 00000000..f9f6f970
--- /dev/null
+++ b/src/views/monitor/topology-build/components/GraphEditModal.vue
@@ -0,0 +1,1150 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 标签文本及其配置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 标签文本及其配置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 图片
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 图标
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 标签文本及其配置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/monitor/topology-build/hooks/useCombo.ts b/src/views/monitor/topology-build/hooks/useCombo.ts
index e6912fb5..7f893a90 100644
--- a/src/views/monitor/topology-build/hooks/useCombo.ts
+++ b/src/views/monitor/topology-build/hooks/useCombo.ts
@@ -1,7 +1,7 @@
import { message, Form } from 'ant-design-vue/lib';
import { reactive, watch } from 'vue';
import { graphG6 } from './useGraph';
-import { number } from 'echarts';
+import useI18n from '@/hooks/useI18n';
/**图分组内置类型 */
export const comboTypeOptions = [
@@ -39,118 +39,130 @@ export const comboPositionOptions = [
},
];
-/**图分组信息状态类型 */
-type ComboStateType = {
- /**图分组原始数据 */
- origin: Record;
- /**图分组表单数据 */
- form: Record;
-};
+export default function useCombo() {
+ const { t } = useI18n();
-/**图分组信息状态 */
-export let comboState: ComboStateType = reactive({
- origin: {},
- form: {
- id: '',
- type: 'rect',
- parentId: '',
- size: [40, 40],
- padding: [30, 30, 30, 30],
- style: {
- fill: '#ffffff',
- stroke: '#ffffff',
- lineWidth: 1,
- },
- label: '',
- labelCfg: {
- refX: 10,
- refY: 10,
- position: 'top',
+ /**图分组信息状态类型 */
+ type ComboStateType = {
+ /**图分组原始数据 */
+ origin: Record;
+ /**图分组表单数据 */
+ form: Record;
+ };
+
+ /**图分组信息状态 */
+ let comboState: ComboStateType = reactive({
+ origin: {},
+ form: {
+ id: '',
+ type: 'rect',
+ parentId: '',
+ size: [40, 40],
+ padding: [30, 30, 30, 30],
style: {
- fill: '#000000',
- fontSize: 12,
- fontWeight: 500,
+ fill: '#ffffff',
+ stroke: '#ffffff',
+ lineWidth: 1,
+ },
+ label: '',
+ labelCfg: {
+ refX: 10,
+ refY: 10,
+ position: 'top',
+ style: {
+ fill: '#000000',
+ fontSize: 12,
+ fontWeight: 500,
+ },
},
},
- },
-});
+ });
-/**图分组对话分组内表单属性和校验规则 */
-export const comboStateForm = Form.useForm(
- comboState.form,
- reactive({
- id: [{ required: true, message: '分组唯一标识 ID' }],
- })
-);
+ /**图分组对话分组内表单属性和校验规则 */
+ const comboStateForm = Form.useForm(
+ comboState.form,
+ reactive({
+ id: [{ required: true, message: '分组唯一标识 ID' }],
+ })
+ );
-/**图分组编辑监听更新视图 */
-watch(comboState.form, combo => {
- const info = JSON.parse(JSON.stringify(combo));
- const comboId = info.id;
- if (comboId) {
- graphG6.value.clearItemStates(comboId, 'selected');
- console.log(info);
- const data = graphG6.value.save();
- const item = data.combos.find((item: any) => item.id === combo.id);
- Object.assign(item, combo);
- // 无父组id时不要设置,避免导致绘制失败
- if (!combo.parentId) {
- Reflect.deleteProperty(item, 'parentId');
+ /**图分组编辑监听更新视图 */
+ watch(comboState.form, combo => {
+ const info = JSON.parse(JSON.stringify(combo));
+ const comboId = info.id;
+ if (comboId) {
+ graphG6.value.clearItemStates(comboId, 'selected');
+ console.log(info);
+ const data = graphG6.value.save();
+ const item = data.combos.find((item: any) => item.id === combo.id);
+ Object.assign(item, combo);
+ // 无父组id时不要设置,避免导致绘制失败
+ if (!combo.parentId) {
+ Reflect.deleteProperty(item, 'parentId');
+ }
+ graphG6.value.read(data);
}
- graphG6.value.read(data);
- }
-});
+ });
-/**图分组类型输入限制 */
-export function handleComboTypeChange(type: any) {
- // 类型尺寸和边距
- if (type === 'circle') {
- comboState.form.size = 30;
- comboState.form.padding = 30;
- }
- if (type === 'rect') {
- comboState.form.size = [30, 20];
- comboState.form.padding = [10, 20, 10, 20];
- }
-}
-
-/**图分组新增或更新 */
-export function handleOkcombo() {
- const combo = JSON.parse(JSON.stringify(comboState.form));
- if (!combo.id) {
- message.warn({
- content: `分组元素ID错误`,
- duration: 2,
- });
- return false;
- }
-
- const item = graphG6.value.findById(combo.id);
- if (item) {
- const data = graphG6.value.save();
- const item = data.combos.find((item: any) => item.id === combo.id);
- Object.assign(item, combo);
- if (!combo.parentId) {
- Reflect.deleteProperty(item, 'parentId');
+ /**图分组类型输入限制 */
+ function handleComboTypeChange(type: any) {
+ // 类型尺寸和边距
+ if (type === 'circle') {
+ comboState.form.size = 30;
+ comboState.form.padding = 30;
+ }
+ if (type === 'rect') {
+ comboState.form.size = [30, 20];
+ comboState.form.padding = [10, 20, 10, 20];
}
- graphG6.value.read(data);
- } else {
- graphG6.value.createCombo(combo, []);
}
- comboStateForm.resetFields();
- comboState.origin = {};
- return true;
-}
-/**图分组取消还原 */
-export function handleCancelcombo() {
- const origin = JSON.parse(JSON.stringify(comboState.origin));
- if (origin.id) {
- const data = graphG6.value.save();
- const item = data.combos.find((combo: any) => combo.id === origin.id);
- Object.assign(item, origin);
- graphG6.value.read(data);
+ /**图分组新增或更新 */
+ function handleOkcombo() {
+ const combo = JSON.parse(JSON.stringify(comboState.form));
+ if (!combo.id) {
+ message.warn({
+ content: `分组元素ID错误`,
+ duration: 2,
+ });
+ return false;
+ }
+
+ const item = graphG6.value.findById(combo.id);
+ if (item) {
+ const data = graphG6.value.save();
+ const item = data.combos.find((item: any) => item.id === combo.id);
+ Object.assign(item, combo);
+ if (!combo.parentId) {
+ Reflect.deleteProperty(item, 'parentId');
+ }
+ graphG6.value.read(data);
+ } else {
+ graphG6.value.createCombo(combo, []);
+ }
comboStateForm.resetFields();
comboState.origin = {};
+ return true;
}
+
+ /**图分组取消还原 */
+ function handleCancelcombo() {
+ const origin = JSON.parse(JSON.stringify(comboState.origin));
+ if (origin.id) {
+ const data = graphG6.value.save();
+ const item = data.combos.find((combo: any) => combo.id === origin.id);
+ Object.assign(item, origin);
+ graphG6.value.read(data);
+ comboStateForm.resetFields();
+ comboState.origin = {};
+ }
+ }
+
+ return {
+ comboState,
+ comboStateForm,
+ handleComboTypeChange,
+ handleOkcombo,
+ handleCancelcombo,
+ };
}
diff --git a/src/views/monitor/topology-build/hooks/useEdge.ts b/src/views/monitor/topology-build/hooks/useEdge.ts
index 8b3ce2cf..7828b00a 100644
--- a/src/views/monitor/topology-build/hooks/useEdge.ts
+++ b/src/views/monitor/topology-build/hooks/useEdge.ts
@@ -1,5 +1,6 @@
import { message, Form } from 'ant-design-vue/lib';
import { reactive, watch } from 'vue';
+import useI18n from '@/hooks/useI18n';
import { graphG6 } from './useGraph';
/**图边内置边类型 */
@@ -54,98 +55,117 @@ export const edgePositionOptions = [
},
];
-/**图边信息状态类型 */
-type EdgeStateType = {
- /**图边原始数据 */
- origin: Record;
- /**图边表单数据 */
- form: Record;
-};
+export default function useEdge() {
+ const { t } = useI18n();
-/**图边信息状态 */
-export let edgeState: EdgeStateType = reactive({
- origin: {},
- form: {
- id: '',
- source: '',
- target: '',
- type: 'polyline',
- style: {
- offset: 20,
- radius: 2,
- stroke: '#ffffff',
- lineWidth: 1,
- cursor: 'pointer',
- },
- label: '',
- labelCfg: {
- refX: 0,
- refY: 0,
- position: 'middle',
- autoRotate: false,
+ /**图边信息状态类型 */
+ type EdgeStateType = {
+ /**图边原始数据 */
+ origin: Record;
+ /**图边表单数据 */
+ form: Record;
+ };
+
+ /**图边信息状态 */
+ let edgeState: EdgeStateType = reactive({
+ origin: {},
+ form: {
+ id: '',
+ source: '',
+ target: '',
+ type: 'polyline',
style: {
- fill: '#ffffff',
- fontSize: 12,
- fontWeight: 500,
+ offset: 20,
+ radius: 2,
+ stroke: '#ffffff',
+ lineWidth: 1,
+ cursor: 'pointer',
+ },
+ label: '',
+ labelCfg: {
+ refX: 0,
+ refY: 0,
+ position: 'middle',
+ autoRotate: false,
+ style: {
+ fill: '#ffffff',
+ fontSize: 12,
+ fontWeight: 500,
+ },
},
},
- },
-});
+ });
-/**图边对话框内表单属性和校验规则 */
-export const edgeStateForm = Form.useForm(
- edgeState.form,
- reactive({
- id: [{ required: true, message: '边唯一 ID' }],
- source: [{ required: true, message: '起始点 id' }],
- target: [{ required: true, message: '结束点 id' }],
- type: [{ required: true, message: 'line' }],
- })
-);
+ /**图边对话框内表单属性和校验规则 */
+ const edgeStateForm = Form.useForm(
+ edgeState.form,
+ reactive({
+ id: [{ required: true, message: '边唯一 ID' }],
+ source: [{ required: true, message: '起始点 id' }],
+ target: [{ required: true, message: '结束点 id' }],
+ type: [{ required: true, message: 'line' }],
+ })
+ );
-/**图边编辑监听更新视图 */
-watch(edgeState.form, edge => {
- const info = JSON.parse(JSON.stringify(edge));
- const edgeId = info.id;
- if (edgeId) {
- graphG6.value.clearItemStates(edgeId, 'selected');
- graphG6.value.updateItem(edgeId, info);
- }
-});
+ /**图边编辑监听更新视图 */
+ watch(edgeState.form, edge => {
+ const info = JSON.parse(JSON.stringify(edge));
+ const edgeId = info.id;
+ if (edgeId && edgeId !== '#') {
+ graphG6.value.clearItemStates(edgeId, 'selected');
+ graphG6.value.updateItem(edgeId, info);
+ }
+ });
-/**图边新增或更新 */
-export function handleOkEdge() {
- const edge = JSON.parse(JSON.stringify(edgeState.form));
- if (!edge.id) {
- message.warn({
- content: `边元素ID错误`,
- duration: 2,
- });
- return false;
+ /**图边新增或更新 */
+ function handleOkEdge() {
+ return edgeStateForm
+ .validate()
+ .then(e => {
+ const edge = JSON.parse(JSON.stringify(edgeState.form));
+ if (!edge.id) {
+ message.warn({
+ content: `边元素ID错误`,
+ duration: 2,
+ });
+ return false;
+ }
+
+ debugger;
+ // graphG6.value.removeItem(edge.id);
+ // edge.id = `${edge.source}~${Date.now()}~${edge.target}`;
+ // graphG6.value.addItem('edge', edge);
+ const item = graphG6.value.findById(edge.id);
+ if (item) {
+ graphG6.value.updateItem(item, edge);
+ } else {
+ edge.id = `${edge.source}~${Date.now()}~${edge.target}`;
+ graphG6.value.addItem('edge', edge);
+ }
+ edgeStateForm.resetFields();
+ edgeState.origin = {};
+ return true;
+ })
+ .catch(e => {
+ message.error(
+ t('common.errorFields', { num: e.errorFields.length }),
+ 3
+ );
+ return false;
+ });
}
- // graphG6.value.removeItem(edge.id);
- // edge.id = `${edge.source}~${Date.now()}~${edge.target}`;
- // graphG6.value.addItem('edge', edge);
- const item = graphG6.value.findById(edge.id);
- if (item) {
- graphG6.value.updateItem(item, edge);
- } else {
- edge.id = `${edge.source}~${Date.now()}~${edge.target}`;
- graphG6.value.addItem('edge', edge);
- }
- edgeStateForm.resetFields();
- edgeState.origin = {};
- return true;
-}
-
-/**图边取消还原 */
-export function handleCancelEdge() {
- const origin = JSON.parse(JSON.stringify(edgeState.origin));
- if (origin.id) {
- graphG6.value.updateItem(origin.id, origin);
- // graphG6.value.removeItem(edgeOrigin.id);
- // graphG6.value.addItem('edge', edgeOrigin);
- edgeStateForm.resetFields();
- edgeState.origin = {};
+
+ /**图边取消还原 */
+ function handleCancelEdge() {
+ const origin = JSON.parse(JSON.stringify(edgeState.origin));
+ if (origin.id) {
+ graphG6.value.updateItem(origin.id, origin);
+ // graphG6.value.removeItem(edgeOrigin.id);
+ // graphG6.value.addItem('edge', edgeOrigin);
+ edgeStateForm.resetFields();
+ edgeState.origin = {};
+ }
}
+
+ return { edgeState, edgeStateForm, handleOkEdge, handleCancelEdge };
}
diff --git a/src/views/monitor/topology-build/hooks/useGraph.ts b/src/views/monitor/topology-build/hooks/useGraph.ts
index e33c9689..435eed8b 100644
--- a/src/views/monitor/topology-build/hooks/useGraph.ts
+++ b/src/views/monitor/topology-build/hooks/useGraph.ts
@@ -1,3 +1,4 @@
+import useI18n from '@/hooks/useI18n';
import {
Graph,
GraphData,
@@ -9,462 +10,6 @@ import {
} from '@antv/g6';
import { ref } from 'vue';
-/**图实例对象 */
-export const graphG6 = ref(null);
-
-/**图事件变更 */
-export const graphEvent = ref<{
- type: string;
- target: HTMLElement | (IShapeBase & ICanvas);
- item: Item | null;
-}>();
-
-/**图画布右击菜单 */
-const graphCanvasMenu = new Menu({
- offsetX: 6,
- offseY: 10,
- itemTypes: ['canvas'],
- getContent(evt) {
- return `
- `;
- },
- handleMenuClick(target, item) {
- console.log(target, item);
- const targetId = target.id;
- switch (targetId) {
- case 'show':
- // 显示节点
- graphG6.value.getNodes().forEach((node: any) => {
- if (!node.isVisible()) {
- graphG6.value.showItem(node);
- graphG6.value.refreshItem(node);
- }
- });
- // 显示边
- graphG6.value.getEdges().forEach((edge: any) => {
- if (!edge.isVisible()) {
- graphG6.value.showItem(edge);
- graphG6.value.refreshItem(edge);
- }
- });
- // 显示框
- graphG6.value.getCombos().forEach((combo: any) => {
- if (!combo.isVisible()) {
- graphG6.value.showItem(combo);
- graphG6.value.updateCombo(combo);
- }
- });
- break;
- }
- },
-});
-
-/**图分组Combo 右击菜单 */
-const graphComboMenu = new Menu({
- offsetX: 6,
- offseY: 10,
- itemTypes: ['combo'],
- getContent(evt) {
- console.log(evt);
- return `
-
-
- 1. 编辑
-
-
- 2. 隐藏
-
-
- `;
- },
- handleMenuClick(target, item) {
- console.log(target, item);
- const targetId = target.id;
- switch (targetId) {
- case 'edit':
- graphEvent.value = { type: `combo-${targetId}`, target, item };
- break;
- case 'hide':
- graphG6.value.hideItem(item);
- break;
- }
- },
-});
-
-/**图节点右击菜单 */
-const graphNodeMenu = new Menu({
- offsetX: 6,
- offseY: 10,
- itemTypes: ['node'],
- getContent(evt) {
- console.log(evt);
- return `
-
-
- 1. 编辑
-
-
- 2. 隐藏
-
-
- `;
- },
- handleMenuClick(target, item) {
- console.log(target, item);
- const targetId = target.id;
- switch (targetId) {
- case 'edit':
- graphEvent.value = { type: `node-${targetId}`, target, item };
- break;
- case 'hide':
- graphG6.value.hideItem(item);
- break;
- }
- },
-});
-
-/**图节点展示 */
-const graphNodeTooltip = new Tooltip({
- offsetX: 10,
- offsetY: 20,
- getContent(e: any) {
- const outDiv = document.createElement('div');
- outDiv.style.width = '180px';
- outDiv.innerHTML = `
- 自定义tooltip
-
- - Label: ${e.item.getModel().label || e.item.getModel().id}
-
`;
- return outDiv;
- },
- itemTypes: ['node'],
-});
-
-/**图边右击菜单 */
-const graphEdgeMenu = new Menu({
- offsetX: 6,
- offseY: 10,
- itemTypes: ['edge'],
- getContent(evt) {
- console.log(evt);
- return `
-
-
- 1. 编辑
-
-
- 2. 隐藏
-
-
- `;
- },
- handleMenuClick(target, item) {
- console.log(target, item);
- const targetId = target.id;
- switch (targetId) {
- case 'edit':
- graphEvent.value = { type: `edge-${targetId}`, target, item };
- break;
- case 'hide':
- graphG6.value.hideItem(item);
- break;
- }
- },
-});
-
-/**图边展示 */
-const graphEdgeTooltip = new Tooltip({
- offsetX: 10,
- offsetY: 20,
- getContent(e: any) {
- const outDiv = document.createElement('div');
- outDiv.style.width = '180px';
- outDiv.innerHTML = `
- graphEdgeTooltip
-
- - Label: ${e.item.getModel().label || e.item.getModel().id}
-
`;
- return outDiv;
- },
- itemTypes: ['edge'],
-});
-
-/**图绑定事件 */
-function fnGraphEvent(graph: Graph) {
- // 调用 graph.add / graph.addItem 方法之后触发
- graph.on('afteradditem', evt => {
- fnSelectSourceTargetOptionsData();
- });
-
- // 鼠标进入节点事件
- graph.on('edge:mouseenter', (ev: any) => {
- // 获得鼠标当前目标边
- const edge = ev.item;
- // 该边的起始点
- const source = edge.getSource();
- // 该边的结束点
- const target = edge.getTarget();
- // 先将边提前,再将端点提前。这样该边两个端点还是在该边上层,较符合常规。
- // edge.toFront();
- // source.toFront();
- // target.toFront();
- });
-
- graph.on('edge:mouseleave', (ev: any) => {
- // 获得图上所有边实例
- const edges = graph.getEdges();
- // 遍历边,将所有边的层级放置在后方,以恢复原样
- // edges.forEach(edge => {
- // edge.toBack();
- // });
- });
-
- graph.on('node:mouseenter', evt => {
- // 获得鼠标当前目标节点
- const node = evt.item;
- // 获取该节点的所有相关边
- const edges = node && graph.getEdges();
- // 遍历相关边,将所有相关边提前,再将相关边的两个端点提前,以保证相关边的端点在边的上方常规效果
- // edges.forEach((edge: any) => {
- // edge.toFront();
- // edge.getSource().toFront();
- // edge.getTarget().toFront();
- // });
- // graphEvent.value = {
- // type: 'node:mouseenter',
- // target: evt.target,
- // item: evt.item,
- // };
- });
-
- graph.on('node:mouseleave', (ev: any) => {
- // 获得图上所有边实例
- const edges = graph.getEdges();
- // 遍历边,将所有边的层级放置在后方,以恢复原样
- // edges.forEach(edge => {
- // edge.toBack();
- // });
- });
-}
-
-/**图元素选择开始结束点 */
-export const selectSourceTargetOptions = ref[]>([]);
-
-/**图元素选择嵌入框 */
-export const selectComboOptions = ref[]>([]);
-
-/**
- * 图元素选择开始结束点数据获取
- */
-function fnSelectSourceTargetOptionsData() {
- // 节点
- selectSourceTargetOptions.value = [];
- graphG6.value.getNodes().forEach((node: any) => {
- const info = JSON.parse(JSON.stringify(node.getModel()));
- selectSourceTargetOptions.value.push({
- value: info.id,
- label: info.label,
- info,
- });
- });
- // 框
- selectComboOptions.value = [
- {
- value: '',
- label: '未分配',
- },
- ];
- graphG6.value.getCombos().forEach((combo: any) => {
- const info = JSON.parse(JSON.stringify(combo.getModel()));
- const comboInfo = {
- value: info.id,
- label: info.label,
- info,
- };
- selectSourceTargetOptions.value.push(comboInfo);
- selectComboOptions.value.push(comboInfo);
- });
-}
-
-/**图数据渲染 */
-export function handleRanderGraph(container: HTMLElement, data: GraphData) {
- if (!container) return;
- const { clientHeight, clientWidth } = container;
-
- const graph = new Graph({
- container: container,
- width: clientWidth,
- height: clientHeight,
- animate: true,
- fitCenter: true,
- modes: {
- default: [
- {
- type: 'click-select',
- selectEdge: true,
- },
- 'drag-combo',
- {
- type: 'drag-node',
- onlyChangeComboSize: true,
- },
- 'drag-canvas',
- 'zoom-canvas',
- 'collapse-expand-combo',
- ],
- edit: [
- {
- type: 'click-select',
- selectEdge: true,
- },
- {
- type: 'drag-node',
- shouldEnd: (e: any) => {
- return true;
- },
- },
- { type: 'drag-combo' },
- 'drag-canvas',
- 'zoom-canvas',
- { type: 'create-edge', key: 'alt' },
- ],
- },
- groupByTypes: false,
- // layout: {
- // type: 'dagre',
- // sortByCombo: false,
- // ranksep: 10,
- // nodesep: 10,
- // },
- // 全局节点
- defaultNode: {
- type: 'rect',
- size: [80, 40],
- style: {
- radius: 8,
- // fill: '#ffffff',
- stroke: '#ffffff',
- lineWidth: 1,
- cursor: 'pointer',
- },
- labelCfg: {
- position: 'center',
- offset: 0,
- style: {
- fill: '#000000',
- fontSize: 12,
- fontWeight: 500,
- },
- },
- icon: {
- show: false,
- img: '/svg/service.svg',
- width: 25,
- height: 25,
- offset: 20, // triangle 特有
- },
- direction: 'up', // triangle 三角形的方向
- },
- // 全局边
- defaultEdge: {
- type: 'polyline',
- style: {
- offset: 20, // 拐弯处距离节点最小距离
- radius: 2, // 拐弯处的圆角弧度,若不设置则为直角
- stroke: '#ffffff',
- lineWidth: 1,
- cursor: 'pointer',
- },
- labelCfg: {
- refX: 0,
- refY: 0,
- position: 'middle',
- autoRotate: false,
- style: {
- fill: '#ffffff',
- fontSize: 12,
- fontWeight: 500,
- },
- },
- },
- // 全局框节点
- defaultCombo: {
- type: 'rect', // Combo 类型
- size: [40, 40],
- padding: [30, 30, 30, 30],
- style: {
- radius: 2,
- fill: '#ffffff',
- stroke: '#ffffff',
- lineWidth: 1,
- cursor: 'grab',
- fillOpacity: 0.5,
- },
- labelCfg: {
- refX: 10,
- refY: 10,
- position: 'top',
- style: {
- fill: '#000000',
- fontSize: 12,
- fontWeight: 500,
- },
- },
- },
- plugins: [
- graphCanvasMenu,
- graphComboMenu,
- graphNodeMenu,
- graphNodeTooltip,
- graphEdgeMenu,
- graphEdgeTooltip,
- ],
- });
- graph.data(data);
- graph.render();
-
- // 图绑定事件
- fnGraphEvent(graph);
-
- graphG6.value = graph;
-
- // 图元素选择开始结束点数据
- fnSelectSourceTargetOptionsData();
-
- return graph;
-}
-
/**图模式选择项 */
export const graphModeOptions = [
{
@@ -477,12 +22,494 @@ export const graphModeOptions = [
},
];
+/**图实例对象 */
+export const graphG6 = ref(null);
+
+/**图事件变更 */
+export const graphEvent = ref<{
+ type: string;
+ target: HTMLElement | (IShapeBase & ICanvas);
+ item: Item | null;
+}>();
+
/**图模式选择项 */
export const graphMode = ref('default');
-/**图模式改变 default | edit */
-export function handleChangeMode(value: any) {
- console.log(value, JSON.parse(JSON.stringify(graphG6.value.save())));
- graphG6.value.setMode(value);
- graphMode.value = graphG6.value.getCurrentMode();
+export default function useGraph() {
+ //实例化i18n
+ const { t } = useI18n();
+
+ /**图画布右击菜单 */
+ const graphCanvasMenu = new Menu({
+ offsetX: 6,
+ offseY: 10,
+ itemTypes: ['canvas'],
+ getContent(evt) {
+ return `
+
+
+ 1. 显示所有隐藏项
+
+
+ 2. 新增节点
+
+
+ 3. 新增边
+
+
+ 4. 新增分组
+
+
`;
+ },
+ handleMenuClick(target, item) {
+ console.log(target, item);
+ const targetId = target.id;
+ switch (targetId) {
+ case 'create-node':
+ case 'create-edge':
+ case 'create-combo':
+ graphEvent.value = { type: `canvas-${targetId}`, target, item };
+ break;
+ case 'show':
+ // 显示节点
+ graphG6.value.getNodes().forEach((node: any) => {
+ if (!node.isVisible()) {
+ graphG6.value.showItem(node);
+ graphG6.value.refreshItem(node);
+ }
+ });
+ // 显示边
+ graphG6.value.getEdges().forEach((edge: any) => {
+ if (!edge.isVisible()) {
+ graphG6.value.showItem(edge);
+ graphG6.value.refreshItem(edge);
+ }
+ });
+ // 显示分组
+ graphG6.value.getCombos().forEach((combo: any) => {
+ if (!combo.isVisible()) {
+ graphG6.value.showItem(combo);
+ graphG6.value.updateCombo(combo);
+ }
+ });
+ break;
+ }
+ },
+ });
+
+ /**图分组Combo 右击菜单 */
+ const graphComboMenu = new Menu({
+ offsetX: 6,
+ offseY: 10,
+ itemTypes: ['combo'],
+ getContent(evt) {
+ console.log(evt);
+ return `
+
+
+ 1. 编辑
+
+
+ 2. 隐藏
+
+
+ `;
+ },
+ handleMenuClick(target, item) {
+ console.log(target, item);
+ const targetId = target.id;
+ switch (targetId) {
+ case 'edit':
+ graphEvent.value = { type: `combo-${targetId}`, target, item };
+ break;
+ case 'hide':
+ graphG6.value.hideItem(item);
+ break;
+ }
+ },
+ });
+
+ /**图节点右击菜单 */
+ const graphNodeMenu = new Menu({
+ offsetX: 6,
+ offseY: 10,
+ itemTypes: ['node'],
+ getContent(evt) {
+ console.log(evt);
+ return `
+
+
+ 1. 编辑
+
+
+ 2. 隐藏
+
+
+ `;
+ },
+ handleMenuClick(target, item) {
+ console.log(target, item);
+ const targetId = target.id;
+ switch (targetId) {
+ case 'edit':
+ graphEvent.value = { type: `node-${targetId}`, target, item };
+ break;
+ case 'hide':
+ graphG6.value.hideItem(item);
+ break;
+ }
+ },
+ });
+
+ /**图节点展示 */
+ const graphNodeTooltip = new Tooltip({
+ offsetX: 10,
+ offsetY: 20,
+ getContent(e: any) {
+ const outDiv = document.createElement('div');
+ outDiv.style.width = '180px';
+ outDiv.innerHTML = `
+ 自定义tooltip
+
+ - Label: ${e.item.getModel().label || e.item.getModel().id}
+
`;
+ return outDiv;
+ },
+ itemTypes: ['node'],
+ });
+
+ /**图边右击菜单 */
+ const graphEdgeMenu = new Menu({
+ offsetX: 6,
+ offseY: 10,
+ itemTypes: ['edge'],
+ getContent(evt) {
+ console.log(evt);
+ return `
+
+
+ 1. 编辑
+
+
+ 2. 隐藏
+
+
+ `;
+ },
+ handleMenuClick(target, item) {
+ console.log(target, item);
+ const targetId = target.id;
+ switch (targetId) {
+ case 'edit':
+ graphEvent.value = { type: `edge-${targetId}`, target, item };
+ break;
+ case 'hide':
+ graphG6.value.hideItem(item);
+ break;
+ }
+ },
+ });
+
+ /**图边展示 */
+ const graphEdgeTooltip = new Tooltip({
+ offsetX: 10,
+ offsetY: 20,
+ getContent(e: any) {
+ const outDiv = document.createElement('div');
+ outDiv.style.width = '180px';
+ outDiv.innerHTML = `
+ graphEdgeTooltip
+
+ - Label: ${e.item.getModel().label || e.item.getModel().id}
+
`;
+ return outDiv;
+ },
+ itemTypes: ['edge'],
+ });
+
+ /**图绑定事件 */
+ function fnGraphEvent(graph: Graph) {
+ // 调用 graph.add / graph.addItem 方法之后触发
+ graph.on('afteradditem', evt => {
+ fnSelectSourceTargetOptionsData();
+ });
+
+ // 鼠标进入节点事件
+ graph.on('edge:mouseenter', (ev: any) => {
+ // 获得鼠标当前目标边
+ const edge = ev.item;
+ // 该边的起始点
+ const source = edge.getSource();
+ // 该边的结束点
+ const target = edge.getTarget();
+ // 先将边提前,再将端点提前。这样该边两个端点还是在该边上层,较符合常规。
+ // edge.toFront();
+ // source.toFront();
+ // target.toFront();
+ });
+
+ graph.on('edge:mouseleave', (ev: any) => {
+ // 获得图上所有边实例
+ const edges = graph.getEdges();
+ // 遍历边,将所有边的层级放置在后方,以恢复原样
+ // edges.forEach(edge => {
+ // edge.toBack();
+ // });
+ });
+
+ graph.on('node:mouseenter', evt => {
+ // 获得鼠标当前目标节点
+ const node = evt.item;
+ // 获取该节点的所有相关边
+ const edges = node && graph.getEdges();
+ // 遍历相关边,将所有相关边提前,再将相关边的两个端点提前,以保证相关边的端点在边的上方常规效果
+ // edges.forEach((edge: any) => {
+ // edge.toFront();
+ // edge.getSource().toFront();
+ // edge.getTarget().toFront();
+ // });
+ // graphEvent.value = {
+ // type: 'node:mouseenter',
+ // target: evt.target,
+ // item: evt.item,
+ // };
+ });
+
+ graph.on('node:mouseleave', (ev: any) => {
+ // 获得图上所有边实例
+ const edges = graph.getEdges();
+ // 遍历边,将所有边的层级放置在后方,以恢复原样
+ // edges.forEach(edge => {
+ // edge.toBack();
+ // });
+ });
+ }
+
+ /**图元素选择开始结束点 */
+ const selectSourceTargetOptions = ref[]>([]);
+
+ /**图元素选择嵌入分组 */
+ const selectComboOptions = ref[]>([]);
+
+ /**
+ * 图元素选择开始结束点数据获取
+ */
+ function fnSelectSourceTargetOptionsData() {
+ // 节点
+ selectSourceTargetOptions.value = [];
+ graphG6.value.getNodes().forEach((node: any) => {
+ const info = JSON.parse(JSON.stringify(node.getModel()));
+ selectSourceTargetOptions.value.push({
+ value: info.id,
+ label: info.label,
+ info,
+ });
+ });
+ // 分组
+ selectComboOptions.value = [
+ {
+ value: '',
+ label: '未分配',
+ },
+ ];
+ graphG6.value.getCombos().forEach((combo: any) => {
+ const info = JSON.parse(JSON.stringify(combo.getModel()));
+ const comboInfo = {
+ value: info.id,
+ label: info.label,
+ info,
+ };
+ selectSourceTargetOptions.value.push(comboInfo);
+ selectComboOptions.value.push(comboInfo);
+ });
+ }
+
+ /**图数据渲染 */
+ function handleRanderGraph(container: HTMLElement, data: GraphData) {
+ if (!container) return;
+ const { clientHeight, clientWidth } = container;
+
+ const graph = new Graph({
+ container: container,
+ width: clientWidth,
+ height: clientHeight,
+ animate: true,
+ fitCenter: true,
+ modes: {
+ default: [
+ {
+ type: 'click-select',
+ selectEdge: true,
+ },
+ 'drag-combo',
+ {
+ type: 'drag-node',
+ onlyChangeComboSize: true,
+ },
+ 'drag-canvas',
+ 'zoom-canvas',
+ 'collapse-expand-combo',
+ ],
+ edit: [
+ {
+ type: 'click-select',
+ selectEdge: true,
+ },
+ {
+ type: 'drag-node',
+ shouldEnd: (e: any) => {
+ return true;
+ },
+ },
+ { type: 'drag-combo' },
+ 'drag-canvas',
+ 'zoom-canvas',
+ { type: 'create-edge', key: 'alt' },
+ ],
+ },
+ groupByTypes: false,
+ // layout: {
+ // type: 'dagre',
+ // sortByCombo: false,
+ // ranksep: 10,
+ // nodesep: 10,
+ // },
+ // 全局节点
+ defaultNode: {
+ type: 'rect',
+ size: [80, 40],
+ style: {
+ radius: 8,
+ // fill: '#ffffff',
+ stroke: '#ffffff',
+ lineWidth: 1,
+ cursor: 'pointer',
+ },
+ labelCfg: {
+ position: 'center',
+ offset: 0,
+ style: {
+ fill: '#000000',
+ fontSize: 12,
+ fontWeight: 500,
+ },
+ },
+ icon: {
+ show: false,
+ img: '/svg/service.svg',
+ width: 25,
+ height: 25,
+ offset: 20, // triangle 特有
+ },
+ direction: 'up', // triangle 三角形的方向
+ },
+ // 全局边
+ defaultEdge: {
+ type: 'polyline',
+ style: {
+ offset: 20, // 拐弯处距离节点最小距离
+ radius: 2, // 拐弯处的圆角弧度,若不设置则为直角
+ stroke: '#ffffff',
+ lineWidth: 1,
+ cursor: 'pointer',
+ },
+ labelCfg: {
+ refX: 0,
+ refY: 0,
+ position: 'middle',
+ autoRotate: false,
+ style: {
+ fill: '#ffffff',
+ fontSize: 12,
+ fontWeight: 500,
+ },
+ },
+ },
+ // 全局分组节点
+ defaultCombo: {
+ type: 'rect', // Combo 类型
+ size: [40, 40],
+ padding: [30, 30, 30, 30],
+ style: {
+ radius: 2,
+ fill: '#ffffff',
+ stroke: '#ffffff',
+ lineWidth: 1,
+ cursor: 'grab',
+ fillOpacity: 0.5,
+ },
+ labelCfg: {
+ refX: 10,
+ refY: 10,
+ position: 'top',
+ style: {
+ fill: '#000000',
+ fontSize: 12,
+ fontWeight: 500,
+ },
+ },
+ },
+ plugins: [
+ graphCanvasMenu,
+ graphComboMenu,
+ graphNodeMenu,
+ graphNodeTooltip,
+ graphEdgeMenu,
+ graphEdgeTooltip,
+ ],
+ });
+ graph.data(data);
+ graph.render();
+
+ // 图绑定事件
+ fnGraphEvent(graph);
+
+ graphG6.value = graph;
+
+ // 图元素选择开始结束点数据
+ fnSelectSourceTargetOptionsData();
+
+ return graph;
+ }
+
+ /**图模式改变 default | edit */
+ function handleChangeMode(value: any) {
+ console.log(value, JSON.parse(JSON.stringify(graphG6.value.save())));
+ graphG6.value.setMode(value);
+ graphMode.value = graphG6.value.getCurrentMode();
+ }
+
+ return {
+ selectSourceTargetOptions,
+ selectComboOptions,
+ handleRanderGraph,
+ handleChangeMode,
+ };
}
diff --git a/src/views/monitor/topology-build/hooks/useNode.ts b/src/views/monitor/topology-build/hooks/useNode.ts
index eec4b07a..ff01e4b0 100644
--- a/src/views/monitor/topology-build/hooks/useNode.ts
+++ b/src/views/monitor/topology-build/hooks/useNode.ts
@@ -1,6 +1,7 @@
import { message, Form } from 'ant-design-vue/lib';
import { reactive, watch } from 'vue';
import { graphG6 } from './useGraph';
+import useI18n from '@/hooks/useI18n';
/**图节点内置边类型 */
export const nodeTypeOptions = [
@@ -85,204 +86,216 @@ export const nodeImageOptions = [
{ value: '/svg/service_db.svg', label: '数据服务器' },
];
-/**图节点信息状态类型 */
-type NodeStateType = {
- /**图节点原始数据 */
- origin: Record;
- /**图节点表单数据 */
- form: Record;
-};
+export default function useNode() {
+ const { t } = useI18n();
-/**图节点信息状态 */
-export let nodeState: NodeStateType = reactive({
- origin: {},
- form: {
- id: '',
- comboId: '',
- x: 0,
- y: 0,
- type: 'circle',
- size: 30,
- anchorPoints: false,
- style: {
- fill: '#ffffff',
- stroke: '#ffffff',
- lineWidth: 1,
- },
- label: '',
- labelCfg: {
- position: 'center',
- offset: 0,
+ /**图节点信息状态类型 */
+ type NodeStateType = {
+ /**图节点原始数据 */
+ origin: Record;
+ /**图节点表单数据 */
+ form: Record;
+ };
+
+ /**图节点信息状态 */
+ let nodeState: NodeStateType = reactive({
+ origin: {},
+ form: {
+ id: '',
+ comboId: '',
+ x: 0,
+ y: 0,
+ type: 'circle',
+ size: 30,
+ anchorPoints: false,
style: {
- fill: '#000000',
- fontSize: 12,
- fontWeight: 500,
+ fill: '#ffffff',
+ stroke: '#ffffff',
+ lineWidth: 1,
+ },
+ label: '',
+ labelCfg: {
+ position: 'center',
+ offset: 0,
+ style: {
+ fill: '#000000',
+ fontSize: 12,
+ fontWeight: 500,
+ },
},
},
- },
-});
+ });
-/**图节点对话框内表单属性和校验规则 */
-export const nodeStateForm = Form.useForm(
- nodeState.form,
- reactive({
- id: [{ required: true, message: '节点唯一 ID' }],
- type: [{ required: true, message: 'line' }],
- })
-);
+ /**图节点对话框内表单属性和校验规则 */
+ const nodeStateForm = Form.useForm(
+ nodeState.form,
+ reactive({
+ id: [{ required: true, message: '节点唯一 ID' }],
+ type: [{ required: true, message: 'line' }],
+ })
+ );
-/**图节点编辑监听更新视图 */
-watch(nodeState.form, node => {
- const info = JSON.parse(JSON.stringify(node));
- console.log(info);
- const nodeId = info.id;
- if (nodeId) {
- // 图片类型需要移除style属性,避免填充
- if (info.type === 'image') {
- Reflect.deleteProperty(info, 'style');
- }
- graphG6.value.clearItemStates(nodeId, 'selected');
- graphG6.value.updateItem(nodeId, info);
- // 三角和图片的样式变更需要重绘才生效
- if (
- info.type === 'triangle' ||
- info.type === 'image' ||
- info.comboId !== nodeState.origin.comboId
- ) {
- graphG6.value.read(graphG6.value.save());
- }
- }
-});
-
-/**图节点类型输入限制 */
-export function handleNodeTypeChange(type: any) {
- // 设置图标属性
- if (['circle', 'ellipse', 'diamond', 'star', 'donut'].includes(type)) {
- const origin = nodeState.origin;
- if (origin.icon) {
- nodeState.form = Object.assign(nodeState.form, {
- size: origin.size,
- icon: origin.icon,
- });
- } else {
- let size: number[] | number = [30];
- if (['circle', 'star', 'donut'].includes(type)) {
- size = 30;
+ /**图节点编辑监听更新视图 */
+ watch(nodeState.form, node => {
+ const info = JSON.parse(JSON.stringify(node));
+ console.log(info);
+ const nodeId = info.id;
+ if (nodeId) {
+ // 图片类型需要移除style属性,避免填充
+ if (info.type === 'image') {
+ Reflect.deleteProperty(info, 'style');
+ }
+ graphG6.value.clearItemStates(nodeId, 'selected');
+ graphG6.value.updateItem(nodeId, info);
+ // 三角和图片的样式变更需要重绘才生效
+ if (
+ info.type === 'triangle' ||
+ info.type === 'image' ||
+ info.comboId !== nodeState.origin.comboId
+ ) {
+ graphG6.value.read(graphG6.value.save());
}
- nodeState.form = Object.assign(nodeState.form, {
- size,
- icon: {
- show: false,
- img: '',
- width: 25,
- height: 25,
- },
- });
}
- } else if (type === 'triangle') {
- // 三角
- const origin = nodeState.origin;
- if (origin.icon) {
- nodeState.form = Object.assign(nodeState.form, {
- size: 40,
- direction: origin.direction || 'up', // triangle 三角形的方向
- icon: Object.assign({ offset: 20 }, origin.icon),
- });
- } else {
- nodeState.form = Object.assign(nodeState.form, {
- size: 30,
- direction: 'up', // triangle 三角形的方向
- icon: {
- show: false,
+ });
+
+ /**图节点类型输入限制 */
+ function handleNodeTypeChange(type: any) {
+ // 设置图标属性
+ if (['circle', 'ellipse', 'diamond', 'star', 'donut'].includes(type)) {
+ const origin = nodeState.origin;
+ if (origin.icon) {
+ nodeState.form = Object.assign(nodeState.form, {
+ size: origin.size,
+ icon: origin.icon,
+ });
+ } else {
+ let size: number[] | number = [30];
+ if (['circle', 'star', 'donut'].includes(type)) {
+ size = 30;
+ }
+ nodeState.form = Object.assign(nodeState.form, {
+ size,
+ icon: {
+ show: false,
+ img: '',
+ width: 25,
+ height: 25,
+ },
+ });
+ }
+ } else if (type === 'triangle') {
+ // 三角
+ const origin = nodeState.origin;
+ if (origin.icon) {
+ nodeState.form = Object.assign(nodeState.form, {
+ size: 40,
+ direction: origin.direction || 'up', // triangle 三角形的方向
+ icon: Object.assign({ offset: 20 }, origin.icon),
+ });
+ } else {
+ nodeState.form = Object.assign(nodeState.form, {
+ size: 30,
+ direction: 'up', // triangle 三角形的方向
+ icon: {
+ show: false,
+ img: '/svg/service.svg',
+ width: 25,
+ height: 25,
+ offset: 20, // triangle 特有
+ },
+ });
+ }
+ }
+ // 设置图片属性
+ if (type === 'image') {
+ const origin = nodeState.origin;
+ if (origin.img) {
+ nodeState.form = Object.assign(nodeState.form, {
+ size: [30, 30],
+ img: origin.img,
+ clipCfg: origin.clipCfg,
+ });
+ } else {
+ nodeState.form = Object.assign(nodeState.form, {
+ size: [30, 30],
img: '/svg/service.svg',
- width: 25,
- height: 25,
- offset: 20, // triangle 特有
- },
- });
- }
- }
- // 设置图片属性
- if (type === 'image') {
- const origin = nodeState.origin;
- if (origin.img) {
- nodeState.form = Object.assign(nodeState.form, {
- size: [30, 30],
- img: origin.img,
- clipCfg: origin.clipCfg,
- });
+ clipCfg: {
+ show: false,
+ width: 0,
+ height: 0,
+ type: 'circle',
+ },
+ });
+ }
+ Reflect.deleteProperty(nodeState.form, 'style');
} else {
- nodeState.form = Object.assign(nodeState.form, {
- size: [30, 30],
- img: '/svg/service.svg',
- clipCfg: {
- show: false,
- width: 0,
- height: 0,
- type: 'circle',
- },
- });
- }
- Reflect.deleteProperty(nodeState.form, 'style');
- } else {
- // 当切换非图片时补充style属性
- if (!Reflect.has(nodeState.form, 'style')) {
- nodeState.form = Object.assign(nodeState.form, {
- style: {
- fill: '#ffffff',
- stroke: '#ffffff',
- lineWidth: 1,
- },
- });
+ // 当切换非图片时补充style属性
+ if (!Reflect.has(nodeState.form, 'style')) {
+ nodeState.form = Object.assign(nodeState.form, {
+ style: {
+ fill: '#ffffff',
+ stroke: '#ffffff',
+ lineWidth: 1,
+ },
+ });
+ }
}
}
-}
-/**图节点新增或更新 */
-export function handleOkNode() {
- const node = JSON.parse(JSON.stringify(nodeState.form));
- if (!node.id) {
- message.warn({
- content: `节点元素ID错误`,
- duration: 2,
- });
- return false;
- }
- // graphG6.value.removeItem(node.id);
- // graphG6.value.addItem('node', node);
- const item = graphG6.value.findById(node.id);
- if (item) {
- graphG6.value.updateItem(item, node);
- } else {
- graphG6.value.addItem('node', node);
- }
- // 三角和图片的样式变更需要重绘才生效
- if (
- node.type === 'triangle' ||
- node.type === 'image' ||
- node.comboId !== nodeState.origin.comboId
- ) {
- graphG6.value.read(graphG6.value.save());
- }
- nodeStateForm.resetFields();
- nodeState.origin = {};
- return true;
-}
-
-/**图节点取消还原 */
-export function handleCancelNode() {
- const origin = JSON.parse(JSON.stringify(nodeState.origin));
- if (origin.id) {
- graphG6.value.updateItem(origin.id, origin);
+ /**图节点新增或更新 */
+ function handleOkNode() {
+ const node = JSON.parse(JSON.stringify(nodeState.form));
+ if (!node.id) {
+ message.warn({
+ content: `节点元素ID错误`,
+ duration: 2,
+ });
+ return false;
+ }
+ // graphG6.value.removeItem(node.id);
+ // graphG6.value.addItem('node', node);
+ const item = graphG6.value.findById(node.id);
+ if (item) {
+ graphG6.value.updateItem(item, node);
+ } else {
+ graphG6.value.addItem('node', node);
+ }
// 三角和图片的样式变更需要重绘才生效
if (
- origin.type === 'triangle' ||
- origin.type === 'image' ||
- origin.comboId !== nodeState.form.comboId
+ node.type === 'triangle' ||
+ node.type === 'image' ||
+ node.comboId !== nodeState.origin.comboId
) {
graphG6.value.read(graphG6.value.save());
}
nodeStateForm.resetFields();
nodeState.origin = {};
+ return true;
}
+
+ /**图节点取消还原 */
+ function handleCancelNode() {
+ const origin = JSON.parse(JSON.stringify(nodeState.origin));
+ if (origin.id) {
+ graphG6.value.updateItem(origin.id, origin);
+ // 三角和图片的样式变更需要重绘才生效
+ if (
+ origin.type === 'triangle' ||
+ origin.type === 'image' ||
+ origin.comboId !== nodeState.form.comboId
+ ) {
+ graphG6.value.read(graphG6.value.save());
+ }
+ nodeStateForm.resetFields();
+ nodeState.origin = {};
+ }
+ }
+
+ return {
+ nodeState,
+ nodeStateForm,
+ handleNodeTypeChange,
+ handleOkNode,
+ handleCancelNode,
+ };
}
diff --git a/src/views/monitor/topology-build/index.vue b/src/views/monitor/topology-build/index.vue
index aedb9834..38417af0 100644
--- a/src/views/monitor/topology-build/index.vue
+++ b/src/views/monitor/topology-build/index.vue
@@ -2,88 +2,18 @@
import { reactive, onMounted, ref, watch } from 'vue';
import { PageContainer } from 'antdv-pro-layout';
import useI18n from '@/hooks/useI18n';
-import {
- handleRanderGraph,
- graphEvent,
+import GraphEditModal from './components/GraphEditModal.vue';
+import useGraph, {
graphG6,
- selectSourceTargetOptions,
- selectComboOptions,
graphMode,
graphModeOptions,
- handleChangeMode,
-} from './hooks/useGraph';
-import {
- edgeTypeOptions,
- edgePositionOptions,
- handleOkEdge,
- handleCancelEdge,
- edgeState,
- edgeStateForm,
-} from './hooks/useEdge';
-import {
- nodeTypeOptions,
- nodePositionOptions,
- nodeDirectionOptions,
- nodeImageClipCfgOptions,
- nodeImageOptions,
- handleNodeTypeChange,
- handleOkNode,
- handleCancelNode,
- nodeState,
- nodeStateForm,
-} from './hooks/useNode';
-import {
- comboState,
- comboStateForm,
- comboTypeOptions,
- comboPositionOptions,
- handleComboTypeChange,
- handleOkcombo,
- handleCancelcombo,
-} from './hooks/useCombo';
-
+} from './/hooks/useGraph';
const { t } = useI18n();
+const { handleRanderGraph, handleChangeMode } = useGraph();
/**图DOM节点实例对象 */
const graphG6Dom = ref(undefined);
-/**图监听事件变更 */
-watch(graphEvent, v => {
- if (!v) return;
- const { type, target, item } = v;
- console.log(type, target, item);
-
- // 边
- if (type === 'edge-edit' && item) {
- const edge = item.getModel();
- edgeState.origin = JSON.parse(JSON.stringify(edge));
- edgeState.form = Object.assign(edgeState.form, edge);
- modalState.title = '边信息编辑';
- modalState.formType = 'edge';
- modalState.visible = true;
- }
- // 节点
- if (type === 'node-edit' && item) {
- const node = item.getModel();
- console.log(node.comboId);
- nodeState.origin = JSON.parse(JSON.stringify(node));
- nodeState.form = Object.assign(nodeState.form, node);
- modalState.title = '节点信息编辑';
- modalState.formType = 'node';
- modalState.visible = true;
- }
- // 分组
- if (type === 'combo-edit' && item) {
- const combo = item.getModel();
- console.log(JSON.parse(JSON.stringify(combo)));
- comboState.origin = JSON.parse(JSON.stringify(combo));
- comboState.form = Object.assign(comboState.form, combo);
- modalState.title = '框信息编辑';
- modalState.formType = 'combo';
- modalState.visible = true;
- }
-});
-
/**图数据 */
const graphG6Data = reactive>({
nodes: [
@@ -2746,72 +2676,6 @@ onMounted(() => {
fnRanderGraph(graphG6Data);
});
-/**对话框对象信息状态类型 */
-type ModalStateType = {
- /**对话框是否显示 */
- visible: boolean;
- /**标题 */
- title: string;
- /**图元素表单类型 */
- formType: 'edge' | 'node' | 'combo';
- /**确定按钮 loading */
- confirmLoading: boolean;
-};
-
-/**对话框对象信息状态 */
-let modalState: ModalStateType = reactive({
- visible: false,
- title: '图信息',
- formType: 'edge',
- confirmLoading: false,
-});
-
-/**
- * 对话框弹出确认执行函数
- * 进行表达规则校验
- */
-function fnModalOk() {
- modalState.confirmLoading = true;
- const type = modalState.formType;
- let result = false;
- // 边编辑确认
- if (type === 'edge') {
- result = handleOkEdge();
- }
- // 节点编辑确认
- if (type === 'node') {
- result = handleOkNode();
- }
- // 分租编辑确认
- if (type === 'combo') {
- result = handleOkcombo();
- }
- console.log(type, result);
- modalState.visible = !result;
- modalState.confirmLoading = !result;
-}
-
-/**
- * 对话框弹出关闭执行函数
- * 进行表达规则校验
- */
-function fnModalCancel() {
- modalState.visible = false;
- const type = modalState.formType;
- // 边编辑还原
- if (type === 'edge') {
- handleCancelEdge();
- }
- // 节点编辑还原
- if (type === 'node') {
- handleCancelNode();
- }
- // 分租编辑还原
- if (type === 'combo') {
- handleCancelcombo();
- }
-}
-
/**保存图数据 */
function fnGraphSave() {
sessionStorage.setItem('graph', JSON.stringify(graphG6.value.save()));
@@ -2880,986 +2744,7 @@ function fnGraphLoad() {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 标签文本及其配置
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 标签文本及其配置
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 图片
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 图标
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 标签文本及其配置
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+