diff --git a/package.json b/package.json index cc306759201967ff7e85740ef893b0532491b92a..93ed47a2cc6c610324aae71b412feeaff098f337 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ "eslint": "9.16.0", "eslint-plugin-vue": "9.32.0", "globals": "15.13.0", + "mitt": "^3.0.1", "prettier": "3.4.2", "typescript-eslint": "8.17.0", "uuid": "^11.0.5", diff --git a/src/assets/styles/theme.scss b/src/assets/styles/theme.scss index 6cce089a7abc774ad2534f748ee05e246a953f05..6d8b29e111cfea48695ae91c16db829c1b613e6b 100644 --- a/src/assets/styles/theme.scss +++ b/src/assets/styles/theme.scss @@ -20,6 +20,8 @@ body[theme='dark'] { --flow-node-boder-default-over: #314265; --flow-node-success-over-color: #1F312A; --flow-node-error-over-color: #332127; + --flow-branch-node-error-node-cover-color: #602c27; + --flow-branch-node-success-node-cover-color: #295336; } body[theme='light'] { @@ -44,4 +46,6 @@ body[theme='light'] { --flow-node-boder-default-over: #c7d6f5; --flow-node-success-over-color: #e6f6e9; --flow-node-error-over-color: #f8e7e7; + --flow-branch-node-error-node-cover-color: #edb3b3; + --flow-branch-node-success-node-cover-color: #b3dbb8; } diff --git a/src/bus/index.ts b/src/bus/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..0020e13cd319177b6d1618d55502639e1b53965c --- /dev/null +++ b/src/bus/index.ts @@ -0,0 +1,4 @@ +// 引入mitt +import mitt from 'mitt' +const bus = mitt(); +export default bus; \ No newline at end of file diff --git a/src/components/dialoguePanel/DialoguePanel.vue b/src/components/dialoguePanel/DialoguePanel.vue index 7288af2ebe7a3e209c42676aa35cdadd9ba7337b..751cf80ef3b5764c916bc3712044316f11166251 100644 --- a/src/components/dialoguePanel/DialoguePanel.vue +++ b/src/components/dialoguePanel/DialoguePanel.vue @@ -1119,10 +1119,13 @@ const handleSendMessage = async (question, user_selected_flow, user_selected_app height: 20px; } } -// 工作流调试抽屉样式-- +// 工作流调试抽屉样式 .workFlowDebugStyle { width: auto; padding-right: 24px; + .loading { + display: none; + } .dialogue-panel__content { gap: 16px; .userArea { diff --git a/src/store/conversation.ts b/src/store/conversation.ts index 8847cae1cc876377f2d632d0d390ed3df9f8a32d..a962de852ee8b3a308ca09c1f016f929d17ba275 100644 --- a/src/store/conversation.ts +++ b/src/store/conversation.ts @@ -24,8 +24,9 @@ import { ElMessageBox } from 'element-plus'; import { qiankunWindow } from 'vite-plugin-qiankun/dist/helper'; import { storeToRefs } from 'pinia'; import { Application } from 'src/apis/paths/type'; - +import $bus from 'src/bus/index' const STREAM_URL = '/api/chat'; +const newStreamUrl = 'api/mock/chat'; let controller = new AbortController(); export var txt2imgPath = ref(""); export var echartsObj = ref({}); @@ -88,6 +89,7 @@ export const useSessionStore = defineStore('conversation', () => { user_selected_flow?: string; groupId?: string; params?: any; + type?: any; }, ind?: number ): Promise => { @@ -115,26 +117,44 @@ export const useSessionStore = defineStore('conversation', () => { pp = {}; } if (params.user_selected_flow) { - resp = await fetch(STREAM_URL, { - signal: controller.signal, - method: 'POST', - keepalive: true, - headers: headers, - body: JSON.stringify({ - question: params.question, - language, - conversationId: params.conversationId, - groupId: params.groupId, - // record_id: params.qaRecordId, - app:{ + // 之前的对话历史记录 + if (!params.type) { + resp = await fetch(STREAM_URL, { + signal: controller.signal, + method: 'POST', + keepalive: true, + headers: headers, + body: JSON.stringify({ + question: params.question, + language, + conversationId: params.conversationId, + groupId: params.groupId, + // record_id: params.qaRecordId, + app:{ + appId:params.user_selected_app[0], + flowId: params.user_selected_flow, + params: pp, + auth:{}, + }, + features:features, + }), + }); + } else { + // 新的工作流调试记录 + resp = await fetch(newStreamUrl, { + signal: controller.signal, + method: 'POST', + keepalive: true, + headers: headers, + body: JSON.stringify({ + question: params.question, appId:params.user_selected_app[0], + conversationId: params.conversationId, flowId: params.user_selected_flow, - params: pp, - auth:{}, - }, - features:features, - }), - }); + }), + }); + + } } else if (params.user_selected_app) { resp = await fetch(STREAM_URL, { @@ -258,17 +278,13 @@ export const useSessionStore = defineStore('conversation', () => { conversationItem.groupId = message.groupId; } else if(message["event"] === "flow.start") { - //事件流开始 - // display:boolean, - // progress:string, - // id:number - // title:string, - // data:any, + //事件流开始--后续验证对话无下拉连接后则完全替换 let flow = message.flow; conversationItem.flowdata = { - id: flow?.step_name||"", + id: flow?.stepName||"", title: i18n.global.t('flow.flow_start'), - progress: flow?.step_progresss||"", + // 工作流这里stepName代替step_progresss,为不影响首页对话暂且用|| + progress: flow?.stepProgress || "", status:'running', display:true, flowId:flow?.flowId||"", @@ -281,25 +297,25 @@ export const useSessionStore = defineStore('conversation', () => { // target.data.input = message // } conversationItem.flowdata?.data[0].push({ - id:message.flow?.step_name, - title:message.flow?.step_name, - status:message.flow?.step_status, + id:message.flow?.stepName, + title:message.flow?.stepName, + status:message.flow?.stepStatus, data:{ input:message.content, } }) if(conversationItem.flowdata){ - conversationItem.flowdata.progress = message.flow?.step_progress; - conversationItem.flowdata.status = message.flow?.step_status; + conversationItem.flowdata.progress = message.flow?.stepProgress; + conversationItem.flowdata.status = message.flow?.stepStatus; } } else if(message["event"] === "step.output") { - const target = conversationItem.flowdata?.data[0].find(item => item.id === message.flow.step_name); + const target = conversationItem.flowdata?.data[0].find(item => item.id === message.flow.stepName); if (target) { target.data.output = message.content - target.status = message.flow.step_status; + target.status = message.flow?.stepStatus; if(message.flow.step_status === "error"){ - conversationItem.flowdata.status = message.flow?.step_status; + conversationItem.flowdata.status = message.flow?.stepStatus; } } } @@ -310,15 +326,15 @@ export const useSessionStore = defineStore('conversation', () => { conversationItem.flowdata?.data[0].push({ id:"end", title:"end", - status:message.flow?.step_status, + status:message.flow?.stepStatus, data:{ input:message.content, } }) conversationItem.flowdata = { - id: flow?.step_name, + id: flow?.stepName, title: i18n.global.t('flow.flow_end'), - progress: flow?.step_progress, + progress: flow?.stepProgress, status:"success", display:true, data:conversationItem.flowdata.data, @@ -336,6 +352,10 @@ export const useSessionStore = defineStore('conversation', () => { } } }); + // 将lines传递给workflow-以更新工作流节点的状态 + if(params.user_selected_flow && params.user_selected_app) { + $bus.emit('getNodesStatue', lines); + } } } catch (err: any) { isPaused.value = true; @@ -458,11 +478,12 @@ export const useSessionStore = defineStore('conversation', () => { qaRecordId?: string, user_selected_flow?: string, params?: any, + type?: any, ): Promise => { const { updateSessionTitle, currentSelectedSession } = useHistorySessionStore(); if (conversationList.value.length === 0) { // 如果当前还没有对话记录,将第一个问题的questtion作为对话标题 - updateSessionTitle({ conversationId: currentSelectedSession, title: question.slice(0, 20) }); + const res = await updateSessionTitle({ conversationId: currentSelectedSession, title: question.slice(0, 20) }); } if (regenerateInd) { // 重新生成,指定某个回答,修改默认索引 @@ -506,6 +527,7 @@ export const useSessionStore = defineStore('conversation', () => { user_selected_flow, groupId:groupId, params:params||undefined, + type: type }, regenerateInd ?? undefined ) diff --git a/src/views/api/style.scss b/src/views/api/style.scss index b8fd4b7373c0869da8dc1a0eebd7c17450444a0a..7ee635ab20f6b228b7801e17469dddd3589dbcd9 100644 --- a/src/views/api/style.scss +++ b/src/views/api/style.scss @@ -58,7 +58,7 @@ .appCenterCardContainer { margin-top: 16px; width: fit-content; - max-width: 1328px; + max-width: 1336px; .appCenterCardBox { width: fit-content; display: flex; diff --git a/src/views/app/index.vue b/src/views/app/index.vue index a0215ee67f860b7ccf1d9c7f9ae162ab77884741..5d2fece6ed750958760cfee80d9524673817ac38 100644 --- a/src/views/app/index.vue +++ b/src/views/app/index.vue @@ -35,7 +35,7 @@
-
+
+
{ }; const routerToDetail = appItem => { + if (!appItem.published && appType.value === 'createdByMe') { + return; + } //获取appItem.id & appItem.name - router.push(`/copilot?appId=${appItem.appId}&name=${encodeURIComponent(encodeURI(appItem.name))}`); + router.push(`/copilot?appId=${appItem.appId}&name=${appItem.name}`); }; const handleParmasQueryAppList = (params?: any) => { diff --git a/src/views/app/style.scss b/src/views/app/style.scss index 96eb9d7e406ca6227ef8d1b0fbe19f4907ac8aa3..878576ce4c2a1815ec2bff1846ac61929c1756a4 100644 --- a/src/views/app/style.scss +++ b/src/views/app/style.scss @@ -31,6 +31,7 @@ .createApp { margin-left: 16px; + border-radius: 4px; } } @@ -155,6 +156,12 @@ ) !important; } } + .appCenterNoData { + width: 480px; + height: 240px; + background-image: var(--no-work-flow); + background-size: contain; + } } ::-webkit-scrollbar { width: 4px; diff --git a/src/views/createapp/components/codeMirror/nodeMirrorText.vue b/src/views/createapp/components/codeMirror/nodeMirrorText.vue index 4d3327d1437387a10c3a7dc42b8b68e9f434c87a..a9a24d1511d396730c97f72d883fb38487b58bc9 100644 --- a/src/views/createapp/components/codeMirror/nodeMirrorText.vue +++ b/src/views/createapp/components/codeMirror/nodeMirrorText.vue @@ -29,19 +29,27 @@ diff --git a/src/views/createapp/components/workFlowConfig/BranchNode.vue b/src/views/createapp/components/workFlowConfig/BranchNode.vue index adfc20145a239186b5fff78ad27b27e7f809c13a..96dcb3834d852a7ae91d2d0b8734c47be618e118 100644 --- a/src/views/createapp/components/workFlowConfig/BranchNode.vue +++ b/src/views/createapp/components/workFlowConfig/BranchNode.vue @@ -23,12 +23,16 @@ const props = defineProps({ }); const emits = defineEmits(['delNode', 'editYamlDrawer']); -const statusList = ref(['running', 'success', 'error']); +const statusList = ref(['pending', 'success', 'error']); const branchIdList = ref([]); +// 当前节点状态-工作流调试结果-成功/失败/运行中 const curStatus = ref(''); +// 当前节点运行耗时 +const costTime = ref(''); + watch( () => props.data, () => { @@ -38,10 +42,12 @@ watch( } else { curStatus.value = props.data?.status; } - if (props.data.parameters?.input_parameters?.input_parameters) { - branchIdList.value = props.data.parameters.input_parameters.input_parameters.choices?.choices?.map(item => item?.branchId); + costTime.value = props.data?.constTime || ''; + if (props.data?.parameters?.input_parameters?.choices) { + branchIdList.value = props.data?.parameters?.input_parameters?.choices.map( + item => item?.branchId, + ); } - console.log(props.data.parameters?.input_parameters?.input_parameters?.choices?.choices, 'props', branchIdList.value) }, { deep: true, immediate: true }, ); @@ -75,10 +81,13 @@ const editYaml = (nodeName, yamlCode) => {
{{ props.data.description }}
-
-
+
+
{{ item.description }} -
@@ -86,7 +95,13 @@ const editYaml = (nodeName, yamlCode) => {
- +
@@ -106,7 +121,7 @@ const editYaml = (nodeName, yamlCode) => { position: relative; margin-bottom: 8px; .vue-flow__handle-right { - right: -18px; + right: -30px; } &:last-child { margin-bottom: 0px; @@ -124,5 +139,21 @@ const editYaml = (nodeName, yamlCode) => { } } } + .customNodeStyle.default { + .branchDesc { + .branchItem { + .vue-flow__handle-right { + right: -18px; + } + } + } + &:hover { + .branchItem { + .vue-flow__handle-right { + right: -30px; + } + } + } + } } diff --git a/src/views/createapp/components/workFlowConfig/CustomNode.vue b/src/views/createapp/components/workFlowConfig/CustomNode.vue index 4cd53c782654fcac417efe8fc7f2eff4ad0936f0..0e1198e2c6e6ff2115a454f21a5f597b95fe4a15 100644 --- a/src/views/createapp/components/workFlowConfig/CustomNode.vue +++ b/src/views/createapp/components/workFlowConfig/CustomNode.vue @@ -28,8 +28,12 @@ const emits = defineEmits(['delNode', 'editYamlDrawer']); const statusList = ref(['running', 'success', 'error']); +// 当前节点状态-工作流调试结果-成功/失败/运行中 const curStatus = ref(''); +// 当前节点运行耗时 +const costTime = ref(''); + watch( () => props.data, () => { @@ -39,10 +43,12 @@ watch( } else { curStatus.value = props.data?.status; } + costTime.value = props.data?.constTime || ''; }, { deep: true, immediate: true }, ); +// 删除节点 const delNode = id => { emits('delNode', id); }; @@ -79,6 +85,12 @@ const editYaml = (nodeName, yamlCode) => {
- +
diff --git a/src/views/createapp/components/workFlowDebug.vue b/src/views/createapp/components/workFlowDebug.vue index 354efea6cb5b4b93f79a9b9287618fcc7454dc45..9e94fd98aee6fb8a0b2feba4a05890362e0b2f9e 100644 --- a/src/views/createapp/components/workFlowDebug.vue +++ b/src/views/createapp/components/workFlowDebug.vue @@ -111,7 +111,7 @@ const handleSendMessage = async (groupId: string | undefined, question: string, if (!currentSelectedSession.value) { await generateSessionDebug({ debug: true }); } - await sendQuestion(groupId, question, [props.appId], undefined, undefined, props.flowId, undefined); + await sendQuestion(groupId, question, [props.appId], undefined, undefined, props.flowId, undefined, true); }; const clearSuggestion = (index: number): void => { diff --git a/src/views/dialogue/components/DialogueAside.vue b/src/views/dialogue/components/DialogueAside.vue index 7998f2ded980d7657b737ce2b775f2ad6cd5da08..5c50129feb58da4ec5b9024625c15e95e7070ed6 100644 --- a/src/views/dialogue/components/DialogueAside.vue +++ b/src/views/dialogue/components/DialogueAside.vue @@ -50,7 +50,6 @@ const isCollapsed = ref(false); const selectedAppId = ref(null); // const apps = ref([ - { appId: "1", name: 'CVE热修复助手' }, ]); const filteredHistorySessions = computed(() => { diff --git a/src/views/styles/workFlowArrange.scss b/src/views/styles/workFlowArrange.scss index 6915c15f849f1be86987101c4f79e4eb03e5b777..909414dde25f487645fd685069e8036cd0f07843 100644 --- a/src/views/styles/workFlowArrange.scss +++ b/src/views/styles/workFlowArrange.scss @@ -80,7 +80,7 @@ width: 312px; min-width: 256px; background-color: var(--o-bg-color-base); - padding: 24px 0px 24px 24px; + padding: 24px 4px 24px 24px; display: flex; flex-direction: column; border-radius: 8px; @@ -88,10 +88,14 @@ } .apiCenterBox { + height: 100%; + display: flex; + flex-direction: column; .apiCenterTitle { color: var(--o-text-color-primary); font-size: 16px; font-weight: 700; + line-height: 24px; } .apiCenterSearch { margin: 8px 0; @@ -108,21 +112,25 @@ } .apiContanter { - .el-collapse-item__header { - padding: 0 !important; - height: 28px; - font-size: 14px; - color: var(--o-text-color-primary); - display: flex; - gap: 8px; - text-align: left; - flex-wrap: nowrap; - .el-icon { - color: var(--o-text-color-tertiary); + flex: 1; + overflow: auto; + .el-collapse { + .el-collapse-item__header { + padding: 0 !important; + height: 28px; + font-size: 14px; + color: var(--o-text-color-primary); + display: flex; + gap: 8px; + text-align: left; + flex-wrap: nowrap; + .el-icon { + color: var(--o-text-color-tertiary); + } + } + .el-collapse-item__content { + margin-left: 0px; } - } - .el-collapse-item__content { - margin-left: 0px; } } } @@ -488,6 +496,9 @@ .outRingRight { box-shadow: 0px 0px 0px 8px rgba(36, 171, 54, 0.1); } + .leftNodeBox { + background-color: var(--flow-branch-node-success-node-cover-color); + } .leftBox { background-color: var(--flow-node-success-over-color); } @@ -542,6 +553,10 @@ } .outRingRight { box-shadow: 0px 0px 0px 8px rgba(227, 32, 32, 0.1); + display: none; + } + .leftNodeBox { + background-color: var(--flow-branch-node-error-node-cover-color); } .leftBox { background-color: var(--flow-node-error-over-color); @@ -551,6 +566,62 @@ } } } + + .customNodeStyle.running { + border: 4px solid rgba(99, 149, 253, 0.3); + box-shadow: 0px 0px 0px 8px rgba(99, 149, 253, 0.1); + .vue-flow__handle-left { + transform: rotate(-45deg); + width: 24px; + height: 24px; + left: -12px; + margin-top: -12px; + border: 4px solid rgba(99, 149, 253, 0.3); + border-right: 4px solid transparent; + border-bottom: 4px solid transparent; + &::after { + border: 4px solid rgba(99, 149, 253, 0.3); + background: rgba(99, 149, 253); + background-clip: content-box; + } + } + .vue-flow__handle-right { + width: 24px; + height: 24px; + right: -12px; + margin-top: -12px; + transform: rotate(45deg); + border: 4px solid rgba(99, 149, 253, 0.3); + border-left: 4px solid transparent; + border-bottom: 4px solid transparent; + &::after { + border: 4px solid rgba(99, 149, 253, 0.3); + background: rgba(99, 149, 253); + background-clip: content-box; + } + } + .leftBox { + background-color: transparent; + } + .rightBox { + background-color: transparent; + } + &:hover { + box-shadow: 0px 0px 0px 8px rgba(99, 149, 253, 0.1); + .outRingLeft { + box-shadow: 0px 0px 0px 8px rgba(99, 149, 253, 0.1); + } + .outRingRight { + box-shadow: 0px 0px 0px 8px rgba(99, 149, 253, 0.1); + } + .leftBox { + background-color: var(--flow-node-default-over-color); + } + .rightBox { + background-color: var(--flow-node-default-over-color); + } + } + } } .vue-flow__node:has(.default) { margin-top: 0px;