设置安全措施确认人,签字板添加白色背景,查看大图添加本地图片支持

main
hs 2025-07-29 08:50:41 +08:00
parent 9348f657e5
commit d672f1d944
9 changed files with 588 additions and 1284 deletions

View File

@ -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,

View File

@ -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,
},
);
}

View File

@ -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,
),
],
)
);
}
}

View File

@ -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: [

View File

@ -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),
],
),
],
),
],
),
),
),
);
}
}

View File

@ -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),
);
}

View File

@ -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,
};
}
}

View File

@ -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;
}

View File

@ -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