Files
kuaishai2/lib/features/program_detail/widgets/step_list.dart
Developer 5d28bf631b chore(project): 初始化项目基础配置文件
- 添加 CodeGraph、Android 和通用 gitignore 配置
- 创建项目元数据文件跟踪 Flutter 项目属性
- 添加 Codex AI 指导文档 AGENTS.md 说明项目架构
- 配置代码分析选项 analysis_options.yaml
- 设置 Android 应用清单权限和 Kiosk 模式配置
- 实现中英文国际化支持 AppLocalizations
- 配置 GoRouter 应用路由导航
- 创建明亮工业控制风格的主题配置 AppTheme
2026-06-04 11:19:44 +08:00

272 lines
8.9 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:flutter/material.dart';
import '../../../core/localization/app_localizations.dart';
import '../../../core/theme/app_theme.dart';
import '../../../shared/widgets/common_button.dart';
import '../../programs/models/step.dart' as models;
/// 步骤列表组件
class StepList extends StatefulWidget {
final int programId;
final List<models.Step> steps;
final int? selectedStepId;
final void Function(int?) onStepSelected;
final void Function() onAddStep;
final void Function(int oldIndex, int newIndex)? onReorder;
final void Function(List<int> stepIds)? onDeleteSteps;
const StepList({
super.key,
required this.programId,
required this.steps,
this.selectedStepId,
required this.onStepSelected,
required this.onAddStep,
this.onReorder,
this.onDeleteSteps,
});
@override
State<StepList> createState() => _StepListState();
}
class _StepListState extends State<StepList> {
final Set<int> _selectedIds = {};
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context);
final allSelected = _selectedIds.length == widget.steps.length && widget.steps.isNotEmpty;
return Container(
color: Colors.white,
child: Column(
children: [
// 标题
Container(
height: 50,
padding: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
color: AppTheme.primaryColor.withValues(alpha: 0.1),
),
child: Row(
children: [
Icon(Icons.list, color: AppTheme.primaryColor, size: 20),
const SizedBox(width: 12),
Text(
'步骤列表',
style: TextStyle(
color: AppTheme.primaryColor,
fontWeight: FontWeight.w600,
),
),
const Spacer(),
Text(
'${widget.steps.length}',
style: TextStyle(
color: AppTheme.textSecondary,
fontSize: 12,
),
),
],
),
),
// 表头
Container(
height: 40,
padding: const EdgeInsets.symmetric(horizontal: 12),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: AppTheme.idleColor.withValues(alpha: 0.2)),
),
),
child: Row(
children: [
SizedBox(
width: 40,
child: Checkbox(
value: allSelected,
onChanged: (value) {
setState(() {
if (value == true) {
_selectedIds.clear();
_selectedIds.addAll(widget.steps.map((s) => s.id!));
} else {
_selectedIds.clear();
}
});
},
),
),
SizedBox(width: 40, child: Text('#', style: TextStyle(fontSize: 12))),
Expanded(child: Text(l10n?.stepName ?? '名称', style: TextStyle(fontSize: 12))),
SizedBox(width: 60, child: Text(l10n?.position ?? '孔位', style: TextStyle(fontSize: 12))),
],
),
),
// 步骤列表(可拖拽排序)
Expanded(
child: widget.steps.isEmpty
? Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.add_circle_outline, size: 48, color: AppTheme.idleColor),
const SizedBox(height: 12),
Text('暂无步骤', style: TextStyle(color: AppTheme.textSecondary)),
],
),
)
: ReorderableListView.builder(
padding: const EdgeInsets.all(8),
itemCount: widget.steps.length,
onReorder: (oldIndex, newIndex) {
if (widget.onReorder != null) {
// 调整 newIndexReorderableListView 的特殊行为)
if (newIndex > oldIndex) newIndex -= 1;
widget.onReorder!(oldIndex, newIndex);
}
},
itemBuilder: (context, index) {
final step = widget.steps[index];
final isSelected = widget.selectedStepId == step.id || _selectedIds.contains(step.id);
return _buildStepItem(step, isSelected, index);
},
),
),
// 底部操作栏
Container(
height: 60,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
border: Border(
top: BorderSide(color: AppTheme.idleColor.withValues(alpha: 0.2)),
),
),
child: Row(
children: [
// 添加按钮
CommonButton(
text: '添加',
icon: Icons.add,
type: ButtonType.primary,
onPressed: widget.onAddStep,
),
const SizedBox(width: 12),
// 删除按钮
if (_selectedIds.isNotEmpty)
CommonButton(
text: '删除',
icon: Icons.delete,
type: ButtonType.danger,
onPressed: () => _showDeleteConfirmDialog(context),
),
],
),
),
],
),
);
}
/// 步骤项
Widget _buildStepItem(models.Step step, bool isSelected, int index) {
return Container(
key: ValueKey(step.id),
margin: const EdgeInsets.symmetric(vertical: 2),
decoration: BoxDecoration(
color: isSelected ? AppTheme.primaryLight.withValues(alpha: 0.3) : Colors.white,
borderRadius: BorderRadius.circular(4),
border: isSelected ? Border.all(color: AppTheme.primaryColor, width: 2) : null,
),
child: ListTile(
dense: true,
leading: Checkbox(
value: _selectedIds.contains(step.id),
onChanged: (value) {
setState(() {
if (value == true) {
_selectedIds.add(step.id!);
} else {
_selectedIds.remove(step.id!);
}
});
},
),
title: Row(
children: [
Container(
width: 30,
alignment: Alignment.center,
child: Text(
'${step.stepNo}',
style: TextStyle(
color: AppTheme.primaryColor,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(width: 8),
Expanded(child: Text(step.name)),
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: AppTheme.primaryColor.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(4),
),
child: Text(
step.position,
style: TextStyle(
color: AppTheme.primaryColor,
fontSize: 12,
),
),
),
],
),
trailing: Icon(Icons.drag_handle, color: AppTheme.idleColor),
onTap: () => widget.onStepSelected(step.id),
),
);
}
/// 显示删除确认对话框
void _showDeleteConfirmDialog(BuildContext context) {
final l10n = AppLocalizations.of(context);
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: Text(l10n?.confirm ?? '确认'),
content: Text(
_selectedIds.length == 1
? '确定要删除此步骤吗?'
: '确定要删除选中的 ${_selectedIds.length} 个步骤吗?',
),
actions: [
TextButton(
onPressed: () => Navigator.of(ctx).pop(),
child: Text(l10n?.cancel ?? '取消'),
),
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: AppTheme.errorColor,
foregroundColor: Colors.white,
),
onPressed: () {
Navigator.of(ctx).pop();
if (widget.onDeleteSteps != null) {
widget.onDeleteSteps!(_selectedIds.toList());
}
setState(() {
_selectedIds.clear();
});
},
child: Text(l10n?.confirm ?? '确认'),
),
],
),
);
}
}