初始化项目
This commit is contained in:
@@ -0,0 +1,248 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Auth;
|
||||
|
||||
use App\Models\Auth\User;
|
||||
use App\Services\Auth\PermissionService;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class AuthService
|
||||
{
|
||||
protected $permissionService;
|
||||
|
||||
public function __construct(PermissionService $permissionService)
|
||||
{
|
||||
$this->permissionService = $permissionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理员登录
|
||||
*/
|
||||
public function login(array $credentials): array
|
||||
{
|
||||
$user = User::where('username', $credentials['username'])->first();
|
||||
|
||||
if (!$user || !Hash::check($credentials['password'], $user->password)) {
|
||||
throw ValidationException::withMessages([
|
||||
'username' => ['用户名或密码错误'],
|
||||
]);
|
||||
}
|
||||
|
||||
if ($user->status !== 1) {
|
||||
throw ValidationException::withMessages([
|
||||
'username' => ['账号已被禁用'],
|
||||
]);
|
||||
}
|
||||
|
||||
// 更新登录信息
|
||||
$user->update([
|
||||
'last_login_at' => now(),
|
||||
'last_login_ip' => request()->ip(),
|
||||
]);
|
||||
|
||||
// 生成token
|
||||
$token = Auth::guard('admin')->login($user);
|
||||
|
||||
// 生成refresh token
|
||||
$refreshToken = Auth::guard('admin')->refresh();
|
||||
|
||||
// 获取用户菜单
|
||||
$menu = $this->getUserMenu($user);
|
||||
|
||||
// 获取用户权限列表
|
||||
$permissions = $this->getUserPermissions($user);
|
||||
|
||||
return [
|
||||
'token' => $token,
|
||||
'refreshToken' => $refreshToken,
|
||||
'user' => $this->getUserInfo($user),
|
||||
'menu' => $menu,
|
||||
'permissions' => $permissions,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理员登出
|
||||
*/
|
||||
public function logout(): void
|
||||
{
|
||||
Auth::guard('admin')->logout();
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新token
|
||||
*/
|
||||
public function refresh(): array
|
||||
{
|
||||
$newToken = Auth::guard('admin')->refresh();
|
||||
$user = Auth::guard('admin')->user();
|
||||
|
||||
// 生成新的refresh token
|
||||
$newRefreshToken = Auth::guard('admin')->refresh();
|
||||
|
||||
// 获取用户菜单
|
||||
$menu = $this->getUserMenu($user);
|
||||
|
||||
// 获取用户权限列表
|
||||
$permissions = $this->getUserPermissions($user);
|
||||
|
||||
return [
|
||||
'token' => $newToken,
|
||||
'refreshToken' => $newRefreshToken,
|
||||
'user' => $this->getUserInfo($user),
|
||||
'menu' => $menu,
|
||||
'permissions' => $permissions,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户信息
|
||||
*/
|
||||
public function me(): array
|
||||
{
|
||||
$user = Auth::guard('admin')->user();
|
||||
return $this->getUserInfo($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* 找回密码
|
||||
*/
|
||||
public function resetPassword(array $data): void
|
||||
{
|
||||
$user = User::where('username', $data['username'])
|
||||
->orWhere('email', $data['username'])
|
||||
->orWhere('phone', $data['username'])
|
||||
->first();
|
||||
|
||||
if (!$user) {
|
||||
throw ValidationException::withMessages([
|
||||
'username' => ['用户不存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
$user->update([
|
||||
'password' => Hash::make($data['password']),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改密码
|
||||
*/
|
||||
public function changePassword(array $data): void
|
||||
{
|
||||
$user = Auth::guard('admin')->user();
|
||||
|
||||
if (!Hash::check($data['old_password'], $user->password)) {
|
||||
throw ValidationException::withMessages([
|
||||
'old_password' => ['原密码错误'],
|
||||
]);
|
||||
}
|
||||
|
||||
$user->update([
|
||||
'password' => Hash::make($data['password']),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息详情
|
||||
*/
|
||||
private function getUserInfo(User $user): array
|
||||
{
|
||||
$user->load(['department', 'roles.permissions']);
|
||||
|
||||
return [
|
||||
'id' => $user->id,
|
||||
'username' => $user->username,
|
||||
'real_name' => $user->real_name,
|
||||
'email' => $user->email,
|
||||
'phone' => $user->phone,
|
||||
'avatar' => $user->avatar,
|
||||
'department' => $user->department ? [
|
||||
'id' => $user->department->id,
|
||||
'name' => $user->department->name,
|
||||
] : null,
|
||||
'roles' => $user->roles->pluck('name')->toArray(),
|
||||
'permissions' => $this->getUserPermissions($user),
|
||||
'status' => $user->status,
|
||||
'last_login_at' => $user->last_login_at ? $user->last_login_at->toDateTimeString() : null,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户菜单
|
||||
*/
|
||||
private function getUserMenu(User $user): array
|
||||
{
|
||||
// 获取用户的所有权限
|
||||
$permissionIds = [];
|
||||
foreach ($user->roles as $role) {
|
||||
foreach ($role->permissions as $permission) {
|
||||
$permissionIds[] = $permission->id;
|
||||
}
|
||||
}
|
||||
|
||||
// 查询菜单类型的权限
|
||||
$menuPermissions = \App\Models\Auth\Permission::whereIn('id', $permissionIds)
|
||||
->where('type', 'menu')
|
||||
->where('status', 1)
|
||||
->orderBy('sort', 'asc')
|
||||
->get();
|
||||
|
||||
// 构建菜单树
|
||||
return $this->buildMenuTree($menuPermissions);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建菜单树
|
||||
*/
|
||||
private function buildMenuTree($permissions, $parentId = 0): array
|
||||
{
|
||||
$tree = [];
|
||||
foreach ($permissions as $permission) {
|
||||
if ($permission->parent_id == $parentId) {
|
||||
$node = [
|
||||
'path' => $permission->route,
|
||||
'name' => $permission->code,
|
||||
'meta' => $permission->meta ? json_decode($permission->meta, true) : [],
|
||||
];
|
||||
|
||||
// 添加组件路径
|
||||
if ($permission->component) {
|
||||
$node['component'] = $permission->component;
|
||||
}
|
||||
|
||||
// 添加重定向
|
||||
if (!empty($node['meta']['redirect'])) {
|
||||
$node['redirect'] = $node['meta']['redirect'];
|
||||
}
|
||||
|
||||
// 递归构建子菜单
|
||||
$children = $this->buildMenuTree($permissions, $permission->id);
|
||||
if (!empty($children)) {
|
||||
$node['children'] = $children;
|
||||
}
|
||||
|
||||
$tree[] = $node;
|
||||
}
|
||||
}
|
||||
return $tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户权限列表
|
||||
*/
|
||||
private function getUserPermissions(User $user): array
|
||||
{
|
||||
$permissions = [];
|
||||
foreach ($user->roles as $role) {
|
||||
foreach ($role->permissions as $permission) {
|
||||
if (!in_array($permission->code, $permissions)) {
|
||||
$permissions[] = $permission->code;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $permissions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,319 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Auth;
|
||||
|
||||
use App\Models\Auth\Department;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class DepartmentService
|
||||
{
|
||||
/**
|
||||
* 获取部门列表
|
||||
*/
|
||||
public function getList(array $params): array
|
||||
{
|
||||
$query = Department::query();
|
||||
|
||||
// 搜索条件
|
||||
if (!empty($params['keyword'])) {
|
||||
$query->where(function ($q) use ($params) {
|
||||
$q->where('name', 'like', '%' . $params['keyword'] . '%')
|
||||
->orWhere('leader', 'like', '%' . $params['keyword'] . '%')
|
||||
->orWhere('phone', 'like', '%' . $params['keyword'] . '%');
|
||||
});
|
||||
}
|
||||
|
||||
if (isset($params['status']) && $params['status'] !== '') {
|
||||
$query->where('status', $params['status']);
|
||||
}
|
||||
|
||||
if (isset($params['parent_id']) && $params['parent_id'] !== '') {
|
||||
$query->where('parent_id', $params['parent_id']);
|
||||
}
|
||||
|
||||
// 排序
|
||||
$orderBy = $params['order_by'] ?? 'sort';
|
||||
$orderDirection = $params['order_direction'] ?? 'asc';
|
||||
$query->orderBy($orderBy, $orderDirection);
|
||||
|
||||
// 分页
|
||||
$page = $params['page'] ?? 1;
|
||||
$pageSize = $params['page_size'] ?? 20;
|
||||
$list = $query->paginate($pageSize, ['*'], 'page', $page);
|
||||
|
||||
return [
|
||||
'list' => $list->items(),
|
||||
'total' => $list->total(),
|
||||
'page' => $page,
|
||||
'page_size' => $pageSize,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取部门树
|
||||
*/
|
||||
public function getTree(array $params = []): array
|
||||
{
|
||||
$query = Department::query();
|
||||
|
||||
if (isset($params['status']) && $params['status'] !== '') {
|
||||
$query->where('status', $params['status']);
|
||||
}
|
||||
|
||||
$departments = $query->orderBy('sort', 'asc')->get();
|
||||
return $this->buildTree($departments);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有部门(不分页)
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
$departments = Department::where('status', 1)->orderBy('sort', 'asc')->get();
|
||||
return $departments->map(function ($department) {
|
||||
return [
|
||||
'id' => $department->id,
|
||||
'name' => $department->name,
|
||||
'parent_id' => $department->parent_id,
|
||||
];
|
||||
})->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取部门详情
|
||||
*/
|
||||
public function getById(int $id): array
|
||||
{
|
||||
$department = Department::with(['parent', 'children'])->find($id);
|
||||
|
||||
if (!$department) {
|
||||
throw ValidationException::withMessages([
|
||||
'id' => ['部门不存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => $department->id,
|
||||
'name' => $department->name,
|
||||
'parent_id' => $department->parent_id,
|
||||
'parent' => $department->parent ? [
|
||||
'id' => $department->parent->id,
|
||||
'name' => $department->parent->name,
|
||||
] : null,
|
||||
'leader' => $department->leader,
|
||||
'phone' => $department->phone,
|
||||
'sort' => $department->sort,
|
||||
'status' => $department->status,
|
||||
'children_count' => $department->children()->count(),
|
||||
'users_count' => $department->users()->count(),
|
||||
'created_at' => $department->created_at->toDateTimeString(),
|
||||
'updated_at' => $department->updated_at->toDateTimeString(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建部门
|
||||
*/
|
||||
public function create(array $data): Department
|
||||
{
|
||||
// 检查部门名称是否已存在
|
||||
$query = Department::where('name', $data['name']);
|
||||
if (!empty($data['parent_id'])) {
|
||||
$query->where('parent_id', $data['parent_id']);
|
||||
} else {
|
||||
$query->where('parent_id', 0);
|
||||
}
|
||||
if ($query->exists()) {
|
||||
throw ValidationException::withMessages([
|
||||
'name' => ['同级部门名称已存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
// 如果有父级ID,检查父级是否存在
|
||||
if (!empty($data['parent_id'])) {
|
||||
$parent = Department::find($data['parent_id']);
|
||||
if (!$parent) {
|
||||
throw ValidationException::withMessages([
|
||||
'parent_id' => ['父级部门不存在'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return Department::create([
|
||||
'name' => $data['name'],
|
||||
'parent_id' => $data['parent_id'] ?? 0,
|
||||
'leader' => $data['leader'] ?? null,
|
||||
'phone' => $data['phone'] ?? null,
|
||||
'sort' => $data['sort'] ?? 0,
|
||||
'status' => $data['status'] ?? 1,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新部门
|
||||
*/
|
||||
public function update(int $id, array $data): Department
|
||||
{
|
||||
$department = Department::find($id);
|
||||
|
||||
if (!$department) {
|
||||
throw ValidationException::withMessages([
|
||||
'id' => ['部门不存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
// 检查部门名称是否已被其他部门使用
|
||||
if (isset($data['name']) && $data['name'] !== $department->name) {
|
||||
$query = Department::where('name', $data['name'])
|
||||
->where('id', '!=', $id);
|
||||
$parentId = isset($data['parent_id']) ? $data['parent_id'] : $department->parent_id;
|
||||
if ($parentId) {
|
||||
$query->where('parent_id', $parentId);
|
||||
} else {
|
||||
$query->where('parent_id', 0);
|
||||
}
|
||||
if ($query->exists()) {
|
||||
throw ValidationException::withMessages([
|
||||
'name' => ['同级部门名称已存在'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果有父级ID,检查父级是否存在
|
||||
if (isset($data['parent_id']) && !empty($data['parent_id'])) {
|
||||
$parent = Department::find($data['parent_id']);
|
||||
if (!$parent) {
|
||||
throw ValidationException::withMessages([
|
||||
'parent_id' => ['父级部门不存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
// 不能将部门设置为自己的子级
|
||||
if ($data['parent_id'] == $id) {
|
||||
throw ValidationException::withMessages([
|
||||
'parent_id' => ['不能将部门设置为自己的子级'],
|
||||
]);
|
||||
}
|
||||
|
||||
// 不能将部门设置为自己的子孙级
|
||||
if ($this->isDescendant($id, $data['parent_id'])) {
|
||||
throw ValidationException::withMessages([
|
||||
'parent_id' => ['不能将部门设置为自己的子孙级'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$updateData = [
|
||||
'name' => $data['name'] ?? $department->name,
|
||||
'parent_id' => $data['parent_id'] ?? $department->parent_id,
|
||||
'leader' => $data['leader'] ?? $department->leader,
|
||||
'phone' => $data['phone'] ?? $department->phone,
|
||||
'sort' => $data['sort'] ?? $department->sort,
|
||||
'status' => $data['status'] ?? $department->status,
|
||||
];
|
||||
|
||||
$department->update($updateData);
|
||||
return $department;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除部门
|
||||
*/
|
||||
public function delete(int $id): void
|
||||
{
|
||||
$department = Department::find($id);
|
||||
|
||||
if (!$department) {
|
||||
throw ValidationException::withMessages([
|
||||
'id' => ['部门不存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
// 检查是否有子部门
|
||||
if ($department->children()->exists()) {
|
||||
throw ValidationException::withMessages([
|
||||
'id' => ['该部门下还有子部门,无法删除'],
|
||||
]);
|
||||
}
|
||||
|
||||
// 检查部门下是否有用户
|
||||
if ($department->users()->exists()) {
|
||||
throw ValidationException::withMessages([
|
||||
'id' => ['该部门下还有用户,无法删除'],
|
||||
]);
|
||||
}
|
||||
|
||||
$department->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除部门
|
||||
*/
|
||||
public function batchDelete(array $ids): int
|
||||
{
|
||||
// 检查是否有子部门
|
||||
$hasChildren = Department::whereIn('id', $ids)->whereHas('children')->exists();
|
||||
if ($hasChildren) {
|
||||
throw ValidationException::withMessages([
|
||||
'ids' => ['选中的部门中还有子部门,无法删除'],
|
||||
]);
|
||||
}
|
||||
|
||||
// 检查部门下是否有用户
|
||||
$hasUsers = Department::whereIn('id', $ids)->whereHas('users')->exists();
|
||||
if ($hasUsers) {
|
||||
throw ValidationException::withMessages([
|
||||
'ids' => ['选中的部门中还有用户,无法删除'],
|
||||
]);
|
||||
}
|
||||
|
||||
return Department::whereIn('id', $ids)->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量更新部门状态
|
||||
*/
|
||||
public function batchUpdateStatus(array $ids, int $status): int
|
||||
{
|
||||
return Department::whereIn('id', $ids)->update(['status' => $status]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建部门树
|
||||
*/
|
||||
private function buildTree($departments, $parentId = 0): array
|
||||
{
|
||||
$tree = [];
|
||||
foreach ($departments as $department) {
|
||||
if ($department->parent_id == $parentId) {
|
||||
$node = [
|
||||
'id' => $department->id,
|
||||
'name' => $department->name,
|
||||
'parent_id' => $department->parent_id,
|
||||
'leader' => $department->leader,
|
||||
'phone' => $department->phone,
|
||||
'sort' => $department->sort,
|
||||
'status' => $department->status,
|
||||
'children' => $this->buildTree($departments, $department->id),
|
||||
];
|
||||
$tree[] = $node;
|
||||
}
|
||||
}
|
||||
return $tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否为子孙部门
|
||||
*/
|
||||
private function isDescendant($id, $childId): bool
|
||||
{
|
||||
if ($id == $childId) {
|
||||
return true;
|
||||
}
|
||||
$child = Department::find($childId);
|
||||
if (!$child || $child->parent_id == 0) {
|
||||
return false;
|
||||
}
|
||||
return $this->isDescendant($id, $child->parent_id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Auth;
|
||||
|
||||
use App\Models\Auth\User;
|
||||
use App\Models\Auth\Department;
|
||||
use App\Models\Auth\Role;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use App\Exports\UserExport;
|
||||
use App\Exports\DepartmentExport;
|
||||
use App\Imports\UserImport;
|
||||
use App\Imports\DepartmentImport;
|
||||
|
||||
class ImportExportService
|
||||
{
|
||||
/**
|
||||
* 下载用户导入模板
|
||||
*/
|
||||
public function downloadUserTemplate(): string
|
||||
{
|
||||
$filename = 'user_import_template_' . date('YmdHis') . '.xlsx';
|
||||
$path = storage_path('app/exports/' . $filename);
|
||||
|
||||
// 确保目录存在
|
||||
if (!is_dir(dirname($path))) {
|
||||
mkdir(dirname($path), 0755, true);
|
||||
}
|
||||
|
||||
// 使用模板数据创建Excel
|
||||
$templateData = [
|
||||
[
|
||||
'用户名*',
|
||||
'密码*',
|
||||
'真实姓名*',
|
||||
'邮箱',
|
||||
'手机号',
|
||||
'部门名称',
|
||||
'角色名称(多个用逗号分隔)',
|
||||
'备注',
|
||||
],
|
||||
[
|
||||
'test001',
|
||||
'123456',
|
||||
'测试用户001',
|
||||
'test001@example.com',
|
||||
'13800138001',
|
||||
'技术部',
|
||||
'管理员',
|
||||
'示例数据',
|
||||
],
|
||||
];
|
||||
|
||||
Excel::store(new \App\Exports\GenericExport($templateData), 'exports/' . $filename);
|
||||
|
||||
return $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载部门导入模板
|
||||
*/
|
||||
public function downloadDepartmentTemplate(): string
|
||||
{
|
||||
$filename = 'department_import_template_' . date('YmdHis') . '.xlsx';
|
||||
|
||||
// 确保目录存在
|
||||
if (!is_dir(storage_path('app/exports'))) {
|
||||
mkdir(storage_path('app/exports'), 0755, true);
|
||||
}
|
||||
|
||||
$templateData = [
|
||||
[
|
||||
'部门名称*',
|
||||
'上级部门名称',
|
||||
'负责人',
|
||||
'联系电话',
|
||||
'排序',
|
||||
'备注',
|
||||
],
|
||||
[
|
||||
'前端开发组',
|
||||
'技术部',
|
||||
'张三',
|
||||
'13800138001',
|
||||
'1',
|
||||
'示例数据',
|
||||
],
|
||||
];
|
||||
|
||||
Excel::store(new \App\Exports\GenericExport($templateData), 'exports/' . $filename);
|
||||
|
||||
return $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出用户数据
|
||||
*/
|
||||
public function exportUsers(array $userIds = []): string
|
||||
{
|
||||
$filename = 'users_export_' . date('YmdHis') . '.xlsx';
|
||||
|
||||
// 确保目录存在
|
||||
if (!is_dir(storage_path('app/exports'))) {
|
||||
mkdir(storage_path('app/exports'), 0755, true);
|
||||
}
|
||||
|
||||
Excel::store(new UserExport($userIds), 'exports/' . $filename);
|
||||
|
||||
return $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出部门数据
|
||||
*/
|
||||
public function exportDepartments(array $departmentIds = []): string
|
||||
{
|
||||
$filename = 'departments_export_' . date('YmdHis') . '.xlsx';
|
||||
|
||||
// 确保目录存在
|
||||
if (!is_dir(storage_path('app/exports'))) {
|
||||
mkdir(storage_path('app/exports'), 0755, true);
|
||||
}
|
||||
|
||||
Excel::store(new DepartmentExport($departmentIds), 'exports/' . $filename);
|
||||
|
||||
return $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入用户数据
|
||||
*/
|
||||
public function importUsers(string $filePath, string $realPath): array
|
||||
{
|
||||
if (!file_exists($realPath)) {
|
||||
throw ValidationException::withMessages([
|
||||
'file' => ['文件不存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
$import = new UserImport();
|
||||
Excel::import($import, $realPath);
|
||||
|
||||
// 删除临时文件
|
||||
if (file_exists($realPath)) {
|
||||
unlink($realPath);
|
||||
}
|
||||
|
||||
return [
|
||||
'success_count' => $import->getSuccessCount(),
|
||||
'error_count' => $import->getErrorCount(),
|
||||
'errors' => $import->getErrors(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入部门数据
|
||||
*/
|
||||
public function importDepartments(string $filePath, string $realPath): array
|
||||
{
|
||||
if (!file_exists($realPath)) {
|
||||
throw ValidationException::withMessages([
|
||||
'file' => ['文件不存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
$import = new DepartmentImport();
|
||||
Excel::import($import, $realPath);
|
||||
|
||||
// 删除临时文件
|
||||
if (file_exists($realPath)) {
|
||||
unlink($realPath);
|
||||
}
|
||||
|
||||
return [
|
||||
'success_count' => $import->getSuccessCount(),
|
||||
'error_count' => $import->getErrorCount(),
|
||||
'errors' => $import->getErrors(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取导出文件路径
|
||||
*/
|
||||
public function getExportFilePath(string $filename): string
|
||||
{
|
||||
return storage_path('app/exports/' . $filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除导出文件
|
||||
*/
|
||||
public function deleteExportFile(string $filename): bool
|
||||
{
|
||||
$path = $this->getExportFilePath($filename);
|
||||
if (file_exists($path)) {
|
||||
return unlink($path);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Auth;
|
||||
|
||||
use App\Models\Auth\User;
|
||||
use App\Models\Auth\Role;
|
||||
use App\Models\Auth\Permission;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class PermissionCacheService
|
||||
{
|
||||
protected $cachePrefix = 'permission:';
|
||||
protected $cacheMinutes = 60; // 缓存60分钟
|
||||
|
||||
/**
|
||||
* 获取用户的权限列表(带缓存)
|
||||
*/
|
||||
public function getUserPermissions(int $userId): array
|
||||
{
|
||||
$cacheKey = $this->getUserPermissionsCacheKey($userId);
|
||||
|
||||
return Cache::remember($cacheKey, now()->addMinutes($this->cacheMinutes), function() use ($userId) {
|
||||
$user = User::find($userId);
|
||||
if (!$user) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$permissions = [];
|
||||
foreach ($user->roles as $role) {
|
||||
foreach ($role->permissions as $permission) {
|
||||
$permissions[$permission->id] = [
|
||||
'id' => $permission->id,
|
||||
'name' => $permission->name,
|
||||
'code' => $permission->code,
|
||||
'type' => $permission->type,
|
||||
'route' => $permission->route,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return array_values($permissions);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户的权限编码列表(带缓存)
|
||||
*/
|
||||
public function getUserPermissionCodes(int $userId): array
|
||||
{
|
||||
$cacheKey = $this->getUserPermissionCodesCacheKey($userId);
|
||||
|
||||
return Cache::remember($cacheKey, now()->addMinutes($this->cacheMinutes), function() use ($userId) {
|
||||
$permissions = $this->getUserPermissions($userId);
|
||||
return array_column($permissions, 'code');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户的菜单树(带缓存)
|
||||
*/
|
||||
public function getUserMenuTree(int $userId): array
|
||||
{
|
||||
$cacheKey = $this->getUserMenuTreeCacheKey($userId);
|
||||
|
||||
return Cache::remember($cacheKey, now()->addMinutes($this->cacheMinutes), function() use ($userId) {
|
||||
$user = User::find($userId);
|
||||
if (!$user) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// 获取用户的所有权限ID
|
||||
$permissionIds = [];
|
||||
foreach ($user->roles as $role) {
|
||||
foreach ($role->permissions as $permission) {
|
||||
$permissionIds[] = $permission->id;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取菜单类型的权限
|
||||
$permissions = Permission::whereIn('id', $permissionIds)
|
||||
->whereIn('type', ['menu', 'api'])
|
||||
->where('status', 1)
|
||||
->orderBy('sort', 'asc')
|
||||
->get();
|
||||
|
||||
return $this->buildMenuTree($permissions->toArray());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否有某个权限(带缓存)
|
||||
*/
|
||||
public function userHasPermission(int $userId, string $permissionCode): bool
|
||||
{
|
||||
$codes = $this->getUserPermissionCodes($userId);
|
||||
return in_array($permissionCode, $codes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色的权限列表(带缓存)
|
||||
*/
|
||||
public function getRolePermissions(int $roleId): array
|
||||
{
|
||||
$cacheKey = $this->getRolePermissionsCacheKey($roleId);
|
||||
|
||||
return Cache::remember($cacheKey, now()->addMinutes($this->cacheMinutes), function() use ($roleId) {
|
||||
$role = Role::find($roleId);
|
||||
if (!$role) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $role->permissions->map(function($permission) {
|
||||
return [
|
||||
'id' => $permission->id,
|
||||
'name' => $permission->name,
|
||||
'code' => $permission->code,
|
||||
'type' => $permission->type,
|
||||
];
|
||||
})->toArray();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除用户权限缓存
|
||||
*/
|
||||
public function clearUserPermissionCache(int $userId): void
|
||||
{
|
||||
Cache::forget($this->getUserPermissionsCacheKey($userId));
|
||||
Cache::forget($this->getUserPermissionCodesCacheKey($userId));
|
||||
Cache::forget($this->getUserMenuTreeCacheKey($userId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除角色权限缓存
|
||||
*/
|
||||
public function clearRolePermissionCache(int $roleId): void
|
||||
{
|
||||
Cache::forget($this->getRolePermissionsCacheKey($roleId));
|
||||
|
||||
// 清除所有拥有该角色的用户权限缓存
|
||||
$role = Role::find($roleId);
|
||||
if ($role) {
|
||||
foreach ($role->users as $user) {
|
||||
$this->clearUserPermissionCache($user->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有权限缓存
|
||||
*/
|
||||
public function clearAllPermissionCache(): void
|
||||
{
|
||||
if (Cache::getStore() instanceof \Illuminate\Cache\RedisStore) {
|
||||
$redis = Cache::getStore()->connection();
|
||||
$keys = $redis->keys($this->cachePrefix . '*');
|
||||
if (!empty($keys)) {
|
||||
$redis->del($keys);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除指定用户的权限缓存(当用户角色变化时调用)
|
||||
*/
|
||||
public function onUserRolesChanged(int $userId): void
|
||||
{
|
||||
$this->clearUserPermissionCache($userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除角色的用户缓存(当角色权限变化时调用)
|
||||
*/
|
||||
public function onRolePermissionsChanged(int $roleId): void
|
||||
{
|
||||
$this->clearRolePermissionCache($roleId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除权限的所有缓存(当权限本身变化时调用)
|
||||
*/
|
||||
public function onPermissionChanged(int $permissionId): void
|
||||
{
|
||||
// 清除所有缓存,因为权限变化可能影响所有用户
|
||||
$this->clearAllPermissionCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建菜单树
|
||||
*/
|
||||
protected function buildMenuTree(array $permissions, int $parentId = 0): array
|
||||
{
|
||||
$tree = [];
|
||||
foreach ($permissions as $permission) {
|
||||
if ($permission['parent_id'] == $parentId) {
|
||||
$node = [
|
||||
'id' => $permission['id'],
|
||||
'name' => $permission['name'],
|
||||
'code' => $permission['code'],
|
||||
'type' => $permission['type'],
|
||||
'route' => $permission['route'],
|
||||
'component' => $permission['component'],
|
||||
'meta' => json_decode($permission['meta'] ?? '{}', true),
|
||||
'sort' => $permission['sort'],
|
||||
'children' => $this->buildMenuTree($permissions, $permission['id']),
|
||||
];
|
||||
|
||||
// 如果没有子节点,移除children字段
|
||||
if (empty($node['children'])) {
|
||||
unset($node['children']);
|
||||
}
|
||||
|
||||
$tree[] = $node;
|
||||
}
|
||||
}
|
||||
|
||||
// 按sort排序
|
||||
usort($tree, function($a, $b) {
|
||||
return $a['sort'] <=> $b['sort'];
|
||||
});
|
||||
|
||||
return $tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成用户权限缓存键
|
||||
*/
|
||||
protected function getUserPermissionsCacheKey(int $userId): string
|
||||
{
|
||||
return $this->cachePrefix . 'user:' . $userId . ':permissions';
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成用户权限编码缓存键
|
||||
*/
|
||||
protected function getUserPermissionCodesCacheKey(int $userId): string
|
||||
{
|
||||
return $this->cachePrefix . 'user:' . $userId . ':permission_codes';
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成用户菜单树缓存键
|
||||
*/
|
||||
protected function getUserMenuTreeCacheKey(int $userId): string
|
||||
{
|
||||
return $this->cachePrefix . 'user:' . $userId . ':menu_tree';
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成角色权限缓存键
|
||||
*/
|
||||
protected function getRolePermissionsCacheKey(int $roleId): string
|
||||
{
|
||||
return $this->cachePrefix . 'role:' . $roleId . ':permissions';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Auth;
|
||||
|
||||
use App\Models\Auth\Permission;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class PermissionService
|
||||
{
|
||||
/**
|
||||
* 获取权限列表
|
||||
*/
|
||||
public function getList(array $params): array
|
||||
{
|
||||
$query = Permission::query();
|
||||
|
||||
// 搜索条件
|
||||
if (!empty($params['keyword'])) {
|
||||
$query->where(function ($q) use ($params) {
|
||||
$q->where('name', 'like', '%' . $params['keyword'] . '%')
|
||||
->orWhere('code', 'like', '%' . $params['keyword'] . '%');
|
||||
});
|
||||
}
|
||||
|
||||
if (!empty($params['type'])) {
|
||||
$query->where('type', $params['type']);
|
||||
}
|
||||
|
||||
if (isset($params['status']) && $params['status'] !== '') {
|
||||
$query->where('status', $params['status']);
|
||||
}
|
||||
|
||||
// 排序
|
||||
$orderBy = $params['order_by'] ?? 'sort';
|
||||
$orderDirection = $params['order_direction'] ?? 'asc';
|
||||
$query->orderBy($orderBy, $orderDirection);
|
||||
|
||||
// 分页
|
||||
$page = $params['page'] ?? 1;
|
||||
$pageSize = $params['page_size'] ?? 20;
|
||||
$list = $query->paginate($pageSize, ['*'], 'page', $page);
|
||||
|
||||
return [
|
||||
'list' => $list->items(),
|
||||
'total' => $list->total(),
|
||||
'page' => $page,
|
||||
'page_size' => $pageSize,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取权限树
|
||||
*/
|
||||
public function getTree(array $params = []): array
|
||||
{
|
||||
$query = Permission::query();
|
||||
|
||||
if (!empty($params['type'])) {
|
||||
$query->where('type', $params['type']);
|
||||
}
|
||||
|
||||
if (isset($params['status']) && $params['status'] !== '') {
|
||||
$query->where('status', $params['status']);
|
||||
}
|
||||
|
||||
$permissions = $query->orderBy('sort', 'asc')->get();
|
||||
return $this->buildTree($permissions);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取菜单树(前端使用)
|
||||
*/
|
||||
public function getMenuTree(int $userId = null): array
|
||||
{
|
||||
$query = Permission::whereIn('type', ['menu', 'api'])
|
||||
->where('status', 1);
|
||||
|
||||
if ($userId) {
|
||||
// 获取用户的权限
|
||||
$user = \App\Models\Auth\User::find($userId);
|
||||
if ($user) {
|
||||
$permissionIds = [];
|
||||
foreach ($user->roles as $role) {
|
||||
foreach ($role->permissions as $permission) {
|
||||
$permissionIds[] = $permission->id;
|
||||
}
|
||||
}
|
||||
$query->whereIn('id', $permissionIds);
|
||||
}
|
||||
}
|
||||
|
||||
$permissions = $query->orderBy('sort', 'asc')->get();
|
||||
return $this->buildTree($permissions);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取权限详情
|
||||
*/
|
||||
public function getById(int $id): array
|
||||
{
|
||||
$permission = Permission::with(['parent'])->find($id);
|
||||
|
||||
if (!$permission) {
|
||||
throw ValidationException::withMessages([
|
||||
'id' => ['权限不存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => $permission->id,
|
||||
'name' => $permission->name,
|
||||
'code' => $permission->code,
|
||||
'type' => $permission->type,
|
||||
'parent_id' => $permission->parent_id,
|
||||
'parent' => $permission->parent ? [
|
||||
'id' => $permission->parent->id,
|
||||
'name' => $permission->parent->name,
|
||||
] : null,
|
||||
'route' => $permission->route,
|
||||
'component' => $permission->component,
|
||||
'meta' => $permission->meta,
|
||||
'sort' => $permission->sort,
|
||||
'status' => $permission->status,
|
||||
'created_at' => $permission->created_at->toDateTimeString(),
|
||||
'updated_at' => $permission->updated_at->toDateTimeString(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建权限
|
||||
*/
|
||||
public function create(array $data): Permission
|
||||
{
|
||||
// 检查权限名称是否已存在
|
||||
if (Permission::where('name', $data['name'])->exists()) {
|
||||
throw ValidationException::withMessages([
|
||||
'name' => ['权限名称已存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
// 检查权限编码是否已存在
|
||||
if (Permission::where('code', $data['code'])->exists()) {
|
||||
throw ValidationException::withMessages([
|
||||
'code' => ['权限编码已存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
// 如果有父级ID,检查父级是否存在
|
||||
if (!empty($data['parent_id'])) {
|
||||
$parent = Permission::find($data['parent_id']);
|
||||
if (!$parent) {
|
||||
throw ValidationException::withMessages([
|
||||
'parent_id' => ['父级权限不存在'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return Permission::create([
|
||||
'name' => $data['name'],
|
||||
'code' => $data['code'],
|
||||
'type' => $data['type'] ?? 'api',
|
||||
'parent_id' => $data['parent_id'] ?? 0,
|
||||
'route' => $data['route'] ?? null,
|
||||
'component' => $data['component'] ?? null,
|
||||
'meta' => $data['meta'] ?? null,
|
||||
'sort' => $data['sort'] ?? 0,
|
||||
'status' => $data['status'] ?? 1,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新权限
|
||||
*/
|
||||
public function update(int $id, array $data): Permission
|
||||
{
|
||||
$permission = Permission::find($id);
|
||||
|
||||
if (!$permission) {
|
||||
throw ValidationException::withMessages([
|
||||
'id' => ['权限不存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
// 检查权限名称是否已被其他权限使用
|
||||
if (isset($data['name']) && $data['name'] !== $permission->name) {
|
||||
if (Permission::where('name', $data['name'])->exists()) {
|
||||
throw ValidationException::withMessages([
|
||||
'name' => ['权限名称已存在'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// 检查权限编码是否已被其他权限使用
|
||||
if (isset($data['code']) && $data['code'] !== $permission->code) {
|
||||
if (Permission::where('code', $data['code'])->exists()) {
|
||||
throw ValidationException::withMessages([
|
||||
'code' => ['权限编码已存在'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果有父级ID,检查父级是否存在
|
||||
if (isset($data['parent_id']) && !empty($data['parent_id'])) {
|
||||
$parent = Permission::find($data['parent_id']);
|
||||
if (!$parent) {
|
||||
throw ValidationException::withMessages([
|
||||
'parent_id' => ['父级权限不存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
// 不能将权限设置为自己的子级
|
||||
if ($data['parent_id'] == $id) {
|
||||
throw ValidationException::withMessages([
|
||||
'parent_id' => ['不能将权限设置为自己的子级'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$updateData = [
|
||||
'name' => $data['name'] ?? $permission->name,
|
||||
'code' => $data['code'] ?? $permission->code,
|
||||
'type' => $data['type'] ?? $permission->type,
|
||||
'parent_id' => $data['parent_id'] ?? $permission->parent_id,
|
||||
'route' => $data['route'] ?? $permission->route,
|
||||
'component' => $data['component'] ?? $permission->component,
|
||||
'meta' => isset($data['meta']) ? $data['meta'] : $permission->meta,
|
||||
'sort' => $data['sort'] ?? $permission->sort,
|
||||
'status' => $data['status'] ?? $permission->status,
|
||||
];
|
||||
|
||||
$permission->update($updateData);
|
||||
return $permission;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除权限
|
||||
*/
|
||||
public function delete(int $id): void
|
||||
{
|
||||
$permission = Permission::find($id);
|
||||
|
||||
if (!$permission) {
|
||||
throw ValidationException::withMessages([
|
||||
'id' => ['权限不存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
// 检查是否有子权限
|
||||
if ($permission->children()->exists()) {
|
||||
throw ValidationException::withMessages([
|
||||
'id' => ['该权限下还有子权限,无法删除'],
|
||||
]);
|
||||
}
|
||||
|
||||
// 检查是否被角色使用
|
||||
if ($permission->roles()->exists()) {
|
||||
throw ValidationException::withMessages([
|
||||
'id' => ['该权限已被角色使用,无法删除'],
|
||||
]);
|
||||
}
|
||||
|
||||
$permission->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除权限
|
||||
*/
|
||||
public function batchDelete(array $ids): int
|
||||
{
|
||||
// 检查是否有子权限
|
||||
$hasChildren = Permission::whereIn('id', $ids)->whereHas('children')->exists();
|
||||
if ($hasChildren) {
|
||||
throw ValidationException::withMessages([
|
||||
'ids' => ['选中的权限中还有子权限,无法删除'],
|
||||
]);
|
||||
}
|
||||
|
||||
// 检查是否被角色使用
|
||||
$hasRoles = Permission::whereIn('id', $ids)->whereHas('roles')->exists();
|
||||
if ($hasRoles) {
|
||||
throw ValidationException::withMessages([
|
||||
'ids' => ['选中的权限中已被角色使用,无法删除'],
|
||||
]);
|
||||
}
|
||||
|
||||
return Permission::whereIn('id', $ids)->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量更新权限状态
|
||||
*/
|
||||
public function batchUpdateStatus(array $ids, int $status): int
|
||||
{
|
||||
return Permission::whereIn('id', $ids)->update(['status' => $status]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建权限树
|
||||
*/
|
||||
private function buildTree($permissions, $parentId = 0): array
|
||||
{
|
||||
$tree = [];
|
||||
foreach ($permissions as $permission) {
|
||||
if ($permission->parent_id == $parentId) {
|
||||
$node = [
|
||||
'id' => $permission->id,
|
||||
'name' => $permission->name,
|
||||
'code' => $permission->code,
|
||||
'type' => $permission->type,
|
||||
'route' => $permission->route,
|
||||
'component' => $permission->component,
|
||||
'meta' => $permission->meta,
|
||||
'sort' => $permission->sort,
|
||||
'status' => $permission->status,
|
||||
'children' => $this->buildTree($permissions, $permission->id),
|
||||
];
|
||||
$tree[] = $node;
|
||||
}
|
||||
}
|
||||
return $tree;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,430 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Auth;
|
||||
|
||||
use App\Models\Auth\Role;
|
||||
use App\Models\Auth\Permission;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class RoleService
|
||||
{
|
||||
/**
|
||||
* 获取角色列表
|
||||
*/
|
||||
public function getList(array $params): array
|
||||
{
|
||||
$query = Role::query();
|
||||
|
||||
// 搜索条件
|
||||
if (!empty($params['keyword'])) {
|
||||
$query->where(function ($q) use ($params) {
|
||||
$q->where('name', 'like', '%' . $params['keyword'] . '%')
|
||||
->orWhere('code', 'like', '%' . $params['keyword'] . '%');
|
||||
});
|
||||
}
|
||||
|
||||
if (isset($params['status']) && $params['status'] !== '') {
|
||||
$query->where('status', $params['status']);
|
||||
}
|
||||
|
||||
// 排序
|
||||
$orderBy = $params['order_by'] ?? 'sort';
|
||||
$orderDirection = $params['order_direction'] ?? 'asc';
|
||||
$query->orderBy($orderBy, $orderDirection);
|
||||
|
||||
// 分页
|
||||
$page = $params['page'] ?? 1;
|
||||
$pageSize = $params['page_size'] ?? 20;
|
||||
$list = $query->paginate($pageSize, ['*'], 'page', $page);
|
||||
|
||||
return [
|
||||
'list' => $list->items(),
|
||||
'total' => $list->total(),
|
||||
'page' => $page,
|
||||
'page_size' => $pageSize,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有角色(不分页)
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
$roles = Role::where('status', 1)->orderBy('sort', 'asc')->get();
|
||||
return $roles->map(function ($role) {
|
||||
return [
|
||||
'id' => $role->id,
|
||||
'name' => $role->name,
|
||||
'code' => $role->code,
|
||||
];
|
||||
})->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色详情
|
||||
*/
|
||||
public function getById(int $id): array
|
||||
{
|
||||
$role = Role::with(['permissions'])->find($id);
|
||||
|
||||
if (!$role) {
|
||||
throw ValidationException::withMessages([
|
||||
'id' => ['角色不存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => $role->id,
|
||||
'name' => $role->name,
|
||||
'code' => $role->code,
|
||||
'description' => $role->description,
|
||||
'sort' => $role->sort,
|
||||
'status' => $role->status,
|
||||
'permissions' => $role->permissions->pluck('id')->toArray(),
|
||||
'created_at' => $role->created_at->toDateTimeString(),
|
||||
'updated_at' => $role->updated_at->toDateTimeString(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建角色
|
||||
*/
|
||||
public function create(array $data): Role
|
||||
{
|
||||
// 检查角色名称是否已存在
|
||||
if (Role::where('name', $data['name'])->exists()) {
|
||||
throw ValidationException::withMessages([
|
||||
'name' => ['角色名称已存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
// 检查角色编码是否已存在
|
||||
if (Role::where('code', $data['code'])->exists()) {
|
||||
throw ValidationException::withMessages([
|
||||
'code' => ['角色编码已存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$role = Role::create([
|
||||
'name' => $data['name'],
|
||||
'code' => $data['code'],
|
||||
'description' => $data['description'] ?? null,
|
||||
'sort' => $data['sort'] ?? 0,
|
||||
'status' => $data['status'] ?? 1,
|
||||
]);
|
||||
|
||||
// 关联权限
|
||||
if (!empty($data['permission_ids'])) {
|
||||
$role->permissions()->attach($data['permission_ids']);
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
return $role;
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新角色
|
||||
*/
|
||||
public function update(int $id, array $data): Role
|
||||
{
|
||||
$role = Role::find($id);
|
||||
|
||||
if (!$role) {
|
||||
throw ValidationException::withMessages([
|
||||
'id' => ['角色不存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
// 检查角色名称是否已被其他角色使用
|
||||
if (isset($data['name']) && $data['name'] !== $role->name) {
|
||||
if (Role::where('name', $data['name'])->exists()) {
|
||||
throw ValidationException::withMessages([
|
||||
'name' => ['角色名称已存在'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// 检查角色编码是否已被其他角色使用
|
||||
if (isset($data['code']) && $data['code'] !== $role->code) {
|
||||
if (Role::where('code', $data['code'])->exists()) {
|
||||
throw ValidationException::withMessages([
|
||||
'code' => ['角色编码已存在'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$updateData = [
|
||||
'name' => $data['name'] ?? $role->name,
|
||||
'code' => $data['code'] ?? $role->code,
|
||||
'description' => $data['description'] ?? $role->description,
|
||||
'sort' => $data['sort'] ?? $role->sort,
|
||||
'status' => $data['status'] ?? $role->status,
|
||||
];
|
||||
|
||||
$role->update($updateData);
|
||||
|
||||
// 更新权限关联
|
||||
if (isset($data['permission_ids'])) {
|
||||
$role->permissions()->sync($data['permission_ids']);
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
return $role;
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除角色
|
||||
*/
|
||||
public function delete(int $id): void
|
||||
{
|
||||
$role = Role::find($id);
|
||||
|
||||
if (!$role) {
|
||||
throw ValidationException::withMessages([
|
||||
'id' => ['角色不存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
// 检查角色下是否有用户
|
||||
if ($role->users()->exists()) {
|
||||
throw ValidationException::withMessages([
|
||||
'id' => ['该角色下还有用户,无法删除'],
|
||||
]);
|
||||
}
|
||||
|
||||
$role->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除角色
|
||||
*/
|
||||
public function batchDelete(array $ids): int
|
||||
{
|
||||
// 检查角色下是否有用户
|
||||
$hasUsers = Role::whereIn('id', $ids)->whereHas('users')->exists();
|
||||
if ($hasUsers) {
|
||||
throw ValidationException::withMessages([
|
||||
'ids' => ['选中的角色中还有用户,无法删除'],
|
||||
]);
|
||||
}
|
||||
|
||||
return Role::whereIn('id', $ids)->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量更新角色状态
|
||||
*/
|
||||
public function batchUpdateStatus(array $ids, int $status): int
|
||||
{
|
||||
return Role::whereIn('id', $ids)->update(['status' => $status]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分配权限
|
||||
*/
|
||||
public function assignPermissions(int $id, array $permissionIds): void
|
||||
{
|
||||
$role = Role::find($id);
|
||||
|
||||
if (!$role) {
|
||||
throw ValidationException::withMessages([
|
||||
'id' => ['角色不存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
$role->permissions()->sync($permissionIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色的权限列表
|
||||
*/
|
||||
public function getPermissions(int $id): array
|
||||
{
|
||||
$role = Role::with(['permissions' => function ($query) {
|
||||
$query->orderBy('sort', 'asc');
|
||||
}])->find($id);
|
||||
|
||||
if (!$role) {
|
||||
throw ValidationException::withMessages([
|
||||
'id' => ['角色不存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->buildPermissionTree($role->permissions);
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制角色
|
||||
*/
|
||||
public function copy(int $id, array $data): Role
|
||||
{
|
||||
$sourceRole = Role::with(['permissions'])->find($id);
|
||||
|
||||
if (!$sourceRole) {
|
||||
throw ValidationException::withMessages([
|
||||
'id' => ['角色不存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
// 检查新角色名称是否已存在
|
||||
if (Role::where('name', $data['name'])->exists()) {
|
||||
throw ValidationException::withMessages([
|
||||
'name' => ['角色名称已存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
// 检查新角色编码是否已存在
|
||||
if (Role::where('code', $data['code'])->exists()) {
|
||||
throw ValidationException::withMessages([
|
||||
'code' => ['角色编码已存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
// 创建新角色
|
||||
$newRole = Role::create([
|
||||
'name' => $data['name'],
|
||||
'code' => $data['code'],
|
||||
'description' => $data['description'] ?? $sourceRole->description,
|
||||
'sort' => $data['sort'] ?? $sourceRole->sort,
|
||||
'status' => $data['status'] ?? 1,
|
||||
]);
|
||||
|
||||
// 复制权限
|
||||
$permissionIds = $sourceRole->permissions->pluck('id')->toArray();
|
||||
if (!empty($permissionIds)) {
|
||||
$newRole->permissions()->attach($permissionIds);
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
return $newRole;
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量复制角色
|
||||
*/
|
||||
public function batchCopy(array $roleIds, array $data): array
|
||||
{
|
||||
$successCount = 0;
|
||||
$errorCount = 0;
|
||||
$errors = [];
|
||||
$newRoles = [];
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
foreach ($roleIds as $index => $roleId) {
|
||||
try {
|
||||
$sourceRole = Role::with(['permissions'])->find($roleId);
|
||||
|
||||
if (!$sourceRole) {
|
||||
$errors[] = "角色ID {$roleId} 不存在";
|
||||
$errorCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 生成新的名称和编码
|
||||
$newName = $data['name'] ?? ($sourceRole->name . ' (副本)');
|
||||
$newCode = $data['code'] ?? ($sourceRole->code . '_copy_' . time());
|
||||
|
||||
// 检查名称和编码是否已存在
|
||||
$nameSuffix = '';
|
||||
$codeSuffix = '';
|
||||
$counter = 1;
|
||||
|
||||
while (Role::where('name', $newName . $nameSuffix)->exists()) {
|
||||
$nameSuffix = ' (' . $counter . ')';
|
||||
$counter++;
|
||||
}
|
||||
|
||||
$counter = 1;
|
||||
while (Role::where('code', $newCode . $codeSuffix)->exists()) {
|
||||
$codeSuffix = '_' . $counter;
|
||||
$counter++;
|
||||
}
|
||||
|
||||
// 创建新角色
|
||||
$newRole = Role::create([
|
||||
'name' => $newName . $nameSuffix,
|
||||
'code' => $newCode . $codeSuffix,
|
||||
'description' => $data['description'] ?? $sourceRole->description,
|
||||
'sort' => $data['sort'] ?? $sourceRole->sort,
|
||||
'status' => $data['status'] ?? 1,
|
||||
]);
|
||||
|
||||
// 复制权限
|
||||
$permissionIds = $sourceRole->permissions->pluck('id')->toArray();
|
||||
if (!empty($permissionIds)) {
|
||||
$newRole->permissions()->attach($permissionIds);
|
||||
}
|
||||
|
||||
$newRoles[] = [
|
||||
'id' => $newRole->id,
|
||||
'name' => $newRole->name,
|
||||
'code' => $newRole->code,
|
||||
];
|
||||
|
||||
$successCount++;
|
||||
} catch (\Exception $e) {
|
||||
$errors[] = "复制角色ID {$roleId} 失败:" . $e->getMessage();
|
||||
$errorCount++;
|
||||
}
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return [
|
||||
'success_count' => $successCount,
|
||||
'error_count' => $errorCount,
|
||||
'errors' => $errors,
|
||||
'new_roles' => $newRoles,
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建权限树
|
||||
*/
|
||||
private function buildPermissionTree($permissions, $parentId = 0): array
|
||||
{
|
||||
$tree = [];
|
||||
foreach ($permissions as $permission) {
|
||||
if ($permission->parent_id == $parentId) {
|
||||
$node = [
|
||||
'id' => $permission->id,
|
||||
'name' => $permission->name,
|
||||
'code' => $permission->code,
|
||||
'type' => $permission->type,
|
||||
'route' => $permission->route,
|
||||
'component' => $permission->component,
|
||||
'meta' => $permission->meta,
|
||||
'sort' => $permission->sort,
|
||||
'status' => $permission->status,
|
||||
'children' => $this->buildPermissionTree($permissions, $permission->id),
|
||||
];
|
||||
$tree[] = $node;
|
||||
}
|
||||
}
|
||||
return $tree;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Auth;
|
||||
|
||||
use App\Models\Auth\User;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class UserOnlineService
|
||||
{
|
||||
protected $cachePrefix = 'user_online:';
|
||||
protected $expireMinutes = 5;
|
||||
|
||||
/**
|
||||
* 设置用户在线
|
||||
*/
|
||||
public function setOnline(int $userId, string $token): void
|
||||
{
|
||||
$key = $this->getCacheKey($userId, $token);
|
||||
Cache::put($key, [
|
||||
'user_id' => $userId,
|
||||
'token' => $token,
|
||||
'last_active_at' => now()->toDateTimeString(),
|
||||
'ip' => request()->ip(),
|
||||
'user_agent' => request()->userAgent(),
|
||||
], now()->addMinutes($this->expireMinutes));
|
||||
|
||||
// 更新用户的最后在线时间
|
||||
User::where('id', $userId)->update([
|
||||
'last_active_at' => now(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户在线状态
|
||||
*/
|
||||
public function updateOnline(int $userId, string $token): void
|
||||
{
|
||||
$key = $this->getCacheKey($userId, $token);
|
||||
if (Cache::has($key)) {
|
||||
Cache::put($key, [
|
||||
'user_id' => $userId,
|
||||
'token' => $token,
|
||||
'last_active_at' => now()->toDateTimeString(),
|
||||
'ip' => request()->ip(),
|
||||
'user_agent' => request()->userAgent(),
|
||||
], now()->addMinutes($this->expireMinutes));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置用户离线
|
||||
*/
|
||||
public function setOffline(int $userId, string $token): void
|
||||
{
|
||||
$key = $this->getCacheKey($userId, $token);
|
||||
Cache::forget($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置用户所有设备离线
|
||||
*/
|
||||
public function setAllOffline(int $userId): void
|
||||
{
|
||||
$pattern = $this->cachePrefix . $userId . ':*';
|
||||
$keys = Cache::store('redis')->getPrefix() . $pattern;
|
||||
|
||||
// Redis 模式删除
|
||||
if (Cache::getStore() instanceof \Illuminate\Cache\RedisStore) {
|
||||
$redis = Cache::getStore()->connection();
|
||||
$keys = $redis->keys($this->cachePrefix . $userId . ':*');
|
||||
if (!empty($keys)) {
|
||||
$redis->del($keys);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否在线
|
||||
*/
|
||||
public function isOnline(int $userId): bool
|
||||
{
|
||||
$pattern = $this->cachePrefix . $userId . ':*';
|
||||
|
||||
if (Cache::getStore() instanceof \Illuminate\Cache\RedisStore) {
|
||||
$redis = Cache::getStore()->connection();
|
||||
$keys = $redis->keys($this->cachePrefix . $userId . ':*');
|
||||
return !empty($keys);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户在线信息
|
||||
*/
|
||||
public function getOnlineInfo(int $userId, string $token): ?array
|
||||
{
|
||||
$key = $this->getCacheKey($userId, $token);
|
||||
return Cache::get($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户所有在线会话
|
||||
*/
|
||||
public function getUserSessions(int $userId): array
|
||||
{
|
||||
$sessions = [];
|
||||
|
||||
if (Cache::getStore() instanceof \Illuminate\Cache\RedisStore) {
|
||||
$redis = Cache::getStore()->connection();
|
||||
$keys = $redis->keys($this->cachePrefix . $userId . ':*');
|
||||
|
||||
foreach ($keys as $key) {
|
||||
$session = $redis->get($key);
|
||||
if ($session) {
|
||||
$sessions[] = json_decode($session, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $sessions;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有在线用户数量
|
||||
*/
|
||||
public function getOnlineCount(): int
|
||||
{
|
||||
$count = 0;
|
||||
|
||||
if (Cache::getStore() instanceof \Illuminate\Cache\RedisStore) {
|
||||
$redis = Cache::getStore()->connection();
|
||||
$keys = $redis->keys($this->cachePrefix . '*');
|
||||
// 去重用户ID
|
||||
$userIds = [];
|
||||
foreach ($keys as $key) {
|
||||
preg_match('/user_online:(\d+):/', $key, $matches);
|
||||
if (isset($matches[1])) {
|
||||
$userIds[$matches[1]] = true;
|
||||
}
|
||||
}
|
||||
$count = count($userIds);
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取在线用户列表
|
||||
*/
|
||||
public function getOnlineUsers(int $limit = 100): array
|
||||
{
|
||||
$onlineUsers = [];
|
||||
|
||||
if (Cache::getStore() instanceof \Illuminate\Cache\RedisStore) {
|
||||
$redis = Cache::getStore()->connection();
|
||||
$keys = $redis->keys($this->cachePrefix . '*');
|
||||
|
||||
$userIds = [];
|
||||
$userSessions = [];
|
||||
|
||||
foreach ($keys as $key) {
|
||||
$session = $redis->get($key);
|
||||
if ($session) {
|
||||
$session = json_decode($session, true);
|
||||
$userId = $session['user_id'];
|
||||
if (!isset($userIds[$userId])) {
|
||||
$userIds[$userId] = $userId;
|
||||
}
|
||||
$userSessions[$userId] = $session;
|
||||
}
|
||||
}
|
||||
|
||||
$userIdList = array_values(array_slice($userIds, 0, $limit));
|
||||
$users = User::whereIn('id', $userIdList)->get();
|
||||
|
||||
foreach ($users as $user) {
|
||||
$onlineUsers[] = [
|
||||
'id' => $user->id,
|
||||
'username' => $user->username,
|
||||
'real_name' => $user->real_name,
|
||||
'avatar' => $user->avatar,
|
||||
'last_active_at' => $userSessions[$user->id]['last_active_at'] ?? null,
|
||||
'ip' => $userSessions[$user->id]['ip'] ?? null,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $onlineUsers;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理过期会话
|
||||
*/
|
||||
public function cleanExpiredSessions(): int
|
||||
{
|
||||
// Redis 的 TTL 会自动清理过期键
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成缓存键
|
||||
*/
|
||||
protected function getCacheKey(int $userId, string $token): string
|
||||
{
|
||||
return $this->cachePrefix . $userId . ':' . md5($token);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Auth;
|
||||
|
||||
use App\Models\Auth\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use App\Exports\Auth\UserExport;
|
||||
use App\Imports\Auth\UserImport;
|
||||
use App\Jobs\Auth\UserImportJob;
|
||||
use App\Jobs\Auth\UserExportJob;
|
||||
|
||||
class UserService
|
||||
{
|
||||
/**
|
||||
* 获取用户列表
|
||||
*/
|
||||
public function getList(array $params): array
|
||||
{
|
||||
$query = User::with(['department', 'roles']);
|
||||
|
||||
// 搜索条件
|
||||
if (!empty($params['keyword'])) {
|
||||
$query->where(function ($q) use ($params) {
|
||||
$q->where('username', 'like', '%' . $params['keyword'] . '%')
|
||||
->orWhere('real_name', 'like', '%' . $params['keyword'] . '%')
|
||||
->orWhere('phone', 'like', '%' . $params['keyword'] . '%')
|
||||
->orWhere('email', 'like', '%' . $params['keyword'] . '%');
|
||||
});
|
||||
}
|
||||
|
||||
if (!empty($params['department_id'])) {
|
||||
$query->where('department_id', $params['department_id']);
|
||||
}
|
||||
|
||||
if (isset($params['status']) && $params['status'] !== '') {
|
||||
$query->where('status', $params['status']);
|
||||
}
|
||||
|
||||
if (!empty($params['role_id'])) {
|
||||
$query->whereHas('roles', function ($q) use ($params) {
|
||||
$q->where('role_id', $params['role_id']);
|
||||
});
|
||||
}
|
||||
|
||||
// 排序
|
||||
$orderBy = $params['order_by'] ?? 'id';
|
||||
$orderDirection = $params['order_direction'] ?? 'desc';
|
||||
$query->orderBy($orderBy, $orderDirection);
|
||||
|
||||
// 分页
|
||||
$page = $params['page'] ?? 1;
|
||||
$pageSize = $params['page_size'] ?? 20;
|
||||
$list = $query->paginate($pageSize, ['*'], 'page', $page);
|
||||
|
||||
return [
|
||||
'list' => $list->items(),
|
||||
'total' => $list->total(),
|
||||
'page' => $page,
|
||||
'page_size' => $pageSize,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户详情
|
||||
*/
|
||||
public function getById(int $id): array
|
||||
{
|
||||
$user = User::with(['department', 'roles'])->find($id);
|
||||
|
||||
if (!$user) {
|
||||
throw ValidationException::withMessages([
|
||||
'id' => ['用户不存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->formatUserInfo($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建用户
|
||||
*/
|
||||
public function create(array $data): User
|
||||
{
|
||||
// 检查用户名是否已存在
|
||||
if (User::where('username', $data['username'])->exists()) {
|
||||
throw ValidationException::withMessages([
|
||||
'username' => ['用户名已存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
// 检查手机号是否已存在
|
||||
if (!empty($data['phone']) && User::where('phone', $data['phone'])->exists()) {
|
||||
throw ValidationException::withMessages([
|
||||
'phone' => ['手机号已被使用'],
|
||||
]);
|
||||
}
|
||||
|
||||
// 检查邮箱是否已存在
|
||||
if (!empty($data['email']) && User::where('email', $data['email'])->exists()) {
|
||||
throw ValidationException::withMessages([
|
||||
'email' => ['邮箱已被使用'],
|
||||
]);
|
||||
}
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$user = User::create([
|
||||
'username' => $data['username'],
|
||||
'password' => Hash::make($data['password']),
|
||||
'real_name' => $data['real_name'],
|
||||
'email' => $data['email'] ?? null,
|
||||
'phone' => $data['phone'] ?? null,
|
||||
'department_id' => $data['department_id'] ?? null,
|
||||
'avatar' => $data['avatar'] ?? null,
|
||||
'status' => $data['status'] ?? 1,
|
||||
]);
|
||||
|
||||
// 关联角色
|
||||
if (!empty($data['role_ids'])) {
|
||||
$user->roles()->attach($data['role_ids']);
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
return $user;
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户
|
||||
*/
|
||||
public function update(int $id, array $data): User
|
||||
{
|
||||
$user = User::find($id);
|
||||
|
||||
if (!$user) {
|
||||
throw ValidationException::withMessages([
|
||||
'id' => ['用户不存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
// 检查用户名是否已被其他用户使用
|
||||
if (isset($data['username']) && $data['username'] !== $user->username) {
|
||||
if (User::where('username', $data['username'])->exists()) {
|
||||
throw ValidationException::withMessages([
|
||||
'username' => ['用户名已存在'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// 检查手机号是否已被其他用户使用
|
||||
if (isset($data['phone']) && $data['phone'] !== $user->phone) {
|
||||
if (User::where('phone', $data['phone'])->exists()) {
|
||||
throw ValidationException::withMessages([
|
||||
'phone' => ['手机号已被使用'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// 检查邮箱是否已被其他用户使用
|
||||
if (isset($data['email']) && $data['email'] !== $user->email) {
|
||||
if (User::where('email', $data['email'])->exists()) {
|
||||
throw ValidationException::withMessages([
|
||||
'email' => ['邮箱已被使用'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$updateData = [
|
||||
'real_name' => $data['real_name'] ?? $user->real_name,
|
||||
'email' => $data['email'] ?? $user->email,
|
||||
'phone' => $data['phone'] ?? $user->phone,
|
||||
'department_id' => $data['department_id'] ?? $user->department_id,
|
||||
'avatar' => $data['avatar'] ?? $user->avatar,
|
||||
'status' => $data['status'] ?? $user->status,
|
||||
];
|
||||
|
||||
if (isset($data['username'])) {
|
||||
$updateData['username'] = $data['username'];
|
||||
}
|
||||
|
||||
if (isset($data['password'])) {
|
||||
$updateData['password'] = Hash::make($data['password']);
|
||||
}
|
||||
|
||||
$user->update($updateData);
|
||||
|
||||
// 更新角色关联
|
||||
if (isset($data['role_ids'])) {
|
||||
$user->roles()->sync($data['role_ids']);
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
return $user;
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
*/
|
||||
public function delete(int $id): void
|
||||
{
|
||||
$user = User::find($id);
|
||||
|
||||
if (!$user) {
|
||||
throw ValidationException::withMessages([
|
||||
'id' => ['用户不存在'],
|
||||
]);
|
||||
}
|
||||
|
||||
$user->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除用户
|
||||
*/
|
||||
public function batchDelete(array $ids): int
|
||||
{
|
||||
return User::whereIn('id', $ids)->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量更新用户状态
|
||||
*/
|
||||
public function batchUpdateStatus(array $ids, int $status): int
|
||||
{
|
||||
return User::whereIn('id', $ids)->update(['status' => $status]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量分配部门
|
||||
*/
|
||||
public function batchAssignDepartment(array $ids, int $departmentId): int
|
||||
{
|
||||
return User::whereIn('id', $ids)->update(['department_id' => $departmentId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量分配角色
|
||||
*/
|
||||
public function batchAssignRoles(array $ids, array $roleIds): void
|
||||
{
|
||||
foreach ($ids as $userId) {
|
||||
$user = User::find($userId);
|
||||
if ($user) {
|
||||
$user->roles()->sync($roleIds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出用户数据
|
||||
*/
|
||||
public function export(array $params): string
|
||||
{
|
||||
// 异步导出
|
||||
$job = new UserExportJob($params);
|
||||
dispatch($job);
|
||||
|
||||
return '导出任务已提交,请稍后在导出列表中查看';
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入用户数据
|
||||
*/
|
||||
public function import(\Illuminate\Http\UploadedFile $file): array
|
||||
{
|
||||
$path = $file->store('imports');
|
||||
|
||||
// 异步导入
|
||||
$job = new UserImportJob($path);
|
||||
dispatch($job);
|
||||
|
||||
return [
|
||||
'message' => '导入任务已提交,请稍后在导入列表中查看',
|
||||
'file_path' => $path,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化用户信息
|
||||
*/
|
||||
private function formatUserInfo(User $user): array
|
||||
{
|
||||
return [
|
||||
'id' => $user->id,
|
||||
'username' => $user->username,
|
||||
'real_name' => $user->real_name,
|
||||
'email' => $user->email,
|
||||
'phone' => $user->phone,
|
||||
'avatar' => $user->avatar,
|
||||
'department' => $user->department ? [
|
||||
'id' => $user->department->id,
|
||||
'name' => $user->department->name,
|
||||
] : null,
|
||||
'roles' => $user->roles->map(function ($role) {
|
||||
return [
|
||||
'id' => $role->id,
|
||||
'name' => $role->name,
|
||||
'code' => $role->code,
|
||||
];
|
||||
})->toArray(),
|
||||
'status' => $user->status,
|
||||
'last_login_at' => $user->last_login_at ? $user->last_login_at->toDateTimeString() : null,
|
||||
'last_login_ip' => $user->last_login_ip,
|
||||
'created_at' => $user->created_at->toDateTimeString(),
|
||||
'updated_at' => $user->updated_at->toDateTimeString(),
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user