356 lines
12 KiB
Dart
356 lines
12 KiB
Dart
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<OtherPromisePage> createState() => _OtherPromisePageState();
|
||
}
|
||
|
||
class _OtherPromisePageState extends State<OtherPromisePage> {
|
||
bool _loading = true;
|
||
Map<String, dynamic> 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<void> _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<String, dynamic> merged = {};
|
||
|
||
if (res['varList'] is Map) merged.addAll(Map<String, dynamic>.from(res['varList']));
|
||
if (res['people'] is Map) merged.addAll(Map<String, dynamic>.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<void> _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<void> _sign() async {
|
||
// 如果你的签字页面需要横屏,请在 MineSignPage 内或调用签字前后处理屏幕方向。
|
||
// 下面直接跳转并等待返回签名图片路径(String),与原 uniapp 的行为一致。
|
||
final result = await Navigator.push<String>(
|
||
context,
|
||
MaterialPageRoute(builder: (_) => const MineSignPage()),
|
||
);
|
||
|
||
if (result != null && result.isNotEmpty) {
|
||
setState(() {
|
||
info['FILEPATH'] = result;
|
||
});
|
||
// 清除焦点,防止键盘/输入问题
|
||
FocusScope.of(context).unfocus();
|
||
}
|
||
}
|
||
|
||
Future<void> 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<Widget>((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(),
|
||
|
||
],
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|