Compare commits
2 Commits
853000839d
...
1a1d582874
| Author | SHA1 | Date |
|---|---|---|
|
|
1a1d582874 | |
|
|
5e9f726eaa |
|
|
@ -24,13 +24,13 @@ class BottomPicker {
|
|||
/// [itemExtent]: 列表行高
|
||||
/// [height]: 弹窗总高度
|
||||
static Future<T?> show<T>(
|
||||
BuildContext context, {
|
||||
required List<T> items,
|
||||
required Widget Function(T item) itemBuilder,
|
||||
int initialIndex = 0,
|
||||
double itemExtent = 40.0,
|
||||
double height = 250,
|
||||
}) {
|
||||
BuildContext context, {
|
||||
required List<T> items,
|
||||
required Widget Function(T item) itemBuilder,
|
||||
int initialIndex = 0,
|
||||
double itemExtent = 40.0,
|
||||
double height = 250,
|
||||
}) {
|
||||
if (items.isEmpty) return Future.value(null);
|
||||
|
||||
// 确保初始索引合法
|
||||
|
|
@ -51,16 +51,25 @@ class BottomPicker {
|
|||
children: [
|
||||
// 按钮行
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 8,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {FocusScope.of(context).unfocus();Navigator.of(ctx).pop();},
|
||||
onPressed: () {
|
||||
FocusScope.of(context).unfocus();
|
||||
Navigator.of(ctx).pop();
|
||||
},
|
||||
child: const Text('取消'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {FocusScope.of(context).unfocus(); Navigator.of(ctx).pop(selected);},
|
||||
onPressed: () {
|
||||
FocusScope.of(context).unfocus();
|
||||
Navigator.of(ctx).pop(selected);
|
||||
},
|
||||
child: const Text('确定'),
|
||||
),
|
||||
],
|
||||
|
|
@ -70,8 +79,9 @@ class BottomPicker {
|
|||
// 滚动选择器
|
||||
Expanded(
|
||||
child: CupertinoPicker(
|
||||
scrollController:
|
||||
FixedExtentScrollController(initialItem: initialIndex),
|
||||
scrollController: FixedExtentScrollController(
|
||||
initialItem: initialIndex,
|
||||
),
|
||||
itemExtent: 30,
|
||||
onSelectedItemChanged: (index) {
|
||||
selected = items[index];
|
||||
|
|
|
|||
|
|
@ -607,8 +607,8 @@ U6Hzm1ninpWeE+awIDAQAB
|
|||
},
|
||||
);
|
||||
}
|
||||
/// 作业流程图
|
||||
static Future<Map<String, dynamic>> dhGetFlowList(String hotworkId) {
|
||||
/// 动火作业流程图
|
||||
static Future<Map<String, dynamic>> hotGetFlowList(String hotworkId) {
|
||||
return HttpManager().request(
|
||||
basePath,
|
||||
'/app/hotwork/getFlowList',
|
||||
|
|
@ -618,7 +618,18 @@ U6Hzm1ninpWeE+awIDAQAB
|
|||
},
|
||||
);
|
||||
}
|
||||
/// 作业详情
|
||||
/// 高处作业流程图
|
||||
static Future<Map<String, dynamic>> highGetFlowList(String highworkId) {
|
||||
return HttpManager().request(
|
||||
basePath,
|
||||
'/app/highwork/getFlowList',
|
||||
method: Method.post,
|
||||
data: {
|
||||
"HIGHWORK_ID":highworkId
|
||||
},
|
||||
);
|
||||
}
|
||||
/// 动火作业详情
|
||||
static Future<Map<String, dynamic>> getHomeworkFindById(String hotworkId) {
|
||||
return HttpManager().request(
|
||||
basePath,
|
||||
|
|
@ -631,8 +642,22 @@ U6Hzm1ninpWeE+awIDAQAB
|
|||
},
|
||||
);
|
||||
}
|
||||
/// 高处作业详情
|
||||
static Future<Map<String, dynamic>> getHighHomeworkFindById(String hotworkId) {
|
||||
return HttpManager().request(
|
||||
basePath,
|
||||
'/app/highwork/findById',
|
||||
method: Method.post,
|
||||
data: {
|
||||
"HIGHWORK_ID":hotworkId,
|
||||
"CORPINFO_ID":SessionService.instance.corpinfoId,
|
||||
"USER_ID":SessionService.instance.loginUserId,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// 提交作业
|
||||
static Future<Map<String, dynamic>> submitHotwork(String url, Map data) {
|
||||
static Future<Map<String, dynamic>> submitHomework(String url, Map data) {
|
||||
return HttpManager().request(
|
||||
basePath,
|
||||
url,
|
||||
|
|
@ -681,22 +706,22 @@ U6Hzm1ninpWeE+awIDAQAB
|
|||
);
|
||||
}
|
||||
/// 安全防护措施
|
||||
static Future<Map<String, dynamic>> listSignFinishMeasures(String hotworkId) {
|
||||
static Future<Map<String, dynamic>> listSignFinishMeasures(String workType,String hotworkId) {
|
||||
return HttpManager().request(
|
||||
basePath,
|
||||
'/app/hotwork/listSignFinishMeasures',
|
||||
'/app/$workType/listSignFinishMeasures',
|
||||
method: Method.post,
|
||||
data: {
|
||||
"HOTWORK_ID":hotworkId,
|
||||
},
|
||||
);
|
||||
}
|
||||
/// 所有安全防护措施
|
||||
static Future<Map<String, dynamic>> listSignFinishAllMeasures() {
|
||||
/// 所有安全防护措施hotwork
|
||||
static Future<Map<String, dynamic>> listSignFinishAllMeasures(String workType) {
|
||||
final String tm = DateTime.now().millisecondsSinceEpoch.toString();
|
||||
return HttpManager().request(
|
||||
basePath,
|
||||
'/app/hotwork/listAllMeasures?tm=$tm',
|
||||
'/app/$workType/listAllMeasures?tm=$tm',
|
||||
method: Method.post,
|
||||
data: {
|
||||
"CORPINFO_ID":SessionService.instance.corpinfoId,
|
||||
|
|
@ -756,6 +781,7 @@ U6Hzm1ninpWeE+awIDAQAB
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
/// 保存或作废气体检测
|
||||
static Future<Map<String, dynamic>> saveGasTest(
|
||||
Map<String, dynamic> formData,
|
||||
|
|
@ -780,6 +806,7 @@ U6Hzm1ninpWeE+awIDAQAB
|
|||
}
|
||||
/// 保存安全措施确认
|
||||
static Future<Map<String, dynamic>> saveSafeFunctionSure (
|
||||
String workType,
|
||||
Map<String, dynamic> formData,
|
||||
List<String> filePaths,
|
||||
) async {
|
||||
|
|
@ -796,7 +823,7 @@ U6Hzm1ninpWeE+awIDAQAB
|
|||
}
|
||||
return HttpManager().uploadFaceImage(
|
||||
baseUrl: basePath,
|
||||
path: '/app/hotwork/nextStep',
|
||||
path: '/app/$workType/nextStep',
|
||||
fromData: data,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,12 +3,9 @@ import 'dart:io';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:qhd_prevention/customWidget/custom_button.dart';
|
||||
|
||||
import '../../../customWidget/single_image_viewer.dart';
|
||||
import '../../../tools/tools.dart';
|
||||
|
||||
class ItemListWidget {
|
||||
|
||||
static const Color detailtextColor = Colors.black54;
|
||||
|
||||
/// 单行水平排列:
|
||||
/// - 可编辑时:标题 + TextField
|
||||
/// - 不可编辑时:标题 + 带省略号的文本
|
||||
|
|
@ -19,6 +16,7 @@ class ItemListWidget {
|
|||
String? text, // 不可编辑时显示的文本
|
||||
String hintText = '请输入',
|
||||
double fontSize = 15, // 字体大小
|
||||
bool isRequired = true,
|
||||
}) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 12),
|
||||
|
|
@ -28,9 +26,18 @@ class ItemListWidget {
|
|||
? MainAxisAlignment.start
|
||||
: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(fontSize: fontSize, fontWeight: FontWeight.bold),
|
||||
Row(
|
||||
children: [
|
||||
if (isRequired && isEditable)
|
||||
Text('* ', style: TextStyle(color: Colors.red)),
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: fontSize,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
), // 显示标题
|
||||
const SizedBox(width: 8),
|
||||
isEditable
|
||||
|
|
@ -67,6 +74,7 @@ class ItemListWidget {
|
|||
String? text, // 不可编辑时显示的文本
|
||||
double fontSize = 15, // 字体大小
|
||||
double height = 110, // 整体高度
|
||||
bool isRequired = true,
|
||||
}) {
|
||||
return Container(
|
||||
// 统一左右 padding,保证标题和内容在同一左侧基线
|
||||
|
|
@ -75,9 +83,18 @@ class ItemListWidget {
|
|||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(fontSize: fontSize, fontWeight: FontWeight.bold),
|
||||
Row(
|
||||
children: [
|
||||
if (isRequired && isEditable)
|
||||
Text('* ', style: TextStyle(color: Colors.red)),
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: fontSize,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Expanded(
|
||||
|
|
@ -95,7 +112,7 @@ class ItemListWidget {
|
|||
decoration: InputDecoration(
|
||||
hintText: '请输入',
|
||||
// 去掉 TextField 默认内边距
|
||||
contentPadding: EdgeInsets.zero,
|
||||
//contentPadding: EdgeInsets.zero,
|
||||
border: InputBorder.none,
|
||||
),
|
||||
)
|
||||
|
|
@ -127,7 +144,7 @@ class ItemListWidget {
|
|||
double fontSize = 15, // 字体大小
|
||||
bool isClean = false,
|
||||
VoidCallback? onTapClean, // 清除回调
|
||||
|
||||
bool isRequired = true,
|
||||
}) {
|
||||
return InkWell(
|
||||
onTap: isEditable ? onTap : null,
|
||||
|
|
@ -136,9 +153,18 @@ class ItemListWidget {
|
|||
child: Row(
|
||||
children: [
|
||||
// 1. 标题
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(fontSize: fontSize, fontWeight: FontWeight.bold),
|
||||
Row(
|
||||
children: [
|
||||
if (isRequired && isEditable)
|
||||
Text('* ', style: TextStyle(color: Colors.red)),
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: fontSize,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (isClean)
|
||||
Column(
|
||||
|
|
@ -196,6 +222,7 @@ class ItemListWidget {
|
|||
VoidCallback? onTap, // 第一行点击回调
|
||||
double fontSize = 15, // 字体大小
|
||||
double row2Height = 80, // 第二行高度
|
||||
bool isRequired = true,
|
||||
}) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 12),
|
||||
|
|
@ -208,12 +235,18 @@ class ItemListWidget {
|
|||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: fontSize,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
if (isRequired && isEditable)
|
||||
Text('* ', style: TextStyle(color: Colors.red)),
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: fontSize,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
|
|
@ -247,7 +280,7 @@ class ItemListWidget {
|
|||
style: TextStyle(fontSize: fontSize),
|
||||
decoration: InputDecoration(
|
||||
hintText: '请输入',
|
||||
contentPadding: EdgeInsets.zero,
|
||||
//contentPadding: EdgeInsets.zero,
|
||||
border: InputBorder.none,
|
||||
),
|
||||
)
|
||||
|
|
@ -279,6 +312,7 @@ class ItemListWidget {
|
|||
required String hintText,
|
||||
double fontSize = 15, // 字体大小
|
||||
double row2Height = 80, // 第二行高度
|
||||
bool isRequired = true,
|
||||
}) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 12),
|
||||
|
|
@ -290,14 +324,24 @@ class ItemListWidget {
|
|||
child: Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: fontSize,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
child: Row(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
if (isRequired && isEditable)
|
||||
Text('* ', style: TextStyle(color: Colors.red)),
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: fontSize,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
|
|
@ -331,7 +375,7 @@ class ItemListWidget {
|
|||
style: TextStyle(fontSize: fontSize),
|
||||
decoration: InputDecoration(
|
||||
hintText: hintText,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
//contentPadding: EdgeInsets.zero,
|
||||
border: InputBorder.none,
|
||||
),
|
||||
)
|
||||
|
|
@ -367,6 +411,7 @@ class ItemListWidget {
|
|||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
|
|
@ -409,15 +454,21 @@ class ItemListWidget {
|
|||
required VoidCallback? onTap, // 第一行点击回调
|
||||
double fontSize = 15, // 字体大小
|
||||
Color btnColor = Colors.blue,
|
||||
bool isRequired = false,
|
||||
}) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 12),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(fontSize: fontSize, fontWeight: FontWeight.bold),
|
||||
Row(
|
||||
children: [
|
||||
Text("* ", style: TextStyle(color: Colors.red),),
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(fontSize: fontSize, fontWeight: FontWeight.bold),
|
||||
),
|
||||
],
|
||||
),
|
||||
CustomButton(
|
||||
text: buttonText,
|
||||
|
|
@ -430,6 +481,7 @@ class ItemListWidget {
|
|||
),
|
||||
);
|
||||
}
|
||||
|
||||
static Widget itemContainer(Widget child) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import '../../../../../customWidget/ItemWidgetFactory.dart';
|
|||
import '../../../../../customWidget/single_image_viewer.dart';
|
||||
import '../../../../../tools/tools.dart';
|
||||
import '../special_Wrok/MeasuresListWidget.dart';
|
||||
import 'WorkDetailFormWidget.dart';
|
||||
import 'dh_work/HotWorkDetailFormWidget.dart';
|
||||
|
||||
class SpecialWorkFormBaseWork extends StatelessWidget {
|
||||
/// 基础数据
|
||||
|
|
@ -221,7 +221,7 @@ class SpecialWorkFormBaseWork extends StatelessWidget {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 1. 作业详情表单
|
||||
WorkDetailFormWidget(
|
||||
HotWorkDetailFormWidget(
|
||||
pd: pd,
|
||||
isEditable: isEditable,
|
||||
onChooseLevel: onChooseLevel,
|
||||
|
|
|
|||
|
|
@ -1,180 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../../../tools/tools.dart';
|
||||
import '../../item_list_widget.dart';
|
||||
import '../special_Wrok/MeasuresListWidget.dart';
|
||||
|
||||
/// 通用明细表单组件
|
||||
/// 编辑模式时需传入对应的 TextEditingController;非编辑模式可不传
|
||||
class WorkDetailFormWidget extends StatelessWidget {
|
||||
final Map<String, dynamic> pd;
|
||||
final bool isEditable;
|
||||
final VoidCallback onChooseLevel;
|
||||
final VoidCallback onChooseHotworkUser;
|
||||
final VoidCallback onAnalyzeTap;
|
||||
/// 编辑模式下需提供以下控制器,非编辑可不传
|
||||
final TextEditingController? contentController;
|
||||
final TextEditingController? locationController;
|
||||
final TextEditingController? methodController;
|
||||
final TextEditingController? hotworkPersonController;
|
||||
final TextEditingController? relatedController;
|
||||
final TextEditingController? riskController;
|
||||
|
||||
const WorkDetailFormWidget({
|
||||
Key? key,
|
||||
required this.pd,
|
||||
required this.isEditable,
|
||||
required this.onChooseLevel,
|
||||
required this.onChooseHotworkUser,
|
||||
required this.onAnalyzeTap,
|
||||
this.contentController,
|
||||
this.locationController,
|
||||
this.methodController,
|
||||
this.hotworkPersonController,
|
||||
this.relatedController,
|
||||
this.riskController,
|
||||
}) : assert(
|
||||
!isEditable ||
|
||||
(contentController != null &&
|
||||
locationController != null &&
|
||||
methodController != null &&
|
||||
hotworkPersonController != null &&
|
||||
relatedController != null &&
|
||||
riskController != null),
|
||||
'Editable mode requires all TextEditingController parameters',
|
||||
),
|
||||
super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final pd = this.pd;
|
||||
return
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '申请单位:',
|
||||
isEditable: false,
|
||||
text: pd['APPLY_DEPARTMENT_NAME'] ?? '',
|
||||
),
|
||||
const Divider(),
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '申请人:',
|
||||
isEditable: false,
|
||||
text: pd['APPLY_USER_NAME'] ?? '',
|
||||
),
|
||||
if (FormUtils.hasValue(pd, 'CHECK_NO')) ...[
|
||||
const Divider(),
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '编号:',
|
||||
isEditable: false,
|
||||
text: pd['CHECK_NO'] ?? '',
|
||||
),
|
||||
],
|
||||
const Divider(),
|
||||
ItemListWidget.multiLineTitleTextField(
|
||||
label: '作业内容:',
|
||||
isEditable: isEditable,
|
||||
controller: contentController,
|
||||
text: pd['WORK_CONTENT'] ?? '',
|
||||
),
|
||||
const Divider(),
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '动火地点及动火部位:',
|
||||
isEditable: isEditable,
|
||||
controller: locationController,
|
||||
text: pd['WORK_PLACE'] ?? '',
|
||||
),
|
||||
const Divider(),
|
||||
ItemListWidget.selectableLineTitleTextField(
|
||||
label: '动火作业级别:',
|
||||
isEditable: isEditable,
|
||||
onTap: onChooseLevel,
|
||||
text: pd['WORK_LEVEL'] ?? '',
|
||||
),
|
||||
const Divider(),
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '动火方式:',
|
||||
isEditable: isEditable,
|
||||
controller: methodController,
|
||||
text: pd['WORK_FUNCTION'] ?? '',
|
||||
),
|
||||
if (pd['WORK_START_DATE']?.toString().isNotEmpty == true) ...[
|
||||
const Divider(),
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '动火作业实施时间:',
|
||||
isEditable: isEditable,
|
||||
text: '${pd['WORK_START_DATE']} 至 ${pd['WORK_END_DATE'] ?? '--'}',
|
||||
),
|
||||
],
|
||||
const Divider(),
|
||||
ItemListWidget.twoRowSelectableTitleText(
|
||||
label: '动火人及证书编号:',
|
||||
isEditable: isEditable,
|
||||
onTap: onChooseHotworkUser,
|
||||
text: pd['WORK_USER'] ?? '',
|
||||
controller: hotworkPersonController,
|
||||
),
|
||||
const Divider(),
|
||||
ItemListWidget.twoRowButtonTitleText(
|
||||
label: '关联其他特殊作业及安全作业票:',
|
||||
isEditable: isEditable,
|
||||
onTap: () async {
|
||||
final val = await showDialog<String>(
|
||||
context: context,
|
||||
builder:
|
||||
(_) => SelectionPopup(
|
||||
type: 'assignments',
|
||||
initialValue: pd['SPECIAL_WORK'] ?? '',
|
||||
onConfirm: (v) => Navigator.of(context).pop(v),
|
||||
),
|
||||
);
|
||||
if (val != null) pd['SPECIAL_WORK'] = val;
|
||||
FocusHelper.clearFocus(context);
|
||||
},
|
||||
hintText: '请输入关联的其他特殊作业及安全作业票编号',
|
||||
controller: relatedController,
|
||||
text: pd['SPECIAL_WORK'] ?? '',
|
||||
),
|
||||
const Divider(),
|
||||
ItemListWidget.twoRowButtonTitleText(
|
||||
label: '风险辨识结果:',
|
||||
isEditable: isEditable,
|
||||
onTap: () async {
|
||||
final val = await showDialog<String>(
|
||||
context: context,
|
||||
builder:
|
||||
(_) => SelectionPopup(
|
||||
type: 'identification',
|
||||
initialValue: pd['RISK_IDENTIFICATION'] ?? '',
|
||||
onConfirm: (v) => Navigator.of(context).pop(v),
|
||||
),
|
||||
);
|
||||
if (val != null) pd['RISK_IDENTIFICATION'] = val;
|
||||
FocusHelper.clearFocus(context);
|
||||
},
|
||||
hintText: '请输入风险辨识结果',
|
||||
controller: riskController,
|
||||
text: pd['RISK_IDENTIFICATION'] ?? '',
|
||||
),
|
||||
if (FormUtils.hasValue(pd, 'ANALYZE_TIME')) ...[
|
||||
const Divider(),
|
||||
ItemListWidget.OneRowButtonTitleText(
|
||||
label: '分析人:',
|
||||
text: pd['ANALYZE_USER_NAME'] ?? '',
|
||||
onTap: onAnalyzeTap,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../../../../tools/tools.dart';
|
||||
import '../../../item_list_widget.dart';
|
||||
import '../../special_Wrok/MeasuresListWidget.dart';
|
||||
|
||||
/// 通用明细表单组件(支持编辑/只读)
|
||||
class HotWorkDetailFormWidget extends StatefulWidget {
|
||||
final Map<String, dynamic> pd;
|
||||
final bool isEditable;
|
||||
final VoidCallback onChooseLevel;
|
||||
final VoidCallback onChooseHotworkUser;
|
||||
final VoidCallback onAnalyzeTap;
|
||||
|
||||
/// 编辑模式下需提供以下控制器,非编辑可不传
|
||||
final TextEditingController? contentController;
|
||||
final TextEditingController? locationController;
|
||||
final TextEditingController? methodController;
|
||||
final TextEditingController? hotworkPersonController;
|
||||
final TextEditingController? relatedController;
|
||||
final TextEditingController? riskController;
|
||||
|
||||
const HotWorkDetailFormWidget({
|
||||
Key? key,
|
||||
required this.pd,
|
||||
required this.isEditable,
|
||||
required this.onChooseLevel,
|
||||
required this.onChooseHotworkUser,
|
||||
required this.onAnalyzeTap,
|
||||
this.contentController,
|
||||
this.locationController,
|
||||
this.methodController,
|
||||
this.hotworkPersonController,
|
||||
this.relatedController,
|
||||
this.riskController,
|
||||
}) : assert(
|
||||
!isEditable ||
|
||||
(contentController != null &&
|
||||
locationController != null &&
|
||||
methodController != null &&
|
||||
hotworkPersonController != null &&
|
||||
relatedController != null &&
|
||||
riskController != null),
|
||||
'Editable mode requires all TextEditingController parameters',
|
||||
),
|
||||
super(key: key);
|
||||
|
||||
@override
|
||||
State<HotWorkDetailFormWidget> createState() => _HotWorkDetailFormWidgetState();
|
||||
}
|
||||
|
||||
class _HotWorkDetailFormWidgetState extends State<HotWorkDetailFormWidget> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final pd = widget.pd;
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.all(Radius.circular(5)),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '申请单位:',
|
||||
isEditable: false,
|
||||
text: pd['APPLY_DEPARTMENT_NAME'] ?? '',
|
||||
),
|
||||
const Divider(),
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '申请人:',
|
||||
isEditable: false,
|
||||
text: pd['APPLY_USER_NAME'] ?? '',
|
||||
),
|
||||
if (FormUtils.hasValue(pd, 'CHECK_NO')) ...[
|
||||
const Divider(),
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '编号:',
|
||||
isEditable: false,
|
||||
text: pd['CHECK_NO'] ?? '',
|
||||
),
|
||||
],
|
||||
const Divider(),
|
||||
ItemListWidget.multiLineTitleTextField(
|
||||
label: '作业内容:',
|
||||
isEditable: widget.isEditable,
|
||||
controller: widget.contentController,
|
||||
text: pd['WORK_CONTENT'] ?? '',
|
||||
),
|
||||
const Divider(),
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '动火地点及动火部位:',
|
||||
isEditable: widget.isEditable,
|
||||
controller: widget.locationController,
|
||||
text: pd['WORK_PLACE'] ?? '',
|
||||
),
|
||||
const Divider(),
|
||||
ItemListWidget.selectableLineTitleTextField(
|
||||
label: '动火作业级别:',
|
||||
isEditable: widget.isEditable,
|
||||
onTap: widget.onChooseLevel,
|
||||
text: pd['WORK_LEVEL'] ?? '',
|
||||
),
|
||||
const Divider(),
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '动火方式:',
|
||||
isEditable: widget.isEditable,
|
||||
controller: widget.methodController,
|
||||
text: pd['WORK_FUNCTION'] ?? '',
|
||||
),
|
||||
if (pd['WORK_START_DATE']?.toString().isNotEmpty == true) ...[
|
||||
const Divider(),
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '动火作业实施时间:',
|
||||
isEditable: false,
|
||||
text: '${pd['WORK_START_DATE']} 至 ${pd['WORK_END_DATE'] ?? '--'}',
|
||||
),
|
||||
],
|
||||
const Divider(),
|
||||
ItemListWidget.twoRowSelectableTitleText(
|
||||
label: '动火人及证书编号:',
|
||||
isEditable: widget.isEditable,
|
||||
onTap: widget.onChooseHotworkUser,
|
||||
text: pd['WORK_USER'] ?? '',
|
||||
controller: widget.hotworkPersonController,
|
||||
),
|
||||
const Divider(),
|
||||
ItemListWidget.twoRowButtonTitleText(
|
||||
label: '关联其他特殊作业及安全作业票:',
|
||||
isEditable: widget.isEditable,
|
||||
onTap: () async {
|
||||
final val = await showDialog<String>(
|
||||
context: context,
|
||||
builder: (_) => SelectionPopup(
|
||||
type: 'assignments',
|
||||
initialValue: pd['SPECIAL_WORK'] ?? '',
|
||||
onConfirm: (val) {
|
||||
setState(() {
|
||||
pd['SPECIAL_WORK'] = val;
|
||||
widget.relatedController?.text = val;
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
FocusHelper.clearFocus(context);
|
||||
},
|
||||
hintText: '请输入关联的其他特殊作业及安全作业票编号',
|
||||
controller: widget.relatedController,
|
||||
text: pd['SPECIAL_WORK'] ?? '',
|
||||
),
|
||||
const Divider(),
|
||||
ItemListWidget.twoRowButtonTitleText(
|
||||
label: '风险辨识结果:',
|
||||
isEditable: widget.isEditable,
|
||||
onTap: () async {
|
||||
await showDialog<String>(
|
||||
context: context,
|
||||
builder: (_) => SelectionPopup(
|
||||
type: 'identification',
|
||||
initialValue: pd['RISK_IDENTIFICATION'] ?? '',
|
||||
onConfirm: (val) {
|
||||
setState(() {
|
||||
pd['RISK_IDENTIFICATION'] = val;
|
||||
widget.riskController?.text = val;
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
FocusHelper.clearFocus(context);
|
||||
},
|
||||
hintText: '请输入风险辨识结果',
|
||||
controller: widget.riskController,
|
||||
text: pd['RISK_IDENTIFICATION'] ?? '',
|
||||
),
|
||||
if (FormUtils.hasValue(pd, 'ANALYZE_TIME')) ...[
|
||||
const Divider(),
|
||||
ItemListWidget.OneRowButtonTitleText(
|
||||
label: '分析人:',
|
||||
text: pd['ANALYZE_USER_NAME'] ?? '',
|
||||
onTap: widget.onAnalyzeTap,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@ import 'package:qhd_prevention/pages/mine/mine_sign_page.dart';
|
|||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/MeasuresListWidget.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/dh_work/qtfx_work_detail/hotwork_gas_list.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/WorkDetailFormWidget.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/HotWorkDetailFormWidget.dart';
|
||||
|
||||
/// 安全措施确认
|
||||
class HotworkSafeFuncSure extends StatefulWidget {
|
||||
|
|
@ -254,7 +254,7 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
|
|||
onConfirm: () async {
|
||||
LoadingDialogHelper.show(context);
|
||||
try {
|
||||
final result = await ApiService.saveSafeFunctionSure(
|
||||
final result = await ApiService.saveSafeFunctionSure('hotwork',
|
||||
formData,
|
||||
imagePaths,
|
||||
);
|
||||
|
|
@ -453,7 +453,7 @@ class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
|
|||
padding: EdgeInsets.all(12),
|
||||
child: Column(
|
||||
children: [
|
||||
WorkDetailFormWidget(
|
||||
HotWorkDetailFormWidget(
|
||||
pd: pd,
|
||||
isEditable: false,
|
||||
onChooseLevel: () {},
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ class _HotworkAqglDetailState extends State<HotworkAqglDetail> {
|
|||
onConfirm: () async {
|
||||
LoadingDialogHelper.show(context);
|
||||
try {
|
||||
final result = await ApiService.saveSafeFunctionSure(
|
||||
final result = await ApiService.saveSafeFunctionSure('hotwork',
|
||||
formData,
|
||||
signImages,
|
||||
);
|
||||
|
|
@ -210,7 +210,7 @@ class _HotworkAqglDetailState extends State<HotworkAqglDetail> {
|
|||
}
|
||||
|
||||
Future<void> _getMeasures(String homework_id) async {
|
||||
final data = await ApiService.listSignFinishMeasures(
|
||||
final data = await ApiService.listSignFinishMeasures('hotwork',
|
||||
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
|
||||
);
|
||||
setState(() {
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ class _HotworkAqjdDetailState extends State<HotworkAqjdDetail> {
|
|||
onConfirm: () async {
|
||||
LoadingDialogHelper.show(context);
|
||||
try {
|
||||
final result = await ApiService.saveSafeFunctionSure(
|
||||
final result = await ApiService.saveSafeFunctionSure('hotwork',
|
||||
formData,
|
||||
signImages,
|
||||
);
|
||||
|
|
@ -240,7 +240,7 @@ class _HotworkAqjdDetailState extends State<HotworkAqjdDetail> {
|
|||
}
|
||||
|
||||
Future<void> _getMeasures(String homework_id) async {
|
||||
final data = await ApiService.listSignFinishMeasures(
|
||||
final data = await ApiService.listSignFinishMeasures('hotwork',
|
||||
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
|
||||
);
|
||||
setState(() {
|
||||
|
|
|
|||
|
|
@ -183,6 +183,7 @@ class _HotworkDbbzDetailState extends State<HotworkDbbzDetail> {
|
|||
LoadingDialogHelper.show(context);
|
||||
try {
|
||||
final result = await ApiService.saveSafeFunctionSure(
|
||||
'hotwork',
|
||||
formData,
|
||||
signImages,
|
||||
);
|
||||
|
|
@ -212,7 +213,7 @@ class _HotworkDbbzDetailState extends State<HotworkDbbzDetail> {
|
|||
}
|
||||
|
||||
Future<void> _getMeasures(String homework_id) async {
|
||||
final data = await ApiService.listSignFinishMeasures(
|
||||
final data = await ApiService.listSignFinishMeasures('hotwork',
|
||||
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
|
||||
);
|
||||
setState(() {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ 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/WorkDetailFormWidget.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/HotWorkDetailFormWidget.dart';
|
||||
import 'package:qhd_prevention/tools/h_colors.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
|
|
@ -301,6 +301,7 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
|
|||
if (personList.isEmpty) {
|
||||
// 如果还是没数据,说明该部门没有可选的人
|
||||
ToastUtil.showNormal(context, '请先选择' + type.displayName);
|
||||
|
||||
return;
|
||||
}
|
||||
DepartmentPersonPicker.show(
|
||||
|
|
@ -408,7 +409,7 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
|
|||
printLongString(jsonStr);
|
||||
try {
|
||||
String url = "/app/hotwork/" + msg;
|
||||
final result = await ApiService.submitHotwork(url, pd);
|
||||
final result = await ApiService.submitHomework(url, pd);
|
||||
LoadingDialogHelper.hide(context);
|
||||
if (result['result'] == 'success') {
|
||||
ToastUtil.showSuccess(context, status == '1' ? '提交成功' : '已暂存');
|
||||
|
|
@ -472,7 +473,7 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
|
|||
}
|
||||
|
||||
Future<void> _getMeasures(String homework_id) async {
|
||||
final data = await ApiService.listSignFinishMeasures(
|
||||
final data = await ApiService.listSignFinishMeasures('hotwork',
|
||||
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
|
||||
);
|
||||
setState(() {
|
||||
|
|
@ -493,7 +494,7 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
|
|||
child: Column(
|
||||
children: [
|
||||
_card(
|
||||
WorkDetailFormWidget(
|
||||
HotWorkDetailFormWidget(
|
||||
pd: pd,
|
||||
isEditable: isEditable,
|
||||
contentController: _contentController,
|
||||
|
|
|
|||
|
|
@ -180,6 +180,7 @@ class _HotworkDhspDetailState extends State<HotworkDhspDetail> {
|
|||
LoadingDialogHelper.show(context);
|
||||
try {
|
||||
final result = await ApiService.saveSafeFunctionSure(
|
||||
'hotwork',
|
||||
formData,
|
||||
signImages,
|
||||
);
|
||||
|
|
@ -209,7 +210,7 @@ class _HotworkDhspDetailState extends State<HotworkDhspDetail> {
|
|||
}
|
||||
|
||||
Future<void> _getMeasures(String homework_id) async {
|
||||
final data = await ApiService.listSignFinishMeasures(
|
||||
final data = await ApiService.listSignFinishMeasures('hotwork',
|
||||
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
|
||||
);
|
||||
setState(() {
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ class _HotWorkListPageState extends State<HotWorkListPage> {
|
|||
/// 打开流程图
|
||||
Future<void> _openFlowDrawer(String hotworkId) async {
|
||||
try {
|
||||
final response = await ApiService.dhGetFlowList(hotworkId);
|
||||
final response = await ApiService.hotGetFlowList(hotworkId);
|
||||
final List<dynamic>? newFlow = response['flowList'];
|
||||
if (newFlow == null || newFlow.isEmpty) {
|
||||
ToastUtil.showNormal(context, '暂无流程图数据');
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ 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/toast_util.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/WorkDetailFormWidget.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/HotWorkDetailFormWidget.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
|
|
@ -170,6 +170,7 @@ class _HotworkJhrDetailState extends State<HotworkJhrDetail> {
|
|||
LoadingDialogHelper.show(context);
|
||||
try {
|
||||
final result = await ApiService.saveSafeFunctionSure(
|
||||
'hotwork',
|
||||
formData,
|
||||
imagePaths,
|
||||
);
|
||||
|
|
@ -202,7 +203,7 @@ class _HotworkJhrDetailState extends State<HotworkJhrDetail> {
|
|||
}
|
||||
|
||||
Future<void> _getMeasures(String homework_id) async {
|
||||
final data = await ApiService.listSignFinishMeasures(
|
||||
final data = await ApiService.listSignFinishMeasures('hotwork',
|
||||
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
|
||||
);
|
||||
setState(() {
|
||||
|
|
@ -326,7 +327,7 @@ class _HotworkJhrDetailState extends State<HotworkJhrDetail> {
|
|||
child: Column(
|
||||
children: [
|
||||
// _card(_defaultDetail()),
|
||||
WorkDetailFormWidget(
|
||||
HotWorkDetailFormWidget(
|
||||
pd: pd,
|
||||
isEditable: false,
|
||||
onChooseLevel: (){},
|
||||
|
|
|
|||
|
|
@ -171,6 +171,7 @@ class _HotworkJsjdDetailState extends State<HotworkJsjdDetail> {
|
|||
LoadingDialogHelper.show(context);
|
||||
try {
|
||||
final result = await ApiService.saveSafeFunctionSure(
|
||||
'hotwork',
|
||||
formData,
|
||||
signImages,
|
||||
);
|
||||
|
|
@ -200,7 +201,7 @@ class _HotworkJsjdDetailState extends State<HotworkJsjdDetail> {
|
|||
}
|
||||
|
||||
Future<void> _getMeasures(String homework_id) async {
|
||||
final data = await ApiService.listSignFinishMeasures(
|
||||
final data = await ApiService.listSignFinishMeasures('hotwork',
|
||||
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
|
||||
);
|
||||
setState(() {
|
||||
|
|
|
|||
|
|
@ -216,6 +216,7 @@ class _HotworkJszyDetailState extends State<HotworkJszyDetail> {
|
|||
LoadingDialogHelper.show(context);
|
||||
try {
|
||||
final result = await ApiService.saveSafeFunctionSure(
|
||||
'hotwork',
|
||||
formData,
|
||||
signImages,
|
||||
);
|
||||
|
|
@ -245,7 +246,7 @@ class _HotworkJszyDetailState extends State<HotworkJszyDetail> {
|
|||
}
|
||||
|
||||
Future<void> _getMeasures(String homework_id) async {
|
||||
final data = await ApiService.listSignFinishMeasures(
|
||||
final data = await ApiService.listSignFinishMeasures('hotwork',
|
||||
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
|
||||
);
|
||||
setState(() {
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ class _HotworkKszyDetailState extends State<HotworkKszyDetail> {
|
|||
onConfirm: () async {
|
||||
LoadingDialogHelper.show(context);
|
||||
try {
|
||||
final result = await ApiService.saveSafeFunctionSure(
|
||||
final result = await ApiService.saveSafeFunctionSure('hotwork',
|
||||
formData,
|
||||
signImages,
|
||||
);
|
||||
|
|
@ -218,7 +218,7 @@ class _HotworkKszyDetailState extends State<HotworkKszyDetail> {
|
|||
}
|
||||
|
||||
Future<void> _getMeasures(String homework_id) async {
|
||||
final data = await ApiService.listSignFinishMeasures(
|
||||
final data = await ApiService.listSignFinishMeasures('hotwork',
|
||||
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
|
||||
);
|
||||
setState(() {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ 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/WorkDetailFormWidget.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/HotWorkDetailFormWidget.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
|
|
@ -321,6 +321,7 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
|
|||
LoadingDialogHelper.show(context);
|
||||
try {
|
||||
final result = await ApiService.saveSafeFunctionSure(
|
||||
'hotwork',
|
||||
formData,
|
||||
imagePaths,
|
||||
);
|
||||
|
|
@ -358,7 +359,7 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
|
|||
}
|
||||
|
||||
Future<void> _getMeasures() async {
|
||||
final data = await ApiService.listSignFinishAllMeasures();
|
||||
final data = await ApiService.listSignFinishAllMeasures('hotwork');
|
||||
setState(() {
|
||||
measuresList = List<Map<String, dynamic>>.from(
|
||||
data['measuresList'] ?? <Map<String, dynamic>>[],
|
||||
|
|
@ -544,7 +545,7 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
|
|||
child: Column(
|
||||
children: [
|
||||
// _card(_defaultDetail()),
|
||||
WorkDetailFormWidget(
|
||||
HotWorkDetailFormWidget(
|
||||
pd: pd,
|
||||
isEditable: false,
|
||||
onChooseLevel: (){},
|
||||
|
|
|
|||
|
|
@ -180,6 +180,7 @@ class _HotworkSzdwDetailState extends State<HotworkSzdwDetail> {
|
|||
LoadingDialogHelper.show(context);
|
||||
try {
|
||||
final result = await ApiService.saveSafeFunctionSure(
|
||||
'hotwork',
|
||||
formData,
|
||||
signImages,
|
||||
);
|
||||
|
|
@ -199,7 +200,7 @@ class _HotworkSzdwDetailState extends State<HotworkSzdwDetail> {
|
|||
|
||||
/// 初始化拉取数据
|
||||
Future<void> _getData() async {
|
||||
final data = await ApiService.getHomeworkFindById(widget.HOTWORK_ID);
|
||||
final data = await ApiService.getHighHomeworkFindById(widget.HOTWORK_ID);
|
||||
setState(() {
|
||||
pd = data['pd'];
|
||||
|
||||
|
|
@ -209,7 +210,7 @@ class _HotworkSzdwDetailState extends State<HotworkSzdwDetail> {
|
|||
}
|
||||
|
||||
Future<void> _getMeasures(String homework_id) async {
|
||||
final data = await ApiService.listSignFinishMeasures(
|
||||
final data = await ApiService.listSignFinishMeasures('hotwork',
|
||||
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
|
||||
);
|
||||
setState(() {
|
||||
|
|
|
|||
|
|
@ -237,6 +237,7 @@ class _HotworkYsgdDetailState extends State<HotworkYsgdDetail> {
|
|||
LoadingDialogHelper.show(context);
|
||||
try {
|
||||
final result = await ApiService.saveSafeFunctionSure(
|
||||
'hotwork',
|
||||
formData,
|
||||
signImages,
|
||||
);
|
||||
|
|
@ -266,7 +267,7 @@ class _HotworkYsgdDetailState extends State<HotworkYsgdDetail> {
|
|||
}
|
||||
|
||||
Future<void> _getMeasures(String homework_id) async {
|
||||
final data = await ApiService.listSignFinishMeasures(
|
||||
final data = await ApiService.listSignFinishMeasures('hotwork',
|
||||
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
|
||||
);
|
||||
setState(() {
|
||||
|
|
|
|||
|
|
@ -180,6 +180,7 @@ class _HotworkZyfzDetailState extends State<HotworkZyfzDetail> {
|
|||
LoadingDialogHelper.show(context);
|
||||
try {
|
||||
final result = await ApiService.saveSafeFunctionSure(
|
||||
'hotwork',
|
||||
formData,
|
||||
signImages,
|
||||
);
|
||||
|
|
@ -209,7 +210,7 @@ class _HotworkZyfzDetailState extends State<HotworkZyfzDetail> {
|
|||
}
|
||||
|
||||
Future<void> _getMeasures(String homework_id) async {
|
||||
final data = await ApiService.listSignFinishMeasures(
|
||||
final data = await ApiService.listSignFinishMeasures('hotwork',
|
||||
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
|
||||
);
|
||||
setState(() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,155 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../../../../tools/tools.dart';
|
||||
import '../../../item_list_widget.dart';
|
||||
import '../../special_Wrok/MeasuresListWidget.dart';
|
||||
|
||||
/// 通用高处作业明细表单组件(支持编辑/只读)
|
||||
class HighWorkDetailFormWidget extends StatefulWidget {
|
||||
final Map<String, dynamic> pd;
|
||||
final bool isEditable;
|
||||
final VoidCallback onChooseLevel;
|
||||
|
||||
/// 编辑模式下需提供以下控制器,非编辑模式可不传
|
||||
final TextEditingController? locationController; // 地点
|
||||
final TextEditingController? hightController; // 高度
|
||||
final TextEditingController? contentController; // 内容
|
||||
final TextEditingController? relatedController;
|
||||
final TextEditingController? riskController;
|
||||
|
||||
const HighWorkDetailFormWidget({
|
||||
Key? key,
|
||||
required this.pd,
|
||||
required this.isEditable,
|
||||
required this.onChooseLevel,
|
||||
this.locationController,
|
||||
this.hightController,
|
||||
this.contentController,
|
||||
this.relatedController,
|
||||
this.riskController,
|
||||
}) : assert(
|
||||
!isEditable ||
|
||||
(locationController != null &&
|
||||
hightController != null &&
|
||||
contentController != null &&
|
||||
relatedController != null &&
|
||||
riskController != null),
|
||||
'Editable mode requires all TextEditingController parameters',
|
||||
),
|
||||
super(key: key);
|
||||
|
||||
@override
|
||||
State<HighWorkDetailFormWidget> createState() => _HighWorkDetailFormWidgetState();
|
||||
}
|
||||
|
||||
class _HighWorkDetailFormWidgetState extends State<HighWorkDetailFormWidget> {
|
||||
String _getWorkLevelText(dynamic level) {
|
||||
switch (level?.toString()) {
|
||||
case '1': return 'I级高处作业';
|
||||
case '2': return 'II级高处作业';
|
||||
case '3': return 'III级高处作业';
|
||||
case '4': return 'IV级高处作业';
|
||||
default: return '';
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final pd = widget.pd;
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.all(Radius.circular(5)),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
if (!widget.isEditable && FormUtils.hasValue(pd, 'CHECK_NO')) ...[
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '编号:',
|
||||
isEditable: false,
|
||||
text: pd['CHECK_NO'] ?? '',
|
||||
),
|
||||
const Divider(),
|
||||
],
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '作业地点:',
|
||||
isEditable: widget.isEditable,
|
||||
controller: widget.locationController,
|
||||
text: pd['WORK_PLACE'] ?? '',
|
||||
),
|
||||
const Divider(),
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '作业高度(米):',
|
||||
isEditable: widget.isEditable,
|
||||
controller: widget.hightController,
|
||||
text: pd['WORK_HIGH'] ?? '',
|
||||
),
|
||||
const Divider(),
|
||||
ItemListWidget.selectableLineTitleTextField(
|
||||
label: '高处作业级别:',
|
||||
isEditable: widget.isEditable,
|
||||
onTap: widget.onChooseLevel,
|
||||
text: _getWorkLevelText(pd['WORK_LEVEL']),
|
||||
),
|
||||
const Divider(),
|
||||
ItemListWidget.multiLineTitleTextField(
|
||||
label: '作业内容:',
|
||||
isEditable: widget.isEditable,
|
||||
controller: widget.contentController,
|
||||
text: pd['WORK_CONTENT'] ?? '',
|
||||
),
|
||||
const Divider(),
|
||||
ItemListWidget.twoRowButtonTitleText(
|
||||
label: '关联的其他特殊作业及安全作业票编号:',
|
||||
isEditable: widget.isEditable,
|
||||
onTap: () async {
|
||||
final val = await showDialog<String>(
|
||||
context: context,
|
||||
builder: (_) => SelectionPopup(
|
||||
type: 'assignments',
|
||||
initialValue: pd['SPECIAL_WORK'] ?? '',
|
||||
onConfirm: (v) {
|
||||
setState(() {
|
||||
pd['SPECIAL_WORK'] = v;
|
||||
widget.relatedController?.text = v;
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
FocusHelper.clearFocus(context);
|
||||
},
|
||||
hintText: '请输入关联的其他特殊作业及安全作业票编号',
|
||||
controller: widget.relatedController,
|
||||
text: pd['SPECIAL_WORK'] ?? '',
|
||||
),
|
||||
const Divider(),
|
||||
ItemListWidget.twoRowButtonTitleText(
|
||||
label: '风险辨识结果:',
|
||||
isEditable: widget.isEditable,
|
||||
onTap: () async {
|
||||
await showDialog<String>(
|
||||
context: context,
|
||||
builder: (_) => SelectionPopup(
|
||||
type: 'identification',
|
||||
initialValue: pd['RISK_IDENTIFICATION'] ?? '',
|
||||
onConfirm: (v) {
|
||||
setState(() {
|
||||
pd['RISK_IDENTIFICATION'] = v;
|
||||
widget.riskController?.text = v;
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
FocusHelper.clearFocus(context);
|
||||
},
|
||||
hintText: '请输入风险辨识结果',
|
||||
controller: widget.riskController,
|
||||
text: pd['RISK_IDENTIFICATION'] ?? '',
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,360 @@
|
|||
import 'dart:io';
|
||||
import 'dart:ui';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:qhd_prevention/customWidget/toast_util.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/customWidget/custom_button.dart';
|
||||
import 'package:qhd_prevention/customWidget/photo_picker_row.dart';
|
||||
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
import 'package:qhd_prevention/pages/mine/mine_sign_page.dart';
|
||||
|
||||
/// 本地路径 + 线上路径模型
|
||||
class ImageData {
|
||||
String localPath;
|
||||
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 {
|
||||
final int index;
|
||||
final int status;
|
||||
final String measures;
|
||||
final List<ImageData> imgList;
|
||||
final List<Map<String, dynamic>> signImgList;
|
||||
|
||||
const DangerousOptionsPage({
|
||||
Key? key,
|
||||
required this.index,
|
||||
this.status = 1,
|
||||
this.measures = '',
|
||||
this.imgList = const [],
|
||||
this.signImgList = const [],
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_DangerousOptionsPageState createState() => _DangerousOptionsPageState();
|
||||
}
|
||||
|
||||
class _DangerousOptionsPageState extends State<DangerousOptionsPage> {
|
||||
late int index;
|
||||
late int status;
|
||||
late String measures;
|
||||
late List<ImageData> imgList;
|
||||
late List<SignImageData> signImgList;
|
||||
List<String> signTimes = [];
|
||||
|
||||
bool buttonLoading = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
index = widget.index;
|
||||
status = widget.status;
|
||||
measures = widget.measures;
|
||||
imgList = List<ImageData>.from(widget.imgList);
|
||||
signImgList =
|
||||
widget.signImgList.map((map) => SignImageData.fromJson(map)).toList();
|
||||
}
|
||||
|
||||
/// 拍照或选图后的回调
|
||||
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> _submit() async {
|
||||
if (signImgList.isEmpty) {
|
||||
ToastUtil.showNormal(context, '请签字');
|
||||
return;
|
||||
}
|
||||
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': sineImageList,
|
||||
'index': index,
|
||||
'status': status,
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _sign() async {
|
||||
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(() {
|
||||
final imageData = SignImageData(
|
||||
SIGNER_TIME: now,
|
||||
filePath: path,
|
||||
key: signImgList.length,
|
||||
);
|
||||
signImgList.add(imageData);
|
||||
signTimes.add(now);
|
||||
});
|
||||
FocusHelper.clearFocus(context);
|
||||
}
|
||||
}
|
||||
|
||||
Widget _signListWidget() {
|
||||
return Column(
|
||||
children:
|
||||
signImgList.map((imgData) {
|
||||
final idx = signImgList.indexOf(imgData);
|
||||
return Column(
|
||||
children: [
|
||||
const SizedBox(height: 10),
|
||||
const Divider(),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
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),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: MyAppbar(title: '安全措施'),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
|
||||
color: Colors.white,
|
||||
child: ListView(
|
||||
children: [
|
||||
Table(
|
||||
border: TableBorder.all(color: Colors.grey.shade300),
|
||||
columnWidths: {0: FlexColumnWidth(3), 1: FlexColumnWidth(2)},
|
||||
children: [
|
||||
TableRow(
|
||||
decoration: BoxDecoration(color: Colors.grey.shade200),
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.all(10),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'主要安全措施',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.all(10),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'操作',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
TableRow(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 12,
|
||||
horizontal: 5,
|
||||
),
|
||||
child: Text(measures),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(0),
|
||||
child: Column(
|
||||
children: [
|
||||
RadioListTile<int>(
|
||||
value: -1,
|
||||
groupValue: status,
|
||||
title: Text('不涉及'),
|
||||
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,
|
||||
),
|
||||
onChanged: (v) => setState(() => status = v!),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
RepairedPhotoSection(
|
||||
title: '上传图片',
|
||||
maxCount: 2,
|
||||
mediaType: MediaType.image,
|
||||
initialMediaPaths:
|
||||
imgList
|
||||
.map((e) => '${ApiService.baseImgPath}${e.serverPath}')
|
||||
.toList(),
|
||||
onChanged: (paths) {},
|
||||
onMediaAdded: _onImageAdded,
|
||||
onMediaRemoved: (path) {
|
||||
final item = imgList.firstWhere((e) => e.localPath == path);
|
||||
_onImageRemoved(item);
|
||||
},
|
||||
onAiIdentify: () {},
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('签字:', style: TextStyle(fontSize: 16)),
|
||||
CustomButton(
|
||||
text: '新增手写签字',
|
||||
height: 36,
|
||||
backgroundColor: Colors.green,
|
||||
onPressed: _sign,
|
||||
),
|
||||
],
|
||||
),
|
||||
if (signImgList.isNotEmpty) _signListWidget(),
|
||||
const SizedBox(height: 30),
|
||||
CustomButton(
|
||||
text: '保存',
|
||||
backgroundColor: Colors.blue,
|
||||
onPressed: buttonLoading ? null : _submit,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,516 @@
|
|||
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/dh_work/aqcs_work_detail/dangerous_options_page.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
|
||||
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/mine/mine_sign_page.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/MeasuresListWidget.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/dh_work/qtfx_work_detail/hotwork_gas_list.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/HotWorkDetailFormWidget.dart';
|
||||
|
||||
/// 安全措施确认
|
||||
class HotworkSafeFuncSure extends StatefulWidget {
|
||||
const HotworkSafeFuncSure({
|
||||
super.key,
|
||||
required this.HOTWORK_ID,
|
||||
required this.flow,
|
||||
});
|
||||
|
||||
final String HOTWORK_ID;
|
||||
final String flow;
|
||||
|
||||
@override
|
||||
State<HotworkSafeFuncSure> createState() => _HotworkSafeFuncSureState();
|
||||
}
|
||||
|
||||
class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
|
||||
late bool isEditable = false;
|
||||
final levelList = ["特级", "一级", "二级"];
|
||||
|
||||
/// 编辑还是新增
|
||||
late String msg = 'add';
|
||||
|
||||
/// 详情
|
||||
late Map<String, dynamic> pd = {};
|
||||
late List<Map<String, dynamic>> measuresList = [];
|
||||
/// 其他安全措施
|
||||
final TextEditingController _otherController = TextEditingController();
|
||||
|
||||
/// 动火人及证书编号
|
||||
late List<dynamic> workUserList = [];
|
||||
|
||||
/// 安全防护措施列表
|
||||
List<String> imagePaths = [];
|
||||
List<String> signTimes = []; // 签字时间列表
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_getData();
|
||||
_getHotWorkNameList();
|
||||
}
|
||||
|
||||
/// 弹出单位选择
|
||||
void chooseUnitHandle(MeasureItem item) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
barrierColor: Colors.black54,
|
||||
backgroundColor: Colors.transparent,
|
||||
builder:
|
||||
(_) =>
|
||||
DepartmentPicker(
|
||||
onSelected: (id, name) async {
|
||||
setState(() {
|
||||
item.DEPARTMENT_ID = id;
|
||||
item.DEPARTMENT_NAME = name;
|
||||
});
|
||||
_getPersonListForUnitId(item);
|
||||
},
|
||||
),
|
||||
).then((_) {});
|
||||
}
|
||||
|
||||
Future<void> _getPersonListForUnitId(MeasureItem item) async {
|
||||
// 拉取该单位的人员列表并缓存
|
||||
final result = await ApiService.getListTreePersonList(item.DEPARTMENT_ID);
|
||||
setState(() {
|
||||
item.userList = List<Map<String, dynamic>>.from(
|
||||
result['userList'] ?? <Map<String, dynamic>>[],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// 签字
|
||||
Future<void> _sign() async {
|
||||
FocusHelper.clearFocus(context);
|
||||
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(),
|
||||
);
|
||||
}
|
||||
bool _validateAndProceed(BuildContext context) {
|
||||
for (var i = 0; i < measuresList.length; i++) {
|
||||
final m = measuresList[i];
|
||||
|
||||
// 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;
|
||||
}
|
||||
String reasonText = '';
|
||||
|
||||
if (status == '1') {
|
||||
if (!_validateAndProceed(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 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['STEP_REASON'] = reasonText;
|
||||
formData['MEASURES'] = json.encode(measuresList);
|
||||
|
||||
await showDialog<String>(
|
||||
context: context,
|
||||
builder:
|
||||
(_) =>
|
||||
CustomAlertDialog(
|
||||
title: '提示',
|
||||
content: '请确认' + (status == '1' ? "通过" : "作废") + '本作业票?',
|
||||
cancelText: '取消',
|
||||
confirmText: '确定',
|
||||
onConfirm: () async {
|
||||
LoadingDialogHelper.show(context);
|
||||
try {
|
||||
final result = await ApiService.saveSafeFunctionSure(
|
||||
'highwork',
|
||||
formData,
|
||||
imagePaths,
|
||||
);
|
||||
LoadingDialogHelper.hide(context);
|
||||
if (result['result'] == 'success') {
|
||||
ToastUtil.showSuccess(
|
||||
context,
|
||||
status == '1' ? '提交成功' : '已暂存',
|
||||
);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
} catch (e) {
|
||||
LoadingDialogHelper.hide(context);
|
||||
ToastUtil.showNormal(context, '操作失败:$e');
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void printLongString(String text, {int chunkSize = 800}) {
|
||||
final pattern = RegExp('.{1,$chunkSize}'); // 每 chunkSize 个字符一组
|
||||
for (final match in pattern.allMatches(text)) {
|
||||
print(match.group(0));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _getHotWorkNameList() async {
|
||||
final result = await ApiService.getHotWorkNameList();
|
||||
setState(() {
|
||||
workUserList = result['varList'] ?? '';
|
||||
});
|
||||
}
|
||||
|
||||
/// 初始化拉取数据
|
||||
Future<void> _getData() async {
|
||||
final data = await ApiService.getHighHomeworkFindById(widget.HOTWORK_ID);
|
||||
setState(() {
|
||||
pd = data['pd'];
|
||||
_getMeasures();
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _getMeasures() async {
|
||||
final data = await ApiService.listSignSureAllMeasures(widget.HOTWORK_ID);
|
||||
setState(() {
|
||||
measuresList = List<Map<String, dynamic>>.from(
|
||||
data['measuresForSignList'] ?? <Map<String, dynamic>>[],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Future<void> _itemToSign(Map<String, dynamic> measures, int index) async {
|
||||
// 签名图片列表
|
||||
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, serverPath: path));
|
||||
}
|
||||
}
|
||||
//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);
|
||||
if (result != null) {
|
||||
setState(() {
|
||||
// 更新返回的图片列表(local + remote)
|
||||
final returned = result['imgList'] as List<dynamic>;
|
||||
// 先映射成 ImageData 列表
|
||||
final imgDataList = returned.map((m) {
|
||||
return ImageData(
|
||||
localPath: m['local'] as String,
|
||||
serverPath: m['remote'] as String,
|
||||
);
|
||||
}).toList();
|
||||
|
||||
// 抽取所有非空的 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'].toString();
|
||||
index = result['index'] as int;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// 安全防护措施
|
||||
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: true,
|
||||
onSign: (item) {
|
||||
_itemToSign(item, measuresList.indexOf(item));
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
ItemListWidget.singleLineTitleText(label: '其他安全措施:',
|
||||
isEditable: true,
|
||||
hintText: '请输入其他安全措施',
|
||||
controller
|
||||
:_otherController),
|
||||
SizedBox(height: 20),
|
||||
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
SizedBox(),
|
||||
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: [
|
||||
HotWorkDetailFormWidget(
|
||||
pd: pd,
|
||||
isEditable: false,
|
||||
onChooseLevel: () {},
|
||||
onChooseHotworkUser: () {},
|
||||
onAnalyzeTap: () {
|
||||
pushPage(
|
||||
HotworkGasList(HOTWORK_ID: widget.HOTWORK_ID),
|
||||
context,
|
||||
);
|
||||
},
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
_setSafeDetailWidget(),
|
||||
SizedBox(height: 20),
|
||||
_bottomButtons(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MeasureItem {
|
||||
final double id;
|
||||
String DEPARTMENT_ID;
|
||||
String DEPARTMENT_NAME;
|
||||
String USER_ID;
|
||||
String USER_NAME;
|
||||
List<Map<String, dynamic>> userList;
|
||||
int userIndex;
|
||||
List<Map<String, dynamic>> selectMeasures;
|
||||
|
||||
MeasureItem({
|
||||
required this.id,
|
||||
this.DEPARTMENT_ID = '',
|
||||
this.DEPARTMENT_NAME = '',
|
||||
this.USER_ID = '',
|
||||
this.USER_NAME = '',
|
||||
List<Map<String, dynamic>>? userList,
|
||||
this.userIndex = -1,
|
||||
List<Map<String, dynamic>>? selectMeasures,
|
||||
})
|
||||
: userList = userList ?? [],
|
||||
selectMeasures = selectMeasures ?? [];
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'DEPARTMENT_ID': DEPARTMENT_ID,
|
||||
'DEPARTMENT_NAME': DEPARTMENT_NAME,
|
||||
'USER_ID': USER_ID,
|
||||
'USER_NAME': USER_NAME,
|
||||
'userList': userList,
|
||||
'userIndex': userIndex,
|
||||
'selectMeasures': selectMeasures,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,328 @@
|
|||
import 'dart:io';
|
||||
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/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 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
|
||||
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/mine/mine_sign_page.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/dh_work/qtfx_work_detail/hotwork_gas_list.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(
|
||||
'highwork',
|
||||
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.getHighHomeworkFindById(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('highwork',
|
||||
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(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,363 @@
|
|||
import 'dart:io';
|
||||
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/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 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
|
||||
import 'package:qhd_prevention/customWidget/photo_picker_row.dart';
|
||||
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/mine/mine_sign_page.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/dh_work/qtfx_work_detail/hotwork_gas_list.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(
|
||||
'highwork',
|
||||
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.getHighHomeworkFindById(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('highwork',
|
||||
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(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,330 @@
|
|||
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/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 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
|
||||
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/mine/mine_sign_page.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/qtfx_work_detail/hotwork_gas_list.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(
|
||||
'highwork',
|
||||
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.getHighHomeworkFindById(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('highwork',
|
||||
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(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
|
||||
class HotSafeWorkChoosePage extends StatefulWidget {
|
||||
const HotSafeWorkChoosePage({super.key});
|
||||
|
||||
@override
|
||||
State<HotSafeWorkChoosePage> createState() => _HotSafeWorkChoosePageState();
|
||||
}
|
||||
|
||||
class _HotSafeWorkChoosePageState extends State<HotSafeWorkChoosePage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: MyAppbar(title: 'dong'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,682 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.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/dh_work/HotWorkDetailFormWidget.dart';
|
||||
import 'package:qhd_prevention/tools/h_colors.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/qtfx_work_detail/hotwork_gas_list.dart';
|
||||
import 'package:qhd_prevention/customWidget/bottom_picker.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/MeasuresListWidget.dart';
|
||||
|
||||
|
||||
enum EditUserType {
|
||||
ANALYZE('分析单位', '分析单位负责人'),
|
||||
GUARDIAN('监护人单位', '监护人'),
|
||||
CONFESS('安全交底人单位', '安全交底人'),
|
||||
ACCEPT_CONFESS('接受交底人单位', '接受交底人'),
|
||||
CONFIRM('作业负责人单位', '作业负责人'),
|
||||
LEADER('所在单位', '所在单位负责人'),
|
||||
AUDIT('安全管理部门', '安全管理部门负责人'),
|
||||
APPROVE('动火审批单位', '动火审批负责人'),
|
||||
MONITOR('动火前在岗部门', '动火前在岗班长'),
|
||||
WORK_START('作业开始负责人单位', '作业开始负责人'),
|
||||
WORK_END('作业结束负责人单位', '作业结束负责人'),
|
||||
ACCEPT('验收部门', '验收部门负责人');
|
||||
|
||||
/// 对应的单位显示名
|
||||
final String displayName;
|
||||
final String personName;
|
||||
|
||||
const EditUserType(this.displayName, this.personName);
|
||||
}
|
||||
|
||||
class HotworkApplyDetail extends StatefulWidget {
|
||||
const HotworkApplyDetail({
|
||||
super.key,
|
||||
required this.HOTWORK_ID,
|
||||
required this.flow,
|
||||
});
|
||||
|
||||
final String HOTWORK_ID;
|
||||
final String flow;
|
||||
|
||||
@override
|
||||
State<HotworkApplyDetail> createState() => _HotworkApplyDetailState();
|
||||
}
|
||||
|
||||
class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
|
||||
late bool isEditable = false;
|
||||
final levelList = ["特级", "一级", "二级"];
|
||||
|
||||
/// 编辑还是新增
|
||||
late String msg = 'add';
|
||||
|
||||
/// 详情
|
||||
late Map<String, dynamic> pd = {};
|
||||
late Map<String, dynamic> signs = {};
|
||||
late List<Map<String, dynamic>> measuresList = [];
|
||||
|
||||
final TextEditingController _contentController = TextEditingController();
|
||||
final TextEditingController _locationController = TextEditingController();
|
||||
final TextEditingController _methodController = TextEditingController();
|
||||
final TextEditingController _hotworkPersonController =
|
||||
TextEditingController();
|
||||
final TextEditingController _relatedController = TextEditingController();
|
||||
final TextEditingController _riskController = TextEditingController();
|
||||
|
||||
/// 动火人及证书编号
|
||||
late List<dynamic> workUserList = [];
|
||||
|
||||
// 存储各单位的人员列表
|
||||
final Map<EditUserType, List<Map<String, dynamic>>> _personCache = {};
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.HOTWORK_ID.length > 0) {
|
||||
msg = 'edit';
|
||||
_getData();
|
||||
} else {
|
||||
isEditable = true;
|
||||
pd['ANALYZE_TIME'] = 1;
|
||||
pd['APPLY_DEPARTMENT_ID'] = SessionService.instance.deptId;
|
||||
pd['APPLY_DEPARTMENT_NAME'] =
|
||||
SessionService.instance.loginUser!['DEPARTMENT_NAME'] ?? '';
|
||||
pd['APPLY_USER_ID'] = SessionService.instance.loginUserId;
|
||||
pd['APPLY_USER_NAME'] = SessionService.instance.username;
|
||||
}
|
||||
_getHotWorkNameList();
|
||||
|
||||
_contentController.addListener(() {
|
||||
setState(() {
|
||||
pd['WORK_CONTENT'] = _contentController.text.trim();
|
||||
});
|
||||
});
|
||||
_locationController.addListener(() {
|
||||
pd['WORK_PLACE'] = _locationController.text.trim();
|
||||
});
|
||||
_methodController.addListener(() {
|
||||
pd['WORK_FUNCTION'] = _methodController.text.trim();
|
||||
});
|
||||
_hotworkPersonController.addListener(() {
|
||||
pd['WORK_USER'] = _hotworkPersonController.text.trim();
|
||||
});
|
||||
_relatedController.addListener(() {
|
||||
pd['SPECIAL_WORK'] = _relatedController.text.trim();
|
||||
});
|
||||
_riskController.addListener(() {
|
||||
pd['RISK_IDENTIFICATION'] = _riskController.text.trim();
|
||||
});
|
||||
}
|
||||
|
||||
void set_pd_DEPARTMENT_ID(EditUserType type, String id) {
|
||||
pd['${type.name}_DEPARTMENT_ID'] = id;
|
||||
}
|
||||
|
||||
void set_pd_DEPARTMENT_NAME(EditUserType type, String name) {
|
||||
pd['${type.name}_DEPARTMENT_NAME'] = name;
|
||||
}
|
||||
|
||||
void set_pd_USER_ID(EditUserType type, String id) {
|
||||
pd['${type.name}_USER_ID'] = id;
|
||||
}
|
||||
|
||||
void set_pd_USER_Name(EditUserType type, String name) {
|
||||
pd['${type.name}_USER_NAME'] = name;
|
||||
}
|
||||
|
||||
String get_pd_DEPARTMENT_ID(EditUserType type) {
|
||||
return pd['${type.name}_DEPARTMENT_ID'] ?? '';
|
||||
}
|
||||
|
||||
String get_pd_DEPARTMENT_NAME(EditUserType type) {
|
||||
return pd['${type.name}_DEPARTMENT_NAME'] ?? '';
|
||||
}
|
||||
|
||||
String get_pd_USER_ID(EditUserType type) {
|
||||
return pd['${type.name}_USER_ID'] ?? '';
|
||||
}
|
||||
|
||||
String get_pd_USER_Name(EditUserType type) {
|
||||
return pd['${type.name}_USER_NAME'] ?? '';
|
||||
}
|
||||
|
||||
Future<void> _chooseLevel() async {
|
||||
final choice = await BottomPicker.show<String>(
|
||||
context,
|
||||
items: levelList,
|
||||
itemBuilder: (item) => Text(item, textAlign: TextAlign.center),
|
||||
initialIndex: 0,
|
||||
);
|
||||
if (choice != null) {
|
||||
// 用户点击确定并选择了 choice
|
||||
setState(() {
|
||||
pd['WORK_LEVEL'] = choice;
|
||||
FocusHelper.clearFocus(context);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _chooseHorkUser() async {
|
||||
final choice = await BottomPicker.show<String>(
|
||||
context,
|
||||
items: workUserList.map((item) => item['NAME'] as String).toList(),
|
||||
itemBuilder: (item) => Text(item, textAlign: TextAlign.center),
|
||||
initialIndex: 0,
|
||||
);
|
||||
if (choice != null) {
|
||||
setState(() {
|
||||
pd['WORK_USER'] = choice;
|
||||
_hotworkPersonController.text = choice;
|
||||
Map<String, dynamic> result = workUserList.firstWhere(
|
||||
(item) => item['NAME'] == choice,
|
||||
orElse: () => {}, // 避免找不到时报错
|
||||
);
|
||||
if (FormUtils.hasValue(result, 'USER_ID')) {
|
||||
pd['WORK_USER_ID'] = result['USER_ID'];
|
||||
}
|
||||
FocusHelper.clearFocus(context);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Widget _card(Widget child) {
|
||||
return Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 5),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _chooseItem(EditUserType type) {
|
||||
bool isClean = false;
|
||||
|
||||
if (isEditable) {
|
||||
if (type == EditUserType.AUDIT && (pd['WORK_LEVEL'] ?? '') == '二级') {
|
||||
isClean = true;
|
||||
}
|
||||
if (type == EditUserType.APPROVE &&
|
||||
((pd['WORK_LEVEL'] ?? '') == '二级' ||
|
||||
(pd['WORK_LEVEL'] ?? '') == '一级')) {
|
||||
isClean = true;
|
||||
}
|
||||
}
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
ItemListWidget.selectableLineTitleTextField(
|
||||
label: type.displayName,
|
||||
isEditable: isEditable,
|
||||
isClean: isClean,
|
||||
onTapClean: () {
|
||||
setState(() {
|
||||
pd['${type.name}_DEPARTMENT_NAME'] = '';
|
||||
pd['${type.name}_USER_NAME'] = '';
|
||||
_personCache.remove(type);
|
||||
});
|
||||
},
|
||||
text: pd['${type.name}_DEPARTMENT_NAME'] ?? '请选择',
|
||||
onTap: () => chooseUnitHandle(type),
|
||||
),
|
||||
Divider(),
|
||||
ItemListWidget.selectableLineTitleTextField(
|
||||
label: type.personName,
|
||||
isEditable: isEditable,
|
||||
text: pd['${type.name}_USER_NAME'] ?? '请选择',
|
||||
onTap: () => choosePersonHandle(type),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// 弹出单位选择
|
||||
void chooseUnitHandle(EditUserType type) {
|
||||
FocusHelper.clearFocus(context);
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
barrierColor: Colors.black54,
|
||||
backgroundColor: Colors.transparent,
|
||||
builder:
|
||||
(_) => DepartmentPicker(
|
||||
onSelected: (id, name) async {
|
||||
setState(() {
|
||||
set_pd_DEPARTMENT_ID(type, id);
|
||||
set_pd_DEPARTMENT_NAME(type, name);
|
||||
set_pd_USER_ID(type, '');
|
||||
set_pd_USER_Name(type, '');
|
||||
});
|
||||
_getPersonListForUnitId(id, type);
|
||||
},
|
||||
),
|
||||
).then((_) {
|
||||
FocusHelper.clearFocus(context);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _getPersonListForUnitId(String id, EditUserType type) async {
|
||||
// 拉取该单位的人员列表并缓存
|
||||
final result = await ApiService.getListTreePersonList(id);
|
||||
setState(() {
|
||||
_personCache[type] = List<Map<String, dynamic>>.from(
|
||||
result['userList'] as List,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/// 弹出人员选择,需先选择单位
|
||||
void choosePersonHandle(EditUserType type) async {
|
||||
FocusHelper.clearFocus(context);
|
||||
|
||||
String unitId = get_pd_DEPARTMENT_ID(type);
|
||||
final personList = _personCache[type] ?? [];
|
||||
if (!unitId.isNotEmpty) {
|
||||
final unitName = type.displayName;
|
||||
ToastUtil.showNormal(context, '请先选择$unitName');
|
||||
return;
|
||||
}
|
||||
|
||||
if (personList.isEmpty) { // 一般这种情况是因为重新编辑没有缓存对应部门的负责人,所以先拉取一下接口
|
||||
await _getPersonListForUnitId(unitId, type);
|
||||
final list = _personCache[type] ?? [];
|
||||
|
||||
if (list.isEmpty) { // 如果还是没数据,说明该部门没有可选的人
|
||||
ToastUtil.showNormal(context, '暂无数据,请选择其他单位');
|
||||
}else{
|
||||
choosePersonHandle(type);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (personList.isEmpty) {
|
||||
// 如果还是没数据,说明该部门没有可选的人
|
||||
ToastUtil.showNormal(context, '请先选择' + type.displayName);
|
||||
return;
|
||||
}
|
||||
DepartmentPersonPicker.show(
|
||||
context,
|
||||
personsData: personList,
|
||||
onSelected: (userId, name) {
|
||||
setState(() {
|
||||
set_pd_USER_ID(type, userId);
|
||||
set_pd_USER_Name(type, name);
|
||||
});
|
||||
},
|
||||
).then((_) {
|
||||
FocusHelper.clearFocus(context);
|
||||
});
|
||||
}
|
||||
|
||||
/// 提交 1 提交 0暂存
|
||||
Future<void> _submit(String status) async {
|
||||
// 通用文本字段校验规则
|
||||
final textRules = <Map<String, dynamic>>[
|
||||
{'value': _contentController.text.trim(), 'message': '请填写作业内容'},
|
||||
{'value': _locationController.text.trim(), 'message': '请填写动火地点及部位'},
|
||||
{'value': _methodController.text.trim(), 'message': '请填写动火方式'},
|
||||
{'value': _hotworkPersonController.text.trim(), 'message': '请填写动火人及证书编号'},
|
||||
{
|
||||
'value': _relatedController.text.trim(),
|
||||
'message': '请输入关联的其他特殊作业及安全作业票编号',
|
||||
},
|
||||
{'value': _riskController.text.trim(), 'message': '请填写风险辨识结果'},
|
||||
];
|
||||
final level = pd['WORK_LEVEL'] ?? '';
|
||||
print('---level-$level');
|
||||
|
||||
/// 各项负责人校验
|
||||
final unitRules = <EditUserType>[
|
||||
EditUserType.ANALYZE,
|
||||
EditUserType.GUARDIAN,
|
||||
EditUserType.CONFESS,
|
||||
EditUserType.ACCEPT_CONFESS,
|
||||
EditUserType.CONFIRM,
|
||||
EditUserType.LEADER,
|
||||
EditUserType.AUDIT,
|
||||
EditUserType.APPROVE,
|
||||
EditUserType.MONITOR,
|
||||
EditUserType.WORK_START,
|
||||
EditUserType.WORK_END,
|
||||
EditUserType.ACCEPT,
|
||||
];
|
||||
if (status == '1') {
|
||||
// 文本校验
|
||||
for (var rule in textRules) {
|
||||
if ((rule['value'] as String).isEmpty) {
|
||||
ToastUtil.showNormal(context, rule['message']);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 级别校验
|
||||
if (level.length == 0) {
|
||||
ToastUtil.showNormal(context, '请选择动火级别');
|
||||
return;
|
||||
}
|
||||
|
||||
for (var type in unitRules) {
|
||||
if (get_pd_DEPARTMENT_ID(type).length == 0) {
|
||||
ToastUtil.showNormal(context, '请选择${type.displayName}');
|
||||
return;
|
||||
}
|
||||
if (get_pd_USER_ID(type).length == 0) {
|
||||
ToastUtil.showNormal(context, '请选择${type.displayName}负责人');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// LoadingDialogHelper.show(context);
|
||||
|
||||
String taskId = '0';
|
||||
if (level == '特级') {
|
||||
taskId = '1';
|
||||
} else if (level == '一级') {
|
||||
taskId = '2';
|
||||
} else if (level == '二级') {
|
||||
taskId = '3';
|
||||
}
|
||||
|
||||
// 提交参数
|
||||
if (msg == 'add') {
|
||||
pd['CORPINFO_ID'] = SessionService.instance.corpinfoId;
|
||||
pd['CREATOR'] = SessionService.instance.loginUserId;
|
||||
pd['OPERATOR'] = SessionService.instance.loginUserId;
|
||||
pd['ACTION_USER'] = SessionService.instance.username;
|
||||
pd['APPLY_STATUS'] = status;
|
||||
pd['STEP_ID'] = status;
|
||||
pd['TASK_ID'] = taskId;
|
||||
pd['HOTWORK_ID'] = widget.HOTWORK_ID;
|
||||
pd['APPLY_DEPARTMENT_ID'] = SessionService.instance.deptId;
|
||||
pd['APPLY_DEPARTMENT_NAME'] =
|
||||
SessionService.instance.loginUser?['DEPARTMENT_NAME'] ?? '';
|
||||
pd['APPLY_USER_ID'] = SessionService.instance.loginUserId;
|
||||
pd['APPLY_USER_NAME'] = SessionService.instance.username;
|
||||
pd['USER_ID'] = SessionService.instance.loginUserId;
|
||||
}
|
||||
|
||||
LoadingDialogHelper.show(context);
|
||||
String jsonStr = jsonEncode(pd);
|
||||
printLongString(jsonStr);
|
||||
try {
|
||||
String url = "/app/hotwork/" + msg;
|
||||
final result = await ApiService.submitHomework(url, pd);
|
||||
LoadingDialogHelper.hide(context);
|
||||
if (result['result'] == 'success') {
|
||||
ToastUtil.showSuccess(context, status == '1' ? '提交成功' : '已暂存');
|
||||
Navigator.pop(context);
|
||||
}
|
||||
} catch (e) {
|
||||
LoadingDialogHelper.hide(context);
|
||||
ToastUtil.showNormal(context, '操作失败:$e');
|
||||
}
|
||||
}
|
||||
|
||||
void printLongString(String text, {int chunkSize = 800}) {
|
||||
final pattern = RegExp('.{1,$chunkSize}'); // 每 chunkSize 个字符一组
|
||||
for (final match in pattern.allMatches(text)) {
|
||||
print(match.group(0));
|
||||
}
|
||||
}
|
||||
|
||||
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.getHighHomeworkFindById(widget.HOTWORK_ID);
|
||||
setState(() {
|
||||
pd = data['pd'];
|
||||
if (pd['STEP_ID'] == 0) {
|
||||
isEditable = true;
|
||||
} else {
|
||||
_getSigns(pd['HOTWORK_ID'] ?? '');
|
||||
_getMeasures(pd['HOTWORK_ID'] ?? '');
|
||||
}
|
||||
// 给所有输入框赋值
|
||||
_contentController.text = pd['WORK_CONTENT'] ?? '';
|
||||
_locationController.text = pd['WORK_PLACE'] ?? '';
|
||||
_methodController.text = pd['WORK_FUNCTION'] ?? '';
|
||||
_hotworkPersonController.text = pd['WORK_USER'] ?? '';
|
||||
_relatedController.text = pd['SPECIAL_WORK'] ?? '';
|
||||
_riskController.text = pd['RISK_IDENTIFICATION'] ?? '';
|
||||
});
|
||||
// final data = await ApiService.getHighHomeworkFindById(widget.HOTWORK_ID);
|
||||
// setState(() {
|
||||
// pd = data['pd'];
|
||||
// });
|
||||
// LoadingDialogHelper.hide(context);
|
||||
}
|
||||
|
||||
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'] ?? {};
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _getMeasures(String homework_id) async {
|
||||
final data = await ApiService.listSignFinishMeasures('highwork',
|
||||
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
|
||||
);
|
||||
setState(() {
|
||||
measuresList = List<Map<String, dynamic>>.from(
|
||||
data['finishMeasuresList'] ?? <Map<String, dynamic>>[],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: h_backGroundColor(),
|
||||
appBar: MyAppbar(title: '动火安全作业申请'),
|
||||
body: SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Column(
|
||||
children: [
|
||||
_card(
|
||||
HotWorkDetailFormWidget(
|
||||
pd: pd,
|
||||
isEditable: isEditable,
|
||||
contentController: _contentController,
|
||||
locationController: _locationController,
|
||||
methodController: _methodController,
|
||||
hotworkPersonController: _hotworkPersonController,
|
||||
relatedController: _relatedController,
|
||||
riskController: _riskController,
|
||||
onChooseLevel: _chooseLevel,
|
||||
onChooseHotworkUser: _chooseHorkUser,
|
||||
onAnalyzeTap: () {
|
||||
pushPage(
|
||||
HotworkGasList(HOTWORK_ID: widget.HOTWORK_ID),
|
||||
context,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
if (isEditable)
|
||||
Column(
|
||||
children: [
|
||||
SizedBox(height: 15),
|
||||
_card(_chooseItem(EditUserType.ANALYZE)),
|
||||
SizedBox(height: 15),
|
||||
_card(_chooseItem(EditUserType.GUARDIAN)),
|
||||
SizedBox(height: 15),
|
||||
_card(_chooseItem(EditUserType.CONFESS)),
|
||||
SizedBox(height: 15),
|
||||
_card(_chooseItem(EditUserType.ACCEPT_CONFESS)),
|
||||
SizedBox(height: 15),
|
||||
_card(_chooseItem(EditUserType.CONFIRM)),
|
||||
SizedBox(height: 15),
|
||||
_card(_chooseItem(EditUserType.LEADER)),
|
||||
SizedBox(height: 15),
|
||||
_card(_chooseItem(EditUserType.AUDIT)),
|
||||
SizedBox(height: 15),
|
||||
_card(_chooseItem(EditUserType.APPROVE)),
|
||||
SizedBox(height: 15),
|
||||
_card(_chooseItem(EditUserType.MONITOR)),
|
||||
SizedBox(height: 15),
|
||||
_card(
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
_chooseItem(EditUserType.WORK_START),
|
||||
Divider(),
|
||||
Row(
|
||||
children: [
|
||||
SizedBox(width: 12),
|
||||
Text(
|
||||
'友情提示:负责填写作业实际开始时间',
|
||||
style: TextStyle(color: Colors.red),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 15),
|
||||
_card(
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
_chooseItem(EditUserType.WORK_END),
|
||||
Divider(),
|
||||
Row(
|
||||
children: [
|
||||
SizedBox(width: 12),
|
||||
Text(
|
||||
'友情提示:负责填写作业实际结束时间',
|
||||
style: TextStyle(color: Colors.red),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 15),
|
||||
_card(_chooseItem(EditUserType.ACCEPT)),
|
||||
SizedBox(height: 15),
|
||||
],
|
||||
),
|
||||
if (measuresList.length > 0)
|
||||
Column(
|
||||
children: [
|
||||
SizedBox(height: 20),
|
||||
ListItemFactory.createBuildSimpleSection('安全防护措施'),
|
||||
Container(
|
||||
color: Colors.white,
|
||||
child: MeasuresListWidget(
|
||||
measuresList:
|
||||
measuresList, // List<Map<String, dynamic>>
|
||||
baseImgPath: ApiService.baseImgPath,
|
||||
isAllowEdit: false,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
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,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SignaturesListWidget(
|
||||
signs: signs,
|
||||
pd: pd,
|
||||
baseImgPath: ApiService.baseImgPath,
|
||||
),
|
||||
isEditable
|
||||
? Row(
|
||||
spacing: 10,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: CustomButton(
|
||||
height: 45,
|
||||
textStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.white,
|
||||
),
|
||||
text: '提交',
|
||||
backgroundColor: Colors.blue,
|
||||
onPressed: () {
|
||||
_submit('1');
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
Expanded(
|
||||
child: CustomButton(
|
||||
textStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.white,
|
||||
),
|
||||
text: '暂存',
|
||||
backgroundColor: Colors.green,
|
||||
onPressed: () {
|
||||
_submit('0');
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Column(
|
||||
children: [
|
||||
SizedBox(height: 20),
|
||||
Row(
|
||||
children: [
|
||||
SizedBox(width: 50),
|
||||
Expanded(
|
||||
child: CustomButton(
|
||||
height: 45,
|
||||
textStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.white,
|
||||
),
|
||||
text: '返回',
|
||||
backgroundColor: Colors.green,
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
),
|
||||
SizedBox(width: 50),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,327 @@
|
|||
import 'dart:io';
|
||||
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/toast_util.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/qtfx_work_detail/hotwork_gas_list.dart';
|
||||
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
|
||||
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
|
||||
import 'package:qhd_prevention/pages/mine/mine_sign_page.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/SpecialWorkFormBaseWork.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(
|
||||
'highwork',
|
||||
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.getHighHomeworkFindById(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('highwork',
|
||||
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(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,645 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.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/gc_work/HighWorkDetailFormWidget.dart';
|
||||
import 'package:qhd_prevention/tools/h_colors.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/customWidget/bottom_picker.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/MeasuresListWidget.dart';
|
||||
|
||||
|
||||
enum EditUserType {
|
||||
GUARDIAN('监护人单位', '监护人', true),
|
||||
CONFESS('安全交底人单位', '安全交底人', true),
|
||||
ACCEPT_CONFESS('接受交底人单位', '接受交底人', true),
|
||||
WORK_USER('作业人单位', '作业人', true),
|
||||
CONFIRM('作业负责人单位', '作业负责人', true),
|
||||
LEADER('所在单位', '所在单位负责人', true),
|
||||
AUDIT('审核部门', '审核部门负责人', false),
|
||||
APPROVE('审批部门', '审批部门负责人', false),
|
||||
WORK_START('作业开始负责人单位', '作业开始负责人', true),
|
||||
WORK_END('作业结束负责人单位', '作业结束负责人', true),
|
||||
ACCEPT('验收部门', '验收部门负责人', true);
|
||||
|
||||
/// 对应的单位显示名
|
||||
final String displayName;
|
||||
final String personName;
|
||||
final bool isRequired;
|
||||
|
||||
const EditUserType(this.displayName, this.personName, this.isRequired);
|
||||
}
|
||||
|
||||
class HighworkApplyDetail extends StatefulWidget {
|
||||
const HighworkApplyDetail({
|
||||
super.key,
|
||||
required this.HIGHWORK_ID,
|
||||
required this.flow,
|
||||
});
|
||||
|
||||
final String HIGHWORK_ID;
|
||||
final String flow;
|
||||
|
||||
@override
|
||||
State<HighworkApplyDetail> createState() => _HighworkApplyDetailState();
|
||||
}
|
||||
|
||||
class _HighworkApplyDetailState extends State<HighworkApplyDetail> {
|
||||
late bool isEditable = false;
|
||||
final levelList = ["I级高处作业", "II级高处作业", "III级高处作业","IV级高处作业"];
|
||||
|
||||
/// 编辑还是新增
|
||||
late String msg = 'add';
|
||||
|
||||
/// 详情
|
||||
late Map<String, dynamic> pd = {};
|
||||
late Map<String, dynamic> signs = {};
|
||||
late List<Map<String, dynamic>> measuresList = [];
|
||||
|
||||
final TextEditingController _locationController = TextEditingController();
|
||||
final TextEditingController _hightController = TextEditingController();
|
||||
final TextEditingController _contentController = TextEditingController();
|
||||
final TextEditingController _relatedController = TextEditingController();
|
||||
final TextEditingController _riskController = TextEditingController();
|
||||
|
||||
/// 动火人及证书编号
|
||||
late List<dynamic> workUserList = [];
|
||||
|
||||
// 存储各单位的人员列表
|
||||
final Map<EditUserType, List<Map<String, dynamic>>> _personCache = {};
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.HIGHWORK_ID.length > 0) {
|
||||
msg = 'edit';
|
||||
_getData();
|
||||
} else {
|
||||
isEditable = true;
|
||||
pd['APPLY_DEPARTMENT_ID'] = SessionService.instance.deptId;
|
||||
pd['APPLY_DEPARTMENT_NAME'] =
|
||||
SessionService.instance.loginUser!['DEPARTMENT_NAME'] ?? '';
|
||||
pd['APPLY_USER_ID'] = SessionService.instance.loginUserId;
|
||||
pd['APPLY_USER_NAME'] = SessionService.instance.username;
|
||||
}
|
||||
_getHotWorkNameList();
|
||||
|
||||
_contentController.addListener(() {
|
||||
setState(() {
|
||||
pd['WORK_CONTENT'] = _contentController.text.trim();
|
||||
});
|
||||
});
|
||||
_locationController.addListener(() {
|
||||
pd['WORK_PLACE'] = _locationController.text.trim();
|
||||
});
|
||||
_hightController.addListener(() {
|
||||
pd['WORK_HIGH'] = _hightController.text.trim();
|
||||
});
|
||||
_relatedController.addListener(() {
|
||||
pd['SPECIAL_WORK'] = _relatedController.text.trim();
|
||||
});
|
||||
_riskController.addListener(() {
|
||||
pd['RISK_IDENTIFICATION'] = _riskController.text.trim();
|
||||
});
|
||||
}
|
||||
|
||||
void set_pd_DEPARTMENT_ID(EditUserType type, String id) {
|
||||
pd['${type.name}_DEPARTMENT_ID'] = id;
|
||||
}
|
||||
|
||||
void set_pd_DEPARTMENT_NAME(EditUserType type, String name) {
|
||||
pd['${type.name}_DEPARTMENT_NAME'] = name;
|
||||
}
|
||||
|
||||
void set_pd_USER_ID(EditUserType type, String id) {
|
||||
pd['${type.name}_USER_ID'] = id;
|
||||
}
|
||||
|
||||
void set_pd_USER_Name(EditUserType type, String name) {
|
||||
pd['${type.name}_USER_NAME'] = name;
|
||||
}
|
||||
|
||||
String get_pd_DEPARTMENT_ID(EditUserType type) {
|
||||
return pd['${type.name}_DEPARTMENT_ID'] ?? '';
|
||||
}
|
||||
|
||||
String get_pd_DEPARTMENT_NAME(EditUserType type) {
|
||||
return pd['${type.name}_DEPARTMENT_NAME'] ?? '';
|
||||
}
|
||||
|
||||
String get_pd_USER_ID(EditUserType type) {
|
||||
return pd['${type.name}_USER_ID'] ?? '';
|
||||
}
|
||||
|
||||
String get_pd_USER_Name(EditUserType type) {
|
||||
return pd['${type.name}_USER_NAME'] ?? '';
|
||||
}
|
||||
|
||||
Future<void> _chooseLevel() async {
|
||||
final choice = await BottomPicker.show<String>(
|
||||
context,
|
||||
items: levelList,
|
||||
itemBuilder: (item) => Text(item, textAlign: TextAlign.center),
|
||||
initialIndex: 0,
|
||||
);
|
||||
if (choice != null) {
|
||||
// 用户点击确定并选择了 choice
|
||||
setState(() {
|
||||
pd['WORK_LEVEL_NAME'] = choice;
|
||||
pd['WORK_LEVEL'] = (levelList.indexOf(choice) + 1).toString();
|
||||
FocusHelper.clearFocus(context);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Widget _card(Widget child) {
|
||||
return Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 5),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _chooseItem(EditUserType type) {
|
||||
bool isClean = false;
|
||||
|
||||
if (isEditable) {
|
||||
if (type == EditUserType.AUDIT && (pd['WORK_LEVEL'] ?? '') == '二级') {
|
||||
isClean = true;
|
||||
}
|
||||
if (type == EditUserType.APPROVE &&
|
||||
((pd['WORK_LEVEL'] ?? '') == '二级' ||
|
||||
(pd['WORK_LEVEL'] ?? '') == '一级')) {
|
||||
isClean = true;
|
||||
}
|
||||
}
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
ItemListWidget.selectableLineTitleTextField(
|
||||
isRequired: type.isRequired,
|
||||
label: type.displayName,
|
||||
isEditable: isEditable,
|
||||
isClean: isClean,
|
||||
onTapClean: () {
|
||||
setState(() {
|
||||
pd['${type.name}_DEPARTMENT_NAME'] = '';
|
||||
pd['${type.name}_USER_NAME'] = '';
|
||||
_personCache.remove(type);
|
||||
});
|
||||
},
|
||||
text: pd['${type.name}_DEPARTMENT_NAME'] ?? '请选择',
|
||||
onTap: () => chooseUnitHandle(type),
|
||||
),
|
||||
Divider(),
|
||||
ItemListWidget.selectableLineTitleTextField(
|
||||
isRequired: type.isRequired,
|
||||
label: type.personName,
|
||||
isEditable: isEditable,
|
||||
text: pd['${type.name}_USER_NAME'] ?? '请选择',
|
||||
onTap: () => choosePersonHandle(type),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// 弹出单位选择
|
||||
void chooseUnitHandle(EditUserType type) {
|
||||
FocusHelper.clearFocus(context);
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
barrierColor: Colors.black54,
|
||||
backgroundColor: Colors.transparent,
|
||||
builder:
|
||||
(_) => DepartmentPicker(
|
||||
onSelected: (id, name) async {
|
||||
setState(() {
|
||||
set_pd_DEPARTMENT_ID(type, id);
|
||||
set_pd_DEPARTMENT_NAME(type, name);
|
||||
set_pd_USER_ID(type, '');
|
||||
set_pd_USER_Name(type, '');
|
||||
});
|
||||
_getPersonListForUnitId(id, type);
|
||||
},
|
||||
),
|
||||
).then((_) {
|
||||
FocusHelper.clearFocus(context);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _getPersonListForUnitId(String id, EditUserType type) async {
|
||||
// 拉取该单位的人员列表并缓存
|
||||
final result = await ApiService.getListTreePersonList(id);
|
||||
setState(() {
|
||||
_personCache[type] = List<Map<String, dynamic>>.from(
|
||||
result['userList'] as List,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/// 弹出人员选择,需先选择单位
|
||||
void choosePersonHandle(EditUserType type) async {
|
||||
FocusHelper.clearFocus(context);
|
||||
|
||||
String unitId = get_pd_DEPARTMENT_ID(type);
|
||||
final personList = _personCache[type] ?? [];
|
||||
if (!unitId.isNotEmpty) {
|
||||
final unitName = type.displayName;
|
||||
ToastUtil.showNormal(context, '请先选择$unitName');
|
||||
return;
|
||||
}
|
||||
|
||||
if (personList.isEmpty) { // 一般这种情况是因为重新编辑没有缓存对应部门的负责人,所以先拉取一下接口
|
||||
await _getPersonListForUnitId(unitId, type);
|
||||
final list = _personCache[type] ?? [];
|
||||
|
||||
if (list.isEmpty) { // 如果还是没数据,说明该部门没有可选的人
|
||||
ToastUtil.showNormal(context, '暂无数据,请选择其他单位');
|
||||
}else{
|
||||
choosePersonHandle(type);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (personList.isEmpty) {
|
||||
// 如果还是没数据,说明该部门没有可选的人
|
||||
ToastUtil.showNormal(context, '请先选择' + type.displayName);
|
||||
return;
|
||||
}
|
||||
DepartmentPersonPicker.show(
|
||||
context,
|
||||
personsData: personList,
|
||||
onSelected: (userId, name) {
|
||||
setState(() {
|
||||
set_pd_USER_ID(type, userId);
|
||||
set_pd_USER_Name(type, name);
|
||||
});
|
||||
},
|
||||
).then((_) {
|
||||
FocusHelper.clearFocus(context);
|
||||
});
|
||||
}
|
||||
|
||||
/// 提交 1 提交 0暂存
|
||||
Future<void> _submit(String status) async {
|
||||
// 通用文本字段校验规则
|
||||
final textRules = <Map<String, dynamic>>[
|
||||
{'value': _locationController.text.trim(), 'message': '请填写地点及部位'},
|
||||
{'value': _hightController.text.trim(), 'message': '请填写高度'},
|
||||
|
||||
{'value': _contentController.text.trim(), 'message': '请填写作业内容'},
|
||||
{
|
||||
'value': _relatedController.text.trim(),
|
||||
'message': '请输入关联的其他特殊作业及安全作业票编号',
|
||||
},
|
||||
{'value': _riskController.text.trim(), 'message': '请填写风险辨识结果'},
|
||||
];
|
||||
final level = pd['WORK_LEVEL'] ?? '';
|
||||
print('---level-$level');
|
||||
|
||||
/// 各项负责人校验
|
||||
final unitRules = <EditUserType>[
|
||||
EditUserType.GUARDIAN,
|
||||
EditUserType.CONFESS,
|
||||
EditUserType.ACCEPT_CONFESS,
|
||||
EditUserType.CONFIRM,
|
||||
EditUserType.LEADER,
|
||||
// EditUserType.AUDIT,
|
||||
// EditUserType.APPROVE,
|
||||
EditUserType.WORK_USER,
|
||||
EditUserType.WORK_START,
|
||||
EditUserType.WORK_END,
|
||||
EditUserType.ACCEPT,
|
||||
];
|
||||
if (status == '1') {
|
||||
// 文本校验
|
||||
for (var rule in textRules) {
|
||||
if ((rule['value'] as String).isEmpty) {
|
||||
ToastUtil.showNormal(context, rule['message']);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 级别校验
|
||||
if (level.length == 0) {
|
||||
ToastUtil.showNormal(context, '请输入高处作业级别');
|
||||
return;
|
||||
}
|
||||
|
||||
for (var type in unitRules) {
|
||||
if (get_pd_DEPARTMENT_ID(type).length == 0) {
|
||||
ToastUtil.showNormal(context, '请选择${type.displayName}');
|
||||
return;
|
||||
}
|
||||
if (get_pd_USER_ID(type).length == 0) {
|
||||
ToastUtil.showNormal(context, '请选择${type.displayName}负责人');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// LoadingDialogHelper.show(context);
|
||||
|
||||
String taskId = '0';
|
||||
if (pd['WORK_LEVEL'] == '1') {
|
||||
taskId = '5';
|
||||
} else if (pd['WORK_LEVEL'] == '2' || pd['WORK_LEVEL'] == '3') {
|
||||
taskId = '6';
|
||||
} else if (pd['WORK_LEVEL'] == '4') {
|
||||
taskId = '7';
|
||||
}
|
||||
|
||||
// 提交参数
|
||||
if (msg == 'add') {
|
||||
pd['CORPINFO_ID'] = SessionService.instance.corpinfoId;
|
||||
pd['CREATOR'] = SessionService.instance.loginUserId;
|
||||
pd['OPERATOR'] = SessionService.instance.loginUserId;
|
||||
pd['ACTION_USER'] = SessionService.instance.username;
|
||||
pd['APPLY_STATUS'] = status;
|
||||
pd['STEP_ID'] = status;
|
||||
pd['TASK_ID'] = taskId;
|
||||
pd['HIGHWORK_ID'] = widget.HIGHWORK_ID;
|
||||
pd['APPLY_DEPARTMENT_ID'] = SessionService.instance.deptId;
|
||||
pd['APPLY_DEPARTMENT_NAME'] =
|
||||
SessionService.instance.loginUser?['DEPARTMENT_NAME'] ?? '';
|
||||
pd['APPLY_USER_ID'] = SessionService.instance.loginUserId;
|
||||
pd['APPLY_USER_NAME'] = SessionService.instance.username;
|
||||
pd['USER_ID'] = SessionService.instance.loginUserId;
|
||||
}
|
||||
|
||||
LoadingDialogHelper.show(context);
|
||||
String jsonStr = jsonEncode(pd);
|
||||
printLongString(jsonStr);
|
||||
try {
|
||||
String url = "/app/highwork/" + msg;
|
||||
final result = await ApiService.submitHomework(url, pd);
|
||||
LoadingDialogHelper.hide(context);
|
||||
if (result['result'] == 'success') {
|
||||
ToastUtil.showSuccess(context, status == '1' ? '提交成功' : '已暂存');
|
||||
Navigator.pop(context);
|
||||
}
|
||||
} catch (e) {
|
||||
LoadingDialogHelper.hide(context);
|
||||
ToastUtil.showNormal(context, '操作失败:$e');
|
||||
}
|
||||
}
|
||||
|
||||
void printLongString(String text, {int chunkSize = 800}) {
|
||||
final pattern = RegExp('.{1,$chunkSize}'); // 每 chunkSize 个字符一组
|
||||
for (final match in pattern.allMatches(text)) {
|
||||
print(match.group(0));
|
||||
}
|
||||
}
|
||||
|
||||
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.getHighHomeworkFindById(widget.HIGHWORK_ID);
|
||||
setState(() {
|
||||
pd = data['pd'];
|
||||
if (pd['STEP_ID'] == 0) {
|
||||
isEditable = true;
|
||||
} else {
|
||||
_getSigns(pd['HIGHWORK_ID'] ?? '');
|
||||
_getMeasures(pd['HIGHWORK_ID'] ?? '');
|
||||
}
|
||||
// 给所有输入框赋值
|
||||
_contentController.text = pd['WORK_CONTENT'] ?? '';
|
||||
_locationController.text = pd['WORK_PLACE'] ?? '';
|
||||
_hightController.text = pd['WORK_HIGH'] ?? '';
|
||||
_relatedController.text = pd['SPECIAL_WORK'] ?? '';
|
||||
_riskController.text = pd['RISK_IDENTIFICATION'] ?? '';
|
||||
});
|
||||
// final data = await ApiService.getHighHomeworkFindById(widget.HIGHWORK_ID);
|
||||
// setState(() {
|
||||
// pd = data['pd'];
|
||||
// });
|
||||
// LoadingDialogHelper.hide(context);
|
||||
}
|
||||
|
||||
Future<void> _getSigns(String homework_id) async {
|
||||
final data = await ApiService.listSignFinished(
|
||||
homework_id.length > 0 ? homework_id : widget.HIGHWORK_ID,
|
||||
);
|
||||
setState(() {
|
||||
signs = data['signs'] ?? {};
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _getMeasures(String homework_id) async {
|
||||
final data = await ApiService.listSignFinishMeasures('highwork',
|
||||
homework_id.length > 0 ? homework_id : widget.HIGHWORK_ID,
|
||||
);
|
||||
setState(() {
|
||||
measuresList = List<Map<String, dynamic>>.from(
|
||||
data['finishMeasuresList'] ?? <Map<String, dynamic>>[],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: h_backGroundColor(),
|
||||
appBar: MyAppbar(title: '高处作业申请'),
|
||||
body: SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Column(
|
||||
children: [
|
||||
_card(
|
||||
HighWorkDetailFormWidget(
|
||||
pd: pd,
|
||||
isEditable: isEditable,
|
||||
contentController: _contentController,
|
||||
locationController: _locationController,
|
||||
hightController: _hightController,
|
||||
relatedController: _relatedController,
|
||||
riskController: _riskController,
|
||||
onChooseLevel: _chooseLevel,
|
||||
),
|
||||
),
|
||||
if (isEditable)
|
||||
Column(
|
||||
children: [
|
||||
|
||||
SizedBox(height: 15),
|
||||
_card(_chooseItem(EditUserType.GUARDIAN)),
|
||||
SizedBox(height: 15),
|
||||
_card(_chooseItem(EditUserType.CONFESS)),
|
||||
SizedBox(height: 15),
|
||||
_card(_chooseItem(EditUserType.ACCEPT_CONFESS)),
|
||||
SizedBox(height: 15),
|
||||
_card(_chooseItem(EditUserType.WORK_USER)),
|
||||
SizedBox(height: 15),
|
||||
_card(_chooseItem(EditUserType.CONFIRM)),
|
||||
SizedBox(height: 15),
|
||||
_card(_chooseItem(EditUserType.LEADER)),
|
||||
SizedBox(height: 15),
|
||||
_card(_chooseItem(EditUserType.AUDIT)),
|
||||
SizedBox(height: 15),
|
||||
_card(_chooseItem(EditUserType.APPROVE)),
|
||||
SizedBox(height: 15),
|
||||
_card(
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
_chooseItem(EditUserType.WORK_START),
|
||||
Divider(),
|
||||
Row(
|
||||
children: [
|
||||
SizedBox(width: 12),
|
||||
Text(
|
||||
'友情提示:负责填写作业实际开始时间',
|
||||
style: TextStyle(color: Colors.red),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 15),
|
||||
_card(
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
_chooseItem(EditUserType.WORK_END),
|
||||
Divider(),
|
||||
Row(
|
||||
children: [
|
||||
SizedBox(width: 12),
|
||||
Text(
|
||||
'友情提示:负责填写作业实际结束时间',
|
||||
style: TextStyle(color: Colors.red),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 15),
|
||||
_card(_chooseItem(EditUserType.ACCEPT)),
|
||||
SizedBox(height: 15),
|
||||
],
|
||||
),
|
||||
if (measuresList.length > 0)
|
||||
Column(
|
||||
children: [
|
||||
SizedBox(height: 20),
|
||||
ListItemFactory.createBuildSimpleSection('安全防护措施'),
|
||||
Container(
|
||||
color: Colors.white,
|
||||
child: MeasuresListWidget(
|
||||
measuresList:
|
||||
measuresList, // List<Map<String, dynamic>>
|
||||
baseImgPath: ApiService.baseImgPath,
|
||||
isAllowEdit: false,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
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,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SignaturesListWidget(
|
||||
signs: signs,
|
||||
pd: pd,
|
||||
baseImgPath: ApiService.baseImgPath,
|
||||
),
|
||||
isEditable
|
||||
? Row(
|
||||
spacing: 10,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: CustomButton(
|
||||
height: 45,
|
||||
textStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.white,
|
||||
),
|
||||
text: '提交',
|
||||
backgroundColor: Colors.blue,
|
||||
onPressed: () {
|
||||
_submit('1');
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
Expanded(
|
||||
child: CustomButton(
|
||||
textStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.white,
|
||||
),
|
||||
text: '暂存',
|
||||
backgroundColor: Colors.green,
|
||||
onPressed: () {
|
||||
_submit('0');
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Column(
|
||||
children: [
|
||||
SizedBox(height: 20),
|
||||
Row(
|
||||
children: [
|
||||
SizedBox(width: 50),
|
||||
Expanded(
|
||||
child: CustomButton(
|
||||
height: 45,
|
||||
textStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.white,
|
||||
),
|
||||
text: '返回',
|
||||
backgroundColor: Colors.green,
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
),
|
||||
SizedBox(width: 50),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +1,34 @@
|
|||
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/dh_work_detai/hotwork_apply_detail.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/aqcs_work_detail/hotwork_safe_func_sure.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/aqgl_work_detail/hotwork_aqgl_detail.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/aqjd_work_detail/hotwork_aqjd_detail.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/dbbz_work_detail/hotwork_dbbz_detail.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/dhsp_work_detail/hotwork_dhsp_detail.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/jhr_work_detail/hotwork_jhr_detail.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/jszy_work_detail/hotwork_jszy_detail.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/kszy_work_detail/hotwork_kszy_detail.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/szaq_work_detail/hotwork_set_safe_detail.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/szdw_work_detail/hotwork_szdw_detail.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/ysgd_work_detail/hotwork_ysgd_detail.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/zyfz_work_detail/hotwork_zyfz_detail.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/gc_work/gc_work_detai/highwork_apply_detail.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/gc_work/aqcs_work_detail/hotwork_safe_func_sure.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/gc_work/aqgl_work_detail/hotwork_aqgl_detail.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/gc_work/aqjd_work_detail/hotwork_aqjd_detail.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/gc_work/dbbz_work_detail/hotwork_dbbz_detail.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/gc_work/dhsp_work_detail/hotwork_dhsp_detail.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/gc_work/jhr_work_detail/hotwork_jhr_detail.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/gc_work/jszy_work_detail/hotwork_jszy_detail.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/gc_work/kszy_work_detail/hotwork_kszy_detail.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/gc_work/szaq_work_detail/highwork_set_safe_detail.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/gc_work/szdw_work_detail/hotwork_szdw_detail.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/gc_work/ysgd_work_detail/hotwork_ysgd_detail.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/gc_work/zyfz_work_detail/hotwork_zyfz_detail.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
import 'package:qhd_prevention/customWidget/bottom_picker.dart';
|
||||
import 'package:qhd_prevention/customWidget/custom_button.dart';
|
||||
import 'package:qhd_prevention/customWidget/search_bar_widget.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/dh_work/qtfx_work_detail/hotwork_gas_list.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/dh_work/jsjd_work_detail/hotwork_jsjd_detail.dart';
|
||||
|
||||
class HighworkListPage extends StatefulWidget {
|
||||
final String flow;
|
||||
final String workTypeTitle;
|
||||
const HighworkListPage({Key? key, required this.flow, required this.workTypeTitle}) : super(key: key);
|
||||
|
||||
const HighworkListPage({
|
||||
Key? key,
|
||||
required this.flow,
|
||||
required this.workTypeTitle,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_HighworkListPageState createState() => _HighworkListPageState();
|
||||
|
|
@ -128,16 +131,17 @@ class _HighworkListPageState extends State<HighworkListPage> {
|
|||
list.clear();
|
||||
_fetchData();
|
||||
}
|
||||
|
||||
/// 申请
|
||||
void _handleApply() {
|
||||
// 处理申请按钮点击逻辑
|
||||
pushPage(HotworkApplyDetail(HOTWORK_ID: '', flow: widget.flow), context);
|
||||
pushPage(HighworkApplyDetail(HIGHWORK_ID: '', flow: widget.flow), context);
|
||||
}
|
||||
|
||||
/// 打开流程图
|
||||
Future<void> _openFlowDrawer(String hotworkId) async {
|
||||
try {
|
||||
final response = await ApiService.dhGetFlowList(hotworkId);
|
||||
final response = await ApiService.highGetFlowList(hotworkId);
|
||||
final List<dynamic>? newFlow = response['flowList'];
|
||||
if (newFlow == null || newFlow.isEmpty) {
|
||||
ToastUtil.showNormal(context, '暂无流程图数据');
|
||||
|
|
@ -159,70 +163,73 @@ class _HighworkListPageState extends State<HighworkListPage> {
|
|||
}
|
||||
|
||||
void _goToDetail(Map<String, dynamic> item) async {
|
||||
final Map<String, dynamic> data = {'HOTWORK_ID': item['HOTWORK_ID'], 'flow': widget.flow};
|
||||
final Map<String, dynamic> data = {
|
||||
'HIGHWORK_ID': item['HIGHWORK_ID'],
|
||||
'flow': widget.flow,
|
||||
};
|
||||
String routeName = '';
|
||||
switch (widget.flow) {
|
||||
case '提交申请':
|
||||
//await pushPage(HotworkApplyDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
|
||||
await pushPage(HighworkApplyDetail(HIGHWORK_ID: item['HIGHWORK_ID'], flow: widget.flow), context);
|
||||
break;
|
||||
case '设置安全措施确认人':
|
||||
//await pushPage(HotworkSetSafeDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
|
||||
await pushPage(HighworkSetSafeDetail(HIGHWORK_ID: item['HIGHWORK_ID'], flow: widget.flow), context);
|
||||
break;
|
||||
case '安全措施确认':
|
||||
//await pushPage(HotworkSafeFuncSure(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
|
||||
//await pushPage(HotworkSafeFuncSure(HIGHWORK_ID: item['HIGHWORK_ID'], flow: widget.flow), context);
|
||||
break;
|
||||
case '监护人签字':
|
||||
routeName = '/hotwork-guardian-detail';
|
||||
//await pushPage(HotworkJhrDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
|
||||
//await pushPage(HotworkJhrDetail(HIGHWORK_ID: item['HIGHWORK_ID'], flow: widget.flow), context);
|
||||
break;
|
||||
case '安全交底人签字':
|
||||
routeName = '/hotwork-confess-detail';
|
||||
//await pushPage(HotworkAqjdDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
|
||||
//await pushPage(HotworkAqjdDetail(HIGHWORK_ID: item['HIGHWORK_ID'], flow: widget.flow), context);
|
||||
|
||||
break;
|
||||
case '接受交底人签字':
|
||||
routeName = '/hotwork-acceptconfess-detail';
|
||||
//await pushPage(HotworkJsjdDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
|
||||
//await pushPage(HotworkJsjdDetail(HIGHWORK_ID: item['HIGHWORK_ID'], flow: widget.flow), context);
|
||||
|
||||
break;
|
||||
case '作业负责人签字':
|
||||
routeName = '/hotwork-confirm-detail';
|
||||
//await pushPage(HotworkZyfzDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
|
||||
//await pushPage(HotworkZyfzDetail(HIGHWORK_ID: item['HIGHWORK_ID'], flow: widget.flow), context);
|
||||
|
||||
break;
|
||||
case '所在单位签字':
|
||||
routeName = '/hotwork-leader-detail';
|
||||
//await pushPage(HotworkSzdwDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
|
||||
//await pushPage(HotworkSzdwDetail(HIGHWORK_ID: item['HIGHWORK_ID'], flow: widget.flow), context);
|
||||
|
||||
break;
|
||||
case '安全管理部门签字':
|
||||
routeName = '/hotwork-audit-detail';
|
||||
//await pushPage(HotworkAqglDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
|
||||
//await pushPage(HotworkAqglDetail(HIGHWORK_ID: item['HIGHWORK_ID'], flow: widget.flow), context);
|
||||
|
||||
break;
|
||||
case '审批人签字':
|
||||
routeName = '/hotwork-approve-detail';
|
||||
//await pushPage(HotworkDhspDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
|
||||
//await pushPage(HotworkDhspDetail(HIGHWORK_ID: item['HIGHWORK_ID'], flow: widget.flow), context);
|
||||
|
||||
break;
|
||||
case '当班班长验票':
|
||||
routeName = '/hotwork-monitor-detail';
|
||||
//await pushPage(HotworkDbbzDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
|
||||
//await pushPage(HotworkDbbzDetail(HIGHWORK_ID: item['HIGHWORK_ID'], flow: widget.flow), context);
|
||||
|
||||
break;
|
||||
case '开始作业':
|
||||
routeName = '/hotwork-startwork-detail';
|
||||
//await pushPage(HotworkKszyDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
|
||||
//await pushPage(HotworkKszyDetail(HIGHWORK_ID: item['HIGHWORK_ID'], flow: widget.flow), context);
|
||||
|
||||
break;
|
||||
case '结束作业':
|
||||
routeName = '/hotwork-endwork-detail';
|
||||
//await pushPage(HotworkJszyDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
|
||||
//await pushPage(HotworkJszyDetail(HIGHWORK_ID: item['HIGHWORK_ID'], flow: widget.flow), context);
|
||||
|
||||
break;
|
||||
case '验收签字':
|
||||
routeName = '/hotwork-accept-detail';
|
||||
//await pushPage(HotworkYsgdDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
|
||||
//await pushPage(HotworkYsgdDetail(HIGHWORK_ID: item['HIGHWORK_ID'], flow: widget.flow), context);
|
||||
|
||||
break;
|
||||
default:
|
||||
|
|
@ -235,7 +242,7 @@ class _HighworkListPageState extends State<HighworkListPage> {
|
|||
// Navigator.pushNamed(
|
||||
// context,
|
||||
// routeName,
|
||||
// arguments: {'HOTWORK_ID': item['HOTWORK_ID'], 'flow': widget.flow},
|
||||
// arguments: {'HIGHWORK_ID': item['HIGHWORK_ID'], 'flow': widget.flow},
|
||||
// );
|
||||
}
|
||||
|
||||
|
|
@ -249,9 +256,7 @@ class _HighworkListPageState extends State<HighworkListPage> {
|
|||
final Color dotColor =
|
||||
status == 1 ? Colors.green : (status == 0 ? Colors.blue : Colors.grey);
|
||||
final Color textColor =
|
||||
status == 1
|
||||
? Colors.green
|
||||
: (status == 0 ? Colors.blue : Colors.black);
|
||||
status == 1 ? Colors.green : (status == 0 ? Colors.blue : Colors.black);
|
||||
|
||||
return ListTile(
|
||||
visualDensity: VisualDensity(vertical: -4),
|
||||
|
|
@ -307,6 +312,7 @@ class _HighworkListPageState extends State<HighworkListPage> {
|
|||
),
|
||||
);
|
||||
}
|
||||
|
||||
String _getWorkLevelText(dynamic level) {
|
||||
switch (level?.toString()) {
|
||||
case '1':
|
||||
|
|
@ -319,6 +325,7 @@ class _HighworkListPageState extends State<HighworkListPage> {
|
|||
return 'IV级高处作业';
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildListItem(Map<String, dynamic> item) {
|
||||
return Card(
|
||||
color: Colors.white,
|
||||
|
|
@ -328,19 +335,22 @@ class _HighworkListPageState extends State<HighworkListPage> {
|
|||
child: Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
child: Column(
|
||||
spacing: 8,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text("编号: ${item['CHECK_NO'] ?? ''}", style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),),
|
||||
Text(
|
||||
"编号: ${item['CHECK_NO'] ?? ''}",
|
||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
||||
),
|
||||
Text(
|
||||
"作业级别: ${_getWorkLevelText(item['WORK_LEVEL'])}",
|
||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
|
|
@ -348,7 +358,6 @@ class _HighworkListPageState extends State<HighworkListPage> {
|
|||
Text("监护人: ${item['GUARDIAN_USER_NAME'] ?? ''}"),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
|
|
@ -356,36 +365,24 @@ class _HighworkListPageState extends State<HighworkListPage> {
|
|||
Text("接受交底人: ${item['ACCEPT_CONFESS_USER_NAME'] ?? ''}"),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text("作业负责人: ${item['CONFIRM_USER_NAME'] ?? ''}"),
|
||||
Text("所在单位负责人: ${item['LEADER_USER_NAME'] ?? ''}"),
|
||||
],
|
||||
),
|
||||
// const SizedBox(height: 8),
|
||||
// Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
// children: [
|
||||
// Text("作业负责人: ${item['CONFIRM_USER_NAME'] ?? ''}"),
|
||||
// Text("动火点负责人: ${item['LEADER_USER_NAME'] ?? ''}"),
|
||||
// ],
|
||||
// ),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text("作业负责人: ${item['CONFIRM_USER_NAME'] ?? ''}"),
|
||||
Text("所在单位负责人: ${item['LEADER_USER_NAME'] ?? ''}"),
|
||||
],
|
||||
),
|
||||
|
||||
if (item['AUDIT_USER_NAME'] != null)
|
||||
Text("安全管理部门负责人: ${item['AUDIT_USER_NAME'] ?? ''}"),
|
||||
if (item['APPROVE_USER_NAME'] != null)
|
||||
Text("安全管理部门负责人: ${item['APPROVE_USER_NAME'] ?? ''}"),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text("动火前在岗班长: ${item['MONITOR_USER_NAME'] ?? ''}"),
|
||||
Text("验收部门负责人: ${item['ACCEPT_USER_NAME'] ?? ''}"),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
if (item['APPROVE_USER_NAME'] != null)
|
||||
Text("审批部门负责人: ${item['APPROVE_USER_NAME'] ?? ''}"),
|
||||
Text("验收部门负责人: ${item['ACCEPT_USER_NAME'] ?? ''}"),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
|
|
@ -397,18 +394,19 @@ class _HighworkListPageState extends State<HighworkListPage> {
|
|||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(children: [
|
||||
CustomButton(
|
||||
text: '查看流程图',
|
||||
height: 35,
|
||||
padding: EdgeInsets.symmetric(horizontal: 12),
|
||||
margin: EdgeInsets.only(left: 0),
|
||||
backgroundColor: Colors.blue,
|
||||
onPressed: () => _openFlowDrawer(item['HOTWORK_ID']),
|
||||
),
|
||||
SizedBox(width: 1,)
|
||||
],)
|
||||
Row(
|
||||
children: [
|
||||
CustomButton(
|
||||
text: '查看流程图',
|
||||
height: 35,
|
||||
padding: EdgeInsets.symmetric(horizontal: 12),
|
||||
margin: EdgeInsets.only(left: 0),
|
||||
backgroundColor: Colors.blue,
|
||||
onPressed: () => _openFlowDrawer(item['HIGHWORK_ID']),
|
||||
),
|
||||
SizedBox(width: 1),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,352 @@
|
|||
import 'dart:io';
|
||||
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/toast_util.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/HotWorkDetailFormWidget.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/qtfx_work_detail/hotwork_gas_list.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/MeasuresListWidget.dart';
|
||||
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
|
||||
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
|
||||
import 'package:qhd_prevention/pages/mine/mine_sign_page.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(
|
||||
'highwork',
|
||||
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.getHighHomeworkFindById(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('highwork',
|
||||
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()),
|
||||
HotWorkDetailFormWidget(
|
||||
pd: pd,
|
||||
isEditable: false,
|
||||
onChooseLevel: (){},
|
||||
onChooseHotworkUser: (){},
|
||||
onAnalyzeTap: () {
|
||||
pushPage(
|
||||
HotworkGasList(HOTWORK_ID: widget.HOTWORK_ID),
|
||||
context,
|
||||
);
|
||||
},
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
_setSafeDetailWidget(),
|
||||
SizedBox(height: 20),
|
||||
_bottomButtons(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,308 @@
|
|||
import 'dart:io';
|
||||
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/toast_util.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/qtfx_work_detail/hotwork_gas_list.dart';
|
||||
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
|
||||
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
|
||||
import 'package:qhd_prevention/pages/mine/mine_sign_page.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/SpecialWorkFormBaseWork.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(
|
||||
'highwork',
|
||||
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.getHighHomeworkFindById(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('highwork',
|
||||
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(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,370 @@
|
|||
import 'dart:io';
|
||||
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/toast_util.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/qtfx_work_detail/hotwork_gas_list.dart';
|
||||
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
|
||||
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
|
||||
import 'package:qhd_prevention/pages/mine/mine_sign_page.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/SpecialWorkFormBaseWork.dart';
|
||||
import 'package:qhd_prevention/customWidget/picker/CupertinoDatePicker.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(
|
||||
'highwork',
|
||||
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.getHighHomeworkFindById(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('highwork',
|
||||
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(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,343 @@
|
|||
import 'dart:io';
|
||||
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/toast_util.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/qtfx_work_detail/hotwork_gas_list.dart';
|
||||
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
|
||||
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
|
||||
import 'package:qhd_prevention/pages/mine/mine_sign_page.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/SpecialWorkFormBaseWork.dart';
|
||||
|
||||
import 'package:qhd_prevention/customWidget/picker/CupertinoDatePicker.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(
|
||||
'highwork',
|
||||
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.getHighHomeworkFindById(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('highwork',
|
||||
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(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:qhd_prevention/customWidget/custom_button.dart';
|
||||
|
||||
/// 安全措施弹窗
|
||||
class SafeFunctionDialog extends StatefulWidget {
|
||||
/// 原始数据列表,每个元素为包含 "PROTECTIVE_MEASURES" 键的 Map
|
||||
final List<Map<String, dynamic>> data;
|
||||
|
||||
/// 已选中的初始数据列表
|
||||
final List<Map<String, dynamic>> initialSelectedItems;
|
||||
|
||||
/// 点击确认回调,返回选中的 Map 列表
|
||||
final void Function(List<Map<String, dynamic>> selectedItems) onConfirm;
|
||||
|
||||
/// 构造函数,支持传入已选中的数据
|
||||
const SafeFunctionDialog({
|
||||
Key? key,
|
||||
required this.data,
|
||||
this.initialSelectedItems = const [],
|
||||
required this.onConfirm,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<SafeFunctionDialog> createState() => _SafeFunctionDialogState();
|
||||
}
|
||||
|
||||
class _SafeFunctionDialogState extends State<SafeFunctionDialog> {
|
||||
/// 存放所有可选项的 Map 列表
|
||||
late final List<Map<String, dynamic>> _allItems;
|
||||
|
||||
/// 存放当前被选中的 Map 列表
|
||||
late final List<Map<String, dynamic>> _selectedItems;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// 初始化所有选项
|
||||
_allItems = widget.data;
|
||||
// 初始化已选中项,克隆一份避免修改原数据
|
||||
_selectedItems = List<Map<String, dynamic>>.from(widget.initialSelectedItems);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
insetPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 24),
|
||||
content: SizedBox(
|
||||
width: MediaQuery.of(context).size.width - 24,
|
||||
height: MediaQuery.of(context).size.height -
|
||||
MediaQuery.of(context).padding.top -
|
||||
MediaQuery.of(context).padding.bottom,
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: _allItems.length,
|
||||
itemBuilder: (ctx, index) {
|
||||
final item = _allItems[index];
|
||||
final label = item['PROTECTIVE_MEASURES'] as String? ?? '';
|
||||
final checked = _selectedItems.contains(item);
|
||||
return CheckboxListTile(
|
||||
controlAffinity: ListTileControlAffinity.leading,
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 0),
|
||||
activeColor: Colors.blue,
|
||||
title: Text(label, style: const TextStyle(fontSize: 14)),
|
||||
value: checked,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
if (value == true) {
|
||||
_selectedItems.add(item);
|
||||
} else {
|
||||
_selectedItems.remove(item);
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CustomButton(
|
||||
text: '确定',
|
||||
height: 40,
|
||||
backgroundColor: Colors.blue,
|
||||
onPressed: () {
|
||||
widget.onConfirm(_selectedItems);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: CustomButton(
|
||||
text: '关闭',
|
||||
height: 40,
|
||||
backgroundColor: Colors.grey.shade300,
|
||||
textStyle: TextStyle(color: Colors.grey.shade600),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 显示安全措施弹窗
|
||||
/// [initialSelected] 可选,指定弹窗打开时的已选项
|
||||
Future<void> showSafeFunctionDialog(
|
||||
BuildContext context,
|
||||
List<Map<String, dynamic>> data,
|
||||
void Function(List<Map<String, dynamic>>) onConfirm, {
|
||||
List<Map<String, dynamic>> initialSelected = const [],
|
||||
}) {
|
||||
return showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (_) => SafeFunctionDialog(
|
||||
data: data,
|
||||
initialSelectedItems: initialSelected,
|
||||
onConfirm: onConfirm,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,599 @@
|
|||
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/gc_work/HighWorkDetailFormWidget.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
|
||||
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
|
||||
import 'package:qhd_prevention/pages/mine/mine_sign_page.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/dh_work/szaq_work_detail/SafeFunctionDialog.dart';
|
||||
/// 设置安全措施确认人
|
||||
class HighworkSetSafeDetail extends StatefulWidget {
|
||||
const HighworkSetSafeDetail({
|
||||
super.key,
|
||||
required this.HIGHWORK_ID,
|
||||
required this.flow,
|
||||
});
|
||||
|
||||
final String HIGHWORK_ID;
|
||||
final String flow;
|
||||
|
||||
@override
|
||||
State<HighworkSetSafeDetail> createState() => _HighworkSetSafeDetailState();
|
||||
}
|
||||
|
||||
class _HighworkSetSafeDetailState extends State<HighworkSetSafeDetail> {
|
||||
late bool isEditable = false;
|
||||
|
||||
/// 详情
|
||||
late Map<String, dynamic> pd = {};
|
||||
late List<Map<String, dynamic>> measuresList = [];
|
||||
|
||||
/// 安全防护措施列表
|
||||
late List<MeasureItem> measuresListCopy = [];
|
||||
List<String> imagePaths = [];
|
||||
List<String> signTimes = []; // 签字时间列表
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_getData();
|
||||
addMeasuresListCopy();
|
||||
}
|
||||
|
||||
String measuresListToJson() {
|
||||
final List<Map<String, dynamic>> jsonList =
|
||||
measuresListCopy.map((item) => item.toJson()).toList();
|
||||
return jsonEncode(jsonList);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Widget _chooseItem(MeasureItem item) {
|
||||
return Column(
|
||||
children: [
|
||||
ItemListWidget.selectableLineTitleTextField(
|
||||
label: "确认单位",
|
||||
isEditable: true,
|
||||
text: item.DEPARTMENT_NAME ?? '请选择',
|
||||
onTap: () => chooseUnitHandle(item),
|
||||
),
|
||||
Divider(height: 8, color: Colors.grey.shade200),
|
||||
ItemListWidget.selectableLineTitleTextField(
|
||||
label: '确认人',
|
||||
isEditable: true,
|
||||
text: item.USER_NAME ?? '请选择',
|
||||
onTap: () => choosePersonHandle(item),
|
||||
),
|
||||
Divider(height: 8, color: Colors.grey.shade200),
|
||||
// 安全措施
|
||||
ItemListWidget.OneRowButtonTitle(
|
||||
isRequired: true,
|
||||
label: '安全措施:',
|
||||
buttonText: '选择安全措施',
|
||||
onTap: () {
|
||||
showSafeFunctionDialog(
|
||||
context,
|
||||
measuresList,
|
||||
initialSelected: item.selectMeasures,
|
||||
(selected) {
|
||||
setState(() {
|
||||
item.selectMeasures = selected;
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// 弹出单位选择
|
||||
void chooseUnitHandle(MeasureItem item) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
barrierColor: Colors.black54,
|
||||
backgroundColor: Colors.transparent,
|
||||
builder:
|
||||
(_) => DepartmentPicker(
|
||||
onSelected: (id, name) async {
|
||||
setState(() {
|
||||
item.DEPARTMENT_ID = id;
|
||||
item.DEPARTMENT_NAME = name;
|
||||
});
|
||||
_getPersonListForUnitId(item);
|
||||
},
|
||||
),
|
||||
).then((_) {});
|
||||
}
|
||||
|
||||
Future<void> _getPersonListForUnitId(MeasureItem item) async {
|
||||
// 拉取该单位的人员列表并缓存
|
||||
final result = await ApiService.getListTreePersonList(item.DEPARTMENT_ID);
|
||||
setState(() {
|
||||
item.userList = List<Map<String, dynamic>>.from(
|
||||
result['userList'] ?? <Map<String, dynamic>>[],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/// 弹出人员选择,需先选择单位
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
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_HIGHWORK_MEASURES_ID': item['BUS_HIGHWORK_MEASURES_ID'],
|
||||
'USER_ID': userId,
|
||||
});
|
||||
}
|
||||
// 检查长度是否一致
|
||||
if (signers.length != measuresList.length) {
|
||||
// 使用 ScaffoldMessenger 弹出提示
|
||||
ToastUtil.showNormal(context, '请为每个安全措施选择确认人');
|
||||
return;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
} 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['HIGHWORK_ID'] = widget.HIGHWORK_ID;
|
||||
formData['SIGNTIME'] = signTimes.join(',');
|
||||
formData['USER_ID'] = SessionService.instance.loginUserId;
|
||||
formData['APPLY_STATUS'] = status;
|
||||
formData['STEP_REASON'] = reasonText;
|
||||
formData['PREPARERS'] = json.encode(signers);
|
||||
|
||||
await showDialog<String>(
|
||||
context: context,
|
||||
builder:
|
||||
(_) => CustomAlertDialog(
|
||||
title: '提示',
|
||||
content: '请确认' + (status == '1' ? "通过" : "作废") + '本作业票?',
|
||||
cancelText: '取消',
|
||||
confirmText: '确定',
|
||||
onConfirm: () async {
|
||||
LoadingDialogHelper.show(context);
|
||||
try {
|
||||
final result = await ApiService.saveSafeFunctionSure(
|
||||
'highwork',
|
||||
formData,
|
||||
imagePaths,
|
||||
);
|
||||
LoadingDialogHelper.hide(context);
|
||||
if (result['result'] == 'success') {
|
||||
ToastUtil.showSuccess(
|
||||
context,
|
||||
'保存成功',
|
||||
);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
} catch (e) {
|
||||
LoadingDialogHelper.hide(context);
|
||||
ToastUtil.showNormal(context, '操作失败:$e');
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void printLongString(String text, {int chunkSize = 800}) {
|
||||
final pattern = RegExp('.{1,$chunkSize}'); // 每 chunkSize 个字符一组
|
||||
for (final match in pattern.allMatches(text)) {
|
||||
print(match.group(0));
|
||||
}
|
||||
}
|
||||
|
||||
/// 初始化拉取数据
|
||||
Future<void> _getData() async {
|
||||
final data = await ApiService.getHighHomeworkFindById(widget.HIGHWORK_ID);
|
||||
setState(() {
|
||||
pd = data['pd'];
|
||||
_getMeasures();
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _getMeasures() async {
|
||||
final data = await ApiService.listSignFinishAllMeasures('highwork');
|
||||
setState(() {
|
||||
measuresList = List<Map<String, dynamic>>.from(
|
||||
data['measuresList'] ?? <Map<String, dynamic>>[],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
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: [],
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/// 安全防护措施
|
||||
Widget _setSafeDetailWidget() {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: 5),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
ListItemFactory.createBuildSimpleSection('安全防护措施'),
|
||||
CustomButton(
|
||||
text: '添加',
|
||||
padding: EdgeInsets.symmetric(horizontal: 15),
|
||||
backgroundColor: Colors.blue,
|
||||
height: 32,
|
||||
onPressed: () => addMeasuresListCopy(),
|
||||
),
|
||||
],
|
||||
),
|
||||
...measuresListCopy.asMap().entries.map((entry) {
|
||||
int index = entry.key;
|
||||
MeasureItem item = entry.value;
|
||||
return Padding(
|
||||
padding: EdgeInsets.all(0),
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
color: Colors.white,
|
||||
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(2),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
border: Border.all(color: Colors.grey.shade300),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 部门 picker
|
||||
_chooseItem(item),
|
||||
|
||||
...item.selectMeasures.asMap().entries.map((e) {
|
||||
int idx = e.key;
|
||||
String txt = e.value['PROTECTIVE_MEASURES'];
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(
|
||||
top: 4,
|
||||
left: 12,
|
||||
right: 12,
|
||||
bottom: 12,
|
||||
),
|
||||
child: Text('${idx + 1}. $txt'),
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (index != 0)
|
||||
Positioned(
|
||||
top: 0,
|
||||
right: 0,
|
||||
child: GestureDetector(
|
||||
onTap: () => removeMeasuresListCopy(index),
|
||||
child: Stack(
|
||||
alignment: AlignmentDirectional.center,
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.red,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
width: 20,
|
||||
height: 20,
|
||||
),
|
||||
Icon(Icons.close, color: Colors.white, size: 15),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
SizedBox(height: 20),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
SizedBox(),
|
||||
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()),
|
||||
HighWorkDetailFormWidget(
|
||||
pd: pd,
|
||||
isEditable: false,
|
||||
onChooseLevel: (){},
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
_setSafeDetailWidget(),
|
||||
SizedBox(height: 20),
|
||||
_bottomButtons(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MeasureItem {
|
||||
final double id;
|
||||
String DEPARTMENT_ID;
|
||||
String DEPARTMENT_NAME;
|
||||
String USER_ID;
|
||||
String USER_NAME;
|
||||
List<Map<String, dynamic>> userList;
|
||||
int userIndex;
|
||||
List<Map<String, dynamic>> selectMeasures;
|
||||
|
||||
MeasureItem({
|
||||
required this.id,
|
||||
this.DEPARTMENT_ID = '',
|
||||
this.DEPARTMENT_NAME = '',
|
||||
this.USER_ID = '',
|
||||
this.USER_NAME = '',
|
||||
List<Map<String, dynamic>>? userList,
|
||||
this.userIndex = -1,
|
||||
List<Map<String, dynamic>>? selectMeasures,
|
||||
}) : userList = userList ?? [],
|
||||
selectMeasures = selectMeasures ?? [];
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'DEPARTMENT_ID': DEPARTMENT_ID,
|
||||
'DEPARTMENT_NAME': DEPARTMENT_NAME,
|
||||
'USER_ID': USER_ID,
|
||||
'USER_NAME': USER_NAME,
|
||||
'userList': userList,
|
||||
'userIndex': userIndex,
|
||||
'selectMeasures': selectMeasures,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,327 @@
|
|||
import 'dart:io';
|
||||
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/toast_util.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/qtfx_work_detail/hotwork_gas_list.dart';
|
||||
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
|
||||
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
|
||||
import 'package:qhd_prevention/pages/mine/mine_sign_page.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/SpecialWorkFormBaseWork.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(
|
||||
'highwork',
|
||||
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.getHighHomeworkFindById(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('highwork',
|
||||
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(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,411 @@
|
|||
import 'dart:io';
|
||||
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/toast_util.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/qtfx_work_detail/hotwork_gas_list.dart';
|
||||
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
|
||||
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
|
||||
import 'package:qhd_prevention/pages/mine/mine_sign_page.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/SpecialWorkFormBaseWork.dart';
|
||||
import 'package:qhd_prevention/customWidget/picker/CupertinoDatePicker.dart';
|
||||
import 'package:qhd_prevention/customWidget/photo_picker_row.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(
|
||||
'highwork',
|
||||
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.getHighHomeworkFindById(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('highwork',
|
||||
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(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,326 @@
|
|||
import 'dart:io';
|
||||
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/toast_util.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/qtfx_work_detail/hotwork_gas_list.dart';
|
||||
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
|
||||
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
|
||||
import 'package:qhd_prevention/pages/mine/mine_sign_page.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/SpecialWorkFormBaseWork.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(
|
||||
'highwork',
|
||||
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.getHighHomeworkFindById(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('highwork',
|
||||
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(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -289,46 +289,54 @@ void presentPage(BuildContext context, Widget page) {
|
|||
}
|
||||
|
||||
class LoadingDialogHelper {
|
||||
/// 显示 loading,对话框中可选文字
|
||||
// 保存对话框自己的 context
|
||||
static BuildContext? _dialogContext;
|
||||
|
||||
static void show(BuildContext context, {String? message}) {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (_) => Center(
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black87,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const CircularProgressIndicator(
|
||||
valueColor: AlwaysStoppedAnimation(Colors.white),
|
||||
),
|
||||
if (message != null) ...[
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
message,
|
||||
style: TextStyle(color: Colors.white),
|
||||
builder: (dialogContext) {
|
||||
// 存下来,后面 hide 时一定用它
|
||||
_dialogContext = dialogContext;
|
||||
return Center(
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black87,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const CircularProgressIndicator(
|
||||
valueColor: AlwaysStoppedAnimation(Colors.white),
|
||||
),
|
||||
if (message != null) ...[
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
message,
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
],
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// 隐藏 loading
|
||||
static void hide(BuildContext context) {
|
||||
if (Navigator.canPop(context)) {
|
||||
Navigator.of(context).pop();
|
||||
if (_dialogContext != null && Navigator.canPop(_dialogContext!)) {
|
||||
Navigator.of(_dialogContext!).pop();
|
||||
_dialogContext = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// 将秒数转换为 “HH:MM:SS” 格式
|
||||
String secondsCount(dynamic seconds) {
|
||||
// 先尝试解析出一个 double 值
|
||||
|
|
|
|||
Loading…
Reference in New Issue