# 管理后台功能增强 - 设计文档 ## 架构设计 ### 整体架构 ``` ┌─────────────────────────────────────────────────────────┐ │ Filament Admin Panel │ ├─────────────────────────────────────────────────────────┤ │ 系统设置页面 │ 操作日志页面 │ 大屏配置 │ SOP模板 │ ├─────────────────────────────────────────────────────────┤ │ Filament Resources & Pages │ ├─────────────────────────────────────────────────────────┤ │ Laravel Models │ ├─────────────────────────────────────────────────────────┤ │ MySQL Database │ └─────────────────────────────────────────────────────────┘ ``` ## 数据库设计 ### 1. 系统设置表 (system_settings) ```sql CREATE TABLE system_settings ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, `key` VARCHAR(255) NOT NULL UNIQUE COMMENT '配置键', `value` JSON NOT NULL COMMENT '配置值', `group` VARCHAR(100) NOT NULL COMMENT '配置分组', description TEXT COMMENT '配置说明', is_public BOOLEAN DEFAULT FALSE COMMENT '是否公开', created_at TIMESTAMP NULL, updated_at TIMESTAMP NULL, INDEX idx_group (`group`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ``` ### 2. 操作日志表 (activity_log) 使用 spatie/laravel-activitylog 包的标准表结构 ### 3. 大屏终端表 (terminals) ```sql CREATE TABLE terminals ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL COMMENT '终端名称', code VARCHAR(100) NOT NULL UNIQUE COMMENT '终端编码', ip_address VARCHAR(45) COMMENT 'IP地址', station_id BIGINT UNSIGNED COMMENT '线站ID', diagram_url VARCHAR(500) COMMENT '组态图URL', display_config JSON COMMENT '显示配置', is_online BOOLEAN DEFAULT FALSE COMMENT '在线状态', last_online_at TIMESTAMP NULL COMMENT '最后在线时间', created_at TIMESTAMP NULL, updated_at TIMESTAMP NULL, deleted_at TIMESTAMP NULL, INDEX idx_station (station_id), INDEX idx_online (is_online) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ``` ### 4. 终端知识库关联表 (terminal_knowledge_bases) ```sql CREATE TABLE terminal_knowledge_bases ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, terminal_id BIGINT UNSIGNED NOT NULL COMMENT '终端ID', knowledge_base_id BIGINT UNSIGNED NOT NULL COMMENT '知识库ID', priority INTEGER DEFAULT 0 COMMENT '优先级', created_at TIMESTAMP NULL, updated_at TIMESTAMP NULL, FOREIGN KEY (terminal_id) REFERENCES terminals(id) ON DELETE CASCADE, UNIQUE KEY uk_terminal_kb (terminal_id, knowledge_base_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ``` ### 5. 终端提示词表 (terminal_prompts) ```sql CREATE TABLE terminal_prompts ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, terminal_id BIGINT UNSIGNED NOT NULL COMMENT '终端ID', prompt_template TEXT NOT NULL COMMENT '提示词模板', variables JSON COMMENT '变量配置', created_at TIMESTAMP NULL, updated_at TIMESTAMP NULL, FOREIGN KEY (terminal_id) REFERENCES terminals(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ``` ### 6. 终端同步日志表 (terminal_sync_logs) ```sql CREATE TABLE terminal_sync_logs ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, terminal_id BIGINT UNSIGNED NOT NULL COMMENT '终端ID', status ENUM('pending', 'syncing', 'synced', 'failed') DEFAULT 'pending' COMMENT '同步状态', config_snapshot JSON COMMENT '配置快照', synced_at TIMESTAMP NULL COMMENT '同步时间', error_message TEXT COMMENT '错误信息', created_at TIMESTAMP NULL, updated_at TIMESTAMP NULL, FOREIGN KEY (terminal_id) REFERENCES terminals(id) ON DELETE CASCADE, INDEX idx_status (status), INDEX idx_synced_at (synced_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ``` ### 7. SOP模板表 (sop_templates) ```sql CREATE TABLE sop_templates ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL COMMENT '模板名称', description TEXT COMMENT '模板描述', category VARCHAR(100) COMMENT '分类', tags JSON COMMENT '标签', version VARCHAR(50) DEFAULT '1.0.0' COMMENT '版本号', status ENUM('draft', 'published', 'archived') DEFAULT 'draft' COMMENT '状态', applicable_departments JSON COMMENT '适用部门', applicable_positions JSON COMMENT '适用岗位', published_at TIMESTAMP NULL COMMENT '发布时间', created_by BIGINT UNSIGNED COMMENT '创建人', created_at TIMESTAMP NULL, updated_at TIMESTAMP NULL, deleted_at TIMESTAMP NULL, INDEX idx_status (status), INDEX idx_category (category) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ``` ### 8. SOP步骤表 (sop_steps) ```sql CREATE TABLE sop_steps ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, sop_template_id BIGINT UNSIGNED NOT NULL COMMENT '模板ID', step_number INTEGER NOT NULL COMMENT '步骤序号', title VARCHAR(255) NOT NULL COMMENT '步骤标题', content TEXT COMMENT '步骤内容', sort_order INTEGER DEFAULT 0 COMMENT '排序', is_required BOOLEAN DEFAULT TRUE COMMENT '是否必需', created_at TIMESTAMP NULL, updated_at TIMESTAMP NULL, FOREIGN KEY (sop_template_id) REFERENCES sop_templates(id) ON DELETE CASCADE, INDEX idx_template_sort (sop_template_id, sort_order) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ``` ### 9. SOP交互任务表 (sop_interactive_tasks) ```sql CREATE TABLE sop_interactive_tasks ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, sop_step_id BIGINT UNSIGNED NOT NULL COMMENT '步骤ID', task_type ENUM('confirm', 'input', 'select', 'photo', 'scan') NOT NULL COMMENT '任务类型', task_config JSON COMMENT '任务配置', validation_rules JSON COMMENT '验证规则', timeout_seconds INTEGER COMMENT '超时时间', is_required BOOLEAN DEFAULT TRUE COMMENT '是否必需', created_at TIMESTAMP NULL, updated_at TIMESTAMP NULL, FOREIGN KEY (sop_step_id) REFERENCES sop_steps(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ``` ### 10. SOP模板版本表 (sop_template_versions) ```sql CREATE TABLE sop_template_versions ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, sop_template_id BIGINT UNSIGNED NOT NULL COMMENT '模板ID', version VARCHAR(50) NOT NULL COMMENT '版本号', change_log TEXT COMMENT '变更说明', content_snapshot JSON COMMENT '内容快照', created_by BIGINT UNSIGNED COMMENT '创建人', created_at TIMESTAMP NULL, FOREIGN KEY (sop_template_id) REFERENCES sop_templates(id) ON DELETE CASCADE, INDEX idx_template_version (sop_template_id, version) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ``` ## 模型设计 ### 1. SystemSetting 模型 ```php namespace App\Models; use Illuminate\Database\Eloquent\Model; class SystemSetting extends Model { protected $fillable = [ 'key', 'value', 'group', 'description', 'is_public' ]; protected $casts = [ 'value' => 'array', 'is_public' => 'boolean', ]; // 获取配置值 public static function get(string $key, $default = null) { $setting = static::where('key', $key)->first(); return $setting ? $setting->value : $default; } // 设置配置值 public static function set(string $key, $value, string $group = 'general') { return static::updateOrCreate( ['key' => $key], ['value' => $value, 'group' => $group] ); } } ``` ### 2. Terminal 模型 ```php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; use Spatie\Activitylog\Traits\LogsActivity; use Spatie\Activitylog\LogOptions; class Terminal extends Model { use SoftDeletes, LogsActivity; protected $fillable = [ 'name', 'code', 'ip_address', 'station_id', 'diagram_url', 'display_config', 'is_online', 'last_online_at' ]; protected $casts = [ 'display_config' => 'array', 'is_online' => 'boolean', 'last_online_at' => 'datetime', ]; public function knowledgeBases() { return $this->belongsToMany(KnowledgeBase::class, 'terminal_knowledge_bases') ->withPivot('priority') ->orderBy('priority'); } public function prompt() { return $this->hasOne(TerminalPrompt::class); } public function syncLogs() { return $this->hasMany(TerminalSyncLog::class); } public function getActivitylogOptions(): LogOptions { return LogOptions::defaults() ->logOnly(['name', 'code', 'station_id', 'diagram_url', 'display_config']) ->logOnlyDirty(); } } ``` ### 3. SopTemplate 模型 ```php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; use Spatie\Activitylog\Traits\LogsActivity; use Spatie\Activitylog\LogOptions; class SopTemplate extends Model { use SoftDeletes, LogsActivity; protected $fillable = [ 'name', 'description', 'category', 'tags', 'version', 'status', 'applicable_departments', 'applicable_positions', 'published_at', 'created_by' ]; protected $casts = [ 'tags' => 'array', 'applicable_departments' => 'array', 'applicable_positions' => 'array', 'published_at' => 'datetime', ]; public function steps() { return $this->hasMany(SopStep::class)->orderBy('sort_order'); } public function versions() { return $this->hasMany(SopTemplateVersion::class); } public function creator() { return $this->belongsTo(User::class, 'created_by'); } public function getActivitylogOptions(): LogOptions { return LogOptions::defaults() ->logOnly(['name', 'description', 'category', 'status', 'version']) ->logOnlyDirty(); } } ``` ## Filament资源设计 ### 1. SystemSettingResource - 使用Tabs组件按group分组显示配置 - 使用KeyValue字段编辑JSON配置 - 敏感配置使用Password字段 ### 2. ActivityLogResource - 只读资源,不允许创建和编辑 - 使用Tables\Filters进行筛选 - 使用Actions\ExportAction导出数据 - 自定义ViewAction显示变更对比 ### 3. TerminalResource - 使用Badge显示在线状态 - 使用Select2组件选择知识库(多选+搜索) - 使用MonacoEditor编辑提示词 - 自定义Action触发配置下发 ### 4. SopTemplateResource - 使用Repeater组件管理步骤 - 使用RichEditor编辑步骤内容 - 使用Builder组件配置交互任务 - 自定义PreviewAction预览模板 ## API设计 ### 终端配置同步API ```php POST /api/terminals/{terminal}/sync Response: { "success": true, "sync_log_id": 123, "message": "配置同步已启动" } ``` ### SOP模板导出API ```php GET /api/sop-templates/{template}/export?format=json|pdf Response: File Download ``` ## 前端组件设计 ### 1. 日志对比组件 ```php // app/Filament/Components/LogDiffViewer.php class LogDiffViewer extends Component { public array $oldData; public array $newData; public function render() { return view('filament.components.log-diff-viewer'); } } ``` ### 2. 终端状态指示器 ```php // app/Filament/Components/TerminalStatusBadge.php class TerminalStatusBadge extends Component { public bool $isOnline; public ?Carbon $lastOnlineAt; public function render() { return view('filament.components.terminal-status-badge'); } } ``` ### 3. SOP步骤编辑器 ```php // app/Filament/Components/SopStepEditor.php class SopStepEditor extends Component { public array $steps = []; public function addStep() { $this->steps[] = [ 'title' => '', 'content' => '', 'sort_order' => count($this->steps) + 1, ]; } public function removeStep($index) { unset($this->steps[$index]); $this->steps = array_values($this->steps); } public function reorderSteps($orderedIds) { // 重新排序逻辑 } } ``` ## 服务层设计 ### 1. SystemSettingService ```php namespace App\Services; class SystemSettingService { public function getGroupedSettings(): array { return SystemSetting::all() ->groupBy('group') ->toArray(); } public function updateSettings(array $settings): void { foreach ($settings as $key => $value) { SystemSetting::set($key, $value); } } } ``` ### 2. TerminalSyncService ```php namespace App\Services; class TerminalSyncService { public function syncConfiguration(Terminal $terminal): TerminalSyncLog { $log = TerminalSyncLog::create([ 'terminal_id' => $terminal->id, 'status' => 'pending', 'config_snapshot' => $this->getConfigSnapshot($terminal), ]); // 触发异步同步任务 dispatch(new SyncTerminalConfigJob($terminal, $log)); return $log; } private function getConfigSnapshot(Terminal $terminal): array { return [ 'terminal' => $terminal->toArray(), 'knowledge_bases' => $terminal->knowledgeBases->toArray(), 'prompt' => $terminal->prompt?->toArray(), ]; } } ``` ### 3. SopTemplateService ```php namespace App\Services; class SopTemplateService { public function publish(SopTemplate $template): void { // 创建版本快照 $this->createVersion($template); // 更新状态 $template->update([ 'status' => 'published', 'published_at' => now(), ]); } public function createVersion(SopTemplate $template): SopTemplateVersion { return SopTemplateVersion::create([ 'sop_template_id' => $template->id, 'version' => $template->version, 'content_snapshot' => [ 'template' => $template->toArray(), 'steps' => $template->steps->toArray(), ], 'created_by' => auth()->id(), ]); } public function export(SopTemplate $template, string $format): string { return match($format) { 'json' => $this->exportToJson($template), 'pdf' => $this->exportToPdf($template), default => throw new \InvalidArgumentException("Unsupported format: $format"), }; } } ``` ## 任务队列设计 ### 1. SyncTerminalConfigJob ```php namespace App\Jobs; class SyncTerminalConfigJob implements ShouldQueue { public function __construct( public Terminal $terminal, public TerminalSyncLog $log ) {} public function handle(): void { try { $this->log->update(['status' => 'syncing']); // 调用终端API同步配置 $response = Http::post($this->terminal->sync_url, [ 'config' => $this->log->config_snapshot, ]); if ($response->successful()) { $this->log->update([ 'status' => 'synced', 'synced_at' => now(), ]); } else { throw new \Exception($response->body()); } } catch (\Exception $e) { $this->log->update([ 'status' => 'failed', 'error_message' => $e->getMessage(), ]); } } } ``` ## 权限设计 ### 策略定义 ```php // app/Policies/SystemSettingPolicy.php class SystemSettingPolicy { public function viewAny(User $user): bool { return $user->hasRole('admin'); } public function update(User $user, SystemSetting $setting): bool { return $user->hasRole('admin'); } } // app/Policies/TerminalPolicy.php class TerminalPolicy { public function viewAny(User $user): bool { return $user->hasAnyRole(['admin', 'terminal_manager']); } public function sync(User $user, Terminal $terminal): bool { return $user->hasRole('admin'); } } // app/Policies/SopTemplatePolicy.php class SopTemplatePolicy { public function publish(User $user, SopTemplate $template): bool { return $user->hasAnyRole(['admin', 'content_manager']); } } ``` ## 测试策略 ### 单元测试 - SystemSetting模型的get/set方法 - Terminal模型的关联关系 - SopTemplate的版本管理逻辑 - 各Service类的核心方法 ### 功能测试 - Filament资源的CRUD操作 - 日志筛选和导出功能 - 终端配置同步流程 - SOP模板发布流程 ### 集成测试 - 操作日志自动记录 - 终端配置同步任务 - SOP模板导入导出 ## 性能优化 ### 数据库优化 - 为常用查询字段添加索引 - 使用Eager Loading避免N+1问题 - 大表使用分区(如activity_log) ### 缓存策略 - 系统设置使用缓存(Cache::remember) - 终端在线状态使用Redis缓存 - SOP模板列表使用查询缓存 ### 前端优化 - 使用Lazy Loading加载大型列表 - Monaco Editor按需加载 - 图片使用CDN加速 ## 安全考虑 ### 数据安全 - 敏感配置(API密钥)使用加密存储 - 操作日志不可删除 - SOP模板版本不可修改 ### 访问控制 - 基于角色的权限控制 - 敏感操作需要二次确认 - API接口使用认证和授权 ### 输入验证 - 所有表单输入进行验证 - 富文本内容进行XSS过滤 - 文件上传进行类型和大小限制