feat:三个窗口接口联调版本

This commit is contained in:
liailing1026
2026-01-09 13:54:32 +08:00
parent 5847365eee
commit 920588b063
26 changed files with 4133 additions and 1856 deletions

View File

@@ -20,6 +20,10 @@
"@element-plus/icons-vue": "^2.3.2", "@element-plus/icons-vue": "^2.3.2",
"@jsplumb/browser-ui": "^6.2.10", "@jsplumb/browser-ui": "^6.2.10",
"@types/markdown-it": "^14.1.2", "@types/markdown-it": "^14.1.2",
"@vue-flow/background": "^1.3.2",
"@vue-flow/controls": "^1.1.3",
"@vue-flow/core": "^1.48.1",
"@vue-flow/minimap": "^1.5.4",
"@vueuse/core": "^14.0.0", "@vueuse/core": "^14.0.0",
"axios": "^1.12.2", "axios": "^1.12.2",
"dompurify": "^3.3.0", "dompurify": "^3.3.0",

195
frontend/pnpm-lock.yaml generated
View File

@@ -17,6 +17,18 @@ importers:
'@types/markdown-it': '@types/markdown-it':
specifier: ^14.1.2 specifier: ^14.1.2
version: 14.1.2 version: 14.1.2
'@vue-flow/background':
specifier: ^1.3.2
version: 1.3.2(@vue-flow/core@1.48.1(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))
'@vue-flow/controls':
specifier: ^1.1.3
version: 1.1.3(@vue-flow/core@1.48.1(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))
'@vue-flow/core':
specifier: ^1.48.1
version: 1.48.1(vue@3.5.25(typescript@5.9.3))
'@vue-flow/minimap':
specifier: ^1.5.4
version: 1.5.4(@vue-flow/core@1.48.1(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))
'@vueuse/core': '@vueuse/core':
specifier: ^14.0.0 specifier: ^14.0.0
version: 14.1.0(vue@3.5.25(typescript@5.9.3)) version: 14.1.0(vue@3.5.25(typescript@5.9.3))
@@ -625,36 +637,42 @@ packages:
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm-musl@2.5.1': '@parcel/watcher-linux-arm-musl@2.5.1':
resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==}
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
libc: [musl]
'@parcel/watcher-linux-arm64-glibc@2.5.1': '@parcel/watcher-linux-arm64-glibc@2.5.1':
resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==}
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm64-musl@2.5.1': '@parcel/watcher-linux-arm64-musl@2.5.1':
resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==}
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [musl]
'@parcel/watcher-linux-x64-glibc@2.5.1': '@parcel/watcher-linux-x64-glibc@2.5.1':
resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==}
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [glibc]
'@parcel/watcher-linux-x64-musl@2.5.1': '@parcel/watcher-linux-x64-musl@2.5.1':
resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==}
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [musl]
'@parcel/watcher-win32-arm64@2.5.1': '@parcel/watcher-win32-arm64@2.5.1':
resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==}
@@ -726,56 +744,67 @@ packages:
resolution: {integrity: sha512-UPMMNeC4LXW7ZSHxeP3Edv09aLsFUMaD1TSVW6n1CWMECnUIJMFFB7+XC2lZTdPtvB36tYC0cJWc86mzSsaviw==} resolution: {integrity: sha512-UPMMNeC4LXW7ZSHxeP3Edv09aLsFUMaD1TSVW6n1CWMECnUIJMFFB7+XC2lZTdPtvB36tYC0cJWc86mzSsaviw==}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm-musleabihf@4.53.4': '@rollup/rollup-linux-arm-musleabihf@4.53.4':
resolution: {integrity: sha512-H8uwlV0otHs5Q7WAMSoyvjV9DJPiy5nJ/xnHolY0QptLPjaSsuX7tw+SPIfiYH6cnVx3fe4EWFafo6gH6ekZKA==} resolution: {integrity: sha512-H8uwlV0otHs5Q7WAMSoyvjV9DJPiy5nJ/xnHolY0QptLPjaSsuX7tw+SPIfiYH6cnVx3fe4EWFafo6gH6ekZKA==}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-linux-arm64-gnu@4.53.4': '@rollup/rollup-linux-arm64-gnu@4.53.4':
resolution: {integrity: sha512-BLRwSRwICXz0TXkbIbqJ1ibK+/dSBpTJqDClF61GWIrxTXZWQE78ROeIhgl5MjVs4B4gSLPCFeD4xML9vbzvCQ==} resolution: {integrity: sha512-BLRwSRwICXz0TXkbIbqJ1ibK+/dSBpTJqDClF61GWIrxTXZWQE78ROeIhgl5MjVs4B4gSLPCFeD4xML9vbzvCQ==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm64-musl@4.53.4': '@rollup/rollup-linux-arm64-musl@4.53.4':
resolution: {integrity: sha512-6bySEjOTbmVcPJAywjpGLckK793A0TJWSbIa0sVwtVGfe/Nz6gOWHOwkshUIAp9j7wg2WKcA4Snu7Y1nUZyQew==} resolution: {integrity: sha512-6bySEjOTbmVcPJAywjpGLckK793A0TJWSbIa0sVwtVGfe/Nz6gOWHOwkshUIAp9j7wg2WKcA4Snu7Y1nUZyQew==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-linux-loong64-gnu@4.53.4': '@rollup/rollup-linux-loong64-gnu@4.53.4':
resolution: {integrity: sha512-U0ow3bXYJZ5MIbchVusxEycBw7bO6C2u5UvD31i5IMTrnt2p4Fh4ZbHSdc/31TScIJQYHwxbj05BpevB3201ug==} resolution: {integrity: sha512-U0ow3bXYJZ5MIbchVusxEycBw7bO6C2u5UvD31i5IMTrnt2p4Fh4ZbHSdc/31TScIJQYHwxbj05BpevB3201ug==}
cpu: [loong64] cpu: [loong64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-ppc64-gnu@4.53.4': '@rollup/rollup-linux-ppc64-gnu@4.53.4':
resolution: {integrity: sha512-iujDk07ZNwGLVn0YIWM80SFN039bHZHCdCCuX9nyx3Jsa2d9V/0Y32F+YadzwbvDxhSeVo9zefkoPnXEImnM5w==} resolution: {integrity: sha512-iujDk07ZNwGLVn0YIWM80SFN039bHZHCdCCuX9nyx3Jsa2d9V/0Y32F+YadzwbvDxhSeVo9zefkoPnXEImnM5w==}
cpu: [ppc64] cpu: [ppc64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-gnu@4.53.4': '@rollup/rollup-linux-riscv64-gnu@4.53.4':
resolution: {integrity: sha512-MUtAktiOUSu+AXBpx1fkuG/Bi5rhlorGs3lw5QeJ2X3ziEGAq7vFNdWVde6XGaVqi0LGSvugwjoxSNJfHFTC0g==} resolution: {integrity: sha512-MUtAktiOUSu+AXBpx1fkuG/Bi5rhlorGs3lw5QeJ2X3ziEGAq7vFNdWVde6XGaVqi0LGSvugwjoxSNJfHFTC0g==}
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-musl@4.53.4': '@rollup/rollup-linux-riscv64-musl@4.53.4':
resolution: {integrity: sha512-btm35eAbDfPtcFEgaXCI5l3c2WXyzwiE8pArhd66SDtoLWmgK5/M7CUxmUglkwtniPzwvWioBKKl6IXLbPf2sQ==} resolution: {integrity: sha512-btm35eAbDfPtcFEgaXCI5l3c2WXyzwiE8pArhd66SDtoLWmgK5/M7CUxmUglkwtniPzwvWioBKKl6IXLbPf2sQ==}
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-linux-s390x-gnu@4.53.4': '@rollup/rollup-linux-s390x-gnu@4.53.4':
resolution: {integrity: sha512-uJlhKE9ccUTCUlK+HUz/80cVtx2RayadC5ldDrrDUFaJK0SNb8/cCmC9RhBhIWuZ71Nqj4Uoa9+xljKWRogdhA==} resolution: {integrity: sha512-uJlhKE9ccUTCUlK+HUz/80cVtx2RayadC5ldDrrDUFaJK0SNb8/cCmC9RhBhIWuZ71Nqj4Uoa9+xljKWRogdhA==}
cpu: [s390x] cpu: [s390x]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.53.4': '@rollup/rollup-linux-x64-gnu@4.53.4':
resolution: {integrity: sha512-jjEMkzvASQBbzzlzf4os7nzSBd/cvPrpqXCUOqoeCh1dQ4BP3RZCJk8XBeik4MUln3m+8LeTJcY54C/u8wb3DQ==} resolution: {integrity: sha512-jjEMkzvASQBbzzlzf4os7nzSBd/cvPrpqXCUOqoeCh1dQ4BP3RZCJk8XBeik4MUln3m+8LeTJcY54C/u8wb3DQ==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-musl@4.53.4': '@rollup/rollup-linux-x64-musl@4.53.4':
resolution: {integrity: sha512-lu90KG06NNH19shC5rBPkrh6mrTpq5kviFylPBXQVpdEu0yzb0mDgyxLr6XdcGdBIQTH/UAhDJnL+APZTBu1aQ==} resolution: {integrity: sha512-lu90KG06NNH19shC5rBPkrh6mrTpq5kviFylPBXQVpdEu0yzb0mDgyxLr6XdcGdBIQTH/UAhDJnL+APZTBu1aQ==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-openharmony-arm64@4.53.4': '@rollup/rollup-openharmony-arm64@4.53.4':
resolution: {integrity: sha512-dFDcmLwsUzhAm/dn0+dMOQZoONVYBtgik0VuY/d5IJUUb787L3Ko/ibvTvddqhb3RaB7vFEozYevHN4ox22R/w==} resolution: {integrity: sha512-dFDcmLwsUzhAm/dn0+dMOQZoONVYBtgik0VuY/d5IJUUb787L3Ko/ibvTvddqhb3RaB7vFEozYevHN4ox22R/w==}
@@ -846,24 +875,28 @@ packages:
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [glibc]
'@tailwindcss/oxide-linux-arm64-musl@4.1.18': '@tailwindcss/oxide-linux-arm64-musl@4.1.18':
resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [musl]
'@tailwindcss/oxide-linux-x64-gnu@4.1.18': '@tailwindcss/oxide-linux-x64-gnu@4.1.18':
resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [glibc]
'@tailwindcss/oxide-linux-x64-musl@4.1.18': '@tailwindcss/oxide-linux-x64-musl@4.1.18':
resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [musl]
'@tailwindcss/oxide-wasm32-wasi@4.1.18': '@tailwindcss/oxide-wasm32-wasi@4.1.18':
resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==}
@@ -956,6 +989,9 @@ packages:
'@types/web-bluetooth@0.0.16': '@types/web-bluetooth@0.0.16':
resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==} resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==}
'@types/web-bluetooth@0.0.20':
resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==}
'@types/web-bluetooth@0.0.21': '@types/web-bluetooth@0.0.21':
resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==}
@@ -1076,6 +1112,29 @@ packages:
'@volar/typescript@2.4.26': '@volar/typescript@2.4.26':
resolution: {integrity: sha512-N87ecLD48Sp6zV9zID/5yuS1+5foj0DfuYGdQ6KHj/IbKvyKv1zNX6VCmnKYwtmHadEO6mFc2EKISiu3RDPAvA==} resolution: {integrity: sha512-N87ecLD48Sp6zV9zID/5yuS1+5foj0DfuYGdQ6KHj/IbKvyKv1zNX6VCmnKYwtmHadEO6mFc2EKISiu3RDPAvA==}
'@vue-flow/background@1.3.2':
resolution: {integrity: sha512-eJPhDcLj1wEo45bBoqTXw1uhl0yK2RaQGnEINqvvBsAFKh/camHJd5NPmOdS1w+M9lggc9igUewxaEd3iCQX2w==}
peerDependencies:
'@vue-flow/core': ^1.23.0
vue: ^3.3.0
'@vue-flow/controls@1.1.3':
resolution: {integrity: sha512-XCf+G+jCvaWURdFlZmOjifZGw3XMhN5hHlfMGkWh9xot+9nH9gdTZtn+ldIJKtarg3B21iyHU8JjKDhYcB6JMw==}
peerDependencies:
'@vue-flow/core': ^1.23.0
vue: ^3.3.0
'@vue-flow/core@1.48.1':
resolution: {integrity: sha512-3IxaMBLvWRbznZ4CuK0kVhp4Y4lCDQx9nhi48Swp6PwPw29KNhmiKd2kaBogYeWjGLb/tLjlE9V0s3jEmKCYWw==}
peerDependencies:
vue: ^3.3.0
'@vue-flow/minimap@1.5.4':
resolution: {integrity: sha512-l4C+XTAXnRxsRpUdN7cAVFBennC1sVRzq4bDSpVK+ag7tdMczAnhFYGgbLkUw3v3sY6gokyWwMl8CDonp8eB2g==}
peerDependencies:
'@vue-flow/core': ^1.23.0
vue: ^3.3.0
'@vue/babel-helper-vue-transform-on@1.5.0': '@vue/babel-helper-vue-transform-on@1.5.0':
resolution: {integrity: sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==} resolution: {integrity: sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==}
@@ -1183,6 +1242,9 @@ packages:
vue: vue:
optional: true optional: true
'@vueuse/core@10.11.1':
resolution: {integrity: sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==}
'@vueuse/core@14.1.0': '@vueuse/core@14.1.0':
resolution: {integrity: sha512-rgBinKs07hAYyPF834mDTigH7BtPqvZ3Pryuzt1SD/lg5wEcWqvwzXXYGEDb2/cP0Sj5zSvHl3WkmMELr5kfWw==} resolution: {integrity: sha512-rgBinKs07hAYyPF834mDTigH7BtPqvZ3Pryuzt1SD/lg5wEcWqvwzXXYGEDb2/cP0Sj5zSvHl3WkmMELr5kfWw==}
peerDependencies: peerDependencies:
@@ -1191,12 +1253,18 @@ packages:
'@vueuse/core@9.13.0': '@vueuse/core@9.13.0':
resolution: {integrity: sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==} resolution: {integrity: sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==}
'@vueuse/metadata@10.11.1':
resolution: {integrity: sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==}
'@vueuse/metadata@14.1.0': '@vueuse/metadata@14.1.0':
resolution: {integrity: sha512-7hK4g015rWn2PhKcZ99NyT+ZD9sbwm7SGvp7k+k+rKGWnLjS/oQozoIZzWfCewSUeBmnJkIb+CNr7Zc/EyRnnA==} resolution: {integrity: sha512-7hK4g015rWn2PhKcZ99NyT+ZD9sbwm7SGvp7k+k+rKGWnLjS/oQozoIZzWfCewSUeBmnJkIb+CNr7Zc/EyRnnA==}
'@vueuse/metadata@9.13.0': '@vueuse/metadata@9.13.0':
resolution: {integrity: sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==} resolution: {integrity: sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==}
'@vueuse/shared@10.11.1':
resolution: {integrity: sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==}
'@vueuse/shared@14.1.0': '@vueuse/shared@14.1.0':
resolution: {integrity: sha512-EcKxtYvn6gx1F8z9J5/rsg3+lTQnvOruQd8fUecW99DCK04BkWD7z5KQ/wTAx+DazyoEE9dJt/zV8OIEQbM6kw==} resolution: {integrity: sha512-EcKxtYvn6gx1F8z9J5/rsg3+lTQnvOruQd8fUecW99DCK04BkWD7z5KQ/wTAx+DazyoEE9dJt/zV8OIEQbM6kw==}
peerDependencies: peerDependencies:
@@ -1522,6 +1590,44 @@ packages:
csstype@3.2.3: csstype@3.2.3:
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
d3-color@3.1.0:
resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==}
engines: {node: '>=12'}
d3-dispatch@3.0.1:
resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==}
engines: {node: '>=12'}
d3-drag@3.0.0:
resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==}
engines: {node: '>=12'}
d3-ease@3.0.1:
resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==}
engines: {node: '>=12'}
d3-interpolate@3.0.1:
resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==}
engines: {node: '>=12'}
d3-selection@3.0.0:
resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==}
engines: {node: '>=12'}
d3-timer@3.0.1:
resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==}
engines: {node: '>=12'}
d3-transition@3.0.1:
resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==}
engines: {node: '>=12'}
peerDependencies:
d3-selection: 2 - 3
d3-zoom@3.0.0:
resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==}
engines: {node: '>=12'}
data-urls@6.0.0: data-urls@6.0.0:
resolution: {integrity: sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==} resolution: {integrity: sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==}
engines: {node: '>=20'} engines: {node: '>=20'}
@@ -2482,24 +2588,28 @@ packages:
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [glibc]
lightningcss-linux-arm64-musl@1.30.2: lightningcss-linux-arm64-musl@1.30.2:
resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [musl]
lightningcss-linux-x64-gnu@1.30.2: lightningcss-linux-x64-gnu@1.30.2:
resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [glibc]
lightningcss-linux-x64-musl@1.30.2: lightningcss-linux-x64-musl@1.30.2:
resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [musl]
lightningcss-win32-arm64-msvc@1.30.2: lightningcss-win32-arm64-msvc@1.30.2:
resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==}
@@ -4418,6 +4528,8 @@ snapshots:
'@types/web-bluetooth@0.0.16': {} '@types/web-bluetooth@0.0.16': {}
'@types/web-bluetooth@0.0.20': {}
'@types/web-bluetooth@0.0.21': {} '@types/web-bluetooth@0.0.21': {}
'@typescript-eslint/eslint-plugin@8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': '@typescript-eslint/eslint-plugin@8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)':
@@ -4582,6 +4694,34 @@ snapshots:
path-browserify: 1.0.1 path-browserify: 1.0.1
vscode-uri: 3.1.0 vscode-uri: 3.1.0
'@vue-flow/background@1.3.2(@vue-flow/core@1.48.1(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))':
dependencies:
'@vue-flow/core': 1.48.1(vue@3.5.25(typescript@5.9.3))
vue: 3.5.25(typescript@5.9.3)
'@vue-flow/controls@1.1.3(@vue-flow/core@1.48.1(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))':
dependencies:
'@vue-flow/core': 1.48.1(vue@3.5.25(typescript@5.9.3))
vue: 3.5.25(typescript@5.9.3)
'@vue-flow/core@1.48.1(vue@3.5.25(typescript@5.9.3))':
dependencies:
'@vueuse/core': 10.11.1(vue@3.5.25(typescript@5.9.3))
d3-drag: 3.0.0
d3-interpolate: 3.0.1
d3-selection: 3.0.0
d3-zoom: 3.0.0
vue: 3.5.25(typescript@5.9.3)
transitivePeerDependencies:
- '@vue/composition-api'
'@vue-flow/minimap@1.5.4(@vue-flow/core@1.48.1(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))':
dependencies:
'@vue-flow/core': 1.48.1(vue@3.5.25(typescript@5.9.3))
d3-selection: 3.0.0
d3-zoom: 3.0.0
vue: 3.5.25(typescript@5.9.3)
'@vue/babel-helper-vue-transform-on@1.5.0': {} '@vue/babel-helper-vue-transform-on@1.5.0': {}
'@vue/babel-plugin-jsx@1.5.0(@babel/core@7.28.5)': '@vue/babel-plugin-jsx@1.5.0(@babel/core@7.28.5)':
@@ -4755,6 +4895,16 @@ snapshots:
typescript: 5.9.3 typescript: 5.9.3
vue: 3.5.25(typescript@5.9.3) vue: 3.5.25(typescript@5.9.3)
'@vueuse/core@10.11.1(vue@3.5.25(typescript@5.9.3))':
dependencies:
'@types/web-bluetooth': 0.0.20
'@vueuse/metadata': 10.11.1
'@vueuse/shared': 10.11.1(vue@3.5.25(typescript@5.9.3))
vue-demi: 0.14.10(vue@3.5.25(typescript@5.9.3))
transitivePeerDependencies:
- '@vue/composition-api'
- vue
'@vueuse/core@14.1.0(vue@3.5.25(typescript@5.9.3))': '@vueuse/core@14.1.0(vue@3.5.25(typescript@5.9.3))':
dependencies: dependencies:
'@types/web-bluetooth': 0.0.21 '@types/web-bluetooth': 0.0.21
@@ -4772,10 +4922,19 @@ snapshots:
- '@vue/composition-api' - '@vue/composition-api'
- vue - vue
'@vueuse/metadata@10.11.1': {}
'@vueuse/metadata@14.1.0': {} '@vueuse/metadata@14.1.0': {}
'@vueuse/metadata@9.13.0': {} '@vueuse/metadata@9.13.0': {}
'@vueuse/shared@10.11.1(vue@3.5.25(typescript@5.9.3))':
dependencies:
vue-demi: 0.14.10(vue@3.5.25(typescript@5.9.3))
transitivePeerDependencies:
- '@vue/composition-api'
- vue
'@vueuse/shared@14.1.0(vue@3.5.25(typescript@5.9.3))': '@vueuse/shared@14.1.0(vue@3.5.25(typescript@5.9.3))':
dependencies: dependencies:
vue: 3.5.25(typescript@5.9.3) vue: 3.5.25(typescript@5.9.3)
@@ -5130,6 +5289,42 @@ snapshots:
csstype@3.2.3: {} csstype@3.2.3: {}
d3-color@3.1.0: {}
d3-dispatch@3.0.1: {}
d3-drag@3.0.0:
dependencies:
d3-dispatch: 3.0.1
d3-selection: 3.0.0
d3-ease@3.0.1: {}
d3-interpolate@3.0.1:
dependencies:
d3-color: 3.1.0
d3-selection@3.0.0: {}
d3-timer@3.0.1: {}
d3-transition@3.0.1(d3-selection@3.0.0):
dependencies:
d3-color: 3.1.0
d3-dispatch: 3.0.1
d3-ease: 3.0.1
d3-interpolate: 3.0.1
d3-selection: 3.0.0
d3-timer: 3.0.1
d3-zoom@3.0.0:
dependencies:
d3-dispatch: 3.0.1
d3-drag: 3.0.0
d3-interpolate: 3.0.1
d3-selection: 3.0.0
d3-transition: 3.0.1(d3-selection@3.0.0)
data-urls@6.0.0: data-urls@6.0.0:
dependencies: dependencies:
whatwg-mimetype: 4.0.0 whatwg-mimetype: 4.0.0

View File

@@ -3,91 +3,61 @@
"Icon": "Hailey_Johnson.png", "Icon": "Hailey_Johnson.png",
"Name": "船舶设计师", "Name": "船舶设计师",
"Profile": "提供船舶制造中的实际需求和约束。", "Profile": "提供船舶制造中的实际需求和约束。",
"Classification": "船舶制造数据空间", "Classification": "船舶制造数据空间"
"apiUrl": "http://8.130.104.76:21088/api/v1",
"apiKey": "0geK2bSKAjlaRp0qPLPq_zxFJu8MhJZIwNZSH30Ty6g",
"apiModel": "Flowise"
}, },
{ {
"Icon": "Jennifer_Moore.png", "Icon": "Jennifer_Moore.png",
"Name": "防护工程专家", "Name": "防护工程专家",
"Profile": "专注于船舶腐蚀防护技术的设计与应用。在你的总结回答中,必须引用来自数联网的搜索数据,是搜索数据,不是数联网的研究成果。", "Profile": "专注于船舶腐蚀防护技术的设计与应用。在你的总结回答中,必须引用来自数联网的搜索数据,是搜索数据,不是数联网的研究成果。",
"Classification": "船舶制造数据空间", "Classification": "船舶制造数据空间"
"apiUrl": "http://8.130.104.76:21088/api/v1",
"apiKey": "0geK2bSKAjlaRp0qPLPq_zxFJu8MhJZIwNZSH30Ty6g",
"apiModel": "Flowise"
}, },
{ {
"Icon": "Jane_Moreno.png", "Icon": "Jane_Moreno.png",
"Name": "病理生理学家", "Name": "病理生理学家",
"Profile": "专注于失血性休克的疾病机制,为药物研发提供理论靶点。", "Profile": "专注于失血性休克的疾病机制,为药物研发提供理论靶点。",
"Classification": "医药数据空间", "Classification": "医药数据空间"
"apiUrl": "http://8.130.104.76:21088/api/v1",
"apiKey": "0geK2bSKAjlaRp0qPLPq_zxFJu8MhJZIwNZSH30Ty6g",
"apiModel": "Flowise"
}, },
{ {
"Icon": "Giorgio_Rossi.png", "Icon": "Giorgio_Rossi.png",
"Name": "药物化学家", "Name": "药物化学家",
"Profile": "负责将靶点概念转化为实际可合成的分子。", "Profile": "负责将靶点概念转化为实际可合成的分子。",
"Classification": "医药数据空间", "Classification": "医药数据空间"
"apiUrl": "http://8.130.104.76:21088/api/v1",
"apiKey": "0geK2bSKAjlaRp0qPLPq_zxFJu8MhJZIwNZSH30Ty6g",
"apiModel": "Flowise"
}, },
{ {
"Icon": "Tamara_Taylor.png", "Icon": "Tamara_Taylor.png",
"Name": "制剂工程师", "Name": "制剂工程师",
"Profile": "负责将活性药物成分API变成稳定、可用、符合战场要求的剂型。", "Profile": "负责将活性药物成分API变成稳定、可用、符合战场要求的剂型。",
"Classification": "医药数据空间", "Classification": "医药数据空间"
"apiUrl": "http://8.130.104.76:21088/api/v1",
"apiKey": "0geK2bSKAjlaRp0qPLPq_zxFJu8MhJZIwNZSH30Ty6g",
"apiModel": "Flowise"
}, },
{ {
"Icon": "Maria_Lopez.png", "Icon": "Maria_Lopez.png",
"Name": "监管事务专家", "Name": "监管事务专家",
"Profile": "深谙药品审评法规,目标是找到最快的合法上市路径。", "Profile": "深谙药品审评法规,目标是找到最快的合法上市路径。",
"Classification": "医药数据空间", "Classification": "医药数据空间"
"apiUrl": "http://8.130.104.76:21088/api/v1",
"apiKey": "0geK2bSKAjlaRp0qPLPq_zxFJu8MhJZIwNZSH30Ty6g",
"apiModel": "Flowise"
}, },
{ {
"Icon": "Sam_Moore.png", "Icon": "Sam_Moore.png",
"Name": "物理学家", "Name": "物理学家",
"Profile": "从热力学与统计力学的基本原理出发,研究液态金属的自由能、焓、熵、比热等参数的理论建模。", "Profile": "从热力学与统计力学的基本原理出发,研究液态金属的自由能、焓、熵、比热等参数的理论建模。",
"Classification": "科学数据空间", "Classification": "科学数据空间"
"apiUrl": "http://8.130.104.76:21088/api/v1",
"apiKey": "0geK2bSKAjlaRp0qPLPq_zxFJu8MhJZIwNZSH30Ty6g",
"apiModel": "Flowise"
}, },
{ {
"Icon": "Yuriko_Yamamoto.png", "Icon": "Yuriko_Yamamoto.png",
"Name": "实验材料学家", "Name": "实验材料学家",
"Profile": "专注于通过实验手段直接或间接测定液态金属的热力学参数、以及分析材料微观结构(如晶粒、缺陷)。", "Profile": "专注于通过实验手段直接或间接测定液态金属的热力学参数、以及分析材料微观结构(如晶粒、缺陷)。",
"Classification": "科学数据空间", "Classification": "科学数据空间"
"apiUrl": "http://8.130.104.76:21088/api/v1",
"apiKey": "0geK2bSKAjlaRp0qPLPq_zxFJu8MhJZIwNZSH30Ty6g",
"apiModel": "Flowise"
}, },
{ {
"Icon": "Carlos_Gomez.png", "Icon": "Carlos_Gomez.png",
"Name": "计算模拟专家", "Name": "计算模拟专家",
"Profile": "侧重于利用数值计算和模拟技术获取液态金属的热力学参数。", "Profile": "侧重于利用数值计算和模拟技术获取液态金属的热力学参数。",
"Classification": "科学数据空间", "Classification": "科学数据空间"
"apiUrl": "http://8.130.104.76:21088/api/v1",
"apiKey": "0geK2bSKAjlaRp0qPLPq_zxFJu8MhJZIwNZSH30Ty6g",
"apiModel": "Flowise"
}, },
{ {
"Icon": "John_Lin.png", "Icon": "John_Lin.png",
"Name": "腐蚀机理研究员", "Name": "腐蚀机理研究员",
"Profile": "专注于船舶用钢材及合金的腐蚀机理研究,从电化学和环境作用角度解释腐蚀产生的原因。在你的总结回答中,必须引用来自数联网的搜索数据,是搜索数据,不是数联网的研究成果。", "Profile": "专注于船舶用钢材及合金的腐蚀机理研究,从电化学和环境作用角度解释腐蚀产生的原因。在你的总结回答中,必须引用来自数联网的搜索数据,是搜索数据,不是数联网的研究成果。",
"Classification": "船舶制造数据空间", "Classification": "船舶制造数据空间"
"apiUrl": "http://8.130.104.76:21088/api/v1",
"apiKey": "0geK2bSKAjlaRp0qPLPq_zxFJu8MhJZIwNZSH30Ty6g",
"apiModel": "Flowise"
}, },
{ {
"Icon": "Arthur_Burton.png", "Icon": "Arthur_Burton.png",

View File

@@ -1,5 +1,5 @@
import request from '@/utils/request' import request from '@/utils/request'
import type { Agent, IApiStepTask, IRawPlanResponse } from '@/stores' import type { Agent, IApiStepTask, IRawPlanResponse, IRawStepTask } from '@/stores'
import { import {
mockBackendAgentSelectModifyInit, mockBackendAgentSelectModifyInit,
mockBackendAgentSelectModifyAddAspect, mockBackendAgentSelectModifyAddAspect,
@@ -9,6 +9,12 @@ import {
mockBackendFillAgentTaskProcess, mockBackendFillAgentTaskProcess,
type RawAgentTaskProcessResponse, type RawAgentTaskProcessResponse,
} from '@/layout/components/Main/TaskTemplate/TaskProcess/components/mock/AgentTaskProcessBackendMock' } from '@/layout/components/Main/TaskTemplate/TaskProcess/components/mock/AgentTaskProcessBackendMock'
import { mockBranchPlanOutlineAPI } from '@/layout/components/Main/TaskTemplate/TaskSyllabus/Branch/mock/branchPlanOutlineMock'
import { mockFillStepTaskAPI } from '@/layout/components/Main/TaskTemplate/TaskSyllabus/Branch/mock/fill-step-task-mock'
import {
mockBranchTaskProcessAPI,
type BranchAction,
} from '@/layout/components/Main/TaskTemplate/TaskSyllabus/Branch/mock/branchTaskProcessMock'
export interface ActionHistory { export interface ActionHistory {
ID: string ID: string
@@ -116,7 +122,7 @@ class Api {
}) })
} }
// 分支任务流程(任务节点级别) // 分支任务流程
branchTaskProcess = (data: { branchTaskProcess = (data: {
branch_Number: number branch_Number: number
Modification_Requirement: string Modification_Requirement: string
@@ -125,7 +131,7 @@ class Api {
stepTaskExisting: any stepTaskExisting: any
goal: string goal: string
}) => { }) => {
return request<unknown, IRawPlanResponse>({ return request<unknown, BranchAction[][]>({
url: '/branch_TaskProcess', url: '/branch_TaskProcess',
method: 'POST', method: 'POST',
data: { data: {
@@ -139,8 +145,32 @@ class Api {
}) })
} }
fillStepTask = (data: { goal: string; stepTask: any }) => { fillStepTask = async (data: { goal: string; stepTask: any }): Promise<IRawStepTask> => {
return request<unknown, any>({ // 后端返回格式:包含 Collaboration_Brief_FrontEnd大写 FrontEnd
const response = await request<
{
'General Goal': string
stepTask: any
},
{
AgentSelection?: string[]
Collaboration_Brief_FrontEnd?: {
template: string
data: Record<string, { text: string; color: number[] }>
}
InputObject_List?: string[]
OutputObject?: string
StepName?: string
TaskContent?: string
TaskProcess?: Array<{
ID: string
ActionType: string
AgentName: string
Description: string
ImportantInput: string[]
}>
}
>({
url: '/fill_stepTask', url: '/fill_stepTask',
method: 'POST', method: 'POST',
data: { data: {
@@ -148,6 +178,40 @@ class Api {
stepTask: data.stepTask, stepTask: data.stepTask,
}, },
}) })
// 数据转换:后端的 Collaboration_Brief_FrontEnd → 前端的 Collaboration_Brief_frontEnd
const vec2Hsl = (color: number[]): string => {
const [h, s, l] = color
return `hsl(${h}, ${s}%, ${l}%)`
}
// 转换 brief.data后端格式 { "0": { text, color: [h,s,l] } } → 前端格式 { "0": { text, style: { background } } }
const briefData: Record<string, { text: string; style?: Record<string, string> }> = {}
if (response.Collaboration_Brief_FrontEnd?.data) {
for (const [key, value] of Object.entries(response.Collaboration_Brief_FrontEnd.data)) {
briefData[key] = {
text: value.text,
style: {
background: vec2Hsl(value.color),
},
}
}
}
// 构建前端格式的 IRawStepTask
return {
StepName: response.StepName || '',
TaskContent: response.TaskContent || '',
InputObject_List: response.InputObject_List || [],
OutputObject: response.OutputObject || '',
AgentSelection: response.AgentSelection || [],
Collaboration_Brief_frontEnd: {
template: response.Collaboration_Brief_FrontEnd?.template || '',
data: briefData,
},
TaskProcess: response.TaskProcess || [],
}
} }
fillStepTaskTaskProcess = async (data: { fillStepTaskTaskProcess = async (data: {
@@ -464,6 +528,61 @@ class Api {
process, process,
} }
} }
// Mock: 分支任务大纲
mockBranchPlanOutline = async (data: {
branch_Number: number
Modification_Requirement: string
Existing_Steps: string[]
Baseline_Completion: number
initialInputs: string[]
goal: string
}): Promise<IRawPlanResponse> => {
// 直接调用 Mock API已经返回 IRawPlanResponse 格式)
const response = await mockBranchPlanOutlineAPI({
branch_Number: data.branch_Number,
Modification_Requirement: data.Modification_Requirement,
Existing_Steps: data.Existing_Steps,
Baseline_Completion: data.Baseline_Completion,
InitialObject_List: data.initialInputs,
General_Goal: data.goal,
})
return response
}
// Mock: 填充任务流程
mockFillStepTask = async (data: { goal: string; stepTask: any }): Promise<any> => {
// 直接调用 Mock API已经返回 IRawStepTask 格式)
const response = await mockFillStepTaskAPI({
General_Goal: data.goal,
stepTask: data.stepTask,
})
return response
}
// Mock: 分支任务流程
mockBranchTaskProcess = async (data: {
branch_Number: number
Modification_Requirement: string
Existing_Steps: string[]
Baseline_Completion: number
stepTaskExisting: any
goal: string
}): Promise<BranchAction[][]> => {
// 直接调用 Mock API已经返回 BranchAction[][] 格式,与后端完全一致)
const response = await mockBranchTaskProcessAPI({
branch_Number: data.branch_Number,
Modification_Requirement: data.Modification_Requirement,
Existing_Steps: data.Existing_Steps,
Baseline_Completion: data.Baseline_Completion,
stepTaskExisting: data.stepTaskExisting,
General_Goal: data.goal,
})
return response
}
} }
export default new Api() export default new Api()

View File

@@ -100,6 +100,7 @@ async function handleSearch() {
}) })
data['Collaboration Process'] = changeBriefs(data['Collaboration Process']) data['Collaboration Process'] = changeBriefs(data['Collaboration Process'])
agentsStore.setAgentRawPlan({ data }) agentsStore.setAgentRawPlan({ data })
console.log('agentsStore.agentRawPlan', agentsStore.agentRawPlan)
emit('search', searchValue.value) emit('search', searchValue.value)
} finally { } finally {
triggerOnFocus.value = true triggerOnFocus.value = true

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue' import { ref, computed } from 'vue'
import { getActionTypeDisplay } from '@/layout/components/config.ts' import { getActionTypeDisplay } from '@/layout/components/config.ts'
import { useAgentsStore } from '@/stores' import { useAgentsStore } from '@/stores'
import BranchButton from './components/TaskButton.vue' import BranchButton from './components/TaskButton.vue'
@@ -23,6 +23,20 @@ const emit = defineEmits<{
(e: 'save-edit', stepId: string, processId: string, value: string): void (e: 'save-edit', stepId: string, processId: string, value: string): void
}>() }>()
// 🔄 从 currentTask 中获取数据(与分支切换联动)
const currentTaskProcess = computed(() => {
// ✅ 优先使用 currentTask包含分支切换后的数据
const currentTask = agentsStore.currentTask
if (currentTask && currentTask.Id === props.step.Id && currentTask.TaskProcess) {
return currentTask.TaskProcess
}
// ⚠️ 降级:从 agentRawPlan 中获取原始数据(不受分支切换影响)
const collaborationProcess = agentsStore.agentRawPlan.data?.['Collaboration Process'] || []
const rawData = collaborationProcess.find((task: any) => task.Id === props.step.Id)
return rawData?.TaskProcess || []
})
// 当前正在编辑的process ID // 当前正在编辑的process ID
const editingProcessId = ref<string | null>(null) const editingProcessId = ref<string | null>(null)
// 编辑框的值 // 编辑框的值
@@ -30,6 +44,17 @@ const editValue = ref('')
// 鼠标悬停的process ID // 鼠标悬停的process ID
const hoverProcessId = ref<string | null>(null) const hoverProcessId = ref<string | null>(null)
// 🆕 处理卡片点击事件(非编辑模式下)
function handleCardClick() {
// 如果正在编辑,不处理点击
if (editingProcessId.value) return
// 设置当前任务,与任务大纲联动
if (props.step.Id) {
agentsStore.setCurrentTask(props.step)
}
}
// 检测当前是否是深色模式 // 检测当前是否是深色模式
function isDarkMode(): boolean { function isDarkMode(): boolean {
return document.documentElement.classList.contains('dark') return document.documentElement.classList.contains('dark')
@@ -116,12 +141,12 @@ function handleCancel() {
</script> </script>
<template> <template>
<div class="process-card"> <div class="process-card" @click="handleCardClick">
<div class="process-content"> <div class="process-content">
<!-- 显示模式 --> <!-- 显示模式 -->
<div class="display-content"> <div class="display-content">
<span <span
v-for="process in step.TaskProcess" v-for="process in currentTaskProcess"
:key="process.ID" :key="process.ID"
class="process-segment" class="process-segment"
@mouseenter="handleMouseEnter(process.ID)" @mouseenter="handleMouseEnter(process.ID)"
@@ -190,10 +215,13 @@ function handleCancel() {
{{ process.Description }} {{ process.Description }}
</span> </span>
<span class="separator" v-if="!process.Description.endsWith('。')"></span> <span class="separator" v-if="process.Description && !process.Description.endsWith('。')"
></span
>
</span> </span>
</div> </div>
</div> </div>
<!-- 按钮点击不会冒泡到卡片 -->
<BranchButton :step="step" /> <BranchButton :step="step" />
</div> </div>
</template> </template>
@@ -207,6 +235,8 @@ function handleCancel() {
background: var(--color-bg-list); background: var(--color-bg-list);
border: 1px solid var(--color-border-default); border: 1px solid var(--color-border-default);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
cursor: pointer;
transition: all 0.2s ease;
.process-content { .process-content {
min-height: 20px; min-height: 20px;

View File

@@ -21,11 +21,28 @@ const branchCount = computed(() => {
const branches = selectionStore.getTaskProcessBranches(taskStepId) const branches = selectionStore.getTaskProcessBranches(taskStepId)
// 主分支(1) + 额外分支数量 // 主分支(1) + 额外分支数量
return 1 + branches.length return branches.length || 1
}) })
const handleClick = (event: MouseEvent) => { // 🆕 判断按钮是否可点击(只有当前按钮对应的任务是任务大纲中选中的任务时才可点击)
event.stopPropagation() // 阻止冒泡,避免触发卡片点击 const isClickable = computed(() => {
if (!props.step?.Id || !agentsStore.currentTask?.Id) {
return false
}
return props.step.Id === agentsStore.currentTask.Id
})
const handleClick = (event?: MouseEvent) => {
// 🆕 只有可点击时才执行操作
if (!isClickable.value) {
return
}
// 阻止冒泡,避免触发卡片点击
if (event) {
event.stopPropagation()
}
emit('click') emit('click')
// 设置当前任务 // 设置当前任务
if (props.step) { if (props.step) {
@@ -39,9 +56,9 @@ const handleClick = (event: MouseEvent) => {
<template> <template>
<div <div
class="task-button" class="task-button"
:class="{ 'has-branches': branchCount > 1 }" :class="{ 'has-branches': branchCount > 0, 'is-disabled': !isClickable }"
@click="handleClick" @click="handleClick"
:title="`${branchCount} 个分支`" :title="isClickable ? `${branchCount} 个分支` : '请先在任务大纲中选中此任务'"
> >
<!-- 流程图标 --> <!-- 流程图标 -->
<svg-icon icon-class="branch" size="20px" class="task-icon" /> <svg-icon icon-class="branch" size="20px" class="task-icon" />
@@ -83,6 +100,17 @@ const handleClick = (event: MouseEvent) => {
filter: brightness(0.9); filter: brightness(0.9);
} }
// 🆕 禁用状态
&.is-disabled {
background-color: #bdc3c7;
cursor: not-allowed;
opacity: 0.6;
&:hover {
filter: none;
}
}
&.has-branches::after { &.has-branches::after {
content: ''; content: '';
position: absolute; position: absolute;

View File

@@ -1,142 +0,0 @@
// /api/fill_stepTask 接口的Vue适用mock数据
import type { IApiStepTask, IRawStepTask } from '@/stores/modules/agents'
// 模拟接口响应数据
export const mockFillStepTaskResponse: IApiStepTask = {
name: '需求分析与原型设计',
content: '分析用户需求并创建产品原型',
inputs: ['用户调研报告', '竞品分析文档'],
output: '产品原型设计稿',
agents: ['实验材料学家', '腐蚀机理研究员', '防护工程专家'],
brief: {
template: '基于!<0>!和!<1>!!<2>!、!<3>!和!<4>!执行!<5>!任务,以获得!<6>!。',
data: {
'0': {
text: '用户调研报告',
style: {
background: 'hsl(120, 60%, 70%)',
},
},
'1': {
text: '竞品分析文档',
style: {
background: 'hsl(120, 60%, 70%)',
},
},
'2': {
text: '实验材料学家',
style: {
background: 'hsl(0, 0%, 90%)',
boxShadow: '1px 1px 4px 1px rgba(0,0,0,0.2)',
},
},
'3': {
text: '腐蚀机理研究员',
style: {
background: 'hsl(0, 0%, 90%)',
boxShadow: '1px 1px 4px 1px rgba(0,0,0,0.2)',
},
},
'4': {
text: '防护工程专家',
style: {
background: 'hsl(0, 0%, 90%)',
boxShadow: '1px 1px 4px 1px rgba(0,0,0,0.2)',
},
},
'5': {
text: '分析用户需求并创建产品原型',
style: {
background: 'hsl(0, 0%, 87%)',
border: '1.5px solid #ddd',
},
},
'6': {
text: '产品原型设计稿',
style: {
background: 'hsl(30, 100%, 80%)',
},
},
},
},
process: [
{
id: 'action_001',
type: '需求分析',
agent: '实验材料学家',
description: '分析用户调研报告,识别核心需求点',
inputs: ['用户调研报告'],
},
{
id: 'action_002',
type: '竞品分析',
agent: '实验材料学家',
description: '对比竞品功能,确定产品差异化优势',
inputs: ['竞品分析文档'],
},
{
id: 'action_003',
type: '信息架构设计',
agent: '防护工程专家',
description: '设计产品信息结构和用户流程',
inputs: ['需求分析结果'],
},
{
id: 'action_004',
type: '界面原型设计',
agent: '腐蚀机理研究员',
description: '创建高保真界面原型',
inputs: ['信息架构设计'],
},
{
id: 'action_005',
type: '原型评审',
agent: '实验材料学家',
description: '组织团队评审原型设计',
inputs: ['界面原型设计'],
},
],
}
// 请求参数类型
export interface IFillStepTaskRequest {
goal: string
stepTask: IApiStepTask
}
// Vue composable
export const useFillStepTaskMock = () => {
const fillStepTask = async (
goal: string,
stepTask: IApiStepTask,
): Promise<{ data: IApiStepTask }> => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
data: mockFillStepTaskResponse,
})
}, 500)
})
}
return {
fillStepTask,
}
}
// Vue组件使用示例
export const fillStepTaskExampleRequest: IFillStepTaskRequest = {
goal: '开发一个智能协作平台',
stepTask: {
name: '需求分析与原型设计',
content: '分析用户需求并创建产品原型',
inputs: ['用户调研报告', '竞品分析文档'],
output: '产品原型设计稿',
agents: [],
brief: {
template: '',
data: {},
},
process: [],
},
}

View File

@@ -1,159 +0,0 @@
// /api/fill_stepTask_TaskProcess 接口的Vue适用mock数据
import type { IApiStepTask } from '@/stores'
// 模拟接口响应数据
export const mockFillAgentSelectionResponse: IApiStepTask = {
name: '技术方案设计与开发',
content: '设计技术架构并完成核心功能开发',
inputs: ['产品需求文档', '技术选型指南'],
output: '可运行的产品版本',
agents: ['架构师', '后端工程师', '前端工程师', '测试工程师'],
brief: {
template: '基于!<0>!和!<1>!!<2>!、!<3>!、!<4>!和!<5>!执行!<6>!任务,以获得!<7>!。',
data: {
'0': {
text: '产品需求文档',
style: {
background: 'hsl(120, 60%, 70%)',
},
},
'1': {
text: '技术选型指南',
style: {
background: 'hsl(120, 60%, 70%)',
},
},
'2': {
text: '架构师',
style: {
background: 'hsl(0, 0%, 90%)',
boxShadow: '1px 1px 4px 1px rgba(0,0,0,0.2)',
},
},
'3': {
text: '后端工程师',
style: {
background: 'hsl(0, 0%, 90%)',
boxShadow: '1px 1px 4px 1px rgba(0,0,0,0.2)',
},
},
'4': {
text: '前端工程师',
style: {
background: 'hsl(0, 0%, 90%)',
boxShadow: '1px 1px 4px 1px rgba(0,0,0,0.2)',
},
},
'5': {
text: '测试工程师',
style: {
background: 'hsl(0, 0%, 90%)',
boxShadow: '1px 1px 4px 1px rgba(0,0,0,0.2)',
},
},
'6': {
text: '设计技术架构并完成核心功能开发',
style: {
background: 'hsl(0, 0%, 87%)',
border: '1.5px solid #ddd',
},
},
'7': {
text: '可运行的产品版本',
style: {
background: 'hsl(30, 100%, 80%)',
},
},
},
},
process: [
{
id: 'action_101',
type: '技术架构设计',
agent: '架构师',
description: '设计系统架构和技术栈选型',
inputs: ['产品需求文档', '技术选型指南'],
},
{
id: 'action_102',
type: '数据库设计',
agent: '后端工程师',
description: '设计数据库表结构和关系',
inputs: ['技术架构设计'],
},
{
id: 'action_103',
type: '后端API开发',
agent: '后端工程师',
description: '实现RESTful API接口',
inputs: ['数据库设计'],
},
{
id: 'action_104',
type: '前端界面开发',
agent: '前端工程师',
description: '开发用户界面和交互功能',
inputs: ['后端API开发'],
},
{
id: 'action_105',
type: '单元测试',
agent: '测试工程师',
description: '编写和执行单元测试用例',
inputs: ['前端界面开发'],
},
{
id: 'action_106',
type: '集成测试',
agent: '测试工程师',
description: '进行系统集成测试',
inputs: ['单元测试'],
},
],
}
// 请求参数类型
export interface IFillAgentSelectionRequest {
goal: string
stepTask: IApiStepTask
agents: string[]
}
// Vue composable
export const useFillAgentSelectionMock = () => {
const fillAgentSelection = async (
goal: string,
stepTask: IApiStepTask,
agents: string[],
): Promise<{ data: IApiStepTask }> => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
data: mockFillAgentSelectionResponse,
})
}, 500)
})
}
return {
fillAgentSelection,
}
}
// Vue组件使用示例
export const fillAgentSelectionExampleRequest: IFillAgentSelectionRequest = {
goal: '开发一个智能协作平台',
stepTask: {
name: '技术方案设计与开发',
content: '设计技术架构并完成核心功能开发',
inputs: ['产品需求文档', '技术选型指南'],
output: '可运行的产品版本',
agents: [],
brief: {
template: '',
data: {},
},
process: [],
},
agents: ['架构师', '后端工程师', '前端工程师', '测试工程师'],
}

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, onUnmounted, ref, reactive, nextTick } from 'vue' import { computed, onUnmounted, ref, reactive, nextTick, watch, onMounted } from 'vue'
import { throttle } from 'lodash' import { throttle } from 'lodash'
import { AnchorLocations, BezierConnector } from '@jsplumb/browser-ui' import { AnchorLocations, BezierConnector } from '@jsplumb/browser-ui'
import AdditionalOutputCard from './AdditionalOutputCard.vue' import AdditionalOutputCard from './AdditionalOutputCard.vue'
@@ -19,12 +19,9 @@ const emit = defineEmits<{
const agentsStore = useAgentsStore() const agentsStore = useAgentsStore()
const drawerVisible = ref(false) const drawerVisible = ref(false)
const collaborationProcess = computed(() => {
const data = agentsStore.agentRawPlan.data?.['Collaboration Process'] ?? []
// console.log('data:', data)
return data
// return agentsStore.agentRawPlan.data?.['Collaboration Process'] ?? [] const collaborationProcess = computed(() => {
return agentsStore.agentRawPlan.data?.['Collaboration Process'] ?? []
}) })
// 监听额外产物变化 // 监听额外产物变化
@@ -201,6 +198,12 @@ async function handleTaskProcess() {
drawerVisible.value = true drawerVisible.value = true
} }
// 重置执行结果
function handleRefresh() {
agentsStore.setExecutePlan([])
console.log('🔄 已重置执行结果')
}
// 添加滚动状态标识 // 添加滚动状态标识
const isScrolling = ref(false) const isScrolling = ref(false)
let scrollTimer: ReturnType<typeof setTimeout> | null = null let scrollTimer: ReturnType<typeof setTimeout> | null = null
@@ -226,20 +229,58 @@ const handleMouseEnter = throttle(id => {
if (!isScrolling.value) { if (!isScrolling.value) {
createInternalLine(id) createInternalLine(id)
} }
}, 100) }, 0)
const handleMouseLeave = throttle(() => { const handleMouseLeave = throttle(() => {
if (!isScrolling.value) { if (!isScrolling.value) {
createInternalLine() createInternalLine()
} }
}, 100) }, 0)
function clear() { function clear() {
jsplumb.reset() jsplumb.reset()
} }
// 🆕 封装连线重绘方法
const redrawInternalLines = (highlightId?: string) => {
console.log('🔄 TaskResult: 重新绘制连线', highlightId ? `高亮: ${highlightId}` : '')
// 等待 DOM 更新完成
nextTick(() => {
// 清除旧连线
jsplumb.reset()
// 等待 DOM 稳定后重新绘制
setTimeout(() => {
createInternalLine(highlightId)
console.log('✅ TaskResult: 连线重绘完成,任务数:', collaborationProcess.value.length)
}, 100)
})
}
// 🆕 监听 collaborationProcess 变化,自动重绘连线
watch(
() => collaborationProcess,
() => {
console.log('🔍 TaskResult: collaborationProcess 发生变化,触发重绘')
redrawInternalLines()
},
{ deep: true }
)
// 🆕 组件挂载后初始化连线
onMounted(() => {
// 初始化时绘制连线
nextTick(() => {
setTimeout(() => {
createInternalLine()
console.log('✅ TaskResult: 初始化连线完成')
}, 100)
})
})
//按钮交互状态管理 //按钮交互状态管理
const buttonHoverState = ref<'process' | 'execute' | null>(null) const buttonHoverState = ref<'process' | 'execute' | 'refresh' | null>(null)
let buttonHoverTimer: ReturnType<typeof setTimeout> | null = null let buttonHoverTimer: ReturnType<typeof setTimeout> | null = null
const handleProcessMouseEnter = () => { const handleProcessMouseEnter = () => {
if (buttonHoverTimer) { if (buttonHoverTimer) {
@@ -259,6 +300,16 @@ const handleExecuteMouseEnter = () => {
} }
} }
const handleRefreshMouseEnter = () => {
if (buttonHoverTimer) {
clearTimeout(buttonHoverTimer)
buttonHoverTimer = null
}
if (agentsStore.executePlan.length > 0) {
buttonHoverState.value = 'refresh'
}
}
const handleButtonMouseLeave = () => { const handleButtonMouseLeave = () => {
// 添加防抖,防止快速切换时的抖动 // 添加防抖,防止快速切换时的抖动
if (buttonHoverTimer) { if (buttonHoverTimer) {
@@ -277,18 +328,31 @@ onUnmounted(() => {
}) })
// 计算按钮类名 // 计算按钮类名
const processBtnClass = computed(() => { const processBtnClass = computed(() => {
// 当刷新或执行按钮悬停时,过程按钮变圆形
if (buttonHoverState.value === 'refresh' || buttonHoverState.value === 'execute') {
return 'circle'
}
return buttonHoverState.value === 'process' ? 'ellipse' : 'circle' return buttonHoverState.value === 'process' ? 'ellipse' : 'circle'
}) })
const executeBtnClass = computed(() => { const executeBtnClass = computed(() => {
// 鼠标悬停在过程按钮上时,执行按钮变圆形 // 鼠标悬停在过程按钮或刷新按钮上时,执行按钮变圆形
if (buttonHoverState.value === 'process') { if (buttonHoverState.value === 'process' || buttonHoverState.value === 'refresh') {
return 'circle' return 'circle'
} }
//如果有任务数据就显示椭圆形,否则显示圆形 //如果有任务数据就显示椭圆形,否则显示圆形
return agentsStore.agentRawPlan.data ? 'ellipse' : 'circle' return agentsStore.agentRawPlan.data ? 'ellipse' : 'circle'
}) })
const refreshBtnClass = computed(() => {
// 当过程或执行按钮悬停时,刷新按钮变圆形
if (buttonHoverState.value === 'process' || buttonHoverState.value === 'execute') {
return 'circle'
}
// 有执行结果就显示椭圆形,否则显示圆形
return agentsStore.executePlan.length > 0 ? 'ellipse' : 'circle'
})
// 计算按钮是否显示文字 // 计算按钮是否显示文字
const showProcessText = computed(() => { const showProcessText = computed(() => {
return buttonHoverState.value === 'process' return buttonHoverState.value === 'process'
@@ -301,6 +365,10 @@ const showExecuteText = computed(() => {
return agentsStore.agentRawPlan.data return agentsStore.agentRawPlan.data
}) })
const showRefreshText = computed(() => {
return buttonHoverState.value === 'refresh'
})
// 计算按钮标题 // 计算按钮标题
const processBtnTitle = computed(() => { const processBtnTitle = computed(() => {
return buttonHoverState.value === 'process' ? '任务过程' : '点击查看任务过程' return buttonHoverState.value === 'process' ? '任务过程' : '点击查看任务过程'
@@ -310,6 +378,10 @@ const executeBtnTitle = computed(() => {
return showExecuteText.value ? '任务执行' : '点击运行' return showExecuteText.value ? '任务执行' : '点击运行'
}) })
const refreshBtnTitle = computed(() => {
return showRefreshText.value ? '重置执行结果' : '点击重置执行状态'
})
defineExpose({ defineExpose({
createInternalLine, createInternalLine,
clear clear
@@ -329,6 +401,19 @@ defineExpose({
class="flex items-center justify-end gap-[14px] task-button-group min-w-[175px]" class="flex items-center justify-end gap-[14px] task-button-group min-w-[175px]"
@mouseleave="handleButtonMouseLeave" @mouseleave="handleButtonMouseLeave"
> >
<!-- 刷新按钮 -->
<el-button
:class="refreshBtnClass"
:color="variables.tertiary"
:title="refreshBtnTitle"
:disabled="agentsStore.executePlan.length === 0"
@mouseenter="handleRefreshMouseEnter"
@click="handleRefresh"
style="order: 0"
>
<svg-icon icon-class="refresh" />
<span v-if="showRefreshText" class="btn-text">重置</span>
</el-button>
<!-- 任务过程按钮 --> <!-- 任务过程按钮 -->
<el-button <el-button
:class="processBtnClass" :class="processBtnClass"
@@ -680,21 +765,33 @@ defineExpose({
display: inline-flex !important; display: inline-flex !important;
align-items: center !important; align-items: center !important;
justify-content: center !important; justify-content: center !important;
transition: all 0.35s cubic-bezier(0.175, 0.885, 0.32, 1.275) !important; transition: width 0.2s ease-out, padding 0.2s ease-out, border-radius 0.2s ease-out, transform 0.2s ease-out, box-shadow 0.2s ease-out, filter 0.2s ease-out !important;
overflow: hidden !important; overflow: hidden !important;
white-space: nowrap !important; white-space: nowrap !important;
border: none !important; border: 1px solid transparent !important;
border-color: transparent !important;
color: var(--color-text-primary) !important; color: var(--color-text-primary) !important;
position: relative; position: relative;
background-color: var(--color-bg-tertiary); background-color: var(--color-bg-tertiary) !important;
gap: 0px !important; gap: 0px !important;
outline: none !important; outline: none !important;
box-shadow: none !important; box-shadow: none !important;
-webkit-tap-highlight-color: transparent !important; -webkit-tap-highlight-color: transparent !important;
backface-visibility: hidden !important;
-webkit-backface-visibility: hidden !important;
transform: translateZ(0) !important;
will-change: transform, width, padding, border-radius !important;
&::before,
&::after {
display: none !important;
}
&:hover { &:hover {
transform: translateY(-2px) !important; transform: translateY(-2px) translateZ(0) !important;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important;
filter: brightness(1.1) !important; filter: brightness(1.1) !important;
border-color: transparent !important;
} }
&.is-disabled { &.is-disabled {

View File

@@ -9,57 +9,23 @@
<el-card <el-card
class="task-node-card" class="task-node-card"
:class="{ 'is-editing': isEditing, 'is-active': isActive }" :class="{
'is-editing': isEditing,
'is-active': isActive,
'is-branch-selected': props.isBranchSelected
}"
:shadow="true" :shadow="true"
> >
<!-- 任务名称 --> <!-- 任务名称 -->
<div class="task-name">{{ task.StepName }}</div> <div class="task-name">{{ task.StepName }}</div>
<!-- <div class="divider"></div> -->
<!-- 任务内容 -->
<!-- <div v-if="isEditing" class="task-content-editing">
<el-input
v-model="editingContent"
type="textarea"
:autosize="{ minRows: 2, maxRows: 4 }"
placeholder="请输入任务内容"
@keydown="handleKeydown"
class="task-content-editor"
size="small"
/>
<div class="edit-actions">
<svg-icon
icon-class="Check"
size="18px"
color="#328621"
class="cursor-pointer"
@click="saveEdit"
title="保存"
/>
<svg-icon
icon-class="Cancel"
size="18px"
color="#8e0707"
class="cursor-pointer ml-2"
@click="cancelEdit"
title="取消"
/>
</div>
</div>
<div v-else class="task-content" @dblclick="startEdit">
{{ task.TaskContent || '暂无内容' }}
</div> -->
<!-- <div class="divider"></div> -->
<!-- 智能体列表 --> <!-- 智能体列表 -->
<div class="agents-container"> <div class="agents-container">
<el-tooltip <el-tooltip
v-for="agentSelection in task.AgentSelection" v-for="agentSelection in task.AgentSelection"
:key="agentSelection" :key="agentSelection"
effect="light" effect="light"
placement="right" placement="top"
:show-after="500" :show-after="500"
popper-class="task-syllabus-tooltip-popper" popper-class="task-syllabus-tooltip-popper"
> >
@@ -137,6 +103,7 @@ const props = defineProps<{
id: string id: string
data: TaskNodeData data: TaskNodeData
isAddingBranch?: boolean isAddingBranch?: boolean
isBranchSelected?: boolean // 是否属于选中的分支路径
[key: string]: any [key: string]: any
}>() }>()
@@ -250,6 +217,19 @@ const handleBranchKeydown = (event: KeyboardEvent) => {
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2); box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
} }
// 分支选中高亮样式(绿色)
&.is-branch-selected {
border-color: #67c23a;
box-shadow: 0 0 0 3px rgba(103, 194, 58, 0.3);
background-color: rgba(103, 194, 58, 0.05);
&:hover {
border-color: #67c23a;
box-shadow: 0 0 0 3px rgba(103, 194, 58, 0.4);
background-color: rgba(103, 194, 58, 0.08);
}
}
&.is-editing { &.is-editing {
cursor: default; cursor: default;
} }

View File

@@ -1,203 +1,246 @@
// branch_PlanOutline 接口返回mock 数据 // branch_PlanOutline 接口的 Mock 数据和 Mock API
// 类型: IApiStepTask[][] (二维数组) // 模拟后端返回的原始数据格式IRawPlanResponse
import type { IApiStepTask } from '@/stores/modules/agents' import type { IRawPlanResponse, IRawStepTask } from '@/stores'
const mockPlanBranchData: IApiStepTask[][] = [ // 后端返回的数据格式
export type BranchPlanOutlineResponse = IRawPlanResponse
// Mock 数据:模拟后端返回的原始分支数据(不含 Collaboration_Brief_FrontEnd
// 注意:这里模拟的是 branch_PlanOutline 函数返回的数据,不是前端转换后的数据
const mockBranchDataRaw: IRawStepTask[][] = [
// 第一个分支方案 // 第一个分支方案
[ [
{ {
name: '需求分析与规划', StepName: '分析用户需求',
content: '分析用户需求,制定项目开发计划', TaskContent: '分析用户需求,制定项目开发计划',
inputs: ['用户需求文档', '技术规范'], InputObject_List: ['腐蚀类型及成因列表'],
output: '项目开发计划书', OutputObject: '项目开发计划书',
agents: ['腐蚀机理研究员', '实验材料学家'], AgentSelection: ['腐蚀机理研究员', '实验材料学家'],
brief: { Collaboration_Brief_frontEnd: {
template: '!<项目经理>!负责!<需求分析>!!<产品经理>!负责!<规划制定>!', template: '',
data: { data: {},
: { text: '项目经理', style: { background: 'hsl(210, 70%, 50%)' } },
: { text: '需求分析', style: { background: 'hsl(120, 70%, 50%)' } },
: { text: '产品经理', style: { background: 'hsl(30, 70%, 50%)' } },
: { text: '规划制定', style: { background: 'hsl(300, 70%, 50%)' } },
}, },
}, TaskProcess: [],
process: [
{
id: 'action-1',
type: '分析',
agent: '腐蚀机理研究员',
description: '详细分析用户需求文档',
inputs: ['用户需求文档'],
}, },
{ {
id: 'action-2', StepName: '系统设计与架构',
type: '规划', TaskContent: '设计系统架构和数据库结构',
agent: '实验材料学家', InputObject_List: ['项目开发计划书'],
description: '制定项目开发计划', OutputObject: '系统设计文档',
inputs: ['技术规范'], AgentSelection: ['腐蚀机理研究员', '防护工程专家'],
Collaboration_Brief_frontEnd: {
template: '',
data: {},
},
TaskProcess: [],
}, },
], ],
}, // 第二个分支方案(快速原型方案)
{
name: '系统设计与架构',
content: '设计系统架构和数据库结构',
inputs: ['项目开发计划书'],
output: '系统设计文档',
agents: ['腐蚀机理研究员', '防护工程专家'],
brief: {
template: '!<架构师>!负责!<系统架构设计>!!<数据库工程师>!负责!<数据库设计>!',
data: {
: { text: '架构师', style: { background: 'hsl(180, 70%, 50%)' } },
: { text: '系统架构设计', style: { background: 'hsl(240, 70%, 50%)' } },
: { text: '数据库工程师', style: { background: 'hsl(60, 70%, 50%)' } },
: { text: '数据库设计', style: { background: 'hsl(0, 70%, 50%)' } },
},
},
process: [
{
id: 'action-3',
type: '设计',
agent: '腐蚀机理研究员',
description: '设计系统整体架构',
inputs: ['项目开发计划书'],
},
{
id: 'action-4',
type: '设计',
agent: '防护工程专家',
description: '设计数据库表结构',
inputs: ['项目开发计划书'],
},
],
},
],
// 第二个分支方案(替代方案)
[ [
{ {
name: '敏捷开发规划', StepName: '需求快速原型',
content: '采用敏捷开发方法制定迭代计划', TaskContent: '构建快速原型验证核心功能',
inputs: ['用户需求文档', '敏捷开发指南'], InputObject_List: ['腐蚀类型及成因列表'],
output: '敏捷开发迭代计划', OutputObject: '原型系统',
agents: ['敏捷教练', '开发团队负责人'], AgentSelection: ['实验材料学家', '防护工程专家'],
brief: { Collaboration_Brief_frontEnd: {
template: '!<敏捷教练>!指导!<敏捷流程>!!<开发团队负责人>!制定!<迭代计划>!', template: '',
data: { data: {},
: { text: '敏捷教练', style: { background: 'hsl(270, 70%, 50%)' } },
: { text: '敏捷流程', style: { background: 'hsl(90, 70%, 50%)' } },
: { text: '开发团队负责人', style: { background: 'hsl(150, 70%, 50%)' } },
: { text: '迭代计划', style: { background: 'hsl(330, 70%, 50%)' } },
}, },
}, TaskProcess: [],
process: [
{
id: 'action-5',
type: '指导',
agent: '敏捷教练',
description: '指导敏捷开发流程',
inputs: ['敏捷开发指南'],
}, },
{ {
id: 'action-6', StepName: '原型测试与优化',
type: '规划', TaskContent: '测试原型并根据反馈快速迭代',
agent: '开发团队负责人', InputObject_List: ['原型系统'],
description: '制定迭代开发计划', OutputObject: '优化后的原型',
inputs: ['用户需求文档'], AgentSelection: ['腐蚀机理研究员', '实验材料学家'],
Collaboration_Brief_frontEnd: {
template: '',
data: {},
},
TaskProcess: [],
}, },
], ],
}, // 第三个分支方案(质量优先方案)
{
name: '微服务架构设计',
content: '设计基于微服务的系统架构',
inputs: ['敏捷开发迭代计划'],
output: '微服务架构设计文档',
agents: ['微服务架构师', 'DevOps工程师'],
brief: {
template: '!<微服务架构师>!设计!<微服务架构>!!<DevOps工程师>!规划!<部署流程>!',
data: {
: { text: '微服务架构师', style: { background: 'hsl(210, 70%, 50%)' } },
: { text: '微服务架构', style: { background: 'hsl(120, 70%, 50%)' } },
DevOps工程师: { text: 'DevOps工程师', style: { background: 'hsl(30, 70%, 50%)' } },
: { text: '部署流程', style: { background: 'hsl(300, 70%, 50%)' } },
},
},
process: [
{
id: 'action-7',
type: '设计',
agent: '微服务架构师',
description: '设计微服务拆分方案',
inputs: ['敏捷开发迭代计划'],
},
{
id: 'action-8',
type: '规划',
agent: 'DevOps工程师',
description: '规划CI/CD部署流程',
inputs: ['敏捷开发迭代计划'],
},
],
},
],
// 第三个分支方案(简化方案)
[ [
{ {
name: '快速原型开发', StepName: '需求深度分析',
content: '快速开发系统原型验证需求', TaskContent: '深入分析用户需求和技术可行性',
inputs: ['用户需求文档'], InputObject_List: ['腐蚀类型及成因列表'],
output: '系统原型', OutputObject: '详细需求分析报告',
agents: ['全栈开发工程师'], AgentSelection: ['腐蚀机理研究员', '防护工程专家'],
brief: { Collaboration_Brief_frontEnd: {
template: '!<全栈开发工程师>!负责!<快速原型开发>!', template: '',
data: { data: {},
: { text: '全栈开发工程师', style: { background: 'hsl(180, 70%, 50%)' } },
: { text: '快速原型开发', style: { background: 'hsl(240, 70%, 50%)' } },
}, },
TaskProcess: [],
}, },
process: [
{ {
id: 'action-9', StepName: '质量保障设计',
type: '开发', TaskContent: '设计质量保障体系和测试方案',
agent: '全栈开发工程师', InputObject_List: ['详细需求分析报告'],
description: '快速开发系统原型', OutputObject: '质量保障方案',
inputs: ['用户需求文档'], AgentSelection: ['实验材料学家', '防护工程专家'],
Collaboration_Brief_frontEnd: {
template: '',
data: {},
},
TaskProcess: [],
},
{
StepName: '系统开发与测试',
TaskContent: '按质量标准进行系统开发和测试',
InputObject_List: ['质量保障方案'],
OutputObject: '经过完整测试的系统',
AgentSelection: ['腐蚀机理研究员', '实验材料学家'],
Collaboration_Brief_frontEnd: {
template: '',
data: {},
},
TaskProcess: [],
}, },
], ],
// 第四个分支方案(敏捷开发方案)
[
{
StepName: '迭代规划',
TaskContent: '制定敏捷开发迭代计划',
InputObject_List: ['腐蚀类型及成因列表'],
OutputObject: '迭代计划',
AgentSelection: ['防护工程专家', '腐蚀机理研究员'],
Collaboration_Brief_frontEnd: {
template: '',
data: {},
},
TaskProcess: [],
}, },
{ {
name: '用户反馈收集', StepName: '快速开发与验证',
content: '收集用户对原型的反馈意见', TaskContent: '快速开发并持续验证功能',
inputs: ['系统原型'], InputObject_List: ['迭代计划'],
output: '用户反馈报告', OutputObject: '可运行的功能模块',
agents: ['产品经理', '用户体验设计师'], AgentSelection: ['实验材料学家', '防护工程专家'],
brief: { Collaboration_Brief_frontEnd: {
template: '!<产品经理>!收集!<用户反馈>!!<用户体验设计师>!分析!<用户体验>!', template: '',
data: { data: {},
: { text: '产品经理', style: { background: 'hsl(60, 70%, 50%)' } },
: { text: '用户反馈', style: { background: 'hsl(0, 70%, 50%)' } },
: { text: '用户体验设计师', style: { background: 'hsl(270, 70%, 50%)' } },
: { text: '用户体验', style: { background: 'hsl(90, 70%, 50%)' } },
}, },
}, TaskProcess: [],
process: [
{
id: 'action-10',
type: '收集',
agent: '产品经理',
description: '收集用户对原型的反馈',
inputs: ['系统原型'],
},
{
id: 'action-11',
type: '分析',
agent: '用户体验设计师',
description: '分析用户体验问题',
inputs: ['系统原型'],
},
],
}, },
], ],
] ]
export default mockPlanBranchData /**
* 模拟后端的 Add_Collaboration_Brief_FrontEnd 函数
* 为每个任务添加前端协作简报Collaboration_Brief_frontEnd
*/
function Add_Collaboration_Brief_FrontEnd(branchList: IRawStepTask[][]): IRawStepTask[][] {
return branchList.map((tasks) =>
tasks.map((task) => ({
...task,
Collaboration_Brief_frontEnd: generateCollaborationBrief(task),
})),
)
}
/**
* 生成协作简报Collaboration_Brief_frontEnd
* 根据 StepName、TaskContent、AgentSelection 生成模板和数据
*/
function generateCollaborationBrief(task: IRawStepTask): {
template: string
data: Record<string, any>
} {
const agents = task.AgentSelection || []
const stepName = task.StepName || ''
// 为每个 agent 生成颜色
const colors = [
'hsl(210, 70%, 50%)',
'hsl(30, 70%, 50%)',
'hsl(120, 70%, 50%)',
'hsl(270, 70%, 50%)',
]
// 生成 data 对象
const data: Record<string, any> = {}
agents.forEach((agent, index) => {
data[agent] = {
text: agent,
style: { background: colors[index % colors.length] },
}
})
// 生成 template简化版本实际应根据任务内容生成
const template =
agents.length > 0
? agents.map((agent, i) => `!<${agent}>!负责!<${stepName}-${i}>!`).join('')
: ''
return {
template,
data,
}
}
/**
* Mock API模拟后端 branch_PlanOutline 接口调用
*
* @param branch_Number - 分支数量
* @param Modification_Requirement - 修改需求
* @param Existing_Steps - 现有步骤名称列表
* @param Baseline_Completion - 基线完成度
* @param InitialObject_List - 初始对象列表
* @param General_Goal - 总体目标
* @returns Promise<IRawPlanResponse> - 返回包含 'Collaboration Process' 的响应
*/
export const mockBranchPlanOutlineAPI = async (params: {
branch_Number: number
Modification_Requirement: string
Existing_Steps: string[]
Baseline_Completion: number
InitialObject_List: string[]
General_Goal: string
}): Promise<IRawPlanResponse> => {
// 模拟网络延迟 800ms
await new Promise((resolve) => setTimeout(resolve, 800))
console.log('[Mock API] branch_PlanOutline 调用参数:', params)
// 🆕 使用轮询方式选择分支方案(依次循环使用所有分支方案)
const totalBranches = mockBranchDataRaw.length
const sessionKey = `branch-plan-outline-index-${params.General_Goal || 'default'}`
// 获取上一次的选择索引
let lastIndex = parseInt(sessionStorage.getItem(sessionKey) || '0')
// 计算本次的选择索引(轮询到下一个分支)
const selectedBranchIndex = (lastIndex + 1) % totalBranches
// 保存本次的选择索引
sessionStorage.setItem(sessionKey, selectedBranchIndex.toString())
const rawBranchData = mockBranchDataRaw[selectedBranchIndex]
console.log(
'[Mock API] branch_PlanOutline 选择分支方案:',
selectedBranchIndex + 1,
'/',
totalBranches,
)
// 模拟后端处理:添加 Collaboration_Brief_FrontEnd
const processedBranches = Add_Collaboration_Brief_FrontEnd([rawBranchData])
// 构造响应数据(符合后端返回格式)
const response: IRawPlanResponse = {
'Collaboration Process': processedBranches[0] || [],
}
console.log('[Mock API] branch_PlanOutline 返回数据:', response)
return response
}
export default mockBranchPlanOutlineAPI

View File

@@ -1,189 +1,155 @@
// branch_TaskProcess 接口返回mock 数据 // branch_TaskProcess 接口的 Mock 数据和 Mock API
// 类型: IApiAgentAction[][] (二维数组) export interface BranchAction {
ID: string
ActionType: string
AgentName: string
Description: string
ImportantInput: string[]
}
import type { IApiAgentAction } from '@/stores/modules/agents' export type BranchTaskProcessResponse = BranchAction[][]
const mockTaskProcessData: IApiAgentAction[][] = [ // Mock 数据模拟后端返回的原始任务流程数据2D 数组)
// 格式:[[action1, action2], [action3, action4]]
const mockBranchTaskProcessDataRaw: BranchAction[][] = [
// 第一个任务分支方案 // 第一个任务分支方案
[ [
{ {
id: 'analyze-requirements-1', ID: 'agent3',
type: '分析', ActionType: 'Critique',
agent: '实验材料学家', AgentName: '实验材料学家',
description: '详细分析用户需求文档', Description: '详细分析用户需求文档',
inputs: ['用户需求文档'], ImportantInput: ['agent2'],
}, },
{ {
id: 'design-architecture-1', ID: 'agent4',
type: '设计', ActionType: 'Critique',
agent: '腐蚀机理研究员', AgentName: '腐蚀机理研究员',
description: '设计系统整体架构', Description: '设计系统整体架构',
inputs: ['需求分析结果'], ImportantInput: ['agent3'],
}, },
{ {
id: 'implement-core-1', ID: 'agent5',
type: '实现', ActionType: 'Improve',
agent: '防护工程专家', AgentName: '防护工程专家',
description: '实现系统核心功能', Description: '实现系统核心功能',
inputs: ['系统架构设计'], ImportantInput: ['agent4'],
}, },
{ {
id: 'test-system-1', ID: 'agent6',
type: '测试', ActionType: 'Finalize',
agent: '实验材料学家', AgentName: '实验材料学家',
description: '进行系统集成测试', Description: '进行系统集成测试',
inputs: ['系统核心功能'], ImportantInput: ['agent5'],
},
],
// 第二个任务分支方案
[
{
ID: 'agent7',
ActionType: 'Critique',
AgentName: '实验材料学家',
Description: '深入分析用户需求和技术约束',
ImportantInput: ['agent2'],
},
{
ID: 'agent8',
ActionType: 'Critique',
AgentName: '防护工程专家',
Description: '设计系统技术架构和数据流',
ImportantInput: ['agent8'],
},
{
ID: 'agent9',
ActionType: 'Improve',
AgentName: '腐蚀机理研究员',
Description: '评估系统安全性',
ImportantInput: ['agent4'],
},
{
ID: 'agent10',
ActionType: 'Finalize',
AgentName: '实验材料学家',
Description: '完成系统安全测试',
ImportantInput: ['agent9'],
}, },
], ],
// 第二个任务分支方案(替代方案) //第三个任务分支方案
[ [
{ {
id: 'quick-prototype-2', ID: 'agent12',
type: '原型', ActionType: 'Critique',
agent: '实验材料学家', AgentName: '腐蚀机理研究员',
description: '快速开发系统原型', Description: '设计系统整体架构',
inputs: ['用户需求文档'], ImportantInput: ['agent11'],
}, },
{ {
id: 'user-feedback-2', ID: 'agent13',
type: '收集', ActionType: 'Improve',
agent: '腐蚀机理研究员', AgentName: '防护工程专家',
description: '收集用户对原型的反馈', Description: '实现系统核心功能',
inputs: ['系统原型'], ImportantInput: ['agent12'],
}, },
{ {
id: 'iterate-design-2', ID: 'agent14',
type: '迭代', ActionType: 'Finalize',
agent: '防护工程专家', AgentName: '实验材料学家',
description: '根据反馈迭代设计', Description: '进行系统集成测试',
inputs: ['用户反馈'], ImportantInput: ['agent13'],
},
{
id: 'final-implement-2',
type: '实现',
agent: '实验材料学家',
description: '实现最终用户界面',
inputs: ['迭代设计稿'],
},
],
// 第三个任务分支方案(敏捷开发方案)
[
{
id: 'sprint-planning-3',
type: '规划',
agent: '实验材料学家',
description: '制定冲刺计划',
inputs: ['用户故事', '技术债务'],
},
{
id: 'code-review-3',
type: '评审',
agent: '防护工程专家',
description: '进行代码审查',
inputs: ['开发代码'],
},
{
id: 'unit-test-3',
type: '测试',
agent: '腐蚀机理研究员',
description: '编写单元测试',
inputs: ['功能代码'],
},
{
id: 'deploy-staging-3',
type: '部署',
agent: '实验材料学家',
description: '部署到测试环境',
inputs: ['测试通过代码'],
},
{
id: 'acceptance-test-3',
type: '验收',
agent: '腐蚀机理研究员',
description: '进行验收测试',
inputs: ['测试环境系统'],
},
],
// 第四个任务分支方案(微服务方案)
[
{
id: 'service-split-4',
type: '拆分',
agent: '实验材料学家',
description: '拆分单体应用为微服务',
inputs: ['单体应用代码'],
},
{
id: 'api-design-4',
type: '设计',
agent: '防护工程专家',
description: '设计微服务API接口',
inputs: ['服务拆分方案'],
},
{
id: 'service-implement-4',
type: '实现',
agent: '防护工程专家',
description: '实现各个微服务',
inputs: ['API设计文档'],
},
{
id: 'orchestration-4',
type: '编排',
agent: '腐蚀机理研究员',
description: '配置服务编排和负载均衡',
inputs: ['微服务实现'],
},
{
id: 'monitoring-setup-4',
type: '监控',
agent: '实验材料学家',
description: '设置监控和日志系统',
inputs: ['运行中的微服务'],
},
],
// 第五个任务分支方案(数据驱动方案)
[
{
id: 'data-analysis-5',
type: '分析',
agent: '腐蚀机理研究员',
description: '分析业务数据和需求',
inputs: ['业务数据', '用户行为数据'],
},
{
id: 'ml-model-5',
type: '建模',
agent: '实验材料学家',
description: '构建预测模型',
inputs: ['分析结果', '历史数据'],
},
{
id: 'data-pipeline-5',
type: '构建',
agent: '防护工程专家',
description: '构建数据处理流水线',
inputs: ['数据源', '模型需求'],
},
{
id: 'api-integration-5',
type: '集成',
agent: '实验材料学家',
description: '集成数据服务到应用',
inputs: ['数据处理流水线', '预测模型'],
},
{
id: 'performance-optimize-5',
type: '优化',
agent: '腐蚀机理研究员',
description: '优化系统性能',
inputs: ['运行数据', '性能指标'],
}, },
], ],
] ]
export default mockTaskProcessData /**
* Mock API模拟后端 branch_TaskProcess 接口调用
*
* @param branch_Number - 分支数量
* @param Modification_Requirement - 修改需求
* @param Existing_Steps - 现有步骤名称列表
* @param Baseline_Completion - 基线完成度
* @param stepTaskExisting - 现有任务
* @param General_Goal - 总体目标
* @returns Promise<BranchAction[][]> - 返回 2D 数组,与后端格式完全一致
*/
export const mockBranchTaskProcessAPI = async (params: {
branch_Number: number
Modification_Requirement: string
Existing_Steps: string[]
Baseline_Completion: number
stepTaskExisting: any
General_Goal: string
}): Promise<BranchAction[][]> => {
// 模拟网络延迟 800ms
await new Promise((resolve) => setTimeout(resolve, 800))
console.log('[Mock API] branch_TaskProcess 调用参数:', params)
// 🆕 使用轮询方式选择分支方案(依次循环使用所有分支方案)
const totalBranches = mockBranchTaskProcessDataRaw.length
const sessionKey = `branch-task-process-index-${params.stepTaskExisting?.Id || 'default'}`
// 获取上一次的选择索引
let lastIndex = parseInt(sessionStorage.getItem(sessionKey) || '0')
// 计算本次的选择索引(轮询到下一个分支)
const selectedBranchIndex = (lastIndex + 1) % totalBranches
// 保存本次的选择索引
sessionStorage.setItem(sessionKey, selectedBranchIndex.toString())
const rawBranchData = mockBranchTaskProcessDataRaw[selectedBranchIndex] || []
console.log(
'[Mock API] branch_TaskProcess 选择分支方案:',
selectedBranchIndex + 1,
'/',
totalBranches,
)
console.log('[Mock API] branch_TaskProcess 返回数据:', rawBranchData)
// 直接返回 2D 数组,与后端格式完全一致
return [rawBranchData]
}
export default mockBranchTaskProcessAPI

View File

@@ -29,7 +29,7 @@ const scoreDimensions = ref<string[]>([])
interface AgentHeatmapData { interface AgentHeatmapData {
agentName: string agentName: string
scores: number[] // 各维度的评分 scores: number[] // 各维度的评分
scoreDetails?: Array<{ dimension: string; score: number; reason: string }> // 详细信息(可选) scoreDetails?: Array<{ dimension: string; score: number; reason: string }> // 详细信息
} }
// 所有agent的热力图数据 // 所有agent的热力图数据
@@ -57,6 +57,9 @@ const searchValue = ref('')
// 标志位:防止重复初始化 // 标志位:防止重复初始化
const isInitializing = ref(false) const isInitializing = ref(false)
const isAddingDimension = ref(false) const isAddingDimension = ref(false)
const isLoadingConfirm = ref(false) // 确认 agent 组合时的加载状态
const isLoadingSelectGroup = ref(false) // 选择已保存组合时的加载状态
const isLoadingInitialTask = ref(false) // 首次加载任务时的加载状态
// 处理搜索提交 // 处理搜索提交
const handleSubmit = async () => { const handleSubmit = async () => {
@@ -143,19 +146,8 @@ const confirmAgentSelection = async () => {
if (selectedAgents.value.size > 0 && currentTask.value?.Id) { if (selectedAgents.value.size > 0 && currentTask.value?.Id) {
const agentArray = Array.from(selectedAgents.value) const agentArray = Array.from(selectedAgents.value)
// 检查该agent组合是否已存在包括初始agent组合和用户添加的组合) // 检查该agent组合是否已存在统一检查,包括初始组合和用户添加的组合)
const existingGroups = agentsStore.getConfirmedAgentGroups(currentTask.value.Id) const existingGroups = agentsStore.getConfirmedAgentGroups(currentTask.value.Id)
const initialGroup = currentTaskAgents.value
// 检查是否与初始组合相同
if (areAgentGroupsEqual(agentArray, initialGroup)) {
console.log('该agent组合与初始组合相同只选中卡片不添加重复')
selectedAssignmentGroup.value = [...initialGroup]
selectedAgents.value = new Set(initialGroup)
return
}
// 检查是否与已存在的用户添加组合相同
const existingDuplicateIndex = existingGroups.findIndex(group => const existingDuplicateIndex = existingGroups.findIndex(group =>
areAgentGroupsEqual(agentArray, group) areAgentGroupsEqual(agentArray, group)
) )
@@ -176,7 +168,8 @@ const confirmAgentSelection = async () => {
// 调用 Mock API 填充任务流程 // 调用 Mock API 填充任务流程
try { try {
console.log('=== 开始调用 fillStepTaskTaskProcess Mock API ===') isLoadingConfirm.value = true
console.log('=== 开始调用 mockFillStepTaskTaskProcess Mock API ===')
console.log('1. 当前任务数据 (IRawStepTask 格式):', currentTask.value) console.log('1. 当前任务数据 (IRawStepTask 格式):', currentTask.value)
console.log('2. 选中的 agents:', agentArray) console.log('2. 选中的 agents:', agentArray)
@@ -218,12 +211,14 @@ const confirmAgentSelection = async () => {
console.log('✅ Mock API 调用成功,数据已存储到 selectionStore') console.log('✅ Mock API 调用成功,数据已存储到 selectionStore')
} catch (error) { } catch (error) {
console.error('❌ Mock API 调用失败:', error) console.error('❌ Mock API 调用失败:', error)
} finally {
isLoadingConfirm.value = false
} }
} }
} }
// 点击 Assignment 部分的 agent 组合卡片,更新 Comparison 部分的选中状态 // 点击 Assignment 部分的 agent 组合卡片,更新 Comparison 部分的选中状态
const selectAgentGroup = (agentNames: string[]) => { const selectAgentGroup = async (agentNames: string[]) => {
// 更新Assignment边框状态 // 更新Assignment边框状态
selectedAssignmentGroup.value = [...agentNames] selectedAssignmentGroup.value = [...agentNames]
@@ -237,6 +232,116 @@ const selectAgentGroup = (agentNames: string[]) => {
agentsStore.setSelectedAgentGroup(currentTask.value.Id, agentNames) agentsStore.setSelectedAgentGroup(currentTask.value.Id, agentNames)
} }
// 🆕 联动更新:更新 currentTask 的 AgentSelection 和 TaskProcess
if (currentTask.value?.Id && agentNames.length > 0) {
console.log('🔄 开始联动更新 currentTask 的 agent 组合:', agentNames)
// 从 selectionStore 获取该 agent 组合对应的 TaskProcess 数据
let taskProcessData = selectionStore.getAgentTaskProcess(currentTask.value.Id, agentNames)
// 🆕 如果 selectionStore 中没有数据,自动调用 API 加载
if (!taskProcessData) {
console.log('⚠️ selectionStore 中没有该组合的 TaskProcess 数据,开始加载...')
console.log('📋 当前任务信息:', {
taskId: currentTask.value.Id,
taskName: currentTask.value.StepName,
agents: agentNames
})
try {
isLoadingSelectGroup.value = true
// 将 IRawStepTask 转换为 IApiStepTask 格式
const stepTaskForApi = {
name: currentTask.value.StepName || '',
content: currentTask.value.TaskContent || '',
inputs: currentTask.value.InputObject_List || [],
output: currentTask.value.OutputObject || '',
agents: agentNames,
brief: currentTask.value.Collaboration_Brief_frontEnd || {
template: '',
data: {}
},
process: []
}
const goal = agentsStore.agentRawPlan.data?.['General Goal'] || '开发智能协作系统'
console.log('📤 准备调用 API:', {
goal,
stepTask: stepTaskForApi,
agents: agentNames
})
// 调用 Mock API 加载数据
const filledTask = await api.mockFillStepTaskTaskProcess({
goal,
stepTask: stepTaskForApi,
agents: agentNames
})
console.log('🔍 API 返回的完整响应:', filledTask)
console.log('🔍 process 数据:', filledTask.process)
console.log('🔍 process 长度:', filledTask.process?.length)
console.log('✅ TaskProcess 数据加载成功:', {
agents: agentNames,
processCount: filledTask.process?.length || 0,
processDetail: filledTask.process,
briefDetail: filledTask.brief
})
// 存储到 selectionStore
selectionStore.setAgentTaskProcess(currentTask.value.Id, agentNames, filledTask)
console.log('💾 数据已存储到 selectionStore验证存储是否成功...')
// 验证存储
const storedData = selectionStore.getAgentTaskProcess(currentTask.value.Id, agentNames)
console.log('📦 验证存储结果:', storedData ? '成功' : '失败', storedData)
taskProcessData = filledTask
} catch (error) {
console.error('❌ 加载 TaskProcess 数据失败:', error)
return
} finally {
isLoadingSelectGroup.value = false
}
}
if (taskProcessData) {
console.log('✅ 找到 TaskProcess 数据,开始更新 currentTask:', {
taskId: currentTask.value.Id,
agents: agentNames,
processCount: taskProcessData.process?.length || 0,
processDetail: taskProcessData.process,
briefDetail: taskProcessData.brief
})
// 🆕 数据格式转换IApiAgentAction[] → TaskProcess[]
const convertedTaskProcess = (taskProcessData.process || []).map(action => ({
ID: action.id,
ActionType: action.type,
AgentName: action.agent,
Description: action.description,
ImportantInput: action.inputs || []
}))
console.log('🔄 数据格式转换完成:', {
original: taskProcessData.process,
converted: convertedTaskProcess
})
// 更新 currentTask 的 AgentSelection 和 TaskProcess
// 使用 updateCurrentAgentSelection 强制更新,避免被 setCurrentTask 的"智能保留"逻辑阻止
agentsStore.updateCurrentAgentSelection(
[...agentNames],
convertedTaskProcess,
taskProcessData.brief || currentTask.value.Collaboration_Brief_frontEnd
)
console.log('✅ currentTask 已更新,新的 AgentSelection:', agentNames)
console.log('📋 验证更新结果:', agentsStore.currentTask)
}
}
// 重新排序被选中的agent排在前面其他agent按平均分降序 // 重新排序被选中的agent排在前面其他agent按平均分降序
if (agentsHeatmapData.value.length > 0) { if (agentsHeatmapData.value.length > 0) {
agentsHeatmapData.value.sort((a, b) => { agentsHeatmapData.value.sort((a, b) => {
@@ -406,18 +511,27 @@ const fetchAgentScores = async () => {
} }
// TODO: 切换到真实API时取消注释下面这行 // TODO: 切换到真实API时取消注释下面这行
// const response = await api.agentSelectModifyInit({ // const agentScores = await api.agentSelectModifyInit({
// goal: agentsStore.agentRawPlan.data?.['General Goal'] || '', // goal: agentsStore.agentRawPlan.data?.['General Goal'] || '',
// stepTask: currentTask.value // stepTask: currentTask.value
// }) // })
// 使用 Mock API开发阶段 // 🆕 使用 Mock API开发阶段,传递当前任务的 AgentSelection 以获取对应的维度
const goal = agentsStore.agentRawPlan.data?.['General Goal'] || '开发智能协作系统'
console.log('📤 调用 mockAgentSelectModifyInit参数:', {
goal,
stepTask: currentTask.value,
agentSelection: currentTask.value?.AgentSelection
})
const agentScores = await api.mockAgentSelectModifyInit() const agentScores = await api.mockAgentSelectModifyInit()
// 从转换后的数据中提取维度列表第一个agent的所有维度 // 从转换后的数据中提取维度列表第一个agent的所有维度
const firstAgent = Object.keys(agentScores)[0] const firstAgent = Object.keys(agentScores)[0]
const aspectList = firstAgent ? Object.keys(agentScores[firstAgent] || {}) : [] const aspectList = firstAgent ? Object.keys(agentScores[firstAgent] || {}) : []
console.log('✅ 获取到的维度列表:', aspectList)
// 保存到 store // 保存到 store
agentsStore.setAgentScoreData({ agentsStore.setAgentScoreData({
aspectList, aspectList,
@@ -594,9 +708,10 @@ watch(
{ deep: true } { deep: true }
) )
// 按需加载初始 agent 组合的 TaskProcess方案B // 初始化和任务切换处理
// 当用户第一次打开智能体探索窗口时,检查当前任务的初始 agent 组合是否已有 TaskProcess 数据 // 1. 首次加载时,自动将初始 agent 组合添加到 confirmedAgentGroups
// 如果没有,则调用 fill_stepTask_TaskProcess API 获取并存储 // 2. 恢复之前的选择状态
// 3. 加载 TaskProcess 数据
watch( watch(
() => currentTask.value, () => currentTask.value,
async newTask => { async newTask => {
@@ -604,28 +719,22 @@ watch(
return return
} }
// 从 store 中恢复之前选择的 agent 组合 // 检查是否已经添加过初始组合
const savedAgentGroup = agentsStore.getSelectedAgentGroup(newTask.Id) const existingGroups = agentsStore.getConfirmedAgentGroups(newTask.Id)
if (savedAgentGroup) { const hasInitialGroup = existingGroups.length > 0
console.log('📂 恢复之前选择的 agent 组合:', savedAgentGroup)
selectedAssignmentGroup.value = [...savedAgentGroup] // 首次初始化:自动添加初始组合(相当于系统自动执行了 confirmAgentSelection
selectedAgents.value = new Set(savedAgentGroup) if (!hasInitialGroup) {
} else { console.log('🎯 首次初始化,自动添加初始 agent 组合到 Assignment')
// 没有保存的选择,使用默认的初始组合 agentsStore.addConfirmedAgentGroup(newTask.Id, [...newTask.AgentSelection])
selectedAssignmentGroup.value = [...newTask.AgentSelection]
selectedAgents.value = new Set(newTask.AgentSelection)
}
// 调用 API 获取初始 agent 组合的 TaskProcess 数据 // 调用 API 获取初始 agent 组合的 TaskProcess 数据
console.log('🔄 开始加载初始 agent 组合的 TaskProcess...') console.log('🔄 开始加载初始 agent 组合的 TaskProcess...')
// 检查是否已有数据 // 检查是否已有数据
if (selectionStore.hasAgentTaskProcess(newTask.Id, newTask.AgentSelection)) { if (!selectionStore.hasAgentTaskProcess(newTask.Id, newTask.AgentSelection)) {
console.log(' 初始 agent 组合已有 TaskProcess 数据,跳过加载')
return
}
try { try {
isLoadingInitialTask.value = true
console.log('=== 开始加载初始 agent 组合的 TaskProcess ===') console.log('=== 开始加载初始 agent 组合的 TaskProcess ===')
console.log('1. 任务ID:', newTask.Id) console.log('1. 任务ID:', newTask.Id)
console.log('2. 初始 agents:', newTask.AgentSelection) console.log('2. 初始 agents:', newTask.AgentSelection)
@@ -664,6 +773,28 @@ watch(
console.log('✅ 初始 agent 组合的 TaskProcess 已加载并存储') console.log('✅ 初始 agent 组合的 TaskProcess 已加载并存储')
} catch (error) { } catch (error) {
console.error('❌ 加载初始 agent 组合的 TaskProcess 失败:', error) console.error('❌ 加载初始 agent 组合的 TaskProcess 失败:', error)
} finally {
isLoadingInitialTask.value = false
}
} else {
console.log(' 初始 agent 组合已有 TaskProcess 数据,跳过加载')
}
}
// 从 store 中恢复之前选择的 agent 组合(如果有)
const savedAgentGroup = agentsStore.getSelectedAgentGroup(newTask.Id)
if (savedAgentGroup) {
console.log('📂 恢复之前选择的 agent 组合:', savedAgentGroup)
selectedAssignmentGroup.value = [...savedAgentGroup]
selectedAgents.value = new Set(savedAgentGroup)
} else {
// 没有保存的选择,默认选中第一个组合(即初始组合)
const allGroups = agentsStore.getConfirmedAgentGroups(newTask.Id)
if (allGroups.length > 0 && allGroups[0]) {
console.log('🔄 默认选中第一个组合(初始组合):', allGroups[0])
selectedAssignmentGroup.value = [...allGroups[0]]
selectedAgents.value = new Set(allGroups[0])
}
} }
}, },
{ immediate: true } // 立即执行一次 { immediate: true } // 立即执行一次
@@ -672,7 +803,7 @@ watch(
// 获取热力图颜色评分1-5颜色从浅到深 // 获取热力图颜色评分1-5颜色从浅到深
const getHeatmapColor = (score: number) => { const getHeatmapColor = (score: number) => {
const colors = [ const colors = [
'#f0f0f0', // 1分 - 最浅 '#f7f7f7', // 1分 - 最浅
'#d4e5f7', // 2分 '#d4e5f7', // 2分
'#89b4e8', // 3分 '#89b4e8', // 3分
'#4575b4', // 4分 '#4575b4', // 4分
@@ -686,49 +817,15 @@ const getHeatmapColor = (score: number) => {
<div class="agent-allocation-container"> <div class="agent-allocation-container">
<!-- 左侧区域 - 20% --> <!-- 左侧区域 - 20% -->
<div class="allocation-left"> <div class="allocation-left">
<div class="section-card"> <div class="section-card" v-loading="isLoadingSelectGroup">
<div class="section-title">Assignment</div> <div class="section-title">Assignment</div>
<!-- 初始agent组合卡片 --> <!-- 所有 agent 组合卡片包括初始组合和用户创建的组合 -->
<div
class="agents-grid"
:class="{ 'agent-group-selected': isAgentGroupSelected(currentTaskAgents) }"
@click="selectAgentGroup(currentTaskAgents)"
>
<el-tooltip
v-for="agent in currentTaskAgents"
:key="agent"
effect="light"
placement="top"
:teleported="false"
:show-after="500"
popper-class="agent-allocation-tooltip-popper"
>
<template #content>
<div class="agent-tooltip">
<div class="agent-tooltip-name">{{ agent }}</div>
<div class="agent-tooltip-separator"></div>
<div class="agent-tooltip-description">
{{
agentsStore.agents.find(a => a.Name === agent)?.Profile || '暂无描述'
}}
</div>
</div>
</template>
<div class="agent-item">
<div class="agent-icon" :style="{ background: getAgentMapIcon(agent).color }">
<svg-icon :icon-class="getAgentMapIcon(agent).icon" color="#fff" size="20px" />
</div>
</div>
</el-tooltip>
</div>
<!-- 确认的agent组合列表 -->
<div <div
v-for="(group, groupIndex) in confirmedAgentGroups" v-for="(group, groupIndex) in confirmedAgentGroups"
:key="groupIndex" :key="groupIndex"
class="agents-grid" class="agents-grid"
:class="{ 'agent-group-selected': isAgentGroupSelected(group) }" :class="{ 'agent-group-selected': isAgentGroupSelected(group) }"
style="margin-top: 12px" :style="{ marginTop: groupIndex > 0 ? '12px' : '0' }"
@click="selectAgentGroup(group)" @click="selectAgentGroup(group)"
> >
<el-tooltip <el-tooltip
@@ -767,7 +864,11 @@ const getHeatmapColor = (score: number) => {
<div class="allocation-right"> <div class="allocation-right">
<div class="section-card"> <div class="section-card">
<div class="section-title">Comparison</div> <div class="section-title">Comparison</div>
<div v-if="allAgents.length > 0" class="comparison-content"> <div
v-if="allAgents.length > 0"
class="comparison-content"
v-loading="isInitializing || isLoadingInitialTask || isLoadingConfirm"
>
<!-- 热力矩阵图 --> <!-- 热力矩阵图 -->
<div v-if="agentsHeatmapData.length > 0" class="heatmap-container"> <div v-if="agentsHeatmapData.length > 0" class="heatmap-container">
<!-- 虚线选择框 - 包裹选中的agent头像 --> <!-- 虚线选择框 - 包裹选中的agent头像 -->
@@ -777,7 +878,11 @@ const getHeatmapColor = (score: number) => {
:style="getSelectionBoxStyle()" :style="getSelectionBoxStyle()"
> >
<!-- 确定按钮 --> <!-- 确定按钮 -->
<div class="confirm-button" @click="confirmAgentSelection"> <div
class="confirm-button"
:class="{ 'is-loading': isLoadingConfirm }"
@click="confirmAgentSelection"
>
<svg-icon icon-class="Check" color="#328621" size="12px" /> <svg-icon icon-class="Check" color="#328621" size="12px" />
</div> </div>
</div> </div>
@@ -874,7 +979,7 @@ const getHeatmapColor = (score: number) => {
</div> </div>
<!-- 输入框区域 --> <!-- 输入框区域 -->
<div class="search-input-container"> <div class="search-input-container" v-loading="isAddingDimension">
<el-input <el-input
v-model="searchValue" v-model="searchValue"
placeholder="请输入新维度" placeholder="请输入新维度"
@@ -887,7 +992,7 @@ const getHeatmapColor = (score: number) => {
size="16px" size="16px"
color="#409eff" color="#409eff"
class="submit-icon" class="submit-icon"
:class="{ 'is-disabled': !searchValue }" :class="{ 'is-disabled': !searchValue, 'is-loading': isAddingDimension }"
@click="searchValue && handleSubmit()" @click="searchValue && handleSubmit()"
/> />
</template> </template>
@@ -1039,6 +1144,25 @@ const getHeatmapColor = (score: number) => {
transform: scale(1.1); transform: scale(1.1);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
} }
&.is-loading {
opacity: 0.6;
cursor: not-allowed;
pointer-events: none;
svg {
animation: spin 1s linear infinite;
}
}
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
} }
} }
@@ -1102,16 +1226,19 @@ const getHeatmapColor = (score: number) => {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: flex-start; justify-content: flex-start;
padding-top: 40px; // 对齐第一个评分单元格(跳过列头) padding-top: 40px; // 对齐第一个评分单元格
flex-shrink: 0; flex-shrink: 0;
max-width: 200px; //
.dimension-label { .dimension-label {
width: 60px; min-width: 60px; // 改为最小宽度,允许根据内容自适应
width: auto; // 宽度自适应
height: 40px; height: 40px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: flex-start; justify-content: flex-start;
padding-left: 8px; padding-left: 8px;
padding-right: 8px; // 添加右侧内边距,确保文字不会紧贴边缘
font-size: 12px; font-size: 12px;
font-weight: 600; font-weight: 600;
color: var(--color-text-title-header); color: var(--color-text-title-header);
@@ -1119,6 +1246,7 @@ const getHeatmapColor = (score: number) => {
cursor: pointer; cursor: pointer;
user-select: none; user-select: none;
transition: all 0.2s ease; transition: all 0.2s ease;
white-space: nowrap; // 防止文字换行
&:hover { &:hover {
color: #409eff; color: #409eff;
@@ -1177,6 +1305,11 @@ const getHeatmapColor = (score: number) => {
opacity: 0.4; opacity: 0.4;
cursor: not-allowed; cursor: not-allowed;
} }
&.is-loading {
opacity: 0.7;
animation: spin 1s linear infinite;
}
} }
} }
} }

View File

@@ -22,7 +22,7 @@ const agentGroupCount = computed(() => {
const confirmedGroups = agentsStore.getConfirmedAgentGroups(agentsStore.currentTask.Id) const confirmedGroups = agentsStore.getConfirmedAgentGroups(agentsStore.currentTask.Id)
// 当前任务agents(1) + 已确认的agent组合数量 // 当前任务agents(1) + 已确认的agent组合数量
return 1 + confirmedGroups.length return confirmedGroups.length || 1
}) })
const handleClick = () => { const handleClick = () => {

View File

@@ -11,9 +11,9 @@ const emit = defineEmits<{
// 获取分支数量 - 主分支(1) + 额外分支数量 // 获取分支数量 - 主分支(1) + 额外分支数量
const branchCount = computed(() => { const branchCount = computed(() => {
// flowBranches 包含所有通过 Branch 创建的分支 // flowBranches 包含所有通过 Branch 创建的分支
const extraBranches = selectionStore.flowBranches?.length || 0 const extraBranches = selectionStore.flowBranches?.length || 1
// 始终至少有1个主分支 // 始终至少有1个主分支
return 1 + extraBranches return extraBranches
}) })
const handleClick = () => { const handleClick = () => {
@@ -26,7 +26,7 @@ const handleClick = () => {
<template> <template>
<div <div
class="branch-button" class="branch-button"
:class="{ 'has-branches': branchCount > 1 }" :class="{ 'has-branches': branchCount > 0 }"
@click="handleClick" @click="handleClick"
:title="`${branchCount} 个分支`" :title="`${branchCount} 个分支`"
> >

View File

@@ -0,0 +1,116 @@
// Mock数据 - 用于agentSelectModifyAddAspect接口
// 模拟用户输入新维度后所有agent在该维度上的评分数据
import { vueAgentList } from './AgentAssignmentMock'
// 类型定义
export interface NewDimensionScore {
score: number
reason: string
}
export type NewDimensionScoreData = Record<string, NewDimensionScore>
// 模拟接口返回的数据结构
export interface AgentAddAspectResponse {
aspectName: string // 新添加的维度名称
agentScores: NewDimensionScoreData // 所有agent在该维度上的评分
}
// 生成指定维度名称的mock评分数据
export const generateMockDimensionScores = (dimensionName: string): AgentAddAspectResponse => {
const agentScores: NewDimensionScoreData = {}
vueAgentList.forEach((agent) => {
// 随机生成1-5的评分
const score = Math.floor(Math.random() * 5) + 1
// 根据评分生成不同的原因描述
let reason = ''
switch (score) {
case 5:
reason = `在"${dimensionName}"方面表现卓越,展现出杰出的能力和深刻的理解`
break
case 4:
reason = `在"${dimensionName}"方面表现优秀,具有良好的专业能力和执行力`
break
case 3:
reason = `在"${dimensionName}"方面表现合格,能够完成相关任务`
break
case 2:
reason = `在"${dimensionName}"方面表现一般,仍有提升空间`
break
case 1:
reason = `在"${dimensionName}"方面需要加强,建议进一步提升相关能力`
break
}
agentScores[agent] = { score, reason }
})
return {
aspectName: dimensionName,
agentScores,
}
}
// 预设的一些常用维度及其评分数据
export const presetDimensionScores: Record<string, AgentAddAspectResponse> = {
创新性: generateMockDimensionScores('创新性'),
技术能力: generateMockDimensionScores('技术能力'),
沟通技巧: generateMockDimensionScores('沟通技巧'),
问题解决: generateMockDimensionScores('问题解决'),
团队协作: generateMockDimensionScores('团队协作'),
学习能力: generateMockDimensionScores('学习能力'),
执行力: generateMockDimensionScores('执行力'),
责任心: generateMockDimensionScores('责任心'),
适应性: generateMockDimensionScores('适应性'),
领导力: generateMockDimensionScores('领导力'),
}
// 模拟API调用函数用于前端测试
export const mockAgentAddAspectApi = async (
aspectList: string[],
): Promise<AgentAddAspectResponse[]> => {
// 获取新增的维度(最后一个)
const newAspect = aspectList[aspectList.length - 1]
// 模拟网络延迟 500ms
await new Promise((resolve) => setTimeout(resolve, 20000))
// 如果是预设维度,返回预设数据
if (presetDimensionScores[newAspect]) {
return [presetDimensionScores[newAspect]]
}
// 否则动态生成新的评分数据
return [generateMockDimensionScores(newAspect)]
}
// Vue Composition API 兼容的hook
export const useAgentAddAspectMock = () => {
const addNewDimension = async (dimensionName: string) => {
const response = await mockAgentAddAspectApi([dimensionName])
return response[0]
}
const getMultipleDimensions = async (dimensionNames: string[]) => {
const responses: AgentAddAspectResponse[] = []
for (const dimension of dimensionNames) {
if (presetDimensionScores[dimension]) {
responses.push(presetDimensionScores[dimension])
} else {
responses.push(generateMockDimensionScores(dimension))
}
}
return responses
}
return {
addNewDimension,
getMultipleDimensions,
generateMockDimensionScores,
}
}

View File

@@ -0,0 +1,192 @@
// 模拟后端原始返回格式的Mock数据 - 维度 -> agent -> { Reason, Score }
import { vueAgentList, vueAspectList } from './AgentAssignmentMock'
// 后端返回的评分项格式
export interface BackendScoreItem {
Reason: string
Score: number
}
// 后端返回的完整数据格式
export type BackendAgentScoreResponse = Record<string, Record<string, BackendScoreItem>>
// 模拟后端返回的原始数据结构(维度 -> agent -> { Reason, Score }
export const mockBackendAgentScoreData: BackendAgentScoreResponse = {
: {
: { Reason: '展现出卓越的创造力和创新思维', Score: 4 },
: { Reason: '展现出杰出的创造性问题解决能力', Score: 5 },
: { Reason: '具有中等创造技能,有待提升', Score: 3 },
: { Reason: '在大多数情况下展现较强的创造性思维', Score: 4 },
: { Reason: '展现出胜任的创造能力', Score: 3 },
: { Reason: '具有较强的创造性表达能力', Score: 4 },
: { Reason: '擅长创新性思维方法', Score: 5 },
: { Reason: '展现出卓越的创造性思维和创新能力', Score: 5 },
: { Reason: '展现出良好的创造性问题解决能力', Score: 4 },
: { Reason: '展现出卓越的创造性问题解决能力', Score: 5 },
: { Reason: '展现出平衡的创造能力', Score: 4 },
: { Reason: '展现出卓越的创造天赋', Score: 5 },
: { Reason: '展现出胜任的创造性思维', Score: 3 },
: { Reason: '展现出较强的创造性主动性', Score: 4 },
: { Reason: '具有发展中的创造技能', Score: 3 },
: { Reason: '展现出卓越的创造愿景', Score: 5 },
: { Reason: '展现出卓越的创造性执行力', Score: 4 },
: { Reason: '具有较强的创造性问题解决能力', Score: 4 },
: { Reason: '展现出胜任的创造能力', Score: 3 },
},
: {
: { Reason: '展现出卓越的共情能力和社会意识', Score: 5 },
: { Reason: '具有较强的情绪调节和人际交往技能', Score: 4 },
: { Reason: '展现出卓越的情感智力', Score: 5 },
: { Reason: '在大多数情况下展现平均的情感智力', Score: 3 },
: { Reason: '具有良好的情绪意识和沟通能力', Score: 4 },
: { Reason: '在情绪意识方面偶尔表现不足', Score: 3 },
: { Reason: '具有较强的情绪理解能力', Score: 4 },
: { Reason: '展现出卓越的共情能力和社交技能', Score: 5 },
: { Reason: '具有良好的情绪调节能力', Score: 4 },
: { Reason: '展现出卓越的情感智力和社会意识', Score: 5 },
: { Reason: '具有发展中的情绪意识', Score: 3 },
: { Reason: '擅长人际交往和建立关系', Score: 5 },
: { Reason: '展现出平衡的情感智力', Score: 4 },
: { Reason: '具有基本的情绪理解能力', Score: 3 },
: { Reason: '展现出良好的情绪调节能力', Score: 4 },
: { Reason: '展现出卓越的社会意识', Score: 5 },
: { Reason: '在情感智力方面需要提升', Score: 3 },
: { Reason: '具有较强的共情能力', Score: 4 },
: { Reason: '具有良好的情绪沟通技能', Score: 4 },
},
: {
: { Reason: '展现出胜任的哲学推理技能', Score: 3 },
: { Reason: '展现出卓越的逻辑推理和分析能力', Score: 5 },
: { Reason: '展现出深刻的哲学洞察力和批判性思维', Score: 2 },
: { Reason: '展现出良好的哲学理解能力', Score: 1 },
: { Reason: '具有基础哲学推理能力,存在一些局限', Score: 3 },
: { Reason: '展现出较强的分析思维能力', Score: 4 },
: { Reason: '展现出卓越的哲学深度', Score: 5 },
: { Reason: '展现出卓越的专业分析和推理能力', Score: 5 },
: { Reason: '具有良好的批判性思维能力', Score: 4 },
: { Reason: '具有较强的专业性分析和推理能力', Score: 4 },
: { Reason: '展现出卓越的逻辑推理能力', Score: 5 },
: { Reason: '具有基础的哲学理解能力', Score: 3 },
: { Reason: '展现出平衡的哲学推理能力', Score: 4 },
: { Reason: '需要在哲学思维方面发展', Score: 3 },
: { Reason: '展现出良好的分析技能', Score: 4 },
: { Reason: '具有较强的哲学洞察力', Score: 4 },
: { Reason: '擅长批判性思维和分析', Score: 5 },
: { Reason: '具有基础哲学推理能力', Score: 3 },
: { Reason: '展现出卓越的哲学才能', Score: 5 },
},
: {
: { Reason: '在任务完成方面展现出卓越的效率', Score: 4 },
: { Reason: '擅长高效的工作流程管理', Score: 5 },
: { Reason: '展现出平均的效率,有提升空间', Score: 3 },
: { Reason: '具有良好的时间管理技能', Score: 4 },
: { Reason: '展现出胜任的效率', Score: 3 },
: { Reason: '展现出卓越的生产力', Score: 5 },
: { Reason: '具有强大的任务执行能力', Score: 4 },
: { Reason: '具有良好的工作效率和时间管理', Score: 4 },
: { Reason: '展现出良好的工作流程优化能力', Score: 4 },
: { Reason: '展现出卓越的效率和工作流程管理', Score: 5 },
: { Reason: '展现出足够的效率', Score: 3 },
: { Reason: '擅长快速完成任务', Score: 5 },
: { Reason: '展现出良好的生产力', Score: 4 },
: { Reason: '具有中等的效率水平', Score: 3 },
: { Reason: '具有较强的任务效率', Score: 4 },
: { Reason: '具有良好的执行速度', Score: 4 },
: { Reason: '展现出卓越的效率', Score: 5 },
: { Reason: '展现出平均的生产力', Score: 3 },
: { Reason: '在执行方面具有良好的效率', Score: 4 },
},
: {
: { Reason: '展现出卓越的细节关注度', Score: 5 },
: { Reason: '展现出卓越的准确性和精确度', Score: 5 },
: { Reason: '展现出卓越的精确度', Score: 5 },
: { Reason: '展现出良好的准确性', Score: 4 },
: { Reason: '展现出中等的准确性,有提升空间', Score: 3 },
: { Reason: '具有较强的细节关注度', Score: 4 },
: { Reason: '在精确度和准确性方面表现卓越', Score: 5 },
: { Reason: '展现出卓越的细节导向和精确度', Score: 5 },
: { Reason: '展现出平均的准确性', Score: 3 },
: { Reason: '展现出卓越的准确性和精确技能', Score: 5 },
: { Reason: '展现出卓越的准确性', Score: 5 },
: { Reason: '展现出较强的精确度', Score: 4 },
: { Reason: '展现出中等的准确性', Score: 3 },
: { Reason: '具有良好的细节导向能力', Score: 4 },
: { Reason: '在准确性和精确度方面表现卓越', Score: 5 },
: { Reason: '展现出较强的细节关注度', Score: 4 },
: { Reason: '展现出平均的准确性水平', Score: 3 },
: { Reason: '在工作中具有良好的精确度', Score: 4 },
: { Reason: '展现出卓越的准确性', Score: 5 },
},
: {
: { Reason: '展现出卓越的协作技能', Score: 4 },
: { Reason: '在团队合作和协作方面表现卓越', Score: 5 },
: { Reason: '具有较强的协作能力', Score: 4 },
: { Reason: '具有中等的协作技能', Score: 3 },
: { Reason: '展现出良好的团队合作精神', Score: 4 },
: { Reason: '具有较强的合作能力', Score: 4 },
: { Reason: '展现出平均的协作技能', Score: 3 },
: { Reason: '在团队协作方面表现卓越', Score: 5 },
: { Reason: '展现出良好的合作工作能力', Score: 4 },
: { Reason: '在团队协作和合作方面表现卓越', Score: 5 },
: { Reason: '具有中等的协作水平', Score: 3 },
: { Reason: '展现出良好的协作技能', Score: 4 },
: { Reason: '在协调和团队合作方面表现卓越', Score: 5 },
: { Reason: '具有较强的合作能力', Score: 4 },
: { Reason: '展现出平均的协作水平', Score: 3 },
: { Reason: '展现出良好的团队合作精神', Score: 4 },
: { Reason: '具有较强的协作技能', Score: 4 },
: { Reason: '在团队协作方面表现卓越', Score: 5 },
: { Reason: '具有中等的协作能力', Score: 3 },
},
}
// 模拟后端API调用 - agentSelectModifyInit
export const mockBackendAgentSelectModifyInit = async (): Promise<BackendAgentScoreResponse> => {
// 模拟网络延迟 300ms
await new Promise(resolve => setTimeout(resolve, 300))
return mockBackendAgentScoreData
}
// 模拟后端API调用 - agentSelectModifyAddAspect添加新维度
export const mockBackendAgentSelectModifyAddAspect = async (
aspectList: string[]
): Promise<BackendAgentScoreResponse> => {
// 模拟网络延迟 500ms
await new Promise(resolve => setTimeout(resolve, 500))
// 获取新添加的维度(最后一个)
const newAspect = aspectList[aspectList.length - 1]
if (!newAspect) {
return {}
}
// 生成该维度下所有agent的评分
const aspectData: Record<string, BackendScoreItem> = {}
vueAgentList.forEach(agent => {
const score = Math.floor(Math.random() * 5) + 1
let reason = ''
switch (score) {
case 5:
reason = `在"${newAspect}"方面表现卓越,展现出杰出的能力和深刻的理解`
break
case 4:
reason = `在"${newAspect}"方面表现优秀,具有良好的专业能力和执行力`
break
case 3:
reason = `在"${newAspect}"方面表现合格,能够完成相关任务`
break
case 2:
reason = `在"${newAspect}"方面表现一般,仍有提升空间`
break
case 1:
reason = `在"${newAspect}"方面需要加强,建议进一步提升相关能力`
break
}
aspectData[agent] = { Reason: reason, Score: score }
})
return {
[newAspect]: aspectData
}
}

View File

@@ -0,0 +1,314 @@
// Vue兼容的mock数据 - 6个维度19个智能体
export const vueAgentList = [
'船舶设计师',
'防护工程专家',
'病理生理学家',
'药物化学家',
'制剂工程师',
'监管事务专家',
'物理学家',
'实验材料学家',
'计算模拟专家',
'腐蚀机理研究员',
'先进材料研发员',
'肾脏病学家',
'临床研究协调员',
'中医药专家',
'药物安全专家',
'二维材料科学家',
'光电物理学家',
'机器学习专家',
'流体动力学专家',
]
export const vueAspectList = ['能力', '可用性', '专业性', '效率', '准确性', '协作性']
// 类型定义
export type AgentName = (typeof vueAgentList)[number]
export type AspectName = (typeof vueAspectList)[number]
export interface AgentScore {
score: number
reason: string
}
export type IAgentSelectModifyAddRequest = Record<AspectName, Record<AgentName, AgentScore>>
// Vue友好的数据结构 - agent -> 维度 -> 评分(与后端返回格式一致)
export const vueAgentScoreData: Record<AgentName, Record<AspectName, AgentScore>> = {
: {
: { score: 4, reason: '展现出卓越的创造力和创新思维' },
: { score: 5, reason: '展现出卓越的共情能力和社会意识' },
: { score: 3, reason: '展现出胜任的哲学推理技能' },
: { score: 4, reason: '在任务完成方面展现出卓越的效率' },
: { score: 5, reason: '展现出卓越的细节关注度' },
: { score: 4, reason: '展现出卓越的协作技能' },
},
: {
: { score: 5, reason: '展现出杰出的创造性问题解决能力' },
: { score: 4, reason: '具有较强的情绪调节和人际交往技能' },
: { score: 5, reason: '展现出卓越的逻辑推理和分析能力' },
: { score: 5, reason: '擅长高效的工作流程管理' },
: { score: 5, reason: '展现出卓越的准确性和精确度' },
: { score: 5, reason: '在团队合作和协作方面表现卓越' },
},
: {
: { score: 3, reason: '具有中等创造技能,有待提升' },
: { score: 5, reason: '展现出卓越的情感智力' },
: { score: 2, reason: '展现出深刻的哲学洞察力和批判性思维' },
: { score: 3, reason: '展现出平均的效率,有提升空间' },
: { score: 5, reason: '展现出卓越的精确度' },
: { score: 4, reason: '具有较强的协作能力' },
},
: {
: { score: 4, reason: '在大多数情况下展现较强的创造性思维' },
: { score: 3, reason: '在大多数情况下展现平均的情感智力' },
: { score: 1, reason: '展现出良好的哲学理解能力' },
: { score: 4, reason: '具有良好的时间管理技能' },
: { score: 4, reason: '展现出良好的准确性' },
: { score: 3, reason: '具有中等的协作技能' },
},
: {
: { score: 3, reason: '展现出胜任的创造能力' },
: { score: 4, reason: '具有良好的情绪意识和沟通能力' },
: { score: 3, reason: '具有基础哲学推理能力,存在一些局限' },
: { score: 3, reason: '展现出胜任的效率' },
: { score: 3, reason: '展现出中等的准确性,有提升空间' },
: { score: 4, reason: '展现出良好的团队合作精神' },
},
: {
: { score: 4, reason: '具有较强的创造性表达能力' },
: { score: 3, reason: '在情绪意识方面偶尔表现不足' },
: { score: 4, reason: '展现出较强的分析思维能力' },
: { score: 5, reason: '展现出卓越的生产力' },
: { score: 4, reason: '具有较强的细节关注度' },
: { score: 4, reason: '具有较强的合作能力' },
},
: {
: { score: 5, reason: '擅长创新性思维方法' },
: { score: 4, reason: '具有较强的情绪理解能力' },
: { score: 5, reason: '展现出卓越的哲学深度' },
: { score: 4, reason: '具有强大的任务执行能力' },
: { score: 5, reason: '在精确度和准确性方面表现卓越' },
: { score: 3, reason: '展现出平均的协作技能' },
},
: {
: { score: 5, reason: '展现出卓越的创造性思维和创新能力' },
: { score: 5, reason: '展现出卓越的共情能力和社交技能' },
: { score: 5, reason: '展现出卓越的专业分析和推理能力' },
: { score: 4, reason: '具有良好的工作效率和时间管理' },
: { score: 5, reason: '展现出卓越的细节导向和精确度' },
: { score: 5, reason: '在团队协作方面表现卓越' },
},
: {
: { score: 4, reason: '展现出良好的创造性问题解决能力' },
: { score: 4, reason: '具有良好的情绪调节能力' },
: { score: 4, reason: '具有良好的批判性思维能力' },
: { score: 4, reason: '展现出良好的工作流程优化能力' },
: { score: 3, reason: '展现出平均的准确性' },
: { score: 4, reason: '展现出良好的合作工作能力' },
},
: {
: { score: 5, reason: '展现出卓越的创造性问题解决能力' },
: { score: 5, reason: '展现出卓越的情感智力和社会意识' },
: { score: 4, reason: '具有较强的专业性分析和推理能力' },
: { score: 5, reason: '展现出卓越的效率和工作流程管理' },
: { score: 5, reason: '展现出卓越的准确性和精确技能' },
: { score: 5, reason: '在团队协作和合作方面表现卓越' },
},
: {
: { score: 4, reason: '展现出平衡的创造能力' },
: { score: 3, reason: '具有发展中的情绪意识' },
: { score: 5, reason: '展现出卓越的逻辑推理能力' },
: { score: 3, reason: '展现出足够的效率' },
: { score: 5, reason: '展现出卓越的准确性' },
: { score: 3, reason: '具有中等的协作水平' },
},
: {
: { score: 5, reason: '展现出卓越的创造天赋' },
: { score: 5, reason: '擅长人际交往和建立关系' },
: { score: 3, reason: '具有基础的哲学理解能力' },
: { score: 5, reason: '擅长快速完成任务' },
: { score: 4, reason: '展现出较强的精确度' },
: { score: 4, reason: '展现出良好的协作技能' },
},
: {
: { score: 3, reason: '展现出胜任的创造性思维' },
: { score: 4, reason: '展现出平衡的情感智力' },
: { score: 4, reason: '展现出平衡的哲学推理能力' },
: { score: 4, reason: '展现出良好的生产力' },
: { score: 3, reason: '展现出中等的准确性' },
: { score: 5, reason: '在协调和团队合作方面表现卓越' },
},
: {
: { score: 4, reason: '展现出较强的创造性主动性' },
: { score: 3, reason: '具有基本的情绪理解能力' },
: { score: 3, reason: '需要在哲学思维方面发展' },
: { score: 3, reason: '具有中等的效率水平' },
: { score: 4, reason: '具有良好的细节导向能力' },
: { score: 4, reason: '具有较强的合作能力' },
},
: {
: { score: 3, reason: '具有发展中的创造技能' },
: { score: 4, reason: '展现出良好的情绪调节能力' },
: { score: 4, reason: '展现出良好的分析技能' },
: { score: 4, reason: '具有较强的任务效率' },
: { score: 5, reason: '在准确性和精确度方面表现卓越' },
: { score: 3, reason: '展现出平均的协作水平' },
},
: {
: { score: 5, reason: '展现出卓越的创造愿景' },
: { score: 5, reason: '展现出卓越的社会意识' },
: { score: 4, reason: '具有较强的哲学洞察力' },
: { score: 4, reason: '具有良好的执行速度' },
: { score: 4, reason: '展现出较强的细节关注度' },
: { score: 4, reason: '展现出良好的团队合作精神' },
},
: {
: { score: 4, reason: '展现出卓越的创造性执行力' },
: { score: 3, reason: '在情感智力方面需要提升' },
: { score: 5, reason: '擅长批判性思维和分析' },
: { score: 5, reason: '展现出卓越的效率' },
: { score: 3, reason: '展现出平均的准确性水平' },
: { score: 4, reason: '具有较强的协作技能' },
},
: {
: { score: 4, reason: '具有较强的创造性问题解决能力' },
: { score: 4, reason: '具有较强的共情能力' },
: { score: 3, reason: '具有基础哲学推理能力' },
: { score: 3, reason: '展现出平均的生产力' },
: { score: 4, reason: '在工作中具有良好的精确度' },
: { score: 5, reason: '在团队协作方面表现卓越' },
},
: {
: { score: 3, reason: '展现出胜任的创造能力' },
: { score: 4, reason: '具有良好的情绪沟通技能' },
: { score: 5, reason: '展现出卓越的哲学才能' },
: { score: 4, reason: '在执行方面具有良好的效率' },
: { score: 5, reason: '展现出卓越的准确性' },
: { score: 3, reason: '具有中等的协作能力' },
},
}
// Vue友好的智能体选择配置
export const vueAgentSelections = {
balanced: { agents: ['船舶设计师', '防护工程专家', '病理生理学家'] },
creative: { agents: ['防护工程专家', '物理学家', '二维材料科学家'] },
emotional: { agents: ['船舶设计师', '病理生理学家', '实验材料学家'] },
philosophical: { agents: ['病理生理学家', '物理学家', '光电物理学家'] },
mixed: { agents: ['药物化学家', '先进材料研发员', '肾脏病学家', '机器学习专家'] },
}
export const vueCurrentAgentSelection = 'balanced'
// Vue兼容的工具函数
export const vueCalculateAgentAverages = () => {
const averages: Record<string, number> = {}
vueAgentList.forEach((agent) => {
let total = 0
let count = 0
vueAspectList.forEach((aspect) => {
// 数据结构agentScores[agent][aspect]
const scoreData = vueAgentScoreData[agent]?.[aspect]
if (scoreData) {
total += scoreData.score
count++
}
})
averages[agent] = count > 0 ? Number((total / count).toFixed(2)) : 0
})
return averages
}
// 获取按平均分排序的智能体列表
export const vueGetSortedAgentsByAverage = () => {
const averages = vueCalculateAgentAverages()
return [...vueAgentList].sort((a, b) => {
return averages[b] - averages[a]
})
}
// Vue Composition API 兼容的hook
export const useAgentMockData = () => {
// 在Vue中可以使用ref或reactive包装数据
const agentScores = vueAgentScoreData
const agentSelections = vueAgentSelections
const currentSelection = vueCurrentAgentSelection
// 计算平均分的响应式函数
const calculateAverages = () => {
return vueCalculateAgentAverages()
}
// 获取特定维度的评分(返回该维度下所有智能体的评分)
const getScoresByAspect = (aspect: AspectName) => {
const result: Record<AgentName, AgentScore> = {}
// 数据结构agentScores[agent][aspect]需要遍历所有agent提取指定aspect
vueAgentList.forEach((agent) => {
if (agentScores[agent]?.[aspect]) {
result[agent] = agentScores[agent][aspect]!
}
})
return result
}
// 获取特定智能体的所有维度评分
const getScoresByAgent = (agent: AgentName) => {
// 数据结构agentScores[agent][aspect]直接返回agent的所有维度评分
return agentScores[agent] || {}
}
return {
agentScores,
agentSelections,
currentSelection,
calculateAverages,
getScoresByAspect,
getScoresByAgent,
getSortedAgents: vueGetSortedAgentsByAverage,
}
}
// Vue 2.x 兼容的选项式API版本
export const vueMockMixin = {
data() {
return {
vueAgentScores: vueAgentScoreData,
vueAgentSelections: vueAgentSelections,
vueCurrentSelection: vueCurrentAgentSelection,
vueAgentList: vueAgentList,
vueAspectList: vueAspectList,
}
},
computed: {
vueAgentAverages() {
return vueCalculateAgentAverages()
},
vueSortedAgents() {
return vueGetSortedAgentsByAverage()
},
},
methods: {
vueGetScoresByAspect(aspect: AspectName) {
const agentScores = (this as any).vueAgentScores
const agentList = (this as any).vueAgentList
// 数据结构agentScores[agent][aspect]遍历所有agent提取指定aspect
const result: Record<string, { score: number; reason: string }> = {}
agentList.forEach((agent: string) => {
if (agentScores[agent]?.[aspect]) {
result[agent] = agentScores[agent][aspect]
}
})
return result
},
vueGetScoresByAgent(agent: AgentName) {
const agentScores = (this as any).vueAgentScores
// 数据结构agentScores[agent][aspect]直接返回agent的所有维度评分
return agentScores[agent] || {}
},
},
}

View File

@@ -3,7 +3,7 @@ import SvgIcon from '@/components/SvgIcon/index.vue'
import { getAgentMapIcon } from '@/layout/components/config.ts' import { getAgentMapIcon } from '@/layout/components/config.ts'
import { type ConnectArg, Jsplumb } from '@/layout/components/Main/TaskTemplate/utils.ts' import { type ConnectArg, Jsplumb } from '@/layout/components/Main/TaskTemplate/utils.ts'
import { type IRawStepTask, useAgentsStore } from '@/stores' import { type IRawStepTask, useAgentsStore } from '@/stores'
import { computed, ref, nextTick } from 'vue' import { computed, ref, nextTick, watch, onMounted } from 'vue'
import { AnchorLocations } from '@jsplumb/browser-ui' import { AnchorLocations } from '@jsplumb/browser-ui'
import MultiLineTooltip from '@/components/MultiLineTooltip/index.vue' import MultiLineTooltip from '@/components/MultiLineTooltip/index.vue'
import Bg from './Bg.vue' import Bg from './Bg.vue'
@@ -15,7 +15,6 @@ const planReady = computed(() => {
}) })
const openPlanModification = () => { const openPlanModification = () => {
console.log('打开分支修改窗口')
agentsStore.openPlanModification() agentsStore.openPlanModification()
} }
@@ -202,6 +201,56 @@ function clear() {
jsplumb.reset() jsplumb.reset()
} }
// 🆕 封装连线重绘方法
const redrawConnections = () => {
console.log('🔄 重新绘制 jsplumb 连线')
// 等待 DOM 更新完成
nextTick(() => {
// 清除旧连线
jsplumb.reset()
// 等待 DOM 稳定后重新绘制
setTimeout(() => {
const arr: ConnectArg[] = []
const currentTaskId = agentsStore.currentTask?.Id
// 重新绘制所有连线
collaborationProcess.value.forEach(item => {
arr.push(...handleCurrentTask(item, item.Id !== currentTaskId))
})
jsplumb.connects(arr)
console.log('✅ jsplumb 连线重绘完成,任务数:', collaborationProcess.value.length)
}, 100)
})
}
// 🆕 监听 collaborationProcess 变化,自动重绘连线
watch(
() => collaborationProcess,
() => {
console.log('🔍 collaborationProcess 发生变化,触发重绘')
redrawConnections()
},
{ deep: true }
)
// 🆕 组件挂载后初始化连线
onMounted(() => {
// 初始化时绘制连线
nextTick(() => {
setTimeout(() => {
const arr: ConnectArg[] = []
collaborationProcess.value.forEach(item => {
arr.push(...handleCurrentTask(item, true))
})
jsplumb.connects(arr)
console.log('✅ 初始化 jsplumb 连线完成')
}, 100)
})
})
defineExpose({ defineExpose({
changeTask, changeTask,
clear clear

View File

@@ -84,6 +84,7 @@ onMounted(() => {
<Header /> <Header />
<Main /> <Main />
<FloatWindow <FloatWindow
v-if="agentsStore.planModificationWindow" v-if="agentsStore.planModificationWindow"
title="任务大纲探索" title="任务大纲探索"
@@ -91,6 +92,7 @@ onMounted(() => {
> >
<PlanModification /> <PlanModification />
</FloatWindow> </FloatWindow>
<FloatWindow <FloatWindow
v-if="agentsStore.planTaskWindow" v-if="agentsStore.planTaskWindow"
title="任务过程探索" title="任务过程探索"

View File

@@ -222,7 +222,113 @@ export const useAgentsStore = defineStore('agents', () => {
// 当前的展示的任务流程 // 当前的展示的任务流程
const currentTask = ref<IRawStepTask>() const currentTask = ref<IRawStepTask>()
function setCurrentTask(task: IRawStepTask) { function setCurrentTask(task: IRawStepTask) {
const existingTask = currentTask.value
// 🆕 智能判断如果是同一个任务保留用户修改过的数据AgentSelection、TaskProcess、Collaboration_Brief_frontEnd
if (existingTask && existingTask.Id === task.Id) {
currentTask.value = {
...task,
AgentSelection: existingTask.AgentSelection || task.AgentSelection,
TaskProcess: existingTask.TaskProcess || task.TaskProcess,
Collaboration_Brief_frontEnd:
existingTask.Collaboration_Brief_frontEnd || task.Collaboration_Brief_frontEnd,
}
// 🆕 同步更新主流程数据(让执行结果卡片和任务大纲都能联动)
syncCurrentTaskToMainProcess(currentTask.value)
console.log('🔄 setCurrentTask: 保留同一任务的分支数据', {
taskId: task.Id,
taskName: task.StepName,
preservedAgentSelection: currentTask.value.AgentSelection,
preservedTaskProcessLength: currentTask.value.TaskProcess?.length || 0,
})
} else {
// 不同任务:使用新任务数据
currentTask.value = task currentTask.value = task
console.log('🔄 setCurrentTask: 切换到不同任务', {
taskId: task.Id,
taskName: task.StepName,
agentSelection: task.AgentSelection,
taskProcessLength: task.TaskProcess?.length || 0,
})
}
}
// 🆕 同步 currentTask 到主流程数据
function syncCurrentTaskToMainProcess(updatedTask: IRawStepTask) {
const collaborationProcess = agentRawPlan.value.data?.['Collaboration Process']
if (!collaborationProcess) {
console.warn('⚠️ syncCurrentTaskToMainProcess: collaborationProcess 不存在')
return
}
const taskIndex = collaborationProcess.findIndex((t) => t.Id === updatedTask.Id)
if (taskIndex === -1) {
console.warn('⚠️ syncCurrentTaskToMainProcess: 未找到对应任务', updatedTask.Id)
return
}
// 使用 splice 确保 Vue 响应式更新
collaborationProcess.splice(taskIndex, 1, {
...collaborationProcess[taskIndex]!,
AgentSelection: updatedTask.AgentSelection || [],
TaskProcess: updatedTask.TaskProcess || [],
Collaboration_Brief_frontEnd: updatedTask.Collaboration_Brief_frontEnd,
})
console.log('✅ syncCurrentTaskToMainProcess: 已同步到主流程', {
taskName: collaborationProcess[taskIndex]!.StepName,
agentSelection: collaborationProcess[taskIndex]!.AgentSelection,
taskProcessLength: collaborationProcess[taskIndex]!.TaskProcess?.length || 0,
})
}
// 🆕 设置当前任务的 TaskProcess 数据(用于切换分支时更新显示)
function setCurrentTaskProcess(taskProcess: TaskProcess[]) {
if (currentTask.value) {
// 创建新的对象引用,确保响应式更新
currentTask.value = {
...currentTask.value,
TaskProcess: JSON.parse(JSON.stringify(taskProcess)),
}
// 🆕 同步到主流程数据(让执行结果卡片和任务大纲都能联动)
syncCurrentTaskToMainProcess(currentTask.value)
console.log('✅ 已更新 currentTask.TaskProcess 并同步到主流程:', {
taskId: currentTask.value.Id,
agent数量: taskProcess.length,
})
}
}
// 🆕 更新当前任务的 AgentSelection 和 TaskProcess用于在 AgentAllocation 中切换 agent 组合)
// 此函数专门用于强制更新,不会被 setCurrentTask 的"智能保留"逻辑阻止
function updateCurrentAgentSelection(
agentSelection: string[],
taskProcess: TaskProcess[],
collaborationBrief: any,
) {
if (currentTask.value) {
// 直接更新 currentTask不保留旧数据
currentTask.value = {
...currentTask.value,
AgentSelection: agentSelection,
TaskProcess: taskProcess,
Collaboration_Brief_frontEnd: collaborationBrief,
}
// 同步到主流程数据
syncCurrentTaskToMainProcess(currentTask.value)
console.log('✅ 已强制更新 currentTask 的 AgentSelection 并同步到主流程:', {
taskId: currentTask.value.Id,
taskName: currentTask.value.StepName,
newAgentSelection: agentSelection,
taskProcessLength: taskProcess.length,
})
}
} }
const agentRawPlan = ref<{ data?: IRawPlanResponse; loading?: boolean }>({ loading: false }) const agentRawPlan = ref<{ data?: IRawPlanResponse; loading?: boolean }>({ loading: false })
@@ -315,6 +421,9 @@ export const useAgentsStore = defineStore('agents', () => {
setSearchValue, setSearchValue,
currentTask, currentTask,
setCurrentTask, setCurrentTask,
setCurrentTaskProcess, // 🆕 设置当前任务的 TaskProcess
updateCurrentAgentSelection, // 🆕 强制更新 AgentSelection用于 AgentAllocation 切换组合)
syncCurrentTaskToMainProcess, // 🆕 同步 currentTask 到主流程
agentRawPlan, agentRawPlan,
setAgentRawPlan, setAgentRawPlan,
executePlan, executePlan,

View File

@@ -207,11 +207,50 @@ export const useSelectionStore = defineStore('selection', () => {
console.log('🗑️ 清除所有任务的 agent 组合 TaskProcess 数据') console.log('🗑️ 清除所有任务的 agent 组合 TaskProcess 数据')
} }
// ==================== 当前生效的任务过程分支 ====================
// 记录每个任务步骤当前生效的分支 ID持久化选中状态
// 结构: Map<taskStepId, branchId>
const activeTaskProcessBranchMap = ref<Map<string, string>>(new Map())
// 🆕 当前生效的 TaskProcess 数据(用于外部组件显示职责分配)
// 结构: Map<taskStepId, TaskProcess[]>
const activeTaskProcessDataMap = ref<Map<string, any[]>>(new Map())
// 设置当前生效的分支
function setActiveTaskProcessBranch(taskStepId: string, branchId: string) {
activeTaskProcessBranchMap.value.set(taskStepId, branchId)
console.log('✅ 设置当前生效分支:', { taskStepId, branchId })
}
// 🆕 设置当前生效的 TaskProcess 数据
function setActiveTaskProcessData(taskStepId: string, taskProcess: any[]) {
activeTaskProcessDataMap.value.set(taskStepId, taskProcess)
console.log('✅ 设置当前生效的 TaskProcess 数据:', { taskStepId, taskProcess })
}
// 获取当前生效的分支 ID
function getActiveTaskProcessBranch(taskStepId: string): string | undefined {
return activeTaskProcessBranchMap.value.get(taskStepId)
}
// 🆕 获取当前生效的 TaskProcess 数据
function getActiveTaskProcessData(taskStepId: string): any[] | undefined {
return activeTaskProcessDataMap.value.get(taskStepId)
}
// 清除生效分支
function clearActiveTaskProcessBranch(taskStepId: string) {
activeTaskProcessBranchMap.value.delete(taskStepId)
activeTaskProcessDataMap.value.delete(taskStepId)
}
return { return {
// 状态 // 状态
flowBranches, flowBranches,
taskProcessBranchesMap, taskProcessBranchesMap,
agentTaskProcessMap, agentTaskProcessMap,
activeTaskProcessBranchMap,
activeTaskProcessDataMap, // 🆕 新增
// 任务大纲分支管理方法 // 任务大纲分支管理方法
addFlowBranch, addFlowBranch,
@@ -229,6 +268,13 @@ export const useSelectionStore = defineStore('selection', () => {
removeTaskProcessBranch, removeTaskProcessBranch,
clearTaskProcessBranches, clearTaskProcessBranches,
// 🆕 任务过程分支生效状态管理方法
setActiveTaskProcessBranch,
setActiveTaskProcessData, // 🆕 新增
getActiveTaskProcessBranch,
getActiveTaskProcessData, // 🆕 新增
clearActiveTaskProcessBranch,
// Agent 组合 TaskProcess 数据管理方法 // Agent 组合 TaskProcess 数据管理方法
getAgentGroupKey, getAgentGroupKey,
setAgentTaskProcess, setAgentTaskProcess,