Compare commits

...

2 Commits

Author SHA1 Message Date
hs c75dfba154 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	lib/customWidget/photo_picker_row.dart
2025-09-01 17:26:29 +08:00
hs ff41cbce60 改bug 2025-09-01 17:25:55 +08:00
151 changed files with 1949 additions and 1192 deletions

View File

@ -6,9 +6,13 @@
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<!-- 相册权限 -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <!-- Android 13+ -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- Android 12及以下 -->
<!-- Android 13+ -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<!-- Android 12 及以下 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- 相机 -->
<uses-permission android:name="android.permission.CAMERA" />

View File

@ -8,6 +8,40 @@ PODS:
- Flutter
- connectivity_plus (0.0.1):
- Flutter
- DKImagePickerController/Core (4.3.9):
- DKImagePickerController/ImageDataManager
- DKImagePickerController/Resource
- DKImagePickerController/ImageDataManager (4.3.9)
- DKImagePickerController/PhotoGallery (4.3.9):
- DKImagePickerController/Core
- DKPhotoGallery
- DKImagePickerController/Resource (4.3.9)
- DKPhotoGallery (0.0.19):
- DKPhotoGallery/Core (= 0.0.19)
- DKPhotoGallery/Model (= 0.0.19)
- DKPhotoGallery/Preview (= 0.0.19)
- DKPhotoGallery/Resource (= 0.0.19)
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Core (0.0.19):
- DKPhotoGallery/Model
- DKPhotoGallery/Preview
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Model (0.0.19):
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Preview (0.0.19):
- DKPhotoGallery/Model
- DKPhotoGallery/Resource
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Resource (0.0.19):
- SDWebImage
- SwiftyGif
- file_picker (0.0.1):
- DKImagePickerController/PhotoGallery
- Flutter
- Flutter (1.0.0)
- flutter_baidu_mapapi_base (3.9.0):
- BaiduMapKit/Utils (= 6.6.4)
@ -39,12 +73,18 @@ PODS:
- FlutterMacOS
- pdfx (1.0.0):
- Flutter
- permission_handler_apple (9.3.0):
- Flutter
- photo_manager (3.7.1):
- Flutter
- FlutterMacOS
- SDWebImage (5.21.1):
- SDWebImage/Core (= 5.21.1)
- SDWebImage/Core (5.21.1)
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- SwiftyGif (5.4.5)
- url_launcher_ios (0.0.1):
- Flutter
- video_compress (0.3.0):
@ -61,6 +101,7 @@ PODS:
DEPENDENCIES:
- camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`)
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
- file_picker (from `.symlinks/plugins/file_picker/ios`)
- Flutter (from `Flutter`)
- flutter_baidu_mapapi_base (from `.symlinks/plugins/flutter_baidu_mapapi_base/ios`)
- flutter_baidu_mapapi_map (from `.symlinks/plugins/flutter_baidu_mapapi_map/ios`)
@ -74,6 +115,7 @@ DEPENDENCIES:
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- pdfx (from `.symlinks/plugins/pdfx/ios`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- photo_manager (from `.symlinks/plugins/photo_manager/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
@ -85,12 +127,18 @@ DEPENDENCIES:
SPEC REPOS:
trunk:
- BaiduMapKit
- DKImagePickerController
- DKPhotoGallery
- SDWebImage
- SwiftyGif
EXTERNAL SOURCES:
camera_avfoundation:
:path: ".symlinks/plugins/camera_avfoundation/ios"
connectivity_plus:
:path: ".symlinks/plugins/connectivity_plus/ios"
file_picker:
:path: ".symlinks/plugins/file_picker/ios"
Flutter:
:path: Flutter
flutter_baidu_mapapi_base:
@ -117,6 +165,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
pdfx:
:path: ".symlinks/plugins/pdfx/ios"
permission_handler_apple:
:path: ".symlinks/plugins/permission_handler_apple/ios"
photo_manager:
:path: ".symlinks/plugins/photo_manager/ios"
shared_preferences_foundation:
@ -136,6 +186,9 @@ SPEC CHECKSUMS:
BaiduMapKit: 84991811cb07b24c6ead7d59022c13245427782c
camera_avfoundation: be3be85408cd4126f250386828e9b1dfa40ab436
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_baidu_mapapi_base: 24dd82034374c6f52a73e90316834c63ff8d4f64
flutter_baidu_mapapi_map: f799cc1bb3d39196b8d3d59399ca8635e690bd44
@ -149,8 +202,11 @@ SPEC CHECKSUMS:
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
pdfx: 77f4dddc48361fbb01486fa2bdee4532cbb97ef3
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
photo_manager: 1d80ae07a89a67dfbcae95953a1e5a24af7c3e62
SDWebImage: f29024626962457f3470184232766516dee8dfea
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
video_compress: f2133a07762889d67f0711ac831faa26f956980e
video_player_avfoundation: 2cef49524dd1f16c5300b9cd6efd9611ce03639b

View File

@ -32,7 +32,7 @@ class ListItemFactory {
Text(
leftText,
style: TextStyle(
fontSize: 15,
fontSize: 13,
fontWeight: FontWeight.bold,
color: textColor,
),
@ -47,7 +47,7 @@ class ListItemFactory {
fit: FlexFit.loose,
child: Text(
rightText,
style: TextStyle(fontSize: 15, color: Colors.grey),
style: TextStyle(fontSize: 13, color: Colors.grey),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
@ -65,7 +65,7 @@ class ListItemFactory {
fit: FlexFit.loose,
child: Text(
rightText,
style: TextStyle(fontSize: 15, color: Colors.grey),
style: TextStyle(fontSize: 13, color: Colors.grey),
maxLines: 1,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.right,
@ -101,7 +101,7 @@ class ListItemFactory {
Text(
topText,
style: TextStyle(
fontSize: 15,
fontSize: 13,
fontWeight: FontWeight.bold,
color: Colors.black,
),
@ -109,7 +109,7 @@ class ListItemFactory {
const SizedBox(height: 5),
Text(
bottomText,
style: TextStyle(fontSize: 15, color: Colors.grey),
style: TextStyle(fontSize: 13, color: Colors.grey),
softWrap: true,
maxLines: null, //
),
@ -139,7 +139,7 @@ class ListItemFactory {
Text(
text,
style: const TextStyle(
fontSize: 15,
fontSize: 13,
fontWeight: FontWeight.bold,
color: Colors.black,
),
@ -202,7 +202,7 @@ class ListItemFactory {
Text(
text,
style: const TextStyle(
fontSize: 15,
fontSize: 13,
fontWeight: FontWeight.bold,
color: Colors.black,
),
@ -250,7 +250,7 @@ class ListItemFactory {
children: [
Text(
text,
style: TextStyle(fontSize: 15, color: Colors.grey),
style: TextStyle(fontSize: 13, color: Colors.grey),
softWrap: true,
maxLines: null, //
),
@ -296,7 +296,7 @@ class ListItemFactory {
child: Text(
title,
style: TextStyle(
fontSize: 15,
fontSize: 13,
fontWeight: FontWeight.bold,
color: Colors.black,
),
@ -418,7 +418,7 @@ class ListItemFactory {
if (isRequired) Text('* ', style: TextStyle(color: Colors.red)),
Text(
title,
style: const TextStyle(fontSize: 15, fontWeight: FontWeight.bold),
style: const TextStyle(fontSize: 13, fontWeight: FontWeight.bold),
),
],
),
@ -458,7 +458,7 @@ class ListItemFactory {
if (isRequired) Text('* ', style: TextStyle(color: Colors.red)),
//
Expanded(
child:HhTextStyleUtils.mainTitle(label, fontSize: 15),
child:HhTextStyleUtils.mainTitle(label, fontSize: 13),
),
],
),
@ -472,7 +472,7 @@ class ListItemFactory {
keyboardType: TextInputType.multiline,
maxLines: null,
expands: true,
style: const TextStyle(fontSize: 15),
style: const TextStyle(fontSize: 13),
decoration: InputDecoration(
hintText: hint,
border: InputBorder.none,
@ -519,7 +519,7 @@ class ListItemFactory {
child: Text(
title,
style: TextStyle(
fontSize: 15,
fontSize: 13,
fontWeight: FontWeight.bold,
color: Colors.black,
),

View File

@ -28,7 +28,7 @@ class BottomPicker {
required List<T> items,
required Widget Function(T item) itemBuilder,
int initialIndex = 0,
double itemExtent = 40.0,
double itemExtent = 50.0,
double height = 250,
}) {
if (items.isEmpty) return Future.value(null);
@ -82,13 +82,15 @@ class BottomPicker {
scrollController: FixedExtentScrollController(
initialItem: initialIndex,
),
itemExtent: 30,
itemExtent: itemExtent,
onSelectedItemChanged: (index) {
selected = items[index];
},
children: items.map(itemBuilder).toList(),
// itemBuilder Widget Center
children: items.map((item) => Center(child: itemBuilder(item))).toList(),
),
),
],
),
);

View File

@ -27,7 +27,7 @@ class BottomPickerTwo {
required List<dynamic> items,
required Widget Function(dynamic item) itemBuilder,
int initialIndex = 0,
double itemExtent = 40.0,
double itemExtent = 50.0,
double height = 250,
double desiredSpacing = 16.0,
}) {
@ -72,7 +72,7 @@ class BottomPickerTwo {
scrollController: FixedExtentScrollController(
initialItem: initialIndex,
),
itemExtent: 35,
itemExtent: itemExtent,
onSelectedItemChanged: (index) {
selected = items[index];
},
@ -88,7 +88,7 @@ class BottomPickerTwo {
// '选项 $index',
items[index]["NAME"],
style: TextStyle(
fontSize: 18,
fontSize: 15,
color:
index == selected
? CupertinoColors.activeBlue

View File

@ -65,7 +65,7 @@ class _VideoPlayerPopupState extends State<VideoPlayerPopup> {
playedColor: Colors.blue,
backgroundColor: Colors.white,
handleColor: Colors.blue,
bufferedColor: Colors.red,
bufferedColor: Colors.white,
),
aspectRatio: _videoController.value.aspectRatio > 0
? _videoController.value.aspectRatio

View File

@ -1,13 +1,10 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart';
import 'package:qhd_prevention/tools/VideoConverter.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
import 'package:video_compress/video_compress.dart';
import 'package:wechat_assets_picker/wechat_assets_picker.dart';
import 'package:photo_manager/photo_manager.dart';
import 'package:path/path.dart' as p;
@ -54,12 +51,15 @@ class _MediaPickerGridState extends State<MediaPickerRow> {
@override
void initState() {
super.initState();
_mediaPaths = widget.initialMediaPaths != null
_mediaPaths =
widget.initialMediaPaths != null
? widget.initialMediaPaths!.take(widget.maxCount).toList()
: [];
WidgetsBinding.instance.addPostFrameCallback((_) {
widget.onChanged(
_mediaPaths.map((p) => p.startsWith('http') ? File('') : File(p)).toList(),
_mediaPaths
.map((p) => p.startsWith('http') ? File('') : File(p))
.toList(),
);
});
}
@ -114,45 +114,26 @@ class _MediaPickerGridState extends State<MediaPickerRow> {
}
}
Future<void> _cameraAction() async {
if (!widget.isEdit || _mediaPaths.length >= widget.maxCount) return;
try {
if (widget.mediaType == MediaType.image) {
XFile? picked = await _picker.pickImage(source: ImageSource.camera);
if (picked != null) {
final path = picked.path;
setState(() => _mediaPaths.add(path));
widget.onChanged(_mediaPaths.map((p) => File(p)).toList());
widget.onMediaAdded?.call(path);
}
} else {
// video from camera
XFile? picked = await _picker.pickVideo(source: ImageSource.camera);
if (picked != null) {
await _handlePickedPath(picked.path);
}
}
} catch (e) {
debugPrint('拍摄失败: $e');
}
}
Future<void> _showPickerOptions() async {
if (!widget.isEdit) return; //
showModalBottomSheet(
context: context,
backgroundColor: Colors.white,
builder: (_) => SafeArea(
builder:
(_) => SafeArea(
child: Wrap(
children: [
ListTile(
titleAlignment: ListTileTitleAlignment.center,
leading: Icon(
widget.mediaType == MediaType.image ? Icons.camera_alt : Icons.videocam,
widget.mediaType == MediaType.image
? Icons.camera_alt
: Icons.videocam,
),
title: Text(
widget.mediaType == MediaType.image ? '拍照' : '拍摄视频',
),
title: Text(widget.mediaType == MediaType.image ? '拍照' : '拍摄视频'),
onTap: () {
Navigator.of(context).pop();
_pickCamera();
@ -161,9 +142,13 @@ class _MediaPickerGridState extends State<MediaPickerRow> {
ListTile(
titleAlignment: ListTileTitleAlignment.center,
leading: Icon(
widget.mediaType == MediaType.image ? Icons.photo_library : Icons.video_library,
widget.mediaType == MediaType.image
? Icons.photo_library
: Icons.video_library,
),
title: Text(
widget.mediaType == MediaType.image ? '从相册选择' : '从相册选择视频',
),
title: Text(widget.mediaType == MediaType.image ? '从相册选择' : '从相册选择视频'),
onTap: () {
Navigator.of(context).pop();
_pickGallery();
@ -205,53 +190,182 @@ class _MediaPickerGridState extends State<MediaPickerRow> {
}
}
// _pickGallery
Future<void> _pickGallery() async {
if (!widget.isEdit || _mediaPaths.length >= widget.maxCount) return;
try {
// iOS: 使 PhotoManager.requestPermissionExtend() limited
if (Platform.isIOS) {
final permission = await PhotoManager.requestPermissionExtend();
debugPrint('iOS photo permission state: $permission');
if (permission != PermissionState.authorized &&
permission != PermissionState.limited) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('请到设置中开启相册访问权限')),
);
}
return;
}
try {
// limited AssetPicker
final remaining = widget.maxCount - _mediaPaths.length;
final List<AssetEntity>? assets = await AssetPicker.pickAssets(
context,
pickerConfig: AssetPickerConfig(
requestType: widget.mediaType == MediaType.image ? RequestType.image : RequestType.video,
requestType:
widget.mediaType == MediaType.image ? RequestType.image : RequestType.video,
maxAssets: remaining,
gridCount: 4,
),
);
if (assets != null) {
for (final asset in assets) {
if (_mediaPaths.length >= widget.maxCount) break;
try {
final file = await asset.file;
if (file != null) {
final path = file.path;
//
await _handlePickedPath(path);
}
}
setState(() {});
widget.onChanged(_mediaPaths.map((p) => File(p)).toList());
} else {
debugPrint('资产获取 file 为空asset id: ${asset.id}');
}
} catch (e) {
debugPrint('相册选择失败: $e');
debugPrint('读取 asset 文件失败: $e');
}
}
if (mounted) setState(() {});
widget.onChanged(_mediaPaths.map((p) => File(p)).toList());
}
} else {
// Android: 使 permission_handler
final PermissionStatus current = await Permission.storage.status;
PermissionStatus status;
if (current.isGranted) {
status = PermissionStatus.granted;
} else {
status = await Permission.storage.request();
}
debugPrint('Android storage permission: $status');
if (status == PermissionStatus.granted) {
final remaining = widget.maxCount - _mediaPaths.length;
final List<AssetEntity>? assets = await AssetPicker.pickAssets(
context,
pickerConfig: AssetPickerConfig(
requestType:
widget.mediaType == MediaType.image ? RequestType.image : RequestType.video,
maxAssets: remaining,
gridCount: 4,
),
);
if (assets != null) {
for (final asset in assets) {
if (_mediaPaths.length >= widget.maxCount) break;
try {
final file = await asset.file;
if (file != null) {
final path = file.path;
await _handlePickedPath(path);
} else {
debugPrint('资产获取 file 为空asset id: ${asset.id}');
}
} catch (e) {
debugPrint('读取 asset 文件失败: $e');
}
}
if (mounted) setState(() {});
widget.onChanged(_mediaPaths.map((p) => File(p)).toList());
}
} else if (status == PermissionStatus.permanentlyDenied) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('请到设置中开启相册访问权限')),
);
}
await openAppSettings();
} else {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('相册访问权限被拒绝')),
);
}
}
}
} catch (e, st) {
debugPrint('相册选择失败: $e\n$st');
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('相册选择失败')),
);
}
}
}
void _removeMedia(int index) {
if (!widget.isEdit) return; //
// 使 permission_handler
Future<void> _cameraAction() async {
if (!widget.isEdit || _mediaPaths.length >= widget.maxCount) return;
//
final PermissionStatus status = await Permission.camera.request();
if (status != PermissionStatus.granted) {
if (mounted) {
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('相机权限被拒绝')));
}
return;
}
try {
if (widget.mediaType == MediaType.image) {
XFile? picked = await _picker.pickImage(source: ImageSource.camera);
if (picked != null) {
final path = picked.path;
setState(() => _mediaPaths.add(path));
widget.onChanged(_mediaPaths.map((p) => File(p)).toList());
widget.onMediaAdded?.call(path);
}
} else {
// video from camera
XFile? picked = await _picker.pickVideo(source: ImageSource.camera);
if (picked != null) {
await _handlePickedPath(picked.path);
}
}
} catch (e) {
debugPrint('拍摄失败: $e');
//
if (mounted) {
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('拍摄失败,请检查相机权限或设备状态')));
}
}
}
void _removeMedia(int index) async {
final ok = await CustomAlertDialog.showConfirm(
context,
title: '温馨提示',
content:
widget.mediaType == MediaType.image ? '确定要删除这张图片吗?' : '确定要删除这个视频吗?',
cancelText: '取消',
);
if (ok) {
final removed = _mediaPaths[index];
setState(() => _mediaPaths.removeAt(index));
widget.onChanged(_mediaPaths.map((p) => File(p)).toList());
widget.onMediaRemoved?.call(removed);
}
}
@override
Widget build(BuildContext context) {
@ -282,28 +396,42 @@ class _MediaPickerGridState extends State<MediaPickerRow> {
children: [
ClipRRect(
borderRadius: BorderRadius.circular(5),
child: widget.mediaType == MediaType.image
child: SizedBox.expand(
//
child:
widget.mediaType == MediaType.image
? (isNetwork
? Image.network(path, fit: BoxFit.cover, width: 80, height: 80)
: Image.file(File(path), width: 80, height: 80, fit: BoxFit.cover))
? Image.network(
path,
fit: BoxFit.cover, //
)
: Image.file(
File(path),
fit: BoxFit.cover, //
))
: Container(
color: Colors.black12,
child: Center(
child: const Center(
child: Icon(
Icons.videocam,
color: Colors.white70,
),
),
),
),
),
),
),
),
//
if (widget.isEdit)
Positioned(
top: -15,
right: -15,
child: IconButton(
icon: const Icon(Icons.cancel, size: 20, color: Colors.red),
icon: const Icon(
Icons.cancel,
size: 20,
color: Colors.red,
),
onPressed: () => _removeMedia(index),
),
),
@ -336,9 +464,7 @@ class _MediaPickerGridState extends State<MediaPickerRow> {
Positioned.fill(
child: Container(
color: Colors.transparent,
child: const Center(
child: CircularProgressIndicator(),
),
child: const Center(child: CircularProgressIndicator()),
),
),
],
@ -346,12 +472,6 @@ class _MediaPickerGridState extends State<MediaPickerRow> {
}
}
/// 使Grid
/// isEdit
class RepairedPhotoSection extends StatefulWidget {
@ -400,7 +520,8 @@ class _RepairedPhotoSectionState extends State<RepairedPhotoSection> {
@override
void initState() {
super.initState();
_mediaPaths = widget.initialMediaPaths?.take(widget.maxCount).toList() ?? [];
_mediaPaths =
widget.initialMediaPaths?.take(widget.maxCount).toList() ?? [];
WidgetsBinding.instance.addPostFrameCallback((_) {
widget.onChanged(_mediaPaths.map((p) => File(p)).toList());
});
@ -418,7 +539,10 @@ class _RepairedPhotoSectionState extends State<RepairedPhotoSection> {
padding: EdgeInsets.symmetric(horizontal: widget.horizontalPadding),
child: ListItemFactory.createRowSpaceBetweenItem(
leftText: widget.title,
rightText: widget.isShowNum ? '${_mediaPaths.length}/${widget.maxCount}' : '',
rightText:
widget.isShowNum
? '${_mediaPaths.length}/${widget.maxCount}'
: '',
isRequired: widget.isRequired,
),
),
@ -439,14 +563,17 @@ class _RepairedPhotoSectionState extends State<RepairedPhotoSection> {
},
onMediaAdded: widget.onMediaAdded,
onMediaRemoved: widget.onMediaRemoved,
onMediaTapped: widget.onMediaTapped, //
onMediaTapped: widget.onMediaTapped,
//
isEdit: widget.isEdit, //
),
),
const SizedBox(height: 20),
const SizedBox(height: 8),
if (widget.isShowAI && widget.isEdit) // AI
Padding(
padding: EdgeInsets.symmetric(horizontal: widget.horizontalPadding),
padding: EdgeInsets.symmetric(
horizontal: widget.horizontalPadding,
),
child: GestureDetector(
onTap: widget.onAiIdentify,
child: Container(

View File

@ -6,6 +6,7 @@ import 'package:flutter/material.dart';
/// context,
/// mode: BottomPickerMode.date, // BottomPickerMode.dateTime
/// allowFuture: true,
/// allowPast: false, // false
/// minTimeStr: '2025-08-20 08:30',
/// );
/// if (picked != null) {
@ -16,7 +17,8 @@ enum BottomPickerMode { dateTime, date }
class BottomDateTimePicker {
static Future<DateTime?> showDate(
BuildContext context, {
bool allowFuture = false,
bool allowFuture = true,
bool allowPast = true, //
String? minTimeStr, // 'yyyy-MM-dd HH:mm'
BottomPickerMode mode = BottomPickerMode.dateTime,
}) {
@ -29,6 +31,7 @@ class BottomDateTimePicker {
),
builder: (_) => _InlineDateTimePickerContent(
allowFuture: allowFuture,
allowPast: allowPast,
minTimeStr: minTimeStr,
mode: mode,
),
@ -38,12 +41,14 @@ class BottomDateTimePicker {
class _InlineDateTimePickerContent extends StatefulWidget {
final bool allowFuture;
final bool allowPast;
final String? minTimeStr;
final BottomPickerMode mode;
const _InlineDateTimePickerContent({
Key? key,
this.allowFuture = false,
this.allowFuture = true,
this.allowPast = true,
this.minTimeStr,
this.mode = BottomPickerMode.dateTime,
}) : super(key: key);
@ -87,13 +92,25 @@ class _InlineDateTimePickerContentState
// minTimeStr
_minTime = _parseMinTime(widget.minTimeStr);
// now _minTime
// now _minTime allowPast
final now = DateTime.now();
DateTime initial = now;
// now
if (_minTime != null && _minTime!.isAfter(initial)) {
initial = _minTime!;
}
// initial now 00:00
if (!widget.allowPast) {
if (widget.mode == BottomPickerMode.date) {
final today = DateTime(now.year, now.month, now.day);
if (initial.isBefore(today)) initial = today;
} else {
if (initial.isBefore(now)) initial = now;
}
}
// date
if (widget.mode == BottomPickerMode.date) {
initial = DateTime(initial.year, initial.month, initial.day);
@ -120,7 +137,7 @@ class _InlineDateTimePickerContentState
minuteCtrl = FixedExtentScrollController(
initialItem: selectedMinute.clamp(0, minutes.length - 1));
// minTime
// minTime /
WidgetsBinding.instance.addPostFrameCallback((_) {
_enforceConstraintsAndUpdateControllers();
});
@ -169,7 +186,7 @@ class _InlineDateTimePickerContentState
});
}
//
// allowPast allowFuture
void _enforceConstraintsAndUpdateControllers() {
final now = DateTime.now();
final isDateOnly = widget.mode == BottomPickerMode.date;
@ -179,12 +196,27 @@ class _InlineDateTimePickerContentState
: DateTime(
selectedYear, selectedMonth, selectedDay, selectedHour, selectedMinute);
// _minTime date
if (_minTime != null) {
final DateTime minRef = isDateOnly
// _minTime allowPast
DateTime? minRef;
if (!widget.allowPast) {
// now 00:00
minRef = isDateOnly
? DateTime(now.year, now.month, now.day)
: now;
// _minTime now _minTime
if (_minTime != null && _minTime!.isAfter(minRef)) {
minRef = isDateOnly
? DateTime(_minTime!.year, _minTime!.month, _minTime!.day)
: _minTime!;
if (picked.isBefore(minRef)) {
: _minTime;
}
} else if (_minTime != null) {
// _minTime _minTime
minRef = isDateOnly
? DateTime(_minTime!.year, _minTime!.month, _minTime!.day)
: _minTime;
}
if (minRef != null && picked.isBefore(minRef)) {
// minRef
selectedYear = minRef.year;
selectedMonth = minRef.month;
@ -197,7 +229,6 @@ class _InlineDateTimePickerContentState
selectedMinute = 0;
}
//
_updateDays(jumpDay: false);
yearCtrl.jumpToItem(years.indexOf(selectedYear));
monthCtrl.jumpToItem(selectedMonth - 1);
@ -208,7 +239,6 @@ class _InlineDateTimePickerContentState
}
return;
}
}
// allowFuture == false
if (!widget.allowFuture) {
@ -370,7 +400,7 @@ class _InlineDateTimePickerContentState
return Expanded(
child: CupertinoPicker.builder(
scrollController: controller,
itemExtent: 32,
itemExtent: 40,
childCount: items.length,
onSelectedItemChanged: onSelected,
itemBuilder: (context, index) {

View File

@ -237,20 +237,29 @@ U6Hzm1ninpWeE+awIDAQAB
},
);
}
///
static Future<Map<String, dynamic>> getRecordMapInfo(String CHECKRECORD_ID) {
/// ()
static Future<Map<String, dynamic>> getNormalRecordMapInfo(Map data) {
return HttpManager().request(
basePath,
'/app/customCheckRecord/goMap',
method: Method.post,
data: {
'USER_ID': SessionService.instance.loginUserId,
'CORPINFO_ID': SessionService.instance.corpinfoId,
'CHECKRECORD_ID': CHECKRECORD_ID,
...data
},
);
}
/// ()
static Future<Map<String, dynamic>> getDangerRecordMapInfo(Map data) {
return HttpManager().request(
basePath,
'/app/checkrecord/goMap',
method: Method.post,
data: {
...data
},
);
}
/// 1 2
static Future<Map<String, dynamic>> getDanger(int type) {
@ -301,7 +310,7 @@ U6Hzm1ninpWeE+awIDAQAB
'userId': SessionService.instance.loginUserId,
'USER_NAME': SessionService.instance.username,
'CHECK_DEPARTMENT_ID': SessionService.instance.deptId,
'IS_MAIN': SessionService.instance.isRest,
'IS_MAIN': SessionService.instance.loginUser?['ISMAIN']??'',
'CORPINFO_ID': SessionService.instance.corpinfoId,
'USER_ID': SessionService.instance.loginUserId,
},
@ -312,7 +321,7 @@ U6Hzm1ninpWeE+awIDAQAB
static Future<Map<String, dynamic>> getHiddenRoll() {
return HttpManager().request(
basePath,
'/app/offduty/isRest',
'/app/hidden/getHiddenByCorp',
method: Method.post,
data: {
'CORPINFO_ID': SessionService.instance.corpinfoId,
@ -431,7 +440,7 @@ U6Hzm1ninpWeE+awIDAQAB
},
);
}
///
static Future<Map<String, dynamic>> fnSetUserFaceTime(int FACE_TIME) {
return HttpManager().request(
baseFacePath,
@ -445,16 +454,28 @@ U6Hzm1ninpWeE+awIDAQAB
},
);
}
static Future<Map<String, dynamic>> fnGetUserFaceTime(int FACE_TIME) {
///
static Future<Map<String, dynamic>> fnGetUserFaceTime() {
return HttpManager().request(
baseFacePath,
'/app/user/getUserFaceTime',
method: Method.post,
withToken: true,
data: {
'loading': false,
'FACE_TIME': FACE_TIME,
'CORPINFO_ID': SessionService.instance.corpinfoId,
'USER_ID': SessionService.instance.loginUserId,
},
);
}
///
static Future<Map<String, dynamic>> fnGetUserFace() {
return HttpManager().request(
basePath,
'/app/user/getUserFace',
method: Method.post,
withToken: true,
data: {
'USERNAME': SessionService.instance.username,
'CORPINFO_ID': SessionService.instance.corpinfoId,
'USER_ID': SessionService.instance.loginUserId,
},
@ -474,7 +495,7 @@ U6Hzm1ninpWeE+awIDAQAB
},
);
}
///
static Future<Map<String, dynamic>> fnGetVideoPlayProgress(
String VIDEOCOURSEWARE_ID,
String CURRICULUM_ID,
@ -968,7 +989,7 @@ U6Hzm1ninpWeE+awIDAQAB
);
}
///
///
static Future<Map<String, dynamic>> saveSafeFunctionSure(
String workType,
Map<String, dynamic> formData,
@ -3877,19 +3898,7 @@ U6Hzm1ninpWeE+awIDAQAB
},
);
}
///
static Future<Map<String, dynamic>> deleteNFCImage(Map data) {
return HttpManager().request(
basePath,
'/app/app/imgfiles/delete',
method: Method.post,
data: {
...data,
"CORPINFO_ID": SessionService.instance.corpinfoId,
"USER_ID": SessionService.instance.loginUserId,
},
);
}
/// nfc
static Future<Map<String, dynamic>> nfcInspectionRecord(
int showCount,

View File

@ -1,6 +1,7 @@
// main.dart
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:qhd_prevention/pages/badge_manager.dart';
import 'package:qhd_prevention/services/auth_service.dart';
import 'package:qhd_prevention/tools/tools.dart';
@ -34,7 +35,10 @@ class GlobalMessage {
}
/// helper
Future<T?> showDialogAfterUnfocus<T>(BuildContext context, Widget dialog) async {
Future<T?> showDialogAfterUnfocus<T>(
BuildContext context,
Widget dialog,
) async {
//
FocusScope.of(context).unfocus();
try {
@ -65,7 +69,10 @@ Future<T?> showModalBottomSheetAfterUnfocus<T>({
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
// EasyLoading
EasyLoading.instance
..displayDuration = const Duration(seconds: 20)
@ -123,9 +130,21 @@ class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: '',
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
// 使 delegate
],
supportedLocales: [
const Locale('zh', 'CN'), //
const Locale('en', 'US'), //
],
locale: const Locale('zh', 'CN'),
// 使
navigatorKey: navigatorKey,
// push/pop TextField
navigatorObservers: [KeyboardUnfocusNavigatorObserver(),routeObserver],
navigatorObservers: [KeyboardUnfocusNavigatorObserver(), routeObserver],
builder: (context, child) {
return EasyLoading.init(
builder: (context, widget) {
@ -133,7 +152,11 @@ class MyApp extends StatelessWidget {
behavior: HitTestBehavior.translucent,
onTap: () {
//
FocusHelper.clearFocus(context);
try {
FocusManager.instance.primaryFocus?.unfocus();
} catch (e) {
debugPrint('NavigatorObserver unfocus error: $e');
}
},
child: widget,
);
@ -142,7 +165,7 @@ class MyApp extends StatelessWidget {
},
theme: ThemeData(
textTheme: const TextTheme(
bodyMedium: TextStyle(fontSize: 14), //
bodyMedium: TextStyle(fontSize: 13), //
),
dividerTheme: const DividerThemeData(
color: Colors.black12,
@ -169,9 +192,7 @@ class MyApp extends StatelessWidget {
),
home: isLoggedIn ? const MainPage() : const LoginPage(),
debugShowCheckedModeBanner: false,
routes: {
'/login': (_) => const LoginPage(),
},
routes: {'/login': (_) => const LoginPage()},
);
}
}

View File

@ -151,19 +151,23 @@ class _DangerManagerDetailPageState extends State<DangerManagerDetailPage> {
}
Future<void> _submit() async {
if (!FormUtils.hasValue(hiddenForm, 'CHECKTIME')) {
ToastUtil.showNormal(context, '请选择验收时间');
return;
}
LoadingDialogHelper.show();
final result = await ApiService.checkKeyprojectDanger(widget.info['HIDDEN_ID'] ?? '', hiddenForm);
final result = await ApiService.checkKeyprojectDanger(
widget.info['HIDDEN_ID'] ?? '',
hiddenForm,
);
if (result['result'] == 'success') {
final List<String> files = _getServerPath(hiddenForm['ysImgs']);
for (String p in files) {
final upResult = await ApiService.addNormalImgFiles(p,{'TYPE':'5','FOREIGN_KEY':widget.info['HIDDEN_ID']});
final upResult = await ApiService.addNormalImgFiles(p, {
'TYPE': '5',
'FOREIGN_KEY': widget.info['HIDDEN_ID'],
});
if (FormUtils.hasValue(upResult, 'network_error')) {
LoadingDialogHelper.hide();
ToastUtil.showNormal(context, '上传文件出错');
@ -272,7 +276,8 @@ class _DangerManagerDetailPageState extends State<DangerManagerDetailPage> {
ItemListWidget.singleLineTitleText(
label: '整改部门',
isEditable: false,
text: hiddenForm['RECTIFICATIONDEPT_NAME'] ?? '',
text:
hiddenForm['RECTIFICATIONDEPT_NAME'] ?? '',
),
const Divider(),
ItemListWidget.singleLineTitleText(
@ -342,31 +347,47 @@ class _DangerManagerDetailPageState extends State<DangerManagerDetailPage> {
),
const Divider(),
Padding(padding: EdgeInsets.symmetric(horizontal: 8),child: RepairedPhotoSection(
Padding(
padding: EdgeInsets.symmetric(
horizontal: 8,
),
child: RepairedPhotoSection(
title: '验收照片',
maxCount: 4,
mediaType: MediaType.image,
isShowAI: false,
isEdit: widget.info['TabCur'] == '1'
isEdit:
widget.info['TabCur'] == '1'
? true
: false,
isRequired:false,
initialMediaPaths: _getServerPath(
hiddenForm['ysImgs'],
).map((path) => '${ApiService.baseImgPath}$path').toList(),
isRequired: false,
initialMediaPaths:
_getServerPath(hiddenForm['ysImgs'])
.map(
(path) =>
'${ApiService.baseImgPath}$path',
)
.toList(),
onMediaTapped: (p) {
presentOpaque(SingleImageViewer(imageUrl: p), context);
presentOpaque(
SingleImageViewer(imageUrl: p),
context,
);
},
onChanged:
(files) => setState(() {
hiddenForm['ysImgs'] =
files
.map((f) => {'FILEPATH': f.path})
.map(
(f) => {
'FILEPATH': f.path,
},
)
.toList();
}), onAiIdentify: () { },
),)
}),
onAiIdentify: () {},
),
),
],
),

View File

@ -6,6 +6,7 @@ import 'package:intl/intl.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
import 'package:qhd_prevention/customWidget/bottom_picker.dart';
import 'package:qhd_prevention/customWidget/bottom_picker_two.dart';
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/date_picker_dialog.dart';
import 'package:qhd_prevention/customWidget/department_person_picker.dart';
@ -19,6 +20,17 @@ import 'package:qhd_prevention/tools/tools.dart';
import '../../../customWidget/photo_picker_row.dart';
import '../../../http/ApiService.dart';
class ImgData {
final String path;
final String id;
const ImgData({
required this.path,
required this.id,
});
}
class CheckInformationOneItem extends StatefulWidget {
const CheckInformationOneItem(this.id,this.item, this.result, this.type, {super.key,required this.onClose});
@ -46,8 +58,8 @@ class _CheckInformationOneItemState extends State<CheckInformationOneItem> {
List<Map<String, dynamic>> _personCache = [];
List<String> _yinHuanImages = [];
List<String> _yinHuanVido = [];
List<ImgData> _yinHuanImages = [];
List<ImgData> _yinHuanVido = [];
// String _yinHuanVido="";
dynamic _hazardLeve;
String yinHuanId = "";
@ -59,7 +71,7 @@ class _CheckInformationOneItemState extends State<CheckInformationOneItem> {
String responsibleName="";
String dataTime = "";
List<String> _zhengGaiImages = [];
List<ImgData> _zhengGaiImages = [];
List<String> _yinHuanTypeIds = [];
List<String> _yinHuanTypeNames = [];
@ -70,10 +82,6 @@ class _CheckInformationOneItemState extends State<CheckInformationOneItem> {
void initState() {
// TODO: implement initState
super.initState();
// unqualifiedInspectionItemID=SessionService.instance.unqualifiedInspectionItemID.toString();
unqualifiedInspectionItemID=widget.item.departmentId;
setState(() {
@ -83,10 +91,12 @@ class _CheckInformationOneItemState extends State<CheckInformationOneItem> {
dynamic pd=widget.result["pd"];
for(int i=0;i<hImgs.length;i++){
if (hImgs[i]['FILEPATH'].toString().endsWith('.mp4')) {
_yinHuanVido.add(ApiService.baseImgPath +hImgs[i]['FILEPATH']);
final ImgData = hImgs[i];
if (ImgData['FILEPATH'].toString().endsWith('.mp4')) {
_yinHuanVido.add(ImgData(path: ApiService.baseImgPath +hImgs[i]['FILEPATH'], id: ImgData['IMGFILES_ID']));
} else {
_yinHuanImages.add(ApiService.baseImgPath +hImgs[i]["FILEPATH"]);
_yinHuanImages.add(ImgData(path: ApiService.baseImgPath +hImgs[i]['FILEPATH'], id: ImgData['IMGFILES_ID']));
}
}
// _yinHuanVido
@ -113,7 +123,7 @@ class _CheckInformationOneItemState extends State<CheckInformationOneItem> {
dataTime=pd["RECTIFICATIONDEADLINE"];
_dangerDetailController.text=pd["RECTIFYDESCR"];
_zhengGaiImages= rImgs.map((e) => ApiService.baseImgPath +e["FILEPATH"]).toList();
_zhengGaiImages= rImgs.map((e) => ImgData(path: ApiService.baseImgPath +e["FILEPATH"], id: e['IMGFILES_ID'])).toList();
// _zhengGaiImages"rImgs" -> [_GrowableList]
}else{
@ -170,7 +180,34 @@ class _CheckInformationOneItemState extends State<CheckInformationOneItem> {
),
);
}
String _getIDForPath(String path, List<ImgData> imgList) {
for (ImgData data in imgList) {
if (data.path == path) {
return data.id;
}
}
return '';
}
Future<bool> _removeFileWithType(String type, String id) async{
if (id.isEmpty) {
return true;
}
final result = await ApiService.onImageRemoved(id);
if (result['result'] == 'success') {
return true;
}else{
return false;
}
// return
}
ImgData _getImageDataForPath(String path, List<ImgData> list) {
for (ImgData data in list) {
if (data.path == path) {
return data;
}
}
return ImgData(path: '', id: '');
}
Widget _buildSectionContainer({required Widget child}) {
return Container(
margin: const EdgeInsets.only(top: 10),
@ -201,21 +238,29 @@ class _CheckInformationOneItemState extends State<CheckInformationOneItem> {
title: "隐患照片",
maxCount: 4,
mediaType: MediaType.image,
initialMediaPaths:_yinHuanImages,
initialMediaPaths:_yinHuanImages.map((item) => item.path).toList(),
isShowAI: true,
onMediaAdded: (value) {
_yinHuanImages.add(value);
_yinHuanImages.add(ImgData(path: value, id: ''));
},
onMediaRemoved: (value) {
onMediaRemoved: (value) async {
if (value.startsWith('http')) {
final result = await _removeFileWithType('img', _getIDForPath(value, _yinHuanImages));
if (result) {
setState(() {
_yinHuanImages.remove(_getImageDataForPath(value, _yinHuanImages));
});
}
}else{
setState(() {
_yinHuanImages.remove(_getImageDataForPath(value, _yinHuanImages));
});
}
},
onChanged: (List<File> files) {
// // files
// _yinHuanImages.clear();
// for(int i=0;i<files.length;i++){
// _yinHuanImages.add(files[i].path);
// }
},
onChanged: (List<File> files) {},
onAiIdentify: () {
// AI
if(_yinHuanImages.isEmpty){
@ -226,7 +271,7 @@ class _CheckInformationOneItemState extends State<CheckInformationOneItem> {
ToastUtil.showNormal(context, "识别暂时只能上传一张图片");
return;
}
_identifyImg(_yinHuanImages[0]);
_identifyImg(_yinHuanImages[0].path);
},
),
),
@ -235,10 +280,26 @@ class _CheckInformationOneItemState extends State<CheckInformationOneItem> {
title: "隐患视频",
maxCount: 1,
mediaType: MediaType.video,
initialMediaPaths: _yinHuanVido,
initialMediaPaths: _yinHuanVido.map((item) => item.path).toList(),
onMediaAdded: (value) {
_yinHuanVido.add(value);
_yinHuanVido.add(ImgData(path: value, id: ''));
},
onMediaRemoved: (value) async {
if (value.startsWith('http')) {
final result = await _removeFileWithType('video', _getIDForPath(value, _yinHuanVido));
if (result) {
setState(() {
_yinHuanVido.remove(_getImageDataForPath(value, _yinHuanVido));
});
}
}else{
setState(() {
_yinHuanVido.remove(_getImageDataForPath(value, _yinHuanVido));
});
}
},
onChanged: (List<File> files) {
// files
// _yinHuanVido=files[0].path;
@ -366,17 +427,28 @@ class _CheckInformationOneItemState extends State<CheckInformationOneItem> {
horizontalPadding: 0,
mediaType: MediaType.image,
isShowAI: false,
initialMediaPaths: _zhengGaiImages,
initialMediaPaths:_zhengGaiImages.map((item) => item.path).toList(),
onMediaAdded: (value) {
_zhengGaiImages.add(value);
_zhengGaiImages.add(ImgData(path: value, id: ''));
},
onMediaRemoved: (value) async {
if (value.startsWith('http')) {
final result = await _removeFileWithType('img', _getIDForPath(value, _zhengGaiImages));
if (result) {
setState(() {
_zhengGaiImages.remove(_getImageDataForPath(value, _zhengGaiImages));
});
}
}else{
setState(() {
_zhengGaiImages.remove(_getImageDataForPath(value, _zhengGaiImages));
});
}
},
onChanged: (List<File> files) {
// files
// _zhengGaiImages.clear();
// for(int i=0;i<files.length;i++){
// _zhengGaiImages.add(files[i].path);
// }
},
onAiIdentify: () {
@ -651,21 +723,21 @@ class _CheckInformationOneItemState extends State<CheckInformationOneItem> {
String hiddenId = result['pd']['HIDDEN_ID'] ;
// SessionService.instance.setUnqualifiedInspectionItemIDJson(hiddenId);
bool success = true;
for (int i=0;i<_yinHuanImages.length;i++){
_addImgFiles(_yinHuanImages[i],"3",hiddenId);
success = await _addImgFiles(_yinHuanImages[i],"3",hiddenId);
}
if(_yinHuanVido.isNotEmpty) {
_addImgFiles(_yinHuanVido[0],"3",hiddenId);
success = await _addImgFiles(_yinHuanVido[0],"3",hiddenId);
}
if(_isDanger){
for (int i=0;i<_zhengGaiImages.length;i++){
_addImgFiles(_zhengGaiImages[i],"4",hiddenId);
success = await _addImgFiles(_zhengGaiImages[i],"4",hiddenId);
}
}
if (success) {
setState(() {
ToastUtil.showNormal(context, "提交成功");
Navigator.pop(context);
@ -673,31 +745,40 @@ class _CheckInformationOneItemState extends State<CheckInformationOneItem> {
});
}
}
} catch (e) {
LoadingDialogHelper.hide();
print('Error fetching data: $e');
}
}
Future<String> _addImgFiles(String imagePath,String type,String id) async {
Future<bool> _addImgFiles(ImgData imgData,String type,String id) async {
if (imgData.id.isEmpty) {
try {
final raw = await ApiService.addImgFiles( imagePath, type, id);
final raw = await ApiService.addImgFiles( imgData.path, type, id);
if (raw['result'] == 'success') {
return raw['imgPath'];
Map pd = raw['pd'];
imgData = ImgData(path: pd['FILEPATH'], id: pd['IMGFILES_ID']);
return true;
}else{
// _showMessage('反馈提交失败');
return "";
ToastUtil.showError(context, raw['message'] ?? '图片上传失败,请重试');
return false;
}
} catch (e) {
// Toast
print('加载数据失败:$e');
return "";
ToastUtil.showError(context, '图片上传失败,请重试');
return false;
}
}
//
return true;
}
Future<void> _identifyImg(String imagePath) async {

View File

@ -80,7 +80,17 @@ class _CheckRecordDetailPageState extends State<CheckRecordDetailPage> {
Future<void> _getMapData() async {
setState(() => _loadingMap = true);
try {
final resData = await ApiService.getRecordMapInfo(widget.id);
Map data = {
'USER_ID': SessionService.instance.loginUserId,
'CORPINFO_ID': SessionService.instance.corpinfoId,
'CHECKRECORD_ID': widget.id,
};
Map resData = {};
if (widget.type == 1) {
resData = await ApiService.getDangerRecordMapInfo(data);
} else {
resData = await ApiService.getNormalRecordMapInfo(data);
}
final built = buildCoversFromRes(resData);
double lat = centerLat;
double lng = centerLng;
@ -109,7 +119,7 @@ class _CheckRecordDetailPageState extends State<CheckRecordDetailPage> {
}
}
List<Map<String, dynamic>> buildCoversFromRes(Map<String, dynamic> res) {
List<Map<String, dynamic>> buildCoversFromRes(Map res) {
final list = <Map<String, dynamic>>[];
final cinfo = res['cinfo'];

View File

@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
import 'package:qhd_prevention/customWidget/photo_picker_row.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/http/ApiService.dart';
import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
class PhotoItem {
@ -79,6 +80,7 @@ class _DangerImageUpdataPageState extends State<DangerImageUpdataPage> {
appBar: MyAppbar(title: "检查照片"),
body: Column(
children: [
ItemListWidget.itemContainer(
RepairedPhotoSection(
title: "检查照片",
maxCount: 4,
@ -106,6 +108,7 @@ class _DangerImageUpdataPageState extends State<DangerImageUpdataPage> {
onChanged: (List<File> value) {},
),
),
//
Container(
margin: const EdgeInsets.only(bottom: 20),

View File

@ -6,12 +6,15 @@ import 'package:intl/intl.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
import 'package:qhd_prevention/customWidget/bottom_picker.dart';
import 'package:qhd_prevention/customWidget/bottom_picker_two.dart';
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/date_picker_dialog.dart';
import 'package:qhd_prevention/customWidget/department_person_picker.dart';
import 'package:qhd_prevention/customWidget/department_picker.dart';
import 'package:qhd_prevention/customWidget/department_picker_hidden_type.dart';
import 'package:qhd_prevention/customWidget/department_picker_two.dart';
import 'package:qhd_prevention/customWidget/full_screen_video_page.dart';
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
@ -19,6 +22,17 @@ import 'package:qhd_prevention/tools/tools.dart';
import '../../../customWidget/photo_picker_row.dart';
import '../../../http/ApiService.dart';
class ImgData {
final String path;
final String id;
const ImgData({
required this.path,
required this.id,
});
}
class HazardRegistrationPage extends StatefulWidget {
const HazardRegistrationPage(this.item, this.result, this.type, {super.key,required this.onClose});
@ -45,8 +59,8 @@ class _HazardRegistrationPageState extends State<HazardRegistrationPage> {
List<Map<String, dynamic>> _personCache = [];
List<String> _yinHuanImages = [];
List<String> _yinHuanVido = [];
List<ImgData> _yinHuanImages = [];
List<ImgData> _yinHuanVido = [];
// String _yinHuanVido="";
dynamic _hazardLeve;
String yinHuanId = "";
@ -58,7 +72,7 @@ class _HazardRegistrationPageState extends State<HazardRegistrationPage> {
String responsibleName="";
String dataTime = "";
List<String> _zhengGaiImages = [];
List<ImgData> _zhengGaiImages = [];
List<String> _yinHuanTypeIds = [];
List<String> _yinHuanTypeNames = [];
@ -69,25 +83,21 @@ class _HazardRegistrationPageState extends State<HazardRegistrationPage> {
void initState() {
// TODO: implement initState
super.initState();
setState(() {
neiRong=widget.item['CHECK_CONTENT'] ?? '';
_standardController.text=widget.item["CHECK_UNQUALIFIED"]??"";
});
unqualifiedInspectionItemID=SessionService.instance.unqualifiedInspectionItemID.toString();
setState(() {
if(unqualifiedInspectionItemID.isNotEmpty){
List<dynamic> hImgs=widget.result["hImgs"];
List<dynamic> rImgs=widget.result["rImgs"];
if(unqualifiedInspectionItemID.isNotEmpty && widget.result.isNotEmpty){
List<dynamic> hImgs=widget.result["hImgs"] ?? [];
List<dynamic> rImgs=widget.result["rImgs"]?? [];
dynamic pd=widget.result["pd"];
for(int i=0;i<hImgs.length;i++){
if (hImgs[i]['FILEPATH'].toString().endsWith('.mp4')) {
_yinHuanVido.add(ApiService.baseImgPath +hImgs[i]['FILEPATH']);
final item = hImgs[i];
if (item['FILEPATH'].toString().endsWith('.mp4')) {
_yinHuanVido.add(ImgData(path: ApiService.baseImgPath +item['FILEPATH'], id: item['IMGFILES_ID']));
} else {
_yinHuanImages.add(ApiService.baseImgPath +hImgs[i]["FILEPATH"]);
_yinHuanImages.add(ImgData(path: ApiService.baseImgPath +item['FILEPATH'], id: item['IMGFILES_ID']));
}
}
// _yinHuanVido
@ -114,18 +124,44 @@ class _HazardRegistrationPageState extends State<HazardRegistrationPage> {
dataTime=pd["RECTIFICATIONDEADLINE"];
_dangerDetailController.text=pd["RECTIFYDESCR"];
_zhengGaiImages= rImgs.map((e) => ApiService.baseImgPath +e["FILEPATH"]).toList();
_zhengGaiImages= rImgs.map((e) => ImgData(path: ApiService.baseImgPath +e["FILEPATH"], id: '')).toList();
// _zhengGaiImages"rImgs" -> [_GrowableList]
}
});
_getHazardLevel();
}
String _getIDForPath(String path, List<ImgData> imgList) {
for (ImgData data in imgList) {
if (data.path == path) {
return data.id;
}
}
return '';
}
Future<bool> _removeFileWithType(String type, String id) async{
if (id.isEmpty) {
return true;
}
final result = await ApiService.onImageRemoved(id);
if (result['result'] == 'success') {
return true;
}else{
return false;
}
// return
}
ImgData _getImageDataForPath(String path, List<ImgData> list) {
for (ImgData data in list) {
if (data.path == path) {
return data;
}
}
return ImgData(path: '', id: '');
}
Future<void> _getHazardLevel() async {
try {
final result = await ApiService.getHazardLevel();
@ -200,20 +236,28 @@ class _HazardRegistrationPageState extends State<HazardRegistrationPage> {
title: "隐患照片",
maxCount: 4,
mediaType: MediaType.image,
initialMediaPaths:_yinHuanImages,
initialMediaPaths:_yinHuanImages.map((item) => item.path).toList(),
isShowAI: true,
onMediaAdded: (value) {
_yinHuanImages.add(value);
_yinHuanImages.add(ImgData(path: value, id: ''));
},
onMediaRemoved: (value) {
onMediaRemoved: (value) async {
if (value.startsWith('http')) {
final result = await _removeFileWithType('img', _getIDForPath(value, _yinHuanImages));
if (result) {
setState(() {
_yinHuanImages.remove(_getImageDataForPath(value, _yinHuanImages));
});
}
}else{
setState(() {
_yinHuanImages.remove(_getImageDataForPath(value, _yinHuanImages));
});
}
},
onChanged: (List<File> files) {
// // files
// _yinHuanImages.clear();
// for(int i=0;i<files.length;i++){
// _yinHuanImages.add(files[i].path);
// }
onChanged: (List<File> files) {},
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onAiIdentify: () {
// AI
@ -225,7 +269,7 @@ class _HazardRegistrationPageState extends State<HazardRegistrationPage> {
ToastUtil.showNormal(context, "识别暂时只能上传一张图片");
return;
}
_identifyImg(_yinHuanImages[0]);
_identifyImg(_yinHuanImages[0].path);
},
),
),
@ -234,17 +278,23 @@ class _HazardRegistrationPageState extends State<HazardRegistrationPage> {
title: "隐患视频",
maxCount: 1,
mediaType: MediaType.video,
initialMediaPaths: _yinHuanVido,
initialMediaPaths: _yinHuanVido.map((item) => item.path).toList(),
onMediaAdded: (value) {
_yinHuanVido.add(value);
_yinHuanVido.add(ImgData(path: value, id: ''));
},
onMediaRemoved: (value){
_yinHuanVido.remove(value);
},
onMediaTapped: (path) {
showDialog(
context: context,
barrierColor: Colors.black54,
builder: (_) => VideoPlayerPopup(videoUrl:path),
);
},
onChanged: (List<File> files) {
// files
// _yinHuanVido=files[0].path;
},
onAiIdentify: () {
// AI
},
onAiIdentify: () {},
),
),
_buildSectionContainer(
@ -365,18 +415,27 @@ class _HazardRegistrationPageState extends State<HazardRegistrationPage> {
horizontalPadding: 0,
mediaType: MediaType.image,
isShowAI: false,
initialMediaPaths: _zhengGaiImages,
initialMediaPaths:_zhengGaiImages.map((item) => item.path).toList(),
onMediaAdded: (value) {
_zhengGaiImages.add(value);
_zhengGaiImages.add(ImgData(path: value, id: ''));
},
onChanged: (List<File> files) {
// files
// _zhengGaiImages.clear();
// for(int i=0;i<files.length;i++){
// _zhengGaiImages.add(files[i].path);
// }
onMediaRemoved: (value) async {
if (value.startsWith('http')) {
final result = await _removeFileWithType('img', _getIDForPath(value, _zhengGaiImages));
if (result) {
setState(() {
_zhengGaiImages.remove(_getImageDataForPath(value, _zhengGaiImages));
});
}
}else{
setState(() {
_zhengGaiImages.remove(_getImageDataForPath(value, _zhengGaiImages));
});
}
},
onChanged: (List<File> files) {},
onAiIdentify: () {
},
@ -640,26 +699,28 @@ class _HazardRegistrationPageState extends State<HazardRegistrationPage> {
String hiddenId = result['pd']['HIDDEN_ID'] ;
SessionService.instance.setUnqualifiedInspectionItemIDJson(hiddenId);
bool success = true;
for (int i=0;i<_yinHuanImages.length;i++){
_addImgFiles(_yinHuanImages[i],"3",hiddenId);
success = await _addImgFiles(_yinHuanImages[i],"3",hiddenId);
}
if(_yinHuanVido.isNotEmpty) {
_addImgFiles(_yinHuanVido[0],"3",hiddenId);
success = await _addImgFiles(_yinHuanVido[0],"3",hiddenId);
}
if(_isDanger){
for (int i=0;i<_zhengGaiImages.length;i++){
_addImgFiles(_zhengGaiImages[i],"4",hiddenId);
success = await _addImgFiles(_zhengGaiImages[i],"4",hiddenId);
}
}
if (success) {
setState(() {
ToastUtil.showNormal(context, "提交成功");
Navigator.pop(context);
widget.onClose(hiddenId,_standardController.text.trim());
widget.onClose(hiddenId, _standardController.text.trim());
});
}
}
} catch (e) {
LoadingDialogHelper.hide();
print('Error fetching data: $e');
@ -668,23 +729,32 @@ class _HazardRegistrationPageState extends State<HazardRegistrationPage> {
Future<String> _addImgFiles(String imagePath,String type,String id) async {
Future<bool> _addImgFiles(ImgData imgData,String type,String id) async {
if (imgData.id.isEmpty) {
try {
final raw = await ApiService.addImgFiles( imagePath, type, id);
final raw = await ApiService.addImgFiles( imgData.path, type, id);
if (raw['result'] == 'success') {
return raw['imgPath'];
Map pd = raw['pd'];
imgData = ImgData(path: pd['FILEPATH'], id: pd['IMGFILES_ID']);
return true;
}else{
// _showMessage('反馈提交失败');
return "";
ToastUtil.showError(context, raw['message'] ?? '图片上传失败,请重试');
return false;
}
} catch (e) {
// Toast
print('加载首页数据失败:$e');
return "";
print('加载数据失败:$e');
ToastUtil.showError(context, '图片上传失败,请重试');
return false;
}
}
//
return true;
}
Future<void> _identifyImg(String imagePath) async {

View File

@ -22,16 +22,6 @@ class _InspectRecordsListPageState extends State<InspectRecordsListPage>
int _selectedTab = 0;
int pageNum = 1;
//
final List<Map<String, dynamic>> _notifications = List.generate(10, (i) {
bool read = i % 3 == 0;
return {
'title': '测试数据标题标题 ${i + 1}',
'time': '2025-06-${10 + i} 12:3${i}',
'read': read,
};
});
@override
void initState() {
super.initState();
@ -145,7 +135,7 @@ class _InspectRecordsListPageState extends State<InspectRecordsListPage>
),
labelColor: Colors.blue,
unselectedLabelColor: Colors.grey,
tabs: const [Tab(text: '政府公告'), Tab(text: '企业公告')],
tabs: const [Tab(text: '平台公告'), Tab(text: '企业公告')],
),
// Search bar

View File

@ -218,9 +218,14 @@ class _HiddenDangerAcceptancePageState extends State<HiddenDangerAcceptancePage>
Divider(height: 1),
_buildInfoItem('发现时间', pd['CREATTIME'] ?? ''),
Divider(height: 1),
_buildInfoItem('隐患级别', pd['HIDDENLEVELNAME'] ?? ''),
Divider(height: 1),
if (pd['HIDDEN_CATEGORY']?.isNotEmpty == true)
Column(children: [
_buildInfoItem('隐患类别', pd['HIDDEN_CATEGORY_NAME'] ?? ''),
Divider(height: 1),
],),
_buildInfoItem('隐患类型', pd['HIDDENTYPE_NAME'] ?? ''),
Divider(height: 1),
@ -467,29 +472,13 @@ class _HiddenDangerAcceptancePageState extends State<HiddenDangerAcceptancePage>
GestureDetector(
onTap: () async {
DateTime? picked = await BottomDateTimePicker.showDate(context);
DateTime? picked = await BottomDateTimePicker.showDate(context, allowPast: false,);
if (picked != null) {
setState(() {
dataTime = DateFormat('yyyy-MM-dd HH:mm').format(picked);
});
}
// showDialog(
// context: context,
// builder:
// (_) => HDatePickerDialog(
// initialDate: DateTime.now(),
// onCancel: () => Navigator.of(context).pop(),
// onConfirm: (selected) {
// Navigator.of(context).pop();
// setState(() {
// // _selectData = selected;
// dataTime= DateFormat('yyyy-MM-dd').format(selected);
//
// });
// },
// ),
// );
},
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 0),
@ -563,7 +552,7 @@ class _HiddenDangerAcceptancePageState extends State<HiddenDangerAcceptancePage>
LoadingDialogHelper.show();
final data = await ApiService.addHazardAcceptance( type, miaoshu, dataTime,widget.item['HIDDEN_ID']);
final data = await ApiService.addHazardAcceptance( type, miaoshu, dataTime,widget.item['HIDDEN_ID'] ?? '');
if (data['result'] == 'success') {
String hiddenCheckId="";

View File

@ -159,7 +159,7 @@ class _EquipmentInspectionListPageState
return ListView.builder(
controller: _scrollController,
itemCount: _periodList.length,
itemCount: _equipList.length,
itemBuilder: (context, index) {
final period = _periodList[index];
final items = groupedItems[period] ?? [];
@ -298,7 +298,7 @@ class _EquipmentInspectionListPageState
),
labelColor: Colors.blue,
unselectedLabelColor: Colors.grey,
tabs: const [Tab(text: '待反馈'), Tab(text: '已反馈')],
tabs: const [Tab(text: '开始巡检'), Tab(text: '巡检记录')],
),
),

View File

@ -11,10 +11,8 @@ import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/tools/tools.dart';
class ImmediatelyInspection extends StatefulWidget {
const ImmediatelyInspection(this. id, {super.key});
const ImmediatelyInspection(this.id, {super.key});
final String id;
@ -23,13 +21,12 @@ class ImmediatelyInspection extends StatefulWidget {
}
class _ImmediatelyInspectionState extends State<ImmediatelyInspection> {
final TextEditingController _xunController = TextEditingController();
final TextEditingController _neiRongController = TextEditingController();
//
bool _isFault = false;
String dataTime="";
String dataTime = "";
List<String> _guZhangImages = [];
List<String> _xiuGaiImages = [];
@ -46,20 +43,27 @@ class _ImmediatelyInspectionState extends State<ImmediatelyInspection> {
children: [
Container(
color: Colors.white,
child: Column(children: [
child: Column(
children: [
ItemListWidget.singleLineTitleText(
label: '巡检人:',
isEditable: true,
isRequired: false,
controller: _xunController,
hintText: '请输入巡检人',
text: '',
),
const Divider(),
Padding(
padding: EdgeInsets.symmetric(horizontal: 15,vertical: 10),
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 10),
child: GestureDetector(
child: ItemListWidget.selectableLineTitleTextRightButton(label: '巡检日期', text: dataTime.isEmpty?
'请选择':dataTime??'', isEditable: true, isRequired: true,horizontalnum: 0),
child: ItemListWidget.selectableLineTitleTextRightButton(
label: '巡检日期',
text: dataTime.isEmpty ? '请选择' : dataTime ?? '',
isEditable: true,
isRequired: false,
horizontalnum: 0,
),
onTap: () async {
showDialog(
context: context,
@ -70,9 +74,9 @@ class _ImmediatelyInspectionState extends State<ImmediatelyInspection> {
onConfirm: (selected) {
Navigator.of(context).pop();
setState(() {
dataTime= DateFormat('yyyy-MM-dd').format(selected);
dataTime = DateFormat(
'yyyy-MM-dd',
).format(selected);
});
},
),
@ -85,29 +89,28 @@ class _ImmediatelyInspectionState extends State<ImmediatelyInspection> {
// isRight: true,
// ),
),
],
),
),
SizedBox(height: 15,),
SizedBox(height: 15),
Container(
color: Colors.white,
child: ItemListWidget.multiLineTitleTextField(
label: '巡检内容:',
isEditable: true,
isRequired: false,
controller: _neiRongController,
hintText: "(必填)",
text:'',
text: '',
),
),
SizedBox(height: 15,),
SizedBox(height: 15),
ListItemFactory.createYesNoSection(
title: '是否有故障',
horizontalPadding: 0,
horizontalPadding: 2,
groupValue: _isFault,
onChanged: (val) {
setState(() {
@ -118,7 +121,7 @@ class _ImmediatelyInspectionState extends State<ImmediatelyInspection> {
// if(_isFault)
// SizedBox(height: 15,),
if(_isFault)
if (_isFault)
RepairedPhotoSection(
horizontalPadding: 15,
title: "故障照片",
@ -130,16 +133,12 @@ class _ImmediatelyInspectionState extends State<ImmediatelyInspection> {
onMediaRemoved: (value) {
_guZhangImages.remove(value);
},
onChanged: (files) {
},
onAiIdentify: () {
},
onChanged: (files) {},
onAiIdentify: () {},
),
SizedBox(height:_isFault? 15:0,),
if(_isFault)
SizedBox(height: _isFault ? 15 : 0),
if (_isFault)
RepairedPhotoSection(
horizontalPadding: 15,
title: "故障处理后照片",
@ -151,15 +150,11 @@ class _ImmediatelyInspectionState extends State<ImmediatelyInspection> {
onMediaRemoved: (value) {
_xiuGaiImages.remove(value);
},
onChanged: (files) {
},
onAiIdentify: () {
},
onChanged: (files) {},
onAiIdentify: () {},
),
SizedBox(height:_isFault? 15:0,),
SizedBox(height: _isFault ? 15 : 0),
RepairedPhotoSection(
horizontalPadding: 15,
title: "巡检照片",
@ -171,14 +166,11 @@ class _ImmediatelyInspectionState extends State<ImmediatelyInspection> {
onMediaRemoved: (value) {
_xunJianImages.remove(value);
},
onChanged: (files) {
},
onAiIdentify: () {
},
onChanged: (files) {},
onAiIdentify: () {},
),
SizedBox(height:25,),
SizedBox(height: 25),
CustomButton(
text: "提交",
backgroundColor: Colors.blue,
@ -187,7 +179,7 @@ class _ImmediatelyInspectionState extends State<ImmediatelyInspection> {
_startInspection();
},
),
SizedBox(height:25,),
SizedBox(height: 25),
],
),
);
@ -195,79 +187,74 @@ class _ImmediatelyInspectionState extends State<ImmediatelyInspection> {
Future<void> _startInspection() async {
try {
String person=_xunController.text.trim();
if(person.isEmpty){
String person = _xunController.text.trim();
if (person.isEmpty) {
ToastUtil.showNormal(context, "请填巡检人");
return;
}
if(dataTime.isEmpty){
if (dataTime.isEmpty) {
ToastUtil.showNormal(context, "请选择巡检时间");
return;
}
String content=_neiRongController.text.trim();
if(content.isEmpty){
String content = _neiRongController.text.trim();
if (content.isEmpty) {
ToastUtil.showNormal(context, "请选巡检内容");
return;
}
if(_isFault&&_guZhangImages.isEmpty){
if (_isFault && _guZhangImages.isEmpty) {
ToastUtil.showNormal(context, "请上传故障照片");
return;
}
if(_isFault&&_xiuGaiImages.isEmpty){
if (_isFault && _xiuGaiImages.isEmpty) {
ToastUtil.showNormal(context, "请上传故障处理后照片");
return;
}
if(_xunJianImages.isEmpty){
if (_xunJianImages.isEmpty) {
ToastUtil.showNormal(context, "请上传巡检图片");
return;
}
LoadingDialogHelper.show(message: "提交中...");
for(int i=0;i<_guZhangImages.length;i++){
for (int i = 0; i < _guZhangImages.length; i++) {
allImagePaths.add(_guZhangImages[i]);
allImageTypes.add("24");
}
for(int m=0;m<_xiuGaiImages.length;m++){
for (int m = 0; m < _xiuGaiImages.length; m++) {
allImagePaths.add(_xiuGaiImages[m]);
allImageTypes.add("25");
}
for(int n=0;n<_xunJianImages.length;n++){
for (int n = 0; n < _xunJianImages.length; n++) {
allImagePaths.add(_xunJianImages[n]);
allImageTypes.add("26");
}
final formData = {
'SPECIALEQUIPMENT_ID': widget.id,
'CREATOR': SessionService.instance.username,
'ISFAULT': _isFault?"":"",
'ISFAULT': _isFault ? "" : "",
'INSPECTOR': person,
'INSPECTIONCONTENT': content,
'INSPECTIONTIME': dataTime,
'TYPES':allImageTypes.join(','),
'TYPES': allImageTypes.join(','),
"CORPINFO_ID": SessionService.instance.corpinfoId,
'USER_ID': SessionService.instance.loginUserId,
};
final result = await ApiService.startInspection(formData,allImagePaths);
final result = await ApiService.startInspection(formData, allImagePaths);
LoadingDialogHelper.hide();
if (result['result'] == 'success') {
setState(() {
ToastUtil.showNormal(context, "提交成功");
Navigator.pop(context);
});
}
} catch (e) {
@ -275,7 +262,4 @@ class _ImmediatelyInspectionState extends State<ImmediatelyInspection> {
print('Error fetching data: $e');
}
}
}

View File

@ -526,8 +526,7 @@ class _NfcCheckDangerDetailState extends State<NfcCheckDangerDetail> {
if (id.isEmpty) {
return true;
}
Map data = {'IMGFILES_ID': id};
final result = await ApiService.deleteNFCImage(data);
final result = await ApiService.onImageRemoved(id);
if (result['result'] == 'success') {
return true;
}else{

View File

@ -1,15 +1,9 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/pages/home/SafeCheck/CheckPersonSure/check_person_detail.dart';
import 'package:qhd_prevention/pages/home/SafeCheck/DangeCheck/safeCheck_assignment_detail_page.dart';
import 'package:qhd_prevention/pages/home/SafeCheck/Start/safeCheck_start_detail.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/dh_work_detai/hotwork_apply_detail.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/tools/tools.dart';
import 'package:qhd_prevention/customWidget/bottom_picker.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/search_bar_widget.dart';
import 'package:qhd_prevention/http/ApiService.dart';
class SafecheckAssignmentList extends StatefulWidget {

View File

@ -77,7 +77,7 @@ class _SafecheckDangerDetailState extends State<SafecheckDangerDetail> {
inspectedForm = {
'INSPECTION_EXPLAIN_ID': '', // ID
'INSPECTION_STATUS': '3',
'INSPECTION_ID': widget.INSPECTION_ID, // ID
'INSPECTION_ID': widget.INSPECTION_ID ?? '', // ID
'INSPECTED_EXPLAIN': '', //
'INSPECTED_EXPLAIN_FILENAME': '', //
'INSPECTED_SITEUSER_SIGN_IMG': '', //
@ -261,11 +261,11 @@ class _SafecheckDangerDetailState extends State<SafecheckDangerDetail> {
),
ItemListWidget.OneRowImageTitle(
label: '被检查单位现场负责人签字',
text: form['INSPECTED_SITEUSER_SIGN_TIME'],
text: form['INSPECTED_SITEUSER_SIGN_TIME'] ?? '',
onTapCallBack: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
imgPath: form['INSPECTED_SITEUSER_SIGN_IMG'],
imgPath: form['INSPECTED_SITEUSER_SIGN_IMG'] ?? '',
),
],
),

View File

@ -732,7 +732,7 @@ class _SafecheckStartDetailState extends State<SafecheckStartDetail> {
ItemListWidget.multiLineTitleTextField(
label: '检查人意见:',
isEditable: false,
text: item['opinion'],
text: item['opinion'] ?? '',
),
const Divider(),
ItemListWidget.OneRowImageTitle(
@ -750,7 +750,7 @@ class _SafecheckStartDetailState extends State<SafecheckStartDetail> {
ItemListWidget.multiLineTitleTextField(
label: '被检查单位现场负责人意见:',
isEditable: false,
text: item['INSPECTED_EXPLAIN'],
text: item['INSPECTED_EXPLAIN'] ?? '',
),
if (FormUtils.hasValue(form, 'INSPECTED_EXPLAIN'))
ItemListWidget.multiLineTitleTextField(
@ -761,11 +761,11 @@ class _SafecheckStartDetailState extends State<SafecheckStartDetail> {
if (form['INSPECTION_STATUS'] == '3')
ItemListWidget.OneRowImageTitle(
label: '检查人签字',
text: form['INSPECTED_SITEUSER_SIGN_TIME'],
text: form['INSPECTED_SITEUSER_SIGN_TIME'] ?? '',
onTapCallBack: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
imgPath: item['INSPECTED_SITEUSER_SIGN_IMG'],
imgPath: item['INSPECTED_SITEUSER_SIGN_IMG'] ?? '',
),
],
),
@ -1028,7 +1028,7 @@ class _SafecheckStartDetailState extends State<SafecheckStartDetail> {
if (picked != null) {
setState(() {
form['INSPECTION_TIME_START'] = DateFormat(
'yyyy-MM-dd HH:mm',
'yyyy-MM-dd HH:mm:ss',
).format(picked);
});
FocusHelper.clearFocus(context);
@ -1048,7 +1048,7 @@ class _SafecheckStartDetailState extends State<SafecheckStartDetail> {
if (picked != null) {
setState(() {
form['INSPECTION_TIME_END'] = DateFormat(
'yyyy-MM-dd HH:mm',
'yyyy-MM-dd HH:mm:ss',
).format(picked);
});
FocusHelper.clearFocus(context);

View File

@ -279,9 +279,12 @@ class _SafecheckStartListPageState extends State<SafecheckStartListPage> {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"检查时间: ${item['INSPECTION_TIME_START'] ?? ''}${item['INSPECTION_TIME_END'] ?? ''}",
Flexible(
child: Text(
"检查时间: ${item['INSPECTION_TIME_START'] ?? ''}${item['INSPECTION_TIME_END'] ?? ''}",maxLines: 2,overflow: TextOverflow.ellipsis,
),
),
],
),
const SizedBox(height: 8),

View File

@ -385,7 +385,7 @@ class _HomeDangerPageState extends State<HomeDangerPage>
Future<void> _goScan() async {
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (_) => ScanPage()),
MaterialPageRoute(builder: (_) => ScanPage(totalList: [])),
);
dynamic item;

View File

@ -5,6 +5,8 @@ import 'package:flutter/material.dart';
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
import 'package:qhd_prevention/customWidget/promise/promise_page.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/pages/home/scan_page.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/services/auth_service.dart';
import 'package:qhd_prevention/tools/update/update_dialogs.dart';
import 'package:shared_preferences/shared_preferences.dart';
@ -33,13 +35,18 @@ class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
_HomePageState createState() => _HomePageState();
HomePageState createState() => HomePageState();
}
class _HomePageState extends State<HomePage> {
class HomePageState extends State<HomePage> {
int _eight_work_count = 0;
int _safetyEnvironmentalInspection = 0;
void startScan() {
Navigator.push(
context,
MaterialPageRoute(builder: (_) => ScanPage(totalList: totalList)),
);
}
// key
static const String _hiddenCacheKey = 'hidden_roll_cache';
@ -59,7 +66,7 @@ class _HomePageState extends State<HomePage> {
return '';
}
}
List totalList = [];
///
List<Map<String, dynamic>> buttonInfos = [
{
@ -74,7 +81,7 @@ class _HomePageState extends State<HomePage> {
},
{
"icon": "assets/icon-apps/home-risk.png",
"title": "风险",
"title": "风险",
"unreadCount": 0,
},
{"icon": "assets/icon-apps/home-fl.png", "title": "法律法规", "unreadCount": 0},
@ -109,7 +116,7 @@ class _HomePageState extends State<HomePage> {
"title": "安全例会",
"unreadCount": 0,
},
{"icon": "assets/icon-apps/home-xj.png", "title": "燃气巡检", "unreadCount": 0},
// {"icon": "assets/icon-apps/home-xj.png", "title": "燃气巡检", "unreadCount": 0},
];
///
@ -182,6 +189,17 @@ 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();
if (FormUtils.hasValue(result, 'pd')) {
//
@ -573,7 +591,7 @@ class _HomePageState extends State<HomePage> {
children: [
Image.asset(iconPath, width: 40, height: 40),
const SizedBox(height: 5),
Text(label, style: const TextStyle(fontSize: 14)),
Text(label, style: const TextStyle(fontSize: 13)),
],
),
),
@ -596,7 +614,7 @@ class _HomePageState extends State<HomePage> {
),
child: Center(
child: Text(
unreadCount > 99 ? '99+' : '$unreadCount',
'$unreadCount',
style: const TextStyle(
color: Colors.white,
fontSize: 11,
@ -715,7 +733,7 @@ class _HomePageState extends State<HomePage> {
Text(
title,
style: const TextStyle(
fontSize: 16,
fontSize: 14,
fontWeight: FontWeight.bold,
),
maxLines: 1,
@ -724,7 +742,7 @@ class _HomePageState extends State<HomePage> {
const SizedBox(height: 4),
Text(
subtitle,
style: const TextStyle(fontSize: 14, color: Colors.black),
style: const TextStyle(fontSize: 13, color: Colors.black),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),

View File

@ -1,14 +1,20 @@
import 'dart:convert';
import 'dart:io';
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/pages/home/study/face_ecognition_page.dart';
import 'package:qhd_prevention/pages/home/work/risk_list_page.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:image_picker/image_picker.dart';
import 'package:qhd_prevention/tools/tools.dart';
class ScanPage extends StatefulWidget {
const ScanPage({Key? key}) : super(key: key);
// const ScanPage({Key? key}) : super(key: key,);
const ScanPage({super.key, required this.totalList});
final List totalList;
@override
State<ScanPage> createState() => _ScanPageState();
}
@ -47,24 +53,77 @@ class _ScanPageState extends State<ScanPage> {
}
}
void _showResult(String code) {
Navigator.of(context).pop(code);
// showDialog(
// context: context,
// builder: (_) => AlertDialog(
// title: const Text('扫描结果'),
// content: Text(code),
// actions: [
// TextButton(
// onPressed: () {
// Navigator.of(context).pop(code);
// _controller.start(); //
// },
// child: const Text('确定'),
// ),
// ],
// ),
// );
void _showResult(String result) {
try {
if (result.contains('STUDENT_ID')) {
final Map<String, dynamic> stuInfo = jsonDecode(result);
print('stuInfo: $stuInfo');
// res.result.split("@")[1]
String? stuId;
final parts = result.split('@');
if (parts.length > 1) stuId = parts[1];
// userId = res.result.substring(0, res.result.indexOf('%_face'))
String? userId;
final idx = result.indexOf('%_face');
if (idx >= 0) {
userId = result.substring(0, idx);
}
print('stuId: $stuId, userId: $userId');
// id stuInfo.USER_ID
if (SessionService.instance.loginUserId == stuInfo['USER_ID']) {
goToFace(stuInfo);
} else {
ToastUtil.showNormal(context, '当前登录账号不匹配,无法扫码学习,请切换至正确的账号后再尝试人脸识别!');
return;
}
} else {
// STUDENT_ID id
bool found = false;
final listId = result;
for (final item in widget.totalList) {
if (item['LISTMANAGER_ID'] == listId) {
found = true;
goToList(listId: item['LISTMANAGER_ID'], listName: item['NAME']);
break;
}
}
if (!found) {
ToastUtil.showError(context, '无法检查该清单');
}
}
} catch (e, st) {
//
print('handleScanResult error: $e\n$st');
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('扫码处理失败: ${e.toString()}')),
);
}
}
//
void goToFace(Map<String, dynamic> stuInfo) async {
print('navigate to face with $stuInfo');
final passed = await pushPage<bool>(
FaceRecognitionPage(studentId: stuInfo['STUDENT_ID'], mode: FaceMode.auto),
context,
);
if (passed == true) {
ToastUtil.showSuccess(context, '验证成功');
} else {
ToastUtil.showError(context, '验证失败');
}
}
//
void goToList({required String listId, required String listName}) {
print('navigate to list: $listId, name: $listName');
Navigator.pop(context,Animation);
pushPage(RiskListPage(1, listId), context);
}
@override

View File

@ -184,12 +184,12 @@ class _FaceRecognitionPageState extends State<FaceRecognitionPage> {
children: [
Text(
'请将人脸置于圆圈内',
style: const TextStyle(fontSize: 18, color: Colors.black87),
style: const TextStyle(fontSize: 16, color: Colors.black87),
textAlign: TextAlign.center,
),
Text(
_errMsg,
style: const TextStyle(fontSize: 18, color: Colors.red),
style: const TextStyle(fontSize: 14, color: Colors.red),
textAlign: TextAlign.center,
),
const SizedBox(height: 20),

View File

@ -97,7 +97,7 @@ class _StudyDetailPageState extends State<StudyDetailPage>
title: '温馨提示',
content: '重要提醒:尊敬的用户,根据规定我们会在您学习过程中多次进行人脸识别认证,为了保护您的隐私请您在摄像设备视野内确保衣冠整齐。',
cancelText: '取消',
confirmText: '同意并继续'
confirmText: '同意并继续',
);
if (ok) {}
}
@ -113,9 +113,7 @@ class _StudyDetailPageState extends State<StudyDetailPage>
_faceTime = int.tryParse(pd['FACE_TIME']?.toString() ?? '10') ?? 10;
_videoList = List.from(pd['VIDEOLIST'] ?? []);
// set initial face time
if (pd['ISFACE'] == '1') {
await ApiService.fnSetUserFaceTime(_faceTime);
}
// compute percent
for (var item in _videoList) {
if (item['nodes'] is List && (item['nodes'] as List).isNotEmpty) {
@ -210,16 +208,35 @@ class _StudyDetailPageState extends State<StudyDetailPage>
Future<void> _navigateFaceIfNeeded(FutureOr<void> Function() onPass) async {
if (_info?['ISFACE'] == '1') {
LoadingDialogHelper.show();
final resData = await ApiService.fnGetUserFace();
LoadingDialogHelper.hide();
final pd_data = resData['pd'];
if (FormUtils.hasValue(pd_data, 'USERAVATARURL')) {
final passed = await pushPage<bool>(
FaceRecognitionPage(studentId: widget.studentId, mode: FaceMode.auto),
context,
);
if (passed == true) {
await ApiService.fnSetUserFaceTime(_faceTime);
await onPass();
} else {
ScaffoldMessenger.of(
ToastUtil.showError(context, '人脸验证未通过,无法继续');
}
} else {
final ok = await CustomAlertDialog.showConfirm(
context,
).showSnackBar(const SnackBar(content: Text('人脸验证未通过,无法继续')));
title: '温馨提示',
content: '您当前还未进行人脸认证,请先进行认证',
cancelText: '取消',
);
if (ok) {
await pushPage(
const FaceRecognitionPage(studentId: '', mode: FaceMode.manual),
context,
);
}
}
} else {
await onPass();
@ -290,9 +307,11 @@ class _StudyDetailPageState extends State<StudyDetailPage>
if (secondsSinceLast >= _uploadIntervalSeconds && !_endReported) {
_lastReported = pos;
// _ongoingSubmit
_ongoingSubmit = (_ongoingSubmit ?? Future.value()).then((_) {
_ongoingSubmit = (_ongoingSubmit ?? Future.value())
.then((_) {
return _submitPlayTime(end: false, seconds: pos.inSeconds);
}).whenComplete(() {
})
.whenComplete(() {
//
_ongoingSubmit = null;
});
@ -305,9 +324,11 @@ class _StudyDetailPageState extends State<StudyDetailPage>
if (endedOrClose && !_endReported) {
_endReported = true;
final finalSeconds = (dur.inMilliseconds / 1000.0).ceil();
_ongoingSubmit = (_ongoingSubmit ?? Future.value()).then((_) async {
_ongoingSubmit = (_ongoingSubmit ?? Future.value())
.then((_) async {
await _submitPlayTime(end: true, seconds: finalSeconds);
}).whenComplete(() {
})
.whenComplete(() {
_ongoingSubmit = null;
// 退 route退
_exitTopRouteIfPresent();
@ -350,20 +371,23 @@ class _StudyDetailPageState extends State<StudyDetailPage>
// RESOURCETIME
final resTraw = pd['RESOURCETIME'];
final resT = (resTraw is num)
final resT =
(resTraw is num)
? resTraw.toDouble()
: double.tryParse('$resTraw') ?? seconds.toDouble();
// videoTime
final videoTimeRaw = _currentVideoData!['VIDEOTIME'];
final videoTime = (videoTimeRaw is String)
final videoTime =
(videoTimeRaw is String)
? double.tryParse(videoTimeRaw) ?? 1.0
: (videoTimeRaw is num ? videoTimeRaw.toDouble() : 1.0);
final comp = pd['PLAYCOUNT'] != null && pd['PLAYCOUNT'] > 0;
final pctDouble = comp ? 100.0 : ((resT / (videoTime > 0 ? videoTime : 1.0)) * 100.0);
final pct = pctDouble.clamp(0.0, 100.0).toDouble().round();
final pctDouble =
comp ? 100.0 : ((resT / (videoTime > 0 ? videoTime : 1.0)) * 100.0);
final pct = (pctDouble.clamp(0.00, 100.00) * 100).round() / 100;
final str = '${pct}%';
if (mounted) {
@ -386,7 +410,7 @@ class _StudyDetailPageState extends State<StudyDetailPage>
title: '温馨提示',
content: '当前任务内所有课程均已学完,是否直接参加考试?',
cancelText: '',
confirmText: ''
confirmText: '',
);
if (ok) {
_startExam(resData);
@ -459,14 +483,16 @@ class _StudyDetailPageState extends State<StudyDetailPage>
}
}
}
void _startFaceTimer() {
_faceTimer = Timer.periodic(Duration(seconds: _faceTime), (_) async {
final res = await ApiService.fnGetUserFaceTime(_faceTime);
final res = await ApiService.fnGetUserFaceTime();
final isPlaying = _videoController?.value.isPlaying == true;
final isVideo = _currentVideoData?['IS_VIDEO'] == 0;
final needAuth = FormUtils.hasValue(res, 'data');
if (isPlaying && isVideo && needAuth) {
if (isPlaying && isVideo && !needAuth) {
_exitTopRouteIfPresent();
_videoController!.pause();
_videoController!.removeListener(_onTimeUpdate);
await _showFaceAuthOnce();
@ -475,17 +501,66 @@ class _StudyDetailPageState extends State<StudyDetailPage>
}
Future<void> _showFaceAuthOnce() async {
// cancel
_faceTimer?.cancel();
_faceTimer = null;
final passed = await pushPage<bool>(
FaceRecognitionPage(studentId: widget.studentId, mode: FaceMode.auto),
context,
);
if (passed == true) {
await _videoController?.play();
await ApiService.fnSetUserFaceTime(_faceTime);
// listener
try {
// controller
if (_videoController != null && _videoController!.value.isInitialized) {
// listener
try {
_videoController!.removeListener(_onTimeUpdate);
} catch (_) {}
//
try {
final currentPos = _videoController!.value.position;
_lastReported = currentPos;
debugPrint('Face auth passed — resetting _lastReported to $currentPos');
} catch (_) {
_lastReported = Duration.zero;
}
// listener
await _videoController!.play();
_videoController!.addListener(_onTimeUpdate);
} else {
// controller UI
debugPrint('Face auth passed but _videoController is null or not initialized');
}
setState(() {});
} catch (e, st) {
debugPrint('Error resuming playback after face auth: $e\n$st');
}
//
_startFaceTimer();
} else {
ToastUtil.showError(context, '人脸验证未通过,无法继续');
if (_videoController != null) {
try {
_videoController?.removeListener(_onTimeUpdate);
} catch (_) {}
try {
_videoController?.dispose();
} catch (_) {}
_videoController = null;
}
_faceTimer?.cancel();
setState(() {
});
}
}
Widget _buildVideoOrCover(double containerW, double containerH) {
final c = _videoController;
if (c != null && c.value.isInitialized) {
@ -524,7 +599,7 @@ class _StudyDetailPageState extends State<StudyDetailPage>
child: Column(
children: [
_buildVideoOrCover(screenWidth(context), 250),
const SizedBox(height: 5,),
const SizedBox(height: 5),
Container(
width: double.infinity,
color: Colors.white,
@ -541,12 +616,14 @@ class _StudyDetailPageState extends State<StudyDetailPage>
Container(
color: Colors.white,
child: TabBar(
indicatorColor: Colors.blue,
labelStyle: const TextStyle(
fontSize: 16,
color: Colors.black87,
),
controller: _tabController,
labelStyle: const TextStyle(fontSize: 16),
indicator: const UnderlineTabIndicator(
borderSide: BorderSide(width: 3.0, color: Colors.blue),
insets: EdgeInsets.symmetric(horizontal: 0.0),
),
labelColor: Colors.blue,
unselectedLabelColor: Colors.grey,
tabs: const [Tab(text: '课件目录'), Tab(text: '详情')],
),
),
@ -640,15 +717,18 @@ class _StudyDetailPageState extends State<StudyDetailPage>
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
Expanded(
child: Text(
"进度:${m['percent']}",
style: const TextStyle(color: Colors.blue),
),
),
if (m['IS_VIDEO'] == 0) ...[
Text(secondsCount(m['VIDEOTIME'])),
const SizedBox(width: 6),
const SizedBox(width: 20),
const Icon(Icons.play_circle, color: Colors.blue),
],
SizedBox(width: 20),
CustomButton(
onPressed:
() => pushPage(

View File

@ -21,7 +21,7 @@ class ItemListWidget {
TextEditingController? controller, // 使
String? text, //
String hintText = '请输入',
double fontSize = 15, //
double fontSize = 14, //
bool isRequired = true,
bool strongRequired = false,
ValueChanged<String>? onChanged,
@ -90,7 +90,7 @@ class ItemListWidget {
required bool isEditable, //
TextEditingController? controller, // 使
String? text, //
double fontSize = 15, //
double fontSize = 14, //
double height = 110, //
bool isRequired = true,
String hintText = '请输入',
@ -164,7 +164,7 @@ class ItemListWidget {
required bool isEditable, //
required String text, //
VoidCallback? onTap, //
double fontSize = 15, //
double fontSize = 14, //
bool isClean = false,
VoidCallback? onTapClean, //
bool isRequired = true,
@ -245,7 +245,7 @@ class ItemListWidget {
required bool isEditable,
required String text,
VoidCallback? onTap,
double fontSize = 15,
double fontSize = 14,
bool isClean = false,
VoidCallback? onTapClean,
bool isRequired = true,
@ -334,7 +334,7 @@ class ItemListWidget {
required String text, //
TextEditingController? controller, //
VoidCallback? onTap, //
double fontSize = 15, //
double fontSize = 14, //
double row2Height = 80, //
bool isRequired = true,
}) {
@ -426,7 +426,7 @@ class ItemListWidget {
required VoidCallback? onTap, //
String buttonText = '选择其他',
required String hintText,
double fontSize = 15, //
double fontSize = 14, //
double row2Height = 80, //
bool isRequired = true,
}) {
@ -517,7 +517,7 @@ class ItemListWidget {
required String label, //
required String text, //
required VoidCallback? onTap, //
double fontSize = 15, //
double fontSize = 14, //
String buttonText = '分析详情'
}) {
return Container(
@ -572,7 +572,7 @@ class ItemListWidget {
required String label, //
required String buttonText, //
required VoidCallback onTap, //
double fontSize = 15, //
double fontSize = 14, //
Color btnColor = Colors.blue,
bool isRequired = false,
}) {
@ -610,7 +610,7 @@ class ItemListWidget {
static Widget OneRowImageTitle({
required String label, //
required String imgPath, //
double fontSize = 15, //
double fontSize = 14, //
Color btnColor = Colors.blue,
bool isRequired = false,
String text = '',
@ -663,7 +663,7 @@ class ItemListWidget {
required String title, //
required List<dynamic>? imageUrls,
double row2Height = 80, //
double fontSize = 15, //
double fontSize = 14, //
void Function(String)? onTapCallBack,
bool isRequired = true,
}) {
@ -742,7 +742,7 @@ class ItemListWidget {
TextEditingController? controller, //
required VoidCallback? onTap, //
required String hintText,
double fontSize = 15, //
double fontSize = 14, //
double row2Height = 80, //
bool isRequired = true,
}) {

View File

@ -329,6 +329,9 @@ if (path != null) {
.toList(),
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere((e) => e.localPath == path);
_onImageRemoved(item);

View File

@ -215,6 +215,12 @@ class _HotWorkDetailFormWidgetState extends State<HotWorkDetailFormWidget> {
cleanText: '清除监控',
isRequired: pd['WORK_LEVEL'] == '特级',
isEditable: widget.isEditable,
onTapClean: () {
setState(() {
pd['VIDEONAME'] = '';
pd['VIDEOMANAGER_ID'] = '';
});
},
onTap: widget.onChooseVideoManager ?? () {},
text: pd['VIDEONAME'] ?? '',
),

View File

@ -182,6 +182,8 @@ class _HotworkAqglDetailState extends State<HotworkAqglDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -212,6 +212,8 @@ class _HotworkAqjdDetailState extends State<HotworkAqjdDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();
@ -322,6 +324,9 @@ class _HotworkAqjdDetailState extends State<HotworkAqjdDetail> {
mediaType: MediaType.image,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere(
(e) => e.localPath == path,

View File

@ -184,6 +184,8 @@ class _HotworkDbbzDetailState extends State<HotworkDbbzDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -274,7 +274,7 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
if (picked != null) {
setState(() {
pd['WORK_EXPECTED_START_TIME'] = DateFormat(
'yyyy-MM-dd HH:mm',
'yyyy-MM-dd HH:mm:ss',
).format(picked);
///
@ -298,7 +298,7 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
if (picked != null) {
setState(() {
pd['WORK_EXPECTED_END_TIME'] = DateFormat(
'yyyy-MM-dd HH:mm',
'yyyy-MM-dd HH:mm:ss',
).format(picked);
});
}
@ -633,7 +633,7 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
ToastUtil.showSuccess(context, status == '1' ? '提交成功' : '已暂存');
Navigator.of(context).pop(true);
} else {
ToastUtil.showSuccess(context, '提交失败');
ToastUtil.showError(context, '提交失败');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -182,6 +182,8 @@ class _HotworkDhspDetailState extends State<HotworkDhspDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -174,6 +174,8 @@ class _HotworkJhrDetailState extends State<HotworkJhrDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -176,6 +176,8 @@ class _HotworkJsjdDetailState extends State<HotworkJsjdDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -221,6 +221,8 @@ class _HotworkJszyDetailState extends State<HotworkJszyDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();
@ -339,7 +341,7 @@ class _HotworkJszyDetailState extends State<HotworkJszyDetail> {
if (picked != null) {
setState(() {
endTime = DateFormat(
'yyyy-MM-dd HH:mm',
'yyyy-MM-dd HH:mm:ss',
).format(picked);
});
}

View File

@ -193,6 +193,8 @@ class _HotworkKszyDetailState extends State<HotworkKszyDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();
@ -311,7 +313,7 @@ class _HotworkKszyDetailState extends State<HotworkKszyDetail> {
if (picked != null) {
setState(() {
startTime = DateFormat(
'yyyy-MM-dd HH:mm',
'yyyy-MM-dd HH:mm:ss',
).format(picked);
});
}

View File

@ -320,7 +320,7 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
} else {
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {

View File

@ -182,6 +182,8 @@ class _HotworkSzdwDetailState extends State<HotworkSzdwDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -243,6 +243,8 @@ class _HotworkYsgdDetailState extends State<HotworkYsgdDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();
@ -369,7 +371,7 @@ class _HotworkYsgdDetailState extends State<HotworkYsgdDetail> {
if (picked != null) {
setState(() {
startTime = DateFormat(
'yyyy-MM-dd HH:mm',
'yyyy-MM-dd HH:mm:ss',
).format(picked);
});
FocusHelper.clearFocus(context);
@ -385,6 +387,9 @@ class _HotworkYsgdDetailState extends State<HotworkYsgdDetail> {
horizontalPadding: 0,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere(
(e) => e.localPath == path,

View File

@ -182,6 +182,8 @@ class _HotworkZyfzDetailState extends State<HotworkZyfzDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -364,6 +364,12 @@ class _CutroadDetailFormWidgetState extends State<CutroadDetailFormWidget> {
label: '视频监控:',
isClean: widget.isEditable,
cleanText: '清除监控',
onTapClean: () {
setState(() {
pd['VIDEONAME'] = '';
pd['VIDEOMANAGER_ID'] = '';
});
},
isRequired: false,
isEditable: widget.isEditable,
onTap: widget.onChooseVideoManager ?? () {},

View File

@ -211,6 +211,8 @@ class _CutroadAqjdDetailState extends State<CutroadAqjdDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();
@ -315,6 +317,9 @@ class _CutroadAqjdDetailState extends State<CutroadAqjdDetail> {
mediaType: MediaType.image,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere(
(e) => e.localPath == path,

View File

@ -450,7 +450,7 @@ class _CutroadApplyDetailState extends State<CutroadApplyDetail> {
if (picked != null) {
setState(() {
pd['WORK_EXPECTED_START_TIME'] = DateFormat(
'yyyy-MM-dd HH:mm',
'yyyy-MM-dd HH:mm:ss',
).format(picked);
///
@ -474,7 +474,7 @@ class _CutroadApplyDetailState extends State<CutroadApplyDetail> {
if (picked != null) {
setState(() {
pd['WORK_EXPECTED_END_TIME'] = DateFormat(
'yyyy-MM-dd HH:mm',
'yyyy-MM-dd HH:mm:ss',
).format(picked);
});
}

View File

@ -303,7 +303,7 @@ setState(() {
if (picked != null) {
setState(() {
startTime = DateFormat(
'yyyy-MM-dd HH:mm',
'yyyy-MM-dd HH:mm:ss',
).format(picked);
});
}

View File

@ -362,6 +362,9 @@ setState(() {
horizontalPadding: 0,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere((e) => e.localPath == path);
_onImageRemoved(item);

View File

@ -328,6 +328,9 @@ setState(() {
horizontalPadding: 0,
isRequired: true,
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere((e) => e.localPath == path);
_onImageRemoved(item);

View File

@ -411,6 +411,12 @@ class _BreakgroundDetailFormWidgetState
label: '视频监控:',
isClean: widget.isEditable,
cleanText: '清除监控',
onTapClean: () {
setState(() {
pd['VIDEONAME'] = '';
pd['VIDEOMANAGER_ID'] = '';
});
},
isRequired: false,
isEditable: widget.isEditable,
onTap: widget.onChooseVideoManager ?? () {},

View File

@ -211,6 +211,8 @@ class _BreakgroundAqjdDetailState extends State<BreakgroundAqjdDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();
@ -315,6 +317,9 @@ class _BreakgroundAqjdDetailState extends State<BreakgroundAqjdDetail> {
mediaType: MediaType.image,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere(
(e) => e.localPath == path,

View File

@ -226,7 +226,7 @@ class _BreakgroundApplyDetailState extends State<BreakgroundApplyDetail> {
if (picked != null) {
setState(() {
pd['WORK_EXPECTED_START_TIME'] = DateFormat(
'yyyy-MM-dd HH:mm',
'yyyy-MM-dd HH:mm:ss',
).format(picked);
///
@ -250,7 +250,7 @@ class _BreakgroundApplyDetailState extends State<BreakgroundApplyDetail> {
if (picked != null) {
setState(() {
pd['WORK_EXPECTED_END_TIME'] = DateFormat(
'yyyy-MM-dd HH:mm',
'yyyy-MM-dd HH:mm:ss',
).format(picked);
});
}

View File

@ -182,6 +182,8 @@ class _BreakgroundDzzhDetailState extends State<BreakgroundDzzhDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -176,6 +176,8 @@ class _BreakgroundJhrDetailState extends State<BreakgroundJhrDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -176,6 +176,8 @@ class _BreakgroundJsjdDetailState extends State<BreakgroundJsjdDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -201,6 +201,8 @@ class _BreakgroundJszyDetailState extends State<BreakgroundJszyDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();
@ -313,7 +315,7 @@ class _BreakgroundJszyDetailState extends State<BreakgroundJszyDetail> {
if (picked != null) {
setState(() {
endTime = DateFormat(
'yyyy-MM-dd HH:mm',
'yyyy-MM-dd HH:mm:ss',
).format(picked);
});
}

View File

@ -184,6 +184,8 @@ class _BreakgroundKszyDetailState extends State<BreakgroundKszyDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();
@ -302,7 +304,7 @@ class _BreakgroundKszyDetailState extends State<BreakgroundKszyDetail> {
if (picked != null) {
setState(() {
startTime = DateFormat(
'yyyy-MM-dd HH:mm',
'yyyy-MM-dd HH:mm:ss',
).format(picked);
});
}

View File

@ -181,6 +181,8 @@ class _BreakgroundShbmDetailState extends State<BreakgroundShbmDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -181,6 +181,8 @@ class _BreakgroundSpbmDetailState extends State<BreakgroundSpbmDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -175,6 +175,8 @@ class _BreakgroundSsrDetailState extends State<BreakgroundSsrDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -319,6 +319,8 @@ class _BreakgroundSetSafeDetailState extends State<BreakgroundSetSafeDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -182,6 +182,8 @@ class _BreakgroundSzdwDetailState extends State<BreakgroundSzdwDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -243,6 +243,8 @@ class _BreakgroundYsgdDetailState extends State<BreakgroundYsgdDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();
@ -363,7 +365,7 @@ class _BreakgroundYsgdDetailState extends State<BreakgroundYsgdDetail> {
if (picked != null) {
setState(() {
startTime = DateFormat(
'yyyy-MM-dd HH:mm',
'yyyy-MM-dd HH:mm:ss',
).format(picked);
});
FocusHelper.clearFocus(context);
@ -379,6 +381,9 @@ class _BreakgroundYsgdDetailState extends State<BreakgroundYsgdDetail> {
horizontalPadding: 0,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere(
(e) => e.localPath == path,

View File

@ -182,6 +182,8 @@ class _BreakgroundZyfzDetailState extends State<BreakgroundZyfzDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -202,6 +202,8 @@ class _BreakgroundZyrDetailState extends State<BreakgroundZyrDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();
@ -351,6 +353,9 @@ class _BreakgroundZyrDetailState extends State<BreakgroundZyrDetail> {
isShowNum: false,
isRequired: true,
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = workImages.firstWhere(
(e) => e.localPath == path,

View File

@ -393,6 +393,12 @@ class _HoistworkDetailFormWidgetState extends State<HoistWorkDetailFormWidget> {
label: '视频监控:',
isClean: widget.isEditable,
cleanText: '清除监控',
onTapClean: () {
setState(() {
pd['VIDEONAME'] = '';
pd['VIDEOMANAGER_ID'] = '';
});
},
isRequired: false,
isEditable: widget.isEditable,
onTap: widget.onChooseVideoManager ?? () {},

View File

@ -211,6 +211,8 @@ class _HoistworkAqjdDetailState extends State<HoistworkAqjdDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();
@ -315,6 +317,9 @@ class _HoistworkAqjdDetailState extends State<HoistworkAqjdDetail> {
mediaType: MediaType.image,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere(
(e) => e.localPath == path,

View File

@ -188,7 +188,7 @@ class _HoistworkApplyDetailState extends State<HoistworkApplyDetail> {
if (picked != null) {
setState(() {
pd['WORK_EXPECTED_START_TIME'] = DateFormat(
'yyyy-MM-dd HH:mm',
'yyyy-MM-dd HH:mm:ss',
).format(picked);
///
@ -212,7 +212,7 @@ class _HoistworkApplyDetailState extends State<HoistworkApplyDetail> {
if (picked != null) {
setState(() {
pd['WORK_EXPECTED_END_TIME'] = DateFormat(
'yyyy-MM-dd HH:mm',
'yyyy-MM-dd HH:mm:ss',
).format(picked);
});
}

View File

@ -182,6 +182,8 @@ class _HoistworkDzzhDetailState extends State<HoistworkDzzhDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -176,6 +176,8 @@ class _HoistworkJhrDetailState extends State<HoistworkJhrDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -176,6 +176,8 @@ class _HoistworkJsjdDetailState extends State<HoistworkJsjdDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -201,6 +201,8 @@ class _HoistworkJszyDetailState extends State<HoistworkJszyDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();
@ -313,7 +315,7 @@ class _HoistworkJszyDetailState extends State<HoistworkJszyDetail> {
if (picked != null) {
setState(() {
endTime = DateFormat(
'yyyy-MM-dd HH:mm',
'yyyy-MM-dd HH:mm:ss',
).format(picked);
});
}

View File

@ -184,6 +184,8 @@ class _HoistworkKszyDetailState extends State<HoistworkKszyDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();
@ -302,7 +304,7 @@ class _HoistworkKszyDetailState extends State<HoistworkKszyDetail> {
if (picked != null) {
setState(() {
startTime = DateFormat(
'yyyy-MM-dd HH:mm',
'yyyy-MM-dd HH:mm:ss',
).format(picked);
});
}

View File

@ -181,6 +181,8 @@ class _HoistworkShbmDetailState extends State<HoistworkShbmDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -181,6 +181,8 @@ class _HoistworkSpbmDetailState extends State<HoistworkSpbmDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -175,6 +175,8 @@ class _HoistworkSsrDetailState extends State<HoistworkSsrDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -318,6 +318,8 @@ class _HoistworkSetSafeDetailState extends State<HoistworkSetSafeDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -182,6 +182,8 @@ class _HoistworkSzdwDetailState extends State<HoistworkSzdwDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -243,6 +243,8 @@ class _HoistworkYsgdDetailState extends State<HoistworkYsgdDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();
@ -363,7 +365,7 @@ class _HoistworkYsgdDetailState extends State<HoistworkYsgdDetail> {
if (picked != null) {
setState(() {
startTime = DateFormat(
'yyyy-MM-dd HH:mm',
'yyyy-MM-dd HH:mm:ss',
).format(picked);
});
FocusHelper.clearFocus(context);
@ -379,6 +381,9 @@ class _HoistworkYsgdDetailState extends State<HoistworkYsgdDetail> {
horizontalPadding: 0,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere(
(e) => e.localPath == path,

View File

@ -182,6 +182,8 @@ class _HoistworkZyfzDetailState extends State<HoistworkZyfzDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -175,6 +175,8 @@ class _HoistworkZyrDetailState extends State<HoistworkZyrDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -182,6 +182,12 @@ class _HighWorkDetailFormWidgetState extends State<HighWorkDetailFormWidget> {
label: '视频监控:',
isClean: widget.isEditable,
cleanText: '清除监控',
onTapClean: () {
setState(() {
pd['VIDEONAME'] = '';
pd['VIDEOMANAGER_ID'] = '';
});
},
isRequired: false,
isEditable: widget.isEditable,
onTap: widget.onChooseVideoManager ?? () {},

View File

@ -211,6 +211,8 @@ class _HighworkAqjdDetailState extends State<HighworkAqjdDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();
@ -315,6 +317,9 @@ class _HighworkAqjdDetailState extends State<HighworkAqjdDetail> {
mediaType: MediaType.image,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere(
(e) => e.localPath == path,

View File

@ -182,7 +182,7 @@ class _HighworkApplyDetailState extends State<HighworkApplyDetail> {
if (picked != null) {
setState(() {
pd['WORK_EXPECTED_START_TIME'] = DateFormat(
'yyyy-MM-dd HH:mm',
'yyyy-MM-dd HH:mm:ss',
).format(picked);
///
@ -206,7 +206,7 @@ class _HighworkApplyDetailState extends State<HighworkApplyDetail> {
if (picked != null) {
setState(() {
pd['WORK_EXPECTED_END_TIME'] = DateFormat(
'yyyy-MM-dd HH:mm',
'yyyy-MM-dd HH:mm:ss',
).format(picked);
});
}

View File

@ -176,6 +176,8 @@ class _HighworkJhrDetailState extends State<HighworkJhrDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -176,6 +176,8 @@ class _HighworkJsjdDetailState extends State<HighworkJsjdDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -201,6 +201,8 @@ class _HighworkJszyDetailState extends State<HighworkJszyDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();
@ -313,7 +315,7 @@ class _HighworkJszyDetailState extends State<HighworkJszyDetail> {
if (picked != null) {
setState(() {
endTime = DateFormat(
'yyyy-MM-dd HH:mm',
'yyyy-MM-dd HH:mm:ss',
).format(picked);
});
}

View File

@ -184,6 +184,8 @@ class _HighworkKszyDetailState extends State<HighworkKszyDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();
@ -302,7 +304,7 @@ class _HighworkKszyDetailState extends State<HighworkKszyDetail> {
if (picked != null) {
setState(() {
startTime = DateFormat(
'yyyy-MM-dd HH:mm',
'yyyy-MM-dd HH:mm:ss',
).format(picked);
});
}

View File

@ -181,6 +181,8 @@ class _HighworkShbmDetailState extends State<HighworkShbmDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -181,6 +181,8 @@ class _HighworkSpbmDetailState extends State<HighworkSpbmDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -317,6 +317,8 @@ class _HighworkSetSafeDetailState extends State<HighworkSetSafeDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -182,6 +182,8 @@ class _HighworkSzdwDetailState extends State<HighworkSzdwDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -243,6 +243,8 @@ class _HighworkYsgdDetailState extends State<HighworkYsgdDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();
@ -363,7 +365,7 @@ class _HighworkYsgdDetailState extends State<HighworkYsgdDetail> {
if (picked != null) {
setState(() {
startTime = DateFormat(
'yyyy-MM-dd HH:mm',
'yyyy-MM-dd HH:mm:ss',
).format(picked);
});
FocusHelper.clearFocus(context);
@ -379,6 +381,9 @@ class _HighworkYsgdDetailState extends State<HighworkYsgdDetail> {
horizontalPadding: 0,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere(
(e) => e.localPath == path,

View File

@ -182,6 +182,8 @@ class _HighworkZyfzDetailState extends State<HighworkZyfzDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -175,6 +175,8 @@ class _HighworkZyrDetailState extends State<HighworkZyrDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

View File

@ -250,6 +250,12 @@ class _ElectricityDetailFormWidgetState extends State<ElectricityDetailFormWidge
label: '视频监控:',
isClean: widget.isEditable,
cleanText: '清除监控',
onTapClean: () {
setState(() {
pd['VIDEONAME'] = '';
pd['VIDEOMANAGER_ID'] = '';
});
},
isRequired: false,
isEditable: widget.isEditable,
onTap: widget.onChooseVideoManager ?? () {},

View File

@ -212,6 +212,8 @@ class _ElectricityAqjdDetailState extends State<ElectricityAqjdDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();
@ -322,6 +324,9 @@ class _ElectricityAqjdDetailState extends State<ElectricityAqjdDetail> {
mediaType: MediaType.image,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaTapped: (path) {
presentOpaque(SingleImageViewer(imageUrl: path), context);
},
onMediaRemoved: (path) {
final item = imgList.firstWhere(
(e) => e.localPath == path,

View File

@ -184,6 +184,8 @@ class _ElectricityDbbzDetailState extends State<ElectricityDbbzDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.of(context).pop(true);
}else{
ToastUtil.showNormal(context, '操作失败:${result['msg'] ?? '未知错误'}');
}
} catch (e) {
LoadingDialogHelper.hide();

Some files were not shown because too many files have changed in this diff Show More