diff --git a/ui/src/api/API_README.md b/ui/src/api/API_README.md index be626f439bc..ade5a0d7f35 100644 --- a/ui/src/api/API_README.md +++ b/ui/src/api/API_README.md @@ -338,6 +338,21 @@ API 对象和工作空间上下文,作为该抽屉的范围选择例外。Syst 详情和取消为 GET action/、POST action//cancel。 - 智能体复制查询完整 ApplicationDetail,model 映射 model_id 后创建,不使用卡片摘要。 +### 智能体概览 + +`admin/workspace/application/overview.ts` 独立维护概览接口,沿用 v2 的应用统计协议,在 +`/workspace//application/` 下提供三个 GET 接口,均传入 +`start_time`、`end_time`,由调用方管理 loading: + +- `getMonitoring(workspaceId, range, applicationId)` 请求 `/application_stats`,返回 `HomeMonitoringDay[]`,供概览复用首页监控。 +- `getTokenUsage` 请求 `/application_token_usage`,返回 `ApplicationTokenUsage[]`,字段为 + `username`、`token_usage`。 +- `getTopQuestions` 请求 `/top_questions`,返回 `ApplicationTopQuestion[]`,字段为 + `username`、`chat_record_count`。 + +两类用户排行返回按使用量降序排列的完整数组,不使用首页排行的分页、总量或导出接口。 +业务类型经 `@/api/types` 导出;Tokens 接口不包含用户对话次数,不据此展示每轮平均消耗。 + ### 工作空间首页 `admin/workspace/homepage.ts` 维护 `/workspace//homepage` 的四类资源汇总、 @@ -568,6 +583,17 @@ System 前缀中的额外 `knowledge` 段暂按 V2 保留,不能依据普通 目标文档选项通过 `workspace/knowledge/document.ts` 的 `getAllDocuments(knowledgeId)` 请求不分页的文档列表。聊天记录与标注接口保留在同一 API 文件,尚未接入日志详情正文。 +### 智能体发布渠道 + +`admin/workspace/application/access.ts` 独立维护发布渠道接口,前缀为 +`/workspace//application//platform`,沿用 v2 协议。 +GET `/status` 返回按平台标识索引的 `[是否已配置, 是否启用]`;POST `/status` 提交 +`{ type, status }`。GET、POST `/` 查询与保存对应平台配置,不由通用 application.ts 转发。 +平台标识由 `APPLICATION_ACCESS_PLATFORM` 定义,业务类型在 `types/application.ts` 经公共入口导出。 +公众号配置包含布尔值 `is_certification`,其余表单字段为字符串;配置保存保留未编辑字段。 +回调地址沿用 Admin API base 下的 `/chat//`,不使用独立 Chat API base。 +这些接口依赖部署端提供对应的平台接入服务。 + ### 知识库外部检索服务 四个知识库范围分别在自己的 `external-retrieval.ts` 中维护配置接口,仅资源前缀与写入能力不同: diff --git a/ui/src/api/admin/system/homepage.ts b/ui/src/api/admin/system/homepage.ts index 94fd3961a47..46420c21159 100644 --- a/ui/src/api/admin/system/homepage.ts +++ b/ui/src/api/admin/system/homepage.ts @@ -1,7 +1,6 @@ import { get, getExportFile } from '../core/request' import type { ParamsPage, ResponsePage } from '../core/types' import type { - Dict, HomeApplicationAggregation, HomeKnowledgeAggregation, HomeToolAggregation, @@ -14,52 +13,46 @@ import type { const prefix = `/system/homepage` -/** 合并系统首页的工作空间筛选条件。 */ -const withWorkspaceId = (workspaceId: string, query: Dict = {}) => ({ - ...query, - workspace_id: workspaceId, -}) /** 获取智能体数量与发布状态。 */ const getApplicationAggregation = (workspaceId: string) => - get(`${prefix}/application/aggregation`, withWorkspaceId(workspaceId)) + get(`${prefix}/application/aggregation`, { workspace_id: workspaceId }) /** 获取知识库与文档数量。 */ const getKnowledgeAggregation = (workspaceId: string) => - get(`${prefix}/knowledge/aggregation`, withWorkspaceId(workspaceId)) + get(`${prefix}/knowledge/aggregation`, { workspace_id: workspaceId }) /** 获取工具数量与类型分布。 */ -const getToolAggregation = (workspaceId: string) => get(`${prefix}/tool/aggregation`, withWorkspaceId(workspaceId)) +const getToolAggregation = (workspaceId: string) => get(`${prefix}/tool/aggregation`, { workspace_id: workspaceId }) /** 获取模型数量与类型分布。 */ -const getModelAggregation = (workspaceId: string) => get(`${prefix}/model/aggregation`, withWorkspaceId(workspaceId)) +const getModelAggregation = (workspaceId: string) => get(`${prefix}/model/aggregation`, { workspace_id: workspaceId }) /** 获取指定日期及智能体范围内的每日使用趋势。 */ const getMonitoring = (workspaceId: string, range: HomeDateRange, applicationId?: string) => - get( - `${prefix}/monitoring/aggregation`, - withWorkspaceId(workspaceId, { - ...range, - ...(applicationId ? { application_id: applicationId } : {}), - }), - ) + get(`${prefix}/monitoring/aggregation`, { + ...range, + ...(applicationId ? { application_id: applicationId } : {}), + workspace_id: workspaceId, + }) /** 获取工作空间日期范围内的 Tokens 总量。 */ const getTokensAggregation = (workspaceId: string, range: HomeDateRange) => - get(`${prefix}/tokens/aggregation`, withWorkspaceId(workspaceId, { ...range })) + get(`${prefix}/tokens/aggregation`, { ...range, workspace_id: workspaceId }) /** 获取工作空间日期范围内的对话轮次。 */ const getChatRecordAggregation = (workspaceId: string, range: HomeDateRange) => - get(`${prefix}/chat_record/aggregation`, withWorkspaceId(workspaceId, { ...range })) + get(`${prefix}/chat_record/aggregation`, { ...range, workspace_id: workspaceId }) const rankingPaths = { tokens: 'tokens_ranking', questions: 'question_ranking', userTokens: 'user_tokens_ranking' } /** 分页查询智能体或用户使用排行。 */ const getRanking = (workspaceId: string, kind: HomeRankingKind, page: ParamsPage, range: HomeDateRange, name?: string) => - get>( - `${prefix}/application/${rankingPaths[kind]}/${page.currentPage}/${page.pageSize}`, - withWorkspaceId(workspaceId, { ...range, ...(name ? { name } : {}) }), - ) + get>(`${prefix}/application/${rankingPaths[kind]}/${page.currentPage}/${page.pageSize}`, { + ...range, + ...(name ? { name } : {}), + workspace_id: workspaceId, + }) /** 按当前日期与名称筛选导出完整排行。 */ const exportRanking = (workspaceId: string, kind: HomeRankingKind, range: HomeDateRange, name?: string) => - getExportFile( - `${rankingPaths[kind]}.xlsx`, - `${prefix}/${rankingPaths[kind]}/export`, - withWorkspaceId(workspaceId, { ...range, ...(name ? { name } : {}) }), - ) + getExportFile(`${rankingPaths[kind]}.xlsx`, `${prefix}/${rankingPaths[kind]}/export`, { + ...range, + ...(name ? { name } : {}), + workspace_id: workspaceId, + }) export default { getApplicationAggregation, diff --git a/ui/src/api/admin/workspace/application/access.ts b/ui/src/api/admin/workspace/application/access.ts new file mode 100644 index 00000000000..5d3a90d05e2 --- /dev/null +++ b/ui/src/api/admin/workspace/application/access.ts @@ -0,0 +1,22 @@ +/** 工作空间智能体发布渠道配置与启停接口。 */ +import { get, post } from '../../core/request' +import type { ApplicationAccessConfig, ApplicationAccessPlatform, ApplicationAccessStatus, ApplicationAccessStatusPayload } from '@/api/types' +import { getWorkspaceId } from '@/utils/resource-context' + +const getPrefix = (applicationId: string) => `/workspace/${getWorkspaceId()}/application/${applicationId}/platform` + +/** 获取智能体各发布渠道的配置及启用状态。 */ +const getPlatformStatus = (applicationId: string) => get(`${getPrefix(applicationId)}/status`) + +/** 启用或停用智能体发布渠道。 */ +const postPlatformStatus = (applicationId: string, payload: ApplicationAccessStatusPayload) => post(`${getPrefix(applicationId)}/status`, payload) + +/** 获取智能体指定发布渠道的配置。 */ +const getPlatformConfig = (applicationId: string, platform: ApplicationAccessPlatform) => + get(`${getPrefix(applicationId)}/${platform}`) + +/** 保存智能体指定发布渠道的配置。 */ +const postPlatformConfig = (applicationId: string, platform: ApplicationAccessPlatform, payload: ApplicationAccessConfig) => + post(`${getPrefix(applicationId)}/${platform}`, payload) + +export default { getPlatformStatus, postPlatformStatus, getPlatformConfig, postPlatformConfig } diff --git a/ui/src/api/admin/workspace/application/application.ts b/ui/src/api/admin/workspace/application/application.ts index 224bb5f8701..96f77f8b988 100644 --- a/ui/src/api/admin/workspace/application/application.ts +++ b/ui/src/api/admin/workspace/application/application.ts @@ -75,7 +75,6 @@ const putApplicationPublish = (applicationId: string, publishName: string, publi }) } - export default { getApplicationPage, getApplicationDetail, diff --git a/ui/src/api/admin/workspace/application/overview.ts b/ui/src/api/admin/workspace/application/overview.ts new file mode 100644 index 00000000000..83d8c1ec2de --- /dev/null +++ b/ui/src/api/admin/workspace/application/overview.ts @@ -0,0 +1,24 @@ +/** 工作空间智能体概览的使用统计与用户排行接口。 */ +import { get } from '../../core/request' +import type { ApplicationTokenUsage, ApplicationTopQuestion, HomeDateRange, HomeMonitoringDay } from '@/api/types' +import { getWorkspaceId } from '@/utils/resource-context' + +const getPrefix = (workspaceId = getWorkspaceId()) => `/workspace/${workspaceId}/application` + +/** 获取智能体每日对话、用户、Tokens 与满意度统计。 */ +const getMonitoring = (workspaceId: string, range: HomeDateRange, applicationId: string) => + get(`${getPrefix(workspaceId)}/${applicationId}/application_stats`, { ...range }) + +/** 获取智能体按用户排序的 Tokens 消耗。 */ +const getTokenUsage = (applicationId: string, range: HomeDateRange) => + get(`${getPrefix()}/${applicationId}/application_token_usage`, { ...range }) + +/** 获取智能体按用户排序的提问次数。 */ +const getTopQuestions = (applicationId: string, range: HomeDateRange) => + get(`${getPrefix()}/${applicationId}/top_questions`, { ...range }) + +export default { + getMonitoring, + getTokenUsage, + getTopQuestions, +} diff --git a/ui/src/api/enums/application.ts b/ui/src/api/enums/application.ts index ea209a25941..7eee230ec6c 100644 --- a/ui/src/api/enums/application.ts +++ b/ui/src/api/enums/application.ts @@ -1,2 +1,12 @@ /** 后端智能体类型枚举值。 */ export const APPLICATION_TYPE = { SIMPLE: 'SIMPLE', WORK_FLOW: 'WORK_FLOW' } as const + +/** 智能体发布渠道的后端平台标识。 */ +export const APPLICATION_ACCESS_PLATFORM = { + WECOM_BOT: 'wecomBot', + WECOM: 'wecom', + DINGTALK: 'dingtalk', + WECHAT: 'wechat', + LARK: 'lark', + SLACK: 'slack', +} as const diff --git a/ui/src/api/types/application.ts b/ui/src/api/types/application.ts index 158e70d81f0..eeeb907daf2 100644 --- a/ui/src/api/types/application.ts +++ b/ui/src/api/types/application.ts @@ -1,12 +1,28 @@ /** Workspace 智能体列表及其卡片共用的业务类型。 */ import type LogicFlow from '@logicflow/core' -import { APPLICATION_TYPE } from '@/api/enums' +import { APPLICATION_ACCESS_PLATFORM, APPLICATION_TYPE } from '@/api/enums' import type { DefaultModelSettingPayload } from './model' import type { WorkflowStoreTemplate } from './workflow-template' +import type { Dict } from './common' export type ApplicationType = (typeof APPLICATION_TYPE)[keyof typeof APPLICATION_TYPE] +export type ApplicationAccessPlatform = (typeof APPLICATION_ACCESS_PLATFORM)[keyof typeof APPLICATION_ACCESS_PLATFORM] + +/** 状态数组依次为是否已配置、是否启用;未配置的平台可能不返回。 */ +export type ApplicationAccessStatus = Partial> + +export interface ApplicationAccessConfig extends Dict { + callback_url?: string + is_certification?: boolean +} + +export interface ApplicationAccessStatusPayload { + type: ApplicationAccessPlatform + status: boolean +} + export interface ApplicationDetail extends Omit { /** 详情接口返回的主模型 ID。 */ model?: string | null @@ -96,3 +112,15 @@ export interface ApplicationStoreResponse { additionalProperties: { tags: { key: string; name: string }[] } apps: ApplicationStoreTemplate[] } + +/** 智能体概览的用户 Tokens 消耗,接口返回完整排行。 */ +export interface ApplicationTokenUsage { + username: string + token_usage: number | null +} + +/** 智能体概览的用户提问次数,接口返回完整排行。 */ +export interface ApplicationTopQuestion { + username: string + chat_record_count: number +} diff --git a/ui/src/assets/iconfont.js b/ui/src/assets/iconfont.js index b801a0765ad..5a8dac930f0 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/assets/logo/logo_enterprise-wechat-bot.svg b/ui/src/assets/logo/logo_enterprise-wechat-bot.svg new file mode 100644 index 00000000000..bcf0aa0d9db --- /dev/null +++ b/ui/src/assets/logo/logo_enterprise-wechat-bot.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/ui/src/assets/logo/logo_slack.svg b/ui/src/assets/logo/logo_slack.svg new file mode 100644 index 00000000000..fa48c94966e --- /dev/null +++ b/ui/src/assets/logo/logo_slack.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ui/src/assets/logo/logo_wechat.svg b/ui/src/assets/logo/logo_wechat.svg new file mode 100644 index 00000000000..6c0e78de852 --- /dev/null +++ b/ui/src/assets/logo/logo_wechat.svg @@ -0,0 +1,3 @@ + + + diff --git a/ui/src/router/ROUTE_README.md b/ui/src/router/ROUTE_README.md index cbb28eb1d96..b8fbd510561 100644 --- a/ui/src/router/ROUTE_README.md +++ b/ui/src/router/ROUTE_README.md @@ -256,7 +256,8 @@ Workspace 共享覆盖 resourceScope,保留 Workspace scope 及知识库 activ ### 智能体 Workspace 详情父路由为 workspace-application-detail-layout,详情参数包含 applicationId 与 ApplicationDetail.type。 -菜单为概览、设置、接入第三方、对话用户、对话日志;SIMPLE 的 setting 与高级 workflow-entry 互斥显示。 +菜单为概览、设置、发布渠道、对话用户、对话日志;SIMPLE 的 setting 与高级 workflow-entry 互斥显示。 +发布渠道使用 access 路径、workspace-application-access 路由名,对应 application-detail/access 页面。 高级设置重定向 workflow-application,保留 workspaceId、applicationId 和 query。 对话日志保留 operation-log 路径和 workspace-application-operation-log 名称。 diff --git a/ui/src/router/admin/workspace/modules/application.ts b/ui/src/router/admin/workspace/modules/application.ts index 5f7e68a92b0..1a2c00f58dc 100644 --- a/ui/src/router/admin/workspace/modules/application.ts +++ b/ui/src/router/admin/workspace/modules/application.ts @@ -65,10 +65,10 @@ export const applicationRoutes: RouteRecordRaw[] = [ }, }, { - path: 'integration', - name: 'workspace-application-integration', - component: () => import('@/views/application-detail/integration/index.vue'), - meta: { title: '接入第三方', icon: 'icon_dataset_outlined', activeIcon: 'icon_dataset_filled', order: 30 }, + path: 'access', + name: 'workspace-application-access', + component: () => import('@/views/application-detail/access/index.vue'), + meta: { title: '发布渠道', icon: 'icon_application_outlined', activeIcon: 'icon_application_filled', order: 30 }, }, { path: 'chat-user', diff --git a/ui/src/views/VIEW_README.md b/ui/src/views/VIEW_README.md index 8230fcfadff..ee659036d5d 100644 --- a/ui/src/views/VIEW_README.md +++ b/ui/src/views/VIEW_README.md @@ -40,7 +40,7 @@ | `application-detail/` | 智能体详情上下文与资源详情布局 | | `application-detail/overview/`、`setting/` | 概览、简易智能体设置 | | `application-detail/chat-user/`、`chat-log/` | 对话授权、日志与标注 | -| `application-detail/integration/` | 接入第三方占位页 | +| `application-detail/access/` | 发布渠道配置、启停与回调地址 | | `knowledge-detail/` | 四范围知识库详情、菜单与上下文 | | `knowledge-detail/library/document/`、`tags/` | 文档及标签维护 | | `knowledge-detail/library/image/` | 图片列表,复用文档操作 | @@ -93,6 +93,11 @@ ## 详情布局与知识库上下文 +智能体发布渠道位于 `application-detail/access/`,支持企业微信智能机器人、企业微信应用、钉钉、 +公众号、飞书和 Slack。平台字段与后台指引在功能本地 `platforms.ts` 维护;卡片按配置状态显示 +启停开关,保存状态成功后更新显示。配置抽屉按需挂载并在关闭动画后卸载,每次打开重新查询, +保存失败保留草稿。公众号提供认证开关,飞书 Verification Token 可选;回调 URL 只读并支持复制。 + `layout/ResourceDetailLayout.vue` 提供侧栏和固定标题栏。子页声明 `ResourceDetailPageProps`, 普通页使用默认标题;`defineExpose({ customHeader: true })` 配合 Teleport 到 `headerTarget` 自定义标题、搜索及操作;`hideHeader: true` 隐藏整个标题栏且优先于自定义标题。 @@ -244,6 +249,13 @@ View 负责路由、资源与模式、图加载、保存/发布/调试编排 - 首页组件位于 `home/components/`,排行位于 `components/ranking/`。完整 Homepage API 和 workspaceId 由 View 传入。 智能体筛选只影响趋势;日期复用 MkDateRange,默认过去 7 天;占比使用工作空间同期总量,累计活跃人次为每日人数之和。 失败不伪装成零。快捷创建复用资源入口,`fitTriggerWidth` 仅显式开启时测量触发器。 +- `HomeStatistics` 接收完整的 Workspace Homepage、System Homepage 或 Overview API。 + 智能体概览通过 `hideHeader: true` 隐藏详情布局标题栏,保留内容内的监控与排行标题。 + 三类场景统一调用 `getMonitoring(workspaceId, range, applicationId)`;全部智能体使用空 ID, + 两类首页不提交智能体筛选,概览传当前智能体 ID。页面直接传入完整 API,不包装接口。 + 排行由概览本地 `components/ApplicationRanking.vue` 调用 Overview API,展示用户 Tokens 消耗与提问次数两类 TOP5。 + 应用排行复用首页 `RankingCard`,由概览转换展示字段;占比使用当前应用同期完整排行总量。 + 概览内暂时隐藏卡片详情入口,不接入排行抽屉、搜索、分页或导出。 - 触发器表单共用创建/编辑,保留任务 ID 和参数;资源模式固定单任务,完整输入定义不足时补查详情。 保存校验全部折叠任务;参数初始化不覆盖已配置值,移除事件引用时恢复自定义默认值。 - 智能体/知识库对话用户页使用双栏布局和当前页授权;知识库从 context 取四范围 ChatUser API。 diff --git a/ui/src/views/application-detail/access/AccessSettingDrawer.vue b/ui/src/views/application-detail/access/AccessSettingDrawer.vue new file mode 100644 index 00000000000..0ebcf9a4559 --- /dev/null +++ b/ui/src/views/application-detail/access/AccessSettingDrawer.vue @@ -0,0 +1,121 @@ + + + diff --git a/ui/src/views/application-detail/access/index.vue b/ui/src/views/application-detail/access/index.vue new file mode 100644 index 00000000000..d4dc065a97c --- /dev/null +++ b/ui/src/views/application-detail/access/index.vue @@ -0,0 +1,104 @@ + + + diff --git a/ui/src/views/application-detail/access/platforms.ts b/ui/src/views/application-detail/access/platforms.ts new file mode 100644 index 00000000000..9339106cd65 --- /dev/null +++ b/ui/src/views/application-detail/access/platforms.ts @@ -0,0 +1,111 @@ +/** 发布渠道的展示信息、配置字段与平台后台指引。 */ +import { APPLICATION_ACCESS_PLATFORM } from '@/api/enums' +import type { ApplicationAccessPlatform } from '@/api/types' +import wecomBotLogo from '@/assets/logo/logo_enterprise-wechat-bot.svg' +import wecomLogo from '@/assets/logo/logo_enterprise-wechat.svg' +import dingtalkLogo from '@/assets/logo/logo_dingtalk.svg' +import wechatLogo from '@/assets/logo/logo_wechat.svg' +import larkLogo from '@/assets/logo/logo_lark.svg' +import slackLogo from '@/assets/logo/logo_slack.svg' + +interface AccessField { + key: string + label: string + secret?: boolean + required?: boolean +} + +export interface AccessPlatformDefinition { + key: ApplicationAccessPlatform + name: string + logo: string + description: string + fields: AccessField[] + consoleUrl?: string + consoleName?: string + callbackTip?: string +} + +export const accessPlatforms: AccessPlatformDefinition[] = [ + { + key: APPLICATION_ACCESS_PLATFORM.WECOM_BOT, + name: '企业微信智能机器人', + logo: wecomBotLogo, + description: '打造企业微信智能机器人', + fields: [ + { key: 'token', label: 'Token' }, + { key: 'encoding_aes_key', label: 'EncodingAESKey' }, + ], + consoleUrl: 'https://work.weixin.qq.com/wework_admin/frame#/manageTools', + consoleName: '企业微信后台', + callbackTip: '-管理工具-智能机器人-创建机器人-API模式创建的 "URL" 中', + }, + { + key: APPLICATION_ACCESS_PLATFORM.WECOM, + name: '企业微信应用', + logo: wecomLogo, + description: '打造企业微信智能体', + fields: [ + { key: 'app_id', label: '企业 ID' }, + { key: 'agent_id', label: 'Agent ID' }, + { key: 'secret', label: 'Secret', secret: true }, + { key: 'token', label: 'Token' }, + { key: 'encoding_aes_key', label: 'EncodingAESKey' }, + ], + consoleUrl: 'https://work.weixin.qq.com/wework_admin/frame#apps', + consoleName: '企业微信后台', + callbackTip: '-应用管理-自建-创建的应用-接收消息-设置 API 接收的 "URL" 中', + }, + { + key: APPLICATION_ACCESS_PLATFORM.DINGTALK, + name: '钉钉应用', + logo: dingtalkLogo, + description: '打造钉钉智能体', + fields: [ + { key: 'client_id', label: 'Client ID' }, + { key: 'client_secret', label: 'Client Secret', secret: true }, + ], + consoleUrl: 'https://open-dev.dingtalk.com/fe/app?hash=%23%2Fcorp%2Fapp#/corp/app', + consoleName: '钉钉开放平台', + callbackTip: '-机器人页面,设置 "消息接收模式" 为 HTTP模式 ,并把上面 URL 填写到"消息接收地址"中', + }, + { + key: APPLICATION_ACCESS_PLATFORM.WECHAT, + name: '公众号', + logo: wechatLogo, + description: '打造公众号智能体', + fields: [ + { key: 'app_id', label: '开发者 ID (APP ID)' }, + { key: 'app_secret', label: '开发者密钥 (APP SECRET)', secret: true }, + { key: 'token', label: '令牌 (TOKEN)' }, + { key: 'encoding_aes_key', label: '消息加解密密钥' }, + ], + consoleUrl: 'https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev', + consoleName: '微信公众平台', + callbackTip: '-设置与开发-基本配置-服务器配置的 "服务器地址URL" 中', + }, + { + key: APPLICATION_ACCESS_PLATFORM.LARK, + name: '飞书应用', + logo: larkLogo, + description: '打造飞书智能体', + fields: [ + { key: 'app_id', label: 'App ID' }, + { key: 'app_secret', label: 'App Secret', secret: true }, + { key: 'verification_token', label: 'Verification Token', required: false }, + ], + consoleUrl: 'https://open.feishu.cn/app/', + consoleName: '飞书开放平台', + callbackTip: '-事件与回调-事件配置-配置订阅方式的 "请求地址" 中', + }, + { + key: APPLICATION_ACCESS_PLATFORM.SLACK, + name: 'Slack', + logo: slackLogo, + description: '打造 Slack 智能体', + fields: [ + { key: 'signing_secret', label: 'Signing Secret', secret: true }, + { key: 'bot_user_token', label: 'Bot User Token', secret: true }, + ], + }, +] diff --git a/ui/src/views/application-detail/integration/index.vue b/ui/src/views/application-detail/integration/index.vue deleted file mode 100644 index ab4f012177c..00000000000 --- a/ui/src/views/application-detail/integration/index.vue +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/ui/src/views/application-detail/overview/components/ApplicationRanking.vue b/ui/src/views/application-detail/overview/components/ApplicationRanking.vue new file mode 100644 index 00000000000..6fc6ced2d15 --- /dev/null +++ b/ui/src/views/application-detail/overview/components/ApplicationRanking.vue @@ -0,0 +1,82 @@ + + + + + diff --git a/ui/src/views/application-detail/overview/index.vue b/ui/src/views/application-detail/overview/index.vue index 3d9d275e376..1389bced3a7 100644 --- a/ui/src/views/application-detail/overview/index.vue +++ b/ui/src/views/application-detail/overview/index.vue @@ -1,9 +1,22 @@ diff --git a/ui/src/views/home/components/HomeStatistics.vue b/ui/src/views/home/components/HomeStatistics.vue index 63a5e044400..9fb62e2da71 100644 --- a/ui/src/views/home/components/HomeStatistics.vue +++ b/ui/src/views/home/components/HomeStatistics.vue @@ -3,11 +3,17 @@ import { formatTokenNumber, numberFormat } from '@/utils/number' import { computed, ref, watch } from 'vue' import type { HomeMonitoringDay } from '@/api/types' import type HomepageApi from '@/api/admin/workspace/homepage' +import type SystemHomepageApi from '@/api/admin/system/homepage' +import type OverviewApi from '@/api/admin/workspace/application/overview' import MkDateRange from '@/components/mk-date-range/index.vue' import type { MkDateRangeValue } from '@/components/mk-date-range/types' import MkLineChart from '@/components/mk-echart/LineCharts.vue' import { beforeDay } from '@/utils/time' -const props = defineProps<{ workspaceId: string; applicationId: string; api: typeof HomepageApi }>() +const props = defineProps<{ + workspaceId: string + applicationId: string + api: typeof HomepageApi | typeof SystemHomepageApi | typeof OverviewApi +}>() defineSlots<{ application(props: { loading: boolean }): unknown }>() /* 日期、智能体筛选与使用统计 */ @@ -47,7 +53,7 @@ const metrics = computed(() => function loadMonitoring() { loading.value = true return props.api - .getMonitoring(props.workspaceId, range.value, props.applicationId === 'all' ? undefined : props.applicationId) + .getMonitoring(props.workspaceId, range.value, props.applicationId === 'all' ? '' : props.applicationId) .then((result) => { monitoring.value = result }) @@ -97,9 +103,9 @@ watch(() => [props.workspaceId, props.applicationId], loadMonitoring, { immediat

{{ metric.id === 'tokens' ? formatTokenNumber(metric.series[0]?.total) : numberFormat(metric.series[0]?.total) }}

- +{{ numberFormat(metric.series[1]?.total) }} + + +{{ numberFormat(metric.series[1]?.total) }} + diff --git a/ui/src/views/system/settings/authentication/components/SCANLogin.vue b/ui/src/views/system/settings/authentication/components/SCANLogin.vue index 5f20a56e308..0e9ad6c1cbc 100644 --- a/ui/src/views/system/settings/authentication/components/SCANLogin.vue +++ b/ui/src/views/system/settings/authentication/components/SCANLogin.vue @@ -3,8 +3,8 @@ import { onMounted, ref, useTemplateRef } from 'vue' import AuthScanApi from '@/api/admin/system/settings/auth-scan-setting' import type { QrCodeProvider, QrLoginPlatform, QrLoginPlatformPayload } from '@/api/types' import { LOGIN_METHOD } from '@/api/enums' -import { LOGIN_METHOD_LABELS, SCAN_FIELD_LABELS } from '@/constants' -import { MsgSuccess, MsgError } from '@/utils/message' +import { LOGIN_METHOD_LABELS } from '@/constants' +import { MsgSuccess } from '@/utils/message' import dingtalkLogo from '@/assets/logo/logo_dingtalk.svg' import enterpriseWechatLogo from '@/assets/logo/logo_enterprise-wechat.svg' import larkLogo from '@/assets/logo/logo_lark.svg' @@ -76,51 +76,32 @@ function handleEditPlatform(platform: QrLoginPlatformView) { editScanDrawerRef.value?.open(platform) } -/* 校验 */ -function handleValidatePlatform(platform: QrLoginPlatformView) { - loading.value = true - return AuthScanApi.postValidateQrLoginPlatform(platform) - .then((res) => { - res ? MsgSuccess('校验成功') : MsgError('校验失败') - }) - .finally(() => { - loading.value = false - }) -} - onMounted(loadQrPlatforms)