This commit is contained in:
zimoyin
2026-04-03 15:34:04 +08:00
parent 1a84e92384
commit 673c83109f
5 changed files with 894 additions and 247 deletions
+56 -180
View File
@@ -5,10 +5,10 @@ namespace plugin\admin\app\model;
use app\utils\Logger;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Builder;
use plugin\admin\app\common\DataPermissionService;
use support\Db;
use support\Model;
/**
* @method static \Illuminate\Database\Eloquent\Builder|static withDataPermission()
*/
@@ -20,194 +20,70 @@ class Base extends Model
protected $connection = 'plugin.admin.mysql';
/**
* 格式化日期
*
* @param DateTimeInterface $date
* @return string
* --------------------------
* 【核心配置】权限规则配置
* 新增规则只需在这里加一项,无需改下面的逻辑
* --------------------------
*/
protected function serializeDate(DateTimeInterface $date)
protected function getPermissionRules(): array
{
return [
// 规则1:医院权限
'hospital' => [
'table' => 'opm_mw_hospital', // 表名
'admin_attr' => 'hospitals', // 用户属性里的键($admin['hospitals']
'permission_field'=> 'id', // 表中用于权限过滤的字段
'related_field' => null, // 关联上级权限的字段(如科室关联医院的organ_id)
'related_rule' => null, // 关联的上级规则key(对应上面的'hospital'
],
// 规则2:科室权限
'department' => [
'table' => 'opm_mw_department',
'admin_attr' => 'departments',
'permission_field'=> 'id',
'related_field' => 'organ_id', // 科室通过organ_id关联医院
'related_rule' => 'hospital', // 关联上级规则:医院
],
// 规则3:数据权限
// 这个需要绑定 医院的.id
// 这个需要绑定 科室的.id
'data' => [
'table' => 'opm_mw_info_data',
'admin_attr' => 'data',
'permission_field'=> 'id',
'related_field' => null,
'related_rule' => null,
],
];
}
/**
* 格式化日期
*/
protected function serializeDate(DateTimeInterface $date): string
{
return $date->format('Y-m-d H:i:s');
}
public function scopeWithDataPermission(Builder $query): Builder
public function scopeWithDataPermission(Builder $query): Builder
{
$admin = runCatching(fn() => admin(),"无法获取登录状态")->getOrDefault([]);
$admin = runCatching(fn() => admin(), "无法获取登录状态")->getOrDefault([]);
$hospitalRaw = trim((string)($admin['hospitals'] ?? ''));
$departmentRaw = trim((string)($admin['departments'] ?? ''));
if ($hospitalRaw === '*' && $departmentRaw === '*') {
return $query;
}
$hospitalIds = $this->parseVisibleIds($hospitalRaw);
$departmentIds = $this->parseVisibleIds($departmentRaw);
if (empty($hospitalIds) && empty($departmentIds)) {
return $query->whereRaw('1 = 0');
}
$baseQuery = $query->getQuery();
// 主表
[$fromTable, $fromAlias] = $this->parseTableAlias((string)($baseQuery->from ?? ''));
// 识别 join 里的医院/科室表别名
$hospitalAlias = $this->findTableAlias($baseQuery, 'opm_mw_hospital');
$departmentAlias = $this->findTableAlias($baseQuery, 'opm_mw_department');
Logger::debug('scopeWithDataPermission fromTable:{} fromAlias:{} hospitalAlias:{} departmentAlias:{} hospitalIds:{} departmentIds:{}', [
$fromTable,
$fromAlias,
$hospitalAlias,
$departmentAlias,
$hospitalIds,
$departmentIds,
]);
// 1) 主表就是医院表:只加医院权限
if ($fromTable === 'opm_mw_hospital' && $hospitalAlias) {
if (empty($hospitalIds)) {
return $query->whereRaw('1 = 0');
// 超管判断(可选,也可以在规则里配置*)
$isSuper = true;
foreach (['hospitals', 'departments'] as $attr) {
if (($admin[$attr] ?? '') !== '*') {
$isSuper = false;
break;
}
return $query->whereIn("{$hospitalAlias}.id", $hospitalIds);
}
if ($isSuper) return $query;
// 2) 主表就是科室表:只加科室权限
if ($fromTable === 'opm_mw_department' && $departmentAlias) {
return $query->where(function (Builder $q) use ($departmentAlias, $hospitalIds, $departmentIds) {
$has = false;
// 科室权限:department.id
if (!empty($departmentIds)) {
$q->whereIn("{$departmentAlias}.id", $departmentIds);
$has = true;
}
// 医院权限:department.organ_id
if (!empty($hospitalIds)) {
if ($has) {
$q->whereIn("{$departmentAlias}.organ_id", $hospitalIds);
} else {
$q->orWhereIn("{$departmentAlias}.organ_id", $hospitalIds);
}
$has = true;
}
if (!$has) {
$q->whereRaw('1 = 0');
}
});
}
// 3) 主表不是这两个,但 join 里有它们:按别名补条件
return $query->where(function (Builder $q) use (
$hospitalAlias,
$departmentAlias,
$hospitalIds,
$departmentIds
) {
$hasAny = false;
if ($hospitalAlias && !empty($hospitalIds)) {
$q->whereIn("{$hospitalAlias}.id", $hospitalIds);
$hasAny = true;
}
if ($departmentAlias) {
$q->where(function (Builder $dq) use ($departmentAlias, $hospitalIds, $departmentIds) {
$has = false;
if (!empty($departmentIds)) {
$dq->whereIn("{$departmentAlias}.id", $departmentIds);
$has = true;
}
if (!empty($hospitalIds)) {
if ($has) {
$dq->orWhereIn("{$departmentAlias}.organ_id", $hospitalIds);
} else {
$dq->whereIn("{$departmentAlias}.organ_id", $hospitalIds);
}
$has = true;
}
if (!$has) {
$dq->whereRaw('1 = 0');
}
});
$hasAny = true;
}
if (!$hasAny) {
$q->whereRaw('1 = 0');
}
});
// 使用服务类应用权限
$service = new DataPermissionService($admin);
return $service->apply($query);
}
/**
* 解析 "table as t" / "table t"
*/
protected function parseTableAlias(string $table): array
{
$table = trim(str_replace('`', '', $table));
if ($table === '') {
return ['', ''];
}
if (stripos($table, ' as ') !== false) {
[$name, $alias] = preg_split('/\s+as\s+/i', $table, 2);
return [trim($name), trim($alias)];
}
$parts = preg_split('/\s+/', $table);
if (count($parts) >= 2) {
return [trim($parts[0]), trim($parts[1])];
}
return [$table, $table];
}
/**
* 在 from / joins 中找指定表的别名
*/
protected function findTableAlias($baseQuery, string $tableName): ?string
{
[$fromTable, $fromAlias] = $this->parseTableAlias((string)($baseQuery->from ?? ''));
if ($fromTable === $tableName) {
return $fromAlias;
}
foreach (($baseQuery->joins ?? []) as $join) {
[$joinTable, $joinAlias] = $this->parseTableAlias((string)($join->table ?? ''));
if ($joinTable === $tableName) {
return $joinAlias;
}
}
return null;
}
/**
* 把 "1,2,3" / "123" / " 1 , 2 " 转成数组
*/
protected function parseVisibleIds(string $raw): array
{
$raw = trim($raw);
if ($raw === '' || $raw === '*') {
return [];
}
$parts = preg_split('/[,\s]+/u', $raw) ?: [];
$parts = array_filter($parts, static fn($v) => $v !== '');
return array_values(array_unique(array_map('intval', $parts)));
}
}
}