library-picturebook-activity/docs/design/super-admin/unified-user-management.md
aid 418aa57ea8 Day4: 超管端设计优化 + UGC绘本创作社区P0实现
一、超管端设计优化
- 文档管理SOP体系建立,docs目录重组
- 统一用户管理:跨租户全局视角,合并用户管理+公众用户
- 活动监管全模块重构:全部活动(统计卡片+阶段筛选+SuperDetail详情页)、报名数据/作品数据/评审进度(两层合一扁平列表)、成果发布(去Tab+统计+隐藏写操作)
- 菜单精简:移除评委管理/评审规则/通知管理
- Bug修复:租户编辑丢失隐藏菜单、pageSize限制、主色统一

二、UGC绘本创作社区P0
- 数据库:10张新表(user_works/user_work_pages/work_tags等)
- 子女账号独立化:Child升级为独立User,家长切换+独立登录
- 用户作品库:CRUD+发布审核,8个API
- AI创作流程:提交→生成→保存到作品库,4个API
- 作品广场:首页改造为推荐流,标签+搜索+排序
- 内容审核(超管端):作品审核+作品管理+标签管理
- 活动联动:WorkSelector作品选择器
- 布局改造:底部5Tab(发现/创作/活动/作品库/我的)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 22:20:25 +08:00

295 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 统一用户管理 — 设计方案
> 所属端:超管端
> 状态:已实现(待验收)
> 创建日期2026-03-27
> 最后更新2026-03-27
---
## 1. 背景与问题
超管端"用户中心"下有两个用户管理页面:"用户管理"和"公众用户管理",存在以下问题:
| 问题 | 说明 |
|------|------|
| 超管看不到全局用户 | "用户管理"只显示 super 租户的用户,看不到 gdlib、judge、public 等租户的用户 |
| 用户类型无法区分 | 表格里没有"所属租户"或"用户类型"列,不知道用户属于哪个机构 |
| 两个页面职责重叠又割裂 | "用户管理"管 super 用户,"公众用户"管 public 用户,机构用户和评委谁都管不到 |
| 公众用户缺少管理操作 | 不能禁用异常账号、不能编辑信息 |
| 用户管理缺少关键字段 | 没有手机号、来源、城市等字段展示 |
| 没有搜索功能 | "用户管理"页面无任何筛选手段 |
**目标**:将两个页面合并为一个统一的用户管理页面,超管可以在全局视角下查看、筛选、管理所有类型的用户。
---
## 2. 现状分析
### 2.1 用户数据模型
系统通过 **租户归属 + 角色 + 来源** 三层组合区分用户类型:
```
用户类型推导规则:
├── tenant.isSuper === 1 → 平台用户(运营团队)
├── tenant.code === 'public' → 公众用户(家长/独立参与者)
├── tenant.code === 'judge' → 评委
└── 其他租户 → 机构用户
```
User 模型关键字段:`tenantId`, `username`, `nickname`, `phone`, `city`, `birthday`, `gender`, `userSource`, `status`, `organization`
### 2.2 现有页面
**用户管理**`views/system/users/Index.vue`
- 数据来源:`GET /api/users`,按 `req.tenantId` 过滤,超管只看到 super 租户用户
- 表格列ID、用户名、昵称、邮箱、角色、状态、创建时间
- 操作:新增、编辑、改密、删除
- 无搜索功能
**公众用户管理**`views/system/public-users/Index.vue`
- 数据来源:`GET /api/public/users`,专查 public 租户用户
- 表格列:用户信息(头像+昵称)、手机号、城市、子女数、报名数、状态、注册时间
- 操作查看详情Drawer 展示子女+报名记录)
- 有关键词搜索,但不能禁用/编辑
### 2.3 现有后端接口
```
GET /api/users — 按 tenantId 隔离,返回当前租户的用户
GET /api/users/:id — 用户详情
POST /api/users — 创建用户
PATCH /api/users/:id — 更新用户
DELETE /api/users/:id — 删除用户
GET /api/public/users — 公众用户列表(独立接口)
GET /api/public/users/:id — 公众用户详情(含子女+报名)
```
---
## 3. 设计方案
### 3.1 整体思路
合并"用户管理"和"公众用户管理"为一个页面,超管端通过统计卡片 + 筛选条件实现分类查看,详情 Drawer 根据用户类型展示不同内容。菜单层面移除"公众用户管理"入口。
### 3.2 页面设计
#### 页面结构
```
┌─ 标题卡片 ─────────────────────────────────────────────┐
│ 用户管理 │
└────────────────────────────────────────────────────────┘
┌─ 统计卡片(一行,可点击切换)──────────────────────────────┐
│ [全部 128] [平台 3] [机构 15] [评委 8] [公众 102] │
└────────────────────────────────────────────────────────┘
┌─ 筛选栏 ───────────────────────────────────────────────┐
│ 关键词:[_______] 所属机构:[下拉] 用户来源:[下拉] │
│ 状态:[下拉] [搜索] [重置] │
└────────────────────────────────────────────────────────┘
┌─ 数据表格 ─────────────────────────────────────────────┐
│ 用户信息 | 用户类型 | 所属机构 | 手机号 | 城市 | │
│ | 角色 | 来源 | 注册时间 | 操作 | │
└────────────────────────────────────────────────────────┘
```
#### 统计卡片
- 5 张卡片横排,每张显示:类型图标 + 类型名称 + 数量
- 选中的卡片高亮(主色边框),点击 = 设置 userType 筛选
- 点"全部"清除类型筛选
- 数据来源:`GET /api/users/stats`
#### 筛选栏
| 筛选项 | 组件 | 可选值 | 联动逻辑 |
|--------|------|--------|---------|
| 关键词 | Input | 用户名/昵称/手机号 | — |
| 所属机构 | Select | 租户下拉列表 | 仅 userType 为空或 "org" 时显示 |
| 用户来源 | Select | 管理员创建 / 自主注册 | — |
| 状态 | Select | 正常 / 禁用 | — |
#### 表格列
| 列 | 宽度 | 渲染方式 |
|----|------|----------|
| 用户信息 | 220 | 头像 + 昵称 + @用户名(竖排布局)|
| 用户类型 | 90 | Tag颜色区分蓝=平台,绿=机构,橙=评委,紫=公众 |
| 所属机构 | 140 | tenant.name公众/平台用户显示 "-" |
| 手机号 | 130 | phone 或 "-" |
| 城市 | 100 | city 或 "-" |
| 角色 | 120 | 角色名 Tag 列表 |
| 来源 | 90 | Tag管理创建/ 自主注册(蓝)|
| 注册时间 | 160 | YYYY-MM-DD HH:mm |
| 操作 | 140 | 查看详情 / 更多下拉(禁用/启用、重置密码)|
#### 操作设计
| 操作 | 说明 | 权限 |
|------|------|------|
| 查看详情 | 打开右侧 Drawer | 所有用户可查看 |
| 禁用/启用 | 切换 status 字段 | 不能禁用自己,不能禁用其他租户的唯一管理员 |
| 重置密码 | 弹窗输入新密码 | — |
注意:超管不提供"新增用户"和"删除用户"操作。新增用户应在各自端完成(机构管理端创建机构用户,公众端自主注册),删除用户风险过高,只提供禁用。
#### 详情 Drawer按用户类型适配内容
**通用区域**(所有类型):
```
基本信息 — Descriptions 组件
├── 昵称 / 用户名 / 手机号 / 邮箱
├── 城市 / 性别 / 所属单位
├── 所属机构 / 角色 / 用户来源
└── 注册时间 / 状态
```
**公众用户额外区域**
```
子女信息N个
├── 姓名 / 年龄 / 年级 / 城市 / 学校
报名记录近20条
├── 活动名称 / 报名状态 / 参与者(本人/子女名) / 报名时间
```
**评委额外区域**
```
评审活动
├── 活动名称 / 评审状态 / 已评/总数
```
**机构用户额外区域**
```
权限概览
├── 拥有角色 / 权限数量
```
### 3.3 后端改动
#### 3.3.1 改造 GET /api/users扩展查询参数
超管isSuper=1调用时
- 不按 `req.tenantId` 过滤,查全部用户
- 新增查询参数:
| 参数 | 类型 | 说明 |
|------|------|------|
| `userType` | string? | `platform` / `org` / `judge` / `public`,映射到租户条件 |
| `filterTenantId` | number? | 指定机构筛选 |
| `userSource` | string? | `admin_created` / `self_registered` |
| `status` | string? | `enabled` / `disabled` |
| `keyword` | string? | 搜索范围增加 phone 字段 |
- 返回字段增加:
- `tenant: { id, name, code, tenantType, isSuper }`(用于前端推导用户类型)
- `_count: { children, contestRegistrations }`(公众用户的子女数和报名数)
普通租户调用时:保持现有逻辑不变。
userType 映射逻辑:
```
platform → tenant.isSuper = 1
org → tenant.isSuper = 0 AND tenant.code NOT IN ('public', 'judge')
judge → tenant.code = 'judge'
public → tenant.code = 'public'
```
#### 3.3.2 新增 GET /api/users/stats
仅超管可访问,返回各类型用户数量:
```json
{
"total": 128,
"platform": 3,
"org": 15,
"judge": 8,
"public": 102
}
```
实现方式:分别 count 查询,按上述 userType 映射条件。
#### 3.3.3 改造 GET /api/users/:id
超管调用时:
- 不做 tenantId 过滤
- 公众用户额外返回:`children`(子女列表)、`contestRegistrations`近20条报名记录含活动名和子女名
- 评委额外返回:`contestJudges`(参与的评审活动列表)
#### 3.3.4 新增 PATCH /api/users/:id/status
专门用于禁用/启用,区分于通用的 update 接口:
```json
// Request
{ "status": "enabled" | "disabled" }
// 校验规则
// - 不能操作自己
// - 不能禁用其他租户的唯一管理员(查该租户下 tenant_admin 角色用户数)
```
### 3.4 前端改动
| 文件 | 操作 | 说明 |
|------|------|------|
| `frontend/src/api/users.ts` | 修改 | 扩展 UserQueryParams 类型,新增 stats 和 updateStatus 接口 |
| `frontend/src/views/system/users/Index.vue` | 重写 | 统一用户管理页面 |
| `frontend/src/views/system/public-users/Index.vue` | 废弃 | 功能合并到用户管理,文件保留但不再使用 |
| 后端菜单配置 | 修改 | 超管端移除"公众用户管理"菜单项 |
---
## 4. 改动范围
### 后端
| 文件 | 改动类型 |
|------|---------|
| `backend/src/users/users.service.ts` | 修改findAll 增加跨租户查询逻辑、新增 getStats 方法、findOne 增加关联数据 |
| `backend/src/users/users.controller.ts` | 修改findAll 增加查询参数、新增 stats 和 updateStatus 端点 |
| `backend/src/users/dto/create-user.dto.ts` | 修改:新增查询参数 DTO |
### 前端
| 文件 | 改动类型 |
|------|---------|
| `frontend/src/api/users.ts` | 修改:扩展类型和接口 |
| `frontend/src/views/system/users/Index.vue` | 重写 |
| `frontend/src/views/system/public-users/Index.vue` | 废弃(保留文件不删除)|
### 菜单配置
| 改动 | 说明 |
|------|------|
| 超管端菜单 | 用户中心下移除"公众用户管理"子菜单 |
---
## 5. 实施记录
### 2026-03-27 — 首次实现
**后端改动3 个文件):**
- `backend/src/users/users.service.ts` — findAll 重构为参数对象模式,超管跨租户查询;新增 getStats()、updateStatus() 方法findOne 超管调用时返回子女/报名/评审关联数据
- `backend/src/users/users.controller.ts` — 新增 GET /api/users/stats、PATCH /api/users/:id/status 端点findAll 增加 userType/filterTenantId/userSource/status 查询参数
- `backend/src/auth/strategies/jwt.strategy.ts` — JWT validate 时查租户 isSuper 字段,注入 isSuperTenant 到 req.user
**前端改动2 个文件):**
- `frontend/src/api/users.ts` — 扩展 UserQueryParams、User、UserStats 类型;新增 getUserStats()、updateUserStatus() 接口;保留 usersApi 兼容导出
- `frontend/src/views/system/users/Index.vue` — 完全重写:统计卡片 + 筛选栏 + 统一表格 + 详情 Drawer按用户类型适配+ 禁用/启用/重置密码操作
**待手动操作:**
- 超管端菜单管理中删除"公众用户管理"菜单项(数据在数据库中,非 menus.json
**验证结果:**
- 后端 TSC 编译通过NestJS 启动成功,/api/users/stats 和 /api/users/:id/status 路由注册正常
- 前端无新增 TS 错误(原有错误均为已有代码)