# 管理员列表 — 技术方案

> **依据：** 《管理员列表功能需求.md》v1.1  
> **关联：** 《会员管理技术方案》v1.1、《商户管理技术方案》v1.7、《店铺管理技术方案》v1.3、《关联需求分析.md》v1.5、《账号管理功能需求-草稿》（并列模块）  
> **范围：** 平台管理端 **平台管理员** CRUD；**复用** RuoYi `sys_user` / `sys_user_role` / `sys_role`，**不新建** biz 业务表。  
> **原则：** 列表范围与会员模块 **对称**——会员按 `role_key=member` 过滤，本模块按 **`admin` + `merchant`** 过滤（草稿 §5）。

---

## 1. 技术架构

| 项 | 选型 |
|----|------|
| 基础框架 | RuoYi **v3.9.2**（`springboot2` 分支） |
| 数据库 | **MySQL 5.7.39** |
| ORM / 权限 / 响应 | MyBatis；`@PreAuthorize`；`AjaxResult` / `TableDataInfo`（`code`、`msg`、`data`/`rows`/`total`） |
| 密码 | `SecurityUtils.encryptPassword`（BCrypt）；存 **`sys_user.password`** |
| 账号 | **与 `sys_user` 复用**；无扩展表 |
| 操作日志 | 增删改 `@Log` |

### 1.1 模块落位

```text
baqing-shop/src/main/java/com/ruoyi/web/modules/account/
├── controller/PlatformAdminController.java      # /agri/platformAdmin
├── service/IPlatformAdminService.java
├── service/impl/PlatformAdminServiceImpl.java
├── support/PlatformAdminSupport.java
├── constant/PlatformAdminConstants.java
├── dto/PlatformAdminCreateDTO.java
├── dto/PlatformAdminUpdateDTO.java
├── vo/PlatformAdminListVO.java
├── vo/PlatformAdminDetailVO.java
├── vo/PlatformAdminRoleOptionVO.java
└── mapper/PlatformAdminMapper.java

resources/mapper/account/PlatformAdminMapper.xml
sql/agri_platform_admin.sql
```

### 1.2 账号体系与关联模块

```text
sys_user（RuoYi 用户表）
    ├── sys_user_role ── sys_role
    │       ├── role_key=admin      → 本模块列表范围
    │       ├── role_key=merchant   → 本模块列表范围（草稿 §5）
    │       └── role_key=member     → 会员管理（/agri/member），本模块排除
    │
    ├── biz_member（member_id=user_id）
    └── biz_merchant_account.account_id → 删除管理员时校验
```

| 模块 | 基路径 | 列表过滤 | 与本模块关系 |
|------|--------|----------|--------------|
| **管理员列表（本文）** | `/agri/platformAdmin` | `admin` / `merchant` | — |
| 会员管理 | `/agri/member` | `member` | **互斥**（纯 member 不在本列表） |
| 商户管理 | `/agri/merchant` | — | `adminUserOptions` 检索 **merchant**；与本列表 merchant 用户 **同一 role_key** |
| 账号管理（草稿） | 待定 | `biz_merchant_account` | **经营账号** 专册；与本模块 **分表分接口** |
| RuoYi 系统用户 | `/system/user` | 全量/部门数据权限 | 农资业务入口走 **本模块**；系统菜单可保留给超管 |

### 1.3 配置项（可选）

```yaml
# application.yml
agri:
  platform-admin:
    list-role-keys: admin,merchant
    assignable-role-keys: admin,merchant
```

未配置时使用 `PlatformAdminConstants` 默认值。

---

## 2. 数据库设计

### 2.1 本模块表

**无新建表。** 读写以下 RuoYi 系统表：

| 表名 | 用途 |
|------|------|
| `sys_user` | 管理员账号主数据 |
| `sys_user_role` | 用户—角色关联 |
| `sys_role` | 角色定义（`role_key`、`role_name`） |

### 2.2 字段映射（需求 → `sys_user`）

| 需求字段 | 库字段 | 说明 |
|----------|--------|------|
| 管理员名称 | `nick_name` | 列表展示优先昵称，空则 `user_name` |
| 登录名 | `user_name` | 新增必填；**不可改** |
| 手机号 | `phonenumber` | `del_flag='0'` 唯一（`ISysUserService.checkPhoneUnique`） |
| 邮箱 | `email` | |
| 头像 | `avatar` | URL |
| 添加时间 | `create_time` | |
| 状态 | `status` | 0 正常 1 停用；删除用 `del_flag='2'` |
| 角色名称 | `sys_role.role_name` | 列表 **聚合**；仅展示 **`admin`/`merchant`** |

### 2.3 角色初始化（`sql/agri_platform_admin.sql`）

| role_key | role_name | 用途 |
|----------|-----------|------|
| `admin` | 超级管理员 | RuoYi 内置；列表/表单范围 |
| `merchant` | 商户经营 | 列表/表单范围；商户绑定、adminUserOptions |
| `member` | 会员 | 会员模块；**非**本列表范围 |

完整幂等脚本见 [`sql/agri_platform_admin.sql`](../../../../sql/agri_platform_admin.sql)（实现阶段落库）。

### 2.4 关联表（只读校验）

| 表 | 删除/改角色时 |
|----|----------------|
| `biz_merchant_account` | `account_id = sys_user.user_id` 且 `del_flag='0'` → **禁止删除**；提示先在商户/店铺侧处理 |
| `biz_member` | `member_id = user_id` 存在 → **不级联删** 会员扩展；若用户仅有 member 角色则 **不在本列表** |

### 2.5 索引与约束

沿用 RuoYi：`sys_user` PK(`user_id`)；`phonenumber`/`user_name` 唯一性 **应用层** 校验；列表排序 `create_time DESC`。

**列表过滤 SQL 片段（`platformAdminRoleExists`）：**

```sql
and exists (
  select 1
  from sys_user_role ur
  inner join sys_role r on ur.role_id = r.role_id
    and r.del_flag = '0' and r.status = '0'
  where ur.user_id = u.user_id
    and r.role_key in ('admin', 'merchant')
)
```

**角色名聚合（列表）：**

```sql
group_concat(distinct r.role_name order by r.role_sort separator '、') as role_names
-- 仅聚合 role_key in ('admin','merchant') 的角色
```

---

## 3. 接口设计

**基路径：** `/agri/platformAdmin`  
**权限前缀：** `agri:platformAdmin`

### 3.1 接口一览

| 方法 | 路径 | 权限 | 说明 |
|------|------|------|------|
| GET | `/list` | list | 分页列表 |
| GET | `/{userId}` | query | 详情 |
| POST | `/` | add | 新增管理员 |
| PUT | `/` | edit | 编辑 |
| DELETE | `/{userIds}` | remove | 逻辑删除（支持批量，逗号分隔） |
| GET | `/roleOptions` | list | 表单可选 **`admin`、`merchant`** 下拉 |

> **不提供：** 导出、导入、重置密码（需求非本期；改密可走 RuoYi `/system/user/resetPwd` 或二期接口）。

### 3.2 列表 `GET /list`

| Query | 说明 |
|-------|------|
| pageNum, pageSize | 分页 |
| keyword | 可选；**管理员名称** 模糊（`nick_name` / `user_name`） |

**过滤：** `u.del_flag='0'` + `platformAdminRoleExists`（§2.5）。  
**排序：** `u.create_time DESC`。

**rows（`PlatformAdminListVO`）：**

| 字段 | 类型 | 说明 |
|------|------|------|
| userId | Long | |
| adminName | String | `nick_name` 优先，否则 `user_name` |
| userName | String | 登录名（编辑页展示） |
| phonenumber | String | |
| email | String | |
| roleNames | String | admin/merchant 角色名聚合 |
| createTime | datetime | 添加时间 |

### 3.3 详情 `GET /{userId}`

**data（`PlatformAdminDetailVO`）：** `userId`、`adminName`、`userName`、`phonenumber`、`email`、`avatar`、`roleIds[]`、`roleNames`、`createTime`。

| 规则 | 说明 |
|------|------|
| 不在列表范围 | `code!=200`，`msg` 管理员不存在 |
| userId 不存在或已删 | 同上 |

### 3.4 新增 `POST /`

**Body（`PlatformAdminCreateDTO`）：**

| 字段 | 必填 | 说明 |
|------|:----:|------|
| adminName | ✓ | → `nick_name` |
| userName | ✓ | → `user_name`；唯一 |
| phonenumber | ✓ | 唯一 |
| email | — | |
| avatar | — | |
| password | ✓ | 明文入参，BCrypt 入库 |
| roleIds | ✓ | 至少 1 个；须为 **`admin` 或 `merchant`** |

**流程（事务）：**

1. 校验 `roleIds` ⊆ `{admin, merchant}`；
2. `checkUserNameUnique` / `checkPhoneUnique`；
3. `ISysUserService.insertUser`（`dept_id=100`，`status=0`，`roleIds`）；
4. 返回 `userId`。

**失败 msg 示例：** 登录名已存在、手机号已存在、请选择角色、所选角色无效。

### 3.5 编辑 `PUT /`

**Body（`PlatformAdminUpdateDTO`）：**

| 字段 | 必填 | 说明 |
|------|:----:|------|
| userId | ✓ | |
| adminName | ✓ | |
| phonenumber | ✓ | 排除自身唯一 |
| email | — | |
| avatar | — | |
| roleIds | ✓ | 至少保留 1 个 **`admin` 或 `merchant`** |

**流程：**

1. 加载用户且在列表范围内；
2. **当前登录用户编辑自身：** 允许改资料；`roleIds` 须仍含 ≥1 个 **admin 或 merchant**；
3. **最后一个 admin：** 若目标用户是唯一 `role_key=admin` 账号，则 `roleIds` **必须仍含 admin**；
4. `ISysUserService.updateUser`（**不更新** `user_name`、密码）。

### 3.6 删除 `DELETE /{userIds}`

| 校验 | 说明 |
|------|------|
| 含当前登录 `userId` | 禁止；`msg` 不能删除当前用户 |
| 含 user_id=1（RuoYi 内置超管） | `checkUserAllowed` |
| 删除后无剩余 `admin` 角色用户 | 禁止；`msg` 至少保留一名超级管理员 |
| `biz_merchant_account.account_id = user_id` | 禁止；`msg` 该账号已绑定商户经营账号 |
| 批量 | **任一条失败则整批失败**（与商户删除策略一致） |

**实现：** `ISysUserService.deleteUserByIds`（`del_flag='2'`）；**不删** `biz_member` / 商户 / 店铺数据。

### 3.7 角色选项 `GET /roleOptions`

**data：** `[{ roleId, roleName, roleKey }]`  
**范围：** `status=0`、`del_flag=0`、`role_key in (admin, merchant)`。

### 3.8 统一响应

| 类型 | 结构 |
|------|------|
| 成功 | `{ "code": 200, "msg": "操作成功", "data": ... }` |
| 分页 | `{ "code": 200, "msg": "查询成功", "rows": [], "total": 0 }` |
| 失败 | `{ "code": 500, "msg": "业务原因", "data": null }` |

---

## 4. 核心实现要点

### 4.1 Service 分层

| 类 | 职责 |
|----|------|
| `PlatformAdminServiceImpl` | 列表/详情/CRUD 编排 |
| `PlatformAdminSupport` | 解析 `role_key`→`role_id`；`assertInListScope(userId)`；`countUsersWithRoleKey('admin')` |
| `PlatformAdminMapper` | 列表 JOIN 聚合、经营账号绑定计数 |
| `ISysUserService` | 用户 insert/update/delete（复用 RuoYi） |

### 4.2 与商户模块协作

| 场景 | 行为 |
|------|------|
| 本模块新增管理员 | 可直接分配 **merchant**；与商户 adminUserOptions **同一 role_key** |
| `GET /agri/merchant/adminUserOptions` | 检索 **merchant** 角色用户（本列表 merchant 子集） |
| 删除管理员 | 见 §3.6 经营账号 `account_id` 校验 |

### 4.3 与会员模块边界

| 场景 | 行为 |
|------|------|
| 创建管理员 | **禁止** `roleIds` 含 member |
| 列表 | 含 **admin**、**merchant**；不含纯 member |
| 删除 | 仅逻辑删 `sys_user`；若同 id 存在 `biz_member`，会员模块列表亦不可见（member 角色若已移除） |

### 4.4 安全规则（代码）

```text
PlatformAdminSupport.assertDeletable(userIds, currentUserId)
    ├── 不含 currentUserId
    ├── 不含 userId=1
    ├── 删除后 count(admin) >= 1
    └── 无 biz_merchant_account 引用（by account_id）

PlatformAdminSupport.assertEditableRoles(userId, roleIds, currentUserId)
    ├── roleIds 非空且均为 admin/merchant
    ├── 编辑自身 → 仍含 admin 或 merchant
    └── 唯一 admin → roleIds 仍含 admin
```

---

## 5. 权限与菜单

| 权限字符 | 说明 |
|----------|------|
| `agri:platformAdmin:list` | 列表、角色选项 |
| `agri:platformAdmin:query` | 详情 |
| `agri:platformAdmin:add` | 新增 |
| `agri:platformAdmin:edit` | 编辑 |
| `agri:platformAdmin:remove` | 删除 |

菜单：**农资管理 → 权限管理 → 管理员列表**（与 **账号管理** 并列，路由 `agri/platformAdmin/index`）。

---

## 6. 非本期

| 项 | 说明 |
|----|------|
| 前端页面 | 另册《管理员列表前端技术方案》 |
| 账号管理 | 独立模块 `/agri/accountManage`；全平台 sys_user 统览；权限 `agri:accountManage:*` |
| 子管理员 CRUD | 商家端；见店铺设置 |
| 重置密码 API | 可复用 RuoYi 或二期 `PUT /{userId}/resetPwd` |
| 部门/岗位 | 固定 `dept_id=100`；不做表单 |

---

## 7. 修订记录

| 版本 | 说明 |
|------|------|
| **v1.1** | 草稿 §5：`admin` + `merchant` 列表/表单；废止 `shop_admin` |
| **v1.0** | 首版：复用 sys_user；六接口 |

---

*文档版本：v1.1 · 关联《管理员列表功能需求.md》v1.1*
