。。。

main
hs 2025-09-18 15:40:01 +08:00
parent a70c6a7336
commit 2618fceec4
16 changed files with 216 additions and 134 deletions

View File

@ -184,14 +184,14 @@ U6Hzm1ninpWeE+awIDAQAB
);
}
static Future<Map<String, dynamic>> getUpdateInfo() {
return HttpManager().request(
projectManagerUrl,
'/projectDetails/findUpdate?code=cloud&type=APP',
basePath,
'/app/versionmanager/getVersion',
method: Method.post,
data: {},
data: {
'FILETYPE':Platform.pathSeparator
},
);
}
@ -533,14 +533,10 @@ U6Hzm1ninpWeE+awIDAQAB
);
}
///
static Future<Map<String, dynamic>> getUserFace(
///
static Future<Map<String, dynamic>> getStudyUserFace(
String imagePath,
String studentId,
String VIDEOCOURSEWARE_ID,
String CURRICULUM_ID,
String CHAPTER_ID,
String CLASS_ID,
Map data
) async {
final file = File(imagePath);
if (!await file.exists()) {
@ -550,17 +546,53 @@ U6Hzm1ninpWeE+awIDAQAB
return HttpManager().uploadFaceImage(
baseUrl: baseFacePath,
path: '/app/user/compareFaceV2',
fromData: {
...data,
'USER_ID': SessionService.instance.loginUserId,
'CORPINFO_ID': SessionService.instance.corpinfoId,
'FFILE': await MultipartFile.fromFile(file.path, filename: fileName),
},
);
}
static Future<Map<String, dynamic>> getUpdataUserFace(
String imagePath,
Map data
) async {
final file = File(imagePath);
if (!await file.exists()) {
throw ApiException('file_not_found', '图片不存在:$imagePath');
}
final fileName = file.path.split(Platform.pathSeparator).last;
return HttpManager().uploadFaceImage(
baseUrl: basePath,
path: '/app/user/editUserFaceV2',
fromData: {
...data,
'USER_ID': SessionService.instance.loginUserId,
'CORPINFO_ID': SessionService.instance.corpinfoId,
'FFILE': await MultipartFile.fromFile(file.path, filename: fileName),
},
);
}
static Future<Map<String, dynamic>> getScanUserFace(
String imagePath,
Map data
) async {
final file = File(imagePath);
if (!await file.exists()) {
throw ApiException('file_not_found', '图片不存在:$imagePath');
}
final fileName = file.path.split(Platform.pathSeparator).last;
return HttpManager().uploadFaceImage(
baseUrl: basePath,
path: '/app/user/compareFaceForH5V2',
fromData: {
...data,
'USER_ID': SessionService.instance.loginUserId,
'STUDENT_ID': studentId,
'CORPINFO_ID': SessionService.instance.corpinfoId,
"CLASS_ID":CLASS_ID,
"VIDEOCOURSEWARE_ID": VIDEOCOURSEWARE_ID,
"CURRICULUM_ID": CURRICULUM_ID,
"CHAPTER_ID": CHAPTER_ID,
'FFILE': await MultipartFile.fromFile(file.path, filename: fileName),
},
);

View File

@ -14,7 +14,9 @@ import 'package:qhd_prevention/tools/tools.dart';
class ScanPage extends StatefulWidget {
// const ScanPage({Key? key}) : super(key: key,);
const ScanPage({super.key, required this.totalList});
final List totalList;
@override
State<ScanPage> createState() => _ScanPageState();
}
@ -99,9 +101,9 @@ class _ScanPageState extends State<ScanPage> {
} catch (e, st) {
//
print('handleScanResult error: $e\n$st');
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('扫码处理失败: ${e.toString()}')),
);
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('扫码处理失败: ${e.toString()}')));
}
}
@ -109,10 +111,17 @@ class _ScanPageState extends State<ScanPage> {
void goToFace(Map<String, dynamic> stuInfo) async {
print('navigate to face with $stuInfo');
final passed = await pushPage<bool>(
FaceRecognitionPage(studentId: stuInfo['STUDENT_ID'],
VIDEOCOURSEWARE_ID: stuInfo['VIDEOCOURSEWARE_ID'],CURRICULUM_ID: stuInfo['CURRICULUM_ID'],
CHAPTER_ID: stuInfo['CHAPTER_ID'],CLASS_ID: stuInfo['CLASS_ID'],
mode: FaceMode.auto),
FaceRecognitionPage(
studentId: stuInfo['STUDENT_ID'],
data: {
'VIDEOCOURSEWARE_ID': stuInfo['VIDEOCOURSEWARE_ID'],
'CURRICULUM_ID': stuInfo['CURRICULUM_ID'],
'CHAPTER_ID': stuInfo['CHAPTER_ID'],
'CLASS_ID': stuInfo['CLASS_ID'],
'STUDENT_ID':stuInfo['STUDENT_ID'],
},
mode: FaceMode.scan,
),
context,
);
if (passed == true) {
@ -127,8 +136,8 @@ class _ScanPageState extends State<ScanPage> {
//
void goToList({required String listId, required String listName}) {
print('navigate to list: $listId, name: $listName');
Navigator.pop(context,Animation);
pushPage(RiskListPage(1, listId,""), context);
Navigator.pop(context, Animation);
pushPage(RiskListPage(1, listId, ""), context);
}
@override
@ -175,15 +184,20 @@ class _ScanPageState extends State<ScanPage> {
//
// 1.
Positioned(
left: 0, right: 0, top: 0,
height: top, //
left: 0,
right: 0,
top: 0,
height: top,
//
child: Container(color: Colors.black54),
),
// 2.
Positioned(
left: 0, right: 0,
top: top + scanSize, //
left: 0,
right: 0,
top: top + scanSize,
//
bottom: 0,
child: Container(color: Colors.black54),
),
@ -192,8 +206,10 @@ class _ScanPageState extends State<ScanPage> {
Positioned(
left: 0,
top: top,
width: left, //
height: scanSize, //
width: left,
//
height: scanSize,
//
child: Container(color: Colors.black54),
),
@ -202,7 +218,8 @@ class _ScanPageState extends State<ScanPage> {
left: left + scanSize,
top: top,
right: 0,
height: scanSize, //
height: scanSize,
//
child: Container(color: Colors.black54),
),
@ -239,11 +256,15 @@ class _ScanPageState extends State<ScanPage> {
child: IconButton(
iconSize: 32,
color: Colors.white,
icon: Icon(_torchOn ? Icons.flashlight_off_outlined : Icons.flashlight_on_outlined),
icon: Icon(
_torchOn
? Icons.flashlight_off_outlined
: Icons.flashlight_on_outlined,
),
onPressed: () {
_controller.toggleTorch();
setState(() {
_torchOn = !_torchOn;
_torchOn = !_torchOn;
});
},
),
@ -273,5 +294,4 @@ class _ScanPageState extends State<ScanPage> {
),
);
}
}

View File

@ -17,28 +17,18 @@ import 'package:qhd_prevention/tools/tools.dart';
const MethodChannel _platformChan = MethodChannel('qhd_prevention/permissions');
///
enum FaceMode { auto, manual }
enum FaceMode { setUpdata, study, scan }
class FaceRecognitionPage extends StatefulWidget {
final String studentId;
final String VIDEOCOURSEWARE_ID;
final String CURRICULUM_ID;
final String CHAPTER_ID;
final String CLASS_ID;
final Map data;
final FaceMode mode;
const FaceRecognitionPage({
Key? key,
required this.studentId,
required this.VIDEOCOURSEWARE_ID,
required this.CURRICULUM_ID,
required this.CHAPTER_ID,
required this.CLASS_ID,
this.mode = FaceMode.auto,
required this.data,
this.mode = FaceMode.study,
}) : super(key: key);
@override
@ -55,7 +45,7 @@ class _FaceRecognitionPageState extends State<FaceRecognitionPage>
static const Duration _interval = Duration(seconds: 2);
String _errMsg = '';
bool get _isManualMode => widget.mode == FaceMode.manual;
bool get _isManualMode => widget.mode == FaceMode.setUpdata;
bool _isInitializing = false;
bool _isTaking = false;
@ -271,9 +261,18 @@ class _FaceRecognitionPageState extends State<FaceRecognitionPage>
} catch (_) {}
final XFile pic = await _cameraController!.takePicture();
final res = await ApiService.getUserFace(pic.path, widget.studentId,
widget.VIDEOCOURSEWARE_ID,widget.CURRICULUM_ID,widget.CHAPTER_ID,widget.CLASS_ID,);
var res = {};
switch(widget.mode) {
case FaceMode.study:
res = await ApiService.getStudyUserFace(pic.path, widget.data);
break;
case FaceMode.setUpdata:
res = await ApiService.getUpdataUserFace(pic.path, widget.data);
break;
case FaceMode.scan:
res = await ApiService.getScanUserFace(pic.path, widget.data);
break;
}
if (res['result'] == 'success') {
_onSuccess();
} else {
@ -335,7 +334,7 @@ class _FaceRecognitionPageState extends State<FaceRecognitionPage>
void _onSuccess() {
_timer?.cancel();
if (widget.mode == FaceMode.manual) {
if (widget.mode == FaceMode.setUpdata) {
ToastUtil.showSuccess(context, '已更新人脸信息');
Future.delayed(const Duration(milliseconds: 800), () {
if (mounted) Navigator.of(context).pop(true);

View File

@ -236,7 +236,7 @@ class _StudyDetailPageState extends State<StudyDetailPage>
}
} catch (_) {}
await _navigateFaceIfNeeded(() async {
await _navigateFaceIfNeeded(data,() async {
if ((data['IS_VIDEO'] ?? 0) == 1) {
//
if (data['VIDEOFILES'] != null) {
@ -289,7 +289,7 @@ class _StudyDetailPageState extends State<StudyDetailPage>
});
}
Future<void> _navigateFaceIfNeeded(FutureOr<void> Function() onPass) async {
Future<void> _navigateFaceIfNeeded(Map data, FutureOr<void> Function() onPass) async {
if (!_isFace) {
await onPass();
return;
@ -303,13 +303,16 @@ class _StudyDetailPageState extends State<StudyDetailPage>
await _exitTopRouteAndWait();
await _lockPortrait();
final passed = await pushPage<bool>(
FaceRecognitionPage(
FaceRecognitionPage (
studentId: widget.studentId,
VIDEOCOURSEWARE_ID: "",
CURRICULUM_ID: "",
CHAPTER_ID: "",
CLASS_ID: "",
mode: FaceMode.auto,
data: {
'CLASS_ID': widget.studyData['CLASS_ID'],
'STUDENT_ID': widget.studyData['STUDENT_ID'],
'CURRICULUM_ID': data['CURRICULUM_ID'],
'CHAPTER_ID': data['CHAPTER_ID'],
'VIDEOCOURSEWARE_ID': data['VIDEOCOURSEWARE_ID']
},
mode: FaceMode.study,
),
context,
);
@ -332,17 +335,17 @@ class _StudyDetailPageState extends State<StudyDetailPage>
if (ok) {
await _exitTopRouteAndWait();
await _lockPortrait();
await pushPage(
const FaceRecognitionPage(
studentId: '',
VIDEOCOURSEWARE_ID: '',
CURRICULUM_ID: '',
CHAPTER_ID: '',
CLASS_ID: '',
mode: FaceMode.manual,
),
context,
);
await pushPage(FaceRecognitionPage (
studentId: widget.studentId,
data: {
'CLASS_ID': widget.studyData['CLASS_ID'],
'STUDENT_ID': widget.studyData['STUDENT_ID'],
'CURRICULUM_ID': data['CURRICULUM_ID'],
'CHAPTER_ID': data['CHAPTER_ID'],
'VIDEOCOURSEWARE_ID': data['VIDEOCOURSEWARE_ID']
},
mode: FaceMode.study,
), context);
await _restoreDefaultOrientations();
}
}
@ -695,13 +698,16 @@ class _StudyDetailPageState extends State<StudyDetailPage>
await _lockPortrait();
final passed = await pushPage<bool>(
FaceRecognitionPage(
FaceRecognitionPage (
studentId: widget.studentId,
VIDEOCOURSEWARE_ID: "",
CURRICULUM_ID: "",
CHAPTER_ID: "",
CLASS_ID: "",
mode: FaceMode.auto,
data: {
'CLASS_ID': widget.studyData['CLASS_ID'],
'STUDENT_ID': widget.studyData['STUDENT_ID'],
'CURRICULUM_ID': _currentVideoData?['CURRICULUM_ID'],
'CHAPTER_ID': _currentVideoData?['CHAPTER_ID'],
'VIDEOCOURSEWARE_ID': _currentVideoData?['VIDEOCOURSEWARE_ID']
},
mode: FaceMode.study,
),
context,
);

View File

@ -76,7 +76,7 @@ class ItemListWidget {
onChanged: onChanged,
onSubmitted: onFieldSubmitted,
keyboardType: actualKeyboardType,
maxLength: showMaxLength?120:null,
maxLength: showMaxLength ? 120 : null,
style: TextStyle(fontSize: fontSize),
maxLines: 1,
//
@ -146,6 +146,7 @@ class ItemListWidget {
bool isRequired = true,
String hintText = '请输入',
ValueChanged<String>? onChanged,
bool showMaxLength = false,
}) {
return Container(
// padding线
@ -179,6 +180,7 @@ class ItemListWidget {
maxLines: null,
expands: true,
onChanged: onChanged,
maxLength: showMaxLength ? 120 : null,
//
textAlignVertical: TextAlignVertical.top,
style: TextStyle(fontSize: fontSize),

View File

@ -187,7 +187,6 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
/// 1 0
Future<void> _submit(String status) async {
if (imagePaths.isEmpty) {
ToastUtil.showNormal(context, '请签字');
return;
@ -208,19 +207,19 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
title: '作废原因',
hintText: '请输入作废原因',
cancelText: '取消',
confirmText: '确定'
confirmText: '确定',
);
//
if (reasonText == null) {
//
return;
}
if (reasonText == null) {
//
return;
}
//
if (reasonText.isEmpty) {
ToastUtil.showNormal(context, '请填写作废原因');
return;
}
//
if (reasonText.isEmpty) {
ToastUtil.showNormal(context, '请填写作废原因');
return;
}
}
final Map<String, dynamic> formData = {};
//
@ -377,11 +376,11 @@ if (reasonText.isEmpty) {
),
],
),
ItemListWidget.singleLineTitleText(
ItemListWidget.multiLineTitleTextField(
label: '其他安全措施:',
showMaxLength:true,
showMaxLength: true,
isEditable: true,
isRequired: true,
hintText: '请输入其他安全措施',
controller: _otherController,
),

View File

@ -430,11 +430,11 @@ if (reasonText.isEmpty) {
),
],
),
ItemListWidget.singleLineTitleText(
ItemListWidget.multiLineTitleTextField(
label: '其他安全措施:',
showMaxLength:true,
showMaxLength: true,
isEditable: true,
isRequired: true,
hintText: '请输入其他安全措施',
controller: _otherController,
),

View File

@ -389,11 +389,11 @@ if (reasonText.isEmpty) {
),
],
),
ItemListWidget.singleLineTitleText(
ItemListWidget.multiLineTitleTextField(
label: '其他安全措施:',
showMaxLength:true,
showMaxLength: true,
isEditable: true,
isRequired: true,
hintText: '请输入其他安全措施',
controller: _otherController,
),

View File

@ -388,11 +388,11 @@ if (reasonText.isEmpty) {
),
],
),
ItemListWidget.singleLineTitleText(
ItemListWidget.multiLineTitleTextField(
label: '其他安全措施:',
showMaxLength:true,
showMaxLength: true,
isEditable: true,
isRequired: true,
hintText: '请输入其他安全措施',
controller: _otherController,
),

View File

@ -376,11 +376,11 @@ if (reasonText.isEmpty) {
),
],
),
ItemListWidget.singleLineTitleText(
ItemListWidget.multiLineTitleTextField(
label: '其他安全措施:',
showMaxLength: true,
isEditable: true,
showMaxLength:true,
isRequired: true,
hintText: '请输入其他安全措施',
controller: _otherController,
),

View File

@ -378,11 +378,11 @@ if (reasonText.isEmpty) {
),
],
),
ItemListWidget.singleLineTitleText(
ItemListWidget.multiLineTitleTextField(
label: '其他安全措施:',
showMaxLength:true,
showMaxLength: true,
isEditable: true,
isRequired: true,
hintText: '请输入其他安全措施',
controller: _otherController,
),

View File

@ -391,11 +391,11 @@ if (reasonText.isEmpty) {
),
],
),
ItemListWidget.singleLineTitleText(
ItemListWidget.multiLineTitleTextField(
label: '其他安全措施:',
showMaxLength:true,
showMaxLength: true,
isEditable: true,
isRequired: true,
hintText: '请输入其他安全措施',
controller: _otherController,
),

View File

@ -376,11 +376,11 @@ if (reasonText.isEmpty) {
),
],
),
ItemListWidget.singleLineTitleText(
ItemListWidget.multiLineTitleTextField(
label: '其他安全措施:',
showMaxLength:true,
showMaxLength: true,
isEditable: true,
isRequired: true,
hintText: '请输入其他安全措施',
controller: _otherController,
),

View File

@ -5,6 +5,8 @@ import 'package:fluttertoast/fluttertoast.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/pages/mine/mine_set_pwd_page.dart';
import 'package:qhd_prevention/services/auth_service.dart';
import 'package:qhd_prevention/tools/tools.dart';
import 'package:qhd_prevention/tools/update/update_dialogs.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../tools/tools.dart';
import 'main_tab.dart';
@ -97,19 +99,25 @@ class _LoginPageState extends State<LoginPage> {
try{
final result = await AuthService.checkUpdate();
if (FormUtils.hasValue(result, 'pd')) {
//
Map pd = result['pd'];
CustomAlertDialog.showConfirm(
context,
title: '更新通知',
cancelText: '',
confirmText: '我知道了',
content: pd['UPLOAD_CONTENT'] ?? '',
onConfirm: () {
ToastUtil.showNormal(context, '更新去吧!');
},
);
return;
final versionInfo = await getAppVersion();
bool isWifi = await checkNetworkWifi();
if (versionInfo.versionName != pd['VERSION']) {
//
final ok = await CustomAlertDialog.showConfirm(
context,
title: '更新通知',
content: isWifi ? '发现新版本,是否更新?为了更好的体验,请更新到最新版本。' : '发现新版本,检查到您当前使用的是移动网络,是否更新?更新时请注意流量消耗。为了更好的体验,请更新到最新版本。',
cancelText: pd['ISUPDATE'] == '1' ? '' : '稍后更新',
confirmText: '立即更新'
);
if (ok) {
// await showUpdateConfirmDialog(context, apkUrl: apkUrl);
}
return;
}
}
}catch(_) {}

View File

@ -26,6 +26,7 @@ class _MineSetPageState extends State<MineSetPage> {
final result = await AuthService.checkUpdate();
LoadingDialogHelper.hide();
if (FormUtils.hasValue(result, 'pd')) {
//
Map pd = result['pd'];
CustomAlertDialog.showConfirm(
@ -68,10 +69,8 @@ class _MineSetPageState extends State<MineSetPage> {
child: _setItemWidget("更新人脸信息"),
onTap: () {
pushPage(
const FaceRecognitionPage(studentId: '',
VIDEOCOURSEWARE_ID: '',CURRICULUM_ID: '',
CHAPTER_ID: '',CLASS_ID: '',
mode: FaceMode.manual),
const FaceRecognitionPage(studentId: '',data: {},
mode: FaceMode.setUpdata),
context,
);
},

View File

@ -7,6 +7,7 @@ import 'package:flutter/services.dart';
import 'dart:io';
import 'package:image_picker/image_picker.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
int getRandomWithNum(int min, int max) {
if (max < min) {
@ -594,3 +595,19 @@ class CameraPermissionHelper {
}
}
Future<bool> checkNetworkWifi() async {
final connectivityResult = await Connectivity().checkConnectivity();
if (connectivityResult == ConnectivityResult.mobile) {
print("当前是移动网络(可能是 2G/3G/4G/5G");
} else if (connectivityResult == ConnectivityResult.wifi) {
return true;
print("当前是 WiFi");
} else if (connectivityResult == ConnectivityResult.ethernet) {
print("当前是有线网络");
} else if (connectivityResult == ConnectivityResult.none) {
print("当前无网络连接");
}
return false;
}