144 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Dart
		
	
	
			
		
		
	
	
			144 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Dart
		
	
	
| import 'dart:async';
 | |
| import 'package:flutter/material.dart';
 | |
| import 'package:intl/intl.dart';
 | |
| import '../../../http/ApiService.dart';
 | |
| import '../../../tools/tools.dart';
 | |
| 
 | |
| class HiddenRollWidget extends StatefulWidget {
 | |
|   /// 隐患列表数据
 | |
|   final List<Map<String, dynamic>> hiddenList;
 | |
|   /// 每行高度
 | |
|   final double rowHeight;
 | |
|   /// 同一时间可见的行数
 | |
|   final int visibleCount;
 | |
|   /// 滚动间隔
 | |
|   final Duration interval;
 | |
|   /// 点击回调,传递 HIDDEN_ID
 | |
|   final ValueChanged<String>? onItemTap;
 | |
| 
 | |
|   const HiddenRollWidget({
 | |
|     Key? key,
 | |
|     required this.hiddenList,
 | |
|     this.rowHeight = 35,
 | |
|     this.visibleCount = 5,
 | |
|     this.interval = const Duration(seconds: 3),
 | |
|     this.onItemTap,
 | |
|   }) : super(key: key);
 | |
| 
 | |
|   @override
 | |
|   _HiddenRollWidgetState createState() => _HiddenRollWidgetState();
 | |
| }
 | |
| 
 | |
| class _HiddenRollWidgetState extends State<HiddenRollWidget> {
 | |
|   late final ScrollController _ctrl;
 | |
|   late final Timer _timer;
 | |
|   int _currentIndex = 0;
 | |
| 
 | |
|   @override
 | |
|   void initState() {
 | |
|     super.initState();
 | |
|     _ctrl = ScrollController();
 | |
|     _timer = Timer.periodic(widget.interval, (_) => _scrollToNext());
 | |
|   }
 | |
| 
 | |
|   void _scrollToNext() {
 | |
|     if (!_ctrl.hasClients || widget.hiddenList.isEmpty) return;
 | |
|     _currentIndex++;
 | |
|     if (_currentIndex >= widget.hiddenList.length) {
 | |
|       _currentIndex = 0;
 | |
|       _ctrl.jumpTo(0);
 | |
|     } else {
 | |
|       _ctrl.animateTo(
 | |
|         widget.rowHeight * _currentIndex,
 | |
|         duration: const Duration(milliseconds: 400),
 | |
|         curve: Curves.easeInOut,
 | |
|       );
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   void dispose() {
 | |
|     _timer.cancel();
 | |
|     _ctrl.dispose();
 | |
|     super.dispose();
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   Widget build(BuildContext context) {
 | |
|     // 容器高度 = 行高 * 可见行数
 | |
|     return SizedBox(
 | |
|       height: widget.rowHeight * widget.visibleCount,
 | |
|       child: ListView.builder(
 | |
|         controller: _ctrl,
 | |
|         physics: const NeverScrollableScrollPhysics(),
 | |
|         itemExtent: widget.rowHeight,
 | |
|         itemCount: widget.hiddenList.length,
 | |
|         itemBuilder: (_, idx) {
 | |
|           final item = widget.hiddenList[idx];
 | |
|           // 原始时间字符串
 | |
|           String rawTime = item['CREATTIME'] ?? '';
 | |
|           DateTime? dt;
 | |
|           if (rawTime.isNotEmpty) {
 | |
|             try {
 | |
|               dt = DateTime.parse(rawTime.replaceAll('-', '/'));
 | |
|             } catch (_) {}
 | |
|           }
 | |
|           // 去除年份,仅保留 MM-dd HH:mm
 | |
|           String displayTime;
 | |
|           if (dt != null) {
 | |
|             displayTime = DateFormat('MM-dd HH:mm').format(dt);
 | |
|           } else {
 | |
|             final parts = rawTime.split(' ');
 | |
|             if (parts.length >= 2) {
 | |
|               final datePart = parts[0];
 | |
|               final timePart = parts[1];
 | |
|               final mmdd = datePart.length >= 5 ? datePart.substring(5) : datePart;
 | |
|               final hm = timePart.length >= 5 ? timePart.substring(0, 5) : timePart;
 | |
|               displayTime = '$mmdd $hm';
 | |
|             } else {
 | |
|               displayTime = rawTime;
 | |
|             }
 | |
|           }
 | |
|           // 隐患描述裁剪
 | |
|           String descr = item['HIDDENDESCR'] ?? '';
 | |
|           final displayDescr = descr.length > 10 ? '${descr.substring(0, 10)}...' : descr;
 | |
|           return InkWell(
 | |
|             onTap: () => widget.onItemTap?.call(item['HIDDEN_ID'] as String),
 | |
|             child: Padding(
 | |
|               padding: const EdgeInsets.symmetric(horizontal: 15),
 | |
|               child: Row(
 | |
|                 mainAxisAlignment: MainAxisAlignment.spaceBetween,
 | |
|                 children: [
 | |
|                   Expanded(
 | |
|                     flex: 3,
 | |
|                     child: Text(
 | |
|                       displayDescr,
 | |
|                       overflow: TextOverflow.ellipsis,
 | |
|                     ),
 | |
|                   ),
 | |
|                   Expanded(
 | |
|                     flex: 2,
 | |
|                     child: Text(
 | |
|                       item['CREATORNAME'] ?? '',
 | |
|                       textAlign: TextAlign.center,
 | |
|                       overflow: TextOverflow.ellipsis,
 | |
|                     ),
 | |
|                   ),
 | |
|                   Expanded(
 | |
|                     flex: 2,
 | |
|                     child: Text(
 | |
|                       displayTime,
 | |
|                       textAlign: TextAlign.right,
 | |
|                       overflow: TextOverflow.ellipsis,
 | |
|                     ),
 | |
|                   ),
 | |
|                 ],
 | |
|               ),
 | |
|             ),
 | |
|           );
 | |
|         },
 | |
|       ),
 | |
|     );
 | |
|   }
 | |
| }
 |