八项作业动火作业流程完成

main
hs 2025-07-31 17:33:26 +08:00
parent 3a00844a57
commit ff39ac4737
24 changed files with 4701 additions and 292 deletions

View File

@ -7,6 +7,7 @@ import UIKit
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}

View File

@ -36,7 +36,7 @@ class ListItemFactory {
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
_truncateText(rightText,14),
_truncateText(rightText,100),
// rightText,
style: TextStyle(fontSize: 15, color: Colors.grey),
),
@ -233,7 +233,7 @@ class ListItemFactory {
);
}
///
/// YesNo
static Widget createYesNoSection({
required String title,
required String yesLabel,
@ -317,7 +317,23 @@ class ListItemFactory {
),
);
}
///
static Widget headerTitle(String title) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
Text(
title,
style: const TextStyle(fontSize: 15, fontWeight: FontWeight.bold),
),
],
),
);
}
///
static Widget createCustomItem({
required Widget child,
@ -344,8 +360,10 @@ class ListItemFactory {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//
HhTextStyleUtils.mainTitle(label, fontSize: 15),
const SizedBox(height: 8),
//
Expanded(
child: TextField(
autofocus: false,
@ -357,6 +375,7 @@ class ListItemFactory {
decoration: InputDecoration(
hintText: hint,
border: InputBorder.none,
contentPadding: EdgeInsets.zero, //
),
),
),
@ -365,7 +384,6 @@ class ListItemFactory {
);
}
///
static Widget createYesNoSectionTwo({
required String title,

View File

@ -244,8 +244,8 @@ class _MediaPickerRowState extends State<MediaPickerRow> {
}
}
///
class RepairedPhotoSection extends StatelessWidget {
///
class RepairedPhotoSection extends StatefulWidget {
final int maxCount;
final MediaType mediaType;
final String title;
@ -271,54 +271,85 @@ class RepairedPhotoSection extends StatelessWidget {
this.onMediaRemoved,
}) : super(key: key);
@override
_RepairedPhotoSectionState createState() => _RepairedPhotoSectionState();
}
class _RepairedPhotoSectionState extends State<RepairedPhotoSection> {
late List<String> _mediaPaths;
@override
void initState() {
super.initState();
//
_mediaPaths = widget.initialMediaPaths?.take(widget.maxCount).toList() ?? [];
//
WidgetsBinding.instance.addPostFrameCallback((_) {
widget.onChanged(
_mediaPaths.map((p) => File(p)).toList(),
);
});
}
@override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
padding: const EdgeInsets.only(left: 5, right: 10),
padding: const EdgeInsets.only(left: 0, right: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: horizontalPadding),
padding: EdgeInsets.symmetric(horizontal: widget.horizontalPadding),
child: ListItemFactory.createRowSpaceBetweenItem(
leftText: title,
rightText: '${initialMediaPaths?.length ?? 0}/$maxCount',
leftText: widget.title,
//
rightText: '${_mediaPaths.length}/${widget.maxCount}',
),
),
const SizedBox(height: 8),
Padding(
padding: EdgeInsets.symmetric(horizontal: horizontalPadding),
padding: EdgeInsets.symmetric(horizontal: widget.horizontalPadding),
child: MediaPickerRow(
maxCount: maxCount,
mediaType: mediaType,
initialMediaPaths: initialMediaPaths,
onChanged: onChanged,
onMediaAdded: onMediaAdded,
onMediaRemoved: onMediaRemoved,
maxCount: widget.maxCount,
mediaType: widget.mediaType,
initialMediaPaths: _mediaPaths,
// onChanged mediaPaths
onChanged: (files) {
final newPaths = files.map((f) => f.path).toList();
setState(() {
_mediaPaths = newPaths;
});
widget.onChanged(files);
},
// _mediaPaths
onMediaAdded: widget.onMediaAdded,
onMediaRemoved: widget.onMediaRemoved,
),
),
const SizedBox(height: 20),
if (isShowAI)
Row(
children: [
GestureDetector(
onTap: onAiIdentify,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 15),
height: 36,
decoration: BoxDecoration(
color: const Color(0xFFDFEAFF),
borderRadius: BorderRadius.circular(18),
),
child: Row(
children: [
Image.asset('assets/images/ai_img.png', width: 20),
const SizedBox(width: 5),
const Text('AI隐患识别与处理'),
],
),
if (widget.isShowAI)
Padding(
padding: EdgeInsets.symmetric(horizontal: widget.horizontalPadding),
child: GestureDetector(
onTap: widget.onAiIdentify,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 15),
height: 36,
decoration: BoxDecoration(
color: const Color(0xFFDFEAFF),
borderRadius: BorderRadius.circular(18),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Image.asset('assets/images/ai_img.png', width: 20),
const SizedBox(width: 5),
const Text('AI隐患识别与处理'),
],
),
),
],
),
),
],
),

View File

@ -801,7 +801,7 @@ U6Hzm1ninpWeE+awIDAQAB
);
}
///
///
static Future<Map<String, dynamic>> uploadSaveFile (
String filePath,
) async {
@ -842,6 +842,9 @@ U6Hzm1ninpWeE+awIDAQAB
// MultipartFile
for (var i = 0; i < filePaths.length; i++) {
final path = filePaths[i];
if (path.contains('uploadFiles')) {
continue;
}
data['file$i'] = await MultipartFile.fromFile(
path,
filename: path.split(Platform.pathSeparator).last,

View File

@ -430,4 +430,14 @@ class ItemListWidget {
),
);
}
static Widget itemContainer(Widget child) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
child: child,
);
}
}

View File

@ -1,20 +1,17 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import '../../../../../customWidget/date_picker_dialog.dart';
import '../../../../../http/ApiService.dart';
import '../../../../../tools/tools.dart';
import 'dh_work_detai/hotwork_apply_detail.dart';
import '../../../../../../customWidget/date_picker_dialog.dart';
import '../../../../../../http/ApiService.dart';
import '../../../../../../tools/tools.dart';
import 'hotwork_apply_detail.dart';
///
import 'package:flutter/material.dart';
///
import 'package:flutter/services.dart';
///
///
class MeasuresListWidget extends StatelessWidget {
const MeasuresListWidget({
super.key,
@ -22,6 +19,8 @@ class MeasuresListWidget extends StatelessWidget {
required this.baseImgPath,
required this.isAllowEdit,
this.onSign,
this.isShowSign = false,
});
/// Map
final List<Map<String, dynamic>> measuresList;
@ -35,6 +34,8 @@ class MeasuresListWidget extends StatelessWidget {
/// item
final void Function(Map<String, dynamic> item)? onSign;
///
final bool isShowSign;
@override
@ -128,17 +129,15 @@ class MeasuresListWidget extends StatelessWidget {
isAllowEdit
? TextButton(
onPressed: () {
if ((item['STATUS'] as String?) != '-1') {
onSign?.call(item);
}
onSign?.call(item);
},
child: Text(
(item['SIGN_ITEM'] ?? '').toString().isNotEmpty
? '已签字'
: '签字',
style: TextStyle(
color: (item['STATUS'] as String?) == '-1'
? Colors.grey
color: (item['SIGN_ITEM'] ?? '').toString().isNotEmpty
? Colors.grey.shade600
: Colors.blue,
),
),
@ -156,7 +155,7 @@ class MeasuresListWidget extends StatelessWidget {
//
if (item.containsKey('IMG_PATH') &&
(item['IMG_PATH'] as String).isNotEmpty)
(item['IMG_PATH'] as String).isNotEmpty && isShowSign)
..._buildImageRows(
context,
(item['IMG_PATH'] as String).split(','),
@ -258,15 +257,10 @@ class MeasuresListWidget extends StatelessWidget {
children: [
GestureDetector(
onTap: () {
Navigator.of(context).push(
PageRouteBuilder(
opaque: false,
pageBuilder: (_, __, ___) =>
SingleImageViewer(imageUrl: '$baseImgPath\$p'),
),
);
presentOpaque(SingleImageViewer(imageUrl: '$baseImgPath$p'), context);
},
child: Image.network('$baseImgPath\$p', width: 80, height: 80),
child: Image.network('$baseImgPath$p', width: 80, height: 80),
),
if (time.isNotEmpty) ...[const SizedBox(width: 8), Text(time)],
],
@ -276,7 +270,6 @@ class MeasuresListWidget extends StatelessWidget {
}
}
///
class OtherMeasuresWidget extends StatelessWidget {
///
@ -363,36 +356,71 @@ class OtherMeasuresWidget extends StatelessWidget {
/// SIGN_PATH List String
Widget _buildSignImages(BuildContext context, Map<String, dynamic> item) {
final dynamic raw = item['SIGN_PATH'];
final rawPath = item['SIGN_PATH'];
List<String> paths = [];
if (raw is String && raw.isNotEmpty) {
paths = [raw];
} else if (raw is List) {
paths = raw.cast<String>();
if (rawPath is String && rawPath.isNotEmpty) {
paths = [rawPath];
} else if (rawPath is List) {
paths = rawPath.whereType<String>().toList();
}
// SIGN_TIME String/List
List<String> times = [];
if (item.containsKey('SIGN_TIME')) {
final rawTime = item['SIGN_TIME'];
if (rawTime is String && rawTime.isNotEmpty) {
times = [rawTime];
} else if (rawTime is List) {
times = rawTime.whereType<String>().toList();
}
}
//
if (paths.isEmpty) return const SizedBox.shrink();
return Wrap(
spacing: 8,
runSpacing: 8,
children:
paths.map((p) {
return GestureDetector(
// +
final children = <Widget>[];
for (var i = 0; i < paths.length; i++) {
final path = paths[i];
// 使
final timeLabel = (i < times.length) ? times[i] : '';
children.add(
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
GestureDetector(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder:
(_) => SingleImageViewer(imageUrl: '$baseImgPath$p'),
),
);
presentOpaque(SingleImageViewer(imageUrl: '$baseImgPath$path'), context);
},
child: Image.network(
'$baseImgPath$p',
'$baseImgPath$path',
width: 60,
height: 60,
errorBuilder: (c, o, s) => const Icon(Icons.broken_image),
fit: BoxFit.cover,
errorBuilder: (_, __, ___) => const Icon(Icons.broken_image),
),
);
}).toList(),
),
const SizedBox(width: 8),
Expanded(
child: Text(
timeLabel,
style: const TextStyle(fontSize: 12, color: Colors.black54),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
],
),
);
if (i != paths.length - 1) {
children.add(const SizedBox(height: 8));
}
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: children,
);
}
}
@ -568,14 +596,9 @@ class SignaturesListWidget extends StatelessWidget {
children: [
GestureDetector(
onTap:
() => Navigator.of(context).push(
MaterialPageRoute(
builder:
(_) => SingleImageViewer(
imageUrl: '$baseImgPath${signPaths[i]}',
),
),
),
() => presentOpaque(SingleImageViewer(
imageUrl: '$baseImgPath${signPaths[i]}',
), context),
child: Image.network(
'$baseImgPath${signPaths[i]}',
width: 100,
@ -664,14 +687,9 @@ class SignaturesListWidget extends StatelessWidget {
children: [
GestureDetector(
onTap:
() => Navigator.of(context).push(
MaterialPageRoute(
builder:
(_) => SingleImageViewer(
imageUrl: '$baseImgPath${signPaths[i]}',
),
),
),
() => presentOpaque(SingleImageViewer(
imageUrl: '$baseImgPath${signPaths[i]}',
), context),
child: Image.network(
'$baseImgPath${signPaths[i]}',
width: 100,
@ -714,7 +732,6 @@ class SelectionPopup extends StatefulWidget {
@override
_SelectionPopupState createState() => _SelectionPopupState();
}
class _SelectionPopupState extends State<SelectionPopup> {
late List<Map<String, String>> workList;
late String selectedWorkType;
@ -986,3 +1003,5 @@ class _SelectionPopupState extends State<SelectionPopup> {
);
}
}

View File

@ -0,0 +1,399 @@
import 'dart:math' as math;
import 'package:flutter/material.dart';
import '../../../../../customWidget/ItemWidgetFactory.dart';
import '../../../../../customWidget/single_image_viewer.dart';
import '../../../../../tools/tools.dart';
import '../special_Wrok/MeasuresListWidget.dart';
import 'WorkDetailFormWidget.dart';
class SpecialWorkFormBaseWork extends StatelessWidget {
///
final Map<String, dynamic> pd;
///
final List<Map<String, dynamic>> measuresList;
///
final Map<String, dynamic> signs;
///
final String baseImgPath;
///
final bool isEditable;
///
final VoidCallback onChooseLevel;
///
final VoidCallback onChooseHotworkUser;
///
final VoidCallback onAnalyzeTap;
const SpecialWorkFormBaseWork({
Key? key,
required this.pd,
required this.measuresList,
required this.signs,
required this.baseImgPath,
this.isEditable = false,
required this.onChooseLevel,
required this.onChooseHotworkUser,
required this.onAnalyzeTap,
}) : super(key: key);
Widget _itemContainer(Widget child) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 8),
child: child,
);
}
Widget signItemWidget(
String signKey,
String nameKey,
String name,
BuildContext context,
) {
return _itemContainer(
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//
Padding(
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10),
child: Row(
children: [
Expanded(
child: ListItemFactory.headerTitle(name),
),
if (FormUtils.hasValue(pd, nameKey))
Text(
pd[nameKey]?.toString() ?? '',
style: const TextStyle(fontSize: 16),
),
],
),
),
const SizedBox(height: 8),
if (FormUtils.hasValue(signs, signKey))
...((signs[signKey] as List<dynamic>)
.cast<Map<String, dynamic>>()
.map((item) {
// SIGN_PATH
List<String> signPaths = [];
final rawSP = FormUtils.hasValue(item, 'SIGN_PATH') ? item['SIGN_PATH'] : null;
if (rawSP is String && rawSP.isNotEmpty) {
signPaths = rawSP.split(',').map((s) => s.trim()).toList();
} else if (rawSP is List) {
signPaths = rawSP.cast<String>();
}
// SIGN_TIME
List<String> signTimes = [];
final rawST = FormUtils.hasValue(item, 'SIGN_TIME') ? item['SIGN_TIME'] : null;
if (rawST is String && rawST.isNotEmpty) {
signTimes = rawST.split(',');
} else if (rawST is List) {
signTimes = rawST.cast<String>();
}
final pairCount = math.min(signPaths.length, signTimes.length);
// IMG_PATH, 2
List<String> imgPaths = [];
final rawIP = FormUtils.hasValue(item, 'IMG_PATH') ? item['IMG_PATH'] : null;
if (rawIP is String && rawIP.isNotEmpty) {
imgPaths = rawIP.split(',').map((s) => s.trim()).take(2).toList();
} else if (rawIP is List) {
imgPaths = rawIP.cast<String>().take(2).toList();
}
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (imgPaths.isNotEmpty) ...[
Row(
children: imgPaths.map((p) {
final fullUrl = '$baseImgPath$p';
return Padding(
padding: const EdgeInsets.only(right: 8.0),
child: ClipRRect(
borderRadius: BorderRadius.circular(2),
child: Image.network(
fullUrl,
width: 50,
height: 50,
fit: BoxFit.cover,
errorBuilder: (_, __, ___) => const Icon(
Icons.broken_image,
size: 40,
),
),
),
);
}).toList(),
),
const SizedBox(height: 8),
],
//
...List.generate(pairCount, (index) {
final imgPath = signPaths[index];
final timeLabel = signTimes[index];
final fullUrl = '$baseImgPath$imgPath';
const imageWidth = 200.0;
const imageHeight = 100.0;
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
onTap: () => presentOpaque(
SingleImageViewer(imageUrl: fullUrl),
context,
),
child: ClipRRect(
borderRadius: BorderRadius.circular(4),
child: Image.network(
fullUrl,
width: imageWidth,
height: imageHeight,
fit: BoxFit.cover,
errorBuilder: (_, __, ___) =>
const Icon(Icons.broken_image, size: 60),
),
),
),
const SizedBox(width: 12),
Expanded(
child: SizedBox(
height: imageHeight,
child: Align(
alignment: Alignment.bottomRight,
child: Text(
timeLabel,
style: const TextStyle(
fontSize: 14,
color: Colors.black87,
),
),
),
),
),
],
),
if (index < pairCount - 1)
const Padding(
padding: EdgeInsets.only(top: 8.0),
child: Divider(height: 1),
),
],
),
);
}),
],
),
);
}).toList()),
],
),
);
}
@override
Widget build(BuildContext context) {
return Column(
spacing: 12,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 1.
WorkDetailFormWidget(
pd: pd,
isEditable: isEditable,
onChooseLevel: onChooseLevel,
onChooseHotworkUser: onChooseHotworkUser,
onAnalyzeTap: onAnalyzeTap,
),
// 2.
if (measuresList.isNotEmpty)
_itemContainer(
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ListItemFactory.createBuildSimpleSection('安全防护措施'),
MeasuresListWidget(
measuresList: measuresList,
baseImgPath: baseImgPath,
isAllowEdit: isEditable,
isShowSign: true,
),
],
),
),
// 3.
if (FormUtils.hasValue(signs, 'MEASURES_CONFIRM'))
_itemContainer(
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ListItemFactory.createBuildSimpleSection('其他安全防护措施'),
OtherMeasuresWidget(
otherMeasures: signs['MEASURES_CONFIRM'],
baseImgPath: baseImgPath,
),
],
),
),
// 4.
if (FormUtils.hasValue(signs, 'GUARDIAN'))
signItemWidget('GUARDIAN', 'GUARDIAN_USER_NAME', '监护人', context),
if (FormUtils.hasValue(signs, 'CONFESS'))
signItemWidget('CONFESS', 'CONFESS_USER_NAME', '安全交底人', context),
if (FormUtils.hasValue(signs, 'ACCEPT_CONFESS'))
signItemWidget('ACCEPT_CONFESS', 'ACCEPT_CONFESS_USER_NAME', '接受交底人', context),
//
if (FormUtils.hasValue(signs, 'CONFIRM')) ...[
Column(
children: [
_itemContainer(
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(padding: EdgeInsets.symmetric(horizontal: 8), child: ListItemFactory.headerTitle('作业负责人意见'),),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(signs['CONFIRM'][0]['DESCR'] ?? ''),
),
],
),
),
Divider(height: 1,),
signItemWidget('CONFIRM', 'CONFIRM_USER_NAME', '作业负责人', context),
],
)
],
//
if (FormUtils.hasValue(signs, 'LEADER')) ...[
Column(
children: [
_itemContainer(
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(padding: EdgeInsets.symmetric(horizontal: 8), child: ListItemFactory.headerTitle('所在单位意见'),),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(signs['LEADER'][0]['DESCR'] ?? ''),
),
],
),
),
Divider(height: 1,),
signItemWidget('LEADER', 'LEADER_USER_NAME', '所在单位负责人', context),
],
)
],
//
if (FormUtils.hasValue(signs, 'AUDIT')) ...[
Column(
children: [
_itemContainer(
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(padding: EdgeInsets.symmetric(horizontal: 8), child: ListItemFactory.headerTitle('安全管理部门意见'),),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(signs['AUDIT'][0]['DESCR'] ?? ''),
),
],
),
),
Divider(height: 1,),
signItemWidget('AUDIT', 'AUDIT_USER_NAME', '安全管理部门负责人', context),
],
)
],
//
if (FormUtils.hasValue(signs, 'APPROVE')) ...[
Column(
children: [
_itemContainer(
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(padding: EdgeInsets.symmetric(horizontal: 8), child: ListItemFactory.headerTitle('动火审批人意见'),),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(signs['APPROVE'][0]['DESCR'] ?? ''),
),
],
),
),
Divider(height: 1,),
signItemWidget('APPROVE', 'APPROVE_USER_NAME', '动火审批人', context),
],
)
],
//
if (FormUtils.hasValue(signs, 'MONITOR'))
signItemWidget('MONITOR', 'MONITOR_USER_NAME', '动火前在岗班长', context),
//
if (FormUtils.hasValue(signs, 'WORK_START'))
signItemWidget('WORK_START', 'WORK_START_USER_NAME', '作业开始负责人', context),
//
if (FormUtils.hasValue(signs, 'WORK_END'))
signItemWidget('WORK_END', 'WORK_END_USER_NAME', '作业结束负责人', context),
//
if (FormUtils.hasValue(signs, 'ACCEPT')) ...[
Column(
children: [
_itemContainer(
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(padding: EdgeInsets.symmetric(horizontal: 8), child: ListItemFactory.headerTitle('完工验收意见'),),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(signs['ACCEPT'][0]['DESCR'] ?? ''),
),
],
),
),
Divider(height: 1,),
signItemWidget('ACCEPT', 'ACCEPT_USER_NAME', '验收部门负责人', context),
],
)
],
],
);
}
}

View File

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import '../../../../../tools/tools.dart';
import '../../item_list_widget.dart';
import '../special_Wrok/dh_work_detai/MeasuresListWidget.dart';
import '../special_Wrok/MeasuresListWidget.dart';
///
/// TextEditingController
@ -12,7 +12,6 @@ class WorkDetailFormWidget extends StatelessWidget {
final VoidCallback onChooseLevel;
final VoidCallback onChooseHotworkUser;
final VoidCallback onAnalyzeTap;
///
final TextEditingController? contentController;
final TextEditingController? locationController;

View File

@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:intl/intl.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/http/ApiService.dart';
import 'package:qhd_prevention/http/HttpManager.dart';
import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
@ -19,8 +20,38 @@ import '../../../../../mine/mine_sign_page.dart';
/// + 线
class ImageData {
String localPath;
String? serverPath;
ImageData({required this.localPath, this.serverPath});
String serverPath;
ImageData({required this.localPath, required this.serverPath});
}
class SignImageData {
String SIGNER_TIME;
String? filePath;
int? key = 0;
SignImageData({
required this.SIGNER_TIME,
required this.filePath,
required this.key,
});
Map<String, dynamic> toJson() => {
'SIGNER_TIME': SIGNER_TIME,
'filePath': filePath,
'key': key,
};
factory SignImageData.fromJson(Map<String, dynamic> json) {
return SignImageData(
SIGNER_TIME: json['SIGNER_TIME'] as String,
filePath: json['filePath'] as String?,
key:
json['key'] is int
? json['key'] as int
: int.tryParse(json['key']?.toString() ?? ''),
);
}
}
class DangerousOptionsPage extends StatefulWidget {
@ -28,7 +59,7 @@ class DangerousOptionsPage extends StatefulWidget {
final int status;
final String measures;
final List<ImageData> imgList;
final List<String> signImgList;
final List<Map<String, dynamic>> signImgList;
const DangerousOptionsPage({
Key? key,
@ -48,12 +79,10 @@ class _DangerousOptionsPageState extends State<DangerousOptionsPage> {
late int status;
late String measures;
late List<ImageData> imgList;
late List<String> signImgList;
late List<SignImageData> signImgList;
List<String> signTimes = [];
bool buttonLoading = false;
final Dio _dio = Dio();
final _picker = ImagePicker();
@override
void initState() {
@ -62,7 +91,8 @@ class _DangerousOptionsPageState extends State<DangerousOptionsPage> {
status = widget.status;
measures = widget.measures;
imgList = List<ImageData>.from(widget.imgList);
signImgList = List<String>.from(widget.signImgList);
signImgList =
widget.signImgList.map((map) => SignImageData.fromJson(map)).toList();
}
///
@ -87,29 +117,61 @@ class _DangerousOptionsPageState extends State<DangerousOptionsPage> {
Future<void> _submit() async {
if (signImgList.isEmpty) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('请签字')));
ToastUtil.showNormal(context, '请签字');
return;
}
await ApiService.saveDangerousOptionsFile(signImgList);
List<String> filePaths =
signImgList.map((img) => img.filePath ?? '').toList();
final result = await ApiService.saveDangerousOptionsFile(filePaths);
final List<dynamic> signList = result['FILE_PATH_LIST'];
List<Map<String, dynamic>> sineImageList = [];
for (SignImageData data in signImgList) {
for (Map<String, dynamic> img in signList) {
String imgName = 'file${data.key}';
if (data.filePath!.contains('uploadFiles')) {
final idata = {
'filePath': data.filePath,
'SIGNER_TIME': data.SIGNER_TIME,
'key': data.key,
};
sineImageList.add(idata);
}
if (imgName == img['key']) {
final idata = {
'filePath': img['filePath'] ?? '',
'SIGNER_TIME': data.SIGNER_TIME,
'key': data.key,
};
sineImageList.add(idata);
}
}
}
setState(() => buttonLoading = true);
Navigator.pop(context, {
'imgList': imgList.map((e) => {'local': e.localPath, 'remote': e.serverPath}).toList(),
'signImgList': signImgList,
'imgList':
imgList
.map((e) => {'local': e.localPath, 'remote': e.serverPath})
.toList(),
'signImgList': sineImageList,
'index': index,
'status': status,
});
}
Future<void> _sign() async {
final path = await Navigator.push(
final String path = await Navigator.push(
context,
MaterialPageRoute(builder: (c) => MineSignPage()),
);
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
signImgList.add(path);
final imageData = SignImageData(
SIGNER_TIME: now,
filePath: path,
key: signImgList.length,
);
signImgList.add(imageData);
signTimes.add(now);
});
FocusHelper.clearFocus(context);
@ -118,41 +180,57 @@ class _DangerousOptionsPageState extends State<DangerousOptionsPage> {
Widget _signListWidget() {
return Column(
children: signImgList.map((path) {
final idx = signImgList.indexOf(path);
return Column(
children: [
const SizedBox(height: 10),
const Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children:
signImgList.map((imgData) {
final idx = signImgList.indexOf(imgData);
return Column(
children: [
GestureDetector(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 200, maxHeight: 150),
child: Image.file(File(path), fit: BoxFit.contain),
),
onTap: () => presentOpaque(SingleImageViewer(imageUrl: path), context),
),
Column(
const SizedBox(height: 10),
const Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CustomButton(
text: '删除',
height: 30,
padding: const EdgeInsets.symmetric(horizontal: 10),
backgroundColor: Colors.red,
onPressed: () {
setState(() => signImgList.removeAt(idx));
},
GestureDetector(
child: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 230,
maxHeight: 150,
),
child:
(imgData.filePath ?? '').contains('uploadFiles')
? Image.network(
'${ApiService.baseImgPath}${imgData.filePath}',
)
: Image.file(
File(imgData.filePath ?? ''),
fit: BoxFit.contain,
),
),
onTap:
() => presentOpaque(
SingleImageViewer(imageUrl: imgData.filePath ?? ''),
context,
),
),
Column(
children: [
CustomButton(
text: '删除',
height: 30,
padding: const EdgeInsets.symmetric(horizontal: 10),
backgroundColor: Colors.red,
onPressed: () {
setState(() => signImgList.removeAt(idx));
},
),
const SizedBox(height: 80),
],
),
const SizedBox(height: 80),
],
),
],
),
],
);
}).toList(),
);
}).toList(),
);
}
@ -177,13 +255,19 @@ class _DangerousOptionsPageState extends State<DangerousOptionsPage> {
Padding(
padding: EdgeInsets.all(10),
child: Center(
child: Text('主要安全措施', style: TextStyle(fontWeight: FontWeight.bold)),
child: Text(
'主要安全措施',
style: TextStyle(fontWeight: FontWeight.bold),
),
),
),
Padding(
padding: EdgeInsets.all(10),
child: Center(
child: Text('操作', style: TextStyle(fontWeight: FontWeight.bold)),
child: Text(
'操作',
style: TextStyle(fontWeight: FontWeight.bold),
),
),
),
],
@ -191,7 +275,10 @@ class _DangerousOptionsPageState extends State<DangerousOptionsPage> {
TableRow(
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 5),
padding: const EdgeInsets.symmetric(
vertical: 12,
horizontal: 5,
),
child: Text(measures),
),
Padding(
@ -202,16 +289,28 @@ class _DangerousOptionsPageState extends State<DangerousOptionsPage> {
value: -1,
groupValue: status,
title: Text('不涉及'),
contentPadding: const EdgeInsets.symmetric(vertical: 0, horizontal: 8.0),
visualDensity: VisualDensity(vertical: -4, horizontal: 0),
contentPadding: const EdgeInsets.symmetric(
vertical: 0,
horizontal: 8.0,
),
visualDensity: VisualDensity(
vertical: -4,
horizontal: 0,
),
onChanged: (v) => setState(() => status = v!),
),
RadioListTile<int>(
value: 1,
groupValue: status,
title: Text('涉及'),
contentPadding: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 8.0),
visualDensity: VisualDensity(vertical: -4, horizontal: 0),
contentPadding: const EdgeInsets.symmetric(
vertical: 4.0,
horizontal: 8.0,
),
visualDensity: VisualDensity(
vertical: -4,
horizontal: 0,
),
onChanged: (v) => setState(() => status = v!),
),
],
@ -226,7 +325,10 @@ class _DangerousOptionsPageState extends State<DangerousOptionsPage> {
title: '上传图片',
maxCount: 2,
mediaType: MediaType.image,
initialMediaPaths: imgList.map((e) => e.localPath).toList(),
initialMediaPaths:
imgList
.map((e) => '${ApiService.baseImgPath}${e.serverPath}')
.toList(),
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaRemoved: (path) {

View File

@ -16,7 +16,7 @@ import '../../../../../../customWidget/single_image_viewer.dart';
import '../../../../../../http/ApiService.dart';
import '../../../../../mine/mine_sign_page.dart';
import '../../../../../my_appbar.dart';
import '../../special_Wrok/dh_work_detai/MeasuresListWidget.dart';
import '../../special_Wrok/MeasuresListWidget.dart';
import '../../special_Wrok/qtfx_work_detail/hotwork_gas_list.dart';
import '../WorkDetailFormWidget.dart';
@ -52,7 +52,6 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
late List<dynamic> workUserList = [];
///
late List<MeasureItem> measuresListCopy = [];
List<String> imagePaths = [];
List<String> signTimes = []; //
@override
@ -60,13 +59,6 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
super.initState();
_getData();
_getHotWorkNameList();
addMeasuresListCopy();
}
String measuresListToJson() {
final List<Map<String, dynamic>> jsonList =
measuresListCopy.map((item) => item.toJson()).toList();
return jsonEncode(jsonList);
}
///
@ -100,42 +92,11 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
});
}
///
void choosePersonHandle(MeasureItem item) async {
String unitId = item.DEPARTMENT_ID;
final personList = item.userList;
if (!unitId.isNotEmpty) {
ToastUtil.showNormal(context, '请先选择确认单位');
return;
}
if (personList.isEmpty) {
//
await _getPersonListForUnitId(item);
final list = item.userList;
if (list.isEmpty) {
//
ToastUtil.showNormal(context, '暂无数据,请选择其他单位');
} else {
choosePersonHandle(item);
}
return;
}
DepartmentPersonPicker.show(
context,
personsData: personList,
onSelected: (userId, name) {
setState(() {
item.USER_NAME = name;
item.USER_ID = userId;
print(json.encode(measuresListCopy));
});
},
).then((_) {});
}
///
Future<void> _sign() async {
FocusHelper.clearFocus(context);
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
@ -208,49 +169,47 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
}).toList(),
);
}
bool _validateAndProceed(BuildContext context) {
for (var i = 0; i < measuresList.length; i++) {
final m = measuresList[i];
/// 1 0
// 1.
if (!FormUtils.hasValue(m, 'SIGN_ITEM')) {
ToastUtil.showNormal(context, '${i + 1}项未签字');
return false;
}
// STATUS == '1' ANSWER
if (m['STATUS'] == '1') {
for (var j = 1; j <= 4; j++) {
if (FormUtils.hasValue(m, 'QUESTION${j}')
) {
if (!FormUtils.hasValue(m, 'ANSWER${j}')
|| (m['ANSWER${j}'] as String?)!.length == 0) {
ToastUtil.showNormal(context, '${i + 1}项未填写第${j}');
return false;
}
}
}
}
}
return true;
}
/// 1 0
Future<void> _submit(String status) async {
if (_otherController.text.trim().isEmpty) {
ToastUtil.showNormal(context, '请输入其他安全措施,没有请填“无”');
return;
}
if (imagePaths.isEmpty) {
ToastUtil.showNormal(context, '请签字');
return;
}
List<Map<String, dynamic>> signers = [];
String reasonText = '';
if (status == '1') {
int index = 0;
for (var item in measuresListCopy) {
if (item.USER_ID.isEmpty) {
ToastUtil.showNormal(
context,
'${index + 1}项未设置确认人',
);
return;
}
if (item.selectMeasures.isEmpty) {
ToastUtil.showNormal(
context,
'${index + 1}项未选择安全措施',
);
return;
}
final userId = item.USER_ID;
final selectMeasures = item.selectMeasures as List<dynamic>? ?? [];
for (var item in selectMeasures) {
signers.add({
'BUS_HOTWORK_MEASURES_ID': item['BUS_HOTWORK_MEASURES_ID'],
'USER_ID': userId,
});
}
//
if (signers.length != measuresList.length) {
// 使 ScaffoldMessenger
ToastUtil.showNormal(context, '请为每个安全措施选择确认人');
return;
}
index++;
if (!_validateAndProceed(context)) {
return;
}
} else {
await showDialog<String>(
@ -273,15 +232,15 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
return;
}
}
final Map<String, dynamic> formData = {};
//
formData['APPLY_STATUS'] = status;
formData['HOTWORK_ID'] = widget.HOTWORK_ID;
formData['DESCR'] = _otherController.text.trim().isEmpty ? _otherController.text.trim() : "";
formData['SIGNTIME'] = signTimes.join(',');
formData['USER_ID'] = SessionService.instance.loginUserId;
formData['APPLY_STATUS'] = status;
formData['STEP_REASON'] = reasonText;
formData['PREPARERS'] = json.encode(signers);
formData['MEASURES'] = json.encode(measuresList);
await showDialog<String>(
context: context,
@ -327,8 +286,6 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
final result = await ApiService.getHotWorkNameList();
setState(() {
workUserList = result['varList'] ?? '';
List<String> names =
workUserList.map((item) => item['NAME'] as String).toList();
});
}
@ -350,42 +307,20 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
});
}
void removeMeasuresListCopy(int index) {
setState(() {
measuresListCopy.removeAt(index);
});
}
void addMeasuresListCopy() {
setState(() {
measuresListCopy.add(
MeasureItem(
id: Random().nextDouble(),
DEPARTMENT_ID: '',
DEPARTMENT_NAME: '',
USER_ID: '',
USER_NAME: '',
userList: [],
userIndex: -1,
selectMeasures: [],
),
);
});
}
Future<void> _itemToSign(Map<String, dynamic> measures, int index) async {
//
final List<String> signImgList = measures['SIGN_ITEM'] ?? [];
final List<Map<String, dynamic>> signImgList = measures['SIGN_ITEM'] ?? [];
//
final List<ImageData> imgList = [];
if ((measures['IMG_PATH'] as String?)?.isNotEmpty ?? false) {
for (var path in (measures['IMG_PATH'] as String).split(',')) {
imgList.add(ImageData(localPath: path));
imgList.add(ImageData(localPath:path, serverPath: path));
}
}
final result = await pushPage(DangerousOptionsPage(index: index,status: measures['STATUS'] ?? 1,
//measures['STATUS']
final result = await pushPage(DangerousOptionsPage(index: index,status: int.parse(FormUtils.hasValue(measures, 'STATUS') ? measures['STATUS'] : '1'),
measures: measures['PROTECTIVE_MEASURES'] ?? '',
imgList: imgList,
signImgList: signImgList), context);
@ -393,18 +328,28 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
setState(() {
// local + remote
final returned = result['imgList'] as List<dynamic>;
measures['IMG_PATH'] = returned.map((m) {
// ImageData
final imgDataList = returned.map((m) {
return ImageData(
localPath: m['local'] as String,
serverPath: m['remote'] as String?,
serverPath: m['remote'] as String,
);
}).toList();
//
measures['SIGN_ITEM'] = List<String>.from(result['signImgList'] as List);
// serverPath
final serverPathString = imgDataList
.map((e) => e.serverPath)
.where((s) => s.isNotEmpty)
.map((s) => s) // String? String
.join(',');
// measures
measures['IMG_PATH'] = serverPathString;
//
measures['SIGN_ITEM'] = List<Map<String,dynamic>>.from(result['signImgList'] as List);
//
measures['STATUS'] = result['status'];
measures['STATUS'] = result['status'].toString();
index = result['index'] as int;
});
}

View File

@ -0,0 +1,335 @@
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/department_person_picker.dart';
import 'package:qhd_prevention/customWidget/department_picker.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/home/tap/tabList/special_wrok/SpecialWorkFormBaseWork.dart';
import 'package:qhd_prevention/tools/tools.dart';
import '../../../../../../customWidget/bottom_picker.dart';
import '../../../../../../customWidget/custom_alert_dialog.dart';
import '../../../../../../customWidget/photo_picker_row.dart';
import '../../../../../../customWidget/single_image_viewer.dart';
import '../../../../../../http/ApiService.dart';
import '../../../../../mine/mine_sign_page.dart';
import '../../../../../my_appbar.dart';
import '../../special_Wrok/MeasuresListWidget.dart';
import '../../special_Wrok/qtfx_work_detail/hotwork_gas_list.dart';
import '../WorkDetailFormWidget.dart';
import '../szaq_work_detail/SafeFunctionDialog.dart';
///
class HotworkAqglDetail extends StatefulWidget {
const HotworkAqglDetail({
super.key,
required this.HOTWORK_ID,
required this.flow,
});
final String HOTWORK_ID;
final String flow;
@override
State<HotworkAqglDetail> createState() => _HotworkAqglDetailState();
}
class _HotworkAqglDetailState extends State<HotworkAqglDetail> {
late bool isEditable = false;
///
late Map<String, dynamic> pd = {};
final TextEditingController _contentController = TextEditingController();
///
late List<Map<String, dynamic>> measuresList = [];
late Map<String, dynamic> signs = {};
List<String> signImages = [];
List<String> signTimes = []; //
@override
void initState() {
super.initState();
_getData();
}
///
Future<void> _sign() async {
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
});
}
}
Widget _signListWidget() {
return Column(
children:
signImages.map((path) {
return Column(
children: [
const SizedBox(height: 10),
const Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
child: // ConstrainedBox BoxFit.contain
ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 200,
maxHeight: 150,
),
child: Image.file(
File(path),
//
fit: BoxFit.contain,
),
),
onTap: () {
presentOpaque(
SingleImageViewer(imageUrl: path),
context,
);
},
),
Column(
children: [
Container(
padding: const EdgeInsets.only(right: 5),
child: CustomButton(
text: 'X',
height: 30,
padding: const EdgeInsets.symmetric(horizontal: 10),
backgroundColor: Colors.red,
onPressed: () {
setState(() {
signImages.remove(path);
});
},
),
),
const SizedBox(height: 80),
],
),
],
),
],
);
}).toList(),
);
}
/// -1 1
Future<void> _submit(String status) async {
if (signImages.isEmpty) {
ToastUtil.showNormal(context, '请签字');
return;
}
String reasonText = '';
String DESCR = _contentController.text.trim();
if (DESCR.isEmpty) {
ToastUtil.showNormal(context, '请输入安全管理部门意见');
return;
}
if (status == '1') {
} else {
await showDialog<String>(
context: context,
builder:
(_) => CustomAlertDialog(
title: '作废原因',
mode: DialogMode.input,
hintText: '请输入作废原因',
cancelText: '取消',
confirmText: '确定',
onInputConfirm: (text) {
reasonText = text;
},
),
);
if (reasonText.isEmpty) {
ToastUtil.showNormal(context, '请填写作废原因');
return;
}
}
// measures
final Map<String, dynamic> formData = {};
//
formData['HOTWORK_ID'] = widget.HOTWORK_ID;
formData['SIGNTIME'] = signTimes.join(',');
formData['USER_ID'] = SessionService.instance.loginUserId;
formData['APPLY_STATUS'] = status;
formData['STEP_REASON'] = reasonText;
formData['DESCR'] = DESCR;
await showDialog<String>(
context: context,
builder:
(_) => CustomAlertDialog(
title: '提示',
content: '请确认' + (status == '1' ? "通过" : "作废") + '本作业票?',
cancelText: '取消',
confirmText: '确定',
onConfirm: () async {
LoadingDialogHelper.show(context);
try {
final result = await ApiService.saveSafeFunctionSure(
formData,
signImages,
);
LoadingDialogHelper.hide(context);
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
}
} catch (e) {
LoadingDialogHelper.hide(context);
ToastUtil.showNormal(context, '操作失败:$e');
}
},
),
);
}
///
Future<void> _getData() async {
final data = await ApiService.getHomeworkFindById(widget.HOTWORK_ID);
setState(() {
pd = data['pd'];
_getSigns(pd['HOTWORK_ID'] ?? '');
_getMeasures(pd['HOTWORK_ID'] ?? '');
});
}
Future<void> _getMeasures(String homework_id) async {
final data = await ApiService.listSignFinishMeasures(
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
);
setState(() {
measuresList = List<Map<String, dynamic>>.from(
data['finishMeasuresList'] ?? <Map<String, dynamic>>[],
);
});
}
Future<void> _getSigns(String homework_id) async {
final data = await ApiService.listSignFinished(
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
);
setState(() {
signs = data['signs'] ?? {};
});
}
///
Widget _bottomButtons() {
return Row(
spacing: 10,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: CustomButton(
height: 45,
textStyle: TextStyle(fontSize: 16, color: Colors.white),
text: '作废',
backgroundColor: Colors.red,
onPressed: () {
_submit('-1');
},
),
),
Expanded(
child: CustomButton(
textStyle: TextStyle(fontSize: 16, color: Colors.white),
text: '通过',
backgroundColor: Colors.green,
onPressed: () {
_submit('1');
},
),
),
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppbar(title: '安全管理部门意见'),
body: SafeArea(
child: SingleChildScrollView(
padding: EdgeInsets.all(12),
child: Column(
spacing: 12,
children: [
// _setSafeDetailWidget(),
SpecialWorkFormBaseWork(
pd: pd,
measuresList: measuresList,
signs: signs,
baseImgPath: ApiService.baseImgPath,
isEditable: false,
onChooseLevel: () {},
onChooseHotworkUser: () {},
onAnalyzeTap: () {
pushPage(
HotworkGasList(HOTWORK_ID: widget.HOTWORK_ID),
context,
);
},
),
ItemListWidget.itemContainer(
Column(
children: [
ListItemFactory.createBuildMultilineInput(
'安全管理部门意见',
'请输入意见',
_contentController,
),
Divider(),
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ListItemFactory.headerTitle('安全管理部门负责人'),
CustomButton(
text: '新增手写签字',
height: 36,
backgroundColor: Colors.green,
onPressed: () {
_sign();
},
),
],
),
if (signImages.isNotEmpty) _signListWidget(),
],
)
],
),
),
_bottomButtons(),
],
),
),
),
);
}
}

View File

@ -0,0 +1,370 @@
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/department_person_picker.dart';
import 'package:qhd_prevention/customWidget/department_picker.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/home/tap/tabList/special_wrok/SpecialWorkFormBaseWork.dart';
import 'package:qhd_prevention/tools/tools.dart';
import '../../../../../../customWidget/bottom_picker.dart';
import '../../../../../../customWidget/custom_alert_dialog.dart';
import '../../../../../../customWidget/photo_picker_row.dart';
import '../../../../../../customWidget/single_image_viewer.dart';
import '../../../../../../http/ApiService.dart';
import '../../../../../mine/mine_sign_page.dart';
import '../../../../../my_appbar.dart';
import '../../special_Wrok/MeasuresListWidget.dart';
import '../../special_Wrok/qtfx_work_detail/hotwork_gas_list.dart';
import '../WorkDetailFormWidget.dart';
import '../szaq_work_detail/SafeFunctionDialog.dart';
/// + 线
class ImageData {
String localPath;
String serverPath;
ImageData({required this.localPath, required this.serverPath});
}
///
class HotworkAqjdDetail extends StatefulWidget {
const HotworkAqjdDetail({
super.key,
required this.HOTWORK_ID,
required this.flow,
});
final String HOTWORK_ID;
final String flow;
@override
State<HotworkAqjdDetail> createState() => _HotworkAqjdDetailState();
}
class _HotworkAqjdDetailState extends State<HotworkAqjdDetail> {
late bool isEditable = false;
///
late Map<String, dynamic> pd = {};
late List<ImageData> imgList = [];
///
late List<Map<String, dynamic>> measuresList = [];
late Map<String, dynamic> signs = {};
List<String> signImages = [];
List<String> signTimes = []; //
@override
void initState() {
super.initState();
_getData();
}
///
Future<void> _onImageAdded(String localPath) async {
//
final res = await ApiService.uploadSaveFile(localPath);
final url = res['FILE_PATH'] as String;
setState(() {
imgList.add(ImageData(localPath: localPath, serverPath: url));
});
}
///
Future<void> _onImageRemoved(ImageData item) async {
if (item.serverPath != null) {
await ApiService.deleteSaveFile(item.serverPath!);
}
setState(() {
imgList.remove(item);
});
}
///
Future<void> _sign() async {
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
});
}
}
Widget _signListWidget() {
return Column(
children:
signImages.map((path) {
return Column(
children: [
const SizedBox(height: 10),
const Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
child: // ConstrainedBox BoxFit.contain
ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 200,
maxHeight: 150,
),
child: Image.file(
File(path),
//
fit: BoxFit.contain,
),
),
onTap: () {
presentOpaque(
SingleImageViewer(imageUrl: path),
context,
);
},
),
Column(
children: [
Container(
padding: const EdgeInsets.only(right: 5),
child: CustomButton(
text: 'X',
height: 30,
padding: const EdgeInsets.symmetric(horizontal: 10),
backgroundColor: Colors.red,
onPressed: () {
setState(() {
signImages.remove(path);
});
},
),
),
const SizedBox(height: 80),
],
),
],
),
],
);
}).toList(),
);
}
/// -1 1
Future<void> _submit(String status) async {
if (signImages.isEmpty) {
ToastUtil.showNormal(context, '请签字');
return;
}
String reasonText = '';
if (status == '1') {
} else {
await showDialog<String>(
context: context,
builder:
(_) => CustomAlertDialog(
title: '作废原因',
mode: DialogMode.input,
hintText: '请输入作废原因',
cancelText: '取消',
confirmText: '确定',
onInputConfirm: (text) {
reasonText = text;
},
),
);
if (reasonText.isEmpty) {
ToastUtil.showNormal(context, '请填写作废原因');
return;
}
}
// serverPath
final serverPathString = imgList
.map((e) => e.serverPath)
.where((s) => s.isNotEmpty)
.map((s) => s) // String? String
.join(',');
// measures
final Map<String, dynamic> formData = {};
//
formData['HOTWORK_ID'] = widget.HOTWORK_ID;
formData['SIGNTIME'] = signTimes.join(',');
formData['USER_ID'] = SessionService.instance.loginUserId;
formData['APPLY_STATUS'] = status;
formData['STEP_REASON'] = reasonText;
formData['IMG_PATH'] = serverPathString;
await showDialog<String>(
context: context,
builder:
(_) => CustomAlertDialog(
title: '提示',
content: '请确认' + (status == '1' ? "通过" : "作废") + '本作业票?',
cancelText: '取消',
confirmText: '确定',
onConfirm: () async {
LoadingDialogHelper.show(context);
try {
final result = await ApiService.saveSafeFunctionSure(
formData,
signImages,
);
LoadingDialogHelper.hide(context);
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
}
} catch (e) {
LoadingDialogHelper.hide(context);
ToastUtil.showNormal(context, '操作失败:$e');
}
},
),
);
}
///
Future<void> _getData() async {
final data = await ApiService.getHomeworkFindById(widget.HOTWORK_ID);
setState(() {
pd = data['pd'];
_getSigns(pd['HOTWORK_ID'] ?? '');
_getMeasures(pd['HOTWORK_ID'] ?? '');
});
}
Future<void> _getMeasures(String homework_id) async {
final data = await ApiService.listSignFinishMeasures(
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
);
setState(() {
measuresList = List<Map<String, dynamic>>.from(
data['finishMeasuresList'] ?? <Map<String, dynamic>>[],
);
});
}
Future<void> _getSigns(String homework_id) async {
final data = await ApiService.listSignFinished(
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
);
setState(() {
signs = data['signs'] ?? {};
});
}
///
Widget _bottomButtons() {
return Row(
spacing: 10,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: CustomButton(
height: 45,
textStyle: TextStyle(fontSize: 16, color: Colors.white),
text: '作废',
backgroundColor: Colors.red,
onPressed: () {
_submit('-1');
},
),
),
Expanded(
child: CustomButton(
textStyle: TextStyle(fontSize: 16, color: Colors.white),
text: '通过',
backgroundColor: Colors.green,
onPressed: () {
_submit('1');
},
),
),
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppbar(title: '安全交底人签字确认'),
body: SafeArea(
child: SingleChildScrollView(
padding: EdgeInsets.all(12),
child: Column(
spacing: 12,
children: [
// _setSafeDetailWidget(),
SpecialWorkFormBaseWork(
pd: pd,
measuresList: measuresList,
signs: signs,
baseImgPath: ApiService.baseImgPath,
isEditable: false,
onChooseLevel: () {},
onChooseHotworkUser: () {},
onAnalyzeTap: () {
pushPage(
HotworkGasList(HOTWORK_ID: widget.HOTWORK_ID),
context,
);
},
),
ItemListWidget.itemContainer(Column(
children: [RepairedPhotoSection(
title: '上传图片',
maxCount: 2,
mediaType: MediaType.image,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaRemoved: (path) {
final item = imgList.firstWhere((e) => e.localPath == path);
_onImageRemoved(item);
},
onAiIdentify: () {},
),
ItemListWidget.itemContainer(
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ListItemFactory.headerTitle('安全交底人'),
CustomButton(
text: '新增手写签字',
height: 36,
backgroundColor: Colors.green,
onPressed: () {
_sign();
},
),
],
),
if (signImages.isNotEmpty) _signListWidget(),
],
),
),],
),),
_bottomButtons(),
],
),
),
),
);
}
}

View File

@ -0,0 +1,335 @@
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/department_person_picker.dart';
import 'package:qhd_prevention/customWidget/department_picker.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/home/tap/tabList/special_wrok/SpecialWorkFormBaseWork.dart';
import 'package:qhd_prevention/tools/tools.dart';
import '../../../../../../customWidget/bottom_picker.dart';
import '../../../../../../customWidget/custom_alert_dialog.dart';
import '../../../../../../customWidget/photo_picker_row.dart';
import '../../../../../../customWidget/single_image_viewer.dart';
import '../../../../../../http/ApiService.dart';
import '../../../../../mine/mine_sign_page.dart';
import '../../../../../my_appbar.dart';
import '../../special_Wrok/MeasuresListWidget.dart';
import '../../special_Wrok/qtfx_work_detail/hotwork_gas_list.dart';
import '../WorkDetailFormWidget.dart';
import '../szaq_work_detail/SafeFunctionDialog.dart';
///
class HotworkDbbzDetail extends StatefulWidget {
const HotworkDbbzDetail({
super.key,
required this.HOTWORK_ID,
required this.flow,
});
final String HOTWORK_ID;
final String flow;
@override
State<HotworkDbbzDetail> createState() => _HotworkDbbzDetailState();
}
class _HotworkDbbzDetailState extends State<HotworkDbbzDetail> {
late bool isEditable = false;
///
late Map<String, dynamic> pd = {};
final TextEditingController _contentController = TextEditingController();
///
late List<Map<String, dynamic>> measuresList = [];
late Map<String, dynamic> signs = {};
List<String> signImages = [];
List<String> signTimes = []; //
@override
void initState() {
super.initState();
_getData();
}
///
Future<void> _sign() async {
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
});
}
}
Widget _signListWidget() {
return Column(
children:
signImages.map((path) {
return Column(
children: [
const SizedBox(height: 10),
const Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
child: // ConstrainedBox BoxFit.contain
ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 200,
maxHeight: 150,
),
child: Image.file(
File(path),
//
fit: BoxFit.contain,
),
),
onTap: () {
presentOpaque(
SingleImageViewer(imageUrl: path),
context,
);
},
),
Column(
children: [
Container(
padding: const EdgeInsets.only(right: 5),
child: CustomButton(
text: 'X',
height: 30,
padding: const EdgeInsets.symmetric(horizontal: 10),
backgroundColor: Colors.red,
onPressed: () {
setState(() {
signImages.remove(path);
});
},
),
),
const SizedBox(height: 80),
],
),
],
),
],
);
}).toList(),
);
}
/// -1 1
Future<void> _submit(String status) async {
if (signImages.isEmpty) {
ToastUtil.showNormal(context, '请签字');
return;
}
String reasonText = '';
String DESCR = _contentController.text.trim();
if (DESCR.isEmpty) {
ToastUtil.showNormal(context, '请输入安全管理部门意见');
return;
}
if (status == '1') {
} else {
await showDialog<String>(
context: context,
builder:
(_) => CustomAlertDialog(
title: '作废原因',
mode: DialogMode.input,
hintText: '请输入作废原因',
cancelText: '取消',
confirmText: '确定',
onInputConfirm: (text) {
reasonText = text;
},
),
);
if (reasonText.isEmpty) {
ToastUtil.showNormal(context, '请填写作废原因');
return;
}
}
// measures
final Map<String, dynamic> formData = {};
//
formData['HOTWORK_ID'] = widget.HOTWORK_ID;
formData['SIGNTIME'] = signTimes.join(',');
formData['USER_ID'] = SessionService.instance.loginUserId;
formData['APPLY_STATUS'] = status;
formData['STEP_REASON'] = reasonText;
formData['DESCR'] = DESCR;
await showDialog<String>(
context: context,
builder:
(_) => CustomAlertDialog(
title: '提示',
content: '请确认' + (status == '1' ? "通过" : "作废") + '本作业票?',
cancelText: '取消',
confirmText: '确定',
onConfirm: () async {
LoadingDialogHelper.show(context);
try {
final result = await ApiService.saveSafeFunctionSure(
formData,
signImages,
);
LoadingDialogHelper.hide(context);
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
}
} catch (e) {
LoadingDialogHelper.hide(context);
ToastUtil.showNormal(context, '操作失败:$e');
}
},
),
);
}
///
Future<void> _getData() async {
final data = await ApiService.getHomeworkFindById(widget.HOTWORK_ID);
setState(() {
pd = data['pd'];
_getSigns(pd['HOTWORK_ID'] ?? '');
_getMeasures(pd['HOTWORK_ID'] ?? '');
});
}
Future<void> _getMeasures(String homework_id) async {
final data = await ApiService.listSignFinishMeasures(
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
);
setState(() {
measuresList = List<Map<String, dynamic>>.from(
data['finishMeasuresList'] ?? <Map<String, dynamic>>[],
);
});
}
Future<void> _getSigns(String homework_id) async {
final data = await ApiService.listSignFinished(
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
);
setState(() {
signs = data['signs'] ?? {};
});
}
///
Widget _bottomButtons() {
return Row(
spacing: 10,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: CustomButton(
height: 45,
textStyle: TextStyle(fontSize: 16, color: Colors.white),
text: '作废',
backgroundColor: Colors.red,
onPressed: () {
_submit('-1');
},
),
),
Expanded(
child: CustomButton(
textStyle: TextStyle(fontSize: 16, color: Colors.white),
text: '通过',
backgroundColor: Colors.green,
onPressed: () {
_submit('1');
},
),
),
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppbar(title: '班长验票'),
body: SafeArea(
child: SingleChildScrollView(
padding: EdgeInsets.all(12),
child: Column(
spacing: 12,
children: [
// _setSafeDetailWidget(),
SpecialWorkFormBaseWork(
pd: pd,
measuresList: measuresList,
signs: signs,
baseImgPath: ApiService.baseImgPath,
isEditable: false,
onChooseLevel: () {},
onChooseHotworkUser: () {},
onAnalyzeTap: () {
pushPage(
HotworkGasList(HOTWORK_ID: widget.HOTWORK_ID),
context,
);
},
),
ItemListWidget.itemContainer(
Column(
children: [
ListItemFactory.createBuildMultilineInput(
'动火前在岗班长意见',
'请输入意见',
_contentController,
),
Divider(),
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ListItemFactory.headerTitle('动火前在岗班长'),
CustomButton(
text: '新增手写签字',
height: 36,
backgroundColor: Colors.green,
onPressed: () {
_sign();
},
),
],
),
if (signImages.isNotEmpty) _signListWidget(),
],
)
],
),
),
_bottomButtons(),
],
),
),
),
);
}
}

View File

@ -14,7 +14,7 @@ import '../../../../../../customWidget/bottom_picker.dart';
import '../../../../../../http/ApiService.dart';
import '../../../../../my_appbar.dart';
import '../../special_Wrok/qtfx_work_detail/hotwork_gas_list.dart';
import 'MeasuresListWidget.dart';
import '../../special_Wrok/MeasuresListWidget.dart';
enum EditUserType {
ANALYZE('分析单位', '分析单位负责人'),

View File

@ -0,0 +1,335 @@
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/department_person_picker.dart';
import 'package:qhd_prevention/customWidget/department_picker.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/home/tap/tabList/special_wrok/SpecialWorkFormBaseWork.dart';
import 'package:qhd_prevention/tools/tools.dart';
import '../../../../../../customWidget/bottom_picker.dart';
import '../../../../../../customWidget/custom_alert_dialog.dart';
import '../../../../../../customWidget/photo_picker_row.dart';
import '../../../../../../customWidget/single_image_viewer.dart';
import '../../../../../../http/ApiService.dart';
import '../../../../../mine/mine_sign_page.dart';
import '../../../../../my_appbar.dart';
import '../../special_Wrok/MeasuresListWidget.dart';
import '../../special_Wrok/qtfx_work_detail/hotwork_gas_list.dart';
import '../WorkDetailFormWidget.dart';
import '../szaq_work_detail/SafeFunctionDialog.dart';
///
class HotworkDhspDetail extends StatefulWidget {
const HotworkDhspDetail({
super.key,
required this.HOTWORK_ID,
required this.flow,
});
final String HOTWORK_ID;
final String flow;
@override
State<HotworkDhspDetail> createState() => _HotworkDhspDetailState();
}
class _HotworkDhspDetailState extends State<HotworkDhspDetail> {
late bool isEditable = false;
///
late Map<String, dynamic> pd = {};
final TextEditingController _contentController = TextEditingController();
///
late List<Map<String, dynamic>> measuresList = [];
late Map<String, dynamic> signs = {};
List<String> signImages = [];
List<String> signTimes = []; //
@override
void initState() {
super.initState();
_getData();
}
///
Future<void> _sign() async {
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
});
}
}
Widget _signListWidget() {
return Column(
children:
signImages.map((path) {
return Column(
children: [
const SizedBox(height: 10),
const Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
child: // ConstrainedBox BoxFit.contain
ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 200,
maxHeight: 150,
),
child: Image.file(
File(path),
//
fit: BoxFit.contain,
),
),
onTap: () {
presentOpaque(
SingleImageViewer(imageUrl: path),
context,
);
},
),
Column(
children: [
Container(
padding: const EdgeInsets.only(right: 5),
child: CustomButton(
text: 'X',
height: 30,
padding: const EdgeInsets.symmetric(horizontal: 10),
backgroundColor: Colors.red,
onPressed: () {
setState(() {
signImages.remove(path);
});
},
),
),
const SizedBox(height: 80),
],
),
],
),
],
);
}).toList(),
);
}
/// -1 1
Future<void> _submit(String status) async {
if (signImages.isEmpty) {
ToastUtil.showNormal(context, '请签字');
return;
}
String reasonText = '';
String DESCR = _contentController.text.trim();
if (DESCR.isEmpty) {
ToastUtil.showNormal(context, '请输入安全管理部门意见');
return;
}
if (status == '1') {
} else {
await showDialog<String>(
context: context,
builder:
(_) => CustomAlertDialog(
title: '作废原因',
mode: DialogMode.input,
hintText: '请输入作废原因',
cancelText: '取消',
confirmText: '确定',
onInputConfirm: (text) {
reasonText = text;
},
),
);
if (reasonText.isEmpty) {
ToastUtil.showNormal(context, '请填写作废原因');
return;
}
}
// measures
final Map<String, dynamic> formData = {};
//
formData['HOTWORK_ID'] = widget.HOTWORK_ID;
formData['SIGNTIME'] = signTimes.join(',');
formData['USER_ID'] = SessionService.instance.loginUserId;
formData['APPLY_STATUS'] = status;
formData['STEP_REASON'] = reasonText;
formData['DESCR'] = DESCR;
await showDialog<String>(
context: context,
builder:
(_) => CustomAlertDialog(
title: '提示',
content: '请确认' + (status == '1' ? "通过" : "作废") + '本作业票?',
cancelText: '取消',
confirmText: '确定',
onConfirm: () async {
LoadingDialogHelper.show(context);
try {
final result = await ApiService.saveSafeFunctionSure(
formData,
signImages,
);
LoadingDialogHelper.hide(context);
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
}
} catch (e) {
LoadingDialogHelper.hide(context);
ToastUtil.showNormal(context, '操作失败:$e');
}
},
),
);
}
///
Future<void> _getData() async {
final data = await ApiService.getHomeworkFindById(widget.HOTWORK_ID);
setState(() {
pd = data['pd'];
_getSigns(pd['HOTWORK_ID'] ?? '');
_getMeasures(pd['HOTWORK_ID'] ?? '');
});
}
Future<void> _getMeasures(String homework_id) async {
final data = await ApiService.listSignFinishMeasures(
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
);
setState(() {
measuresList = List<Map<String, dynamic>>.from(
data['finishMeasuresList'] ?? <Map<String, dynamic>>[],
);
});
}
Future<void> _getSigns(String homework_id) async {
final data = await ApiService.listSignFinished(
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
);
setState(() {
signs = data['signs'] ?? {};
});
}
///
Widget _bottomButtons() {
return Row(
spacing: 10,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: CustomButton(
height: 45,
textStyle: TextStyle(fontSize: 16, color: Colors.white),
text: '作废',
backgroundColor: Colors.red,
onPressed: () {
_submit('-1');
},
),
),
Expanded(
child: CustomButton(
textStyle: TextStyle(fontSize: 16, color: Colors.white),
text: '通过',
backgroundColor: Colors.green,
onPressed: () {
_submit('1');
},
),
),
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppbar(title: '审批部门意见'),
body: SafeArea(
child: SingleChildScrollView(
padding: EdgeInsets.all(12),
child: Column(
spacing: 12,
children: [
// _setSafeDetailWidget(),
SpecialWorkFormBaseWork(
pd: pd,
measuresList: measuresList,
signs: signs,
baseImgPath: ApiService.baseImgPath,
isEditable: false,
onChooseLevel: () {},
onChooseHotworkUser: () {},
onAnalyzeTap: () {
pushPage(
HotworkGasList(HOTWORK_ID: widget.HOTWORK_ID),
context,
);
},
),
ItemListWidget.itemContainer(
Column(
children: [
ListItemFactory.createBuildMultilineInput(
'动火审批部门意见',
'请输入意见',
_contentController,
),
Divider(),
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ListItemFactory.headerTitle('动火审批人'),
CustomButton(
text: '新增手写签字',
height: 36,
backgroundColor: Colors.green,
onPressed: () {
_sign();
},
),
],
),
if (signImages.isNotEmpty) _signListWidget(),
],
)
],
),
),
_bottomButtons(),
],
),
),
),
);
}
}

View File

@ -0,0 +1,358 @@
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/department_person_picker.dart';
import 'package:qhd_prevention/customWidget/department_picker.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
import 'package:qhd_prevention/tools/tools.dart';
import '../../../../../../customWidget/bottom_picker.dart';
import '../../../../../../customWidget/custom_alert_dialog.dart';
import '../../../../../../customWidget/single_image_viewer.dart';
import '../../../../../../http/ApiService.dart';
import '../../../../../mine/mine_sign_page.dart';
import '../../../../../my_appbar.dart';
import '../../special_Wrok/MeasuresListWidget.dart';
import '../../special_Wrok/qtfx_work_detail/hotwork_gas_list.dart';
import '../WorkDetailFormWidget.dart';
import '../szaq_work_detail/SafeFunctionDialog.dart';
///
class HotworkJhrDetail extends StatefulWidget {
const HotworkJhrDetail({
super.key,
required this.HOTWORK_ID,
required this.flow,
});
final String HOTWORK_ID;
final String flow;
@override
State<HotworkJhrDetail> createState() => _HotworkJhrDetailState();
}
class _HotworkJhrDetailState extends State<HotworkJhrDetail> {
late bool isEditable = false;
///
late Map<String, dynamic> pd = {};
///
late List<Map<String, dynamic>> measuresList = [];
late Map<String, dynamic> signs = {};
List<String> imagePaths = [];
List<String> signTimes = []; //
@override
void initState() {
super.initState();
_getData();
}
///
Future<void> _sign() async {
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
imagePaths.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
});
}
}
Widget _signListWidget() {
return Column(
children:
imagePaths.map((path) {
return Column(
children: [
const SizedBox(height: 10),
const Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
child: // ConstrainedBox BoxFit.contain
ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 200,
maxHeight: 150,
),
child: Image.file(
File(path),
//
fit: BoxFit.contain,
),
),
onTap: () {
presentOpaque(
SingleImageViewer(imageUrl: path),
context,
);
},
),
Column(
children: [
Container(
padding: const EdgeInsets.only(right: 5),
child: CustomButton(
text: 'X',
height: 30,
padding: const EdgeInsets.symmetric(horizontal: 10),
backgroundColor: Colors.red,
onPressed: () {
setState(() {
imagePaths.remove(path);
});
},
),
),
const SizedBox(height: 80),
],
),
],
),
],
);
}).toList(),
);
}
/// -1 1
Future<void> _submit(String status) async {
if (imagePaths.isEmpty) {
ToastUtil.showNormal(context, '请签字');
return;
}
String reasonText = '';
if (status == '1') {
} else {
await showDialog<String>(
context: context,
builder:
(_) => CustomAlertDialog(
title: '作废原因',
mode: DialogMode.input,
hintText: '请输入作废原因',
cancelText: '取消',
confirmText: '确定',
onInputConfirm: (text) {
reasonText = text;
},
),
);
if (reasonText.isEmpty) {
ToastUtil.showNormal(context, '请填写作废原因');
return;
}
}
final Map<String, dynamic> formData = {};
//
formData['HOTWORK_ID'] = widget.HOTWORK_ID;
formData['SIGNTIME'] = signTimes.join(',');
formData['USER_ID'] = SessionService.instance.loginUserId;
formData['APPLY_STATUS'] = status;
formData['STEP_REASON'] = reasonText;
await showDialog<String>(
context: context,
builder:
(_) => CustomAlertDialog(
title: '提示',
content: '请确认' + (status == '1' ? "通过" : "作废") + '本作业票?',
cancelText: '取消',
confirmText: '确定',
onConfirm: () async {
LoadingDialogHelper.show(context);
try {
final result = await ApiService.saveSafeFunctionSure(
formData,
imagePaths,
);
LoadingDialogHelper.hide(context);
if (result['result'] == 'success') {
ToastUtil.showSuccess(
context,
'保存成功',
);
Navigator.pop(context);
}
} catch (e) {
LoadingDialogHelper.hide(context);
ToastUtil.showNormal(context, '操作失败:$e');
}
},
),
);
}
///
Future<void> _getData() async {
final data = await ApiService.getHomeworkFindById(widget.HOTWORK_ID);
setState(() {
pd = data['pd'];
_getSigns(pd['HOTWORK_ID'] ?? '');
_getMeasures(pd['HOTWORK_ID'] ?? '');
});
}
Future<void> _getMeasures(String homework_id) async {
final data = await ApiService.listSignFinishMeasures(
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
);
setState(() {
measuresList = List<Map<String, dynamic>>.from(
data['finishMeasuresList'] ?? <Map<String, dynamic>>[],
);
});
}
Future<void> _getSigns(String homework_id) async {
final data = await ApiService.listSignFinished(
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
);
setState(() {
signs = data['signs'] ?? {};
});
}
///
Widget _setSafeDetailWidget() {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
padding: EdgeInsets.symmetric(horizontal: 5),
child: Column(
children: [
if (measuresList.isNotEmpty)
Column(
children: [
SizedBox(height: 5),
ListItemFactory.createBuildSimpleSection('安全防护措施'),
Container(
color: Colors.white,
child: MeasuresListWidget(
measuresList:
measuresList, // List<Map<String, dynamic>>
baseImgPath: ApiService.baseImgPath,
isAllowEdit: false,
isShowSign:true,
),
),
],
),
if (FormUtils.hasValue(signs, 'MEASURES_CONFIRM'))
Column(
children: [
SizedBox(height: 20),
ListItemFactory.createBuildSimpleSection('其他安全防护措施'),
Container(
color: Colors.white,
child: OtherMeasuresWidget(
otherMeasures: signs['MEASURES_CONFIRM'],
baseImgPath: ApiService.baseImgPath,
),
),
],
),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ListItemFactory.createBuildSimpleSection('监护人'),
CustomButton(
text: '新增手写签字',
height: 36,
backgroundColor: Colors.green,
onPressed: () {
_sign();
},
),
],
),
SizedBox(height: 10),
if (imagePaths.isNotEmpty) _signListWidget(),
],
),
);
}
///
Widget _bottomButtons() {
return Row(
spacing: 10,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: CustomButton(
height: 45,
textStyle: TextStyle(fontSize: 16, color: Colors.white),
text: '作废',
backgroundColor: Colors.red,
onPressed: () {
_submit('-1');
},
),
),
Expanded(
child: CustomButton(
textStyle: TextStyle(fontSize: 16, color: Colors.white),
text: '通过',
backgroundColor: Colors.green,
onPressed: () {
_submit('1');
},
),
),
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppbar(title: '监护人签字确认'),
body: SafeArea(
child: SingleChildScrollView(
padding: EdgeInsets.all(12),
child: Column(
children: [
// _card(_defaultDetail()),
WorkDetailFormWidget(
pd: pd,
isEditable: false,
onChooseLevel: (){},
onChooseHotworkUser: (){},
onAnalyzeTap: () {
pushPage(
HotworkGasList(HOTWORK_ID: widget.HOTWORK_ID),
context,
);
},
),
SizedBox(height: 20),
_setSafeDetailWidget(),
SizedBox(height: 20),
_bottomButtons(),
],
),
),
),
);
}
}

View File

@ -0,0 +1,317 @@
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/department_person_picker.dart';
import 'package:qhd_prevention/customWidget/department_picker.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/home/tap/tabList/special_wrok/SpecialWorkFormBaseWork.dart';
import 'package:qhd_prevention/tools/tools.dart';
import '../../../../../../customWidget/bottom_picker.dart';
import '../../../../../../customWidget/custom_alert_dialog.dart';
import '../../../../../../customWidget/photo_picker_row.dart';
import '../../../../../../customWidget/single_image_viewer.dart';
import '../../../../../../http/ApiService.dart';
import '../../../../../mine/mine_sign_page.dart';
import '../../../../../my_appbar.dart';
import '../../special_Wrok/MeasuresListWidget.dart';
import '../../special_Wrok/qtfx_work_detail/hotwork_gas_list.dart';
import '../WorkDetailFormWidget.dart';
import '../szaq_work_detail/SafeFunctionDialog.dart';
///
class HotworkJsjdDetail extends StatefulWidget {
const HotworkJsjdDetail({
super.key,
required this.HOTWORK_ID,
required this.flow,
});
final String HOTWORK_ID;
final String flow;
@override
State<HotworkJsjdDetail> createState() => _HotworkJsjdDetailState();
}
class _HotworkJsjdDetailState extends State<HotworkJsjdDetail> {
late bool isEditable = false;
///
late Map<String, dynamic> pd = {};
///
late List<Map<String, dynamic>> measuresList = [];
late Map<String, dynamic> signs = {};
List<String> signImages = [];
List<String> signTimes = []; //
@override
void initState() {
super.initState();
_getData();
}
///
Future<void> _sign() async {
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
});
}
}
Widget _signListWidget() {
return Column(
children:
signImages.map((path) {
return Column(
children: [
const SizedBox(height: 10),
const Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
child: // ConstrainedBox BoxFit.contain
ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 200,
maxHeight: 150,
),
child: Image.file(
File(path),
//
fit: BoxFit.contain,
),
),
onTap: () {
presentOpaque(
SingleImageViewer(imageUrl: path),
context,
);
},
),
Column(
children: [
Container(
padding: const EdgeInsets.only(right: 5),
child: CustomButton(
text: 'X',
height: 30,
padding: const EdgeInsets.symmetric(horizontal: 10),
backgroundColor: Colors.red,
onPressed: () {
setState(() {
signImages.remove(path);
});
},
),
),
const SizedBox(height: 80),
],
),
],
),
],
);
}).toList(),
);
}
/// -1 1
Future<void> _submit(String status) async {
if (signImages.isEmpty) {
ToastUtil.showNormal(context, '请签字');
return;
}
String reasonText = '';
if (status == '1') {
} else {
await showDialog<String>(
context: context,
builder:
(_) => CustomAlertDialog(
title: '作废原因',
mode: DialogMode.input,
hintText: '请输入作废原因',
cancelText: '取消',
confirmText: '确定',
onInputConfirm: (text) {
reasonText = text;
},
),
);
if (reasonText.isEmpty) {
ToastUtil.showNormal(context, '请填写作废原因');
return;
}
}
// measures
final Map<String, dynamic> formData = {};
//
formData['HOTWORK_ID'] = widget.HOTWORK_ID;
formData['SIGNTIME'] = signTimes.join(',');
formData['USER_ID'] = SessionService.instance.loginUserId;
formData['APPLY_STATUS'] = status;
formData['STEP_REASON'] = reasonText;
await showDialog<String>(
context: context,
builder:
(_) => CustomAlertDialog(
title: '提示',
content: '请确认' + (status == '1' ? "通过" : "作废") + '本作业票?',
cancelText: '取消',
confirmText: '确定',
onConfirm: () async {
LoadingDialogHelper.show(context);
try {
final result = await ApiService.saveSafeFunctionSure(
formData,
signImages,
);
LoadingDialogHelper.hide(context);
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
}
} catch (e) {
LoadingDialogHelper.hide(context);
ToastUtil.showNormal(context, '操作失败:$e');
}
},
),
);
}
///
Future<void> _getData() async {
final data = await ApiService.getHomeworkFindById(widget.HOTWORK_ID);
setState(() {
pd = data['pd'];
_getSigns(pd['HOTWORK_ID'] ?? '');
_getMeasures(pd['HOTWORK_ID'] ?? '');
});
}
Future<void> _getMeasures(String homework_id) async {
final data = await ApiService.listSignFinishMeasures(
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
);
setState(() {
measuresList = List<Map<String, dynamic>>.from(
data['finishMeasuresList'] ?? <Map<String, dynamic>>[],
);
});
}
Future<void> _getSigns(String homework_id) async {
final data = await ApiService.listSignFinished(
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
);
setState(() {
signs = data['signs'] ?? {};
});
}
///
Widget _bottomButtons() {
return Row(
spacing: 10,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: CustomButton(
height: 45,
textStyle: TextStyle(fontSize: 16, color: Colors.white),
text: '作废',
backgroundColor: Colors.red,
onPressed: () {
_submit('-1');
},
),
),
Expanded(
child: CustomButton(
textStyle: TextStyle(fontSize: 16, color: Colors.white),
text: '通过',
backgroundColor: Colors.green,
onPressed: () {
_submit('1');
},
),
),
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppbar(title: '接受交底人签字确认'),
body: SafeArea(
child: SingleChildScrollView(
padding: EdgeInsets.all(12),
child: Column(
spacing: 12,
children: [
// _setSafeDetailWidget(),
SpecialWorkFormBaseWork(
pd: pd,
measuresList: measuresList,
signs: signs,
baseImgPath: ApiService.baseImgPath,
isEditable: false,
onChooseLevel: () {},
onChooseHotworkUser: () {},
onAnalyzeTap: () {
pushPage(
HotworkGasList(HOTWORK_ID: widget.HOTWORK_ID),
context,
);
},
),
ItemListWidget.itemContainer(
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ListItemFactory.headerTitle('接受交底人'),
CustomButton(
text: '新增手写签字',
height: 36,
backgroundColor: Colors.green,
onPressed: () {
_sign();
},
),
],
),
if (signImages.isNotEmpty) _signListWidget(),
],
),
),
_bottomButtons(),
],
),
),
),
);
}
}

View File

@ -0,0 +1,378 @@
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/department_person_picker.dart';
import 'package:qhd_prevention/customWidget/department_picker.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/home/tap/tabList/special_wrok/SpecialWorkFormBaseWork.dart';
import 'package:qhd_prevention/tools/tools.dart';
import '../../../../../../customWidget/bottom_picker.dart';
import '../../../../../../customWidget/custom_alert_dialog.dart';
import '../../../../../../customWidget/photo_picker_row.dart';
import '../../../../../../customWidget/picker/CupertinoDatePicker.dart';
import '../../../../../../customWidget/single_image_viewer.dart';
import '../../../../../../http/ApiService.dart';
import '../../../../../mine/mine_sign_page.dart';
import '../../../../../my_appbar.dart';
import '../../special_Wrok/MeasuresListWidget.dart';
import '../../special_Wrok/qtfx_work_detail/hotwork_gas_list.dart';
import '../WorkDetailFormWidget.dart';
import '../szaq_work_detail/SafeFunctionDialog.dart';
///
class HotworkJszyDetail extends StatefulWidget {
const HotworkJszyDetail({
super.key,
required this.HOTWORK_ID,
required this.flow,
});
final String HOTWORK_ID;
final String flow;
@override
State<HotworkJszyDetail> createState() => _HotworkJszyDetailState();
}
class _HotworkJszyDetailState extends State<HotworkJszyDetail> {
late bool isEditable = false;
///
late Map<String, dynamic> pd = {};
///
String endTime = '';
///
late List<Map<String, dynamic>> measuresList = [];
late Map<String, dynamic> signs = {};
List<String> signImages = [];
List<String> signTimes = []; //
@override
void initState() {
super.initState();
_getData();
}
///
Future<void> _sign() async {
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
});
}
}
Widget _signListWidget() {
return Column(
children:
signImages.map((path) {
return Column(
children: [
const SizedBox(height: 10),
const Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
child: // ConstrainedBox BoxFit.contain
ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 200,
maxHeight: 150,
),
child: Image.file(
File(path),
//
fit: BoxFit.contain,
),
),
onTap: () {
presentOpaque(
SingleImageViewer(imageUrl: path),
context,
);
},
),
Column(
children: [
Container(
padding: const EdgeInsets.only(right: 5),
child: CustomButton(
text: 'X',
height: 30,
padding: const EdgeInsets.symmetric(horizontal: 10),
backgroundColor: Colors.red,
onPressed: () {
setState(() {
signImages.remove(path);
});
},
),
),
const SizedBox(height: 80),
],
),
],
),
],
);
}).toList(),
);
}
bool checkWorkTime(Map<String, dynamic> pd, BuildContext context) {
//
final start = DateTime.parse(pd['WORK_START_DATE'] as String);
final end = DateTime.parse(endTime);
//
if (end.isAtSameMomentAs(start) || end.isBefore(start)) {
ToastUtil.showNormal(context, '作业开始时间不能晚于或等于结束时间,请重新选择');
return false;
}
// 8 8 * 60 * 60 * 1000 ms
if (pd['WORK_LEVEL'] == '特级' || pd['WORK_LEVEL'] == '一级') {
final diffMs = end.difference(start).inMilliseconds;
const max8h = 8 * 60 * 60 * 1000;
if (diffMs >= max8h) {
ToastUtil.showNormal(context, '动火级别为特级或一级时动火作业开始时间与结束时间应不超过8小时请重新选择');
return false;
}
}
// 72 72 * 60 * 60 * 1000 ms
if (pd['WORK_LEVEL'] == '二级') {
final diffMs = end.difference(start).inMilliseconds;
const max72h = 72 * 60 * 60 * 1000;
if (diffMs >= max72h) {
ToastUtil.showNormal(context, '动火级别为二级时动火作业开始时间与结束时间应不超过72小时请重新选择');
return false;
}
}
return true;
}
/// -1 1
Future<void> _submit(String status) async {
if (signImages.isEmpty) {
ToastUtil.showNormal(context, '请签字');
return;
}
String reasonText = '';
if (status == '1') {
if (endTime.isEmpty) {
ToastUtil.showNormal(context, '请选择作业结束时间');
return;
}
if (!checkWorkTime(pd, context)) {
return;
}
} else {
await showDialog<String>(
context: context,
builder:
(_) => CustomAlertDialog(
title: '作废原因',
mode: DialogMode.input,
hintText: '请输入作废原因',
cancelText: '取消',
confirmText: '确定',
onInputConfirm: (text) {
reasonText = text;
},
),
);
if (reasonText.isEmpty) {
ToastUtil.showNormal(context, '请填写作废原因');
return;
}
}
// measures
final Map<String, dynamic> formData = {};
//
formData['HOTWORK_ID'] = widget.HOTWORK_ID;
formData['SIGNTIME'] = signTimes.join(',');
formData['USER_ID'] = SessionService.instance.loginUserId;
formData['APPLY_STATUS'] = status;
formData['STEP_REASON'] = reasonText;
formData['WORK_END_DATE'] = endTime;
await showDialog<String>(
context: context,
builder:
(_) => CustomAlertDialog(
title: '提示',
content: '请确认' + (status == '1' ? "通过" : "作废") + '本作业票?',
cancelText: '取消',
confirmText: '确定',
onConfirm: () async {
LoadingDialogHelper.show(context);
try {
final result = await ApiService.saveSafeFunctionSure(
formData,
signImages,
);
LoadingDialogHelper.hide(context);
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
}
} catch (e) {
LoadingDialogHelper.hide(context);
ToastUtil.showNormal(context, '操作失败:$e');
}
},
),
);
}
///
Future<void> _getData() async {
final data = await ApiService.getHomeworkFindById(widget.HOTWORK_ID);
setState(() {
pd = data['pd'];
_getSigns(pd['HOTWORK_ID'] ?? '');
_getMeasures(pd['HOTWORK_ID'] ?? '');
});
}
Future<void> _getMeasures(String homework_id) async {
final data = await ApiService.listSignFinishMeasures(
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
);
setState(() {
measuresList = List<Map<String, dynamic>>.from(
data['finishMeasuresList'] ?? <Map<String, dynamic>>[],
);
});
}
Future<void> _getSigns(String homework_id) async {
final data = await ApiService.listSignFinished(
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
);
setState(() {
signs = data['signs'] ?? {};
});
}
///
Widget _bottomButtons() {
return Row(
spacing: 10,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: CustomButton(
height: 45,
textStyle: TextStyle(fontSize: 16, color: Colors.white),
text: '作废',
backgroundColor: Colors.red,
onPressed: () {
_submit('-1');
},
),
),
Expanded(
child: CustomButton(
textStyle: TextStyle(fontSize: 16, color: Colors.white),
text: '通过',
backgroundColor: Colors.green,
onPressed: () {
_submit('1');
},
),
),
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppbar(title: '作业结束时间选择'),
body: SafeArea(
child: SingleChildScrollView(
padding: EdgeInsets.all(12),
child: Column(
spacing: 12,
children: [
// _setSafeDetailWidget(),
SpecialWorkFormBaseWork(
pd: pd,
measuresList: measuresList,
signs: signs,
baseImgPath: ApiService.baseImgPath,
isEditable: false,
onChooseLevel: () {},
onChooseHotworkUser: () {},
onAnalyzeTap: () {
pushPage(
HotworkGasList(HOTWORK_ID: widget.HOTWORK_ID),
context,
);
},
),
ItemListWidget.itemContainer(
Column(
children: [
GestureDetector(
child: ListItemFactory.createRowSpaceBetweenItem(leftText: '作业结束时间', rightText: endTime.isEmpty?'请选择':endTime, isRight: true),
onTap: () async {
DateTime? picked = await BottomDateTimePicker.showDate(context);
if (picked != null) {
setState(() {
endTime = DateFormat('yyyy-MM-dd HH:mm').format(picked);
});
}
},
),
Divider(),
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ListItemFactory.headerTitle('作业结束时间负责人'),
CustomButton(
text: '新增手写签字',
height: 36,
backgroundColor: Colors.green,
onPressed: () {
_sign();
},
),
],
),
if (signImages.isNotEmpty) _signListWidget(),
],
),
],
),
),
_bottomButtons(),
],
),
),
),
);
}
}

View File

@ -0,0 +1,351 @@
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/department_person_picker.dart';
import 'package:qhd_prevention/customWidget/department_picker.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/home/tap/tabList/special_wrok/SpecialWorkFormBaseWork.dart';
import 'package:qhd_prevention/tools/tools.dart';
import '../../../../../../customWidget/bottom_picker.dart';
import '../../../../../../customWidget/custom_alert_dialog.dart';
import '../../../../../../customWidget/photo_picker_row.dart';
import '../../../../../../customWidget/picker/CupertinoDatePicker.dart';
import '../../../../../../customWidget/single_image_viewer.dart';
import '../../../../../../http/ApiService.dart';
import '../../../../../mine/mine_sign_page.dart';
import '../../../../../my_appbar.dart';
import '../../special_Wrok/MeasuresListWidget.dart';
import '../../special_Wrok/qtfx_work_detail/hotwork_gas_list.dart';
import '../WorkDetailFormWidget.dart';
import '../szaq_work_detail/SafeFunctionDialog.dart';
///
class HotworkKszyDetail extends StatefulWidget {
const HotworkKszyDetail({
super.key,
required this.HOTWORK_ID,
required this.flow,
});
final String HOTWORK_ID;
final String flow;
@override
State<HotworkKszyDetail> createState() => _HotworkKszyDetailState();
}
class _HotworkKszyDetailState extends State<HotworkKszyDetail> {
late bool isEditable = false;
///
late Map<String, dynamic> pd = {};
///
String startTime = '';
///
late List<Map<String, dynamic>> measuresList = [];
late Map<String, dynamic> signs = {};
List<String> signImages = [];
List<String> signTimes = []; //
@override
void initState() {
super.initState();
_getData();
}
///
Future<void> _sign() async {
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
});
}
}
Widget _signListWidget() {
return Column(
children:
signImages.map((path) {
return Column(
children: [
const SizedBox(height: 10),
const Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
child: // ConstrainedBox BoxFit.contain
ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 200,
maxHeight: 150,
),
child: Image.file(
File(path),
//
fit: BoxFit.contain,
),
),
onTap: () {
presentOpaque(
SingleImageViewer(imageUrl: path),
context,
);
},
),
Column(
children: [
Container(
padding: const EdgeInsets.only(right: 5),
child: CustomButton(
text: 'X',
height: 30,
padding: const EdgeInsets.symmetric(horizontal: 10),
backgroundColor: Colors.red,
onPressed: () {
setState(() {
signImages.remove(path);
});
},
),
),
const SizedBox(height: 80),
],
),
],
),
],
);
}).toList(),
);
}
/// -1 1
Future<void> _submit(String status) async {
if (signImages.isEmpty) {
ToastUtil.showNormal(context, '请签字');
return;
}
String reasonText = '';
if (status == '1') {
if (startTime.isEmpty) {
ToastUtil.showNormal(context, '请选择作业开始时间');
return;
}
final workStart = DateTime.parse(pd['WORK_START_DATE'] as String);
final analyzeTime = DateTime.parse(pd['ANALYZE_TIME'] as String);
final intervalMs = workStart.difference(analyzeTime).inMilliseconds;
const thresholdMs = 30 * 60 * 1000;
if (intervalMs >= thresholdMs) {
ToastUtil.showNormal(context, '气体分析时间与开始时间间隔超过30分钟请重新上传气体检测结果');
return;
}
} else {
await showDialog<String>(
context: context,
builder:
(_) => CustomAlertDialog(
title: '作废原因',
mode: DialogMode.input,
hintText: '请输入作废原因',
cancelText: '取消',
confirmText: '确定',
onInputConfirm: (text) {
reasonText = text;
},
),
);
if (reasonText.isEmpty) {
ToastUtil.showNormal(context, '请填写作废原因');
return;
}
}
// measures
final Map<String, dynamic> formData = {};
//
formData['HOTWORK_ID'] = widget.HOTWORK_ID;
formData['SIGNTIME'] = signTimes.join(',');
formData['USER_ID'] = SessionService.instance.loginUserId;
formData['APPLY_STATUS'] = status;
formData['STEP_REASON'] = reasonText;
formData['WORK_START_DATE'] = startTime;
await showDialog<String>(
context: context,
builder:
(_) => CustomAlertDialog(
title: '提示',
content: '请确认' + (status == '1' ? "通过" : "作废") + '本作业票?',
cancelText: '取消',
confirmText: '确定',
onConfirm: () async {
LoadingDialogHelper.show(context);
try {
final result = await ApiService.saveSafeFunctionSure(
formData,
signImages,
);
LoadingDialogHelper.hide(context);
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
}
} catch (e) {
LoadingDialogHelper.hide(context);
ToastUtil.showNormal(context, '操作失败:$e');
}
},
),
);
}
///
Future<void> _getData() async {
final data = await ApiService.getHomeworkFindById(widget.HOTWORK_ID);
setState(() {
pd = data['pd'];
_getSigns(pd['HOTWORK_ID'] ?? '');
_getMeasures(pd['HOTWORK_ID'] ?? '');
});
}
Future<void> _getMeasures(String homework_id) async {
final data = await ApiService.listSignFinishMeasures(
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
);
setState(() {
measuresList = List<Map<String, dynamic>>.from(
data['finishMeasuresList'] ?? <Map<String, dynamic>>[],
);
});
}
Future<void> _getSigns(String homework_id) async {
final data = await ApiService.listSignFinished(
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
);
setState(() {
signs = data['signs'] ?? {};
});
}
///
Widget _bottomButtons() {
return Row(
spacing: 10,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: CustomButton(
height: 45,
textStyle: TextStyle(fontSize: 16, color: Colors.white),
text: '作废',
backgroundColor: Colors.red,
onPressed: () {
_submit('-1');
},
),
),
Expanded(
child: CustomButton(
textStyle: TextStyle(fontSize: 16, color: Colors.white),
text: '通过',
backgroundColor: Colors.green,
onPressed: () {
_submit('1');
},
),
),
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppbar(title: '作业开始时间选择'),
body: SafeArea(
child: SingleChildScrollView(
padding: EdgeInsets.all(12),
child: Column(
spacing: 12,
children: [
// _setSafeDetailWidget(),
SpecialWorkFormBaseWork(
pd: pd,
measuresList: measuresList,
signs: signs,
baseImgPath: ApiService.baseImgPath,
isEditable: false,
onChooseLevel: () {},
onChooseHotworkUser: () {},
onAnalyzeTap: () {
pushPage(
HotworkGasList(HOTWORK_ID: widget.HOTWORK_ID),
context,
);
},
),
ItemListWidget.itemContainer(
Column(
children: [
GestureDetector(
child: ListItemFactory.createRowSpaceBetweenItem(leftText: '作业开始时间', rightText: startTime.isEmpty?'请选择':startTime, isRight: true),
onTap: () async {
DateTime? picked = await BottomDateTimePicker.showDate(context);
if (picked != null) {
setState(() {
startTime = DateFormat('yyyy-MM-dd HH:mm').format(picked);
});
}
},
),
Divider(),
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ListItemFactory.headerTitle('作业开始时间负责人'),
CustomButton(
text: '新增手写签字',
height: 36,
backgroundColor: Colors.green,
onPressed: () {
_sign();
},
),
],
),
if (signImages.isNotEmpty) _signListWidget(),
],
),
],
),
),
_bottomButtons(),
],
),
),
),
);
}
}

View File

@ -2,7 +2,17 @@ import 'package:flutter/material.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/dh_work_detai/hotwork_apply_detail.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/aqcs_work_detail/hotwork_safe_func_sure.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/aqgl_work_detail/hotwork_aqgl_detail.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/aqjd_work_detail/hotwork_aqjd_detail.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dbbz_work_detail/hotwork_dbbz_detail.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dhsp_work_detail/hotwork_dhsp_detail.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/jhr_work_detail/hotwork_jhr_detail.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/jszy_work_detail/hotwork_jszy_detail.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/kszy_work_detail/hotwork_kszy_detail.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/szaq_work_detail/hotwork_set_safe_detail.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/szdw_work_detail/hotwork_szdw_detail.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/ysgd/hotwork_ysgd_detail.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/zyfz_work_detail/hotwork_zyfz_detail.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/tools/tools.dart';
import '../../../../../customWidget/bottom_picker.dart';
@ -10,6 +20,7 @@ import '../../../../../customWidget/custom_button.dart';
import '../../../../../customWidget/search_bar_widget.dart';
import '../../../../../http/ApiService.dart';
import '../special_Wrok/qtfx_work_detail/hotwork_gas_list.dart';
import 'jsjd_work_detail/hotwork_jsjd_detail.dart';
class SpecialWorkListPage extends StatefulWidget {
final String flow;
@ -191,7 +202,7 @@ class _SpecialWorkListPageState extends State<SpecialWorkListPage> {
_fetchData();
break;
case '气体检测':
pushPage(HotworkGasList(HOTWORK_ID: item['HOTWORK_ID'], addFlag:true), context);
await pushPage(HotworkGasList(HOTWORK_ID: item['HOTWORK_ID'], addFlag:true), context);
break;
case '设置安全措施确认人':
await pushPage(HotworkSetSafeDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
@ -201,46 +212,70 @@ class _SpecialWorkListPageState extends State<SpecialWorkListPage> {
break;
case '监护人签字':
routeName = '/hotwork-guardian-detail';
await pushPage(HotworkJhrDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
break;
case '安全交底人签字':
routeName = '/hotwork-confess-detail';
await pushPage(HotworkAqjdDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
break;
case '接受交底人签字':
routeName = '/hotwork-acceptconfess-detail';
await pushPage(HotworkJsjdDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
break;
case '作业负责人签字':
routeName = '/hotwork-confirm-detail';
await pushPage(HotworkZyfzDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
break;
case '所在单位签字':
routeName = '/hotwork-leader-detail';
await pushPage(HotworkSzdwDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
break;
case '安全管理部门签字':
routeName = '/hotwork-audit-detail';
await pushPage(HotworkAqglDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
break;
case '审批人签字':
routeName = '/hotwork-approve-detail';
await pushPage(HotworkDhspDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
break;
case '当班班长验票':
routeName = '/hotwork-monitor-detail';
await pushPage(HotworkDbbzDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
break;
case '开始作业':
routeName = '/hotwork-startwork-detail';
await pushPage(HotworkKszyDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
break;
case '结束作业':
routeName = '/hotwork-endwork-detail';
await pushPage(HotworkJszyDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
break;
case '验收签字':
routeName = '/hotwork-accept-detail';
await pushPage(HotworkYsgdDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
break;
default:
routeName = '/hotwork-detail';
}
Navigator.pushNamed(
context,
routeName,
arguments: {'HOTWORK_ID': item['HOTWORK_ID'], 'flow': widget.flow},
);
setState(() {
_fetchSteps();
_fetchData();
});
// Navigator.pushNamed(
// context,
// routeName,
// arguments: {'HOTWORK_ID': item['HOTWORK_ID'], 'flow': widget.flow},
// );
}
Widget _buildFlowStepItem({

View File

@ -11,13 +11,11 @@ import 'package:qhd_prevention/customWidget/department_picker.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
import 'package:qhd_prevention/tools/tools.dart';
import '../../../../../../customWidget/bottom_picker.dart';
import '../../../../../../customWidget/custom_alert_dialog.dart';
import '../../../../../../customWidget/single_image_viewer.dart';
import '../../../../../../http/ApiService.dart';
import '../../../../../mine/mine_sign_page.dart';
import '../../../../../my_appbar.dart';
import '../../special_Wrok/dh_work_detai/MeasuresListWidget.dart';
import '../../special_Wrok/qtfx_work_detail/hotwork_gas_list.dart';
import '../WorkDetailFormWidget.dart';
import 'SafeFunctionDialog.dart';
@ -38,18 +36,11 @@ class HotworkSetSafeDetail extends StatefulWidget {
class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
late bool isEditable = false;
final levelList = ["特级", "一级", "二级"];
///
late String msg = 'add';
///
late Map<String, dynamic> pd = {};
late List<Map<String, dynamic>> measuresList = [];
///
late List<dynamic> workUserList = [];
///
late List<MeasureItem> measuresListCopy = [];
List<String> imagePaths = [];
@ -58,7 +49,6 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
void initState() {
super.initState();
_getData();
_getHotWorkNameList();
addMeasuresListCopy();
}
@ -339,7 +329,7 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
if (result['result'] == 'success') {
ToastUtil.showSuccess(
context,
status == '1' ? '提交成功' : '已暂存',
'保存成功',
);
Navigator.pop(context);
}
@ -359,15 +349,6 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
}
}
Future<void> _getHotWorkNameList() async {
final result = await ApiService.getHotWorkNameList();
setState(() {
workUserList = result['varList'] ?? '';
List<String> names =
workUserList.map((item) => item['NAME'] as String).toList();
});
}
///
Future<void> _getData() async {
final data = await ApiService.getHomeworkFindById(widget.HOTWORK_ID);

View File

@ -0,0 +1,335 @@
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/department_person_picker.dart';
import 'package:qhd_prevention/customWidget/department_picker.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/home/tap/tabList/special_wrok/SpecialWorkFormBaseWork.dart';
import 'package:qhd_prevention/tools/tools.dart';
import '../../../../../../customWidget/bottom_picker.dart';
import '../../../../../../customWidget/custom_alert_dialog.dart';
import '../../../../../../customWidget/photo_picker_row.dart';
import '../../../../../../customWidget/single_image_viewer.dart';
import '../../../../../../http/ApiService.dart';
import '../../../../../mine/mine_sign_page.dart';
import '../../../../../my_appbar.dart';
import '../../special_Wrok/MeasuresListWidget.dart';
import '../../special_Wrok/qtfx_work_detail/hotwork_gas_list.dart';
import '../WorkDetailFormWidget.dart';
import '../szaq_work_detail/SafeFunctionDialog.dart';
///
class HotworkSzdwDetail extends StatefulWidget {
const HotworkSzdwDetail({
super.key,
required this.HOTWORK_ID,
required this.flow,
});
final String HOTWORK_ID;
final String flow;
@override
State<HotworkSzdwDetail> createState() => _HotworkSzdwDetailState();
}
class _HotworkSzdwDetailState extends State<HotworkSzdwDetail> {
late bool isEditable = false;
///
late Map<String, dynamic> pd = {};
final TextEditingController _contentController = TextEditingController();
///
late List<Map<String, dynamic>> measuresList = [];
late Map<String, dynamic> signs = {};
List<String> signImages = [];
List<String> signTimes = []; //
@override
void initState() {
super.initState();
_getData();
}
///
Future<void> _sign() async {
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
});
}
}
Widget _signListWidget() {
return Column(
children:
signImages.map((path) {
return Column(
children: [
const SizedBox(height: 10),
const Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
child: // ConstrainedBox BoxFit.contain
ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 200,
maxHeight: 150,
),
child: Image.file(
File(path),
//
fit: BoxFit.contain,
),
),
onTap: () {
presentOpaque(
SingleImageViewer(imageUrl: path),
context,
);
},
),
Column(
children: [
Container(
padding: const EdgeInsets.only(right: 5),
child: CustomButton(
text: 'X',
height: 30,
padding: const EdgeInsets.symmetric(horizontal: 10),
backgroundColor: Colors.red,
onPressed: () {
setState(() {
signImages.remove(path);
});
},
),
),
const SizedBox(height: 80),
],
),
],
),
],
);
}).toList(),
);
}
/// -1 1
Future<void> _submit(String status) async {
if (signImages.isEmpty) {
ToastUtil.showNormal(context, '请签字');
return;
}
String reasonText = '';
String DESCR = _contentController.text.trim();
if (DESCR.isEmpty) {
ToastUtil.showNormal(context, '请输入所在单位负责人意见');
return;
}
if (status == '1') {
} else {
await showDialog<String>(
context: context,
builder:
(_) => CustomAlertDialog(
title: '作废原因',
mode: DialogMode.input,
hintText: '请输入作废原因',
cancelText: '取消',
confirmText: '确定',
onInputConfirm: (text) {
reasonText = text;
},
),
);
if (reasonText.isEmpty) {
ToastUtil.showNormal(context, '请填写作废原因');
return;
}
}
// measures
final Map<String, dynamic> formData = {};
//
formData['HOTWORK_ID'] = widget.HOTWORK_ID;
formData['SIGNTIME'] = signTimes.join(',');
formData['USER_ID'] = SessionService.instance.loginUserId;
formData['APPLY_STATUS'] = status;
formData['STEP_REASON'] = reasonText;
formData['DESCR'] = DESCR;
await showDialog<String>(
context: context,
builder:
(_) => CustomAlertDialog(
title: '提示',
content: '请确认' + (status == '1' ? "通过" : "作废") + '本作业票?',
cancelText: '取消',
confirmText: '确定',
onConfirm: () async {
LoadingDialogHelper.show(context);
try {
final result = await ApiService.saveSafeFunctionSure(
formData,
signImages,
);
LoadingDialogHelper.hide(context);
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
}
} catch (e) {
LoadingDialogHelper.hide(context);
ToastUtil.showNormal(context, '操作失败:$e');
}
},
),
);
}
///
Future<void> _getData() async {
final data = await ApiService.getHomeworkFindById(widget.HOTWORK_ID);
setState(() {
pd = data['pd'];
_getSigns(pd['HOTWORK_ID'] ?? '');
_getMeasures(pd['HOTWORK_ID'] ?? '');
});
}
Future<void> _getMeasures(String homework_id) async {
final data = await ApiService.listSignFinishMeasures(
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
);
setState(() {
measuresList = List<Map<String, dynamic>>.from(
data['finishMeasuresList'] ?? <Map<String, dynamic>>[],
);
});
}
Future<void> _getSigns(String homework_id) async {
final data = await ApiService.listSignFinished(
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
);
setState(() {
signs = data['signs'] ?? {};
});
}
///
Widget _bottomButtons() {
return Row(
spacing: 10,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: CustomButton(
height: 45,
textStyle: TextStyle(fontSize: 16, color: Colors.white),
text: '作废',
backgroundColor: Colors.red,
onPressed: () {
_submit('-1');
},
),
),
Expanded(
child: CustomButton(
textStyle: TextStyle(fontSize: 16, color: Colors.white),
text: '通过',
backgroundColor: Colors.green,
onPressed: () {
_submit('1');
},
),
),
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppbar(title: '所在单位意见'),
body: SafeArea(
child: SingleChildScrollView(
padding: EdgeInsets.all(12),
child: Column(
spacing: 12,
children: [
// _setSafeDetailWidget(),
SpecialWorkFormBaseWork(
pd: pd,
measuresList: measuresList,
signs: signs,
baseImgPath: ApiService.baseImgPath,
isEditable: false,
onChooseLevel: () {},
onChooseHotworkUser: () {},
onAnalyzeTap: () {
pushPage(
HotworkGasList(HOTWORK_ID: widget.HOTWORK_ID),
context,
);
},
),
ItemListWidget.itemContainer(
Column(
children: [
ListItemFactory.createBuildMultilineInput(
'所在单位负责人意见',
'请输入意见',
_contentController,
),
Divider(),
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ListItemFactory.headerTitle('所在单位负责人'),
CustomButton(
text: '新增手写签字',
height: 36,
backgroundColor: Colors.green,
onPressed: () {
_sign();
},
),
],
),
if (signImages.isNotEmpty) _signListWidget(),
],
)
],
),
),
_bottomButtons(),
],
),
),
),
);
}
}

View File

@ -0,0 +1,418 @@
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/department_person_picker.dart';
import 'package:qhd_prevention/customWidget/department_picker.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/home/tap/tabList/special_wrok/SpecialWorkFormBaseWork.dart';
import 'package:qhd_prevention/tools/tools.dart';
import '../../../../../../customWidget/bottom_picker.dart';
import '../../../../../../customWidget/custom_alert_dialog.dart';
import '../../../../../../customWidget/photo_picker_row.dart';
import '../../../../../../customWidget/picker/CupertinoDatePicker.dart';
import '../../../../../../customWidget/single_image_viewer.dart';
import '../../../../../../http/ApiService.dart';
import '../../../../../mine/mine_sign_page.dart';
import '../../../../../my_appbar.dart';
import '../../special_Wrok/MeasuresListWidget.dart';
import '../../special_Wrok/qtfx_work_detail/hotwork_gas_list.dart';
import '../WorkDetailFormWidget.dart';
import '../szaq_work_detail/SafeFunctionDialog.dart';
///
class ImageData {
String localPath;
String serverPath;
ImageData({required this.localPath, required this.serverPath});
}
class HotworkYsgdDetail extends StatefulWidget {
const HotworkYsgdDetail({
super.key,
required this.HOTWORK_ID,
required this.flow,
});
final String HOTWORK_ID;
final String flow;
@override
State<HotworkYsgdDetail> createState() => _HotworkYsgdDetailState();
}
class _HotworkYsgdDetailState extends State<HotworkYsgdDetail> {
late bool isEditable = false;
///
late Map<String, dynamic> pd = {};
///
String startTime = '';
///
final TextEditingController _contentController = TextEditingController();
late List<ImageData> imgList = [];
///
late List<Map<String, dynamic>> measuresList = [];
late Map<String, dynamic> signs = {};
List<String> signImages = [];
List<String> signTimes = []; //
@override
void initState() {
super.initState();
_getData();
}
///
Future<void> _onImageAdded(String localPath) async {
//
final res = await ApiService.uploadSaveFile(localPath);
final url = res['FILE_PATH'] as String;
setState(() {
imgList.add(ImageData(localPath: localPath, serverPath: url));
});
}
///
Future<void> _onImageRemoved(ImageData item) async {
if (item.serverPath != null) {
await ApiService.deleteSaveFile(item.serverPath!);
}
setState(() {
imgList.remove(item);
});
}
///
Future<void> _sign() async {
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
});
}
}
Widget _signListWidget() {
return Column(
children:
signImages.map((path) {
return Column(
children: [
const SizedBox(height: 10),
const Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
child: // ConstrainedBox BoxFit.contain
ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 200,
maxHeight: 150,
),
child: Image.file(
File(path),
//
fit: BoxFit.contain,
),
),
onTap: () {
presentOpaque(
SingleImageViewer(imageUrl: path),
context,
);
},
),
Column(
children: [
Container(
padding: const EdgeInsets.only(right: 5),
child: CustomButton(
text: 'X',
height: 30,
padding: const EdgeInsets.symmetric(horizontal: 10),
backgroundColor: Colors.red,
onPressed: () {
setState(() {
signImages.remove(path);
});
},
),
),
const SizedBox(height: 80),
],
),
],
),
],
);
}).toList(),
);
}
/// -1 1
Future<void> _submit(String status) async {
if (signImages.isEmpty) {
ToastUtil.showNormal(context, '请签字');
return;
}
String DESCR = _contentController.text.trim();
if (DESCR.isEmpty) {
ToastUtil.showNormal(context, '请输入负责人意见');
return;
}
String reasonText = '';
if (status == '1') {
if (startTime.isEmpty) {
ToastUtil.showNormal(context, '请选择验收时间');
return;
}
// final workStart = DateTime.parse(pd['WORK_START_DATE'] as String);
final endTime = DateTime.parse(pd['WORK_END_DATE'] as String);
final acceptTime = DateTime.parse(startTime);
final intervalMs = endTime.difference(acceptTime).inMilliseconds;
const thresholdMs = 30 * 60 * 1000;
if (intervalMs >= thresholdMs) {
ToastUtil.showNormal(context, '请在作业结束30分钟内完成验收');
return;
}
if (imgList.isNotEmpty) {
ToastUtil.showNormal(context, '请上传验收视频');
return;
}
} else {
await showDialog<String>(
context: context,
builder:
(_) => CustomAlertDialog(
title: '作废原因',
mode: DialogMode.input,
hintText: '请输入作废原因',
cancelText: '取消',
confirmText: '确定',
onInputConfirm: (text) {
reasonText = text;
},
),
);
if (reasonText.isEmpty) {
ToastUtil.showNormal(context, '请填写作废原因');
return;
}
}
final serverPathString = imgList
.map((e) => e.serverPath)
.where((s) => s.isNotEmpty)
.map((s) => s) // String? String
.join(',');
// measures
final Map<String, dynamic> formData = {};
//
formData['HOTWORK_ID'] = widget.HOTWORK_ID;
formData['SIGNTIME'] = signTimes.join(',');
formData['USER_ID'] = SessionService.instance.loginUserId;
formData['APPLY_STATUS'] = status;
formData['STEP_REASON'] = reasonText;
formData['ACCEPT_TIME'] = startTime;
formData['DESCR'] = DESCR;
formData['VIDEO_PATH'] = serverPathString;
await showDialog<String>(
context: context,
builder:
(_) => CustomAlertDialog(
title: '提示',
content: '请确认' + (status == '1' ? "通过" : "作废") + '本作业票?',
cancelText: '取消',
confirmText: '确定',
onConfirm: () async {
LoadingDialogHelper.show(context);
try {
final result = await ApiService.saveSafeFunctionSure(
formData,
signImages,
);
LoadingDialogHelper.hide(context);
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
}
} catch (e) {
LoadingDialogHelper.hide(context);
ToastUtil.showNormal(context, '操作失败:$e');
}
},
),
);
}
///
Future<void> _getData() async {
final data = await ApiService.getHomeworkFindById(widget.HOTWORK_ID);
setState(() {
pd = data['pd'];
_getSigns(pd['HOTWORK_ID'] ?? '');
_getMeasures(pd['HOTWORK_ID'] ?? '');
});
}
Future<void> _getMeasures(String homework_id) async {
final data = await ApiService.listSignFinishMeasures(
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
);
setState(() {
measuresList = List<Map<String, dynamic>>.from(
data['finishMeasuresList'] ?? <Map<String, dynamic>>[],
);
});
}
Future<void> _getSigns(String homework_id) async {
final data = await ApiService.listSignFinished(
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
);
setState(() {
signs = data['signs'] ?? {};
});
}
///
Widget _bottomButtons() {
return Row(
spacing: 10,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: CustomButton(
height: 45,
textStyle: TextStyle(fontSize: 16, color: Colors.white),
text: '作废',
backgroundColor: Colors.red,
onPressed: () {
_submit('-1');
},
),
),
Expanded(
child: CustomButton(
textStyle: TextStyle(fontSize: 16, color: Colors.white),
text: '通过',
backgroundColor: Colors.green,
onPressed: () {
_submit('1');
},
),
),
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppbar(title: '完工验收'),
body: SafeArea(
child: SingleChildScrollView(
padding: EdgeInsets.all(12),
child: Column(
spacing: 12,
children: [
// _setSafeDetailWidget(),
SpecialWorkFormBaseWork(
pd: pd,
measuresList: measuresList,
signs: signs,
baseImgPath: ApiService.baseImgPath,
isEditable: false,
onChooseLevel: () {},
onChooseHotworkUser: () {},
onAnalyzeTap: () {
pushPage(
HotworkGasList(HOTWORK_ID: widget.HOTWORK_ID),
context,
);
},
),
ItemListWidget.itemContainer(
Column(
children: [
ListItemFactory.createBuildMultilineInput(
'完工验收',
'请输入意见',
_contentController,
),
Divider(),
GestureDetector(
child: ListItemFactory.createRowSpaceBetweenItem(leftText: '验收时间', rightText: startTime.isEmpty?'请选择':startTime, isRight: true),
onTap: () async {
DateTime? picked = await BottomDateTimePicker.showDate(context);
if (picked != null) {
setState(() {
startTime = DateFormat('yyyy-MM-dd HH:mm').format(picked);
});
FocusHelper.clearFocus(context);
}
},
),
Divider(),
RepairedPhotoSection(
title: '验收视频',
maxCount: 1,
mediaType: MediaType.video,
horizontalPadding: 0,
onChanged: (paths) {},
onMediaAdded: _onImageAdded,
onMediaRemoved: (path) {
final item = imgList.firstWhere((e) => e.localPath == path);
_onImageRemoved(item);
},
onAiIdentify: () {},
),
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ListItemFactory.headerTitle('验收部门负责人'),
CustomButton(
text: '新增手写签字',
height: 36,
backgroundColor: Colors.green,
onPressed: () {
_sign();
},
),
],
),
if (signImages.isNotEmpty) _signListWidget(),
],
),
],
),
),
_bottomButtons(),
],
),
),
),
);
}
}

View File

@ -0,0 +1,334 @@
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/department_person_picker.dart';
import 'package:qhd_prevention/customWidget/department_picker.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/home/tap/tabList/special_wrok/SpecialWorkFormBaseWork.dart';
import 'package:qhd_prevention/tools/tools.dart';
import '../../../../../../customWidget/bottom_picker.dart';
import '../../../../../../customWidget/custom_alert_dialog.dart';
import '../../../../../../customWidget/photo_picker_row.dart';
import '../../../../../../customWidget/single_image_viewer.dart';
import '../../../../../../http/ApiService.dart';
import '../../../../../mine/mine_sign_page.dart';
import '../../../../../my_appbar.dart';
import '../../special_Wrok/MeasuresListWidget.dart';
import '../../special_Wrok/qtfx_work_detail/hotwork_gas_list.dart';
import '../WorkDetailFormWidget.dart';
import '../szaq_work_detail/SafeFunctionDialog.dart';
///
class HotworkZyfzDetail extends StatefulWidget {
const HotworkZyfzDetail({
super.key,
required this.HOTWORK_ID,
required this.flow,
});
final String HOTWORK_ID;
final String flow;
@override
State<HotworkZyfzDetail> createState() => _HotworkZyfzDetailState();
}
class _HotworkZyfzDetailState extends State<HotworkZyfzDetail> {
late bool isEditable = false;
///
late Map<String, dynamic> pd = {};
final TextEditingController _contentController = TextEditingController();
///
late List<Map<String, dynamic>> measuresList = [];
late Map<String, dynamic> signs = {};
List<String> signImages = [];
List<String> signTimes = []; //
@override
void initState() {
super.initState();
_getData();
}
///
Future<void> _sign() async {
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
signImages.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
});
}
}
Widget _signListWidget() {
return Column(
children:
signImages.map((path) {
return Column(
children: [
const SizedBox(height: 10),
const Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
child: // ConstrainedBox BoxFit.contain
ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 200,
maxHeight: 150,
),
child: Image.file(
File(path),
//
fit: BoxFit.contain,
),
),
onTap: () {
presentOpaque(
SingleImageViewer(imageUrl: path),
context,
);
},
),
Column(
children: [
Container(
padding: const EdgeInsets.only(right: 5),
child: CustomButton(
text: 'X',
height: 30,
padding: const EdgeInsets.symmetric(horizontal: 10),
backgroundColor: Colors.red,
onPressed: () {
setState(() {
signImages.remove(path);
});
},
),
),
const SizedBox(height: 80),
],
),
],
),
],
);
}).toList(),
);
}
/// -1 1
Future<void> _submit(String status) async {
if (signImages.isEmpty) {
ToastUtil.showNormal(context, '请签字');
return;
}
String reasonText = '';
String DESCR = _contentController.text.trim();
if (DESCR.isEmpty) {
ToastUtil.showNormal(context, '请输入负责人意见');
return;
}
if (status == '1') {
} else {
await showDialog<String>(
context: context,
builder:
(_) => CustomAlertDialog(
title: '作废原因',
mode: DialogMode.input,
hintText: '请输入作废原因',
cancelText: '取消',
confirmText: '确定',
onInputConfirm: (text) {
reasonText = text;
},
),
);
if (reasonText.isEmpty) {
ToastUtil.showNormal(context, '请填写作废原因');
return;
}
}
// measures
final Map<String, dynamic> formData = {};
//
formData['HOTWORK_ID'] = widget.HOTWORK_ID;
formData['SIGNTIME'] = signTimes.join(',');
formData['USER_ID'] = SessionService.instance.loginUserId;
formData['APPLY_STATUS'] = status;
formData['STEP_REASON'] = reasonText;
formData['DESCR'] = DESCR;
await showDialog<String>(
context: context,
builder:
(_) => CustomAlertDialog(
title: '提示',
content: '请确认' + (status == '1' ? "通过" : "作废") + '本作业票?',
cancelText: '取消',
confirmText: '确定',
onConfirm: () async {
LoadingDialogHelper.show(context);
try {
final result = await ApiService.saveSafeFunctionSure(
formData,
signImages,
);
LoadingDialogHelper.hide(context);
if (result['result'] == 'success') {
ToastUtil.showSuccess(context, '保存成功');
Navigator.pop(context);
}
} catch (e) {
LoadingDialogHelper.hide(context);
ToastUtil.showNormal(context, '操作失败:$e');
}
},
),
);
}
///
Future<void> _getData() async {
final data = await ApiService.getHomeworkFindById(widget.HOTWORK_ID);
setState(() {
pd = data['pd'];
_getSigns(pd['HOTWORK_ID'] ?? '');
_getMeasures(pd['HOTWORK_ID'] ?? '');
});
}
Future<void> _getMeasures(String homework_id) async {
final data = await ApiService.listSignFinishMeasures(
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
);
setState(() {
measuresList = List<Map<String, dynamic>>.from(
data['finishMeasuresList'] ?? <Map<String, dynamic>>[],
);
});
}
Future<void> _getSigns(String homework_id) async {
final data = await ApiService.listSignFinished(
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
);
setState(() {
signs = data['signs'] ?? {};
});
}
///
Widget _bottomButtons() {
return Row(
spacing: 10,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: CustomButton(
height: 45,
textStyle: TextStyle(fontSize: 16, color: Colors.white),
text: '作废',
backgroundColor: Colors.red,
onPressed: () {
_submit('-1');
},
),
),
Expanded(
child: CustomButton(
textStyle: TextStyle(fontSize: 16, color: Colors.white),
text: '通过',
backgroundColor: Colors.green,
onPressed: () {
_submit('1');
},
),
),
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppbar(title: '作业负责人意见'),
body: SafeArea(
child: SingleChildScrollView(
padding: EdgeInsets.all(12),
child: Column(
spacing: 12,
children: [
SpecialWorkFormBaseWork(
pd: pd,
measuresList: measuresList,
signs: signs,
baseImgPath: ApiService.baseImgPath,
isEditable: false,
onChooseLevel: () {},
onChooseHotworkUser: () {},
onAnalyzeTap: () {
pushPage(
HotworkGasList(HOTWORK_ID: widget.HOTWORK_ID),
context,
);
},
),
ItemListWidget.itemContainer(
Column(
children: [
ListItemFactory.createBuildMultilineInput(
'作业负责人意见',
'请输入意见',
_contentController,
),
Divider(),
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ListItemFactory.headerTitle('作业负责人'),
CustomButton(
text: '新增手写签字',
height: 36,
backgroundColor: Colors.green,
onPressed: () {
_sign();
},
),
],
),
if (signImages.isNotEmpty) _signListWidget(),
],
)
],
),
),
_bottomButtons(),
],
),
),
),
);
}
}