2025.7.24 法律法规详情页面和功能,完成已验收列表,已验收详情,待整改列表,待整改详情页面

main
xufei 2025-07-24 20:01:23 +08:00
parent 4d3fb2b6e6
commit 507dee2e67
14 changed files with 1537 additions and 110 deletions

View File

@ -968,6 +968,20 @@ U6Hzm1ninpWeE+awIDAQAB
);
}
///
static Future<Map<String, dynamic>> getDangerDetailTwo(String id) {
return HttpManager().request(
basePath,
'/app/customHidden/goEdit',
method: Method.post,
data: {
"HIDDEN_ID": id,
"CORPINFO_ID": SessionService.instance.corpinfoId,
"USER_ID": SessionService.instance.loginUserId,
},
);
}
///
static Future<Map<String, dynamic>> getUserInfo() {
return HttpManager().request(
@ -1109,6 +1123,70 @@ U6Hzm1ninpWeE+awIDAQAB
);
}
///
static Future<Map<String, dynamic>> getLowListByParentId(String id) {
return HttpManager().request(
basePath,
'/app/mfolderStipulate/listByParentId',
method: Method.post,
data: {
"PARENT_ID":id,
"TYPE":2,
"CORPINFO_ID":SessionService.instance.corpinfoId,
"USER_ID":SessionService.instance.loginUserId,
},
);
}
///
static Future<Map<String, dynamic>> rectificationSubmission(String id,String buMenId,String renYuanId) {
return HttpManager().request(
basePath,
'/app/hidden/editRec',
method: Method.post,
data: {
"RECTIFICATIONDEPT": buMenId,
"RECTIFICATIONOR": renYuanId,
"HIDDEN_ID": id,
"CORPINFO_ID": SessionService.instance.corpinfoId,
"USER_ID": SessionService.instance.loginUserId,
},
);
}
///
static Future<Map<String, dynamic>> normalRectificationSubmission(String id,String buMenId,String renYuanId) {
return HttpManager().request(
basePath,
'/app/hidden/rectify',
method: Method.post,
data: {
// "RECTIFICATIONTIME": _this.RECTIFICATIONTIME,
// "RECTIFYDESCR": _this.RECTIFYDESCR,
// "HAVESCHEME": _this.HAVESCHEME,
// "HAVEPLAN": _this.HAVEPLAN,
// "HIDDEN_ID": _this.id,
//
// "SCREENINGDATE": _this.pd.CREATTIME ? _this.pd.CREATTIME : '',
// "LISTNAME": _this.pd.LIST_NAME ? _this.pd.LIST_NAME : '',
// "GOVERNSTANDARDS": _this.pd.GOVERNSTANDARDS ? _this.pd.GOVERNSTANDARDS : '',
// "GOVERNMETHOD": _this.pd.GOVERNMETHOD ? _this.pd.GOVERNMETHOD : '',
// "EXPENDITURE": _this.pd.EXPENDITURE ? _this.pd.EXPENDITURE : '',
// "PRINCIPAL": _this.pd.PRINCIPAL ? _this.pd.PRINCIPAL : '',
// "PROGRAMMING": _this.pd.PROGRAMMING ? _this.pd.PROGRAMMING : '',
// "TIMELIMITFOR": _this.pd.TIMELIMITFOR ? _this.pd.TIMELIMITFOR : '',
// "JOBREQUIREMENT": _this.pd.JOBREQUIREMENT ? _this.pd.JOBREQUIREMENT : '',
// "OTHERBUSINESS": _this.pd.OTHERBUSINESS ? _this.pd.OTHERBUSINESS : '',
// "OTHER": JSON.stringify(_this.other),
"CORPINFO_ID": SessionService.instance.corpinfoId,
"USER_ID": SessionService.instance.loginUserId,
},
);
}
}

View File

@ -10,7 +10,7 @@ import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/tools/SmallWidget.dart';
import 'package:qhd_prevention/tools/tools.dart';
import '../../../http/ApiService.dart';
import '../../http/ApiService.dart';
class AiAlarmPage extends StatefulWidget {
const AiAlarmPage({super.key});

View File

@ -1,12 +1,12 @@
import 'package:flutter/material.dart';
import 'package:qhd_prevention/pages/app/Danger_paicha/check_record_page.dart';
import 'package:qhd_prevention/pages/app/Danger_paicha/quick_report_page.dart';
import 'package:qhd_prevention/pages/home/work/danger_wait_list_page.dart';
import 'package:qhd_prevention/pages/app/danger_wait_list_page.dart';
import 'package:qhd_prevention/pages/home/work/risk_list_page.dart';
import '../../tools/tools.dart';
import '../home/userInfo_page.dart';
import '../home/work/ai_alarm_page.dart';
import 'ai_alarm_page.dart';
import '../home/work/danger_page.dart';
import '../home/work/danger_repair_page.dart';

View File

@ -1,14 +1,15 @@
import 'package:flutter/material.dart';
import 'package:qhd_prevention/pages/app/pending_rectification_detail_page.dart';
import 'package:qhd_prevention/pages/home/work/custom_driver_drawer.dart';
import 'package:qhd_prevention/pages/home/risk/risk_detail_page.dart';
import 'package:qhd_prevention/pages/home/work/danger_repair_page.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 '../../../http/ApiService.dart';
import '../../app/application_page.dart';
import '../../http/ApiService.dart';
import 'application_page.dart';
import '/customWidget/search_bar_widget.dart';
import 'danger_wait_deawer.dart';
import '../home/work/danger_wait_deawer.dart';
import 'hidden_record_detail_page.dart';
enum DangerType {
@ -16,9 +17,9 @@ enum DangerType {
ristRecord("隐患记录", "隐患记录-详情"),
wait("待整改隐患", "隐患整改"),
expired("超期未整改", "超期未整改-详情"),
waitAcceptance("隐患验收", "隐患验收"),
waitAcceptance("隐患验收", "隐患验收-详情"),
acceptance("已验收隐患", "已验收隐患"),
acceptanced("已验收隐患", "隐患记录-详情");
acceptanced("已验收隐患", "已验收隐患-详情");
final String displayName;
final String detailTitle;
@ -103,6 +104,7 @@ class _DangerWaitListPageState extends State<DangerWaitListPage> {
appBar: MyAppbar(
title: widget.dangerType.displayName,
actions: [
if(1==widget.appItem)
TextButton(
onPressed: () {
//
@ -207,15 +209,32 @@ class _DangerWaitListPageState extends State<DangerWaitListPage> {
break;
case 2://
// _getDangerRecord(2,_page,"","","","","","","","",keyWord,addList);
// pushPage(PendingRectificationDetailPage(widget.dangerType,item), context);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PendingRectificationDetailPage(
widget.dangerType,item,
onClose: (result) {
print('详情页面已关闭,返回结果: $result');
getListData(widget.appItem,false,"");
SessionService.instance.setDangerWaitInfo("");
// reRefreshData();
},
),
),
);
break;
case 3://
// _getDangerRecord(5,_page,"","","","","-1","","","",keyWord,addList);
pushPage(HiddenRecordDetailPage(widget.dangerType,item), context);
break;
case 4://
// _getDangerRecord(3,_page,"","","","","","3","","",keyWord,addList);
pushPage(HiddenRecordDetailPage(widget.dangerType,item), context);
break;
case 5://
// _getDangerRecord(4,_page,"","","","","","4","","1",keyWord,addList);
pushPage(HiddenRecordDetailPage(widget.dangerType,item), context);
break;
}

View File

@ -1,49 +1,105 @@
import 'dart:io';
import 'package:flutter/material.dart';
import '../../../../../customWidget/ItemWidgetFactory.dart';
import '../../../../../customWidget/custom_button.dart';
import '../../../../../customWidget/date_picker_dialog.dart';
import '../../../../../customWidget/photo_picker_row.dart';
import '../../../../../tools/h_colors.dart';
import '../../../../../tools/tools.dart';
import 'package:intl/intl.dart';
import 'package:qhd_prevention/customWidget/department_person_picker.dart';
import 'package:qhd_prevention/customWidget/department_picker.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/http/ApiService.dart';
import '../../customWidget/ItemWidgetFactory.dart';
import '../../customWidget/custom_button.dart';
import '../../customWidget/date_picker_dialog.dart';
import '../../customWidget/photo_picker_row.dart';
import '../../tools/h_colors.dart';
import '../../tools/tools.dart';
class DepartmentEntry {
String department;
String responsible;
DepartmentEntry({
required this.department,
required this.responsible,
});
}
///
class DannerRepair extends StatefulWidget {
const DannerRepair({super.key});
DannerRepair(this.pd, {super.key});
final Map<String, dynamic> pd;
final _DannerRepairState DannerRepairState=_DannerRepairState();
@override
State<DannerRepair> createState() => _DannerRepairState();
State<DannerRepair> createState() => DannerRepairState;
}
class _DannerRepairState extends State<DannerRepair> {
//
bool _acceptedPrepare = false;
bool acceptedPrepare = false;
//
bool _acceptedPlan = false;
final _standardController = TextEditingController();
final _methodController = TextEditingController();
final _fundController = TextEditingController();
final _personController = TextEditingController();
final _workTimeController = TextEditingController();
final _timeController = TextEditingController();
final _workController = TextEditingController();
final _otherController = TextEditingController();
bool acceptedPlan = false;
final standardController = TextEditingController();
final methodController = TextEditingController();
final fundController = TextEditingController();
final personController = TextEditingController();
final workTimeController = TextEditingController();
final timeController = TextEditingController();
final workController = TextEditingController();
final otherController = TextEditingController();
late var _selectData = DateTime.now();
late TextEditingController miaoShuController;
String dataTime="";
//
List<String> gaiHouImages = [];
//
List<String> fangAnImages = [];
//
List<String> jiHuaImages = [];
int yanShouAdd=1;
final List<DepartmentEntry> _departments = [
DepartmentEntry(department: '请选择', responsible: '请选择'),
];
void _addDepartment() {
setState(() {
_departments.add(DepartmentEntry(department: '请选择', responsible: '请选择'));
});
}
void _removeDepartment(int index) {
if (index == 0) return; //
setState(() {
_departments.removeAt(index);
});
}
@override
void initState() {
// TODO: implement initState
super.initState();
// _yanShouFuZeItem.add(_departmentItem(0));
}
@override
void dispose() {
//
_standardController.dispose();
_methodController.dispose();
_fundController.dispose();
_personController.dispose();
_workTimeController.dispose();
_timeController.dispose();
_workController.dispose();
_otherController.dispose();
standardController.dispose();
methodController.dispose();
fundController.dispose();
personController.dispose();
workTimeController.dispose();
timeController.dispose();
workController.dispose();
otherController.dispose();
super.dispose();
}
@ -69,6 +125,7 @@ class _DannerRepairState extends State<DannerRepair> {
children: [HhTextStyleUtils.mainTitle("隐患描述", fontSize: 15)],
),
TextField(
controller: miaoShuController,
keyboardType: TextInputType.multiline,
maxLines: null, //
style: TextStyle(fontSize: 15),
@ -93,6 +150,8 @@ class _DannerRepairState extends State<DannerRepair> {
Navigator.of(context).pop();
setState(() {
_selectData = selected;
dataTime= DateFormat('yyyy-MM-dd').format(selected);
});
},
),
@ -102,7 +161,7 @@ class _DannerRepairState extends State<DannerRepair> {
padding: EdgeInsets.symmetric(horizontal: 15),
child: ListItemFactory.createRowSpaceBetweenItem(
leftText: "整改日期",
rightText: "请选择",
rightText: dataTime.isEmpty?"请选择":dataTime,
isRight: true,
),
),
@ -114,8 +173,14 @@ class _DannerRepairState extends State<DannerRepair> {
mediaType: MediaType.image,
onChanged: (files) {
// files
gaiHouImages.clear();
for(int i=0;i<files.length;i++){
gaiHouImages.add(files[i].path);
}
},
onAiIdentify: () {
},
onAiIdentify: () {},
),
Divider(),
@ -123,7 +188,9 @@ class _DannerRepairState extends State<DannerRepair> {
mainAxisAlignment: MainAxisAlignment.end,
children: [
CustomButton(
onPressed: () {},
onPressed: () {
_addDepartment();
},
text: "添加",
backgroundColor: Colors.blue,
borderRadius: 17,
@ -132,34 +199,74 @@ class _DannerRepairState extends State<DannerRepair> {
),
],
),
_departmentItem(1),
_departmentItem(2),
Column(
children: List.generate(
_departments.length,
(index) => _departmentItem(
_departments[index],
index,
showLabel: index == 0,
),
),
),
// for(int m=0;m<_yanShouFuZeItem.length;m++)
// _yanShouFuZeItem[m],
// _departmentItem(m),
// _departmentItem(2),
Divider(),
ListItemFactory.createYesNoSection(
title: "是否有整改方案",
yesLabel: "",
noLabel: "",
groupValue: _acceptedPrepare,
groupValue: acceptedPrepare,
onChanged: (val) {
setState(() {
_acceptedPrepare = val;
acceptedPrepare = val;
});
},
),
_acceptedPrepare ? _acceptPrepare() : SizedBox(height: 1),
acceptedPrepare ? _acceptPrepare() : SizedBox(height: 1),
Divider(),
//
// const SizedBox(height: 16),
if(acceptedPrepare)
RepairedPhotoSection(
horizontalPadding: 0,
title: "方案图片",
maxCount: 4,
mediaType: MediaType.image,
onChanged: (files) {
// files
fangAnImages.clear();
for(int i=0;i<files.length;i++){
fangAnImages.add(files[i].path);
}
},
onAiIdentify: () {
},
),
Divider(),
ListItemFactory.createYesNoSection(
title: "是否有整改计划",
yesLabel: "",
noLabel: "",
groupValue: _acceptedPlan,
groupValue: acceptedPlan,
onChanged: (val) {
setState(() {
_acceptedPlan = val;
acceptedPlan = val;
});
},
),
_acceptedPlan ? _acceptPlan() : SizedBox(height: 1),
acceptedPlan ? _acceptPlan() : SizedBox(height: 1),
],
),
);
@ -167,16 +274,16 @@ class _DannerRepairState extends State<DannerRepair> {
///
Widget _acceptPrepare() {
final fields = [
_buildReadOnlyRow("排查日期", "2025-1-2 11:22:30"),
_buildReadOnlyRow("排查日期", widget.pd["CREATTIME"]),
_buildReadOnlyRow("隐患清单", "-----"),
ListItemFactory.createBuildMultilineInput("治理标准", "请输入治理标准", _standardController),
ListItemFactory.createBuildMultilineInput("治理方法", "请输入治理方法", _methodController),
ListItemFactory.createBuildMultilineInput("经费落实", "请输入经费落实", _fundController),
ListItemFactory.createBuildMultilineInput("负责人员", "请输入负责人员", _personController),
ListItemFactory.createBuildMultilineInput("工时安排", "请输入工时安排", _workTimeController),
ListItemFactory.createBuildMultilineInput("时限要求", "请输入时限要求", _timeController),
ListItemFactory.createBuildMultilineInput("工作要求", "请输入工作要求", _workController),
ListItemFactory.createBuildMultilineInput("其他事项", "请输入其他事项", _otherController),
ListItemFactory.createBuildMultilineInput("治理标准", "请输入治理标准", standardController),
ListItemFactory.createBuildMultilineInput("治理方法", "请输入治理方法", methodController),
ListItemFactory.createBuildMultilineInput("经费落实", "请输入经费落实", fundController),
ListItemFactory.createBuildMultilineInput("负责人员", "请输入负责人员", personController),
ListItemFactory.createBuildMultilineInput("工时安排", "请输入工时安排", workTimeController),
ListItemFactory.createBuildMultilineInput("时限要求", "请输入时限要求", timeController),
ListItemFactory.createBuildMultilineInput("工作要求", "请输入工作要求", workController),
ListItemFactory.createBuildMultilineInput("其他事项", "请输入其他事项", otherController),
];
return ListView.separated(
@ -202,7 +309,11 @@ class _DannerRepairState extends State<DannerRepair> {
/// item
Widget _departmentItem(int num) {
Widget _departmentItem(
DepartmentEntry entry,
int index, {
required bool showLabel,
}) {
return Padding(
padding: const EdgeInsets.all(10),
child: Stack(
@ -216,7 +327,7 @@ class _DannerRepairState extends State<DannerRepair> {
),
// num > 1
if (num > 1)
if (index > 0)
Positioned(
top: -20,
left: -20,
@ -225,6 +336,7 @@ class _DannerRepairState extends State<DannerRepair> {
constraints: const BoxConstraints(),
icon: const Icon(Icons.cancel, color: Colors.red, size: 25),
onPressed: () {
_removeDepartment(index);
//
// setState(() => _items.removeAt(num));
},
@ -236,9 +348,45 @@ class _DannerRepairState extends State<DannerRepair> {
}
// #region
Widget _noAccepet_repair(bool _accept) {
String buMenId="";
String buMenName="";
String renYuanId="";
String renYuanName="";
//
late List<Map<String, dynamic>> _personCache = [];
return Column(
children: [
Container(
GestureDetector(
onTap: () {
showModalBottomSheet(
context: context,
isScrollControlled: true,
barrierColor: Colors.black54,
backgroundColor: Colors.transparent,
builder: (ctx) => DepartmentPicker(onSelected: (id, name) async {
setState(() {
buMenId=id;
buMenName=name;
//
renYuanId="";
renYuanName="";
});
//
final result = await ApiService.getListTreePersonList(id);
_personCache=List<Map<String, dynamic>>.from(
result['userList'] as List,
);
}),
);
},
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10),
decoration: BoxDecoration(
color: Colors.white,
@ -246,15 +394,35 @@ class _DannerRepairState extends State<DannerRepair> {
),
child: ListItemFactory.createRowSpaceBetweenItem(
leftText: "整改部门",
rightText: "测试啊",
rightText: buMenName,
isRight: true,
),
),
),
Divider(
height: 10,
color: _accept ? h_backGroundColor() : Colors.transparent,
),
Container(
GestureDetector(
onTap: () {
if ( renYuanId.isEmpty) {
ToastUtil.showNormal(context, '请先选择部门');
return;
}
DepartmentPersonPicker.show(
context,
personsData: _personCache,
onSelected: (userId, name) {
setState(() {
renYuanId = userId;
renYuanName = name;
});
},
);
},
child:Container(
padding: EdgeInsets.symmetric(horizontal: 10),
decoration: BoxDecoration(
color: Colors.white,
@ -262,10 +430,11 @@ class _DannerRepairState extends State<DannerRepair> {
),
child: ListItemFactory.createRowSpaceBetweenItem(
leftText: "整改负责人",
rightText: "测试啊",
rightText: renYuanName,
isRight: true,
),
),
),
],
);
}
@ -276,8 +445,13 @@ class _DannerRepairState extends State<DannerRepair> {
padding: EdgeInsets.symmetric(horizontal: 10),
child: MediaPickerRow(
maxCount: 4,
onChanged: (List<File> images) {
onChanged: (List<File> files) {
// images
// files
jiHuaImages.clear();
for(int i=0;i<files.length;i++){
jiHuaImages.add(files[i].path);
}
},
),
);

View File

@ -5,17 +5,19 @@ import 'package:qhd_prevention/pages/my_appbar.dart';
import 'dart:convert';
import 'package:video_player/video_player.dart';
import '../../../customWidget/ItemWidgetFactory.dart';
import '../../../customWidget/single_image_viewer.dart';
import '../../../customWidget/video_player_widget.dart';
import '../../../http/ApiService.dart';
import '../../../tools/tools.dart';
import '../../customWidget/ItemWidgetFactory.dart';
import '../../customWidget/full_screen_video_page.dart';
import '../../customWidget/single_image_viewer.dart';
import '../../customWidget/video_player_widget.dart';
import '../../http/ApiService.dart';
import '../../tools/tools.dart';
import 'danger_wait_list_page.dart';
class HiddenRecordDetailPage extends StatefulWidget {
const HiddenRecordDetailPage(this.dangerType, this.item, {Key? key}) : super(key: key);
final DangerType dangerType;
final item;
@ -41,7 +43,11 @@ class _HiddenRecordDetailPageState extends State<HiddenRecordDetailPage> {
@override
void initState() {
super.initState();
getData();
if("2"==widget.item['HIDDEN_RISKSTANDARD']){
getDataTwo();
}else {
getData();
}
}
@override
@ -85,7 +91,40 @@ class _HiddenRecordDetailPageState extends State<HiddenRecordDetailPage> {
}
}
Future<void> getDataTwo() async {
try {
final data = await ApiService.getDangerDetailTwo(widget.item['HIDDEN_ID']);
if (data['result'] == 'success') {
setState(() {
pd = data['pd'];
hs = data['hs'] ?? {};
//
for (var img in data['hImgs']) {
if (img['FILEPATH'].toString().endsWith('.mp4')) {
videoList.add(img);
} else {
files.add(img["FILEPATH"]);
}
}
// List<dynamic> filesZheng = data['rImgs'] ?? [];
for (var img in data['rImgs']) {
files2.add(img["FILEPATH"]);
}
// files2=data['rImgs'] ?? [];
files4 = data['sImgs'] ?? [];
files5 = data['pImgs'] ?? [];
files6 = data['yImgs'] ?? [];
checkList = data['checkList'] ?? [];
});
}
} catch (e) {
print('Error fetching data: $e');
}
}
@ -111,7 +150,7 @@ class _HiddenRecordDetailPageState extends State<HiddenRecordDetailPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppbar(title: "隐患记录-详情"),
appBar: MyAppbar(title: widget.dangerType.detailTitle),
body: pd.isEmpty
? const Center(child: CircularProgressIndicator())
: LayoutBuilder(
@ -184,10 +223,16 @@ class _HiddenRecordDetailPageState extends State<HiddenRecordDetailPage> {
const Text('隐患视频', style: TextStyle(fontWeight: FontWeight.bold)),
GestureDetector(
onTap: () {
present(
BigVideoViewer(videoUrl:ApiService.baseImgPath + videoList[0]['FILEPATH']),
context,
showDialog(
context: context,
barrierColor: Colors.black54,
builder: (_) => VideoPlayerPopup(videoUrl: ApiService.baseImgPath + videoList[0]['FILEPATH']),
);
// present(
// BigVideoViewer(videoUrl:ApiService.baseImgPath + videoList[0]['FILEPATH']),
// context,
// );
},
// => _playVideo(ApiService.baseImgPath + videoList[0]['FILEPATH']),
child: Image.asset(

View File

@ -0,0 +1,604 @@
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:qhd_prevention/customWidget/big_video_viewer.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'dart:convert';
import 'package:video_player/video_player.dart';
import '../../customWidget/ItemWidgetFactory.dart';
import '../../customWidget/custom_button.dart';
import '../../customWidget/department_person_picker.dart';
import '../../customWidget/department_picker.dart';
import '../../customWidget/full_screen_video_page.dart';
import '../../customWidget/single_image_viewer.dart';
import '../../customWidget/toast_util.dart';
import '../../customWidget/video_player_widget.dart';
import '../../http/ApiService.dart';
import '../../tools/h_colors.dart';
import '../../tools/tools.dart';
import 'danner_repair.dart';
import 'danger_wait_list_page.dart';
class PendingRectificationDetailPage extends StatefulWidget {
const PendingRectificationDetailPage(this.dangerType, this.item, {super.key,required this.onClose});
final Function(String) onClose; //
final DangerType dangerType;
final item;
@override
_PendingRectificationDetailPageState createState() => _PendingRectificationDetailPageState();
}
class _PendingRectificationDetailPageState extends State<PendingRectificationDetailPage> {
late Map<String, dynamic> pd = {};
late Map<String, dynamic> hs = {};
List<String> files = [];
List<String> files2 = [];
List<dynamic> files4 = [];
List<dynamic> files5 = [];
List<dynamic> files6 = [];
List<dynamic> videoList = [];
List<dynamic> checkList = [];
bool modalShow = false;
String videoSrc = "";
VideoPlayerController? _videoController;
//
bool _accepted = true;
String buMenId="";
String buMenName="";
String renYuanId="";
String renYuanName="";
//
late List<Map<String, dynamic>> _personCache = [];
late DannerRepair dannerRepair;
@override
void initState() {
super.initState();
if("2"==widget.item['HIDDEN_RISKSTANDARD']){
getDataTwo();
}else {
getData();
}
}
@override
void dispose() {
_videoController?.dispose();
super.dispose();
}
Future<void> getData() async {
try {
final data = await ApiService.getDangerDetail(widget.item['HIDDEN_ID']);
if (data['result'] == 'success') {
setState(() {
pd = data['pd'];
buMenId=pd["RECTIFICATIONDEPT"];
buMenName=pd["RECTIFICATIONDEPTNAME"];
renYuanId=pd["RECTIFICATIONOR"];
renYuanName=pd["RECTIFICATIONORNAME"];
hs = data['hs'] ?? {};
//
for (var img in data['hImgs']) {
if (img['FILEPATH'].toString().endsWith('.mp4')) {
videoList.add(img);
} else {
files.add(img["FILEPATH"]);
}
}
// List<dynamic> filesZheng = data['rImgs'] ?? [];
for (var img in data['rImgs']) {
files2.add(img["FILEPATH"]);
}
// files2=data['rImgs'] ?? [];
files4 = data['sImgs'] ?? [];
files5 = data['pImgs'] ?? [];
files6 = data['yImgs'] ?? [];
checkList = data['checkList'] ?? [];
});
}
} catch (e) {
print('Error fetching data: $e');
}
}
Future<void> getDataTwo() async {
try {
final data = await ApiService.getDangerDetailTwo(widget.item['HIDDEN_ID']);
if (data['result'] == 'success') {
setState(() {
pd = data['pd'];
hs = data['hs'] ?? {};
//
for (var img in data['hImgs']) {
if (img['FILEPATH'].toString().endsWith('.mp4')) {
videoList.add(img);
} else {
files.add(img["FILEPATH"]);
}
}
// List<dynamic> filesZheng = data['rImgs'] ?? [];
for (var img in data['rImgs']) {
files2.add(img["FILEPATH"]);
}
// files2=data['rImgs'] ?? [];
files4 = data['sImgs'] ?? [];
files5 = data['pImgs'] ?? [];
files6 = data['yImgs'] ?? [];
checkList = data['checkList'] ?? [];
});
}
} catch (e) {
print('Error fetching data: $e');
}
}
Widget _buildInfoItem(String title, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 120,
child: Text(
title,
style: const TextStyle(fontWeight: FontWeight.bold),
),
),
Expanded(child: Text(value,textAlign: TextAlign.right,)),
],
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppbar(title: widget.dangerType.detailTitle),
body: pd.isEmpty
? const Center(child: CircularProgressIndicator())
: LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: constraints.maxHeight,
),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildInfoItem('隐患描述', pd['HIDDENDESCR'] ?? ''),
Divider(height: 1),
//
_buildInfoItem('隐患来源', _getSourceText(pd['SOURCE'])),
Divider(height: 1),
//
if (pd['SOURCE'] == '2') ...[
_buildInfoItem('风险点(单元)', pd['RISK_UNIT'] ?? ''),
Divider(height: 1),
_buildInfoItem('辨识部位', pd['IDENTIFICATION'] ?? ''),
Divider(height: 1),
_buildInfoItem('存在风险', pd['RISK_DESCR'] ?? ''),
Divider(height: 1),
_buildInfoItem('风险分级', pd['LEVEL'] ?? ''),
Divider(height: 1),
_buildInfoItem('检查内容', pd['CHECK_CONTENT'] ?? ''),
Divider(height: 1),
],
_buildInfoItem('隐患部位', pd['HIDDENPART'] ?? ''),
Divider(height: 1),
_buildInfoItem('发现人', pd['CREATORNAME'] ?? ''),
Divider(height: 1),
_buildInfoItem('发现时间', pd['CREATTIME'] ?? ''),
Divider(height: 1),
if (pd['HIDDEN_CATEGORY']?.isNotEmpty == true)
_buildInfoItem('隐患类别', pd['HIDDEN_CATEGORY_NAME'] ?? ''),
_buildInfoItem('隐患类型', pd['HIDDENTYPE_NAME'] ?? ''),
Divider(height: 1),
_buildInfoItem('整改类型', _getRectificationType(pd['RECTIFICATIONTYPE'])),
if (pd['RECTIFICATIONTYPE'] == '2')
_buildInfoItem('整改期限', pd['RECTIFICATIONDEADLINE'] ?? ''),
Divider(height: 1),
//
// const Text('隐患照片', style: TextStyle(fontWeight: FontWeight.bold)),
// _buildImageGrid(files, onTap: (index) => _showImageGallery(files, index)),
ListItemFactory.createTextImageItem(
text: "隐患照片",
imageUrls: files,
onImageTapped: (index) {
present(
SingleImageViewer(imageUrl:ApiService.baseImgPath + files[index]),
context,
);
},
),
//
if (videoList.isNotEmpty) ...[
const SizedBox(height: 16),
const Text('隐患视频', style: TextStyle(fontWeight: FontWeight.bold)),
GestureDetector(
onTap: () {
showDialog(
context: context,
barrierColor: Colors.black54,
builder: (_) => VideoPlayerPopup(videoUrl: ApiService.baseImgPath + videoList[0]['FILEPATH']),
);
// present(
// BigVideoViewer(videoUrl:ApiService.baseImgPath + videoList[0]['FILEPATH']),
// context,
// );
},
// => _playVideo(ApiService.baseImgPath + videoList[0]['FILEPATH']),
child: Image.asset(
'assets/image/videostart.png', //
color: Colors.blue,
width: 120,
height: 120,
),
),
],
SizedBox(height: 10,),
//
// if (pd['STATE'] != null && int.parse(pd['STATE']) >= 2 && int.parse(pd['STATE']) <= 4) ...[
// // const Divider(height: 10,color: Colors.grey,),
// const Text('整改信息', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
// Divider(height: 1),
// _buildInfoItem('整改描述', pd['RECTIFYDESCR'] ?? ''),
// Divider(height: 1),
// _buildInfoItem('整改部门', pd['RECTIFICATIONDEPTNAME'] ?? ''),
// Divider(height: 1),
// _buildInfoItem('整改人', pd['RECTIFICATIONORNAME'] ?? ''),
// Divider(height: 1),
// _buildInfoItem('整改时间', pd['RECTIFICATIONTIME'] ?? ''),
// Divider(height: 1),
// // const Text('整改后图片', style: TextStyle(fontWeight: FontWeight.bold)),
// // _buildImageGrid(files2, onTap: (index) => _showImageGallery(files2, index)),
// ListItemFactory.createTextImageItem(
// text: "整改后图片",
// imageUrls: files2,
// onImageTapped: (index) {
// present(
// SingleImageViewer(imageUrl: ApiService.baseImgPath +files2[index]),
// context,
// );
// },
// ),
//
// // ...
// ],
//
//
_danner_type_wait(),
SizedBox(height: MediaQuery.of(context).padding.bottom + 20),
],
),
),
),
);
},
),
);
}
///
Widget _danner_type_wait() {
return SizedBox(
child: Column(
children: [
ListItemFactory.createYesNoSection(
horizontalPadding: 0,
title: '是否正常整改',
yesLabel: '',
noLabel: '',
groupValue: _accepted,
onChanged: (val) {
setState(() {
_accepted = val;
});
},
),
//
_accepted ? _getRepairState() : _noAccepet_repair(_accepted),
const SizedBox(height: 20),
CustomButton(
text: "提交",
backgroundColor: Colors.blue,
onPressed: () {
// ToastUtil
//
// _submitToServer();
_accepted ? _normalRectificationSubmission() : _rectificationSubmission();
},
),
],
),
);
}
Widget _getRepairState() {
dannerRepair= DannerRepair(pd);
return dannerRepair;
}
// #region
Widget _noAccepet_repair(bool _accept) {
return Column(
children: [
GestureDetector(
onTap: () {
showModalBottomSheet(
context: context,
isScrollControlled: true,
barrierColor: Colors.black54,
backgroundColor: Colors.transparent,
builder: (ctx) => DepartmentPicker(onSelected: (id, name) async {
setState(() {
buMenId=id;
buMenName=name;
//
renYuanId="";
renYuanName="";
});
//
final result = await ApiService.getListTreePersonList(id);
_personCache=List<Map<String, dynamic>>.from(
result['userList'] as List,
);
}),
);
},
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(5),
),
child: ListItemFactory.createRowSpaceBetweenItem(
leftText: "整改部门",
rightText: buMenName,
isRight: true,
),
),
),
Divider(
height: 10,
color: _accept ? h_backGroundColor() : Colors.transparent,
),
GestureDetector(
onTap: () {
if ( renYuanId.isEmpty) {
ToastUtil.showNormal(context, '请先选择部门');
return;
}
DepartmentPersonPicker.show(
context,
personsData: _personCache,
onSelected: (userId, name) {
setState(() {
renYuanId = userId;
renYuanName = name;
});
},
);
},
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(5),
),
child: ListItemFactory.createRowSpaceBetweenItem(
leftText: "整改负责人",
rightText: renYuanName,
isRight: true,
),
),
),
],
);
}
Future<void> _normalRectificationSubmission() async {
try {
String miaoShu= dannerRepair.DannerRepairState.miaoShuController.text;
if(miaoShu.isEmpty){
ToastUtil.showNormal(context, "请填整改描述");
return;
}
String dataTime= dannerRepair.DannerRepairState.dataTime;
if(dataTime.isEmpty){
ToastUtil.showNormal(context, "请选择整改时间");
return;
}
List<String> gaiHouImages = dannerRepair.DannerRepairState.gaiHouImages;
if(gaiHouImages.isEmpty){
ToastUtil.showNormal(context, "请上传整改后照片");
return;
}
//
bool acceptedPrepare= dannerRepair.DannerRepairState.acceptedPrepare;
if(acceptedPrepare){
String standard= dannerRepair.DannerRepairState.standardController.text;
if(standard.isEmpty){
ToastUtil.showNormal(context, "请输入治理标准要求");
return;
}
String method= dannerRepair.DannerRepairState.methodController.text;
if(method.isEmpty){
ToastUtil.showNormal(context, "请输入治理方法");
return;
}
String fund= dannerRepair.DannerRepairState.fundController.text;
if(fund.isEmpty){
ToastUtil.showNormal(context, "请输入经费和物资的落实");
return;
}
String person= dannerRepair.DannerRepairState.personController.text;
if(person.isEmpty){
ToastUtil.showNormal(context, "请输入负责治理人员");
return;
}
String workTime= dannerRepair.DannerRepairState.workTimeController.text;
if(workTime.isEmpty){
ToastUtil.showNormal(context, "请输入工时安排");
return;
}
String time= dannerRepair.DannerRepairState.timeController.text;
if(time.isEmpty){
ToastUtil.showNormal(context, "请输入时限要求");
return;
}
String work= dannerRepair.DannerRepairState.workController.text;
if(work.isEmpty){
ToastUtil.showNormal(context, "请输入工作要求");
return;
}
String other= dannerRepair.DannerRepairState.otherController.text;
if(other.isEmpty){
ToastUtil.showNormal(context, "请输入工作要求");
return;
}
List<String> fangAnImages = dannerRepair.DannerRepairState.fangAnImages;
if(fangAnImages.isEmpty){
ToastUtil.showNormal(context, "请上传方案照片");
return;
}
}
//
bool acceptedPlan= dannerRepair.DannerRepairState.acceptedPlan;
if(acceptedPlan){
List<String> fangAnImages = dannerRepair.DannerRepairState.jiHuaImages;
if(fangAnImages.isEmpty){
ToastUtil.showNormal(context, "请上传计划照片");
return;
}
}
final result = await ApiService.normalRectificationSubmission(pd["HIDDEN_ID"],buMenId,renYuanId);
if (result['result'] == 'success') {
setState(() {
ToastUtil.showNormal(context, "提交成功");
Navigator.of(context).pop();
widget.onClose('关闭详情'); //
});
}else{
ToastUtil.showNormal(context, "加载数据失败");
}
} catch (e) {
// Toast
print('加载数据失败:$e');
}
}
Future<void> _rectificationSubmission() async {
try {
final result = await ApiService.rectificationSubmission(pd["HIDDEN_ID"],buMenId,renYuanId);
if (result['result'] == 'success') {
setState(() {
ToastUtil.showNormal(context, "提交成功");
Navigator.of(context).pop();
widget.onClose('关闭详情'); //
});
}else{
ToastUtil.showNormal(context, "加载数据失败");
}
} catch (e) {
// Toast
print('加载数据失败:$e');
}
}
String _getSourceText(String? source) {
switch (source) {
case '1': return '隐患快报';
case '2': return '隐患排查清单检查';
case '3': return '标准排查清单检查';
case '4': return '专项检查';
case '5': return '安全检查';
default: return '';
}
}
String _getRectificationType(String? type) {
switch (type) {
case '1': return '立即整改';
case '2': return '限期整改';
default: return '';
}
}
}

View File

@ -8,7 +8,7 @@ import 'package:qhd_prevention/pages/home/study/study_garden_page.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/work_tab_list_page.dart';
import 'package:qhd_prevention/pages/home/userInfo_page.dart';
import 'package:qhd_prevention/pages/home/work/danger_page.dart';
import 'package:qhd_prevention/pages/home/work/danger_wait_list_page.dart';
import 'package:qhd_prevention/pages/app/danger_wait_list_page.dart';
import 'package:qhd_prevention/pages/home/work/laws_regulations_page.dart';
import 'package:qhd_prevention/pages/home/workSet_page.dart';

View File

@ -3,8 +3,8 @@ import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/pages/home/work/dangerTypeItems/danger_detail.dart';
import 'package:qhd_prevention/pages/home/work/dangerTypeItems/finish/danger_acceptance_finish.dart';
import 'package:qhd_prevention/pages/home/work/dangerTypeItems/wait/danger_acceptance.dart';
import 'package:qhd_prevention/pages/home/work/dangerTypeItems/wait/danner_repair.dart';
import 'package:qhd_prevention/pages/home/work/danger_wait_list_page.dart';
import 'package:qhd_prevention/pages/app/danner_repair.dart';
import 'package:qhd_prevention/pages/app/danger_wait_list_page.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/tools/h_colors.dart';
import '../../../customWidget/ItemWidgetFactory.dart';
@ -130,7 +130,7 @@ class _DangerRepairPageState extends State<DangerRepairPage> {
},
),
//
_accepted ? DannerRepair() : _noAccepet_repair(_accepted),
// _accepted ? DannerRepair() : _noAccepet_repair(_accepted),
const SizedBox(height: 20),
CustomButton(
@ -230,63 +230,75 @@ class _DangerRepairPageState extends State<DangerRepairPage> {
children: [
ListItemFactory.createRowSpaceBetweenItem(
leftText: "隐患描述",
rightText: pd["HIDDENDESCR"],
rightText: "",
// rightText: pd["HIDDENDESCR"]??"",
),
Divider(height: 1),
ListItemFactory.createRowSpaceBetweenItem(
leftText: "隐患来源",
rightText: _getSourceDangers(pd),
rightText: "",
// rightText: _getSourceDangers(pd),
),
Divider(height: 1),
ListItemFactory.createRowSpaceBetweenItem(
leftText: "风险点(单元)",
rightText: pd["RISK_UNIT"],
rightText: "",
// rightText: pd["RISK_UNIT"]??"",
),
Divider(height: 1),
ListItemFactory.createRowSpaceBetweenItem(
leftText: "辨识部位",
rightText: pd["IDENTIFICATION"],
rightText: "",
// rightText: pd["IDENTIFICATION"]??"",
),
Divider(height: 1),
ListItemFactory.createColumnTextItem(
topText: "存在风险",
bottomText: pd["RISK_DESCR"],
bottomText: "",
// bottomText: pd["RISK_DESCR"]??"",
),
Divider(height: 1),
ListItemFactory.createRowSpaceBetweenItem(
leftText: "风险分级",
rightText: pd["LEVEL"],
rightText: "",
// rightText: pd["LEVEL"]??"",
),
Divider(height: 1),
ListItemFactory.createColumnTextItem(
topText: "检测内容",
bottomText: pd["CHECK_CONTENT"],
bottomText: "",
// bottomText: pd["CHECK_CONTENT"]??"",
),
Divider(height: 1),
ListItemFactory.createRowSpaceBetweenItem(
leftText: "隐患部位",
rightText: pd["HIDDENPART"],
rightText: "",
// rightText: pd["HIDDENPART"]??"",
),
Divider(height: 1),
ListItemFactory.createRowSpaceBetweenItem(
leftText: "发现人",
rightText: pd["CREATORNAME"],
rightText: "",
// rightText: pd["CREATORNAME"]??"",
),
Divider(height: 1),
ListItemFactory.createRowSpaceBetweenItem(
leftText: "发现时间",
rightText: pd["CREATTIME"],
rightText: "",
// rightText: pd["CREATTIME"]??"",
),
Divider(height: 1),
ListItemFactory.createRowSpaceBetweenItem(
leftText: "隐患类型",
rightText: pd["HIDDENTYPE_NAME"],
rightText: "",
// rightText: pd["HIDDENTYPE_NAME"]??"",
),
Divider(height: 1),
ListItemFactory.createRowSpaceBetweenItem(
leftText: "整改类型",
rightText: _getZhengGaiType(pd),
rightText: "",
// rightText: _getZhengGaiType(pd),
),
Divider(height: 1),

View File

@ -73,9 +73,10 @@ class _LawsListPickerState extends State<LawsListPicker> {
} else {
expandedSet.add(cat.id);
}
}else {
selectedId = cat.id;
widget.onSelected(cat);
}
selectedId = cat.id;
widget.onSelected(cat);
});
},
child: Container(

View File

@ -4,14 +4,19 @@ import 'dart:convert';
import 'package:path_provider/path_provider.dart';
import 'package:intl/intl.dart';
import 'package:dio/dio.dart';
import 'package:qhd_prevention/pages/home/work/read_file_page.dart';
import 'package:qhd_prevention/pages/home/work/risk_list_picker.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import '../../../customWidget/remote_file_page.dart';
import '../../../customWidget/search_bar_widget.dart';
import '../../../http/ApiService.dart';
import '../../../tools/tools.dart';
import 'laws_list_picker.dart';
import 'package:url_launcher/url_launcher.dart';
import 'laws_regulations_two_page.dart';
class LawsRegulationsPage extends StatefulWidget {
const LawsRegulationsPage({super.key});
@ -89,28 +94,20 @@ class _LawsRegulationsPage extends State<LawsRegulationsPage> {
//
try {
final url =ApiService.baseImgPath + file["FILEPATH"];
openFile(url);
pushPage(
ReadFilePage(
fileUrl: url,
),
context,
);
} catch (e) {
print(e.toString());
}
}
Future<void> openFile(String url) async {
// final Uri _url = Uri.file(filePath);
if (await canLaunch(url)) {
await launch(
url,
forceSafariVC: false, // iOSfalse使SafariViewController
forceWebView: false, // false使WebView
enableJavaScript: true, // JavaScript
);
} else {
throw 'Could not launch $url';
}
}
String _formatDate(String dateString) {
try {
@ -146,7 +143,9 @@ class _LawsRegulationsPage extends State<LawsRegulationsPage> {
body: Column(
children: [
//
Padding(
Container(
color: Colors.white,
child:Padding(
padding: EdgeInsets.all(10),
child: SearchBarWidget(
controller: _searchController,
@ -156,7 +155,7 @@ class _LawsRegulationsPage extends State<LawsRegulationsPage> {
},
),
),
),
Expanded(child: _buildContent()),
],
),
@ -168,11 +167,13 @@ class _LawsRegulationsPage extends State<LawsRegulationsPage> {
return LawsListPicker(
data: _accordionList,
onSelected: (item) {
setState(() {
pushPage(LawsRegulationsTwoPage(item!.id), context);
// setState(() {
// riskId = item?.id;
// itemNameTwo=item!.name;
// setResult();
});
// });
},
);

View File

@ -0,0 +1,321 @@
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:path_provider/path_provider.dart';
import 'package:intl/intl.dart';
import 'package:dio/dio.dart';
import 'package:qhd_prevention/pages/home/work/read_file_page.dart';
import 'package:qhd_prevention/pages/home/work/risk_list_picker.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import '../../../customWidget/remote_file_page.dart';
import '../../../customWidget/search_bar_widget.dart';
import '../../../http/ApiService.dart';
import '../../../tools/tools.dart';
import 'laws_list_picker.dart';
import 'package:url_launcher/url_launcher.dart';
class LawsRegulationsTwoPage extends StatefulWidget {
const LawsRegulationsTwoPage(this.id, {super.key});
final String id;
@override
State<LawsRegulationsTwoPage> createState() => _LawsRegulationsTwoPage();
}
class _LawsRegulationsTwoPage extends State<LawsRegulationsTwoPage> {
final TextEditingController _searchController = TextEditingController();
List<dynamic> _fileList = [];
@override
void initState() {
super.initState();
_getLowListByParentId();
}
Future<void> _getLowListByParentId() async {
try {
_fileList.clear();
final result = await ApiService.getLowListByParentId(widget.id);
if (result['result'] == 'success') {
final List<dynamic> newList = result['varList'] ?? [];
setState(() {
_fileList.addAll(newList);
});
} else {
_showMessage('加载数据失败');
}
} catch (e) {
// Toast
print('加载数据失败:$e');
}
}
Future<void> _downloadFile(String filePath) async {
//
try {
final Uri url = Uri.parse(ApiService.baseImgPath + filePath);
if (!await launchUrl(url,mode:LaunchMode.externalApplication)) {
throw Exception('Could not launch $url');
}
} catch (e) {
print(e.toString());
}
}
Future<void> _showFile(dynamic file) async {
//
try {
final url =ApiService.baseImgPath + file["FILEPATH"];
pushPage(
ReadFilePage(
fileUrl: url,
),
context,
);
} catch (e) {
print(e.toString());
}
}
String _formatDate(String dateString) {
try {
final date = DateTime.parse(dateString);
return DateFormat('yyyy-MM-dd HH:mm:ss').format(date);
} catch (e) {
return dateString;
}
}
String _getFileType(String extension) {
switch (extension) {
case '.docx':
case '.doc':
return '文件属性:文档';
case '.xls':
case '.xlsx':
return '文件属性:表格';
case '.ppt':
case '.pptx':
return '文件属性:幻灯片';
case '.pdf':
return '文件属性PDF';
default:
return '文件属性:';
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppbar(title: "法律法规"),
body: Column(
children: [
//
// Container(
// color: Colors.white,
// child:Padding(
// padding: EdgeInsets.all(10),
// child: SearchBarWidget(
// controller: _searchController,
// onSearch: (keyboard) {
// //
// _getLowListByParentId();
// },
// ),
// ),
// ),
Expanded(child: _buildContent()),
],
),
);
}
Widget _buildContent() {
if (_fileList.isNotEmpty) {
return ListView.builder(
itemCount: _fileList.length,
itemBuilder:
(context, index) => FileCard(
file: _fileList[index],
onDownload: _downloadFile,
onPreview: _showFile,
formatDate: _formatDate,
getFileType: _getFileType,
),
);
} else {
return const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.folder_open, size: 64, color: Colors.grey),
SizedBox(height: 16),
Text('暂无数据', style: TextStyle(fontSize: 18, color: Colors.grey)),
],
),
);
}
}
void _showMessage(String msg) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(msg)));
}
}
class CustomCollapse extends StatefulWidget {
final dynamic item;
final Function(String) onTap;
const CustomCollapse({super.key, required this.item, required this.onTap});
@override
State<CustomCollapse> createState() => _CustomCollapseState();
}
class _CustomCollapseState extends State<CustomCollapse> {
bool _isExpanded = false;
@override
Widget build(BuildContext context) {
final hasChildren =
widget.item['children'] != null &&
(widget.item['children'] as List).isNotEmpty;
return Card(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Column(
children: [
ListTile(
title: Text(
widget.item['name'] ?? '未命名',
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
),
trailing:
hasChildren
? Icon(
_isExpanded ? Icons.expand_less : Icons.expand_more,
color: Colors.blue,
)
: null,
onTap:
hasChildren
? () => setState(() => _isExpanded = !_isExpanded)
: () => widget.onTap(widget.item['id'] ?? ''),
),
if (_isExpanded && hasChildren)
...(widget.item['children'] as List).map<Widget>((child) {
return Padding(
padding: const EdgeInsets.only(left: 16.0),
child: ListTile(
title: Text(child['name']),
leading: const Icon(Icons.description, color: Colors.blue),
onTap: () => widget.onTap(child['id'] ?? ''),
),
);
}).toList(),
],
),
);
}
}
class FileCard extends StatelessWidget {
final dynamic file;
final Function(String) onDownload;
final Function(dynamic) onPreview;
final String Function(String) formatDate;
final String Function(String) getFileType;
const FileCard({
super.key,
required this.file,
required this.onDownload,
required this.onPreview,
required this.formatDate,
required this.getFileType,
});
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
file['NAME'] ?? '未命名文件',
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10),
Text(
getFileType(file['extension_name'] ?? ''),
style: TextStyle(color: Colors.grey[600]),
),
const SizedBox(height: 5),
Text(
'上传日期:${formatDate(file['CTIME'] ?? '')}',
style: TextStyle(color: Colors.grey[600]),
),
const SizedBox(height: 15),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
OutlinedButton.icon(
icon: const Icon(Icons.download, size: 18),
label: const Text('下载'),
onPressed: () => onDownload(file['FILEPATH'] ?? ''),
style: OutlinedButton.styleFrom(
foregroundColor: Colors.blue,
side: const BorderSide(color: Colors.blue),
),
),
const SizedBox(width: 10),
ElevatedButton.icon(
icon: const Icon(Icons.visibility, size: 18),
label: const Text('预览'),
onPressed: () => onPreview(file),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.cyan,
foregroundColor: Colors.white,
),
),
],
),
],
),
),
);
}
}
//
class StudyDetailPage extends StatelessWidget {
final String parentId;
const StudyDetailPage({super.key, required this.parentId});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('详情页面')),
body: Center(child: Text('父级ID: $parentId')),
);
}
}

View File

@ -0,0 +1,148 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:pdfx/pdfx.dart';
import 'package:path_provider/path_provider.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:dio/dio.dart';
import 'package:qhd_prevention/tools/tools.dart';
class ReadFilePage extends StatefulWidget {
final String fileUrl;
// final int countdownSeconds;
const ReadFilePage({
Key? key,
required this.fileUrl,
// this.countdownSeconds = 3,
}) : super(key: key);
@override
_ReadFilePageState createState() => _ReadFilePageState();
}
class _ReadFilePageState extends State<ReadFilePage> {
String? _localPath;
bool _isLoading = true;
bool _hasScrolledToBottom = false;
bool _timerFinished = false;
late int _secondsRemaining;
Timer? _countdownTimer;
late PdfControllerPinch _pdfController;
int _totalPages = 0;
@override
void initState() {
super.initState();
// _secondsRemaining = widget.countdownSeconds;
_startCountdown();
_downloadAndLoad();
}
Future<void> _downloadAndLoad() async {
try {
final url = widget.fileUrl;
final filename = url.split('/').last;
final dir = await getTemporaryDirectory();
final filePath = '${dir.path}/$filename';
final dio = Dio();
final response = await dio.get<List<int>>(
url,
options: Options(responseType: ResponseType.bytes),
);
final file = File(filePath);
await file.writeAsBytes(response.data!);
// PDF
_pdfController = PdfControllerPinch(
document: PdfDocument.openFile(filePath),
);
setState(() {
_localPath = filePath;
_isLoading = false;
});
} catch (e) {
//
setState(() {
_isLoading = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('文件加载失败: \$e')),
);
}
}
void _startCountdown() {
_countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
setState(() {
if (_secondsRemaining > 1) {
_secondsRemaining--;
} else {
_secondsRemaining = 0;
_timerFinished = true;
_countdownTimer?.cancel();
}
});
});
}
@override
void dispose() {
_countdownTimer?.cancel();
if (!_isLoading) {
_pdfController.dispose();
}
super.dispose();
}
@override
Widget build(BuildContext context) {
final isButtonEnabled = _timerFinished && _hasScrolledToBottom;
return Scaffold(
appBar: MyAppbar(title: '文件详情'),
backgroundColor: Colors.white,
body: SafeArea(
child: Column(
children: [
Expanded(
child: _isLoading
? const Center(child: CircularProgressIndicator())
: PdfViewPinch(
controller: _pdfController,
scrollDirection: Axis.vertical,
onDocumentLoaded: (document) {
setState(() {
_totalPages = document.pagesCount;
});
},
onPageChanged: (page) {
if (page == _totalPages - 1) {
setState(() => _hasScrolledToBottom = true);
}
},
),
),
// Padding(
// padding: const EdgeInsets.all(16),
// child: CustomButton(
// backgroundColor: isButtonEnabled ? Colors.blue : Colors.grey,
// text: isButtonEnabled
// ? '我已学习完毕'
// : _secondsRemaining == 0 ? '我已学习完毕' : '$_secondsRemaining s我已学习完毕',
// onPressed: isButtonEnabled
// ? () {
// // TODO:
// Navigator.pop(context);
// }
// : null,
// ),
// ),
],
),
),
);
}
}

View File

@ -560,6 +560,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "7.0.1"
ndef_record:
dependency: transitive
description:
name: ndef_record
sha256: "0c72dfac0d5c16fc264846d103ee5d8249cd3858261a5a537b455a24c1bd5857"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.2.1"
nested:
dependency: transitive
description:
@ -568,6 +576,22 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.0"
nfc_manager:
dependency: "direct main"
description:
name: nfc_manager
sha256: "164cc0223dee528d4d05a542da921f0b3a31ca0312400701c93ebf4ce757f676"
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.0.2"
nfc_manager_ndef:
dependency: "direct main"
description:
name: nfc_manager_ndef
sha256: "676e741c42b63ab1fda5a981015cb706ab4fdb76e5d0eec6611993bb27d7e7bf"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.1"
nm:
dependency: transitive
description: