diff --git a/README.md b/README.md index ed84766..62e7dd4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# qhd_prevention +# flutter_integrated_whb -A new Flutter project. +危化项目. ## Getting Started diff --git a/assets/icon-apps/close-icon.png b/assets/icon-apps/close-icon.png new file mode 100644 index 0000000..e69de29 diff --git a/assets/icon-apps/home-study-old.png b/assets/icon-apps/home-study-old.png new file mode 100644 index 0000000..e69de29 diff --git a/assets/icon-apps/home-study.png b/assets/icon-apps/home-study.png index 8ba8b01..5d5f855 100644 Binary files a/assets/icon-apps/home-study.png and b/assets/icon-apps/home-study.png differ diff --git a/assets/icon-apps/home-zdgcgl.jpg b/assets/icon-apps/home-zdgcgl.jpg new file mode 100644 index 0000000..c29c05a Binary files /dev/null and b/assets/icon-apps/home-zdgcgl.jpg differ diff --git a/assets/icon-apps/icon-aq-1.png b/assets/icon-apps/icon-aq-1.png new file mode 100644 index 0000000..6e9247f Binary files /dev/null and b/assets/icon-apps/icon-aq-1.png differ diff --git a/assets/icon-apps/icon-jh-1.png b/assets/icon-apps/icon-jh-1.png new file mode 100644 index 0000000..e69de29 diff --git a/assets/icon-apps/icon-js-1.png b/assets/icon-apps/icon-js-1.png new file mode 100644 index 0000000..e69de29 diff --git a/assets/icon-apps/icon-zl-11.png b/assets/icon-apps/icon-zl-11.png new file mode 100644 index 0000000..c1c82c5 Binary files /dev/null and b/assets/icon-apps/icon-zl-11.png differ diff --git a/assets/icon-apps/nike.png b/assets/icon-apps/nike.png new file mode 100644 index 0000000..4f2de59 Binary files /dev/null and b/assets/icon-apps/nike.png differ diff --git a/assets/icon-apps/safetymeeting.png b/assets/icon-apps/safetymeeting.png new file mode 100644 index 0000000..7a5759c Binary files /dev/null and b/assets/icon-apps/safetymeeting.png differ diff --git a/assets/images/app-logo.png b/assets/images/app-logo.png index 54baf79..97db434 100644 Binary files a/assets/images/app-logo.png and b/assets/images/app-logo.png differ diff --git a/assets/images/apps-banner-qa.png b/assets/images/apps-banner-qa.png new file mode 100644 index 0000000..93e9bdb Binary files /dev/null and b/assets/images/apps-banner-qa.png differ diff --git a/assets/images/apps-banner.png b/assets/images/apps-banner.png index 0093235..15331fc 100644 Binary files a/assets/images/apps-banner.png and b/assets/images/apps-banner.png differ diff --git a/assets/images/banner.jpg b/assets/images/banner.jpg index 3df5fa8..48bff15 100644 Binary files a/assets/images/banner.jpg and b/assets/images/banner.jpg differ diff --git a/assets/images/banner.png b/assets/images/banner.png index f6d6ade..e239adb 100644 Binary files a/assets/images/banner.png and b/assets/images/banner.png differ diff --git a/assets/images/bg-login.png b/assets/images/bg-login.png index 6bc71fd..4ebb677 100644 Binary files a/assets/images/bg-login.png and b/assets/images/bg-login.png differ diff --git a/assets/images/biyan.png b/assets/images/biyan.png new file mode 100644 index 0000000..e69de29 diff --git a/assets/images/study-app02.png b/assets/images/study-app02.png index 223e441..2c22b4a 100644 Binary files a/assets/images/study-app02.png and b/assets/images/study-app02.png differ diff --git a/assets/images/study-app02old.png b/assets/images/study-app02old.png new file mode 100644 index 0000000..e69de29 diff --git a/assets/images/zhengyan.png b/assets/images/zhengyan.png new file mode 100644 index 0000000..e69de29 diff --git a/assets/study/bgimg1.png b/assets/study/bgimg1.png new file mode 100644 index 0000000..004c26a Binary files /dev/null and b/assets/study/bgimg1.png differ diff --git a/assets/study/copy-one.png b/assets/study/copy-one.png new file mode 100644 index 0000000..e69de29 diff --git a/assets/study/err.png b/assets/study/err.png new file mode 100644 index 0000000..e69de29 diff --git a/assets/study/play.png b/assets/study/play.png new file mode 100644 index 0000000..e69de29 diff --git a/assets/study/right.png b/assets/study/right.png new file mode 100644 index 0000000..e69de29 diff --git a/assets/study/time.png b/assets/study/time.png new file mode 100644 index 0000000..e69de29 diff --git a/assets/tabbar/img.png b/assets/tabbar/img.png new file mode 100644 index 0000000..4e82803 Binary files /dev/null and b/assets/tabbar/img.png differ diff --git a/assets/tabbar/study-app02old.jpg b/assets/tabbar/study-app02old.jpg new file mode 100644 index 0000000..eb96d4d Binary files /dev/null and b/assets/tabbar/study-app02old.jpg differ diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 999ffaa..d1e408d 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -2,6 +2,8 @@ PODS: - connectivity_plus (0.0.1): - Flutter - Flutter (1.0.0) + - fluttertoast (0.0.2): + - Flutter - image_picker_ios (0.0.1): - Flutter - mobile_scanner (7.0.0): @@ -25,6 +27,7 @@ PODS: DEPENDENCIES: - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) - Flutter (from `Flutter`) + - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) - mobile_scanner (from `.symlinks/plugins/mobile_scanner/darwin`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) @@ -38,6 +41,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/connectivity_plus/ios" Flutter: :path: Flutter + fluttertoast: + :path: ".symlinks/plugins/fluttertoast/ios" image_picker_ios: :path: ".symlinks/plugins/image_picker_ios/ios" mobile_scanner: @@ -56,6 +61,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + fluttertoast: 2c67e14dce98bbdb200df9e1acf610d7a6264ea1 image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a mobile_scanner: 9157936403f5a0644ca3779a38ff8404c5434a93 package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 diff --git a/lib/http/ApiService.dart b/lib/http/ApiService.dart new file mode 100644 index 0000000..3106bb6 --- /dev/null +++ b/lib/http/ApiService.dart @@ -0,0 +1,224 @@ +import 'package:dio/dio.dart'; +import 'package:qhd_prevention/tools/tools.dart'; + +import 'HttpManager.dart'; + +class ApiService { + // static const String basePath = "http://192.168.0.25:28199/"; + // static const String basePath = "http://192.168.20.240:8500/integrated_whb"; + // static const String baseFacePath = "http://192.168.0.25:38199/"; + // 人脸识别服务 + // static const String baseFacePath = "https://qaaqwh.qhdsafety.com/whb_stu_face/"; + + // static const String basePath = "https://qaaqwh.qhdsafety.com/integrated_whb/"; + // static const String baseImgPath = "https://file.zcloudchina.com/YTHFile"; + // static const String adminPath = "https://qaaqwh.qhdsafety.com/integrated_whb/"; + // static const String projectManagerUrl = 'https://pm.qhdsafety.com/zy-projectManage/'; + // static const String publicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDUoHAavCikaZxjlDM6Km8cX+ye78F4oF39AcEfnE1p2Yn9pJ9WFxYZ4Vkh6F8SKMi7k4nYsKceqB1RwG996SvHQ5C3pM3nbXCP4K15ad6QhN4a7lzlbLhiJcyIKszvvK8ncUDw8mVQ0j/2mwxv05yH6LN9OKU6Hzm1ninpWeE+awIDAQAB' + /// 人脸识别服务 + static const String baseFacePath = + "https://qaaqwh.qhdsafety.com/whb_stu_face/"; + + /// 登录及其他管理后台接口 + static const String basePath = "https://qaaqwh.qhdsafety.com/integrated_whb"; + + /// 图片文件服务 + static const String baseImgPath = "https://file.zcloudchina.com/YTHFile"; + + /// 管理后台统一路径 + static const String adminPath = + "https://qaaqwh.qhdsafety.com/integrated_whb/"; + + /// 项目管理系统 + static const String projectManagerUrl = + 'https://pm.qhdsafety.com/zy-projectManage'; + + /// RSA 公钥 + static const publicKey = ''' +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDUoHAavCikaZxjlDM6Km8cX+ye +78F4oF39AcEfnE1p2Yn9pJ9WFxYZ4Vkh6F8SKMi7k4nYsKceqB1RwG996SvHQ5C3p +M3nbXCP4K15ad6QhN4a7lzlbLhiJcyIKszvvK8ncUDw8mVQ0j/2mwxv05yH6LN9OK +U6Hzm1ninpWeE+awIDAQAB +-----END PUBLIC KEY----- +'''; + + /// 登录验证接口 + static Future> loginCheck(String keydataVal) { + return HttpManager().request( + basePath, + '/admin/check', + method: Method.post, + data: { + 'KEYDATA': keydataVal, + 'SOURCE': '2', + 'tm': DateTime.now().millisecondsSinceEpoch.toString(), + }, + ); + } + + ///TODO -------------–-------------------- 首页 -------------–-------------------- + /// 我的工作 + static Future> getWork() { + return HttpManager().request( + basePath, + '/app/hidden/getCountByUserId', + method: Method.post, + data: { + 'userId': SessionService.instance.loginUserId, + 'USER_NAME': SessionService.instance.username, + 'CHECK_DEPARTMENT_ID': SessionService.instance.deptId, + 'IS_MAIN': SessionService.instance.isRest, + 'CORPINFO_ID': SessionService.instance.corpinfoId, + 'USER_ID': SessionService.instance.loginUserId, + }, + ); + } + + /// + static Future> getRedPoint() { + return HttpManager().request( + basePath, + '/app/eightwork/checkWork', + method: Method.post, + data: {'USER_ID': SessionService.instance.loginUserId}, + ); + } + + /// + static Future> getUserData() { + return HttpManager().request( + basePath, + '/app/hidden/getUserIndexData', + method: Method.post, + data: { + 'userId': SessionService.instance.loginUserId, + 'USER_NAME': SessionService.instance.username, + 'CHECK_DEPARTMENT_ID': SessionService.instance.deptId, + 'IS_MAIN': SessionService.instance.isRest, + 'CORPINFO_ID': SessionService.instance.corpinfoId, + 'USER_ID': SessionService.instance.loginUserId, + }, + ); + } + + static Future> getSafetyEnvironmentalInspectionCount() { + return HttpManager().request( + basePath, + '/app/safetyenvironmental/countCheck', + method: Method.post, + data: { + 'CORPINFO_ID': SessionService.instance.corpinfoId, + 'INSPECTION_USER_ID': SessionService.instance.loginUserId, + 'INSPECTED_SITEUSER_ID': SessionService.instance.loginUserId, + 'INSPECTION_ORIGINATOR_ID': SessionService.instance.loginUserId, + 'tm': DateTime.now().millisecondsSinceEpoch.toString(), + }, + ); + } + + static Future> getUpdateInfo() { + return HttpManager().request( + projectManagerUrl, + '/projectDetails/findUpdate?code=cloud&type=APP', + method: Method.post, + data: {}, + ); + } + + static Future> getDeptData() { + return HttpManager().request( + basePath, + '/app/hidden/getDeptIndexData', + method: Method.post, + data: { + 'userId': SessionService.instance.loginUserId, + 'USER_NAME': SessionService.instance.username, + 'DEPARTMENT_ID': SessionService.instance.deptId, + 'IS_MAIN': SessionService.instance.isRest, + 'CORPINFO_ID': SessionService.instance.corpinfoId, + 'USER_ID': SessionService.instance.loginUserId, + }, + ); + } + + /// 月隐患 1 月隐患,2年隐患 + static Future> getDanger(int type) { + return HttpManager().request( + basePath, + '/app/hidden/getIndexCount', + method: Method.post, + data: { + 'userId': SessionService.instance.loginUserId, + 'CORPINFO_ID': SessionService.instance.corpinfoId, + (type == 1 ? 'IS_MONTH' : 'IS_YEAR'): '1', + 'USER_ID': SessionService.instance.loginUserId, + }, + ); + } + + static Future> getSurveyData() { + return HttpManager().request( + basePath, + '/app/survey/goEdit', + method: Method.post, + data: { + 'CORPINFO_ID': SessionService.instance.corpinfoId, + 'USER_ID': SessionService.instance.loginUserId, + }, + ); + } + + static Future> getUserId() { + return HttpManager().request( + basePath, + '/app/surveyanswer/getUserId', + method: Method.post, + data: { + 'CORPINFO_ID': SessionService.instance.corpinfoId, + 'USER_ID': SessionService.instance.loginUserId, + }, + ); + } + /// 获取清单数量 + static Future> getListData() { + return HttpManager().request( + basePath, + '/app/listmanager/checkList', + method: Method.post, + data: { + 'userId': SessionService.instance.loginUserId, + 'USER_NAME': SessionService.instance.username, + 'CHECK_DEPARTMENT_ID': SessionService.instance.deptId, + 'IS_MAIN': SessionService.instance.isRest, + 'CORPINFO_ID': SessionService.instance.corpinfoId, + 'USER_ID': SessionService.instance.loginUserId, + }, + ); + } + /// 获取滚动隐患 + static Future> getHiddenRoll() { + return HttpManager().request( + basePath, + '/app/hidden/getHiddenByCorp', + method: Method.post, + data: { + 'CORPINFO_ID': SessionService.instance.corpinfoId, + 'HIDDENLEVEL': 'hiddenLevel0001', + }, + ); + } + + static Future> getIsRest() { + return HttpManager().request( + basePath, + '/app/hidden/getHiddenByCorp', + method: Method.post, + data: { + 'CORPINFO_ID': SessionService.instance.corpinfoId, + 'USER_ID': SessionService.instance.loginUserId, + }, + ); + } + +} diff --git a/lib/http/HttpManager.dart b/lib/http/HttpManager.dart new file mode 100644 index 0000000..8a09aab --- /dev/null +++ b/lib/http/HttpManager.dart @@ -0,0 +1,99 @@ +import 'package:dio/dio.dart'; + +/// 统一接口异常 +class ApiException implements Exception { + final String result; + final String message; + ApiException(this.result, this.message); + @override + String toString() => 'ApiException($result): $message'; +} + +/// HTTP 方法枚举 +enum Method { get, post, put, delete } + +class HttpManager { + HttpManager._internal() { + _dio = Dio(BaseOptions( + connectTimeout: const Duration(milliseconds: 10000), + receiveTimeout: const Duration(milliseconds: 10000), + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + )); + _initInterceptors(); + } + + static final HttpManager _instance = HttpManager._internal(); + factory HttpManager() => _instance; + late final Dio _dio; + + void _initInterceptors() { + _dio.interceptors + ..add(LogInterceptor(request: true, responseBody: true, error: true)) + ..add(InterceptorsWrapper(onError: (err, handler) { + // 全局错误处理,可根据 err.response?.statusCode 或 err.type 操作 + handler.next(err); + })); + } + + /// 通用 request 方法,返回完整后台 JSON + /// baseUrl: 基础路径,如 basePath + /// path: 接口路径,如 '/admin/check' + /// method: HTTP 方法,默认 POST + /// data: Form 表单参数 + /// params: URL 查询参数 + Future> request( + String baseUrl, + String path, { + Method method = Method.post, + Map? data, + Map? params, + CancelToken? cancelToken, + }) async { + Response resp; + final url = baseUrl + path; + final options = Options( + method: method.name.toUpperCase(), + contentType: Headers.formUrlEncodedContentType, + ); + try { + switch (method) { + case Method.get: + resp = await _dio.get(url, + queryParameters: params, cancelToken: cancelToken, options: options); + break; + case Method.put: + resp = await _dio.put(url, + data: data, queryParameters: params, cancelToken: cancelToken, options: options); + break; + case Method.delete: + resp = await _dio.delete(url, + queryParameters: params, cancelToken: cancelToken, options: options); + break; + case Method.post: + default: + resp = await _dio.post(url, + data: data, queryParameters: params, cancelToken: cancelToken, options: options); + } + } on DioError catch (e) { + // 网络或服务器错误 + throw ApiException('network_error', e.message ?? ""); + } + + // 解析返回 JSON + final json = resp.data is Map + ? resp.data as Map + : {}; + final result = json['result'] as String?; + final msg = json['msg'] as String? ?? json['message'] as String? ?? ''; + if (result != 'success') { + // 非 success 都抛异常 + throw ApiException(result ?? 'unknown', msg); + } + // 返回完整数据,包括 msg、USER_ID 等 + return json; + } + +} + diff --git a/lib/pages/home/home_page.dart b/lib/pages/home/home_page.dart index c2b7b73..42b42b8 100644 --- a/lib/pages/home/home_page.dart +++ b/lib/pages/home/home_page.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:convert'; import 'dart:ffi'; import 'package:flutter/material.dart'; import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart'; @@ -9,6 +10,7 @@ import 'package:qhd_prevention/pages/home/work/danger_page.dart'; import 'package:qhd_prevention/pages/home/work/danger_wait_list_page.dart'; import 'package:qhd_prevention/pages/home/workSet_page.dart'; +import '../../http/ApiService.dart'; import '../../tools/tools.dart'; class HomePage extends StatefulWidget { @@ -19,44 +21,12 @@ class HomePage extends StatefulWidget { } class _HomePageState extends State { - final List> buttonInfos = [ - {"icon": "assets/icon-apps/home-base.png", "title": "人员信息"}, - {"icon": "assets/icon-apps/home-rili.png", "title": "工作安排"}, - {"icon": "assets/icon-apps/home-risk.png", "title": "风险布控"}, - {"icon": "assets/icon-apps/home-fl.png", "title": "法律法规"}, - ]; - final List> workInfos = [ - { - "icon": "assets/icon-apps/jobico1.png", - "num": "1", - "detail": "待排查", - "index": 1, - }, - { - "icon": "assets/icon-apps/jobico2.png", - "num": "2", - "detail": "待整改", - "index": 2, - }, - { - "icon": "assets/icon-apps/jobico3.png", - "num": "3", - "detail": "已超期", - "index": 3, - }, - { - "icon": "assets/icon-apps/jobico4.png", - "num": "4", - "detail": "待验收", - "index": 4, - }, - { - "icon": "assets/icon-apps/jobico5.png", - "num": "5", - "detail": "已验收", - "index": 5, - }, - ]; + final int _eight_work_count = 0; + final int _safetyEnvironmentalInspection = 0; + late final List> buttonInfos; + + /// 我的工作 + List> workInfos = []; final List> pcData = [ { "index": 1, @@ -114,42 +84,6 @@ class _HomePageState extends State { ); } - Widget _buildIconSection(BuildContext context) { - return Container( - padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 10), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: - buttonInfos.asMap().entries.map((entry) { - final index = entry.key; // 获取当前索引 - final btnInfo = entry.value; // 获取按钮信息 - - return _buildIconButton( - icon: Image.asset(btnInfo["icon"]!, width: 40, height: 40), - label: btnInfo["title"]!, - onPressed: () { - // 使用索引判断点击的是哪个按钮 - print("点击了第 $index 个按钮"); - if (index == 0) { - pushPage(UserinfoPage(), context); - } else if (index == 1) { - pushPage(WorkSetPage(), context); - } else if (index == 2) { - pushPage(RiskControlPage(), context); - } else if (index == 3) { - pushPage(LowPage(), context); - } - }, - ); - }).toList(), - ), - ); - } - Widget _buildWorkSection(BuildContext context) { return Container( decoration: BoxDecoration( @@ -194,8 +128,6 @@ class _HomePageState extends State { ); } - - Widget _buildPCDataSection() { return Container( decoration: BoxDecoration( @@ -205,7 +137,6 @@ class _HomePageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - // _widgetTopTip(title: "排查数据"), ListItemFactory.createBuildSimpleSection("排查数据"), ...pcData.map(_widgetPCDataItem), ], @@ -213,23 +144,106 @@ class _HomePageState extends State { ); } - // 构建图标按钮:图上文字下 + /// 定义 item 宽度 + double _itemWidth(BuildContext context) { + final screenW = MediaQuery.of(context).size.width; + return (screenW - 20) / 4; + } + + Widget _buildIconSection(BuildContext context) { + return Container( + padding: const EdgeInsets.symmetric(vertical: 10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + ), + child: Wrap( + runSpacing: 16, + children: + buttonInfos.asMap().entries.map((entry) { + final idx = entry.key; + final info = entry.value; + return _buildIconButton( + context: context, + iconPath: info["icon"] as String, + label: info["title"] as String, + unreadCount: info["unreadCount"] as int, + onPressed: () { + final index = entry.key; + // 你的导航逻辑 + if (index == 0) { + pushPage(UserinfoPage(), context); + } else if (index == 1) { + pushPage(WorkSetPage(), context); + } else if (index == 2) { + pushPage(RiskControlPage(), context); + } else if (index == 3) { + pushPage(LowPage(), context); + } + }, + ); + }).toList(), + ), + ); + } + Widget _buildIconButton({ - required Widget icon, + required BuildContext context, + required String iconPath, required String label, - required VoidCallback onPressed, // 添加点击回调参数 + required VoidCallback onPressed, + int unreadCount = 0, }) { + final w = _itemWidth(context); return InkWell( - onTap: onPressed, // 处理点击事件 + onTap: onPressed, borderRadius: BorderRadius.circular(8), - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12), - child: Column( - mainAxisSize: MainAxisSize.min, + child: SizedBox( + width: w, + child: Stack( + clipBehavior: Clip.none, children: [ - icon, - const SizedBox(height: 5), - Text(label, style: const TextStyle(fontSize: 14)), + /// 中心对齐 + Align( + alignment: Alignment.topCenter, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Image.asset(iconPath, width: 40, height: 40), + const SizedBox(height: 5), + Text(label, style: const TextStyle(fontSize: 14)), + ], + ), + ), + if (unreadCount > 0) + Positioned( + right: -4, + top: -4, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 4, + vertical: 2, + ), + decoration: BoxDecoration( + color: Colors.red, + borderRadius: BorderRadius.circular(10), + ), + constraints: const BoxConstraints( + minWidth: 16, + minHeight: 16, + ), + child: Text( + unreadCount > 99 ? '99+' : '$unreadCount', + style: const TextStyle( + color: Colors.white, + fontSize: 10, + height: 1, + ), + textAlign: TextAlign.center, + ), + ), + ), ], ), ), @@ -312,9 +326,9 @@ class _HomePageState extends State { pushPage(DangerWaitListPage(DangerType.wait), context); } else if (index == 3) { pushPage(DangerWaitListPage(DangerType.expired), context); - }else if (index == 4) { + } else if (index == 4) { pushPage(DangerWaitListPage(DangerType.waitAcceptance), context); - }else if (index == 5) { + } else if (index == 5) { pushPage(DangerWaitListPage(DangerType.acceptance), context); } }, @@ -357,4 +371,135 @@ class _HomePageState extends State { ), ); } + + void initState() { + super.initState(); + buttonInfos = [ + { + "icon": "assets/icon-apps/home-base.png", + "title": "人员信息", + "unreadCount": 0, + }, + { + "icon": "assets/icon-apps/home-rili.png", + "title": "工作安排", + "unreadCount": 0, + }, + { + "icon": "assets/icon-apps/home-risk.png", + "title": "风险布控", + "unreadCount": 0, + }, + { + "icon": "assets/icon-apps/home-fl.png", + "title": "法律法规", + "unreadCount": 0, + }, + { + "icon": "assets/icon-apps/home-gw.png", + "title": "特殊作业", + "unreadCount": _eight_work_count, + }, + { + "icon": "assets/icon-apps/home-zdgcgl.jpg", + "title": "重点工程管理", + "unreadCount": 0, + }, + { + "icon": "assets/icon-apps/home-cns.png", + "title": "安全承诺", + "unreadCount": 0, + }, + { + "icon": "assets/icon-apps/home-study.png", + "title": "学习园地", + "unreadCount": 0, + }, + { + "icon": "assets/icon-apps/home-base.png", + "title": "安全检查", + "unreadCount": _safetyEnvironmentalInspection, + }, + { + "icon": "assets/icon-apps/home-speEquip.jpg", + "title": "设备巡检", + "unreadCount": 0, + }, + { + "icon": "assets/icon-apps/safetymeeting.png", + "title": "安全例会", + "unreadCount": 0, + }, + ]; + + _fetchData(); // 初始化时请求 + + } + Future _fetchData() async { + try { + // “我的工作” 数量 + final raw = await ApiService.getWork(); + // 如果拿到的是 String,就 decode;如果本来就是 Map,就直接用 + final Map data = raw is String + ? json.decode(raw as String) as Map + : raw; + + final hidCount = data['hidCount'] as Map; + print(hidCount); + setState(() { + workInfos = [ + { + "icon": "assets/icon-apps/jobico1.png", + "index": 1, + "detail": "待排查", + "num": (hidCount['dpc'] ?? 0).toString(), + }, + { + "icon": "assets/icon-apps/jobico2.png", + "index": 2, + "detail": "待整改", + "num": (hidCount['dzg'] ?? 0).toString(), + }, + { + "icon": "assets/icon-apps/jobico3.png", + "index": 3, + "detail": "已超期", + "num": (hidCount['ycq'] ?? 0).toString(), + }, + { + "icon": "assets/icon-apps/jobico4.png", + "index": 4, + "detail": "待验收", + "num": (hidCount['dys'] ?? 0).toString(), + }, + { + "icon": "assets/icon-apps/jobico5.png", + "index": 5, + "detail": "已验收", + "num": (hidCount['yys'] ?? 0).toString(), + }, + ]; + + }); + + + // // 特殊作业红点 + // final redPointJson = await ApiService.getRedPoint(); + // setState(() { + // eightWorkCount = + // int.parse(redPointJson['unreadCount'].toString()); + // }); + // + // // 安全检查数 + // final checkJson = + // await ApiService.getSafetyEnvironmentalInspectionCount(); + // setState(() { + // safetyCheckCount = + // int.parse(checkJson['count'].toString()); + // }); + } catch (e) { + // 出错时可以 Toast 或者在页面上显示错误状态 + print('加载首页数据失败:$e'); + } + } } diff --git a/lib/pages/login_page.dart b/lib/pages/login_page.dart index c8fd3be..8183aef 100644 --- a/lib/pages/login_page.dart +++ b/lib/pages/login_page.dart @@ -1,6 +1,18 @@ // ignore_for_file: use_build_context_synchronously +import 'dart:convert'; + +import 'package:encrypt/encrypt.dart' as encrypt; +import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; +import 'package:dio/dio.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:qhd_prevention/tools/StorageService.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import '../http/ApiService.dart'; +import 'package:pointycastle/asymmetric/api.dart' show RSAPublicKey; +import '../http/HttpManager.dart'; +import '../tools/tools.dart'; import 'main_tab.dart'; void main() => runApp(const MyApp()); @@ -29,62 +41,82 @@ class LoginPage extends StatefulWidget { const LoginPage({super.key}); @override - // ignore: library_private_types_in_public_api _LoginPageState createState() => _LoginPageState(); } class _LoginPageState extends State { - final TextEditingController _phoneController = TextEditingController(); - final TextEditingController _passwordController = TextEditingController(); + final TextEditingController _phoneController = TextEditingController(text: '13293211008'); + final TextEditingController _passwordController = TextEditingController(text: 'Zsaq@123456'); final GlobalKey _formKey = GlobalKey(); String _errorMessage = ''; bool _isLoading = false; bool _obscurePassword = true; + bool _agreed = false; @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: Colors.white, - body: SingleChildScrollView( - child: Column( - children: [ - _buildHeader(), - - Transform.translate( - offset: const Offset(0, -20), - child: Container( - decoration: const BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - topLeft: Radius.circular(30), - topRight: Radius.circular(30), - ), + resizeToAvoidBottomInset: false, + body: Container( + width: double.infinity, + height: double.infinity, + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/images/bg-login.png'), + fit: BoxFit.cover, + ), + ), + child: Form( + key: _formKey, + child: Stack( + children: [ + Positioned.fill( + child: Image.asset( + 'assets/images/bg-login.png', + fit: BoxFit.cover, ), - child: Padding( - padding: const EdgeInsets.only(top: 30), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: SingleChildScrollView( child: Column( children: [ - // 手机号 + const SizedBox(height: 150), + Row( + children: [ + Image.asset('assets/image/logo.png', height: 50), + const SizedBox(width: 15), + const Expanded( + child: Text( + '欢迎使用,\n智守安全云平台!', + style: TextStyle( + fontSize: 22, + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + const SizedBox(height: 50), _buildInputSection( label: "手机号码", controller: _phoneController, hintText: "请输入手机号...", keyboardType: TextInputType.phone, validator: (value) { - if (value == null || value.isEmpty) { + if (value == null || value.isEmpty) return '请输入手机号'; - } - if (!RegExp(r'^1[3-9]\d{9}$').hasMatch(value)) { - return '请输入有效的手机号'; - } + // if (!RegExp(r'^1[3-9]\d{9}\$').hasMatch(value)) + // return '请输入有效的手机号'; return null; }, ), - - Padding(padding: const EdgeInsets.symmetric(horizontal: 25), - child: const Divider(height: 1, thickness: 1), + const Divider( + height: 1, + thickness: 1, + color: Colors.white70, ), - // 密码 _buildInputSection( label: "密码", controller: _passwordController, @@ -93,49 +125,52 @@ class _LoginPageState extends State { suffixIcon: IconButton( icon: Icon( _obscurePassword - ? Icons.visibility - : Icons.visibility_off, - color: Colors.grey, + ? Icons.visibility_off + : Icons.visibility, + color: Colors.white, ), - onPressed: () { - setState(() { - _obscurePassword = !_obscurePassword; - }); - }, + onPressed: + () => + setState( + () => _obscurePassword = !_obscurePassword, + ), ), validator: (value) { - if (value == null || value.isEmpty) { + if (value == null || value.isEmpty) return '请输入密码'; - } - if (value.length < 6) { - return '密码长度至少6位'; - } return null; }, ), - Padding(padding: const EdgeInsets.symmetric(horizontal: 25), - child: const Divider(height: 1, thickness: 1), + const Divider( + height: 1, + thickness: 1, + color: Colors.white70, ), - // 登录按钮 + const SizedBox(height: 30), + if (_errorMessage.isNotEmpty) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 25), + child: Text( + _errorMessage, + style: const TextStyle(color: Colors.blue), + ), + ), Padding( - padding: const EdgeInsets.symmetric( - horizontal: 25, vertical: 24), + padding: const EdgeInsets.symmetric(vertical: 24), child: SizedBox( width: double.infinity, height: 48, child: ElevatedButton( - onPressed: _isLoading ? null : _handleLogin, + onPressed: + (!_isLoading && _agreed) ? _handleLogin : null, style: ElevatedButton.styleFrom( backgroundColor: Colors.blue, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), - child: _isLoading - ? const CircularProgressIndicator( - color: Colors.white, - ) - : const Text( + child: + const Text( '登录', style: TextStyle( fontSize: 18, @@ -146,63 +181,75 @@ class _LoginPageState extends State { ), ), ), - Padding(padding: const EdgeInsets.only(left: 30, right: 30), - child:Text(" 本平台为互联网非涉密平台,严禁处理、传输国家秘密和工作秘密", - style: TextStyle(color: Colors.red)) - ) + + Padding( + padding: const EdgeInsets.all(0), + child: Row( + children: [ + Checkbox( + value: _agreed, + activeColor: Colors.white, + checkColor: Colors.blueAccent, + side: const BorderSide(color: Colors.white), + onChanged: + (v) => setState(() => _agreed = v ?? false), + ), + Expanded( + child: RichText( + text: TextSpan( + children: [ + TextSpan( + text: '我已阅读并同意', + style: const TextStyle( + color: Colors.white, + ), + ), + TextSpan( + text: '《用户协议》', + style: const TextStyle( + color: Color(0xFF0D1D8C), + ), + recognizer: + TapGestureRecognizer() + ..onTap = () { + // 打开用户协议 + }, + ), + TextSpan( + text: '和', + style: const TextStyle( + color: Colors.white, + ), + ), + TextSpan( + text: '《隐私政策》', + style: const TextStyle( + color: Color(0xFF0D1D8C), + ), + recognizer: + TapGestureRecognizer() + ..onTap = () { + // 打开隐私政策 + }, + ), + ], + ), + ), + ), + ], + ), + ), ], ), ), ), - ), - ], + ], + ), ), ), ); } - // 顶部图片和文字 - Widget _buildHeader() { - return Stack( - alignment: Alignment.center, - children: [ - Image.asset( - 'assets/images/login-bg.png', - width: double.infinity, - fit: BoxFit.fitWidth, - ), - Positioned( - bottom: 40, - left: 30, - child: Column( - children: [ - const Text( - '欢迎登录', - style: TextStyle( - fontSize: 28, - fontWeight: FontWeight.bold, - color: Colors.white, - shadows: [ - Shadow( - blurRadius: 10, - color: Colors.black45, - offset: Offset(2, 2), - ), - ], - ), - ), - const SizedBox(height: 8), - Text( - '秦皇岛市应急管局\n数智应急管理平台', - style: TextStyle(fontSize: 18, color: Colors.white), - ), - ], - ), - ), - ], - ); - } - // 输入区域组件 Widget _buildInputSection({ required String label, required TextEditingController controller, @@ -213,7 +260,7 @@ class _LoginPageState extends State { String? Function(String?)? validator, }) { return Padding( - padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 12), + padding: const EdgeInsets.symmetric(vertical: 12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -222,7 +269,7 @@ class _LoginPageState extends State { style: const TextStyle( fontSize: 20, fontWeight: FontWeight.w500, - color: Colors.black87, + color: Colors.white, ), ), const SizedBox(height: 15), @@ -231,56 +278,112 @@ class _LoginPageState extends State { obscureText: obscureText, keyboardType: keyboardType, validator: validator, - // 关键属性:让文字在行内垂直居中 textAlignVertical: TextAlignVertical.center, decoration: InputDecoration( hintText: hintText, + hintStyle: const TextStyle(color: Colors.white70), suffixIcon: suffixIcon, - // 去掉默认的上下/左右 padding,让文字贴紧外层的 25 左边距 isDense: true, contentPadding: EdgeInsets.zero, ), + style: const TextStyle(color: Colors.white), ), ], ), ); } + Future _handleLogin() async { + // 表单校验 + if (!(_formKey.currentState?.validate() ?? false)) return; - // 登录处理 - void _handleLogin() { - // 清除之前的错误信息 - setState(() => _errorMessage = ''); - Navigator.pushReplacement( - context, - MaterialPageRoute(builder: (context) => const MainPage()), + final userName = _phoneController.text.trim(); + final userPwd = _passwordController.text; + + // RSA 加密:encrypt 包的用法 + final parser = encrypt.RSAKeyParser(); + final pub = parser.parse(ApiService.publicKey) as RSAPublicKey; + final encrypter = encrypt.Encrypter(encrypt.RSA(publicKey: pub)); + final plain = 'zcloudchina$userName,zy,$userPwd'; + + String keydataVal; + try { + keydataVal = encrypter.encrypt(plain).base64; + } catch (e) { + Fluttertoast.showToast(msg: '加密失败:$e', toastLength: Toast.LENGTH_LONG); + return; + } + + setState(() => _isLoading = true); + showDialog( + context: context, + barrierDismissible: false, + builder: (_) => const Center(child: CircularProgressIndicator()), ); - // if (_formKey.currentState?.validate() ?? false) { - // setState(() => _isLoading = true); - // - // // 模拟登录请求 - // Future.delayed(const Duration(seconds: 2), () { - // setState(() => _isLoading = false); - // // 登录成功,跳转到主页 - // // Navigator.pushReplacement( - // // context, - // // MaterialPageRoute(builder: (context) => const MainPage()), - // // ); - // // 模拟登录逻辑 - // if (_phoneController.text == "13800138000" && - // _passwordController.text == "123456") { - // // 登录成功,跳转到主页 - // Navigator.pushReplacement( - // context, - // MaterialPageRoute(builder: (context) => const MainPage()), - // ); - // } else { - // // 登录失败,显示错误信息 - // setState(() { - // _errorMessage = '手机号或密码错误,请重试'; - // }); - // } - // }); - // } + + try { + final data = await ApiService.loginCheck(keydataVal); + final result = data['result'] as String? ?? ''; + + if (result == 'success') { + // 存储用户信息 + final prefs = await SharedPreferences.getInstance(); + await prefs.setString('USER', json.encode(data)); + await prefs.setStringList('remember', [userName, userPwd]); + + SessionService.instance + ..setLoginUserId(data['USER_ID'] as String) + ..setCorpinfoId(data['CORPINFO_ID'] as String) + ..setDeptId(data['DEPARTMENT_ID'] as String) + ..setDeptLevel(data['DEPARTMENT_LEVEL'] as String) + ..setIsRest(data['ISREST'] as String) + ..setUsername(data['NAME'] as String) + ..setLoginUser(data); // 这里 data 保存整个用户 JSON + + final weak = data['WEAK_PASSWORD'] == '1'; + final longTerm = data['LONG_TERM_PASSWORD_NOT_CHANGED'] == '1'; + + Navigator.of(context).pop(); // 关 loading + setState(() => _isLoading = false); + + if (weak) { + // uni.redirectTo({ + // url: '/pages/login/forget/forget-reset?canBack=1' + // }); + } else if (longTerm) { + // uni.redirectTo({ + // url: '/pages/login/forget/forget-reset?canBack=2' + // }); + + } else { + Navigator.pushReplacement( + context, + MaterialPageRoute(builder: (_) => const MainPage()), + ); + } + + } else { + // 理论上不会走这里,非 'success' 会抛 ApiException + } + + } on ApiException catch (e) { + // 业务错误: + Navigator.of(context).pop(); + setState(() => _isLoading = false); + + String tip = e.message; + + Fluttertoast.showToast(msg: tip, toastLength: Toast.LENGTH_LONG); + + } catch (e) { + // 网络或其它未预期错误 + Navigator.of(context).pop(); + setState(() => _isLoading = false); + Fluttertoast.showToast( + msg: '服务器正在升级,请稍后再试。\n${e.toString()}', + toastLength: Toast.LENGTH_LONG, + ); + } } -} + +} \ No newline at end of file diff --git a/lib/tools/StorageService.dart b/lib/tools/StorageService.dart new file mode 100644 index 0000000..7d1bfb6 --- /dev/null +++ b/lib/tools/StorageService.dart @@ -0,0 +1,52 @@ +import 'package:shared_preferences/shared_preferences.dart'; + +class StorageService { + StorageService._internal(); + static final StorageService instance = StorageService._internal(); + + late final SharedPreferences _prefs; + + /// 启动时调用一次,确保 prefs 已就绪 + Future init() async { + _prefs = await SharedPreferences.getInstance(); + } + + /// 存储 String + Future setString(String key, String value) => + _prefs.setString(key, value); + + /// 读取 String + String? getString(String key) => _prefs.getString(key); + + /// 存储 String 列表 + Future setStringList(String key, List value) => + _prefs.setStringList(key, value); + + /// 读取 String 列表 + List? getStringList(String key) => _prefs.getStringList(key); + + /// 存储 int + Future setInt(String key, int value) => _prefs.setInt(key, value); + + /// 读取 int + int? getInt(String key) => _prefs.getInt(key); + + /// 存储 bool + Future setBool(String key, bool value) => _prefs.setBool(key, value); + + /// 读取 bool + bool? getBool(String key) => _prefs.getBool(key); + + /// 存储 double + Future setDouble(String key, double value) => + _prefs.setDouble(key, value); + + /// 读取 double + double? getDouble(String key) => _prefs.getDouble(key); + + /// 删除单个 key + Future remove(String key) => _prefs.remove(key); + + /// 清空所有 + Future clear() => _prefs.clear(); +} diff --git a/lib/tools/tools.dart b/lib/tools/tools.dart index 75d69b6..88dc670 100644 --- a/lib/tools/tools.dart +++ b/lib/tools/tools.dart @@ -17,15 +17,14 @@ double screenWidth(BuildContext context) { 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, - ), + MaterialPageRoute(fullscreenDialog: true, builder: (context) => page), ); } + /// 文本样式工具类 /// 文本样式工具类 /// 文本样式工具类,返回 Text Widget @@ -36,11 +35,11 @@ class HhTextStyleUtils { /// [fontSize]: 字体大小,默认16.0 /// [bold]: 是否加粗,默认true static Text mainTitle( - String text, { - Color color = Colors.black, - double fontSize = 16.0, - bool bold = true, - }) { + String text, { + Color color = Colors.black, + double fontSize = 16.0, + bool bold = true, + }) { return Text( text, style: TextStyle( @@ -50,7 +49,11 @@ class HhTextStyleUtils { ), ); } - static TextStyle secondaryTitleStyle = TextStyle(color:Colors.black54, fontSize: 15.0); + + static TextStyle secondaryTitleStyle = TextStyle( + color: Colors.black54, + fontSize: 15.0, + ); /// 次要标题,返回 Text /// [text]: 文本内容 @@ -58,15 +61,14 @@ class HhTextStyleUtils { /// [fontSize]: 字体大小,默认14.0 /// [bold]: 是否加粗,默认false static Text secondaryTitle( - String text, { - Color color = Colors.black54, - double fontSize = 14.0, - bool bold = false, - }) { + 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, @@ -80,11 +82,11 @@ class HhTextStyleUtils { /// [fontSize]: 字体大小,默认12.0 /// [bold]: 是否加粗,默认false static Text smallText( - String text, { - Color color = Colors.black54, - double fontSize = 12.0, - bool bold = false, - }) { + String text, { + Color color = Colors.black54, + double fontSize = 12.0, + bool bold = false, + }) { return Text( text, style: TextStyle( @@ -131,4 +133,120 @@ Future getAppVersion() async { fullVersion: '1.0.0+0', ); } -} \ No newline at end of file +} + +/// ------------------------------------------------------ +/// 全局会话管理 +/// ------------------------------------------------------ +class SessionService { + SessionService._(); + + static final SessionService instance = SessionService._(); + + String? corpinfoId; + String? loginUserId; + Map? loginUser; + String? deptId; + String? deptLevel; + String? postId; + String? username; + String? version; + String? basePath; + String? isRest; + List? permission; + bool updateInfo = false; + + /// 如果以下任何一项为空,则跳转到登录页 + void loginSession(BuildContext context) { + if (corpinfoId == null || loginUserId == null || loginUser == null) { + Navigator.pushReplacementNamed(context, '/login'); + } + } + + // setters + void setLoginUser(Map user) => loginUser = user; + + void setLoginUserId(String id) => loginUserId = id; + + void setCorpinfoId(String id) => corpinfoId = id; + + void setDeptId(String id) => deptId = id; + + void setDeptLevel(String level) => deptLevel = level; + + void setPostId(String id) => postId = id; + + void setUsername(String name) => username = name; + + void setVersion(String ver) => version = ver; + + void setBasePath(String url) => basePath = url; + + void setIsRest(String rest) => isRest = rest; + + void setPermission(List list) => permission = list; + + void setUpdateInfo(bool flag) => updateInfo = flag; + + +} + +/// ------------------------------------------------------ +/// 日期格式化 +/// ------------------------------------------------------ +String formatDate(DateTime? date, String fmt) { + if (date == null) return ''; + String twoDigits(int n) => n.toString().padLeft(2, '0'); + + final replacements = { + 'yyyy': date.year.toString(), + 'yy': date.year.toString().substring(2), + 'MM': twoDigits(date.month), + 'M': date.month.toString(), + 'dd': twoDigits(date.day), + 'd': date.day.toString(), + 'hh': twoDigits(date.hour), + 'h': date.hour.toString(), + 'mm': twoDigits(date.minute), + 'm': date.minute.toString(), + 'ss': twoDigits(date.second), + 's': date.second.toString(), + }; + + String result = fmt; + replacements.forEach((key, value) { + result = result.replaceAllMapped(RegExp(key), (_) => value); + }); + return result; +} + +/// ------------------------------------------------------ +/// 防多次点击 +/// ------------------------------------------------------ +class ClickUtil { + ClickUtil._(); + + static bool _canClick = true; + + /// 调用示例: + /// ClickUtil.noMultipleClicks(() { /* your code */ }); + static void noMultipleClicks(VoidCallback fn, {int delayMs = 2000}) { + if (_canClick) { + _canClick = false; + fn(); + Future.delayed(Duration(milliseconds: delayMs), () { + _canClick = true; + }); + } else { + // 可替换成 Toast + debugPrint('请稍后点击'); + } + } +} + +void presentPage(BuildContext context, Widget page) { + Navigator.push( + context, + MaterialPageRoute(fullscreenDialog: true, builder: (_) => page), + ); +} diff --git a/pubspec.lock b/pubspec.lock index 065dc98..f32a19a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -9,6 +9,14 @@ packages: url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.7.0" + asn1lib: + dependency: transitive + description: + name: asn1lib + sha256: "9a8f69025044eb466b9b60ef3bc3ac99b4dc6c158ae9c56d25eeccf5bc56d024" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "1.6.5" async: dependency: transitive description: @@ -65,6 +73,14 @@ packages: url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.0.1" + convert: + dependency: transitive + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "3.1.2" cross_file: dependency: transitive description: @@ -105,6 +121,30 @@ packages: url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.7.11" + dio: + dependency: "direct main" + description: + name: dio + sha256: "253a18bbd4851fecba42f7343a1df3a9a4c1d31a2c1b37e221086b4fa8c8dbc9" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "5.8.0+1" + dio_web_adapter: + dependency: transitive + description: + name: dio_web_adapter + sha256: "7586e476d70caecaf1686d21eee7247ea43ef5c345eab9e0cc3583ff13378d78" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "2.1.1" + encrypt: + dependency: "direct main" + description: + name: encrypt + sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "5.0.3" extended_image: dependency: transitive description: @@ -208,6 +248,14 @@ packages: description: flutter source: sdk version: "0.0.0" + fluttertoast: + dependency: "direct main" + description: + name: fluttertoast + sha256: "25e51620424d92d3db3832464774a6143b5053f15e382d8ffbfd40b6e795dcf1" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "8.2.12" html: dependency: transitive description: @@ -528,6 +576,14 @@ packages: url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "2.1.8" + pointycastle: + dependency: "direct main" + description: + name: pointycastle + sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "3.9.1" provider: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index f28a5d2..169eab7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -50,6 +50,14 @@ dependencies: video_player: ^2.10.0 #网络监听 connectivity_plus: ^6.1.4 + #接口请求 + dio: ^5.8.0+1 + #toast + fluttertoast: ^8.2.12 + #RSA 加密库 + encrypt: ^5.0.3 + pointycastle: ^3.6.2 + dev_dependencies: flutter_test: sdk: flutter