You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

3.4 KiB

设计:管理员用户列表 — 逐用户统计与公开页链接

日期:2026-04-18
状态:已定稿(与产品对话一致)

1. 背景与目标

管理员(代码中与 role === 'admin' 一致,沿用 requireAdmin;不引入新角色)在「用户管理」页需要:

  1. 逐用户统计(表格列):文章数、时间线条目数、RSS 订阅源数。
  2. 跳转与复制:当用户存在 publicSlug 时,可打开站内公开主页 /@{publicSlug},并可将 完整 URLorigin + '/@' + publicSlug)复制到剪贴板。

明确不包含(第一期):RSS 条目总数(rss_items)、全局汇总卡片、代用户登录、仅按可见性过滤后的计数。

2. 统计语义

对每位用户,三个计数均为对应表中 user_id 等于该用户 id 的全表行数不按 visibility 或其它展示规则过滤。理由:该页面向运营/审计,需反映库内真实数据量;若未来要「仅公开内容」计数,应单独开需求并改字段命名以免歧义。

3. 架构与方案选择

在已选方案下:扩展现有 GET /api/admin/users,在同一分页响应中为每个用户返回三个非负整数字段,避免二次请求与 id 合并问题。

未采用:独立 stats 接口、用户表冗余计数列。

4. API 契约

  • 路径GET /api/admin/users(不变)。
  • 鉴权:现有全局 auth + requireAdmin
  • 分页:沿用现有 limit(默认 50,最大 100)、offset
  • 响应users 数组元素在现有字段(id, username, email, role, status, publicSlug, createdAt)基础上增加:
字段 类型 说明
postCount 整数 ≥ 0 posts 表中该 user_id 行数
timelineEventCount 整数 ≥ 0 timeline_events 表中该 user_id 行数
rssFeedCount 整数 ≥ 0 rss_feeds 表中该 user_id 行数

实现细节:使用 Drizzle + SQLite 可维护的聚合方式(例如相关子查询或等价 join),以保证与分页 ORDER BY 一致且性能可接受;user_id 上应可利用现有外键/索引。

5. 前端(用户管理页)

文件app/pages/me/admin/users/index.vue(为主变更点)。

  • 表格新增三列,展示上述三个计数。
  • publicSlug 非空
    • 打开:链到路由 /@{publicSlug}(与站内其它公开页一致)。
    • 复制:点击后写入剪贴板的 URL 应与浏览器打开 /@{publicSlug} 时一致;推荐使用 URL(\/@${publicSlug}`, window.location.origin).href` 生成,避免手写拼接与编码不一致。
  • publicSlug 为空:不渲染可点击外链;复制按钮禁用或隐藏,并显示「—」等占位。
  • 复制失败:向用户展示简短错误提示(与项目现有 toast/通知模式一致)。

6. 错误与边界

  • 计数为 0 时正常显示。
  • 网络或权限错误沿用现有 request/unwrap 行为。

7. 测试

第一期以手动验证为主。若仓库已有 admin 列表或 Drizzle 集成测试惯例,可补充最小用例(例如种子数据下某用户的三个计数);非强制阻塞项,在实现计划中标注。

8. 非目标

  • 不修改 users 表结构。
  • 不增加 rss_items 计数列。
  • 不实现「超级管理员」与 admin 的区分。