diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig index 592ceee..ec97fc6 100644 --- a/ios/Flutter/Debug.xcconfig +++ b/ios/Flutter/Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig index 592ceee..c4855bf 100644 --- a/ios/Flutter/Release.xcconfig +++ b/ios/Flutter/Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 0bf5f31..dc77a28 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -9,8 +9,10 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; + 35D44C7FD343AFDEF38CE768 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1452DBDD84CD21A497A545F7 /* Pods_RunnerTests.framework */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 77B97B54C97C64E60F90748C /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9F62E50C3C8FC174C5F55CBC /* Pods_Runner.framework */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; @@ -40,11 +42,14 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 0097BD3248D8B72245BEB567 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 1452DBDD84CD21A497A545F7 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 471FAAD7B3A41D95705DBC8A /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; @@ -55,6 +60,11 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 9F62E50C3C8FC174C5F55CBC /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + C3B8FEABBB9C59CC447A93CE /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + CB7336689B2748DD792AF4A8 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + E07AF9B4433E188ABB668EAB /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + F142A595A7801DD8FCFA8F0E /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -62,12 +72,35 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 77B97B54C97C64E60F90748C /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9A79291EF429202CAC51B2B3 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 35D44C7FD343AFDEF38CE768 /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 125261287552F05BC35DCF6E /* Pods */ = { + isa = PBXGroup; + children = ( + CB7336689B2748DD792AF4A8 /* Pods-Runner.debug.xcconfig */, + 471FAAD7B3A41D95705DBC8A /* Pods-Runner.release.xcconfig */, + E07AF9B4433E188ABB668EAB /* Pods-Runner.profile.xcconfig */, + 0097BD3248D8B72245BEB567 /* Pods-RunnerTests.debug.xcconfig */, + F142A595A7801DD8FCFA8F0E /* Pods-RunnerTests.release.xcconfig */, + C3B8FEABBB9C59CC447A93CE /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; 331C8082294A63A400263BE5 /* RunnerTests */ = { isa = PBXGroup; children = ( @@ -76,6 +109,15 @@ path = RunnerTests; sourceTree = ""; }; + 41DC4FCE86590B2FF769CA12 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 9F62E50C3C8FC174C5F55CBC /* Pods_Runner.framework */, + 1452DBDD84CD21A497A545F7 /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -94,6 +136,8 @@ 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, 331C8082294A63A400263BE5 /* RunnerTests */, + 125261287552F05BC35DCF6E /* Pods */, + 41DC4FCE86590B2FF769CA12 /* Frameworks */, ); sourceTree = ""; }; @@ -128,8 +172,10 @@ isa = PBXNativeTarget; buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( + 7EB6F8425B893287783D984F /* [CP] Check Pods Manifest.lock */, 331C807D294A63A400263BE5 /* Sources */, 331C807F294A63A400263BE5 /* Resources */, + 9A79291EF429202CAC51B2B3 /* Frameworks */, ); buildRules = ( ); @@ -145,12 +191,15 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + A63797C3EAC37C8DDBC69E97 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + AD2261CB40DC2B31B58C85D5 /* [CP] Embed Pods Frameworks */, + E52A55AB384D528E01BB1DB0 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -238,6 +287,28 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; + 7EB6F8425B893287783D984F /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -253,6 +324,62 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; + A63797C3EAC37C8DDBC69E97 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + AD2261CB40DC2B31B58C85D5 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + E52A55AB384D528E01BB1DB0 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -379,6 +506,7 @@ }; 331C8088294A63A400263BE5 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 0097BD3248D8B72245BEB567 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -396,6 +524,7 @@ }; 331C8089294A63A400263BE5 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = F142A595A7801DD8FCFA8F0E /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -411,6 +540,7 @@ }; 331C808A294A63A400263BE5 /* Profile */ = { isa = XCBuildConfiguration; + baseConfigurationReference = C3B8FEABBB9C59CC447A93CE /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata index 1d526a1..21a3cc1 100644 --- a/ios/Runner.xcworkspace/contents.xcworkspacedata +++ b/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/lib/Custom/dashed_line_text.dart b/lib/Custom/dashed_line_text.dart new file mode 100644 index 0000000..2eeb25c --- /dev/null +++ b/lib/Custom/dashed_line_text.dart @@ -0,0 +1,87 @@ +import 'package:flutter/material.dart'; + +class DashedLineText extends StatelessWidget { + final String text; + final TextStyle? textStyle; + final Color lineColor; + final double strokeWidth; + final double dashLength; + + const DashedLineText({ + super.key, + required this.text, + this.textStyle, + this.lineColor = Colors.blue, + this.strokeWidth = 1.0, + this.dashLength = 3.0, + }); + + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: CustomPaint( + painter: _DashedLinePainter( + color: lineColor, + strokeWidth: strokeWidth, + dashLength: dashLength, + ), + size: const Size(double.infinity, 1), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: Text( + text, + style: textStyle ?? Theme.of(context).textTheme.bodyMedium, + ), + ), + Expanded( + child: CustomPaint( + painter: _DashedLinePainter( + color: lineColor, + strokeWidth: strokeWidth, + dashLength: dashLength, + ), + size: const Size(double.infinity, 1), + ), + ), + ], + ); + } +} + +class _DashedLinePainter extends CustomPainter { + final Color color; + final double strokeWidth; + final double dashLength; + + const _DashedLinePainter({ + required this.color, + required this.strokeWidth, + required this.dashLength, + }); + + @override + void paint(Canvas canvas, Size size) { + final paint = Paint() + ..color = color + ..strokeWidth = strokeWidth + ..style = PaintingStyle.stroke; + + double startX = 0; + while (startX < size.width) { + canvas.drawLine( + Offset(startX, size.height / 2), + Offset(startX + dashLength, size.height / 2), + paint, + ); + startX += dashLength * 2; // 间隔 = 线段长度 + 空白长度 + } + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) => false; +} \ No newline at end of file diff --git a/lib/Custom/read_only_table.dart b/lib/Custom/read_only_table.dart new file mode 100644 index 0000000..4edef18 --- /dev/null +++ b/lib/Custom/read_only_table.dart @@ -0,0 +1,122 @@ +import 'package:flutter/material.dart'; +class ReadOnlyTable extends StatelessWidget { + final List headers; + final List? columnWidths; + final List> data; + /// 回调,点击“操作”列时会触发,传入行索引 + final void Function(int rowIndex)? onTapAction; + + const ReadOnlyTable({ + Key? key, + required this.headers, + required this.data, + this.columnWidths, + this.onTapAction, + }) : assert(columnWidths == null || columnWidths.length == headers.length), + super(key: key); + + @override + Widget build(BuildContext context) { + const cellPadding = EdgeInsets.all(8.0); + final headerStyle = const TextStyle(fontWeight: FontWeight.bold); + + // 表头 + Widget buildHeader() { + return Table( + border: TableBorder.all(color: Colors.black26), + columnWidths: columnWidths != null + ? Map.fromIterables( + List.generate(headers.length, (i) => i), + columnWidths!, + ) + : null, + defaultVerticalAlignment: TableCellVerticalAlignment.middle, + children: [ + TableRow( + decoration: const BoxDecoration(color: Color(0xFFE0E0E0)), + children: headers + .map((h) => Padding( + padding: cellPadding, + child: Text(h, style: headerStyle), + )) + .toList(), + ), + ], + ); + } + + // 有数据的表格 + Widget buildDataTable() { + return Table( + border: TableBorder.all(color: Colors.black26), + columnWidths: columnWidths != null + ? Map.fromIterables( + List.generate(headers.length, (i) => i), + columnWidths!, + ) + : null, + defaultVerticalAlignment: TableCellVerticalAlignment.middle, + children: [ + for (int row = 0; row < data.length; row++) + TableRow( + children: List.generate(headers.length, (col) { + final text = col < data[row].length ? data[row][col] : ''; + + // 如果是最后一列(操作列),并且提供了回调,则渲染为可点击蓝色文本 + // if (col == headers.length - 1 && onTapAction != null) { + // return Padding( + // padding: cellPadding, + // child: GestureDetector( + // onTap: () => onTapAction!(row), + // child: Text( + // text, + // style: const TextStyle( + // color: Colors.blue, + // ), + // ), + // ), + // ); + // } + + return Padding( + padding: cellPadding, + child: Text(text, softWrap: true), + ); + }), + ), + ], + ); + } + + // 主体 + if (data.isEmpty) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + buildHeader(), + Container( + height: 50, + alignment: Alignment.center, + decoration: const BoxDecoration( + border: Border( + left: BorderSide(color: Colors.black26, width: 1), + right: BorderSide(color: Colors.black26, width: 1), + bottom: BorderSide(color: Colors.black26, width: 1), + ), + ), + child: const Text('暂无更多数据'), + ), + ], + ); + } else { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + buildHeader(), + buildDataTable(), + ], + ); + } + } +} + diff --git a/lib/home/adaptive_list_item.dart b/lib/home/adaptive_list_item.dart new file mode 100644 index 0000000..1e68334 --- /dev/null +++ b/lib/home/adaptive_list_item.dart @@ -0,0 +1,77 @@ +import 'package:flutter/material.dart'; + +class AdaptiveListItem extends StatelessWidget { + final String title; + final List> items; + final List? actions; + + const AdaptiveListItem({ + super.key, + required this.title, + required this.items, + required this.actions, + }); + + @override + Widget build(BuildContext context) { + // 按 2 个一组切片 + final List>> rows = []; + for (var i = 0; i < items.length; i += 2) { + rows.add(items.sublist(i, i + 2 > items.length ? items.length : i + 2)); + } + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // 标题 + Text( + title, + style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16), + ), + const SizedBox(height: 8), + + // 每一行最多两个 + ...rows.map((rowItems) { + return Padding( + padding: const EdgeInsets.only(bottom: 8), + child: _buildItemRow(rowItems[0]), + ); + }), + if (actions!.isNotEmpty) + Column( + spacing: 15, + children: [ + Divider(height: 1,), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: actions!, + ) + ], + ) + + ], + ); + } + + Widget _buildItemRow(Map item) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "${item['title']}: ", + style: const TextStyle( + fontWeight: FontWeight.w500, + color: Colors.grey, + ), + ), + Expanded( + child: Text( + item['value'] ?? '', + style: const TextStyle(fontWeight: FontWeight.w500), + softWrap: true, + ), + ), + ], + ); + } +} diff --git a/lib/home/danger_edit_page.dart b/lib/home/danger_edit_page.dart new file mode 100644 index 0000000..1aaf1f4 --- /dev/null +++ b/lib/home/danger_edit_page.dart @@ -0,0 +1,33 @@ +import 'package:flutter/material.dart'; +import 'package:qhdkfq_regulatory_flutter/Custom/dashed_line_text.dart'; +import 'package:qhdkfq_regulatory_flutter/tools/h_colors.dart'; +import 'package:qhdkfq_regulatory_flutter/tools/my_appbar.dart'; + +class DangerEditPage extends StatefulWidget { + const DangerEditPage({super.key}); + + @override + State createState() => _DangerEditPageState(); +} + +class _DangerEditPageState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: MyAppbar(title: "编辑"), + body: SafeArea(child: ListView( + padding: EdgeInsets.symmetric(horizontal: 15), + children: [ + SizedBox(height: 20,), + DashedLineText( + text: "基本信息", + lineColor: h_mainBlueColor(), + textStyle: TextStyle(fontSize: 16, color: h_mainBlueColor()), + ), + ], + )), + ); + } +} + diff --git a/lib/home/department_picker.dart b/lib/home/department_picker.dart new file mode 100644 index 0000000..98851c3 --- /dev/null +++ b/lib/home/department_picker.dart @@ -0,0 +1,152 @@ +import 'package:flutter/material.dart'; + +class Category { + final String id; + final String title; + final List children; + + Category({ + required this.id, + required this.title, + this.children = const [], + }); +} + +class DepartmentPicker extends StatefulWidget { + final List data; + final String? initialSelectedId; + final Set? initialExpandedSet; + final ValueChanged onSelected; + + const DepartmentPicker({ + Key? key, + required this.data, + this.initialSelectedId, + this.initialExpandedSet, + required this.onSelected, + }) : super(key: key); + + @override + _DepartmentPickerState createState() => _DepartmentPickerState(); +} + +class _DepartmentPickerState extends State { + late String? selectedId; + late Set expandedSet; + + @override + void initState() { + super.initState(); + selectedId = widget.initialSelectedId; + expandedSet = Set.from(widget.initialExpandedSet ?? {}); + } + + Widget _buildRow(Category cat, int indent) { + final bool hasChildren = cat.children.isNotEmpty; + final bool isExpanded = expandedSet.contains(cat.id); + final bool isSelected = cat.id == selectedId; + + return Column( + children: [ + InkWell( + onTap: () { + setState(() { + if (hasChildren) { + if (isExpanded) { + expandedSet.remove(cat.id); + } else { + expandedSet.add(cat.id); + } + } + selectedId = cat.id; + }); + }, + child: Container( + color: Colors.white, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + // 左侧缩进 + SizedBox(width: 16.0 * indent), + // 展开/占位图标 + SizedBox( + width: 24, + child: hasChildren + ? Icon( + isExpanded ? Icons.arrow_drop_down : Icons.arrow_right_outlined, + size: 30, + color: Colors.grey[600], + ) + : const SizedBox.shrink(), + ), + const SizedBox(width: 8), + // 标题 + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 12), + child: Text(cat.title), + ), + ), + // 单选圈保持右侧对齐 + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Icon( + isSelected + ? Icons.radio_button_checked + : Icons.radio_button_unchecked, + color: Colors.blue, + ), + ), + ], + ), + ), + ), + if (hasChildren && isExpanded) + ...cat.children.map((c) => _buildRow(c, indent + 1)), + // const Divider(height: 1), + ], + ); + } + + @override + Widget build(BuildContext context) { + return Container( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height * 0.7, + color: Colors.transparent, + child: Column( + children: [ + // 顶部操作栏 + Container( + color: Colors.white, + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + GestureDetector( + onTap: () => Navigator.of(context).pop(), + child: const Text('取消', style: TextStyle(fontSize: 16)), + ), + GestureDetector( + onTap: () => Navigator.of(context).pop(selectedId), + child: const Text('确定', style: TextStyle(fontSize: 16, color: Colors.blue),), + ), + ], + ), + ), + const Divider(height: 1), + // 列表区 + Expanded( + child: Container( + color: Colors.white, + child: ListView.builder( + itemCount: widget.data.length, + itemBuilder: (ctx, idx) => _buildRow(widget.data[idx], 0), + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/home/help_detail_page.dart b/lib/home/help_detail_page.dart new file mode 100644 index 0000000..c501613 --- /dev/null +++ b/lib/home/help_detail_page.dart @@ -0,0 +1,157 @@ +import 'package:flutter/material.dart'; +import 'package:qhdkfq_regulatory_flutter/Custom/dashed_line_text.dart'; +import 'package:qhdkfq_regulatory_flutter/tools/h_colors.dart'; +import 'package:qhdkfq_regulatory_flutter/tools/my_appbar.dart'; + +import '../Custom/read_only_table.dart'; + +class HelpDetailPage extends StatefulWidget { + const HelpDetailPage({super.key}); + + @override + State createState() => _HelpDetailPageState(); +} + +class _HelpDetailPageState extends State { + final List _infoList = [ + InfoModel("公司名称", "测试1"), + InfoModel("地址", "测试2"), + InfoModel("姓名", "测试3"), + InfoModel("联系电话", "测试4"), + InfoModel("编号", "测试5"), + InfoModel("场所", "测试6"), + InfoModel("类型", "测试7"), + InfoModel("帮扶时间", "测试8"), + InfoModel("现场照片", "测试9"), + ]; + + @override + void initState() { + // TODO: implement initState + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: MyAppbar(title: "帮扶记录详情"), + body: SafeArea( + child: ListView( + padding: EdgeInsets.symmetric(horizontal: 15), + children: [ + SizedBox(height: 20), + DashedLineText( + text: "基本信息", + lineColor: h_mainBlueColor(), + textStyle: TextStyle(fontSize: 16, color: h_mainBlueColor()), + ), + ListView.separated( + shrinkWrap: true, + physics: const ClampingScrollPhysics(), // 嵌套listview关闭回弹 + separatorBuilder: + (_, __) => const Divider(height: 0.5, color: Colors.black12), + itemCount: _infoList.length, + itemBuilder: (context, index) { + final InfoModel item = _infoList[index]; + return _createRowSpaceBetweenItem( + horizontalPadding: 10, + verticalPadding: 15, + leftText: item.title, + rightText: item.discript, + ); + }, + ), + DashedLineText( + text: "帮扶内容", + lineColor: h_mainBlueColor(), + textStyle: TextStyle(fontSize: 16, color: h_mainBlueColor()), + ), + SizedBox(height: 20), + + ReadOnlyTable( + headers: ['序号', '所属帮扶', '隐患描述', '操作'], + columnWidths: [ + const FixedColumnWidth(50), + const FlexColumnWidth(2), + const FlexColumnWidth(3), + const FlexColumnWidth(1.5), + ], + data: [ + ['1', '政府部门', '测试文本测,试文本测试文本测试文本,测试文本测试文本', '合格'], + ['2', '社会组织', '试文本测试文本测试文本', '不合格'], + ], + onTapAction: (row) { + print('点击操作:第\$row 行'); + }, + ), + SizedBox(height: 20), + DashedLineText( + text: "帮扶隐患", + lineColor: h_mainBlueColor(), + textStyle: TextStyle(fontSize: 16, color: h_mainBlueColor()), + ), + SizedBox(height: 20), + + ReadOnlyTable(headers: ['序号', '来源', '内容', '操作'], data: []), + ], + ), + ), + ); + } + + Widget _createRowSpaceBetweenItem({ + required String leftText, + required String rightText, + double verticalPadding = 10, + double horizontalPadding = 0, + Color textColor = Colors.black, + bool isRight = false, + }) { + return Padding( + padding: EdgeInsets.symmetric( + vertical: verticalPadding, + horizontal: horizontalPadding, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + leftText, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + color: textColor, + ), + ), + if (isRight) + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + rightText, + style: TextStyle(fontSize: 15, color: Colors.grey), + ), + SizedBox(width: 2), + Icon( + Icons.arrow_forward_ios_rounded, + color: Colors.black45, + size: 15, + ), + ], + ) + else + Text(rightText, style: TextStyle(fontSize: 15, color: Colors.grey)), + ], + ), + ); + } + +} + +class InfoModel { + final String title; + final String discript; + + InfoModel(this.title, this.discript); +} diff --git a/lib/home/help_record_page.dart b/lib/home/help_record_page.dart new file mode 100644 index 0000000..fa0d2ea --- /dev/null +++ b/lib/home/help_record_page.dart @@ -0,0 +1,111 @@ +import 'package:flutter/material.dart'; +import 'package:qhdkfq_regulatory_flutter/tools/my_appbar.dart'; + +class HelpRecordPage extends StatefulWidget { + const HelpRecordPage({super.key}); + + @override + State createState() => _HelpRecordPageState(); +} + +class _HelpRecordPageState extends State { + Widget _buildDynamicRadioRow({ + required List options, // 选项文本数组 + required int? selectedValue, // 当前选中的值(索引) + required ValueChanged onChanged, // 选项变更回调 + }) { + return Wrap( + spacing: 5, // 横向间距 + runSpacing: 5, // 纵向行距 + children: List.generate(options.length, (i) { + return _buildRadioOption( + isSelected: selectedValue == i, + label: options[i], + value: i, + onChanged: onChanged, + ); + }), + ); + } + + /// 自定义Radio + Widget _buildRadioOption({ + required bool isSelected, + required String label, + required int value, + required ValueChanged onChanged, + }) { + return InkWell( + onTap: () => onChanged(value), + splashColor: Colors.blue, + borderRadius: BorderRadius.circular(20), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + // 自定义单选按钮 - 带对勾样式 + SizedBox( + child: + isSelected + ? const Icon( + Icons.check_circle, + size: 22, + color: Colors.blue, + ) + : const Icon( + Icons.circle_outlined, + size: 22, + color: Colors.grey, + ), + ), + SizedBox(width: 10), + Text( + label, + style: TextStyle( + fontSize: 15, + color: isSelected ? Colors.blue : Colors.grey[700], + fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, + ), + ), + SizedBox(width: 10), + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + late List radioTitles = ["日常检查","专项检查","总和检查","执法检查","举报检查"]; + + /// 选择的radio + late int? selectRadioIndex = 0; + return Scaffold( + appBar: MyAppbar(title: "帮扶记录"), + body: SafeArea( + child: Column( + children: [ + Container( + width: double.maxFinite, + padding: EdgeInsets.all(15), + color: Colors.white, + child: _buildDynamicRadioRow( + options: radioTitles, + selectedValue: selectRadioIndex, + onChanged: (val) { + setState(() { + selectRadioIndex = val; + }); + }, + ), + ), + SizedBox(height: 10,), + ListView( + children: [ + + ], + ) + ], + ), + ), + ); + } +} diff --git a/lib/home/home_categroy_list_page.dart b/lib/home/home_categroy_list_page.dart new file mode 100644 index 0000000..655a3c5 --- /dev/null +++ b/lib/home/home_categroy_list_page.dart @@ -0,0 +1,577 @@ +import 'package:flutter/material.dart'; +import 'package:qhdkfq_regulatory_flutter/home/danger_edit_page.dart'; +import 'package:qhdkfq_regulatory_flutter/home/help_detail_page.dart'; +import 'package:qhdkfq_regulatory_flutter/home/help_record_page.dart'; +import 'package:qhdkfq_regulatory_flutter/home/home_page.dart'; +import 'package:qhdkfq_regulatory_flutter/tools/custom_button.dart'; +import 'package:qhdkfq_regulatory_flutter/tools/h_colors.dart'; +import 'package:qhdkfq_regulatory_flutter/tools/my_appbar.dart'; +import 'package:qhdkfq_regulatory_flutter/tools/tools.dart'; + +import '../tools/date_tool.dart'; +import 'adaptive_list_item.dart'; +import 'department_picker.dart'; + +class HomeCategroyListPage extends StatefulWidget { + const HomeCategroyListPage(this.type, {super.key}); + + final int selectTabIndex = 0; + final HomeCategroyType type; + + @override + State createState() => _HomeCategroyListPageState(); +} + +class _HomeCategroyListPageState extends State + with SingleTickerProviderStateMixin { + final _searchController = TextEditingController(); + + // 已选择的分类 id + String? _selectedCategoryId; + + /// 选择的部门 + final String _chooseDepartment = "请选择部门"; + final String _chooseDataStr = getCurrentYearMonth(); + + /// 选择的tab + int _selectedTab = 0; + + /// 选择的radio + late int _selectRadioIndex = 0; + + /// 是否是本人 + late bool _isMySelf = true; + + /// 当前显示的企业数据(过滤后) + List> _displayData = []; + late TabController _tabController; + late List _radioTitles = []; + + /// 模拟数据 + final List data = [ + Category( + id: '1', + title: '分类一1', + children: [ + Category(id: '1-1', title: '子项 1-1'), + Category(id: '1-2', title: '子项 1-2'), + ], + ), + Category(id: '2', title: '分类二'), + Category( + id: '3', + title: '分类三', + children: [ + Category( + id: '3-1', + title: '子项 3-1', + children: [Category(id: '3-1-1', title: '子项 3-1-1')], + ), + ], + ), + ]; + + /// 模拟企业数据 + final List> _enterpriseData = List.generate(15, (index) { + return { + 'id': index, + 'name': '${['化工', '制造', '能源', '食品', '建筑'][index % 5]}企业${index + 1}', + 'creditCode': '9137${10000 + index}', + 'industry': ['化工', '制造', '能源', '食品', '建筑'][index % 5], + 'scale': ['大型', '中型', '小型'][index % 3], + 'safetyLevel': ['A', 'B', 'C'][index % 3], + 'lastCheck': '2025-0${6 + index % 3}-${10 + index % 20}', + 'riskCount': index % 4, + 'hiddenDangerCount': index % 5, + 'isDivided': index % 3 == 0, + }; + }); + + @override + void initState() { + super.initState(); + _displayData = _enterpriseData; // 初始显示所有数据 + _tabController = TabController( + length: widget.type.tabLists.length, + vsync: this, + ); + _tabController.addListener(() { + if (!_tabController.indexIsChanging) { + setState(() { + _selectedTab = _tabController.index; + }); + } + }); + } + + List _tabbarItemList(List tabTitles) { + return tabTitles.map((title) { + return Tab(text: title); + }).toList(); + } + + @override + /// 列表 + Widget _listViewWidget() { + return ListView.builder( + itemCount: _displayData.length, + itemBuilder: (context, index) { + final enterprise = _displayData[index]; + return Card( + color: Colors.white, + margin: const EdgeInsets.symmetric(horizontal: 0, vertical: 6), + elevation: 0.5, + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.zero), + child: Padding( + padding: const EdgeInsets.all(15), + child: AdaptiveListItem( + title: enterprise['name'], + items: _getEnterpriseProperties(enterprise), + actions: + widget.type == HomeCategroyType.supervisionSupport + ? [ + + CustomButton( + height: 40, + text: "查看", + backgroundColor: Colors.blue, + padding: EdgeInsets.symmetric(horizontal: 30), + onPressed: () { + pushPage(HelpRecordPage(), context); + }, + ), + CustomButton( + height: 40, + text: "监管帮扶", + backgroundColor: Colors.blue, + padding: EdgeInsets.symmetric(horizontal: 30), + onPressed: () {}, + ), + ] + : [], + ), + ), + ); + }, + ); + } + + /// 测试数据 + List> _getEnterpriseProperties( + Map enterprise, + ) { + switch (widget.type) { + case HomeCategroyType.enterpriseInfo: + return [ + {"title": "统一信用代码", "value": enterprise['creditCode']}, + {"title": "所属行业", "value": enterprise['industry']}, + {"title": "企业规模", "value": enterprise['scale']}, + {"title": "安全等级", "value": enterprise['safetyLevel']}, + {"title": "最近检查", "value": enterprise['lastCheck']}, + ]; + case HomeCategroyType.dualPrevention: + return [ + {"title": "风险点数量", "value": "${enterprise['riskCount']}个"}, + {"title": "隐患数量", "value": "${enterprise['hiddenDangerCount']}个"}, + {"title": "最近检查", "value": enterprise['lastCheck']}, + {"title": "安全等级", "value": enterprise['safetyLevel']}, + ]; + case HomeCategroyType.keySafety: + return [ + {"title": "重点区域", "value": "生产车间${enterprise['id'] % 5 + 1}"}, + { + "title": "责任人", + "value": "张${['三', '四', '五', '六', '七'][enterprise['id'] % 5]}", + }, + {"title": "上次检查", "value": enterprise['lastCheck']}, + {"title": "状态", "value": enterprise['riskCount'] > 2 ? "需整改" : "正常"}, + ]; + case HomeCategroyType.supervisionSupport: + return [ + { + "title": "帮扶类型", + "value": ["技术指导", "安全培训", "设备支持"][enterprise['id'] % 3], + }, + { + "title": "负责人", + "value": "王${['工', '主任', '经理'][enterprise['id'] % 3]}", + }, + {"title": "开始日期", "value": "2025-06-${10 + enterprise['id'] % 20}"}, + { + "title": "状态", + "value": ["进行中", "已完成", "待开始"][enterprise['id'] % 3], + }, + ]; + case HomeCategroyType.specialInspection: + return [ + { + "title": "检查类型", + "value": ["常规", "突击", "专项"][enterprise['id'] % 3], + }, + { + "title": "检查结果", + "value": ["合格", "需整改", "不合格"][enterprise['id'] % 3], + }, + {"title": "检查日期", "value": enterprise['lastCheck']}, + { + "title": "检查人", + "value": "李${['工', '主任', '专员'][enterprise['id'] % 3]}", + }, + ]; + case HomeCategroyType.disasterReduction: + return [ + {"title": "防灾设施", "value": "${enterprise['id'] % 5 + 3}项"}, + {"title": "上次演练", "value": "2025-05-${20 + enterprise['id'] % 10}"}, + { + "title": "应急预案", + "value": ["已备案", "待更新", "完善中"][enterprise['id'] % 3], + }, + { + "title": "责任人", + "value": "赵${['主管', '经理', '专员'][enterprise['id'] % 3]}", + }, + ]; + default: + return [ + {"title": "统一信用代码", "value": enterprise['creditCode']}, + {"title": "所属行业", "value": enterprise['industry']}, + ]; + } + } + + /// 选择部门这一行 + Widget _chooseDepartmentWidget() { + return Row( + spacing: 15, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + // 左侧部门选择区域 + _departmentWidget(1), + // 不同类型显示不同 + if (widget.type == HomeCategroyType.enterpriseInfo && + _radioTitles.isNotEmpty) + Padding( + padding: EdgeInsets.only(left: 10), + child: _buildDynamicRadioRow( + options: _radioTitles, + selectedValue: _selectRadioIndex, + onChanged: (newValue) { + setState(() => _selectRadioIndex = newValue!); + }, + ), + ), + if (widget.type == HomeCategroyType.dualPrevention && _selectedTab == 2) + // 左侧日期选择区域 + _departmentWidget(2), + ], + ); + } + + /// 选择部门单个组件 + Widget _departmentWidget(int type) { + return Expanded( + child: GestureDetector( + onTap: () { + if (type == 1) { + showModalBottomSheet( + context: context, + isScrollControlled: true, + barrierColor: Colors.black54, + backgroundColor: Colors.transparent, + builder: + (ctx) => DepartmentPicker( + data: data, + onSelected: (selectedId) { + setState(() { + _selectedCategoryId = selectedId; + }); + }, + ), + ); + } else {} + }, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), + decoration: BoxDecoration( + color: h_backGroundColor(), + borderRadius: BorderRadius.circular(4), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + type == 1 ? _chooseDepartment : _chooseDataStr, + overflow: TextOverflow.ellipsis, + style: const TextStyle(fontSize: 14, color: Colors.black), + ), + ), + const Icon( + Icons.keyboard_arrow_down, + color: Colors.black54, + size: 20, + ), + ], + ), + ), + ), + ); + } + + /// radio显示 + Row _buildDynamicRadioRow({ + required List options, // 选项文本数组 + required int? selectedValue, // 当前选中的值(索引) + required ValueChanged onChanged, // 选项变更回调 + }) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + for (int i = 0; i < options.length; i++) ...[ + _buildRadioOption( + isSelected: selectedValue == i, + label: options[i], + value: i, // 使用索引作为值 + onChanged: onChanged, + ), + if (i < options.length - 1) const SizedBox(width: 5), // 最后一个选项后不加间距 + ], + ], + ); + } + + /// 自定义Radio + Widget _buildRadioOption({ + required bool isSelected, + required String label, + required int value, + required ValueChanged onChanged, + }) { + return InkWell( + onTap: () => onChanged(value), + splashColor: Colors.blue, + borderRadius: BorderRadius.circular(20), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + // 自定义单选按钮 - 带对勾样式 + SizedBox( + child: + isSelected + ? const Icon( + Icons.check_circle, + size: 22, + color: Colors.blue, + ) + : const Icon( + Icons.circle_outlined, + size: 22, + color: Colors.grey, + ), + ), + SizedBox(width: 10), + Text( + label, + style: TextStyle( + fontSize: 15, + color: isSelected ? Colors.blue : Colors.grey[700], + fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, + ), + ), + SizedBox(width: 10), + ], + ), + ); + } + + // 搜索框 + Widget _searchBar() { + const double searchBarHeight = 40.0; + const double borderRadius = searchBarHeight / 2; + + return Row( + children: [ + Expanded( + child: SizedBox( + height: searchBarHeight, + child: TextField( + controller: _searchController, + decoration: InputDecoration( + filled: true, + fillColor: const Color(0xFFF5F5F5), + prefixIcon: const Icon(Icons.search_rounded, size: 20), + hintText: "请输入关键字", + hintStyle: const TextStyle(fontSize: 14), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(borderRadius), + borderSide: BorderSide.none, + ), + isDense: true, + contentPadding: const EdgeInsets.symmetric(vertical: 0), + ), + onChanged: (val) { + // 搜索过滤 + setState(() { + if (val.isEmpty) { + _displayData = _enterpriseData; + } else { + _displayData = + _enterpriseData.where((e) { + return e['name'].contains(val) || + e['creditCode'].contains(val); + }).toList(); + } + }); + }, + onSubmitted: (val) { + // 提交搜索 + }, + ), + ), + ), + const SizedBox(width: 10), + SizedBox( + height: searchBarHeight, + child: TextButton( + onPressed: () { + // 搜索操作 + setState(() { + if (_searchController.text.isEmpty) { + _displayData = _enterpriseData; + } else { + _displayData = + _enterpriseData.where((e) { + return e['name'].contains(_searchController.text) || + e['creditCode'].contains(_searchController.text); + }).toList(); + } + }); + }, + style: TextButton.styleFrom( + padding: const EdgeInsets.symmetric(horizontal: 16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(borderRadius), + ), + ), + child: const Text( + "搜索", + style: TextStyle(color: Colors.blue, fontSize: 16), + ), + ), + ), + ], + ); + } + + Widget build(BuildContext context) { + if (widget.type == HomeCategroyType.enterpriseInfo) { + if (_selectedTab == 0) { + _radioTitles = ["全部", "已划分", "未划分"]; + } else if (_selectedTab == 1) { + _radioTitles = ["全部", "已通过", "已打回"]; + } else { + _radioTitles = []; // 其他tab不需要显示radio + } + } else if (widget.type == HomeCategroyType.supervisionSupport || + widget.type == HomeCategroyType.specialInspection) { + if (_selectedTab == 1) { + _radioTitles = ["全部", "待整改", "待复查", "已复查"]; + } + } else { + _radioTitles = []; + } + + return Scaffold( + backgroundColor: h_backGroundColor(), + appBar: MyAppbar(title: widget.type.title), + body: SafeArea( + child: Column( + children: [ + if (widget.type.tabLists.isNotEmpty) + Container( + color: Colors.white, + child: TabBar( + controller: _tabController, + labelStyle: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w300, + ), + indicator: UnderlineTabIndicator( + borderSide: BorderSide(width: 3.0, color: Colors.blue), + insets: EdgeInsets.symmetric(horizontal: 15.0), + ), + labelColor: Colors.blue, + unselectedLabelColor: Colors.black, + tabs: _tabbarItemList(widget.type.tabLists), + onTap: (index) { + setState(() { + _selectedTab = index; + }); + }, + ), + ), + const SizedBox(height: 15), + Container( + padding: const EdgeInsets.all(15), + color: Colors.white, + child: Column( + spacing: 15, + children: [ + _searchBar(), + if (widget.type == HomeCategroyType.enterpriseInfo || + widget.type == HomeCategroyType.dualPrevention || + widget.type == HomeCategroyType.keySafety) + _chooseDepartmentWidget(), + if ((widget.type == HomeCategroyType.supervisionSupport || + widget.type == HomeCategroyType.specialInspection) && + _selectedTab == 1) + Column( + spacing: 10, + crossAxisAlignment: CrossAxisAlignment.start, + + children: [ + Padding( + padding: EdgeInsets.only(left: 3), + child: _buildDynamicRadioRow( + options: _radioTitles, + selectedValue: _selectRadioIndex, + onChanged: (newValue) { + setState(() => _selectRadioIndex = newValue!); + }, + ), + ), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Checkbox( + activeColor: Colors.blue, + value: _isMySelf, + materialTapTargetSize: + MaterialTapTargetSize.shrinkWrap, + visualDensity: const VisualDensity( + horizontal: -4, + vertical: 0, + ), + onChanged: (bool? newValue) { + setState(() { + _isMySelf = newValue ?? false; + }); + }, + ), + const SizedBox(width: 4), + Text("只看自己"), + ], + ), + ], + ), + ], + ), + ), + const SizedBox(height: 10), + Expanded(child: _listViewWidget()), + ], + ), + ), + ); + } +} diff --git a/lib/home/home_page.dart b/lib/home/home_page.dart index 6896961..90c194f 100644 --- a/lib/home/home_page.dart +++ b/lib/home/home_page.dart @@ -2,7 +2,23 @@ import 'dart:async'; import 'dart:ffi'; import 'package:flutter/material.dart'; import 'package:flutter_html/flutter_html.dart'; +import 'package:qhdkfq_regulatory_flutter/home/home_categroy_list_page.dart'; +import 'package:qhdkfq_regulatory_flutter/tools/h_colors.dart'; +import 'package:qhdkfq_regulatory_flutter/tools/tools.dart'; +enum HomeCategroyType { + enterpriseInfo("企业信息", ["监管划分", "信息审核", "持证人员"]), // 企业信息 + dualPrevention("双重预防", ["风险辨识管控", "隐患排查治理", "安全教育培训"]), // 双重预防 + keySafety("重点安全", ["安全生产费用", "危险作业"]), // 重点安全 + supervisionSupport("监管帮扶", ["监管帮扶管理", "监管帮扶隐患管理"]), // 监管帮扶 + specialInspection("专项检查", ["专项检查管理", "专项检查隐患管理"]), // 专项检查 + disasterReduction("防灾减灾", []), // 防灾减灾; + supervisionRecord("帮扶记录", []); // 防灾减灾; + + final String title; + final List tabLists; + const HomeCategroyType(this.title, this.tabLists); +} class HomePage extends StatefulWidget { const HomePage({Key? key}) : super(key: key); @@ -12,7 +28,6 @@ class HomePage extends StatefulWidget { } class _HomePageState extends State { - // 模拟数据 final List> operations = [ { @@ -25,11 +40,7 @@ class _HomePageState extends State { 'type': '高处作业', 'time': '2025-03-21 09:00', }, - { - 'company': '万基钢管 (秦皇岛) 有限公司', - 'type': '高处作业', - 'time': '2025-03-18 14:00', - }, + {'company': '万基钢管 (秦皇岛) 有限公司', 'type': '高处作业', 'time': '2025-03-18 14:00'}, { 'company': '通用电气-哈动力-南汽轮能源服务 (BSH) 有限公司', 'type': '高处作业', @@ -69,16 +80,16 @@ class _HomePageState extends State { @override Widget build(BuildContext context) { return Scaffold( + backgroundColor: h_backGroundColor(), body: RefreshIndicator( onRefresh: _onRefresh, child: ListView( physics: const AlwaysScrollableScrollPhysics(), - children: [ _buildBgImage(), // _buildStatsCards(), - const SizedBox(height: 24), + // const SizedBox(height: 12), _buildSectionTitle('企业排查情况'), const SizedBox(height: 12), _buildInspectionTable(), @@ -87,116 +98,32 @@ class _HomePageState extends State { const SizedBox(height: 12), ..._buildOperationList(), ], - ), ), ); } Widget _buildBgImage() { - return Stack( - alignment: const FractionalOffset(0.5, 1), + return Column( children: [ - Padding( - padding: EdgeInsetsGeometry.fromLTRB(0, 0, 0, 150), - child: Image.asset( - "assets/images/banner.png", - width: MediaQuery.of(context).size.width, // 获取屏幕宽度 - fit: BoxFit.cover), + // 背景图片 + Image.asset( + "assets/images/banner.png", + width: MediaQuery.of(context).size.width, + fit: BoxFit.cover, + height: 200, // 设置固定高度或根据内容调整 ), - _buildStatsCards(), + Transform.translate(offset: Offset(0, -40), child: _buildStatsCards()), ], ); } - Widget _buildStatsCards() { - return - Container( - padding: const EdgeInsets.all(12), - margin: EdgeInsets.fromLTRB(12,0,12,0), - - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 8, - offset: const Offset(0, 4), - ) - ], - ), - - child: GridView.count( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - crossAxisCount: 4, - crossAxisSpacing: 16, - mainAxisSpacing: 16, - // childAspectRatio: 1.5, - children: [ - _buildStatCard('企业信息', "assets/images/ico1.png"), - _buildStatCard('双重预防', "assets/images/ico2.png"), - _buildStatCard('重点安全', "assets/images/ico4.png"), - _buildStatCard('监管帮扶', "assets/images/ico9.png"), - _buildStatCard('专项检查', "assets/images/ico8.png"), - _buildStatCard('防灾减灾', "assets/images/ico10.png"), - ], - - - ), - ); - } - - Widget _buildStatCard(String title, String icon ){ - return Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - // Container( - // padding: const EdgeInsets.all(12), - // decoration: BoxDecoration( - // color: color.withOpacity(0.1), - // shape: BoxShape.circle, - // ), - Image.asset(icon,width: 30,height: 30,fit:BoxFit.cover), - // child: Icon(icon, color: color, size: 32), - // ), - // const SizedBox(height: 12), - Padding( - padding: EdgeInsetsGeometry.fromLTRB(0,5,0,0), - child: Text(title, style: const TextStyle(fontSize: 16)) - ) - - ], - - - ); - } - - Widget _buildSectionTitle(String title) { - return Row( - children: [ - Container( - margin: EdgeInsets.fromLTRB(12,0,12,0), - width: 4, - height: 20, - decoration: BoxDecoration( - color: const Color(0xFF0D47A1), - borderRadius: BorderRadius.circular(2), - ), - ), - const SizedBox(width: 8), - Text(title, style: Theme.of(context).textTheme.titleMedium), - ], - ); - } - - Widget _buildInspectionTable() { return Container( - margin: EdgeInsets.fromLTRB(12,0,12,0), - padding: const EdgeInsets.fromLTRB(16,16,16,10), + padding: const EdgeInsets.all(12), + margin: EdgeInsets.fromLTRB(12, 0, 12, 0), + decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), @@ -205,7 +132,110 @@ class _HomePageState extends State { color: Colors.black.withOpacity(0.05), blurRadius: 8, offset: const Offset(0, 4), - ) + ), + ], + ), + + child: GridView.count( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + crossAxisCount: 4, + crossAxisSpacing: 16, + mainAxisSpacing: 16, + // childAspectRatio: 1.5, + // enterpriseInfo("企业信息"), // 企业信息 + // dualPrevention("双重预防"), // 双重预防 + // keySafety("重点安全"), // 重点安全 + // supervisionSupport("监管帮扶"), // 监管帮扶 + // specialInspection("专项检查"), // 专项检查 + // disasterReduction("防灾减灾"); // 防灾减灾; + children: [ + _buildStatCard( + '企业信息', + "assets/images/ico1.png", + HomeCategroyType.enterpriseInfo, + ), + _buildStatCard( + '双重预防', + "assets/images/ico2.png", + HomeCategroyType.dualPrevention, + ), + _buildStatCard( + '重点安全', + "assets/images/ico4.png", + HomeCategroyType.keySafety, + ), + _buildStatCard( + '监管帮扶', + "assets/images/ico9.png", + HomeCategroyType.supervisionSupport, + ), + _buildStatCard( + '专项检查', + "assets/images/ico8.png", + HomeCategroyType.specialInspection, + ), + _buildStatCard( + '防灾减灾', + "assets/images/ico10.png", + HomeCategroyType.disasterReduction, + ), + ], + ), + ); + } + + Widget _buildStatCard(String title, String icon, HomeCategroyType type) { + return GestureDetector( + onTap: () { + pushPage(HomeCategroyListPage(type), context); + }, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset(icon, width: 30, height: 30, fit: BoxFit.cover), + Padding( + padding: EdgeInsets.only(top: 5), + child: Text(title, style: const TextStyle(fontSize: 16)), + ), + ], + ), + ); + } + + Widget _buildSectionTitle(String title) { + return Row( + children: [ + Container( + margin: EdgeInsets.fromLTRB(12, 0, 12, 0), + width: 4, + height: 20, + decoration: BoxDecoration( + color: const Color(0xFF0D47A1), + borderRadius: BorderRadius.circular(2), + ), + ), + Text( + title, + style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + ), + ], + ); + } + + Widget _buildInspectionTable() { + return Container( + margin: EdgeInsets.fromLTRB(12, 0, 12, 0), + padding: const EdgeInsets.fromLTRB(16, 16, 16, 10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 8, + offset: const Offset(0, 4), + ), ], ), child: Table( @@ -220,18 +250,18 @@ class _HomePageState extends State { ), children: [ TableRow( - decoration: BoxDecoration(color: Colors.grey[100]), + decoration: BoxDecoration(color: Colors.grey[50]), children: [ - _buildTableCell('各单位的管辖企业数',Colors.black, isHeader: true), - _buildTableCell('已排查', Colors.black,isHeader: true), - _buildTableCell('未排查',Colors.black, isHeader: true), + _buildTableCell('各单位的管辖企业数', Colors.black, isHeader: true), + _buildTableCell('已排查', Colors.black, isHeader: true), + _buildTableCell('未排查', Colors.black, isHeader: true), ], ), TableRow( children: [ - _buildTableCell('49',Colors.blue), - _buildTableCell('36',Colors.green), - _buildTableCell('13',Colors.orange), + _buildTableCell('49', Colors.blue), + _buildTableCell('36', Colors.green), + _buildTableCell('13', Colors.orange), ], ), ], @@ -245,10 +275,10 @@ class _HomePageState extends State { child: Text( text, style: TextStyle( - fontSize: 14, - fontWeight: isHeader ? FontWeight.bold : FontWeight.normal, + fontSize: 16, + fontWeight: FontWeight.bold, // color: isHeader ? const Color(0xFF333333) : const Color(0xFF666666), - color:color, + color: color, ), textAlign: TextAlign.center, ), @@ -258,7 +288,7 @@ class _HomePageState extends State { List _buildOperationList() { return [ Container( - margin: EdgeInsets.fromLTRB(12,0,12,0), + margin: EdgeInsets.fromLTRB(12, 0, 12, 0), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), @@ -267,7 +297,7 @@ class _HomePageState extends State { color: Colors.black.withOpacity(0.05), blurRadius: 8, offset: const Offset(0, 4), - ) + ), ], ), child: Column( @@ -285,9 +315,10 @@ class _HomePageState extends State { width: MediaQuery.of(context).size.width, // 获取屏幕宽度 decoration: BoxDecoration( border: Border( - bottom: index < operations.length - 1 - ? BorderSide(color: Colors.grey[200]!) - : BorderSide.none, + bottom: + index < operations.length - 1 + ? BorderSide(color: Colors.grey[200]!) + : BorderSide.none, ), ), padding: const EdgeInsets.all(16), @@ -297,13 +328,17 @@ class _HomePageState extends State { children: [ // Row( // mainAxisAlignment: MainAxisAlignment.spaceBetween, - // children: [ - Text( - operation['company']!, - style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: Color(0xFF333333)), - // maxLines: 1, - // overflow: TextOverflow.ellipsis, - ), + // children: [ + Text( + operation['company']!, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Color(0xFF333333), + ), + // maxLines: 1, + // overflow: TextOverflow.ellipsis, + ), // ], // ), const SizedBox(height: 8), @@ -313,8 +348,7 @@ class _HomePageState extends State { color: _getOperationColor(operation['type']!).withOpacity(0.1), borderRadius: BorderRadius.circular(4), ), - child: - Text( + child: Text( operation['type']!, style: TextStyle( fontSize: 12, @@ -346,8 +380,4 @@ class _HomePageState extends State { return Colors.blue; } } - - - } - diff --git a/lib/main.dart b/lib/main.dart index 7547c72..ff7788f 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; - import 'package:shared_preferences/shared_preferences.dart'; import './pages/login_page.dart'; // 导入登录页面 import './pages/main_tab.dart'; // 导入主页(带TabBar的页面) @@ -28,9 +27,19 @@ class MyApp extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp( title: '', + builder: (context, child) { + return GestureDetector( + behavior: HitTestBehavior.translucent, // 让空白区域也能点击 + onTap: () { + // 收起键盘 + FocusScope.of(context).unfocus(); + }, + child: child, + ); + }, theme: ThemeData( dividerTheme: const DividerThemeData( - color: Colors.black12, + color: Color(0xF1F1F1FF), thickness: 1, // 线高 indent: 0, // 左缩进 endIndent: 0, // 右缩进 @@ -43,8 +52,7 @@ class MyApp extends StatelessWidget { ), ), // 根据登录状态决定初始页面 - // home: isLoggedIn ? const MainPage() : const LoginPage(), - home:const LoginPage(), + home: isLoggedIn ? const MainPage() : const LoginPage(), debugShowCheckedModeBanner: false, ); } diff --git a/lib/tools/SmallWidget.dart b/lib/tools/SmallWidget.dart new file mode 100644 index 0000000..73df7b0 --- /dev/null +++ b/lib/tools/SmallWidget.dart @@ -0,0 +1,25 @@ +import 'dart:ffi'; + +import 'package:flutter/material.dart'; + +import 'h_colors.dart'; +/// 标签(eg:风险等级) +Widget riskTagText(int level, String title) { + + final List colors = riskLevelTextColors(); + if (colors.length <= (level - 1)) { + return SizedBox(); + } + return Container( + padding: EdgeInsets.symmetric(vertical: 3, horizontal: 5), + decoration: BoxDecoration( + color: colors[level-1], + borderRadius: const BorderRadius.all(Radius.circular(5)), + ), + // color: Colors., + child: Text( + title, + style: TextStyle(color: Colors.white, fontSize: 14), + ), + ); +} \ No newline at end of file diff --git a/lib/tools/custom_button.dart b/lib/tools/custom_button.dart new file mode 100644 index 0000000..f41e432 --- /dev/null +++ b/lib/tools/custom_button.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; + +/// 自定义默认按钮 +class CustomButton extends StatelessWidget { + final String text; // 按钮文字 + final Color backgroundColor; // 按钮背景色 + final double borderRadius; // 圆角半径(默认5) + final VoidCallback? onPressed; // 点击事件回调 + final EdgeInsetsGeometry? padding; // 内边距 + final EdgeInsetsGeometry? margin; // 外边距 + final double? height; // 按钮高度 + final TextStyle? textStyle; // 文字样式 + + const CustomButton({ + super.key, + required this.text, + required this.backgroundColor, + this.borderRadius = 5.0, + this.onPressed, + this.padding, + this.margin, + this.height, + this.textStyle, + }); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: onPressed, + child: Container( + height: height ?? 50, // 默认高度50 + padding: padding ?? const EdgeInsets.all(8), // 默认内边距 + margin: margin ?? const EdgeInsets.symmetric(horizontal: 8), // 默认外边距 + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(borderRadius), + color: backgroundColor, + ), + child: Center( + child: Text( + text, + style: textStyle ?? const TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/tools/date_tool.dart b/lib/tools/date_tool.dart new file mode 100644 index 0000000..a31a072 --- /dev/null +++ b/lib/tools/date_tool.dart @@ -0,0 +1,14 @@ +// 获取当前年月字符串(格式:2025-07) +String getCurrentYearMonth() { + final now = DateTime.now(); + return '${now.year}-${now.month.toString().padLeft(2, '0')}'; +} +// 获取当前年份字符串 +String getCurrentYear() { + return DateTime.now().year.toString(); +} + +// 获取当前月份字符串(带前导零) +String getCurrentMonth() { + return DateTime.now().month.toString().padLeft(2, '0'); +} diff --git a/lib/tools/h_colors.dart b/lib/tools/h_colors.dart new file mode 100644 index 0000000..9284acb --- /dev/null +++ b/lib/tools/h_colors.dart @@ -0,0 +1,13 @@ +import 'dart:ffi'; +import 'dart:ui'; + +Color h_backGroundColor() => Color(0xFFFAFAFA); +Color h_mainBlueColor() => Color(0xFF2A56F7); + +List riskLevelTextColors() { + return [Color(0xFFE54D42),Color(0xFFF37B1D),Color(0xFFF9BD08),Color(0xFF3281FF)]; +} + +List riskLevelBgColors() { + return [Color(0xFFFADBD9),Color(0xFFFCE6D2),Color(0xFFFDF2CE),Color(0xFFCCE6FF)]; +} diff --git a/lib/tools/my_appbar.dart b/lib/tools/my_appbar.dart new file mode 100644 index 0000000..1bca125 --- /dev/null +++ b/lib/tools/my_appbar.dart @@ -0,0 +1,89 @@ +import 'package:flutter/material.dart'; +import 'dart:io' show Platform; + +import 'package:qhdkfq_regulatory_flutter/tools/h_colors.dart'; + +class MyAppbar extends StatelessWidget implements PreferredSizeWidget { + final String title; + final VoidCallback? onBackPressed; + final Color backgroundColor; + final Color textColor; + final List? actions; + final bool isBack; + final bool centerTitle; // 新增:控制标题是否居中 + + const MyAppbar({ + Key? key, + required this.title, + this.onBackPressed, + this.backgroundColor = Colors.blue, + this.textColor = Colors.white, + this.actions, + this.isBack = true, + this.centerTitle = true, // 默认居中 + }) : super(key: key); + + // 根据平台设置不同高度 + @override + Size get preferredSize { + // iOS使用更紧凑的高度(44点),Android保持默认(56点) + return Size.fromHeight(Platform.isIOS ? 44.0 : kToolbarHeight); + } + + @override + Widget build(BuildContext context) { + return AppBar( + backgroundColor: h_mainBlueColor(), + automaticallyImplyLeading: false, + centerTitle: centerTitle, + toolbarHeight: preferredSize.height, // 使用计算的高度 + title: Text( + title, + style: TextStyle( + color: textColor, + fontSize: Platform.isIOS ? 17.0 : 18.0, // iOS使用更小字号 + fontWeight: FontWeight.w600, // iOS使用中等字重 + ), + ), + leading: isBack ? _buildBackButton(context) : null, + actions: _buildActions(), + elevation: Platform.isIOS ? 0 : 4, // iOS无阴影 + // iOS添加底部边框 + shape: Platform.isIOS + ? const Border(bottom: BorderSide(color: Colors.black12, width: 0.5)) + : null, + ); + } + + // 返回按钮 + Widget _buildBackButton(BuildContext context) { + return Padding( + padding: EdgeInsets.only(left: Platform.isIOS ? 8.0 : 16.0), + child: IconButton( + icon: Icon( + Platform.isIOS ? Icons.arrow_back_ios : Icons.arrow_back, + color: textColor, + size: Platform.isIOS ? 20.0 : 24.0, // iOS使用更小图标 + ), + padding: EdgeInsets.zero, // 移除默认内边距 + constraints: const BoxConstraints(), // 移除默认约束 + onPressed: onBackPressed ?? () => Navigator.of(context).pop(), + ), + ); + } + + // 右侧按钮间距 + List? _buildActions() { + if (actions == null) return null; + + return [ + Padding( + padding: EdgeInsets.only(right: Platform.isIOS ? 8.0 : 16.0), + child: Row( + mainAxisSize: MainAxisSize.min, + children: actions!, + ), + ) + ]; + } +} \ No newline at end of file diff --git a/lib/tools/tools.dart b/lib/tools/tools.dart new file mode 100644 index 0000000..75d69b6 --- /dev/null +++ b/lib/tools/tools.dart @@ -0,0 +1,134 @@ +import 'dart:ui'; +import 'dart:math'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:package_info_plus/package_info_plus.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; +} + +void pushPage(Widget page, BuildContext context) { + Navigator.push(context, MaterialPageRoute(builder: (context) => page)); +} +void present(Widget page, BuildContext context) { + Navigator.push( + context, + MaterialPageRoute( + fullscreenDialog: true, + builder: (context) => page, + ), + ); +} +/// 文本样式工具类 +/// 文本样式工具类 +/// 文本样式工具类,返回 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', + ); + } +} \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 11dcbff..39b0b10 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,16 +5,16 @@ packages: dependency: transitive description: name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" - url: "https://pub.flutter-io.cn" + sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "2.13.0" + version: "2.12.0" boolean_selector: dependency: transitive description: name: boolean_selector sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.1.2" characters: @@ -22,7 +22,7 @@ packages: description: name: characters sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.4.0" clock: @@ -30,7 +30,7 @@ packages: description: name: clock sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.1.2" collection: @@ -38,7 +38,7 @@ packages: description: name: collection sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.19.1" cross_file: @@ -46,7 +46,7 @@ packages: description: name: cross_file sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.3.4+2" crypto: @@ -54,7 +54,7 @@ packages: description: name: crypto sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.0.6" csslib: @@ -62,7 +62,7 @@ packages: description: name: csslib sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.0.2" cupertino_icons: @@ -70,23 +70,23 @@ packages: description: name: cupertino_icons sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.0.8" device_info_plus: dependency: "direct main" description: name: device_info_plus - sha256: "72d146c6d7098689ff5c5f66bcf593ac11efc530095385356e131070333e64da" - url: "https://pub.flutter-io.cn" + sha256: "98f28b42168cc509abc92f88518882fd58061ea372d7999aecc424345c7bff6a" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "11.3.0" + version: "11.5.0" device_info_plus_platform_interface: dependency: transitive description: name: device_info_plus_platform_interface sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "7.0.3" dio: @@ -94,7 +94,7 @@ packages: description: name: dio sha256: "253a18bbd4851fecba42f7343a1df3a9a4c1d31a2c1b37e221086b4fa8c8dbc9" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "5.8.0+1" dio_web_adapter: @@ -102,7 +102,7 @@ packages: description: name: dio_web_adapter sha256: "7586e476d70caecaf1686d21eee7247ea43ef5c345eab9e0cc3583ff13378d78" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.1.1" extended_image: @@ -110,7 +110,7 @@ packages: description: name: extended_image sha256: f6cbb1d798f51262ed1a3d93b4f1f2aa0d76128df39af18ecb77fa740f88b2e0 - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "10.0.1" extended_image_library: @@ -118,39 +118,39 @@ packages: description: name: extended_image_library sha256: "1f9a24d3a00c2633891c6a7b5cab2807999eb2d5b597e5133b63f49d113811fe" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "5.0.1" fake_async: dependency: transitive description: name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.flutter-io.cn" + sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "1.3.3" + version: "1.3.2" ffi: dependency: transitive description: name: ffi sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.1.4" file: dependency: transitive description: name: file - sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" - url: "https://pub.flutter-io.cn" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "6.1.4" + version: "7.0.1" file_selector_linux: dependency: transitive description: name: file_selector_linux sha256: "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.9.3+2" file_selector_macos: @@ -158,7 +158,7 @@ packages: description: name: file_selector_macos sha256: "8c9250b2bd2d8d4268e39c82543bacbaca0fda7d29e0728c3c4bbb7c820fd711" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.9.4+3" file_selector_platform_interface: @@ -166,7 +166,7 @@ packages: description: name: file_selector_platform_interface sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.6.2" file_selector_windows: @@ -174,7 +174,7 @@ packages: description: name: file_selector_windows sha256: "320fcfb6f33caa90f0b58380489fc5ac05d99ee94b61aa96ec2bff0ba81d3c2b" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.9.3+4" flutter: @@ -187,7 +187,7 @@ packages: description: name: flutter_html sha256: "38a2fd702ffdf3243fb7441ab58aa1bc7e6922d95a50db76534de8260638558d" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.0.0" flutter_lints: @@ -195,7 +195,7 @@ packages: description: name: flutter_lints sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "5.0.0" flutter_plugin_android_lifecycle: @@ -203,7 +203,7 @@ packages: description: name: flutter_plugin_android_lifecycle sha256: f948e346c12f8d5480d2825e03de228d0eb8c3a737e4cdaa122267b89c022b5e - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.0.28" flutter_screenutil: @@ -211,7 +211,7 @@ packages: description: name: flutter_screenutil sha256: "8239210dd68bee6b0577aa4a090890342d04a136ce1c81f98ee513fc0ce891de" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "5.9.3" flutter_test: @@ -229,7 +229,7 @@ packages: description: name: html sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.15.6" http: @@ -237,7 +237,7 @@ packages: description: name: http sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.4.0" http_client_helper: @@ -245,7 +245,7 @@ packages: description: name: http_client_helper sha256: "8a9127650734da86b5c73760de2b404494c968a3fd55602045ffec789dac3cb1" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.0.0" http_parser: @@ -253,7 +253,7 @@ packages: description: name: http_parser sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "4.1.2" image_picker: @@ -261,7 +261,7 @@ packages: description: name: image_picker sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.1.2" image_picker_android: @@ -269,7 +269,7 @@ packages: description: name: image_picker_android sha256: "317a5d961cec5b34e777b9252393f2afbd23084aa6e60fcf601dcf6341b9ebeb" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.8.12+23" image_picker_for_web: @@ -277,7 +277,7 @@ packages: description: name: image_picker_for_web sha256: "717eb042ab08c40767684327be06a5d8dbb341fe791d514e4b92c7bbe1b7bb83" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.0.6" image_picker_ios: @@ -285,7 +285,7 @@ packages: description: name: image_picker_ios sha256: "05da758e67bc7839e886b3959848aa6b44ff123ab4b28f67891008afe8ef9100" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.8.12+2" image_picker_linux: @@ -293,7 +293,7 @@ packages: description: name: image_picker_linux sha256: "34a65f6740df08bbbeb0a1abd8e6d32107941fd4868f67a507b25601651022c9" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.2.1+2" image_picker_macos: @@ -301,7 +301,7 @@ packages: description: name: image_picker_macos sha256: "1b90ebbd9dcf98fb6c1d01427e49a55bd96b5d67b8c67cf955d60a5de74207c1" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.2.1+2" image_picker_platform_interface: @@ -309,7 +309,7 @@ packages: description: name: image_picker_platform_interface sha256: "886d57f0be73c4b140004e78b9f28a8914a09e50c2d816bdd0520051a71236a0" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.10.1" image_picker_windows: @@ -317,7 +317,7 @@ packages: description: name: image_picker_windows sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.2.1+1" intl: @@ -325,7 +325,7 @@ packages: description: name: intl sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.20.2" js: @@ -333,23 +333,23 @@ packages: description: name: js sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.7.2" leak_tracker: dependency: transitive description: name: leak_tracker - sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" - url: "https://pub.flutter-io.cn" + sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "10.0.9" + version: "10.0.8" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.0.9" leak_tracker_testing: @@ -357,7 +357,7 @@ packages: description: name: leak_tracker_testing sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.0.1" lints: @@ -365,7 +365,7 @@ packages: description: name: lints sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7 - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "5.1.1" list_counter: @@ -373,7 +373,7 @@ packages: description: name: list_counter sha256: c447ae3dfcd1c55f0152867090e67e219d42fe6d4f2807db4bbe8b8d69912237 - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.0.2" matcher: @@ -381,7 +381,7 @@ packages: description: name: matcher sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.12.17" material_color_utilities: @@ -389,7 +389,7 @@ packages: description: name: material_color_utilities sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.11.1" meta: @@ -397,7 +397,7 @@ packages: description: name: meta sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.16.0" mime: @@ -405,7 +405,7 @@ packages: description: name: mime sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.0.0" mobile_scanner: @@ -413,7 +413,7 @@ packages: description: name: mobile_scanner sha256: "54005bdea7052d792d35b4fef0f84ec5ddc3a844b250ecd48dc192fb9b4ebc95" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "7.0.1" nested: @@ -421,7 +421,7 @@ packages: description: name: nested sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.0.0" oktoast: @@ -429,7 +429,7 @@ packages: description: name: oktoast sha256: f1366c5c793ddfb8f55bc6fc3e45db43c45debf173b765fb4c5ec096cbdeb84a - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.4.0" package_info_plus: @@ -437,7 +437,7 @@ packages: description: name: package_info_plus sha256: "7e76fad405b3e4016cd39d08f455a4eb5199723cf594cd1b8916d47140d93017" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "4.2.0" package_info_plus_platform_interface: @@ -445,7 +445,7 @@ packages: description: name: package_info_plus_platform_interface sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.0.1" path: @@ -453,7 +453,7 @@ packages: description: name: path sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.9.1" path_provider: @@ -461,7 +461,7 @@ packages: description: name: path_provider sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.1.5" path_provider_android: @@ -469,7 +469,7 @@ packages: description: name: path_provider_android sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9 - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.2.17" path_provider_foundation: @@ -477,7 +477,7 @@ packages: description: name: path_provider_foundation sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.4.1" path_provider_linux: @@ -485,7 +485,7 @@ packages: description: name: path_provider_linux sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.2.1" path_provider_platform_interface: @@ -493,7 +493,7 @@ packages: description: name: path_provider_platform_interface sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.1.2" path_provider_windows: @@ -501,7 +501,7 @@ packages: description: name: path_provider_windows sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.3.0" permission_handler: @@ -509,7 +509,7 @@ packages: description: name: permission_handler sha256: bc917da36261b00137bbc8896bf1482169cd76f866282368948f032c8c1caae1 - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "12.0.1" permission_handler_android: @@ -517,7 +517,7 @@ packages: description: name: permission_handler_android sha256: "1e3bc410ca1bf84662104b100eb126e066cb55791b7451307f9708d4007350e6" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "13.0.1" permission_handler_apple: @@ -525,7 +525,7 @@ packages: description: name: permission_handler_apple sha256: f000131e755c54cf4d84a5d8bd6e4149e262cc31c5a8b1d698de1ac85fa41023 - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "9.4.7" permission_handler_html: @@ -533,7 +533,7 @@ packages: description: name: permission_handler_html sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.1.3+5" permission_handler_platform_interface: @@ -541,7 +541,7 @@ packages: description: name: permission_handler_platform_interface sha256: eb99b295153abce5d683cac8c02e22faab63e50679b937fa1bf67d58bb282878 - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "4.3.0" permission_handler_windows: @@ -549,7 +549,7 @@ packages: description: name: permission_handler_windows sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.2.1" photo_manager: @@ -557,7 +557,7 @@ packages: description: name: photo_manager sha256: a0d9a7a9bc35eda02d33766412bde6d883a8b0acb86bbe37dac5f691a0894e8a - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.7.1" photo_manager_image_provider: @@ -565,7 +565,7 @@ packages: description: name: photo_manager_image_provider sha256: b6015b67b32f345f57cf32c126f871bced2501236c405aafaefa885f7c821e4f - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.2.0" photo_view: @@ -573,7 +573,7 @@ packages: description: name: photo_view sha256: "1fc3d970a91295fbd1364296575f854c9863f225505c28c46e0a03e48960c75e" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.15.0" platform: @@ -581,7 +581,7 @@ packages: description: name: platform sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.1.6" plugin_platform_interface: @@ -589,7 +589,7 @@ packages: description: name: plugin_platform_interface sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.1.8" provider: @@ -597,7 +597,7 @@ packages: description: name: provider sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "6.1.5" shared_preferences: @@ -605,7 +605,7 @@ packages: description: name: shared_preferences sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.5.3" shared_preferences_android: @@ -613,7 +613,7 @@ packages: description: name: shared_preferences_android sha256: "20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.4.10" shared_preferences_foundation: @@ -621,7 +621,7 @@ packages: description: name: shared_preferences_foundation sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.5.4" shared_preferences_linux: @@ -629,7 +629,7 @@ packages: description: name: shared_preferences_linux sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.4.1" shared_preferences_platform_interface: @@ -637,7 +637,7 @@ packages: description: name: shared_preferences_platform_interface sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.4.1" shared_preferences_web: @@ -645,7 +645,7 @@ packages: description: name: shared_preferences_web sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.4.3" shared_preferences_windows: @@ -653,7 +653,7 @@ packages: description: name: shared_preferences_windows sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.4.1" simple_gesture_detector: @@ -661,7 +661,7 @@ packages: description: name: simple_gesture_detector sha256: ba2cd5af24ff20a0b8d609cec3f40e5b0744d2a71804a2616ae086b9c19d19a3 - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.2.1" sky_engine: @@ -674,7 +674,7 @@ packages: description: name: source_span sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.10.1" stack_trace: @@ -682,7 +682,7 @@ packages: description: name: stack_trace sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.12.1" stream_channel: @@ -690,7 +690,7 @@ packages: description: name: stream_channel sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.1.4" string_scanner: @@ -698,7 +698,7 @@ packages: description: name: string_scanner sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.4.1" table_calendar: @@ -706,7 +706,7 @@ packages: description: name: table_calendar sha256: "0c0c6219878b363a2d5f40c7afb159d845f253d061dc3c822aa0d5fe0f721982" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.2.0" term_glyph: @@ -714,7 +714,7 @@ packages: description: name: term_glyph sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.2.2" test_api: @@ -722,7 +722,7 @@ packages: description: name: test_api sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.7.4" typed_data: @@ -730,7 +730,7 @@ packages: description: name: typed_data sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.4.0" url_launcher: @@ -738,7 +738,7 @@ packages: description: name: url_launcher sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "6.3.1" url_launcher_android: @@ -746,7 +746,7 @@ packages: description: name: url_launcher_android sha256: "8582d7f6fe14d2652b4c45c9b6c14c0b678c2af2d083a11b604caeba51930d79" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "6.3.16" url_launcher_ios: @@ -754,7 +754,7 @@ packages: description: name: url_launcher_ios sha256: "7f2022359d4c099eea7df3fdf739f7d3d3b9faf3166fb1dd390775176e0b76cb" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "6.3.3" url_launcher_linux: @@ -762,7 +762,7 @@ packages: description: name: url_launcher_linux sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.2.1" url_launcher_macos: @@ -770,7 +770,7 @@ packages: description: name: url_launcher_macos sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.2.2" url_launcher_platform_interface: @@ -778,7 +778,7 @@ packages: description: name: url_launcher_platform_interface sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.3.2" url_launcher_web: @@ -786,7 +786,7 @@ packages: description: name: url_launcher_web sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.4.1" url_launcher_windows: @@ -794,7 +794,7 @@ packages: description: name: url_launcher_windows sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.1.4" vector_math: @@ -802,7 +802,7 @@ packages: description: name: vector_math sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.1.4" video_player: @@ -810,7 +810,7 @@ packages: description: name: video_player sha256: "0d55b1f1a31e5ad4c4967bfaa8ade0240b07d20ee4af1dfef5f531056512961a" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.10.0" video_player_android: @@ -818,7 +818,7 @@ packages: description: name: video_player_android sha256: "4a5135754a62dbc827a64a42ef1f8ed72c962e191c97e2d48744225c2b9ebb73" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.8.7" video_player_avfoundation: @@ -826,7 +826,7 @@ packages: description: name: video_player_avfoundation sha256: "0d47db6cbf72db61d86369219efd35c7f9d93515e1319da941ece81b1f21c49c" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.7.2" video_player_platform_interface: @@ -834,7 +834,7 @@ packages: description: name: video_player_platform_interface sha256: cf2a1d29a284db648fd66cbd18aacc157f9862d77d2cc790f6f9678a46c1db5a - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "6.4.0" video_player_web: @@ -842,7 +842,7 @@ packages: description: name: video_player_web sha256: e8bba2e5d1e159d5048c9a491bb2a7b29c535c612bb7d10c1e21107f5bd365ba - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.3.5" visibility_detector: @@ -850,23 +850,23 @@ packages: description: name: visibility_detector sha256: dd5cc11e13494f432d15939c3aa8ae76844c42b723398643ce9addb88a5ed420 - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.4.0+2" vm_service: dependency: transitive description: name: vm_service - sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 - url: "https://pub.flutter-io.cn" + sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "15.0.0" + version: "14.3.1" web: dependency: transitive description: name: web sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.1.1" webview_flutter: @@ -874,7 +874,7 @@ packages: description: name: webview_flutter sha256: c3e4fe614b1c814950ad07186007eff2f2e5dd2935eba7b9a9a1af8e5885f1ba - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "4.13.0" webview_flutter_android: @@ -882,7 +882,7 @@ packages: description: name: webview_flutter_android sha256: f6e6afef6e234801da77170f7a1847ded8450778caf2fe13979d140484be3678 - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "4.7.0" webview_flutter_platform_interface: @@ -890,7 +890,7 @@ packages: description: name: webview_flutter_platform_interface sha256: f0dc2dc3a2b1e3a6abdd6801b9355ebfeb3b8f6cde6b9dc7c9235909c4a1f147 - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.13.1" webview_flutter_wkwebview: @@ -898,7 +898,7 @@ packages: description: name: webview_flutter_wkwebview sha256: a3d461fe3467014e05f3ac4962e5fdde2a4bf44c561cb53e9ae5c586600fdbc3 - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "3.22.0" wechat_assets_picker: @@ -906,7 +906,7 @@ packages: description: name: wechat_assets_picker sha256: cafe3d32564ed3cacf9822f251941f7b44fe9885c17c8de4fca7e939a459e1ef - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "9.5.1" wechat_picker_library: @@ -914,33 +914,33 @@ packages: description: name: wechat_picker_library sha256: a42e09cb85b15fc9410f6a69671371cc60aa99c4a1f7967f6593a7f665f6f47a - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.0.5" win32: dependency: transitive description: name: win32 - sha256: "66814138c3562338d05613a6e368ed8cfb237ad6d64a9e9334be3f309acfca03" - url: "https://pub.flutter-io.cn" + sha256: "329edf97fdd893e0f1e3b9e88d6a0e627128cc17cc316a8d67fda8f1451178ba" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "5.14.0" + version: "5.13.0" win32_registry: dependency: transitive description: name: win32_registry - sha256: "21ec76dfc731550fd3e2ce7a33a9ea90b828fdf19a5c3bcf556fa992cfa99852" - url: "https://pub.flutter-io.cn" + sha256: "6f1b564492d0147b330dd794fee8f512cec4977957f310f9951b5f9d83618dae" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted - version: "1.1.5" + version: "2.1.0" xdg_directories: dependency: transitive description: name: xdg_directories sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" - url: "https://pub.flutter-io.cn" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "1.1.0" sdks: - dart: ">=3.8.0 <4.0.0" + dart: ">=3.7.0 <4.0.0" flutter: ">=3.29.0" diff --git a/test/widget_test.dart b/test/widget_test.dart index 16849aa..c903c90 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -13,7 +13,7 @@ import 'package:qhdkfq_regulatory_flutter/main.dart'; void main() { testWidgets('Counter increments smoke test', (WidgetTester tester) async { // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); + await tester.pumpWidget(const MyApp(isLoggedIn: false,)); // Verify that our counter starts at 0. expect(find.text('0'), findsOneWidget);