import 'dart:math'; import 'package:flutter/material.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; int getRandomWithNum(int min, int max) { final random = Random(); return random.nextInt(max) + min; // 生成随机数 } double screenWidth(BuildContext context) { double screenWidth = MediaQuery.of(context).size.width; return screenWidth; } Future pushPage(Widget page, BuildContext context) { return Navigator.push( context, MaterialPageRoute(builder: (_) => page), ); } void present(Widget page, BuildContext context) { Navigator.of(context).push( PageRouteBuilder( pageBuilder: (context, animation, secondaryAnimation) => page, transitionDuration: Duration.zero, reverseTransitionDuration: Duration.zero, ), ); } void presentOpaque(Widget page, BuildContext context) { Navigator.of(context).push( PageRouteBuilder( opaque: false, // 允许下层透出 barrierColor: Colors.black.withOpacity(0.5), //路由遮罩色 pageBuilder: (context, animation, secondaryAnimation) => page, transitionDuration: Duration.zero, reverseTransitionDuration: Duration.zero, ), ); } class FocusHelper { static final FocusNode _emptyNode = FocusNode(); /// 延迟一帧后再移交焦点,避免不生效的问题 static void clearFocus(BuildContext context) { WidgetsBinding.instance.addPostFrameCallback((_) { FocusScope.of(context).requestFocus(_emptyNode); }); } } /// 文本样式工具类,返回 Text Widget class HhTextStyleUtils { /// 主要标题,返回 Text /// [text]: 文本内容 /// [color]: 文本颜色,默认黑色 /// [fontSize]: 字体大小,默认16.0 /// [bold]: 是否加粗,默认true static Text mainTitle( String text, { Color color = Colors.black, double fontSize = 16.0, bool bold = true, }) { return Text( text, style: TextStyle( color: color, fontSize: fontSize, fontWeight: bold ? FontWeight.bold : FontWeight.normal, ), ); } static TextStyle secondaryTitleStyle = TextStyle( color: Colors.black54, fontSize: 15.0, ); /// 次要标题,返回 Text /// [text]: 文本内容 /// [color]: 文本颜色,默认深灰 /// [fontSize]: 字体大小,默认14.0 /// [bold]: 是否加粗,默认false static Text secondaryTitle( String text, { Color color = Colors.black54, double fontSize = 14.0, bool bold = false, }) { return Text( text, style: TextStyle( color: color, fontSize: fontSize, fontWeight: bold ? FontWeight.bold : FontWeight.normal, ), ); } /// 小文字,返回 Text /// [text]: 文本内容 /// [color]: 文本颜色,默认灰色 /// [fontSize]: 字体大小,默认12.0 /// [bold]: 是否加粗,默认false static Text smallText( String text, { Color color = Colors.black54, double fontSize = 12.0, bool bold = false, }) { return Text( text, style: TextStyle( color: color, fontSize: fontSize, fontWeight: bold ? FontWeight.bold : FontWeight.normal, ), ); } } /// 版本信息模型类 class AppVersionInfo { final String versionName; // 版本名称(如 1.0.0) final String buildNumber; // 构建号(如 1) final String fullVersion; // 完整版本(如 1.0.0+1) AppVersionInfo({ required this.versionName, required this.buildNumber, required this.fullVersion, }); @override String toString() { return fullVersion; } } // 获取应用版本信息的方法 Future getAppVersion() async { try { final packageInfo = await PackageInfo.fromPlatform(); return AppVersionInfo( versionName: packageInfo.version, buildNumber: packageInfo.buildNumber, fullVersion: '${packageInfo.version}+${packageInfo.buildNumber}', ); } catch (e) { // 获取失败时返回默认值 return AppVersionInfo( versionName: '1.0.0', buildNumber: '1', fullVersion: '1.0.0+0', ); } } /// ------------------------------------------------------ /// 全局会话管理 /// ------------------------------------------------------ class SessionService { SessionService._(); static final SessionService instance = SessionService._(); String? corpinfoId; String? loginUserId; Map? loginUser; String? deptId; String? deptLevel; String? postId; String? username; String? version; String? basePath; String? isRest; List? permission; bool updateInfo = false; String? dangerJson; String? riskJson; String? departmentJsonStr; String? departmentHiddenTypeJsonStr; String? customRecordDangerJson; String? unqualifiedInspectionItemID; String? listItemNameJson; /// 如果以下任何一项为空,则跳转到登录页 void loginSession(BuildContext context) { if (corpinfoId == null || loginUserId == null || loginUser == null) { Navigator.pushReplacementNamed(context, '/login'); } } // setters void setLoginUser(Map user) => loginUser = user; void setLoginUserId(String id) => loginUserId = id; void setCorpinfoId(String id) => corpinfoId = id; void setDeptId(String id) => deptId = id; void setDeptLevel(String level) => deptLevel = level; void setPostId(String id) => postId = id; void setUsername(String name) => username = name; void setVersion(String ver) => version = ver; void setBasePath(String url) => basePath = url; void setIsRest(String rest) => isRest = rest; void setPermission(List list) => permission = list; void setUpdateInfo(bool flag) => updateInfo = flag; void setDangerWaitInfo(String json) => dangerJson = json; void setRiskWaitInfo(String json) => riskJson = json; void setDepartmentJsonStr(String json) => departmentJsonStr = json; void setCustomRecordDangerJson(String json) => customRecordDangerJson = json; void setUnqualifiedInspectionItemIDJson(String json) => unqualifiedInspectionItemID = json; void setListItemNameJson(String json) => listItemNameJson = json; } /// ------------------------------------------------------ /// 日期格式化 /// ------------------------------------------------------ String formatDate(DateTime? date, String fmt) { if (date == null) return ''; String twoDigits(int n) => n.toString().padLeft(2, '0'); final replacements = { 'yyyy': date.year.toString(), 'yy': date.year.toString().substring(2), 'MM': twoDigits(date.month), 'M': date.month.toString(), 'dd': twoDigits(date.day), 'd': date.day.toString(), 'hh': twoDigits(date.hour), 'h': date.hour.toString(), 'mm': twoDigits(date.minute), 'm': date.minute.toString(), 'ss': twoDigits(date.second), 's': date.second.toString(), }; String result = fmt; replacements.forEach((key, value) { result = result.replaceAllMapped(RegExp(key), (_) => value); }); return result; } /// ------------------------------------------------------ /// 防多次点击 /// ------------------------------------------------------ class ClickUtil { ClickUtil._(); static bool _canClick = true; /// 调用示例: /// ClickUtil.noMultipleClicks(() { /* your code */ }); static void noMultipleClicks(VoidCallback fn, {int delayMs = 2000}) { if (_canClick) { _canClick = false; fn(); Future.delayed(Duration(milliseconds: delayMs), () { _canClick = true; }); } else { debugPrint('请稍后点击'); } } } void presentPage(BuildContext context, Widget page) { Navigator.push( context, MaterialPageRoute(fullscreenDialog: true, builder: (_) => page), ); } class LoadingDialogHelper { // 显示加载框 static void show({String? message}) { if (message != null) { EasyLoading.show(status: message); } else { EasyLoading.show(); } } // 隐藏加载框 static void hide() { if (EasyLoading.isShow) { EasyLoading.dismiss(); } } } /// 将秒数转换为 “HH:MM:SS” 格式 String secondsCount(dynamic seconds) { // 先尝试解析出一个 double 值 double totalSeconds; if (seconds == null) { totalSeconds = 0; } else if (seconds is num) { totalSeconds = seconds.toDouble(); } else { // seconds 是字符串或其他,尝试 parse totalSeconds = double.tryParse(seconds.toString()) ?? 0.0; } // 取整秒,向下取整 final int secs = totalSeconds.floor(); final int h = (secs ~/ 3600) % 24; final int m = (secs ~/ 60) % 60; final int s = secs % 60; // padLeft 保证两位数 final String hh = h.toString().padLeft(2, '0'); final String mm = m.toString().padLeft(2, '0'); final String ss = s.toString().padLeft(2, '0'); return '$hh:$mm:$ss'; } void printLongString(String text, {int chunkSize = 800}) { final pattern = RegExp('.{1,$chunkSize}'); // 每 chunkSize 个字符一组 for (final match in pattern.allMatches(text)) { print(match.group(0)); } } /// 表单处理 class FormUtils { /// 判断 [data] 中的 [key] 是否存在“有效值”: /// - key 不存在或值为 null -> false /// - String:去掉首尾空白后非空 -> true /// - Iterable / Map:非空 -> true /// - 其它类型(int、double、bool 等)只要不为 null 就算有值 -> true static bool hasValue(Map data, String key) { if (!data.containsKey(key)) return false; final val = data[key]; if (val == null) return false; if (val is String) { return val.trim().isNotEmpty; } if (val is Iterable || val is Map) { return val.isNotEmpty; } // 数字、布尔等其它非空即可 return true; } /// 在list中根据一个 key,value,找到对应的map static Map findMapForKeyValue(List list,String key, String value) { Map target = list.firstWhere( (item) => item[key] == value, orElse: () => {}, ); return target ?? {}; } } class NoDataWidget { static Widget show() { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Image.asset('assets/images/null.png', width: 200,), Text('暂无数据', style: TextStyle(color: Colors.grey)), ], ), ); } }