From 2709c1858fc13704a1adcb105848501739a558ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=8C=AF=E5=8D=87?= <359059686@qq.com> Date: Sat, 11 Oct 2025 09:26:55 +0800 Subject: [PATCH] =?UTF-8?q?feat=20:=20=E4=BC=81=E4=B8=9A=E5=88=97=E8=A1=A8?= =?UTF-8?q?UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/app/bindings/initial_binding.dart | 8 +- lib/app/routes/app_pages.dart | 2 + lib/app/routes/app_routes.dart | 2 + lib/data/providers/connectivity_provider.dart | 62 --- .../providers/network_status_service.dart | 46 ++ lib/data/repositories/auth_repository.dart | 8 +- lib/data/repositories/problem_repository.dart | 8 +- lib/main.dart | 54 +- .../auth/controllers/login_controller.dart | 17 +- .../enterprise_list_controller.dart | 113 +++++ .../enterprise_list/enterprise_list_page.dart | 280 +++++++++++ .../model/enterprise_model.dart | 19 + .../widgets/enterprise_card.dart | 272 ++++++++++ lib/modules/home/bindings/home_binding.dart | 2 + .../home/controllers/home_controller.dart | 8 +- lib/modules/home/views/home_page.dart | 109 ++-- .../controllers/problem_controller.dart | 2 +- lib/modules/test.dart | 468 ++++++++++++++++++ pubspec.lock | 62 +-- pubspec.yaml | 2 +- 20 files changed, 1343 insertions(+), 201 deletions(-) delete mode 100644 lib/data/providers/connectivity_provider.dart create mode 100644 lib/data/providers/network_status_service.dart create mode 100644 lib/modules/enterprise_list/enterprise_list_controller.dart create mode 100644 lib/modules/enterprise_list/enterprise_list_page.dart create mode 100644 lib/modules/enterprise_list/model/enterprise_model.dart create mode 100644 lib/modules/enterprise_list/widgets/enterprise_card.dart create mode 100644 lib/modules/test.dart diff --git a/lib/app/bindings/initial_binding.dart b/lib/app/bindings/initial_binding.dart index 9526088..4b91d26 100644 --- a/lib/app/bindings/initial_binding.dart +++ b/lib/app/bindings/initial_binding.dart @@ -1,6 +1,6 @@ import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; -import 'package:problem_check_system/data/providers/connectivity_provider.dart'; +import 'package:problem_check_system/data/providers/network_status_service.dart'; import 'package:problem_check_system/data/providers/http_provider.dart'; import 'package:problem_check_system/data/providers/sqlite_provider.dart'; import 'package:problem_check_system/data/repositories/auth_repository.dart'; @@ -24,7 +24,7 @@ class InitialBinding implements Bindings { Get.put(Uuid(), permanent: true); Get.put(HttpProvider()); Get.put(SQLiteProvider()); - Get.put(ConnectivityProvider()); + Get.put(NetworkStatusService()); Get.put(UpgraderService()); } @@ -39,14 +39,14 @@ class InitialBinding implements Bindings { () => AuthRepository( httpProvider: Get.find(), storage: Get.find(), - connectivityProvider: Get.find(), + networkStatusService: Get.find(), ), ); Get.lazyPut( () => ProblemRepository( sqliteProvider: Get.find(), httpProvider: Get.find(), - connectivityProvider: Get.find(), + networkStatusService: Get.find(), authRepository: Get.find(), ), ); diff --git a/lib/app/routes/app_pages.dart b/lib/app/routes/app_pages.dart index 4c80be9..2fc5472 100644 --- a/lib/app/routes/app_pages.dart +++ b/lib/app/routes/app_pages.dart @@ -8,6 +8,7 @@ import 'package:problem_check_system/modules/my/views/change_password.dart'; import 'package:problem_check_system/modules/problem/bindings/problem_form_binding.dart'; import 'package:problem_check_system/modules/problem/views/problem_form_page.dart'; import 'package:problem_check_system/modules/problem/views/problem_upload_page.dart'; +import 'package:problem_check_system/modules/test.dart'; import 'app_routes.dart'; @@ -39,5 +40,6 @@ abstract class AppPages { page: () => const ProblemFormPage(), binding: ProblemFormBinding(), ), + GetPage(name: AppRoutes.test, page: () => const HealthApp()), ]; } diff --git a/lib/app/routes/app_routes.dart b/lib/app/routes/app_routes.dart index dc498fc..74164cc 100644 --- a/lib/app/routes/app_routes.dart +++ b/lib/app/routes/app_routes.dart @@ -11,4 +11,6 @@ abstract class AppRoutes { static const problemUpload = '/problemUpload'; static const problemForm = '/problemForm'; // #endregion + + static const test = '/test'; } diff --git a/lib/data/providers/connectivity_provider.dart b/lib/data/providers/connectivity_provider.dart deleted file mode 100644 index 5ea7d83..0000000 --- a/lib/data/providers/connectivity_provider.dart +++ /dev/null @@ -1,62 +0,0 @@ -// lib/data/providers/connectivity_provider.dart -import 'dart:async'; -import 'package:connectivity_plus/connectivity_plus.dart'; -import 'package:get/get.dart'; -import 'package:flutter/material.dart'; - -class ConnectivityProvider extends GetxService { - final Connectivity _connectivity = Connectivity(); - final RxBool isOnline = false.obs; - late StreamSubscription> _connectivitySubscription; - - @override - void onInit() { - super.onInit(); - _initConnectivityListener(); - } - - @override - void onClose() { - _connectivitySubscription.cancel(); - super.onClose(); - } - - Future _initConnectivityListener() async { - _connectivitySubscription = _connectivity.onConnectivityChanged.listen(( - results, - ) { - final isConnected = results.any( - (result) => - result == ConnectivityResult.mobile || - result == ConnectivityResult.wifi || - result == ConnectivityResult.ethernet, - ); - isOnline.value = isConnected; - if (isConnected) { - Get.snackbar( - '网络状态', - '已连接到网络', - colorText: Colors.white, - backgroundColor: Colors.green, - snackPosition: SnackPosition.TOP, - ); - } else { - Get.snackbar( - '网络状态', - '已断开网络连接', - colorText: Colors.white, - backgroundColor: Colors.red, - snackPosition: SnackPosition.TOP, - ); - } - }); - - final initialResults = await _connectivity.checkConnectivity(); - isOnline.value = initialResults.any( - (result) => - result == ConnectivityResult.mobile || - result == ConnectivityResult.wifi || - result == ConnectivityResult.ethernet, - ); - } -} diff --git a/lib/data/providers/network_status_service.dart b/lib/data/providers/network_status_service.dart new file mode 100644 index 0000000..ff79937 --- /dev/null +++ b/lib/data/providers/network_status_service.dart @@ -0,0 +1,46 @@ +// lib/data/providers/connectivity_provider.dart +import 'dart:async'; +import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:get/get.dart'; + +class NetworkStatusService extends GetxService { + final Connectivity _connectivity = Connectivity(); + final RxBool isOnline = false.obs; + StreamSubscription>? _connectivitySubscription; + + @override + void onInit() { + super.onInit(); + _initConnectivityListener(); + _checkInitialConnectivity(); + } + + @override + void onClose() { + _connectivitySubscription?.cancel(); + super.onClose(); + } + + void _initConnectivityListener() { + _connectivitySubscription = _connectivity.onConnectivityChanged.listen(( + results, + ) { + isOnline.value = _isConnected(results); + // UI 层监听 isOnline.value 变化后自行处理提示 + }); + } + + Future _checkInitialConnectivity() async { + final initialResults = await _connectivity.checkConnectivity(); + isOnline.value = _isConnected(initialResults); + } + + bool _isConnected(List results) { + return results.any( + (result) => + result == ConnectivityResult.mobile || + result == ConnectivityResult.wifi || + result == ConnectivityResult.ethernet, + ); + } +} diff --git a/lib/data/repositories/auth_repository.dart b/lib/data/repositories/auth_repository.dart index d9d5484..58a478b 100644 --- a/lib/data/repositories/auth_repository.dart +++ b/lib/data/repositories/auth_repository.dart @@ -3,18 +3,18 @@ import 'package:get_storage/get_storage.dart'; import 'package:problem_check_system/core/utils/constants/api_endpoints.dart'; import 'package:problem_check_system/data/models/auth_model.dart'; import 'package:problem_check_system/data/models/user/user.dart'; -import 'package:problem_check_system/data/providers/connectivity_provider.dart'; +import 'package:problem_check_system/data/providers/network_status_service.dart'; import 'package:problem_check_system/data/providers/http_provider.dart'; class AuthRepository extends GetxService { final HttpProvider httpProvider; final GetStorage storage; - final ConnectivityProvider connectivityProvider; + final NetworkStatusService networkStatusService; AuthRepository({ required this.httpProvider, required this.storage, - required this.connectivityProvider, + required this.networkStatusService, }); static const String _tokenKey = 'token'; @@ -84,7 +84,7 @@ class AuthRepository extends GetxService { // 是否在线 bool get isOnline { - return connectivityProvider.isOnline.value; + return networkStatusService.isOnline.value; } /// Check if a user is currently logged in by verifying the existence of a token. diff --git a/lib/data/repositories/problem_repository.dart b/lib/data/repositories/problem_repository.dart index 7713c80..5a2aefc 100644 --- a/lib/data/repositories/problem_repository.dart +++ b/lib/data/repositories/problem_repository.dart @@ -4,7 +4,7 @@ import 'package:problem_check_system/core/extensions/http_response_extension.dar import 'package:problem_check_system/core/utils/constants/api_endpoints.dart'; import 'package:problem_check_system/data/models/problem_model.dart'; import 'package:problem_check_system/data/models/server_problem.dart'; -import 'package:problem_check_system/data/providers/connectivity_provider.dart'; +import 'package:problem_check_system/data/providers/network_status_service.dart'; import 'package:problem_check_system/data/providers/http_provider.dart'; import 'package:problem_check_system/data/providers/sqlite_provider.dart'; import 'package:problem_check_system/data/repositories/auth_repository.dart'; @@ -14,15 +14,15 @@ import 'package:problem_check_system/data/repositories/auth_repository.dart'; class ProblemRepository extends GetxService { final SQLiteProvider sqliteProvider; final HttpProvider httpProvider; - final ConnectivityProvider connectivityProvider; + final NetworkStatusService networkStatusService; final AuthRepository authRepository; - RxBool get isOnline => connectivityProvider.isOnline; + RxBool get isOnline => networkStatusService.isOnline; ProblemRepository({ required this.sqliteProvider, required this.httpProvider, - required this.connectivityProvider, + required this.networkStatusService, required this.authRepository, }); diff --git a/lib/main.dart b/lib/main.dart index 8aae613..fff08da 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -11,11 +11,11 @@ import 'package:flutter_localizations/flutter_localizations.dart'; void main() async { // 确保 Flutter Binding 已初始化 WidgetsFlutterBinding.ensureInitialized(); - // // 设置应用为竖屏模式 - // SystemChrome.setPreferredOrientations([ - // DeviceOrientation.portraitUp, - // DeviceOrientation.portraitDown, - // ]); + // 设置应用为竖屏模式 + SystemChrome.setPreferredOrientations([ + DeviceOrientation.portraitUp, + DeviceOrientation.portraitDown, + ]); // 初始化 GetStorage,这是关键步骤 await GetStorage.init(); // Add this line @@ -51,7 +51,49 @@ class MainApp extends StatelessWidget { Locale('zh', 'CN'), // 支持中文 ], title: '问题检查系统', // 使用更有意义的应用标题 - theme: ThemeData(useMaterial3: true, primarySwatch: Colors.blue), + theme: ThemeData( + useMaterial3: true, + + // 【推荐】使用 colorSchemeSeed 从一个种子颜色生成完整的 M3 调色板 + colorScheme: ColorScheme.fromSeed( + seedColor: const Color(0xFF3B82F6), + ), + + // (可选) 如果想进一步定制 NavigationBar 的主题 + navigationBarTheme: NavigationBarThemeData( + // 1. 在主题中设置你想要的高度 + height: 48, // 比如我们想让它更高,设置为 70 + // 2. 【关键】增大图标尺寸,让内容撑满新高度 + // 使用 MaterialStateProperty.resolveWith 来响应不同状态(如下拉、聚焦等) + iconTheme: WidgetStateProperty.resolveWith((states) { + // 你可以根据状态返回不同的 IconThemeData + return IconThemeData( + size: 24, // 将图标大小从默认的 24 增大到 28 + ); + }), + // 标签行为:控制标签是否总是显示 + labelBehavior: + NavigationDestinationLabelBehavior.onlyShowSelected, + // backgroundColor: Colors.white, + // 指示器的颜色 + indicatorColor: const Color.fromARGB(88, 19, 214, 12), + // 【核心】使用 indicatorShape 属性并传入我们的自定义类 + // indicatorShape: const CustomIndicatorShape( + // // 在这里调整你想要的宽度 + // // horizontalPadding: 24.0, // 让指示器变得更窄 + // // horizontalPadding: 8.0, // 让指示器变得更宽 + // horizontalPadding: 0, // 让指示器宽度接近内容宽度 + // ), + // 标签文本样式 + labelTextStyle: WidgetStateProperty.all( + TextStyle( + fontSize: 12.sp, + fontWeight: FontWeight.w500, + color: Colors.blue, + ), + ), + ), + ), // 仅使用 GetX 路由系统 initialRoute: AppRoutes.login, // 使用路由常量作为初始页面 initialBinding: InitialBinding(), // 如果有全局绑定,继续保留 diff --git a/lib/modules/auth/controllers/login_controller.dart b/lib/modules/auth/controllers/login_controller.dart index 2187c6c..e82b27a 100644 --- a/lib/modules/auth/controllers/login_controller.dart +++ b/lib/modules/auth/controllers/login_controller.dart @@ -79,12 +79,19 @@ class LoginController extends GetxController { _authRepository.saveUserId(user.id!); } } on DioException catch (e) { - // 捕获由拦截器处理后抛出的 DioException - // 拦截器已经显示了 Snackbar,这里你可以做其他业务处理,例如清空表单等。 - debugPrint('登录失败,由DioException捕获: ${e.message}'); + Get.snackbar( + '请求失败', + e.error.toString(), + backgroundColor: Colors.red, + colorText: Colors.white, + ); } catch (e) { - // 捕获其他非 DioException 异常 - debugPrint('发生未知错误: $e'); + Get.snackbar( + '请求失败', + e.toString(), + backgroundColor: Colors.red, + colorText: Colors.white, + ); } } diff --git a/lib/modules/enterprise_list/enterprise_list_controller.dart b/lib/modules/enterprise_list/enterprise_list_controller.dart new file mode 100644 index 0000000..a3c3d8e --- /dev/null +++ b/lib/modules/enterprise_list/enterprise_list_controller.dart @@ -0,0 +1,113 @@ +// lib/app/modules/enterprise_list/enterprise_list_controller.dart + +import 'package:get/get.dart'; +import 'package:problem_check_system/modules/enterprise_list/model/enterprise_model.dart'; + +class EnterpriseListController extends GetxController { + // 使用 .obs 使列表变为响应式,当数据变化时,UI会自动更新 + final enterpriseList = [].obs; + + @override + void onInit() { + super.onInit(); + fetchEnterprises(); // 页面初始化时加载数据 + } + + // 模拟从API获取数据的过程 + void fetchEnterprises() { + // 模拟网络延迟 + Future.delayed(const Duration(milliseconds: 500), () { + // 创建一些示例数据 + var mockData = [ + Enterprise( + companyName: '山东汇丰石化集团有限公司', + companyType: '危险化学品生产', + totalIssues: 29, + creationTime: '2025-07-31 15:30:29', + uploaded: 15, + notUploaded: 14, + ), + Enterprise( + companyName: '山东荣源石化集团有限公司', + companyType: '危险化学品生产', + totalIssues: 29, + creationTime: '2025-07-31 15:30:29', + uploaded: 15, + notUploaded: 14, + ), + Enterprise( + companyName: '山东江潜石化集团有限公司', + companyType: '危险化学品生产', + totalIssues: 29, + creationTime: '2025-07-31 15:30:29', + uploaded: 15, + notUploaded: 14, + ), + Enterprise( + companyName: '山东汇绿武化集团有限公司', + companyType: '危险化学品生产', + totalIssues: 29, + creationTime: '2025-07-31 15:30:29', + uploaded: 15, + notUploaded: 14, + ), + Enterprise( + companyName: '山东汇绿武化集团有限公司', + companyType: '危险化学品生产', + totalIssues: 29, + creationTime: '2025-07-31 15:30:29', + uploaded: 15, + notUploaded: 14, + ), + Enterprise( + companyName: '山东汇绿武化集团有限公司', + companyType: '危险化学品生产', + totalIssues: 29, + creationTime: '2025-07-31 15:30:29', + uploaded: 15, + notUploaded: 14, + ), + Enterprise( + companyName: '山东汇绿武化集团有限公司', + companyType: '危险化学品生产', + totalIssues: 29, + creationTime: '2025-07-31 15:30:29', + uploaded: 15, + notUploaded: 14, + ), + Enterprise( + companyName: '山东汇绿武化集团有限公司', + companyType: '危险化学品生产', + totalIssues: 29, + creationTime: '2025-07-31 15:30:29', + uploaded: 15, + notUploaded: 14, + ), + Enterprise( + companyName: '山东汇绿武化集团有限公司', + companyType: '危险化学品生产', + totalIssues: 29, + creationTime: '2025-07-31 15:30:29', + uploaded: 15, + notUploaded: 14, + ), + ]; + enterpriseList.assignAll(mockData); // 更新列表 + }); + } + + // 可以在这里添加其他业务逻辑,例如: + void onSearch() { + // 处理搜索逻辑 + } + + void onAddNew() { + // 处理添加新条目的逻辑 + Get.snackbar('提示', '添加功能待实现'); + } + + void onUpload() { + // 处理上传逻辑 + Get.snackbar('提示', '上传功能待实现'); + } +} diff --git a/lib/modules/enterprise_list/enterprise_list_page.dart b/lib/modules/enterprise_list/enterprise_list_page.dart new file mode 100644 index 0000000..3a2ff5e --- /dev/null +++ b/lib/modules/enterprise_list/enterprise_list_page.dart @@ -0,0 +1,280 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:problem_check_system/modules/enterprise_list/model/enterprise_model.dart'; +import 'package:problem_check_system/modules/enterprise_list/widgets/enterprise_card.dart'; +import 'enterprise_list_controller.dart'; + +class EnterpriseListPage extends GetView { + const EnterpriseListPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text( + '企业列表', + style: TextStyle( + fontWeight: FontWeight.bold, + fontFamily: 'MyFont', + fontSize: 18.sp, + color: Colors.white, + ), + ), + backgroundColor: const Color(0xFF3B82F6), + elevation: 0, + centerTitle: true, + actions: [ + IconButton( + icon: Icon(Icons.add, color: Colors.white), // 使用 .sp + onPressed: () { + // 处理筛选按钮点击事件 + }, + ), + IconButton( + icon: Icon(Icons.upload, color: Colors.pink[300]), // 使用 .sp + onPressed: () { + // 处理筛选按钮点击事件 + }, + ), + ], + ), + body: Stack( + children: [ + Column( + children: [ + _buildFilterBar(), + // 使用 Obx 包裹需要响应式更新的 Widget + Expanded( + child: Obx(() { + if (controller.enterpriseList.isEmpty) { + return const Center(child: CircularProgressIndicator()); + } + return ListView.builder( + padding: EdgeInsets.symmetric( + horizontal: 16.w, // 使用 .w + vertical: 8.h, // 使用 .h + ), + itemCount: controller.enterpriseList.length, + itemBuilder: (context, index) { + final enterprise = controller.enterpriseList[index]; + return Padding( + padding: EdgeInsets.only(bottom: 12.h), // 使用 .h + // child: _EnterpriseCard(enterprise: enterprise), + child: EnterpriseCard(), + ); + }, + ); + }), + ), + ], + ), + ], + ), + ); + } + + Widget _buildFilterBar() { + return Container( + padding: EdgeInsets.fromLTRB(16.w, 12.h, 16.w, 12.h), // 使用 .w 和 .h + color: Colors.white, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Row( + children: [ + const Text('企业名称', style: TextStyle(color: Colors.black54)), + SizedBox(width: 4.w), // 使用 .w + Icon( + Icons.search, + size: 20.sp, + color: Colors.black54, + ), // 使用 .sp + ], + ), + ), + _buildDropdown('选择日期'), + _buildDropdown('近一周'), + _buildDropdown('类型'), + ], + ), + ); + } + + Widget _buildDropdown(String text) { + return Padding( + padding: EdgeInsets.symmetric(horizontal: 8.w), // 使用 .w + child: Row( + children: [ + Text(text, style: const TextStyle(color: Colors.black54)), + const Icon(Icons.arrow_drop_down, color: Colors.black54), + ], + ), + ); + } +} + +class _EnterpriseCard extends StatelessWidget { + final Enterprise enterprise; + const _EnterpriseCard({required this.enterprise}); + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.all(16.r), // 使用 .r 保证四边 padding 比例一致 + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8.r), // 使用 .r + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '企业名称', + style: TextStyle(fontSize: 9.sp, color: Colors.grey), + ), + SizedBox(height: 4.h), // 使用 .h + Text( + enterprise.companyName, + style: TextStyle( + fontSize: 12.5.sp, + fontWeight: FontWeight.w500, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ], + ), + + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '企业类型', + style: TextStyle(fontSize: 9.sp, color: Colors.grey), + ), + SizedBox(height: 4.h), // 使用 .h + Text( + enterprise.companyType, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 12.5.sp, + fontWeight: FontWeight.w500, + ), + ), + ], + ), + + Container( + padding: EdgeInsets.symmetric( + horizontal: 5.w, + vertical: 2.h, + ), // 使用 .w 和 .h + decoration: BoxDecoration( + // color: Colors.orange[100], + borderRadius: BorderRadius.circular(10.r), // 使用 .r + border: Border.all(color: Colors.red), + ), + child: Text( + '信息未上传', + maxLines: 1, + style: TextStyle(fontSize: 9.sp, color: Colors.red), // 使用 .sp + ), + ), + ], + ), + SizedBox(height: 16.h), // 使用 .h + Row( + children: [ + Icon( + Icons.description, + size: 16.sp, + color: Colors.grey, + ), // 使用 .sp + SizedBox(width: 4.w), // 使用 .w + Text( + '问题总数: ${enterprise.totalIssues}', + style: TextStyle(fontSize: 12.sp, color: Colors.grey), // 使用 .sp + ), + SizedBox(width: 16.w), // 使用 .w + Icon( + Icons.access_time, + size: 16.sp, + color: Colors.grey, + ), // 使用 .sp + SizedBox(width: 4.w), // 使用 .w + Text( + '创建时间: ${enterprise.creationTime}', + style: TextStyle(fontSize: 12.sp, color: Colors.grey), // 使用 .sp + ), + ], + ), + // SizedBox(height: 16.h), // 使用 .h + Row( + children: [ + _buildTag('已上传 ${enterprise.uploaded}', Colors.blue), + SizedBox(width: 8.w), // 使用 .w + _buildTag('未上传 ${enterprise.notUploaded}', Colors.red), + const Spacer(), + Icon(Icons.edit, size: 16.sp, color: Colors.grey), // 使用 .sp + SizedBox(width: 4.w), // 使用 .w + Text( + '修改信息', + style: TextStyle( + fontSize: 9.5.sp, + color: Colors.grey, + ), // 使用 .sp + ), + SizedBox(width: 16.w), // 使用 .w + ElevatedButton( + onPressed: () {}, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF3B82F6), + + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(4.r), // 使用 .r + ), + // padding: EdgeInsets.symmetric( + // horizontal: 16.w, // 使用 .w + // vertical: 8.h, // 使用 .h + // ), + // tapTargetSize: MaterialTapTargetSize.shrinkWrap, + ), + child: const Text( + '查看问题', + style: TextStyle(color: Colors.white), + ), + ), + ], + ), + ], + ), + ); + } + + Widget _buildTag(String text, Color color) { + return Container( + padding: EdgeInsets.symmetric( + horizontal: 6.w, + vertical: 2.h, + ), // 使用 .w 和 .h + decoration: BoxDecoration( + color: color.withOpacity(0.1), + borderRadius: BorderRadius.circular(4.r), // 使用 .r + ), + child: Text( + text, + style: TextStyle(color: color, fontSize: 8.5.sp), + ), // 使用 .sp + ); + } +} diff --git a/lib/modules/enterprise_list/model/enterprise_model.dart b/lib/modules/enterprise_list/model/enterprise_model.dart new file mode 100644 index 0000000..7802e33 --- /dev/null +++ b/lib/modules/enterprise_list/model/enterprise_model.dart @@ -0,0 +1,19 @@ +// lib/app/modules/enterprise_list/models/enterprise_model.dart + +class Enterprise { + final String companyName; + final String companyType; + final int totalIssues; + final String creationTime; + final int uploaded; + final int notUploaded; + + Enterprise({ + required this.companyName, + required this.companyType, + required this.totalIssues, + required this.creationTime, + required this.uploaded, + required this.notUploaded, + }); +} diff --git a/lib/modules/enterprise_list/widgets/enterprise_card.dart b/lib/modules/enterprise_list/widgets/enterprise_card.dart new file mode 100644 index 0000000..03a8537 --- /dev/null +++ b/lib/modules/enterprise_list/widgets/enterprise_card.dart @@ -0,0 +1,272 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +// 主卡片组件 +class EnterpriseCard extends StatelessWidget { + const EnterpriseCard({super.key}); + + @override + Widget build(BuildContext context) { + return Material( + color: Colors.transparent, + child: Container( + // 【核心修改 1】移除 Container 的 padding + // padding: EdgeInsets.only(...), // <--- 移除这一段 + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12.r), + border: Border.all(color: Colors.grey.shade300, width: 1.w), + ), + // 【核心修改 2】使用 Clip.antiAlias 来剪裁溢出的按钮部分 + clipBehavior: Clip.antiAlias, + child: Stack( + // Stack 默认会填满父组件(Container) + children: [ + // --- 内容层 --- + // 【核心修改 3】使用 Padding 在 Stack 内部创建内边距 + Padding( + padding: EdgeInsets.only( + left: 16.w, + right: 16.w, + top: 16.h, + // 底部 padding 需要足够大,为按钮留出空间 + bottom: 0.h, + ), + child: Column( + // 让 Column 包裹内容,避免不必要的高度 + mainAxisSize: MainAxisSize.min, + children: [ + _buildTopSection(), + SizedBox(height: 12.h), + _buildMiddleSection(), + SizedBox(height: 12.h), + _buildBottomSection(context), + ], + ), + ), + + // --- 按钮层 --- + // 【核心修改 4】修改 Positioned 的定位 + Positioned( + bottom: 0, // 相对于卡片底部 + right: 0, // 相对于卡片右侧 + child: Row( + children: [ + // --- “修改信息” 按钮 --- + TextButton.icon( + onPressed: () { + print('修改信息按钮被点击'); + }, + icon: Icon(Icons.edit_outlined, size: 16.sp), + label: Text('修改信息', style: TextStyle(fontSize: 9.5.sp)), + style: TextButton.styleFrom( + foregroundColor: Colors.grey.shade600, + padding: EdgeInsets.symmetric( + horizontal: 16.w, + vertical: 8.h, + ), + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + minimumSize: const Size(0, 0), + ), + ), + // --- “查看问题” 按钮 --- + ElevatedButton( + onPressed: () { + print('查看问题按钮被点击'); + }, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF42A5F5), + foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(12.r), + // 注意:右下角因为贴边,不再需要圆角,否则会有缝隙 + // bottomRight: Radius.circular(12.r), + ), + ), + padding: EdgeInsets.symmetric( + horizontal: 16.w, + vertical: 8.h, + ), + // elevation: 0, // 移除阴影,因为它已经被剪裁了 + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + minimumSize: const Size(0, 0), + ), + child: Text( + "查看问题", + style: TextStyle( + fontSize: 13.sp, + fontWeight: FontWeight.w500, + ), + ), + ), + ], + ), + ), + ], + ), + ), + ); + } + + /// 构建顶部区域:企业名称、类型和状态 + Widget _buildTopSection() { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '企业名称', + style: TextStyle( + fontSize: 9.sp, + color: Colors.grey.shade500, + ), // .sp 适配字体 + ), + SizedBox(height: 4.h), // .h 适配垂直间距 + Text( + '山东汇丰石化集团有限公司', + style: TextStyle( + fontSize: 12.5.sp, + fontWeight: FontWeight.w500, + color: Colors.black87, + ), + overflow: TextOverflow.ellipsis, + ), + ], + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '企业类型', + style: TextStyle(fontSize: 9.sp, color: Colors.grey.shade500), + ), + SizedBox(height: 4.h), + Text( + '危险化学品生产', + style: TextStyle( + fontSize: 12.5.sp, + fontWeight: FontWeight.w500, + color: Colors.black87, + ), + overflow: TextOverflow.ellipsis, + ), + ], + ), + // SizedBox(width: 8.w), + Container( + padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 3.h), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8.r), + border: Border.all(color: Colors.red.shade400, width: 1.w), + ), + child: Text( + '信息未上传', + style: TextStyle(fontSize: 7.sp, color: Colors.red.shade400), + ), + ), + ], + ); + } + + /// 构建中间区域:问题总数和创建时间 + Widget _buildMiddleSection() { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Icon(Icons.description_outlined, color: Colors.grey, size: 16.sp), + SizedBox(width: 4.w), + Text( + '问题总数: ', + style: TextStyle(fontSize: 12.sp, color: Colors.grey), + ), + Text( + '29', + style: TextStyle( + fontSize: 12.5.sp, + color: Colors.black87, + fontWeight: FontWeight.w500, + ), + ), + ], + ), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Icon(Icons.access_time, color: Colors.grey, size: 16.sp), + Text( + '创建时间: 2025-07-31 15:30:29', + style: TextStyle(fontSize: 12.sp, color: Colors.grey), + ), + ], + ), + ], + ); + } + + /// 构建底部区域:标签和复选框 + Widget _buildBottomSection(BuildContext context) { + return Row( + children: [ + _buildTag( + text: '已上传 15', + textColor: Colors.blue.shade700, + backgroundColor: Colors.blue.shade50, + ), + SizedBox(width: 8.w), + _buildTag( + text: '未上传 14', + textColor: Colors.red.shade600, + backgroundColor: Colors.red.shade50, + ), + const Spacer(), + + Theme( + data: Theme.of(context).copyWith( + checkboxTheme: CheckboxThemeData( + // 将点击区域收缩,移除额外的 padding + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + // (可选) 进一步压缩视觉密度 + visualDensity: VisualDensity.compact, + ), + ), + child: Checkbox( + value: true, + onChanged: (bool? value) {}, + // 其他属性... + ), + ), + ], + ); + } + + /// 用于创建“已上传”和“未上传”标签的辅助方法 + Widget _buildTag({ + required String text, + required Color textColor, + required Color backgroundColor, + }) { + return Container( + padding: EdgeInsets.symmetric(horizontal: 6.w, vertical: 2.h), + decoration: BoxDecoration( + color: backgroundColor, + // borderRadius: BorderRadius.circular(4.r), + // border: Border.all(color: textColor.withAlpha(128), width: 1.w), + ), + child: Text( + text, + style: TextStyle( + color: textColor, + fontSize: 10.sp, + fontWeight: FontWeight.w500, + ), + ), + ); + } +} diff --git a/lib/modules/home/bindings/home_binding.dart b/lib/modules/home/bindings/home_binding.dart index c441c3b..80d7e13 100644 --- a/lib/modules/home/bindings/home_binding.dart +++ b/lib/modules/home/bindings/home_binding.dart @@ -2,6 +2,7 @@ import 'package:get/get.dart'; import 'package:problem_check_system/data/models/problem_sync_status.dart'; import 'package:problem_check_system/data/repositories/auth_repository.dart'; import 'package:problem_check_system/data/repositories/problem_repository.dart'; +import 'package:problem_check_system/modules/enterprise_list/enterprise_list_controller.dart'; import 'package:problem_check_system/modules/home/controllers/home_controller.dart'; import 'package:problem_check_system/modules/my/controllers/my_controller.dart'; import 'package:problem_check_system/modules/problem/controllers/problem_controller.dart'; @@ -12,6 +13,7 @@ class HomeBinding implements Bindings { /// 注册主页控制器 Get.lazyPut(() => HomeController()); Get.put(ProblemStateManager(uuid: Get.find(), authRepository: Get.find())); + Get.lazyPut(() => EnterpriseListController()); /// 注册问题控制器 Get.lazyPut( diff --git a/lib/modules/home/controllers/home_controller.dart b/lib/modules/home/controllers/home_controller.dart index b6b7c5a..37e8831 100644 --- a/lib/modules/home/controllers/home_controller.dart +++ b/lib/modules/home/controllers/home_controller.dart @@ -1,20 +1,18 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:problem_check_system/modules/enterprise_list/enterprise_list_page.dart'; import 'package:problem_check_system/modules/my/views/my_page.dart'; import 'package:problem_check_system/modules/problem/views/problem_page.dart'; class HomeController extends GetxController { - // 使用 Rx 类型管理响应式状态 var selectedIndex = 0.obs; - // 页面列表 final List pages = [ - // const Center(child: Text('首页内容')), - const ProblemPage(), // 使用 const 确保子页面不会频繁重建 + const EnterpriseListPage(), + const ProblemPage(), const MyPage(), ]; - // 改变选中索引,这个方法将由 NavigationBar 调用 void changeIndex(int index) { selectedIndex.value = index; } diff --git a/lib/modules/home/views/home_page.dart b/lib/modules/home/views/home_page.dart index 105fc4d..d28ac11 100644 --- a/lib/modules/home/views/home_page.dart +++ b/lib/modules/home/views/home_page.dart @@ -1,7 +1,8 @@ +// lib/modules/home/views/home_page.dart + import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:problem_check_system/modules/home/controllers/home_controller.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; class HomePage extends GetView { const HomePage({super.key}); @@ -11,86 +12,38 @@ class HomePage extends GetView { return Obx( () => Scaffold( body: controller.pages[controller.selectedIndex.value], - bottomNavigationBar: _buildCustomBottomBar(), - ), - ); - } - Widget _buildCustomBottomBar() { - return Container( - height: 60.h, // 自定义高度 - decoration: BoxDecoration( - color: Colors.white, - boxShadow: [ - BoxShadow( - color: Colors.grey.withAlpha(76), - blurRadius: 8, - offset: const Offset(0, -2), - ), - ], - ), - child: Row( - children: [ - // 首页项(已注释) - // _buildBottomBarItem( - // index: 0, - // icon: Icons.home_outlined, - // activeIcon: Icons.home, - // label: '首页', - // ), - _buildBottomBarItem( - index: 0, - icon: Icons.description_outlined, - activeIcon: Icons.description, - label: '问题', - ), - _buildBottomBarItem( - index: 1, - icon: Icons.person_outlined, - activeIcon: Icons.person, - label: '我的', - ), - ], - ), - ); - } + // 1. 将 BottomNavigationBar 替换为 NavigationBar + bottomNavigationBar: NavigationBar( + // 2. 将 'currentIndex' 属性重命名为 'selectedIndex' + selectedIndex: controller.selectedIndex.value, + + // 3. 将 'onTap' 属性重命名为 'onDestinationSelected' + onDestinationSelected: controller.changeIndex, - Widget _buildBottomBarItem({ - required int index, - required IconData icon, - required IconData activeIcon, - required String label, - }) { - bool isSelected = controller.selectedIndex.value == index; + // M3 风格调整 (可选, 但推荐) + // 动画时长 + animationDuration: const Duration(milliseconds: 800), - return Expanded( - child: GestureDetector( - onTap: () => controller.changeIndex(index), - child: Container( - color: Colors.transparent, // 透明背景,无点击效果 - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - isSelected ? activeIcon : icon, - color: isSelected - ? const Color(0xFF418CFC) - : Colors.grey.shade600, - size: 24.w, - ), - SizedBox(width: 4.w), // 图标和文字之间的间距 - Text( - label, - style: TextStyle( - fontSize: 14.sp, - color: isSelected - ? const Color(0xFF418CFC) - : Colors.grey.shade600, - fontWeight: isSelected ? FontWeight.w500 : FontWeight.normal, - ), - ), - ], - ), + // 4. 将 'items' 替换为 'destinations',并使用 NavigationDestination + destinations: const [ + NavigationDestination( + // M3 的一个重要特性是区分选中和未选中的图标 + icon: Icon(Icons.home_outlined, color: Colors.blue), + selectedIcon: Icon(Icons.home, color: Colors.blue), + label: '企业', + ), + NavigationDestination( + icon: Icon(Icons.now_widgets_outlined, color: Colors.orange), + selectedIcon: Icon(Icons.now_widgets, color: Colors.orange), + label: '全部问题', + ), + NavigationDestination( + icon: Icon(Icons.person_outline, color: Colors.cyan), + selectedIcon: Icon(Icons.person, color: Colors.cyan), + label: '我的', + ), + ], ), ), ); diff --git a/lib/modules/problem/controllers/problem_controller.dart b/lib/modules/problem/controllers/problem_controller.dart index e8390d3..3b3c4d8 100644 --- a/lib/modules/problem/controllers/problem_controller.dart +++ b/lib/modules/problem/controllers/problem_controller.dart @@ -832,7 +832,7 @@ class ProblemController extends GetxController final DateTimeRange? picked = await showDateRangePicker( context: context, - firstDate: DateTime(2025, 8, 1), // 可选的最早日期 + firstDate: DateTime(2024, 8, 1), // 可选的最早日期 lastDate: DateTime(2101), // 可选的最晚日期 initialDateRange: initialDateRange, ); diff --git a/lib/modules/test.dart b/lib/modules/test.dart new file mode 100644 index 0000000..d2f5f88 --- /dev/null +++ b/lib/modules/test.dart @@ -0,0 +1,468 @@ +import 'package:flutter/material.dart'; + +class HealthApp extends StatelessWidget { + const HealthApp({super.key}); + + @override + Widget build(BuildContext context) { + return HomePage1(); + } +} + +class HomePage1 extends StatefulWidget { + const HomePage1({super.key}); + + @override + State createState() => _HomePageState(); +} + +class _HomePageState extends State + with SingleTickerProviderStateMixin { + late TabController _tabController; + int _bottomNavIndex = 0; + + @override + void initState() { + super.initState(); + _tabController = TabController(length: 3, vsync: this); + } + + @override + void dispose() { + _tabController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: _buildAppBar(), + body: SingleChildScrollView( + child: Column( + children: [ + // _buildSearchBar(), + // _buildServicesGrid(), + const SizedBox(height: 12), + // _buildHealthManagementCard(), + const SizedBox(height: 12), + // _buildDoctorBanner(), + const SizedBox(height: 12), + // _buildPopularServices(), + ], + ), + ), + // bottomNavigationBar: _buildBottomNavigationBar(), + ); + } + + // 构建顶部 AppBar + PreferredSizeWidget _buildAppBar() { + return AppBar( + backgroundColor: Colors.blue, + elevation: 0, + leading: SizedBox(), + title: const Center( + child: Text( + '企业列表', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontFamily: 'MyFont', + ), + ), + ), + actions: [ + // IconButton( + // onPressed: () {}, + // icon: const Icon(Icons.widgets_outlined, color: Colors.black), + // ), + IconButton( + onPressed: () {}, + icon: const Icon(Icons.add, color: Colors.white), + ), + ], + bottom: TabBar( + controller: _tabController, + isScrollable: true, + labelColor: Colors.black, + unselectedLabelColor: Colors.grey[700], + indicatorColor: Colors.blue, + indicatorWeight: 3, + tabs: const [ + Tab(text: '问题列表'), + Tab(text: '历史问题列表'), + Tab(text: '企业基本情况'), + ], + ), + ); + } + + // 构建顶部 AppBar + PreferredSizeWidget _buildAppBar2() { + return AppBar( + backgroundColor: Colors.lightBlue[50], + elevation: 0, + leading: const Icon(Icons.arrow_back_ios, color: Colors.black), + title: const Center( + child: Text( + '企业列表', + style: TextStyle(color: Colors.black, fontWeight: FontWeight.bold), + ), + ), + actions: [ + // IconButton( + // onPressed: () {}, + // icon: const Icon(Icons.widgets_outlined, color: Colors.black), + // ), + IconButton( + onPressed: () {}, + icon: const Icon(Icons.add, color: Colors.black), + ), + ], + bottom: TabBar( + controller: _tabController, + isScrollable: true, + labelColor: Colors.black, + unselectedLabelColor: Colors.grey[700], + indicatorColor: Colors.blue, + indicatorWeight: 3, + tabs: const [ + Tab(text: '问题列表'), + Tab(text: '历史问题列表'), + Tab(text: '企业基本情况'), + ], + ), + ); + } + + // 构建搜索框 + Widget _buildSearchBar() { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + color: Colors.lightBlue[50], + child: Row( + children: [ + const Text('淄博', style: TextStyle(fontSize: 16)), + const Icon(Icons.arrow_drop_down), + const SizedBox(width: 8), + Expanded( + child: Container( + height: 40, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(20), + ), + child: const TextField( + decoration: InputDecoration( + hintText: '家庭共济', + prefixIcon: Icon(Icons.search, color: Colors.grey), + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric(vertical: 10), + ), + ), + ), + ), + TextButton( + onPressed: () {}, + child: const Text( + '搜索', + style: TextStyle(color: Colors.black, fontSize: 16), + ), + ), + ], + ), + ); + } + + // 构建功能网格 + Widget _buildServicesGrid() { + // 辅助函数创建单个网格项 + Widget buildGridItem( + IconData icon, + String label, { + bool isSpecial = false, + }) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Stack( + alignment: Alignment.topRight, + children: [ + Icon(icon, size: 40, color: Colors.blue), + if (isSpecial) + Container( + padding: const EdgeInsets.symmetric( + horizontal: 4, + vertical: 1, + ), + decoration: BoxDecoration( + color: Colors.red, + borderRadius: BorderRadius.circular(8), + ), + child: const Text( + '正品药', + style: TextStyle(color: Colors.white, fontSize: 8), + ), + ), + ], + ), + const SizedBox(height: 8), + Text(label, style: const TextStyle(fontSize: 12)), + ], + ); + } + + return Container( + color: Colors.lightBlue[50], + padding: const EdgeInsets.fromLTRB(16, 16, 16, 24), + child: GridView.count( + crossAxisCount: 5, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + children: [ + buildGridItem(Icons.qr_code_scanner, '医保码'), + buildGridItem(Icons.add_box, '挂号'), + buildGridItem(Icons.person, '问诊'), + buildGridItem(Icons.medical_services, '买药', isSpecial: true), + buildGridItem(Icons.shield, '健康保障'), + buildGridItem(Icons.local_hospital, '好药源选'), + buildGridItem(Icons.health_and_safety, '体检'), + buildGridItem(Icons.mood, '口腔'), + buildGridItem(Icons.grass, '中医'), + buildGridItem(Icons.apps, '全部服务'), + ], + ), + ); + } + + // 构建健康管理卡片 + Widget _buildHealthManagementCard() { + return Container( + margin: const EdgeInsets.symmetric(horizontal: 16), + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + '我的健康管理', + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16), + ), + const SizedBox(height: 12), + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.blue.withOpacity(0.1), + borderRadius: BorderRadius.circular(8), + ), + child: Row( + children: [ + const Icon(Icons.warning_amber_rounded, color: Colors.orange), + const SizedBox(width: 8), + const Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '你的补充医保待激活', + style: TextStyle(fontWeight: FontWeight.bold), + ), + Text( + '√ 医保内外都能报 √ 带病投保首选', + style: TextStyle(color: Colors.grey, fontSize: 12), + ), + ], + ), + ), + ElevatedButton( + onPressed: () {}, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.orange, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18.0), + ), + ), + child: const Text('去激活'), + ), + ], + ), + ), + ], + ), + ); + } + + // 构建医生问诊横幅 + Widget _buildDoctorBanner() { + return Container( + margin: const EdgeInsets.symmetric(horizontal: 16), + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + image: const DecorationImage( + // 模拟医生背景图 + image: NetworkImage( + 'https://img.tukuppt.com/png_preview/00/34/83/8fT4fFFaLg.jpg!/fw/780', + ), // 使用一个示例医生图片 URL + fit: BoxFit.cover, + alignment: Alignment.centerRight, + opacity: 0.8, + ), + ), + child: const Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '三甲医生快速问诊', + style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + SizedBox(height: 4), + Text('100%公立医生 不限制问诊次数', style: TextStyle(color: Colors.grey)), + ], + ), + // 医生图片通过 DecorationImage 实现 + ], + ), + ); + } + + // 构建热门服务部分 + Widget _buildPopularServices() { + return Container( + margin: const EdgeInsets.symmetric(horizontal: 16), + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + ), + child: Column( + children: [ + const Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '热门服务', + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16), + ), + Text('专病专科', style: TextStyle(color: Colors.grey)), + Text('健康百科', style: TextStyle(color: Colors.grey)), + Row( + children: [ + Text('更多', style: TextStyle(color: Colors.grey)), + Icon(Icons.arrow_forward_ios, size: 12, color: Colors.grey), + ], + ), + ], + ), + const SizedBox(height: 16), + Row( + children: [ + _buildServiceCard( + '百万医疗险', + '600万医疗保障', + Icons.add_to_photos, + Colors.blue, + ), + const SizedBox(width: 12), + _buildServiceCard( + '百万住院保障', + '医保内外都可报', + Icons.security, + Colors.cyan, + ), + ], + ), + const SizedBox(height: 12), + Row( + children: [ + _buildServiceCard( + '医保种牙', + '种植牙方案科普', + Icons.mood, + Colors.lightBlue, + ), + const SizedBox(width: 12), + _buildServiceCard( + '我的家', + '家人健康我守护', + Icons.home, + Colors.purpleAccent, + ), + ], + ), + ], + ), + ); + } + + // 服务卡片的小组件 + Widget _buildServiceCard( + String title, + String subtitle, + IconData icon, + Color color, + ) { + return Expanded( + child: Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: color.withOpacity(0.1), + borderRadius: BorderRadius.circular(8), + ), + child: Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: const TextStyle(fontWeight: FontWeight.bold), + ), + const SizedBox(height: 4), + Text( + subtitle, + style: const TextStyle(fontSize: 12, color: Colors.grey), + ), + ], + ), + ), + Icon(icon, color: color, size: 30), + ], + ), + ), + ); + } + + // 构建底部导航栏 + Widget _buildBottomNavigationBar() { + return BottomNavigationBar( + currentIndex: _bottomNavIndex, + onTap: (index) { + setState(() { + _bottomNavIndex = index; + }); + }, + type: BottomNavigationBarType.fixed, + selectedItemColor: Colors.blue, + unselectedItemColor: Colors.grey, + items: const [ + BottomNavigationBarItem(icon: Icon(Icons.home), label: '企业'), + BottomNavigationBarItem( + icon: Icon(Icons.card_membership), + label: '全部问题', + ), + // BottomNavigationBarItem(icon: Icon(Icons.waves), label: 'AQ-健康管家'), + // BottomNavigationBarItem(icon: Icon(Icons.add_moderator), label: '医疗保障'), + BottomNavigationBarItem(icon: Icon(Icons.person_outline), label: '我的'), + ], + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index 5aea328..bcbf8ab 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,18 +5,18 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: f0bb5d1648339c8308cc0b9838d8456b3cfe5c91f9dc1a735b4d003269e5da9a + sha256: dd3d2ad434b9510001d089e8de7556d50c834481b9abc2891a0184a8493a19dc url: "https://pub.flutter-io.cn" source: hosted - version: "88.0.0" + version: "89.0.0" analyzer: dependency: transitive description: name: analyzer - sha256: "0b7b9c329d2879f8f05d6c05b32ee9ec025f39b077864bdb5ac9a7b63418a98f" + sha256: c22b6e7726d1f9e5db58c7251606076a71ca0dbcf76116675edfadbec0c9e875 url: "https://pub.flutter-io.cn" source: hosted - version: "8.1.1" + version: "8.2.0" args: dependency: transitive description: @@ -117,10 +117,10 @@ packages: dependency: transitive description: name: code_builder - sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e" + sha256: "11654819532ba94c34de52ff5feb52bd81cba1de00ef2ed622fd50295f9d4243" url: "https://pub.flutter-io.cn" source: hosted - version: "4.10.1" + version: "4.11.0" collection: dependency: transitive description: @@ -295,10 +295,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "6382ce712ff69b0f719640ce957559dde459e55ecd433c767e06d139ddf16cab" + sha256: b0694b7fb1689b0e6cc193b3f1fcac6423c4f93c74fb20b806c6b6f196db0c31 url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.29" + version: "2.0.30" flutter_screenutil: dependency: "direct main" description: @@ -337,10 +337,10 @@ packages: dependency: "direct dev" description: name: freezed - sha256: b6445822d9b3961a9d0f3def0b4297bd77314bdbfd1de0b62eaca27c93e9bc0f + sha256: "13065f10e135263a4f5a4391b79a8efc5fb8106f8dd555a9e49b750b45393d77" url: "https://pub.flutter-io.cn" source: hosted - version: "3.2.2" + version: "3.2.3" freezed_annotation: dependency: "direct main" description: @@ -513,26 +513,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" url: "https://pub.flutter-io.cn" source: hosted - version: "10.0.9" + version: "11.0.2" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" url: "https://pub.flutter-io.cn" source: hosted - version: "3.0.9" + version: "3.0.10" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" url: "https://pub.flutter-io.cn" source: hosted - version: "3.0.1" + version: "3.0.2" lints: dependency: transitive description: @@ -713,10 +713,10 @@ packages: dependency: transitive description: name: path_provider_android - sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9 + sha256: "993381400e94d18469750e5b9dcb8206f15bc09f9da86b9e44a9b0092a0066db" url: "https://pub.flutter-io.cn" source: hosted - version: "2.2.17" + version: "2.2.18" path_provider_foundation: dependency: transitive description: @@ -825,10 +825,10 @@ packages: dependency: transitive description: name: pool - sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d" url: "https://pub.flutter-io.cn" source: hosted - version: "1.5.1" + version: "1.5.2" pretty_dio_logger: dependency: "direct main" description: @@ -918,10 +918,10 @@ packages: dependency: transitive description: name: sqflite_android - sha256: "2b3070c5fa881839f8b402ee4a39c1b4d561704d4ebbbcfb808a119bc2a1701b" + sha256: ecd684501ebc2ae9a83536e8b15731642b9570dc8623e0073d227d0ee2bfea88 url: "https://pub.flutter-io.cn" source: hosted - version: "2.4.1" + version: "2.4.2+2" sqflite_common: dependency: transitive description: @@ -990,10 +990,10 @@ packages: dependency: "direct main" description: name: tdesign_flutter - sha256: "1ff7689c69fe9d3762ebad661c3d027cac7d2aa6270e1f748b6610b3fd567278" + sha256: "6c95cd746d7ff3ee5e3c9c4dd0e202f69c8c6e04cf53f29ace4da16f5cfbc7e4" url: "https://pub.flutter-io.cn" source: hosted - version: "0.2.4" + version: "0.2.5" tdesign_flutter_adaptation: dependency: transitive description: @@ -1014,10 +1014,10 @@ packages: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" url: "https://pub.flutter-io.cn" source: hosted - version: "0.7.4" + version: "0.7.6" typed_data: dependency: transitive description: @@ -1038,18 +1038,18 @@ packages: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.4" + version: "2.2.0" vm_service: dependency: transitive description: name: vm_service - sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 + sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" url: "https://pub.flutter-io.cn" source: hosted - version: "15.0.0" + version: "15.0.2" watcher: dependency: transitive description: @@ -1115,5 +1115,5 @@ packages: source: hosted version: "3.1.3" sdks: - dart: ">=3.8.1 <4.0.0" + dart: ">=3.9.0 <4.0.0" flutter: ">=3.29.0" diff --git a/pubspec.yaml b/pubspec.yaml index ee93e33..7ac3cad 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: problem_check_system description: "A new Flutter project." publish_to: "none" -version: 1.0.0 +version: 1.0.1 environment: sdk: ^3.8.1