From d20172626221e98a0e3c8c492b367082b1c97381 Mon Sep 17 00:00:00 2001
From: Ethan-Zhang
Date: Sun, 17 Aug 2025 07:49:44 +0800
Subject: [PATCH 1/4] =?UTF-8?q?Feat:=20=E5=90=88=E5=85=A5release-0.10.0?=
=?UTF-8?q?=E5=8F=98=E6=9B=B4=EF=BC=8C=E4=B8=BArelease-0.10.1=E9=93=BA?=
=?UTF-8?q?=E5=9E=AB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Dockerfile | 30 +-
build/linux/euler-copilot-web.spec | 9 +-
build/linux/nginx.conf.local.tmpl | 8 +-
deploy/nginx.conf.tmpl | 25 +-
electron/main/common/locale.ts | 4 +-
electron/main/common/platform.ts | 2 +-
src/apis/appCenter/appCenterService.ts | 13 +
src/apis/paths/account.ts | 1 +
src/apis/paths/conversation.ts | 12 +-
src/apis/paths/mcp.ts | 18 +-
src/apis/paths/type.ts | 11 +-
src/apis/workFlow/workFlowService.ts | 3 +-
src/assets/svgs/file_download.svg | 13 +
src/assets/svgs/file_download_active.svg | 13 +
src/assets/svgs/file_download_hover.svg | 13 +
src/assets/svgs/html.svg | 28 +
src/assets/svgs/jpeg.svg | 27 +
src/assets/svgs/json.svg | 28 +
src/assets/svgs/png.svg | 28 +
src/assets/svgs/pptx.svg | 28 +
src/assets/svgs/txt_green.svg | 28 +
src/assets/svgs/warning.svg | 8 +
src/assets/svgs/yaml.svg | 28 +
src/assets/svgs/zip.svg | 28 +
src/components/commonFooter/CommonFooter.vue | 28 +-
src/components/dialoguePanel/DialogueFlow.vue | 214 +++-
.../dialoguePanel/DialoguePanel.scss | 6 -
.../dialoguePanel/DialoguePanel.vue | 346 +++++-
src/components/dialoguePanel/FlowCode.vue | 55 +-
src/components/dialoguePanel/ParamsModel.vue | 137 +++
src/i18n/index.ts | 18 +-
src/i18n/lang/en.ts | 528 ++++-----
src/i18n/lang/zh-cn.ts | 101 +-
src/store/account.ts | 3 +
src/store/conversation.ts | 465 ++++----
src/store/historySession.ts | 5 +-
src/store/lang.ts | 4 +-
src/views/api/components/ActiveModel.vue | 167 +++
src/views/api/components/McpDrawer.vue | 40 +-
src/views/api/components/PluginCard.vue | 3 +-
src/views/api/index.vue | 219 +++-
.../createapp/components/AgentAppConfig.vue | 11 +-
src/views/createapp/components/DebugApp.vue | 492 ++++----
src/views/createapp/components/McpDrawer.vue | 129 ++-
src/views/createapp/components/types.ts | 72 +-
src/views/createapp/components/workFlow.vue | 28 +-
.../components/workFlowConfig/BranchNode.vue | 262 -----
.../workFlowConfig/ChoiceBranchDrawer.vue | 2 +-
.../VariableAssignNodeDrawer.vue | 2 +-
.../workFlowConfig/workFlowDialog.vue | 4 +-
.../workFlowConfig/yamlEditDrawer.vue | 14 +-
src/views/createapp/index.vue | 10 +
.../dialogue/components/DialogueSession.vue | 245 +++-
.../dialogue/components/MultiSelectTags.vue | 5 +
src/views/dialogue/components/TitleBar.vue | 4 +-
src/views/dialogue/types.ts | 1 +
.../analysis.md | 57 +
...nents_dialoguePanel__DialogueFlow.vue.diff | 318 ++++++
.../analysis.md | 22 +
...nts_dialoguePanel__DialoguePanel.scss.diff | 12 +
.../analysis.md | 28 +
...ents_dialoguePanel__DialoguePanel.vue.diff | 84 ++
.../analysis.md | 49 +
...ws_createapp_components__DebugApp.vue.diff | 611 ++++++++++
.../analysis.md | 31 +
...ws_createapp_components__workFlow.vue.diff | 246 ++++
.../analysis.md | 28 +
...ts_workFlowConfig__workFlowDialog.vue.diff | 22 +
.../analysis.md | 30 +
...ts_workFlowConfig__yamlEditDrawer.vue.diff | 1004 +++++++++++++++++
.../analysis.md | 40 +
...logue_components__DialogueSession.vue.diff | 460 ++++++++
...30\346\233\264\346\200\273\347\273\223.md" | 432 +++++++
73 files changed, 6178 insertions(+), 1322 deletions(-)
create mode 100644 src/assets/svgs/file_download.svg
create mode 100644 src/assets/svgs/file_download_active.svg
create mode 100644 src/assets/svgs/file_download_hover.svg
create mode 100644 src/assets/svgs/html.svg
create mode 100644 src/assets/svgs/jpeg.svg
create mode 100644 src/assets/svgs/json.svg
create mode 100644 src/assets/svgs/png.svg
create mode 100644 src/assets/svgs/pptx.svg
create mode 100644 src/assets/svgs/txt_green.svg
create mode 100644 src/assets/svgs/warning.svg
create mode 100644 src/assets/svgs/yaml.svg
create mode 100644 src/assets/svgs/zip.svg
create mode 100644 src/components/dialoguePanel/ParamsModel.vue
create mode 100644 src/views/api/components/ActiveModel.vue
delete mode 100644 src/views/createapp/components/workFlowConfig/BranchNode.vue
create mode 100644 web_diff/file_analyses/src_components_dialoguePanel_DialogueFlow.vue/analysis.md
create mode 100644 web_diff/file_analyses/src_components_dialoguePanel_DialogueFlow.vue/src_components_dialoguePanel__DialogueFlow.vue.diff
create mode 100644 web_diff/file_analyses/src_components_dialoguePanel_DialoguePanel.scss/analysis.md
create mode 100644 web_diff/file_analyses/src_components_dialoguePanel_DialoguePanel.scss/src_components_dialoguePanel__DialoguePanel.scss.diff
create mode 100644 web_diff/file_analyses/src_components_dialoguePanel_DialoguePanel.vue/analysis.md
create mode 100644 web_diff/file_analyses/src_components_dialoguePanel_DialoguePanel.vue/src_components_dialoguePanel__DialoguePanel.vue.diff
create mode 100644 web_diff/file_analyses/src_views_createapp_components_DebugApp.vue/analysis.md
create mode 100644 web_diff/file_analyses/src_views_createapp_components_DebugApp.vue/src_views_createapp_components__DebugApp.vue.diff
create mode 100644 web_diff/file_analyses/src_views_createapp_components_workFlow.vue/analysis.md
create mode 100644 web_diff/file_analyses/src_views_createapp_components_workFlow.vue/src_views_createapp_components__workFlow.vue.diff
create mode 100644 web_diff/file_analyses/src_views_createapp_components_workFlowConfig_workFlowDialog.vue/analysis.md
create mode 100644 web_diff/file_analyses/src_views_createapp_components_workFlowConfig_workFlowDialog.vue/src_views_createapp_components_workFlowConfig__workFlowDialog.vue.diff
create mode 100644 web_diff/file_analyses/src_views_createapp_components_workFlowConfig_yamlEditDrawer.vue/analysis.md
create mode 100644 web_diff/file_analyses/src_views_createapp_components_workFlowConfig_yamlEditDrawer.vue/src_views_createapp_components_workFlowConfig__yamlEditDrawer.vue.diff
create mode 100644 web_diff/file_analyses/src_views_dialogue_components_DialogueSession.vue/analysis.md
create mode 100644 web_diff/file_analyses/src_views_dialogue_components_DialogueSession.vue/src_views_dialogue_components__DialogueSession.vue.diff
create mode 100644 "web_diff/\345\217\230\346\233\264\346\200\273\347\273\223.md"
diff --git a/Dockerfile b/Dockerfile
index 556ab0e5..e477cfd2 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,20 +1,33 @@
+# 第一阶段:构建前端项目
FROM node:22.14.0-alpine
WORKDIR /opt
-COPY . .
-# ENV HTTPS_PROXY=
-ENV ELECTRON_MIRROR="https://npmmirror.com/mirrors/electron/"
-RUN npm install pnpm -g --registry=https://registry.npmmirror.com && \
- pnpm install --registry=https://registry.npmmirror.com && \
- pnpm run build
-
+# 更换Alpine为国内镜像源(解决apk安装失败问题)
+RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
+COPY . .
+# 配置国内镜像,加速Electron及依赖下载
+ENV ELECTRON_MIRROR="https://npmmirror.com/mirrors/electron/" \
+ ELECTRON_BUILDER_BINARIES_MIRROR="https://npmmirror.com/mirrors/electron-builder-binaries/"
+
+# 安装必要工具(git+ssh客户端+CA证书),并配置Git协议转换
+RUN apk add --no-cache git openssh-client ca-certificates \
+ && git config --global url."https://github.com/".insteadOf git@github.com: \
+ && git config --global url."https://".insteadOf git:// \
+ && npm install pnpm -g --registry=https://registry.npmmirror.com \
+ && pnpm config set registry https://registry.npmmirror.com \
+ && pnpm config set network-timeout 600000 \
+ && pnpm install \
+ && pnpm run build
+
+# 第二阶段:部署到nginx
FROM hub.oepkgs.net/openeuler/openeuler:24.03-lts-sp2
ENV TZ Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
echo $TZ > /etc/timezone
+# 替换OpenEuler镜像源为华为云,加速依赖安装
RUN sed -i 's|repo.openeuler.org|repo.huaweicloud.com/openeuler|g' /etc/yum.repos.d/openEuler.repo && \
sed -i '/metalink/d' /etc/yum.repos.d/openEuler.repo && \
sed -i '/metadata_expire/d' /etc/yum.repos.d/openEuler.repo && \
@@ -22,6 +35,7 @@ RUN sed -i 's|repo.openeuler.org|repo.huaweicloud.com/openeuler|g' /etc/yum.repo
yum install -y nginx shadow-utils passwd gettext && \
yum clean all
+# 从构建阶段复制产物到nginx
COPY --from=0 /opt/dist /usr/share/nginx/html
COPY --from=0 /opt/public /usr/share/nginx/html
COPY --from=0 /opt/deploy/nginx.conf.tmpl /opt/nginx.conf.tmpl
@@ -29,5 +43,5 @@ COPY --from=0 /opt/deploy/start.sh /opt/start.sh
EXPOSE 8080
WORKDIR /opt
-
ENTRYPOINT [ "bash", "./start.sh" ]
+
diff --git a/build/linux/euler-copilot-web.spec b/build/linux/euler-copilot-web.spec
index 30f83bd6..0859c55c 100644
--- a/build/linux/euler-copilot-web.spec
+++ b/build/linux/euler-copilot-web.spec
@@ -15,8 +15,8 @@
BuildArch: aarch64 x86_64
Name: euler-copilot-web
-Version: 0.9.6
-Release: 6%{?dist}
+Version: 0.10.0
+Release: 1%{?dist}
License: MulanPSL-2.0
Summary: openEuler 智能化解决方案 Web 前端
Source0: %{name}-%{version}.tar.gz
@@ -315,6 +315,9 @@ fi
%changelog
+* Mon Sep 15 2025 openEuler - 0.10.0-1
+- 升级至 0.10.0 版本
+
* Mon Jun 16 2025 openEuler - 0.9.6-6
- 优化 RPM 打包配置:启用自动 provide 并过滤 Electron 内部库
@@ -331,4 +334,4 @@ fi
- 增加安装后提示信息
* Thu Apr 17 2025 openEuler - 0.9.6-1
-- Initial release
+- Initial release
\ No newline at end of file
diff --git a/build/linux/nginx.conf.local.tmpl b/build/linux/nginx.conf.local.tmpl
index b10a8d2c..9a5f99db 100644
--- a/build/linux/nginx.conf.local.tmpl
+++ b/build/linux/nginx.conf.local.tmpl
@@ -6,12 +6,16 @@ server {
client_body_buffer_size 5120M;
client_max_body_size 5120M;
+ add_header 'Access-Control-Allow-Origin' '*'; # 允许所有源
+ add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE'; # 允许的HTTP方法
+ add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization'; # 允许的请求头
+ add_header 'Access-Control-Expose-Headers' 'Content-Length, Content-Range'; # 允许前端访问的响应头
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options nosniff;
add_header Referrer-Policy "no-referrer";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; always";
add_header Cache-Control "no-cache";
- add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: base64;";
+ add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src * data: base64;";
resolver 8.8.8.8 8.8.4.4 valid=60s;
resolver_timeout 5s;
@@ -140,4 +144,4 @@ server {
expires 30d;
add_header Cache-Control public;
}
-}
+}
\ No newline at end of file
diff --git a/deploy/nginx.conf.tmpl b/deploy/nginx.conf.tmpl
index c2ef1a64..6ec3bd94 100644
--- a/deploy/nginx.conf.tmpl
+++ b/deploy/nginx.conf.tmpl
@@ -63,12 +63,17 @@ http {
server_name localhost;
charset utf-8;
+ add_header 'Access-Control-Allow-Origin' '*'; # 允许所有源
+ add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE'; # 允许的HTTP方法
+ add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization'; # 允许的请求头
+ add_header 'Access-Control-Expose-Headers' 'Content-Length, Content-Range'; # 允许前端访问的响应头
+
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options nosniff;
add_header Referrer-Policy "no-referrer";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; always";
add_header Cache-Control "no-cache";
- add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: base64;";
+ add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src * data: base64;";
limit_conn limitperip 50;
resolver 8.8.8.8 8.8.4.4 valid=60s;
@@ -117,6 +122,22 @@ http {
proxy_pass ${FRAMEWORK_URL}/api/;
}
+
+
+ location /wtd/ {
+ proxy_set_header X-Forwarded-For $http_x_real_ip;
+ add_header Cache-Control "no-cache,no-store,must-revalidate";
+ add_header X-Accel-Buffering no;
+ proxy_buffering off;
+ proxy_intercept_errors on;
+
+ error_page 404 /404.html;
+ limit_req zone=ratelimit burst=15 nodelay;
+ proxy_read_timeout 500s;
+ proxy_connect_timeout 500s;
+
+ proxy_pass ${FRAMEWORK_URL}/witchaind/;
+ }
location /witchaind/ {
proxy_set_header X-Forwarded-For $http_x_real_ip;
@@ -149,4 +170,4 @@ http {
internal;
}
}
-}
+}
\ No newline at end of file
diff --git a/electron/main/common/locale.ts b/electron/main/common/locale.ts
index a2d6daa9..6ec8b07e 100644
--- a/electron/main/common/locale.ts
+++ b/electron/main/common/locale.ts
@@ -30,7 +30,7 @@ export function processZhLocale(appLocale: string): string {
// country codes, assume they use Simplified Chinese.
// For other cases, assume they use Traditional.
if (['hans', 'cn', 'sg', 'my'].includes(region)) {
- return 'zh_cn';
+ return 'zh';
}
return 'zh_tw';
@@ -84,4 +84,4 @@ export async function resolveNlsConfiguration(
osLocale,
resolvedLanguage: osLocale,
};
-}
+}
\ No newline at end of file
diff --git a/electron/main/common/platform.ts b/electron/main/common/platform.ts
index 1cd6acc8..cbb9e61f 100644
--- a/electron/main/common/platform.ts
+++ b/electron/main/common/platform.ts
@@ -9,7 +9,7 @@
// See the Mulan PSL v2 for more details.
import * as nls from './nls';
-export const LANGUAGE_DEFAULT = 'zh_cn';
+export const LANGUAGE_DEFAULT = 'zh';
let _isWindows = false;
let _isMacintosh = false;
diff --git a/src/apis/appCenter/appCenterService.ts b/src/apis/appCenter/appCenterService.ts
index 025e7899..b5553932 100644
--- a/src/apis/appCenter/appCenterService.ts
+++ b/src/apis/appCenter/appCenterService.ts
@@ -108,6 +108,18 @@ export const getPartAppConfgUser = (): Promise<
return get('/api/user');
};
+/**
+ * 修改用户设置
+ *
+ * @param params
+ * @returns
+ */
+export const updateUserInfo = (params: {
+ autoExecute: boolean;
+}): Promise<[any, FcResponse | undefined]> => {
+ return post(`/api/user`, {autoExecute: params.autoExecute});
+};
+
export const appCenterApi = {
queryAppList,
createOrUpdateApp,
@@ -116,4 +128,5 @@ export const appCenterApi = {
releaseSingleAppData,
changeSingleAppCollect,
getPartAppConfgUser,
+ updateUserInfo,
};
diff --git a/src/apis/paths/account.ts b/src/apis/paths/account.ts
index 93411cdf..af452185 100644
--- a/src/apis/paths/account.ts
+++ b/src/apis/paths/account.ts
@@ -24,6 +24,7 @@ export const authorizeUser = (): Promise<
organization: string;
revision_number: string | null;
is_admin: boolean;
+ auto_execute?: boolean;
}>
| undefined
),
diff --git a/src/apis/paths/conversation.ts b/src/apis/paths/conversation.ts
index 1527ebb8..5e2ed858 100644
--- a/src/apis/paths/conversation.ts
+++ b/src/apis/paths/conversation.ts
@@ -11,16 +11,20 @@ import { get, put, post, del } from 'src/apis/server';
import type { FcResponse } from 'src/apis/server';
import { ConversationRecordList, ConversationList } from './type';
+import i18n from 'src/i18n';
+
const BASE_URL = '/api/conversation';
+const { t } = i18n.global;
/**
* 停止生成
* @returns
*/
-export const stopGeneration = (): Promise<
+export const stopGeneration = (taskId: string): Promise<
[any, FcResponse
下载地址:${excelPath.value}`;
}
-
- // 🔑 只有在还没完成时才设置完成状态
- if (!conversationItem.isFinish) {
- conversationItem.isFinish = true;
- isAnswerGenerating.value = false;
-
- // 如果是工作流的调试功能-调试对话结束时-发送调试对话结束
- if (isFlowDebug) {
- $bus.emit('debugChatEnd');
- }
+ conversationItem.isFinish = true;
+ isAnswerGenerating.value = false;
+ // 如果是工作流的调试功能-调试对话结束时-发送调试对话结束
+ if (isFlowDebug) {
+ $bus.emit('debugChatEnd');
+ }
+ },
+ waitingForStart: (
+ conversationItem: RobotConversationItem,
+ message: Record,
+ ) => {
+ const flow = (message.flow || {}) as Record;
+ const content = (message.content || {}) as Record;
+ conversationItem.flowdata = {
+ id: flow.stepId,
+ title: flow.stepName,
+ status: flow.stepStatus,
+ taskId: currentTaskId,
+ data: {
+ exData: content,
+ },
+ };
+ if (conversationItem.flowdata) {
+ conversationItem.flowdata.progress = flow.stepProgress;
+ conversationItem.flowdata.status = flow.stepStatus;
+ }
+ },
+ waitingForParam: (
+ conversationItem: RobotConversationItem,
+ message: Record,
+ ) => {
+ const flow = (message.flow || {}) as Record;
+ const content = (message.content || {}) as Record;
+ conversationItem.flowdata = {
+ id: flow.stepId,
+ title: flow.stepName,
+ status: flow.stepStatus,
+ taskId: currentTaskId,
+ data: {
+ exParam: content,
+ },
+ };
+ if (conversationItem.flowdata) {
+ conversationItem.flowdata.progress = flow.stepProgress;
+ conversationItem.flowdata.status = flow.stepStatus;
}
},
+ flowCancel: (
+ conversationItem: RobotConversationItem,
+ message: Record,
+ ) => {
+ const content = (message.content || {}) as Record;
+ const contentFlow = (content.flow || {}) as Record;
+ const messageFlow = (message.flow || {}) as Record;
+
+ // 取消运行
+ conversationItem.flowdata = {
+ id: contentFlow.stepId,
+ title: i18n.global.t('flow.flow_cancel'),
+ progress: contentFlow.stepProgress,
+ status: messageFlow.stepStatus,
+ display: true,
+ data: conversationItem?.flowdata?.data,
+ };
+ },
+ flowSuccess: (
+ conversationItem: RobotConversationItem,
+ message: Record,
+ isFlowDebug: boolean,
+ ) => {
+ const content = (message.content || {}) as Record;
+ const contentFlow = (content.flow || {}) as Record;
+ const messageFlow = (message.flow || {}) as Record;
+ conversationItem.flowdata = {
+ id: contentFlow.stepId,
+ title: i18n.global.t('flow.flow_end'),
+ progress: contentFlow.stepProgress,
+ status: 'success',
+ display: true,
+ data: conversationItem?.flowdata?.data,
+ };
+ },
};
// chat message回调
- const handleMsgDataShow = async (
+ const handleMsgDataShow = (
params: Record,
msgData: Record,
conversationItem: RobotConversationItem,
@@ -358,87 +299,27 @@ export const useSessionStore = defineStore('conversation', () => {
return;
}
const rawMsgData = msgData.data as string;
-
if (rawMsgData === '[DONE]') {
dataTransfers.dataDone(conversationItem, !!params.type);
return;
}
-
-
-
- // 🔑 重要修复:处理带详细信息的ERROR消息
- if (rawMsgData.startsWith('[ERROR]')) {
- console.error('❌ 收到ERROR事件,停止对话生成:', rawMsgData);
- conversationItem.isFinish = true;
- isAnswerGenerating.value = false;
-
- // 🔑 重要:按正确顺序停止对话
- // 1. 首先中断前端fetchEventSource连接
- controller.abort();
-
- // 2. 然后调用后端停止接口,清理后端WebSocket连接
- try {
- const resp = await api.stopGeneration();
- if (resp?.[1]?.code === 200) {
- // 后端停止成功
- }
- } catch (stopError) {
- console.error('调用停止接口失败:', stopError);
- // 即使停止接口失败,也继续处理错误显示
- }
-
- // 提取错误信息
- const errorMessage = rawMsgData.replace('[ERROR]', '').trim();
-
- // 🔑 修复:确保错误信息正确显示在对话内容中
- // 初始化message数组和currentInd,如果不存在的话
- if (!conversationItem.message || conversationItem.message.length === 0) {
- conversationItem.message = [''];
- conversationItem.currentInd = 0;
- }
-
- const currentIndex = conversationItem.currentInd || 0;
-
- // 确保currentIndex对应的message元素存在
- if (!conversationItem.message[currentIndex]) {
- conversationItem.message[currentIndex] = '';
- }
-
- // 设置错误信息到对话内容中
- conversationItem.message[currentIndex] = errorMessage || '系统错误,请稍后再试';
-
- // 🔑 重要:显示错误提示给用户
- errorMsg(errorMessage || '系统错误,请稍后再试');
+ if (rawMsgData === '[ERROR]') {
+ dataTransfers.dataDone(conversationItem, !!params.type);
return;
}
// 同一时间戳传来的decodeValue是含有三条信息的合并,so需要分割
- // 这里json解析,添加错误处理
- let message: any;
- try {
- message = JSON.parse(rawMsgData || '{}');
- } catch (parseError) {
- console.error('📨 JSON解析失败:', {
- rawData: rawMsgData,
- error: parseError,
- length: rawMsgData?.length
- });
- // 如果解析失败,尝试处理为文本消息
- if (rawMsgData && rawMsgData.trim()) {
- dataTransfers.textAdd(conversationItem, {
- event: 'text.add',
- content: { text: rawMsgData }
- });
- }
- return;
- }
+ // 这里json解析
+ const message = JSON.parse(rawMsgData || '{}');
const eventType = message['event'];
if ('metadata' in message) {
conversationItem.metadata = message.metadata;
}
+ currentTaskId.value = message.taskId;
if ('event' in message) {
switch (eventType) {
case 'text.add':
+ currentMessage.value = message;
dataTransfers.textAdd(conversationItem, message);
break;
case 'heartbeat':
@@ -448,7 +329,7 @@ export const useSessionStore = defineStore('conversation', () => {
break;
case 'document.add':
// 遇到文档添加事件,先省略
- // dataTransfers.documentAdd(conversationItem, message);
+ dataTransfers.documentAdd(conversationItem, message);
break;
case 'Suggestion':
dataTransfers.suggestionFunc(conversationItem, message);
@@ -456,7 +337,7 @@ export const useSessionStore = defineStore('conversation', () => {
case 'init':
//初始化获取 metadata
conversationItem.metadata = message.metadata;
- conversationItem.createdAt = message.content.created_at;
+ conversationItem.createdAt = message.content.createdAt;
conversationItem.groupId = message.groupId;
break;
case 'flow.start':
@@ -469,17 +350,25 @@ export const useSessionStore = defineStore('conversation', () => {
case 'step.output':
dataTransfers.stepOutput(conversationItem, message);
break;
+ case 'step.waiting_for_start':
+ // 事件流等待开始
+ dataTransfers.waitingForStart(conversationItem, message);
+ break;
+ case 'step.waiting_for_param':
+ // 事件流等待参数
+ dataTransfers.waitingForParam(conversationItem, message);
+ break;
+ case 'flow.cancel':
+ // 事件流取消
+ dataTransfers.flowCancel(conversationItem, message);
+ break;
case 'flow.stop':
//时间流结束
dataTransfers.flowStop(conversationItem, message, !!params.type);
break;
- case 'loop.progress':
- //循环进度更新
- dataTransfers.loopProgress(conversationItem, message);
- break;
- case 'loop.completed':
- //循环完成
- dataTransfers.loopCompleted(conversationItem, message, !!params.type);
+ case 'flow.success':
+ //时间流结束
+ dataTransfers.flowSuccess(conversationItem, message, !!params.type);
break;
default:
break;
@@ -512,7 +401,7 @@ export const useSessionStore = defineStore('conversation', () => {
conversationId: params.conversationId,
features: features,
groupId: params.groupId,
- language,
+ language: langStore.language,
question: params.question,
// record_id: params.qaRecordId,
}),
@@ -531,6 +420,7 @@ export const useSessionStore = defineStore('conversation', () => {
},
conversationId: params.conversationId,
debug: true,
+ language: langStore.language,
question: params.question,
}),
openWhenHidden: true,
@@ -541,6 +431,7 @@ export const useSessionStore = defineStore('conversation', () => {
params: Record,
innerParams: Record,
fetchParams: Record,
+ isDebug: boolean,
) => {
await fetchEventSource(url, {
...fetchParams,
@@ -551,9 +442,10 @@ export const useSessionStore = defineStore('conversation', () => {
flowId: '',
params: innerParams || {},
},
+ ...(isDebug && { debug: isDebug }),
conversationId: params.conversationId,
features: features,
- language,
+ language: langStore.language,
groupId: params.groupId,
question: params.question,
record_id: params.qaRecordId,
@@ -579,13 +471,25 @@ export const useSessionStore = defineStore('conversation', () => {
conversationId: params.conversationId,
features: features,
groupId: params.groupId,
- language,
+ language: langStore.language,
question: params.question,
record_id: params.qaRecordId,
}),
openWhenHidden: true,
});
},
+ fetchWait: async (
+ url: string,
+ params: Record,
+ innerParams: Record,
+ fetchParams: Record,
+ ) => {
+ await fetchEventSource(url, {
+ ...fetchParams,
+ body: JSON.stringify({ taskId: currentTaskId.value, params: params }),
+ openWhenHidden: true,
+ });
+ },
};
const judgeResp = async (resp) => {
@@ -617,6 +521,8 @@ export const useSessionStore = defineStore('conversation', () => {
type?: any;
},
ind?: number,
+ waitType?: string,
+ isDebug?: boolean,
): Promise => {
const { currentSelectedSession } = useHistorySessionStore();
params.conversationId = currentSelectedSession;
@@ -632,15 +538,7 @@ export const useSessionStore = defineStore('conversation', () => {
if (params.params && typeof params.params === 'object') {
pp = params.params;
} else if (params.params && typeof params.params === 'string') {
- try {
- pp = Object(JSON.parse(params.params));
- } catch (parseError) {
- console.error('📨 参数解析失败:', {
- params: params.params,
- error: parseError
- });
- pp = {}; // 使用空对象作为默认值
- }
+ pp = Object(JSON.parse(params.params));
}
isPaused.value = false;
excelPath.value = '';
@@ -667,18 +565,23 @@ export const useSessionStore = defineStore('conversation', () => {
resp = response;
},
onmessage: async (ev) => {
- await handleMsgDataShow(params, ev, conversationItem);
+ handleMsgDataShow(params, ev, conversationItem);
},
};
-
- if (params.user_selected_flow) {
+ if(isDebug){
+ await funcFetch.fetchAppNew(streamUrl, params, pp, fetchParams, isDebug);
+ } else if (params.user_selected_flow) {
// 之前的对话历史记录
await funcFetch.fetchHistory(streamUrl, params, pp, fetchParams);
} else if (params.user_selected_app) {
// 新的工作流调试记录
await funcFetch.fetchAppNew(streamUrl, params, pp, fetchParams);
- // } else if (false) {
- // //写传参数情况
+ } else if (waitType) {
+ if (waitType === 'params') {
+ await funcFetch.fetchWait(streamUrl, params, pp, fetchParams);
+ } else {
+ await funcFetch.fetchWait(streamUrl, params.params, pp, fetchParams);
+ }
} else {
await funcFetch.fetchDefault(streamUrl, params, pp, fetchParams);
}
@@ -728,6 +631,8 @@ export const useSessionStore = defineStore('conversation', () => {
* @param user_selected_flow
* @param params
* @param type
+ * @param waitType
+ * @param isDebug
*/
const sendQuestion = async (
groupId: string | undefined,
@@ -738,6 +643,8 @@ export const useSessionStore = defineStore('conversation', () => {
user_selected_flow?: string,
params?: any,
type?: any,
+ waitType?: string,
+ isDebug?: boolean,
): Promise => {
const { updateSessionTitle, currentSelectedSession } =
useHistorySessionStore();
@@ -761,7 +668,7 @@ export const useSessionStore = defineStore('conversation', () => {
comment: 'none',
});
targetItem.currentInd = targetItem.message.length - 1; //123
- } else {
+ } else if (!waitType) {
// 初次生成 ,创建一个问题和一个回答
const ind = conversationList.value.length - 1;
const messageList = new MessageArray();
@@ -810,7 +717,10 @@ export const useSessionStore = defineStore('conversation', () => {
params: params || undefined,
};
}
- await getStream(getStreamParams, regenerateInd ?? undefined);
+ if (waitType) {
+ getStreamParams = params;
+ }
+ await getStream(getStreamParams, regenerateInd ?? undefined, waitType, isDebug);
};
/**
@@ -829,7 +739,7 @@ export const useSessionStore = defineStore('conversation', () => {
targetItem.message[0] += '暂停生成';
targetItem.isFinish = true;
cancel();
- const resp = await api.stopGeneration();
+ const resp = await api.stopGeneration(currentMessage.value.taskId);
if (resp?.[1]?.code === 200) {
isAnswerGenerating.value = false;
}
@@ -899,6 +809,21 @@ export const useSessionStore = defineStore('conversation', () => {
};
// #endregion
+ /**
+ * 处理历史对话数据中尾注位置
+ */
+ const handleMessage = (record: any): string => {
+ let message = record.content.answer;
+ record.metadata.footNoteMetadataList?.reverse().forEach((footNoteMetadata: any) => {
+ const insertFile = record.document?.filter((file: any) => file._id === footNoteMetadata.releatedId);
+ const insertNumber = insertFile[0]?.order;
+ if (!insertNumber) return;
+ const pos = footNoteMetadata.insertPosition;
+ message = message.slice(0, pos) + `[[${insertNumber}]]` + message.slice(pos)
+ });
+ return message;
+ }
+
/**
* 获取历史对话数据
* @param conversationId
@@ -936,12 +861,12 @@ export const useSessionStore = defineStore('conversation', () => {
cid: conversationList.value.length + 1,
belong: 'user',
message: record.content.question,
- createdAt: record.created_at,
+ createdAt: record.createdAt,
},
{
cid: conversationList.value.length + 2,
belong: 'robot',
- message: [record.content.answer],
+ message: [handleMessage(record)],
messageList,
currentInd: 0,
isAgainst: false,
@@ -951,6 +876,7 @@ export const useSessionStore = defineStore('conversation', () => {
conversationId: record.conversationId,
groupId: record.groupId,
metadata: record.metadata,
+ document: record.document,
flowdata: record?.flow
? (generateFlowData(record.flow) as FlowType)
: undefined,
@@ -965,22 +891,31 @@ export const useSessionStore = defineStore('conversation', () => {
const generateFlowData = (record: any): FlowDataType => {
const flowData = {
id: record.recordId,
- title: record.id,
- status: 'success',
+ title: record.flowName,
+ status: record.flowStatus,
display: true,
flowId: record.flowId,
data: [[]] as any[],
};
+ // 看有没有取消的
+ let isCancelled = false;
for (let i = 0; i < record.steps.length; i++) {
flowData.data[0].push({
id: record.steps[i].stepId,
- title: record.steps[i].stepId,
+ title: record.steps[i].stepName,
status: record.steps[i].stepStatus,
data: {
input: record.steps[i].input,
output: record.steps[i].output,
+ ...(record.steps[i].exData && { exData: record.steps[i].exData }),
},
});
+ if (record.steps[i].stepStatus === 'cancelled') {
+ isCancelled = true;
+ }
+ }
+ if (isCancelled) {
+ flowData.status = 'cancelled';
}
return flowData;
};
@@ -990,18 +925,13 @@ export const useSessionStore = defineStore('conversation', () => {
*/
const stopDebug = async (): Promise => {
isPaused.value = true;
-
- // 安全检查:确保 conversationList 不为空
- if (conversationList.value.length > 0) {
- (
- conversationList.value[
- conversationList.value.length - 1
- ] as RobotConversationItem
- ).isFinish = true;
- }
-
+ (
+ conversationList.value[
+ conversationList.value.length - 1
+ ] as RobotConversationItem
+ ).isFinish = true;
cancel();
- const resp = await api.stopGeneration();
+ const resp = await api.stopGeneration(currentMessage.value.taskId);
if (resp?.[1]?.code === 200) {
isAnswerGenerating.value = false;
}
@@ -1018,6 +948,7 @@ export const useSessionStore = defineStore('conversation', () => {
dialogueRef,
app,
appList,
+ currentMessage,
sendQuestion,
pausedStream,
stopDebug,
@@ -1027,4 +958,4 @@ export const useSessionStore = defineStore('conversation', () => {
getConversation,
cancel,
};
-});
+});
\ No newline at end of file
diff --git a/src/store/historySession.ts b/src/store/historySession.ts
index 9b702d5e..eb9638ae 100644
--- a/src/store/historySession.ts
+++ b/src/store/historySession.ts
@@ -216,8 +216,9 @@ export const useHistorySessionStore = defineStore(
/**
* 创建一个新的会话
*/
- const generateSession = async (): Promise => {
- const [_, res] = await api.createSession(user_selected_app.value);
+ const generateSession = async (isDebug): Promise => {
+ const appId = user_selected_app.value ?? '';
+ const [_, res] = await api.createSession({appId, debug: isDebug});
if (!_ && res) {
currentSelectedSession.value = res.result.conversationId;
await getHistorySession();
diff --git a/src/store/lang.ts b/src/store/lang.ts
index 4c5c359b..bdfec2e9 100644
--- a/src/store/lang.ts
+++ b/src/store/lang.ts
@@ -9,7 +9,7 @@ export const useLangStore = defineStore(
const i18n = useI18n();
const language = ref();
- const changeLanguage = (lang: 'zh_cn' | 'en') => {
+ const changeLanguage = (lang: 'zh' | 'en') => {
language.value = lang;
i18n.locale.value = language.value;
if (ipcRenderer) {
@@ -26,7 +26,7 @@ export const useLangStore = defineStore(
electronProcess.env['EULERCOPILOT_NLS_CONFIG'] &&
changeLanguage(nlsConfig.userLocale);
} else {
- !language.value && changeLanguage('zh_cn');
+ !language.value && changeLanguage('zh');
}
});
return {
diff --git a/src/views/api/components/ActiveModel.vue b/src/views/api/components/ActiveModel.vue
new file mode 100644
index 00000000..835e22ce
--- /dev/null
+++ b/src/views/api/components/ActiveModel.vue
@@ -0,0 +1,167 @@
+
+
+
+
+
+
+ {{ props.item.description }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/api/components/McpDrawer.vue b/src/views/api/components/McpDrawer.vue
index a44eff4a..e421cd9e 100644
--- a/src/views/api/components/McpDrawer.vue
+++ b/src/views/api/components/McpDrawer.vue
@@ -32,25 +32,20 @@ const COMMAND_TEMPLATE = {
command: '',
args: [],
env: {},
- autoApprove: [],
- autoInstall: true,
- disabled: false,
};
const URL_TEMPLATE = {
+ headers: {},
url: '',
- env: {},
- autoApprove: [],
- autoInstall: true,
- disabled: false,
};
+const STREAM = {};
const loading = ref(false);
-const mcpConfigTemplate = {
+const mcpConfigTemplate = ref({
stdio: COMMAND_TEMPLATE,
sse: URL_TEMPLATE,
- stream: URL_TEMPLATE,
-};
+ stream: STREAM,
+});
const form = reactive({
icon: '',
@@ -149,7 +144,7 @@ async function onConfirm(formEl: FormInstance | undefined) {
icon: form.icon,
name: form.name,
description: form.description,
- config: form.mcpConfig,
+ config: JSON.parse(form.mcpConfig),
mcpType: form.type,
});
@@ -178,7 +173,6 @@ async function onConfirm(formEl: FormInstance | undefined) {
jsonEditorRef.value.setJsonValue('{\n \n}');
emits('success');
loading.value = false;
-
} catch (error) {
console.error('Create or update MCP service failed:', error);
ElMessage({
@@ -200,13 +194,23 @@ async function getMcpServiceDetail(serviceId: string) {
form.description = description;
form.type = mcpType;
form.mcpConfig = data;
- jsonEditorRef.value.setJsonValue(form.mcpConfig);
+ let json = {};
+ if (mcpType === 'stdio') {
+ json.command = data.command;
+ json.args = data.args;
+ json.env = data.env;
+ } else if (mcpType === 'sse') {
+ json.headers = data.headers;
+ json.url = data.url;
+ }
+ jsonEditorRef.value.setJsonValue(JSON.stringify(json, null, 2));
+ mcpConfigTemplate.value[mcpType] = json;
}
}
async function setMcpConfig(type: string) {
jsonEditorRef.value.setJsonValue(
- JSON.stringify(mcpConfigTemplate[type], null, 2),
+ JSON.stringify(mcpConfigTemplate.value[type], null, 2),
);
}
@@ -222,6 +226,12 @@ watch(
}
getMcpServiceDetail(props.serviceId);
} else {
+ // 初始化
+ mcpConfigTemplate.value = {
+ stdio: COMMAND_TEMPLATE,
+ sse: URL_TEMPLATE,
+ stream: STREAM,
+ };
if (formRef.value) formRef.value.resetFields();
setMcpConfig(form.type);
}
@@ -240,7 +250,7 @@ watch(
:model-value="visible"
@close="emits('update:visible', false)"
>
-
+
();
display: flex;
flex-direction: column;
gap: 4px;
+ width: 70%;
&__top {
min-height: 24px;
@@ -66,7 +67,7 @@ const props = defineProps();
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
- width: 80%;
+ width: 70%;
font-weight: 700;
}
}
diff --git a/src/views/api/index.vue b/src/views/api/index.vue
index a566f503..c313e5ba 100644
--- a/src/views/api/index.vue
+++ b/src/views/api/index.vue
@@ -103,6 +103,30 @@
:lazy="true"
>
+ handleSearchMcpList(tab.props.name)"
+ >
+
+
+
+
+
-
+
+
{{ t('plugin_center.mcp.install_failed') }}
+
+
+

+
+ {{ t('plugin_center.mcp.install_success') }}
+
+
+
+
+

+
+ {{ t('plugin_center.mcp.not_installed') }}
+
+
@@ -156,7 +205,7 @@
class="apiCenterCardId"
v-if="pluginType === 'mcp'"
>
- ID:
+ ID:
{{ item.serviceId }}
+
+ {{ t('plugin_center.mcp.install') }}
+
+
+
{{
item.isActive
@@ -187,29 +258,38 @@
: t('plugin_center.mcp.activate')
}}
-
+
-
- {{ $t('semantic.interface_edit') }}
-
-
- {{ $t('semantic.interface_delete') }}
-
-
+ {{ $t('semantic.interface_edit') }}
+
+
+
+ {{ $t('semantic.cancel') }}
+
+
+
+ {{ $t('semantic.interface_delete') }}
+
@@ -283,14 +363,15 @@
@change="handleChangePage"
/>
+
@@ -106,7 +157,7 @@ onMounted(() => {
:model-value="visible"
@close="emits('update:visible', false)"
>
-
+
{
clearable
>
-
+
handleSearchMcpList(tab.props.name)"
+ >
+
+
+
+
-
+
{{ item.name }}
{{ item.description }}
+
+ {{
+ item.isActive
+ ? t('plugin_center.mcp.deactivate')
+ : t('plugin_center.mcp.activate')
+ }}
+
@@ -148,6 +234,12 @@ onMounted(() => {
+
+
\ No newline at end of file
diff --git a/src/views/createapp/components/types.ts b/src/views/createapp/components/types.ts
index ce88543b..9a4bd2b4 100644
--- a/src/views/createapp/components/types.ts
+++ b/src/views/createapp/components/types.ts
@@ -7,6 +7,8 @@
// IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
// PURPOSE.
// See the Mulan PSL v2 for more details.
+import i18n from 'src/i18n';
+
import type {
UserDialoguePanelType,
RobotDialoguePanelType,
@@ -93,40 +95,39 @@ export const nodeTypeToIcon = {
// 这里是对应的图标
export const iconTypeList = [
- { name: 'HTTP请求', value: 'API', icon: API, class: 'otherNode' },
- { name: 'MCP', value: 'MCP', icon: API, class: 'otherNode' },
- { name: 'SQL查询', value: 'SQL', icon: API, class: 'otherNode' },
- { name: '图表', value: 'Graph', icon: API, class: 'otherNode' },
- { name: '代码执行', value: 'Code', icon: CODE, class: 'otherNode' },
- { name: '大模型', value: 'LLM', icon: LLM, class: 'systemNode' },
- { name: '知识库', value: 'RAG', icon: KENOWLEDGE_BASE, class: 'systemNode' },
+ { name: i18n.global.t('opertion.api'), value: 'API', icon: API, class: 'otherNode' },
+ { name: i18n.global.t('opertion.mcp'), value: 'MCP', icon: API, class: 'otherNode' },
+ { name: i18n.global.t('opertion.sql'), value: 'SQL', icon: API, class: 'otherNode' },
+ { name: i18n.global.t('opertion.gcraph'), value: 'Graph', icon: API, class: 'otherNode' },
+ { name: i18n.global.t('opertion.llm'), value: 'LLM', icon: LLM, class: 'systemNode' },
+ { name: i18n.global.t('opertion.rag'), value: 'RAG', icon: KENOWLEDGE_BASE, class: 'systemNode' },
{
- name: '问题推荐',
+ name: i18n.global.t('opertion.suggestion'),
value: 'Suggestion',
icon: get_CVE_DETAIL,
class: 'aposNode',
},
// 循环控制节点
{
- name: '跳过本轮',
+ name: i18n.global.t('opertion.skip_round'),
value: 'continue',
icon: REFRESH,
class: 'systemNode',
},
{
- name: '退出循环',
+ name: i18n.global.t('opertion.exit_loop'),
value: 'break',
icon: STOP_FILLED,
class: 'systemNode',
},
{
- name: '变量赋值',
+ name: i18n.global.t('opertion.variable_assign'),
value: 'VariableAssign',
icon: CODE, // 暂时使用CODE图标,与菜单保持一致
class: 'systemNode',
},
{
- name: '文件提取器',
+ name: i18n.global.t('opertion.file_extract'),
value: 'FileExtract',
icon: CODE,
class: 'systemNode',
@@ -187,3 +188,50 @@ export interface ListItem {
id: string;
value: string | null;
}
+
+const opertionList = [
+ // Number operations
+ {value: 'number_equal', label: i18n.global.t('opertion.equal'), str: '='},
+ {value: 'number_not_equal', label: i18n.global.t('opertion.not_equal'), str: '≠'},
+ {value: 'number_greater_than', label: i18n.global.t('opertion.greater_than'), str: '>'},
+ {value: 'number_less_than', label: i18n.global.t('opertion.less_than'), str: '<'},
+ {value: 'number_greater_than_or_equal', label: i18n.global.t('opertion.greater_than_or_equal'), str: '≥'},
+ {value: 'number_less_than_or_equal', label: i18n.global.t('opertion.less_than_or_equal'), str: '≤'},
+
+ // String operations
+ {value: 'string_equal', label: i18n.global.t('opertion.equal'), str: '='},
+ {value: 'string_not_equal', label: i18n.global.t('opertion.not_equal'), str: '≠'},
+ {value: 'string_contains', label: i18n.global.t('opertion.contains'), str: ''},
+ {value: 'string_not_contains', label: i18n.global.t('opertion.does_not_contain'), str: ''},
+ {value: 'string_starts_with', label: i18n.global.t('opertion.starts_with'), str: '='},
+ {value: 'string_ends_with', label: i18n.global.t('opertion.ends_with'), str: '='},
+ {value: 'string_length_equal', label: i18n.global.t('opertion.length_equal'), str: '|...|='},
+ {value: 'string_length_greater_than', label: i18n.global.t('opertion.length_greater_than'), str: '|...|>'},
+ {value: 'string_length_greater_than_or_equal', label: i18n.global.t('opertion.length_greater_than_or_equal'), str: '|...|≥'},
+ {value: 'string_length_less_than', label: i18n.global.t('opertion.length_less_than'), str: '|...|<'},
+ {value: 'string_length_less_than_or_equal', label: i18n.global.t('opertion.length_less_than_or_equal'), str: '|...|≤'},
+ {value: 'string_regex_match', label: i18n.global.t('opertion.regex_match'), str: '\\+'},
+
+ // List operations
+ {value: 'list_equal', label: i18n.global.t('opertion.equal'), str: '='},
+ {value: 'list_not_equal', label: i18n.global.t('opertion.not_equal'), str: '≠'},
+ {value: 'list_contains', label: i18n.global.t('opertion.contains'), str: ''},
+ {value: 'list_not_contains', label: i18n.global.t('opertion.does_not_contain'), str: ''},
+ {value: 'list_length_equal', label: i18n.global.t('opertion.length_equal'), str: '|...|='},
+ {value: 'list_length_greater_than', label: i18n.global.t('opertion.length_greater_than'), str: '|...|>'},
+ {value: 'list_length_greater_than_or_equal', label: i18n.global.t('opertion.length_greater_than_or_equal'), str: '|...|≥'},
+ {value: 'list_length_less_than', label: i18n.global.t('opertion.length_less_than'), str: '|...|<'},
+ {value: 'list_length_less_than_or_equal', label: i18n.global.t('opertion.length_less_than_or_equal'), str: '|...|≤'},
+
+ // Boolean operations
+ {value: 'bool_equal', label: i18n.global.t('opertion.equal'), str: '='},
+ {value: 'bool_not_equal', label: i18n.global.t('opertion.not_equal'), str: '≠'},
+
+ // Dictionary operations
+ {value: 'dict_equal', label: i18n.global.t('opertion.equal'), str: '='},
+ {value: 'dict_not_equal', label: i18n.global.t('opertion.not_equal'), str: '≠'},
+ {value: 'dict_contains_key', label: i18n.global.t('opertion.contains_key'), str: ''},
+ {value: 'dict_not_contains_key', label: i18n.global.t('opertion.does_not_contain_key'), str: ''}
+]
+
+ export const opertionListMap = new Map(opertionList.map(item => [item.value, item]));
diff --git a/src/views/createapp/components/workFlow.vue b/src/views/createapp/components/workFlow.vue
index 8e0a0475..7e6af886 100644
--- a/src/views/createapp/components/workFlow.vue
+++ b/src/views/createapp/components/workFlow.vue
@@ -6,7 +6,6 @@ import { ElMessage } from 'element-plus';
import { VueFlow, useVueFlow } from '@vue-flow/core';
import { Background } from '@vue-flow/background';
import { MiniMap } from '@vue-flow/minimap';
-import BranchNode from './workFlowConfig/BranchNode.vue';
import ChoiceBranchNode from './workFlowConfig/ChoiceBranchNode.vue';
import VariableAssignNode from './workFlowConfig/VariableAssignNode.vue';
import LoopNode from './workFlowConfig/LoopNode.vue';
@@ -48,8 +47,11 @@ import CustomLoading from '../../customLoading/index.vue';
import EditFlowName from './workFlowConfig/editFlowName.vue';
import NodeListPanel from './workFlowConfig/NodeListPanel.vue';
import EnvironmentVariableDrawer from './workFlowConfig/EnvironmentVariableDrawer.vue';
+import { useLangStore } from '@/store';
const { t } = useI18n();
+const langStore = useLangStore();
+
const copilotAside = ref
();
const isCopilotAsideVisible = ref(false);
@@ -1085,6 +1087,7 @@ onMounted(() => {
.queryAllFlowService({
page: 1,
pageSize: 10,
+ language: langStore.language,
})
.then((res) => {
const services = res[1]?.result.services || [];
@@ -1161,6 +1164,7 @@ const nodesChange = (nodes) => {
removeSelectedNodes([getSelectedNodes.value[0]]);
}
if (nodes?.[0]?.type === 'remove') {
+ // TODO 为什么0.10.0删除了delNode?
delNode(nodes[0].id);
// 节点增加删除时直接将工作流debug状态置为false
emits('updateFlowsDebug', false);
@@ -2127,7 +2131,10 @@ const saveFlow = async (updateNodeParameter?, debug?) => {
if (response[1]?.result) {
queryFlow('update');
const updatedCurFlow = response[1].result.flow;
- isNodeConnect.value = response[1].result.connectivity;
+ isNodeConnect.value = updatedCurFlow.connectivity;
+ if (!isNodeConnect.value) {
+ ElMessage.error(i18n.global.t('semantic.check_connect'));
+ }
redrageFlow(updatedCurFlow?.nodes, updatedCurFlow?.edges);
}
@@ -2264,17 +2271,6 @@ defineExpose({
>
-
-
-
-
-
@@ -2450,7 +2446,9 @@ defineExpose({
-
{{ $t(`flow.${StatusInfoTitle[debugStatus]}`) }}
+
+ {{ $t(`flow.${StatusInfoTitle[debugStatus]}`) }}
+
-import { Position, Handle } from '@vue-flow/core';
-import { ref, onMounted, watch } from 'vue';
-import { BranchSourceIdType } from '../types';
-import NodeMirrorText from '../codeMirror/nodeMirrorText.vue';
-import { CopyDocument } from '@element-plus/icons-vue';
-import { ElMessage } from 'element-plus';
-import { IconSuccess } from '@computing/opendesign-icons';
-import { useI18n } from 'vue-i18n';
-const props = defineProps({
- id: {
- type: String,
- required: true,
- },
- data: {
- type: Object, // 目前定义的对象中只有label,desc属性是有的,后续可能会有展开的情形
- required: true,
- },
- type: {
- type: String,
- required: false,
- },
- position: {
- type: Object,
- required: false,
- },
- disabled: {
- type: Boolean,
- required: false,
- },
- selected: {
- type: Boolean,
- default: false,
- },
-});
-const emits = defineEmits(['delNode', 'editYamlDrawer']);
-
-const statusList = ref(['running', 'success', 'error']);
-
-const branchIdList = ref([]);
-
-// 当前节点状态-工作流调试结果-成功/失败/运行中
-const curStatus = ref('');
-
-// 当前节点运行耗时
-const costTime = ref('');
-
-// 定义传给mirror展示输入输出的存储量
-const inputAndOutput = ref({
- input_parameters: {},
- output_parameters: {},
-});
-
-// 处理节点点击事件
-const handleNodeClick = () => {
- if (!props.disabled) {
- editYaml(props.data.name, props.data.description, props.data.parameters);
- }
-};
-
-watch(
- () => props.data,
- () => {
- const isInclude = statusList.value.includes(props.data?.status);
- // 设置节点的状态-默认以及成功、失败、运行中
- if (!isInclude) {
- curStatus.value = 'default';
- } else {
- curStatus.value = props.data?.status;
- }
- // 节点调试消耗时间【目前只有调试接口返回的节点step.output才有值,其余状态为''不显示】
- costTime.value = props.data?.constTime || '';
- // 这里是分支节点独有的,需要根据接口拖拽节点里的choices决定有几个handle节点
- if (props.data?.parameters?.input_parameters?.choices) {
- branchIdList.value =
- props.data?.parameters?.input_parameters?.choices.map(
- (item) => item?.branchId,
- );
- }
- // 默认的输入赋值
- inputAndOutput.value.input_parameters =
- props.data?.parameters?.input_parameters || {};
- // 判断是否有调试的输入输出,有调试的输入输出,需要将其显示/否则显示默认的输出
- if (props.data.content?.type === 'input') {
- inputAndOutput.value.input_parameters = props.data.content.params;
- } else if (props.data.content?.type === 'output') {
- inputAndOutput.value.output_parameters = props.data.content.params;
- } else {
- inputAndOutput.value.input_parameters =
- props.data?.parameters?.input_parameters || {};
- inputAndOutput.value.output_parameters =
- props.data?.parameters?.output_parameters || {};
- }
- },
- { deep: true, immediate: true },
-);
-
-const delNode = (id) => {
- emits('delNode', id);
-};
-
-// 编辑yaml
-const editYaml = (nodeName, nodeDesc, yamlCode) => {
- emits('editYamlDrawer', nodeName, nodeDesc, yamlCode, props.id);
-};
-
-const { t } = useI18n();
-
-const handleCopyTextToclipboard = (text) => {
- const input = document.createElement('input');
- input.value = text;
- document.body.appendChild(input);
- input.select();
- document.execCommand('copy');
- ElMessage({
- showClose: true,
- message: t('feedback.copied_successfully'),
- icon: IconSuccess,
- customClass: 'o-message--success',
- duration: 2000,
- });
- document.body.removeChild(input);
-};
-
-
-
-
-
-
-
-
-
-
-
-
-
{{ props.data.name }}
-
-
- ···
-
- {{ $t('semantic.edit') }}
-
-
- {{ $t('semantic.interface_delete') }}
-
-
-
-
-
-
-
- {{ item.description }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/views/createapp/components/workFlowConfig/ChoiceBranchDrawer.vue b/src/views/createapp/components/workFlowConfig/ChoiceBranchDrawer.vue
index 26fa75dc..89b42d2f 100644
--- a/src/views/createapp/components/workFlowConfig/ChoiceBranchDrawer.vue
+++ b/src/views/createapp/components/workFlowConfig/ChoiceBranchDrawer.vue
@@ -595,7 +595,7 @@ const formatValue = (value, type) => {
@update:model-value="emit('update:visible', $event)"
title="配置条件分支"
direction="rtl"
- size="600px"
+ size="50%"
:before-close="handleClose"
class="choice-branch-drawer"
>
diff --git a/src/views/createapp/components/workFlowConfig/VariableAssignNodeDrawer.vue b/src/views/createapp/components/workFlowConfig/VariableAssignNodeDrawer.vue
index 74a98aed..b9296c73 100644
--- a/src/views/createapp/components/workFlowConfig/VariableAssignNodeDrawer.vue
+++ b/src/views/createapp/components/workFlowConfig/VariableAssignNodeDrawer.vue
@@ -202,7 +202,7 @@ const conversationId = computed(() => {
:model-value="visible"
@update:model-value="closeDrawer"
title="变量赋值节点配置"
- :size="600"
+ :size="800"
:before-close="closeDrawer"
>
diff --git a/src/views/createapp/components/workFlowConfig/workFlowDialog.vue b/src/views/createapp/components/workFlowConfig/workFlowDialog.vue
index c69cb3b0..52fe8e9c 100644
--- a/src/views/createapp/components/workFlowConfig/workFlowDialog.vue
+++ b/src/views/createapp/components/workFlowConfig/workFlowDialog.vue
@@ -132,7 +132,7 @@ const handleSubmit = (formEl: FormInstance | undefined) => {
apiId: 'startId',
nodeId: 'Empty',
serviceId: 'start',
- name: '开始',
+ name: i18n.global.t('main.start'),
callId: 'start',
description: 'startNode',
editable: false,
@@ -147,7 +147,7 @@ const handleSubmit = (formEl: FormInstance | undefined) => {
apiId: 'endId',
nodeId: 'Empty',
serviceId: 'end',
- name: '结束',
+ name: i18n.global.t('main.end'),
callId: 'end',
description: 'endNode',
editable: false,
diff --git a/src/views/createapp/components/workFlowConfig/yamlEditDrawer.vue b/src/views/createapp/components/workFlowConfig/yamlEditDrawer.vue
index 5360c68d..2a56ed57 100644
--- a/src/views/createapp/components/workFlowConfig/yamlEditDrawer.vue
+++ b/src/views/createapp/components/workFlowConfig/yamlEditDrawer.vue
@@ -158,9 +158,19 @@ const yamlExpress = ref([
},
]);
const yamlBaseInfoRule = ref({
- name: [{ required: true, message: '请输入工作流名称', trigger: 'blur' }],
+ name: [
+ {
+ required: true,
+ message: i18n.global.t('flow.enterWorkflowName'),
+ trigger: 'blur',
+ },
+ ],
description: [
- { required: true, message: '请输入工作流描述', trigger: 'blur' },
+ {
+ required: true,
+ message: i18n.global.t('flow.enterWorkflowDesc'),
+ trigger: 'blur',
+ },
],
});
const activeName = ref([
diff --git a/src/views/createapp/index.vue b/src/views/createapp/index.vue
index 987f71d3..45819b26 100644
--- a/src/views/createapp/index.vue
+++ b/src/views/createapp/index.vue
@@ -39,6 +39,10 @@ onMounted(() => {
if (currentAppType) {
createAppType.value = currentAppType;
}
+ // 如果是agent直接可以发布
+ if(appType.value === 'agent') {
+ publishValidate.value = true;
+ }
});
onUnmounted(() => {
@@ -142,6 +146,7 @@ const saveApp = async (type: 'agent' | 'flow') => {
appType: type,
icon: formData.icon,
name: formData.name,
+ llm: formData.model,
description: formData.description,
dialogRounds: formData.dialogRounds,
mcpService: formData.mcps,
@@ -171,6 +176,10 @@ const getPublishStatus = (status) => {
}
};
+const saveConfig = () => {
+ saveApp(appType.value as 'agent' | 'flow');
+};
+
const handleJumperAppCenter = () => {
router.push('/app?to=createdByMe');
};
@@ -256,6 +265,7 @@ function onDebugSuccess(status: boolean) {
v-else-if="appType === 'agent'"
:handleValidateContent="handleValidateContent"
:onDebug="onDebugSuccess"
+ :saveConfig="saveConfig"
/>
-import { computed, onMounted, ref, watch } from 'vue';
+import { computed, onMounted, ref, watch, nextTick } from 'vue';
import DialoguePanel from 'src/components/dialoguePanel/DialoguePanel.vue';
import UploadFileGroup from 'src/components/uploadFile/UploadFileGroup.vue';
import InitalPanel from 'src/views/dialogue/components/InitalPanel.vue';
@@ -14,6 +14,8 @@ import { UploadTypeName, UploadStatus } from 'src/components/uploadFile/type';
import CommonFooter from 'src/components/commonFooter/CommonFooter.vue';
import { api } from 'src/apis';
import { useHistorySessionStore } from 'src/store/historySession';
+import { ElMessage } from 'element-plus';
+import { useAccountStore } from 'src/store';
import { successMsg, errorMsg } from 'src/components/Message';
import i18n from 'src/i18n';
import DialogueVariablePanel from './DialogueVariablePanel.vue';
@@ -28,6 +30,9 @@ export interface DialogueSession {
createAppForm: any;
}
+const autoExecuteRef = ref(
false);
+const { userinfo } = storeToRefs(useAccountStore());
+
const props = withDefaults(defineProps(), {});
const Form = ref(props.createAppForm);
const AppForm = ref(props.createAppForm);
@@ -36,11 +41,21 @@ const { pausedStream } = useSessionStore();
const themeStore = useChangeThemeStore();
const isCreateApp = ref(props?.isCreateApp);
const selectedLLM = ref({});
+const curFileList = ref>([]);
const handleChangeMode = (val: string) => {
selectedLLM.value = val;
};
const llmOptions = ref([]);
const { app } = storeToRefs(useSessionStore());
+const showFileSource = ref(false);
+
+const closeShowFileSource = () => {
+ showFileSource.value = false;
+};
+const openShowFileSource = (fileList: Array) => {
+ showFileSource.value = true;
+ curFileList.value = fileList;
+};
// 对话输入内容
const dialogueInput = ref('');
@@ -55,8 +70,9 @@ const currentFlowId = ref('');
// 对话列表
const { sendQuestion } = useSessionStore();
-const { conversationList, isAnswerGenerating, dialogueRef } =
- storeToRefs(useSessionStore());
+const { conversationList, isAnswerGenerating, dialogueRef } = storeToRefs(
+ useSessionStore(),
+);
const { generateSession } = useHistorySessionStore();
const { currentSelectedSession } = storeToRefs(useHistorySessionStore());
@@ -291,7 +307,7 @@ const handleKeydown = (event: KeyboardEvent) => {
*
* @param item
*/
-const getItem = (item: ConversationItem, field: string): T | undefined => {
+const getItem = (item: ConversationItem, field: string): T | undefined => {
if (field in item) {
return (item as RobotConversationItem)[field] as T;
@@ -361,6 +377,7 @@ const isAllowToSend = computed(() => {
// 会话切换时
watch(currentSelectedSession, async (newVal) => {
if (!newVal) return;
+ closeShowFileSource();
const newExistList = existUploadMap.get(newVal);
const newFileView = uploadViewsMap.get(newVal);
let curPolling = pollingMap.get(newVal);
@@ -679,7 +696,12 @@ const getProviderLLM = async () => {
}
};
-// 🔑 移除全局收集器定义,改为使用per-QA的files字段
+const autoExecuteChange = async (value) => {
+ autoExecuteRef.value = value;
+ await nextTick();
+ Object.assign(userinfo.value, { auto_execute: value });
+ api.updateUserInfo({ autoExecute: value });
+};
onMounted(() => {
// 数据初始化
@@ -687,19 +709,28 @@ onMounted(() => {
if (!inputRef.value) return;
inputRef.value.focus();
getProviderLLM();
-
- // 🔑 移除全局收集器初始化,改为使用per-QA的files字段
-
+
// 🔑 重要修复:只在没有现有变量配置时才加载
// 避免重复加载导致覆盖用户已输入的变量状态
if (user_selected_app.value && conversationVariables.value.length === 0) {
loadConversationVariables();
} else if (user_selected_app.value && conversationVariables.value.length > 0) {
}
-
-
});
+watch(
+ [userinfo],
+ () => {
+ if (userinfo.value.auto_execute) {
+ autoExecuteRef.value = userinfo.value.auto_execute;
+ }
+ },
+ {
+ immediate: true,
+ deep: true,
+ },
+);
+
watch(selectLLM, (newValue) => {
if (newValue) {
selectedLLM.value.modalName = newValue.modelName;
@@ -757,7 +788,7 @@ const getappMode = (appId: string) => {
watch(
() => user_selected_app,
(val, oldVal) => {
- if (app.value) {
+ if (app.value.appId) {
user_selected_app.value = app.value.appId;
}
if (user_selected_app.value && !isCreateApp.value) {
@@ -824,6 +855,89 @@ watch(
deep: true,
},
);
+
+function downloadFun(url: string) {
+ const token = localStorage.getItem('ECSESSION');
+ if (!token) {
+ ElMessage.error(`Token is not available yet`);
+ return;
+ }
+ fetch(url, {
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
+ })
+ .then((response) => {
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+ // 提取 Content-Disposition 头部
+ const contentDisposition = response.headers.get('Content-Disposition');
+ let fileName = 'default-filename';
+ // 解析文件名(处理编码及格式)
+ if (contentDisposition) {
+ const fileNameMatch = contentDisposition.match(
+ /filename\*?=(?:UTF-8'')?"?([^";]+)"?/i,
+ );
+ if (fileNameMatch && fileNameMatch[1]) {
+ fileName = decodeURIComponent(fileNameMatch[1].replace(/"/g, ''));
+ }
+ }
+ return response.blob().then((blob) => ({ blob, fileName }));
+ })
+ .then(({ blob, fileName }) => {
+ const a = document.createElement('a');
+ a.href = URL.createObjectURL(blob);
+ a.download = fileName;
+ a.style.display = 'none';
+ a.click();
+ URL.revokeObjectURL(a.href);
+ })
+ .catch((error) => {
+ ElMessage.error(`下载失败: ${error}`);
+ });
+}
+const downLoadSourceFile = (file: any) => {
+ if (!file) return;
+ const url = `${window.origin}/witchaind/api/doc/download?docId=${file.documentId}`;
+ downloadFun(url);
+};
+
+const formatDate = (timestamp: number) => {
+ const date = new Date(timestamp * 1000); // 秒转毫秒
+ const year = date.getFullYear();
+ const month = String(date.getMonth() + 1).padStart(2, '0');
+ const day = String(date.getDate()).padStart(2, '0');
+ return `${year}-${month}-${day}`;
+};
+/**
+ * @description 处理并过滤文件列表,将文件列表中的字段名统一为指定格式
+ * @param {ConversationItem} ConversationItem - 对话项对象
+ * @param {string} str - 字段名
+ * @returns {Array} 格式化后的文件列表
+ */
+const getFormatFileList = (ConversationItem, str) => {
+ let fileList: any = getItem(ConversationItem, str);
+ if (!fileList || fileList?.length === 0) return;
+ let newFileList: any = [];
+ fileList?.forEach((file) => {
+ if (file.associated === 'answer') {
+ newFileList.push({
+ documentId: file._id,
+ documentName: file.name,
+ documentAbstract: file.abstract,
+ documentType: file.type,
+ documentSize: file.size,
+ sourceUrl: file.sourceUrl,
+ documentOrder: file.order,
+ createdAt: file.created_at,
+ documentAuthor: file.author,
+ });
+ }
+ });
+ return newFileList;
+};
+
@@ -904,6 +1018,7 @@ watch(
@handleReport="handleReport"
@handleSendMessage="handleSendMessage"
@clearSuggestion="clearSuggestion(index)"
+ @openShowFileSource="openShowFileSource"
/>
@@ -939,7 +1054,10 @@ watch(
{{ $t('feedback.stop') }}
-
+
- 请选择模型
+ {{ $t('app.modelSelected_input') }}
-
+
+
+
+
+
+
+ {{ $t('history.auto_execute') }}
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ file?.documentAbstract ?? '' }}
+
+
+
+
+
+
@@ -1348,6 +1546,25 @@ button[disabled]:hover {
}
}
+ &__autoExecute {
+ position: absolute;
+ cursor: pointer;
+ width: 120px;
+ height: 32px;
+ box-sizing: border-box;
+ border: 1px solid rgba(223, 229, 239);
+ border-radius: 8px;
+ background: rgb(253, 254, 255);
+
+ .switch-wrapper {
+ position: absolute;
+ width: 120px;
+ height: 32px;
+ line-height: 30px;
+ text-align: center;
+ }
+ }
+
&__icon {
text-align: right;
& img {
diff --git a/src/views/dialogue/components/MultiSelectTags.vue b/src/views/dialogue/components/MultiSelectTags.vue
index 30a16ef1..431c5995 100644
--- a/src/views/dialogue/components/MultiSelectTags.vue
+++ b/src/views/dialogue/components/MultiSelectTags.vue
@@ -98,6 +98,11 @@ const handleKnowledgeList = async () => {
// 移除标签
const removeTag = (index) => {
selectedTags.value.splice(index, 1);
+ // 触发父组件的updateValue事件
+ emit(
+ 'updateValue',
+ selectedTags.value.map((item) => item.kbId),
+ );
};
// 检查标签是否已被选中
diff --git a/src/views/dialogue/components/TitleBar.vue b/src/views/dialogue/components/TitleBar.vue
index 77b7cd7c..b09ad4cc 100644
--- a/src/views/dialogue/components/TitleBar.vue
+++ b/src/views/dialogue/components/TitleBar.vue
@@ -28,7 +28,7 @@ onMounted(async () => {
: `${origin}/witchaind`;
});
-const changeLanguagefun = (lang: 'zh_cn' | 'en') => {
+const changeLanguagefun = (lang: 'zh' | 'en') => {
changeLanguage(lang);
// 同步语言到iframe
const iframe = document.querySelector
('#my-iframe');
@@ -97,7 +97,7 @@ const headerStyles = computed(() => {
@@ -478,7 +481,7 @@ const handleRightValueChange = (conditionIndex: number, value: any) => {
class="danger-button"
@click="removeCondition(conditionIndex)"
type="button"
- title="删除条件"
+ :title="t('choiceBranch.titles.delete_condition')"
>
@@ -493,7 +496,7 @@ const handleRightValueChange = (conditionIndex: number, value: any) => {
:icon="Plus"
@click="addCondition"
>
- 添加条件
+ {{ t('choiceBranch.buttons.add_condition') }}
@@ -515,17 +518,27 @@ const handleRightValueChange = (conditionIndex: number, value: any) => {
.branch-card {
border-radius: 8px;
margin-bottom: 16px;
- background: #ffffff;
+ background: var(--el-bg-color);
+
+ body[theme='dark'] & {
+ background: #1f2329;
+ border-color: var(--el-border-color);
+ };
&.default-branch {
- border-color: #f56c6c;
- background: #fef0f0;
+ border-color: var(--el-color-danger);
+ background: var(--el-color-danger-light-9);
}
.branch-header {
padding: 16px;
- border-bottom: 1px solid #e4e7ed;
- background: #f8f9fa;
+ border-bottom: 1px solid var(--el-border-color-light);
+ background: var(--el-fill-color-extra-light);
+
+ body[theme='dark'] & {
+ background: var(--o-bash-bg, #2a2f37);
+ border-bottom-color: var(--el-border-color);
+ };
display: flex;
align-items: center;
justify-content: space-between;
@@ -538,11 +551,11 @@ const handleRightValueChange = (conditionIndex: number, value: any) => {
.main-title {
font-size: 18px;
font-weight: 700;
- color: #409eff;
+ color: var(--el-color-primary);
padding: 6px 12px;
- background: #ecf5ff;
+ background: var(--el-color-primary-light-9);
border-radius: 6px;
- border: 1px solid #d9ecff;
+ border: 1px solid var(--el-color-primary-light-7);
min-width: 60px;
text-align: center;
}
@@ -550,7 +563,11 @@ const handleRightValueChange = (conditionIndex: number, value: any) => {
.sub-title {
font-size: 14px;
font-weight: 600;
- color: #606266;
+ color: var(--el-text-color-primary);
+
+ body[theme='dark'] & {
+ color: #e4e8ee;
+ }
}
}
@@ -571,14 +588,22 @@ const handleRightValueChange = (conditionIndex: number, value: any) => {
.conditions-title {
font-weight: 600;
- color: black;
+ color: var(--el-text-color-primary);
font-size: 16px;
+
+ body[theme='dark'] & {
+ color: #e4e8ee;
+ }
}
.conditions-subtitle {
font-weight: 500;
- color: #676f83;
+ color: var(--el-text-color-secondary);
font-size: 12px;
+
+ body[theme='dark'] & {
+ color: #d3dce9;
+ }
}
}
@@ -606,9 +631,16 @@ const handleRightValueChange = (conditionIndex: number, value: any) => {
font-weight: 600;
font-size: 10px;
padding: 4px 8px;
- background-color: white;
+ background-color: var(--el-bg-color);
+ color: var(--el-text-color-primary);
z-index: 1;
+ body[theme='dark'] & {
+ background-color: #1f2329;
+ color: #e4e8ee;
+ border-color: var(--el-border-color);
+ };
+
// 调整图标大小
:deep(.el-icon) {
font-size: 10px;
@@ -652,8 +684,13 @@ const handleRightValueChange = (conditionIndex: number, value: any) => {
.condition-setting-col {
flex: 1;
min-width: 0;
- background: #f8f9fa;
- border: 1px solid #e4e7ed;
+ background: var(--el-fill-color-extra-light);
+ border: 1px solid var(--el-border-color-light);
+
+ body[theme='dark'] & {
+ background: var(--o-bash-bg, #2a2f37);
+ border-color: var(--el-border-color);
+ };
border-radius: 8px;
overflow: hidden;
transition: background-color 0.2s ease;
@@ -684,7 +721,11 @@ const handleRightValueChange = (conditionIndex: number, value: any) => {
.condition-number {
font-size: 12px;
font-weight: 600;
- color: #909399;
+ color: var(--el-text-color-secondary);
+
+ body[theme='dark'] & {
+ color: #d3dce9;
+ }
}
}
@@ -696,7 +737,11 @@ const handleRightValueChange = (conditionIndex: number, value: any) => {
padding: 6px 0 6px 0;
&:not(:last-child) {
- border-bottom: 1px solid #e4e7ed;
+ border-bottom: 1px solid var(--el-border-color-light);
+
+ body[theme='dark'] & {
+ border-bottom-color: var(--el-border-color);
+ };
margin-left: 2px;
margin-right: 2px;
padding-left: 0;
@@ -708,13 +753,21 @@ const handleRightValueChange = (conditionIndex: number, value: any) => {
.variable-section {
flex: 3; // VariableChooser 占3份空间
- border-right: 1px solid #e4e7ed;
+ border-right: 1px solid var(--el-border-color-light);
+
+ body[theme='dark'] & {
+ border-right-color: var(--el-border-color);
+ };
padding-right: 12px;
}
.data-type-select {
flex: 0 0 25%;
- border-right: 1px solid #e4e7ed;
+ border-right: 1px solid var(--el-border-color-light);
+
+ body[theme='dark'] & {
+ border-right-color: var(--el-border-color);
+ };
padding-right: 12px;
:deep(.el-select__wrapper) {
@@ -746,7 +799,11 @@ const handleRightValueChange = (conditionIndex: number, value: any) => {
.value-section {
flex: 1;
min-width: 0;
- border-right: 1px solid #e4e7ed;
+ border-right: 1px solid var(--el-border-color-light);
+
+ body[theme='dark'] & {
+ border-right-color: var(--el-border-color);
+ };
padding-right: 12px;
.reference-input,
@@ -767,7 +824,7 @@ const handleRightValueChange = (conditionIndex: number, value: any) => {
.el-button {
border: none;
background: transparent;
- color: #409eff;
+ color: var(--el-color-primary);
font-size: 12px;
padding: 4px 8px;
border-radius: 0;
@@ -800,91 +857,7 @@ const handleRightValueChange = (conditionIndex: number, value: any) => {
}
}
-// 深色主题支持
-.dark {
- .branch-card {
- background: #374151;
- border-color: #4b5563;
-
- &.default-branch {
- border-color: #f87171;
- background: #450a0a;
- }
-
- .branch-header {
- background: #4b5563;
- border-color: #6b7280;
-
- .branch-title-section {
- .main-title {
- color: #3b82f6;
- background: #1e3a8a;
- border-color: #1e40af;
- }
-
- .sub-title {
- color: #e5e7eb;
- }
- }
- }
-
- .conditions-container {
- .conditions-bracket {
- .bracket-line {
- background: #3b82f6;
- }
- }
-
- .conditions-list {
- .condition-item {
- background: #4b5563;
- border-color: #6b7280;
-
- .condition-setting-col {
- background: #4b5563;
- border-color: #6b7280;
-
- .condition-row {
- &:not(:last-child) {
- border-bottom-color: #6b7280;
- }
-
- &.variable-row {
- .variable-section {
- border-right-color: #6b7280;
- }
-
- .data-type-select {
- border-right-color: #6b7280;
- }
-
- .operator-select :deep(.el-select__wrapper) {
- border-right-color: #6b7280;
- }
- }
-
- &.value-row {
- .value-section {
- border-right-color: #6b7280;
- }
-
- .toggle-section .el-button {
- color: #3b82f6;
-
- &:hover {
- background: rgba(59, 130, 246, 0.2);
- }
- }
- }
- }
- }
- }
- }
- }
-
-
- }
-}
+// 深色主题适配已集成到主样式中
// 确保VariableChooser组件样式适配
:deep(.variable-chooser) {
diff --git a/src/views/createapp/components/workFlowConfig/ChoiceBranchDrawer.vue b/src/views/createapp/components/workFlowConfig/ChoiceBranchDrawer.vue
index 89b42d2f..550d3bac 100644
--- a/src/views/createapp/components/workFlowConfig/ChoiceBranchDrawer.vue
+++ b/src/views/createapp/components/workFlowConfig/ChoiceBranchDrawer.vue
@@ -77,68 +77,68 @@ const formData = ref({
});
// 操作符选项
-const operatorOptions = {
+const operatorOptions = computed(() => ({
string: [
- { label: '等于', value: 'eq' },
- { label: '不等于', value: 'ne' },
- { label: '包含', value: 'contains' },
- { label: '不包含', value: 'not_contains' },
- { label: '开始于', value: 'starts_with' },
- { label: '结束于', value: 'ends_with' },
- { label: '为空', value: 'is_empty' },
- { label: '不为空', value: 'is_not_empty' },
+ { label: t('choiceBranch.operators.eq'), value: 'eq' },
+ { label: t('choiceBranch.operators.ne'), value: 'ne' },
+ { label: t('choiceBranch.operators.contains'), value: 'contains' },
+ { label: t('choiceBranch.operators.not_contains'), value: 'not_contains' },
+ { label: t('choiceBranch.operators.starts_with'), value: 'starts_with' },
+ { label: t('choiceBranch.operators.ends_with'), value: 'ends_with' },
+ { label: t('choiceBranch.operators.is_empty'), value: 'is_empty' },
+ { label: t('choiceBranch.operators.is_not_empty'), value: 'is_not_empty' },
],
number: [
- { label: '等于', value: 'eq' },
- { label: '不等于', value: 'ne' },
- { label: '大于', value: 'gt' },
- { label: '大于等于', value: 'gte' },
- { label: '小于', value: 'lt' },
- { label: '小于等于', value: 'lte' },
+ { label: t('choiceBranch.operators.eq'), value: 'eq' },
+ { label: t('choiceBranch.operators.ne'), value: 'ne' },
+ { label: t('choiceBranch.operators.gt'), value: 'gt' },
+ { label: t('choiceBranch.operators.gte'), value: 'gte' },
+ { label: t('choiceBranch.operators.lt'), value: 'lt' },
+ { label: t('choiceBranch.operators.lte'), value: 'lte' },
],
bool: [
- { label: '等于', value: 'eq' },
- { label: '不等于', value: 'ne' },
+ { label: t('choiceBranch.operators.eq'), value: 'eq' },
+ { label: t('choiceBranch.operators.ne'), value: 'ne' },
],
list: [
- { label: '包含', value: 'contains' },
- { label: '不包含', value: 'not_contains' },
- { label: '为空', value: 'is_empty' },
- { label: '不为空', value: 'is_not_empty' },
- { label: '长度等于', value: 'length_eq' },
- { label: '长度大于', value: 'length_gt' },
- { label: '长度小于', value: 'length_lt' },
+ { label: t('choiceBranch.operators.contains'), value: 'contains' },
+ { label: t('choiceBranch.operators.not_contains'), value: 'not_contains' },
+ { label: t('choiceBranch.operators.is_empty'), value: 'is_empty' },
+ { label: t('choiceBranch.operators.is_not_empty'), value: 'is_not_empty' },
+ { label: t('choiceBranch.operators.length_eq'), value: 'length_eq' },
+ { label: t('choiceBranch.operators.length_gt'), value: 'length_gt' },
+ { label: t('choiceBranch.operators.length_lt'), value: 'length_lt' },
],
dict: [
- { label: '包含键', value: 'has_key' },
- { label: '不包含键', value: 'not_has_key' },
- { label: '为空', value: 'is_empty' },
- { label: '不为空', value: 'is_not_empty' },
+ { label: t('choiceBranch.operators.has_key'), value: 'has_key' },
+ { label: t('choiceBranch.operators.not_has_key'), value: 'not_has_key' },
+ { label: t('choiceBranch.operators.is_empty'), value: 'is_empty' },
+ { label: t('choiceBranch.operators.is_not_empty'), value: 'is_not_empty' },
],
-};
+}));
// 值类型选项
-const valueTypeOptions = [
- { label: '字符串', value: 'string' },
- { label: '数字', value: 'number' },
- { label: '布尔值', value: 'bool' },
- { label: '列表', value: 'list' },
- { label: '字典', value: 'dict' },
- { label: '引用变量', value: 'reference' },
-];
+const valueTypeOptions = computed(() => [
+ { label: t('choiceBranch.data_types.string'), value: 'string' },
+ { label: t('choiceBranch.data_types.number'), value: 'number' },
+ { label: t('choiceBranch.data_types.bool'), value: 'bool' },
+ { label: t('choiceBranch.data_types.list'), value: 'list' },
+ { label: t('choiceBranch.data_types.dict'), value: 'dict' },
+ { label: t('choiceBranch.data_types.reference'), value: 'reference' },
+]);
// 逻辑运算符选项
-const logicOptions = [
- { label: '且 (AND)', value: 'and' },
- { label: '或 (OR)', value: 'or' },
-];
+const logicOptions = computed(() => [
+ { label: t('choiceBranch.logic_operators.and'), value: 'and' },
+ { label: t('choiceBranch.logic_operators.or'), value: 'or' },
+]);
// 初始化表单数据
const initFormData = () => {
if (props.nodeData) {
const allChoices = JSON.parse(JSON.stringify(props.nodeData.parameters?.input_parameters?.choices || []));
- console.log('[ChoiceBranchDrawer] 初始化表单数据 - 原始choices:', {
+ console.log('[ChoiceBranchDrawer]', t('choiceBranch.console.init_form_data'), {
allChoices,
choicesCount: allChoices.length,
nodeData: props.nodeData
@@ -148,7 +148,7 @@ const initFormData = () => {
let defaultBranches = allChoices.filter(choice => choice.is_default);
let nonDefaultChoices = allChoices.filter(choice => !choice.is_default);
- console.log('[ChoiceBranchDrawer] 分支分离结果:', {
+ console.log('[ChoiceBranchDrawer]', t('choiceBranch.console.branch_separation_result'), {
defaultBranches,
nonDefaultChoices,
defaultCount: defaultBranches.length,
@@ -157,7 +157,7 @@ const initFormData = () => {
// 详细打印每个非默认分支的条件信息
nonDefaultChoices.forEach((choice, index) => {
- console.log(`[ChoiceBranchDrawer] 非默认分支 ${index}:`, {
+ console.log(`[ChoiceBranchDrawer] ${t('choiceBranch.console.non_default_branch')} ${index}:`, {
branch_id: choice.branch_id,
name: choice.name,
is_default: choice.is_default,
@@ -168,13 +168,13 @@ const initFormData = () => {
// 验证默认分支数量
if (defaultBranches.length > 1) {
- console.warn('[ChoiceBranchDrawer] 发现多个默认分支,只保留第一个:', defaultBranches);
- ElMessage.error('数据错误:不能有多个默认分支');
+ console.warn('[ChoiceBranchDrawer]', t('choiceBranch.console.found_multiple_default'), defaultBranches);
+ ElMessage.error(t('choiceBranch.validation.data_error_multiple_default'));
defaultBranches = [defaultBranches[0]]; // 只保留第一个默认分支
}
formData.value = {
- name: props.nodeData.name || '条件分支',
+ name: props.nodeData.name || t('choiceBranch.titles.condition_branch'),
description: props.nodeData.description || '',
choices: nonDefaultChoices,
defaultBranch: defaultBranches.length > 0 ? defaultBranches[0] : null,
@@ -189,7 +189,7 @@ const initFormData = () => {
})
.map((choice, index) => ({
branch_id: choice.branch_id || uuidv4(),
- name: choice.name || `分支 ${index + 1}`,
+ name: choice.name || `${t('choiceBranch.status.branch_prefix')} ${index + 1}`,
logic: choice.logic || 'and',
conditions: (() => {
// 处理条件数组
@@ -204,7 +204,7 @@ const initFormData = () => {
type: condition.right?.type || 'string',
value: condition.right?.value || '',
},
- operate: condition.operator || condition.operate || 'string_equal',
+ operate: condition.operate || 'string_equal',
dataType: condition.dataType || 'string',
isRightReference: condition.isRightReference !== undefined ? condition.isRightReference : false,
}));
@@ -245,10 +245,10 @@ const initFormData = () => {
// 更新非默认分支名称为 IF/ELIF(如果有有效分支)
if (formData.value.choices.length > 0) {
- console.log('[ChoiceBranchDrawer] 有非默认分支,更新名称');
+ console.log('[ChoiceBranchDrawer]', t('choiceBranch.console.has_non_default_branch'));
updateBranchNames();
} else {
- console.log('[ChoiceBranchDrawer] 没有非默认分支,创建一个空的IF分支');
+ console.log('[ChoiceBranchDrawer]', t('choiceBranch.console.no_non_default_branch'));
// 如果没有非默认分支,创建一个空的IF分支,这样用户就不需要手动点击+ELIF按钮
formData.value.choices = [
{
@@ -263,7 +263,7 @@ const initFormData = () => {
// 如果没有默认分支,创建一个
if (!formData.value.defaultBranch) {
- console.log('[ChoiceBranchDrawer] 没有默认分支,创建ELSE分支');
+ console.log('[ChoiceBranchDrawer]', t('choiceBranch.console.no_default_branch'));
formData.value.defaultBranch = {
branch_id: 'else_' + uuidv4(),
name: 'ELSE',
@@ -272,10 +272,10 @@ const initFormData = () => {
is_default: true,
};
} else {
- console.log('[ChoiceBranchDrawer] 已有默认分支:', formData.value.defaultBranch);
+ console.log('[ChoiceBranchDrawer]', t('choiceBranch.console.has_default_branch'), formData.value.defaultBranch);
}
- console.log('[ChoiceBranchDrawer] 最终formData:', {
+ console.log('[ChoiceBranchDrawer]', t('choiceBranch.console.final_form_data'), {
choices: formData.value.choices,
defaultBranch: formData.value.defaultBranch,
choicesCount: formData.value.choices.length
@@ -283,7 +283,7 @@ const initFormData = () => {
} else {
// 如果没有nodeData,创建空的表单数据,不自动创建IF分支
formData.value = {
- name: '条件分支',
+ name: t('choiceBranch.titles.condition_branch'),
description: '',
choices: [], // 不自动创建IF分支
defaultBranch: {
@@ -409,13 +409,13 @@ const updateCondition = (choiceIndex, conditionIndex, condition) => {
const validateForm = () => {
// 验证基本信息
if (!formData.value.name || formData.value.name.trim() === '') {
- ElMessage.error('请填写节点名称');
+ ElMessage.error(t('choiceBranch.validation.enter_node_name'));
return false;
}
// 验证是否至少有一个分支(默认分支)
if (!formData.value.defaultBranch && formData.value.choices.length === 0) {
- ElMessage.error('至少需要一个分支');
+ ElMessage.error(t('choiceBranch.validation.need_at_least_one_branch'));
return false;
}
@@ -435,15 +435,15 @@ const validateForm = () => {
// 对于有条件的分支,验证条件完整性
for (const condition of validConditions) {
if (!condition.left.value || condition.left.value === '') {
- ElMessage.error(`${choice.name} 分支存在未填写的左值变量`);
+ ElMessage.error(t('choiceBranch.validation.branch_missing_left_variable', { branchName: choice.name }));
return false;
}
if (!condition.right.value || condition.right.value === '') {
- ElMessage.error(`${choice.name} 分支存在未填写的右值`);
+ ElMessage.error(t('choiceBranch.validation.branch_missing_right_value', { branchName: choice.name }));
return false;
}
if (!condition.operate) {
- ElMessage.error(`${choice.name} 分支存在未选择的操作符`);
+ ElMessage.error(t('choiceBranch.validation.branch_missing_operator', { branchName: choice.name }));
return false;
}
}
@@ -479,7 +479,7 @@ const saveNode = () => {
// 如果没有任何有效的非默认分支,确保至少有默认分支
if (allChoices.length === 0) {
- ElMessage.error('至少需要一个有效的分支');
+ ElMessage.error(t('choiceBranch.validation.need_valid_branch'));
return;
}
@@ -523,13 +523,13 @@ const saveNode = () => {
output_parameters: {
branch_id: {
type: 'string',
- description: '选中的分支ID'
+ description: t('choiceBranch.titles.selected_branch_id')
}
},
},
};
- console.log('[ChoiceBranchDrawer] 保存的最终数据:', {
+ console.log('[ChoiceBranchDrawer]', t('choiceBranch.console.save_final_data'), {
processedChoices,
validChoicesCount: validChoices.length,
totalChoicesCount: allChoices.length
@@ -593,7 +593,7 @@ const formatValue = (value, type) => {
{
-
基本信息
+
{{ $t('choiceBranch.basic_info') }}
-
-
+
+
-
+
@@ -621,7 +621,7 @@ const formatValue = (value, type) => {
@@ -648,7 +648,7 @@ const formatValue = (value, type) => {
@@ -658,7 +658,7 @@ const formatValue = (value, type) => {
ELSE
-
用于定义当IF/ELIF条件均不满足时执行的分支
+
{{ $t('choiceBranch.tips.else_description') }}
@@ -667,8 +667,8 @@ const formatValue = (value, type) => {
@@ -685,6 +685,11 @@ const formatValue = (value, type) => {
height: 100%;
overflow-y: auto;
padding: 20px;
+ background: var(--el-bg-color);
+
+ body[theme='dark'] & {
+ background: #1f2329;
+ }
}
.section {
@@ -693,8 +698,12 @@ const formatValue = (value, type) => {
.section-title {
font-size: 16px;
font-weight: 600;
- color: #303133;
+ color: var(--el-text-color-primary);
margin: 0 0 16px 0;
+
+ body[theme='dark'] & {
+ color: #e4e8ee;
+ }
}
.section-header {
@@ -712,8 +721,8 @@ const formatValue = (value, type) => {
.add-branch-btn {
width: calc(100% - 20px);
padding: 12px 16px;
- background-color: #f2f4f7;
- color: black;
+ background-color: var(--el-fill-color-extra-light);
+ color: var(--el-text-color-primary);
border: none;
border-radius: 6px;
font-size: 14px;
@@ -724,13 +733,24 @@ const formatValue = (value, type) => {
gap: 6px;
transition: all 0.2s;
+ body[theme='dark'] & {
+ background-color: #1f2329;
+ color: #e4e8ee;
+ border: 1px solid var(--el-border-color);
+ }
+
svg {
width: 14px;
height: 14px;
}
&:hover {
- background-color: #e5e7eb;
+ background-color: var(--el-fill-color-light);
+
+ body[theme='dark'] & {
+ background-color: var(--flow-node-default-over-color, #25303e);
+ border-color: var(--flow-node-boder-default-over, #314265);
+ }
}
&:active {
@@ -741,23 +761,35 @@ const formatValue = (value, type) => {
.divider {
height: 1px;
- background: #e4e7ed;
+ background: var(--el-border-color-light);
margin: 24px 0;
+
+ body[theme='dark'] & {
+ background: var(--el-border-color);
+ }
}
.default-branch-section {
.else-title {
font-size: 16px;
font-weight: 600;
- color: #303133;
+ color: var(--el-text-color-primary);
margin: 0 0 8px 0;
+
+ body[theme='dark'] & {
+ color: #e4e8ee;
+ }
}
.else-description {
font-size: 14px;
- color: #909399;
+ color: var(--el-text-color-secondary);
margin: 0;
line-height: 1.5;
+
+ body[theme='dark'] & {
+ color: #d3dce9;
+ }
}
}
@@ -766,28 +798,17 @@ const formatValue = (value, type) => {
.drawer-footer {
padding: 16px 20px;
- border-top: 1px solid #e4e7ed;
- background: #f8f9fa;
+ border-top: 1px solid var(--el-border-color-light);
+ background: var(--el-bg-color);
display: flex;
justify-content: flex-end;
gap: 12px;
-}
-
-// 深色主题支持
-.dark {
- .choice-branch-drawer {
- .drawer-content {
- background: #1a1a1a;
- }
-
- .section-title {
- color: #e5e7eb;
- }
-
- .drawer-footer {
- background: #374151;
- border-color: #4b5563;
- }
+
+ body[theme='dark'] & {
+ background: #1f2329;
+ border-top-color: var(--el-border-color);
}
}
+
+// 深色主题适配已集成到主样式中
\ No newline at end of file
diff --git a/src/views/createapp/components/workFlowConfig/ChoiceBranchNode.vue b/src/views/createapp/components/workFlowConfig/ChoiceBranchNode.vue
index 79c6268a..15a6393b 100644
--- a/src/views/createapp/components/workFlowConfig/ChoiceBranchNode.vue
+++ b/src/views/createapp/components/workFlowConfig/ChoiceBranchNode.vue
@@ -65,7 +65,7 @@ const branches = computed(() => {
return choices.map((choice, index) => {
return {
id: choice.branch_id || `branch_${index}`,
- name: choice.name || `分支 ${index + 1}`,
+ name: choice.name || `${t('choiceBranch.status.branch_prefix')} ${index + 1}`,
isDefault: choice.is_default || false,
conditions: choice.conditions || [],
logic: choice.logic || 'and'
@@ -169,40 +169,8 @@ const setConnectStatus = (type) => {
};
// 操作符中文映射
-const operatorLabels = {
- 'string_equal': '等于',
- 'string_not_equal': '不等于',
- 'string_contains': '包含',
- 'string_not_contains': '不包含',
- 'string_starts_with': '开始于',
- 'string_ends_with': '结束于',
- 'string_length_equal': '长度等于',
- 'string_length_greater_than': '长度大于',
- 'string_length_greater_than_or_equal': '长度大于等于',
- 'string_length_less_than': '长度小于',
- 'string_length_less_than_or_equal': '长度小于等于',
- 'string_regex_match': '正则匹配',
- 'number_equal': '等于',
- 'number_not_equal': '不等于',
- 'number_greater_than': '大于',
- 'number_less_than': '小于',
- 'number_greater_than_or_equal': '大于等于',
- 'number_less_than_or_equal': '小于等于',
- 'list_equal': '等于',
- 'list_not_equal': '不等于',
- 'list_contains': '包含',
- 'list_not_contains': '不包含',
- 'list_length_equal': '长度等于',
- 'list_length_greater_than': '长度大于',
- 'list_length_greater_than_or_equal': '长度大于等于',
- 'list_length_less_than': '长度小于',
- 'list_length_less_than_or_equal': '长度小于等于',
- 'bool_equal': '等于',
- 'bool_not_equal': '不等于',
- 'dict_equal': '等于',
- 'dict_not_equal': '不等于',
- 'dict_contains_key': '包含键',
- 'dict_not_contains_key': '不包含键',
+const getOperatorLabel = (operatorKey: string): string => {
+ return t(`choiceBranch.operators.${operatorKey}`, operatorKey);
};
// 解析变量引用,提取变量名
@@ -254,7 +222,7 @@ const formatValueByType = (value, dataType, isReference = false) => {
// 格式化条件显示
const formatConditions = (conditions, logic) => {
if (!conditions || conditions.length === 0) {
- return '条件未设置';
+ return t('choiceBranch.status.condition_not_set');
}
// 过滤掉无效条件(left.value为null的条件)
@@ -266,7 +234,7 @@ const formatConditions = (conditions, logic) => {
});
if (validConditions.length === 0) {
- return '条件未设置';
+ return t('choiceBranch.status.condition_not_set');
}
const conditionTexts = validConditions.map(condition => {
@@ -275,7 +243,7 @@ const formatConditions = (conditions, logic) => {
// 获取操作符中文
const operatorKey = condition.operator || condition.operate;
- let operatorLabel = operatorLabels[operatorKey];
+ let operatorLabel = getOperatorLabel(operatorKey);
// 如果没有找到映射,提供简单的后备显示
if (!operatorLabel) {
@@ -312,14 +280,14 @@ const formatConditions = (conditions, logic) => {
return `${leftValue} ${operatorLabel} ${rightValue}`;
});
- const logicText = logic === 'and' ? ' 且 ' : ' 或 ';
+ const logicText = logic === 'and' ? ` ${t('choiceBranch.logic_operators.and_text')} ` : ` ${t('choiceBranch.logic_operators.or_text')} `;
return conditionTexts.join(logicText);
};
// 格式化条件显示为HTML(带标签样式)
const formatConditionsHtml = (conditions, logic) => {
if (!conditions || conditions.length === 0) {
- return '
条件未设置';
+ return `
${t('choiceBranch.status.condition_not_set')}`;
}
// 过滤掉无效条件(left.value为null的条件)
@@ -331,7 +299,7 @@ const formatConditionsHtml = (conditions, logic) => {
});
if (validConditions.length === 0) {
- return '
条件未设置';
+ return `
${t('choiceBranch.status.condition_not_set')}`;
}
const conditionTexts = validConditions.map(condition => {
@@ -341,11 +309,11 @@ const formatConditionsHtml = (conditions, logic) => {
// 获取操作符中文 - 添加操作符样式
const operatorKey = condition.operator || condition.operate;
- let operatorLabel = operatorLabels[operatorKey];
+ let operatorLabel = getOperatorLabel(operatorKey);
// 如果没有找到映射,提供简单的后备显示
- if (!operatorLabel) {
- console.warn(`[Choice显示] 未找到操作符映射: ${operatorKey}`);
+ if (operatorLabel === operatorKey) {
+ console.warn(`[Choice显示]`, t('choiceBranch.console.operator_mapping_not_found'), operatorKey);
switch(operatorKey) {
case 'number_less_than_or_equal':
operatorLabel = '<=';
@@ -386,7 +354,7 @@ const formatConditionsHtml = (conditions, logic) => {
return `${leftHtml} ${operatorHtml} ${rightHtml}`;
});
- const logicText = logic === 'and' ? '
且 ' : '
或 ';
+ const logicText = logic === 'and' ? `
${t('choiceBranch.logic_operators.and_text')} ` : `
${t('choiceBranch.logic_operators.or_text')} `;
return conditionTexts.join(logicText);
};
@@ -520,7 +488,7 @@ const handleBranchInsertNode = (event: Event, branchId: string) => {
- 其他所有情况
+ {{ t('choiceBranch.tips.other_cases') }}
@@ -549,7 +517,7 @@ const handleBranchInsertNode = (event: Event, branchId: string) => {
-
点击编辑添加分支条件
+
{{ t('choiceBranch.tips.click_edit_add_branch') }}
@@ -1094,7 +1062,7 @@ const handleBranchInsertNode = (event: Event, branchId: string) => {
// 深色主题支持 - 使用用户指定的颜色规范
.dark {
.choiceBranchNodeStyle {
- background: #26262a !important;
+ background: #353f58 !important;
border: 2px solid rgba(255, 255, 255, 0.08) !important;
.title .label {
diff --git a/src/views/createapp/components/workFlowConfig/CodeNodeDrawer.vue b/src/views/createapp/components/workFlowConfig/CodeNodeDrawer.vue
index f3c84466..aed04e7c 100644
--- a/src/views/createapp/components/workFlowConfig/CodeNodeDrawer.vue
+++ b/src/views/createapp/components/workFlowConfig/CodeNodeDrawer.vue
@@ -28,22 +28,22 @@
- 基本信息
+ {{ $t('flow.node_config.basic_info') }}
-
+
-
-
-
-
+
+
+
+
@@ -56,18 +56,18 @@
-
变量管理
+
{{ $t('flow.node_config.variable_management') }}
-
+
@@ -89,28 +89,28 @@
:show-actions="true"
:show-variable-info="true"
output-format="wrapped"
- placeholder="输入节点内的变量名"
+ :placeholder="$t('flow.node_config.variable_placeholder')"
@remove="removeInputVariable(index)"
@variable-selected="(selectedVar, reference) => handleInputVariableSelected(selectedVar, index)"
/>
-
暂无输入变量
-
选择变量作为代码输入参数
+
{{ $t('flow.node_config.no_input_variables') }}
+
{{ $t('flow.node_config.input_variables_tip') }}
-
+
@@ -123,20 +123,20 @@
@@ -166,29 +166,29 @@
- 执行配置
+ {{ $t('flow.node_config.execution_config') }}
-
+
- 秒
+ {{ $t('flow.node_config.seconds') }}
-
+
- MB
+ {{ $t('flow.node_config.mb') }}
-
+
- 核心
+ {{ $t('flow.node_config.cores') }}
@@ -208,7 +208,7 @@
- 代码编辑
+ {{ $t('flow.node_config.code_editor') }}
@@ -230,9 +230,9 @@
@@ -929,12 +929,23 @@ watch(inputVariables, () => {
.code-node-drawer {
:deep(.el-drawer) {
border-radius: 8px 0 0 8px;
+ background: var(--el-bg-color);
+
+ body[theme='dark'] & {
+ background: #1f2329;
+ }
}
:deep(.el-drawer__header) {
padding: 24px 24px 16px !important;
margin-bottom: 0;
border-bottom: 1px solid var(--el-border-color-lighter);
+ background: var(--el-bg-color);
+
+ body[theme='dark'] & {
+ background: #1f2329;
+ border-bottom-color: var(--el-border-color);
+ }
}
:deep(.el-drawer__body) {
@@ -944,6 +955,12 @@ watch(inputVariables, () => {
:deep(.el-drawer__footer) {
padding: 16px 24px;
border-top: 1px solid var(--el-border-color-lighter);
+ background: var(--el-bg-color);
+
+ body[theme='dark'] & {
+ background: #1f2329;
+ border-top-color: var(--el-border-color);
+ }
}
.drawer-header {
@@ -953,6 +970,10 @@ watch(inputVariables, () => {
font-size: 16px;
font-weight: 500;
color: var(--el-text-color-primary);
+
+ body[theme='dark'] & {
+ color: #e4e8ee;
+ };
.node-icon {
width: 24px;
@@ -965,6 +986,11 @@ watch(inputVariables, () => {
.drawer-body {
height: 100%;
overflow-y: auto;
+ background: var(--el-bg-color);
+
+ body[theme='dark'] & {
+ background: #1f2329;
+ };
.code-content {
:deep(.el-collapse-item__header) {
@@ -972,6 +998,13 @@ watch(inputVariables, () => {
font-weight: 500;
background: var(--el-fill-color-extra-light);
border-bottom: 1px solid var(--el-border-color-lighter);
+ color: var(--el-text-color-primary);
+
+ body[theme='dark'] & {
+ background: var(--o-bash-bg, #2a2f37);
+ border-bottom-color: var(--el-border-color);
+ color: #e4e8ee;
+ }
}
:deep(.el-collapse-item__wrap) {
@@ -980,6 +1013,11 @@ watch(inputVariables, () => {
:deep(.el-collapse-item__content) {
padding: 20px 24px;
+ background: var(--el-bg-color);
+
+ body[theme='dark'] & {
+ background: #1f2329;
+ }
}
}
}
@@ -994,6 +1032,10 @@ watch(inputVariables, () => {
margin-left: 8px;
color: var(--el-text-color-secondary);
font-size: 12px;
+
+ body[theme='dark'] & {
+ color: #d3dce9;
+ }
}
}
@@ -1016,49 +1058,81 @@ watch(inputVariables, () => {
// 确保工具栏在暗色主题下正确显示
.editor-toolbar {
+ background: var(--el-fill-color-extra-light);
+
+ body[theme='dark'] & {
+ background: var(--o-bash-bg, #2a2f37);
+ }
+
.toolbar-left {
.language-selector {
label {
- color: #abb2bf;
+ color: var(--el-text-color-primary);
+
+ body[theme='dark'] & {
+ color: #e4e8ee;
+ }
}
}
.toolbar-actions {
:deep(.el-button) {
- color: #ffffff !important; // 使用白色文字确保清晰可见
- font-size: 13px !important; // 稍微增大字体
- font-weight: 500 !important; // 增加字体粗细
- padding: 6px 12px !important; // 增加内边距提升点击体验
- border-radius: 4px !important; // 添加圆角
- transition: all 0.2s ease !important; // 添加过渡动画
- border: 1px solid transparent !important; // 透明边框便于添加悬停效果
+ color: var(--el-text-color-primary) !important;
+ font-size: 13px !important;
+ font-weight: 500 !important;
+ padding: 6px 12px !important;
+ border-radius: 4px !important;
+ transition: all 0.2s ease !important;
+ border: 1px solid transparent !important;
background: transparent !important;
+ body[theme='dark'] & {
+ color: #e4e8ee !important;
+ }
+
span {
- color: #ffffff !important;
+ color: var(--el-text-color-primary) !important;
+
+ body[theme='dark'] & {
+ color: #e4e8ee !important;
+ }
}
&:hover {
- color: #61afef !important; // 悬停时使用主题蓝色
- background: rgba(97, 175, 239, 0.15) !important; // 稍微增加背景透明度
- border-color: rgba(97, 175, 239, 0.3) !important; // 添加边框效果
- transform: translateY(-1px) !important; // 轻微上移效果
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2) !important; // 添加阴影
+ color: var(--el-color-primary) !important;
+ background: var(--el-color-primary-light-9) !important;
+ border-color: var(--el-color-primary-light-7) !important;
+ transform: translateY(-1px) !important;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1) !important;
+
+ body[theme='dark'] & {
+ background: var(--flow-node-default-over-color, #25303e) !important;
+ border-color: var(--flow-node-boder-default-over, #314265) !important;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3) !important;
+ }
span {
- color: #61afef !important;
+ color: var(--el-color-primary) !important;
}
}
&:active {
- transform: translateY(0) !important; // 点击时回到原位
- background: rgba(97, 175, 239, 0.25) !important;
+ transform: translateY(0) !important;
+ background: var(--el-color-primary-light-8) !important;
+
+ body[theme='dark'] & {
+ background: var(--flow-node-default-over-color, #25303e) !important;
+ }
}
&:focus {
outline: none !important;
- border-color: #61afef !important;
- box-shadow: 0 0 0 2px rgba(97, 175, 239, 0.2) !important;
+ border-color: var(--el-color-primary) !important;
+ box-shadow: 0 0 0 2px var(--el-color-primary-light-8) !important;
+
+ body[theme='dark'] & {
+ box-shadow: 0 0 0 2px var(--flow-node-boder-default-over, #314265) !important;
+ }
}
}
}
@@ -1082,10 +1156,18 @@ watch(inputVariables, () => {
margin-bottom: 16px;
padding-bottom: 8px;
border-bottom: 1px solid var(--el-border-color-lighter);
+
+ body[theme='dark'] & {
+ border-bottom-color: var(--el-border-color);
+ }
span {
font-weight: 500;
color: var(--el-text-color-primary);
+
+ body[theme='dark'] & {
+ color: #e4e8ee;
+ }
}
}
@@ -1096,6 +1178,11 @@ watch(inputVariables, () => {
background: var(--el-fill-color-extra-light);
border-radius: 6px;
border: 1px solid var(--el-border-color-lighter);
+
+ body[theme='dark'] & {
+ background: var(--o-bash-bg, #2a2f37);
+ border-color: var(--el-border-color);
+ };
.variable-header {
display: flex;
@@ -1126,6 +1213,10 @@ watch(inputVariables, () => {
text-align: center;
padding: 40px 20px;
color: var(--el-text-color-secondary);
+
+ body[theme='dark'] & {
+ color: #d3dce9;
+ }
p {
margin: 0;
@@ -1135,6 +1226,10 @@ watch(inputVariables, () => {
font-size: 12px;
margin-top: 8px;
color: var(--el-text-color-placeholder);
+
+ body[theme='dark'] & {
+ color: #8d98aa;
+ }
}
}
}
diff --git a/src/views/createapp/components/workFlowConfig/CommentNode.vue b/src/views/createapp/components/workFlowConfig/CommentNode.vue
new file mode 100644
index 00000000..473ea9c3
--- /dev/null
+++ b/src/views/createapp/components/workFlowConfig/CommentNode.vue
@@ -0,0 +1,530 @@
+
+
+
+
+
+
+
diff --git a/src/views/createapp/components/workFlowConfig/CustomNode.vue b/src/views/createapp/components/workFlowConfig/CustomNode.vue
index 68f4bbb8..a6c648d6 100644
--- a/src/views/createapp/components/workFlowConfig/CustomNode.vue
+++ b/src/views/createapp/components/workFlowConfig/CustomNode.vue
@@ -444,7 +444,7 @@ const handleSourceHandleLeave = () => {
/* 黑夜模式支持 - 使用用户指定的颜色规范 */
.dark .customNodeStyle {
- background: #26262a !important;
+ background: #353f58 !important;
border: 2px solid rgba(255, 255, 255, 0.08) !important;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3) !important;
@@ -453,7 +453,7 @@ const handleSourceHandleLeave = () => {
}
.nodeBox {
- background: #26262a !important;
+ background: #353f58 !important;
.title {
.label {
@@ -499,14 +499,14 @@ const handleSourceHandleLeave = () => {
}
.handle-plus-button .plus-icon {
- background: #26262a;
+ background: #353f58;
border-color: #63b3ed;
color: #63b3ed;
box-shadow: 0 3px 8px rgba(99, 179, 237, 0.4);
&:hover {
background: #63b3ed;
- color: #26262a;
+ color: #353f58;
box-shadow: 0 5px 15px rgba(99, 179, 237, 0.6);
}
}
diff --git a/src/views/createapp/components/workFlowConfig/CustomSaENode.vue b/src/views/createapp/components/workFlowConfig/CustomSaENode.vue
index 81cdcdde..3ec36bb9 100644
--- a/src/views/createapp/components/workFlowConfig/CustomSaENode.vue
+++ b/src/views/createapp/components/workFlowConfig/CustomSaENode.vue
@@ -2,6 +2,9 @@
import { Position, Handle } from '@vue-flow/core';
import { ref, onMounted, watch, nextTick, computed } from 'vue';
import { Plus } from '@element-plus/icons-vue';
+import { useI18n } from 'vue-i18n';
+
+const { t } = useI18n();
const props = defineProps({
id: {
type: String,
@@ -59,7 +62,7 @@ const setConnectStatus = (type) => {
// 处理开始节点点击编辑
const handleStartNodeClick = () => {
- const isStartNode = props.data.name === '开始' || props.data.name === 'start';
+ const isStartNode = props.data.name === '开始' || props.data.name === 'start' || props.data.name === t('flow.node_names.start');
if (isStartNode) {
// 使用nextTick确保DOM更新完成
nextTick(() => {
@@ -119,12 +122,12 @@ const conversationVariables = computed(() => {
// 判断是否为开始节点
const isStartNode = computed(() => {
- return props.data.name === '开始' || props.data.name === 'start';
+ return props.data.name === '开始' || props.data.name === 'start' || props.data.name === t('flow.node_names.start');
});
// 判断是否为结束节点
const isEndNode = computed(() => {
- return props.data.name === '结束' || props.data.name === 'end';
+ return props.data.name === '结束' || props.data.name === 'end' || props.data.name === t('flow.node_names.end');
});
// 获取变量类型的显示名称
@@ -206,19 +209,19 @@ watch(
-
+
@@ -457,11 +460,11 @@ watch(
/* 黑夜模式支持 - 使用用户指定的颜色规范 */
.dark .nodeSaEBorder {
- background: #26262a !important;
+ background: #353f58 !important;
border: 2px solid rgba(255, 255, 255, 0.08) !important;
.nodeSaEBorderBox {
- background: #26262a !important;
+ background: #353f58 !important;
}
.saEText {
@@ -492,12 +495,12 @@ watch(
.handle-plus-button .plus-icon {
color: #63b3ed;
- background: #26262a;
+ background: #353f58;
border-color: #63b3ed;
&:hover {
background: #63b3ed;
- color: #26262a;
+ color: #353f58;
}
}
}
diff --git a/src/views/createapp/components/workFlowConfig/DirectReplyDrawer.vue b/src/views/createapp/components/workFlowConfig/DirectReplyDrawer.vue
index 6ace1af8..9269c188 100644
--- a/src/views/createapp/components/workFlowConfig/DirectReplyDrawer.vue
+++ b/src/views/createapp/components/workFlowConfig/DirectReplyDrawer.vue
@@ -28,24 +28,24 @@
-
基本信息
+
{{ $t('flow.node_config.basic_info') }}
-
+
-
+
@@ -60,7 +60,7 @@
- 回复内容
+ {{ $t('app.outputContent') }}
@@ -69,13 +69,13 @@
v-model="nodeConfig.answer"
:flow-id="flowId"
:current-step-id="nodeId"
- placeholder="请输入回复内容,可以使用变量插入功能..."
+ :placeholder="$t('app.inputContent') + '...'"
@variable-inserted="handleFileVariableInserted"
/>
- {{ getCharCount() }} 字符
+ {{ getCharCount() }} {{ $t('common.characters') }}
@@ -86,7 +86,7 @@
-
+
({{ nodeConfig.fileVariables.length }})
@@ -103,7 +103,7 @@
{{ fileVar.displayName }}
{{ formatVariableDisplay(fileVar.variableName) }}
-
{{ fileVar.fileType === 'file' ? '单文件' : '多文件' }}
+
{{ fileVar.fileType === 'file' ? $t('flow.single_file') : $t('flow.multiple_files') }}
✕
@@ -172,19 +172,19 @@ interface Props {
const props = defineProps
()
const emit = defineEmits(['update:visible', 'saveNode'])
-// const { t } = useI18n() // 暂时不使用
+const { t } = useI18n()
// 响应式数据
const drawerVisible = ref(false)
const activeName = ref(['basic', 'content'])
-const nodeName = ref('回答')
+const nodeName = ref(t('flow.answer'))
const textEditorRef = ref()
// 节点配置
const nodeConfig = ref({
- name: '回答',
+ name: t('flow.answer'),
description: '',
answer: '',
fileVariables: []
@@ -225,7 +225,7 @@ const initializeNodeData = () => {
}
nodeConfig.value = {
- name: props.nodeData.name || '回答',
+ name: props.nodeData.name || t('flow.answer'),
description: props.nodeData.description || '',
answer: props.nodeData.parameters?.input_parameters?.answer || '',
fileVariables: fileVariables
@@ -250,7 +250,7 @@ const handleFileVariableInserted = (variable: any) => {
// 检查是否已存在相同的文件变量
const existingIndex = nodeConfig.value.fileVariables?.findIndex(f => f.variableName === variable.name)
if (existingIndex !== undefined && existingIndex >= 0) {
- ElMessage.warning(`文件变量 ${variable.name} 已存在,无需重复添加`)
+ ElMessage.warning(t('flow.file_variable_exists', { name: variable.name }))
return
}
@@ -272,7 +272,7 @@ const handleFileVariableInserted = (variable: any) => {
// 如果传入的是字符串变量名(向后兼容)
else if (typeof variable === 'string') {
// 这里需要根据变量名查找变量类型,暂时跳过
- console.log('收到字符串变量名:', variable)
+ console.log('Received string variable name:', variable)
}
}
@@ -309,7 +309,7 @@ const removeFileVariable = (index: number) => {
// 格式化变量显示
const formatVariableDisplay = (variableName: string) => {
- return `变量: {{${variableName}}}`
+ return t('flow.variable_format', { name: variableName })
}
const closeDrawer = () => {
@@ -319,7 +319,7 @@ const closeDrawer = () => {
const saveNode = () => {
// 验证必填字段
if (!nodeConfig.value.name.trim()) {
- ElMessage.error('请输入节点名称')
+ ElMessage.error(t('flow.node_config.node_name_required'))
return
}
diff --git a/src/views/createapp/components/workFlowConfig/EnvironmentVariableDrawer.vue b/src/views/createapp/components/workFlowConfig/EnvironmentVariableDrawer.vue
index 3f614702..370a5dc4 100644
--- a/src/views/createapp/components/workFlowConfig/EnvironmentVariableDrawer.vue
+++ b/src/views/createapp/components/workFlowConfig/EnvironmentVariableDrawer.vue
@@ -16,7 +16,7 @@
-
+
@@ -25,13 +25,13 @@
- 环境变量与当前工作流绑定,在流程运行期间只能读取,不能修改。适用于存储配置信息、密钥、常量等。
+ {{ $t('flow.env_description_content') }}
@@ -39,14 +39,14 @@
@@ -80,8 +80,8 @@
-
暂无环境变量
-
点击"添加变量"按钮创建你的第一个环境变量
+
{{ $t('flow.no_env_variables') }}
+
{{ $t('flow.create_first_env_variable') }}
@@ -90,7 +90,7 @@
@@ -98,7 +98,7 @@
@@ -108,39 +108,39 @@
:rules="variableRules"
ref="variableFormRef"
>
-
+
-
-
-
-
-
-
+
+
+
+
+
+
-
+
@@ -150,33 +150,33 @@
v-model="editingVariable.valueJson"
type="textarea"
:rows="4"
- placeholder="请输入JSON格式的对象"
+ :placeholder="$t('flow.input_json_placeholder')"
/>
-
+
@@ -237,14 +237,14 @@ const variableFormRef = ref()
// 表单验证规则
const variableRules = {
name: [
- { required: true, message: '请输入变量名', trigger: 'blur' },
- { pattern: /^[a-zA-Z_][a-zA-Z0-9_]*$/, message: '变量名只能包含字母、数字和下划线,且不能以数字开头', trigger: 'blur' }
+ { required: true, message: t('flow.variable_name_required'), trigger: 'blur' },
+ { pattern: /^[a-zA-Z_][a-zA-Z0-9_]*$/, message: t('flow.variable_name_pattern'), trigger: 'blur' }
],
var_type: [
- { required: true, message: '请选择变量类型', trigger: 'change' }
+ { required: true, message: t('flow.variable_type_required'), trigger: 'change' }
],
value: [
- { required: true, message: '请输入变量值', trigger: 'blur' }
+ { required: true, message: t('flow.variable_value_required'), trigger: 'blur' }
]
}
@@ -268,7 +268,7 @@ const getVariableTypeDisplay = (type: string): string => {
// 格式化变量值显示
const formatVariableValue = (variable: Variable): string => {
if (variable.value === null || variable.value === undefined) {
- return '未设置'
+ return t('flow.not_set')
}
switch (variable.var_type) {
@@ -287,7 +287,7 @@ const formatVariableValue = (variable: Variable): string => {
return '{ ... }'
}
case 'secret':
- return '****** (隐藏)'
+ return '****** (' + t('flow.hidden') + ')'
default:
const defaultValue = String(variable.value)
return defaultValue.length > 50 ? `${defaultValue.substring(0, 50)}...` : defaultValue
@@ -309,7 +309,7 @@ const getValueClass = (type: string): string => {
// 加载环境变量列表
const loadEnvironmentVariables = async () => {
if (!props.flowId) {
- console.warn('没有flowId,跳过环境变量加载')
+ console.warn('No flowId, skipping environment variable loading')
return
}
@@ -331,8 +331,8 @@ const loadEnvironmentVariables = async () => {
environmentVariables.value = variables || []
} catch (error) {
- console.error('❌ 加载环境变量失败:', error)
- ElMessage.error('加载环境变量失败')
+ console.error('❌ Loading environment variables failed:', error)
+ ElMessage.error(t('flow.load_env_variables_failed'))
environmentVariables.value = []
} finally {
variablesLoading.value = false
@@ -375,7 +375,7 @@ const saveEnvironmentVariable = async () => {
try {
variableData.value = JSON.parse(variableData.valueJson || '{}')
} catch (error) {
- ElMessage.error('JSON格式不正确,请检查输入')
+ ElMessage.error(t('flow.json_format_error'))
return
}
} else if (variableData.var_type === 'boolean') {
@@ -397,22 +397,22 @@ const saveEnvironmentVariable = async () => {
},
variableData
)
- ElMessage.success('环境变量更新成功')
+ ElMessage.success(t('flow.env_variable_update_success'))
} else {
// 创建变量
await createVariable({
...variableData,
flow_id: props.flowId
})
- ElMessage.success('环境变量创建成功')
+ ElMessage.success(t('flow.env_variable_create_success'))
}
showVariableDialog.value = false
await loadEnvironmentVariables()
} catch (error) {
- console.error('保存环境变量失败:', error)
- ElMessage.error(isEditingVariable.value ? '更新环境变量失败' : '创建环境变量失败')
+ console.error('Save environment variable failed:', error)
+ ElMessage.error(isEditingVariable.value ? t('flow.env_variable_update_failed') : t('flow.env_variable_create_failed'))
}
}
@@ -420,11 +420,11 @@ const saveEnvironmentVariable = async () => {
const deleteEnvironmentVariable = async (variable: Variable) => {
try {
await ElMessageBox.confirm(
- `确定要删除环境变量"${variable.name}"吗?此操作不可恢复。`,
- '确认删除',
+ t('flow.confirm_delete_env_variable', { name: variable.name }),
+ t('flow.confirm_delete_title'),
{
- confirmButtonText: '确定',
- cancelButtonText: '取消',
+ confirmButtonText: t('common.confirm'),
+ cancelButtonText: t('common.cancel'),
type: 'warning',
}
)
@@ -435,14 +435,14 @@ const deleteEnvironmentVariable = async (variable: Variable) => {
flow_id: props.flowId
})
- ElMessage.success('环境变量删除成功')
+ ElMessage.success(t('flow.env_variable_delete_success'))
showVariableDialog.value = false
await loadEnvironmentVariables()
} catch (error) {
if (error !== 'cancel') {
- console.error('删除环境变量失败:', error)
- ElMessage.error('删除环境变量失败')
+ console.error('Delete environment variable failed:', error)
+ ElMessage.error(t('flow.env_variable_delete_failed'))
}
}
}
@@ -467,7 +467,7 @@ const closeDrawer = () => {
}
onMounted(() => {
- console.log('🚀 EnvironmentVariableDrawer 已挂载')
+ console.log('🚀 EnvironmentVariableDrawer mounted')
nextTick(() => {
loadEnvironmentVariables()
})
diff --git a/src/views/createapp/components/workFlowConfig/FileExtractorDrawer.vue b/src/views/createapp/components/workFlowConfig/FileExtractorDrawer.vue
index b47cb5dc..5a0d87af 100644
--- a/src/views/createapp/components/workFlowConfig/FileExtractorDrawer.vue
+++ b/src/views/createapp/components/workFlowConfig/FileExtractorDrawer.vue
@@ -2,40 +2,40 @@
@@ -2701,12 +2983,13 @@ export default {
@click="handleSubCanvasClick"
@dblclick="handleSubCanvasClick"
@wheel="handleSubCanvasWheel"
+ @contextmenu="handleSubCanvasContextMenu"
>
-
+
-
-
@@ -222,14 +225,14 @@ watch(
@@ -272,7 +275,7 @@ watch(
}
&.node-selected .nodeContainer {
- border-color: #409eff;
+ border-color: #409eff;
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
&:hover {
@@ -568,46 +571,25 @@ watch(
-// 深色主题支持 - 使用用户指定的颜色规范
+// 深色主题支持 - 使用与其他Node一致的样式规范
.dark {
- .variable-assign-border {
- background: #26262a !important;
- border: 2px solid rgba(255, 255, 255, 0.08) !important;
-
- &:hover {
- border-color: #3182ce;
+ .customNodeStyle {
+ .nodeContainer {
+ background: #353f58 !important;
+ border: 2px solid rgba(255, 255, 255, 0.08) !important;
+
+ &:hover {
+ border-color: #3182ce;
+ }
}
- &.node-selected {
+ &.node-selected .nodeContainer {
border-color: #3182ce;
box-shadow: 0 0 0 2px rgba(49, 130, 206, 0.2);
}
- &.running {
- border-color: #3182ce;
- background: linear-gradient(135deg, #1a365d 0%, #2c5282 100%);
- }
-
- &.success {
- border-color: #68d391;
- background: linear-gradient(135deg, #1a202c 0%, #2d3748 100%);
- }
-
- &.error {
- border-color: #fc8181;
- background: linear-gradient(135deg, #2d1b1b 0%, #3d2626 100%);
- }
- }
-
- .node-content {
- .node-header {
- .node-icon {
- color: #63b3ed;
- }
-
- .node-title {
- color: #ffffff !important;
- }
+ .label {
+ color: #ffffff !important;
}
.operations-list {
@@ -633,6 +615,15 @@ watch(
color: #718096;
}
}
+
+ .nodeFooter {
+ background: rgba(45, 55, 72, 0.8);
+ border-top-color: rgba(255, 255, 255, 0.1);
+
+ .nodeIdText {
+ color: #a0aec0;
+ }
+ }
}
.vue-flow__handle {
@@ -657,5 +648,20 @@ watch(
}
}
}
+
+ .deleteButton {
+ background-color: #e53e3e;
+ color: #ffffff;
+ box-shadow: 0 4px 12px rgba(229, 62, 62, 0.4);
+
+ &:hover {
+ background-color: #e53e3e;
+ box-shadow: 0 6px 20px rgba(229, 62, 62, 0.5);
+ }
+
+ &:active {
+ background-color: #c53030;
+ }
+ }
}
diff --git a/src/views/createapp/components/workFlowConfig/VariableAssignNodeDrawer.vue b/src/views/createapp/components/workFlowConfig/VariableAssignNodeDrawer.vue
index b9296c73..570f5d50 100644
--- a/src/views/createapp/components/workFlowConfig/VariableAssignNodeDrawer.vue
+++ b/src/views/createapp/components/workFlowConfig/VariableAssignNodeDrawer.vue
@@ -4,6 +4,7 @@ import { ElDrawer, ElButton, ElInput, ElForm, ElFormItem, ElMessage } from 'elem
import { Plus } from '@element-plus/icons-vue';
import { v4 as uuidv4 } from 'uuid';
import VariableAssignCard from './VariableAssignCard.vue';
+import i18n from '@/i18n';
// 类型定义
interface VariableOperation {
@@ -59,7 +60,7 @@ const localNodeData = ref
({
// 表单验证规则
const rules = {
name: [
- { required: true, message: '请输入节点名称', trigger: 'blur' }
+ { required: true, message: i18n.global.t('flow.node_config.node_name_placeholder'), trigger: 'blur' }
]
};
@@ -79,7 +80,7 @@ watch(
([visible, nodeData]) => {
if (visible && nodeData && typeof nodeData === 'object') {
localNodeData.value = {
- name: nodeData.name || '变量赋值',
+ name: nodeData.name || i18n.global.t('flow.node_names.variable_assign'),
description: nodeData.description || '',
callId: nodeData.callId || 'VariableAssign',
parameters: {
@@ -113,7 +114,7 @@ const addOperation = () => {
// 删除操作
const removeOperation = (operationIndex: number) => {
if (operations.value.length <= 1) {
- ElMessage.warning('至少需要保留一个变量操作');
+ ElMessage.warning(i18n.global.t('flow.node_config.at_least_one_operation'));
return;
}
@@ -129,7 +130,7 @@ const updateOperation = (operationIndex: number, updatedOperation: VariableOpera
const validateData = (): boolean => {
// 检查节点名称
if (!localNodeData.value.name.trim()) {
- ElMessage.error('请输入节点名称');
+ ElMessage.error(i18n.global.t('flow.node_config.node_name_placeholder'));
return false;
}
@@ -138,19 +139,19 @@ const validateData = (): boolean => {
const operation = operations.value[i];
if (!operation.variable_name.trim()) {
- ElMessage.error(`第 ${i + 1} 个操作:请选择变量`);
+ ElMessage.error(i18n.global.t('flow.node_config.operation_select_variable', { index: i + 1 }));
return false;
}
if (!operation.operation) {
- ElMessage.error(`第 ${i + 1} 个操作:请选择操作类型`);
+ ElMessage.error(i18n.global.t('flow.node_config.operation_select_type', { index: i + 1 }));
return false;
}
// 检查需要值的操作是否提供了值
const operationsWithoutValue = ['clear', 'sqrt', 'pop_first', 'pop_last'];
if (!operationsWithoutValue.includes(operation.operation) && !operation.value) {
- ElMessage.error(`第 ${i + 1} 个操作:请输入操作值`);
+ ElMessage.error(i18n.global.t('flow.node_config.operation_input_value', { index: i + 1 }));
return false;
}
}
@@ -201,7 +202,7 @@ const conversationId = computed(() => {
@@ -213,20 +214,20 @@ const conversationId = computed(() => {
label-width="80px"
class="node-form"
>
-
+
-
+
@@ -235,14 +236,14 @@ const conversationId = computed(() => {
@@ -266,8 +267,8 @@ const conversationId = computed(() => {
diff --git a/src/views/createapp/components/workFlowConfig/VariableBasedStartNodeDrawer.vue b/src/views/createapp/components/workFlowConfig/VariableBasedStartNodeDrawer.vue
index 2a7eed44..26e155cd 100644
--- a/src/views/createapp/components/workFlowConfig/VariableBasedStartNodeDrawer.vue
+++ b/src/views/createapp/components/workFlowConfig/VariableBasedStartNodeDrawer.vue
@@ -13,7 +13,7 @@
-
+
@@ -22,7 +22,7 @@
- 开始节点
+ {{ $t('flow.node_names.start') }}
{{ nodeDescription }}
@@ -31,7 +31,7 @@
v-else
v-model="nodeDescription"
type="textarea"
- placeholder="开始节点"
+ :placeholder="$t('flow.node_names.start')"
:rows="3"
maxlength="200"
show-word-limit
@@ -45,15 +45,15 @@
@@ -121,44 +121,44 @@
-
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
+
@@ -167,7 +167,7 @@
-
文档
+
{{ $t('startNodeVariableManager.document_category') }}
TXT, MD, MDX, MARKDOWN, PDF, HTML, XLSX, XLS, DOC, DOCX, CSV, EML, MSG, PPTX, PPT, XML, EPUB
@@ -180,7 +180,7 @@
-
图片
+
{{ $t('startNodeVariableManager.image_category') }}
JPG, JPEG, PNG, GIF, WEBP, SVG
@@ -193,7 +193,7 @@
-
音频
+
{{ $t('startNodeVariableManager.audio_category') }}
MP3, M4A, WAV, AMR, MPGA
@@ -206,7 +206,7 @@
-
视频
+
{{ $t('startNodeVariableManager.video_category') }}
MP4, MOV, MPEG, WEBM
@@ -219,11 +219,11 @@
-
其他文件类型
+
{{ $t('startNodeVariableManager.other_file_types') }}
@@ -234,27 +234,27 @@
-
上传文件类型
+
{{ $t('startNodeVariableManager.upload_file_types') }}
- 本地上传
+ {{ $t('startNodeVariableManager.local_upload') }}
- URL上传
+ {{ $t('startNodeVariableManager.url_upload') }}
-
文件上传限制
+
{{ $t('startNodeVariableManager.file_upload_limits') }}
-
+
- 文件类型固定为1个文件
+ {{ $t('startNodeVariableManager.file_type_fixed') }}
-
+
- MB
+ {{ $t('startNodeVariableManager.mb_unit') }}
-
+
- 选中后,用户在对话时必须上传文件
+ {{ $t('startNodeVariableManager.required_file_note') }}
-
+
@@ -312,7 +312,7 @@
@@ -323,7 +323,7 @@
v-else-if="editingVariable.var_type === 'secret'"
v-model="editingVariable.value"
type="password"
- placeholder="请输入密钥值"
+ :placeholder="$t('startNodeVariableManager.enter_secret_value')"
show-password
/>
@@ -333,14 +333,14 @@
v-model="editingVariable.valueJson"
type="textarea"
:rows="4"
- placeholder="请输入JSON格式的对象值"
+ :placeholder="$t('startNodeVariableManager.enter_json_object')"
/>
@@ -348,7 +348,7 @@
@@ -356,7 +356,7 @@
@@ -364,7 +364,7 @@
@@ -372,7 +372,7 @@
- 文件列表类型变量将在对话时由用户上传,默认为空数组
+ {{ $t('startNodeVariableManager.file_array_tip') }}
@@ -380,7 +380,7 @@
@@ -388,7 +388,7 @@
@@ -396,36 +396,36 @@
-
+
@@ -506,11 +506,11 @@ const variableFormRef = ref()
// 表单验证规则
const variableFormRules = {
name: [
- { required: true, message: '请输入变量名称', trigger: 'blur' },
- { pattern: /^[a-zA-Z_][a-zA-Z0-9_]*$/, message: '变量名只能包含字母、数字和下划线,且必须以字母或下划线开头', trigger: 'blur' }
+ { required: true, message: t('startNodeVariableManager.enter_variable_name_validation'), trigger: 'blur' },
+ { pattern: /^[a-zA-Z_][a-zA-Z0-9_]*$/, message: t('startNodeVariableManager.variable_name_pattern_validation'), trigger: 'blur' }
],
var_type: [
- { required: true, message: '请选择变量类型', trigger: 'change' }
+ { required: true, message: t('startNodeVariableManager.select_variable_type_validation'), trigger: 'change' }
]
}
@@ -593,7 +593,7 @@ const loadAllVariables = async () => {
} catch (error) {
console.error('❌ 变量加载过程发生未知错误:', error)
- ElMessage.error('变量加载失败')
+ ElMessage.error(t('startNodeVariableManager.load_variables_failed'))
} finally {
variablesLoading.value = false
}
@@ -632,7 +632,7 @@ onUnmounted(() => {
// 获取变量显示值
const getVariableDisplayValue = (value: any): string => {
- if (value === null || value === undefined) return '(未设置)'
+ if (value === null || value === undefined) return t('startNodeVariableManager.not_set')
if (typeof value === 'object') return JSON.stringify(value)
return String(value)
}
@@ -704,9 +704,9 @@ const finishEditDesc = async () => {
description: nodeDescription.value
})
- ElMessage.success('描述保存成功')
+ ElMessage.success(t('startNodeVariableManager.description_save_success'))
} catch (error) {
- ElMessage.error('描述保存失败')
+ ElMessage.error(t('startNodeVariableManager.description_save_failed'))
}
}
@@ -835,22 +835,22 @@ const editConversationVariable = (variable: Variable) => {
const saveConversationVariable = async () => {
// 详细的参数验证
if (!editingVariable.value) {
- ElMessage.error('缺少变量数据')
+ ElMessage.error(t('startNodeVariableManager.missing_variable_data'))
return
}
if (!props.flowId) {
- ElMessage.error('缺少工作流ID (flowId),无法保存对话变量')
+ ElMessage.error(t('startNodeVariableManager.missing_flow_id'))
return
}
if (!editingVariable.value.name || !editingVariable.value.name.trim()) {
- ElMessage.error('变量名不能为空')
+ ElMessage.error(t('startNodeVariableManager.variable_name_empty'))
return
}
if (!editingVariable.value.var_type) {
- ElMessage.error('请选择变量类型')
+ ElMessage.error(t('startNodeVariableManager.select_variable_type_required'))
return
}
@@ -867,7 +867,7 @@ const saveConversationVariable = async () => {
if (editingVariable.value.value !== null && editingVariable.value.value !== undefined) {
value = Number(editingVariable.value.value)
if (isNaN(value)) {
- ElMessage.error('请输入有效的数字')
+ ElMessage.error(t('startNodeVariableManager.enter_valid_number'))
return
}
} else {
@@ -888,7 +888,7 @@ const saveConversationVariable = async () => {
try {
value = JSON.parse(editingVariable.value.valueJson)
} catch (error) {
- ElMessage.error('JSON格式不正确,请检查对象值的语法')
+ ElMessage.error(t('startNodeVariableManager.json_format_incorrect'))
return
}
} else {
@@ -959,11 +959,11 @@ const saveConversationVariable = async () => {
}
const updateResult = await updateVariable(updateParams, updateData)
- ElMessage.success('变量更新成功')
+ ElMessage.success(t('startNodeVariableManager.variable_update_success'))
} else {
// 创建变量
const createResult = await createVariable(variableData)
- ElMessage.success('变量创建成功')
+ ElMessage.success(t('startNodeVariableManager.variable_create_success'))
}
handleVariableDialogClose()
@@ -1020,7 +1020,7 @@ const deleteConversationVariable = async () => {
flow_id: props.flowId
})
- ElMessage.success('变量删除成功')
+ ElMessage.success(t('startNodeVariableManager.variable_delete_success'))
// 在关闭对话框前先保存变量名(避免引用失效)
const deletedVariableName = editingVariable.value.name
@@ -1039,7 +1039,7 @@ const deleteConversationVariable = async () => {
emits('variablesUpdated')
} catch (error) {
console.error('❌ 删除变量失败:', error)
- ElMessage.error('删除变量失败')
+ ElMessage.error(t('startNodeVariableManager.delete_variable_failed'))
}
}
@@ -1076,7 +1076,7 @@ const saveStartNodeConfig = () => {
}
emits('saveStartNode', nodeParams, props.nodeYamlId, nodeName.value, nodeDescription.value)
- ElMessage.success('保存成功')
+ ElMessage.success(t('startNodeVariableManager.save_success'))
closeDrawer()
}
@@ -1244,11 +1244,16 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
padding: 16px 24px;
border-bottom: 1px solid var(--o-border-color-light);
margin-bottom: 0;
+ background: var(--el-bg-color);
}
.el-drawer__body {
padding: 0;
+ background: var(--el-bg-color);
}
+
+ // 深色主题适配
+ background: var(--el-bg-color);
}
.drawerHeader {
@@ -1268,12 +1273,18 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
.headerText {
font-size: 16px;
font-weight: 600;
- color: var(--o-text-color-primary);
+ color: var(--el-text-color-primary);
+
+ // 深色主题下确保文字可读
+ body[theme='dark'] & {
+ color: #e4e8ee;
+ }
}
}
.drawerBody {
padding: 0;
+ background: var(--el-bg-color);
.descriptionSection {
margin: 20px 24px;
@@ -1287,11 +1298,22 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
text-align: center;
font-size: 14px;
transition: all 0.2s;
+ background: var(--el-fill-color-extra-light);
+
+ body[theme='dark'] & {
+ background: var(--flow-bg-color, #343a43);
+ border-color: var(--el-border-color);
+ }
&:hover {
border-color: var(--el-color-primary);
color: var(--el-color-primary);
background: var(--el-color-primary-light-9);
+
+ body[theme='dark'] & {
+ background: var(--flow-node-default-over-color, #25303e);
+ border-color: var(--flow-node-boder-default-over, #314265);
+ }
}
}
@@ -1304,24 +1326,51 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
font-size: 14px;
line-height: 1.4;
transition: all 0.2s;
+ color: var(--el-text-color-primary);
+
+ body[theme='dark'] & {
+ background: var(--flow-bg-color, #343a43);
+ border-color: var(--el-border-color);
+ color: #e4e8ee;
+ }
&:hover {
border-color: var(--el-color-primary);
background: var(--el-color-primary-light-9);
+
+ body[theme='dark'] & {
+ background: var(--flow-node-default-over-color, #25303e);
+ border-color: var(--flow-node-boder-default-over, #314265);
+ }
}
}
.descInput {
margin-top: 8px;
+
+ body[theme='dark'] & {
+ :deep(.el-textarea__inner) {
+ background: var(--flow-bg-color, #343a43) !important;
+ border-color: var(--el-border-color) !important;
+ color: #e4e8ee !important;
+
+ &::placeholder {
+ color: var(--el-text-color-placeholder) !important;
+ }
+ }
+ }
}
}
.tabContainer {
+ background: var(--el-bg-color);
+
.tabHeader {
display: flex;
border-bottom: 1px solid var(--el-border-color-light);
padding: 0 24px;
margin-bottom: 20px;
+ background: var(--el-bg-color);
.tabItem {
padding: 14px 16px;
@@ -1345,6 +1394,7 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
.inputFieldsSection {
padding: 0 24px 24px;
+ background: var(--el-bg-color);
.inputFieldsHeader {
display: flex;
@@ -1359,6 +1409,10 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
font-weight: 600;
color: var(--el-text-color-primary);
margin-bottom: 6px;
+
+ body[theme='dark'] & {
+ color: #e4e8ee;
+ }
}
.inputFieldsHint {
@@ -1384,16 +1438,22 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
color: var(--el-color-primary);
background: var(--el-color-primary-light-9);
transform: scale(1.1);
+
+ body[theme='dark'] & {
+ background: var(--flow-node-default-over-color, #25303e);
+ }
}
&:active {
transform: scale(0.95);
}
+
}
}
.variableList {
min-height: 100px;
+ background: var(--el-bg-color);
.variableItem {
display: flex;
@@ -1405,18 +1465,34 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
background: var(--el-fill-color-extra-light);
transition: all 0.2s;
+ // 深色主题优化
+ body[theme='dark'] & {
+ background: var(--flow-bg-color, #343a43);
+ border-color: var(--el-border-color);
+ }
+
&.editable {
cursor: pointer;
&:hover {
background: var(--el-color-primary-light-9);
border-color: var(--el-color-primary-light-7);
+
+ body[theme='dark'] & {
+ background: var(--flow-node-default-over-color, #25303e);
+ border-color: var(--flow-node-boder-default-over, #314265);
+ }
}
}
&.readonly {
opacity: 0.8;
background: var(--el-fill-color-lighter);
+
+ body[theme='dark'] & {
+ background: var(--o-bash-bg, #2a2f37);
+ opacity: 0.7;
+ }
}
.variableIcon {
@@ -1438,6 +1514,10 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
font-family: 'Monaco', 'Consolas', monospace;
line-height: 1.4;
margin-bottom: 4px;
+
+ body[theme='dark'] & {
+ color: #e4e8ee;
+ }
}
.variableType {
@@ -1447,6 +1527,11 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
padding: 2px 6px;
border-radius: 4px;
display: inline-block;
+
+ body[theme='dark'] & {
+ background: var(--o-bash-bg, #2a2f37);
+ color: var(--el-text-color-secondary);
+ }
}
}
}
@@ -1455,6 +1540,7 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
text-align: center;
padding: 40px 20px;
color: var(--el-text-color-secondary);
+ background: var(--el-bg-color);
.emptyText {
font-size: 14px;
@@ -1472,7 +1558,8 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
justify-content: flex-end;
gap: 12px;
padding: 16px 24px;
- border-top: 1px solid var(--o-border-color-light);
+ border-top: 1px solid var(--el-border-color-light);
+ background: var(--el-bg-color);
}
// 透明遮罩样式
@@ -1544,9 +1631,19 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
transition: all 0.2s;
cursor: pointer;
+ body[theme='dark'] & {
+ background: var(--flow-bg-color, #343a43);
+ border-color: var(--el-border-color);
+ }
+
&:hover {
border-color: var(--el-color-primary-light-7);
background: var(--el-color-primary-light-9);
+
+ body[theme='dark'] & {
+ background: var(--flow-node-default-over-color, #25303e);
+ border-color: var(--flow-node-boder-default-over, #314265);
+ }
}
&:active {
@@ -1582,6 +1679,10 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
font-weight: 600;
color: var(--el-text-color-primary);
margin-bottom: 4px;
+
+ body[theme='dark'] & {
+ color: #e4e8ee;
+ }
}
.category-types {
@@ -1595,6 +1696,10 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
.el-input {
font-size: 12px;
+
+ :deep(.el-input__wrapper) {
+ background: var(--el-bg-color);
+ }
}
}
}
@@ -1611,6 +1716,10 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
font-weight: 600;
color: var(--el-text-color-primary);
margin-bottom: 12px;
+
+ body[theme='dark'] & {
+ color: #e4e8ee;
+ }
}
.upload-method-tabs {
@@ -1626,7 +1735,12 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
cursor: pointer;
font-size: 13px;
transition: all 0.2s;
- background: white;
+ background: var(--el-bg-color);
+ color: var(--el-text-color-primary);
+
+ body[theme='dark'] & {
+ color: #e4e8ee;
+ }
&.active {
border-color: var(--el-color-primary);
@@ -1637,6 +1751,11 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
&:hover:not(.active) {
border-color: var(--el-color-primary-light-7);
background: var(--el-color-primary-light-9);
+
+ body[theme='dark'] & {
+ background: var(--flow-node-default-over-color, #25303e);
+ border-color: var(--flow-node-boder-default-over, #314265);
+ }
}
}
}
@@ -1649,6 +1768,10 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
font-weight: 600;
color: var(--el-text-color-primary);
margin-bottom: 8px;
+
+ body[theme='dark'] & {
+ color: #e4e8ee;
+ }
}
.upload-limit-item {
@@ -1662,6 +1785,10 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
color: var(--el-text-color-primary);
font-weight: 500;
min-width: 120px;
+
+ body[theme='dark'] & {
+ color: #e4e8ee;
+ }
}
.unit-label {
@@ -1696,6 +1823,11 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
margin-bottom: 12px;
color: var(--el-text-color-secondary);
font-size: 13px;
+
+ body[theme='dark'] & {
+ background: var(--o-bash-bg, #2a2f37);
+ border-color: var(--el-border-color);
+ }
}
}
@@ -1712,9 +1844,12 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
margin-bottom: 12px;
color: var(--el-text-color-secondary);
font-size: 13px;
+
+ body[theme='dark'] & {
+ background: var(--o-bash-bg, #2a2f37);
+ border-color: var(--el-border-color);
+ }
}
-
-
}
// 数组输入区域
@@ -1730,15 +1865,32 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
margin-bottom: 12px;
color: var(--el-text-color-secondary);
font-size: 13px;
+
+ body[theme='dark'] & {
+ background: var(--o-bash-bg, #2a2f37);
+ border-color: var(--el-border-color);
+ }
}
}
// 变量对话框样式增强
:deep(.el-dialog) {
+ background: var(--el-bg-color);
+
+ .el-dialog__header {
+ background: var(--el-bg-color);
+ border-bottom: 1px solid var(--el-border-color-light);
+
+ .el-dialog__title {
+ color: var(--el-text-color-primary);
+ }
+ }
+
.el-dialog__body {
padding: 20px 24px;
max-height: 70vh;
overflow-y: auto;
+ background: var(--el-bg-color);
}
.el-form-item {
@@ -1747,11 +1899,16 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
.el-form-item__label {
font-weight: 600;
color: var(--el-text-color-primary);
+
+ body[theme='dark'] & {
+ color: #e4e8ee !important;
+ }
}
.el-form-item__content {
.el-input__wrapper {
transition: all 0.2s;
+ background: var(--el-bg-color);
&:hover {
box-shadow: 0 0 0 1px var(--el-color-primary-light-7);
@@ -1760,15 +1917,26 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
.el-select {
width: 100%;
+
+ .el-select__wrapper {
+ background: var(--el-bg-color);
+ }
}
.el-textarea__inner {
transition: all 0.2s;
+ background: var(--el-bg-color);
&:hover {
border-color: var(--el-color-primary-light-7);
}
}
+
+ .el-input-number {
+ .el-input__wrapper {
+ background: var(--el-bg-color);
+ }
+ }
}
}
@@ -1776,10 +1944,16 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
.el-button {
border-style: dashed;
transition: all 0.2s;
+ background: var(--el-bg-color);
&:hover {
border-color: var(--el-color-primary);
color: var(--el-color-primary);
+ background: var(--el-color-primary-light-9);
+
+ body[theme='dark'] & {
+ background: var(--flow-node-default-over-color, #25303e);
+ }
}
}
}
@@ -1789,18 +1963,22 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
.variable-dialog {
:deep(.el-dialog) {
max-height: 90vh;
+ background: var(--el-bg-color);
.el-dialog__header {
border-bottom: 1px solid var(--el-border-color-light);
+ background: var(--el-bg-color);
}
.el-dialog__body {
max-height: 70vh;
overflow-y: auto;
+ background: var(--el-bg-color);
}
.el-dialog__footer {
border-top: 1px solid var(--el-border-color-light);
+ background: var(--el-bg-color);
}
}
}
@@ -1814,6 +1992,11 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
padding: 16px;
background: var(--el-fill-color-extra-light);
+ body[theme='dark'] & {
+ background: var(--flow-bg-color, #343a43);
+ border-color: var(--el-border-color);
+ }
+
// 自定义滚动条样式
&::-webkit-scrollbar {
width: 6px;
@@ -1822,10 +2005,14 @@ const toggleUploadMethod = (method: 'manual' | 'url') => {
&::-webkit-scrollbar-track {
background: var(--el-fill-color-light);
border-radius: 3px;
+
+ body[theme='dark'] & {
+ background: var(--o-bash-bg, #2a2f37);
+ }
}
&::-webkit-scrollbar-thumb {
- background: var(--el-border-color);
+ background: var(--o-scrollbar-thumb, var(--el-border-color));
border-radius: 3px;
&:hover {
diff --git a/src/views/createapp/components/workFlowConfig/insertNodeMenu.vue b/src/views/createapp/components/workFlowConfig/insertNodeMenu.vue
index 76555e1d..ca75e658 100644
--- a/src/views/createapp/components/workFlowConfig/insertNodeMenu.vue
+++ b/src/views/createapp/components/workFlowConfig/insertNodeMenu.vue
@@ -12,54 +12,30 @@
@click.stop
>
-
-
-
+
+
+
\ No newline at end of file
diff --git a/src/views/createapp/components/workFlowConfig/useDnD.js b/src/views/createapp/components/workFlowConfig/useDnD.js
index f097b5f0..c4d80be8 100644
--- a/src/views/createapp/components/workFlowConfig/useDnD.js
+++ b/src/views/createapp/components/workFlowConfig/useDnD.js
@@ -255,13 +255,28 @@ function createNewNode(nodeMetaData, position, customNodeId = null) {
const nodeId = customNodeId || getId();
const cleanNodeData = sanitizeNodeData(nodeMetaData, nodeId);
+ // 确定节点类型
+ let nodeType = 'custom'; // 默认类型
+ if (nodeMetaData.type === 'plugin-node') {
+ nodeType = 'plugin-node';
+ } else if (nodeMetaData.callId === 'Choice') {
+ nodeType = 'Choice';
+ } else if (nodeMetaData.callId === 'Loop') {
+ nodeType = 'Loop';
+ } else if (nodeMetaData.callId === 'VariableAssign') {
+ nodeType = 'VariableAssign';
+ }
+
return {
id: nodeId,
- type: nodeMetaData.callId === 'Choice' ? 'Choice' :
- nodeMetaData.callId === 'Loop' ? 'Loop' :
- nodeMetaData.callId === 'VariableAssign' ? 'VariableAssign' : 'custom',
+ type: nodeType,
position,
- data: {
+ data: nodeMetaData.type === 'plugin-node' ? {
+ // 插件节点的完整数据结构
+ ...nodeMetaData.data,
+ nodeId: nodeId
+ } : {
+ // 常规节点的数据结构
name: cleanNodeData.name,
description: cleanNodeData.description,
nodeId: cleanNodeData.nodeId,
diff --git a/src/views/dialogue/components/AppInitalPreview.vue b/src/views/dialogue/components/AppInitalPreview.vue
index 326de5ed..c674c5b6 100644
--- a/src/views/dialogue/components/AppInitalPreview.vue
+++ b/src/views/dialogue/components/AppInitalPreview.vue
@@ -61,7 +61,7 @@ watch(
background-color: var(--o-bg-color-base);
border-radius: 8px;
bottom: 0px;
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+ box-shadow: var(--o-shadow-base);
margin: 12px 88px;
}
@@ -77,10 +77,10 @@ watch(
float: right;
text-align: center;
margin-right: 98px;
- color: #8d98aa;
+ color: var(--o-text-color-secondary);
.red-word {
- color: #e02020;
+ color: var(--o-color-danger);
}
}
diff --git a/src/views/dialogue/components/DialogueVariablePanel.vue b/src/views/dialogue/components/DialogueVariablePanel.vue
index c3f1e9c9..640fb884 100644
--- a/src/views/dialogue/components/DialogueVariablePanel.vue
+++ b/src/views/dialogue/components/DialogueVariablePanel.vue
@@ -1024,8 +1024,8 @@ watch(
+
+
diff --git a/src/views/settings/components/ModelCard.vue b/src/views/settings/components/ModelCard.vue
index 5957e900..043f5f82 100644
--- a/src/views/settings/components/ModelCard.vue
+++ b/src/views/settings/components/ModelCard.vue
@@ -1,5 +1,5 @@
@@ -36,7 +51,9 @@ const cardStyles = computed
(() => {
- {{ name }}
+
+ {{ name }}
+
@@ -85,6 +102,10 @@ const cardStyles = computed
(() => {
line-height: 24px;
font-weight: 700;
margin-left: 10px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ max-width: 200px;
}
}
}
diff --git a/src/views/settings/components/SystemModelSettings.vue b/src/views/settings/components/SystemModelSettings.vue
new file mode 100644
index 00000000..d90105c5
--- /dev/null
+++ b/src/views/settings/components/SystemModelSettings.vue
@@ -0,0 +1,475 @@
+
+
+
+
+
+
+
+
+
{{ t('settings.reasoning_model_preference') }}
+
+
+
+
+
+
+
+
![model icon]()
+
+
+
+
+
+
+
+
![]()
+
+
+
{{ model.modelName }}
+
+
+
+
+
+
+
+
+
{{ t('settings.embedding_model_preference') }}
+
+
+
+
+
+
+
+
![model icon]()
+
+
+
+
+
+
+
+
![]()
+
+
+
{{ model.modelName }}
+
+
+
+
+
+
+
+
+
{{ t('settings.reranker_preference') }}
+
+
+
+
+
+
+
+
![model icon]()
+
+
+
+
+
+
+
+
![]()
+
+
+
{{ model.modelName }}
+
+
+
+
+
+
+
+
+ {{ t('settings.chain_of_thought_preference') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/styles/workFlowArrange.scss b/src/views/styles/workFlowArrange.scss
index 2afcee7e..3406c0ae 100644
--- a/src/views/styles/workFlowArrange.scss
+++ b/src/views/styles/workFlowArrange.scss
@@ -383,7 +383,6 @@
align-items: center;
}
.label {
- max-width: 64px !important;
flex: 1;
height: 24px;
line-height: 24px;
@@ -672,7 +671,7 @@
// 深色主题变量 - 使用用户指定的颜色
[data-theme="dark"], .dark {
- --flow-node-bg: #26262a;
+ --flow-node-bg: #353f58;
--flow-node-border: rgba(255, 255, 255, 0.08);
--flow-node-border-selected: #63b3ed;
--flow-node-border-hover: rgba(255, 255, 255, 0.16);
--
Gitee
From 20fe9c08817cde9c74f4a92b2b95dea0c8b414fe Mon Sep 17 00:00:00 2001
From: Ethan-Zhang
Date: Thu, 21 Aug 2025 08:09:03 +0800
Subject: [PATCH 4/4] =?UTF-8?q?Fix:=20=E8=BF=98=E5=8E=9F=E9=80=9A=E7=94=A8?=
=?UTF-8?q?=E5=BC=80=E5=8F=91=E6=9C=8D=E5=8A=A1=E9=85=8D=E7=BD=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
vite.config.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/vite.config.ts b/vite.config.ts
index f6d8fef7..26b10af3 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -72,10 +72,10 @@ export default ({ mode }): UserConfigExport => {
},
server: {
- host: '10.211.55.10',
+ host: 'localhost',
hmr: true,
port: 8080,
- origin: 'http://10.211.55.10:8080',
+ origin: 'http://localhost:8080',
headers: {
'Access-Control-Allow-Origin': '*',
},
--
Gitee