一、超管端设计优化 - 文档管理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>
295 lines
12 KiB
Markdown
295 lines
12 KiB
Markdown
# 统一用户管理 — 设计方案
|
||
|
||
> 所属端:超管端
|
||
> 状态:已实现(待验收)
|
||
> 创建日期: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 错误(原有错误均为已有代码)
|