From e8232f23c75be29c70b7849c5d1462dcd461d321 Mon Sep 17 00:00:00 2001 From: wangdan-fit2cloud Date: Sat, 22 Aug 2026 18:41:57 +0800 Subject: [PATCH] feat: application view --- ui/AGENTS.md | 3 +- ui/package.json | 1 - ui/src/api/admin/workspace/application.ts | 37 ++++++ ui/src/api/enums/application.ts | 5 + ui/src/api/enums/index.ts | 1 + ui/src/api/types/application.ts | 70 +++++++++++ ui/src/api/types/index.ts | 1 + ui/src/assets/iconfont.js | 2 +- ui/src/auto-imports.d.ts | 90 -------------- .../components/business/folder-tree/index.vue | 8 +- .../business/model-select/index.vue | 2 +- .../global/mk-complex-search/index.vue | 2 +- ui/src/components/global/mk-empty/index.vue | 1 + ui/src/layout/LayoutHeader.vue | 4 +- ui/src/router/ROUTE_README.md | 18 +-- ui/src/router/admin/system/index.ts | 4 +- ui/src/router/admin/system/modules/agent.ts | 17 --- .../admin/system/modules/application.ts | 17 +++ ui/src/router/admin/workflow/index.ts | 6 +- ui/src/router/admin/workspace/index.ts | 4 +- .../router/admin/workspace/modules/agent.ts | 36 ------ .../admin/workspace/modules/application.ts | 36 ++++++ ui/src/styles/element-plus.scss | 13 +- ui/src/utils/application.ts | 4 + ui/src/utils/common.ts | 9 +- ui/src/views/VIEW_README.md | 48 ++++---- ui/src/views/agent/AgentDetailView.vue | 33 ----- ui/src/views/application/ApplicationView.vue | 115 ++++++++++++++++++ .../components/ApplicationCard.vue | 83 +++++++++++++ .../views/{agent => application}/template.ts | 0 ui/src/views/model/components/ModelCard.vue | 2 + .../identity/workspaces/WorkspaceListView.vue | 2 +- ui/src/views/tool/ToolView.vue | 23 ++-- ui/src/views/workflow/AgentWorkflowView.vue | 56 --------- .../workflow/ApplicationWorkflowView.vue | 79 ++++++++++++ .../components/WorkflowComponentMenu.vue | 6 +- ui/src/workflow-canvas/WORKFLOW_README.md | 2 +- ui/src/workflow-canvas/component/NodeMenu.vue | 6 +- .../workflow-canvas/component/NodeSearch.vue | 2 + ui/src/workflow-canvas/core/NodeCascader.vue | 2 + ui/src/workflow-canvas/core/NodeContainer.vue | 2 +- ui/src/workflow-canvas/core/utils.ts | 4 - ui/src/workflow-canvas/core/workflow-node.ts | 3 +- ui/src/workflow-canvas/index.vue | 2 + .../nodes/ai-chat-node/index.vue | 6 +- .../workflow-canvas/nodes/base-node/index.vue | 2 + .../nodes/reply-node/index.vue | 2 + .../nodes/start-node/index.vue | 2 + ui/vite.config.ts | 20 ++- 49 files changed, 570 insertions(+), 323 deletions(-) create mode 100644 ui/src/api/admin/workspace/application.ts create mode 100644 ui/src/api/enums/application.ts create mode 100644 ui/src/api/types/application.ts delete mode 100644 ui/src/auto-imports.d.ts delete mode 100644 ui/src/router/admin/system/modules/agent.ts create mode 100644 ui/src/router/admin/system/modules/application.ts delete mode 100644 ui/src/router/admin/workspace/modules/agent.ts create mode 100644 ui/src/router/admin/workspace/modules/application.ts create mode 100644 ui/src/utils/application.ts delete mode 100644 ui/src/views/agent/AgentDetailView.vue create mode 100644 ui/src/views/application/ApplicationView.vue create mode 100644 ui/src/views/application/components/ApplicationCard.vue rename ui/src/views/{agent => application}/template.ts (100%) delete mode 100644 ui/src/views/workflow/AgentWorkflowView.vue create mode 100644 ui/src/views/workflow/ApplicationWorkflowView.vue diff --git a/ui/AGENTS.md b/ui/AGENTS.md index 617e3f9907c..9c5cfd7d74f 100644 --- a/ui/AGENTS.md +++ b/ui/AGENTS.md @@ -178,7 +178,7 @@ Keep these behaviors: - `base: './'` for v2-compatible static deployment. - `envDir: './env'`. - Proxy `/admin/api`, `/chat/api`, `/doc`, `/schema`, `/static`, and `oss` file paths to the backend. -- Keep Tailwind, Vue, Vue JSX, Element Plus auto import, and component auto registration plugins. +- Keep Tailwind, Vue, Vue JSX, and component auto registration plugins. - Do not add `unplugin-vue-define-options`; Vue 3.5 already supports `defineOptions`. - Avoid adding `vite-plugin-html` unless multi-template requirements exceed Vite's built-in HTML env replacement. @@ -186,5 +186,6 @@ Keep these behaviors: - Prefer existing project structure and naming. - Keep UI code typed and data-driven. +- Explicitly import APIs used from Vue, Vue Router, and Pinia; do not restore API auto import. - Name business variables after their domain and purpose. Avoid context-free collection names such as `items` or `list` when a name such as `systemMenuItems` makes the contents clear. diff --git a/ui/package.json b/ui/package.json index 4b9e4d29d71..a3d3bf3eff9 100644 --- a/ui/package.json +++ b/ui/package.json @@ -52,7 +52,6 @@ "sass": "^1.101.0", "tailwindcss": "^4.3.2", "typescript": "~6.0.0", - "unplugin-auto-import": "^21.0.0", "unplugin-vue-components": "^32.1.0", "vite": "^8.0.16", "vue-eslint-parser": "^10.4.1", diff --git a/ui/src/api/admin/workspace/application.ts b/ui/src/api/admin/workspace/application.ts new file mode 100644 index 00000000000..4dbedcb2dc1 --- /dev/null +++ b/ui/src/api/admin/workspace/application.ts @@ -0,0 +1,37 @@ +import { get, put } from '../core/request' +import type { ParamsPage, ResponsePage } from '../core/types' +import type { + ApplicationDetail, + ApplicationFormPayload, + RequestParams, +} from '@/api/types' +import { getWorkspaceId } from '@/utils/workspace-context' + +const getPrefix = () => { + const workspaceId = getWorkspaceId() + return `/workspace/${workspaceId}/application` +} + +/** 获取工作空间智能体列表。 */ +const getApplicationPage = (page: ParamsPage, query?: RequestParams) => { + return get>( + `${getPrefix()}/${page.currentPage}/${page.pageSize}`, + query, + ) +} + +/** 获取工作空间智能体详情。 */ +const getApplicationDetail = (applicationId: string) => { + return get(`${getPrefix()}/${applicationId}`) +} + +/** 保存工作空间智能体配置。 */ +const putApplication = (applicationId: string, data: ApplicationFormPayload) => { + return put(`${getPrefix()}/${applicationId}`, data) +} + +export default { + getApplicationPage, + getApplicationDetail, + putApplication, +} diff --git a/ui/src/api/enums/application.ts b/ui/src/api/enums/application.ts new file mode 100644 index 00000000000..1dae8c640c7 --- /dev/null +++ b/ui/src/api/enums/application.ts @@ -0,0 +1,5 @@ +/** 后端智能体类型枚举值。 */ +export const APPLICATION_TYPE = { + SIMPLE: 'SIMPLE', + WORK_FLOW: 'WORK_FLOW', +} as const diff --git a/ui/src/api/enums/index.ts b/ui/src/api/enums/index.ts index 7cbb9094f45..923864bcb15 100644 --- a/ui/src/api/enums/index.ts +++ b/ui/src/api/enums/index.ts @@ -1,4 +1,5 @@ /** API 枚举值的唯一公共入口。 */ +export * from './application' export * from './folder' export * from './login' export * from './system-role' diff --git a/ui/src/api/types/application.ts b/ui/src/api/types/application.ts new file mode 100644 index 00000000000..fde507aac34 --- /dev/null +++ b/ui/src/api/types/application.ts @@ -0,0 +1,70 @@ +/** Workspace 智能体列表及其卡片共用的业务类型。 */ + +import type LogicFlow from '@logicflow/core' +import { APPLICATION_TYPE } from '@/api/enums' + +export type ApplicationType = (typeof APPLICATION_TYPE)[keyof typeof APPLICATION_TYPE] + +export interface ApplicationDetail { + create_time?: string + desc?: string | null + folder_id?: string + icon?: string + id: string + is_portal: boolean + is_publish: boolean + name: string + nick_name?: string | null + publish_time?: string | null + resource_count?: number + resource_type: string + type: ApplicationType + update_time?: string + user_id?: string | null + workspace_id?: string + work_flow?: LogicFlow.GraphConfigData +} + +export interface ApplicationFormPayload { + name?: string + desc?: string + model_id?: string + dialogue_number?: number + prologue?: string + knowledge_id_list?: string[] + knowledge_setting?: Record + model_setting?: Record + problem_optimization?: boolean + problem_optimization_prompt?: string + icon?: string + type?: ApplicationType + work_flow?: LogicFlow.GraphData + model_params_setting?: Record + tts_model_params_setting?: Record + stt_model_params_setting?: Record + stt_model_id?: string + tts_model_id?: string + stt_model_enable?: boolean + tts_model_enable?: boolean + tts_type?: string + tts_autoplay?: boolean + stt_autosend?: boolean + folder_id?: string + workspace_id?: string + mcp_enable?: boolean + mcp_servers?: string + mcp_tool_ids?: string[] + mcp_source?: string + tool_enable?: boolean + tool_ids?: string[] + application_enable?: boolean + application_ids?: string[] + skill_tool_ids?: string[] + mcp_output_enable?: boolean + work_flow_template?: Record + long_term_enable?: boolean + long_term_model_id?: string + long_term_model_params_setting?: Record + long_term_trigger_setting?: Record + long_term_trigger_type?: string +} diff --git a/ui/src/api/types/index.ts b/ui/src/api/types/index.ts index aaf8b385ccb..db34fe0d171 100644 --- a/ui/src/api/types/index.ts +++ b/ui/src/api/types/index.ts @@ -1,4 +1,5 @@ /** API 与 View 或 Component 跨层业务类型的唯一公共入口。 */ +export type * from './application' export type * from './common' export type * from './chat-user' export type * from './chat-user-groups' diff --git a/ui/src/assets/iconfont.js b/ui/src/assets/iconfont.js index b7499a89dc6..d7458848af2 100644 --- a/ui/src/assets/iconfont.js +++ b/ui/src/assets/iconfont.js @@ -1 +1 @@ -window._iconfont_svg_string_5200172='',(l=>{var a=(h=(h=document.getElementsByTagName("script"))[h.length-1]).getAttribute("data-injectcss"),h=h.getAttribute("data-disable-injectsvg");if(!h){var v,o,t,i,c,e=function(a,h){h.parentNode.insertBefore(a,h)};if(a&&!l.__iconfont__svg__cssinject__){l.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(a){console&&console.log(a)}}v=function(){var a,h=document.createElement("div");h.innerHTML=l._iconfont_svg_string_5200172,(h=h.getElementsByTagName("svg")[0])&&(h.setAttribute("aria-hidden","true"),h.style.position="absolute",h.style.width=0,h.style.height=0,h.style.overflow="hidden",h=h,(a=document.body).firstChild?e(h,a.firstChild):a.appendChild(h))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(v,0):(o=function(){document.removeEventListener("DOMContentLoaded",o,!1),v()},document.addEventListener("DOMContentLoaded",o,!1)):document.attachEvent&&(t=v,i=l.document,c=!1,m(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,d())})}function d(){c||(c=!0,t())}function m(){try{i.documentElement.doScroll("left")}catch(a){return void setTimeout(m,50)}d()}})(window); \ No newline at end of file +window._iconfont_svg_string_5200172='',(l=>{var a=(h=(h=document.getElementsByTagName("script"))[h.length-1]).getAttribute("data-injectcss"),h=h.getAttribute("data-disable-injectsvg");if(!h){var v,o,t,i,c,e=function(a,h){h.parentNode.insertBefore(a,h)};if(a&&!l.__iconfont__svg__cssinject__){l.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(a){console&&console.log(a)}}v=function(){var a,h=document.createElement("div");h.innerHTML=l._iconfont_svg_string_5200172,(h=h.getElementsByTagName("svg")[0])&&(h.setAttribute("aria-hidden","true"),h.style.position="absolute",h.style.width=0,h.style.height=0,h.style.overflow="hidden",h=h,(a=document.body).firstChild?e(h,a.firstChild):a.appendChild(h))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(v,0):(o=function(){document.removeEventListener("DOMContentLoaded",o,!1),v()},document.addEventListener("DOMContentLoaded",o,!1)):document.attachEvent&&(t=v,i=l.document,c=!1,m(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,d())})}function d(){c||(c=!0,t())}function m(){try{i.documentElement.doScroll("left")}catch(a){return void setTimeout(m,50)}d()}})(window); \ No newline at end of file diff --git a/ui/src/auto-imports.d.ts b/ui/src/auto-imports.d.ts deleted file mode 100644 index 101b7d6f09d..00000000000 --- a/ui/src/auto-imports.d.ts +++ /dev/null @@ -1,90 +0,0 @@ -/* eslint-disable */ -/* prettier-ignore */ -// @ts-nocheck -// noinspection JSUnusedGlobalSymbols -// Generated by unplugin-auto-import -// biome-ignore lint: disable -export {} -declare global { - const EffectScope: typeof import('vue').EffectScope - const acceptHMRUpdate: typeof import('pinia').acceptHMRUpdate - const computed: typeof import('vue').computed - const createApp: typeof import('vue').createApp - const createPinia: typeof import('pinia').createPinia - const customRef: typeof import('vue').customRef - const defineAsyncComponent: typeof import('vue').defineAsyncComponent - const defineComponent: typeof import('vue').defineComponent - const defineStore: typeof import('pinia').defineStore - const effectScope: typeof import('vue').effectScope - const getActivePinia: typeof import('pinia').getActivePinia - const getCurrentInstance: typeof import('vue').getCurrentInstance - const getCurrentScope: typeof import('vue').getCurrentScope - const getCurrentWatcher: typeof import('vue').getCurrentWatcher - const h: typeof import('vue').h - const inject: typeof import('vue').inject - const isProxy: typeof import('vue').isProxy - const isReactive: typeof import('vue').isReactive - const isReadonly: typeof import('vue').isReadonly - const isRef: typeof import('vue').isRef - const isShallow: typeof import('vue').isShallow - const mapActions: typeof import('pinia').mapActions - const mapGetters: typeof import('pinia').mapGetters - const mapState: typeof import('pinia').mapState - const mapStores: typeof import('pinia').mapStores - const mapWritableState: typeof import('pinia').mapWritableState - const markRaw: typeof import('vue').markRaw - const nextTick: typeof import('vue').nextTick - const onActivated: typeof import('vue').onActivated - const onBeforeMount: typeof import('vue').onBeforeMount - const onBeforeRouteLeave: typeof import('vue-router').onBeforeRouteLeave - const onBeforeRouteUpdate: typeof import('vue-router').onBeforeRouteUpdate - const onBeforeUnmount: typeof import('vue').onBeforeUnmount - const onBeforeUpdate: typeof import('vue').onBeforeUpdate - const onDeactivated: typeof import('vue').onDeactivated - const onErrorCaptured: typeof import('vue').onErrorCaptured - const onMounted: typeof import('vue').onMounted - const onRenderTracked: typeof import('vue').onRenderTracked - const onRenderTriggered: typeof import('vue').onRenderTriggered - const onScopeDispose: typeof import('vue').onScopeDispose - const onServerPrefetch: typeof import('vue').onServerPrefetch - const onUnmounted: typeof import('vue').onUnmounted - const onUpdated: typeof import('vue').onUpdated - const onWatcherCleanup: typeof import('vue').onWatcherCleanup - const provide: typeof import('vue').provide - const reactive: typeof import('vue').reactive - const readonly: typeof import('vue').readonly - const ref: typeof import('vue').ref - const resolveComponent: typeof import('vue').resolveComponent - const setActivePinia: typeof import('pinia').setActivePinia - const setMapStoreSuffix: typeof import('pinia').setMapStoreSuffix - const shallowReactive: typeof import('vue').shallowReactive - const shallowReadonly: typeof import('vue').shallowReadonly - const shallowRef: typeof import('vue').shallowRef - const storeToRefs: typeof import('pinia').storeToRefs - const toRaw: typeof import('vue').toRaw - const toRef: typeof import('vue').toRef - const toRefs: typeof import('vue').toRefs - const toValue: typeof import('vue').toValue - const triggerRef: typeof import('vue').triggerRef - const unref: typeof import('vue').unref - const useAttrs: typeof import('vue').useAttrs - const useCssModule: typeof import('vue').useCssModule - const useCssVars: typeof import('vue').useCssVars - const useId: typeof import('vue').useId - const useLink: typeof import('vue-router').useLink - const useModel: typeof import('vue').useModel - const useRoute: typeof import('vue-router').useRoute - const useRouter: typeof import('vue-router').useRouter - const useSlots: typeof import('vue').useSlots - const useTemplateRef: typeof import('vue').useTemplateRef - const watch: typeof import('vue').watch - const watchEffect: typeof import('vue').watchEffect - const watchPostEffect: typeof import('vue').watchPostEffect - const watchSyncEffect: typeof import('vue').watchSyncEffect -} -// for type re-export -declare global { - // @ts-ignore - export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, ShallowRef, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue' - import('vue') -} diff --git a/ui/src/components/business/folder-tree/index.vue b/ui/src/components/business/folder-tree/index.vue index 8476d86237f..9db5bb8842e 100644 --- a/ui/src/components/business/folder-tree/index.vue +++ b/ui/src/components/business/folder-tree/index.vue @@ -1,12 +1,13 @@ - - diff --git a/ui/src/views/application/ApplicationView.vue b/ui/src/views/application/ApplicationView.vue new file mode 100644 index 00000000000..b0546557c9b --- /dev/null +++ b/ui/src/views/application/ApplicationView.vue @@ -0,0 +1,115 @@ + + + diff --git a/ui/src/views/application/components/ApplicationCard.vue b/ui/src/views/application/components/ApplicationCard.vue new file mode 100644 index 00000000000..2ab72557b20 --- /dev/null +++ b/ui/src/views/application/components/ApplicationCard.vue @@ -0,0 +1,83 @@ + + + diff --git a/ui/src/views/agent/template.ts b/ui/src/views/application/template.ts similarity index 100% rename from ui/src/views/agent/template.ts rename to ui/src/views/application/template.ts diff --git a/ui/src/views/model/components/ModelCard.vue b/ui/src/views/model/components/ModelCard.vue index 22fa5f03f60..c764ec57879 100644 --- a/ui/src/views/model/components/ModelCard.vue +++ b/ui/src/views/model/components/ModelCard.vue @@ -1,4 +1,6 @@ - - diff --git a/ui/src/views/workflow/ApplicationWorkflowView.vue b/ui/src/views/workflow/ApplicationWorkflowView.vue new file mode 100644 index 00000000000..8cfba655266 --- /dev/null +++ b/ui/src/views/workflow/ApplicationWorkflowView.vue @@ -0,0 +1,79 @@ + + + diff --git a/ui/src/views/workflow/components/WorkflowComponentMenu.vue b/ui/src/views/workflow/components/WorkflowComponentMenu.vue index acaee2ecafa..35795d1f3c0 100644 --- a/ui/src/views/workflow/components/WorkflowComponentMenu.vue +++ b/ui/src/views/workflow/components/WorkflowComponentMenu.vue @@ -1,4 +1,6 @@