Skip to content

6.15 首页与个人中心 ​

概述

首页与个人中心模块负责当前登录用户的信息获取、菜单加载、密码修改和个人信息更新。该模块不继承 BaseLogic,而是专用业务逻辑。

模块特点 ​

特性说明
基类无(直接操作 Model)
用途当前登录用户的自身操作
权限无需配置 #[Permission],已登录即可访问
超级管理员uid=1 拥有全部权限 *:*:*

API 接口 ​

方法路径说明
GET/api/index/getUser获取当前登录用户信息(含角色和权限)
GET/api/index/getMenus获取当前用户菜单(树形)
PUT/api/index/updatePassword修改密码
PUT/api/index/updateProfile更新个人信息

核心代码 ​

获取用户信息 ​

php
// app/logic/IndexLogic.php

public function getUser(int $userId): array
{
    $user = User::with(['dept'])->find($userId);
    if (!$user) {
        throw new \Exception('用户不存在');
    }

    $data = $user->toArray();

    // 头像补全域名前缀
    if (!empty($data['avatar'])) {
        $data['avatar'] = get_file_url($data['avatar']);
    }

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

    // 获取角色列表(完整角色对象)
    $roleIds = UserRole::where('user_id', $userId)->column('role_id');
    if (!empty($roleIds)) {
        $data['roles'] = Role::whereIn('id', $roleIds)->select()->toArray();
    } else {
        $data['roles'] = [];
    }

    // 获取权限列表
    if ($userId === 1) {
        $data['permissions'] = ['*:*:*'];
    } else {
        if (!empty($roleIds)) {
            $data['permissions'] = RoleMenu::alias('rm')
                ->join('think_menu m', 'rm.menu_id = m.id')
                ->whereIn('rm.role_id', $roleIds)
                ->where('m.is_delete', 0)
                ->where('m.type', 1)
                ->column('m.permission');
        } else {
            $data['permissions'] = [];
        }
    }

    // authorities 字段(预留)
    $data['authorities'] = null;

    // 隐藏敏感字段
    unset($data['password'], $data['salt']);

    return $data;
}

返回结构说明

  • roles:完整角色对象数组(含 id、name、code 等),非仅 ID
  • permissions:权限码数组,超级管理员为 ['*:*:*']
  • city:4 层城市编码数组 [省, 市, 区, 街道]
  • avatar:自动补全域名前缀
  • 字段名由 Result::success() 自动转为 camelCase 返回前端

获取菜单 ​

php
public function getMenus(int $userId): array
{
    // 超级管理员:全部菜单
    // type=0 仅返回可导航菜单(目录+页面),type=1 为权限按钮不返回
    if ($userId === 1) {
        $menus = Menu::where('status', 0)
            ->where('hide', 0)
            ->where('type', 0)
            ->where('is_delete', 0)
            ->order('sort', 'asc')
            ->select()->toArray();
        return $this->buildTree($menus);
    }

    // 普通用户:通过角色关联获取菜单
    $roleIds = UserRole::where('user_id', $userId)->column('role_id');
    if (empty($roleIds)) {
        return [];
    }

    $menuIds = RoleMenu::whereIn('role_id', $roleIds)->column('menu_id');
    $menuIds = array_unique($menuIds);

    if (empty($menuIds)) {
        return [];
    }

    $menus = Menu::whereIn('id', $menuIds)
        ->where('status', 0)
        ->where('hide', 0)
        ->where('type', 0)
        ->where('is_delete', 0)
        ->order('sort', 'asc')
        ->select()->toArray();

    return $this->buildTree($menus);
}

菜单查询条件

获取菜单(非节点)数据时保证四个条件:type=0(可导航菜单)、status=0(启用)、hide=0(未隐藏)、is_delete=0(未删除)。

菜单类型说明

代码中 where('type', 0) 用于筛选可导航的菜单项(目录和页面)。在当前实现中,type=0 表示可导航的菜单项(包括目录和页面),type=1 表示仅用于权限控制的按钮节点,不会出现在菜单树中。

修改密码 ​

php
public function updatePassword(int $userId, string $oldPassword, string $newPassword): bool
{
    $user = User::find($userId);

    // 验证旧密码
    if (!PasswordService::verify($oldPassword, $user->password, $user->salt)) {
        throw new \Exception('旧密码错误');
    }

    // 加密新密码
    $encrypted = PasswordService::encrypt($newPassword);
    $user->password = $encrypted['password'];
    $user->salt = $encrypted['salt'];
    return $user->save() !== false;
}

更新个人信息 ​

php
public function updateProfile(int $userId, array $data): bool
{
    $user = User::find($userId);

    // 处理城市字段
    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']);
    }

    // 排除敏感字段
    unset($data['password'], $data['salt'], $data['role_id'], $data['tenant_id'], $data['id']);

    return $user->save($data) !== false;
}

安全设计

updateProfile 会排除 password、salt、role_id、tenant_id 等敏感字段,防止用户越权修改自身权限。

前端调用 ​

typescript
// 获取当前用户信息
const userInfo = await getUserInfo();
// userInfo.permissions = ['sys:user:page', 'sys:article:add', ...]
// userInfo.roles = [1]

// 获取菜单(用于动态路由生成)
const menus = await getMenuList();
// menus = [{id:1, name:'系统管理', path:'/system', children:[...]}]

// 修改密码
await updatePassword({ oldPassword: '123456', newPassword: '654321' });

// 更新个人信息
await updateProfile({ realname: '张三', mobile: '13800138000' });

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