From a795b2c8961e5972c2a759a3a2f6b5330a6c4c80 Mon Sep 17 00:00:00 2001 From: "jiangdong.cheng" Date: Thu, 12 Feb 2026 17:10:36 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Admin/SiteSettingController.php | 319 +++++++++------ .../Controllers/Admin/UploadController.php | 14 +- resources/views/admin/articles/form.blade.php | 213 +++++++--- .../views/admin/articles/index.blade.php | 30 +- .../views/admin/categories/form.blade.php | 90 ++-- .../views/admin/categories/index.blade.php | 28 +- .../views/admin/feedback/index.blade.php | 43 +- resources/views/admin/guides/form.blade.php | 153 +++++-- resources/views/admin/guides/index.blade.php | 32 +- resources/views/admin/models/form.blade.php | 233 ++++++++--- resources/views/admin/models/index.blade.php | 32 +- .../partials/admin-page-header.blade.php | 65 +++ .../admin/partials/markdown-editor.blade.php | 48 +++ .../admin/partials/modern-form-head.blade.php | 89 ++++ .../partials/modern-form-scripts.blade.php | 222 ++++++++++ .../partials/modern-index-head.blade.php | 57 +++ .../partials/slug-autofill-script.blade.php | 42 ++ .../admin/partials/status-badge.blade.php | 10 + .../views/admin/settings/index.blade.php | 384 +++--------------- .../views/admin/settings/item-form.blade.php | 97 +++++ resources/views/admin/settings/show.blade.php | 232 +++++++++++ resources/views/admin/sources/form.blade.php | 83 +++- resources/views/admin/sources/index.blade.php | 28 +- resources/views/admin/tools/form.blade.php | 287 +++++++------ resources/views/admin/tools/index.blade.php | 26 +- resources/views/layouts/admin.blade.php | 33 +- resources/views/layouts/site.blade.php | 40 ++ resources/views/public/tools/index.blade.php | 103 +++-- routes/web.php | 6 +- 29 files changed, 2155 insertions(+), 884 deletions(-) create mode 100644 resources/views/admin/partials/admin-page-header.blade.php create mode 100644 resources/views/admin/partials/markdown-editor.blade.php create mode 100644 resources/views/admin/partials/modern-form-head.blade.php create mode 100644 resources/views/admin/partials/modern-form-scripts.blade.php create mode 100644 resources/views/admin/partials/modern-index-head.blade.php create mode 100644 resources/views/admin/partials/slug-autofill-script.blade.php create mode 100644 resources/views/admin/partials/status-badge.blade.php create mode 100644 resources/views/admin/settings/item-form.blade.php create mode 100644 resources/views/admin/settings/show.blade.php diff --git a/app/Http/Controllers/Admin/SiteSettingController.php b/app/Http/Controllers/Admin/SiteSettingController.php index e7a2f6f..1025474 100644 --- a/app/Http/Controllers/Admin/SiteSettingController.php +++ b/app/Http/Controllers/Admin/SiteSettingController.php @@ -11,135 +11,79 @@ use Illuminate\Contracts\View\View; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\Cache; +use Illuminate\Support\Facades\Route as RouteFacade; use Illuminate\Validation\Rule; class SiteSettingController extends Controller { public function index(): View { + $this->ensureDefaultModules(); + $modules = HomeModule::query() - ->with(['items' => fn ($query) => $query->orderBy('sort_order')->orderBy('id')]) + ->withCount('items') ->orderBy('sort_order') ->orderBy('id') ->get(); - if ($modules->isEmpty()) { - $this->ensureDefaultModules(); - - $modules = HomeModule::query() - ->with(['items' => fn ($query) => $query->orderBy('sort_order')->orderBy('id')]) - ->orderBy('sort_order') - ->orderBy('id') - ->get(); - } - return view('admin.settings.index', [ 'modules' => $modules, + ]); + } + + public function show(HomeModule $module): View + { + $this->ensureDefaultModules(); + + $module->load([ + 'items' => fn ($query) => $query->orderBy('sort_order')->orderBy('id'), + ]); + + return view('admin.settings.show', [ + 'module' => $module, + 'moduleNav' => $this->moduleNavigation(), 'routeOptions' => $this->routeOptions(), ]); } - public function update(Request $request): RedirectResponse + public function update(Request $request, HomeModule $module): RedirectResponse { - $moduleData = $request->input('modules', []); - if (!is_array($moduleData) || $moduleData === []) { - return redirect() - ->route('admin.settings.index') - ->with('status', '未提交有效的模块配置。'); - } + $validated = $request->validate([ + 'name' => ['required', 'string', 'max:120'], + 'title' => ['nullable', 'string', 'max:160'], + 'subtitle' => ['nullable', 'string', 'max:255'], + 'enabled' => ['nullable', 'boolean'], + 'sort_order' => ['nullable', 'integer', 'min:0', 'max:9999'], + 'limit' => ['nullable', 'integer', 'min:1', 'max:30'], + 'more_link_type' => ['nullable', Rule::in(['route', 'url'])], + 'more_link_target' => ['nullable', 'string', 'max:255'], + 'extra.side_title' => ['nullable', 'string', 'max:120'], + 'extra.side_subtitle' => ['nullable', 'string', 'max:255'], + ]); - foreach ($moduleData as $moduleId => $moduleInput) { - if (!is_numeric($moduleId) || !is_array($moduleInput)) { - continue; - } + $module->fill([ + 'name' => $validated['name'], + 'title' => $validated['title'] ?? null, + 'subtitle' => $validated['subtitle'] ?? null, + 'enabled' => (bool) ($validated['enabled'] ?? false), + 'sort_order' => (int) ($validated['sort_order'] ?? $module->sort_order), + 'limit' => (int) ($validated['limit'] ?? $module->limit), + 'more_link_type' => $validated['more_link_type'] ?? null, + 'more_link_target' => $validated['more_link_target'] ?? null, + 'extra' => [ + 'side_title' => data_get($validated, 'extra.side_title'), + 'side_subtitle' => data_get($validated, 'extra.side_subtitle'), + ], + ]); - $module = HomeModule::query()->find((int) $moduleId); - if (! $module instanceof HomeModule) { - continue; - } - - $validatedModule = validator($moduleInput, [ - 'name' => ['required', 'string', 'max:120'], - 'title' => ['nullable', 'string', 'max:160'], - 'subtitle' => ['nullable', 'string', 'max:255'], - 'enabled' => ['nullable', 'boolean'], - 'sort_order' => ['nullable', 'integer', 'min:0', 'max:9999'], - 'limit' => ['nullable', 'integer', 'min:1', 'max:30'], - 'more_link_type' => ['nullable', Rule::in(['route', 'url'])], - 'more_link_target' => ['nullable', 'string', 'max:255'], - 'extra.side_title' => ['nullable', 'string', 'max:120'], - 'extra.side_subtitle' => ['nullable', 'string', 'max:255'], - ])->validate(); - - $module->fill([ - 'name' => $validatedModule['name'], - 'title' => $validatedModule['title'] ?? null, - 'subtitle' => $validatedModule['subtitle'] ?? null, - 'enabled' => (bool) ($validatedModule['enabled'] ?? false), - 'sort_order' => (int) ($validatedModule['sort_order'] ?? $module->sort_order), - 'limit' => (int) ($validatedModule['limit'] ?? $module->limit), - 'more_link_type' => $validatedModule['more_link_type'] ?? null, - 'more_link_target' => $validatedModule['more_link_target'] ?? null, - 'extra' => [ - 'side_title' => data_get($validatedModule, 'extra.side_title'), - 'side_subtitle' => data_get($validatedModule, 'extra.side_subtitle'), - ], - ]); - - $this->validateModuleLink($module->module_key, $module->more_link_type, $module->more_link_target); - $module->save(); - - $itemsInput = $moduleInput['items'] ?? []; - if (!is_array($itemsInput)) { - continue; - } - - foreach ($itemsInput as $itemId => $itemInput) { - if (!is_numeric($itemId) || !is_array($itemInput)) { - continue; - } - - $item = HomeModuleItem::query() - ->where('home_module_id', $module->id) - ->find((int) $itemId); - - if (! $item instanceof HomeModuleItem) { - continue; - } - - $validatedItem = validator($itemInput, [ - 'title' => ['nullable', 'string', 'max:160'], - 'subtitle' => ['nullable', 'string', 'max:255'], - 'image_path' => ['nullable', 'string', 'max:255'], - 'link_type' => ['nullable', Rule::in(['route', 'url'])], - 'link_target' => ['nullable', 'string', 'max:255'], - 'sort_order' => ['nullable', 'integer', 'min:0', 'max:9999'], - 'enabled' => ['nullable', 'boolean'], - ])->validate(); - - $linkType = $validatedItem['link_type'] ?? 'route'; - $linkTarget = $validatedItem['link_target'] ?? null; - - $this->validateItemRules($module->module_key, $validatedItem); - $this->validateItemLink($linkType, $linkTarget); - - $item->fill([ - 'title' => $validatedItem['title'] ?? null, - 'subtitle' => $validatedItem['subtitle'] ?? null, - 'image_path' => $validatedItem['image_path'] ?? null, - 'link_type' => $linkType, - 'link_target' => $linkTarget, - 'sort_order' => (int) ($validatedItem['sort_order'] ?? $item->sort_order), - 'enabled' => (bool) ($validatedItem['enabled'] ?? false), - ])->save(); - } - } + $this->validateModuleLink($module->module_key, $module->more_link_type, $module->more_link_target); + $module->save(); $this->clearHomeCaches(); return redirect() - ->route('admin.settings.index') - ->with('status', '首页模块配置已更新。'); + ->route('admin.settings.show', $module) + ->with('status', '模块配置已更新。'); } public function storeItem(Request $request, HomeModule $module): RedirectResponse @@ -155,7 +99,7 @@ class SiteSettingController extends Controller ]); $this->validateItemRules($module->module_key, $validated); - $this->validateItemLink($validated['link_type'], $validated['link_target'] ?? null); + $this->validateItemLink($module->module_key, $validated['link_type'], $validated['link_target'] ?? null); $module->items()->create([ 'title' => $validated['title'] ?? null, @@ -170,10 +114,60 @@ class SiteSettingController extends Controller $this->clearHomeCaches(); return redirect() - ->route('admin.settings.index') + ->route('admin.settings.show', $module) ->with('status', '模块条目已新增。'); } + public function editItem(HomeModule $module, HomeModuleItem $item): View + { + if ($item->home_module_id !== $module->id) { + abort(404); + } + + return view('admin.settings.item-form', [ + 'module' => $module, + 'item' => $item, + 'moduleNav' => $this->moduleNavigation(), + 'routeOptions' => $this->routeOptions(), + ]); + } + + public function updateItem(Request $request, HomeModule $module, HomeModuleItem $item): RedirectResponse + { + if ($item->home_module_id !== $module->id) { + abort(404); + } + + $validated = $request->validate([ + 'title' => ['nullable', 'string', 'max:160'], + 'subtitle' => ['nullable', 'string', 'max:255'], + 'image_path' => ['nullable', 'string', 'max:255'], + 'link_type' => ['required', Rule::in(['route', 'url'])], + 'link_target' => ['nullable', 'string', 'max:255'], + 'sort_order' => ['nullable', 'integer', 'min:0', 'max:9999'], + 'enabled' => ['nullable', 'boolean'], + ]); + + $this->validateItemRules($module->module_key, $validated); + $this->validateItemLink($module->module_key, $validated['link_type'], $validated['link_target'] ?? null); + + $item->fill([ + 'title' => $validated['title'] ?? null, + 'subtitle' => $validated['subtitle'] ?? null, + 'image_path' => $validated['image_path'] ?? null, + 'link_type' => $validated['link_type'], + 'link_target' => $validated['link_target'] ?? null, + 'sort_order' => (int) ($validated['sort_order'] ?? $item->sort_order), + 'enabled' => (bool) ($validated['enabled'] ?? false), + ])->save(); + + $this->clearHomeCaches(); + + return redirect() + ->route('admin.settings.show', $module) + ->with('status', '模块条目已更新。'); + } + public function destroyItem(HomeModule $module, HomeModuleItem $item): RedirectResponse { if ($item->home_module_id !== $module->id) { @@ -184,7 +178,7 @@ class SiteSettingController extends Controller $this->clearHomeCaches(); return redirect() - ->route('admin.settings.index') + ->route('admin.settings.show', $module) ->with('status', '模块条目已删除。'); } @@ -193,13 +187,72 @@ class SiteSettingController extends Controller */ private function routeOptions(): array { - return [ - ['name' => '工具集首页', 'value' => 'tools.index'], - ['name' => '工具列表页', 'value' => 'tools.list'], - ['name' => '模型推荐', 'value' => 'models.index'], - ['name' => '文章资讯', 'value' => 'news.index'], - ['name' => '教程学习', 'value' => 'guides.index'], + $allRouteNames = collect(RouteFacade::getRoutes()->getRoutesByName()) + ->filter(function ($route, $name): bool { + if (!is_string($name) || $name === '') { + return false; + } + + if (! method_exists($route, 'parameterNames')) { + return false; + } + + return count($route->parameterNames()) === 0; + }) + ->keys() + ->map(fn ($name) => (string) $name) + ->filter(fn (string $name) => ! str_starts_with($name, 'admin.')) + ->filter(fn (string $name) => ! str_starts_with($name, 'debugbar.')) + ->filter(fn (string $name) => ! str_starts_with($name, 'ignition.')) + ->filter(fn (string $name) => ! str_starts_with($name, '_')) + ->values(); + + $priority = [ + 'home', + 'tools.index', + 'tools.list', + 'models.index', + 'news.index', + 'guides.index', ]; + + $priorityRoutes = collect($priority) + ->filter(fn (string $name) => $allRouteNames->contains($name)); + + $remainingRoutes = $allRouteNames + ->reject(fn (string $name) => in_array($name, $priority, true)) + ->sort() + ->values(); + + return $priorityRoutes + ->concat($remainingRoutes) + ->map(fn (string $name) => [ + 'name' => $this->routeLabel($name), + 'value' => $name, + ]) + ->values() + ->all(); + } + + private function routeLabel(string $name): string + { + return match ($name) { + 'home' => '首页', + 'tools.index' => '工具首页', + 'tools.list' => '工具列表', + 'models.index' => '模型推荐', + 'news.index' => '文章资讯', + 'guides.index' => '教程学习', + default => $name, + }; + } + + private function moduleNavigation() + { + return HomeModule::query() + ->orderBy('sort_order') + ->orderBy('id') + ->get(['id', 'name', 'module_key']); } private function ensureDefaultModules(): void @@ -231,11 +284,17 @@ class SiteSettingController extends Controller return; } - if ($type === null && $target === null) { + $target = trim((string) $target); + + if ($type === null && $target === '') { return; } if ($type === 'route') { + if ($target === '') { + abort(422, '请选择有效的“更多链接”路由。'); + } + if (! in_array($target, array_column($this->routeOptions(), 'value'), true)) { abort(422, '模块“更多链接”路由不在允许范围内。'); } @@ -243,7 +302,7 @@ class SiteSettingController extends Controller return; } - if ($type === 'url' && $target !== null && ! $this->isValidUrlOrPath($target)) { + if ($type === 'url' && $target !== '' && ! $this->isValidUrlOrPath($target)) { abort(422, '模块“更多链接”URL格式不正确。'); } } @@ -263,17 +322,36 @@ class SiteSettingController extends Controller } } - private function validateItemLink(string $type, ?string $target): void + private function validateItemLink(string $moduleKey, string $type, ?string $target): void { + $target = trim((string) $target); + $isStrictModule = in_array($moduleKey, ['channel_cards', 'promo_banners'], true); + if ($type === 'route') { - if (! in_array((string) $target, array_column($this->routeOptions(), 'value'), true)) { - abort(422, '条目路由不在允许范围内。'); + if ($target === '') { + if ($isStrictModule) { + abort(422, '频道卡片/横幅推荐条目必须填写链接目标。'); + } + + return; + } + + if (! in_array($target, array_column($this->routeOptions(), 'value'), true)) { + abort(422, '请选择有效的前台路由,或将链接类型改为 URL。'); } return; } - if ($target === null || ! $this->isValidUrlOrPath($target)) { + if ($target === '') { + if ($isStrictModule) { + abort(422, '频道卡片/横幅推荐条目必须填写链接目标。'); + } + + return; + } + + if (! $this->isValidUrlOrPath($target)) { abort(422, '条目URL格式不正确。'); } } @@ -292,4 +370,3 @@ class SiteSettingController extends Controller Cache::flush(); } } - diff --git a/app/Http/Controllers/Admin/UploadController.php b/app/Http/Controllers/Admin/UploadController.php index 6beeaed..81ddfa4 100644 --- a/app/Http/Controllers/Admin/UploadController.php +++ b/app/Http/Controllers/Admin/UploadController.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; +use App\Support\MarkdownRenderer; use GdImage; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; @@ -26,6 +27,18 @@ class UploadController extends Controller private const THUMB_WEBP_QUALITY = 80; + public function markdownPreview(Request $request, MarkdownRenderer $markdownRenderer): JsonResponse + { + $validated = $request->validate([ + 'markdown' => ['nullable', 'string'], + ]); + + return response()->json([ + 'success' => true, + 'html' => $markdownRenderer->render((string) ($validated['markdown'] ?? '')), + ]); + } + public function markdownImage(Request $request): JsonResponse { $validated = $request->validate([ @@ -177,4 +190,3 @@ class UploadController extends Controller return $binary; } } - diff --git a/resources/views/admin/articles/form.blade.php b/resources/views/admin/articles/form.blade.php index 9b7e866..a78b450 100644 --- a/resources/views/admin/articles/form.blade.php +++ b/resources/views/admin/articles/form.blade.php @@ -2,89 +2,176 @@ @section('title', $item->exists ? '编辑资讯' : '新建资讯') +@section('head') + @include('admin.partials.modern-form-head') +@endsection + @section('content') -
+

{{ $item->exists ? '编辑资讯' : '新建资讯' }}

@if($item->exists)
-
@csrf
-
@csrf
+
+ @csrf + +
+
+ @csrf + +
@endif
+

* 为必填项

+
@csrf @if($method !== 'POST') @method($method) @endif -
-
- -
- - -
-
- - -
-
-
- -
- - -
-
- - -
-
-
-
- -
-
- -
- 支持图片:`![alt](https://...)` 或 `![alt](/images/xxx.png)` - +
+

基础信息

+

先完成标题、摘要、来源和状态,确保资讯可正确归档。

+ +
+
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+
+ +
-
- +
-
-
-
-
-
+
+
+

内容编辑

+

正文为必填,系统会按统一规则渲染 Markdown 并用于前台展示。

-
+ @include('admin.partials.markdown-editor', [ + 'field' => 'body', + 'value' => $item->body, + 'label' => '正文内容(Markdown)', + 'required' => true, + 'rows' => 18, + 'minlength' => 100, + 'previewId' => 'article-body-preview', + 'hint' => '后端要求正文不少于 100 字符,请优先完善结构化内容。', + ]) +
+
+ +
+
+ 高级设置(SEO 与补充字段) + +
+
+ + +
+ +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ +
+
+ 正文建议包含结论段,便于前台摘要抓取。 + +
+
@endsection + +@section('scripts') + @include('admin.partials.modern-form-scripts') +@endsection + diff --git a/resources/views/admin/articles/index.blade.php b/resources/views/admin/articles/index.blade.php index 7a37ec0..169311d 100644 --- a/resources/views/admin/articles/index.blade.php +++ b/resources/views/admin/articles/index.blade.php @@ -2,20 +2,27 @@ @section('title', 'AI 资讯管理') +@section('head') + @include('admin.partials.modern-index-head') +@endsection + @section('content') -
-
+
+
新建资讯
+
-
+
- +
@@ -29,16 +36,20 @@ @forelse($items as $item) - + - + @empty - + + + @endforelse
标题
-
{{ $item->title }}
-
{{ $item->excerpt }}
+
{{ $item->title }}
+
{{ $item->excerpt }}
{{ $item->status?->value ?? '-' }}@include('admin.partials.status-badge', ['status' => $item->status]) {{ $item->source_level?->value ?? '-' }} {{ $item->published_at?->format('Y-m-d H:i') ?: '-' }}编辑 + 编辑 +
暂无资讯数据
暂无资讯数据,先新增一条内容吧。
@@ -46,3 +57,4 @@
@endsection + diff --git a/resources/views/admin/categories/form.blade.php b/resources/views/admin/categories/form.blade.php index 33172ad..2610b75 100644 --- a/resources/views/admin/categories/form.blade.php +++ b/resources/views/admin/categories/form.blade.php @@ -2,57 +2,79 @@ @section('title', $item->exists ? '编辑分类' : '新建分类') +@section('head') + @include('admin.partials.modern-form-head') +@endsection + @section('content') -
+

{{ $item->exists ? '编辑分类' : '新建分类' }}

返回列表
+
+

* 为必填项

+
@csrf @if($method !== 'POST') @method($method) @endif -
- - - - @foreach($typeOptions as $type) - - @endforeach - - - - - -
+
+
+

基础信息

+

分类会影响前台聚合页面展示,请优先保证类型与 slug 规范。

-
- - -
+
+
+ + + + @foreach($typeOptions as $type) + + @endforeach + +
必须与系统允许类型一致。
+
-
- - +
+ + +
+ +
+ + +
默认由名称生成,可手动调整。
+
+ +
+ + +
+ +
+ +
+
+
- - -
- -
- -
- -
- +
+ 建议保持 slug 简短并避免重复。 + +
@endsection + +@section('scripts') + @include('admin.partials.slug-autofill-script') +@endsection + diff --git a/resources/views/admin/categories/index.blade.php b/resources/views/admin/categories/index.blade.php index f51c379..dd30947 100644 --- a/resources/views/admin/categories/index.blade.php +++ b/resources/views/admin/categories/index.blade.php @@ -2,9 +2,13 @@ @section('title', '分类管理') +@section('head') + @include('admin.partials.modern-index-head') +@endsection + @section('content') -
-
+
+
+
-
- -
- - -
-
-
- - -
- -
- -
-
- -
- 支持图片:`![alt](https://...)` - +
+

基础信息

+

先设定教程标题、难度与摘要,便于读者判断是否适合。

+ +
+
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+ +
+ + +
建议概括适用人群、完成收益和学习前提。
+
-
- +
-
-
-
-
+
+
+

内容编辑

+

正文支持 Markdown 实时预览,适合分章节组织教程。

-
+ @include('admin.partials.markdown-editor', [ + 'field' => 'body', + 'value' => $item->body, + 'label' => '正文内容(Markdown)', + 'required' => true, + 'rows' => 18, + 'minlength' => 100, + 'previewId' => 'guide-body-preview', + 'hint' => '后端要求正文不少于 100 字符,建议用二级标题组织步骤。', + ]) +
+
+ +
+
+ 高级设置(SEO 字段) + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ +
+
+ 建议保存前先检查预览中的标题层级与代码块格式。 + +
+
@endsection + +@section('scripts') + @include('admin.partials.modern-form-scripts') +@endsection + diff --git a/resources/views/admin/guides/index.blade.php b/resources/views/admin/guides/index.blade.php index e443338..0bedc9f 100644 --- a/resources/views/admin/guides/index.blade.php +++ b/resources/views/admin/guides/index.blade.php @@ -2,20 +2,27 @@ @section('title', 'AI 教程管理') +@section('head') + @include('admin.partials.modern-index-head') +@endsection + @section('content') -
-
+
+
新建教程
+
-
+
- +
@@ -29,16 +36,20 @@ @forelse($items as $item) - - + + - + @empty - + + + @endforelse
标题
-
{{ $item->title }}
-
{{ $item->excerpt }}
+
{{ $item->title }}
+
{{ $item->excerpt }}
{{ $item->difficulty }}{{ $item->status?->value ?? '-' }}{{ $item->difficulty ?: '-' }}@include('admin.partials.status-badge', ['status' => $item->status]) {{ $item->updated_at?->format('Y-m-d H:i') }}编辑 + 编辑 +
暂无教程数据
暂无教程数据,先新增一条内容吧。
@@ -46,3 +57,4 @@
@endsection + diff --git a/resources/views/admin/models/form.blade.php b/resources/views/admin/models/form.blade.php index f053045..adf6693 100644 --- a/resources/views/admin/models/form.blade.php +++ b/resources/views/admin/models/form.blade.php @@ -2,82 +2,207 @@ @section('title', $item->exists ? '编辑模型' : '新建模型') +@section('head') + @include('admin.partials.modern-form-head') +@endsection + @section('content') -
+

{{ $item->exists ? '编辑模型' : '新建模型' }}

@if($item->exists)
-
@csrf
-
@csrf
+
+ @csrf + +
+
+ @csrf + +
@endif
+
+

* 为必填项

+
@csrf @if($method !== 'POST') @method($method) @endif -
-
-
-
-
+
+
+

基础信息

+

维护模型的核心参数与展示信息,用于榜单、详情和筛选。

-
-
-
-
- +
+
+ + +
+
+ + +
默认自动生成,可按品牌规范调整。
+
+ +
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + +
+
+ +
+
+
-
- -
-
- -
-
- +
+
+

内容编辑

+

可补充模型能力、限制与使用建议,支持 Markdown 实时预览。

+ + @include('admin.partials.markdown-editor', [ + 'field' => 'description', + 'value' => $item->description, + 'label' => '模型详情(Markdown)', + 'required' => false, + 'rows' => 16, + 'previewId' => 'model-description-preview', + 'hint' => '建议包含适用场景、输入输出限制、定价说明。', + ]) +
-
-
-
+
+
+ 高级设置(SEO 与补充字段) -
-
-
+
+
+ + +
-
-
-
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
-
-
-
-
- -
+
+
+ 评分字段会参与排序,修改后请核对展示结果。 + +
+
@endsection + +@section('scripts') + @include('admin.partials.modern-form-scripts') +@endsection + diff --git a/resources/views/admin/models/index.blade.php b/resources/views/admin/models/index.blade.php index 0710798..8be3f5d 100644 --- a/resources/views/admin/models/index.blade.php +++ b/resources/views/admin/models/index.blade.php @@ -2,20 +2,27 @@ @section('title', 'AI 模型管理') +@section('head') + @include('admin.partials.modern-index-head') +@endsection + @section('content') -
-
+
+
新建模型
+
-
+
- +
@@ -30,17 +37,21 @@ @forelse($items as $item) - + - + - + @empty - + + + @endforelse
名称
-
{{ $item->name }}
-
{{ $item->summary }}
+
{{ $item->name }}
+
{{ $item->summary }}
{{ $item->modality }}{{ $item->modality ?: '-' }} {{ $item->total_score }}{{ $item->status?->value ?? '-' }}@include('admin.partials.status-badge', ['status' => $item->status]) {{ $item->updated_at?->format('Y-m-d H:i') }}编辑 + 编辑 +
暂无模型数据
暂无模型数据,先新增一条内容吧。
@@ -48,3 +59,4 @@
@endsection + diff --git a/resources/views/admin/partials/admin-page-header.blade.php b/resources/views/admin/partials/admin-page-header.blade.php new file mode 100644 index 0000000..0e50d20 --- /dev/null +++ b/resources/views/admin/partials/admin-page-header.blade.php @@ -0,0 +1,65 @@ +@php + $routeName = (string) (request()->route()?->getName() ?? ''); + $parts = explode('.', $routeName); + $moduleKey = $parts[1] ?? 'dashboard'; + $actionKey = $parts[2] ?? 'index'; + + $moduleMeta = [ + 'dashboard' => ['label' => '控制台', 'index' => 'admin.dashboard', 'subtitle' => '查看系统概览与关键运营数据。'], + 'tools' => ['label' => 'AI 工具', 'index' => 'admin.tools.index', 'subtitle' => '维护工具信息、状态与展示内容。'], + 'models' => ['label' => 'AI 模型', 'index' => 'admin.models.index', 'subtitle' => '管理模型参数、评分与发布状态。'], + 'articles' => ['label' => 'AI 资讯', 'index' => 'admin.articles.index', 'subtitle' => '维护资讯内容、来源与发布质量。'], + 'guides' => ['label' => 'AI 教程', 'index' => 'admin.guides.index', 'subtitle' => '维护教程内容与学习难度分层。'], + 'categories' => ['label' => '分类管理', 'index' => 'admin.categories.index', 'subtitle' => '统一管理分类体系与启用状态。'], + 'sources' => ['label' => '来源管理', 'index' => 'admin.sources.index', 'subtitle' => '维护可信来源白名单与抓取策略。'], + 'settings' => ['label' => '首页配置', 'index' => 'admin.settings.index', 'subtitle' => '配置首页模块、条目与展示顺序。'], + 'feedback' => ['label' => '反馈管理', 'index' => 'admin.feedback.index', 'subtitle' => '跟进用户反馈并及时更新处理状态。'], + ][$moduleKey] ?? ['label' => '管理后台', 'index' => 'admin.dashboard', 'subtitle' => '维护站点内容与配置。']; + + $actionLabel = [ + 'index' => '列表', + 'create' => '新建', + 'edit' => '编辑', + ][$actionKey] ?? '详情'; + + $defaultTitle = $moduleMeta['label']; + $pageTitle = trim((string) $__env->yieldContent('title')); + $pageTitle = $pageTitle !== '' ? $pageTitle : $defaultTitle; + + $pageSubtitle = trim((string) $__env->yieldContent('page_subtitle')); + if ($pageSubtitle === '') { + $pageSubtitle = $actionKey === 'index' + ? $moduleMeta['subtitle'] + : '当前为'.$actionLabel.'页面,请按提示完成必填信息并保存。'; + } +@endphp + +
+ + +
+
+

{{ $pageTitle }}

+
{{ $pageSubtitle }}
+
+ @if(trim((string) $__env->yieldContent('page_actions')) !== '') +
+ @yield('page_actions') +
+ @endif +
+
+ diff --git a/resources/views/admin/partials/markdown-editor.blade.php b/resources/views/admin/partials/markdown-editor.blade.php new file mode 100644 index 0000000..0d2bb32 --- /dev/null +++ b/resources/views/admin/partials/markdown-editor.blade.php @@ -0,0 +1,48 @@ +@php + $inputName = $field ?? 'body'; + $previewElementId = $previewId ?? 'preview-'.str_replace(['[', ']', '.'], '-', $inputName); + $inputValue = old($inputName, $value ?? ''); + $isRequired = (bool) ($required ?? false); + $editorRows = (int) ($rows ?? 14); +@endphp + +
+
+
+ + {{ $label ?? '正文内容' }} + @if($isRequired) + * + @endif + + +
+
+ + + @if(!empty($hint)) +
{{ $hint }}
+ @endif +
+
+ +
+
+ 实时预览 + 自动渲染 +
+
+
在左侧输入 Markdown 内容,这里会实时显示预览。
+
+
+
diff --git a/resources/views/admin/partials/modern-form-head.blade.php b/resources/views/admin/partials/modern-form-head.blade.php new file mode 100644 index 0000000..038f49d --- /dev/null +++ b/resources/views/admin/partials/modern-form-head.blade.php @@ -0,0 +1,89 @@ + + + diff --git a/resources/views/admin/partials/modern-form-scripts.blade.php b/resources/views/admin/partials/modern-form-scripts.blade.php new file mode 100644 index 0000000..1cddf77 --- /dev/null +++ b/resources/views/admin/partials/modern-form-scripts.blade.php @@ -0,0 +1,222 @@ + + diff --git a/resources/views/admin/partials/modern-index-head.blade.php b/resources/views/admin/partials/modern-index-head.blade.php new file mode 100644 index 0000000..70ce883 --- /dev/null +++ b/resources/views/admin/partials/modern-index-head.blade.php @@ -0,0 +1,57 @@ + + diff --git a/resources/views/admin/partials/slug-autofill-script.blade.php b/resources/views/admin/partials/slug-autofill-script.blade.php new file mode 100644 index 0000000..712d6d7 --- /dev/null +++ b/resources/views/admin/partials/slug-autofill-script.blade.php @@ -0,0 +1,42 @@ + + diff --git a/resources/views/admin/partials/status-badge.blade.php b/resources/views/admin/partials/status-badge.blade.php new file mode 100644 index 0000000..5e93698 --- /dev/null +++ b/resources/views/admin/partials/status-badge.blade.php @@ -0,0 +1,10 @@ +@php + $statusValue = strtolower((string) ($status?->value ?? $status ?? 'default')); + $statusClass = match ($statusValue) { + 'draft', 'review', 'published', 'stale', 'archived' => $statusValue, + default => 'default', + }; +@endphp + +{{ $statusValue !== '' ? $statusValue : '-' }} + diff --git a/resources/views/admin/settings/index.blade.php b/resources/views/admin/settings/index.blade.php index 85133ac..5dd9509 100644 --- a/resources/views/admin/settings/index.blade.php +++ b/resources/views/admin/settings/index.blade.php @@ -1,346 +1,66 @@ @extends('layouts.admin') -@section('title', '首页模块配置') +@section('title', '首页配置') @section('head') - + @include('admin.partials.modern-index-head') @endsection +@section('page_subtitle', '二级菜单化管理首页模块:先选模块,再进入列表、新增与修改。') + @section('content') -
-
-

首页模块配置(AI工具集)

-
-
-

支持配置模块标题、副标题、图片、链接、排序与展示数量。保存后首页立即生效。

- -
- @csrf - @method('put') - -
- @foreach($modules as $module) -
-
-
- -
-

{{ $module->name }}

-
key: {{ $module->module_key }}
-
-
- -
- -
-
- - id}.name", $module->name) }}" required> -
-
- - id}.title", $module->title) }}"> -
-
- - id}.subtitle", $module->subtitle) }}"> -
-
- - id}.sort_order", $module->sort_order) }}"> -
- -
- - id}.limit", $module->limit) }}"> -
-
- - @php($moduleLinkType = old("modules.{$module->id}.more_link_type", $module->more_link_type)) - -
-
- - id}.more_link_target", $module->more_link_target) }}" placeholder="route 名称或 URL / 站内路径"> -
-
- - id}.extra.side_title", data_get($module->extra, 'side_title')) }}"> -
-
- - id}.extra.side_subtitle", data_get($module->extra, 'side_subtitle')) }}"> -
-
- - @if(in_array($module->module_key, ['channel_cards', 'promo_banners'], true)) -
-
-
模块条目
- 条目要求:标题、图片、链接必填 -
- -
- @foreach($module->items as $item) -
-
- item: {{ $item->id }} - -
-
-
- - id}.items.{$item->id}.sort_order", $item->sort_order) }}"> -
-
- -
-
- - id}.items.{$item->id}.title", $item->title) }}"> -
-
- - id}.items.{$item->id}.subtitle", $item->subtitle) }}"> -
- -
- -
- id}.items.{$item->id}.image_path", $item->image_path) }}" id="module-item-image-{{ $item->id }}" placeholder="/storage/markdown-images/..."> - -
-
-
- - @php($itemLinkType = old("modules.{$module->id}.items.{$item->id}.link_type", $item->link_type)) - -
-
- - id}.items.{$item->id}.link_target", $item->link_target) }}" placeholder="如 tools.list 或 https://..."> -
- -
- @if(!empty($item->image_path)) - {{ $item->title ?: '预览图' }} - @else -
暂无图片
- @endif -
-
- -
-
-
- @endforeach -
- @endif -
- @endforeach -
- -
- -
-
+
+
+
+

首页配置模块

+
请选择一个模块进入二级配置页。
+
+
共 {{ number_format($modules->count()) }} 个模块
-@foreach($modules as $module) - @if(in_array($module->module_key, ['channel_cards', 'promo_banners'], true)) -
-
-

新增条目 - {{ $module->name }}

-
-
-
- @csrf -
- - -
-
- - -
-
- -
- - -
-
-
- - -
- -
- - -
-
- - -
-
- -
- -
-
可选内部路由: - @foreach($routeOptions as $option) - {{ $option['value'] }} - @endforeach -
- -
-
-
-
- @endif -@endforeach - -
-
-

内部路由参考

-
-
-
- @foreach($routeOptions as $option) -
-
- {{ $option['name'] }} - {{ $option['value'] }} -
-
- @endforeach -
+
+
+ + + + + + + + + + + + + @forelse($modules as $module) + + + + + + + + + @empty + + + + @endforelse + +
模块键名状态条目数排序操作
+
{{ $module->name }}
+
{{ $module->title ?: '未设置模块标题' }}
+
{{ $module->module_key }} + @if($module->enabled) + 启用 + @else + 停用 + @endif + {{ number_format((int) $module->items_count) }}{{ (int) $module->sort_order }} + 进入配置 +
暂无模块数据。
@endsection -@section('scripts') - - -@endsection diff --git a/resources/views/admin/settings/item-form.blade.php b/resources/views/admin/settings/item-form.blade.php new file mode 100644 index 0000000..3028404 --- /dev/null +++ b/resources/views/admin/settings/item-form.blade.php @@ -0,0 +1,97 @@ +@extends('layouts.admin') + +@section('title', '编辑条目 - '.$module->name) + +@section('head') + @include('admin.partials.modern-form-head') +@endsection + +@section('page_subtitle', '独立编辑模块条目,保存后返回模块列表。') + +@section('page_actions') + 返回模块配置 +@endsection + +@section('content') +
+
+ @foreach($moduleNav as $navItem) + + {{ $navItem->name }} + + @endforeach +
+
+ +
+
+

编辑条目

+
+
+
+ @csrf + @method('put') + +
+ + +
+
+ + +
+
+ + +
+
+ +
+ +
+ +
+ + +
+
+
+ + +
+
+ + +
+ + @if(!empty($item->image_path)) +
+ item image +
+ @endif + +
+
+ 若为频道卡片/横幅,标题、图片、链接需同时填写。 + +
+
+
+
+
+ + + @foreach($routeOptions as $option) + + @endforeach + +@endsection diff --git a/resources/views/admin/settings/show.blade.php b/resources/views/admin/settings/show.blade.php new file mode 100644 index 0000000..e7bdc99 --- /dev/null +++ b/resources/views/admin/settings/show.blade.php @@ -0,0 +1,232 @@ +@extends('layouts.admin') + +@section('title', '首页配置 - '.$module->name) + +@section('head') + @include('admin.partials.modern-form-head') + @include('admin.partials.modern-index-head') +@endsection + +@section('page_subtitle', '模块配置与条目列表已拆分,支持新增与单条编辑。') + +@section('page_actions') + 返回模块列表 +@endsection + +@section('content') +
+
+ @foreach($moduleNav as $navItem) + + {{ $navItem->name }} + + @endforeach +
+
+ +
+
+

模块信息

+
+
+

* 为必填项

+ +
+ @csrf + @method('put') + +
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+
+ + +
+
+ +
+ +
+ + @php($moduleLinkType = old('more_link_type', $module->more_link_type)) + +
+
+ + +
+ + @php($moduleExtra = old('extra', $module->extra ?? [])) +
+ + +
+
+ + +
+ +
+
+ 建议先保存模块信息,再新增条目。 + +
+
+
+
+
+ +
+
+

新增条目

+
+
+
+ @csrf + +
+ + +
+
+ + +
+
+ + +
+
+ +
+ +
+ +
+ + +
+
+
+ + +
+
+ + +
+ +
+
可选内部路由: + @foreach($routeOptions as $option) + {{ $option['value'] }} + @endforeach +
+ +
+
+
+
+ +
+
+

条目列表

+ 共 {{ number_format($module->items->count()) }} 条 +
+
+ + + + + + + + + + + + + @forelse($module->items as $item) + + + + + + + + + @empty + + + + @endforelse + +
标题链接图片状态排序操作
+
{{ $item->title ?: '-' }}
+
{{ $item->subtitle ?: '-' }}
+
+
{{ $item->link_type }}
+
{{ $item->link_target ?: '-' }}
+
+ @if(!empty($item->image_path)) + item image + @else + + @endif + + @if($item->enabled) + 启用 + @else + 停用 + @endif + {{ (int) $item->sort_order }} + 修改 +
+ @csrf + @method('delete') + +
+
当前模块暂无条目,请先新增。
+
+
+ + + @foreach($routeOptions as $option) + + @endforeach + +@endsection diff --git a/resources/views/admin/sources/form.blade.php b/resources/views/admin/sources/form.blade.php index 02f3688..0ec4e34 100644 --- a/resources/views/admin/sources/form.blade.php +++ b/resources/views/admin/sources/form.blade.php @@ -2,35 +2,80 @@ @section('title', $item->exists ? '编辑来源' : '新建来源') +@section('head') + @include('admin.partials.modern-form-head') +@endsection + @section('content') -
-

{{ $item->exists ? '编辑来源' : '新建来源' }}

+
+
+

{{ $item->exists ? '编辑来源' : '新建来源' }}

+ 返回列表 +
+
+

* 为必填项

+
@csrf @if($method !== 'POST') @method($method) @endif -
-
-
-
- - +
+
+

基础信息

+

来源会参与资讯/工具可信度判定,请优先填写真实域名与信任等级。

+ +
+
+ + +
+
+ + +
仅填域名,不需要协议头。
+
+ +
+ + +
+
+ + +
+ +
+ + +
+ +
+ + +
+
+
-
- - +
+
+ 建议优先维护白名单来源,提升前台内容质量。 + +
- -
- -
@endsection + diff --git a/resources/views/admin/sources/index.blade.php b/resources/views/admin/sources/index.blade.php index 8b81b6c..a202b5d 100644 --- a/resources/views/admin/sources/index.blade.php +++ b/resources/views/admin/sources/index.blade.php @@ -2,20 +2,27 @@ @section('title', '来源白名单管理') +@section('head') + @include('admin.partials.modern-index-head') +@endsection + @section('content') -
-
+
+
新建来源
+
-
+
- +
@@ -29,8 +36,8 @@ @forelse($items as $item) - - + + - + @empty - + + + @endforelse
名称
{{ $item->name }}{{ $item->domain }}{{ $item->name }}{{ $item->domain }} {{ $item->type }} {{ $item->trust_level?->value ?? '-' }} @@ -40,10 +47,14 @@ @endif 编辑 + 编辑 +
暂无来源数据
暂无来源数据,先新增一条内容吧。
@@ -51,3 +62,4 @@
@endsection + diff --git a/resources/views/admin/tools/form.blade.php b/resources/views/admin/tools/form.blade.php index 091ae8d..f3de348 100644 --- a/resources/views/admin/tools/form.blade.php +++ b/resources/views/admin/tools/form.blade.php @@ -2,139 +2,196 @@ @section('title', $item->exists ? '编辑工具' : '新建工具') +@section('head') + @include('admin.partials.modern-form-head') +@endsection + @section('content') -
+

{{ $item->exists ? '编辑工具' : '新建工具' }}

@if($item->exists)
-
@csrf
-
@csrf
+
+ @csrf + +
+
+ @csrf + +
@endif
+
+

* 为必填项

+
@csrf @if($method !== 'POST') @method($method) @endif -
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
+
+
+

基础信息

+

填写工具的核心资料,便于检索、筛选和展示。

-
- - -
-
-
- -
- 支持图片:`![alt](https://...)` - +
+
+ + +
建议使用产品全名,避免缩写歧义。
+
+
+ + +
默认自动生成,可手动调整为英文短链。
+
+ +
+ + +
+
+ + +
+
+ + +
示例:`free`、`freemium`、`paid`。
+
+
+ + +
+ +
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + +
用于列表卡片,建议 50-120 字。
+
+
+ + +
+
+
+ +
+
+

内容编辑

+

左侧编辑 Markdown,右侧实时预览,支持一键上传图片。

+ + @include('admin.partials.markdown-editor', [ + 'field' => 'description', + 'value' => $item->description, + 'label' => '详细描述(Markdown)', + 'required' => false, + 'rows' => 16, + 'previewId' => 'tool-description-preview', + 'hint' => '可包含功能亮点、使用场景和注意事项。', + ]) +
+
+ +
+
+ 高级设置(SEO 与补充字段) + +
+
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ +
+
+ 建议先检查右侧预览,再保存。 +
- -
-
- - -
- -
- - -
-
- - -
-
- - -
-
- - -
- -
-
@endsection + +@section('scripts') + @include('admin.partials.modern-form-scripts') +@endsection + diff --git a/resources/views/admin/tools/index.blade.php b/resources/views/admin/tools/index.blade.php index 59dd7e9..53a0d02 100644 --- a/resources/views/admin/tools/index.blade.php +++ b/resources/views/admin/tools/index.blade.php @@ -2,20 +2,27 @@ @section('title', 'AI 工具管理') +@section('head') + @include('admin.partials.modern-index-head') +@endsection + @section('content') -
-
+
+
新建工具
+
-
+
- +
@@ -30,11 +37,11 @@ @forelse($items as $item) - + @empty - + + + @endforelse
名称
-
{{ $item->name }}
-
{{ $item->summary }}
+
{{ $item->name }}
+
{{ $item->summary }}
{{ $item->category?->name ?? '-' }}{{ $item->status?->value ?? '-' }}@include('admin.partials.status-badge', ['status' => $item->status]) {{ $item->source_level?->value ?? '-' }} {{ $item->updated_at?->format('Y-m-d H:i') }} @@ -42,7 +49,9 @@
暂无工具数据
暂无工具数据,先新增一条内容吧。
@@ -50,3 +59,4 @@
@endsection + diff --git a/resources/views/layouts/admin.blade.php b/resources/views/layouts/admin.blade.php index 50d9eb3..c96d24c 100644 --- a/resources/views/layouts/admin.blade.php +++ b/resources/views/layouts/admin.blade.php @@ -52,6 +52,36 @@ border-color: #3b82f6; background: #eff6ff; } + .navbar-vertical .nav-link.active { + background: rgba(59, 130, 246, .2); + color: #fff; + border-radius: .6rem; + } + .admin-page-head { + padding: .15rem 0 .95rem; + margin-bottom: .45rem; + border-bottom: 1px solid #e5eaf4; + } + .admin-page-subtitle { + color: #64748b; + font-size: .88rem; + line-height: 1.55; + } + .admin-page-actions .btn { + border-radius: .6rem; + } + .admin-breadcrumb .breadcrumb { + --tblr-breadcrumb-divider-color: #94a3b8; + --tblr-breadcrumb-item-active-color: #475569; + font-size: .8rem; + } + .admin-breadcrumb .breadcrumb-item a { + color: #64748b; + text-decoration: none; + } + .admin-breadcrumb .breadcrumb-item a:hover { + color: #2563eb; + } @yield('head') @@ -79,6 +109,7 @@ + @@ -102,7 +133,7 @@
diff --git a/resources/views/layouts/site.blade.php b/resources/views/layouts/site.blade.php index 22b61c8..2c235b7 100644 --- a/resources/views/layouts/site.blade.php +++ b/resources/views/layouts/site.blade.php @@ -998,6 +998,46 @@ +@php + $topNavItems = [ + ['route' => 'tools.index', 'label' => 'AI工具集'], + ['route' => 'models.index', 'label' => '模型推荐'], + ['route' => 'news.index', 'label' => '文章资讯'], + ['route' => 'guides.index', 'label' => '教程学习'], + ['route' => 'tools.list', 'label' => '工具列表'], + ]; +@endphp + + +
@yield('content') diff --git a/resources/views/public/tools/index.blade.php b/resources/views/public/tools/index.blade.php index 61e6ed2..0625a34 100644 --- a/resources/views/public/tools/index.blade.php +++ b/resources/views/public/tools/index.blade.php @@ -9,53 +9,58 @@ @@ -81,12 +87,31 @@ $latestModule = $modules['latest_tools'] ?? null; $categoryModule = $modules['category_sections'] ?? null; $moduleOrder = collect($modules)->sortBy('sort_order')->pluck('module_key')->values(); + + $channelItems = collect(data_get($channelModule, 'items', []))->take((int) data_get($channelModule, 'limit', 5)); + $bannerItems = collect(data_get($bannerModule, 'items', []))->take((int) data_get($bannerModule, 'limit', 2)); @endphp
- -
AI-BOT.CN

{{ data_get($hotModule, 'extra.side_title', 'AI工具集') }}

@@ -150,10 +173,15 @@ @foreach($moduleOrder as $moduleKey) @if($moduleKey === 'channel_cards' && data_get($channelModule, 'enabled', true) === true) @php - $channelItems = collect(data_get($channelModule, 'items', []))->take((int) data_get($channelModule, 'limit', 5)); $miniItems = $channelItems->take(4); @endphp -
+
+
+

{{ data_get($channelModule, 'title', '频道卡片') }}

+
查看更多 +
+ +
@endif @if($moduleKey === 'promo_banners' && data_get($bannerModule, 'enabled', true) === true) - @php($bannerItems = collect(data_get($bannerModule, 'items', []))->take((int) data_get($bannerModule, 'limit', 2))) -
+
+
+

{{ data_get($bannerModule, 'title', '横幅推荐') }}

+ 查看更多 +
+ +
@endif @@ -229,7 +264,7 @@