diff --git a/docs/develop-guides/changelog.md b/docs/develop-guides/changelog.md index 4ff8d481..f1646afd 100644 --- a/docs/develop-guides/changelog.md +++ b/docs/develop-guides/changelog.md @@ -33,6 +33,7 @@ - 优化图谱抽取器配置:未配置时在图谱中心展示配置入口,抽取方案收敛为 LLM,前端仅保留“更多拓展中”占位;LLM 抽取器使用固定 Prompt + 自定义 Schema,并支持模型参数与并发队列数;已配置后允许修改参数并提示重置重抽风险。修复上传并入库新文件时旧内存 metadata 覆盖数据库图谱配置的问题。 - 新增 Milvus 图谱检索链路:Query 可召回图谱实体和三元组,结合 Chunk 命中实体构造 seed entity,读取 Neo4j 2-hop 子图后用 igraph 执行 PPR,最终以 Chunk 为产物并通过 RRF 与原 Chunk 召回融合;检索配置改为 dataclass 元数据生成,支持 `depend_on` 控制重排序和图检索参数展示。 - 收紧用户管理部门隔离:普通管理员创建用户时固定归属本部门,用户列表、访问选项、详情、更新和删除接口均限制在本部门范围内。 +- 修复用户管理列表超过 100 人时被默认分页截断的问题:前端按 `skip/limit` 分批加载用户,并在用户卡片列表中补充分页渲染。 - 调整 Agent 资源默认选择与运行时上下文:未显式配置工具、知识库、MCP、Skills、子智能体时默认启用当前用户可访问/可用的全部资源,显式选择后按允许列表过滤;Agent 创建前统一完成最终资源权限过滤、知识库 `kb_id` 可见范围派生和 Skill prompt/readable 依赖闭包派生,聊天运行时与文件系统预览复用同一结果。 - 重构 Skills 权限与安装流程:Skill 增加 `source_type/share_config/enabled`,内置 Skill 作为启动同步入库的全局资源,不再保留前端安装/更新状态,支持启停但不允许删除;上传和远程添加统一为解析草稿后确认生效范围,安装 slug 优先读取 `SKILL.md` 的 `slug` 字段并保留 `name` 展示名,压缩包名称不参与 slug 校验;管理端支持编辑生效范围与启停;Agent 运行时按当前用户可访问 Skills 派生 prompt/readable 依赖闭包并限制挂载/激活,Skills prompt 改为模型请求级注入以避免污染 runtime context;主智能体恢复 `install_skill` 工具,允许当前用户安装私有 Skill 并激活当前会话,子智能体配置和运行态均禁用该工具。 - 精简历史兼容层:移除 sandbox provisioner `local` 后端别名、ask_user_question 单问题旧协议、JWT 历史默认密钥特殊判断、内置 Skill `SKILLS.md` 文件名回退、运行事件数字 seq 兼容和前端若干旧字段回退。 diff --git a/web/src/components/UserManagementComponent.vue b/web/src/components/UserManagementComponent.vue index bb333c1d..882c22d7 100644 --- a/web/src/components/UserManagementComponent.vue +++ b/web/src/components/UserManagementComponent.vue @@ -69,7 +69,7 @@ />
-
+
+
+ +
@@ -283,6 +293,8 @@ const userManagement = reactive({ searchKeyword: '', departmentFilter: '', roleFilter: '', + currentPage: 1, + pageSize: 50, error: null, modalVisible: false, modalTitle: '添加用户', @@ -356,6 +368,12 @@ const filteredUsers = computed(() => { }) }) +const paginatedUsers = computed(() => { + const pageSize = Number(userManagement.pageSize) + const start = (userManagement.currentPage - 1) * pageSize + return filteredUsers.value.slice(start, start + pageSize) +}) + // 获取部门列表 const fetchDepartments = async () => { if (!userStore.isSuperAdmin) return // 普通管理员不需要获取所有部门列表 @@ -427,6 +445,23 @@ watch( } ) +watch( + () => [userManagement.searchKeyword, userManagement.departmentFilter, userManagement.roleFilter], + () => { + userManagement.currentPage = 1 + } +) + +watch( + () => filteredUsers.value.length, + (total) => { + const maxPage = Math.max(1, Math.ceil(total / Number(userManagement.pageSize))) + if (userManagement.currentPage > maxPage) { + userManagement.currentPage = maxPage + } + } +) + // 格式化时间显示 const formatTime = (timeStr) => formatDateTime(timeStr) @@ -946,6 +981,12 @@ onMounted(async () => { } } } + + .pagination-section { + display: flex; + justify-content: flex-end; + margin-top: 16px; + } } } diff --git a/web/src/stores/user.js b/web/src/stores/user.js index 6ba4ff3a..90208696 100644 --- a/web/src/stores/user.js +++ b/web/src/stores/user.js @@ -146,19 +146,37 @@ export const useUserStore = defineStore('user', () => { } // 用户管理功能 - async function getUsers() { + async function getUsers({ pageSize = 100 } = {}) { try { - const response = await fetch('/api/auth/users', { - headers: { - ...getAuthHeaders() - } - }) + const users = [] + let skip = 0 - if (!response.ok) { - throw new Error('获取用户列表失败') + while (true) { + const params = new URLSearchParams({ + skip: String(skip), + limit: String(pageSize) + }) + const response = await fetch(`/api/auth/users?${params.toString()}`, { + headers: { + ...getAuthHeaders() + } + }) + + if (!response.ok) { + throw new Error('获取用户列表失败') + } + + const batch = await response.json() + users.push(...batch) + + if (batch.length < pageSize) { + break + } + + skip += pageSize } - return await response.json() + return users } catch (error) { console.error('获取用户列表错误:', error) throw error