diff --git a/app/Filament/Actions/SyncConfigAction.php b/app/Filament/Actions/SyncConfigAction.php deleted file mode 100644 index bceb2a4..0000000 --- a/app/Filament/Actions/SyncConfigAction.php +++ /dev/null @@ -1,71 +0,0 @@ -label('同步配置') - ->icon('heroicon-o-arrow-path') - ->color('success') - ->requiresConfirmation() - ->modalHeading('同步终端配置') - ->modalDescription('确定要将配置同步到此终端吗?') - ->modalSubmitActionLabel('确认同步') - ->action(function (Terminal $record) { - $service = app(TerminalSyncService::class); - $log = $service->syncConfiguration($record); - - Notification::make() - ->title('同步任务已启动') - ->body("终端 {$record->name} 的配置同步任务已加入队列") - ->success() - ->send(); - }); - } - - /** - * 创建批量同步Action - * - * @return BulkAction - */ - public static function makeBulk(): BulkAction - { - return BulkAction::make('batchSync') - ->label('批量同步') - ->icon('heroicon-o-arrow-path') - ->color('success') - ->requiresConfirmation() - ->modalHeading('批量同步终端配置') - ->modalDescription(fn ($records) => "确定要同步 {$records->count()} 个终端的配置吗?") - ->modalSubmitActionLabel('确认同步') - ->action(function ($records) { - $service = app(TerminalSyncService::class); - $terminalIds = $records->pluck('id')->toArray(); - $logs = $service->batchSync($terminalIds); - - Notification::make() - ->title('批量同步任务已启动') - ->body("已为 " . count($logs) . " 个终端创建同步任务") - ->success() - ->send(); - }) - ->deselectRecordsAfterCompletion(); - } -} diff --git a/app/Filament/Resources/TerminalResource.php b/app/Filament/Resources/TerminalResource.php index 8bd78a3..76c78b8 100644 --- a/app/Filament/Resources/TerminalResource.php +++ b/app/Filament/Resources/TerminalResource.php @@ -3,7 +3,6 @@ namespace App\Filament\Resources; use App\Filament\Resources\TerminalResource\Pages; -use App\Filament\Actions\SyncConfigAction; use App\Models\Terminal; use Filament\Forms; use Filament\Forms\Form; @@ -86,50 +85,34 @@ class TerminalResource extends Resource ]) ->columns(2), - Forms\Components\Section::make('组态图配置') + Forms\Components\Section::make('组态配置') ->schema([ Forms\Components\TextInput::make('diagram_url') - ->label('组态图URL') + ->label('组态界面地址') ->url() ->maxLength(500) ->placeholder('https://example.com/diagram.png') - ->helperText('组态图的访问地址'), + ->helperText('组态界面的访问地址'), ]), - Forms\Components\Section::make('SCADA网关配置') + Forms\Components\Section::make('网关配置') ->schema([ Forms\Components\TextInput::make('scada_data_url') - ->label('SCADA数据查询URL') + ->label('数据查询URL') ->url() ->maxLength(500) ->placeholder('http://gateway:8080/api/data') - ->helperText('OPC UA HTTP网关的数据查询地址'), + ->helperText('网关的数据查询地址'), Forms\Components\TextInput::make('scada_tags_url') - ->label('SCADA点位定义URL') + ->label('点位定义URL') ->url() ->maxLength(500) ->placeholder('http://gateway:8080/api/tags') - ->helperText('OPC UA HTTP网关的点位定义查询地址'), + ->helperText('网关的点位定义查询地址'), ]) ->columns(2), - Forms\Components\Section::make('显示配置') - ->schema([ - Forms\Components\KeyValue::make('display_config') - ->label('显示参数') - ->keyLabel('参数名称') - ->valueLabel('参数值') - ->addActionLabel('添加参数') - ->helperText('配置终端的显示参数,如分辨率、刷新率等') - ->default([ - 'resolution' => '1920x1080', - 'refresh_rate' => '60', - 'orientation' => 'landscape', - 'brightness' => '80', - ]), - ]), - Forms\Components\Section::make('知识库关联') ->schema([ Forms\Components\Repeater::make('knowledgeBaseAssociations') @@ -158,7 +141,8 @@ class TerminalResource extends Resource ->reorderableWithButtons() ->addActionLabel('添加知识库') ->reorderableWithDragAndDrop(false) - ->itemLabel(fn (array $state): ?string => + ->itemLabel( + fn(array $state): ?string => \App\Models\KnowledgeBase::find($state['id'])?->name ?? '未选择' ) ->collapsed() @@ -195,7 +179,8 @@ class TerminalResource extends Resource ->reorderableWithButtons() ->addActionLabel('添加指引') ->reorderableWithDragAndDrop(false) - ->itemLabel(fn (array $state): ?string => + ->itemLabel( + fn(array $state): ?string => \App\Models\Guide::find($state['id'])?->name ?? '未选择' ) ->collapsed() @@ -216,16 +201,16 @@ class TerminalResource extends Resource ->placeholderText('请输入AI提示词模板...') ->disablePreview() ->columnSpan(2), - + Forms\Components\Grid::make(1) ->schema([ Forms\Components\Placeholder::make('template_selector') ->label('模板库') - ->content(fn () => view('filament.components.prompt-template-selector')), - + ->content(fn() => view('filament.components.prompt-template-selector')), + Forms\Components\Placeholder::make('variable_helper') ->label('变量参考') - ->content(fn () => view('filament.components.prompt-variable-helper')), + ->content(fn() => view('filament.components.prompt-variable-helper')), ]) ->columnSpan(1), ]), @@ -296,33 +281,6 @@ class TerminalResource extends Resource ->falseColor('danger') ->sortable(), - Tables\Columns\TextColumn::make('latestSyncLog.status') - ->label('同步状态') - ->badge() - ->formatStateUsing(fn (string $state): string => match ($state) { - 'pending' => '待同步', - 'syncing' => '同步中', - 'synced' => '已同步', - 'failed' => '失败', - default => '未知', - }) - ->color(fn (string $state): string => match ($state) { - 'pending' => 'warning', - 'syncing' => 'info', - 'synced' => 'success', - 'failed' => 'danger', - default => 'gray', - }) - ->icon(fn (string $state): string => match ($state) { - 'pending' => 'heroicon-o-clock', - 'syncing' => 'heroicon-o-arrow-path', - 'synced' => 'heroicon-o-check-circle', - 'failed' => 'heroicon-o-x-circle', - default => 'heroicon-o-question-mark-circle', - }) - ->placeholder('从未同步') - ->sortable(), - Tables\Columns\TextColumn::make('last_online_at') ->label('最后在线时间') ->dateTime('Y-m-d H:i:s') @@ -348,17 +306,8 @@ class TerminalResource extends Resource ->placeholder('全部') ->trueLabel('在线') ->falseLabel('离线'), - - Tables\Filters\Filter::make('station_id') - ->label('已绑定线站') - ->query(fn (Builder $query): Builder => $query->whereNotNull('station_id')), - - Tables\Filters\Filter::make('has_diagram') - ->label('已配置组态图') - ->query(fn (Builder $query): Builder => $query->whereNotNull('diagram_url')), ]) ->actions([ - SyncConfigAction::make(), Tables\Actions\ViewAction::make() ->label('查看'), Tables\Actions\EditAction::make() @@ -368,7 +317,6 @@ class TerminalResource extends Resource ]) ->bulkActions([ Tables\Actions\BulkActionGroup::make([ - SyncConfigAction::makeBulk(), Tables\Actions\DeleteBulkAction::make() ->label('批量删除'), ]), @@ -380,7 +328,7 @@ class TerminalResource extends Resource ->collapsible(), Tables\Grouping\Group::make('is_online') ->label('按在线状态分组') - ->getTitleFromRecordUsing(fn (Terminal $record): string => $record->is_online ? '在线' : '离线') + ->getTitleFromRecordUsing(fn(Terminal $record): string => $record->is_online ? '在线' : '离线') ->collapsible(), ]); } diff --git a/app/Filament/Resources/TerminalResource/Pages/ViewTerminal.php b/app/Filament/Resources/TerminalResource/Pages/ViewTerminal.php index ba92d86..eeb8073 100644 --- a/app/Filament/Resources/TerminalResource/Pages/ViewTerminal.php +++ b/app/Filament/Resources/TerminalResource/Pages/ViewTerminal.php @@ -43,24 +43,16 @@ class ViewTerminal extends ViewRecord ]) ->columns(2), - Infolists\Components\Section::make('组态图配置') + Infolists\Components\Section::make('组态配置') ->schema([ Infolists\Components\TextEntry::make('diagram_url') - ->label('组态图URL') + ->label('组态界面地址') ->copyable() ->placeholder('未设置') - ->url(fn ($state) => $state) + ->url(fn($state) => $state) ->openUrlInNewTab(), ]), - Infolists\Components\Section::make('显示配置') - ->schema([ - Infolists\Components\KeyValueEntry::make('display_config') - ->label('显示参数') - ->keyLabel('参数名称') - ->valueLabel('参数值'), - ]), - Infolists\Components\Section::make('知识库关联') ->schema([ Infolists\Components\RepeatableEntry::make('knowledgeBases') @@ -103,49 +95,6 @@ class ViewTerminal extends ViewRecord ]) ->columns(2), - Infolists\Components\Section::make('同步历史') - ->schema([ - Infolists\Components\RepeatableEntry::make('syncLogs') - ->label('同步记录') - ->schema([ - Infolists\Components\TextEntry::make('status') - ->label('状态') - ->badge() - ->formatStateUsing(fn (string $state): string => match ($state) { - 'pending' => '待同步', - 'syncing' => '同步中', - 'synced' => '已同步', - 'failed' => '失败', - default => '未知', - }) - ->color(fn (string $state): string => match ($state) { - 'pending' => 'warning', - 'syncing' => 'info', - 'synced' => 'success', - 'failed' => 'danger', - default => 'gray', - }), - Infolists\Components\TextEntry::make('created_at') - ->label('创建时间') - ->dateTime('Y-m-d H:i:s'), - Infolists\Components\TextEntry::make('synced_at') - ->label('同步完成时间') - ->dateTime('Y-m-d H:i:s') - ->placeholder('未完成'), - Infolists\Components\TextEntry::make('error_message') - ->label('错误信息') - ->placeholder('无') - ->color('danger') - ->columnSpanFull(), - ]) - ->columns(3) - ->placeholder('暂无同步记录') - ->contained(false), - ]) - ->description('显示最近的配置同步记录,按时间倒序排列') - ->collapsible() - ->collapsed(), - Infolists\Components\Section::make('时间信息') ->schema([ Infolists\Components\TextEntry::make('created_at') diff --git a/app/Filament/Widgets/TerminalStatsWidget.php b/app/Filament/Widgets/TerminalStatsWidget.php index 7c3d1c3..84fda40 100644 --- a/app/Filament/Widgets/TerminalStatsWidget.php +++ b/app/Filament/Widgets/TerminalStatsWidget.php @@ -5,7 +5,6 @@ namespace App\Filament\Widgets; use App\Models\Terminal; use App\Models\TerminalKnowledgeBase; use App\Models\TerminalPrompt; -use App\Models\TerminalSyncLog; use Filament\Widgets\StatsOverviewWidget as BaseWidget; use Filament\Widgets\StatsOverviewWidget\Stat; @@ -25,15 +24,6 @@ class TerminalStatsWidget extends BaseWidget // 统计提示词 $totalPrompts = TerminalPrompt::count(); - // 统计最近同步 - $recentSyncs = TerminalSyncLog::where('created_at', '>=', now()->subDay()) - ->where('status', 'success') - ->count(); - - $failedSyncs = TerminalSyncLog::where('created_at', '>=', now()->subDay()) - ->where('status', 'failed') - ->count(); - return [ Stat::make('终端总数', $totalTerminals) ->description("{$onlineTerminals} 个在线") @@ -50,16 +40,6 @@ class TerminalStatsWidget extends BaseWidget ->description('终端提示词总数') ->descriptionIcon('heroicon-m-chat-bubble-left-right') ->color('success'), - - Stat::make('今日同步成功', $recentSyncs) - ->description('最近24小时') - ->descriptionIcon('heroicon-m-arrow-path') - ->color('success'), - - Stat::make('今日同步失败', $failedSyncs) - ->description($failedSyncs > 0 ? '需要检查' : '运行正常') - ->descriptionIcon($failedSyncs > 0 ? 'heroicon-m-exclamation-triangle' : 'heroicon-m-check-circle') - ->color($failedSyncs > 0 ? 'danger' : 'success'), ]; } } diff --git a/app/Http/Controllers/Api/TerminalApiController.php b/app/Http/Controllers/Api/TerminalApiController.php index dea1658..3cff39f 100644 --- a/app/Http/Controllers/Api/TerminalApiController.php +++ b/app/Http/Controllers/Api/TerminalApiController.php @@ -47,7 +47,6 @@ class TerminalApiController extends Controller 'diagram_url' => $terminal->diagram_url, 'scada_data_url' => $terminal->scada_data_url, 'scada_tags_url' => $terminal->scada_tags_url, - 'display_config' => $terminal->display_config, ], 'system_prompt' => $systemPrompt, 'guide_count' => $guideCount, diff --git a/app/Jobs/SyncTerminalConfigJob.php b/app/Jobs/SyncTerminalConfigJob.php deleted file mode 100644 index 74dd71b..0000000 --- a/app/Jobs/SyncTerminalConfigJob.php +++ /dev/null @@ -1,160 +0,0 @@ -log->update(['status' => 'syncing']); - - Log::info('开始同步终端配置', [ - 'terminal_id' => $this->terminal->id, - 'terminal_name' => $this->terminal->name, - 'log_id' => $this->log->id, - ]); - - // 模拟同步过程(因为没有真实的终端API) - // 在实际环境中,这里应该调用真实的终端API - $this->simulateSync(); - - // 更新状态为已同步 - $this->log->update([ - 'status' => 'synced', - 'synced_at' => now(), - 'error_message' => null, - ]); - - Log::info('终端配置同步成功', [ - 'terminal_id' => $this->terminal->id, - 'log_id' => $this->log->id, - ]); - - } catch (\Exception $e) { - // 记录错误日志 - Log::error('终端配置同步失败', [ - 'terminal_id' => $this->terminal->id, - 'log_id' => $this->log->id, - 'error' => $e->getMessage(), - 'attempt' => $this->attempts(), - ]); - - // 更新状态为失败 - $this->log->update([ - 'status' => 'failed', - 'error_message' => $e->getMessage(), - ]); - - // 如果还有重试次数,则重新抛出异常以触发重试 - if ($this->attempts() < $this->tries) { - throw $e; - } - } - } - - /** - * 模拟同步过程 - * - * @return void - * @throws \Exception - */ - private function simulateSync(): void - { - // 模拟网络延迟 - sleep(2); - - // 随机模拟成功或失败(90%成功率) - if (rand(1, 100) <= 10) { - throw new \Exception('模拟同步失败:网络连接超时'); - } - - // 在实际环境中,这里应该是类似这样的代码: - // $response = Http::timeout(30) - // ->post($this->terminal->sync_url, [ - // 'config' => $this->log->config_snapshot, - // ]); - // - // if (!$response->successful()) { - // throw new \Exception('同步失败:' . $response->body()); - // } - } - - /** - * 任务失败时的处理 - * - * @param \Throwable $exception - * @return void - */ - public function failed(\Throwable $exception): void - { - Log::error('终端配置同步任务最终失败', [ - 'terminal_id' => $this->terminal->id, - 'log_id' => $this->log->id, - 'error' => $exception->getMessage(), - ]); - - // 确保状态更新为失败 - $this->log->update([ - 'status' => 'failed', - 'error_message' => '同步失败(已达最大重试次数):' . $exception->getMessage(), - ]); - } - - /** - * 计算重试延迟时间(秒) - * - * @return int - */ - public function backoff(): int - { - // 指数退避:第1次重试等待10秒,第2次等待30秒 - return [10, 30][$this->attempts() - 1] ?? 60; - } -} diff --git a/app/Models/Terminal.php b/app/Models/Terminal.php index 45aeef5..f42b110 100644 --- a/app/Models/Terminal.php +++ b/app/Models/Terminal.php @@ -26,7 +26,6 @@ class Terminal extends Model 'diagram_url', 'scada_data_url', 'scada_tags_url', - 'display_config', 'is_online', 'last_online_at', ]; @@ -39,7 +38,6 @@ class Terminal extends Model protected function casts(): array { return [ - 'display_config' => 'array', 'is_online' => 'boolean', 'last_online_at' => 'datetime', ]; @@ -81,26 +79,6 @@ class Terminal extends Model return $this->hasOne(TerminalPrompt::class); } - /** - * 获取终端的同步日志 - * - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function syncLogs() - { - return $this->hasMany(TerminalSyncLog::class)->orderBy('created_at', 'desc'); - } - - /** - * 获取终端的最新同步日志 - * - * @return \Illuminate\Database\Eloquent\Relations\HasOne - */ - public function latestSyncLog() - { - return $this->hasOne(TerminalSyncLog::class)->latestOfMany(); - } - /** * 配置活动日志选项 * @@ -109,7 +87,7 @@ class Terminal extends Model public function getActivitylogOptions(): LogOptions { return LogOptions::defaults() - ->logOnly(['name', 'code', 'station_id', 'diagram_url', 'display_config']) + ->logOnly(['name', 'code', 'station_id', 'diagram_url']) ->logOnlyDirty() ->setDescriptionForEvent(fn(string $eventName) => "终端已{$eventName}"); } diff --git a/app/Models/TerminalSyncLog.php b/app/Models/TerminalSyncLog.php deleted file mode 100644 index 4ad808d..0000000 --- a/app/Models/TerminalSyncLog.php +++ /dev/null @@ -1,44 +0,0 @@ - - */ - protected $fillable = [ - 'terminal_id', - 'status', - 'config_snapshot', - 'synced_at', - 'error_message', - ]; - - /** - * 属性类型转换 - * - * @return array - */ - protected function casts(): array - { - return [ - 'config_snapshot' => 'array', - 'synced_at' => 'datetime', - ]; - } - - /** - * 获取同步日志所属的终端 - * - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ - public function terminal() - { - return $this->belongsTo(Terminal::class); - } -} diff --git a/app/Policies/TerminalPolicy.php b/app/Policies/TerminalPolicy.php index 88670f3..b59af1d 100644 --- a/app/Policies/TerminalPolicy.php +++ b/app/Policies/TerminalPolicy.php @@ -65,18 +65,6 @@ class TerminalPolicy return $user->can('terminal.delete'); } - /** - * 判断用户是否可以同步终端配置 - * - * @param User $user - * @param Terminal $terminal - * @return bool - */ - public function sync(User $user, Terminal $terminal): bool - { - return $user->can('terminal.sync'); - } - /** * 判断用户是否可以恢复已删除的终端 * diff --git a/app/Services/TerminalSyncService.php b/app/Services/TerminalSyncService.php deleted file mode 100644 index d9bb390..0000000 --- a/app/Services/TerminalSyncService.php +++ /dev/null @@ -1,112 +0,0 @@ - $terminal->id, - 'status' => 'pending', - 'config_snapshot' => $this->getConfigSnapshot($terminal), - ]); - - // 触发异步同步任务 - dispatch(new SyncTerminalConfigJob($terminal, $log)); - - return $log; - } - - /** - * 获取终端配置快照 - * - * @param Terminal $terminal - * @return array - */ - public function getConfigSnapshot(Terminal $terminal): array - { - // 加载关联数据 - $terminal->load(['knowledgeBases', 'prompt']); - - return [ - 'terminal' => [ - 'id' => $terminal->id, - 'name' => $terminal->name, - 'code' => $terminal->code, - 'ip_address' => $terminal->ip_address, - 'station_id' => $terminal->station_id, - 'diagram_url' => $terminal->diagram_url, - 'display_config' => $terminal->display_config, - ], - 'knowledge_bases' => $terminal->knowledgeBases->map(function ($kb) { - return [ - 'id' => $kb->id, - 'name' => $kb->name, - 'priority' => $kb->pivot->priority, - ]; - })->toArray(), - 'prompt' => $terminal->prompt ? [ - 'prompt_template' => $terminal->prompt->prompt_template, - 'variables' => $terminal->prompt->variables, - ] : null, - ]; - } - - /** - * 更新同步状态 - * - * @param TerminalSyncLog $log - * @param string $status - * @param string|null $errorMessage - * @return void - */ - public function updateSyncStatus(TerminalSyncLog $log, string $status, ?string $errorMessage = null): void - { - $data = ['status' => $status]; - - if ($status === 'synced') { - $data['synced_at'] = now(); - } - - if ($errorMessage) { - $data['error_message'] = $errorMessage; - } - - $log->update($data); - } - - /** - * 批量同步终端配置 - * - * @param array $terminalIds - * @return array - */ - public function batchSync(array $terminalIds): array - { - $logs = []; - - foreach ($terminalIds as $terminalId) { - $terminal = Terminal::find($terminalId); - if ($terminal) { - $logs[] = $this->syncConfiguration($terminal); - } - } - - return $logs; - } -} diff --git a/database/factories/TerminalFactory.php b/database/factories/TerminalFactory.php index 5f5eb33..a1142f7 100644 --- a/database/factories/TerminalFactory.php +++ b/database/factories/TerminalFactory.php @@ -30,12 +30,6 @@ class TerminalFactory extends Factory 'ip_address' => fake()->localIpv4(), 'station_id' => null, // 需要关联实际的线站ID 'diagram_url' => fake()->imageUrl(1920, 1080, 'diagram', true), - 'display_config' => [ - 'resolution' => fake()->randomElement(['1920x1080', '2560x1440', '3840x2160']), - 'refresh_rate' => fake()->randomElement([30, 60, 120]), - 'orientation' => fake()->randomElement(['landscape', 'portrait']), - 'brightness' => fake()->numberBetween(50, 100), - ], 'is_online' => fake()->boolean(70), // 70%概率在线 'last_online_at' => fake()->dateTimeBetween('-7 days', 'now'), ]; @@ -63,21 +57,6 @@ class TerminalFactory extends Factory ]); } - /** - * 指定终端为高分辨率配置 - */ - public function highResolution(): static - { - return $this->state(fn (array $attributes) => [ - 'display_config' => [ - 'resolution' => '3840x2160', - 'refresh_rate' => 60, - 'orientation' => 'landscape', - 'brightness' => 80, - ], - ]); - } - /** * 指定终端为生产线终端 */ diff --git a/database/migrations/2026_03_02_014623_create_terminals_table.php b/database/migrations/2026_03_02_014623_create_terminals_table.php index 886b046..65eb2f4 100644 --- a/database/migrations/2026_03_02_014623_create_terminals_table.php +++ b/database/migrations/2026_03_02_014623_create_terminals_table.php @@ -16,9 +16,11 @@ return new class extends Migration $table->string('name')->comment('终端名称'); $table->string('code', 100)->unique()->comment('终端编码'); $table->string('ip_address', 45)->nullable()->comment('IP地址'); + $table->string('mac_address', 17)->nullable()->unique()->comment('MAC地址 (AA:BB:CC:DD:EE:FF)'); $table->string('station_id', 50)->nullable()->comment('线站ID'); - $table->string('diagram_url', 500)->nullable()->comment('组态图URL'); - $table->json('display_config')->nullable()->comment('显示配置'); + $table->string('diagram_url', 500)->nullable()->comment('组态界面地址'); + $table->string('scada_data_url', 500)->nullable()->comment('网关数据查询地址'); + $table->string('scada_tags_url', 500)->nullable()->comment('网关点位定义查询地址'); $table->boolean('is_online')->default(false)->comment('在线状态'); $table->timestamp('last_online_at')->nullable()->comment('最后在线时间'); $table->timestamps(); diff --git a/database/migrations/2026_03_02_015105_create_terminal_sync_logs_table.php b/database/migrations/2026_03_02_015105_create_terminal_sync_logs_table.php deleted file mode 100644 index b9b0cbe..0000000 --- a/database/migrations/2026_03_02_015105_create_terminal_sync_logs_table.php +++ /dev/null @@ -1,44 +0,0 @@ -id(); - $table->unsignedBigInteger('terminal_id')->comment('终端ID'); - $table->enum('status', ['pending', 'syncing', 'synced', 'failed']) - ->default('pending') - ->comment('同步状态'); - $table->json('config_snapshot')->nullable()->comment('配置快照'); - $table->timestamp('synced_at')->nullable()->comment('同步时间'); - $table->text('error_message')->nullable()->comment('错误信息'); - $table->timestamps(); - - // 添加外键约束 - $table->foreign('terminal_id') - ->references('id') - ->on('terminals') - ->onDelete('cascade'); - - // 添加索引 - $table->index('status', 'idx_terminal_sync_logs_status'); - $table->index('synced_at', 'idx_terminal_sync_logs_synced_at'); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::dropIfExists('terminal_sync_logs'); - } -}; diff --git a/database/migrations/2026_03_13_010200_add_terminal_fields.php b/database/migrations/2026_03_13_010200_add_terminal_fields.php deleted file mode 100644 index 5d1d975..0000000 --- a/database/migrations/2026_03_13_010200_add_terminal_fields.php +++ /dev/null @@ -1,27 +0,0 @@ -string('mac_address', 17)->nullable()->unique()->after('ip_address') - ->comment('MAC地址 (AA:BB:CC:DD:EE:FF)'); - $table->string('scada_data_url', 500)->nullable()->after('diagram_url') - ->comment('OPC UA网关数据查询地址'); - $table->string('scada_tags_url', 500)->nullable()->after('scada_data_url') - ->comment('OPC UA网关点位定义查询地址'); - }); - } - - public function down(): void - { - Schema::table('terminals', function (Blueprint $table) { - $table->dropColumn(['mac_address', 'scada_data_url', 'scada_tags_url']); - }); - } -}; diff --git a/database/seeders/PermissionSeeder.php b/database/seeders/PermissionSeeder.php index 78549e4..ea09395 100644 --- a/database/seeders/PermissionSeeder.php +++ b/database/seeders/PermissionSeeder.php @@ -38,8 +38,6 @@ class PermissionSeeder extends Seeder 'terminal.create' => '创建终端', 'terminal.update' => '编辑终端', 'terminal.delete' => '删除终端', - 'terminal.sync' => '同步终端配置', - // 操作指引权限 'guide.view' => '查看指引', 'guide.create' => '创建指引', @@ -127,7 +125,6 @@ class PermissionSeeder extends Seeder 'terminal.create', 'terminal.update', 'terminal.delete', - 'terminal.sync', // 操作指引 'guide.view', diff --git a/database/seeders/TerminalSeeder.php b/database/seeders/TerminalSeeder.php index ad7613f..0765e86 100644 --- a/database/seeders/TerminalSeeder.php +++ b/database/seeders/TerminalSeeder.php @@ -38,13 +38,6 @@ class TerminalSeeder extends Seeder 'ip_address' => $ipAddress, 'station_id' => $beamline, 'diagram_url' => 'https://ssrf.9z.work/scada/demo.html', - 'display_config' => [ - 'resolution' => '3840x2160', - 'refresh_rate' => 60, - 'orientation' => 'landscape', - 'brightness' => 80, - 'touch_enabled' => true, - ], 'is_online' => in_array($beamline, ['BL02U1', 'BL07U', 'BL08U', 'BL13U', 'BL15U']), 'last_online_at' => in_array($beamline, ['BL02U1', 'BL07U', 'BL08U', 'BL13U', 'BL15U']) ? now() diff --git a/tests/Feature/TerminalResourceTest.php b/tests/Feature/TerminalResourceTest.php index 95e11a3..2a14edb 100644 --- a/tests/Feature/TerminalResourceTest.php +++ b/tests/Feature/TerminalResourceTest.php @@ -63,10 +63,6 @@ class TerminalResourceTest extends TestCase 'ip_address' => '192.168.1.100', 'station_id' => 1, 'diagram_url' => 'https://example.com/diagram.html', - 'display_config' => [ - 'resolution' => '1920x1080', - 'refresh_rate' => '60', - ], ]; Livewire::test(CreateTerminal::class) diff --git a/tests/Feature/TerminalSyncTest.php b/tests/Feature/TerminalSyncTest.php deleted file mode 100644 index 73532a7..0000000 --- a/tests/Feature/TerminalSyncTest.php +++ /dev/null @@ -1,280 +0,0 @@ -syncService = app(TerminalSyncService::class); - } - - /** - * 测试单个终端同步 - */ - public function test_can_sync_single_terminal(): void - { - Queue::fake(); - - // 创建测试终端 - $terminal = Terminal::factory()->create([ - 'name' => '测试终端', - 'code' => 'TEST-001', - ]); - - // 执行同步 - $log = $this->syncService->syncConfiguration($terminal); - - // 断言同步日志已创建 - $this->assertInstanceOf(TerminalSyncLog::class, $log); - $this->assertEquals('pending', $log->status); - $this->assertEquals($terminal->id, $log->terminal_id); - $this->assertNotNull($log->config_snapshot); - - // 断言任务已加入队列 - Queue::assertPushed(SyncTerminalConfigJob::class, function ($job) use ($terminal, $log) { - return $job->terminal->id === $terminal->id - && $job->log->id === $log->id; - }); - } - - /** - * 测试配置快照包含完整信息 - */ - public function test_config_snapshot_contains_complete_information(): void - { - // 创建终端及关联数据 - $terminal = Terminal::factory()->create([ - 'name' => '测试终端', - 'code' => 'TEST-002', - 'ip_address' => '192.168.1.100', - 'station_id' => 1, - 'diagram_url' => 'https://example.com/diagram.html', - 'display_config' => ['resolution' => '1920x1080'], - ]); - - // 创建知识库关联 - $kb1 = KnowledgeBase::factory()->create(['name' => '知识库1']); - $kb2 = KnowledgeBase::factory()->create(['name' => '知识库2']); - $terminal->knowledgeBases()->attach($kb1->id, ['priority' => 1]); - $terminal->knowledgeBases()->attach($kb2->id, ['priority' => 2]); - - // 创建提示词 - TerminalPrompt::factory()->create([ - 'terminal_id' => $terminal->id, - 'prompt_template' => '你好,{user}', - 'variables' => ['user' => 'string'], - ]); - - // 获取配置快照 - $snapshot = $this->syncService->getConfigSnapshot($terminal); - - // 断言快照包含终端信息 - $this->assertArrayHasKey('terminal', $snapshot); - $this->assertEquals('测试终端', $snapshot['terminal']['name']); - $this->assertEquals('TEST-002', $snapshot['terminal']['code']); - $this->assertEquals('192.168.1.100', $snapshot['terminal']['ip_address']); - - // 断言快照包含知识库信息 - $this->assertArrayHasKey('knowledge_bases', $snapshot); - $this->assertCount(2, $snapshot['knowledge_bases']); - $this->assertEquals('知识库1', $snapshot['knowledge_bases'][0]['name']); - $this->assertEquals(1, $snapshot['knowledge_bases'][0]['priority']); - - // 断言快照包含提示词信息 - $this->assertArrayHasKey('prompt', $snapshot); - $this->assertEquals('你好,{user}', $snapshot['prompt']['prompt_template']); - } - - /** - * 测试批量同步 - */ - public function test_can_batch_sync_terminals(): void - { - Queue::fake(); - - // 创建多个终端 - $terminals = Terminal::factory()->count(3)->create(); - $terminalIds = $terminals->pluck('id')->toArray(); - - // 执行批量同步 - $logs = $this->syncService->batchSync($terminalIds); - - // 断言创建了3个同步日志 - $this->assertCount(3, $logs); - - // 断言每个终端都有同步日志 - foreach ($terminals as $terminal) { - $this->assertDatabaseHas('terminal_sync_logs', [ - 'terminal_id' => $terminal->id, - 'status' => 'pending', - ]); - } - - // 断言任务已加入队列 - Queue::assertPushed(SyncTerminalConfigJob::class, 3); - } - - /** - * 测试同步状态更新 - */ - public function test_can_update_sync_status(): void - { - $terminal = Terminal::factory()->create(); - $log = TerminalSyncLog::create([ - 'terminal_id' => $terminal->id, - 'status' => 'pending', - 'config_snapshot' => [], - ]); - - // 更新为同步中 - $this->syncService->updateSyncStatus($log, 'syncing'); - $this->assertEquals('syncing', $log->fresh()->status); - - // 更新为已同步 - $this->syncService->updateSyncStatus($log, 'synced'); - $log->refresh(); - $this->assertEquals('synced', $log->status); - $this->assertNotNull($log->synced_at); - - // 更新为失败 - $this->syncService->updateSyncStatus($log, 'failed', '测试错误'); - $log->refresh(); - $this->assertEquals('failed', $log->status); - $this->assertEquals('测试错误', $log->error_message); - } - - /** - * 测试同步任务成功执行 - */ - public function test_sync_job_executes_successfully(): void - { - $terminal = Terminal::factory()->create(); - $log = TerminalSyncLog::create([ - 'terminal_id' => $terminal->id, - 'status' => 'pending', - 'config_snapshot' => [], - ]); - - // 执行任务 - $job = new SyncTerminalConfigJob($terminal, $log); - $job->handle(); - - // 断言状态更新为已同步 - $log->refresh(); - $this->assertEquals('synced', $log->status); - $this->assertNotNull($log->synced_at); - $this->assertNull($log->error_message); - } - - /** - * 测试同步失败处理 - */ - public function test_sync_job_handles_failure(): void - { - $terminal = Terminal::factory()->create(); - $log = TerminalSyncLog::create([ - 'terminal_id' => $terminal->id, - 'status' => 'pending', - 'config_snapshot' => [], - ]); - - $job = new SyncTerminalConfigJob($terminal, $log); - - // 模拟失败(通过调用failed方法) - $exception = new \Exception('测试同步失败'); - $job->failed($exception); - - // 断言状态更新为失败 - $log->refresh(); - $this->assertEquals('failed', $log->status); - $this->assertStringContainsString('测试同步失败', $log->error_message); - } - - /** - * 测试同步历史记录 - */ - public function test_can_view_sync_history(): void - { - $terminal = Terminal::factory()->create(); - - // 创建多条同步记录 - TerminalSyncLog::create([ - 'terminal_id' => $terminal->id, - 'status' => 'synced', - 'config_snapshot' => [], - 'synced_at' => now()->subHours(2), - 'created_at' => now()->subHours(2), - ]); - - TerminalSyncLog::create([ - 'terminal_id' => $terminal->id, - 'status' => 'failed', - 'config_snapshot' => [], - 'error_message' => '网络错误', - 'created_at' => now()->subHour(), - ]); - - TerminalSyncLog::create([ - 'terminal_id' => $terminal->id, - 'status' => 'synced', - 'config_snapshot' => [], - 'synced_at' => now(), - 'created_at' => now(), - ]); - - // 获取同步历史(应该按时间倒序) - $logs = $terminal->syncLogs; - - $this->assertCount(3, $logs); - // 最新的记录应该在第一位 - $this->assertEquals('synced', $logs[0]->status); - $this->assertEquals('failed', $logs[1]->status); - $this->assertEquals('synced', $logs[2]->status); - } - - /** - * 测试获取最新同步日志 - */ - public function test_can_get_latest_sync_log(): void - { - $terminal = Terminal::factory()->create(); - - // 创建多条同步记录 - TerminalSyncLog::create([ - 'terminal_id' => $terminal->id, - 'status' => 'synced', - 'config_snapshot' => [], - 'created_at' => now()->subHours(2), - ]); - - $latestLog = TerminalSyncLog::create([ - 'terminal_id' => $terminal->id, - 'status' => 'pending', - 'config_snapshot' => [], - 'created_at' => now(), - ]); - - // 获取最新同步日志 - $result = $terminal->latestSyncLog; - - $this->assertNotNull($result); - $this->assertEquals($latestLog->id, $result->id); - $this->assertEquals('pending', $result->status); - } -}