import 'package:flutter/material.dart'; import '../../core/theme/app_colors.dart'; import '../models/approval_status.dart'; class ApprovalTimeline extends StatelessWidget { final List records; final List chain; final String currentApproverId; const ApprovalTimeline({ super.key, required this.records, required this.chain, this.currentApproverId = '', }); @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('审批进度', style: TextStyle( fontSize: 13, fontWeight: FontWeight.w600, color: AppColors.textPrimary)), const SizedBox(height: 12), ...chain.asMap().entries.map((entry) { final idx = entry.key; final approverId = entry.value; final record = records.where((r) => r.approverId == approverId).firstOrNull; final isCurrent = approverId == currentApproverId; return _buildNode(idx, chain.length, approverId, record, isCurrent); }), ], ); } Widget _buildNode(int index, int total, String approverId, ApprovalRecord? record, bool isCurrent) { final isDone = record != null && record.action == 'approve'; final isRejected = record != null && record.action == 'reject'; final isLast = index == total - 1; return IntrinsicHeight( child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Column( children: [ Container( width: 22, height: 22, decoration: BoxDecoration( color: isRejected ? AppColors.error : isDone ? AppColors.success : isCurrent ? AppColors.primary : const Color(0xFFDDDDDD), shape: BoxShape.circle, ), child: Center( child: isRejected ? const Icon(Icons.close, size: 12, color: Colors.white) : isDone ? const Icon(Icons.check, size: 12, color: Colors.white) : isCurrent ? const Text('●', style: TextStyle(color: Colors.white, fontSize: 10)) : null, ), ), if (!isLast) Container( width: 1.5, height: 36, color: isDone ? AppColors.success : const Color(0xFFDDDDDD)), ], ), const SizedBox(width: 10), Expanded( child: Padding( padding: EdgeInsets.only(bottom: isLast ? 0 : 12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( record?.approverName ?? '审批人$approverId', style: TextStyle( fontSize: 13, fontWeight: FontWeight.w500, color: isRejected ? AppColors.error : isCurrent ? AppColors.primary : AppColors.textPrimary, ), ), if (record != null && record.action != 'pending') ...[ const SizedBox(height: 2), Text( '${record.action == 'approve' ? '已通过' : '已拒绝'} · ${record.approvalTime.toString().substring(0, 16)}', style: const TextStyle(fontSize: 11, color: AppColors.textHint), ), if (record.opinion.isNotEmpty) Padding( padding: const EdgeInsets.only(top: 2), child: Text('意见:${record.opinion}', style: const TextStyle(fontSize: 11, color: AppColors.textSecondary)), ), ] else if (isCurrent) ...[ const SizedBox(height: 2), const Text('当前节点', style: TextStyle(fontSize: 11, color: AppColors.primary)), ] else ...[ const SizedBox(height: 2), const Text('待处理', style: TextStyle(fontSize: 11, color: AppColors.textHint)), ], ], ), ), ), ], ), ); } }