200 lines
6.7 KiB
PHP
200 lines
6.7 KiB
PHP
<?php
|
||
|
||
namespace App\Utilities;
|
||
|
||
use App\Models\Auth\User;
|
||
use App\Models\Auth\UserAccessGroup;
|
||
|
||
class SidebarPermissions
|
||
{
|
||
private const LEGACY_PAGE_KEYS = [
|
||
'refunds/small-payment-work-orders' => 'financial-operations/small-payment-work-orders',
|
||
];
|
||
|
||
private const FINAL_SECTION_KEYS = [
|
||
'supplier-payables' => 'supplier-payables-final',
|
||
'courier-payables' => 'courier-payables-final',
|
||
];
|
||
|
||
public static function settings(): array
|
||
{
|
||
$value = setting('system.sidebar_permissions', []);
|
||
|
||
if (is_string($value)) {
|
||
$value = json_decode($value, true) ?: [];
|
||
}
|
||
|
||
return is_array($value) ? $value : [];
|
||
}
|
||
|
||
public static function subjectKey(User $user): string
|
||
{
|
||
$userKey = 'user_' . $user->id;
|
||
$settings = self::settings();
|
||
|
||
if (in_array($userKey, $settings['configured'] ?? [], true)) {
|
||
return $userKey;
|
||
}
|
||
|
||
return 'role_' . SystemAccess::roleName($user);
|
||
}
|
||
|
||
public static function allowedKeys(User $user): ?array
|
||
{
|
||
if (SystemAccess::isSuperAdmin($user)) {
|
||
return null;
|
||
}
|
||
|
||
$settings = self::settings();
|
||
$userSubject = 'user_' . $user->id;
|
||
if (in_array($userSubject, $settings['configured'] ?? [], true)) {
|
||
return self::normalizeAllowedKeys((array) ($settings['subjects'][$userSubject] ?? []));
|
||
}
|
||
|
||
$groups = UserAccessGroup::forUser($user);
|
||
if ($groups->isNotEmpty()) {
|
||
return self::normalizeAllowedKeys(
|
||
$groups->flatMap(fn ($group) => $group->page_permissions ?? [])->all()
|
||
);
|
||
}
|
||
|
||
$subject = 'role_' . SystemAccess::roleName($user);
|
||
|
||
if (! in_array($subject, $settings['configured'] ?? [], true)) {
|
||
return null;
|
||
}
|
||
|
||
return self::normalizeAllowedKeys((array) ($settings['subjects'][$subject] ?? []));
|
||
}
|
||
|
||
public static function navigationFor(User $user): array
|
||
{
|
||
$navigation = BusinessNavigation::all();
|
||
$allowed = self::allowedKeys($user);
|
||
|
||
if ($allowed === null) {
|
||
return $navigation;
|
||
}
|
||
|
||
$navigation = array_values(array_filter(array_map(function (array $section) use ($allowed) {
|
||
$sectionKey = $section['slug'];
|
||
|
||
if (in_array($sectionKey, $allowed, true)) {
|
||
return $section;
|
||
}
|
||
|
||
$pages = array_values(array_filter(array_map(function (array $page) use ($allowed, $sectionKey) {
|
||
$pageKey = $sectionKey . '/' . $page['slug'];
|
||
|
||
if (in_array($pageKey, $allowed, true)) {
|
||
// 若有 children,保留 children 的精确权限过滤
|
||
if (! empty($page['children'])) {
|
||
$page['children'] = array_values(array_filter($page['children'], function (array $child) use ($allowed, $sectionKey) {
|
||
return in_array($sectionKey . '/' . $child['slug'], $allowed, true);
|
||
}));
|
||
}
|
||
return $page;
|
||
}
|
||
|
||
// 子页面可能在 allowed 列表中(独立 URL),父级分组也允许展开
|
||
if (! empty($page['children'])) {
|
||
$visibleChildren = array_values(array_filter($page['children'], function (array $child) use ($allowed, $sectionKey) {
|
||
return in_array($sectionKey . '/' . $child['slug'], $allowed, true);
|
||
}));
|
||
if (! empty($visibleChildren)) {
|
||
$page['children'] = $visibleChildren;
|
||
return $page;
|
||
}
|
||
}
|
||
|
||
return null;
|
||
}, $section['pages'] ?? [])));
|
||
|
||
if (! empty($pages)) {
|
||
$section['pages'] = $pages;
|
||
|
||
return $section;
|
||
}
|
||
|
||
return null;
|
||
}, $navigation)));
|
||
|
||
// 新增的公司成本安排、税金预测表与主体经营报表共用公司经营报表权限。
|
||
// 对已经保存过精确权限的账号兼容旧配置,避免新增页面被旧权限集合隐藏。
|
||
foreach ($navigation as &$section) {
|
||
if (($section['slug'] ?? null) !== 'company-management') {
|
||
continue;
|
||
}
|
||
|
||
$hasSubjectReport = collect($section['pages'] ?? [])->contains('slug', 'subject-operating-report');
|
||
|
||
if ($hasSubjectReport) {
|
||
$configuredPages = collect(BusinessNavigation::all())
|
||
->firstWhere('slug', 'company-management')['pages'] ?? [];
|
||
|
||
foreach (['company-cost-arrangement', 'tax-forecast'] as $sharedReportSlug) {
|
||
$alreadyVisible = collect($section['pages'] ?? [])->contains('slug', $sharedReportSlug);
|
||
|
||
if ($alreadyVisible) {
|
||
continue;
|
||
}
|
||
|
||
$sharedReportPage = collect($configuredPages)->firstWhere('slug', $sharedReportSlug);
|
||
|
||
if ($sharedReportPage) {
|
||
$section['pages'][] = $sharedReportPage;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
unset($section);
|
||
|
||
return $navigation;
|
||
}
|
||
|
||
public static function allKeys(): array
|
||
{
|
||
$keys = [];
|
||
|
||
foreach (BusinessNavigation::all() as $section) {
|
||
$keys[] = $section['slug'];
|
||
|
||
foreach ($section['pages'] ?? [] as $page) {
|
||
$keys[] = $section['slug'] . '/' . $page['slug'];
|
||
|
||
foreach ($page['children'] ?? [] as $child) {
|
||
$keys[] = $section['slug'] . '/' . $child['slug'];
|
||
}
|
||
}
|
||
}
|
||
|
||
return $keys;
|
||
}
|
||
|
||
public static function normalizeAllowedKeys(array $keys): array
|
||
{
|
||
$normalized = [];
|
||
|
||
foreach ($keys as $key) {
|
||
$key = (string) $key;
|
||
$normalizedKey = self::LEGACY_PAGE_KEYS[$key] ?? $key;
|
||
$normalized[] = $normalizedKey;
|
||
|
||
foreach (self::FINAL_SECTION_KEYS as $sectionKey => $finalSectionKey) {
|
||
if ($normalizedKey === $sectionKey) {
|
||
$normalized[] = $finalSectionKey;
|
||
} elseif (str_starts_with($normalizedKey, $sectionKey . '/')) {
|
||
// 「终版」目录已是独立目录,按同样的子页面粒度跟着授权。
|
||
$normalized[] = $finalSectionKey . substr($normalizedKey, strlen($sectionKey));
|
||
}
|
||
}
|
||
|
||
if ($key === 'refunds') {
|
||
$normalized[] = self::LEGACY_PAGE_KEYS['refunds/small-payment-work-orders'];
|
||
}
|
||
}
|
||
|
||
return array_values(array_unique($normalized));
|
||
}
|
||
}
|