。。。。

main
hs 2025-09-17 18:05:47 +08:00
parent 6ca5a27418
commit 76d0fdbd16
10 changed files with 473 additions and 398 deletions

View File

@ -352,6 +352,13 @@ setState(() {
} }
Widget _mainWidget() { Widget _mainWidget() {
bool isShowCheck = false;
if (FormUtils.hasValue(inspectedForm, 'hiddenList')) {
List list = inspectedForm['hiddenList'];
if (list.isEmpty) {
isShowCheck = true;
}
}
return ListView( return ListView(
children: [ children: [
Column( Column(
@ -380,8 +387,9 @@ setState(() {
: false, : false,
yesLabel: '同意', yesLabel: '同意',
noLabel: '申辩', noLabel: '申辩',
isEdit: true, isEdit: isShowCheck ? true : false,
isRequired: false, isRequired: false,
text: inspectedForm['INSPECTION_STATUS'] == '3' ? '同意' : '申辩',
horizontalPadding: 3, horizontalPadding: 3,
verticalPadding: 0, verticalPadding: 0,
onChanged: (val) { onChanged: (val) {

View File

@ -16,6 +16,7 @@ class _StudyClassListPageState extends State<StudyClassListPage> {
late List<dynamic> _list = []; late List<dynamic> _list = [];
late String _classId = ''; late String _classId = '';
late String _post_id = ''; late String _post_id = '';
late Map _classInfo = {};
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -32,6 +33,7 @@ class _StudyClassListPageState extends State<StudyClassListPage> {
final result = await ApiService.getClassList(_classId, _post_id); final result = await ApiService.getClassList(_classId, _post_id);
if (result['result'] == 'success') { if (result['result'] == 'success') {
final List<dynamic> newList = result['varList'] ?? []; final List<dynamic> newList = result['varList'] ?? [];
_classInfo = result['classInfo'] ?? {};
setState(() { setState(() {
_list.addAll(newList); _list.addAll(newList);
}); });
@ -46,7 +48,7 @@ class _StudyClassListPageState extends State<StudyClassListPage> {
final result = await ApiService.getVideoPermissions(); final result = await ApiService.getVideoPermissions();
if (result['result'] == 'success') { if (result['result'] == 'success') {
SessionService.instance.setStudyToken(result['token'] ?? ''); SessionService.instance.setStudyToken(result['token'] ?? '');
pushPage(StudyDetailPage(item, widget.studyData['STUDENT_ID'],widget.studyData), context); pushPage(StudyDetailPage(_classInfo, item, widget.studyData['STUDENT_ID'],widget.studyData), context);
} }
} }
@override @override

View File

@ -24,10 +24,17 @@ enum TakeExamType { video_study, strengththen, list }
class StudyDetailPage extends StatefulWidget { class StudyDetailPage extends StatefulWidget {
final Map studyDetailDetail; final Map studyDetailDetail;
final Map classInfo;
final String studentId; final String studentId;
final Map studyData; final Map studyData;
const StudyDetailPage(this.studyDetailDetail, this.studentId, this.studyData,{super.key}); const StudyDetailPage(
this.classInfo,
this.studyDetailDetail,
this.studentId,
this.studyData, {
super.key,
});
@override @override
State<StudyDetailPage> createState() => _StudyDetailPageState(); State<StudyDetailPage> createState() => _StudyDetailPageState();
@ -54,6 +61,7 @@ class _StudyDetailPageState extends State<StudyDetailPage>
int _currentNodeIndex = 0; int _currentNodeIndex = 0;
bool _hasNodes = false; bool _hasNodes = false;
Duration _lastReported = Duration.zero; Duration _lastReported = Duration.zero;
bool _isFace = false;
// //
bool _endReported = false; // bool _endReported = false; //
@ -69,6 +77,7 @@ class _StudyDetailPageState extends State<StudyDetailPage>
WakelockPlus.enable(); WakelockPlus.enable();
_classId = widget.studyDetailDetail['CLASS_ID'] ?? ''; _classId = widget.studyDetailDetail['CLASS_ID'] ?? '';
_classCurriculumId = widget.studyDetailDetail['CLASSCURRICULUM_ID'] ?? ''; _classCurriculumId = widget.studyDetailDetail['CLASSCURRICULUM_ID'] ?? '';
_isFace = widget.classInfo['ISFACE'] == '1' ? true : false;
_tabController = TabController(length: 2, vsync: this); _tabController = TabController(length: 2, vsync: this);
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
_showFaceIntro(); _showFaceIntro();
@ -99,10 +108,12 @@ class _StudyDetailPageState extends State<StudyDetailPage>
} }
Future<void> _showFaceIntro() async { Future<void> _showFaceIntro() async {
if (_isFace) {
final ok = await CustomAlertDialog.showConfirm( final ok = await CustomAlertDialog.showConfirm(
context, context,
title: '温馨提示', title: '温馨提示',
content: '重要提醒:尊敬的用户,根据规定我们会在您学习过程中多次进行人脸识别认证,为了保护您的隐私请您在摄像设备视野内确保衣冠整齐。', content:
'重要提醒:尊敬的用户,根据规定我们会在您学习过程中多次进行人脸识别认证,为了保护您的隐私请您在摄像设备视野内确保衣冠整齐。',
cancelText: '取消', cancelText: '取消',
confirmText: '同意并继续', confirmText: '同意并继续',
); );
@ -111,6 +122,7 @@ class _StudyDetailPageState extends State<StudyDetailPage>
return; return;
} }
} }
}
Future<void> _loadData() async { Future<void> _loadData() async {
try { try {
@ -179,8 +191,6 @@ class _StudyDetailPageState extends State<StudyDetailPage>
return '$s%'; return '$s%';
} }
Future<void> _onVideoTap( Future<void> _onVideoTap(
Map<String, dynamic> data, Map<String, dynamic> data,
bool hasNodes, bool hasNodes,
@ -191,9 +201,15 @@ class _StudyDetailPageState extends State<StudyDetailPage>
debugPrint('_onVideoTap ignored because a video is loading'); debugPrint('_onVideoTap ignored because a video is loading');
return; return;
} }
// if (_isFace) {
try {
await ApiService.fnClearUserFaceTime(); await ApiService.fnClearUserFaceTime();
} catch (e, st) {
debugPrint('fnClearUserFaceTime error: $e\n$st');
}
_faceTimer?.cancel(); _faceTimer?.cancel();
_faceTimer = null;
}
// //
if (_currentVideoData != null && _lastReported > Duration.zero) { if (_currentVideoData != null && _lastReported > Duration.zero) {
@ -252,7 +268,6 @@ class _StudyDetailPageState extends State<StudyDetailPage>
seconds: int.parse('${data['VIDEOTIME'] ?? '0'}'), seconds: int.parse('${data['VIDEOTIME'] ?? '0'}'),
); );
} }
} else { } else {
ToastUtil.showNormal(context, '课件文件资源已失效,请联系管理员'); ToastUtil.showNormal(context, '课件文件资源已失效,请联系管理员');
} }
@ -267,13 +282,18 @@ class _StudyDetailPageState extends State<StudyDetailPage>
// //
await _getVideoPlayInfo(data['VIDEOCOURSEWARE_ID']); await _getVideoPlayInfo(data['VIDEOCOURSEWARE_ID']);
LoadingDialogHelper.hide(); LoadingDialogHelper.hide();
if (_isFace) {
_startFaceTimer(); _startFaceTimer();
} }
}
}); });
} }
Future<void> _navigateFaceIfNeeded(FutureOr<void> Function() onPass) async { Future<void> _navigateFaceIfNeeded(FutureOr<void> Function() onPass) async {
if (_info?['ISFACE'] == '1') { if (!_isFace) {
await onPass();
return;
}
LoadingDialogHelper.show(); LoadingDialogHelper.show();
final resData = await ApiService.fnGetUserFace(); final resData = await ApiService.fnGetUserFace();
LoadingDialogHelper.hide(); LoadingDialogHelper.hide();
@ -283,10 +303,14 @@ class _StudyDetailPageState extends State<StudyDetailPage>
await _exitTopRouteAndWait(); await _exitTopRouteAndWait();
await _lockPortrait(); await _lockPortrait();
final passed = await pushPage<bool>( final passed = await pushPage<bool>(
FaceRecognitionPage(studentId: widget.studentId, FaceRecognitionPage(
VIDEOCOURSEWARE_ID:"",CURRICULUM_ID:"", studentId: widget.studentId,
CHAPTER_ID: "",CLASS_ID: "", VIDEOCOURSEWARE_ID: "",
mode: FaceMode.auto), CURRICULUM_ID: "",
CHAPTER_ID: "",
CLASS_ID: "",
mode: FaceMode.auto,
),
context, context,
); );
await _restoreDefaultOrientations(); await _restoreDefaultOrientations();
@ -309,18 +333,19 @@ class _StudyDetailPageState extends State<StudyDetailPage>
await _exitTopRouteAndWait(); await _exitTopRouteAndWait();
await _lockPortrait(); await _lockPortrait();
await pushPage( await pushPage(
const FaceRecognitionPage(studentId: '', const FaceRecognitionPage(
VIDEOCOURSEWARE_ID: '',CURRICULUM_ID: '', studentId: '',
CHAPTER_ID: '',CLASS_ID: '', VIDEOCOURSEWARE_ID: '',
mode: FaceMode.manual), CURRICULUM_ID: '',
CHAPTER_ID: '',
CLASS_ID: '',
mode: FaceMode.manual,
),
context, context,
); );
await _restoreDefaultOrientations(); await _restoreDefaultOrientations();
} }
} }
} else {
await onPass();
}
} }
Future<void> _getVideoPlayInfo(String vidId) async { Future<void> _getVideoPlayInfo(String vidId) async {
@ -471,8 +496,16 @@ class _StudyDetailPageState extends State<StudyDetailPage>
_exitTopRouteIfPresent(); _exitTopRouteIfPresent();
}); });
//
if (_isFace) {
try {
ApiService.fnClearUserFaceTime(); ApiService.fnClearUserFaceTime();
} catch (e, st) {
debugPrint('fnClearUserFaceTime error on end: $e\n$st');
}
_faceTimer?.cancel(); _faceTimer?.cancel();
_faceTimer = null;
}
} }
} }
} }
@ -484,7 +517,8 @@ class _StudyDetailPageState extends State<StudyDetailPage>
}) async { }) async {
// snapshot VIDEOCOURSEWARE_ID // snapshot VIDEOCOURSEWARE_ID
if (snapshot['VIDEOCOURSEWARE_ID'] == null || if (snapshot['VIDEOCOURSEWARE_ID'] == null ||
snapshot['VIDEOCOURSEWARE_ID'] == '') return; snapshot['VIDEOCOURSEWARE_ID'] == '')
return;
// //
if (_endReported && !end) return; if (_endReported && !end) return;
@ -504,7 +538,9 @@ class _StudyDetailPageState extends State<StudyDetailPage>
// snapshot['IS_VIDEO']==1 // snapshot['IS_VIDEO']==1
// 100% UI 100% // 100% UI 100%
final isNonVideo = (snapshot['IS_VIDEO'] != null && snapshot['IS_VIDEO'].toString() == '1'); final isNonVideo =
(snapshot['IS_VIDEO'] != null &&
snapshot['IS_VIDEO'].toString() == '1');
const int maxRetries = 2; const int maxRetries = 2;
int attempt = 0; int attempt = 0;
@ -520,7 +556,8 @@ class _StudyDetailPageState extends State<StudyDetailPage>
if (mounted) { if (mounted) {
setState(() { setState(() {
if (snapshot['IS_NODE'] == true) { if (snapshot['IS_NODE'] == true) {
final fi = snapshot['FIRST_INDEX'] as int? ?? _currentFirstIndex; final fi =
snapshot['FIRST_INDEX'] as int? ?? _currentFirstIndex;
final ni = snapshot['NODE_INDEX'] as int? ?? _currentNodeIndex; final ni = snapshot['NODE_INDEX'] as int? ?? _currentNodeIndex;
if (fi >= 0 && fi < _videoList.length) { if (fi >= 0 && fi < _videoList.length) {
final nodes = _videoList[fi]['nodes'] as List<dynamic>?; final nodes = _videoList[fi]['nodes'] as List<dynamic>?;
@ -529,7 +566,8 @@ class _StudyDetailPageState extends State<StudyDetailPage>
} }
} }
} else { } else {
final fi = snapshot['FIRST_INDEX'] as int? ?? _currentFirstIndex; final fi =
snapshot['FIRST_INDEX'] as int? ?? _currentFirstIndex;
if (fi >= 0 && fi < _videoList.length) { if (fi >= 0 && fi < _videoList.length) {
_videoList[fi]['percent'] = str; _videoList[fi]['percent'] = str;
} }
@ -558,15 +596,20 @@ class _StudyDetailPageState extends State<StudyDetailPage>
// //
final resTraw = pd['RESOURCETIME']; final resTraw = pd['RESOURCETIME'];
final resT = (resTraw is num) ? resTraw.toDouble() : double.tryParse('$resTraw') ?? seconds.toDouble(); final resT =
(resTraw is num)
? resTraw.toDouble()
: double.tryParse('$resTraw') ?? seconds.toDouble();
final videoTimeRaw = snapshot['VIDEOTIME']; final videoTimeRaw = snapshot['VIDEOTIME'];
final videoTime = (videoTimeRaw is String) final videoTime =
(videoTimeRaw is String)
? double.tryParse(videoTimeRaw) ?? 1.0 ? double.tryParse(videoTimeRaw) ?? 1.0
: (videoTimeRaw is num ? videoTimeRaw.toDouble() : 1.0); : (videoTimeRaw is num ? videoTimeRaw.toDouble() : 1.0);
final comp = pd['PLAYCOUNT'] != null && pd['PLAYCOUNT'] > 0; final comp = pd['PLAYCOUNT'] != null && pd['PLAYCOUNT'] > 0;
final pctDouble = comp ? 100.0 : ((resT / (videoTime > 0 ? videoTime : 1.0)) * 100.0); final pctDouble =
comp ? 100.0 : ((resT / (videoTime > 0 ? videoTime : 1.0)) * 100.0);
// //
double pctClamped = pctDouble.clamp(0.00, 100.00); double pctClamped = pctDouble.clamp(0.00, 100.00);
// 2 // 2
@ -621,83 +664,10 @@ class _StudyDetailPageState extends State<StudyDetailPage>
} }
} }
///
Future<void> _startExam(Map resData) async {
Map pd = resData['pd'] ?? {};
Map paper = resData['paper'] ?? {};
setState(() {
_loading = true;
});
final arguments = {
'STAGEEXAMPAPERINPUT_ID': paper['STAGEEXAMPAPERINPUT_ID'] ?? '',
'STAGEEXAMPAPER_ID': paper['STAGEEXAMPAPER_ID'] ?? '',
'CLASS_ID': _classId,
'POST_ID': pd['POST_ID'] ?? '',
'STUDENT_ID': widget.studentId,
'NUMBEROFEXAMS': pd['NUMBEROFEXAMS'] ?? '',
};
print('--_startExam data---$arguments');
final data = await ApiService.getStartExam(arguments);
setState(() {
_loading = false;
});
if (data['result'] == 'success') {
pushPage(
TakeExamPage(
examInfo: {
'CLASS_ID': _classId,
'POST_ID': pd['POST_ID'] ?? '',
'STUDENT_ID': widget.studentId,
'STRENGTHEN_PAPER_QUESTION_ID':
paper['STAGEEXAMPAPERINPUT_ID'] ?? '',
...data,
},
examType: TakeExamType.video_study, jumpType: 2,
),
context,
);
} else {
ToastUtil.showError(context, '请求错误');
}
}
void _exitTopRouteIfPresent() {
final route = ModalRoute.of(context);
if (route == null) return;
// route
if (!route.isCurrent) {
// pop
try {
Navigator.of(context).maybePop();
} catch (_) {
//
}
}
}
/// 退退
Future<void> _exitTopRouteAndWait({int waitMs = 300}) async {
_exitTopRouteIfPresent();
await Future.delayed(Duration(milliseconds: waitMs));
}
///
Future<void> _lockPortrait() async {
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
}
///
Future<void> _restoreDefaultOrientations() async {
await SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight,
]);
}
void _startFaceTimer() { void _startFaceTimer() {
//
if (!_isFace) return;
_faceTimer = Timer.periodic(Duration(seconds: _faceTime), (_) async { _faceTimer = Timer.periodic(Duration(seconds: _faceTime), (_) async {
final res = await ApiService.fnGetUserFaceTime(); final res = await ApiService.fnGetUserFaceTime();
final isPlaying = _videoController?.value.isPlaying == true; final isPlaying = _videoController?.value.isPlaying == true;
@ -714,6 +684,8 @@ class _StudyDetailPageState extends State<StudyDetailPage>
} }
Future<void> _showFaceAuthOnce() async { Future<void> _showFaceAuthOnce() async {
//
if (!_isFace) return;
// cancel // cancel
_faceTimer?.cancel(); _faceTimer?.cancel();
_faceTimer = null; _faceTimer = null;
@ -723,10 +695,14 @@ class _StudyDetailPageState extends State<StudyDetailPage>
await _lockPortrait(); await _lockPortrait();
final passed = await pushPage<bool>( final passed = await pushPage<bool>(
FaceRecognitionPage(studentId: widget.studentId, FaceRecognitionPage(
VIDEOCOURSEWARE_ID: "",CURRICULUM_ID: "", studentId: widget.studentId,
CHAPTER_ID: "",CLASS_ID: "", VIDEOCOURSEWARE_ID: "",
mode: FaceMode.auto), CURRICULUM_ID: "",
CHAPTER_ID: "",
CLASS_ID: "",
mode: FaceMode.auto,
),
context, context,
); );
@ -768,7 +744,9 @@ class _StudyDetailPageState extends State<StudyDetailPage>
debugPrint('Error resuming playback after face auth: $e\n$st'); debugPrint('Error resuming playback after face auth: $e\n$st');
} }
// //
if (_isFace) {
_startFaceTimer(); _startFaceTimer();
}
} else { } else {
ToastUtil.showError(context, '人脸验证未通过,无法继续'); ToastUtil.showError(context, '人脸验证未通过,无法继续');
if (_videoController != null) { if (_videoController != null) {
@ -785,6 +763,82 @@ class _StudyDetailPageState extends State<StudyDetailPage>
} }
} }
///
Future<void> _startExam(Map resData) async {
Map pd = resData['pd'] ?? {};
Map paper = resData['paper'] ?? {};
setState(() {
_loading = true;
});
final arguments = {
'STAGEEXAMPAPERINPUT_ID': paper['STAGEEXAMPAPERINPUT_ID'] ?? '',
'STAGEEXAMPAPER_ID': paper['STAGEEXAMPAPER_ID'] ?? '',
'CLASS_ID': _classId,
'POST_ID': pd['POST_ID'] ?? '',
'STUDENT_ID': widget.studentId,
'NUMBEROFEXAMS': pd['NUMBEROFEXAMS'] ?? '',
};
print('--_startExam data---$arguments');
final data = await ApiService.getStartExam(arguments);
setState(() {
_loading = false;
});
if (data['result'] == 'success') {
pushPage(
TakeExamPage(
examInfo: {
'CLASS_ID': _classId,
'POST_ID': pd['POST_ID'] ?? '',
'STUDENT_ID': widget.studentId,
'STRENGTHEN_PAPER_QUESTION_ID':
paper['STAGEEXAMPAPERINPUT_ID'] ?? '',
...data,
},
examType: TakeExamType.video_study,
jumpType: 3,
),
context,
);
} else {
ToastUtil.showError(context, '请求错误');
}
}
void _exitTopRouteIfPresent() {
final route = ModalRoute.of(context);
if (route == null) return;
// route
if (!route.isCurrent) {
// pop
try {
Navigator.of(context).maybePop();
} catch (_) {
//
}
}
}
/// 退退
Future<void> _exitTopRouteAndWait({int waitMs = 300}) async {
_exitTopRouteIfPresent();
await Future.delayed(Duration(milliseconds: waitMs));
}
///
Future<void> _lockPortrait() async {
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
}
///
Future<void> _restoreDefaultOrientations() async {
await SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight,
]);
}
Widget _buildVideoOrCover(double containerW, double containerH) { Widget _buildVideoOrCover(double containerW, double containerH) {
final c = _videoController; final c = _videoController;
if (c != null && c.value.isInitialized) { if (c != null && c.value.isInitialized) {
@ -896,9 +950,7 @@ class _StudyDetailPageState extends State<StudyDetailPage>
const SizedBox(width: 5), const SizedBox(width: 5),
Text( Text(
(item['NAME'] ?? '').toString(), (item['NAME'] ?? '').toString(),
style: const TextStyle( style: const TextStyle(fontSize: 15),
fontSize: 15,
),
), ),
], ],
), ),

View File

@ -116,9 +116,6 @@ class _TakeExamPageState extends State<TakeExamPage> {
content: '您无考试次数!', content: '您无考试次数!',
); );
if (ok) { if (ok) {
if (widget.jumpType == 2) {
Navigator.pop(context);
}
Navigator.pop(context); Navigator.pop(context);
}; };
} }
@ -235,10 +232,17 @@ class _TakeExamPageState extends State<TakeExamPage> {
content: content:
passed passed
? '您的成绩为 $score 分,恭喜您通过本次考试,请继续保持!' ? '您的成绩为 $score 分,恭喜您通过本次考试,请继续保持!'
: '您的成绩为 $score 分,很遗憾您没有通过本次考试,请再接再厉!', : '您的成绩为 $score 分,很遗憾您没有通过本次考试,请再接再 厉!',
cancelText: '', cancelText: '',
confirmText: '确定', confirmText: '确定',
); );
if (widget.jumpType == 2) {
Navigator.pop(context);
}
if (widget.jumpType == 3) {
Navigator.pop(context);
Navigator.pop(context);
}
Navigator.of(context).pop(); Navigator.of(context).pop();
} }
} }

View File

@ -68,8 +68,8 @@ class MeasuresListWidget extends StatelessWidget {
// //
double col0Fixed = 40; // double col0Fixed = 40; //
double col2Fixed = 80; // double col2Fixed = 70; //
double col3Fixed = 80; // double col3Fixed = 60; //
// 4isAllowEdit == true40 // 4isAllowEdit == true40
final showCol3 = !isAllowEdit; final showCol3 = !isAllowEdit;
@ -112,7 +112,8 @@ class MeasuresListWidget extends StatelessWidget {
} }
return Table( return Table(
defaultVerticalAlignment: TableCellVerticalAlignment.middle, // top
defaultVerticalAlignment: TableCellVerticalAlignment.top,
columnWidths: columnWidths, columnWidths: columnWidths,
border: TableBorder( border: TableBorder(
horizontalInside: BorderSide(color: Colors.grey.shade300), horizontalInside: BorderSide(color: Colors.grey.shade300),
@ -123,8 +124,8 @@ class MeasuresListWidget extends StatelessWidget {
TableRow( TableRow(
decoration: BoxDecoration(color: Colors.grey.shade100), decoration: BoxDecoration(color: Colors.grey.shade100),
children: [ children: [
const Padding( Padding(
padding: EdgeInsets.all(2), padding: const EdgeInsets.all(6),
child: Center( child: Center(
child: Text( child: Text(
'序号', '序号',
@ -132,8 +133,8 @@ class MeasuresListWidget extends StatelessWidget {
), ),
), ),
), ),
const Padding( Padding(
padding: EdgeInsets.all(8), padding: const EdgeInsets.all(8),
child: Center( child: Center(
child: Text( child: Text(
'安全措施', '安全措施',
@ -142,13 +143,14 @@ class MeasuresListWidget extends StatelessWidget {
), ),
), ),
Padding( Padding(
padding: const EdgeInsets.all(2), padding: const EdgeInsets.all(6),
child: Center( child: Center(
child: Text( child: Text(
isAllowEdit ? '操作' : '是否\n涉及', isAllowEdit ? '操作' : '是否\n涉及',
style: const TextStyle( style: const TextStyle(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
textAlign: TextAlign.center,
), ),
), ),
), ),
@ -168,21 +170,25 @@ class MeasuresListWidget extends StatelessWidget {
for (var item in measuresList) for (var item in measuresList)
TableRow( TableRow(
children: [ children: [
//
Padding( Padding(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(6),
child: Center( child: Center(
child: Text('${measuresList.indexOf(item) + 1}'), child:
Text('${measuresList.indexOf(item) + 1}'),
), ),
), ),
// + + // + +
Padding( Padding(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(6),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
// //
Text( Text(
item['PROTECTIVE_MEASURES'] as String? ?? '', item['PROTECTIVE_MEASURES'] as String? ?? '',
softWrap: true,
), ),
// 14 + // 14 +
for (var i = 1; i <= 4; i++) for (var i = 1; i <= 4; i++)
@ -194,7 +200,9 @@ class MeasuresListWidget extends StatelessWidget {
if (item.containsKey('IMG_PATH') && if (item.containsKey('IMG_PATH') &&
(item['IMG_PATH'] as String).isNotEmpty && (item['IMG_PATH'] as String).isNotEmpty &&
isShowSign) isShowSign)
Row( Padding(
padding: const EdgeInsets.only(top: 6),
child: Row(
children: [ children: [
..._buildImageRows( ..._buildImageRows(
context, context,
@ -204,14 +212,16 @@ class MeasuresListWidget extends StatelessWidget {
), ),
], ],
), ),
),
], ],
), ),
), ),
// / + // / +
Padding( Padding(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(0),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
// //
isAllowEdit isAllowEdit
@ -226,8 +236,7 @@ class MeasuresListWidget extends StatelessWidget {
? '已签字' ? '已签字'
: '签字', : '签字',
style: TextStyle( style: TextStyle(
color: color: (item['SIGN_ITEM'] ?? '')
(item['SIGN_ITEM'] ?? '')
.toString() .toString()
.isNotEmpty .isNotEmpty
? Colors.grey.shade600 ? Colors.grey.shade600
@ -239,11 +248,8 @@ class MeasuresListWidget extends StatelessWidget {
(item['STATUS'] as String?) == '-1' (item['STATUS'] as String?) == '-1'
? '不涉及' ? '不涉及'
: '涉及', : '涉及',
style: TextStyle( style: const TextStyle(
color: color: Colors.black,
(item['STATUS'] as String?) == '-1'
? Colors.black
: Colors.black,
), ),
), ),
], ],
@ -252,7 +258,9 @@ class MeasuresListWidget extends StatelessWidget {
// //
if (!isAllowEdit) if (!isAllowEdit)
Column( Padding(
padding: const EdgeInsets.all(6),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
if (item.containsKey('SIGN_PATH') && if (item.containsKey('SIGN_PATH') &&
@ -280,7 +288,8 @@ class MeasuresListWidget extends StatelessWidget {
height: 40, height: 40,
fit: BoxFit.fill, fit: BoxFit.fill,
errorBuilder: errorBuilder:
(_, __, ___) => Container( (_, __, ___) =>
Container(
width: 40, width: 40,
height: 40, height: 40,
color: Colors.grey.shade200, color: Colors.grey.shade200,
@ -297,6 +306,7 @@ class MeasuresListWidget extends StatelessWidget {
}).toList(), }).toList(),
], ],
), ),
),
], ],
), ),
], ],
@ -319,20 +329,27 @@ class MeasuresListWidget extends StatelessWidget {
return Padding( return Padding(
padding: const EdgeInsets.only(top: 8), padding: const EdgeInsets.only(top: 8),
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.start, //
children: [ children: [
Expanded( Expanded(
flex: 2, flex: 2,
child: Container(
padding: const EdgeInsets.only(right: 8), //
child: Text( child: Text(
'$question:', '$question:',
softWrap: true,
maxLines: 2,
overflow: TextOverflow.ellipsis, // visible null
style: const TextStyle(fontWeight: FontWeight.w800), style: const TextStyle(fontWeight: FontWeight.w800),
), ),
), ),
),
Expanded( Expanded(
flex: 1, flex: 1,
child: SizedBox(
child: TextFormField( child: TextFormField(
initialValue: answer, initialValue: answer,
textAlign: TextAlign.center, textAlign: TextAlign.center,
//
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
inputFormatters: [FilteringTextInputFormatter.digitsOnly], inputFormatters: [FilteringTextInputFormatter.digitsOnly],
decoration: InputDecoration( decoration: InputDecoration(
@ -341,7 +358,6 @@ class MeasuresListWidget extends StatelessWidget {
vertical: 8, vertical: 8,
horizontal: 4, horizontal: 4,
), ),
//
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey.shade300), borderSide: BorderSide(color: Colors.grey.shade300),
), ),
@ -354,30 +370,33 @@ class MeasuresListWidget extends StatelessWidget {
}, },
), ),
), ),
),
], ],
), ),
); );
} }
// //
return Padding( return Padding(
padding: const EdgeInsets.only(top: 8), padding: const EdgeInsets.only(top: 8, bottom: 6),
child: Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Expanded(
flex: 3,
child: Text(
'$question:', '$question:',
style: const TextStyle(fontWeight: FontWeight.w800), style: const TextStyle(fontWeight: FontWeight.w800),
), softWrap: true,
Text(answer.isNotEmpty ? answer : '0'), ),
], ),
const SizedBox(width: 12),
Expanded(
flex: 1,
child: Text(
answer.isNotEmpty ? answer : '0',
textAlign: TextAlign.right,
), ),
), ),
const Divider(),
], ],
), ),
); );
@ -436,8 +455,6 @@ class MeasuresListWidget extends StatelessWidget {
), ),
if (i != rowPaths.length - 1) SizedBox(width: spacing), if (i != rowPaths.length - 1) SizedBox(width: spacing),
], ],
// 使 Expanded
// Expanded(child: SizedBox()),
], ],
), ),
); );
@ -445,6 +462,7 @@ class MeasuresListWidget extends StatelessWidget {
} }
} }
/// ///
class OtherMeasuresWidget extends StatelessWidget { class OtherMeasuresWidget extends StatelessWidget {
/// ///
@ -854,7 +872,7 @@ class SignaturesListWidget extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(5),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -862,7 +880,7 @@ class SignaturesListWidget extends StatelessWidget {
label, label,
style: const TextStyle(fontWeight: FontWeight.bold), style: const TextStyle(fontWeight: FontWeight.bold),
), ),
const SizedBox(height: 4), const SizedBox(height: 2),
TextField( TextField(
controller: TextEditingController(text: descr), controller: TextEditingController(text: descr),
maxLines: null, maxLines: null,
@ -873,7 +891,7 @@ class SignaturesListWidget extends StatelessWidget {
), ),
), ),
Padding( Padding(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(5),
child: Text('$personDes: $name'), child: Text('$personDes: $name'),
), ),
for (var i = 0; i < signPaths.length; i++) for (var i = 0; i < signPaths.length; i++)
@ -897,7 +915,7 @@ class SignaturesListWidget extends StatelessWidget {
(_, __, ___) => const Icon(Icons.broken_image), (_, __, ___) => const Icon(Icons.broken_image),
), ),
), ),
const SizedBox(width: 16), const SizedBox(width: 10),
Expanded( Expanded(
child: Text(i < signTimes.length ? signTimes[i] : ''), child: Text(i < signTimes.length ? signTimes[i] : ''),
), ),

View File

@ -167,13 +167,13 @@ class _HotWorkDetailFormWidgetState extends State<HotWorkDetailFormWidget> {
hintText: '请选择动火人及证书编号', hintText: '请选择动火人及证书编号',
onTap: widget.onChooseHotworkUser, onTap: widget.onChooseHotworkUser,
), ),
if (FormUtils.hasValue(pd, 'WORK_USER_DEPARTMENT_NAME') && if (FormUtils.hasValue(pd, 'UNIT_NAME') &&
!widget.isEditable) ...[ !widget.isEditable) ...[
const Divider(), const Divider(),
ItemListWidget.singleLineTitleText( ItemListWidget.singleLineTitleText(
label: '作业单位:', label: '作业单位:',
isEditable: false, isEditable: false,
text: pd['WORK_USER_DEPARTMENT_NAME'] ?? '', text: pd['UNIT_NAME'] ?? '',
), ),
], ],
if (FormUtils.hasValue(pd, 'CONFIRM_USER_NAME') && if (FormUtils.hasValue(pd, 'CONFIRM_USER_NAME') &&
@ -186,6 +186,14 @@ class _HotWorkDetailFormWidgetState extends State<HotWorkDetailFormWidget> {
text: pd['CONFIRM_USER_NAME'] ?? '', text: pd['CONFIRM_USER_NAME'] ?? '',
), ),
], ],
if (FormUtils.hasValue(pd, 'ANALYZE_TIME') && !widget.isEditable) ...[
const Divider(),
ItemListWidget.OneRowStartButtonTitle(
label: '气体分析信息:',
text: pd['ANALYZE_USER_NAME'] ?? '',
onTap: widget.onAnalyzeTap,
),
],
const Divider(), const Divider(),
ItemListWidget.twoRowButtonTitleText( ItemListWidget.twoRowButtonTitleText(
label: '关联其他特殊作业及安全作业票编号', label: '关联其他特殊作业及安全作业票编号',
@ -388,14 +396,7 @@ class _HotWorkDetailFormWidgetState extends State<HotWorkDetailFormWidget> {
text: pd['VIDEONAME'] ?? '', text: pd['VIDEONAME'] ?? '',
), ),
if (FormUtils.hasValue(pd, 'ANALYZE_TIME') && !widget.isEditable) ...[
const Divider(),
ItemListWidget.OneRowStartButtonTitle(
label: '气体分析信息:',
text: pd['ANALYZE_USER_NAME'] ?? '',
onTap: widget.onAnalyzeTap,
),
],
], ],
), ),
); );

View File

@ -1,18 +0,0 @@
import 'package:flutter/material.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
class HotSafeWorkChoosePage extends StatefulWidget {
const HotSafeWorkChoosePage({super.key});
@override
State<HotSafeWorkChoosePage> createState() => _HotSafeWorkChoosePageState();
}
class _HotSafeWorkChoosePageState extends State<HotSafeWorkChoosePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppbar(title: 'dong'),
);
}
}

View File

@ -364,35 +364,33 @@ class _HotWorkListPageState extends State<HotWorkListPage> {
overflow: TextOverflow.visible, overflow: TextOverflow.visible,
), ),
), ),
const SizedBox(width: 8),
Expanded(
child: item['APPROVE_USER_NAME'] != null
? Text(
"审批部门负责人: ${item['APPROVE_USER_NAME'] ?? ''}",
textAlign: TextAlign.right,
softWrap: true,
maxLines: null,
overflow: TextOverflow.visible,
)
: const SizedBox.shrink(),
),
],
),
Row(
children: [
Expanded( Expanded(
child: Text( child: Text(
"安全交底人: ${item['CONFESS_USER_NAME'] ?? ''}", "安全交底人: ${item['CONFESS_USER_NAME'] ?? ''}",
softWrap: true, softWrap: true,
maxLines: null, maxLines: null,
textAlign: TextAlign.right,
overflow: TextOverflow.visible, overflow: TextOverflow.visible,
), ),
), ),
const SizedBox(width: 8), ],
),
Row(
children: [
Expanded( Expanded(
child: Text( child: Text(
"接受交底人: ${item['ACCEPT_CONFESS_USER_NAME'] ?? ''}", "接受交底人: ${item['ACCEPT_CONFESS_USER_NAME'] ?? ''}",
softWrap: true,
maxLines: null,
overflow: TextOverflow.visible,
),
),
Expanded(
child: Text(
"作业负责人: ${item['CONFIRM_USER_NAME'] ?? ''}",
textAlign: TextAlign.right, textAlign: TextAlign.right,
softWrap: true, softWrap: true,
maxLines: null, maxLines: null,
@ -404,19 +402,10 @@ class _HotWorkListPageState extends State<HotWorkListPage> {
Row( Row(
children: [ children: [
Expanded(
child: Text(
"作业负责人: ${item['CONFIRM_USER_NAME'] ?? ''}",
softWrap: true,
maxLines: null,
overflow: TextOverflow.visible,
),
),
const SizedBox(width: 8),
Expanded( Expanded(
child: Text( child: Text(
"所在单位负责人: ${item['LEADER_USER_NAME'] ?? ''}", "所在单位负责人: ${item['LEADER_USER_NAME'] ?? ''}",
textAlign: TextAlign.right, textAlign: TextAlign.left,
softWrap: true, softWrap: true,
maxLines: null, maxLines: null,
overflow: TextOverflow.visible, overflow: TextOverflow.visible,

View File

@ -65,13 +65,17 @@ class _BlindboardApplyDetailState extends State<BlindboardApplyDetail> {
late List<dynamic> boardList = [ late List<dynamic> boardList = [
{'BOARD_MATERIAL': '', 'BOARD_SPECIFICATION': '', 'BOARD_NO': ''}, {'BOARD_MATERIAL': '', 'BOARD_SPECIFICATION': '', 'BOARD_NO': ''},
]; ];
/// ------------------- ------------------- /// ------------------- -------------------
/// ///
late List<dynamic> videoMonitoringList = []; late List<dynamic> videoMonitoringList = [];
/// ///
late List<dynamic> unitAllList = []; late List<dynamic> unitAllList = [];
/// ///
late List<dynamic> workAreaList = []; late List<dynamic> workAreaList = [];
/// -------------------------------------- /// --------------------------------------
late Map<String, dynamic> signs = {}; late Map<String, dynamic> signs = {};
late List<Map<String, dynamic>> measuresList = []; late List<Map<String, dynamic>> measuresList = [];
@ -86,8 +90,6 @@ class _BlindboardApplyDetailState extends State<BlindboardApplyDetail> {
final TextEditingController _relatedController = TextEditingController(); final TextEditingController _relatedController = TextEditingController();
final TextEditingController _riskController = TextEditingController(); final TextEditingController _riskController = TextEditingController();
// //
final Map<EditUserType, List<Map<String, dynamic>>> _personCache = {}; final Map<EditUserType, List<Map<String, dynamic>>> _personCache = {};
@ -105,7 +107,6 @@ class _BlindboardApplyDetailState extends State<BlindboardApplyDetail> {
pd['APPLY_USER_ID'] = SessionService.instance.loginUserId; pd['APPLY_USER_ID'] = SessionService.instance.loginUserId;
pd['APPLY_USER_NAME'] = SessionService.instance.username; pd['APPLY_USER_NAME'] = SessionService.instance.username;
pd['IS_CONTRACTOR_WORK'] = '0'; pd['IS_CONTRACTOR_WORK'] = '0';
} }
_getVideoList(); _getVideoList();
@ -132,6 +133,7 @@ class _BlindboardApplyDetailState extends State<BlindboardApplyDetail> {
pd['RISK_IDENTIFICATION'] = _riskController.text.trim(); pd['RISK_IDENTIFICATION'] = _riskController.text.trim();
}); });
} }
/// ---------------------------- -------------------------------- /// ---------------------------- --------------------------------
/// ///
Future<void> _chooseVideoManager() async { Future<void> _chooseVideoManager() async {
@ -159,6 +161,7 @@ class _BlindboardApplyDetailState extends State<BlindboardApplyDetail> {
}); });
} }
} }
/// ///
Future<void> _chooseUnitManager() async { Future<void> _chooseUnitManager() async {
final choice = await BottomPicker.show<String>( final choice = await BottomPicker.show<String>(
@ -183,9 +186,8 @@ class _BlindboardApplyDetailState extends State<BlindboardApplyDetail> {
} }
} }
/// ///
Future<void> _showLocationHandle() async{ Future<void> _showLocationHandle() async {
if (!FormUtils.hasValue(pd, 'ELECTRONIC_FENCE_AREA_ID')) { if (!FormUtils.hasValue(pd, 'ELECTRONIC_FENCE_AREA_ID')) {
ToastUtil.showNormal(context, '请选择作业区域'); ToastUtil.showNormal(context, '请选择作业区域');
return; return;
@ -194,10 +196,11 @@ class _BlindboardApplyDetailState extends State<BlindboardApplyDetail> {
setState(() { setState(() {
pd['LONGITUDE'] = mapData['longitue'] ?? ''; pd['LONGITUDE'] = mapData['longitue'] ?? '';
pd['LATITUDE'] = mapData['latitude'] ?? ''; pd['LATITUDE'] = mapData['latitude'] ?? '';
pd['LATITUDE_LONGITUDE'] = '${mapData['longitue'] ?? ''},${mapData['latitude'] ?? ''}'; pd['LATITUDE_LONGITUDE'] =
'${mapData['longitue'] ?? ''},${mapData['latitude'] ?? ''}';
}); });
} }
/// ///
Future<void> _getWorkArea() async { Future<void> _getWorkArea() async {
//FocusHelper.clearFocus(context); //FocusHelper.clearFocus(context);
@ -220,6 +223,7 @@ class _BlindboardApplyDetailState extends State<BlindboardApplyDetail> {
//FocusHelper.clearFocus(context); //FocusHelper.clearFocus(context);
}); });
} }
/// ///
Future<void> _getVideoList() async { Future<void> _getVideoList() async {
final result = await ApiService.getVideomanagerList(); final result = await ApiService.getVideomanagerList();
@ -227,6 +231,7 @@ class _BlindboardApplyDetailState extends State<BlindboardApplyDetail> {
videoMonitoringList = result['varList'] ?? []; videoMonitoringList = result['varList'] ?? [];
}); });
} }
/// ///
Future<void> _getUnitListAll() async { Future<void> _getUnitListAll() async {
final result = await ApiService.getUnitListAll(); final result = await ApiService.getUnitListAll();
@ -440,9 +445,23 @@ class _BlindboardApplyDetailState extends State<BlindboardApplyDetail> {
]; ];
final level = pd['WORK_TYPE'] ?? ''; final level = pd['WORK_TYPE'] ?? '';
print('---level-$level'); print('---level-$level');
int index = 0;
for (Map item in boardList) { for (Map item in boardList) {
if (!FormUtils.hasValue(item, 'BOARD_MATERIAL')) {
ToastUtil.showNormal(context, '请填写盲板抽堵参数第${index+1}项材质');
return;
} }
if (!FormUtils.hasValue(item, 'BOARD_SPECIFICATION')) {
ToastUtil.showNormal(context, '请填写盲板抽堵参数第${index+1}项规格');
return;
}
if (!FormUtils.hasValue(item, 'BOARD_NO')) {
ToastUtil.showNormal(context, '请填写盲板抽堵参数第${index+1}项编号');
return;
}
index += 1;
}
/// ///
final unitRules = <EditUserType>[ final unitRules = <EditUserType>[
EditUserType.GUARDIAN, EditUserType.GUARDIAN,
@ -478,7 +497,8 @@ class _BlindboardApplyDetailState extends State<BlindboardApplyDetail> {
return; return;
} }
if (pd['IS_CONTRACTOR_WORK'] == '1' && !FormUtils.hasValue(pd, 'UNITS_ID')) { if (pd['IS_CONTRACTOR_WORK'] == '1' &&
!FormUtils.hasValue(pd, 'UNITS_ID')) {
ToastUtil.showNormal(context, '请选择承包商'); ToastUtil.showNormal(context, '请选择承包商');
return; return;
} }
@ -510,7 +530,8 @@ class _BlindboardApplyDetailState extends State<BlindboardApplyDetail> {
pd['ACTION_USER'] = SessionService.instance.username; pd['ACTION_USER'] = SessionService.instance.username;
pd['APPLY_STATUS'] = status; pd['APPLY_STATUS'] = status;
pd['boardList'] = jsonEncode(boardList).toString(); pd['boardList'] = jsonEncode(boardList).toString();
pd['SPECIAL_WORK'] = FormUtils.hasValue(pd, 'SPECIAL_WORK') ? pd['SPECIAL_WORK'] : ''; pd['SPECIAL_WORK'] =
FormUtils.hasValue(pd, 'SPECIAL_WORK') ? pd['SPECIAL_WORK'] : '';
// //
if (msg == 'add') { if (msg == 'add') {
pd['STEP_ID'] = status; pd['STEP_ID'] = status;
@ -548,8 +569,6 @@ class _BlindboardApplyDetailState extends State<BlindboardApplyDetail> {
} }
} }
/// ///
Future<void> _getData() async { Future<void> _getData() async {
final data = await ApiService.getHomeworkFindById( final data = await ApiService.getHomeworkFindById(

View File

@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 2.1.2+9 version: 2.1.2+10
environment: environment:
sdk: ^3.7.0 sdk: ^3.7.0