设置安全措施确认人完成
parent
d672f1d944
commit
217310e511
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 143 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
|
|
@ -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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -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: [
|
||||||
|
|
|
||||||
|
|
@ -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: [
|
||||||
|
|
|
||||||
|
|
@ -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';
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue