。。。

main
hs 2025-09-18 21:45:41 +08:00
parent 6d737adce3
commit 21387b3cbc
49 changed files with 379 additions and 310 deletions

View File

@ -15,7 +15,7 @@ if (keystorePropertiesFile.exists()) {
}
android {
namespace = "com.zhuoyun.qhdprevention.qhd_prevention"
namespace = "uni.UNI85F7A17"
compileSdk = flutter.compileSdkVersion
ndkVersion = "28.1.13356709"
@ -29,7 +29,7 @@ android {
}
defaultConfig {
applicationId = "com.zhuoyun.qhdprevention.qhd_prevention"
applicationId = "uni.UNI85F7A17"
minSdk = 24
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode

View File

@ -104,7 +104,7 @@
<!-- FileProvider 配置 -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.zhuoyun.qhdprevention.qhd_prevention.fileprovider"
android:authorities="uni.UNI85F7A17.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data

View File

@ -1,60 +0,0 @@
package com.zhuoyun.qhdprevention.qhd_prevention
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import androidx.core.content.FileProvider
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import java.io.File
class MainActivity: FlutterActivity() {
private val CHANNEL = "app.install"
private val REQ_INSTALL_UNKNOWN = 9999
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
when (call.method) {
"installApk" -> {
val path = call.argument<String>("path")
if (path == null) {
result.error("NO_PATH", "no path provided", null)
return@setMethodCallHandler
}
installApk(path, result)
}
else -> result.notImplemented()
}
}
}
private fun installApk(path: String, result: MethodChannel.Result) {
val file = File(path)
if (!file.exists()) {
result.error("NO_FILE", "file not exist", null)
return
}
// Android 8.0+ 需要允许安装未知来源
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (!packageManager.canRequestPackageInstalls()) {
// 引导用户去设置允许安装未知来源(你可以在 Flutter 侧提示用户)
val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, Uri.parse("package:$packageName"))
startActivity(intent)
result.error("NEED_INSTALL_PERMISSION", "need install permission", null)
return
}
}
val apkUri: Uri = FileProvider.getUriForFile(this, "$packageName.fileprovider", file)
val intent = Intent(Intent.ACTION_VIEW)
intent.setDataAndType(apkUri, "application/vnd.android.package-archive")
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
startActivity(intent)
result.success(true)
}
}

View File

@ -1,4 +1,4 @@
package com.zhuoyun.qhdprevention.qhd_prevention
package uni.UNI85F7A17
import android.app.Application
import android.content.Context

View File

@ -503,10 +503,10 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.zhuoyun.qhdprevention.qhdPrevention;
PRODUCT_BUNDLE_IDENTIFIER = uni.UNI85F7A17;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "flutter-weihua";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "qa-zsaq";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
@ -523,7 +523,7 @@
DEVELOPMENT_TEAM = 8AKCJ9LW7D;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.zhuoyun.qhdprevention.qhdPrevention.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = uni.UNI85F7A17.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@ -542,7 +542,7 @@
DEVELOPMENT_TEAM = 8AKCJ9LW7D;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.zhuoyun.qhdprevention.qhdPrevention.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = uni.UNI85F7A17.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@ -559,7 +559,7 @@
DEVELOPMENT_TEAM = 8AKCJ9LW7D;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.zhuoyun.qhdprevention.qhdPrevention.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = uni.UNI85F7A17.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@ -697,10 +697,10 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.zhuoyun.qhdprevention.qhdPrevention;
PRODUCT_BUNDLE_IDENTIFIER = uni.UNI85F7A17;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "flutter-weihua";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "qa-zsaq";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
@ -728,10 +728,10 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.zhuoyun.qhdprevention.qhdPrevention;
PRODUCT_BUNDLE_IDENTIFIER = uni.UNI85F7A17;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "flutter-weihua";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "qa-zsaq";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";

View File

@ -33,6 +33,9 @@ class _RemoteFilePageState extends State<RemoteFilePage> {
late PdfControllerPinch _pdfController;
int _totalPages = 0;
// (<=3)
Timer? _pageViewTimer;
@override
void initState() {
super.initState();
@ -93,12 +96,36 @@ class _RemoteFilePageState extends State<RemoteFilePage> {
@override
void dispose() {
_countdownTimer?.cancel();
_pageViewTimer?.cancel();
if (!_isLoading) {
_pdfController.dispose();
}
super.dispose();
}
// pdfx page 1-based
void _onPageChanged(int page) {
//
_pageViewTimer?.cancel();
// 1
if (_totalPages > 0 && page >= _totalPages) {
//
setState(() => _hasScrolledToBottom = true);
return;
}
// <=3
if (_totalPages > 0 && _totalPages <= 3) {
// page == _totalPages
if (page == _totalPages) {
_pageViewTimer = Timer(const Duration(seconds: 1), () {
if (mounted) setState(() => _hasScrolledToBottom = true);
});
}
}
}
@override
Widget build(BuildContext context) {
final isButtonEnabled = _timerFinished && _hasScrolledToBottom;
@ -117,12 +144,14 @@ class _RemoteFilePageState extends State<RemoteFilePage> {
onDocumentLoaded: (document) {
setState(() {
_totalPages = document.pagesCount;
// 1
if (_totalPages <= 1) {
_hasScrolledToBottom = true;
}
});
},
onPageChanged: (page) {
if (page == _totalPages - 1) {
setState(() => _hasScrolledToBottom = true);
}
_onPageChanged(page);
},
),
),

View File

@ -19,13 +19,13 @@ class ApiService {
// 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 baseFacePath = "http://192.168.20.240:8500/whb_stu_face/";
static const String baseFacePath = "https://qaaqwh.qhdsafety.com/whb_stu_face";
// static const String baseFacePath = "http://192.168.20.240:8500/whb_stu_face/";
// static const String baseFacePath = "http://192.168.0.25:38199"; //
///
// static const String basePath = "https://qaaqwh.qhdsafety.com/integrated_whb";
static const String basePath = "http://192.168.20.240:8500/integrated_whb";//
static const String basePath = "https://qaaqwh.qhdsafety.com/integrated_whb";
// static const String basePath = "http://192.168.20.240:8500/integrated_whb";//
// static const String basePath = "http://192.168.0.25:28199";//
// static const String basePath = "http://192.168.0.45:28199";//
@ -190,7 +190,7 @@ U6Hzm1ninpWeE+awIDAQAB
'/app/versionmanager/getVersion',
method: Method.post,
data: {
'FILETYPE':Platform.pathSeparator
'FILETYPE':Platform.isIOS ? 'iOS' : 'Android'
},
);
}

View File

@ -21,7 +21,7 @@ import 'pages/mine/mine_set_pwd_page.dart';
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
//
final RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();
bool _isLoggingOut = false;
//
class GlobalMessage {
static void showError(String message) {
@ -109,17 +109,32 @@ void main( ) async {
// HTTP
HttpManager.onUnauthorized = () async {
final navigatorState = navigatorKey.currentState;
if (navigatorState == null) return;
// ModalRoute null
final currentRouteName = ModalRoute.of(navigatorState.context)?.settings.name;
if (currentRouteName == '/login') {
//
return;
}
if (_isLoggingOut) return; //
_isLoggingOut = true;
try {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool('isLoggedIn', false);
await prefs.remove('token');
navigatorKey.currentState?.pushNamedAndRemoveUntil(
'/login',
(route) => false,
);
navigatorState.pushNamedAndRemoveUntil('/login', (route) => false);
Future.delayed(const Duration(milliseconds: 100), () {
GlobalMessage.showError('您的账号已在其他设备登录,已自动下线,请使用单一设备进行学习。');
});
} finally {
_isLoggingOut = false;
}
};
//
final prefs = await SharedPreferences.getInstance();

View File

@ -353,9 +353,9 @@ setState(() {
Widget _mainWidget() {
bool isShowCheck = false;
if (FormUtils.hasValue(inspectedForm, 'hiddenList')) {
List list = inspectedForm['hiddenList'];
if (list.isEmpty) {
if (FormUtils.hasValue(form, 'hiddenList')) {
List list = form['hiddenList'];
if (list.isNotEmpty) {
isShowCheck = true;
}
}

View File

@ -190,33 +190,33 @@ class HomePageState extends State<HomePage> {
/// loading
Future<void> _initialLoad() async {
///
final data = await ApiService.getListData();
if (data['result'] == 'success') {
final content = data['varList'] ?? [];
for (Map item in content) {
if (item['checkCount'] == 0) {
totalList.add(item);
}
}
}
final result = await AuthService.checkUpdate();
try{
if (FormUtils.hasValue(result, 'pd')) {
//
Map pd = result['pd'];
CustomAlertDialog.showAlert(
final versionInfo = await getAppVersion();
bool isWifi = true;
if (versionInfo.versionName != pd['VERSION']) {
//
final ok = await CustomAlertDialog.showConfirm(
context,
barrierDismissible:false,
title: '更新通知',
content: pd['UPLOAD_CONTENT'] ?? '',
onConfirm: () async{
final apkUrl = 'http://192.168.1.191:8888/app-release.apk';
await showUpdateConfirmDialog(context, apkUrl: apkUrl);
},
content: isWifi ? '发现新版本,是否更新?为了更好的体验,请更新到最新版本。' : '发现新版本,检查到您当前使用的是移动网络,是否更新?更新时请注意流量消耗。为了更好的体验,请更新到最新版本。',
cancelText: pd['ISUPDATE'] == '1' ? '' : '稍后更新',
confirmText: '立即更新'
);
if (ok) {
final apkUrl = pd['FILEURL'] ?? '';
await showUpdateConfirm(context, apkUrl: apkUrl);
}
return;
}
}
}catch(_){}
final corppromiseData = await ApiService.checkSafeCorppromise();
if (corppromiseData['ISSIGN'] == 1) {
//
@ -241,7 +241,16 @@ class HomePageState extends State<HomePage> {
_fetchData();
_fetchHiddenList(showLoading: hiddenList.isEmpty);
fetchAndSaveBd09(context);
///
final data = await ApiService.getListData();
if (data['result'] == 'success') {
final content = data['varList'] ?? [];
for (Map item in content) {
if (item['checkCount'] == 0) {
totalList.add(item);
}
}
}
}
Future<void> _onRefresh() async {
@ -333,7 +342,16 @@ class HomePageState extends State<HomePage> {
//
final data = await ApiService.getWork();
final hidCount = data['hidCount'] as Map<String, dynamic>? ?? {};
setState(() {
// workInfos
workInfos =
workInfos.map((info) {
final idx = info['index'] as int;
final key = _workKey(idx);
final num = (hidCount[key] ?? 0).toString();
return {...info, 'num': num};
}).toList();
});
// // BadgeManager
// BadgeManager().updateEnvInspectCount();
// BadgeManager().updateEightWorkCount();
@ -350,15 +368,6 @@ class HomePageState extends State<HomePage> {
//
setState(() {
// workInfos
workInfos =
workInfos.map((info) {
final idx = info['index'] as int;
final key = _workKey(idx);
final num = (hidCount[key] ?? 0).toString();
return {...info, 'num': num};
}).toList();
// BadgeManager
_safetyEnvironmentalInspection = BadgeManager().envInspectCount;
_eight_work_count = BadgeManager().eightWorkCount;

View File

@ -80,6 +80,7 @@ class _FaceRecognitionPageState extends State<FaceRecognitionPage>
//
try {
_cameraController?.dispose();
Navigator.pop(context);
} catch (_) {}
_cameraController = null;
} else if (state == AppLifecycleState.resumed) {

View File

@ -225,7 +225,7 @@ class _StudyDetailPageState extends State<StudyDetailPage>
await _submitPlayTime(
snapshot: prevSnapshot,
end: false,
seconds: _lastReported.inSeconds,
seconds: _lastReported.inSeconds.toString(),
);
}
@ -256,7 +256,7 @@ class _StudyDetailPageState extends State<StudyDetailPage>
'VIDEOCOURSEWARE_ID': data['VIDEOCOURSEWARE_ID'] ?? '',
'CURRICULUM_ID': data['CURRICULUM_ID'] ?? '',
'CHAPTER_ID': data['CHAPTER_ID'] ?? '',
'VIDEOTIME': data['VIDEOTIME'] ?? 0,
'VIDEOTIME': data['VIDEOTIME'] ?? '0.0',
'IS_NODE': hasNodes,
'FIRST_INDEX': fi,
'NODE_INDEX': ni,
@ -265,7 +265,7 @@ class _StudyDetailPageState extends State<StudyDetailPage>
await _submitPlayTime(
snapshot: docSnapshot,
end: true,
seconds: int.parse('${data['VIDEOTIME'] ?? '0'}'),
seconds: data['VIDEOTIME'] ?? '0.0',
);
}
} else {
@ -324,6 +324,17 @@ class _StudyDetailPageState extends State<StudyDetailPage>
await onPass();
} else {
ToastUtil.showError(context, '人脸验证未通过,无法继续');
if (_videoController != null) {
try {
_videoController?.removeListener(_onTimeUpdate);
} catch (_) {}
try {
_videoController?.dispose();
} catch (_) {}
_videoController = null;
}
_faceTimer?.cancel();
setState(() {});
}
} else {
final ok = await CustomAlertDialog.showConfirm(
@ -458,7 +469,7 @@ class _StudyDetailPageState extends State<StudyDetailPage>
return _submitPlayTime(
snapshot: snapshot,
end: false,
seconds: pos.inSeconds,
seconds: pos.inSeconds.toString(),
);
})
.whenComplete(() {
@ -490,7 +501,7 @@ class _StudyDetailPageState extends State<StudyDetailPage>
await _submitPlayTime(
snapshot: snapshot,
end: true,
seconds: finalSeconds,
seconds: finalSeconds.toString(),
);
})
.whenComplete(() {
@ -516,7 +527,7 @@ class _StudyDetailPageState extends State<StudyDetailPage>
Future<void> _submitPlayTime({
required Map<String, dynamic> snapshot,
required bool end,
required int seconds,
required String seconds,
}) async {
// snapshot VIDEOCOURSEWARE_ID
if (snapshot['VIDEOCOURSEWARE_ID'] == null ||
@ -602,7 +613,7 @@ class _StudyDetailPageState extends State<StudyDetailPage>
final resT =
(resTraw is num)
? resTraw.toDouble()
: double.tryParse('$resTraw') ?? seconds.toDouble();
: double.tryParse('$resTraw') ?? double.parse(seconds);
final videoTimeRaw = snapshot['VIDEOTIME'];
final videoTime =

View File

@ -1322,6 +1322,7 @@ class SignItemWidget extends StatelessWidget {
this.smallThumbSize = 50.0,
this.signImageWidth = 200.0,
this.signImageHeight = 100.0,
required this.isShowTime,
}) : super(key: key);
/// signs map key
@ -1348,6 +1349,7 @@ class SignItemWidget extends StatelessWidget {
///
final double signImageWidth;
final double signImageHeight;
final bool isShowTime;
@override
Widget build(BuildContext context) {
@ -1579,6 +1581,7 @@ class SignItemWidget extends StatelessWidget {
),
),
);
if (isShowTime) {
//
list.add(const SizedBox(height: 10));
list.add(
@ -1595,6 +1598,8 @@ class SignItemWidget extends StatelessWidget {
],
),
);
}
return list;
}
@ -1615,6 +1620,7 @@ class ConfirmWithSignWidget extends StatelessWidget {
required this.nameKey, // 'CONFIRM_USER_NAME',
required this.headerTitle, // '作业负责人意见',
required this.roleTitle, // '作业负责人',
this.isShowTime = true,
}) : super(key: key);
// null {}
@ -1643,6 +1649,8 @@ class ConfirmWithSignWidget extends StatelessWidget {
/// SignItemWidget title '作业负责人'
final String roleTitle;
final bool isShowTime;
@override
Widget build(BuildContext context) {
// null Map访
@ -1767,6 +1775,7 @@ class ConfirmWithSignWidget extends StatelessWidget {
pd: safePd,
signs: safeSigns,
baseImgPath: baseImgPath,
isShowTime:isShowTime,
),
],
),

View File

@ -26,11 +26,7 @@ class SignImageData {
String? filePath;
int? key;
SignImageData({
required this.SIGNER_TIME,
this.filePath,
this.key,
});
SignImageData({required this.SIGNER_TIME, this.filePath, this.key});
Map<String, dynamic> toJson() => {
'SIGNER_TIME': SIGNER_TIME,
@ -47,8 +43,10 @@ class SignImageData {
}
@override
String toString() => 'SignImageData(key:$key, filePath:$filePath, SIGNER_TIME:$SIGNER_TIME)';
String toString() =>
'SignImageData(key:$key, filePath:$filePath, SIGNER_TIME:$SIGNER_TIME)';
}
class DangerousOptionsPage extends StatefulWidget {
final int index;
final int status;
@ -134,32 +132,23 @@ class _DangerousOptionsPageState extends State<DangerousOptionsPage> {
return;
}
LoadingDialogHelper.show();
List<String> filePaths =
signImgList.map((img) => img.filePath ?? '').toList();
final result = await ApiService.saveDangerousOptionsFile(filePaths);
final List<dynamic> signList = result['FILE_PATH_LIST'];
List<Map<String, dynamic>> sineImageList = [];
List<SignImageData> filePaths = [];
List severImageList = [];
for (SignImageData data in signImgList) {
for (Map<String, dynamic> img in signList) {
String imgName = 'file${data.key}';
if (data.filePath!.contains('uploadFiles')) {
final idata = {
String path = data.filePath ?? '';
if (!path.contains('uploadFiles')) {
filePaths.add(data);
} else {
severImageList.add({
'filePath': data.filePath,
'SIGNER_TIME': data.SIGNER_TIME,
'key': data.key,
};
sineImageList.add(idata);
}
if (imgName == img['key']) {
final idata = {
'filePath': img['filePath'] ?? '',
'SIGNER_TIME': data.SIGNER_TIME,
'key': data.key,
};
sineImageList.add(idata);
}
});
}
}
if (filePaths.length == 0) {
//
setState(() => buttonLoading = true);
LoadingDialogHelper.hide();
Navigator.pop(context, {
@ -167,7 +156,37 @@ class _DangerousOptionsPageState extends State<DangerousOptionsPage> {
imgList
.map((e) => {'local': e.localPath, 'remote': e.serverPath})
.toList(),
'signImgList': sineImageList,
'signImgList': signImgList,
'index': index,
'status': status,
});
return;
}
final result = await ApiService.saveDangerousOptionsFile(filePaths.map((item) => item.filePath).toList());
final List<dynamic> signList = result['FILE_PATH_LIST'];
for (SignImageData data in filePaths) {
for (Map<String, dynamic> img in signList) {
String imgName = 'file${data.key}';
if (imgName == img['key']) {
final idata = {
'filePath': img['filePath'] ?? '',
'SIGNER_TIME': data.SIGNER_TIME,
'key': data.key,
};
severImageList.add(idata);
}
}
}
setState(() => buttonLoading = true);
LoadingDialogHelper.hide();
Navigator.pop(context, {
'imgList':
imgList
.map((e) => {'local': e.localPath, 'remote': e.serverPath})
.toList(),
'signImgList': severImageList,
'index': index,
'status': status,
});
@ -350,7 +369,9 @@ class _DangerousOptionsPageState extends State<DangerousOptionsPage> {
onMediaAdded: _onImageAdded,
onMediaRemoved: (path) {
print(path);
final item = imgList.firstWhere((e) => path.contains(e.localPath) );
final item = imgList.firstWhere(
(e) => path.contains(e.localPath),
);
_onImageRemoved(item);
},
onAiIdentify: () {},

View File

@ -223,6 +223,7 @@ class _HotWorkDetailFormWidgetState extends State<HotWorkDetailFormWidget> {
const Divider(),
ItemListWidget.twoRowButtonTitleText(
label: '风险辨识结果',
isInput: false,
isEditable: widget.isEditable,
onTap: () async {
await showDialog<String>(

View File

@ -110,7 +110,8 @@ class SpecialWorkFormBaseWork extends StatelessWidget {
baseImgPath: baseImgPath,
sectionKey: 'CONFESS',
nameKey: 'CONFESS_USER_NAME',
headerTitle: '安全交底人意见',
headerTitle: '安全交底人',
isShowTime: false,
roleTitle: '安全交底人',
),
if (FormUtils.hasValue(signs, 'ACCEPT_CONFESS'))
@ -121,12 +122,14 @@ class SpecialWorkFormBaseWork extends StatelessWidget {
sectionKey: 'ACCEPT_CONFESS',
nameKey: 'ACCEPT_CONFESS_USER_NAME',
headerTitle: '接受交底人',
isShowTime: false,
roleTitle: '',
),
if (FormUtils.hasValue(signs, 'GUARDIAN'))
ConfirmWithSignWidget(
signs: signs,
pd: pd,
isShowTime: false,
baseImgPath: baseImgPath,
sectionKey: 'GUARDIAN',
nameKey: 'GUARDIAN_USER_NAME',

View File

@ -387,7 +387,7 @@ if (reasonText.isEmpty) {
),
onTap: () async {
DateTime? picked = await BottomDateTimePicker.showDate(
allowPast:false,
minTimeStr: pd['WORK_END_DATE'],
mode: BottomPickerMode.dateTimeWithSeconds,
context,
);

View File

@ -212,6 +212,7 @@ class _CutroadDetailFormWidgetState extends State<CutroadDetailFormWidget> {
ItemListWidget.twoRowButtonTitleText(
label: '风险辨识结果',
isInput: false,
isEditable: widget.isEditable,
onTap: () async {
await showDialog<String>(

View File

@ -106,6 +106,7 @@ class CutroadFormBaseWork extends StatelessWidget {
sectionKey: 'CONFESS',
nameKey: 'CONFESS_USER_NAME',
headerTitle: '安全交底人',
isShowTime: false,
roleTitle: '安全交底人',
),
if (FormUtils.hasValue(signs, 'ACCEPT_CONFESS'))
@ -116,6 +117,7 @@ class CutroadFormBaseWork extends StatelessWidget {
sectionKey: 'ACCEPT_CONFESS',
nameKey: 'ACCEPT_CONFESS_USER_NAME',
headerTitle: '接受交底人',
isShowTime: false,
roleTitle: '',
),
if (FormUtils.hasValue(signs, 'CONFIRM'))

View File

@ -378,7 +378,7 @@ if (reasonText.isEmpty) {
),
onTap: () async {
DateTime? picked = await BottomDateTimePicker.showDate(
allowPast:false,
minTimeStr: pd['WORK_END_DATE'],
mode: BottomPickerMode.dateTimeWithSeconds,
context,
);

View File

@ -210,6 +210,7 @@ class _BreakgroundDetailFormWidgetState
ItemListWidget.twoRowButtonTitleText(
label: '风险辨识结果',
isInput: false,
isEditable: widget.isEditable,
onTap: () async {
await showDialog<String>(

View File

@ -116,6 +116,7 @@ class SpecialWorkFormBaseWork extends StatelessWidget {
sectionKey: 'CONFESS',
nameKey: 'CONFESS_USER_NAME',
headerTitle: '安全交底人',
isShowTime: false,
roleTitle: '安全交底人',
),
if (FormUtils.hasValue(signs, 'ACCEPT_CONFESS'))
@ -126,6 +127,7 @@ class SpecialWorkFormBaseWork extends StatelessWidget {
sectionKey: 'ACCEPT_CONFESS',
nameKey: 'ACCEPT_CONFESS_USER_NAME',
headerTitle: '接受交底人',
isShowTime: false,
roleTitle: '',
),
if (FormUtils.hasValue(signs, 'CONFIRM'))

View File

@ -381,7 +381,7 @@ if (reasonText.isEmpty) {
),
onTap: () async {
DateTime? picked = await BottomDateTimePicker.showDate(
allowPast:false,
minTimeStr: pd['WORK_END_DATE'],
mode: BottomPickerMode.dateTimeWithSeconds,
context,
);

View File

@ -261,6 +261,7 @@ class _HoistworkDetailFormWidgetState extends State<HoistWorkDetailFormWidget> {
const Divider(),
ItemListWidget.twoRowButtonTitleText(
label: '风险辨识结果',
isInput: false,
isEditable: widget.isEditable,
onTap: () async {
await showDialog<String>(

View File

@ -278,6 +278,7 @@ class SpecialWorkFormBaseWork extends StatelessWidget {
sectionKey: 'CONFESS',
nameKey: 'CONFESS_USER_NAME',
headerTitle: '安全交底人',
isShowTime: false,
roleTitle: '安全交底人',
),
if (FormUtils.hasValue(signs, 'ACCEPT_CONFESS'))
@ -288,6 +289,7 @@ class SpecialWorkFormBaseWork extends StatelessWidget {
sectionKey: 'ACCEPT_CONFESS',
nameKey: 'ACCEPT_CONFESS_USER_NAME',
headerTitle: '接受交底人',
isShowTime: false,
roleTitle: '',
),

View File

@ -381,7 +381,7 @@ if (reasonText.isEmpty) {
),
onTap: () async {
DateTime? picked = await BottomDateTimePicker.showDate(
allowPast:false,
minTimeStr: pd['WORK_END_DATE'],
mode: BottomPickerMode.dateTimeWithSeconds,
context,
);

View File

@ -241,6 +241,7 @@ class _HighWorkDetailFormWidgetState extends State<HighWorkDetailFormWidget> {
const Divider(),
ItemListWidget.twoRowButtonTitleText(
label: '风险辨识结果',
isInput: false,
isEditable: widget.isEditable,
onTap: () async {
await showDialog<String>(

View File

@ -115,6 +115,7 @@ class HighWorkFormBaseWork extends StatelessWidget {
sectionKey: 'CONFESS',
nameKey: 'CONFESS_USER_NAME',
headerTitle: '安全交底人',
isShowTime: false,
roleTitle: '安全交底人',
),
if (FormUtils.hasValue(signs, 'ACCEPT_CONFESS'))
@ -125,6 +126,7 @@ class HighWorkFormBaseWork extends StatelessWidget {
sectionKey: 'ACCEPT_CONFESS',
nameKey: 'ACCEPT_CONFESS_USER_NAME',
headerTitle: '接受交底人',
isShowTime: false,
roleTitle: '',
),
if (FormUtils.hasValue(signs, 'CONFIRM'))

View File

@ -436,7 +436,25 @@ class _HighworkApplyDetailState extends State<HighworkApplyDetail> {
//FocusHelper.clearFocus(context);
});
}
bool checkWorkTime(Map<String, dynamic> pd, BuildContext context) {
//
final start = DateTime.parse(pd['WORK_EXPECTED_START_TIME'] as String);
final end = DateTime.parse(pd['WORK_EXPECTED_END_TIME'] as String);
//
if (end.isAtSameMomentAs(start) || end.isBefore(start)) {
ToastUtil.showNormal(context, '作业开始时间不能晚于或等于结束时间,请重新选择');
return false;
}
final diffMs = end.difference(start).inMilliseconds;
const max8h = 7 * 24 * 60 * 60 * 1000;
if (diffMs >= max8h) {
ToastUtil.showNormal(context, '作业开始时间与结束时间应不超过7天请重新选择');
return false;
}
return true;
}
/// 1 0
Future<void> _submit(String status) async {
//

View File

@ -59,6 +59,12 @@ class _HighworkJszyDetailState extends State<HighworkJszyDetail> {
//
if (end.isAtSameMomentAs(start) || end.isBefore(start)) {
ToastUtil.showNormal(context, '作业开始时间不能晚于或等于结束时间,请重新选择');
return false;
}
final diffMs = end.difference(start).inMilliseconds;
const max8h = 7 *24 * 60 * 60 * 1000;
if (diffMs >= max8h) {
ToastUtil.showNormal(context, '作业开始时间与结束时间应不超过7天请重新选择');
return false;
}
@ -68,7 +74,6 @@ class _HighworkJszyDetailState extends State<HighworkJszyDetail> {
/// -1 1
Future<void> _submit(String status) async {
String? reasonText = '';
if (status == '1') {
if (endTime.isEmpty) {
@ -84,7 +89,7 @@ class _HighworkJszyDetailState extends State<HighworkJszyDetail> {
title: '作废原因',
hintText: '请输入作废原因',
cancelText: '取消',
confirmText: '确定'
confirmText: '确定',
);
//
if (reasonText == null) {

View File

@ -381,7 +381,7 @@ if (reasonText.isEmpty) {
),
onTap: () async {
DateTime? picked = await BottomDateTimePicker.showDate(
allowPast:false,
minTimeStr: pd['WORK_END_DATE'],
mode: BottomPickerMode.dateTimeWithSeconds,
context,
);

View File

@ -184,7 +184,6 @@ class _HomeGasTestPageState extends State<HomeGasTestPage> {
return;
}
if (status == 1) {
Map itemForm = {
'ANALYZE_GAS': _gasController.text,
'ANALYZE_RESULT': _resultController.text,
@ -256,7 +255,7 @@ if (reasonText.isEmpty) {
'CORPINFO_ID': SessionService.instance.corpinfoId,
'USER_ID': SessionService.instance.loginUserId,
};
LoadingDialogHelper.show();
try {
await ApiService.saveGasTest('hotwork', formData, imagePaths);
ToastUtil.showNormal(context, status == 1 ? '保存成功' : '作废成功');
@ -266,6 +265,7 @@ if (reasonText.isEmpty) {
} finally {
setState(() => _loading = false);
}
LoadingDialogHelper.hide();
}
@override

View File

@ -244,6 +244,7 @@ class _ElectricityDetailFormWidgetState extends State<ElectricityDetailFormWidge
const Divider(),
ItemListWidget.twoRowButtonTitleText(
label: '风险辨识结果',
isInput: false,
isEditable: widget.isEditable,
onTap: () async {
await showDialog<String>(

View File

@ -292,7 +292,8 @@ class SpecialWorkFormBaseWork extends StatelessWidget {
baseImgPath: baseImgPath,
sectionKey: 'CONFESS',
nameKey: 'CONFESS_USER_NAME',
headerTitle: '安全交底人意见',
headerTitle: '安全交底人',
isShowTime: false,
roleTitle: '安全交底人',
),
if (FormUtils.hasValue(signs, 'ACCEPT_CONFESS'))
@ -303,6 +304,7 @@ class SpecialWorkFormBaseWork extends StatelessWidget {
sectionKey: 'ACCEPT_CONFESS',
nameKey: 'ACCEPT_CONFESS_USER_NAME',
headerTitle: '接受交底人',
isShowTime: false,
roleTitle: '',
),

View File

@ -217,6 +217,7 @@ if (reasonText.isEmpty) {
'CORPINFO_ID': SessionService.instance.corpinfoId,
'USER_ID': SessionService.instance.loginUserId,
};
LoadingDialogHelper.show();
try {
await ApiService.saveGasTest('electricity', formData, imagePaths);
@ -227,6 +228,7 @@ if (reasonText.isEmpty) {
} finally {
setState(() => _loading = false);
}
LoadingDialogHelper.hide();
}
///

View File

@ -387,7 +387,7 @@ if (reasonText.isEmpty) {
),
onTap: () async {
DateTime? picked = await BottomDateTimePicker.showDate(
allowPast:false,
minTimeStr: pd['WORK_END_DATE'],
mode: BottomPickerMode.dateTimeWithSeconds,
context,
);

View File

@ -642,6 +642,7 @@ class _BlindboardDetailFormWidgetState
const Divider(),
ItemListWidget.twoRowButtonTitleText(
label: '风险辨识结果',
isInput: false,
isEditable: widget.isEditable,
onTap: () async {
await showDialog<String>(

View File

@ -299,6 +299,7 @@ class BlindboardFormBaseWork extends StatelessWidget {
sectionKey: 'CONFESS',
nameKey: 'CONFESS_USER_NAME',
headerTitle: '安全交底人',
isShowTime: false,
roleTitle: '安全交底人',
),
if (FormUtils.hasValue(signs, 'ACCEPT_CONFESS'))
@ -309,6 +310,7 @@ class BlindboardFormBaseWork extends StatelessWidget {
sectionKey: 'ACCEPT_CONFESS',
nameKey: 'ACCEPT_CONFESS_USER_NAME',
headerTitle: '接受交底人',
isShowTime: false,
roleTitle: '',
),
if (FormUtils.hasValue(signs, 'CONFIRM'))

View File

@ -374,7 +374,7 @@ if (reasonText.isEmpty) {
),
onTap: () async {
DateTime? picked = await BottomDateTimePicker.showDate(
allowPast:false,
minTimeStr: pd['WORK_END_DATE'],
mode: BottomPickerMode.dateTimeWithSeconds,
context,
);

View File

@ -254,6 +254,7 @@ class _SpaceWorkDetailFormWidgetState extends State<SpaceWorkDetailFormWidget> {
const Divider(),
ItemListWidget.twoRowButtonTitleText(
label: '风险辨识结果',
isInput: false,
isEditable: widget.isEditable,
onTap: () async {
await showDialog<String>(

View File

@ -120,6 +120,7 @@ class SpecialWorkFormBaseWork extends StatelessWidget {
sectionKey: 'CONFESS',
nameKey: 'CONFESS_USER_NAME',
headerTitle: '安全交底人',
isShowTime: false,
roleTitle: '安全交底人',
),
if (FormUtils.hasValue(signs, 'ACCEPT_CONFESS'))
@ -130,6 +131,7 @@ class SpecialWorkFormBaseWork extends StatelessWidget {
sectionKey: 'ACCEPT_CONFESS',
nameKey: 'ACCEPT_CONFESS_USER_NAME',
headerTitle: '接受交底人',
isShowTime: false,
roleTitle: '',
),
if (FormUtils.hasValue(signs, 'CONFIRM'))

View File

@ -252,6 +252,7 @@ if (reasonText.isEmpty) {
barrierDismissible: false,
);
if (!confirmed) return;
LoadingDialogHelper.show();
try {
await ApiService.saveGasTest('confinedspace', formData, imagePaths);
@ -262,6 +263,7 @@ if (reasonText.isEmpty) {
} finally {
setState(() => _loading = false);
}
LoadingDialogHelper.hide();
}
///

View File

@ -391,7 +391,7 @@ if (reasonText.isEmpty) {
),
onTap: () async {
DateTime? picked = await BottomDateTimePicker.showDate(
allowPast:false,
minTimeStr: pd['WORK_END_DATE'],
mode: BottomPickerMode.dateTimeWithSeconds,
context,
);

View File

@ -101,19 +101,20 @@ class _LoginPageState extends State<LoginPage> {
if (FormUtils.hasValue(result, 'pd')) {
Map pd = result['pd'];
final versionInfo = await getAppVersion();
bool isWifi = await checkNetworkWifi();
bool isWifi = true;
if (versionInfo.versionName != pd['VERSION']) {
//
final ok = await CustomAlertDialog.showConfirm(
context,
barrierDismissible:false,
title: '更新通知',
content: isWifi ? '发现新版本,是否更新?为了更好的体验,请更新到最新版本。' : '发现新版本,检查到您当前使用的是移动网络,是否更新?更新时请注意流量消耗。为了更好的体验,请更新到最新版本。',
cancelText: pd['ISUPDATE'] == '1' ? '' : '稍后更新',
confirmText: '立即更新'
);
if (ok) {
// await showUpdateConfirmDialog(context, apkUrl: apkUrl);
final apkUrl = pd['FILEURL'] ?? '';
await showUpdateConfirm(context, apkUrl: apkUrl);
}
return;
}

View File

@ -8,6 +8,7 @@ import 'package:qhd_prevention/pages/mine/mine_set_pwd_page.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/services/auth_service.dart';
import 'package:qhd_prevention/tools/h_colors.dart';
import 'package:qhd_prevention/tools/update/update_dialogs.dart';
import '../../tools/tools.dart';
@ -26,19 +27,26 @@ class _MineSetPageState extends State<MineSetPage> {
final result = await AuthService.checkUpdate();
LoadingDialogHelper.hide();
if (FormUtils.hasValue(result, 'pd')) {
//
Map pd = result['pd'];
CustomAlertDialog.showConfirm(
final versionInfo = await getAppVersion();
bool isWifi = true;
if (versionInfo.versionName != pd['VERSION']) {
//
final ok = await CustomAlertDialog.showConfirm(
context,
barrierDismissible:false,
title: '更新通知',
cancelText: '',
confirmText: '我知道了',
content: pd['UPLOAD_CONTENT'] ?? '',
onConfirm: () {
ToastUtil.showNormal(context, '更新去吧!');
}
content: isWifi ? '发现新版本,是否更新?为了更好的体验,请更新到最新版本。' : '发现新版本,检查到您当前使用的是移动网络,是否更新?更新时请注意流量消耗。为了更好的体验,请更新到最新版本。',
cancelText: pd['ISUPDATE'] == '1' ? '' : '稍后更新',
confirmText: '立即更新'
);
if (ok) {
final apkUrl = pd['FILEURL'] ?? '';
await showUpdateConfirm(context, apkUrl: apkUrl);
}
return;
}
}else{
_loadAppVersion();

View File

@ -600,6 +600,7 @@ Future<bool> checkNetworkWifi() async {
final connectivityResult = await Connectivity().checkConnectivity();
if (connectivityResult == ConnectivityResult.mobile) {
print("当前是移动网络(可能是 2G/3G/4G/5G");
return false;
} else if (connectivityResult == ConnectivityResult.wifi) {
return true;
print("当前是 WiFi");

View File

@ -3,43 +3,16 @@ import 'package:flutter/material.dart';
import 'package:qhd_prevention/services/update_service.dart';
///
Future<void> showUpdateConfirmDialog(BuildContext context, {
Future<void> showUpdateConfirm(BuildContext context, {
required String apkUrl,
String title = '发现新版本',
String content = '检测到新版本,是否立即更新?',
String updateButtonText = '更新',
String cancelButtonText = '稍后',
}) async {
final confirmed = await showDialog<bool>(
context: context,
barrierDismissible: false,
builder: (ctx) {
return AlertDialog(
title: Text(title),
content: Text(content),
actions: [
TextButton(
onPressed: () => Navigator.of(ctx).pop(false),
child: Text(cancelButtonText),
),
ElevatedButton(
onPressed: () => Navigator.of(ctx).pop(true),
child: Text(updateButtonText),
),
],
);
},
);
if (confirmed == true) {
//
}) async {
await showDialog(
context: context,
barrierDismissible: false,
builder: (ctx) => DownloadProgressDialog(apkUrl: apkUrl),
);
}
}
/// initState
class DownloadProgressDialog extends StatefulWidget {

View File

@ -16,8 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
#version: 2.1.2+10
version: 2.2.0
version: 2.1.2+59
environment:
sdk: ^3.7.0