Files
rxthinkcmf-wiki/RXThinkCMF_ThinkPhp6_EleVue/zh/modules/tenant.md
T
2026-09-29 09:49:04 +08:00

6.9 KiB

6.13 租户管理

:::tip 概述 租户管理是多租户体系的核心,支持租户的 CRUD、创建租户账号、查看租户用户。继承 BaseLogic(系统共享,租户表本身不隔离)。 :::

模块特点

特性 说明
基类 BaseLogic(系统共享,租户表不隔离)
特殊接口 account(创建租户账号)、users(查看租户用户)
删除校验 beforeDelete 检查用户数 + 保护默认租户
编码生成 afterAdd 自动生成租户编码(T+4位ID)
状态校验 TenantMiddleware 校验租户状态和过期时间

API 接口

方法 路径 权限码 说明
GET /api/tenant/page sys:tenant:page 分页列表
GET /api/tenant/list sys:tenant:list 全量列表
GET /api/tenant/detail/:id sys:tenant:detail 详情
GET /api/tenant/users/:tenantId - 租户用户列表
POST /api/tenant/add sys:tenant:add 新增租户
POST /api/tenant/account sys:tenant:add 创建租户账号
PUT /api/tenant/update sys:tenant:update 修改租户
DELETE /api/tenant/delete/:id sys:tenant:delete 删除租户
DELETE /api/tenant/batchDelete sys:tenant:batchDelete 批量删除

核心代码

// app/logic/TenantLogic.php

class TenantLogic extends BaseLogic
{
    /**
     * 关联的模型类
     *
     * @var string
     */
    protected string $modelClass = Tenant::class;

    /**
     * LIKE 模糊匹配字段
     *
     * @var array
     */
    protected array $pageLikeFields = ['name', 'code', 'contact'];

    /**
     * 精确匹配字段
     *
     * @var array
     */
    protected array $pageEqFields = ['status'];

    /**
     * 默认排序规则
     *
     * @var array
     */
    protected array $pageOrderBy = ['field' => 'id', 'type' => 'desc'];

    /**
     * 枚举显示名映射
     *
     * @var array
     */
    protected array $serializeMaps = ['status' => 'tenant_status'];

    /**
     * 修改前处理:禁止修改编码
     *
     * @param int   $id   租户 ID
     * @param array $data 待更新的数据
     * @return array 过滤后的数据
     */
    protected function beforeUpdate(int $id, array $data): array
    {
        // 租户编码由系统自动生成(T+4位ID),不允许手动修改
        unset($data['code']);
        return $data;
    }

    /**
     * 新增后处理:自动生成租户编码
     *
     * @param int   $id   新增的租户 ID
     * @param array $data 新增时提交的原始数据
     * @return void
     */
    protected function afterAdd(int $id, array $data): void
    {
        // 编码格式:T + 4位ID左补零,如 T0001、T0002;因为依赖自增ID,所以在新增完成后回写
        $code = 'T' . str_pad((string)$id, 4, '0', STR_PAD_LEFT);
        Tenant::where('id', $id)->update(['code' => $code]);
    }

    /**
     * 删除前处理:保护默认租户 + 检查用户数
     *
     * @param int $id 待删除的租户 ID
     * @return void
     * @throws \Exception 当为默认租户或存在用户时抛出
     */
    protected function beforeDelete(int $id): void
    {
        // 默认租户不可删除
        if ($id == 1) {
            throw new \Exception('默认租户不可删除');
        }
        $userCount = User::where('tenant_id', $id)->where('is_delete', 0)->count();
        if ($userCount > 0) {
            throw new \Exception('该租户下存在用户,不可删除');
        }
    }

    /**
     * 列表查询后处理:批量补充租户用户数
     *
     * @param array &$records 记录列表(引用传递)
     * @param array $params   查询参数
     * @return void
     */
    protected function afterPageList(array &$records, array $params): void
    {
        if (empty($records)) return;

        // 一次性查询当前页所有租户的用户数量,避免 N+1
        $tenantIds = array_column($records, 'id');
        $counts = User::where('is_delete', 0)
            ->whereIn('tenant_id', $tenantIds)
            ->group('tenant_id')
            ->column('count(*)', 'tenant_id');

        foreach ($records as &$record) {
            $record['userCount'] = $counts[$record['id']] ?? 0;
        }
    }
}

列表返回 userCount

/api/tenant/page 和 /api/tenant/list 接口返回的每条记录中自动包含 userCount 字段,表示该租户下的用户数量。

:::tip 实现方式 通过 BaseLogic::afterPageList 钩子实现,使用 whereIn + group 批量查询,避免 N+1 问题。 :::

创建租户账号

// TenantLogic::createAccount()
// 处理流程:
// 1. 校验租户存在 + 用户数限制
// 2. 注入租户ID,调用 UserLogic::add() 完成标准创建
//    (含编码自动生成、密码加密、头像处理、角色关联)

:::tip 用户编码由 UserLogic 统一生成 创建租户账号时不再由 TenantLogic 直接生成用户编码, 而是通过 UserLogic::beforeAdd 统一生成,确保所有用户创建路径(直接添加、租户账号、导入)编码规则一致。 :::

:::warning 默认租户保护 默认租户(id=1)不可删除,编码不可修改。超级管理员(tenant_id=0)不受租户隔离限制,创建租户隔离数据时自动代入默认租户(tenant_id=1)。详见 多租户隔离。 :::

套餐化角色预置

系统内置三套租户角色模板,分配不同的菜单权限,用于按套餐等级快速授权:

角色名称 定位 菜单范围
租户-标准版 基础功能 核心业务模块
租户-专业版 进阶功能 核心 + 高级模块
租户-旗舰版 全功能 全部菜单(最全)

使用方式: 创建租户后,通过「角色管理 → 授权菜单」为对应角色分配菜单权限。创建租户管理员账号时,选择对应套餐角色即可完成授权。

:::tip 设计意图 套餐角色解决了"每个租户都要手动配一遍菜单"的重复工作。管理员创建租户时只需选择套餐,角色权限即刻生效。 :::

演示数据

系统内置一组演示数据,可直接登录体验多租户效果:

平台级

账号 密码 角色 说明
admin 123456 超级管理员 平台管理,可管理所有租户

租户级

账号 密码 所属租户 角色 说明
tenant001 123456 客户租户A 租户管理员 可体验租户视角的功能与数据隔离

:::warning 演示环境注意 以上账号仅用于开发和演示环境,生产环境部署后请立即修改密码或删除演示数据。 :::

租户状态

字段 说明
status 0=禁用 1=启用
expire_time 过期时间,过期后 TenantMiddleware 返回 403
max_user_num 最大用户数限制