设置安全措施确认人,签字板添加白色背景,查看大图添加本地图片支持
parent
9348f657e5
commit
d672f1d944
|
@ -1,3 +1,5 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:photo_view/photo_view.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
|
@ -8,6 +10,12 @@ class SingleImageViewer extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
ImageProvider provider;
|
||||
if (imageUrl.toLowerCase().startsWith('http')) {
|
||||
provider = NetworkImage(imageUrl);
|
||||
} else {
|
||||
provider = FileImage(File(imageUrl));
|
||||
}
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.black.withValues(alpha: 0.5),
|
||||
appBar: MyAppbar(
|
||||
|
@ -21,7 +29,7 @@ class SingleImageViewer extends StatelessWidget {
|
|||
),
|
||||
body: Center(
|
||||
child: PhotoView(
|
||||
imageProvider: NetworkImage(imageUrl),
|
||||
imageProvider: provider,
|
||||
backgroundDecoration: BoxDecoration(color: Colors.black.withValues(alpha:0.5)),
|
||||
minScale: PhotoViewComputedScale.contained,
|
||||
maxScale: PhotoViewComputedScale.covered * 2,
|
||||
|
|
|
@ -692,16 +692,15 @@ U6Hzm1ninpWeE+awIDAQAB
|
|||
);
|
||||
}
|
||||
/// 所有安全防护措施
|
||||
static Future<Map<String, dynamic>> listSignFinishAllMeasures(String hotworkId) {
|
||||
static Future<Map<String, dynamic>> listSignFinishAllMeasures() {
|
||||
final String tm = DateTime.now().millisecondsSinceEpoch.toString();
|
||||
return HttpManager().request(
|
||||
basePath,
|
||||
'/app/hotwork/listAllMeasuresForSign?tm=$tm',
|
||||
'/app/hotwork/listAllMeasures?tm=$tm',
|
||||
method: Method.post,
|
||||
data: {
|
||||
"CORPINFO_ID":SessionService.instance.corpinfoId,
|
||||
"CONFIRM_ID":SessionService.instance.loginUserId,
|
||||
"HOTWORK_ID":hotworkId,
|
||||
"USER_ID":SessionService.instance.loginUserId,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -319,7 +319,6 @@ class ItemListWidget {
|
|||
}
|
||||
/// 单行布局:
|
||||
/// 标题 + 文字 + 按钮
|
||||
|
||||
static Widget OneRowButtonTitleText({
|
||||
required String label, // 标题
|
||||
required String text, // 显示内容或提示
|
||||
|
@ -359,4 +358,35 @@ class ItemListWidget {
|
|||
)
|
||||
);
|
||||
}
|
||||
/// 单行布局:
|
||||
/// 标题 + 按钮
|
||||
static Widget OneRowButtonTitle({
|
||||
required String label, // 标题
|
||||
required String buttonText, // 按钮文字
|
||||
required VoidCallback? onTap, // 第一行点击回调
|
||||
double fontSize = 15, // 字体大小
|
||||
Color btnColor = Colors.blue,
|
||||
|
||||
}) {
|
||||
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),
|
||||
),
|
||||
CustomButton(
|
||||
text: buttonText,
|
||||
height: 30,
|
||||
padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 5),
|
||||
backgroundColor: btnColor,
|
||||
onPressed: onTap,
|
||||
),
|
||||
],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -601,6 +601,7 @@ class _SelectionPopupState extends State<SelectionPopup> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Dialog(
|
||||
backgroundColor: Colors.white,
|
||||
insetPadding: const EdgeInsets.symmetric(horizontal: 10, vertical: 40),
|
||||
child: SizedBox(
|
||||
width: double.infinity,
|
||||
|
@ -616,6 +617,7 @@ class _SelectionPopupState extends State<SelectionPopup> {
|
|||
// 作业类型下拉
|
||||
Expanded(
|
||||
child: DropdownButton<String>(
|
||||
dropdownColor: Colors.white,
|
||||
style: TextStyle(),
|
||||
isExpanded: true,
|
||||
value: selectedWorkName,
|
||||
|
@ -643,7 +645,7 @@ class _SelectionPopupState extends State<SelectionPopup> {
|
|||
children: [
|
||||
Text(selectedDate == null
|
||||
? '选择作业申请时间'
|
||||
: selectedDate!.toString().split(' ')[0]),
|
||||
: selectedDate!.toString().split(' ')[0],style: TextStyle(color: Colors.blue),),
|
||||
SizedBox(width: 5,),
|
||||
Icon(Icons.arrow_drop_down, color: Colors.grey, size: 20,), ],
|
||||
)),
|
||||
|
@ -667,6 +669,7 @@ class _SelectionPopupState extends State<SelectionPopup> {
|
|||
: item['NAME'] as String? ?? '';
|
||||
final checked = value.contains(key);
|
||||
return CheckboxListTile(
|
||||
activeColor: Colors.blue,
|
||||
title: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
|
|
|
@ -1,744 +0,0 @@
|
|||
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/tools/tools.dart';
|
||||
import '../../../../../../customWidget/bottom_picker.dart';
|
||||
import '../../../../../../http/ApiService.dart';
|
||||
import '../../../../../my_appbar.dart';
|
||||
import '../../special_Wrok/dh_work_detai/MeasuresListWidget.dart';
|
||||
import '../../special_Wrok/qtfx_work_detail/hotwork_gas_list.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 GasWorkApplyDetail extends StatefulWidget {
|
||||
const GasWorkApplyDetail({
|
||||
super.key,
|
||||
required this.HOTWORK_ID,
|
||||
required this.flow,
|
||||
});
|
||||
|
||||
final String HOTWORK_ID;
|
||||
final String flow;
|
||||
|
||||
@override
|
||||
State<GasWorkApplyDetail> createState() => _GasWorkApplyDetailState();
|
||||
}
|
||||
|
||||
class _GasWorkApplyDetailState extends State<GasWorkApplyDetail> {
|
||||
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();
|
||||
_getHotWorkNameList();
|
||||
} 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;
|
||||
}
|
||||
_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;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Widget _defaultDetail() {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '申请单位:',
|
||||
isEditable: false,
|
||||
text: pd['APPLY_DEPARTMENT_NAME'] ?? '',
|
||||
),
|
||||
Divider(),
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '申请人:',
|
||||
isEditable: false,
|
||||
text: pd['APPLY_USER_NAME'] ?? '',
|
||||
),
|
||||
if (FormUtils.hasValue(pd, 'CHECK_NO'))
|
||||
Column(
|
||||
children: [
|
||||
Divider(),
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '编号:',
|
||||
isEditable: false,
|
||||
text: pd['CHECK_NO'] ?? '',
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
Divider(),
|
||||
ItemListWidget.multiLineTitleTextField(
|
||||
label: '作业内容:',
|
||||
isEditable: isEditable,
|
||||
controller: _contentController,
|
||||
text: pd['WORK_CONTENT'] ?? '',
|
||||
),
|
||||
Divider(),
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '动火地点及动火部位:',
|
||||
isEditable: isEditable,
|
||||
controller: _locationController,
|
||||
text: pd['WORK_PLACE'] ?? '',
|
||||
),
|
||||
Divider(),
|
||||
ItemListWidget.selectableLineTitleTextField(
|
||||
label: '动火作业级别',
|
||||
isEditable: isEditable,
|
||||
onTap: () {
|
||||
_chooseLevel();
|
||||
},
|
||||
text: pd['WORK_LEVEL'] ?? '',
|
||||
),
|
||||
Divider(),
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '动火方式:',
|
||||
isEditable: isEditable,
|
||||
controller: _methodController,
|
||||
text: pd['WORK_FUNCTION'] ?? '',
|
||||
),
|
||||
if (pd['WORK_START_DATE'] != null &&
|
||||
pd['WORK_START_DATE'].toString().isNotEmpty)
|
||||
Column(
|
||||
children: [
|
||||
Divider(),
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '动火作业\n实施时间:',
|
||||
isEditable: isEditable,
|
||||
controller: _methodController,
|
||||
text:
|
||||
pd['WORK_START_DATE'] ??
|
||||
'' +
|
||||
'至' +
|
||||
(pd['WORK_END_DATE']
|
||||
? pd['WORK_END_DATE'] ?? ''
|
||||
: '--') ??
|
||||
'',
|
||||
),
|
||||
],
|
||||
),
|
||||
Divider(),
|
||||
ItemListWidget.twoRowSelectableTitleText(
|
||||
label: '动火人及证书编号:',
|
||||
isEditable: isEditable,
|
||||
onTap: () {
|
||||
_chooseHorkUser();
|
||||
},
|
||||
controller: _hotworkPersonController,
|
||||
text: pd['WORK_USER'] ?? '',
|
||||
),
|
||||
Divider(),
|
||||
ItemListWidget.twoRowButtonTitleText(
|
||||
label: '关联的其他特殊作业及安全作业票编号',
|
||||
isEditable: isEditable,
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (_) => SelectionPopup(
|
||||
type: 'assignments',
|
||||
initialValue: pd['SPECIAL_WORK'] ?? '',
|
||||
onConfirm: (val) {
|
||||
// val 为逗号分隔的选中值
|
||||
setState(() {
|
||||
pd['SPECIAL_WORK'] = val;
|
||||
_relatedController.text = val;
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
// identification
|
||||
},
|
||||
hintText: '请输入关联的其他特殊作业及安全作业票编号',
|
||||
controller: _relatedController,
|
||||
text: pd['SPECIAL_WORK'] ?? '',
|
||||
),
|
||||
Divider(),
|
||||
ItemListWidget.twoRowButtonTitleText(
|
||||
label: '风险辨识结果',
|
||||
isEditable: isEditable,
|
||||
onTap: () {
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (_) => SelectionPopup(
|
||||
type: 'identification',
|
||||
initialValue: pd['RISK_IDENTIFICATION'] ?? '',
|
||||
onConfirm: (val) {
|
||||
// val 为逗号分隔的选中值
|
||||
setState(() {
|
||||
pd['RISK_IDENTIFICATION'] = val;
|
||||
_riskController.text = val;
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
hintText: '请输入风险辨识结果',
|
||||
controller: _riskController,
|
||||
text: pd['RISK_IDENTIFICATION'] ?? '',
|
||||
),
|
||||
if (FormUtils.hasValue(pd, 'ANALYZE_TIME'))
|
||||
Column(
|
||||
children: [
|
||||
Divider(),
|
||||
ItemListWidget.OneRowButtonTitleText(
|
||||
label: '分析人',
|
||||
text: pd['ANALYZE_USER_NAME'] ?? '',
|
||||
onTap: () {
|
||||
pushPage(
|
||||
HotworkGasList(HOTWORK_ID: widget.HOTWORK_ID),
|
||||
context,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _card(Widget child) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _chooseItem(EditUserType type) {
|
||||
return Column(
|
||||
children: [
|
||||
ItemListWidget.selectableLineTitleTextField(
|
||||
label: type.displayName,
|
||||
isEditable: isEditable,
|
||||
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) {
|
||||
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, '');
|
||||
});
|
||||
// 拉取该单位的人员列表并缓存
|
||||
final result = await ApiService.getListTreePersonList(id);
|
||||
_personCache[type] = List<Map<String, dynamic>>.from(
|
||||
result['userList'] as List,
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 弹出人员选择,需先选择单位
|
||||
void choosePersonHandle(EditUserType type) {
|
||||
final unitId = get_pd_DEPARTMENT_ID(type);
|
||||
final personList = _personCache[type] ?? [];
|
||||
if (unitId == null || personList.isEmpty) {
|
||||
final unitName = type.displayName;
|
||||
ToastUtil.showNormal(context, '请先选择$unitName');
|
||||
return;
|
||||
}
|
||||
DepartmentPersonPicker.show(
|
||||
context,
|
||||
personsData: personList,
|
||||
onSelected: (userId, name) {
|
||||
setState(() {
|
||||
set_pd_USER_ID(type, userId);
|
||||
set_pd_USER_Name(type, name);
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// 提交 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'] as String? ?? '';
|
||||
|
||||
/// 各项负责人校验
|
||||
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 TASK_ID = '0';
|
||||
if (level == '特级') {
|
||||
TASK_ID = '1';
|
||||
} else if (level == '一级') {
|
||||
TASK_ID = '2';
|
||||
} else if (level == '二级') {
|
||||
TASK_ID = '3';
|
||||
}
|
||||
|
||||
// 提交参数
|
||||
Map<String, dynamic> payload = {};
|
||||
if (msg == 'add') {
|
||||
payload = {
|
||||
'HOTWORK_ID': widget.HOTWORK_ID,
|
||||
'CREATOR': SessionService.instance.loginUserId,
|
||||
'OPERATOR': SessionService.instance.loginUserId,
|
||||
'ACTION_USER': SessionService.instance.username,
|
||||
'APPLY_STATUS': status,
|
||||
'CORPINFO_ID': SessionService.instance.corpinfoId,
|
||||
'USER_ID': SessionService.instance.loginUserId,
|
||||
'STEP_ID': status,
|
||||
'WORK_LEVEL': TASK_ID,
|
||||
};
|
||||
}
|
||||
pd.forEach((key, value) {
|
||||
payload[key] = value;
|
||||
});
|
||||
LoadingDialogHelper.show(context);
|
||||
|
||||
try {
|
||||
String url = "/app/hotwork/" + msg;
|
||||
final result = await ApiService.submitHotwork(url, payload);
|
||||
if (result['result'] == 'success') {
|
||||
ToastUtil.showSuccess(context, status == '1' ? '提交成功' : '已暂存');
|
||||
}
|
||||
} catch (e) {
|
||||
ToastUtil.showNormal(context, '操作失败:$e');
|
||||
}
|
||||
LoadingDialogHelper.hide(context);
|
||||
}
|
||||
Future<void> _getHotWorkNameList() async {
|
||||
final result = await ApiService.getHotWorkNameList();
|
||||
setState(() {
|
||||
workUserList = result['varList'] ?? '';
|
||||
List<String> names = workUserList.map((item) => item['NAME'] as String).toList();
|
||||
|
||||
});
|
||||
}
|
||||
/// 初始化拉取数据
|
||||
Future<void> _getData() async {
|
||||
final data = await ApiService.getHomeworkFindById(widget.HOTWORK_ID);
|
||||
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.getHomeworkFindById(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(
|
||||
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(
|
||||
appBar: MyAppbar(title: '动火安全作业申请'),
|
||||
body: SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Column(
|
||||
children: [
|
||||
_card(_defaultDetail()),
|
||||
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,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
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,120 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:qhd_prevention/customWidget/custom_button.dart';
|
||||
|
||||
/// 安全措施弹窗
|
||||
class SafeFunctionDialog extends StatefulWidget {
|
||||
final List<Map<String, dynamic>> data;
|
||||
|
||||
/// 点击确认回调,返回选中的措施列表
|
||||
final void Function(List<String> selectedMeasures) onConfirm;
|
||||
|
||||
/// 构造函数
|
||||
const SafeFunctionDialog({
|
||||
Key? key,
|
||||
required this.data,
|
||||
required this.onConfirm,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<SafeFunctionDialog> createState() => _SafeFunctionDialogState();
|
||||
}
|
||||
|
||||
class _SafeFunctionDialogState extends State<SafeFunctionDialog> {
|
||||
/// 存放所有可选项的文字
|
||||
late final List<String> _allMeasures;
|
||||
|
||||
/// 存放当前被选中的文字
|
||||
final List<String> _selectedMeasures = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_allMeasures =
|
||||
widget.data
|
||||
.map((e) => e['PROTECTIVE_MEASURES'] as String? ?? '')
|
||||
.toList();
|
||||
}
|
||||
|
||||
@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: _allMeasures.length,
|
||||
itemBuilder: (ctx, index) {
|
||||
final measure = _allMeasures[index];
|
||||
final checked = _selectedMeasures.contains(measure);
|
||||
return CheckboxListTile(
|
||||
// 将复选框移到左侧
|
||||
controlAffinity: ListTileControlAffinity.leading,
|
||||
// 调整左右间隙
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 0),
|
||||
activeColor: Colors.blue,
|
||||
title: Text(measure, style: const TextStyle(fontSize: 14)),
|
||||
value: checked,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
if (value == true) {
|
||||
_selectedMeasures.add(measure);
|
||||
} else {
|
||||
_selectedMeasures.remove(measure);
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CustomButton(
|
||||
text: '确定',
|
||||
height: 40,
|
||||
backgroundColor: Colors.blue,
|
||||
onPressed: () {
|
||||
widget.onConfirm(_selectedMeasures);
|
||||
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(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> showSafeFunctionDialog(
|
||||
BuildContext context,
|
||||
List<Map<String, dynamic>> data,
|
||||
void Function(List<String>) onConfirm,
|
||||
) {
|
||||
return showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (_) => SafeFunctionDialog(data: data, onConfirm: onConfirm),
|
||||
);
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
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';
|
||||
|
@ -10,31 +12,14 @@ import 'package:qhd_prevention/customWidget/toast_util.dart';
|
|||
import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
import '../../../../../../customWidget/bottom_picker.dart';
|
||||
import '../../../../../../customWidget/single_image_viewer.dart';
|
||||
import '../../../../../../http/ApiService.dart';
|
||||
import '../../../../../mine/mine_sign_page.dart';
|
||||
import '../../../../../my_appbar.dart';
|
||||
import '../../special_Wrok/dh_work_detai/MeasuresListWidget.dart';
|
||||
import '../../special_Wrok/qtfx_work_detail/hotwork_gas_list.dart';
|
||||
import 'SafeFunctionDialog.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 HotworkSetSafeDetail extends StatefulWidget {
|
||||
const HotworkSetSafeDetail({
|
||||
|
@ -61,120 +46,29 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
|
|||
late Map<String, dynamic> pd = {};
|
||||
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 = [];
|
||||
|
||||
/// 安全防护措施列表
|
||||
late List<dynamic> measuresListCopy = [];
|
||||
|
||||
// 存储各单位的人员列表
|
||||
final Map<EditUserType, List<Map<String, dynamic>>> _personCache = {};
|
||||
|
||||
late List<MeasureItem> measuresListCopy = [];
|
||||
List<String> imagePaths = [];
|
||||
List<String> signTimes = []; // 签字时间列表
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_getData();
|
||||
_getHotWorkNameList();
|
||||
addMeasuresListCopy();
|
||||
_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;
|
||||
String measuresListToJson() {
|
||||
final List<Map<String, dynamic>> jsonList =
|
||||
measuresListCopy.map((item) => item.toJson()).toList();
|
||||
return jsonEncode(jsonList);
|
||||
}
|
||||
|
||||
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 _defaultDetail() {
|
||||
return Column(
|
||||
|
@ -207,30 +101,24 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
|
|||
ItemListWidget.multiLineTitleTextField(
|
||||
label: '作业内容:',
|
||||
isEditable: isEditable,
|
||||
controller: _contentController,
|
||||
text: pd['WORK_CONTENT'] ?? '',
|
||||
),
|
||||
Divider(),
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '动火地点及动火部位:',
|
||||
isEditable: isEditable,
|
||||
controller: _locationController,
|
||||
text: pd['WORK_PLACE'] ?? '',
|
||||
),
|
||||
Divider(),
|
||||
ItemListWidget.selectableLineTitleTextField(
|
||||
label: '动火作业级别',
|
||||
isEditable: isEditable,
|
||||
onTap: () {
|
||||
_chooseLevel();
|
||||
},
|
||||
text: pd['WORK_LEVEL'] ?? '',
|
||||
),
|
||||
Divider(),
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '动火方式:',
|
||||
isEditable: isEditable,
|
||||
controller: _methodController,
|
||||
text: pd['WORK_FUNCTION'] ?? '',
|
||||
),
|
||||
if (pd['WORK_START_DATE'] != null &&
|
||||
|
@ -241,7 +129,6 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
|
|||
ItemListWidget.singleLineTitleText(
|
||||
label: '动火作业\n实施时间:',
|
||||
isEditable: isEditable,
|
||||
controller: _methodController,
|
||||
text:
|
||||
pd['WORK_START_DATE'] ??
|
||||
'' +
|
||||
|
@ -257,65 +144,22 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
|
|||
ItemListWidget.twoRowSelectableTitleText(
|
||||
label: '动火人及证书编号:',
|
||||
isEditable: isEditable,
|
||||
onTap: () {
|
||||
_chooseHorkUser();
|
||||
},
|
||||
controller: _hotworkPersonController,
|
||||
text: pd['WORK_USER'] ?? '',
|
||||
),
|
||||
Divider(),
|
||||
ItemListWidget.twoRowButtonTitleText(
|
||||
label: '关联的其他特殊作业及安全作业票编号',
|
||||
isEditable: isEditable,
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder:
|
||||
(_) => SelectionPopup(
|
||||
type: 'assignments',
|
||||
initialValue: pd['SPECIAL_WORK'] ?? '',
|
||||
onConfirm: (val) {
|
||||
// val 为逗号分隔的选中值
|
||||
setState(() {
|
||||
pd['SPECIAL_WORK'] = val;
|
||||
_relatedController.text = val;
|
||||
});
|
||||
},
|
||||
),
|
||||
).then((_) {
|
||||
FocusHelper.clearFocus(context);
|
||||
});
|
||||
// identification
|
||||
},
|
||||
onTap: ()=>{},
|
||||
hintText: '请输入关联的其他特殊作业及安全作业票编号',
|
||||
controller: _relatedController,
|
||||
text: pd['SPECIAL_WORK'] ?? '',
|
||||
),
|
||||
Divider(),
|
||||
ItemListWidget.twoRowButtonTitleText(
|
||||
label: '风险辨识结果',
|
||||
isEditable: isEditable,
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder:
|
||||
(_) => SelectionPopup(
|
||||
type: 'identification',
|
||||
initialValue: pd['RISK_IDENTIFICATION'] ?? '',
|
||||
onConfirm: (val) {
|
||||
// val 为逗号分隔的选中值
|
||||
setState(() {
|
||||
pd['RISK_IDENTIFICATION'] = val;
|
||||
_riskController.text = val;
|
||||
});
|
||||
},
|
||||
),
|
||||
).then((_) {
|
||||
FocusHelper.clearFocus(context);
|
||||
});
|
||||
},
|
||||
onTap: () {},
|
||||
hintText: '请输入风险辨识结果',
|
||||
controller: _riskController,
|
||||
text: pd['RISK_IDENTIFICATION'] ?? '',
|
||||
),
|
||||
if (FormUtils.hasValue(pd, 'ANALYZE_TIME'))
|
||||
|
@ -348,29 +192,41 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
|
|||
);
|
||||
}
|
||||
|
||||
Widget _chooseItem(EditUserType type) {
|
||||
Widget _chooseItem(MeasureItem item) {
|
||||
return Column(
|
||||
children: [
|
||||
ItemListWidget.selectableLineTitleTextField(
|
||||
label: type.displayName,
|
||||
isEditable: isEditable,
|
||||
text: pd['${type.name}_DEPARTMENT_NAME'] ?? '请选择',
|
||||
onTap: () => chooseUnitHandle(type),
|
||||
label: "确认单位",
|
||||
isEditable: true,
|
||||
text: item.DEPARTMENT_NAME ?? '请选择',
|
||||
onTap: () => chooseUnitHandle(item),
|
||||
),
|
||||
Divider(),
|
||||
Divider(height: 8, color: Colors.grey.shade200),
|
||||
ItemListWidget.selectableLineTitleTextField(
|
||||
label: type.personName,
|
||||
isEditable: isEditable,
|
||||
text: pd['${type.name}_USER_NAME'] ?? '请选择',
|
||||
onTap: () => choosePersonHandle(type),
|
||||
label: '确认人',
|
||||
isEditable: true,
|
||||
text: item.USER_NAME ?? '请选择',
|
||||
onTap: () => choosePersonHandle(item),
|
||||
),
|
||||
Divider(height: 8, color: Colors.grey.shade200),
|
||||
// 安全措施
|
||||
ItemListWidget.OneRowButtonTitle(
|
||||
label: '安全措施:',
|
||||
buttonText: '选择安全措施',
|
||||
onTap: () {
|
||||
showSafeFunctionDialog(context, measuresList, (selected) {
|
||||
// 在这里处理用户的选择结果
|
||||
debugPrint('用户选择了:' + json.encode(selected));
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// 弹出单位选择
|
||||
void chooseUnitHandle(EditUserType type) {
|
||||
FocusHelper.clearFocus(context);
|
||||
void chooseUnitHandle(MeasureItem item) {
|
||||
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
|
@ -380,50 +236,48 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
|
|||
(_) => 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, '');
|
||||
item.DEPARTMENT_ID = id;
|
||||
item.DEPARTMENT_NAME = name;
|
||||
});
|
||||
_getPersonListForUnitId(id, type);
|
||||
_getPersonListForUnitId(item);
|
||||
},
|
||||
),
|
||||
).then((_) {
|
||||
FocusHelper.clearFocus(context);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _getPersonListForUnitId(String id, EditUserType type) async {
|
||||
Future<void> _getPersonListForUnitId(MeasureItem item) async {
|
||||
// 拉取该单位的人员列表并缓存
|
||||
final result = await ApiService.getListTreePersonList(id);
|
||||
final result = await ApiService.getListTreePersonList(item.DEPARTMENT_ID);
|
||||
setState(() {
|
||||
_personCache[type] = List<Map<String, dynamic>>.from(
|
||||
result['userList'] as List,
|
||||
|
||||
item.userList = List<Map<String, dynamic>>.from(
|
||||
result['userList'] ?? <Map<String, dynamic>>[],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/// 弹出人员选择,需先选择单位
|
||||
void choosePersonHandle(EditUserType type) async {
|
||||
FocusHelper.clearFocus(context);
|
||||
void choosePersonHandle(MeasureItem item) async {
|
||||
|
||||
String unitId = get_pd_DEPARTMENT_ID(type);
|
||||
final personList = _personCache[type] ?? [];
|
||||
String unitId = item.DEPARTMENT_ID;
|
||||
final personList = item.userList;
|
||||
if (!unitId.isNotEmpty) {
|
||||
final unitName = type.displayName;
|
||||
final unitName = item.DEPARTMENT_NAME;
|
||||
ToastUtil.showNormal(context, '请先选择$unitName');
|
||||
return;
|
||||
}
|
||||
if (personList.isEmpty) {
|
||||
// 一般这种情况是因为重新编辑没有缓存对应部门的负责人,所以先拉取一下接口
|
||||
await _getPersonListForUnitId(unitId, type);
|
||||
final list = _personCache[type] ?? [];
|
||||
await _getPersonListForUnitId(item);
|
||||
final list = item.userList;
|
||||
|
||||
if (list.isEmpty) {
|
||||
// 如果还是没数据,说明该部门没有可选的人
|
||||
ToastUtil.showNormal(context, '暂无数据,请选择其他单位');
|
||||
} else {
|
||||
choosePersonHandle(type);
|
||||
choosePersonHandle(item);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -432,83 +286,108 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
|
|||
personsData: personList,
|
||||
onSelected: (userId, name) {
|
||||
setState(() {
|
||||
set_pd_USER_ID(type, userId);
|
||||
set_pd_USER_Name(type, name);
|
||||
item.USER_NAME = name;
|
||||
item.USER_ID = userId;
|
||||
print(json.encode(measuresListCopy));
|
||||
});
|
||||
},
|
||||
).then((_) {
|
||||
FocusHelper.clearFocus(context);
|
||||
|
||||
});
|
||||
}
|
||||
/// 签字
|
||||
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: Image.file(
|
||||
File(path),
|
||||
width: 200,
|
||||
height: 150,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
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 提交 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;
|
||||
}
|
||||
}
|
||||
// // 文本校验
|
||||
// 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 (MeasureItem item in measuresListCopy) {
|
||||
// if (item.USER_ID.isNotEmpty) {
|
||||
// ToastUtil.showNormal(context, '请选择确认人');
|
||||
// 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;
|
||||
|
@ -517,7 +396,6 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
|
|||
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'] =
|
||||
|
@ -565,18 +443,8 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
|
|||
final data = await ApiService.getHomeworkFindById(widget.HOTWORK_ID);
|
||||
setState(() {
|
||||
pd = data['pd'];
|
||||
if (pd['STEP_ID'] == 0) {
|
||||
isEditable = true;
|
||||
} else {
|
||||
_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'] ?? '';
|
||||
_getMeasures();
|
||||
|
||||
});
|
||||
// final data = await ApiService.getHomeworkFindById(widget.HOTWORK_ID);
|
||||
// setState(() {
|
||||
|
@ -585,21 +453,21 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
|
|||
// LoadingDialogHelper.hide(context);
|
||||
}
|
||||
|
||||
Future<void> _getMeasures(String homework_id) async {
|
||||
final data = await ApiService.listSignFinishAllMeasures(
|
||||
homework_id.length > 0 ? homework_id : widget.HOTWORK_ID,
|
||||
);
|
||||
Future<void> _getMeasures() async {
|
||||
final data = await ApiService.listSignFinishAllMeasures();
|
||||
setState(() {
|
||||
measuresList = List<Map<String, dynamic>>.from(
|
||||
data['finishMeasuresList'] ?? <Map<String, dynamic>>[],
|
||||
data['measuresList'] ?? <Map<String, dynamic>>[],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void removeMeasuresListCopy(int index) {
|
||||
setState(() {
|
||||
measuresListCopy.removeAt(index);
|
||||
});
|
||||
}
|
||||
|
||||
void addMeasuresListCopy() {
|
||||
setState(() {
|
||||
measuresListCopy.add(
|
||||
|
@ -616,6 +484,148 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
|
|||
);
|
||||
});
|
||||
}
|
||||
|
||||
/// 安全防护措施
|
||||
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;
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(top: 4),
|
||||
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('0');
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
|
@ -628,156 +638,9 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
|
|||
_card(_defaultDetail()),
|
||||
|
||||
SizedBox(height: 20),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: 5),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
ListItemFactory.createBuildSimpleSection('安全防护措施'),
|
||||
CustomButton(
|
||||
text: '添加',
|
||||
padding: EdgeInsets.symmetric(horizontal: 15),
|
||||
backgroundColor: Colors.blue,
|
||||
height: 36,
|
||||
onPressed: () {},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
...measuresListCopy.asMap().entries.map((entry) {
|
||||
int index = entry.key;
|
||||
MeasureItem item = entry.value;
|
||||
return Padding(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Stack(
|
||||
children: [
|
||||
Card(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 部门 picker
|
||||
ItemListWidget.selectableLineTitleTextField(
|
||||
label: '确认单位:',
|
||||
isEditable: isEditable,
|
||||
onTap: () {
|
||||
|
||||
},
|
||||
text:item.DEPARTMENT_NAME ?? '请选择',
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
// 用户 picker
|
||||
ItemListWidget.selectableLineTitleTextField(
|
||||
label: '确认人:',
|
||||
isEditable: isEditable,
|
||||
onTap: () {
|
||||
|
||||
},
|
||||
text:item.USER_NAME ?? '请选择',
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
// 安全措施
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('安全措施:'),
|
||||
ElevatedButton(
|
||||
onPressed: () {},
|
||||
style: ElevatedButton.styleFrom(shape: StadiumBorder()),
|
||||
child: Text('选择安全措施'),
|
||||
),
|
||||
],
|
||||
),
|
||||
...item.selectMeasures.asMap().entries.map((e) {
|
||||
int idx = e.key;
|
||||
String txt = e.value;
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(top: 4),
|
||||
child: Text('${idx + 1}. $txt'),
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
if (index != 0)
|
||||
Positioned(
|
||||
top: 0,
|
||||
right: 0,
|
||||
child: IconButton(
|
||||
icon: Icon(Icons.close, color: Colors.red),
|
||||
onPressed: () => removeMeasuresListCopy(index),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
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),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
_setSafeDetailWidget(),
|
||||
SizedBox(height: 20),
|
||||
_bottomButtons(),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -785,13 +648,14 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MeasureItem {
|
||||
final double id;
|
||||
String DEPARTMENT_ID;
|
||||
String DEPARTMENT_NAME;
|
||||
String USER_ID;
|
||||
String USER_NAME;
|
||||
List<String> userList;
|
||||
List<Map<String, dynamic>> userList;
|
||||
int userIndex;
|
||||
List<String> selectMeasures;
|
||||
|
||||
|
@ -801,9 +665,21 @@ class MeasureItem {
|
|||
this.DEPARTMENT_NAME = '',
|
||||
this.USER_ID = '',
|
||||
this.USER_NAME = '',
|
||||
List<String>? userList,
|
||||
List<Map<String, dynamic>>? userList,
|
||||
this.userIndex = -1,
|
||||
List<String>? selectMeasures,
|
||||
}) : userList = userList ?? [],
|
||||
selectMeasures = 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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ class _SignatureConfirmPageState extends State<SignatureConfirmPage> {
|
|||
bool _hasSignature = false;
|
||||
File? fileN;
|
||||
Uint8List? _postBytes;
|
||||
late String imagepath="";
|
||||
late String imagepath = "";
|
||||
|
||||
void _clearSignature() {
|
||||
setState(() {
|
||||
|
@ -48,25 +48,22 @@ class _SignatureConfirmPageState extends State<SignatureConfirmPage> {
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
_saveSignPic();
|
||||
|
||||
|
||||
|
||||
// // 保存签名逻辑
|
||||
// ScaffoldMessenger.of(context).showSnackBar(
|
||||
// const SnackBar(content: Text('签名已确认')),
|
||||
// );
|
||||
//模拟保存后返回
|
||||
|
||||
|
||||
}
|
||||
|
||||
// 保存签名
|
||||
void _saveSignPic() async {
|
||||
RenderRepaintBoundary boundary = _signatureKey.currentContext!.findRenderObject() as RenderRepaintBoundary;
|
||||
RenderRepaintBoundary boundary = _signatureKey.currentContext!
|
||||
.findRenderObject() as RenderRepaintBoundary;
|
||||
var image = await boundary.toImage(pixelRatio: 1);
|
||||
ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png);
|
||||
ByteData? byteData =
|
||||
await image.toByteData(format: ui.ImageByteFormat.png);
|
||||
|
||||
int timestamp = DateTime.now().millisecondsSinceEpoch;
|
||||
|
||||
|
@ -81,7 +78,7 @@ class _SignatureConfirmPageState extends State<SignatureConfirmPage> {
|
|||
}
|
||||
|
||||
var file = await File(path).create(recursive: true);
|
||||
if(byteData != null) {
|
||||
if (byteData != null) {
|
||||
file.writeAsBytesSync(byteData.buffer.asInt8List(), flush: true);
|
||||
|
||||
setState(() {
|
||||
|
@ -95,13 +92,6 @@ class _SignatureConfirmPageState extends State<SignatureConfirmPage> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
@ -129,7 +119,6 @@ class _SignatureConfirmPageState extends State<SignatureConfirmPage> {
|
|||
body: SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
|
||||
// 标题区域
|
||||
_buildTitleBar(),
|
||||
// MyAppbar(title: "签字"),
|
||||
|
@ -202,36 +191,39 @@ class _SignatureConfirmPageState extends State<SignatureConfirmPage> {
|
|||
},
|
||||
child: RepaintBoundary(
|
||||
key: _signatureKey,
|
||||
child: Stack(
|
||||
children: [
|
||||
// if (imagepath.length > 0)
|
||||
// Image.file(
|
||||
// File(imagepath), // 显示选择的图片文件
|
||||
// fit: BoxFit.contain, // 设置图片填充方式为完整显示,保持宽高比例
|
||||
// ),
|
||||
child: Container(
|
||||
// 给画布添加白色背景,不透明导出
|
||||
color: Colors.white,
|
||||
child: Stack(
|
||||
children: [
|
||||
// if (imagepath.length > 0)
|
||||
// Image.file(
|
||||
// File(imagepath), // 显示选择的图片文件
|
||||
// fit: BoxFit.contain, // 设置图片填充方式为完整显示,保持宽高比例
|
||||
// ),
|
||||
|
||||
// 背景横线
|
||||
_buildBackgroundLines(),
|
||||
|
||||
// 背景横线
|
||||
_buildBackgroundLines(),
|
||||
// 签名画布
|
||||
CustomPaint(
|
||||
painter: SignaturePainter(points: _points),
|
||||
size: Size.infinite,
|
||||
),
|
||||
|
||||
// 签名画布
|
||||
CustomPaint(
|
||||
painter: SignaturePainter(points: _points),
|
||||
size: Size.infinite,
|
||||
),
|
||||
|
||||
// 提示文字
|
||||
if (!_hasSignature)
|
||||
const Center(
|
||||
child: Text(
|
||||
'请在此处签名',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.grey,
|
||||
// 提示文字
|
||||
if (!_hasSignature)
|
||||
const Center(
|
||||
child: Text(
|
||||
'请在此处签名',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -259,53 +251,51 @@ class _SignatureConfirmPageState extends State<SignatureConfirmPage> {
|
|||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
// 重签按钮
|
||||
Expanded(
|
||||
child: OutlinedButton(
|
||||
onPressed: _clearSignature,
|
||||
style: OutlinedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
side: const BorderSide(color: Colors.blue),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
child: const Text(
|
||||
'重签',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.blue,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(width: 20),
|
||||
|
||||
// 确定按钮
|
||||
Expanded(
|
||||
child: ElevatedButton(
|
||||
onPressed: _confirmSignature,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.blue,
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
child: const Text(
|
||||
'确定',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w500,
|
||||
// 重签按钮
|
||||
Expanded(
|
||||
child: OutlinedButton(
|
||||
onPressed: _clearSignature,
|
||||
style: OutlinedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
side: const BorderSide(color: Colors.blue),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
child: const Text(
|
||||
'重签',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.blue,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(width: 20),
|
||||
|
||||
// 确定按钮
|
||||
Expanded(
|
||||
child: ElevatedButton(
|
||||
onPressed: _confirmSignature,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.blue,
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
child: const Text(
|
||||
'确定',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
],
|
||||
),
|
||||
);
|
||||
|
@ -333,7 +323,8 @@ class SignaturePainter extends CustomPainter {
|
|||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(SignaturePainter oldDelegate) => oldDelegate.points != points;
|
||||
bool shouldRepaint(SignaturePainter oldDelegate) =>
|
||||
oldDelegate.points != points;
|
||||
}
|
||||
|
||||
// 背景横线绘制器
|
||||
|
@ -341,7 +332,7 @@ class BackgroundLinesPainter extends CustomPainter {
|
|||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
Paint paint = Paint()
|
||||
// ..color = Colors.grey[200]!
|
||||
// ..color = Colors.grey[200]!
|
||||
..color = Color.from(alpha: 0, red: 0, green: 0, blue: 0)!
|
||||
..strokeWidth = 0;
|
||||
|
||||
|
@ -357,9 +348,4 @@ class BackgroundLinesPainter extends CustomPainter {
|
|||
|
||||
@override
|
||||
bool shouldRepaint(CustomPainter oldDelegate) => false;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -284,20 +284,46 @@ void presentPage(BuildContext context, Widget page) {
|
|||
}
|
||||
|
||||
class LoadingDialogHelper {
|
||||
static void show(BuildContext context) {
|
||||
/// 显示 loading,对话框中可选文字
|
||||
static void show(BuildContext context, {String? message}) {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (_) => const Center(child: CircularProgressIndicator()),
|
||||
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),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 隐藏 loading
|
||||
static void hide(BuildContext context) {
|
||||
if (Navigator.canPop(context)) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 将秒数转换为 “HH:MM:SS” 格式
|
||||
String secondsCount(dynamic seconds) {
|
||||
// 先尝试解析出一个 double 值
|
||||
|
|
Loading…
Reference in New Issue