Compare commits
2 Commits
c738be9e23
...
d0307e7f09
Author | SHA1 | Date |
---|---|---|
|
d0307e7f09 | |
|
a68c1448c6 |
|
@ -1,6 +1,6 @@
|
||||||
# qhd_prevention
|
# flutter_integrated_whb
|
||||||
|
|
||||||
A new Flutter project.
|
危化项目.
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
|
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 9.5 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 72 KiB |
After Width: | Height: | Size: 343 KiB |
Before Width: | Height: | Size: 226 KiB After Width: | Height: | Size: 428 KiB |
Before Width: | Height: | Size: 180 KiB After Width: | Height: | Size: 110 KiB |
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 170 KiB |
Before Width: | Height: | Size: 381 KiB After Width: | Height: | Size: 345 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 78 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 23 KiB |
|
@ -2,6 +2,8 @@ PODS:
|
||||||
- connectivity_plus (0.0.1):
|
- connectivity_plus (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- Flutter (1.0.0)
|
- Flutter (1.0.0)
|
||||||
|
- fluttertoast (0.0.2):
|
||||||
|
- Flutter
|
||||||
- image_picker_ios (0.0.1):
|
- image_picker_ios (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- mobile_scanner (7.0.0):
|
- mobile_scanner (7.0.0):
|
||||||
|
@ -25,6 +27,7 @@ PODS:
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
|
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
|
||||||
- Flutter (from `Flutter`)
|
- Flutter (from `Flutter`)
|
||||||
|
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
|
||||||
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
|
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
|
||||||
- mobile_scanner (from `.symlinks/plugins/mobile_scanner/darwin`)
|
- mobile_scanner (from `.symlinks/plugins/mobile_scanner/darwin`)
|
||||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||||
|
@ -38,6 +41,8 @@ EXTERNAL SOURCES:
|
||||||
:path: ".symlinks/plugins/connectivity_plus/ios"
|
:path: ".symlinks/plugins/connectivity_plus/ios"
|
||||||
Flutter:
|
Flutter:
|
||||||
:path: Flutter
|
:path: Flutter
|
||||||
|
fluttertoast:
|
||||||
|
:path: ".symlinks/plugins/fluttertoast/ios"
|
||||||
image_picker_ios:
|
image_picker_ios:
|
||||||
:path: ".symlinks/plugins/image_picker_ios/ios"
|
:path: ".symlinks/plugins/image_picker_ios/ios"
|
||||||
mobile_scanner:
|
mobile_scanner:
|
||||||
|
@ -56,6 +61,7 @@ EXTERNAL SOURCES:
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
|
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
|
||||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||||
|
fluttertoast: 2c67e14dce98bbdb200df9e1acf610d7a6264ea1
|
||||||
image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a
|
image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a
|
||||||
mobile_scanner: 9157936403f5a0644ca3779a38ff8404c5434a93
|
mobile_scanner: 9157936403f5a0644ca3779a38ff8404c5434a93
|
||||||
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
|
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
|
||||||
|
|
|
@ -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<Map<String, dynamic>> 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<Map<String, dynamic>> 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<Map<String, dynamic>> getRedPoint() {
|
||||||
|
return HttpManager().request(
|
||||||
|
basePath,
|
||||||
|
'/app/eightwork/checkWork',
|
||||||
|
method: Method.post,
|
||||||
|
data: {'USER_ID': SessionService.instance.loginUserId},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
static Future<Map<String, dynamic>> 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<Map<String, dynamic>> 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<Map<String, dynamic>> getUpdateInfo() {
|
||||||
|
return HttpManager().request(
|
||||||
|
projectManagerUrl,
|
||||||
|
'/projectDetails/findUpdate?code=cloud&type=APP',
|
||||||
|
method: Method.post,
|
||||||
|
data: {},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<Map<String, dynamic>> 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<Map<String, dynamic>> 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<Map<String, dynamic>> getSurveyData() {
|
||||||
|
return HttpManager().request(
|
||||||
|
basePath,
|
||||||
|
'/app/survey/goEdit',
|
||||||
|
method: Method.post,
|
||||||
|
data: {
|
||||||
|
'CORPINFO_ID': SessionService.instance.corpinfoId,
|
||||||
|
'USER_ID': SessionService.instance.loginUserId,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<Map<String, dynamic>> getUserId() {
|
||||||
|
return HttpManager().request(
|
||||||
|
basePath,
|
||||||
|
'/app/surveyanswer/getUserId',
|
||||||
|
method: Method.post,
|
||||||
|
data: {
|
||||||
|
'CORPINFO_ID': SessionService.instance.corpinfoId,
|
||||||
|
'USER_ID': SessionService.instance.loginUserId,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
/// 获取清单数量
|
||||||
|
static Future<Map<String, dynamic>> 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<Map<String, dynamic>> getHiddenRoll() {
|
||||||
|
return HttpManager().request(
|
||||||
|
basePath,
|
||||||
|
'/app/hidden/getHiddenByCorp',
|
||||||
|
method: Method.post,
|
||||||
|
data: {
|
||||||
|
'CORPINFO_ID': SessionService.instance.corpinfoId,
|
||||||
|
'HIDDENLEVEL': 'hiddenLevel0001',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<Map<String, dynamic>> getIsRest() {
|
||||||
|
return HttpManager().request(
|
||||||
|
basePath,
|
||||||
|
'/app/hidden/getHiddenByCorp',
|
||||||
|
method: Method.post,
|
||||||
|
data: {
|
||||||
|
'CORPINFO_ID': SessionService.instance.corpinfoId,
|
||||||
|
'USER_ID': SessionService.instance.loginUserId,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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<Map<String, dynamic>> request(
|
||||||
|
String baseUrl,
|
||||||
|
String path, {
|
||||||
|
Method method = Method.post,
|
||||||
|
Map<String, dynamic>? data,
|
||||||
|
Map<String, dynamic>? 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<String, dynamic>
|
||||||
|
? resp.data as Map<String, dynamic>
|
||||||
|
: <String, dynamic>{};
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
import 'dart:ffi';
|
import 'dart:ffi';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.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/work/danger_wait_list_page.dart';
|
||||||
import 'package:qhd_prevention/pages/home/workSet_page.dart';
|
import 'package:qhd_prevention/pages/home/workSet_page.dart';
|
||||||
|
|
||||||
|
import '../../http/ApiService.dart';
|
||||||
import '../../tools/tools.dart';
|
import '../../tools/tools.dart';
|
||||||
|
|
||||||
class HomePage extends StatefulWidget {
|
class HomePage extends StatefulWidget {
|
||||||
|
@ -19,44 +21,12 @@ class HomePage extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _HomePageState extends State<HomePage> {
|
class _HomePageState extends State<HomePage> {
|
||||||
final List<Map<String, String>> buttonInfos = [
|
final int _eight_work_count = 0;
|
||||||
{"icon": "assets/icon-apps/home-base.png", "title": "人员信息"},
|
final int _safetyEnvironmentalInspection = 0;
|
||||||
{"icon": "assets/icon-apps/home-rili.png", "title": "工作安排"},
|
late final List<Map<String, dynamic>> buttonInfos;
|
||||||
{"icon": "assets/icon-apps/home-risk.png", "title": "风险布控"},
|
|
||||||
{"icon": "assets/icon-apps/home-fl.png", "title": "法律法规"},
|
/// 我的工作
|
||||||
];
|
List<Map<String, dynamic>> workInfos = [];
|
||||||
final List<Map<String, dynamic>> 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 List<Map<String, dynamic>> pcData = [
|
final List<Map<String, dynamic>> pcData = [
|
||||||
{
|
{
|
||||||
"index": 1,
|
"index": 1,
|
||||||
|
@ -114,42 +84,6 @@ class _HomePageState extends State<HomePage> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
Widget _buildWorkSection(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
|
@ -194,8 +128,6 @@ class _HomePageState extends State<HomePage> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Widget _buildPCDataSection() {
|
Widget _buildPCDataSection() {
|
||||||
return Container(
|
return Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
|
@ -205,7 +137,6 @@ class _HomePageState extends State<HomePage> {
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
// _widgetTopTip(title: "排查数据"),
|
|
||||||
ListItemFactory.createBuildSimpleSection("排查数据"),
|
ListItemFactory.createBuildSimpleSection("排查数据"),
|
||||||
...pcData.map(_widgetPCDataItem),
|
...pcData.map(_widgetPCDataItem),
|
||||||
],
|
],
|
||||||
|
@ -213,26 +144,109 @@ class _HomePageState extends State<HomePage> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构建图标按钮:图上文字下
|
/// 定义 item 宽度
|
||||||
Widget _buildIconButton({
|
double _itemWidth(BuildContext context) {
|
||||||
required Widget icon,
|
final screenW = MediaQuery.of(context).size.width;
|
||||||
required String label,
|
return (screenW - 20) / 4;
|
||||||
required VoidCallback onPressed, // 添加点击回调参数
|
}
|
||||||
}) {
|
|
||||||
return InkWell(
|
Widget _buildIconSection(BuildContext context) {
|
||||||
onTap: onPressed, // 处理点击事件
|
return Container(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
child: Padding(
|
),
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
|
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 BuildContext context,
|
||||||
|
required String iconPath,
|
||||||
|
required String label,
|
||||||
|
required VoidCallback onPressed,
|
||||||
|
int unreadCount = 0,
|
||||||
|
}) {
|
||||||
|
final w = _itemWidth(context);
|
||||||
|
return InkWell(
|
||||||
|
onTap: onPressed,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
child: SizedBox(
|
||||||
|
width: w,
|
||||||
|
child: Stack(
|
||||||
|
clipBehavior: Clip.none,
|
||||||
|
children: [
|
||||||
|
/// 中心对齐
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.topCenter,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
icon,
|
Image.asset(iconPath, width: 40, height: 40),
|
||||||
const SizedBox(height: 5),
|
const SizedBox(height: 5),
|
||||||
Text(label, style: const TextStyle(fontSize: 14)),
|
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<HomePage> {
|
||||||
pushPage(DangerWaitListPage(DangerType.wait), context);
|
pushPage(DangerWaitListPage(DangerType.wait), context);
|
||||||
} else if (index == 3) {
|
} else if (index == 3) {
|
||||||
pushPage(DangerWaitListPage(DangerType.expired), context);
|
pushPage(DangerWaitListPage(DangerType.expired), context);
|
||||||
}else if (index == 4) {
|
} else if (index == 4) {
|
||||||
pushPage(DangerWaitListPage(DangerType.waitAcceptance), context);
|
pushPage(DangerWaitListPage(DangerType.waitAcceptance), context);
|
||||||
}else if (index == 5) {
|
} else if (index == 5) {
|
||||||
pushPage(DangerWaitListPage(DangerType.acceptance), context);
|
pushPage(DangerWaitListPage(DangerType.acceptance), context);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -357,4 +371,135 @@ class _HomePageState extends State<HomePage> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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<void> _fetchData() async {
|
||||||
|
try {
|
||||||
|
// “我的工作” 数量
|
||||||
|
final raw = await ApiService.getWork();
|
||||||
|
// 如果拿到的是 String,就 decode;如果本来就是 Map,就直接用
|
||||||
|
final Map<String, dynamic> data = raw is String
|
||||||
|
? json.decode(raw as String) as Map<String, dynamic>
|
||||||
|
: raw;
|
||||||
|
|
||||||
|
final hidCount = data['hidCount'] as Map<String, dynamic>;
|
||||||
|
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');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,18 @@
|
||||||
// ignore_for_file: use_build_context_synchronously
|
// 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: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';
|
import 'main_tab.dart';
|
||||||
|
|
||||||
void main() => runApp(const MyApp());
|
void main() => runApp(const MyApp());
|
||||||
|
@ -29,62 +41,82 @@ class LoginPage extends StatefulWidget {
|
||||||
const LoginPage({super.key});
|
const LoginPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
// ignore: library_private_types_in_public_api
|
|
||||||
_LoginPageState createState() => _LoginPageState();
|
_LoginPageState createState() => _LoginPageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _LoginPageState extends State<LoginPage> {
|
class _LoginPageState extends State<LoginPage> {
|
||||||
final TextEditingController _phoneController = TextEditingController();
|
final TextEditingController _phoneController = TextEditingController(text: '13293211008');
|
||||||
final TextEditingController _passwordController = TextEditingController();
|
final TextEditingController _passwordController = TextEditingController(text: 'Zsaq@123456');
|
||||||
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
|
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
|
||||||
String _errorMessage = '';
|
String _errorMessage = '';
|
||||||
bool _isLoading = false;
|
bool _isLoading = false;
|
||||||
bool _obscurePassword = true;
|
bool _obscurePassword = true;
|
||||||
|
bool _agreed = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Colors.white,
|
resizeToAvoidBottomInset: false,
|
||||||
body: SingleChildScrollView(
|
body: Container(
|
||||||
child: Column(
|
width: double.infinity,
|
||||||
children: [
|
height: double.infinity,
|
||||||
_buildHeader(),
|
|
||||||
|
|
||||||
Transform.translate(
|
|
||||||
offset: const Offset(0, -20),
|
|
||||||
child: Container(
|
|
||||||
decoration: const BoxDecoration(
|
decoration: const BoxDecoration(
|
||||||
color: Colors.white,
|
image: DecorationImage(
|
||||||
borderRadius: BorderRadius.only(
|
image: AssetImage('assets/images/bg-login.png'),
|
||||||
topLeft: Radius.circular(30),
|
fit: BoxFit.cover,
|
||||||
topRight: Radius.circular(30),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Padding(
|
child: Form(
|
||||||
padding: const EdgeInsets.only(top: 30),
|
key: _formKey,
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
Positioned.fill(
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/images/bg-login.png',
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 30),
|
||||||
|
child: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
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(
|
_buildInputSection(
|
||||||
label: "手机号码",
|
label: "手机号码",
|
||||||
controller: _phoneController,
|
controller: _phoneController,
|
||||||
hintText: "请输入手机号...",
|
hintText: "请输入手机号...",
|
||||||
keyboardType: TextInputType.phone,
|
keyboardType: TextInputType.phone,
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value == null || value.isEmpty) {
|
if (value == null || value.isEmpty)
|
||||||
return '请输入手机号';
|
return '请输入手机号';
|
||||||
}
|
// if (!RegExp(r'^1[3-9]\d{9}\$').hasMatch(value))
|
||||||
if (!RegExp(r'^1[3-9]\d{9}$').hasMatch(value)) {
|
// return '请输入有效的手机号';
|
||||||
return '请输入有效的手机号';
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
const Divider(
|
||||||
Padding(padding: const EdgeInsets.symmetric(horizontal: 25),
|
height: 1,
|
||||||
child: const Divider(height: 1, thickness: 1),
|
thickness: 1,
|
||||||
|
color: Colors.white70,
|
||||||
),
|
),
|
||||||
// 密码
|
|
||||||
_buildInputSection(
|
_buildInputSection(
|
||||||
label: "密码",
|
label: "密码",
|
||||||
controller: _passwordController,
|
controller: _passwordController,
|
||||||
|
@ -93,49 +125,52 @@ class _LoginPageState extends State<LoginPage> {
|
||||||
suffixIcon: IconButton(
|
suffixIcon: IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
_obscurePassword
|
_obscurePassword
|
||||||
? Icons.visibility
|
? Icons.visibility_off
|
||||||
: Icons.visibility_off,
|
: Icons.visibility,
|
||||||
color: Colors.grey,
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
onPressed:
|
||||||
|
() =>
|
||||||
|
setState(
|
||||||
|
() => _obscurePassword = !_obscurePassword,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
|
||||||
setState(() {
|
|
||||||
_obscurePassword = !_obscurePassword;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value == null || value.isEmpty) {
|
if (value == null || value.isEmpty)
|
||||||
return '请输入密码';
|
return '请输入密码';
|
||||||
}
|
|
||||||
if (value.length < 6) {
|
|
||||||
return '密码长度至少6位';
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
Padding(padding: const EdgeInsets.symmetric(horizontal: 25),
|
const Divider(
|
||||||
child: const Divider(height: 1, thickness: 1),
|
height: 1,
|
||||||
|
thickness: 1,
|
||||||
|
color: Colors.white70,
|
||||||
),
|
),
|
||||||
// 登录按钮
|
const SizedBox(height: 30),
|
||||||
|
if (_errorMessage.isNotEmpty)
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(horizontal: 25),
|
||||||
horizontal: 25, vertical: 24),
|
child: Text(
|
||||||
|
_errorMessage,
|
||||||
|
style: const TextStyle(color: Colors.blue),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 24),
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
height: 48,
|
height: 48,
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: _isLoading ? null : _handleLogin,
|
onPressed:
|
||||||
|
(!_isLoading && _agreed) ? _handleLogin : null,
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.blue,
|
backgroundColor: Colors.blue,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: _isLoading
|
child:
|
||||||
? const CircularProgressIndicator(
|
const Text(
|
||||||
color: Colors.white,
|
|
||||||
)
|
|
||||||
: const Text(
|
|
||||||
'登录',
|
'登录',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
|
@ -146,63 +181,75 @@ class _LoginPageState extends State<LoginPage> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(padding: const EdgeInsets.only(left: 30, right: 30),
|
|
||||||
child:Text(" 本平台为互联网非涉密平台,严禁处理、传输国家秘密和工作秘密",
|
Padding(
|
||||||
style: TextStyle(color: Colors.red))
|
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({
|
Widget _buildInputSection({
|
||||||
required String label,
|
required String label,
|
||||||
required TextEditingController controller,
|
required TextEditingController controller,
|
||||||
|
@ -213,7 +260,7 @@ class _LoginPageState extends State<LoginPage> {
|
||||||
String? Function(String?)? validator,
|
String? Function(String?)? validator,
|
||||||
}) {
|
}) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 12),
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
@ -222,7 +269,7 @@ class _LoginPageState extends State<LoginPage> {
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
color: Colors.black87,
|
color: Colors.white,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 15),
|
const SizedBox(height: 15),
|
||||||
|
@ -231,56 +278,112 @@ class _LoginPageState extends State<LoginPage> {
|
||||||
obscureText: obscureText,
|
obscureText: obscureText,
|
||||||
keyboardType: keyboardType,
|
keyboardType: keyboardType,
|
||||||
validator: validator,
|
validator: validator,
|
||||||
// 关键属性:让文字在行内垂直居中
|
|
||||||
textAlignVertical: TextAlignVertical.center,
|
textAlignVertical: TextAlignVertical.center,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: hintText,
|
hintText: hintText,
|
||||||
|
hintStyle: const TextStyle(color: Colors.white70),
|
||||||
suffixIcon: suffixIcon,
|
suffixIcon: suffixIcon,
|
||||||
// 去掉默认的上下/左右 padding,让文字贴紧外层的 25 左边距
|
|
||||||
isDense: true,
|
isDense: true,
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
),
|
),
|
||||||
|
style: const TextStyle(color: Colors.white),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _handleLogin() async {
|
||||||
|
// 表单校验
|
||||||
|
if (!(_formKey.currentState?.validate() ?? false)) return;
|
||||||
|
|
||||||
// 登录处理
|
final userName = _phoneController.text.trim();
|
||||||
void _handleLogin() {
|
final userPwd = _passwordController.text;
|
||||||
// 清除之前的错误信息
|
|
||||||
setState(() => _errorMessage = '');
|
// 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()),
|
||||||
|
);
|
||||||
|
|
||||||
|
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(
|
Navigator.pushReplacement(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(builder: (context) => const MainPage()),
|
MaterialPageRoute(builder: (_) => const MainPage()),
|
||||||
);
|
);
|
||||||
// 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 = '手机号或密码错误,请重试';
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} 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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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<void> init() async {
|
||||||
|
_prefs = await SharedPreferences.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 存储 String
|
||||||
|
Future<bool> setString(String key, String value) =>
|
||||||
|
_prefs.setString(key, value);
|
||||||
|
|
||||||
|
/// 读取 String
|
||||||
|
String? getString(String key) => _prefs.getString(key);
|
||||||
|
|
||||||
|
/// 存储 String 列表
|
||||||
|
Future<bool> setStringList(String key, List<String> value) =>
|
||||||
|
_prefs.setStringList(key, value);
|
||||||
|
|
||||||
|
/// 读取 String 列表
|
||||||
|
List<String>? getStringList(String key) => _prefs.getStringList(key);
|
||||||
|
|
||||||
|
/// 存储 int
|
||||||
|
Future<bool> setInt(String key, int value) => _prefs.setInt(key, value);
|
||||||
|
|
||||||
|
/// 读取 int
|
||||||
|
int? getInt(String key) => _prefs.getInt(key);
|
||||||
|
|
||||||
|
/// 存储 bool
|
||||||
|
Future<bool> setBool(String key, bool value) => _prefs.setBool(key, value);
|
||||||
|
|
||||||
|
/// 读取 bool
|
||||||
|
bool? getBool(String key) => _prefs.getBool(key);
|
||||||
|
|
||||||
|
/// 存储 double
|
||||||
|
Future<bool> setDouble(String key, double value) =>
|
||||||
|
_prefs.setDouble(key, value);
|
||||||
|
|
||||||
|
/// 读取 double
|
||||||
|
double? getDouble(String key) => _prefs.getDouble(key);
|
||||||
|
|
||||||
|
/// 删除单个 key
|
||||||
|
Future<bool> remove(String key) => _prefs.remove(key);
|
||||||
|
|
||||||
|
/// 清空所有
|
||||||
|
Future<bool> clear() => _prefs.clear();
|
||||||
|
}
|
|
@ -17,15 +17,14 @@ double screenWidth(BuildContext context) {
|
||||||
void pushPage(Widget page, BuildContext context) {
|
void pushPage(Widget page, BuildContext context) {
|
||||||
Navigator.push(context, MaterialPageRoute(builder: (context) => page));
|
Navigator.push(context, MaterialPageRoute(builder: (context) => page));
|
||||||
}
|
}
|
||||||
|
|
||||||
void present(Widget page, BuildContext context) {
|
void present(Widget page, BuildContext context) {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(fullscreenDialog: true, builder: (context) => page),
|
||||||
fullscreenDialog: true,
|
|
||||||
builder: (context) => page,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 文本样式工具类
|
/// 文本样式工具类
|
||||||
/// 文本样式工具类
|
/// 文本样式工具类
|
||||||
/// 文本样式工具类,返回 Text Widget
|
/// 文本样式工具类,返回 Text Widget
|
||||||
|
@ -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
|
||||||
/// [text]: 文本内容
|
/// [text]: 文本内容
|
||||||
|
@ -66,7 +69,6 @@ class HhTextStyleUtils {
|
||||||
return Text(
|
return Text(
|
||||||
text,
|
text,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
|
|
||||||
color: color,
|
color: color,
|
||||||
fontSize: fontSize,
|
fontSize: fontSize,
|
||||||
fontWeight: bold ? FontWeight.bold : FontWeight.normal,
|
fontWeight: bold ? FontWeight.bold : FontWeight.normal,
|
||||||
|
@ -132,3 +134,119 @@ Future<AppVersionInfo> getAppVersion() async {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ------------------------------------------------------
|
||||||
|
/// 全局会话管理
|
||||||
|
/// ------------------------------------------------------
|
||||||
|
class SessionService {
|
||||||
|
SessionService._();
|
||||||
|
|
||||||
|
static final SessionService instance = SessionService._();
|
||||||
|
|
||||||
|
String? corpinfoId;
|
||||||
|
String? loginUserId;
|
||||||
|
Map<String, dynamic>? loginUser;
|
||||||
|
String? deptId;
|
||||||
|
String? deptLevel;
|
||||||
|
String? postId;
|
||||||
|
String? username;
|
||||||
|
String? version;
|
||||||
|
String? basePath;
|
||||||
|
String? isRest;
|
||||||
|
List<dynamic>? permission;
|
||||||
|
bool updateInfo = false;
|
||||||
|
|
||||||
|
/// 如果以下任何一项为空,则跳转到登录页
|
||||||
|
void loginSession(BuildContext context) {
|
||||||
|
if (corpinfoId == null || loginUserId == null || loginUser == null) {
|
||||||
|
Navigator.pushReplacementNamed(context, '/login');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setters
|
||||||
|
void setLoginUser(Map<String, dynamic> 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<dynamic> 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 = <String, String>{
|
||||||
|
'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),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
56
pubspec.lock
|
@ -9,6 +9,14 @@ packages:
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.7.0"
|
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:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -65,6 +73,14 @@ packages:
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
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:
|
cross_file:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -105,6 +121,30 @@ packages:
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.11"
|
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:
|
extended_image:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -208,6 +248,14 @@ packages:
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
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:
|
html:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -528,6 +576,14 @@ packages:
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.8"
|
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:
|
provider:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
13
pubspec.yaml
|
@ -50,12 +50,13 @@ dependencies:
|
||||||
video_player: ^2.10.0
|
video_player: ^2.10.0
|
||||||
#网络监听
|
#网络监听
|
||||||
connectivity_plus: ^6.1.4
|
connectivity_plus: ^6.1.4
|
||||||
#网页页面加载
|
#接口请求
|
||||||
webview_flutter: ^4.4.0
|
dio: ^5.8.0+1
|
||||||
#手写签字
|
#toast
|
||||||
# signature: ^6.0.0
|
fluttertoast: ^8.2.12
|
||||||
|
#RSA 加密库
|
||||||
path_provider: ^2.0.1
|
encrypt: ^5.0.3
|
||||||
|
pointycastle: ^3.6.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|