Skip to content

6.1 用户管理 ​

概述

用户管理是系统核心模块,继承 BaseTenantLogic 实现租户隔离,支持 CRUD、重置密码、Excel 导入导出。

模块特点 ​

特性说明
租户隔离继承 BaseTenantLogic,自动按 tenant_id 过滤
数据权限配置 dataScopeDeptField='dept_id',支持按部门过滤
编码生成beforeAdd 自动生成用户编码(租户编码-6位序号,如 T0001-000020)
文件字段avatar(头像),保存到 user/avatar 目录
唯一校验username、mobile 全局唯一
枚举映射gender→gender 字典,status→user_status 字典
密码加密bcrypt 双重加盐,新增时自动加密
角色关联通过 UserRole 中间表关联,支持多角色

文件清单 ​

文件说明
app/controller/UserController.php控制器(9 个接口)
app/logic/UserLogic.php逻辑层(含 import/export/resetPassword)
app/model/User.php模型
app/model/UserRole.php用户角色关联模型
app/validate/UserValidate.php验证器

API 接口 ​

方法路径权限码说明
GET/api/user/pagesys:user:page分页列表
GET/api/user/detail/:idsys:user:detail详情
POST/api/user/addsys:user:add新增
PUT/api/user/updatesys:user:update修改
PUT/api/user/resetPwdsys:user:resetPwd重置密码
DELETE/api/user/delete/:idsys:user:delete删除
DELETE/api/user/batchDeletesys:user:batchDelete批量删除
POST/api/user/importsys:user:import导入
GET/api/user/exportsys:user:export导出

特殊逻辑 ​

重置密码 ​

php
// app/controller/UserController.php

public function resetPwd(): Json
{
    $data = $this->getJsonBody();
    $id = $data['userId'] ?? 0;

    if (empty($id)) {
        return $this->fail('缺少id参数');
    }

    $this->logic->resetPassword($id);
    return $this->success(null, '密码重置成功');
}

请求参数:

参数类型必填说明
userIdint是用户ID

默认密码

重置密码接口无需传递密码参数,系统自动使用 PasswordService::getDefaultPasswordPlain() 作为默认密码。

新增用户(beforeAdd 钩子) ​

php
// app/logic/UserLogic.php

/**
 * 新增前处理:生成编码、处理城市、加密密码
 *
 * @param array $data 待新增的数据
 * @return array 处理后的数据
 */
protected function beforeAdd(array $data): array
{
    // 自动生成用户编码:租户编码 + 租户内序号(如 T0001-000020)
    $tenantId = $data['tenantId'] ?? request()->tenantId ?? 0;
    if ($tenantId == 0) {
        $tenantId = config('tenant.default_tenant_id', 1);
    }
    if ($tenantId > 0) {
        $tenant = Tenant::find($tenantId);
        $currentUserCount = User::where('tenant_id', $tenantId)->where('is_delete', 0)->count();
        $nextSeq = $currentUserCount + 1;
        $data['code'] = $tenant->code . '-' . str_pad((string)$nextSeq, 6, '0', STR_PAD_LEFT);
    }

    // 处理城市字段
    if (isset($data['city']) && is_array($data['city'])) {
        $data['province_code'] = $data['city'][0] ?? '';
        $data['city_code'] = $data['city'][1] ?? '';
        $data['district_code'] = $data['city'][2] ?? '';
        $data['street_code'] = $data['city'][3] ?? '';
        $data['city_info'] = City::resolveCityNames($data['city']);
        unset($data['city']);
    }

    // 密码加密
    $password = $data['password'] ?? PasswordService::getDefaultPasswordPlain();
    $encrypted = PasswordService::encrypt($password);
    $data['password'] = $encrypted['password'];
    $data['salt'] = $encrypted['salt'];

    return $data;
}

编码规则

  • 用户编码格式:租户编码-6位序号,如 T0001-000020
  • 序号 = 当前租户下未删除用户数 + 1
  • 超级管理员(tenantId=0)自动代入默认租户生成编码
  • 编码由系统自动生成,前端不传,修改时不可变更

新增后保存角色(afterAdd 钩子) ​

php
/**
 * 新增后处理:保存用户角色关联
 *
 * @param int   $id   新增用户的主键 ID
 * @param array $data 新增时提交的原始数据
 * @return void
 */
protected function afterAdd(int $id, array $data): void
{
    $roleIds = $data['roles'] ?? [];
    foreach ($roleIds as $roleId) {
        UserRole::create([
            'user_id' => $id,
            'role_id' => $roleId,
            'create_user' => request()->userInfo->username ?? '',
        ]);
    }
}

多角色支持

前端传 roles: [1, 2, 3] 数组,afterAdd 遍历写入 UserRole 中间表。afterUpdate 同理,先删后插实现全量覆盖。

详情补全(afterDetail 钩子) ​

php
/**
 * 详情查询后处理:补充关联数据与格式化输出
 *
 * @param int   $id   用户 ID
 * @param array &$data 详情数据(引用传递)
 * @return void
 */
protected function afterDetail(int $id, array &$data): void
{
    // 补充角色信息
    $roleIds = UserRole::where('user_id', $id)->column('role_id');
    $data['roles'] = $roleIds;

    // 补充关联名称
    $data['levelName'] = Level::getNameMap()[$data['level_id']] ?? '';
    $data['positionName'] = Position::getNameMap()[$data['position_id']] ?? '';
    $data['deptName'] = Dept::getNameMap()[$data['dept_id']] ?? '';

    // 组装城市数组
    $data['city'] = [
        $data['province_code'] ?? '',
        $data['city_code'] ?? '',
        $data['district_code'] ?? '',
        $data['street_code'] ?? '',
    ];

    // 移除敏感字段
    unset($data['password'], $data['salt']);
}

导出(export) ​

导出为分批导出(chunkExport),每批 500 条,避免内存溢出。

导出列字段来源
用户编码code(系统自动生成)
姓名realname
性别genderText(DictService 自动转换)
手机号mobile
邮箱email
部门deptName(Dept::getNameMap 映射)
职级levelName(Level::getNameMap 映射)
岗位positionName(Position::getNameMap 映射)
城市cityInfo(4个城市编码拼接为名称字符串)
地址address
用户名username
简介intro
状态statusText(DictService 自动转换)
备注note

导入(import) ​

导入时需处理以下反向映射:

导入列处理逻辑
性别/状态非数字时 DictService::getValue 反查
部门/职级/岗位名称通过 array_flip(getNameMap) 反查 ID
城市cityInfo 通过 City::resolveCityCodes 拆为4个编码
用户编码忽略(由 beforeAdd 自动生成)

导入不处理 code

导入时即使 Excel 中有「用户编码」列也会被忽略,编码由 beforeAdd 自动生成。

小蚂蚁云团队 · 提供技术支持