352 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Dart
		
	
	
			
		
		
	
	
			352 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Dart
		
	
	
| import 'dart:convert';
 | ||
| import 'dart:io';
 | ||
| import 'package:flutter/material.dart';
 | ||
| import 'package:intl/intl.dart';
 | ||
| import 'package:qhd_prevention/customWidget/custom_button.dart';
 | ||
| import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
 | ||
| import 'package:qhd_prevention/pages/main_tab.dart';
 | ||
| import 'package:qhd_prevention/pages/mine/mine_sign_page.dart';
 | ||
| import 'package:qhd_prevention/pages/my_appbar.dart';
 | ||
| import 'package:qhd_prevention/customWidget/toast_util.dart';
 | ||
| import 'package:qhd_prevention/http/ApiService.dart';
 | ||
| import 'package:qhd_prevention/tools/tools.dart';
 | ||
| 
 | ||
| class PromisePage extends StatefulWidget {
 | ||
|   const PromisePage({super.key});
 | ||
| 
 | ||
|   @override
 | ||
|   State<PromisePage> createState() => _PromisePageState();
 | ||
| }
 | ||
| 
 | ||
| class _PromisePageState extends State<PromisePage> {
 | ||
|   bool _loading = true;
 | ||
| 
 | ||
|   Map<String, dynamic> info = {};
 | ||
|   String? baseImgPath;
 | ||
| 
 | ||
|   @override
 | ||
|   void initState() {
 | ||
|     super.initState();
 | ||
|     _loadData();
 | ||
|   }
 | ||
| 
 | ||
|   Future<void> _loadData() async {
 | ||
|     setState(() {
 | ||
|       _loading = true;
 | ||
|     });
 | ||
| 
 | ||
|     try {
 | ||
|       final Map<String, dynamic> payload =
 | ||
|           await ApiService.safeCorppromiseDetail();
 | ||
| 
 | ||
|       final coll = (payload['COLLATERAL'] as List?) ?? [];
 | ||
|       final DETAIL =
 | ||
|           coll.map((e) {
 | ||
|             return {
 | ||
|               'value': e?['COLLATERAL']?.toString() ?? '',
 | ||
|               'id': e?['PROMISEDETAIL_ID']?.toString() ?? '',
 | ||
|             };
 | ||
|           }).toList();
 | ||
| 
 | ||
|       final Map<String, dynamic> resolved = {};
 | ||
|       if (payload['TEXT'] is Map) {
 | ||
|         resolved.addAll(payload['TEXT'] as Map<String, dynamic>);
 | ||
|       } else {
 | ||
|         resolved['TEXT'] = payload['TEXT']?.toString() ?? '';
 | ||
|       }
 | ||
|       resolved['DETAIL'] = DETAIL;
 | ||
|       resolved['SIGNTIME'] = DateFormat('yyyy-MM-dd').format(DateTime.now());
 | ||
| 
 | ||
|       resolved['COVERPEOPLE'] =
 | ||
|           (payload['COVERPEOPLE'] is List && payload['COVERPEOPLE'].isNotEmpty)
 | ||
|               ? payload['COVERPEOPLE'][0]['USERNAME']?.toString() ?? ''
 | ||
|               : '';
 | ||
|       // 合并其他顶层字段(保留现有字段)
 | ||
|       if (payload is Map<String, dynamic>) {
 | ||
|         payload.forEach((k, v) {
 | ||
|           if (!resolved.containsKey(k)) resolved[k] = v;
 | ||
|         });
 | ||
|       }
 | ||
|       resolved['PROMISEPEOPLE_ID'] = payload['PROMISEPEOPLE_ID'] ?? '';
 | ||
| 
 | ||
|       setState(() {
 | ||
|         info = resolved;
 | ||
|         _loading = false;
 | ||
|       });
 | ||
|     } catch (e, st) {
 | ||
|       debugPrint('safeCorppromiseDetail error: $e\n$st');
 | ||
|       setState(() {
 | ||
|         _loading = false;
 | ||
|       });
 | ||
|       ToastUtil.showNormal(context, '加载失败,请稍后重试');
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   String _formatDateShort(String? s) {
 | ||
|     if (s == null) return '';
 | ||
|     if (s.length >= 10) return s.substring(0, 10);
 | ||
|     return s;
 | ||
|   }
 | ||
| 
 | ||
|   // 点击签字:导航到你自己实现的签字页面,等待返回签字路径(String)
 | ||
|   Future<void> _sign() async {
 | ||
|     await NativeOrientation.setLandscape();
 | ||
|     final String path = await Navigator.push(
 | ||
|       context,
 | ||
|       MaterialPageRoute(builder: (c) => MineSignPage()),
 | ||
|     );
 | ||
|     await NativeOrientation.setPortrait();
 | ||
| 
 | ||
|     if (path != null) {
 | ||
|       setState(() {
 | ||
|         info['FILEPATH'] = path;
 | ||
|       });
 | ||
|       //FocusHelper.clearFocus(context);
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   // 提交:占位实现 —— 请把下面的逻辑替换为你项目的上传/提交 API(例如 ApiService.editPeopleII 或类似)
 | ||
|   Future<void> submitSignedPromise() async {
 | ||
|     LoadingDialogHelper.show();
 | ||
|     final filePath = (info['FILEPATH'] ?? '').toString();
 | ||
|     if (filePath.isEmpty) {
 | ||
|       ToastUtil.showNormal(context, '请签字');
 | ||
|       return;
 | ||
|     }
 | ||
|     final result = await ApiService.submitCorppromiseSign(filePath,info);
 | ||
|     LoadingDialogHelper.hide();
 | ||
|     if (result['result'] == 'success') {
 | ||
|       ToastUtil.showSuccess(context, '提交成功');
 | ||
|       Navigator.pushReplacement(
 | ||
|         context,
 | ||
|         MaterialPageRoute(builder: (_) => const MainPage()),
 | ||
|       );
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   Widget _buildTitle() {
 | ||
|     final type = (info['TYPE'] ?? '').toString();
 | ||
|     final title = type == '0' ? '安全生产承诺书' : '安全生产责任状';
 | ||
|     return Padding(
 | ||
|       padding: const EdgeInsets.symmetric(vertical: 12.0),
 | ||
|       child: Text(
 | ||
|         title,
 | ||
|         style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold),
 | ||
|         textAlign: TextAlign.center,
 | ||
|       ),
 | ||
|     );
 | ||
|   }
 | ||
| 
 | ||
|   Widget _buildHeaderName() {
 | ||
|     final type = (info['TYPE'] ?? '').toString();
 | ||
|     if (type == '0') {
 | ||
|       return Padding(
 | ||
|         padding: const EdgeInsets.symmetric(vertical: 8.0),
 | ||
|         child: Text(
 | ||
|           '${info['COVERPEOPLE'] ?? ''}:',
 | ||
|           style: const TextStyle(fontSize: 16),
 | ||
|         ),
 | ||
|       );
 | ||
|     }
 | ||
|     return const SizedBox.shrink();
 | ||
|   }
 | ||
| 
 | ||
|   Widget _buildParagraph(String text) {
 | ||
|     return Padding(
 | ||
|       padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 8.0),
 | ||
|       child: RichText(
 | ||
|         textAlign: TextAlign.justify,
 | ||
|         text: TextSpan(
 | ||
|           style: const TextStyle(
 | ||
|             height: 1.6,
 | ||
|             letterSpacing: 0.5,
 | ||
|             color: Colors.black,
 | ||
|           ),
 | ||
|           children: [
 | ||
|             const WidgetSpan(
 | ||
|               child: SizedBox(width: 28), // 缩进2个汉字宽度
 | ||
|             ),
 | ||
|             TextSpan(text: text),
 | ||
|           ],
 | ||
|         ),
 | ||
|       ),
 | ||
|     );
 | ||
|   }
 | ||
| 
 | ||
|   Widget _buildCollateralList() {
 | ||
|     final detail = (info['DETAIL'] as List?) ?? [];
 | ||
|     if (detail.isEmpty) return const SizedBox.shrink();
 | ||
|     return Padding(
 | ||
|       padding: const EdgeInsets.only(left: 0, right: 8.0, top: 6.0),
 | ||
|       child: Column(
 | ||
|         crossAxisAlignment: CrossAxisAlignment.start,
 | ||
|         children:
 | ||
|             detail.map((e) {
 | ||
|               return _buildParagraph(e['value']?.toString() ?? '');
 | ||
|             }).toList(),
 | ||
|       ),
 | ||
|     );
 | ||
|   }
 | ||
| 
 | ||
|   Widget _buildFooter() {
 | ||
|     final type = (info['TYPE'] ?? '').toString();
 | ||
|     final signImagePath = (info['FILEPATH'] ?? '').toString();
 | ||
|     final signTime = (info['SIGNTIME'] ?? '').toString();
 | ||
|     final creatTime = (info['CREATTIME'] ?? '').toString();
 | ||
| 
 | ||
|     Widget signPreview;
 | ||
|     if (signImagePath.isNotEmpty && signImagePath.startsWith('http')) {
 | ||
|       signPreview = Image.network(
 | ||
|         (baseImgPath ?? '') + signImagePath,
 | ||
|         width: 100,
 | ||
|         height: 50,
 | ||
|         fit: BoxFit.fill,
 | ||
|       );
 | ||
|     } else if (signImagePath.isNotEmpty && File(signImagePath).existsSync()) {
 | ||
|       signPreview = Image.file(
 | ||
|         File(signImagePath),
 | ||
|         width: 100,
 | ||
|         height: 50,
 | ||
|         fit: BoxFit.fill,
 | ||
|       );
 | ||
|     } else {
 | ||
|       signPreview = const SizedBox.shrink();
 | ||
|     }
 | ||
| 
 | ||
|     return Padding(
 | ||
|       padding: const EdgeInsets.only(
 | ||
|         top: 12.0,
 | ||
|         left: 8.0,
 | ||
|         right: 8.0,
 | ||
|         bottom: 20.0,
 | ||
|       ),
 | ||
|       child: Column(
 | ||
|         crossAxisAlignment: CrossAxisAlignment.stretch,
 | ||
|         children: [
 | ||
|           if (type == '0')
 | ||
|             const Align(
 | ||
|               alignment: Alignment.centerRight,
 | ||
|               child: Text('承诺单位(盖章):'),
 | ||
|             ),
 | ||
|           if (type == '1')
 | ||
|             Column(
 | ||
|               crossAxisAlignment: CrossAxisAlignment.end,
 | ||
|               children: [
 | ||
|                 Text('发状人:${info['COVERPEOPLE'] ?? ''}'),
 | ||
|                 const SizedBox(height: 6),
 | ||
|                 Text(creatTime.isNotEmpty ? _formatDateShort(creatTime) : ''),
 | ||
|               ],
 | ||
|             ),
 | ||
|           const SizedBox(height: 12),
 | ||
|           Row(
 | ||
|             mainAxisAlignment: MainAxisAlignment.spaceBetween,
 | ||
|             children: [
 | ||
|               Expanded(
 | ||
|                 child: Row(
 | ||
|                   crossAxisAlignment: CrossAxisAlignment.end,
 | ||
|                   mainAxisAlignment: MainAxisAlignment.end,
 | ||
|                   children: [
 | ||
|                     Text(type == '0' ? '主要负责人签字:' : '受状人:'),
 | ||
|                     const SizedBox(height: 8),
 | ||
|                     GestureDetector(
 | ||
|                       onTap: () {
 | ||
|                         presentOpaque(
 | ||
|                           SingleImageViewer(imageUrl: info['FILEPATH'] ?? ''),
 | ||
|                           context,
 | ||
|                         );
 | ||
|                       },
 | ||
|                       child: signPreview,
 | ||
|                     ),
 | ||
|                     const SizedBox(height: 8),
 | ||
|                     CustomButton(
 | ||
|                       text:
 | ||
|                           (info['FILEPATH'] ?? '').toString().isNotEmpty
 | ||
|                               ? '重签'
 | ||
|                               : '手写签字',
 | ||
|                       backgroundColor: Colors.blue,
 | ||
|                       padding: EdgeInsets.symmetric(
 | ||
|                         vertical: 0,
 | ||
|                         horizontal: 20,
 | ||
|                       ),
 | ||
|                       height: 35,
 | ||
|                       onPressed: _sign,
 | ||
|                     ),
 | ||
|                   ],
 | ||
|                 ),
 | ||
|               ),
 | ||
|             ],
 | ||
|           ),
 | ||
|           const SizedBox(height: 10),
 | ||
|           Row(
 | ||
|             mainAxisAlignment: MainAxisAlignment.spaceBetween,
 | ||
|             children: [
 | ||
|               const SizedBox(),
 | ||
|               Column(
 | ||
|                 crossAxisAlignment: CrossAxisAlignment.end,
 | ||
|                 children: [Text(signTime)],
 | ||
|               ),
 | ||
|             ],
 | ||
|           ),
 | ||
|         ],
 | ||
|       ),
 | ||
|     );
 | ||
|   }
 | ||
| 
 | ||
|   @override
 | ||
|   Widget build(BuildContext context) {
 | ||
|     return Scaffold(
 | ||
|       appBar: const MyAppbar(title: '安全承诺', isBack: false),
 | ||
|       body:
 | ||
|           _loading
 | ||
|               ? const Center(child: CircularProgressIndicator())
 | ||
|               : SingleChildScrollView(
 | ||
|                 child: Container(
 | ||
|                   color: Colors.white,
 | ||
|                   padding: const EdgeInsets.symmetric(
 | ||
|                     horizontal: 12,
 | ||
|                     vertical: 5,
 | ||
|                   ),
 | ||
|                   child: Column(
 | ||
|                     crossAxisAlignment: CrossAxisAlignment.start,
 | ||
|                     children: [
 | ||
|                       Row(
 | ||
|                         mainAxisAlignment: MainAxisAlignment.center,
 | ||
|                         children: [_buildTitle()],
 | ||
|                       ),
 | ||
|                       _buildHeaderName(),
 | ||
|                       _buildParagraph(info['TEXT']?.toString() ?? ''),
 | ||
|                       _buildCollateralList(),
 | ||
|                       if ((info['TYPE'] ?? '').toString() == '0') ...[
 | ||
|                         _buildParagraph(
 | ||
|                           '若违反上述承诺和未履行安全生产职责,或发生责任事故的,接受政府或公司事故调查组做出的处罚决定。',
 | ||
|                         ),
 | ||
|                         _buildParagraph(
 | ||
|                           '承诺期限自${_formatDateShort(info['PROMISE_TERM_START']?.toString())}至${_formatDateShort(info['PROMISE_TERM_END']?.toString())}。',
 | ||
|                         ),
 | ||
|                       ] else ...[
 | ||
|                         _buildParagraph(
 | ||
|                           '若未履行安全生产职责,或发生生产安全事故的,接受公司或政府事故调查组做出的处罚。',
 | ||
|                         ),
 | ||
|                         _buildParagraph(
 | ||
|                           '责任期限自${_formatDateShort(info['PROMISE_TERM_START']?.toString())}至${_formatDateShort(info['PROMISE_TERM_END']?.toString())}。',
 | ||
|                         ),
 | ||
|                       ],
 | ||
|                       const SizedBox(height: 8),
 | ||
|                       _buildFooter(),
 | ||
|                       const SizedBox(height: 12),
 | ||
|                       SizedBox(
 | ||
|                         width: double.infinity,
 | ||
|                         child: CustomButton(
 | ||
|                           text: '提 交',
 | ||
|                           backgroundColor: Colors.blue,
 | ||
|                           onPressed: submitSignedPromise,
 | ||
|                         ),
 | ||
|                       ),
 | ||
|                     ],
 | ||
|                   ),
 | ||
|                 ),
 | ||
|               ),
 | ||
|     );
 | ||
|   }
 | ||
| }
 |