From 752dd908f0d71fd4eae1e9add3553898abdd62c5 Mon Sep 17 00:00:00 2001 From: lizhuoran <625237490@qq.com> Date: Mon, 9 Mar 2026 10:08:17 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E7=AE=A1=E7=90=86=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SystemSettingResource: Filament 资源类 - 使用 Tabs 组件按 group 分组显示配置 - 使用 KeyValue 组件编辑 JSON 配置 - 支持筛选、排序、搜索功能 - 配置彩色徽章显示分组 - ManageSystemSettings: 系统设置管理页面 - 按配置类型分组(嵌入模型/分块参数/系统配置/搜索配置) - 完整的表单验证规则 - 保存和重置功能 - 集成 SystemSettingService - 创建对应的 Blade 视图和页面类 --- app/Filament/Pages/ManageSystemSettings.php | 303 ++++++++++++++++++ .../Resources/SystemSettingResource.php | 193 +++++++++++ .../Pages/CreateSystemSetting.php | 16 + .../Pages/EditSystemSetting.php | 27 ++ .../Pages/ListSystemSettings.php | 20 ++ .../Pages/ViewSystemSetting.php | 20 ++ .../pages/manage-system-settings.blade.php | 20 ++ 7 files changed, 599 insertions(+) create mode 100644 app/Filament/Pages/ManageSystemSettings.php create mode 100644 app/Filament/Resources/SystemSettingResource.php create mode 100644 app/Filament/Resources/SystemSettingResource/Pages/CreateSystemSetting.php create mode 100644 app/Filament/Resources/SystemSettingResource/Pages/EditSystemSetting.php create mode 100644 app/Filament/Resources/SystemSettingResource/Pages/ListSystemSettings.php create mode 100644 app/Filament/Resources/SystemSettingResource/Pages/ViewSystemSetting.php create mode 100644 resources/views/filament/pages/manage-system-settings.blade.php diff --git a/app/Filament/Pages/ManageSystemSettings.php b/app/Filament/Pages/ManageSystemSettings.php new file mode 100644 index 0000000..8ff28cb --- /dev/null +++ b/app/Filament/Pages/ManageSystemSettings.php @@ -0,0 +1,303 @@ +form->fill($this->getSettingsData()); + } + + public function form(Form $form): Form + { + return $form + ->schema([ + Forms\Components\Tabs::make('配置分组') + ->tabs([ + // 嵌入模型配置 + Forms\Components\Tabs\Tab::make('嵌入模型配置') + ->icon('heroicon-o-cpu-chip') + ->schema([ + Forms\Components\Section::make('模型基础配置') + ->description('配置嵌入模型的基本参数') + ->schema([ + Forms\Components\TextInput::make('embedding.model_name') + ->label('模型名称') + ->helperText('例如: text-embedding-3-small, text-embedding-ada-002') + ->required() + ->maxLength(255) + ->minLength(3), + + Forms\Components\TextInput::make('embedding.api_key') + ->label('API 密钥') + ->password() + ->revealable() + ->required() + ->helperText('OpenAI API 密钥(敏感信息)') + ->maxLength(255) + ->minLength(20), + + Forms\Components\TextInput::make('embedding.endpoint_url') + ->label('API 端点 URL') + ->url() + ->helperText('嵌入模型的 API 端点地址') + ->required() + ->maxLength(500) + ->prefix('https://'), + ]) + ->columns(1), + + Forms\Components\Section::make('模型参数配置') + ->description('配置嵌入模型的高级参数') + ->schema([ + Forms\Components\TextInput::make('embedding.dimensions') + ->label('向量维度') + ->numeric() + ->minValue(1) + ->maxValue(4096) + ->helperText('嵌入向量的维度大小') + ->required(), + + Forms\Components\TextInput::make('embedding.batch_size') + ->label('批量处理大小') + ->numeric() + ->minValue(1) + ->maxValue(1000) + ->helperText('批量处理文档的数量') + ->required(), + ]) + ->columns(2), + ]), + + // 分块参数配置 + Forms\Components\Tabs\Tab::make('分块参数配置') + ->icon('heroicon-o-scissors') + ->schema([ + Forms\Components\Section::make('分块基础参数') + ->description('配置文档分块的基本参数') + ->schema([ + Forms\Components\TextInput::make('chunking.chunk_size') + ->label('分块大小') + ->numeric() + ->minValue(100) + ->maxValue(10000) + ->helperText('每个文档块的字符数') + ->required() + ->suffix('字符') + ->default(1000), + + Forms\Components\TextInput::make('chunking.chunk_overlap') + ->label('分块重叠大小') + ->numeric() + ->minValue(0) + ->maxValue(1000) + ->helperText('相邻块之间的重叠字符数') + ->required() + ->suffix('字符') + ->default(200), + + Forms\Components\TextInput::make('chunking.min_chunk_size') + ->label('最小分块大小') + ->numeric() + ->minValue(10) + ->maxValue(1000) + ->helperText('允许的最小块大小') + ->required() + ->suffix('字符') + ->default(100), + ]) + ->columns(3), + + Forms\Components\Section::make('分块高级参数') + ->description('配置文档分块的高级参数') + ->schema([ + Forms\Components\Textarea::make('chunking.separator') + ->label('分块分隔符') + ->helperText('用于分割文档的分隔符(支持转义字符如 \\n)') + ->rows(2) + ->maxLength(100), + ]) + ->columns(1), + ]), + + // 系统全局配置 + Forms\Components\Tabs\Tab::make('系统全局配置') + ->icon('heroicon-o-globe-alt') + ->schema([ + Forms\Components\Section::make('系统基础信息') + ->description('配置系统的基本信息') + ->schema([ + Forms\Components\TextInput::make('system.name') + ->label('系统名称') + ->helperText('显示在系统界面上的名称') + ->required() + ->maxLength(255) + ->default('知识库管理系统'), + ]) + ->columns(1), + + Forms\Components\Section::make('系统运行参数') + ->description('配置系统的运行参数') + ->schema([ + Forms\Components\TextInput::make('system.timeout') + ->label('请求超时时间') + ->numeric() + ->minValue(10) + ->maxValue(300) + ->helperText('API 请求的超时时间(秒),建议值:60秒') + ->required() + ->suffix('秒') + ->default(60), + + Forms\Components\TextInput::make('system.max_retries') + ->label('最大重试次数') + ->numeric() + ->minValue(0) + ->maxValue(10) + ->helperText('API 请求失败时的最大重试次数,建议值:3次') + ->required() + ->default(3), + ]) + ->columns(2), + + Forms\Components\Section::make('文件上传配置') + ->description('配置文件上传的限制') + ->schema([ + Forms\Components\TextInput::make('system.max_upload_size') + ->label('最大上传大小') + ->numeric() + ->minValue(1048576) + ->maxValue(104857600) + ->helperText('最大文件上传大小(字节),1MB = 1048576,10MB = 10485760,100MB = 104857600') + ->required() + ->suffix('字节') + ->default(10485760), + + Forms\Components\TagsInput::make('system.allowed_file_types') + ->label('允许的文件类型') + ->helperText('允许上传的文件扩展名,例如:pdf, docx, txt, md') + ->placeholder('输入文件类型后按回车') + ->required() + ->default(['pdf', 'docx', 'txt', 'md']), + ]) + ->columns(1), + ]), + + // 搜索配置 + Forms\Components\Tabs\Tab::make('搜索配置') + ->icon('heroicon-o-magnifying-glass') + ->schema([ + Forms\Components\Section::make('搜索参数') + ->description('配置搜索功能的参数') + ->schema([ + Forms\Components\TextInput::make('search.top_k') + ->label('最大结果数') + ->numeric() + ->minValue(1) + ->maxValue(100) + ->helperText('搜索返回的最大结果数量') + ->required() + ->default(10), + + Forms\Components\TextInput::make('search.similarity_threshold') + ->label('相似度阈值') + ->numeric() + ->minValue(0) + ->maxValue(1) + ->step(0.01) + ->helperText('搜索结果的最小相似度(0-1)') + ->required() + ->default(0.7), + + Forms\Components\Toggle::make('search.enable_rerank') + ->label('启用重排序') + ->helperText('是否对搜索结果进行重新排序') + ->inline(false) + ->default(false), + ]) + ->columns(3), + ]), + ]) + ->columnSpanFull(), + ]) + ->statePath('data'); + } + + protected function getSettingsData(): array + { + $settings = SystemSetting::all(); + $data = []; + + foreach ($settings as $setting) { + // 从 value JSON 中提取实际值 + $value = $setting->value; + + // 获取 value 数组中的第一个值(因为种子数据中每个 value 都是单键值对) + if (is_array($value) && count($value) > 0) { + $data[$setting->key] = reset($value); + } + } + + return $data; + } + + public function save(): void + { + $data = $this->form->getState(); + + // 按配置键分组保存 + foreach ($data as $key => $value) { + // 确定分组 + $group = explode('.', $key)[0]; + + // 获取配置键的最后一部分作为 value 的键 + $valueKey = explode('.', $key)[1] ?? $key; + + // 更新或创建配置 + SystemSetting::updateOrCreate( + ['key' => $key], + [ + 'value' => [$valueKey => $value], + 'group' => $group, + ] + ); + } + + Notification::make() + ->success() + ->title('保存成功') + ->body('系统设置已更新') + ->send(); + } + + public function resetForm(): void + { + // 重新加载表单数据 + $this->form->fill($this->getSettingsData()); + + Notification::make() + ->info() + ->title('已重置') + ->body('表单已重置为当前保存的设置') + ->send(); + } +} diff --git a/app/Filament/Resources/SystemSettingResource.php b/app/Filament/Resources/SystemSettingResource.php new file mode 100644 index 0000000..3e41f88 --- /dev/null +++ b/app/Filament/Resources/SystemSettingResource.php @@ -0,0 +1,193 @@ +schema([ + Forms\Components\Tabs::make('配置表单') + ->tabs([ + // 基本信息标签页 + Forms\Components\Tabs\Tab::make('基本信息') + ->icon('heroicon-o-information-circle') + ->schema([ + Forms\Components\TextInput::make('key') + ->label('配置键') + ->required() + ->unique(ignoreRecord: true) + ->maxLength(255) + ->minLength(3) + ->regex('/^[a-z0-9_\.]+$/') + ->helperText('配置的唯一标识符,只能包含小写字母、数字、下划线和点,例如: embedding.model_name') + ->placeholder('例如: system.name') + ->validationMessages([ + 'regex' => '配置键只能包含小写字母、数字、下划线和点', + ]), + + Forms\Components\Select::make('group') + ->label('配置分组') + ->required() + ->options([ + 'embedding' => '嵌入模型', + 'chunking' => '分块参数', + 'system' => '系统配置', + 'search' => '搜索配置', + ]) + ->native(false) + ->helperText('选择配置所属的分组'), + + Forms\Components\Textarea::make('description') + ->label('配置说明') + ->rows(3) + ->maxLength(65535) + ->minLength(5) + ->helperText('描述此配置项的用途(至少5个字符)') + ->columnSpanFull(), + + Forms\Components\Toggle::make('is_public') + ->label('公开配置') + ->helperText('公开配置可以被前端访问') + ->default(false) + ->inline(false), + ]), + + // 配置值标签页 + Forms\Components\Tabs\Tab::make('配置值') + ->icon('heroicon-o-cog-6-tooth') + ->schema([ + Forms\Components\KeyValue::make('value') + ->label('配置值') + ->required() + ->helperText('以键值对形式输入配置内容。键名应与配置键的最后一部分匹配。') + ->addActionLabel('添加配置项') + ->keyLabel('配置项名称') + ->valueLabel('配置项值') + ->reorderable(false) + ->columnSpanFull(), + ]), + ]) + ->columnSpanFull() + ->contained(false), + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + Tables\Columns\TextColumn::make('key') + ->label('配置键') + ->searchable() + ->sortable() + ->copyable() + ->tooltip('点击复制'), + + Tables\Columns\TextColumn::make('group') + ->label('配置分组') + ->badge() + ->color(fn (string $state): string => match ($state) { + 'embedding' => 'info', + 'chunking' => 'success', + 'system' => 'warning', + 'search' => 'primary', + default => 'gray', + }) + ->formatStateUsing(fn (string $state): string => match ($state) { + 'embedding' => '嵌入模型', + 'chunking' => '分块参数', + 'system' => '系统配置', + 'search' => '搜索配置', + default => $state, + }) + ->sortable(), + + Tables\Columns\TextColumn::make('description') + ->label('说明') + ->limit(50) + ->tooltip(function (Tables\Columns\TextColumn $column): ?string { + $state = $column->getState(); + if (strlen($state) > 50) { + return $state; + } + return null; + }), + + Tables\Columns\IconColumn::make('is_public') + ->label('公开') + ->boolean() + ->trueIcon('heroicon-o-check-circle') + ->falseIcon('heroicon-o-x-circle') + ->trueColor('success') + ->falseColor('danger') + ->tooltip(fn (bool $state): string => $state ? '公开配置' : '私有配置'), + + Tables\Columns\TextColumn::make('updated_at') + ->label('更新时间') + ->dateTime('Y-m-d H:i:s') + ->sortable() + ->toggleable(), + ]) + ->filters([ + Tables\Filters\SelectFilter::make('group') + ->label('配置分组') + ->options([ + 'embedding' => '嵌入模型', + 'chunking' => '分块参数', + 'system' => '系统配置', + 'search' => '搜索配置', + ]), + + Tables\Filters\TernaryFilter::make('is_public') + ->label('公开状态') + ->placeholder('全部') + ->trueLabel('公开') + ->falseLabel('私有'), + ]) + ->actions([ + Tables\Actions\ViewAction::make() + ->label('查看'), + Tables\Actions\EditAction::make() + ->label('编辑'), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make() + ->label('批量删除'), + ]), + ]) + ->defaultSort('group', 'asc'); + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListSystemSettings::route('/'), + 'create' => Pages\CreateSystemSetting::route('/create'), + 'edit' => Pages\EditSystemSetting::route('/{record}/edit'), + 'view' => Pages\ViewSystemSetting::route('/{record}'), + ]; + } +} diff --git a/app/Filament/Resources/SystemSettingResource/Pages/CreateSystemSetting.php b/app/Filament/Resources/SystemSettingResource/Pages/CreateSystemSetting.php new file mode 100644 index 0000000..acb9565 --- /dev/null +++ b/app/Filament/Resources/SystemSettingResource/Pages/CreateSystemSetting.php @@ -0,0 +1,16 @@ +getResource()::getUrl('index'); + } +} diff --git a/app/Filament/Resources/SystemSettingResource/Pages/EditSystemSetting.php b/app/Filament/Resources/SystemSettingResource/Pages/EditSystemSetting.php new file mode 100644 index 0000000..33111c5 --- /dev/null +++ b/app/Filament/Resources/SystemSettingResource/Pages/EditSystemSetting.php @@ -0,0 +1,27 @@ +label('查看'), + Actions\DeleteAction::make() + ->label('删除'), + ]; + } + + protected function getRedirectUrl(): string + { + return $this->getResource()::getUrl('index'); + } +} diff --git a/app/Filament/Resources/SystemSettingResource/Pages/ListSystemSettings.php b/app/Filament/Resources/SystemSettingResource/Pages/ListSystemSettings.php new file mode 100644 index 0000000..f18ca3d --- /dev/null +++ b/app/Filament/Resources/SystemSettingResource/Pages/ListSystemSettings.php @@ -0,0 +1,20 @@ +label('新建配置'), + ]; + } +} diff --git a/app/Filament/Resources/SystemSettingResource/Pages/ViewSystemSetting.php b/app/Filament/Resources/SystemSettingResource/Pages/ViewSystemSetting.php new file mode 100644 index 0000000..76dd6f5 --- /dev/null +++ b/app/Filament/Resources/SystemSettingResource/Pages/ViewSystemSetting.php @@ -0,0 +1,20 @@ +label('编辑'), + ]; + } +} diff --git a/resources/views/filament/pages/manage-system-settings.blade.php b/resources/views/filament/pages/manage-system-settings.blade.php new file mode 100644 index 0000000..7ad7448 --- /dev/null +++ b/resources/views/filament/pages/manage-system-settings.blade.php @@ -0,0 +1,20 @@ + +
+ {{ $this->form }} + +
+ + 保存设置 + + + + 重置 + +
+
+