diff --git a/ui/src/api/API_README.md b/ui/src/api/API_README.md index 22abb3cb4a7..d2d04f499a9 100644 --- a/ui/src/api/API_README.md +++ b/ui/src/api/API_README.md @@ -114,8 +114,9 @@ API 枚举与类型统一在 `src/api` 范围内管理,相关规则由本文 - 同一业务边界内的重复类型提取到最近共同目录的 `common.ts`;`common.ts` 不得成为无关类型 的集合。 - API 与 View 或 Component 使用同一业务类型时只保留一份声明,不得在两层分别定义。 -- 智能体详情及保存参数中的 `default_model_setting` 共用模型类别 `DefaultModelType` 和单项 - 配置 `ModelConfig`(`types/model.ts`),工作流页面及设置抽屉从 `@/api/types` 引用。 +- 智能体详情及保存参数中的 `default_model_setting` 使用 `DefaultModelSettingPayload`;该类型由 + `DefaultModelType` 和单项配置 `ModelConfig` 组合而成(`types/model.ts`),工作流页面及设置抽屉 + 从 `@/api/types` 引用。 - 名称相同但业务含义或字段约束不同的类型不要强行合并,应使用明确的领域名称区分。 - 使用 `interface` 描述对象结构,使用 `type` 描述联合类型、交叉类型、工具类型结果或别名。 - 类型名称必须体现业务含义,避免使用 `Data`、`Item`、`Info` 等脱离领域后含义不清的名称。 diff --git a/ui/src/api/admin/system/workspace.ts b/ui/src/api/admin/system/workspace.ts index 17bdbe8240d..bb902058cec 100644 --- a/ui/src/api/admin/system/workspace.ts +++ b/ui/src/api/admin/system/workspace.ts @@ -5,13 +5,11 @@ import type { CreateWorkspaceMemberPayload, Dict, WorkspaceItem, WorkspaceMember const prefix = '/system/workspace' /** 首页头部工作空间列表 | 系统管理的工作空间模块 */ -// TODO 工作空间管理员接口 /workspace 未区分 const getSystemWorkspaceList = () => { return get(prefix) } /** 获取工作空间成员列表 **/ -// TODO 工作空间管理员接口 /workspace 未区分 const getWorkspaceMemberList = (workspace_id: string, page: ParamsPage, query?: Dict) => { return get>(`${prefix}/${workspace_id}/user_list/${page.currentPage}/${page.pageSize}`, query) diff --git a/ui/src/api/types/application.ts b/ui/src/api/types/application.ts index 36e7f93549e..c044e8efedd 100644 --- a/ui/src/api/types/application.ts +++ b/ui/src/api/types/application.ts @@ -2,12 +2,12 @@ import type LogicFlow from '@logicflow/core' import { APPLICATION_TYPE } from '@/api/enums' -import type { DefaultModelType, ModelConfig } from './model' +import type { DefaultModelSettingPayload } from './model' export type ApplicationType = (typeof APPLICATION_TYPE)[keyof typeof APPLICATION_TYPE] export interface ApplicationDetail { - default_model_setting?: Partial> + default_model_setting?: DefaultModelSettingPayload create_time?: string desc?: string | null folder?: string @@ -29,7 +29,7 @@ export interface ApplicationDetail { } export interface ApplicationFormPayload { - default_model_setting?: ApplicationDetail['default_model_setting'] + default_model_setting?: DefaultModelSettingPayload name?: string desc?: string model_id?: string diff --git a/ui/src/api/types/common.ts b/ui/src/api/types/common.ts index 6b653445f4b..0b2dde2d5fe 100644 --- a/ui/src/api/types/common.ts +++ b/ui/src/api/types/common.ts @@ -25,3 +25,24 @@ export interface CommonUserOption { nick_name: string roles?: string[] } + + +export interface DynamicFormField { + attrs?: Record + default_value?: unknown + field: string + input_type: string + label: string | DynamicFormLabel + option_list?: Record[] + required?: boolean + text_field?: string + value_field?: string + [key: string]: unknown +} + +export interface DynamicFormLabel { + attrs?: { tooltip?: string; [key: string]: unknown } + input_type: string + label: string + type?: string +} diff --git a/ui/src/api/types/model.ts b/ui/src/api/types/model.ts index 7f1cc7f46e9..e70745725bd 100644 --- a/ui/src/api/types/model.ts +++ b/ui/src/api/types/model.ts @@ -2,6 +2,7 @@ import { MODEL_STATUS } from '@/api/enums' import type { Dict } from './common' +import type { DynamicFormField } from './common' export type ModelStatus = (typeof MODEL_STATUS)[keyof typeof MODEL_STATUS] @@ -13,6 +14,8 @@ export interface ModelConfig { model_params_setting?: Dict } +export type DefaultModelSettingPayload = Partial> + export interface ModelProviderItem { icon: string name: string @@ -49,26 +52,6 @@ export interface ModelPayload { provider: string } -export interface DynamicFormField { - attrs?: Record - default_value?: unknown - field: string - input_type: string - label: string | DynamicFormLabel - option_list?: Record[] - required?: boolean - text_field?: string - value_field?: string - [key: string]: unknown -} - -export interface DynamicFormLabel { - attrs?: { tooltip?: string; [key: string]: unknown } - input_type: string - label: string - type?: string -} - export interface BaseModelOption { desc?: string model_type: string diff --git a/ui/src/api/types/tool.ts b/ui/src/api/types/tool.ts index 118292d04b9..5ab5abaf58b 100644 --- a/ui/src/api/types/tool.ts +++ b/ui/src/api/types/tool.ts @@ -2,7 +2,7 @@ import type LogicFlow from '@logicflow/core' import { TOOL_SCOPE, TOOL_TYPE } from '@/api/enums' -import type { DynamicFormField } from './model' +import type { DynamicFormField } from './common' export type ToolScope = (typeof TOOL_SCOPE)[keyof typeof TOOL_SCOPE] export type ToolType = (typeof TOOL_TYPE)[keyof typeof TOOL_TYPE] diff --git a/ui/src/assets/iconfont.js b/ui/src/assets/iconfont.js index 4bc7c0607c9..2db31ad9298 100644 --- a/ui/src/assets/iconfont.js +++ b/ui/src/assets/iconfont.js @@ -1 +1 @@ -window._iconfont_svg_string_5200172='',(h=>{var a=(l=(l=document.getElementsByTagName("script"))[l.length-1]).getAttribute("data-injectcss"),l=l.getAttribute("data-disable-injectsvg");if(!l){var o,v,t,i,c,d=function(a,l){l.parentNode.insertBefore(a,l)};if(a&&!h.__iconfont__svg__cssinject__){h.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(a){console&&console.log(a)}}o=function(){var a,l=document.createElement("div");l.innerHTML=h._iconfont_svg_string_5200172,(l=l.getElementsByTagName("svg")[0])&&(l.setAttribute("aria-hidden","true"),l.style.position="absolute",l.style.width=0,l.style.height=0,l.style.overflow="hidden",l=l,(a=document.body).firstChild?d(l,a.firstChild):a.appendChild(l))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(o,0):(v=function(){document.removeEventListener("DOMContentLoaded",v,!1),o()},document.addEventListener("DOMContentLoaded",v,!1)):document.attachEvent&&(t=o,i=h.document,c=!1,m(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,e())})}function e(){c||(c=!0,t())}function m(){try{i.documentElement.doScroll("left")}catch(a){return void setTimeout(m,50)}e()}})(window); \ No newline at end of file +window._iconfont_svg_string_5200172='',(h=>{var a=(l=(l=document.getElementsByTagName("script"))[l.length-1]).getAttribute("data-injectcss"),l=l.getAttribute("data-disable-injectsvg");if(!l){var o,v,t,i,c,d=function(a,l){l.parentNode.insertBefore(a,l)};if(a&&!h.__iconfont__svg__cssinject__){h.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(a){console&&console.log(a)}}o=function(){var a,l=document.createElement("div");l.innerHTML=h._iconfont_svg_string_5200172,(l=l.getElementsByTagName("svg")[0])&&(l.setAttribute("aria-hidden","true"),l.style.position="absolute",l.style.width=0,l.style.height=0,l.style.overflow="hidden",l=l,(a=document.body).firstChild?d(l,a.firstChild):a.appendChild(l))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(o,0):(v=function(){document.removeEventListener("DOMContentLoaded",v,!1),o()},document.addEventListener("DOMContentLoaded",v,!1)):document.attachEvent&&(t=o,i=h.document,c=!1,m(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,e())})}function e(){c||(c=!0,t())}function m(){try{i.documentElement.doScroll("left")}catch(a){return void setTimeout(m,50)}e()}})(window); \ No newline at end of file diff --git a/ui/src/assets/workflow/icon_intent.svg b/ui/src/assets/workflow/icon_intent.svg new file mode 100644 index 00000000000..bd5b06b720c --- /dev/null +++ b/ui/src/assets/workflow/icon_intent.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/ui/src/components/COMPONENT_README.md b/ui/src/components/COMPONENT_README.md index da0a933fe72..b17e56c4fc2 100644 --- a/ui/src/components/COMPONENT_README.md +++ b/ui/src/components/COMPONENT_README.md @@ -171,6 +171,15 @@ import WorkspaceRelationTags from '@/components/business/workspace-relation-tags - 组件样式默认使用 `scoped`;明确的全局规则放入 `src/styles`。 - `global` 不创建仅用于二次导出的 `components/index.ts`。 +### 数字输入框 + +项目内所有设置 `controls-position="right"` 的 `el-input-number` 必须同时显式设置 +`align="left"`,统一将输入内容左对齐。页面、公共组件和工作流节点均遵循此规则。 + +```vue + +``` + ### 浮层触发节点 Element Plus 使用 `ElOnlyChild` 处理浮层触发器。`el-tooltip`、`el-popover`、 @@ -1069,7 +1078,6 @@ import FolderTree from '@/components/business/folder-tree/index.vue' 其他范围暂不展示创建入口。创建成功后触发 `refresh`,使用方重新加载原业务范围的模型选项, 不自动替换当前选中模型。`footer` 插槽仍可覆盖默认创建入口。 - ```vue - + diff --git a/ui/src/components/global/markdown-editor/MdPreview.vue b/ui/src/components/global/markdown-editor/MdPreview.vue index 0a2451cb145..a90b80139dd 100644 --- a/ui/src/components/global/markdown-editor/MdPreview.vue +++ b/ui/src/components/global/markdown-editor/MdPreview.vue @@ -17,9 +17,4 @@ const language = computed(() => { - + diff --git a/ui/src/components/mk-dynamics-form/constructor/items/PasswordInputConstructor.vue b/ui/src/components/mk-dynamics-form/constructor/items/PasswordInputConstructor.vue index 9f255f42d1f..9e1c7e541f0 100644 --- a/ui/src/components/mk-dynamics-form/constructor/items/PasswordInputConstructor.vue +++ b/ui/src/components/mk-dynamics-form/constructor/items/PasswordInputConstructor.vue @@ -23,7 +23,13 @@ watch( const getData = () => { return { input_type: 'PasswordInput', - attrs: { maxlength: formValue.value.maxlength, minlength: formValue.value.minlength, 'show-word-limit': true, type: 'password', 'show-password': true }, + attrs: { + maxlength: formValue.value.maxlength, + minlength: formValue.value.minlength, + 'show-word-limit': true, + type: 'password', + 'show-password': true, + }, default_value: formValue.value.default_value, show_default_value: formValue.value.show_default_value, props_info: { @@ -57,7 +63,12 @@ const render = (formData: DynamicFormValue) => { formValue.value.show_password = attrs['show-password'] } const rules = computed(() => [ - { min: formValue.value.minlength, max: formValue.value.maxlength, message: `长度在 ${formValue.value.minlength} 到 ${formValue.value.maxlength} 个字符`, trigger: 'blur' }, + { + min: formValue.value.minlength, + max: formValue.value.maxlength, + message: `长度在 ${formValue.value.minlength} 到 ${formValue.value.maxlength} 个字符`, + trigger: 'blur', + }, ]) defineExpose({ getData, render }) @@ -77,7 +88,7 @@ onMounted(() => {
- + - @@ -87,6 +98,7 @@ onMounted(() => { :min="formValue.minlength > formValue.maxlength ? formValue.minlength : 1" :step="1" controls-position="right" + align="left" step-strictly /> diff --git a/ui/src/components/mk-dynamics-form/constructor/items/SliderConstructor.vue b/ui/src/components/mk-dynamics-form/constructor/items/SliderConstructor.vue index 54dc7f7469d..e01e171a890 100644 --- a/ui/src/components/mk-dynamics-form/constructor/items/SliderConstructor.vue +++ b/ui/src/components/mk-dynamics-form/constructor/items/SliderConstructor.vue @@ -81,7 +81,7 @@ onBeforeMount(() => { - @@ -89,17 +89,28 @@ onBeforeMount(() => { - + - + { formValue.value.show_default_value = formData.show_default_value } const rules = computed(() => [ - { min: formValue.value.minlength, max: formValue.value.maxlength, message: `长度在 ${formValue.value.minlength} 到 ${formValue.value.maxlength} 个字符`, trigger: 'blur' }, + { + min: formValue.value.minlength, + max: formValue.value.maxlength, + message: `长度在 ${formValue.value.minlength} 到 ${formValue.value.maxlength} 个字符`, + trigger: 'blur', + }, ]) defineExpose({ getData, render }) @@ -73,7 +78,7 @@ onMounted(() => {
- + - @@ -83,6 +88,7 @@ onMounted(() => { :min="formValue.minlength > formValue.maxlength ? formValue.minlength : 1" :step="1" controls-position="right" + align="left" step-strictly /> @@ -102,7 +108,14 @@ onMounted(() => {
- +
diff --git a/ui/src/components/mk-dynamics-form/constructor/items/TextareaInputConstructor.vue b/ui/src/components/mk-dynamics-form/constructor/items/TextareaInputConstructor.vue index c69790d53db..e28a992df35 100644 --- a/ui/src/components/mk-dynamics-form/constructor/items/TextareaInputConstructor.vue +++ b/ui/src/components/mk-dynamics-form/constructor/items/TextareaInputConstructor.vue @@ -55,7 +55,12 @@ const render = (formData: DynamicFormValue) => { formValue.value.show_default_value = formData.show_default_value } const rules = computed(() => [ - { min: formValue.value.minlength, max: formValue.value.maxlength, message: `长度在 ${formValue.value.minlength} 到 ${formValue.value.maxlength} 个字符`, trigger: 'blur' }, + { + min: formValue.value.minlength, + max: formValue.value.maxlength, + message: `长度在 ${formValue.value.minlength} 到 ${formValue.value.maxlength} 个字符`, + trigger: 'blur', + }, ]) defineExpose({ getData, render }) @@ -73,7 +78,7 @@ onMounted(() => {
- + - @@ -83,6 +88,7 @@ onMounted(() => { :min="formValue.minlength > formValue.maxlength ? formValue.minlength : 1" :step="1" controls-position="right" + align="left" step-strictly /> diff --git a/ui/src/components/mk-dynamics-form/constructor/items/UploadInputConstructor.vue b/ui/src/components/mk-dynamics-form/constructor/items/UploadInputConstructor.vue index 940a66f1d15..a162d9e2e7e 100644 --- a/ui/src/components/mk-dynamics-form/constructor/items/UploadInputConstructor.vue +++ b/ui/src/components/mk-dynamics-form/constructor/items/UploadInputConstructor.vue @@ -77,10 +77,16 @@ onMounted(() => { :rules="[{ required: true, message: '单次上传最多文件数必填', trigger: 'change' }]" :min="0" controls-position="right" + align="left" /> - - + + @@ -96,7 +102,9 @@ onMounted(() => { @blur="handleInputConfirm" :style="{ '--el-input-border-radius': '4px' }" /> - 添加扩展名 + + 添加扩展名 + diff --git a/ui/src/router/admin/workflow/index.ts b/ui/src/router/admin/workflow/index.ts index bab28c97b50..9dae47a3aaa 100644 --- a/ui/src/router/admin/workflow/index.ts +++ b/ui/src/router/admin/workflow/index.ts @@ -5,13 +5,13 @@ export const workflowRoutes: RouteRecordRaw[] = [ { path: '/workspace/:workspaceId/application/:applicationId/workflow', name: 'workflow-application', - component: () => import('@/views/workflow/ApplicationWorkflowView.vue'), + component: () => import('@/views/workflow/application/ApplicationWorkflowView.vue'), meta: { title: '智能体工作流', resourceScope: 'workspace' }, }, { path: '/workspace/:workspaceId/tool/:toolId/workflow', name: 'workflow-tool', - component: () => import('@/views/workflow/ToolWorkflowView.vue'), + component: () => import('@/views/workflow/tool/ToolWorkflowView.vue'), meta: { title: '工具工作流', resourceScope: 'workspace' }, }, ] diff --git a/ui/src/styles/STYLE_README.md b/ui/src/styles/STYLE_README.md index 50468c735c6..834f52ea952 100644 --- a/ui/src/styles/STYLE_README.md +++ b/ui/src/styles/STYLE_README.md @@ -418,7 +418,7 @@ Drawer 的 `header` 插槽内时,组合 `absolute-center` 和宽度工具类 ```scss .selected { - background: rgb(var(--mk-primary-rgb) / 10%); + background: rgb(var(--mk-N600-rgb) / 10%); } ``` diff --git a/ui/src/styles/element-plus.scss b/ui/src/styles/element-plus.scss index 3767a6d2795..6d27771fccf 100644 --- a/ui/src/styles/element-plus.scss +++ b/ui/src/styles/element-plus.scss @@ -179,7 +179,7 @@ &:hover, &:active, &.is-active { - background: rgb(var(--mk-primary-rgb) / 10%); + background: var(--mk-primary-transparent-10); } } } @@ -247,9 +247,6 @@ &__body { overflow: inherit; } - &.is-always-shadow { - border: none; - } &.is-hover-shadow { cursor: pointer; &:hover { @@ -487,6 +484,9 @@ /* form */ .el-form-item { margin-bottom: calc(var(--spacing) * 4); + &.small { + margin-bottom: calc(var(--spacing) * 2); + } &:last-child { margin-bottom: 0; } @@ -698,7 +698,7 @@ } } .el-radio-button { - --el-radio-button-checked-bg-color: rgb(var(--mk-primary-rgb) / 10%); + --el-radio-button-checked-bg-color: var(--mk-primary-transparent-10); --el-radio-button-checked-text-color: var(--el-color-primary); &__inner { @@ -785,6 +785,10 @@ &__title { color: var(--mk-N500); font-size: var(--mk-font-size-base); + padding: 0 calc(var(--spacing) * 3); + } + .el-select-dropdown__item { + padding-left: calc(var(--spacing) * 2); } } @@ -1031,7 +1035,7 @@ } &--plain { &.el-tag--info { - --el-tag-border-color: rgb(var(--mk-primary-rgb) / 10%); + --el-tag-border-color: var(--mk-primary-transparent-10); --el-tag-text-color: var(--mk-N600); font-weight: 500 !important; } diff --git a/ui/src/styles/variables.scss b/ui/src/styles/variables.scss index 07d7379719f..bf2f7de578d 100644 --- a/ui/src/styles/variables.scss +++ b/ui/src/styles/variables.scss @@ -4,6 +4,7 @@ --mk-primary-rgb: 51 112 255; --mk-primary-gradient-end: #7f3bf5; --mk-primary-gradient: linear-gradient(180deg, var(--mk-primary) 0%, var(--mk-primary-gradient-end) 100%); + --mk-primary-transparent-10: rgb(var(--mk-primary-rgb) / 10%); --mk-danger: #f54a45; --mk-danger-rgb: 245 74 69; --mk-success: #34c724; diff --git a/ui/src/views/VIEW_README.md b/ui/src/views/VIEW_README.md index 8b80daf677e..b9cd718efd0 100644 --- a/ui/src/views/VIEW_README.md +++ b/ui/src/views/VIEW_README.md @@ -236,8 +236,8 @@ Dialog。新增或重命名文件时,应同步更新所有导入和页面功 | `application-detail/WorkspaceApplicationDetail.vue` | 工作空间智能体详情上下文与资源详情布局 | | `application-detail/overview/OverviewView.vue` | 智能体概览内容 | | `application-detail/setting/SimpleSettingView.vue` | 简易智能体设置内容 | -| `workflow/ApplicationWorkflowView.vue` | 智能体工作流页面头部与全屏画布 | -| `workflow/ToolWorkflowView.vue` | 工具工作流页面头部与全屏画布 | +| `workflow/application/ApplicationWorkflowView.vue` | 智能体工作流页面头部与全屏画布 | +| `workflow/tool/ToolWorkflowView.vue` | 工具工作流页面头部与全屏画布 | | `chat/ChatView.vue` | Chat 入口的对话页面 | | `error/NotFoundView.vue` | Admin 未匹配路由和全局 404 页面 | | `home/HomeView.vue` | Workspace 首页 | @@ -280,9 +280,9 @@ Dialog。新增或重命名文件时,应同步更新所有导入和页面功 共同使用,统一全屏容器、页面头部、返回按钮、标题和保存时间展示。通过 `loading`、`title`、 `saveTime` 传入展示状态,点击返回按钮触发 `back` 事件。 -`actions` 插槽用于添加组件、保存、调试等页面操作,默认插槽放置画布及页面浮层;画布继续使用 +`actions` 插槽用于默认模型设置、保存、调试等页面操作,默认插槽放置画布及页面浮层;画布继续使用 `min-h-0 flex-1` 占满头部下方空间。页面保留画布 Ref、资源与模式配置、接口调用、保存和退出确认 -逻辑,布局组件只负责展示。 +逻辑,布局组件只负责展示。添加组件入口由画布右上角的 `AddNode` 统一提供,页面不再转发节点选择事件。 ## 工作流默认模型设置 @@ -298,8 +298,8 @@ Dialog。新增或重命名文件时,应同步更新所有导入和页面功 通过 `modelValue` 接收详情配置;`disabled` 控制顶部按钮。 编辑及参数弹窗只修改抽屉副本,通过 `save(settings)` 提交副本;取消或关闭时选择不保存, 直接丢弃副本,详情中的原配置不受影响。API 与组件共用的模型类别 -`DefaultModelType` 和单项配置 `ModelConfig` 维护在 `api/types/model.ts`;按类别组织的配置直接使用 -`Partial>`,不再声明与组件名称相近的配置集合类型。 +`DefaultModelType`、单项配置 `ModelConfig` 和按类别组织的 `DefaultModelSettingPayload` 维护在 +`api/types/model.ts`,避免在组件 Props、Emits 和状态中重复展开工具类型。 `ApplicationWorkflowView` 用 `applicationDetail` 保存完整详情,用 `defaultModelSetting` 单独承接 模型配置,在详情加载或保存成功后从接口的 `default_model_setting` 深拷贝回填,缺省为空对象。 抽屉的 `save(settings)` 调用页面 `handleSaveDefaultModelSetting(settings)`,先暂存到 diff --git a/ui/src/views/login/LoginView.vue b/ui/src/views/login/LoginView.vue index 3d284fbdacb..583ea6de5bd 100644 --- a/ui/src/views/login/LoginView.vue +++ b/ui/src/views/login/LoginView.vue @@ -77,7 +77,7 @@ onBeforeMount(() => { - diff --git a/ui/src/views/system/operate-logs/dialog/CleanStrategyDialog.vue b/ui/src/views/system/operate-logs/dialog/CleanStrategyDialog.vue index 9fd627259b1..39d3644daba 100644 --- a/ui/src/views/system/operate-logs/dialog/CleanStrategyDialog.vue +++ b/ui/src/views/system/operate-logs/dialog/CleanStrategyDialog.vue @@ -47,7 +47,7 @@ defineExpose({ open })
删除 - + 天之前的对话记录
diff --git a/ui/src/views/workflow/ApplicationWorkflowView.vue b/ui/src/views/workflow/application/ApplicationWorkflowView.vue similarity index 93% rename from ui/src/views/workflow/ApplicationWorkflowView.vue rename to ui/src/views/workflow/application/ApplicationWorkflowView.vue index 113e02448b2..d56d52cf0da 100644 --- a/ui/src/views/workflow/ApplicationWorkflowView.vue +++ b/ui/src/views/workflow/application/ApplicationWorkflowView.vue @@ -7,14 +7,13 @@ import { Aim, Close, FullScreen } from '@element-plus/icons-vue' import { cloneDeep } from 'lodash' import ApplicationApi from '@/api/admin/workspace/application/application.ts' import ModelApi from '@/api/admin/workspace/model/model' -import type { ApplicationDetail } from '@/api/types' +import type { ApplicationDetail, DefaultModelSettingPayload } from '@/api/types' import { MsgConfirm, MsgError, MsgSuccess } from '@/utils/message' import WorkflowCanvas from '@/workflow-canvas/index.vue' import { defaultApplicationNodes } from '@/workflow-canvas/config/node-mapping' -import { WorkflowMode, type ShapeItem } from '@/workflow-canvas/types' -import DefaultModelSettingButton from './components/default-model-setting/DefaultModelSettingButton.vue' -import CreateNodeMenu from './components/CreateNodeMenu.vue' -import WorkflowViewLayout from './components/WorkflowViewLayout.vue' +import { WorkflowMode } from '@/workflow-canvas/types' +import DefaultModelSettingButton from '../components/default-model-setting/DefaultModelSettingButton.vue' +import WorkflowViewLayout from '../components/WorkflowViewLayout.vue' import Conversation from '@/components/conversation/index.vue' defineOptions({ name: 'ApplicationWorkflowView' }) @@ -34,11 +33,6 @@ const workspaceId = route.params.workspaceId as string const workflowRef = useTemplateRef>('workflowRef') -/* 添加工作流组件 */ -function handleAddNode(shapeItem: ShapeItem) { - workflowRef.value?.addNode(shapeItem) -} - /* 智能体工作流加载与保存 */ const applicationDetail = ref() const loading = ref(false) @@ -91,13 +85,13 @@ function handleSave() { } /* 应用默认模型设置:抽屉提交后暂存,保存失败时从详情回滚。 */ -const defaultModelSetting = ref>({}) +const defaultModelSetting = ref({}) function handleApplyDefaultModelToAll(graphData: LogicFlow.GraphData) { workflowRef.value?.renderGraphData(graphData) } -function handleSaveDefaultModelSetting(settings: NonNullable) { +function handleSaveDefaultModelSetting(settings: DefaultModelSettingPayload) { defaultModelSetting.value = cloneDeep(settings) return handleSave() } @@ -244,7 +238,7 @@ function handleBack() { } // 保存失败时保留当前页面,避免丢失尚未写入服务端的画布数据。 - MsgConfirm('当前工作流尚未保存,是否保存后退出?', undefined, { + MsgConfirm('提示', '当前工作流尚未保存,是否保存后退出?', { cancelButtonText: '直接退出', confirmButtonText: '保存并退出', confirmButtonType: 'primary', @@ -270,7 +264,6 @@ onMounted(() => {