2026-03-06 17:59:44 +08:00
|
|
|
|
|
|
|
|
|
|
import 'dart:io';
|
|
|
|
|
|
|
|
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
|
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
|
|
|
|
|
|
import 'package:qhd_prevention/customWidget/custom_button.dart';
|
|
|
|
|
|
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
|
|
|
|
|
|
import 'package:qhd_prevention/customWidget/toast_util.dart';
|
|
|
|
|
|
import 'package:qhd_prevention/pages/mine/mine_sign_page.dart';
|
|
|
|
|
|
import 'package:qhd_prevention/pages/my_appbar.dart';
|
|
|
|
|
|
import 'package:qhd_prevention/services/SessionService.dart';
|
|
|
|
|
|
import 'package:qhd_prevention/tools/tools.dart';
|
|
|
|
|
|
import 'package:webview_flutter/webview_flutter.dart';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SignInstructionsWebview extends StatefulWidget {
|
|
|
|
|
|
final String url;
|
|
|
|
|
|
final String name;
|
|
|
|
|
|
|
|
|
|
|
|
const SignInstructionsWebview({Key? key, required this.url, required this.name,}) : super(key: key);
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
State<SignInstructionsWebview> createState() => _SignInstructionsWebviewState(name);
|
|
|
|
|
|
|
|
|
|
|
|
// _SignInstructionsWebviewState(this.name);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class _SignInstructionsWebviewState extends State<SignInstructionsWebview> {
|
|
|
|
|
|
late final WebViewController _controller;
|
|
|
|
|
|
final String name;
|
|
|
|
|
|
ValueNotifier<double> loadingProgress = ValueNotifier(0.0);
|
|
|
|
|
|
ValueNotifier<bool> isLoading = ValueNotifier(true);
|
|
|
|
|
|
|
|
|
|
|
|
_SignInstructionsWebviewState(this.name);
|
|
|
|
|
|
|
|
|
|
|
|
List<String> signImages = [];
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-04-02 10:35:41 +08:00
|
|
|
|
final String noticeContent = '''
|
|
|
|
|
|
欢迎您到访秦皇岛港。为保障您的人身安全及港口生产作业秩序,请注意港口属于重点安全监管区域,存在大型机械作业、货物装卸、车辆往来等生产场景,可能面临机械伤害、物体打击、车辆碰撞等安全风险。请您认真阅读以下须知内容,确认遵守后签字:
|
|
|
|
|
|
|
|
|
|
|
|
1.入港时请主动出示有效身份证件,配合安保人员进行身份核验与信息登记,凭港口核发的《临时访客证》入港,自觉接受出港查验;不转借、冒用访客凭证,不将无关人员带入港口。
|
|
|
|
|
|
|
|
|
|
|
|
2.入港后请严格在指定区域活动,未经陪同人员及港口负责人许可,绝不擅自进入标有"禁止入内""危险区域"等标识的场所,不靠近起重机械、输送设备、危险品存储点等高危险部位,不跨越安全护栏、警戒线,不在作业区域逗留围观。
|
|
|
|
|
|
|
|
|
|
|
|
3.遵守港口生产秩序,不干扰装卸、运输、检修等正常工作;不随意触摸、操作生产设备、仪器仪表及安全设施,不移动、遮挡安全警示标识;如需拍摄港口场景须提前征得港口方同意,不拍摄涉及安全、商业秘密的内容。
|
|
|
|
|
|
|
|
|
|
|
|
4.严格遵守消防安全规定,不在港口内吸烟,不携带火种、易燃易爆物品、管制器具等违禁物品入港;发现火灾、设备故障等隐患或突发情况,第一时间告知陪同人员或港口工作人员,配合应急处置,不擅自行动引发次生风险。
|
|
|
|
|
|
|
|
|
|
|
|
5.注意自身安全防护,行走时主动避让作业车辆与机械,不擅自横穿作业通道;雨天、雾天等恶劣天气下,听从陪同人员安排,加强安全防范。
|
|
|
|
|
|
|
|
|
|
|
|
6.已知晓港口所去区域应急逃生路线,遇紧急情况按港口指引有序疏散。
|
|
|
|
|
|
|
|
|
|
|
|
本人确认已完整阅读并理解以上须知,承诺严格遵守。如因违反本须知及港口安全规定导致自身人身伤害或港口、他人财产损失,自愿承担全部责任。
|
|
|
|
|
|
''';
|
|
|
|
|
|
|
2026-03-06 17:59:44 +08:00
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
void initState() {
|
|
|
|
|
|
super.initState();
|
|
|
|
|
|
_controller = WebViewController()
|
|
|
|
|
|
..setJavaScriptMode(JavaScriptMode.unrestricted)
|
|
|
|
|
|
..setNavigationDelegate(NavigationDelegate(
|
|
|
|
|
|
onProgress: (progress) {
|
|
|
|
|
|
loadingProgress.value = progress / 100;
|
|
|
|
|
|
if (progress == 100) isLoading.value = false;
|
|
|
|
|
|
},
|
|
|
|
|
|
onPageStarted: (url) => isLoading.value = true,
|
|
|
|
|
|
onPageFinished: (url) => isLoading.value = false,
|
|
|
|
|
|
))
|
|
|
|
|
|
..loadRequest(Uri.parse(widget.url));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
|
return
|
|
|
|
|
|
Container(
|
|
|
|
|
|
color: Colors.white,
|
|
|
|
|
|
padding: EdgeInsets.only(bottom: 10),
|
|
|
|
|
|
child: Column(
|
|
|
|
|
|
children: [
|
|
|
|
|
|
MyAppbar(title: name,onBackPressed: () async {
|
|
|
|
|
|
if (await _controller.canGoBack()) {
|
|
|
|
|
|
_controller.goBack();
|
|
|
|
|
|
} else{
|
|
|
|
|
|
Navigator.of(context).pop();
|
|
|
|
|
|
}
|
|
|
|
|
|
},),
|
2026-04-02 10:35:41 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Expanded(
|
|
|
|
|
|
child:SingleChildScrollView(
|
|
|
|
|
|
padding: const EdgeInsets.all(20),
|
|
|
|
|
|
child: Text(
|
|
|
|
|
|
noticeContent,
|
|
|
|
|
|
style: const TextStyle(
|
|
|
|
|
|
fontSize: 14,
|
|
|
|
|
|
height: 1.6,
|
|
|
|
|
|
color: Colors.black87,
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
|
|
// Expanded( child: WebViewWidget(controller: _controller),),
|
|
|
|
|
|
|
2026-03-06 17:59:44 +08:00
|
|
|
|
// ValueListenableBuilder<bool>(
|
|
|
|
|
|
// valueListenable: isLoading,
|
|
|
|
|
|
// builder: (context, loading, _) {
|
|
|
|
|
|
// return loading
|
|
|
|
|
|
// ? const Center(child: CircularProgressIndicator())
|
|
|
|
|
|
// : const SizedBox();
|
|
|
|
|
|
// },
|
|
|
|
|
|
// ),
|
|
|
|
|
|
|
|
|
|
|
|
SizedBox(height: 5,),
|
|
|
|
|
|
|
|
|
|
|
|
Container(
|
|
|
|
|
|
padding: EdgeInsets.symmetric(horizontal: 12),
|
|
|
|
|
|
child: Row(
|
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
|
|
|
children: [
|
|
|
|
|
|
ListItemFactory.headerTitle('签字:', isRequired: true),
|
|
|
|
|
|
CustomButton(
|
|
|
|
|
|
text: signImages.isNotEmpty ? '重新签字' : '手写签字',
|
|
|
|
|
|
height: 36,
|
|
|
|
|
|
backgroundColor: Colors.blue,
|
|
|
|
|
|
onPressed: _sign,
|
|
|
|
|
|
),
|
|
|
|
|
|
],
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
|
|
if (signImages.isNotEmpty) _signListWidget(),
|
|
|
|
|
|
|
|
|
|
|
|
SizedBox(height: 10,),
|
|
|
|
|
|
CustomButton(
|
|
|
|
|
|
text: '完成',
|
|
|
|
|
|
margin: EdgeInsets.symmetric(horizontal: 10),
|
|
|
|
|
|
padding: const EdgeInsets.symmetric(
|
|
|
|
|
|
vertical: 10,
|
|
|
|
|
|
horizontal: 10,
|
|
|
|
|
|
),
|
|
|
|
|
|
height: 40,
|
|
|
|
|
|
backgroundColor: Colors.blue,
|
|
|
|
|
|
onPressed: () {
|
|
|
|
|
|
if( signImages.isEmpty){
|
|
|
|
|
|
ToastUtil.showNormal(context, '请先签字');
|
2026-03-23 08:41:16 +08:00
|
|
|
|
return;
|
2026-03-06 17:59:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Navigator.pop(context, signImages[0]);
|
|
|
|
|
|
},
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Widget _signListWidget() {
|
|
|
|
|
|
return Column(
|
|
|
|
|
|
children:
|
|
|
|
|
|
signImages.map((path) {
|
|
|
|
|
|
return Column(
|
|
|
|
|
|
children: [
|
|
|
|
|
|
const SizedBox(height: 15),
|
|
|
|
|
|
// 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(() {
|
|
|
|
|
|
signImages.remove(path);
|
|
|
|
|
|
});
|
|
|
|
|
|
},
|
|
|
|
|
|
),
|
|
|
|
|
|
),
|
|
|
|
|
|
const SizedBox(height: 80),
|
|
|
|
|
|
],
|
|
|
|
|
|
),
|
|
|
|
|
|
],
|
|
|
|
|
|
),
|
|
|
|
|
|
],
|
|
|
|
|
|
);
|
|
|
|
|
|
}).toList(),
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// 签字
|
|
|
|
|
|
Future<void> _sign() async {
|
|
|
|
|
|
|
|
|
|
|
|
await NativeOrientation.setLandscape();
|
|
|
|
|
|
final path = await Navigator.push(
|
|
|
|
|
|
context,
|
|
|
|
|
|
MaterialPageRoute(builder: (context) => MineSignPage()),
|
|
|
|
|
|
);
|
|
|
|
|
|
await NativeOrientation.setPortrait();
|
|
|
|
|
|
if (path != null) {
|
|
|
|
|
|
setState(() {
|
|
|
|
|
|
signImages = [];
|
|
|
|
|
|
signImages.add(path);
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|