diff --git a/package.json b/package.json
index cf44b03..d7b4967 100644
--- a/package.json
+++ b/package.json
@@ -22,6 +22,9 @@
"dependencies": {
"@element-plus/icons-vue": "2.3.2",
"@highlightjs/vue-plugin": "2.1.2",
+ "@vue-flow/background": "^1.3.2",
+ "@vue-flow/core": "^1.43.1",
+ "@vue-flow/node-resizer": "^1.4.0",
"@vueup/vue-quill": "1.2.0",
"@vueuse/core": "14.2.1",
"animate.css": "4.1.1",
@@ -38,6 +41,7 @@
"nprogress": "0.2.0",
"pinia": "3.0.4",
"screenfull": "6.0.2",
+ "uuid": "^13.0.0",
"vue": "3.5.30",
"vue-cropper": "1.1.4",
"vue-i18n": "11.3.0",
diff --git a/src/main.ts b/src/main.ts
index 16ac610..a0d62bb 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -3,6 +3,9 @@ import { createApp } from 'vue';
import 'virtual:uno.css';
import 'element-plus/theme-chalk/dark/css-vars.css';
import '@/assets/styles/index.scss';
+import '@vue-flow/core/dist/style.css';
+import '@vue-flow/core/dist/theme-default.css';
+import '@vue-flow/node-resizer/dist/style.css';
// App、router、store
import App from './App.vue';
diff --git a/src/permission.ts b/src/permission.ts
index fb60b07..fa40865 100644
--- a/src/permission.ts
+++ b/src/permission.ts
@@ -11,7 +11,7 @@ import { usePermissionStore } from '@/store/modules/permission';
import { ElMessage } from 'element-plus/es';
NProgress.configure({ showSpinner: false });
-const whiteList = ['/login', '/register', '/social-callback', '/register*', '/register/*'];
+const whiteList = ['/login', '/register', '/social-callback', '/register*', '/register/*', '/visualEditor'];
const isWhiteList = (path: string) => {
return whiteList.some((pattern) => isPathMatch(pattern, path));
diff --git a/src/router/index.ts b/src/router/index.ts
index a6497db..8438e11 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -26,6 +26,11 @@ import Layout from '@/layout/index.vue';
// 公共路由
export const constantRoutes: RouteRecordRaw[] = [
+ {
+ path: '/visualEditor',
+ hidden: true,
+ component: () => import('@/views/visualEditor/index.vue')
+ },
{
path: '/redirect',
component: Layout,
diff --git a/src/views/visualEditor/index.vue b/src/views/visualEditor/index.vue
new file mode 100644
index 0000000..cd007ab
--- /dev/null
+++ b/src/views/visualEditor/index.vue
@@ -0,0 +1,144 @@
+
+
+
+
+
+
+
+
+ 线
+
+
+
+
+
+ 元件1
+
+
+
+
+
+ 元件2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/visualEditor/nodes/circuitComponent.vue b/src/views/visualEditor/nodes/circuitComponent.vue
new file mode 100644
index 0000000..5f9c1ac
--- /dev/null
+++ b/src/views/visualEditor/nodes/circuitComponent.vue
@@ -0,0 +1,73 @@
+
+
+
+
+
diff --git a/src/views/visualEditor/nodes/line.vue b/src/views/visualEditor/nodes/line.vue
new file mode 100644
index 0000000..a1bd4b7
--- /dev/null
+++ b/src/views/visualEditor/nodes/line.vue
@@ -0,0 +1,72 @@
+
+
+
+
+
diff --git a/src/views/visualEditor/tool.js b/src/views/visualEditor/tool.js
new file mode 100644
index 0000000..c025b7f
--- /dev/null
+++ b/src/views/visualEditor/tool.js
@@ -0,0 +1,87 @@
+import { useVueFlow } from '@vue-flow/core';
+import { ref, watch } from 'vue';
+import { v4 as uuidv4 } from 'uuid';
+
+const getId = (type) => {
+ return `${type}_${uuidv4().replaceAll('-', '_')}`;
+};
+
+const getOption = (e) => {
+ if (e === 'circuitComponent') {
+ return {
+ title: ''
+ };
+ }
+};
+const getNodeSize = (e) => {
+ if (e === 'circuitComponent') {
+ return { width: 50, height: 50 };
+ } else if (e === 'line') {
+ return { width: 100, height: 20 };
+ }
+};
+const nameEnum = {};
+const tool = () => {
+ const nodeType = ref('');
+ const customData = ref({ type: 1 });
+ const { addNodes, screenToFlowCoordinate, onNodesInitialized, updateNode } = useVueFlow({ id: 'flowA' });
+ const onDragStart = (event, type, data) => {
+ if (event.dataTransfer) {
+ event.dataTransfer.setData('application/vueflow', type);
+ event.dataTransfer.effectAllowed = 'move';
+ }
+
+ nodeType.value = type;
+ customData.value = data || { type: 1 };
+ document.addEventListener('drop', onDragEnd);
+ };
+ const onDragEnd = () => {
+ nodeType.value = null;
+ document.removeEventListener('drop', onDragEnd);
+ };
+ const onDrop = (event) => {
+ const dimensions = getNodeSize(nodeType.value);
+
+ const position = screenToFlowCoordinate({
+ x: event.clientX,
+ y: event.clientY
+ });
+
+ const nodeId = getId(nodeType.value);
+ const newNode = {
+ id: nodeId,
+ name: nameEnum[nodeType.value],
+ draggable: true,
+ type: nodeType.value,
+ dimensions,
+ position,
+ data: { options: getOption(nodeType.value), outputData: {}, customData: customData.value }
+ };
+
+ const { off } = onNodesInitialized(() => {
+ updateNode(nodeId, (node) => ({
+ position: { x: node.position.x - node.dimensions.width / 2, y: node.position.y - node.dimensions.height / 2 }
+ }));
+
+ off();
+ });
+
+ addNodes(newNode);
+ };
+ const onDragOver = (event) => {
+ event.preventDefault();
+
+ if (nodeType.value) {
+ if (event.dataTransfer) {
+ event.dataTransfer.dropEffect = 'move';
+ }
+ }
+ };
+ return {
+ onDragStart,
+ onDragEnd,
+ onDrop,
+ onDragOver
+ };
+};
+export default tool;