设置安全措施确认人完成

main
hs 2025-07-30 10:51:07 +08:00
parent d672f1d944
commit 217310e511
19 changed files with 2197 additions and 745 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
assets/images/xj_finish.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
assets/images/xj_top.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

BIN
assets/images/xj_wait.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
assets/images/xjjd_top.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -704,6 +704,21 @@ U6Hzm1ninpWeE+awIDAQAB
}, },
); );
} }
///
static Future<Map<String, dynamic>> listSignSureAllMeasures(String homeWorkId) {
final String tm = DateTime.now().millisecondsSinceEpoch.toString();
return HttpManager().request(
basePath,
'/app/hotwork/listAllMeasuresForSign?tm=$tm',
method: Method.post,
data: {
"CORPINFO_ID":SessionService.instance.corpinfoId,
"HOTWORK_ID": homeWorkId,
"USER_ID":SessionService.instance.loginUserId,
},
);
}
/// ///
static Future<Map<String, dynamic>> getEightWorkStartList(Map data) { static Future<Map<String, dynamic>> getEightWorkStartList(Map data) {
@ -763,7 +778,28 @@ U6Hzm1ninpWeE+awIDAQAB
fromData: data, fromData: data,
); );
} }
///
static Future<Map<String, dynamic>> saveSafeFunctionSure (
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/nextStep',
fromData: data,
);
}

View File

@ -0,0 +1,360 @@
import 'package:flutter/material.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
class HomeNfcDetailPage extends StatefulWidget {
const HomeNfcDetailPage({super.key});
@override
State<HomeNfcDetailPage> createState() => _HomeNfcDetailPageState();
}
class _HomeNfcDetailPageState extends State<HomeNfcDetailPage> {
Map<String, String> info = {
'title': '设备巡检 A',
'status': '专项巡检',
'department': '安全部',
'owner': '张三',
'unType': 'UN1001',
'cycle': '7天',
'points': '3/5',
};
final List<ProgressItem> demoData = const [
ProgressItem(status: '未查', location: '到期哦i维护经费欺废气阀我废费欺废气阀我废费欺废气阀我废气阀', code: 'XJ1001'),
ProgressItem(status: '已查', location: 'B区-配电室', code: 'XJ1002', checkTime: '2025-07-28 15:32'),
ProgressItem(status: '已查', location: 'B区-配电室', code: 'XJ1002', checkTime: '2025-07-28 15:32'),
ProgressItem(status: '已查', location: 'B区-配电室', code: 'XJ1002', checkTime: '2025-07-28 15:32'),
ProgressItem(status: '已查', location: 'B区-配电室', code: 'XJ1002', checkTime: '2025-07-28 15:32'),
ProgressItem(status: '已查', location: 'B区-配电室', code: 'XJ1002', checkTime: '2025-07-28 15:32'),
ProgressItem(status: '已查', location: 'B区-配电室', code: 'XJ1002', checkTime: '2025-07-28 15:32'),
ProgressItem(status: '已查', location: 'B区-配电室', code: 'XJ1002', checkTime: '2025-07-28 15:32'),
ProgressItem(status: '已查', location: 'B区-配电室', code: 'XJ1002', checkTime: '2025-07-28 15:32'),
ProgressItem(status: '已查', location: 'B区-配电室', code: 'XJ1002', checkTime: '2025-07-28 15:32'),
];
Widget _pendingTopCard(Map<String, String> item) {
return SizedBox(
height: 180,
child: Stack(
clipBehavior: Clip.none,
children: [
ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.asset(
'assets/images/xj_top.png',
height: 70,
width: double.infinity,
fit: BoxFit.cover,
),
),
// &
Positioned(
top: 12,
left: 12,
child: Text(
item['title']!,
style: const TextStyle(
color: Colors.black87,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
Positioned(
top: 12,
right: 12,
child: Container(
height: 30,
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: Colors.blue.withOpacity(0.7),
borderRadius: BorderRadius.circular(15),
),
child: Center(
child: Text(
item['status']!,
style: const TextStyle(color: Colors.white, fontSize: 14),
),
),
),
),
//
Positioned(
left: 0,
right: 0,
top: 50, //
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 0),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.black12,
blurRadius: 4,
offset: Offset(0, 1),
),
],
),
child: _buildInfoGrid(item),
),
),
],
),
);
}
///
Widget _buildInfoGrid(Map<String, String> item) {
return Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('负责部门:${item['department']}'),
const SizedBox(height: 8),
Text('负责人:${item['owner']}'),
const SizedBox(height: 8),
Text('UN件类型${item['unType']}'),
],
),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text('巡检周期:${item['cycle']}'),
const SizedBox(height: 8),
Text('已巡点位:${item['points']}'),
Text('涉及管道区域:${item['department']}')
],
),
),
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppbar(title: '任务详情'),
body: SafeArea(child: Padding(padding: EdgeInsets.all(16), child: Column(
children: [
_pendingTopCard(info),
Expanded(child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.black12,
blurRadius: 4,
offset: Offset(0, 1),
),
],
),
child: SingleChildScrollView(
child: ProgressList(
items: demoData,
onStartCheck: (idx) {
print('开始检查第 $idx');
},
),
)
))
],
),)),
);
}
}
///
class ProgressItem {
final String status; //
final String location; //
final String code; //
final String? checkTime; //
const ProgressItem({
required this.status,
required this.location,
required this.code,
this.checkTime,
});
}
///
class ProgressList extends StatelessWidget {
///
final List<ProgressItem> items;
/// index items
final void Function(int index) onStartCheck;
const ProgressList({
Key? key,
required this.items,
required this.onStartCheck,
}) : super(key: key);
@override
Widget build(BuildContext context) {
// Column
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//
const Padding(
padding: EdgeInsets.all(16),
child: Text(
'已查点位1/5',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
),
const Divider(height: 1),
//
ListView.builder(
physics: const NeverScrollableScrollPhysics(), //
shrinkWrap: true,
itemCount: items.length,
itemBuilder: (ctx, idx) {
return _ProgressListItem(
item: items[idx],
onStart: () => onStartCheck(idx),
);
},
),
],
);
}
}
///
class _ProgressListItem extends StatelessWidget {
final ProgressItem item;
final VoidCallback onStart;
const _ProgressListItem({
Key? key,
required this.item,
required this.onStart,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final bool unchecked = item.status == '未查';
return Container(
height: 100,
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
//
Column(children: [
Stack(
alignment: Alignment.center,
children: [
Image.asset(
unchecked
? 'assets/images/xj_wait.png'
: 'assets/images/xj_finish.png',
width: 50,
height: 30,
fit: BoxFit.cover,
),
Positioned(
top: 2,
child: Text(
item.status,
style: const TextStyle(color: Colors.white, fontSize: 14),
),
),
],
),
SizedBox(height: 15,),
Positioned(
// bottom: 0,
// right: 17,
child: Image.asset(
'assets/images/xjjd_top.png',
width: 15,
height: 30,
),
),
],),
const SizedBox(width: 20),
//
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
item.location,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
maxLines: 1, //
overflow: TextOverflow.ellipsis, //
),
const SizedBox(height: 4),
Text('NFC编码${item.code}'),
unchecked
? InkWell(
onTap: onStart,
child: Column(
children: [
SizedBox(height: 5,),
Container(
height: 35,
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(vertical: 1),
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [Color(0xFFFFA726), Color(0xFFFF7043)],
),
borderRadius: BorderRadius.circular(5),
),
child: const Text(
'开始检查',
style: TextStyle(color: Colors.white, fontSize: 14),
),
),
],
)
)
: Text(
'检查时间:' + (item.checkTime ?? ''),
style: const TextStyle(fontSize: 14),
textAlign: TextAlign.center,
),
],
),
),
//
const SizedBox(width: 8),
Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Icon(Icons.chevron_right, color: Colors.grey),
SizedBox()
],
)
],
),
);
}
}

View File

@ -0,0 +1,263 @@
import 'package:flutter/material.dart';
import 'package:qhd_prevention/pages/home/NFC/home_nfc_detail_page.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/tools/tools.dart';
class HomeNfcListPage extends StatefulWidget {
const HomeNfcListPage({super.key});
@override
State<HomeNfcListPage> createState() => _HomeNfcListPageState();
}
class _HomeNfcListPageState extends State<HomeNfcListPage>
with SingleTickerProviderStateMixin {
late TabController _tabController;
//
final List<Map<String, String>> _pendingList = [
{
'title': '设备巡检 A',
'status': '待巡检',
'department': '安全部',
'owner': '张三',
'unType': 'UN1001',
'cycle': '7天',
'points': '3/5',
},
{
'title': '设备巡检 B',
'status': '待巡检',
'department': '维护部',
'owner': '李四',
'unType': 'UN1002',
'cycle': '30天',
'points': '1/2',
},
{
'title': '设备巡检 C',
'status': '待巡检',
'department': '维护部',
'owner': '李四',
'unType': 'UN1002',
'cycle': '30天',
'points': '1/2',
},
];
final List<Map<String, String>> _recordList = [
{
'title': '设备巡检 A',
'status': '待巡检',
'department': '安全部',
'owner': '张三',
'unType': 'UN1001',
'cycle': '7天',
'points': '3/5',
},
];
@override
void initState() {
super.initState();
_tabController = TabController(length: 2, vsync: this);
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppbar(title: '巡检列表'),
body: SafeArea(
child: Column(
children: [
// Tab bar
TabBar(
controller: _tabController,
labelStyle: const TextStyle(fontSize: 16),
indicator: const UnderlineTabIndicator(
borderSide: BorderSide(width: 3.0, color: Colors.blue),
insets: EdgeInsets.symmetric(horizontal: 50.0),
),
labelColor: Colors.blue,
unselectedLabelColor: Colors.grey,
tabs: const [Tab(text: '待巡检'), Tab(text: '巡检记录')],
),
const SizedBox(height: 8),
// Tab
Expanded(
child: TabBarView(
controller: _tabController,
children: [_buildPendingList(), _buildRecordList()],
),
),
],
),
),
);
}
Widget _buildPendingList() {
if (_pendingList.isEmpty) {
return NoDataWidget.show(); //
}
return ListView.builder(
itemCount: _pendingList.length,
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 0),
itemBuilder: (context, index) {
final item = _pendingList[index];
return Container(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 0),
child: GestureDetector(
onTap: (){
pushPage(HomeNfcDetailPage(), context);
},
child: _pendingCard(item, false),
),
);
},
);
}
Widget _buildRecordList() {
if (_recordList.isEmpty) {
return NoDataWidget.show(); //
}
return ListView.builder(
itemCount: _recordList.length,
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 0),
itemBuilder: (context, index) {
final item = _recordList[index];
return Container(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 0),
child: _pendingCard(item, true),
);
},
);
}
///
Widget _pendingCard(Map<String, String> item, bool isFinish) {
return SizedBox(
height: 180,
child: Stack(
clipBehavior: Clip.none,
children: [
// &
ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.asset(
'assets/images/xj_top.png',
height: 70,
width: double.infinity,
fit: BoxFit.cover,
),
),
// &
Positioned(
top: 12,
left: 12,
child: Text(
item['title']!,
style: const TextStyle(
color: Colors.black87,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
if (!isFinish)
Positioned(
top: 12,
right: 12,
child: Container(
height: 30,
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: Colors.blue.withOpacity(0.7),
borderRadius: BorderRadius.circular(15),
),
child: Center(
child: Text(
item['status']!,
style: const TextStyle(color: Colors.white, fontSize: 14),
),
),
),
),
//
Positioned(
left: 0,
right: 0,
top: 50, //
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 0),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(10),
bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10),
),
boxShadow: [
BoxShadow(
color: Colors.black12,
blurRadius: 4,
offset: Offset(0, 1),
),
],
),
child: _buildInfoGrid(item, isFinish),
),
),
],
),
);
}
///
Widget _buildInfoGrid(Map<String, String> item, bool isFinish) {
return Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('负责部门:${item['department']}'),
const SizedBox(height: 8),
Text('负责人:${item['owner']}'),
const SizedBox(height: 8),
Text('UN件类型${item['unType']}'),
],
),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text('巡检周期:${item['cycle']}'),
const SizedBox(height: 8),
Text('已巡点位:${item['points']}'),
isFinish
? Text('涉及管道区域:${item['department']}')
: const SizedBox(height: 25),
],
),
),
],
);
}
}

View File

@ -2,6 +2,7 @@ import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart'; import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
import 'package:qhd_prevention/pages/home/NFC/home_nfc_list_page.dart';
import 'package:qhd_prevention/pages/home/low_page.dart'; import 'package:qhd_prevention/pages/home/low_page.dart';
import 'package:qhd_prevention/pages/home/risk/riskControl_page.dart'; import 'package:qhd_prevention/pages/home/risk/riskControl_page.dart';
import 'package:qhd_prevention/pages/home/study/study_garden_page.dart'; import 'package:qhd_prevention/pages/home/study/study_garden_page.dart';
@ -196,6 +197,8 @@ class _HomePageState extends State<HomePage> {
pushPage(WorkTabListPage(), context); pushPage(WorkTabListPage(), context);
} else if (index == 7) { } else if (index == 7) {
pushPage(StudyGardenPage(), context); pushPage(StudyGardenPage(), context);
} else if (index == 11) {
pushPage(HomeNfcListPage(), context);
} }
}, },
); );
@ -513,6 +516,11 @@ class _HomePageState extends State<HomePage> {
"title": "安全例会", "title": "安全例会",
"unreadCount": 0, "unreadCount": 0,
}, },
{
"icon": "assets/icon-apps/home-xj.png",
"title": "燃气巡检",
"unreadCount": 0,
},
]; ];
}); });

View File

@ -19,9 +19,10 @@ class ItemListWidget {
return Container( return Container(
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 12), padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 12),
child: Row( child: Row(
mainAxisAlignment: isEditable mainAxisAlignment:
? MainAxisAlignment.start isEditable
: MainAxisAlignment.spaceBetween, ? MainAxisAlignment.start
: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
label, label,
@ -30,23 +31,23 @@ class ItemListWidget {
const SizedBox(width: 8), const SizedBox(width: 8),
isEditable isEditable
? Expanded( ? Expanded(
child: TextField( child: TextField(
autofocus: false, autofocus: false,
controller: controller, controller: controller,
style: TextStyle(fontSize: fontSize), style: TextStyle(fontSize: fontSize),
maxLines: 1, maxLines: 1,
decoration: InputDecoration( decoration: InputDecoration(
isDense: true, isDense: true,
hintText: hintText, hintText: hintText,
contentPadding: EdgeInsets.symmetric(vertical: 8), contentPadding: EdgeInsets.symmetric(vertical: 8),
), ),
), ),
) )
: Text( : Text(
text ?? '', text ?? '',
style: TextStyle(fontSize: fontSize, color: detailtextColor), style: TextStyle(fontSize: fontSize, color: detailtextColor),
overflow: TextOverflow.ellipsis, // overflow: TextOverflow.ellipsis, //
), ),
], ],
), ),
); );
@ -76,47 +77,53 @@ class ItemListWidget {
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
Expanded( Expanded(
child: isEditable child:
? TextField( isEditable
autofocus: false, ? TextField(
controller: controller, autofocus: false,
keyboardType: TextInputType.multiline, controller: controller,
maxLines: null, keyboardType: TextInputType.multiline,
expands: true, maxLines: null,
// expands: true,
textAlignVertical: TextAlignVertical.top, //
style: TextStyle(fontSize: fontSize), textAlignVertical: TextAlignVertical.top,
decoration: InputDecoration( style: TextStyle(fontSize: fontSize),
hintText: '请输入', decoration: InputDecoration(
// TextField hintText: '请输入',
contentPadding: EdgeInsets.zero, // TextField
border: InputBorder.none, contentPadding: EdgeInsets.zero,
), border: InputBorder.none,
) ),
: SingleChildScrollView( )
// padding : SingleChildScrollView(
padding: EdgeInsets.zero, // padding
child: Text( padding: EdgeInsets.zero,
text ?? '', child: Text(
style: TextStyle(fontSize: fontSize, color: detailtextColor), text ?? '',
), style: TextStyle(
), fontSize: fontSize,
color: detailtextColor,
),
),
),
), ),
], ],
), ),
); );
} }
/// ///
/// - + + /// - + +
/// - + /// - +
static Widget selectableLineTitleTextField({ static Widget selectableLineTitleTextField({
required String label, // required String label, //
required bool isEditable, // required bool isEditable, //
required String text, // required String text, //
VoidCallback? onTap, // VoidCallback? onTap, //
double fontSize = 15, // double fontSize = 15, //
bool isClean = false,
VoidCallback? onTapClean, //
}) { }) {
return InkWell( return InkWell(
onTap: isEditable ? onTap : null, onTap: isEditable ? onTap : null,
@ -127,14 +134,24 @@ class ItemListWidget {
// 1. // 1.
Text( Text(
label, label,
style: TextStyle( style: TextStyle(fontSize: fontSize, fontWeight: FontWeight.bold),
fontSize: fontSize,
fontWeight: FontWeight.bold,
),
), ),
if (isClean)
Column(
children: [
CustomButton(
text: '清除',
height: 20,
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 0),
textStyle: TextStyle(fontSize: 11, color: Colors.white),
borderRadius: 10,
backgroundColor: Colors.red,
onPressed: onTapClean,
),
SizedBox(height: 20),
],
),
const SizedBox(width: 8), const SizedBox(width: 8),
Expanded( Expanded(
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
@ -153,10 +170,7 @@ class ItemListWidget {
if (isEditable) if (isEditable)
const Padding( const Padding(
padding: EdgeInsets.only(left: 4), padding: EdgeInsets.only(left: 4),
child: Icon( child: Icon(Icons.chevron_right, size: 20),
Icons.chevron_right,
size: 20,
),
), ),
], ],
), ),
@ -167,8 +181,6 @@ class ItemListWidget {
); );
} }
/// ///
/// ///
/// ///
@ -194,7 +206,10 @@ class ItemListWidget {
children: [ children: [
Text( Text(
label, label,
style: TextStyle(fontSize: fontSize, fontWeight: FontWeight.bold), style: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
),
), ),
Row( Row(
children: [ children: [
@ -209,7 +224,7 @@ class ItemListWidget {
), ),
if (isEditable) const Icon(Icons.chevron_right), if (isEditable) const Icon(Icons.chevron_right),
], ],
) ),
], ],
), ),
), ),
@ -217,27 +232,31 @@ class ItemListWidget {
Container( Container(
height: row2Height, height: row2Height,
padding: const EdgeInsets.symmetric(vertical: 8), padding: const EdgeInsets.symmetric(vertical: 8),
child: isEditable child:
? TextField( isEditable
autofocus: false, ? TextField(
controller: controller, autofocus: false,
keyboardType: TextInputType.multiline, controller: controller,
maxLines: null, keyboardType: TextInputType.multiline,
expands: true, maxLines: null,
style: TextStyle(fontSize: fontSize), expands: true,
decoration: InputDecoration( style: TextStyle(fontSize: fontSize),
hintText: '请输入', decoration: InputDecoration(
contentPadding: EdgeInsets.zero, hintText: '请输入',
border: InputBorder.none, contentPadding: EdgeInsets.zero,
), border: InputBorder.none,
) ),
: SingleChildScrollView( )
padding: EdgeInsets.zero, : SingleChildScrollView(
child: Text( padding: EdgeInsets.zero,
text, child: Text(
style: TextStyle(fontSize: fontSize, color: detailtextColor), text,
), style: TextStyle(
), fontSize: fontSize,
color: detailtextColor,
),
),
),
), ),
], ],
), ),
@ -269,7 +288,10 @@ class ItemListWidget {
Flexible( Flexible(
child: Text( child: Text(
label, label,
style: TextStyle(fontSize: fontSize, fontWeight: FontWeight.bold), style: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
),
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
@ -279,7 +301,10 @@ class ItemListWidget {
CustomButton( CustomButton(
text: "选择其他", text: "选择其他",
height: 30, height: 30,
padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 5), padding: const EdgeInsets.symmetric(
vertical: 2,
horizontal: 5,
),
backgroundColor: Colors.green, backgroundColor: Colors.green,
onPressed: onTap, onPressed: onTap,
), ),
@ -291,32 +316,37 @@ class ItemListWidget {
Container( Container(
height: row2Height, height: row2Height,
padding: const EdgeInsets.symmetric(vertical: 8), padding: const EdgeInsets.symmetric(vertical: 8),
child: isEditable child:
? TextField( isEditable
autofocus: false, ? TextField(
controller: controller, autofocus: false,
keyboardType: TextInputType.multiline, controller: controller,
maxLines: null, keyboardType: TextInputType.multiline,
expands: true, maxLines: null,
style: TextStyle(fontSize: fontSize), expands: true,
decoration: InputDecoration( style: TextStyle(fontSize: fontSize),
hintText: hintText, decoration: InputDecoration(
contentPadding: EdgeInsets.zero, hintText: hintText,
border: InputBorder.none, contentPadding: EdgeInsets.zero,
), border: InputBorder.none,
) ),
: SingleChildScrollView( )
padding: EdgeInsets.zero, : SingleChildScrollView(
child: Text( padding: EdgeInsets.zero,
text, child: Text(
style: TextStyle(fontSize: fontSize, color: detailtextColor), text,
), style: TextStyle(
), fontSize: fontSize,
color: detailtextColor,
),
),
),
), ),
], ],
), ),
); );
} }
/// ///
/// + + /// + +
static Widget OneRowButtonTitleText({ static Widget OneRowButtonTitleText({
@ -330,23 +360,31 @@ class ItemListWidget {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Expanded(child: Row( Expanded(
children: [ child: Row(
Text( children: [
label, Text(
style: TextStyle(fontSize: fontSize, fontWeight: FontWeight.bold), label,
), style: TextStyle(
SizedBox(width: 15,), fontSize: fontSize,
Expanded( fontWeight: FontWeight.bold,
child: Text( ),
text,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: fontSize, color: detailtextColor),
), ),
), SizedBox(width: 15),
], Expanded(
),), child: Text(
text,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: fontSize,
color: detailtextColor,
),
),
),
],
),
),
CustomButton( CustomButton(
text: "分析详情", text: "分析详情",
height: 30, height: 30,
@ -355,9 +393,10 @@ class ItemListWidget {
onPressed: onTap, onPressed: onTap,
), ),
], ],
) ),
); );
} }
/// ///
/// + /// +
static Widget OneRowButtonTitle({ static Widget OneRowButtonTitle({
@ -366,27 +405,25 @@ class ItemListWidget {
required VoidCallback? onTap, // required VoidCallback? onTap, //
double fontSize = 15, // double fontSize = 15, //
Color btnColor = Colors.blue, Color btnColor = Colors.blue,
}) { }) {
return Container( return Container(
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 12), padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 12),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
label, label,
style: TextStyle(fontSize: fontSize, fontWeight: FontWeight.bold), style: TextStyle(fontSize: fontSize, fontWeight: FontWeight.bold),
), ),
CustomButton( CustomButton(
text: buttonText, text: buttonText,
height: 30, height: 30,
padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 5), padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 5),
backgroundColor: btnColor, backgroundColor: btnColor,
onPressed: onTap, onPressed: onTap,
), ),
], ],
) ),
); );
} }
} }

View File

@ -0,0 +1,163 @@
import 'package:flutter/material.dart';
import '../../../../../tools/tools.dart';
import '../../item_list_widget.dart';
import '../special_Wrok/dh_work_detai/MeasuresListWidget.dart';
///
/// TextEditingController
class WorkDetailFormWidget extends StatelessWidget {
final Map<String, dynamic> pd;
final bool isEditable;
final VoidCallback onChooseLevel;
final VoidCallback onChooseHotworkUser;
final VoidCallback onAnalyzeTap;
///
final TextEditingController? contentController;
final TextEditingController? locationController;
final TextEditingController? methodController;
final TextEditingController? hotworkPersonController;
final TextEditingController? relatedController;
final TextEditingController? riskController;
const WorkDetailFormWidget({
Key? key,
required this.pd,
required this.isEditable,
required this.onChooseLevel,
required this.onChooseHotworkUser,
required this.onAnalyzeTap,
this.contentController,
this.locationController,
this.methodController,
this.hotworkPersonController,
this.relatedController,
this.riskController,
}) : assert(
!isEditable || (contentController != null && locationController != null && methodController != null && hotworkPersonController != null && relatedController != null && riskController != null),
'Editable mode requires all TextEditingController parameters',
),
super(key: key);
@override
Widget build(BuildContext context) {
final pd = this.pd;
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ItemListWidget.singleLineTitleText(
label: '申请单位:',
isEditable: false,
text: pd['APPLY_DEPARTMENT_NAME'] ?? '',
),
const Divider(),
ItemListWidget.singleLineTitleText(
label: '申请人:',
isEditable: false,
text: pd['APPLY_USER_NAME'] ?? '',
),
if (FormUtils.hasValue(pd, 'CHECK_NO')) ...[
const Divider(),
ItemListWidget.singleLineTitleText(
label: '编号:',
isEditable: false,
text: pd['CHECK_NO'] ?? '',
),
],
const Divider(),
ItemListWidget.multiLineTitleTextField(
label: '作业内容:',
isEditable: isEditable,
controller: contentController,
text: pd['WORK_CONTENT'] ?? '',
),
const Divider(),
ItemListWidget.singleLineTitleText(
label: '动火地点及动火部位:',
isEditable: isEditable,
controller: locationController,
text: pd['WORK_PLACE'] ?? '',
),
const Divider(),
ItemListWidget.selectableLineTitleTextField(
label: '动火作业级别:',
isEditable: isEditable,
onTap: onChooseLevel,
text: pd['WORK_LEVEL'] ?? '',
),
const Divider(),
ItemListWidget.singleLineTitleText(
label: '动火方式:',
isEditable: isEditable,
controller: methodController,
text: pd['WORK_FUNCTION'] ?? '',
),
if (pd['WORK_START_DATE']?.toString().isNotEmpty == true) ...[
const Divider(),
ItemListWidget.singleLineTitleText(
label: '动火作业实施时间:',
isEditable: isEditable,
text: '${pd['WORK_START_DATE']}${pd['WORK_END_DATE'] ?? '--'}',
),
],
const Divider(),
ItemListWidget.twoRowSelectableTitleText(
label: '动火人及证书编号:',
isEditable: isEditable,
onTap: onChooseHotworkUser,
text: pd['WORK_USER'] ?? '',
controller: hotworkPersonController,
),
const Divider(),
ItemListWidget.twoRowButtonTitleText(
label: '关联其他特殊作业及安全作业票:',
isEditable: isEditable,
onTap: () async {
final val = await showDialog<String>(
context: context,
builder: (_) => SelectionPopup(
type: 'assignments',
initialValue: pd['SPECIAL_WORK'] ?? '',
onConfirm: (v) => Navigator.of(context).pop(v),
),
);
if (val != null) pd['SPECIAL_WORK'] = val;
FocusHelper.clearFocus(context);
},
hintText: '请输入关联的其他特殊作业及安全作业票编号',
controller: relatedController,
text: pd['SPECIAL_WORK'] ?? '',
),
const Divider(),
ItemListWidget.twoRowButtonTitleText(
label: '风险辨识结果:',
isEditable: isEditable,
onTap: () async {
final val = await showDialog<String>(
context: context,
builder: (_) => SelectionPopup(
type: 'identification',
initialValue: pd['RISK_IDENTIFICATION'] ?? '',
onConfirm: (v) => Navigator.of(context).pop(v),
),
);
if (val != null) pd['RISK_IDENTIFICATION'] = val;
FocusHelper.clearFocus(context);
},
hintText: '请输入风险辨识结果',
controller: riskController,
text: pd['RISK_IDENTIFICATION'] ?? '',
),
if (FormUtils.hasValue(pd, 'ANALYZE_TIME')) ...[
const Divider(),
ItemListWidget.OneRowButtonTitleText(
label: '分析人:',
text: pd['ANALYZE_USER_NAME'] ?? '',
onTap: onAnalyzeTap,
),
],
],
);
}
}

View File

@ -0,0 +1,532 @@
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/department_person_picker.dart';
import 'package:qhd_prevention/customWidget/department_picker.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
import 'package:qhd_prevention/tools/tools.dart';
import '../../../../../../customWidget/bottom_picker.dart';
import '../../../../../../customWidget/custom_alert_dialog.dart';
import '../../../../../../customWidget/single_image_viewer.dart';
import '../../../../../../http/ApiService.dart';
import '../../../../../mine/mine_sign_page.dart';
import '../../../../../my_appbar.dart';
import '../../special_Wrok/dh_work_detai/MeasuresListWidget.dart';
import '../../special_Wrok/qtfx_work_detail/hotwork_gas_list.dart';
import '../WorkDetailFormWidget.dart';
///
class HotworkSafeFuncSure extends StatefulWidget {
const HotworkSafeFuncSure({
super.key,
required this.HOTWORK_ID,
required this.flow,
});
final String HOTWORK_ID;
final String flow;
@override
State<HotworkSafeFuncSure> createState() => _HotworkSafeFuncSureState();
}
class _HotworkSafeFuncSureState extends State<HotworkSafeFuncSure> {
late bool isEditable = false;
final levelList = ["特级", "一级", "二级"];
///
late String msg = 'add';
///
late Map<String, dynamic> pd = {};
late List<Map<String, dynamic>> measuresList = [];
///
late List<dynamic> workUserList = [];
///
late List<MeasureItem> measuresListCopy = [];
List<String> imagePaths = [];
List<String> signTimes = []; //
@override
void initState() {
super.initState();
_getData();
_getHotWorkNameList();
addMeasuresListCopy();
}
String measuresListToJson() {
final List<Map<String, dynamic>> jsonList =
measuresListCopy.map((item) => item.toJson()).toList();
return jsonEncode(jsonList);
}
Widget _card(Widget child) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(5),
),
child: child,
);
}
///
void chooseUnitHandle(MeasureItem item) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
barrierColor: Colors.black54,
backgroundColor: Colors.transparent,
builder:
(_) => DepartmentPicker(
onSelected: (id, name) async {
setState(() {
item.DEPARTMENT_ID = id;
item.DEPARTMENT_NAME = name;
});
_getPersonListForUnitId(item);
},
),
).then((_) {});
}
Future<void> _getPersonListForUnitId(MeasureItem item) async {
//
final result = await ApiService.getListTreePersonList(item.DEPARTMENT_ID);
setState(() {
item.userList = List<Map<String, dynamic>>.from(
result['userList'] ?? <Map<String, dynamic>>[],
);
});
}
///
void choosePersonHandle(MeasureItem item) async {
String unitId = item.DEPARTMENT_ID;
final personList = item.userList;
if (!unitId.isNotEmpty) {
ToastUtil.showNormal(context, '请先选择确认单位');
return;
}
if (personList.isEmpty) {
//
await _getPersonListForUnitId(item);
final list = item.userList;
if (list.isEmpty) {
//
ToastUtil.showNormal(context, '暂无数据,请选择其他单位');
} else {
choosePersonHandle(item);
}
return;
}
DepartmentPersonPicker.show(
context,
personsData: personList,
onSelected: (userId, name) {
setState(() {
item.USER_NAME = name;
item.USER_ID = userId;
print(json.encode(measuresListCopy));
});
},
).then((_) {});
}
///
Future<void> _sign() async {
final path = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => MineSignPage()),
);
if (path != null) {
final now = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now());
setState(() {
imagePaths.add(path);
signTimes.add(now);
FocusHelper.clearFocus(context);
});
}
}
Widget _signListWidget() {
return Column(
children:
imagePaths.map((path) {
return Column(
children: [
const SizedBox(height: 10),
const Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
child: // ConstrainedBox BoxFit.contain
ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 200,
maxHeight: 150,
),
child: Image.file(
File(path),
//
fit: BoxFit.contain,
),
),
onTap: () {
presentOpaque(
SingleImageViewer(imageUrl: path),
context,
);
},
),
Column(
children: [
Container(
padding: const EdgeInsets.only(right: 5),
child: CustomButton(
text: 'X',
height: 30,
padding: const EdgeInsets.symmetric(horizontal: 10),
backgroundColor: Colors.red,
onPressed: () {
setState(() {
imagePaths.remove(path);
});
},
),
),
const SizedBox(height: 80),
],
),
],
),
],
);
}).toList(),
);
}
/// 1 0
Future<void> _submit(String status) async {
if (imagePaths.isEmpty) {
ToastUtil.showNormal(context, '请签字');
return;
}
List<Map<String, dynamic>> signers = [];
String reasonText = '';
if (status == '1') {
int index = 0;
for (var item in measuresListCopy) {
if (item.USER_ID.isEmpty) {
ToastUtil.showNormal(
context,
'${index + 1}项未设置确认人',
);
return;
}
if (item.selectMeasures.isEmpty) {
ToastUtil.showNormal(
context,
'${index + 1}项未选择安全措施',
);
return;
}
final userId = item.USER_ID;
final selectMeasures = item.selectMeasures as List<dynamic>? ?? [];
for (var item in selectMeasures) {
signers.add({
'BUS_HOTWORK_MEASURES_ID': item['BUS_HOTWORK_MEASURES_ID'],
'USER_ID': userId,
});
}
//
if (signers.length != measuresList.length) {
// 使 ScaffoldMessenger
ToastUtil.showNormal(context, '请为每个安全措施选择确认人');
return;
}
index++;
}
} else {
await showDialog<String>(
context: context,
builder:
(_) => CustomAlertDialog(
title: '作废原因',
mode: DialogMode.input,
hintText: '请输入作废原因',
cancelText: '取消',
confirmText: '确定',
onInputConfirm: (text) {
reasonText = text;
},
),
);
if (reasonText.isEmpty) {
ToastUtil.showNormal(context, '请填写作废原因');
return;
}
}
final Map<String, dynamic> formData = {};
//
formData['HOTWORK_ID'] = widget.HOTWORK_ID;
formData['SIGNTIME'] = signTimes.join(',');
formData['USER_ID'] = SessionService.instance.loginUserId;
formData['APPLY_STATUS'] = status;
formData['STEP_REASON'] = reasonText;
formData['PREPARERS'] = json.encode(signers);
await showDialog<String>(
context: context,
builder:
(_) => CustomAlertDialog(
title: '提示',
content: '请确认' + (status == '1' ? "通过" : "作废") + '本作业票?',
cancelText: '取消',
confirmText: '确定',
onConfirm: () async {
LoadingDialogHelper.show(context);
try {
final result = await ApiService.saveSafeFunctionSure(
formData,
imagePaths,
);
LoadingDialogHelper.hide(context);
if (result['result'] == 'success') {
ToastUtil.showSuccess(
context,
status == '1' ? '提交成功' : '已暂存',
);
Navigator.pop(context);
}
} catch (e) {
LoadingDialogHelper.hide(context);
ToastUtil.showNormal(context, '操作失败:$e');
}
},
),
);
}
void printLongString(String text, {int chunkSize = 800}) {
final pattern = RegExp('.{1,$chunkSize}'); // chunkSize
for (final match in pattern.allMatches(text)) {
print(match.group(0));
}
}
Future<void> _getHotWorkNameList() async {
final result = await ApiService.getHotWorkNameList();
setState(() {
workUserList = result['varList'] ?? '';
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'];
_getMeasures();
});
}
Future<void> _getMeasures() async {
final data = await ApiService.listSignSureAllMeasures(widget.HOTWORK_ID);
setState(() {
measuresList = List<Map<String, dynamic>>.from(
data['measuresForSignList'] ?? <Map<String, dynamic>>[],
);
});
}
void removeMeasuresListCopy(int index) {
setState(() {
measuresListCopy.removeAt(index);
});
}
void addMeasuresListCopy() {
setState(() {
measuresListCopy.add(
MeasureItem(
id: Random().nextDouble(),
DEPARTMENT_ID: '',
DEPARTMENT_NAME: '',
USER_ID: '',
USER_NAME: '',
userList: [],
userIndex: -1,
selectMeasures: [],
),
);
});
}
///
Widget _setSafeDetailWidget() {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
padding: EdgeInsets.symmetric(horizontal: 5),
child: Column(
children: [
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,
),
),
],
),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(),
CustomButton(
text: '新增手写签字',
height: 36,
backgroundColor: Colors.green,
onPressed: () {
_sign();
},
),
],
),
SizedBox(height: 10),
if (imagePaths.isNotEmpty) _signListWidget(),
],
),
);
}
///
Widget _bottomButtons() {
return Row(
spacing: 10,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: CustomButton(
height: 45,
textStyle: TextStyle(fontSize: 16, color: Colors.white),
text: '作废',
backgroundColor: Colors.red,
onPressed: () {
_submit('-1');
},
),
),
Expanded(
child: CustomButton(
textStyle: TextStyle(fontSize: 16, color: Colors.white),
text: '通过',
backgroundColor: Colors.green,
onPressed: () {
_submit('1');
},
),
),
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppbar(title: '安全措施确认人意见'),
body: SafeArea(
child: SingleChildScrollView(
padding: EdgeInsets.all(12),
child: Column(
children: [
// _card(_defaultDetail()),
_card(
WorkDetailFormWidget(
pd: pd,
isEditable: false,
onChooseLevel: (){},
onChooseHotworkUser: (){},
onAnalyzeTap: () {
pushPage(
HotworkGasList(HOTWORK_ID: widget.HOTWORK_ID),
context,
);
},
),
),
SizedBox(height: 20),
_setSafeDetailWidget(),
SizedBox(height: 20),
_bottomButtons(),
],
),
),
),
);
}
}
class MeasureItem {
final double id;
String DEPARTMENT_ID;
String DEPARTMENT_NAME;
String USER_ID;
String USER_NAME;
List<Map<String, dynamic>> userList;
int userIndex;
List<Map<String, dynamic>> selectMeasures;
MeasureItem({
required this.id,
this.DEPARTMENT_ID = '',
this.DEPARTMENT_NAME = '',
this.USER_ID = '',
this.USER_NAME = '',
List<Map<String, dynamic>>? userList,
this.userIndex = -1,
List<Map<String, dynamic>>? selectMeasures,
}) : userList = userList ?? [],
selectMeasures = selectMeasures ?? [];
Map<String, dynamic> toJson() {
return {
'id': id,
'DEPARTMENT_ID': DEPARTMENT_ID,
'DEPARTMENT_NAME': DEPARTMENT_NAME,
'USER_ID': USER_ID,
'USER_NAME': USER_NAME,
'userList': userList,
'userIndex': userIndex,
'selectMeasures': selectMeasures,
};
}
}

View File

@ -50,7 +50,6 @@ class MeasuresListWidget extends StatelessWidget {
border: TableBorder( border: TableBorder(
horizontalInside: BorderSide(color: Colors.grey.shade300), horizontalInside: BorderSide(color: Colors.grey.shade300),
verticalInside: BorderSide(color: Colors.grey.shade300), verticalInside: BorderSide(color: Colors.grey.shade300),
), ),
children: [ children: [
// //
@ -155,26 +154,32 @@ class MeasuresListWidget extends StatelessWidget {
padding: const EdgeInsets.only(top: 8), padding: const EdgeInsets.only(top: 8),
child: Column( child: Column(
children: [ children: [
Padding(padding: EdgeInsets.symmetric(horizontal: 12), child: Row( Padding(
crossAxisAlignment: CrossAxisAlignment.start, padding: EdgeInsets.symmetric(horizontal: 12),
mainAxisAlignment: MainAxisAlignment.spaceBetween, child: Row(
children: [ crossAxisAlignment: CrossAxisAlignment.start,
Text( mainAxisAlignment: MainAxisAlignment.spaceBetween,
'$question: ', children: [
style: const TextStyle(fontWeight: FontWeight.w800), Text(
), '$question: ',
Text(answer.isNotEmpty ? answer : '0') style: const TextStyle(fontWeight: FontWeight.w800),
], ),
),), Text(answer.isNotEmpty ? answer : '0'),
Divider() ],
),
),
Divider(),
], ],
) ),
); );
} }
/// + /// +
List<Widget> _buildImageRows(BuildContext context, List<String> paths, String time) { List<Widget> _buildImageRows(
BuildContext context,
List<String> paths,
String time,
) {
return paths.map((p) { return paths.map((p) {
return Padding( return Padding(
padding: const EdgeInsets.only(top: 8), padding: const EdgeInsets.only(top: 8),
@ -182,16 +187,16 @@ class MeasuresListWidget extends StatelessWidget {
children: [ children: [
GestureDetector( GestureDetector(
onTap: () { onTap: () {
Navigator.of(context).push(PageRouteBuilder( Navigator.of(context).push(
opaque: false, PageRouteBuilder(
pageBuilder: (_, __, ___) => SingleImageViewer(imageUrl: '$baseImgPath$p'), opaque: false,
)); pageBuilder:
(_, __, ___) =>
SingleImageViewer(imageUrl: '$baseImgPath$p'),
),
);
}, },
child: Image.network( child: Image.network('$baseImgPath$p', width: 80, height: 80),
'$baseImgPath$p',
width: 80,
height: 80,
),
), ),
if (time.isNotEmpty) ...[const SizedBox(width: 8), Text(time)], if (time.isNotEmpty) ...[const SizedBox(width: 8), Text(time)],
], ],
@ -200,6 +205,7 @@ class MeasuresListWidget extends StatelessWidget {
}).toList(); }).toList();
} }
} }
/// ///
class OtherMeasuresWidget extends StatelessWidget { class OtherMeasuresWidget extends StatelessWidget {
/// ///
@ -214,17 +220,17 @@ class OtherMeasuresWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final list = (otherMeasures ?? []) final list =
.where((e) => e is Map<String, dynamic>) (otherMeasures ?? [])
.map((e) => e as Map<String, dynamic>) .where((e) => e is Map<String, dynamic>)
.toList(); .map((e) => e as Map<String, dynamic>)
.toList();
if (list.isEmpty) { if (list.isEmpty) {
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Container( Container(
margin: const EdgeInsets.symmetric(horizontal: 10), margin: const EdgeInsets.symmetric(horizontal: 10),
decoration: BoxDecoration( decoration: BoxDecoration(
@ -244,13 +250,19 @@ class OtherMeasuresWidget extends StatelessWidget {
Padding( Padding(
padding: EdgeInsets.all(8), padding: EdgeInsets.all(8),
child: Center( child: Center(
child: Text('其他安全措施', style: TextStyle(fontWeight: FontWeight.bold)), child: Text(
'其他安全措施',
style: TextStyle(fontWeight: FontWeight.bold),
),
), ),
), ),
Padding( Padding(
padding: EdgeInsets.all(8), padding: EdgeInsets.all(8),
child: Center( child: Center(
child: Text('签字', style: TextStyle(fontWeight: FontWeight.bold)), child: Text(
'签字',
style: TextStyle(fontWeight: FontWeight.bold),
),
), ),
), ),
], ],
@ -291,29 +303,35 @@ class OtherMeasuresWidget extends StatelessWidget {
return Wrap( return Wrap(
spacing: 8, spacing: 8,
runSpacing: 8, runSpacing: 8,
children: paths.map((p) { children:
return GestureDetector( paths.map((p) {
onTap: () { return GestureDetector(
Navigator.of(context).push(MaterialPageRoute( onTap: () {
builder: (_) => SingleImageViewer(imageUrl: '$baseImgPath$p'), Navigator.of(context).push(
)); MaterialPageRoute(
}, builder:
child: Image.network( (_) => SingleImageViewer(imageUrl: '$baseImgPath$p'),
'$baseImgPath$p', ),
width: 60, );
height: 60, },
errorBuilder: (c, o, s) => const Icon(Icons.broken_image), child: Image.network(
), '$baseImgPath$p',
); width: 60,
}).toList(), height: 60,
errorBuilder: (c, o, s) => const Icon(Icons.broken_image),
),
);
}).toList(),
); );
} }
} }
/// ///
class SignaturesListWidget extends StatelessWidget { class SignaturesListWidget extends StatelessWidget {
final Map<String, dynamic>? signs; final Map<String, dynamic>? signs;
final Map<String, dynamic>? pd; final Map<String, dynamic>? pd;
final String baseImgPath; final String baseImgPath;
const SignaturesListWidget({ const SignaturesListWidget({
Key? key, Key? key,
this.signs, this.signs,
@ -327,22 +345,96 @@ class SignaturesListWidget extends StatelessWidget {
final safePd = pd ?? {}; final safePd = pd ?? {};
return Column( return Column(
children: [ children: [
_buildSection(context, '监护人', safeSigns['GUARDIAN'], safePd['GUARDIAN_USER_NAME'], EditUserType.GUARDIAN), _buildSection(
_buildSection(context, '安全交底人', safeSigns['CONFESS'], safePd['CONFESS_USER_NAME'], EditUserType.CONFESS), context,
_buildSection(context, '接受交底人', safeSigns['ACCEPT_CONFESS'], safePd['ACCEPT_CONFESS_USER_NAME'], EditUserType.ACCEPT_CONFESS), '监护人',
_buildTextareaWithSigns(context, '作业负责人意见', safeSigns['CONFIRM'], safePd['CONFIRM_USER_NAME'], EditUserType.CONFIRM), safeSigns['GUARDIAN'],
_buildTextareaWithSigns(context, '所在单位意见', safeSigns['LEADER'], safePd['LEADER_USER_NAME'], EditUserType.LEADER), safePd['GUARDIAN_USER_NAME'],
_buildTextareaWithSigns(context, '安全管理部门意见', safeSigns['AUDIT'], safePd['AUDIT_USER_NAME'], EditUserType.AUDIT), EditUserType.GUARDIAN,
_buildTextareaWithSigns(context, '动火审批人意见', safeSigns['APPROVE'], safePd['APPROVE_USER_NAME'], EditUserType.APPROVE), ),
_buildTextareaWithSigns(context, '动火前在岗班长意见', safeSigns['MONITOR'], safePd['MONITOR_USER_NAME'], EditUserType.MONITOR), _buildSection(
_buildSection(context, '作业开始负责人', safeSigns['WORK_START'], safePd['WORK_START_USER_NAME'], EditUserType.WORK_START), context,
_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'), 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}) { 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(); if (rawList is! List || rawList.isEmpty) return const SizedBox.shrink();
final list = rawList.cast<Map<String, dynamic>>(); final list = rawList.cast<Map<String, dynamic>>();
final first = list.first; final first = list.first;
@ -364,20 +456,38 @@ class SignaturesListWidget extends StatelessWidget {
return Container( return Container(
margin: const EdgeInsets.only(top: 20), margin: const EdgeInsets.only(top: 20),
decoration: BoxDecoration(color: Colors.white,border: Border.symmetric(vertical: BorderSide(color: Colors.grey.shade300))), decoration: BoxDecoration(
color: Colors.white,
border: Border.symmetric(
vertical: BorderSide(color: Colors.grey.shade300),
),
),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
child: Text('$title: $name', style: const TextStyle(fontWeight: FontWeight.bold)), child: Text(
'$title: $name',
style: const TextStyle(fontWeight: FontWeight.bold),
),
), ),
if (showImages && first['IMG_PATH'] is List) if (showImages && first['IMG_PATH'] is List)
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 20), padding: const EdgeInsets.symmetric(horizontal: 20),
child: Wrap( child: Wrap(
spacing: 8, spacing: 8,
children: (first['IMG_PATH'] as List).cast<String>().map((img) => Image.network('$baseImgPath$img', width: 50, height: 50)).toList(), 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++) for (var i = 0; i < signPaths.length; i++)
@ -386,11 +496,27 @@ class SignaturesListWidget extends StatelessWidget {
child: Row( child: Row(
children: [ children: [
GestureDetector( GestureDetector(
onTap: () => Navigator.of(context).push(MaterialPageRoute(builder: (_) => SingleImageViewer(imageUrl: '$baseImgPath${signPaths[i]}'))), onTap:
child: Image.network('$baseImgPath${signPaths[i]}', width: 100, height: 100, errorBuilder: (_, __, ___) => const Icon(Icons.broken_image)), () => 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), const SizedBox(width: 16),
Expanded(child: Text(i < signTimes.length ? signTimes[i] : '')), Expanded(
child: Text(i < signTimes.length ? signTimes[i] : ''),
),
], ],
), ),
), ),
@ -399,14 +525,20 @@ class SignaturesListWidget extends StatelessWidget {
); );
} }
Widget _buildTextareaWithSigns(BuildContext context, String label, dynamic rawList, dynamic userName, EditUserType type, {String? timeKey}) { Widget _buildTextareaWithSigns(
BuildContext context,
String label,
dynamic rawList,
dynamic userName,
EditUserType type, {
String? timeKey,
}) {
if (rawList is! List || rawList.isEmpty) return const SizedBox.shrink(); if (rawList is! List || rawList.isEmpty) return const SizedBox.shrink();
final first = (rawList as List).cast<Map<String, dynamic>>().first; final first = (rawList as List).cast<Map<String, dynamic>>().first;
final descr = first['DESCR'] is String ? first['DESCR'] as String : ''; final descr = first['DESCR'] is String ? first['DESCR'] as String : '';
final name = pd?['${type.name}_USER_NAME']; final name = pd?['${type.name}_USER_NAME'];
final personDes = type.personName; final personDes = type.personName;
final signPaths = <String>[]; final signPaths = <String>[];
final signTimes = <String>[]; final signTimes = <String>[];
if (first['SIGN_PATH'] != null) { if (first['SIGN_PATH'] != null) {
@ -422,7 +554,12 @@ class SignaturesListWidget extends StatelessWidget {
return Container( return Container(
margin: const EdgeInsets.only(top: 20), margin: const EdgeInsets.only(top: 20),
decoration: BoxDecoration(color: Colors.white,border: Border.symmetric(vertical: BorderSide(color: Colors.grey.shade300))), decoration: BoxDecoration(
color: Colors.white,
border: Border.symmetric(
vertical: BorderSide(color: Colors.grey.shade300),
),
),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -431,9 +568,17 @@ class SignaturesListWidget extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text(label, style: const TextStyle(fontWeight: FontWeight.bold)), Text(
label,
style: const TextStyle(fontWeight: FontWeight.bold),
),
const SizedBox(height: 4), const SizedBox(height: 4),
TextField(controller: TextEditingController(text: descr), maxLines: null, readOnly: true, decoration: const InputDecoration(border: InputBorder.none)), TextField(
controller: TextEditingController(text: descr),
maxLines: null,
readOnly: true,
decoration: const InputDecoration(border: InputBorder.none),
),
], ],
), ),
), ),
@ -447,11 +592,27 @@ class SignaturesListWidget extends StatelessWidget {
child: Row( child: Row(
children: [ children: [
GestureDetector( GestureDetector(
onTap: () => Navigator.of(context).push(MaterialPageRoute(builder: (_) => SingleImageViewer(imageUrl: '$baseImgPath${signPaths[i]}'))), onTap:
child: Image.network('$baseImgPath${signPaths[i]}', width: 100, height: 100, errorBuilder: (_, __, ___) => const Icon(Icons.broken_image)), () => 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), const SizedBox(width: 16),
Expanded(child: Text(i < signTimes.length ? signTimes[i] : '')), Expanded(
child: Text(i < signTimes.length ? signTimes[i] : ''),
),
], ],
), ),
), ),
@ -460,12 +621,15 @@ class SignaturesListWidget extends StatelessWidget {
); );
} }
} }
/// ///
class SelectionPopup extends StatefulWidget { class SelectionPopup extends StatefulWidget {
/// : 'assignments' 'identification' /// : 'assignments' 'identification'
final String type; final String type;
/// ///
final String initialValue; final String initialValue;
/// ///
final void Function(String) onConfirm; final void Function(String) onConfirm;
@ -514,22 +678,20 @@ class _SelectionPopupState extends State<SelectionPopup> {
} }
Future<void> _pickDate() async { Future<void> _pickDate() async {
showDialog( showDialog(
context: context, context: context,
builder: builder:
(_) => HDatePickerDialog( (_) => HDatePickerDialog(
initialDate: DateTime.now(), initialDate: DateTime.now(),
onCancel: () => Navigator.of(context).pop(), onCancel: () => Navigator.of(context).pop(),
onConfirm: (selected) { onConfirm: (selected) {
Navigator.of(context).pop(); Navigator.of(context).pop();
setState(() { setState(() {
selectedDate = selected; selectedDate = selected;
}); });
}, },
), ),
); );
} }
Future<void> _getData() async { Future<void> _getData() async {
@ -538,7 +700,8 @@ class _SelectionPopupState extends State<SelectionPopup> {
if (widget.type == 'assignments') { if (widget.type == 'assignments') {
params = { params = {
'WORK_TYPE': selectedWorkType, 'WORK_TYPE': selectedWorkType,
'KEYWORDS': selectedDate == null ? '' : selectedDate!.toString().split(' ')[0], 'KEYWORDS':
selectedDate == null ? '' : selectedDate!.toString().split(' ')[0],
'CORPINFO_ID': SessionService.instance.corpinfoId, 'CORPINFO_ID': SessionService.instance.corpinfoId,
}; };
} else { } else {
@ -567,14 +730,12 @@ class _SelectionPopupState extends State<SelectionPopup> {
item['CHECK_NO'] = (prefixMap[type] ?? '') + ' ' + no; item['CHECK_NO'] = (prefixMap[type] ?? '') + ' ' + no;
} }
}); });
} else {
}else{
final result = await ApiService.getEightWorkInfo(params); final result = await ApiService.getEightWorkInfo(params);
setState(() { setState(() {
list = (result['accidentType'] as List).cast<Map<String, dynamic>>(); list = (result['accidentType'] as List).cast<Map<String, dynamic>>();
}); });
} }
} catch (e) { } catch (e) {
ToastUtil.showError(context, '$e'); ToastUtil.showError(context, '$e');
} }
@ -582,15 +743,16 @@ class _SelectionPopupState extends State<SelectionPopup> {
void _reset() { void _reset() {
setState(() { setState(() {
selectedWorkType = ''; // 0
selectedWorkName = '请选择'; selectedWorkType = workList[0]['WORK_TYPE']!;
selectedDate = null; selectedWorkName = workList[0]['WORK_NAME']!;
selectedDate = null;
list.clear(); list.clear();
selectValue.clear(); selectValue.clear();
}); });
_getData(); _getData();
} }
void _determine() { void _determine() {
// //
final result = selectValue.join(','); final result = selectValue.join(',');
@ -610,51 +772,76 @@ class _SelectionPopupState extends State<SelectionPopup> {
children: [ children: [
// //
if (widget.type == 'assignments') if (widget.type == 'assignments')
Padding( Padding(
padding: const EdgeInsets.all(12), padding: const EdgeInsets.all(12),
child: Row( child: Row(
children: [ children: [
// //
Expanded( Expanded(
child: DropdownButton<String>( child: DropdownButton<String>(
dropdownColor: Colors.white, dropdownColor: Colors.white,
style: TextStyle(), style: TextStyle(),
isExpanded: true, isExpanded: true,
value: selectedWorkName, value: selectedWorkName,
items: workList items:
.map((e) => DropdownMenuItem( workList
value: e['WORK_NAME'], .map(
child: Text(e['WORK_NAME']!, style: TextStyle(color: Colors.black87),), (e) => DropdownMenuItem(
)) value: e['WORK_NAME'],
.toList(), child: Text(
onChanged: (v) { e['WORK_NAME']!,
final idx = workList.indexWhere((e) => e['WORK_NAME'] == v); style: TextStyle(color: Colors.black87),
if (idx >= 0) { ),
setState(() { ),
selectedWorkType = workList[idx]['WORK_TYPE']!; )
selectedWorkName = v!; .toList(),
}); onChanged: (v) {
_getData(); 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),
const SizedBox(width: 12),
TextButton(onPressed: _pickDate, child: Row( TextButton(
children: [ onPressed: _pickDate,
Text(selectedDate == null child: Row(
? '选择作业申请时间' children: [
: selectedDate!.toString().split(' ')[0],style: TextStyle(color: Colors.blue),), Text(
SizedBox(width: 5,), selectedDate == null
Icon(Icons.arrow_drop_down, color: Colors.grey, size: 20,), ], ? '选择作业申请时间'
)), : selectedDate!.toString().split(' ')[0],
style: TextStyle(color: Colors.blue),
),
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,) CustomButton(
], text: '清空',
padding: EdgeInsets.symmetric(horizontal: 15),
height: 35,
backgroundColor: Colors.blue,
onPressed: _reset,
),
],
),
), ),
),
const Divider(), const Divider(),
// //
Expanded( Expanded(
@ -664,9 +851,10 @@ class _SelectionPopupState extends State<SelectionPopup> {
itemBuilder: (c, i) { itemBuilder: (c, i) {
final item = list[i]; final item = list[i];
final value = selectValue; final value = selectValue;
final key = widget.type == 'assignments' final key =
? item['CHECK_NO'] as String? ?? '' widget.type == 'assignments'
: item['NAME'] as String? ?? ''; ? item['CHECK_NO'] as String? ?? ''
: item['NAME'] as String? ?? '';
final checked = value.contains(key); final checked = value.contains(key);
return CheckboxListTile( return CheckboxListTile(
activeColor: Colors.blue, activeColor: Colors.blue,
@ -700,11 +888,22 @@ class _SelectionPopupState extends State<SelectionPopup> {
child: Row( child: Row(
children: [ children: [
Expanded( Expanded(
child:CustomButton(text: '确定', height: 40, backgroundColor: Colors.blue, onPressed: _determine,) child: CustomButton(
text: '确定',
height: 40,
backgroundColor: Colors.blue,
onPressed: _determine,
),
), ),
const SizedBox(width: 12), const SizedBox(width: 12),
Expanded( Expanded(
child: CustomButton(text: '关闭', height: 40, backgroundColor: Colors.grey.shade300, textStyle: TextStyle(color: Colors.grey.shade600), onPressed: () => Navigator.of(context).pop(),) child: CustomButton(
text: '关闭',
height: 40,
backgroundColor: Colors.grey.shade300,
textStyle: TextStyle(color: Colors.grey.shade600),
onPressed: () => Navigator.of(context).pop(),
),
), ),
], ],
), ),

View File

@ -7,6 +7,7 @@ import 'package:qhd_prevention/customWidget/department_person_picker.dart';
import 'package:qhd_prevention/customWidget/department_picker.dart'; import 'package:qhd_prevention/customWidget/department_picker.dart';
import 'package:qhd_prevention/customWidget/toast_util.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/item_list_widget.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/WorkDetailFormWidget.dart';
import 'package:qhd_prevention/tools/tools.dart'; import 'package:qhd_prevention/tools/tools.dart';
import '../../../../../../customWidget/bottom_picker.dart'; import '../../../../../../customWidget/bottom_picker.dart';
import '../../../../../../http/ApiService.dart'; import '../../../../../../http/ApiService.dart';
@ -159,12 +160,10 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
pd['WORK_LEVEL'] = choice; pd['WORK_LEVEL'] = choice;
FocusHelper.clearFocus(context); FocusHelper.clearFocus(context);
}); });
} }
} }
Future<void> _chooseHorkUser() async{ Future<void> _chooseHorkUser() async {
final choice = await BottomPicker.show<String>( final choice = await BottomPicker.show<String>(
context, context,
items: workUserList.map((item) => item['NAME'] as String).toList(), items: workUserList.map((item) => item['NAME'] as String).toList(),
@ -176,7 +175,7 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
pd['WORK_USER'] = choice; pd['WORK_USER'] = choice;
_hotworkPersonController.text = choice; _hotworkPersonController.text = choice;
Map<String, dynamic> result = workUserList.firstWhere( Map<String, dynamic> result = workUserList.firstWhere(
(item) => item['NAME'] == choice, (item) => item['NAME'] == choice,
orElse: () => {}, // orElse: () => {}, //
); );
if (FormUtils.hasValue(result, 'USER_ID')) { if (FormUtils.hasValue(result, 'USER_ID')) {
@ -184,172 +183,9 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
} }
FocusHelper.clearFocus(context); 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) { Widget _card(Widget child) {
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
@ -361,11 +197,32 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
} }
Widget _chooseItem(EditUserType type) { Widget _chooseItem(EditUserType type) {
bool isClean = false;
if (isEditable) {
if (type == EditUserType.AUDIT && (pd['WORK_LEVEL'] ?? '') == '二级') {
isClean = true;
}
if (type == EditUserType.APPROVE &&
((pd['WORK_LEVEL'] ?? '') == '二级' ||
(pd['WORK_LEVEL'] ?? '') == '一级')) {
isClean = true;
}
}
return Column( return Column(
children: [ children: [
ItemListWidget.selectableLineTitleTextField( ItemListWidget.selectableLineTitleTextField(
label: type.displayName, label: type.displayName,
isEditable: isEditable, isEditable: isEditable,
isClean: isClean,
onTapClean: () {
setState(() {
pd['${type.name}_DEPARTMENT_NAME'] = '';
pd['${type.name}_USER_NAME'] = '';
_personCache.remove(type);
});
},
text: pd['${type.name}_DEPARTMENT_NAME'] ?? '请选择', text: pd['${type.name}_DEPARTMENT_NAME'] ?? '请选择',
onTap: () => chooseUnitHandle(type), onTap: () => chooseUnitHandle(type),
), ),
@ -416,7 +273,7 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
} }
/// ///
void choosePersonHandle(EditUserType type) async{ void choosePersonHandle(EditUserType type) async {
FocusHelper.clearFocus(context); FocusHelper.clearFocus(context);
String unitId = get_pd_DEPARTMENT_ID(type); String unitId = get_pd_DEPARTMENT_ID(type);
@ -426,17 +283,22 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
ToastUtil.showNormal(context, '请先选择$unitName'); ToastUtil.showNormal(context, '请先选择$unitName');
return; return;
} }
if (personList.isEmpty) { // if (personList.isEmpty) {
await _getPersonListForUnitId(unitId, type); //
final list = _personCache[type] ?? []; ToastUtil.showNormal(context, '请先选择' + type.displayName);
if (list.isEmpty) { //
ToastUtil.showNormal(context, '暂无数据,请选择其他单位');
}else{
choosePersonHandle(type);
}
return; return;
} }
// if (personList.isEmpty) { //
// await _getPersonListForUnitId(unitId, type);
// final list = _personCache[type] ?? [];
//
// if (list.isEmpty) { //
// ToastUtil.showNormal(context, '暂无数据,请选择其他单位');
// }else{
// choosePersonHandle(type);
// }
// return;
// }
DepartmentPersonPicker.show( DepartmentPersonPicker.show(
context, context,
personsData: personList, personsData: personList,
@ -467,6 +329,7 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
]; ];
final level = pd['WORK_LEVEL'] ?? ''; final level = pd['WORK_LEVEL'] ?? '';
print('---level-$level'); print('---level-$level');
/// ///
final unitRules = <EditUserType>[ final unitRules = <EditUserType>[
EditUserType.ANALYZE, EditUserType.ANALYZE,
@ -529,11 +392,11 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
pd['TASK_ID'] = taskId; pd['TASK_ID'] = taskId;
pd['HOTWORK_ID'] = widget.HOTWORK_ID; pd['HOTWORK_ID'] = widget.HOTWORK_ID;
pd['APPLY_DEPARTMENT_ID'] = SessionService.instance.deptId; pd['APPLY_DEPARTMENT_ID'] = SessionService.instance.deptId;
pd['APPLY_DEPARTMENT_NAME'] = SessionService.instance.loginUser?['DEPARTMENT_NAME'] ?? ''; pd['APPLY_DEPARTMENT_NAME'] =
SessionService.instance.loginUser?['DEPARTMENT_NAME'] ?? '';
pd['APPLY_USER_ID'] = SessionService.instance.loginUserId; pd['APPLY_USER_ID'] = SessionService.instance.loginUserId;
pd['APPLY_USER_NAME'] = SessionService.instance.username; pd['APPLY_USER_NAME'] = SessionService.instance.username;
pd['USER_ID'] = SessionService.instance.loginUserId; pd['USER_ID'] = SessionService.instance.loginUserId;
} }
LoadingDialogHelper.show(context); LoadingDialogHelper.show(context);
@ -552,20 +415,23 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
ToastUtil.showNormal(context, '操作失败:$e'); ToastUtil.showNormal(context, '操作失败:$e');
} }
} }
void printLongString(String text, {int chunkSize = 800}) { void printLongString(String text, {int chunkSize = 800}) {
final pattern = RegExp('.{1,$chunkSize}'); // chunkSize final pattern = RegExp('.{1,$chunkSize}'); // chunkSize
for (final match in pattern.allMatches(text)) { for (final match in pattern.allMatches(text)) {
print(match.group(0)); print(match.group(0));
} }
} }
Future<void> _getHotWorkNameList() async { Future<void> _getHotWorkNameList() async {
final result = await ApiService.getHotWorkNameList(); final result = await ApiService.getHotWorkNameList();
setState(() { setState(() {
workUserList = result['varList'] ?? ''; workUserList = result['varList'] ?? '';
List<String> names = workUserList.map((item) => item['NAME'] as String).toList(); List<String> names =
workUserList.map((item) => item['NAME'] as String).toList();
}); });
} }
/// ///
Future<void> _getData() async { Future<void> _getData() async {
final data = await ApiService.getHomeworkFindById(widget.HOTWORK_ID); final data = await ApiService.getHomeworkFindById(widget.HOTWORK_ID);
@ -584,7 +450,6 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
_hotworkPersonController.text = pd['WORK_USER'] ?? ''; _hotworkPersonController.text = pd['WORK_USER'] ?? '';
_relatedController.text = pd['SPECIAL_WORK'] ?? ''; _relatedController.text = pd['SPECIAL_WORK'] ?? '';
_riskController.text = pd['RISK_IDENTIFICATION'] ?? ''; _riskController.text = pd['RISK_IDENTIFICATION'] ?? '';
}); });
// final data = await ApiService.getHomeworkFindById(widget.HOTWORK_ID); // final data = await ApiService.getHomeworkFindById(widget.HOTWORK_ID);
// setState(() { // setState(() {
@ -622,7 +487,26 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> {
padding: EdgeInsets.all(12), padding: EdgeInsets.all(12),
child: Column( child: Column(
children: [ children: [
_card(_defaultDetail()), _card(
WorkDetailFormWidget(
pd: pd,
isEditable: isEditable,
contentController: _contentController,
locationController: _locationController,
methodController: _methodController,
hotworkPersonController: _hotworkPersonController,
relatedController: _relatedController,
riskController: _riskController,
onChooseLevel: _chooseLevel,
onChooseHotworkUser: _chooseHorkUser,
onAnalyzeTap: () {
pushPage(
HotworkGasList(HOTWORK_ID: widget.HOTWORK_ID),
context,
);
},
),
),
if (isEditable) if (isEditable)
Column( Column(
children: [ children: [

View File

@ -12,6 +12,7 @@ import 'package:qhd_prevention/pages/mine/mine_sign_page.dart';
import '../../../../../customWidget/custom_alert_dialog.dart'; import '../../../../../customWidget/custom_alert_dialog.dart';
import '../../../../../customWidget/picker/CupertinoDatePicker.dart'; import '../../../../../customWidget/picker/CupertinoDatePicker.dart';
import '../../../../../customWidget/single_image_viewer.dart';
class HomeGasTestPage extends StatefulWidget { class HomeGasTestPage extends StatefulWidget {
const HomeGasTestPage({Key? key, required this.HOTWORK_ID}) : super(key: key); const HomeGasTestPage({Key? key, required this.HOTWORK_ID}) : super(key: key);
@ -68,21 +69,29 @@ class _HomeGasTestPageState extends State<HomeGasTestPage> {
return Column( return Column(
children: [ children: [
const SizedBox(height: 10), const SizedBox(height: 10),
// const DottedLine(
// dashLength: 6.0,
// dashGapLength: 4.0,
// lineThickness: 0.5,
// dashColor: Colors.grey,
// ),
const Divider(), const Divider(),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Image.file( GestureDetector(
File(path), child: // ConstrainedBox BoxFit.contain
width: 200, ConstrainedBox(
height: 150, constraints: const BoxConstraints(
fit: BoxFit.cover, maxWidth: 200,
maxHeight: 150,
),
child: Image.file(
File(path),
//
fit: BoxFit.contain,
),
),
onTap: () {
presentOpaque(
SingleImageViewer(imageUrl: path),
context,
);
},
), ),
Column( Column(
children: [ children: [

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:qhd_prevention/customWidget/toast_util.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/home/tap/tabList/special_Wrok/dh_work_detai/hotwork_apply_detail.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/aqcs_work_detail/hotwork_safe_func_sure.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/szaq_work_detail/hotwork_set_safe_detail.dart'; import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/szaq_work_detail/hotwork_set_safe_detail.dart';
import 'package:qhd_prevention/pages/my_appbar.dart'; import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/tools/tools.dart'; import 'package:qhd_prevention/tools/tools.dart';
@ -196,7 +197,7 @@ class _SpecialWorkListPageState extends State<SpecialWorkListPage> {
await pushPage(HotworkSetSafeDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context); await pushPage(HotworkSetSafeDetail(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
break; break;
case '安全措施确认': case '安全措施确认':
routeName = '/hotwork-measures-confirm-detail'; await pushPage(HotworkSafeFuncSure(HOTWORK_ID: item['HOTWORK_ID'], flow: widget.flow), context);
break; break;
case '监护人签字': case '监护人签字':
routeName = '/hotwork-guardian-detail'; routeName = '/hotwork-guardian-detail';

View File

@ -3,15 +3,20 @@ import 'package:qhd_prevention/customWidget/custom_button.dart';
/// ///
class SafeFunctionDialog extends StatefulWidget { class SafeFunctionDialog extends StatefulWidget {
/// "PROTECTIVE_MEASURES" Map
final List<Map<String, dynamic>> data; final List<Map<String, dynamic>> data;
/// ///
final void Function(List<String> selectedMeasures) onConfirm; final List<Map<String, dynamic>> initialSelectedItems;
/// /// Map
final void Function(List<Map<String, dynamic>> selectedItems) onConfirm;
///
const SafeFunctionDialog({ const SafeFunctionDialog({
Key? key, Key? key,
required this.data, required this.data,
this.initialSelectedItems = const [],
required this.onConfirm, required this.onConfirm,
}) : super(key: key); }) : super(key: key);
@ -20,19 +25,19 @@ class SafeFunctionDialog extends StatefulWidget {
} }
class _SafeFunctionDialogState extends State<SafeFunctionDialog> { class _SafeFunctionDialogState extends State<SafeFunctionDialog> {
/// /// Map
late final List<String> _allMeasures; late final List<Map<String, dynamic>> _allItems;
/// /// Map
final List<String> _selectedMeasures = []; late final List<Map<String, dynamic>> _selectedItems;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_allMeasures = //
widget.data _allItems = widget.data;
.map((e) => e['PROTECTIVE_MEASURES'] as String? ?? '') //
.toList(); _selectedItems = List<Map<String, dynamic>>.from(widget.initialSelectedItems);
} }
@override @override
@ -41,32 +46,30 @@ class _SafeFunctionDialogState extends State<SafeFunctionDialog> {
insetPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 24), insetPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 24),
content: SizedBox( content: SizedBox(
width: MediaQuery.of(context).size.width - 24, width: MediaQuery.of(context).size.width - 24,
height: height: MediaQuery.of(context).size.height -
MediaQuery.of(context).size.height -
MediaQuery.of(context).padding.top - MediaQuery.of(context).padding.top -
MediaQuery.of(context).padding.bottom, MediaQuery.of(context).padding.bottom,
child: Column( child: Column(
children: [ children: [
Expanded( Expanded(
child: ListView.builder( child: ListView.builder(
itemCount: _allMeasures.length, itemCount: _allItems.length,
itemBuilder: (ctx, index) { itemBuilder: (ctx, index) {
final measure = _allMeasures[index]; final item = _allItems[index];
final checked = _selectedMeasures.contains(measure); final label = item['PROTECTIVE_MEASURES'] as String? ?? '';
final checked = _selectedItems.contains(item);
return CheckboxListTile( return CheckboxListTile(
//
controlAffinity: ListTileControlAffinity.leading, controlAffinity: ListTileControlAffinity.leading,
//
contentPadding: const EdgeInsets.symmetric(horizontal: 0), contentPadding: const EdgeInsets.symmetric(horizontal: 0),
activeColor: Colors.blue, activeColor: Colors.blue,
title: Text(measure, style: const TextStyle(fontSize: 14)), title: Text(label, style: const TextStyle(fontSize: 14)),
value: checked, value: checked,
onChanged: (value) { onChanged: (value) {
setState(() { setState(() {
if (value == true) { if (value == true) {
_selectedMeasures.add(measure); _selectedItems.add(item);
} else { } else {
_selectedMeasures.remove(measure); _selectedItems.remove(item);
} }
}); });
}, },
@ -83,7 +86,7 @@ class _SafeFunctionDialogState extends State<SafeFunctionDialog> {
height: 40, height: 40,
backgroundColor: Colors.blue, backgroundColor: Colors.blue,
onPressed: () { onPressed: () {
widget.onConfirm(_selectedMeasures); widget.onConfirm(_selectedItems);
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
), ),
@ -107,14 +110,21 @@ class _SafeFunctionDialogState extends State<SafeFunctionDialog> {
} }
} }
///
/// [initialSelected]
Future<void> showSafeFunctionDialog( Future<void> showSafeFunctionDialog(
BuildContext context, BuildContext context,
List<Map<String, dynamic>> data, List<Map<String, dynamic>> data,
void Function(List<String>) onConfirm, void Function(List<Map<String, dynamic>>) onConfirm, {
) { List<Map<String, dynamic>> initialSelected = const [],
}) {
return showDialog( return showDialog(
context: context, context: context,
barrierDismissible: false, barrierDismissible: false,
builder: (_) => SafeFunctionDialog(data: data, onConfirm: onConfirm), builder: (_) => SafeFunctionDialog(
data: data,
initialSelectedItems: initialSelected,
onConfirm: onConfirm,
),
); );
} }

View File

@ -12,15 +12,16 @@ 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/item_list_widget.dart';
import 'package:qhd_prevention/tools/tools.dart'; import 'package:qhd_prevention/tools/tools.dart';
import '../../../../../../customWidget/bottom_picker.dart'; import '../../../../../../customWidget/bottom_picker.dart';
import '../../../../../../customWidget/custom_alert_dialog.dart';
import '../../../../../../customWidget/single_image_viewer.dart'; import '../../../../../../customWidget/single_image_viewer.dart';
import '../../../../../../http/ApiService.dart'; import '../../../../../../http/ApiService.dart';
import '../../../../../mine/mine_sign_page.dart'; import '../../../../../mine/mine_sign_page.dart';
import '../../../../../my_appbar.dart'; import '../../../../../my_appbar.dart';
import '../../special_Wrok/dh_work_detai/MeasuresListWidget.dart'; import '../../special_Wrok/dh_work_detai/MeasuresListWidget.dart';
import '../../special_Wrok/qtfx_work_detail/hotwork_gas_list.dart'; import '../../special_Wrok/qtfx_work_detail/hotwork_gas_list.dart';
import '../WorkDetailFormWidget.dart';
import 'SafeFunctionDialog.dart'; import 'SafeFunctionDialog.dart';
///
class HotworkSetSafeDetail extends StatefulWidget { class HotworkSetSafeDetail extends StatefulWidget {
const HotworkSetSafeDetail({ const HotworkSetSafeDetail({
super.key, super.key,
@ -46,7 +47,6 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
late Map<String, dynamic> pd = {}; late Map<String, dynamic> pd = {};
late List<Map<String, dynamic>> measuresList = []; late List<Map<String, dynamic>> measuresList = [];
/// ///
late List<dynamic> workUserList = []; late List<dynamic> workUserList = [];
@ -60,128 +60,14 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
_getData(); _getData();
_getHotWorkNameList(); _getHotWorkNameList();
addMeasuresListCopy(); addMeasuresListCopy();
} }
String measuresListToJson() { String measuresListToJson() {
final List<Map<String, dynamic>> jsonList = final List<Map<String, dynamic>> jsonList =
measuresListCopy.map((item) => item.toJson()).toList(); measuresListCopy.map((item) => item.toJson()).toList();
return jsonEncode(jsonList); return jsonEncode(jsonList);
} }
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,
text: pd['WORK_CONTENT'] ?? '',
),
Divider(),
ItemListWidget.singleLineTitleText(
label: '动火地点及动火部位:',
isEditable: isEditable,
text: pd['WORK_PLACE'] ?? '',
),
Divider(),
ItemListWidget.selectableLineTitleTextField(
label: '动火作业级别',
isEditable: isEditable,
text: pd['WORK_LEVEL'] ?? '',
),
Divider(),
ItemListWidget.singleLineTitleText(
label: '动火方式:',
isEditable: isEditable,
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,
text:
pd['WORK_START_DATE'] ??
'' +
'' +
(pd['WORK_END_DATE']
? pd['WORK_END_DATE'] ?? ''
: '--') ??
'',
),
],
),
Divider(),
ItemListWidget.twoRowSelectableTitleText(
label: '动火人及证书编号:',
isEditable: isEditable,
text: pd['WORK_USER'] ?? '',
),
Divider(),
ItemListWidget.twoRowButtonTitleText(
label: '关联的其他特殊作业及安全作业票编号',
isEditable: isEditable,
onTap: ()=>{},
hintText: '请输入关联的其他特殊作业及安全作业票编号',
text: pd['SPECIAL_WORK'] ?? '',
),
Divider(),
ItemListWidget.twoRowButtonTitleText(
label: '风险辨识结果',
isEditable: isEditable,
onTap: () {},
hintText: '请输入风险辨识结果',
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) { Widget _card(Widget child) {
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
@ -214,10 +100,16 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
label: '安全措施:', label: '安全措施:',
buttonText: '选择安全措施', buttonText: '选择安全措施',
onTap: () { onTap: () {
showSafeFunctionDialog(context, measuresList, (selected) { showSafeFunctionDialog(
// context,
debugPrint('用户选择了:' + json.encode(selected)); measuresList,
}); initialSelected: item.selectMeasures,
(selected) {
setState(() {
item.selectMeasures = selected;
});
},
);
}, },
), ),
], ],
@ -226,7 +118,6 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
/// ///
void chooseUnitHandle(MeasureItem item) { void chooseUnitHandle(MeasureItem item) {
showModalBottomSheet( showModalBottomSheet(
context: context, context: context,
isScrollControlled: true, isScrollControlled: true,
@ -242,16 +133,13 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
_getPersonListForUnitId(item); _getPersonListForUnitId(item);
}, },
), ),
).then((_) { ).then((_) {});
});
} }
Future<void> _getPersonListForUnitId(MeasureItem item) async { Future<void> _getPersonListForUnitId(MeasureItem item) async {
// //
final result = await ApiService.getListTreePersonList(item.DEPARTMENT_ID); final result = await ApiService.getListTreePersonList(item.DEPARTMENT_ID);
setState(() { setState(() {
item.userList = List<Map<String, dynamic>>.from( item.userList = List<Map<String, dynamic>>.from(
result['userList'] ?? <Map<String, dynamic>>[], result['userList'] ?? <Map<String, dynamic>>[],
); );
@ -260,12 +148,10 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
/// ///
void choosePersonHandle(MeasureItem item) async { void choosePersonHandle(MeasureItem item) async {
String unitId = item.DEPARTMENT_ID; String unitId = item.DEPARTMENT_ID;
final personList = item.userList; final personList = item.userList;
if (!unitId.isNotEmpty) { if (!unitId.isNotEmpty) {
final unitName = item.DEPARTMENT_NAME; ToastUtil.showNormal(context, '请先选择确认单位');
ToastUtil.showNormal(context, '请先选择$unitName');
return; return;
} }
if (personList.isEmpty) { if (personList.isEmpty) {
@ -291,10 +177,9 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
print(json.encode(measuresListCopy)); print(json.encode(measuresListCopy));
}); });
}, },
).then((_) { ).then((_) {});
});
} }
/// ///
Future<void> _sign() async { Future<void> _sign() async {
final path = await Navigator.push( final path = await Navigator.push(
@ -311,115 +196,168 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
}); });
} }
} }
Widget _signListWidget() { Widget _signListWidget() {
return Column( return Column(
children: imagePaths.map((path) { children:
return Column( imagePaths.map((path) {
children: [ return Column(
const SizedBox(height: 10),
const Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
GestureDetector( const SizedBox(height: 10),
child: Image.file( const Divider(),
File(path), Row(
width: 200, mainAxisAlignment: MainAxisAlignment.spaceBetween,
height: 150,
fit: BoxFit.cover,
),
onTap: () {
presentOpaque(
SingleImageViewer(imageUrl:path),
context,
);
},
),
Column(
children: [ children: [
Container( GestureDetector(
padding: const EdgeInsets.only(right: 5), child: // ConstrainedBox BoxFit.contain
child: CustomButton( ConstrainedBox(
text: 'X', constraints: const BoxConstraints(
height: 30, maxWidth: 200,
padding: const EdgeInsets.symmetric(horizontal: 10), maxHeight: 150,
backgroundColor: Colors.red, ),
onPressed: () { child: Image.file(
setState(() { File(path),
imagePaths.remove(path); //
}); fit: BoxFit.contain,
}, ),
), ),
onTap: () {
presentOpaque(
SingleImageViewer(imageUrl: path),
context,
);
},
),
Column(
children: [
Container(
padding: const EdgeInsets.only(right: 5),
child: CustomButton(
text: 'X',
height: 30,
padding: const EdgeInsets.symmetric(horizontal: 10),
backgroundColor: Colors.red,
onPressed: () {
setState(() {
imagePaths.remove(path);
});
},
),
),
const SizedBox(height: 80),
],
), ),
const SizedBox(height: 80),
], ],
), ),
], ],
), );
], }).toList(),
);
}).toList(),
); );
} }
/// 1 0 /// 1 0
Future<void> _submit(String status) async { Future<void> _submit(String status) async {
// if (imagePaths.isEmpty) {
ToastUtil.showNormal(context, '请签字');
return;
}
List<Map<String, dynamic>> signers = [];
String reasonText = '';
if (status == '1') { if (status == '1') {
// // int index = 0;
// for (var rule in textRules) { for (var item in measuresListCopy) {
// if ((rule['value'] as String).isEmpty) { if (item.USER_ID.isEmpty) {
// ToastUtil.showNormal(context, rule['message']); ToastUtil.showNormal(
// return; context,
// } '${index + 1}项未设置确认人',
// } );
// // return;
// if (level.length == 0) { }
// ToastUtil.showNormal(context, '请选择动火级别'); if (item.selectMeasures.isEmpty) {
// return; ToastUtil.showNormal(
// } context,
// '${index + 1}项未选择安全措施',
// for (MeasureItem item in measuresListCopy) { );
// if (item.USER_ID.isNotEmpty) { return;
// ToastUtil.showNormal(context, '请选择确认人'); }
// return; final userId = item.USER_ID;
// } final selectMeasures = item.selectMeasures as List<dynamic>? ?? [];
// }
}
// LoadingDialogHelper.show(context);
// for (var item in selectMeasures) {
if (msg == 'add') { signers.add({
pd['CORPINFO_ID'] = SessionService.instance.corpinfoId; 'BUS_HOTWORK_MEASURES_ID': item['BUS_HOTWORK_MEASURES_ID'],
pd['CREATOR'] = SessionService.instance.loginUserId; 'USER_ID': userId,
pd['OPERATOR'] = SessionService.instance.loginUserId; });
pd['ACTION_USER'] = SessionService.instance.username; }
pd['APPLY_STATUS'] = status; //
pd['STEP_ID'] = status; if (signers.length != measuresList.length) {
pd['HOTWORK_ID'] = widget.HOTWORK_ID; // 使 ScaffoldMessenger
pd['APPLY_DEPARTMENT_ID'] = SessionService.instance.deptId; ToastUtil.showNormal(context, '请为每个安全措施选择确认人');
pd['APPLY_DEPARTMENT_NAME'] = return;
SessionService.instance.loginUser?['DEPARTMENT_NAME'] ?? ''; }
pd['APPLY_USER_ID'] = SessionService.instance.loginUserId; index++;
pd['APPLY_USER_NAME'] = SessionService.instance.username; }
pd['USER_ID'] = SessionService.instance.loginUserId; } else {
} await showDialog<String>(
context: context,
LoadingDialogHelper.show(context); builder:
String jsonStr = jsonEncode(pd); (_) => CustomAlertDialog(
printLongString(jsonStr); title: '作废原因',
try { mode: DialogMode.input,
String url = "/app/hotwork/" + msg; hintText: '请输入作废原因',
final result = await ApiService.submitHotwork(url, pd); cancelText: '取消',
LoadingDialogHelper.hide(context); confirmText: '确定',
if (result['result'] == 'success') { onInputConfirm: (text) {
ToastUtil.showSuccess(context, status == '1' ? '提交成功' : '已暂存'); reasonText = text;
Navigator.pop(context); },
),
);
if (reasonText.isEmpty) {
ToastUtil.showNormal(context, '请填写作废原因');
return;
} }
} catch (e) {
LoadingDialogHelper.hide(context);
ToastUtil.showNormal(context, '操作失败:$e');
} }
final Map<String, dynamic> formData = {};
//
formData['HOTWORK_ID'] = widget.HOTWORK_ID;
formData['SIGNTIME'] = signTimes.join(',');
formData['USER_ID'] = SessionService.instance.loginUserId;
formData['APPLY_STATUS'] = status;
formData['STEP_REASON'] = reasonText;
formData['PREPARERS'] = json.encode(signers);
await showDialog<String>(
context: context,
builder:
(_) => CustomAlertDialog(
title: '提示',
content: '请确认' + (status == '1' ? "通过" : "作废") + '本作业票?',
cancelText: '取消',
confirmText: '确定',
onConfirm: () async {
LoadingDialogHelper.show(context);
try {
final result = await ApiService.saveSafeFunctionSure(
formData,
imagePaths,
);
LoadingDialogHelper.hide(context);
if (result['result'] == 'success') {
ToastUtil.showSuccess(
context,
status == '1' ? '提交成功' : '已暂存',
);
Navigator.pop(context);
}
} catch (e) {
LoadingDialogHelper.hide(context);
ToastUtil.showNormal(context, '操作失败:$e');
}
},
),
);
} }
void printLongString(String text, {int chunkSize = 800}) { void printLongString(String text, {int chunkSize = 800}) {
@ -444,13 +382,7 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
setState(() { setState(() {
pd = data['pd']; pd = data['pd'];
_getMeasures(); _getMeasures();
}); });
// final data = await ApiService.getHomeworkFindById(widget.HOTWORK_ID);
// setState(() {
// pd = data['pd'];
// });
// LoadingDialogHelper.hide(context);
} }
Future<void> _getMeasures() async { Future<void> _getMeasures() async {
@ -535,9 +467,14 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
...item.selectMeasures.asMap().entries.map((e) { ...item.selectMeasures.asMap().entries.map((e) {
int idx = e.key; int idx = e.key;
String txt = e.value; String txt = e.value['PROTECTIVE_MEASURES'];
return Padding( return Padding(
padding: EdgeInsets.only(top: 4), padding: EdgeInsets.only(
top: 4,
left: 12,
right: 12,
bottom: 12,
),
child: Text('${idx + 1}. $txt'), child: Text('${idx + 1}. $txt'),
); );
}), }),
@ -589,7 +526,6 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
), ),
SizedBox(height: 10), SizedBox(height: 10),
if (imagePaths.isNotEmpty) _signListWidget(), if (imagePaths.isNotEmpty) _signListWidget(),
], ],
), ),
); );
@ -608,7 +544,7 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
text: '作废', text: '作废',
backgroundColor: Colors.red, backgroundColor: Colors.red,
onPressed: () { onPressed: () {
_submit('1'); _submit('-1');
}, },
), ),
), ),
@ -618,7 +554,7 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
text: '通过', text: '通过',
backgroundColor: Colors.green, backgroundColor: Colors.green,
onPressed: () { onPressed: () {
_submit('0'); _submit('1');
}, },
), ),
), ),
@ -635,8 +571,21 @@ class _HotworkSetSafeDetailState extends State<HotworkSetSafeDetail> {
padding: EdgeInsets.all(12), padding: EdgeInsets.all(12),
child: Column( child: Column(
children: [ children: [
_card(_defaultDetail()), // _card(_defaultDetail()),
_card(
WorkDetailFormWidget(
pd: pd,
isEditable: false,
onChooseLevel: (){},
onChooseHotworkUser: (){},
onAnalyzeTap: () {
pushPage(
HotworkGasList(HOTWORK_ID: widget.HOTWORK_ID),
context,
);
},
),
),
SizedBox(height: 20), SizedBox(height: 20),
_setSafeDetailWidget(), _setSafeDetailWidget(),
SizedBox(height: 20), SizedBox(height: 20),
@ -657,7 +606,7 @@ class MeasureItem {
String USER_NAME; String USER_NAME;
List<Map<String, dynamic>> userList; List<Map<String, dynamic>> userList;
int userIndex; int userIndex;
List<String> selectMeasures; List<Map<String, dynamic>> selectMeasures;
MeasureItem({ MeasureItem({
required this.id, required this.id,
@ -667,9 +616,10 @@ class MeasureItem {
this.USER_NAME = '', this.USER_NAME = '',
List<Map<String, dynamic>>? userList, List<Map<String, dynamic>>? userList,
this.userIndex = -1, this.userIndex = -1,
List<String>? selectMeasures, List<Map<String, dynamic>>? selectMeasures,
}) : userList = userList ?? [], }) : userList = userList ?? [],
selectMeasures = selectMeasures ?? []; selectMeasures = selectMeasures ?? [];
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
return { return {
'id': id, 'id': id,