气体检测,无数据通用组件
parent
4d3fb2b6e6
commit
fd4cbf2dff
|
|
@ -339,6 +339,7 @@ class ListItemFactory {
|
|||
const SizedBox(height: 8),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
autofocus: false,
|
||||
controller: controller,
|
||||
keyboardType: TextInputType.multiline,
|
||||
maxLines: null,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:qhd_prevention/customWidget/toast_util.dart';
|
||||
|
||||
/// 通用底部弹窗选择器
|
||||
/// Example:
|
||||
|
|
@ -30,8 +31,12 @@ class BottomPicker {
|
|||
double itemExtent = 40.0,
|
||||
double height = 250,
|
||||
}) {
|
||||
if (items.isEmpty) return Future.value(null);
|
||||
|
||||
// 确保初始索引合法
|
||||
final safeIndex = initialIndex.clamp(0, items.length - 1);
|
||||
// 当前选中项
|
||||
T selected = items[initialIndex];
|
||||
T selected = items[safeIndex];
|
||||
|
||||
return showModalBottomSheet<T>(
|
||||
context: context,
|
||||
|
|
@ -51,11 +56,11 @@ class BottomPicker {
|
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(ctx).pop(),
|
||||
onPressed: () {FocusScope.of(context).unfocus();Navigator.of(ctx).pop();},
|
||||
child: const Text('取消'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(ctx).pop(selected),
|
||||
onPressed: () {FocusScope.of(context).unfocus(); Navigator.of(ctx).pop(selected);},
|
||||
child: const Text('确定'),
|
||||
),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,27 +1,56 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class CustomAlertDialog extends StatelessWidget {
|
||||
/// 对话框模式
|
||||
enum DialogMode { text, input }
|
||||
|
||||
class CustomAlertDialog extends StatefulWidget {
|
||||
final String title;
|
||||
final String content;
|
||||
final String content; // 文字模式下显示
|
||||
final String hintText; // 输入模式下提示
|
||||
final String cancelText;
|
||||
final String confirmText;
|
||||
final VoidCallback? onCancel;
|
||||
final VoidCallback? onConfirm;
|
||||
final VoidCallback? onConfirm; // 文字模式回调
|
||||
final ValueChanged<String>? onInputConfirm; // 输入模式回调
|
||||
final DialogMode mode; // 新增:对话框模式
|
||||
|
||||
const CustomAlertDialog({
|
||||
Key? key,
|
||||
required this.title,
|
||||
required this.content,
|
||||
this.cancelText = "取消",
|
||||
this.confirmText = "确定",
|
||||
this.content = '',
|
||||
this.hintText = '',
|
||||
this.cancelText = '取消',
|
||||
this.confirmText = '确定',
|
||||
this.onCancel,
|
||||
this.onConfirm,
|
||||
this.onInputConfirm,
|
||||
this.mode = DialogMode.text, // 默认文字模式
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final bool hasCancel = cancelText.trim().isNotEmpty;
|
||||
_CustomAlertDialogState createState() => _CustomAlertDialogState();
|
||||
}
|
||||
|
||||
class _CustomAlertDialogState extends State<CustomAlertDialog> {
|
||||
late TextEditingController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// 输入模式下初始化 TextField
|
||||
_controller = TextEditingController();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
bool get hasCancel => widget.cancelText.trim().isNotEmpty;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Dialog(
|
||||
backgroundColor: Colors.transparent,
|
||||
child: Container(
|
||||
|
|
@ -29,34 +58,55 @@ class CustomAlertDialog extends StatelessWidget {
|
|||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
),
|
||||
padding: EdgeInsets.zero,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const SizedBox(height: 20),
|
||||
Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
widget.title,
|
||||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 30),
|
||||
child: Text(
|
||||
content,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.black45,
|
||||
|
||||
// ★ 根据 mode 决定展示文字还是输入框 ★
|
||||
if (widget.mode == DialogMode.text)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 30),
|
||||
child: Text(
|
||||
widget.content,
|
||||
style: const TextStyle(fontSize: 16, color: Colors.black45),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
)
|
||||
else
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: TextField(
|
||||
controller: _controller,
|
||||
|
||||
decoration: InputDecoration(
|
||||
hintText: widget.hintText,
|
||||
border: const OutlineInputBorder(),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.blue, width: 1),
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
isDense: true,
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
vertical: 10,
|
||||
horizontal: 10,
|
||||
),
|
||||
),
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 20),
|
||||
const Divider(height: 1),
|
||||
hasCancel ? _buildDoubleButtons(context) : _buildSingleButton(context),
|
||||
|
||||
hasCancel
|
||||
? _buildDoubleButtons(context)
|
||||
: _buildSingleButton(context),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
@ -66,17 +116,18 @@ class CustomAlertDialog extends StatelessWidget {
|
|||
Widget _buildDoubleButtons(BuildContext context) {
|
||||
return Row(
|
||||
children: [
|
||||
// 取消
|
||||
Expanded(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
onCancel?.call();
|
||||
widget.onCancel?.call();
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
cancelText,
|
||||
widget.cancelText,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.black,
|
||||
|
|
@ -86,20 +137,27 @@ class CustomAlertDialog extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
),
|
||||
|
||||
Container(width: 1, height: 48, color: Colors.grey[300]),
|
||||
|
||||
// 确定
|
||||
Expanded(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
onConfirm?.call();
|
||||
if (widget.mode == DialogMode.text) {
|
||||
widget.onConfirm?.call();
|
||||
} else {
|
||||
widget.onInputConfirm?.call(_controller.text.trim());
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
confirmText,
|
||||
widget.confirmText,
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF3874F6), // 蓝色字体
|
||||
color: Color(0xFF3874F6),
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 18,
|
||||
),
|
||||
|
|
@ -115,16 +173,20 @@ class CustomAlertDialog extends StatelessWidget {
|
|||
return InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
onConfirm?.call();
|
||||
if (widget.mode == DialogMode.text) {
|
||||
widget.onConfirm?.call();
|
||||
} else {
|
||||
widget.onInputConfirm?.call(_controller.text.trim());
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
confirmText,
|
||||
widget.confirmText,
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF3874F6), // 蓝色字体
|
||||
color: Color(0xFF3874F6),
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 18,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class CustomButton extends StatelessWidget {
|
|||
return GestureDetector(
|
||||
onTap: onPressed,
|
||||
child: Container(
|
||||
height: height ?? 50, // 默认高度50
|
||||
height: height ?? 45, // 默认高度45
|
||||
padding: padding ?? const EdgeInsets.all(8), // 默认内边距
|
||||
margin: margin ?? const EdgeInsets.symmetric(horizontal: 5), // 默认外边距
|
||||
decoration: BoxDecoration(
|
||||
|
|
@ -40,6 +40,7 @@ class CustomButton extends StatelessWidget {
|
|||
text,
|
||||
style: textStyle ?? const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:qhd_prevention/customWidget/custom_button.dart';
|
||||
|
||||
class HDatePickerDialog extends StatefulWidget {
|
||||
final DateTime initialDate;
|
||||
|
|
@ -125,7 +126,7 @@ class _HDatePickerDialogState extends State<HDatePickerDialog> {
|
|||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected ? Theme.of(context).primaryColor : null,
|
||||
color: isSelected ? Colors.blue : null,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Center(
|
||||
|
|
@ -147,14 +148,13 @@ class _HDatePickerDialogState extends State<HDatePickerDialog> {
|
|||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: widget.onCancel,
|
||||
child: const Text('取消'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () => widget.onConfirm(_selectedDate),
|
||||
child: const Text('确定'),
|
||||
),
|
||||
Expanded(child: CustomButton(text: '取消',height: 40,backgroundColor: Colors.grey.shade500,
|
||||
onPressed: widget.onCancel),),
|
||||
SizedBox(width: 30,),
|
||||
Expanded(child: CustomButton(text: '确定',height: 40,backgroundColor: Colors.blue,
|
||||
onPressed: () => widget.onConfirm(_selectedDate)),)
|
||||
|
||||
|
||||
],
|
||||
),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:qhd_prevention/customWidget/search_bar_widget.dart';
|
||||
|
||||
/// 用户数据模型
|
||||
class Person {
|
||||
final String userId;
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ class _MediaPickerRowState extends State<MediaPickerRow> {
|
|||
widget.onChanged(_files);
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('拍摄失败: \$e');
|
||||
debugPrint('拍摄失败: $e');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -140,7 +140,7 @@ class _MediaPickerRowState extends State<MediaPickerRow> {
|
|||
widget.onChanged(_files);
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('相册选择失败: \$e');
|
||||
debugPrint('相册选择失败: $e');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,220 @@
|
|||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// 调用示例:
|
||||
/// DateTime? picked = await BottomDateTimePicker.show(context);
|
||||
/// if (picked != null) {
|
||||
/// print('用户选择的时间:$picked');
|
||||
/// }
|
||||
class BottomDateTimePicker {
|
||||
static Future<DateTime?> show(BuildContext context) {
|
||||
return showModalBottomSheet<DateTime>(
|
||||
context: context,
|
||||
backgroundColor: Colors.white,
|
||||
isScrollControlled: true,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(12)),
|
||||
),
|
||||
builder: (_) => _InlineDateTimePickerContent(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _InlineDateTimePickerContent extends StatefulWidget {
|
||||
@override
|
||||
State<_InlineDateTimePickerContent> createState() => _InlineDateTimePickerContentState();
|
||||
}
|
||||
|
||||
class _InlineDateTimePickerContentState extends State<_InlineDateTimePickerContent> {
|
||||
// 数据源
|
||||
final List<int> years = List.generate(101, (i) => 1970 + i);
|
||||
final List<int> months = List.generate(12, (i) => i + 1);
|
||||
final List<int> days = List.generate(31, (i) => i + 1);
|
||||
final List<int> hours = List.generate(24, (i) => i);
|
||||
final List<int> minutes = List.generate(60, (i) => i);
|
||||
|
||||
// Controllers
|
||||
late FixedExtentScrollController yearCtrl;
|
||||
late FixedExtentScrollController monthCtrl;
|
||||
late FixedExtentScrollController dayCtrl;
|
||||
late FixedExtentScrollController hourCtrl;
|
||||
late FixedExtentScrollController minuteCtrl;
|
||||
|
||||
// 当前选中值
|
||||
late int selectedYear;
|
||||
late int selectedMonth;
|
||||
late int selectedDay;
|
||||
late int selectedHour;
|
||||
late int selectedMinute;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final now = DateTime.now();
|
||||
selectedYear = now.year;
|
||||
selectedMonth = now.month;
|
||||
selectedDay = now.day;
|
||||
selectedHour = now.hour;
|
||||
selectedMinute = now.minute;
|
||||
|
||||
yearCtrl = FixedExtentScrollController(initialItem: years.indexOf(selectedYear));
|
||||
monthCtrl = FixedExtentScrollController(initialItem: selectedMonth - 1);
|
||||
dayCtrl = FixedExtentScrollController(initialItem: selectedDay - 1);
|
||||
hourCtrl = FixedExtentScrollController(initialItem: selectedHour);
|
||||
minuteCtrl = FixedExtentScrollController(initialItem: selectedMinute);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
yearCtrl.dispose();
|
||||
monthCtrl.dispose();
|
||||
dayCtrl.dispose();
|
||||
hourCtrl.dispose();
|
||||
minuteCtrl.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _checkAndClampToNow() {
|
||||
final picked = DateTime(selectedYear, selectedMonth, selectedDay, selectedHour, selectedMinute);
|
||||
final now = DateTime.now();
|
||||
if (picked.isAfter(now)) {
|
||||
// 回滚到当前时间
|
||||
selectedYear = now.year;
|
||||
selectedMonth = now.month;
|
||||
selectedDay = now.day;
|
||||
selectedHour = now.hour;
|
||||
selectedMinute = now.minute;
|
||||
|
||||
// 更新各滚轮位置
|
||||
yearCtrl.jumpToItem(years.indexOf(selectedYear));
|
||||
monthCtrl.jumpToItem(selectedMonth - 1);
|
||||
dayCtrl.jumpToItem(selectedDay - 1);
|
||||
hourCtrl.jumpToItem(selectedHour);
|
||||
minuteCtrl.jumpToItem(selectedMinute);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
height: 300,
|
||||
child: Column(
|
||||
children: [
|
||||
// 顶部按钮
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: const Text("取消", style: TextStyle(color: Colors.grey)),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
final result = DateTime(
|
||||
selectedYear,
|
||||
selectedMonth,
|
||||
selectedDay,
|
||||
selectedHour,
|
||||
selectedMinute,
|
||||
);
|
||||
Navigator.of(context).pop(result);
|
||||
},
|
||||
child: const Text("确定", style: TextStyle(color: Colors.blue)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const Divider(height: 1),
|
||||
|
||||
// 五列数字滚轮
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
// 年
|
||||
_buildPicker(
|
||||
controller: yearCtrl,
|
||||
items: years.map((e) => e.toString()).toList(),
|
||||
onSelected: (idx) {
|
||||
setState(() {
|
||||
selectedYear = years[idx];
|
||||
_checkAndClampToNow();
|
||||
});
|
||||
},
|
||||
),
|
||||
|
||||
// 月
|
||||
_buildPicker(
|
||||
controller: monthCtrl,
|
||||
items: months.map((e) => e.toString().padLeft(2, '0')).toList(),
|
||||
onSelected: (idx) {
|
||||
setState(() {
|
||||
selectedMonth = months[idx];
|
||||
_checkAndClampToNow();
|
||||
});
|
||||
},
|
||||
),
|
||||
|
||||
// 日
|
||||
_buildPicker(
|
||||
controller: dayCtrl,
|
||||
items: days.map((e) => e.toString().padLeft(2, '0')).toList(),
|
||||
onSelected: (idx) {
|
||||
setState(() {
|
||||
selectedDay = days[idx];
|
||||
_checkAndClampToNow();
|
||||
});
|
||||
},
|
||||
),
|
||||
|
||||
// 时
|
||||
_buildPicker(
|
||||
controller: hourCtrl,
|
||||
items: hours.map((e) => e.toString().padLeft(2, '0')).toList(),
|
||||
onSelected: (idx) {
|
||||
setState(() {
|
||||
selectedHour = hours[idx];
|
||||
_checkAndClampToNow();
|
||||
});
|
||||
},
|
||||
),
|
||||
|
||||
// 分
|
||||
_buildPicker(
|
||||
controller: minuteCtrl,
|
||||
items: minutes.map((e) => e.toString().padLeft(2, '0')).toList(),
|
||||
onSelected: (idx) {
|
||||
setState(() {
|
||||
selectedMinute = minutes[idx];
|
||||
_checkAndClampToNow();
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPicker({
|
||||
required FixedExtentScrollController controller,
|
||||
required List<String> items,
|
||||
required ValueChanged<int> onSelected,
|
||||
}) {
|
||||
return Expanded(
|
||||
child: CupertinoPicker.builder(
|
||||
scrollController: controller,
|
||||
itemExtent: 32,
|
||||
childCount: items.length,
|
||||
onSelectedItemChanged: onSelected,
|
||||
itemBuilder: (context, index) {
|
||||
return Center(child: Text(items[index]));
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -70,7 +70,7 @@ class _RemoteFilePageState extends State<RemoteFilePage> {
|
|||
_isLoading = false;
|
||||
});
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('文件加载失败: \$e')),
|
||||
SnackBar(content: Text('文件加载失败: $e')),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,14 +9,20 @@ class SingleImageViewer extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.black,
|
||||
backgroundColor: Colors.black.withValues(alpha: 0.7),
|
||||
appBar: MyAppbar(
|
||||
backgroundColor: Colors.transparent, title: '',
|
||||
isBack: false,
|
||||
actions: [
|
||||
IconButton(onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
}, icon: Icon(Icons.close, color: Colors.white, size: 40,),)
|
||||
],
|
||||
backgroundColor: Colors.black.withValues(alpha:0.7), title: '',
|
||||
),
|
||||
body: Center(
|
||||
child: PhotoView(
|
||||
imageProvider: NetworkImage(imageUrl),
|
||||
backgroundDecoration: BoxDecoration(color: Colors.black),
|
||||
backgroundDecoration: BoxDecoration(color: Colors.black.withValues(alpha:00.5)),
|
||||
minScale: PhotoViewComputedScale.contained,
|
||||
maxScale: PhotoViewComputedScale.covered * 2,
|
||||
onTapUp: (context, details, controllerValue) {
|
||||
|
|
|
|||
|
|
@ -607,6 +607,7 @@ U6Hzm1ninpWeE+awIDAQAB
|
|||
},
|
||||
);
|
||||
}
|
||||
/// 作业流程图
|
||||
static Future<Map<String, dynamic>> dhGetFlowList(String hotworkId) {
|
||||
return HttpManager().request(
|
||||
basePath,
|
||||
|
|
@ -617,6 +618,138 @@ U6Hzm1ninpWeE+awIDAQAB
|
|||
},
|
||||
);
|
||||
}
|
||||
/// 作业详情
|
||||
static Future<Map<String, dynamic>> getHomeworkFindById(String hotworkId) {
|
||||
return HttpManager().request(
|
||||
basePath,
|
||||
'/app/hotwork/findById',
|
||||
method: Method.post,
|
||||
data: {
|
||||
"HOTWORK_ID":hotworkId,
|
||||
"CORPINFO_ID":SessionService.instance.corpinfoId,
|
||||
"USER_ID":SessionService.instance.loginUserId,
|
||||
},
|
||||
);
|
||||
}
|
||||
/// 提交作业
|
||||
static Future<Map<String, dynamic>> submitHotwork(String url, Map data) {
|
||||
return HttpManager().request(
|
||||
basePath,
|
||||
url,
|
||||
method: Method.post,
|
||||
data: {
|
||||
...data
|
||||
},
|
||||
);
|
||||
}
|
||||
/// 气体分析详情列表
|
||||
static Future<Map<String, dynamic>> hotworkGasList(String hotworkId) {
|
||||
return HttpManager().request(
|
||||
basePath,
|
||||
'/app/hotwork/gas/list',
|
||||
method: Method.post,
|
||||
data: {
|
||||
"HOTWORK_ID":hotworkId,
|
||||
"tm": DateTime.now().millisecondsSinceEpoch,
|
||||
"CORPINFO_ID":SessionService.instance.corpinfoId,
|
||||
"USER_ID":SessionService.instance.loginUserId,
|
||||
},
|
||||
);
|
||||
}
|
||||
/// 气体分析详情列表删除
|
||||
static Future<Map<String, dynamic>> hotworkGasDelete(String hotworkId) {
|
||||
return HttpManager().request(
|
||||
basePath,
|
||||
'/app/hotwork/gas/delete',
|
||||
method: Method.post,
|
||||
data: {
|
||||
"HOTWORK_ID":hotworkId,
|
||||
"tm": DateTime.now().millisecondsSinceEpoch,
|
||||
"CORPINFO_ID":SessionService.instance.corpinfoId,
|
||||
"USER_ID":SessionService.instance.loginUserId,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
static Future<Map<String, dynamic>> listSignFinished(String hotworkId) {
|
||||
return HttpManager().request(
|
||||
basePath,
|
||||
'/app/hotwork/listSignFinished',
|
||||
method: Method.post,
|
||||
data: {
|
||||
"HOTWORK_ID":hotworkId,
|
||||
},
|
||||
);
|
||||
}
|
||||
/// 安全防护措施
|
||||
static Future<Map<String, dynamic>> listSignFinishMeasures(String hotworkId) {
|
||||
return HttpManager().request(
|
||||
basePath,
|
||||
'/app/hotwork/listSignFinishMeasures',
|
||||
method: Method.post,
|
||||
data: {
|
||||
"HOTWORK_ID":hotworkId,
|
||||
},
|
||||
);
|
||||
}
|
||||
/// 关联的特殊作业列表
|
||||
static Future<Map<String, dynamic>> getEightWorkStartList(Map data) {
|
||||
return HttpManager().request(
|
||||
basePath,
|
||||
'/app/eightwork/startingList',
|
||||
method: Method.post,
|
||||
data: {
|
||||
...data
|
||||
},
|
||||
);
|
||||
}
|
||||
/// 风险辨识结果 风险列表
|
||||
static Future<Map<String, dynamic>> getEightWorkInfo(Map data) {
|
||||
return HttpManager().request(
|
||||
basePath,
|
||||
'/app/eightwork/getInfo',
|
||||
method: Method.post,
|
||||
data: {
|
||||
...data
|
||||
},
|
||||
);
|
||||
}
|
||||
/// 动火人及证书编号
|
||||
static Future<Map<String, dynamic>> getHotWorkNameList() {
|
||||
return HttpManager().request(
|
||||
basePath,
|
||||
'/app/hotwork/namelist',
|
||||
method: Method.post,
|
||||
data: {
|
||||
"tm": DateTime.now().millisecondsSinceEpoch,
|
||||
"CORPINFO_ID":SessionService.instance.corpinfoId,
|
||||
"USER_ID":SessionService.instance.loginUserId,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// 保存或作废气体检测
|
||||
static Future<Map<String, dynamic>> saveGasTest(
|
||||
Map<String, dynamic> formData,
|
||||
List<String> filePaths,
|
||||
) async {
|
||||
// 复制一份 formData
|
||||
final data = Map<String, dynamic>.from(formData);
|
||||
|
||||
// 把文件路径填成 MultipartFile
|
||||
for (var i = 0; i < filePaths.length; i++) {
|
||||
final path = filePaths[i];
|
||||
data['file$i'] = await MultipartFile.fromFile(
|
||||
path,
|
||||
filename: path.split(Platform.pathSeparator).last,
|
||||
);
|
||||
}
|
||||
return HttpManager().uploadFaceImage(
|
||||
baseUrl: basePath,
|
||||
path: '/app/hotwork/gas/save',
|
||||
fromData: data,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,8 @@ void main() async {
|
|||
class MyApp extends StatelessWidget {
|
||||
final bool isLoggedIn;
|
||||
|
||||
const MyApp({super.key, required this.isLoggedIn});
|
||||
MyApp({super.key, required this.isLoggedIn});
|
||||
final FocusNode _blankFocusNode = FocusNode(); // 全局空焦点节点
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
@ -72,7 +73,7 @@ class MyApp extends StatelessWidget {
|
|||
behavior: HitTestBehavior.translucent, // 让空白区域也能点击
|
||||
onTap: () {
|
||||
// 收起键盘
|
||||
FocusScope.of(context).unfocus();
|
||||
FocusScope.of(context).requestFocus(_blankFocusNode);
|
||||
},
|
||||
child: child,
|
||||
);
|
||||
|
|
@ -107,7 +108,6 @@ class MyApp extends StatelessWidget {
|
|||
debugShowCheckedModeBanner: false,
|
||||
routes: {
|
||||
'/login': (_) => const LoginPage(),
|
||||
//---------动火列表详情
|
||||
|
||||
// ... 其他路由
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import '../../http/ApiService.dart';
|
||||
import '../../tools/tools.dart';
|
||||
import '../../../http/ApiService.dart';
|
||||
import '../../../tools/tools.dart';
|
||||
|
||||
class HiddenRollWidget extends StatefulWidget {
|
||||
/// 隐患列表数据
|
||||
|
|
@ -12,7 +12,7 @@ import 'package:qhd_prevention/pages/home/work/danger_wait_list_page.dart';
|
|||
import 'package:qhd_prevention/pages/home/work/laws_regulations_page.dart';
|
||||
import 'package:qhd_prevention/pages/home/workSet_page.dart';
|
||||
|
||||
import '../../customWidget/hidden_roll_widget.dart';
|
||||
import 'hidden_roll_widget.dart';
|
||||
import '../../http/ApiService.dart';
|
||||
import '../../tools/tools.dart';
|
||||
|
||||
|
|
@ -359,7 +359,7 @@ class _HomePageState extends State<HomePage> {
|
|||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Image.asset(icon, width: 35, height: 35),
|
||||
const SizedBox(width: 15),
|
||||
const SizedBox(width: 5),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ class _RiskControlPageState extends State<RiskControlPage> {
|
|||
),
|
||||
Expanded(
|
||||
child: _list.isEmpty
|
||||
? Center(child: Text('暂无数据'))
|
||||
? NoDataWidget.show()
|
||||
: ListView.separated(
|
||||
separatorBuilder: (_, __) => const Divider(height: 1),
|
||||
itemCount: _list.length,
|
||||
|
|
|
|||
|
|
@ -49,16 +49,7 @@ class _StudyClassListPageState extends State<StudyClassListPage> {
|
|||
appBar: MyAppbar(title: "课程列表"),
|
||||
body: SafeArea(
|
||||
child: _list.isEmpty
|
||||
? Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Image.asset('assets/images/null.png', width: 150),
|
||||
SizedBox(height: 12),
|
||||
Text('暂无数据', style: TextStyle(color: Colors.grey)),
|
||||
],
|
||||
),
|
||||
) : ListView.builder(
|
||||
? NoDataWidget.show() : ListView.builder(
|
||||
itemCount: _list.length,
|
||||
itemBuilder: (context, index) {
|
||||
return _buildItem(_list[index]);
|
||||
|
|
|
|||
|
|
@ -383,16 +383,7 @@ class _StudyMyTaskPageState extends State<StudyMyTaskPage> {
|
|||
onNotification: _onScroll,
|
||||
child:
|
||||
_list.isEmpty
|
||||
? Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Image.asset('assets/images/null.png', width: 150),
|
||||
SizedBox(height: 12),
|
||||
Text('暂无数据', style: TextStyle(color: Colors.grey)),
|
||||
],
|
||||
),
|
||||
)
|
||||
? NoDataWidget.show()
|
||||
: ListView.builder(
|
||||
itemCount: _list.length,
|
||||
itemBuilder: (_, i) => _buildItem(_list[i]),
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ import 'package:flutter/material.dart';
|
|||
import 'package:qhd_prevention/customWidget/custom_button.dart';
|
||||
import 'package:qhd_prevention/customWidget/toast_util.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import '../../../http/ApiService.dart'; // 替换为实际路径
|
||||
import '../../../http/ApiService.dart';
|
||||
import '../../../tools/tools.dart'; // 替换为实际路径
|
||||
|
||||
class StudyPractisePage extends StatefulWidget {
|
||||
final String videoCoursewareId;
|
||||
|
|
@ -253,7 +254,7 @@ class _PracticePageState extends State<StudyPractisePage> {
|
|||
loading
|
||||
? Center(child: CircularProgressIndicator())
|
||||
: options.isEmpty
|
||||
? Center(child: Text('暂无数据'))
|
||||
? NoDataWidget.show()
|
||||
: Padding(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: Column(
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/tools/h_colors.dart';
|
||||
import '../../../http/ApiService.dart';
|
||||
import '../../../tools/tools.dart';
|
||||
|
||||
class StudyScorePage extends StatefulWidget {
|
||||
const StudyScorePage({Key? key}) : super(key: key);
|
||||
|
|
@ -229,9 +230,7 @@ class _StudyScorePageState extends State<StudyScorePage> {
|
|||
Expanded(
|
||||
child:
|
||||
list.isEmpty
|
||||
? Center(
|
||||
child: Text('暂无数据', style: TextStyle(color: Colors.grey)),
|
||||
)
|
||||
? NoDataWidget.show()
|
||||
: ListView.builder(
|
||||
controller: _scrollController,
|
||||
itemCount: list.length + 1,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import 'package:qhd_prevention/customWidget/custom_button.dart';
|
|||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
|
||||
import '../../../tools/tools.dart';
|
||||
|
||||
class VideoStudyDetailPage extends StatefulWidget {
|
||||
final String studentId;
|
||||
final String classId;
|
||||
|
|
@ -163,7 +165,7 @@ class _VideoStudyDetailPageState extends State<VideoStudyDetailPage> {
|
|||
body: loading
|
||||
? Center(child: CircularProgressIndicator())
|
||||
: questions.isEmpty
|
||||
? Center(child: Text('暂无数据'))
|
||||
? NoDataWidget.show()
|
||||
: Padding(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: Column(
|
||||
|
|
|
|||
|
|
@ -5,15 +5,19 @@ class ItemListWidget {
|
|||
/// 单行水平排列:
|
||||
/// - 可编辑时:标题 + TextField
|
||||
/// - 不可编辑时:标题 + 带省略号的文本
|
||||
|
||||
static const Color detailtextColor = Colors.black54;
|
||||
|
||||
static Widget singleLineTitleText({
|
||||
required String label, // 标题文本
|
||||
required bool isEditable, // 是否可编辑
|
||||
TextEditingController? controller, // 编辑时使用的控制器
|
||||
String? text, // 不可编辑时显示的文本
|
||||
String hintText = '请输入',
|
||||
double fontSize = 15, // 字体大小
|
||||
}) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
|
||||
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 12),
|
||||
child: Row(
|
||||
mainAxisAlignment: isEditable
|
||||
? MainAxisAlignment.start
|
||||
|
|
@ -27,19 +31,20 @@ class ItemListWidget {
|
|||
isEditable
|
||||
? Expanded(
|
||||
child: TextField(
|
||||
autofocus: false,
|
||||
controller: controller,
|
||||
style: TextStyle(fontSize: fontSize),
|
||||
maxLines: 1,
|
||||
decoration: const InputDecoration(
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
hintText: '请输入',
|
||||
hintText: hintText,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 8),
|
||||
),
|
||||
),
|
||||
)
|
||||
: Text(
|
||||
text ?? '',
|
||||
style: TextStyle(fontSize: fontSize, color: Colors.grey[500]),
|
||||
style: TextStyle(fontSize: fontSize, color: detailtextColor),
|
||||
overflow: TextOverflow.ellipsis, // 超出省略
|
||||
),
|
||||
],
|
||||
|
|
@ -59,7 +64,8 @@ class ItemListWidget {
|
|||
double height = 110, // 整体高度
|
||||
}) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
|
||||
// 统一左右 padding,保证标题和内容在同一左侧基线
|
||||
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 12),
|
||||
height: height,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
|
@ -67,28 +73,32 @@ class ItemListWidget {
|
|||
Text(
|
||||
label,
|
||||
style: TextStyle(fontSize: fontSize, fontWeight: FontWeight.bold),
|
||||
), // 显示标题
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Expanded(
|
||||
child: isEditable
|
||||
? TextField(
|
||||
autofocus: false,
|
||||
controller: controller,
|
||||
keyboardType: TextInputType.multiline,
|
||||
maxLines: null,
|
||||
expands: true, // 填满剩余高度
|
||||
expands: true,
|
||||
// 垂直顶部对齐
|
||||
textAlignVertical: TextAlignVertical.top,
|
||||
style: TextStyle(fontSize: fontSize),
|
||||
decoration: const InputDecoration(
|
||||
hintText: '请输入'
|
||||
decoration: InputDecoration(
|
||||
hintText: '请输入',
|
||||
// 去掉 TextField 默认内边距
|
||||
contentPadding: EdgeInsets.zero,
|
||||
border: InputBorder.none,
|
||||
),
|
||||
)
|
||||
: Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
|
||||
child: SingleChildScrollView(
|
||||
child: Text(
|
||||
text ?? '',
|
||||
style: TextStyle(fontSize: fontSize, color: Colors.grey),
|
||||
),
|
||||
: SingleChildScrollView(
|
||||
// 去掉多余的 padding
|
||||
padding: EdgeInsets.zero,
|
||||
child: Text(
|
||||
text ?? '',
|
||||
style: TextStyle(fontSize: fontSize, color: detailtextColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
@ -97,6 +107,7 @@ class ItemListWidget {
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
/// 单行可点击选择:
|
||||
/// - 可编辑时:标题 + “请选择”提示 + 右箭头
|
||||
/// - 不可编辑时:标题 + 文本内容
|
||||
|
|
@ -110,7 +121,7 @@ class ItemListWidget {
|
|||
return InkWell(
|
||||
onTap: isEditable ? onTap : null,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
|
||||
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 12),
|
||||
child: Row(
|
||||
children: [
|
||||
// 1. 标题
|
||||
|
|
@ -135,7 +146,7 @@ class ItemListWidget {
|
|||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontSize: fontSize,
|
||||
color: isEditable ? Colors.black : Colors.grey,
|
||||
color: isEditable ? Colors.black : detailtextColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
@ -171,7 +182,7 @@ class ItemListWidget {
|
|||
double row2Height = 80, // 第二行高度
|
||||
}) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
|
||||
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
|
|
@ -188,10 +199,10 @@ class ItemListWidget {
|
|||
Row(
|
||||
children: [
|
||||
Text(
|
||||
isEditable ? (text.isNotEmpty ? text : '请选择') : '',
|
||||
isEditable ? '请选择' : '',
|
||||
style: TextStyle(
|
||||
fontSize: fontSize,
|
||||
color: isEditable ? Colors.black : Colors.grey,
|
||||
color: isEditable ? Colors.black : detailtextColor,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
|
|
@ -208,6 +219,7 @@ class ItemListWidget {
|
|||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: isEditable
|
||||
? TextField(
|
||||
autofocus: false,
|
||||
controller: controller,
|
||||
keyboardType: TextInputType.multiline,
|
||||
maxLines: null,
|
||||
|
|
@ -223,7 +235,7 @@ class ItemListWidget {
|
|||
padding: EdgeInsets.zero,
|
||||
child: Text(
|
||||
text,
|
||||
style: TextStyle(fontSize: fontSize, color: Colors.grey),
|
||||
style: TextStyle(fontSize: fontSize, color: detailtextColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
@ -246,27 +258,31 @@ class ItemListWidget {
|
|||
double row2Height = 80, // 第二行高度
|
||||
}) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
|
||||
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 第一行:标题 + 按钮
|
||||
InkWell(
|
||||
onTap: isEditable ? onTap : null,
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(fontSize: fontSize, fontWeight: FontWeight.bold),
|
||||
Flexible(
|
||||
child: Text(
|
||||
label,
|
||||
style: TextStyle(fontSize: fontSize, fontWeight: FontWeight.bold),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
CustomButton(
|
||||
text: "选择其他",
|
||||
height: 30,
|
||||
padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 5),
|
||||
backgroundColor: Colors.green,
|
||||
onPressed: onTap,
|
||||
),
|
||||
if (isEditable)
|
||||
CustomButton(
|
||||
text: "选择其他",
|
||||
height: 30,
|
||||
padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 5),
|
||||
backgroundColor: Colors.green,
|
||||
onPressed: onTap,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
@ -277,6 +293,7 @@ class ItemListWidget {
|
|||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: isEditable
|
||||
? TextField(
|
||||
autofocus: false,
|
||||
controller: controller,
|
||||
keyboardType: TextInputType.multiline,
|
||||
maxLines: null,
|
||||
|
|
@ -292,7 +309,7 @@ class ItemListWidget {
|
|||
padding: EdgeInsets.zero,
|
||||
child: Text(
|
||||
text,
|
||||
style: TextStyle(fontSize: fontSize, color: Colors.grey),
|
||||
style: TextStyle(fontSize: fontSize, color: detailtextColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
@ -300,5 +317,46 @@ class ItemListWidget {
|
|||
),
|
||||
);
|
||||
}
|
||||
/// 单行布局:
|
||||
/// 标题 + 文字 + 按钮
|
||||
|
||||
static Widget OneRowButtonTitleText({
|
||||
required String label, // 标题
|
||||
required String text, // 显示内容或提示
|
||||
required VoidCallback? onTap, // 第一行点击回调
|
||||
double fontSize = 15, // 字体大小
|
||||
}) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 12),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(child: Row(
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(fontSize: fontSize, fontWeight: FontWeight.bold),
|
||||
),
|
||||
SizedBox(width: 15,),
|
||||
Expanded(
|
||||
child: Text(
|
||||
text,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(fontSize: fontSize, color: detailtextColor),
|
||||
),
|
||||
),
|
||||
],
|
||||
),),
|
||||
CustomButton(
|
||||
text: "分析详情",
|
||||
height: 30,
|
||||
padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 5),
|
||||
backgroundColor: Colors.green,
|
||||
onPressed: onTap,
|
||||
),
|
||||
],
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,336 +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 '../../../../../../customWidget/bottom_picker.dart';
|
||||
import '../../../../../../http/ApiService.dart';
|
||||
import '../../../../../my_appbar.dart';
|
||||
|
||||
enum EditUserType {
|
||||
analyze('分析单位'),
|
||||
confirm('作业负责人单位'),
|
||||
guardian('监护人单位'),
|
||||
confess('安全交底人单位'),
|
||||
acceptconfess('接受交底人单位'),
|
||||
workstart('作业开始负责人单位'),
|
||||
workend('作业结束负责人单位'),
|
||||
leader('安全管理部门'),
|
||||
audit('审核部门'),
|
||||
approve('动火审批单位'),
|
||||
monitor('动火前在岗部门'),
|
||||
accept('验收部门');
|
||||
|
||||
/// 对应的单位显示名
|
||||
final String displayName;
|
||||
|
||||
const EditUserType(this.displayName);
|
||||
}
|
||||
|
||||
class HotworkApplyDetail extends StatefulWidget {
|
||||
const HotworkApplyDetail({
|
||||
super.key,
|
||||
required this.HOTWORK_ID,
|
||||
required this.flow,
|
||||
});
|
||||
|
||||
final String HOTWORK_ID;
|
||||
final String flow;
|
||||
|
||||
@override
|
||||
State<HotworkApplyDetail> createState() => _HotworkApplyDetailState();
|
||||
}
|
||||
|
||||
class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
|
||||
final bool isEditable = true;
|
||||
/// 编辑还是新增
|
||||
late String msg = 'add';
|
||||
|
||||
// 保存不同环节的单位和负责人
|
||||
final Map<EditUserType, String> _selectedUnitId = {};
|
||||
final Map<EditUserType, String> _selectedUnitName = {};
|
||||
final Map<EditUserType, String> _selectedPersonId = {};
|
||||
final Map<EditUserType, String> _selectedPersonName = {};
|
||||
|
||||
// 存储各单位的人员列表
|
||||
final Map<EditUserType, List<Map<String, dynamic>>> _personCache = {};
|
||||
|
||||
Widget _defaultDetail() {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '申请单位:',
|
||||
isEditable: false,
|
||||
text: '1111',
|
||||
),
|
||||
Divider(),
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '申请人:',
|
||||
isEditable: false,
|
||||
text: '1111',
|
||||
),
|
||||
Divider(),
|
||||
ItemListWidget.multiLineTitleTextField(
|
||||
label: '作业内容:',
|
||||
isEditable: isEditable,
|
||||
text: '1111',
|
||||
),
|
||||
Divider(),
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '动火地点及动火部位:',
|
||||
isEditable: isEditable,
|
||||
text: '1111',
|
||||
),
|
||||
Divider(),
|
||||
ItemListWidget.selectableLineTitleTextField(
|
||||
label: '动火作业级别',
|
||||
isEditable: isEditable,
|
||||
onTap: () {},
|
||||
text: '',
|
||||
),
|
||||
Divider(),
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '动火方式:',
|
||||
isEditable: isEditable,
|
||||
text: '1111',
|
||||
),
|
||||
Divider(),
|
||||
ItemListWidget.twoRowSelectableTitleText(
|
||||
label: '动火人及证书编号:',
|
||||
isEditable: isEditable,
|
||||
text: '1111',
|
||||
),
|
||||
Divider(),
|
||||
ItemListWidget.twoRowButtonTitleText(
|
||||
label: '关联的其他特殊作业及安全作业票编号',
|
||||
isEditable: isEditable,
|
||||
text: '1111',
|
||||
hintText: '请输入关联的其他特殊作业及安全作业票编号',
|
||||
onTap: () {},
|
||||
),
|
||||
Divider(),
|
||||
ItemListWidget.twoRowButtonTitleText(
|
||||
label: '风险辨识结果',
|
||||
isEditable: isEditable,
|
||||
text: '1111',
|
||||
hintText: '请输入风险辨识结果',
|
||||
onTap: () {},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _card(Widget child) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _chooseItem(String unitLabel, String personLabel, EditUserType type) {
|
||||
return Column(
|
||||
children: [
|
||||
ItemListWidget.selectableLineTitleTextField(
|
||||
label: unitLabel,
|
||||
isEditable: isEditable,
|
||||
text: _selectedUnitName[type] ?? '请选择',
|
||||
onTap: () => chooseUnitHandle(type),
|
||||
),
|
||||
Divider(),
|
||||
ItemListWidget.selectableLineTitleTextField(
|
||||
label: personLabel,
|
||||
isEditable: isEditable,
|
||||
text: _selectedPersonName[type] ?? '请选择',
|
||||
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(() {
|
||||
_selectedUnitId[type] = id;
|
||||
_selectedUnitName[type] = name;
|
||||
// 清空已选人员
|
||||
_selectedPersonId.remove(type);
|
||||
_selectedPersonName.remove(type);
|
||||
});
|
||||
// 拉取该单位的人员列表并缓存
|
||||
final result = await ApiService.getListTreePersonList(id);
|
||||
_personCache[type] = List<Map<String, dynamic>>.from(
|
||||
result['userList'] as List,
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 弹出人员选择,需先选择单位
|
||||
void choosePersonHandle(EditUserType type) {
|
||||
final unitId = _selectedUnitId[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(() {
|
||||
_selectedPersonId[type] = userId;
|
||||
_selectedPersonName[type] = name;
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
Future<void> _submit(String STATUS) async {
|
||||
// '1'提交 ‘0’暂存
|
||||
|
||||
|
||||
}
|
||||
/// 初始化拉取数据
|
||||
Future<void> _getData() async {
|
||||
// '1'提交 ‘0’暂存
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: MyAppbar(title: '动火安全作业申请'),
|
||||
body: SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
padding: EdgeInsets.all(12),
|
||||
child: Column(
|
||||
children: [
|
||||
_card(_defaultDetail()),
|
||||
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.acceptconfess),
|
||||
),
|
||||
SizedBox(height: 15),
|
||||
_card(_chooseItem('作业负责人单位', '作业负责人', EditUserType.confirm)),
|
||||
SizedBox(height: 15),
|
||||
_card(_chooseItem('安全管理部门', '所在单位负责人', EditUserType.leader)),
|
||||
SizedBox(height: 15),
|
||||
_card(_chooseItem('动火审批单位', '动火审批负责人', EditUserType.approve)),
|
||||
SizedBox(height: 15),
|
||||
_card(_chooseItem('动火前在岗部门', '动火前在岗班长', EditUserType.monitor)),
|
||||
SizedBox(height: 15),
|
||||
_card(
|
||||
_chooseItem('作业开始负责人单位', '作业开始负责人', EditUserType.workstart),
|
||||
),
|
||||
SizedBox(height: 15),
|
||||
_card(
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
_chooseItem('作业开始负责人单位', '作业开始负责人', EditUserType.workend),
|
||||
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.workend),
|
||||
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),
|
||||
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('1');
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
// TODO: implement initState
|
||||
super.initState();
|
||||
if (widget.HOTWORK_ID.length > 0) {
|
||||
msg = 'edit';
|
||||
_getData();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,714 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:qhd_prevention/customWidget/custom_button.dart';
|
||||
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
|
||||
import 'package:qhd_prevention/customWidget/toast_util.dart';
|
||||
|
||||
import '../../../../../../customWidget/date_picker_dialog.dart';
|
||||
import '../../../../../../http/ApiService.dart';
|
||||
import '../../../../../../tools/tools.dart';
|
||||
import 'hotwork_apply_detail.dart';
|
||||
|
||||
/// 表格组件,用于展示“安全防护措施”列表
|
||||
class MeasuresListWidget extends StatelessWidget {
|
||||
/// 接口返回的原始 Map 列表
|
||||
final List<Map<String, dynamic>> measuresList;
|
||||
|
||||
/// 图片的基础路径
|
||||
final String baseImgPath;
|
||||
|
||||
const MeasuresListWidget({
|
||||
Key? key,
|
||||
required this.measuresList,
|
||||
required this.baseImgPath,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (measuresList.isEmpty) {
|
||||
return const Center(child: Text('暂无更多数据'));
|
||||
}
|
||||
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.only(top: 10, bottom: 20),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 表格容器
|
||||
Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 5),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.grey.shade300),
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: Table(
|
||||
columnWidths: const {
|
||||
0: FlexColumnWidth(3),
|
||||
1: FixedColumnWidth(100),
|
||||
},
|
||||
border: TableBorder(
|
||||
horizontalInside: BorderSide(color: Colors.grey.shade300),
|
||||
verticalInside: BorderSide(color: Colors.grey.shade300),
|
||||
|
||||
),
|
||||
children: [
|
||||
// 表头
|
||||
TableRow(
|
||||
decoration: BoxDecoration(color: Colors.grey.shade100),
|
||||
children: const [
|
||||
Padding(
|
||||
padding: EdgeInsets.all(8),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'主要安全措施',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.all(8),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'操作',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// 数据行
|
||||
for (var item in measuresList)
|
||||
TableRow(
|
||||
children: [
|
||||
// 第一列:措施 + 签名 + 问题答案
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 主要安全措施
|
||||
Text(item['PROTECTIVE_MEASURES'] as String? ?? ''),
|
||||
|
||||
// 签名图片 + 时间
|
||||
if (item.containsKey('SIGN_PATH') &&
|
||||
(item['SIGN_PATH'] as String).isNotEmpty)
|
||||
..._buildImageRows(
|
||||
context,
|
||||
(item['SIGN_PATH'] as String).split(','),
|
||||
item['SIGN_TIME'] as String? ?? '',
|
||||
),
|
||||
|
||||
// 问题1~4 + 答案
|
||||
for (var i = 1; i <= 4; i++)
|
||||
if (item.containsKey('QUESTION$i'))
|
||||
_buildQnA(
|
||||
item['QUESTION$i'] as String? ?? '',
|
||||
item['ANSWER$i'] as String? ?? '0',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// 第二列:状态 + 图片
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Column(
|
||||
children: [
|
||||
// 状态
|
||||
Text(
|
||||
(item['STATUS'] as String?) == '-1'
|
||||
? '不涉及'
|
||||
: '涉及',
|
||||
style: TextStyle(
|
||||
color:
|
||||
(item['STATUS'] as String?) == '-1'
|
||||
? Colors.grey
|
||||
: Colors.black,
|
||||
),
|
||||
),
|
||||
|
||||
// 操作图片
|
||||
if (item.containsKey('IMG_PATH') &&
|
||||
(item['IMG_PATH'] as String).isNotEmpty)
|
||||
..._buildImageRows(
|
||||
context,
|
||||
(item['IMG_PATH'] as String).split(','),
|
||||
'',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 构造“问题 + 答案”行
|
||||
Widget _buildQnA(String question, String answer) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(padding: EdgeInsets.symmetric(horizontal: 12), child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'$question: ',
|
||||
style: const TextStyle(fontWeight: FontWeight.w800),
|
||||
),
|
||||
Text(answer.isNotEmpty ? answer : '0')
|
||||
],
|
||||
),),
|
||||
Divider()
|
||||
],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/// 构造一组图片 + 可选时间文本行
|
||||
List<Widget> _buildImageRows(BuildContext context, List<String> paths, String time) {
|
||||
|
||||
return paths.map((p) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.of(context).push(PageRouteBuilder(
|
||||
opaque: false,
|
||||
pageBuilder: (_, __, ___) => SingleImageViewer(imageUrl: '$baseImgPath$p'),
|
||||
));
|
||||
},
|
||||
child: Image.network(
|
||||
'$baseImgPath$p',
|
||||
width: 80,
|
||||
height: 80,
|
||||
),
|
||||
),
|
||||
if (time.isNotEmpty) ...[const SizedBox(width: 8), Text(time)],
|
||||
],
|
||||
),
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
/// 其他安全防护措施表格组件
|
||||
class OtherMeasuresWidget extends StatelessWidget {
|
||||
/// 其他安全防护措施数据列表
|
||||
final List<dynamic>? otherMeasures;
|
||||
final String baseImgPath;
|
||||
|
||||
const OtherMeasuresWidget({
|
||||
Key? key,
|
||||
required this.otherMeasures,
|
||||
required this.baseImgPath,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final list = (otherMeasures ?? [])
|
||||
.where((e) => e is Map<String, dynamic>)
|
||||
.map((e) => e as Map<String, dynamic>)
|
||||
.toList();
|
||||
if (list.isEmpty) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
|
||||
Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 10),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.grey.shade300),
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: Table(
|
||||
border: TableBorder(
|
||||
horizontalInside: BorderSide(color: Colors.grey.shade300),
|
||||
verticalInside: BorderSide(color: Colors.grey.shade300),
|
||||
),
|
||||
children: [
|
||||
// 表头
|
||||
TableRow(
|
||||
decoration: BoxDecoration(color: Colors.grey.shade100),
|
||||
children: const [
|
||||
Padding(
|
||||
padding: EdgeInsets.all(8),
|
||||
child: Center(
|
||||
child: Text('其他安全措施', style: TextStyle(fontWeight: FontWeight.bold)),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.all(8),
|
||||
child: Center(
|
||||
child: Text('签字', style: TextStyle(fontWeight: FontWeight.bold)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// 数据行
|
||||
for (var item in list)
|
||||
TableRow(
|
||||
children: [
|
||||
// 描述
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Text(item['DESCR'] as String? ?? ''),
|
||||
),
|
||||
// 签字图片
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: _buildSignImages(context, item),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// 处理 SIGN_PATH 可能是 List 或 String
|
||||
Widget _buildSignImages(BuildContext context, Map<String, dynamic> item) {
|
||||
final dynamic raw = item['SIGN_PATH'];
|
||||
List<String> paths = [];
|
||||
if (raw is String && raw.isNotEmpty) {
|
||||
paths = [raw];
|
||||
} else if (raw is List) {
|
||||
paths = raw.cast<String>();
|
||||
}
|
||||
if (paths.isEmpty) return const SizedBox.shrink();
|
||||
return Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
children: paths.map((p) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (_) => SingleImageViewer(imageUrl: '$baseImgPath$p'),
|
||||
));
|
||||
},
|
||||
child: Image.network(
|
||||
'$baseImgPath$p',
|
||||
width: 60,
|
||||
height: 60,
|
||||
errorBuilder: (c, o, s) => const Icon(Icons.broken_image),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
/// 各角色签名展示组件
|
||||
class SignaturesListWidget extends StatelessWidget {
|
||||
final Map<String, dynamic>? signs;
|
||||
final Map<String, dynamic>? pd;
|
||||
final String baseImgPath;
|
||||
const SignaturesListWidget({
|
||||
Key? key,
|
||||
this.signs,
|
||||
this.pd,
|
||||
required this.baseImgPath,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final safeSigns = signs ?? {};
|
||||
final safePd = pd ?? {};
|
||||
return Column(
|
||||
children: [
|
||||
_buildSection(context, '监护人', safeSigns['GUARDIAN'], safePd['GUARDIAN_USER_NAME'], EditUserType.GUARDIAN),
|
||||
_buildSection(context, '安全交底人', safeSigns['CONFESS'], safePd['CONFESS_USER_NAME'], EditUserType.CONFESS),
|
||||
_buildSection(context, '接受交底人', safeSigns['ACCEPT_CONFESS'], safePd['ACCEPT_CONFESS_USER_NAME'], EditUserType.ACCEPT_CONFESS),
|
||||
_buildTextareaWithSigns(context, '作业负责人意见', safeSigns['CONFIRM'], safePd['CONFIRM_USER_NAME'], EditUserType.CONFIRM),
|
||||
_buildTextareaWithSigns(context, '所在单位意见', safeSigns['LEADER'], safePd['LEADER_USER_NAME'], EditUserType.LEADER),
|
||||
_buildTextareaWithSigns(context, '安全管理部门意见', safeSigns['AUDIT'], safePd['AUDIT_USER_NAME'], EditUserType.AUDIT),
|
||||
_buildTextareaWithSigns(context, '动火审批人意见', safeSigns['APPROVE'], safePd['APPROVE_USER_NAME'], EditUserType.APPROVE),
|
||||
_buildTextareaWithSigns(context, '动火前在岗班长意见', safeSigns['MONITOR'], safePd['MONITOR_USER_NAME'], EditUserType.MONITOR),
|
||||
_buildSection(context, '作业开始负责人', safeSigns['WORK_START'], safePd['WORK_START_USER_NAME'], EditUserType.WORK_START),
|
||||
_buildSection(context, '作业结束负责人', safeSigns['WORK_END'], safePd['WORK_END_USER_NAME'], EditUserType.WORK_END),
|
||||
_buildTextareaWithSigns(context, '完工验收', safeSigns['ACCEPT'], safePd['ACCEPT_USER_NAME'], EditUserType.ACCEPT, timeKey: 'ACCEPT_TIME'),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSection(BuildContext context, String title, dynamic rawList, dynamic userName, EditUserType type, {bool showImages = false}) {
|
||||
if (rawList is! List || rawList.isEmpty) return const SizedBox.shrink();
|
||||
final list = rawList.cast<Map<String, dynamic>>();
|
||||
final first = list.first;
|
||||
final name = userName is String ? userName : '';
|
||||
|
||||
// 签字图片和时间
|
||||
final signPaths = <String>[];
|
||||
final signTimes = <String>[];
|
||||
if (first['SIGN_PATH'] != null) {
|
||||
final rawPath = first['SIGN_PATH'];
|
||||
if (rawPath is String && rawPath.isNotEmpty) signPaths.add(rawPath);
|
||||
if (rawPath is List) signPaths.addAll(rawPath.cast<String>());
|
||||
}
|
||||
if (first['SIGN_TIME'] != null) {
|
||||
final rawTime = first['SIGN_TIME'];
|
||||
if (rawTime is String && rawTime.isNotEmpty) signTimes.add(rawTime);
|
||||
if (rawTime is List) signTimes.addAll(rawTime.cast<String>());
|
||||
}
|
||||
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(top: 20),
|
||||
decoration: BoxDecoration(color: Colors.white,border: Border.symmetric(vertical: BorderSide(color: Colors.grey.shade300))),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Text('$title: $name', style: const TextStyle(fontWeight: FontWeight.bold)),
|
||||
),
|
||||
if (showImages && first['IMG_PATH'] is List)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Wrap(
|
||||
spacing: 8,
|
||||
children: (first['IMG_PATH'] as List).cast<String>().map((img) => Image.network('$baseImgPath$img', width: 50, height: 50)).toList(),
|
||||
),
|
||||
),
|
||||
for (var i = 0; i < signPaths.length; i++)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 20),
|
||||
child: Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () => Navigator.of(context).push(MaterialPageRoute(builder: (_) => SingleImageViewer(imageUrl: '$baseImgPath${signPaths[i]}'))),
|
||||
child: Image.network('$baseImgPath${signPaths[i]}', width: 100, height: 100, errorBuilder: (_, __, ___) => const Icon(Icons.broken_image)),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(child: Text(i < signTimes.length ? signTimes[i] : '')),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTextareaWithSigns(BuildContext context, String label, dynamic rawList, dynamic userName, EditUserType type, {String? timeKey}) {
|
||||
if (rawList is! List || rawList.isEmpty) return const SizedBox.shrink();
|
||||
final first = (rawList as List).cast<Map<String, dynamic>>().first;
|
||||
final descr = first['DESCR'] is String ? first['DESCR'] as String : '';
|
||||
final name = pd?['${type.name}_USER_NAME'];
|
||||
final personDes = type.personName;
|
||||
|
||||
|
||||
final signPaths = <String>[];
|
||||
final signTimes = <String>[];
|
||||
if (first['SIGN_PATH'] != null) {
|
||||
final rawPath = first['SIGN_PATH'];
|
||||
if (rawPath is String && rawPath.isNotEmpty) signPaths.add(rawPath);
|
||||
if (rawPath is List) signPaths.addAll(rawPath.cast<String>());
|
||||
}
|
||||
if (first['SIGN_TIME'] != null) {
|
||||
final rawTime = first['SIGN_TIME'];
|
||||
if (rawTime is String && rawTime.isNotEmpty) signTimes.add(rawTime);
|
||||
if (rawTime is List) signTimes.addAll(rawTime.cast<String>());
|
||||
}
|
||||
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(top: 20),
|
||||
decoration: BoxDecoration(color: Colors.white,border: Border.symmetric(vertical: BorderSide(color: Colors.grey.shade300))),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(label, style: const TextStyle(fontWeight: FontWeight.bold)),
|
||||
const SizedBox(height: 4),
|
||||
TextField(controller: TextEditingController(text: descr), maxLines: null, readOnly: true, decoration: const InputDecoration(border: InputBorder.none)),
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Text('$personDes: $name'),
|
||||
),
|
||||
for (var i = 0; i < signPaths.length; i++)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 20),
|
||||
child: Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () => Navigator.of(context).push(MaterialPageRoute(builder: (_) => SingleImageViewer(imageUrl: '$baseImgPath${signPaths[i]}'))),
|
||||
child: Image.network('$baseImgPath${signPaths[i]}', width: 100, height: 100, errorBuilder: (_, __, ___) => const Icon(Icons.broken_image)),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(child: Text(i < signTimes.length ? signTimes[i] : '')),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
///动火安全申请里的’选择其他‘弹窗
|
||||
class SelectionPopup extends StatefulWidget {
|
||||
/// 类型: 'assignments' 或 'identification'
|
||||
final String type;
|
||||
/// 初始选中值,以逗号分隔
|
||||
final String initialValue;
|
||||
/// 确认回调
|
||||
final void Function(String) onConfirm;
|
||||
|
||||
const SelectionPopup({
|
||||
Key? key,
|
||||
required this.type,
|
||||
required this.initialValue,
|
||||
required this.onConfirm,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_SelectionPopupState createState() => _SelectionPopupState();
|
||||
}
|
||||
|
||||
class _SelectionPopupState extends State<SelectionPopup> {
|
||||
late List<Map<String, String>> workList;
|
||||
late String selectedWorkType;
|
||||
late String selectedWorkName;
|
||||
DateTime? selectedDate;
|
||||
List<String> selectValue = [];
|
||||
List<Map<String, dynamic>> list = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// 初始化作业类型列表
|
||||
workList = [
|
||||
{'WORK_TYPE': '', 'WORK_NAME': '作业选择'},
|
||||
{'WORK_TYPE': 'HOTWORK', 'WORK_NAME': '动火作业'},
|
||||
{'WORK_TYPE': 'CONFINEDSPACE', 'WORK_NAME': '受限作业'},
|
||||
{'WORK_TYPE': 'HIGHWORK', 'WORK_NAME': '高处作业'},
|
||||
{'WORK_TYPE': 'ELECTRICITY', 'WORK_NAME': '临时用电'},
|
||||
{'WORK_TYPE': 'BREAKGROUND', 'WORK_NAME': '动土作业'},
|
||||
{'WORK_TYPE': 'HOISTING', 'WORK_NAME': '吊装作业'},
|
||||
{'WORK_TYPE': 'CUTROAD', 'WORK_NAME': '断路作业'},
|
||||
{'WORK_TYPE': 'BLINDBOARD', 'WORK_NAME': '盲板作业'},
|
||||
];
|
||||
selectedWorkType = workList[0]['WORK_TYPE']!;
|
||||
selectedWorkName = workList[0]['WORK_NAME']!;
|
||||
// 初始选中值
|
||||
if (widget.initialValue.isNotEmpty) {
|
||||
selectValue = widget.initialValue.split(',');
|
||||
}
|
||||
// 立即加载数据
|
||||
_getData();
|
||||
}
|
||||
|
||||
Future<void> _pickDate() async {
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder:
|
||||
(_) => HDatePickerDialog(
|
||||
initialDate: DateTime.now(),
|
||||
onCancel: () => Navigator.of(context).pop(),
|
||||
onConfirm: (selected) {
|
||||
Navigator.of(context).pop();
|
||||
setState(() {
|
||||
selectedDate = selected;
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
Future<void> _getData() async {
|
||||
// 构造参数
|
||||
Map<String, dynamic> params;
|
||||
if (widget.type == 'assignments') {
|
||||
params = {
|
||||
'WORK_TYPE': selectedWorkType,
|
||||
'KEYWORDS': selectedDate == null ? '' : selectedDate!.toString().split(' ')[0],
|
||||
'CORPINFO_ID': SessionService.instance.corpinfoId,
|
||||
};
|
||||
} else {
|
||||
params = {
|
||||
'vectors': jsonEncode(['accidentType']),
|
||||
};
|
||||
}
|
||||
try {
|
||||
if (widget.type == 'assignments') {
|
||||
final result = await ApiService.getEightWorkStartList(params);
|
||||
setState(() {
|
||||
list = (result['varList'] as List).cast<Map<String, dynamic>>();
|
||||
for (var item in list) {
|
||||
final type = item['WORK_TYPE'] as String? ?? '';
|
||||
final no = item['CHECK_NO'] as String? ?? '';
|
||||
final prefixMap = {
|
||||
'HOTWORK': '动火作业',
|
||||
'CONFINEDSPACE': '受限作业',
|
||||
'HIGHWORK': '高处作业',
|
||||
'ELECTRICITY': '临时用电',
|
||||
'BREAKGROUND': '动土作业',
|
||||
'HOISTING': '吊装作业',
|
||||
'CUTROAD': '断路作业',
|
||||
'BLINDBOARD': '盲板作业',
|
||||
};
|
||||
item['CHECK_NO'] = (prefixMap[type] ?? '') + ' ' + no;
|
||||
}
|
||||
});
|
||||
|
||||
}else{
|
||||
final result = await ApiService.getEightWorkInfo(params);
|
||||
setState(() {
|
||||
list = (result['accidentType'] as List).cast<Map<String, dynamic>>();
|
||||
});
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
ToastUtil.showError(context, '$e');
|
||||
}
|
||||
}
|
||||
|
||||
void _reset() {
|
||||
setState(() {
|
||||
selectedWorkType = '';
|
||||
selectedWorkName = '请选择';
|
||||
selectedDate = null;
|
||||
list.clear();
|
||||
selectValue.clear();
|
||||
});
|
||||
_getData();
|
||||
}
|
||||
|
||||
void _determine() {
|
||||
// 合并选中
|
||||
final result = selectValue.join(',');
|
||||
widget.onConfirm(result);
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Dialog(
|
||||
insetPadding: const EdgeInsets.symmetric(horizontal: 10, vertical: 40),
|
||||
child: SizedBox(
|
||||
width: double.infinity,
|
||||
height: 800,
|
||||
child: Column(
|
||||
children: [
|
||||
// 筛选栏
|
||||
if (widget.type == 'assignments')
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Row(
|
||||
children: [
|
||||
// 作业类型下拉
|
||||
Expanded(
|
||||
child: DropdownButton<String>(
|
||||
style: TextStyle(),
|
||||
isExpanded: true,
|
||||
value: selectedWorkName,
|
||||
items: workList
|
||||
.map((e) => DropdownMenuItem(
|
||||
value: e['WORK_NAME'],
|
||||
child: Text(e['WORK_NAME']!, style: TextStyle(color: Colors.black87),),
|
||||
))
|
||||
.toList(),
|
||||
onChanged: (v) {
|
||||
final idx = workList.indexWhere((e) => e['WORK_NAME'] == v);
|
||||
if (idx >= 0) {
|
||||
setState(() {
|
||||
selectedWorkType = workList[idx]['WORK_TYPE']!;
|
||||
selectedWorkName = v!;
|
||||
});
|
||||
_getData();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
|
||||
TextButton(onPressed: _pickDate, child: Row(
|
||||
children: [
|
||||
Text(selectedDate == null
|
||||
? '选择作业申请时间'
|
||||
: selectedDate!.toString().split(' ')[0]),
|
||||
SizedBox(width: 5,),
|
||||
Icon(Icons.arrow_drop_down, color: Colors.grey, size: 20,), ],
|
||||
)),
|
||||
|
||||
// 清空
|
||||
CustomButton(text: '清空',padding: EdgeInsets.symmetric(horizontal: 15),height: 35, backgroundColor: Colors.blue, onPressed: _reset,)
|
||||
],
|
||||
),
|
||||
),
|
||||
const Divider(),
|
||||
// 列表多选
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 0),
|
||||
itemCount: list.length,
|
||||
itemBuilder: (c, i) {
|
||||
final item = list[i];
|
||||
final value = selectValue;
|
||||
final key = widget.type == 'assignments'
|
||||
? item['CHECK_NO'] as String? ?? ''
|
||||
: item['NAME'] as String? ?? '';
|
||||
final checked = value.contains(key);
|
||||
return CheckboxListTile(
|
||||
title: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(key),
|
||||
if (widget.type == 'assignments') ...[
|
||||
Text('作业内容: ${item['WORK_CONTENT'] ?? ''}'),
|
||||
Text('作业负责人: ${item['CONFIRM_USER_NAME'] ?? ''}'),
|
||||
Text('作业申请时间: ${item['CREATTIME'] ?? ''}'),
|
||||
],
|
||||
],
|
||||
),
|
||||
value: checked,
|
||||
onChanged: (v) {
|
||||
setState(() {
|
||||
if (v == true)
|
||||
selectValue.add(key);
|
||||
else
|
||||
selectValue.remove(key);
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
// 确定/关闭
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child:CustomButton(text: '确定', height: 40, backgroundColor: Colors.blue, onPressed: _determine,)
|
||||
),
|
||||
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(),)
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
|
||||
class HotSafeWorkChoosePage extends StatefulWidget {
|
||||
const HotSafeWorkChoosePage({super.key});
|
||||
|
||||
@override
|
||||
State<HotSafeWorkChoosePage> createState() => _HotSafeWorkChoosePageState();
|
||||
}
|
||||
|
||||
class _HotSafeWorkChoosePageState extends State<HotSafeWorkChoosePage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: MyAppbar(title: 'dong'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,792 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
|
||||
import 'package:qhd_prevention/customWidget/custom_button.dart';
|
||||
import 'package:qhd_prevention/customWidget/department_person_picker.dart';
|
||||
import 'package:qhd_prevention/customWidget/department_picker.dart';
|
||||
import 'package:qhd_prevention/customWidget/toast_util.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/dh_work_detai/hotwork_gas_list.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
import '../../../../../../customWidget/bottom_picker.dart';
|
||||
import '../../../../../../http/ApiService.dart';
|
||||
import '../../../../../my_appbar.dart';
|
||||
import 'MeasuresListWidget.dart';
|
||||
|
||||
enum EditUserType {
|
||||
ANALYZE('分析单位', '分析单位负责人'),
|
||||
GUARDIAN('监护人单位', '监护人'),
|
||||
CONFESS('安全交底人单位', '安全交底人'),
|
||||
ACCEPT_CONFESS('接受交底人单位', '接受交底人'),
|
||||
CONFIRM('作业负责人单位', '作业负责人'),
|
||||
LEADER('所在单位', '所在单位负责人'),
|
||||
AUDIT('安全管理部门', '安全管理部门负责人'),
|
||||
APPROVE('动火审批单位', '动火审批负责人'),
|
||||
MONITOR('动火前在岗部门', '动火前在岗班长'),
|
||||
WORK_START('作业开始负责人单位', '作业开始负责人'),
|
||||
WORK_END('作业结束负责人单位', '作业结束负责人'),
|
||||
ACCEPT('验收部门', '验收部门负责人');
|
||||
|
||||
/// 对应的单位显示名
|
||||
final String displayName;
|
||||
final String personName;
|
||||
|
||||
const EditUserType(this.displayName, this.personName);
|
||||
}
|
||||
|
||||
class HotworkApplyDetail extends StatefulWidget {
|
||||
const HotworkApplyDetail({
|
||||
super.key,
|
||||
required this.HOTWORK_ID,
|
||||
required this.flow,
|
||||
});
|
||||
|
||||
final String HOTWORK_ID;
|
||||
final String flow;
|
||||
|
||||
@override
|
||||
State<HotworkApplyDetail> createState() => _HotworkApplyDetailState();
|
||||
}
|
||||
|
||||
class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
|
||||
late bool isEditable = false;
|
||||
final levelList = ["特级", "一级", "二级"];
|
||||
|
||||
/// 编辑还是新增
|
||||
late String msg = 'add';
|
||||
|
||||
/// 详情
|
||||
late Map<String, dynamic> pd = {};
|
||||
late Map<String, dynamic> signs = {};
|
||||
late List<Map<String, dynamic>> measuresList = [];
|
||||
|
||||
final TextEditingController _contentController = TextEditingController();
|
||||
final TextEditingController _locationController = TextEditingController();
|
||||
final TextEditingController _methodController = TextEditingController();
|
||||
final TextEditingController _hotworkPersonController =
|
||||
TextEditingController();
|
||||
final TextEditingController _relatedController = TextEditingController();
|
||||
final TextEditingController _riskController = TextEditingController();
|
||||
|
||||
/// 动火人及证书编号
|
||||
late List<dynamic> workUserList = [];
|
||||
|
||||
// 存储各单位的人员列表
|
||||
final Map<EditUserType, List<Map<String, dynamic>>> _personCache = {};
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.HOTWORK_ID.length > 0) {
|
||||
msg = 'edit';
|
||||
_getData();
|
||||
} else {
|
||||
isEditable = true;
|
||||
pd['ANALYZE_TIME'] = 1;
|
||||
pd['APPLY_DEPARTMENT_ID'] = SessionService.instance.deptId;
|
||||
pd['APPLY_DEPARTMENT_NAME'] =
|
||||
SessionService.instance.loginUser!['DEPARTMENT_NAME'] ?? '';
|
||||
pd['APPLY_USER_ID'] = SessionService.instance.loginUserId;
|
||||
pd['APPLY_USER_NAME'] = SessionService.instance.username;
|
||||
}
|
||||
_getHotWorkNameList();
|
||||
|
||||
_contentController.addListener(() {
|
||||
setState(() {
|
||||
pd['WORK_CONTENT'] = _contentController.text.trim();
|
||||
});
|
||||
});
|
||||
_locationController.addListener(() {
|
||||
pd['WORK_PLACE'] = _locationController.text.trim();
|
||||
});
|
||||
_methodController.addListener(() {
|
||||
pd['WORK_FUNCTION'] = _methodController.text.trim();
|
||||
});
|
||||
_hotworkPersonController.addListener(() {
|
||||
pd['WORK_USER'] = _hotworkPersonController.text.trim();
|
||||
});
|
||||
_relatedController.addListener(() {
|
||||
pd['SPECIAL_WORK'] = _relatedController.text.trim();
|
||||
});
|
||||
_riskController.addListener(() {
|
||||
pd['RISK_IDENTIFICATION'] = _riskController.text.trim();
|
||||
});
|
||||
}
|
||||
|
||||
void set_pd_DEPARTMENT_ID(EditUserType type, String id) {
|
||||
pd['${type.name}_DEPARTMENT_ID'] = id;
|
||||
}
|
||||
|
||||
void set_pd_DEPARTMENT_NAME(EditUserType type, String name) {
|
||||
pd['${type.name}_DEPARTMENT_NAME'] = name;
|
||||
}
|
||||
|
||||
void set_pd_USER_ID(EditUserType type, String id) {
|
||||
pd['${type.name}_USER_ID'] = id;
|
||||
}
|
||||
|
||||
void set_pd_USER_Name(EditUserType type, String name) {
|
||||
pd['${type.name}_USER_NAME'] = name;
|
||||
}
|
||||
|
||||
String get_pd_DEPARTMENT_ID(EditUserType type) {
|
||||
return pd['${type.name}_DEPARTMENT_ID'] ?? '';
|
||||
}
|
||||
|
||||
String get_pd_DEPARTMENT_NAME(EditUserType type) {
|
||||
return pd['${type.name}_DEPARTMENT_NAME'] ?? '';
|
||||
}
|
||||
|
||||
String get_pd_USER_ID(EditUserType type) {
|
||||
return pd['${type.name}_USER_ID'] ?? '';
|
||||
}
|
||||
|
||||
String get_pd_USER_Name(EditUserType type) {
|
||||
return pd['${type.name}_USER_NAME'] ?? '';
|
||||
}
|
||||
|
||||
Future<void> _chooseLevel() async {
|
||||
final choice = await BottomPicker.show<String>(
|
||||
context,
|
||||
items: levelList,
|
||||
itemBuilder: (item) => Text(item, textAlign: TextAlign.center),
|
||||
initialIndex: 0,
|
||||
);
|
||||
if (choice != null) {
|
||||
// 用户点击确定并选择了 choice
|
||||
setState(() {
|
||||
pd['WORK_LEVEL'] = choice;
|
||||
FocusHelper.clearFocus(context);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _chooseHorkUser() async{
|
||||
|
||||
final choice = await BottomPicker.show<String>(
|
||||
context,
|
||||
items: workUserList.map((item) => item['NAME'] as String).toList(),
|
||||
itemBuilder: (item) => Text(item, textAlign: TextAlign.center),
|
||||
initialIndex: 0,
|
||||
);
|
||||
if (choice != null) {
|
||||
setState(() {
|
||||
pd['WORK_USER'] = choice;
|
||||
_hotworkPersonController.text = choice;
|
||||
Map<String, dynamic> result = workUserList.firstWhere(
|
||||
(item) => item['NAME'] == choice,
|
||||
orElse: () => {}, // 避免找不到时报错
|
||||
);
|
||||
if (FormUtils.hasValue(result, 'USER_ID')) {
|
||||
pd['WORK_USER_ID'] = result['USER_ID'];
|
||||
}
|
||||
FocusHelper.clearFocus(context);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Widget _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;
|
||||
});
|
||||
},
|
||||
),
|
||||
).then((_) {
|
||||
FocusHelper.clearFocus(context);
|
||||
});
|
||||
// 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;
|
||||
});
|
||||
},
|
||||
),
|
||||
).then((_) {
|
||||
FocusHelper.clearFocus(context);
|
||||
|
||||
});
|
||||
},
|
||||
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) {
|
||||
FocusHelper.clearFocus(context);
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
barrierColor: Colors.black54,
|
||||
backgroundColor: Colors.transparent,
|
||||
builder:
|
||||
(_) => DepartmentPicker(
|
||||
onSelected: (id, name) async {
|
||||
setState(() {
|
||||
set_pd_DEPARTMENT_ID(type, id);
|
||||
set_pd_DEPARTMENT_NAME(type, name);
|
||||
set_pd_USER_ID(type, '');
|
||||
set_pd_USER_Name(type, '');
|
||||
});
|
||||
_getPersonListForUnitId(id, type);
|
||||
},
|
||||
),
|
||||
).then((_) {
|
||||
FocusHelper.clearFocus(context);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _getPersonListForUnitId(String id, EditUserType type) async {
|
||||
// 拉取该单位的人员列表并缓存
|
||||
final result = await ApiService.getListTreePersonList(id);
|
||||
setState(() {
|
||||
_personCache[type] = List<Map<String, dynamic>>.from(
|
||||
result['userList'] as List,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/// 弹出人员选择,需先选择单位
|
||||
void choosePersonHandle(EditUserType type) async{
|
||||
FocusHelper.clearFocus(context);
|
||||
|
||||
String unitId = get_pd_DEPARTMENT_ID(type);
|
||||
final personList = _personCache[type] ?? [];
|
||||
if (!unitId.isNotEmpty) {
|
||||
final unitName = type.displayName;
|
||||
ToastUtil.showNormal(context, '请先选择$unitName');
|
||||
return;
|
||||
}
|
||||
if (personList.isEmpty) { // 一般这种情况是因为重新编辑没有缓存对应部门的负责人,所以先拉取一下接口
|
||||
await _getPersonListForUnitId(unitId, type);
|
||||
final list = _personCache[type] ?? [];
|
||||
|
||||
if (list.isEmpty) { // 如果还是没数据,说明该部门没有可选的人
|
||||
ToastUtil.showNormal(context, '暂无数据,请选择其他单位');
|
||||
}else{
|
||||
choosePersonHandle(type);
|
||||
}
|
||||
return;
|
||||
}
|
||||
DepartmentPersonPicker.show(
|
||||
context,
|
||||
personsData: personList,
|
||||
onSelected: (userId, name) {
|
||||
setState(() {
|
||||
set_pd_USER_ID(type, userId);
|
||||
set_pd_USER_Name(type, name);
|
||||
});
|
||||
},
|
||||
).then((_) {
|
||||
FocusHelper.clearFocus(context);
|
||||
});
|
||||
}
|
||||
|
||||
/// 提交 1 提交 0暂存
|
||||
Future<void> _submit(String status) async {
|
||||
// 通用文本字段校验规则
|
||||
final textRules = <Map<String, dynamic>>[
|
||||
{'value': _contentController.text.trim(), 'message': '请填写作业内容'},
|
||||
{'value': _locationController.text.trim(), 'message': '请填写动火地点及部位'},
|
||||
{'value': _methodController.text.trim(), 'message': '请填写动火方式'},
|
||||
{'value': _hotworkPersonController.text.trim(), 'message': '请填写动火人及证书编号'},
|
||||
{
|
||||
'value': _relatedController.text.trim(),
|
||||
'message': '请输入关联的其他特殊作业及安全作业票编号',
|
||||
},
|
||||
{'value': _riskController.text.trim(), 'message': '请填写风险辨识结果'},
|
||||
];
|
||||
final level = pd['WORK_LEVEL'] ?? '';
|
||||
print('---level-$level');
|
||||
/// 各项负责人校验
|
||||
final unitRules = <EditUserType>[
|
||||
EditUserType.ANALYZE,
|
||||
EditUserType.GUARDIAN,
|
||||
EditUserType.CONFESS,
|
||||
EditUserType.ACCEPT_CONFESS,
|
||||
EditUserType.CONFIRM,
|
||||
EditUserType.LEADER,
|
||||
EditUserType.AUDIT,
|
||||
EditUserType.APPROVE,
|
||||
EditUserType.MONITOR,
|
||||
EditUserType.WORK_START,
|
||||
EditUserType.WORK_END,
|
||||
EditUserType.ACCEPT,
|
||||
];
|
||||
if (status == '1') {
|
||||
// 文本校验
|
||||
for (var rule in textRules) {
|
||||
if ((rule['value'] as String).isEmpty) {
|
||||
ToastUtil.showNormal(context, rule['message']);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 级别校验
|
||||
if (level.length == 0) {
|
||||
ToastUtil.showNormal(context, '请选择动火级别');
|
||||
return;
|
||||
}
|
||||
|
||||
for (var type in unitRules) {
|
||||
if (get_pd_DEPARTMENT_ID(type).length == 0) {
|
||||
ToastUtil.showNormal(context, '请选择${type.displayName}');
|
||||
return;
|
||||
}
|
||||
if (get_pd_USER_ID(type).length == 0) {
|
||||
ToastUtil.showNormal(context, '请选择${type.displayName}负责人');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// LoadingDialogHelper.show(context);
|
||||
|
||||
String taskId = '0';
|
||||
if (level == '特级') {
|
||||
taskId = '1';
|
||||
} else if (level == '一级') {
|
||||
taskId = '2';
|
||||
} else if (level == '二级') {
|
||||
taskId = '3';
|
||||
}
|
||||
|
||||
// 提交参数
|
||||
if (msg == 'add') {
|
||||
pd['CORPINFO_ID'] = SessionService.instance.corpinfoId;
|
||||
pd['CREATOR'] = SessionService.instance.loginUserId;
|
||||
pd['OPERATOR'] = SessionService.instance.loginUserId;
|
||||
pd['ACTION_USER'] = SessionService.instance.username;
|
||||
pd['APPLY_STATUS'] = status;
|
||||
pd['STEP_ID'] = status;
|
||||
pd['TASK_ID'] = taskId;
|
||||
pd['HOTWORK_ID'] = widget.HOTWORK_ID;
|
||||
pd['APPLY_DEPARTMENT_ID'] = SessionService.instance.deptId;
|
||||
pd['APPLY_DEPARTMENT_NAME'] = SessionService.instance.loginUser?['DEPARTMENT_NAME'] ?? '';
|
||||
pd['APPLY_USER_ID'] = SessionService.instance.loginUserId;
|
||||
pd['APPLY_USER_NAME'] = SessionService.instance.username;
|
||||
pd['USER_ID'] = SessionService.instance.loginUserId;
|
||||
|
||||
}
|
||||
|
||||
LoadingDialogHelper.show(context);
|
||||
String jsonStr = jsonEncode(pd);
|
||||
printLongString(jsonStr);
|
||||
try {
|
||||
String url = "/app/hotwork/" + msg;
|
||||
final result = await ApiService.submitHotwork(url, pd);
|
||||
LoadingDialogHelper.hide(context);
|
||||
if (result['result'] == 'success') {
|
||||
ToastUtil.showSuccess(context, status == '1' ? '提交成功' : '已暂存');
|
||||
Navigator.pop(context);
|
||||
}
|
||||
} catch (e) {
|
||||
LoadingDialogHelper.hide(context);
|
||||
ToastUtil.showNormal(context, '操作失败:$e');
|
||||
}
|
||||
}
|
||||
void printLongString(String text, {int chunkSize = 800}) {
|
||||
final pattern = RegExp('.{1,$chunkSize}'); // 每 chunkSize 个字符一组
|
||||
for (final match in pattern.allMatches(text)) {
|
||||
print(match.group(0));
|
||||
}
|
||||
}
|
||||
Future<void> _getHotWorkNameList() async {
|
||||
final result = await ApiService.getHotWorkNameList();
|
||||
setState(() {
|
||||
workUserList = result['varList'] ?? '';
|
||||
List<String> names = workUserList.map((item) => item['NAME'] as String).toList();
|
||||
|
||||
});
|
||||
}
|
||||
/// 初始化拉取数据
|
||||
Future<void> _getData() async {
|
||||
final data = await ApiService.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,188 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
|
||||
import 'package:qhd_prevention/customWidget/toast_util.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/home_gas_test_page.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:photo_view/photo_view.dart';
|
||||
import 'package:photo_view/photo_view_gallery.dart';
|
||||
|
||||
import '../../../../../../customWidget/single_image_viewer.dart';
|
||||
import '../../../../../../tools/tools.dart';
|
||||
|
||||
/// 气体分析详情
|
||||
class HotworkGasList extends StatefulWidget {
|
||||
const HotworkGasList({
|
||||
super.key,
|
||||
required this.HOTWORK_ID,
|
||||
this.addFlag = false,
|
||||
});
|
||||
|
||||
final String HOTWORK_ID;
|
||||
final bool addFlag;
|
||||
|
||||
@override
|
||||
State<HotworkGasList> createState() => _HotworkGasListState();
|
||||
}
|
||||
|
||||
class _HotworkGasListState extends State<HotworkGasList> {
|
||||
List list = [];
|
||||
bool isLoading = true;
|
||||
Future<void> _getListData() async {
|
||||
final data = await ApiService.hotworkGasList(widget.HOTWORK_ID);
|
||||
setState(() {
|
||||
list = data['varList'] ?? [];
|
||||
isLoading = false;
|
||||
});
|
||||
}
|
||||
|
||||
void _deleteItem(String id) async {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
builder:
|
||||
(_) => CustomAlertDialog(
|
||||
title: '温馨提示',
|
||||
content: '确定要删除这条记录?',
|
||||
cancelText: '取消',
|
||||
onCancel: () {},
|
||||
onConfirm: () async {
|
||||
final result = await ApiService.hotworkGasDelete(id);
|
||||
if (result['result']) {
|
||||
ToastUtil.showNormal(context, '删除成功');
|
||||
_getListData();
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
Widget _buildListItem(Map item) {
|
||||
final images = (item['SIGN_PATH'] as String?)?.split(',') ?? [];
|
||||
final baseImgPath = ApiService.baseImgPath;
|
||||
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
margin: const EdgeInsets.symmetric(vertical: 5, horizontal: 5),
|
||||
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('分析时间: ${item['ANALYZE_TIME'] ?? ''}'),
|
||||
Text('代表性气体: ${item['ANALYZE_GAS'] ?? ''}'),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('分析数据: ${item['ANALYZE_RESULT'] ?? ''}'),
|
||||
if ((item['ANALYZE_PLACE'] ?? '').toString().isNotEmpty)
|
||||
Text('分析地点: ${item['ANALYZE_PLACE']}'),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const Text('分析人:'),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 4,
|
||||
children: List.generate(images.length, (i) {
|
||||
final img = baseImgPath + images[i];
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
present(
|
||||
SingleImageViewer(imageUrl: img),
|
||||
context,
|
||||
);
|
||||
},
|
||||
child: Image.network(
|
||||
img,
|
||||
width: 50,
|
||||
height: 30,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
if (widget.addFlag)
|
||||
TextButton(
|
||||
onPressed: () =>
|
||||
_deleteItem(item['HOTWORKGAS_ID'].toString()),
|
||||
style: TextButton.styleFrom(
|
||||
backgroundColor: Colors.red,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
minimumSize: const Size(0, 32),
|
||||
),
|
||||
child: const Text(
|
||||
'删除',
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildListContent() {
|
||||
if (isLoading) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
if (list.isEmpty) {
|
||||
return NoDataWidget.show();
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
itemCount: list.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = list[index];
|
||||
return _buildListItem(item);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_getListData();
|
||||
}
|
||||
void _pyshAddGas() async {
|
||||
await pushPage(HomeGasTestPage(HOTWORK_ID: widget.HOTWORK_ID,), context);
|
||||
_getListData();
|
||||
|
||||
}
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: MyAppbar(
|
||||
title: '气体分析详情',
|
||||
actions: [
|
||||
if (widget.addFlag)
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
_pyshAddGas();
|
||||
},
|
||||
child: const Text('添加', style: TextStyle(color: Colors.white, fontSize: 16)),
|
||||
)
|
||||
],
|
||||
),
|
||||
body: _buildListContent(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,280 @@
|
|||
import 'dart:io';
|
||||
import 'package:dotted_line/dotted_line.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:qhd_prevention/customWidget/custom_button.dart';
|
||||
import 'package:qhd_prevention/customWidget/toast_util.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.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';
|
||||
import 'package:qhd_prevention/pages/mine/mine_sign_page.dart';
|
||||
|
||||
import '../../../../../customWidget/custom_alert_dialog.dart';
|
||||
import '../../../../../customWidget/picker/CupertinoDatePicker.dart';
|
||||
|
||||
class HomeGasTestPage extends StatefulWidget {
|
||||
const HomeGasTestPage({Key? key, required this.HOTWORK_ID}) : super(key: key);
|
||||
|
||||
final String HOTWORK_ID;
|
||||
|
||||
@override
|
||||
_HomeGasTestPageState createState() => _HomeGasTestPageState();
|
||||
}
|
||||
|
||||
class _HomeGasTestPageState extends State<HomeGasTestPage> {
|
||||
String _selectData = '';
|
||||
List<String> imagePaths = [];
|
||||
List<String> signTimes = []; // 签字时间列表
|
||||
|
||||
final TextEditingController _gasController = TextEditingController();
|
||||
final TextEditingController _resultController = TextEditingController();
|
||||
final TextEditingController _addressController = TextEditingController();
|
||||
bool _loading = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
Future<void> _chooseDatePicker() async {
|
||||
DateTime? picked = await BottomDateTimePicker.show(context);
|
||||
if (picked != null) {
|
||||
setState(() {
|
||||
_selectData = DateFormat('yyyy-MM-dd HH:mm').format(picked);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Widget _signListWidget() {
|
||||
return Column(
|
||||
children: imagePaths.map((path) {
|
||||
return Column(
|
||||
children: [
|
||||
const SizedBox(height: 10),
|
||||
const DottedLine(
|
||||
dashLength: 6.0,
|
||||
dashGapLength: 4.0,
|
||||
lineThickness: 0.5,
|
||||
dashColor: Colors.grey,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Image.file(
|
||||
File(path),
|
||||
width: 200,
|
||||
height: 150,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
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(),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _submit(int status) async {
|
||||
if (imagePaths.isEmpty) {
|
||||
ToastUtil.showNormal(context, '请签字');
|
||||
return;
|
||||
}
|
||||
if (status == 1) {
|
||||
if (_selectData.isEmpty || _gasController.text.isEmpty || _resultController.text.isEmpty || _addressController.text.isEmpty) {
|
||||
ToastUtil.showNormal(context, '请完善所有字段');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
String reasonText = '';
|
||||
if (status != 1) {
|
||||
await showDialog<String>(
|
||||
context: context,
|
||||
builder: (_) => CustomAlertDialog(
|
||||
title: '作废原因',
|
||||
mode: DialogMode.input,
|
||||
hintText: '请输入作废原因',
|
||||
cancelText: '取消',
|
||||
confirmText: '确定',
|
||||
onInputConfirm: (text) {
|
||||
reasonText = text;
|
||||
},
|
||||
),
|
||||
);
|
||||
if (reasonText.isEmpty) {
|
||||
ToastUtil.showNormal(context, '请填写作废原因');
|
||||
return;
|
||||
}
|
||||
}
|
||||
bool isConfirm = false;
|
||||
await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (_) => CustomAlertDialog(
|
||||
title: '请确认',
|
||||
content: status == 1 ? '通过本作业票?' : '作废本作业票?',
|
||||
onConfirm: () {
|
||||
isConfirm = true;
|
||||
},
|
||||
),
|
||||
);
|
||||
if (isConfirm != true) return;
|
||||
|
||||
setState(() => _loading = true);
|
||||
|
||||
final formData = {
|
||||
'HOTWORK_ID': widget.HOTWORK_ID,
|
||||
'ANALYZE_TIME': _selectData,
|
||||
'ANALYZE_GAS': _gasController.text,
|
||||
'ANALYZE_RESULT': _resultController.text,
|
||||
'ANALYZE_PLACE': _addressController.text,
|
||||
'ANALYZE_USER': SessionService.instance.username,
|
||||
'APPLY_STATUS': status,
|
||||
'STEP_REASON': reasonText ?? '',
|
||||
'SIGNTIME':signTimes.join(','),
|
||||
'CORPINFO_ID': SessionService.instance.corpinfoId,
|
||||
'USER_ID': SessionService.instance.loginUserId,
|
||||
};
|
||||
|
||||
try {
|
||||
await ApiService.saveGasTest(formData, imagePaths);
|
||||
ToastUtil.showNormal(context, status == 1 ? '保存成功' : '作废成功');
|
||||
Navigator.of(context).pop(status == 1);
|
||||
} catch (e) {
|
||||
ToastUtil.showNormal(context, e.toString());
|
||||
} finally {
|
||||
setState(() => _loading = false);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> setRequest() async {
|
||||
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: MyAppbar(title: '气体检测'),
|
||||
body: _loading
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(5),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
ItemListWidget.selectableLineTitleTextField(
|
||||
label: '分析时间',
|
||||
isEditable: true,
|
||||
text: _selectData,
|
||||
onTap: _chooseDatePicker,
|
||||
),
|
||||
const Divider(),
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '代表性气体:',
|
||||
hintText: '请输入代表性气体',
|
||||
isEditable: true,
|
||||
controller: _gasController,
|
||||
),
|
||||
const Divider(),
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '分析结果:',
|
||||
isEditable: true,
|
||||
controller: _resultController,
|
||||
),
|
||||
const Divider(),
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '分析地点:',
|
||||
isEditable: true,
|
||||
controller: _addressController,
|
||||
),
|
||||
const Divider(),
|
||||
ItemListWidget.singleLineTitleText(
|
||||
label: '分析人:',
|
||||
isEditable: false,
|
||||
text: SessionService.instance.username,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
CustomButton(
|
||||
text: '新增手写签字',
|
||||
height: 40,
|
||||
backgroundColor: Colors.blue,
|
||||
onPressed: _sign,
|
||||
),
|
||||
],
|
||||
),
|
||||
if (imagePaths.isNotEmpty) _signListWidget(),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CustomButton(
|
||||
text: '作废',
|
||||
backgroundColor: Colors.red,
|
||||
onPressed: () => _submit(-1),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
Expanded(
|
||||
child: CustomButton(
|
||||
text: '保存',
|
||||
backgroundColor: Colors.blue,
|
||||
onPressed: () => _submit(1),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,744 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
|
||||
import 'package:qhd_prevention/customWidget/custom_button.dart';
|
||||
import 'package:qhd_prevention/customWidget/department_person_picker.dart';
|
||||
import 'package:qhd_prevention/customWidget/department_picker.dart';
|
||||
import 'package:qhd_prevention/customWidget/toast_util.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/dh_work_detai/hotwork_gas_list.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';
|
||||
|
||||
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,186 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
|
||||
import 'package:qhd_prevention/customWidget/toast_util.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:photo_view/photo_view.dart';
|
||||
import 'package:photo_view/photo_view_gallery.dart';
|
||||
|
||||
import '../../../../../../customWidget/single_image_viewer.dart';
|
||||
import '../../../../../../tools/tools.dart';
|
||||
|
||||
/// 气体分析详情
|
||||
class HotworkGasList extends StatefulWidget {
|
||||
const HotworkGasList({
|
||||
super.key,
|
||||
required this.HOTWORK_ID,
|
||||
this.addFlag = false,
|
||||
});
|
||||
|
||||
final String HOTWORK_ID;
|
||||
final bool addFlag;
|
||||
|
||||
@override
|
||||
State<HotworkGasList> createState() => _HotworkGasListState();
|
||||
}
|
||||
|
||||
class _HotworkGasListState extends State<HotworkGasList> {
|
||||
List list = [];
|
||||
bool isLoading = true;
|
||||
Future<void> _getListData() async {
|
||||
final data = await ApiService.hotworkGasList(widget.HOTWORK_ID);
|
||||
setState(() {
|
||||
list = data['varList'] ?? [];
|
||||
isLoading = false;
|
||||
});
|
||||
}
|
||||
|
||||
void _deleteItem(String id) async {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
builder:
|
||||
(_) => CustomAlertDialog(
|
||||
title: '温馨提示',
|
||||
content: '确定要删除这条记录?',
|
||||
cancelText: '取消',
|
||||
onCancel: () {},
|
||||
onConfirm: () async {
|
||||
final result = await ApiService.hotworkGasDelete(id);
|
||||
if (result['result']) {
|
||||
ToastUtil.showNormal(context, '删除成功');
|
||||
_getListData();
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
Widget _buildListItem(Map item) {
|
||||
final images = (item['SIGN_PATH'] as String?)?.split(',') ?? [];
|
||||
final baseImgPath = ApiService.baseImgPath;
|
||||
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
margin: const EdgeInsets.symmetric(vertical: 5, horizontal: 5),
|
||||
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('分析时间: ${item['ANALYZE_TIME'] ?? ''}'),
|
||||
Text('代表性气体: ${item['ANALYZE_GAS'] ?? ''}'),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('分析数据: ${item['ANALYZE_RESULT'] ?? ''}'),
|
||||
if ((item['ANALYZE_PLACE'] ?? '').toString().isNotEmpty)
|
||||
Text('分析地点: ${item['ANALYZE_PLACE']}'),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const Text('分析人:'),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 4,
|
||||
children: List.generate(images.length, (i) {
|
||||
final img = baseImgPath + images[i];
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
present(
|
||||
SingleImageViewer(imageUrl: img),
|
||||
context,
|
||||
);
|
||||
},
|
||||
child: Image.network(
|
||||
img,
|
||||
width: 50,
|
||||
height: 30,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
if (widget.addFlag)
|
||||
TextButton(
|
||||
onPressed: () =>
|
||||
_deleteItem(item['HOTWORKGAS_ID'].toString()),
|
||||
style: TextButton.styleFrom(
|
||||
backgroundColor: Colors.red,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
minimumSize: const Size(0, 32),
|
||||
),
|
||||
child: const Text(
|
||||
'删除',
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildListContent() {
|
||||
if (isLoading) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
if (list.isEmpty) {
|
||||
return NoDataWidget.show();
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
itemCount: list.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = list[index];
|
||||
return _buildListItem(item);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_getListData();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: MyAppbar(
|
||||
title: '气体分析详情',
|
||||
actions: [
|
||||
if (widget.addFlag)
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
'/hotworkGasDetail',
|
||||
arguments: {'HOTWORK_ID': widget.HOTWORK_ID},
|
||||
).then((_) => _getListData());
|
||||
},
|
||||
child: const Text('添加', style: TextStyle(color: Colors.white)),
|
||||
)
|
||||
],
|
||||
),
|
||||
body: _buildListContent(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +1,24 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/dh_Wrok/dh_work_detai/hotwork_apply_detail.dart';
|
||||
import 'package:qhd_prevention/customWidget/toast_util.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/dh_work_detai/hotwork_apply_detail.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
import '../../../../../customWidget/bottom_picker.dart';
|
||||
import '../../../../../customWidget/custom_button.dart';
|
||||
import '../../../../../customWidget/search_bar_widget.dart';
|
||||
import '../../../../../http/ApiService.dart';
|
||||
import '../special_Wrok/dh_work_detai/hotwork_gas_list.dart';
|
||||
|
||||
class DhWorkListPage extends StatefulWidget {
|
||||
class SpecialWorkListPage extends StatefulWidget {
|
||||
final String flow;
|
||||
|
||||
const DhWorkListPage({Key? key, required this.flow}) : super(key: key);
|
||||
const SpecialWorkListPage({Key? key, required this.flow}) : super(key: key);
|
||||
|
||||
@override
|
||||
_DhWorkListPageState createState() => _DhWorkListPageState();
|
||||
_SpecialWorkListPageState createState() => _SpecialWorkListPageState();
|
||||
}
|
||||
|
||||
class _DhWorkListPageState extends State<DhWorkListPage> {
|
||||
class _SpecialWorkListPageState extends State<SpecialWorkListPage> {
|
||||
// Data and state variables
|
||||
List<dynamic> list = [];
|
||||
int currentPage = 1;
|
||||
|
|
@ -118,15 +120,14 @@ class _DhWorkListPageState extends State<DhWorkListPage> {
|
|||
// 处理申请按钮点击逻辑
|
||||
pushPage(HotworkApplyDetail(HOTWORK_ID: '', flow: widget.flow), context);
|
||||
}
|
||||
|
||||
/// 打开流程图
|
||||
Future<void> _openFlowDrawer(String hotworkId) async {
|
||||
try {
|
||||
final response = await ApiService.dhGetFlowList(hotworkId);
|
||||
final List<dynamic>? newFlow = response['flowList'];
|
||||
if (newFlow == null || newFlow.isEmpty) {
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(SnackBar(content: Text('暂无流程图数据')));
|
||||
ToastUtil.showNormal(context, '暂无流程图数据');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -179,15 +180,16 @@ class _DhWorkListPageState extends State<DhWorkListPage> {
|
|||
}
|
||||
}
|
||||
|
||||
void _goToDetail(Map<String, dynamic> item) {
|
||||
void _goToDetail(Map<String, dynamic> item) async {
|
||||
final Map<String, dynamic> data = {'HOTWORK_ID': item['HOTWORK_ID'], 'flow': widget.flow};
|
||||
String routeName = '';
|
||||
switch (widget.flow) {
|
||||
case '提交申请':
|
||||
pushPage(HotworkApplyDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
|
||||
await pushPage(HotworkApplyDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
|
||||
_fetchData();
|
||||
break;
|
||||
case '气体检测':
|
||||
routeName = '/gas-list';
|
||||
pushPage(HotworkGasList(HOTWORK_ID: item['HOTWORK_ID'], addFlag:true), context);
|
||||
break;
|
||||
case '设置安全措施确认人':
|
||||
routeName = '/hotwork-measures-detail';
|
||||
|
|
@ -323,53 +325,50 @@ class _DhWorkListPageState extends State<DhWorkListPage> {
|
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text("编号: ${item['CHECK_NO'] ?? ''}", style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),),
|
||||
Text("作业级别: ${item['WORK_LEVEL']}", style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),),
|
||||
Text("作业级别: ${item['WORK_LEVEL'] ?? ''}", style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text("申请人: ${item['APPLY_USER_NAME']}"),
|
||||
Text("分析人: ${item['ANALYZE_USER_NAME']}"),
|
||||
Text("申请人: ${item['APPLY_USER_NAME'] ?? ''}"),
|
||||
Text("分析人: ${item['ANALYZE_USER_NAME'] ?? ''}"),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text("监护人: ${item['GUARDIAN_USER_NAME']}"),
|
||||
Text("批准人: ${item['APPROVE_USER_NAME']}"),
|
||||
Text("监护人: ${item['GUARDIAN_USER_NAME'] ?? ''}"),
|
||||
Text("批准人: ${item['APPROVE_USER_NAME'] ?? ''}"),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
if (item['CONFESS_USER_NAME'] != null)
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text("安全交底人: ${item['CONFESS_USER_NAME']}"),
|
||||
Text("接受交底人: ${item['ACCEPT_CONFESS_USER_NAME']}"),
|
||||
Text("安全交底人: ${item['CONFESS_USER_NAME'] ?? ''}"),
|
||||
Text("接受交底人: ${item['ACCEPT_CONFESS_USER_NAME'] ?? ''}"),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
if (item['CONFIRM_USER_NAME'] != null)
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text("作业负责人: ${item['CONFIRM_USER_NAME']}"),
|
||||
Text("动火点负责人: ${item['LEADER_USER_NAME']}"),
|
||||
Text("作业负责人: ${item['CONFIRM_USER_NAME'] ?? ''}"),
|
||||
Text("动火点负责人: ${item['LEADER_USER_NAME'] ?? ''}"),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
if (item['AUDIT_USER_NAME'] != null)
|
||||
Text("安全管理部门负责人: ${item['AUDIT_USER_NAME']}"),
|
||||
Text("安全管理部门负责人: ${item['AUDIT_USER_NAME'] ?? ''}"),
|
||||
const SizedBox(height: 8),
|
||||
if (item['MONITOR_USER_NAME'] != null)
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text("动火前在岗班长: ${item['MONITOR_USER_NAME']}"),
|
||||
Text("验收部门负责人: ${item['ACCEPT_USER_NAME']}"),
|
||||
Text("动火前在岗班长: ${item['MONITOR_USER_NAME'] ?? ''}"),
|
||||
Text("验收部门负责人: ${item['ACCEPT_USER_NAME'] ?? ''}"),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
|
|
@ -424,7 +423,7 @@ class _DhWorkListPageState extends State<DhWorkListPage> {
|
|||
}
|
||||
}
|
||||
|
||||
// 新添加的方法:显示底部选择器
|
||||
// 显示底部选择器
|
||||
Future<void> _showStepPicker() async {
|
||||
if (stepList.isEmpty) {
|
||||
ScaffoldMessenger.of(
|
||||
|
|
@ -462,14 +461,13 @@ class _DhWorkListPageState extends State<DhWorkListPage> {
|
|||
}
|
||||
}
|
||||
|
||||
// 添加这个方法
|
||||
Widget _buildListContent() {
|
||||
if (isLoading && list.isEmpty) {
|
||||
// 初始加载时显示居中的加载指示器
|
||||
return Center(child: CircularProgressIndicator());
|
||||
} else if (list.isEmpty) {
|
||||
// 没有数据
|
||||
return Center(child: Text('暂无数据'));
|
||||
return NoDataWidget.show();
|
||||
} else {
|
||||
// 有数据或加载更多
|
||||
return ListView.builder(
|
||||
|
|
@ -595,7 +593,6 @@ class _DhWorkListPageState extends State<DhWorkListPage> {
|
|||
flex: 2,
|
||||
child: SearchBarWidget(
|
||||
showResetButton: false,
|
||||
|
||||
hintText: "请输入关键字",
|
||||
// isClickableOnly: true,
|
||||
onSearch: (text) {
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/dh_Wrok/dh_work_list_page.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/special_work_list_page.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/special_work_list_page.dart' hide SpecialWorkListPage;
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/work_tab_icon_grid.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
|
|
@ -129,7 +130,7 @@ class _WorkTabDhListState extends State<WorkTabDhList> {
|
|||
default:
|
||||
print("按钮 $index 被点击");
|
||||
}
|
||||
pushPage(DhWorkListPage(flow: title), context);
|
||||
pushPage(SpecialWorkListPage(flow: title), context);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/dh_Wrok/dh_work_list_page.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/special_work_list_page.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/special_work_list_page.dart' hide SpecialWorkListPage;
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/work_tab_icon_grid.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
|
|
@ -123,7 +124,7 @@ class _WorkTabDlListState extends State<WorkTabDlList> {
|
|||
default:
|
||||
print("按钮 $index 被点击");
|
||||
}
|
||||
pushPage(DhWorkListPage(flow: title), context);
|
||||
pushPage(SpecialWorkListPage(flow: title), context);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/dh_Wrok/dh_work_list_page.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/special_work_list_page.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/special_work_list_page.dart' hide SpecialWorkListPage;
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/work_tab_icon_grid.dart';
|
||||
|
|
@ -124,7 +125,7 @@ class _WorkTabDtListState extends State<WorkTabDtList> {
|
|||
default:
|
||||
print("按钮 $index 被点击");
|
||||
}
|
||||
pushPage(DhWorkListPage(flow: title), context);
|
||||
pushPage(SpecialWorkListPage(flow: title), context);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/dh_Wrok/dh_work_list_page.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/special_work_list_page.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/special_work_list_page.dart' hide SpecialWorkListPage;
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
|
||||
|
|
@ -136,7 +137,7 @@ class _WorkTabDzListState extends State<WorkTabDzList> {
|
|||
default:
|
||||
print("按钮 $index 被点击");
|
||||
}
|
||||
pushPage(DhWorkListPage(flow: title), context);
|
||||
pushPage(SpecialWorkListPage(flow: title), context);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/dh_Wrok/dh_work_list_page.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/special_work_list_page.dart';
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
|
||||
|
|
@ -124,7 +124,7 @@ class _WorkTabGcListState extends State<WorkTabGcList> {
|
|||
default:
|
||||
print("按钮 $index 被点击");
|
||||
}
|
||||
pushPage(DhWorkListPage(flow: title), context);
|
||||
pushPage(SpecialWorkListPage(flow: title), context);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/dh_Wrok/dh_work_list_page.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/special_work_list_page.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/special_work_list_page.dart' hide SpecialWorkListPage;
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
|
||||
|
|
@ -124,7 +125,7 @@ class _WorkTabLsydListState extends State<WorkTabLsydList> {
|
|||
default:
|
||||
print("按钮 $index 被点击");
|
||||
}
|
||||
pushPage(DhWorkListPage(flow: title), context);
|
||||
pushPage(SpecialWorkListPage(flow: title), context);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/dh_Wrok/dh_work_list_page.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/special_work_list_page.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/special_work_list_page.dart' hide SpecialWorkListPage;
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
|
||||
|
|
@ -112,7 +113,7 @@ class _WorkTabMbcdListState extends State<WorkTabMbcdList> {
|
|||
default:
|
||||
print("按钮 $index 被点击");
|
||||
}
|
||||
pushPage(DhWorkListPage(flow: title), context);
|
||||
pushPage(SpecialWorkListPage(flow: title), context);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
|
||||
import 'package:qhd_prevention/http/ApiService.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/dh_Wrok/dh_work_list_page.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_Wrok/special_work_list_page.dart';
|
||||
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/special_work_list_page.dart' hide SpecialWorkListPage;
|
||||
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||
import 'package:qhd_prevention/tools/tools.dart';
|
||||
|
||||
|
|
@ -157,7 +158,7 @@ class _WorkTabSxkjListState extends State<WorkTabSxkjList> {
|
|||
default:
|
||||
print("按钮 $index 被点击");
|
||||
}
|
||||
pushPage(DhWorkListPage(flow: title), context);
|
||||
pushPage(SpecialWorkListPage(flow: title), context);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ class _AiAlarmPageState extends State<AiAlarmPage>
|
|||
// List
|
||||
Expanded(
|
||||
child: _list.isEmpty
|
||||
? Center(child: Text('暂无数据'))
|
||||
? NoDataWidget.show()
|
||||
: ListView.separated(
|
||||
itemCount: _notifications.length,
|
||||
separatorBuilder: (_, __) => const SizedBox(),
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ class _DangerWaitListPageState extends State<DangerWaitListPage> {
|
|||
),
|
||||
Expanded(
|
||||
child: _list.isEmpty
|
||||
? Center(child: Text('暂无数据'))
|
||||
? NoDataWidget.show()
|
||||
: ListView.separated(
|
||||
separatorBuilder: (_, __) => const Divider(height: 1),
|
||||
itemCount: _list.length,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import 'package:qhd_prevention/pages/my_appbar.dart';
|
|||
|
||||
import '../../../customWidget/search_bar_widget.dart';
|
||||
import '../../../http/ApiService.dart';
|
||||
import '../../../tools/tools.dart';
|
||||
import 'laws_list_picker.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
|
|
@ -196,16 +197,7 @@ class _LawsRegulationsPage extends State<LawsRegulationsPage> {
|
|||
),
|
||||
);
|
||||
} else {
|
||||
return const Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.folder_open, size: 64, color: Colors.grey),
|
||||
SizedBox(height: 16),
|
||||
Text('暂无数据', style: TextStyle(fontSize: 18, color: Colors.grey)),
|
||||
],
|
||||
),
|
||||
);
|
||||
return NoDataWidget.show();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ class _MineDepartureRecordPage extends State<MineDepartureRecordPage> {
|
|||
Expanded(
|
||||
child:
|
||||
_list.isEmpty
|
||||
? Center(child: Text('暂无数据'))
|
||||
? NoDataWidget.show()
|
||||
: ListView.builder(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
itemCount: _list.length,
|
||||
|
|
@ -146,7 +146,7 @@ class _MineDepartureRecordPage extends State<MineDepartureRecordPage> {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"申请人:${item['USER_NAME']}",
|
||||
"申请人:${item['USER_NAME'] ?? ''}",
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
|
|
@ -154,7 +154,7 @@ class _MineDepartureRecordPage extends State<MineDepartureRecordPage> {
|
|||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
"部门:${item['DEPARTMENTNAME']} \n岗位:${item['POSTNAME']}",
|
||||
"部门:${item['DEPARTMENTNAME'] ?? ''} \n岗位:${item['POSTNAME'] ?? ''}",
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: Colors.grey[600],
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ class _MineDutyManagementPageState extends State<MineDutyManagementPage> {
|
|||
Expanded(
|
||||
child:
|
||||
_list.isEmpty
|
||||
? Center(child: Text('暂无数据'))
|
||||
? NoDataWidget.show()
|
||||
: ListView.builder(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
itemCount: _list.length,
|
||||
|
|
|
|||
|
|
@ -63,36 +63,35 @@ class _SignatureConfirmPageState extends State<SignatureConfirmPage> {
|
|||
}
|
||||
|
||||
// 保存签名
|
||||
void _saveSignPic() async{
|
||||
|
||||
void _saveSignPic() async {
|
||||
RenderRepaintBoundary boundary = _signatureKey.currentContext!.findRenderObject() as RenderRepaintBoundary;
|
||||
var image = await boundary.toImage(pixelRatio: 1);
|
||||
ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png);
|
||||
|
||||
int timestamp = DateTime.now().millisecondsSinceEpoch;
|
||||
|
||||
Directory dir = await getTemporaryDirectory();
|
||||
String path = dir.path +"/"+ 'sign.png';
|
||||
// 在文件名中添加时间戳
|
||||
String path = '${dir.path}/sign_$timestamp.png';
|
||||
|
||||
File file2 = File(path);
|
||||
// 检查文件是否存在
|
||||
if (await file2.exists()) {
|
||||
// 文件存在,删除文件
|
||||
await file2.delete();
|
||||
}
|
||||
|
||||
var file = await File(path).create(recursive: true);
|
||||
if(byteData != null){
|
||||
file.writeAsBytesSync(byteData.buffer.asInt8List(),flush: true);
|
||||
if(byteData != null) {
|
||||
file.writeAsBytesSync(byteData.buffer.asInt8List(), flush: true);
|
||||
|
||||
setState(() {
|
||||
_postBytes = byteData.buffer.asUint8List();
|
||||
fileN = file;
|
||||
imagepath = file.path;
|
||||
Future.delayed(const Duration(milliseconds: 500), () {
|
||||
Navigator.pop(context,imagepath);
|
||||
|
||||
Navigator.pop(context, imagepath);
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ class _NotifPageState extends State<NotifPage>
|
|||
Expanded(
|
||||
child:
|
||||
_list.isEmpty
|
||||
? Center(child: Text('暂无数据'))
|
||||
? NoDataWidget.show()
|
||||
: ListView.builder(
|
||||
itemCount: _list.length,
|
||||
itemBuilder: (context, index) {
|
||||
|
|
|
|||
|
|
@ -24,9 +24,16 @@ void present(Widget page, BuildContext context) {
|
|||
MaterialPageRoute(fullscreenDialog: true, builder: (context) => page),
|
||||
);
|
||||
}
|
||||
class FocusHelper {
|
||||
static final FocusNode _emptyNode = FocusNode();
|
||||
/// 延迟一帧后再移交焦点,避免不生效的问题
|
||||
static void clearFocus(BuildContext context) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
FocusScope.of(context).requestFocus(_emptyNode);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// 文本样式工具类
|
||||
/// 文本样式工具类
|
||||
/// 文本样式工具类,返回 Text Widget
|
||||
class HhTextStyleUtils {
|
||||
/// 主要标题,返回 Text
|
||||
|
|
@ -302,3 +309,41 @@ String secondsCount(dynamic seconds) {
|
|||
|
||||
return '$hh:$mm:$ss';
|
||||
}
|
||||
|
||||
/// 表单处理
|
||||
class FormUtils {
|
||||
/// 判断 [data] 中的 [key] 是否存在“有效值”:
|
||||
/// - key 不存在或值为 null -> false
|
||||
/// - String:去掉首尾空白后非空 -> true
|
||||
/// - Iterable / Map:非空 -> true
|
||||
/// - 其它类型(int、double、bool 等)只要不为 null 就算有值 -> true
|
||||
static bool hasValue(Map<String, dynamic> data, String key) {
|
||||
if (!data.containsKey(key)) return false;
|
||||
final val = data[key];
|
||||
if (val == null) return false;
|
||||
|
||||
if (val is String) {
|
||||
return val.trim().isNotEmpty;
|
||||
}
|
||||
if (val is Iterable || val is Map) {
|
||||
return val.isNotEmpty;
|
||||
}
|
||||
// 数字、布尔等其它非空即可
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class NoDataWidget {
|
||||
static Widget show() {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Image.asset('assets/images/null.png', width: 200,),
|
||||
Text('暂无数据', style: TextStyle(color: Colors.grey)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
306
pubspec.lock
306
pubspec.lock
File diff suppressed because it is too large
Load Diff
|
|
@ -73,7 +73,8 @@ dependencies:
|
|||
geolocator: ^10.0.0
|
||||
#打开外部预览app
|
||||
url_launcher: ^6.0.9
|
||||
|
||||
#虚线
|
||||
dotted_line: ^3.2.3
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
|
|||
Loading…
Reference in New Issue