import 'dart:io'; import 'package:flutter/material.dart'; import 'package:qhd_prevention/customWidget/custom_button.dart'; import 'package:qhd_prevention/customWidget/single_image_viewer.dart'; import 'package:qhd_prevention/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'; /// 完整翻译自你提供的 uniapp 页面逻辑。 /// 注意:下面的 ApiService 方法名(goEditII / editIsReadII / submitCorppromiseSign) /// 仅为示例占位,与你项目中实际的方法名若不同请替换。 class OtherPromisePage extends StatefulWidget { const OtherPromisePage({ super.key, required this.TabCur, required this.PROMISE_ID, required this.PROMISEPEOPLE_ID, }); final int TabCur; final String PROMISE_ID; final String PROMISEPEOPLE_ID; @override State createState() => _OtherPromisePageState(); } class _OtherPromisePageState extends State { bool _loading = true; Map info = {}; String? baseImgPath = ApiService.baseImgPath; @override void initState() { super.initState(); // 按照原 uniapp 的 onLoad:先获取数据 _loadData(); // 如果来自 TabCur == 1,需要标记为已读(uniapp 中是:if(option.TabCur=='1') this.setPromiseIsRead) if (widget.TabCur == 1) { _setPromiseIsRead(); } } Future _loadData() async { setState(() => _loading = true); try { // 请将下面的方法替换为你项目中实际的 ApiService 调用并传入 widget.PROMISE_ID / PROMISEPEOPLE_ID final res = await ApiService.getWorkshopSafetyOtherCommitmen( widget.PROMISE_ID, widget.PROMISEPEOPLE_ID, ); final coll = (res['promistDetail'] as List?) ?? (res['promistdetail'] as List?) ?? []; final DETAIL = coll .map((e) => { 'value': e?['COLLATERAL']?.toString() ?? e?['collateral']?.toString() ?? '', 'id': e?['PROMISEDETAIL_ID']?.toString() ?? e?['promiseDetail_id']?.toString() ?? '', }) .toList(); final Map merged = {}; if (res['varList'] is Map) merged.addAll(Map.from(res['varList'])); if (res['people'] is Map) merged.addAll(Map.from(res['people'])); merged['TEXT'] = res['TEXT']?.toString() ?? res['text']?.toString() ?? merged['TEXT'] ?? ''; merged['DETAIL'] = DETAIL; if (res['coverpeople'] is List && (res['coverpeople'] as List).isNotEmpty) { merged['COVERPEOPLE'] = (res['coverpeople'][0]['USERNAME'] ?? res['coverpeople'][0]['username'])?.toString() ?? ''; } else if (res['coverpeople'] is String) { merged['COVERPEOPLE'] = res['coverpeople']; } res.forEach((k, v) { if (!merged.containsKey(k)) merged[k] = v; }); merged['PROMISEPEOPLE_ID'] = res['PROMISEPEOPLE_ID'] ?? widget.PROMISEPEOPLE_ID; merged['SIGNTIME'] = merged['SIGNTIME'] ?? merged['signtime'] ?? ''; merged['CREATTIME'] = merged['CREATTIME'] ?? merged['creattime'] ?? merged['CREATTIME'] ?? ''; setState(() { info = merged; _loading = false; }); } catch (e, st) { debugPrint('加载承诺详情失败:$e\n$st'); setState(() => _loading = false); ToastUtil.showNormal(context, '加载失败,请稍后重试'); } } Future _setPromiseIsRead() async { try { await ApiService.getWorkshopSafetyOthercorppromise(widget.PROMISEPEOPLE_ID); } catch (e) { debugPrint('标记已读失败: $e'); // 不打断用户流程,uniapp 中也是静默处理失败 } } String _formatDateShort(dynamic s) { if (s == null) return ''; final str = s.toString(); if (str.length >= 10) return str.substring(0, 10); return str; } Future _sign() async { // 如果你的签字页面需要横屏,请在 MineSignPage 内或调用签字前后处理屏幕方向。 // 下面直接跳转并等待返回签名图片路径(String),与原 uniapp 的行为一致。 final result = await Navigator.push( context, MaterialPageRoute(builder: (_) => const MineSignPage()), ); if (result != null && result.isNotEmpty) { setState(() { info['FILEPATH'] = result; }); // 清除焦点,防止键盘/输入问题 FocusScope.of(context).unfocus(); } } Future submitSignedPromise() async { final filePath = (info['FILEPATH'] ?? '').toString(); if (filePath.isEmpty) { ToastUtil.showNormal(context, '请签字'); return; } try { LoadingDialogHelper.show(); // 请替换为你项目的实际提交方法和参数;下面示例使用 submitCorppromiseSign(filePath, info) final res = await ApiService.submitCorppromiseSign(filePath, info); LoadingDialogHelper.hide(); if (res is Map && (res['result'] == 'success' || res['code'] == 0 || res['status'] == 'success')) { ToastUtil.showSuccess(context, '提交成功'); // 和 uniapp 行为类似:提交后导航回主页面 Navigator.pushReplacement(context, MaterialPageRoute(builder: (_) => const MainPage())); } else { final msg = (res is Map) ? (res['message'] ?? res['msg'] ?? '提交失败') : '提交失败'; ToastUtil.showNormal(context, msg.toString()); } } catch (e, st) { LoadingDialogHelper.hide(); debugPrint('提交签字失败:$e\n$st'); ToastUtil.showNormal(context, '提交失败,请重试'); } } 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)), 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') || signImagePath.startsWith('https'))) { signPreview = Image.network( signImagePath, width: 100, height: 50, fit: BoxFit.cover, ); } else if (signImagePath.isNotEmpty && File(signImagePath).existsSync()) { signPreview = Image.file( File(signImagePath), width: 100, height: 50, fit: BoxFit.cover, ); } else if (signImagePath.isNotEmpty && baseImgPath != null) { // 如果后端只给了相对路径,前端需要拼接 baseImgPath signPreview = Image.network( '${baseImgPath!}$signImagePath', width: 100, height: 50, fit: BoxFit.cover, ); } else { signPreview = const SizedBox(width: 100, height: 50); } 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(width: 8), GestureDetector( onTap: () { if ((info['FILEPATH'] ?? '').toString().isNotEmpty) { presentOpaque( SingleImageViewer(imageUrl: info['FILEPATH'] ?? ''), context, ); } }, child: signPreview, ), ], ), ), ], ), const SizedBox(height: 10), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const SizedBox(), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [Text(signTime.isNotEmpty ? _formatDateShort(signTime) : '')], ), ], ), ], ), ); } @override Widget build(BuildContext context) { return Scaffold( appBar: const MyAppbar(title: '安全承诺'), 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: [ Center(child: _buildTitle()), _buildHeaderName(), _buildParagraph(info['TEXT']?.toString() ?? ''), _buildCollateralList(), if ((info['TYPE'] ?? '').toString() == '0') ...[ _buildParagraph( '若违反上述承诺和未履行安全生产职责,或发生责任事故的,接受政府或公司事故调查组做出的处罚决定。', ), _buildParagraph( '承诺期限自${_formatDateShort(info['PROMISE_TERM_START'])}至${_formatDateShort(info['PROMISE_TERM_END'])}。', ), ] else ...[ _buildParagraph( '若未履行安全生产职责,或发生生产安全事故的,接受公司或政府事故调查组做出的处罚。', ), _buildParagraph( '责任期限自${_formatDateShort(info['PROMISE_TERM_START'])}至${_formatDateShort(info['PROMISE_TERM_END'])}。', ), ], const SizedBox(height: 8), _buildFooter(), ], ), ), ), ); } }