This commit is contained in:
cjd
2026-02-05 22:22:10 +08:00
parent fef9fe0c31
commit bf3a2e6971
273 changed files with 30605 additions and 0 deletions

View File

@@ -0,0 +1,105 @@
<?php
namespace App\Providers;
use App\Models\Category;
use App\Models\SiteSetting;
use Illuminate\Support\Str;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\View;
use Livewire\Livewire;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
$this->ensureIntlNumberFormatter();
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
$this->registerFilamentLivewireResolver();
Paginator::defaultView('partials.pagination');
View::composer('layouts.app', function ($view): void {
$categories = Category::with([
'children' => function ($query) {
$query->withCount('products')
->orderBy('sort');
},
])
->withCount('products')
->whereNull('parent_id')
->orderBy('sort')
->get();
$view->with([
'sidebarCategories' => $categories,
'siteTitle' => SiteSetting::value('site_title', 'AI 工具导航'),
'siteDescription' => SiteSetting::value('site_description', '精选 AI 工具与产品导航'),
'siteLogo' => SiteSetting::value('site_logo'),
'siteFooter' => SiteSetting::value('site_footer'),
'gaId' => SiteSetting::value('ga_id'),
'icpNumber' => SiteSetting::value('icp_number'),
'socialLinks' => $this->parseSocialLinks(SiteSetting::value('social_links', '')),
]);
});
}
private function ensureIntlNumberFormatter(): void
{
if (class_exists('NumberFormatter')) {
return;
}
$polyfill = app_path('Support/NumberFormatter.php');
if (is_file($polyfill)) {
require_once $polyfill;
}
}
private function registerFilamentLivewireResolver(): void
{
Livewire::resolveMissingComponent(function (string $name): ?string {
if (! Str::startsWith($name, ['filament.', 'app.'])) {
return null;
}
$class = collect(explode('.', $name))
->map(fn (string $segment) => Str::studly($segment))
->join('\\');
return is_subclass_of($class, \Livewire\Component::class) ? $class : null;
});
}
private function parseSocialLinks(?string $raw): array
{
if (!$raw) {
return [];
}
$lines = preg_split('/\r\n|\r|\n/', $raw);
$links = [];
foreach ($lines as $line) {
$line = trim($line);
if ($line === '') {
continue;
}
[$name, $url] = array_pad(explode('|', $line, 2), 2, '');
if ($name && $url) {
$links[] = ['name' => trim($name), 'url' => trim($url)];
}
}
return $links;
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace App\Providers;
// use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* The model to policy mappings for the application.
*
* @var array<class-string, class-string>
*/
protected $policies = [
//
];
/**
* Register any authentication / authorization services.
*/
public function boot(): void
{
//
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Broadcast;
use Illuminate\Support\ServiceProvider;
class BroadcastServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Broadcast::routes();
require base_path('routes/channels.php');
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace App\Providers;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
class EventServiceProvider extends ServiceProvider
{
/**
* The event to listener mappings for the application.
*
* @var array<class-string, array<int, class-string>>
*/
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
];
/**
* Register any events for your application.
*/
public function boot(): void
{
//
}
/**
* Determine if events and listeners should be automatically discovered.
*/
public function shouldDiscoverEvents(): bool
{
return false;
}
}

View File

@@ -0,0 +1,60 @@
<?php
namespace App\Providers\Filament;
use App\Filament\Pages\SiteSettings;
use Filament\Http\Middleware\Authenticate;
use Filament\Http\Middleware\DisableBladeIconComponents;
use Filament\Http\Middleware\DispatchServingFilamentEvent;
use Filament\Pages;
use Filament\Panel;
use Filament\PanelProvider;
use Filament\Support\Colors\Color;
use Filament\Widgets;
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
use Illuminate\Cookie\Middleware\EncryptCookies;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
use Illuminate\Routing\Middleware\SubstituteBindings;
use Illuminate\Session\Middleware\AuthenticateSession;
use Illuminate\Session\Middleware\StartSession;
use Illuminate\View\Middleware\ShareErrorsFromSession;
class AdminPanelProvider extends PanelProvider
{
public function panel(Panel $panel): Panel
{
return $panel
->default()
->id('admin')
->path('admin')
->login()
->colors([
'primary' => Color::Amber,
])
->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources')
->discoverPages(in: app_path('Filament/Pages'), for: 'App\\Filament\\Pages')
->pages([
Pages\Dashboard::class,
SiteSettings::class,
])
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets')
->widgets([
Widgets\AccountWidget::class,
Widgets\FilamentInfoWidget::class,
])
->middleware([
EncryptCookies::class,
AddQueuedCookiesToResponse::class,
StartSession::class,
AuthenticateSession::class,
ShareErrorsFromSession::class,
VerifyCsrfToken::class,
SubstituteBindings::class,
DisableBladeIconComponents::class,
DispatchServingFilamentEvent::class,
])
->authMiddleware([
Authenticate::class,
]);
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace App\Providers;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider
{
/**
* The path to your application's "home" route.
*
* Typically, users are redirected here after authentication.
*
* @var string
*/
public const HOME = '/home';
/**
* Define your route model bindings, pattern filters, and other route configuration.
*/
public function boot(): void
{
RateLimiter::for('api', function (Request $request) {
return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
});
$this->routes(function () {
Route::middleware('api')
->prefix('api')
->group(base_path('routes/api.php'));
Route::middleware('web')
->group(base_path('routes/web.php'));
});
}
}