Showing
19 changed files
with
678 additions
and
0 deletions
.eslintrc-auto-import.json
0 → 100644
| 1 | +{ | ||
| 2 | + "globals": { | ||
| 3 | + "Component": true, | ||
| 4 | + "ComponentPublicInstance": true, | ||
| 5 | + "ComputedRef": true, | ||
| 6 | + "DirectiveBinding": true, | ||
| 7 | + "EffectScope": true, | ||
| 8 | + "ExtractDefaultPropTypes": true, | ||
| 9 | + "ExtractPropTypes": true, | ||
| 10 | + "ExtractPublicPropTypes": true, | ||
| 11 | + "InjectionKey": true, | ||
| 12 | + "MaybeRef": true, | ||
| 13 | + "MaybeRefOrGetter": true, | ||
| 14 | + "PropType": true, | ||
| 15 | + "Ref": true, | ||
| 16 | + "VNode": true, | ||
| 17 | + "WritableComputedRef": true, | ||
| 18 | + "computed": true, | ||
| 19 | + "createApp": true, | ||
| 20 | + "customRef": true, | ||
| 21 | + "defineAsyncComponent": true, | ||
| 22 | + "defineComponent": true, | ||
| 23 | + "effectScope": true, | ||
| 24 | + "getCurrentInstance": true, | ||
| 25 | + "getCurrentScope": true, | ||
| 26 | + "h": true, | ||
| 27 | + "inject": true, | ||
| 28 | + "isProxy": true, | ||
| 29 | + "isReactive": true, | ||
| 30 | + "isReadonly": true, | ||
| 31 | + "isRef": true, | ||
| 32 | + "markRaw": true, | ||
| 33 | + "nextTick": true, | ||
| 34 | + "onActivated": true, | ||
| 35 | + "onBeforeMount": true, | ||
| 36 | + "onBeforeRouteLeave": true, | ||
| 37 | + "onBeforeRouteUpdate": true, | ||
| 38 | + "onBeforeUnmount": true, | ||
| 39 | + "onBeforeUpdate": true, | ||
| 40 | + "onDeactivated": true, | ||
| 41 | + "onErrorCaptured": true, | ||
| 42 | + "onMounted": true, | ||
| 43 | + "onRenderTracked": true, | ||
| 44 | + "onRenderTriggered": true, | ||
| 45 | + "onScopeDispose": true, | ||
| 46 | + "onServerPrefetch": true, | ||
| 47 | + "onUnmounted": true, | ||
| 48 | + "onUpdated": true, | ||
| 49 | + "onWatcherCleanup": true, | ||
| 50 | + "provide": true, | ||
| 51 | + "reactive": true, | ||
| 52 | + "readonly": true, | ||
| 53 | + "ref": true, | ||
| 54 | + "resolveComponent": true, | ||
| 55 | + "shallowReactive": true, | ||
| 56 | + "shallowReadonly": true, | ||
| 57 | + "shallowRef": true, | ||
| 58 | + "toRaw": true, | ||
| 59 | + "toRef": true, | ||
| 60 | + "toRefs": true, | ||
| 61 | + "toValue": true, | ||
| 62 | + "triggerRef": true, | ||
| 63 | + "unref": true, | ||
| 64 | + "useAttrs": true, | ||
| 65 | + "useCssModule": true, | ||
| 66 | + "useCssVars": true, | ||
| 67 | + "useId": true, | ||
| 68 | + "useLink": true, | ||
| 69 | + "useModel": true, | ||
| 70 | + "useRoute": true, | ||
| 71 | + "useRouter": true, | ||
| 72 | + "useSlots": true, | ||
| 73 | + "useTemplateRef": true, | ||
| 74 | + "watch": true, | ||
| 75 | + "watchEffect": true, | ||
| 76 | + "watchPostEffect": true, | ||
| 77 | + "watchSyncEffect": true | ||
| 78 | + } | ||
| 79 | +} |
.gitignore
0 → 100644
| 1 | +# Logs | ||
| 2 | +logs | ||
| 3 | +*.log | ||
| 4 | +npm-debug.log* | ||
| 5 | +yarn-debug.log* | ||
| 6 | +yarn-error.log* | ||
| 7 | +pnpm-debug.log* | ||
| 8 | +lerna-debug.log* | ||
| 9 | + | ||
| 10 | +node_modules | ||
| 11 | +dist | ||
| 12 | +dist-ssr | ||
| 13 | +*.local | ||
| 14 | + | ||
| 15 | +# Editor directories and files | ||
| 16 | +.vscode/* | ||
| 17 | +!.vscode/extensions.json | ||
| 18 | +.idea | ||
| 19 | +.DS_Store | ||
| 20 | +*.suo | ||
| 21 | +*.ntvs* | ||
| 22 | +*.njsproj | ||
| 23 | +*.sln | ||
| 24 | +*.sw? | ||
| 25 | + | ||
| 26 | +.history |
.vscode/extensions.json
0 → 100644
index.html
0 → 100644
| 1 | +<!doctype html> | ||
| 2 | +<html lang="en"> | ||
| 3 | + <head> | ||
| 4 | + <meta charset="UTF-8" /> | ||
| 5 | + <link rel="icon" type="image/svg+xml" href="/vite.svg" /> | ||
| 6 | + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
| 7 | + <title>Vite + Vue</title> | ||
| 8 | + </head> | ||
| 9 | + <body> | ||
| 10 | + <div id="app"></div> | ||
| 11 | + <script type="module" src="/src/main.js"></script> | ||
| 12 | + </body> | ||
| 13 | +</html> |
package-lock.json
0 → 100644
This diff is collapsed. Click to expand it.
package.json
0 → 100644
| 1 | +{ | ||
| 2 | + "name": "logic-flow2", | ||
| 3 | + "private": true, | ||
| 4 | + "version": "0.0.0", | ||
| 5 | + "type": "module", | ||
| 6 | + "scripts": { | ||
| 7 | + "dev": "vite", | ||
| 8 | + "build": "vite build", | ||
| 9 | + "preview": "vite preview" | ||
| 10 | + }, | ||
| 11 | + "dependencies": { | ||
| 12 | + "@element-plus/icons-vue": "^2.3.1", | ||
| 13 | + "@logicflow/core": "^2.0.11", | ||
| 14 | + "@logicflow/engine": "^0.1.1", | ||
| 15 | + "@logicflow/extension": "^2.0.15", | ||
| 16 | + "@logicflow/vue-node-registry": "^1.0.13", | ||
| 17 | + "autoprefixer": "^10.4.21", | ||
| 18 | + "echarts": "^5.6.0", | ||
| 19 | + "element-plus": "^2.9.6", | ||
| 20 | + "postcss": "^8.5.3", | ||
| 21 | + "tailwindcss": "^4.0.12", | ||
| 22 | + "vue": "^3.5.13", | ||
| 23 | + "vue-router": "^4.5.0" | ||
| 24 | + }, | ||
| 25 | + "devDependencies": { | ||
| 26 | + "@vitejs/plugin-vue": "^5.2.1", | ||
| 27 | + "sass-embedded": "^1.85.1", | ||
| 28 | + "unplugin-auto-import": "^19.1.1", | ||
| 29 | + "vite": "^6.2.0", | ||
| 30 | + "vite-plugin-dynamic-import": "^1.6.0" | ||
| 31 | + } | ||
| 32 | +} |
public/vite.svg
0 → 100644
| 1 | +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg> | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
src/App.vue
0 → 100644
| 1 | +<!-- | ||
| 2 | + * @Date: 2025-03-10 13:07:05 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2025-03-10 14:40:31 | ||
| 5 | + * @FilePath: /logic-flow2/src/App.vue | ||
| 6 | + * @Description: 文件描述 | ||
| 7 | +--> | ||
| 8 | +<script setup> | ||
| 9 | + | ||
| 10 | +</script> | ||
| 11 | + | ||
| 12 | +<template> | ||
| 13 | + <router-view></router-view> | ||
| 14 | +</template> | ||
| 15 | + | ||
| 16 | +<style scoped> | ||
| 17 | + | ||
| 18 | +</style> |
src/auto-imports.d.ts
0 → 100644
| 1 | +/* eslint-disable */ | ||
| 2 | +/* prettier-ignore */ | ||
| 3 | +// @ts-nocheck | ||
| 4 | +// noinspection JSUnusedGlobalSymbols | ||
| 5 | +// Generated by unplugin-auto-import | ||
| 6 | +// biome-ignore lint: disable | ||
| 7 | +export {} | ||
| 8 | +declare global { | ||
| 9 | + const EffectScope: typeof import('vue')['EffectScope'] | ||
| 10 | + const computed: typeof import('vue')['computed'] | ||
| 11 | + const createApp: typeof import('vue')['createApp'] | ||
| 12 | + const customRef: typeof import('vue')['customRef'] | ||
| 13 | + const defineAsyncComponent: typeof import('vue')['defineAsyncComponent'] | ||
| 14 | + const defineComponent: typeof import('vue')['defineComponent'] | ||
| 15 | + const effectScope: typeof import('vue')['effectScope'] | ||
| 16 | + const getCurrentInstance: typeof import('vue')['getCurrentInstance'] | ||
| 17 | + const getCurrentScope: typeof import('vue')['getCurrentScope'] | ||
| 18 | + const h: typeof import('vue')['h'] | ||
| 19 | + const inject: typeof import('vue')['inject'] | ||
| 20 | + const isProxy: typeof import('vue')['isProxy'] | ||
| 21 | + const isReactive: typeof import('vue')['isReactive'] | ||
| 22 | + const isReadonly: typeof import('vue')['isReadonly'] | ||
| 23 | + const isRef: typeof import('vue')['isRef'] | ||
| 24 | + const markRaw: typeof import('vue')['markRaw'] | ||
| 25 | + const nextTick: typeof import('vue')['nextTick'] | ||
| 26 | + const onActivated: typeof import('vue')['onActivated'] | ||
| 27 | + const onBeforeMount: typeof import('vue')['onBeforeMount'] | ||
| 28 | + const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave'] | ||
| 29 | + const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate'] | ||
| 30 | + const onBeforeUnmount: typeof import('vue')['onBeforeUnmount'] | ||
| 31 | + const onBeforeUpdate: typeof import('vue')['onBeforeUpdate'] | ||
| 32 | + const onDeactivated: typeof import('vue')['onDeactivated'] | ||
| 33 | + const onErrorCaptured: typeof import('vue')['onErrorCaptured'] | ||
| 34 | + const onMounted: typeof import('vue')['onMounted'] | ||
| 35 | + const onRenderTracked: typeof import('vue')['onRenderTracked'] | ||
| 36 | + const onRenderTriggered: typeof import('vue')['onRenderTriggered'] | ||
| 37 | + const onScopeDispose: typeof import('vue')['onScopeDispose'] | ||
| 38 | + const onServerPrefetch: typeof import('vue')['onServerPrefetch'] | ||
| 39 | + const onUnmounted: typeof import('vue')['onUnmounted'] | ||
| 40 | + const onUpdated: typeof import('vue')['onUpdated'] | ||
| 41 | + const onWatcherCleanup: typeof import('vue')['onWatcherCleanup'] | ||
| 42 | + const provide: typeof import('vue')['provide'] | ||
| 43 | + const reactive: typeof import('vue')['reactive'] | ||
| 44 | + const readonly: typeof import('vue')['readonly'] | ||
| 45 | + const ref: typeof import('vue')['ref'] | ||
| 46 | + const resolveComponent: typeof import('vue')['resolveComponent'] | ||
| 47 | + const shallowReactive: typeof import('vue')['shallowReactive'] | ||
| 48 | + const shallowReadonly: typeof import('vue')['shallowReadonly'] | ||
| 49 | + const shallowRef: typeof import('vue')['shallowRef'] | ||
| 50 | + const toRaw: typeof import('vue')['toRaw'] | ||
| 51 | + const toRef: typeof import('vue')['toRef'] | ||
| 52 | + const toRefs: typeof import('vue')['toRefs'] | ||
| 53 | + const toValue: typeof import('vue')['toValue'] | ||
| 54 | + const triggerRef: typeof import('vue')['triggerRef'] | ||
| 55 | + const unref: typeof import('vue')['unref'] | ||
| 56 | + const useAttrs: typeof import('vue')['useAttrs'] | ||
| 57 | + const useCssModule: typeof import('vue')['useCssModule'] | ||
| 58 | + const useCssVars: typeof import('vue')['useCssVars'] | ||
| 59 | + const useId: typeof import('vue')['useId'] | ||
| 60 | + const useLink: typeof import('vue-router')['useLink'] | ||
| 61 | + const useModel: typeof import('vue')['useModel'] | ||
| 62 | + const useRoute: typeof import('vue-router')['useRoute'] | ||
| 63 | + const useRouter: typeof import('vue-router')['useRouter'] | ||
| 64 | + const useSlots: typeof import('vue')['useSlots'] | ||
| 65 | + const useTemplateRef: typeof import('vue')['useTemplateRef'] | ||
| 66 | + const watch: typeof import('vue')['watch'] | ||
| 67 | + const watchEffect: typeof import('vue')['watchEffect'] | ||
| 68 | + const watchPostEffect: typeof import('vue')['watchPostEffect'] | ||
| 69 | + const watchSyncEffect: typeof import('vue')['watchSyncEffect'] | ||
| 70 | +} | ||
| 71 | +// for type re-export | ||
| 72 | +declare global { | ||
| 73 | + // @ts-ignore | ||
| 74 | + export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue' | ||
| 75 | + import('vue') | ||
| 76 | +} | ||
| 77 | + | ||
| 78 | +// for vue template auto import | ||
| 79 | +import { UnwrapRef } from 'vue' | ||
| 80 | +declare module 'vue' { | ||
| 81 | + interface GlobalComponents {} | ||
| 82 | + interface ComponentCustomProperties { | ||
| 83 | + readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']> | ||
| 84 | + readonly computed: UnwrapRef<typeof import('vue')['computed']> | ||
| 85 | + readonly createApp: UnwrapRef<typeof import('vue')['createApp']> | ||
| 86 | + readonly customRef: UnwrapRef<typeof import('vue')['customRef']> | ||
| 87 | + readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']> | ||
| 88 | + readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']> | ||
| 89 | + readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']> | ||
| 90 | + readonly getCurrentInstance: UnwrapRef<typeof import('vue')['getCurrentInstance']> | ||
| 91 | + readonly getCurrentScope: UnwrapRef<typeof import('vue')['getCurrentScope']> | ||
| 92 | + readonly h: UnwrapRef<typeof import('vue')['h']> | ||
| 93 | + readonly inject: UnwrapRef<typeof import('vue')['inject']> | ||
| 94 | + readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']> | ||
| 95 | + readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']> | ||
| 96 | + readonly isReadonly: UnwrapRef<typeof import('vue')['isReadonly']> | ||
| 97 | + readonly isRef: UnwrapRef<typeof import('vue')['isRef']> | ||
| 98 | + readonly markRaw: UnwrapRef<typeof import('vue')['markRaw']> | ||
| 99 | + readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']> | ||
| 100 | + readonly onActivated: UnwrapRef<typeof import('vue')['onActivated']> | ||
| 101 | + readonly onBeforeMount: UnwrapRef<typeof import('vue')['onBeforeMount']> | ||
| 102 | + readonly onBeforeRouteLeave: UnwrapRef<typeof import('vue-router')['onBeforeRouteLeave']> | ||
| 103 | + readonly onBeforeRouteUpdate: UnwrapRef<typeof import('vue-router')['onBeforeRouteUpdate']> | ||
| 104 | + readonly onBeforeUnmount: UnwrapRef<typeof import('vue')['onBeforeUnmount']> | ||
| 105 | + readonly onBeforeUpdate: UnwrapRef<typeof import('vue')['onBeforeUpdate']> | ||
| 106 | + readonly onDeactivated: UnwrapRef<typeof import('vue')['onDeactivated']> | ||
| 107 | + readonly onErrorCaptured: UnwrapRef<typeof import('vue')['onErrorCaptured']> | ||
| 108 | + readonly onMounted: UnwrapRef<typeof import('vue')['onMounted']> | ||
| 109 | + readonly onRenderTracked: UnwrapRef<typeof import('vue')['onRenderTracked']> | ||
| 110 | + readonly onRenderTriggered: UnwrapRef<typeof import('vue')['onRenderTriggered']> | ||
| 111 | + readonly onScopeDispose: UnwrapRef<typeof import('vue')['onScopeDispose']> | ||
| 112 | + readonly onServerPrefetch: UnwrapRef<typeof import('vue')['onServerPrefetch']> | ||
| 113 | + readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']> | ||
| 114 | + readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']> | ||
| 115 | + readonly onWatcherCleanup: UnwrapRef<typeof import('vue')['onWatcherCleanup']> | ||
| 116 | + readonly provide: UnwrapRef<typeof import('vue')['provide']> | ||
| 117 | + readonly reactive: UnwrapRef<typeof import('vue')['reactive']> | ||
| 118 | + readonly readonly: UnwrapRef<typeof import('vue')['readonly']> | ||
| 119 | + readonly ref: UnwrapRef<typeof import('vue')['ref']> | ||
| 120 | + readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']> | ||
| 121 | + readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']> | ||
| 122 | + readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']> | ||
| 123 | + readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']> | ||
| 124 | + readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']> | ||
| 125 | + readonly toRef: UnwrapRef<typeof import('vue')['toRef']> | ||
| 126 | + readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']> | ||
| 127 | + readonly toValue: UnwrapRef<typeof import('vue')['toValue']> | ||
| 128 | + readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']> | ||
| 129 | + readonly unref: UnwrapRef<typeof import('vue')['unref']> | ||
| 130 | + readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']> | ||
| 131 | + readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']> | ||
| 132 | + readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']> | ||
| 133 | + readonly useId: UnwrapRef<typeof import('vue')['useId']> | ||
| 134 | + readonly useLink: UnwrapRef<typeof import('vue-router')['useLink']> | ||
| 135 | + readonly useModel: UnwrapRef<typeof import('vue')['useModel']> | ||
| 136 | + readonly useRoute: UnwrapRef<typeof import('vue-router')['useRoute']> | ||
| 137 | + readonly useRouter: UnwrapRef<typeof import('vue-router')['useRouter']> | ||
| 138 | + readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']> | ||
| 139 | + readonly useTemplateRef: UnwrapRef<typeof import('vue')['useTemplateRef']> | ||
| 140 | + readonly watch: UnwrapRef<typeof import('vue')['watch']> | ||
| 141 | + readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']> | ||
| 142 | + readonly watchPostEffect: UnwrapRef<typeof import('vue')['watchPostEffect']> | ||
| 143 | + readonly watchSyncEffect: UnwrapRef<typeof import('vue')['watchSyncEffect']> | ||
| 144 | + } | ||
| 145 | +} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
src/components/logicflow/custom-node.js
0 → 100644
| 1 | +/* | ||
| 2 | + * @Date: 2025-03-10 16:20:35 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2025-03-10 16:33:34 | ||
| 5 | + * @FilePath: /logic-flow2/src/components/logicflow/custom-node.ts | ||
| 6 | + * @Description: 文件描述 | ||
| 7 | + */ | ||
| 8 | +// src/components/logicflow/CustomNode.ts | ||
| 9 | +import { RectNode, RectNodeModel } from "@logicflow/core"; | ||
| 10 | + | ||
| 11 | +// 自定义模型 | ||
| 12 | +export class CustomModel extends RectNodeModel { | ||
| 13 | + setAttributes() { | ||
| 14 | + this.stroke = "#1E90FF"; | ||
| 15 | + this.fill = "#F0F8FF"; | ||
| 16 | + this.radius = 10; | ||
| 17 | + const { isDisabledNode } = this.properties; | ||
| 18 | + | ||
| 19 | + // 动态菜单配置 | ||
| 20 | + if (!isDisabledNode) { | ||
| 21 | + this.menu = [ | ||
| 22 | + { | ||
| 23 | + className: "lf-menu-delete", | ||
| 24 | + icon: true, | ||
| 25 | + callback: (node) => { | ||
| 26 | + this.graphModel.deleteNode(node.id); | ||
| 27 | + this.graphModel.eventCenter.emit("custom:event", node); | ||
| 28 | + }, | ||
| 29 | + }, | ||
| 30 | + { | ||
| 31 | + text: "Edit", | ||
| 32 | + className: "lf-menu-item", | ||
| 33 | + callback: (node) => { | ||
| 34 | + this.graphModel.setElementStateById(node.id, 2); | ||
| 35 | + }, | ||
| 36 | + }, | ||
| 37 | + { | ||
| 38 | + text: "Copy", | ||
| 39 | + className: "lf-menu-item", | ||
| 40 | + callback: (node) => { | ||
| 41 | + this.graphModel.cloneNode(node.id); | ||
| 42 | + }, | ||
| 43 | + }, | ||
| 44 | + ]; | ||
| 45 | + } | ||
| 46 | + } | ||
| 47 | +} | ||
| 48 | + | ||
| 49 | +// 使用默认矩形视图 | ||
| 50 | +export const CustomNode = RectNode; |
src/main.js
0 → 100644
| 1 | +/* | ||
| 2 | + * @Date: 2025-03-10 13:07:05 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2025-03-10 15:50:42 | ||
| 5 | + * @FilePath: /logic-flow2/src/main.js | ||
| 6 | + * @Description: 文件描述 | ||
| 7 | + */ | ||
| 8 | +import { createApp } from 'vue' | ||
| 9 | +import './style.css' | ||
| 10 | +import App from './App.vue' | ||
| 11 | +import router from './router' | ||
| 12 | +import "@logicflow/core/lib/style/index.css"; | ||
| 13 | +import '@logicflow/extension/lib/style/index.css' | ||
| 14 | +import ElementPlus from 'element-plus' | ||
| 15 | +import 'element-plus/dist/index.css' | ||
| 16 | + | ||
| 17 | +import LogicFlow from '@logicflow/core'; | ||
| 18 | +import { Menu } from "@logicflow/extension"; | ||
| 19 | +LogicFlow.use(Menu) // 右键菜单 | ||
| 20 | + | ||
| 21 | +const app = createApp(App) | ||
| 22 | +app.use(ElementPlus) | ||
| 23 | +app.use(router) | ||
| 24 | +app.mount('#app') |
src/router/index.js
0 → 100644
| 1 | +/* | ||
| 2 | + * @Date: 2025-03-10 13:15:30 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2025-03-10 15:49:17 | ||
| 5 | + * @FilePath: /logic-flow2/src/router/index.js | ||
| 6 | + * @Description: 文件描述 | ||
| 7 | + */ | ||
| 8 | +import { createRouter, createWebHistory } from 'vue-router' | ||
| 9 | + | ||
| 10 | +const router = createRouter({ | ||
| 11 | + history: createWebHistory(), | ||
| 12 | + routes: [ | ||
| 13 | + { | ||
| 14 | + path: '/', | ||
| 15 | + name: 'home', | ||
| 16 | + component: () => import('../views/Home.vue') | ||
| 17 | + }, | ||
| 18 | + { | ||
| 19 | + path: '/menu', | ||
| 20 | + name: 'menu', | ||
| 21 | + component: () => import('../views/menu.vue') | ||
| 22 | + }, | ||
| 23 | + ] | ||
| 24 | +}) | ||
| 25 | + | ||
| 26 | +// 全局前置守卫 | ||
| 27 | +router.beforeEach((to, from, next) => { | ||
| 28 | + // 这里可以添加路由导航守卫的逻辑 | ||
| 29 | + next() | ||
| 30 | +}) | ||
| 31 | + | ||
| 32 | +export default router |
src/style.css
0 → 100644
File mode changed
src/utils/math.ts
0 → 100644
| 1 | +/** | ||
| 2 | + * 获取随机整数 [min, max],不包含 [excludemMin, excludeMax] | ||
| 3 | + * @param min | ||
| 4 | + * @param max | ||
| 5 | + * @returns | ||
| 6 | + */ | ||
| 7 | +export const getRandom = (min: number, max: number, excludemMin?: number, excludeMax?: number) => { | ||
| 8 | + let res = Math.floor(Math.random() * (max - min + 1) + min) | ||
| 9 | + | ||
| 10 | + if ( | ||
| 11 | + excludemMin !== undefined && | ||
| 12 | + excludeMax !== undefined && | ||
| 13 | + res >= excludemMin && | ||
| 14 | + res <= excludeMax | ||
| 15 | + ) { | ||
| 16 | + res = getRandom(min, max, excludemMin, excludeMax) | ||
| 17 | + } | ||
| 18 | + | ||
| 19 | + return res | ||
| 20 | +} |
src/utils/performance.ts
0 → 100644
| 1 | +/** | ||
| 2 | + * 获取页面 dom 数量 | ||
| 3 | + * @returns | ||
| 4 | + */ | ||
| 5 | +export const getTotalDOMNumber = () => document.querySelectorAll('*').length | ||
| 6 | + | ||
| 7 | +export type PerformanceLongTaskEntry = { | ||
| 8 | + type: 'longTask' | ||
| 9 | + eventType: string | ||
| 10 | + startTime: number | ||
| 11 | + duration: number | ||
| 12 | +} | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * 监控长任务事件响应时间:耗费了 50 毫秒或更多时间 | ||
| 16 | + */ | ||
| 17 | +export const startObservingLongTasks = (callback: any) => { | ||
| 18 | + const observer = new PerformanceObserver((entryList) => { | ||
| 19 | + const entries = entryList.getEntries() | ||
| 20 | + entries.forEach((entry) => { | ||
| 21 | + requestIdleCallback(() => { | ||
| 22 | + callback(entry) | ||
| 23 | + }) | ||
| 24 | + }) | ||
| 25 | + }) | ||
| 26 | + observer.observe({ entryTypes: ['longtask'] }) | ||
| 27 | +} |
src/views/home.vue
0 → 100644
| 1 | +<!-- | ||
| 2 | + * @Date: 2025-03-10 14:37:31 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2025-03-10 15:47:42 | ||
| 5 | + * @FilePath: /logic-flow2/src/views/Home.vue | ||
| 6 | + * @Description: 文件描述 | ||
| 7 | +--> | ||
| 8 | +<template> | ||
| 9 | + <div>插件</div> | ||
| 10 | + <el-button type="primary" @click="goTo('menu')">Menu</el-button> | ||
| 11 | +</template> | ||
| 12 | + | ||
| 13 | +<script setup> | ||
| 14 | +import { useRouter } from 'vue-router' | ||
| 15 | + | ||
| 16 | +const router = useRouter() | ||
| 17 | + | ||
| 18 | +const goTo = (name) => { | ||
| 19 | + router.push({ name }) | ||
| 20 | +} | ||
| 21 | +</script> | ||
| 22 | + | ||
| 23 | +<style scoped> | ||
| 24 | +</style> |
src/views/menu.vue
0 → 100644
| 1 | +<!-- | ||
| 2 | + * @Date: 2025-03-10 14:37:31 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2025-03-10 16:38:24 | ||
| 5 | + * @FilePath: /logic-flow2/src/views/menu.vue | ||
| 6 | + * @Description: 文件描述 | ||
| 7 | +--> | ||
| 8 | +<template> | ||
| 9 | + <div class="container"> | ||
| 10 | + <div ref="container" class="flow-container"></div> | ||
| 11 | + </div> | ||
| 12 | +</template> | ||
| 13 | + | ||
| 14 | +<script setup> | ||
| 15 | +import LogicFlow from '@logicflow/core'; | ||
| 16 | +import { CustomNode, CustomModel } from '@components/logicflow/custom-node.js'; // 指定业务状态设置菜单 | ||
| 17 | + | ||
| 18 | +const container = ref(null); | ||
| 19 | +let lf = null; | ||
| 20 | + | ||
| 21 | +onMounted(() => { | ||
| 22 | + lf = new LogicFlow({ | ||
| 23 | + container: container.value, | ||
| 24 | + grid: true, | ||
| 25 | + }); | ||
| 26 | + | ||
| 27 | + // 为菜单追加选项(必须在 lf.render() 之前设置) | ||
| 28 | + // 或者直接通过 lf.addMenuConfig 也可以调用 | ||
| 29 | + lf.extension.menu.addMenuConfig({ | ||
| 30 | + nodeMenu: [ | ||
| 31 | + { | ||
| 32 | + text: '分享', | ||
| 33 | + callback() { | ||
| 34 | + alert('分享成功!') | ||
| 35 | + }, | ||
| 36 | + }, | ||
| 37 | + { | ||
| 38 | + text: '属性', | ||
| 39 | + callback(node) { | ||
| 40 | + alert(` | ||
| 41 | + 节点id:${node.id} | ||
| 42 | + 节点类型:${node.type} | ||
| 43 | + 节点坐标:(x: ${node.x}, y: ${node.y}) | ||
| 44 | + `) | ||
| 45 | + }, | ||
| 46 | + }, | ||
| 47 | + ], | ||
| 48 | + edgeMenu: [ | ||
| 49 | + { | ||
| 50 | + text: '属性', | ||
| 51 | + callback(edge) { | ||
| 52 | + const { | ||
| 53 | + id, | ||
| 54 | + type, | ||
| 55 | + startPoint, | ||
| 56 | + endPoint, | ||
| 57 | + sourceNodeId, | ||
| 58 | + targetNodeId, | ||
| 59 | + } = edge | ||
| 60 | + alert(` | ||
| 61 | + 边id:${id} | ||
| 62 | + 边类型:${type} | ||
| 63 | + 边起点坐标:(startPoint: [${startPoint.x}, ${startPoint.y}]) | ||
| 64 | + 边终点坐标:(endPoint: [${endPoint.x}, ${endPoint.y}]) | ||
| 65 | + 源节点id:${sourceNodeId} | ||
| 66 | + 目标节点id:${targetNodeId} | ||
| 67 | + `) | ||
| 68 | + }, | ||
| 69 | + }, | ||
| 70 | + ], | ||
| 71 | + graphMenu: [ | ||
| 72 | + { | ||
| 73 | + text: '分享', | ||
| 74 | + callback() { | ||
| 75 | + alert('分享成功!') | ||
| 76 | + }, | ||
| 77 | + }, | ||
| 78 | + ], | ||
| 79 | + }) | ||
| 80 | + // 如果默认菜单中存在不需要的选项,或者无法满足需求,可以通过lf.setMenuConfig重置菜单,更换为自定义菜单。 | ||
| 81 | + lf.extension.menu.setMenuConfig({ | ||
| 82 | + nodeMenu: [ | ||
| 83 | + { | ||
| 84 | + text: "删除", | ||
| 85 | + callback(node) { | ||
| 86 | + lf.deleteNode(node.id); | ||
| 87 | + }, | ||
| 88 | + }, | ||
| 89 | + ], // 覆盖默认的节点右键菜单 | ||
| 90 | + edgeMenu: false, // 删除默认的边右键菜单 | ||
| 91 | + graphMenu: [], // 覆盖默认的边右键菜单,与false表现一样 | ||
| 92 | + }); | ||
| 93 | + | ||
| 94 | + // 注册自定义节点 | ||
| 95 | + lf.register({ | ||
| 96 | + type: "custom_node", | ||
| 97 | + view: CustomNode, | ||
| 98 | + model: CustomModel, | ||
| 99 | + }); | ||
| 100 | + | ||
| 101 | + // 监听自定义事件 | ||
| 102 | + lf.on('custom:event', (nodeData) => { | ||
| 103 | + console.log('Node deleted:', nodeData); | ||
| 104 | + // 这里可以添加业务逻辑 | ||
| 105 | + }); | ||
| 106 | + | ||
| 107 | + lf.render({ | ||
| 108 | + nodes: [ | ||
| 109 | + { id: 'node1', type: 'rect', x: 100, y: 100 }, | ||
| 110 | + { id: 'node2', type: 'circle', x: 300, y: 100 }, | ||
| 111 | + { | ||
| 112 | + id: 'node3', | ||
| 113 | + type: 'custom_node', | ||
| 114 | + x: 500, | ||
| 115 | + y: 100, | ||
| 116 | + properties: { | ||
| 117 | + isDisabledNode: false | ||
| 118 | + } | ||
| 119 | + } | ||
| 120 | + ], | ||
| 121 | + edges: [{ id: 'edge1', sourceNodeId: 'node1', targetNodeId: 'node2' }], | ||
| 122 | + }); | ||
| 123 | +}); | ||
| 124 | +</script> | ||
| 125 | + | ||
| 126 | +<style scoped> | ||
| 127 | +.container { | ||
| 128 | + width: 100vw; | ||
| 129 | + height: 100vh; | ||
| 130 | + display: flex; | ||
| 131 | + flex-direction: column; | ||
| 132 | +} | ||
| 133 | + | ||
| 134 | +.flow-container { | ||
| 135 | + flex: 1; | ||
| 136 | + width: 100%; | ||
| 137 | + height: 100%; | ||
| 138 | +} | ||
| 139 | + | ||
| 140 | +/* 自定义菜单样式 */ | ||
| 141 | +.lf-menu-item { | ||
| 142 | + padding: 8px; | ||
| 143 | + cursor: pointer; | ||
| 144 | + &:hover { | ||
| 145 | + background: #f0f8ff; | ||
| 146 | + } | ||
| 147 | +} | ||
| 148 | +</style> |
vite.config.js
0 → 100644
| 1 | +/* | ||
| 2 | + * @Date: 2025-03-10 13:07:05 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2025-03-10 16:49:02 | ||
| 5 | + * @FilePath: /logic-flow2/vite.config.js | ||
| 6 | + * @Description: 文件描述 | ||
| 7 | + */ | ||
| 8 | +import { defineConfig } from 'vite' | ||
| 9 | +import vue from '@vitejs/plugin-vue' | ||
| 10 | +import AutoImport from 'unplugin-auto-import/vite' | ||
| 11 | +import dynamicImport from 'vite-plugin-dynamic-import'; | ||
| 12 | + | ||
| 13 | +import path from 'path'; | ||
| 14 | + | ||
| 15 | +// https://vite.dev/config/ | ||
| 16 | +export default defineConfig({ | ||
| 17 | + plugins: [ | ||
| 18 | + vue(), | ||
| 19 | + dynamicImport(), // 增强 Vite 内置的 dynamic import, 支持在 import() 中使用别名 | ||
| 20 | + AutoImport({ | ||
| 21 | + imports: ['vue', 'vue-router'], | ||
| 22 | + dts: 'src/auto-imports.d.ts', | ||
| 23 | + dirs: ['src/composables', 'src/stores'], | ||
| 24 | + vueTemplate: true, | ||
| 25 | + eslintrc: { | ||
| 26 | + enabled: true, | ||
| 27 | + }, | ||
| 28 | + }), | ||
| 29 | + ], | ||
| 30 | + resolve: { | ||
| 31 | + alias: { | ||
| 32 | + '@': '/src', | ||
| 33 | + '@components': path.resolve(__dirname, 'src/components'), | ||
| 34 | + }, | ||
| 35 | + }, | ||
| 36 | +}) |
yarn.lock
0 → 100644
This diff is collapsed. Click to expand it.
-
Please register or login to post a comment