249 lines
8.4 KiB
PHP
249 lines
8.4 KiB
PHP
<?php
|
|
// +----------------------------------------------------------------------
|
|
// | saiadmin [ saiadmin快速开发框架 ]
|
|
// +----------------------------------------------------------------------
|
|
// | Author: sai <1430792918@qq.com>
|
|
// +----------------------------------------------------------------------
|
|
namespace plugin\saiadmin\app\logic\system;
|
|
|
|
use app\dice\helper\AdminScopeHelper;
|
|
use plugin\saiadmin\app\cache\UserMenuCache;
|
|
use plugin\saiadmin\app\model\system\SystemRole;
|
|
use plugin\saiadmin\app\service\SystemRoleChannelService;
|
|
use plugin\saiadmin\basic\think\BaseLogic;
|
|
use plugin\saiadmin\exception\ApiException;
|
|
use support\think\Cache;
|
|
use support\think\Db;
|
|
|
|
/**
|
|
* 角色逻辑层(按渠道 dept_id 隔离)
|
|
*/
|
|
class SystemRoleLogic extends BaseLogic
|
|
{
|
|
public function __construct()
|
|
{
|
|
$this->model = new SystemRole();
|
|
}
|
|
|
|
/**
|
|
* 分页列表(按渠道过滤)
|
|
*/
|
|
public function indexList(array $where, $requestDeptId = null): array
|
|
{
|
|
$query = $this->search($where);
|
|
$this->applyDeptScope($query, $requestDeptId);
|
|
$levelArr = array_column($this->adminInfo['roleList'] ?? [], 'level');
|
|
if (!empty($levelArr)) {
|
|
$maxLevel = max($levelArr);
|
|
$query->where('level', '<', $maxLevel);
|
|
}
|
|
$query->where('id', '<>', SystemRoleChannelService::SUPER_ADMIN_ROLE_ID);
|
|
return $this->getList($query);
|
|
}
|
|
|
|
public function add($data): bool
|
|
{
|
|
$data = $this->handleData($data);
|
|
$deptId = AdminScopeHelper::normalizeRecordDeptId($data['dept_id'] ?? null);
|
|
$data['dept_id'] = $deptId;
|
|
$this->assertCodeUniqueInDept($data['code'] ?? '', $deptId, null);
|
|
return $this->model->save($data);
|
|
}
|
|
|
|
public function edit($id, $data): bool
|
|
{
|
|
$model = $this->model->findOrEmpty($id);
|
|
if ($model->isEmpty()) {
|
|
throw new ApiException('Data not found');
|
|
}
|
|
$this->assertRoleWritable($model);
|
|
$data = $this->handleData($data);
|
|
$deptId = AdminScopeHelper::normalizeRecordDeptId($model->dept_id ?? $data['dept_id'] ?? null);
|
|
$data['dept_id'] = $deptId;
|
|
$this->assertCodeUniqueInDept($data['code'] ?? '', $deptId, (int) $id);
|
|
return $model->save($data);
|
|
}
|
|
|
|
public function destroy($ids): bool
|
|
{
|
|
$levelArr = array_column($this->adminInfo['roleList'] ?? [], 'level');
|
|
$maxLevel = !empty($levelArr) ? max($levelArr) : 100;
|
|
|
|
$idList = is_array($ids) ? $ids : explode(',', (string) $ids);
|
|
foreach ($idList as $roleId) {
|
|
$roleId = (int) $roleId;
|
|
if ($roleId === SystemRoleChannelService::SUPER_ADMIN_ROLE_ID) {
|
|
throw new ApiException('Cannot delete super admin role');
|
|
}
|
|
$role = $this->model->find($roleId);
|
|
if (!$role) {
|
|
continue;
|
|
}
|
|
$this->assertRoleWritable($role);
|
|
if ((int) ($role->level ?? 0) >= $maxLevel) {
|
|
throw new ApiException('Cannot operate roles with higher level than current account');
|
|
}
|
|
}
|
|
|
|
return $this->model->destroy($ids);
|
|
}
|
|
|
|
protected function handleData($data)
|
|
{
|
|
$levelArr = array_column($this->adminInfo['roleList'] ?? [], 'level');
|
|
if (!empty($levelArr)) {
|
|
$maxLevel = max($levelArr);
|
|
if (($data['level'] ?? 0) >= $maxLevel) {
|
|
throw new ApiException('Cannot operate roles with higher level than current account');
|
|
}
|
|
}
|
|
return $data;
|
|
}
|
|
|
|
public function accessRole(array $where = [], $requestDeptId = null): array
|
|
{
|
|
$query = $this->search($where);
|
|
$this->applyDeptScope($query, $requestDeptId);
|
|
$levelArr = array_column($this->adminInfo['roleList'] ?? [], 'level');
|
|
if (!empty($levelArr)) {
|
|
$maxLevel = max($levelArr);
|
|
$query->where('level', '<', $maxLevel);
|
|
}
|
|
$query->where('id', '<>', SystemRoleChannelService::SUPER_ADMIN_ROLE_ID);
|
|
$query->order('sort', 'desc');
|
|
return $this->getAll($query);
|
|
}
|
|
|
|
public function getMenuIdsByRoleIds($ids): array
|
|
{
|
|
if (empty($ids)) {
|
|
return [];
|
|
}
|
|
return $this->model->where('id', 'in', $ids)->with([
|
|
'menus' => function ($query) {
|
|
$query->where('status', 1)->order('sort', 'desc');
|
|
}
|
|
])->select()->toArray();
|
|
}
|
|
|
|
public function getMenuByRole($id): array
|
|
{
|
|
$role = $this->model->findOrEmpty($id);
|
|
if ($role->isEmpty()) {
|
|
throw new ApiException('Data not found');
|
|
}
|
|
$this->assertRoleWritable($role);
|
|
$menus = $role->menus ?: [];
|
|
return [
|
|
'id' => $id,
|
|
'menus' => $menus
|
|
];
|
|
}
|
|
|
|
public function saveMenuPermission($id, $menu_ids): mixed
|
|
{
|
|
$role = $this->model->findOrEmpty($id);
|
|
if ($role->isEmpty()) {
|
|
throw new ApiException('Data not found');
|
|
}
|
|
$this->assertRoleWritable($role);
|
|
|
|
return $this->transaction(function () use ($id, $menu_ids) {
|
|
$role = $this->model->findOrEmpty($id);
|
|
if ($role) {
|
|
$role->menus()->detach();
|
|
$data = array_map(function ($menu_id) use ($id) {
|
|
return ['menu_id' => $menu_id, 'role_id' => $id];
|
|
}, $menu_ids);
|
|
Db::name('sa_system_role_menu')->limit(100)->insertAll($data);
|
|
}
|
|
$cache = config('plugin.saiadmin.saithink.button_cache');
|
|
$tag = $cache['role'] . $id;
|
|
Cache::tag($tag)->clear();
|
|
UserMenuCache::clearMenuCache();
|
|
return true;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 解析并校验当前请求应操作的渠道 ID
|
|
*/
|
|
public function resolveRequestDeptId($requestDeptId): int
|
|
{
|
|
if ((int) ($this->adminInfo['id'] ?? 0) === 1) {
|
|
return AdminScopeHelper::resolveConfigDeptId($this->adminInfo, $requestDeptId);
|
|
}
|
|
$deptLogic = new SystemDeptLogic();
|
|
$deptLogic->init($this->adminInfo);
|
|
return $deptLogic->resolveAccessibleDeptId();
|
|
}
|
|
|
|
/**
|
|
* 列表/下拉按渠道过滤
|
|
*/
|
|
protected function applyDeptScope($query, $requestDeptId = null): void
|
|
{
|
|
if (!$this->tableHasDeptIdColumn()) {
|
|
return;
|
|
}
|
|
if ((int) ($this->adminInfo['id'] ?? 0) === 1) {
|
|
$deptId = AdminScopeHelper::resolveConfigDeptId($this->adminInfo, $requestDeptId);
|
|
$query->where('dept_id', $deptId);
|
|
return;
|
|
}
|
|
$deptLogic = new SystemDeptLogic();
|
|
$deptLogic->init($this->adminInfo);
|
|
$deptId = $deptLogic->resolveAccessibleDeptId();
|
|
if ($deptId > 0) {
|
|
$query->where('dept_id', $deptId);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 校验角色属于当前可操作渠道
|
|
*/
|
|
public function assertRoleWritable($role): void
|
|
{
|
|
if (!$this->tableHasDeptIdColumn()) {
|
|
return;
|
|
}
|
|
$roleDeptId = AdminScopeHelper::normalizeRecordDeptId($role->dept_id ?? null);
|
|
if ((int) ($role->id ?? 0) === SystemRoleChannelService::SUPER_ADMIN_ROLE_ID) {
|
|
throw new ApiException('Cannot operate super admin role');
|
|
}
|
|
if ((int) ($this->adminInfo['id'] ?? 0) === 1) {
|
|
return;
|
|
}
|
|
$deptLogic = new SystemDeptLogic();
|
|
$deptLogic->init($this->adminInfo);
|
|
$scopeDeptId = $deptLogic->resolveAccessibleDeptId();
|
|
if ($scopeDeptId > 0 && $roleDeptId !== $scopeDeptId) {
|
|
throw new ApiException('No permission to operate this channel role');
|
|
}
|
|
}
|
|
|
|
protected function assertCodeUniqueInDept(string $code, int $deptId, ?int $excludeId): void
|
|
{
|
|
if ($code === '') {
|
|
return;
|
|
}
|
|
$query = SystemRole::where('code', $code)->where('dept_id', $deptId);
|
|
if ($excludeId !== null && $excludeId > 0) {
|
|
$query->where('id', '<>', $excludeId);
|
|
}
|
|
if ($query->count() > 0) {
|
|
throw new ApiException('Role code already exists in this channel');
|
|
}
|
|
}
|
|
|
|
protected function tableHasDeptIdColumn(): bool
|
|
{
|
|
try {
|
|
$fields = Db::getFields((new SystemRole())->getTable());
|
|
return isset($fields['dept_id']);
|
|
} catch (\Throwable $e) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|