import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:file_picker/file_picker.dart'; import 'dart:io'; import '../../../core/localization/app_localizations.dart'; import '../../../core/theme/app_theme.dart'; import '../../../shared/widgets/common_button.dart'; import '../models/program.dart'; import '../providers/programs_provider.dart'; import '../widgets/program_form_dialog.dart'; import '../services/program_import_service.dart'; /// 程序管理页面 class ProgramsPage extends ConsumerStatefulWidget { const ProgramsPage({super.key}); @override ConsumerState createState() => _ProgramsPageState(); } class _ProgramsPageState extends ConsumerState { final Set _selectedIds = {}; @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context); final programsState = ref.watch(programsProvider); return Scaffold( body: Container( color: AppTheme.backgroundColor, child: Column( children: [ // 顶部导航栏 Container( height: 60, padding: const EdgeInsets.symmetric(horizontal: 24), decoration: BoxDecoration( color: Colors.white, boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.1), blurRadius: 4, offset: const Offset(0, 2), ), ], ), child: Row( children: [ // 返回按钮 IconButton( icon: const Icon(Icons.arrow_back), onPressed: () => context.go('/'), ), const SizedBox(width: 16), Text( l10n?.programs ?? '程序管理', style: const TextStyle( fontSize: 20, fontWeight: FontWeight.w600, ), ), const Spacer(), // 新增按钮 CommonButton( text: l10n?.addProgram ?? '新增', icon: Icons.add, type: ButtonType.primary, onPressed: () => _showAddDialog(context, ref), ), const SizedBox(width: 12), // 导入按钮 CommonButton( text: l10n?.importProgram ?? '导入', icon: Icons.file_upload, type: ButtonType.secondary, onPressed: () => _importPrograms(context, ref), ), ], ), ), // 程序列表表格 Expanded( child: programsState.isLoading ? const Center(child: CircularProgressIndicator()) : programsState.programs.isEmpty ? Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.folder_open, size: 64, color: AppTheme.idleColor, ), const SizedBox(height: 16), Text( l10n?.noData ?? '暂无数据', style: TextStyle( color: AppTheme.textSecondary, fontSize: 16, ), ), ], ), ) : Container( margin: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.1), blurRadius: 8, offset: const Offset(2, 2), ), ], ), child: Column( children: [ // 表头 _buildTableHeader(l10n, programsState.programs), // 表格内容 Expanded( child: ListView.builder( itemCount: programsState.programs.length, itemBuilder: (context, index) { final program = programsState.programs[index]; final isSelected = _selectedIds.contains(program.id); return _buildTableRow( context, ref, l10n, program, isSelected, index == programsState.programs.length - 1, ); }, ), ), ], ), ), ), // 底部操作栏 if (programsState.programs.isNotEmpty) Container( height: 60, padding: const EdgeInsets.symmetric(horizontal: 24), decoration: BoxDecoration( color: Colors.white, boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.1), blurRadius: 4, offset: const Offset(0, -2), ), ], ), child: Row( children: [ Text( '${l10n?.selected ?? '已选择'}: ${_selectedIds.length}', style: TextStyle(color: AppTheme.textSecondary), ), const Spacer(), if (_selectedIds.isNotEmpty) CommonButton( text: l10n?.deleteProgram ?? '删除', icon: Icons.delete, type: ButtonType.danger, onPressed: () => _showDeleteConfirmDialog( context, ref, l10n, _selectedIds.toList(), ), ), ], ), ), ], ), ), ); } /// 表头 Widget _buildTableHeader(AppLocalizations? l10n, List programs) { final allSelected = _selectedIds.length == programs.length && programs.isNotEmpty; return Container( height: 50, padding: const EdgeInsets.symmetric(horizontal: 16), decoration: BoxDecoration( color: AppTheme.primaryColor.withValues(alpha: 0.1), borderRadius: const BorderRadius.vertical(top: Radius.circular(12)), ), child: Row( children: [ // 复选框 SizedBox( width: 50, child: Checkbox( value: allSelected, onChanged: (value) { setState(() { if (value == true) { _selectedIds.clear(); _selectedIds.addAll(programs.map((p) => p.id!)); } else { _selectedIds.clear(); } }); }, ), ), // 编号 SizedBox( width: 100, child: Text( l10n?.programCode ?? '编号', style: TextStyle( fontWeight: FontWeight.w600, color: AppTheme.textPrimary, ), ), ), // 名称 Expanded( flex: 2, child: Text( l10n?.programName ?? '名称', style: TextStyle( fontWeight: FontWeight.w600, color: AppTheme.textPrimary, ), ), ), // 创建时间 Expanded( child: Text( l10n?.createTime ?? '创建时间', style: TextStyle( fontWeight: FontWeight.w600, color: AppTheme.textPrimary, ), ), ), // 状态 SizedBox( width: 80, child: Text( '状态', style: TextStyle( fontWeight: FontWeight.w600, color: AppTheme.textPrimary, ), ), ), // 操作 SizedBox( width: 150, child: Text( l10n?.detail ?? '操作', style: TextStyle( fontWeight: FontWeight.w600, color: AppTheme.textPrimary, ), textAlign: TextAlign.center, ), ), ], ), ); } /// 表格行 Widget _buildTableRow( BuildContext context, WidgetRef ref, AppLocalizations? l10n, Program program, bool isSelected, bool isLast, ) { return Container( height: 50, padding: const EdgeInsets.symmetric(horizontal: 16), decoration: BoxDecoration( color: isSelected ? AppTheme.primaryLight.withValues(alpha: 0.2) : null, border: isLast ? null : Border( bottom: BorderSide( color: AppTheme.idleColor.withValues(alpha: 0.2), ), ), ), child: Row( children: [ // 复选框 SizedBox( width: 50, child: Checkbox( value: isSelected, onChanged: (value) { setState(() { if (value == true) { _selectedIds.add(program.id!); } else { _selectedIds.remove(program.id!); } }); }, ), ), // 编号 SizedBox( width: 100, child: Text( program.code, style: TextStyle(color: AppTheme.textPrimary), ), ), // 名称 Expanded( flex: 2, child: Text( program.name, style: TextStyle(color: AppTheme.textPrimary), ), ), // 创建时间 Expanded( child: Text( program.createdAt, style: TextStyle(color: AppTheme.textSecondary), ), ), // 状态 SizedBox( width: 80, child: Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: program.status == 1 ? AppTheme.successColor.withValues(alpha: 0.1) : AppTheme.idleColor.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(4), ), child: Text( program.status == 1 ? '启用' : '停用', style: TextStyle( color: program.status == 1 ? AppTheme.successColor : AppTheme.idleColor, fontSize: 12, ), textAlign: TextAlign.center, ), ), ), // 操作按钮 SizedBox( width: 150, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ IconButton( icon: const Icon(Icons.edit, size: 20), color: AppTheme.primaryColor, onPressed: () => _showEditDialog(context, ref, program), ), IconButton( icon: const Icon(Icons.delete, size: 20), color: AppTheme.errorColor, onPressed: () => _showDeleteConfirmDialog( context, ref, l10n, [program.id!], ), ), IconButton( icon: const Icon(Icons.visibility, size: 20), color: AppTheme.textSecondary, onPressed: () => context.go('/programs/${program.id}'), ), ], ), ), ], ), ); } /// 显示新增对话框 void _showAddDialog(BuildContext context, WidgetRef ref) { showDialog( context: context, builder: (context) => const ProgramFormDialog(), ); } /// 导入程序 Future _importPrograms(BuildContext context, WidgetRef ref) async { try { // 选择文件 final result = await FilePicker.platform.pickFiles( type: FileType.custom, allowedExtensions: ['json'], allowMultiple: false, ); if (result == null || result.files.isEmpty) { return; } final file = result.files.first; if (file.path == null) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('无法读取文件'), backgroundColor: AppTheme.errorColor, ), ); return; } // 读取文件内容 final jsonContent = await File(file.path!).readAsString(); // 导入程序 final importedCount = await ProgramImportService.instance.importFromJson(jsonContent); // 刷新程序列表 ref.read(programsProvider.notifier).loadPrograms(); // 显示结果 ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('成功导入 $importedCount 个程序'), backgroundColor: importedCount > 0 ? AppTheme.successColor : AppTheme.warningColor, ), ); } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('导入失败: ${e.toString()}'), backgroundColor: AppTheme.errorColor, ), ); } } /// 显示编辑对话框 void _showEditDialog(BuildContext context, WidgetRef ref, Program program) { showDialog( context: context, builder: (context) => ProgramFormDialog(program: program), ); } /// 显示删除确认对话框 void _showDeleteConfirmDialog( BuildContext context, WidgetRef ref, AppLocalizations? l10n, List ids, ) { showDialog( context: context, builder: (context) => AlertDialog( title: Text(l10n?.confirm ?? '确认'), content: Text( ids.length == 1 ? '确定要删除此程序吗?' : '确定要删除选中的 ${ids.length} 个程序吗?', ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: Text(l10n?.cancel ?? '取消'), ), ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: AppTheme.errorColor, foregroundColor: Colors.white, ), onPressed: () async { final notifier = ref.read(programsProvider.notifier); await notifier.deletePrograms(ids); setState(() { _selectedIds.removeAll(ids); }); Navigator.of(context).pop(); }, child: Text(l10n?.confirm ?? '确认'), ), ], ), ); } }