diff --git a/ui/src/api/API_README.md b/ui/src/api/API_README.md index 65771a72cab..1163c07ddd5 100644 --- a/ui/src/api/API_README.md +++ b/ui/src/api/API_README.md @@ -504,6 +504,7 @@ System 接口由资源管理服务提供;本地开源后端没有对应扩展 文件状态响应还包含 `REVOKE: '4'`、`REVOKED: '5'`、`IGNORED: 'n'`。 `DocumentItem.status_meta` 使用可空的 `DocumentStatusMeta`:`aggs` 为 `{ status, count }[]`, `state_time` 按任务编号、状态字符两级索引时间字符串;两项均可缺省。 +无分段时聚合项的 `status` 可为 `null`,按忽略状态解析,不计入成功数量。 `DocumentTaskState` 和 `DocumentTaskType` 从文档枚举派生,统一从 `@/api/types` 导入。 启用状态传布尔值,`false` 不省略;单选全部时省略该字段。`tags` 传数组,沿用 Axios 的 `tags[]` 序列化,内容为标签 ID 或特殊值 `NO_TAG`,不传标签名称或 JSON 字符串。 @@ -531,3 +532,22 @@ System 接口由资源管理服务提供;本地开源后端没有对应扩展 Workspace 共享知识库详情由 `resourceScope: 'workspace-shared'` 选择上述完整共享 API 对象; 普通详情继续使用 `workspace/knowledge/`。共享详情和文档查询不使用 System 共享资源管理 API, 也不回退到普通 Workspace 知识库接口。文档创建者选项沿用共享列表的 System `common.ts` 查询。 + +### 资源对话用户授权 + +`workspace/chat-user.ts` 使用 Admin 请求客户端,通过资源的 `user_group` 查询和保存组自动授权, +通过 `user_group_id/` 查询分页用户及保存逐用户授权,沿用已有接口路径与请求体。 +使用 `ParamsPage`、`ResponsePage`,调用方直接读取已解包数据并管理 loading。 +公共授权类型维护在 `types/chat-user.ts`,经 `@/api/types` 导出。当前由工作空间智能体详情页调用; +仓库内开源后端尚未注册这组资源授权路径,实际联调依赖提供这些接口的后端环境。 + +### 智能体对话日志 + +`workspace/application/chat-log.ts` 使用 Admin 请求客户端,日志分页请求 +`//chat//`,导出使用 `postExportExcel` 请求 +`//chat/export`,查询包含日期、摘要或用户及点赞、点踩下限; +导出请求体为 `{ select_ids }`,空数组表示导出当前筛选结果。 +日志业务类型经 `@/api/types` 导出,来源枚举经 `@/api/enums` 导出,loading 由调用方维护。 +清除策略通过 PUT `batch_clean_time` 提交当前智能体的单元素 `id_list`、`clean_time`、 +`file_clean_time`,避免调用通用应用编辑流程;成功后页面刷新应用详情。 +聊天记录、标注、添加知识库接口保留在同一 API 文件,尚未接入本次日志列表页面。 diff --git a/ui/src/api/admin/workspace/application/chat-log.ts b/ui/src/api/admin/workspace/application/chat-log.ts new file mode 100644 index 00000000000..8d2c45dcf40 --- /dev/null +++ b/ui/src/api/admin/workspace/application/chat-log.ts @@ -0,0 +1,74 @@ +import { del, get, post, postExportExcel, put } from '../../core/request' +import type { ParamsPage, ResponsePage } from '../../core/types' +import type { ChatLog, Dict } from '@/api/types' +import { getWorkspaceId } from '@/utils/resource-context' + +const getPrefix = () => `/workspace/${getWorkspaceId()}/application` + +/** 分页获取智能体对话日志。 */ +const getChatLog = (applicationId: string, page: ParamsPage, query: Dict) => + get>(`${getPrefix()}/${applicationId}/chat/${page.currentPage}/${page.pageSize}`, query) + +/** 导出筛选结果或选中的对话日志。 */ +const postExportChatLog = (applicationId: string, applicationName: string, query: Dict, data: { select_ids: string[] }) => + postExportExcel(`${applicationName}.xlsx`, `${getPrefix()}/${applicationId}/chat/export`, query, data) + +/** 保存当前智能体的日志与文件清除策略。 */ +const putChatLogCleanTime = (applicationId: string, cleanTime: number, fileCleanTime: number) => + put<{ id_list: string[]; clean_time: number; file_clean_time: number }, boolean>(`${getPrefix()}/batch_clean_time`, { + id_list: [applicationId], + clean_time: cleanTime, + file_clean_time: fileCleanTime, + }) + +/** 将对话记录添加至知识库。 */ +const postChatLogAddKnowledge = (applicationId: string, data: Dict) => post(`${getPrefix()}/${applicationId}/add_knowledge`, data) + +/** 分页获取对话中的聊天记录。 */ +const getChatRecordLog = (applicationId: string, chatId: string, page: ParamsPage, orderAsc = true) => + get>>(`${getPrefix()}/${applicationId}/chat/${chatId}/chat_record/${page.currentPage}/${page.pageSize}`, { + order_asc: orderAsc, + }) + +/** 获取聊天记录详情。 */ +const getChatRecordDetails = (applicationId: string, chatId: string, chatRecordId: string) => + get>(`${getPrefix()}/${applicationId}/chat/${chatId}/chat_record/${chatRecordId}`) + +/** 获取聊天记录的标注段落。 */ +const getMarkChatRecord = (applicationId: string, chatId: string, chatRecordId: string) => + get[]>(`${getPrefix()}/${applicationId}/chat/${chatId}/chat_record/${chatRecordId}/improve`) + +/** 保存聊天记录的知识库标注内容。 */ +const putChatRecordLog = ( + applicationId: string, + chatId: string, + chatRecordId: string, + knowledgeId: string, + documentId: string, + data: Dict, +) => put(`${getPrefix()}/${applicationId}/chat/${chatId}/chat_record/${chatRecordId}/knowledge/${knowledgeId}/document/${documentId}/improve`, data) + +/** 删除聊天记录的知识库标注。 */ +const deleteMarkChatRecord = ( + applicationId: string, + chatId: string, + chatRecordId: string, + knowledgeId: string, + documentId: string, + paragraphId: string, +) => + del( + `${getPrefix()}/${applicationId}/chat/${chatId}/chat_record/${chatRecordId}/knowledge/${knowledgeId}/document/${documentId}/paragraph/${paragraphId}/improve`, + ) + +export default { + getChatLog, + postExportChatLog, + putChatLogCleanTime, + postChatLogAddKnowledge, + getChatRecordLog, + getChatRecordDetails, + getMarkChatRecord, + putChatRecordLog, + deleteMarkChatRecord, +} diff --git a/ui/src/api/admin/workspace/chat-user.ts b/ui/src/api/admin/workspace/chat-user.ts index ea937bbbd85..7a8983affca 100644 --- a/ui/src/api/admin/workspace/chat-user.ts +++ b/ui/src/api/admin/workspace/chat-user.ts @@ -1,63 +1,35 @@ -import type { Ref } from 'vue' -import { Result } from '@/request/Result' -import { get, put } from '@/request/index' -import type { ChatUserGroupItem, ChatUserGroupUserItem, putUserGroupUserParams } from '@/api/type/workspaceChatUser' -import type { pageRequest, PageList } from '@/api/type/common' +import { get, put } from '../core/request' +import type { ParamsPage, ResponsePage } from '../core/types' +import type { + ChatUserAuthorization, + ChatUserAuthorizationGroup, + ChatUserAuthorizationResource, + ChatUserGroupAuthorizationPayload, + ChatUserAuthorizationPayload, + Dict, +} from '@/api/types' +import { getWorkspaceId } from '@/utils/resource-context' -import useStore from '@/stores' -const prefix: any = { _value: '/workspace/' } -Object.defineProperty(prefix, 'value', { - get: function () { - const { user } = useStore() - return this._value + user.getWorkspaceId() - }, -}) -/** - * 获取用户组列表 - */ -const getUserGroupList: (resource: any, loading?: Ref) => Promise> = (resource, loading) => { - return get(`${prefix.value}/${resource.resource_type}/${resource.resource_id}/user_group`, undefined, loading) -} +const getPrefix = (resource: ChatUserAuthorizationResource) => `/workspace/${getWorkspaceId()}/${resource.resource_type}/${resource.resource_id}` -/** - * 修改用户组列表授权 - */ -const editUserGroupList: (resource: any, data: { user_group_id: string, is_auth: boolean }[], loading?: Ref) => Promise> = (resource, data, loading) => { - return put(`${prefix.value}/${resource.resource_type}/${resource.resource_id}/user_group`, data, undefined, loading) +/** 获取资源的对话用户组及自动授权状态。 */ +const getUserGroupList = (resource: ChatUserAuthorizationResource) => { + return get(`${getPrefix(resource)}/user_group`) } -/** - * 获取用户组的用户列表 - */ -const getUserGroupUserList: ( - resource: any, - user_group_id: string, - page: pageRequest, - params?: any, - loading?: Ref, -) => Promise>> = (resource, user_group_id, page, params, loading) => { - return get( - `${prefix.value}/${resource.resource_type}/${resource.resource_id}/user_group_id/${user_group_id}/${page.current_page}/${page.page_size}`, - params, - loading, - ) +/** 保存资源的用户组自动授权设置。 */ +const putUserGroupAuthorization = (resource: ChatUserAuthorizationResource, data: ChatUserGroupAuthorizationPayload[]) => { + return put(`${getPrefix(resource)}/user_group`, data) } -/** - * 更新用户组的用户列表 - */ -const putUserGroupUser: ( - resource: any, - user_group_id: string, - data: putUserGroupUserParams[], - loading?: Ref, -) => Promise> = (resource, user_group_id, data, loading) => { - return put(`${prefix.value}/${resource.resource_type}/${resource.resource_id}/user_group_id/${user_group_id}`, data, undefined, loading) +/** 分页查询用户组内的对话用户及资源授权状态。 */ +const getUserGroupUserList = (resource: ChatUserAuthorizationResource, userGroupId: string, page: ParamsPage, query?: Dict) => { + return get>(`${getPrefix(resource)}/user_group_id/${userGroupId}/${page.currentPage}/${page.pageSize}`, query) } -export default { - getUserGroupList, - editUserGroupList, - getUserGroupUserList, - putUserGroupUser +/** 保存用户组内的对话用户资源授权。 */ +const putUserGroupUser = (resource: ChatUserAuthorizationResource, userGroupId: string, data: ChatUserAuthorizationPayload[]) => { + return put(`${getPrefix(resource)}/user_group_id/${userGroupId}`, data) } + +export default { getUserGroupList, putUserGroupAuthorization, getUserGroupUserList, putUserGroupUser } diff --git a/ui/src/api/enums/chat-log.ts b/ui/src/api/enums/chat-log.ts new file mode 100644 index 00000000000..3df46e20120 --- /dev/null +++ b/ui/src/api/enums/chat-log.ts @@ -0,0 +1,12 @@ +/** 对话日志的发起来源。 */ +export const CHAT_LOG_SOURCE = { + ONLINE: 'ONLINE', + API_CALL: 'API_CALL', + ENTERPRISE_WECHAT: 'ENTERPRISE_WECHAT', + WECHAT_PUBLIC_ACCOUNT: 'WECHAT_PUBLIC_ACCOUNT', + LARK: 'LARK', + DINGTALK: 'DINGTALK', + ENTERPRISE_WECHAT_ROBOT: 'ENTERPRISE_WECHAT_ROBOT', + TRIGGER: 'TRIGGER', + SLACK: 'SLACK', +} as const diff --git a/ui/src/api/enums/index.ts b/ui/src/api/enums/index.ts index 0547f89edb8..ae2f2e32120 100644 --- a/ui/src/api/enums/index.ts +++ b/ui/src/api/enums/index.ts @@ -12,3 +12,4 @@ export * from './file' export * from './state' export * from './document' +export * from './chat-log' diff --git a/ui/src/api/types/application.ts b/ui/src/api/types/application.ts index 81782dc72c8..bada2f48a9a 100644 --- a/ui/src/api/types/application.ts +++ b/ui/src/api/types/application.ts @@ -32,6 +32,8 @@ export interface ApplicationDetail extends Omit } export interface ApplicationFormPayload { + clean_time?: number + file_clean_time?: number default_model_setting?: DefaultModelSettingPayload name?: string desc?: string diff --git a/ui/src/api/types/chat-log.ts b/ui/src/api/types/chat-log.ts new file mode 100644 index 00000000000..0bb7d175592 --- /dev/null +++ b/ui/src/api/types/chat-log.ts @@ -0,0 +1,17 @@ +import type { CHAT_LOG_SOURCE } from '@/api/enums' + +export type ChatLogSource = (typeof CHAT_LOG_SOURCE)[keyof typeof CHAT_LOG_SOURCE] + +/** 智能体对话日志列表记录。 */ +export interface ChatLog { + id: string + abstract: string + chat_record_count: number + star_num: number + trample_num: number + mark_sum: number + asker?: { username?: string; nick_name?: string } | null + ip_address?: string | null + source?: { type?: string } | null + update_time: string +} diff --git a/ui/src/api/types/chat-user.ts b/ui/src/api/types/chat-user.ts index af07d7f4a90..5634310ee04 100644 --- a/ui/src/api/types/chat-user.ts +++ b/ui/src/api/types/chat-user.ts @@ -100,3 +100,31 @@ export interface BatchSetChatUserQuotaResult { success_count: number failed_count: number } + +/** 对话用户授权所属的资源。 */ +export interface ChatUserAuthorizationResource { + resource_id: string + resource_type: string +} + +/** 资源内的对话用户组自动授权状态。 */ +export interface ChatUserAuthorizationGroup { + id: string + name: string + is_auth: boolean +} + +/** 用户组内的对话用户资源授权状态。 */ +export interface ChatUserAuthorization extends Pick { + is_auth: boolean +} + +export interface ChatUserGroupAuthorizationPayload { + user_group_id: string + is_auth: boolean +} + +export interface ChatUserAuthorizationPayload { + chat_user_id: string + is_auth: boolean +} diff --git a/ui/src/api/types/document.ts b/ui/src/api/types/document.ts index 5211d5d6a50..8b0fad4298d 100644 --- a/ui/src/api/types/document.ts +++ b/ui/src/api/types/document.ts @@ -6,7 +6,7 @@ export type DocumentTaskType = (typeof DOCUMENT_TASK_TYPE)[keyof typeof DOCUMENT /** 文件各任务的分段计数及状态发生时间。 */ export interface DocumentStatusMeta { - aggs?: { status: string; count: number }[] + aggs?: { status: string | null; count: number }[] state_time?: Partial>>> } diff --git a/ui/src/api/types/index.ts b/ui/src/api/types/index.ts index 1784ea3dfad..c99fd1f083d 100644 --- a/ui/src/api/types/index.ts +++ b/ui/src/api/types/index.ts @@ -27,3 +27,4 @@ export type * from './state' export type * from './portal' export type * from './document' +export type * from './chat-log' diff --git a/ui/src/assets/iconfont.js b/ui/src/assets/iconfont.js index 186494baa7c..af81f216b8b 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,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 +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.d.ts b/ui/src/components.d.ts index faf4d8e35a5..7d426d008ef 100644 --- a/ui/src/components.d.ts +++ b/ui/src/components.d.ts @@ -49,6 +49,7 @@ declare module 'vue' { RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] TableFilterCascader: typeof import('./components/global/mk-table/mk-table-filter/TableFilterCascader.vue')['default'] + TableFilterCustom: typeof import('./components/global/mk-table/mk-table-filter/TableFilterCustom.vue')['default'] TableFilterMultiple: typeof import('./components/global/mk-table/mk-table-filter/TableFilterMultiple.vue')['default'] TableFilterSingle: typeof import('./components/global/mk-table/mk-table-filter/TableFilterSingle.vue')['default'] ToolIcon: typeof import('./components/global/mk-icon/ToolIcon.vue')['default'] @@ -95,6 +96,7 @@ declare global { const RouterLink: typeof import('vue-router')['RouterLink'] const RouterView: typeof import('vue-router')['RouterView'] const TableFilterCascader: typeof import('./components/global/mk-table/mk-table-filter/TableFilterCascader.vue')['default'] + const TableFilterCustom: typeof import('./components/global/mk-table/mk-table-filter/TableFilterCustom.vue')['default'] const TableFilterMultiple: typeof import('./components/global/mk-table/mk-table-filter/TableFilterMultiple.vue')['default'] const TableFilterSingle: typeof import('./components/global/mk-table/mk-table-filter/TableFilterSingle.vue')['default'] const ToolIcon: typeof import('./components/global/mk-icon/ToolIcon.vue')['default'] diff --git a/ui/src/components/COMPONENT_README.md b/ui/src/components/COMPONENT_README.md index a53b010b6ce..85052a23889 100644 --- a/ui/src/components/COMPONENT_README.md +++ b/ui/src/components/COMPONENT_README.md @@ -283,9 +283,10 @@ Dialog、Drawer、Popover、嵌套区域等其他大、小表格均禁止开启 数据写回边界自行 `cloneDeep`,保持 LogicFlow 的可观察树约束。 `MkTableFilter` 放在 `global/mk-table/mk-table-filter/`,公共入口为 `index.vue`。 -入口统一选择模式、渲染触发按钮、计算筛选高亮和回写模型;三个内部组件分别维护对应交互: +入口统一选择模式、渲染触发按钮、计算筛选高亮和回写模型;四个内部组件分别维护对应交互: `TableFilterSingle.vue` 复用 `MkDropdown`、`MkDropdownMenu` 和 `MkDropdownItem`, -`TableFilterMultiple.vue` 管理多选草稿及确认,`TableFilterCascader.vue` 管理级联面板及即时提交。 +`TableFilterMultiple.vue` 管理多选草稿及确认,`TableFilterCascader.vue` 管理级联面板及即时提交, +`TableFilterCustom.vue` 管理对象草稿和自定义内容;多选与自定义模式共用 `TableFilterActions.vue` 的重置、确定按钮。 内部组件通过默认插槽接收同一个触发按钮,只向入口发送 `select` 和 `open`;页面只使用 `MkTableFilter`,不直接引用模式组件。多选与级联继续使用 Popover,不强行统一其提交和关闭行为。 @@ -297,6 +298,7 @@ Dialog、Drawer、Popover、嵌套区域等其他大、小表格均禁止开启 | `multiple` | `TableFilterOption[]` / 字符串、数字或布尔值数组 | 打开时复制草稿,确定后提交;重置提交 `[]`;点击外部丢弃草稿 | | `single` | `TableFilterOption[]` / 字符串、数字或布尔值,加 `null` | 点击立即提交并关闭;“全部”提交 `null` | | `cascader` | Element Plus `CascaderOption[]` / 由 `cascaderProps` 决定 | 勾选立即提交;多选保持打开,单选提交后关闭 | +| `custom` | 不传 options / 自定义对象 | 打开时深拷贝草稿,确定后提交;重置提交 `resetValue` | `TableFilterOption` 位于 `global/mk-table/mk-table-filter/types.ts`,包含 `label`、`value` 和可选 `disabled`;扁平选项不使用空字符串作为业务值。`false`、`0` 都是有效筛选条件,正确高亮筛选图标。 @@ -310,7 +312,14 @@ Dialog、Drawer、Popover、嵌套区域等其他大、小表格均禁止开启 外部模型变更同步面板;自身提交后的模型回写保留原始父组勾选,关闭再打开也保持。 通过 `cascaderProps` 覆盖字段映射、单多选、路径输出及懒加载等原生配置。 级联多选重置为 `[]`,单选重置为 `null`;单选模型需声明可空类型。 -`width` 可覆盖弹层宽度,扁平模式默认 192px,级联默认自适应。 +`width` 可覆盖弹层宽度,扁平模式默认 192px,级联默认自适应,自定义模式默认 240px。 + +自定义模式通过默认作用域插槽接收 `{ value }`,`value` 是可编辑的独立对象草稿,字段类型跟随 +`v-model` 推断;页面用 `v-model="value.xxx"` 绑定输入,不直接修改页面已生效的筛选。 +`resetValue` 传入完整的默认对象,未传时回退 `{}`;固定表单字段应显式传入,避免重置后缺失字段。 +重置和确定都关闭浮层、回写模型并触发 `change`;点击外部关闭不提交,再次打开按当前模型回填。 +草稿、提交值和默认值之间使用 Lodash 深拷贝隔离,图标按已生效对象是否与 `resetValue` 深度相等决定高亮。 +自定义内容放在内置滚动区,页面不再编写 Popover、开关状态或重置、确定按钮。 `change(value)` 在写回模型后触发,类型跟随模型;`open` 在每次打开时触发,供页面加载选项。 组件不请求业务接口、不转换查询参数。文档文件状态用唯一选项值映射为 `status` 和 `task_type`, @@ -334,6 +343,24 @@ Dialog、Drawer、Popover、嵌套区域等其他大、小表格均禁止开启 ``` +```vue + + + + +``` + 表格操作列需要 More 菜单时使用 `MkTableMoreDropdown`。组件统一提供点击型、右下定位的 More 按钮以及 `MkDropdownMenu`,默认插槽中直接放置 `MkDropdownItem`;插槽为空,或其中的条件菜单项 均未渲染时,不显示 More 触发器。其他 Dropdown 属性和事件通过 `$attrs` 传入,菜单容器样式通过 diff --git a/ui/src/components/global/mk-table/mk-table-filter/TableFilterCustom.vue b/ui/src/components/global/mk-table/mk-table-filter/TableFilterCustom.vue new file mode 100644 index 00000000000..e49e76e5a42 --- /dev/null +++ b/ui/src/components/global/mk-table/mk-table-filter/TableFilterCustom.vue @@ -0,0 +1,53 @@ + + + diff --git a/ui/src/components/global/mk-table/mk-table-filter/TableFilterMultiple.vue b/ui/src/components/global/mk-table/mk-table-filter/TableFilterMultiple.vue index de9779d088e..1e0251f58f0 100644 --- a/ui/src/components/global/mk-table/mk-table-filter/TableFilterMultiple.vue +++ b/ui/src/components/global/mk-table/mk-table-filter/TableFilterMultiple.vue @@ -70,7 +70,7 @@ function handleConfirm() { 重置 - 确定 + 确定 diff --git a/ui/src/components/global/mk-table/mk-table-filter/index.vue b/ui/src/components/global/mk-table/mk-table-filter/index.vue index ae1d4bd1b19..4f1e0a1c0e1 100644 --- a/ui/src/components/global/mk-table/mk-table-filter/index.vue +++ b/ui/src/components/global/mk-table/mk-table-filter/index.vue @@ -1,24 +1,27 @@ + + diff --git a/ui/src/views/application-detail/chat-log/clean-strategy/ButtonCleanStrategy.vue b/ui/src/views/application-detail/chat-log/clean-strategy/ButtonCleanStrategy.vue new file mode 100644 index 00000000000..01560ea4e21 --- /dev/null +++ b/ui/src/views/application-detail/chat-log/clean-strategy/ButtonCleanStrategy.vue @@ -0,0 +1,22 @@ + + + diff --git a/ui/src/views/application-detail/chat-log/clean-strategy/CleanStrategyDialog.vue b/ui/src/views/application-detail/chat-log/clean-strategy/CleanStrategyDialog.vue new file mode 100644 index 00000000000..cc65335ee64 --- /dev/null +++ b/ui/src/views/application-detail/chat-log/clean-strategy/CleanStrategyDialog.vue @@ -0,0 +1,95 @@ + + + diff --git a/ui/src/views/application-detail/chat-log/constants.ts b/ui/src/views/application-detail/chat-log/constants.ts new file mode 100644 index 00000000000..2ee77cea940 --- /dev/null +++ b/ui/src/views/application-detail/chat-log/constants.ts @@ -0,0 +1,14 @@ +import { CHAT_LOG_SOURCE } from '@/api/enums' +import type { ChatLogSource } from '@/api/types' + +export const CHAT_LOG_SOURCE_LABELS: Record = { + [CHAT_LOG_SOURCE.ONLINE]: '线上使用', + [CHAT_LOG_SOURCE.API_CALL]: 'API 调用', + [CHAT_LOG_SOURCE.ENTERPRISE_WECHAT]: '企业微信', + [CHAT_LOG_SOURCE.WECHAT_PUBLIC_ACCOUNT]: '微信公众号', + [CHAT_LOG_SOURCE.LARK]: '飞书', + [CHAT_LOG_SOURCE.DINGTALK]: '钉钉', + [CHAT_LOG_SOURCE.ENTERPRISE_WECHAT_ROBOT]: '企业微信机器人', + [CHAT_LOG_SOURCE.TRIGGER]: '触发器', + [CHAT_LOG_SOURCE.SLACK]: 'Slack', +} diff --git a/ui/src/views/application-detail/chat-log/index.vue b/ui/src/views/application-detail/chat-log/index.vue new file mode 100644 index 00000000000..fb5c3c84d62 --- /dev/null +++ b/ui/src/views/application-detail/chat-log/index.vue @@ -0,0 +1,270 @@ + + + diff --git a/ui/src/views/application-detail/chat-user/index.vue b/ui/src/views/application-detail/chat-user/index.vue index 826aeb4c838..a1f646d4ae1 100644 --- a/ui/src/views/application-detail/chat-user/index.vue +++ b/ui/src/views/application-detail/chat-user/index.vue @@ -1,10 +1,214 @@ diff --git a/ui/src/views/application-detail/context.ts b/ui/src/views/application-detail/context.ts index c930aa780e2..c7c6351cc06 100644 --- a/ui/src/views/application-detail/context.ts +++ b/ui/src/views/application-detail/context.ts @@ -10,8 +10,8 @@ import type { ApplicationDetail } from '@/api/types' export interface ApplicationDetailContext { /** 当前共享详情,子页面不能直接替换其引用。 */ application: ComputedRef - /** 重新请求当前 applicationId 的完整详情。 */ - refreshApplicationDetail: () => Promise + /** 重新请求当前 applicationId 的完整详情;showLoading 默认 true,传 false 不修改整页加载状态。 */ + refreshApplicationDetail: (showLoading?: boolean) => Promise /** 使用接口返回的完整详情更新上下文,避免额外请求。 */ replaceApplicationDetail: (applicationDetail: ApplicationDetail) => void } diff --git a/ui/src/views/application-detail/index.vue b/ui/src/views/application-detail/index.vue index 6f8e6e9219b..b2ec52a2f34 100644 --- a/ui/src/views/application-detail/index.vue +++ b/ui/src/views/application-detail/index.vue @@ -36,17 +36,17 @@ function replaceApplicationDetail(applicationDetail: ApplicationDetail) { application.value = applicationDetail } -function refreshApplicationDetail() { +function refreshApplicationDetail(showLoading = true) { const currentApplicationId = applicationId.value if (!currentApplicationId) return Promise.resolve() - loading.value = true + if (showLoading) loading.value = true return ApplicationApi.getApplicationDetail(currentApplicationId) .then((applicationDetail) => { replaceApplicationDetail(applicationDetail) }) .finally(() => { - loading.value = false + if (showLoading) loading.value = false }) } diff --git a/ui/src/views/application-detail/operation-log/index.vue b/ui/src/views/application-detail/operation-log/index.vue deleted file mode 100644 index d24bde1378b..00000000000 --- a/ui/src/views/application-detail/operation-log/index.vue +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/ui/src/views/home/components/HomeStatistics.vue b/ui/src/views/home/components/HomeStatistics.vue index 06a2b975f45..8befd72bc96 100644 --- a/ui/src/views/home/components/HomeStatistics.vue +++ b/ui/src/views/home/components/HomeStatistics.vue @@ -88,7 +88,7 @@ watch(() => [props.workspaceId, props.applicationId], loadMonitoring, { immediat :name="index === 0 ? 'icon_thumbsup_filled' : 'icon_thumbdown_filled'" :size="16" class="shrink-0" - :class="index === 0 ? 'text-[#FFCC00]!' : 'text-danger!'" + :class="index === 0 ? 'text-[#FFC60A]!' : 'text-danger!'" />

{{ numberFormat(series.total) }}

diff --git a/ui/src/views/knowledge-detail/document/components/DocumentStatus.vue b/ui/src/views/knowledge-detail/document/components/DocumentStatus.vue index 70b12a18076..bdfb6e7fba4 100644 --- a/ui/src/views/knowledge-detail/document/components/DocumentStatus.vue +++ b/ui/src/views/knowledge-detail/document/components/DocumentStatus.vue @@ -43,8 +43,8 @@ interface DocumentTaskStatus { failed: boolean } -function getTaskState(status: string, type: DocumentTaskType) { - return status.at(-type) ?? DOCUMENT_TASK_STATE.IGNORED +function getTaskState(status: string | null | undefined, type: DocumentTaskType) { + return status?.at(-type) ?? DOCUMENT_TASK_STATE.IGNORED } /** 按从右起的任务位置解析状态,并汇总对应分段数量。 */