重构工作流绘制
This commit is contained in:
262
package-lock.json
generated
262
package-lock.json
generated
@@ -14,6 +14,10 @@
|
||||
"@element-plus/icons-vue": "^2.3.1",
|
||||
"@logicflow/core": "^2.2.1",
|
||||
"@logicflow/extension": "^2.2.1",
|
||||
"@vue-flow/background": "^1.3.2",
|
||||
"@vue-flow/controls": "^1.1.3",
|
||||
"@vue-flow/core": "^1.48.2",
|
||||
"@vue-flow/minimap": "^1.5.4",
|
||||
"@wangeditor/editor": "^5.1.23",
|
||||
"axios": "1.8.2",
|
||||
"codemirror": "^6.0.1",
|
||||
@@ -923,6 +927,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@interactjs/core/-/core-1.10.27.tgz",
|
||||
"integrity": "sha512-SliUr/3ZbLAdED8LokzYzWHWMdCB5Cq+UnpXuRy+BIod1j97m4IUFf/D1iIKUBBjBcucgXbz28z96WnenVCB7Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"@interactjs/utils": "1.10.27"
|
||||
}
|
||||
@@ -993,6 +998,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@interactjs/modifiers/-/modifiers-1.10.27.tgz",
|
||||
"integrity": "sha512-ei/qfoQ+9/8k6WzNzdNqHI6cWkIV576N4Ap16r5CoqOWwhA6Xzj3OMHf1g0t1O4eSq2HdJsVJn3eLNfw9HsbeQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@interactjs/snappers": "1.10.27"
|
||||
},
|
||||
@@ -1059,7 +1065,8 @@
|
||||
"version": "1.10.27",
|
||||
"resolved": "https://registry.npmjs.org/@interactjs/utils/-/utils-1.10.27.tgz",
|
||||
"integrity": "sha512-+qfLOio2OxQqg1cXSnRaCl+N8MQDQLDS9w+aOGxH8YLAhIMyt7Asxx/46//sT8orgsi16pmlBPtngPHT9s8zKw==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@intlify/core-base": {
|
||||
"version": "11.1.2",
|
||||
@@ -1151,6 +1158,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@logicflow/core/-/core-2.2.1.tgz",
|
||||
"integrity": "sha512-VzLPrCrT4eXnOLjoGQ5v4GUSay3+6rd3YNZD0qOJw4vME5e4WjQ5fd+hKK2zlIzgdRI4D54dXiEFJrS6xdV6yQ==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"classnames": "^2.3.2",
|
||||
"lodash-es": "^4.17.21",
|
||||
@@ -1904,6 +1912,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz",
|
||||
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/lodash": "*"
|
||||
}
|
||||
@@ -1914,6 +1923,7 @@
|
||||
"integrity": "sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
@@ -1985,6 +1995,7 @@
|
||||
"integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "7.18.0",
|
||||
"@typescript-eslint/types": "7.18.0",
|
||||
@@ -2160,6 +2171,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@uppy/core/-/core-2.3.4.tgz",
|
||||
"integrity": "sha512-iWAqppC8FD8mMVqewavCz+TNaet6HPXitmGXpGGREGrakZ4FeuWytVdrelydzTdXx6vVKkOmI2FLztGg73sENQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@transloadit/prettier-bytes": "0.0.7",
|
||||
"@uppy/store-default": "^2.1.1",
|
||||
@@ -2191,6 +2203,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@uppy/xhr-upload/-/xhr-upload-2.1.3.tgz",
|
||||
"integrity": "sha512-YWOQ6myBVPs+mhNjfdWsQyMRWUlrDLMoaG7nvf/G6Y3GKZf8AyjFDjvvJ49XWQ+DaZOftGkHmF1uh/DBeGivJQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@uppy/companion-client": "^2.2.2",
|
||||
"@uppy/utils": "^4.1.2",
|
||||
@@ -2243,6 +2256,99 @@
|
||||
"vscode-uri": "^3.0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue-flow/background": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@vue-flow/background/-/background-1.3.2.tgz",
|
||||
"integrity": "sha512-eJPhDcLj1wEo45bBoqTXw1uhl0yK2RaQGnEINqvvBsAFKh/camHJd5NPmOdS1w+M9lggc9igUewxaEd3iCQX2w==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@vue-flow/core": "^1.23.0",
|
||||
"vue": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue-flow/controls": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@vue-flow/controls/-/controls-1.1.3.tgz",
|
||||
"integrity": "sha512-XCf+G+jCvaWURdFlZmOjifZGw3XMhN5hHlfMGkWh9xot+9nH9gdTZtn+ldIJKtarg3B21iyHU8JjKDhYcB6JMw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@vue-flow/core": "^1.23.0",
|
||||
"vue": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue-flow/core": {
|
||||
"version": "1.48.2",
|
||||
"resolved": "https://registry.npmjs.org/@vue-flow/core/-/core-1.48.2.tgz",
|
||||
"integrity": "sha512-raxhgKWE+G/mcEvXJjGFUDYW9rAI3GOtiHR3ZkNpwBWuIaCC1EYiBmKGwJOoNzVFgwO7COgErnK7i08i287AFA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vueuse/core": "^10.5.0",
|
||||
"d3-drag": "^3.0.0",
|
||||
"d3-interpolate": "^3.0.1",
|
||||
"d3-selection": "^3.0.0",
|
||||
"d3-zoom": "^3.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue-flow/core/node_modules/@types/web-bluetooth": {
|
||||
"version": "0.0.20",
|
||||
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz",
|
||||
"integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@vue-flow/core/node_modules/@vueuse/core": {
|
||||
"version": "10.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.11.1.tgz",
|
||||
"integrity": "sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/web-bluetooth": "^0.0.20",
|
||||
"@vueuse/metadata": "10.11.1",
|
||||
"@vueuse/shared": "10.11.1",
|
||||
"vue-demi": ">=0.14.8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue-flow/core/node_modules/@vueuse/metadata": {
|
||||
"version": "10.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.11.1.tgz",
|
||||
"integrity": "sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue-flow/core/node_modules/@vueuse/shared": {
|
||||
"version": "10.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.11.1.tgz",
|
||||
"integrity": "sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"vue-demi": ">=0.14.8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue-flow/minimap": {
|
||||
"version": "1.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue-flow/minimap/-/minimap-1.5.4.tgz",
|
||||
"integrity": "sha512-l4C+XTAXnRxsRpUdN7cAVFBennC1sVRzq4bDSpVK+ag7tdMczAnhFYGgbLkUw3v3sY6gokyWwMl8CDonp8eB2g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"d3-selection": "^3.0.0",
|
||||
"d3-zoom": "^3.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@vue-flow/core": "^1.23.0",
|
||||
"vue": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-core": {
|
||||
"version": "3.5.25",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.25.tgz",
|
||||
@@ -2419,6 +2525,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@wangeditor/basic-modules/-/basic-modules-1.1.7.tgz",
|
||||
"integrity": "sha512-cY9CPkLJaqF05STqfpZKWG4LpxTMeGSIIF1fHvfm/mz+JXatCagjdkbxdikOuKYlxDdeqvOeBmsUBItufDLXZg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"is-url": "^1.2.4"
|
||||
},
|
||||
@@ -2451,6 +2558,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@wangeditor/core/-/core-1.1.19.tgz",
|
||||
"integrity": "sha512-KevkB47+7GhVszyYF2pKGKtCSj/YzmClsD03C3zTt+9SR2XWT5T0e3yQqg8baZpcMvkjs1D8Dv4fk8ok/UaS2Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/event-emitter": "^0.3.3",
|
||||
"event-emitter": "^0.3.5",
|
||||
@@ -2569,6 +2677,7 @@
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -2824,6 +2933,7 @@
|
||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.2.tgz",
|
||||
"integrity": "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@codemirror/autocomplete": "^6.0.0",
|
||||
"@codemirror/commands": "^6.0.0",
|
||||
@@ -2950,6 +3060,112 @@
|
||||
"node": ">=0.12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-color": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
|
||||
"integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-dispatch": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
|
||||
"integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-drag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz",
|
||||
"integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"d3-dispatch": "1 - 3",
|
||||
"d3-selection": "3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-ease": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
|
||||
"integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-interpolate": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
|
||||
"integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"d3-color": "1 - 3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-selection": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
|
||||
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
|
||||
"license": "ISC",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-timer": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
|
||||
"integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-transition": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz",
|
||||
"integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"d3-color": "1 - 3",
|
||||
"d3-dispatch": "1 - 3",
|
||||
"d3-ease": "1 - 3",
|
||||
"d3-interpolate": "1 - 3",
|
||||
"d3-timer": "1 - 3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"d3-selection": "2 - 3"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-zoom": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz",
|
||||
"integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"d3-dispatch": "1 - 3",
|
||||
"d3-drag": "2 - 3",
|
||||
"d3-interpolate": "1 - 3",
|
||||
"d3-selection": "2 - 3",
|
||||
"d3-transition": "2 - 3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/dayjs": {
|
||||
"version": "1.11.19",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz",
|
||||
@@ -3041,6 +3257,7 @@
|
||||
"resolved": "https://registry.npmjs.org/dom7/-/dom7-3.0.0.tgz",
|
||||
"integrity": "sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"ssr-window": "^3.0.0-alpha.1"
|
||||
}
|
||||
@@ -3077,6 +3294,7 @@
|
||||
"resolved": "https://registry.npmjs.org/echarts/-/echarts-5.6.0.tgz",
|
||||
"integrity": "sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tslib": "2.3.0",
|
||||
"zrender": "5.6.1"
|
||||
@@ -3305,6 +3523,7 @@
|
||||
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.6.1",
|
||||
@@ -4097,7 +4316,8 @@
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/is-hotkey/-/is-hotkey-0.2.0.tgz",
|
||||
"integrity": "sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/is-number": {
|
||||
"version": "7.0.0",
|
||||
@@ -4284,13 +4504,15 @@
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/lodash-es": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
|
||||
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/lodash-unified": {
|
||||
"version": "1.0.3",
|
||||
@@ -4307,32 +4529,37 @@
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
|
||||
"integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/lodash.clonedeep": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
|
||||
"integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/lodash.debounce": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
|
||||
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/lodash.foreach": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz",
|
||||
"integrity": "sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/lodash.isequal": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||
"integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==",
|
||||
"deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/lodash.merge": {
|
||||
"version": "4.6.2",
|
||||
@@ -4345,13 +4572,15 @@
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
|
||||
"integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/lodash.toarray": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz",
|
||||
"integrity": "sha512-QyffEA3i5dma5q2490+SgCvDN0pXLmRGSyAANuVi0HQ01Pkfr9fuoKQW8wm1wGBnJITs/mS7wQvS6VshUEBFCw==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.30.21",
|
||||
@@ -4464,6 +4693,7 @@
|
||||
"resolved": "https://registry.npmjs.org/mobx/-/mobx-5.15.7.tgz",
|
||||
"integrity": "sha512-wyM3FghTkhmC+hQjyPGGFdpehrcX1KOXsDuERhfK2YbJemkUhEB+6wzEN639T21onxlfYBmriA1PFnvxTUhcKw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mobx"
|
||||
@@ -4528,6 +4758,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
@@ -4814,6 +5045,7 @@
|
||||
"resolved": "https://registry.npmjs.org/preact/-/preact-10.27.2.tgz",
|
||||
"integrity": "sha512-5SYSgFKSyhCbk6SrXyMpqjb5+MQBgfvEKE/OC+PujcY34sOpqtr+0AZQtPYx5IA6VxynQ7rUPCtKzyovpj9Bpg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/preact"
|
||||
@@ -5074,6 +5306,7 @@
|
||||
"integrity": "sha512-N+7WK20/wOr7CzA2snJcUSSNTCzeCGUTFY3OgeQP3mZ1aj9NMQ0mSTXwlrnd89j33zzQJGqIN52GIOmYrfq46A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"chokidar": "^4.0.0",
|
||||
"immutable": "^5.0.2",
|
||||
@@ -5292,6 +5525,7 @@
|
||||
"resolved": "https://registry.npmjs.org/slate/-/slate-0.72.8.tgz",
|
||||
"integrity": "sha512-/nJwTswQgnRurpK+bGJFH1oM7naD5qDmHd89JyiKNT2oOKD8marW0QSBtuFnwEbL5aGCS8AmrhXQgNOsn4osAw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"immer": "^9.0.6",
|
||||
"is-plain-object": "^5.0.0",
|
||||
@@ -5315,6 +5549,7 @@
|
||||
"resolved": "https://registry.npmjs.org/snabbdom/-/snabbdom-3.6.3.tgz",
|
||||
"integrity": "sha512-W2lHLLw2qR2Vv0DcMmcxXqcfdBaIcoN+y/86SmHv8fn4DazEQSH6KN3TjZcWvwujW56OHiiirsbHWZb4vx/0fg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12.17.0"
|
||||
}
|
||||
@@ -5480,6 +5715,7 @@
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -5557,6 +5793,7 @@
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"devOptional": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -5626,6 +5863,7 @@
|
||||
"integrity": "sha512-BiReIiMS2fyFqbqNT/Qqt4CVITDU9M9vE+DKcVAsB+ZV0wvTKd+3hMbkpxz1b+NmEDMegpVbisKiAZOnvO92Sw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"fdir": "^6.4.4",
|
||||
@@ -5794,6 +6032,7 @@
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -5813,6 +6052,7 @@
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.25.tgz",
|
||||
"integrity": "sha512-YLVdgv2K13WJ6n+kD5owehKtEXwdwXuj2TTyJMsO7pSeKw2bfRNZGjhB7YzrpbMYj5b5QsUebHpOqR3R3ziy/g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.5.25",
|
||||
"@vue/compiler-sfc": "3.5.25",
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
"@element-plus/icons-vue": "^2.3.1",
|
||||
"@logicflow/core": "^2.2.1",
|
||||
"@logicflow/extension": "^2.2.1",
|
||||
"@vue-flow/background": "^1.3.2",
|
||||
"@vue-flow/controls": "^1.1.3",
|
||||
"@vue-flow/core": "^1.48.2",
|
||||
"@vue-flow/minimap": "^1.5.4",
|
||||
"@wangeditor/editor": "^5.1.23",
|
||||
"axios": "1.8.2",
|
||||
"codemirror": "^6.0.1",
|
||||
|
||||
@@ -3856,15 +3856,11 @@ const deleteSelectedElement = async () => {
|
||||
if (affectedNodeNames.length > 0) {
|
||||
const previewNames = affectedNodeNames.slice(0, 8);
|
||||
const overflowText = affectedNodeNames.length > 8 ? `\n...等 ${affectedNodeNames.length} 个节点` : '';
|
||||
await ElMessageBox.confirm(
|
||||
`删除该节点将清理以下下级节点中的引用:\n${previewNames.join('、')}${overflowText}`,
|
||||
'删除确认',
|
||||
{
|
||||
confirmButtonText: '继续删除',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}
|
||||
);
|
||||
await ElMessageBox.confirm(`删除该节点将清理以下下级节点中的引用:\n${previewNames.join('、')}${overflowText}`, '删除确认', {
|
||||
confirmButtonText: '继续删除',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
});
|
||||
}
|
||||
|
||||
affectedCount = cleanupReferencesToNode(cur.id);
|
||||
@@ -3878,7 +3874,7 @@ const deleteSelectedElement = async () => {
|
||||
if (error === 'cancel') return;
|
||||
ElMessage.error('删除失败');
|
||||
}
|
||||
};// 从后端 DSL 恢复工作流
|
||||
}; // 从后端 DSL 恢复工作流
|
||||
const loadWorkflowFromDsl = (dsl: any) => {
|
||||
const lf = logicFlowInstance.value;
|
||||
if (!lf || !dsl) return;
|
||||
@@ -5626,7 +5622,3 @@ onBeforeUnmount(() => {
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
279
src/views/settings/workflow/component/InputSourceManager.vue
Normal file
279
src/views/settings/workflow/component/InputSourceManager.vue
Normal file
@@ -0,0 +1,279 @@
|
||||
<template>
|
||||
<div class="input-source-manager">
|
||||
<el-divider content-position="left">上级参数引用</el-divider>
|
||||
|
||||
<!-- 已引用的参数列表 -->
|
||||
<div v-if="currentInputSource && currentInputSource.length > 0" class="input-source-list">
|
||||
<div v-for="(sourceNode, index) in currentInputSource" :key="index" class="input-source-item">
|
||||
<div class="input-source-header">
|
||||
<span class="input-source-node-name">{{ getNodeName(sourceNode.nodeId) }}</span>
|
||||
</div>
|
||||
<div v-if="sourceNode.field && sourceNode.field.length > 0" class="input-source-fields">
|
||||
<div v-for="fieldName in sourceNode.field" :key="fieldName" class="field-tag">
|
||||
<el-tag size="small">{{ fieldName }}</el-tag>
|
||||
<el-button type="danger" link size="small" @click="emit('removeField', sourceNode.nodeId, fieldName)">删除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-source-output">
|
||||
<el-switch
|
||||
:model-value="sourceNode.quoteOutput === true"
|
||||
@change="(val: boolean) => emit('toggleOutput', sourceNode.nodeId, val)"
|
||||
size="small"
|
||||
active-text="引入输出"
|
||||
inactive-text=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 显示所有上级节点的输出引用选项 -->
|
||||
<div v-if="availableParentNodes.length > 0" class="parent-nodes-output">
|
||||
<div class="parent-nodes-title">上级节点输出</div>
|
||||
<div v-for="parentNode in availableParentNodes" :key="parentNode.id" class="parent-node-output-item">
|
||||
<span class="parent-node-name">{{ parentNode.name }}</span>
|
||||
<el-switch
|
||||
:model-value="isNodeOutputQuoted(parentNode.id)"
|
||||
@change="(val: boolean) => emit('toggleOutput', parentNode.id, val)"
|
||||
size="small"
|
||||
active-text="引入输出"
|
||||
inactive-text=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 选择参数下拉框 -->
|
||||
<el-form-item label="选择参数">
|
||||
<el-select :model-value="selectedParam" @update:model-value="handleParamSelect" placeholder="选择上级节点的参数" class="w100">
|
||||
<el-option v-for="param in availableParams" :key="param.value" :label="param.label" :value="param.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue';
|
||||
import type { Node } from '@vue-flow/core';
|
||||
|
||||
interface NodeData {
|
||||
label: string;
|
||||
nodeCode: string;
|
||||
inputSource: Array<{ nodeId: string; field: string[]; quoteOutput?: boolean }> | null;
|
||||
formConfig?: any[];
|
||||
modelConfig?: any;
|
||||
skillName?: string;
|
||||
}
|
||||
|
||||
interface ParentNode {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface ParamOption {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
selectedNode: Node<NodeData> | null;
|
||||
nodes: Node<NodeData>[];
|
||||
edges: any[];
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'removeField', nodeId: string, fieldName: string): void;
|
||||
(e: 'toggleOutput', nodeId: string, enabled: boolean): void;
|
||||
(e: 'addParam', paramValue: string): void;
|
||||
}>();
|
||||
|
||||
const selectedParam = ref('');
|
||||
|
||||
// 当前节点的 inputSource
|
||||
const currentInputSource = computed(() => {
|
||||
if (!props.selectedNode?.data.inputSource) return [];
|
||||
return props.selectedNode.data.inputSource.filter((item) => item.field && item.field.length > 0);
|
||||
});
|
||||
|
||||
// 获取节点名称
|
||||
const getNodeName = (nodeId: string) => {
|
||||
const node = props.nodes.find((n) => n.id === nodeId);
|
||||
return node?.data.label || nodeId;
|
||||
};
|
||||
|
||||
// 获取所有上级节点(用于显示输出引用选项)
|
||||
const availableParentNodes = computed(() => {
|
||||
if (!props.selectedNode) return [];
|
||||
|
||||
// 获取已经引用了字段的节点ID列表
|
||||
const inputSource = props.selectedNode.data.inputSource;
|
||||
const nodesWithFields = new Set<string>();
|
||||
if (Array.isArray(inputSource)) {
|
||||
inputSource.forEach((item) => {
|
||||
if (item.field && item.field.length > 0) {
|
||||
nodesWithFields.add(item.nodeId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 递归查找所有上级节点
|
||||
const findAllParentNodes = (nodeId: string, visited = new Set<string>()): string[] => {
|
||||
if (visited.has(nodeId)) return [];
|
||||
visited.add(nodeId);
|
||||
|
||||
const incomingEdges = props.edges.filter((e) => e.target === nodeId);
|
||||
const parentIds: string[] = [];
|
||||
|
||||
incomingEdges.forEach((edge) => {
|
||||
parentIds.push(edge.source);
|
||||
parentIds.push(...findAllParentNodes(edge.source, visited));
|
||||
});
|
||||
|
||||
return parentIds;
|
||||
};
|
||||
|
||||
const allParentIds = findAllParentNodes(props.selectedNode.id);
|
||||
const parentNodes = allParentIds
|
||||
.map((parentId) => {
|
||||
const parentNode = props.nodes.find((n) => n.id === parentId);
|
||||
if (!parentNode) return null;
|
||||
|
||||
const nodeCode = String(parentNode.data.nodeCode || '').toLowerCase();
|
||||
const isJudge = ['判断', 'judge', 'condition', 'if', 'branch', 'gateway'].some((k) => nodeCode.includes(k));
|
||||
const isStart = nodeCode === '__start__';
|
||||
|
||||
if (isJudge || isStart || nodesWithFields.has(parentId)) return null;
|
||||
|
||||
return {
|
||||
id: parentId,
|
||||
name: parentNode.data.label,
|
||||
};
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
return parentNodes as ParentNode[];
|
||||
});
|
||||
|
||||
// 检查节点输出是否被引用
|
||||
const isNodeOutputQuoted = (nodeId: string): boolean => {
|
||||
if (!props.selectedNode) return false;
|
||||
const inputSource = props.selectedNode.data.inputSource;
|
||||
if (!Array.isArray(inputSource)) return false;
|
||||
|
||||
const node = inputSource.find((item) => item.nodeId === nodeId);
|
||||
return node?.quoteOutput === true;
|
||||
};
|
||||
|
||||
// 获取可用的参数选项
|
||||
const availableParams = computed(() => {
|
||||
if (!props.selectedNode) return [];
|
||||
|
||||
const params: ParamOption[] = [];
|
||||
const visited = new Set<string>();
|
||||
|
||||
const findParents = (nodeId: string) => {
|
||||
if (visited.has(nodeId)) return;
|
||||
visited.add(nodeId);
|
||||
|
||||
props.edges
|
||||
.filter((e) => e.target === nodeId)
|
||||
.forEach((edge) => {
|
||||
const parent = props.nodes.find((n) => n.id === edge.source);
|
||||
if (parent && parent.data.nodeCode !== '__start__' && parent.data.nodeCode !== 'judge') {
|
||||
params.push({
|
||||
label: `${parent.data.label}.output`,
|
||||
value: `\${${parent.id}.output}`,
|
||||
});
|
||||
}
|
||||
findParents(edge.source);
|
||||
});
|
||||
};
|
||||
|
||||
findParents(props.selectedNode.id);
|
||||
return params;
|
||||
});
|
||||
|
||||
const handleParamSelect = (value: string) => {
|
||||
if (!value) return;
|
||||
emit('addParam', value);
|
||||
selectedParam.value = '';
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.input-source-manager {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.input-source-list {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.input-source-item {
|
||||
padding: 12px;
|
||||
margin-bottom: 12px;
|
||||
background: #f8fafc;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.input-source-header {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.input-source-node-name {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
.input-source-fields {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.field-tag {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 4px 8px;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.input-source-output {
|
||||
padding-top: 8px;
|
||||
border-top: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.parent-nodes-output {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.parent-nodes-title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #64748b;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.parent-node-output-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px 12px;
|
||||
margin-bottom: 6px;
|
||||
background: #f8fafc;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.parent-node-name {
|
||||
font-size: 13px;
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
.w100 {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
263
src/views/settings/workflow/component/NodeConfigPanel.vue
Normal file
263
src/views/settings/workflow/component/NodeConfigPanel.vue
Normal file
@@ -0,0 +1,263 @@
|
||||
<template>
|
||||
<div class="config-panel">
|
||||
<h3>节点配置</h3>
|
||||
<div v-if="selectedNode">
|
||||
<el-form label-position="top">
|
||||
<el-form-item label="节点名称">
|
||||
<el-input :model-value="selectedNode.data.label" @update:model-value="updateNodeLabel" />
|
||||
</el-form-item>
|
||||
<el-form-item label="节点类型">
|
||||
<el-tag>{{ selectedNode.data.nodeCode }}</el-tag>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 模型选择 -->
|
||||
<el-form-item v-if="nodeConfig?.modelConfig && nodeConfig.modelConfig.length > 0" label="选择模型">
|
||||
<el-button type="primary" @click="emit('openModelSelector')" style="width: 100%">选择模型</el-button>
|
||||
<div v-if="selectedNode.data.modelConfig?.modelName" class="selected-tag">
|
||||
<el-tag type="success" size="large" closable @close="emit('removeModel')">
|
||||
{{ selectedNode.data.modelConfig.modelName }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 技能选择 -->
|
||||
<el-form-item v-if="nodeConfig?.skillOption" label="选择技能">
|
||||
<el-button type="primary" @click="emit('openSkillSelector')" style="width: 100%">选择技能</el-button>
|
||||
<div v-if="selectedNode.data.skillName" class="selected-tag">
|
||||
<el-tag type="success" size="large" closable @close="emit('removeSkill')">
|
||||
{{ selectedNode.data.skillName }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 动态表单字段 -->
|
||||
<template v-if="nodeConfig?.formConfig && nodeConfig.formConfig.length > 0">
|
||||
<el-divider content-position="left">节点参数</el-divider>
|
||||
<el-form-item v-for="field in nodeConfig.formConfig" :key="field.field" :label="field.label" :required="field.required">
|
||||
<el-input
|
||||
v-if="field.type === 'input' || field.type === 'string'"
|
||||
:model-value="getFieldValue(field.field)"
|
||||
@update:model-value="updateFieldValue(field.field, $event)"
|
||||
:placeholder="field.required ? '必填' : '选填'"
|
||||
/>
|
||||
<el-input-number
|
||||
v-else-if="field.type === 'number' || field.type === 'inputNumber'"
|
||||
:model-value="getFieldValue(field.field)"
|
||||
@update:model-value="updateFieldValue(field.field, $event)"
|
||||
class="w100"
|
||||
/>
|
||||
<el-input
|
||||
v-else-if="field.type === 'textarea'"
|
||||
:model-value="getFieldValue(field.field)"
|
||||
@update:model-value="updateFieldValue(field.field, $event)"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
:placeholder="field.required ? '必填' : '选填'"
|
||||
/>
|
||||
<el-switch
|
||||
v-else-if="field.type === 'switch'"
|
||||
:model-value="getFieldValue(field.field)"
|
||||
@update:model-value="updateFieldValue(field.field, $event)"
|
||||
/>
|
||||
<el-select
|
||||
v-else-if="field.type === 'select' && field.options"
|
||||
:model-value="getFieldValue(field.field)"
|
||||
@update:model-value="updateFieldValue(field.field, $event)"
|
||||
:placeholder="field.required ? '必填' : '选填'"
|
||||
class="w100"
|
||||
>
|
||||
<el-option v-for="opt in field.options" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||||
</el-select>
|
||||
<el-input
|
||||
v-else
|
||||
:model-value="getFieldValue(field.field)"
|
||||
@update:model-value="updateFieldValue(field.field, $event)"
|
||||
:placeholder="field.required ? '必填' : '选填'"
|
||||
/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-form>
|
||||
|
||||
<!-- 上级参数管理 -->
|
||||
<InputSourceManager
|
||||
v-if="selectedNode.data.nodeCode !== '__start__'"
|
||||
:selected-node="selectedNode"
|
||||
:nodes="allNodes"
|
||||
:edges="allEdges"
|
||||
@remove-field="(nodeId: string, fieldName: string) => emit('removeField', nodeId, fieldName)"
|
||||
@toggle-output="(nodeId: string, enabled: boolean) => emit('toggleOutput', nodeId, enabled)"
|
||||
@add-param="(paramValue: string) => emit('addParamByValue', paramValue)"
|
||||
/>
|
||||
</div>
|
||||
<el-empty v-else description="请选择一个节点" :image-size="100" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Node } from '@vue-flow/core';
|
||||
import InputSourceManager from './InputSourceManager.vue';
|
||||
|
||||
interface NodeData {
|
||||
label: string;
|
||||
nodeCode: string;
|
||||
inputSource: Array<{ nodeId: string; field: string[]; quoteOutput?: boolean }> | null;
|
||||
formConfig?: any[];
|
||||
modelConfig?: any;
|
||||
skillName?: string;
|
||||
}
|
||||
|
||||
interface ParamRef {
|
||||
id: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
interface NodeConfig {
|
||||
formConfig: any[];
|
||||
modelConfig: any[];
|
||||
skillOption: boolean;
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
selectedNode: Node<NodeData> | null;
|
||||
availableParams: ParamRef[];
|
||||
nodeConfig: NodeConfig | null;
|
||||
allNodes: Node<NodeData>[];
|
||||
allEdges: any[];
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:selectedNode', node: Node<NodeData>): void;
|
||||
(e: 'addParam', param: ParamRef): void;
|
||||
(e: 'openModelSelector'): void;
|
||||
(e: 'removeModel'): void;
|
||||
(e: 'openSkillSelector'): void;
|
||||
(e: 'removeSkill'): void;
|
||||
(e: 'removeField', nodeId: string, fieldName: string): void;
|
||||
(e: 'toggleOutput', nodeId: string, enabled: boolean): void;
|
||||
(e: 'addParamByValue', paramValue: string): void;
|
||||
}>();
|
||||
|
||||
const updateNodeLabel = (newLabel: string) => {
|
||||
if (!props.selectedNode) return;
|
||||
const updatedNode = {
|
||||
...props.selectedNode,
|
||||
data: {
|
||||
...props.selectedNode.data,
|
||||
label: newLabel,
|
||||
},
|
||||
};
|
||||
emit('update:selectedNode', updatedNode);
|
||||
};
|
||||
|
||||
const getFieldValue = (fieldName: string) => {
|
||||
if (!props.selectedNode?.data.formConfig) return '';
|
||||
const field = props.selectedNode.data.formConfig.find((f: any) => f.field === fieldName);
|
||||
return field?.value ?? '';
|
||||
};
|
||||
|
||||
const updateFieldValue = (fieldName: string, value: any) => {
|
||||
if (!props.selectedNode) return;
|
||||
|
||||
const formConfig = props.selectedNode.data.formConfig || [];
|
||||
const existingIndex = formConfig.findIndex((f: any) => f.field === fieldName);
|
||||
|
||||
let updatedFormConfig;
|
||||
if (existingIndex >= 0) {
|
||||
updatedFormConfig = [...formConfig];
|
||||
updatedFormConfig[existingIndex] = { ...updatedFormConfig[existingIndex], value };
|
||||
} else {
|
||||
const fieldDef = props.nodeConfig?.formConfig.find((f) => f.field === fieldName);
|
||||
if (fieldDef) {
|
||||
updatedFormConfig = [...formConfig, { ...fieldDef, value }];
|
||||
} else {
|
||||
updatedFormConfig = formConfig;
|
||||
}
|
||||
}
|
||||
|
||||
const updatedNode = {
|
||||
...props.selectedNode,
|
||||
data: {
|
||||
...props.selectedNode.data,
|
||||
formConfig: updatedFormConfig,
|
||||
},
|
||||
};
|
||||
emit('update:selectedNode', updatedNode);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.config-panel {
|
||||
background: #ffffff;
|
||||
border-radius: 10px;
|
||||
padding: 16px;
|
||||
overflow-y: auto;
|
||||
box-shadow: 0 1px 3px rgba(15, 23, 42, 0.06);
|
||||
border: 1px solid #e6eaf0;
|
||||
|
||||
h3 {
|
||||
margin: 0 0 16px 0;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
color: #334155;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
:deep(.el-form) {
|
||||
.el-form-item {
|
||||
margin-bottom: 14px;
|
||||
|
||||
.el-form-item__label {
|
||||
font-weight: 600;
|
||||
color: #475569;
|
||||
margin-bottom: 6px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.el-input__wrapper {
|
||||
border-radius: 6px;
|
||||
box-shadow: none;
|
||||
border: 1px solid #dbe3ee;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
border-color: #b8c4d6;
|
||||
}
|
||||
|
||||
&.is-focus {
|
||||
border-color: #3b82f6;
|
||||
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.12);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.param-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px 12px;
|
||||
margin-bottom: 8px;
|
||||
background: #f8fafc;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
border-color: #cbd5e1;
|
||||
background: #f1f5f9;
|
||||
}
|
||||
}
|
||||
|
||||
.selected-tag {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.w100 {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.el-empty) {
|
||||
padding: 32px 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
149
src/views/settings/workflow/component/NodeLibraryPanel.vue
Normal file
149
src/views/settings/workflow/component/NodeLibraryPanel.vue
Normal file
@@ -0,0 +1,149 @@
|
||||
<template>
|
||||
<div class="node-library-panel" :class="{ collapsed: collapsed }">
|
||||
<div class="node-library-header">
|
||||
<span>节点库</span>
|
||||
<el-button class="collapse-btn" text circle @click="emit('update:collapsed', !collapsed)">
|
||||
<el-icon>
|
||||
<ArrowRightBold v-if="collapsed" />
|
||||
<ArrowLeftBold v-else />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
<div v-if="!collapsed" class="node-library-content">
|
||||
<el-empty v-if="nodeLibraryGroups.length === 0" description="暂无节点" :image-size="40" />
|
||||
<div v-else class="node-library-groups">
|
||||
<div v-for="group in nodeLibraryGroups" :key="group.group" class="node-group">
|
||||
<div class="node-group-title">{{ group.label }}</div>
|
||||
<div class="node-group-items">
|
||||
<el-button
|
||||
v-for="item in group.items"
|
||||
:key="item.nodeCode"
|
||||
text
|
||||
class="node-item"
|
||||
@click="emit('addNode', item.nodeCode, item.nodeName)"
|
||||
>
|
||||
{{ item.nodeName }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ArrowLeftBold, ArrowRightBold } from '@element-plus/icons-vue';
|
||||
import type { NodeLibraryGroup } from '/@/api/settings/creation';
|
||||
|
||||
defineProps<{
|
||||
nodeLibraryGroups: NodeLibraryGroup[];
|
||||
collapsed: boolean;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:collapsed', value: boolean): void;
|
||||
(e: 'addNode', nodeCode: string, nodeName: string): void;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.node-library-panel {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
z-index: 10;
|
||||
background: #fff;
|
||||
border: 1px solid #d8e0eb;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 2px 8px rgba(15, 23, 42, 0.08);
|
||||
width: 132px;
|
||||
max-height: calc(100% - 20px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
transition: width 0.18s ease;
|
||||
|
||||
&.collapsed {
|
||||
width: 40px;
|
||||
|
||||
.node-library-header {
|
||||
padding: 8px;
|
||||
border-bottom: none;
|
||||
|
||||
> span {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.node-library-content {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.node-library-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px;
|
||||
border-bottom: 1px solid #e7ecf3;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: #1f2937;
|
||||
background: #f8fafc;
|
||||
|
||||
.collapse-btn {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 1px solid #cfd8e6;
|
||||
color: #64748b;
|
||||
}
|
||||
}
|
||||
|
||||
.node-library-content {
|
||||
padding: 12px;
|
||||
overflow-y: auto;
|
||||
max-height: 480px;
|
||||
}
|
||||
|
||||
.node-library-groups {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.node-group {
|
||||
.node-group-title {
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: #64748b;
|
||||
margin-bottom: 8px;
|
||||
padding-bottom: 4px;
|
||||
border-bottom: 1px solid #e7ecf3;
|
||||
}
|
||||
|
||||
.node-group-items {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.node-item {
|
||||
justify-content: flex-start;
|
||||
width: 100%;
|
||||
padding: 8px 10px;
|
||||
color: #475569;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
background: transparent;
|
||||
border: none;
|
||||
transition: all 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
background: #f1f5f9;
|
||||
color: #1e293b;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
40
src/views/settings/workflow/component/SaveWorkflowDialog.vue
Normal file
40
src/views/settings/workflow/component/SaveWorkflowDialog.vue
Normal file
@@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="500px" :close-on-click-modal="false">
|
||||
<el-form :model="saveForm" label-position="top">
|
||||
<el-form-item label="工作流名称" required>
|
||||
<el-input v-model="saveForm.flowName" placeholder="请输入工作流名称" maxlength="50" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item label="工作流描述">
|
||||
<el-input v-model="saveForm.description" type="textarea" :rows="4" placeholder="请输入工作流描述(选填)" maxlength="200" show-word-limit />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="saving" @click="emit('confirm')">{{ confirmText }}</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: boolean;
|
||||
saveForm: { flowName: string; description: string };
|
||||
currentEditingWorkflowId: string | null;
|
||||
saving: boolean;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: boolean): void;
|
||||
(e: 'confirm'): void;
|
||||
}>();
|
||||
|
||||
const dialogVisible = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (value: boolean) => emit('update:modelValue', value),
|
||||
});
|
||||
|
||||
const dialogTitle = computed(() => (props.currentEditingWorkflowId ? '编辑工作流' : '保存工作流'));
|
||||
const confirmText = computed(() => (props.currentEditingWorkflowId ? '确定更新' : '确定保存'));
|
||||
</script>
|
||||
191
src/views/settings/workflow/component/WorkflowListPanel.vue
Normal file
191
src/views/settings/workflow/component/WorkflowListPanel.vue
Normal file
@@ -0,0 +1,191 @@
|
||||
<template>
|
||||
<div class="workflow-list-panel">
|
||||
<div class="panel-header">
|
||||
<el-tabs v-model="activeTab" class="workflow-tabs">
|
||||
<el-tab-pane label="我的工作流" name="user"></el-tab-pane>
|
||||
<el-tab-pane label="模板工作流" name="template"></el-tab-pane>
|
||||
</el-tabs>
|
||||
<el-button type="success" size="small" @click="emit('create')">新建</el-button>
|
||||
</div>
|
||||
<div class="workflow-list-content" v-loading="loading">
|
||||
<el-empty v-if="currentList.length === 0" description="暂无工作流" :image-size="60" />
|
||||
<div v-else class="workflow-items">
|
||||
<div
|
||||
v-for="workflow in currentList"
|
||||
:key="workflow.id"
|
||||
class="workflow-item"
|
||||
:class="{ active: currentEditingId === workflow.id }"
|
||||
@click="emit('edit', workflow)"
|
||||
>
|
||||
<div class="workflow-item-content">
|
||||
<div class="workflow-item-name">{{ workflow.flowName || workflow.flowTemplateName || '未命名工作流' }}</div>
|
||||
<div class="workflow-item-desc">{{ workflow.description || '暂无描述' }}</div>
|
||||
</div>
|
||||
<div class="workflow-item-actions">
|
||||
<el-button type="primary" link size="small" @click.stop="emit('edit', workflow)">编辑</el-button>
|
||||
<el-button type="danger" link size="small" @click.stop="emit('delete', workflow)">删除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue';
|
||||
import type { WorkflowItem } from '/@/api/settings/creation';
|
||||
|
||||
const props = defineProps<{
|
||||
userWorkflowList: WorkflowItem[];
|
||||
templateWorkflowList: WorkflowItem[];
|
||||
currentEditingId: string | null;
|
||||
loading: boolean;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'edit', workflow: WorkflowItem): void;
|
||||
(e: 'delete', workflow: WorkflowItem): void;
|
||||
(e: 'create'): void;
|
||||
}>();
|
||||
|
||||
const activeTab = ref<'user' | 'template'>('user');
|
||||
|
||||
const currentList = computed(() => {
|
||||
return activeTab.value === 'user' ? props.userWorkflowList : props.templateWorkflowList;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.workflow-list-panel {
|
||||
background: #ffffff;
|
||||
border-radius: 10px;
|
||||
padding: 16px;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-shadow: 0 1px 3px rgba(15, 23, 42, 0.06);
|
||||
border: 1px solid #e6eaf0;
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 14px;
|
||||
|
||||
:deep(.el-button) {
|
||||
border-radius: 6px;
|
||||
font-weight: 500;
|
||||
font-size: 12px;
|
||||
padding: 6px 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.workflow-tabs {
|
||||
flex: 1;
|
||||
|
||||
:deep(.el-tabs__header) {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__nav-wrap::after) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__item) {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #64748b;
|
||||
padding: 0 16px;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
|
||||
&.is-active {
|
||||
color: #3b82f6;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-tabs__active-bar) {
|
||||
background-color: #3b82f6;
|
||||
}
|
||||
}
|
||||
|
||||
.workflow-list-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: rgba(102, 126, 234, 0.05);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.workflow-items {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.workflow-item {
|
||||
padding: 12px;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
background: #fff;
|
||||
|
||||
&:hover {
|
||||
border-color: #c5d2e6;
|
||||
box-shadow: 0 2px 8px rgba(15, 23, 42, 0.06);
|
||||
}
|
||||
|
||||
&.active {
|
||||
border-color: #3b82f6;
|
||||
background: #eff6ff;
|
||||
}
|
||||
}
|
||||
|
||||
.workflow-item-content {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.workflow-item-name {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
margin-bottom: 4px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.workflow-item-desc {
|
||||
font-size: 12px;
|
||||
color: #64748b;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.workflow-item-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
justify-content: flex-end;
|
||||
|
||||
:deep(.el-button) {
|
||||
border-radius: 6px;
|
||||
font-weight: 500;
|
||||
font-size: 12px;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
1019
src/views/settings/workflow/index.vue
Normal file
1019
src/views/settings/workflow/index.vue
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user