Merge remote-tracking branch 'origin/main'

# Conflicts:
#	pubspec.lock
main
hs 2025-07-28 14:22:19 +08:00
commit 51c094710f
20 changed files with 2573 additions and 530 deletions

View File

@ -35,7 +35,8 @@ class ListItemFactory {
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
rightText,
_truncateText(rightText,14),
// rightText,
style: TextStyle(fontSize: 15, color: Colors.grey),
),
SizedBox(width: 2,),
@ -47,7 +48,14 @@ class ListItemFactory {
],
),
);
}
//
static String _truncateText(String text, int maxLength) {
if (text.length <= maxLength) return text;
return text.substring(0, maxLength) + '...';
}
///2
static Widget createColumnTextItem({

View File

@ -0,0 +1,83 @@
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
///
/// Example:
/// ```dart
/// final choice = await BottomPickerTwo.show<String>(
/// context,
/// items: ['选项1', '选项2', '选项3'],
/// itemBuilder: (item) => Text(item, textAlign: TextAlign.center),
/// initialIndex: 1,
/// );
/// if (choice != null) {
/// // choice
/// }
/// ```
class BottomPickerTwo {
///
///
/// [items]:
/// [itemBuilder]: Widget
/// [initialIndex]:
/// [itemExtent]:
/// [height]:
static Future<dynamic> show<T>(
BuildContext context, {
required List<dynamic> items,
required Widget Function(dynamic item) itemBuilder,
int initialIndex = 0,
double itemExtent = 40.0,
double height = 250,
}) {
//
T selected = items[initialIndex];
return showModalBottomSheet<T>(
context: context,
backgroundColor: Colors.white,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(12)),
),
builder: (ctx) {
return SizedBox(
height: height,
child: Column(
children: [
//
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton(
onPressed: () => Navigator.of(ctx).pop(),
child: const Text('取消'),
),
TextButton(
onPressed: () => Navigator.of(ctx).pop(selected),
child: const Text('确定'),
),
],
),
),
const Divider(height: 1),
//
Expanded(
child: CupertinoPicker(
scrollController:
FixedExtentScrollController(initialItem: initialIndex),
itemExtent: 30,
onSelectedItemChanged: (index) {
selected = items[index];
},
children: items.map(itemBuilder).toList(),
),
),
],
),
);
},
);
}
}

View File

@ -0,0 +1,230 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:qhd_prevention/customWidget/search_bar_widget.dart';
import 'package:qhd_prevention/http/ApiService.dart';
import '../tools/tools.dart'; // SessionService
//
class Category {
final String id;
final String name;
final List<Category> children;
Category({
required this.id,
required this.name,
this.children = const [],
});
factory Category.fromJson(Map<String, dynamic> json) {
return Category(
id: json['id'] as String,
name: json['name'] as String,
children: (json['nodes'] as List<dynamic>)
.map((e) => Category.fromJson(e as Map<String, dynamic>))
.toList(),
);
}
}
/// id name
typedef DeptSelectHiddenTypeCallback = void Function(String id, String name);
class DepartmentPickerHiddenType extends StatefulWidget {
/// id name
final DeptSelectHiddenTypeCallback onSelected;
const DepartmentPickerHiddenType({Key? key, required this.onSelected}) : super(key: key);
@override
_DepartmentPickerHiddenTypeState createState() => _DepartmentPickerHiddenTypeState();
}
class _DepartmentPickerHiddenTypeState extends State<DepartmentPickerHiddenType> {
String selectedId = '';
String selectedName = '';
Set<String> expandedSet = {};
List<Category> original = [];
List<Category> filtered = [];
bool loading = true;
final TextEditingController _searchController = TextEditingController();
@override
void initState() {
super.initState();
//
selectedId = '';
selectedName = '';
expandedSet = {};
_searchController.addListener(_onSearchChanged);
_loadData();
}
@override
void dispose() {
_searchController.removeListener(_onSearchChanged);
_searchController.dispose();
super.dispose();
}
Future<void> _loadData() async {
try {
List<dynamic> raw;
if (SessionService.instance.departmentHiddenTypeJsonStr?.isNotEmpty ?? false) {
raw = json.decode(SessionService.instance.departmentHiddenTypeJsonStr!) as List<dynamic>;
} else {
final resultLevel = await ApiService. getHiddenLevelsListTwo();
List<dynamic> levelList = resultLevel['list'] as List;
String parentId="";
for(int i=0;i<levelList.length;i++){
String level = levelList[i]['BIANMA'];
String province= SessionService.instance.loginUser?["PROVINCE"]??"";
// null
bool isMatch = level.contains(province);
if(isMatch){
parentId=levelList[i]['DICTIONARIES_ID'];
}
}
final result = await ApiService.getHiddenTypeList(parentId);
final String nodes = result['zTreeNodes'] as String;
SessionService.instance.departmentHiddenTypeJsonStr = nodes;
raw = json.decode(nodes) as List<dynamic>;
}
setState(() {
original = raw.map((e) => Category.fromJson(e as Map<String, dynamic>)).toList();
filtered = original;
loading = false;
});
} catch (e) {
setState(() => loading = false);
}
}
void _onSearchChanged() {
final query = _searchController.text.toLowerCase().trim();
setState(() {
filtered = query.isEmpty ? original : _filterCategories(original, query);
});
}
List<Category> _filterCategories(List<Category> list, String query) {
List<Category> result = [];
for (var cat in list) {
final children = _filterCategories(cat.children, query);
if (cat.name.toLowerCase().contains(query) || children.isNotEmpty) {
result.add(Category(id: cat.id, name: cat.name, children: children));
}
}
return result;
}
Widget _buildRow(Category cat, int indent) {
final hasChildren = cat.children.isNotEmpty;
final isExpanded = expandedSet.contains(cat.id);
final isSelected = cat.id == selectedId;
return Column(
children: [
InkWell(
onTap: () {
setState(() {
if (hasChildren) {
isExpanded ? expandedSet.remove(cat.id) : expandedSet.add(cat.id);
}
selectedId = cat.id;
selectedName = cat.name;
});
},
child: Container(
color: Colors.white,
child: Row(
children: [
SizedBox(width: 16.0 * indent),
SizedBox(
width: 24,
child: hasChildren
? Icon(isExpanded ? Icons.arrow_drop_down_rounded : Icons.arrow_right_rounded,
size: 35, color: Colors.grey[600])
: const SizedBox.shrink(),
),
const SizedBox(width: 5),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 12),
child: Text(cat.name),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Icon(
isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
color: Colors.green,
),
),
],
),
),
),
if (hasChildren && isExpanded)
...cat.children.map((c) => _buildRow(c, indent + 1)),
],
);
}
@override
Widget build(BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height * 0.7,
color: Colors.white,
child: Column(
children: [
Container(
color: Colors.white,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Row(
children: [
GestureDetector(
onTap: () => Navigator.of(context).pop(),
child: const Text('取消', style: TextStyle(fontSize: 16)),
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: SearchBarWidget(
controller: _searchController,
isShowSearchButton: false,
onSearch: (keyboard) {
},
),
),
),
GestureDetector(
onTap: () {
Navigator.of(context).pop();
widget.onSelected(selectedId, selectedName);
},
child: const Text('确定', style: TextStyle(fontSize: 16, color: Colors.green)),
),
],
),
),
Divider(),
Expanded(
child: loading
? const Center(child: CircularProgressIndicator())
: Container(
color: Colors.white,
child: ListView.builder(
itemCount: filtered.length,
itemBuilder: (ctx, idx) => _buildRow(filtered[idx], 0),
),
),
),
],
),
);
}
}

View File

@ -797,6 +797,30 @@ U6Hzm1ninpWeE+awIDAQAB
);
}
///
static Future<Map<String, dynamic>> addImgFiles(String imagePath,String type,String id) async {
final file = File(imagePath);
if (!await file.exists()) {
throw ApiException('file_not_found', '图片不存在:$imagePath');
}
final fileName = file.path.split(Platform.pathSeparator).last;
return HttpManager().uploadFaceImage(
baseUrl: basePath,
path: '/app/feedback/upload',
fromData: {
'FOREIGN_KEY': id,
'TYPE': type,
"corpUserId":"",
'CORPINFO_ID': SessionService.instance.corpinfoId,
'USER_ID': SessionService.instance.loginUserId,
'FFILE': await MultipartFile.fromFile(
file.path,
filename: fileName
),
}
);
}
///
static Future<Map<String, dynamic>> changePassWord(String oldPwd,String confirmPwd) {
return HttpManager().request(
@ -1071,6 +1095,35 @@ U6Hzm1ninpWeE+awIDAQAB
},
);
}
/// 2
static Future<Map<String, dynamic>> getHiddenLevelsListTwo() {
return HttpManager().request(
basePath,
'/dictionaries/getLevels',
method: Method.post,
data: {
"DICTIONARIES_ID": '3babc15144444bdc8d763d0af2bdfff8',
"CORPINFO_ID": SessionService.instance.corpinfoId,
"USER_ID": SessionService.instance.loginUserId,
},
);
}
///
static Future<Map<String, dynamic>> getHiddenTypeList(String parentId) {
return HttpManager().request(
basePath,
'/dictionaries/listAllDictToParId',
method: Method.post,
data: {
"parentId": parentId,
"CORPINFO_ID": SessionService.instance.corpinfoId,
"USER_ID": SessionService.instance.loginUserId,
},
);
}
///
static Future<Map<String, dynamic>> getListTreePersonList(String DEPARTMENT_ID) {
return HttpManager().request(
@ -1101,6 +1154,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(
@ -1242,6 +1309,95 @@ 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 dataTime,String miaoShu,String acceptedPrepareType,String acceptedPlanType,
String id,String caertTime,String listName,
String standard,String method,String fund,String person,
String workTime,String time,String work,String other,String json) {
// print("============>"+ dataTime+ miaoShu+ acceptedPrepareType+ acceptedPlanType+
// id+ caertTime+ listName+ standard+ method+ fund+ person+
// workTime+ time+ work+ other+ json);
return HttpManager().request(
basePath,
'/app/hidden/rectify',
method: Method.post,
data: {
"RECTIFICATIONTIME": dataTime,
"RECTIFYDESCR": miaoShu,
"HAVESCHEME": acceptedPrepareType,
"HAVEPLAN": acceptedPlanType,
"HIDDEN_ID": id,
"SCREENINGDATE": caertTime.isNotEmpty ? caertTime : '',
"LISTNAME": listName.isNotEmpty ? caertTime : '',
"GOVERNSTANDARDS": standard,
"GOVERNMETHOD": method,
"EXPENDITURE": fund,
"PRINCIPAL": person,
"PROGRAMMING": workTime,
"TIMELIMITFOR": time,
"JOBREQUIREMENT": work,
"OTHERBUSINESS": other,
"OTHER": json,
"CORPINFO_ID": SessionService.instance.corpinfoId,
"USER_ID": SessionService.instance.loginUserId,
},
);
}
///
static Future<Map<String, dynamic>> getHazardLevel() {
return HttpManager().request(
basePath,
'/dictionaries/getLevels?tm=${DateTime.now().millisecondsSinceEpoch}',
method: Method.post,
data: {
"DICTIONARIES_ID": '5e7cf8620ba54ad89719d0be62133c7a',
"CORPINFO_ID": SessionService.instance.corpinfoId,
"USER_ID": SessionService.instance.loginUserId,
},
);
}
}

View File

@ -1,9 +1,16 @@
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/bottom_picker_two.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/date_picker_dialog.dart';
import 'package:qhd_prevention/customWidget/department_picker.dart';
import 'package:qhd_prevention/customWidget/department_picker_hidden_type.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import '../../../customWidget/photo_picker_row.dart';
import '../../../http/ApiService.dart';
class QuickReportPage extends StatefulWidget {
const QuickReportPage({super.key});
@ -17,13 +24,43 @@ class _QuickReportPageState extends State<QuickReportPage> {
final _partController = TextEditingController();
final _dangerDetailController = TextEditingController();
final String _repairLevel = "请选择";
final String _repairType = "请选择";
final String _dangerOrganize = "请选择";
final String _dangerTime = "请选择";
String _repairLevel = "";
late bool _isDanger = false;
late List<dynamic> _hazardLeveLlist = []; //
dynamic _hazardLeve;
String yinHuanId = "";
String yinHuanName = "";
String buMenId = "";
String buMenName = "";
String dataTime = "";
@override
void initState() {
// TODO: implement initState
super.initState();
_getHazardLevel();
}
Future<void> _getHazardLevel() async {
try {
final result = await ApiService.getHazardLevel();
if (result['result'] == 'success') {
final List<dynamic> newList = result['varList'] ?? [];
setState(() {
_hazardLeveLlist.addAll(newList);
});
}
} catch (e) {
print('Error fetching data: $e');
}
}
@override
void dispose() {
_standardController.dispose();
@ -41,14 +78,14 @@ class _QuickReportPageState extends State<QuickReportPage> {
//
_pageDetail(),
//
Container(
padding: const EdgeInsets.all(15),
color: Colors.white,
child: Text(
' 严禁在本互联网非涉密平台处理、传输国家秘密和工作秘密,请确认扫描、传输的文件资料不涉及国家秘密和工作秘密',
style: TextStyle(fontSize: 14, color: Colors.red),
),
),
// Container(
// padding: const EdgeInsets.all(15),
// color: Colors.white,
// child: Text(
// ' 严禁在本互联网非涉密平台处理、传输国家秘密和工作秘密,请确认扫描、传输的文件资料不涉及国家秘密和工作秘密',
// style: TextStyle(fontSize: 14, color: Colors.red),
// ),
// ),
],
),
);
@ -111,20 +148,55 @@ class _QuickReportPageState extends State<QuickReportPage> {
_partController,
),
),
_buildSectionContainer(
GestureDetector(
onTap: () async {
final choice = await BottomPickerTwo.show<String>(
context,
items: _hazardLeveLlist,
itemBuilder: (item) => Text(item, textAlign: TextAlign.center),
initialIndex: 0,
);
if (choice != null) {
setState(() {
_hazardLeve = choice;
_repairLevel=_hazardLeve[""];
});
}
},
child: _buildSectionContainer(
child: ListItemFactory.createRowSpaceBetweenItem(
leftText: "隐患级别",
rightText: _repairLevel,
rightText: _repairLevel.isNotEmpty?_repairLevel:"请选择",
isRight: true,
),
),
_buildSectionContainer(
),
GestureDetector(
onTap: () {
showModalBottomSheet(
context: context,
isScrollControlled: true,
barrierColor: Colors.black54,
backgroundColor: Colors.transparent,
builder:
(ctx) => DepartmentPickerHiddenType(
onSelected: (id, name) async {
setState(() {
yinHuanId = id;
yinHuanName = name;
});
},
),
);
},
child: _buildSectionContainer(
child: ListItemFactory.createRowSpaceBetweenItem(
leftText: "隐患类型",
rightText: _repairType,
rightText: yinHuanName.isNotEmpty?yinHuanName:"请选择",
isRight: true,
),
),
),
_buildSectionContainer(
child: ListItemFactory.createYesNoSection(
title: "是否立即整改",
@ -169,25 +241,68 @@ class _QuickReportPageState extends State<QuickReportPage> {
if (!_isDanger)
Column(
children: [
_buildSectionContainer(
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;
});
},
),
);
},
child: _buildSectionContainer(
child: ListItemFactory.createRowSpaceBetweenItem(
leftText: "整改责任部门",
rightText: _dangerOrganize,
rightText: buMenName.isNotEmpty ? buMenName : "请选择",
isRight: true,
),
),
_buildSectionContainer(
),
GestureDetector(
onTap: () {
showDialog(
context: context,
builder:
(_) => HDatePickerDialog(
initialDate: DateTime.now(),
onCancel: () => Navigator.of(context).pop(),
onConfirm: (selected) {
Navigator.of(context).pop();
setState(() {
dataTime = DateFormat(
'yyyy-MM-dd',
).format(selected);
});
},
),
);
},
child: _buildSectionContainer(
child: ListItemFactory.createRowSpaceBetweenItem(
leftText: "整改期限",
rightText: _dangerTime,
rightText: dataTime.isNotEmpty ? dataTime : "请选择",
isRight: true,
),
),
),
],
),
SizedBox(height: 30),
CustomButton(text: "提交", backgroundColor: Colors.blue),
CustomButton(
onPressed: () {},
text: "提交",
backgroundColor: Colors.blue,
),
],
),
),

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';
@ -93,26 +93,27 @@ class ApplicationPage extends StatelessWidget {
// 使
final List<Map<String, dynamic>> buttonInfos = [
{
'title': '隐患排查',
'title': '隐患快报',
'list': [
{'item': AppItem.riskInspection, 'icon': 'assets/icon-apps/icon-zl-6.png', 'title': '隐患排查', 'num': 0},
{'item': AppItem.quickReport, 'icon': 'assets/icon-apps/icon-pc-1.png', 'title': '隐患快报', 'num': 2},
{'item': AppItem.checkRecord, 'icon': 'assets/icon-apps/icon-zl-2.png', 'title': '检查记录', 'num': 0},
],
},
{
'title': '专项检',
'title': '隐患排',
'list': [
{'item': AppItem.specialRectification, 'icon': 'assets/icon-apps/icon-pc-1.png', 'title': '隐患整改', 'num': 5},
{'item': AppItem.specialRecord, 'icon': 'assets/icon-apps/icon-zl-2.png', 'title': '隐患记录', 'num': 0},
{'item': AppItem.riskInspection, 'icon': 'assets/icon-apps/icon-zl-6.png', 'title': '隐患排查', 'num': 0},
{'item': AppItem.checkRecord, 'icon': 'assets/icon-apps/icon-zl-2.png', 'title': '检查记录', 'num': 0},
// {'item': AppItem.specialRectification, 'icon': 'assets/icon-apps/icon-pc-1.png', 'title': '隐患整改', 'num': 5},
// {'item': AppItem.specialRecord, 'icon': 'assets/icon-apps/icon-zl-2.png', 'title': '隐患记录', 'num': 0},
],
},
{
'title': '监管帮扶',
'list': [
{'item': AppItem.supervisionRectification, 'icon': 'assets/icon-apps/icon-pc-1.png', 'title': '隐患整改', 'num': 2},
{'item': AppItem.supervisionRecord, 'icon': 'assets/icon-apps/icon-zl-2.png', 'title': '隐患记录', 'num': 0},
{'item': AppItem.supervisionRectification, 'icon': 'assets/icon-apps/icon-zl-6.png', 'title': '标准排查', 'num': 2},
{'item': AppItem.supervisionRecord, 'icon': 'assets/icon-apps/icon-zl-2.png', 'title': '检查记录', 'num': 0},
],
},
@ -131,7 +132,7 @@ class ApplicationPage extends StatelessWidget {
'title': '监测预警',
'list': [
{'item': AppItem.aiAlarm, 'icon': 'assets/icon-apps/icon-pc-1.png', 'title': 'AI报警', 'num': 0},
// {'item': AppItem.supervisionRecord, 'icon': 'assets/icon-apps/icon-zl-2.png', 'title': '隐患记录', 'num': 0},
],
},
];

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

@ -0,0 +1,489 @@
import 'dart:io';
import 'package:flutter/material.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;
String index;
String departmentId;
String responsibleId;
DepartmentEntry({
required this.department,
required this.responsible,
required this.index,
required this.departmentId,
required this.responsibleId,
});
// Map
Map<String, dynamic> toJson() {
return {
'DEPARTMENT_ID': departmentId,
'USER_ID': responsibleId,
'DEPARTMENT_NAME': department,
'USER_NAME': responsible,
'index': index,
};
}
}
///
class DannerRepair extends StatefulWidget {
DannerRepair(this.pd, {super.key});
final Map<String, dynamic> pd;
@override
State<DannerRepair> createState() => DannerRepairState();
}
class DannerRepairState extends State<DannerRepair> {
//
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();
final TextEditingController miaoShuController = TextEditingController();
late var _selectData = DateTime.now();
String dataTime="";
//
List<String> gaiHouImages = [];
//
List<String> fangAnImages = [];
//
List<String> jiHuaImages = [];
int yanShouAdd=1;
final List<DepartmentEntry> departments = [
DepartmentEntry(department: '请选择', responsible: '请选择',index:'',departmentId: '',responsibleId:''),
];
void _addDepartment() {
setState(() {
departments.add(DepartmentEntry(department: '请选择', responsible: '请选择',index:'',departmentId: '',responsibleId:''));
});
}
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();
miaoShuController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(bottom: 10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(5),
),
child: Column(
children: [
ListItemFactory.createBuildSimpleSection("隐患整改"),
Divider(height: 1),
Container(
height: 130,
padding: EdgeInsets.all(15),
child: Column(
children: [
Row(
children: [HhTextStyleUtils.mainTitle("隐患描述", fontSize: 15)],
),
TextField(
controller: miaoShuController,
keyboardType: TextInputType.multiline,
maxLines: null, //
style: TextStyle(fontSize: 15),
decoration: InputDecoration(
hintText: '请对隐患进行详细描述(必填项)',
border: InputBorder.none,
),
),
],
),
),
Divider(height: 1),
GestureDetector(
onTap: () {
showDialog(
context: context,
builder:
(_) => HDatePickerDialog(
initialDate: DateTime.now(),
onCancel: () => Navigator.of(context).pop(),
onConfirm: (selected) {
Navigator.of(context).pop();
setState(() {
_selectData = selected;
dataTime= DateFormat('yyyy-MM-dd').format(selected);
});
},
),
);
},
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 15),
child: ListItemFactory.createRowSpaceBetweenItem(
leftText: "整改日期",
rightText: dataTime.isEmpty?"请选择":dataTime,
isRight: true,
),
),
),
Divider(),
RepairedPhotoSection(
title: "整改后照片",
maxCount: 4,
mediaType: MediaType.image,
onChanged: (files) {
// files
gaiHouImages.clear();
for(int i=0;i<files.length;i++){
gaiHouImages.add(files[i].path);
}
},
onAiIdentify: () {
},
),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
CustomButton(
onPressed: () {
_addDepartment();
},
text: "添加",
backgroundColor: Colors.blue,
borderRadius: 17,
height: 34,
padding: EdgeInsets.symmetric(horizontal: 20),
),
],
),
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,
onChanged: (val) {
setState(() {
acceptedPrepare = val;
});
},
),
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,
onChanged: (val) {
setState(() {
acceptedPlan = val;
});
},
),
acceptedPlan ? _acceptPlan() : SizedBox(height: 1),
],
),
);
}
///
Widget _acceptPrepare() {
final fields = [
_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),
];
return ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: fields.length,
separatorBuilder:
(_, __) => const Divider(height: 1, color: Colors.black12),
itemBuilder:
(_, index) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
child: fields[index],
),
);
}
Widget _buildReadOnlyRow(String left, String right) {
return ListItemFactory.createRowSpaceBetweenItem(
leftText: left,
rightText: right,
);
}
/// item
Widget _departmentItem(
DepartmentEntry entry,
int index, {
required bool showLabel,
}) {
return Padding(
padding: const EdgeInsets.all(10),
child: Stack(
clipBehavior: Clip.none,
children: [
Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.black12, width: 1),
),
child: _noAccepet_repair(false,index),
),
// num > 1
if (index > 0)
Positioned(
top: -20,
left: -20,
child: IconButton(
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
icon: const Icon(Icons.cancel, color: Colors.red, size: 25),
onPressed: () {
_removeDepartment(index);
//
// setState(() => _items.removeAt(num));
},
),
),
],
),
);
}
//
List<Map<String, dynamic>> _personCache = [];
// #region
Widget _noAccepet_repair(bool _accept,int index, ) {
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="";
departments[index].department=name;
departments[index].departmentId=id;
departments[index].responsible="";
departments[index].responsibleId="";
});
//
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: departments[index].department.isNotEmpty?departments[index].department:"请选择",
isRight: true,
),
),
),
Divider(
height: 10,
color: _accept ? h_backGroundColor() : Colors.transparent,
),
GestureDetector(
onTap: () {
if ( departments[index].departmentId.isEmpty) {
ToastUtil.showNormal(context, '请先选择部门');
return;
}
DepartmentPersonPicker.show(
context,
personsData: _personCache,
onSelected: (userId, name) {
setState(() {
// renYuanId = userId;
// renYuanName = name;
departments[index].responsible=name;
departments[index].responsibleId=userId;
departments[index].index=(index-1).toString();
});
},
);
},
child:Container(
padding: EdgeInsets.symmetric(horizontal: 10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(5),
),
child: ListItemFactory.createRowSpaceBetweenItem(
leftText: "整改负责人",
rightText: departments[index].responsible.isNotEmpty?departments[index].responsible:"请选择",
isRight: true,
),
),
),
],
);
}
///
Widget _acceptPlan() {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 10),
child: MediaPickerRow(
maxCount: 4,
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,8 +43,12 @@ class _HiddenRecordDetailPageState extends State<HiddenRecordDetailPage> {
@override
void initState() {
super.initState();
if("2"==widget.item['HIDDEN_RISKSTANDARD']){
getDataTwo();
}else {
getData();
}
}
@override
void dispose() {
@ -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,707 @@
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;
//
final GlobalKey<DannerRepairState> dannerRepairKey = GlobalKey();
@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'];
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');
}
}
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,key: dannerRepairKey, );
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 dataTime= dannerRepairKey.currentState!.dataTime;
if(dataTime.isEmpty){
ToastUtil.showNormal(context, "请选择整改时间");
return;
}
String miaoShu= dannerRepairKey.currentState!.miaoShuController.text.trim();
if(miaoShu.isEmpty){
ToastUtil.showNormal(context, "请填整改描述");
return;
}
List<String> gaiHouImages = dannerRepairKey.currentState!.gaiHouImages;
if(gaiHouImages.isEmpty){
ToastUtil.showNormal(context, "请上传整改后照片");
return;
}
String acceptedPrepareType="0";
String standard="";
String method="";
String fund="";
String person="";
String workTime="";
String time="";
String work="";
String other="";
List<String> fangAnImages =[];
//
bool acceptedPrepare= dannerRepairKey.currentState!.acceptedPrepare;
if(acceptedPrepare){
acceptedPrepareType="1";
standard= dannerRepairKey.currentState!.standardController.text;
if(standard.isEmpty){
ToastUtil.showNormal(context, "请输入治理标准要求");
return;
}
method= dannerRepairKey.currentState!.methodController.text;
if(method.isEmpty){
ToastUtil.showNormal(context, "请输入治理方法");
return;
}
fund= dannerRepairKey.currentState!.fundController.text;
if(fund.isEmpty){
ToastUtil.showNormal(context, "请输入经费和物资的落实");
return;
}
person= dannerRepairKey.currentState!.personController.text;
if(person.isEmpty){
ToastUtil.showNormal(context, "请输入负责治理人员");
return;
}
workTime= dannerRepairKey.currentState!.workTimeController.text;
if(workTime.isEmpty){
ToastUtil.showNormal(context, "请输入工时安排");
return;
}
time= dannerRepairKey.currentState!.timeController.text;
if(time.isEmpty){
ToastUtil.showNormal(context, "请输入时限要求");
return;
}
work= dannerRepairKey.currentState!.workController.text;
if(work.isEmpty){
ToastUtil.showNormal(context, "请输入工作要求");
return;
}
other= dannerRepairKey.currentState!.otherController.text;
if(other.isEmpty){
ToastUtil.showNormal(context, "请输入工作要求");
return;
}
fangAnImages = dannerRepairKey.currentState!.fangAnImages;
if(fangAnImages.isEmpty){
ToastUtil.showNormal(context, "请上传方案照片");
return;
}
}
String acceptedPlanType="0";
List<String> jiHuaImages =[];
//
bool acceptedPlan= dannerRepairKey.currentState!.acceptedPlan;
if(acceptedPlan){
acceptedPlanType="1";
jiHuaImages = dannerRepairKey.currentState!.jiHuaImages;
if(jiHuaImages.isEmpty){
ToastUtil.showNormal(context, "请上传计划照片");
return;
}
}
List<DepartmentEntry> departments = dannerRepairKey.currentState!.departments;
bool departmentsAllInput=true;
bool departmentsSameMan=false;
for(int i=0;i<departments.length;i++){
if( departments[i].responsibleId.isEmpty){
departmentsAllInput=false;
}else{
for(int m=i+1;m<departments.length;m++){
if(departments[i].responsibleId==departments[m].responsibleId){
departmentsSameMan=true;
}
}
}
}
if(!departmentsAllInput){
ToastUtil.showNormal(context, "请添加验收部门负责人");
return;
}
if(departmentsSameMan){
ToastUtil.showNormal(context, "不能选择重复的验收部门负责人");
return;
}
String caertTime= pd["CREATTIME"];
String listName= "";//pd["LIST_NAME"];
String id= pd["HIDDEN_ID"];
// JSON
String json = _convertDepartmentsToJson(departments);
for(int i=0;i<gaiHouImages.length;i++){
_addImgFiles(gaiHouImages[i],"4",id) ;
}
for(int i=0;i<fangAnImages.length;i++){
_addImgFiles(fangAnImages[i],"8",id) ;
}
for(int i=0;i<jiHuaImages.length;i++){
_addImgFiles(jiHuaImages[i],"22",id) ;
}
final result = await ApiService.normalRectificationSubmission(
dataTime, miaoShu, acceptedPrepareType, acceptedPlanType,
id, caertTime, listName,
standard, method, fund, person,
workTime, time, work, other, json);
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 _convertDepartmentsToJson(List<DepartmentEntry> departments) {
// 1. Map
List<Map<String, dynamic>> jsonList = departments
.map((dept) => dept.toJson())
.toList();
// 2. 使 jsonEncode JSON
return jsonEncode(jsonList);
}
Future<String> _addImgFiles(String imagePath,String type,String id) async {
try {
final raw = await ApiService.addImgFiles( imagePath, type, id);
if (raw['result'] == 'success') {
return raw['imgPath'];
}else{
// _showMessage('反馈提交失败');
return "";
}
} catch (e) {
// Toast
print('加载首页数据失败:$e');
return "";
}
}
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

@ -1,285 +0,0 @@
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';
///
class DannerRepair extends StatefulWidget {
const DannerRepair({super.key});
@override
State<DannerRepair> createState() => _DannerRepairState();
}
class _DannerRepairState extends State<DannerRepair> {
//
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();
late var _selectData = DateTime.now();
@override
void dispose() {
//
_standardController.dispose();
_methodController.dispose();
_fundController.dispose();
_personController.dispose();
_workTimeController.dispose();
_timeController.dispose();
_workController.dispose();
_otherController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(bottom: 10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(5),
),
child: Column(
children: [
ListItemFactory.createBuildSimpleSection("隐患整改"),
Divider(height: 1),
Container(
height: 130,
padding: EdgeInsets.all(15),
child: Column(
children: [
Row(
children: [HhTextStyleUtils.mainTitle("隐患描述", fontSize: 15)],
),
TextField(
keyboardType: TextInputType.multiline,
maxLines: null, //
style: TextStyle(fontSize: 15),
decoration: InputDecoration(
hintText: '请对隐患进行详细描述(必填项)',
border: InputBorder.none,
),
),
],
),
),
Divider(height: 1),
GestureDetector(
onTap: () {
showDialog(
context: context,
builder:
(_) => HDatePickerDialog(
initialDate: DateTime.now(),
onCancel: () => Navigator.of(context).pop(),
onConfirm: (selected) {
Navigator.of(context).pop();
setState(() {
_selectData = selected;
});
},
),
);
},
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 15),
child: ListItemFactory.createRowSpaceBetweenItem(
leftText: "整改日期",
rightText: "请选择",
isRight: true,
),
),
),
Divider(),
RepairedPhotoSection(
title: "整改后照片",
maxCount: 4,
mediaType: MediaType.image,
onChanged: (files) {
// files
},
onAiIdentify: () {},
),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
CustomButton(
onPressed: () {},
text: "添加",
backgroundColor: Colors.blue,
borderRadius: 17,
height: 34,
padding: EdgeInsets.symmetric(horizontal: 20),
),
],
),
_departmentItem(1),
_departmentItem(2),
Divider(),
ListItemFactory.createYesNoSection(
title: "是否有整改方案",
yesLabel: "",
noLabel: "",
groupValue: _acceptedPrepare,
onChanged: (val) {
setState(() {
_acceptedPrepare = val;
});
},
),
_acceptedPrepare ? _acceptPrepare() : SizedBox(height: 1),
Divider(),
ListItemFactory.createYesNoSection(
title: "是否有整改计划",
yesLabel: "",
noLabel: "",
groupValue: _acceptedPlan,
onChanged: (val) {
setState(() {
_acceptedPlan = val;
});
},
),
_acceptedPlan ? _acceptPlan() : SizedBox(height: 1),
],
),
);
}
///
Widget _acceptPrepare() {
final fields = [
_buildReadOnlyRow("排查日期", "2025-1-2 11:22:30"),
_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),
];
return ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: fields.length,
separatorBuilder:
(_, __) => const Divider(height: 1, color: Colors.black12),
itemBuilder:
(_, index) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
child: fields[index],
),
);
}
Widget _buildReadOnlyRow(String left, String right) {
return ListItemFactory.createRowSpaceBetweenItem(
leftText: left,
rightText: right,
);
}
/// item
Widget _departmentItem(int num) {
return Padding(
padding: const EdgeInsets.all(10),
child: Stack(
clipBehavior: Clip.none,
children: [
Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.black12, width: 1),
),
child: _noAccepet_repair(false),
),
// num > 1
if (num > 1)
Positioned(
top: -20,
left: -20,
child: IconButton(
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
icon: const Icon(Icons.cancel, color: Colors.red, size: 25),
onPressed: () {
//
// setState(() => _items.removeAt(num));
},
),
),
],
),
);
}
// #region
Widget _noAccepet_repair(bool _accept) {
return Column(
children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(5),
),
child: ListItemFactory.createRowSpaceBetweenItem(
leftText: "整改部门",
rightText: "测试啊",
isRight: true,
),
),
Divider(
height: 10,
color: _accept ? h_backGroundColor() : Colors.transparent,
),
Container(
padding: EdgeInsets.symmetric(horizontal: 10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(5),
),
child: ListItemFactory.createRowSpaceBetweenItem(
leftText: "整改负责人",
rightText: "测试啊",
isRight: true,
),
),
],
);
}
///
Widget _acceptPlan() {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 10),
child: MediaPickerRow(
maxCount: 4,
onChanged: (List<File> images) {
// images
},
),
);
}
}

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);
}
});
},
child: Container(

View File

@ -4,15 +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});
@ -90,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 {
@ -147,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,
@ -157,7 +155,7 @@ class _LawsRegulationsPage extends State<LawsRegulationsPage> {
},
),
),
),
Expanded(child: _buildContent()),
],
),
@ -169,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

@ -165,6 +165,7 @@ class SessionService {
String? dangerJson;
String? riskJson;
String? departmentJsonStr;
String? departmentHiddenTypeJsonStr;
///
void loginSession(BuildContext context) {

File diff suppressed because it is too large Load Diff