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
3.4 KiB
设计:管理员用户列表 — 逐用户统计与公开页链接
日期:2026-04-18
状态:已定稿(与产品对话一致)
1. 背景与目标
管理员(代码中与 role === 'admin' 一致,沿用 requireAdmin;不引入新角色)在「用户管理」页需要:
- 逐用户统计(表格列):文章数、时间线条目数、RSS 订阅源数。
- 跳转与复制:当用户存在
publicSlug时,可打开站内公开主页/@{publicSlug},并可将 完整 URL(origin + '/@' + 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的区分。