import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../core/localization/app_localizations.dart'; import '../../../core/theme/app_theme.dart'; import '../../device/providers/run_state_provider.dart'; /// 运行状态监控面板 - 暗色工业风格 /// 显示当前孔位、步骤、倒计时、进度条、参数详情 class RunStatusMonitor extends ConsumerWidget { const RunStatusMonitor({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final l10n = AppLocalizations.of(context); final runState = ref.watch(runStateProvider); if (runState.status == RunStatus.idle) { return const SizedBox.shrink(); } return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: AppTheme.cardBg, borderRadius: BorderRadius.circular(8), border: Border.all(color: AppTheme.borderSubtle, width: 1), ), child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 标题 + 程序名 Row( children: [ Text( l10n?.runningMonitor ?? '运行状态监控', style: const TextStyle( color: AppTheme.textHeading, fontSize: 15, fontWeight: FontWeight.w600, ), ), const Spacer(), Flexible( child: Text( runState.currentProgram?.name ?? '', maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle( color: AppTheme.accentPrimary, fontSize: 18, fontWeight: FontWeight.w700, ), ), ), ], ), const SizedBox(height: 14), // 进度信息横排 (孔位 / 步骤 / 剩余时间) Row( children: [ // 当前孔位 _buildInfoBlock( label: l10n?.currentHole ?? '当前孔位', value: runState.currentWell ?? '--', valueColor: AppTheme.textHeading, ), const SizedBox(width: 20), // 当前步骤 Flexible( child: _buildInfoBlock( label: l10n?.currentStep ?? '当前步骤', value: '${l10n?.stepNo ?? '步骤'} ${runState.currentStepIndex + 1}', subValue: runState.currentStep?.name ?? '--', valueColor: AppTheme.accentInfo, ), ), const SizedBox(width: 20), // 剩余时间 _buildInfoBlock( label: l10n?.remainingTime ?? '剩余时间', value: runState.formattedRemainingTime, valueColor: AppTheme.textHeading, valueSize: 20, ), ], ), const SizedBox(height: 14), // 总进度条 _buildProgressBar(l10n, runState), const SizedBox(height: 14), // 步骤参数 if (runState.currentStep != null) _buildStepParams(l10n, runState.currentStep!), ], ), ), ); } /// 信息块 Widget _buildInfoBlock({ required String label, required String value, String? subValue, Color valueColor = AppTheme.textHeading, double valueSize = 16, }) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label, style: const TextStyle( color: AppTheme.textTertiary, fontSize: 11, ), ), const SizedBox(height: 2), Text( value, style: TextStyle( color: valueColor, fontSize: valueSize, fontWeight: FontWeight.w600, fontFamily: 'monospace', ), ), if (subValue != null) ...[ const SizedBox(height: 2), Text( subValue, style: const TextStyle( color: AppTheme.textSecondary, fontSize: 11, ), ), ], ], ); } /// 进度条 Widget _buildProgressBar(AppLocalizations? l10n, RunState runState) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Text( l10n?.progress ?? '总进度', style: const TextStyle( color: AppTheme.textTertiary, fontSize: 11, ), ), const Spacer(), Text( runState.formattedProgress, style: const TextStyle( color: AppTheme.accentPrimary, fontSize: 12, fontWeight: FontWeight.w600, fontFamily: 'monospace', ), ), ], ), const SizedBox(height: 6), ClipRRect( borderRadius: BorderRadius.circular(4), child: LinearProgressIndicator( value: runState.progress, minHeight: 8, backgroundColor: const Color(0xFF1E293B), valueColor: AlwaysStoppedAnimation(AppTheme.accentPrimary), ), ), ], ); } /// 步骤参数详情 Widget _buildStepParams(AppLocalizations? l10n, dynamic step) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( l10n?.stepParams ?? '步骤参数', style: const TextStyle( color: AppTheme.textTertiary, fontSize: 11, ), ), const SizedBox(height: 8), Row( children: [ _buildInfoBlock( label: l10n?.speed ?? '速度', value: '${step.speed} ${l10n?.speedLevel ?? '档'}', ), const SizedBox(width: 20), _buildInfoBlock( label: l10n?.duration ?? '持续时间', value: '${step.mixTime} s', ), const SizedBox(width: 20), _buildInfoBlock( label: l10n?.sampleVolume ?? '样品体积', value: '${step.volume} μL', ), ], ), ], ); } }