Repository navigation
v0.0.27 — 用户列表服务端分页、Tab 标题修复与后台交互细节打磨
用户管理改为真正的服务端分页(响应带
total),浏览器标签页标题恢复由路由驱动,访问令牌复制在 HTTP 环境下不再静默失败,表单校验错误也变成了用户能看懂的中英文提示。
中文
✨ 新增功能
- 用户管理服务端分页:
GET /api/user/新增page(1 基页号)与pageSize(兼容page_size,上限 100)参数,响应在保留data数组的前提下新增total/page/page_size。前端分页条改由真实总数驱动,展示「共 N 条 · 第 X / Y 页」,并支持切换每页条数。 - 可读的表单校验提示:新增
common.ValidationMessage,把 validator 的字段 + 规则映射为中英文文案(如「密码长度不能少于 8 位」),多个字段错误以「;」/「; 」拼接;无法识别的字段回落为「该字段」/「value」,不再输出Key: 'User.Password' ... failed on the 'min' tag这类英文原文。 - Tab 标题可测化:新增前端纯函数
src/utils/title.js与 Node 单测,标题拼装规则(页面标题 + 站点名、i18n 未命中回落)可独立验证。
🐛 问题修复
- 浏览器标签页标题被后端覆盖:此前
/api/status返回的system_name(默认可能是one-api)会无条件改写document.title,导致刷新后标题变成站点配置值。现在标题只由路由meta.title+ 固定站点名ONE-API-PRO生成,并为所有页面补齐meta.title,切换语言时即时刷新。 - 访问令牌复制在 HTTP 环境下静默失败:
navigator.clipboard在非安全上下文(http 访问)或被拒绝授权时不可用,且原实现只挂了then,失败无任何反馈。现改为异步 +try/catch,自动降级到隐藏 textarea +execCommand('copy'),仍然失败时提示「复制失败,请手动选中复制」。 - 用户列表翻页错位:旧的「是否已到末页」推算会在总数变化或快速翻页时渲染空页/多一页,并引用了未定义的
pageTotal。现在页数完全来自后端total,并加入fetchSeq竞态保护与越界页回退。 - 用户列表
total与过滤条件不一致:新增model.CountAllUsers(),与GetAllUsers()使用完全相同的过滤条件(排除已删除用户),保证列表为空时总数依然准确。
🔧 重构
- 个人设置页精简:移除「个人信息」与「访问令牌」两个分区及其表单状态与保存逻辑,相关能力统一收敛到右上角用户菜单的弹窗,页面只保留推广链接、第三方绑定与危险操作区。
- 令牌弹窗交互:「访问令牌」弹窗在输入框右侧内嵌复制图标(带 tooltip 与
aria-label),并在上方提示「令牌(仅显示一次,请复制保存)」。
⚠️ 升级注意事项
GET /api/user/的data仍为数组,新增字段为向后兼容的附加字段;只传旧参数p(0 基页索引)的调用方行为不变。- 个人设置页不再提供修改个人资料与生成访问令牌的入口,请使用右上角用户菜单。
- 无数据库结构变更,无需执行迁移脚本。
English
✨ New Features
- Server-side pagination for user management:
GET /api/user/now acceptspage(1-based) andpageSize(alsopage_size, capped at 100), and the response keeps thedataarray while addingtotal/page/page_size. The frontend pager is driven by the real total, renders 「N total · Page X of Y」, and lets users change the page size. - Human-readable validation messages: new
common.ValidationMessagemaps each validator field + rule to zh/en copy (e.g. "password length must be at least 8 characters"), joins multiple field errors with "; ", and falls back to a generic label for unknown fields — raw strings likeKey: 'User.Password' ... failed on the 'min' tagare never returned. - Testable tab titles: new frontend pure-function module
src/utils/title.jswith Node unit tests, so title composition (page title + site name, i18n miss fallback) can be verified in isolation.
🐛 Bug Fixes
- Tab title overwritten by the backend:
/api/statusused to assigndocument.title = system_name(whose default could beone-api) on every load, so a refresh replaced the page title with the configured site name. Titles are now derived only from the routemeta.titleplus the fixed site nameONE-API-PRO; every page declaresmeta.titleand the title refreshes on locale change. - Token copy silently failed over HTTP:
navigator.clipboardis unavailable in non-secure contexts (plain http) or when permission is denied, and the old implementation only chained.then, so nothing happened on failure. Copying is now async withtry/catch, degrades to a hidden textarea +execCommand('copy'), and reports "Copy failed. Please select and copy manually." when even that fails. - Misaligned user-list paging: the old "have we reached the last page" heuristic rendered empty or extra pages when the total changed or pages were clicked quickly, and referenced an undefined
pageTotal. The page count now comes from the backendtotal, with afetchSeqrace guard and out-of-range page fallback. - User
totaldisagreed with the list filter: addedmodel.CountAllUsers(), which applies exactly the same filter asGetAllUsers()(soft-deleted users excluded), so the total stays accurate even when the page is empty.
🔧 Refactor
- Streamlined personal settings page: removed the 「Profile」 and 「Access Token」 sections together with their form state and save logic; both capabilities now live in the top-right user-menu modal, leaving promotion link, third-party bindings and the danger zone on the page.
- Token modal interaction: the access-token input now embeds a copy icon in its suffix (with tooltip and
aria-label), plus the hint 「Token (shown only once, please copy and save it)」 above it.
⚠️ Upgrade Notes
datainGET /api/user/remains an array; the new fields are additive. Callers that only send the legacyp(0-based page index) parameter keep their current behavior.- The personal settings page no longer exposes profile editing or access-token generation; use the top-right user menu instead.
- No database schema changes and no migration script required.