From 3826fddb22d325843884da908d3e5e870dd84047 Mon Sep 17 00:00:00 2001 From: wangdan-fit2cloud Date: Fri, 4 Sep 2026 12:13:06 +0800 Subject: [PATCH] feat: markdown editor --- ui/src/components/COMPONENT_README.md | 22 ++- ui/src/components/codemirror-editor/Json.vue | 12 +- .../components/codemirror-editor/python.vue | 12 +- .../components/codemirror-editor/style.scss | 53 ++++++ .../global/markdown-editor/MdEditor.vue | 2 +- .../markdown-editor/MdEditorMagnify.vue | 13 +- .../global/markdown-editor/MdPreview.vue | 2 +- .../global/markdown-editor/config.ts | 2 +- .../global/markdown-editor/md-editor.scss | 168 +++++++++++++++++ .../global/markdown-editor/sup-popover.scss | 23 --- ui/src/styles/app.scss | 170 +++++++----------- ui/src/styles/element-plus.scss | 6 + ui/src/styles/variables.scss | 1 + .../tool/tool-store/ToolStoreDetailDrawer.vue | 4 +- ui/src/workflow-canvas/WORKFLOW_README.md | 4 + .../node-container/NodeConditionDropdown.vue | 5 +- .../node-container/NodeOperateDropdown.vue | 9 +- .../core/node-container/index.vue | 108 +++++++---- ui/src/workflow-canvas/core/shortcut.ts | 6 +- ui/src/workflow-canvas/core/workflow-node.ts | 43 +++-- .../nodes/ai-chat-node/index.vue | 14 +- .../workflow-canvas/nodes/base-node/index.vue | 19 +- .../nodes/condition-node/index.vue | 18 +- .../workflow-canvas/nodes/form-node/index.vue | 18 +- .../nodes/image-generate-node/index.vue | 22 ++- .../nodes/image-understand-node/index.vue | 28 ++- .../nodes/intent-node/index.vue | 34 ++-- .../component/ParametersFieldTable.vue | 12 +- .../nodes/parameter-extraction-node/index.vue | 18 +- .../nodes/question-node/index.vue | 26 ++- .../nodes/reply-node/index.vue | 8 +- .../nodes/speech-to-text-node/index.vue | 20 +-- .../nodes/text-to-speech-node/index.vue | 14 +- .../nodes/text-to-video-node/index.vue | 22 ++- .../nodes/variable-assign-node/index.vue | 12 +- ui/src/workflow-canvas/style.scss | 15 +- 36 files changed, 595 insertions(+), 370 deletions(-) create mode 100644 ui/src/components/codemirror-editor/style.scss create mode 100644 ui/src/components/global/markdown-editor/md-editor.scss delete mode 100644 ui/src/components/global/markdown-editor/sup-popover.scss diff --git a/ui/src/components/COMPONENT_README.md b/ui/src/components/COMPONENT_README.md index ba9e2e9ce6b..54190b48b46 100644 --- a/ui/src/components/COMPONENT_README.md +++ b/ui/src/components/COMPONENT_README.md @@ -52,7 +52,7 @@ src/components/ │ │ ├── MdEditor.vue # 支持多语言和自定义页脚的 Markdown 编辑器 │ │ ├── MdEditorMagnify.vue # 支持弹窗放大编辑的 Markdown 编辑器 │ │ ├── MdPreview.vue # 禁用代码折叠的 Markdown 预览器 -│ │ ├── sup-popover.scss # Markdown 上标说明悬浮层样式 +│ │ ├── md-editor.scss # Markdown 编辑器、预览区和上标说明浮层的共享样式 │ │ └── sup-popover.ts # Markdown 上标说明悬浮层交互 │ ├── mk-complex-search/ │ │ └── index.vue # 字段选择与输入或枚举条件组合搜索框 @@ -115,7 +115,8 @@ src/components/ │ └── LogoIcon.vue # 不带产品名称的图形 Logo,手动导入 ├── codemirror-editor/ │ ├── python.vue # 内置 pylint 诊断和全屏编辑的 Python 编辑器 -│ └── Json.vue # 支持格式化、语法诊断和全屏编辑的 JSON 输入框 +│ ├── Json.vue # 支持格式化、语法诊断和全屏编辑的 JSON 输入框 +│ └── style.scss # Python 与 JSON 编辑器共享的 scoped 样式 └── mk-source-card/ │ ├── index.vue # 来源资源的统一卡片结构,手动导入 │ ├── mk-source-card-action.vue # 卡片悬浮操作容器 @@ -198,6 +199,18 @@ Element Plus 使用 `ElOnlyChild` 处理浮层触发器。`el-tooltip`、`el-pop 配置为本地实例,避免运行时加载 CDN 资源;`md-editor-v3` v6 的图标已随依赖打包,不再维护或加载 旧版 `markdown-iconfont.js`。 +编辑器、预览区和上标说明浮层的共享样式统一放在组件目录的 `md-editor.scss`,由 `config.ts` +引入。`MdEditor` 与 `MdPreview` 在底层组件根节点添加 `mk-markdown-editor`,编辑器内部样式 +仅在该范围生效;`MdEditorMagnify` 通过复用 `MdEditor` 继承样式。上标浮层由 `sup-popover.ts` +挂载到 `body`,使用独立的 `markdown-sup-popover` 类名,不依赖编辑器祖先或 Vue scoped 属性。 +组件专属样式不放入全局 `src/styles`;第三方基础 CSS 仍由全局 Sass 入口加载。 + +可编辑的 Markdown 输入框悬浮边框使用 `--el-input-hover-border-color`,编辑区获得焦点时 +使用 `--el-input-focus-border-color`,未提供这两个变量时分别回退到 Element Plus 的悬浮边框色 +和主题色。只读、禁用和独立预览不触发编辑边框状态。编辑器自带的滚动条统一使用 +`el-scrollbar` 的颜色变量、6px 宽度和 0.3/0.5 透明度,内容溢出时由编辑器控制显示,悬浮 +滑块时加深颜色;不再额外通过轨道透明度隐藏滚动条,保留原有滚动节点和拖动逻辑。 + ```vue @@ -700,6 +713,11 @@ import MkDragUpload from '@/components/mk-drag-upload/index.vue' ### PythonCodeEditor +Python 与 JSON 编辑器通过 ` diff --git a/ui/src/components/codemirror-editor/python.vue b/ui/src/components/codemirror-editor/python.vue index 7d674cf60a3..78db0c6c7eb 100644 --- a/ui/src/components/codemirror-editor/python.vue +++ b/ui/src/components/codemirror-editor/python.vue @@ -68,8 +68,8 @@ function submitEditorDialog() { - +
+ +
- + diff --git a/ui/src/components/codemirror-editor/style.scss b/ui/src/components/codemirror-editor/style.scss new file mode 100644 index 00000000000..adeaa6141cd --- /dev/null +++ b/ui/src/components/codemirror-editor/style.scss @@ -0,0 +1,53 @@ +/* CodeMirror 编辑器 */ +.mk-codemirror { + :deep(.cm-editor) { + --el-scrollbar-bg-color: var(--el-text-color-secondary); + --el-scrollbar-hover-bg-color: var(--el-text-color-secondary); + --el-scrollbar-hover-opacity: 0.5; + --el-scrollbar-opacity: 0.3; + border: var(--el-border); + border-radius: var(--el-border-radius-base); + overflow: hidden; + scrollbar-color: transparent transparent; + scrollbar-width: thin; + } + + :deep(.cm-editor .cm-gutters.cm-gutters-before) { + border: none; + } + + :deep(.cm-editor.cm-focused) { + outline: none !important; + } + + :deep(.cm-editor::-webkit-scrollbar) { + background-color: transparent; + height: 6px; + width: 6px; + } + + :deep(.cm-editor::-webkit-scrollbar-corner) { + background-color: transparent; + } + + :deep(.cm-editor::-webkit-scrollbar-thumb) { + background-color: transparent; + border-radius: var(--el-border-radius-base); + transition: background-color var(--el-transition-duration); + } + + :deep(.cm-editor:hover) { + scrollbar-color: color-mix(in srgb, var(--el-scrollbar-bg-color) calc(var(--el-scrollbar-opacity) * 100%), transparent) transparent; + } + + :deep(.cm-editor:hover::-webkit-scrollbar-thumb) { + background-color: var(--el-scrollbar-bg-color); + opacity: var(--el-scrollbar-opacity); + } + + // 滑块悬浮状态覆盖编辑器悬浮状态。 + :deep(.cm-editor::-webkit-scrollbar-thumb:hover) { + background-color: var(--el-scrollbar-hover-bg-color); + opacity: var(--el-scrollbar-hover-opacity); + } +} diff --git a/ui/src/components/global/markdown-editor/MdEditor.vue b/ui/src/components/global/markdown-editor/MdEditor.vue index 57d88c7fb35..6f9c06ccf77 100644 --- a/ui/src/components/global/markdown-editor/MdEditor.vue +++ b/ui/src/components/global/markdown-editor/MdEditor.vue @@ -18,7 +18,7 @@ const language = computed(() => { diff --git a/ui/src/workflow-canvas/style.scss b/ui/src/workflow-canvas/style.scss index 8c5edfe700e..004f9b34ada 100644 --- a/ui/src/workflow-canvas/style.scss +++ b/ui/src/workflow-canvas/style.scss @@ -8,6 +8,7 @@ cursor: pointer; } +/* edge */ // 连接线 .workflow-edge-delete-wrapper { overflow: visible; @@ -27,8 +28,9 @@ } } -// 连接节点按钮 +/* anchor */ +// 连接节点按钮 .workflow-node-anchor-wrapper { overflow: visible; } @@ -46,15 +48,18 @@ transition: transform 0.2s ease; background: var(--el-color-primary); &.is-connected { - background: white; + background: white !important; .workflow-node-add-icon { opacity: 0; } } &.is-connected.is-right:hover { - background: var(--el-color-primary); + background: var(--el-color-primary) !important; transform: scale(1.17); + &.is-abnormal { + background: var(--el-color-warning) !important; + } .workflow-node-add-icon { opacity: 1; @@ -63,6 +68,10 @@ &:not(.is-connected):hover { transform: scale(1.17); } + &.is-abnormal { + background: var(--el-color-warning); + border: 2px solid var(--el-color-warning); + } .workflow-node-add-icon { height: calc(var(--spacing) * 6);