932 lines
34 KiB
Dart
932 lines
34 KiB
Dart
import 'dart:convert';
|
||
|
||
import 'package:flutter/material.dart';
|
||
import 'package:intl/intl.dart';
|
||
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
|
||
import 'package:qhd_prevention/customWidget/bottom_picker.dart';
|
||
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
|
||
import 'package:qhd_prevention/customWidget/custom_button.dart';
|
||
import 'package:qhd_prevention/customWidget/picker/CupertinoDatePicker.dart';
|
||
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
|
||
import 'package:qhd_prevention/customWidget/toast_util.dart';
|
||
import 'package:qhd_prevention/http/ApiService.dart';
|
||
import 'package:qhd_prevention/pages/KeyProjects/SafeCheck/custom/MultiTextFieldWithTitle.dart';
|
||
import 'package:qhd_prevention/pages/KeyProjects/SafeCheck/custom/safeCheck_table.dart';
|
||
import 'package:qhd_prevention/pages/KeyProjects/SafeCheck/custom/safe_drawer_page.dart';
|
||
import 'package:qhd_prevention/pages/app/Danger_paicha/quick_report_page.dart';
|
||
import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
|
||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||
import 'package:qhd_prevention/tools/tools.dart';
|
||
|
||
class SafecheckDetail extends StatefulWidget {
|
||
const SafecheckDetail({
|
||
super.key,
|
||
required this.OUTSOURCED_ID,
|
||
required this.KEYPROJECTCHECK_ID,
|
||
required this.isEdit,
|
||
});
|
||
|
||
final String OUTSOURCED_ID;
|
||
final String KEYPROJECTCHECK_ID;
|
||
final bool isEdit;
|
||
|
||
@override
|
||
State<SafecheckDetail> createState() => _SafecheckDetailState();
|
||
}
|
||
|
||
class _SafecheckDetailState extends State<SafecheckDetail> {
|
||
/// 被检查单位负责人
|
||
late List<dynamic> personList = [];
|
||
|
||
/// 检查类型
|
||
late List<dynamic> typeList = [];
|
||
|
||
/// 被检查单位
|
||
late List<dynamic> toCheckUnitList = [];
|
||
|
||
bool? chooseTitleType = null;
|
||
|
||
// 存储多行输入的内容
|
||
List<String> multiTexts = [];
|
||
|
||
List<String> delInspectors = [];
|
||
List<String> delSituations = [];
|
||
List<String> delHiddens = [];
|
||
List<String> delHiddenFiles = [];
|
||
|
||
// rules 格式: [{ 'name': 'INSPECTION_CATEGORY', 'message': '请填写检查题目' }, ...]
|
||
List<Map<String, String>> rules = [
|
||
{'name': 'INSPECTION_CATEGORY', 'message': '请选择检查题目'},
|
||
{'name': 'UNITS_ID', 'message': '请选择被检查单位'},
|
||
{'name': 'PERSONNELMANAGEMENT_ID', 'message': '请选择被检查单位现场负责人'},
|
||
{'name': 'INSPECTION_TYPE', 'message': '请选择检查类型不能为空'},
|
||
{'name': 'INSPECTION_PLACE', 'message': '请输入检查场所'},
|
||
{'name': 'INSPECTION_TIME_START', 'message': '请选择检查开始时间'},
|
||
{'name': 'INSPECTION_TIME_END', 'message': '请选择作业结束时间'},
|
||
{'name': 'INSPECTION_USERS', 'message': '请输入检查人员'},
|
||
];
|
||
|
||
Map<String, dynamic> form = {
|
||
'INSPECTION_USERS': '',
|
||
'KEYPROJECTCHECK_ID': '', // 检查ID
|
||
'OUTSOURCED_ID': '', // 检查ID
|
||
'INSPECTION_CATEGORY': '', // 检查标题
|
||
'INSPECTION_SOURCE': '5', // 检查来源(4-监管端 5-企业端)
|
||
'INSPECTION_ORIGINATOR_ID': '', // 检查发起人
|
||
'UNITS_ID': '', // 被检查单位
|
||
'UNITS_NAME': '',
|
||
'PERSONNELMANAGEMENT_ID': '', // 被检查单位现场负责人
|
||
'INSPECTED_SITEUSER_INDEX': '',
|
||
'PERSON_NAME': '',
|
||
'INSPECTED_EXPLAIN': '', // 申辩内容
|
||
'INSPECTED_SITEUSER_SIGN_IMG': '', // 被检查单位现场负责人签字
|
||
'INSPECTED_SITEUSER_SIGN_TIME': '', // 被检查单位现场负责人签字时间
|
||
'INSPECTION_TYPE': '', // 检查类型
|
||
'INSPECTION_TYPE_NAME': '',
|
||
'INSPECTION_PLACE': '', // 检查场所
|
||
'INSPECTION_TIME_START': '', // 检查开始时间
|
||
'INSPECTION_TIME_END': '', // 检查结束时间
|
||
'INSPECTION_STATUS': '0', // 状态
|
||
'POSITIONDESC': '', // 隐患位置描述
|
||
'CREATTIME': '',
|
||
'inspectorList': [
|
||
{
|
||
'INSPECTION_INSPECTOR_ID': '', //检查人员主键
|
||
'INSPECTION_DEPARTMENT_ID': '', //检查人员部门ID
|
||
'INSPECTION_DEPARTMENT_NAME': '',
|
||
'INSPECTION_USER_ID': '', //检查人员ID
|
||
'INSPECTION_USER_INDEX': '',
|
||
'INSPECTION_USER_NAME': '',
|
||
},
|
||
],
|
||
'situationList': [
|
||
{'INSPECTION_SITUATION_ID': '', 'SITUATION': ''},
|
||
],
|
||
'hiddenList': [
|
||
{
|
||
'ISRELEVANT': '2',
|
||
'HIDDEN_ID': '', // 隐患ID
|
||
'HIDDENDESCR': '', // 隐患描述
|
||
'HIDDENPART': '', // 隐患部位
|
||
'HIDDENPART_NAME': '',
|
||
'HIDDENLEVEL': '', // 隐患级别
|
||
'HIDDENLEVEL_NAME': '',
|
||
'HIDDENTYPE': '', // 隐患类型1
|
||
'HIDDENTYPE_NAME': '',
|
||
'HIDDENTYPE2': '', // 隐患类型2
|
||
'HIDDENTYPE2_NAME': '',
|
||
'LONGITUDE': '', // 隐患位置经度
|
||
'LATITUDE': '', // 隐患位置纬度
|
||
'DISCOVERYTIME': '', // 隐患发现时间
|
||
'HIDDENFINDDEPT': '', // 隐患发现部门(隐患责任人部门)
|
||
'HIDDENFINDDEPT_NAME': '',
|
||
'CREATOR': '', // 发现人(隐患责任人)
|
||
'CREATOR_INDEX': '',
|
||
'CREATOR_NAME': '',
|
||
'SOURCE': '5', // 隐患来源
|
||
'hiddenImgs': <String>[],
|
||
'zgImgs': <String>[],
|
||
'hiddenVideos': <String>[],
|
||
'RECTIFICATIONTYPE': '2',
|
||
'RECTIFICATIONDEADLINE': '',
|
||
'RECTIFYDESCR': '',
|
||
'RECTIFICATIONDEPT_NAME': '',
|
||
'RECTIFICATIONDEPT': '',
|
||
'RECTIFICATIONOR_INDEX': '',
|
||
'HIDDENLEVEL_INDEX': '',
|
||
'RECTIFICATIONOR_NAME': '',
|
||
'RECTIFICATIONOR': '',
|
||
'punishForm': null,
|
||
},
|
||
],
|
||
'INSPECTION_USER_SIGN_TIME': '',
|
||
'INSPECTION_USER_OPINION': '',
|
||
};
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
form['OUTSOURCED_ID'] = widget.OUTSOURCED_ID;
|
||
form['KEYPROJECTCHECK_ID'] = widget.KEYPROJECTCHECK_ID;
|
||
form['hiddenList'] = [];
|
||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||
if (widget.KEYPROJECTCHECK_ID.isNotEmpty) {
|
||
_getData();
|
||
} else {
|
||
// 只有在没有 KEYPROJECTCHECK_ID 时,才做本地的初始值设置
|
||
setState(() {
|
||
form['APPLY_DEPARTMENT_ID'] = SessionService.instance.deptId ?? '';
|
||
form['APPLY_DEPARTMENT_NAME'] =
|
||
SessionService.instance.loginUser?['DEPARTMENT_NAME'] ?? '';
|
||
form['APPLY_USER_ID'] = SessionService.instance.loginUserId ?? '';
|
||
form['APPLY_USER'] = SessionService.instance.username ?? '';
|
||
});
|
||
}
|
||
// 无论如何都去拉取下拉/基础数据
|
||
_getAllRequest();
|
||
});
|
||
}
|
||
|
||
Future<void> _getData() async {
|
||
try {
|
||
final result = await ApiService.getSafeCheckGoEdit(widget.KEYPROJECTCHECK_ID);
|
||
// 在 await 之后检查 mounted,避免页面已经被 pop 导致 setState 报错
|
||
if (!mounted) return;
|
||
setState(() {
|
||
form = result['pd'] ?? {};
|
||
_syncMultiTextsFromForm();
|
||
});
|
||
} catch (e, st) {
|
||
print('加载单条数据失败: $e\n$st');
|
||
if (mounted) {
|
||
ToastUtil.showNormal(context, '加载数据失败:$e');
|
||
}
|
||
}
|
||
}
|
||
|
||
Future<void> _getAllRequest() async {
|
||
try {
|
||
// 在网络请求前确保 widget 已经 build 完毕
|
||
LoadingDialogHelper.show();
|
||
|
||
final result = await ApiService.addSafeCheckRecord(widget.OUTSOURCED_ID);
|
||
// 若页面已被销毁,就直接返回
|
||
if (!mounted) {
|
||
LoadingDialogHelper.hide();
|
||
return;
|
||
}
|
||
|
||
setState(() {
|
||
Map pd = result['pd'] ?? {};
|
||
form['UNITS_NAME'] = pd['UNITS_NAME'] ?? '';
|
||
form['UNITS_ID'] = pd['UNITS_ID'] ?? '';
|
||
form['PERSONNELMANAGEMENT_ID'] = pd['PERSONNELMANAGEMENT_ID'] ?? '';
|
||
form['PERSON_NAME'] = pd['NAME'] ?? '';
|
||
});
|
||
|
||
try {
|
||
final personData = await ApiService.getSafeCheckPersonList(
|
||
form['UNITS_ID'] ?? '',
|
||
'1',
|
||
);
|
||
if (!mounted) return;
|
||
setState(() {
|
||
personList = personData['varList'] ?? [];
|
||
});
|
||
} catch (e) {
|
||
print('加载 personList 失败: $e');
|
||
}
|
||
|
||
try {
|
||
final typeListData = await ApiService.getSafeCheckTypeList();
|
||
if (!mounted) return;
|
||
setState(() {
|
||
typeList = jsonDecode(typeListData['zTreeNodes'] ?? '[]');
|
||
});
|
||
} catch (e) {
|
||
print('加载 typeList 失败: $e');
|
||
}
|
||
|
||
try {
|
||
final toUnitListData = await ApiService.getSafeCheckToUnitList(widget.OUTSOURCED_ID);
|
||
if (!mounted) return;
|
||
setState(() {
|
||
toCheckUnitList = toUnitListData['varList'] ?? [];
|
||
// 仅在没有选择时自动回填
|
||
if (!FormUtils.hasValue(form, 'UNITS_NAME') && toCheckUnitList.isNotEmpty) {
|
||
form['UNITS_NAME'] = toCheckUnitList.first['UNITS_NAME'];
|
||
}
|
||
if (!FormUtils.hasValue(form, 'UNITS_ID') && toCheckUnitList.isNotEmpty) {
|
||
form['UNITS_ID'] = toCheckUnitList.first['UNITS_ID'];
|
||
}
|
||
});
|
||
} catch (e) {
|
||
print('加载 toCheckUnitList 失败: $e');
|
||
}
|
||
} catch (e, st) {
|
||
print('总的加载失败: $e\n$st');
|
||
if (mounted) ToastUtil.showNormal(context, '加载数据失败:$e');
|
||
} finally {
|
||
LoadingDialogHelper.hide();
|
||
}
|
||
}
|
||
|
||
Future<void> _choosePerson() async {
|
||
final choice = await BottomPicker.show<String>(
|
||
context,
|
||
items: personList.map((val) => val['NAME'] as String).toList(),
|
||
itemBuilder: (item) => Text(item, textAlign: TextAlign.center),
|
||
initialIndex: 0,
|
||
);
|
||
if (choice != null) {
|
||
// 用户点击确定并选择了 choice
|
||
setState(() {
|
||
form['PERSON_NAME'] = choice;
|
||
final data = FormUtils.findMapForKeyValue(personList, 'NAME', choice);
|
||
form['PERSONNELMANAGEMENT_ID'] = data['PERSONNELMANAGEMENT_ID'];
|
||
form['INSPECTED_SITEUSER_INDEX'] = personList.indexOf(data);
|
||
|
||
FocusHelper.clearFocus(context);
|
||
});
|
||
}
|
||
}
|
||
|
||
Future<void> _chooseType() async {
|
||
final choice = await BottomPicker.show<String>(
|
||
context,
|
||
items: typeList.map((val) => val['name'] as String).toList(),
|
||
itemBuilder: (item) => Text(item, textAlign: TextAlign.center),
|
||
initialIndex: 0,
|
||
);
|
||
if (choice != null) {
|
||
// 用户点击确定并选择了 choice
|
||
setState(() {
|
||
form['INSPECTION_TYPE_NAME'] = choice;
|
||
final data = FormUtils.findMapForKeyValue(typeList, 'name', choice);
|
||
form['INSPECTION_TYPE'] = data['id'];
|
||
|
||
FocusHelper.clearFocus(context);
|
||
});
|
||
}
|
||
}
|
||
|
||
Future<void> _openDrawer(Map<String, dynamic> hiddenForm, int index) async {
|
||
try {
|
||
final result = await openCustomDrawer<Map>(
|
||
context,
|
||
SafeDrawerPage(
|
||
initialHidden: hiddenForm,
|
||
editType:
|
||
widget.isEdit
|
||
? (index < 0 ? SafeEditType.add : SafeEditType.edit)
|
||
: SafeEditType.see,
|
||
toCheckUnitList: toCheckUnitList,
|
||
),
|
||
);
|
||
|
||
if (result != null && mounted) {
|
||
setState(() {
|
||
if (index < 0) {
|
||
// 新增
|
||
form['hiddenList'].add(result);
|
||
} else {
|
||
// 修改
|
||
form['hiddenList'][index] = result;
|
||
}
|
||
});
|
||
}
|
||
} catch (e) {
|
||
print("打开抽屉失败: $e");
|
||
ToastUtil.showNormal(context, "打开抽屉失败");
|
||
}
|
||
}
|
||
|
||
Future<T?> openCustomDrawer<T>(BuildContext context, Widget child) {
|
||
return Navigator.of(context).push<T>(
|
||
PageRouteBuilder(
|
||
opaque: false,
|
||
barrierDismissible: true,
|
||
barrierColor: Colors.black54,
|
||
pageBuilder: (_, __, ___) {
|
||
return Align(
|
||
alignment: Alignment.centerRight,
|
||
child: FractionallySizedBox(
|
||
widthFactor: 4 / 5,
|
||
child: Material(color: Colors.white, child: child),
|
||
),
|
||
);
|
||
},
|
||
transitionsBuilder: (_, anim, __, child) {
|
||
return SlideTransition(
|
||
position: Tween(
|
||
begin: const Offset(1, 0),
|
||
end: Offset.zero,
|
||
).animate(CurvedAnimation(parent: anim, curve: Curves.easeOut)),
|
||
child: child,
|
||
);
|
||
},
|
||
),
|
||
);
|
||
}
|
||
|
||
/// 将 form['situationList'](若存在)转换为 List<String>
|
||
List<String> _situationListToStrings() {
|
||
final List<dynamic> cur = List<dynamic>.from(form['situationList'] ?? []);
|
||
if (cur.isEmpty) return ['']; // 保持至少一行,和 uni-app 行为一致
|
||
return cur.map((e) {
|
||
if (e is Map && e['SITUATION'] != null) return e['SITUATION'].toString();
|
||
return '';
|
||
}).toList();
|
||
}
|
||
|
||
/// 将 List<String> 转换成 uni-app 风格的 situationList(保留已存在的 INSPECTION_SITUATION_ID)
|
||
List<Map<String, dynamic>> _stringsToSituationList(List<String> texts) {
|
||
final List<dynamic> existing = List<dynamic>.from(
|
||
form['situationList'] ?? [],
|
||
);
|
||
final List<Map<String, dynamic>> out = [];
|
||
|
||
for (int i = 0; i < texts.length; i++) {
|
||
final s = texts[i] ?? '';
|
||
if (i < existing.length && existing[i] is Map) {
|
||
// 保留已有项的其他字段(如 INSPECTION_SITUATION_ID),只覆盖 SITUATION
|
||
final Map<String, dynamic> copy = Map<String, dynamic>.from(
|
||
existing[i],
|
||
);
|
||
copy['SITUATION'] = s;
|
||
// 若没有 INSPECTION_SITUATION_ID 字段,确保它存在(保持原 uni-app 结构)
|
||
copy['INSPECTION_SITUATION_ID'] = copy['INSPECTION_SITUATION_ID'] ?? '';
|
||
out.add(copy);
|
||
} else {
|
||
// 新增项
|
||
out.add({'INSPECTION_SITUATION_ID': '', 'SITUATION': s});
|
||
}
|
||
}
|
||
|
||
// 如果用户删除了行,要把超出的 existing id 记录到 delSituations(可选)
|
||
// 下面为示例:把被删除的旧 ID 收集到 delSituations,便于编辑时提交删除列表
|
||
if (existing.isNotEmpty && existing.length > texts.length) {
|
||
for (int j = texts.length; j < existing.length; j++) {
|
||
final ex = existing[j];
|
||
if (ex is Map) {
|
||
final id = (ex['INSPECTION_SITUATION_ID'] ?? '').toString();
|
||
if (id.isNotEmpty) {
|
||
delSituations.add(id);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return out;
|
||
}
|
||
|
||
/// 在加载数据之后调用:把已存在的 form['situationList'] 同步到 multiTexts(用于 MultiTextFieldWithTitle)
|
||
void _syncMultiTextsFromForm() {
|
||
final List<String> arr = _situationListToStrings();
|
||
setState(() {
|
||
multiTexts = arr;
|
||
});
|
||
}
|
||
|
||
// ------------ 提交入口 ------------
|
||
Future<void> _submit() async {
|
||
if (!widget.isEdit) {
|
||
Navigator.of(context).pop();
|
||
|
||
return;
|
||
}
|
||
bool required = true;
|
||
// 基于 rules 验证
|
||
for (final r in rules) {
|
||
final name = r['name'] ?? '';
|
||
final message = r['message'] ?? '请完善表单';
|
||
final v = form[name];
|
||
if (v == null || v.toString().isEmpty || v.toString() == '请选择') {
|
||
LoadingDialogHelper.hide();
|
||
ToastUtil.showNormal(context, message);
|
||
required = false;
|
||
break;
|
||
}
|
||
}
|
||
if (!required) return;
|
||
|
||
// situationList 每项 SITUATION 非空
|
||
final situations = (form['situationList'] as List<dynamic>?) ?? [];
|
||
for (var i = 0; i < situations.length; i++) {
|
||
final s = Map<String, dynamic>.from(situations[i]);
|
||
if ((s['SITUATION'] ?? '').toString().trim().isEmpty) {
|
||
LoadingDialogHelper.hide();
|
||
ToastUtil.showNormal(context, '请填写第${i + 1}项检查情况');
|
||
return;
|
||
}
|
||
}
|
||
|
||
// 检查 inspectorList 中是否有重复 INSPECTION_USER_ID
|
||
final List<Map<String, String>> inspectors = form['inspectorList'] ?? [];
|
||
final seenIds = <String>{};
|
||
for (final it in inspectors) {
|
||
final id = (it as Map)['INSPECTION_USER_ID']?.toString() ?? '';
|
||
if (id.isNotEmpty) {
|
||
if (seenIds.contains(id)) {
|
||
LoadingDialogHelper.hide();
|
||
ToastUtil.showNormal(context, '检查人重复!请检查数据');
|
||
return;
|
||
}
|
||
seenIds.add(id);
|
||
}
|
||
}
|
||
|
||
//根据 hiddenList 构建需要上传的文件数组
|
||
final origHiddenList = (form['hiddenList'] as List<dynamic>?) ?? [];
|
||
final List<List<Map<String, dynamic>>> hiddenFilesPerHidden = [];
|
||
|
||
for (var i = 0; i < origHiddenList.length; i++) {
|
||
final hidden = Map<String, dynamic>.from(origHiddenList[i] as Map);
|
||
final List<Map<String, dynamic>> fileList = [];
|
||
|
||
// hiddenImgs (多张)
|
||
final hiddenImgs = (hidden['hiddenImgs'] as List<dynamic>?) ?? [];
|
||
for (var j = 0; j < hiddenImgs.length; j++) {
|
||
final img = hiddenImgs[j];
|
||
// 如果是字符串路径
|
||
if (img is String) {
|
||
fileList.add({'type': 3, 'FILEPATH': img});
|
||
} else if (img is Map) {
|
||
final hasId = (img['IMGFILES_ID'] ?? '').toString().isNotEmpty;
|
||
if (!hasId) {
|
||
fileList.add({
|
||
'type': 3,
|
||
'FILEPATH': img['FILEPATH'] ?? img['path'] ?? '',
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
// zgImgs (整改图)
|
||
final zgImgs = (hidden['zgImgs'] as List<dynamic>?) ?? [];
|
||
for (var j = 0; j < zgImgs.length; j++) {
|
||
final img = zgImgs[j];
|
||
if (img is String) {
|
||
fileList.add({'type': 4, 'FILEPATH': img});
|
||
} else if (img is Map) {
|
||
final hasId = (img['IMGFILES_ID'] ?? '').toString().isNotEmpty;
|
||
if (!hasId) {
|
||
fileList.add({
|
||
'type': 4,
|
||
'FILEPATH': img['FILEPATH'] ?? img['path'] ?? '',
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
// hiddenVideos (只取第一个)
|
||
final hiddenVideos = (hidden['hiddenVideos'] as List<dynamic>?) ?? [];
|
||
if (hiddenVideos.isNotEmpty) {
|
||
final v = hiddenVideos[0];
|
||
if (v is String) {
|
||
fileList.add({'type': 102, 'FILEPATH': v});
|
||
} else if (v is Map) {
|
||
final hasId = (v['IMGFILES_ID'] ?? '').toString().isNotEmpty;
|
||
if (!hasId) {
|
||
fileList.add({
|
||
'type': 102,
|
||
'FILEPATH': v['FILEPATH'] ?? v['path'] ?? '',
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
hiddenFilesPerHidden.add(fileList);
|
||
}
|
||
|
||
// 确保当前登录用户在 inspectorList 中(依据 SessionService)
|
||
final loginUser = SessionService.instance.loginUser ?? {};
|
||
final loginUserId = SessionService.instance.loginUserId ?? '';
|
||
final idx = inspectors.indexWhere((item) {
|
||
final m = Map<String, dynamic>.from(item as Map);
|
||
return (m['INSPECTION_USER_ID'] ?? '') ==
|
||
(loginUser['USER_ID'] ?? loginUserId);
|
||
});
|
||
if (idx < 0) {
|
||
inspectors.add({
|
||
'INSPECTION_INSPECTOR_ID': '',
|
||
'INSPECTION_DEPARTMENT_ID': loginUser['DEPARTMENT_ID'] ?? '',
|
||
'INSPECTION_DEPARTMENT_NAME': loginUser['DEPARTMENT_NAME'] ?? '',
|
||
'INSPECTION_USER_ID': loginUser['USER_ID'] ?? loginUserId,
|
||
'INSPECTION_USER_INDEX': '',
|
||
'INSPECTION_USER_NAME': loginUser['NAME'] ?? '',
|
||
});
|
||
}
|
||
|
||
// 准备 form 字段(JSON 字符串等)
|
||
form['INSPECTORJSON'] = jsonEncode(inspectors);
|
||
form['SITUATIONJSON'] = jsonEncode(situations);
|
||
form['HIDDENJSON'] = jsonEncode(origHiddenList);
|
||
form['delInspectors'] = delInspectors.join(',');
|
||
form['delSituations'] = delSituations.join(',');
|
||
form['delHiddens'] = delHiddens.join(',');
|
||
form['delHiddenFiles'] = delHiddenFiles.join(',');
|
||
form['CREATOR'] = loginUser['USER_ID'] ?? loginUserId;
|
||
form['CORPINFO_ID'] = SessionService.instance.corpinfoId ?? '';
|
||
form['ACTION_USER'] = loginUser['NAME'] ?? '';
|
||
LoadingDialogHelper.show(); // 显示 loading
|
||
|
||
// 提交主表
|
||
try {
|
||
final requestData = <String, dynamic>{
|
||
'CORPINFO_ID': form['CORPINFO_ID'],
|
||
...form,
|
||
};
|
||
final res = await ApiService.safeKeyprojectCheckSubmit(requestData);
|
||
// 如果你的 ApiService 返回结构不同,请按实际调整判断
|
||
if (res != null && res['result'] == 'success') {
|
||
final pd = res['pd'] ?? {};
|
||
final List<dynamic> returnedHiddenList = pd['hiddenList'] ?? [];
|
||
|
||
// 如果没有附件需要上传,直接完成
|
||
final hasFiles = hiddenFilesPerHidden.any((lst) => lst.isNotEmpty);
|
||
if (!hasFiles) {
|
||
LoadingDialogHelper.hide();
|
||
ToastUtil.showNormal(context, '提交成功');
|
||
Navigator.of(context).pop();
|
||
return;
|
||
}
|
||
|
||
// 若每个 hidden 有 punishForm,需要先提交罚单
|
||
for (var i = 0; i < returnedHiddenList.length; i++) {
|
||
if (i < (form['hiddenList'] as List).length) {
|
||
final hidden = Map<String, dynamic>.from(
|
||
(form['hiddenList'] as List)[i],
|
||
);
|
||
final punishForm = hidden['punishForm'];
|
||
if (punishForm != null) {
|
||
final hid = (returnedHiddenList[i]['HIDDEN_ID'] ?? '').toString();
|
||
punishForm['HIDDEN_ID'] = hid;
|
||
// await 调用罚单提交(在下面实现)
|
||
await fnSubmit(Map<String, dynamic>.from(punishForm));
|
||
}
|
||
}
|
||
}
|
||
|
||
// 上传所有附件(按隐患对应的 hiddenId)
|
||
// 把返回的 hiddenList 转为 Map 列表,确保索引一致
|
||
final returnedHiddenMapList =
|
||
returnedHiddenList
|
||
.map((e) => Map<String, dynamic>.from(e))
|
||
.toList();
|
||
await uploadHiddenFiles(hiddenFilesPerHidden, returnedHiddenMapList);
|
||
|
||
LoadingDialogHelper.hide();
|
||
ToastUtil.showNormal(context, '提交成功');
|
||
Navigator.of(context).pop();
|
||
} else {
|
||
LoadingDialogHelper.hide();
|
||
final msg =
|
||
res != null
|
||
? (res['msg'] ?? res['msaesge'] ?? res['message'] ?? '提交失败')
|
||
: '提交失败';
|
||
ToastUtil.showNormal(context, msg);
|
||
}
|
||
} catch (e) {
|
||
LoadingDialogHelper.hide();
|
||
ToastUtil.showNormal(context, '提交异常:$e');
|
||
}
|
||
}
|
||
|
||
// ========== 上传附件的方法 ==========
|
||
Future<void> uploadHiddenFiles(
|
||
List<List<Map<String, dynamic>>> hiddenFilesPerHidden,
|
||
List<Map<String, dynamic>> returnedHiddenList,
|
||
) async {
|
||
for (var i = 0; i < hiddenFilesPerHidden.length; i++) {
|
||
final filesForHidden = hiddenFilesPerHidden[i];
|
||
if (filesForHidden.isEmpty) continue;
|
||
final hiddenId =
|
||
i < returnedHiddenList.length
|
||
? (returnedHiddenList[i]['HIDDEN_ID']?.toString() ?? '')
|
||
: '';
|
||
if (hiddenId.isEmpty) continue;
|
||
|
||
for (final f in filesForHidden) {
|
||
final filePath = f['FILEPATH']?.toString() ?? '';
|
||
final type = f['type']?.toString() ?? '';
|
||
if (filePath.isEmpty) continue;
|
||
try {
|
||
await ApiService.addImgFiles(filePath, type, hiddenId);
|
||
} catch (e) {
|
||
// 你可以记录失败项或重试,这里先忽略单文件错误
|
||
print('上传文件失败: $e (path=$filePath)');
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// ========== 罚单提交方法(对应原 fnSubmit) ==========
|
||
Future<bool> fnSubmit(Map<String, dynamic>? ordForm) async {
|
||
if (ordForm == null) return false;
|
||
|
||
final Map<String, String> punishRules = {
|
||
'REASON': '请填写处罚原因',
|
||
'AMOUT': '请填写处罚金额',
|
||
'DATE': '请选择下发处罚时间',
|
||
};
|
||
// 校验
|
||
for (final entry in punishRules.entries) {
|
||
final key = entry.key;
|
||
final msg = entry.value;
|
||
final val = ordForm[key];
|
||
if (val == null || val.toString().trim().isEmpty) {
|
||
ToastUtil.showNormal(context, msg);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
final requestData = Map<String, dynamic>.from(ordForm);
|
||
requestData['CORPINFO_ID'] = SessionService.instance.corpinfoId ?? '';
|
||
requestData['CREATOR'] = SessionService.instance.loginUserId ?? '';
|
||
requestData['OPERATOR'] = SessionService.instance.loginUserId ?? '';
|
||
|
||
try {
|
||
LoadingDialogHelper.show();
|
||
final res = await ApiService.safeCheckPunishSubmit(requestData);
|
||
LoadingDialogHelper.hide();
|
||
if (FormUtils.hasValue(res, 'result') && res['result'] == 'success') {
|
||
return true;
|
||
} else {
|
||
final msg =
|
||
res != null
|
||
? (res['msg'] ?? res['msaesge'] ?? res['message'] ?? '提交失败')
|
||
: '提交失败';
|
||
ToastUtil.showNormal(context, msg);
|
||
return false;
|
||
}
|
||
} catch (e) {
|
||
LoadingDialogHelper.hide();
|
||
ToastUtil.showNormal(context, '罚单提交异常:$e');
|
||
return false;
|
||
}
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
appBar: MyAppbar(title: "安全检查发起", actions: []),
|
||
|
||
body: SafeArea(
|
||
child: Padding(
|
||
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 12),
|
||
child: form.isNotEmpty ? ListView(
|
||
children: [
|
||
Column(
|
||
children: [
|
||
ItemListWidget.itemContainer(
|
||
horizontal: 0,
|
||
Column(
|
||
children: [
|
||
ListItemFactory.createYesNoSection(
|
||
title: '检查题目:',
|
||
groupValue: chooseTitleType,
|
||
yesLabel: '安全',
|
||
noLabel: '综合',
|
||
isEdit: widget.isEdit,
|
||
isRequired: true,
|
||
horizontalPadding: 5,
|
||
verticalPadding: 0,
|
||
text: form['INSPECTION_CATEGORY'] ?? '',
|
||
onChanged: (val) {
|
||
setState(() {
|
||
chooseTitleType = val;
|
||
form['INSPECTION_CATEGORY'] =
|
||
val == true ? '安全' : '综合';
|
||
});
|
||
},
|
||
),
|
||
const Divider(),
|
||
ItemListWidget.singleLineTitleText(
|
||
label: '被检查单位:',
|
||
isEditable: false,
|
||
text: form['UNITS_NAME'],
|
||
onChanged: (val) {
|
||
setState(() {
|
||
form['UNITS_NAME'] = val;
|
||
});
|
||
},
|
||
),
|
||
const Divider(),
|
||
|
||
ItemListWidget.selectableLineTitleTextRightButton(
|
||
label: '被检查单位现场负责人:',
|
||
isEditable: widget.isEdit,
|
||
onTap: () {
|
||
_choosePerson();
|
||
},
|
||
text: form['PERSON_NAME'] ?? '',
|
||
),
|
||
const Divider(),
|
||
|
||
ItemListWidget.singleLineTitleText(
|
||
label: '检查场所:',
|
||
isEditable: widget.isEdit,
|
||
text: form['INSPECTION_PLACE'],
|
||
hintText: '请输入检查场所',
|
||
onChanged: (val) {
|
||
setState(() {
|
||
form['INSPECTION_PLACE'] = val;
|
||
});
|
||
},
|
||
),
|
||
const Divider(),
|
||
|
||
ItemListWidget.selectableLineTitleTextRightButton(
|
||
label: '检查类型:',
|
||
onTap: () {
|
||
_chooseType();
|
||
},
|
||
isEditable: widget.isEdit,
|
||
text: form['INSPECTION_TYPE_NAME'] ?? '',
|
||
),
|
||
const Divider(),
|
||
|
||
ItemListWidget.selectableLineTitleTextRightButton(
|
||
label: '检查开始时间:',
|
||
isEditable: widget.isEdit,
|
||
text: form['INSPECTION_TIME_START'] ?? '',
|
||
onTap: () async {
|
||
DateTime? picked =
|
||
await BottomDateTimePicker.showDate(context);
|
||
if (picked != null) {
|
||
setState(() {
|
||
form['INSPECTION_TIME_START'] = DateFormat(
|
||
'yyyy-MM-dd HH:mm',
|
||
).format(picked);
|
||
});
|
||
FocusHelper.clearFocus(context);
|
||
}
|
||
},
|
||
),
|
||
const Divider(),
|
||
|
||
ItemListWidget.selectableLineTitleTextRightButton(
|
||
label: '检查结束时间:',
|
||
isEditable: widget.isEdit,
|
||
text: form['INSPECTION_TIME_END'] ?? '',
|
||
onTap: () async {
|
||
DateTime? picked =
|
||
await BottomDateTimePicker.showDate(context);
|
||
if (picked != null) {
|
||
setState(() {
|
||
form['INSPECTION_TIME_END'] = DateFormat(
|
||
'yyyy-MM-dd HH:mm',
|
||
).format(picked);
|
||
});
|
||
FocusHelper.clearFocus(context);
|
||
}
|
||
},
|
||
),
|
||
|
||
const Divider(),
|
||
MultiTextFieldWithTitle(
|
||
label: "检查情况",
|
||
// 更合适的标题
|
||
isEditable: widget.isEdit,
|
||
// 使用父组件的编辑状态
|
||
hintText: "请输入检查情况...",
|
||
texts: multiTexts,
|
||
onTextsChanged: (texts) {
|
||
setState(() {
|
||
multiTexts = texts; // 保存到状态变量
|
||
form['situationList'] = _stringsToSituationList(
|
||
texts,
|
||
);
|
||
});
|
||
},
|
||
),
|
||
|
||
const Divider(),
|
||
ItemListWidget.multiLineTitleTextField(
|
||
label: '检查人员',
|
||
text: form['INSPECTION_USERS'] ?? '',
|
||
isEditable: widget.isEdit,
|
||
onChanged: (val) {
|
||
setState(() {
|
||
form['INSPECTION_USERS'] = val;
|
||
});
|
||
},
|
||
),
|
||
const Divider(),
|
||
ItemListWidget.itemContainer(
|
||
Row(
|
||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||
children: [
|
||
ListItemFactory.headerTitle('发现问题'),
|
||
if (widget.isEdit)
|
||
CustomButton(
|
||
text: " 添加 ",
|
||
height: 30,
|
||
padding: const EdgeInsets.symmetric(
|
||
vertical: 2,
|
||
horizontal: 5,
|
||
),
|
||
backgroundColor: Colors.blue,
|
||
onPressed: () {
|
||
_openDrawer(form, -1); // 添加括号和 await
|
||
FocusHelper.clearFocus(context);
|
||
},
|
||
),
|
||
],
|
||
),
|
||
),
|
||
HiddenListTable(
|
||
hiddenList: form['hiddenList'] ?? [],
|
||
forbidEdit: widget.isEdit,
|
||
baseImgPath: ApiService.baseImgPath,
|
||
personSignImg: form['PERSON_SIGN_IMG'] ?? '',
|
||
personSignTime: form['PERSON_SIGN_TIME'] ?? '',
|
||
showHidden: (item, idx) {
|
||
_openDrawer(item, idx);
|
||
},
|
||
removeHidden: (item, idx) {
|
||
/* 删除逻辑 */
|
||
},
|
||
context: context,
|
||
),
|
||
|
||
if (!widget.isEdit)
|
||
Column(children: [
|
||
const Divider(),
|
||
ItemListWidget.twoRowTitleAndImages(
|
||
title: '签字',
|
||
onTapCallBack: (p) {
|
||
presentOpaque(SingleImageViewer(imageUrl: p), context);
|
||
},
|
||
imageUrls: [
|
||
'${form['PERSON_SIGN_IMG'] ?? ''}',
|
||
],
|
||
),
|
||
const Divider(),
|
||
ItemListWidget.singleLineTitleText(label: '签字时间', isEditable: false, text: form['PERSON_SIGN_TIME'] ?? '')
|
||
],)
|
||
],
|
||
),
|
||
),
|
||
SizedBox(height: 20),
|
||
Row(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
if (widget.isEdit)
|
||
SizedBox(
|
||
width: 150,
|
||
child: CustomButton(
|
||
text: '返回',
|
||
textStyle: TextStyle(
|
||
color: Colors.white,
|
||
fontSize: 17,
|
||
),
|
||
backgroundColor: Colors.black38,
|
||
onPressed: () => Navigator.pop(context),
|
||
),
|
||
),
|
||
SizedBox(
|
||
width: 150,
|
||
child: CustomButton(
|
||
text: widget.isEdit ? '提交' : '返回',
|
||
textStyle: TextStyle(
|
||
color: Colors.white,
|
||
fontSize: 17,
|
||
),
|
||
backgroundColor: Colors.blue,
|
||
onPressed: _submit,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
],
|
||
): SizedBox(),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|