1.将部门修改为渠道,并且所有dice_表关联渠道表

2.将所有配置表,记录表设置关联渠道
3.优化后台页面设置
This commit is contained in:
2026-05-19 09:49:02 +08:00
parent 085454fb78
commit dd264b1e97
143 changed files with 4741 additions and 1254 deletions

View File

@@ -2,129 +2,123 @@
// +----------------------------------------------------------------------
// | saiadmin [ saiadmin快速开发框架 ]
// +----------------------------------------------------------------------
// | Author: sai <1430792918@qq.com>
// +----------------------------------------------------------------------
namespace plugin\saiadmin\app\logic\system;
use app\dice\service\DiceChannelConfigService;
use plugin\saiadmin\app\service\SystemRoleChannelService;
use plugin\saiadmin\basic\think\BaseLogic;
use plugin\saiadmin\exception\ApiException;
use plugin\saiadmin\app\model\system\SystemDept;
use plugin\saiadmin\app\model\system\SystemUser;
use plugin\saiadmin\utils\Helper;
use plugin\saiadmin\utils\Arr;
/**
* 部门逻辑层
* 渠道逻辑层(表 sa_system_dept
*/
class SystemDeptLogic extends BaseLogic
{
/**
* 构造函数
*/
public function __construct()
{
$this->model = new SystemDept();
}
/**
* 添加数据
*/
public function add($data): mixed
{
$data = $this->handleData($data);
$this->model->save($data);
return $this->model->getKey();
$deptId = (int) $this->model->getKey();
if ($deptId > 0) {
(new DiceChannelConfigService())->copyDefaultConfigToDept($deptId);
(new SystemRoleChannelService())->copyDefaultRolesToDept($deptId, false);
}
return $deptId;
}
/**
* 修改数据
*/
public function edit($id, $data): mixed
{
$oldLevel = $data['level'] . $id . ',';
$data = $this->handleData($data);
if ($data['parent_id'] == $id) {
throw new ApiException('Parent department cannot be the same as current department');
}
if (in_array($id, explode(',', $data['level']))) {
throw new ApiException('Cannot set parent department to a child of current department');
}
$newLevel = $data['level'] . $id . ',';
$deptIds = $this->model->where('level', 'like', $oldLevel . '%')->column('id');
return $this->transaction(function () use ($deptIds, $oldLevel, $newLevel, $data, $id) {
$this->model->whereIn('id', $deptIds)->exp('level', "REPLACE(level, '$oldLevel', '$newLevel')")->update([]);
return $this->model->update($data, ['id' => $id]);
});
return $this->model->update($data, ['id' => $id]);
}
/**
* 数据删除
*/
public function destroy($ids): bool
{
$num = $this->model->where('parent_id', 'in', $ids)->count();
if ($num > 0) {
throw new ApiException('This department has sub-departments, please delete them first');
} else {
$count = SystemUser::where('dept_id', 'in', $ids)->count();
if ($count > 0) {
throw new ApiException('This department has users, please delete or transfer them first');
}
return $this->model->destroy($ids);
$count = SystemUser::where('dept_id', 'in', $ids)->count();
if ($count > 0) {
throw new ApiException('This channel has users, please delete or transfer them first');
}
return $this->model->destroy($ids);
}
/**
* 数据处理
* 带关联选项删除渠道
*/
public function destroyWithRelations(int $deptId, array $deleteTables): bool
{
(new SystemRoleChannelService())->deleteRolesByDept($deptId);
(new DiceChannelConfigService())->destroyDeptWithRelations($deptId, $deleteTables);
return true;
}
public function getDestroyPreview(array $deptIds): array
{
return (new DiceChannelConfigService())->getDestroyPreview($deptIds);
}
public function syncAllChannelConfigs(): array
{
$config = (new DiceChannelConfigService())->syncAllChannelsFromDefault();
$roles = (new SystemRoleChannelService())->syncAllChannelsFromDefault();
return ['config' => $config, 'roles' => $roles];
}
protected function handleData($data)
{
// 处理上级部门
if (empty($data['parent_id']) || $data['parent_id'] == 0) {
$data['level'] = '0';
$data['parent_id'] = 0;
} else {
$parentMenu = SystemDept::findOrEmpty($data['parent_id']);
$data['level'] = $parentMenu['level'] . $parentMenu['id'] . ',';
}
$data['level'] = '0';
$data['parent_id'] = 0;
return $data;
}
/**
* 数据树形化
* @param array $where
* @return array
*/
public function tree(array $where = []): array
{
$query = $this->search($where);
$request = request();
if ($request && $request->input('tree', 'false') === 'true') {
$query->field('id, id as value, name as label, parent_id');
}
$query->order('sort', 'desc');
$query->with(['leader']);
$data = $this->getAll($query);
return Helper::makeTree($data);
return $this->getAll($query);
}
/**
* 可操作部门
* @param array $where
* @return array
*/
public function accessDept(array $where = []): array
{
$query = $this->search($where);
// 超级管理员(id=1)可查看全部部门,普通管理员按部门权限过滤
if (isset($this->adminInfo['id']) && $this->adminInfo['id'] > 1) {
$query->auth($this->adminInfo['deptList'] ?? []);
$deptId = $this->resolveAccessibleDeptId();
if ($deptId > 0) {
$query->where('id', $deptId);
} else {
return [];
}
}
$query->field('id, id as value, name as label, parent_id');
$query->field('id, id as value, name as label');
$query->order('sort', 'desc');
$data = $this->getAll($query);
return Helper::makeTree($data);
return $this->getAll($query);
}
/**
* 当前管理员可操作的渠道 IDdeptList 缺失时回退 dept_id
*/
public function resolveAccessibleDeptId(?array $adminInfo = null): int
{
$adminInfo = $adminInfo ?? $this->adminInfo ?? [];
if (empty($adminInfo['id']) || (int) $adminInfo['id'] <= 1) {
return 0;
}
$deptList = $adminInfo['deptList'] ?? [];
if (is_array($deptList) && isset($deptList['id']) && (int) $deptList['id'] > 0) {
return (int) $deptList['id'];
}
$deptId = $adminInfo['dept_id'] ?? null;
if ($deptId !== null && $deptId !== '' && (int) $deptId > 0) {
return (int) $deptId;
}
return 0;
}
}

View File

@@ -6,121 +6,133 @@
// +----------------------------------------------------------------------
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 plugin\saiadmin\utils\Helper;
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 = max($levelArr);
$levelArr = array_column($this->adminInfo['roleList'] ?? [], 'level');
$maxLevel = !empty($levelArr) ? max($levelArr) : 100;
$num = SystemRole::where('level', '>=', $maxLevel)->whereIn('id', $ids)->count();
if ($num > 0) {
throw new ApiException('Cannot operate roles with higher level than current account');
} else {
return $this->model->destroy($ids);
$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');
$maxLevel = max($levelArr);
if ($data['level'] >= $maxLevel) {
throw new ApiException('Cannot operate roles with higher level than current account');
$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;
}
/**
* 可操作角色
* @param array $where
* @return array
*/
public function accessRole(array $where = []): array
public function accessRole(array $where = [], $requestDeptId = null): array
{
$query = $this->search($where);
// 越权保护
$levelArr = array_column($this->adminInfo['roleList'], 'level');
$maxLevel = max($levelArr);
$query->where('level', '<', $maxLevel);
$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);
}
/**
* 根据角色数组获取菜单
* @param $ids
* @return array
*/
public function getMenuIdsByRoleIds($ids): array
{
if (empty($ids))
if (empty($ids)) {
return [];
}
return $this->model->where('id', 'in', $ids)->with([
'menus' => function ($query) {
$query->where('status', 1)->order('sort', 'desc');
}
])->select()->toArray();
}
/**
* 根据角色获取菜单
* @param $id
* @return array
*/
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,
@@ -128,14 +140,14 @@ class SystemRoleLogic extends BaseLogic
];
}
/**
* 保存菜单权限
* @param $id
* @param $menu_ids
* @return mixed
*/
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) {
@@ -147,10 +159,90 @@ class SystemRoleLogic extends BaseLogic
}
$cache = config('plugin.saiadmin.saithink.button_cache');
$tag = $cache['role'] . $id;
Cache::tag($tag)->clear(); // 清理权限缓存-角色TAG
UserMenuCache::clearMenuCache(); // 清理菜单缓存
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;
}
}
}

View File

@@ -40,9 +40,16 @@ class SystemUserLogic extends BaseLogic
{
$query = $this->search($where);
$query->with(['depts']);
// 超级管理员(id=1)可查看全部用户,普通管理员按部门权限过滤
// 超级管理员(id=1)可查看全部用户,渠道管理员按本渠道过滤
if (isset($this->adminInfo['id']) && $this->adminInfo['id'] > 1) {
$query->auth($this->adminInfo['deptList'] ?? []);
$deptLogic = new SystemDeptLogic();
$deptLogic->init($this->adminInfo);
$deptId = $deptLogic->resolveAccessibleDeptId();
if ($deptId > 0) {
$query->where('dept_id', $deptId);
} else {
$query->auth($this->adminInfo['deptList'] ?? []);
}
}
return $this->getList($query);
}
@@ -70,6 +77,12 @@ class SystemUserLogic extends BaseLogic
$data = $admin->hidden(['password'])->toArray();
$data['roleList'] = $admin->roles->toArray() ?: [];
$data['deptList'] = $admin->depts ? $admin->depts->toArray() : [];
if (empty($data['deptList']) && ! empty($admin->dept_id)) {
$dept = SystemDept::find($admin->dept_id);
if ($dept && ! $dept->isEmpty()) {
$data['deptList'] = $dept->toArray();
}
}
return $data;
}