| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- import 'package:flutter/material.dart';
- import '../../core/theme/app_colors.dart';
- import '../models/approval_status.dart';
- class ApprovalTimeline extends StatelessWidget {
- final List<ApprovalRecord> records;
- final List<String> 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)),
- ],
- ],
- ),
- ),
- ),
- ],
- ),
- );
- }
- }
|