Merge remote-tracking branch 'origin/master'
# Conflicts: # lib/pages/home/home_page.dartmaster
commit
63d5bbf943
Binary file not shown.
|
After Width: | Height: | Size: 72 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
|
|
@ -910,11 +910,13 @@ class ItemListWidget {
|
||||||
bool isRequired = false,
|
bool isRequired = false,
|
||||||
String text = '',
|
String text = '',
|
||||||
void Function(String)? onTapCallBack,
|
void Function(String)? onTapCallBack,
|
||||||
|
double verticalInset = vertical_inset,
|
||||||
|
double horizontalInset = horizontal_inset,
|
||||||
}) {
|
}) {
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: EdgeInsets.symmetric(
|
||||||
vertical: vertical_inset,
|
vertical: verticalInset,
|
||||||
horizontal: horizontal_inset,
|
horizontal: horizontalInset,
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
|
@ -994,6 +996,8 @@ class ItemListWidget {
|
||||||
double fontSize = 14, // 字体大小
|
double fontSize = 14, // 字体大小
|
||||||
void Function(String)? onTapCallBack,
|
void Function(String)? onTapCallBack,
|
||||||
bool isRequired = true,
|
bool isRequired = true,
|
||||||
|
double verticalInset = vertical_inset,
|
||||||
|
double horizontalInset = horizontal_inset,
|
||||||
}) {
|
}) {
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
|
@ -1002,9 +1006,9 @@ class ItemListWidget {
|
||||||
// 标题部分
|
// 标题部分
|
||||||
if (title.isNotEmpty)
|
if (title.isNotEmpty)
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: EdgeInsets.symmetric(
|
||||||
vertical: vertical_inset,
|
vertical: verticalInset,
|
||||||
horizontal: horizontal_inset,
|
horizontal: horizontalInset,
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
title,
|
title,
|
||||||
|
|
@ -1263,11 +1267,13 @@ class ItemListWidget {
|
||||||
required String text, // 显示内容或提示
|
required String text, // 显示内容或提示
|
||||||
double fontSize = 14, // 字体大小
|
double fontSize = 14, // 字体大小
|
||||||
bool isRequired = true,
|
bool isRequired = true,
|
||||||
|
double verticalInset = vertical_inset,
|
||||||
|
double horizontalInset = horizontal_inset,
|
||||||
}) {
|
}) {
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: EdgeInsets.symmetric(
|
||||||
vertical: vertical_inset,
|
vertical: verticalInset,
|
||||||
horizontal: horizontal_inset,
|
horizontal: horizontalInset,
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,563 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/bottom_picker.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/custom_button.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/item_list_widget.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/photo_picker_row.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/toast_util.dart';
|
||||||
|
import 'package:qhd_prevention/http/ApiService.dart';
|
||||||
|
import 'package:qhd_prevention/http/modules/basic_info_api.dart';
|
||||||
|
|
||||||
|
import 'package:qhd_prevention/pages/home/doorAndCar/sign_instructions_webView.dart';
|
||||||
|
import 'package:qhd_prevention/pages/mine/mine_sign_page.dart';
|
||||||
|
import 'package:qhd_prevention/pages/mine/webViewPage.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:flutter/gestures.dart';
|
||||||
|
|
||||||
|
class DoorareaCarAddPage extends StatefulWidget {
|
||||||
|
const DoorareaCarAddPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<DoorareaCarAddPage> createState() => _DoorareaCarAddPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DoorareaCarAddPageState extends State<DoorareaCarAddPage> {
|
||||||
|
Map<String, dynamic> pd = {};
|
||||||
|
bool _agreed = false;
|
||||||
|
|
||||||
|
// 部门列表
|
||||||
|
List<dynamic> _deptList = [];
|
||||||
|
List<Map> _personList = [];
|
||||||
|
List<String> signImages = [];
|
||||||
|
|
||||||
|
late bool _isMyCompanyArea = false;
|
||||||
|
late bool _isSelectCar = false;
|
||||||
|
|
||||||
|
|
||||||
|
List<String> _vehicleImages = [];
|
||||||
|
List<String> _vehicleLicenseImages = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_getDept();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取部门
|
||||||
|
Future<void> _getDept() async {
|
||||||
|
// try {
|
||||||
|
// final data = {
|
||||||
|
// 'eqCorpinfoId': widget.scanData['id'],
|
||||||
|
// // 'eqParentId': widget.scanData['corpinfoId'],
|
||||||
|
// };
|
||||||
|
// final result = await BasicInfoApi.getDeptTree(data);
|
||||||
|
// if (result['success'] == true) {
|
||||||
|
// final list = result['data'] ?? [];
|
||||||
|
// if (list.length > 0) {
|
||||||
|
// setState(() {
|
||||||
|
// _deptList = list[0]['childrenList'] ?? [];
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交
|
||||||
|
Future<void> _saveSuccess() async {
|
||||||
|
if (!FormUtils.hasValue(pd, 'corpinfoId')) {
|
||||||
|
ToastUtil.showNormal(context, '请选择部门');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!FormUtils.hasValue(pd, 'postName')) {
|
||||||
|
ToastUtil.showNormal(context, '请输入岗位');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// try {
|
||||||
|
// final result = await BasicInfoApi.userFirmEntry(pd);
|
||||||
|
// LoadingDialogHelper.hide();
|
||||||
|
// if (result['success'] == true) {
|
||||||
|
// ToastUtil.showNormal(context, '申请成功');
|
||||||
|
// _relogin();
|
||||||
|
// } else {
|
||||||
|
// ToastUtil.showNormal(context, result['errMessage']);
|
||||||
|
// }
|
||||||
|
// } catch (e) {
|
||||||
|
// LoadingDialogHelper.hide();
|
||||||
|
// ToastUtil.showNormal(context, '操作失败,请重试');
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _addPersonWight(Map personData) {
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
Padding(padding: const EdgeInsets.only(top: 5),child: Container(
|
||||||
|
margin: const EdgeInsets.symmetric(horizontal: 12),
|
||||||
|
// padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
// 边框
|
||||||
|
border: Border.all(
|
||||||
|
color: Colors.grey.shade300,
|
||||||
|
width: 1.0,
|
||||||
|
style: BorderStyle.solid,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(5),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '选择部门:',
|
||||||
|
isEditable: true,
|
||||||
|
text: personData['departmentName'] ?? '请选择',
|
||||||
|
isRequired: true,
|
||||||
|
onTap: () async {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '选择人员:',
|
||||||
|
isEditable: true,
|
||||||
|
text: personData['postName'] ?? '请选择',
|
||||||
|
isRequired: true,
|
||||||
|
onTap: () async {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
ItemListWidget.itemContainer(RepairedPhotoSection(
|
||||||
|
isRequired: true,
|
||||||
|
title: "人员照片",
|
||||||
|
maxCount: 1,
|
||||||
|
horizontalPadding: 0,
|
||||||
|
mediaType: MediaType.image,
|
||||||
|
isShowAI: false,
|
||||||
|
onChanged: (List<File> files) {},
|
||||||
|
onAiIdentify: () {},
|
||||||
|
),),
|
||||||
|
const SizedBox(height: 10)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
),),
|
||||||
|
Positioned(
|
||||||
|
top: 0,
|
||||||
|
right: 2,
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.all(2),
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
color: Colors.red,
|
||||||
|
),
|
||||||
|
|
||||||
|
child: GestureDetector(
|
||||||
|
child: const Icon(Icons.close, size: 14, color: Colors.white,),
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
_personList.remove(personData);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: MyAppbar(title: '车辆申请'),
|
||||||
|
body: SafeArea(
|
||||||
|
child: ItemListWidget.itemContainer(
|
||||||
|
horizontal: 5,
|
||||||
|
vertical: 12,
|
||||||
|
ListView(
|
||||||
|
children: [
|
||||||
|
|
||||||
|
|
||||||
|
ListItemFactory.createBuildSimpleSection('申请信息'),
|
||||||
|
|
||||||
|
|
||||||
|
const Divider(),
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '选择管辖单位:',
|
||||||
|
isEditable: true,
|
||||||
|
text: pd['departmentName'] ?? '请选择',
|
||||||
|
isRequired: true,
|
||||||
|
onTap: () async {
|
||||||
|
if (_deptList.isEmpty) {
|
||||||
|
ToastUtil.showNormal(context, '暂无部门信息');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final found = await BottomPicker.show(
|
||||||
|
context,
|
||||||
|
items: _deptList,
|
||||||
|
itemBuilder:
|
||||||
|
(i) => Text(i['name']!, textAlign: TextAlign.center),
|
||||||
|
initialIndex: 0,
|
||||||
|
);
|
||||||
|
//FocusHelper.clearFocus(context);
|
||||||
|
|
||||||
|
if (found != null) {
|
||||||
|
setState(() {
|
||||||
|
pd['departmentId'] = found['id'];
|
||||||
|
pd['departmentName'] = found['name'];
|
||||||
|
pd['corpinfoId'] = found['corpinfoId'];
|
||||||
|
pd['corpinfoName'] = found['corpinfoName'];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
const Divider(),
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '选择管辖区域:',
|
||||||
|
isEditable: true,
|
||||||
|
text: pd['departmentName'] ?? '请选择',
|
||||||
|
isRequired: true,
|
||||||
|
onTap: () async {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '审核人员部门:',
|
||||||
|
isEditable: true,
|
||||||
|
text: pd['departmentName'] ?? '请选择',
|
||||||
|
isRequired: true,
|
||||||
|
onTap: () async {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '审核人员:',
|
||||||
|
isEditable: true,
|
||||||
|
text: pd['departmentName'] ?? '请选择',
|
||||||
|
isRequired: true,
|
||||||
|
onTap: () async {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '选择项目:',
|
||||||
|
isEditable: true,
|
||||||
|
text: pd['departmentName'] ?? '请选择',
|
||||||
|
isRequired: true,
|
||||||
|
onTap: () async {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
child: ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '选择时间:',
|
||||||
|
isEditable: false,
|
||||||
|
text: pd['departmentName'] ?? '',
|
||||||
|
isRequired: true,
|
||||||
|
onTap: () async {},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
const Divider(),
|
||||||
|
ItemListWidget.multiLineTitleTextField(
|
||||||
|
label: '申请原因',
|
||||||
|
isEditable: true,
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///车辆信息
|
||||||
|
ListItemFactory.createBuildSimpleSection('车辆信息'),
|
||||||
|
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '驾驶人部门',
|
||||||
|
isEditable: !_isSelectCar,
|
||||||
|
onTap: () {
|
||||||
|
|
||||||
|
},
|
||||||
|
text: '',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(height: 1,),
|
||||||
|
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '驾驶人',
|
||||||
|
isEditable: !_isSelectCar,
|
||||||
|
onTap: () {
|
||||||
|
|
||||||
|
},
|
||||||
|
text: '',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(height: 1,),
|
||||||
|
|
||||||
|
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '车牌类型',
|
||||||
|
isEditable: !_isSelectCar,
|
||||||
|
onTap: () {
|
||||||
|
|
||||||
|
},
|
||||||
|
text: '',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
const Divider(height: 1,),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '车辆类型',
|
||||||
|
isEditable: !_isSelectCar,
|
||||||
|
onTap: () {
|
||||||
|
|
||||||
|
},
|
||||||
|
text: '',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
const Divider(height: 1,),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '车牌号',
|
||||||
|
isEditable: !_isSelectCar,
|
||||||
|
onTap: () {
|
||||||
|
|
||||||
|
},
|
||||||
|
text: '',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// ItemListWidget.singleLineTitleText(
|
||||||
|
// label: '车牌号',
|
||||||
|
// isEditable: !_isSelectCar,
|
||||||
|
// text: '',
|
||||||
|
// onChanged: (value) {
|
||||||
|
//
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
|
||||||
|
|
||||||
|
const Divider(),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||||
|
child: RepairedPhotoSection(
|
||||||
|
isRequired:true,
|
||||||
|
title: "车辆照片",
|
||||||
|
maxCount: 4,
|
||||||
|
mediaType: MediaType.image,
|
||||||
|
isShowAI: false,
|
||||||
|
onChanged: (List<File> files) {
|
||||||
|
// 上传图片 files
|
||||||
|
_vehicleImages.clear();
|
||||||
|
for(int i=0;i<files.length;i++){
|
||||||
|
_vehicleImages.add(files[i].path);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onAiIdentify: () {
|
||||||
|
},
|
||||||
|
),),
|
||||||
|
|
||||||
|
const Divider(),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||||
|
child: RepairedPhotoSection(
|
||||||
|
isRequired:true,
|
||||||
|
title: "行驶证照片",
|
||||||
|
maxCount: 2,
|
||||||
|
mediaType: MediaType.image,
|
||||||
|
isShowAI: false,
|
||||||
|
onChanged: (List<File> files) {
|
||||||
|
// 上传图片 files
|
||||||
|
_vehicleLicenseImages.clear();
|
||||||
|
for(int i=0;i<files.length;i++){
|
||||||
|
_vehicleLicenseImages.add(files[i].path);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onAiIdentify: () {
|
||||||
|
},
|
||||||
|
),),
|
||||||
|
|
||||||
|
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Checkbox(
|
||||||
|
value: _agreed,
|
||||||
|
activeColor: Colors.blue,
|
||||||
|
checkColor: Colors.white,
|
||||||
|
side: const BorderSide(color: Colors.grey),
|
||||||
|
onChanged: (value) {
|
||||||
|
setState(() {
|
||||||
|
_agreed = value ?? false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Flexible(
|
||||||
|
child: RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
children: [
|
||||||
|
const TextSpan(
|
||||||
|
text: '我已阅读并同意',
|
||||||
|
style: TextStyle(color: Colors.black, fontSize: 12),
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text: '《安全进港须知》',
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.blue,
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
recognizer:
|
||||||
|
TapGestureRecognizer()
|
||||||
|
..onTap = () async {
|
||||||
|
|
||||||
|
final path = await Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(builder: (context) => SignInstructionsWebview(
|
||||||
|
name: "安全进港须知",
|
||||||
|
url:
|
||||||
|
'http://47.92.102.56:7811/file/xieyi/zsyhxy.htm',
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
await NativeOrientation.setPortrait();
|
||||||
|
if (path != null) {
|
||||||
|
setState(() {
|
||||||
|
setState(() {
|
||||||
|
_agreed = true;
|
||||||
|
signImages = [];
|
||||||
|
signImages.add(path);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// pushPage(
|
||||||
|
// const SignInstructionsWebview(
|
||||||
|
// name: "安全进港须知",
|
||||||
|
// url:
|
||||||
|
// 'http://47.92.102.56:7811/file/xieyi/zsyhxy.htm',
|
||||||
|
// ),
|
||||||
|
// context,
|
||||||
|
// );
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
// 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: '提交申请',
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 10,
|
||||||
|
horizontal: 10,
|
||||||
|
),
|
||||||
|
height: 40,
|
||||||
|
backgroundColor: Colors.blue,
|
||||||
|
onPressed: () {
|
||||||
|
_saveSuccess();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,528 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/bottom_picker.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/custom_button.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/item_list_widget.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/photo_picker_row.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/toast_util.dart';
|
||||||
|
import 'package:qhd_prevention/http/ApiService.dart';
|
||||||
|
import 'package:qhd_prevention/http/modules/basic_info_api.dart';
|
||||||
|
|
||||||
|
import 'package:qhd_prevention/pages/home/doorAndCar/sign_instructions_webView.dart';
|
||||||
|
import 'package:qhd_prevention/pages/mine/mine_sign_page.dart';
|
||||||
|
import 'package:qhd_prevention/pages/mine/webViewPage.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:flutter/gestures.dart';
|
||||||
|
|
||||||
|
class FirstlevelCarAddPage extends StatefulWidget {
|
||||||
|
const FirstlevelCarAddPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<FirstlevelCarAddPage> createState() => _FirstlevelCarAddPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FirstlevelCarAddPageState extends State<FirstlevelCarAddPage> {
|
||||||
|
Map<String, dynamic> pd = {};
|
||||||
|
bool _agreed = false;
|
||||||
|
|
||||||
|
// 部门列表
|
||||||
|
List<dynamic> _deptList = [];
|
||||||
|
List<Map> _personList = [];
|
||||||
|
List<String> signImages = [];
|
||||||
|
|
||||||
|
late bool _isMyCompanyArea = false;
|
||||||
|
late bool _isSelectCar = false;
|
||||||
|
|
||||||
|
|
||||||
|
List<String> _vehicleImages = [];
|
||||||
|
List<String> _vehicleLicenseImages = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_getDept();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取部门
|
||||||
|
Future<void> _getDept() async {
|
||||||
|
// try {
|
||||||
|
// final data = {
|
||||||
|
// 'eqCorpinfoId': widget.scanData['id'],
|
||||||
|
// // 'eqParentId': widget.scanData['corpinfoId'],
|
||||||
|
// };
|
||||||
|
// final result = await BasicInfoApi.getDeptTree(data);
|
||||||
|
// if (result['success'] == true) {
|
||||||
|
// final list = result['data'] ?? [];
|
||||||
|
// if (list.length > 0) {
|
||||||
|
// setState(() {
|
||||||
|
// _deptList = list[0]['childrenList'] ?? [];
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交
|
||||||
|
Future<void> _saveSuccess() async {
|
||||||
|
if (!FormUtils.hasValue(pd, 'corpinfoId')) {
|
||||||
|
ToastUtil.showNormal(context, '请选择部门');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!FormUtils.hasValue(pd, 'postName')) {
|
||||||
|
ToastUtil.showNormal(context, '请输入岗位');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// try {
|
||||||
|
// final result = await BasicInfoApi.userFirmEntry(pd);
|
||||||
|
// LoadingDialogHelper.hide();
|
||||||
|
// if (result['success'] == true) {
|
||||||
|
// ToastUtil.showNormal(context, '申请成功');
|
||||||
|
// _relogin();
|
||||||
|
// } else {
|
||||||
|
// ToastUtil.showNormal(context, result['errMessage']);
|
||||||
|
// }
|
||||||
|
// } catch (e) {
|
||||||
|
// LoadingDialogHelper.hide();
|
||||||
|
// ToastUtil.showNormal(context, '操作失败,请重试');
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _addPersonWight(Map personData) {
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
Padding(padding: const EdgeInsets.only(top: 5),child: Container(
|
||||||
|
margin: const EdgeInsets.symmetric(horizontal: 12),
|
||||||
|
// padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
// 边框
|
||||||
|
border: Border.all(
|
||||||
|
color: Colors.grey.shade300,
|
||||||
|
width: 1.0,
|
||||||
|
style: BorderStyle.solid,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(5),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '选择部门:',
|
||||||
|
isEditable: true,
|
||||||
|
text: personData['departmentName'] ?? '请选择',
|
||||||
|
isRequired: true,
|
||||||
|
onTap: () async {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '选择人员:',
|
||||||
|
isEditable: true,
|
||||||
|
text: personData['postName'] ?? '请选择',
|
||||||
|
isRequired: true,
|
||||||
|
onTap: () async {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
ItemListWidget.itemContainer(RepairedPhotoSection(
|
||||||
|
isRequired: true,
|
||||||
|
title: "人员照片",
|
||||||
|
maxCount: 1,
|
||||||
|
horizontalPadding: 0,
|
||||||
|
mediaType: MediaType.image,
|
||||||
|
isShowAI: false,
|
||||||
|
onChanged: (List<File> files) {},
|
||||||
|
onAiIdentify: () {},
|
||||||
|
),),
|
||||||
|
const SizedBox(height: 10)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
),),
|
||||||
|
Positioned(
|
||||||
|
top: 0,
|
||||||
|
right: 2,
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.all(2),
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
color: Colors.red,
|
||||||
|
),
|
||||||
|
|
||||||
|
child: GestureDetector(
|
||||||
|
child: const Icon(Icons.close, size: 14, color: Colors.white,),
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
_personList.remove(personData);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: MyAppbar(title: '车辆申请'),
|
||||||
|
body: SafeArea(
|
||||||
|
child: ItemListWidget.itemContainer(
|
||||||
|
horizontal: 5,
|
||||||
|
vertical: 12,
|
||||||
|
ListView(
|
||||||
|
children: [
|
||||||
|
|
||||||
|
|
||||||
|
ListItemFactory.createBuildSimpleSection('申请信息'),
|
||||||
|
const Divider(),
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '选择项目名称:',
|
||||||
|
isEditable: true,
|
||||||
|
text: pd['departmentName'] ?? '请选择',
|
||||||
|
isRequired: true,
|
||||||
|
onTap: () async {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '审核人员:',
|
||||||
|
isEditable: true,
|
||||||
|
text: pd['departmentName'] ?? '请选择',
|
||||||
|
isRequired: true,
|
||||||
|
onTap: () async {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
child: ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '选择时间:',
|
||||||
|
isEditable: false,
|
||||||
|
text: pd['departmentName'] ?? '',
|
||||||
|
isRequired: true,
|
||||||
|
onTap: () async {},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '访问港区:',
|
||||||
|
isEditable: true,
|
||||||
|
text: pd['departmentName'] ?? '请选择',
|
||||||
|
isRequired: true,
|
||||||
|
onTap: () async {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '选择范围:',
|
||||||
|
isEditable: true,
|
||||||
|
text: pd['departmentName'] ?? '请选择',
|
||||||
|
isRequired: true,
|
||||||
|
onTap: () async {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
// ItemListWidget.multiLineTitleTextField(
|
||||||
|
// label: '申请原因',
|
||||||
|
// isEditable: true,
|
||||||
|
// ),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///车辆信息
|
||||||
|
ListItemFactory.createBuildSimpleSection('车辆信息'),
|
||||||
|
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '驾驶人部门',
|
||||||
|
isEditable: !_isSelectCar,
|
||||||
|
onTap: () {
|
||||||
|
|
||||||
|
},
|
||||||
|
text: '',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(height: 1,),
|
||||||
|
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '驾驶人',
|
||||||
|
isEditable: !_isSelectCar,
|
||||||
|
onTap: () {
|
||||||
|
|
||||||
|
},
|
||||||
|
text: '',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(height: 1,),
|
||||||
|
|
||||||
|
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '车牌类型',
|
||||||
|
isEditable: !_isSelectCar,
|
||||||
|
onTap: () {
|
||||||
|
|
||||||
|
},
|
||||||
|
text: '',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
const Divider(height: 1,),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '车辆类型',
|
||||||
|
isEditable: !_isSelectCar,
|
||||||
|
onTap: () {
|
||||||
|
|
||||||
|
},
|
||||||
|
text: '',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
const Divider(height: 1,),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '车牌号',
|
||||||
|
isEditable: !_isSelectCar,
|
||||||
|
onTap: () {
|
||||||
|
|
||||||
|
},
|
||||||
|
text: '',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// ItemListWidget.singleLineTitleText(
|
||||||
|
// label: '车牌号',
|
||||||
|
// isEditable: !_isSelectCar,
|
||||||
|
// text: '',
|
||||||
|
// onChanged: (value) {
|
||||||
|
//
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
|
||||||
|
|
||||||
|
const Divider(),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||||
|
child: RepairedPhotoSection(
|
||||||
|
isRequired:true,
|
||||||
|
title: "车辆照片",
|
||||||
|
maxCount: 4,
|
||||||
|
mediaType: MediaType.image,
|
||||||
|
isShowAI: false,
|
||||||
|
onChanged: (List<File> files) {
|
||||||
|
// 上传图片 files
|
||||||
|
_vehicleImages.clear();
|
||||||
|
for(int i=0;i<files.length;i++){
|
||||||
|
_vehicleImages.add(files[i].path);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onAiIdentify: () {
|
||||||
|
},
|
||||||
|
),),
|
||||||
|
|
||||||
|
const Divider(),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||||
|
child: RepairedPhotoSection(
|
||||||
|
isRequired:true,
|
||||||
|
title: "行驶证照片",
|
||||||
|
maxCount: 2,
|
||||||
|
mediaType: MediaType.image,
|
||||||
|
isShowAI: false,
|
||||||
|
onChanged: (List<File> files) {
|
||||||
|
// 上传图片 files
|
||||||
|
_vehicleLicenseImages.clear();
|
||||||
|
for(int i=0;i<files.length;i++){
|
||||||
|
_vehicleLicenseImages.add(files[i].path);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onAiIdentify: () {
|
||||||
|
},
|
||||||
|
),),
|
||||||
|
|
||||||
|
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Checkbox(
|
||||||
|
value: _agreed,
|
||||||
|
activeColor: Colors.blue,
|
||||||
|
checkColor: Colors.white,
|
||||||
|
side: const BorderSide(color: Colors.grey),
|
||||||
|
onChanged: (value) {
|
||||||
|
setState(() {
|
||||||
|
_agreed = value ?? false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Flexible(
|
||||||
|
child: RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
children: [
|
||||||
|
const TextSpan(
|
||||||
|
text: '我已阅读并同意',
|
||||||
|
style: TextStyle(color: Colors.black, fontSize: 12),
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text: '《安全进港须知》',
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.blue,
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
recognizer:
|
||||||
|
TapGestureRecognizer()
|
||||||
|
..onTap = () async {
|
||||||
|
|
||||||
|
final path = await Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(builder: (context) => SignInstructionsWebview(
|
||||||
|
name: "安全进港须知",
|
||||||
|
url:
|
||||||
|
'http://47.92.102.56:7811/file/xieyi/zsyhxy.htm',
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
await NativeOrientation.setPortrait();
|
||||||
|
if (path != null) {
|
||||||
|
setState(() {
|
||||||
|
setState(() {
|
||||||
|
_agreed = true;
|
||||||
|
signImages = [];
|
||||||
|
signImages.add(path);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// pushPage(
|
||||||
|
// const SignInstructionsWebview(
|
||||||
|
// name: "安全进港须知",
|
||||||
|
// url:
|
||||||
|
// 'http://47.92.102.56:7811/file/xieyi/zsyhxy.htm',
|
||||||
|
// ),
|
||||||
|
// context,
|
||||||
|
// );
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
// 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: '提交申请',
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 10,
|
||||||
|
horizontal: 10,
|
||||||
|
),
|
||||||
|
height: 40,
|
||||||
|
backgroundColor: Colors.blue,
|
||||||
|
onPressed: () {
|
||||||
|
_saveSuccess();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,320 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/custom_button.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/item_list_widget.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/toast_util.dart';
|
||||||
|
import 'package:qhd_prevention/http/ApiService.dart';
|
||||||
|
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||||
|
import 'package:qhd_prevention/tools/h_colors.dart';
|
||||||
|
import 'package:qhd_prevention/tools/tools.dart';
|
||||||
|
|
||||||
|
class CarApplicationRecord extends StatefulWidget {
|
||||||
|
const CarApplicationRecord(this.type, {super.key});
|
||||||
|
|
||||||
|
final int type;//1 一级口门人员审核 2 一级口门车辆审核 3 审批记录(人员) 4 审批记录(车辆)
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<CarApplicationRecord> createState() => _CarApplicationRecordState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CarApplicationRecordState extends State<CarApplicationRecord> {
|
||||||
|
// 申请信息数据
|
||||||
|
final Map<String, String> applicationInfo = {
|
||||||
|
'mingcheng': '项目名称',
|
||||||
|
'bumen': '审核人员部门',
|
||||||
|
'renyuan': '审核人员',
|
||||||
|
'shijian': '2024-01-01 至 2024-12-31',
|
||||||
|
'gangqu': '访问港区',
|
||||||
|
'diqu': '访问地区',
|
||||||
|
};
|
||||||
|
|
||||||
|
// 车辆信息数据
|
||||||
|
final Map<String, String> vehicleInfo = {
|
||||||
|
'name': '驾驶人姓名',
|
||||||
|
'type': '车辆类型',
|
||||||
|
'licenseType': '车牌号类型',
|
||||||
|
'license': '车牌号',};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: MyAppbar(title: '车辆审核记录'),
|
||||||
|
body:
|
||||||
|
Container(
|
||||||
|
color: Colors.white,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
padding: EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// 申请信息标题
|
||||||
|
_buildSectionTitle('申请信息'),
|
||||||
|
SizedBox(height: 12),
|
||||||
|
|
||||||
|
// 申请信息卡片
|
||||||
|
_buildInfoCard(applicationInfo),
|
||||||
|
SizedBox(height: 24),
|
||||||
|
|
||||||
|
// 车辆信息标题
|
||||||
|
_buildSectionTitle('车辆信息'),
|
||||||
|
SizedBox(height: 12),
|
||||||
|
|
||||||
|
// 车辆信息卡片
|
||||||
|
_buildCarCard(vehicleInfo),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
|
||||||
|
|
||||||
|
// SizedBox(height: 10),
|
||||||
|
|
||||||
|
// 底部按钮
|
||||||
|
if(widget.type==2)
|
||||||
|
_buildActionButtons(),
|
||||||
|
|
||||||
|
if(widget.type==4)
|
||||||
|
CustomButton(
|
||||||
|
height: 35,
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
backgroundColor: h_AppBarColor(),
|
||||||
|
textStyle: const TextStyle(color: Colors.black),
|
||||||
|
buttonStyle: ButtonStyleType.primary,
|
||||||
|
text: '关闭')
|
||||||
|
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildSectionTitle(String title) {
|
||||||
|
return Text(
|
||||||
|
title,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildInfoCard(info) {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.only(top: 0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '项目名称:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum: 0,
|
||||||
|
text: applicationInfo['mingcheng'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '访问港区:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum: 0,
|
||||||
|
text: applicationInfo['gangqu'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '区域范围:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum: 0,
|
||||||
|
text: applicationInfo['diqu'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '审核人员部门:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum: 0,
|
||||||
|
text: applicationInfo['bumen'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '审核人员:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum: 0,
|
||||||
|
text: applicationInfo['renyuan'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '所属项目:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum: 0,
|
||||||
|
text: applicationInfo['mingcheng'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '选择时间:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum: 0,
|
||||||
|
text: applicationInfo['shijian'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildCarCard(info) {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.only(top: 0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '驾驶人姓名:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum: 0,
|
||||||
|
text: info['name'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '车辆类型:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum: 0,
|
||||||
|
text: info['type'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '车牌号类型:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum: 0,
|
||||||
|
text: info['licenseType'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '车牌号:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum: 0,
|
||||||
|
text: info['license'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
// 照片信息
|
||||||
|
_buildPhotoItem(1),
|
||||||
|
const Divider(),
|
||||||
|
_buildPhotoItem(2),
|
||||||
|
const Divider(),
|
||||||
|
// _buildPhotoItem(3),
|
||||||
|
Container(
|
||||||
|
height: 150,
|
||||||
|
padding: EdgeInsets.all(8),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Image.network('${ApiService.baseImgPath}1983773013086048256/202601/ai_recognition_images/a9c8e701f773470d8a8485ccb6fb35b7.jpg'),
|
||||||
|
),
|
||||||
|
// const Divider(),
|
||||||
|
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildPhotoItem(int witch) {
|
||||||
|
String labelName='';
|
||||||
|
switch(witch){
|
||||||
|
case 1:
|
||||||
|
labelName='车辆照片';
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
labelName='行驶证照片';
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
labelName='机动车登记证书';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.only(bottom: 12),
|
||||||
|
child:
|
||||||
|
ItemListWidget.twoRowTitleAndImages(
|
||||||
|
title: labelName,
|
||||||
|
horizontalInset:0,
|
||||||
|
onTapCallBack: (path) {
|
||||||
|
presentOpaque(SingleImageViewer(imageUrl: path), context);
|
||||||
|
},
|
||||||
|
imageUrls: ['1983773013086048256/202601/ai_recognition_images/a9c8e701f773470d8a8485ccb6fb35b7.jpg','1983773013086048256/202601/ai_recognition_images/a9c8e701f773470d8a8485ccb6fb35b7.jpg'],
|
||||||
|
),
|
||||||
|
// ItemListWidget.OneRowImageTitle(
|
||||||
|
// label: labelName,
|
||||||
|
// text: '',
|
||||||
|
// onTapCallBack: (path) {
|
||||||
|
// presentOpaque(SingleImageViewer(imageUrl: path), context);
|
||||||
|
// },
|
||||||
|
// imgPath: '1983773013086048256/202601/ai_recognition_images/a9c8e701f773470d8a8485ccb6fb35b7.jpg',
|
||||||
|
// ),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildActionButtons() {
|
||||||
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
// 验收按钮
|
||||||
|
|
||||||
|
Expanded(
|
||||||
|
child: CustomButton(
|
||||||
|
height: 35,
|
||||||
|
onPressed: () async {
|
||||||
|
final confirmed = await CustomAlertDialog.showInput(
|
||||||
|
context,
|
||||||
|
title: "驳回原因",
|
||||||
|
hintText: '输入内容',
|
||||||
|
cancelText: '关闭',
|
||||||
|
confirmText: '确定',
|
||||||
|
);
|
||||||
|
if (confirmed != null) {
|
||||||
|
ToastUtil.showNormal(context, confirmed);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
backgroundColor: h_backGroundColor(),
|
||||||
|
textStyle: const TextStyle(color: Colors.black),
|
||||||
|
buttonStyle: ButtonStyleType.secondary,
|
||||||
|
text: '驳回')
|
||||||
|
),
|
||||||
|
|
||||||
|
SizedBox(width: 10), // 使用width而不是height
|
||||||
|
// 查看详情按钮
|
||||||
|
Expanded(
|
||||||
|
child: CustomButton(
|
||||||
|
height: 35,
|
||||||
|
onPressed: () {
|
||||||
|
|
||||||
|
},
|
||||||
|
backgroundColor: h_AppBarColor(),
|
||||||
|
textStyle: const TextStyle(color: Colors.white),
|
||||||
|
buttonStyle: ButtonStyleType.primary,
|
||||||
|
text: '审核通过')
|
||||||
|
),
|
||||||
|
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,383 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/custom_button.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/item_list_widget.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/toast_util.dart';
|
||||||
|
import 'package:qhd_prevention/http/ApiService.dart';
|
||||||
|
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||||
|
import 'package:qhd_prevention/tools/h_colors.dart';
|
||||||
|
import 'package:qhd_prevention/tools/tools.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class OnlylookDoorareaCar extends StatefulWidget {
|
||||||
|
const OnlylookDoorareaCar(this.type, {super.key});
|
||||||
|
|
||||||
|
final int type;//1 审核 2 查看
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<OnlylookDoorareaCar> createState() => _OnlylookDoorareaCarState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _OnlylookDoorareaCarState extends State<OnlylookDoorareaCar> {
|
||||||
|
|
||||||
|
// 模拟申请信息数据
|
||||||
|
final Map<String, String> applicationInfo = {
|
||||||
|
'mingcheng': '项目名称',
|
||||||
|
'bumen': '审核人员部门',
|
||||||
|
'renyuan': '审核人员',
|
||||||
|
'shijian': '2024-01-01 至 2024-12-31',
|
||||||
|
'gangqu': '访问港区',
|
||||||
|
'diqu': '访问地区',
|
||||||
|
};
|
||||||
|
|
||||||
|
// 模拟人员列表数据
|
||||||
|
final Map<String, String> personnelList =
|
||||||
|
{
|
||||||
|
'name': '张三',
|
||||||
|
'bumen': '技术部',
|
||||||
|
'isPei': '是',
|
||||||
|
'wan': 'A区、B区',
|
||||||
|
};
|
||||||
|
|
||||||
|
/// 是否是监管端
|
||||||
|
bool isJGD = false;
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
_getTypeTitle();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: MyAppbar(title: '车辆审核'),
|
||||||
|
body:
|
||||||
|
Container(
|
||||||
|
color: Colors.white,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
padding: EdgeInsets.all(16),
|
||||||
|
child:
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
|
||||||
|
// 申请信息卡片
|
||||||
|
_buildInfoCard(),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
|
||||||
|
// 人员列表
|
||||||
|
_buildPersonCard(),
|
||||||
|
|
||||||
|
SizedBox(height: 10,),
|
||||||
|
if(widget.type==1)
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
// 验收按钮
|
||||||
|
|
||||||
|
Expanded(
|
||||||
|
child:CustomButton(
|
||||||
|
height: 35,
|
||||||
|
onPressed: () async {
|
||||||
|
|
||||||
|
final confirmed = await CustomAlertDialog.showInput(
|
||||||
|
context,
|
||||||
|
title: "驳回原因",
|
||||||
|
hintText: '输入内容',
|
||||||
|
cancelText: '关闭',
|
||||||
|
confirmText: '确定',
|
||||||
|
);
|
||||||
|
if (confirmed!=null) {
|
||||||
|
ToastUtil.showNormal(context, confirmed);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
backgroundColor: h_backGroundColor(),
|
||||||
|
textStyle: const TextStyle(color: Colors.black),
|
||||||
|
buttonStyle:ButtonStyleType.secondary,
|
||||||
|
text: '驳回')
|
||||||
|
),
|
||||||
|
|
||||||
|
SizedBox(width: 10), // 使用width而不是height
|
||||||
|
// 查看详情按钮
|
||||||
|
Expanded(
|
||||||
|
child:CustomButton(
|
||||||
|
height: 35,
|
||||||
|
onPressed: () {
|
||||||
|
|
||||||
|
},
|
||||||
|
backgroundColor: h_AppBarColor(),
|
||||||
|
textStyle: const TextStyle(color: Colors.white),
|
||||||
|
buttonStyle:ButtonStyleType.primary,
|
||||||
|
text: '审核通过')
|
||||||
|
),
|
||||||
|
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
if(widget.type==2)
|
||||||
|
CustomButton(
|
||||||
|
height: 35,
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
backgroundColor: h_AppBarColor(),
|
||||||
|
textStyle: const TextStyle(color: Colors.white),
|
||||||
|
buttonStyle:ButtonStyleType.primary,
|
||||||
|
text: '关闭'),
|
||||||
|
|
||||||
|
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildInfoCard() {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// 标题
|
||||||
|
Container(
|
||||||
|
width: double.infinity,
|
||||||
|
padding: EdgeInsets.only(bottom: 10),
|
||||||
|
child: Text(
|
||||||
|
'申请信息',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// 信息列表
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '管辖单位:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum:0,
|
||||||
|
text: applicationInfo['mingcheng'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '管辖区域:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum:0,
|
||||||
|
text: applicationInfo['bumen'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '审核人员部门:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum:0,
|
||||||
|
text: applicationInfo['renyuan'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '审核人员:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum:0,
|
||||||
|
text: applicationInfo['diqu'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
|
||||||
|
// if((applicationInfo['gangqu'] ?? '').isNotEmpty)
|
||||||
|
const Divider(),
|
||||||
|
// if((applicationInfo['gangqu'] ?? '').isNotEmpty)
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '所属项目:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum:0,
|
||||||
|
text: applicationInfo['gangqu'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '时间范围:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum:0,
|
||||||
|
text: applicationInfo['shijian'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
|
||||||
|
ItemListWidget.twoRowTitleText(
|
||||||
|
label: '申请原因:',
|
||||||
|
text: applicationInfo['shijian']??'',
|
||||||
|
horizontalInset:0,
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildPersonCard() {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// 标题
|
||||||
|
Container(
|
||||||
|
width: double.infinity,
|
||||||
|
padding: EdgeInsets.only(bottom: 10),
|
||||||
|
child: Text(
|
||||||
|
'车辆信息',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// 信息列表
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '驾驶人部门:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum:0,
|
||||||
|
text: personnelList['name'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '驾驶人:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum:0,
|
||||||
|
text: personnelList['bumen'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
// ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
// label: '手机号:',
|
||||||
|
// isEditable: false,
|
||||||
|
// horizontalnum:0,
|
||||||
|
// text: personnelList['wan'] ?? '',
|
||||||
|
// onTap: () {},
|
||||||
|
// ),
|
||||||
|
// const Divider(),
|
||||||
|
//
|
||||||
|
// ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
// label: '部门:',
|
||||||
|
// isEditable: false,
|
||||||
|
// horizontalnum:0,
|
||||||
|
// text: personnelList['wan'] ?? '',
|
||||||
|
// onTap: () {},
|
||||||
|
// ),
|
||||||
|
// const Divider(),
|
||||||
|
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '车辆类型:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum:0,
|
||||||
|
text: personnelList['wan'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '车牌类型:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum:0,
|
||||||
|
text: personnelList['wan'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '车牌号:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum:0,
|
||||||
|
text: personnelList['wan'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
|
||||||
|
ItemListWidget.twoRowTitleAndImages(
|
||||||
|
title: '车辆照片',
|
||||||
|
horizontalInset:0,
|
||||||
|
onTapCallBack: (path) {
|
||||||
|
presentOpaque(SingleImageViewer(imageUrl: path), context);
|
||||||
|
},
|
||||||
|
imageUrls: ['1983773013086048256/202601/ai_recognition_images/a9c8e701f773470d8a8485ccb6fb35b7.jpg','1983773013086048256/202601/ai_recognition_images/a9c8e701f773470d8a8485ccb6fb35b7.jpg'],
|
||||||
|
),
|
||||||
|
// ItemListWidget.OneRowImageTitle(
|
||||||
|
// label: '车辆照片:',
|
||||||
|
// imgPath: '1983773013086048256/202601/ai_recognition_images/a9c8e701f773470d8a8485ccb6fb35b7.jpg',
|
||||||
|
// horizontalInset:0,
|
||||||
|
// onTapCallBack: (imgUrl) {
|
||||||
|
// presentOpaque(SingleImageViewer(imageUrl: imgUrl), context);
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
ItemListWidget.twoRowTitleAndImages(
|
||||||
|
title: '行驶证照片',
|
||||||
|
horizontalInset:0,
|
||||||
|
onTapCallBack: (path) {
|
||||||
|
presentOpaque(SingleImageViewer(imageUrl: path), context);
|
||||||
|
},
|
||||||
|
imageUrls: ['1983773013086048256/202601/ai_recognition_images/a9c8e701f773470d8a8485ccb6fb35b7.jpg','1983773013086048256/202601/ai_recognition_images/a9c8e701f773470d8a8485ccb6fb35b7.jpg'],
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
Container(
|
||||||
|
height: 150,
|
||||||
|
padding: EdgeInsets.all(8),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Image.network('${ApiService.baseImgPath}1983773013086048256/202601/ai_recognition_images/a9c8e701f773470d8a8485ccb6fb35b7.jpg'),
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Future<void> _getTypeTitle() async {
|
||||||
|
String text= await _getString('selectedRole');
|
||||||
|
setState(() {
|
||||||
|
if(text=='fgszd'||text=='FGSZD'){//分公司
|
||||||
|
isJGD=false;
|
||||||
|
}else{//监管端
|
||||||
|
isJGD=true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> _getString(String key) async {
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
String text=prefs.getString(key)??'';
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,102 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/item_list_widget.dart';
|
||||||
|
import 'package:qhd_prevention/pages/home/doorAndCar/person/doorArea_person_record_page.dart';
|
||||||
|
|
||||||
|
|
||||||
|
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||||
|
import 'package:qhd_prevention/tools/tools.dart';
|
||||||
|
|
||||||
|
class DoorareaTypePage extends StatefulWidget {
|
||||||
|
const DoorareaTypePage(this.type, {super.key});
|
||||||
|
|
||||||
|
final int type;//1 进港口门申请 2 进港口门申请记录 3 封闭区域口门申请 4 封闭区域口门申请记录
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<DoorareaTypePage> createState() => _DoorareaTypePageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DoorareaTypePageState extends State<DoorareaTypePage> {
|
||||||
|
|
||||||
|
String labelOne='';
|
||||||
|
String labelTwo='';
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
// TODO: implement initState
|
||||||
|
super.initState();
|
||||||
|
switch(widget.type){
|
||||||
|
case 1:
|
||||||
|
labelOne='人员申请';
|
||||||
|
labelTwo='车辆申请';
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
labelOne='人员申请记录';
|
||||||
|
labelTwo='车辆申请记录';
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
labelOne='人员申请';
|
||||||
|
labelTwo='车辆申请';
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
labelOne='人员申请记录';
|
||||||
|
labelTwo='车辆申请记录';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
appBar: MyAppbar(title: '查看'),
|
||||||
|
body: SafeArea(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: labelOne,
|
||||||
|
isEditable: true,
|
||||||
|
isRequired: false,
|
||||||
|
onTap: () async {
|
||||||
|
if(widget.type==1){
|
||||||
|
await pushPage(DoorareaPersonRecordPage(1), context);
|
||||||
|
}else if(widget.type==2){
|
||||||
|
await pushPage(DoorareaPersonRecordPage(2), context);
|
||||||
|
}else if(widget.type==3){
|
||||||
|
await pushPage(DoorareaPersonRecordPage(3), context);
|
||||||
|
}else if(widget.type==4){
|
||||||
|
await pushPage(DoorareaPersonRecordPage(4), context);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
text: '',
|
||||||
|
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: labelTwo,
|
||||||
|
isEditable: true,
|
||||||
|
isRequired: false,
|
||||||
|
onTap: () async {
|
||||||
|
if(widget.type==1){
|
||||||
|
await pushPage(DoorareaPersonRecordPage(5), context);
|
||||||
|
}else if(widget.type==2){
|
||||||
|
await pushPage(DoorareaPersonRecordPage(6), context);
|
||||||
|
}else if(widget.type==3){
|
||||||
|
await pushPage(DoorareaPersonRecordPage(7), context);
|
||||||
|
}else if(widget.type==4){
|
||||||
|
await pushPage(DoorareaPersonRecordPage(8), context);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
text: '',
|
||||||
|
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,324 @@
|
||||||
|
// lib/pages/application_template.dart
|
||||||
|
import 'dart:ffi';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:qhd_prevention/pages/home/doorAndCar/doorArea_type_page.dart';
|
||||||
|
|
||||||
|
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||||
|
import 'package:qhd_prevention/tools/tools.dart';
|
||||||
|
|
||||||
|
typedef ItemTapCallback = void Function();
|
||||||
|
|
||||||
|
class AppSectionItem {
|
||||||
|
final String title;
|
||||||
|
final String icon; // asset path
|
||||||
|
final int badge;
|
||||||
|
final bool visible;
|
||||||
|
final ItemTapCallback? onTap;
|
||||||
|
|
||||||
|
AppSectionItem({
|
||||||
|
required this.title,
|
||||||
|
required this.icon,
|
||||||
|
this.badge = 0,
|
||||||
|
this.visible = true,
|
||||||
|
this.onTap,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class AppSection {
|
||||||
|
final String title;
|
||||||
|
final List<AppSectionItem> items;
|
||||||
|
|
||||||
|
AppSection({
|
||||||
|
required this.title,
|
||||||
|
required this.items,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
class DoorcarTabPage extends StatefulWidget {
|
||||||
|
const DoorcarTabPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<DoorcarTabPage> createState() => _DoorcarTabPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DoorcarTabPageState extends State<DoorcarTabPage> {
|
||||||
|
|
||||||
|
final String bannerAsset = 'assets/images/door_banner.png';
|
||||||
|
late List<AppSection> defaultSections = [
|
||||||
|
|
||||||
|
AppSection(title: '口门门禁申请', items: [
|
||||||
|
AppSectionItem(
|
||||||
|
title: '进港口门申请',
|
||||||
|
icon: 'assets/images/door_ico9.png',
|
||||||
|
badge: 0,
|
||||||
|
onTap: () async {
|
||||||
|
await pushPage(DoorareaTypePage(1), context);
|
||||||
|
_fetchData();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
AppSectionItem(
|
||||||
|
title: '进港口门申请记录',
|
||||||
|
icon: 'assets/images/door_ico10.png',
|
||||||
|
badge: 0,
|
||||||
|
onTap: () async {
|
||||||
|
await pushPage(DoorareaTypePage(2), context);
|
||||||
|
_fetchData();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AppSectionItem(
|
||||||
|
title: '封闭区域口门申请',
|
||||||
|
icon: 'assets/images/door_ico9.png',
|
||||||
|
badge: 0,
|
||||||
|
onTap: () async {
|
||||||
|
await pushPage(DoorareaTypePage(3), context);
|
||||||
|
_fetchData();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
AppSectionItem(
|
||||||
|
title: '封闭区域口门申请记录',
|
||||||
|
icon: 'assets/images/door_ico10.png',
|
||||||
|
badge: 0,
|
||||||
|
onTap: () async {
|
||||||
|
await pushPage(DoorareaTypePage(4), context);
|
||||||
|
_fetchData();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
|
||||||
|
]),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
// TODO: implement initState
|
||||||
|
super.initState();
|
||||||
|
_fetchData();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _fetchData() async {
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final double bannerHeight = (730.0 / 1125.0) * MediaQuery.of(context).size.width;
|
||||||
|
final double iconSectionHeight =
|
||||||
|
MediaQuery.of(context).size.height - bannerHeight - 30.0;
|
||||||
|
const double iconOverlapBanner = 30.0;
|
||||||
|
|
||||||
|
// 过滤掉没有可见 items 的分组
|
||||||
|
final visibleSections = defaultSections
|
||||||
|
.map((s) => AppSection(
|
||||||
|
title: s.title,
|
||||||
|
items: s.items.where((it) => it.visible).toList()))
|
||||||
|
.where((s) => s.items.isNotEmpty)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
extendBodyBehindAppBar: true,
|
||||||
|
appBar: MyAppbar(title: '智能门禁', backgroundColor: Colors.transparent,),
|
||||||
|
body: ListView(
|
||||||
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: bannerHeight + iconSectionHeight,
|
||||||
|
child: Stack(
|
||||||
|
clipBehavior: Clip.none,
|
||||||
|
children: [
|
||||||
|
Positioned(
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
height: bannerHeight,
|
||||||
|
child: _buildBannerSection(bannerHeight, context),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
left: 10,
|
||||||
|
right: 10,
|
||||||
|
top: bannerHeight - iconOverlapBanner,
|
||||||
|
height: iconSectionHeight,
|
||||||
|
child: _buildIconSection(context, visibleSections),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildBannerSection(double bannerHeight, BuildContext context) {
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
Image.asset(
|
||||||
|
bannerAsset,
|
||||||
|
width: MediaQuery.of(context).size.width,
|
||||||
|
height: bannerHeight,
|
||||||
|
fit: BoxFit.fitWidth,
|
||||||
|
errorBuilder: (c, e, s) {
|
||||||
|
return Container(
|
||||||
|
color: Colors.blueGrey,
|
||||||
|
height: bannerHeight,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: const Text('Banner', style: TextStyle(color: Colors.white)),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildIconSection(BuildContext context, List<AppSection> buttonInfos) {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
boxShadow: const [
|
||||||
|
BoxShadow(color: Colors.black12, blurRadius: 6, offset: Offset(0, 2)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: ListView.builder(
|
||||||
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
|
padding: const EdgeInsets.all(0),
|
||||||
|
itemCount: buttonInfos.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final section = buttonInfos[index];
|
||||||
|
final items = section.items;
|
||||||
|
if (items.isEmpty) return const SizedBox.shrink();
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 10, left: 10, right: 10),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// 标题
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(10, 10, 10, 5),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Container(width: 2, height: 10, color: Colors.blue),
|
||||||
|
const SizedBox(width: 5),
|
||||||
|
Text(section.title,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 14, fontWeight: FontWeight.bold)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// icons
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(10),
|
||||||
|
child: LayoutBuilder(
|
||||||
|
builder: (context, constraints) {
|
||||||
|
const spacing = 20.0;
|
||||||
|
final totalWidth = constraints.maxWidth;
|
||||||
|
final itemWidth = (totalWidth - spacing * 2) / 2;
|
||||||
|
return Wrap(
|
||||||
|
spacing: spacing,
|
||||||
|
runSpacing: spacing,
|
||||||
|
children: items.map<Widget>((item) {
|
||||||
|
return SizedBox(
|
||||||
|
width: itemWidth,
|
||||||
|
child: _buildItem(
|
||||||
|
item,
|
||||||
|
onTap: item.onTap ??
|
||||||
|
() => debugPrint('Tapped ${item.title}'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(10, 0, 10, 5),
|
||||||
|
child: Text('*申请封闭区域时,系统已自动包含进港口门权限,您无需再次申请进港口门权限。',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 12, fontWeight: FontWeight.bold,color: Colors.red)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildItem(AppSectionItem item, {VoidCallback? onTap}) {
|
||||||
|
const double iconSize = 30;
|
||||||
|
final int badgeNum = item.badge;
|
||||||
|
final String title = item.title;
|
||||||
|
final String iconPath = item.icon;
|
||||||
|
|
||||||
|
return InkWell(
|
||||||
|
onTap: onTap,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
child: SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Stack(
|
||||||
|
clipBehavior: Clip.none,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: iconSize,
|
||||||
|
height: iconSize,
|
||||||
|
child: Image.asset(
|
||||||
|
iconPath,
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
errorBuilder: (c, e, s) {
|
||||||
|
return Container(
|
||||||
|
color: Colors.grey.shade200,
|
||||||
|
child: const Center(child: Icon(Icons.image, size: 18)),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (badgeNum > 0)
|
||||||
|
Positioned(
|
||||||
|
top: -6,
|
||||||
|
right: -6,
|
||||||
|
child: Container(
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.symmetric(horizontal: 4, vertical: 2),
|
||||||
|
decoration:
|
||||||
|
const BoxDecoration(color: Colors.red, shape: BoxShape.circle),
|
||||||
|
constraints: const BoxConstraints(minWidth: 16, minHeight: 16),
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
badgeNum > 99 ? '99+' : badgeNum.toString(),
|
||||||
|
style: const TextStyle(color: Colors.white, fontSize: 10, height: 1),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Text(
|
||||||
|
title,
|
||||||
|
style: const TextStyle(fontSize: 13),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
maxLines: 2,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,499 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/bottom_picker.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/custom_button.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/item_list_widget.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/photo_picker_row.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/toast_util.dart';
|
||||||
|
import 'package:qhd_prevention/http/ApiService.dart';
|
||||||
|
import 'package:qhd_prevention/http/modules/basic_info_api.dart';
|
||||||
|
import 'package:qhd_prevention/pages/home/doorAndCar/person_selection_page.dart';
|
||||||
|
import 'package:qhd_prevention/pages/home/doorAndCar/sign_instructions_webView.dart';
|
||||||
|
|
||||||
|
|
||||||
|
import 'package:qhd_prevention/pages/mine/mine_sign_page.dart';
|
||||||
|
import 'package:qhd_prevention/pages/mine/webViewPage.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:flutter/gestures.dart';
|
||||||
|
|
||||||
|
class DoorareaPersonApplyPage extends StatefulWidget {
|
||||||
|
const DoorareaPersonApplyPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<DoorareaPersonApplyPage> createState() =>
|
||||||
|
_DoorareaPersonApplyPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DoorareaPersonApplyPageState extends State<DoorareaPersonApplyPage> {
|
||||||
|
Map<String, dynamic> pd = {};
|
||||||
|
bool _agreed = false;
|
||||||
|
|
||||||
|
// 部门列表
|
||||||
|
List<dynamic> _deptList = [];
|
||||||
|
List<Person> _personList = [];
|
||||||
|
List<String> signImages = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_getDept();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取部门
|
||||||
|
Future<void> _getDept() async {
|
||||||
|
// try {
|
||||||
|
// final data = {
|
||||||
|
// 'eqCorpinfoId': widget.scanData['id'],
|
||||||
|
// // 'eqParentId': widget.scanData['corpinfoId'],
|
||||||
|
// };
|
||||||
|
// final result = await BasicInfoApi.getDeptTree(data);
|
||||||
|
// if (result['success'] == true) {
|
||||||
|
// final list = result['data'] ?? [];
|
||||||
|
// if (list.length > 0) {
|
||||||
|
// setState(() {
|
||||||
|
// _deptList = list[0]['childrenList'] ?? [];
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交
|
||||||
|
Future<void> _saveSuccess() async {
|
||||||
|
if (!FormUtils.hasValue(pd, 'corpinfoId')) {
|
||||||
|
ToastUtil.showNormal(context, '请选择部门');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!FormUtils.hasValue(pd, 'postName')) {
|
||||||
|
ToastUtil.showNormal(context, '请输入岗位');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// try {
|
||||||
|
// final result = await BasicInfoApi.userFirmEntry(pd);
|
||||||
|
// LoadingDialogHelper.hide();
|
||||||
|
// if (result['success'] == true) {
|
||||||
|
// ToastUtil.showNormal(context, '申请成功');
|
||||||
|
// _relogin();
|
||||||
|
// } else {
|
||||||
|
// ToastUtil.showNormal(context, result['errMessage']);
|
||||||
|
// }
|
||||||
|
// } catch (e) {
|
||||||
|
// LoadingDialogHelper.hide();
|
||||||
|
// ToastUtil.showNormal(context, '操作失败,请重试');
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _addPersonWight(Person personData) {
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
Card(
|
||||||
|
margin: EdgeInsets.only(bottom: 12),
|
||||||
|
color: Colors.white,
|
||||||
|
elevation: 2,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
// 第一行:姓名和部门
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
'姓名: ${personData.name??''}',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Colors.grey[700],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// _buildInfoItem('姓名:', person['姓名'] ?? '',),
|
||||||
|
SizedBox(width: 24),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
'部门: ${personData.group??''}',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Colors.grey[700],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// _buildInfoItem('部门:', person['部门'] ?? ''),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
// SizedBox(height: 8),
|
||||||
|
|
||||||
|
// 第二行:删除
|
||||||
|
// Row(
|
||||||
|
// mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
// children: [
|
||||||
|
// CustomButton(
|
||||||
|
// height: 35,
|
||||||
|
// onPressed: () async {
|
||||||
|
//
|
||||||
|
// },
|
||||||
|
// backgroundColor: Colors.red,
|
||||||
|
// textStyle: const TextStyle(color: Colors.black),
|
||||||
|
// buttonStyle:ButtonStyleType.primary,
|
||||||
|
// text: '删除')
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
top: 0,
|
||||||
|
right: 2,
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.all(2),
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
color: Colors.red,
|
||||||
|
),
|
||||||
|
|
||||||
|
child: GestureDetector(
|
||||||
|
child: const Icon(Icons.close, size: 14, color: Colors.white,),
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
_personList.remove(personData);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: MyAppbar(title: '人员申请'),
|
||||||
|
body: SafeArea(
|
||||||
|
child: ItemListWidget.itemContainer(
|
||||||
|
horizontal: 5,
|
||||||
|
vertical: 12,
|
||||||
|
ListView(
|
||||||
|
children: [
|
||||||
|
ListItemFactory.createBuildSimpleSection('申请信息'),
|
||||||
|
const Divider(),
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '选择管辖单位:',
|
||||||
|
isEditable: true,
|
||||||
|
text: pd['departmentName'] ?? '请选择',
|
||||||
|
isRequired: true,
|
||||||
|
onTap: () async {
|
||||||
|
if (_deptList.isEmpty) {
|
||||||
|
ToastUtil.showNormal(context, '暂无部门信息');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final found = await BottomPicker.show(
|
||||||
|
context,
|
||||||
|
items: _deptList,
|
||||||
|
itemBuilder:
|
||||||
|
(i) => Text(i['name']!, textAlign: TextAlign.center),
|
||||||
|
initialIndex: 0,
|
||||||
|
);
|
||||||
|
//FocusHelper.clearFocus(context);
|
||||||
|
|
||||||
|
if (found != null) {
|
||||||
|
setState(() {
|
||||||
|
pd['departmentId'] = found['id'];
|
||||||
|
pd['departmentName'] = found['name'];
|
||||||
|
pd['corpinfoId'] = found['corpinfoId'];
|
||||||
|
pd['corpinfoName'] = found['corpinfoName'];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '选择管辖区域:',
|
||||||
|
isEditable: true,
|
||||||
|
text: pd['departmentName'] ?? '请选择',
|
||||||
|
isRequired: true,
|
||||||
|
onTap: () async {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '审核人员部门:',
|
||||||
|
isEditable: true,
|
||||||
|
text: pd['departmentName'] ?? '请选择',
|
||||||
|
isRequired: true,
|
||||||
|
onTap: () async {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '审核人员:',
|
||||||
|
isEditable: true,
|
||||||
|
text: pd['departmentName'] ?? '请选择',
|
||||||
|
isRequired: true,
|
||||||
|
onTap: () async {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '选择项目:',
|
||||||
|
isEditable: true,
|
||||||
|
text: pd['departmentName'] ?? '请选择',
|
||||||
|
isRequired: true,
|
||||||
|
onTap: () async {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
child: ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '选择时间:',
|
||||||
|
isEditable: false,
|
||||||
|
text: pd['departmentName'] ?? '',
|
||||||
|
isRequired: true,
|
||||||
|
onTap: () async {},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
ItemListWidget.multiLineTitleTextField(
|
||||||
|
label: '申请原因',
|
||||||
|
isEditable: true,
|
||||||
|
),
|
||||||
|
|
||||||
|
const Divider(),
|
||||||
|
if (_personList.isNotEmpty)
|
||||||
|
...[
|
||||||
|
ListItemFactory.createBuildSimpleSection('人员信息'),
|
||||||
|
// const Divider(),
|
||||||
|
for (var i = 0; i < _personList.length; i++)
|
||||||
|
_addPersonWight(_personList[i]),
|
||||||
|
],
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
CustomButton(
|
||||||
|
text: '添加人员',
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
|
height: 35,
|
||||||
|
backgroundColor: Colors.blue,
|
||||||
|
onPressed: () async {
|
||||||
|
final result = await Navigator.push<SelectionPersonResult>(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(builder: (context) => PersonSelectionPage(_personList)),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result != null) {
|
||||||
|
// 处理返回的选中结果
|
||||||
|
_showSelectedResult(context, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Checkbox(
|
||||||
|
value: _agreed,
|
||||||
|
activeColor: Colors.blue,
|
||||||
|
checkColor: Colors.white,
|
||||||
|
side: const BorderSide(color: Colors.grey),
|
||||||
|
onChanged: (value) {
|
||||||
|
setState(() {
|
||||||
|
_agreed = value ?? false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Flexible(
|
||||||
|
child: RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
children: [
|
||||||
|
const TextSpan(
|
||||||
|
text: '我已阅读并同意',
|
||||||
|
style: TextStyle(color: Colors.black, fontSize: 12),
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text: '《安全进港须知》',
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.blue,
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
recognizer:
|
||||||
|
TapGestureRecognizer()
|
||||||
|
..onTap = () async {
|
||||||
|
final path = await Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(builder: (context) => SignInstructionsWebview(
|
||||||
|
name: "安全进港须知",
|
||||||
|
url:
|
||||||
|
'http://47.92.102.56:7811/file/xieyi/zsyhxy.htm',
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
await NativeOrientation.setPortrait();
|
||||||
|
if (path != null) {
|
||||||
|
setState(() {
|
||||||
|
setState(() {
|
||||||
|
_agreed = true;
|
||||||
|
signImages = [];
|
||||||
|
signImages.add(path);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
// 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: '提交申请',
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 10,
|
||||||
|
horizontal: 10,
|
||||||
|
),
|
||||||
|
height: 40,
|
||||||
|
backgroundColor: Colors.blue,
|
||||||
|
onPressed: () {
|
||||||
|
_saveSuccess();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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 {
|
||||||
|
// final name = SessionService.instance.name ?? '';
|
||||||
|
// await NativeOrientation.setLandscape();
|
||||||
|
// final path = await Navigator.push(
|
||||||
|
// context,
|
||||||
|
// MaterialPageRoute(builder: (context) => MineSignPage(personName: name,)),
|
||||||
|
// );
|
||||||
|
// await NativeOrientation.setPortrait();
|
||||||
|
// if (path != null) {
|
||||||
|
// setState(() {
|
||||||
|
// signImages = [];
|
||||||
|
// signImages.add(path);
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
void _showSelectedResult(BuildContext context, SelectionPersonResult result) {
|
||||||
|
// String message = '选中了 ${result.selectedPersons.length} 人:\n';
|
||||||
|
// result.groupedSelected.forEach((group, persons) {
|
||||||
|
// message += '组${group}: ${persons.map((p) => p.name).join(', ')}\n';
|
||||||
|
// });
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_personList.clear();
|
||||||
|
for(int i=0;i<result.selectedPersons.length;i++){
|
||||||
|
_personList.add(result.selectedPersons[i]);
|
||||||
|
_addPersonWight(result.selectedPersons[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,394 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:qhd_prevention/pages/home/doorAndCar/car/doorArea_car_add_page.dart';
|
||||||
|
import 'package:qhd_prevention/pages/home/doorAndCar/car/firstlevel_car_add_page.dart';
|
||||||
|
import 'package:qhd_prevention/pages/home/doorAndCar/car/onlyLook_car_application.dart';
|
||||||
|
import 'package:qhd_prevention/pages/home/doorAndCar/car/onlyLook_doorarea_car.dart';
|
||||||
|
import 'package:qhd_prevention/pages/home/doorAndCar/person/doorArea_person_add_page.dart';
|
||||||
|
import 'package:qhd_prevention/pages/home/doorAndCar/person/firstlevel_person_add_page.dart';
|
||||||
|
import 'package:qhd_prevention/pages/home/doorAndCar/person/onlyLook_doorarea_person.dart';
|
||||||
|
import 'package:qhd_prevention/pages/home/doorAndCar/person/onlyLook_person_application.dart';
|
||||||
|
|
||||||
|
|
||||||
|
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||||
|
import 'package:qhd_prevention/tools/h_colors.dart';
|
||||||
|
import 'package:qhd_prevention/tools/tools.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/custom_button.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/search_bar_widget.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class DoorareaPersonRecordPage extends StatefulWidget {
|
||||||
|
const DoorareaPersonRecordPage(this.type, {Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
final int type;//1 进港口门申请(人) 2 进港口门申请记录(人) 3 封闭区域口门申请(人) 4 封闭区域口门申请记录(人)
|
||||||
|
//5 进港口门申请(车) 6 进港口门申请记录(车) 7 封闭区域口门申请(车) 8 封闭区域口门申请记录(车)
|
||||||
|
|
||||||
|
@override
|
||||||
|
_DoorareaPersonRecordPageState createState() => _DoorareaPersonRecordPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DoorareaPersonRecordPageState extends State<DoorareaPersonRecordPage> {
|
||||||
|
// Data and state variables
|
||||||
|
// List<dynamic> list = [];
|
||||||
|
final List<Map<String, dynamic>> list = [
|
||||||
|
{
|
||||||
|
'applicant': '封闭区域申请',
|
||||||
|
'region': '申请人',
|
||||||
|
'people': '人数',
|
||||||
|
'startTime': '2025-10-29 00:00',
|
||||||
|
'endTime': '2025-10-31 00:00',
|
||||||
|
'license': '申请区域',
|
||||||
|
'status': '待审核',
|
||||||
|
'statusColor': Colors.orange,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'applicant': '封闭区域申请',
|
||||||
|
'region': '申请人',
|
||||||
|
'people': '人数',
|
||||||
|
'startTime': '2025-10-29 00:00',
|
||||||
|
'endTime': '2025-10-31 00:00',
|
||||||
|
'license': '申请区域',
|
||||||
|
'status': '待审核',
|
||||||
|
'statusColor': Colors.orange,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'applicant': '封闭区域申请',
|
||||||
|
'region': '申请人',
|
||||||
|
'people': '人数',
|
||||||
|
'startTime': '2025-10-29 00:00',
|
||||||
|
'endTime': '2025-10-31 00:00',
|
||||||
|
'license': '申请区域',
|
||||||
|
'status': '待审核',
|
||||||
|
'statusColor': Colors.orange,
|
||||||
|
},
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
Map pd = {};
|
||||||
|
|
||||||
|
int currentPage = 1;
|
||||||
|
int rows = 10;
|
||||||
|
int totalPage = 1;
|
||||||
|
bool isLoading = false;
|
||||||
|
final TextEditingController _searchController = TextEditingController();
|
||||||
|
|
||||||
|
int sindex = 0;
|
||||||
|
String searchKeywords = '';
|
||||||
|
|
||||||
|
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||||
|
|
||||||
|
final ScrollController _scrollController = ScrollController();
|
||||||
|
|
||||||
|
/// 是否是监管端
|
||||||
|
|
||||||
|
String titleName='';
|
||||||
|
String buttonName='';
|
||||||
|
|
||||||
|
bool isAdd = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
switch(widget.type){
|
||||||
|
case 1:
|
||||||
|
case 3:
|
||||||
|
titleName='人员审核';
|
||||||
|
buttonName='查看';
|
||||||
|
isAdd=true;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
case 4:
|
||||||
|
titleName='人员审核记录';
|
||||||
|
buttonName='查看';
|
||||||
|
isAdd=false;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
case 7:
|
||||||
|
titleName='车辆审核';
|
||||||
|
buttonName='查看';
|
||||||
|
isAdd=true;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
case 8:
|
||||||
|
titleName='车辆审核记录';
|
||||||
|
buttonName='查看';
|
||||||
|
isAdd=false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_fetchData();
|
||||||
|
_scrollController.addListener(_onScroll);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_scrollController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onScroll() {
|
||||||
|
if (_scrollController.position.pixels >=
|
||||||
|
_scrollController.position.maxScrollExtent &&
|
||||||
|
!isLoading) {
|
||||||
|
if (currentPage < totalPage) {
|
||||||
|
currentPage++;
|
||||||
|
_fetchData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Future<void> _fetchData() async {
|
||||||
|
|
||||||
|
// if (isLoading) return;
|
||||||
|
// setState(() => isLoading = true);
|
||||||
|
//
|
||||||
|
// try {
|
||||||
|
// final data = {
|
||||||
|
// "likeCorpName": searchKeywords,
|
||||||
|
// "pageSize": rows,
|
||||||
|
// "pageIndex": currentPage,
|
||||||
|
// };
|
||||||
|
// final response = await RiskwarningApi.getCorpRiskStatement();
|
||||||
|
// final firmRes = await RiskwarningApi.getCorpRiskList(data);
|
||||||
|
// setState(() {
|
||||||
|
// pd = response['data'];
|
||||||
|
// if (currentPage == 1) {
|
||||||
|
// list = firmRes['data'];
|
||||||
|
// } else {
|
||||||
|
// list.addAll(firmRes['data']);
|
||||||
|
// }
|
||||||
|
// totalPage = firmRes['totalPages'] ?? 1;
|
||||||
|
// isLoading = false;
|
||||||
|
// });
|
||||||
|
// } catch (e) {
|
||||||
|
// print('Error fetching data: $e');
|
||||||
|
// setState(() => isLoading = false);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
void _search() {
|
||||||
|
searchKeywords = _searchController.text.trim();
|
||||||
|
currentPage = 1;
|
||||||
|
list.clear();
|
||||||
|
_fetchData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _goToDetail(Map<String, dynamic> item,int index) async {
|
||||||
|
switch(widget.type){
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
await pushPage(OnlylookDoorareaPerson(2), context);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
await pushPage(OnlylookPersonApplication(3), context);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
await pushPage(OnlylookDoorareaCar(2), context);
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
case 8:
|
||||||
|
await pushPage(CarApplicationRecord(4), context);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_fetchData();
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildListItem(Map<String, dynamic> item,int index) {
|
||||||
|
return InkWell(
|
||||||
|
onTap: () {
|
||||||
|
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.all(20),
|
||||||
|
margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black12,
|
||||||
|
blurRadius: 4,
|
||||||
|
offset: const Offset(0, 2),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
item['applicant'],
|
||||||
|
// '${item['name']??''}',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Text('申请人:${item['region']??""}',),
|
||||||
|
if(widget.type==5||widget.type==6||widget.type==7||widget.type==8)...[
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Text('车牌号:${item['region']??""}',),
|
||||||
|
],
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Text('申请区域:${item['license']??""}',),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Text('时间范围:自${item['startTime']??""}至${item['endTime']??""}止'),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Text('审核状态:${item['status']??""}',),
|
||||||
|
if(widget.type==2||widget.type==4||widget.type==6||widget.type==8)...[
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Text('驳回原因:${item['status']??""}',),
|
||||||
|
],
|
||||||
|
|
||||||
|
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
CustomButton(
|
||||||
|
height: 35,
|
||||||
|
onPressed: () {
|
||||||
|
_goToDetail(item,index);
|
||||||
|
},
|
||||||
|
backgroundColor: h_AppBarColor(),
|
||||||
|
textStyle: const TextStyle(color: Colors.white),
|
||||||
|
buttonStyle:ButtonStyleType.primary,
|
||||||
|
text: buttonName),
|
||||||
|
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Widget _buildListContent() {
|
||||||
|
if (isLoading && list.isEmpty) {
|
||||||
|
// 初始加载时显示居中的加载指示器
|
||||||
|
return Center(child: CircularProgressIndicator());
|
||||||
|
} else if (list.isEmpty) {
|
||||||
|
// 没有数据
|
||||||
|
return NoDataWidget.show();
|
||||||
|
} else {
|
||||||
|
// 有数据或加载更多
|
||||||
|
return ListView.builder(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
|
||||||
|
controller: _scrollController,
|
||||||
|
itemCount: list.length + (isLoading ? 1 : 0),
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
if (index >= list.length) {
|
||||||
|
// 加载更多时在列表底部显示加载指示器
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||||
|
child: Center(child: CircularProgressIndicator()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return _buildListItem(list[index],index);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
key: _scaffoldKey,
|
||||||
|
appBar: MyAppbar(title: titleName, actions: [
|
||||||
|
|
||||||
|
if(isAdd)
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.add, color: Colors.white, size: 30),
|
||||||
|
onPressed: () async {
|
||||||
|
switch(widget.type){
|
||||||
|
case 1:
|
||||||
|
await pushPage(DoorareaPersonApplyPage(), context);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
await pushPage(FirstlevelPersonAddPage(), context);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
await pushPage(DoorareaCarAddPage(), context);
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
await pushPage(FirstlevelCarAddPage(), context);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_fetchData();
|
||||||
|
|
||||||
|
},
|
||||||
|
),
|
||||||
|
|
||||||
|
],),
|
||||||
|
body: Column(
|
||||||
|
children: [
|
||||||
|
// 搜索框区域(带筛选图标)
|
||||||
|
Container(
|
||||||
|
color: Colors.white,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 8),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
// 可点击的筛选图标
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
// 筛选逻辑
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'筛选',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 2),
|
||||||
|
Icon(
|
||||||
|
Icons.expand_more,
|
||||||
|
size: 20,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
// 搜索框
|
||||||
|
Expanded(
|
||||||
|
child: SearchBarWidget(
|
||||||
|
showResetButton: true,
|
||||||
|
hintText: '请输入关键字',
|
||||||
|
resetButtonText: '重置',
|
||||||
|
onReset: () {
|
||||||
|
FocusScope.of(context).unfocus();
|
||||||
|
_searchController.text = '';
|
||||||
|
_search();
|
||||||
|
},
|
||||||
|
onSearch: (text) {
|
||||||
|
FocusScope.of(context).unfocus();
|
||||||
|
_search();
|
||||||
|
},
|
||||||
|
controller: _searchController,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
const Divider(height: 1),
|
||||||
|
// List
|
||||||
|
Expanded(child: _buildListContent()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,469 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/bottom_picker.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/custom_button.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/item_list_widget.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/photo_picker_row.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/toast_util.dart';
|
||||||
|
import 'package:qhd_prevention/http/ApiService.dart';
|
||||||
|
import 'package:qhd_prevention/http/modules/basic_info_api.dart';
|
||||||
|
import 'package:qhd_prevention/pages/home/doorAndCar/person_selection_page.dart';
|
||||||
|
import 'package:qhd_prevention/pages/home/doorAndCar/sign_instructions_webView.dart';
|
||||||
|
|
||||||
|
|
||||||
|
import 'package:qhd_prevention/pages/mine/mine_sign_page.dart';
|
||||||
|
import 'package:qhd_prevention/pages/mine/webViewPage.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:flutter/gestures.dart';
|
||||||
|
|
||||||
|
class FirstlevelPersonAddPage extends StatefulWidget {
|
||||||
|
const FirstlevelPersonAddPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<FirstlevelPersonAddPage> createState() =>
|
||||||
|
_FirstlevelPersonAddPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FirstlevelPersonAddPageState extends State<FirstlevelPersonAddPage> {
|
||||||
|
Map<String, dynamic> pd = {};
|
||||||
|
bool _agreed = false;
|
||||||
|
|
||||||
|
// 部门列表
|
||||||
|
List<dynamic> _deptList = [];
|
||||||
|
List<Person> _personList = [];
|
||||||
|
List<String> signImages = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_getDept();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取部门
|
||||||
|
Future<void> _getDept() async {
|
||||||
|
// try {
|
||||||
|
// final data = {
|
||||||
|
// 'eqCorpinfoId': widget.scanData['id'],
|
||||||
|
// // 'eqParentId': widget.scanData['corpinfoId'],
|
||||||
|
// };
|
||||||
|
// final result = await BasicInfoApi.getDeptTree(data);
|
||||||
|
// if (result['success'] == true) {
|
||||||
|
// final list = result['data'] ?? [];
|
||||||
|
// if (list.length > 0) {
|
||||||
|
// setState(() {
|
||||||
|
// _deptList = list[0]['childrenList'] ?? [];
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交
|
||||||
|
Future<void> _saveSuccess() async {
|
||||||
|
if (!FormUtils.hasValue(pd, 'corpinfoId')) {
|
||||||
|
ToastUtil.showNormal(context, '请选择部门');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!FormUtils.hasValue(pd, 'postName')) {
|
||||||
|
ToastUtil.showNormal(context, '请输入岗位');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// try {
|
||||||
|
// final result = await BasicInfoApi.userFirmEntry(pd);
|
||||||
|
// LoadingDialogHelper.hide();
|
||||||
|
// if (result['success'] == true) {
|
||||||
|
// ToastUtil.showNormal(context, '申请成功');
|
||||||
|
// _relogin();
|
||||||
|
// } else {
|
||||||
|
// ToastUtil.showNormal(context, result['errMessage']);
|
||||||
|
// }
|
||||||
|
// } catch (e) {
|
||||||
|
// LoadingDialogHelper.hide();
|
||||||
|
// ToastUtil.showNormal(context, '操作失败,请重试');
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _addPersonWight(Person personData) {
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
Card(
|
||||||
|
margin: EdgeInsets.only(bottom: 12),
|
||||||
|
color: Colors.white,
|
||||||
|
elevation: 2,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
// 第一行:姓名和部门
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
'姓名: ${personData.name??''}',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Colors.grey[700],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// _buildInfoItem('姓名:', person['姓名'] ?? '',),
|
||||||
|
SizedBox(width: 24),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
'部门: ${personData.group??''}',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Colors.grey[700],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// _buildInfoItem('部门:', person['部门'] ?? ''),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
// SizedBox(height: 8),
|
||||||
|
|
||||||
|
// 第二行:删除
|
||||||
|
// Row(
|
||||||
|
// mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
// children: [
|
||||||
|
// CustomButton(
|
||||||
|
// height: 35,
|
||||||
|
// onPressed: () async {
|
||||||
|
//
|
||||||
|
// },
|
||||||
|
// backgroundColor: Colors.red,
|
||||||
|
// textStyle: const TextStyle(color: Colors.black),
|
||||||
|
// buttonStyle:ButtonStyleType.primary,
|
||||||
|
// text: '删除')
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
top: 0,
|
||||||
|
right: 2,
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.all(2),
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
color: Colors.red,
|
||||||
|
),
|
||||||
|
|
||||||
|
child: GestureDetector(
|
||||||
|
child: const Icon(Icons.close, size: 14, color: Colors.white,),
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
_personList.remove(personData);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: MyAppbar(title: '人员申请'),
|
||||||
|
body: SafeArea(
|
||||||
|
child: ItemListWidget.itemContainer(
|
||||||
|
horizontal: 5,
|
||||||
|
vertical: 12,
|
||||||
|
ListView(
|
||||||
|
children: [
|
||||||
|
ListItemFactory.createBuildSimpleSection('申请信息'),
|
||||||
|
const Divider(),
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '选择项目名称:',
|
||||||
|
isEditable: true,
|
||||||
|
text: pd['departmentName'] ?? '请选择',
|
||||||
|
isRequired: true,
|
||||||
|
onTap: () async {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '审核人员:',
|
||||||
|
isEditable: true,
|
||||||
|
text: pd['departmentName'] ?? '请选择',
|
||||||
|
isRequired: true,
|
||||||
|
onTap: () async {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
child: ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '选择时间:',
|
||||||
|
isEditable: false,
|
||||||
|
text: pd['departmentName'] ?? '',
|
||||||
|
isRequired: true,
|
||||||
|
onTap: () async {},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '访问港区:',
|
||||||
|
isEditable: true,
|
||||||
|
text: pd['departmentName'] ?? '请选择',
|
||||||
|
isRequired: true,
|
||||||
|
onTap: () async {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '选择范围:',
|
||||||
|
isEditable: true,
|
||||||
|
text: pd['departmentName'] ?? '请选择',
|
||||||
|
isRequired: true,
|
||||||
|
onTap: () async {},
|
||||||
|
),
|
||||||
|
// const Divider(),
|
||||||
|
// ItemListWidget.multiLineTitleTextField(
|
||||||
|
// label: '申请原因',
|
||||||
|
// isEditable: true,
|
||||||
|
// ),
|
||||||
|
|
||||||
|
const Divider(),
|
||||||
|
if (_personList.isNotEmpty)
|
||||||
|
...[
|
||||||
|
ListItemFactory.createBuildSimpleSection('人员信息'),
|
||||||
|
// const Divider(),
|
||||||
|
for (var i = 0; i < _personList.length; i++)
|
||||||
|
_addPersonWight(_personList[i]),
|
||||||
|
],
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
CustomButton(
|
||||||
|
text: '添加人员',
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
|
height: 35,
|
||||||
|
backgroundColor: Colors.blue,
|
||||||
|
onPressed: () async {
|
||||||
|
final result = await Navigator.push<SelectionPersonResult>(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(builder: (context) => PersonSelectionPage(_personList)),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result != null) {
|
||||||
|
// 处理返回的选中结果
|
||||||
|
_showSelectedResult(context, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Checkbox(
|
||||||
|
value: _agreed,
|
||||||
|
activeColor: Colors.blue,
|
||||||
|
checkColor: Colors.white,
|
||||||
|
side: const BorderSide(color: Colors.grey),
|
||||||
|
onChanged: (value) {
|
||||||
|
setState(() {
|
||||||
|
_agreed = value ?? false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Flexible(
|
||||||
|
child: RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
children: [
|
||||||
|
const TextSpan(
|
||||||
|
text: '我已阅读并同意',
|
||||||
|
style: TextStyle(color: Colors.black, fontSize: 12),
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text: '《安全进港须知》',
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.blue,
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
recognizer:
|
||||||
|
TapGestureRecognizer()
|
||||||
|
..onTap = () async {
|
||||||
|
final path = await Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(builder: (context) => SignInstructionsWebview(
|
||||||
|
name: "安全进港须知",
|
||||||
|
url:
|
||||||
|
'http://47.92.102.56:7811/file/xieyi/zsyhxy.htm',
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
await NativeOrientation.setPortrait();
|
||||||
|
if (path != null) {
|
||||||
|
setState(() {
|
||||||
|
setState(() {
|
||||||
|
_agreed = true;
|
||||||
|
signImages = [];
|
||||||
|
signImages.add(path);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
// 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: '提交申请',
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 10,
|
||||||
|
horizontal: 10,
|
||||||
|
),
|
||||||
|
height: 40,
|
||||||
|
backgroundColor: Colors.blue,
|
||||||
|
onPressed: () {
|
||||||
|
_saveSuccess();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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 {
|
||||||
|
// final name = SessionService.instance.name ?? '';
|
||||||
|
// await NativeOrientation.setLandscape();
|
||||||
|
// final path = await Navigator.push(
|
||||||
|
// context,
|
||||||
|
// MaterialPageRoute(builder: (context) => MineSignPage(personName: name,)),
|
||||||
|
// );
|
||||||
|
// await NativeOrientation.setPortrait();
|
||||||
|
// if (path != null) {
|
||||||
|
// setState(() {
|
||||||
|
// signImages = [];
|
||||||
|
// signImages.add(path);
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
void _showSelectedResult(BuildContext context, SelectionPersonResult result) {
|
||||||
|
// String message = '选中了 ${result.selectedPersons.length} 人:\n';
|
||||||
|
// result.groupedSelected.forEach((group, persons) {
|
||||||
|
// message += '组${group}: ${persons.map((p) => p.name).join(', ')}\n';
|
||||||
|
// });
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_personList.clear();
|
||||||
|
for(int i=0;i<result.selectedPersons.length;i++){
|
||||||
|
_personList.add(result.selectedPersons[i]);
|
||||||
|
_addPersonWight(result.selectedPersons[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,351 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/custom_button.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/item_list_widget.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/toast_util.dart';
|
||||||
|
import 'package:qhd_prevention/http/ApiService.dart';
|
||||||
|
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||||
|
import 'package:qhd_prevention/tools/h_colors.dart';
|
||||||
|
import 'package:qhd_prevention/tools/tools.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class OnlylookDoorareaPerson extends StatefulWidget {
|
||||||
|
const OnlylookDoorareaPerson(this.type, {super.key});
|
||||||
|
|
||||||
|
final int type;//1 审核 2 查看
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<OnlylookDoorareaPerson> createState() => _OnlylookDoorareaPersonState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _OnlylookDoorareaPersonState extends State<OnlylookDoorareaPerson> {
|
||||||
|
|
||||||
|
// 模拟申请信息数据
|
||||||
|
final Map<String, String> applicationInfo = {
|
||||||
|
'mingcheng': '项目名称',
|
||||||
|
'bumen': '审核人员部门',
|
||||||
|
'renyuan': '审核人员',
|
||||||
|
'shijian': '2024-01-01 至 2024-12-31',
|
||||||
|
'gangqu': '访问港区',
|
||||||
|
'diqu': '访问地区',
|
||||||
|
};
|
||||||
|
|
||||||
|
// 模拟人员列表数据
|
||||||
|
final List<Map<String, String>> personnelList = [
|
||||||
|
{
|
||||||
|
'name': '张三',
|
||||||
|
'bumen': '技术部',
|
||||||
|
'isPei': '是',
|
||||||
|
'wan': 'A区、B区',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': '李四',
|
||||||
|
'bumen': '安全部',
|
||||||
|
'isPei': '否',
|
||||||
|
'wan': 'C区',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': '王五',
|
||||||
|
'bumen': '运营部',
|
||||||
|
'isPei': '是',
|
||||||
|
'wan': 'A区、C区、D区',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: MyAppbar(title: '人员审核'),
|
||||||
|
body:
|
||||||
|
Container(
|
||||||
|
color: Colors.white,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
padding: EdgeInsets.all(16),
|
||||||
|
child:
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
|
||||||
|
// 申请信息卡片
|
||||||
|
_buildInfoCard(),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
|
||||||
|
// 人员列表
|
||||||
|
_buildPersonWidget(),
|
||||||
|
|
||||||
|
SizedBox(height: 10,),
|
||||||
|
if(widget.type==1)
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
// 验收按钮
|
||||||
|
|
||||||
|
Expanded(
|
||||||
|
child:CustomButton(
|
||||||
|
height: 35,
|
||||||
|
onPressed: () async {
|
||||||
|
|
||||||
|
final confirmed = await CustomAlertDialog.showInput(
|
||||||
|
context,
|
||||||
|
title: "驳回原因",
|
||||||
|
hintText: '输入内容',
|
||||||
|
cancelText: '关闭',
|
||||||
|
confirmText: '确定',
|
||||||
|
);
|
||||||
|
if (confirmed!=null) {
|
||||||
|
ToastUtil.showNormal(context, confirmed);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
backgroundColor: h_backGroundColor(),
|
||||||
|
textStyle: const TextStyle(color: Colors.black),
|
||||||
|
buttonStyle:ButtonStyleType.secondary,
|
||||||
|
text: '驳回')
|
||||||
|
),
|
||||||
|
|
||||||
|
SizedBox(width: 10), // 使用width而不是height
|
||||||
|
// 查看详情按钮
|
||||||
|
Expanded(
|
||||||
|
child:CustomButton(
|
||||||
|
height: 35,
|
||||||
|
onPressed: () {
|
||||||
|
|
||||||
|
},
|
||||||
|
backgroundColor: h_AppBarColor(),
|
||||||
|
textStyle: const TextStyle(color: Colors.white),
|
||||||
|
buttonStyle:ButtonStyleType.primary,
|
||||||
|
text: '审核通过')
|
||||||
|
),
|
||||||
|
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
if(widget.type==2)
|
||||||
|
CustomButton(
|
||||||
|
height: 35,
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
backgroundColor: h_AppBarColor(),
|
||||||
|
textStyle: const TextStyle(color: Colors.black),
|
||||||
|
buttonStyle:ButtonStyleType.primary,
|
||||||
|
text: '关闭'),
|
||||||
|
|
||||||
|
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildInfoCard() {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// 标题
|
||||||
|
Container(
|
||||||
|
width: double.infinity,
|
||||||
|
padding: EdgeInsets.only(bottom: 10),
|
||||||
|
child: Text(
|
||||||
|
'申请信息',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// 信息列表
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '管辖单位:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum:0,
|
||||||
|
text: applicationInfo['mingcheng'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '管辖区域:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum:0,
|
||||||
|
text: applicationInfo['bumen'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '审核人员部门:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum:0,
|
||||||
|
text: applicationInfo['renyuan'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '审核人员:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum:0,
|
||||||
|
text: applicationInfo['diqu'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
|
||||||
|
// if((applicationInfo['gangqu'] ?? '').isNotEmpty)
|
||||||
|
const Divider(),
|
||||||
|
// if((applicationInfo['gangqu'] ?? '').isNotEmpty)
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '所属项目:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum:0,
|
||||||
|
text: applicationInfo['gangqu'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '时间范围:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum:0,
|
||||||
|
text: applicationInfo['shijian'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
|
||||||
|
ItemListWidget.twoRowTitleText(
|
||||||
|
label: '申请原因:',
|
||||||
|
text: applicationInfo['shijian']??'',
|
||||||
|
horizontalInset:0,
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildPersonWidget() {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// 标题
|
||||||
|
Container(
|
||||||
|
width: double.infinity,
|
||||||
|
padding: EdgeInsets.only(bottom: 10),
|
||||||
|
child: Text(
|
||||||
|
'人员信息',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// 人员列表
|
||||||
|
...personnelList.map((person) => _buildPersonCard(person)),
|
||||||
|
|
||||||
|
Container(
|
||||||
|
height: 150,
|
||||||
|
padding: EdgeInsets.all(8),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Image.network('${ApiService.baseImgPath}1983773013086048256/202601/ai_recognition_images/a9c8e701f773470d8a8485ccb6fb35b7.jpg'),
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Widget _buildPersonCard(Map<String, String> person) {
|
||||||
|
return Card(
|
||||||
|
margin: EdgeInsets.only(bottom: 12),
|
||||||
|
color: Colors.white,
|
||||||
|
elevation: 2,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
// 第一行:姓名和部门
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
'姓名: ${person['name']}',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Colors.grey[700],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// _buildInfoItem('姓名:', person['姓名'] ?? '',),
|
||||||
|
SizedBox(width: 24),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
'部门: ${person['bumen']}',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Colors.grey[700],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// _buildInfoItem('部门:', person['部门'] ?? ''),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
// SizedBox(height: 8),
|
||||||
|
|
||||||
|
// 第二行:删除
|
||||||
|
// Row(
|
||||||
|
// mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
// children: [
|
||||||
|
// CustomButton(
|
||||||
|
// height: 35,
|
||||||
|
// onPressed: () async {
|
||||||
|
//
|
||||||
|
// },
|
||||||
|
// backgroundColor: Colors.red,
|
||||||
|
// textStyle: const TextStyle(color: Colors.black),
|
||||||
|
// buttonStyle:ButtonStyleType.primary,
|
||||||
|
// text: '删除')
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,329 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/custom_button.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/item_list_widget.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/toast_util.dart';
|
||||||
|
import 'package:qhd_prevention/http/ApiService.dart';
|
||||||
|
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||||
|
import 'package:qhd_prevention/tools/h_colors.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class OnlylookPersonApplication extends StatefulWidget {
|
||||||
|
const OnlylookPersonApplication(this.type, {super.key});
|
||||||
|
|
||||||
|
final int type;//1 一级口门人员审核 2 一级口门车辆审核 3 审批记录(人员) 4 审批记录(车辆)
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<OnlylookPersonApplication> createState() => _OnlylookPersonApplicationState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _OnlylookPersonApplicationState extends State<OnlylookPersonApplication> {
|
||||||
|
|
||||||
|
// 模拟申请信息数据
|
||||||
|
final Map<String, String> applicationInfo = {
|
||||||
|
'mingcheng': '项目名称',
|
||||||
|
'bumen': '审核人员部门',
|
||||||
|
'renyuan': '审核人员',
|
||||||
|
'shijian': '2024-01-01 至 2024-12-31',
|
||||||
|
'gangqu': '访问港区',
|
||||||
|
'diqu': '访问地区',
|
||||||
|
};
|
||||||
|
|
||||||
|
// 模拟人员列表数据
|
||||||
|
final List<Map<String, String>> personnelList = [
|
||||||
|
{
|
||||||
|
'name': '张三',
|
||||||
|
'bumen': '技术部',
|
||||||
|
'isPei': '是',
|
||||||
|
'wan': 'A区、B区',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': '李四',
|
||||||
|
'bumen': '安全部',
|
||||||
|
'isPei': '否',
|
||||||
|
'wan': 'C区',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': '王五',
|
||||||
|
'bumen': '运营部',
|
||||||
|
'isPei': '是',
|
||||||
|
'wan': 'A区、C区、D区',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: MyAppbar(title: '申请记录'),
|
||||||
|
body:
|
||||||
|
Container(
|
||||||
|
color: Colors.white,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
padding: EdgeInsets.all(16),
|
||||||
|
child:
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// 申请信息卡片
|
||||||
|
_buildInfoCard(),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
|
||||||
|
|
||||||
|
// 人员列表
|
||||||
|
...personnelList.map((person) => _buildPersonCard(person)),
|
||||||
|
|
||||||
|
Container(
|
||||||
|
height: 150,
|
||||||
|
padding: EdgeInsets.all(8),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Image.network('${ApiService.baseImgPath}1983773013086048256/202601/ai_recognition_images/a9c8e701f773470d8a8485ccb6fb35b7.jpg'),
|
||||||
|
),
|
||||||
|
|
||||||
|
SizedBox(height: 10,),
|
||||||
|
if(widget.type==1)
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
// 验收按钮
|
||||||
|
|
||||||
|
Expanded(
|
||||||
|
child:CustomButton(
|
||||||
|
height: 35,
|
||||||
|
onPressed: () async {
|
||||||
|
|
||||||
|
final confirmed = await CustomAlertDialog.showInput(
|
||||||
|
context,
|
||||||
|
title: "驳回原因",
|
||||||
|
hintText: '输入内容',
|
||||||
|
cancelText: '关闭',
|
||||||
|
confirmText: '确定',
|
||||||
|
);
|
||||||
|
if (confirmed!=null) {
|
||||||
|
ToastUtil.showNormal(context, confirmed);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
backgroundColor: h_backGroundColor(),
|
||||||
|
textStyle: const TextStyle(color: Colors.black),
|
||||||
|
buttonStyle:ButtonStyleType.secondary,
|
||||||
|
text: '驳回')
|
||||||
|
),
|
||||||
|
|
||||||
|
SizedBox(width: 10), // 使用width而不是height
|
||||||
|
// 查看详情按钮
|
||||||
|
Expanded(
|
||||||
|
child:CustomButton(
|
||||||
|
height: 35,
|
||||||
|
onPressed: () {
|
||||||
|
|
||||||
|
},
|
||||||
|
backgroundColor: h_AppBarColor(),
|
||||||
|
textStyle: const TextStyle(color: Colors.white),
|
||||||
|
buttonStyle:ButtonStyleType.primary,
|
||||||
|
text: '审核通过')
|
||||||
|
),
|
||||||
|
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
if(widget.type==3)
|
||||||
|
CustomButton(
|
||||||
|
height: 35,
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
backgroundColor: h_AppBarColor(),
|
||||||
|
textStyle: const TextStyle(color: Colors.black),
|
||||||
|
buttonStyle:ButtonStyleType.primary,
|
||||||
|
text: '关闭'),
|
||||||
|
|
||||||
|
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildInfoCard() {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
// 标题
|
||||||
|
Container(
|
||||||
|
width: double.infinity,
|
||||||
|
padding: EdgeInsets.only(bottom: 10),
|
||||||
|
child: Text(
|
||||||
|
'申请信息',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// 信息列表
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '项目名称:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum:0,
|
||||||
|
text: applicationInfo['mingcheng'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '审核人员部门:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum:0,
|
||||||
|
text: applicationInfo['bumen'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '审核人员:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum:0,
|
||||||
|
text: applicationInfo['renyuan'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '时间范围:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum:0,
|
||||||
|
text: applicationInfo['shijian'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '访问港区:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum:0,
|
||||||
|
text: applicationInfo['gangqu'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
ItemListWidget.selectableLineTitleTextRightButton(
|
||||||
|
label: '区域范围:',
|
||||||
|
isEditable: false,
|
||||||
|
horizontalnum:0,
|
||||||
|
text: applicationInfo['diqu'] ?? '',
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildPersonCard(Map<String, String> person) {
|
||||||
|
return Card(
|
||||||
|
margin: EdgeInsets.only(bottom: 12),
|
||||||
|
color: Colors.white,
|
||||||
|
elevation: 2,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
// 第一行:姓名和部门
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
'姓名: ${person['name']}',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Colors.grey[700],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// _buildInfoItem('姓名:', person['姓名'] ?? '',),
|
||||||
|
SizedBox(width: 24),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
'部门: ${person['bumen']}',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Colors.grey[700],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// _buildInfoItem('部门:', person['部门'] ?? ''),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(height: 12),
|
||||||
|
|
||||||
|
// 第二行:是否培训和权限范围
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
_buildInfoItem('是否培训:', person['isPei'] ?? ''), // 改为 'isPei'
|
||||||
|
SizedBox(width: 24),
|
||||||
|
Expanded(
|
||||||
|
child: _buildInfoItem(
|
||||||
|
'现口门权限范围:',
|
||||||
|
person['wan'] ?? '', // 改为 'wan'
|
||||||
|
isExpanded: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildInfoItem(String label, String value, {bool isExpanded = false}) {
|
||||||
|
return Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
label,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Colors.grey[700],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 4),
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 0, vertical: 8),
|
||||||
|
// decoration: BoxDecoration(
|
||||||
|
// color: Colors.grey[50],
|
||||||
|
// borderRadius: BorderRadius.circular(6),
|
||||||
|
// border: Border.all(
|
||||||
|
// color: Colors.grey[300]!,
|
||||||
|
// width: 1,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
child: Text(
|
||||||
|
value,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
maxLines: isExpanded ? null : 1,
|
||||||
|
overflow: isExpanded ? null : TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,496 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:lpinyin/lpinyin.dart';
|
||||||
|
import 'package:qhd_prevention/customWidget/search_bar_widget.dart';
|
||||||
|
import 'package:qhd_prevention/pages/my_appbar.dart';
|
||||||
|
|
||||||
|
// 人员模型类
|
||||||
|
class Person {
|
||||||
|
final String id;
|
||||||
|
final String name;
|
||||||
|
final String group;
|
||||||
|
|
||||||
|
Person({required this.id, required this.name, required this.group});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择结果类
|
||||||
|
class SelectionPersonResult {
|
||||||
|
final List<Person> selectedPersons;
|
||||||
|
final Map<String, List<Person>> groupedSelected;
|
||||||
|
|
||||||
|
SelectionPersonResult({
|
||||||
|
required this.selectedPersons,
|
||||||
|
required this.groupedSelected,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class PersonSelectionPage extends StatefulWidget {
|
||||||
|
const PersonSelectionPage(this.oldList, {super.key});
|
||||||
|
|
||||||
|
final List<Person> oldList;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<PersonSelectionPage> createState() => _PersonSelectionPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PersonSelectionPageState extends State<PersonSelectionPage> {
|
||||||
|
// 字母表(将#放在最后)
|
||||||
|
final List<String> alphabet = [
|
||||||
|
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||||
|
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '#'
|
||||||
|
];
|
||||||
|
|
||||||
|
// 人员数据
|
||||||
|
late final Map<String, List<Person>> groupedPersons;
|
||||||
|
// 存储排序后的分组键列表
|
||||||
|
late final List<String> sortedGroupKeys;
|
||||||
|
// 存储每个分组的GlobalKey
|
||||||
|
final Map<String, GlobalKey> groupKeys = {};
|
||||||
|
|
||||||
|
final List<Map<String, dynamic>> list = [
|
||||||
|
{
|
||||||
|
'id': 'p1',
|
||||||
|
'name': '赵',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'p2',
|
||||||
|
'name': '钱',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'p3',
|
||||||
|
'name': '算',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'p4',
|
||||||
|
'name': '里',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'p5',
|
||||||
|
'name': '周',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'p6',
|
||||||
|
'name': '吴',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'p7',
|
||||||
|
'name': '啊',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'p8',
|
||||||
|
'name': '到',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'p9',
|
||||||
|
'name': '噢',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'p10',
|
||||||
|
'name': '饿',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'p11',
|
||||||
|
'name': '不',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'p12',
|
||||||
|
'name': '吃',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'p13',
|
||||||
|
'name': '123', // 测试数字
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'p14',
|
||||||
|
'name': '@@@', // 测试特殊字符
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// 选中状态
|
||||||
|
final Map<String, bool> selectedStates = {};
|
||||||
|
|
||||||
|
// 分组选中状态
|
||||||
|
final Map<String, bool> groupSelectedStates = {};
|
||||||
|
|
||||||
|
// 列表控制器
|
||||||
|
final ScrollController _scrollController = ScrollController();
|
||||||
|
final TextEditingController _searchController = TextEditingController();
|
||||||
|
|
||||||
|
// 存储每个分组在列表中的位置索引
|
||||||
|
late final Map<String, int> _groupIndexMap = {};
|
||||||
|
|
||||||
|
// 创建oldList的ID集合,用于快速查找
|
||||||
|
late final Set<String> _oldSelectedIds;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
// 创建oldList的ID集合
|
||||||
|
_oldSelectedIds = widget.oldList.map((person) => person.id).toSet();
|
||||||
|
_initData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _initData() {
|
||||||
|
// 根据姓名首字母分组
|
||||||
|
groupedPersons = {};
|
||||||
|
|
||||||
|
for (var item in list) {
|
||||||
|
String name = item['name'];
|
||||||
|
String id = item['id'];
|
||||||
|
|
||||||
|
// 使用lpinyin获取姓名首字母
|
||||||
|
String firstLetter = _getFirstLetter(name);
|
||||||
|
|
||||||
|
// 创建Person对象
|
||||||
|
Person person = Person(
|
||||||
|
id: id,
|
||||||
|
name: name,
|
||||||
|
group: firstLetter,
|
||||||
|
);
|
||||||
|
|
||||||
|
// 添加到对应分组
|
||||||
|
if (!groupedPersons.containsKey(firstLetter)) {
|
||||||
|
groupedPersons[firstLetter] = [];
|
||||||
|
}
|
||||||
|
groupedPersons[firstLetter]!.add(person);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对每个分组内的人员按姓名排序
|
||||||
|
groupedPersons.forEach((key, value) {
|
||||||
|
value.sort((a, b) => a.name.compareTo(b.name));
|
||||||
|
});
|
||||||
|
|
||||||
|
// 对分组键进行排序(确保#在最后)
|
||||||
|
sortedGroupKeys = groupedPersons.keys.toList()..sort((a, b) {
|
||||||
|
// 如果a是#,a应该在后面
|
||||||
|
if (a == '#') return 1;
|
||||||
|
// 如果b是#,b应该在后面
|
||||||
|
if (b == '#') return -1;
|
||||||
|
// 其他情况正常排序
|
||||||
|
return a.compareTo(b);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 构建分组索引映射
|
||||||
|
for (int i = 0; i < sortedGroupKeys.length; i++) {
|
||||||
|
_groupIndexMap[sortedGroupKeys[i]] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化选中状态和为每个分组创建GlobalKey
|
||||||
|
for (var group in groupedPersons.keys) {
|
||||||
|
for (var person in groupedPersons[group]!) {
|
||||||
|
// 检查当前人员是否在oldList中,如果在则设置为true
|
||||||
|
selectedStates[person.id] = _oldSelectedIds.contains(person.id);
|
||||||
|
}
|
||||||
|
// 初始化分组选中状态
|
||||||
|
groupSelectedStates[group] = false;
|
||||||
|
groupKeys[group] = GlobalKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新每个分组的全选状态
|
||||||
|
for (var group in groupedPersons.keys) {
|
||||||
|
_updateGroupSelection(group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用lpinyin获取姓名的首字母
|
||||||
|
String _getFirstLetter(String name) {
|
||||||
|
if (name.isEmpty) return '#';
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 检查第一个字符是否是英文字母
|
||||||
|
String firstChar = name.substring(0, 1);
|
||||||
|
RegExp englishLetter = RegExp(r'^[A-Za-z]$');
|
||||||
|
if (englishLetter.hasMatch(firstChar)) {
|
||||||
|
return firstChar.toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查第一个字符是否是数字或特殊字符
|
||||||
|
RegExp nonChinese = RegExp(r'^[0-9!@#\$%^&*()_+\-=\[\]{};:"\\|,.<>\/?~`]');
|
||||||
|
if (nonChinese.hasMatch(firstChar)) {
|
||||||
|
return '#';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取拼音 - 使用WITHOUT_TONE格式获取完整拼音
|
||||||
|
String pinyin = PinyinHelper.getPinyin(name,
|
||||||
|
separator: ' ', format: PinyinFormat.WITHOUT_TONE);
|
||||||
|
|
||||||
|
if (pinyin.isNotEmpty) {
|
||||||
|
// 获取第一个字的拼音首字母
|
||||||
|
List<String> pinyinParts = pinyin.split(' ');
|
||||||
|
if (pinyinParts.isNotEmpty) {
|
||||||
|
String firstCharPinyin = pinyinParts[0];
|
||||||
|
if (firstCharPinyin.isNotEmpty) {
|
||||||
|
String firstLetter = firstCharPinyin.substring(0, 1).toUpperCase();
|
||||||
|
|
||||||
|
// 检查是否是英文字母
|
||||||
|
if (englishLetter.hasMatch(firstLetter)) {
|
||||||
|
return firstLetter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// 异常处理,返回#
|
||||||
|
print('拼音转换错误: $e');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果无法识别,返回#
|
||||||
|
return '#';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 滚动到指定分组
|
||||||
|
void _scrollToGroup(String letter) {
|
||||||
|
if (!groupedPersons.containsKey(letter)) return;
|
||||||
|
|
||||||
|
// 方法1:使用索引跳转(更精确)
|
||||||
|
int? index = _groupIndexMap[letter];
|
||||||
|
if (index != null && _scrollController.hasClients) {
|
||||||
|
// 计算大概的滚动位置(每个分组标题高度 + 每个人item高度)
|
||||||
|
double position = 0;
|
||||||
|
for (int i = 0; i < index; i++) {
|
||||||
|
String group = sortedGroupKeys[i];
|
||||||
|
// 分组标题高度56,每个人item高度56
|
||||||
|
position += 56; // 分组标题高度
|
||||||
|
position += (groupedPersons[group]?.length ?? 0) * 56; // 人员列表高度
|
||||||
|
}
|
||||||
|
|
||||||
|
_scrollController.animateTo(
|
||||||
|
position,
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 方法2:使用GlobalKey(备选方案)
|
||||||
|
final key = groupKeys[letter];
|
||||||
|
if (key?.currentContext != null) {
|
||||||
|
Scrollable.ensureVisible(
|
||||||
|
key!.currentContext!,
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
alignment: 0, // 滚动到顶部
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新分组的全选状态
|
||||||
|
void _updateGroupSelection(String group) {
|
||||||
|
final groupPersons = groupedPersons[group]!;
|
||||||
|
final allSelected = groupPersons.every((person) => selectedStates[person.id] == true);
|
||||||
|
final anySelected = groupPersons.any((person) => selectedStates[person.id] == true);
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
groupSelectedStates[group] = allSelected;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 切换分组的全选/全不选
|
||||||
|
void _toggleGroupSelection(String group) {
|
||||||
|
final newState = !(groupSelectedStates[group] ?? false);
|
||||||
|
final groupPersons = groupedPersons[group]!;
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
groupSelectedStates[group] = newState;
|
||||||
|
for (var person in groupPersons) {
|
||||||
|
selectedStates[person.id] = newState;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取选中的人员
|
||||||
|
SelectionPersonResult _getSelectedResult() {
|
||||||
|
List<Person> selectedPersons = [];
|
||||||
|
Map<String, List<Person>> groupedSelected = {};
|
||||||
|
|
||||||
|
for (var group in groupedPersons.keys) {
|
||||||
|
final groupPersons = groupedPersons[group]!;
|
||||||
|
final selectedInGroup = groupPersons
|
||||||
|
.where((person) => selectedStates[person.id] == true)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
if (selectedInGroup.isNotEmpty) {
|
||||||
|
groupedSelected[group] = selectedInGroup;
|
||||||
|
selectedPersons.addAll(selectedInGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SelectionPersonResult(
|
||||||
|
selectedPersons: selectedPersons,
|
||||||
|
groupedSelected: groupedSelected,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确认添加并返回
|
||||||
|
void _confirmSelection() {
|
||||||
|
final result = _getSelectedResult();
|
||||||
|
Navigator.pop(context, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
appBar: MyAppbar(title: '选择人员', actions: [
|
||||||
|
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
_confirmSelection();
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
"确认添加",
|
||||||
|
style: TextStyle(color: Colors.white, fontSize: 16),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
],),
|
||||||
|
body: Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
color: Colors.white,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 8),
|
||||||
|
child: SearchBarWidget(
|
||||||
|
showResetButton: true,
|
||||||
|
hintText: '请输入关键字',
|
||||||
|
resetButtonText: '重置',
|
||||||
|
onReset: () {
|
||||||
|
FocusScope.of(context).unfocus();
|
||||||
|
_searchController.text = '';
|
||||||
|
_search();
|
||||||
|
},
|
||||||
|
onSearch: (text) {
|
||||||
|
FocusScope.of(context).unfocus();
|
||||||
|
_search();
|
||||||
|
},
|
||||||
|
controller: _searchController,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
// 人员列表
|
||||||
|
Expanded(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
// 左侧人员列表
|
||||||
|
Expanded(
|
||||||
|
child: ListView.builder(
|
||||||
|
controller: _scrollController,
|
||||||
|
itemCount: sortedGroupKeys.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
String group = sortedGroupKeys[index];
|
||||||
|
List<Person> persons = groupedPersons[group]!;
|
||||||
|
|
||||||
|
return _buildGroupSection(group, persons);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// 右侧字母导航
|
||||||
|
Container(
|
||||||
|
width: 30,
|
||||||
|
color: Colors.grey.shade50,
|
||||||
|
child: ListView.builder(
|
||||||
|
itemCount: alphabet.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final letter = alphabet[index];
|
||||||
|
final hasGroup = groupedPersons.containsKey(letter);
|
||||||
|
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: hasGroup ? () => _scrollToGroup(letter) : null,
|
||||||
|
child: Container(
|
||||||
|
height: 30,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Text(
|
||||||
|
letter,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
color: hasGroup
|
||||||
|
? Colors.blue
|
||||||
|
: Colors.grey.shade400,
|
||||||
|
fontWeight: hasGroup
|
||||||
|
? FontWeight.bold
|
||||||
|
: FontWeight.normal,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建分组区域
|
||||||
|
Widget _buildGroupSection(String group, List<Person> persons) {
|
||||||
|
return Container(
|
||||||
|
key: groupKeys[group],
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// 分组标题
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||||
|
color: Colors.grey.shade100,
|
||||||
|
height: 56, // 固定高度便于计算
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
group,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Spacer(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// 人员列表
|
||||||
|
...persons.map((person) => _buildPersonItem(person)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建人员项
|
||||||
|
Widget _buildPersonItem(Person person) {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
bottom: BorderSide(
|
||||||
|
color: Colors.grey.shade200,
|
||||||
|
width: 0.5,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
height: 56, // 固定高度便于计算
|
||||||
|
child: CheckboxListTile(
|
||||||
|
title: Text(
|
||||||
|
person.name,
|
||||||
|
style: const TextStyle(fontSize: 14),
|
||||||
|
),
|
||||||
|
value: selectedStates[person.id] ?? false,
|
||||||
|
onChanged: (bool? value) {
|
||||||
|
setState(() {
|
||||||
|
selectedStates[person.id] = value ?? false;
|
||||||
|
_updateGroupSelection(person.group);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
activeColor: Colors.blue,
|
||||||
|
controlAffinity: ListTileControlAffinity.leading,
|
||||||
|
contentPadding: const EdgeInsets.symmetric(horizontal: 0),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _search() {
|
||||||
|
// searchKeywords = _searchController.text.trim();
|
||||||
|
// currentPage = 1;
|
||||||
|
// list.clear();
|
||||||
|
// _fetchData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,206 @@
|
||||||
|
|
||||||
|
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 = [];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@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();
|
||||||
|
}
|
||||||
|
},),
|
||||||
|
Expanded( child: WebViewWidget(controller: _controller),),
|
||||||
|
// 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, '请先签字');
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue