Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion ui/src/api/API_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,17 @@ FormData;保存返回完整配置,页面以该返回值作为唯一数据来
`admin/auth/current-user.ts` 的 postCurrentUserPassword 向 `/user/current/reset_password`
提交 RSA 加密的 `{ encryptedData }`;调用方校验与加密,成功清除凭据后进入登录。

### 系统用户列表排序

系统用户分页排序以 `order_by` 传入 `create_time`;对话用户分页传入 `create_time` 或 `used_tokens`,
后者从列字段 `token_quota.used_tokens` 映射。升序使用字段原名,降序添加 `-`,取消排序不传值。
排序由服务端处理,不做前端当前页排序。

### 操作日志排序

操作日志列表与导出共用查询条件,操作时间排序通过 `order_by` 传入 `create_time` 或 `-create_time`,
取消排序不传值。

### 平台许可证

`admin/system/license.ts` 通过 GET、PUT `/license/profile` 查询和更新授权信息,
Expand Down Expand Up @@ -592,7 +603,8 @@ Workspace 共享 Paragraph API 仅 getParagraphPage、getParagraphDetail,不

四范围 `knowledge/problem.ts` 使用各自知识库前缀追加 `/<knowledgeId>/problem`,
由知识库及文档详情上下文的 `resourceApi.problem` 选择,不固定 Workspace。
`getProblemsPage(knowledgeId, page, query)` 返回 `ResponsePage<ProblemItem>`,query 仅传 content。
`getProblemsPage(knowledgeId, page, query)` 返回 `ResponsePage<ProblemItem>`,query 支持 content 和 order_by。
排序字段为 paragraph_count、hit_num、last_hit_time、create_time、update_time,降序在字段名前加 `-`。
`ProblemItem` 包含 id、content、paragraph_count、hit_num、last_hit_time、create_time、update_time;
分段已有问题仍使用轻量 `ParagraphProblem`,不要求包含列表统计字段。

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { del, get, post, put } from '@/api/admin/core/request'
import type { ParamsPage, ResponsePage } from '@/api/admin/core/types'
import type { ProblemItem, ProblemBatchAssociationPayload, ProblemParagraph } from '@/api/types'
import type { Dict, ProblemItem, ProblemBatchAssociationPayload, ProblemParagraph } from '@/api/types'

const getPrefix = (knowledgeId: string) => `/system/resource/knowledge/${knowledgeId}/problem`

/** 批量创建知识库问题。 */
const postProblems = (knowledgeId: string, contents: string[]) => post<string[], void>(getPrefix(knowledgeId), contents)

/** 分页搜索知识库问题,供问题列表及分段关联候选使用。 */
const getProblemsPage = (knowledgeId: string, page: ParamsPage, query?: { content?: string }) =>
const getProblemsPage = (knowledgeId: string, page: ParamsPage, query?: Dict<unknown>) =>
get<ResponsePage<ProblemItem>>(`${getPrefix(knowledgeId)}/${page.currentPage}/${page.pageSize}`, query)

/** 编辑单个知识库问题的内容。 */
Expand Down
4 changes: 2 additions & 2 deletions ui/src/api/admin/system/shared-resources/knowledge/problem.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { del, get, post, put } from '@/api/admin/core/request'
import type { ParamsPage, ResponsePage } from '@/api/admin/core/types'
import type { ProblemItem, ProblemBatchAssociationPayload, ProblemParagraph } from '@/api/types'
import type { Dict, ProblemItem, ProblemBatchAssociationPayload, ProblemParagraph } from '@/api/types'

const getPrefix = (knowledgeId: string) => `/system/shared/knowledge/${knowledgeId}/problem`

/** 批量创建知识库问题。 */
const postProblems = (knowledgeId: string, contents: string[]) => post<string[], void>(getPrefix(knowledgeId), contents)

/** 分页搜索知识库问题,供问题列表及分段关联候选使用。 */
const getProblemsPage = (knowledgeId: string, page: ParamsPage, query?: { content?: string }) =>
const getProblemsPage = (knowledgeId: string, page: ParamsPage, query?: Dict<unknown>) =>
get<ResponsePage<ProblemItem>>(`${getPrefix(knowledgeId)}/${page.currentPage}/${page.pageSize}`, query)

/** 编辑单个知识库问题的内容。 */
Expand Down
4 changes: 2 additions & 2 deletions ui/src/api/admin/workspace/knowledge/problem.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { del, get, post, put } from '../../core/request'
import type { ParamsPage, ResponsePage } from '../../core/types'
import type { ProblemItem, ProblemBatchAssociationPayload, ProblemParagraph } from '@/api/types'
import type { Dict, ProblemItem, ProblemBatchAssociationPayload, ProblemParagraph } from '@/api/types'
import { getWorkspaceId } from '@/utils/resource-context'

const getPrefix = (knowledgeId: string) => `/workspace/${getWorkspaceId()}/knowledge/${knowledgeId}/problem`
Expand All @@ -9,7 +9,7 @@ const getPrefix = (knowledgeId: string) => `/workspace/${getWorkspaceId()}/knowl
const postProblems = (knowledgeId: string, contents: string[]) => post<string[], void>(getPrefix(knowledgeId), contents)

/** 分页搜索知识库问题,供问题列表及分段关联候选使用。 */
const getProblemsPage = (knowledgeId: string, page: ParamsPage, query?: { content?: string }) =>
const getProblemsPage = (knowledgeId: string, page: ParamsPage, query?: Dict<unknown>) =>
get<ResponsePage<ProblemItem>>(`${getPrefix(knowledgeId)}/${page.currentPage}/${page.pageSize}`, query)

/** 编辑单个知识库问题的内容。 */
Expand Down
4 changes: 2 additions & 2 deletions ui/src/api/admin/workspace/shared/knowledge/problem.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { get } from '../../../core/request'
import type { ParamsPage, ResponsePage } from '../../../core/types'
import type { ProblemItem } from '@/api/types'
import type { Dict, ProblemItem } from '@/api/types'
import { getWorkspaceId } from '@/utils/resource-context'

const getPrefix = (knowledgeId: string) => `/system/shared/workspace/${getWorkspaceId()}/knowledge/${knowledgeId}/problem`

/** 分页查询工作空间共享知识库的问题,只提供只读访问。 */
const getProblemsPage = (knowledgeId: string, page: ParamsPage, query?: { content?: string }) =>
const getProblemsPage = (knowledgeId: string, page: ParamsPage, query?: Dict<unknown>) =>
get<ResponsePage<ProblemItem>>(`${getPrefix(knowledgeId)}/${page.currentPage}/${page.pageSize}`, query)

export default { getProblemsPage }
15 changes: 12 additions & 3 deletions ui/src/views/VIEW_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@
- Python 生成入口由 `CodeGenerate` 选择 Tool/Model API,复用 `GenerateContent`;全屏替换只修改草稿,确认后回写。
- System 模型/工具使用表格,保留既有权限、引用数量删除提示和末页回退;不新增不存在的创建/导入能力。
工作空间列与选项仅企业版显示,筛选 `workspace_ids` 使用 JSON 数组字符串。
- System 资源管理智能体列表支持发布时间、创建时间排序;知识库、工具、模型列表支持更新时间、创建时间排序。
通过 `toOrderBy` 将时间列转换为 `order_by` 查询参数,切换排序回第一页;搜索、筛选及分页保留排序,取消排序不传值。
- Workspace 共享知识库只读;System 共享资源页面按自身 API 维护,不组合 Workspace 文件夹移动等操作。
- System 共享知识库、模型、工具菜单复用功能本地 `authorized-workspace-action/index.vue`,打开同目录的
`AuthorizedWorkspaceDialog` 配置工作空间白名单/黑名单;保留弹窗实例,关闭动画结束后清空本次数据,
Expand Down Expand Up @@ -208,7 +210,7 @@ System 资源管理或 System 共享 Knowledge API 的 `postKnowledgeHitTest`;
- 名称使用 `MkEditName`,最长 128,禁止 `: \ / ? * [ ]`;成功按 ID 更新名称与时间。
- 文件状态、启用、命中处理用 `MkTableFilter single`,标签用 `cascader`;改变条件回第一页并清空选择,保留其他条件。
状态查询同步更新 `status` 与 `task_type`;布尔 false 保留,“全部”省略条件;标签传叶子 ID 或 `NO_TAG`。
- 字符数使用服务端表头排序,通过 `toOrderBy` 更新独立的 `orderBy`,请求时作为 `order_by` 传入;切换排序回第一页并清空选择,
- 字符数、分段数、召回次数、最后一次召回时间、创建者、创建时间和更新时间使用服务端表头排序,通过 `toOrderBy` 更新独立的 `orderBy`,请求时作为 `order_by` 传入;切换排序回第一页并清空选择,
取消排序恢复后端默认顺序。搜索、筛选、分页和轮询保留当前排序,导入成功清空搜索及筛选时也保留排序。
- 任务解析及筛选统一在 `document/status.ts`,展示由 `DocumentStatus.vue` 负责;不复用执行记录状态。
汇总优先级为取消中、执行中、排队中、失败、取消完成、成功;忽略未知和 n,保留取消完成显示成功的既有规则。
Expand Down Expand Up @@ -253,7 +255,8 @@ System 资源管理或 System 共享 Knowledge API 的 `postKnowledgeHitTest`;

### 问题管理

`problem/` 使用 `resourceApi.problem`,默认每页 20 条,不提供表头排序,搜索将 content 传给后端。
`problem/` 使用 `resourceApi.problem`,默认每页 20 条,搜索将 content 传给后端。
关联分段数、召回次数、最近一次召回时间、创建时间和更新时间使用 `order_by` 表头排序;切换排序清空选择并查询第一页,搜索和分页保留排序。
`ButtonCreateProblem` 内聚创建按钮和多行输入弹窗;快捷创建使用 `MkQuickCreate`,每个问题最多 256 字符。
单项与批量删除直接提交,删除后末页为空时回退到最后有效页;名称编辑复用 `MkEditName`。
点击数据行打开 `ProblemDetailDrawer`,勾选、名称编辑和操作按钮不触发行详情。
Expand Down Expand Up @@ -324,7 +327,6 @@ View 负责路由、资源与模式、图加载、保存/发布/调试编排
- 工具、知识库执行记录抽屉按需挂载,关闭后卸载;知识库记录每 6 秒刷新,关闭停止。
执行时间列声明 `sortable`,独立 `orderBy` 通过 `toOrderBy` 添加 `ett.` 前缀,以 `order` 查询参数传入。
切换排序回第一页;搜索、筛选、分页与轮询保留排序,重新打开时恢复默认排序。
当前本地后端两类接口仍固定按执行时间降序,需支持 `order` 后才能实际响应升序请求。

## 其他页面约束

Expand Down Expand Up @@ -372,12 +374,14 @@ View 负责路由、资源与模式、图加载、保存/发布/调试编排
概览内暂时隐藏卡片详情入口,不接入排行抽屉、搜索、分页或导出。
- 触发器执行记录的执行时间列使用服务端排序,独立 `orderBy` 经 `toOrderBy` 添加 `ett.` 前缀,
通过查询参数 `order` 传入。切换排序回第一页;搜索、分页和详情跨页保留排序,重新打开抽屉恢复默认排序。
- 触发器列表的下次执行时间、创建时间使用 `order_by` 表头排序,切换时清空选择并回到第一页;搜索、筛选和分页保留排序。
- 触发器表单共用创建/编辑,保留任务 ID 和参数;资源模式固定单任务,完整输入定义不足时补查详情。
保存校验全部折叠任务;参数初始化不覆盖已配置值,移除事件引用时恢复自定义默认值。
- 智能体/知识库对话用户页使用双栏布局和当前页授权;智能体从 context 取 Workspace/System 资源管理 ChatUser API,知识库取四范围 API。
自动授权立即保存,手动保存只提交当前页;请求共用 loading 与 inert,失败保留勾选。
授权人数取 `authorized_count`,不以分页勾选推算。
- 对话日志筛选、导出使用同组查询;无勾选导出筛选结果,日期清空禁用导出。
对话次数、对话用户、最近对话时间使用 `order_by` 表头排序,用户列映射为 `username`;切换时清空选择并回到第一页,筛选、分页和导出保留排序。
清除策略通过当前范围 ChatLog API 保存、使用弹窗自身 loading;添加知识库固定所选对话 ID,选项使用当前范围 Knowledge/Document API。
`ChatLogDetailDrawer` 使用现有 `LogConversation` 展示只读历史对话与执行详情,正文查询仍使用 Workspace API;上一条/下一条与跨页由页面管理。
- 外部检索页从 context 读取四范围 ExternalRetrieval API;Workspace 共享只读,禁用开关并阻止提交。
Expand All @@ -388,6 +392,11 @@ View 负责路由、资源与模式、图加载、保存/发布/调试编排
默认登录方式仅展示草稿中已选的 `login_value`;跨域地址按行清理,取消不回写。
- 用户导入、改密、批量角色/配额流程留在各自业务目录;工作空间成员按用户联动角色行选择,
删除按 `user_relation_id` 去重,不按用户 ID 丢弃角色记录。
- 系统用户列表的创建时间、对话用户列表的 Tokens 使用量和创建时间使用服务端表头排序。
切换排序清空选择并回到第一页,搜索、筛选和分页保留排序;取消排序恢复后端默认顺序。
排序参数见 API 文档。
- 系统操作日志的操作时间使用服务端表头排序,切换后回到第一页,保留搜索及筛选条件。
分页和导出沿用当前排序条件,取消排序不传排序值。
- 登录页使用 `formEl.validate` 回调和清晰的 LDAP/本地分支,不额外抽象或改写提交控制流程。
- Chat/Portal 页面以 auth token 为面板 key,token 变化重建并加载用户档案;路由认证见路由文档。
会话装配在 conversation-panel,列表 Store 不感知 Router;门户复用 chat 装配,保留各智能体最近会话分组。
Expand Down
18 changes: 15 additions & 3 deletions ui/src/views/application-detail/chat-log/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import MkDateRange from '@/components/mk-date-range/index.vue'
import type { MkDateRangeValue } from '@/components/mk-date-range/types'
import type { ResourceDetailPageProps } from '@/layout/ResourceDetailLayout.vue'
import { beforeDay, datetimeFormat } from '@/utils/time'
import { toOrderBy } from '@/utils/common'
import { useApplicationDetailContext } from '../context'
import ButtonCleanStrategy from './clean-strategy/ButtonCleanStrategy.vue'
import ButtonAddKnowledge from './add-knowledge/ButtonAddKnowledge.vue'
Expand All @@ -22,6 +23,7 @@ const { application, applicationId, resourceApi } = useApplicationDetailContext(
// 日志搜索与日期筛选
const loading = ref(false)
const chatLogs = ref<ChatLog[]>([])
const orderBy = ref<string>()
const paginationConfig = ref({ currentPage: 1, pageSize: 20, total: 0 })
const sourceOptions: OptionItem<string>[] = Object.entries(CHAT_LOG_SOURCE_LABELS).map(([value, label]) => ({ value, label }))
const searchFields: OptionItem<string>[] = [
Expand Down Expand Up @@ -59,11 +61,20 @@ function handleFeedbackChange() {
const chatLogQuery = computed<Dict<unknown>>(() => ({
...chatLogSearchQuery.value,
...chatLogDateQuery.value,
order_by: orderBy.value,
...(selectedFeedback.value === 'star' ? { min_star: 1 } : {}),
...(selectedFeedback.value === 'trample' ? { min_trample: 1 } : {}),
comparer: 'and',
}))

/* 表头排序:清空选择并重新查询第一页。 */
function handleSortChange(sort: Parameters<typeof toOrderBy>[0]) {
orderBy.value = toOrderBy(sort, (prop) => (prop === 'asker.username' ? 'username' : prop))
chatLogTableRef.value?.clearSelection()
paginationConfig.value.currentPage = 1
return loadChatLogs()
}

function loadChatLogs(currentPage = paginationConfig.value.currentPage): Promise<ChatLog[]> {
// 自定义日期清空后等待重新选择,避免提交后端不接受的空日期。
if (!chatLogDateQuery.value.start_time) {
Expand Down Expand Up @@ -190,13 +201,14 @@ onMounted(() => loadChatLogs())
@current-change="loadChatLogs()"
@size-change="loadChatLogs()"
@selection-change="handleSelectionChange"
@sort-change="handleSortChange"
@row-click="handleRowClick"
row-class-name="cursor-pointer"
resizable
>
<el-table-column type="selection" width="40" />
<el-table-column prop="abstract" label="摘要" min-width="220" show-overflow-tooltip />
<el-table-column prop="chat_record_count" label="对话次数" width="100" />
<el-table-column prop="chat_record_count" label="对话次数" width="100" sortable />
<el-table-column width="140">
<template #header>
<MkTableFilter v-model="selectedFeedback" mode="single" label="用户反馈" :options="feedbackOptions" @change="handleFeedbackChange" />
Expand All @@ -216,7 +228,7 @@ onMounted(() => loadChatLogs())
</template>
</el-table-column>
<el-table-column prop="mark_sum" label="改进标注" width="100" />
<el-table-column label="用户" min-width="130" show-overflow-tooltip>
<el-table-column prop="asker.username" label="用户" min-width="130" show-overflow-tooltip sortable>
<template #default="{ row }">{{ row.asker?.username || '-' }}</template>
</el-table-column>
<el-table-column label="IP 地址" width="140" show-overflow-tooltip>
Expand All @@ -225,7 +237,7 @@ onMounted(() => loadChatLogs())
<el-table-column label="来源" min-width="140" show-overflow-tooltip>
<template #default="{ row }">{{ formatSource(row.source?.type) }}</template>
</el-table-column>
<el-table-column label="最近对话时间" width="180">
<el-table-column prop="update_time" label="最近对话时间" width="180" sortable>
<template #default="{ row }">{{ datetimeFormat(row.update_time) }}</template>
</el-table-column>
<template #footer-batch-actions>
Expand Down
10 changes: 5 additions & 5 deletions ui/src/views/knowledge-detail/library/document/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -457,19 +457,19 @@ onBeforeUnmount(() => {
{{ DOCUMENT_HIT_HANDLING_LABELS[row.hit_handling_method] }}
</template>
</el-table-column>
<el-table-column prop="hit_num" label="召回次数">
<el-table-column prop="hit_num" width="120" label="召回次数" sortable>
<template #default="{ row }">
{{ numberFormat(row.hit_num) }}
</template>
</el-table-column>
<el-table-column label="最后一次召回时间" width="180">
<el-table-column prop="last_hit_time" label="最后一次召回时间" width="180" sortable>
<template #default="{ row }">{{ datetimeFormat(row.last_hit_time) }}</template>
</el-table-column>
<el-table-column prop="nick_name" label="创建者" show-overflow-tooltip />
<el-table-column label="更新时间" width="180">
<el-table-column prop="nick_name" width="120" label="创建者" show-overflow-tooltip sortable />
<el-table-column prop="update_time" label="更新时间" width="180" sortable>
<template #default="{ row }">{{ datetimeFormat(row.update_time) }}</template>
</el-table-column>
<el-table-column label="创建时间" width="180">
<el-table-column prop="create_time" label="创建时间" width="180" sortable>
<template #default="{ row }">{{ datetimeFormat(row.create_time) }}</template>
</el-table-column>
<el-table-column label="操作" width="160" fixed="right" v-if="!isWorkspaceSharedResource()">
Expand Down
Loading
Loading