diff --git a/ui/src/api/API_README.md b/ui/src/api/API_README.md index 91a5ce879d0..f0075551ad2 100644 --- a/ui/src/api/API_README.md +++ b/ui/src/api/API_README.md @@ -366,6 +366,10 @@ API 对象和工作空间上下文,作为该抽屉的范围选择例外。Syst - 知识库 Workflow API 记录为 `//action//`,筛选 user_name、state; 详情和取消为 GET action/、POST action//cancel。 - 智能体复制查询完整 ApplicationDetail,model 映射 model_id 后创建,不使用卡片摘要。 +- Workspace 与 System 资源管理的 Application API 提供 `putApplicationPortal(applicationId, isPortal)` 和 + `exportApplicationSkills(applicationId, applicationName)` 的本地 mock;前者返回 `{ id, is_portal }`, + 后者返回 `{ application_id, name }`,均不发送请求或持久化,也不生成 Skills 文件。真实接口待接入, + 不通过智能体配置保存接口模拟上下架。 ### 智能体概览 diff --git a/ui/src/api/admin/system/resource-management/application/application.ts b/ui/src/api/admin/system/resource-management/application/application.ts index 8b9d87e3565..df45a84ec1b 100644 --- a/ui/src/api/admin/system/resource-management/application/application.ts +++ b/ui/src/api/admin/system/resource-management/application/application.ts @@ -22,6 +22,13 @@ const exportApplication = (applicationId: string, applicationName: string) => { return getExportFile(`${applicationName}.mk`, `${prefix}/${applicationId}/export`) } +/** 模拟 System 资源管理智能体 Skills 导出;TODO:接入真实下载接口。 */ +const exportApplicationSkills = (applicationId: string, applicationName: string) => + Promise.resolve({ application_id: applicationId, name: applicationName }) + +/** 模拟 System 资源管理智能体门户上下架;TODO:接入真实接口,当前不持久化。 */ +const putApplicationPortal = (applicationId: string, isPortal: boolean) => Promise.resolve({ id: applicationId, is_portal: isPortal }) + /** 获取 System 资源管理智能体详情。 */ const getApplicationDetail = (applicationId: string) => get(`${prefix}/${applicationId}`) @@ -53,4 +60,6 @@ export default { getApplicationPage, deleteApplication, exportApplication, + exportApplicationSkills, + putApplicationPortal, } diff --git a/ui/src/api/admin/workspace/application/application.ts b/ui/src/api/admin/workspace/application/application.ts index 7f08ca5b16c..ced90312b9c 100644 --- a/ui/src/api/admin/workspace/application/application.ts +++ b/ui/src/api/admin/workspace/application/application.ts @@ -42,6 +42,13 @@ const exportApplication = (applicationId: string, applicationName: string) => { return getExportFile(`${applicationName}.mk`, `${getPrefix()}/${applicationId}/export`) } +/** 模拟导出工作空间智能体为 Skills;TODO:接入真实下载接口。 */ +const exportApplicationSkills = (applicationId: string, applicationName: string) => + Promise.resolve({ application_id: applicationId, name: applicationName }) + +/** 模拟工作空间智能体门户上下架;TODO:接入真实接口,当前不持久化。 */ +const putApplicationPortal = (applicationId: string, isPortal: boolean) => Promise.resolve({ id: applicationId, is_portal: isPortal }) + /** 导入智能体文件并创建工作空间智能体。 */ const postApplicationImport = (file: File, folderId: string) => { const payload = new FormData() @@ -89,6 +96,8 @@ export default { putAccessToken, deleteApplication, exportApplication, + exportApplicationSkills, + putApplicationPortal, postApplication, postApplicationImport, putApplication, diff --git a/ui/src/assets/iconfont.js b/ui/src/assets/iconfont.js index 7fd69669718..498e61e158c 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,e(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,m())})}function m(){c||(c=!0,t())}function e(){try{i.documentElement.doScroll("left")}catch(a){return void setTimeout(e,50)}m()}})(window); \ No newline at end of file diff --git a/ui/src/components/COMPONENT_README.md b/ui/src/components/COMPONENT_README.md index a8d80c41af1..5b8fd1e35ec 100644 --- a/ui/src/components/COMPONENT_README.md +++ b/ui/src/components/COMPONENT_README.md @@ -246,15 +246,17 @@ Element Plus 的 `v-infinite-scroll`。组件通过 `v-model` 管理已经加载 ### MkStatusLabel -提供 `success`、`failure`、`loading`、`disabled` 四种图标类型,通过 `type + label` 展示业务状态。 -组件不依赖 API 状态枚举或业务文案;业务方维护状态与 `{ type, label }` 的映射。 +提供 `success`、`failure`、`loading`、`disabled`、`custom` 五种图标类型,通过 `type + label` 展示业务状态。 +组件不依赖 API 状态枚举或业务文案;业务方维护状态与 `{ type, label, icon? }` 的映射。 `StatusLabelType`、`StatusLabelOptions` 从 `global/mk-status-label/types.ts` 导入。 传入 `type` 时使用该类型和外部 `label`,优先于布尔模式,不回退到启用/禁用文案。 未传 `type` 时保留 `active` 便捷模式,默认“已启用 / 已禁用”; -`activeText`、`inactiveText` 可修改文案,`inactiveIcon` 可覆盖未激活图标(默认 `icon_ban_filled`)。 -成功图标固定为 `icon_succeed_colorful`,失败图标为 `icon_close_colorful`,加载类型使用 `LoadingIcon`, -禁用图标使用灰色样式。`inactiveIcon` 仅影响布尔模式。 +`activeText`、`inactiveText` 可修改文案。 +`icon` 接收完整 SVG Symbol ID,在两种模式下均优先替换图标,包括加载图标;不改变状态文案及禁用状态的灰色样式。 +未传 `icon` 时,成功使用 `icon_succeed_colorful`,失败使用 `icon_close_colorful`,加载使用 `LoadingIcon`, +禁用使用 `icon_ban_filled`。仅替换未激活图标时,由调用方按 `active` 条件传入 `icon`。 +`type="custom"` 使用外部 `label` 与 `icon`,不附加状态颜色,保留图标自带颜色或继承文字颜色;未传 `icon` 时仅显示文案。 接口使用 type/label,未知业务状态由调用方显示原始文案,不伪装成成功或禁用状态。 ### MkTable diff --git a/ui/src/components/global/mk-status-label/index.vue b/ui/src/components/global/mk-status-label/index.vue index 55ee1d49b94..4a711b279a0 100644 --- a/ui/src/components/global/mk-status-label/index.vue +++ b/ui/src/components/global/mk-status-label/index.vue @@ -11,24 +11,26 @@ const props = withDefaults( active?: boolean activeText?: string inactiveText?: string - inactiveIcon?: string + icon?: string }>(), - { activeText: '已启用', inactiveText: '已禁用', inactiveIcon: 'icon_ban_filled' }, + { activeText: '已启用', inactiveText: '已禁用' }, ) const displayType = computed(() => props.type ?? (props.active ? 'success' : 'disabled')) const displayLabel = computed(() => (props.type !== undefined ? props.label : props.active ? props.activeText : props.inactiveText)) const iconName = computed(() => { + if (props.icon) return props.icon + if (displayType.value === 'custom') return undefined if (displayType.value === 'success') return 'icon_succeed_colorful' if (displayType.value === 'failure') return 'icon_close_colorful' - return props.type === undefined ? props.inactiveIcon : 'icon_ban_filled' + return 'icon_ban_filled' }) diff --git a/ui/src/components/global/mk-status-label/types.ts b/ui/src/components/global/mk-status-label/types.ts index e5d33536425..135bad9ea74 100644 --- a/ui/src/components/global/mk-status-label/types.ts +++ b/ui/src/components/global/mk-status-label/types.ts @@ -1,6 +1,7 @@ -export type StatusLabelType = 'success' | 'failure' | 'loading' | 'disabled' +export type StatusLabelType = 'success' | 'failure' | 'loading' | 'disabled' | 'custom' export interface StatusLabelOptions { type: StatusLabelType label: string + icon?: string } diff --git a/ui/src/layout/AppLayout.vue b/ui/src/layout/AppLayout.vue index cc2e26dece4..a4db5e9fac9 100644 --- a/ui/src/layout/AppLayout.vue +++ b/ui/src/layout/AppLayout.vue @@ -17,7 +17,7 @@ const mode = computed(() => route.meta.scope ?? 'workspace')
- +
diff --git a/ui/src/layout/LayoutSidebar.vue b/ui/src/layout/LayoutSidebar.vue index 42e9c7012ff..508b62a67d7 100644 --- a/ui/src/layout/LayoutSidebar.vue +++ b/ui/src/layout/LayoutSidebar.vue @@ -1,27 +1,34 @@